1+ import Base: ==
2+ import DataStructures: OrderedDict
13struct 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
4042end
4143
44+
4245struct GDALDataset
4346 filename:: String
4447 bandsize:: Tuple{Int,Int}
@@ -48,25 +51,31 @@ struct GDALDataset
4851end
4952
5053function 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
7180end
7281Base. haskey (ds:: GDALDataset , k) = in (k, (" X" , " Y" )) || haskey (ds. bands, k)
@@ -235,6 +244,136 @@ allow_parallel_write(::GDALDataset) = false
235244allow_missings (:: Type{<:GDALDataset} ) = false
236245allow_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+
238377function __init__ ()
239378 @info " new driver key :gdal, updating backendlist."
240379 YAB. backendlist[:gdal ] = GDALDataset
0 commit comments