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 contracts::{debug_ensures, debug_requires};
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use geo::{EuclideanLength, Point};
|
use geo::{EuclideanDistance, EuclideanLength, Point};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graph::{BendIndex, BendWeight, DotIndex, DotWeight, Ends, SegIndex, SegWeight, TaggedIndex},
|
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()))]
|
#[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))]
|
||||||
fn segbend_around(
|
fn segbend_around(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut head: Head,
|
head: Head,
|
||||||
around: TaggedIndex,
|
around: TaggedIndex,
|
||||||
from: Point,
|
from: Point,
|
||||||
to: Point,
|
to: Point,
|
||||||
cw: bool,
|
cw: bool,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<SegbendHead, ()> {
|
) -> Result<SegbendHead, ()> {
|
||||||
head = self.extend_head(head, from)?;
|
let head = self.extend_head(head, from)?;
|
||||||
self.segbend(head, around, to, cw, width)
|
self.segbend(head, around, to, cw, width)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
|
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
|
||||||
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> {
|
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> {
|
||||||
if let Head::Segbend(head) = 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 {
|
} else {
|
||||||
Ok(head)
|
Ok(head)
|
||||||
// No assertion for now because we temporarily use floats.
|
// 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_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()))]
|
#[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))]
|
||||||
fn segbend(
|
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 {
|
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 {
|
let to_circle = Circle {
|
||||||
pos: self.layout.primitive(into).weight().circle.pos,
|
pos: self.layout.primitive(into).weight().circle.pos,
|
||||||
r: 0.0,
|
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)
|
math::tangent_segment(from_circle, from_cw, to_circle, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,10 +41,10 @@ impl<'a, 'b> Guide<'a, 'b> {
|
||||||
cw: bool,
|
cw: bool,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Line {
|
) -> 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 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))
|
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,10 +54,10 @@ impl<'a, 'b> Guide<'a, 'b> {
|
||||||
around: DotIndex,
|
around: DotIndex,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> (Line, Line) {
|
) -> (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 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> =
|
let tangents: Vec<Line> =
|
||||||
math::tangent_segments(from_circle, from_cw, to_circle, None).collect();
|
math::tangent_segments(from_circle, from_cw, to_circle, None).collect();
|
||||||
(tangents[0], tangents[1])
|
(tangents[0], tangents[1])
|
||||||
|
|
@ -70,10 +70,10 @@ impl<'a, 'b> Guide<'a, 'b> {
|
||||||
cw: bool,
|
cw: bool,
|
||||||
width: f64,
|
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 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))
|
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.node_count() == old(self.graph.node_count()))]
|
||||||
#[debug_ensures(self.graph.edge_count() == old(self.graph.edge_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());
|
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());
|
self.insert_into_rtree(bend.tag());
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bow(&self, bend: BendIndex) -> Bow {
|
pub fn bow(&self, bend: BendIndex) -> Bow {
|
||||||
|
|
@ -195,6 +206,9 @@ impl Layout {
|
||||||
Segbend::from_dot_next(dot, &self.graph)
|
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>(
|
fn fail_and_remove_if_collides_except<Weight: std::marker::Copy>(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: Index<Weight>,
|
index: Index<Weight>,
|
||||||
|
|
@ -230,16 +244,12 @@ impl Layout {
|
||||||
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]
|
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]
|
||||||
#[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))]
|
#[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))]
|
||||||
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), ()> {
|
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), ()> {
|
||||||
let mut cur_bend = self.primitive(dot).outer();
|
self.primitive(dot)
|
||||||
loop {
|
.tagged_prev()
|
||||||
if let None = cur_bend {
|
.map(|prev| self.remove_from_rtree(prev));
|
||||||
break;
|
self.primitive(dot)
|
||||||
}
|
.tagged_next()
|
||||||
|
.map(|next| self.remove_from_rtree(next));
|
||||||
self.remove_from_rtree(cur_bend.unwrap().tag());
|
|
||||||
cur_bend = self.primitive(cur_bend.unwrap()).outer();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.remove_from_rtree(dot.tag());
|
self.remove_from_rtree(dot.tag());
|
||||||
|
|
||||||
let mut dot_weight = self.primitive(dot).weight();
|
let mut dot_weight = self.primitive(dot).weight();
|
||||||
|
|
@ -251,22 +261,24 @@ impl Layout {
|
||||||
if let Some(..) = self.detect_collision_except(dot, &[]) {
|
if let Some(..) = self.detect_collision_except(dot, &[]) {
|
||||||
// Restore original state.
|
// Restore original state.
|
||||||
*self.graph.node_weight_mut(dot.index).unwrap() = TaggedWeight::Dot(old_weight);
|
*self.graph.node_weight_mut(dot.index).unwrap() = TaggedWeight::Dot(old_weight);
|
||||||
|
|
||||||
self.insert_into_rtree(dot.tag());
|
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(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.insert_into_rtree(dot.tag());
|
self.insert_into_rtree(dot.tag());
|
||||||
|
self.primitive(dot)
|
||||||
let mut cur_bend = self.primitive(dot).outer();
|
.tagged_prev()
|
||||||
loop {
|
.map(|prev| self.insert_into_rtree(prev));
|
||||||
match cur_bend {
|
self.primitive(dot)
|
||||||
Some(..) => (),
|
.tagged_next()
|
||||||
None => break,
|
.map(|next| self.insert_into_rtree(next));
|
||||||
}
|
|
||||||
|
|
||||||
self.insert_into_rtree(cur_bend.unwrap().tag());
|
|
||||||
cur_bend = self.primitive(cur_bend.unwrap()).outer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue