-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Remove rotation-related functions (#111)
* remove rotation-realted functions * remove exports for rotations * fix tests for rotations * add an example page for rotation with quaternion * replace rotationmatrix with rotmatrix_from_quat * Apply suggestion (fix english and LaTeX) Co-authored-by: Seth Axen <[email protected]> * Apply suggestion (fix english) Co-authored-by: Seth Axen <[email protected]> * apply english suggestion from code review * update the documentation for basic rotation with unit quaternion * add U(1,\mathbb{H}) * update the symbols for rotating a vector * update around SO(3) and SU(2) * fix typo * fix LaTeX command * fix typo * add more argument type specification in rotations.md Co-authored-by: Seth Axen <[email protected]>
- Loading branch information
Showing
6 changed files
with
195 additions
and
214 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
# Rotations with quaternions | ||
|
||
One of the most useful application of quaternions is representation of 3D-rotations. | ||
See also [Rotations.jl documentation](https://juliageometry.github.io/Rotations.jl/stable/3d_quaternion/) | ||
|
||
```@example rotation | ||
using Quaternions | ||
using LinearAlgebra | ||
``` | ||
|
||
## Basics | ||
A 3D rotation can be represented by a [unit quaternion (versor)](https://en.wikipedia.org/wiki/Versor). | ||
For example, a 90° rotation around the ``y``-axis is ``q = \frac{1}{\sqrt{2}} + 0i + \frac{1}{\sqrt{2}} j + 0k``. | ||
Rotations with quaternions have the following properties: | ||
|
||
* A unit quaternion (4 real numbers) is more efficient for representing a rotation than a rotation matrix (9 real numbers). | ||
* This results in higher computational performance in terms of time, memory usage, and accuracy. | ||
* The negative of a unit quaternion represents the same rotation. | ||
* The conjugate of a unit quaternion represents the inverse rotation. | ||
* The quaternion has unit length, so conjugate and multiplicative inverse is the same. | ||
* The set of unit quaternion ``\left\{w + ix + jy + kz \in \mathbb{H} \ | \ x, y, z \in \mathbb{R} \right\} = U(1,\mathbb{H}) \simeq S^3`` forms a group, and the group is homomorphic to the following groups. | ||
* ``SU(2) = \{R \in \mathcal{M}(2,\mathbb{C}) \ | \ R R^{*} = I\}`` is isomorphic to ``U(1,\mathbb{H})``. | ||
* ``SO(3) = \{R \in \mathcal{M}(3,\mathbb{R}) \ | \ R R^\top = I\}`` is homomorphic to ``U(1,\mathbb{H})``, and the mapping ``U(1,\mathbb{H}) \to SO(3)`` is double covering. | ||
|
||
## Rotation around a vector | ||
A ``\theta`` rotation around a unit vector ``v = (v_x, v_y, v_z)`` can be obtained as | ||
```math | ||
q = \cos(\theta/2) + \sin(\theta/2)(iv_x + jv_y + kv_z). | ||
``` | ||
|
||
```@example rotation | ||
function quat_from_axisangle(axis::AbstractVector, theta::Real) | ||
if length(axis) != 3 | ||
error("Must be a 3-vector") | ||
end | ||
s, c = sincos(theta / 2) | ||
axis = normalize(axis) | ||
return Quaternion(c, s*axis[1], s*axis[2], s*axis[3]) | ||
end | ||
nothing # hide | ||
``` | ||
|
||
```@repl rotation | ||
q1 = quat_from_axisangle([0,1,0], deg2rad(90)) # 90° rotation around y-axis | ||
q2 = quat_from_axisangle([1,1,1], deg2rad(120)) | ||
q3 = -q2 # additive inverse quaternion represents the same rotation | ||
``` | ||
|
||
## Rotate a vector with a quaternion | ||
A vector ``u = (u_x, u_y, u_z)`` can be rotated by a unit quaternion ``q``. | ||
The rotated vector ``v = (v_x, v_y, v_z)`` can be obtained as | ||
```math | ||
\begin{aligned} | ||
q_u &= iu_x + ju_y + ku_z \\ | ||
q_v &= q q_u \bar{q} = 0 + iv_x + jv_y + kv_z \\ | ||
v &= (v_x, v_y, v_z). | ||
\end{aligned} | ||
``` | ||
|
||
```@example rotation | ||
function rotate_vector(q::Quaternion, u::AbstractVector) | ||
if length(u) != 3 | ||
error("Must be a 3-vector") | ||
end | ||
q_u = Quaternion(0, u[1], u[2], u[3]) | ||
q_v = q*q_u*conj(q) | ||
return [imag_part(q_v)...] | ||
end | ||
nothing # hide | ||
``` | ||
|
||
```@repl rotation | ||
rotate_vector(q1, [1,2,3]) | ||
rotate_vector(q2, [1,2,3]) | ||
rotate_vector(q3, [1,2,3]) # Same as q2 | ||
``` | ||
|
||
## Convert a quaternion to a rotation matrix | ||
A unit quaternion can be converted to a rotation matrix. | ||
|
||
```@example rotation | ||
function rotmatrix_from_quat(q::Quaternion) | ||
sx, sy, sz = 2q.s * q.v1, 2q.s * q.v2, 2q.s * q.v3 | ||
xx, xy, xz = 2q.v1^2, 2q.v1 * q.v2, 2q.v1 * q.v3 | ||
yy, yz, zz = 2q.v2^2, 2q.v2 * q.v3, 2q.v3^2 | ||
r = [1 - (yy + zz) xy - sz xz + sy; | ||
xy + sz 1 - (xx + zz) yz - sx; | ||
xz - sy yz + sx 1 - (xx + yy)] | ||
return r | ||
end | ||
nothing # hide | ||
``` | ||
|
||
```@repl rotation | ||
m1 = rotmatrix_from_quat(q1) | ||
m2 = rotmatrix_from_quat(q2) | ||
m3 = rotmatrix_from_quat(q3) # Same as q2 | ||
``` | ||
|
||
This function does not return [`StaticMatrix`](https://juliaarrays.github.io/StaticArrays.jl/dev/pages/api/#StaticArraysCore.StaticArray), so the implementation is not much effective. | ||
If you need more performance, please consider using [Rotations.jl](https://github.com/JuliaGeometry/Rotations.jl). | ||
|
||
## Convert a rotation matrix to a quaternion | ||
A rotation matrix can be converted to a unit quaternion. | ||
The following implementation is based on [https://arxiv.org/pdf/math/0701759.pdf](https://arxiv.org/pdf/math/0701759.pdf). | ||
Note that the following mapping ``SO(3) \to SU(2)`` is not surjective. | ||
|
||
```@example rotation | ||
function quat_from_rotmatrix(dcm::AbstractMatrix{T}) where {T<:Real} | ||
a2 = 1 + dcm[1,1] + dcm[2,2] + dcm[3,3] | ||
a = sqrt(a2)/2 | ||
b,c,d = (dcm[3,2]-dcm[2,3])/4a, (dcm[1,3]-dcm[3,1])/4a, (dcm[2,1]-dcm[1,2])/4a | ||
return Quaternion(a,b,c,d) | ||
end | ||
nothing # hide | ||
``` | ||
|
||
```@repl rotation | ||
quat_from_rotmatrix(m1) | ||
quat_from_rotmatrix(m2) | ||
quat_from_rotmatrix(m3) | ||
quat_from_rotmatrix(m1) ≈ q1 | ||
quat_from_rotmatrix(m2) ≈ q2 | ||
quat_from_rotmatrix(m3) ≈ q3 # q2 == -q3 | ||
``` | ||
|
||
## Interpolate two rotations (slerp) | ||
Slerp (spherical linear interpolation) is a method to interpolate between two unit quaternions. | ||
This function [`slerp`](@ref) equates antipodal points, and interpolates the shortest path. | ||
Therefore, the output `slerp(q1, q2, 1)` may be different from `q2`. (`slerp(q1, q2, 0)` is always equal to `q1`.) | ||
|
||
```@repl rotation | ||
slerp(q1, q2, 0) ≈ q1 | ||
slerp(q1, q2, 1) ≈ q2 | ||
slerp(q1, q3, 1) ≈ q3 | ||
slerp(q1, q3, 1) ≈ -q3 | ||
r = slerp(q1, q2, 1/2) | ||
abs(q1-r) ≈ abs(q2-r) # Same distance | ||
abs(r) # Interpolates on the unit sphere S³ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.