From bf3803b8df3c0ee528b39a08815b76e8f31dd537 Mon Sep 17 00:00:00 2001 From: Yuto Horikawa Date: Sat, 25 Nov 2023 21:47:18 +0900 Subject: [PATCH] Add more methods to `quat` (#132) * add more methods to `quat` * fix typo * Fix docstring in `src/Quaternion.jl` Co-authored-by: Seth Axen * avoid tests on unbound_args * add more tests on `quat` * add more tests on `quat` * replace `function quat end` with `quat` --------- Co-authored-by: Seth Axen --- src/Quaternion.jl | 38 ++++++++++++++++++++++++++++++++++---- test/Quaternion.jl | 12 ++++++++++++ test/runtests.jl | 4 +++- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/Quaternion.jl b/src/Quaternion.jl index f2f5562..e05dcdd 100644 --- a/src/Quaternion.jl +++ b/src/Quaternion.jl @@ -28,9 +28,9 @@ Base.promote_rule(::Type{Quaternion{T}}, ::Type{S}) where {T <: Real, S <: Real} Base.promote_rule(::Type{Quaternion{T}}, ::Type{Quaternion{S}}) where {T <: Real, S <: Real} = Quaternion{promote_type(T, S)} """ - quat(r, [i, j, k]) + quat(w, [x, y, z]) -Convert real numbers or arrays to quaternion. `i, j, k` defaults to zero. +Convert real numbers or arrays to quaternion. `x, y, z` defaults to zero. # Examples ```jldoctest @@ -49,8 +49,12 @@ julia> quat([1, 2, 3]) """ quat -quat(p, v1, v2, v3) = Quaternion(p, v1, v2, v3) -quat(x) = Quaternion(x) +quat(q::Quaternion) = q +quat(s::Real) = Quaternion(s) +quat(s::Real, v1::Real, v2::Real, v3::Real) = Quaternion(s, v1, v2, v3) + +## Array operations on quaternions ## +quat(A::AbstractArray{<:Quaternion}) = A function quat(A::AbstractArray{T}) where T if !isconcretetype(T) error("`quat` not defined on abstractly-typed arrays; please convert to a more specific type") @@ -58,6 +62,32 @@ function quat(A::AbstractArray{T}) where T convert(AbstractArray{typeof(quat(zero(T)))}, A) end +""" + quat(T::Type) + +Return an appropriate type that can represent a value of type `T` as a quaternion. +Equivalent to `typeof(quat(zero(T)))`. + +# Examples +```jldoctest +julia> quat(Quaternion{Int}) +Quaternion{Int64} + +julia> quat(Int) +Quaternion{Int64} +``` +""" +quat(::Type{T}) where {T<:Real} = Quaternion{T} +quat(::Type{Quaternion{T}}) where {T<:Real} = Quaternion{T} + +quat(::Missing) = missing +# Same definitioin as in Base: https://github.com/JuliaLang/julia/blob/v1.9.3/base/missing.jl#L111-L115 +quat(::Type{Missing}) = Missing +function quat(::Type{Union{T, Missing}}) where T + T === Any && throw(MethodError(quat, (Any,))) # To prevent StackOverflowError + Union{quat(T), Missing} +end + """ real(T::Type{<:Quaternion}) diff --git a/test/Quaternion.jl b/test/Quaternion.jl index 53b36bc..737e397 100644 --- a/test/Quaternion.jl +++ b/test/Quaternion.jl @@ -93,6 +93,18 @@ end @test quat(Quaternion(1, 2, 3, 4)) === Quaternion(1, 2, 3, 4) @test quat([2, 3, 4]) == Quaternion{Int}[2, 3, 4] @test_throws ErrorException quat(Real[1,2,3]) + @test quat(Quaternion[1,2]) == Quaternion[1,2] + + @test quat(Int) === Quaternion{Int} + @test quat(Float32) === Quaternion{Float32} + @test quat(Quaternion{Int}) === Quaternion{Int} + @test quat(Quaternion{Float32}) === Quaternion{Float32} + + # Note that `quat(1,missing,0,0)` throws an error. + # This is the same behavior as `complex(1,missing)`. + @test quat(missing) === missing + @test quat(Missing) === Missing + @test quat(Union{Missing, Int}) === Union{Missing, Quaternion{Int}} end @testset "random generation" begin diff --git a/test/runtests.jl b/test/runtests.jl index 4777001..9c938de 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,7 +3,9 @@ using Quaternions using Aqua using RealDot -Aqua.test_all(Quaternions) +# Avoid tests on unbound_args. +# https://github.com/JuliaGeometry/Quaternions.jl/pull/132#discussion_r1383817950 +Aqua.test_all(Quaternions, unbound_args=false) include("helpers.jl") include("Quaternion.jl")