summaryrefslogtreecommitdiffstats
path: root/packages/svgbob/src/buffer/fragment_buffer/fragment/rect.rs
diff options
context:
space:
mode:
Diffstat (limited to 'packages/svgbob/src/buffer/fragment_buffer/fragment/rect.rs')
-rw-r--r--packages/svgbob/src/buffer/fragment_buffer/fragment/rect.rs198
1 files changed, 198 insertions, 0 deletions
diff --git a/packages/svgbob/src/buffer/fragment_buffer/fragment/rect.rs b/packages/svgbob/src/buffer/fragment_buffer/fragment/rect.rs
new file mode 100644
index 0000000..2942991
--- /dev/null
+++ b/packages/svgbob/src/buffer/fragment_buffer/fragment/rect.rs
@@ -0,0 +1,198 @@
+use crate::{fragment::Bounds, util, Cell, Point};
+use parry2d::shape::ConvexPolygon;
+use parry2d::shape::{Polyline, Segment, Shape};
+use sauron::{
+ html::attributes::*,
+ svg::{attributes::*, *},
+ Node,
+};
+use std::cmp::Ordering;
+use std::fmt;
+
+#[derive(Debug, Clone)]
+pub struct Rect {
+ pub start: Point,
+ pub end: Point,
+ pub is_filled: bool,
+ pub radius: Option<f32>,
+ //TODO:Make this as enum
+ pub is_broken: bool,
+}
+
+impl Rect {
+ /// creates a new rect and reorder the points swapping the end points if necessary
+ /// such that the start is the most top-left and end point is the most bottom-right
+ pub(in crate) fn new(
+ start: Point,
+ end: Point,
+ is_filled: bool,
+ is_broken: bool,
+ ) -> Self {
+ let mut rect = Rect {
+ start,
+ end,
+ is_filled,
+ radius: None,
+ is_broken,
+ };
+ rect.sort_reorder_end_points();
+ rect
+ }
+
+ pub(in crate) fn rounded_new(
+ start: Point,
+ end: Point,
+ is_filled: bool,
+ radius: f32,
+ is_broken: bool,
+ ) -> Self {
+ let mut rect = Rect {
+ start,
+ end,
+ is_filled,
+ radius: Some(radius),
+ is_broken,
+ };
+ rect.sort_reorder_end_points();
+ rect
+ }
+
+ /// reorder the end points swap end points such that
+ /// start < end
+ pub(in crate) fn sort_reorder_end_points(&mut self) {
+ if self.start > self.end {
+ let tmp_start = self.start;
+ self.start = self.end;
+ self.end = tmp_start;
+ }
+ }
+
+ /// recompute the rect with start and end point offset by the cell
+ /// location
+ pub(in crate) fn absolute_position(&self, cell: Cell) -> Self {
+ Rect {
+ start: cell.absolute_position(self.start),
+ end: cell.absolute_position(self.end),
+ ..*self
+ }
+ }
+
+ pub(in crate) fn scale(&self, scale: f32) -> Self {
+ Rect {
+ start: self.start.scale(scale),
+ end: self.end.scale(scale),
+ radius: self.radius.map(|r| r * scale),
+ ..*self
+ }
+ }
+
+ pub(crate) fn width(&self) -> f32 {
+ self.end.x - self.start.x
+ }
+
+ pub(crate) fn height(&self) -> f32 {
+ self.end.y - self.start.y
+ }
+
+ pub(crate) fn is_broken(&self) -> bool {
+ self.is_broken
+ }
+
+ pub fn is_rounded(&self) -> bool {
+ if let Some(ref r) = &self.radius {
+ *r > 0.0
+ } else {
+ false
+ }
+ }
+}
+
+impl Bounds for Rect {
+ fn bounds(&self) -> (Point, Point) {
+ let aabb = Segment::new(*self.start, *self.end).local_aabb();
+ (Point::from(*aabb.mins), Point::from(*aabb.maxs))
+ }
+}
+
+impl fmt::Display for Rect {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "R {} {}", self.start, self.end)
+ }
+}
+
+impl Into<Polyline> for Rect {
+ fn into(self) -> Polyline {
+ Polyline::new(
+ vec![
+ *self.start,
+ *Point::new(self.end.x, self.start.y),
+ *self.end,
+ *Point::new(self.start.x, self.end.y),
+ *self.start,
+ ],
+ None,
+ )
+ }
+}
+
+impl Into<ConvexPolygon> for Rect {
+ fn into(self) -> ConvexPolygon {
+ ConvexPolygon::from_convex_polyline(vec![
+ *self.start,
+ *Point::new(self.end.x, self.start.y),
+ *self.end,
+ *Point::new(self.start.x, self.end.y),
+ ])
+ .expect("must create a convex polygon")
+ }
+}
+
+impl<MSG> Into<Node<MSG>> for Rect {
+ fn into(self) -> Node<MSG> {
+ rect(
+ [
+ x(self.start.x),
+ y(self.start.y),
+ width(self.width()),
+ height(self.height()),
+ classes_flag([
+ ("broken", self.is_broken),
+ ("solid", !self.is_broken),
+ ("filled", self.is_filled),
+ ("nofill", !self.is_filled),
+ ]),
+ if let Some(radius) = self.radius {
+ rx(radius)
+ } else {
+ rx(0)
+ },
+ ],
+ [],
+ )
+ }
+}
+
+impl Eq for Rect {}
+
+impl Ord for Rect {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.start
+ .cmp(&other.start)
+ .then(self.end.cmp(&other.end))
+ .then(self.is_filled.cmp(&other.is_filled))
+ .then(util::opt_ord(self.radius, other.radius))
+ .then(self.is_broken.cmp(&other.is_broken))
+ }
+}
+
+impl PartialOrd for Rect {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for Rect {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}