Skip to content

Commit eb94fc2

Browse files
authored
Merge pull request #116 from JuliaImages/jc/rebox
- upgrade legacy methods with cleaner keyword alternatives - rewrite/update the docstring of `warp` and related functions
2 parents 9257562 + 3fe10ed commit eb94fc2

File tree

14 files changed

+616
-476
lines changed

14 files changed

+616
-476
lines changed

Project.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ version = "0.8.12"
66
AxisAlgorithms = "13072b0f-2c55-5437-9ae7-d433b7a33950"
77
ColorVectorSpace = "c3611d14-8923-5661-9e6a-0046d554d3a4"
88
CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298"
9-
IdentityRanges = "bbac6d45-d8f3-5730-bfe4-7a449cd117ca"
109
ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534"
1110
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
1211
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
@@ -17,7 +16,6 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1716
AxisAlgorithms = "1.0"
1817
ColorVectorSpace = "0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9"
1918
CoordinateTransformations = "0.5, 0.6"
20-
IdentityRanges = "0.3"
2119
ImageCore = "0.8.1, 0.9"
2220
Interpolations = "0.9, 0.10, 0.11, 0.12, 0.13"
2321
OffsetArrays = "0.10, 0.11, 1.0.1"

src/ImageTransformations.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ using StaticArrays
77
using Interpolations, AxisAlgorithms
88
using OffsetArrays
99
using ColorVectorSpace
10-
using IdentityRanges
1110

1211
import Base: eltype, size, length
1312
using Base: tail, Indices
@@ -32,7 +31,10 @@ include("interpolations.jl")
3231
include("warp.jl")
3332
include("warpedview.jl")
3433
include("invwarpedview.jl")
34+
include("compat.jl")
35+
include("deprecated.jl")
3536

37+
# TODO: move to warp.jl
3638
@inline _getindex(A, v::StaticVector) = A[Tuple(v)...]
3739
@inline _getindex(A::AbstractInterpolation, v::StaticVector) = A(Tuple(v)...)
3840
@inline _getindex(A, v) = A[v...]

src/autorange.jl

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,38 @@
1-
function autorange(img, tform)
2-
R = CartesianIndices(axes(img))
3-
autorange(R, tform)
4-
end
1+
"""
2+
autorange(A::AbstractArray, tform::Transformation)
3+
4+
For given transformation `tform`, return the "smallest" range indices that
5+
preserves all information from `A` after applying `tform`.
6+
7+
# Examples
8+
9+
For transformation that preserves the array size, `autorange` is equivalent to `axes(A)`.
10+
11+
```jldoctest; setup=:(using ImageTransformations: autorange; using CoordinateTransformations, Rotations, ImageTransformations)
12+
A = rand(5, 5)
13+
tform = IdentityTransformation()
14+
autorange(A, tform) == axes(A)
515
16+
# output
17+
true
18+
```
19+
20+
The diffrence shows up when `tform` enlarges the input array `A`. In the following example, we need
21+
at least `(0:6, 0:6)` as the range indices to get all data of `A`:
22+
23+
```jldoctest; setup=:(using ImageTransformations: autorange; using CoordinateTransformations, Rotations, ImageTransformations)
24+
A = rand(5, 5)
25+
tform = recenter(RotMatrix(pi/8), center(A))
26+
autorange(A, tform)
27+
28+
# output
29+
(0:6, 0:6)
30+
```
31+
32+
!!! note
33+
This function is not exported; it is mainly for internal usage to infer the default indices.
34+
"""
35+
autorange(A::AbstractArray, tform) = autorange(CartesianIndices(A), tform)
636
function autorange(R::CartesianIndices, tform)
737
tform = _round(tform)
838
mn = mx = tform(SVector(first(R).I))
@@ -91,9 +121,6 @@ function _round(tform::T; kwargs...) where T<:CoordinateTransformations.Transfor
91121
end
92122
T(rounded_fields...)
93123
end
94-
if isdefined(Base, :ComposedFunction)
95-
_round(tform::ComposedFunction; kwargs...) = _round(tform.outer; kwargs...) _round(tform.inner; kwargs...)
96-
end
97124
_round(tform; kwargs...) = tform
98125

99126
__round(x; kwargs...) = x

src/compat.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This file includes two kinds of codes
2+
# - Codes for backward compatibility
3+
# - Glue codes that might nolonger be necessary in the future
4+
5+
# patch for issue #110
6+
if isdefined(Base, :ComposedFunction) # Julia >= 1.6.0-DEV.85
7+
# https://github.com/JuliaLang/julia/pull/37517
8+
_round(tform::ComposedFunction; kwargs...) = _round(tform.outer; kwargs...) _round(tform.inner; kwargs...)
9+
end
10+
11+
@static if !isdefined(Base, :IdentityUnitRange)
12+
const IdentityUnitRange = Base.Slice
13+
else
14+
using Base: IdentityUnitRange
15+
end
16+
17+
@static if VERSION < v"1.1"
18+
@inline isnothing(x) = x === nothing
19+
end
20+
21+
# FIXME: upstream https://github.com/JuliaGraphics/ColorVectorSpace.jl/issues/75
22+
@inline _nan(::Type{HSV{Float16}}) = HSV{Float16}(NaN16,NaN16,NaN16)
23+
@inline _nan(::Type{HSV{Float32}}) = HSV{Float32}(NaN32,NaN32,NaN32)
24+
@inline _nan(::Type{HSV{Float64}}) = HSV{Float64}(NaN,NaN,NaN)
25+
@inline _nan(::Type{T}) where {T} = nan(T)

src/deprecated.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# BEGIN 0.9 deprecations
2+
3+
@deprecate warp(img::AbstractArray, tform::Transformation, method::MethodType, ) warp(img, tform; method=method)
4+
@deprecate warp(img::AbstractArray, tform::Transformation, fillvalue::FillType) warp(img, tform; fillvalue=fillvalue)
5+
@deprecate warp(img::AbstractArray, tform::Transformation, method::MethodType, fillvalue::FillType) warp(img, tform; method=method, fillvalue=fillvalue)
6+
@deprecate warp(img::AbstractArray, tform::Transformation, fillvalue::FillType, method::MethodType) warp(img, tform; method=method, fillvalue=fillvalue)
7+
@deprecate warp(img::AbstractArray, tform::Transformation, inds, method::MethodType, ) warp(img, tform, inds; method=method)
8+
@deprecate warp(img::AbstractArray, tform::Transformation, inds, fillvalue::FillType) warp(img, tform, inds; fillvalue=fillvalue)
9+
@deprecate warp(img::AbstractArray, tform::Transformation, inds, method::MethodType, fillvalue::FillType) warp(img, tform, inds; method=method, fillvalue=fillvalue)
10+
@deprecate warp(img::AbstractArray, tform::Transformation, inds, fillvalue::FillType, method::MethodType) warp(img, tform, inds; method=method, fillvalue=fillvalue)
11+
12+
@deprecate imrotate(img::AbstractArray, θ::Real, method::MethodType ) imrotate(img, θ; method=method)
13+
@deprecate imrotate(img::AbstractArray, θ::Real, fillvalue::FillType) imrotate(img, θ; fillvalue=fillvalue)
14+
@deprecate imrotate(img::AbstractArray, θ::Real, method::MethodType, fillvalue::FillType) imrotate(img, θ; method=method, fillvalue=fillvalue)
15+
@deprecate imrotate(img::AbstractArray, θ::Real, fillvalue::FillType, method::MethodType) imrotate(img, θ; method=method, fillvalue=fillvalue)
16+
@deprecate imrotate(img::AbstractArray, θ::Real, inds, method::MethodType ) imrotate(img, θ, inds; method=method)
17+
@deprecate imrotate(img::AbstractArray, θ::Real, inds, fillvalue::FillType) imrotate(img, θ, inds; fillvalue=fillvalue)
18+
@deprecate imrotate(img::AbstractArray, θ::Real, inds, method::MethodType, fillvalue::FillType) imrotate(img, θ, inds; method=method, fillvalue=fillvalue)
19+
@deprecate imrotate(img::AbstractArray, θ::Real, inds, fillvalue::FillType, method::MethodType) imrotate(img, θ, inds; method=method, fillvalue=fillvalue)
20+
21+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, method::MethodType, ) WarpedView(img, tform; method=method)
22+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, fillvalue::FillType) WarpedView(img, tform; fillvalue=fillvalue)
23+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, method::MethodType, fillvalue::FillType) WarpedView(img, tform; method=method, fillvalue=fillvalue)
24+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, fillvalue::FillType, method::MethodType) WarpedView(img, tform; method=method, fillvalue=fillvalue)
25+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, inds, method::MethodType, ) WarpedView(img, tform, inds; method=method)
26+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, inds, fillvalue::FillType) WarpedView(img, tform, inds; fillvalue=fillvalue)
27+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, inds, method::MethodType, fillvalue::FillType) WarpedView(img, tform, inds; method=method, fillvalue=fillvalue)
28+
@deprecate WarpedView(img::AbstractArray, tform::Transformation, inds, fillvalue::FillType, method::MethodType) WarpedView(img, tform, inds; method=method, fillvalue=fillvalue)
29+
30+
@deprecate warpedview(args...; kwargs...) WarpedView(args...; kwargs...)
31+
32+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, method::MethodType, ) invwarpedview(img, tinv; method=method)
33+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, fillvalue::FillType) invwarpedview(img, tinv; fillvalue=fillvalue)
34+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, method::MethodType, fillvalue::FillType) invwarpedview(img, tinv; method=method, fillvalue=fillvalue)
35+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, fillvalue::FillType, method::MethodType) invwarpedview(img, tinv; method=method, fillvalue=fillvalue)
36+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, inds, method::MethodType, ) invwarpedview(img, tinv, inds; method=method)
37+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, inds, fillvalue::FillType) invwarpedview(img, tinv, inds; fillvalue=fillvalue)
38+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, inds, method::MethodType, fillvalue::FillType) invwarpedview(img, tinv, inds; method=method, fillvalue=fillvalue)
39+
@deprecate invwarpedview(img::AbstractArray, tinv::Transformation, inds, fillvalue::FillType, method::MethodType) invwarpedview(img, tinv, inds; method=method, fillvalue=fillvalue)
40+
41+
# END 0.9 deprecations

src/interpolations.jl

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,42 @@
1-
# FIXME: upstream https://github.com/JuliaGraphics/ColorVectorSpace.jl/issues/75
2-
@inline _nan(::Type{HSV{Float16}}) = HSV{Float16}(NaN16,NaN16,NaN16)
3-
@inline _nan(::Type{HSV{Float32}}) = HSV{Float32}(NaN32,NaN32,NaN32)
4-
@inline _nan(::Type{HSV{Float64}}) = HSV{Float64}(NaN,NaN,NaN)
5-
@inline _nan(::Type{T}) where {T} = nan(T)
6-
7-
#wraper to deal with degree or interpolation types
1+
# A helper function to let our `method` keyword correctly understands `Degree` inputs.
82
@inline wrap_BSpline(itp::Interpolations.InterpolationType) = itp
93
@inline wrap_BSpline(degree::Interpolations.Degree) = BSpline(degree)
104

115
# The default values used by extrapolation for off-domain points
126
const FillType = Union{Number,Colorant,Flat,Periodic,Reflect}
137
const FloatLike{T<:AbstractFloat} = Union{T,AbstractGray{T}}
148
const FloatColorant{T<:AbstractFloat} = Colorant{T}
15-
@inline _default_fill(::Type{T}) where {T<:FloatLike} = convert(T, NaN)
16-
@inline _default_fill(::Type{T}) where {T<:FloatColorant} = _nan(T)
17-
@inline _default_fill(::Type{T}) where {T} = zero(T)
9+
@inline _default_fillvalue(::Type{T}) where {T<:FloatLike} = convert(T, NaN)
10+
@inline _default_fillvalue(::Type{T}) where {T<:FloatColorant} = _nan(T)
11+
@inline _default_fillvalue(::Type{T}) where {T} = zero(T)
1812

1913
@inline _make_compatible(T, fill) = fill
2014
@inline _make_compatible(::Type{T}, fill::Number) where {T} = T(fill)
2115

2216
Interpolations.tweight(A::AbstractArray{C}) where C<:Colorant{T} where T = T
2317

24-
box_extrapolation(etp::AbstractExtrapolation) = etp
25-
26-
function box_extrapolation(itp::AbstractInterpolation{T}, fill::FillType = _default_fill(T); kwargs...) where T
27-
etp = extrapolate(itp, _make_compatible(T, fill))
28-
box_extrapolation(etp)
29-
end
30-
31-
function box_extrapolation(parent::AbstractArray, args...; method::Union{Interpolations.Degree,Interpolations.InterpolationType}=Linear(), kwargs...)
32-
if typeof(method)<:Interpolations.Degree
33-
box_extrapolation(parent, method, args...)
34-
else
35-
itp = interpolate(parent, method)
36-
box_extrapolation(itp, args...)
37-
end
38-
end
39-
40-
function box_extrapolation(parent::AbstractArray{T,N}, degree::Interpolations.Degree, args...; method::Union{Interpolations.Degree,Interpolations.InterpolationType}=Linear(), kwargs...) where {T,N}
41-
itp = interpolate(parent, BSpline(degree))
42-
box_extrapolation(itp, args...)
43-
end
44-
45-
function box_extrapolation(parent::AbstractArray, degree::D, args...; method::Union{Interpolations.Degree,Interpolations.InterpolationType}=Linear(), kwargs...) where D<:Union{Linear,Constant}
46-
axs = axes(parent)
47-
T = typeof(zero(Interpolations.tweight(parent))*zero(eltype(parent)))
48-
itp = Interpolations.BSplineInterpolation{T,ndims(parent),typeof(parent),BSpline{D},typeof(axs)}(parent, axs, BSpline(degree))
49-
box_extrapolation(itp, args...)
50-
end
51-
52-
function box_extrapolation(parent::AbstractArray, fill::FillType; kwargs...)
53-
box_extrapolation(parent, Linear(), fill)
54-
end
55-
56-
function box_extrapolation(itp::AbstractInterpolation, degree::Union{Linear,Constant}, args...; kwargs...)
57-
throw(ArgumentError("Boxing an interpolation in another interpolation is discouraged. Did you specify the parameter \"$degree\" on purpose?"))
58-
end
18+
const MethodType = Union{Interpolations.Degree, Interpolations.InterpolationType}
5919

60-
function box_extrapolation(itp::AbstractInterpolation, degree::Interpolations.Degree, args...; kwargs...)
61-
throw(ArgumentError("Boxing an interpolation in another interpolation is discouraged. Did you specify the parameter \"$degree\" on purpose?"))
20+
function box_extrapolation(
21+
parent::AbstractArray;
22+
fillvalue::FillType = _default_fillvalue(eltype(parent)),
23+
method=Linear(),
24+
kwargs...)
25+
T = typeof(zero(Interpolations.tweight(parent)) * zero(eltype(parent)))
26+
itp = maybe_lazy_interpolate(T, parent, method)
27+
extrapolate(itp, _make_compatible(T, fillvalue))
6228
end
29+
box_extrapolation(etp::AbstractExtrapolation) = etp
30+
box_extrapolation(itp::AbstractInterpolation{T}; fillvalue=_default_fillvalue(T)) where T =
31+
extrapolate(itp, _make_compatible(T, fillvalue))
6332

64-
function box_extrapolation(itp::AbstractExtrapolation, fill::FillType; kwargs...)
65-
throw(ArgumentError("Boxing an extrapolation in another extrapolation is discouraged. Did you specify the parameter \"$fill\" on purpose?"))
33+
@inline function maybe_lazy_interpolate(::Type{T}, A::AbstractArray, degree::D) where {T, D<:Union{Linear, Constant}}
34+
axs = axes(A)
35+
return Interpolations.BSplineInterpolation{T,ndims(A),typeof(A),BSpline{D},typeof(axs)}(A, axs, BSpline(degree))
6636
end
6737

68-
function box_extrapolation(parent::AbstractArray, itp::Interpolations.InterpolationType; kwargs...)
69-
throw(ArgumentError("Argument support for interpolation is not supported. Are you looking for the method keyword to pass an interpolation method?"))
38+
@inline function maybe_lazy_interpolate(::Type{T}, A::AbstractArray, method::MethodType) where T
39+
return interpolate(A, wrap_BSpline(method))
7040
end
7141

7242
# This is type-piracy, but necessary if we want Interpolations to be

src/invwarpedview.jl

Lines changed: 26 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22
InvWarpedView(img, tinv, [indices]) -> wv
33
44
Create a view of `img` that lazily transforms any given index `I`
5-
passed to `wv[I]` to correspond to `img[inv(tinv)(I)]`. While
6-
technically this approach is known as backward mode warping, note
7-
that `InvWarpedView` is created by supplying the forward
8-
transformation
5+
passed to `wv[I]` so that `wv[I] == img[inv(tinv)(I)]`.
96
107
The conceptual difference to [`WarpedView`](@ref) is that
118
`InvWarpedView` is intended to be used when reasoning about the
@@ -14,20 +11,18 @@ Furthermore, `InvWarpedView` allows simple nesting of
1411
transformations, in which case the transformations will be
1512
composed into a single one.
1613
17-
The optional parameter `indices` can be used to specify the
18-
domain of the resulting `wv`. By default the indices are computed
19-
in such a way that `wv` contains all the original pixels in
20-
`img`.
14+
See [`invwarpedview`](@ref) for a convenient constructor of `InvWarpedView`.
2115
22-
see [`invwarpedview`](@ref) for more information.
16+
For detailed explaination of warp, associated arguments and parameters,
17+
please refer to [`warp`](@ref).
2318
"""
2419
struct InvWarpedView{T,N,A,F,I,FI<:Transformation,E} <: AbstractArray{T,N}
2520
inner::WarpedView{T,N,A,F,I,E}
2621
inverse::FI
2722
end
2823

2924
function InvWarpedView(inner::WarpedView{T,N,TA,F,I,E}) where {T,N,TA,F,I,E}
30-
tinv = inv(inner.transform)
25+
tinv = _round(inv(inner.transform))
3126
InvWarpedView{T,N,TA,F,I,typeof(tinv),E}(inner, tinv)
3227
end
3328

@@ -67,78 +62,35 @@ function Base.showarg(io::IO, A::InvWarpedView, toplevel)
6762
end
6863

6964
"""
70-
invwarpedview(img, tinv, [indices], [degree = Linear()], [fill = NaN]) -> wv
65+
invwarpedview(img, tinv, [indices]; kwargs...) -> wv
7166
7267
Create a view of `img` that lazily transforms any given index `I`
73-
passed to `wv[I]` to correspond to `img[inv(tinv)(I)]`. While
74-
technically this approach is known as backward mode warping, note
75-
that `InvWarpedView` is created by supplying the forward
76-
transformation. The given transformation `tinv` must accept a
77-
`SVector` as input and support `inv(tinv)`. A useful package to
78-
create a wide variety of such transformations is
79-
[CoordinateTransformations.jl](https://github.com/FugroRoames/CoordinateTransformations.jl).
80-
81-
When invoking `wv[I]`, values for `img` must be reconstructed at
82-
arbitrary locations `inv(tinv)(I)`. `InvWarpedView` serves as a
83-
wrapper around [`WarpedView`](@ref) which takes care of
84-
interpolation and extrapolation. The parameters `degree` and
85-
`fill` can be used to specify the b-spline degree and the
86-
extrapolation scheme respectively.
87-
88-
The optional parameter `indices` can be used to specify the
89-
domain of the resulting `wv`. By default the indices are computed
90-
in such a way that `wv` contains all the original pixels in
91-
`img`.
92-
"""
93-
@inline invwarpedview(A::AbstractArray, tinv::Transformation, args...) =
94-
InvWarpedView(A, tinv, args...)
95-
96-
function invwarpedview(
97-
A::AbstractArray{T},
98-
tinv::Transformation,
99-
degree::Union{Linear,Constant},
100-
fill::FillType = _default_fill(T)) where T
101-
invwarpedview(box_extrapolation(A, degree, fill), tinv)
102-
end
68+
passed to `wv[I]` so that `wv[I] == img[inv(tinv)(I)]`.
10369
104-
function invwarpedview(
105-
A::AbstractArray{T},
106-
tinv::Transformation,
107-
indices::Tuple,
108-
degree::Union{Linear,Constant},
109-
fill::FillType = _default_fill(T)) where T
110-
invwarpedview(box_extrapolation(A, degree, fill), tinv, indices)
111-
end
70+
Except for the lazy evaluation, the following two lines are equivalent:
11271
113-
function invwarpedview(
114-
A::AbstractArray,
115-
tinv::Transformation,
116-
fill::FillType)
117-
invwarpedview(A, tinv, Linear(), fill)
118-
end
72+
```julia
73+
warp(img, inv(tform), [indices]; kwargs...)
74+
invwarpedview(img, tform, [indices]; kwargs...)
75+
```
11976
120-
function invwarpedview(
121-
A::AbstractArray,
122-
tinv::Transformation,
123-
indices::Tuple,
124-
fill::FillType)
125-
invwarpedview(A, tinv, indices, Linear(), fill)
77+
For detailed explaination of warp, associated arguments and parameters,
78+
please refer to [`warp`](@ref).
79+
"""
80+
function invwarpedview(A::AbstractArray, tinv::Transformation, indices::Tuple=autorange(A, tinv); kwargs...)
81+
InvWarpedView(box_extrapolation(A; kwargs...), tinv, indices)
12682
end
12783

128-
function invwarpedview(
129-
inner_view::SubArray{T,N,W,I},
130-
tinv::Transformation) where {T,N,W<:InvWarpedView,I<:Tuple{Vararg{AbstractUnitRange}}}
131-
inner = parent(inner_view)
132-
new_inner = InvWarpedView(inner, tinv, autorange(inner, tinv))
133-
inds = autorange(CartesianIndices(inner_view.indices), tinv)
134-
view(new_inner, map(x->IdentityRange(first(x),last(x)), inds)...)
84+
# For SubArray:
85+
# 1. We can exceed the boundary of SubArray by using its parent and thus trick Interpolations in
86+
# order to get better extrapolation result around the border. Otherwise it will just fill it.
87+
# 2. For default indices, we use `IdentityUnitRange`, which guarantees `r[i] == i`, to preserve the view indices.
88+
function invwarpedview(A::SubArray, tinv::Transformation; kwargs...)
89+
default_indices = map(IdentityUnitRange, autorange(CartesianIndices(A.indices), tinv))
90+
invwarpedview(A, tinv, default_indices; kwargs...)
13591
end
136-
137-
function invwarpedview(
138-
inner_view::SubArray{T,N,W,I},
139-
tinv::Transformation,
140-
indices::Tuple) where {T,N,W<:InvWarpedView,I<:Tuple{Vararg{AbstractUnitRange}}}
141-
inner = parent(inner_view)
92+
function invwarpedview(A::SubArray, tinv::Transformation, indices::Tuple; kwargs...)
93+
inner = parent(A)
14294
new_inner = InvWarpedView(inner, tinv, autorange(inner, tinv))
14395
view(new_inner, indices...)
14496
end

0 commit comments

Comments
 (0)