diff --git a/Project.toml b/Project.toml index 20128cdc..a1a35b08 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SimpleSDMLayers" uuid = "2c645270-77db-11e9-22c3-0f302a89c64c" authors = ["Timothée Poisot "] -version = "0.2.0" +version = "0.2.1" [deps] GDAL = "add2ef01-049f-52c4-9ee2-e494f65e021a" diff --git a/src/lib/overloads.jl b/src/lib/overloads.jl index b83309e1..6fdaeca0 100644 --- a/src/lib/overloads.jl +++ b/src/lib/overloads.jl @@ -125,7 +125,7 @@ end Given a layer and a latitude, returns NaN if the latitude is outside the range, or the grid index containing this latitude if it is within range """ -function match_latitude(p::T, l::K) where {T <: SimpleSDMLayer, K <: AbstractFloat} +function _match_latitude(p::T, l::K) where {T <: SimpleSDMLayer, K <: AbstractFloat} l > p.top && return NaN l < p.bottom && return NaN return findmin(abs.(l .- latitudes(p)))[2] @@ -135,7 +135,7 @@ end Given a layer and a longitude, returns NaN if the longitude is outside the range, or the grid index containing this longitude if it is within range """ -function match_longitude(p::T, l::K) where {T <: SimpleSDMLayer, K <: AbstractFloat} +function _match_longitude(p::T, l::K) where {T <: SimpleSDMLayer, K <: AbstractFloat} l > p.right && return NaN l < p.left && return NaN return findmin(abs.(l .- longitudes(p)))[2] @@ -148,29 +148,49 @@ Extracts the value of a layer at a given latitude and longitude. If values outside the range are requested, will return `NaN`. """ function Base.getindex(p::T, longitude::K, latitude::K) where {T <: SimpleSDMLayer, K <: AbstractFloat} - i = match_longitude(p, longitude) - j = match_latitude(p, latitude) + i = _match_longitude(p, longitude) + j = _match_latitude(p, latitude) isnan(i) && return NaN isnan(j) && return NaN return p.grid[j, i] end """ - Base.getindex(p::T; left::K=nothing, right::K=nothing, top::K=nothing, bottom::K=nothing) where {T <: SimpleSDMLayer, K <: Union{Nothing,AbstractFloat}} + Base.getindex(p::T; left=nothing, right=nothing, top=nothing, bottom=nothing) where {T <: SimpleSDMLayer, K <: Union{Nothing,AbstractFloat}} Returns a subset of the argument layer, where the new limits are given by `left`, `right`, `top`, and `bottom`. Up to three of these can be omitted, and if so these limits will not be affected. """ -function Base.getindex(p::T; left::K=nothing, right::K=nothing, top::K=nothing, bottom::K=nothing) where {T <: SimpleSDMLayer, K <: Union{Nothing,AbstractFloat}} - imax = isnothing(right) ? p.right : match_longitude(p, right) - imin = isnothing(left) ? p.left : match_longitude(p, left) - jmax = isnothing(top) ? p.top : match_latitude(p, top) - jmin = isnothing(bottom) ? p.bottom : match_latitude(p, bottom) +function Base.getindex(p::T; left=nothing, right=nothing, top=nothing, bottom=nothing) where {T <: SimpleSDMLayer} + for limit in [left, right, top, bottom] + if !isnothing(limit) + @assert typeof(limit) <: AbstractFloat + end + end + imax = _match_longitude(p, isnothing(right) ? p.right : right) + imin = _match_longitude(p, isnothing(left) ? p.left : left) + jmax = _match_latitude(p, isnothing(top) ? p.top : top) + jmin = _match_latitude(p, isnothing(bottom) ? p.bottom : bottom) any(isnan.([imin, imax, jmin, jmax])) && throw(ArgumentError("Unable to extract, coordinates outside of range")) return p[jmin:jmax, imin:imax] end +""" + Base.getindex(p::T, n::NT) where {T <: SimpleSDMLayer, NT <: NamedTuple} + +Returns a subset of the argument layer, where the new limits are given in +a NamedTuple by `left`, `right`, `top`, and `bottom`, in any order. Up to +three of these can be omitted, and if so these limits will not be affected. +""" +function Base.getindex(p::T, n::NT) where {T <: SimpleSDMLayer, NT <: NamedTuple} + l = isdefined(n, :left) ? n.left : nothing + r = isdefined(n, :right) ? n.right : nothing + t = isdefined(n, :top) ? n.top : nothing + b = isdefined(n, :bottom) ? n.bottom : nothing + Base.getindex(p; left = l, right = r, top = t, bottom = b) +end + """ Base.getindex(p1::T1, p2::T2) where {T1 <: SimpleSDMLayer, T2 <: SimpleSDMLayer} @@ -201,8 +221,8 @@ Changes the values of the cell including the point at the requested latitude and longitude. """ function Base.setindex!(p::SimpleSDMResponse{T}, v::T, lon::Float64, lat::Float64) where {T} - i = match_longitude(p, lon) - j = match_latitude(p, lat) + i = _match_longitude(p, lon) + j = _match_latitude(p, lat) p[j,i] = v end diff --git a/test/overloads.jl b/test/overloads.jl index 2fc497c2..9bfbd650 100644 --- a/test/overloads.jl +++ b/test/overloads.jl @@ -26,6 +26,15 @@ end @test S[left=0.2, right=0.6, bottom=0.5, top=1.0].right ≈ 0.6 @test S[left=0.2, right=0.6, bottom=0.5, top=1.0].left ≈ 0.2 +@test typeof(S[left=0.2, bottom=0.5]) == typeof(S) +@test S[left=0.2, bottom=0.5].top ≈ 1.0 +@test S[left=0.2, bottom=0.5].bottom ≈ 0.4 +@test S[left=0.2, bottom=0.5].right ≈ 1.0 +@test S[left=0.2, bottom=0.5].left ≈ 0.2 + +C = (left=0.2, bottom=0.5) +@test typeof(S[C]) == typeof(S) + Y = SimpleSDMResponse(zeros(Float64, (5,5)), 0.0, 1.0, 0.0, 1.0) Y[0.1,0.1] = 0.2 @test Y[0.1,0.1] == 0.2