struct Chem::Spatial::Quat

Overview

The quaternion is a mathematical construct that extends the complex numbers and it is useful to encode three-dimensional rotations. Quats are represented by four numbers (w, x, y, z), where w is considered as the real (scalar) part and x, y, z the imaginary (vector) part. Rotations can be encoded as a unit quaternion using the axis-angle representation, where x, y, z correspond to the rotation axis and w to the rotation angle by the following formula:

q(v, t) = q(w, x, y, z) = q(cos(t/2), sin(t/2)vx, sin(t/2)vy, sin(t/2)vz)

where v is a unit vector and t is the rotation angle. Quats have several useful mathematical properties, e.g., quaternion multiplication can be used to represent a sequence of rotations producing a single quaternion. Indeed, the rotation encoded in the quaternion q can be applied to a ordinary vector p simply by

p* = q * p * q-1

where q-1 is the inverse of q and p* is the rotated vector (see Quat#* for details).

Examples

q = Quat[1, 2, 3, 4]
q                 # => [1.0 2.0 3.0 4.0]
q.real            # => 1.0
q.imag            # => [2.0 3.0 4.0]
q.w               # => 1.0
q.x               # => 2.0
q.y               # => 3.0
q.z               # => 4.0
-q                # => [-1.0 -2.0 -3.0 -4.0]
q.abs             # => 5.477225575051661
q.abs2            # => 30.0
q.conj            # => [1.0 -2.0 -3.0 -4.0]
q.inv             # => [0.033 -0.067 -0.1 -0.133]
q.normalize       # => [0.183 0.365 0.548 0.730]
q.unit?           # => false
q.normalize.unit? # => true
q.zero?           # => false

q * 2  # => [2.0 4.0 6.0 8.0]
q / 10 # => [0.2 0.4 0.6 0.8]

p = Quat[4, 3, 2, 1]
p + q # => [5.0 5.0 5.0 5.0]
p * q # => [-12.0 16.0 4.0 22.0]
q * p # => [-12.0 6.0 24.0 12.0]

Use the convenience methods to encode rotations.

v = Vec3[1, 2, 3]
q = Quat.aligning v, to: Vec3[1, 0, 0]
q * v # => [3.742 0.0 0.0]
# or
v.transform(q)    # => [3.742 0.0 0.0]
(q * v).normalize # => [1.0 0.0 0.0]

q = Quat.rotation Vec3[0, 1, 0], by: 90
q * v # => [3.0 2.0 -1.0]
v * q # => [-3.0 2.0 1.0]

NOTE Quat multiplication is not commutative: q * v != v * p, the former will apply the rotation encoded in q to v but the latter will produce the inverse rotation. Use Vec3#transform to avoid the ambiguity.

Defined in:

chem/spatial/quat.cr

Constructors

Instance Method Summary

Constructor Detail

def self.[](w : Float64, x : Float64, y : Float64, z : Float64) : self #

Returns a quaternion with w as the real (scalar) part and x, y, and z as the vector (imaginary) part.


[View source]
def self.aligning(u : Vec3, to v : Vec3) : self #

Returns a quaternion encoding the rotation operation to align u to v.


[View source]
def self.aligning(u : Tuple(Vec3, Vec3), to v : Tuple(Vec3, Vec3)) : self #

Returns a quaternion encoding the rotation to align u[0] to v[0] and u[1] to v[1].

First compute the alignment of u[0] to v[0], then the alignment of the transformed u[1] to v[1] on the plane perpendicular to v[0] by taking their projections.


[View source]
def self.identity : self #

Returns the identity quaternion (no rotation).


[View source]
def self.new(w : Float64, x : Float64, y : Float64, z : Float64) #

Creates a new quaternion with w as the real (scalar) part and x, y, and z as the vector (imaginary) part.


[View source]
def self.rotation(x : Number, y : Number, z : Number) : self #

Returns a quaternion encoding the rotation by the Euler angles.

The rotation rotates x degrees around the X axis, y degrees around the Y axis, and z degrees around the y axis; applied in that order (XYZ).


[View source]
def self.rotation(about rotaxis : Vec3, by theta : Number) : self #

Returns a quaternion encoding the rotation about the axis vector rotaxis by theta degrees.


[View source]

Instance Method Detail

def *(rhs : self) : self #

Returns the Hamilton product of the quaternion and rhs.


[View source]
def *(rhs : Vec3) : Vec3 #

Returns the conjugate of rhs by the quaternion.

The conjugate of rhs is calculated as p* = q * p * q^-1, where p is a quaternion whose vector part is rhs and real part equals zero. Thus, the resulting quaternion is computed using the Hamilton product and its vector part corresponds to p*. Such operation can be written as (self * rhs.to_q * inv).imag, but this method implements an optimized version by using some vector and quaternion identities. The faster method is taken from this post of the molecular matters blog.

If the quaternion encodes a rotation about an axis, this effectively applies such rotation to rhs.


[View source]
def *(rhs : Number) : self #

Returns the element-wise multiplication of the quaternion by rhs.


[View source]
def +(rhs : self) : self #

Returns the element-wise addition of the quaternion by rhs.


[View source]
def -(rhs : self) : self #

Returns the element-wise subtraction of the quaternion by rhs.


[View source]
def - : self #

Returns the negation of the quaternion.


[View source]
def /(rhs : Number) : self #

Returns the element-wise division of the quaternion by rhs.


[View source]
def abs : Float64 #

Returns the absolute value (norm) using the Pythagorean theorem.


[View source]
def abs2 : Float64 #

Returns the square of the absolute value (norm).


[View source]
def close_to?(rhs : self, delta : Number = Float64::EPSILON) : Bool #

Returns true if the elements of the quaternions are within delta from each other, else false.

Quat[1, 2, 3, 4].close_to?(Quat[1, 2, 3, 4])                     # => true
Quat[1, 2, 3, 4].close_to?(Quat[1.001, 1.999, 3.00004, 4], 1e-3) # => true
Quat[1, 2, 3, 4].close_to?(Quat[4, 3, 2, 1])                     # => false
Quat[1, 2, 3, 4].close_to?(Quat[1.001, 1.999, 3.00004, 4], 1e-8) # => false

[View source]
def conj : self #

Returns the conjugate of the quaternion.


[View source]
def dot(rhs : self) : Float64 #

Returns the dot product of the quaternion and rhs.


[View source]
def imag : Vec3 #

Returns the imaginary part of the quaternion.


[View source]
def inv : self #

Returns the inverse of the quaternion.


[View source]
def normalize : self #

Returns the normalized quaternion of the quaternion.


[View source]
def real : Float64 #

Returns the real part of the quaternion.


[View source]
def to_mat3 : Mat3 #

Returns the rotation matrix equivalent to the quaternion.


[View source]
def to_s(io : IO) : Nil #
Description copied from struct Struct

Same as #inspect(io).


[View source]
def unit? : Bool #

Returns true if the quaternion is a unit quaternion, else false.


[View source]
def w : Float64 #

Real (scalar) part of the quaternion.


[View source]
def x : Float64 #

X component of the imaginary (vector) part of the quaternion.


[View source]
def y : Float64 #

Y component of the imaginary (vector) part of the quaternion.


[View source]
def z : Float64 #

Z component of the imaginary (vector) part of the quaternion.


[View source]
def zero? : Bool #

Returns true if the quaternion is a zero quaternion, else false.


[View source]