diff --git a/src/ColorVectorSpace.jl b/src/ColorVectorSpace.jl index 176ac00..e8811dc 100644 --- a/src/ColorVectorSpace.jl +++ b/src/ColorVectorSpace.jl @@ -4,11 +4,28 @@ module ColorVectorSpace using ColorTypes, FixedPointNumbers, Compat, Base.Cartesian -import Base: ==, +, -, *, /, .+, .-, .*, ./, ^, < +import Base: ==, +, -, *, /, .+, .-, .*, ./, ^, <, ~ import Base: abs, abs2, clamp, convert, copy, div, eps, isfinite, isinf, - isnan, isless, length, one, promote_array_type, promote_rule, zero, + isnan, isless, length, mapreduce, norm, one, promote_array_type, promote_rule, zero, trunc, floor, round, ceil, bswap, - mod, rem, atan2, hypot + mod, rem, atan2, hypot, max, min + +# The unaryOps +import Base: conj, sin, cos, tan, sinh, cosh, tanh, + asin, acos, atan, asinh, acosh, atanh, + sec, csc, cot, asec, acsc, acot, + sech, csch, coth, asech, acsch, acoth, + sinc, cosc, cosd, cotd, cscd, secd, + sind, tand, acosd, acotd, acscd, asecd, + asind, atand, rad2deg, deg2rad, + log, log2, log10, log1p, exponent, exp, + exp2, expm1, cbrt, sqrt, erf, + erfc, erfcx, erfi, dawson, + significand, lgamma, + gamma, lfact, frexp, modf, airy, airyai, + airyprime, airyaiprime, airybi, airybiprime, + besselj0, besselj1, bessely0, bessely1, + eta, zeta, digamma typealias AbstractGray{T} Color{T,1} typealias TransparentRGB{C<:AbstractRGB,T} TransparentColor{C,T,4} @@ -20,9 +37,14 @@ typealias TransparentGrayUfixed{C<:AbstractGray,T<:Ufixed} TransparentColor{C,T, @compat typealias MathTypes Union{AbstractRGB,TransparentRGB,AbstractGray,TransparentRGB} -export sumsq - ## Generic algorithms +if VERSION >= v"0.4-" + mapreduce(f, op::Base.ShortCircuiting, a::MathTypes) = f(a) # ambiguity + mapreduce(f, op, a::MathTypes) = f(a) +else + mapreduce(f, op, a::MathTypes) = Base.evaluate(f, a) +end + for f in (:trunc, :floor, :round, :ceil, :eps, :bswap) @eval $f{T}(g::Gray{T}) = Gray{T}($f(gray(g))) @eval @vectorize_1arg Gray $f @@ -127,11 +149,11 @@ isinf{T<:Ufixed}(c::Colorant{T}) = false isinf{T<:AbstractFloat}(c::AbstractRGB{T}) = isinf(red(c)) || isinf(green(c)) || isinf(blue(c)) isinf(c::TransparentRGBFloat) = isinf(red(c)) || isinf(green(c)) || isinf(blue(c)) || isinf(alpha(c)) abs(c::AbstractRGB) = abs(red(c))+abs(green(c))+abs(blue(c)) # should this have a different name? -abs{T<:Ufixed}(c::AbstractRGB{T}) = float32(red(c))+float32(green(c))+float32(blue(c)) # should this have a different name? +abs{T<:Ufixed}(c::AbstractRGB{T}) = Float32(red(c))+Float32(green(c))+Float32(blue(c)) # should this have a different name? abs(c::TransparentRGB) = abs(red(c))+abs(green(c))+abs(blue(c))+abs(alpha(c)) # should this have a different name? -abs{T<:Ufixed}(c::TransparentRGB{T}) = float32(red(c))+float32(green(c))+float32(blue(c))+float32(alpha(c)) # should this have a different name? -sumsq(c::AbstractRGB) = red(c)^2+green(c)^2+blue(c)^2 -sumsq{T<:Ufixed}(c::AbstractRGB{T}) = float32(red(c))^2+float32(green(c))^2+float32(blue(c))^2 +abs{T<:Ufixed}(c::TransparentRGB{T}) = Float32(red(c))+Float32(green(c))+Float32(blue(c))+Float32(alpha(c)) # should this have a different name? +abs2(c::AbstractRGB) = red(c)^2+green(c)^2+blue(c)^2 +abs2{T<:Ufixed}(c::AbstractRGB{T}) = Float32(red(c))^2+Float32(green(c))^2+Float32(blue(c))^2 one{C<:AbstractRGB}(::Type{C}) = C(1,1,1) one{C<:TransparentRGB}(::Type{C}) = C(1,1,1,1) @@ -171,6 +193,26 @@ typemax{C<:AbstractRGB}(::Type{C}) = one(C) # Scalar Gray copy(c::AbstractGray) = c +const unaryOps = (:-, :~, :conj, :abs, + :sin, :cos, :tan, :sinh, :cosh, :tanh, + :asin, :acos, :atan, :asinh, :acosh, :atanh, + :sec, :csc, :cot, :asec, :acsc, :acot, + :sech, :csch, :coth, :asech, :acsch, :acoth, + :sinc, :cosc, :cosd, :cotd, :cscd, :secd, + :sind, :tand, :acosd, :acotd, :acscd, :asecd, + :asind, :atand, :rad2deg, :deg2rad, + :log, :log2, :log10, :log1p, :exponent, :exp, + :exp2, :expm1, :cbrt, :sqrt, :erf, + :erfc, :erfcx, :erfi, :dawson, + :significand, :lgamma, + :gamma, :lfact, :frexp, :modf, :airy, :airyai, + :airyprime, :airyaiprime, :airybi, :airybiprime, + :besselj0, :besselj1, :bessely0, :bessely1, + :eta, :zeta, :digamma) +for op in unaryOps + @eval ($op)(c::AbstractGray) = $op(gray(c)) +end + (*)(f::Real, c::AbstractGray) = base_colorant_type(c){multype(typeof(f),eltype(c))}(f*gray(c)) (*)(f::Real, c::TransparentGray) = base_colorant_type(c){multype(typeof(f),eltype(c))}(f*gray(c), f*alpha(c)) (*)(c::AbstractGray, f::Real) = (*)(f, c) @@ -180,10 +222,12 @@ copy(c::AbstractGray) = c (.*)(f::Real, c::TransparentGray) = (*)(f, c) (.*)(c::TransparentGray, f::Real) = (*)(f, c) (/)(c::AbstractGray, f::Real) = (one(f)/f)*c +(/)(n::Number, c::AbstractGray) = n/gray(c) (/)(c::TransparentGray, f::Real) = (one(f)/f)*c (/)(c::AbstractGray, f::Integer) = (one(eltype(c))/f)*c (/)(c::TransparentGray, f::Integer) = (one(eltype(c))/f)*c (./)(c::AbstractGray, f::Real) = c/f +(./)(n::Number, c::AbstractGray) = n/gray(c) (./)(c::TransparentGray, f::Real) = c/f (+){S,T}(a::AbstractGray{S}, b::AbstractGray{T}) = color_rettype(a,b){sumtype(S,T)}(gray(a)+gray(b)) (+)(a::TransparentGray, b::TransparentGray) = color_rettype(a,b){sumtype(eltype(a),eltype(b))}(gray(a)+gray(b),alpha(a)+alpha(b)) @@ -206,6 +250,14 @@ div(a::AbstractGray, b::AbstractGray) = div(gray(a), gray(b)) (.-)(a::AbstractGray, b::Number) = gray(a)-b (.+)(a::Number, b::AbstractGray) = a+gray(b) (.-)(a::Number, b::AbstractGray) = a-gray(b) +max{T<:AbstractGray}(a::T, b::T) = T(max(gray(a),gray(b))) +max(a::AbstractGray, b::AbstractGray) = max(promote(a,b)...) +max(a::Number, b::AbstractGray) = max(promote(a,b)...) +max(a::AbstractGray, b::Number) = max(promote(a,b)...) +min{T<:AbstractGray}(a::T, b::T) = T(min(gray(a),gray(b))) +min(a::AbstractGray, b::AbstractGray) = min(promote(a,b)...) +min(a::Number, b::AbstractGray) = min(promote(a,b)...) +min(a::AbstractGray, b::Number) = min(promote(a,b)...) isfinite{T<:AbstractFloat}(c::AbstractGray{T}) = isfinite(gray(c)) isfinite(c::TransparentGrayFloat) = isfinite(gray(c)) && isfinite(alpha(c)) @@ -213,15 +265,13 @@ isnan{T<:AbstractFloat}(c::AbstractGray{T}) = isnan(gray(c)) isnan(c::TransparentGrayFloat) = isnan(gray(c)) && isnan(alpha(c)) isinf{T<:AbstractFloat}(c::AbstractGray{T}) = isinf(gray(c)) isinf(c::TransparentGrayFloat) = isinf(gray(c)) && isnan(alpha(c)) -abs(c::AbstractGray) = abs(gray(c)) # should this have a different name? +norm(c::AbstractGray) = abs(gray(c)) abs(c::TransparentGray) = abs(gray(c))+abs(alpha(c)) # should this have a different name? -abs{T<:Ufixed}(c::AbstractGray{T}) = float32(gray(c)) # should this have a different name? -abs(c::TransparentGrayUfixed) = float32(gray(c)) + float32(alpha(c)) # should this have a different name? -sumsq(x::Real) = x^2 -sumsq(c::AbstractGray) = gray(c)^2 -sumsq{T<:Ufixed}(c::AbstractGray{T}) = float32(gray(c))^2 -sumsq(c::TransparentGray) = gray(c)^2+alpha(c)^2 -sumsq(c::TransparentGrayUfixed) = float32(gray(c))^2 + float32(alpha(c))^2 +abs(c::TransparentGrayUfixed) = Float32(gray(c)) + Float32(alpha(c)) # should this have a different name? +abs2(c::AbstractGray) = gray(c)^2 +abs2{T<:Ufixed}(c::AbstractGray{T}) = Float32(gray(c))^2 +abs2(c::TransparentGray) = gray(c)^2+alpha(c)^2 +abs2(c::TransparentGrayUfixed) = Float32(gray(c))^2 + Float32(alpha(c))^2 atan2(x::Gray, y::Gray) = atan2(convert(Real, x), convert(Real, y)) hypot(x::Gray, y::Gray) = hypot(convert(Real, x), convert(Real, y)) @@ -358,4 +408,6 @@ end promote_rule{C1<:Colorant,C2<:Colorant}(::Type{C1}, ::Type{C2}) = color_rettype(C1,C2){promote_type(eltype(C1), eltype(C2))} promote_rule{T<:Real,C<:AbstractGray}(::Type{T}, ::Type{C}) = promote_type(T, eltype(C)) +@deprecate sumsq abs2 + end diff --git a/test/runtests.jl b/test/runtests.jl index 7aadb03..8b62986 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,6 @@ module ColorVectorSpaceTests -using FactCheck, ColorVectorSpace, ColorTypes, FixedPointNumbers, Compat +using FactCheck, Base.Test, ColorVectorSpace, ColorTypes, FixedPointNumbers, Compat macro test_colortype_approx_eq(a, b) :(test_colortype_approx_eq($(esc(a)), $(esc(b)), $(string(a)), $(string(b)))) @@ -28,6 +28,8 @@ facts("Colortypes") do @test_colortype_approx_eq cf^2 Gray{Float32}(0.01) @test_colortype_approx_eq cf^3.0f0 Gray{Float32}(0.001) @fact eltype(2.0*cf) --> Float64 + @fact abs2(ccmp) --> 0.2f0^2 + @fact sumabs2(ccmp) --> 0.2f0^2 cu = Gray{U8}(0.1) @fact 2*cu --> Gray(2*cu.val) @fact 2.0f0*cu --> Gray(2.0f0*cu.val) @@ -70,6 +72,7 @@ facts("Colortypes") do @fact (acf/Gray{Float32}(2))[1] --> roughly(0.05f0) @fact (acu/2)[1] --> Gray(gray(acu[1])/2) @fact (acf/2)[1] --> roughly(Gray{Float32}(0.05f0)) + @fact sumabs2([cf,ccmp]) --> roughly(0.05f0) @fact gray(0.8) --> 0.8 end @@ -85,6 +88,24 @@ facts("Colortypes") do @fact isless(0.5, g1) --> false @fact g1 < 0.5 --> true @fact 0.5 < g1 --> false + @fact @inferred(max(g1, g2)) --> g2 + @fact @inferred(max(g1, 0.1)) --> 0.2 + @fact @inferred(min(g1, g2)) --> g1 + @fact @inferred(min(g1, 0.1)) --> 0.1 + end + + context("Unary operations with Gray") do + for g in (Gray(0.4), Gray{U8}(0.4)) + for op in ColorVectorSpace.unaryOps + try + v = @eval $op(gray(g)) # if this fails, don't bother + @fact $op(g) --> v + end + end + end + u = U8(0.4) + @fact ~Gray(u) --> Gray(~u) + @fact -Gray(u) --> Gray(-u) end context("Arithmetic with GrayA") do @@ -138,6 +159,7 @@ facts("Colortypes") do @fact RGB(1, Inf, 0.5) --> isinf @fact RGB(1, Inf, 0.5) --> not(isnan) @fact abs(RGB(0.1,0.2,0.3)) --> roughly(0.6) + @fact sumabs2(RGB(0.1,0.2,0.3)) --> roughly(0.14) acu = RGB{U8}[cu] acf = RGB{Float32}[cf]