Skip to main content

aoer_plotty_rs/elements/
mod.rs

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                // All teh dots are identical
63                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        // println!("Len of truchet set {}", truchets.len());
78        truchets
79    }
80
81    /// Returns the Geometry for the given truchet, centered on 0.0, with a scale of 1.0
82    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)?; // Buffer is 1/2 of 1/3
87                let ac2 = Geometry::LineString(arc_center(-0.5, -0.5, 0.5, 90.0, 0.0))
88                    .buffer(1.0f64 / 6.0f64)?; // Buffer is 1/2 of 1/3
89                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                // println!("HUGS TRUE");
212                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::DOTS(false).draw()?;
244                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)?; // Buffer is 1/2 of 1/3
294                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        // Basically just testing that it runs.
318        let _full_set = CarlsonSmithTruchet::full_set();
319        let _full_set = CarlsonSmithTruchet::full_set();
320    }
321}