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