UNPKG

quaternion

Version:

A rotation library using quaternions

27 lines (25 loc) 9.63 kB
/* Quaternion.js v2.0.2 12/1/2024 https://raw.org/book/algebra/quaternions/ Copyright (c) 2024, Robert Eisele (https://raw.org/) Licensed under the MIT license. */ 'use strict';(function(C){function m(a,b,c,e){const d=Object.create(n.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(n.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.abs(a),e=Math.abs(b);if(0===a)return Math.log(e);if(0===b)return Math.log(c);if(3E3>c&&3E3>e)return.5*Math.log(a*a+b*b);a/=2;b/=2;return.5*Math.log(a*a+b*b)+Math.LN2}function t(a,b,c,e,d){if(void 0!==d)a.w=b,a.x=c,a.y=e,a.z=d;else{if("object"=== typeof b&&void 0===e){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(4===b.length){a.w=b[0];a.x=b[1];a.y=b[2];a.z=b[3];return}if(3===b.length){a.w=0;a.x=b[0];a.y=b[1];a.z=b[2];return}throw Error("Invalid object");}if("string"===typeof b&&void 0===e){b=b.match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g);var f=1;c=0;e={i:"x",j:"y",k:"z"};if(null===b)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&&"\t"!==g&&"\n"!==g)if("+"===g)f++;else if("-"===g)c++;else{if(0===f+c)throw Error("Parse error"+g);f=e[g];if(void 0!==f)" "===h||isNaN(h)?g="1":(g=h,d++);else{if(isNaN(g))throw Error("Parser error");f=e[h];void 0!==f&&d++}a[f||"w"]+=parseFloat((c%2?"-":"")+g);f=c=0}}if(0<f+c)throw Error("Parser error");}else void 0===b&&a!==k?(a.w=1,a.x=a.y=a.z=0):(a.w=b||0,c&&3===c.length?(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(0!==a){""!==c?e+=0>a?" - ":" + ":0>a&&(e+="-");a=Math.abs(a);if(1!==a||""===b)e+=a;e+=b}return e}function n(a,b,c,e){if(this instanceof n)t(this,a,b,c,e);else{const d=Object.create(n.prototype);t(d,a,b,c,e);return d}}const k=Object.create(n.prototype);n.prototype={w:1,x:0,y:0,z:0,add:function(a,b,c,e){t(k,a,b,c,e);return m(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 m(this.w-k.w,this.x-k.x,this.y-k.y,this.z-k.z)},neg:function(){return m(-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(1E-16>d)return n.ZERO;d=1/d;return m(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 m(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 m(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(0===d)return n.ZERO;d=1/d;return m(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(0===l)return n.ZERO;l=1/l;return m((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 m(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),f=d*Math.sin(e)/e;return 0===e?m(d,0,0,0):m(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(0===c&&0===e)return m(z(a,b),Math.atan2(b,a),0,0);var d=Math.sqrt(b*b+c*c+e*e);d=Math.atan2(d,a)/d;return m(.5*Math.log(b*b+c*c+e*e+a*a),b*d,c*d,e* d)},pow:function(a,b,c,e){t(k,a,b,c,e);if(0===k.y&&0===k.z){if(1===k.w&&0===k.x)return this;if(0===k.w&&0===k.x)return n.ONE;if(0===this.y&&0===this.z){a=this.w;b=this.x;if(0===a&&0===b)return n.ZERO;c=Math.atan2(b,a);e=z(a,b);if(0===k.x){if(0===b&&0<=a)return m(Math.pow(a,k.w),0,0,0);if(0===a)switch(k.w%4){case 0:return m(Math.pow(b,k.w),0,0,0);case 1:return m(0,Math.pow(b,k.w),0,0);case 2:return m(-Math.pow(b,k.w),0,0,0);case 3:return m(0,-Math.pow(b,k.w),0,0)}}a=Math.exp(k.w*e-k.x*c);b=k.x*e+k.w* c;return m(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 1E-16>Math.abs(k.w-this.w)&&1E-16>Math.abs(k.x-this.x)&&1E-16>Math.abs(k.y-this.y)&&1E-16>Math.abs(k.z-this.z)},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=this.w;let b=2*Math.acos(a);a=1-a*a;1E-16>a?(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=this.w;var b=1-a*a;if(1E-16>b)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 1<=v?Math.PI/2:-1>=v?-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 r=d*d;d*=f;f*=f;return void 0===a||"ZXY"===a?[-Math.atan2(2*(p-c),1-2*(l+f)),b(2*(d+g)),-Math.atan2(2*(e-h),1- 2*(l+r))]:"XYZ"===a||"RPY"===a?[-Math.atan2(2*(d-g),1-2*(l+r)),b(2*(e+h)),-Math.atan2(2*(p-c),1-2*(r+f))]:"YXZ"===a?[Math.atan2(2*(e+h),1-2*(l+r)),-b(2*(d-g)),Math.atan2(2*(p+c),1-2*(l+f))]:"ZYX"===a||"YPR"===a?[Math.atan2(2*(p+c),1-2*(r+f)),-b(2*(e-h)),Math.atan2(2*(d+g),1-2*(l+r))]:"YZX"===a?[-Math.atan2(2*(e-h),1-2*(r+f)),b(2*(p+c)),-Math.atan2(2*(d-g),1-2*(l+f))]:"XZY"===a?[Math.atan2(2*(d+g),1-2*(l+f)),-b(2*(p-c)),Math.atan2(2*(e+h),1-2*(r+f))]:null},clone:function(){return m(this.w,this.x,this.y, this.z)},rotateVector:function(a){const b=this.w,c=this.x,e=this.y,d=this.z,f=a[0],g=a[1];a=a[2];let h=e*a-d*g,l=d*f-c*a,p=c*g-e*f;h+=h;l+=l;p+=p;return[f+b*h+e*p-d*l,g+b*l+d*h-c*p,a+b*p+c*l-e*h]},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,r=k.y,v=k.z,x=d*l+f*p+g*r+h*v;0>x&&(d=-d,f=-f,g=-g,h=-h,x=-x);if(x>=1-1E-16)return function(q){return u(d+q*(l-d),f+q*(p-f),g+q*(r-g),h+q*(v-h))};let A=Math.acos(x),B=Math.sin(A);return function(q){var w=A*q;q=Math.sin(w); w=Math.cos(w)-x*q/B;q/=B;return m(w*d+q*l,w*f+q*p,w*g+q*r,w*h+q*v)}}};n.ZERO=m(0,0,0,0);n.ONE=m(1,0,0,0);n.I=m(0,1,0,0);n.J=m(0,0,1,0);n.K=m(0,0,0,1);n.fromAxisAngle=function(a,b){const c=a[0],e=a[1];a=a[2];b*=.5;const d=Math.sin(b)/Math.sqrt(c*c+e*e+a*a);return m(Math.cos(b),c*d,e*d,a*d)};n.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);0<g&&(c/=g,e/=g,a/=g);0<h&&(d/=h,f/=h,b/=h);g=c*d+e*f+a*b;return g>=1-1E-16? n.ONE:1E-16>=1+g?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)};n.random=function(){var a=Math.random();const b=Math.random(),c=Math.random(),e=Math.sqrt(1-a);a=Math.sqrt(a);return m(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))};n.fromEulerLogical=function(a,b,c,e){return n.fromEuler(c,b,a,void 0!==e?e[2]+e[1]+e[0]:e)};n.fromEuler=function(a,b,c,e){var d=.5*a,f=.5*b,g=.5*c;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 void 0===e||"ZXY"===e?m(c*b*a-d*f*g,f*c*a-d*g*b,d*f*a+g*c*b,d*b*a+f*g*c):"XYZ"===e||"RPY"===e?m(c*b*a-d*f*g,d*b*a+f*g*c,f*c*a-d*g*b,d*f*a+g*c*b):"YXZ"===e?m(d*f*g+c*b*a,d*g*b+f*c*a,d*b*a-f*g*c,g*c*b-d*f*a):"ZYX"===e||"YPR"===e?m(d*f*g+c*b*a,g*c*b-d*f*a,d*g*b+f*c*a,d*b*a-f*g*c):"YZX"===e?m(c*b*a-d*f*g,d*f*a+g*c*b,d*b*a+f*g*c,f*c*a-d*g*b):"XZY"===e?m(d*f*g+c*b*a,d*b*a-f*g*c,g*c*b-d*f*a,d*g*b+f*c*a):"ZYZ"===e?m(c*b*a-d*g*b,f*g*c-d*f*a,d*f*g+f*c*a,d*b* a+g*c*b):"ZXZ"===e?m(c*b*a-d*g*b,d*f*g+f*c*a,d*f*a-f*g*c,d*b*a+g*c*b):"YXY"===e?m(c*b*a-d*g*b,d*f*g+f*c*a,d*b*a+g*c*b,f*g*c-d*f*a):"YZY"===e?m(c*b*a-d*g*b,d*f*a-f*g*c,d*b*a+g*c*b,d*f*g+f*c*a):"XYX"===e?m(c*b*a-d*g*b,d*b*a+g*c*b,d*f*g+f*c*a,d*f*a-f*g*c):"XZX"===e?m(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};n.fromMatrix=function(a){let b,c,e,d,f,g,h,l;9===a.length?(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 0<p?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)};"function"===typeof define&&define.amd?define([],function(){return n}):"object"===typeof exports?(Object.defineProperty(n,"__esModule",{value:!0}),n["default"]=n,n.Quaternion=n,module.exports=n):C.Quaternion=n})(this);