microcad_core/geo2d/
geometry.rs1use crate::traits::Align;
5
6use super::*;
7
8use geo::ConvexHull;
9use strum::IntoStaticStr;
10
11#[derive(IntoStaticStr, Clone, Debug)]
13pub enum Geometry2D {
14 LineString(LineString),
16 MultiLineString(MultiLineString),
18 Polygon(Polygon),
20 MultiPolygon(MultiPolygon),
22 Rect(Rect),
24 Circle(Circle),
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(
40 &self,
41 resolution: &RenderResolution,
42 other: &Self,
43 op: &BooleanOp,
44 ) -> geo2d::MultiPolygon {
45 use geo::BooleanOps;
46 self.render_to_multi_polygon(resolution)
47 .boolean_op(&other.render_to_multi_polygon(resolution), op.into())
48 }
49
50 pub fn hull(&self, resolution: &RenderResolution) -> Self {
52 match self {
53 Geometry2D::LineString(line_string) => Geometry2D::Polygon(line_string.convex_hull()),
54 Geometry2D::MultiLineString(multi_line_string) => {
55 Geometry2D::Polygon(multi_line_string.convex_hull())
56 }
57 Geometry2D::Polygon(polygon) => Geometry2D::Polygon(polygon.convex_hull()),
58 Geometry2D::MultiPolygon(multi_polygon) => {
59 Geometry2D::Polygon(multi_polygon.convex_hull())
60 }
61 Geometry2D::Rect(rect) => Geometry2D::Rect(*rect),
62 Geometry2D::Circle(circle) => Geometry2D::Circle(circle.clone()),
63 Geometry2D::Line(line) => Geometry2D::Polygon(
64 LineString::new(vec![line.0.into(), line.1.into()]).convex_hull(),
65 ),
66 Geometry2D::Collection(collection) => Geometry2D::Polygon(collection.hull(resolution)),
67 }
68 }
69
70 pub fn is_areal(&self) -> bool {
72 !matches!(
73 self,
74 Geometry2D::LineString(_)
75 | Geometry2D::MultiLineString(_)
76 | Geometry2D::Line(_)
77 | Geometry2D::Collection(_)
78 )
79 }
80}
81
82impl FetchBounds2D for MultiPolygon {
83 fn fetch_bounds_2d(&self) -> Bounds2D {
84 use geo::BoundingRect;
85 self.bounding_rect().into()
86 }
87}
88
89impl FetchBounds2D for Geometry2D {
90 fn fetch_bounds_2d(&self) -> Bounds2D {
91 use geo::BoundingRect;
92
93 match &self {
94 Geometry2D::LineString(line_string) => line_string.bounding_rect().into(),
95 Geometry2D::MultiLineString(multi_line_string) => {
96 multi_line_string.bounding_rect().into()
97 }
98 Geometry2D::Polygon(polygon) => polygon.bounding_rect().into(),
99 Geometry2D::MultiPolygon(multi_polygon) => multi_polygon.fetch_bounds_2d(),
100 Geometry2D::Rect(rect) => Some(*rect).into(),
101 Geometry2D::Circle(circle) => circle.fetch_bounds_2d(),
102 Geometry2D::Line(line) => line.fetch_bounds_2d(),
103 Geometry2D::Collection(collection) => collection.fetch_bounds_2d(),
104 }
105 }
106}
107
108impl Transformed2D for Geometry2D {
109 fn transformed_2d(&self, resolution: &RenderResolution, mat: &Mat3) -> Self {
110 if self.is_areal() {
111 Self::MultiPolygon(
112 self.render_to_multi_polygon(resolution)
113 .transformed_2d(resolution, mat),
114 )
115 } else {
116 match self {
117 Geometry2D::LineString(line_string) => {
118 Self::LineString(line_string.transformed_2d(resolution, mat))
119 }
120 Geometry2D::MultiLineString(multi_line_string) => {
121 Self::MultiLineString(multi_line_string.transformed_2d(resolution, mat))
122 }
123 Geometry2D::Line(line) => Self::Line(line.transformed_2d(resolution, mat)),
124 Geometry2D::Collection(geometries) => {
125 Self::Collection(geometries.transformed_2d(resolution, mat))
126 }
127 _ => unreachable!("Geometry type not supported"),
128 }
129 }
130 }
131}
132
133impl Align for Geometry2D {
134 fn align(&self, resolution: &RenderResolution) -> Self {
135 if let Some(bounds) = self.fetch_bounds_2d().rect() {
136 let d: Vec2 = bounds.center().x_y().into();
137 self.transformed_2d(resolution, &Mat3::from_translation(-d))
138 } else {
139 self.clone()
140 }
141 }
142}
143
144impl RenderToMultiPolygon for Geometry2D {
145 fn render_to_existing_multi_polygon(
146 &self,
147 resolution: &RenderResolution,
148 polygons: &mut MultiPolygon,
149 ) {
150 match self {
151 Geometry2D::Polygon(polygon) => polygons.0.push(polygon.clone()),
152 Geometry2D::MultiPolygon(multi_polygon) => {
153 polygons.0.append(&mut multi_polygon.0.clone())
154 }
155 Geometry2D::Rect(rect) => polygons
156 .0
157 .push(rect.render_to_polygon(resolution).expect("Polygon")),
158 Geometry2D::Circle(circle) => polygons
159 .0
160 .push(circle.render_to_polygon(resolution).expect("Polygon")),
161 Geometry2D::Collection(geometries) => {
162 geometries.render_to_existing_multi_polygon(resolution, polygons);
163 }
164 _ => {}
165 }
166 }
167}