-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathgeom_relations.jl
More file actions
483 lines (434 loc) · 22.9 KB
/
geom_relations.jl
File metadata and controls
483 lines (434 loc) · 22.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
import GeometryOps as GO
import GeoInterface as GI
import LibGEOS as LG
using Extents
using DataFrames
using ..TestHelpers
# Tests of DE-9IM Methods
pt1 = LG.Point([0.0, 0.0])
pt2 = LG.Point([5.0, 5.0])
pt3 = LG.Point([1.0, 0.0])
pt4 = LG.Point([0.5, 0.0])
pt5 = LG.Point([0.5, 0.25])
pt6 = LG.Point([0.6, 0.4])
pt7 = LG.Point([0.4, 0.8])
l1 = LG.LineString([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]])
l2 = LG.LineString([[0.0, 0.0], [1.0, 0.0]])
l3 = LG.LineString([[-1.0, 0.0], [0.0, 0.0], [1.0, 0.0]])
l4 = LG.LineString([[0.5, 0.0], [1.0, 0.0], [1.0, 0.5]])
l5 = LG.LineString([[0.0, 0.0], [-1.0, -1.0]])
l6 = LG.LineString([[2.0, 2.0], [0.0, 1.0]])
l7 = LG.LineString([[0.5, 1.0], [0.5, -1.0]])
l8 = LG.LineString([[0.0, 0.0], [0.5, 0.0], [0.5, 0.5], [1.0, -0.5]])
l9 = LG.LineString([[0.0, 1.0], [0.0, -1.0], [1.0, 1.0]])
l10 = LG.LineString([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]])
l11 = LG.LineString([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0], [-1.0, 0.0]])
l12 = LG.LineString([[0.6, 0.5], [0.6, 0.9]])
l13 = LG.LineString([[2.0, 2.0], [3.0, 3.0]])
l14 = LG.LineString([[0.6, 0.25], [0.6, 0.35]])
l15 = LG.LineString([[0.0, 3.0], [4.0, 3.0]])
l16 = LG.LineString([[0.3, -0.7], [1.0, 0.0], [3.0, 0.6]])
r1 = LG.LinearRing([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]])
r2 = LG.LinearRing([[0.5, 0.2], [0.6, 0.4], [0.7, 0.2], [0.5, 0.2]])
r3 = LG.LinearRing([[0.2, 0.7], [0.4, 0.9], [0.5, 0.6], [0.2, 0.7]])
r4 = LG.LinearRing([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]])
r5 = LG.LinearRing([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [1.0, 2.0], [1.0, 1.0], [0.0, 0.0]])
r6 = LG.LinearRing([[0.0, 0.0], [-1.0, 0.0], [-1.0, 1.0], [0.0, 1.0], [0.0, 0.0]])
r7 = LG.LinearRing([[0.5, 0.5], [1.5, 0.5], [1.5, 1.5], [0.5, 1.5], [0.5, 0.5]])
r8 = LG.LinearRing([[0.1, 0.1], [0.2, 0.1], [0.2, 0.2], [0.1, 0.2], [0.1, 0.1]])
r9 = LG.LinearRing([[1.0, -0.5], [0.5, -1.0], [1.5, -1.0], [1.0, -0.5]])
r10 = LG.LinearRing([[0.5, 0.2], [0.6, 0.4], [0.3, 0.3], [0.5, 0.2]])
r11 = LG.LinearRing([[0.55, 0.21], [0.55, 0.23], [0.65, 0.23], [0.66, 0.21], [0.55, 0.21]])
p1 = LG.Polygon(r4, [r2, r3])
p2 = LG.Polygon(r4)
p3 = LG.Polygon(r2)
p4 = LG.Polygon(r6)
p5 = LG.Polygon(r9)
p6 = LG.Polygon(r11)
p7 = LG.Polygon(r7)
p8 = LG.Polygon([[[0.0, 0.0], [0.0, 3.0], [1.0, 2.0], [2.0, 3.0], [3.0, 2.0], [4.0, 3.0], [4.0, 0.0], [0.0, 0.0]]])
p9 = LG.Polygon([[[0.0, 0.0], [0.0, 3.0], [1.0, 4.0], [2.0, 3.0], [3.0, 4.0], [4.0, 3.0], [4.0, 0.0], [0.0, 0.0]]])
p10 = LG.Polygon([
[[0.1, 0.5], [0.1, 0.99], [0.6, 0.99], [0.6, 0.5], [0.1, 0.5]],
[[0.15, 0.55], [0.15, 0.95], [0.55, 0.95], [0.55, 0.55], [0.15, 0.55]]
])
p11 = LG.Polygon(r3)
# Polygon with interior notch sharing collinear edges with a rectangle (issue #396)
p12 = LG.Polygon([[[0.0, 0.0], [0.0, 4.0], [8.0, 4.0], [8.0, 0.0], [0.0, 0.0]]])
p13 = LG.Polygon([[[0.0, 0.0], [0.0, 2.0], [7.0, 1.0], [7.0, 3.0], [0.0, 3.0], [0.0, 4.0], [8.0, 4.0], [8.0, 0.0], [0.0, 0.0]]])
mpt1 = LG.MultiPoint([pt1, pt2])
mpt2 = LG.MultiPoint([pt2, pt3])
mpt3 = LG.MultiPoint([pt4, pt5])
ml1 = LG.MultiLineString([l5, l6, l7])
ml2 = LG.MultiLineString([l1])
mp1 = LG.MultiPolygon([p1])
mp2 = LG.MultiPolygon([p6, p7])
gc1 = LG.GeometryCollection([pt1, l5, p6])
ext1 = Extents.Extent(X=(0.0, 1.0), Y=(0.0, 1.0))
ext2 = Extents.Extent(X=(0.5, 1.5), Y=(0.5, 1.5))
ext3 = Extents.Extent(X=(2.0, 3.0), Y=(2.0, 3.0))
ext4 = Extents.Extent(X=(1.0, 2.0), Y=(1.0, 2.0)) # Touches ext1
test_pairs = [
# Points and geometries
(pt1, pt1, "pt1", "pt1", "Same point"),
(pt1, pt2, "pt1", "pt2", "Different point"),
(pt1, l1, "pt1", "l1", "Point on line endpoint"),
(pt2, l1, "pt2", "l1", "Point outside line"),
(pt3, l1, "pt3", "l1", "Point on line segment"),
(pt4, l1, "pt4", "l1", "Point on line vertex between segments"),
(l1, pt3, "l1", "pt3", "Point on line segment (order swapped)"),
(pt1, r1, "pt1", "r1", "Point on ring 'endpoint'"),
(pt2, r1, "pt2", "r1", "Point outside ring"),
(pt3, r1, "pt3", "r1", "Point on ring segment"),
(pt4, r1, "pt4", "r1", "Point on ring vertex between segments"),
(r1, pt3, "r1", "pt3", "Point on ring segment (order swapped)"),
(p1, pt1, "p1", "pt1", "Point on vertex of polygon"),
(pt2, p1, "pt2", "p1", "Point outside of polygon's external ring"),
(pt4, p1, "pt4", "p1", "Point on polygon's edge"),
(pt5, p1, "pt5", "p1", "Point inside of polygon"),
(pt6, p1, "pt6", "p1", "Point on hole edge"),
(pt7, p1, "pt7", "p1", "Point inside of polygon hole"),
(p1, pt5, "p1", "pt5", "Point inside of polygon (order swapped)"),
# Lines and geometries
(l1, l1, "l1", "l1", "Same line"),
(l2, l1, "l2", "l1", "L2 is one segment of l1"),
(l3, l1, "l3", "l1", "L3 shares one segment with l1 and has one segment outside"),
(l4, l1, "l4", "l1", "L4 shares half of each of l1 segments"),
(l5, l1, "l5", "l1", "L5 shares one endpoint with l1 but not segments"),
(l6, l1, "l6", "l1", "Lines are disjoint"),
(l7, l1, "l7", "l1", "L7 crosses through one of l1's segments"),
(l8, l1, "l8", "l1", "Overlaps one segment and crosses through another segment"),
(l9, l1, "l9", "l1", "Two segments touch and two segments crosses"),
(l16, l1, "l16", "l1", "L16 bounces off of l1's corner"),
(l1, r1, "l1", "r1", "Line inside of ring"),
(l3, r1, "l3", "r1", "Line covers one edge of linear ring and has segment outside"),
(l5, r1, "l5", "r1", "Line and linear ring are only covered by vertex"),
(l6, r1, "l6", "r1", "Line and ring are disjoint"),
(l7, r1, "l7", "r1", "Line crosses through two ring edges"),
(l8, r1, "l8", "r1", "Line crosses through two ring edges and touches third edge"),
(l10, r1, "l10", "r1", "Line is equal to linear ring"),
(l11, r1, "l11", "r1", "Line covers linear ring and then has extra segment"),
(l1, p1, "l1", "p1", "Line on polygon edge"),
(l3, p1, "l3", "p1", "Line on polygon edge and extending beyond polygon edge"),
(l5, p1, "l5", "p1", "Line outside polygon connected by a vertex"),
(l7, p1, "l7", "p1", "Line through polygon cutting to the outside"),
(l12, p1, "l12", "p1", "Line inside polygon"),
(l13, p1, "l13", "p1", "Line outside of polygon"),
(l14, p1, "l14", "p1", "Line in polygon hole"),
(l15, p8, "l15", "p8", "Line outside crown-shaped polygon but touching edges"),
(l15, p9, "l15", "p9", "Line within crown-shaped polygon but touching edges"),
# Ring and geometries
(r1, l1, "r1", "l1", "Line is within linear ring"),
(r1, l3, "r1", "l3", "Line covers one edge of linear ring and has segment outside"),
(r1, l5, "r1", "l5", "Line and linear ring are only connected at vertex"),
(r1, l6, "r1", "l6", "Line and linear ring are disjoint"),
(r1, l7, "r1", "l7", "Line crosses though two ring edges"),
(r1, l8, "r1", "l8", "Line crosses through two ring edges and touches third edge"),
(r1, l10, "r1", "l10", "Line is equal to linear ring"),
(r1, l11, "r1", "l11", "Line covers linear ring and then has extra segment"),
(r1, r1, "r1", "r1", "Same rings"),
(r2, r1, "r2", "r1", "Disjoint ring with one 'inside' of hole created"),
(r3, r1, "r3", "r1", "Disjoint ring with one 'outside' of hole created"),
(r4, r1, "r4", "r1", "Rings share two sides and rest of sides don't touch"),
(r1, r5, "r1", "r5", "Ring shares all edges with other ring, plus an extra loop"),
(r1, r6, "r1", "r6", "Rings share just one vertex"),
(r1, r7, "r1", "r7", "Rings cross one another"),
(r4, p1, "r4", "p1", "Ring on boundary of polygon"),
(r1, p1, "r1", "p1", "Ring on boundary and cutting through polygon"),
(r2, p1, "r2", "p1", "Ring on hole boundary"),
(r6, p1, "r6", "p1", "Ring touches polygon at one vertex"),
(r7, p1, "r7", "p1", "Ring crosses through polygon"),
(r8, p1, "r8", "p1", "Ring inside of polygon"),
(r9, p1, "r9", "p1", "Ring outside of polygon"),
(r10, p1, "r10", "p1", "Ring inside of polygon and shares hole's edge"),
(r11, p1, "r11", "p1", "Ring inside of polygon hole"),
# Polygon and geometries
(p1, p1, "p1", "p1", "Same polygons"),
(p1, p2, "p1", "p2", "P1 and p2 are the same but p1 has holes"),
(p2, p1, "p2", "p1", "P1 and p2 are the same but p1 has holes (order swapped)"),
(p3, p1, "p3", "p1", "P3 is equal to one of p1's holes"),
(p4, p1, "p4", "p1", "Polygon's share just one vertex"),
(p5, p1, "p5", "p1", "Polygon outside of other polygon"),
(p6, p1, "p6", "p1", "Polygon inside of other polygon's hole"),
(p7, p1, "p7", "p1", "Polygons overlap"),
(p10, p1, "p10", "p1", "Polygon's with nested holes"),
(p12, p13, "p12", "p13", "Rectangle with polygon with collinear notch (#396)"),
(p13, p12, "p13", "p12", "Polygon with collinear notch inside rectangle (#396)"),
# Multigeometries
(mpt1, mpt1, "mpt1", "mpt1", "Same set of points for multipoints"),
(mpt1, mpt2, "mpt1", "mpt2", "Some point matches, others are different"),
(mpt1, mpt3, "mpt1", "mpt3", "No shared points"),
(ml1, ml2, "ml1", "ml2", "Lines in ml1 cross and touch ml2"),
(mp1, mp2, "mp1", "mp2", "Polygons in mp1 are inside hole and overlap"),
# Extent tests
(ext1, ext1, "ext1", "ext1", "Same extent"),
(ext1, ext2, "ext1", "ext2", "Overlapping extents"),
(ext1, ext3, "ext1", "ext3", "Disjoint extents"),
(ext1, ext4, "ext1", "ext4", "Touching extents"),
(ext1, pt1, "ext1", "pt1", "Point inside extent"),
(ext1, pt2, "ext1", "pt2", "Point outside extent"),
(ext1, l1, "ext1", "l1", "Line inside extent"),
(ext1, l2, "ext1", "l2", "Line crossing extent"),
(ext1, p1, "ext1", "p1", "Polygon same as extent"),
(ext1, p2, "ext1", "p2", "Polygon overlapping extent"),
]
function test_geom_relation(GO_f, LG_f, f_name; swap_points=false)
for (g1, g2, sg1, sg2, sdesc) in test_pairs
@testset "$sg1 $sg2 $sdesc" begin
if swap_points
@test_implementations (GO_f($g2, $g1) == LG_f($g2, $g1))
else
@test_implementations GO_f($g1, $g2) == LG_f($g1, $g2)
end
end
end
end
function test_geom_relation(GO_f, alg::GO.Algorithm, f_name; swap_points=false)
for (g1, g2, sg1, sg2, sdesc) in test_pairs
@testset "$sg1 $sg2 $sdesc" begin
if swap_points
@test_implementations (GO_f($g2, $g1) == GO_f(alg, $g2, $g1))
else
@test_implementations GO_f($g1, $g2) == GO_f(alg, $g1, $g2)
end
end
end
end
@testset "Contains" begin test_geom_relation(GO.contains, GO.GEOS(), "contains"; swap_points = true) end
@testset "Covered By" begin test_geom_relation(GO.coveredby, GO.GEOS(), "coveredby") end
@testset "Covers" begin test_geom_relation(GO.covers, GO.GEOS(), "covers"; swap_points = true) end
@testset "Disjoint" begin test_geom_relation(GO.disjoint, GO.GEOS(), "disjoint")end
@testset "Intersect" begin test_geom_relation(GO.intersects, GO.GEOS(), "intersects") end
@testset "Touches" begin test_geom_relation(GO.touches, GO.GEOS(), "touches") end
@testset "Within" begin test_geom_relation(GO.within, GO.GEOS(), "within") end
@testset "Overlaps" begin
p1 = LG.Point([0.0, 0.0])
p2 = LG.Point([0.0, 1.0])
mp1 = LG.MultiPoint([[0.0, 1.0], [4.0, 4.0]])
mp2 = LG.MultiPoint([[0.0, 1.0], [2.0, 2.0]])
mp3 = LG.MultiPoint([[0.0, 1.0], [2.0, 2.0], [3.0, 3.0]])
mp4 = LG.MultiPoint([
[-36.05712890625, 26.480407161007275],
[-35.7220458984375, 27.137368359795584],
[-35.13427734375, 26.83387451505858],
[-35.4638671875, 27.254629577800063],
[-35.5462646484375, 26.86328062676624],
[-35.3924560546875, 26.504988828743404],
])
mp5 = GI.MultiPoint([
[-35.4638671875, 27.254629577800063],
[-35.5462646484375, 26.86328062676624],
[-35.3924560546875, 26.504988828743404],
[-35.2001953125, 26.12091815959972],
[-34.9969482421875, 26.455820238459893],
])
@testset_implementations "Points/MultiPoints" begin
# Two points can't overlap
@test GO.overlaps($p1, $p1) == LG.overlaps($p1, $p2)
# No shared points, doesn't overlap
@test GO.overlaps($p1, $mp1) == LG.overlaps($p1, $mp1)
# One shared point, does overlap
@test GO.overlaps($p2, $mp1) == LG.overlaps($p2, $mp1)
# All shared points, doesn't overlap
@test GO.overlaps($mp1, $mp1) == LG.overlaps($mp1, $mp1)
# Not all shared points, overlaps
@test GO.overlaps($mp1, $mp2) == LG.overlaps($mp1, $mp2)
# One set of points entirely inside other set, doesn't overlap
@test GO.overlaps($mp2, $mp3) == LG.overlaps($mp2, $mp3)
# Not all points shared, overlaps
@test GO.overlaps($mp1, $mp3) == LG.overlaps($mp1, $mp3)
# Some shared points, overlaps
@test GO.overlaps($mp1, $mp2) == LG.overlaps($mp1, $mp2)
@test GO.overlaps($mp1, $mp2) == GO.overlaps($mp2, $mp1)
end
l1 = LG.LineString([[0.0, 0.0], [0.0, 10.0]])
l2 = LG.LineString([[0.0, -10.0], [0.0, 20.0]])
l3 = LG.LineString([[0.0, -10.0], [0.0, 3.0]])
l4 = LG.LineString([[5.0, -5.0], [5.0, 5.0]])
# Linear rings that intersect but don't overlap
r1 = LG.LinearRing([[0.0, 0.0], [0.0, 5.0], [5.0, 5.0], [5.0, 0.0], [0.0, 0.0]])
r2 = LG.LinearRing([[1.0, 1.0], [1.0, 6.0], [6.0, 6.0], [6.0, 1.0], [1.0, 1.0]])
@testset_implementations "Lines/Rings" begin
# Line can't overlap with itself
@test GO.overlaps($l1, $l1) == LG.overlaps($l1, $l1)
# Line completely within other line doesn't overlap
@test GO.overlaps($l1, $l2) == GO.overlaps($l2, $l1) == LG.overlaps($l1, $l2)
# Overlapping lines
@test GO.overlaps($l1, $l3) == GO.overlaps($l3, $l1) == LG.overlaps($l1, $l3)
# Lines that don't touch
@test GO.overlaps($l1, $l4) == LG.overlaps($l1, $l4)
@test LG.overlaps($r1, $r2) == LG.overlaps($r1, $r2)
end
p1 = LG.Polygon([[[0.0, 0.0], [0.0, 5.0], [5.0, 5.0], [5.0, 0.0], [0.0, 0.0]]])
p2 = LG.Polygon([
[[10.0, 0.0], [10.0, 20.0], [30.0, 20.0], [30.0, 0.0], [10.0, 0.0]],
[[15.0, 1.0], [15.0, 11.0], [25.0, 11.0], [25.0, 1.0], [15.0, 1.0]]
])
p3 = LG.Polygon([[[1.0, 1.0], [1.0, 6.0], [6.0, 6.0], [6.0, 1.0], [1.0, 1.0]]])
p4 = LG.Polygon([[[20.0, 5.0], [20.0, 10.0], [18.0, 10.0], [18.0, 5.0], [20.0, 5.0]]])
p5 = LG.Polygon(
[[
[-53.57208251953125, 28.287451910503744],
[-53.33038330078125, 28.29228897739706],
[-53.34136352890625, 28.430052892335723],
[-53.57208251953125, 28.287451910503744],
]]
)
m1 = LG.MultiPolygon([
[[[0.0, 0.0], [0.0, 5.0], [5.0, 5.0], [5.0, 0.0], [0.0, 0.0]]],
[
[[10.0, 0.0], [10.0, 20.0], [30.0, 20.0], [30.0, 0.0], [10.0, 0.0]],
[[15.0, 1.0], [15.0, 11.0], [25.0, 11.0], [25.0, 1.0], [15.0, 1.0]]
]
])
@testset_implementations "Polygons/MultiPolygons" begin
# Test basic polygons that don't overlap
@test GO.overlaps($p1, $p2) == LG.overlaps($p1, $p2)
@test !GO.overlaps($p1, (1, 1))
@test !GO.overlaps((1, 1), $p2)
# Test basic polygons that overlap
@test GO.overlaps($p1, $p3) == LG.overlaps($p1, $p3)
# Test one polygon within the other
@test GO.overlaps($p2, $p4) == GO.overlaps($p4, $p2) == LG.overlaps($p2, $p4)
# Test equal polygons
@test GO.overlaps($p5, $p5) == LG.overlaps($p5, $p5)
# Test polygon that overlaps with multipolygon
@test GO.overlaps($m1, $p3) == LG.overlaps($m1, $p3)
# Test polygon in hole of multipolygon, doesn't overlap
@test GO.overlaps($m1, $p4) == LG.overlaps($m1, $p4)
end
# Test Line × Line overlaps (GI.Line, not LineString)
@testset "Line × Line overlaps" begin
# Overlapping collinear lines
line1 = GI.Line([(0.0, 0.0), (2.0, 0.0)])
line2 = GI.Line([(1.0, 0.0), (3.0, 0.0)])
@test GO.overlaps(line1, line2) == true
# Non-overlapping collinear lines
line3 = GI.Line([(0.0, 0.0), (1.0, 0.0)])
line4 = GI.Line([(2.0, 0.0), (3.0, 0.0)])
@test GO.overlaps(line3, line4) == false
# One line fully contains the other
line5 = GI.Line([(0.0, 0.0), (4.0, 0.0)])
line6 = GI.Line([(1.0, 0.0), (2.0, 0.0)])
@test GO.overlaps(line5, line6) == false
# Non-collinear lines
line7 = GI.Line([(0.0, 0.0), (1.0, 0.0)])
line8 = GI.Line([(0.0, 0.0), (0.0, 1.0)])
@test GO.overlaps(line7, line8) == false
end
# Test MultiPolygon × MultiPolygon overlaps
@testset "MultiPolygon × MultiPolygon overlaps" begin
# Create two multipolygons that overlap
mp1 = GI.MultiPolygon([
[[[0.0, 0.0], [2.0, 0.0], [2.0, 2.0], [0.0, 2.0], [0.0, 0.0]]],
[[[5.0, 5.0], [7.0, 5.0], [7.0, 7.0], [5.0, 7.0], [5.0, 5.0]]]
])
mp2 = GI.MultiPolygon([
[[[1.0, 1.0], [3.0, 1.0], [3.0, 3.0], [1.0, 3.0], [1.0, 1.0]]],
[[[6.0, 6.0], [8.0, 6.0], [8.0, 8.0], [6.0, 8.0], [6.0, 6.0]]]
])
@test GO.overlaps(mp1, mp2) == true
# Create two multipolygons that don't overlap
mp3 = GI.MultiPolygon([
[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]
])
mp4 = GI.MultiPolygon([
[[[5.0, 5.0], [6.0, 5.0], [6.0, 6.0], [5.0, 6.0], [5.0, 5.0]]]
])
@test GO.overlaps(mp3, mp4) == false
end
end
@testset "Crosses" begin
line6 = GI.LineString([(1.0, 1.0), (1.0, 2.0), (1.0, 3.0), (1.0, 4.0)])
line7 = GI.LineString([(1, 1), (1, 2), (1, 3), (1, 4)])
line8 = GI.LineString([(1, 1), (1, 2), (1, 3), (1, 4)])
poly7 = GI.Polygon([[(-1.0, 2.0), (3.0, 2.0), (3.0, 3.0), (-1.0, 3.0), (-1.0, 2.0)]])
@testset_implementations begin
@test GO.crosses(GI.LineString([(-2.0, 2.0), (4.0, 2.0)]), $line6) == true
@test GO.crosses(GI.LineString([(0.5, 2.5), (1.0, 1.0)]), $poly7) == true
@test GO.crosses(GI.MultiPoint([(1.0, 2.0), (12.0, 12.0)]), $line7) == true
@test GO.crosses(GI.MultiPoint([(1.0, 0.0), (12.0, 12.0)]), $line8) == false
@test GO.crosses(GI.LineString([(-2.0, 2.0), (-4.0, 2.0)]), $poly7) == false
end
end
@testset "Single-argument methods" begin
@test GO.contains(p2)(p1) == GO.contains(p1, p2)
@test GO.coveredby(p2)(p1) == GO.coveredby(p1, p2)
@test GO.covers(p2)(p1) == GO.covers(p1, p2)
@test GO.crosses(l2)(l1) == GO.crosses(l1, l2)
@test GO.disjoint(p2)(p1) == GO.disjoint(p1, p2)
@test GO.intersects(p2)(p1) == GO.intersects(p1, p2)
@test GO.overlaps(p2)(p1) == GO.overlaps(p1, p2)
@test GO.touches(p2)(p1) == GO.touches(p1, p2)
@test GO.within(p2)(p1) == GO.within(p1, p2)
end
@testset "Features, Table rows and Extents" begin
feature1 = GI.Feature(pt1; properties=Dict{Symbol, Any}())
feature2 = GI.Feature(pt2; properties=Dict{Symbol, Any}())
# Test NamedTuple
named_tuple1 = (; geometry=pt1)
named_tuple2 = (; geometry=pt2)
@test GO.disjoint(named_tuple1, named_tuple2) == GO.disjoint(pt1, pt2)
@test GO.coveredby(named_tuple1, ext1) == GO.coveredby(pt1, ext1)
@test GO.within(named_tuple1, ext1) == GO.within(pt1, ext1)
# Test DataFrame row
df = DataFrame(geometry=[pt1, pt2])
df_row1 = df[1, :]
df_row2 = df[2, :]
@test GO.disjoint(df_row1, df_row2) == GO.disjoint(pt1, pt2)
@test GO.coveredby(df_row1, ext1) == GO.coveredby(pt1, ext1)
@test GO.within(df_row1, ext1) == GO.within(pt1, ext1)
# Test features
@test GO.disjoint(feature1, feature2) == GO.disjoint(pt1, pt2)
@test GO.coveredby(feature1, ext1) == GO.coveredby(pt1, ext1)
@test GO.within(feature1, ext1) == GO.within(pt1, ext1)
# Test mixed types
@test GO.disjoint(feature1, named_tuple2) == GO.disjoint(pt1, pt2)
@test GO.coveredby(feature1, ext1) == GO.coveredby(pt1, ext1)
@test GO.within(df_row1, ext1) == GO.within(pt1, ext1)
# Test extents
@test GO.disjoint(ext1, ext3) == Extents.disjoint(ext1, ext3)
@test GO.coveredby(ext1, ext1) == Extents.coveredby(ext1, ext1)
# Test crosses with Features
line_a = GI.LineString([(-2.0, 2.0), (4.0, 2.0)])
line_b = GI.LineString([(1.0, 1.0), (1.0, 2.0), (1.0, 3.0), (1.0, 4.0)])
poly_c = GI.Polygon([[(-1.0, 2.0), (3.0, 2.0), (3.0, 3.0), (-1.0, 3.0), (-1.0, 2.0)]])
line_d = GI.LineString([(0.5, 2.5), (1.0, 1.0)])
mpt_e = GI.MultiPoint([(1.0, 2.0), (12.0, 12.0)])
feature_line_a = GI.Feature(line_a; properties=Dict{Symbol, Any}())
feature_line_b = GI.Feature(line_b; properties=Dict{Symbol, Any}())
feature_poly_c = GI.Feature(poly_c; properties=Dict{Symbol, Any}())
feature_line_d = GI.Feature(line_d; properties=Dict{Symbol, Any}())
feature_mpt_e = GI.Feature(mpt_e; properties=Dict{Symbol, Any}())
# Test crosses with both geometries as Features
@test GO.crosses(feature_line_a, feature_line_b) == GO.crosses(line_a, line_b)
@test GO.crosses(feature_line_d, feature_poly_c) == GO.crosses(line_d, poly_c)
@test GO.crosses(feature_mpt_e, feature_line_b) == GO.crosses(mpt_e, line_b)
# Test crosses with one Feature and one raw geometry
@test GO.crosses(feature_line_a, line_b) == GO.crosses(line_a, line_b)
@test GO.crosses(line_a, feature_line_b) == GO.crosses(line_a, line_b)
@test GO.crosses(feature_line_d, poly_c) == GO.crosses(line_d, poly_c)
@test GO.crosses(line_d, feature_poly_c) == GO.crosses(line_d, poly_c)
# Test overlaps with Features
poly_overlap1 = GI.Polygon([[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]])
poly_overlap2 = GI.Polygon([[[0.5, 0.5], [1.5, 0.5], [1.5, 1.5], [0.5, 1.5], [0.5, 0.5]]])
poly_disjoint = GI.Polygon([[[2.0, 2.0], [3.0, 2.0], [3.0, 3.0], [2.0, 3.0], [2.0, 2.0]]])
feature_overlap1 = GI.Feature(poly_overlap1; properties=Dict{Symbol, Any}())
feature_overlap2 = GI.Feature(poly_overlap2; properties=Dict{Symbol, Any}())
feature_disjoint = GI.Feature(poly_disjoint; properties=Dict{Symbol, Any}())
# Test overlaps with both geometries as Features
@test GO.overlaps(feature_overlap1, feature_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
@test GO.overlaps(feature_overlap1, feature_disjoint) == GO.overlaps(poly_overlap1, poly_disjoint)
# Test overlaps with one Feature and one raw geometry
@test GO.overlaps(feature_overlap1, poly_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
@test GO.overlaps(poly_overlap1, feature_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
@test GO.overlaps(feature_overlap1, poly_disjoint) == GO.overlaps(poly_overlap1, poly_disjoint)
@test GO.overlaps(poly_overlap1, feature_disjoint) == GO.overlaps(poly_overlap1, poly_disjoint)
# Test with NamedTuples for crosses and overlaps
nt_line_a = (; geometry=line_a)
nt_line_b = (; geometry=line_b)
nt_poly_overlap1 = (; geometry=poly_overlap1)
nt_poly_overlap2 = (; geometry=poly_overlap2)
@test GO.crosses(nt_line_a, nt_line_b) == GO.crosses(line_a, line_b)
@test GO.overlaps(nt_poly_overlap1, nt_poly_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
end