Skip to content

Commit 222292b

Browse files
committed
Add MutliDatasets
1 parent 9ddb084 commit 222292b

File tree

1 file changed

+156
-17
lines changed

1 file changed

+156
-17
lines changed

ext/ArchGDALExt/archgdaldataset.jl

Lines changed: 156 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Base: ==
2+
import DataStructures: OrderedDict
13
struct GDALBand{T} <: AG.DiskArrays.AbstractDiskArray{T,2}
24
filename::String
35
band::Int
@@ -39,6 +41,7 @@ function DiskArrays.readblock!(b::GDALBand, aout, r::AbstractUnitRange...)
3941
aout .= aout2
4042
end
4143

44+
4245
struct GDALDataset
4346
filename::String
4447
bandsize::Tuple{Int,Int}
@@ -48,25 +51,31 @@ struct GDALDataset
4851
end
4952

5053
function GDALDataset(filename; mode="r")
51-
AG.read(filename) do r
52-
nb = AG.nraster(r)
53-
allbands = map(1:nb) do iband
54-
b = AG.getband(r, iband)
55-
gb = GDALBand(b, filename, iband)
56-
name = AG.GDAL.gdalgetdescription(b.ptr)
57-
if isempty(name)
58-
name = AG.getname(AG.getcolorinterp(b))
54+
nb = AG.read(filename) do r
55+
AG.nraster(r)
56+
end
57+
if nb == 0
58+
return GDALMultiDataset(filename)
59+
else
60+
AG.read(filename) do r
61+
allbands = map(1:nb) do iband
62+
b = AG.getband(r, iband)
63+
gb = GDALBand(b, filename, iband)
64+
name = AG.GDAL.gdalgetdescription(b.ptr)
65+
if isempty(name)
66+
name = AG.getname(AG.getcolorinterp(b))
67+
end
68+
name => gb
5969
end
60-
name => gb
61-
end
62-
proj = AG.getproj(r)
63-
trans = AG.getgeotransform(r)
64-
s = AG._common_size(r)
65-
allnames = first.(allbands)
66-
if !allunique(allnames)
67-
allbands = ["Band$i"=>last(v) for (i,v) in enumerate(allbands)]
70+
proj = AG.getproj(r)
71+
trans = AG.getgeotransform(r)
72+
s = AG._common_size(r)
73+
allnames = first.(allbands)
74+
if !allunique(allnames)
75+
allbands = ["Band$i"=>last(v) for (i,v) in enumerate(allbands)]
76+
end
77+
GDALDataset(filename, s[1:end-1], proj, trans, OrderedDict(allbands))
6878
end
69-
GDALDataset(filename, s[1:end-1], proj, trans, OrderedDict(allbands))
7079
end
7180
end
7281
Base.haskey(ds::GDALDataset, k) = in(k, ("X", "Y")) || haskey(ds.bands, k)
@@ -235,6 +244,136 @@ allow_parallel_write(::GDALDataset) = false
235244
allow_missings(::Type{<:GDALDataset}) = false
236245
allow_missings(::GDALDataset) = false
237246

247+
#MultiDataset implementation
248+
struct GDALBandInfo
249+
bandsize::Tuple{Int,Int}
250+
projection::Union{String, AG.AbstractSpatialRef}
251+
trans::Vector{Float64}
252+
end
253+
==(a::GDALBandInfo,b::GDALBandInfo) = a.bandsize == b.bandsize &&
254+
a.projection == b.projection &&
255+
a.trans == b.trans
256+
struct GDALMultiDataset
257+
bandinfo::Vector{GDALBandInfo}
258+
bands::OrderedDict{String,Tuple{String,GDALBand,Int}}
259+
end
260+
function getbandinfo(gds::GDALMultiDataset, k)
261+
if k in keys(gds.bands)
262+
i = gds.bands[k][3]
263+
bandext = length(gds.bandinfo) == 1 ? "" : "_$i"
264+
gds.bandinfo[i],"X$bandext","Y$bandext"
265+
else
266+
nspl = split(k,'_')
267+
i = if length(nspl)==1
268+
1
269+
else
270+
parse(Int,nspl[2])
271+
end
272+
if startswith(k,"X")
273+
gds.bandinfo[i],k,replace(k,'X'=>'Y')
274+
elseif startswith(k,"Y")
275+
gds.bandinfo[i],replace(k,'Y'=>'X'),k
276+
else
277+
error()
278+
end
279+
end
280+
end
281+
282+
function GDALMultiDataset(filename)
283+
subdatasets = OrderedDict{String, String}()
284+
AG.read(filename) do ds
285+
subds = AG.metadata(ds; domain="SUBDATASETS")
286+
for dsstring in subds
287+
k,v = split(dsstring,'=')
288+
if endswith(k,"_NAME")
289+
k2 = last(split(v,':'))
290+
subdatasets[k2] = v
291+
end
292+
end
293+
end
294+
bandinfos = GDALBandInfo[]
295+
allbands = OrderedDict{String,Tuple{String,GDALBand,Int}}()
296+
for (k,v) in subdatasets
297+
AG.read(v) do ds
298+
s = AG._common_size(ds)
299+
bandinfo = GDALBandInfo((s[1],s[2]), AG.getproj(ds), AG.getgeotransform(ds))
300+
i = findfirst(==(bandinfo),bandinfos)
301+
if isnothing(i)
302+
push!(bandinfos,bandinfo)
303+
i = length(bandinfos)
304+
end
305+
nr = AG.nraster(ds)
306+
for iband in 1:nr
307+
b = AG.getband(ds, iband)
308+
gb = GDALBand(b, v, iband)
309+
if nr == 1
310+
allbands[k] = (v,gb,iband)
311+
else
312+
allbands[(string(k,"_",iband))] = (v,gb,i)
313+
end
314+
end
315+
end
316+
end
317+
GDALMultiDataset(bandinfos, allbands)
318+
end
319+
320+
function xyname(ds::GDALMultiDataset,k)
321+
if k in keys(ds.bands)
322+
i = ds.bands[k][3]
323+
bandext = length(ds.bandinfo) == 1 ? "" : "_$i"
324+
"X$bandext","Y$bandext"
325+
else
326+
if startswith(k,"X")
327+
k,replace(k,'X'=>'Y')
328+
elseif startswith(k,"Y")
329+
replace(k,'Y'=>'X'),k
330+
else
331+
error()
332+
end
333+
end
334+
end
335+
function Base.haskey(ds::GDALMultiDataset, k)
336+
x,y = xyname(ds,k)
337+
in(k, (x,y)) || haskey(ds.bands, k)
338+
end
339+
#Implement Dataset interface
340+
function YAB.get_var_handle(ds::GDALMultiDataset, name; persist=true)
341+
bandinfo,x,y = getbandinfo(ds,name)
342+
if name == x
343+
range(bandinfo.trans[1], length = bandinfo.bandsize[1], step = bandinfo.trans[2])
344+
elseif name == y
345+
range(bandinfo.trans[4], length = bandinfo.bandsize[2], step = bandinfo.trans[6])
346+
else
347+
ds.bands[name][2]
348+
end
349+
end
350+
351+
352+
YAB.get_varnames(ds::GDALMultiDataset) = collect(keys(ds.bands))
353+
354+
function YAB.get_var_dims(ds::GDALMultiDataset, d)
355+
x,y = xyname(ds,d)
356+
if d == x
357+
return (x,)
358+
elseif d == y
359+
return (y,)
360+
else
361+
return (x, y)
362+
end
363+
end
364+
365+
YAB.get_global_attrs(ds::GDALMultiDataset) = Dict()
366+
367+
function YAB.get_var_attrs(ds::GDALMultiDataset, name)
368+
_,x,y = getbandinfo(ds,name)
369+
if name in (x,y)
370+
Dict{String,Any}()
371+
else
372+
ds.bands[name][2].attrs
373+
end
374+
end
375+
376+
238377
function __init__()
239378
@info "new driver key :gdal, updating backendlist."
240379
YAB.backendlist[:gdal] = GDALDataset

0 commit comments

Comments
 (0)