microcad_core/geo2d/
geometry.rs1use super::*;
5use crate::traits::{Center, TotalMemory, VertexCount};
6use derive_more::From;
7
8use geo::{ConvexHull, MultiPolygon};
9use strum::IntoStaticStr;
10
11#[derive(IntoStaticStr, From, Clone, Debug)]
13pub enum Geometry2D {
14 LineString(LineString),
16 MultiLineString(MultiLineString),
18 Polygon(Polygon),
20 MultiPolygon(MultiPolygon),
22 Rect(Rect),
24 Line(Line),
26 Collection(Geometries2D),
28}
29
30impl Geometry2D {
31 pub fn name(&self) -> &'static str {
33 self.into()
34 }
35
36 pub fn boolean_op(self, other: Self, op: &BooleanOp) -> geo2d::MultiPolygon {
38 use geo::BooleanOps;
39 self.to_multi_polygon()
40 .boolean_op(&other.to_multi_polygon(), op.into())
41 }
42
43 pub fn to_multi_polygon(&self) -> MultiPolygon {
45 match self {
46 Geometry2D::Line(_) | Geometry2D::LineString(_) | Geometry2D::MultiLineString(_) => {
47 MultiPolygon::empty()
48 }
49 Geometry2D::Polygon(polygon) => MultiPolygon(vec![polygon.clone()]),
50 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.clone(),
51 Geometry2D::Rect(rect) => MultiPolygon(vec![rect.to_polygon()]),
52 Geometry2D::Collection(collection) => collection.to_multi_polygon(),
53 }
54 }
55
56 pub fn hull(&self) -> Self {
58 match self {
59 Geometry2D::LineString(line_string) => Geometry2D::Polygon(line_string.convex_hull()),
60 Geometry2D::MultiLineString(multi_line_string) => {
61 Geometry2D::Polygon(multi_line_string.convex_hull())
62 }
63 Geometry2D::Polygon(polygon) => Geometry2D::Polygon(polygon.convex_hull()),
64 Geometry2D::MultiPolygon(multi_polygon) => {
65 Geometry2D::Polygon(multi_polygon.convex_hull())
66 }
67 Geometry2D::Rect(rect) => Geometry2D::Rect(*rect),
68 Geometry2D::Line(line) => Geometry2D::Polygon(
69 LineString::new(vec![line.0.into(), line.1.into()]).convex_hull(),
70 ),
71 Geometry2D::Collection(collection) => Geometry2D::Polygon(collection.hull()),
72 }
73 }
74
75 pub fn is_areal(&self) -> bool {
77 !matches!(
78 self,
79 Geometry2D::LineString(_)
80 | Geometry2D::MultiLineString(_)
81 | Geometry2D::Line(_)
82 | Geometry2D::Collection(_)
83 )
84 }
85
86 pub fn with_bounds(self) -> WithBounds2D<Geometry2D> {
88 let bounds = self.calc_bounds_2d();
89 WithBounds2D {
90 bounds,
91 inner: self,
92 }
93 }
94}
95
96impl CalcBounds2D for MultiPolygon {
97 fn calc_bounds_2d(&self) -> Bounds2D {
98 use geo::BoundingRect;
99 self.bounding_rect().into()
100 }
101}
102
103impl CalcBounds2D for Geometry2D {
104 fn calc_bounds_2d(&self) -> Bounds2D {
105 use geo::BoundingRect;
106
107 match &self {
108 Geometry2D::LineString(line_string) => line_string.bounding_rect().into(),
109 Geometry2D::MultiLineString(multi_line_string) => {
110 multi_line_string.bounding_rect().into()
111 }
112 Geometry2D::Polygon(polygon) => polygon.bounding_rect().into(),
113 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.calc_bounds_2d(),
114 Geometry2D::Rect(rect) => Some(*rect).into(),
115 Geometry2D::Line(line) => line.calc_bounds_2d(),
116 Geometry2D::Collection(collection) => collection.calc_bounds_2d(),
117 }
118 }
119}
120
121impl Transformed2D for Geometry2D {
122 fn transformed_2d(&self, mat: &Mat3) -> Self {
123 if self.is_areal() {
124 let multi_polygon: MultiPolygon = self.clone().into();
125 Self::MultiPolygon(multi_polygon.transformed_2d(mat))
126 } else {
127 match self {
128 Geometry2D::LineString(line_string) => {
129 Self::LineString(line_string.transformed_2d(mat))
130 }
131 Geometry2D::MultiLineString(multi_line_string) => {
132 Self::MultiLineString(multi_line_string.transformed_2d(mat))
133 }
134 Geometry2D::Line(line) => Self::Line(line.transformed_2d(mat)),
135 Geometry2D::Collection(geometries) => {
136 Self::Collection(geometries.transformed_2d(mat))
137 }
138 _ => unreachable!("Geometry type not supported"),
139 }
140 }
141 }
142}
143
144impl Center for Geometry2D {
145 fn center(&self) -> Self {
146 if let Some(bounds) = self.calc_bounds_2d().rect() {
147 let d: Vec2 = bounds.center().x_y().into();
148 self.transformed_2d(&Mat3::from_translation(-d))
149 } else {
150 self.clone()
151 }
152 }
153}
154
155impl geo::Buffer for Geometry2D {
156 type Scalar = Scalar;
157
158 fn buffer_with_style(
159 &self,
160 style: geo::buffer::BufferStyle<Self::Scalar>,
161 ) -> MultiPolygon<Self::Scalar> {
162 match &self {
163 Geometry2D::LineString(line_string) => line_string.buffer_with_style(style),
164 Geometry2D::MultiLineString(multi_line_string) => {
165 multi_line_string.buffer_with_style(style)
166 }
167 Geometry2D::Polygon(polygon) => polygon.buffer_with_style(style),
168 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.buffer_with_style(style),
169 Geometry2D::Rect(rect) => rect.buffer_with_style(style),
170 Geometry2D::Line(line) => {
171 LineString::new(vec![line.0.into(), line.1.into()]).buffer_with_style(style)
172 }
173 Geometry2D::Collection(collection) => collection.buffer_with_style(style),
174 }
175 }
176}
177
178impl From<Geometry2D> for MultiPolygon {
179 fn from(geo: Geometry2D) -> Self {
180 match geo {
181 Geometry2D::Polygon(polygon) => polygon.into(),
182 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon,
183 Geometry2D::Rect(rect) => MultiPolygon(vec![rect.to_polygon()]),
184 Geometry2D::Collection(collection) => collection.into(),
185 _ => MultiPolygon::empty(),
186 }
187 }
188}
189
190impl TotalMemory for LineString {
191 fn heap_memory(&self) -> usize {
192 self.0.heap_memory()
193 }
194}
195
196impl TotalMemory for MultiLineString {
197 fn heap_memory(&self) -> usize {
198 self.0.iter().map(|l| l.heap_memory()).sum()
199 }
200}
201
202impl TotalMemory for Polygon {
203 fn heap_memory(&self) -> usize {
204 self.exterior().heap_memory()
205 + self
206 .interiors()
207 .iter()
208 .map(|l| l.heap_memory())
209 .sum::<usize>()
210 }
211}
212
213impl TotalMemory for MultiPolygon {
214 fn heap_memory(&self) -> usize {
215 self.0.iter().map(|p| p.heap_memory()).sum()
216 }
217}
218
219impl TotalMemory for Rect {}
220impl TotalMemory for Line {}
221
222impl TotalMemory for Geometry2D {
223 fn heap_memory(&self) -> usize {
224 match &self {
225 Geometry2D::LineString(line_string) => line_string.heap_memory(),
226 Geometry2D::MultiLineString(multi_line_string) => multi_line_string.heap_memory(),
227 Geometry2D::Polygon(polygon) => polygon.heap_memory(),
228 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.heap_memory(),
229 Geometry2D::Rect(rect) => rect.heap_memory(),
230 Geometry2D::Line(line) => line.heap_memory(),
231 Geometry2D::Collection(collection) => collection.heap_memory(),
232 }
233 }
234}
235
236impl VertexCount for LineString {
237 fn vertex_count(&self) -> usize {
238 self.0.len()
239 }
240}
241
242impl VertexCount for MultiLineString {
243 fn vertex_count(&self) -> usize {
244 self.iter().map(|l| l.vertex_count()).sum()
245 }
246}
247
248impl VertexCount for Polygon {
249 fn vertex_count(&self) -> usize {
250 self.exterior().vertex_count()
251 + self
252 .interiors()
253 .iter()
254 .map(|l| l.vertex_count())
255 .sum::<usize>()
256 }
257}
258
259impl VertexCount for MultiPolygon {
260 fn vertex_count(&self) -> usize {
261 self.iter().map(|p| p.vertex_count()).sum()
262 }
263}
264
265impl VertexCount for Rect {
266 fn vertex_count(&self) -> usize {
267 4
268 }
269}
270
271impl VertexCount for Line {
272 fn vertex_count(&self) -> usize {
273 2
274 }
275}
276
277impl VertexCount for Geometry2D {
278 fn vertex_count(&self) -> usize {
279 match &self {
280 Geometry2D::LineString(line_string) => line_string.vertex_count(),
281 Geometry2D::MultiLineString(multi_line_string) => multi_line_string.vertex_count(),
282 Geometry2D::Polygon(polygon) => polygon.vertex_count(),
283 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.vertex_count(),
284 Geometry2D::Rect(rect) => rect.vertex_count(),
285 Geometry2D::Line(line) => line.vertex_count(),
286 Geometry2D::Collection(collection) => collection.vertex_count(),
287 }
288 }
289}