From cd2060041d3906cd9a0ad5100bf7f30dd21267fd Mon Sep 17 00:00:00 2001 From: rafaqz Date: Sat, 28 Sep 2024 19:40:17 +0200 Subject: [PATCH 1/2] add cycled dims and crs capacity --- src/Extents.jl | 49 +++++++++++++++++++++++++++++++++++++++--------- test/runtests.jl | 9 +++++---- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/Extents.jl b/src/Extents.jl index 8febd59..e73c910 100644 --- a/src/Extents.jl +++ b/src/Extents.jl @@ -8,6 +8,34 @@ const ORDER_DOC = """ The order of dimensions is ignored in all cases. """ +abstract type AbstractBounds{T} end + +Base.getindex(b::AbstractBounds, i) = b.bounds[i] +Base.first(b::AbstractBounds) = b[1] +Base.last(b::AbstractBounds) = b[2] +Base.iterate(b::AbstractBounds, args...) = iterate(b.bounds, args...) + +struct Bounds{T,C} <: AbstractBounds{T} + bounds::Tuple{T,T} + crs::C +end +Bounds(bounds::Tuple{<:Any,<:Any}; crs=nothing) = Bounds(bounds, crs) +Bounds(a, b; kw...) = Bounds(promote(a, b); kw...) + +Base.show(io::IO, bs::Bounds) = + print(io, "$(typeof(bs).name.wrapper)($(bs[1]), $(bs[2]))") + +struct Cyclic{T,C} <: AbstractBounds{T} + bounds::Tuple{T,T} + cycle::Tuple{T,T} + crs::C +end +Cyclic(a, b; kw...) = Cyclic(promote(a, b); kw...) +Cyclic(bounds::Tuple{<:Any,<:Any}; cycle, crs=nothing) = Cyclic(bounds, cycle, crs) + +Base.show(io::IO, bs::Cyclic) = + print(io, "$(typeof(bs).name.wrapper)($(bs[1]), $(bs[2]); cycle=$(bs.cycle))") + """ Extent @@ -38,7 +66,7 @@ julia> values(ext) struct Extent{K,V} bounds::NamedTuple{K,V} function Extent{K,V}(bounds::NamedTuple{K,V}) where {K,V} - bounds = map(b -> promote(b...), bounds) + bounds = map(_promote, bounds) new{K,typeof(values(bounds))}(bounds) end end @@ -47,6 +75,9 @@ Extent{K}(vals::V) where {K,V} = Extent{K,V}(NamedTuple{K,V}(vals)) Extent{K1}(vals::NamedTuple{K2,V}) where {K1,K2,V} = Extent(NamedTuple{K1}(vals)) Extent(vals::NamedTuple{K,V}) where {K,V} = Extent{K,V}(vals) +_promote(b::Tuple) = promote(b...) +_promote(b::AbstractBounds) = b + bounds(ext::Extent) = getfield(ext, :bounds) @inline function Base.getproperty(ext::Extent, key::Symbol) @@ -230,7 +261,7 @@ $DE_9IM_DOC contains(a::Extent, b::Extent; strict=false) = _do_bounds(all, _contain, a, b, strict) # Must contain interior points, not just boundary -_contain(a::Tuple, b::Tuple) = _cover(a, b) && _hasinterior(b) +_contain(a, b) = _cover(a, b) && _hasinterior(b) """ within(a::Extent, b::Extent; strict=false) @@ -270,7 +301,7 @@ $DE_9IM_DOC """ intersects(a::Extent, b::Extent; strict=false) = _do_bounds(all, _intersect, a, b, strict) -_intersect((min_a, max_a)::Tuple, (min_b, max_b)::Tuple) = +_intersect((min_a, max_a), (min_b, max_b)) = (min_a <= min_b && max_a >= min_b) || (min_b <= min_a && max_b >= min_a) """ @@ -316,7 +347,7 @@ function touches(a::Extent, b::Extent; strict=false) end end -_touch((min_a, max_a)::Tuple, (min_b, max_b)::Tuple) = (min_a == max_b || max_a == min_b) +_touch((min_a, max_a), (min_b, max_b)) = (min_a == max_b || max_a == min_b) """ @@ -337,7 +368,7 @@ $DE_9IM_DOC """ covers(a::Extent, b::Extent; strict=false) = _do_bounds(all, _cover, a, b, strict) -_cover((min_a, max_a)::Tuple, (min_b, max_b)::Tuple) = (min_a <= min_b && max_a >= max_b) +_cover((min_a, max_a), (min_b, max_b)) = (min_a <= min_b && max_a >= max_b) """ coveredby(a::Extent, b::Extent; strict=false) @@ -400,13 +431,13 @@ $DE_9IM_DOC """ equals(a::Extent, b::Extent; strict=false) = _do_bounds(all, _equal, a, b, strict) -_equal(a::Tuple, b::Tuple) = a == b +_equal(a, b) = a == b # Handle `nothing` bounds for all methods for f in (:_intersect, :_cover, :_contain, :_touch, :_equal) @eval begin - $f(::Nothing, ::Tuple) = nothing - $f(::Tuple, ::Nothing) = nothing + $f(::Nothing, ::Union{Tuple,AbstractBounds}) = nothing + $f(::Union{Tuple,AbstractBounds}, ::Nothing) = nothing $f(::Nothing, ::Nothing) = nothing end end @@ -483,6 +514,6 @@ _skipnothing(::Nothing, vals...) = _skipnothing(vals...) _skipnothing() = () _hasinterior(ex::Extent) = all(map(_hasinterior, bounds(ex))) -_hasinterior((min, max)::Tuple) = min != max +_hasinterior((min, max)) = min != max end diff --git a/test/runtests.jl b/test/runtests.jl index c2b7e9f..5cab290 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,6 +6,7 @@ const E = Extent ex1 = Extent(X=(1, 2), Y=(3, 4)) ex2 = Extent(Y=(3, 4), X=(1, 2)) ex3 = Extent(X=(1, 2), Y=(3, 4), Z=(5.0, 6.0)) +ex1 = Extent(X=Extents.Bounds(1, 2), Y=(3, 4)) struct HasExtent end Extents.extent(::HasExtent) = Extent(X=(0, 1), Y=(0, 1)) @@ -73,7 +74,7 @@ end @testset "covers" begin # An extent contains itself - @test Extents.covers(E(X=(2, 3), Y=(3, 4)), E(X=(2, 3), Y=(3, 4))) == true + @test Extents.covers(E(X=Extents.Bounds(2, 3), Y=(3, 4)), E(X=(2, 3), Y=(3, 4))) == true # A larger extent covers a smaller one inside it @test Extents.covers(E(X=(0, 4), Y=(1, 5)), E(X=(2, 3), Y=(3, 4))) == true # Intersecting but not covers in one dimension @@ -103,7 +104,7 @@ end @testset "coveredby" begin # An extent contains itself - @test Extents.coveredby(E(X=(2, 3), Y=(3, 4)), E(X=(2, 3), Y=(3, 4))) == true + @test Extents.coveredby(E(X=Extents.Bounds(2, 3), Y=(3, 4)), E(X=(2, 3), Y=(3, 4))) == true # A larger extent coveredby a smaller one inside it @test Extents.contains(E(X=(0, 4), Y=(1, 5)), E(X=(2, 3), Y=(3, 4))) == true @test Extents.coveredby(E(X=(2, 3), Y=(3, 4)), E(X=(0, 4), Y=(1, 5))) == true @@ -134,7 +135,7 @@ end @testset "contains" begin # An extent contains itself - @test Extents.contains(E(X=(2, 3), Y=(3, 4)), E(X=(2, 3), Y=(3, 4))) == true + @test Extents.contains(E(X=(2, 3), Y=(3, 4)), E(X=(2, 3), Y=Extents.Bounds(3, 4))) == true # A larger extent contains a smaller one inside it @test Extents.contains(E(X=(0, 4), Y=(1, 5)), E(X=(2, 3), Y=(3, 4))) == true # Intersecting but not contains in one dimension @@ -164,7 +165,7 @@ end @testset "within" begin # An extent contains itself - @test Extents.within(E(X=(2, 3), Y=(3, 4)), E(X=(2, 3), Y=(3, 4))) == true + @test Extents.within(E(X=(2, 3), Y=(3, 4)), E(X=Extents.Bounds(2, 3), Y=(3, 4))) == true # A larger extent within a smaller one inside it @test Extents.contains(E(X=(0, 4), Y=(1, 5)), E(X=(2, 3), Y=(3, 4))) == true @test Extents.within(E(X=(2, 3), Y=(3, 4)), E(X=(0, 4), Y=(1, 5))) == true From 13bf62e197744bd722a05769bde4f17d4b32b73a Mon Sep 17 00:00:00 2001 From: Rafael Schouten Date: Fri, 10 Jan 2025 16:19:22 +0100 Subject: [PATCH 2/2] add intervals --- src/Extents.jl | 52 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/Extents.jl b/src/Extents.jl index 0fe6b9b..cd659bb 100644 --- a/src/Extents.jl +++ b/src/Extents.jl @@ -8,32 +8,42 @@ const ORDER_DOC = """ The order of dimensions is ignored in all cases. """ -abstract type AbstractBounds{T} end +abstract type AbstractBounds{L,U,T} end + +const CC = AbstractBounds{:closed,:closed} +const CO = AbstractBounds{:closed,:open} +const OC = AbstractBounds{:open,:closed} +const OO = AbstractBounds{:open,:open} + +(::Type{T})(bounds::Tuple{<:Any,<:Any}) where {T<:AbstractBounds{L,U}} where {L,U} = + T(bounds; kw...) Base.getindex(b::AbstractBounds, i) = b.bounds[i] Base.first(b::AbstractBounds) = b[1] Base.last(b::AbstractBounds) = b[2] Base.iterate(b::AbstractBounds, args...) = iterate(b.bounds, args...) -struct Bounds{T,C} <: AbstractBounds{T} +struct Bounds{L,U,T} <: AbstractBounds{L,U,T} bounds::Tuple{T,T} - crs::C + Bounds{L,U}(bounds::Tuple{T,T}) where {L,U,T} = new{L,U,T}(bounds) end -Bounds(bounds::Tuple{<:Any,<:Any}; crs=nothing) = Bounds(bounds, crs) -Bounds(a, b; kw...) = Bounds(promote(a, b); kw...) +Bounds{L,U}(a, b) where {L,U} = Bounds{L,U}((a, b)) +Bounds{L,U}((a, b)::Tuple) where {L,U} = Bounds{L,U}(promote(a, b)) Base.show(io::IO, bs::Bounds) = print(io, "$(typeof(bs).name.wrapper)($(bs[1]), $(bs[2]))") -struct Cyclic{T,C} <: AbstractBounds{T} +struct CyclicBounds{L,U,T,C} <: AbstractBounds{L,U,T} bounds::Tuple{T,T} cycle::Tuple{T,T} - crs::C + CyclicBounds{L,U}(bounds::Tuple{T,T}, cycle::Tuple{T,T}) where {L,U,T,C} = + new{L,U,T,C}(bounds, cycle) end -Cyclic(a, b; kw...) = Cyclic(promote(a, b); kw...) -Cyclic(bounds::Tuple{<:Any,<:Any}; cycle, crs=nothing) = Cyclic(bounds, cycle, crs) +CyclicBounds{L,U}(a, b; kw...) where {L,U} = CyclicBounds{L,U}((a, b); kw...) +CyclicBounds{L,U}((a, b)::Tuple{<:Any,<:Any}; cycle) where {L,U} = + CyclicBounds{L,U}(promote(a, b), cycle) -Base.show(io::IO, bs::Cyclic) = +Base.show(io::IO, bs::CyclicBounds) = print(io, "$(typeof(bs).name.wrapper)($(bs[1]), $(bs[2]); cycle=$(bs.cycle))") """ @@ -357,6 +367,7 @@ intersects(a::Extent, b::Extent; strict=false) = _do_bounds(all, _intersect, a, _intersect((min_a, max_a), (min_b, max_b)) = (min_a <= min_b && max_a >= min_b) || (min_b <= min_a && max_b >= min_a) + """ disjoint(a::Extent, b::Extent; strict=false) @@ -400,8 +411,17 @@ function touches(a::Extent, b::Extent; strict=false) end end -_touch((min_a, max_a), (min_b, max_b)) = (min_a == max_b || max_a == min_b) - +_touch((min_a, max_a)::T, (min_b, max_b)::T ) where T = (min_a == max_b || max_a == min_b) +_touch((min_a, max_a)::CC, (min_b, max_b)::CO) = max_a == min_b +_touch((min_a, max_a)::OO, (min_b, max_b)::OC) = min_a == max_b +_touch((min_a, max_a)::CC, (min_b, max_b)::OC) = min_a == max_b +_touch((min_a, max_a)::OO, (min_b, max_b)::CO) = max_a == min_b +_touch((min_a, max_a)::CO, (min_b, max_b)::CC) = min_a == max_b +_touch((min_a, max_a)::OC, (min_b, max_b)::OO) = min_a == max_b +_touch((min_a, max_a)::OC, (min_b, max_b)::CC) = max_a == min_b +_touch((min_a, max_a)::CO, (min_b, max_b)::OO) = max_a == min_b +_touch((min_a, max_a)::CO, (min_b, max_b)::OC) = false +_touch((min_a, max_a)::OC, (min_b, max_b)::CO) = false """ covers(a::Extent, b::Extent; strict=false) @@ -421,7 +441,9 @@ $DE_9IM_DOC """ covers(a::Extent, b::Extent; strict=false) = _do_bounds(all, _cover, a, b, strict) -_cover((min_a, max_a), (min_b, max_b)) = (min_a <= min_b && max_a >= max_b) +_cover((min_a, max_a)::AbstractBounds{T,T}, (min_b, max_b)::AbstractBounds{T,T}) where {T} = + (min_a <= min_b && max_a >= max_b) +_cover((min_a, max_a)::CO, (min_b, max_b)) = (min_a <= min_b && max_a >= max_b) """ coveredby(a::Extent, b::Extent; strict=false) @@ -483,8 +505,10 @@ $ORDER_DOC $DE_9IM_DOC """ equals(a::Extent, b::Extent; strict=false) = _do_bounds(all, _equal, a, b, strict) +equals(a::Extent{L,U}, b::Extent{L,U}; strict=false) where {L,U} = _do_bounds(all, _equal, a, b, strict) -_equal(a, b) = a == b +_equal(a::AbstractBounds{L,U}, b::AbstractBounds{L,U}) where {L,U} = a == b +_equal(a, b) = false # Handle `nothing` bounds for all methods for f in (:_intersect, :_cover, :_contain, :_touch, :_equal)