microcad_core/geo2d/
collection.rs1use derive_more::{Deref, DerefMut};
7use geo::{CoordsIter, HasDimensions, MultiPolygon};
8use std::rc::Rc;
9
10use crate::{
11 geo2d::{CalcBounds2D, bounds::Bounds2D},
12 traits::{DistributeGrid, TotalMemory, VertexCount},
13 *,
14};
15
16#[derive(Debug, Clone, Default, Deref, DerefMut)]
18pub struct Geometries2D(Vec<Rc<Geometry2D>>);
19
20impl Geometries2D {
21 pub fn new(geometries: Vec<Geometry2D>) -> Self {
23 Self(geometries.into_iter().map(Rc::new).collect())
24 }
25
26 pub fn append(&mut self, mut geometries: Geometries2D) {
28 self.0.append(&mut geometries.0)
29 }
30
31 pub fn boolean_op(&self, op: &BooleanOp) -> geo2d::MultiPolygon {
33 let multi_polygon_list: Vec<_> = self
34 .0
35 .iter()
36 .filter_map(|geo| {
38 let multi_polygon = geo.to_multi_polygon();
39 if multi_polygon.is_empty() {
40 None
41 } else {
42 Some(multi_polygon)
43 }
44 })
45 .collect();
46
47 if multi_polygon_list.is_empty() {
48 return geo2d::MultiPolygon::empty();
49 }
50
51 multi_polygon_list[1..]
52 .iter()
53 .fold(multi_polygon_list[0].clone(), |acc, geo| {
54 use geo::BooleanOps;
55 acc.boolean_op(geo, op.into())
56 })
57 }
58
59 pub fn to_multi_polygon(&self) -> MultiPolygon {
61 let mut polygons = Vec::new();
62 self.iter().for_each(|geo| {
63 polygons.append(&mut (**geo).clone().to_multi_polygon().0);
64 });
65
66 MultiPolygon::new(polygons)
67 }
68
69 pub fn hull(&self) -> geo2d::Polygon {
71 let mut coords: Vec<_> = self
72 .iter()
73 .flat_map(|geo| match geo.as_ref() {
74 Geometry2D::LineString(line_string) => {
75 line_string.coords_iter().collect::<Vec<_>>()
76 }
77 Geometry2D::MultiLineString(multi_line_string) => {
78 multi_line_string.coords_iter().collect::<Vec<_>>()
79 }
80 Geometry2D::Polygon(polygon) => polygon.exterior_coords_iter().collect::<Vec<_>>(),
81 Geometry2D::MultiPolygon(multi_polygon) => {
82 multi_polygon.exterior_coords_iter().collect::<Vec<_>>()
83 }
84 Geometry2D::Rect(rect) => rect.coords_iter().collect::<Vec<_>>(),
85 Geometry2D::Line(line) => vec![line.0.into(), line.1.into()],
86 Geometry2D::Collection(collection) => {
87 collection.hull().exterior_coords_iter().collect::<Vec<_>>()
88 }
89 })
90 .collect();
91
92 geo2d::Polygon::new(
93 geo::algorithm::convex_hull::qhull::quick_hull(&mut coords),
94 vec![],
95 )
96 }
97}
98
99impl geo::Buffer for Geometries2D {
100 type Scalar = Scalar;
101
102 fn buffer_with_style(
103 &self,
104 style: geo::buffer::BufferStyle<Self::Scalar>,
105 ) -> MultiPolygon<Self::Scalar> {
106 let mut polygons = Vec::new();
107 self.iter().for_each(|geo| {
108 polygons.append(&mut (**geo).clone().buffer_with_style(style.clone()).0);
109 });
110
111 MultiPolygon::new(polygons)
112 }
113}
114
115impl FromIterator<Rc<Geometry2D>> for Geometries2D {
116 fn from_iter<T: IntoIterator<Item = Rc<Geometry2D>>>(iter: T) -> Self {
117 Geometries2D(iter.into_iter().collect())
118 }
119}
120
121impl CalcBounds2D for Geometries2D {
122 fn calc_bounds_2d(&self) -> Bounds2D {
123 self.0.iter().fold(Bounds2D::default(), |bounds, geometry| {
124 bounds.extend(geometry.calc_bounds_2d())
125 })
126 }
127}
128
129impl Transformed2D for Geometries2D {
130 fn transformed_2d(&self, mat: &Mat3) -> Self {
131 Self(
132 self.iter()
133 .map(|geometry| Rc::new(geometry.transformed_2d(mat)))
134 .collect::<Vec<_>>(),
135 )
136 }
137}
138
139impl From<Geometries2D> for MultiPolygon {
140 fn from(geometries: Geometries2D) -> Self {
141 Self(
142 geometries
143 .iter()
144 .flat_map(|geo| {
145 let multi_polygon: MultiPolygon = geo.as_ref().clone().into();
146 multi_polygon.0
147 })
148 .collect(),
149 )
150 }
151}
152
153impl DistributeGrid for Geometries2D {
154 fn distribute_grid(&self, rect: Rect, rows: Integer, columns: Integer) -> Self {
155 Geometries2D(
156 GridCells::new(rect, rows, columns)
157 .zip(self.0.iter())
158 .map(|(cell, geo)| {
159 let center = geo.calc_bounds_2d().center();
160 let cell_center: Vec2 = cell.center().x_y().into();
161 let d = center - cell_center;
162 Rc::new(geo.transformed_2d(&Mat3::from_translation(d)))
163 })
164 .collect(),
165 )
166 }
167}
168
169impl TotalMemory for Geometries2D {
170 fn heap_memory(&self) -> usize {
171 self.iter().map(|geo| geo.heap_memory()).sum()
172 }
173}
174
175impl VertexCount for Geometries2D {
176 fn vertex_count(&self) -> usize {
177 self.iter().map(|geo| geo.vertex_count()).sum()
178 }
179}