draw: Implement flipping the bend if a shorter one is available

This commit is contained in:
Mikolaj Wielgus 2023-09-19 20:56:40 +02:00
parent abf92c7f43
commit 0695b1deab
3 changed files with 70 additions and 42 deletions

View File

@ -1,6 +1,6 @@
use contracts::{debug_ensures, debug_requires};
use enum_dispatch::enum_dispatch;
use geo::{EuclideanLength, Point};
use geo::{EuclideanDistance, EuclideanLength, Point};
use crate::{
graph::{BendIndex, BendWeight, DotIndex, DotWeight, Ends, SegIndex, SegWeight, TaggedIndex},
@ -176,21 +176,43 @@ impl<'a> Draw<'a> {
#[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))]
fn segbend_around(
&mut self,
mut head: Head,
head: Head,
around: TaggedIndex,
from: Point,
to: Point,
cw: bool,
width: f64,
) -> Result<SegbendHead, ()> {
head = self.extend_head(head, from)?;
let head = self.extend_head(head, from)?;
self.segbend(head, around, to, cw, width)
}
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> {
if let Head::Segbend(head) = head {
Ok(Head::Segbend(self.extend_head_bend(head, to)?))
self.layout.move_dot(head.dot, to)?;
if let TaggedIndex::Dot(around) = self.layout.primitive(head.segbend.bend).around() {
let cw = self.layout.primitive(head.segbend.bend).weight().cw;
let prev_dot = self.layout.primitive(head.segbend.ends().0).prev().unwrap();
let prev_head = self.prev_head(prev_dot);
let alternate_tangent = self
.guide(&Default::default())
.head_around_dot_segment(&prev_head, around, cw, 5.0);
let segbend_dot_pos = self.layout.primitive(head.segbend.dot).weight().circle.pos;
if alternate_tangent.end_point().euclidean_distance(&to)
< segbend_dot_pos.euclidean_distance(&to)
{
self.layout.flip_bend(head.segbend.bend);
self.layout
.move_dot(head.segbend.dot, alternate_tangent.end_point())?;
}
}
Ok(Head::Segbend(head))
} else {
Ok(head)
// No assertion for now because we temporarily use floats.
@ -200,12 +222,6 @@ impl<'a> Draw<'a> {
}
}
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
fn extend_head_bend(&mut self, head: SegbendHead, to: Point) -> Result<SegbendHead, ()> {
self.layout.extend_bend(head.segbend.bend, head.dot, to)?;
Ok(head)
}
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
#[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))]
fn segbend(

View File

@ -24,13 +24,13 @@ impl<'a, 'b> Guide<'a, 'b> {
}
pub fn head_into_dot_segment(&self, head: &Head, into: DotIndex, width: f64) -> Line {
let from_circle = self.head_circle(&head, width);
let from_circle = self.head_circle(head, width);
let to_circle = Circle {
pos: self.layout.primitive(into).weight().circle.pos,
r: 0.0,
};
let from_cw = self.head_cw(&head);
let from_cw = self.head_cw(head);
math::tangent_segment(from_circle, from_cw, to_circle, None)
}
@ -41,10 +41,10 @@ impl<'a, 'b> Guide<'a, 'b> {
cw: bool,
width: f64,
) -> Line {
let from_circle = self.head_circle(&head, width);
let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width);
let from_cw = self.head_cw(&head);
let from_cw = self.head_cw(head);
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
}
@ -54,10 +54,10 @@ impl<'a, 'b> Guide<'a, 'b> {
around: DotIndex,
width: f64,
) -> (Line, Line) {
let from_circle = self.head_circle(&head, width);
let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width);
let from_cw = self.head_cw(&head);
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])
@ -70,10 +70,10 @@ impl<'a, 'b> Guide<'a, 'b> {
cw: bool,
width: f64,
) -> Line {
let from_circle = self.head_circle(&head, width);
let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width);
let from_cw = self.head_cw(&head);
let from_cw = self.head_cw(head);
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
}

View File

@ -176,11 +176,22 @@ impl Layout {
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]
#[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))]
pub fn extend_bend(&mut self, bend: BendIndex, dot: DotIndex, to: Point) -> Result<(), ()> {
pub fn flip_bend(&mut self, bend: BendIndex) {
self.remove_from_rtree(bend.tag());
let result = self.move_dot(dot, to);
let cw = self
.graph
.node_weight(bend.index)
.unwrap()
.as_bend()
.unwrap()
.cw;
self.graph
.node_weight_mut(bend.index)
.unwrap()
.as_bend_mut()
.unwrap()
.cw = !cw;
self.insert_into_rtree(bend.tag());
result
}
pub fn bow(&self, bend: BendIndex) -> Bow {
@ -195,6 +206,9 @@ impl Layout {
Segbend::from_dot_next(dot, &self.graph)
}
#[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count()))]
#[debug_ensures(ret.is_ok() -> self.graph.edge_count() == old(self.graph.edge_count()))]
#[debug_ensures(ret.is_err() -> self.graph.node_count() == old(self.graph.node_count() - 1))]
fn fail_and_remove_if_collides_except<Weight: std::marker::Copy>(
&mut self,
index: Index<Weight>,
@ -230,16 +244,12 @@ impl Layout {
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]
#[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))]
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), ()> {
let mut cur_bend = self.primitive(dot).outer();
loop {
if let None = cur_bend {
break;
}
self.remove_from_rtree(cur_bend.unwrap().tag());
cur_bend = self.primitive(cur_bend.unwrap()).outer();
}
self.primitive(dot)
.tagged_prev()
.map(|prev| self.remove_from_rtree(prev));
self.primitive(dot)
.tagged_next()
.map(|next| self.remove_from_rtree(next));
self.remove_from_rtree(dot.tag());
let mut dot_weight = self.primitive(dot).weight();
@ -251,22 +261,24 @@ impl Layout {
if let Some(..) = self.detect_collision_except(dot, &[]) {
// Restore original state.
*self.graph.node_weight_mut(dot.index).unwrap() = TaggedWeight::Dot(old_weight);
self.insert_into_rtree(dot.tag());
self.primitive(dot)
.tagged_prev()
.map(|prev| self.insert_into_rtree(prev));
self.primitive(dot)
.tagged_next()
.map(|next| self.insert_into_rtree(next));
return Err(());
}
self.insert_into_rtree(dot.tag());
let mut cur_bend = self.primitive(dot).outer();
loop {
match cur_bend {
Some(..) => (),
None => break,
}
self.insert_into_rtree(cur_bend.unwrap().tag());
cur_bend = self.primitive(cur_bend.unwrap()).outer();
}
self.primitive(dot)
.tagged_prev()
.map(|prev| self.insert_into_rtree(prev));
self.primitive(dot)
.tagged_next()
.map(|next| self.insert_into_rtree(next));
Ok(())
}