UNPKG

@turbox3d/math

Version:

Large-scale graphics application math library

488 lines 15 kB
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import { MathUtils } from '../MathUtils'; var Quaternion = /*#__PURE__*/function () { function Quaternion() { var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var w = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1; _classCallCheck(this, Quaternion); this._onChangeCallback = function () { // }; this.isQuaternion = true; this._x = x; this._y = y; this._z = z; this._w = w; } return _createClass(Quaternion, [{ key: "x", get: function get() { return this._x; }, set: function set(value) { this._x = value; this._onChangeCallback(); } }, { key: "y", get: function get() { return this._y; }, set: function set(value) { this._y = value; this._onChangeCallback(); } }, { key: "z", get: function get() { return this._z; }, set: function set(value) { this._z = value; this._onChangeCallback(); } }, { key: "w", get: function get() { return this._w; }, set: function set(value) { this._w = value; this._onChangeCallback(); } }, { key: "set", value: function set(x, y, z, w) { this._x = x; this._y = y; this._z = z; this._w = w; this._onChangeCallback(); return this; } }, { key: "clone", value: function clone() { return new Quaternion(this._x, this._y, this._z, this._w); } }, { key: "copy", value: function copy(quaternion) { this._x = quaternion.x; this._y = quaternion.y; this._z = quaternion.z; this._w = quaternion.w; this._onChangeCallback(); return this; } }, { key: "setFromEuler", value: function setFromEuler(euler) { var x = euler._x; var y = euler._y; var z = euler._z; var order = euler._order; // http://www.mathworks.com/matlabcentral/fileexchange/ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ // content/SpinCalc.m var cos = Math.cos; var sin = Math.sin; var c1 = cos(x / 2); var c2 = cos(y / 2); var c3 = cos(z / 2); var s1 = sin(x / 2); var s2 = sin(y / 2); var s3 = sin(z / 2); switch (order) { case 'XYZ': this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; break; case 'YXZ': this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; break; case 'ZXY': this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; break; case 'ZYX': this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; break; case 'YZX': this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; break; case 'XZY': this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; break; default: console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: ".concat(order)); } this._onChangeCallback(); return this; } }, { key: "setFromAxisAngle", value: function setFromAxisAngle(axis, angle) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm // assumes axis is normalized var halfAngle = angle / 2; var s = Math.sin(halfAngle); this._x = axis.x * s; this._y = axis.y * s; this._z = axis.z * s; this._w = Math.cos(halfAngle); this._onChangeCallback(); return this; } }, { key: "setFromRotationMatrix", value: function setFromRotationMatrix(m) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var te = m.elements; var m11 = te[0]; var m12 = te[4]; var m13 = te[8]; var m21 = te[1]; var m22 = te[5]; var m23 = te[9]; var m31 = te[2]; var m32 = te[6]; var m33 = te[10]; var trace = m11 + m22 + m33; if (trace > 0) { var s = 0.5 / Math.sqrt(trace + 1.0); this._w = 0.25 / s; this._x = (m32 - m23) * s; this._y = (m13 - m31) * s; this._z = (m21 - m12) * s; } else if (m11 > m22 && m11 > m33) { var _s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33); this._w = (m32 - m23) / _s; this._x = 0.25 * _s; this._y = (m12 + m21) / _s; this._z = (m13 + m31) / _s; } else if (m22 > m33) { var _s2 = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33); this._w = (m13 - m31) / _s2; this._x = (m12 + m21) / _s2; this._y = 0.25 * _s2; this._z = (m23 + m32) / _s2; } else { var _s3 = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22); this._w = (m21 - m12) / _s3; this._x = (m13 + m31) / _s3; this._y = (m23 + m32) / _s3; this._z = 0.25 * _s3; } this._onChangeCallback(); return this; } }, { key: "setFromUnitVectors", value: function setFromUnitVectors(vFrom, vTo) { // assumes direction vectors vFrom and vTo are normalized var EPS = 0.000001; var r = vFrom.dot(vTo) + 1; if (r < EPS) { r = 0; if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) { this._x = -vFrom.y; this._y = vFrom.x; this._z = 0; this._w = r; } else { this._x = 0; this._y = -vFrom.z; this._z = vFrom.y; this._w = r; } } else { // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; this._w = r; } return this.normalize(); } }, { key: "angleTo", value: function angleTo(q) { return 2 * Math.acos(Math.abs(MathUtils.clamp(this.dot(q), -1, 1))); } }, { key: "rotateTowards", value: function rotateTowards(q, step) { var angle = this.angleTo(q); if (angle === 0) return this; var t = Math.min(1, step / angle); this.slerp(q, t); return this; } }, { key: "identity", value: function identity() { return this.set(0, 0, 0, 1); } }, { key: "invert", value: function invert() { // quaternion is assumed to have unit length return this.conjugate(); } }, { key: "conjugate", value: function conjugate() { this._x *= -1; this._y *= -1; this._z *= -1; this._onChangeCallback(); return this; } }, { key: "dot", value: function dot(v) { return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; } }, { key: "lengthSq", value: function lengthSq() { return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; } }, { key: "length", value: function length() { return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w); } }, { key: "normalize", value: function normalize() { var l = this.length(); if (l === 0) { this._x = 0; this._y = 0; this._z = 0; this._w = 1; } else { l = 1 / l; this._x *= l; this._y *= l; this._z *= l; this._w *= l; } this._onChangeCallback(); return this; } }, { key: "multiply", value: function multiply(q) { return this.multiplyQuaternions(this, q); } }, { key: "premultiply", value: function premultiply(q) { return this.multiplyQuaternions(q, this); } }, { key: "multiplyQuaternions", value: function multiplyQuaternions(a, b) { // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm var qax = a._x; var qay = a._y; var qaz = a._z; var qaw = a._w; var qbx = b._x; var qby = b._y; var qbz = b._z; var qbw = b._w; this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; this._onChangeCallback(); return this; } }, { key: "slerp", value: function slerp(qb, t) { if (t === 0) return this; if (t === 1) return this.copy(qb); var x = this._x; var y = this._y; var z = this._z; var w = this._w; // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; if (cosHalfTheta < 0) { this._w = -qb._w; this._x = -qb._x; this._y = -qb._y; this._z = -qb._z; cosHalfTheta = -cosHalfTheta; } else { this.copy(qb); } if (cosHalfTheta >= 1.0) { this._w = w; this._x = x; this._y = y; this._z = z; return this; } var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; if (sqrSinHalfTheta <= Number.EPSILON) { var s = 1 - t; this._w = s * w + t * this._w; this._x = s * x + t * this._x; this._y = s * y + t * this._y; this._z = s * z + t * this._z; this.normalize(); this._onChangeCallback(); return this; } var sinHalfTheta = Math.sqrt(sqrSinHalfTheta); var halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta); var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta; var ratioB = Math.sin(t * halfTheta) / sinHalfTheta; this._w = w * ratioA + this._w * ratioB; this._x = x * ratioA + this._x * ratioB; this._y = y * ratioA + this._y * ratioB; this._z = z * ratioA + this._z * ratioB; this._onChangeCallback(); return this; } }, { key: "equals", value: function equals(quaternion) { return quaternion._x === this._x && quaternion._y === this._y && quaternion._z === this._z && quaternion._w === this._w; } }, { key: "fromArray", value: function fromArray(array) { var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; this._x = array[offset]; this._y = array[offset + 1]; this._z = array[offset + 2]; this._w = array[offset + 3]; this._onChangeCallback(); return this; } }, { key: "toArray", value: function toArray() { var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; array[offset] = this._x; array[offset + 1] = this._y; array[offset + 2] = this._z; array[offset + 3] = this._w; return array; } }, { key: "_onChange", value: function _onChange(callback) { this._onChangeCallback = callback; return this; } }], [{ key: "slerp", value: function slerp(qa, qb, qm, t) { return qm.copy(qa).slerp(qb, t); } }, { key: "slerpFlat", value: function slerpFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t) { // fuzz-free, array-based Quaternion SLERP operation var x0 = src0[srcOffset0 + 0]; var y0 = src0[srcOffset0 + 1]; var z0 = src0[srcOffset0 + 2]; var w0 = src0[srcOffset0 + 3]; var x1 = src1[srcOffset1 + 0]; var y1 = src1[srcOffset1 + 1]; var z1 = src1[srcOffset1 + 2]; var w1 = src1[srcOffset1 + 3]; if (t === 0) { dst[dstOffset + 0] = x0; dst[dstOffset + 1] = y0; dst[dstOffset + 2] = z0; dst[dstOffset + 3] = w0; return; } if (t === 1) { dst[dstOffset + 0] = x1; dst[dstOffset + 1] = y1; dst[dstOffset + 2] = z1; dst[dstOffset + 3] = w1; return; } if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1) { var s = 1 - t; var cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1; var dir = cos >= 0 ? 1 : -1; var sqrSin = 1 - cos * cos; // Skip the Slerp for tiny steps to avoid numeric problems: if (sqrSin > Number.EPSILON) { var sin = Math.sqrt(sqrSin); var len = Math.atan2(sin, cos * dir); s = Math.sin(s * len) / sin; t = Math.sin(t * len) / sin; } var tDir = t * dir; x0 = x0 * s + x1 * tDir; y0 = y0 * s + y1 * tDir; z0 = z0 * s + z1 * tDir; w0 = w0 * s + w1 * tDir; // Normalize in case we just did a lerp: if (s === 1 - t) { var f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0); x0 *= f; y0 *= f; z0 *= f; w0 *= f; } } dst[dstOffset] = x0; dst[dstOffset + 1] = y0; dst[dstOffset + 2] = z0; dst[dstOffset + 3] = w0; } }, { key: "multiplyQuaternionsFlat", value: function multiplyQuaternionsFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1) { var x0 = src0[srcOffset0]; var y0 = src0[srcOffset0 + 1]; var z0 = src0[srcOffset0 + 2]; var w0 = src0[srcOffset0 + 3]; var x1 = src1[srcOffset1]; var y1 = src1[srcOffset1 + 1]; var z1 = src1[srcOffset1 + 2]; var w1 = src1[srcOffset1 + 3]; dst[dstOffset] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; dst[dstOffset + 1] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; dst[dstOffset + 2] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; dst[dstOffset + 3] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; return dst; } }]); }(); export { Quaternion };