diff options
Diffstat (limited to 'packages/svgbob/src/buffer/fragment_buffer/fragment/marker_line.rs')
-rw-r--r-- | packages/svgbob/src/buffer/fragment_buffer/fragment/marker_line.rs | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/packages/svgbob/src/buffer/fragment_buffer/fragment/marker_line.rs b/packages/svgbob/src/buffer/fragment_buffer/fragment/marker_line.rs new file mode 100644 index 0000000..e52f965 --- /dev/null +++ b/packages/svgbob/src/buffer/fragment_buffer/fragment/marker_line.rs @@ -0,0 +1,182 @@ +use crate::{ + fragment::{marker_line, Bounds, Cell, Fragment, Line, Polygon}, + Point, +}; +use sauron::{html::attributes::class, Node}; +use std::fmt; + +#[derive(Debug, Clone, PartialEq)] +pub enum Marker { + // --> + Arrow, + // ---|> + ClearArrow, + // ----* + Circle, + // -----# + Square, + // \ + // \ + // # + Diamond, + // -----o + OpenCircle, + // -----O + BigOpenCircle, +} + +impl Marker { + fn is_arrow(&self) -> bool { + match self { + Marker::Arrow | Marker::ClearArrow => true, + _ => false, + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct MarkerLine { + pub line: Line, + pub start_marker: Option<Marker>, + pub end_marker: Option<Marker>, +} + +impl MarkerLine { + pub fn new( + a: Point, + b: Point, + is_broken: bool, + start_marker: Option<Marker>, + end_marker: Option<Marker>, + ) -> Self { + MarkerLine { + line: Line::new_noswap(a, b, is_broken), + start_marker, + end_marker, + } + } + + pub fn absolute_position(&self, cell: Cell) -> Self { + MarkerLine { + line: self.line.absolute_position(cell), + start_marker: self.start_marker.clone(), + end_marker: self.end_marker.clone(), + } + } + + pub fn align(&self) -> Self { + MarkerLine { + line: self.line.align(), + start_marker: self.start_marker.clone(), + end_marker: self.end_marker.clone(), + } + } + + pub fn scale(&self, scale: f32) -> Self { + MarkerLine { + line: self.line.scale(scale), + start_marker: self.start_marker.clone(), + end_marker: self.end_marker.clone(), + } + } + + /// merge this marker line to the polygon + pub(crate) fn merge_polygon(&self, polygon: &Polygon) -> Option<Fragment> { + let poly_center = polygon.center(); + let distance_end_center = self.line.end.distance(&poly_center); + let distance_start_center = self.line.start.distance(&poly_center); + + let line_heading = self.line.heading(); + + let threshold_length = line_heading.threshold_length(); + let is_close_start_point = distance_start_center < threshold_length; + let is_close_end_point = distance_end_center < threshold_length; + + let is_same_direction = polygon.matched_direction(line_heading); + + let is_opposite_direction = + polygon.matched_direction(line_heading.opposite()); + + let can_merge = (is_same_direction || is_opposite_direction) + && (is_close_start_point || is_close_end_point); + + if can_merge { + let marker = polygon.get_marker(); + + let start_marker = + if is_close_start_point && self.start_marker.is_none() { + marker.clone() + } else { + self.start_marker.clone() + }; + let end_marker = if is_close_end_point && self.end_marker.is_none() + { + marker + } else { + self.end_marker.clone() + }; + + let extended_line = if is_close_start_point { + self.line.extend_start(threshold_length / 2.0) + } else if is_close_end_point { + self.line.extend(threshold_length / 2.0) + } else { + panic!("There is no endpoint close to the polygon"); + }; + + Some(marker_line( + extended_line.start, + extended_line.end, + extended_line.is_broken, + start_marker, + end_marker, + )) + } else { + None + } + } +} + +impl Bounds for MarkerLine { + fn bounds(&self) -> (Point, Point) { + self.line.bounds() + } +} + +impl fmt::Display for Marker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Marker::Arrow => write!(f, "arrow"), + Marker::ClearArrow => write!(f, "clear_arrow"), + Marker::Circle => write!(f, "circle"), + Marker::Square => write!(f, "square"), + Marker::Diamond => write!(f, "diamond"), + Marker::OpenCircle => write!(f, "open_circle"), + Marker::BigOpenCircle => write!(f, "big_open_circle"), + } + } +} + +impl fmt::Display for MarkerLine { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{} {:?} {:?}", + self.line, self.start_marker, self.end_marker + ) + } +} + +impl<MSG> Into<Node<MSG>> for MarkerLine { + fn into(self) -> Node<MSG> { + let node: Node<MSG> = self.line.into(); + let mut classes = vec![]; + if let Some(start_marker) = self.start_marker { + classes.push(class(format!("start_marked_{}", start_marker))); + } + if let Some(end_marker) = self.end_marker { + classes.push(class(format!("end_marked_{}", end_marker))); + } + node.add_attributes(classes) + } +} |