-
Notifications
You must be signed in to change notification settings - Fork 35
Remove rotation-related functions #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
ccd3a83
remove rotation-realted functions
hyrodium 05914a9
remove exports for rotations
hyrodium f103871
fix tests for rotations
hyrodium 15f3137
add an example page for rotation with quaternion
hyrodium 821fac0
replace rotationmatrix with rotmatrix_from_quat
hyrodium b01af90
Apply suggestion (fix english and LaTeX)
hyrodium 503013c
Apply suggestion (fix english)
hyrodium 4054efc
apply english suggestion from code review
hyrodium 0502337
update the documentation for basic rotation with unit quaternion
hyrodium 5a60395
add U(1,\mathbb{H})
hyrodium 7d37937
update the symbols for rotating a vector
hyrodium 97a8ef8
update around SO(3) and SU(2)
hyrodium 8b271ca
fix typo
hyrodium 524b178
fix LaTeX command
hyrodium 3d7b144
fix typo
hyrodium b7aa354
add more argument type specification in rotations.md
hyrodium File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor point, but I prefer we avoid
_from_quatunless necessary, since in Julia,_from_XXXis handled by the type constraint in the method overload, so it's redundant.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with that as the common manner in the Julia language. However this is just documentation and readers cannot check the methods of the function by running
methods(XXX), and I thought explicitXXX_from_YYYis a little better.