iron_shapes/
concepts_impl.rs

1// SPDX-FileCopyrightText: 2022 Thomas Kramer
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5//! Implement the geometry concepts for the default data types.
6
7use crate::concepts::*;
8use crate::isotropy::*;
9use crate::prelude as types;
10use crate::prelude::{CoordinateType, IntoEdges, Scale};
11
12impl<C> PointBase<C> for types::Point<C::Coord>
13where
14    C: CoordinateBase,
15{
16    fn new(x: C::Coord, y: C::Coord) -> Self {
17        types::Point::new(x, y)
18    }
19
20    fn get(&self, orient: Orientation2D) -> C::Coord {
21        match orient {
22            Orientation2D::Horizontal => self.x,
23            Orientation2D::Vertical => self.y,
24        }
25    }
26
27    fn set(&mut self, orient: Orientation2D, value: C::Coord) {
28        let c = match orient {
29            Orientation2D::Horizontal => &mut self.x,
30            Orientation2D::Vertical => &mut self.y,
31        };
32        *c = value
33    }
34}
35
36impl<C> PointConcept<C> for types::Point<C::Coord> where C: CoordinateConcept {}
37
38impl<C> Segment<C> for types::REdge<C::Coord>
39where
40    C: CoordinateConcept,
41{
42    type Point = types::Point<C::Coord>;
43
44    fn get_point(&self, dir: Direction1D) -> Self::Point {
45        match dir {
46            Direction1D::Low => self.start(),
47            Direction1D::High => self.end(),
48        }
49    }
50}
51
52impl<C> Interval<C> for types::Interval<C>
53where
54    C: CoordinateType,
55{
56    fn get(&self, d: Direction1D) -> C {
57        match d {
58            Direction1D::Low => self.start(),
59            Direction1D::High => self.end(),
60        }
61    }
62}
63
64impl<C> Rectangle<C> for types::Rect<C::Coord>
65where
66    C: CoordinateConcept,
67{
68    type Interval = types::Interval<C::Coord>;
69
70    fn get(&self, orientation: Orientation2D) -> Self::Interval {
71        // let start = self.lower_left.get(orientation);
72        // let end = self.upper_right.get(orientation);
73        let (start, end) = match orientation {
74            Orientation2D::Horizontal => (self.lower_left().x, self.upper_right().x),
75            Orientation2D::Vertical => (self.lower_left().y, self.upper_right().y),
76        };
77        types::Interval::new(start, end)
78    }
79}
80
81impl<C> Polygon90<C> for types::Rect<C::Coord>
82where
83    C: CoordinateConcept,
84{
85    type CompactIterator = std::vec::IntoIter<C::Coord>;
86
87    fn compact_iter(&self) -> Self::CompactIterator {
88        vec![
89            self.lower_left.x,
90            self.lower_left.y,
91            self.upper_right.x,
92            self.upper_right.y,
93        ]
94        .into_iter()
95    }
96}
97
98impl<C> Polygon<C> for types::Rect<C::Coord>
99where
100    C: CoordinateConcept,
101{
102    fn set(&mut self, _iter: impl Iterator<Item = <Self as PolygonSet<C>>::Point>) {
103        // iter.map(|p| types::Rect::new(p, p))
104        //     .reduce(|acc, rect| acc.add_rect(p))
105        unimplemented!()
106    }
107}
108
109impl<C> PolygonWithHoles<C> for types::Rect<C::Coord>
110where
111    C: CoordinateConcept,
112{
113    fn num_holes(&self) -> usize {
114        0
115    }
116}
117
118impl<C> Polygon90WithHoles<C> for types::Rect<C::Coord> where C: CoordinateConcept {}
119
120impl<C> Polygon90Set<C> for types::Rect<C::Coord> where C: CoordinateConcept {}
121
122impl<C> IntoSegments<C> for types::Rect<C::Coord>
123where
124    C: CoordinateConcept,
125{
126    type Segment = types::REdge<C::Coord>;
127    type SegmentIter = types::RectEdgeIterator<C::Coord>;
128
129    fn into_segments(self) -> Self::SegmentIter {
130        self.into_edges()
131    }
132}
133
134impl<C> IntoPoints<C> for types::Rect<C::Coord>
135where
136    C: CoordinateConcept,
137{
138    type Point = types::Point<C::Coord>;
139    type PointIter = <Self as IntoIterator>::IntoIter;
140
141    fn into_points(self) -> Self::PointIter {
142        self.into_iter()
143    }
144}
145
146impl<C> PolygonSet<C> for types::Rect<C::Coord>
147where
148    C: CoordinateConcept,
149{
150    type Point = types::Point<C::Coord>;
151    type Segment = types::REdge<C::Coord>;
152    type AllPoints = <Self as IntoIterator>::IntoIter;
153
154    fn num_polygons(&self) -> usize {
155        1
156    }
157
158    fn convolved(mut self, p: &Self::Point) -> Self {
159        self.lower_left = self.lower_left + p;
160        self.upper_right = self.upper_right + p;
161        self
162    }
163
164    fn convolve(&mut self, p: &Self::Point) {
165        self.lower_left = self.lower_left + p;
166        self.upper_right = self.upper_right + p;
167    }
168
169    fn scaled(self, scale: C::Coord) -> Self {
170        self.scale(scale);
171        self
172    }
173
174    fn scale(&mut self, scale: C::Coord) {
175        self.upper_right = self.upper_right * scale;
176        self.lower_left = self.lower_left * scale;
177    }
178
179    fn all_points(&self) -> Self::AllPoints {
180        self.into_iter()
181    }
182}
183
184#[test]
185fn test_point() {
186    fn some_point_function<P: PointBase<C>, C: CoordinateBase>(p: P) -> C::Coord {
187        p.x() + p.y()
188    }
189
190    let p = types::Point::new(1, 2);
191    assert_eq!(some_point_function::<_, i32>(p), 3);
192}