quaternion
Version:
The RAW rotation library using quaternions
28 lines (26 loc) • 9.89 kB
JavaScript
/*
Quaternion.js v2.2.0 9/17/2025
https://raw.org/book/algebra/quaternions/
Copyright (c) 2025, Robert Eisele (https://raw.org/)
Licensed under the MIT license.
*/
'use strict';(function(C){function n(a,b,c,e){const d=Object.create(m.prototype);d.w=a;d.x=b;d.y=c;d.z=e;return d}function u(a,b,c,e){const d=Object.create(m.prototype),f=1/Math.sqrt(a*a+b*b+c*c+e*e);d.w=a*f;d.x=b*f;d.y=c*f;d.z=e*f;return d}function z(a,b){const c=Math.max(Math.abs(a),Math.abs(b));if(c===0)return-Infinity;a/=c;b/=c;return Math.log(c)+.5*Math.log(a*a+b*b)}function t(a,b,c,e,d){if(d!==void 0)a.w=b,a.x=c,a.y=e,a.z=d;else{if(typeof b==="object"&&e===void 0){if("w"in b||"x"in b||"y"in
b||"z"in b){a.w=b.w||0;a.x=b.x||0;a.y=b.y||0;a.z=b.z||0;return}if("re"in b&&"im"in b){a.w=b.re;a.x=b.im;a.y=0;a.z=0;return}if(b.length===4){a.w=b[0];a.x=b[1];a.y=b[2];a.z=b[3];return}if(b.length===3){a.w=0;a.x=b[0];a.y=b[1];a.z=b[2];return}throw Error("Invalid object");}if(typeof b==="string"&&e===void 0){b=b.toLowerCase().match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g);var f=1;c=0;e={i:"x",j:"y",k:"z"};if(b===null)throw Error("Parse error");a.w=a.x=a.y=a.z=0;for(d=0;d<b.length;d++){let g=b[d],h=b[d+
1];if(g!==" "&&g!=="\t"&&g!=="\n")if(g==="+")f++;else if(g==="-")c++;else{if(f+c===0)throw Error("Parse error"+g);f=e[g];if(f!==void 0)h===" "||isNaN(h)?g="1":(g=h,d++);else{if(isNaN(g))throw Error("Parser error");f=e[h];f!==void 0&&d++}a[f||"w"]+=parseFloat((c%2?"-":"")+g);f=c=0}}if(f+c>0)throw Error("Parser error");}else b===void 0&&a!==k?(a.w=1,a.x=a.y=a.z=0):(a.w=b||0,c&&c.length===3?(a.x=c[0],a.y=c[1],a.z=c[2]):(a.x=c||0,a.y=e||0,a.z=d||0))}}function y(a,b,c){let e="";if(a!==0){c!==""?e+=a<0?
" - ":" + ":a<0&&(e+="-");a=Math.abs(a);if(1!==a||b==="")e+=a;e+=b}return e}function m(a,b,c,e){if(this instanceof m)t(this,a,b,c,e);else{const d=Object.create(m.prototype);t(d,a,b,c,e);return d}}const k=Object.create(m.prototype);m.prototype={w:1,x:0,y:0,z:0,add:function(a,b,c,e){t(k,a,b,c,e);return n(this.w+k.w,this.x+k.x,this.y+k.y,this.z+k.z)},sub:function(a,b,c,e){t(k,a,b,c,e);return n(this.w-k.w,this.x-k.x,this.y-k.y,this.z-k.z)},neg:function(){return n(-this.w,-this.x,-this.y,-this.z)},norm:function(){const a=
this.w,b=this.x,c=this.y,e=this.z;return Math.sqrt(a*a+b*b+c*c+e*e)},normSq:function(){const a=this.w,b=this.x,c=this.y,e=this.z;return a*a+b*b+c*c+e*e},normalize:function(){const a=this.w,b=this.x,c=this.y,e=this.z;let d=Math.sqrt(a*a+b*b+c*c+e*e);if(d<1E-12)return m.ZERO;d=1/d;return n(a*d,b*d,c*d,e*d)},mul:function(a,b,c,e){t(k,a,b,c,e);a=this.w;b=this.x;c=this.y;e=this.z;const d=k.w,f=k.x,g=k.y,h=k.z;return f===0&&g===0&&h===0?n(this.w*d,this.x*d,this.y*d,this.z*d):n(a*d-b*f-c*g-e*h,a*f+b*d+c*
h-e*g,a*g+c*d+e*f-b*h,a*h+e*d+b*g-c*f)},scale:function(a){return n(this.w*a,this.x*a,this.y*a,this.z*a)},dot:function(a,b,c,e){t(k,a,b,c,e);return this.w*k.w+this.x*k.x+this.y*k.y+this.z*k.z},inverse:function(){const a=this.w,b=this.x,c=this.y,e=this.z;let d=a*a+b*b+c*c+e*e;if(d===0)return m.ZERO;d=1/d;return n(a*d,-b*d,-c*d,-e*d)},div:function(a,b,c,e){t(k,a,b,c,e);a=this.w;b=this.x;c=this.y;e=this.z;const d=k.w,f=k.x,g=k.y,h=k.z;let l=d*d+f*f+g*g+h*h;if(l===0)return m.ZERO;l=1/l;return n((a*d+b*
f+c*g+e*h)*l,(b*d-a*f-c*h+e*g)*l,(c*d-a*g-e*f+b*h)*l,(e*d-a*h-b*g+c*f)*l)},conjugate:function(){return n(this.w,-this.x,-this.y,-this.z)},exp:function(){const a=this.x,b=this.y,c=this.z,e=Math.sqrt(a*a+b*b+c*c),d=Math.exp(this.w);if(e===0)return n(d,0,0,0);const f=e<1E-8?d*(1-e*e/6):d*Math.sin(e)/e;return n(d*Math.cos(e),a*f,b*f,c*f)},log:function(){const a=this.w,b=this.x,c=this.y,e=this.z;if(c===0&&e===0)return n(z(a,b),Math.atan2(b,a),0,0);var d=Math.sqrt(b*b+c*c+e*e);d=d<1E-12?1/Math.max(1,a):
Math.atan2(d,a)/d;return n(Math.log(b*b+c*c+e*e+a*a)*.5,b*d,c*d,e*d)},pow:function(a,b,c,e){t(k,a,b,c,e);if(k.y===0&&k.z===0){if(k.w===1&&k.x===0)return this;if(k.w===0&&k.x===0)return m.ONE;if(this.y===0&&this.z===0){a=this.w;b=this.x;if(a===0&&b===0)return m.ZERO;c=Math.atan2(b,a);e=z(a,b);if(k.x===0&&b===0&&a>=0)return n(Math.pow(a,k.w),0,0,0);a=Math.exp(k.w*e-k.x*c);b=k.x*e+k.w*c;return n(a*Math.cos(b),a*Math.sin(b),0,0)}}return this.log().mul(k).exp()},equals:function(a,b,c,e){t(k,a,b,c,e);return Math.abs(k.w-
this.w)<1E-12&&Math.abs(k.x-this.x)<1E-12&&Math.abs(k.y-this.y)<1E-12&&Math.abs(k.z-this.z)<1E-12},isUnit:function(){const a=this.w*this.w+this.x*this.x+this.y*this.y+this.z*this.z;return Math.abs(a-1)<1E-12*Math.max(1,a)},isFinite:function(){return isFinite(this.w)&&isFinite(this.x)&&isFinite(this.y)&&isFinite(this.z)},isNaN:function(){return isNaN(this.w)||isNaN(this.x)||isNaN(this.y)||isNaN(this.z)},toString:function(){var a=this.w;const b=this.x,c=this.y,e=this.z;if(isNaN(a)||isNaN(b)||isNaN(c)||
isNaN(e))return"NaN";a=y(a,"","");a+=y(b,"i",a);a+=y(c,"j",a);a+=y(e,"k",a);return""===a?"0":a},real:function(){return this.w},imag:function(){return[this.x,this.y,this.z]},toVector:function(){return[this.w,this.x,this.y,this.z]},toMatrix:function(a){var b=this.w,c=this.x,e=this.y,d=this.z;const f=b*c,g=b*e;b*=d;const h=c*c,l=c*e;c*=d;const p=e*e;e*=d;d*=d;return a?[[1-2*(p+d),2*(l-b),2*(c+g)],[2*(l+b),1-2*(h+d),2*(e-f)],[2*(c-g),2*(e+f),1-2*(h+p)]]:[1-2*(p+d),2*(l-b),2*(c+g),2*(l+b),1-2*(h+d),2*
(e-f),2*(c-g),2*(e+f),1-2*(h+p)]},toMatrix4:function(a){var b=this.w,c=this.x,e=this.y,d=this.z;const f=b*c,g=b*e;b*=d;const h=c*c,l=c*e;c*=d;const p=e*e;e*=d;d*=d;return a?[[1-2*(p+d),2*(l-b),2*(c+g),0],[2*(l+b),1-2*(h+d),2*(e-f),0],[2*(c-g),2*(e+f),1-2*(h+p),0],[0,0,0,1]]:[1-2*(p+d),2*(l-b),2*(c+g),0,2*(l+b),1-2*(h+d),2*(e-f),0,2*(c-g),2*(e+f),1-2*(h+p),0,0,0,0,1]},toCSSTransform:function(){var a=Math.max(-1,Math.min(1,this.w));let b=2*Math.acos(a);a=1-a*a;a<1E-12?(b=0,a=1):a=1/Math.sqrt(a);return"rotate3d("+
this.x*a+","+this.y*a+","+this.z*a+","+b+"rad)"},toAxisAngle:function(){const a=Math.max(-1,Math.min(1,this.w));var b=1-a*a;if(b<1E-12)return[[this.x,this.y,this.z],0];b=1/Math.sqrt(b);return[[this.x*b,this.y*b,this.z*b],2*Math.acos(a)]},toEuler:function(a){function b(v){return v>=1?Math.PI/2:v<=-1?-Math.PI/2:Math.asin(v)}var c=this.w,e=this.x,d=this.y,f=this.z;const g=c*e,h=c*d;c*=f;const l=e*e,p=e*d;e*=f;const q=d*d;d*=f;f*=f;return a===void 0||a==="ZXY"?[-Math.atan2(2*(p-c),1-2*(l+f)),b(2*(d+g)),
-Math.atan2(2*(e-h),1-2*(l+q))]:a==="XYZ"||a==="RPY"?[-Math.atan2(2*(d-g),1-2*(l+q)),b(2*(e+h)),-Math.atan2(2*(p-c),1-2*(q+f))]:a==="YXZ"?[Math.atan2(2*(e+h),1-2*(l+q)),-b(2*(d-g)),Math.atan2(2*(p+c),1-2*(l+f))]:a==="ZYX"||a==="YPR"?[Math.atan2(2*(p+c),1-2*(q+f)),-b(2*(e-h)),Math.atan2(2*(d+g),1-2*(l+q))]:a==="YZX"?[-Math.atan2(2*(e-h),1-2*(q+f)),b(2*(p+c)),-Math.atan2(2*(d-g),1-2*(l+f))]:a==="XZY"?[Math.atan2(2*(d+g),1-2*(l+f)),-b(2*(p-c)),Math.atan2(2*(e+h),1-2*(q+f))]:null},clone:function(){return n(this.w,
this.x,this.y,this.z)},rotateVector:function(a){var b=this.w;const c=this.x,e=this.y;var d=this.z,f=a.x??a[0];const g=a.y??a[1],h=a.z??a[2];let l=e*h-d*g,p=d*f-c*h,q=c*g-e*f;l+=l;p+=p;q+=q;f=f+b*l+e*q-d*p;d=g+b*p+d*l-c*q;b=h+b*q+c*p-e*l;return Array.isArray(a)?[f,d,b]:{x:f,y:d,z:b}},slerp:function(a,b,c,e){t(k,a,b,c,e);let d=this.w,f=this.x,g=this.y,h=this.z,l=k.w,p=k.x,q=k.y,v=k.z,x=d*l+f*p+g*q+h*v;x<0&&(d=-d,f=-f,g=-g,h=-h,x=-x);if(x>=1-1E-12)return function(r){return u(d+r*(l-d),f+r*(p-f),g+r*
(q-g),h+r*(v-h))};let A=Math.acos(x),B=Math.sin(A);return function(r){var w=A*r;r=Math.sin(w);w=Math.cos(w)-x*r/B;r/=B;return n(w*d+r*l,w*f+r*p,w*g+r*q,w*h+r*v)}}};m.ZERO=n(0,0,0,0);m.ONE=n(1,0,0,0);m.I=n(0,1,0,0);m.J=n(0,0,1,0);m.K=n(0,0,0,1);Object.freeze(m.ZERO);Object.freeze(m.ONE);Object.freeze(m.I);Object.freeze(m.J);Object.freeze(m.K);m.fromAxisAngle=function(a,b){const c=a[0],e=a[1];a=a[2];var d=c*c+e*e+a*a;if(d===0)return m.ONE;b*=.5;d=Math.sin(b)/Math.sqrt(d);return n(Math.cos(b),c*d,e*
d,a*d)};m.fromVectors=function(a,b){let c=a[0],e=a[1];a=a[2];let d=b[0],f=b[1];b=b[2];var g=Math.sqrt(c*c+e*e+a*a);const h=Math.sqrt(d*d+f*f+b*b);g>0&&(c/=g,e/=g,a/=g);h>0&&(d/=h,f/=h,b/=h);g=c*d+e*f+a*b;return g>=1-1E-12?m.ONE:1+g<=1E-12?Math.abs(c)>Math.abs(a)?u(0,-e,c,0):u(0,0,-a,e):u(1+g,e*b-a*f,a*d-c*b,c*f-e*d)};m.random=function(){var a=Math.random();const b=Math.random(),c=Math.random(),e=Math.sqrt(1-a);a=Math.sqrt(a);return n(a*Math.cos(2*Math.PI*c),e*Math.sin(2*Math.PI*b),e*Math.cos(2*Math.PI*
b),a*Math.sin(2*Math.PI*c))};m.fromEulerLogical=function(a,b,c,e){return m.fromEuler(c,b,a,e!==void 0?e[2]+e[1]+e[0]:e)};m.fromEuler=function(a,b,c,e){var d=a*.5,f=b*.5,g=c*.5;c=Math.cos(d);b=Math.cos(f);a=Math.cos(g);d=Math.sin(d);f=Math.sin(f);g=Math.sin(g);return e===void 0||e==="ZXY"?n(c*b*a-d*f*g,f*c*a-d*g*b,d*f*a+g*c*b,d*b*a+f*g*c):e==="XYZ"||e==="RPY"?n(c*b*a-d*f*g,d*b*a+f*g*c,f*c*a-d*g*b,d*f*a+g*c*b):e==="YXZ"?n(d*f*g+c*b*a,d*g*b+f*c*a,d*b*a-f*g*c,g*c*b-d*f*a):e==="ZYX"||e==="YPR"?n(d*f*g+
c*b*a,g*c*b-d*f*a,d*g*b+f*c*a,d*b*a-f*g*c):e==="YZX"?n(c*b*a-d*f*g,d*f*a+g*c*b,d*b*a+f*g*c,f*c*a-d*g*b):e==="XZY"?n(d*f*g+c*b*a,d*b*a-f*g*c,g*c*b-d*f*a,d*g*b+f*c*a):e==="ZYZ"?n(c*b*a-d*g*b,f*g*c-d*f*a,d*f*g+f*c*a,d*b*a+g*c*b):e==="ZXZ"?n(c*b*a-d*g*b,d*f*g+f*c*a,d*f*a-f*g*c,d*b*a+g*c*b):e==="YXY"?n(c*b*a-d*g*b,d*f*g+f*c*a,d*b*a+g*c*b,f*g*c-d*f*a):e==="YZY"?n(c*b*a-d*g*b,d*f*a-f*g*c,d*b*a+g*c*b,d*f*g+f*c*a):e==="XYX"?n(c*b*a-d*g*b,d*b*a+g*c*b,d*f*g+f*c*a,d*f*a-f*g*c):e==="XZX"?n(c*b*a-d*g*b,d*b*a+g*
c*b,f*g*c-d*f*a,d*f*g+f*c*a):null};m.fromMatrix=function(a){let b,c,e,d,f,g,h,l;a.length===9?(b=a[0],c=a[1],e=a[2],d=a[3],f=a[4],g=a[5],h=a[6],l=a[7],a=a[8]):(b=a[0][0],c=a[0][1],e=a[0][2],d=a[1][0],f=a[1][1],g=a[1][2],h=a[2][0],l=a[2][1],a=a[2][2]);const p=b+f+a;return p>0?u(p+1,l-g,e-h,d-c):b>f&&b>a?u(l-g,1+b-f-a,c+d,e+h):f>a?u(e-h,c+d,1+f-b-a,g+l):u(d-c,e+h,g+l,1+a-b-f)};typeof define==="function"&&define.amd?define([],function(){return m}):typeof exports==="object"?(Object.defineProperty(m,"__esModule",
{value:!0}),m["default"]=m,m.Quaternion=m,module.exports=m):C.Quaternion=m})(this);