Skip to content

Commit

Permalink
clarify rotation of quaternions (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
markromanmiller committed Mar 15, 2021
1 parent a14425d commit 13f5aac
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
4 changes: 2 additions & 2 deletions R/quat-operations.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ NULL

quat_proxy_equal <- function(x, ...) {
q <- x
x <- rotate(quat(w = 0, x = 1, y = 0, z = 0), rotator = q)
y <- rotate(quat(w = 0, x = 0, y = 1, z = 0), rotator = q)
x <- rotate(vector3(x = 1, y = 0, z = 0), rotator = q)
y <- rotate(vector3(x = 0, y = 1, z = 0), rotator = q)

data.frame(
x_x = x$x, x_y = x$y, x_z = x$z,
Expand Down
38 changes: 35 additions & 3 deletions R/rotate.R
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ make_rotator <- function(axis, angle, from, to) {
#'
#' Rotate points or quaternions using a handful of ways to define a rotation.
#'
#' Note that with quaternions, there are two operations that might be called
#' "rotations." The operation is selected using the `as` argument. When
#' quaternions represent orientations, rotation is merely quaternion
#' multiplication. This operation is perfomed by the arguments `"orientation"` or
#' `"multipliying"`. When quaternions represent actions, rotation is
#' conjugating the first quaternion by the second. This operation is performed
#' by the arguments `"action"` or `"conjugating"`.
#'
#' If it is not clear which to use, ask whether the identity quaternion (no
#' rotation at all) should become something other than the identity quaternion
#' after rotation. If so, use `"orientation"`; if not, use `"action"`.
#'
#' @param rotand Object to be rotated; can be either a vector or a quaternion
#' @param ... Additional arguments passed on to underlying S3 methods
#' @param rotator (Optional) Quaternion specifying the rotation to perform. If
Expand All @@ -55,6 +67,10 @@ make_rotator <- function(axis, angle, from, to) {
#' @param from,to (Optional) Instead of specifying an axis-angle pair, or angle
#' amount, a rotation is performed mapping the direction of `from` to the
#' direction of `to`.
#' @param as Specify the rotation to apply to the quaternion as the type of
#' object the quaternion represents or the mathematical operation to be
#' applied. Accepted values are `"action"`, `"orientation"`, `"multiplying"`,
#' and `"conjugating"`.
#'
#' @examples
#' example_vector <- vector3(x = 1:4, y = 2:5, z = 3:6)
Expand All @@ -79,7 +95,7 @@ rotate.dddr_vector3 <- function(rotand, rotator=NULL, ..., origin=NULL) {
rotand <- rotand - origin
}
rotand <- quat(0, rotand$x, rotand$y, rotand$z)
result <- rotate.dddr_quat(rotand, rotator, ...)
result <- rotate.dddr_quat(rotand, rotator, ..., as = "conjugating")
vec3_result <- vector3(result$x, result$y, result$z)
if (!is.null(origin)) {
vec3_result <- vec3_result + origin
Expand All @@ -92,7 +108,7 @@ rotate.dddr_vector3 <- function(rotand, rotator=NULL, ..., origin=NULL) {
#' @export
rotate.dddr_quat <- function(
rotand, rotator = NULL, ...,
axis = NULL, angle = NULL, from = NULL, to = NULL
axis = NULL, angle = NULL, from = NULL, to = NULL, as = NULL
) {
if (is.null(rotator)) {
rotator <- make_rotator(axis, angle, from, to)
Expand All @@ -103,5 +119,21 @@ rotate.dddr_quat <- function(
)
}
}
rotator * rotand * Conj(rotator)

if (is.null(as) ||
!(as %in% c("action", "orientation", "multiplying", "conjugating"))
) {
rlang::abort(paste(
"To rotate a quaternion, `as` should be specified as",
"\"action\", \"orientation\", \"multiplying\", or \"conjugating\"."
))
}

result <- rotator * rotand

if (as %in% c("action", "conjugating")) {
result <- result * Conj(rotator)
}

result
}
21 changes: 20 additions & 1 deletion man/rotation.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 13f5aac

Please sign in to comment.