maker_panel/features/
rect.rs

1use geo::{Coordinate, MultiPolygon};
2use std::fmt;
3
4/// A rectangular region with square edges.
5#[derive(Debug, Clone)]
6pub struct Rect<U = super::Unit> {
7    rect: geo::Rect<f64>,
8    inner: U,
9}
10
11impl Rect {
12    /// Constructs a new rectangle using the provided corners.
13    pub fn new(top_left: Coordinate<f64>, bottom_right: Coordinate<f64>) -> Self {
14        Self {
15            rect: geo::Rect::new(top_left, bottom_right),
16            inner: super::Unit,
17        }
18    }
19
20    /// Constructs a new rectangle given a center point and sizes.
21    pub fn with_center(center: Coordinate<f64>, width: f64, height: f64) -> Self {
22        Self {
23            rect: geo::Rect::new(
24                center
25                    + Coordinate {
26                        x: -width / 2.,
27                        y: -height / 2.,
28                    },
29                center
30                    + Coordinate {
31                        x: width / 2.,
32                        y: height / 2.,
33                    },
34            ),
35            inner: super::Unit,
36        }
37    }
38}
39
40impl<U: super::InnerFeature + Clone + std::fmt::Debug> Rect<U> {
41    /// Constructs a rectangle surrounding the inner feature. The
42    /// origin of the inner feature will match the centeroid of the
43    /// rectangle.
44    pub fn with_inner(inner: U) -> Self {
45        let tl: Coordinate<f64> = [-1f64, -1f64].into();
46        let br: Coordinate<f64> = [1f64, 1f64].into();
47        let rect = geo::Rect::new(tl, br);
48        Self { rect, inner }
49    }
50
51    /// Returns a new rectangle around the provided center.
52    pub fn dimensions(mut self, center: Coordinate<f64>, width: f64, height: f64) -> Self {
53        let rect = geo::Rect::new(
54            center
55                + Coordinate {
56                    x: -width / 2.,
57                    y: -height / 2.,
58                },
59            center
60                + Coordinate {
61                    x: width / 2.,
62                    y: height / 2.,
63                },
64        );
65        self.inner.translate(center);
66        Self {
67            rect,
68            inner: self.inner,
69        }
70    }
71
72    /// Returns a new rectangle using the provided bounds.
73    pub fn bounds(mut self, top_left: Coordinate<f64>, bottom_right: Coordinate<f64>) -> Self {
74        let rect = geo::Rect::new(top_left, bottom_right);
75        self.inner.translate(rect.center());
76        Self {
77            rect,
78            inner: self.inner,
79        }
80    }
81}
82
83impl<U: super::InnerFeature> fmt::Display for Rect<U> {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        write!(
86            f,
87            "rect({:?}, {:?}, U = {})",
88            self.rect.min(),
89            self.rect.max(),
90            self.inner
91        )
92    }
93}
94
95impl<U: super::InnerFeature + Clone + std::fmt::Debug> super::Feature for Rect<U> {
96    fn name(&self) -> &'static str {
97        "rect"
98    }
99
100    fn edge_union(&self) -> Option<MultiPolygon<f64>> {
101        Some(self.rect.clone().to_polygon().into())
102    }
103
104    fn translate(&mut self, v: Coordinate<f64>) {
105        use geo::algorithm::translate::Translate;
106        self.rect.translate_inplace(v.x, v.y);
107        self.inner.translate(v);
108    }
109
110    fn interior(&self) -> Vec<super::InnerAtom> {
111        self.inner.atoms()
112    }
113}