mirror of https://codeberg.org/topola/topola.git
tracer: Add some initial code for squeezing/tucking
Not functional yet.
This commit is contained in:
parent
ce72a2ba4b
commit
c9d0b2178e
47
src/draw.rs
47
src/draw.rs
|
|
@ -127,26 +127,21 @@ impl<'a> Draw<'a> {
|
||||||
dirs = [false, true];
|
dirs = [false, true];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, tangent) in [tangents.0, tangents.1].iter().enumerate() {
|
[tangents.0, tangents.1]
|
||||||
match self.segbend_around(
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, tangent)| {
|
||||||
|
self.segbend_around(
|
||||||
head,
|
head,
|
||||||
TaggedIndex::Dot(around),
|
TaggedIndex::Dot(around),
|
||||||
tangent.start_point(),
|
tangent.start_point(),
|
||||||
tangent.end_point(),
|
tangent.end_point(),
|
||||||
dirs[i],
|
dirs[i],
|
||||||
width,
|
width,
|
||||||
) {
|
)
|
||||||
Ok(head) => {
|
.ok()
|
||||||
return Ok(head);
|
})
|
||||||
}
|
.ok_or(())
|
||||||
Err(err) => {
|
|
||||||
if i >= 1 {
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
|
#[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 self,
|
||||||
mut head: Head,
|
mut head: Head,
|
||||||
around: BendIndex,
|
around: BendIndex,
|
||||||
cw: bool,
|
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<SegbendHead, ()> {
|
) -> Result<SegbendHead, ()> {
|
||||||
let tangent = self
|
let mut tangents = self
|
||||||
.guide(&Default::default())
|
.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())?;
|
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
|
||||||
self.segbend(
|
tangents = (tangents.1, tangents.0);
|
||||||
|
dirs = [false, true];
|
||||||
|
}
|
||||||
|
|
||||||
|
[tangents.0, tangents.1]
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find_map(|(i, tangent)| {
|
||||||
|
self.segbend_around(
|
||||||
head,
|
head,
|
||||||
TaggedIndex::Bend(around),
|
TaggedIndex::Bend(around),
|
||||||
|
tangent.start_point(),
|
||||||
tangent.end_point(),
|
tangent.end_point(),
|
||||||
cw,
|
dirs[i],
|
||||||
width,
|
width,
|
||||||
)
|
)
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.ok_or(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
|
||||||
|
|
|
||||||
43
src/guide.rs
43
src/guide.rs
|
|
@ -34,20 +34,6 @@ impl<'a, 'b> Guide<'a, 'b> {
|
||||||
math::tangent_segment(from_circle, from_cw, to_circle, None)
|
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(
|
pub fn head_around_dot_segments(
|
||||||
&self,
|
&self,
|
||||||
head: &Head,
|
head: &Head,
|
||||||
|
|
@ -77,6 +63,35 @@ impl<'a, 'b> Guide<'a, 'b> {
|
||||||
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
|
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> {
|
pub fn head_cw(&self, head: &Head) -> Option<bool> {
|
||||||
if let Head::Segbend(head) = head {
|
if let Head::Segbend(head) = head {
|
||||||
Some(self.layout.primitive(head.segbend.bend).weight().cw)
|
Some(self.layout.primitive(head.segbend.bend).weight().cw)
|
||||||
|
|
|
||||||
114
src/main.rs
114
src/main.rs
|
|
@ -68,7 +68,7 @@ impl<'a> DebugRouterObserver<'a> {
|
||||||
|
|
||||||
impl<'a> RouterObserver for DebugRouterObserver<'a> {
|
impl<'a> RouterObserver for DebugRouterObserver<'a> {
|
||||||
fn on_rework(&mut self, tracer: &Tracer, trace: &Trace) {
|
fn on_rework(&mut self, tracer: &Tracer, trace: &Trace) {
|
||||||
render_times(
|
/*render_times(
|
||||||
self.event_pump,
|
self.event_pump,
|
||||||
self.canvas,
|
self.canvas,
|
||||||
RouterOrLayout::Layout(tracer.layout),
|
RouterOrLayout::Layout(tracer.layout),
|
||||||
|
|
@ -77,13 +77,13 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&trace.path,
|
&trace.path,
|
||||||
20,
|
20,
|
||||||
);
|
);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
|
fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
|
||||||
let mut path = trace.path.clone();
|
let mut path = trace.path.clone();
|
||||||
path.push(edge.target());
|
path.push(edge.target());
|
||||||
render_times(
|
/*render_times(
|
||||||
self.event_pump,
|
self.event_pump,
|
||||||
self.canvas,
|
self.canvas,
|
||||||
RouterOrLayout::Layout(tracer.layout),
|
RouterOrLayout::Layout(tracer.layout),
|
||||||
|
|
@ -92,11 +92,11 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&path,
|
&path,
|
||||||
5,
|
5,
|
||||||
);
|
);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
|
fn on_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference) {
|
||||||
render_times(
|
/*render_times(
|
||||||
self.event_pump,
|
self.event_pump,
|
||||||
self.canvas,
|
self.canvas,
|
||||||
RouterOrLayout::Layout(tracer.layout),
|
RouterOrLayout::Layout(tracer.layout),
|
||||||
|
|
@ -105,7 +105,7 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&trace.path,
|
&trace.path,
|
||||||
5,
|
5,
|
||||||
);
|
);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {}
|
fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {}
|
||||||
|
|
@ -145,7 +145,18 @@ fn main() {
|
||||||
let dot2 = router
|
let dot2 = router
|
||||||
.layout
|
.layout
|
||||||
.add_dot(DotWeight {
|
.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 {
|
circle: Circle {
|
||||||
pos: (470.5, 350.5).into(),
|
pos: (470.5, 350.5).into(),
|
||||||
r: 8.0,
|
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(
|
render_times(
|
||||||
&mut event_pump,
|
&mut event_pump,
|
||||||
&mut canvas,
|
&mut canvas,
|
||||||
RouterOrLayout::Router(&mut router),
|
RouterOrLayout::Router(&mut router),
|
||||||
Some(dot1),
|
Some(dot1),
|
||||||
Some(dot2),
|
Some(dot_end),
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
-1,
|
-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(
|
render_times(
|
||||||
&mut event_pump,
|
&mut event_pump,
|
||||||
&mut canvas,
|
&mut canvas,
|
||||||
|
|
@ -338,11 +423,6 @@ fn render_times(
|
||||||
if let Some(follower) = follower {
|
if let Some(follower) = follower {
|
||||||
let state = event_pump.mouse_state();
|
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 {
|
if let Some(from) = from {
|
||||||
mesh = router
|
mesh = router
|
||||||
.reroute(
|
.reroute(
|
||||||
|
|
@ -351,6 +431,10 @@ fn render_times(
|
||||||
&mut DebugRouterObserver::new(event_pump, canvas),
|
&mut DebugRouterObserver::new(event_pump, canvas),
|
||||||
)
|
)
|
||||||
.ok();
|
.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() {
|
for edge in mesh.edge_references() {
|
||||||
let endpoints = (mesh.position(edge.source()), mesh.position(edge.target()));
|
let endpoints = (mesh.position(edge.source()), mesh.position(edge.target()));
|
||||||
|
|
||||||
|
|
@ -430,7 +514,7 @@ fn render_times(
|
||||||
color,
|
color,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
//});
|
//});
|
||||||
|
|
||||||
canvas.present();
|
canvas.present();
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ pub fn intersect_circles(circle1: &Circle, circle2: &Circle) -> Vec<Point> {
|
||||||
let p = circle1.pos + delta * (a / d);
|
let p = circle1.pos + delta * (a / d);
|
||||||
let h = (circle1.r * circle1.r - a * a).sqrt();
|
let h = (circle1.r * circle1.r - a * a).sqrt();
|
||||||
|
|
||||||
if h == 0. {
|
if h == 0.0 {
|
||||||
return [p].into();
|
return [p].into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ impl<'a, Weight> Primitive<'a, Weight> {
|
||||||
.weight()
|
.weight()
|
||||||
.circle;
|
.circle;
|
||||||
|
|
||||||
core_circle.r + r + 5.0
|
core_circle.r + r + 3.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn neighbors(&self) -> impl Iterator<Item = TaggedIndex> + '_ {
|
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()))
|
.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;
|
let mut prev_index = self.index.index;
|
||||||
|
|
||||||
while let Some(index) = self
|
while let Some(index) = self
|
||||||
.graph
|
.graph
|
||||||
.neighbors_directed(prev_index, Incoming)
|
.neighbors_directed(prev_index, Incoming)
|
||||||
|
// Ensure subsequent unwrap doesn't panic.
|
||||||
.filter(|ni| self.graph.find_edge(*ni, prev_index).is_some())
|
.filter(|ni| self.graph.find_edge(*ni, prev_index).is_some())
|
||||||
|
// Filter out non-End edges.
|
||||||
.filter(|ni| {
|
.filter(|ni| {
|
||||||
self.graph
|
self.graph
|
||||||
.edge_weight(self.graph.find_edge(*ni, prev_index).unwrap())
|
.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();
|
let weight = *self.graph.node_weight(index).unwrap();
|
||||||
|
|
||||||
if mem::discriminant(&self.tagged_weight()) == mem::discriminant(&weight) {
|
if let Some(TaggedWeight::Bend(..)) = self.graph.node_weight(index) {
|
||||||
return Some(Index::<Weight>::new(index));
|
return Some(BendIndex::new(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_index = index;
|
prev_index = index;
|
||||||
|
|
@ -124,13 +126,15 @@ impl<'a, Weight> Primitive<'a, Weight> {
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_next_akin(&self) -> Option<Index<Weight>> {
|
pub fn next_bend(&self) -> Option<BendIndex> {
|
||||||
let mut prev_index = self.index.index;
|
let mut prev_index = self.index.index;
|
||||||
|
|
||||||
while let Some(index) = self
|
while let Some(index) = self
|
||||||
.graph
|
.graph
|
||||||
.neighbors_directed(prev_index, Outgoing)
|
.neighbors_directed(prev_index, Outgoing)
|
||||||
|
// Ensure subsequent unwrap doesn't panic.
|
||||||
.filter(|ni| self.graph.find_edge(prev_index, *ni).is_some())
|
.filter(|ni| self.graph.find_edge(prev_index, *ni).is_some())
|
||||||
|
// Filter out non-End edges.
|
||||||
.filter(|ni| {
|
.filter(|ni| {
|
||||||
self.graph
|
self.graph
|
||||||
.edge_weight(self.graph.find_edge(prev_index, *ni).unwrap())
|
.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();
|
let weight = *self.graph.node_weight(index).unwrap();
|
||||||
|
|
||||||
if mem::discriminant(&self.tagged_weight()) == mem::discriminant(&weight) {
|
if let Some(TaggedWeight::Bend(..)) = self.graph.node_weight(index) {
|
||||||
return Some(Index::<Weight>::new(index));
|
return Some(BendIndex::new(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_index = index;
|
prev_index = index;
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ impl BendShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn between_ends(&self, point: Point) -> bool {
|
pub fn between_ends(&self, point: Point) -> bool {
|
||||||
math::between_vectors(
|
math::between_vectors(
|
||||||
point - self.c.pos,
|
point - self.c.pos,
|
||||||
self.from - self.c.pos,
|
self.from - self.c.pos,
|
||||||
|
|
@ -69,6 +69,7 @@ impl BendShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Use enum_dispatch.
|
||||||
#[derive(Debug, Clone, Copy, EnumAsInner, PartialEq)]
|
#[derive(Debug, Clone, Copy, EnumAsInner, PartialEq)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
// Intentionally in different order to reorder `self.intersects(...)` properly.
|
// Intentionally in different order to reorder `self.intersects(...)` properly.
|
||||||
|
|
|
||||||
154
src/tracer.rs
154
src/tracer.rs
|
|
@ -1,7 +1,9 @@
|
||||||
use contracts::debug_ensures;
|
use contracts::debug_ensures;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
draw::{BareHead, Draw, Head},
|
bow::Bow,
|
||||||
|
draw::{BareHead, Draw, Head, HeadDot, SegbendHead},
|
||||||
|
graph::{BendIndex, DotIndex, Ends},
|
||||||
layout::Layout,
|
layout::Layout,
|
||||||
mesh::{Mesh, MeshEdgeReference, VertexIndex},
|
mesh::{Mesh, MeshEdgeReference, VertexIndex},
|
||||||
rules::Rules,
|
rules::Rules,
|
||||||
|
|
@ -84,11 +86,159 @@ impl<'a> Tracer<'a> {
|
||||||
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
|
#[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<(), ()> {
|
pub fn step(&mut self, trace: &mut Trace, to: VertexIndex, width: f64) -> Result<(), ()> {
|
||||||
let to_dot = self.mesh.dot(to);
|
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);
|
trace.path.push(to);
|
||||||
Ok(())
|
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_ok() -> trace.path.len() == old(trace.path.len() - 1))]
|
||||||
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
|
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
|
||||||
pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> {
|
pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue