summaryrefslogtreecommitdiffstats
path: root/packages/svgbob/src/buffer/fragment_buffer/fragment/marker_line.rs
diff options
context:
space:
mode:
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.rs182
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)
+ }
+}