Skip to content

Commit c1b4cf0

Browse files
evetionvisr
andauthored
Give geometry type hints in Schema. (#160)
* Give geometry type hints in Schema. * Also change IGeometry type. * Also converted geometry. Optimized getgeomtype call. Added several tests. * Merged master and fixed display test. * geometry first, fields second Co-authored-by: Martijn Visser <[email protected]>
1 parent 14b92da commit c1b4cf0

File tree

6 files changed

+37
-21
lines changed

6 files changed

+37
-21
lines changed

src/ogr/geometry.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ end
298298
299299
Fetch geometry type code
300300
"""
301-
getgeomtype(geom::AbstractGeometry) = GDAL.ogr_g_getgeometrytype(geom.ptr)
301+
getgeomtype(geom::AbstractGeometry) = _geomtype(geom)
302302

303303
"""
304304
geomname(geom::AbstractGeometry)

src/tables.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ getlayer(t::Table) = Base.getfield(t, :layer)
1313
function Tables.schema(layer::AbstractFeatureLayer)
1414
field_names, geom_names, featuredefn, fielddefns = schema_names(layer)
1515
ngeom = ArchGDAL.ngeom(featuredefn)
16-
geomdefns = (ArchGDAL.getgeomdefn(featuredefn, i) for i in 0:ngeom-1)
16+
geomtypes = (IGeometry{ArchGDAL.gettype(ArchGDAL.getgeomdefn(featuredefn, i))} for i in 0:ngeom-1)
1717
field_types = (_FIELDTYPE[gettype(fielddefn)] for fielddefn in fielddefns)
18-
geom_types = (IGeometry for i in 1:ngeom)
19-
Tables.Schema((field_names..., geom_names...), (field_types..., geom_types...))
18+
Tables.Schema((geom_names..., field_names...), (geomtypes..., field_types...))
2019
end
2120

2221
Tables.istable(::Type{<:Table}) = true
@@ -34,7 +33,7 @@ end
3433

3534
function Base.getindex(t::Table, idx::Integer)
3635
layer = getlayer(t)
37-
setnextbyindex!(layer, idx-1)
36+
setnextbyindex!(layer, idx-1)
3837
return nextnamedtuple(layer)
3938
end
4039

@@ -55,15 +54,16 @@ function nextnamedtuple(layer::IFeatureLayer)
5554
return nextfeature(layer) do feature
5655
prop = (getfield(feature, name) for name in field_names)
5756
geom = (getgeom(feature, idx-1) for idx in 1:length(geom_names))
58-
NamedTuple{(field_names..., geom_names...)}((prop..., geom...))
57+
NamedTuple{(geom_names..., field_names...)}((geom..., prop...))
5958
end
6059
end
6160

6261
function schema_names(layer::AbstractFeatureLayer)
6362
featuredefn = layerdefn(layer)
6463
fielddefns = (getfielddefn(featuredefn, i) for i in 0:nfield(layer)-1)
6564
field_names = (Symbol(getname(fielddefn)) for fielddefn in fielddefns)
66-
geom_names = (Symbol(getname(getgeomdefn(featuredefn, i-1))) for i in 1:ngeom(layer))
65+
geom_names = collect(Symbol(getname(getgeomdefn(featuredefn, i-1))) for i in 1:ngeom(layer))
66+
replace!(geom_names, Symbol("")=>Symbol("geometry"), count=1)
6767
return (field_names, geom_names, featuredefn, fielddefns)
6868
end
6969

src/types.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,21 +205,23 @@ mutable struct ISpatialRef <: AbstractSpatialRef
205205
end
206206
end
207207

208-
mutable struct Geometry <: AbstractGeometry
208+
mutable struct Geometry{OGRwkbGeometryType} <: AbstractGeometry
209209
ptr::GDALGeometry
210210

211-
Geometry(ptr::GDALGeometry = C_NULL) = new(ptr)
211+
Geometry(ptr::GDALGeometry = C_NULL) = new{ptr != C_NULL ? GDAL.ogr_g_getgeometrytype(ptr) : GDAL.wkbUnknown}(ptr)
212212
end
213+
_geomtype(::Geometry{T}) where T = T
213214

214-
mutable struct IGeometry <: AbstractGeometry
215+
mutable struct IGeometry{OGRwkbGeometryType} <: AbstractGeometry
215216
ptr::GDALGeometry
216217

217218
function IGeometry(ptr::GDALGeometry = C_NULL)
218-
geom = new(ptr)
219+
geom = new{ptr != C_NULL ? GDAL.ogr_g_getgeometrytype(ptr) : GDAL.wkbUnknown}(ptr)
219220
finalizer(destroy, geom)
220221
return geom
221222
end
222223
end
224+
_geomtype(::IGeometry{T}) where T = T
223225

224226
mutable struct ColorTable
225227
ptr::GDALColorTable

test/test_display.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import ArchGDAL; const AG = ArchGDAL
2020
Field 1 (pointname): [OFTString], point-a, point-b, a, b
2121
"""
2222
@test sprint(print, AG.nextnamedtuple(layer), context=:compact => true) ==
23-
"(FID = 2.0, pointname = \"point-a\", = Geometry: wkbPoint)"
23+
"(geometry = Geometry: wkbPoint, FID = 2.0, pointname = \"point-a\")"
2424
@test sprint(print, AG.layerdefn(layer)) == """
2525
Geometry (index 0): (wkbPoint)
2626
Field (index 0): FID (OFTReal)

test/test_geometry.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ end
2626
@test AG.issimple(point) == true
2727
@test AG.isring(point) == false
2828
@test AG.getz(point, 0) == 0
29+
@test typeof(point) == AG.Geometry{GDAL.wkbPoint}
2930

3031
@test sprint(print, AG.envelope(point)) == "GDAL.OGREnvelope(100.0, 100.0, 70.0, 70.0)"
3132
@test sprint(print, AG.envelope3d(point)) == "GDAL.OGREnvelope3D(100.0, 100.0, 70.0, 70.0, 0.0, 0.0)"
@@ -107,7 +108,8 @@ end
107108
@test AG.toWKT(geom) == "LINESTRING (1 4,2 5,3 6)"
108109
AG.setpoint!(geom, 1, 10, 10)
109110
@test AG.toWKT(geom) == "LINESTRING (1 4,10 10,3 6)"
110-
@test GFT.val(convert(GFT.WellKnownText, geom)) == AG.toWKT(geom)
111+
@test GFT.val(convert(GFT.WellKnownText, geom)) == AG.toWKT(geom)
112+
@test typeof(geom) == AG.Geometry{GDAL.wkbLineString}
111113
end
112114
AG.createlinestring([1.,2.,3.], [4.,5.,6.], [7.,8.,9.]) do geom
113115
@test AG.toWKT(geom) == "LINESTRING (1 4 7,2 5 8,3 6 9)"
@@ -116,7 +118,7 @@ end
116118
AG.addpoint!(geom, 11, 11, 11)
117119
@test AG.toWKT(geom) == "LINESTRING (1 4 7,10 10 10,3 6 9,11 11 11)"
118120
end
119-
121+
120122
@test AG.toWKT(AG.createlinearring([1.,2.,3.], [4.,5.,6.])) == "LINEARRING (1 4,2 5,3 6)"
121123
AG.createlinearring([1.,2.,3.], [4.,5.,6.]) do geom
122124
# @test GeoInterface.geotype(geom) == :LinearRing
@@ -126,6 +128,7 @@ end
126128
@test AG.toWKT(geom) == "LINEARRING (1 4,2 5,3 6,0 0,0 0)"
127129
AG.empty!(geom)
128130
@test AG.toWKT(geom) == "LINEARRING EMPTY"
131+
@test typeof(geom) == AG.Geometry{GDAL.wkbLineString} # this seems odd
129132
end
130133
AG.createlinearring([1.,2.,3.], [4.,5.,6.], [7.,8.,9.]) do geom
131134
@test AG.toWKT(geom) == "LINEARRING (1 4 7,2 5 8,3 6 9)"
@@ -138,6 +141,7 @@ end
138141
@test GeoInterface.geotype(geom) == :Polygon
139142
@test isapprox(GeoInterface.coordinates(geom), [[[1,4],[2,5],[3,6]]], atol=1e-6)
140143
@test AG.toWKT(geom) == "POLYGON ((1 4,2 5,3 6))"
144+
@test typeof(geom) == AG.Geometry{GDAL.wkbPolygon}
141145
end
142146
AG.createpolygon([1.,2.,3.], [4.,5.,6.], [7.,8.,9.]) do geom
143147
@test AG.toWKT(geom) == "POLYGON ((1 4 7,2 5 8,3 6 9))"
@@ -150,6 +154,7 @@ end
150154
@test GeoInterface.geotype(geom) == :MultiPoint
151155
@test isapprox(GeoInterface.coordinates(geom), [[1,4],[2,5],[3,6]], atol=1e-6)
152156
@test AG.toWKT(geom) == "MULTIPOINT (1 4,2 5,3 6)"
157+
@test typeof(geom) == AG.Geometry{GDAL.wkbMultiPoint}
153158
end
154159
AG.createmultipoint([1.,2.,3.], [4.,5.,6.], [7.,8.,9.]) do geom
155160
@test AG.toWKT(geom) == "MULTIPOINT (1 4 7,2 5 8,3 6 9)"
@@ -179,18 +184,24 @@ end
179184
atol=1e-6
180185
)
181186
@test AG.toWKT(geom) == "MULTIPOLYGON (((0 0,0 4,4 4,4 0),(1 1,1 3,3 3,3 1)),((10 0,10 4,14 4,14 0),(11 1,11 3,13 3,13 1)))"
187+
@test typeof(geom) == AG.Geometry{GDAL.wkbMultiPolygon}
182188
end
183189

184190
AG.fromWKT("CURVEPOLYGON(CIRCULARSTRING(-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0),(-1 0,0 0.5,1 0,0 1,-1 0))") do geom
191+
@test typeof(geom) == AG.Geometry{GDAL.wkbCurvePolygon}
185192
@test AG.toWKT(AG.curvegeom(AG.lineargeom(geom, 0.5))) == "CURVEPOLYGON (CIRCULARSTRING (-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0),(-1 0,0.0 0.5,1 0,0 1,-1 0))"
186193
AG.lineargeom(geom, 0.5) do lgeom
194+
@test typeof(lgeom) == AG.Geometry{GDAL.wkbPolygon}
187195
AG.curvegeom(lgeom) do clgeom
188196
@test AG.toWKT(clgeom) == "CURVEPOLYGON (CIRCULARSTRING (-2 0,-1 -1,0 0,1 -1,2 0,0 2,-2 0),(-1 0,0.0 0.5,1 0,0 1,-1 0))"
197+
@test typeof(clgeom) == AG.Geometry{GDAL.wkbCurvePolygon}
189198
end
190199
@test AG.ngeom(AG.polygonize(AG.forceto(lgeom, GDAL.wkbMultiLineString))) == 2
191200
AG.forceto(lgeom, GDAL.wkbMultiLineString) do mlsgeom
201+
@test typeof(mlsgeom) == AG.Geometry{GDAL.wkbMultiLineString}
192202
AG.polygonize(mlsgeom) do plgeom
193203
@test AG.ngeom(plgeom) == 2
204+
@test typeof(plgeom) == AG.Geometry{GDAL.wkbGeometryCollection}
194205
end
195206
end
196207
end
@@ -232,6 +243,7 @@ end
232243
@test AG.toWKT(result) == "MULTIPOLYGON (((0 4 8,4 4 8,4 0 8,0 0 8,0 4 8),(3 1 8,3 3 8,1 3 8,1 1 8,3 1 8)),((10 4 8,14 4 8,14 0 8,10 0 8,10 4 8),(13 1 8,13 3 8,11 3 8,11 1 8,13 1 8)))"
233244
AG.segmentize!(result, 2)
234245
@test AG.toWKT(result) == "MULTIPOLYGON (((0 4 8,2 4 8,4 4 8,4 2 8,4 0 8,2 0 8,0 0 8,0 2 8,0 4 8),(3 1 8,3 3 8,1 3 8,1 1 8,3 1 8)),((10 4 8,12 4 8,14 4 8,14 2 8,14 0 8,12 0 8,10 0 8,10 2 8,10 4 8),(13 1 8,13 3 8,11 3 8,11 1 8,13 1 8)))"
246+
@test typeof(result) == AG.Geometry{GDAL.wkbMultiPolygon25D}
235247
end
236248

237249
@test AG.toWKT(AG.symdifference(geom1, geom2)) == "GEOMETRYCOLLECTION (POLYGON ((0 4 8,4 4 8,4 0 8,0 0 8,0 4 8),(3 1 8,3 3 8,1 3 8,1 1 8,3 1 8)),POLYGON ((10 4 8,14 4 8,14 0 8,10 0 8,10 4 8),(13 1 8,13 3 8,11 3 8,11 1 8,13 1 8)),POINT (2 5 8),POINT (3 6 9))"
@@ -242,12 +254,14 @@ end
242254
@test AG.toWKT(result) == "GEOMETRYCOLLECTION (POLYGON ((0 4 8,4 4 8,4 0 8,0 0 8,0 4 8),(3 1 8,3 3 8,1 3 8,1 1 8,3 1 8)),POINT (2 5 8),POINT (3 6 9))"
243255
AG.removeallgeoms!(result)
244256
@test AG.toWKT(result) == "GEOMETRYCOLLECTION EMPTY"
257+
@test typeof(result) == AG.Geometry{GDAL.wkbGeometryCollection25D}
245258
end
246259

247260
geom3 = AG.fromWKT("GEOMETRYCOLLECTION (POINT (2 5 8),POLYGON ((0 0 8,0 4 8,4 4 8,4 0 8,0 0 8),(1 1 8,3 1 8,3 3 8,1 3 8,1 1 8)),POLYGON ((10 0 8,10 4 8,14 4 8,14 0 8,10 0 8),(11 1 8,13 1 8,13 3 8,11 3 8,11 1 8)), POINT EMPTY)")
248261
AG.clone(geom3) do geom4
249262
@test sprint(print, AG.clone(geom3)) == "Geometry: GEOMETRYCOLLECTION (POINT (2 5 8),POLYGON ((0 0 8, ... MPTY)"
250263
@test sprint(print, AG.clone(geom4)) == "Geometry: GEOMETRYCOLLECTION (POINT (2 5 8),POLYGON ((0 0 8, ... MPTY)"
264+
@test typeof(geom4) == AG.Geometry{GDAL.wkbGeometryCollection25D}
251265
end
252266
AG.clone(AG.getgeom(geom3, 3)) do geom4
253267
@test sprint(print, geom4) == "Geometry: POINT EMPTY"

test/test_tables.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ using Tables
4444
@test Base.length(gt2) == 9
4545
@test Base.IteratorSize(typeof(gt)) == Base.HasLength()
4646
@test Base.IteratorEltype(typeof(gt1)) == Base.HasEltype()
47-
@test propertynames(gt) == (:FID, :pointname, Symbol(""))
48-
@test propertynames(gt1) == (:id, :zoom, :location, :point, :linestring)
49-
@test propertynames(gt2) == (:id, :zoom, :location, :point, :linestring)
47+
@test propertynames(gt) == (:geometry, :FID, :pointname)
48+
@test propertynames(gt1) == (:point, :linestring, :id, :zoom, :location)
49+
@test propertynames(gt2) == (:point, :linestring, :id, :zoom, :location)
5050
@test getproperty(gt, :FID) == [iterate(gt, i)[1].FID for i in 0:size(gt)-1]
5151
@test getproperty(gt1, :zoom) == [iterate(gt1, i)[1].zoom for i in 0:size(gt1)-1]
5252
@test sprint(print, gt2[5].linestring) == sprint(print, gt2[3].point)
@@ -59,10 +59,10 @@ using Tables
5959

6060
AG.resetreading!(layer)
6161
AG.resetreading!(layer1)
62-
63-
@test AG.nextnamedtuple(layer) isa NamedTuple{(:FID, :pointname, Symbol("")),Tuple{Float64,String,ArchGDAL.IGeometry}}
64-
@test AG.nextnamedtuple(layer1) isa NamedTuple{(:id, :zoom, :location, :point, :linestring),Tuple{String,String,String,ArchGDAL.IGeometry,ArchGDAL.IGeometry}}
65-
for i in 1:4
62+
63+
@test AG.nextnamedtuple(layer) isa NamedTuple{(:geometry, :FID, :pointname),Tuple{ArchGDAL.IGeometry{AG.GDAL.wkbPoint},Float64,String}}
64+
@test AG.nextnamedtuple(layer1) isa NamedTuple{(:point, :linestring, :id, :zoom, :location),Tuple{ArchGDAL.IGeometry{AG.GDAL.wkbPoint},ArchGDAL.IGeometry{AG.GDAL.wkbLineString},String,String,String}}
65+
for i in (1,3,4)
6666
@test AG.schema_names(layer)[i] isa Base.Generator || AG.schema_names(layer)[i] isa ArchGDAL.IFeatureDefnView
6767
@test AG.schema_names(layer1)[i] isa Base.Generator || AG.schema_names(layer1)[i] isa ArchGDAL.IFeatureDefnView
6868
end

0 commit comments

Comments
 (0)