Skip to content

Commit bd479c5

Browse files
authored
fix rasterization for a single feature (#323)
* fix rasterization for a single feature
1 parent 6e48254 commit bd479c5

File tree

6 files changed

+48
-23
lines changed

6 files changed

+48
-23
lines changed

src/lookup.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ LA.transformfunc(lookup::AffineProjected) = CoordinateTransformations.inv(lookup
167167
# DD.bounds(lookup::AffineProjected) = lookup.metadata
168168

169169
function Dimensions.sliceunalligneddims(
170-
_, I::NTuple{<:Any,<:Union{Colon,AbstractArray}},
170+
_, I::NTuple{2,<:Union{Colon,AbstractArray}},
171171
ud1::Dimension{<:AffineProjected}, ud2::Dimension{<:AffineProjected}
172172
)
173173
# swap colons for the dimension index, which is the same as the array axis
@@ -193,7 +193,7 @@ end
193193

194194
function Base.reverse(lookup::AffineProjected)
195195
sp = reverse(span(lookup))
196-
rebuild(lookup; data=i, order=o, span=sp)
196+
rebuild(lookup; order=o, span=sp)
197197
end
198198

199199
"""

src/methods/extract.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ function _extract(x::RasterStackOrArray, ::GI.PointTrait, point; dims, names, at
8787

8888
# Extract the values
8989
if any(map(ismissing, coords))
90+
# TODO test this branch somehow
9091
geometry = map(_ -> missing, coords)
91-
layer_vals = map(_ -> missing, layer_keys)
92+
layer_vals = map(_ -> missing, names)
9293
else
9394
selectors = map(dims, coords) do d, c
9495
_at_or_contains(d, c, atol)

src/methods/rasterize.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,15 @@ function _rasterize(to::DimTuple, data;
8787
)
8888
_rasterize(to, GeoInterface.trait(data), data; fill, name, kw...)
8989
end
90-
function _rasterize(to::DimTuple, ::GI.AbstractFeatureTrait, feature; fill, kw...)
91-
fill = _featurefillval(feature, fill)
92-
dest = _create_rasterize_dest(fill, to; kw...)
90+
function _rasterize(to::DimTuple, ::GI.AbstractFeatureTrait, feature; fill, name, kw...)
91+
fillval = _featurefillval(feature, fill)
92+
name = _filter_name(name, fill)
93+
@show name fillval
94+
dest = _create_rasterize_dest(fillval, to; name, kw...)
9395
return rasterize!(dest, feature; fill, kw...)
9496
end
9597
function _rasterize(to::DimTuple, ::GI.AbstractFeatureCollectionTrait, fc; name, fill, kw...)
98+
# TODO: how to handle when there are fillvals with different types
9699
fillval = _featurefillval(GI.getfeature(fc, 1), fill)
97100
name = _filter_name(name, fill)
98101
dest = _create_rasterize_dest(fillval, to; name, kw...)
@@ -122,6 +125,7 @@ function _rasterize(to::DimTuple, ::Nothing, data; fill, name, kw...)
122125
return rasterize!(dest, data; fill, kw...)
123126
end
124127

128+
# Create a destination raster to fill into using `rasterize!`
125129
function _create_rasterize_dest(fill, dims; name=nothing, kw...)
126130
_create_rasterize_dest(fill, name, dims; kw...)
127131
end
@@ -249,7 +253,8 @@ function _rasterize!(x, ::GI.AbstractFeatureCollectionTrait, fc; fill, kw...)
249253
return x
250254
end
251255
function _rasterize!(x, ::GI.AbstractFeatureTrait, feature; fill, kw...)
252-
rasterize!(x, geom; fill=_featurefillval(feature, fill), kw...)
256+
# TODO test this branch
257+
rasterize!(x, GI.geometry(feature); fill=_featurefillval(feature, fill), kw...)
253258
end
254259
function _rasterize!(x, ::GI.AbstractGeometryTrait, geom; fill, _buffer=nothing, kw...)
255260
# TODO fix DimensionalData selectors so this works without _pad
@@ -397,6 +402,7 @@ end
397402
_filter_name(name, fill::NamedTuple) = keys(fill)
398403
_filter_name(name::NamedTuple, fill::NamedTuple) = keys(fill)
399404
_filter_name(name::Nothing, fill::Nothing) = nothing
405+
_filter_name(name::DimensionalData.NoName, fill::Nothing) = nothing
400406
_filter_name(name::Union{NamedTuple,Tuple,Array}, fill::NTuple{<:Any,Symbol}) = fill
401407
function _filter_name(name::Union{NamedTuple,Tuple,Array}, fill::Union{Tuple,Array})
402408
length(name) == length(fill) || throw(ArgumentError("`name` keyword (possibly from `to` object) does not match length of fill. A fix is to use a `NamedTuple` for `fill`."))

src/openstack.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ ConstructionBase.constructorof(::Type{<:OpenStack{X,K}}) where {X,K} = OpenStack
2323

2424
dataset(os::OpenStack) = os.dataset
2525
Base.keys(os::OpenStack{<:Any,K}) where K = K
26-
Base.values(os::OpenStack{<:Any}) = (fs[k] for k in keys(fs))
26+
# TODO test this, and does it make sense to return an iterator here?
27+
Base.values(os::OpenStack{<:Any}) = (os[k] for k in keys(os))
2728
# Indexing OpenStack returns memory-backed Raster.
2829
Base.getindex(os::OpenStack, key::Symbol) = dataset(os)[key]

src/polygon_ops.jl

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const DEFAULT_TABLE_DIM_KEYS = (:X, :Y, :Z)
99
function _fill_geometry!(B::AbstractRaster, geom; kw...)
1010
_fill_geometry!(B, GI.trait(geom), geom; kw...)
1111
end
12-
function _fill_geometry!(B::AbstractRaster, ::GI.AbstractFeatureTrait, geom; kw...)
13-
return _fill_geometry!(B, GI.geometry(geom), geom; kw...)
12+
function _fill_geometry!(B::AbstractRaster, ::GI.AbstractFeatureTrait, feature; kw...)
13+
return _fill_geometry!(B, GI.geometry(feature); kw...)
1414
end
1515
function _fill_geometry!(B::AbstractRaster, ::GI.AbstractFeatureCollectionTrait, fc; kw...)
1616
for feature in GI.getfeature(fc)
@@ -25,7 +25,7 @@ function _fill_geometry!(B::AbstractRaster, ::GI.AbstractGeometryTrait, geom; sh
2525
_fill_linestring!(B, geom; shape, kw...)
2626
elseif shape === :polygon
2727
geomextent = _extent(geom)
28-
arrayextent = Extents.extent(B, DEFAULT_POINT_ORDER)
28+
arrayextent = Extents.extent(B, DEFAULT_POINT_ORDER)
2929
# Only fill if the gemoetry bounding box overlaps the array bounding box
3030
Extents.intersects(geomextent, arrayextent) || return B
3131
_fill_polygon!(B, geom; shape, geomextent, kw...)
@@ -125,14 +125,15 @@ function _iyperm(dims::Tuple{<:Dimension,<:Dimension})
125125
return iyperm
126126
end
127127
function _iyperm(dims::Tuple{<:Dimension,<:Dimension,<:Dimension})
128+
# TODO: test this 3d case
128129
a1, a2, a3 = map(dims) do d
129130
l = parent(d)
130131
LA.ordered_firstindex(l):_order_step(l):LA.ordered_lastindex(l)
131132
end
132133
iyperm = Array{Int}(undef, length(a1) * length(a2) * length(a3))
133134
lis = (LinearIndices(size(dims))[i, j, k] for k in a3 for j in a2 for i in a1)
134135
for (i, li) in enumerate(lis)
135-
Iyperm[i] = li
136+
iyperm[i] = li
136137
end
137138
return iyperm
138139
end
@@ -263,7 +264,7 @@ function _fill_line!(A::AbstractRaster, line, fill)
263264
# delta: How far to move along the ray to move 1 grid cell.
264265
cs = cos(angle)
265266
si = sin(angle)
266-
max_x, delta_x = if isapprox(cs, zero(cs); atol=1e-10)
267+
max_x, delta_x = if isapprox(cs, zero(cs); atol=1e-10)
267268
-Inf, Inf
268269
else
269270
1.0 / cs, xoffset / cs
@@ -280,7 +281,7 @@ function _fill_line!(A::AbstractRaster, line, fill)
280281
for t in 0:manhattan_distance
281282
D = map((d, o) -> d(o), dimconstructors, (x, y))
282283
if checkbounds(Bool, A, D...)
283-
if fill isa Function
284+
if fill isa Function
284285
@inbounds A[D...] = fill(A[D...])
285286
else
286287
@inbounds A[D...] = fill
@@ -333,7 +334,7 @@ function to_edges_and_nodes!(edges, nodes, lastnode, geom)
333334
for (n, point) in enumerate(GI.getpoint(geom))
334335
i = lastnode + n
335336
if n == npoints
336-
# The closing edge of a sub-polygon
337+
# The closing edge of a sub-polygon
337338
edges[i, 1] = i
338339
edges[i, 2] = lastnode + 1
339340
else
@@ -367,10 +368,11 @@ function _extent(::Nothing, data)
367368
Extents.union(ext, _extent(geom))
368369
end
369370
else
371+
# TODO: test this branch
370372
# Table of points with dimension columns
371373
reduce(DEFAULT_TABLE_DIM_KEYS; init=(;)) do acc, key
372-
if key in Tables.columnnames(cols)
373-
merge(acc, (; key=extrema(columns)))
374+
if key in Tables.columnnames(cols)
375+
merge(acc, (; key=extrema(cols[key])))
374376
else
375377
acc
376378
end
@@ -393,7 +395,7 @@ function _extent(::GI.AbstractTrait, geom)
393395
end
394396
end
395397
_extent(::GI.AbstractFeatureTrait, feature) = _extent(GI.geometry(feature))
396-
function _extent(::GI.AbstractFeatureCollectionTrait, features)
398+
function _extent(::GI.AbstractFeatureCollectionTrait, features)
397399
features = GI.getfeature(features)
398400
reduce(features; init=_extent(first(features))) do acc, f
399401
Extents.union(acc, _extent(f))
@@ -403,12 +405,13 @@ end
403405
# extent_may_intersect
404406
# Check if there is an extent for the geometry
405407
function extent_may_intersect(x, geom)
408+
# TODO: this is not actually used.
406409
rasterextent = Extents.extent(x, DEFAULT_POINT_ORDER)
407410
geomextent = GI.extent(geom)
408-
if ext isa Nothing
411+
if isnothing(rasterextent) || isnothing(geomextent)
409412
return true
410413
else
411-
return Extents.intersects(geomextent, rasterext)
414+
return Extents.intersects(geomextent, rasterextent)
412415
end
413416
end
414417

@@ -422,7 +425,7 @@ _dimcoord(::ZDim, point) = GI.z(point)
422425
# Get the shape category for a geometry
423426
@inline _geom_shape(geom) = _geom_shape(GI.geomtrait(geom))
424427
@inline _geom_shape(geom::Union{<:GI.PointTrait,<:GI.MultiPointTrait}) = :point
425-
@inline _geom_shape(geom::Union{<:GI.LineStringTrait,<:GI.MultiLineStringTrait}) = :line
428+
@inline _geom_shape(geom::Union{<:GI.LineStringTrait,<:GI.MultiLineStringTrait}) = :line
426429
@inline _geom_shape(geom::Union{<:GI.LinearRingTrait,<:GI.PolygonTrait,<:GI.MultiPolygonTrait}) = :polygon
427430
# _geom_shape(trait, geom) = throw(ArgumentError("Geometry trait $trait not handled by Rasters.jl"))
428431

test/methods.jl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ gaNaN = replace_missing(ga, NaN32)
1212
gaMi = replace_missing(ga)
1313
st = RasterStack((a=A, b=B), (X, Y); missingval=(a=missing,b=missing))
1414

15-
1615
pointvec = [(-20.0, 30.0),
1716
(-20.0, 10.0),
1817
(0.0, 10.0),
@@ -403,7 +402,22 @@ end
403402
@test sum(ra) == 12
404403
end
405404
end
406-
405+
@testset "a single feature" begin
406+
feature = pointfc[4]
407+
GeoInterface.isfeature(feature)
408+
@testset "NTuple of Symbol fill makes an stack" begin
409+
rst = rasterize(feature; to=A, fill=(:val1, :val2))
410+
rst = rasterize(feature; to=A, fill=(:val1, :val2))
411+
@test keys(rst) == (:val1, :val2)
412+
@test dims(rst) == dims(A)
413+
@test map(sum skipmissing, rst) === (val1=4, val2=8.0f0)
414+
end
415+
@testset "Symbol fill makes an array" begin
416+
ra = rasterize(feature; to=A, fill=:val1)
417+
@test ra isa Raster{Union{Missing,Int64}}
418+
@test name(ra) == :val1
419+
end
420+
end
407421
@testset "feature collection, table from fill of Symbol keys" begin
408422
for data in (pointfc, DataFrame(pointfc))
409423
@testset "NTuple of Symbol fill makes an stack" begin

0 commit comments

Comments
 (0)