1use crate::geo_types::boolean::BooleanOp;
2use crate::geo_types::buffer::Buffer;
3use crate::geo_types::shapes::arc_center;
4use geo::algorithm::rotate::Rotate;
5use geo_types::{coord, point, Geometry, GeometryCollection, LineString, Point, Rect};
6use std::collections::HashMap;
7use std::error::Error;
8use std::rc::Rc;
9
10pub enum CarlsonSmithTruchet {
11 TLBR(bool),
12 DIV(bool),
13 DOTS(bool),
14 PINWHEEL(bool),
15 PLUS(bool),
16 UNHAPPY(bool),
17 HUGS(bool),
18}
19
20impl CarlsonSmithTruchet {
21 pub fn full_set() -> HashMap<String, Rc<Geometry<f64>>> {
22 let prefix = |x| if x { "^" } else { "" };
23 let mut truchets = HashMap::new();
24 for invert in vec![true, false] {
25 for i in (0..360).step_by(90) {
26 truchets.insert(
27 format!("{}TLBR{}", prefix(invert), i),
28 Rc::new(
29 CarlsonSmithTruchet::TLBR(invert)
30 .draw()
31 .unwrap()
32 .rotate_around_point(f64::from(i), point! {x: 0.0, y: 0.0}),
33 ),
34 );
35 truchets.insert(
36 format!("{}DIV{}", prefix(invert), i),
37 Rc::new(
38 CarlsonSmithTruchet::DIV(invert)
39 .draw()
40 .unwrap()
41 .rotate_around_point(f64::from(i), point! {x: 0.0, y: 0.0}),
42 ),
43 );
44 truchets.insert(
45 format!("{}UNHAPPY{}", prefix(invert), i),
46 Rc::new(
47 CarlsonSmithTruchet::UNHAPPY(invert)
48 .draw()
49 .unwrap()
50 .rotate_around_point(f64::from(i), point! {x: 0.0, y: 0.0}),
51 ),
52 );
53 truchets.insert(
54 format!("{}HUGS{}", prefix(invert), i),
55 Rc::new(
56 CarlsonSmithTruchet::HUGS(invert)
57 .draw()
58 .unwrap()
59 .rotate_around_point(f64::from(i), point! {x: 0.0, y: 0.0}),
60 ),
61 );
62 truchets.insert(
64 format!("{}DOTS{}", prefix(invert), i),
65 Rc::new(CarlsonSmithTruchet::DOTS(invert).draw().unwrap()),
66 );
67 truchets.insert(
68 format!("{}PINWHEEL{}", prefix(invert), i),
69 Rc::new(CarlsonSmithTruchet::PINWHEEL(invert).draw().unwrap()),
70 );
71 truchets.insert(
72 format!("{}PLUS{}", prefix(invert), i),
73 Rc::new(CarlsonSmithTruchet::PLUS(invert).draw().unwrap()),
74 );
75 }
76 }
77 truchets
79 }
80
81 pub fn draw(&self) -> Result<Geometry<f64>, Box<dyn Error>> {
83 match self {
84 CarlsonSmithTruchet::TLBR(false) => {
85 let mut ac1 = Geometry::LineString(arc_center(0.5, 0.5, 0.5, 180.0, 270.0))
86 .buffer(1.0f64 / 6.0f64)?; let ac2 = Geometry::LineString(arc_center(-0.5, -0.5, 0.5, 90.0, 0.0))
88 .buffer(1.0f64 / 6.0f64)?; ac1.0.extend(ac2.0);
90 Ok(Geometry::MultiPolygon(ac1))
91 }
92 CarlsonSmithTruchet::DIV(false) => Ok(Geometry::GeometryCollection(
93 GeometryCollection::new_from(vec![
94 Geometry::MultiPolygon(
95 Geometry::Point(Point::new(0.0, 0.5))
96 .buffer(1.0f64 / 6.0f64)
97 .unwrap(),
98 ),
99 Geometry::MultiPolygon(
100 Geometry::Point(Point::new(0.0, -0.5))
101 .buffer(1.0f64 / 6.0f64)
102 .unwrap(),
103 ),
104 Geometry::MultiPolygon(
105 Geometry::LineString(LineString::new(vec![
106 coord! {x: -0.5, y: 0.0},
107 coord! {x: 0.5, y: 0.0},
108 ]))
109 .buffer(1.0f64 / 6.0f64)
110 .unwrap(),
111 ),
112 ]),
113 )),
114 CarlsonSmithTruchet::DOTS(false) => Ok(Geometry::GeometryCollection(
115 GeometryCollection::new_from(vec![
116 Geometry::MultiPolygon(
117 Geometry::Point(Point::new(0.0, 0.5))
118 .buffer(1.0f64 / 6.0f64)
119 .unwrap(),
120 ),
121 Geometry::MultiPolygon(
122 Geometry::Point(Point::new(0.0, -0.5))
123 .buffer(1.0f64 / 6.0f64)
124 .unwrap(),
125 ),
126 Geometry::MultiPolygon(
127 Geometry::Point(Point::new(0.5, 0.0))
128 .buffer(1.0f64 / 6.0f64)
129 .unwrap(),
130 ),
131 Geometry::MultiPolygon(
132 Geometry::Point(Point::new(-0.5, -0.0))
133 .buffer(1.0f64 / 6.0f64)
134 .unwrap(),
135 ),
136 ]),
137 )),
138 CarlsonSmithTruchet::PINWHEEL(false) => {
139 let center = Geometry::Rect(Rect::<f64>::new(
140 coord! {x:-0.5, y:-0.5},
141 coord! {x: 0.5, y: 0.5},
142 ));
143 let corners = CarlsonSmithTruchet::PINWHEEL(true).draw()?;
144 let points = CarlsonSmithTruchet::DOTS(false).draw()?;
145 let out = center.union(&points)?.difference(&corners)?;
146 Ok(out)
147 }
148 CarlsonSmithTruchet::PINWHEEL(true) => Ok(Geometry::GeometryCollection(
149 GeometryCollection::new_from(vec![
150 Geometry::MultiPolygon(
151 Geometry::Point(Point::new(0.5, 0.5))
152 .buffer(1.0f64 / 3.0f64)
153 .unwrap(),
154 ),
155 Geometry::MultiPolygon(
156 Geometry::Point(Point::new(0.5, -0.5))
157 .buffer(1.0f64 / 3.0f64)
158 .unwrap(),
159 ),
160 Geometry::MultiPolygon(
161 Geometry::Point(Point::new(-0.5, 0.5))
162 .buffer(1.0f64 / 3.0f64)
163 .unwrap(),
164 ),
165 Geometry::MultiPolygon(
166 Geometry::Point(Point::new(-0.5, -0.5))
167 .buffer(1.0f64 / 3.0f64)
168 .unwrap(),
169 ),
170 ]),
171 )),
172 CarlsonSmithTruchet::PLUS(false) => Ok(Geometry::MultiPolygon(
173 Geometry::LineString(LineString::new(vec![
174 coord! {x: -0.5, y: 0.0},
175 coord! {x: 0.5, y: 0.0},
176 ]))
177 .buffer(1.0f64 / 6.0f64)?,
178 )
179 .union(&Geometry::MultiPolygon(
180 Geometry::LineString(LineString::new(vec![
181 coord! {x:0.0, y:-0.5},
182 coord! {x:0.0, y: 0.5},
183 ]))
184 .buffer(1.0f64 / 6.0f64)?,
185 ))?),
186 CarlsonSmithTruchet::UNHAPPY(false) => Ok(Geometry::GeometryCollection(
187 GeometryCollection::new_from(vec![
188 Geometry::MultiPolygon(
189 Geometry::Point(Point::new(-0.5, 0.0)).buffer(1.0f64 / 6.0f64)?,
190 ),
191 Geometry::MultiPolygon(
192 Geometry::Point(Point::new(0.0, -0.5)).buffer(1.0f64 / 6.0f64)?,
193 ),
194 Geometry::MultiPolygon(
195 Geometry::LineString(arc_center(0.5, 0.5, 0.5, 180.0, 270.0))
196 .buffer(1.0f64 / 6.0f64)?,
197 ),
198 ]),
199 )),
200 CarlsonSmithTruchet::HUGS(false) => {
201 let center = Geometry::Rect(Rect::<f64>::new(
202 coord! {x:-0.5, y: 0.5},
203 coord! {x: 0.5, y: -1.0/6.0},
204 ));
205 let corners = CarlsonSmithTruchet::PINWHEEL(true).draw()?;
206 let points = CarlsonSmithTruchet::DOTS(false).draw()?;
207 let out = center.union(&points)?.difference(&corners)?;
208 Ok(out)
209 }
210 CarlsonSmithTruchet::HUGS(true) => {
211 let negative = CarlsonSmithTruchet::HUGS(false).draw()?;
213 let positive = Geometry::GeometryCollection(GeometryCollection::new_from(vec![
214 Geometry::Rect(Rect::<f64>::new(
215 coord! {x:-0.5, y:-0.5},
216 coord! {x: 0.5, y: 0.5},
217 )),
218 Geometry::MultiPolygon(
219 Geometry::Point(Point::new(0.5, 0.5))
220 .buffer(1.0f64 / 3.0f64)
221 .unwrap(),
222 ),
223 Geometry::MultiPolygon(
224 Geometry::Point(Point::new(0.5, -0.5))
225 .buffer(1.0f64 / 3.0f64)
226 .unwrap(),
227 ),
228 Geometry::MultiPolygon(
229 Geometry::Point(Point::new(-0.5, 0.5))
230 .buffer(1.0f64 / 3.0f64)
231 .unwrap(),
232 ),
233 Geometry::MultiPolygon(
234 Geometry::Point(Point::new(-0.5, -0.5))
235 .buffer(1.0f64 / 3.0f64)
236 .unwrap(),
237 ),
238 ]))
239 .unary_union()?;
240 Ok(positive.difference(&negative)?)
241 }
242 CarlsonSmithTruchet::TLBR(true) => {
243 let dots = CarlsonSmithTruchet::PINWHEEL(true).draw()?;
245 let line = Geometry::MultiPolygon(
246 Geometry::LineString(LineString(vec![
247 coord! {x: -0.5, y: 0.5},
248 coord! {x:0.5, y:-0.5},
249 ]))
250 .buffer(1.0f64 / 5.0f64)?,
251 );
252 Ok(dots
253 .union(&line)?
254 .difference(&CarlsonSmithTruchet::TLBR(false).draw()?)?)
255 }
256 CarlsonSmithTruchet::DIV(true) => {
257 let center = Geometry::Rect(Rect::<f64>::new(
258 coord! {x:-0.5, y:-0.5},
259 coord! {x: 0.5, y: 0.5},
260 ));
261 let corners = CarlsonSmithTruchet::PINWHEEL(true).draw()?;
262 Ok(center
263 .union(&corners)?
264 .difference(&CarlsonSmithTruchet::DIV(false).draw()?)?)
265 }
266 CarlsonSmithTruchet::DOTS(true) => {
267 let center = Geometry::Rect(Rect::<f64>::new(
268 coord! {x:-0.5, y:-0.5},
269 coord! {x: 0.5, y: 0.5},
270 ));
271 let corners = CarlsonSmithTruchet::PINWHEEL(true).draw()?;
272 Ok(center
273 .union(&corners)?
274 .difference(&CarlsonSmithTruchet::DOTS(false).draw()?)?)
275 }
276 CarlsonSmithTruchet::PLUS(true) => {
277 let center = Geometry::Rect(Rect::<f64>::new(
278 coord! {x:-0.5, y:-0.5},
279 coord! {x: 0.5, y: 0.5},
280 ));
281 let corners = CarlsonSmithTruchet::PINWHEEL(true).draw()?;
282 Ok(center
283 .union(&corners)?
284 .difference(&CarlsonSmithTruchet::PLUS(false).draw()?)?)
285 }
286 CarlsonSmithTruchet::UNHAPPY(true) => {
287 let center = Geometry::Rect(Rect::<f64>::new(
288 coord! {x:-0.5, y:-0.5},
289 coord! {x: 0.5, y: 0.5},
290 ));
291 let corners = CarlsonSmithTruchet::PINWHEEL(true).draw()?;
292 let ac1 = Geometry::LineString(arc_center(0.5, 0.5, 0.5, 180.0, 270.0))
293 .buffer(1.0f64 / 6.0f64)?; let p1 = Geometry::MultiPolygon(
295 Geometry::Point(Point::new(-0.5, 0.0)).buffer(1.0f64 / 6.0f64)?,
296 );
297 let p2 = Geometry::MultiPolygon(
298 Geometry::Point(Point::new(0.0, -0.5)).buffer(1.0f64 / 6.0f64)?,
299 );
300
301 Ok(center
302 .union(&corners)?
303 .difference(&Geometry::MultiPolygon(ac1))?
304 .difference(&p1)?
305 .difference(&p2)?)
306 }
307 }
308 }
309}
310
311#[cfg(test)]
312pub mod tests {
313 use crate::elements::CarlsonSmithTruchet;
314
315 #[test]
316 fn test_cst_all() {
317 let _full_set = CarlsonSmithTruchet::full_set();
319 let _full_set = CarlsonSmithTruchet::full_set();
320 }
321}