Skip to content

Commit 8374ebe

Browse files
rafaqzasinghvi17
andauthored
allow table rows in relations, and reorganise boilerplate (#347)
* allow table rows in relations, and reorganise boilerplate * tweaks * forward more keywords * add tests and bugfix * remove AG Co-authored-by: Anshul Singhvi <[email protected]> * Actually remove AG --------- Co-authored-by: Anshul Singhvi <[email protected]>
1 parent 30f576d commit 8374ebe

File tree

10 files changed

+76
-110
lines changed

10 files changed

+76
-110
lines changed

src/GeometryOps.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ include("methods/geom_relations/intersects.jl")
8282
include("methods/geom_relations/overlaps.jl")
8383
include("methods/geom_relations/touches.jl")
8484
include("methods/geom_relations/within.jl")
85+
include("methods/geom_relations/common.jl")
8586
include("methods/orientation.jl")
8687
include("methods/polygonize.jl")
8788

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Identical boilerplate methods for geom relations live here
2+
3+
for f in (:coveredby, :crosses, :disjoint, :overlaps, :touches, :within)
4+
_f = Symbol(:_, f)
5+
6+
@eval begin
7+
# Features
8+
$_f(::GI.FeatureTrait, g1, ::GI.AbstractGeometryTrait, g2; kw...) = $f(GI.geometry(g1), g2; kw...)
9+
$_f(::GI.AbstractGeometryTrait, g1, ::GI.FeatureTrait, g2; kw...) = $f(g1, GI.geometry(g2); kw...)
10+
$_f(::GI.FeatureTrait, g1, ::GI.FeatureTrait, g2; kw...) = $f(GI.geometry(g1), GI.geometry(g2); kw...)
11+
12+
# Extent forwarding
13+
$_f(t1::GI.FeatureTrait, f1, ::Nothing, e::Extents.Extent; kw...) =
14+
$_f(t1, f1, GI.PolygonTrait(), extent_to_polygon(e); kw...)
15+
$_f(::Nothing, e1::Extents.Extent, t2::GI.FeatureTrait, f2; kw...) =
16+
$_f(GI.PolygonTrait(), extent_to_polygon(e1), t2, f2; kw...)
17+
$_f(t1::GI.AbstractGeometryTrait, g1, ::Nothing, e::Extents.Extent; kw...) =
18+
$_f(t1, g1, GI.PolygonTrait(), extent_to_polygon(e); kw...)
19+
$_f(::Nothing, e1::Extents.Extent, t2::GI.AbstractGeometryTrait, g2; kw...) =
20+
$_f(GI.PolygonTrait(), extent_to_polygon(e1), t2, g2; kw...)
21+
$_f(::Nothing, e1::Extents.Extent, ::Nothing, e2::Extents.Extent; kw...) =
22+
Extents.$f(e1, e2)
23+
24+
# Table rows ? or error
25+
$_f(::Nothing, g1, ::GI.FeatureTrait, f2; kw...) = $f(_geometry_or_error(g1; kw...), f2)
26+
$_f(::GI.FeatureTrait, f1, ::Nothing, g2; kw...) = $f(f1, _geometry_or_error(g2; kw...))
27+
$_f(::Nothing, g1, ::GI.AbstractGeometryTrait, g2; kw...) = $f(_geometry_or_error(g1; kw...), g2)
28+
$_f(::GI.AbstractGeometryTrait, g1, ::Nothing, g2; kw...) = $f(g1, _geometry_or_error(g2; kw...))
29+
$_f(::Nothing, g1, ::Nothing, g2; kw...) =
30+
$f(_geometry_or_error(g1; kw...), _geometry_or_error(g2; kw...))
31+
end
32+
end

src/methods/geom_relations/coveredby.jl

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ This is equivalent to `x -> coveredby(x, g1)`.
8787
"""
8888
coveredby(g1) = Base.Fix2(coveredby, g1)
8989

90-
# # Convert features to geometries
91-
_coveredby(::GI.FeatureTrait, g1, ::Any, g2) = coveredby(GI.geometry(g1), g2)
92-
_coveredby(::Any, g1, t2::GI.FeatureTrait, g2) = coveredby(g1, GI.geometry(g2))
93-
_coveredby(::FeatureTrait, g1, ::FeatureTrait, g2) = coveredby(GI.geometry(g1), GI.geometry(g2))
94-
9590
# # Points coveredby geometries
9691

9792
# Point is coveredby another point if those points are equal
@@ -279,16 +274,3 @@ function _coveredby(
279274
end
280275
return true
281276
end
282-
283-
# Extent forwarding
284-
function _coveredby(t1::GI.AbstractGeometryTrait, g1, t2, e::Extents.Extent)
285-
return _coveredby(t1, g1, GI.PolygonTrait(), extent_to_polygon(e))
286-
end
287-
function _coveredby(t1, e1::Extents.Extent, t2, g2)
288-
return _coveredby(GI.PolygonTrait(), extent_to_polygon(e1), t2, g2)
289-
end
290-
function _coveredby(t1, e1::Extents.Extent, t2, e2::Extents.Extent)
291-
return Extents.coveredby(e1, e2)
292-
end
293-
294-

src/methods/geom_relations/crosses.jl

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ import GeoInterface as GI, GeometryOps as GO
1616
```
1717
"""
1818
crosses(g1, g2)::Bool = crosses(trait(g1), g1, trait(g2), g2)::Bool
19-
crosses(t1::FeatureTrait, g1, t2, g2)::Bool = crosses(GI.geometry(g1), g2)
20-
crosses(t1, g1, t2::FeatureTrait, g2)::Bool = crosses(g1, geometry(g2))
19+
2120
crosses(::MultiPointTrait, g1, ::LineStringTrait, g2)::Bool = multipoint_crosses_line(g1, g2)
2221
crosses(::MultiPointTrait, g1, ::PolygonTrait, g2)::Bool = multipoint_crosses_poly(g1, g2)
2322
crosses(::LineStringTrait, g1, ::MultiPointTrait, g2)::Bool = multipoint_crosses_lines(g2, g1)
@@ -34,21 +33,6 @@ This is equivalent to `x -> crosses(x, g1)`.
3433
"""
3534
crosses(g1) = Base.Fix2(crosses, g1)
3635

37-
function crosses(t1::GI.AbstractGeometryTrait, g1, t2, e::Extents.Extent)
38-
return crosses(t1, g1, GI.PolygonTrait(), extent_to_polygon(e))
39-
end
40-
function crosses(t1, e1::Extents.Extent, t2, g2)
41-
return crosses(GI.PolygonTrait(), extent_to_polygon(e1), t2, g2)
42-
end
43-
function crosses(t1, e1::Extents.Extent, t2, e2::Extents.Extent)
44-
return false # two extents can never cross!
45-
# TODO that's not quite true, if one extent is a line...
46-
end
47-
48-
49-
50-
51-
5236

5337

5438
function multipoint_crosses_line(geom1, geom2)

src/methods/geom_relations/disjoint.jl

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,6 @@ This is equivalent to `x -> disjoint(x, g1)`.
8383
"""
8484
disjoint(g1) = Base.Fix2(disjoint, g1)
8585

86-
# # Convert features to geometries
87-
_disjoint(::FeatureTrait, g1, ::Any, g2) = disjoint(GI.geometry(g1), g2)
88-
_disjoint(::Any, g1, ::FeatureTrait, g2) = disjoint(g1, geometry(g2))
89-
_disjoint(::FeatureTrait, g1, ::FeatureTrait, g2) = disjoint(GI.geometry(g1), GI.geometry(g2))
90-
9186
# # Point disjoint geometries
9287

9388
# Point is disjoint from another point if the points are not equal.
@@ -263,17 +258,3 @@ function _disjoint(
263258
end
264259
return true
265260
end
266-
267-
268-
# Extent forwarding
269-
function _disjoint(t1::GI.AbstractGeometryTrait, g1, t2, e::Extents.Extent)
270-
return _disjoint(t1, g1, GI.PolygonTrait(), extent_to_polygon(e))
271-
end
272-
function _disjoint(t1, e1::Extents.Extent, t2, g2)
273-
return _disjoint(GI.PolygonTrait(), extent_to_polygon(e1), t2, g2)
274-
end
275-
function _disjoint(t1, e1::Extents.Extent, t2, e2::Extents.Extent)
276-
return Extents.disjoint(e1, e2)
277-
end
278-
279-

src/methods/geom_relations/overlaps.jl

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export overlaps
44

55
#=
66
## What is overlaps?
7-
87
The overlaps function checks if two geometries overlap. Two geometries can only
98
overlap if they have the same dimension, and if they overlap, but one is not
109
contained, within, or equal to the other.
@@ -235,18 +234,6 @@ function _overlaps(
235234
return seg_val == line_over && (!a_fully_within && !b_fully_within)
236235
end
237236

238-
# Extent forwarding
239-
240-
function _overlaps(t1::GI.AbstractGeometryTrait, g1, t2, e::Extents.Extent)
241-
return _overlaps(t1, g1, GI.PolygonTrait(), extent_to_polygon(e))
242-
end
243-
function _overlaps(t1, e1::Extents.Extent, t2, g2)
244-
return _overlaps(GI.PolygonTrait(), extent_to_polygon(e1), t2, g2)
245-
end
246-
function _overlaps(t1, e1::Extents.Extent, t2, e2::Extents.Extent)
247-
return Extents.overlaps(e1, e2)
248-
end
249-
250237
#= TODO: Once overlaps is swapped over to use the geom relations workflow, can
251238
delete these helpers. =#
252239

src/methods/geom_relations/touches.jl

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,6 @@ This is equivalent to `x -> touches(x, g1)`.
8686
"""
8787
touches(g1) = Base.Fix2(touches, g1)
8888

89-
# # Convert features to geometries
90-
_touches(::GI.FeatureTrait, g1, ::Any, g2) = touches(GI.geometry(g1), g2)
91-
_touches(::Any, g1, t2::GI.FeatureTrait, g2) = touches(g1, GI.geometry(g2))
92-
_touches(::FeatureTrait, g1, ::FeatureTrait, g2) = touches(GI.geometry(g1), GI.geometry(g2))
93-
9489
# # Point touches geometries
9590

9691
# Point cannot touch another point as if they are equal, interiors interact
@@ -302,18 +297,3 @@ function _touches(
302297
end
303298
return has_touched
304299
end
305-
306-
# Extent forwarding
307-
308-
309-
function _touches(t1::GI.AbstractGeometryTrait, g1, t2, e::Extents.Extent)
310-
return _touches(t1, g1, GI.PolygonTrait(), extent_to_polygon(e))
311-
end
312-
function _touches(t1, e1::Extents.Extent, t2::GI.AbstractGeometryTrait, g2)
313-
return _touches(GI.PolygonTrait(), extent_to_polygon(e1), t2, g2)
314-
end
315-
function _touches(t1, e1::Extents.Extent, t2, e2::Extents.Extent)
316-
return Extents.touches(e1, e2)
317-
end
318-
319-

src/methods/geom_relations/within.jl

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,6 @@ This is equivalent to `x -> within(x, g1)`.
9090
"""
9191
within(g1) = Base.Fix2(within, g1)
9292

93-
# # Convert features to geometries
94-
_within(::GI.FeatureTrait, g1, ::Any, g2) = within(GI.geometry(g1), g2)
95-
_within(::Any, g1, t2::GI.FeatureTrait, g2) = within(g1, GI.geometry(g2))
96-
_within(::FeatureTrait, g1, ::FeatureTrait, g2) = within(GI.geometry(g1), GI.geometry(g2))
97-
9893

9994
# # Points within geometries
10095

@@ -286,19 +281,3 @@ function _within(
286281
end
287282
return true
288283
end
289-
290-
291-
# Extent forwarding
292-
293-
294-
function _within(t1::GI.AbstractGeometryTrait, g1, t2, e::Extents.Extent)
295-
return _within(t1, g1, GI.PolygonTrait(), extent_to_polygon(e))
296-
end
297-
function _within(t1, e1::Extents.Extent, t2, g2)
298-
return _within(GI.PolygonTrait(), extent_to_polygon(e1), t2, g2)
299-
end
300-
function _within(t1, e1::Extents.Extent, t2, e2::Extents.Extent)
301-
return Extents.within(e1, e2)
302-
end
303-
304-

src/utils/utils.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,12 @@ function extent_to_polygon(ext::Extents.Extent{(:Y, :X)})
287287
return GI.Polygon(StaticArrays.@SVector[GI.LinearRing(StaticArrays.@SVector[(x1, y1), (x2, y1), (x2, y2), (x1, y2), (x1, y1)])])
288288
end
289289

290-
291-
290+
# This will accept table rows etc
291+
# TODO can rows have metadata to detectg the geometry column name?
292+
function _geometry_or_error(g; geometrycolumn=:geometry)
293+
hasproperty(g, geometrycolumn) || throw(ArgumentError("Objects that return no geometry or feature traits must at least have property matching `geometrycolumn: `:$geometrycolumn`"))
294+
return getproperty(g, geometrycolumn)
295+
end
296+
_geometry_or_error(g::Extents.Extent; kw...) = g
292297

293298

test/methods/geom_relations.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import GeometryOps as GO
22
import GeoInterface as GI
33
import LibGEOS as LG
44
using Extents
5+
using DataFrames
56
using ..TestHelpers
67

78
# Tests of DE-9IM Methods
@@ -343,3 +344,37 @@ end
343344
@test GO.touches(p2)(p1) == GO.touches(p1, p2)
344345
@test GO.within(p2)(p1) == GO.within(p1, p2)
345346
end
347+
348+
@testset "Features, Table rows and Extents" begin
349+
feature1 = GI.Feature(pt1; properties=Dict{Symbol, Any}())
350+
feature2 = GI.Feature(pt2; properties=Dict{Symbol, Any}())
351+
352+
# Test NamedTuple
353+
named_tuple1 = (; geometry=pt1)
354+
named_tuple2 = (; geometry=pt2)
355+
@test GO.disjoint(named_tuple1, named_tuple2) == GO.disjoint(pt1, pt2)
356+
@test GO.coveredby(named_tuple1, ext1) == GO.coveredby(pt1, ext1)
357+
@test GO.within(named_tuple1, ext1) == GO.within(pt1, ext1)
358+
359+
# Test DataFrame row
360+
df = DataFrame(geometry=[pt1, pt2])
361+
df_row1 = df[1, :]
362+
df_row2 = df[2, :]
363+
@test GO.disjoint(df_row1, df_row2) == GO.disjoint(pt1, pt2)
364+
@test GO.coveredby(df_row1, ext1) == GO.coveredby(pt1, ext1)
365+
@test GO.within(df_row1, ext1) == GO.within(pt1, ext1)
366+
367+
# Test features
368+
@test GO.disjoint(feature1, feature2) == GO.disjoint(pt1, pt2)
369+
@test GO.coveredby(feature1, ext1) == GO.coveredby(pt1, ext1)
370+
@test GO.within(feature1, ext1) == GO.within(pt1, ext1)
371+
372+
# Test mixed types
373+
@test GO.disjoint(feature1, named_tuple2) == GO.disjoint(pt1, pt2)
374+
@test GO.coveredby(feature1, ext1) == GO.coveredby(pt1, ext1)
375+
@test GO.within(df_row1, ext1) == GO.within(pt1, ext1)
376+
377+
# Test extents
378+
@test GO.disjoint(ext1, ext3) == Extents.disjoint(ext1, ext3)
379+
@test GO.coveredby(ext1, ext1) == Extents.coveredby(ext1, ext1)
380+
end

0 commit comments

Comments
 (0)