Skip to content
This repository has been archived by the owner on Dec 11, 2022. It is now read-only.

Fix cropping when omitting a limit #18

Merged
merged 8 commits into from
Apr 10, 2020
Merged
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SimpleSDMLayers"
uuid = "2c645270-77db-11e9-22c3-0f302a89c64c"
authors = ["Timothée Poisot <[email protected]>"]
version = "0.2.0"
version = "0.2.1"

[deps]
GDAL = "add2ef01-049f-52c4-9ee2-e494f65e021a"
Expand Down
44 changes: 32 additions & 12 deletions src/lib/overloads.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]
Expand All @@ -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}

Expand Down Expand Up @@ -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

Expand Down
9 changes: 9 additions & 0 deletions test/overloads.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down