sedona_testing/
fixtures.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17use std::{fs::File, path::PathBuf, str::FromStr};
18
19use geo_types::{LineString, MultiPolygon, Point, Polygon};
20use wkt::{TryFromWkt, WktFloat};
21
22/// A well-known binary blob of MULTIPOINT (EMPTY)
23///
24/// The wkt crate's parser rejects this; however, it's a corner case that may show
25/// up in WKB generated externally.
26pub const MULTIPOINT_WITH_EMPTY_CHILD_WKB: [u8; 30] = [
27    0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
28    0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f,
29];
30
31/// A well-known binary blob of MULTIPOINT ((1 2 3)) where outer dimension is specified for xy
32/// while inner point's dimension is actually xyz
33pub const MULTIPOINT_WITH_INFERRED_Z_DIMENSION_WKB: [u8; 38] = [
34    0x01, // byte-order
35    0x04, 0x00, 0x00, 0x00, // multipoint with xy-dimension specified
36    0x01, 0x00, 0x00, 0x00, // 1 point
37    // nested point geom
38    0x01, // byte-order
39    0xe9, 0x03, 0x00, 0x00, // point with xyz-dimension specified
40    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x-coordinate of point
41    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y-coordinate of point
42    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // z-coordinate of point
43];
44
45/// EWKB for POINT (1 2) with SRID 4326
46/// Little endian, geometry type 1 (POINT) with SRID flag (0x20000000)
47pub const POINT_WITH_SRID_4326_EWKB: [u8; 25] = [
48    0x01, // byte-order
49    0x01, 0x00, 0x00, 0x20, // geometry type 1 (POINT) with SRID flag (0x20000000)
50    0xe6, 0x10, 0x00, 0x00, // SRID 4326
51    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x-coordinate 1.0
52    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y-coordinate 2.0
53];
54
55/// EWKB for POINT Z (1 2 3) with SRID 3857
56/// Little endian, geometry type 1001 (POINT Z) with SRID flag
57pub const POINT_Z_WITH_SRID_3857_EWKB: [u8; 33] = [
58    0x01, // byte-order
59    0x01, 0x00, 0x00, 0xa0, // geometry type
60    // 0xe9, 0x03, 0x00, 0x20, // geometry type 1001 (POINT Z) with SRID flag
61    0x11, 0x0f, 0x00, 0x00, // SRID 3857
62    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x-coordinate 1.0
63    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y-coordinate 2.0
64    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // z-coordinate 3.0
65];
66
67pub const POINT_M_WITH_SRID_4326_EWKB: [u8; 33] = [
68    0x01, // byte-order
69    0x01, 0x00, 0x00, 0x60, // geometry type
70    0xe6, 0x10, 0x00, 0x00, // SRID
71    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x-coordinate 1.0
72    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y-coordinate 2.0
73    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // m-coordinate 3.0
74];
75
76/// EWKB for POINT ZM (1 2 3 4) with SRID 4326
77pub const POINT_ZM_WITH_SRID_4326_EWKB: [u8; 41] = [
78    0x01, // byte-order
79    0x01, 0x00, 0x00, 0xe0, // geometry type
80    // 0xb9, 0x0b, 0x00, 0x20, // geometry type 3001 (POINT ZM) with SRID flag
81    0xe6, 0x10, 0x00, 0x00, // SRID 4326
82    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x = 1.0
83    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y = 2.0
84    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // z = 3.0
85    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, // m = 4.0
86];
87
88/// EWKB for LINESTRING (1 2, 3 4) with SRID 4326
89/// Little endian, geometry type 2 (LINESTRING) with SRID flag
90pub const LINESTRING_WITH_SRID_4326_EWKB: [u8; 45] = [
91    0x01, // byte-order
92    0x02, 0x00, 0x00, 0x20, // geometry type
93    0xe6, 0x10, 0x00, 0x00, // SRID 4326
94    0x02, 0x00, 0x00, 0x00, // number of points (2)
95    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x1 = 1.0
96    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y1 = 2.0
97    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // x2 = 3.0
98    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, // y2 = 4.0
99];
100
101/// EWKB for POLYGON ((0 0, 0 1, 1 0, 0 0)) with SRID 4326
102/// Little endian, geometry type 3 (POLYGON) with SRID flag
103pub const POLYGON_WITH_SRID_4326_EWKB: [u8; 81] = [
104    0x01, // byte-order
105    0x03, 0x00, 0x00, 0x20, // geometry type 3 (POLYGON) with SRID flag
106    0xe6, 0x10, 0x00, 0x00, // SRID 4326
107    0x01, 0x00, 0x00, 0x00, // number of rings (1)
108    0x04, 0x00, 0x00, 0x00, // number of points in exterior ring (4)
109    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // x1 = 0.0
110    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // y1 = 0.0
111    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // x2 = 0.0
112    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // y2 = 1.0
113    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x3 = 1.0
114    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // y3 = 0.0
115    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // x4 = 0.0
116    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // y4 = 0.0
117];
118
119/// EWKB for MULTIPOINT ((1 2), (3 4)) with SRID 4326
120/// Little endian, geometry type 4 (MULTIPOINT) with SRID flag
121pub const MULTIPOINT_WITH_SRID_4326_EWKB: [u8; 55] = [
122    0x01, // byte-order
123    0x04, 0x00, 0x00, 0x20, // geometry type 4 (MULTIPOINT) with SRID flag
124    0xe6, 0x10, 0x00, 0x00, // SRID 4326
125    0x02, 0x00, 0x00, 0x00, // number of points (2)
126    // First point
127    0x01, // byte-order
128    0x01, 0x00, 0x00, 0x00, // geometry type 1 (POINT) - no SRID flag
129    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x1 = 1.0
130    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y1 = 2.0
131    // Second point
132    0x01, // byte-order
133    0x01, 0x00, 0x00, 0x00, // geometry type 1 (POINT) - no SRID flag
134    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // x2 = 3.0
135    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, // y2 = 4.0
136];
137
138/// EWKB for GEOMETRYCOLLECTION (POINT (1 2)) with SRID 4326
139/// Little endian, geometry type 7 (GEOMETRYCOLLECTION) with SRID flag
140pub const GEOMETRYCOLLECTION_POINT_WITH_SRID_4326_EWKB: [u8; 34] = [
141    0x01, // byte-order
142    0x07, 0x00, 0x00, 0x20, // geometry type 7 (GEOMETRYCOLLECTION) with SRID flag
143    0xe6, 0x10, 0x00, 0x00, // SRID 4326
144    0x01, 0x00, 0x00, 0x00, // number of geometries (1)
145    // Nested POINT
146    0x01, // byte-order
147    0x01, 0x00, 0x00, 0x00, // geometry type 1 (POINT) - no SRID flag
148    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x = 1.0
149    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y = 2.0
150];
151
152/// EWKB for GEOMETRYCOLLECTION (POINT Z (1 2 3)) with SRID 4326
153/// Little endian, geometry type 7 (GEOMETRYCOLLECTION) with SRID flag; nested POINT Z (Z flag set)
154pub const GEOMETRYCOLLECTION_POINT_Z_WITH_SRID_4326_EWKB: [u8; 42] = [
155    0x01, // byte-order
156    0x07, 0x00, 0x00, 0x20, // geometry type 7 (GEOMETRYCOLLECTION) with SRID flag
157    0xe6, 0x10, 0x00, 0x00, // SRID 4326
158    0x01, 0x00, 0x00, 0x00, // number of geometries (1)
159    // Nested POINT Z
160    0x01, // byte-order
161    0x01, 0x00, 0x00, 0x80, // geometry type 1 (POINT) with Z flag
162    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x = 1.0
163    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y = 2.0
164    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // z = 3.0
165];
166
167/// EWKB for GEOMETRYCOLLECTION (POINT M (1 2 4)) with SRID 4326
168/// Little endian, geometry type 7 (GEOMETRYCOLLECTION) with SRID flag; nested POINT M (M flag set)
169pub const GEOMETRYCOLLECTION_POINT_M_WITH_SRID_4326_EWKB: [u8; 42] = [
170    0x01, // byte-order
171    0x07, 0x00, 0x00, 0x20, // geometry type 7 (GEOMETRYCOLLECTION) with SRID flag
172    0xe6, 0x10, 0x00, 0x00, // SRID 4326
173    0x01, 0x00, 0x00, 0x00, // number of geometries (1)
174    // Nested POINT M
175    0x01, // byte-order
176    0x01, 0x00, 0x00, 0x40, // geometry type 1 (POINT) with M flag
177    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x = 1.0
178    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y = 2.0
179    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, // m = 4.0
180];
181
182/// EWKB for GEOMETRYCOLLECTION (POINT ZM (1 2 3 4)) with SRID 4326
183/// Little endian, geometry type 7 (GEOMETRYCOLLECTION) with SRID flag; nested POINT ZM (Z and M flags set)
184pub const GEOMETRYCOLLECTION_POINT_ZM_WITH_SRID_4326_EWKB: [u8; 50] = [
185    0x01, // byte-order
186    0x07, 0x00, 0x00, 0x20, // geometry type 7 (GEOMETRYCOLLECTION) with SRID flag
187    0xe6, 0x10, 0x00, 0x00, // SRID 4326
188    0x01, 0x00, 0x00, 0x00, // number of geometries (1)
189    // Nested POINT ZM
190    0x01, // byte-order
191    0x01, 0x00, 0x00, 0xc0, // geometry type 1 (POINT) with Z and M flags
192    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // x = 1.0
193    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // y = 2.0
194    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, // z = 3.0
195    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, // m = 4.0
196];
197
198/// EWKB for POINT EMPTY with SRID 4326
199/// Little endian, geometry type 1 (POINT) with SRID flag
200pub const POINT_EMPTY_WITH_SRID_4326_EWKB: [u8; 25] = [
201    0x01, // byte-order
202    0x01, 0x00, 0x00, 0x20, // geometry type 1 (POINT) with SRID flag
203    0xe6, 0x10, 0x00, 0x00, // SRID 4326
204    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, // x = NaN
205    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, // y = NaN
206];
207
208/// EWKB for GEOMETRYCOLLECTION EMPTY with SRID 4326
209/// Little endian, geometry type 7 (GEOMETRYCOLLECTION) with SRID flag
210pub const GEOMETRYCOLLECTION_EMPTY_WITH_SRID_4326_EWKB: [u8; 13] = [
211    0x01, // byte-order
212    0x07, 0x00, 0x00, 0x20, // geometry type 7 (GEOMETRYCOLLECTION) with SRID flag
213    0xe6, 0x10, 0x00, 0x00, // SRID 4326
214    0x00, 0x00, 0x00, 0x00, // number of geometries (0)
215];
216
217pub fn louisiana<T>() -> LineString<T>
218where
219    T: WktFloat + Default + FromStr,
220{
221    line_string("louisiana.wkt")
222}
223
224pub fn baton_rouge<T>() -> Point<T>
225where
226    T: WktFloat + Default + FromStr,
227{
228    let x = T::from(-91.147385).unwrap();
229    let y = T::from(30.471165).unwrap();
230    Point::new(x, y)
231}
232
233pub fn east_baton_rouge<T>() -> Polygon<T>
234where
235    T: WktFloat + Default + FromStr,
236{
237    polygon("east_baton_rouge.wkt")
238}
239
240pub fn norway_main<T>() -> LineString<T>
241where
242    T: WktFloat + Default + FromStr,
243{
244    line_string("norway_main.wkt")
245}
246
247pub fn norway_concave_hull<T>() -> LineString<T>
248where
249    T: WktFloat + Default + FromStr,
250{
251    line_string("norway_concave_hull.wkt")
252}
253
254pub fn norway_convex_hull<T>() -> LineString<T>
255where
256    T: WktFloat + Default + FromStr,
257{
258    line_string("norway_convex_hull.wkt")
259}
260
261pub fn norway_nonconvex_hull<T>() -> LineString<T>
262where
263    T: WktFloat + Default + FromStr,
264{
265    line_string("norway_nonconvex_hull.wkt")
266}
267
268pub fn vw_orig<T>() -> LineString<T>
269where
270    T: WktFloat + Default + FromStr,
271{
272    line_string("vw_orig.wkt")
273}
274
275pub fn vw_simplified<T>() -> LineString<T>
276where
277    T: WktFloat + Default + FromStr,
278{
279    line_string("vw_simplified.wkt")
280}
281
282pub fn poly1<T>() -> LineString<T>
283where
284    T: WktFloat + Default + FromStr,
285{
286    line_string("poly1.wkt")
287}
288
289pub fn poly1_hull<T>() -> LineString<T>
290where
291    T: WktFloat + Default + FromStr,
292{
293    line_string("poly1_hull.wkt")
294}
295
296pub fn poly2<T>() -> LineString<T>
297where
298    T: WktFloat + Default + FromStr,
299{
300    line_string("poly2.wkt")
301}
302
303pub fn poly2_hull<T>() -> LineString<T>
304where
305    T: WktFloat + Default + FromStr,
306{
307    line_string("poly2_hull.wkt")
308}
309
310pub fn poly_in_ring<T>() -> LineString<T>
311where
312    T: WktFloat + Default + FromStr,
313{
314    line_string("poly_in_ring.wkt")
315}
316
317pub fn ring<T>() -> LineString<T>
318where
319    T: WktFloat + Default + FromStr,
320{
321    line_string("ring.wkt")
322}
323
324pub fn shell<T>() -> LineString<T>
325where
326    T: WktFloat + Default + FromStr,
327{
328    line_string("shell.wkt")
329}
330
331// From https://geodata.nationaalgeoregister.nl/kadastralekaart/wfs/v4_0?request=GetFeature&service=WFS&srsName=EPSG:4326&typeName=kadastralekaartv4:perceel&version=2.0.0&outputFormat=json&bbox=165593,480993,166125,481552
332pub fn nl_zones<T>() -> MultiPolygon<T>
333where
334    T: WktFloat + Default + FromStr,
335{
336    multi_polygon("nl_zones.wkt")
337}
338
339// From https://afnemers.ruimtelijkeplannen.nl/afnemers/services?request=GetFeature&service=WFS&srsName=EPSG:4326&typeName=Enkelbestemming&version=2.0.0&bbox=165618,480983,166149,481542";
340pub fn nl_plots_wgs84<T>() -> MultiPolygon<T>
341where
342    T: WktFloat + Default + FromStr,
343{
344    multi_polygon("nl_plots.wkt")
345}
346
347pub fn nl_plots_epsg_28992<T>() -> MultiPolygon<T>
348where
349    T: WktFloat + Default + FromStr,
350{
351    // https://epsg.io/28992
352    multi_polygon("nl_plots_epsg_28992.wkt")
353}
354
355fn line_string<T>(name: &str) -> LineString<T>
356where
357    T: WktFloat + Default + FromStr,
358{
359    LineString::try_from_wkt_reader(file(name)).unwrap()
360}
361
362pub fn polygon<T>(name: &str) -> Polygon<T>
363where
364    T: WktFloat + Default + FromStr,
365{
366    Polygon::try_from_wkt_reader(file(name)).unwrap()
367}
368
369pub fn multi_polygon<T>(name: &str) -> MultiPolygon<T>
370where
371    T: WktFloat + Default + FromStr,
372{
373    MultiPolygon::try_from_wkt_reader(file(name)).unwrap()
374}
375
376pub fn file(name: &str) -> File {
377    let base = crate::data::sedona_testing_dir()
378        .expect("sedona-testing directory should resolve when accessing fixtures");
379
380    let mut path = PathBuf::from(base);
381    path.push("data");
382    path.push("wkts");
383    path.push("geo-test-fixtures");
384    path.push(name);
385
386    File::open(&path).unwrap_or_else(|_| panic!("Can't open file: {path:?}"))
387}
388
389#[cfg(test)]
390mod tests {
391    use super::*;
392
393    #[test]
394    fn norway_main_linestring_has_vertices() {
395        let ls = norway_main::<f64>();
396        assert!(
397            !ls.0.is_empty(),
398            "LineString loaded from norway_main.wkt should have vertices"
399        );
400
401        let first = ls.0.first().expect("expected at least one coordinate");
402        assert!(first.x.is_finite(), "first coordinate x should be finite");
403        assert!(first.y.is_finite(), "first coordinate y should be finite");
404    }
405
406    #[test]
407    fn nl_zones_multipolygon_not_empty() {
408        let mp = nl_zones::<f64>();
409        assert!(
410            !mp.0.is_empty(),
411            "MultiPolygon from nl_zones.wkt should contain polygons"
412        );
413
414        let polygon = mp.0.first().expect("expected at least one polygon");
415        assert!(
416            !polygon.exterior().0.is_empty(),
417            "polygon exterior ring should contain coordinates"
418        );
419    }
420}