Skip to content

Commit 9c1916d

Browse files
authored
fix dispatch on base types and test them (#84)
* fix dispatch on base types and test them * make NamedTuple point dispatch more specific * clean up and add more tests * bugfix tests * bugfix x/y/z/m
1 parent 9e60b1d commit 9c1916d

File tree

2 files changed

+106
-28
lines changed

2 files changed

+106
-28
lines changed

src/base.jl

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,83 @@
11
# Implementation of GeoInterface for Base Types
22

3+
4+
const PointTuple2 = Tuple{<:Real,<:Real}
5+
const PointTuple3 = Tuple{<:Real,<:Real,<:Real}
6+
const PointTuple4 = Tuple{<:Real,<:Real,<:Real,<:Real}
7+
const PointTuple = Union{PointTuple2,PointTuple3,PointTuple4}
8+
39
GeoInterface.isgeometry(::Type{<:AbstractVector{<:Real}}) = true
410
GeoInterface.geomtrait(::AbstractVector{<:Real}) = PointTrait()
511
GeoInterface.ncoord(::PointTrait, geom::AbstractVector{<:Real}) = Base.length(geom)
612
GeoInterface.getcoord(::PointTrait, geom::AbstractVector{<:Real}, i) = getindex(geom, i)
713

8-
GeoInterface.isgeometry(::Type{<:NTuple{N,<:Real}}) where {N} = true
9-
GeoInterface.geomtrait(::NTuple{N,<:Real}) where {N} = PointTrait()
10-
GeoInterface.ncoord(::PointTrait, geom::NTuple{N,<:Real}) where {N} = N
11-
GeoInterface.getcoord(::PointTrait, geom::NTuple{N,<:Real}, i) where {N} = getindex(geom, i)
12-
13-
for i in 2:4
14-
sig = NamedTuple{default_coord_names[1:i],NTuple{i,T}} where {T<:Real}
15-
GeoInterface.isgeometry(::Type{<:sig}) = true
16-
GeoInterface.geomtrait(::sig) = PointTrait()
17-
GeoInterface.ncoord(::PointTrait, geom::sig) = i
18-
GeoInterface.getcoord(::PointTrait, geom::sig, i) = getindex(geom, i)
14+
GeoInterface.isgeometry(::Type{<:PointTuple}) = true
15+
GeoInterface.geomtrait(::PointTuple) = PointTrait()
16+
GeoInterface.ncoord(::PointTrait, geom::PointTuple) = Base.length(geom)
17+
GeoInterface.getcoord(::PointTrait, geom::PointTuple, i) = getindex(geom, i)
18+
19+
for (i, pointtype) in enumerate((PointTuple2, PointTuple3, PointTuple4))
20+
keys = default_coord_names[1:i+1]
21+
sig = NamedTuple{keys,<:pointtype}
22+
@eval GeoInterface.isgeometry(::Type{<:$sig}) = true
23+
@eval GeoInterface.geomtrait(::$sig) = PointTrait()
24+
@eval GeoInterface.ncoord(::PointTrait, geom::$sig) = $i + 1
25+
@eval GeoInterface.getcoord(::PointTrait, geom::$sig, i) = getindex(geom, i)
1926
end
2027

21-
# Custom coordinate order/names NamedTuple
22-
GeoInterface.isgeometry(::Type{<:NamedTuple{Keys,NTuple{N,T}}}) where {Keys,N,T<:Real} = all(in(default_coord_names), Keys)
23-
GeoInterface.geomtrait(::NamedTuple{Keys,NTuple{N,T}}) where {Keys,N,T<:Real} = PointTrait()
24-
GeoInterface.ncoord(::PointTrait, geom::NamedTuple{Keys,NTuple{N,T}}) where {Keys,N,T<:Real} = Base.length(geom)
25-
GeoInterface.getcoord(::PointTrait, geom::NamedTuple{Keys,NTuple{N,T}}, i) where {Keys,N,T<:Real} = getindex(geom, i)
26-
GeoInterface.coordnames(::PointTrait, geom::NamedTuple{Keys,NTuple{N,T}}) where {Keys,N,T<:Real} = Keys
28+
29+
# Define all possible NamedTuple points
30+
const NamedTuplePoint = Union{
31+
NamedTuple{(:X, :Y),<:PointTuple2},
32+
NamedTuple{(:Y, :X),<:PointTuple2},
33+
NamedTuple{(:X, :Y, :Z),<:PointTuple3},
34+
NamedTuple{(:X, :Z, :Y),<:PointTuple3},
35+
NamedTuple{(:Z, :Y, :X),<:PointTuple3},
36+
NamedTuple{(:Z, :X, :Y),<:PointTuple3},
37+
NamedTuple{(:Y, :X, :Z),<:PointTuple3},
38+
NamedTuple{(:Y, :Z, :X),<:PointTuple3},
39+
NamedTuple{(:X, :Y, :M),<:PointTuple3},
40+
NamedTuple{(:X, :M, :Y),<:PointTuple3},
41+
NamedTuple{(:M, :Y, :X),<:PointTuple3},
42+
NamedTuple{(:M, :X, :Y),<:PointTuple3},
43+
NamedTuple{(:Y, :X, :Z),<:PointTuple3},
44+
NamedTuple{(:Y, :Z, :X),<:PointTuple3},
45+
NamedTuple{(:X, :Y, :Z, :M),<:PointTuple4},
46+
NamedTuple{(:X, :Y, :M, :Z),<:PointTuple4},
47+
NamedTuple{(:X, :Z, :Y, :M),<:PointTuple4},
48+
NamedTuple{(:X, :Z, :M, :Y),<:PointTuple4},
49+
NamedTuple{(:X, :M, :Z, :Y),<:PointTuple4},
50+
NamedTuple{(:X, :M, :Y, :Z),<:PointTuple4},
51+
NamedTuple{(:Y, :X, :Z, :M),<:PointTuple4},
52+
NamedTuple{(:Y, :X, :M, :Z),<:PointTuple4},
53+
NamedTuple{(:Y, :Z, :X, :M),<:PointTuple4},
54+
NamedTuple{(:Y, :Z, :M, :X),<:PointTuple4},
55+
NamedTuple{(:Y, :M, :Z, :X),<:PointTuple4},
56+
NamedTuple{(:Y, :M, :X, :Z),<:PointTuple4},
57+
NamedTuple{(:Z, :Y, :X, :M),<:PointTuple4},
58+
NamedTuple{(:Z, :Y, :M, :X),<:PointTuple4},
59+
NamedTuple{(:Z, :X, :Y, :M),<:PointTuple4},
60+
NamedTuple{(:Z, :X, :M, :Y),<:PointTuple4},
61+
NamedTuple{(:Z, :M, :X, :Y),<:PointTuple4},
62+
NamedTuple{(:Z, :M, :Y, :X),<:PointTuple4},
63+
NamedTuple{(:M, :Y, :Z, :X),<:PointTuple4},
64+
NamedTuple{(:M, :Y, :X, :Z),<:PointTuple4},
65+
NamedTuple{(:M, :Z, :Y, :X),<:PointTuple4},
66+
NamedTuple{(:M, :Z, :X, :Y),<:PointTuple4},
67+
NamedTuple{(:M, :X, :Z, :Y),<:PointTuple4},
68+
NamedTuple{(:M, :X, :Y, :Z),<:PointTuple4},
69+
}
70+
71+
_keys(::Type{<:NamedTuple{K}}) where K = K
72+
GeoInterface.isgeometry(::Type{T}) where {T<:NamedTuplePoint} = all(in(default_coord_names), _keys(T))
73+
GeoInterface.geomtrait(::NamedTuplePoint) = PointTrait()
74+
GeoInterface.ncoord(::PointTrait, geom::NamedTuplePoint) = Base.length(geom)
75+
GeoInterface.getcoord(::PointTrait, geom::NamedTuplePoint, i) = getindex(geom, i)
76+
GeoInterface.coordnames(::PointTrait, geom::NamedTuplePoint) = _keys(typeof(geom))
77+
GeoInterface.x(::PointTrait, geom::NamedTuplePoint) = geom.X
78+
GeoInterface.y(::PointTrait, geom::NamedTuplePoint) = geom.Y
79+
GeoInterface.z(::PointTrait, geom::NamedTuplePoint) = geom.Z
80+
GeoInterface.m(::PointTrait, geom::NamedTuplePoint) = geom.M
2781

2882

2983
# Default features using NamedTuple and AbstractArray
@@ -33,7 +87,7 @@ _is_namedtuple_feature(::Type{<:NamedTuple{K}}) where K = :geometry in K
3387
_is_namedtuple_feature(nt::NamedTuple) = _is_namedtuple_feature(typeof(nt))
3488

3589
GeoInterface.isfeature(T::Type{<:NamedTuple}) = _is_namedtuple_feature(T)
36-
GeoInterface.trait(nt::NamedTuple) = _is_namedtuple_feature(nt) ? FeatureTrait() : nothing
90+
GeoInterface.trait(nt::NamedTuple) = _is_namedtuple_feature(nt) ? FeatureTrait() : geomtrait(nt)
3791
GeoInterface.geometry(nt::NamedTuple) = _is_namedtuple_feature(nt) ? nt.geometry : nothing
3892
GeoInterface.properties(nt::NamedTuple) = _is_namedtuple_feature(nt) ? _nt_properties(nt) : nothing
3993

@@ -51,7 +105,7 @@ _is_array_featurecollection(::Type{<:AbstractArray{T}}) where {T<:NamedTuple} =
51105
_is_array_featurecollection(A::AbstractArray{<:NamedTuple}) = _is_array_featurecollection(typeof(A))
52106

53107
GeoInterface.isfeaturecollection(T::Type{<:MaybeArrayFeatureCollection}) = _is_array_featurecollection(T)
54-
GeoInterface.trait(fc::MaybeArrayFeatureCollection) = _is_array_featurecollection(fc) ? FeatureCollectionTrait() : nothing
108+
GeoInterface.trait(fc::MaybeArrayFeatureCollection) = _is_array_featurecollection(fc) ? FeatureCollectionTrait() : geomtrait(fc)
55109
GeoInterface.nfeature(::FeatureCollectionTrait, fc::MaybeArrayFeatureCollection) = _is_array_featurecollection(fc) ? Base.length(fc) : nothing
56110
GeoInterface.getfeature(::FeatureCollectionTrait, fc::MaybeArrayFeatureCollection, i::Integer) = _is_array_featurecollection(fc) ? fc[i] : nothing
57111
GeoInterface.geometrycolumns(fc::MaybeArrayFeatureCollection) = _is_array_featurecollection(fc) ? (:geometry,) : nothing

test/test_primitives.jl

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -316,31 +316,55 @@ end
316316
end
317317

318318
@testset "Tuple" begin
319-
geom = (1, 2)
319+
geom = (1, 2.0f0)
320+
@test GeoInterface.trait(geom) isa PointTrait
321+
@test GeoInterface.geomtrait(geom) isa PointTrait
320322
@test testgeometry(geom)
321323
@test GeoInterface.x(geom) == 1
324+
@test GeoInterface.y(geom) == 2.0f0
322325
@test GeoInterface.ncoord(geom) == 2
323326
@test collect(GeoInterface.getcoord(geom)) == [1, 2]
324327
end
325328

326329
@testset "NamedTuple" begin
327-
geom = (; X=1, Y=2)
330+
geom = (; X=1, Y=2.0)
331+
@test GeoInterface.is3d(geom) == false
332+
@test GeoInterface.ismeasured(geom) == false
333+
@test GeoInterface.trait(geom) isa PointTrait
334+
@test GeoInterface.geomtrait(geom) isa PointTrait
328335
@test testgeometry(geom)
329336
@test GeoInterface.x(geom) == 1
337+
@test GeoInterface.y(geom) == 2.0
330338
@test collect(GeoInterface.getcoord(geom)) == [1, 2]
331339

332-
geom = (; X=1, Y=2, Z=3)
340+
geom = (; X=1, Y=2, Z=3.0f0, M=4.0)
341+
@test GeoInterface.trait(geom) isa PointTrait
342+
@test GeoInterface.geomtrait(geom) isa PointTrait
343+
@test GeoInterface.is3d(geom)
344+
@test GeoInterface.ismeasured(geom)
345+
@test GeoInterface.coordnames(geom) == (:X, :Y, :Z, :M)
346+
@test GeoInterface.ncoord(geom) == 4
333347
@test testgeometry(geom)
334-
geom = (; X=1, Y=2, Z=3, M=4)
348+
@test GeoInterface.x(geom) === 1
349+
@test GeoInterface.y(geom) === 2
350+
@test GeoInterface.z(geom) === 3.0f0
351+
@test GeoInterface.m(geom) === 4.0
352+
@test GeoInterface.ncoord(geom) == 4
353+
@test GeoInterface.getcoord(geom, 1) === 1
354+
@test GeoInterface.getcoord(geom, 2) === 2
355+
@test GeoInterface.getcoord(geom, 3) === 3.0f0
356+
@test GeoInterface.getcoord(geom, 4) === 4.0
357+
@test collect(GeoInterface.getcoord(geom)) == [1, 2, 3, 4]
358+
359+
geom = (; X=1.0, Y=2.0, Z=0x03)
335360
@test testgeometry(geom)
361+
@test GeoInterface.is3d(geom)
362+
@test GeoInterface.ismeasured(geom) == false
363+
@test GeoInterface.coordnames(geom) == (:X, :Y, :Z)
336364
geom = (; Z=3, X=1, Y=2, M=4)
337365
@test testgeometry(geom)
338-
339-
@test GeoInterface.x(geom) == 1
340-
@test GeoInterface.m(geom) == 4
341-
@test GeoInterface.ncoord(geom) == 4
342366
@test collect(GeoInterface.getcoord(geom)) == [3, 1, 2, 4]
343-
367+
@test GeoInterface.coordnames(geom) == (:Z, :X, :Y, :M)
344368
end
345369

346370
@testset "NamedTupleFeature" begin

0 commit comments

Comments
 (0)