Skip to content

Commit 46a7906

Browse files
mikmooresethaxen
andauthored
fix piracy and type instability (#53)
* fix piracy of normalize(::Vector) and type instability of qrotation(::Vector) * Apply suggestions from code review Co-authored-by: Seth Axen <[email protected]> * zero axis in qrotation() forces zero rotation * Update src/Quaternion.jl Co-authored-by: Seth Axen <[email protected]> Co-authored-by: Seth Axen <[email protected]> Co-authored-by: mikmoore <[email protected]>
1 parent 88d7057 commit 46a7906

File tree

2 files changed

+14
-16
lines changed

2 files changed

+14
-16
lines changed

src/Quaternion.jl

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,14 @@ function qrotation(axis::Vector{T}, theta) where {T <: Real}
207207
if length(axis) != 3
208208
error("Must be a 3-vector")
209209
end
210-
u = normalize(axis)
211-
s = sin(theta / 2)
212-
Quaternion(cos(theta / 2), s * u[1], s * u[2], s * u[3], true)
210+
normaxis = norm(axis)
211+
if iszero(normaxis)
212+
normaxis = oneunit(normaxis)
213+
theta = zero(theta)
214+
end
215+
s,c = sincos(theta / 2)
216+
scaleby = s / normaxis
217+
Quaternion(c, scaleby * axis[1], scaleby * axis[2], scaleby * axis[3], true)
213218
end
214219

215220
# Variant of the above where norm(rotvec) encodes theta
@@ -218,11 +223,9 @@ function qrotation(rotvec::Vector{T}) where {T <: Real}
218223
error("Must be a 3-vector")
219224
end
220225
theta = norm(rotvec)
221-
if theta > 0
222-
s = sin(theta / 2) / theta # divide by theta to make rotvec a unit vector
223-
return Quaternion(cos(theta / 2), s * rotvec[1], s * rotvec[2], s * rotvec[3], true)
224-
end
225-
Quaternion(one(T), zero(T), zero(T), zero(T), true)
226+
s,c = sincos(theta / 2)
227+
scaleby = s / (iszero(theta) ? one(theta) : theta)
228+
Quaternion(c, scaleby * rotvec[1], scaleby * rotvec[2], scaleby * rotvec[3], true)
226229
end
227230

228231
function qrotation(dcm::Matrix{T}) where {T<:Real}
@@ -263,14 +266,6 @@ function rotationmatrix_normalized(q::Quaternion)
263266
xz - sy yz + sx 1 - (xx + yy)]
264267
end
265268

266-
function normalize(v::Vector{T}) where {T}
267-
nv = norm(v)
268-
if nv > 0
269-
return v / nv
270-
end
271-
zeros(promote_type(T, typeof(nv)), length(v))
272-
end
273-
274269

275270
function slerp(qa::Quaternion{T}, qb::Quaternion{T}, t::T) where {T}
276271
# http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

test/test_Quaternion.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ for _ in 1:10, T in (Float32, Float64, Int32, Int64)
2626
end
2727

2828
let # test rotations
29+
@test qrotation([0, 0, 0], 1.0) == Quaternion(1.0) # a zero axis should act like zero rotation
30+
@test qrotation([1, 0, 0], 0.0) == Quaternion(1.0)
31+
@test qrotation([0, 0, 0]) == Quaternion(1.0)
2932
qx = qrotation([1, 0, 0], pi / 4)
3033
@test qx * qx qrotation([1, 0, 0], pi / 2)
3134
@test qx^2 qrotation([1, 0, 0], pi / 2)

0 commit comments

Comments
 (0)