diff --git a/src/core_types.jl b/src/core_types.jl index 4c67926d..9f17be77 100644 --- a/src/core_types.jl +++ b/src/core_types.jl @@ -150,17 +150,18 @@ Base.inv(r::RotMatrix) = RotMatrix(r.mat') end """ - struct Angle2d{T} <: Rotation{2,T} - theta::T + struct Angle2d{T,A} <: Rotation{2,T} + theta::A end A 2×2 rotation matrix parameterized by a 2D rotation by angle. Only the angle is stored inside the `Angle2d` type, values of `getindex` etc. are computed on the fly. """ -struct Angle2d{T} <: Rotation{2,T} - theta::T - Angle2d{T}(theta) where T = new{T}(theta) +struct Angle2d{T,A} <: Rotation{2,T} + theta::A + Angle2d{T,A}(theta::Number) where{T,A} = new{T,A}(theta) + Angle2d{T}(theta::A) where {T,A} = new{T,A}(theta) end @inline function Angle2d(theta) @@ -171,6 +172,7 @@ params(r::Angle2d) = SVector{1}(r.theta) Angle2d(r::Rotation{2}) = Angle2d(rotation_angle(r)) Angle2d{T}(r::Rotation{2}) where {T} = Angle2d{T}(rotation_angle(r)) +Angle2d{T,A}(r::Rotation{2}) where{T,A} = Angle2d{T,A}(rotation_angle(r)) Base.one(::Type{A}) where {A<: Angle2d} = A(0) diff --git a/src/euler_types.jl b/src/euler_types.jl index 4f6f4a4b..e9f0221a 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -12,10 +12,12 @@ for axis in [:X, :Y, :Z] RotType = Symbol("Rot" * string(axis)) @eval begin - struct $RotType{T} <: Rotation{3,T} - theta::T - $RotType{T}(theta) where {T} = new{T}(theta) - $RotType{T}(r::$RotType) where {T} = new{T}(r.theta) + struct $RotType{T,A} <: Rotation{3,T} + theta::A + $RotType{T,A}(theta) where{T,A} = new{T,A}(theta) + $RotType{T}(theta::A) where {T,A} = new{T,A}(theta) + $RotType{T,A}(r::$RotType) where{T,A} = new{T,A}(r.theta) + $RotType{T}(r::$RotType) where {T} = $RotType{T}(r.theta) end @inline function $RotType(theta) @@ -220,11 +222,13 @@ for axis1 in [:X, :Y, :Z] InvRotType = Symbol("Rot" * string(axis2) * string(axis1)) @eval begin - struct $RotType{T} <: Rotation{3,T} - theta1::T - theta2::T - $RotType{T}(theta1, theta2) where {T} = new{T}(theta1, theta2) - $RotType{T}(r::$RotType) where {T} = new{T}(r.theta1, r.theta2) + struct $RotType{T,A} <: Rotation{3,T} + theta1::A + theta2::A + $RotType{T,A}(theta1,theta2) where{T,A} = new{T,A}(theta1, theta2) + $RotType{T}(theta1::A, theta2::A) where {T,A} = new{T,A}(theta1, theta2) + $RotType{T,A}(r::$RotType) where{T,A} = new{T,A}(r.theta1, r.theta2) + $RotType{T}(r::$RotType) where {T} = $RotType{T}(r.theta1, r.theta2) end @inline function $RotType(theta1, theta2) @@ -513,12 +517,14 @@ for axis1 in [:X, :Y, :Z] Rot0Type = Symbol("Rot" * string(axis0)) @eval begin - struct $RotType{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T - $RotType{T}(theta1, theta2, theta3) where {T} = new{T}(theta1, theta2, theta3) - $RotType{T}(r::$RotType) where {T} = new{T}(r.theta1, r.theta2, r.theta3) + struct $RotType{T,A} <: Rotation{3,T} + theta1::A + theta2::A + theta3::A + $RotType{T,A}(theta1,theta2,theta3) where{T,A} = new{T,A}(theta1, theta2, theta3) + $RotType{T}(theta1::A, theta2::A, theta3::A) where {T,A} = new{T,A}(theta1, theta2, theta3) + $RotType{T,A}(r::$RotType) where{T,A} = new{T,A}(r.theta1, r.theta2, r.theta3) + $RotType{T}(r::$RotType) where {T} = $RotType{T}(r.theta1, r.theta2, r.theta3) end @inline function $RotType(theta1, theta2, theta3) diff --git a/test/2d.jl b/test/2d.jl index df004cef..4b4c9f23 100644 --- a/test/2d.jl +++ b/test/2d.jl @@ -18,6 +18,9 @@ using Unitful # don't extraneously contain those units (see issue #55) @test eltype(Angle2d(10u"°")) <: Real @test eltype(Angle2d(20u"rad")) <: Real + + # Check exactitude of degree rotations + @test Angle2d(360u"°") == [1 0;0 1] end ############################### diff --git a/test/rotation_tests.jl b/test/rotation_tests.jl index b1f993a3..b62394e7 100644 --- a/test/rotation_tests.jl +++ b/test/rotation_tests.jl @@ -470,7 +470,7 @@ all_types = (RotMatrix{3}, AngleAxis, RotationVec, rxyz = RotXYZ(1.0, 2.0, 3.0) show(io, MIME("text/plain"), rxyz) str = String(take!(io)) - @test startswith(str, "3×3 RotXYZ{Float64}") && occursin("(1.0, 2.0, 3.0):", str) + @test startswith(str, "3×3 RotXYZ{Float64,") && occursin("(1.0, 2.0, 3.0):", str) end ######################################################################### @@ -491,4 +491,16 @@ all_types = (RotMatrix{3}, AngleAxis, RotationVec, @test Rotations.params(MRP(p1,p2,p3)) == [p1,p2,p3] @test Rotations.params(RodriguesParam(p1,p2,p3)) == [p1,p2,p3] end + + @testset "Exact rotations in degrees" begin + using Unitful: ° + hascoeffs(m, l...) = all(l) do ((i,j),y) m[i,j] == y end + @test hascoeffs(RotX(30°), (1,1)=>1, (2,3)=>-1/2, (3,2)=>1/2) + @test hascoeffs(RotX(60°), (1,1)=>1, (2,2)=>1/2, (3,3)=>1/2) + @test hascoeffs(RotXY(90°,60°), (1,1)=>1/2,(2,3)=>-1/2,(3,2)=>1) + @test hascoeffs(RotXYZ(30°,60°,90°), + (1,2)=>-1/2,(2,3)=>-1/4,(3,1)=>1/2) + # FIXME: this should also have (3,2)=>3/4, but exactness here is as + # a *product* of trigonometric functions simplifying √3... + end end