From 385fbf13c347a64a4f0959207cde6c6a04771435 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 25 Mar 2017 11:36:16 -0400 Subject: [PATCH 01/13] New abstract type syntax. --- src/core_types.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core_types.jl b/src/core_types.jl index 36dc5f3c..cd12f7b7 100644 --- a/src/core_types.jl +++ b/src/core_types.jl @@ -1,10 +1,10 @@ """ - abstract Rotation{N,T} <: StaticMatrix{T} + abstract type Rotation{N,T} <: StaticMatrix{T} An abstract type representing `N`-dimensional rotations. More abstractly, they represent unitary (orthogonal) `N`×`N` matrices. """ -abstract Rotation{N,T} <: StaticMatrix{T} +abstract type Rotation{N,T} <: StaticMatrix{T} end Base.@pure StaticArrays.Size{N}(::Type{Rotation{N}}) = Size(N,N) Base.@pure StaticArrays.Size{N,T}(::Type{Rotation{N,T}}) = Size(N,N) From 2630fc412e82297e1367291fe32ac97d179b7774 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 25 Mar 2017 11:36:36 -0400 Subject: [PATCH 02/13] New inner constructor syntax. --- src/angleaxis_types.jl | 2 +- src/quaternion_types.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/angleaxis_types.jl b/src/angleaxis_types.jl index fb4ef857..e2fef4da 100644 --- a/src/angleaxis_types.jl +++ b/src/angleaxis_types.jl @@ -18,7 +18,7 @@ immutable AngleAxis{T} <: Rotation{3,T} axis_z::T # Ensure axis is normalized - function AngleAxis(θ, x, y, z) + function AngleAxis{T}(θ, x, y, z) where T norm = sqrt(x*x + y*y + z*z) # Not sure what to do with theta?? Should it become theta * norm ? new(θ, x/norm, y/norm, z/norm) diff --git a/src/quaternion_types.jl b/src/quaternion_types.jl index 5602b59f..3d0f4107 100644 --- a/src/quaternion_types.jl +++ b/src/quaternion_types.jl @@ -17,7 +17,7 @@ immutable Quat{T} <: Rotation{3,T} z::T # For the moment we ensure that it is normalized upon construction. - function Quat(w, x, y, z) + function Quat{T}(w, x, y, z) where T norm = copysign(sqrt(w*w + x*x + y*y + z*z), w) # Should this be an error or warning, if it isn't approximately normalized? E.g.: #if norm !≈ 1 From f87aa0943de2057ea82cc7b2b638ddf26fe9c71b Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 25 Mar 2017 11:37:12 -0400 Subject: [PATCH 03/13] Dot syntax for abs applied to arrays. --- src/util.jl | 2 +- test/util_tests.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util.jl b/src/util.jl index 2358df22..89f38b40 100644 --- a/src/util.jl +++ b/src/util.jl @@ -9,7 +9,7 @@ function perpendicular_vector(vec::SVector{3}) T = eltype(vec) # find indices of the two elements of vec with the largest absolute values: - absvec = abs(vec) + absvec = abs.(vec) ind1 = indmax(absvec) # index of largest element @inbounds absvec2 = @SVector [ifelse(i == ind1, typemin(T), absvec[i]) for i = 1 : 3] # set largest element to typemin(T) ind2 = indmax(absvec2) # index of second-largest element diff --git a/test/util_tests.jl b/test/util_tests.jl index 0807fbf7..577cf167 100644 --- a/test/util_tests.jl +++ b/test/util_tests.jl @@ -3,7 +3,7 @@ for i = 1 : 100 vec = rand(SVector{3, Float64}) perp = Rotations.perpendicular_vector(vec) - @test norm(perp) >= maximum(abs(vec)) + @test norm(perp) >= maximum(abs.(vec)) @test isapprox(dot(vec, perp), 0.; atol = 1e-10) end end From 52d109ea3456272bb5bd6d7e502c6b5ff65b1abd Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 25 Mar 2017 11:41:36 -0400 Subject: [PATCH 04/13] ::Int instead of ::Integer in getindex methods, following StaticArrays. --- src/angleaxis_types.jl | 4 ++-- src/core_types.jl | 2 +- src/euler_types.jl | 42 ++++++++++++++++++++--------------------- src/quaternion_types.jl | 4 ++-- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/angleaxis_types.jl b/src/angleaxis_types.jl index e2fef4da..ddf26170 100644 --- a/src/angleaxis_types.jl +++ b/src/angleaxis_types.jl @@ -31,7 +31,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{AA}){AA <: AngleAxis}(t::NTuple{9}) = AA(Quat(t)) -@inline Base.getindex(aa::AngleAxis, i::Integer) = Quat(aa)[i] +@inline Base.getindex(aa::AngleAxis, i::Int) = Quat(aa)[i] @inline function Base.convert{R <: RotMatrix}(::Type{R}, aa::AngleAxis) # Rodrigues' rotation formula. @@ -132,7 +132,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{RV}){RV <: RodriguesVec}(t::NTuple{9}) = RV(Quat(t)) -@inline Base.getindex(aa::RodriguesVec, i::Integer) = Quat(aa)[i] +@inline Base.getindex(aa::RodriguesVec, i::Int) = Quat(aa)[i] # define its interaction with other angle representations @inline Base.convert{R <: RotMatrix}(::Type{R}, rv::RodriguesVec) = convert(R, AngleAxis(rv)) diff --git a/src/core_types.jl b/src/core_types.jl index cd12f7b7..fdebc2e3 100644 --- a/src/core_types.jl +++ b/src/core_types.jl @@ -88,7 +88,7 @@ for N = 2:3 @inline (::Type{RotMatrix{$N,T,$L}}){T}(t::NTuple{$L}) = RotMatrix(SMatrix{$N,$N,T}(t)) end end -Base.@propagate_inbounds Base.getindex(r::RotMatrix, i::Integer) = r.mat[i] +Base.@propagate_inbounds Base.getindex(r::RotMatrix, i::Int) = r.mat[i] @inline (::Type{RotMatrix})(θ::Real) = RotMatrix(@SMatrix [cos(θ) -sin(θ); sin(θ) cos(θ)]) @inline (::Type{RotMatrix{2}})(θ::Real) = RotMatrix(@SMatrix [cos(θ) -sin(θ); sin(θ) cos(θ)]) diff --git a/src/euler_types.jl b/src/euler_types.jl index 0137cb19..a9fa6930 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -23,7 +23,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotX}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotX{T}, i::Integer) +@inline function Base.getindex{T}(r::RotX{T}, i::Int) T2 = Base.promote_op(sin, T) if i == 1 one(T2) @@ -85,7 +85,7 @@ end @inline convert{R<:RotY}(::Type{R}, r::RotY) = R(r.theta) @inline (::Type{R}){R<:RotY}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotY{T}, i::Integer) +@inline function Base.getindex{T}(r::RotY{T}, i::Int) T2 = Base.promote_op(sin, T) if i == 1 cos(r.theta) @@ -152,7 +152,7 @@ end @inline convert{R<:RotZ}(::Type{R}, r::RotZ) = R(r.theta) @inline (::Type{R}){R<:RotZ}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotZ{T}, i::Integer) +@inline function Base.getindex{T}(r::RotZ{T}, i::Int) T2 = Base.promote_op(sin, T) if i == 1 cos(r.theta) @@ -238,7 +238,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotXY}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotXY{T}, i::Integer) +@inline function Base.getindex{T}(r::RotXY{T}, i::Int) Tuple(r)[i] # Slow... end @@ -305,7 +305,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotYX}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotYX{T}, i::Integer) +@inline function Base.getindex{T}(r::RotYX{T}, i::Int) Tuple(r)[i] # Slow... end @@ -372,7 +372,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotXZ}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotXZ{T}, i::Integer) +@inline function Base.getindex{T}(r::RotXZ{T}, i::Int) Tuple(r)[i] # Slow... end @@ -439,7 +439,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotZX}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotZX{T}, i::Integer) +@inline function Base.getindex{T}(r::RotZX{T}, i::Int) Tuple(r)[i] # Slow... end @@ -506,7 +506,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotZY}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotZY{T}, i::Integer) +@inline function Base.getindex{T}(r::RotZY{T}, i::Int) Tuple(r)[i] # Slow... end @@ -574,7 +574,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotYZ}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotYZ{T}, i::Integer) +@inline function Base.getindex{T}(r::RotYZ{T}, i::Int) Tuple(r)[i] # Slow... end @@ -670,7 +670,7 @@ end atan2((R[1, 2] * R[1, 2] + R[1, 3] * R[1, 3])^(1/2), R[1, 1]), atan2(- R[2, 3]*ct1 - R[3, 3]*st1, R[2, 2]*ct1 + R[3, 2]*st1)) end -@inline function Base.getindex{T}(r::RotXYX{T}, i::Integer) +@inline function Base.getindex{T}(r::RotXYX{T}, i::Int) Tuple(r)[i] # Slow... end @@ -750,7 +750,7 @@ end atan2((R[1, 2] * R[1, 2] + R[1, 3] * R[1, 3])^(1/2), R[1, 1]), atan2(R[3, 2]*ct1 - R[2, 2]*st1, R[3, 3]*ct1 - R[2, 3]*st1)) end -@inline function Base.getindex{T}(r::RotXZX{T}, i::Integer) +@inline function Base.getindex{T}(r::RotXZX{T}, i::Int) Tuple(r)[i] # Slow... end @@ -830,7 +830,7 @@ end atan2((R[2, 1] * R[2, 1] + R[2, 3] * R[2, 3])^(1/2), R[2, 2]), atan2(R[1, 3]*ct1 - R[3, 3]*st1, R[1, 1]*ct1 - R[3, 1]*st1)) end -@inline function Base.getindex{T}(r::RotYXY{T}, i::Integer) +@inline function Base.getindex{T}(r::RotYXY{T}, i::Int) Tuple(r)[i] # Slow... end @@ -911,7 +911,7 @@ end atan2((R[2, 1] * R[2, 1] + R[2, 3] * R[2, 3])^(1/2), R[2, 2]), atan2(- R[3, 1]*ct1 - R[1, 1]*st1, R[3, 3]*ct1 + R[1, 3]*st1)) end -@inline function Base.getindex{T}(r::RotYZY{T}, i::Integer) +@inline function Base.getindex{T}(r::RotYZY{T}, i::Int) Tuple(r)[i] # Slow... end @@ -992,7 +992,7 @@ end atan2(- R[1, 2]*ct1 - R[2, 2]*st1, R[1, 1]*ct1 + R[2, 1]*st1)) end -@inline function Base.getindex{T}(r::RotZXZ{T}, i::Integer) +@inline function Base.getindex{T}(r::RotZXZ{T}, i::Int) Tuple(r)[i] # Slow... end @@ -1073,7 +1073,7 @@ end atan2(R[2, 1]*ct1 - R[1, 1]*st1, R[2, 2]*ct1 - R[1, 2]*st1)) end -@inline function Base.getindex{T}(r::RotZYZ{T}, i::Integer) +@inline function Base.getindex{T}(r::RotZYZ{T}, i::Int) Tuple(r)[i] # Slow... end @@ -1164,7 +1164,7 @@ end atan2(R[2, 1]*ct1 + R[3, 1]*st1, R[2, 2]*ct1 + R[3, 2]*st1)) end -@inline function Base.getindex{T}(r::RotXYZ{T}, i::Integer) +@inline function Base.getindex{T}(r::RotXYZ{T}, i::Int) Tuple(r)[i] # Slow... end @@ -1251,7 +1251,7 @@ end atan2(R[1, 3]*st1 - R[2, 3]*ct1, R[2, 2]*ct1 - R[1, 2]*st1)) end -@inline function Base.getindex{T}(r::RotZYX{T}, i::Integer) +@inline function Base.getindex{T}(r::RotZYX{T}, i::Int) Tuple(r)[i] # Slow... end @@ -1338,7 +1338,7 @@ end atan2(R[2, 1]*st1 - R[3, 1]*ct1, R[3, 3]*ct1 - R[2, 3]*st1)) end -@inline function Base.getindex{T}(r::RotXZY{T}, i::Integer) +@inline function Base.getindex{T}(r::RotXZY{T}, i::Int) Tuple(r)[i] # Slow... end @@ -1425,7 +1425,7 @@ end atan2(R[3, 2]*ct1 + R[1, 2]*st1, R[3, 3]*ct1 + R[1, 3]*st1)) end -@inline function Base.getindex{T}(r::RotYZX{T}, i::Integer) +@inline function Base.getindex{T}(r::RotYZX{T}, i::Int) Tuple(r)[i] # Slow... end @@ -1512,7 +1512,7 @@ end atan2(R[3, 2]*st1 - R[1, 2]*ct1, R[1, 1]*ct1 - R[3, 1]*st1)) end -@inline function Base.getindex{T}(r::RotYXZ{T}, i::Integer) +@inline function Base.getindex{T}(r::RotYXZ{T}, i::Int) Tuple(r)[i] # Slow... end @@ -1599,7 +1599,7 @@ end atan2(R[1, 3]*ct1 + R[2, 3]*st1, R[1, 1]*ct1 + R[2, 1]*st1)) end -@inline function Base.getindex{T}(r::RotZXY{T}, i::Integer) +@inline function Base.getindex{T}(r::RotZXY{T}, i::Int) Tuple(r)[i] # Slow... end diff --git a/src/quaternion_types.jl b/src/quaternion_types.jl index 3d0f4107..34393366 100644 --- a/src/quaternion_types.jl +++ b/src/quaternion_types.jl @@ -39,7 +39,7 @@ function (::Type{Q}){Q<:Quat}(t::NTuple{9}) copysign(sqrt(abs(1 - t[1] - t[5] + t[9]))/2, t[2] - t[4])) end -function Base.getindex(q::Quat, i::Integer) +function Base.getindex(q::Quat, i::Int) if i == 1 ww = (q.w * q.w) xx = (q.x * q.x) @@ -207,7 +207,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{SPQ}){SPQ <: SPQuat}(t::NTuple{9}) = SPQ(Quat(t)) -@inline Base.getindex(spq::SPQuat, i::Integer) = Quat(spq)[i] +@inline Base.getindex(spq::SPQuat, i::Int) = Quat(spq)[i] @inline function Base.convert{Q <: Quat}(::Type{Q}, spq::SPQuat) # Both the sign and norm of the Quat is automatically dealt with in its inner constructor From 43343c9a50d400bd153b70932841012f9f348078 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Sat, 25 Mar 2017 12:13:18 -0400 Subject: [PATCH 05/13] Change immutable to struct. --- gen/SimpleSymbolic.jl | 2 +- src/angleaxis_types.jl | 8 ++-- src/core_types.jl | 4 +- src/euler_types.jl | 84 ++++++++++++++++++++--------------------- src/quaternion_types.jl | 8 ++-- 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/gen/SimpleSymbolic.jl b/gen/SimpleSymbolic.jl index 8be1c33a..8ed2ceaf 100644 --- a/gen/SimpleSymbolic.jl +++ b/gen/SimpleSymbolic.jl @@ -1,6 +1,6 @@ module SimpleSymbolic -immutable S +struct S x::Any end diff --git a/src/angleaxis_types.jl b/src/angleaxis_types.jl index ddf26170..ccd2870c 100644 --- a/src/angleaxis_types.jl +++ b/src/angleaxis_types.jl @@ -1,7 +1,7 @@ ################################################################################ ################################################################################ """ - immutable AngleAxis{T} <: Rotation{3,T} + struct AngleAxis{T} <: Rotation{3,T} AngleAxis(Θ, x, y, z) A 3×3 rotation matrix parameterized by a 3D rotation by angle θ about an @@ -11,7 +11,7 @@ Note that the axis is not unique for θ = 0, and that this parameterization does not continuously map the neighbourhood of the null rotation (and therefore might not be suitable for autodifferentation and optimization purposes). """ -immutable AngleAxis{T} <: Rotation{3,T} +struct AngleAxis{T} <: Rotation{3,T} theta::T axis_x::T axis_y::T @@ -113,14 +113,14 @@ end ################################################################################ ################################################################################ """ - immutable RodriguesVec{T} <: Rotation{3,T} + struct RodriguesVec{T} <: Rotation{3,T} RodriguesVec(sx, sy, sz) Rodrigues vector parameterization of a 3×3 rotation matrix. The direction of the vector [sx, sy, sz] defines the axis of rotation, and the rotation angle is given by its norm. """ -immutable RodriguesVec{T} <: Rotation{3,T} +struct RodriguesVec{T} <: Rotation{3,T} sx::T sy::T sz::T diff --git a/src/core_types.jl b/src/core_types.jl index fdebc2e3..4709c25a 100644 --- a/src/core_types.jl +++ b/src/core_types.jl @@ -67,13 +67,13 @@ end ################################################################################ ################################################################################ """ - immutable RotMatrix{N,T} <: Rotation{N,T} + struct RotMatrix{N,T} <: Rotation{N,T} A statically-sized, N×N unitary (orthogonal) matrix. Note: the orthonormality of the input matrix is *not* checked by the constructor. """ -immutable RotMatrix{N,T,L} <: Rotation{N,T} # which is <: AbstractMatrix{T} +struct RotMatrix{N,T,L} <: Rotation{N,T} # which is <: AbstractMatrix{T} mat::SMatrix{N, N, T, L} # The final parameter to SMatrix is the "length" of the matrix, 3 × 3 = 9 end diff --git a/src/euler_types.jl b/src/euler_types.jl index a9fa6930..056e0c0a 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -9,12 +9,12 @@ # Single axis rotations # ######################### """ - immutable RotX{T} <: Rotation{3,T} + struct RotX{T} <: Rotation{3,T} RotX(theta) A 3×3 rotation matrix which represents a rotation by `theta` about the X axis. """ -immutable RotX{T} <: Rotation{3,T} +struct RotX{T} <: Rotation{3,T} theta::T end @@ -73,12 +73,12 @@ end """ - immutable RotY{T} <: Rotation{3,T} + struct RotY{T} <: Rotation{3,T} RotY(theta) A 3×3 rotation matrix which represents a rotation by `theta` about the Y axis. """ -immutable RotY{T} <: Rotation{3,T} +struct RotY{T} <: Rotation{3,T} theta::T end @@ -139,13 +139,13 @@ end """ - immutable RotZ{T} <: Rotation{3,T} + struct RotZ{T} <: Rotation{3,T} RotZ(theta) A 3×3 rotation matrix which represents a rotation by `theta` about the Z axis. """ -immutable RotZ{T} <: Rotation{3,T} +struct RotZ{T} <: Rotation{3,T} theta::T end @@ -218,13 +218,13 @@ end ###################### """ - immutable RotXY{T} <: Rotation{3,T} + struct RotXY{T} <: Rotation{3,T} RotXY(theta_x, theta_y) A 3×3 rotation matrix which represents a rotation by `theta_y` about the Y axis, followed by a rotation by `theta_x` about the X axis. """ -immutable RotXY{T} <: Rotation{3,T} +struct RotXY{T} <: Rotation{3,T} theta1::T theta2::T end @@ -285,13 +285,13 @@ end """ - immutable RotYX{T} <: Rotation{3,T} + struct RotYX{T} <: Rotation{3,T} RotYX(theta_y, theta_x) A 3×3 rotation matrix which represents a rotation by `theta_x` about the X axis, followed by a rotation by `theta_y` about the Y axis. """ -immutable RotYX{T} <: Rotation{3,T} +struct RotYX{T} <: Rotation{3,T} theta1::T theta2::T end @@ -352,13 +352,13 @@ end """ - immutable RotXZ{T} <: Rotation{3,T} + struct RotXZ{T} <: Rotation{3,T} RotXZ(theta_x, theta_z) A 3×3 rotation matrix which represents a rotation by `theta_z` about the Z axis, followed by a rotation by `theta_x` about the X axis. """ -immutable RotXZ{T} <: Rotation{3,T} +struct RotXZ{T} <: Rotation{3,T} theta1::T theta2::T end @@ -419,13 +419,13 @@ end """ - immutable RotZX{T} <: Rotation{3,T} + struct RotZX{T} <: Rotation{3,T} RotZX(theta_z, theta_x) A 3×3 rotation matrix which represents a rotation by `theta_x` about the X axis, followed by a rotation by `theta_z` about the Z axis. """ -immutable RotZX{T} <: Rotation{3,T} +struct RotZX{T} <: Rotation{3,T} theta1::T theta2::T end @@ -486,13 +486,13 @@ end """ - immutable RotZY{T} <: Rotation{3,T} + struct RotZY{T} <: Rotation{3,T} RotZY(theta_z, theta_y) A 3×3 rotation matrix which represents a rotation by `theta_y` about the Y axis, followed by a rotation by `theta_z` about the Z axis. """ -immutable RotZY{T} <: Rotation{3,T} +struct RotZY{T} <: Rotation{3,T} theta1::T theta2::T end @@ -554,13 +554,13 @@ end """ - immutable RotYZ{T} <: Rotation{3,T} + struct RotYZ{T} <: Rotation{3,T} RotYZ(theta_y, theta_z) A 3×3 rotation matrix which represents a rotation by `theta_z` about the Z axis, followed by a rotation by `theta_y` about the Y axis. """ -immutable RotYZ{T} <: Rotation{3,T} +struct RotYZ{T} <: Rotation{3,T} theta1::T theta2::T end @@ -640,7 +640,7 @@ end ########################## """ - immutable RotXYX{T} <: Rotation{3,T} + struct RotXYX{T} <: Rotation{3,T} RotXYX(theta1, theta2, theta3) A 3×3 rotation matrix parameterized by the "proper" XYX Euler angle convention, @@ -648,7 +648,7 @@ consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the X axis by `theta1`. """ -immutable RotXYX{T} <: Rotation{3,T} +struct RotXYX{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -720,7 +720,7 @@ end @inline eye{T}(::Type{RotXYX{T}}) = RotXYX{T}(zero(T), zero(T), zero(T)) """ - immutable RotXZX{T} <: Rotation{3,T} + struct RotXZX{T} <: Rotation{3,T} RotXZX(theta1, theta2, theta3) A 3×3 rotation matrix parameterized by the "proper" XZX Euler angle convention, @@ -728,7 +728,7 @@ consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the X axis by `theta1`. """ -immutable RotXZX{T} <: Rotation{3,T} +struct RotXZX{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -800,7 +800,7 @@ end @inline eye{T}(::Type{RotXZX{T}}) = RotXZX{T}(zero(T), zero(T), zero(T)) """ - immutable RotYXY{T} <: Rotation{3,T} + struct RotYXY{T} <: Rotation{3,T} RotYXY(theta1, theta2, theta3) A 3×3 rotation matrix parameterized by the "proper" YXY Euler angle convention, @@ -808,7 +808,7 @@ consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Y axis by `theta1`. """ -immutable RotYXY{T} <: Rotation{3,T} +struct RotYXY{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -881,7 +881,7 @@ end """ - immutable RotYZY{T} <: Rotation{3,T} + struct RotYZY{T} <: Rotation{3,T} RotYZY(theta1, theta2, theta3) A 3×3 rotation matrix parameterized by the "proper" YXY Euler angle convention, @@ -889,7 +889,7 @@ consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the Y axis by `theta1`. """ -immutable RotYZY{T} <: Rotation{3,T} +struct RotYZY{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -962,7 +962,7 @@ end """ - immutable RotZXZ{T} <: Rotation{3,T} + struct RotZXZ{T} <: Rotation{3,T} RotZXZ(theta1, theta2, theta3) A 3×3 rotation matrix parameterized by the "proper" ZXZ Euler angle convention, @@ -970,7 +970,7 @@ consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Z axis by `theta1`. """ -immutable RotZXZ{T} <: Rotation{3,T} +struct RotZXZ{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -1043,7 +1043,7 @@ end """ - immutable RotZYZ{T} <: Rotation{3,T} + struct RotZYZ{T} <: Rotation{3,T} RotZYZ(theta1, theta2, theta3) A 3×3 rotation matrix parameterized by the "proper" ZXZ Euler angle convention, @@ -1051,7 +1051,7 @@ consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the Z axis by `theta1`. """ -immutable RotZYZ{T} <: Rotation{3,T} +struct RotZYZ{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -1128,7 +1128,7 @@ end ############################### """ - immutable RotXYZ{T} <: Rotation{3,T} + struct RotXYZ{T} <: Rotation{3,T} RotXYZ(theta1, theta2, theta3) RotXYZ(roll=r, pitch=p, yaw=y) @@ -1141,7 +1141,7 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in XYZ order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -immutable RotXYZ{T} <: Rotation{3,T} +struct RotXYZ{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -1215,7 +1215,7 @@ end """ - immutable RotZYX{T} <: Rotation{3,T} + struct RotZYX{T} <: Rotation{3,T} RotZYX(theta1, theta2, theta3) RotZYX(roll=r, pitch=p, yaw=y) @@ -1228,7 +1228,7 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in ZYX order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -immutable RotZYX{T} <: Rotation{3,T} +struct RotZYX{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -1302,7 +1302,7 @@ end """ - immutable RotXZY{T} <: Rotation{3,T} + struct RotXZY{T} <: Rotation{3,T} RotXZY(theta1, theta2, theta3) RotXZY(roll=r, pitch=p, yaw=y) @@ -1315,7 +1315,7 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in XZY order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -immutable RotXZY{T} <: Rotation{3,T} +struct RotXZY{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -1389,7 +1389,7 @@ end """ - immutable RotYZX{T} <: Rotation{3,T} + struct RotYZX{T} <: Rotation{3,T} RotYZX(theta1, theta2, theta3) RotYZX(roll=r, pitch=p, yaw=y) @@ -1402,7 +1402,7 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in YZX order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -immutable RotYZX{T} <: Rotation{3,T} +struct RotYZX{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -1476,7 +1476,7 @@ end """ - immutable RotYXZ{T} <: Rotation{3,T} + struct RotYXZ{T} <: Rotation{3,T} RotYXZ(theta1, theta2, theta3) RotYXZ(roll=r, pitch=p, yaw=y) @@ -1489,7 +1489,7 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in YXZ order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -immutable RotYXZ{T} <: Rotation{3,T} +struct RotYXZ{T} <: Rotation{3,T} theta1::T theta2::T theta3::T @@ -1563,7 +1563,7 @@ end """ - immutable RotZXY{T} <: Rotation{3,T} + struct RotZXY{T} <: Rotation{3,T} RotZXY(theta1, theta2, theta3) RotZXY(roll=r, pitch=p, yaw=y) @@ -1576,7 +1576,7 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in ZXY order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -immutable RotZXY{T} <: Rotation{3,T} +struct RotZXY{T} <: Rotation{3,T} theta1::T theta2::T theta3::T diff --git a/src/quaternion_types.jl b/src/quaternion_types.jl index 34393366..b5d573eb 100644 --- a/src/quaternion_types.jl +++ b/src/quaternion_types.jl @@ -1,5 +1,5 @@ """ - Quat{T} <: Rotation{3,T} + struct Quat{T} <: Rotation{3,T} Quat(w, x, y, z) The `Quat` type is a 3×3 matrix representation of a normalized quaternion. @@ -10,7 +10,7 @@ through matrix-vector multiplication. Note: the constructor will always renormalize the input so that the quaternion has length 1 (w² + x² + y² + z² = 1), and the rotation matrix is orthogonal. """ -immutable Quat{T} <: Rotation{3,T} +struct Quat{T} <: Rotation{3,T} w::T x::T y::T @@ -173,7 +173,7 @@ end ################################################################################ ################################################################################ """ - immutable SPQuat{T} <: Rotation{3,T} + struct SPQuat{T} <: Rotation{3,T} SPQuat(x, y, z) An `SPQuat` is a 3D rotation matrix represented by the "stereographic projection" of a normalized quaternion (shortened to "SPQuat"), which is @@ -193,7 +193,7 @@ See: Note 3: it is safe to assume that the corresponding matrix is orthogonal/unitary for any input x, y, z. """ -immutable SPQuat{T} <: Rotation{3,T} +struct SPQuat{T} <: Rotation{3,T} x::T y::T z::T From bd15ab9a4db2c91a464be459bc6212d20acc148c Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Mon, 27 Mar 2017 13:47:10 -0400 Subject: [PATCH 06/13] Fix takebuf_string deprecation in test. --- test/2d.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/2d.jl b/test/2d.jl index 9029584b..c25c3465 100644 --- a/test/2d.jl +++ b/test/2d.jl @@ -117,7 +117,7 @@ using Rotations, StaticArrays, Base.Test io = IOBuffer() r = rand(RotMatrix{2}) show(io, MIME("text/plain"), r) - str = takebuf_string(io) + str = String(take!(io)) @test startswith(str, "2×2 RotMatrix{Float64}:") end end From f24f6f17a9e0a0a3d19b04255d39e572d90e25a8 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Mon, 27 Mar 2017 14:11:24 -0400 Subject: [PATCH 07/13] Tentatively add inner and outer constructors to RotMatrix to fix ambiguity errors. --- src/core_types.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core_types.jl b/src/core_types.jl index 4709c25a..e542a96a 100644 --- a/src/core_types.jl +++ b/src/core_types.jl @@ -75,7 +75,9 @@ Note: the orthonormality of the input matrix is *not* checked by the constructor """ struct RotMatrix{N,T,L} <: Rotation{N,T} # which is <: AbstractMatrix{T} mat::SMatrix{N, N, T, L} # The final parameter to SMatrix is the "length" of the matrix, 3 × 3 = 9 + RotMatrix{N,T,L}(x::AbstractArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) end +RotMatrix(x::SMatrix{N,N,T,L}) where {N,T,L} = RotMatrix{N,T,L}(x) # These functions (plus size) are enough to satisfy the entire StaticArrays interface: # @inline (::Type{R}){R<:RotMatrix}(t::Tuple) = error("No precise constructor found. Length of input was $(length(t)).") From e2aa085982289a272ccec4668f0183af85e8c1a5 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Mon, 27 Mar 2017 15:11:43 -0400 Subject: [PATCH 08/13] Use convert(Tuple, ...) to fix infinite recursion. --- src/euler_types.jl | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/euler_types.jl b/src/euler_types.jl index 056e0c0a..a6eb32c4 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -239,7 +239,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotXY}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") @inline function Base.getindex{T}(r::RotXY{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotXY{T}) @@ -306,7 +306,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotYX}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") @inline function Base.getindex{T}(r::RotYX{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotYX{T}) @@ -373,7 +373,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotXZ}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") @inline function Base.getindex{T}(r::RotXZ{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotXZ{T}) @@ -440,7 +440,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotZX}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") @inline function Base.getindex{T}(r::RotZX{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotZX{T}) @@ -507,7 +507,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotZY}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") @inline function Base.getindex{T}(r::RotZY{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotZY{T}) @@ -575,7 +575,7 @@ end # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotYZ}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") @inline function Base.getindex{T}(r::RotYZ{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotYZ{T}) @@ -671,7 +671,7 @@ end atan2(- R[2, 3]*ct1 - R[3, 3]*st1, R[2, 2]*ct1 + R[3, 2]*st1)) end @inline function Base.getindex{T}(r::RotXYX{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotXYX{T}) @@ -751,7 +751,7 @@ end atan2(R[3, 2]*ct1 - R[2, 2]*st1, R[3, 3]*ct1 - R[2, 3]*st1)) end @inline function Base.getindex{T}(r::RotXZX{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotXZX{T}) @@ -831,7 +831,7 @@ end atan2(R[1, 3]*ct1 - R[3, 3]*st1, R[1, 1]*ct1 - R[3, 1]*st1)) end @inline function Base.getindex{T}(r::RotYXY{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotYXY{T}) @@ -912,7 +912,7 @@ end atan2(- R[3, 1]*ct1 - R[1, 1]*st1, R[3, 3]*ct1 + R[1, 3]*st1)) end @inline function Base.getindex{T}(r::RotYZY{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotYZY{T}) @@ -993,7 +993,7 @@ end end @inline function Base.getindex{T}(r::RotZXZ{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotZXZ{T}) @@ -1074,7 +1074,7 @@ end end @inline function Base.getindex{T}(r::RotZYZ{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotZYZ{T}) @@ -1165,7 +1165,7 @@ end end @inline function Base.getindex{T}(r::RotXYZ{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotXYZ{T}) @@ -1252,7 +1252,7 @@ end end @inline function Base.getindex{T}(r::RotZYX{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotZYX{T}) @@ -1339,7 +1339,7 @@ end end @inline function Base.getindex{T}(r::RotXZY{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotXZY{T}) @@ -1426,7 +1426,7 @@ end end @inline function Base.getindex{T}(r::RotYZX{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotYZX{T}) @@ -1513,7 +1513,7 @@ end end @inline function Base.getindex{T}(r::RotYXZ{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotYXZ{T}) @@ -1600,7 +1600,7 @@ end end @inline function Base.getindex{T}(r::RotZXY{T}, i::Int) - Tuple(r)[i] # Slow... + convert(Tuple, r)[i] # Slow... end @inline function Base.convert{T}(::Type{Tuple}, r::RotZXY{T}) From 8c067e7d19ad36b24a190c633d224a6e1ab22435 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Mon, 27 Mar 2017 15:13:27 -0400 Subject: [PATCH 09/13] Tentative fix for RotX ambiguity errors. --- src/euler_types.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/euler_types.jl b/src/euler_types.jl index a6eb32c4..71e75718 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -16,10 +16,14 @@ A 3×3 rotation matrix which represents a rotation by `theta` about the X axis. """ struct RotX{T} <: Rotation{3,T} theta::T + RotX{T}(theta) where {T} = new{T}(theta) + RotX{T}(r::RotX) where {T} = new{T}(r.theta) end +@inline RotX(theta::T) where {T} = RotX{T}(theta) +@inline RotX(r::RotX{T}) where {T} = RotX{T}(r) -@inline convert{R<:RotX}(::Type{R}, r::RotX) = R(r.theta) - +@inline convert(::Type{R}, r::RotX) where {R<:RotX} = R(r.theta) +@inline convert(::Type{R}, r::R) where {R<:RotX} = r # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{R}){R<:RotX}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") From 955fbbf09163cfea7064252be51574d8e670a236 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Thu, 30 Mar 2017 14:13:28 -0400 Subject: [PATCH 10/13] Apply changes to RotX throughout, reduce duplication. --- src/euler_types.jl | 688 ++++++++++------------------------------ src/quaternion_types.jl | 22 +- 2 files changed, 181 insertions(+), 529 deletions(-) diff --git a/src/euler_types.jl b/src/euler_types.jl index 71e75718..3dce3bcd 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -8,25 +8,52 @@ ######################### # Single axis rotations # ######################### + +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) + end + + @inline $RotType(theta::T) where {T} = $RotType{T}(theta) + @inline $RotType(r::$RotType{T}) where {T} = $RotType{T}(r) + + @inline convert(::Type{R}, r::$RotType) where {R<:$RotType} = R(r) + @inline convert(::Type{R}, r::R) where {R<:$RotType} = r + + @inline (::Type{R}){R<:$RotType}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") + + @inline Base.:*(r1::$RotType, r2::$RotType) = $RotType(r1.theta + r2.theta) + + @inline inv(r::$RotType) = $RotType(-r.theta) + + # define null rotations for convenience + @inline eye(::Type{$RotType}) = $RotType(0.0) + @inline eye{T}(::Type{$RotType{T}}) = $RotType{T}(zero(T)) + end +end + +function Base.rand{R <: Union{RotX,RotY,RotZ}}(::Type{R}) + T = eltype(R) + if T == Any + T = Float64 + end + + return R(2*pi*rand(T)) +end + + """ struct RotX{T} <: Rotation{3,T} RotX(theta) -A 3×3 rotation matrix which represents a rotation by `theta` about the X axis. + A 3×3 rotation matrix which represents a rotation by `theta` about the X axis. """ -struct RotX{T} <: Rotation{3,T} - theta::T - RotX{T}(theta) where {T} = new{T}(theta) - RotX{T}(r::RotX) where {T} = new{T}(r.theta) -end -@inline RotX(theta::T) where {T} = RotX{T}(theta) -@inline RotX(r::RotX{T}) where {T} = RotX{T}(r) - -@inline convert(::Type{R}, r::RotX) where {R<:RotX} = R(r.theta) -@inline convert(::Type{R}, r::R) where {R<:RotX} = r +RotX -# These 2 functions are enough to satisfy the entire StaticArrays interface: -@inline (::Type{R}){R<:RotX}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") @inline function Base.getindex{T}(r::RotX{T}, i::Int) T2 = Base.promote_op(sin, T) if i == 1 @@ -67,28 +94,15 @@ end v[3] * ct + v[2] * st) end -@inline Base.:*(r1::RotX, r2::RotX) = RotX(r1.theta + r2.theta) - -@inline inv(r::RotX) = RotX(-r.theta) - -# define null rotations for convenience -@inline eye(::Type{RotX}) = RotX(0.0) -@inline eye{T}(::Type{RotX{T}}) = RotX{T}(zero(T)) - """ struct RotY{T} <: Rotation{3,T} RotY(theta) -A 3×3 rotation matrix which represents a rotation by `theta` about the Y axis. + A 3×3 rotation matrix which represents a rotation by `theta` about the Y axis. """ -struct RotY{T} <: Rotation{3,T} - theta::T -end - -@inline convert{R<:RotY}(::Type{R}, r::RotY) = R(r.theta) +RotY -@inline (::Type{R}){R<:RotY}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") @inline function Base.getindex{T}(r::RotY{T}, i::Int) T2 = Base.promote_op(sin, T) if i == 1 @@ -133,29 +147,15 @@ end v[3] * ct - v[1] * st) end -@inline Base.:*(r1::RotY, r2::RotY) = RotY(r1.theta + r2.theta) - -@inline inv(r::RotY) = RotY(-r.theta) - -# define null rotations for convenience -@inline eye(::Type{RotY}) = RotY(0.0) -@inline eye{T}(::Type{RotY{T}}) = RotY{T}(zero(T)) - """ struct RotZ{T} <: Rotation{3,T} RotZ(theta) - -A 3×3 rotation matrix which represents a rotation by `theta` about the Z axis. + A 3×3 rotation matrix which represents a rotation by `theta` about the Z axis. """ -struct RotZ{T} <: Rotation{3,T} - theta::T -end +RotZ -@inline convert{R<:RotZ}(::Type{R}, r::RotZ) = R(r.theta) - -@inline (::Type{R}){R<:RotZ}(t::NTuple{9}) = error("Cannot construct a cardinal axis rotation from a matrix") @inline function Base.getindex{T}(r::RotZ{T}, i::Int) T2 = Base.promote_op(sin, T) if i == 1 @@ -196,31 +196,70 @@ end v[3]) end -@inline Base.:*(r1::RotZ, r2::RotZ) = RotZ(r1.theta + r2.theta) -# define null rotations for convenience -@inline eye(::Type{RotZ}) = RotZ(0.0) -@inline eye{T}(::Type{RotZ{T}}) = RotZ{T}(zero(T)) +################################################################################ +################################################################################ -@inline inv(r::RotZ) = RotZ(-r.theta) +###################### +# Two axis rotations # +###################### -function Base.rand{R <: Union{RotX,RotY,RotZ}}(::Type{R}) +for axis1 in [:X, :Y, :Z] + Rot1Type = Symbol("Rot" * string(axis1)) + for axis2 in filter(axis -> axis != axis1, [:X, :Y, :Z]) + Rot2Type = Symbol("Rot" * string(axis2)) + RotType = Symbol("Rot" * string(axis1) * string(axis2)) + 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) + end + + @inline $RotType(theta1::T1, theta2::T2) where {T1, T2} = $RotType{promote_type(T1, T2)}(theta1, theta2) + @inline $RotType(r::$RotType{T}) where {T} = $RotType{T}(r) + + @inline convert(::Type{R}, r::$RotType) where {R<:$RotType} = R(r) + @inline convert(::Type{R}, r::R) where {R<:$RotType} = r + + @inline function Base.getindex{T}(r::$RotType{T}, i::Int) + convert(Tuple, r)[i] # Slow... + end + + @inline (::Type{R}){R<:$RotType}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") + + # Composing single-axis rotations to obtain a two-axis rotation: + @inline Base.:*(r1::$Rot1Type, r2::$Rot2Type) = $RotType(r1.theta, r2.theta) + + # Composing single-axis rotations with two-axis rotations: + @inline Base.:*(r1::$RotType, r2::$Rot2Type) = $RotType(r1.theta1, r1.theta2 + r2.theta) + @inline Base.:*(r1::$Rot1Type, r2::$RotType) = $RotType(r1.theta + r2.theta1, r2.theta2) + + @inline inv(r::$RotType) = $InvRotType(-r.theta2, -r.theta1) + + # define null rotations for convenience + @inline eye(::Type{$RotType}) = $RotType(0.0, 0.0) + @inline eye{T}(::Type{$RotType{T}}) = $RotType{T}(zero(T), zero(T)) + end + end +end + +function Base.rand{R <: Union{RotXY,RotYZ,RotZX, RotXZ, RotYX, RotZY}}(::Type{R}) T = eltype(R) if T == Any T = Float64 end - return R(2*pi*rand(T)) + # Not really sure what this distribution is, but it's also not clear what + # it should be! rand(RotXY) *is* invariant to pre-rotations by a RotX and + # post-rotations by a RotY... + return R(2*pi*rand(T), 2*pi*rand(T)) end -################################################################################ -################################################################################ - -###################### -# Two axis rotations # -###################### - """ struct RotXY{T} <: Rotation{3,T} RotXY(theta_x, theta_y) @@ -228,23 +267,7 @@ end A 3×3 rotation matrix which represents a rotation by `theta_y` about the Y axis, followed by a rotation by `theta_x` about the X axis. """ -struct RotXY{T} <: Rotation{3,T} - theta1::T - theta2::T -end - -@inline (::Type{R}){R<:RotXY}(r::RotXY) = R(r.theta1, r.theta2) -@inline convert{R<:RotXY}(::Type{R}, r::RotXY) = R(r.theta1, r.theta2) - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 2 inputs (not 9). -@inline (::Type{RotXY}){X,Y}(x::X, y::Y) = RotXY{promote_type(X, Y)}(x, y) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: -@inline (::Type{R}){R<:RotXY}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotXY{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end +RotXY @inline function Base.convert{T}(::Type{Tuple}, r::RotXY{T}) sinθ₁ = sin(r.theta1) @@ -277,16 +300,6 @@ end cosθ₁*-sinθ₂*v[1] + sinθ₁*v[2] + cosθ₁*cosθ₂*v[3]) end -@inline Base.:*(r1::RotX, r2::RotY) = RotXY(r1.theta, r2.theta) -@inline Base.:*(r1::RotXY, r2::RotY) = RotXY(r1.theta1, r1.theta2 + r2.theta) -@inline Base.:*(r1::RotX, r2::RotXY) = RotXY(r1.theta + r2.theta1, r2.theta2) - -@inline inv(r::RotXY) = RotYX(-r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotXY}) = RotXY(0.0, 0.0) -@inline eye{T}(::Type{RotXY{T}}) = RotXY{T}(zero(T), zero(T)) - """ struct RotYX{T} <: Rotation{3,T} @@ -295,23 +308,7 @@ end A 3×3 rotation matrix which represents a rotation by `theta_x` about the X axis, followed by a rotation by `theta_y` about the Y axis. """ -struct RotYX{T} <: Rotation{3,T} - theta1::T - theta2::T -end - -@inline (::Type{R}){R<:RotYX}(r::RotYX) = R(r.theta1, r.theta2) -@inline convert{R<:RotYX}(::Type{R}, r::RotYX) = R(r.theta1, r.theta2) - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 2 inputs (not 9). -@inline (::Type{RotYX}){Y,X}(y::Y, x::X) = RotYX{promote_type(Y, X)}(y, x) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: -@inline (::Type{R}){R<:RotYX}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotYX{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end +RotYX @inline function Base.convert{T}(::Type{Tuple}, r::RotYX{T}) sinθ₁ = sin(r.theta1) @@ -344,16 +341,6 @@ end -sinθ₁*v[1] + cosθ₁*sinθ₂*v[2] + cosθ₁*cosθ₂*v[3]) end -@inline Base.:*(r1::RotY, r2::RotX) = RotYX(r1.theta, r2.theta) -@inline Base.:*(r1::RotYX, r2::RotX) = RotYX(r1.theta1, r1.theta2 + r2.theta) -@inline Base.:*(r1::RotY, r2::RotYX) = RotYX(r1.theta + r2.theta1, r2.theta2) - -@inline inv(r::RotYX) = RotXY(-r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotYX}) = RotYX(0.0, 0.0) -@inline eye{T}(::Type{RotYX{T}}) = RotYX{T}(zero(T), zero(T)) - """ struct RotXZ{T} <: Rotation{3,T} @@ -362,23 +349,7 @@ end A 3×3 rotation matrix which represents a rotation by `theta_z` about the Z axis, followed by a rotation by `theta_x` about the X axis. """ -struct RotXZ{T} <: Rotation{3,T} - theta1::T - theta2::T -end - -@inline (::Type{R}){R<:RotXZ}(r::RotXZ) = R(r.theta1, r.theta2) -@inline convert{R<:RotXZ}(::Type{R}, r::RotXZ) = R(r.theta1, r.theta2) - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 2 inputs (not 9). -@inline (::Type{RotXZ}){X,Z}(x::X, z::Z) = RotXZ{promote_type(X, Z)}(x, z) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: -@inline (::Type{R}){R<:RotXZ}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotXZ{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end +RotXZ @inline function Base.convert{T}(::Type{Tuple}, r::RotXZ{T}) sinθ₁ = sin(r.theta1) @@ -411,16 +382,6 @@ end sinθ₁*sinθ₂*v[1] + sinθ₁*cosθ₂*v[2] + cosθ₁*v[3]) end -@inline Base.:*(r1::RotX, r2::RotZ) = RotXZ(r1.theta, r2.theta) -@inline Base.:*(r1::RotXZ, r2::RotZ) = RotXZ(r1.theta1, r1.theta2 + r2.theta) -@inline Base.:*(r1::RotX, r2::RotXZ) = RotXZ(r1.theta + r2.theta1, r2.theta2) - -@inline inv(r::RotXZ) = RotZX(-r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotXZ}) = RotXZ(0.0, 0.0) -@inline eye{T}(::Type{RotXZ{T}}) = RotXZ{T}(zero(T), zero(T)) - """ struct RotZX{T} <: Rotation{3,T} @@ -429,23 +390,7 @@ end A 3×3 rotation matrix which represents a rotation by `theta_x` about the X axis, followed by a rotation by `theta_z` about the Z axis. """ -struct RotZX{T} <: Rotation{3,T} - theta1::T - theta2::T -end - -@inline (::Type{R}){R<:RotZX}(r::RotZX) = R(r.theta1, r.theta2) -@inline convert{R<:RotZX}(::Type{R}, r::RotZX) = R(r.theta1, r.theta2) - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 2 inputs (not 9). -@inline (::Type{RotZX}){Z,X}(z::Z, x::X) = RotZX{promote_type(Z, X)}(z, x) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: -@inline (::Type{R}){R<:RotZX}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotZX{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end +RotZX @inline function Base.convert{T}(::Type{Tuple}, r::RotZX{T}) sinθ₁ = sin(r.theta1) @@ -478,16 +423,6 @@ end sinθ₂*v[2] + cosθ₂*v[3]) end -@inline Base.:*(r1::RotZ, r2::RotX) = RotZX(r1.theta, r2.theta) -@inline Base.:*(r1::RotZX, r2::RotX) = RotZX(r1.theta1, r1.theta2 + r2.theta) -@inline Base.:*(r1::RotZ, r2::RotZX) = RotZX(r1.theta + r2.theta1, r2.theta2) - -@inline inv(r::RotZX) = RotXZ(-r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotZX}) = RotZX(0.0, 0.0) -@inline eye{T}(::Type{RotZX{T}}) = RotZX{T}(zero(T), zero(T)) - """ struct RotZY{T} <: Rotation{3,T} @@ -496,23 +431,7 @@ end A 3×3 rotation matrix which represents a rotation by `theta_y` about the Y axis, followed by a rotation by `theta_z` about the Z axis. """ -struct RotZY{T} <: Rotation{3,T} - theta1::T - theta2::T -end - -@inline (::Type{R}){R<:RotZY}(r::RotZY) = R(r.theta1, r.theta2) -@inline convert{R<:RotZY}(::Type{R}, r::RotZY) = R(r.theta1, r.theta2) - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 2 inputs (not 9). -@inline (::Type{RotZY}){Z,Y}(z::Z, y::Y) = RotZY{promote_type(Z, Y)}(z, y) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: -@inline (::Type{R}){R<:RotZY}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotZY{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end +RotZY @inline function Base.convert{T}(::Type{Tuple}, r::RotZY{T}) sinθ₁ = sin(r.theta1) @@ -546,17 +465,6 @@ end end -@inline Base.:*(r1::RotZ, r2::RotY) = RotZY(r1.theta, r2.theta) -@inline Base.:*(r1::RotZY, r2::RotY) = RotZY(r1.theta1, r1.theta2 + r2.theta) -@inline Base.:*(r1::RotZ, r2::RotZY) = RotZY(r1.theta + r2.theta1, r2.theta2) - -@inline inv(r::RotZY) = RotYZ(-r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotZY}) = RotZY(0.0, 0.0) -@inline eye{T}(::Type{RotZY{T}}) = RotZY{T}(zero(T), zero(T)) - - """ struct RotYZ{T} <: Rotation{3,T} RotYZ(theta_y, theta_z) @@ -564,23 +472,7 @@ end A 3×3 rotation matrix which represents a rotation by `theta_z` about the Z axis, followed by a rotation by `theta_y` about the Y axis. """ -struct RotYZ{T} <: Rotation{3,T} - theta1::T - theta2::T -end - -@inline (::Type{R}){R<:RotYZ}(r::RotYZ) = R(r.theta1, r.theta2) -@inline convert{R<:RotYZ}(::Type{R}, r::RotYZ) = R(r.theta1, r.theta2) - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 2 inputs (not 9). -@inline (::Type{RotYZ}){Y,Z}(y::Y, z::Z) = RotYZ{promote_type(Y, Z)}(y, z) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: -@inline (::Type{R}){R<:RotYZ}(t::NTuple{9}) = error("Cannot construct a two-axis rotation from a matrix") -@inline function Base.getindex{T}(r::RotYZ{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end +RotYZ @inline function Base.convert{T}(::Type{Tuple}, r::RotYZ{T}) sinθ₁ = sin(r.theta1) @@ -613,26 +505,59 @@ end -sinθ₁*cosθ₂*v[1] + sinθ₁*sinθ₂*v[2] + cosθ₁*v[3]) end -@inline Base.:*(r1::RotY, r2::RotZ) = RotYZ(r1.theta, r2.theta) -@inline Base.:*(r1::RotYZ, r2::RotZ) = RotYZ(r1.theta1, r1.theta2 + r2.theta) -@inline Base.:*(r1::RotY, r2::RotYZ) = RotYZ(r1.theta + r2.theta1, r2.theta2) - -# define null rotations for convenience -@inline eye(::Type{RotYZ}) = RotYZ(0.0, 0.0) -@inline eye{T}(::Type{RotYZ{T}}) = RotYZ{T}(zero(T), zero(T)) - -@inline inv(r::RotYZ) = RotZY(-r.theta2, -r.theta1) +################################################################################ +################################################################################ -function Base.rand{R <: Union{RotXY,RotYZ,RotZX, RotXZ, RotYX, RotZY}}(::Type{R}) - T = eltype(R) - if T == Any - T = Float64 +######################## +# Three axis Rotations # +######################## + +for axis1 in [:X, :Y, :Z] + Rot1Type = Symbol("Rot" * string(axis1)) + for axis2 in filter(axis -> axis != axis1, [:X, :Y, :Z]) + Rot2Type = Symbol("Rot" * string(axis2)) + Rot12Type = Symbol("Rot" * string(axis1) * string(axis2)) + for axis3 in filter(axis -> axis != axis2, [:X, :Y, :Z]) + Rot3Type = Symbol("Rot" * string(axis3)) + Rot23Type = Symbol("Rot" * string(axis2) * string(axis3)) + RotType = Symbol("Rot" * string(axis1) * string(axis2) * string(axis3)) + InvRotType = Symbol("Rot" * string(axis3) * string(axis2) * string(axis1)) + + @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) + end + + @inline $RotType(theta1::T1, theta2::T2, theta3::T3) where {T1, T2, T3} = $RotType{promote_type(promote_type(T1, T2), T3)}(theta1, theta2, theta3) + @inline $RotType(r::$RotType{T}) where {T} = $RotType{T}(r) + + @inline convert(::Type{R}, r::$RotType) where {R<:$RotType} = R(r) + @inline convert(::Type{R}, r::R) where {R<:$RotType} = r + + @inline function Base.getindex{T}(r::$RotType{T}, i::Int) + convert(Tuple, r)[i] # Slow... + end + + # Composing single-axis rotations with two-axis rotations: + @inline Base.:*(r1::$Rot1Type, r2::$Rot23Type) = $RotType(r1.theta, r2.theta1, r2.theta2) + @inline Base.:*(r1::$Rot12Type, r2::$Rot3Type) = $RotType(r1.theta1, r1.theta2, r2.theta) + + # Composing with single-axis rotations: + @inline Base.:*(r1::$RotType, r2::$Rot3Type) = $RotType(r1.theta1, r1.theta2, r1.theta3 + r2.theta) + @inline Base.:*(r1::$Rot1Type, r2::$RotType) = $RotType(r1.theta + r2.theta1, r2.theta2, r2.theta3) + + @inline inv(r::$RotType) = $InvRotType(-r.theta3, -r.theta2, -r.theta1) + + # define null rotations for convenience + @inline eye(::Type{$RotType}) = $RotType(0.0, 0.0, 0.0) + @inline eye{T}(::Type{$RotType{T}}) = $RotType{T}(zero(T), zero(T), zero(T)) + end + end end - - # Not really sure what this distribution is, but it's also not clear what - # it should be! rand(RotXY) *is* invariant to pre-rotations by a RotX and - # post-rotations by a RotY... - return R(2*pi*rand(T), 2*pi*rand(T)) end @@ -652,18 +577,8 @@ consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the X axis by `theta1`. """ -struct RotXYX{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotXYX}){X,Y,Z}(x::X, y::Y, z::Z) = RotXYX{promote_type(promote_type(X, Y), Z)}(x, y, z) +RotXYX - -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotXYX}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -674,9 +589,6 @@ end atan2((R[1, 2] * R[1, 2] + R[1, 3] * R[1, 3])^(1/2), R[1, 1]), atan2(- R[2, 3]*ct1 - R[3, 3]*st1, R[2, 2]*ct1 + R[3, 2]*st1)) end -@inline function Base.getindex{T}(r::RotXYX{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end @inline function Base.convert{T}(::Type{Tuple}, r::RotXYX{T}) sinθ₁ = sin(r.theta1) @@ -712,16 +624,6 @@ end cosθ₁*-sinθ₂*v[1] + (sinθ₁*cosθ₃ + cosθ₁*cosθ₂*sinθ₃)*v[2] + (sinθ₁*-sinθ₃ + cosθ₁*cosθ₂*cosθ₃)*v[3]) end -@inline Base.:*(r1::RotX, r2::RotYX) = RotXYX(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotXY, r2::RotX) = RotXYX(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotXYX, r2::RotX) = RotXYX(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotX, r2::RotXYX) = RotXYX(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotXYX) = RotXYX(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotXYX}) = RotXYX(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotXYX{T}}) = RotXYX{T}(zero(T), zero(T), zero(T)) """ struct RotXZX{T} <: Rotation{3,T} @@ -732,18 +634,8 @@ consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the X axis by `theta1`. """ -struct RotXZX{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotXZX}){X,Y,Z}(x::X, y::Y, z::Z) = RotXZX{promote_type(promote_type(X, Y), Z)}(x, y, z) - +RotXZX -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotXZX}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -754,9 +646,6 @@ end atan2((R[1, 2] * R[1, 2] + R[1, 3] * R[1, 3])^(1/2), R[1, 1]), atan2(R[3, 2]*ct1 - R[2, 2]*st1, R[3, 3]*ct1 - R[2, 3]*st1)) end -@inline function Base.getindex{T}(r::RotXZX{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end @inline function Base.convert{T}(::Type{Tuple}, r::RotXZX{T}) sinθ₁ = sin(r.theta1) @@ -792,16 +681,6 @@ end sinθ₁*sinθ₂*v[1] + (sinθ₁*cosθ₂*cosθ₃ + cosθ₁*sinθ₃)*v[2] + (sinθ₁*cosθ₂*-sinθ₃ + cosθ₁*cosθ₃)*v[3]) end -@inline Base.:*(r1::RotX, r2::RotZX) = RotXZX(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotXZ, r2::RotX) = RotXZX(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotXZX, r2::RotX) = RotXZX(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotX, r2::RotXZX) = RotXZX(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotXZX) = RotXZX(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotXZX}) = RotXZX(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotXZX{T}}) = RotXZX{T}(zero(T), zero(T), zero(T)) """ struct RotYXY{T} <: Rotation{3,T} @@ -812,18 +691,8 @@ consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Y axis by `theta1`. """ -struct RotYXY{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotYXY}){X,Y,Z}(x::X, y::Y, z::Z) = RotYXY{promote_type(promote_type(X, Y), Z)}(x, y, z) - +RotYXY -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotYXY}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -834,9 +703,6 @@ end atan2((R[2, 1] * R[2, 1] + R[2, 3] * R[2, 3])^(1/2), R[2, 2]), atan2(R[1, 3]*ct1 - R[3, 3]*st1, R[1, 1]*ct1 - R[3, 1]*st1)) end -@inline function Base.getindex{T}(r::RotYXY{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end @inline function Base.convert{T}(::Type{Tuple}, r::RotYXY{T}) sinθ₁ = sin(r.theta1) @@ -872,17 +738,6 @@ end (-sinθ₁*cosθ₃ + cosθ₁*cosθ₂*-sinθ₃)*v[1] + cosθ₁*sinθ₂*v[2] + (-sinθ₁*sinθ₃ + cosθ₁*cosθ₂*cosθ₃)*v[3]) end -@inline Base.:*(r1::RotY, r2::RotXY) = RotYXY(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotYX, r2::RotY) = RotYXY(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotYXY, r2::RotY) = RotYXY(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotY, r2::RotYXY) = RotYXY(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotYXY) = RotYXY(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotYXY}) = RotYXY(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotYXY{T}}) = RotYXY{T}(zero(T), zero(T), zero(T)) - """ struct RotYZY{T} <: Rotation{3,T} @@ -893,18 +748,8 @@ consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the Y axis by `theta1`. """ -struct RotYZY{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end - -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotYZY}){X,Y,Z}(x::X, y::Y, z::Z) = RotYZY{promote_type(promote_type(X, Y), Z)}(x, y, z) +RotYZY - -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotYZY}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -915,9 +760,6 @@ end atan2((R[2, 1] * R[2, 1] + R[2, 3] * R[2, 3])^(1/2), R[2, 2]), atan2(- R[3, 1]*ct1 - R[1, 1]*st1, R[3, 3]*ct1 + R[1, 3]*st1)) end -@inline function Base.getindex{T}(r::RotYZY{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end @inline function Base.convert{T}(::Type{Tuple}, r::RotYZY{T}) sinθ₁ = sin(r.theta1) @@ -953,17 +795,6 @@ end (-sinθ₁*cosθ₂*cosθ₃ + cosθ₁*-sinθ₃)*v[1] + sinθ₁*sinθ₂*v[2] + (-sinθ₁*cosθ₂*sinθ₃ + cosθ₁*cosθ₃)*v[3]) end -@inline Base.:*(r1::RotY, r2::RotZY) = RotYZY(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotYZ, r2::RotY) = RotYZY(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotYZY, r2::RotY) = RotYZY(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotY, r2::RotYZY) = RotYZY(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotYZY) = RotYZY(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotYZY}) = RotYZY(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotYZY{T}}) = RotYZY{T}(zero(T), zero(T), zero(T)) - """ struct RotZXZ{T} <: Rotation{3,T} @@ -974,17 +805,8 @@ consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Z axis by `theta1`. """ -struct RotZXZ{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotZXZ -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotZXZ}){X,Y,Z}(x::X, y::Y, z::Z) = RotZXZ{promote_type(promote_type(X, Y), Z)}(x, y, z) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotZXZ}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -996,10 +818,6 @@ end atan2(- R[1, 2]*ct1 - R[2, 2]*st1, R[1, 1]*ct1 + R[2, 1]*st1)) end -@inline function Base.getindex{T}(r::RotZXZ{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotZXZ{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1034,17 +852,6 @@ end sinθ₂*sinθ₃*v[1] + sinθ₂*cosθ₃*v[2] + cosθ₂*v[3]) end -@inline Base.:*(r1::RotZ, r2::RotXZ) = RotZXZ(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotZX, r2::RotZ) = RotZXZ(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotZXZ, r2::RotZ) = RotZXZ(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotZ, r2::RotZXZ) = RotZXZ(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotZXZ) = RotZXZ(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotZXZ}) = RotZXZ(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotZXZ{T}}) = RotZXZ{T}(zero(T), zero(T), zero(T)) - """ struct RotZYZ{T} <: Rotation{3,T} @@ -1055,17 +862,8 @@ consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the Z axis by `theta1`. """ -struct RotZYZ{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotZYZ -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotZYZ}){X,Y,Z}(x::X, y::Y, z::Z) = RotZYZ{promote_type(promote_type(X, Y), Z)}(x, y, z) - -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotZYZ}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -1077,10 +875,6 @@ end atan2(R[2, 1]*ct1 - R[1, 1]*st1, R[2, 2]*ct1 - R[1, 2]*st1)) end -@inline function Base.getindex{T}(r::RotZYZ{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotZYZ{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1115,18 +909,6 @@ end -sinθ₂*cosθ₃*v[1] + sinθ₂*sinθ₃*v[2] + cosθ₂*v[3]) end -@inline Base.:*(r1::RotZ, r2::RotYZ) = RotZYZ(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotZY, r2::RotZ) = RotZYZ(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotZYZ, r2::RotZ) = RotZYZ(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotZ, r2::RotZYZ) = RotZYZ(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotZYZ) = RotZYZ(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotZYZ}) = RotZYZ(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotZYZ{T}}) = RotZYZ{T}(zero(T), zero(T), zero(T)) - - ############################### # Tait-Bryant Euler Rotations # ############################### @@ -1145,18 +927,10 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in XYZ order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -struct RotXYZ{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotXYZ -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotXYZ}){X,Y,Z}(x::X, y::Y, z::Z) = RotXYZ{promote_type(promote_type(X, Y), Z)}(x, y, z) @inline (::Type{Rot}){Rot<:RotXYZ}(; roll=0, pitch=0, yaw=0) = Rot(roll, pitch, yaw) -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotXYZ}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -1168,10 +942,6 @@ end atan2(R[2, 1]*ct1 + R[3, 1]*st1, R[2, 2]*ct1 + R[3, 2]*st1)) end -@inline function Base.getindex{T}(r::RotXYZ{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotXYZ{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1206,17 +976,6 @@ end (cosθ₁*-sinθ₂*cosθ₃ + sinθ₁*sinθ₃)*v[1] + (cosθ₁*sinθ₂*sinθ₃ + sinθ₁*cosθ₃)*v[2] + cosθ₁*cosθ₂*v[3]) end -@inline Base.:*(r1::RotX, r2::RotYZ) = RotXYZ(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotXY, r2::RotZ) = RotXYZ(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotXYZ, r2::RotZ) = RotXYZ(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotX, r2::RotXYZ) = RotXYZ(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotXYZ) = RotZYX(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotXYZ}) = RotXYZ(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotXYZ{T}}) = RotXYZ{T}(zero(T), zero(T), zero(T)) - """ struct RotZYX{T} <: Rotation{3,T} @@ -1232,18 +991,10 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in ZYX order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -struct RotZYX{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotZYX -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotZYX}){X,Y,Z}(x::X, y::Y, z::Z) = RotZYX{promote_type(promote_type(X, Y), Z)}(x, y, z) @inline (::Type{Rot}){Rot<:RotZYX}(; roll=0, pitch=0, yaw=0) = Rot(yaw, pitch, roll) -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotZYX}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -1255,10 +1006,6 @@ end atan2(R[1, 3]*st1 - R[2, 3]*ct1, R[2, 2]*ct1 - R[1, 2]*st1)) end -@inline function Base.getindex{T}(r::RotZYX{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotZYX{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1293,17 +1040,6 @@ end -sinθ₂*v[1] + cosθ₂*sinθ₃*v[2] + cosθ₂*cosθ₃*v[3]) end -@inline Base.:*(r1::RotZ, r2::RotYX) = RotZYX(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotZY, r2::RotX) = RotZYX(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotZYX, r2::RotX) = RotZYX(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotZ, r2::RotZYX) = RotZYX(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotZYX) = RotXYZ(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotZYX}) = RotZYX(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotZYX{T}}) = RotZYX{T}(zero(T), zero(T), zero(T)) - """ struct RotXZY{T} <: Rotation{3,T} @@ -1319,18 +1055,10 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in XZY order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -struct RotXZY{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotXZY -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotXZY}){X,Y,Z}(x::X, y::Y, z::Z) = RotXZY{promote_type(promote_type(X, Y), Z)}(x, y, z) @inline (::Type{Rot}){Rot<:RotXZY}(; roll=0, pitch=0, yaw=0) = Rot(roll, yaw, pitch) -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotXZY}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -1342,10 +1070,6 @@ end atan2(R[2, 1]*st1 - R[3, 1]*ct1, R[3, 3]*ct1 - R[2, 3]*st1)) end -@inline function Base.getindex{T}(r::RotXZY{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotXZY{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1380,17 +1104,6 @@ end (sinθ₁*sinθ₂*cosθ₃ + cosθ₁*-sinθ₃)*v[1] + sinθ₁*cosθ₂*v[2] + (sinθ₁*sinθ₂*sinθ₃ + cosθ₁*cosθ₃)*v[3]) end -@inline Base.:*(r1::RotX, r2::RotZY) = RotXZY(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotXZ, r2::RotY) = RotXZY(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotXZY, r2::RotY) = RotXZY(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotX, r2::RotXZY) = RotXZY(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotXZY) = RotYZX(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotXZY}) = RotXZY(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotXZY{T}}) = RotXZY{T}(zero(T), zero(T), zero(T)) - """ struct RotYZX{T} <: Rotation{3,T} @@ -1406,18 +1119,10 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in YZX order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -struct RotYZX{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotYZX -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotYZX}){X,Y,Z}(x::X, y::Y, z::Z) = RotYZX{promote_type(promote_type(X, Y), Z)}(x, y, z) @inline (::Type{Rot}){Rot<:RotYZX}(; roll=0, pitch=0, yaw=0) = Rot(pitch, yaw, roll) -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotYZX}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -1429,10 +1134,6 @@ end atan2(R[3, 2]*ct1 + R[1, 2]*st1, R[3, 3]*ct1 + R[1, 3]*st1)) end -@inline function Base.getindex{T}(r::RotYZX{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotYZX{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1467,17 +1168,6 @@ end -sinθ₁*cosθ₂*v[1] + (sinθ₁*sinθ₂*cosθ₃ + cosθ₁*sinθ₃)*v[2] + (sinθ₁*sinθ₂*-sinθ₃ + cosθ₁*cosθ₃)*v[3]) end -@inline Base.:*(r1::RotY, r2::RotZX) = RotYZX(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotYZ, r2::RotX) = RotYZX(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotYZX, r2::RotX) = RotYZX(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotY, r2::RotYZX) = RotYZX(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotYZX) = RotXZY(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotYZX}) = RotYZX(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotYZX{T}}) = RotYZX{T}(zero(T), zero(T), zero(T)) - """ struct RotYXZ{T} <: Rotation{3,T} @@ -1493,18 +1183,10 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in YXZ order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -struct RotYXZ{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotYXZ -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotYXZ}){X,Y,Z}(x::X, y::Y, z::Z) = RotYXZ{promote_type(promote_type(X, Y), Z)}(x, y, z) @inline (::Type{Rot}){Rot<:RotYXZ}(; roll=0, pitch=0, yaw=0) = Rot(pitch, roll, yaw) -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotYXZ}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -1516,10 +1198,6 @@ end atan2(R[3, 2]*st1 - R[1, 2]*ct1, R[1, 1]*ct1 - R[3, 1]*st1)) end -@inline function Base.getindex{T}(r::RotYXZ{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotYXZ{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1554,17 +1232,6 @@ end (-sinθ₁*cosθ₃ + cosθ₁*sinθ₂*sinθ₃)*v[1] + (sinθ₁*sinθ₃ + cosθ₁*sinθ₂*cosθ₃)*v[2] + cosθ₁*cosθ₂*v[3]) end -@inline Base.:*(r1::RotY, r2::RotXZ) = RotYXZ(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotYX, r2::RotZ) = RotYXZ(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotYXZ, r2::RotZ) = RotYXZ(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotY, r2::RotYXZ) = RotYXZ(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotYXZ) = RotZXY(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotYXZ}) = RotYXZ(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotYXZ{T}}) = RotYXZ{T}(zero(T), zero(T), zero(T)) - """ struct RotZXY{T} <: Rotation{3,T} @@ -1580,18 +1247,10 @@ The keyword argument form applies roll, pitch and yaw to the X, Y and Z axes respectively, in ZXY order. (Because it is a right-handed coordinate system, note that positive pitch is heading in the negative Z axis). """ -struct RotZXY{T} <: Rotation{3,T} - theta1::T - theta2::T - theta3::T -end +RotZXY -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{RotZXY}){X,Y,Z}(x::X, y::Y, z::Z) = RotZXY{promote_type(promote_type(X, Y), Z)}(x, y, z) @inline (::Type{Rot}){Rot<:RotZXY}(; roll=0, pitch=0, yaw=0) = Rot(yaw, roll, pitch) -# These 2 functions are enough to satisfy the entire StaticArrays interface: @inline function (::Type{Rot}){Rot <: RotZXY}(t::NTuple{9}) R = SMatrix{3,3}(t) @@ -1603,10 +1262,6 @@ end atan2(R[1, 3]*ct1 + R[2, 3]*st1, R[1, 1]*ct1 + R[2, 1]*st1)) end -@inline function Base.getindex{T}(r::RotZXY{T}, i::Int) - convert(Tuple, r)[i] # Slow... -end - @inline function Base.convert{T}(::Type{Tuple}, r::RotZXY{T}) sinθ₁ = sin(r.theta1) cosθ₁ = cos(r.theta1) @@ -1640,14 +1295,3 @@ end (sinθ₁*cosθ₃ + cosθ₁*-sinθ₂*-sinθ₃)*v[1] + cosθ₁*cosθ₂*v[2] + (sinθ₁*sinθ₃ + cosθ₁*-sinθ₂*cosθ₃)*v[3], cosθ₂*-sinθ₃*v[1] + sinθ₂*v[2] + cosθ₂*cosθ₃*v[3]) end - -@inline Base.:*(r1::RotZ, r2::RotXY) = RotZXY(r1.theta, r2.theta1, r2.theta2) -@inline Base.:*(r1::RotZX, r2::RotY) = RotZXY(r1.theta1, r1.theta2, r2.theta) -@inline Base.:*(r1::RotZXY, r2::RotY) = RotZXY(r1.theta1, r1.theta2, r1.theta3 + r2.theta) -@inline Base.:*(r1::RotZ, r2::RotZXY) = RotZXY(r1.theta + r2.theta1, r2.theta2, r2.theta3) - -@inline inv(r::RotZXY) = RotYXZ(-r.theta3, -r.theta2, -r.theta1) - -# define null rotations for convenience -@inline eye(::Type{RotZXY}) = RotZXY(0.0, 0.0, 0.0) -@inline eye{T}(::Type{RotZXY{T}}) = RotZXY{T}(zero(T), zero(T), zero(T)) diff --git a/src/quaternion_types.jl b/src/quaternion_types.jl index b5d573eb..08e79e52 100644 --- a/src/quaternion_types.jl +++ b/src/quaternion_types.jl @@ -23,13 +23,17 @@ struct Quat{T} <: Rotation{3,T} #if norm !≈ 1 # error("Expected a normalized quaternion") # or warn() ? #end - new(w/norm, x/norm, y/norm, z/norm) + new{T}(w/norm, x/norm, y/norm, z/norm) end + + Quat{T}(q::Quat) where {T} = new{T}(q.w, q.x, q.y, q.z) end -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 4 inputs (not 9). -@inline (::Type{Quat}){W,X,Y,Z}(w::W, x::X, y::Y, z::Z) = Quat{promote_type(promote_type(promote_type(W, X), Y), Z)}(w, x, y, z) +@inline Quat(w::W, x::X, y::Y, z::Z) where {W, X, Y, Z} = Quat{promote_type(promote_type(promote_type(W, X), Y), Z)}(w, x, y, z) +@inline Quat(q::Quat{T}) where {T} = Quat{T}(q) + +@inline convert(::Type{Q}, q::Quat) where {Q<:Quat} = Q(q) +@inline convert(::Type{Q}, q::Q) where {Q<:Quat} = q # These 2 functions are enough to satisfy the entire StaticArrays interface: function (::Type{Q}){Q<:Quat}(t::NTuple{9}) @@ -199,11 +203,15 @@ struct SPQuat{T} <: Rotation{3,T} z::T # TODO should we enforce norm <= 1? + SPQuat{T}(x, y, z) where {T} = new{T}(x, y, z) + SPQuat{T}(spq::SPQuat) where {T} = new{T}(spq.x, spq.y, spq.z) end -# StaticArrays will take over *all* the constructors and put everything in a tuple... -# but this isn't quite what we mean when we have 3 inputs (not 9). -@inline (::Type{SPQuat}){X,Y,Z}(x::X, y::Y, z::Z) = SPQuat{promote_type(promote_type(X, Y), Z)}(x, y, z) +@inline SPQuat(x::X, y::Y, z::Z) where {X,Y,Z} = SPQuat{promote_type(promote_type(X, Y), Z)}(x, y, z) +@inline SPQuat(spq::SPQuat{T}) where {T} = SPQuat{T}(spq) + +@inline convert(::Type{SPQ}, spq::SPQuat) where {SPQ<:SPQuat} = SPQ(spq) +@inline convert(::Type{SPQ}, spq::SPQ) where {SPQ<:SPQuat} = spq # These 2 functions are enough to satisfy the entire StaticArrays interface: @inline (::Type{SPQ}){SPQ <: SPQuat}(t::NTuple{9}) = SPQ(Quat(t)) From 1eb9545770db8097a0ac0a8d29a12f9a98a8d1bc Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Thu, 30 Mar 2017 15:35:57 -0400 Subject: [PATCH 11/13] Work around StaticArrays getindex issue. --- src/derivatives.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/derivatives.jl b/src/derivatives.jl index 63cd7aa7..bb60d01e 100644 --- a/src/derivatives.jl +++ b/src/derivatives.jl @@ -36,7 +36,8 @@ function jacobian(::Type{RotMatrix}, q::Quat) # then R = RotMatrix(q) = RotMatrix(s * qhat) = s * RotMatrix(qhat) # get R(q) - R = q[:] + # R = q[:] # FIXME: broken with StaticArrays 0.4.0 due to https://github.com/JuliaArrays/StaticArrays.jl/issues/128 + R = SVector(convert(Tuple, q)) # solve d(s*R)/dQ (because its easy) dsRdQ = @SMatrix [ 2*q.w 2*q.x -2*q.y -2*q.z ; From aae8f8fe70f3aa28f2ba04ef33d0c549311808c7 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Thu, 30 Mar 2017 15:37:53 -0400 Subject: [PATCH 12/13] Update .travis.yml, REQUIRE. --- .travis.yml | 10 +++++----- REQUIRE | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index f327c5ad..c56b0662 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,14 +4,14 @@ os: - linux - osx julia: - - 0.5 + - 0.6 - nightly notifications: email: false -matrix: - allow_failures: - - julia: nightly - - os: osx +# matrix: +# allow_failures: +# - julia: nightly +# - os: osx # uncomment the following lines to override the default test script #script: # - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi diff --git a/REQUIRE b/REQUIRE index cf1ef5f7..c638e93b 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1,2 @@ -julia 0.5 -StaticArrays 0.3.0 +julia 0.6- +StaticArrays 0.4.0 From 0dbaee9e954db59f58db96ab385174b442521653 Mon Sep 17 00:00:00 2001 From: Twan Koolen Date: Thu, 30 Mar 2017 15:48:02 -0400 Subject: [PATCH 13/13] Undo docstring indentation changes. --- src/euler_types.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/euler_types.jl b/src/euler_types.jl index 3dce3bcd..12fdaf67 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -50,7 +50,7 @@ end struct RotX{T} <: Rotation{3,T} RotX(theta) - A 3×3 rotation matrix which represents a rotation by `theta` about the X axis. +A 3×3 rotation matrix which represents a rotation by `theta` about the X axis. """ RotX @@ -99,7 +99,7 @@ end struct RotY{T} <: Rotation{3,T} RotY(theta) - A 3×3 rotation matrix which represents a rotation by `theta` about the Y axis. +A 3×3 rotation matrix which represents a rotation by `theta` about the Y axis. """ RotY @@ -152,7 +152,7 @@ end struct RotZ{T} <: Rotation{3,T} RotZ(theta) - A 3×3 rotation matrix which represents a rotation by `theta` about the Z axis. +A 3×3 rotation matrix which represents a rotation by `theta` about the Z axis. """ RotZ