1#[macro_export]
29macro_rules! wkt {
30 ($($wkt:tt)+) => {
32 {
33 $crate::wkt_internal!($($wkt)+)
34 }
35 };
36}
37
38#[macro_export]
39#[doc(hidden)]
40macro_rules! wkt_internal {
41 (POINT EMPTY) => {
42 compile_error!("EMPTY points are not supported in geo-types")
43 };
44 (POINT($x: literal $y: literal)) => {
45 $crate::point!(x: $x, y: $y)
46 };
47 (POINT $($tail: tt)*) => {
48 compile_error!("Invalid POINT wkt");
49 };
50 (LINE($a_x: literal $a_y: literal,$b_x: literal $b_y: literal)) => {
51 $crate::Line::new(
52 $crate::coord!(x: $a_x, y: $a_y),
53 $crate::coord!(x: $b_x, y: $b_y)
54 )
55 };
56 (LINESTRING EMPTY) => {
57 $crate::LineString::empty()
58 };
59 (LINESTRING ($($x: literal $y: literal),+)) => {
60 $crate::line_string![
61 $($crate::coord!(x: $x, y: $y)),*
62 ]
63 };
64 (LINESTRING ()) => {
65 compile_error!("use `EMPTY` instead of () for an empty collection")
66 };
67 (LINESTRING $($tail: tt)*) => {
68 compile_error!("Invalid LINESTRING wkt");
69 };
70 (POLYGON EMPTY) => {
71 $crate::Polygon::empty()
72 };
73 (POLYGON ( $exterior_tt: tt )) => {
74 $crate::Polygon::new($crate::wkt!(LINESTRING $exterior_tt), $crate::_alloc::vec![])
75 };
76 (POLYGON( $exterior_tt: tt, $($interiors_tt: tt),+ )) => {
77 $crate::Polygon::new(
78 $crate::wkt!(LINESTRING $exterior_tt),
79 $crate::_alloc::vec![
80 $($crate::wkt!(LINESTRING $interiors_tt)),*
81 ]
82 )
83 };
84 (POLYGON ()) => {
85 compile_error!("use `EMPTY` instead of () for an empty collection")
86 };
87 (POLYGON $($tail: tt)*) => {
88 compile_error!("Invalid POLYGON wkt");
89 };
90 (MULTIPOINT EMPTY) => {
91 $crate::MultiPoint::empty()
92 };
93 (MULTIPOINT ()) => {
94 compile_error!("use `EMPTY` instead of () for an empty collection")
95 };
96 (MULTIPOINT ($($x: literal $y: literal),* )) => {
97 $crate::MultiPoint(
98 $crate::_alloc::vec![$($crate::point!(x: $x, y: $y)),*]
99 )
100 };
101 (MULTIPOINT $($tail: tt)*) => {
102 compile_error!("Invalid MULTIPOINT wkt");
103 };
104 (MULTILINESTRING EMPTY) => {
105 $crate::MultiLineString::empty()
106 };
107 (MULTILINESTRING ()) => {
108 compile_error!("use `EMPTY` instead of () for an empty collection")
109 };
110 (MULTILINESTRING ( $($line_string_tt: tt),* )) => {
111 $crate::MultiLineString($crate::_alloc::vec![
112 $($crate::wkt!(LINESTRING $line_string_tt)),*
113 ])
114 };
115 (MULTILINESTRING $($tail: tt)*) => {
116 compile_error!("Invalid MULTILINESTRING wkt");
117 };
118 (MULTIPOLYGON EMPTY) => {
119 $crate::MultiPolygon::empty()
120 };
121 (MULTIPOLYGON ()) => {
122 compile_error!("use `EMPTY` instead of () for an empty collection")
123 };
124 (MULTIPOLYGON ( $($polygon_tt: tt),* )) => {
125 $crate::MultiPolygon($crate::_alloc::vec![
126 $($crate::wkt!(POLYGON $polygon_tt)),*
127 ])
128 };
129 (MULTIPOLYGON $($tail: tt)*) => {
130 compile_error!("Invalid MULTIPOLYGON wkt");
131 };
132 (GEOMETRYCOLLECTION EMPTY) => {
133 $crate::GeometryCollection::empty()
134 };
135 (GEOMETRYCOLLECTION ()) => {
136 compile_error!("use `EMPTY` instead of () for an empty collection")
137 };
138 (GEOMETRYCOLLECTION ( $($el_type:tt $el_tt: tt),* )) => {
139 $crate::GeometryCollection($crate::_alloc::vec![
140 $($crate::Geometry::from($crate::wkt!($el_type $el_tt))),*
141 ])
142 };
143 (GEOMETRYCOLLECTION $($tail: tt)*) => {
144 compile_error!("Invalid GEOMETRYCOLLECTION wkt");
145 };
146 (RECT($a_x: literal $a_y: literal,$b_x: literal $b_y: literal)) => {
147 $crate::Rect::new(
148 $crate::coord!(x: $a_x, y: $a_y),
149 $crate::coord!(x: $b_x, y: $b_y)
150 )
151 };
152 (TRIANGLE($a_x: literal $a_y: literal,$b_x: literal $b_y: literal,$c_x: literal $c_y: literal)) => {
153 $crate::Triangle::new(
154 $crate::coord!(x: $a_x, y: $a_y),
155 $crate::coord!(x: $b_x, y: $b_y),
156 $crate::coord!(x: $c_x, y: $c_y)
157 )
158 };
159 ($name: ident ($($tail: tt)*)) => {
160 compile_error!("Unknown type. Must be one of POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION, LINE, RECT, or TRIANGLE")
161 };
162}
163
164#[cfg(test)]
165mod test {
166 use crate::geometry::*;
167 use alloc::vec;
168
169 #[test]
170 fn point() {
171 let point = wkt! { POINT(1.0 2.0) };
172 assert_eq!(point.x(), 1.0);
173 assert_eq!(point.y(), 2.0);
174
175 let point = wkt! { POINT(1.0 2.0) };
176 assert_eq!(point.x(), 1.0);
177 assert_eq!(point.y(), 2.0);
178
179 }
182
183 #[test]
184 fn line() {
185 let line = wkt! { LINE(1.0 2.0,3.0 4.0) };
186 assert_eq!(line.start, coord!(x: 1.0, y: 2.0));
187 assert_eq!(line.end, coord!(x: 3.0, y: 4.0));
188 }
189
190 #[test]
191 fn empty_line_string() {
192 let line_string: LineString<f64> = wkt! { LINESTRING EMPTY };
193 assert_eq!(line_string.0.len(), 0);
194
195 }
198
199 #[test]
200 fn line_string() {
201 let line_string = wkt! { LINESTRING(1.0 2.0,3.0 4.0) };
202 assert_eq!(line_string.0.len(), 2);
203 assert_eq!(line_string[0], coord! { x: 1.0, y: 2.0 });
204 }
205
206 #[test]
207 fn empty_polygon() {
208 let polygon: Polygon = wkt! { POLYGON EMPTY };
209 assert_eq!(polygon.exterior().0.len(), 0);
210 assert_eq!(polygon.interiors().len(), 0);
211
212 }
215
216 #[test]
217 fn polygon() {
218 let polygon = wkt! { POLYGON((1.0 2.0)) };
219 assert_eq!(polygon.exterior().0.len(), 1);
220 assert_eq!(polygon.exterior().0[0], coord! { x: 1.0, y: 2.0 });
221
222 let polygon = wkt! { POLYGON((1.0 2.0,3.0 4.0)) };
223 assert_eq!(polygon.exterior().0.len(), 3);
225 assert_eq!(polygon.exterior().0[0], coord! { x: 1.0, y: 2.0 });
226 assert_eq!(polygon.exterior().0[1], coord! { x: 3.0, y: 4.0 });
227 assert_eq!(polygon.exterior().0[2], coord! { x: 1.0, y: 2.0 });
228
229 let polygon = wkt! { POLYGON((1.0 2.0), (1.1 2.1)) };
230 assert_eq!(polygon.exterior().0.len(), 1);
231 assert_eq!(polygon.interiors().len(), 1);
232
233 assert_eq!(polygon.exterior().0[0], coord! { x: 1.0, y: 2.0 });
234 assert_eq!(polygon.interiors()[0].0[0], coord! { x: 1.1, y: 2.1 });
235
236 let polygon = wkt! { POLYGON((1.0 2.0,3.0 4.0), (1.1 2.1,3.1 4.1), (1.2 2.2,3.2 4.2)) };
237 assert_eq!(polygon.exterior().0.len(), 3);
238 assert_eq!(polygon.interiors().len(), 2);
239 assert_eq!(polygon.interiors()[1][1], coord! { x: 3.2, y: 4.2 });
240 }
241
242 #[test]
243 fn empty_multi_point() {
244 let multipoint: MultiPoint = wkt! { MULTIPOINT EMPTY };
245 assert!(multipoint.0.is_empty());
246 }
249
250 #[test]
251 fn multi_point() {
252 let multi_point = wkt! { MULTIPOINT(1.0 2.0) };
253 assert_eq!(multi_point.0, vec![point! { x: 1.0, y: 2.0}]);
254
255 let multi_point = wkt! { MULTIPOINT(1.0 2.0,3.0 4.0) };
256 assert_eq!(
257 multi_point.0,
258 vec![point! { x: 1.0, y: 2.0}, point! { x: 3.0, y: 4.0}]
259 );
260 }
261
262 #[test]
263 fn empty_multi_line_string() {
264 let multi_line_string: MultiLineString = wkt! { MULTILINESTRING EMPTY };
265 assert_eq!(multi_line_string.0, vec![]);
266 }
269 #[test]
270 fn multi_line_string() {
271 let multi_line_string = wkt! { MULTILINESTRING ((1.0 2.0,3.0 4.0)) };
272 assert_eq!(multi_line_string.0.len(), 1);
273 assert_eq!(multi_line_string.0[0].0[1], coord! { x: 3.0, y: 4.0 });
274 let multi_line_string = wkt! { MULTILINESTRING ((1.0 2.0,3.0 4.0),(5.0 6.0,7.0 8.0)) };
275 assert_eq!(multi_line_string.0.len(), 2);
276 assert_eq!(multi_line_string.0[1].0[1], coord! { x: 7.0, y: 8.0 });
277
278 let multi_line_string = wkt! { MULTILINESTRING ((1.0 2.0,3.0 4.0),EMPTY) };
279 assert_eq!(multi_line_string.0.len(), 2);
280 assert_eq!(multi_line_string.0[1].0.len(), 0);
281 }
282
283 #[test]
284 fn empty_multi_polygon() {
285 let multi_polygon: MultiPolygon = wkt! { MULTIPOLYGON EMPTY };
286 assert!(multi_polygon.0.is_empty());
287
288 }
291
292 #[test]
293 fn multi_line_polygon() {
294 let multi_polygon = wkt! { MULTIPOLYGON (((1.0 2.0))) };
295 assert_eq!(multi_polygon.0.len(), 1);
296 assert_eq!(multi_polygon.0[0].exterior().0[0], coord! { x: 1.0, y: 2.0});
297
298 let multi_polygon = wkt! { MULTIPOLYGON (((1.0 2.0,3.0 4.0), (1.1 2.1,3.1 4.1), (1.2 2.2,3.2 4.2)),((1.0 2.0))) };
299 assert_eq!(multi_polygon.0.len(), 2);
300 assert_eq!(
301 multi_polygon.0[0].interiors()[1].0[0],
302 coord! { x: 1.2, y: 2.2}
303 );
304
305 let multi_polygon = wkt! { MULTIPOLYGON (((1.0 2.0,3.0 4.0), (1.1 2.1,3.1 4.1), (1.2 2.2,3.2 4.2)), EMPTY) };
306 assert_eq!(multi_polygon.0.len(), 2);
307 assert_eq!(
308 multi_polygon.0[0].interiors()[1].0[0],
309 coord! { x: 1.2, y: 2.2}
310 );
311 assert!(multi_polygon.0[1].exterior().0.is_empty());
312 }
313
314 #[test]
315 fn empty_geometry_collection() {
316 let geometry_collection: GeometryCollection = wkt! { GEOMETRYCOLLECTION EMPTY };
317 assert!(geometry_collection.is_empty());
318
319 }
322
323 #[test]
324 fn geometry_collection() {
325 let geometry_collection = wkt! {
326 GEOMETRYCOLLECTION (
327 POINT (40.0 10.0),
328 LINESTRING (10.0 10.0, 20.0 20.0, 10.0 40.0),
329 POLYGON ((40.0 40.0, 20.0 45.0, 45.0 30.0, 40.0 40.0))
330 )
331 };
332 assert_eq!(geometry_collection.len(), 3);
333
334 let line_string = match &geometry_collection[1] {
335 Geometry::LineString(line_string) => line_string,
336 _ => panic!(
337 "unexpected geometry: {geometry:?}",
338 geometry = geometry_collection[1]
339 ),
340 };
341 assert_eq!(line_string.0[1], coord! {x: 20.0, y: 20.0 });
342 }
343
344 #[test]
345 fn rect() {
346 let rect = wkt! { RECT(1.0 2.0,3.0 4.0) };
347 assert_eq!(rect.min(), coord!(x: 1.0, y: 2.0));
348 assert_eq!(rect.max(), coord!(x: 3.0, y: 4.0));
349 }
350
351 #[test]
352 fn triangle() {
353 let triangle = wkt! { TRIANGLE(0.0 1.0,4.0 2.0,3.0 5.0) };
354 assert_eq!(triangle.0, coord!(x: 0.0, y: 1.0));
355 assert_eq!(triangle.1, coord!(x: 4.0, y: 2.0));
356 assert_eq!(triangle.2, coord!(x: 3.0, y: 5.0));
357 }
358
359 #[test]
360 fn other_numeric_types() {
361 let point: Point<i32> = wkt!(POINT(1 2));
362 assert_eq!(point.x(), 1i32);
363 assert_eq!(point.y(), 2i32);
364
365 let point: Point<u64> = wkt!(POINT(1 2));
366 assert_eq!(point.x(), 1u64);
367 assert_eq!(point.y(), 2u64);
368
369 let point: Point<f32> = wkt!(POINT(1.0 2.0));
370 assert_eq!(point.x(), 1.0f32);
371 assert_eq!(point.y(), 2.0f32);
372 }
373}