-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
HomographyLightweight.min.js
1 lines (1 loc) · 21.1 KB
/
HomographyLightweight.min.js
1
!function(t,i){"object"==typeof exports&&"object"==typeof module?module.exports=i():"function"==typeof define&&define.amd?define([],i):"object"==typeof exports?exports.homography=i():t.homography=i()}(self,(function(){return(()=>{"use strict";var t={d:(i,e)=>{for(var s in e)t.o(e,s)&&!t.o(i,s)&&Object.defineProperty(i,s,{enumerable:!0,get:e[s]})},o:(t,i)=>Object.prototype.hasOwnProperty.call(t,i),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},i={};t.r(i),t.d(i,{Homography:()=>e});class e{constructor(t="auto",i=null,e=null){null!==i&&(i=Math.round(i)),null!==e&&(e=Math.round(e)),this._width=i,this._height=e,this._objectiveWidth=null,this._objectiveHeight=null,this._srcPoints=null,this._dstPoints=null,this.firstTransformSelected=t.toLowerCase(),this.transform=t.toLowerCase(),this._hiddenCanvas=null,this._hiddenCanvas=document.createElement("canvas"),this._hiddenCanvas.style.display="hidden",this._hiddenCanvas.width=i,this._hiddenCanvas.height=e,this._hiddenCanvasContext=this._hiddenCanvas.getContext("2d"),this._HTMLImage=null,this._image=null,this._maxSrcX=null,this._maxSrcY=null,this._minSrcX=null,this._minSrcY=null,this._srcPointsAreNormalized=!0,this._dstPointsAreNormalized=!0,this._trianglesCorrespondencesMatrix=null,this._triangles=null,this._transformMatrix=null,this._piecewiseMatrices=null,this._auxSrcTriangle=new Float32Array(6),this._auxDstTriangle=new Float32Array(6),this._initialTriangles=null}setReferencePoints(t,i,e=null,s=null,h=null,n=null,r=null){if(void 0===t||void 0===i)throw"Source and Destiny points must be defined when calling setReferencePoints().";this._dstPoints=null,this.setSourcePoints(t,e,s,h,n),this.setDestinyPoints(i,r)}setSourcePoints(t,i=null,e=null,s=null,h=null){ArrayBuffer.isView(t)||(t=new Float32Array(t.flat())),this._srcPoints=t,this._srcPointsAreNormalized=null===h?!d(this._srcPoints,8):h,this._transformMatrix=null,this.transform=function(t,i){switch(t){case"auto":if(6===i.length)t="affine";else if(8===i.length)t="projective";else{if(!(i.length>8))throw`Transforms must contain at least 3 points but only ${i.length/2} were given`;t="piecewiseaffine"}break;case"piecewiseaffine":if(i.length<6)throw`A piecewise (or affine) transform needs to determine least three reference points but only ${i.length/2} were given`;break;case"affine":if(6!==i.length)throw`An affine transform needs to determine exactly three reference points but ${i.length/2} were given`;break;case"projective":if(8!==i.length)throw`A projective transform needs to determine exactly four reference points but ${i.length/2} were given`;break;default:throw`Transform "${t}" is unknown`}if("piecewiseaffine"===t)throw"You are executing a lightweight version with no dependencies that can not perform Piecewise Affine transforms, if you need to perform themplease import the full module from https://cdn.jsdelivr.net/gh/Eric-Canas/[email protected]/Homography.js";return t}(this.firstTransformSelected,this._srcPoints),this._objectiveWidth=null,this._objectiveHeight=null,null!==i?this.setImage(i,e,s):null===e&&null===s||this._setSrcWidthHeight(e,s),null!==this._width&&null!==this._height&&this._srcPointsAreNormalized&&(f(this._srcPoints,this._width,this._height),this._srcPointsAreNormalized=!1),null!==this._dstPoints&&"piecewiseaffine"!==this.transform&&(this._transformMatrix=r(this.transform,this._srcPoints,this._dstPoints)),"piecewiseaffine"===this.transform&&null===this._trianglesCorrespondencesMatrix&&(this._triangles=this._initialTriangles,this._piecewiseMatrices=null,!this._srcPointsAreNormalized||this._width>0&&this._height>0?this._setPiecewiseAffineTransformParameters():null===this._triangles&&(this._triangles=n(this._srcPoints)))}setImage(t,i=null,e=null){null!==this._width&&null!==this._height||ArrayBuffer.isView(t.data)||this._setSrcWidthHeight(null===i?t.width:i,null===e?t.height:e),ArrayBuffer.isView(t.data)?(this._image=t.data,this._setSrcWidthHeight(t.width,t.height)):(this._HTMLImage=t,this._image=this._getImageAsRGBAArray(t)),null!==this._srcPoints&&"piecewiseaffine"===this.transform&&this._setPiecewiseAffineTransformParameters(),null!==this._dstPoints&&(this._objectiveWidth<=0||this._objectiveHeight<=0)&&this._induceBestObjectiveWidthAndHeight()}setDestinyPoints(t,i=null){if(ArrayBuffer.isView(t)||(t=new Float32Array(t.flat())),null!==this._srcPoints&&t.length!==this._srcPoints.length)throw`It must be the same amount of destiny points (${t.length/2}) than source points (${this._srcPoints.length/2})`;this._dstPoints=t,this._dstPointsAreNormalized=null===i?!d(this._dstPoints,8):i,"piecewiseaffine"!==this.transform?(this._dstPointsAreNormalized&&this._width>0&&this._height>0&&"projective"===this.transform&&(f(this._dstPoints,this._width,this._height),this._dstPointsAreNormalized=!1),this._putSrcAndDstPointsInSameRange(),this._transformMatrix=r(this.transform,this._srcPoints,this._dstPoints)):this._piecewiseMatrices=null,(null!==this._image||"piecewiseaffine"===this.transform&&this._width>0&&this._height>0)&&this._induceBestObjectiveWidthAndHeight(),"piecewiseaffine"===this.transform&&this._width>0&&this._height>0&&(this._dstPointsAreNormalized&&(f(this._dstPoints,this._width,this._height),this._dstPointsAreNormalized=!1),this._setPiecewiseAffineTransformParameters())}warp(t=null,i=!1,e=!1){if(null!==t)this.setImage(t);else if(null===this._image)throw"warp() must receive an image if it was not setted before through `setImage(img)` or `setSourcePoints(points, img)`";let s;switch(this.transform){case"piecewiseaffine":s=e||this._objectiveWidth>this._width||this._objectiveHeight>this._height||1.2*this._objectiveWidth<this._width||1.2*this._objectiveHeight<this._height?this._inversePiecewiseAffineWarp(this._image):this._piecewiseAffineWarp(this._image);break;case"affine":s=e||this._objectiveWidth!==this._width||this._objectiveHeight!==this._height?this._inverseGeometricWarp(this._image):this._geometricWarp(this._image);break;case"projective":s=this._inverseGeometricWarp(this._image)}return s=this._objectiveWidth*this._objectiveHeight>=1&&!isNaN(this._objectiveWidth*this._objectiveHeight)?new ImageData(s,this._objectiveWidth,this._objectiveHeight):new ImageData(new Uint8ClampedArray(4),1,1),i?this.HTMLImageElementFromImageData(s):s}HTMLImageElementFromImageData(t,i=!0){let e=null;this._objectiveWidth!==this._hiddenCanvas.width&&(e=this._hiddenCanvas.width,this._hiddenCanvas.width=this._objectiveWidth);let s=null;this._objectiveHeight!==this._hiddenCanvas.height&&(s=this._hiddenCanvas.height,this._hiddenCanvas.height=this._objectiveHeight),this._hiddenCanvasContext.clearRect(0,0,this._objectiveWidth,this._objectiveHeight),this._hiddenCanvasContext.putImageData(t,0,0);let h=document.createElement("img");return h.src=this._hiddenCanvas.toDataURL(),h.width=this._objectiveWidth,h.height=this._objectiveHeight,null!==e&&(this._hiddenCanvas.width=e),null!==s&&(this._hiddenCanvas.height=s),i?new Promise(((t,i)=>{h.onload=()=>{t(h)},h.onerror=i})):h}setTriangles(t){this._triangles=t,(!this._srcPointsAreNormalized||this._width>0&&this._height>0)&&null!==this._srcPoints&&this._setPiecewiseAffineTransformParameters()}getTransformationMatrixAsCSS(t=null,i=null,e=null,s=null){if(null===e&&null===s||this._setSrcWidthHeight(e,s),null!==t&&this.setSourcePoints(t,null,e,s),null!==i&&this.setDestinyPoints(i),null===this._srcPoints)throw"Impossible to calculate a transform when srcPoints are not set";if(null===this._dstPoints)throw"Impossible to calculate a transform when dstPoints are not set";if(null===this._transformMatrix)throw"Transform matrix can not be calculated";let h;switch(this.transform){case"affine":h="matrix(";for(let t=0;t<this._transformMatrix.length;t++)h+=`${this._transformMatrix[t].toFixed(5)}`,t<this._transformMatrix.length-1?h+=", ":h+=")";break;case"projective":h="matrix3d(";let t=0;for(let i=0;i<4;i++)for(let e=0;e<4;e++)h+=2===i&&2===e||3===i&&3===e?"1":2===i||2===e?"0":`${this._transformMatrix[3*t++%8].toFixed(5)}`,h+=4*i+e<15?", ":")";break;default:throw`Only "affine" or "projective" transforms can be applied on the CSS transform property, but ${this.transform} selected`}return h}transformHTMLElement(t,i=null,e=null){const s=t.getBoundingClientRect();t.style.transform=this.getTransformationMatrixAsCSS(i,e,s.width,s.height)}_setSrcWidthHeight(t,i){const e=this._width,s=this._height;this._width=t,this._height=i,e===t&&s===i||(this._width=Math.round(t),this._height=Math.round(i),this._trianglesCorrespondencesMatrix=null,this._hiddenCanvas.width<this._width&&(this._hiddenCanvas.width=this._width),this._hiddenCanvas.height<this._height&&(this._hiddenCanvas.height=this._height),"projective"===this.transform&&(null!==this._srcPoints&&this._srcPointsAreNormalized&&(f(this._srcPoints,this._width,this._height),this._srcPointsAreNormalized=!1),null!==this._dstPoints&&this._dstPointsAreNormalized&&(f(this._dstPoints,this._width,this._height),this._dstPointsAreNormalized=!1),null!==this._dstPoints&&null!==this._srcPoints&&(this._transformMatrix=r(this.transform,this._srcPoints,this._dstPoints),this._induceBestObjectiveWidthAndHeight())),null!==this._image&&null!==this._HTMLImage&&(this._image=this._getImageAsRGBAArray(this._HTMLImage)),null!==this._srcPoints&&"piecewiseaffine"===this.transform&&this._setPiecewiseAffineTransformParameters())}_induceBestObjectiveWidthAndHeight(){if("affine"===this.transform||"projective"===this.transform)null===this._transformMatrix&&(this._srcPointsAreNormalized!==this._dstPointsAreNormalized&&this._putSrcAndDstPointsInSameRange(),this._transformMatrix=r(this.transform,this._srcPoints,this._dstPoints)),[this._xOutputOffset,this._yOutputOffset,this._objectiveWidth,this._objectiveHeight]=function(t,i,e){let s,h,n,r;if(6===t.length)s=l(t,0,0),h=l(t,0,e),n=l(t,i,0),r=l(t,i,e);else{if(8!==t.length)throw`Transform matrix have an incorrect shape --\x3e ${t.length}`;s=_(t,0,0),h=_(t,0,e),n=_(t,i,0),r=_(t,i,e)}const a=Math.min(s[0],h[0],n[0],r[0]),o=Math.min(s[1],n[1],h[1],r[1]),c=Math.max(n[0],r[0],s[0],h[0])-a,d=Math.max(h[1],r[1],s[1],n[1])-o;return[Math.round(a),Math.round(o),Math.round(c),Math.round(d)]}(this._transformMatrix,this._width,this._height);else if(this._dstPointsAreNormalized){if(!(this._width>0&&this._height>0))throw"Trying to calculate a the output width and height of a Piecewise Affine transform but source width and height are not set";{const[t,i,e,s]=u(this._dstPoints,!1);this._xOutputOffset=Math.round(t),this._yOutputOffset=Math.round(i),this._objectiveWidth=Math.round((e-t)*this._width),this._objectiveHeight=Math.round((s-i)*this._height)}}else[this._xOutputOffset,this._yOutputOffset,this._objectiveWidth,this._objectiveHeight]=u(this._dstPoints),this._objectiveWidth=this._objectiveWidth-this._xOutputOffset,this._objectiveHeight=this._objectiveHeight-this._yOutputOffset;this._hiddenCanvas.width<this._objectiveWidth&&(this._hiddenCanvas.width=this._objectiveWidth),this._hiddenCanvas.height<this._objectiveHeight&&(this._hiddenCanvas.height=this._objectiveHeight)}_setPiecewiseAffineTransformParameters(){if(null===this._srcPoints)throw"Trying to set the Piecewise Affine Transform parameters before setting the Source Points.";if(null===this._triangles&&(this._triangles=n(this._srcPoints)),this._srcPointsAreNormalized){if(!(this._width>0&&this._height>0))throw"Trying to set the Piecewise Affine Transform parameters without knowing the source points ranges";f(this._srcPoints,this._width,this._height),this._srcPointsAreNormalized=!1}this._srcPointsAreNormalized||null!==this._triangles&&null!==this._trianglesCorrespondencesMatrix||([this._minSrcX,this._minSrcY,this._maxSrcX,this._maxSrcY]=u(this._srcPoints),this._trianglesCorrespondencesMatrix=this._buildTrianglesCorrespondencesMatrix()),null!==this._dstPoints&&null===this._piecewiseMatrices&&null!==this._triangles&&(this._dstPointsAreNormalized&&(f(this._dstPoints,this._width,this._height),this._dstPointsAreNormalized=!1),this._piecewiseMatrices=this._calculatePiecewiseAffineTransformMatrices())}_calculatePiecewiseAffineTransformMatrices(){this._srcPointsAreNormalized!==this._dstPointsAreNormalized&&this._putSrcAndDstPointsInSameRange();let t=[];for(let i=0;i<this._triangles.length;i+=3)this._auxSrcTriangle[0]=this._srcPoints[this._triangles[i]<<1],this._auxSrcTriangle[1]=this._srcPoints[1+(this._triangles[i]<<1)],this._auxSrcTriangle[2]=this._srcPoints[this._triangles[i+1]<<1],this._auxSrcTriangle[3]=this._srcPoints[1+(this._triangles[i+1]<<1)],this._auxSrcTriangle[4]=this._srcPoints[this._triangles[i+2]<<1],this._auxSrcTriangle[5]=this._srcPoints[1+(this._triangles[i+2]<<1)],this._auxDstTriangle[0]=this._dstPoints[this._triangles[i]<<1],this._auxDstTriangle[1]=this._dstPoints[1+(this._triangles[i]<<1)],this._auxDstTriangle[2]=this._dstPoints[this._triangles[i+1]<<1],this._auxDstTriangle[3]=this._dstPoints[1+(this._triangles[i+1]<<1)],this._auxDstTriangle[4]=this._dstPoints[this._triangles[i+2]<<1],this._auxDstTriangle[5]=this._dstPoints[1+(this._triangles[i+2]<<1)],t.push(a(this._auxSrcTriangle,this._auxDstTriangle));return t}_buildTrianglesCorrespondencesMatrix(){const t=(this._maxSrcX-this._minSrcX)*(this._maxSrcY-this._minSrcY);null!==this._trianglesCorrespondencesMatrix&&this._trianglesCorrespondencesMatrix.length===t||(this._trianglesCorrespondencesMatrix=new Int16Array(t)),this._trianglesCorrespondencesMatrix.fill(-1);for(let t=0;t<this._triangles.length;t+=3)this._auxSrcTriangle[0]=this._srcPoints[this._triangles[t]<<1],this._auxSrcTriangle[1]=this._srcPoints[1+(this._triangles[t]<<1)],this._auxSrcTriangle[2]=this._srcPoints[this._triangles[t+1]<<1],this._auxSrcTriangle[3]=this._srcPoints[1+(this._triangles[t+1]<<1)],this._auxSrcTriangle[4]=this._srcPoints[this._triangles[t+2]<<1],this._auxSrcTriangle[5]=this._srcPoints[1+(this._triangles[t+2]<<1)],s(this._auxSrcTriangle,t/3,this._maxSrcX-this._minSrcX,this._minSrcY,this._trianglesCorrespondencesMatrix);return this._trianglesCorrespondencesMatrix}_buildInverseTrianglesCorrespondencesMatrix(){const t=this._objectiveWidth*this._objectiveHeight;null!==this._trianglesCorrespondencesMatrix&&this._trianglesCorrespondencesMatrix.length===t||(this._trianglesCorrespondencesMatrix=new Int16Array(t)),this._trianglesCorrespondencesMatrix.fill(-1);for(let t=0;t<this._triangles.length;t+=3)this._auxDstTriangle[0]=this._dstPoints[this._triangles[t]<<1],this._auxDstTriangle[1]=this._dstPoints[1+(this._triangles[t]<<1)],this._auxDstTriangle[2]=this._dstPoints[this._triangles[t+1]<<1],this._auxDstTriangle[3]=this._dstPoints[1+(this._triangles[t+1]<<1)],this._auxDstTriangle[4]=this._dstPoints[this._triangles[t+2]<<1],this._auxDstTriangle[5]=this._dstPoints[1+(this._triangles[t+2]<<1)],s(this._auxDstTriangle,t/3,this._objectiveWidth,this._yOutputOffset,this._trianglesCorrespondencesMatrix);return this._trianglesCorrespondencesMatrix}_putSrcAndDstPointsInSameRange(){if(this._dstPointsAreNormalized!==this._srcPointsAreNormalized)if(this._dstPointsAreNormalized&&this._width>0&&this._height>0)!function(t,i,e){for(let s=0;s<t.length;s++)t[s]=s%2==0?t[s]/i:t[s]/e}(this._srcPoints,this._width,this._height),this._srcPointsAreNormalized=!0;else{if(!(this._srcPointsAreNormalized&&this._width>0&&this._height>0))throw"Impossible to put source and destiny points in the same range. Possible solutions: \n1. Give a source width/height when calling setSrcPoints.\n2. Set the input image before.\n3. Give Source and Destiny points in the same range (both normalized or both in image dimensions)";f(this._srcPoints,this._width,this._height),this._srcPointsAreNormalized=!1}}_geometricWarp(t){const i=this._width<<2,e=this._objectiveWidth<<2;let s=c(this.transform),h=new Uint8ClampedArray(e*this._objectiveHeight);for(let n=0;n<this._height;n++)for(let r=0;r<this._width;r++){const a=n*i+(r<<2);let[o,l]=s(this._transformMatrix,r,n);o=Math.round(o-this._xOutputOffset),l=Math.round(l-this._yOutputOffset);const _=l*e+(o<<2);h[_]=t[a],h[_+1]=t[a+1],h[_+2]=t[a+2],h[_+3]=t[a+3]}return h}_piecewiseAffineWarp(t){const i=this._width<<2,e=this._objectiveWidth<<2,s=this._maxSrcX-this._minSrcX;let h=new Uint8ClampedArray(e*this._objectiveHeight);for(let n=this._minSrcY;n<this._maxSrcY;n++)for(let r=this._minSrcX;r<this._maxSrcX;r++){const a=this._trianglesCorrespondencesMatrix[(n-this._minSrcY)*s+(r-this._minSrcX)];if(a>-1){const s=n*i+(r<<2);let[o,_]=l(this._piecewiseMatrices[a],r,n);o=Math.round(o-this._xOutputOffset),_=Math.round(_-this._yOutputOffset);const c=_*e+(o<<2);h[c]=t[s],h[c+1]=t[s+1],h[c+2]=t[s+2],h[c+3]=t[s+3]}}return h}_inverseGeometricWarp(t){const i=this._width<<2,e=this._objectiveWidth<<2;let s=new Uint8ClampedArray(e*this._objectiveHeight);this._putSrcAndDstPointsInSameRange();const h=r(this.transform,this._dstPoints,this._srcPoints);let n=c(this.transform);for(let r=this._yOutputOffset;r<this._objectiveHeight+this._yOutputOffset;r++)for(let a=this._xOutputOffset;a<this._objectiveWidth+this._xOutputOffset;a++){let[o,l]=n(h,a,r);if(o>=0&&o<this._width&&l>=0&&l<this._height){const h=(r-this._yOutputOffset)*e+(a-this._xOutputOffset<<2),n=Math.round(l)*i+(Math.round(o)<<2);s[h]=t[n],s[h+1]=t[n+1],s[h+2]=t[n+2],s[h+3]=t[n+3]}}return s}_inversePiecewiseAffineWarp(t){const i=this._width<<2,e=this._objectiveWidth<<2,s=this._buildInverseTrianglesCorrespondencesMatrix(),h=this._objectiveWidth;let n=[];for(let t=0;t<this._piecewiseMatrices.length;t++)n.push(o(this._piecewiseMatrices[t]));let r=new Uint8ClampedArray(e*this._objectiveHeight);for(let a=this._yOutputOffset;a<this._objectiveHeight+this._yOutputOffset;a++)for(let o=this._xOutputOffset;o<this._objectiveWidth+this._xOutputOffset;o++){const _=s[(a-this._yOutputOffset)*h+(o-this._xOutputOffset)];if(_>=0){let[s,h]=l(n[_],o,a);if(s>=this._minSrcX&&s<this._width+this._minSrcX&&h>=this._minSrcY&&h<this._height+this._minSrcY){s=Math.round(s),h=Math.round(h);const n=h*i+(s<<2),l=(a-this._yOutputOffset)*e+(o-this._xOutputOffset<<2);r[l]=t[n],r[l+1]=t[n+1],r[l+2]=t[n+2],r[l+3]=t[n+3]}}}return r}_getImageAsRGBAArray(t){return this._hiddenCanvasContext.clearRect(0,0,this._width,this._height),this._hiddenCanvasContext.drawImage(t,0,0,this._width,this._height),this._hiddenCanvasContext.getImageData(0,0,this._width,this._height).data}}function s(t,i,e,s,n){const r=~~Math.min(t[1],t[3],t[5]),a=Math.ceil(Math.max(t[1],t[3],t[5])),o=function(t){let[i,e,s,h,n,r]=t;return[{m:s!==i?(h-e)/(s-i):1/0,b:s!==i?e-i*((h-e)/(s-i)):i,minY:Math.min(h,e),maxY:Math.max(h,e)},{m:n!==i?(r-e)/(n-i):1/0,b:n!==i?e-i*((r-e)/(n-i)):i,minY:Math.min(r,e),maxY:Math.max(r,e)},{m:n!==s?(r-h)/(n-s):1/0,b:n!==s?h-s*((r-h)/(n-s)):s,minY:Math.min(r,h),maxY:Math.max(r,h)}]}(t);let l,_;for(let t=r;t<a;t++)[l,_]=h(o,t),n.fill(i,(t-s)*e+Math.round(l),(t-s)*e+Math.round(_))}function h(t,i){let e,s=1/0,h=-1/0;for(let n=0;n<t.length;n++)if(i>=t[n].minY&&i<=t[n].maxY){if(t[n].m===1/0)e=t[n].b;else{if(0===t[n].m)continue;e=(i-t[n].b)/t[n].m}e<s&&(s=e),e>h&&(h=e)}return[s,h]}function n(t){return new Delaunator(t).triangles}function r(t,i,e){let s=null;switch(t){case"affine":s=a(i,e);break;case"projective":o=e,h=[[(r=i)[0],r[1],1,0,0,0,-o[0]*r[0],-o[0]*r[1]],[0,0,0,r[0],r[1],1,-o[1]*r[0],-o[1]*r[1]],[r[2],r[3],1,0,0,0,-o[2]*r[2],-o[2]*r[3]],[0,0,0,r[2],r[3],1,-o[3]*r[2],-o[3]*r[3]],[r[4],r[5],1,0,0,0,-o[4]*r[4],-o[4]*r[5]],[0,0,0,r[4],r[5],1,-o[5]*r[4],-o[5]*r[5]],[r[6],r[7],1,0,0,0,-o[6]*r[6],-o[6]*r[7]],[0,0,0,r[6],r[7],1,-o[7]*r[6],-o[7]*r[7]]],n=o,s=function(t,i){var e,s,h,n,r,a=t.LU,o=a.length,l=g(i),_=t.P;for(e=o-1;-1!==e;--e)l[e]=i[e];for(e=0;e<o;++e)for(h=_[e],_[e]!==e&&(r=l[e],l[e]=l[h],l[h]=r),n=a[e],s=0;s<e;++s)l[e]-=l[s]*n[s];for(e=o-1;e>=0;--e){for(n=a[e],s=e+1;s<o;++s)l[e]-=l[s]*n[s];l[e]/=n[e]}return l}(function(t,i){i=i||!1;var e,s,h,n,r,a,o,l,_,c=Math.abs,d=t.length,u=d-1,f=new Array(d);for(i||(t=g(t)),h=0;h<d;++h){for(o=h,_=c((a=t[h])[h]),s=h+1;s<d;++s)_<(n=c(t[s][h]))&&(_=n,o=s);for(f[h]=o,o!=h&&(t[h]=t[o],t[o]=a,a=t[h]),r=a[h],e=h+1;e<d;++e)t[e][h]/=r;for(e=h+1;e<d;++e){for(l=t[e],s=h+1;s<u;++s)l[s]-=l[h]*a[s],l[++s]-=l[h]*a[s];s===u&&(l[s]-=l[h]*a[s])}}return{LU:t,P:f}}(h,!0),n);break;default:throw`${t} transform does not exist`}var h,n,r,o;return s}function a(t,i){const e=t[4],s=t[5],h=t[0]-e,n=t[1]-s,r=t[2]-e,a=t[3]-s,o=i[4],l=i[5],_=i[0]-o,c=i[1]-l,d=i[2]-o,u=i[3]-l,f=h*a-n*r,g=a/f,m=n/-f,w=r/-f,p=h/f,P=(a*e-r*s)/-f,v=(n*e-h*s)/f;return new Float32Array([_*g+d*m,c*g+u*m,_*w+d*p,c*w+u*p,_*P+d*v+o,c*P+u*v+l])}function o(t){const i=t[0],e=t[1],s=t[2],h=t[3],n=t[4],r=t[5];let a=new Float32Array(6);const o=i*h-e*s;return a[0]=h/o,a[1]=e/-o,a[2]=s/-o,a[3]=i/o,a[4]=(h*n-s*r)/-o,a[5]=(e*n-i*r)/o,a}function l(t,i,e){return[t[0]*i+t[2]*e+t[4],t[1]*i+t[3]*e+t[5]]}function _(t,i,e){return[(t[0]*i+t[1]*e+t[2])/(t[6]*i+t[7]*e+1),(t[3]*i+t[4]*e+t[5])/(t[6]*i+t[7]*e+1)]}function c(t){switch(t){case"affine":return l;case"projective":return _;default:throw`${t} transform does not exist`}}function d(t,i){for(let e=0;e<t.length;e++)if(t[e]>i)return!0;return!1}function u(t,i=!0){let e=-1/0,s=-1/0,h=1/0,n=1/0;for(let i=0;i<t.length;i++){const r=t[i];i%2==0?(r>e&&(e=r),r<h&&(h=r)):(r>s&&(s=r),r<n&&(n=r))}return i?[Math.round(h),Math.round(n),Math.round(e),Math.round(s)]:[h,n,e,s]}function f(t,i,e){for(let s=0;s<t.length;s++)t[s]=s%2==0?t[s]*i:t[s]*e}function g(t,i,e){void 0===i&&(i=0),void 0===e&&(e=1);var s,h=Array(t.length);if(i===e-1){for(s in t)t.hasOwnProperty(s)&&(h[s]=t[s]);return h}for(s in t)t.hasOwnProperty(s)&&(h[s]=g(t[s],i+1,e));return h}return i})()}));