Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add center/centered helpers #242

Merged
merged 4 commits into from
May 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ OffsetArray(A, OffsetArrays.Origin(-1, -1))
OffsetArray(OA, OffsetArrays.Origin(-1, -1))
```

Sometimes, it will be convenient to shift the center coordinate of the given array to `(0, 0, ...)`,
`OffsetArrays.centered` is a helper for this very purpose:

```@repl index
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these be doctests instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doctests are already in the src/ and test/ so I think it's okay to just follow the previous doc format here.

Ao = OffsetArrays.centered(A)
Ao[0, 0] == 8.0
```

and `OffsetArrays.center` tells you the center coordinate of given array:

```@repl index
c = OffsetArrays.center(A)
A[c...] == 8.0
```

## Example: Relativistic Notation

Expand Down
69 changes: 69 additions & 0 deletions src/OffsetArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,75 @@ _no_offset_view(::Tuple{<:Base.OneTo,Vararg{<:Base.OneTo}}, A::AbstractUnitRange
_no_offset_view(::Any, A::AbstractArray) = OffsetArray(A, Origin(1))
_no_offset_view(::Any, A::AbstractUnitRange) = UnitRange(A)

#####
# center/centered
# These two helpers are deliberately not exported; their meaning can be very different in
# other scenarios and will be very likely to cause name conflicts if exported.
#####
"""
center(A, [r::RoundingMode=RoundDown])::Dims

Return the center coordinate of given array `A`. If `size(A, k)` is even,
a rounding procedure will be applied with mode `r`.

!!! compat "OffsetArrays 1.9"
This method requires at least OffsetArrays 1.9.

# Examples

```jldoctest; setup=:(using OffsetArrays)
A = reshape(collect(1:9), 3, 3)
c = OffsetArrays.center(A) # (2, 2)
A[c...] == 5 # true

Ao = OffsetArray(A, -2, -2)
c = OffsetArrays.center(Ao) # (0, 0)
Ao[c...] == 5 # true

# output
true
```

To shift the center coordinate of the given array to `(0, 0, ...)`, you
can use [`centered`](@ref OffsetArrays.centered).
"""
function center(A::AbstractArray, r::RoundingMode=RoundDown)
map(axes(A)) do inds
round(Int, (length(inds)-1)/2, r) + first(inds)
Copy link
Member Author

@johnnychen94 johnnychen94 May 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default RoundDown and length(inds)-1 is chosen to match the previous ImageFiltering.centered behavior:

julia> A = reshape(collect(1:6), 2, 3)
2×3 Matrix{Int64}:
 1  3  5
 2  4  6

julia> OffsetArrays.centered(A) == ImageFiltering.centered(A)
true

end
end

"""
centered(A, r::RoundingMode=RoundDown) -> Ao

Shift the center coordinate of array `A` to `(0, 0, ...)`. If `size(A, k)`
is even, a rounding procedure will be applied with mode `r`.

!!! compat "OffsetArrays 1.9"
This method requires at least OffsetArrays 1.9.

# Examples

```jldoctest; setup=:(using OffsetArrays)
A = reshape(collect(1:9), 3, 3)
Ao = OffsetArrays.centered(A)
Ao[0, 0] == 5 # true

A = reshape(collect(1:9), 3, 3)
Ao = OffsetArray(A, OffsetArrays.Origin(0))
Aoo = OffsetArrays.centered(Ao)
Aoo[0, 0] == 5 # true

# output
true
```

To query the center coordinate of the given array, you can
instead use [`center`](@ref OffsetArrays.center).
"""
centered(A::AbstractArray, r::RoundingMode=RoundDown) = OffsetArray(A, .-center(A, r))


####
# work around for segfault in searchsorted*
# https://github.com/JuliaLang/julia/issues/33977
Expand Down
49 changes: 49 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2408,4 +2408,53 @@ end
@test_throws MethodError convert(OffsetArray{Float64, 3, Array{Float64,3}}, A)
end

@testset "center/centered" begin
@testset "center" begin
A = reshape(collect(1:9), 3, 3)
c = OffsetArrays.center(A)
@test c == (2, 2)
@test A[c...] == 5
@test OffsetArrays.center(A, RoundDown) == OffsetArrays.center(A, RoundUp)

A = reshape(collect(1:6), 2, 3)
c = OffsetArrays.center(A)
@test OffsetArrays.center(A, RoundDown) == c
@test c == (1, 2)
@test A[c...] == 3
c = OffsetArrays.center(A, RoundUp)
@test c == (2, 2)
@test A[c...] == 4
end

@testset "centered" begin
A = reshape(collect(1:9), 3, 3)
Ao = OffsetArrays.centered(A)
@test typeof(Ao) <: OffsetArray
@test parent(Ao) === A
@test Ao.offsets == (-2, -2)
@test Ao[0, 0] == 5
@test OffsetArrays.centered(A, RoundDown) == OffsetArrays.centered(A, RoundUp)

A = reshape(collect(1:6), 2, 3)
Ao = OffsetArrays.centered(A)
@test OffsetArrays.centered(A, RoundDown) == Ao
@test typeof(Ao) <: OffsetArray
@test parent(Ao) === A
@test Ao.offsets == (-1, -2)
@test Ao[0, 0] == 3
Ao = OffsetArrays.centered(A, RoundUp)
@test typeof(Ao) <: OffsetArray
@test parent(Ao) === A
@test Ao.offsets == (-2, -2)
@test Ao[0, 0] == 4

A = reshape(collect(1:9), 3, 3)
Ao = OffsetArray(A, -1, -1)
Aoo = OffsetArrays.centered(Ao)
@test parent(Aoo) === A # there will be only one OffsetArray wrapper
@test Aoo.offsets == (-2, -2)
@test Aoo[0, 0] == 5
end
end

include("origin.jl")