From 0695b1deab75078ef1ea7ce9f93f90e1fed3e01e Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 19 Sep 2023 20:56:40 +0200 Subject: [PATCH] draw: Implement flipping the bend if a shorter one is available --- src/draw.rs | 36 ++++++++++++++++++++++--------- src/guide.rs | 16 +++++++------- src/layout.rs | 60 ++++++++++++++++++++++++++++++--------------------- 3 files changed, 70 insertions(+), 42 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 2d78c61..2bdb60a 100644 --- a/src/draw.rs +++ b/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 { - 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 { 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 { - 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( diff --git a/src/guide.rs b/src/guide.rs index 35c3d36..263c7e3 100644 --- a/src/guide.rs +++ b/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 = 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)) } diff --git a/src/layout.rs b/src/layout.rs index 97a10ba..18ed68c 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -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( &mut self, index: Index, @@ -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(()) }