1
1
"""
2
- resample(x, resolution::Number; crs, method)
3
- resample(x; to, method)
4
- resample(xs...; to=first(xs), method)
2
+ resample(x; to, size, res, method)
3
+ resample(xs...; to=first(xs), size, res, method)
5
4
6
5
`resample` uses `ArchGDAL.gdalwarp` to resample a [`Raster`](@ref) or
7
6
[`RasterStack`](@ref) to a new `resolution` and optionally new `crs`,
8
7
or to snap to the bounds, resolution and crs of the object `to`.
9
8
10
9
# Arguments
11
10
12
- - `x`: the object to resample.
13
- - `resolution`: a `Number` specifying the resolution for the output.
14
- If the keyword argument `crs` (described below) is specified, `resolution` must be in units of the `crs`.
11
+ - `x`: the object/s to resample.
15
12
16
13
# Keywords
17
14
18
- - `to`: an `AbstractRaster` whose resolution, crs and bounds will be snapped to.
19
- For best results it should roughly cover the same extent, or be a subset of `A`.
20
- - `crs`: A `GeoFormatTypes.GeoFormat` such as `EPSG(x)` or `WellKnownText(string)` specifying an
21
- output crs (`A` will be reprojected to `crs` in addition to being resampled). Defaults to `crs(A)`
15
+ - `to`: a `Raster`, `RasterStack`, `Tuple` of `Dimension` or `Extents.Extent`.
16
+ If no `to` object is provided the extent will be calculated from `x`,
17
+ $RES_KEYWORD
18
+ $SIZE_KEYWORD
19
+ - `crs`: A `GeoFormatTypes.GeoFormat` coordinate reference system for the output raster,
20
+ such as `EPSG(x)` or `WellKnownText(string)`. Defaults to `crs(A)`.
22
21
- `method`: A `Symbol` or `String` specifying the method to use for resampling.
23
22
From the docs for [`gdalwarp`](https://gdal.org/programs/gdalwarp.html#cmdoption-gdalwarp-r):
24
23
* `:near`: nearest neighbour resampling (default, fastest algorithm, worst interpolation quality).
@@ -38,12 +37,9 @@ or to snap to the bounds, resolution and crs of the object `to`.
38
37
39
38
Where NODATA values are set to `missingval`.
40
39
41
- Notes:
42
- - `missingval` of `missing` does not work with GDAL. Use `replace_missing(A, newmissingval)` to
43
- assign a missing value before using `resample` if the current value is `missing`. This will be
44
- automated in future versions.
45
- - GDAL may cause some unexpected changes in the data, such as returning a reversed dimension or
46
- changing the `crs` datatype from `EPSG` to `WellKnownText`.
40
+ Note:
41
+ - GDAL may cause some unexpected changes in the data, such as returning a reversed Y dimension or
42
+ changing the `crs` type from `EPSG` to `WellKnownText` (it will represent the same CRS).
47
43
48
44
# Example
49
45
@@ -73,49 +69,107 @@ savefig(b, "build/resample_example_after.png"); nothing
73
69
$EXPERIMENTAL
74
70
"""
75
71
function resample end
72
+ resample (x, res; kw... ) = resample (x; res, kw... )
76
73
resample (xs:: RasterStackOrArray... ; kw... ) = resample (xs; kw... )
77
74
function resample (ser:: AbstractRasterSeries , args... ; kw... )
78
75
map (x -> resample (x, args... ; kw... ), ser)
79
76
end
80
77
function resample (xs:: Union{Tuple,NamedTuple} ; to= first (xs), kw... )
81
78
map (x -> resample (x; to, kw... ), xs)
82
79
end
83
- function resample (A:: RasterStackOrArray , resolution:: Number ; kw... )
84
- dimres = map (d -> DD. basetypeof (d)(resolution), dims (A, (XDim, YDim)))
85
- resample (A, dimres; kw... )
86
- end
87
- function resample (A:: RasterStackOrArray , pairs:: Pair... ; kw... )
88
- resample (A, map ((D, x) -> D (x), pairs); kw... )
89
- end
90
- function resample (A:: RasterStackOrArray , resdims:: DimTuple ;
91
- crs:: GeoFormat = crs (A), method= :near , kw...
80
+ function resample (x:: RasterStackOrArray ;
81
+ # We need to combine the `size` and `res` keywords with
82
+ # the extent in extent2dims, even if we already have dims.
83
+ to= nothing , res= nothing , crs= nothing , size= nothing , method= :near , kw...
92
84
)
93
- wkt = convert (String, convert (WellKnownText, crs))
94
- res = map (val, dims (resdims, (YDim, XDim)))
95
- flags = Dict (
96
- :t_srs => wkt,
97
- :tr => res,
98
- :r => method,
99
- )
100
- return warp (A, flags; kw... )
101
- end
102
- function resample (A:: RasterStackOrArray ; to, method= :near , kw... )
103
- all (hasdim (to, (XDim, YDim))) || throw (ArgumentError (" `to` mush have both XDim and YDim dimensions to resize with GDAL" ))
104
- if sampling (to, XDim) isa Points
105
- to = set (to, dims (to, XDim) => Intervals (Start ()))
85
+ (isnothing (size) || isnothing (res)) || _size_and_res_error ()
86
+
87
+ # Flags to send to `warp`, then to GDAL
88
+ flags = Dict {Symbol,Any} ()
89
+
90
+ # Method
91
+ flags[:r ] = method
92
+
93
+ # Extent
94
+ if to isa Extents. Extent || isnothing (dims (to))
95
+ to = isnothing (to) || to isa Extents. Extent ? to : GeoInterface. extent (to)
96
+ if ! isnothing (to)
97
+ # Get the extent of geometries
98
+ (xmin, xmax), (ymin, ymax) = to[(:X , :Y )]
99
+ flags[:te ] = [xmin, ymin, xmax, ymax]
100
+ end
101
+ else
102
+ all (hasdim (to, (XDim, YDim))) || throw (ArgumentError (" `to` mush have both XDim and YDim dimensions to resize with GDAL" ))
103
+ if sampling (to, XDim) isa Points
104
+ to = set (to, dims (to, XDim) => Intervals (Start ()))
105
+ end
106
+ if sampling (to, YDim) isa Points
107
+ to = set (to, dims (to, YDim) => Intervals (Start ()))
108
+ end
109
+
110
+ # Set res from `to` if it was not already set
111
+ if isnothing (res) && isnothing (size)
112
+ xres, yres = map (abs ∘ step, span (to, (XDim, YDim)))
113
+ flags[:tr ] = [yres, xres]
114
+ end
115
+ (xmin, xmax), (ymin, ymax) = bounds (to, (XDim, YDim))
116
+ flags[:te ] = [xmin, ymin, xmax, ymax]
106
117
end
107
- if sampling (to, YDim) isa Points
108
- to = set (to, dims (to, YDim) => Intervals (Start ()))
118
+
119
+ # CRS
120
+ crs = if isnothing (crs)
121
+ if to isa Extents. Extent
122
+ nothing
123
+ else
124
+ # get crs from `to` or `x` if none was passed in
125
+ isnothing (Rasters. crs (to)) ? Rasters. crs (x) : Rasters. crs (to)
126
+ end
127
+ else
128
+ crs
129
+ end
130
+ if ! isnothing (crs)
131
+ wkt = convert (String, convert (WellKnownText, crs))
132
+ flags[:t_srs ] = wkt
133
+ if isnothing (Rasters. crs (x))
134
+ @warn " You have set a crs to resample to, but the object does not have crs so GDAL will assume it is already in the target crs. Use `newraster = setcrs(raster, somecrs)` to fix this."
135
+ end
109
136
end
110
137
111
- wkt = convert (String, convert (WellKnownText, crs (to)))
112
- xres, yres = map (abs ∘ step, span (to, (XDim, YDim)))
113
- (xmin, xmax), (ymin, ymax) = bounds (to, (XDim, YDim))
114
- flags = Dict (
115
- :t_srs => wkt,
116
- :tr => [yres, xres],
117
- :te => [xmin, ymin, xmax, ymax],
118
- :r => method,
119
- )
120
- return warp (A, flags; kw... )
138
+ # Resolution
139
+ if ! isnothing (res)
140
+ xres, yres = if res isa Real
141
+ res, res
142
+ elseif res isa Tuple{<: Dimension{<:Real} ,<: Dimension{<:Real} }
143
+ map (val, dims (res, (YDim, XDim)))
144
+ elseif res isa Tuple{<: Real ,<: Real }
145
+ reverse (res)
146
+ else
147
+ throw (ArgumentError (" `res` must be a `Real`, or a 2 `Tuple` of `Real` or `Dimension`s wrapping `Real`. Got $res " ))
148
+ end
149
+ flags[:tr ] = [yres, xres]
150
+ end
151
+
152
+ # Size
153
+ if ! isnothing (size)
154
+ xsize, ysize = if size isa Int
155
+ size, size
156
+ elseif size isa Tuple{<: Dimension{Int} ,<: Dimension{Int} }
157
+ map (val, dims (size, (YDim, XDim)))
158
+ elseif size isa Tuple{Int,Int}
159
+ reverse (size)
160
+ else
161
+ throw (ArgumentError (" `size` must be a `Int`, or a 2 `Tuple` of `Int` or `Dimension`s wrapping `Int`. Got $size " ))
162
+ end
163
+ flags[:ts ] = [ysize, xsize]
164
+ end
165
+
166
+ # resample with `warp`
167
+ resampled = warp (x, flags; kw... )
168
+
169
+ # Return crs to the original type, from GDAL it will always be WellKnownText
170
+ if isnothing (crs)
171
+ return setcrs (resampled, Rasters. crs (x))
172
+ else
173
+ return setcrs (resampled, crs)
174
+ end
121
175
end
0 commit comments