mirror of https://codeberg.org/topola/topola.git
draw: Implement flipping the bend if a shorter one is available
This commit is contained in:
parent
abf92c7f43
commit
0695b1deab
36
src/draw.rs
36
src/draw.rs
|
|
@ -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(
|
||||
|
|
|
|||
16
src/guide.rs
16
src/guide.rs
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue