Published
Edited
Jul 16, 2019
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
a = quat.create()
Insert cell
Insert cell
b = quatCreate()
Insert cell
Insert cell
quat = ({
add: quatAdd,
calculateW: quatCalculateW,
clone: quatClone,
conjugate: quatConjugate,
copy: quatCopy,
create: quatCreate,
dot: quatDot,
fromMat3: quatFromMat3,
fromValues: quatFromValues,
identity: quatIdentity,
invert: quatInvert,
length: quatLength,
len: quatLen,
lerp: quatLerp,
multiply: quatMultiply,
mul: quatMul,
normalize: quatNormalize,
rotateX: quatRotateX,
rotateY: quatRotateY,
rotateZ: quatRotateZ,
rotationTo: quatRotationTo,
scale: quatScale,
set: quatSet,
setAxes: quatSetAxes,
setAxisAngle: quatSetAxisAngle,
slerp: quatSlerp,
sqlerp: quatSqlerp,
squaredLength: quatSquaredLength,
sqrLen: quatSqrLen,
})
Insert cell
import {vec4add, vec4clone, vec4copy, vec4create, vec4dot, vec4fromValues, vec4length, vec4lerp, vec4normalize, vec4scale, vec4set, vec4squaredLength} from '@rreusser/gl-vec4'
Insert cell
import {vec3dot, vec3cross, vec3normalize, vec3length} from '@rreusser/gl-vec3'
Insert cell
import {mat3create} from '@rreusser/gl-mat3'
Insert cell
/**
* Adds two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
* @function
*/
quatAdd = vec4add
Insert cell
/**
* Calculates the W component of a quat from the X, Y, and Z components.
* Assumes that quaternion is 1 unit in length.
* Any existing W component will be ignored.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate W component of
* @returns {quat} out
*/
function quatCalculateW (out, a) {
var x = a[0], y = a[1], z = a[2]

out[0] = x
out[1] = y
out[2] = z
out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z))
return out
}
Insert cell
/**
* Creates a new quat initialized with values from an existing quaternion
*
* @param {quat} a quaternion to clone
* @returns {quat} a new quaternion
* @function
*/
quatClone = vec4clone
Insert cell
/**
* Calculates the conjugate of a quat
* If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate conjugate of
* @returns {quat} out
*/
function quatConjugate (out, a) {
out[0] = -a[0]
out[1] = -a[1]
out[2] = -a[2]
out[3] = a[3]
return out
}
Insert cell
/**
* Copy the values from one quat to another
*
* @param {quat} out the receiving quaternion
* @param {quat} a the source quaternion
* @returns {quat} out
* @function
*/
quatCopy = vec4copy
Insert cell
/**
* Creates a new identity quat
*
* @returns {quat} a new quaternion
*/
function quatCreate () {
var out = new Float32Array(4)
out[0] = 0
out[1] = 0
out[2] = 0
out[3] = 1
return out
}
Insert cell
/**
* Calculates the dot product of two quat's
*
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {Number} dot product of a and b
* @function
*/
quatDot = vec4dot
Insert cell
/**
* Creates a quaternion from the given 3x3 rotation matrix.
*
* NOTE: The resultant quaternion is not normalized, so you should be sure
* to renormalize the quaternion yourself where necessary.
*
* @param {quat} out the receiving quaternion
* @param {mat3} m rotation matrix
* @returns {quat} out
* @function
*/
function quatFromMat3 (out, m) {
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
// article "Quaternion Calculus and Fast Animation".
var fTrace = m[0] + m[4] + m[8]
var fRoot

if (fTrace > 0.0) {
// |w| > 1/2, may as well choose w > 1/2
fRoot = Math.sqrt(fTrace + 1.0) // 2w
out[3] = 0.5 * fRoot
fRoot = 0.5 / fRoot // 1/(4w)
out[0] = (m[5] - m[7]) * fRoot
out[1] = (m[6] - m[2]) * fRoot
out[2] = (m[1] - m[3]) * fRoot
} else {
// |w| <= 1/2
var i = 0
if (m[4] > m[0]) {
i = 1
}
if (m[8] > m[i * 3 + i]) {
i = 2
}
var j = (i + 1) % 3
var k = (i + 2) % 3

fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0)
out[i] = 0.5 * fRoot
fRoot = 0.5 / fRoot
out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot
out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot
out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot
}

return out
}
Insert cell
/**
* Creates a new quat initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} a new quaternion
* @function
*/
quatFromValues = vec4fromValues
Insert cell
/**
* Set a quat to the identity quaternion
*
* @param {quat} out the receiving quaternion
* @returns {quat} out
*/
function quatIdentity (out) {
out[0] = 0
out[1] = 0
out[2] = 0
out[3] = 1
return out
}
Insert cell
/**
* Calculates the inverse of a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate inverse of
* @returns {quat} out
*/
function quatInvert (out, a) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3,
invDot = dot ? 1.0 / dot : 0

// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0

out[0] = -a0 * invDot
out[1] = -a1 * invDot
out[2] = -a2 * invDot
out[3] = a3 * invDot
return out
}
Insert cell
/**
* Calculates the length of a quat
*
* @param {quat} a vector to calculate length of
* @returns {Number} length of a
* @function
*/
quatLength = vec4length
Insert cell
quatLen = quatLength
Insert cell
/**
* Performs a linear interpolation between two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
* @function
*/
quatLerp = vec4lerp
Insert cell
/**
* Multiplies two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
*/
function quatMultiply (out, a, b) {
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = b[0], by = b[1], bz = b[2], bw = b[3]

out[0] = ax * bw + aw * bx + ay * bz - az * by
out[1] = ay * bw + aw * by + az * bx - ax * bz
out[2] = az * bw + aw * bz + ax * by - ay * bx
out[3] = aw * bw - ax * bx - ay * by - az * bz
return out
}
Insert cell
quatMul = quatMultiply
Insert cell
/**
* Normalize a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quaternion to normalize
* @returns {quat} out
* @function
*/
quatNormalize = vec4normalize
Insert cell
/**
* Rotates a quaternion by the given angle about the X axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
function quatRotateX (out, a, rad) {
rad *= 0.5

var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = Math.sin(rad), bw = Math.cos(rad)

out[0] = ax * bw + aw * bx
out[1] = ay * bw + az * bx
out[2] = az * bw - ay * bx
out[3] = aw * bw - ax * bx
return out
}
Insert cell
/**
* Rotates a quaternion by the given angle about the Y axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
function quatRotateY (out, a, rad) {
rad *= 0.5

var ax = a[0], ay = a[1], az = a[2], aw = a[3],
by = Math.sin(rad), bw = Math.cos(rad)

out[0] = ax * bw - az * by
out[1] = ay * bw + aw * by
out[2] = az * bw + ax * by
out[3] = aw * bw - ay * by
return out
}
Insert cell
/**
* Rotates a quaternion by the given angle about the Z axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
function quatRotateZ (out, a, rad) {
rad *= 0.5

var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bz = Math.sin(rad), bw = Math.cos(rad)

out[0] = ax * bw + ay * bz
out[1] = ay * bw - ax * bz
out[2] = az * bw + aw * bz
out[3] = aw * bw - az * bz
return out
}
Insert cell
/**
* Sets a quaternion to represent the shortest rotation from one
* vector to another.
*
* Both vectors are assumed to be unit length.
*
* @param {quat} out the receiving quaternion.
* @param {vec3} a the initial vector
* @param {vec3} b the destination vector
* @returns {quat} out
*/
quatRotationTo = {
let tmpvec3 = [0, 0, 0]
let xUnitVec3 = [1, 0, 0]
let yUnitVec3 = [0, 1, 0]

return function quatRotationTo (out, a, b) {
var dot = vec3dot(a, b)
if (dot < -0.999999) {
vec3cross(tmpvec3, xUnitVec3, a)
if (vec3length(tmpvec3) < 0.000001) {
vec3cross(tmpvec3, yUnitVec3, a)
}
vec3normalize(tmpvec3, tmpvec3)
quatSetAxisAngle(out, tmpvec3, Math.PI)
return out
} else if (dot > 0.999999) {
out[0] = 0
out[1] = 0
out[2] = 0
out[3] = 1
return out
} else {
vec3cross(tmpvec3, a, b)
out[0] = tmpvec3[0]
out[1] = tmpvec3[1]
out[2] = tmpvec3[2]
out[3] = 1 + dot
return quatNormalize(out, out)
}
}
}
Insert cell
/**
* Scales a quat by a scalar number
*
* @param {quat} out the receiving vector
* @param {quat} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {quat} out
* @function
*/
quatScale = vec4scale
Insert cell
/**
* Set the components of a quat to the given values
*
* @param {quat} out the receiving quaternion
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} out
* @function
*/
quatSet = vec4set
Insert cell
/**
* Sets the specified quaternion with values corresponding to the given
* axes. Each axis is a vec3 and is expected to be unit length and
* perpendicular to all other specified axes.
*
* @param {vec3} view the vector representing the viewing direction
* @param {vec3} right the vector representing the local "right" direction
* @param {vec3} up the vector representing the local "up" direction
* @returns {quat} out
*/
quatSetAxes = {
var matr = mat3create()

return function setAxes (out, view, right, up) {
matr[0] = right[0]
matr[3] = right[1]
matr[6] = right[2]

matr[1] = up[0]
matr[4] = up[1]
matr[7] = up[2]

matr[2] = -view[0]
matr[5] = -view[1]
matr[8] = -view[2]

return quatNormalize(out, quatFromMat3(out, matr))
}
}
Insert cell
/**
* Sets a quat from the given angle and rotation axis,
* then returns it.
*
* @param {quat} out the receiving quaternion
* @param {vec3} axis the axis around which to rotate
* @param {Number} rad the angle in radians
* @returns {quat} out
**/
function quatSetAxisAngle (out, axis, rad) {
rad = rad * 0.5
var s = Math.sin(rad)
out[0] = s * axis[0]
out[1] = s * axis[1]
out[2] = s * axis[2]
out[3] = Math.cos(rad)
return out
}
Insert cell
/**
* Performs a spherical linear interpolation between two quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
*/
function quatSlerp (out, a, b, t) {
// benchmarks:
// http://jsperf.com/quaternion-slerp-implementations

var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = b[0], by = b[1], bz = b[2], bw = b[3]

var omega, cosom, sinom, scale0, scale1

// calc cosine
cosom = ax * bx + ay * by + az * bz + aw * bw
// adjust signs (if necessary)
if (cosom < 0.0) {
cosom = -cosom
bx = -bx
by = -by
bz = -bz
bw = -bw
}
// calculate coefficients
if ((1.0 - cosom) > 0.000001) {
// standard case (slerp)
omega = Math.acos(cosom)
sinom = Math.sin(omega)
scale0 = Math.sin((1.0 - t) * omega) / sinom
scale1 = Math.sin(t * omega) / sinom
} else {
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0 - t
scale1 = t
}
// calculate final values
out[0] = scale0 * ax + scale1 * bx
out[1] = scale0 * ay + scale1 * by
out[2] = scale0 * az + scale1 * bz
out[3] = scale0 * aw + scale1 * bw

return out
}
Insert cell
/**
* Performs a spherical linear interpolation with two control points
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {quat} c the third operand
* @param {quat} d the fourth operand
* @param {Number} t interpolation amount
* @returns {quat} out
*/
quatSqlerp = {
var temp1 = vec4create()
var temp2 = vec4create()

return function sqlerp (out, a, b, c, d, t) {
quatSlerp(temp1, a, d, t)
quatSlerp(temp2, b, c, t)
quatSlerp(out, temp1, temp2, 2 * t * (1 - t))

return out
}
}
Insert cell
/**
* Calculates the squared length of a quat
*
* @param {quat} a vector to calculate squared length of
* @returns {Number} squared length of a
* @function
*/
quatSquaredLength = vec4squaredLength
Insert cell
quatSqrLen = quatSquaredLength
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more