1use crate::prelude::*;
9use crate::traits::{MapPointwise, TryBoundingBox};
10use num_traits::{Num, NumCast};
11
12#[derive(PartialEq, Eq, Clone, Debug, Hash)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15pub enum Geometry<T> {
16 Point(Point<T>),
18 Edge(Edge<T>),
20 Rect(Rect<T>),
22 SimplePolygon(SimplePolygon<T>),
24 SimpleRPolygon(SimpleRPolygon<T>),
26 Polygon(Polygon<T>),
28 Path(Path<T>),
30 Text(Text<T>),
32}
33
34impl<T: CoordinateType> Geometry<T> {
35 pub fn transformed(&self, tf: &SimpleTransform<T>) -> Self {
37 let trans = |p| tf.transform_point(p);
38 match self {
39 Geometry::Point(p) => tf.transform_point(*p).into(),
40 Geometry::Edge(g) => g.transform(trans).into(),
41 Geometry::Rect(g) => g.transform(trans).into(),
42 Geometry::SimplePolygon(g) => g.transform(trans).into(),
43 Geometry::SimpleRPolygon(g) => g.transformed(tf).into(),
44 Geometry::Polygon(g) => g.transform(trans).into(),
45 Geometry::Path(p) => p.transform(tf).into(),
46 Geometry::Text(g) => g.transform(trans).into(),
47 }
48 }
49}
50
51macro_rules! geometry_from {
53 ( $t:tt ) => {
54 impl<T> From<$t<T>> for Geometry<T> {
55 fn from(x: $t<T>) -> Geometry<T> {
56 Geometry::$t(x)
57 }
58 }
59 };
60}
61
62geometry_from!(Point);
64geometry_from!(Edge);
65geometry_from!(Rect);
66geometry_from!(SimplePolygon);
67geometry_from!(SimpleRPolygon);
68geometry_from!(Polygon);
69geometry_from!(Path);
70geometry_from!(Text);
71
72impl<T: Copy + PartialOrd + Num> TryBoundingBox<T> for Geometry<T> {
73 fn try_bounding_box(&self) -> Option<Rect<T>> {
75 match self {
76 Geometry::Point(p) => p.try_bounding_box(),
77 Geometry::Edge(e) => e.try_bounding_box(),
78 Geometry::Rect(e) => e.try_bounding_box(),
79 Geometry::SimplePolygon(e) => e.try_bounding_box(),
80 Geometry::SimpleRPolygon(e) => e.try_bounding_box(),
81 Geometry::Polygon(e) => e.try_bounding_box(),
82 Geometry::Path(p) => p.try_bounding_box(),
83 Geometry::Text(t) => t.try_bounding_box(),
84 }
85 }
86}
87
88impl<T: CoordinateType + NumCast> DoubledOrientedArea<T> for Geometry<T> {
105 fn area_doubled_oriented(&self) -> T {
107 match self {
108 Geometry::Point(_) => T::zero(),
109 Geometry::Edge(_) => T::zero(),
110 Geometry::Rect(e) => e.area_doubled_oriented(),
111 Geometry::SimplePolygon(e) => e.area_doubled_oriented(),
112 Geometry::SimpleRPolygon(e) => e.area_doubled_oriented(),
113 Geometry::Polygon(e) => e.area_doubled_oriented(),
114 Geometry::Path(p) => {
115 T::from(FloatType::round(p.area_approx::<FloatType>() * 2.0_f64)).unwrap()
117 }
118 Geometry::Text(_) => T::zero(),
119 }
120 }
121}
122
123impl<T: CoordinateType + NumCast> ToPolygon<T> for Geometry<T> {
124 fn to_polygon(&self) -> Polygon<T> {
138 match self {
139 Geometry::Point(_) => Polygon::empty(),
140 Geometry::Edge(_) => Polygon::empty(),
141 Geometry::Rect(e) => e.to_polygon(),
142 Geometry::SimplePolygon(e) => Polygon::from(e),
143 Geometry::SimpleRPolygon(p) => Polygon::from(p.to_simple_polygon()),
144 Geometry::Polygon(e) => e.clone(),
145 Geometry::Path(p) => p.to_polygon_approx().cast().into(),
146 Geometry::Text(_) => Polygon::empty(),
147 }
148 }
149}
150
151impl<T: CoordinateType + NumCast> From<Geometry<T>> for Polygon<T> {
152 fn from(g: Geometry<T>) -> Self {
154 g.to_polygon()
155 }
156}
157
158impl<T: CoordinateType + NumCast, Dst: CoordinateType + NumCast> TryCastCoord<T, Dst>
159 for Geometry<T>
160{
161 type Output = Geometry<Dst>;
162
163 fn try_cast(&self) -> Option<Self::Output> {
164 match self {
165 Geometry::Point(p) => p.try_cast().map(|s| s.into()),
166 Geometry::Edge(e) => e.try_cast().map(|s| s.into()),
167 Geometry::Rect(r) => r.try_cast().map(|s| s.into()),
168 Geometry::SimplePolygon(p) => p.try_cast().map(|s| s.into()),
169 Geometry::SimpleRPolygon(p) => p.try_cast().map(|s| s.into()),
170 Geometry::Polygon(p) => p.try_cast().map(|s| s.into()),
171 Geometry::Path(p) => p.try_cast().map(|s| s.into()),
172 Geometry::Text(t) => t.try_cast().map(|s| s.into()),
173 }
174 }
175}
176
177#[test]
178fn test_convert_to_polygon() {
180 let geometries: Vec<Geometry<_>> = vec![
181 Point::new(0, 0).into(),
182 Edge::new((0, 0), (1, 1)).into(),
183 Rect::new((0, 0), (1, 1)).into(),
184 SimplePolygon::from(vec![(0, 0), (1, 0), (1, 1)]).into(),
185 Polygon::new(vec![(0, 0), (1, 0), (1, 1)]).into(),
186 ];
187
188 for g in geometries {
189 assert_eq!(
190 g.area_doubled_oriented(),
191 g.to_polygon().area_doubled_oriented()
192 );
193 }
194}