microcad_core/geo2d/
geometry.rs1use std::rc::Rc;
5
6use crate::traits::Align;
7
8use super::*;
9
10use geo::{ConvexHull, MultiPolygon};
11use strum::IntoStaticStr;
12
13#[derive(IntoStaticStr, Clone, Debug)]
15pub enum Geometry2D {
16 LineString(LineString),
18 MultiLineString(MultiLineString),
20 Polygon(Polygon),
22 MultiPolygon(MultiPolygon),
24 Rect(Rect),
26 Line(Line),
28 Collection(Geometries2D),
30}
31
32impl Geometry2D {
33 pub fn name(&self) -> &'static str {
35 self.into()
36 }
37
38 pub fn boolean_op(self, other: Self, op: &BooleanOp) -> geo2d::MultiPolygon {
40 use geo::BooleanOps;
41 self.to_multi_polygon()
42 .boolean_op(&other.to_multi_polygon(), op.into())
43 }
44
45 pub fn to_multi_polygon(&self) -> MultiPolygon {
47 match self {
48 Geometry2D::Line(_) | Geometry2D::LineString(_) | Geometry2D::MultiLineString(_) => {
49 MultiPolygon::empty()
50 }
51 Geometry2D::Polygon(polygon) => MultiPolygon(vec![polygon.clone()]),
52 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.clone(),
53 Geometry2D::Rect(rect) => MultiPolygon(vec![rect.to_polygon()]),
54 Geometry2D::Collection(collection) => collection.to_multi_polygon(),
55 }
56 }
57
58 pub fn hull(&self) -> Self {
60 match self {
61 Geometry2D::LineString(line_string) => Geometry2D::Polygon(line_string.convex_hull()),
62 Geometry2D::MultiLineString(multi_line_string) => {
63 Geometry2D::Polygon(multi_line_string.convex_hull())
64 }
65 Geometry2D::Polygon(polygon) => Geometry2D::Polygon(polygon.convex_hull()),
66 Geometry2D::MultiPolygon(multi_polygon) => {
67 Geometry2D::Polygon(multi_polygon.convex_hull())
68 }
69 Geometry2D::Rect(rect) => Geometry2D::Rect(*rect),
70 Geometry2D::Line(line) => Geometry2D::Polygon(
71 LineString::new(vec![line.0.into(), line.1.into()]).convex_hull(),
72 ),
73 Geometry2D::Collection(collection) => Geometry2D::Polygon(collection.hull()),
74 }
75 }
76
77 pub fn is_areal(&self) -> bool {
79 !matches!(
80 self,
81 Geometry2D::LineString(_)
82 | Geometry2D::MultiLineString(_)
83 | Geometry2D::Line(_)
84 | Geometry2D::Collection(_)
85 )
86 }
87
88 pub fn with_bounds(self) -> WithBounds2D<Geometry2D> {
90 let bounds = self.calc_bounds_2d();
91 WithBounds2D {
92 bounds,
93 inner: self,
94 }
95 }
96}
97
98impl CalcBounds2D for MultiPolygon {
99 fn calc_bounds_2d(&self) -> Bounds2D {
100 use geo::BoundingRect;
101 self.bounding_rect().into()
102 }
103}
104
105impl CalcBounds2D for Geometry2D {
106 fn calc_bounds_2d(&self) -> Bounds2D {
107 use geo::BoundingRect;
108
109 match &self {
110 Geometry2D::LineString(line_string) => line_string.bounding_rect().into(),
111 Geometry2D::MultiLineString(multi_line_string) => {
112 multi_line_string.bounding_rect().into()
113 }
114 Geometry2D::Polygon(polygon) => polygon.bounding_rect().into(),
115 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.calc_bounds_2d(),
116 Geometry2D::Rect(rect) => Some(*rect).into(),
117 Geometry2D::Line(line) => line.calc_bounds_2d(),
118 Geometry2D::Collection(collection) => collection.calc_bounds_2d(),
119 }
120 }
121}
122
123impl Transformed2D for Geometry2D {
124 fn transformed_2d(&self, mat: &Mat3) -> Self {
125 if self.is_areal() {
126 let multi_polygon: MultiPolygon = self.clone().into();
127 Self::MultiPolygon(multi_polygon.transformed_2d(mat))
128 } else {
129 match self {
130 Geometry2D::LineString(line_string) => {
131 Self::LineString(line_string.transformed_2d(mat))
132 }
133 Geometry2D::MultiLineString(multi_line_string) => {
134 Self::MultiLineString(multi_line_string.transformed_2d(mat))
135 }
136 Geometry2D::Line(line) => Self::Line(line.transformed_2d(mat)),
137 Geometry2D::Collection(geometries) => {
138 Self::Collection(geometries.transformed_2d(mat))
139 }
140 _ => unreachable!("Geometry type not supported"),
141 }
142 }
143 }
144}
145
146impl Align for Geometry2D {
147 fn align(&self) -> Self {
148 if let Some(bounds) = self.calc_bounds_2d().rect() {
149 let d: Vec2 = bounds.center().x_y().into();
150 self.transformed_2d(&Mat3::from_translation(-d))
151 } else {
152 self.clone()
153 }
154 }
155}
156
157impl From<Geometry2D> for MultiPolygon {
158 fn from(geo: Geometry2D) -> Self {
159 match geo {
160 Geometry2D::Polygon(polygon) => polygon.into(),
161 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon,
162 Geometry2D::Rect(rect) => MultiPolygon(vec![rect.to_polygon()]),
163 Geometry2D::Collection(collection) => collection.into(),
164 _ => MultiPolygon::empty(),
165 }
166 }
167}
168
169pub trait RenderToGeometry2D {
171 fn render_to_geometry(&self, resolution: &RenderResolution) -> Rc<Geometry2D>;
175}
176
177impl RenderToGeometry2D for Rc<Geometry2D> {
178 fn render_to_geometry(&self, _: &RenderResolution) -> Rc<Geometry2D> {
179 self.clone()
180 }
181}