@fnndsc/argus 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/ChRISlogo-color-t-i99soF.svg +164 -0
- package/dist/assets/MesloLGS-NF-Bold-DbxbaV6p.ttf +0 -0
- package/dist/assets/MesloLGS-NF-Regular-DAUcZJjt.ttf +0 -0
- package/dist/assets/Settings-B_WPNkCE.js +4407 -0
- package/dist/assets/_commonjsHelpers-CE1G-McA.js +1 -0
- package/dist/assets/addVolumesToViewports-kPbPUzG1.js +1 -0
- package/dist/assets/antonio-latin-400-normal-CZjzwNAN.woff2 +0 -0
- package/dist/assets/antonio-latin-700-normal-DSH-lEDG.woff2 +0 -0
- package/dist/assets/arrive-ClURnB_N.wav +0 -0
- package/dist/assets/blosc-CrUiACa7.js +17 -0
- package/dist/assets/chakra-petch-latin-400-normal-SafcrIr2.woff2 +0 -0
- package/dist/assets/chakra-petch-latin-500-normal-BR1ody1F.woff2 +0 -0
- package/dist/assets/chakra-petch-latin-600-normal-DVQm9bgb.woff2 +0 -0
- package/dist/assets/chakra-petch-latin-700-normal-CnDBPjkL.woff2 +0 -0
- package/dist/assets/charlswasm_decode-BrO4esUm.wasm +0 -0
- package/dist/assets/chunk-INHXZS53-D3tQiqtZ.js +1 -0
- package/dist/assets/computeWorker-D8XJyv-f.js +4095 -0
- package/dist/assets/cornerstoneEngine-COmMRWtq.js +2 -0
- package/dist/assets/dcmjs.es-DfWkgqfk.js +18 -0
- package/dist/assets/decodeImageFrameWorker-BtcTb_T6.js +5 -0
- package/dist/assets/index-B1IRr1ii.js +4145 -0
- package/dist/assets/index-BEqlmVJ8.js +2456 -0
- package/dist/assets/index-BbgujRGq.css +1 -0
- package/dist/assets/index-BivV2-EJ.js +9 -0
- package/dist/assets/index-CH659Lsh.js +1 -0
- package/dist/assets/index-DRvbvdZm.js +320 -0
- package/dist/assets/index-Ddoc1eo6.js +1 -0
- package/dist/assets/index-WxcTPiRU.js +2 -0
- package/dist/assets/index-oaz5IMVa.js +1 -0
- package/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/dist/assets/jpeg-B-x1txLf.js +1 -0
- package/dist/assets/libjpegturbowasm_decode-7ZJ2wGuU.wasm +0 -0
- package/dist/assets/lossless-CyYqoyFe.js +1 -0
- package/dist/assets/lz4-B_Exjfmr.js +15 -0
- package/dist/assets/niivueEngine-B2PDgoH7.js +2 -0
- package/dist/assets/openjpegwasm_decode-B3gWTHpv.wasm +0 -0
- package/dist/assets/openjphjs-B5O5ikHp.wasm +0 -0
- package/dist/assets/press-Cr6-1MeH.wav +0 -0
- package/dist/assets/refuse-DQOeTs-N.wav +0 -0
- package/dist/assets/retreat-CxfXQVOC.wav +0 -0
- package/dist/assets/throttle-CjIII7Yf.js +1 -0
- package/dist/assets/zstd-u5eweWyS.js +15 -0
- package/dist/index.html +626 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2456 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./blosc-CrUiACa7.js","./chunk-INHXZS53-D3tQiqtZ.js","./lz4-B_Exjfmr.js","./zstd-u5eweWyS.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{g as va}from"./_commonjsHelpers-CE1G-McA.js";import{_ as Mi}from"./index-B1IRr1ii.js";var _t=1e-6,Ae=typeof Float32Array<"u"?Float32Array:Array;function qi(){var t=new Ae(9);return Ae!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function wa(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t}function He(t,e,i,r,s,n,a,o,l){var c=new Ae(9);return c[0]=t,c[1]=e,c[2]=i,c[3]=r,c[4]=s,c[5]=n,c[6]=a,c[7]=o,c[8]=l,c}function ya(t,e){var i=e[0],r=e[1],s=e[2],n=e[3],a=e[4],o=e[5],l=e[6],c=e[7],h=e[8],d=h*a-o*c,f=-h*n+o*l,u=c*n-a*l,m=i*d+r*f+s*u;return m?(m=1/m,t[0]=d*m,t[1]=(-h*r+s*c)*m,t[2]=(o*r-s*a)*m,t[3]=f*m,t[4]=(h*i-s*l)*m,t[5]=(-o*i+s*n)*m,t[6]=u*m,t[7]=(-c*i+r*l)*m,t[8]=(a*i-r*n)*m,t):null}function Hs(t,e,i){var r=e[0],s=e[1],n=e[2],a=e[3],o=e[4],l=e[5],c=e[6],h=e[7],d=e[8],f=i[0],u=i[1],m=i[2],p=i[3],g=i[4],x=i[5],A=i[6],y=i[7],v=i[8];return t[0]=f*r+u*a+m*c,t[1]=f*s+u*o+m*h,t[2]=f*n+u*l+m*d,t[3]=p*r+g*a+x*c,t[4]=p*s+g*o+x*h,t[5]=p*n+g*l+x*d,t[6]=A*r+y*a+v*c,t[7]=A*s+y*o+v*h,t[8]=A*n+y*l+v*d,t}function J(){var t=new Ae(16);return Ae!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t}function de(t){var e=new Ae(16);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e[4]=t[4],e[5]=t[5],e[6]=t[6],e[7]=t[7],e[8]=t[8],e[9]=t[9],e[10]=t[10],e[11]=t[11],e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15],e}function ba(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function Ee(t,e,i,r,s,n,a,o,l,c,h,d,f,u,m,p){var g=new Ae(16);return g[0]=t,g[1]=e,g[2]=i,g[3]=r,g[4]=s,g[5]=n,g[6]=a,g[7]=o,g[8]=l,g[9]=c,g[10]=h,g[11]=d,g[12]=f,g[13]=u,g[14]=m,g[15]=p,g}function qs(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function Te(t,e){if(t===e){var i=e[1],r=e[2],s=e[3],n=e[6],a=e[7],o=e[11];t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=i,t[6]=e[9],t[7]=e[13],t[8]=r,t[9]=n,t[11]=e[14],t[12]=s,t[13]=a,t[14]=o}else t[0]=e[0],t[1]=e[4],t[2]=e[8],t[3]=e[12],t[4]=e[1],t[5]=e[5],t[6]=e[9],t[7]=e[13],t[8]=e[2],t[9]=e[6],t[10]=e[10],t[11]=e[14],t[12]=e[3],t[13]=e[7],t[14]=e[11],t[15]=e[15];return t}function Se(t,e){var i=e[0],r=e[1],s=e[2],n=e[3],a=e[4],o=e[5],l=e[6],c=e[7],h=e[8],d=e[9],f=e[10],u=e[11],m=e[12],p=e[13],g=e[14],x=e[15],A=i*o-r*a,y=i*l-s*a,v=i*c-n*a,b=r*l-s*o,w=r*c-n*o,C=s*c-n*l,M=h*p-d*m,T=h*g-f*m,E=h*x-u*m,I=d*g-f*p,S=d*x-u*p,U=f*x-u*g,B=A*U-y*S+v*I+b*E-w*T+C*M;return B?(B=1/B,t[0]=(o*U-l*S+c*I)*B,t[1]=(s*S-r*U-n*I)*B,t[2]=(p*C-g*w+x*b)*B,t[3]=(f*w-d*C-u*b)*B,t[4]=(l*E-a*U-c*T)*B,t[5]=(i*U-s*E+n*T)*B,t[6]=(g*v-m*C-x*y)*B,t[7]=(h*C-f*v+u*y)*B,t[8]=(a*S-o*E+c*M)*B,t[9]=(r*E-i*S-n*M)*B,t[10]=(m*w-p*v+x*A)*B,t[11]=(d*v-h*w-u*A)*B,t[12]=(o*T-a*I-l*M)*B,t[13]=(i*I-r*T+s*M)*B,t[14]=(p*y-m*b-g*A)*B,t[15]=(h*b-d*y+f*A)*B,t):null}function Ye(t,e,i){var r=e[0],s=e[1],n=e[2],a=e[3],o=e[4],l=e[5],c=e[6],h=e[7],d=e[8],f=e[9],u=e[10],m=e[11],p=e[12],g=e[13],x=e[14],A=e[15],y=i[0],v=i[1],b=i[2],w=i[3];return t[0]=y*r+v*o+b*d+w*p,t[1]=y*s+v*l+b*f+w*g,t[2]=y*n+v*c+b*u+w*x,t[3]=y*a+v*h+b*m+w*A,y=i[4],v=i[5],b=i[6],w=i[7],t[4]=y*r+v*o+b*d+w*p,t[5]=y*s+v*l+b*f+w*g,t[6]=y*n+v*c+b*u+w*x,t[7]=y*a+v*h+b*m+w*A,y=i[8],v=i[9],b=i[10],w=i[11],t[8]=y*r+v*o+b*d+w*p,t[9]=y*s+v*l+b*f+w*g,t[10]=y*n+v*c+b*u+w*x,t[11]=y*a+v*h+b*m+w*A,y=i[12],v=i[13],b=i[14],w=i[15],t[12]=y*r+v*o+b*d+w*p,t[13]=y*s+v*l+b*f+w*g,t[14]=y*n+v*c+b*u+w*x,t[15]=y*a+v*h+b*m+w*A,t}function tt(t,e,i){var r=i[0],s=i[1],n=i[2],a,o,l,c,h,d,f,u,m,p,g,x;return e===t?(t[12]=e[0]*r+e[4]*s+e[8]*n+e[12],t[13]=e[1]*r+e[5]*s+e[9]*n+e[13],t[14]=e[2]*r+e[6]*s+e[10]*n+e[14],t[15]=e[3]*r+e[7]*s+e[11]*n+e[15]):(a=e[0],o=e[1],l=e[2],c=e[3],h=e[4],d=e[5],f=e[6],u=e[7],m=e[8],p=e[9],g=e[10],x=e[11],t[0]=a,t[1]=o,t[2]=l,t[3]=c,t[4]=h,t[5]=d,t[6]=f,t[7]=u,t[8]=m,t[9]=p,t[10]=g,t[11]=x,t[12]=a*r+h*s+m*n+e[12],t[13]=o*r+d*s+p*n+e[13],t[14]=l*r+f*s+g*n+e[14],t[15]=c*r+u*s+x*n+e[15]),t}function fr(t,e,i){var r=i[0],s=i[1],n=i[2];return t[0]=e[0]*r,t[1]=e[1]*r,t[2]=e[2]*r,t[3]=e[3]*r,t[4]=e[4]*s,t[5]=e[5]*s,t[6]=e[6]*s,t[7]=e[7]*s,t[8]=e[8]*n,t[9]=e[9]*n,t[10]=e[10]*n,t[11]=e[11]*n,t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15],t}function Ut(t,e,i){var r=Math.sin(i),s=Math.cos(i),n=e[4],a=e[5],o=e[6],l=e[7],c=e[8],h=e[9],d=e[10],f=e[11];return e!==t&&(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[4]=n*s+c*r,t[5]=a*s+h*r,t[6]=o*s+d*r,t[7]=l*s+f*r,t[8]=c*s-n*r,t[9]=h*s-a*r,t[10]=d*s-o*r,t[11]=f*s-l*r,t}function Ca(t,e,i){var r=Math.sin(i),s=Math.cos(i),n=e[0],a=e[1],o=e[2],l=e[3],c=e[8],h=e[9],d=e[10],f=e[11];return e!==t&&(t[4]=e[4],t[5]=e[5],t[6]=e[6],t[7]=e[7],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=n*s-c*r,t[1]=a*s-h*r,t[2]=o*s-d*r,t[3]=l*s-f*r,t[8]=n*r+c*s,t[9]=a*r+h*s,t[10]=o*r+d*s,t[11]=l*r+f*s,t}function Rt(t,e,i){var r=Math.sin(i),s=Math.cos(i),n=e[0],a=e[1],o=e[2],l=e[3],c=e[4],h=e[5],d=e[6],f=e[7];return e!==t&&(t[8]=e[8],t[9]=e[9],t[10]=e[10],t[11]=e[11],t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]),t[0]=n*s+c*r,t[1]=a*s+h*r,t[2]=o*s+d*r,t[3]=l*s+f*r,t[4]=c*s-n*r,t[5]=h*s-a*r,t[6]=d*s-o*r,t[7]=f*s-l*r,t}function Ma(t,e,i){var r=i[0],s=i[1],n=i[2],a=Math.sqrt(r*r+s*s+n*n),o,l,c;return a<_t?null:(a=1/a,r*=a,s*=a,n*=a,o=Math.sin(e),l=Math.cos(e),c=1-l,t[0]=r*r*c+l,t[1]=s*r*c+n*o,t[2]=n*r*c-s*o,t[3]=0,t[4]=r*s*c-n*o,t[5]=s*s*c+l,t[6]=n*s*c+r*o,t[7]=0,t[8]=r*n*c+s*o,t[9]=s*n*c-r*o,t[10]=n*n*c+l,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)}function Da(t,e,i,r,s,n,a){var o=1/(e-i),l=1/(r-s),c=1/(n-a);return t[0]=-2*o,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*l,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(e+i)*o,t[13]=(s+r)*l,t[14]=(a+n)*c,t[15]=1,t}var hi=Da;function Ta(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i,t[3]=e[3]*i,t[4]=e[4]*i,t[5]=e[5]*i,t[6]=e[6]*i,t[7]=e[7]*i,t[8]=e[8]*i,t[9]=e[9]*i,t[10]=e[10]*i,t[11]=e[11]*i,t[12]=e[12]*i,t[13]=e[13]*i,t[14]=e[14]*i,t[15]=e[15]*i,t}var Qs=Ye;function se(){var t=new Ae(3);return Ae!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function Ve(t){var e=new Ae(3);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function Qe(t){var e=t[0],i=t[1],r=t[2];return Math.sqrt(e*e+i*i+r*r)}function k(t,e,i){var r=new Ae(3);return r[0]=t,r[1]=e,r[2]=i,r}function Hr(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t}function it(t,e,i){return t[0]=e[0]+i[0],t[1]=e[1]+i[1],t[2]=e[2]+i[2],t}function ne(t,e,i){return t[0]=e[0]-i[0],t[1]=e[1]-i[1],t[2]=e[2]-i[2],t}function ur(t,e,i){return t[0]=Math.min(e[0],i[0]),t[1]=Math.min(e[1],i[1]),t[2]=Math.min(e[2],i[2]),t}function mr(t,e,i){return t[0]=Math.max(e[0],i[0]),t[1]=Math.max(e[1],i[1]),t[2]=Math.max(e[2],i[2]),t}function Sa(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i,t}function Ea(t,e){var i=e[0]-t[0],r=e[1]-t[1],s=e[2]-t[2];return Math.sqrt(i*i+r*r+s*s)}function Ia(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t}function Ie(t,e){var i=e[0],r=e[1],s=e[2],n=i*i+r*r+s*s;return n>0&&(n=1/Math.sqrt(n)),t[0]=e[0]*n,t[1]=e[1]*n,t[2]=e[2]*n,t}function Fa(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function Jt(t,e,i){var r=e[0],s=e[1],n=e[2],a=i[0],o=i[1],l=i[2];return t[0]=s*l-n*o,t[1]=n*a-r*l,t[2]=r*o-s*a,t}function Ba(t,e,i,r){var s=e[0],n=e[1],a=e[2];return t[0]=s+r*(i[0]-s),t[1]=n+r*(i[1]-n),t[2]=a+r*(i[2]-a),t}function qr(t,e,i){var r=e[0],s=e[1],n=e[2];return t[0]=r*i[0]+s*i[3]+n*i[6],t[1]=r*i[1]+s*i[4]+n*i[7],t[2]=r*i[2]+s*i[5]+n*i[8],t}function Di(t,e){var i=t[0],r=t[1],s=t[2],n=e[0],a=e[1],o=e[2],l=Math.sqrt((i*i+r*r+s*s)*(n*n+a*a+o*o)),c=l&&Fa(t,e)/l;return Math.acos(Math.min(Math.max(c,-1),1))}function Ua(t,e){var i=t[0],r=t[1],s=t[2],n=e[0],a=e[1],o=e[2];return Math.abs(i-n)<=_t*Math.max(1,Math.abs(i),Math.abs(n))&&Math.abs(r-a)<=_t*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(s-o)<=_t*Math.max(1,Math.abs(s),Math.abs(o))}var Qr=ne,Vt=Qe;(function(){var t=se();return function(e,i,r,s,n,a){var o,l;for(i||(i=3),r||(r=0),s?l=Math.min(s*i+r,e.length):l=e.length,o=r;o<l;o+=i)t[0]=e[o],t[1]=e[o+1],t[2]=e[o+2],n(t,t,a),e[o]=t[0],e[o+1]=t[1],e[o+2]=t[2];return e}})();function Xe(){var t=new Ae(4);return Ae!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function ze(t){var e=new Ae(4);return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function ae(t,e,i,r){var s=new Ae(4);return s[0]=t,s[1]=e,s[2]=i,s[3]=r,s}function Zr(t,e,i){return t[0]=e[0]+i[0],t[1]=e[1]+i[1],t[2]=e[2]+i[2],t[3]=e[3]+i[3],t}function Ra(t,e,i){return t[0]=e[0]-i[0],t[1]=e[1]-i[1],t[2]=e[2]-i[2],t[3]=e[3]-i[3],t}function Va(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i,t[3]=e[3]*i,t}function ve(t,e,i){var r=e[0],s=e[1],n=e[2],a=e[3];return t[0]=i[0]*r+i[4]*s+i[8]*n+i[12]*a,t[1]=i[1]*r+i[5]*s+i[9]*n+i[13]*a,t[2]=i[2]*r+i[6]*s+i[10]*n+i[14]*a,t[3]=i[3]*r+i[7]*s+i[11]*n+i[15]*a,t}var Pa=Ra;(function(){var t=Xe();return function(e,i,r,s,n,a){var o,l;for(i||(i=4),r||(r=0),s?l=Math.min(s*i+r,e.length):l=e.length,o=r;o<l;o+=i)t[0]=e[o],t[1]=e[o+1],t[2]=e[o+2],t[3]=e[o+3],n(t,t,a),e[o]=t[0],e[o+1]=t[1],e[o+2]=t[2],e[o+3]=t[3];return e}})();function Na(){var t=new Ae(2);return Ae!=Float32Array&&(t[0]=0,t[1]=0),t}function La(t,e){var i=new Ae(2);return i[0]=t,i[1]=e,i}(function(){var t=Na();return function(e,i,r,s,n,a){var o,l;for(i||(i=2),r||(r=0),s?l=Math.min(s*i+r,e.length):l=e.length,o=r;o<l;o+=i)t[0]=e[o],t[1]=e[o+1],n(t,t,a),e[o]=t[0],e[o+1]=t[1];return e}})();var et=256,$t=[],Yt;for(;et--;)$t[et]=(et+256).toString(16).substring(1);function di(){var t=0,e,i="";if(!Yt||et+16>256){for(Yt=Array(t=256);t--;)Yt[t]=256*Math.random()|0;t=et=0}for(;t<16;t++)e=Yt[et+t],t==6?i+=$t[e&15|64]:t==8?i+=$t[e&63|128]:i+=$t[e],t&1&&t>1&&t<11&&(i+="-");return et++,i}var Ti,jr;function ka(){return jr||(jr=1,Ti=function(e,i){var r=e.length;if(e===i)return!0;if(r!==i.length)return!1;for(var s=0;s<r;s++)if(e[s]!==i[s])return!1;return!0}),Ti}var Oa=ka();const za=va(Oa);var ge=Uint8Array,ut=Uint16Array,Ga=Int32Array,Zs=new ge([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),js=new ge([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),Ya=new ge([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),_s=function(t,e){for(var i=new ut(31),r=0;r<31;++r)i[r]=e+=1<<t[r-1];for(var s=new Ga(i[30]),r=1;r<30;++r)for(var n=i[r];n<i[r+1];++n)s[n]=n-i[r]<<5|r;return{b:i,r:s}},Js=_s(Zs,2),$s=Js.b,Xa=Js.r;$s[28]=258,Xa[258]=28;var Wa=_s(js,0),Ka=Wa.b,Qi=new ut(32768);for(var oe=0;oe<32768;++oe){var We=(oe&43690)>>1|(oe&21845)<<1;We=(We&52428)>>2|(We&13107)<<2,We=(We&61680)>>4|(We&3855)<<4,Qi[oe]=((We&65280)>>8|(We&255)<<8)>>1}var Ft=(function(t,e,i){for(var r=t.length,s=0,n=new ut(e);s<r;++s)t[s]&&++n[t[s]-1];var a=new ut(e);for(s=1;s<e;++s)a[s]=a[s-1]+n[s-1]<<1;var o;if(i){o=new ut(1<<e);var l=15-e;for(s=0;s<r;++s)if(t[s])for(var c=s<<4|t[s],h=e-t[s],d=a[t[s]-1]++<<h,f=d|(1<<h)-1;d<=f;++d)o[Qi[d]>>l]=c}else for(o=new ut(r),s=0;s<r;++s)t[s]&&(o[s]=Qi[a[t[s]-1]++]>>15-t[s]);return o}),Pt=new ge(288);for(var oe=0;oe<144;++oe)Pt[oe]=8;for(var oe=144;oe<256;++oe)Pt[oe]=9;for(var oe=256;oe<280;++oe)Pt[oe]=7;for(var oe=280;oe<288;++oe)Pt[oe]=8;var en=new ge(32);for(var oe=0;oe<32;++oe)en[oe]=5;var Ha=Ft(Pt,9,1),qa=Ft(en,5,1),Si=function(t){for(var e=t[0],i=1;i<t.length;++i)t[i]>e&&(e=t[i]);return e},Be=function(t,e,i){var r=e/8|0;return(t[r]|t[r+1]<<8)>>(e&7)&i},Ei=function(t,e){var i=e/8|0;return(t[i]|t[i+1]<<8|t[i+2]<<16)>>(e&7)},tn=function(t){return(t+7)/8|0},ei=function(t,e,i){return(e==null||e<0)&&(e=0),(i==null||i>t.length)&&(i=t.length),new ge(t.subarray(e,i))},Qa=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],ye=function(t,e,i){var r=new Error(e||Qa[t]);if(r.code=t,Error.captureStackTrace&&Error.captureStackTrace(r,ye),!i)throw r;return r},Ai=function(t,e,i,r){var s=t.length,n=0;if(!s||e.f&&!e.l)return i||new ge(0);var a=!i,o=a||e.i!=2,l=e.i;a&&(i=new ge(s*3));var c=function(at){var _e=i.length;if(at>_e){var Fe=new ge(Math.max(_e*2,at));Fe.set(i),i=Fe}},h=e.f||0,d=e.p||0,f=e.b||0,u=e.l,m=e.d,p=e.m,g=e.n,x=s*8;do{if(!u){h=Be(t,d,1);var A=Be(t,d+1,3);if(d+=3,A)if(A==1)u=Ha,m=qa,p=9,g=5;else if(A==2){var w=Be(t,d,31)+257,C=Be(t,d+10,15)+4,M=w+Be(t,d+5,31)+1;d+=14;for(var T=new ge(M),E=new ge(19),I=0;I<C;++I)E[Ya[I]]=Be(t,d+I*3,7);d+=C*3;for(var S=Si(E),U=(1<<S)-1,B=Ft(E,S,1),I=0;I<M;){var V=B[Be(t,d,U)];d+=V&15;var y=V>>4;if(y<16)T[I++]=y;else{var R=0,P=0;for(y==16?(P=3+Be(t,d,3),d+=2,R=T[I-1]):y==17?(P=3+Be(t,d,7),d+=3):y==18&&(P=11+Be(t,d,127),d+=7);P--;)T[I++]=R}}var L=T.subarray(0,w),N=T.subarray(w);p=Si(L),g=Si(N),u=Ft(L,p,1),m=Ft(N,g,1)}else ye(1);else{var y=tn(d)+4,v=t[y-4]|t[y-3]<<8,b=y+v;if(b>s){l&&ye(0);break}o&&c(f+v),i.set(t.subarray(y,b),f),e.b=f+=v,e.p=d=b*8,e.f=h;continue}if(d>x){l&&ye(0);break}}o&&c(f+131072);for(var Y=(1<<p)-1,_=(1<<g)-1,z=d;;z=d){var R=u[Ei(t,d)&Y],W=R>>4;if(d+=R&15,d>x){l&&ye(0);break}if(R||ye(2),W<256)i[f++]=W;else if(W==256){z=d,u=null;break}else{var K=W-254;if(W>264){var I=W-257,Z=Zs[I];K=Be(t,d,(1<<Z)-1)+$s[I],d+=Z}var q=m[Ei(t,d)&_],te=q>>4;q||ye(3),d+=q&15;var N=Ka[te];if(te>3){var Z=js[te];N+=Ei(t,d)&(1<<Z)-1,d+=Z}if(d>x){l&&ye(0);break}o&&c(f+131072);var ue=f+K;if(f<N){var le=n-N,je=Math.min(N,ue);for(le+f<0&&ye(3);f<je;++f)i[f]=r[le+f]}for(;f<ue;++f)i[f]=i[f-N]}}e.l=u,e.p=z,e.b=f,e.f=h,u&&(h=1,e.m=p,e.d=m,e.n=g)}while(!h);return f!=i.length&&a?ei(i,0,f):i.subarray(0,f)},Za=new ge(0),rn=function(t){(t[0]!=31||t[1]!=139||t[2]!=8)&&ye(6,"invalid gzip data");var e=t[3],i=10;e&4&&(i+=(t[10]|t[11]<<8)+2);for(var r=(e>>3&1)+(e>>4&1);r>0;r-=!t[i++]);return i+(e&2)},ja=function(t){var e=t.length;return(t[e-4]|t[e-3]<<8|t[e-2]<<16|t[e-1]<<24)>>>0},_a=function(t,e){return((t[0]&15)!=8||t[0]>>4>7||(t[0]<<8|t[1])%31)&&ye(6,"invalid zlib data"),(t[1]>>5&1)==1&&ye(6,"invalid zlib data: "+(t[1]&32?"need":"unexpected")+" dictionary"),(t[1]>>3&4)+2},Xt=(function(){function t(e,i){typeof e=="function"&&(i=e,e={}),this.ondata=i;var r=e&&e.dictionary&&e.dictionary.subarray(-32768);this.s={i:0,b:r?r.length:0},this.o=new ge(32768),this.p=new ge(0),r&&this.o.set(r)}return t.prototype.e=function(e){if(this.ondata||ye(5),this.d&&ye(4),!this.p.length)this.p=e;else if(e.length){var i=new ge(this.p.length+e.length);i.set(this.p),i.set(e,this.p.length),this.p=i}},t.prototype.c=function(e){this.s.i=+(this.d=e||!1);var i=this.s.b,r=Ai(this.p,this.s,this.o);this.ondata(ei(r,i,this.s.b),this.d),this.o=ei(r,this.s.b-32768),this.s.b=this.o.length,this.p=ei(this.p,this.s.p/8|0),this.s.p&=7},t.prototype.push=function(e,i){this.e(e),this.c(i)},t})();function Ja(t,e){return Ai(t,{i:2},e,e)}var $a=(function(){function t(e,i){this.v=1,this.r=0,Xt.call(this,e,i)}return t.prototype.push=function(e,i){if(Xt.prototype.e.call(this,e),this.r+=e.length,this.v){var r=this.p.subarray(this.v-1),s=r.length>3?rn(r):4;if(s>r.length){if(!i)return}else this.v>1&&this.onmember&&this.onmember(this.r-r.length);this.p=r.subarray(s),this.v=0}Xt.prototype.c.call(this,0),this.s.f&&!this.s.l?(this.v=tn(this.s.p)+9,this.s={i:0},this.o=new ge(0),this.push(new ge(0),i)):i&&Xt.prototype.c.call(this,i)},t})();function eo(t,e){var i=rn(t);return i+8>t.length&&ye(6,"invalid gzip data"),Ai(t.subarray(i,-8),{i:2},new ge(ja(t)),e)}function to(t,e){return Ai(t.subarray(_a(t),-4),{i:2},e,e)}function io(t,e){return t[0]==31&&t[1]==139&&t[2]==8?eo(t,e):(t[0]&15)!=8||t[0]>>4>7||(t[0]<<8|t[1])%31?Ja(t,e):to(t,e)}var ro=typeof TextDecoder<"u"&&new TextDecoder,so=0;try{ro.decode(Za,{stream:!0}),so=1}catch{}class sn{esize;ecode;edata;littleEndian;constructor(e,i,r,s){if(e%16!=0)throw new Error("This does not appear to be a NIFTI extension");this.esize=e,this.ecode=i,this.edata=r,this.littleEndian=s}toArrayBuffer(){let e=new Uint8Array(this.esize),i=new Uint8Array(this.edata);e.set(i,8);let r=new DataView(e.buffer);return r.setInt32(0,this.esize,this.littleEndian),r.setInt32(4,this.ecode,this.littleEndian),e.buffer}}class O{static crcTable=null;static GUNZIP_MAGIC_COOKIE1=31;static GUNZIP_MAGIC_COOKIE2=139;static getStringAt(e,i,r){var s="",n,a;for(n=i;n<r;n+=1)a=e.getUint8(n),a!==0&&(s+=String.fromCharCode(a));return s}static getByteAt=function(e,i){return e.getUint8(i)};static getShortAt=function(e,i,r){return e.getInt16(i,r)};static getIntAt(e,i,r){return e.getInt32(i,r)}static getFloatAt(e,i,r){return e.getFloat32(i,r)}static getDoubleAt(e,i,r){return e.getFloat64(i,r)}static getInt64At(e,i,r){const s=e.getUint32(i,r),n=e.getInt32(i+4,r);let a;return r?a=n*2**32+s:a=s*2**32+n,n<0&&(a+=-1*2**32*2**32),a}static getUint64At(e,i,r){const s=e.getUint32(i+(r?0:4),r),n=e.getUint32(i+(r?4:0),r);return r?n*2**32+s:s*2**32+n}static getExtensionsAt(e,i,r,s){let n=[],a=i;for(;a<s;){let o=r,l=O.getIntAt(e,a,r);if(!l)break;if(l+a>s&&(o=!o,l=O.getIntAt(e,a,o),l+a>s))throw new Error("This does not appear to be a valid NIFTI extension");if(l%16!=0)throw new Error("This does not appear to be a NIFTI extension");let c=O.getIntAt(e,a+4,o),h=e.buffer.slice(a+8,a+l),d=new sn(l,c,h,o);n.push(d),a+=l}return n}static toArrayBuffer(e){var i,r,s;for(i=new ArrayBuffer(e.length),r=new Uint8Array(i),s=0;s<e.length;s+=1)r[s]=e[s];return i}static isString(e){return typeof e=="string"||e instanceof String}static formatNumber(e,i=void 0){let r;return O.isString(e)?r=Number(e):r=e,i?r=r.toPrecision(5):r=r.toPrecision(7),parseFloat(r)}static makeCRCTable(){let e,i=[];for(var r=0;r<256;r++){e=r;for(var s=0;s<8;s++)e=e&1?3988292384^e>>>1:e>>>1;i[r]=e}return i}static crc32(e){O.crcTable||(O.crcTable=O.makeCRCTable());const i=O.crcTable;let r=-1;for(var s=0;s<e.byteLength;s++)r=r>>>8^i[(r^e.getUint8(s))&255];return(r^-1)>>>0}}class G{littleEndian=!1;dim_info=0;dims=[];intent_p1=0;intent_p2=0;intent_p3=0;intent_code=0;datatypeCode=0;numBitsPerVoxel=0;slice_start=0;slice_end=0;slice_code=0;pixDims=[];vox_offset=0;scl_slope=1;scl_inter=0;xyzt_units=0;cal_max=0;cal_min=0;slice_duration=0;toffset=0;description="";aux_file="";intent_name="";qform_code=0;sform_code=0;quatern_a=0;quatern_b=0;quatern_c=0;quatern_d=0;qoffset_x=0;qoffset_y=0;qoffset_z=0;affine=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];qfac=1;quatern_R;magic="0";isHDR=!1;extensionFlag=[0,0,0,0];extensionSize=0;extensionCode=0;extensions=[];static TYPE_NONE=0;static TYPE_BINARY=1;static TYPE_UINT8=2;static TYPE_INT16=4;static TYPE_INT32=8;static TYPE_FLOAT32=16;static TYPE_COMPLEX64=32;static TYPE_FLOAT64=64;static TYPE_RGB24=128;static TYPE_INT8=256;static TYPE_UINT16=512;static TYPE_UINT32=768;static TYPE_INT64=1024;static TYPE_UINT64=1280;static TYPE_FLOAT128=1536;static TYPE_COMPLEX128=1792;static TYPE_COMPLEX256=2048;static XFORM_UNKNOWN=0;static XFORM_SCANNER_ANAT=1;static XFORM_ALIGNED_ANAT=2;static XFORM_TALAIRACH=3;static XFORM_MNI_152=4;static SPATIAL_UNITS_MASK=7;static TEMPORAL_UNITS_MASK=56;static UNITS_UNKNOWN=0;static UNITS_METER=1;static UNITS_MM=2;static UNITS_MICRON=3;static UNITS_SEC=8;static UNITS_MSEC=16;static UNITS_USEC=24;static UNITS_HZ=32;static UNITS_PPM=40;static UNITS_RADS=48;static MAGIC_COOKIE=348;static STANDARD_HEADER_SIZE=348;static MAGIC_NUMBER_LOCATION=344;static MAGIC_NUMBER=[110,43,49];static MAGIC_NUMBER2=[110,105,49];static EXTENSION_HEADER_SIZE=8;readHeader(e){var i=new DataView(e),r=O.getIntAt(i,0,this.littleEndian),s,n,a,o;if(r!==G.MAGIC_COOKIE&&(this.littleEndian=!0,r=O.getIntAt(i,0,this.littleEndian)),r!==G.MAGIC_COOKIE)throw new Error("This does not appear to be a NIFTI file!");for(this.dim_info=O.getByteAt(i,39),s=0;s<8;s+=1)o=40+s*2,this.dims[s]=O.getShortAt(i,o,this.littleEndian);for(this.intent_p1=O.getFloatAt(i,56,this.littleEndian),this.intent_p2=O.getFloatAt(i,60,this.littleEndian),this.intent_p3=O.getFloatAt(i,64,this.littleEndian),this.intent_code=O.getShortAt(i,68,this.littleEndian),this.datatypeCode=O.getShortAt(i,70,this.littleEndian),this.numBitsPerVoxel=O.getShortAt(i,72,this.littleEndian),this.slice_start=O.getShortAt(i,74,this.littleEndian),s=0;s<8;s+=1)o=76+s*4,this.pixDims[s]=O.getFloatAt(i,o,this.littleEndian);if(this.vox_offset=O.getFloatAt(i,108,this.littleEndian),this.scl_slope=O.getFloatAt(i,112,this.littleEndian),this.scl_inter=O.getFloatAt(i,116,this.littleEndian),this.slice_end=O.getShortAt(i,120,this.littleEndian),this.slice_code=O.getByteAt(i,122),this.xyzt_units=O.getByteAt(i,123),this.cal_max=O.getFloatAt(i,124,this.littleEndian),this.cal_min=O.getFloatAt(i,128,this.littleEndian),this.slice_duration=O.getFloatAt(i,132,this.littleEndian),this.toffset=O.getFloatAt(i,136,this.littleEndian),this.description=O.getStringAt(i,148,228),this.aux_file=O.getStringAt(i,228,252),this.qform_code=O.getShortAt(i,252,this.littleEndian),this.sform_code=O.getShortAt(i,254,this.littleEndian),this.quatern_b=O.getFloatAt(i,256,this.littleEndian),this.quatern_c=O.getFloatAt(i,260,this.littleEndian),this.quatern_d=O.getFloatAt(i,264,this.littleEndian),this.quatern_a=Math.sqrt(1-(Math.pow(this.quatern_b,2)+Math.pow(this.quatern_c,2)+Math.pow(this.quatern_d,2))),this.qoffset_x=O.getFloatAt(i,268,this.littleEndian),this.qoffset_y=O.getFloatAt(i,272,this.littleEndian),this.qoffset_z=O.getFloatAt(i,276,this.littleEndian),this.qform_code<1&&this.sform_code<1&&(this.affine[0][0]=this.pixDims[1],this.affine[1][1]=this.pixDims[2],this.affine[2][2]=this.pixDims[3]),this.qform_code>0&&this.sform_code<this.qform_code){const l=this.quatern_a,c=this.quatern_b,h=this.quatern_c,d=this.quatern_d;for(this.qfac=this.pixDims[0]===0?1:this.pixDims[0],this.quatern_R=[[l*l+c*c-h*h-d*d,2*c*h-2*l*d,2*c*d+2*l*h],[2*c*h+2*l*d,l*l+h*h-c*c-d*d,2*h*d-2*l*c],[2*c*d-2*l*h,2*h*d+2*l*c,l*l+d*d-h*h-c*c]],n=0;n<3;n+=1)for(a=0;a<3;a+=1)this.affine[n][a]=this.quatern_R[n][a]*this.pixDims[a+1],a===2&&(this.affine[n][a]*=this.qfac);this.affine[0][3]=this.qoffset_x,this.affine[1][3]=this.qoffset_y,this.affine[2][3]=this.qoffset_z}else if(this.sform_code>0)for(n=0;n<3;n+=1)for(a=0;a<4;a+=1)o=280+(n*4+a)*4,this.affine[n][a]=O.getFloatAt(i,o,this.littleEndian);if(this.affine[3][0]=0,this.affine[3][1]=0,this.affine[3][2]=0,this.affine[3][3]=1,this.intent_name=O.getStringAt(i,328,344),this.magic=O.getStringAt(i,344,348),this.isHDR=this.magic===String.fromCharCode.apply(null,G.MAGIC_NUMBER2),i.byteLength>G.MAGIC_COOKIE){this.extensionFlag[0]=O.getByteAt(i,348),this.extensionFlag[1]=O.getByteAt(i,349),this.extensionFlag[2]=O.getByteAt(i,350),this.extensionFlag[3]=O.getByteAt(i,351);let l=!0;!this.isHDR&&this.vox_offset<=352&&(l=!1),i.byteLength<=368&&(l=!1),l&&this.extensionFlag[0]&&(this.extensions=O.getExtensionsAt(i,this.getExtensionLocation(),this.littleEndian,this.vox_offset),this.extensionSize=this.extensions[0].esize,this.extensionCode=this.extensions[0].ecode)}}toFormattedString(){var e=O.formatNumber,i="";return i+="Dim Info = "+this.dim_info+`
|
|
3
|
+
`,i+="Image Dimensions (1-8): "+this.dims[0]+", "+this.dims[1]+", "+this.dims[2]+", "+this.dims[3]+", "+this.dims[4]+", "+this.dims[5]+", "+this.dims[6]+", "+this.dims[7]+`
|
|
4
|
+
`,i+="Intent Parameters (1-3): "+this.intent_p1+", "+this.intent_p2+", "+this.intent_p3+`
|
|
5
|
+
`,i+="Intent Code = "+this.intent_code+`
|
|
6
|
+
`,i+="Datatype = "+this.datatypeCode+" ("+this.getDatatypeCodeString(this.datatypeCode)+`)
|
|
7
|
+
`,i+="Bits Per Voxel = "+this.numBitsPerVoxel+`
|
|
8
|
+
`,i+="Slice Start = "+this.slice_start+`
|
|
9
|
+
`,i+="Voxel Dimensions (1-8): "+e(this.pixDims[0])+", "+e(this.pixDims[1])+", "+e(this.pixDims[2])+", "+e(this.pixDims[3])+", "+e(this.pixDims[4])+", "+e(this.pixDims[5])+", "+e(this.pixDims[6])+", "+e(this.pixDims[7])+`
|
|
10
|
+
`,i+="Image Offset = "+this.vox_offset+`
|
|
11
|
+
`,i+="Data Scale: Slope = "+e(this.scl_slope)+" Intercept = "+e(this.scl_inter)+`
|
|
12
|
+
`,i+="Slice End = "+this.slice_end+`
|
|
13
|
+
`,i+="Slice Code = "+this.slice_code+`
|
|
14
|
+
`,i+="Units Code = "+this.xyzt_units+" ("+this.getUnitsCodeString(G.SPATIAL_UNITS_MASK&this.xyzt_units)+", "+this.getUnitsCodeString(G.TEMPORAL_UNITS_MASK&this.xyzt_units)+`)
|
|
15
|
+
`,i+="Display Range: Max = "+e(this.cal_max)+" Min = "+e(this.cal_min)+`
|
|
16
|
+
`,i+="Slice Duration = "+this.slice_duration+`
|
|
17
|
+
`,i+="Time Axis Shift = "+this.toffset+`
|
|
18
|
+
`,i+='Description: "'+this.description+`"
|
|
19
|
+
`,i+='Auxiliary File: "'+this.aux_file+`"
|
|
20
|
+
`,i+="Q-Form Code = "+this.qform_code+" ("+this.getTransformCodeString(this.qform_code)+`)
|
|
21
|
+
`,i+="S-Form Code = "+this.sform_code+" ("+this.getTransformCodeString(this.sform_code)+`)
|
|
22
|
+
`,i+="Quaternion Parameters: b = "+e(this.quatern_b)+" c = "+e(this.quatern_c)+" d = "+e(this.quatern_d)+`
|
|
23
|
+
`,i+="Quaternion Offsets: x = "+this.qoffset_x+" y = "+this.qoffset_y+" z = "+this.qoffset_z+`
|
|
24
|
+
`,i+="S-Form Parameters X: "+e(this.affine[0][0])+", "+e(this.affine[0][1])+", "+e(this.affine[0][2])+", "+e(this.affine[0][3])+`
|
|
25
|
+
`,i+="S-Form Parameters Y: "+e(this.affine[1][0])+", "+e(this.affine[1][1])+", "+e(this.affine[1][2])+", "+e(this.affine[1][3])+`
|
|
26
|
+
`,i+="S-Form Parameters Z: "+e(this.affine[2][0])+", "+e(this.affine[2][1])+", "+e(this.affine[2][2])+", "+e(this.affine[2][3])+`
|
|
27
|
+
`,i+='Intent Name: "'+this.intent_name+`"
|
|
28
|
+
`,this.extensionFlag[0]&&(i+="Extension: Size = "+this.extensionSize+" Code = "+this.extensionCode+`
|
|
29
|
+
`),i}getDatatypeCodeString=function(e){return e===G.TYPE_UINT8?"1-Byte Unsigned Integer":e===G.TYPE_INT16?"2-Byte Signed Integer":e===G.TYPE_INT32?"4-Byte Signed Integer":e===G.TYPE_FLOAT32?"4-Byte Float":e===G.TYPE_FLOAT64?"8-Byte Float":e===G.TYPE_RGB24?"RGB":e===G.TYPE_INT8?"1-Byte Signed Integer":e===G.TYPE_UINT16?"2-Byte Unsigned Integer":e===G.TYPE_UINT32?"4-Byte Unsigned Integer":e===G.TYPE_INT64?"8-Byte Signed Integer":e===G.TYPE_UINT64?"8-Byte Unsigned Integer":"Unknown"};getTransformCodeString=function(e){return e===G.XFORM_SCANNER_ANAT?"Scanner":e===G.XFORM_ALIGNED_ANAT?"Aligned":e===G.XFORM_TALAIRACH?"Talairach":e===G.XFORM_MNI_152?"MNI":"Unknown"};getUnitsCodeString=function(e){return e===G.UNITS_METER?"Meters":e===G.UNITS_MM?"Millimeters":e===G.UNITS_MICRON?"Microns":e===G.UNITS_SEC?"Seconds":e===G.UNITS_MSEC?"Milliseconds":e===G.UNITS_USEC?"Microseconds":e===G.UNITS_HZ?"Hz":e===G.UNITS_PPM?"PPM":e===G.UNITS_RADS?"Rads":"Unknown"};getQformMat(){return this.convertNiftiQFormToNiftiSForm(this.quatern_b,this.quatern_c,this.quatern_d,this.qoffset_x,this.qoffset_y,this.qoffset_z,this.pixDims[1],this.pixDims[2],this.pixDims[3],this.pixDims[0])}convertNiftiQFormToNiftiSForm(e,i,r,s,n,a,o,l,c,h){var d=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],f,u=e,m=i,p=r,g,x,A;return d[3][0]=d[3][1]=d[3][2]=0,d[3][3]=1,f=1-(u*u+m*m+p*p),f<1e-7?(f=1/Math.sqrt(u*u+m*m+p*p),u*=f,m*=f,p*=f,f=0):f=Math.sqrt(f),g=o>0?o:1,x=l>0?l:1,A=c>0?c:1,h<0&&(A=-A),d[0][0]=(f*f+u*u-m*m-p*p)*g,d[0][1]=2*(u*m-f*p)*x,d[0][2]=2*(u*p+f*m)*A,d[1][0]=2*(u*m+f*p)*g,d[1][1]=(f*f+m*m-u*u-p*p)*x,d[1][2]=2*(m*p-f*u)*A,d[2][0]=2*(u*p-f*m)*g,d[2][1]=2*(m*p+f*u)*x,d[2][2]=(f*f+p*p-m*m-u*u)*A,d[0][3]=s,d[1][3]=n,d[2][3]=a,d}convertNiftiSFormToNEMA(e){var i,r,s,n,a,o,l,c,h,d,f,u,m,p,g,x,A,y,v,b,w,C,M,T,E,I,S,U,B,V,R,P,L,N;if(g=0,S=[[0,0,0],[0,0,0],[0,0,0]],U=[[0,0,0],[0,0,0],[0,0,0]],i=e[0][0],r=e[0][1],s=e[0][2],n=e[1][0],a=e[1][1],o=e[1][2],l=e[2][0],c=e[2][1],h=e[2][2],d=Math.sqrt(i*i+n*n+l*l),d===0||(i/=d,n/=d,l/=d,d=Math.sqrt(r*r+a*a+c*c),d===0))return null;if(r/=d,a/=d,c/=d,d=i*r+n*a+l*c,Math.abs(d)>1e-4){if(r-=d*i,a-=d*n,c-=d*l,d=Math.sqrt(r*r+a*a+c*c),d===0)return null;r/=d,a/=d,c/=d}if(d=Math.sqrt(s*s+o*o+h*h),d===0?(s=n*c-l*a,o=l*r-c*i,h=i*a-n*r):(s/=d,o/=d,h/=d),d=i*s+n*o+l*h,Math.abs(d)>1e-4){if(s-=d*i,o-=d*n,h-=d*l,d=Math.sqrt(s*s+o*o+h*h),d===0)return null;s/=d,o/=d,h/=d}if(d=r*s+a*o+c*h,Math.abs(d)>1e-4){if(s-=d*r,o-=d*a,h-=d*c,d=Math.sqrt(s*s+o*o+h*h),d===0)return null;s/=d,o/=d,h/=d}if(S[0][0]=i,S[0][1]=r,S[0][2]=s,S[1][0]=n,S[1][1]=a,S[1][2]=o,S[2][0]=l,S[2][1]=c,S[2][2]=h,f=this.nifti_mat33_determ(S),f===0)return null;for(I=-666,v=C=M=T=1,b=2,w=3,m=1;m<=3;m+=1)for(p=1;p<=3;p+=1)if(m!==p){for(g=1;g<=3;g+=1)if(!(m===g||p===g))for(U[0][0]=U[0][1]=U[0][2]=U[1][0]=U[1][1]=U[1][2]=U[2][0]=U[2][1]=U[2][2]=0,x=-1;x<=1;x+=2)for(A=-1;A<=1;A+=2)for(y=-1;y<=1;y+=2)U[0][m-1]=x,U[1][p-1]=A,U[2][g-1]=y,u=this.nifti_mat33_determ(U),u*f>0&&(E=this.nifti_mat33_mul(U,S),d=E[0][0]+E[1][1]+E[2][2],d>I&&(I=d,v=m,b=p,w=g,C=x,M=A,T=y))}switch(B=V=R=P=L=N="",v*C){case 1:B="X",P="+";break;case-1:B="X",P="-";break;case 2:B="Y",P="+";break;case-2:B="Y",P="-";break;case 3:B="Z",P="+";break;case-3:B="Z",P="-";break}switch(b*M){case 1:V="X",L="+";break;case-1:V="X",L="-";break;case 2:V="Y",L="+";break;case-2:V="Y",L="-";break;case 3:V="Z",L="+";break;case-3:V="Z",L="-";break}switch(w*T){case 1:R="X",N="+";break;case-1:R="X",N="-";break;case 2:R="Y",N="+";break;case-2:R="Y",N="-";break;case 3:R="Z",N="+";break;case-3:R="Z",N="-";break}return B+V+R+P+L+N}nifti_mat33_mul=function(e,i){var r=[[0,0,0],[0,0,0],[0,0,0]],s,n;for(s=0;s<3;s+=1)for(n=0;n<3;n+=1)r[s][n]=e[s][0]*i[0][n]+e[s][1]*i[1][n]+e[s][2]*i[2][n];return r};nifti_mat33_determ=function(e){var i,r,s,n,a,o,l,c,h;return i=e[0][0],r=e[0][1],s=e[0][2],n=e[1][0],a=e[1][1],o=e[1][2],l=e[2][0],c=e[2][1],h=e[2][2],i*a*h-i*c*o-n*r*h+n*c*s+l*r*o-l*a*s};getExtensionLocation(){return G.MAGIC_COOKIE+4}getExtensionSize(e){return O.getIntAt(e,this.getExtensionLocation(),this.littleEndian)}getExtensionCode(e){return O.getIntAt(e,this.getExtensionLocation()+4,this.littleEndian)}addExtension(e,i=-1){i==-1?this.extensions.push(e):this.extensions.splice(i,0,e),this.vox_offset+=e.esize}removeExtension(e){let i=this.extensions[e];i&&(this.vox_offset-=i.esize),this.extensions.splice(e,1)}toArrayBuffer(e=!1){let s=352;if(e)for(let l of this.extensions)s+=l.esize;let n=new Uint8Array(s),a=new DataView(n.buffer);a.setInt32(0,348,this.littleEndian),a.setUint8(39,this.dim_info);for(let l=0;l<8;l++)a.setUint16(40+2*l,this.dims[l],this.littleEndian);a.setFloat32(56,this.intent_p1,this.littleEndian),a.setFloat32(60,this.intent_p2,this.littleEndian),a.setFloat32(64,this.intent_p3,this.littleEndian),a.setInt16(68,this.intent_code,this.littleEndian),a.setInt16(70,this.datatypeCode,this.littleEndian),a.setInt16(72,this.numBitsPerVoxel,this.littleEndian),a.setInt16(74,this.slice_start,this.littleEndian);for(let l=0;l<8;l++)a.setFloat32(76+4*l,this.pixDims[l],this.littleEndian);a.setFloat32(108,this.vox_offset,this.littleEndian),a.setFloat32(112,this.scl_slope,this.littleEndian),a.setFloat32(116,this.scl_inter,this.littleEndian),a.setInt16(120,this.slice_end,this.littleEndian),a.setUint8(122,this.slice_code),a.setUint8(123,this.xyzt_units),a.setFloat32(124,this.cal_max,this.littleEndian),a.setFloat32(128,this.cal_min,this.littleEndian),a.setFloat32(132,this.slice_duration,this.littleEndian),a.setFloat32(136,this.toffset,this.littleEndian),n.set(new TextEncoder().encode(this.description),148),n.set(new TextEncoder().encode(this.aux_file),228),a.setInt16(252,this.qform_code,this.littleEndian),a.setInt16(254,this.sform_code,this.littleEndian),a.setFloat32(256,this.quatern_b,this.littleEndian),a.setFloat32(260,this.quatern_c,this.littleEndian),a.setFloat32(264,this.quatern_d,this.littleEndian),a.setFloat32(268,this.qoffset_x,this.littleEndian),a.setFloat32(272,this.qoffset_y,this.littleEndian),a.setFloat32(276,this.qoffset_z,this.littleEndian);const o=this.affine.flat();for(let l=0;l<12;l++)a.setFloat32(280+4*l,o[l],this.littleEndian);if(n.set(new TextEncoder().encode(this.intent_name),328),n.set(new TextEncoder().encode(this.magic),344),e){n.set(Uint8Array.from([1,0,0,0]),348);let l=this.getExtensionLocation();for(const c of this.extensions)a.setInt32(l,c.esize,c.littleEndian),a.setInt32(l+4,c.ecode,c.littleEndian),n.set(new Uint8Array(c.edata),l+8),l+=c.esize}else n.set(new Uint8Array(4).fill(0),348);return n.buffer}}class xe{littleEndian=!1;dim_info=0;dims=[];intent_p1=0;intent_p2=0;intent_p3=0;intent_code=0;datatypeCode=0;numBitsPerVoxel=0;slice_start=0;slice_end=0;slice_code=0;pixDims=[];vox_offset=0;scl_slope=1;scl_inter=0;xyzt_units=0;cal_max=0;cal_min=0;slice_duration=0;toffset=0;description="";aux_file="";intent_name="";qform_code=0;sform_code=0;quatern_b=0;quatern_c=0;quatern_d=0;qoffset_x=0;qoffset_y=0;qoffset_z=0;affine=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];magic="0";extensionFlag=[0,0,0,0];extensions=[];extensionSize=0;extensionCode=0;static MAGIC_COOKIE=540;static MAGIC_NUMBER_LOCATION=4;static MAGIC_NUMBER=[110,43,50,0,13,10,26,10];static MAGIC_NUMBER2=[110,105,50,0,13,10,26,10];readHeader(e){var i=new DataView(e),r=O.getIntAt(i,0,this.littleEndian),s,n,a,o;if(r!==xe.MAGIC_COOKIE&&(this.littleEndian=!0,r=O.getIntAt(i,0,this.littleEndian)),r!==xe.MAGIC_COOKIE)throw new Error("This does not appear to be a NIFTI file!");for(this.magic=O.getStringAt(i,4,12),this.datatypeCode=O.getShortAt(i,12,this.littleEndian),this.numBitsPerVoxel=O.getShortAt(i,14,this.littleEndian),s=0;s<8;s+=1)o=16+s*8,this.dims[s]=O.getInt64At(i,o,this.littleEndian);for(this.intent_p1=O.getDoubleAt(i,80,this.littleEndian),this.intent_p2=O.getDoubleAt(i,88,this.littleEndian),this.intent_p3=O.getDoubleAt(i,96,this.littleEndian),s=0;s<8;s+=1)o=104+s*8,this.pixDims[s]=O.getDoubleAt(i,o,this.littleEndian);for(this.vox_offset=O.getInt64At(i,168,this.littleEndian),this.scl_slope=O.getDoubleAt(i,176,this.littleEndian),this.scl_inter=O.getDoubleAt(i,184,this.littleEndian),this.cal_max=O.getDoubleAt(i,192,this.littleEndian),this.cal_min=O.getDoubleAt(i,200,this.littleEndian),this.slice_duration=O.getDoubleAt(i,208,this.littleEndian),this.toffset=O.getDoubleAt(i,216,this.littleEndian),this.slice_start=O.getInt64At(i,224,this.littleEndian),this.slice_end=O.getInt64At(i,232,this.littleEndian),this.description=O.getStringAt(i,240,320),this.aux_file=O.getStringAt(i,320,344),this.qform_code=O.getIntAt(i,344,this.littleEndian),this.sform_code=O.getIntAt(i,348,this.littleEndian),this.quatern_b=O.getDoubleAt(i,352,this.littleEndian),this.quatern_c=O.getDoubleAt(i,360,this.littleEndian),this.quatern_d=O.getDoubleAt(i,368,this.littleEndian),this.qoffset_x=O.getDoubleAt(i,376,this.littleEndian),this.qoffset_y=O.getDoubleAt(i,384,this.littleEndian),this.qoffset_z=O.getDoubleAt(i,392,this.littleEndian),n=0;n<3;n+=1)for(a=0;a<4;a+=1)o=400+(n*4+a)*8,this.affine[n][a]=O.getDoubleAt(i,o,this.littleEndian);this.affine[3][0]=0,this.affine[3][1]=0,this.affine[3][2]=0,this.affine[3][3]=1,this.slice_code=O.getIntAt(i,496,this.littleEndian),this.xyzt_units=O.getIntAt(i,500,this.littleEndian),this.intent_code=O.getIntAt(i,504,this.littleEndian),this.intent_name=O.getStringAt(i,508,524),this.dim_info=O.getByteAt(i,524),i.byteLength>xe.MAGIC_COOKIE&&(this.extensionFlag[0]=O.getByteAt(i,540),this.extensionFlag[1]=O.getByteAt(i,541),this.extensionFlag[2]=O.getByteAt(i,542),this.extensionFlag[3]=O.getByteAt(i,543),this.extensionFlag[0]&&(this.extensions=O.getExtensionsAt(i,this.getExtensionLocation(),this.littleEndian,this.vox_offset),this.extensionSize=this.extensions[0].esize,this.extensionCode=this.extensions[0].ecode))}toFormattedString(){var e=O.formatNumber,i="";return i+="Datatype = "+ +this.datatypeCode+" ("+this.getDatatypeCodeString(this.datatypeCode)+`)
|
|
30
|
+
`,i+="Bits Per Voxel = = "+this.numBitsPerVoxel+`
|
|
31
|
+
`,i+="Image Dimensions (1-8): "+this.dims[0]+", "+this.dims[1]+", "+this.dims[2]+", "+this.dims[3]+", "+this.dims[4]+", "+this.dims[5]+", "+this.dims[6]+", "+this.dims[7]+`
|
|
32
|
+
`,i+="Intent Parameters (1-3): "+this.intent_p1+", "+this.intent_p2+", "+this.intent_p3+`
|
|
33
|
+
`,i+="Voxel Dimensions (1-8): "+e(this.pixDims[0])+", "+e(this.pixDims[1])+", "+e(this.pixDims[2])+", "+e(this.pixDims[3])+", "+e(this.pixDims[4])+", "+e(this.pixDims[5])+", "+e(this.pixDims[6])+", "+e(this.pixDims[7])+`
|
|
34
|
+
`,i+="Image Offset = "+this.vox_offset+`
|
|
35
|
+
`,i+="Data Scale: Slope = "+e(this.scl_slope)+" Intercept = "+e(this.scl_inter)+`
|
|
36
|
+
`,i+="Display Range: Max = "+e(this.cal_max)+" Min = "+e(this.cal_min)+`
|
|
37
|
+
`,i+="Slice Duration = "+this.slice_duration+`
|
|
38
|
+
`,i+="Time Axis Shift = "+this.toffset+`
|
|
39
|
+
`,i+="Slice Start = "+this.slice_start+`
|
|
40
|
+
`,i+="Slice End = "+this.slice_end+`
|
|
41
|
+
`,i+='Description: "'+this.description+`"
|
|
42
|
+
`,i+='Auxiliary File: "'+this.aux_file+`"
|
|
43
|
+
`,i+="Q-Form Code = "+this.qform_code+" ("+this.getTransformCodeString(this.qform_code)+`)
|
|
44
|
+
`,i+="S-Form Code = "+this.sform_code+" ("+this.getTransformCodeString(this.sform_code)+`)
|
|
45
|
+
`,i+="Quaternion Parameters: b = "+e(this.quatern_b)+" c = "+e(this.quatern_c)+" d = "+e(this.quatern_d)+`
|
|
46
|
+
`,i+="Quaternion Offsets: x = "+this.qoffset_x+" y = "+this.qoffset_y+" z = "+this.qoffset_z+`
|
|
47
|
+
`,i+="S-Form Parameters X: "+e(this.affine[0][0])+", "+e(this.affine[0][1])+", "+e(this.affine[0][2])+", "+e(this.affine[0][3])+`
|
|
48
|
+
`,i+="S-Form Parameters Y: "+e(this.affine[1][0])+", "+e(this.affine[1][1])+", "+e(this.affine[1][2])+", "+e(this.affine[1][3])+`
|
|
49
|
+
`,i+="S-Form Parameters Z: "+e(this.affine[2][0])+", "+e(this.affine[2][1])+", "+e(this.affine[2][2])+", "+e(this.affine[2][3])+`
|
|
50
|
+
`,i+="Slice Code = "+this.slice_code+`
|
|
51
|
+
`,i+="Units Code = "+this.xyzt_units+" ("+this.getUnitsCodeString(G.SPATIAL_UNITS_MASK&this.xyzt_units)+", "+this.getUnitsCodeString(G.TEMPORAL_UNITS_MASK&this.xyzt_units)+`)
|
|
52
|
+
`,i+="Intent Code = "+this.intent_code+`
|
|
53
|
+
`,i+='Intent Name: "'+this.intent_name+`"
|
|
54
|
+
`,i+="Dim Info = "+this.dim_info+`
|
|
55
|
+
`,i}getExtensionLocation=function(){return xe.MAGIC_COOKIE+4};getExtensionSize=G.prototype.getExtensionSize;getExtensionCode=G.prototype.getExtensionCode;addExtension=G.prototype.addExtension;removeExtension=G.prototype.removeExtension;getDatatypeCodeString=G.prototype.getDatatypeCodeString;getTransformCodeString=G.prototype.getTransformCodeString;getUnitsCodeString=G.prototype.getUnitsCodeString;getQformMat=G.prototype.getQformMat;convertNiftiQFormToNiftiSForm=G.prototype.convertNiftiQFormToNiftiSForm;convertNiftiSFormToNEMA=G.prototype.convertNiftiSFormToNEMA;nifti_mat33_mul=G.prototype.nifti_mat33_mul;nifti_mat33_determ=G.prototype.nifti_mat33_determ;toArrayBuffer(e=!1){let s=544;if(e)for(let l of this.extensions)s+=l.esize;let n=new Uint8Array(s),a=new DataView(n.buffer);a.setInt32(0,540,this.littleEndian),n.set(new TextEncoder().encode(this.magic),4),a.setInt16(12,this.datatypeCode,this.littleEndian),a.setInt16(14,this.numBitsPerVoxel,this.littleEndian);for(let l=0;l<8;l++)a.setBigInt64(16+8*l,BigInt(this.dims[l]),this.littleEndian);a.setFloat64(80,this.intent_p1,this.littleEndian),a.setFloat64(88,this.intent_p2,this.littleEndian),a.setFloat64(96,this.intent_p3,this.littleEndian);for(let l=0;l<8;l++)a.setFloat64(104+8*l,this.pixDims[l],this.littleEndian);a.setBigInt64(168,BigInt(this.vox_offset),this.littleEndian),a.setFloat64(176,this.scl_slope,this.littleEndian),a.setFloat64(184,this.scl_inter,this.littleEndian),a.setFloat64(192,this.cal_max,this.littleEndian),a.setFloat64(200,this.cal_min,this.littleEndian),a.setFloat64(208,this.slice_duration,this.littleEndian),a.setFloat64(216,this.toffset,this.littleEndian),a.setBigInt64(224,BigInt(this.slice_start),this.littleEndian),a.setBigInt64(232,BigInt(this.slice_end),this.littleEndian),n.set(new TextEncoder().encode(this.description),240),n.set(new TextEncoder().encode(this.aux_file),320),a.setInt32(344,this.qform_code,this.littleEndian),a.setInt32(348,this.sform_code,this.littleEndian),a.setFloat64(352,this.quatern_b,this.littleEndian),a.setFloat64(360,this.quatern_c,this.littleEndian),a.setFloat64(368,this.quatern_d,this.littleEndian),a.setFloat64(376,this.qoffset_x,this.littleEndian),a.setFloat64(384,this.qoffset_y,this.littleEndian),a.setFloat64(392,this.qoffset_z,this.littleEndian);const o=this.affine.flat();for(let l=0;l<12;l++)a.setFloat64(400+8*l,o[l],this.littleEndian);if(a.setInt32(496,this.slice_code,this.littleEndian),a.setInt32(500,this.xyzt_units,this.littleEndian),a.setInt32(504,this.intent_code,this.littleEndian),n.set(new TextEncoder().encode(this.intent_name),508),a.setUint8(524,this.dim_info),e){n.set(Uint8Array.from([1,0,0,0]),540);let l=this.getExtensionLocation();for(const c of this.extensions)a.setInt32(l,c.esize,c.littleEndian),a.setInt32(l+4,c.ecode,c.littleEndian),n.set(new Uint8Array(c.edata),l+8),l+=c.esize}else n.set(new Uint8Array(4).fill(0),540);return n.buffer}}function no(t,e=!1){var i,r,s,n;return t.byteLength<G.STANDARD_HEADER_SIZE?!1:(i=new DataView(t),i&&(r=i.getUint8(G.MAGIC_NUMBER_LOCATION)),s=i.getUint8(G.MAGIC_NUMBER_LOCATION+1),n=i.getUint8(G.MAGIC_NUMBER_LOCATION+2),e&&r===G.MAGIC_NUMBER2[0]&&s===G.MAGIC_NUMBER2[1]&&n===G.MAGIC_NUMBER2[2]?!0:r===G.MAGIC_NUMBER[0]&&s===G.MAGIC_NUMBER[1]&&n===G.MAGIC_NUMBER[2])}function ao(t,e=!1){var i,r,s,n;return t.byteLength<G.STANDARD_HEADER_SIZE?!1:(i=new DataView(t),r=i.getUint8(xe.MAGIC_NUMBER_LOCATION),s=i.getUint8(xe.MAGIC_NUMBER_LOCATION+1),n=i.getUint8(xe.MAGIC_NUMBER_LOCATION+2),e&&r===xe.MAGIC_NUMBER2[0]&&s===xe.MAGIC_NUMBER2[1]&&n===xe.MAGIC_NUMBER2[2]?!0:r===xe.MAGIC_NUMBER[0]&&s===xe.MAGIC_NUMBER[1]&&n===xe.MAGIC_NUMBER[2])}function pr(t){var e,i,r;return!!(t&&(e=new DataView(t),i=e.getUint8(0),r=e.getUint8(1),i===O.GUNZIP_MAGIC_COOKIE1||r===O.GUNZIP_MAGIC_COOKIE2))}function oo(t){return io(new Uint8Array(t)).buffer}async function lo(t){const e=new Uint8Array(t),i=e[0]===31&&e[1]===139&&e[2]===8?"gzip":e[0]===120&&(e[1]===1||e[1]===94||e[1]===156||e[1]===218)?"deflate":"deflate-raw",r=new DecompressionStream(i),s=r.writable.getWriter();s.write(e).catch(console.error);const n=s.close().catch(console.error),o=await new Response(r.readable).arrayBuffer();return await n,o}async function _r(t,e=1/0){const i=u=>u[0]===31&&u[1]===139&&u[2]===8?"gzip":u[0]===120&&[1,94,156,218].includes(u[1])?"deflate":"deflate-raw",r=new Uint8Array(t),s=i(r),n=new DecompressionStream(s),a=new TransformStream({transform(u,m){m.enqueue(u)},flush(u){u.terminate()}}),{readable:o,writable:l}=n,c=l.getWriter(),h=o.pipeThrough(a).getReader();c.write(r).catch(u=>{u instanceof Error&&u.name==="AbortError"||console.error("Error during write:",u)});const d=[];let f=0;try{for(;f<e;){const{done:u,value:m}=await h.read();if(u)break;const p=e-f,g=m.subarray(0,Math.min(m.length,p));if(d.push(g),f+=g.length,f>=e){await Promise.all([h.cancel().catch(()=>{}),c.abort().catch(()=>{})]);break}}}catch(u){u instanceof Error&&u.name==="AbortError"||console.error("Error during decompression:",u)}finally{await Promise.allSettled([h.cancel().catch(()=>{}),c.close().catch(()=>{})])}return d.length===1?d[0].buffer:d.reduce((u,m)=>{const p=new Uint8Array(u.byteLength+m.byteLength);return p.set(new Uint8Array(u),0),p.set(m,u.byteLength),p.buffer},new ArrayBuffer(0))}function co(t,e=!1){let i=null;if(pr(t)&&(t=oo(t)),no(t,e)?i=new G:ao(t,e)&&(i=new xe),i)i.readHeader(t);else throw new Error("That file does not appear to be NIFTI!");return i}async function Nt(t,e=!1){if(!pr(t))return co(t,e);let i=null,r=await _r(t,540),s=!0,n=!0;var a=new DataView(r);const o=a.getInt32(0,!0),l=a.getInt32(0,!1);if(o!==348)if(l===348)s=!1;else if(o===540)n=!1;else if(l===540)n=!1,s=!1;else throw new Error("That file does not appear to be NIFTI!");let c=Math.round(a.getFloat32(108,s));return xe&&(c=O.getUint64At(a,168,s)),c>r.byteLength&&(r=await _r(t,c)),n?i=new G:i=new xe,i.readHeader(r),i}function ho(t){return t.extensionFlag[0]!=0}function Jr(t,e){var i=t.vox_offset,r=1,s=1;t.dims[4]&&(r=t.dims[4]),t.dims[5]&&(s=t.dims[5]);var n=t.dims[1]*t.dims[2]*t.dims[3]*r*s*(t.numBitsPerVoxel/8);return e.slice(i,i+n)}function nn(t,e,i,r={}){return e!==void 0&&i!==void 0&&(r={...r,headers:{...r.headers,Range:`bytes=${e}-${e+i-1}`}}),fetch(t,r)}function fo(t,e){return{...t,...e,headers:{...t.headers,...e.headers}}}function $r(t,e){const i=typeof t=="string"?new URL(t):t;i.pathname.endsWith("/")||(i.pathname+="/");const r=new URL(e.slice(1),i);return r.search=i.search,r}async function es(t){if(t.status!==404){if(t.status===200||t.status===206)return new Uint8Array(await t.arrayBuffer());throw new Error(`Unexpected response status ${t.status} ${t.statusText}`)}}async function uo(t,e,i,r){if(r)return fetch(t,{...i,headers:{...i.headers,Range:`bytes=-${e}`}});let s=await fetch(t,{...i,method:"HEAD"});if(!s.ok)return s;let n=s.headers.get("Content-Length"),a=Number(n);return nn(t,a-e,a,i)}class an{url;#e;#t;constructor(e,i={}){this.url=e,this.#e=i.overrides??{},this.#t=i.useSuffixRequest??!1}#i(e){return fo(this.#e,e)}async get(e,i={}){let r=$r(this.url,e).href,s=await fetch(r,this.#i(i));return es(s)}async getRange(e,i,r={}){let s=$r(this.url,e),n=this.#i(r),a;return"suffixLength"in i?a=await uo(s,i.suffixLength,n,this.#t):a=await nn(s,i.offset,i.length,n),es(a)}}class on{#e;constructor(e,i,r){typeof e=="number"?this.#e=new Uint8Array(e):e instanceof ArrayBuffer?this.#e=new Uint8Array(e,i,r):this.#e=new Uint8Array(Array.from(e,s=>s?1:0))}get BYTES_PER_ELEMENT(){return 1}get byteOffset(){return this.#e.byteOffset}get byteLength(){return this.#e.byteLength}get buffer(){return this.#e.buffer}get length(){return this.#e.length}get(e){let i=this.#e[e];return typeof i=="number"?i!==0:i}set(e,i){this.#e[e]=i?1:0}fill(e){this.#e.fill(e?1:0)}*[Symbol.iterator](){for(let e=0;e<this.length;e++)yield this.get(e)}}class gr{_data;chars;#e;constructor(e,i,r,s){if(this.chars=e,this.#e=new TextEncoder,typeof i=="number")this._data=new Uint8Array(i*e);else if(i instanceof ArrayBuffer)s&&(s=s*e),this._data=new Uint8Array(i,r,s);else{let n=Array.from(i);this._data=new Uint8Array(n.length*e);for(let a=0;a<n.length;a++)this.set(a,n[a])}}get BYTES_PER_ELEMENT(){return this.chars}get byteOffset(){return this._data.byteOffset}get byteLength(){return this._data.byteLength}get buffer(){return this._data.buffer}get length(){return this.byteLength/this.BYTES_PER_ELEMENT}get(e){const i=new Uint8Array(this.buffer,this.byteOffset+this.chars*e,this.chars);return new TextDecoder().decode(i).replace(/\x00/g,"")}set(e,i){const r=new Uint8Array(this.buffer,this.byteOffset+this.chars*e,this.chars);r.fill(0),r.set(this.#e.encode(i))}fill(e){const i=this.#e.encode(e);for(let r=0;r<this.length;r++)this._data.set(i,r*this.chars)}*[Symbol.iterator](){for(let e=0;e<this.length;e++)yield this.get(e)}}class Lt{#e;chars;constructor(e,i,r,s){if(this.chars=e,typeof i=="number")this.#e=new Int32Array(i*e);else if(i instanceof ArrayBuffer)s&&(s*=e),this.#e=new Int32Array(i,r,s);else{const n=i,a=new Lt(e,1);this.#e=new Int32Array((function*(){for(let o of n)a.set(0,o),yield*a.#e})())}}get BYTES_PER_ELEMENT(){return this.#e.BYTES_PER_ELEMENT*this.chars}get byteLength(){return this.#e.byteLength}get byteOffset(){return this.#e.byteOffset}get buffer(){return this.#e.buffer}get length(){return this.#e.length/this.chars}get(e){const i=this.chars*e;let r="";for(let s=0;s<this.chars;s++)r+=String.fromCodePoint(this.#e[i+s]);return r.replace(/\u0000/g,"")}set(e,i){const r=this.chars*e,s=this.#e.subarray(r,r+this.chars);s.fill(0);for(let n=0;n<this.chars;n++)s[n]=i.codePointAt(n)??0}fill(e){this.set(0,e);let i=this.#e.subarray(0,this.chars);for(let r=1;r<this.length;r++)this.#e.set(i,r*this.chars)}*[Symbol.iterator](){for(let e=0;e<this.length;e++)yield this.get(e)}}function kt(t){const e=new TextDecoder().decode(t);return JSON.parse(e)}function ts(t,e){const i=e/2,r=e-1;let s=0;for(let n=0;n<t.length;n+=e)for(let a=0;a<i;a+=1)s=t[n+a],t[n+a]=t[n+r-a],t[n+r-a]=s}function ln(t){if(t==="v2:object")return globalThis.Array;let e=t.match(/v2:([US])(\d+)/);if(e){let[,r,s]=e;return(r==="U"?Lt:gr).bind(null,Number(s))}let i={int8:Int8Array,int16:Int16Array,int32:Int32Array,int64:globalThis.BigInt64Array,uint8:Uint8Array,uint16:Uint16Array,uint32:Uint32Array,uint64:globalThis.BigUint64Array,float16:globalThis.Float16Array,float32:Float32Array,float64:Float64Array,bool:on}[t];return me(i,`Unknown or unsupported data_type: ${t}`),i}function rt(t,e){const i=t.length;typeof e=="string"&&(e=e==="C"?Array.from({length:i},(n,a)=>a):Array.from({length:i},(n,a)=>i-1-a)),me(i===e.length,"Order length must match the number of dimensions.");let r=1,s=new Array(i);for(let n=e.length-1;n>=0;n--)s[e[n]]=r,r*=t[e[n]];return s}function mo({name:t,configuration:e}){if(t==="default"){const i=e?.separator??"/";return r=>["c",...r].join(i)}if(t==="v2"){const i=e?.separator??".";return r=>r.join(i)||"0"}throw new Error(`Unknown chunk key encoding: ${t}`)}function po(t){if(t==="|O")return{data_type:"v2:object"};let e=t.match(/^([<|>])(.*)$/);me(e,`Invalid dtype: ${t}`);let[,i,r]=e,s={b1:"bool",i1:"int8",u1:"uint8",i2:"int16",u2:"uint16",i4:"int32",u4:"uint32",i8:"int64",u8:"uint64",f2:"float16",f4:"float32",f8:"float64"}[r]??(r.startsWith("S")||r.startsWith("U")?`v2:${r}`:void 0);return me(s,`Unsupported or unknown dtype: ${t}`),i==="|"?{data_type:s}:{data_type:s,endian:i==="<"?"little":"big"}}function go(t,e={}){let i=[],r=po(t.dtype);t.order==="F"&&i.push({name:"transpose",configuration:{order:"F"}}),"endian"in r&&r.endian==="big"&&i.push({name:"bytes",configuration:{endian:"big"}});for(let{id:s,...n}of t.filters??[])i.push({name:s,configuration:n});if(t.compressor){let{id:s,...n}=t.compressor;i.push({name:s,configuration:n})}return{zarr_format:3,node_type:"array",shape:t.shape,data_type:r.data_type,chunk_grid:{name:"regular",configuration:{chunk_shape:t.chunks}},chunk_key_encoding:{name:"v2",configuration:{separator:t.dimension_separator??"."}},codecs:i,fill_value:t.fill_value,attributes:e}}function Ao(t,e={}){return{zarr_format:3,node_type:"group",attributes:e}}function xo(t,e){if(e!=="number"&&e!=="bigint"&&e!=="boolean"&&e!=="object"&&e!=="string")return t===e;let i=t==="bool";if(e==="boolean")return i;let r=t.startsWith("v2:U")||t.startsWith("v2:S");if(e==="string")return r;let s=t==="int64"||t==="uint64";if(e==="bigint")return s;let n=t==="v2:object";return e==="object"?n:!r&&!s&&!i&&!n}function vo(t){return t?.name==="sharding_indexed"}function cn(t){return(t.data_type==="uint64"||t.data_type==="int64")&&t.fill_value!=null?BigInt(t.fill_value):t.fill_value}function hn(t,...e){if(!e.some(i=>t instanceof i))throw t}function me(t,e=""){if(!t)throw new Error(e)}async function dn(t,{format:e,signal:i}){const r=t instanceof Response?t:new Response(t);me(r.body,"Response does not contain body.");try{return await new Response(r.body.pipeThrough(new DecompressionStream(e),{signal:i})).arrayBuffer()}catch{throw i?.throwIfAborted(),new Error(`Failed to decode ${e}`)}}class Ar{kind="array_to_array";constructor(e,i){me(e.keepbits>=0,"keepbits must be zero or positive")}static fromConfig(e,i){return new Ar(e,i)}encode(e){throw new Error("`BitroundCodec.encode` is not implemented. Please open an issue at https://github.com/manzt/zarrita.js/issues.")}decode(e){return e}}const is=wo();function wo(){const t=new Uint32Array([305419896]);return new Uint8Array(t.buffer,t.byteOffset,t.byteLength)[0]!==18}function rs(t){return"BYTES_PER_ELEMENT"in t?t.BYTES_PER_ELEMENT:4}class xi{kind="array_to_bytes";#e;#t;#i;#s;#r;constructor(e,i){this.#r=e?.endian,this.#t=ln(i.data_type),this.#s=i.shape,this.#e=rt(i.shape,"C");const r=new this.#t(0);this.#i=r.BYTES_PER_ELEMENT}static fromConfig(e,i){return new xi(e,i)}encode(e){let i=new Uint8Array(e.data.buffer);return is&&this.#r==="big"&&ts(i,rs(this.#t)),i}decode(e){return is&&this.#r==="big"&&ts(e,rs(this.#t)),{data:new this.#t(e.buffer,e.byteOffset,e.byteLength/this.#i),shape:this.#s,stride:this.#e}}}class xr{kind="bytes_to_bytes";static fromConfig(){return new xr}encode(e){throw new Error("Not implemented")}decode(e){return new Uint8Array(e.buffer,e.byteOffset,e.byteLength-4)}}class vr{kind="bytes_to_bytes";static fromConfig(e){return new vr}encode(e){throw new Error("Gzip encoding is not enabled by default. Please register a custom codec with `numcodecs/gzip`.")}async decode(e){const i=await dn(e,{format:"gzip"});return new Uint8Array(i)}}function yo(t,e){return me(!Number.isNaN(e),"JsonCodec allow_nan is false but NaN was encountered during encoding."),me(e!==Number.POSITIVE_INFINITY,"JsonCodec allow_nan is false but Infinity was encountered during encoding."),me(e!==Number.NEGATIVE_INFINITY,"JsonCodec allow_nan is false but -Infinity was encountered during encoding."),e}function bo(t,e){return e instanceof Object&&!Array.isArray(e)?Object.keys(e).sort().reduce((i,r)=>(i[r]=e[r],i),{}):e}class wr{configuration;kind="array_to_bytes";#e;#t;constructor(e={}){this.configuration=e;const{encoding:i="utf-8",skipkeys:r=!1,ensure_ascii:s=!0,check_circular:n=!0,allow_nan:a=!0,sort_keys:o=!0,indent:l,strict:c=!0}=e;let h=e.separators;h||(l?h=[", ",": "]:h=[",",":"]),this.#e={encoding:i,skipkeys:r,ensure_ascii:s,check_circular:n,allow_nan:a,indent:l,separators:h,sort_keys:o},this.#t={strict:c}}static fromConfig(e){return new wr(e)}encode(e){const{indent:i,encoding:r,ensure_ascii:s,check_circular:n,allow_nan:a,sort_keys:o}=this.#e;me(r==="utf-8","JsonCodec does not yet support non-utf-8 encoding.");const l=[];me(n,"JsonCodec does not yet support skipping the check for circular references during encoding."),a||l.push(yo),o&&l.push(bo);const c=Array.from(e.data);c.push("|O"),c.push(e.shape);let h;l.length&&(h=(f,u)=>{let m=u;for(let p of l)m=p(f,m);return m});let d=JSON.stringify(c,h,i);return s&&(d=d.replace(/[\u007F-\uFFFF]/g,f=>{const u=`0000${f.charCodeAt(0).toString(16)}`;return`\\u${u.substring(u.length-4)}`})),new TextEncoder().encode(d)}decode(e){const{strict:i}=this.#t;me(i,"JsonCodec does not yet support non-strict decoding.");const r=kt(e),s=r.pop();r.pop(),me(s,"0D not implemented for JsonCodec.");const n=rt(s,"C");return{data:r,shape:s,stride:n}}}function ss(t){return t instanceof on||t instanceof gr||t instanceof Lt?new Proxy(t,{get(i,r){return i.get(Number(r))},set(i,r,s){return i.set(Number(r),s),!0}}):t}function Co(t,e){let i;return t.data instanceof gr||t.data instanceof Lt?i=new t.constructor(t.data.length,t.data.chars):i=new t.constructor(t.data.length),{data:i,shape:t.shape,stride:rt(t.shape,e)}}function Mo(t,e){let i=Co(t,e),r=t.shape.length,s=t.data.length,n=Array(r).fill(0),a=ss(t.data),o=ss(i.data);for(let l=0;l<s;l++){let c=0;for(let h=0;h<r;h++)c+=n[h]*i.stride[h];o[c]=a[l],n[0]+=1;for(let h=0;h<r;h++)if(n[h]===t.shape[h]){if(h+1===r)break;n[h]=0,n[h+1]+=1}}return i}function Do(t){let e=t.shape.length;return me(e===t.stride.length,"Shape and stride must have the same length."),t.stride.map((i,r)=>({stride:i,index:r})).sort((i,r)=>r.stride-i.stride).map(i=>i.index)}function To(t,e){let i=Do(t);return me(i.length===e.length,"Orders must match"),i.every((r,s)=>r===e[s])}class yr{kind="array_to_array";#e;#t;constructor(e,i){let r=e.order??"C",s=i.shape.length,n=new Array(s),a=new Array(s);if(r==="C")for(let o=0;o<s;++o)n[o]=o,a[o]=o;else if(r==="F")for(let o=0;o<s;++o)n[o]=s-o-1,a[o]=s-o-1;else n=r,n.forEach((o,l)=>{me(a[o]===void 0,`Invalid permutation: ${JSON.stringify(r)}`),a[o]=l});this.#e=n,this.#t=a}static fromConfig(e,i){return new yr(e,i)}encode(e){return To(e,this.#t)?e:Mo(e,this.#t)}decode(e){return{data:e.data,shape:e.shape,stride:rt(e.shape,this.#e)}}}class br{kind="array_to_bytes";#e;#t;constructor(e){this.#e=e,this.#t=rt(e,"C")}static fromConfig(e,i){return new br(i.shape)}encode(e){throw new Error("Method not implemented.")}decode(e){let i=new TextDecoder,r=new DataView(e.buffer),s=Array(r.getUint32(0,!0)),n=4;for(let a=0;a<s.length;a++){let o=r.getUint32(n,!0);n+=4,s[a]=i.decode(e.buffer.slice(n,n+o)),n+=o}return{data:s,shape:this.#e,stride:this.#t}}}class Cr{kind="bytes_to_bytes";static fromConfig(e){return new Cr}encode(e){throw new Error("Zlib encoding is not enabled by default. Please register a codec with `numcodecs/zlib`.")}async decode(e){const i=await dn(e,{format:"deflate"});return new Uint8Array(i)}}function So(){return new Map().set("blosc",()=>Mi(()=>import("./blosc-CrUiACa7.js"),__vite__mapDeps([0,1]),import.meta.url).then(t=>t.default)).set("lz4",()=>Mi(()=>import("./lz4-B_Exjfmr.js"),__vite__mapDeps([2,1]),import.meta.url).then(t=>t.default)).set("zstd",()=>Mi(()=>import("./zstd-u5eweWyS.js"),__vite__mapDeps([3,1]),import.meta.url).then(t=>t.default)).set("gzip",()=>vr).set("zlib",()=>Cr).set("transpose",()=>yr).set("bytes",()=>xi).set("crc32c",()=>xr).set("vlen-utf8",()=>br).set("json2",()=>wr).set("bitround",()=>Ar)}const Eo=So();function Zi(t){let e;return{async encode(i){e||(e=await ns(t));for(const s of e.array_to_array)i=await s.encode(i);let r=await e.array_to_bytes.encode(i);for(const s of e.bytes_to_bytes)r=await s.encode(r);return r},async decode(i){e||(e=await ns(t));for(let s=e.bytes_to_bytes.length-1;s>=0;s--)i=await e.bytes_to_bytes[s].decode(i);let r=await e.array_to_bytes.decode(i);for(let s=e.array_to_array.length-1;s>=0;s--)r=await e.array_to_array[s].decode(r);return r}}}async function ns(t){let e=t.codecs.map(async n=>{let a=await Eo.get(n.name)?.();return me(a,`Unknown codec: ${n.name}`),{Codec:a,meta:n}}),i=[],r,s=[];for await(let{Codec:n,meta:a}of e){let o=n.fromConfig(a.configuration,t);switch(o.kind){case"array_to_array":i.push(o);break;case"array_to_bytes":r=o;break;default:s.push(o)}}return r||(me(Io(t),`Cannot encode ${t.data_type} to bytes without a codec`),r=xi.fromConfig({endian:"little"},t)),{array_to_array:i,array_to_bytes:r,bytes_to_bytes:s}}function Io(t){return t.data_type!=="v2:object"}class Ot extends Error{constructor(e,i={}){super(`Node not found: ${e}`,i),this.name="NodeNotFoundError"}}class Mr extends Error{constructor(e){super(`Missing key: ${e}`),this.name="KeyError"}}const as=18446744073709551615n;function Fo(t,e,i,r){me(t.store.getRange,"Store does not support range requests");let s=t.store.getRange.bind(t.store),n=e.map((l,c)=>l/r.chunk_shape[c]),a=Zi({data_type:"uint64",shape:[...n,2],codecs:r.index_codecs}),o={};return async l=>{let c=l.map((A,y)=>Math.floor(A/n[y])),h=t.resolve(i(c)).path,d;if(h in o)d=o[h];else{let A=4,y=16*n.reduce((b,w)=>b*w,1),v=await s(h,{suffixLength:y+A});d=o[h]=v?await a.decode(v):null}if(d===null)return;let{data:f,shape:u,stride:m}=d,p=l.map((A,y)=>A%u[y]).reduce((A,y,v)=>A+y*m[v],0),g=f[p],x=f[p+1];if(!(g===as&&x===as))return s(h,{offset:Number(g),length:Number(x)})}}class nt{store;path;constructor(e,i="/"){this.store=e,this.path=i}resolve(e){let i=new URL(`file://${this.path.endsWith("/")?this.path:`${this.path}/`}`);return new nt(this.store,decodeURIComponent(new URL(e,i).pathname))}}function ji(t){return new nt(t??new Map)}class Dr extends nt{kind="group";#e;constructor(e,i,r){super(e,i),this.#e=r}get attrs(){return this.#e.attributes}}function os(t){return t.find(i=>i.name==="transpose")?.configuration?.order??"C"}const yt=Symbol("zarrita.context");function Bo(t){return t[yt]}function Uo(t,e){let{configuration:i}=e.codecs.find(vo)??{},r={encode_chunk_key:mo(e.chunk_key_encoding),TypedArray:ln(e.data_type),fill_value:e.fill_value};if(i){let n=os(i.codecs);return{...r,kind:"sharded",chunk_shape:i.chunk_shape,codec:Zi({data_type:e.data_type,shape:i.chunk_shape,codecs:i.codecs}),get_strides(a){return rt(a,n)},get_chunk_bytes:Fo(t,e.chunk_grid.configuration.chunk_shape,r.encode_chunk_key,i)}}let s=os(e.codecs);return{...r,kind:"regular",chunk_shape:e.chunk_grid.configuration.chunk_shape,codec:Zi({data_type:e.data_type,shape:e.chunk_grid.configuration.chunk_shape,codecs:e.codecs}),get_strides(n){return rt(n,s)},async get_chunk_bytes(n,a){let o=r.encode_chunk_key(n),l=t.resolve(o).path;return t.store.get(l,a)}}}let fi=class extends nt{kind="array";#e;[yt];constructor(e,i,r){super(e,i),this.#e={...r,fill_value:cn(r)},this[yt]=Uo(this,r)}get attrs(){return this.#e.attributes}get shape(){return this.#e.shape}get chunks(){return this[yt].chunk_shape}get dtype(){return this.#e.data_type}async getChunk(e,i){let r=this[yt],s=await r.get_chunk_bytes(e,i);if(!s){let n=r.chunk_shape.reduce((o,l)=>o*l,1),a=new r.TypedArray(n);return a.fill(r.fill_value),{data:a,shape:r.chunk_shape,stride:r.get_strides(r.chunk_shape)}}return r.codec.decode(s)}is(e){return xo(this.dtype,e)}};function*Ro(t,e,i=1){e===void 0&&(e=t,t=0);for(let r=t;r<e;r+=i)yield r}function*Vo(...t){if(t.length===0)return;const e=t.map(r=>r[Symbol.iterator]()),i=e.map(r=>r.next());if(i.some(r=>r.done))throw new Error("Input contains an empty iterator.");for(let r=0;;){if(i[r].done){if(e[r]=t[r][Symbol.iterator](),i[r]=e[r].next(),++r>=e.length)return}else yield i.map(({value:s})=>s),r=0;i[r]=e[r].next()}}function Po({start:t,stop:e,step:i},r){if(i===0)throw new Error("slice step cannot be zero");i=i??1;const s=i<0,[n,a]=s?[-1,r-1]:[0,r];return t===null?t=s?a:n:t<0?(t+=r,t<n&&(t=n)):t>a&&(t=a),e===null?e=s?n:a:e<0?(e+=r,e<n&&(e=n)):e>a&&(e=a),[t,e,i]}function we(t,e,i=null){return e===void 0&&(e=t,t=null),{start:t,stop:e,step:i}}function No(){const t=[];return{add:e=>t.push(e()),onIdle:()=>Promise.all(t)}}class Tr extends Error{constructor(e){super(e),this.name="IndexError"}}function Lo(t,e){throw new Tr(`too many indicies for array; expected ${e.length}, got ${t.length}`)}function ko(t){throw new Tr(`index out of bounds for dimension with length ${t}`)}function Oo(){throw new Tr("only slices with step >= 1 are supported")}function zo(t,e){t.length>e.length&&Lo(t,e)}function Go(t,e){return t=Math.trunc(t),t<0&&(t=e+t),(t>=e||t<0)&&ko(e),t}class Yo{dim_sel;dim_len;dim_chunk_len;nitems;constructor({dim_sel:e,dim_len:i,dim_chunk_len:r}){e=Go(e,i),this.dim_sel=e,this.dim_len=i,this.dim_chunk_len=r,this.nitems=1}*[Symbol.iterator](){const e=Math.floor(this.dim_sel/this.dim_chunk_len),i=e*this.dim_chunk_len,r=this.dim_sel-i;yield{dim_chunk_ix:e,dim_chunk_sel:r}}}class ls{start;stop;step;dim_len;dim_chunk_len;nitems;nchunks;constructor({dim_sel:e,dim_len:i,dim_chunk_len:r}){const[s,n,a]=Po(e,i);this.start=s,this.stop=n,this.step=a,this.step<1&&Oo(),this.dim_len=i,this.dim_chunk_len=r,this.nitems=Math.max(0,Math.ceil((this.stop-this.start)/this.step)),this.nchunks=Math.ceil(this.dim_len/this.dim_chunk_len)}*[Symbol.iterator](){const e=Math.floor(this.start/this.dim_chunk_len),i=Math.ceil(this.stop/this.dim_chunk_len);for(const r of Ro(e,i)){const s=r*this.dim_chunk_len,n=Math.min(this.dim_len,(r+1)*this.dim_chunk_len),a=n-s;let o=0,l=0;if(this.start<s){const u=(s-this.start)%this.step;u&&(l+=this.step-u),o=Math.ceil((s-this.start)/this.step)}else l=this.start-s;const c=this.stop>n?a:this.stop-s,h=[l,c,this.step],d=Math.ceil((c-l)/this.step),f=[o,o+d,1];yield{dim_chunk_ix:r,dim_chunk_sel:h,dim_out_sel:f}}}}function Xo(t,e){let i=[];return t===null?i=e.map(r=>we(null)):Array.isArray(t)&&(i=t.map(r=>r??we(null))),zo(i,e),i}class Wo{dim_indexers;shape;constructor({selection:e,shape:i,chunk_shape:r}){this.dim_indexers=Xo(e,i).map((s,n)=>new(typeof s=="number"?Yo:ls)({dim_sel:s,dim_len:i[n],dim_chunk_len:r[n]})),this.shape=this.dim_indexers.filter(s=>s instanceof ls).map(s=>s.nitems)}*[Symbol.iterator](){for(const e of Vo(...this.dim_indexers)){const i=e.map(s=>s.dim_chunk_ix),r=e.map(s=>"dim_out_sel"in s?{from:s.dim_chunk_sel,to:s.dim_out_sel}:{from:s.dim_chunk_sel,to:null});yield{chunk_coords:i,mapping:r}}}}function Ko(t,e){return"get"in t?t.get(e):t[e]}async function Ho(t,e,i,r){let s=Bo(t),n=new Wo({selection:e,shape:t.shape,chunk_shape:t.chunks}),a=r.prepare(new s.TypedArray(n.shape.reduce((l,c)=>l*c,1)),n.shape,s.get_strides(n.shape)),o=i.create_queue?.()??No();for(const{chunk_coords:l,mapping:c}of n)o.add(async()=>{let{data:h,shape:d,stride:f}=await t.getChunk(l,i.opts),u=r.prepare(h,d,f);r.set_from_chunk(a,u,c)});return await o.onIdle(),n.shape.length===0?Ko(a.data,0):a}function Sr(t,e=0,i){let r=i??t.length-e;return{length:r,subarray(s,n=r){return Sr(t,e+s,n-s)},set(s,n=0){for(let a=0;a<s.length;a++)t[e+n+a]=s.get(a)},get(s){return t[e+s]}}}function Ii(t){return globalThis.Array.isArray(t.data)?{data:Sr(t.data),stride:t.stride,bytes_per_element:1}:{data:new Uint8Array(t.data.buffer,t.data.byteOffset,t.data.byteLength),stride:t.stride,bytes_per_element:t.data.BYTES_PER_ELEMENT}}function qo(t){return"chars"in t?t.constructor.bind(null,t.chars):t.constructor}function Qo(t,e){if(globalThis.Array.isArray(t.data))return Sr([e]);let i=qo(t.data),r=new i([e]);return new Uint8Array(r.buffer,r.byteOffset,r.byteLength)}const Zo={prepare(t,e,i){return{data:t,shape:e,stride:i}},set_scalar(t,e,i){let r=Ii(t);Ji(r,e,Qo(t,i),r.bytes_per_element)},set_from_chunk(t,e,i){let r=Ii(t);ti(r,Ii(e),r.bytes_per_element,i)}};async function _i(t,e=null,i={}){return Ho(t,e,i,Zo)}function fn(t,e,i){return i<0&&e<t?Math.floor((t-e-1)/-i)+1:t<e?Math.floor((e-t-1)/i)+1:0}function Ji(t,e,i,r){if(e.length===0){t.data.set(i,0);return}const[s,...n]=e,[a,...o]=t.stride;if(typeof s=="number"){const f=t.data.subarray(a*s*r);Ji({data:f,stride:o},n,i,r);return}const[l,c,h]=s,d=fn(l,c,h);if(n.length===0){for(let f=0;f<d;f++)t.data.set(i,a*(l+h*f)*r);return}for(let f=0;f<d;f++){const u=t.data.subarray(a*(l+h*f)*r);Ji({data:u,stride:o},n,i,r)}}function ti(t,e,i,r){const[s,...n]=r,[a,...o]=t.stride,[l,...c]=e.stride;if(s.from===null){if(n.length===0){t.data.set(e.data.subarray(0,i),s.to*i);return}ti({data:t.data.subarray(a*s.to*i),stride:o},e,i,n);return}if(s.to===null){if(n.length===0){let x=s.from*i;t.data.set(e.data.subarray(x,x+i),0);return}ti(t,{data:e.data.subarray(l*s.from*i),stride:c},i,n);return}const[h,d,f]=s.to,[u,m,p]=s.from,g=fn(h,d,f);if(n.length===0){if(f===1&&p===1&&a===1&&l===1){let x=u*i,A=g*i;t.data.set(e.data.subarray(x,x+A),h*i);return}for(let x=0;x<g;x++){let A=l*(u+p*x)*i;t.data.set(e.data.subarray(A,A+i),a*(h+f*x)*i)}return}for(let x=0;x<g;x++)ti({data:t.data.subarray(a*(h+x*f)*i),stride:o},{data:e.data.subarray(l*(u+x*p)*i),stride:c},i,n)}let vi=jo();function jo(){let t=new WeakMap;function e(i){let r=t.get(i)??{v2:0,v3:0};return t.set(i,r),r}return{increment(i,r){e(i)[r]+=1},version_max(i){let r=e(i);return r.v3>r.v2?"v3":"v2"}}}async function _o(t){let e=await t.store.get(t.resolve(".zattrs").path);return e?kt(e):{}}async function Jo(t,e={}){let i="store"in t?t:new nt(t),r={};return(e.attrs??!0)&&(r=await _o(i)),e.kind==="array"?cs(i,r):e.kind==="group"?hs(i,r):cs(i,r).catch(s=>(hn(s,Ot),hs(i,r)))}async function cs(t,e){let{path:i}=t.resolve(".zarray"),r=await t.store.get(i);if(!r)throw new Ot("v2 array",{cause:new Mr(i)});return vi.increment(t.store,"v2"),new fi(t.store,t.path,go(kt(r),e))}async function hs(t,e){let{path:i}=t.resolve(".zgroup"),r=await t.store.get(i);if(!r)throw new Ot("v2 group",{cause:new Mr(i)});return vi.increment(t.store,"v2"),new Dr(t.store,t.path,Ao(kt(r),e))}async function $o(t){let{store:e,path:i}=t.resolve("zarr.json"),r=await t.store.get(i);if(!r)throw new Ot("v3 array or group",{cause:new Mr(i)});let s=kt(r);return s.node_type==="array"&&(s.fill_value=cn(s)),s.node_type==="array"?new fi(e,t.path,s):new Dr(e,t.path,s)}async function el(t,e={}){let i="store"in t?t:new nt(t),r=await $o(i);if(vi.increment(i.store,"v3"),e.kind===void 0||e.kind==="array"&&r instanceof fi||e.kind==="group"&&r instanceof Dr)return r;let s=r instanceof fi?"array":"group";throw new Error(`Expected node of kind ${e.kind}, found ${s}.`)}async function De(t,e={}){let i="store"in t?t.store:t,r=vi.version_max(i),s=r==="v2"?De.v2:De.v3,n=r==="v2"?De.v3:De.v2;return s(t,e).catch(a=>(hn(a,Ot),n(t,e)))}De.v2=Jo;De.v3=el;const tl=-1,il=0,rl=1,sl=2,nl=3,al=4,ol=5,ll=6,cl=7,hl=8,dl=typeof self=="object"?self:globalThis,ds=(t,e)=>{switch(t){case"Function":case"SharedWorker":case"Worker":case"eval":case"setInterval":case"setTimeout":throw new TypeError("unable to deserialize "+t)}return new dl[t](e)},fl=(t,e)=>{const i=(s,n)=>(t.set(n,s),s),r=s=>{if(t.has(s))return t.get(s);const[n,a]=e[s];switch(n){case il:case tl:return i(a,s);case rl:{const o=i([],s);for(const l of a)o.push(r(l));return o}case sl:{const o=i({},s);for(const[l,c]of a)o[r(l)]=r(c);return o}case nl:return i(new Date(a),s);case al:{const{source:o,flags:l}=a;return i(new RegExp(o,l),s)}case ol:{const o=i(new Map,s);for(const[l,c]of a)o.set(r(l),r(c));return o}case ll:{const o=i(new Set,s);for(const l of a)o.add(r(l));return o}case cl:{const{name:o,message:l}=a;return i(ds(o,l),s)}case hl:return i(BigInt(a),s);case"BigInt":return i(Object(BigInt(a)),s);case"ArrayBuffer":return i(new Uint8Array(a).buffer,a);case"DataView":{const{buffer:o}=new Uint8Array(a);return i(new DataView(o),a)}}return i(ds(n,a),s)};return r},ul=t=>fl(new Map,t)(0);var un=Object.defineProperty,mn=t=>{throw TypeError(t)},ml=(t,e,i)=>e in t?un(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i,be=(t,e)=>{for(var i in e)un(t,i,{get:e[i],enumerable:!0})},D=(t,e,i)=>ml(t,typeof e!="symbol"?e+"":e,i),pn=(t,e,i)=>e.has(t)||mn("Cannot "+i),X=(t,e,i)=>(pn(t,e,"read from private field"),i?i.call(t):e.get(t)),lt=(t,e,i)=>e.has(t)?mn("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,i),Ke=(t,e,i,r)=>(pn(t,e,"write to private field"),e.set(t,i),i),pl={version:"0.69.0"},$={TEXTURE0_BACK_VOL:33984,TEXTURE1_COLORMAPS:33985,TEXTURE2_OVERLAY_VOL:33986,TEXTURE3_FONT:33987,TEXTURE5_MATCAP:33989,TEXTURE6_GRADIENT:33990,TEXTURE7_DRAW:33991,TEXTURE8_PAQD:33992,TEXTURE10_DRAW_SMOOTH:33994,TEXTURE9_ORIENT:33993,TEXTURE11_GC_BACK:33995,TEXTURE12_GC_STRENGTH0:33996,TEXTURE13_GC_STRENGTH1:33997,TEXTURE14_GC_LABEL0:33998,TEXTURE15_GC_LABEL1:33999},gl=new Float32Array([-1,-1,-1,.28,.28,.28,-1,-1,-1,.28,.28,.28,-1,1,-1,.28,.28,.28,1,-1,-1,.28,.28,.28,1,1,-1,.28,.28,.28,1,1,-1,.28,.28,.28,-1,-1,1,.8,.8,.8,-1,-1,1,.8,.8,.8,1,-1,1,.8,.8,.8,-1,1,1,.8,.8,.8,1,1,1,.8,.8,.8,1,1,1,.8,.8,.8,-1,1,-1,0,0,.74,-1,1,-1,0,0,.74,-1,1,1,0,0,.74,1,1,-1,0,0,.74,1,1,1,0,0,.74,1,1,1,0,0,.74,-1,-1,-1,.42,0,.42,-1,-1,-1,.42,0,.42,1,-1,-1,.42,0,.42,-1,-1,1,.42,0,.42,1,-1,1,.42,0,.42,1,-1,1,.42,0,.42,-1,-1,-1,.64,0,0,-1,-1,-1,.64,0,0,-1,-1,1,.64,0,0,-1,1,-1,.64,0,0,-1,1,1,.64,0,0,-1,1,1,.64,0,0,1,-1,-1,0,.5,0,1,-1,-1,0,.5,0,1,1,-1,0,.5,0,1,-1,1,0,.5,0,1,1,1,0,.5,0,1,1,1,0,.5,0,-.45,1,-.8,0,0,0,-.45,1,-.8,0,0,0,-.45,1,.8,0,0,0,-.25,1,-.8,0,0,0,-.25,1,.8,0,0,0,-.25,1,.8,0,0,0,-.25,1,.6,0,0,0,-.25,1,.6,0,0,0,-.25,1,.8,0,0,0,.45,1,.6,0,0,0,.25,1,.8,0,0,0,.25,1,.8,0,0,0,.25,1,.1,0,0,0,.25,1,.1,0,0,0,.25,1,.6,0,0,0,.45,1,.1,0,0,0,.45,1,.6,0,0,0,.45,1,.6,0,0,0,-.25,1,-.1,0,0,0,-.25,1,-.1,0,0,0,-.25,1,.1,0,0,0,.25,1,-.1,0,0,0,.45,1,.1,0,0,0,.45,1,.1,0,0,0,.45,-1,-.8,0,0,0,.45,-1,-.8,0,0,0,.05,-1,.8,0,0,0,.25,-1,-.8,0,0,0,-.15,-1,.8,0,0,0,-.15,-1,.8,0,0,0,-.25,-1,-.8,0,0,0,-.25,-1,-.8,0,0,0,.05,-1,.8,0,0,0,-.45,-1,-.8,0,0,0,-.15,-1,.8,0,0,0,-.15,-1,.8,0,0,0,.13,-1,-.3,0,0,0,.13,-1,-.3,0,0,0,.07,-1,-.1,0,0,0,-.33,-1,-.3,0,0,0,-.27,-1,-.1,0,0,0,-.27,-1,-.1,0,0,0,-.45,.6,1,0,0,0,-.45,.6,1,0,0,0,-.45,.4,1,0,0,0,-.25,.8,1,0,0,0,-.25,.4,1,0,0,0,-.25,.4,1,0,0,0,-.25,.8,1,0,0,0,-.25,.8,1,0,0,0,-.25,.6,1,0,0,0,.25,.8,1,0,0,0,.45,.6,1,0,0,0,.45,.6,1,0,0,0,.25,.8,1,0,0,0,.25,.8,1,0,0,0,.25,-.1,1,0,0,0,.45,.6,1,0,0,0,.45,.1,1,0,0,0,.45,.1,1,0,0,0,-.25,.1,1,0,0,0,-.25,.1,1,0,0,0,-.45,-.1,1,0,0,0,.25,.1,1,0,0,0,.25,-.1,1,0,0,0,.25,-.1,1,0,0,0,-.45,-.1,1,0,0,0,-.45,-.1,1,0,0,0,-.45,-.6,1,0,0,0,-.25,-.1,1,0,0,0,-.25,-.8,1,0,0,0,-.25,-.8,1,0,0,0,-.25,-.6,1,0,0,0,-.25,-.6,1,0,0,0,-.25,-.8,1,0,0,0,.45,-.6,1,0,0,0,.25,-.8,1,0,0,0,.25,-.8,1,0,0,0,.25,-.4,1,0,0,0,.25,-.4,1,0,0,0,.25,-.6,1,0,0,0,.45,-.4,1,0,0,0,.45,-.6,1,0,0,0,.45,-.6,1,0,0,0,-.1,-.8,-1,0,0,0,-.1,-.8,-1,0,0,0,-.1,.8,-1,0,0,0,.1,-.8,-1,0,0,0,.1,.8,-1,0,0,0,.1,.8,-1,0,0,0,-1,-.45,-.8,0,0,0,-1,-.45,-.8,0,0,0,-1,-.45,.8,0,0,0,-1,-.25,-.8,0,0,0,-1,-.25,.8,0,0,0,-1,-.25,.8,0,0,0,-1,-.25,-.8,0,0,0,-1,-.25,-.8,0,0,0,-1,-.25,-.6,0,0,0,-1,.45,-.8,0,0,0,-1,.45,-.6,0,0,0,-1,.45,-.6,0,0,0,1,.45,-.8,0,0,0,1,.45,-.8,0,0,0,1,.45,.8,0,0,0,1,.25,-.8,0,0,0,1,.25,.8,0,0,0,1,.25,.8,0,0,0,1,.25,.6,0,0,0,1,.25,.6,0,0,0,1,.25,.8,0,0,0,1,-.45,.6,0,0,0,1,-.25,.8,0,0,0,1,-.25,.8,0,0,0,1,-.25,.1,0,0,0,1,-.25,.1,0,0,0,1,-.25,.6,0,0,0,1,-.45,.1,0,0,0,1,-.45,.6,0,0,0,1,-.45,.6,0,0,0,1,.25,-.1,0,0,0,1,.25,-.1,0,0,0,1,.25,.1,0,0,0,1,-.25,-.1,0,0,0,1,-.45,.1,0,0,0,1,-.45,.1,0,0,0,1,-.25,-.8,0,0,0,1,-.25,-.8,0,0,0,1,-.05,-.1,0,0,0,1,-.45,-.8,0,0,0,1,-.25,-.1,0,0,0,1,-.25,-.1,0,0,0]),ie=class{constructor(e,i,r,s,n=null,a=null){D(this,"sphereIdx",[]),D(this,"sphereVtx",[]),D(this,"renderShaders",[]),D(this,"isVisible",!0),D(this,"isPickable",!0),D(this,"vertexBuffer"),D(this,"indexCount"),D(this,"indexBuffer"),D(this,"vao"),D(this,"mode"),D(this,"glFlags",0),D(this,"id"),D(this,"colorId"),D(this,"modelMatrix",J()),D(this,"scale",[1,1,1]),D(this,"position",[0,0,0]),D(this,"rotation",[0,0,0]),D(this,"rotationRadians",0),D(this,"extentsMin",[]),D(this,"extentsMax",[]),D(this,"furthestVertexFromOrigin"),D(this,"originNegate"),D(this,"fieldOfViewDeObliqueMM"),D(this,"mm"),this.vertexBuffer=i,this.indexCount=s,this.indexBuffer=n,this.vao=a,this.mode=r,this.id=e,this.colorId=[(e>>0&255)/255,(e>>8&255)/255,(e>>16&255)/255,(e>>24&255)/255]}};D(ie,"BLEND",1);D(ie,"CULL_FACE",2);D(ie,"CULL_FRONT",4);D(ie,"CULL_BACK",8);D(ie,"ENABLE_DEPTH_TEST",16);D(ie,"generateCrosshairs",function(t,e,i,r,s,n,a=20,o=0){const l=ie.generateCrosshairsGeometry(t,i,r,s,n,a,o);return new ie(e,l.vertexBuffer,t.TRIANGLES,l.indexCount,l.indexBuffer,l.vao)});D(ie,"generateCrosshairsGeometry",function(t,e,i,r,s,n=20,a=0){const o=[],l=[],c=s*a;if(c<=0){let u=k(i[0],e[1],e[2]),m=k(r[0],e[1],e[2]);ie.makeCylinder(o,l,u,m,s,n),u=k(e[0],i[1],e[2]),m=k(e[0],r[1],e[2]),ie.makeCylinder(o,l,u,m,s,n),u=k(e[0],e[1],i[2]),m=k(e[0],e[1],r[2]),ie.makeCylinder(o,l,u,m,s,n)}else{let u=k(i[0],e[1],e[2]),m=k(e[0]-c,e[1],e[2]);ie.makeCylinder(o,l,u,m,s,n,!1),u=k(e[0]+c,e[1],e[2]),m=k(r[0],e[1],e[2]),ie.makeCylinder(o,l,u,m,s,n,!1),u=k(e[0],i[1],e[2]),m=k(e[0],e[1]-c,e[2]),ie.makeCylinder(o,l,u,m,s,n,!1),u=k(e[0],e[1]+c,e[2]),m=k(e[0],r[1],e[2]),ie.makeCylinder(o,l,u,m,s,n,!1),u=k(e[0],e[1],i[2]),m=k(e[0],e[1],e[2]-c),ie.makeCylinder(o,l,u,m,s,n,!1),u=k(e[0],e[1],e[2]+c),m=k(e[0],e[1],r[2]),ie.makeCylinder(o,l,u,m,s,n,!1)}const h=t.createBuffer();if(h===null)throw new Error("could not instantiate vertex buffer");t.bindBuffer(t.ARRAY_BUFFER,h),t.bufferData(t.ARRAY_BUFFER,new Float32Array(o),t.STATIC_DRAW);const d=t.createBuffer();if(d===null)throw new Error("could not instantiate index buffer");t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,d),t.bufferData(t.ELEMENT_ARRAY_BUFFER,new Uint32Array(l),t.STATIC_DRAW);const f=t.createVertexArray();return t.bindVertexArray(f),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,d),t.bindBuffer(t.ARRAY_BUFFER,h),t.enableVertexAttribArray(0),t.vertexAttribPointer(0,3,t.FLOAT,!1,0,0),t.bindVertexArray(null),{vertexBuffer:h,indexBuffer:d,indexCount:l.length,vao:f}});D(ie,"getFirstPerpVector",function(t){const e=k(0,0,0);return t[0]===0?e[0]=1:t[1]===0?e[1]=1:t[2]===0?e[2]=1:(e[0]=t[2],e[1]=t[2],e[2]=-(t[0]+t[1]),Ie(e,e)),e});D(ie,"subdivide",function(t,e){let i=t.length/3,r=e.length/3;const s=r,n=se(),a=se();for(let o=0;o<s;o++){const l=e[o*3+0],c=e[o*3+1],h=e[o*3+2],d=k(t[l*3+0],t[l*3+1],t[l*3+2]),f=k(t[c*3+0],t[c*3+1],t[c*3+2]),u=k(t[h*3+0],t[h*3+1],t[h*3+2]);it(n,d,f),Ie(a,n),t.push(...a),it(n,f,u),Ie(a,n),t.push(...a),it(n,d,u),Ie(a,n),t.push(...a);let m=[i,i+1,i+2];e.push(...m),m=[l,i,i+2],e.push(...m),m=[i,c,i+1],e.push(...m),e[o*3+0]=i+2,e[o*3+1]=i+1,e[o*3+2]=h,r=r+3,i=i+3}});D(ie,"weldVertices",function(t,e){const i=t.length/3;let r=0;const s=new Int32Array(i);for(let o=0;o<i-1;o++){if(s[o]!==0)continue;s[o]=r;let l=o*3;const c=t[l],h=t[l+1],d=t[l+2];for(let f=o+1;f<i;f++)l+=3,c===t[l]&&h===t[l+1]&&d===t[l+2]&&(s[f]=r);r++}if(r===i)return t;const n=e.length;for(let o=0;o<n;o++)e[o]=s[e[o]];const a=t.slice(0,r*3-1);for(let o=0;o<i-1;o++){const l=o*3,c=s[o]*3;a[c]=t[l],a[c+1]=t[l+1],a[c+2]=t[l+2]}return a});D(ie,"makeSphere",function(t,e,i,r=[0,0,0]){let s=[0,0,1,.894,0,.447,.276,.851,.447,-.724,.526,.447,-.724,-.526,.447,.276,-.851,.447,.724,.526,-.447,-.276,.851,-.447,-.894,0,-.447,-.276,-.851,-.447,.724,-.526,-.447,0,0,-1];const n=[0,1,2,0,2,3,0,3,4,0,4,5,0,5,1,7,6,11,8,7,11,9,8,11,10,9,11,6,10,11,6,2,1,7,3,2,8,4,3,9,5,4,10,1,5,6,7,2,7,8,3,8,9,4,9,10,5,10,6,1];ie.subdivide(s,n),ie.subdivide(s,n),s=ie.weldVertices(s,n);for(let c=0;c<s.length;c++)s[c]=s[c]*i;const a=s.length/3;let o=0;for(let c=0;c<a;c++)s[o]=s[o]+r[0],o++,s[o]=s[o]+r[1],o++,s[o]=s[o]+r[2],o++;const l=Math.floor(t.length/3);for(let c=0;c<n.length;c++)n[c]=n[c]+l;e.push(...n),t.push(...s)});D(ie,"makeCylinder",function(t,e,i,r,s,n=20,a=!0){n<3&&(n=3);const o=se();ne(o,r,i),Ie(o,o);const l=ie.getFirstPerpVector(o),c=se();Jt(c,o,l),Ie(c,c);let h=2*n,d=2*n;a&&(d+=2*n,h+=2);const f=Math.floor(t.length/3),u=new Uint32Array(d*3),m=new Float32Array(h*3);function p(b,w){m[b*3+0]=w[0],m[b*3+1]=w[1],m[b*3+2]=w[2]}function g(b,w,C,M){u[b*3+0]=w+f,u[b*3+1]=C+f,u[b*3+2]=M+f}const x=2*n,A=x+1;a&&(p(x,i),p(A,r));const y=se(),v=se();for(let b=0;b<n;b++){const w=Math.cos(b/n*2*Math.PI),C=Math.sin(b/n*2*Math.PI);y[0]=s*(w*l[0]+C*c[0]),y[1]=s*(w*l[1]+C*c[1]),y[2]=s*(w*l[2]+C*c[2]),it(v,i,y),p(b,v),it(v,r,y),p(b+n,v);let M=0;b<n-1&&(M=b+1),g(b*2,b,M,b+n),g(b*2+1,M,M+n,b+n),a&&(g(n*2+b,b,x,M),g(n*2+b+n,A,b+n,M+n))}e.push(...u),t.push(...m)});D(ie,"makeColoredCylinder",function(t,e,i,r,s,n,a=[192,0,0,255],o=20,l=!1){let c=t.length/3;ie.makeCylinder(t,e,r,s,n,o,l),c=t.length/3-c;const h=[];for(let d=0;d<c*4-1;d+=4)h[d]=a[0],h[d+1]=a[1],h[d+2]=a[2],h[d+3]=a[3];i.push(...h)});D(ie,"makeColoredSphere",function(t,e,i,r,s=[0,0,0],n=[0,0,192,255]){let a=t.length/3;ie.makeSphere(t,e,r,s),a=t.length/3-a;const o=[];for(let l=0;l<a*4-1;l+=4)o[l]=n[0],o[l+1]=n[1],o[l+2]=n[2],o[l+3]=n[3];i.push(...o)});var st=ie,gn=class Ue{constructor({name:e="niivue",level:i="info"}={}){D(this,"level"),D(this,"name"),this.name=`${e}`,this.level=i}debug(...e){Ue.levels[this.level]>Ue.levels.debug||console.debug(`${this.name}-debug`,...e)}info(...e){Ue.levels[this.level]>Ue.levels.info||console.info(`${this.name}-info`,...e)}warn(...e){Ue.levels[this.level]>Ue.levels.warn||console.warn(`${this.name}-warn`,...e)}error(...e){Ue.levels[this.level]>Ue.levels.error||console.error(`${this.name}-error`,...e)}fatal(...e){Ue.levels[this.level]>Ue.levels.fatal||console.error(`${this.name}-fatal`,...e)}setLogLevel(e){this.level=e}setName(e){this.name=e}};D(gn,"levels",{debug:0,info:1,warn:2,error:3,fatal:4,silent:1/0});var Al=gn,F=new Al({name:"niivue",level:"info"}),ii={};be(ii,{$itksnap:()=>xl,$slicer3d:()=>vl,actc:()=>wl,afni_blues_inv:()=>Rc,afni_reds_inv:()=>Vc,batlow:()=>yl,bcgwhw:()=>Cl,bcgwhw_dark:()=>bl,blue:()=>El,blue2cyan:()=>Tl,blue2magenta:()=>Dl,blue2red:()=>Ml,bluegrn:()=>Sl,bone:()=>Il,bronze:()=>Fl,cet_l17:()=>Bl,cividis:()=>Ul,cool:()=>Rl,copper:()=>Pl,copper2:()=>Vl,ct_airways:()=>Nl,ct_artery:()=>Ll,ct_bones:()=>kl,ct_brain:()=>zl,ct_brain_gray:()=>Ol,ct_cardiac:()=>Gl,ct_head:()=>Yl,ct_kidneys:()=>Xl,ct_liver:()=>Wl,ct_muscles:()=>Kl,ct_scalp:()=>Hl,ct_skull:()=>ql,ct_soft:()=>Ql,ct_soft_tissue:()=>Zl,ct_surface:()=>jl,ct_vessels:()=>_l,ct_w_contrast:()=>Jl,cubehelix:()=>$l,electric_blue:()=>ec,freesurfer:()=>tc,ge_color:()=>ic,gold:()=>rc,gray:()=>sc,green:()=>nc,green2cyan:()=>ac,green2orange:()=>oc,hot:()=>cc,hotiron:()=>lc,hsv:()=>hc,inferno:()=>dc,jet:()=>fc,kry:()=>uc,linspecer:()=>mc,lipari:()=>pc,magma:()=>gc,mako:()=>Ac,navia:()=>xc,nih:()=>vc,plasma:()=>wc,random:()=>yc,red:()=>bc,redyell:()=>Cc,rocket:()=>Mc,roi_i256:()=>Pc,surface:()=>Dc,thermal:()=>Tc,turbo:()=>Sc,violet:()=>Ec,viridis:()=>Ic,warm:()=>Fc,winter:()=>Bc,x_rain:()=>Uc});var xl={R:[0,255,0,0,255,0,255,255,0,205,210,102,0,0,46,255,106,221,233,165,255,147,218,75,255,60,255,255,218,0,188,255,255,222,127,139,124,255,70,0,238,238,240,245,184,32,255,25,112,34,248,245,255,144,173,65,255,250,128,50,244,255,123,255,173,255,127,255,143,220,253,255,0,0,128,255,250,148,178,255,135,100,240,250,255,107,135,0,139,245,186,255,255,0,210,255,47,72,175,128,176,255,139,240,255,216,119,219,72,255,199,154,189,240,230,0,85,64,153,205,250,95,0,255,224,176,138,30,240,152,160],G:[0,0,255,0,255,255,0,239,0,133,180,205,0,139,139,228,90,160,150,42,250,112,112,0,182,179,235,228,165,128,143,105,218,184,255,69,252,255,130,100,130,232,255,222,134,178,20,25,128,139,248,255,160,238,255,105,99,240,0,205,164,255,104,165,216,192,255,140,188,20,245,250,206,255,0,250,128,0,34,127,206,149,230,235,245,142,206,0,0,245,85,228,222,191,105,248,79,61,238,128,224,240,0,255,215,191,136,112,209,0,21,205,183,248,230,250,107,224,50,92,250,158,128,69,255,196,43,144,128,251,82],B:[0,0,0,255,0,255,255,213,205,63,140,170,128,139,87,225,205,221,122,42,250,219,214,130,193,113,205,196,32,128,143,180,185,135,0,19,0,224,180,0,238,170,240,179,11,170,147,112,144,34,255,250,122,144,47,225,71,230,0,50,96,240,238,0,230,203,212,0,143,60,230,240,209,127,128,205,114,211,34,80,235,237,140,215,238,35,250,139,139,220,211,181,173,255,30,220,79,139,238,0,230,245,0,255,0,216,153,147,204,255,133,50,107,255,250,154,47,208,204,92,210,160,0,0,255,222,226,255,128,152,45],A:[0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],I:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130]},vl={labels:["background","tissue","bone","skin","connective tissue","blood","organ","mass","muscle","foreign object","waste","teeth","fat","gray matter","white matter","nerve","vein","artery","capillary","ligament","tendon","cartilage","meniscus","lymph node","lymphatic vessel","cerebro-spinal fluid","bile","urine","feces","gas","fluid","edema","bleeding","necrosis","clot","embolism","head","central nervous system","brain","gray matter of brain","telencephalon","cerebral cortex","right frontal lobe","left frontal lobe","right temporal lobe","left temporal lobe","right parietal lobe","left parietal lobe","right occipital lobe","left occipital lobe","right insular lobe","left insular lobe","right limbic lobe","left limbic lobe","right striatum","left striatum","right caudate nucleus","left caudate nucleus","right putamen","left putamen","right pallidum","left pallidum","right amygdaloid complex","left amygdaloid complex","diencephalon","thalamus","right thalamus","left thalamus","pineal gland","midbrain","substantia nigra","right substantia nigra","left substantia nigra","cerebral white matter","right superior longitudinal fasciculus","left superior longitudinal fasciculus","right inferior longitudinal fasciculus","left inferior longitudinal fasciculus","right arcuate fasciculus","left arcuate fasciculus","right uncinate fasciculus","left uncinate fasciculus","right cingulum bundle","left cingulum bundle","projection fibers","right corticospinal tract","left corticospinal tract","right optic radiation","left optic radiation","right medial lemniscus","left medial lemniscus","right superior cerebellar peduncle","left superior cerebellar peduncle","right middle cerebellar peduncle","left middle cerebellar peduncle","right inferior cerebellar peduncle","left inferior cerebellar peduncle","optic chiasm","right optic tract","left optic tract","right fornix","left fornix","commissural fibers","corpus callosum","posterior commissure","cerebellar white matter","CSF space","ventricles of brain","right lateral ventricle","left lateral ventricle","right third ventricle","left third ventricle","cerebral aqueduct","fourth ventricle","subarachnoid space","spinal cord","gray matter of spinal cord","white matter of spinal cord","endocrine system of brain","pituitary gland","adenohypophysis","neurohypophysis","meninges","dura mater","arachnoid","pia mater","muscles of head","salivary glands","lips","nose","tongue","soft palate","right inner ear","left inner ear","right external ear","left external ear","right middle ear","left middle ear","right eyeball","left eyeball","skull","right frontal bone","left frontal bone","right parietal bone","left parietal bone","right temporal bone","left temporal bone","right sphenoid bone","left sphenoid bone","right ethmoid bone","left ethmoid bone","occipital bone","maxilla","right zygomatic bone","right lacrimal bone","vomer bone","right palatine bone","left palatine bone","mandible","neck","muscles of neck","pharynx","larynx","thyroid gland","right parathyroid glands","left parathyroid glands","skeleton of neck","hyoid bone","cervical vertebral column","thorax","trachea","bronchi","right lung","left lung","superior lobe of right lung","superior lobe of left lung","middle lobe of right lung","inferior lobe of right lung","inferior lobe of left lung","pleura","heart","right atrium","left atrium","atrial septum","ventricular septum","right ventricle of heart","left ventricle of heart","mitral valve","tricuspid valve","aortic valve","pulmonary valve","aorta","pericardium","pericardial cavity","esophagus","thymus","mediastinum","skin of thoracic wall","muscles of thoracic wall","skeleton of thorax","thoracic vertebral column","ribs","sternum","right clavicle","left clavicle","abdominal cavity","abdomen","peritoneum","omentum","peritoneal cavity","retroperitoneal space","stomach","duodenum","small bowel","colon","anus","liver","biliary tree","gallbladder","pancreas","spleen","urinary system","right kidney","left kidney","right ureter","left ureter","urinary bladder","urethra","right adrenal gland","left adrenal gland","female internal genitalia","uterus","right fallopian tube","left fallopian tube","right ovary","left ovary","vagina","male internal genitalia","prostate","right seminal vesicle","left seminal vesicle","right deferent duct","left deferent duct","skin of abdominal wall","muscles of abdominal wall","skeleton of abdomen","lumbar vertebral column","female external genitalia","male external genitalia","skeleton of upper limb","muscles of upper limb","right upper limb","left upper limb","right shoulder","left shoulder","right arm"],R:[0,128,241,177,111,216,221,144,192,220,78,255,230,200,250,244,0,216,183,183,152,111,178,68,111,85,0,214,78,218,170,140,188,216,145,150,177,244,250,200,68,128,83,83,162,162,141,141,182,182,188,188,154,154,177,177,30,30,210,210,48,48,98,98,69,166,122,122,253,145,46,0,0,250,127,127,159,159,125,125,106,106,154,154,126,201,201,78,78,174,174,139,139,148,148,186,186,99,156,156,64,64,138,97,126,194,85,88,88,88,88,88,88,88,88,244,200,250,82,57,60,92,255,255,255,255,201,70,188,177,166,182,229,229,174,174,201,201,194,194,241,203,203,229,229,255,255,209,209,248,248,255,196,255,255,255,242,242,222,177,213,184,150,62,62,62,242,250,255,177,182,175,197,197,172,172,202,224,224,255,206,210,203,233,195,181,152,159,166,218,225,224,255,184,211,47,255,173,188,255,226,253,244,205,205,186,177,255,234,204,180,216,255,205,204,255,221,0,139,249,157,203,185,185,247,247,222,124,249,249,244,255,255,227,213,213,193,216,230,245,245,241,241,177,171,217,212,185,185,198,194,177,177,177,177,177],G:[0,174,214,122,184,101,130,238,104,245,63,250,220,200,250,214,151,101,156,214,189,184,212,172,197,188,145,230,63,255,250,224,65,191,60,98,122,214,250,200,131,174,146,146,115,115,93,93,166,166,135,135,150,150,140,140,111,111,157,157,129,129,153,153,110,113,101,101,135,92,101,108,108,250,150,150,116,116,102,102,174,174,146,146,126,160,160,152,152,140,140,126,126,120,120,135,135,106,171,171,123,123,95,113,161,195,188,106,106,106,106,106,106,106,106,214,200,250,174,157,143,162,244,244,244,244,121,163,91,122,84,105,147,147,122,122,112,112,142,142,213,179,179,204,204,243,243,185,185,223,223,230,172,255,250,237,217,217,198,122,124,105,208,162,162,162,206,210,255,122,228,216,165,165,138,138,164,186,186,245,110,115,108,138,100,85,55,63,70,123,130,97,244,122,171,150,244,121,95,239,202,232,217,179,179,124,122,255,234,142,119,132,253,167,168,224,130,145,150,180,108,136,102,102,182,182,154,186,186,186,170,181,190,153,141,141,123,146,158,172,172,172,172,124,85,198,188,135,135,175,98,122,122,122,122,122],B:[0,128,145,101,210,79,101,144,88,20,0,220,70,235,210,49,206,79,220,211,207,210,242,100,131,255,30,130,0,255,250,228,28,216,66,83,101,49,225,215,98,128,164,164,105,105,137,137,110,110,166,166,201,201,190,190,85,85,166,166,126,126,112,112,53,137,38,38,192,109,131,112,112,225,88,88,163,163,154,154,155,155,83,83,55,133,133,141,141,103,103,177,177,72,72,135,135,24,108,108,147,147,74,158,197,164,255,215,215,215,215,215,215,215,215,49,215,225,128,110,83,109,209,209,209,209,77,117,95,101,94,107,118,118,90,90,73,73,0,0,144,77,77,109,109,152,152,85,85,131,131,138,68,167,160,145,123,123,101,101,109,108,243,114,114,114,142,139,207,101,255,244,145,145,115,115,140,162,162,217,84,89,81,112,73,57,13,27,38,97,104,76,209,154,143,103,209,88,76,172,134,158,154,108,108,161,101,220,194,178,153,105,229,142,143,199,101,30,98,111,162,116,83,83,164,164,132,223,150,150,147,158,165,130,113,113,103,127,140,147,147,151,151,92,68,131,102,134,134,125,79,101,101,101,101,101],A:[0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],I:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]},wl={R:[0,0,24,248,255],G:[0,0,177,254,0],B:[0,136,0,0,0],A:[0,32,64,78,128],I:[0,64,128,156,255]},yl={R:[1,10,15,17,21,27,36,49,65,82,99,118,140,161,183,203,222,238,248,253,253,253,252,250],G:[25,42,56,68,79,88,97,105,111,116,122,127,133,138,142,146,150,155,162,170,178,186,195,204],B:[89,92,95,96,98,98,96,91,83,74,64,55,46,43,49,62,79,100,126,151,175,199,223,250],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,11,22,33,44,55,66,77,88,99,110,121,133,144,155,166,177,188,199,210,221,232,243,255]},bl={R:[0,248,242,235,229,222,212,202,193,183,173,145,117,78,39,0,0,0,0,0,0,64,128,191,255,255,255,255,255,238,221,204,214,224,235,245,255,249,242,236,229,223,217,210,204,197,191,184,176,169,161,154,146,139,132,124,117,109,102,0],G:[0,251,247,243,239,235,235,235,235,235,235,216,197,174,150,127,153,178,204,229,255,255,255,255,255,220,185,150,115,77,38,0,31,61,92,122,153,138,122,107,92,77,61,46,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0],B:[0,254,253,252,251,250,251,252,253,254,255,226,198,132,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,80,120,160,200,199,198,197,196,196,195,194,193,192,191,184,176,169,161,154,146,139,132,124,117,109,102,0],A:[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],I:[0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,255]},Cl={R:[255,248,242,235,229,222,212,202,193,183,173,145,117,78,39,0,0,0,0,0,0,64,128,191,255,255,255,255,255,238,221,204,214,224,235,245,255,249,242,236,229,223,217,210,204,197,191,184,176,169,161,154,146,139,132,124,117,109,102,0],G:[255,251,247,243,239,235,235,235,235,235,235,216,197,174,150,127,153,178,204,229,255,255,255,255,255,220,185,150,115,77,38,0,31,61,92,122,153,138,122,107,92,77,61,46,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0],B:[255,254,253,252,251,250,251,252,253,254,255,226,198,132,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,80,120,160,200,199,198,197,196,196,195,194,193,192,191,184,176,169,161,154,146,139,132,124,117,109,102,0],A:[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],I:[0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,255]},Ml={R:[0,0,0,0,196,255],G:[0,32,128,128,128,32],B:[0,255,196,0,0,0],A:[0,128,64,64,64,128],I:[0,1,64,128,192,255]},Dl={R:[0,255],G:[0,0],B:[255,255],A:[0,128],I:[0,255]},Tl={R:[0,0],G:[0,255],B:[255,255],A:[0,128],I:[0,255]},Sl={R:[0,0,0,0],G:[0,1,128,255],B:[0,222,127,32],A:[0,0,64,128],I:[0,1,128,255]},El={R:[0,0,0],G:[0,0,0],B:[0,128,255],A:[0,64,128],I:[0,128,255]},Il={R:[0,103,255],G:[0,126,255],B:[0,165,255],A:[0,76,128],I:[0,153,255]},Fl={R:[0,43,103,199,216,255],G:[0,0,37,155,213,255],B:[0,0,20,97,201,255],A:[0,44,48,54,56,56],I:[0,64,128,196,240,255]},Bl={R:[0,9,24,33,40,46,52,57,62,66,70,74,78,81,85,88,91,94,98,101,103,106,109,112,114,117,119,121,124,126,128,130,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,164,166,168,169,171,172,174,175,177,178,180,181,183,184,186,187,189,190,191,193,194,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,222,223,224,224,225,226,226,227,228,228,229,229,230,231,231,232,233,233,234,234,235,235,236,236,236,237,237,237,238,238,238,239,239,239,240,240,240,241,241,241,242,242,242,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,243,243,243,243,243,243,243,243,243,243,243,243,242,242,242,242,242,242,242,242,241,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,243,243,244,244,245,246,246,247,247,248,249,249,250,250,251,251,252,252,253,253,254,254,254],G:[42,41,41,41,40,40,40,39,39,39,38,38,37,37,36,36,35,35,34,34,33,32,32,31,30,30,30,30,29,29,29,29,28,28,28,27,27,27,26,26,26,25,25,25,24,24,24,24,24,25,25,26,27,27,28,28,29,30,30,31,31,32,33,33,34,34,35,36,36,37,38,39,40,42,43,44,45,47,48,49,50,51,53,54,55,56,57,58,59,60,62,63,64,65,66,68,69,71,72,73,75,76,77,79,80,81,83,84,85,87,88,89,90,92,93,94,95,97,98,100,101,102,104,105,107,108,109,111,112,113,115,116,117,119,120,121,122,124,125,126,128,129,130,132,133,134,136,137,138,140,141,142,144,145,146,147,149,150,151,153,154,155,156,158,159,160,161,163,164,165,167,168,169,170,172,173,174,175,176,178,179,180,181,183,184,185,186,187,189,190,191,192,193,194,196,197,198,199,200,201,203,204,205,206,207,208,209,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,228,229,230,231,232,233,234,235,236,237,238,238,239,240,241,241,242,243,244,244,245,246,247,248,248,249,250,251,251,252,253,254,255],B:[167,167,166,166,166,165,165,165,164,164,164,163,163,162,162,162,161,161,161,160,160,160,159,159,158,158,157,157,156,155,155,154,154,153,153,152,151,151,150,150,149,149,148,147,147,146,146,145,144,144,143,143,142,141,141,140,139,139,138,137,137,136,135,135,134,133,133,132,131,131,130,130,129,128,128,127,127,126,125,125,124,124,123,123,122,121,121,120,119,119,118,118,117,116,116,116,115,115,114,114,113,113,113,112,112,111,111,110,110,109,109,109,108,108,107,107,106,106,106,106,106,105,105,105,105,105,105,105,104,104,104,104,104,103,103,103,103,103,102,102,102,103,103,103,103,104,104,104,104,104,105,105,105,105,106,106,106,106,106,107,107,107,107,108,108,109,110,111,111,112,113,113,114,115,115,116,117,117,118,119,120,120,121,122,122,123,124,125,126,128,129,130,131,132,134,135,136,137,138,140,141,142,143,144,146,147,148,149,150,152,153,155,157,158,160,162,163,165,167,168,170,172,173,175,177,178,180,182,183,185,187,188,190,193,196,199,201,204,207,210,212,215,218,221,224,226,229,232,235,238,240,243,246,249,252,255],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]},Ul={R:[0,86,166,255],G:[32,92,156,233],B:[76,108,117,69],A:[0,56,80,88],I:[0,64,192,255]},Rl={R:[0,0,0],G:[127,196,254],B:[255,255,255],A:[0,64,128],I:[0,128,255]},Vl={R:[0,61,122,183,244,255],G:[0,41,81,122,163,255],B:[0,25,51,76,102,255],A:[0,25,51,71,102,128],I:[0,51,102,153,204,255]},Pl={R:[0,61,122,183,244,255],G:[0,41,81,122,163,203],B:[0,25,51,76,102,127],A:[0,25,51,71,102,128],I:[0,51,102,153,204,255]},Nl={min:-643,max:-235,R:[0,0,0],G:[154,154,154],B:[179,179,101],A:[0,32,0],I:[0,163,255]},Ll={min:114,max:800,R:[0,255,255,255],G:[0,0,129,255],B:[0,0,0,255],A:[0,64,88,228],I:[0,80,160,255]},kl={min:180,max:600,R:[0,0,113,255],G:[0,0,109,250],B:[0,0,101,245],A:[0,0,100,160],I:[0,1,128,255]},Ol={min:-10,max:110,R:[0,127,255],G:[0,127,255],B:[0,127,255],A:[0,48,128],I:[0,124,255]},zl={min:-10,max:110,R:[0,199,255],G:[0,127,255],B:[0,127,255],A:[0,48,128],I:[0,124,255]},Gl={min:-80,max:1e3,R:[0,189,150,150,150,150,255],G:[0,169,54,54,54,54,240],B:[0,153,52,52,52,52,242],A:[0,32,64,0,0,64,64],I:[0,1,82,92,234,242,255]},Yl={min:-590,max:600,R:[0,241,241,248,248,178,178,232,255,255,255],G:[0,156,156,222,222,36,36,51,255,255,255],B:[0,130,130,169,169,24,24,37,255,255,255],A:[0,8,0,0,0,64,64,0,0,222,222],I:[0,2,3,64,122,142,172,182,252,253,255]},Xl={min:114,max:302,R:[0,255,255],G:[0,129,255],B:[0,0,255],A:[0,88,228],I:[0,103,255]},Wl={min:-23,max:246,R:[0,44,255,255,255],G:[0,128,90,255,255],B:[0,0,70,0,255],A:[0,0,82,184,228],I:[0,64,131,196,255]},Kl={min:-100,max:246,R:[0,128,159,255,255,255,255],G:[0,0,56,90,0,255,255],B:[0,0,41,70,0,0,255],A:[0,63,105,135,167,184,228],I:[0,100,128,155,180,209,255]},Hl={min:-590,max:600,R:[0,241,241,248,248,178,232,255,255],G:[0,156,156,222,222,36,51,255,255],B:[0,130,130,169,169,24,37,255,255],A:[0,63,105,135,167,184,228,228,228],I:[0,1,52,127,137,162,172,252,255]},ql={min:140,max:1024,R:[0,2,113,255],G:[0,1,109,250],B:[0,1,101,245],A:[0,1,96,168],I:[0,1,128,255]},Ql={min:-923,max:679,R:[0,0,0,0,0,255,255,255],G:[154,154,154,154,0,0,254,255],B:[179,179,179,179,0,0,0,255],A:[0,3,8,0,0,10,15,20],I:[0,30,62,88,170,200,232,255]},Zl={min:-10,max:110,R:[0,199,255],G:[0,127,255],B:[0,127,255],A:[0,48,128],I:[0,124,255]},jl={min:-600,max:100,R:[0,134,255],G:[0,109,250],B:[0,101,245],A:[0,60,148],I:[0,128,255]},_l={min:114,max:246,R:[0,255,255],G:[0,128,255],B:[0,128,255],A:[0,64,96],I:[0,87,255]},Jl={min:50,max:1e3,R:[98,210,169,128,255],G:[94,26,77,128,255],B:[45,21,74,128,255],A:[0,25,0,4,168],I:[0,41,87,154,255]},$l={R:[0,13,21,26,27,25,22,21,22,28,39,54,75,98,124,148,171,189,202,210,213,211,206,200,195,193,195,201,211,225,240,255],G:[0,5,11,20,31,44,58,72,86,99,109,116,120,122,122,122,121,121,124,129,137,147,161,175,190,205,218,229,238,245,251,255],B:[0,14,30,46,61,71,77,78,75,68,60,52,48,47,53,65,83,105,131,157,183,205,222,235,241,243,242,240,239,240,245,255],A:[0,4,8,12,17,21,25,29,33,37,41,45,50,54,58,62,66,70,74,78,83,87,91,95,99,103,107,111,116,120,124,128],I:[0,8,16,25,33,41,49,58,66,74,82,90,99,107,115,123,132,140,148,156,165,173,181,189,197,206,214,222,230,239,247,255]},ec={R:[0,10,136,255],G:[0,39,220,255],B:[0,223,253,255],A:[0,48,64,70],I:[0,92,192,255]},tc={R:[0,245,205,120,196,220,230,0,122,236,12,204,42,119,220,103,60,255,165,160,0,245,205,120,196,220,230,0,122,236,13,220,103,255,165,160,0,120,200,255,255,164,164,164,234,0,0,0,0,0],G:[0,245,62,18,58,248,148,118,186,13,48,182,204,159,216,255,60,165,42,32,200,245,62,18,58,248,148,118,186,13,48,216,255,165,42,32,200,190,70,148,148,108,108,108,169,0,0,0,0,0],B:[0,245,78,134,250,164,34,14,220,176,255,142,164,176,20,255,60,0,42,240,200,245,78,134,250,164,34,14,220,176,255,20,255,0,42,240,221,150,255,10,10,226,226,226,30,64,112,160,208,255],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,2,3,4,5,7,8,10,11,12,13,14,15,16,17,18,24,26,28,30,31,41,42,43,44,46,47,49,50,51,52,53,54,58,60,62,63,72,77,78,79,80,81,82,85,251,252,253,254,255]},ic={R:[0,0,128,255,255],G:[0,128,0,128,255],B:[0,125,255,0,255],A:[0,32,64,96,128],I:[0,63,128,192,255]},rc={R:[0,142,227,255],G:[0,85,170,255],B:[0,14,76,255],A:[0,42,84,128],I:[0,85,170,255]},sc={R:[0,255],G:[0,255],B:[0,255],A:[0,128],I:[0,255]},nc={R:[0,0,0],G:[0,128,255],B:[0,0,0],A:[0,64,128],I:[0,128,255]},ac={R:[0,0,0],G:[72,72,255],B:[0,255,255],A:[0,64,128],I:[0,88,255]},oc={R:[0,255,255],G:[72,88,255],B:[0,0,0],A:[0,64,128],I:[0,88,255]},lc={R:[0,255,255,255],G:[0,0,126,255],B:[0,0,0,255],A:[0,64,96,128],I:[0,128,191,255]},cc={R:[3,255,255,255],G:[0,0,255,255],B:[0,0,0,255],A:[0,48,96,128],I:[0,95,191,255]},hc={R:[255,255,0,0,0,255,255],G:[0,255,255,255,0,0,0],B:[0,0,0,255,255,255,0],A:[0,14,28,43,57,71,85],I:[0,43,85,128,170,213,255]},dc={R:[0,120,237,240],G:[0,28,105,249],B:[4,109,37,33],A:[0,56,80,88],I:[0,64,192,255]},fc={R:[0,0,127,255,127],G:[0,127,255,127,0],B:[127,255,127,0,0],A:[0,32,64,96,128],I:[0,63,128,192,255]},uc={R:[0,255,255],G:[0,0,255],B:[0,0,0],A:[0,64,64],I:[0,86,255]},mc={R:[94,50,90,152,215,238,249,254,252,241,209,158],G:[79,131,186,214,240,244,237,210,157,100,57,1],B:[162,189,167,164,155,169,168,123,86,68,79,66],A:[0,12,23,35,47,58,70,81,93,105,116,128],I:[0,23,46,70,93,116,139,162,185,209,232,255]},pc={R:[3,7,13,25,45,67,84,98,110,124,138,154,173,191,210,225,233,233,231,229,230,235,243,253],G:[19,33,48,63,77,87,92,94,95,96,96,97,99,101,106,118,133,149,163,177,192,208,225,245],B:[38,58,79,99,114,122,122,120,117,113,110,105,101,97,94,96,103,112,122,134,149,169,192,218],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,11,22,33,44,55,66,77,88,99,110,121,133,144,155,166,177,188,199,210,221,232,243,255]},gc={R:[0,148,183,223,247,252],G:[0,44,55,74,112,253],B:[4,128,121,104,92,191],A:[0,44,53,64,75,107],I:[0,107,128,154,179,255]},Ac={R:[11,59,55,222],G:[4,45,165,245],B:[5,91,172,229],A:[0,23,70,107],I:[0,56,167,255]},xc={R:[3,5,6,8,12,19,28,36,42,48,54,61,68,76,86,96,110,129,154,181,205,224,239,252],G:[19,32,44,58,72,86,98,108,116,122,128,134,141,149,157,167,178,191,204,216,225,232,239,244],B:[39,60,82,104,123,137,144,145,142,138,134,130,126,121,116,110,105,104,112,131,155,178,198,217],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,11,22,33,44,55,66,77,88,99,110,121,133,144,155,166,177,188,199,210,221,232,243,255]},vc={R:[0,85,0,0,0,0,0,0,85,255,255,255,172],G:[0,0,0,0,85,170,255,255,255,255,85,0,0],B:[0,170,85,255,255,170,170,0,85,0,0,0,0],A:[0,5,10,21,26,32,37,42,48,53,64,72,85],I:[0,15,31,63,79,95,111,127,143,159,191,217,255]},wc={R:[13,156,237,240],G:[8,23,121,249],B:[135,158,83,33],A:[0,56,80,88],I:[0,64,192,255]},yc={R:[208,71,33,192,32,195,208,173,233,202,25,210,145,89,87,245,246,38,3,25,57,167,245,86,227,208,81,64,90,199,140,48,212,180,70,120,9,192,245,177,65,157,9,193,100,181,125,145,62,8,108,36,140,237,242,248,161,189,41,114,65,121,97,50,238,149,44,214,124,167,40,167,127,178,231,30,173,244,193,203,204,238,139,135,71,234,234,217,66,14,129,19,97,165,112,244,35,73,192,12,149,71,33,192,32,195,208,173,233,202,25,210,145,89,87,245,246,38,3,25,57,167,245,86,227,208,81,64,90,199,140,48,212,180,70,120,9,192,245,177,65,157,9,193,100,181,125,145,62,8,108,36,140,237,242,248,161,189,41,114,65,121,97,50,238,149,44,214,124,167,40,167,127,178,231,30,173,244,193,203,204,238,139,135,71,234,234,217,66,14,129,19,97,165,112,244,35,73,192,12,149,71,33,192,32,195,208,173,233,202,25,210,145,89,87,245,246,38,3,25,57,167,245,86,227,208,81,64,90,199,140,48,212,180,70,120,9,192,245,177,65,157,9,193,100,181,125,145,62,8,108,36,140,237,242,248],G:[182,46,78,199,79,89,41,208,135,20,154,35,21,43,230,113,191,147,208,37,28,27,86,203,25,209,148,187,139,111,48,102,76,110,106,130,37,160,34,222,90,165,245,222,102,47,19,130,4,232,137,211,240,11,140,21,42,22,241,61,99,115,199,166,114,190,204,60,233,66,115,230,125,103,203,125,13,176,94,131,39,198,167,124,67,175,254,1,15,198,62,237,159,31,218,58,244,47,61,67,94,46,78,199,79,89,41,208,135,20,154,35,21,43,230,113,191,147,208,37,28,27,86,203,25,209,148,187,139,111,48,102,76,110,106,130,37,160,34,222,90,165,245,222,102,47,19,130,4,232,137,211,240,11,140,21,42,22,241,61,99,115,199,166,114,190,204,60,233,66,115,230,125,103,203,125,13,176,94,131,39,198,167,124,67,175,254,1,15,198,62,237,159,31,218,58,244,47,61,67,94,46,78,199,79,89,41,208,135,20,154,35,21,43,230,113,191,147,208,37,28,27,86,203,25,209,148,187,139,111,48,102,76,110,106,130,37,160,34,222,90,165,245,222,102,47,19,130,4,232,137,211,240,11,140,21],B:[191,154,43,10,207,204,164,231,136,58,239,30,147,230,101,111,150,35,128,57,252,79,173,120,25,126,81,85,8,7,122,237,190,152,246,182,130,219,67,76,167,178,235,250,28,61,186,250,199,67,58,50,86,182,108,77,89,112,59,125,226,50,205,227,125,128,104,27,59,66,53,133,159,203,97,125,139,159,158,7,215,47,140,226,223,231,44,110,184,61,233,47,67,148,22,120,173,156,117,181,94,154,43,10,207,204,164,231,136,58,239,30,147,230,101,111,150,35,128,57,252,79,173,120,25,126,81,85,8,7,122,237,190,152,246,182,130,219,67,76,167,178,235,250,28,61,186,250,199,67,58,50,86,182,108,77,89,112,59,125,226,50,205,227,125,128,104,27,59,66,53,133,159,203,97,125,139,159,158,7,215,47,140,226,223,231,44,110,184,61,233,47,67,148,22,120,173,156,117,181,94,154,43,10,207,204,164,231,136,58,239,30,147,230,101,111,150,35,128,57,252,79,173,120,25,126,81,85,8,7,122,237,190,152,246,182,130,219,67,76,167,178,235,250,28,61,186,250,199,67,58,50,86,182,108,77],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]},bc={R:[0,128,255],G:[0,0,0],B:[0,0,0],A:[0,64,128],I:[0,128,255]},Cc={R:[192,224,255],G:[1,128,255],B:[0,0,0],A:[0,64,128],I:[0,128,255]},Mc={R:[3,112,144,188,236,246,255],G:[5,31,29,22,76,158,250],B:[26,87,91,86,62,117,235],A:[0,30,38,49,67,85,107],I:[0,73,92,118,160,205,255]},Dc={R:[1,240,255],G:[1,128,255],B:[1,128,255],A:[0,76,128],I:[0,153,255]},Tc={R:[0,5,18,34,53,72,90,107,126,144,161,178,194,209,222,233,242,248,251,251,249,244,241,252],G:[0,4,10,11,9,11,17,23,30,36,43,50,59,70,83,98,117,136,157,177,199,220,240,254],B:[3,24,50,76,96,106,109,110,108,104,97,89,79,67,55,42,26,12,6,22,47,79,121,164],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,11,22,33,44,55,66,77,88,99,110,121,133,144,155,166,177,188,199,210,221,232,243,255]},Sc={R:[48,48,64,70,65,25,132,195,244,254,218,122],G:[18,18,64,107,150,226,255,241,199,158,57,4],B:[59,59,162,227,255,187,81,52,58,47,7,3],A:[0,22,26,30,34,43,52,57,63,67,77,86],I:[0,1,16,32,49,83,118,140,164,181,219,255]},Ec={R:[0,128,255],G:[0,0,0],B:[0,128,255],A:[0,64,128],I:[0,128,255]},Ic={R:[68,49,53,253],G:[1,104,183,231],B:[84,142,121,37],A:[0,56,80,88],I:[0,64,192,255]},Fc={R:[255,255,255],G:[127,196,254],B:[0,0,0],A:[0,64,128],I:[0,128,255]},Bc={R:[0,0,0],G:[0,128,255],B:[255,196,128],A:[0,64,128],I:[0,128,255]},Uc={R:[3,64,0,0,255,255,255],G:[0,0,0,255,255,192,3],B:[0,32,48,56,64,96,128],A:[0,8,16,24,32,52,80],I:[0,32,64,96,160,192,255]},Rc={min:0,max:0,R:[0,37],G:[242,0],B:[255,255],A:[0,64],I:[0,255]},Vc={R:[255,255],G:[255,11],B:[0,0],A:[0,64],I:[0,255]},Pc={min:0,max:0,R:[65,10,223,120,216,207,251,93,252,217,21,253,131,165,173,143,144,217,86,89,63,254,172,1,142,107,42,78,221,8,222,71,127,126,167,33,104,2,208,216,0,251,7,105,2,101,248,190,253,62,255,224,166,37,110,138,45,34,6,37,69,201,43,122,199,37,173,194,103,211,75,159,96,4,239,98,110,193,253,166,40,255,48,130,140,243,101,9,177,220,133,32,4,81,48,48,210,109,60,132,1,119,1,159,247,33,212,187,253,144,196,254,168,79,64,196,39,97,73,173,104,216,217,43,101,119,254,5,237,103,203,122,57,87,251,164,19,75,200,2,252,150,66,0,255,157,23,254,55,16,240,161,69,253,207,195,5,60,255,251,200,217,134,123,253,180,27,246,130,136,250,232,4,125,140,22,253,255,13,180,123,61,254,111,10,185,76,192,255,223,186,61,198,5,172,13,83,172,171,6,23,73,134,133,109,61,213,55,57,132,36,209,2,144,1,253,68,155,3,160,2,77,121,70,67,176,223,131,4,162,232,255,150,94,235,191,207,10,246,0,225,4,209,116,57,112,172,253,1,6,92,227,73,62,135,223],G:[162,50,112,245,4,124,176,243,56,125,183,139,182,68,189,4,225,10,20,223,7,46,31,193,225,250,219,41,2,100,83,181,34,150,72,223,168,248,80,253,7,117,214,2,248,10,3,59,179,160,90,244,146,4,207,4,125,255,96,100,1,208,130,51,116,181,236,53,244,5,165,28,181,86,96,42,254,1,134,194,214,92,41,204,137,86,207,3,143,3,100,239,164,94,65,251,131,244,173,57,143,107,217,53,210,0,148,250,45,198,81,40,61,218,252,88,171,0,248,24,248,4,41,100,187,46,208,145,43,168,121,46,175,250,125,107,233,112,207,231,174,215,53,9,43,153,52,124,128,65,210,147,255,147,63,200,148,254,0,179,241,42,239,2,230,8,82,135,87,16,3,87,86,151,254,8,255,86,53,19,7,192,171,201,253,247,197,103,251,126,0,149,54,183,61,126,79,113,10,103,184,75,11,195,222,136,149,131,8,99,240,177,252,255,198,16,7,68,178,66,191,150,73,26,211,109,78,209,240,254,1,166,247,131,2,0,167,127,133,10,43,99,235,3,214,142,176,82,132,38,10,249,255,215,44,81],B:[176,182,248,37,117,35,96,69,32,152,108,20,237,250,2,89,141,216,111,251,211,149,10,44,214,103,31,251,3,32,252,246,97,1,219,167,197,4,36,116,206,118,106,43,205,204,114,69,127,205,87,80,41,251,145,204,253,161,247,1,149,9,43,253,97,72,136,161,171,181,26,255,108,80,218,214,231,255,84,31,109,4,218,3,217,36,68,85,241,39,221,2,240,2,173,42,206,5,110,46,103,27,212,184,2,207,246,45,116,72,110,253,38,105,248,159,243,81,192,93,141,145,24,157,234,131,57,178,62,75,65,176,148,40,253,66,76,240,51,154,17,251,139,253,207,9,114,49,200,254,96,73,138,118,204,102,137,89,145,161,4,112,66,234,147,178,212,205,185,11,203,131,2,250,118,169,1,185,154,53,171,197,61,175,249,96,15,254,95,5,222,75,246,194,2,61,180,25,133,165,15,233,59,35,221,140,109,7,114,255,198,0,115,168,252,23,242,80,75,142,137,255,12,182,68,201,4,111,37,228,83,248,24,192,249,5,54,223,160,122,160,114,145,119,252,31,253,250,10,214,8,47,0,142,222,70],A:[0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64],I:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]},Nc=class{constructor(){D(this,"gamma",1),D(this,"version",.1),D(this,"cluts",{});const e=Object.keys(ii).filter(i=>!i.startsWith("$")).sort(new Intl.Collator("en").compare);for(const i of e)this.cluts[i]=ii[i]}addColormap(t,e){this.cluts[t]=e}colormaps(){return Object.keys(this.cluts)}colorMaps(){return this.colormaps()}colormapFromKey(t){let e=this.cluts[t];return e!==void 0||(e=this.cluts[t.toLowerCase()],e!==void 0)?e:(t.length>0&&F.warn("No color map named "+t),{min:0,max:0,R:[0,255],G:[0,255],B:[0,255],A:[0,255],I:[0,255]})}colormap(t="",e=!1){const i=this.colormapFromKey(t);return this.makeLut(i.R,i.G,i.B,i.A,i.I,e)}makeLabelLut(t,e=255,i=1/0){if(t.R===void 0||t.G===void 0||t.B===void 0)throw new Error(`Invalid colormap table: ${t}`);const r=t.R.length,s=t.I??[...Array(r).keys()];let n=!1;for(let u=0;u<s.length;u++)s[u]>i&&(n=!0,s[u]=i);if(n&&F.warn("Some colormap indices clamped to match label range."),r!==t.G.length||r!==t.B.length||r!==s.length)throw new Error(`colormap does not make sense: ${t} Rs ${t.R.length} Gs ${t.G.length} Bs ${t.B.length} Is ${s.length}`);let a=new Uint8ClampedArray(r).fill(e);const o=s.indexOf(0);o>=0&&(a[o]=0),t.A!==void 0&&(a=Uint8ClampedArray.from(t.A));const l=Math.min(...s),c=Math.max(...s),h=c-l+1,d=new Uint8ClampedArray(h*4).fill(0);for(let u=0;u<r;u++){let m=(s[u]-l)*4;d[m++]=t.R[u],d[m++]=t.G[u],d[m++]=t.B[u],d[m++]=a[u]}const f={lut:d,min:l,max:c};if(t.labels){const u=t.labels.length;if(u===h)f.labels=t.labels;else if(u===r){f.labels=Array(h).fill("?");for(let m=0;m<r;m++)f.labels[s[m]-l]=t.labels[m]}}return f}async makeLabelLutFromUrl(t,e=255,i=1/0){const s=await(await fetch(t)).json();return this.makeLabelLut(s,e,i)}makeDrawLut(t){let e=typeof t=="object"?t:ii[t];e===void 0&&(F.warn("colormap undefined ",t),e=this.colormapFromKey(""));const i=this.makeLabelLut(e,255);if(i.labels===void 0&&(i.labels=[]),i.labels.length<256){const a=i.labels.length;for(let o=a;o<256;o++)i.labels.push(o.toString())}const r=new Uint8ClampedArray(256*4);let s=0;for(let a=0;a<256;a++)r[s++]=255,r[s++]=0,r[s++]=0,r[s++]=255;r[3]=0;const n=Math.min(i.lut.length,256*4);if(n>0)for(let a=0;a<n;a++)r[a]=i.lut[a];return{lut:r,labels:i.labels}}makeLut(t,e,i,r,s,n){const a=t.length,o=[...t],l=[...e],c=[...i];if(!s){s=new Array(a);for(let u=0;u<a;u++)s[u]=u/(a-1)*255}r||(r=new Array(a).fill(64),r[0]=0);let h=Uint8ClampedArray.from(r),d=Uint8ClampedArray.from(s);if(n)for(let u=0;u<a;u++)o[u]=t[a-1-u],l[u]=e[a-1-u],c[u]=i[a-1-u],h[u]=255-r[a-1-u],d[u]=255-s[a-1-u];const f=new Uint8ClampedArray(256*4);if(typeof d>"u"){d=new Uint8ClampedArray(a).fill(0);for(let u=0;u<a;u++)d[u]=Math.round(u*255/(a-1))}typeof h>"u"&&(h=new Uint8ClampedArray(a).fill(64),h[0]=0);for(let u=0;u<a-1;u++){const m=d[u];let p=d[u+1];u===0&&m!==0&&F.warn("colormap issue: indices expected to start with 0 not ",m),u===d.length-2&&p!==255&&(F.warn("padding colormap: indices expected end with 255 not ",p),p=255);const g=p-m;let x=m*4;for(let A=m;A<=p;A++){const y=(A-m)/g;f[x++]=o[u]+y*(o[u+1]-o[u]),f[x++]=l[u]+y*(l[u+1]-l[u]),f[x++]=c[u]+y*(c[u+1]-c[u]),f[x++]=h[u]+y*(h[u+1]-h[u])}}if(this.gamma===1)return f;for(let u=0;u<1020;u++)u%4!==3&&(f[u]=Math.pow(f[u]/255,1/this.gamma)*255);return f}},re=new Nc,$e=class{static getClusterBoundaryU8(t,e){const i=new Array(t.length).fill(!1),r=new Array(t.length).fill(!1);for(let a=0;a<t.length;a++)t[a]>0&&(r[a]=!0);const s=e.length/3;let n=0;for(let a=0;a<s;a++){const o=e[n],l=e[n+1],c=e[n+2];n+=3,!(r[o]===r[l]&&r[o]===r[c]&&r[l]===r[c])&&(i[o]=!0,i[l]=!0,i[c]=!0)}return i}static async gzip(t){const e=new CompressionStream("gzip"),i=e.writable.getWriter();i.write(t).catch(console.error);const r=i.close().catch(console.error),s=new Response(e.readable),n=new Uint8Array(await s.arrayBuffer());return await r,n}static createMZ3(t,e,i=!1,r=null,s=null,n=null){const f=e?e.length/3:0,u=t?t.length/3:0;if(!Number.isInteger(f)||f<0)throw new Error("indices length must be a multiple of 3");if(!Number.isInteger(u)||u<0)throw new Error("vertices length must be a multiple of 3");const m=e&&e.length>0,p=t&&t.length>0,g=r instanceof Uint8Array&&r.length===u*4;let x=null,A=0;if(n!=null){const R=typeof n=="string"?n:JSON.stringify(n);x=new TextEncoder().encode(R),A=x.byteLength}let y=!1,v=0;if(s!=null){if(!(s instanceof Float32Array))throw new Error("scalars must be a Float32Array or null/undefined");if(u===0)throw new Error("cannot have scalars without vertices (nvert === 0)");if(s.length>0&&s.length%u===0)y=!0,v=s.length/u;else throw new Error(`scalars.length (${s.length}) must be a positive integer multiple of nvert (${u})`)}let b=0;m&&(b|=1),p&&(b|=2),g&&(b|=4),y&&(b|=8),x&&(b|=64);const w=16,C=m?f*3*4:0,M=p?u*3*4:0,T=g?u*4:0,E=y?v*u*4:0,I=w+A+C+M+T+E,S=new ArrayBuffer(I),U=new DataView(S);let B=0;U.setUint16(B,23117,!0),B+=2,U.setUint16(B,b,!0),B+=2,U.setUint32(B,f,!0),B+=4,U.setUint32(B,u,!0),B+=4,U.setUint32(B,A,!0),B+=4;let V=w;if(A>0&&x&&(new Uint8Array(S,V,x.length).set(x),V+=A),m&&(new Uint32Array(S,V,e.length).set(e),V+=C),p&&(new Float32Array(S,V,t.length).set(t),V+=M),g&&(new Uint8Array(S,V,r.length).set(r),V+=T),y&&(new Float32Array(S,V,s.length).set(s),V+=E),V!==I)throw new Error(`mz3 internal size mismatch: offset ${V} !== totalSize ${I}`);if(i)throw new Error("Call async createMZ3Async() for compression");return S}static async createMZ3Async(t,e,i=!1,r=null,s=null,n=null){const a=this.createMZ3(t,e,i,r,s,n);return i?await this.gzip(new Uint8Array(a)):a}static createOBJ(t,e){let i="";for(let n=0;n<t.length;n+=3)i+=`v ${t[n]} ${t[n+1]} ${t[n+2]}
|
|
56
|
+
`;for(let n=0;n<e.length;n+=3)i+=`f ${e[n]+1} ${e[n+1]+1} ${e[n+2]+1}
|
|
57
|
+
`;return new TextEncoder().encode(i).buffer}static createSTL(t,e){const i=e.length/3,r=84+i*50,s=new ArrayBuffer(r),n=new DataView(s);for(let o=0;o<80;o++)n.setUint8(o,0);n.setUint32(80,i,!0);let a=84;for(let o=0;o<e.length;o+=3){const l=e[o]*3,c=e[o+1]*3,h=e[o+2]*3;n.setFloat32(a,0,!0),n.setFloat32(a+4,0,!0),n.setFloat32(a+8,0,!0),a+=12,n.setFloat32(a,t[l],!0),n.setFloat32(a+4,t[l+1],!0),n.setFloat32(a+8,t[l+2],!0),a+=12,n.setFloat32(a,t[c],!0),n.setFloat32(a+4,t[c+1],!0),n.setFloat32(a+8,t[c+2],!0),a+=12,n.setFloat32(a,t[h],!0),n.setFloat32(a+4,t[h+1],!0),n.setFloat32(a+8,t[h+2],!0),a+=12,n.setUint16(a,0,!0),a+=2}return s}static downloadArrayBuffer(t,e){const i=new Blob([t],{type:"application/octet-stream"}),r=URL.createObjectURL(i),s=document.createElement("a");s.href=r,s.download=e,document.body.appendChild(s),s.style.display="none",s.click(),setTimeout(()=>{document.body.removeChild(s),URL.revokeObjectURL(r)},0)}static async saveMesh(t,e,i=".mz3",r=!1){let s=new ArrayBuffer(0);return/\.obj$/i.test(i)?s=this.createOBJ(t,e):/\.stl$/i.test(i)?s=this.createSTL(t,e):(/\.mz3$/i.test(i)||(i+=".mz3"),s=await this.createMZ3Async(t,e,r)),i.length>4&&this.downloadArrayBuffer(s,i),s}static getClusterBoundary(t,e){const i=new Uint32Array(t.buffer),r=new Array(i.length).fill(!1),s=e.length/3;let n=0;for(let a=0;a<s;a++){const o=e[n],l=e[n+1],c=e[n+2];n+=3,!(i[o]===i[l]&&i[o]===i[c]&&i[l]===i[c])&&(r[o]=!0,r[l]=!0,r[c]=!0)}return r}static getExtents(t){if(!ArrayBuffer.isView(t)&&!Array.isArray(t)||t.length<3)return{mxDx:0,extentsMin:0,extentsMax:0};let e=0;const i=k(t[0],t[1],t[2]),r=k(t[0],t[1],t[2]);for(let a=0;a<t.length;a+=3){const o=k(t[a],t[a+1],t[a+2]);e=Math.max(e,Vt(o)),ur(i,i,o),mr(r,r,o)}const s=[i[0],i[1],i[2]],n=[r[0],r[1],r[2]];return{mxDx:e,extentsMin:s,extentsMax:n}}static generateNormals(t,e){const i=[];let r;const s=t.length;let n,a,o,l,c,h,d,f,u;const m=new Float32Array(s),p=e.length;for(r=0;r<p;r+=3){d=e[r]*3,f=e[r+1]*3,u=e[r+2]*3;const g=[t[d],t[d+1],t[d+2]],x=[t[f],t[f+1],t[f+2]],A=[t[u],t[u+1],t[u+2]];n=x[0]-g[0],a=x[1]-g[1],o=x[2]-g[2],l=A[0]-g[0],c=A[1]-g[1],h=A[2]-g[2],i[0]=c*o-h*a,i[1]=h*n-l*o,i[2]=l*a-c*n,m[d]+=i[0],m[d+1]+=i[1],m[d+2]+=i[2],m[f]+=i[0],m[f+1]+=i[1],m[f+2]+=i[2],m[u]+=i[0],m[u+1]+=i[1],m[u+2]+=i[2]}for(r=0;r<s;r+=3){i[0]=-1*m[r],i[1]=-1*m[r+1],i[2]=-1*m[r+2];let g=i[0]*i[0]+i[1]*i[1]+i[2]*i[2];g>0&&(g=1/Math.sqrt(g),i[0]*=g,i[1]*=g,i[2]*=g),m[r]=i[0],m[r+1]=i[1],m[r+2]=i[2]}return m}},Q,Ce,ri,$i,bt,An=class{constructor(t){lt(this,Q),lt(this,Ce,0),lt(this,ri,[]),lt(this,$i,[]),lt(this,bt),Ke(this,Q,new DataView(t)),this.read()}async extract(t){const e=new Uint8Array(X(this,Q).buffer.slice(t.startsAt,t.startsAt+t.compressedSize));if(t.compressionMethod===0)return e;if(t.compressionMethod===8){const i=new DecompressionStream("deflate-raw"),r=i.writable.getWriter();r.write(e).catch(console.error);const s=r.close().catch(console.error),n=new Response(i.readable),a=new Uint8Array(await n.arrayBuffer());return await s,a}throw new Error(`Unsupported compression method: ${t.compressionMethod}`)}read(){for(;!X(this,bt)&&X(this,Ce)<X(this,Q).byteLength;){const t=X(this,Q).getUint32(X(this,Ce),!0);if(t===67324752){const e=this.readLocalFile(X(this,Ce));e.extract=this.extract.bind(this,e),X(this,ri).push(e);const i=(e.generalPurpose&8)!==0;if(e.startsAt=X(this,Ce)+30+e.fileNameLength+e.extraLength,e.compressedSize===0&&i){let r=e.startsAt;for(;r+20<=X(this,Q).byteLength;){if(X(this,Q).getUint32(r,!0)===134695760&&X(this,Q).getUint16(r+16,!0)===19280){r+=4;break}r++}e.crc=X(this,Q).getUint32(r,!0),e.compressedSize=X(this,Q).getUint32(r+4,!0),e.uncompressedSize=X(this,Q).getUint32(r+8,!0),Ke(this,Ce,r+12)}else Ke(this,Ce,e.startsAt+e.compressedSize)}else if(t===33639248){const e=this.readCentralDirectory(X(this,Ce));X(this,$i).push(e),Ke(this,Ce,X(this,Ce)+(46+e.fileNameLength+e.extraLength+e.fileCommentLength))}else if(t===101010256){Ke(this,bt,this.readEndCentralDirectory(X(this,Ce)));break}else if(t===101075792){Ke(this,bt,this.readEndCentralDirectory64(X(this,Ce)));break}else{console.error(`Unexpected ZIP signature 0x${t.toString(16).padStart(8,"0")} at index ${X(this,Ce)}`);break}}}readLocalFile(t){let e=X(this,Q).getUint32(t+18,!0),i=X(this,Q).getUint32(t+22,!0);const r=X(this,Q).getUint16(t+26,!0),s=X(this,Q).getUint16(t+28,!0),n=t+30+r;if(this.readString(n,s),e===4294967295&&i===4294967295){let a=n,o=!1;for(;a<n+s-4;){const l=X(this,Q).getUint16(a,!0),c=X(this,Q).getUint16(a+2,!0);if(a+=4,l===1)if(c>=16){i=Number(X(this,Q).getBigUint64(a,!0)),a+=8,e=Number(X(this,Q).getBigUint64(a,!0)),o=!0;break}else throw new Error(`ZIP64 extra field found but is too small (expected at least 16 bytes, got ${c}).`);a+=c}if(!o)throw new Error("ZIP64 format missing extra field with signature 0x0001.")}return{signature:this.readString(t,4),version:X(this,Q).getUint16(t+4,!0),generalPurpose:X(this,Q).getUint16(t+6,!0),compressionMethod:X(this,Q).getUint16(t+8,!0),lastModifiedTime:X(this,Q).getUint16(t+10,!0),lastModifiedDate:X(this,Q).getUint16(t+12,!0),crc:X(this,Q).getUint32(t+14,!0),compressedSize:e,uncompressedSize:i,fileNameLength:r,extraLength:s,fileName:this.readString(t+30,r),extra:this.readString(t+30+r,s)}}readCentralDirectory(t){return{versionCreated:X(this,Q).getUint16(t+4,!0),versionNeeded:X(this,Q).getUint16(t+6,!0),fileNameLength:X(this,Q).getUint16(t+28,!0),extraLength:X(this,Q).getUint16(t+30,!0),fileCommentLength:X(this,Q).getUint16(t+32,!0),diskNumber:X(this,Q).getUint16(t+34,!0),internalAttributes:X(this,Q).getUint16(t+36,!0),externalAttributes:X(this,Q).getUint32(t+38,!0),offset:X(this,Q).getUint32(t+42,!0),comments:this.readString(t+46,X(this,Q).getUint16(t+32,!0))}}readEndCentralDirectory(t){const e=X(this,Q).getUint16(t+20,!0);return{numberOfDisks:X(this,Q).getUint16(t+4,!0),centralDirectoryStartDisk:X(this,Q).getUint16(t+6,!0),numberCentralDirectoryRecordsOnThisDisk:X(this,Q).getUint16(t+8,!0),numberCentralDirectoryRecords:X(this,Q).getUint16(t+10,!0),centralDirectorySize:X(this,Q).getUint32(t+12,!0),centralDirectoryOffset:X(this,Q).getUint32(t+16,!0),commentLength:e,comment:this.readString(t+22,e)}}readEndCentralDirectory64(t){const e=Number(X(this,Q).getBigUint64(t+0,!0));return{numberOfDisks:X(this,Q).getUint32(t+16,!0),centralDirectoryStartDisk:X(this,Q).getUint32(t+20,!0),numberCentralDirectoryRecordsOnThisDisk:Number(X(this,Q).getBigUint64(t+24,!0)),numberCentralDirectoryRecords:Number(X(this,Q).getBigUint64(t+32,!0)),centralDirectorySize:Number(X(this,Q).getBigUint64(t+40,!0)),centralDirectoryOffset:Number(X(this,Q).getBigUint64(t+48,!0)),commentLength:e,comment:""}}readString(t,e){return Array.from({length:e},(i,r)=>String.fromCharCode(X(this,Q).getUint8(t+r))).join("")}get entries(){return X(this,ri)}};Q=new WeakMap;Ce=new WeakMap;ri=new WeakMap;$i=new WeakMap;bt=new WeakMap;var H=class ct{static arrayBufferToBase64(e){const i=new Uint8Array(e);return ct.uint8tob64(i)}static async decompress(e){const i=e[0]===31&&e[1]===139&&e[2]===8?"gzip":e[0]===120&&(e[1]===1||e[1]===94||e[1]===156||e[1]===218)?"deflate":"deflate-raw",r=new DecompressionStream(i),s=r.writable.getWriter();s.write(e).catch(console.error);const n=s.close().catch(console.error),a=new Response(r.readable),o=new Uint8Array(await a.arrayBuffer());return await n,o}static async decompressToBuffer(e){const i=await ct.decompress(e);return i.buffer.slice(i.byteOffset,i.byteOffset+i.byteLength)}static async readMatV4(e,i=!1){let r=e.byteLength;if(r<40)throw new Error("File too small to be MAT v4: bytes = "+e.byteLength);let s=new DataView(e),n=s.getUint16(0,!0),a=e;if(n===35615||n===8075){const m=await this.decompress(new Uint8Array(e));s=new DataView(m.buffer),n=s.getUint16(0,!0),a=m.buffer,r=a.byteLength}const o=new TextDecoder("utf-8"),l=new Uint8Array(a);let c=0;const h={};function d(m){return Math.floor(m/10)%10}function f(m,p,g){const x=new Uint8Array(l.subarray(p,g));return m===1?new Float32Array(x.buffer):m===2?new Int32Array(x.buffer):m===3?new Int16Array(x.buffer):m===4?new Uint16Array(x.buffer):m===5?new Uint8Array(x.buffer):new Float64Array(x.buffer)}function u(){const m=s.getUint32(c,!0),p=s.getUint32(c+4,!0),g=s.getUint32(c+8,!0),x=s.getUint32(c+12,!0),A=s.getUint32(c+16,!0);if(c+=20,x!==0)throw new Error("Matlab V4 reader does not support imaginary numbers");const y=p*g;if(y<1)throw new Error("mrows * ncols must be greater than one");const v=new Uint8Array(l.subarray(c,c+A));let b=o.decode(v).trim().replaceAll("\0","");i&&(b=b.replaceAll(".","_"));const w=d(m);let C=8;if(w>=1&&w<=2)C=4;else if(w>=3&&w<=4)C=2;else if(w===5)C=1;else if(w!==0)throw new Error("impossible Matlab v4 datatype");if(c+=A,m>50)throw new Error("Does not appear to be little-endian V4 Matlab file");const M=c+y*C;h[b]=f(w,c,M),c=M}for(;c+20<r;)u();return h}static b64toUint8(e){const i=atob(e),r=i.length,s=new Uint8Array(r);for(let n=0;n<r;n++)s[n]=i.charCodeAt(n);return s}static uint8tob64(e){let i="";const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=e.byteLength,n=s%3,a=s-n;let o,l,c,h,d;for(let f=0;f<a;f=f+3)d=e[f]<<16|e[f+1]<<8|e[f+2],o=(d&16515072)>>18,l=(d&258048)>>12,c=(d&4032)>>6,h=d&63,i+=r[o]+r[l]+r[c]+r[h];return n===1?(d=e[a],o=(d&252)>>2,l=(d&3)<<4,i+=r[o]+r[l]+"=="):n===2&&(d=e[a]<<8|e[a+1],o=(d&64512)>>10,l=(d&1008)>>4,c=(d&15)<<2,i+=r[o]+r[l]+r[c]+"="),i}static download(e,i,r){const s=document.createElement("a"),n=Array.isArray(e)?e:[e],a=new Blob(n,{type:r});s.href=URL.createObjectURL(a),s.download=i,s.click()}static readFileAsync(e){return new Promise((i,r)=>{const s=new FileReader;s.onload=()=>{i(s.result)},s.onerror=r,s.readAsArrayBuffer(e)})}static blobToBase64(e){return new Promise(i=>{const r=new FileReader;r.onloadend=()=>i(r.result),r.readAsDataURL(e)})}static async decompressBase64String(e){const i=atob(e),r=new ArrayBuffer(i.length),s=new Uint8Array(r);for(let n=0;n<i.length;n++)s[n]=i.charCodeAt(n);return ct.decompressArrayBuffer(s)}static async compressToBase64String(e){const i=await ct.compressStringToArrayBuffer(e);return ct.uint8tob64(new Uint8Array(i))}static strToU8(e,i){if(i){const l=new Uint8Array(e.length);for(let c=0;c<e.length;++c)l[c]=e.charCodeAt(c);return l}const r=e.length,s=(l,c,h)=>((h==null||h>l.length)&&(h=l.length),new Uint8Array(l.subarray(c,h)));let n=new Uint8Array(e.length+(e.length>>1)),a=0;const o=l=>{n[a++]=l};for(let l=0;l<r;++l){if(a+5>n.length){const h=new Uint8Array(a+8+(r-l<<1));h.set(n),n=h}let c=e.charCodeAt(l);c<128||i?o(c):c<2048?(o(192|c>>6),o(128|c&63)):(c>55295&&c<57344,c=65536+(c&1047552)|e.charCodeAt(++l)&1023,o(240|c>>18),o(128|c>>12&63),o(128|c>>6&63),o(128|c&63))}return s(n,0,a)}static async compress(e,i="gzip"){const r=new CompressionStream(i),s=r.writable.getWriter();s.write(e).catch(console.error);const n=s.close().catch(console.error),o=await new Response(r.readable).arrayBuffer();return await n,o}static async compressStringToArrayBuffer(e){const i=this.strToU8(e);return await this.compress(i)}static isArrayBufferCompressed(e){if(e&&e.byteLength){const i=new Uint8Array(e);return(i[0]<<8|i[1])===8075}else return!1}static strFromU8(e,i){if(i){let r="";for(let s=0;s<e.length;s+=16384)r+=String.fromCharCode.apply(null,e.subarray(s,s+16384));return r}else{const r=(o,l,c)=>((l==null||l<0)&&(l=0),(c==null||c>o.length)&&(c=o.length),new Uint8Array(o.subarray(l,c))),s=o=>{for(let l="",c=0;;){let h=o[c++];const d=(h>127)+(h>223)+(h>239);if(c+d>o.length)return{s:l,r:r(o,c-1)};d?d===3?(h=((h&15)<<18|(o[c++]&63)<<12|(o[c++]&63)<<6|o[c++]&63)-65536,l+=String.fromCharCode(55296|h>>10,56320|h&1023)):d&1?l+=String.fromCharCode((h&31)<<6|o[c++]&63):l+=String.fromCharCode((h&15)<<12|(o[c++]&63)<<6|o[c++]&63):l+=String.fromCharCode(h)}},{s:n,r:a}=s(e);if(a.length)throw new Error("Unexpected trailing bytes in UTF-8 decoding");return n}}static async decompressArrayBuffer(e){const i=await this.decompress(new Uint8Array(e));return this.strFromU8(i)}static arraysAreEqual(e,i){return za(e,i)}static range(e,i,r){return Array.from({length:(i-e)/r+1},(s,n)=>e+n*r)}static sph2cartDeg(e,i){const r=-i*(Math.PI/180),s=(e-90)%360*(Math.PI/180),n=[Math.cos(r)*Math.cos(s),Math.cos(r)*Math.sin(s),Math.sin(r)],a=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);return a<=0||(n[0]/=a,n[1]/=a,n[2]/=a),n}static vox2mm(e,i){const r=de(i);Te(r,r);const s=ae(e[0],e[1],e[2],1);return ve(s,s,r),k(s[0],s[1],s[2])}},vt=F,ce=class fe{static readTRACT(e){const i=e.byteLength;if(i<20)throw new Error("File too small to be niml.tract: bytes = "+i);const r=new DataView(e),s=new Uint8Array(e);let n=0;function a(){for(;n<i&&s[n]!==60;)n++;const p=n;for(;n<i&&s[n]!==62;)n++;return n++,n-p<1?"":new TextDecoder().decode(e.slice(p,n-1)).trim()}let o=a();function l(p){const g=o.indexOf(p);if(g<0)return 0;const x=o.indexOf('"',g)+1,A=o.indexOf('"',x),y=o.slice(x,A);return parseInt(y)}const c=l("N_tracts=");(!o.startsWith("<network")||c<1)&&F.warn("This is not a valid niml.tract file "+o);let h=0;const d=[];d.push(h);const f=[],u=[];for(let p=0;p<c;p++){o=a();const g=l("ni_dimen="),x=l("Bundle_Tag="),A=o.includes("binary.lsbfirst");for(let y=0;y<g;y++){n+=4;const v=r.getUint32(n,A)/3;n+=4;for(let b=0;b<v;b++)f.push(r.getFloat32(n,A)),n+=4,f.push(-r.getFloat32(n,A)),n+=4,f.push(r.getFloat32(n,A)),n+=4;h+=v,d.push(h),u.push(x)}o=a()}const m=[];return m.push({id:"tract",vals:Float32Array.from(u)}),{pts:new Float32Array(f),offsetPt0:new Uint32Array(d),dps:m}}static async readTT(e){let i=new Uint32Array(0),r=new Float32Array(0);const s=await H.readMatV4(e);if(!("trans_to_mni"in s))throw new Error("TT format file must have 'trans_to_mni'");if(!("voxel_size"in s))throw new Error("TT format file must have 'voxel_size'");if(!("track"in s))throw new Error("TT format file must have 'track'");let n=J();const a=s.trans_to_mni;n=Ee(a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]),Te(n,n);function o(l){const c=new DataView(l.buffer),h=[];let d=0,f=0;for(;f<l.length;){h.push(f);const p=c.getUint32(f,!0);f=f+p+13,d+=p}i=new Uint32Array(h.length+1),r=new Float32Array(d);let u=0;for(let p=0;p<h.length;p++){i[p]=u/3;let g=h[p];const x=c.getUint32(g,!0)/3;let A=c.getInt32(g+4,!0),y=c.getInt32(g+8,!0),v=c.getInt32(g+12,!0);g+=16,r[u++]=A,r[u++]=y,r[u++]=v;for(let b=2;b<=x;b++)A=A+c.getInt8(g++),y=y+c.getInt8(g++),v=v+c.getInt8(g++),r[u++]=A,r[u++]=y,r[u++]=v}for(let p=0;p<u;p++)r[p]=r[p]/32;let m=0;for(let p=0;p<u/3;p++){const g=ae(r[m],r[m+1],r[m+2],1);ve(g,g,n),r[m++]=g[0],r[m++]=g[1],r[m++]=g[2]}i[h.length]=u/3}return o(s.track),{pts:r,offsetPt0:i}}static assembleDpgFromMap(e,i){if(!Array.isArray(i)||i.length===0)throw new Error('assembleDpgFromMap: "groups" is empty or missing; cannot assemble dpg.');const r=new Set;for(const n in e)e[n].forEach(a=>r.add(a.id));const s=[];for(const n of r){const a=[];let o=0;for(let h=0;h<i.length;h++){const d=String(i[h].id),u=(e[d]||[]).find(m=>m.id===n);if(u){const m=u.vals instanceof Float32Array?u.vals:Float32Array.from(u.vals);a.push(m),o+=m.length}else{const m=new Float32Array([NaN]);a.push(m),o+=m.length}}const l=new Float32Array(o);let c=0;for(const h of a)l.set(h,c),c+=h.length;s.push({id:n,vals:l})}return s}static async readTRX(e){function i(p){const g=(p&31744)>>10,x=p&1023;return(p>>15?-1:1)*(g?g===31?x?NaN:1/0:Math.pow(2,g-15)*(1+x/1024):6103515625e-14*(x/1024))}let r=0,s=0,n=new Float32Array([]);const a=[],o={},l=[],c=[],h=[];let d=[],f=!1;const u=new An(e);for(let p=0;p<u.entries.length;p++){const g=u.entries[p];if(g.uncompressedSize===0)continue;const x=g.fileName.split("/"),A=x.slice(-1)[0];if(A.startsWith("."))continue;const y=x.slice(-3)[0],v=x.slice(-2)[0],b=A.split(".")[0],w=await g.extract();if(A.includes("header.json")){const T=new TextDecoder().decode(w);d=JSON.parse(T);continue}let C=0,M=[];if(A.endsWith(".uint64")||A.endsWith(".int64")){C=w.length/8,M=new Uint32Array(C);const T=new Uint32Array(w.buffer);let E=0;for(let I=0;I<C;I++)M[I]=T[E],T[E+1]!==0&&(f=!0),E+=2}else if(A.endsWith(".uint32"))M=new Uint32Array(w.buffer);else if(A.endsWith(".uint16"))M=new Uint16Array(w.buffer);else if(A.endsWith(".uint8"))M=new Uint8Array(w.buffer);else if(A.endsWith(".int32"))M=new Int32Array(w.buffer);else if(A.endsWith(".int16"))M=new Int16Array(w.buffer);else if(A.endsWith(".int8"))M=new Int8Array(w.buffer);else if(A.endsWith(".float64"))M=new Float64Array(w.buffer);else if(A.endsWith(".float32"))M=new Float32Array(w.buffer);else if(A.endsWith(".float16")){C=w.length/2,M=new Float32Array(C);const T=new Uint16Array(w.buffer),E=new Float32Array(65536);for(let I=0;I<65536;I++)E[I]=i(I);for(let I=0;I<C;I++)M[I]=E[T[I]]}else continue;if(C=M.length,v.includes("groups")){l.push({id:b,vals:Float32Array.from(M.slice())});continue}if(y.includes("dpg")){const T=String(v);o[T]||(o[T]=[]),o[T].push({id:b,vals:Float32Array.from(M.slice())});continue}if(v.includes("dpv")){h.push({id:b,vals:Float32Array.from(M.slice())});continue}if(v.includes("dps")){c.push({id:b,vals:Float32Array.from(M.slice())});continue}if(A.startsWith("offsets.")){r=C;for(let T=0;T<C;T++)a[T]=M[T]}A.startsWith("positions.3.")&&(s=C,n=new Float32Array(M))}if(r===0||s===0)throw new Error("Failure reading TRX format (no offsets or points).");if(f)throw new Error("Too many vertices: JavaScript does not support 64 bit integers");let m=[];return l.length>0&&o&&Object.keys(o).length>0&&(m=this.assembleDpgFromMap(o,l)),a[r]=s/3,{pts:n,offsetPt0:new Uint32Array(a),dpg:m,dps:c,dpv:h,groups:l,header:d}}static readTXT(e,i=0){const s=new TextDecoder("utf-8").decode(e).split(/\r?\n|\r/).filter(a=>a.trim().length>0);i<=0&&(i=s.length);const n=new Float32Array(i);for(let a=0;a<i&&a<s.length;a++){const o=parseFloat(s[a].trim());n[a]=Number.isFinite(o)?o:0}return n}static readTSF(e,i=0){const r=new Float32Array(i),s=e.byteLength;if(s<20)throw new Error("File too small to be TSF: bytes = "+s);const n=new Uint8Array(e);let a=0;function o(){for(;a<s&&n[a]===10;)a++;const f=a;for(;a<s&&n[a]!==10;)a++;return a++,a-f<1?"":new TextDecoder().decode(e.slice(f,a-1))}let l=o();if(!l.includes("mrtrix track scalars"))throw new Error("Not a valid TSF file");let c=-1;for(;a<s&&!l.includes("END");)if(l=o(),l.toLowerCase().startsWith("file:")&&(c=parseInt(l.split(" ").pop())),l.toLowerCase().startsWith("datatype:")&&!l.endsWith("Float32LE"))throw new Error("Only supports TSF files with Float32LE");if(c<20)throw new Error("Not a valid TSF file (missing file offset)");a=c;const h=new DataView(e);let d=0;for(;a+4<=s&&d<i;){const f=h.getFloat32(a,!0);if(a+=4,isFinite(f))r[d++]=f;else if(!isNaN(f))break}return r}static readTCK(e){const i=e.byteLength;if(i<20)throw new Error("File too small to be TCK: bytes = "+i);const r=new Uint8Array(e);let s=0;function n(){for(;s<i&&r[s]===10;)s++;const m=s;for(;s<i&&r[s]!==10;)s++;return s++,s-m<1?"":new TextDecoder().decode(e.slice(m,s-1))}let a=n();if(!a.includes("mrtrix tracks"))throw new Error("Not a valid TCK file");let o=-1;for(;s<i&&!a.includes("END");)a=n(),a.toLowerCase().startsWith("file:")&&(o=parseInt(a.split(" ").pop()));if(o<20)throw new Error("Not a valid TCK file (missing file offset)");s=o;const l=new DataView(e);let c=0,h=new Uint32Array(i/16),d=0,f=0,u=new Float32Array(i/4);for(h[0]=0;s+12<i;){const m=l.getFloat32(s,!0);s+=4;const p=l.getFloat32(s,!0);s+=4;const g=l.getFloat32(s,!0);if(s+=4,isFinite(m))u[f++]=m,u[f++]=p,u[f++]=g,c++;else if(h[d++]=c,!isNaN(m))break}return u=u.slice(0,f),h=h.slice(0,d),{pts:u,offsetPt0:h}}static async readTRK(e){let i=new DataView(e),r=i.getUint32(0,!0);if(r!==1128354388){let I;if(r===4247762216)throw new Error("zstd TRK decompression is not supported");I=await H.decompress(new Uint8Array(e)),e=I.buffer,i=new DataView(e),r=i.getUint32(0,!0)}const s=i.getUint32(992,!0),n=i.getUint32(996,!0);if(s>3||n!==1e3||r!==1128354388)throw new Error(`Not a valid TRK file expected version ≤3 (${s}), header size 1000 (${n}) and magic of 1128354388 (${r})`);const a=i.getInt16(36,!0),o=[];for(let I=0;I<a;I++){const S=new Uint8Array(e.slice(38+I*20,58+I*20)),U=new TextDecoder().decode(S).split("\0").shift();o.push({id:U.trim(),vals:[]})}const l=i.getFloat32(12,!0),c=i.getFloat32(16,!0),h=i.getFloat32(20,!0),d=Ee(1/l,0,0,-.5,0,1/c,0,-.5,0,0,1/h,-.5,0,0,0,1),f=i.getInt16(238,!0),u=[];for(let I=0;I<f;I++){const S=new Uint8Array(e.slice(240+I*20,260+I*20)),U=new TextDecoder().decode(S).split("\0").shift();u.push({id:U.trim(),vals:[]})}const m=J();for(let I=0;I<16;I++)m[I]=i.getFloat32(440+I*4,!0);m[15]===0&&(F.warn("TRK vox_to_ras not set"),qs(m));const p=J();Qs(p,d,m);let g=null,x=null;g=new Int32Array(e.slice(n)),x=new Float32Array(g.buffer);const A=g.length;if(A<1)throw new Error("Empty TRK file.");let y=0,v=0,b=new Uint32Array(g.length/4),w=0,C=new Float32Array(g.length),M=0;for(;y<A;){const I=g[y];y=y+1,b[w++]=v;for(let S=0;S<I;S++){const U=x[y+0],B=x[y+1],V=x[y+2];if(y+=3,C[M++]=U*p[0]+B*p[1]+V*p[2]+p[3],C[M++]=U*p[4]+B*p[5]+V*p[6]+p[7],C[M++]=U*p[8]+B*p[9]+V*p[10]+p[11],a>0)for(let R=0;R<a;R++)o[R].vals.push(x[y]),y++;v++}if(f>0)for(let S=0;S<f;S++)u[S].vals.push(x[y]),y++}const T=[];for(let I=0;I<u.length;I++)T.push({id:u[I].id,vals:Float32Array.from(u[I].vals)});const E=[];for(let I=0;I<o.length;I++)E.push({id:o[I].id,vals:Float32Array.from(o[I].vals)});return b[w++]=v,C=C.slice(0,M),b=b.slice(0,w),{pts:C,offsetPt0:b,dps:T,dpv:E}}static readTxtVTK(e){const s=new TextDecoder("utf-8").decode(e).split(`
|
|
58
|
+
`);if(s.length<7||!s[0].startsWith("# vtk DataFile"))throw new Error("Invalid VTK image");if(!s[2].startsWith("ASCII"))throw new Error("Not ASCII VTK mesh");let a=3;for(;s[a].length<1;)a++;if(!s[a].includes("POLYDATA"))throw new Error("Not ASCII VTK polydata");for(a++;s[a].length<1;)a++;if(!s[a].startsWith("POINTS"))throw new Error("Not VTK POINTS");let o=s[a].trim().split(/\s+/);const l=parseInt(o[1]),c=l*3,h=new Float32Array(l*3);let d=0;for(;d<l*3;){a++;const p=s[a].trim().trim().split(/\s+/);for(let g=0;g<p.length&&!(d>=c);g++)h[d]=parseFloat(p[g]),d++}const f=[];for(a++;s[a].length<1;)a++;if(s[a].startsWith("METADATA")){for(;s[a].length>1;)a++;a++}if(o=s[a].trim().split(/\s+/),a++,o[0].includes("LINES")){const m=parseInt(o[1]);if(m<1)throw new Error("Corrupted VTK ASCII");let p=s[a].trim();const g=[];let x=[];if(p.startsWith("OFFSETS")){a++;let A=0;for(;A<m;){p=s[a].trim(),a++;const y=p.trim().split(/\s+/);for(let v=0;v<y.length&&(g[A]=parseInt(y[v]),A++,!(A>=m));v++);}x=Array.from(h)}else{let A=function(){p=s[a].trim();const w=p.trim().split(/\s+/);v=[];for(let C=0;C<w.length;C++)v.push(parseInt(w[C]));b=0,a++},y=0;g[0]=0;let v=[],b=0;A();for(let w=0;w<m;w++){b>=v.length&&A();const C=v[b++];y+=C,g[w+1]=y;for(let M=0;M<C;M++){b>=v.length&&A();const T=v[b++]*3;x.push(h[T+0]),x.push(h[T+1]),x.push(h[T+2])}}}return{pts:Float32Array.from(x),offsetPt0:Uint32Array.from(g)}}else if(o[0].includes("TRIANGLE_STRIPS")){const m=parseInt(o[1]);for(let p=0;p<m;p++){const g=s[a].trim();a++;const x=g.trim().split(/\s+/),A=parseInt(x[0])-2;let y=1;for(let v=0;v<A;v++)v%2?(f.push(parseInt(x[y+2])),f.push(parseInt(x[y+1])),f.push(parseInt(x[y]))):(f.push(parseInt(x[y])),f.push(parseInt(x[y+1])),f.push(parseInt(x[y+2]))),y+=1}}else if(o[0].includes("POLYGONS")){const m=parseInt(o[1]);for(let p=0;p<m;p++){const g=s[a].trim();a++;const x=g.trim().split(/\s+/),A=parseInt(x[0])-2,y=parseInt(x[1]);let v=parseInt(x[2]);for(let b=0;b<A;b++){const w=parseInt(x[3+b]);f.push(y),f.push(v),f.push(w),v=w}}}else throw new Error("Unsupported ASCII VTK datatype "+o[0]);const u=new Uint32Array(f);return{positions:h,indices:u}}static async readLayer(e="",i,r,s=.5,n="warm",a="winter",o=!1,l=null,c=null,h=0){const d={...zc,colormapInvert:!1,colormapType:0,isTransparentBelowCalMin:!0,isAdditiveBlend:!1,colorbarVisible:!0,colormapLabel:null},f=/(?:\.([^.]+))?$/;let u=f.exec(e)[1];u=u.toUpperCase(),u==="GZ"&&(u=f.exec(e.slice(0,-3))[1],u=u.toUpperCase());const m=r.vertexCount/3;if(r.offsetPt0){const x=e.split("/");let A="Unknown";if(x.length>1&&x.pop()&&(A=A.split(".").slice(0,-1).join(".")),u==="TXT"){const C=r.offsetPt0.length-1,M=fe.readTXT(i,C);if(M.length!==C)throw new Error(`TXT file has ${M.length} items, expected one per streamline (${C}).`);r.dps||(r.dps=[]);const T=M.reduce((I,S)=>Math.min(I,S)),E=M.reduce((I,S)=>Math.max(I,S));return r.dps.push({id:A,vals:Float32Array.from(M.slice()),global_min:T,global_max:E,cal_min:T,cal_max:E}),d}if(u==="NII"){const C=await fe.readNII(i,r.pts,""),M=C.reduce((E,I)=>Math.min(E,I)),T=C.reduce((E,I)=>Math.max(E,I));return r.dpv.push({id:A,vals:Float32Array.from(C.slice()),global_min:M,global_max:T,cal_min:M,cal_max:T}),d}if(u!=="TSF")throw new Error("readLayer for streamlines only supports TSF and TXT files.");const y=r.pts.length/3,v=fe.readTSF(i,y);r.dpv||(r.dpv=[]);const b=v.reduce((C,M)=>Math.min(C,M)),w=v.reduce((C,M)=>Math.max(C,M));return r.dpv.push({id:A,vals:Float32Array.from(v.slice()),global_min:b,global_max:w,cal_min:b,cal_max:w}),d}if(m<3){F.error("n_vert < 3 in layer");return}if(u==="MZ3"){const x=await fe.readMZ3(i,m);d.values=x.scalars,"colormapLabel"in x&&(d.colormapLabel=x.colormapLabel)}else if(u==="ANNOT"){const x=fe.readANNOT(i,m,!0);x instanceof Uint32Array?d.values=x:(d.values=x.scalars,d.colormapLabel=x.colormapLabel)}else if(u==="CRV"||u==="CURV"||u==="THICKNESS"||u==="AREA")d.values=fe.readCURV(i,m),d.isTransparentBelowCalMin=!1;else if(u==="GII"){const x=await fe.readGII(i,m);d.values=x.scalars,d.colormapLabel=x.colormapLabel}else if(u==="MGH"||u==="MGZ"){const x=await fe.readMGH(i,m,!0);"scalars"in x?(d.values=x.scalars,d.colormapLabel=x.colormapLabel):d.values=x}else if(u==="NII")d.values=await fe.readNII(i,r.pts,r.anatomicalStructurePrimary);else if(u==="SMP")d.values=await fe.readSMP(i,m);else if(u==="STC")d.values=fe.readSTC(i,m);else if(fe.isCurv(i))d.values=fe.readCURV(i,m),d.isTransparentBelowCalMin=!1;else return F.warn("Unknown layer overlay format "+e),d;if(!d.values){F.error("no values in layer");return}d.nFrame4D=d.values.length/m,d.frame4D=0,d.outlineBorder=h;let p=d.values[0],g=d.values[0];for(let x=0;x<d.values.length;x++)p=Math.min(p,d.values[x]),g=Math.max(g,d.values[x]);return d.global_min=p,d.global_max=g,d.cal_min=l||0,l||(d.cal_min=p),d.cal_max=c||0,c||(d.cal_max=g),d.cal_minNeg=NaN,d.cal_maxNeg=NaN,d.opacity=s,d.colormap=n,d.colormapNegative=a,d.useNegativeCmap=o,d}static async readSMP(e,i){const r=e.byteLength;let s=new DataView(e),n=s.getUint16(0,!0);if(n>5){const d=await H.decompress(new Uint8Array(e));s=new DataView(d.buffer),n=s.getUint16(0,!0),e=d.buffer}n>5&&F.error("Unsupported or invalid BrainVoyager SMP version "+n);const a=s.getUint32(2,!0);a!==i&&F.error("SMP file has "+a+" vertices, background mesh has "+i);const o=s.getUint16(6,!0),l=new Float32Array(a*o);let c=9;function h(){const d=c;for(;c<r&&s.getUint8(c)!==0;)c++;return c++,new TextDecoder().decode(e.slice(d,c-1))}h();for(let d=0;d<o;d++){const f={};f.mapType=s.getUint32(c,!0),c+=4,n>=3&&f.mapType===3&&(f.nLags=s.getUint32(c,!0),c+=4,f.mnLag=s.getUint32(c,!0),c+=4,f.mxLag=s.getUint32(c,!0),c+=4,f.ccOverlay=s.getUint32(c,!0),c+=4),f.clusterSize=s.getUint32(c,!0),c+=4,f.clusterCheck=s.getUint8(c),c+=1,f.critThresh=s.getFloat32(c,!0),c+=4,f.maxThresh=s.getFloat32(c,!0),c+=4,n>=4&&(f.includeValuesGreaterThreshMax=s.getUint32(c,!0),c+=4),f.df1=s.getUint32(c,!0),c+=4,f.df2=s.getUint32(c,!0),c+=4,n>=5?(f.posNegFlag=s.getUint32(c,!0),c+=4):f.posNegFlag=3,f.cortexBonferroni=s.getUint32(c,!0),c+=4,f.posMinRGB=[0,0,0],f.posMaxRGB=[0,0,0],f.negMinRGB=[0,0,0],f.negMaxRGB=[0,0,0],n>=2&&(f.posMinRGB[0]=s.getUint8(c),c++,f.posMinRGB[1]=s.getUint8(c),c++,f.posMinRGB[2]=s.getUint8(c),c++,f.posMaxRGB[0]=s.getUint8(c),c++,f.posMaxRGB[1]=s.getUint8(c),c++,f.posMaxRGB[2]=s.getUint8(c),c++,n>=4&&(f.negMinRGB[0]=s.getUint8(c),c++,f.negMinRGB[1]=s.getUint8(c),c++,f.negMinRGB[2]=s.getUint8(c),c++,f.negMaxRGB[0]=s.getUint8(c),c++,f.negMaxRGB[1]=s.getUint8(c),c++,f.negMaxRGB[2]=s.getUint8(c),c++),f.enableSMPColor=s.getUint8(c),c++,n>=4&&(f.lut=h()),f.colorAlpha=s.getFloat32(c,!0),c+=4),f.name=h();const u=new Float32Array(e,c,a);l.set(u,d*a),c+=a*4}return l}static readSTC(e,i){const r=new DataView(e),s=r.getInt32(8,!1);if(s!==i)throw new Error("Overlay has "+s+" vertices, expected "+i);let n=12+s*4;const a=r.getUint32(n,!1);n+=4;const o=new Float32Array(a*s);for(let l=0;l<a*s;l++)o[l]=r.getFloat32(n,!1),n+=4;return o}static isCurv(e){const i=new DataView(e),r=i.getUint8(0),s=i.getUint8(1),n=i.getUint8(2);return r!==255||s!==255||n!==255?(vt.debug("Unable to recognize file type: does not appear to be FreeSurfer format."),!1):!0}static readCURV(e,i){const r=new DataView(e),s=r.getUint8(0),n=r.getUint8(1),a=r.getUint8(2),o=r.getUint32(3,!1),l=r.getUint32(11,!1);if((s!==255||n!==255||a!==255)&&vt.debug("Unable to recognize file type: does not appear to be FreeSurfer format."),i!==o)throw new Error("CURV file has different number of vertices ( "+o+")than mesh ("+i+")");if(e.byteLength<15+4*o*l)throw new Error("CURV file smaller than specified");const c=new Float32Array(l*o);let h=15;for(let m=0;m<l*o;m++)c[m]=r.getFloat32(h,!1),h+=4;let d=c[0],f=c[0];for(let m=0;m<c.length;m++)d=Math.min(d,c[m]),f=Math.max(f,c[m]);const u=1/(f-d);for(let m=0;m<c.length;m++)c[m]=1-(c[m]-d)*u;return c}static readANNOT(e,i,r=!1){const s=new DataView(e),n=s.getUint32(0,!1),a=this.decimateLayerVertices(n,i);if(i!==a)throw new Error("ANNOT file has different number of vertices than mesh");if(e.byteLength<4+8*n)throw new Error("ANNOT file smaller than specified");let o=0;const l=new Uint32Array(n);for(let v=0;v<n;v++){const b=s.getUint32(o+=4,!1);l[b]=s.getUint32(o+=4,!1)}if(!r)return l;let c=0;try{c=s.getInt32(o+=4,!1)}catch{return l}if(c!==1||s.getInt32(o+=4,!1)>0)return l;const f=s.getInt32(o+=4,!1),u=s.getInt32(o+=4,!1);o+=u;const m=s.getInt32(o+=4,!1);if(m<1)return l;const p={R:Array(f).fill(0),G:Array(f).fill(0),B:Array(f).fill(0),A:Array(f).fill(0),I:Array(f).fill(0),labels:Array(f).fill("")};for(let v=0;v<m;v++){const b=s.getInt32(o+=4,!1),w=s.getInt32(o+=4,!1);o+=4;let C="";for(let S=0;S<w;S++){const U=s.getUint8(o++);if(U===0)break;C+=String.fromCharCode(U)}o-=4;const M=s.getInt32(o+=4,!1),T=s.getInt32(o+=4,!1),E=s.getInt32(o+=4,!1),I=s.getInt32(o+=4,!1);if(b<0||b>=f){F.warn("annot entry out of range");continue}p.R[b]=M,p.G[b]=T,p.B[b]=E,p.A[b]=I,p.I[b]=(I<<24)+(E<<16)+(T<<8)+M,p.labels[b]=C}let g=!0;for(let v=0;v<f;v++)p.A[v]>0&&(g=!1);if(g)for(let v=0;v<f;v++)p.A[v]=255;const x=new Float32Array(n);x.fill(-1);let A=0;for(let v=0;v<i;v++){const b=l[v];for(let w=0;w<f;w++)if(p.I[w]===b){x[v]=w;break}x[v]<0&&(A++,x[v]=0)}A>0&&F.error(`annot vertex colors do not match ${A} of ${n} vertices.`);for(let v=0;v<f;v++)p.I[v]=v;const y=re.makeLabelLut(p);return{scalars:x,colormapLabel:y}}static readNV(e){const i=e.byteLength,r=new Uint8Array(e);let s=0;function n(){for(;s<i&&r[s]===10;)s++;const f=s;for(;s<i&&r[s]!==10;)s++;return s++,s-f<1?"":new TextDecoder().decode(e.slice(f,s-1))}let a=0,o=0,l=0,c=0,h,d;for(;s<i;){const f=n();if(f.startsWith("#"))continue;const u=f.trim().split(/\s+/);if(a<1){a=parseInt(u[0]),h=new Float32Array(a*3);continue}if(l<a*3){h[l]=parseFloat(u[0]),h[l+1]=parseFloat(u[1]),h[l+2]=parseFloat(u[2]),l+=3;continue}if(o<1){o=parseInt(u[0]),d=new Uint32Array(o*3);continue}if(c>=o*3)break;d[c+2]=parseInt(u[0])-1,d[c+1]=parseInt(u[1])-1,d[c+0]=parseInt(u[2])-1,c+=3}return{positions:h,indices:d}}static readASC(e){const i=e.byteLength,r=new Uint8Array(e);let s=0;function n(){for(;s<i&&r[s]===10;)s++;const u=s;for(;s<i&&r[s]!==10;)s++;return s++,s-u<1?"":new TextDecoder().decode(e.slice(u,s-1))}let a=n();a.startsWith("#!ascii")||F.warn("Invalid ASC mesh"),a=n();let o=a.trim().split(/\s+/);const l=parseInt(o[0]),c=parseInt(o[1]),h=new Float32Array(l*3);let d=0;for(let u=0;u<l;u++)a=n(),o=a.trim().split(/\s+/),h[d]=parseFloat(o[0]),h[d+1]=parseFloat(o[1]),h[d+2]=parseFloat(o[2]),d+=3;const f=new Uint32Array(c*3);d=0;for(let u=0;u<c;u++)a=n(),o=a.trim().split(/\s+/),f[d]=parseInt(o[0]),f[d+1]=parseInt(o[1]),f[d+2]=parseInt(o[2]),d+=3;return{positions:h,indices:f}}static readVTK(e){const i=e.byteLength;if(i<20)throw new Error("File too small to be VTK: bytes = "+e.byteLength);const r=new Uint8Array(e);let s=0;function n(p=!0){if(p)for(;s<i&&r[s]===10;)s++;const g=s;for(;s<i&&r[s]!==10;)s++;return s++,s-g<1?"":new TextDecoder().decode(e.slice(g,s-1))}let a=n();if(!a.startsWith("# vtk DataFile"))throw new Error("Invalid VTK mesh");if(a=n(!1),a=n(),a.startsWith("ASCII"))return fe.readTxtVTK(e);if(!a.startsWith("BINARY"))throw new Error("Invalid VTK image, expected ASCII or BINARY "+a);if(a=n(),!a.includes("POLYDATA"))throw new Error("Only able to read VTK POLYDATA "+a);a=n(),(!a.includes("POINTS")||!a.includes("double")&&!a.includes("float"))&&F.warn("Only able to read VTK float or double POINTS"+a);const o=a.includes("double");let l=a.trim().split(/\s+/);const h=parseInt(l[1])*3,d=new Float32Array(h),f=new DataView(e);if(o)for(let p=0;p<h;p++)d[p]=f.getFloat64(s,!1),s+=8;else for(let p=0;p<h;p++)d[p]=f.getFloat32(s,!1),s+=4;a=n(),l=a.trim().split(/\s+/);const u=[];if(l[0].includes("LINES")){const p=parseInt(l[1]),g=s;if(a=n(),a.startsWith("OFFSETS")){let v=!1;a.includes("int64")&&(v=!0);const b=new Uint32Array(p);if(v){let C=!1;for(let M=0;M<p;M++){let T=f.getInt32(s,!1);T!==0&&(C=!0),s+=4,T=f.getInt32(s,!1),s+=4,b[M]=T}C&&F.warn("int32 overflow: JavaScript does not support int64")}else for(let C=0;C<p;C++){const M=f.getInt32(s,!1);s+=4,b[C]=M}return{pts:d,offsetPt0:b}}s=g;let x=0;const A=[],y=[];A.push(x);for(let v=0;v<p;v++){const b=f.getInt32(s,!1);s+=4,x+=b,A.push(x);for(let w=0;w<b;w++){const C=f.getInt32(s,!1)*3;s+=4,y.push(d[C+0]),y.push(d[C+1]),y.push(d[C+2])}}return{pts:Float32Array.from(y),offsetPt0:Uint32Array.from(A)}}else if(l[0].includes("TRIANGLE_STRIPS")){const p=parseInt(l[1]);for(let g=0;g<p;g++){const x=f.getInt32(s,!1)-2;s+=4;for(let A=0;A<x;A++)A%2?(u.push(f.getInt32(s+8,!1)),u.push(f.getInt32(s+4,!1)),u.push(f.getInt32(s,!1))):(u.push(f.getInt32(s,!1)),u.push(f.getInt32(s+4,!1)),u.push(f.getInt32(s+8,!1))),s+=4;s+=8}}else if(l[0].includes("POLYGONS")){const p=parseInt(l[1]),g=s,x=n();if(x.startsWith("OFFSETS")){let A=x.includes("int64");const y=new Uint32Array(p);let v=!1;for(let M=0;M<p;M++)A&&(f.getInt32(s,!1)!==0&&(v=!0),s+=4),y[M]=f.getInt32(s,!1),s+=4;if(!Number.isSafeInteger(p)||p>=2147483648||v)throw new Error("values exceed 2GB limit");const b=n();if(!b.startsWith("CONNECTIVITY"))throw new Error("Expected CONNECTIVITY after OFFSETS");A=b.includes("int64");const w=y[p-1],C=new Uint32Array(w);for(let M=0;M<w;M++)A&&(s+=4),C[M]=f.getInt32(s,!1),s+=4;for(let M=0;M<p;M++){const T=M===0?0:y[M-1],E=y[M];for(let I=1;I<E-T-1;I++)u.push(C[T]),u.push(C[T+I]),u.push(C[T+I+1])}}else{s=g;for(let A=0;A<p;A++){const y=f.getInt32(s,!1)-2;if(A===0&&y>65535)throw new Error("Invalid VTK binary polygons using little-endian data (MRtrix)");s+=4;const v=f.getInt32(s,!1);s+=4;let b=f.getInt32(s,!1);s+=4;for(let w=0;w<y;w++){const C=f.getInt32(s,!1);s+=4,u.push(v,b,C),b=C}}}}else throw new Error("Unsupported binary VTK datatype "+l[0]);const m=new Uint32Array(u);return{positions:d,indices:m}}static readWRL(e){const i=new TextDecoder("utf-8").decode(e),r=/coord\s+Coordinate\s*\{\s*point\s*\[([\s\S]*?)\]/,s=/coordIndex\s*\[([\s\S]*?)\]/,n=/color\s+Color\s*\{\s*color\s*\[([\s\S]*?)\]/,a=r.exec(i),o=s.exec(i),l=n.exec(i);if(!a||!o)throw new Error("Invalid WRL file: Could not find vertices or indices.");const c=new Float32Array(a[1].trim().split(/[\s,]+/).map(Number));let h=null;if(l){h=new Float32Array(l[1].trim().split(/[\s,]+/).map(Number));const f=c.length/3;h.length!==f*3&&(console.warn(`Unexpected color count: expected ${f*3}, got ${h.length}`),h=null)}const d=new Uint32Array(o[1].trim().split(/[\s,]+/).map(Number).filter(f=>f!==-1));return{positions:c,indices:d,colors:h}}static readDFS(e){const i=new DataView(e),r=i.getUint32(0,!0),s=i.getUint16(4,!0);(r!==1599292996||s!==17740)&&F.warn("Not a little-endian brainsuite DFS mesh");const n=i.getUint32(12,!0),a=i.getUint32(24,!0),o=i.getUint32(28,!0),l=i.getUint32(48,!0);let c=n;const h=new Uint32Array(e,c,a*3);c+=a*3*4;const d=new Float32Array(e,c,o*3);for(let u=0;u<o*3;u+=3){const m=d[u];d[u]=d[u+1],d[u+1]=m}let f;return l>=0&&(f=new Float32Array(e,l,o*3)),{positions:d,indices:h,colors:f}}static async readMZ3(e,i=0){if(e.byteLength<20)throw new Error("File too small to be mz3: bytes = "+e.byteLength);let r=new DataView(e),s=e,n=r.getUint16(0,!0);if(n===35615||n===8075){const T=await H.decompress(new Uint8Array(e));r=new DataView(T.buffer),n=r.getUint16(0,!0),s=T.buffer}const a=r.getUint16(2,!0),o=r.getUint32(4,!0);let l=r.getUint32(8,!0);const c=r.getUint32(12,!0);if(vt.debug("MZ3 magic %d attr %d face %d vert %d skip %d",n,a,o,l,c),n!==23117)throw new Error("Invalid MZ3 file");const h=(a&1)!==0,d=(a&2)!==0,f=(a&4)!==0;let u=(a&8)!==0;const m=(a&16)!==0,p=(a&32)!==0,g=(a&64)!==0;if(vt.debug(`isFace=${h} isVert=${d} isRGBA=${f} isSCALAR=${u} isDOUBLE=${m} isAOMAP=${p} isLOOKUP=${g}`),a>127)throw new Error("Unsupported future version of MZ3 file");let x=4;m&&(x=8);let A=0;if(i>0&&!h&&o<1&&!f&&(u=!0),u){const T=i||l,E=16+c+(h?o*12:0)+(d?T*12:0)+(f?T*4:0),I=Math.floor((s.byteLength-E)/x);l!==i&&I%i===0&&(l=i),A=Math.floor(I/l),A<1&&(F.warn("Corrupt MZ3: file reports NSCALAR but not enough bytes"),u=!1)}if(l<3&&i<3)throw new Error("Not a mesh MZ3 file (maybe scalar)");i>0&&i!==l&&F.warn("Layer has "+l+"vertices, but background mesh has "+i);let y=16+c;const v=new DataView(s);let b=null;if(h){b=new Uint32Array(o*3);for(let T=0;T<o*3;T++)b[T]=v.getUint32(y,!0),y+=4}let w=null;if(d){w=new Float32Array(l*3);for(let T=0;T<l*3;T++)w[T]=v.getFloat32(y,!0),y+=4}let C=null;if(f){C=new Float32Array(l*3);for(let T=0;T<l;T++){for(let E=0;E<3;E++)C[T*3+E]=v.getUint8(y++)/255;y++}}let M=new Float32Array;if(u&&A>0)if(m){const T=new Float64Array(A*l);for(let E=0;E<A*l;E++)T[E]=v.getFloat64(y,!0),y+=8;M=Float32Array.from(T)}else{M=new Float32Array(A*l);for(let T=0;T<A*l;T++)M[T]=v.getFloat32(y,!0),y+=4}if(i>0&&g&&u){const T=new TextDecoder("utf-8"),E=new Uint8Array(s,16,c),I=T.decode(E),S=JSON.parse(I),U=re.makeLabelLut(S);return{scalars:M,colormapLabel:U}}if(i>0&&f&&u){let T=M[0];for(let S=0;S<l;S++)T=Math.max(T,M[S]);const E={R:[],G:[],B:[],A:[],I:[],labels:[]};for(let S=0;S<=T;S++)for(let U=0;U<l;U++)if(S===M[U]){const B=U*3;E.I.push(S),E.R.push(C[B]*255),E.G.push(C[B+1]*255),E.B.push(C[B+2]*255),E.A.push(255),E.labels.push(`${S}`);break}const I=re.makeLabelLut(E);return{scalars:M,colormapLabel:I}}return i>0?{scalars:M}:{positions:w,indices:b,scalars:M,colors:C}}static readPLY(e){const i=e.byteLength,r=new Uint8Array(e);let s=0;function n(){for(;s<i&&r[s]===10;)s++;const R=s;for(;s<i&&r[s]!==10;)s++;return s++,s-R<1?"":new TextDecoder().decode(e.slice(R,s-1))}let a=n();if(!a.startsWith("ply"))throw new Error("Not a valid PLY file");a=n();const o=a.includes("ascii");function l(R){if(R==="char"||R==="uchar"||R==="int8"||R==="uint8")return 1;if(R==="short"||R==="ushort"||R==="int16"||R==="uint16")return 2;if(R==="int"||R==="uint"||R==="int32"||R==="uint32"||R==="float"||R==="float32")return 4;if(R==="double")return 8;throw new Error("Unknown data type: "+R)}const c=a.includes("binary_little_endian");let h=0,d=!1,f=0,u=0,m=0,p=0,g=0,x=0,A=0;const y=[];let v=0,b=-1,w=-1,C=-1,M=!1;for(;s<i&&!a.startsWith("end_header");){if(a=n(),a.startsWith("comment"))continue;let R=a.split(/\s/);if(a.startsWith("element vertex"))for(h=parseInt(R[R.length-1]),a=n(),R=a.split(/\s/),v=0,y.length=0;a.startsWith("property");){const P=R[1],L=R[2];y.push(L),L==="red"?(b=v,M=!0):L==="green"?(w=v,M=!0):L==="blue"&&(C=v,M=!0),L==="x"&&P.startsWith("double")?d=!0:L==="x"&&!P.startsWith("float")&&F.error("Error: expect ply xyz to be float or double: "+a);const N=l(P);f+=N,v+=N,a=n(),R=a.split(/\s/)}if(a.startsWith("element face"))for(A=parseInt(R[R.length-1]),a=n(),R=a.split(/\s/);a.startsWith("property");){if(R[1]==="list")m=l(R[2]),p=l(R[3]),u+=m+3*p;else{const P=l(R[1]);u+=P,p===0&&(g+=P,x++)}a=n(),R=a.split(/\s/)}}if(o){A<1&&F.error(`Malformed ply format: faces ${A} `);const R=new Float32Array(h*3);let P;const L=y.indexOf("x"),N=y.indexOf("y"),Y=y.indexOf("z"),_=y.indexOf("red"),z=y.indexOf("green"),W=y.indexOf("blue");_!==-1&&z!==-1&&W!==-1&&(P=new Float32Array(h*3),M=!0);let K=0;for(let ue=0;ue<h;ue++){a=n();const le=a.split(/\s/),je=L>=0?parseFloat(le[L]):parseFloat(le[0]),at=N>=0?parseFloat(le[N]):parseFloat(le[1]),_e=Y>=0?parseFloat(le[Y]):parseFloat(le[2]);if(R[K]=je,R[K+1]=at,R[K+2]=_e,M&&P){const Fe=_>=0?parseInt(le[_]):0,Gt=z>=0?parseInt(le[z]):0,xa=W>=0?parseInt(le[W]):0,Ci=ue*3;P[Ci]=Fe/255,P[Ci+1]=Gt/255,P[Ci+2]=xa/255}K+=3}let Z=new Uint32Array(A*3),q=0;for(let ue=0;ue<A;ue++){a=n();const le=a.split(/\s/),je=parseInt(le[x])-2;if(je<1)break;if(q+je*3>Z.length){const Fe=new Uint32Array(Z.length+Z.length);Fe.set(Z),Z=Fe.slice()}const at=parseInt(le[x+1]);let _e=parseInt(le[x+2]);for(let Fe=0;Fe<je;Fe++){const Gt=parseInt(le[x+3+Fe]);Z[q+0]=at,Z[q+1]=_e,Z[q+2]=Gt,_e=Gt,q+=3}}Z.length!==q&&(Z=Z.slice(0,q));const te={positions:R,indices:Z};return M&&(te.colors=typeof P<"u"?P:void 0),te}(f<12||m<1||p<1||A<1)&&F.warn(`Malformed ply format: stride ${f} count ${m} iBytes ${p} iStrideBytes ${u} iPadBytes ${g} faces ${A}`);const T=new DataView(e);let E,I;if(M&&(I=new Float32Array(h*3)),s%4===0&&f===12&&c)E=new Float32Array(e,s,h*3),s+=h*f;else{E=new Float32Array(h*3);let R=0;for(let P=0;P<h;P++){if(d?(E[R]=T.getFloat64(s,c),E[R+1]=T.getFloat64(s+8,c),E[R+2]=T.getFloat64(s+16,c)):(E[R]=T.getFloat32(s,c),E[R+1]=T.getFloat32(s+4,c),E[R+2]=T.getFloat32(s+8,c)),M&&I){const L=s,N=b>=0?T.getUint8(L+b):0,Y=w>=0?T.getUint8(L+w):0,_=C>=0?T.getUint8(L+C):0,z=P*3;I[z]=N/255,I[z+1]=Y/255,I[z+2]=_/255}R+=3,s+=f}}const S=new Uint32Array(A*3);let U=!0,B=0;if(m===1&&p===4&&u===13)for(let R=0;R<A;R++){const P=T.getUint8(s);s+=m,P!==3&&(U=!1),S[B]=T.getUint32(s,c),s+=4,S[B+1]=T.getUint32(s,c),s+=4,S[B+2]=T.getUint32(s,c),s+=4,B+=3}else{let R=s;for(let P=0;P<A;P++){s=R+g;let L=0;m===1?L=T.getUint8(s):m===2?L=T.getUint16(s,c):m===4&&(L=T.getUint32(s,c)),s+=m,L!==3&&(U=!1);for(let N=0;N<3;N++)p===1?S[B]=T.getUint8(s):p===2?S[B]=T.getUint16(s,c):p===4&&(S[B]=T.getUint32(s,c)),B++,s+=p;R+=u}}U||F.warn("Only able to read PLY meshes limited to triangles.");const V={positions:E,indices:S};return M&&typeof I<"u"&&(V.colors=I),V}static readICO(e){const s=new TextDecoder("utf-8").decode(e).split(`
|
|
59
|
+
`);let n=s[0].trim().split(/\s+/);n.length>1&&F.warn("This is not a valid FreeSurfer ICO/TRI mesh.");const a=parseInt(n[0]),o=new Float32Array(a*3);let l=1;for(let d=0;d<a;d++){const f=s[l].trim().split(/\s+/);l++;let u=parseInt(f[0])-1;const m=parseFloat(f[1]),p=parseFloat(f[2]),g=parseFloat(f[3]);if(u<0||u>=a){F.error("ICO vertices corrupted");break}u*=3,o[u]=m,o[u+1]=p,o[u+2]=g}n=s[l].trim().split(/\s+/),l++;const c=parseInt(n[0]),h=new Uint32Array(c*3);for(let d=0;d<c;d++){const f=s[l].trim().split(/\s+/);l++;let u=parseInt(f[0])-1;const m=parseInt(f[1])-1,p=parseInt(f[2])-1,g=parseInt(f[3])-1;if(u<0||u>=c){F.error("ICO indices corrupted");break}u*=3,h[u]=m,h[u+1]=p,h[u+2]=g}for(let d=0;d<h.length;d+=3){const f=h[d];h[d]=h[d+1],h[d+1]=f}return{positions:o,indices:h}}static readGEO(e,i=!1){const n=new TextDecoder("utf-8").decode(e).split(`
|
|
60
|
+
`),a=n[0].trim().split(/\s+/),o=parseInt(a[0]);let l=parseInt(a[1]),c=parseInt(a[2]);const h=parseInt(a[3]);(o>1||h!==c*3)&&F.warn("Multi-part BYU/GEO header or not a triangular mesh.");const d=[];l*=3;let f=0,u=2;for(;f<l;){const A=n[u].trim().split(/\s+/);u++;for(let y=0;y<A.length&&(d.push(parseFloat(A[y])),f++,!(f>=l));y++);}const m=[];c*=3;let p=0;for(;p<c;){const A=n[u].trim().split(/\s+/);u++;for(let y=0;y<A.length&&(m.push(Math.abs(parseInt(A[y]))-1),p++,!(p>=c));y++);}if(i)for(let A=0;A<m.length;A+=3){const y=m[A];m[A]=m[A+1],m[A+1]=y}const g=new Float32Array(d),x=new Uint32Array(m);return{positions:g,indices:x}}static readOFF(e){const s=new TextDecoder("utf-8").decode(e).split(`
|
|
61
|
+
`),n=[],a=[];let o=0;s[o].includes("OFF")?o++:F.warn("File does not start with OFF");let l=s[o].trim().split(/\s+/);const c=parseInt(l[0]),h=parseInt(l[1]);o++;for(let u=0;u<c;u++)l=s[o].trim().split(/\s+/),n.push(parseFloat(l[0])),n.push(parseFloat(l[1])),n.push(parseFloat(l[2])),o++;for(let u=0;u<h;u++)l=s[o].trim().split(/\s+/),parseInt(l[0])!==3&&F.warn("Only able to read OFF files with triangular meshes"),a.push(parseInt(l[1])),a.push(parseInt(l[2])),a.push(parseInt(l[3])),o++;const d=new Float32Array(n),f=new Uint32Array(a);return{positions:d,indices:f}}static readOBJMNI(e){const s=new TextDecoder("utf-8").decode(e).trim().split(/\s*,\s*|\s+/);(s.length<1||s[0]!=="P")&&F.warn("This is not a valid MNI OBJ mesh.");let n=6;const a=parseInt(s[n++]),o=a*3,l=new Float32Array(o);for(let m=0;m<o;m++)l[m]=parseFloat(s[n++]);n+=o;const c=parseInt(s[n++]),h=parseInt(s[n++]);(c<1||h<0||h>2)&&F.warn("This is not a valid MNI OBJ mesh.");let d=1;h===1?d=c:h===1&&(d=a),n+=d*4,n+=c;const f=c*3,u=new Uint32Array(f);for(let m=0;m<f;m++)u[m]=parseInt(s[n++]);return{positions:l,indices:u}}static async readOBJ(e){const i=new Uint8Array(e,0,2);i[0]===31&&i[1]===139&&(e=await H.decompressToBuffer(new Uint8Array(e)));const s=new TextDecoder("utf-8").decode(e);if(s[0]==="P")return this.readOBJMNI(e);const n=s.split(`
|
|
62
|
+
`),a=n.length,o=[],l=[];for(let u=0;u<a;u++){const m=n[u];if(m[0]==="v"&&m[1]===" "){const p=m.trim().split(/\s+/);o.push(parseFloat(p[1])),o.push(parseFloat(p[2])),o.push(parseFloat(p[3]))}if(m[0]==="f"){const p=m.trim().split(/\s+/),g=p.length-3;if(g<1)break;let x=p[1].split("/");const A=parseInt(x[0])-1;x=p[2].split("/");let y=parseInt(x[0])-1;for(let v=0;v<g;v++){x=p[3+v].split("/");const b=parseInt(x[0])-1;l.push(A),l.push(y),l.push(b),y=b}}}const c=new Float32Array(o),h=new Uint32Array(l);let d=h[0],f=h[0];for(let u=1;u<h.length;u++)h[u]<d&&(d=h[u]),h[u]>f&&(f=h[u]);if(f-d+1>c.length/3)throw new Error("Not a valid OBJ file");for(let u=0;u<h.length;u++)h[u]-=d;return{positions:c,indices:h}}static readFreeSurfer(e){const i=new Uint8Array(e);if(i[0]===35&&i[1]===33&&i[2]===97)return fe.readASC(e);const r=new DataView(e),s=r.getUint32(0,!1),n=r.getUint32(4,!1);(s!==4294966883||n!==1919246708)&&vt.debug("Unable to recognize file type: does not appear to be FreeSurfer format.");let a=0;for(;r.getUint8(a)!==10;)a++;a+=2;let o=r.getUint32(a,!1);a+=4;let l=r.getUint32(a,!1);a+=4,o*=3;const c=new Float32Array(o);for(let u=0;u<o;u++)c[u]=r.getFloat32(a,!1),a+=4;l*=3;const h=new Uint32Array(l);for(let u=0;u<l;u++)h[u]=r.getUint32(a,!1),a+=4;const d=r.getUint32(a,!1);a+=4;let f=d===20;if(!f){const u=r.getUint32(a,!1);a+=4;const m=r.getUint32(a,!1);a+=4,f=d===2&&u===0&&m===20}if(!f)F.warn("Unknown FreeSurfer Mesh extension code.");else{const m=new TextDecoder().decode(e.slice(a)).trim().split(`
|
|
63
|
+
`);for(let p=0;p<m.length;p++){if(!m[p].startsWith("cras"))continue;const x=m[p].split("=")[1].trim().split(" ").map(Number),A=Math.floor(c.length/3);let y=0;for(let v=0;v<A;v++)c[y]+=x[0],y++,c[y]+=x[1],y++,c[y]+=x[2],y++}}return{positions:c,indices:h}}static async readSRF(e){const i=new Uint8Array(e);if(i[0]===35&&i[1]===33&&i[2]===97)return fe.readASC(e);i[0]===31&&i[1]===139&&(e=(await H.decompress(new Uint8Array(e))).buffer);const r=new DataView(e),s=r.getFloat32(0,!0),n=r.getUint32(8,!0),a=r.getUint32(12,!0),o=r.getFloat32(16,!0),l=r.getFloat32(20,!0),c=r.getFloat32(24,!0),h=new Float32Array(n*3);let d=28,f=1;for(let w=0;w<n;w++)h[f]=-r.getFloat32(d,!0)+o,f+=3,d+=4;f=2;for(let w=0;w<n;w++)h[f]=-r.getFloat32(d,!0)+l,f+=3,d+=4;f=0;for(let w=0;w<n;w++)h[f]=-r.getFloat32(d,!0)+c,f+=3,d+=4;d=28+24*n;const u=r.getFloat32(d,!0),m=r.getFloat32(d+4,!0),p=r.getFloat32(d+8,!0),g=r.getFloat32(d+16,!0),x=r.getFloat32(d+20,!0),A=r.getFloat32(d+24,!0);d+=32;const y=new Float32Array(n*3),v=new Uint32Array(e,d,n);f=0;for(let w=0;w<n;w++){const C=v[w];C>1056964608&&(y[f+0]=(C>>16&255)/255,y[f+1]=(C>>8&255)/255,y[f+2]=(C&255)/255),C===0&&(y[f+0]=u,y[f+1]=m,y[f+2]=p),C===1&&(y[f+0]=g,y[f+1]=x,y[f+2]=A),f+=3}d+=n*4;for(let w=0;w<n;w++){const C=r.getUint32(d,!0);d+=4+4*C}const b=new Uint32Array(a*3);for(let w=0;w<a*3;w++)b[w]=r.getInt32(d,!0),d+=4;return s!==4&&F.warn("Not valid SRF"),{positions:h,indices:b,colors:y}}static readTxtSTL(e){const s=new TextDecoder("utf-8").decode(e).split(`
|
|
64
|
+
`);if(!s[0].startsWith("solid"))throw new Error("Not a valid STL file");const n=[];for(let c=1;c<s.length;c++){if(!s[c].includes("vertex"))continue;const h=s[c].trim().split(/\s+/);for(let d=1;d<h.length;d++)n.push(parseFloat(h[d]))}const a=Math.floor(n.length/3);if(a*3!==n.length)throw new Error("Unable to parse ASCII STL file.");const o=new Float32Array(n),l=new Uint32Array(a);for(let c=0;c<a;c++)l[c]=c;return{positions:o,indices:l}}static readSTL(e){if(e.byteLength<134)throw new Error("File too small to be STL: bytes = "+e.byteLength);const i=new DataView(e);if(i.getUint32(0,!0)===1768714099)return fe.readTxtSTL(e);const s=i.getUint32(80,!0),n=3*s;if(e.byteLength<84+s*50)throw new Error("STL file too small to store triangles = "+s);const a=new Uint32Array(n),o=new Float32Array(n*3);let l=96,c=0;for(let h=0;h<s;h++){for(let d=0;d<9;d++)o[c]=i.getFloat32(l,!0),c+=1,l+=4;l+=14}for(let h=0;h<n;h++)a[h]=h;return{positions:o,indices:a}}static decimateLayerVertices(e,i){if(e%i===0)return e;const r=12,s=Math.round(Math.log((e-2)/(r-2))/Math.log(4)),n=Math.round(Math.log((i-2)/(r-2))/Math.log(4)),a=Math.pow(4,s)*(r-2)+2,o=Math.pow(4,n)*(r-2)+2;return a!==e||o!==i?e:i}static async readNII2(e,i=0,r=""){let s=new Float32Array;const n=e.byteLength;let a=!0;const o=new DataView(e);let l=o.getUint16(0,a);if(l===469893120&&(a=!1,l=o.getUint16(0,a)),l!==540)throw new Error("Not a valid NIfTI-2 dataset");const c=Number(o.getBigInt64(168,a)),h=o.getFloat64(176,a),d=o.getFloat64(184,a);(h!==1||d!==0)&&F.warn("ignoring scale slope and intercept");const f=o.getUint32(504,a),u=o.getUint16(12,a);if(u!==2&&u!==4&&u!==8&&u!==16)throw new Error("Unsupported NIfTI datatype "+u);let m=1;const p=[1,1,1,1,1,1,1,1];for(let g=1;g<8;g++)p[g]=Math.max(Number(o.getBigInt64(16+g*8,a)),1),m*=p[g];if(f>=3e3&&f<=3099&&c>580){let g=function(){for(;T<n&&M[T]===10;)T++;const R=T;for(;T<n&&M[T]!==10;)T++;return T++,T-R<1?"":new TextDecoder().decode(e.slice(R,T-1)).trim()},x=function(){let R=g();if(!R.startsWith("<")||R.endsWith(">"))return R;for(;T<n&&!R.endsWith(">");)R+=g();return R},A=function(R,P=!1){const L=E.indexOf(R);if(L<0)return 1;const N=E.indexOf('"',L)+1,Y=E.indexOf('"',N),_=E.slice(N,Y);return P?_:parseInt(_)},y=0,v=0,b=0,w="",C=new Uint32Array;const M=new Uint8Array(e);let T=552,E;const I=p[5],S=new Float32Array(i*I);for(;T<n&&(E=x(),!E.includes("</CIFTI>"));)if(E.includes("<BrainModel")){const R=A("SurfaceNumberOfVertices="),P=A("BrainStructure=",!0).toUpperCase();if(R%i!==0)continue;let L=!1;if(r.includes("CORTEX")&&P.includes("CORTEX")&&(L=!0),!L||(L=!1,r.includes("LEFT")&&P.includes("LEFT")&&(L=!0),r.includes("RIGHT")&&P.includes("RIGHT")&&(L=!0),!L))continue;if(b=R,y=A("IndexOffset="),v=A("IndexCount="),w=P,E.includes("<VertexIndices>")||(E=x()),!E.startsWith("<VertexIndices>")||!E.endsWith("</VertexIndices>"))return F.warn("Unable to find CIfTI <VertexIndices>"),S;E=E.slice(15,-16);const N=E.trim().split(/\s+/);N.length<v&&F.error("Error parsing VertexIndices"),C=new Uint32Array(v);for(let Y=0;Y<v;Y++)C[Y]=parseInt(N[Y])}if(b===0||C.length===0)return F.warn("Unable to find CIfTI structure that matches the mesh."),S;if(u!==16)return F.warn("Only able to read float32 CIfTI (only known datatype)."),S;const U=new Float32Array(v*I),B=c+I*y*4;for(let R=0;R<v*I;R++)U[R]=o.getFloat32(B+R*4,a);let V=0;for(let R=0;R<v;R++)for(let P=0;P<I;P++)S[C[R]+P*i]=U[V],V++;return F.debug("CIfTI diagnostics",b,w,y,v,y,r),S}if(m=this.decimateLayerVertices(m,i),m%i!==0)throw new Error("Vertices in layer ("+m+") is not a multiple of number of vertices ("+i+")");if(a)u===16?s=new Float32Array(e,c,m):u===8?s=new Int32Array(e,c,m):u===4&&(s=new Int16Array(e,c,m));else if(u===16){s=new Float32Array(m);for(let g=0;g<m;g++)s[g]=o.getFloat32(c+g*4,a)}else if(u===8){s=new Int32Array(m);for(let g=0;g<m;g++)s[g]=o.getInt32(c+g*4,a)}else if(u===4){s=new Int16Array(m);for(let g=0;g<m;g++)s[g]=o.getInt16(c+g*2,a)}return u===2&&(s=new Uint8Array(e,c,m)),s}static async readNII(e,i,r=""){const s=i.length/3;let n=new Float32Array,a=!0,o=new DataView(e),l=o.getUint16(0,a);if(l===540||l===469893120)return fe.readNII2(e,s,r);if(l===23553&&(a=!1,l=o.getUint16(0,a)),l!==348){const w=await H.decompress(new Uint8Array(e));if(o=new DataView(w.buffer),e=w.buffer,l=o.getUint16(0,a),l===540||l===469893120)return fe.readNII2(e,s,r);l===23553&&(a=!1,l=o.getUint16(0,a))}l!==348&&F.error("Not a valid NIfTI image.");const c=o.getFloat32(108,a),h=o.getFloat32(112,a),d=o.getFloat32(116,a),f=o.getUint16(252,a),u=o.getUint16(254,a),m=o.getUint16(70,a);if(m!==2&&m!==4&&m!==8&&m!==16)throw new Error("Unsupported NIfTI datatype "+m);const p=J();for(let w=0;w<12;w++)p[w]=o.getFloat32(280+w*4,a);let g=1;const x=new Array(8);for(let w=0;w<8;w++)x[w]=o.getUint16(40+w*2,a),!(w<1)&&(g*=x[w]||1);let A=!1,y=this.decimateLayerVertices(g,s);if(y%s!==0)if(x[0]>=3&&x[1]>1&&x[2]>1&&x[3]>1)A=!0,y=x[1]*x[2]*x[3];else throw new Error("Voxels in layer ("+g+") is not a multiple of number of vertices ("+s+")");if(g=y,a)m===16?n=new Float32Array(e,c,g):m===8?n=new Int32Array(e,c,g):m===4&&(n=new Int16Array(e,c,g));else if(m===16){n=new Float32Array(g);for(let w=0;w<g;w++)n[w]=o.getFloat32(c+w*4,a)}else if(m===8){n=new Int32Array(g);for(let w=0;w<g;w++)n[w]=o.getInt32(c+w*4,a)}else if(m===4){n=new Int16Array(g);for(let w=0;w<g;w++)n[w]=o.getInt16(c+w*2,a)}if(m===2&&(n=new Uint8Array(e,c,g)),Number.isFinite(h)&&Number.isFinite(d)&&h!==0&&(h!==1||d!==0)){const w=new Float32Array(g);for(let C=0;C<g;C++)w[C]=n[C]*h+d;n=w}let v=n[0],b=v;for(let w=0;w<g;w++)isNaN(n[w])&&(n[w]=0),v=Math.min(v,n[w]),b=Math.max(b,n[w]);if(F.debug(`Layer Range ${v}..${b} slope ${h} inter ${d}`),A){let w=function(P,L){const N=[0,0,0];return N[0]=L[0]*P[0]+L[1]*P[1]+L[2]*P[2]+L[3],N[1]=L[4]*P[0]+L[5]*P[1]+L[6]*P[2]+L[7],N[2]=L[8]*P[0]+L[9]*P[1]+L[10]*P[2]+L[11],N};const C=new Float32Array(s);F.warn("Sampling voxel intensities at mesh vertices (assumes precise alignment)."),(f>u||u<=0)&&F.warn(`Requires valid sform (sform_code = ${u})`);const M=J();Se(M,p);const T=x[1],E=x[2],I=x[3],S=T*E;let U=0,B=0,V=0;for(;B<s;){const P=[i[U],i[U+1],i[U+2]],L=w(P,M);U+=3,B+=1;const N=Math.floor(L[0]),Y=Math.floor(L[1]),_=Math.floor(L[2]),z=Math.ceil(L[0]),W=Math.ceil(L[1]),K=Math.ceil(L[2]);if(N<0||z>=T||Y<0||W>=E||_<0||K>=I)continue;const Z=N+Y*T+_*S,q=new Float32Array(8);q[0]=n[Z],q[1]=n[Z+1],q[2]=n[Z+T],q[3]=n[Z+T+1],q[4]=n[Z+S],q[5]=n[Z+S+1],q[6]=n[Z+S+T],q[7]=n[Z+S+T+1];let te=q[0],ue=te;for(let le=1;le<8;le++)te=Math.max(te,q[le]),ue=Math.min(ue,q[le]);Math.abs(ue)>te&&(te=ue),C[B-1]=te,V++}const R=V/s;R<.1&&F.warn(`${V} of ${s} vertices in range (${(R*100).toFixed(1)}%)`),n=C}return n}static async readMGH(e,i=0,r=!1){let s=new DataView(e),n=e;if(s.getUint8(0)===31&&s.getUint8(1)===139){const C=await H.decompress(new Uint8Array(e));n=new ArrayBuffer(C.byteLength),new Uint8Array(n).set(new Uint8Array(C)),s=new DataView(C.buffer)}const a=s.getInt32(0,!1),o=Math.max(1,s.getInt32(4,!1)),l=Math.max(1,s.getInt32(8,!1)),c=Math.max(1,s.getInt32(12,!1)),h=Math.max(1,s.getInt32(16,!1)),d=s.getInt32(20,!1);let f=284;const u=!1;(a!==1||d<0||d>4)&&F.warn("Not a valid MGH file");let m=o*l*c*h,p=[];if(m=this.decimateLayerVertices(m,i),m%i!==0)return F.warn("Vertices in layer ("+m+") is not a multiple of number of vertices ("+i+")"),p;if(d===3){p=new Float32Array(m);for(let C=0;C<m;C++)p[C]=s.getFloat32(f+C*4,u)}else if(d===1){p=new Int32Array(m);for(let C=0;C<m;C++)p[C]=s.getInt32(f+C*4,u)}else if(d===4){p=new Int16Array(m);for(let C=0;C<m;C++)p[C]=s.getInt16(f+C*2,u)}else d===0&&(p=new Uint8Array(e,f,m));if(!r)return p;let g=4;d===4&&(g=2),d===0&&(g=1),f+=g*m,f+=16;const x=1,A=2,y=20,v=30,b=n.byteLength;let w;for(;f<b-8;){const C=s.getInt32(f+=4,u);let M=0;switch(C){case v:M=s.getInt32(f+=4,u)-1;break;case y:case A:M=0;break;case x:M=0;{let T=s.getInt32(f+=4,u);if(T>0)return F.warn("unsupported CTABreadFromBinaryV1"),p;if(T=-T,T!==2)return F.warn("CTABreadFromBinary: unknown version"),p;const E=s.getInt32(f+=4,u);if(E<0)return F.warn("CTABreadFromBinaryV2: nentries was ",E),p;const I=s.getInt32(f+=4,u);f+=I;const S=s.getInt32(f+=4,u);if(S<0)return p;const U={R:[],G:[],B:[],A:[],I:[],labels:[]};for(let B=0;B<S;B++){const V=s.getInt32(f+=4,u),R=s.getInt32(f+=4,u);let P=f+4,L="";for(let W=0;W<R;W++){const K=s.getUint8(P++);if(K===0)break;L+=String.fromCharCode(K)}f+=R;const N=s.getInt32(f+=4,u),Y=s.getInt32(f+=4,u),_=s.getInt32(f+=4,u),z=255-s.getInt32(f+=4,u);U.I.push(V),U.R.push(N),U.G.push(Y),U.B.push(_),U.A.push(z),U.labels.push(L)}w=re.makeLabelLut(U)}break;default:M=s.getInt32(f+=8,u)}f+=M}return{scalars:p,colormapLabel:w}}static readX3D(e){const i=e.byteLength;if(i<20)throw new Error("File too small to be X3D: bytes = "+i);const r=new Uint8Array(e);let s=0;function n(){for(;s<i&&r[s]!==60;)s++;const y=s;for(;s<i&&r[s]!==62;)s++;const v=s;return new TextDecoder().decode(e.slice(y,v+1)).trim()}let a=n();function o(y){const v=a.indexOf(y+"=");if(v<0)return"";const b=a[v+y.length+1],w=a.indexOf(b,v)+1,C=a.indexOf(b,w);return a.slice(w,C)}function l(y){const v=a.indexOf(y+"=");if(v<0)return 1;const b=a[v+y.length+1],w=a.indexOf(b,v)+1,C=a.indexOf(b,w);let M=a.slice(w,C).trim();M=M.replace(/,\s*$/,"");const T=M.trim().split(/\s*,\s*|\s+/);if(T.length<2)return parseFloat(M);let E=new Array(T.length),I=0;for(let S=0;S<T.length;S++){const U=parseFloat(T[S]);isFinite(U)&&(E[I]=U,I++)}return E=E.slice(0,I),E}a.includes("xml version")||F.warn("Not a X3D image");let c=[],h=[],d=[],f=[],u=[0,0,0,0],m=[0,0,0,0],p=[255,255,255,255],g=[255,255,255,255];const x={};function A(){if(!a.endsWith("/>"))if(a.startsWith("<Appearance>"))for(;s<i&&!a.endsWith("</Appearance>");)a+=n();else for(;s<i&&!a.endsWith("/>");)a+=n();const y=o("USE");if(y.length>1){y in x?p=x[y]:F.warn("Unable to find DEF for "+y);return}const v=l("diffuseColor");if(v.length<3)return;p[0]=Math.round(v[0]*255),p[1]=Math.round(v[1]*255),p[2]=Math.round(v[2]*255);const b=o("DEF");b.length<1||(x[b]=p)}for(;s<i;)if(a=n(),p=g.slice(),a.startsWith("<Transform")&&(u=l("translation"),m=l("rotation")),a.startsWith("<Appearance")&&(A(),g=p.slice()),a.startsWith("<Shape")){let y=1,v=1,b=[],w=[];for(;s<i&&(a=n(),a.startsWith("<Appearance")&&A(),!a.startsWith("</Shape"));){if(a.startsWith("<Sphere")&&(y=l("radius"),v=-1),a.startsWith("<Cylinder")&&(y=l("radius"),v=l("height")),a.startsWith("<IndexedFaceSet")&&(v=-2,b=l("coordIndex")),a.startsWith("<IndexedTriangleSet")&&(v=-7,b=l("index")),a.startsWith("<IndexedTriangleStripSet")&&(v=-3,b=l("index")),a.startsWith("<Coordinate")){w=l("point");const C=w.length%3;C!==0&&(w=w.slice(0,-C))}a.startsWith("<Color")&&(f=l("color")),a.startsWith("<Box")&&(v=-4,F.warn("Unsupported x3d shape: Box")),a.startsWith("<Cone")&&(v=-5,F.warn("Unsupported x3d shape: Cone")),a.startsWith("<ElevationGrid")&&(v=-6,F.warn("Unsupported x3d shape: ElevationGrid"))}if(!(v<-3&&v!==-7))if(v<-1){if(b.length<1||w.length<3||w.length===void 0){F.warn("Indexed mesh must specify indices and points");break}const C=Math.floor(c.length/3);let M=2;if(v===-7)h=[...h,...b];else if(v===-2){let I=0;for(;M<b.length;)b[M]>=0?(h.push(b[I]+C),h.push(b[M-1]+C),h.push(b[M-0]+C),M+=1):(M+=3,I=M-2)}else for(;M<b.length;)b[M]>=0?(h.push(b[M-2]+C),h.push(b[M-1]+C),h.push(b[M-0]+C),M+=1):M+=3;c=[...c,...w];const T=Math.floor(w.length/3),E=Array(T).fill(p).flat();if(f.length===T*3){let I=0,S=0;for(let U=0;U<T;U++){for(let B=0;B<3;B++)E[S]=Math.round(f[I]*255),I++,S++;S++}}d=[...d,...E]}else if(v<0)st.makeColoredSphere(c,h,d,y,u,p);else{const C=J();Ma(C,m[3],[m[0],m[1],m[2]]);const M=ae(0,-v*.5,0,1),T=ae(0,+v*.5,0,1);ve(M,M,C),ve(T,T,C),Zr(M,M,u),Zr(T,T,u);const E=k(M[0],M[1],M[2]),I=k(T[0],T[1],T[2]);st.makeColoredCylinder(c,h,d,E,I,y,p)}}return{positions:Float32Array.from(c),indices:Uint32Array.from(h),rgba255:Uint8Array.from(d)}}static async readGII(e,i=0){let r=e.byteLength;if(r<20)throw new Error("File too small to be GII: bytes = "+r);let s=new TextDecoder("ascii").decode(e);if(s[0].charCodeAt(0)===31){const S=await H.decompress(new Uint8Array(e));e=S.buffer,s=new TextDecoder("ascii").decode(S.buffer)}let n=0;function a(){let S=!0,U=n;for(;S;){for(;n<r&&s[n]!=="<";)n++;for(U=n;n<r&&s[n]!==">";)n++;if(S=s[n-1]==="/",U+1<r&&s[U+1]==="/"&&(n+=1,S=!0),n>=r)break}const B=new TextDecoder().decode(e.slice(U+1,n)).trim(),V=B.split(" ")[0].trim(),R=n;let P=n,L=n;if(s[U+1]!=="?"&&s[U+1]!=="!"){const N="</"+V+">";P=s.indexOf(N,R),L=P+N.length-1}return{name:B,startPos:U,contentStartPos:R,contentEndPos:P,endPos:L}}let o=a();if(!o.name.startsWith("?xml"))throw new Error("readGII: Invalid XML file");for(;!o.name.startsWith("GIFTI")&&o.endPos<r;)o=a();if(!o.name.startsWith("GIFTI")||o.contentStartPos===o.contentEndPos)throw new Error("readGII: XML file does not include GIFTI tag");r=o.contentEndPos;let l=new Float32Array,c=new Uint32Array,h=new Float32Array,d="",f=!1,u=!1,m=!1,p=!1,g=[1,1,1];const x=[0,0,0];let A=0,y=!1,v=!1,b=0,w=!1;o.endPos=o.contentStartPos;let C="";function M(S,U=!1){const B=C.indexOf(S);if(B<0)return 1;const V=C.indexOf('"',B)+1,R=C.indexOf('"',V),P=C.slice(V,R);return U?parseFloat(P):parseInt(P)}function T(S){const U=C.indexOf(S);if(U<0)return"";const B=U+S.length,V=C.indexOf("]",B);return C.slice(B,V)}const E={R:[],G:[],B:[],A:[],I:[],labels:[]};for(;o.endPos<r&&o.name.length>1;){if(o=a(),o.name.startsWith("Label Key")&&(C=o.name,E.I.push(M("Key=")),E.R.push(Math.round(255*M("Red=",!0))),E.G.push(Math.round(255*M("Green=",!0))),E.B.push(Math.round(255*M("Blue=",!0))),E.A.push(Math.round(255*M("Alpha",!0))),C=new TextDecoder().decode(e.slice(o.contentStartPos+1,o.contentEndPos)).trim(),E.labels.push(T("<![CDATA["))),o.name.trim()==="Data"){if(m)continue;C=new TextDecoder().decode(e.slice(o.contentStartPos+1,o.contentEndPos)).trim();let S;if(v){const U=g[0]*g[1]*g[2],B=C.split(/\s+/);if(U!==B.length)throw new Error("Unable to parse ASCII GIfTI");if(A===2&&(A=8),A===32&&(A=16),A===8){S=new Int32Array(U);for(let V=0;V<U;V++)S[V]=parseInt(B[V])}if(A===16){S=new Float32Array(U);for(let V=0;V<U;V++)S[V]=parseFloat(B[V])}}else if(typeof Buffer>"u"){let U=function(B){const V=atob(B),R=V.length,P=new Uint8Array(R);for(let L=0;L<R;L++)P[L]=V.charCodeAt(L);return P};if(y){const B=U(C.slice());S=await H.decompress(new Uint8Array(B))}else S=U(C.slice())}else if(y){const U=Buffer.from(C.slice(),"base64");S=await H.decompress(new Uint8Array(U))}else S=Buffer.from(C.slice(),"base64");if(u){if(A!==16&&F.warn("expect positions as FLOAT32"),l=new Float32Array(S.buffer),p){const U=l.slice(),B=U.length/3;let V=0;for(let R=0;R<B;R++)for(let P=0;P<3;P++)l[V]=U[P*B+R],V++}}else if(f){if(A!==8&&F.warn("expect indices as INT32"),c=new Uint32Array(S.buffer),p){const U=c.slice(),B=U.length/3;let V=0;for(let R=0;R<B;R++)for(let P=0;P<3;P++)c[V]=U[P*B+R],V++}}else{let U=function(V,R){const P=V.length,L=new Float32Array(P+R.length);return L.set(V),L.set(R,P),L};b=g[0]*g[1]*g[2],i!==0&&b%i!==0&&F.warn("Number of vertices in scalar overlay ("+b+") does not match mesh ("+i+")");let B;if(A===2){const V=new Uint8Array(S.buffer);B=Float32Array.from(V)}else if(A===8){const V=new Int32Array(S.buffer);B=Float32Array.from(V)}else if(A===16)B=new Float32Array(S.buffer);else if(A===32){const V=new Float64Array(S.buffer);B=Float32Array.from(V)}else throw new Error(`Invalid dataType: ${A}`);h=U(h,B)}continue}if(o.name.trim()==="DataSpace"&&(C=new TextDecoder().decode(e.slice(o.contentStartPos+1,o.contentEndPos)).trim(),C.includes("NIFTI_XFORM_SCANNER_ANAT")&&(w=!0)),o.name.trim()==="MD"&&(C=new TextDecoder().decode(e.slice(o.contentStartPos+1,o.contentEndPos)).trim(),C.includes("AnatomicalStructurePrimary")&&C.includes("CDATA[")&&(d=T("<Value><![CDATA[").toUpperCase()),C.includes("VolGeom")&&C.includes("CDATA["))){let S=-1;if(C.includes("VolGeomC_R")&&(S=0),C.includes("VolGeomC_A")&&(S=1),C.includes("VolGeomC_S")&&(S=2),S<0)continue;x[S]=parseFloat(T("<Value><![CDATA["))}o.name.startsWith("DataArray")&&(C=o.name,g=[1,1,1],y=C.includes('Encoding="GZipBase64Binary"'),v=C.includes('Encoding="ASCII"'),f=C.includes('Intent="NIFTI_INTENT_TRIANGLE"'),u=C.includes('Intent="NIFTI_INTENT_POINTSET"'),m=C.includes('Intent="NIFTI_INTENT_VECTOR"'),p=C.includes('ArrayIndexingOrder="ColumnMajorOrder"'),C.includes('DataType="NIFTI_TYPE_UINT8"')&&(A=2),C.includes('DataType="NIFTI_TYPE_INT32"')&&(A=8),C.includes('DataType="NIFTI_TYPE_FLOAT32"')&&(A=16),C.includes('DataType="NIFTI_TYPE_FLOAT64"')&&(A=32),g[0]=M("Dim0="),g[1]=M("Dim1="),g[2]=M("Dim2="))}let I;if(E.I.length>1&&(E.A.some(U=>U>0)||E.A.fill(255),I=re.makeLabelLut(E)),i>0)return{scalars:h,colormapLabel:I,anatomicalStructurePrimary:d};if(l.length>2&&!w&&(x[0]!==0||x[1]!==0||x[2]!==0)){b=Math.floor(l.length/3);let S=0;for(let U=0;U<b;U++)l[S]+=x[0],S++,l[S]+=x[1],S++,l[S]+=x[2],S++}return{positions:l,indices:c,scalars:h,colormapLabel:I,anatomicalStructurePrimary:d}}},Lc=(t=>(t.LEFT="left",t.RIGHT="right",t.CENTER="center",t))(Lc||{}),kc=(t=>(t.NONE="none",t.CIRCLE="circle",t.RING="ring",t))(kc||{}),Oc=(t=>(t[t.NONE=0]="NONE",t[t.TOPLEFT=9]="TOPLEFT",t[t.TOPCENTER=10]="TOPCENTER",t[t.TOPRIGHT=12]="TOPRIGHT",t[t.MIDDLELEFT=17]="MIDDLELEFT",t[t.MIDDLECENTER=18]="MIDDLECENTER",t[t.MIDDLERIGHT=20]="MIDDLERIGHT",t[t.BOTTOMLEFT=33]="BOTTOMLEFT",t[t.BOTTOMCENTER=34]="BOTTOMCENTER",t[t.BOTTOMRIGHT=36]="BOTTOMRIGHT",t))(Oc||{}),Um=class{constructor(t=[1,1,1,1],e=1,i="left",r=0,s=[0,0,0],n="none",a,o,l){D(this,"textColor"),D(this,"textScale"),D(this,"textAlignment"),D(this,"lineWidth"),D(this,"lineColor"),D(this,"lineTerminator"),D(this,"bulletScale"),D(this,"bulletColor"),D(this,"backgroundColor"),this.textColor=t,this.textScale=e,this.textAlignment=i,this.lineWidth=r,this.lineColor=s,this.lineTerminator=n,this.bulletScale=a,this.bulletColor=o,this.backgroundColor=l}},Er=class{constructor(t,e,i,r,s){D(this,"text"),D(this,"style"),D(this,"points"),D(this,"anchor"),D(this,"onClick"),this.text=t,this.style=e,this.points=i,this.anchor=r||0,this.onClick=s}},zc={colormap:"gray",opacity:0,nFrame4D:0,frame4D:0,outlineBorder:0,cal_min:0,cal_max:0,cal_minNeg:0,cal_maxNeg:0,colormapType:0,values:new Array,useNegativeCmap:!1,showLegend:!0},Rm=class{constructor(t="",e=null,i="",r=1,s=new Uint8Array([255,255,255,255]),n=!0,a=[],o=!0,l=0){D(this,"url"),D(this,"gl"),D(this,"name"),D(this,"opacity"),D(this,"rgba255"),D(this,"visible"),D(this,"layers"),D(this,"colorbarVisible"),D(this,"meshShaderIndex"),this.url=t,this.gl=e,this.name=i,this.opacity=r,this.rgba255=s,this.visible=n,this.layers=a,this.colorbarVisible=o,this.meshShaderIndex=l}},mt=class Le{constructor(e,i,r="",s=new Uint8Array([255,255,255,255]),n=1,a=!0,o,l=null,c=null,h=null,d=null,f=null,u=!0,m=""){D(this,"id"),D(this,"name"),D(this,"anatomicalStructurePrimary"),D(this,"colorbarVisible"),D(this,"furthestVertexFromOrigin"),D(this,"extentsMin"),D(this,"extentsMax"),D(this,"opacity"),D(this,"visible"),D(this,"meshShaderIndex",0),D(this,"offsetPt0",null),D(this,"colormapInvert",!1),D(this,"fiberGroupColormap",null),D(this,"indexBuffer"),D(this,"vertexBuffer"),D(this,"vao"),D(this,"vaoFiber"),D(this,"pts"),D(this,"tris"),D(this,"layers"),D(this,"type","mesh"),D(this,"data_type"),D(this,"rgba255"),D(this,"fiberLength"),D(this,"fiberLengths"),D(this,"fiberDensity"),D(this,"fiberDither",.1),D(this,"fiberColor","Global"),D(this,"fiberDecimationStride",1),D(this,"fiberSides",5),D(this,"fiberRadius",0),D(this,"fiberOcclusion",0),D(this,"f32PerVertex",5),D(this,"dpsThreshold",NaN),D(this,"fiberMask"),D(this,"colormap"),D(this,"dpg"),D(this,"dps"),D(this,"dpv"),D(this,"groups"),D(this,"hasConnectome",!1),D(this,"connectome"),D(this,"indexCount"),D(this,"vertexCount",1),D(this,"nodeScale",4),D(this,"edgeScale",1),D(this,"legendLineThickness",0),D(this,"showLegend",!0),D(this,"nodeColormap","warm"),D(this,"edgeColormap","warm"),D(this,"nodeColormapNegative"),D(this,"edgeColormapNegative"),D(this,"nodeMinColor"),D(this,"nodeMaxColor"),D(this,"edgeMin"),D(this,"edgeMax"),D(this,"nodes"),D(this,"edges"),D(this,"points"),this.anatomicalStructurePrimary=m,this.name=r,this.colorbarVisible=u,this.id=di();const p=$e.getExtents(e);if(this.furthestVertexFromOrigin=p.mxDx,this.extentsMin=p.extentsMin,this.extentsMax=p.extentsMax,this.opacity=n>1?1:n,this.visible=a,this.meshShaderIndex=0,this.indexBuffer=o.createBuffer(),this.vertexBuffer=o.createBuffer(),this.vao=o.createVertexArray(),o.bindVertexArray(this.vao),o.bindBuffer(o.ELEMENT_ARRAY_BUFFER,this.indexBuffer),o.bindBuffer(o.ARRAY_BUFFER,this.vertexBuffer),o.enableVertexAttribArray(0),o.enableVertexAttribArray(1),this.f32PerVertex!==7?(o.vertexAttribPointer(0,3,o.FLOAT,!1,20,0),o.vertexAttribPointer(1,4,o.BYTE,!0,20,12),o.enableVertexAttribArray(2),o.vertexAttribPointer(2,4,o.UNSIGNED_BYTE,!0,20,16)):(o.vertexAttribPointer(0,3,o.FLOAT,!1,28,0),o.vertexAttribPointer(1,3,o.FLOAT,!1,28,12),o.enableVertexAttribArray(2),o.vertexAttribPointer(2,4,o.UNSIGNED_BYTE,!0,28,24)),o.bindVertexArray(null),this.vaoFiber=o.createVertexArray(),this.offsetPt0=null,this.hasConnectome=!1,this.colormapInvert=!1,this.fiberGroupColormap=null,this.pts=e,this.layers=[],this.type="mesh",this.tris=i,s[3]<1){this.rgba255=s,this.fiberLength=2,this.fiberDither=.1,this.fiberColor="Global",this.fiberDecimationStride=1,this.fiberMask=[],this.colormap=l,this.dpg=c,this.dps=h,this.dpv=d,this.groups=f,c&&this.initValuesArray(c),h&&this.initValuesArray(h),d&&this.initValuesArray(d),f&&this.initValuesArray(f),this.offsetPt0=new Uint32Array(i),this.tris=new Uint32Array(0),this.updateFibers(o),o.bindVertexArray(this.vaoFiber),o.bindBuffer(o.ELEMENT_ARRAY_BUFFER,this.indexBuffer),o.bindBuffer(o.ARRAY_BUFFER,this.vertexBuffer),o.enableVertexAttribArray(0),o.vertexAttribPointer(0,3,o.FLOAT,!1,16,0),o.enableVertexAttribArray(1),o.vertexAttribPointer(1,4,o.UNSIGNED_BYTE,!0,16,12),o.bindVertexArray(null);return}if(l){this.connectome=l,this.hasConnectome=!0;const x=Object.keys(l);for(let A=0,y=x.length;A<y;A++)this[x[A]]=l[x[A]]}this.rgba255=s,this.updateMesh(o)}initValuesArray(e){for(let i=0;i<e.length;i++){const r=e[i].vals.reduce((n,a)=>Math.min(n,a)),s=e[i].vals.reduce((n,a)=>Math.max(n,a));e[i].global_min=r,e[i].global_max=s,e[i].cal_min=r,e[i].cal_max=s}return e}linesToCylinders(e,i,r){function s(T){return k(T[0],T[1],T[2])}const n=Math.pow(2,32)-1,a=r.length;let o=0,l=0;for(let T=0;T<a;T++){if(r[T]===n){l++;continue}o++}const c=this.fiberSides,h=c*o,d=this.f32PerVertex;if(d!==5)throw Error("fiberSides > 1 requires f32PerVertex == 5");const f=new Float32Array(h*d),u=new Uint8Array(f.buffer);let m=0,p=Xe(),g=Xe(),x=Xe();const A=se();let y=se(),v=0;const b=this.fiberRadius;for(let T=0;T<a;T++){const E=r[T]===n;if(E&&v<1)continue;let I=r[T]*4;if(v++,v<=1){p=ae(i[I+0],i[I+1],i[I+2],i[I+3]),g=ze(p),T+1<a&&r[T+1]!==n&&(I=r[T+1]*4,x=ae(i[I+0],i[I+1],i[I+2],i[I+3]),ne(A,s(p),s(x)),Ie(A,A),y=st.getFirstPerpVector(A));continue}E?x=ze(g):x=ae(i[I+0],i[I+1],i[I+2],i[I+3]),ne(A,s(p),s(x)),Ie(A,A);const S=se();Jt(S,y,A);const U=se();Jt(U,A,S),y=Ve(y);const B=se();Jt(B,A,U),Ie(B,B);const V=se();for(let R=0;R<c;R++){const P=Math.cos(R/c*2*Math.PI),L=Math.sin(R/c*2*Math.PI);V[0]=b*(P*U[0]+L*B[0]),V[1]=b*(P*U[1]+L*B[1]),V[2]=b*(P*U[2]+L*B[2]),it(V,s(g),V);const N=m*d;f[N+0]=V[0],f[N+1]=V[1],f[N+2]=V[2];const Y=se();ne(Y,V,s(g)),Ie(Y,Y);const _=(N+3)*4;u[_+0]=Y[0]*127,u[_+1]=Y[1]*127,u[_+2]=Y[2]*127,f[N+4]=g[3],m++}p=ze(g),g=ze(x),E&&(v=0)}const w=(o-l)*c*2*3,C=new Uint32Array(w);let M=0;m=0;for(let T=1;T<a;T++){if(r[T]===n){m+=c;continue}if(r[T-1]===n)continue;let E=m,I=m+c;const S=I,U=I+c;for(let B=0;B<c;B++)C[M++]=E,C[M++]=I++,I===U&&(I=U-c),C[M++]=I,C[M++]=E++,E===S&&(E=S-c),C[M++]=I,C[M++]=E;m+=c}e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,Uint32Array.from(C),e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,u,e.STATIC_DRAW),this.indexCount=w}createFiberDensityMap(){if(this.fiberDensity)return;const e=this.pts,i=e.length/3;let r=0;for(let A=0;A<3;A++){const y=this.extentsMax[A]-this.extentsMin[A];r=Math.max(r,y)}if(this.fiberDensity=new Float32Array(i),r===0)return;const s=64,a=r/(s-1)/2,o=(s-1)/r;let l=new Float32Array(s*s*s);const c=[this.extentsMin[0]-a,this.extentsMin[1]-a,this.extentsMin[2]-a],h=[0,0,0],d=-1,f=s*s;let u=0;for(let A=0;A<i;A++){h[0]=Math.round((e[u++]-c[0])*o),h[1]=Math.round((e[u++]-c[1])*o),h[2]=Math.round((e[u++]-c[2])*o);const y=h[0]+h[1]*s+h[2]*f;y!==d&&l[y]++}function m(A,y){let v=A.slice(),b=-1;const w=y-1;for(let M=0;M<y;M++)for(let T=0;T<y;T++)for(let E=0;E<y;E++)b++,!(E<1||E>=w)&&(A[b]=v[b-1]+v[b]+v[b]+v[b+1]);b=-1,v=A.slice();for(let M=0;M<y;M++)for(let T=0;T<y;T++)for(let E=0;E<y;E++)b++,!(T<1||T>=w)&&(A[b]=v[b-y]+v[b]+v[b]+v[b+y]);const C=y*y;b=-1,v=A.slice();for(let M=0;M<y;M++)for(let T=0;T<y;T++)for(let E=0;E<y;E++)b++,!(M<1||M>=w)&&(A[b]=v[b-C]+v[b]+v[b]+v[C]);return A}l=m(l,s),l=m(l,s);let p=0,g=1/0;const x=s*s*s;for(let A=0;A<x;A++)l[A]<=0||(p=Math.max(p,l[A]),g=Math.min(g,l[A]));if(!(p<=1||p<=g)){u=0;for(let A=0;A<x;A++)l[A]=Math.max(0,l[A]-g);p-=g;for(let A=0;A<i;A++){h[0]=Math.round((e[u++]-c[0])*o),h[1]=Math.round((e[u++]-c[1])*o),h[2]=Math.round((e[u++]-c[2])*o);const y=h[0]+h[1]*s+h[2]*f;this.fiberDensity[A]=l[y]/p}}}updateFibers(e){if(!this.offsetPt0||!this.fiberLength)return;const i=this.pts,r=this.offsetPt0,s=r.length-1,n=i.length/3;if(!this.fiberLengths){this.fiberLengths=new Uint32Array(s);for(let w=0;w<s;w++){const C=r[w]*3,M=(r[w+1]-1)*3;let T=0;for(let E=C;E<M;E+=3){const I=k(i[E+0]-i[E+3],i[E+1]-i[E+4],i[E+2]-i[E+5]);T+=Vt(I)}this.fiberLengths[w]=T}}const a=new Float32Array(n*4),o=new Uint32Array(a.buffer);let l=0,c=0;for(let w=0;w<n;w++)a[c+0]=i[l+0],a[c+1]=i[l+1],a[c+2]=i[l+2],l+=3,c+=4;const h=this.fiberDither,d=h*.5;function f(w,C,M){const E=255*(h*Math.random()-d);return w=Math.max(Math.min(w+E,255),0),C=Math.max(Math.min(C+E,255),0),M=Math.max(Math.min(M+E,255),0),w+(C<<8)+(M<<16)}function u(w,C,M,T,E,I,S){const U=k(Math.abs(w-T),Math.abs(C-E),Math.abs(M-I));Ie(U,U);const B=S-d;for(let V=0;V<3;V++)U[V]=255*Math.max(Math.min(Math.abs(U[V])+B,1),0);return U[0]+(U[1]<<8)+(U[2]<<16)}const m=this.fiberColor.toLowerCase();let p=null,g=null;if(m.startsWith("dps")&&this.dps&&this.dps.length>0){const w=parseInt(m.substring(3));w<this.dps.length&&this.dps[w].vals.length===s&&(p=this.dps[w].vals)}if(m.startsWith("dpv")&&this.dpv&&this.dpv.length>0){const w=parseInt(m.substring(3));w<this.dpv.length&&this.dpv[w].vals.length===n&&(g=this.dpv[w])}const x=new Int16Array(s);if(this.groups&&this.fiberGroupColormap!==null||m.startsWith("dpg")&&this.dpg.length>0){const w=new Uint8ClampedArray(this.groups.length*4),C=new Array(this.groups.length).fill(!1);if(this.fiberGroupColormap){const M=this.fiberGroupColormap;M.A===void 0&&(M.A=Array.from(new Uint8ClampedArray(M.I.length).fill(255)));for(let T=0;T<M.I.length;T++){let E=M.I[T];E<0||E>=this.groups.length||M.A[T]<1||(C[E]=!0,E*=4,w[E]=M.R[T],w[E+1]=M.G[T],w[E+2]=M.B[T],w[E+3]=255)}}else if(m.startsWith("dpg")&&this.dpg.length>0){const M=parseInt(m.substring(3)),T=M<this.dpg.length?this.dpg[M]:this.dpg[0],E=re.colormap(this.colormap,this.colormapInvert),I=T.cal_min,S=T.cal_max,U=this.groups.length;for(let B=0;B<U;B++){const V=T.vals[B];if(V<I)continue;let R=Math.round(255*Math.min(Math.max((V-I)/(S-I),0),1));C[B]=!0;const P=B*4;R*=4,w[P]=E[R+0],w[P+1]=E[R+1],w[P+2]=E[R+2],w[P+3]=255}}x.fill(-1);for(let M=0;M<this.groups.length;M++){if(!C[M])continue;const T=this.groups[M];for(let E=0;E<T.vals.length;E++)x[T.vals[E]]=M}for(let M=0;M<s;M++){if(x[M]<0)continue;const T=x[M]%256*4,E=f(w[T],w[T+1],w[T+2]),I=r[M],S=r[M+1]-1,U=I*4+3,B=S*4+3;for(let V=U;V<=B;V+=4)o[V]=E}}else if(g){const w=re.colormap(this.colormap,this.colormapInvert),C=g.cal_min,M=g.cal_max;let T=3;for(let E=0;E<n;E++){let I=Math.min(Math.max((g.vals[E]-C)/(M-C),0),1);I=Math.round(Math.max(Math.min(255,I*255)))*4;const S=w[I]+(w[I+1]<<8)+(w[I+2]<<16);o[T]=S,T+=4}}else if(p){const w=re.colormap(this.colormap,this.colormapInvert);let C=p[0],M=p[0];for(let T=0;T<s;T++)C=Math.min(C,p[T]),M=Math.max(M,p[T]);M===C&&(C-=1);for(let T=0;T<s;T++){let E=(p[T]-C)/(M-C);E=Math.round(Math.max(Math.min(255,E*255)))*4;const I=w[E]+(w[E+1]<<8)+(w[E+2]<<16),S=r[T],U=r[T+1]-1,B=S*4+3,V=U*4+3;for(let R=B;R<=V;R+=4)o[R]=I}}else if(m.includes("fixed"))if(h===0){const w=this.rgba255[0]+(this.rgba255[1]<<8)+(this.rgba255[2]<<16);let C=3;for(let M=0;M<n;M++)o[C]=w,C+=4}else for(let w=0;w<s;w++){const C=f(this.rgba255[0],this.rgba255[1],this.rgba255[2]),M=r[w],T=r[w+1]-1,E=M*4+3,I=T*4+3;for(let S=E;S<=I;S+=4)o[S]=C}else if(m.includes("local"))for(let w=0;w<s;w++){const C=r[w],M=r[w+1]-1;let T=C*3;const E=M*3,I=h*Math.random();let S=u(i[T],i[T+1],i[T+2],i[T+4],i[T+5],i[T+6],I),U=C*4+3;for(;T<E;)o[U]=S,U+=4,T+=3,S=u(i[T-3],i[T-2],i[T-1],i[T+3],i[T+4],i[T+5],I);o[U]=o[U-4]}else for(let w=0;w<s;w++){const C=r[w],M=r[w+1]-1,T=C*3,E=M*3,I=u(i[T],i[T+1],i[T+2],i[E],i[E+1],i[E+2],h*Math.random()),S=C*4+3,U=M*4+3;for(let B=S;B<=U;B+=4)o[B]=I}if(this.fiberOcclusion>0){let w=function(C,M){const T=M*(C&255),E=M*(C>>8&255),I=M*(C>>16&255);return T+(E<<8)+(I<<16)};this.createFiberDensityMap();for(let C=0;C<s;C++){const M=r[C],T=r[C+1]-1,E=M*4+3,I=T*4+3;let S=M;const U=Math.min(this.fiberOcclusion,.99);for(let B=E;B<=I;B+=4){let V=this.fiberDensity[S++];if(V<=0)continue;V=V/((1/U-2)*(1-V)+1);const R=1-Math.min(V,.9);let P=o[B];P=w(P,R),o[B]=P}}}if(Number.isFinite(this.dpsThreshold)&&this.dps&&(p||this.dps[0].vals.length===s&&(p=this.dps[0].vals),p))for(let w=0;w<s;w++)p[w]<this.dpsThreshold&&(x[w]=-1);const A=this.fiberLength,y=Math.pow(2,32)-1,v=[];let b=-1;for(let w=0;w<s;w++)if(!(x[w]<0)&&!(this.fiberLengths[w]<A)&&(b++,b%this.fiberDecimationStride===0)){for(let C=r[w];C<r[w+1];C++)v.push(C);v.push(y)}this.fiberSides>2&&this.fiberRadius>0?this.linesToCylinders(e,a,v):(this.indexCount=v.length,e.bindBuffer(e.ARRAY_BUFFER,this.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,Uint32Array.from(o),e.STATIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,Uint32Array.from(v),e.STATIC_DRAW))}indexNearestXYZmm(e,i,r){const s=this.pts,n=this.pts.length/3;let a=0,o=1/0,l=0;for(let c=0;c<n;c++){const h=Math.pow(s[a]-e,2)+Math.pow(s[a+1]-i,2)+Math.pow(s[a+2]-r,2);h<o&&(o=h,l=c),a+=3}return o=Math.sqrt(o),[l,o]}unloadMesh(e){if(e.bindBuffer(e.ARRAY_BUFFER,null),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,null),e.bindVertexArray(null),e.deleteBuffer(this.vertexBuffer),e.deleteBuffer(this.indexBuffer),e.deleteVertexArray(this.vao),e.deleteVertexArray(this.vaoFiber),this.offsetPt0=null,this.tris=null,this.pts=null,this.layers&&this.layers.length>0)for(let i=0;i<this.layers.length;i++)this.layers[i].values=null;if(this.dpg&&this.dpg.length>0)for(let i=0;i<this.dpg.length;i++)this.dpg[i].vals=null;if(this.dps&&this.dps.length>0)for(let i=0;i<this.dps.length;i++)this.dps[i].vals=null}scalars2RGBA(e,i,r,s=!1){const n=r.length;if(4*n<e.length)return F.error(`colormap2RGBA incorrectly specified ${n}*4 != ${e.length}`),e;const a=Math.round(i.opacity*255);let o=i.cal_min,l=i.cal_max,c=re.colormap(i.colormap,this.colormapInvert),h=1;if(s){if(!i.useNegativeCmap)return e;h=-1,c=re.colormap(i.colormapNegative,i.colormapInvert),o=i.cal_min,l=i.cal_max,isFinite(i.cal_minNeg)&&isFinite(i.cal_minNeg)&&(o=-i.cal_minNeg,l=-i.cal_maxNeg)}let d=o;i.isTransparentBelowCalMin||(d=Number.NEGATIVE_INFINITY);const f=i.colormapType===2;i.colormapType!==0&&(o=Math.min(o,0));const u=255/(l-o);for(let m=0;m<n;m++){let p=r[m]*h;if(isNaN(p))continue;let g=a;if(p<d)if(p>0&&f)g=Math.round(i.opacity*255*Math.pow(p/d,2));else continue;if(p=(p-o)*u,p<0&&i.isTransparentBelowCalMin)continue;p=Math.min(255,Math.max(0,Math.round(p)))*4;const x=m*4;e[x+0]=c[p+0],e[x+1]=c[p+1],e[x+2]=c[p+2],e[x+3]=g}return e}blendColormap(e,i,r,s,n,a,o=!1){const l=this.pts.length/3,c=Math.min(r.opacity,1);function h(y,v,b){return y*(1-b)+v*b}function d(y,v){return Math.min(y+v,255)}const f=o?-1:1,u=Math.min(Math.max(r.frame4D,0),r.nFrame4D-1),m=l*u;let p=s;r.isTransparentBelowCalMin||(p=Number.NEGATIVE_INFINITY),r.colormapType!==0&&(s=Math.min(s,0));const g=255/(n-s);let x=new Array(l).fill(!1);if(r.outlineBorder!==0){const y=new Uint8Array(l).fill(0);for(let v=0;v<l;v++)f*r.values[v+m]>=p&&(y[v]=1);x=$e.getClusterBoundaryU8(y,this.tris);for(let v=0;v<l;v++)f*r.values[v+m]<p&&(x[v]=!1)}const A=new Float32Array(256).fill(c);if(p>s&&r.colormapType===2){let y=Math.round((p-s)*g);y=Math.max(y,1);for(let v=1;v<y;v++)A[v]=c*Math.pow(v/y,2);A[0]=0,p=s+Number.EPSILON}for(let y=0;y<l;y++){const v=f*r.values[y+m];if(v<p)continue;let b=Math.round((v-s)*g);if(b<0&&r.isTransparentBelowCalMin)continue;b=Math.max(0,b),b=Math.min(255,b);let w=A[b];b*=4;let C=y*28+24;if(this.f32PerVertex!==7&&(C=y*20+16),r.isAdditiveBlend){const M=y*4;i[M+0]=d(i[M+0],a[b+0]),i[M+1]=d(i[M+1],a[b+1]),i[M+2]=d(i[M+2],a[b+2]),i[M+3]=d(i[M+3],255)}else{if(x[y]&&(w=r.outlineBorder,r.outlineBorder<0)){e[C+0]=0,e[C+1]=0,e[C+2]=0;continue}e[C+0]=h(e[C+0],a[b+0],w),e[C+1]=h(e[C+1],a[b+1],w),e[C+2]=h(e[C+2],a[b+2],w)}}}updateMesh(e){if(this.offsetPt0){this.updateFibers(e);return}if(this.hasConnectome)return;if(!this.pts||!this.tris||!this.rgba255){F.warn("underspecified mesh");return}function i(c,h,d){return c*(1-d)+h*d}const r=this.generatePosNormClr(this.pts,this.tris,this.rgba255),s=this.pts.length/3,n=new Uint8Array(r.buffer);let a=0;const o=new Uint8Array(s*4);let l=this.tris;if(this.layers&&this.layers.length>0)for(let c=0;c<this.layers.length;c++){const h=this.layers[c],d=h.opacity;if(d<=0||h.cal_min>h.cal_max)continue;if(h.outlineBorder===void 0&&(h.outlineBorder=0),h.isAdditiveBlend===void 0&&(h.isAdditiveBlend=!1),h.colormapLabel&&h.colormapLabel.R&&!h.colormapLabel.lut&&(h.colormapLabel=re.makeLabelLut(h.colormapLabel,255,h.global_max)),h.colormapLabel&&h.colormapLabel.lut){const u=h.colormapLabel;let m=0;h.colormapLabel.min&&(m=h.colormapLabel.min);let p=u.lut;const g=Math.floor(p.length/4);if(h.atlasValues&&g>0&&g===h.atlasValues.length&&h.colormap){const w=h.atlasValues;let C=!1,M=!0;for(let T=0;T<g;T++)isNaN(w[T])?C=!0:M=!1;if(M){F.debug("invisible mesh: all atlasValues are NaN.");return}if(C){F.debug("some vertices have NaN atlasValues (mesh will be decimated).");const T=new Array(s).fill(!1);for(let B=0;B<s;B++){const V=Math.round(h.values[B])-m;isNaN(w[V])&&(T[B]=!0)}const E=new Array(l.length).fill(!1);for(let B=0;B<l.length;B++)T[l[B]]&&(E[B]=!0);const I=this.tris;let S=0;for(let B=0;B<I.length;B+=3)!E[B]&&!E[B+1]&&!E[B+2]&&S++;S===0&&F.debug("invisible mesh: all triangles of a vertex with a NaN atlasValue."),l=new Uint32Array(S*3);let U=0;for(let B=0;B<I.length;B+=3)!E[B]&&!E[B+1]&&!E[B+2]&&(l[U++]=I[B],l[U++]=I[B+1],l[U++]=I[B+2])}p.fill(0),p=this.scalars2RGBA(p,h,w),h.useNegativeCmap&&(p=this.scalars2RGBA(p,h,w,!0))}else h.atlasValues&&F.warn(`Expected ${g} atlasValues but got ${h.atlasValues.length} for mesh layer`);if(h.showLegend&&g===h.colormapLabel.labels.length){h.labels=[];for(let w=0;w<g;w++){const C=Array.from(p.slice(w*4,w*4+4)).map(S=>S/255),M=h.colormapLabel.labels[w],T=[0,0,0];let E=0;for(let S=0;S<s;S++)if(h.values[S]===w){const U=S*3;T[0]+=this.pts[U],T[1]+=this.pts[U+1],T[2]+=this.pts[U+2],E++}if(E>0&&(T[0]/=E,T[1]/=E,T[2]/=E),C[3]===0||!M||M.startsWith("_"))continue;C[3]=1;const I=new Er(M,{textColor:C,bulletScale:1,bulletColor:C,lineWidth:0,lineColor:C,textScale:1,textAlignment:"left",lineTerminator:"none"},T);h.labels.push(I),F.debug("label for mesh layer:",I)}}else delete h.labels;const x=Math.min(Math.max(h.frame4D,0),h.nFrame4D-1),A=s*x,y=new Uint8Array(s*4);let v=0;for(let w=0;w<s;w++){const C=h.values[w+A]-m,M=4*Math.min(Math.max(C,0),g-1);y[v+0]=p[M+0],y[v+1]=p[M+1],y[v+2]=p[M+2],y[v+3]=Math.round(p[M+3]/255*h.opacity*255),v+=4}let b=new Array(s).fill(!1);h.outlineBorder!==0&&(b=$e.getClusterBoundary(y,this.tris)),v=0;for(let w=0;w<s;w++){let C=w*28+24;this.f32PerVertex!==7&&(C=w*20+16);let M=y[v+3]/255;if(b[w]&&(M=h.outlineBorder,h.outlineBorder<0)){n[C+0]=0,n[C+1]=0,n[C+2]=0,v+=4;continue}n[C+0]=i(n[C+0],y[v+0],M),n[C+1]=i(n[C+1],y[v+1],M),n[C+2]=i(n[C+2],y[v+2],M),v+=4}continue}if(h.values instanceof Uint8Array){const u=new Uint8Array(h.values.buffer);let m=new Array(s).fill(!0);h.outlineBorder!==0&&(m=$e.getClusterBoundary(u,this.tris));let p=0;for(let g=0;g<h.values.length;g++){let x=g*28+24;this.f32PerVertex!==7&&(x=g*20+16);let A=d;if(m[g]&&(A=h.outlineBorder,h.outlineBorder<0)){n[x+0]=0,n[x+1]=0,n[x+2]=0,p+=4;continue}n[x+0]=i(n[x+0],u[p+0],A),n[x+1]=i(n[x+1],u[p+1],A),n[x+2]=i(n[x+2],u[p+2],A),p+=4}continue}h.useNegativeCmap&&(h.cal_min=Math.max(Number.EPSILON,h.cal_min),h.cal_max=Math.max(h.cal_min+1e-6,h.cal_max)),h.isTransparentBelowCalMin===void 0&&(h.isTransparentBelowCalMin=!0);const f=re.colormap(h.colormap,h.colormapInvert);if(h.isAdditiveBlend&&a++,this.blendColormap(n,o,h,h.cal_min,h.cal_max,f),h.useNegativeCmap){const u=re.colormap(h.colormapNegative,h.colormapInvert);let m=h.cal_min,p=h.cal_max;isFinite(h.cal_minNeg)&&isFinite(h.cal_minNeg)&&(m=-h.cal_minNeg,p=-h.cal_maxNeg),this.blendColormap(n,o,h,m,p,u,!0)}}if(a>0)for(let c=0;c<s;c++){let h=function(m,p){return Math.min(m*p*.00392156862745098,255)},d=c*28+24;this.f32PerVertex!==7&&(d=c*20+16);const f=c*4,u=Math.min(a,o[f+3]/255);u<=0||(n[d+0]=h(n[d+0],o[f+0]),n[d+1]=h(n[d+1],o[f+1]),n[d+2]=h(n[d+2],o[f+2]),n[d+0]=i(n[d+0],o[f+0],u),n[d+1]=i(n[d+1],o[f+1],u),n[d+2]=i(n[d+2],o[f+2],u))}e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,Uint32Array.from(l),e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,n,e.STATIC_DRAW),this.indexCount=l.length,this.vertexCount=this.pts.length}reverseFaces(e){if(this.offsetPt0||this.hasConnectome)return;const i=this.tris||[];for(let r=0;r<i.length;r+=3){const s=i[r];i[r]=i[r+1],i[r+1]=s}this.updateMesh(e)}hierarchicalOrder(){const r=this.tris.length/3,s=Math.log(r/20)/Math.log(4);if(r!==Math.pow(4,s)*20)return NaN;if(this.pts.length/3!==Math.pow(4,s)*10+2)return NaN;for(let a=0;a<15;a+=3)if(this.tris[a]!==0)return NaN;for(let a=15;a<24;a+=3)if(this.tris[a]!==3)return NaN;for(let a=24;a<30;a+=3)if(this.tris[a]!==4)return NaN;return s}decimateFaces(e,i){let r=this.tris;const s=12,n=20;for(let a=e-1;a>=i;a--){const o=Math.pow(4,a+1)*(s-2)+2,l=Math.pow(4,a)*(s-2)+2,c=r.length/3,h=Math.pow(4,a)*n;F.info(`order ${a+1} -> ${a} vertices ${o} -> ${l} faces ${c} -> ${h}`);const d=Array.from({length:o},(u,m)=>m+1);for(let u=0;u<c;u++){const m=r[3*u],p=r[3*u+1],g=r[3*u+2];d[m-1]=Math.min(d[m-1],p,g)}const f=new Uint32Array(h*3);for(let u=0;u<h;u++)f[3*u]=d[r[3*u]-1],f[3*u+1]=d[r[3*u+1]-1],f[3*u+2]=d[r[3*u+2]-1];r=f}this.tris=new Uint32Array(r)}decimateHierarchicalMesh(e,i=4){const r=this.hierarchicalOrder();if(isNaN(r))return F.warn("Unable to decimate mesh: it does not have a hierarchical structure"),!1;if(i>=r)return F.warn(`Unable to decimate mesh: input order (${r}) must be larger than downsampled order (${i})`),!1;const s=this.pts.length/3,a=Math.pow(4,i)*(12-2)+2;if(this.pts=new Float32Array(this.pts.slice(0,a*3)),this.decimateFaces(r,i),this.layers&&this.layers.length>0)for(let o=0;o<this.layers.length;o++){const l=this.layers[o];l.values instanceof Float32Array||l.values.length!==s?l.values=new Float32Array(l.values.slice(0,a)):F.warn("decimation logic needs to be updated")}return this.updateMesh(e),!0}async setLayerProperty(e,i,r,s){const n=this.layers[e];if(!n||!(i in n)){F.warn("mesh does not have property ",i," for layer ",n);return}if(i==="colormapLabel")if(typeof r=="object")n[i]=re.makeLabelLut(r,255,n.global_max);else if(typeof r=="string"){const a=await re.makeLabelLutFromUrl(r);n[i]=a,this.updateMesh(s);return}else F.error("colormapLabel requires a string or object");else n[i]=r;this.updateMesh(s)}setProperty(e,i,r){if(!(e in this)){console.warn("Mesh does not have property:",e,this);return}this[e]=i,this.updateMesh(r)}generatePosNormClr(e,i,r){(e.length<3||r.length<4)&&(F.error("Catastrophic failure generatePosNormClr()"),F.debug("this",this),F.debug("pts",e),F.debug("rgba",r));const s=$e.generateNormals(e,i),n=e.length/3,a=n===r.length/4,o=this.f32PerVertex,l=new Float32Array(n*o),c=new Uint8Array(l.buffer);let h=0,d=0,f=0,u=(o-1)*4;for(let m=0;m<n;m++)l[f+0]=e[h+0],l[f+1]=e[h+1],l[f+2]=e[h+2],o!==7?(c[u-4]=s[h+0]*127,c[u-3]=s[h+1]*127,c[u-2]=s[h+2]*127):(l[f+3]=s[h+0],l[f+4]=s[h+1],l[f+5]=s[h+2]),c[u]=r[d+0],c[u+1]=r[d+1],c[u+2]=r[d+2],c[u+3]=r[d+3],a&&(d+=4),h+=3,f+=o,u+=o*4;return l}static async readMesh(e,i,r,s=1,n=new Uint8Array([255,255,255,255]),a=!0){let o=new Uint32Array([]),l=new Float32Array([]),c="",h;const d=/(?:\.([^.]+))?$/;let f=d.exec(i)[1];if(f=f.toUpperCase(),f==="GZ"&&(f=d.exec(i.slice(0,-3))[1],f=f.toUpperCase()),f==="JCON"&&F.error("you should never see this message: load using nvconnectome not nvmesh"),f==="JSON"&&F.error("you should never see this message: load using nvconnectome not nvmesh"),n[3]=Math.max(1,n[3]),f==="TCK"||f==="TRK"||f==="TT"||f==="TRX"||f==="TRACT"){if(f==="TCK"?h=ce.readTCK(e):f==="TRACT"?h=ce.readTRACT(e):f==="TT"?h=await ce.readTT(e):f==="TRX"?h=await ce.readTRX(e):h=await ce.readTRK(e),typeof h>"u"){const g=new Float32Array([0,0,0,0,0,0]),x=new Uint32Array([0]);h={pts:g,offsetPt0:x},F.error("Creating empty tracts")}return n[3]=0,new Le(h.pts,h.offsetPt0,i,n,s,a,r,"inferno",h.dpg||null,h.dps||null,h.dpv||null,h.groups)}if(f==="GII")h=await ce.readGII(e);else if(f==="MZ3")h=await ce.readMZ3(e),"positions"in h||F.warn("MZ3 does not have positions (statistical overlay?)");else if(f==="ASC")h=ce.readASC(e);else if(f==="DFS")h=ce.readDFS(e);else if(f==="BYU"||f==="G")h=ce.readGEO(e);else if(f==="GEO")h=ce.readGEO(e,!0);else if(f==="ICO"||f==="TRI")h=ce.readICO(e);else if(f==="OFF")h=ce.readOFF(e);else if(f==="NV")h=ce.readNV(e);else if(f==="OBJ")h=await ce.readOBJ(e);else if(f==="PLY")h=ce.readPLY(e);else if(f==="WRL")h=ce.readWRL(e);else if(f==="X3D")h=ce.readX3D(e);else if(f==="FIB"||f==="VTK"){if(h=ce.readVTK(e),"offsetPt0"in h)return n[3]=0,new Le(h.pts,h.offsetPt0,i,n,s,a,r,"inferno")}else f==="SRF"?h=await ce.readSRF(e):f==="STL"?h=ce.readSTL(e):h=ce.readFreeSurfer(e);if(h.anatomicalStructurePrimary&&(c=h.anatomicalStructurePrimary),h instanceof Float32Array)throw new Error("fatal: unknown mesh type loaded");if(!("positions"in h))throw new Error("positions not loaded");if(!h.indices)throw new Error("indices not loaded");if(l=h.positions,o=h.indices,"rgba255"in h&&h.rgba255.length>0&&(n=h.rgba255),"colors"in h&&h.colors&&h.colors.length===l.length){const g=l.length/3;n=new Uint8Array(g*4);let x=0,A=0;for(let y=0;y<g;y++)n[A++]=h.colors[x]*255,n[A++]=h.colors[x+1]*255,n[A++]=h.colors[x+2]*255,n[A++]=255,x+=3}const u=l.length/3;if(o.length/3<1||u<3)throw new Error("Mesh should have at least one triangle and three vertices");n[3]=Math.max(1,n[3]);const p=new Le(l,o,i,n,s,a,r,null,null,null,null,null,!0,c);if("scalars"in h&&h.scalars.length>0){const g=await ce.readLayer(i,e,p,s,"gray");typeof g>"u"?F.warn("readLayer() failed to convert scalars"):(p.layers.push(g),p.updateMesh(r))}return p}static async loadLayer(e,i){let r=new Uint8Array().buffer;function s(m){const p=window.atob(m),g=p.length,x=new Uint8Array(g);for(let A=0;A<g;A++)x[A]=p.charCodeAt(A);return x.buffer}if(e.base64!==void 0)r=s(e.base64);else{if(!e.url)throw new Error("layer: missing url");const m=await fetch(e.url,{headers:e.headers});if(!m.ok)throw Error(m.statusText);r=await m.arrayBuffer()}let n,a=[];if(e.name&&e.name!=="")n=e.name;else{if(!e.url)throw new Error("layer: missing url");try{a=new URL(e.url).pathname.split("/")}catch{a=e.url.split("/")}finally{n=a.slice(-1)[0]}}n.indexOf("?")>-1&&(n=n.slice(0,n.indexOf("?")));let o=.5;"opacity"in e&&(o=e.opacity);let l="warm";"colormap"in e&&(l=e.colormap);let c="winter";"colormapNegative"in e&&(c=e.colormapNegative);let h=!1;"useNegativeCmap"in e&&(h=e.useNegativeCmap);let d=null;"cal_min"in e&&(d=e.cal_min);let f=null;"cal_max"in e&&(f=e.cal_max);const u=await ce.readLayer(n,r,i,o,l,c,h,d,f);u&&i.layers.push(u)}static async loadFromUrl({url:e="",headers:i={},gl:r,name:s="",opacity:n=1,rgba255:a=[255,255,255,255],visible:o=!0,layers:l=[],buffer:c=new ArrayBuffer(0),meshShaderIndex:h=0}={}){let d=e.split("/");if(s===""){try{d=new URL(e).pathname.split("/")}catch{d=e.split("/")}s=d.slice(-1)[0],s.indexOf("?")>-1&&(s=s.slice(0,s.indexOf("?")))}if(e==="")throw Error("url must not be empty");if(!r)throw Error("gl context is null");let f;if(c.byteLength>0)f=c;else{const m=await fetch(e,{headers:i});if(!m.ok)throw Error(m.statusText);f=await m.arrayBuffer()}const u=await this.readMesh(f,s,r,n,new Uint8Array(a),o);if(h!==void 0&&(u.meshShaderIndex=h),!l||l.length<1)return u;for(let m=0;m<l.length;m++)await Le.loadLayer(l[m],u);return u.updateMesh(r),u}static async readFileAsync(e){return new Promise((i,r)=>{const s=new FileReader;s.onload=()=>{i(s.result)},s.onerror=r,s.readAsArrayBuffer(e)})}static async loadFromFile({file:e,gl:i,name:r="",opacity:s=1,rgba255:n=[255,255,255,255],visible:a=!0,layers:o=[]}={}){if(!e)throw new Error("file must be set");if(!i)throw new Error("rendering context must be set");const l=await Le.readFileAsync(e),c=await Le.readMesh(l,r,i,s,new Uint8Array(n),a);if(!o||o.length<1)return c;for(let h=0;h<o.length;h++)await Le.loadLayer(o[h],c);return c.updateMesh(i),c}async loadFromBase64({base64:e,gl:i,name:r="",opacity:s=1,rgba255:n=[255,255,255,255],visible:a=!0,layers:o=[]}={}){if(!e)throw new Error("base64 must bet set");if(!i)throw new Error("rendering context must be set");function l(d){const f=window.atob(d),u=f.length,m=new Uint8Array(u);for(let p=0;p<u;p++)m[p]=f.charCodeAt(p);return m.buffer}const c=l(e),h=await Le.readMesh(c,r,i,s,new Uint8Array(n),a);if(!o||o.length<1)return h;for(let d=0;d<o.length;d++)await Le.loadLayer(o[d],h);return h.updateMesh(i),h}},Gc="data:image/jpeg;base64,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ZwAAAAAAAAALY3JvcFJlY3RUb3Bsb25nAAAAAAA4QklNA+0AAAAAABAASAAAAAEAAQBIAAAAAQABOEJJTQQmAAAAAAAOAAAAAAAAAAAAAD+AAAA4QklNBA0AAAAAAAQAAAAeOEJJTQQZAAAAAAAEAAAAHjhCSU0D8wAAAAAACQAAAAAAAAAAAQA4QklNJxAAAAAAAAoAAQAAAAAAAAABOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0EAAAAAAAAAgAAOEJJTQQCAAAAAAACAAA4QklNBDAAAAAAAAEBADhCSU0ELQAAAAAABgABAAAAMjhCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAAM9AAAABgAAAAAAAAAAAAACAAAAAgAAAAAEAG0AYwA2ADEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAAIAAAAAAFJnaHRsb25nAAACAAAAAAZzbGljZXNWbExzAAAAAU9iamMAAAABAAAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAAGb3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQAAAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAA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bnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDctMTJUMjA6MDc6NDcrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA3LTEzVDE3OjU0OjI3KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE4LTA3LTEzVDE3OjU0OjI3KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL2pwZWciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo3MmVhYjVmZS02NDZkLWVhNDMtODQyNC0xNWQzZTgwOWExNDQiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo0OGNjMGI3YS1iYTJkLWZmNDAtYmNkNC1jNGQzMzIyZjBiNzQiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDphYzFjM2NhNS1hYTg4LWI5NGMtOGE4MS05YmU4MjA3ZGZiODciPiA8cGhvdG9zaG9wOkRvY3VtZW50QW5jZXN0b3JzPiA8cmRmOkJhZz4gPHJkZjpsaT5hZG9iZTpkb2NpZDpwaG90b3Nob3A6YThjMGNhZTYtODNjYy1hYzQ4LWI2YzAtN2FiODNlOWJkMGM3PC9yZGY6bGk+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6RG9jdW1lbnRBbmNlc3RvcnM+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6YWMxYzNjYTUtYWE4OC1iOTRjLThhODEtOWJlODIwN2RmYjg3IiBzdEV2dDp3aGVuPSIyMDE4LTA3LTEyVDIwOjA3OjQ3KzAxOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgKFdpbmRvd3MpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpjYmI3MzZlZC0zOTRhLTM2NDgtYThiOC02Mzk1MmY0NDcxMjIiIHN0RXZ0OndoZW49IjIwMTgtMDctMTNUMTY6MTM6NTgrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjQ2YjNkYTI3LWI4YjEtYmU0Yi1hYTQ4LTExZGM5NmZkNTIyZiIgc3RFdnQ6d2hlbj0iMjAxOC0wNy0xM1QxNzo1NDoyNyswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGFwcGxpY2F0aW9uL3ZuZC5hZG9iZS5waG90b3Nob3AgdG8gaW1hZ2UvanBlZyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iZGVyaXZlZCIgc3RFdnQ6cGFyYW1ldGVycz0iY29udmVydGVkIGZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9qcGVnIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo3MmVhYjVmZS02NDZkLWVhNDMtODQyNC0xNWQzZTgwOWExNDQiIHN0RXZ0OndoZW49IjIwMTgtMDctMTNUMTc6NTQ6MjcrMDE6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjQ2YjNkYTI3LWI4YjEtYmU0Yi1hYTQ4LTExZGM5NmZkNTIyZiIgc3RSZWY6ZG9jdW1lbnRJRD0iYWRvYmU6ZG9jaWQ6cGhvdG9zaG9wOjg3NjM1NDk5LWZiMTItYWU0MC04NWEzLThkMWFiN2NkZGVhOSIgc3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmFjMWMzY2E1LWFhODgtYjk0Yy04YTgxLTliZTgyMDdkZmI4NyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+/+IMWElDQ19QUk9GSUxFAAEBAAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1TRlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAEAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVzYwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAAAlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAkbHVtaQAAA/gAAAAUbWVhcwAABAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAABDwAAAgMYlRSQwAABDwAAAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1Q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",fs="data:image/png;base64,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",us={atlas:{type:"msdf",distanceRange:2,size:59.65625,width:512,height:256,yOrigin:"bottom"},metrics:{emSize:1,lineHeight:1.171875,ascender:.927734375,descender:-.244140625,underlineY:-.09765625,underlineThickness:.048828125},glyphs:[{unicode:32,advance:.24755859375},{unicode:33,advance:.25732421875,planeBounds:{left:.056159633438645884,bottom:-.02437761405677056,right:.20702396031135412,top:.7299440203067705},atlasBounds:{left:488.5,bottom:145.5,right:497.5,top:190.5}},{unicode:34,advance:.31982421875,planeBounds:{left:.049409125974004715,bottom:.48691155587022,right:.2840869677759953,top:.77187750662978},atlasBounds:{left:486.5,bottom:213.5,right:500.5,top:230.5}},{unicode:35,advance:.61572265625,planeBounds:{left:.037219103997511785,bottom:-.02169206718177056,right:.6239137085024882,top:.7326295671817705},atlasBounds:{left:66.5,bottom:51.5,right:101.5,top:96.5}},{unicode:36,advance:.5615234375,planeBounds:{left:.02956531458715296,bottom:-.12381369908983761,right:.5324464041628472,top:.8484230740898377},atlasBounds:{left:109.5,bottom:197.5,right:139.5,top:255.5}},{unicode:37,advance:.732421875,planeBounds:{left:.026481776289942378,bottom:-.030073418674698794,right:.7137525987100576,top:.7410109186746989},atlasBounds:{left:88.5,bottom:144.5,right:129.5,top:190.5}},{unicode:38,advance:.62158203125,planeBounds:{left:.03225572125458355,bottom:-.030073418674698794,right:.6357130287454166,top:.7410109186746989},atlasBounds:{left:130.5,bottom:144.5,right:166.5,top:190.5}},{unicode:39,advance:.17431640625,planeBounds:{left:.028244602049502358,bottom:.49895501673814824,right:.14558352295049765,top:.7671582645118518},atlasBounds:{left:498.5,bottom:62.5,right:505.5,top:78.5}},{unicode:40,advance:.341796875,planeBounds:{left:.042983329377291775,bottom:-.250029542422407,right:.34471198312270823,top:.8227834486724072},atlasBounds:{left:.5,bottom:191.5,right:18.5,top:255.5}},{unicode:41,advance:.34765625,planeBounds:{left:-.003159248747708225,bottom:-.250029542422407,right:.29856940499770823,top:.8227834486724072},atlasBounds:{left:19.5,bottom:191.5,right:37.5,top:255.5}},{unicode:42,advance:.4306640625,planeBounds:{left:-.011208599684062338,bottom:.27785390031593765,right:.44138438093406235,top:.7304468809340623},atlasBounds:{left:449.5,bottom:23.5,right:476.5,top:50.5}},{unicode:43,advance:.56689453125,planeBounds:{left:.01353503347629649,bottom:.053493525733368255,right:.5499415290237036,top:.6066627242666317},atlasBounds:{left:361.5,bottom:17.5,right:393.5,top:50.5}},{unicode:44,advance:.1962890625,planeBounds:{left:-.009919475797210583,bottom:-.15981695975478,right:.1744702570472106,top:.12514899100478},atlasBounds:{left:498.5,bottom:79.5,right:509.5,top:96.5}},{unicode:45,advance:.27587890625,planeBounds:{left:-.00527594412977999,bottom:.24333249267450235,right:.27969000662978,top:.36067141357549765},atlasBounds:{left:52.5,bottom:7.5,right:69.5,top:14.5}},{unicode:46,advance:.26318359375,planeBounds:{left:.051032680313645884,bottom:-.027092319686354116,right:.20189700718635412,top:.12377200718635412},atlasBounds:{left:501.5,bottom:221.5,right:510.5,top:230.5}},{unicode:47,advance:.412109375,planeBounds:{left:-.013733006073205867,bottom:-.08573505127848349,right:.4053345685732059,top:.7356373950284835},atlasBounds:{left:252.5,bottom:206.5,right:277.5,top:255.5}},{unicode:48,advance:.5615234375,planeBounds:{left:.037458384830081196,bottom:-.030073418674698794,right:.5235767714199189,top:.7410109186746989},atlasBounds:{left:167.5,bottom:144.5,right:196.5,top:190.5}},{unicode:49,advance:.5615234375,planeBounds:{left:.06023674350936354,bottom:-.01998308280677056,right:.37872810024063647,top:.7343385515567705},atlasBounds:{left:488.5,bottom:97.5,right:507.5,top:142.5}},{unicode:50,advance:.5615234375,planeBounds:{left:.025334353719224725,bottom:-.01680925468177056,right:.5449781462807752,top:.7375123796817705},atlasBounds:{left:278.5,bottom:51.5,right:309.5,top:96.5}},{unicode:51,advance:.5615234375,planeBounds:{left:.028181041080081196,bottom:-.030073418674698794,right:.5142994276699189,top:.7410109186746989},atlasBounds:{left:197.5,bottom:144.5,right:226.5,top:190.5}},{unicode:52,advance:.5615234375,planeBounds:{left:.005886103858368255,bottom:-.02169206718177056,right:.5590553023916317,top:.7326295671817705},atlasBounds:{left:310.5,bottom:51.5,right:343.5,top:96.5}},{unicode:53,advance:.5615234375,planeBounds:{left:.055524791080081196,bottom:-.02657487968177056,right:.5416431776699189,top:.7277467546817705},atlasBounds:{left:344.5,bottom:51.5,right:373.5,top:96.5}},{unicode:54,advance:.5615234375,planeBounds:{left:.046003306705081196,bottom:-.034712090549698794,right:.5321216932949189,top:.7363722467996989},atlasBounds:{left:227.5,bottom:144.5,right:256.5,top:190.5}},{unicode:55,advance:.5615234375,planeBounds:{left:.018010134969224725,bottom:-.02169206718177056,right:.5376539275307752,top:.7326295671817705},atlasBounds:{left:374.5,bottom:51.5,right:405.5,top:96.5}},{unicode:56,advance:.5615234375,planeBounds:{left:.037702525455081196,bottom:-.030073418674698794,right:.5238209120449189,top:.7410109186746989},atlasBounds:{left:257.5,bottom:144.5,right:286.5,top:190.5}},{unicode:57,advance:.5615234375,planeBounds:{left:.029401744205081196,bottom:-.025434746799698794,right:.5155201307949189,top:.7456495905496989},atlasBounds:{left:287.5,bottom:144.5,right:316.5,top:190.5}},{unicode:58,advance:.2421875,planeBounds:{left:.046394008438645884,bottom:-.029431286627488215,right:.19725833531135412,top:.5572633178774882},atlasBounds:{left:439.5,bottom:61.5,right:448.5,top:96.5}},{unicode:59,advance:.21142578125,planeBounds:{left:.001066852327789419,bottom:-.16459733294591408,right:.1854565851722106,top:.556198895445914},atlasBounds:{left:406.5,bottom:53.5,right:417.5,top:96.5}},{unicode:60,advance:.50830078125,planeBounds:{left:.016948142433865897,bottom:.0726146348300812,right:.4527784200661341,top:.5587330214199189},atlasBounds:{left:394.5,bottom:21.5,right:420.5,top:50.5}},{unicode:61,advance:.548828125,planeBounds:{left:.051535540940937666,bottom:.17620354038436353,right:.5041285215590624,top:.49469489711563647},atlasBounds:{left:477.5,bottom:31.5,right:504.5,top:50.5}},{unicode:62,advance:.5224609375,planeBounds:{left:.047629290940937666,bottom:.0731029160800812,right:.5002222715590624,top:.5592213026699189},atlasBounds:{left:421.5,bottom:21.5,right:448.5,top:50.5}},{unicode:63,advance:.47216796875,planeBounds:{left:.016704001808865897,bottom:-.027876153049698794,right:.4525342794411341,top:.7432081842996989},atlasBounds:{left:317.5,bottom:144.5,right:343.5,top:190.5}},{unicode:64,advance:.89794921875,planeBounds:{left:.034064457306783605,bottom:-.23896750384690937,right:.8721996065996072,top:.7165065663469093},atlasBounds:{left:155.5,bottom:198.5,right:205.5,top:255.5}},{unicode:65,advance:.65234375,planeBounds:{left:-.008838044092129387,bottom:-.02169206718177056,right:.6616700753421295,top:.7326295671817705},atlasBounds:{left:237.5,bottom:51.5,right:277.5,top:96.5}},{unicode:66,advance:.62255859375,planeBounds:{left:.06464099434422473,bottom:-.02169206718177056,right:.5842847869057752,top:.7326295671817705},atlasBounds:{left:205.5,bottom:51.5,right:236.5,top:96.5}},{unicode:67,advance:.65087890625,planeBounds:{left:.038439807122511785,bottom:-.030073418674698794,right:.6251344116274882,top:.7410109186746989},atlasBounds:{left:344.5,bottom:144.5,right:379.5,top:190.5}},{unicode:68,advance:.65576171875,planeBounds:{left:.06301501010836826,bottom:-.02169206718177056,right:.6161842086416317,top:.7326295671817705},atlasBounds:{left:162.5,bottom:51.5,right:195.5,top:96.5}},{unicode:69,advance:.568359375,planeBounds:{left:.0652904160800812,bottom:-.02169206718177056,right:.5514088026699189,top:.7326295671817705},atlasBounds:{left:132.5,bottom:51.5,right:161.5,top:96.5}},{unicode:70,advance:.552734375,planeBounds:{left:.059675181705081196,bottom:-.02169206718177056,right:.5457935682949189,top:.7326295671817705},atlasBounds:{left:102.5,bottom:51.5,right:131.5,top:96.5}},{unicode:71,advance:.68115234375,planeBounds:{left:.040148791497511785,bottom:-.030073418674698794,right:.6268433960024882,top:.7410109186746989},atlasBounds:{left:380.5,bottom:144.5,right:415.5,top:190.5}},{unicode:72,advance:.712890625,planeBounds:{left:.062365588372511785,bottom:-.02169206718177056,right:.6490601928774882,top:.7326295671817705},atlasBounds:{left:30.5,bottom:51.5,right:65.5,top:96.5}},{unicode:73,advance:.27197265625,planeBounds:{left:.06917965680657412,bottom:-.02169206718177056,right:.20328128069342588,top:.7326295671817705},atlasBounds:{left:196.5,bottom:51.5,right:204.5,top:96.5}},{unicode:74,advance:.5517578125,planeBounds:{left:.007184947330081194,bottom:-.02657487968177056,right:.4933033339199188,top:.7277467546817705},atlasBounds:{left:.5,bottom:51.5,right:29.5,top:96.5}},{unicode:75,advance:.626953125,planeBounds:{left:.061633166497511785,bottom:-.02169206718177056,right:.6483277710024882,top:.7326295671817705},atlasBounds:{left:452.5,bottom:97.5,right:487.5,top:142.5}},{unicode:76,advance:.5380859375,planeBounds:{left:.06341786132300943,bottom:-.02169206718177056,right:.5327735449269906,top:.7326295671817705},atlasBounds:{left:423.5,bottom:97.5,right:451.5,top:142.5}},{unicode:77,advance:.873046875,planeBounds:{left:.05911847969322944,bottom:-.02169206718177056,right:.8134401140567705,top:.7326295671817705},atlasBounds:{left:377.5,bottom:97.5,right:422.5,top:142.5}},{unicode:78,advance:.712890625,planeBounds:{left:.062365588372511785,bottom:-.02169206718177056,right:.6490601928774882,top:.7326295671817705},atlasBounds:{left:341.5,bottom:97.5,right:376.5,top:142.5}},{unicode:79,advance:.6875,planeBounds:{left:.033395854136655315,bottom:-.030073418674698794,right:.6536158646133446,top:.7410109186746989},atlasBounds:{left:416.5,bottom:144.5,right:453.5,top:190.5}},{unicode:80,advance:.630859375,planeBounds:{left:.061550166358368255,bottom:-.02169206718177056,right:.6147193648916317,top:.7326295671817705},atlasBounds:{left:273.5,bottom:97.5,right:306.5,top:142.5}},{unicode:81,advance:.6875,planeBounds:{left:.030466166636655315,bottom:-.14391866037519643,right:.6506861771133446,top:.7445045978751964},atlasBounds:{left:214.5,bottom:202.5,right:251.5,top:255.5}},{unicode:82,advance:.61572265625,planeBounds:{left:.06350329135836826,bottom:-.02169206718177056,right:.6166724898916317,top:.7326295671817705},atlasBounds:{left:186.5,bottom:97.5,right:219.5,top:142.5}},{unicode:83,advance:.59326171875,planeBounds:{left:.020778681983368255,bottom:-.030073418674698794,right:.5739478805166317,top:.7410109186746989},atlasBounds:{left:454.5,bottom:144.5,right:487.5,top:190.5}},{unicode:84,advance:.5966796875,planeBounds:{left:.005480822747511787,bottom:-.02169206718177056,right:.5921754272524882,top:.7326295671817705},atlasBounds:{left:112.5,bottom:97.5,right:147.5,top:142.5}},{unicode:85,advance:.6484375,planeBounds:{left:.049098994483368255,bottom:-.02657487968177056,right:.6022681930166317,top:.7277467546817705},atlasBounds:{left:78.5,bottom:97.5,right:111.5,top:142.5}},{unicode:86,advance:.63623046875,planeBounds:{left:-.008269192599201152,bottom:-.02169206718177056,right:.6454762238492011,top:.7326295671817705},atlasBounds:{left:38.5,bottom:97.5,right:77.5,top:142.5}},{unicode:87,advance:.88720703125,planeBounds:{left:.011923628617731797,bottom:-.02169206718177056,right:.8835841838822683,top:.7326295671817705},atlasBounds:{left:220.5,bottom:97.5,right:272.5,top:142.5}},{unicode:88,advance:.626953125,planeBounds:{left:.004098979136655316,bottom:-.02169206718177056,right:.6243189896133446,top:.7326295671817705},atlasBounds:{left:.5,bottom:97.5,right:37.5,top:142.5}},{unicode:89,advance:.6005859375,planeBounds:{left:-.010793598988344685,bottom:-.02169206718177056,right:.6094264114883446,top:.7326295671817705},atlasBounds:{left:148.5,bottom:97.5,right:185.5,top:142.5}},{unicode:90,advance:.5986328125,planeBounds:{left:.024196650733368255,bottom:-.02169206718177056,right:.5773658492666317,top:.7326295671817705},atlasBounds:{left:307.5,bottom:97.5,right:340.5,top:142.5}},{unicode:91,advance:.26513671875,planeBounds:{left:.05437250871693295,bottom:-.17280296457569408,right:.27228764753306706,top:.8329592145756942},atlasBounds:{left:59.5,bottom:195.5,right:72.5,top:255.5}},{unicode:92,advance:.41015625,planeBounds:{left:.0014037126767941326,bottom:-.08573505127848349,right:.4204712873232059,top:.7356373950284835},atlasBounds:{left:278.5,bottom:206.5,right:303.5,top:255.5}},{unicode:93,advance:.26513671875,planeBounds:{left:-.020659233400995285,bottom:-.17280296457569408,right:.2140186084009953,top:.8329592145756942},atlasBounds:{left:94.5,bottom:195.5,right:108.5,top:255.5}},{unicode:94,advance:.41796875,planeBounds:{left:.006855376669722368,bottom:.33229482979472236,right:.40916024833027764,top:.7345997014552776},atlasBounds:{left:486.5,bottom:231.5,right:510.5,top:255.5}},{unicode:95,advance:.451171875,planeBounds:{left:-.017473255794918804,bottom:-.09553469482549765,right:.4686451307949188,top:.021804226075497646},atlasBounds:{left:70.5,bottom:7.5,right:99.5,top:14.5}},{unicode:96,advance:.30908203125,planeBounds:{left:.00391839948107648,bottom:.5860277898277895,right:.2553589442689235,top:.7704175226722105},atlasBounds:{left:36.5,bottom:3.5,right:51.5,top:14.5}},{unicode:97,advance:.5439453125,planeBounds:{left:.028181041080081196,bottom:-.029187146002488215,right:.5142994276699189,top:.5575074585024882},atlasBounds:{left:30.5,bottom:15.5,right:59.5,top:50.5}},{unicode:98,advance:.56103515625,planeBounds:{left:.048932994205081196,bottom:-.032187684160555265,right:.5350513807949189,top:.7724220591605554},atlasBounds:{left:304.5,bottom:207.5,right:333.5,top:255.5}},{unicode:99,advance:.5234375,planeBounds:{left:.024518931705081196,bottom:-.029187146002488215,right:.5106373182949189,top:.5575074585024882},atlasBounds:{left:.5,bottom:15.5,right:29.5,top:50.5}},{unicode:100,advance:.56396484375,planeBounds:{left:.026227916080081196,bottom:-.032187684160555265,right:.5123463026699189,top:.7724220591605554},atlasBounds:{left:334.5,bottom:207.5,right:363.5,top:255.5}},{unicode:101,advance:.52978515625,planeBounds:{left:.026472056705081196,bottom:-.029187146002488215,right:.5125904432949189,top:.5575074585024882},atlasBounds:{left:468.5,bottom:61.5,right:497.5,top:96.5}},{unicode:102,advance:.34716796875,planeBounds:{left:.004575110905578838,bottom:-.022177918535555265,right:.3733545765944212,top:.7824318247855554},atlasBounds:{left:364.5,bottom:207.5,right:386.5,top:255.5}},{unicode:103,advance:.56103515625,planeBounds:{left:.026960337955081196,bottom:-.22888445766762702,right:.5130787245449189,top:.558962582667627},atlasBounds:{left:28.5,bottom:143.5,right:57.5,top:190.5}},{unicode:104,advance:.55078125,planeBounds:{left:.049826556565937666,bottom:-.01892352016762703,right:.5024195371840624,top:.768923520167627},atlasBounds:{left:.5,bottom:143.5,right:27.5,top:190.5}},{unicode:105,advance:.24267578125,planeBounds:{left:.046882289688645884,bottom:-.01680925468177056,right:.19774661656135412,top:.7375123796817705},atlasBounds:{left:498.5,bottom:145.5,right:507.5,top:190.5}},{unicode:106,advance:.23876953125,planeBounds:{left:-.048979545900995285,bottom:-.2324562772148376,right:.1856982959009953,top:.7397804959648377},atlasBounds:{left:140.5,bottom:197.5,right:154.5,top:255.5}},{unicode:107,advance:.5068359375,planeBounds:{left:.044294322330081196,bottom:-.01892352016762703,right:.5304127089199189,top:.768923520167627},atlasBounds:{left:58.5,bottom:143.5,right:87.5,top:190.5}},{unicode:108,advance:.24267578125,planeBounds:{left:.05428707868157412,bottom:-.01892352016762703,right:.18838870256842588,top:.768923520167627},atlasBounds:{left:477.5,bottom:208.5,right:485.5,top:255.5}},{unicode:109,advance:.87646484375,planeBounds:{left:.04430890170737297,bottom:-.024304333502488215,right:.832155942042627,top:.5623902710024882},atlasBounds:{left:116.5,bottom:15.5,right:163.5,top:50.5}},{unicode:110,advance:.5517578125,planeBounds:{left:.049826556565937666,bottom:-.024304333502488215,right:.5024195371840624,top:.5623902710024882},atlasBounds:{left:60.5,bottom:15.5,right:87.5,top:50.5}},{unicode:111,advance:.5703125,planeBounds:{left:.025090213094224725,bottom:-.029187146002488215,right:.5447340056557752,top:.5575074585024882},atlasBounds:{left:193.5,bottom:15.5,right:224.5,top:50.5}},{unicode:112,advance:.56103515625,planeBounds:{left:.048444712955081196,bottom:-.22644305141762702,right:.5345630995449189,top:.561403988917627},atlasBounds:{left:447.5,bottom:208.5,right:476.5,top:255.5}},{unicode:113,advance:.568359375,planeBounds:{left:.025983775455081196,bottom:-.22644305141762702,right:.5121021620449189,top:.561403988917627},atlasBounds:{left:417.5,bottom:208.5,right:446.5,top:255.5}},{unicode:114,advance:.33837890625,planeBounds:{left:.045180595002291775,bottom:-.024304333502488215,right:.34690924874770823,top:.5623902710024882},atlasBounds:{left:449.5,bottom:61.5,right:467.5,top:96.5}},{unicode:115,advance:.515625,planeBounds:{left:.021669814448009427,bottom:-.029187146002488215,right:.4910254980519906,top:.5575074585024882},atlasBounds:{left:164.5,bottom:15.5,right:192.5,top:50.5}},{unicode:116,advance:.32666015625,planeBounds:{left:-.019433670483564695,bottom:-.02877457520298586,right:.3158203892335647,top:.675258950202986},atlasBounds:{left:418.5,bottom:54.5,right:438.5,top:96.5}},{unicode:117,advance:.55126953125,planeBounds:{left:.048117572190937666,bottom:-.034069958502488215,right:.5007105528090624,top:.5526246460024882},atlasBounds:{left:88.5,bottom:15.5,right:115.5,top:50.5}},{unicode:118,advance:.484375,planeBounds:{left:-.002092396419918806,bottom:-.02080579450955998,right:.4840259901699188,top:.5491261070095601},atlasBounds:{left:331.5,bottom:16.5,right:360.5,top:50.5}},{unicode:119,advance:.75146484375,planeBounds:{left:-.002649098431770561,bottom:-.02080579450955998,right:.7516725359317705,top:.5491261070095601},atlasBounds:{left:225.5,bottom:16.5,right:270.5,top:50.5}},{unicode:120,advance:.49560546875,planeBounds:{left:-.0046143729128470395,bottom:-.02080579450955998,right:.4982667166628471,top:.5491261070095601},atlasBounds:{left:300.5,bottom:16.5,right:330.5,top:50.5}},{unicode:121,advance:.47314453125,planeBounds:{left:-.007219349544918806,bottom:-.23645281704262702,right:.4788990370449188,top:.551394223292627},atlasBounds:{left:387.5,bottom:208.5,right:416.5,top:255.5}},{unicode:122,advance:.49560546875,planeBounds:{left:.018007705073009427,bottom:-.02080579450955998,right:.4873633886769906,top:.5491261070095601},atlasBounds:{left:271.5,bottom:16.5,right:299.5,top:50.5}},{unicode:123,advance:.33837890625,planeBounds:{left:.011572188891435306,bottom:-.20234398020069408,right:.3468262486085647,top:.8034181989506942},atlasBounds:{left:73.5,bottom:195.5,right:93.5,top:255.5}},{unicode:124,advance:.24365234375,planeBounds:{left:.06315671142450235,bottom:-.15466084787519643,right:.18049563232549765,top:.7337624103751964},atlasBounds:{left:206.5,bottom:202.5,right:213.5,top:255.5}},{unicode:125,advance:.33837890625,planeBounds:{left:-.010156326733564695,bottom:-.20234398020069408,right:.3250977329835647,top:.8034181989506942},atlasBounds:{left:38.5,bottom:195.5,right:58.5,top:255.5}},{unicode:126,advance:.68017578125,planeBounds:{left:.046984728997511785,bottom:.1766063915990047,right:.6336793335024882,top:.4112842334009953},atlasBounds:{left:.5,bottom:.5,right:35.5,top:14.5}}],kerning:[]},Yc=33987,Xc=33988,Wc=33989;function Kc(t,e){const i=t.getContext("webgl2",{alpha:!0,antialias:e});if(!i)throw new Error("Unable to initialize WebGL2. Your browser may not support it.");return{gl:i,max2D:i.getParameter(i.MAX_TEXTURE_SIZE),max3D:i.getParameter(i.MAX_3D_TEXTURE_SIZE)}}function Hc(t,e,i,r,s=!1){if(e&&t.deleteTexture(e),e=t.createTexture(),t.activeTexture(i),t.bindTexture(t.TEXTURE_3D,e),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_R,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texStorage3D(t.TEXTURE_3D,1,t.R8,r[1],r[2],r[3]),s){const n=new Uint8Array(r[1]*r[2]*r[3]);t.texSubImage3D(t.TEXTURE_3D,0,0,0,0,r[1],r[2],r[3],t.RED,t.UNSIGNED_BYTE,n)}return e}function qc(t,e,i,r){return e&&t.deleteTexture(e),e=t.createTexture(),t.activeTexture(i),t.bindTexture(t.TEXTURE_3D,e),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_R,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texStorage3D(t.TEXTURE_3D,1,t.R8,r[1],r[2],r[3]),e}function Qc(t,e,i,r,s){e&&t.deleteTexture(e),e=t.createTexture(),t.activeTexture(i),t.bindTexture(t.TEXTURE_3D,e),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_R,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texStorage3D(t.TEXTURE_3D,1,t.R16I,r[1],r[2],r[3]);const n=r[1]*r[2]*r[3];return s.length!==n&&(s=new Int16Array(n)),t.texSubImage3D(t.TEXTURE_3D,0,0,0,0,r[1],r[2],r[3],t.RED_INTEGER,t.SHORT,s),e}function Zc(t,e,i,r,s){return e&&t.deleteTexture(e),e=t.createTexture(),t.activeTexture(i),t.bindTexture(t.TEXTURE_3D,e),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_R,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texStorage3D(t.TEXTURE_3D,1,t.R16F,r[1],r[2],r[3]),t.texSubImage3D(t.TEXTURE_3D,0,0,0,0,r[1],r[2],r[3],t.RED,t.FLOAT,s),e}function jc(t,e,i,r,s=null,n=!0){if(e&&t.deleteTexture(e),e=t.createTexture(),t.activeTexture(i),t.bindTexture(t.TEXTURE_2D,e),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texStorage2D(t.TEXTURE_2D,1,t.RGBA8,r[1],r[2]),s){let a=s;const o=r[1],l=r[2];if(n){a=new Uint8Array(s.length);const c=o*4;for(let h=0;h<l;h++){const d=h*c,f=(l-1-h)*c;a.set(s.subarray(d,d+c),f)}}t.texSubImage2D(t.TEXTURE_2D,0,0,0,o,l,t.RGBA,t.UNSIGNED_BYTE,a)}return e}function _c(t,e,i,r,s=!1){if(e&&t.deleteTexture(e),e=t.createTexture(),t.activeTexture(i),t.bindTexture(t.TEXTURE_3D,e),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_R,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.pixelStorei(t.UNPACK_ALIGNMENT,1),t.texStorage3D(t.TEXTURE_3D,1,t.RGBA8,r[1],r[2],r[3]),s){const n=new Uint8Array(r[1]*r[2]*r[3]*4);t.texSubImage3D(t.TEXTURE_3D,0,0,0,0,r[1],r[2],r[3],t.RGBA,t.UNSIGNED_BYTE,n)}return e}function Jc(t,e,i,r,s=!1){if(e&&t.deleteTexture(e),e=t.createTexture(),t.activeTexture(i),t.bindTexture(t.TEXTURE_3D,e),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_R,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_3D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.pixelStorei(t.UNPACK_ALIGNMENT,2),t.pixelStorei(t.PACK_ALIGNMENT,2),t.texStorage3D(t.TEXTURE_3D,1,t.RGBA16UI,r[1],r[2],r[3]),s){const n=new Uint16Array(r[1]*r[2]*r[3]*4);t.texSubImage3D(t.TEXTURE_3D,0,0,0,0,r[1],r[2],r[3],t.RGBA_INTEGER,t.UNSIGNED_SHORT,n)}return e}function xn(t,e){new URL(e,window.location.href).origin!==window.location.origin&&(t.crossOrigin="")}async function $c(t,e,i,r,s,n,a,o,l){return new Promise((c,h)=>{const d=new Image;d.onload=()=>{if(!s)return;let f;if(i===4){a!==null&&t.deleteTexture(a),f=t.createTexture();const u=d.width/d.height;t.activeTexture(Xc),s.use(t),t.uniform1i(s.uniforms.bmpTexture,4),l&&l(u)}else if(i===5)o!==null&&t.deleteTexture(o),f=t.createTexture(),t.activeTexture(Wc);else{if(!r){h(new Error("Font shader required for texture unit 3"));return}n!==null&&t.deleteTexture(n),f=t.createTexture(),r.use(t),t.activeTexture(Yc),t.uniform1i(r.uniforms.fontTexture,3)}t.bindTexture(t.TEXTURE_2D,f),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,d),c(f)},d.onerror=h,xn(d,e),d.src=e})}var er=()=>{const t=new ArrayBuffer(2);return new DataView(t).setInt16(0,256,!0),new Int16Array(t)[0]===256},vn=(t=>(t[t.UNKNOWN=0]="UNKNOWN",t[t.NII=1]="NII",t[t.DCM=2]="DCM",t[t.DCM_MANIFEST=3]="DCM_MANIFEST",t[t.MIH=4]="MIH",t[t.MIF=5]="MIF",t[t.NHDR=6]="NHDR",t[t.NRRD=7]="NRRD",t[t.MHD=8]="MHD",t[t.MHA=9]="MHA",t[t.MGH=10]="MGH",t[t.MGZ=11]="MGZ",t[t.V=12]="V",t[t.V16=13]="V16",t[t.VMR=14]="VMR",t[t.HEAD=15]="HEAD",t[t.DCM_FOLDER=16]="DCM_FOLDER",t[t.SRC=17]="SRC",t[t.FIB=18]="FIB",t[t.BMP=19]="BMP",t[t.ZARR=20]="ZARR",t[t.NPY=21]="NPY",t[t.NPZ=22]="NPZ",t[t.HDR=23]="HDR",t))(vn||{}),j=Object.freeze({...vn,parse:t=>{let e=0;switch(t.toUpperCase()){case"":case"DCM":e=2;break;case"TXT":e=3;break;case"FZ":case"GQI":case"QSDR":case"FIB":e=18;break;case"HDR":case"NII":e=1;break;case"MIH":e=4;break;case"MIF":e=5;break;case"NHDR":e=6;break;case"NRRD":e=7;break;case"MHD":e=8;break;case"MHA":e=9;break;case"MGH":e=10;break;case"MGZ":e=11;break;case"NPY":e=21;break;case"NPZ":e=22;break;case"SRC":e=17;break;case"V":e=12;break;case"V16":e=13;break;case"VMR":e=14;break;case"HEAD":e=15;break;case"PNG":case"BMP":case"GIF":case"JPG":case"JPEG":e=19;break;case"ZARR":e=20;break}return e}}),si=(t,e="",i="",r="gray",s=1,n=NaN,a=NaN,o=!0,l=.02,c=!1,h=!1,d="",f=0,u=j.UNKNOWN,m=NaN,p=NaN,g=!0,x=!1,A=null)=>({url:t,urlImageData:e,name:i,colormap:r,colorMap:r,opacity:s,cal_min:n,cal_max:a,trustCalMinMax:o,percentileFrac:l,ignoreZeroVoxels:c,useQFormNotSForm:h,colormapNegative:d,imageType:u,cal_minNeg:m,cal_maxNeg:p,colorbarVisible:g,frame4D:f,alphaThreshold:x,colormapLabel:A});function ms(t,e=80){t=t.replace(/[`$]/g,"");const i=[],r=Math.min(e,t.length);for(let s=0;s<r;s++){const n=t.charCodeAt(s);i.push(n&255)}return i}function ui(t,e=!1,i=!1){let n=!0;i&&(n=t.littleEndian);const a=new Uint8Array(348),o=new DataView(a.buffer);o.setInt32(0,348,n),o.setUint8(38,114),o.setUint8(39,t.dim_info);for(let c=0;c<8;c++)o.setUint16(40+2*c,t.dims[c],n);o.setFloat32(56,t.intent_p1,n),o.setFloat32(60,t.intent_p2,n),o.setFloat32(64,t.intent_p3,n),o.setInt16(68,t.intent_code,n),e?(o.setInt16(70,2,n),o.setInt16(72,8,n)):(o.setInt16(70,t.datatypeCode,n),o.setInt16(72,t.numBitsPerVoxel,n)),o.setInt16(74,t.slice_start,n);for(let c=0;c<8;c++)o.setFloat32(76+4*c,t.pixDims[c],n);e?(o.setFloat32(108,352,n),o.setFloat32(112,1,n),o.setFloat32(116,0,n)):(o.setFloat32(108,t.vox_offset,n),o.setFloat32(112,t.scl_slope,n),o.setFloat32(116,t.scl_inter,n)),o.setInt16(120,t.slice_end,n),o.setUint8(122,t.slice_code),t.xyzt_units===0?o.setUint8(123,10):o.setUint8(123,t.xyzt_units),e?(o.setFloat32(124,0,n),o.setFloat32(128,0,n)):(o.setFloat32(124,t.cal_max,n),o.setFloat32(128,t.cal_min,n)),o.setFloat32(132,t.slice_duration,n),o.setFloat32(136,t.toffset,n),a.set(ms(t.description),148),a.set(ms(t.aux_file),228),o.setInt16(252,t.qform_code,n),t.sform_code<1||t.sform_code<1?o.setInt16(254,1,n):o.setInt16(254,t.sform_code,n),o.setFloat32(256,t.quatern_b,n),o.setFloat32(260,t.quatern_c,n),o.setFloat32(264,t.quatern_d,n),o.setFloat32(268,t.qoffset_x,n),o.setFloat32(272,t.qoffset_y,n),o.setFloat32(276,t.qoffset_z,n);const l=t.affine.flat();for(let c=0;c<12;c++)o.setFloat32(280+4*c,l[c],n);return o.setInt32(344,3222382,!0),a}function eh(t,e=!0){const i=Math.round(t.length/3),r=k(0,0,0),s=se(),n=se();let a=0,o=1;e&&(o=2);for(let d=0;d<o;d++){a=0;for(let u=0;u<i;u++){const m=k(t[u*3],t[u*3+1],t[u*3+2]);u===0&&(Hr(s,m),Hr(n,m)),ur(s,s,m),mr(n,n,m),ne(m,m,r);const p=Vt(m);a=Math.max(a,p)}if(d+1>=o)break;let f=!0;for(let u=0;u<3;++u)s[u]>r[u]&&(f=!1),n[u]<r[u]&&(f=!1);if(f)break;Ba(r,s,n,.5),F.debug("origin moved inside volume: ",r)}const l=[s[0],s[1],s[2]],c=[n[0],n[1],n[2]];return{min:l,max:c,furthestVertexFromOrigin:a,origin:r}}function wn(t){const e=[!1,!1,!1,!1],i=[!1,!1,!1,!1];for(let r=0;r<4;r++)for(let s=0;s<4;s++)if(isNaN(t[r][s]))return!1;for(let r=0;r<3;r++)for(let s=0;s<3;s++)t[r][s]!==0&&(e[r]=!0,i[s]=!0);for(let r=0;r<3;r++)if(!e[r]||!i[r])return!1;return!0}async function Ir(t){const e=t.getReader(),{done:i,value:r}=await e.read();if(i)return e.releaseLock(),new ReadableStream({start(a){a.close()}});if(!r||r.length<2)return e.releaseLock(),new ReadableStream({start(a){r&&a.enqueue(r),a.close()}});const s=r[0]===31&&r[1]===139,n=new ReadableStream({async start(a){try{for(a.enqueue(r);;){const{done:o,value:l}=await e.read();if(o){a.close(),e.releaseLock();break}a.enqueue(l)}}catch(o){a.error(o),e.releaseLock()}}});return s?n.pipeThrough(new DecompressionStream("gzip")):n}function yn(t=[256,256,256],e=[1,1,1],i=[1,0,0,-128,0,1,0,-128,0,0,1,-128,0,0,0,1],r=2){const s=new G;s.littleEndian=!0,s.dims=[3,1,1,1,0,0,0,0],s.dims[0]=Math.max(3,t.length);for(let a=0;a<t.length;a++)s.dims[a+1]=t[a];s.pixDims=[1,1,1,1,1,0,0,0];for(let a=0;a<t.length;a++)s.pixDims[a+1]=e[a];if(i.length===16){let a=0;for(let o=0;o<4;o++)for(let l=0;l<4;l++)s.affine[o][l]=i[a],a++}let n=8;return r===256||r===2?n=8:r===512||r===4?n=16:r===16||r===768||r===8||r===2304?n=32:r===64?n=64:F.warn("Unsupported NIfTI datatypeCode for header creation: "+r),s.datatypeCode=r,s.numBitsPerVoxel=n,s.scl_inter=0,s.scl_slope=1,s.sform_code=2,s.magic="n+1",s.vox_offset=352,s}function th(t=[256,256,256],e=[1,1,1],i=[1,0,0,-128,0,1,0,-128,0,0,1,-128,0,0,0,1],r=2,s=new Uint8Array){const n=yn(t,e,i,r),a=ui(n,!1);n.vox_offset=Math.max(352,a.length);const o=ui(n,!1);if(s.length<1)return o;const l=Math.max(0,n.vox_offset-o.length),c=new Uint8Array(l),h=new Uint8Array(s.buffer,s.byteOffset,s.byteLength),d=n.vox_offset+h.length,f=new Uint8Array(d);return f.set(o,0),f.set(c,o.length),f.set(h,n.vox_offset),f}function bn(t,e=null){if(!t.hdr)throw new Error("NVImage header is not defined for toUint8Array");if(!t.img&&e===null)throw new Error("NVImage image data is not defined for toUint8Array");const i=e!==null,r=JSON.parse(JSON.stringify(t.hdr)),s=t.extensions&&t.extensions.length>0,n=new Uint8Array(4);n[0]=s?1:0;let a=new Uint8Array(0);if(s){const g=[];let x=0;for(const y of t.extensions){const v=new Uint8Array(y.edata),b=new Uint8Array(8+v.length),w=new DataView(b.buffer);w.setInt32(0,y.esize,!0),w.setInt32(4,y.ecode,!0),b.set(v,8),g.push(b),x+=b.length}a=new Uint8Array(x);let A=0;for(const y of g)a.set(y,A),A+=y.length}const o=348;r.vox_offset=Math.max(352,o+n.length+a.length),i&&(r.datatypeCode=2,r.numBitsPerVoxel=8,r.scl_slope=1,r.scl_inter=0);const l=ui(r,i);let c;if(i){const g=e,x=t.permRAS;if(x&&(x[0]!==1||x[1]!==2||x[2]!==3)){F.debug("Reorienting drawing bytes back to native space for saving...");const A=t.hdr.dims,y=A[1]*A[2]*A[3],v=t.dimsRAS?t.dimsRAS[1]*t.dimsRAS[2]*t.dimsRAS[3]:y;if(g.length!==v)console.warn(`Drawing length (${g.length}) does not match expected RAS voxel count (${v}). Cannot reorient drawing reliably.`),c=g;else if(!t.img2RASstep||!t.img2RASstart||!t.dimsRAS)console.warn("Missing RAS transformation info (img2RASstep, img2RASstart, dimsRAS). Cannot reorient drawing reliably."),c=g;else{const b=t.img2RASstep,w=t.img2RASstart,C=t.dimsRAS,M=new Uint8Array(y);M.fill(0);const T=g;let E=0;for(let I=0;I<C[3];I++){const S=w[2]+I*b[2];for(let U=0;U<C[2];U++){const B=w[1]+U*b[1];for(let V=0;V<C[1];V++){const P=w[0]+V*b[0]+B+S;P>=0&&P<y?M[P]=T[E]:E<T.length&&console.warn(`Calculated native index ${P} is out of bounds [0..${y-1}] during drawing reorientation.`),E++}}}c=M}}else c=g}else{if(!t.img)throw new Error("NVImage image data is null when trying to save non-drawing.");c=new Uint8Array(t.img.buffer,t.img.byteOffset,t.img.byteLength)}const h=l.length+n.length+a.length,d=Math.max(0,r.vox_offset-h),f=new Uint8Array(d),u=r.vox_offset+c.length,m=new Uint8Array(u);let p=0;return m.set(l,p),p+=l.length,m.set(n,p),p+=n.length,m.set(a,p),p+=a.length,m.set(f,p),p+=f.length,m.set(c,r.vox_offset),m}async function Cn(t,e,i=null){const r=bn(t,i);if(e.toLowerCase().endsWith(".gz"))try{const n=await H.compress(r,"gzip");return new Uint8Array(n)}catch(n){return F.error("Compression failed:",n),F.warn("Returning uncompressed data due to compression error."),r}else return r}async function ih(t,e="",i=null){const r=await Cn(t,e,i);if(!e)return F.debug("saveToDisk: empty file name, returning data as Uint8Array rather than triggering download"),r;try{const s=new Blob([r.buffer],{type:"application/octet-stream"}),n=URL.createObjectURL(s),a=document.createElement("a");a.setAttribute("href",n),a.setAttribute("download",e),a.style.visibility="hidden",document.body.appendChild(a),a.click(),document.body.removeChild(a),setTimeout(()=>URL.revokeObjectURL(n),100)}catch(s){F.error("Failed to trigger download:",s)}return r}function Mn(t,e,i,r,s=0,n=!1){if(!t.hdr)throw new Error("getValue: NVImage header is not defined.");if(!n&&!t.img)throw new Error("getValue: NVImage image data is not defined.");if(n&&!t.imaginary)return F.warn("getValue: Attempted to read imaginary data, but none exists."),[0];const a=t.hdr.dims[1],o=t.hdr.dims[2],l=t.hdr.dims[3],c=t.permRAS.slice();if(c[0]!==1||c[1]!==2||c[2]!==3){const A=ae(e,i,r,1);ve(A,A,t.toRASvox),e=A[0],i=A[1],r=A[2]}e=Math.max(0,Math.min(Math.round(e),a-1)),i=Math.max(0,Math.min(Math.round(i),o-1)),r=Math.max(0,Math.min(Math.round(r),l-1)),s=Math.max(0,s);let h=e+i*a+r*a*o;if(t.hdr.datatypeCode===2304)return t.img?(h*=4,h+3>=t.img.length?(F.warn(`getValue: Calculated index ${h} out of bounds for RGBA data.`),[0]):[t.img[h],t.img[h+1],t.img[h+2],t.img[h+3]]):[0];if(t.hdr.datatypeCode===128)return t.img?(h*=3,h+2>=t.img.length?(F.warn(`getValue: Calculated index ${h} out of bounds for RGB data.`),[0]):[t.img[h],t.img[h+1],t.img[h+2]]):[0];const d=a*o*l,f=s*d,u=h+f,m=n?t.imaginary:t.img;if(u<0||u>=m.length)return[0];const p=m[u],g=isNaN(t.hdr.scl_slope)||t.hdr.scl_slope===0?1:t.hdr.scl_slope,x=isNaN(t.hdr.scl_inter)?0:t.hdr.scl_inter;return[g*p+x]}function rh(t,e,i,r,s=0,n=!1){const a=Mn(t,e,i,r,s,n);return a.length<3?a[0]:a[0]*.2126+a[1]*.7152+a[2]*.0722}function sh(t,e=[-1,0,0],i=[0,0,0],r="same"){const s=[new Uint8Array,[0,0,0]];if(!t.hdr||!t.img||!t.dimsRAS||!t.img2RASstep||!t.img2RASstart)return F.error("getVolumeData: Missing required NVImage properties (hdr, img, dimsRAS, img2RASstep/start)."),s;if(e=e.slice(0,3),i=i.slice(0,3),Math.min(...e)<0||Math.min(...i)<0)return F.warn("getVolumeData: Invalid start or end coordinates provided."),s;const n=t.dimsRAS.slice(1,4);for(let g=0;g<3;g++)if(e[g]=Math.max(0,Math.min(Math.round(e[g]),n[g]-1)),i[g]=Math.max(0,Math.min(Math.round(i[g]),n[g]-1)),i[g]<e[g]){const x=i[g];i[g]=e[g],e[g]=x}const a=[i[0]-e[0]+1,i[1]-e[1]+1,i[2]-e[2]+1],o=a[0]*a[1]*a[2];if(o<=0)return F.warn("getVolumeData: Calculated slab size is zero or negative."),s;let l=t.img.constructor;r==="uint8"?l=Uint8Array:r==="int16"?l=Int16Array:r==="uint16"?l=Uint16Array:r==="float32"||r==="scaled"||r==="normalized"||r==="windowed"?l=Float32Array:r==="float64"?l=Float64Array:r!=="same"&&F.warn(`getVolumeData: Unsupported dataType '${r}'. Using 'same'.`);let c;try{c=new l(o)}catch(g){return F.error(`getVolumeData: Failed to create output array for dataType '${r}'.`,g),s}const h=t.img2RASstep,d=t.img2RASstart,f=t.img;let u=0;for(let g=e[2];g<=i[2];g++){const x=d[2]+g*h[2];for(let A=e[1];A<=i[1];A++){const y=d[1]+A*h[1];for(let v=e[0];v<=i[0];v++){const w=d[0]+v*h[0]+y+x;let C=0;w>=0&&w<f.length&&(C=f[w]),c[u++]=C}}}const m=isNaN(t.hdr.scl_slope)||t.hdr.scl_slope===0?1:t.hdr.scl_slope,p=isNaN(t.hdr.scl_inter)?0:t.hdr.scl_inter;if(r==="scaled"||r==="normalized"||r==="windowed"){c instanceof Float32Array||(F.warn(`getVolumeData: Converting output to Float32 for scaling type '${r}'.`),c=Float32Array.from(c));for(let g=0;g<c.length;g++)c[g]=c[g]*m+p}if(r==="normalized"||r==="windowed"){let g=t.cal_min,x=t.cal_max;r==="normalized"&&(g=t.global_min,x=t.global_max);const A=x-g,y=A===0?0:1/A;for(let v=0;v<c.length;v++)c[v]=(c[v]-g)*y,c[v]=Math.max(0,Math.min(c[v],1))}return[c,a]}function nh(t,e=[-1,0,0],i=[0,0,0],r=new Uint8Array){if(!t.hdr||!t.img||!t.dimsRAS||!t.img2RASstep||!t.img2RASstart){F.error("setVolumeData: Missing required NVImage properties (hdr, img, dimsRAS, img2RASstep/start).");return}if(r.length<1){F.warn("setVolumeData: Input slabData is empty.");return}if(e=e.slice(0,3),i=i.slice(0,3),Math.min(...e)<0||Math.min(...i)<0){F.warn("setVolumeData: Invalid start or end coordinates provided.");return}const s=t.dimsRAS.slice(1,4);for(let d=0;d<3;d++)if(e[d]=Math.max(0,Math.min(Math.round(e[d]),s[d]-1)),i[d]=Math.max(0,Math.min(Math.round(i[d]),s[d]-1)),i[d]<e[d]){const f=i[d];i[d]=e[d],e[d]=f}const n=[i[0]-e[0]+1,i[1]-e[1]+1,i[2]-e[2]+1],a=n[0]*n[1]*n[2];if(a<=0){F.warn("setVolumeData: Calculated slab size is zero or negative.");return}if(r.length<a){F.error(`setVolumeData: Input slabData length (${r.length}) is less than the calculated slab size (${a}).`);return}const o=t.img2RASstep,l=t.img2RASstart,c=t.img;let h=0;for(let d=e[2];d<=i[2];d++){const f=l[2]+d*o[2];for(let u=e[1];u<=i[1];u++){const m=l[1]+u*o[1];for(let p=e[0];p<=i[0];p++){const x=l[0]+p*o[0]+m+f;x>=0&&x<c.length&&(c[x]=r[h]),h++}}}}var tr={};be(tr,{readHEAD:()=>lh});function Wt(t,e){const i=de(e);Te(i,i);const r=ae(t[0],t[1],t[2],1);return ve(r,r,i),k(r[0],r[1],r[2])}function ah(t){if(!t.hdr)throw new Error("hdr not defined");const e=t.hdr.affine,i=Ee(e[0][0],e[0][1],e[0][2],e[0][3],e[1][0],e[1][1],e[1][2],e[1][3],e[2][0],e[2][1],e[2][2],e[2][3],e[3][0],e[3][1],e[3][2],e[3][3]),r=Wt([0,0,0],i),s=Wt([1,0,0],i);ne(s,s,r);const n=Wt([0,1,0],i);ne(n,n,r);const a=Wt([0,0,1],i);ne(a,a,r),t.hdr.pixDims[1]=Qe(s),t.hdr.pixDims[2]=Qe(n),t.hdr.pixDims[3]=Qe(a)}function oh(t,e,i,r){const s=t.hdr;if(s===null)throw new Error("HDR is not set");s.sform_code=2;const n="xxyyzzg";let a=-1,o=-1,l=-1;const c=["x","y","z"];c[0]=n[r[0]],c[1]=n[r[1]],c[2]=n[r[2]];const h=e.slice(0,3),d=i.slice(0,3);for(let f=0;f<3;f++)c[f]==="x"?a=f:c[f]==="y"?o=f:l=f;a<0||o<0||l<0||a===o||a===l||o===l||(s.pixDims[1]=Math.abs(h[0]),s.pixDims[2]=Math.abs(h[1]),s.pixDims[3]=Math.abs(h[2]),s.affine=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],s.affine[0][a]=-h[a],s.affine[1][o]=-h[o],s.affine[2][l]=h[l],s.affine[0][3]=-d[a],s.affine[1][3]=-d[o],s.affine[2][3]=d[l])}async function lh(t,e,i){t.hdr=new G;const r=t.hdr;r.dims[0]=3,r.pixDims=[1,1,1,1,1,0,0,0];let s=[0,0,0],n=[0,0,0],a=[1,1,1];const l=new TextDecoder().decode(e).split(/\r?\n/),c=(e.byteLength+8)%16,h=e.byteLength+(16-c);F.debug(e.byteLength,"len",h);const d=new ArrayBuffer(h);new Uint8Array(d).set(new Uint8Array(e));const f=new sn(h+8,42,d,!0);r.addExtension(f),r.extensionCode=42,r.extensionFlag[0]=1,r.extensionSize=h+8;const u=l.length;let m=0,p=!1;for(;m<u;){let x=l[m];if(m++,!x.startsWith("type"))continue;const A=x.includes("integer-attribute"),y=x.includes("float-attribute");if(x=l[m],m++,!x.startsWith("name"))continue;let v=x.split("= ");const b=v[1];x=l[m],m++,v=x.split("= ");let w=parseInt(v[1]);if(!(w<1)){if(x=l[m],m++,v=x.trim().split(/\s+/),y||A){for(;v.length<w;){x=l[m],m++;const C=x.trim().split(/\s+/);v.push(...C)}for(let C=0;C<w;C++)v[C]=parseFloat(v[C])}switch(b){case"BYTEORDER_STRING":v[0].includes("LSB_FIRST")?r.littleEndian=!0:v[0].includes("MSB_FIRST")&&(r.littleEndian=!1);break;case"BRICK_TYPES":{r.dims[4]=w;const C=parseInt(v[0]);C===0?(r.numBitsPerVoxel=8,r.datatypeCode=2):C===1?(r.numBitsPerVoxel=16,r.datatypeCode=4):C===3?(r.numBitsPerVoxel=32,r.datatypeCode=16):F.warn("Unknown BRICK_TYPES ",C)}break;case"IJK_TO_DICOM_REAL":if(w<12)break;p=!0,r.sform_code=2,r.affine=[[-v[0],-v[1],-v[2],-v[3]],[-v[4],-v[5],-v[6],-v[7]],[v[8],v[9],v[10],v[11]],[0,0,0,1]];break;case"DATASET_DIMENSIONS":w=Math.max(w,3);for(let C=0;C<w;C++)r.dims[C+1]=v[C];break;case"ORIENT_SPECIFIC":s=v;break;case"ORIGIN":n=v;break;case"DELTA":a=v;break;case"TAXIS_FLOATS":r.pixDims[4]=v[0];break;default:F.warn("Unknown:",b)}}}p?ah(t):oh(t,a,n,s);const g=r.numBitsPerVoxel/8*r.dims[1]*r.dims[2]*r.dims[3]*r.dims[4];if(!i)throw new Error("pairedImgData not set");return i.byteLength<g?await H.decompressToBuffer(new Uint8Array(i)):i.slice(0)}var Ct={};be(Ct,{readV16:()=>ch,readVMR:()=>hh});function ch(t,e){t.hdr=new G;const i=t.hdr;i.dims=[3,1,1,1,0,0,0,0],i.pixDims=[1,1,1,1,1,0,0,0];const r=new DataView(e);return i.dims[1]=r.getUint16(0,!0),i.dims[2]=r.getUint16(2,!0),i.dims[3]=r.getUint16(4,!0),2*i.dims[1]*i.dims[2]*i.dims[3]+6!==e.byteLength&&F.warn("This does not look like a valid BrainVoyager V16 file"),i.numBitsPerVoxel=16,i.datatypeCode=512,F.warn("Warning: V16 files have no spatial transforms"),i.affine=[[0,0,-i.pixDims[1],(i.dims[1]-2)*.5*i.pixDims[1]],[-i.pixDims[2],0,0,(i.dims[2]-2)*.5*i.pixDims[2]],[0,-i.pixDims[3],0,(i.dims[3]-2)*.5*i.pixDims[3]],[0,0,0,1]],i.littleEndian=!0,e.slice(6)}function hh(t,e){t.hdr=new G;const i=t.hdr;i.dims=[3,1,1,1,0,0,0,0],i.pixDims=[1,1,1,1,1,0,0,0];const r=new DataView(e),s=r.getUint16(0,!0);s!==4&&F.warn("Not a valid version 4 VMR image"),i.dims[1]=r.getUint16(2,!0),i.dims[2]=r.getUint16(4,!0),i.dims[3]=r.getUint16(6,!0);const n=i.dims[1]*i.dims[2]*i.dims[3];if(s>=4){let a=8+n;const o=r.getUint32(a+88,!0);if(a=a+92,o>0){const l=e.byteLength;for(let c=0;c<o;c++){for(;a<l&&r.getUint8(a)!==0;)a++;for(a++,a+=4;a<l&&r.getUint8(a)!==0;)a++;a++;const h=r.getUint32(a,!0);a+=4;for(let d=0;d<h;d++)a+=4}}i.pixDims[1]=r.getFloat32(a+2,!0),i.pixDims[2]=r.getFloat32(a+6,!0),i.pixDims[3]=r.getFloat32(a+10,!0)}return F.warn("Warning: VMR spatial transform not implemented"),i.affine=[[0,0,-i.pixDims[1],(i.dims[1]-2)*.5*i.pixDims[1]],[-i.pixDims[2],0,0,(i.dims[2]-2)*.5*i.pixDims[2]],[0,-i.pixDims[3],0,(i.dims[3]-2)*.5*i.pixDims[3]],[0,0,0,1]],F.debug(i),i.numBitsPerVoxel=8,i.datatypeCode=2,e.slice(8,8+n)}var Mt={};be(Mt,{readFIB:()=>dh,readSRC:()=>fh});async function dh(t,e){t.hdr=new G;const i=t.hdr;i.littleEndian=!1,i.dims=[3,1,1,1,0,0,0,0],i.pixDims=[1,1,1,1,1,0,0,0];const r=await H.readMatV4(e,!0);if(!("dimension"in r)||!("dti_fa"in r))throw new Error("Not a valid DSIstudio FIB file");const s="index0"in r&&"index1"in r&&"index2"in r&&"odf_vertices"in r;i.numBitsPerVoxel=32,i.datatypeCode=16,i.dims[1]=r.dimension[0],i.dims[2]=r.dimension[1],i.dims[3]=r.dimension[2],i.dims[4]=1,i.pixDims[1]=r.voxel_size[0],i.pixDims[2]=r.voxel_size[1],i.pixDims[3]=r.voxel_size[2],i.sform_code=1;const n=(i.dims[1]-1)*.5*i.pixDims[1],a=(i.dims[2]-1)*.5*i.pixDims[2],o=(i.dims[3]-1)*.5*i.pixDims[3];i.affine=[[i.pixDims[1],0,0,-n],[0,-i.pixDims[2],0,a],[0,0,i.pixDims[2],-o],[0,0,0,1]],i.littleEndian=!0;const l=i.dims[1]*i.dims[2]*i.dims[3],c=l*Math.ceil(i.numBitsPerVoxel/8),h=c*i.dims[4],d=new Uint8Array(new ArrayBuffer(l*4*3));if(s){const p=i.dims[1]*i.dims[2]*i.dims[3],g=new Float32Array(p),x=new Float32Array(p),A=new Float32Array(p),y=r.index0,v=r.odf_vertices;for(let b=0;b<p;b++){const w=y[b]*3;g[b]=v[w+0],x[b]=v[w+1],A[b]=-v[w+2]}d.set(new Uint8Array(g.buffer,g.byteOffset,g.byteLength),0*c),d.set(new Uint8Array(x.buffer,x.byteOffset,x.byteLength),1*c),d.set(new Uint8Array(A.buffer,A.byteOffset,A.byteLength),2*c)}"report"in r&&(i.description=new TextDecoder().decode(r.report.subarray(0,Math.min(79,r.report.byteLength))));const f=new Uint8Array(new ArrayBuffer(h)),u=Float32Array.from(r.dti_fa);if("mask"in r){let p=1;"dti_fa_slope"in r&&(p=r.dti_fa_slope[0]);let g=1;"dti_fa_inter"in r&&(g=r.dti_fa_inter[0]);const x=i.dims[1]*i.dims[2]*i.dims[3],A=r.mask,y=new Float32Array(x);let v=0;for(let b=0;b<x;b++)A[b]!==0&&(y[b]=u[v]*p+g,v++);return[y.buffer,new Float32Array(d.buffer)]}const m=new Uint8Array(u.buffer,u.byteOffset,u.byteLength);return f.set(m,0),[f.buffer,new Float32Array(d.buffer)]}async function fh(t,e){t.hdr=new G;const i=t.hdr;i.littleEndian=!1,i.dims=[3,1,1,1,0,0,0,0],i.pixDims=[1,1,1,1,1,0,0,0];const r=await H.readMatV4(e);if(!("dimension"in r)||!("image0"in r))throw new Error("Not a valid DSIstudio SRC file");let s=0,n=0;for(const[u,m]of Object.entries(r))if(u.startsWith("image")){if(s===0?n=m.length:n!==m.length&&(n=-1),m.constructor!==Uint16Array)throw new Error("DSIstudio SRC files always use Uint16 datatype");s++}if(n<1||s<1)throw new Error("SRC file not valid DSI Studio data. The image(s) should have the same length");i.numBitsPerVoxel=16,i.datatypeCode=512,i.dims[1]=r.dimension[0],i.dims[2]=r.dimension[1],i.dims[3]=r.dimension[2],i.dims[4]=s,i.dims[4]>1&&(i.dims[0]=4),i.pixDims[1]=r.voxel_size[0],i.pixDims[2]=r.voxel_size[1],i.pixDims[3]=r.voxel_size[2],i.sform_code=1;const a=(i.dims[1]-1)*.5*i.pixDims[1],o=(i.dims[2]-1)*.5*i.pixDims[2],l=(i.dims[3]-1)*.5*i.pixDims[3];i.affine=[[i.pixDims[1],0,0,-a],[0,-i.pixDims[2],0,o],[0,0,i.pixDims[2],-l],[0,0,0,1]],i.littleEndian=!0;const c=i.dims[1]*i.dims[2]*i.dims[3]*(i.numBitsPerVoxel/8),h=c*i.dims[4],d=new Uint8Array(new ArrayBuffer(h));let f=0;for(let u=0;u<s;u++){const m=r[`image${u}`],p=new Uint8Array(m.buffer,m.byteOffset,m.byteLength);d.set(p,f),f+=c}return"report"in r&&(i.description=new TextDecoder().decode(r.report.subarray(0,Math.min(79,r.report.byteLength)))),d.buffer}var ir={};be(ir,{readECAT:()=>uh});function uh(t,e){t.hdr=new G;const i=t.hdr;i.dims=[3,1,1,1,0,0,0,0],i.pixDims=[1,1,1,1,1,0,0,0];const r=new DataView(e),s=r.getInt32(0,!1),n=r.getInt16(50,!1);if(s!==1296127058||n<1||n>14)throw new Error("Not a valid ECAT file");let a=512,o=0;const l=[];let c=new Float32Array;for(;;){const h=r.getInt32(a,!1),d=r.getInt32(a+12,!1);if(h+d!==31)break;let f=a+20,u=0,m=0;for(;u<31&&(m=r.getInt32(f,!1),f+=16,m!==0);){u++;let p=m*512;const g=p-512,x=r.getUint16(g,!1);i.dims[1]=r.getUint16(g+4,!1),i.dims[2]=r.getUint16(g+6,!1),i.dims[3]=r.getUint16(g+8,!1);const A=r.getFloat32(g+26,!1);i.pixDims[1]=r.getFloat32(g+34,!1)*10,i.pixDims[2]=r.getFloat32(g+38,!1)*10,i.pixDims[3]=r.getFloat32(g+42,!1)*10,i.pixDims[4]=r.getUint32(g+46,!1)/1e3,l.push(i.pixDims[4]);const y=i.dims[1]*i.dims[2]*i.dims[3],v=new Float32Array(y);if(x===1)for(let w=0;w<y;w++)v[w]=r.getUint8(p)*A,p++;else if(x===6)for(let w=0;w<y;w++)v[w]=r.getUint16(p,!1)*A,p+=2;else if(x===7)for(let w=0;w<y;w++)v[w]=r.getUint32(p,!1)*A,p+=4;else F.warn("Unknown ECAT data type "+x);const b=c.slice(0);c=new Float32Array(b.length+v.length),c.set(b),c.set(v,b.length),o++}if(m===0)break;a+=512}if(i.dims[4]=o,i.pixDims[4]=l[0],o>1){i.dims[0]=4;let h=!1;for(let d=0;d<o;d++)l[d]!==l[0]&&(h=!0);h&&F.warn("Frame durations vary")}return i.sform_code=1,i.affine=[[-i.pixDims[1],0,0,(i.dims[1]-2)*.5*i.pixDims[1]],[0,-i.pixDims[2],0,(i.dims[2]-2)*.5*i.pixDims[2]],[0,0,-i.pixDims[3],(i.dims[3]-2)*.5*i.pixDims[3]],[0,0,0,1]],i.numBitsPerVoxel=32,i.datatypeCode=16,c.buffer}var ni={};be(ni,{imageDataFromArrayBuffer:()=>Dn,readBMP:()=>mh});async function Dn(t){return new Promise((e,i)=>{const r=new Blob([t]),s=URL.createObjectURL(r),n=new Image;n.crossOrigin="Anonymous",n.src=s,n.onload=()=>{URL.revokeObjectURL(s);const a=document.createElement("canvas");a.width=n.width,a.height=n.height;const o=a.getContext("2d");if(!o){i(new Error("Failed to get 2D context"));return}o.drawImage(n,0,0),e(o.getImageData(0,0,n.width,n.height))},n.onerror=a=>{URL.revokeObjectURL(s),i(a)}})}async function mh(t,e){const i=await Dn(e),{width:r,height:s,data:n}=i;t.hdr=new G;const a=t.hdr;a.dims=[3,r,s,1,0,0,0,0],a.pixDims=[1,1,1,1,1,0,0,0],a.affine=[[a.pixDims[1],0,0,-(a.dims[1]-2)*.5*a.pixDims[1]],[0,-a.pixDims[2],0,(a.dims[2]-2)*.5*a.pixDims[2]],[0,0,-a.pixDims[3],(a.dims[3]-2)*.5*a.pixDims[3]],[0,0,0,1]],a.numBitsPerVoxel=8,a.datatypeCode=2304;let o=!0;for(let l=0;l<n.length;l+=4)if(n[l]!==n[l+1]||n[l]!==n[l+2]){o=!1;break}if(o){a.datatypeCode=2;const l=new Uint8Array(r*s);for(let c=0,h=0;c<n.length;c+=4,h++)l[h]=n[c];return l.buffer}return n.buffer}var rr={};be(rr,{readMHA:()=>ph});async function ph(t,e,i){const r=e.byteLength;if(r<20)throw new Error("File too small to be VTK: bytes = "+e.byteLength);const s=new Uint8Array(e);let n=0;function a(p){return p===10||p===13}function o(){for(;n<r&&a(s[n]);)n++;const p=n;for(;n<r&&!a(s[n]);)n++;return n-p<2?"":new TextDecoder().decode(e.slice(p,n))}let l=o();t.hdr=new G;const c=t.hdr;c.pixDims=[1,1,1,1,1,0,0,0],c.dims=[1,1,1,1,1,1,1,1],c.littleEndian=!0;let h=!1,d=!1;const f=He(NaN,0,0,0,1,0,0,0,1),u=k(0,0,0);for(;l!=="";){let p=l.split(" ");if(p.length>2&&(p=p.slice(2)),l.startsWith("BinaryDataByteOrderMSB")&&p[0].includes("False")&&(c.littleEndian=!0),l.startsWith("BinaryDataByteOrderMSB")&&p[0].includes("True")&&(c.littleEndian=!1),l.startsWith("CompressedData")&&p[0].includes("True")&&(h=!0),l.startsWith("TransformMatrix"))for(let g=0;g<9;g++)f[g]=parseFloat(p[g]);if(l.startsWith("Offset"))for(let g=0;g<Math.min(p.length,3);g++)u[g]=parseFloat(p[g]);if(l.startsWith("ElementSpacing"))for(let g=0;g<p.length;g++)c.pixDims[g+1]=parseFloat(p[g]);if(l.startsWith("DimSize")){c.dims[0]=p.length;for(let g=0;g<p.length;g++)c.dims[g+1]=parseInt(p[g])}if(l.startsWith("ElementType"))switch(p[0]){case"MET_UCHAR":c.numBitsPerVoxel=8,c.datatypeCode=2;break;case"MET_CHAR":c.numBitsPerVoxel=8,c.datatypeCode=256;break;case"MET_SHORT":c.numBitsPerVoxel=16,c.datatypeCode=4;break;case"MET_USHORT":c.numBitsPerVoxel=16,c.datatypeCode=512;break;case"MET_INT":c.numBitsPerVoxel=32,c.datatypeCode=8;break;case"MET_UINT":c.numBitsPerVoxel=32,c.datatypeCode=768;break;case"MET_FLOAT":c.numBitsPerVoxel=32,c.datatypeCode=16;break;case"MET_DOUBLE":c.numBitsPerVoxel=64,c.datatypeCode=64;break;default:throw new Error("Unsupported MHA data type: "+p[0])}if(l.startsWith("ObjectType")&&!p[0].includes("Image")&&F.warn("Only able to read ObjectType = Image, not "+l),l.startsWith("ElementDataFile")){p[0]!=="LOCAL"&&(d=!0);break}l=o()}const m=He(c.pixDims[1],0,0,0,c.pixDims[2],0,0,0,c.pixDims[3]);for(Hs(f,f,m),c.affine=[[-f[0],-f[3],-f[6],-u[0]],[-f[1],-f[4],-f[7],-u[1]],[f[2],f[5],f[8],u[2]],[0,0,0,1]];s[n]===10;)n++;return c.vox_offset=n,d&&i?h?await H.decompressToBuffer(new Uint8Array(i.slice(0))):i.slice(0):h?await H.decompressToBuffer(new Uint8Array(e.slice(c.vox_offset))):e.slice(c.vox_offset)}var Tn={};be(Tn,{isFreeSurferLabelImage:()=>En,optimizeFreeSurferLabels:()=>Sn,readMgh:()=>gh});function ps(t,e,i,r=1){const s=e+i;let n=e;const a=[];for(;n+12<=s;){const o=t.getInt32(n,!1),l=t.getInt32(n+8,!1);if(n+=12,l<=0||n+l>s)break;if(o!==r){n+=l;continue}let c=l,h=n;if(r===1){if(n+4>s)break;c=t.getInt32(n,!1),h+=4}if(c>1&&h+c<=s){const d=new Uint8Array(t.buffer,h,c),f=new TextDecoder("utf-8").decode(d.slice(0,-1));a.push(f)}n+=l}return a.join(`
|
|
65
|
+
|
|
66
|
+
`)}function Sn(t,e){if(t.intent_code=1002,t.datatypeCode!==16&&t.datatypeCode!==8)return e;let i=new Float32Array(e);if(t.datatypeCode===8&&(i=new Int32Array(e)),er()){const a=new Uint32Array(e);for(let o=0;o<a.length;o++){const l=a[o];a[o]=(l&255)<<24|(l&65280)<<8|(l&16711680)>>>8|(l&4278190080)>>>24}}t.littleEndian=er();let r=!0,s=1/0,n=-1/0;for(let a=0;a<i.length;a++){const o=i[a];Number.isFinite(o)&&(Number.isInteger(o)||(r=!1),o<s&&(s=o),o>n&&(n=o))}if(!r||s<0||n>2147483647)return F.warn(`FreeSurfer Labels must be integers in INT32 range. range ${s}..${n}`),e;if(n>32767){t.datatypeCode=8;const a=new Int32Array(i.length);for(let o=0;o<i.length;o++)a[o]=Math.trunc(i[o]);return a.buffer}else if(n>255){t.datatypeCode=4,t.numBitsPerVoxel=16;const a=new Int16Array(i.length);for(let o=0;o<i.length;o++)a[o]=Math.trunc(i[o]);return a.buffer}else{t.datatypeCode=2,t.numBitsPerVoxel=8;const a=new Uint8Array(i.length);for(let o=0;o<i.length;o++)a[o]=Math.trunc(i[o]);return a.buffer}}function En(t,e,i){const r=t.byteLength-e.vox_offset;if(r<i)return F.error(`MGH image data size mismatch: expected ${i}, found ${r}`),!1;if(r===i)return!1;const s=e.vox_offset+i+20,n=t.byteLength-s;return n<=12?!1:ps(new DataView(t),s,n).toLowerCase().endsWith("lut.txt")?!0:ps(new DataView(t),s,n,3).includes("mri_label2vol")}async function gh(t,e,i=""){t.hdr||(F.debug("readMgh called before nvImage.hdr was initialized. Creating default."),t.hdr=new G);const r=t.hdr;r.littleEndian=!1;let s=e,n=new DataView(s);if(s.byteLength>=2&&n.getUint8(0)===31&&n.getUint8(1)===139)try{s=await H.decompressToBuffer(new Uint8Array(e)),n=new DataView(s)}catch(N){return F.error("Failed to decompress MGZ file.",N),null}if(s.byteLength<284)return F.error("File too small to be a valid MGH/MGZ header."),null;const a=n.getInt32(0,!1),o=n.getInt32(4,!1),l=n.getInt32(8,!1),c=n.getInt32(12,!1),h=n.getInt32(16,!1),d=n.getInt32(20,!1),f=n.getFloat32(30,!1),u=n.getFloat32(34,!1),m=n.getFloat32(38,!1),p=n.getFloat32(42,!1),g=n.getFloat32(46,!1),x=n.getFloat32(50,!1),A=n.getFloat32(54,!1),y=n.getFloat32(58,!1),v=n.getFloat32(62,!1),b=n.getFloat32(66,!1),w=n.getFloat32(70,!1),C=n.getFloat32(74,!1),M=n.getFloat32(78,!1),T=n.getFloat32(82,!1),E=n.getFloat32(86,!1);if(a!==1&&a!==257&&F.warn(`Unexpected MGH version: ${a}.`),o<=0||l<=0||c<=0)return F.error(`Invalid MGH dimensions: ${o}x${l}x${c}`),null;switch(d){case 0:r.numBitsPerVoxel=8,r.datatypeCode=2;break;case 4:r.numBitsPerVoxel=16,r.datatypeCode=4;break;case 1:r.numBitsPerVoxel=32,r.datatypeCode=8;break;case 3:r.numBitsPerVoxel=32,r.datatypeCode=16;break;default:return F.error(`Unsupported MGH data type: ${d}`),null}r.dims[1]=o,r.dims[2]=l,r.dims[3]=c,r.dims[4]=Math.max(1,h),r.dims[0]=r.dims[4]>1?4:3,r.pixDims[0]=1,r.pixDims[1]=Math.abs(f),r.pixDims[2]=Math.abs(u),r.pixDims[3]=Math.abs(m),r.pixDims[4]=0,r.sform_code=1,r.qform_code=0,r.sform_code=1;const I=Ee(p*r.pixDims[1],A*r.pixDims[2],b*r.pixDims[3],0,g*r.pixDims[1],y*r.pixDims[2],w*r.pixDims[3],0,x*r.pixDims[1],v*r.pixDims[2],C*r.pixDims[3],0,0,0,0,1),S=[r.dims[1]/2,r.dims[2]/2,r.dims[3]/2,1],U=[0,0,0,0];for(let N=0;N<3;N++){U[N]=0;for(let Y=0;Y<3;Y++)U[N]=U[N]+I[Y+N*4]*S[Y]}r.affine=[[I[0],I[1],I[2],M-U[0]],[I[4],I[5],I[6],T-U[1]],[I[8],I[9],I[10],E-U[2]],[0,0,0,1]],r.vox_offset=284,r.magic="n+1";const B=r.numBitsPerVoxel/8,R=o*l*c*r.dims[4]*B,P=s.slice(r.vox_offset,r.vox_offset+R);let L=a===257;return L||(L=["aparc.DKTatlas+aseg.deep.mg","aparc+aseg.mg","aparc.DKTatlas+aseg.mg","aparc.a2005s+aseg.mg","aparc.a2009s+aseg.mg","apas+head.mg","apas+head.samseg.mg","aseg.auto.mg","aseg.auto_noCCseg.mg","aseg.mg","aseg.presurf.hypos.mg","aseg.presurf.mg","brainstemSsLabels.v13.FSvoxelSpace.mg","brainstemSsLabels.v13.mg","ctrl_pts.mg","filled.auto.mg","filled.mg","gtmseg.mg","hypothalamic_subunits_seg.v1.mg","lh.hippoAmygLabels-T1.v22.CA.FSvoxelSpace.mg","lh.hippoAmygLabels-T1.v22.CA.mg","lh.hippoAmygLabels-T1.v22.FS60.FSvoxelSpace.mg","lh.hippoAmygLabels-T1.v22.FS60.mg","lh.hippoAmygLabels-T1.v22.FSvoxelSpace.mg","lh.hippoAmygLabels-T1.v22.HBT.FSvoxelSpace.mg","lh.hippoAmygLabels-T1.v22.HBT.mg","lh.hippoAmygLabels-T1.v22.mg","lh.ribbon.mg","mca-dura.mg","rh.hippoAmygLabels-T1.v22.CA.FSvoxelSpace.mg","rh.hippoAmygLabels-T1.v22.CA.mg","rh.hippoAmygLabels-T1.v22.FS60.FSvoxelSpace.mg","rh.hippoAmygLabels-T1.v22.FS60.mg","rh.hippoAmygLabels-T1.v22.FSvoxelSpace.mg","rh.hippoAmygLabels-T1.v22.HBT.FSvoxelSpace.mg","rh.hippoAmygLabels-T1.v22.HBT.mg","rh.hippoAmygLabels-T1.v22.mg","rh.ribbon.mg","ribbon.mg","synthseg.mg","synthseg.rca.mg","vsinus.mg","subcort.mask.1mm.mg","subcort.mask.mg","surface.defects.mg","ThalamicNuclei.v13.T1.FSvoxelSpace.mg","ThalamicNuclei.v13.T1.mg","wm.asegedit.mg","wmparc.mg"].some(Y=>i.includes(Y))),L||(L=En(s,r,R)),L?Sn(r,P):P}var sr={};be(sr,{readMIF:()=>Ah});async function Ah(t,e,i){t.hdr=new G;const r=t.hdr;r.pixDims=[1,1,1,1,1,0,0,0],r.dims=[1,1,1,1,1,1,1,1];let s=e.byteLength;if(s<20)throw new Error("File too small to be MIF: bytes = "+s);let n=new Uint8Array(e);n[0]===31&&n[1]===139&&(F.debug("MIF with GZ decompression"),e=await H.decompressToBuffer(new Uint8Array(e)),s=e.byteLength,n=new Uint8Array(e));let a=0;function o(){for(;a<s&&n[a]===10;)a++;const S=a;for(;a<s&&n[a]!==10;)a++;return a++,a-S<1?"":new TextDecoder().decode(e.slice(S,a-1))}let l=o();if(!l.startsWith("mrtrix image"))throw new Error("Not a valid MIF file");const c=[];let h=!1,d=0,f=0,u=!1;for(l=o();a<s&&!l.startsWith("END");){let S=l.split(":");if(l=o(),S.length<2)break;const U=S[0];S=S[1].split(",");for(let B=0;B<S.length;B++)S[B]=S[B].trim();switch(U){case"dim":r.dims[0]=S.length;for(let B=0;B<S.length;B++)r.dims[B+1]=parseInt(S[B]);break;case"vox":for(let B=0;B<S.length;B++)r.pixDims[B+1]=parseFloat(S[B]),isNaN(r.pixDims[B+1])&&(r.pixDims[B+1]=0);break;case"layout":for(let B=0;B<S.length;B++)c.push(parseInt(S[B]));break;case"datatype":{const B=S[0];B.startsWith("Bit")?(h=!0,r.datatypeCode=2):B.startsWith("Int8")?r.datatypeCode=256:B.startsWith("UInt8")?r.datatypeCode=2:B.startsWith("Int16")?r.datatypeCode=4:B.startsWith("UInt16")?r.datatypeCode=512:B.startsWith("Int32")?r.datatypeCode=8:B.startsWith("UInt32")?r.datatypeCode=768:B.startsWith("Float32")?r.datatypeCode=16:B.startsWith("Float64")?r.datatypeCode=64:F.warn("Unsupported datatype "+B),B.includes("8")?r.numBitsPerVoxel=8:B.includes("16")?r.numBitsPerVoxel=16:B.includes("32")?r.numBitsPerVoxel=32:B.includes("64")&&(r.numBitsPerVoxel=64),r.littleEndian=!0,B.endsWith("LE")&&(r.littleEndian=!0),B.endsWith("BE")&&(r.littleEndian=!1)}break;case"transform":if(d>2||S.length!==4)break;r.affine[d][0]=parseFloat(S[0]),r.affine[d][1]=parseFloat(S[1]),r.affine[d][2]=parseFloat(S[2]),r.affine[d][3]=parseFloat(S[3]),d++;break;case"comments":r.description=S[0].substring(0,Math.min(79,S[0].length));break;case"RepetitionTime":f=parseFloat(S[0]);break;case"file":u=!S[0].startsWith(". "),u||(S=S[0].split(" "),r.vox_offset=parseInt(S[1]));break}}const m=r.dims[0];m>5&&F.warn("reader only designed for a maximum of 5 dimensions (XYZTD)");let p=1;for(let S=0;S<m;S++)p*=Math.max(r.dims[S+1],1);for(let S=0;S<3;S++)for(let U=0;U<3;U++)r.affine[S][U]*=r.pixDims[U+1];F.debug("mif affine:"+r.affine[0]),f>0&&(r.pixDims[4]=f),u&&!i&&F.warn("MIH header provided without paired image data");let g;if(i&&u)g=i.slice(0);else if(h){r.numBitsPerVoxel=8;const S=new Uint8Array(p),U=e.slice(r.vox_offset,r.vox_offset+Math.ceil(p/8)),B=new Uint8Array(U);let V=0;for(let R=0;R<p;R++){const P=R%8;S[R]=B[V]>>7-P&1,P===7&&V++}g=S.buffer}else g=e.slice(r.vox_offset,r.vox_offset+p*(r.numBitsPerVoxel/8));c.length!==r.dims[0]&&F.warn("dims does not match layout");let x=1;const A=[1,1,1,1,1],y=[!1,!1,!1,!1,!1];for(let S=0;S<c.length;S++)for(let U=0;U<c.length;U++)Math.abs(c[U])===S&&(A[U]=x,(c[U]<0||Object.is(c[U],-0))&&(y[U]=!0),x*=r.dims[U+1]);let v=H.range(0,r.dims[1]-1,1);y[0]&&(v=H.range(r.dims[1]-1,0,-1));for(let S=0;S<r.dims[1];S++)v[S]*=A[0];let b=H.range(0,r.dims[2]-1,1);y[1]&&(b=H.range(r.dims[2]-1,0,-1));for(let S=0;S<r.dims[2];S++)b[S]*=A[1];let w=H.range(0,r.dims[3]-1,1);y[2]&&(w=H.range(r.dims[3]-1,0,-1));for(let S=0;S<r.dims[3];S++)w[S]*=A[2];let C=H.range(0,r.dims[4]-1,1);y[3]&&(C=H.range(r.dims[4]-1,0,-1));for(let S=0;S<r.dims[4];S++)C[S]*=A[3];let M=H.range(0,r.dims[5]-1,1);y[4]&&(M=H.range(r.dims[5]-1,0,-1));for(let S=0;S<r.dims[5];S++)M[S]*=A[4];let T=0,E,I;switch(r.datatypeCode){case 256:E=new Int8Array(g),I=new Int8Array(p);break;case 2:E=new Uint8Array(g),I=new Uint8Array(p);break;case 4:E=new Int16Array(g),I=new Int16Array(p);break;case 512:E=new Uint16Array(g),I=new Uint16Array(p);break;case 8:E=new Int32Array(g),I=new Int32Array(p);break;case 768:E=new Uint32Array(g),I=new Uint32Array(p);break;case 16:E=new Float32Array(g),I=new Float32Array(p);break;case 64:E=new Float64Array(g),I=new Float64Array(p);break;default:throw new Error("unknown datatypeCode")}for(let S=0;S<r.dims[5];S++)for(let U=0;U<r.dims[4];U++)for(let B=0;B<r.dims[3];B++)for(let V=0;V<r.dims[2];V++)for(let R=0;R<r.dims[1];R++)I[T]=E[v[R]+b[V]+w[B]+C[U]+M[S]],T++;return I.buffer}var In={};be(In,{readNifti:()=>xh});async function xh(t,e,i){let r=e,s=null;try{if(pr(r)&&(F.debug(`Decompressing NIfTI file: ${t.name}`),r=await lo(r),F.debug(`Decompression complete for: ${t.name}`)),!r||r.byteLength===0)throw new Error("Buffer became invalid after decompression attempt.");if(t.hdr=await Nt(r,i!=null),ho(t.hdr)&&(t.extensions=t.hdr.extensions),t.hdr===null)throw new Error(`Failed to read NIfTI header: ${t.name}`);if(t.hdr.cal_min===0&&t.hdr.cal_max===255&&t.hdr.datatypeCode!==2&&(F.debug(`Resetting suspicious cal_min/max (0/255) for non-uint8 NIfTI: ${t.name}`),t.hdr.cal_min=0,t.hdr.cal_max=0),s=i?Jr(t.hdr,i):Jr(t.hdr,r),s===null)throw new Error(`nifti-reader-js readImage returned null for ${t.name}`);return s}catch(n){return F.error(`Error processing NIfTI file ${t.name}:`,n),t.hdr=null,null}}var Fn={};be(Fn,{readNrrd:()=>vh});async function vh(t,e,i=null){t.hdr||(F.warn("readNrrd called before nvImage.hdr was initialized. Creating default."),t.hdr=new G);const r=t.hdr;r.pixDims=[1,1,1,1,1,0,0,0],r.dims=[0,0,0,0,0,0,0,0];const s=e.byteLength;let n=null;const a=new Uint8Array(e);for(let w=1;w<s;w++)if(a[w-1]===10&&a[w]===10){const C=e.slice(0,w-1);n=new TextDecoder().decode(C),r.vox_offset=w+1;break}if(n===null)return F.error("readNrrd: could not extract txt"),null;const o=n.split(`
|
|
67
|
+
`);if(!o[0].startsWith("NRRD"))return F.error("Invalid NRRD image (magic signature missing)"),null;const l=o.length;let c=!1,h=!1,d=!1;const f=He(NaN,0,0,0,1,0,0,0,1),u=k(0,0,0);let m=qi();for(let w=1;w<l;w++){let C=o[w];if((C.length===0||C[0]==="#")&&(C.startsWith("#")||C.trim().length===0))continue;C=C.toLowerCase();const M=C.split(":");if(M.length<2)continue;const T=M[0].trim();let E=M[1].trim();switch(E=E.replaceAll(")"," "),E=E.replaceAll("("," "),E=E.trim(),T){case"data file":d=!0;break;case"encoding":if(E.includes("raw"))c=!1;else if(E.includes("gz"))c=!0;else return F.error(`Unsupported NRRD encoding : ${E}`),null;break;case"type":switch(E){case"uchar":case"unsigned char":case"uint8":case"uint8_t":r.numBitsPerVoxel=8,r.datatypeCode=2;break;case"signed char":case"int8":case"int8_t":r.numBitsPerVoxel=8,r.datatypeCode=256;break;case"short":case"short int":case"signed short":case"signed short int":case"int16":case"int16_t":r.numBitsPerVoxel=16,r.datatypeCode=4;break;case"ushort":case"unsigned short":case"unsigned short int":case"uint16":case"uint16_t":r.numBitsPerVoxel=16,r.datatypeCode=512;break;case"int":case"signed int":case"int32":case"int32_t":r.numBitsPerVoxel=32,r.datatypeCode=8;break;case"uint":case"unsigned int":case"uint32":case"uint32_t":r.numBitsPerVoxel=32,r.datatypeCode=768;break;case"float":r.numBitsPerVoxel=32,r.datatypeCode=16;break;case"double":r.numBitsPerVoxel=64,r.datatypeCode=64;break;default:return F.error("Unsupported NRRD data type: "+E),null}break;case"spacings":{const I=E.split(/[ ,]+/);for(let S=0;S<I.length;S++)r.pixDims[S+1]=parseFloat(I[S])}break;case"sizes":{const I=E.split(/[ ,]+/);r.dims[0]=I.length;for(let S=0;S<I.length;S++)r.dims[S+1]=parseInt(I[S])}break;case"endian":E.includes("little")?r.littleEndian=!0:E.includes("big")&&(r.littleEndian=!1);break;case"space directions":{const I=E.split(/[ ,]+/);if(I.length===9)for(let S=0;S<9;S++)f[S]=parseFloat(I[S])}break;case"space origin":{const I=E.split(/[ ,]+/);I.length===3&&(u[0]=parseFloat(I[0]),u[1]=parseFloat(I[1]),u[2]=parseFloat(I[2]))}break;case"space units":E.includes("microns")&&(h=!0);break;case"space":E.includes("right-anterior-superior")||E.includes("ras")?m=He(1,0,0,0,1,0,0,0,1):E.includes("left-anterior-superior")||E.includes("las")?m=He(-1,0,0,0,1,0,0,0,1):E.includes("left-posterior-superior")||E.includes("lps")?m=He(-1,0,0,0,-1,0,0,0,1):F.warn("Unsupported NRRD space value:",E);break;default:F.warn("Unknown:",T);break}}if(!isNaN(f[0])){r.sform_code=2,h&&(Ta(f,f,.001),u[0]*=.001,u[1]*=.001,u[2]*=.001),m[0]<0&&(u[0]=-u[0]),m[4]<0&&(u[1]=-u[1]),m[8]<0&&(u[2]=-u[2]),Hs(f,m,f);const w=Ee(f[0],f[3],f[6],u[0],f[1],f[4],f[7],u[1],f[2],f[5],f[8],u[2],0,0,0,1);if(!t.vox2mm)return null;const C=t.vox2mm([0,0,0],w),M=t.vox2mm([1,0,0],w);ne(M,M,C);const T=t.vox2mm([0,1,0],w);ne(T,T,C);const E=t.vox2mm([0,0,1],w);ne(E,E,C),r.pixDims[0]=1,r.pixDims[1]=Qe(M),r.pixDims[2]=Qe(T),r.pixDims[3]=Qe(E),r.affine=[[w[0],w[1],w[2],w[3]],[w[4],w[5],w[6],w[7]],[w[8],w[9],w[10],w[11]],[0,0,0,1]]}let p=null;const g=d?i:e,x=d?0:r.vox_offset;if(d&&!g)return F.warn("Missing data: NRRD header describes detached data file but only one URL provided"),null;if(!g||x>=g.byteLength)return F.error(`NRRD data offset (${x}) invalid for buffer length (${g?.byteLength??0})`),null;let A=g.slice(x);if(c)try{F.debug("Decompressing NRRD data..."),A=await H.decompressToBuffer(new Uint8Array(A)),F.debug("Decompression complete.")}catch(w){return F.error("Failed to decompress NRRD data.",w),null}const y=r.numBitsPerVoxel/8,b=r.dims.slice(1,r.dims[0]+1).reduce((w,C)=>w*Math.max(1,C),1)*y;return A.byteLength<b?(F.error(`NRRD image data size mismatch: expected ${b}, found ${A.byteLength}`),null):(A.byteLength>b&&(F.warn(`NRRD has extra ${A.byteLength-b} bytes after expected image data. Truncating.`),A=A.slice(0,b)),p=A,r.datatypeCode?r.numBitsPerVoxel?p:(F.error("NRRD parsing failed to set numBitsPerVoxel."),null):(F.error("NRRD parsing failed to set datatypeCode."),null))}var Dt={};be(Dt,{readNPY:()=>Bn,readNPZ:()=>bh});function wh(t){if(t.length<2)throw new Error(`Invalid NPY dtype: ${t}`);const e=t.slice(1),r={b1:1,i1:1,u1:1,i2:2,u2:2,i4:4,u4:4,f4:4,f8:8}[e];if(r===void 0)throw new Error(`Unsupported NPY dtype: ${t}`);return r}function yh(t){if(t.length<2)throw new Error(`Invalid NPY dtype: ${t}`);const e=t.slice(1),r={b1:2,i1:256,u1:2,i2:4,u2:512,i4:8,u4:768,f4:16,f8:64}[e];if(r===void 0)throw new Error(`Unsupported NPY dtype: ${t}`);return r}async function Bn(t,e){const i=new DataView(e),r=[i.getUint8(0),i.getUint8(1),i.getUint8(2),i.getUint8(3),i.getUint8(4),i.getUint8(5)],s=[147,78,85,77,80,89];if(!r.every((U,B)=>U===s[B]))throw new Error("Not a valid NPY file: Magic number mismatch");const n=i.getUint8(6),a=i.getUint8(7);let o,l,c;if(n===1)o=i.getUint16(8,!0),l=10,c="latin1";else if(n===2||n===3)o=i.getUint32(8,!0),l=12,c=n===3?"utf-8":"latin1";else throw new Error(`Unsupported NPY version: ${n}.${a}`);const h=l+o;if(h>e.byteLength)throw new Error("Invalid NPY file: Header length exceeds buffer size");const d=new TextDecoder(c).decode(e.slice(l,h)),f=d.match(/'shape': \((.*?)\)/);if(!f)throw new Error("Invalid NPY header: Shape not found");const u=f[1].split(",").map(U=>U.trim()).filter(U=>U!=="").map(Number);if(u.length===0||u.some(U=>!Number.isInteger(U)||U<=0))throw new Error(`Invalid NPY header: invalid shape (${f[1]})`);if(u.length<2||u.length>4)throw new Error(`Unsupported NPY shape: expected 2D, 3D, or 4D array, got (${u.join(", ")})`);const m=d.match(/'descr': '([^']+)'/);if(!m)throw new Error("Invalid NPY header: Data type not found");const p=m[1],g=p[0],x=new Uint8Array(new Uint16Array([1]).buffer)[0]===1;if(!["<",">","|","="].includes(g))throw new Error(`Invalid NPY dtype endian prefix: ${p}`);const A=u.reduce((U,B)=>U*B,1),y=wh(p),v=A*y;if(e.byteLength-h<v)throw new Error("Invalid .npy file: not enough data bytes for specified shape and data type");const w=e.slice(h,h+v),C=u.length,M=u[u.length-1],T=u[u.length-2],E=u.length>=3?u[u.length-3]:1,I=u.length===4?u[0]:1;t.hdr=new G;const S=t.hdr;return S.dims=[C,M,T,E,I,1,1,1],S.pixDims=[1,1,1,1,1,1,1,1],S.affine=[[S.pixDims[1],0,0,-(S.dims[1]-2)*.5*S.pixDims[1]],[0,-S.pixDims[2],0,(S.dims[2]-2)*.5*S.pixDims[2]],[0,0,-S.pixDims[3],(S.dims[3]-2)*.5*S.pixDims[3]],[0,0,0,1]],S.numBitsPerVoxel=y*8,S.datatypeCode=yh(p),S.littleEndian=g==="<"||g==="|"||g==="="&&x,w}async function bh(t,e){const i=new An(e);for(let r=0;r<i.entries.length;r++){const s=i.entries[r];if(s.fileName.toLowerCase().endsWith(".npy")){const n=await s.extract(),a=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await Bn(t,a)}}}var nr={};be(nr,{readZARR:()=>Mh});function Ch(t,e,i,r){const s=e*i,n=new Uint8Array(s*r*3),a=new Array(r);for(let c=0;c<r;c++)a[c]=s*3*c;let o=0,l=0;for(let c=0;c<s;c++){for(let h=0;h<r;h++)n[a[h]+l]=t[o++],n[a[h]+l+1]=t[o++],n[a[h]+l+2]=t[o++];l+=3}return n}async function Mh(t,e,i){let{width:r,height:s,depth:n=1,data:a}=i??{},o=r*s*n*3,l=o===a.length;if(l||(o=r*s*n,n===3&&(l=!0,n=1)),o!==a.length)throw new Error(`Expected RGB ${r}×${s}×${n}×3 = ${o}, but ZARR length ${a.length}`);t.hdr=new G;const c=t.hdr;if(c.dims=[3,r,s,n,1,1,1,1],c.pixDims=[1,1,1,1,0,0,0,0],c.affine=[[c.pixDims[1],0,0,-(c.dims[1]-2)*.5*c.pixDims[1]],[0,-c.pixDims[2],0,(c.dims[2]-2)*.5*c.pixDims[2]],[0,0,-c.pixDims[3],(c.dims[3]-2)*.5*c.pixDims[3]],[0,0,0,1]],!l){if(c.numBitsPerVoxel=8,c.datatypeCode=2,a instanceof Uint8Array){const u=new ArrayBuffer(a.length);return new Uint8Array(u).set(a),u}return a}c.numBitsPerVoxel=24,c.datatypeCode=128;const h=Ch(a,c.dims[1],c.dims[2],c.dims[3]),d=new ArrayBuffer(h.length);return new Uint8Array(d).set(h),d}function Ge(t,e,i){const r=de(i);Te(r,r);const s=ae(e[0],e[1],e[2],1);return ve(s,s,r),k(s[0],s[1],s[2])}function Un(t,e,i=!1){if(!t.matRAS)throw new Error("matRAS undefined");const r=de(t.matRAS),s=de(r);Te(s,r),Se(s,s);const n=ae(e[0],e[1],e[2],1);ve(n,n,s);const a=k(n[0],n[1],n[2]);return i?a:new Float32Array([Math.round(a[0]),Math.round(a[1]),Math.round(a[2])])}function Dh(t,e){return k((e[0]+.5)/t.dimsRAS[1],(e[1]+.5)/t.dimsRAS[2],(e[2]+.5)/t.dimsRAS[3])}function Th(t,e){return k(Math.round(e[0]*t.dims[1]-.5),Math.round(e[1]*t.dims[2]-.5),Math.round(e[2]*t.dims[3]-.5))}function Sh(t,e,i=!1){const r=ae(e[0],e[1],e[2],1);return i?ve(r,r,t.frac2mm):ve(r,r,t.frac2mmOrtho),r}function Eh(t,e,i=!1){const r=ae(e[0],e[1],e[2],1),s=t.dimsRAS,n=k(0,0,0);if(typeof s>"u")return n;if(!i){const o=de(t.frac2mmOrtho);return Se(o,o),ve(r,r,o),n[0]=r[0],n[1]=r[1],n[2]=r[2],n}if(s[1]<1||s[2]<1||s[3]<1)return n;const a=de(t.matRAS);return Se(a,a),Te(a,a),ve(r,r,a),n[0]=(r[0]+.5)/s[1],n[1]=(r[1]+.5)/s[2],n[2]=(r[2]+.5)/s[3],n}function ar(t,e){return Array.isArray(t)&&Array.isArray(e)&&t.length===e.length&&t.every((i,r)=>i===e[r])}function Rn(t){const e=de(t);Te(e,t);const i=Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2]),r=Math.max(Math.max(Math.abs(e[0]),Math.abs(e[1])),Math.abs(e[2]))/i,s=Math.sqrt(e[4]*e[4]+e[5]*e[5]+e[6]*e[6]),n=Math.max(Math.max(Math.abs(e[4]),Math.abs(e[5])),Math.abs(e[6]))/s,a=Math.sqrt(e[8]*e[8]+e[9]*e[9]+e[10]*e[10]),o=Math.max(Math.max(Math.abs(e[8]),Math.abs(e[9])),Math.abs(e[10]))/a,l=Math.min(Math.min(r,n),o);let c=Math.abs(Math.acos(l)*180/3.141592653);return c>.01?F.warn("Warning voxels not aligned with world space: "+c+` degrees from plumb.
|
|
68
|
+
`):c=0,c}function or(t){if(!t.matRAS)throw new Error("matRAS not defined");if(t.pixDimsRAS===void 0)throw new Error("pixDimsRAS not defined");if(!t.dimsRAS)throw new Error("dimsRAS not defined");t.oblique_angle=Rn(t.matRAS);const e=Ge(t,[0,0,0],t.matRAS),i=Ge(t,[1/t.pixDimsRAS[1],0,0],t.matRAS),r=Ge(t,[0,1/t.pixDimsRAS[2],0],t.matRAS),s=Ge(t,[0,0,1/t.pixDimsRAS[3]],t.matRAS);ne(i,i,e),ne(r,r,e),ne(s,s,e);const n=Ee(i[0],i[1],i[2],0,r[0],r[1],r[2],0,s[0],s[1],s[2],0,0,0,0,1);t.obliqueRAS=de(n);const a=Math.abs(90-Di(i,r)*(180/Math.PI)),o=Math.abs(90-Di(i,s)*(180/Math.PI)),l=Math.abs(90-Di(r,s)*(180/Math.PI));t.maxShearDeg=Math.max(Math.max(a,o),l),t.maxShearDeg>.1&&F.warn("Warning: voxels are rhomboidal, maximum shear is %f degrees.",t.maxShearDeg);const c=ae(t.dimsRAS[1],t.dimsRAS[2],t.dimsRAS[3],1),h=de(t.matRAS);Te(h,h);const d=ae(-.5,-.5,-.5,0);tt(h,h,k(d[0],d[1],d[2])),h[0]*=c[0],h[1]*=c[0],h[2]*=c[0],h[4]*=c[1],h[5]*=c[1],h[6]*=c[1],h[8]*=c[2],h[9]*=c[2],h[10]*=c[2],t.frac2mm=de(h);const f=t.pixDimsRAS[1],u=t.pixDimsRAS[2],m=t.pixDimsRAS[3],p=de(h);p[0]=f*c[0],p[1]=0,p[2]=0,p[4]=0,p[5]=u*c[1],p[6]=0,p[8]=0,p[9]=0,p[10]=m*c[2];const g=Un(t,[0,0,0],!0);p[12]=(-g[0]-.5)*f,p[13]=(-g[1]-.5)*u,p[14]=(-g[2]-.5)*m,t.frac2mmOrtho=de(p),t.extentsMinOrtho=[p[12],p[13],p[14]],t.extentsMaxOrtho=[p[0]+p[12],p[5]+p[13],p[10]+p[14]],t.mm2ortho=J(),Se(t.mm2ortho,n)}function Ih(t){if(!t.hdr)throw new Error("hdr not set");const e=t.hdr.affine,i=t.hdr,r=He(Math.abs(e[0][0]),Math.abs(e[0][1]),Math.abs(e[0][2]),Math.abs(e[1][0]),Math.abs(e[1][1]),Math.abs(e[1][2]),Math.abs(e[2][0]),Math.abs(e[2][1]),Math.abs(e[2][2])),s=[1,1,1];r[3]>r[0]&&(s[0]=2),r[6]>r[0]&&r[6]>r[3]&&(s[0]=3),s[1]=1,s[0]===1?r[4]>r[7]?s[1]=2:s[1]=3:s[0]===2?r[1]>r[7]?s[1]=1:s[1]=3:r[1]>r[4]?s[1]=1:s[1]=2,s[2]=6-s[1]-s[0];let n=[1,2,3];n[s[0]-1]=1,n[s[1]-1]=2,n[s[2]-1]=3;let a=Ee(e[0][0],e[0][1],e[0][2],e[0][3],e[1][0],e[1][1],e[1][2],e[1][3],e[2][0],e[2][1],e[2][2],e[2][3],0,0,0,1);t.mm000=Ge(t,[-.5,-.5,-.5],a),t.mm100=Ge(t,[i.dims[1]-.5,-.5,-.5],a),t.mm010=Ge(t,[-.5,i.dims[2]-.5,-.5],a),t.mm001=Ge(t,[-.5,-.5,i.dims[3]-.5],a);const o=J();ba(o,a);for(let g=0;g<3;g++)for(let x=0;x<3;x++)o[g*4+x]=a[g*4+n[x]-1];const l=[0,0,0];o[0]<0&&(l[0]=1),o[5]<0&&(l[1]=1),o[10]<0&&(l[2]=1),t.dimsRAS=[i.dims[0],i.dims[n[0]],i.dims[n[1]],i.dims[n[2]]],t.pixDimsRAS=[i.pixDims[0],i.pixDims[n[0]],i.pixDims[n[1]],i.pixDims[n[2]]],t.permRAS=n.slice();for(let g=0;g<3;g++)l[g]===1&&(t.permRAS[g]=-t.permRAS[g]);if(ar(n,[1,2,3])&&ar(l,[0,0,0])){t.toRAS=J(),t.matRAS=de(a),or(t),t.img2RASstep=[1,t.dimsRAS[1],t.dimsRAS[1]*t.dimsRAS[2]],t.img2RASstart=[0,0,0];return}qs(a),a[0]=1-l[0]*2,a[5]=1-l[1]*2,a[10]=1-l[2]*2,a[3]=(i.dims[n[0]]-1)*l[0],a[7]=(i.dims[n[1]]-1)*l[1],a[11]=(i.dims[n[2]]-1)*l[2];const c=J();Se(c,a),Ye(c,c,o),t.matRAS=de(c),a=Ee(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1),a[n[0]-1+0]=-l[0]*2+1,a[n[1]-1+4]=-l[1]*2+1,a[n[2]-1+8]=-l[2]*2+1,a[3]=l[0],a[7]=l[1],a[11]=l[2],t.toRAS=de(a),a[3]=0,a[7]=0,a[11]=0,a[12]=0,(t.permRAS[0]===-1||t.permRAS[1]===-1||t.permRAS[2]===-1)&&(a[12]=i.dims[1]-1),a[13]=0,(t.permRAS[0]===-2||t.permRAS[1]===-2||t.permRAS[2]===-2)&&(a[13]=i.dims[2]-1),a[14]=0,(t.permRAS[0]===-3||t.permRAS[1]===-3||t.permRAS[2]===-3)&&(a[14]=i.dims[3]-1),t.toRASvox=de(a),F.debug(t.hdr.dims),F.debug(t.dimsRAS);const h=t.hdr;n=t.permRAS;const d=[Math.abs(n[0]),Math.abs(n[1]),Math.abs(n[2])],f=[h.dims[d[0]],h.dims[d[1]],h.dims[d[2]]],u=[1,h.dims[1],h.dims[1]*h.dims[2]],m=[u[d[0]-1],u[d[1]-1],u[d[2]-1]],p=[0,0,0];for(let g=0;g<3;g++)n[g]<0&&(p[g]=m[g]*(f[g]-1),m[g]=-m[g]);t.img2RASstep=m,t.img2RASstart=p,or(t)}async function Fh(t,e=1){if(!t.permRAS)throw new Error("permRAS undefined");if(!t.hdr)throw new Error("hdr undefined");const i=ui({...t.hdr,vox_offset:352},!1),r=await Nt(i.buffer,!0);e===1?(r.dims[0]=3,r.dims[4]=1):e>1&&(r.dims[0]=4,r.dims[4]=e);const s=t.permRAS.slice();if(s[0]===1&&s[1]===2&&s[2]===3)return r;r.qform_code=0;for(let a=1;a<4;a++)r.dims[a]=t.dimsRAS[a];for(let a=0;a<t.pixDimsRAS.length;a++)r.pixDims[a]=t.pixDimsRAS[a];let n=0;for(let a=0;a<4;a++)for(let o=0;o<4;o++)r.affine[a][o]=t.matRAS[n],n++;return r}function Bh(t,e=0){if(!t.permRAS)throw new Error("permRAS undefined");if(!t.img)throw new Error("img undefined");if(!t.hdr)throw new Error("hdr undefined");const i=t.permRAS.slice();if(i[0]===1&&i[1]===2&&i[2]===3)return t.img;const r=t.hdr,s=r.dims[1]*r.dims[2]*r.dims[3];let n=e*s;(n+s>t.img.length||n<0)&&(n=0,F.warn(`img2RAS nVolume (${e}) out of bounds (${e}+1)×${s} > ${t.img.length}`));const a=t.img.slice(0,s),o=[Math.abs(i[0]),Math.abs(i[1]),Math.abs(i[2])],l=[r.dims[o[0]],r.dims[o[1]],r.dims[o[2]]],c=[1,r.dims[1],r.dims[1]*r.dims[2]],h=[c[o[0]-1],c[o[1]-1],c[o[2]-1]],d=[0,0,0];for(let u=0;u<3;u++)i[u]<0&&(d[u]=h[u]*(l[u]-1),h[u]=-h[u]);let f=0;for(let u=0;u<l[2];u++){const m=d[2]+u*h[2];for(let p=0;p<l[1];p++){const g=d[1]+p*h[1];for(let x=0;x<l[0];x++){const A=d[0]+x*h[0];a[f]=t.img[A+g+m+n],f++}}}return a}function Vn(t,e){e.length!==t.nVox3D*3&&F.warn("float32V1asRGBA() expects "+t.nVox3D*3+"voxels, got ",+e.length);const i=e.slice();t.hdr.datatypeCode=2304,t.nFrame4D=1;for(let l=4;l<7;l++)t.hdr.dims[l]=1;t.hdr.dims[0]=3;const r=new Uint8Array(t.nVox3D*4);let s=1;for(let l=0;l<t.nVox3D*3;l++)isNaN(i[l])||(s=Math.max(s,Math.abs(i[l])));const n=255/s,a=t.nVox3D*2;let o=0;for(let l=0;l<t.nVox3D;l++){const c=i[l],h=i[l+t.nVox3D],d=i[l+a];r[o]=Math.abs(c*n),r[o+1]=Math.abs(h*n),r[o+2]=Math.abs(d*n);const f=+(c>0)*1,u=+(h>0)*2,m=+(d>0)*4;let p=248+f+u+m;Math.abs(c)+Math.abs(h)+Math.abs(d)<.1&&(p=0),r[o+3]=p,o+=4}return r}function Uh(t,e=!1,i=!1,r=!1){let s=t.v1;if(!s&&t.nFrame4D===3&&t.img.constructor===Float32Array&&(s=t.img.slice()),!s)return F.warn("Image does not have V1 data"),!1;if(e)for(let n=0;n<t.nVox3D;n++)s[n]=-s[n];if(i)for(let n=t.nVox3D;n<2*t.nVox3D;n++)s[n]=-s[n];if(r)for(let n=2*t.nVox3D;n<3*t.nVox3D;n++)s[n]=-s[n];return t.img=Vn(t,s),!0}function Tt(t,e){if(!t.hdr)throw new Error("hdr undefined");return t.hdr.scl_slope===0&&(t.hdr.scl_slope=1),e*t.hdr.scl_slope+t.hdr.scl_inter}function Rh(t,e){if(!t.hdr)throw new Error("hdr undefined");return t.hdr.scl_slope===0&&(t.hdr.scl_slope=1),(e-t.hdr.scl_inter)/t.hdr.scl_slope}function Fr(t,e=Number.POSITIVE_INFINITY,i=!0){if(!t.hdr)throw new Error("hdr undefined");if(!t.img)throw new Error("img undefined");let r=Number.POSITIVE_INFINITY,s=Number.NEGATIVE_INFINITY,n=0,a=0,o=t.hdr.dims[1]*t.hdr.dims[2]*t.hdr.dims[3];const l=Math.floor(t.img.length/o);e>=l&&(e=t.frame4D),e=Math.min(e,l-1);const c=e*o;let h=[];if(i){const U=[Math.floor(.25*t.hdr.dims[1]),Math.floor(.25*t.hdr.dims[2]),Math.floor(.25*t.hdr.dims[3])],B=[t.hdr.dims[1]-2*U[0],t.hdr.dims[2]-2*U[1],t.hdr.dims[3]-2*U[2]],V=[B[0]+U[0],B[1]+U[1],B[2]+U[2]];o=B[0]*B[1]*B[2],h=new t.img.constructor(o);let R=-1,P=0;for(let L=0;L<t.hdr.dims[3];L++)for(let N=0;N<t.hdr.dims[2];N++)for(let Y=0;Y<t.hdr.dims[1];Y++)R++,!(Y<U[0]||N<U[1]||L<U[2])&&(Y>=V[0]||N>=V[1]||L>=V[2]||(h[P]=t.img[R+c],P++))}else{h=new t.img.constructor(o);for(let S=0;S<o;S++)h[S]=t.img[S+c]}const d=h.constructor!==Float64Array&&h.constructor!==Float32Array&&t.ignoreZeroVoxels;if(d)for(let S=0;S<o;S++)r=Math.min(h[S],r),s=Math.max(h[S],s),h[S]===0&&n++;else for(let S=0;S<o;S++){if(isNaN(h[S])){a++;continue}h[S]===0&&(n++,t.ignoreZeroVoxels)||(r=Math.min(h[S],r),s=Math.max(h[S],s))}t.ignoreZeroVoxels&&r===s&&n>0&&(r=0);const f=Tt(t,r),u=Tt(t,s),m=re.colormapFromKey(t._colormap);let p=0,g=0;if(m.min!==void 0&&(p=m.min),m.max!==void 0&&(g=m.max),p===g&&t.trustCalMinMax&&isFinite(t.hdr.cal_min)&&isFinite(t.hdr.cal_max)&&t.hdr.cal_max>t.hdr.cal_min)return t.cal_min=t.hdr.cal_min,t.cal_max=t.hdr.cal_max,t.robust_min=t.cal_min,t.robust_max=t.cal_max,t.global_min=f,t.global_max=u,[t.hdr.cal_min,t.hdr.cal_max,t.hdr.cal_min,t.hdr.cal_max];if(p!==g)return t.cal_min=p,t.cal_max=g,t.robust_min=t.cal_min,t.robust_max=t.cal_max,[p,g,p,g];const x=100*n/(o-0);let A=!1;x>60&&!t.ignoreZeroVoxels&&(F.warn(`${Math.round(x)}% of voxels are zero: ignoring zeros for cal_max`),A=!0,t.ignoreZeroVoxels=!0),t.ignoreZeroVoxels||(n=0),n+=a;const y=Math.round((o-0-n)*t.percentileFrac);if(y<1||r===s)return i?Fr(t,e,!1):(F.debug("no variability in image intensity?"),t.cal_min=f,t.cal_max=u,t.robust_min=t.cal_min,t.robust_max=t.cal_max,t.global_min=f,t.global_max=u,[f,u,f,u]);const v=1001,b=(v-1)/(s-r),w=new Array(v);for(let S=0;S<v;S++)w[S]=0;if(d)for(let S=0;S<o;S++)w[Math.round((h[S]-r)*b)]++;else if(t.ignoreZeroVoxels)for(let S=0;S<o;S++)h[S]!==0&&(isNaN(h[S])||w[Math.round((h[S]-r)*b)]++);else for(let S=0;S<o;S++)isNaN(h[S])||w[Math.round((h[S]-r)*b)]++;let C=0,M=0;for(;C<y;)C+=w[M],M++;M--,C=0;let T=v;for(;C<y;)T--,C+=w[T];if(M===T){let S=-1;for(;S!==0;)M>0&&(M--,w[M]>0&&(S=0)),S!==0&&T<v-1&&(T++,w[T]>0&&(S=0)),M===0&&T===v-1&&(S=0)}let E=Tt(t,M/b+r),I=Tt(t,T/b+r);return t.hdr.cal_min<t.hdr.cal_max&&t.hdr.cal_min>=f&&t.hdr.cal_max<=u&&(E=t.hdr.cal_min,I=t.hdr.cal_max),A&&(E=Math.min(E,0)),t.cal_min=E,t.cal_max=I,t.hdr.intent_code===1002&&(t.cal_min=f,t.cal_max=u),t.robust_min=t.cal_min,t.robust_max=t.cal_max,t.global_min=f,t.global_max=u,[E,I,f,u]}function Fi(t,e){t._colormap=e,Fr(t),t.onColormapChange&&t.onColormapChange(t)}function Vh(t,e){t.colormapLabel=re.makeLabelLut(e)}async function Ph(t,e){t.colormapLabel=await re.makeLabelLutFromUrl(e)}function gs(t){return t._colormap}function Nh(t){return t._opacity}function Lh(t,e){t._opacity=e,t.onOpacityChange&&t.onOpacityChange(t)}async function kh(t,e={}){if(t==="")throw Error("url must not be empty");let r=/^(?:[a-z+]+:)?\/\//i.test(t)?t:new URL(t,window.location.href);/(?:.([^.]+))?$/.exec(r.pathname)||(r=new URL("niivue-manifest.txt",t));let a=await fetch(r,{headers:e});if(!a.ok)throw Error(a.statusText);const l=(await a.text()).split(`
|
|
69
|
+
`),h=/(.*\/).*/.exec(r)[0],d=[];for(const f of l){const u=new URL(f,h);if(a=await fetch(u,{headers:e}),!a.ok)throw Error(a.statusText);const m=await a.arrayBuffer();d.push({name:f,data:m})}return d}async function ai(t,e){const i=t.getReader(),r=new $a,s=[];let n=0,a=!1,o,l;const c=new Promise((d,f)=>{o=d,l=f});function h(){const d=new Uint8Array(n);let f=0;for(const u of s)d.set(u,f),f+=u.length;o(d)}return r.ondata=d=>{s.push(d),n+=d.length,n>=e&&(a=!0,i.cancel().catch(()=>{}),h())},(async()=>{try{for(;!a;){const{done:d,value:f}=await i.read();if(d){a=!0,r.push(new Uint8Array,!0);return}r.push(f,!1)}}catch(d){l(d)}})().catch(()=>{}),c}function Oh(t){const i=new URL(t).searchParams.get("response-content-disposition");if(i){const r=i.match(/filename\*?=(?:UTF-8'')?"?([^";]+)"?/);if(r)return decodeURIComponent(r[1])}return t.split("/").pop().split("?")[0]}async function Pn(t="",e={},i=NaN){if(isNaN(i))return null;const r=await fetch(t,{headers:e,cache:"force-cache"});let s=352,n=await ai(r.body,s);const a=new DataView(n.buffer,n.byteOffset,n.byteLength),o=a.getUint16(0,!0),l=o===348;if(!l&&!(o===23553)||(n.length>111&&(s=a.getFloat32(108,l)),s>n.length&&(n=await ai(r.body,s)),!(n[0]===92&&n[1]===1||n[1]===92&&n[0]===1)))return null;const d=await Nt(n.buffer);if(!d)throw new Error("Could not read NIfTI header");const f=d.numBitsPerVoxel/8,u=[1,2,3].reduce((y,v)=>y*(d.dims[v]>1?d.dims[v]:1),1),m=[4,5,6].reduce((y,v)=>y*(d.dims[v]>1?d.dims[v]:1),1),p=Math.max(Math.min(i,m),1),g=d.vox_offset+p*u*f;if(p===m)return null;const x=await fetch(t,{headers:e,cache:"force-cache"});return(await ai(x.body,g)).buffer.slice(0,g)}async function zh(t="",e={},i=NaN){if(isNaN(i))return null;const s=(await fetch(t,{headers:e,cache:"force-cache"})).body.getReader(),{value:n,done:a}=await s.read();let o=n;if(a||!o||o.length<2)throw new Error("Not enough data to determine compression");const l=new DataView(o.buffer,o.byteOffset,o.byteLength),c=l.getUint16(0,!0);if(c===35615)return await s.cancel(),Pn(t,e,i);const d=c===348;if(!d&&!(c===23553))return await s.cancel(),null;let u=352;for(o.length>111&&(u=l.getFloat32(108,d));o.length<u;){let C=function(E,I){const S=new Uint8Array(E.length+I.length);return S.set(E,0),S.set(I,E.length),S};const{value:M,done:T}=await s.read();if(T||!M)break;o=C(o,M)}const m=await Nt(o.buffer);if(!m)throw new Error("Could not read NIfTI header");const p=m.numBitsPerVoxel/8,g=[1,2,3].reduce((C,M)=>C*(m.dims[M]>1?m.dims[M]:1),1),x=[4,5,6].reduce((C,M)=>C*(m.dims[M]>1?m.dims[M]:1),1),A=Math.max(Math.min(i,x),1),y=m.vox_offset+A*g*p,v=new Uint8Array(y),b=Math.min(o.length,y);v.set(o.subarray(0,b),0);let w=b;for(;w<y;){const{value:C,done:M}=await s.read();if(M||!C)return await s.cancel(),null;const T=Math.min(C.length,y-w);v.set(C.subarray(0,T),w),w+=T}return await s.cancel(),v.buffer}async function Gh(t,e=NaN){let i=t.stream();if(!isNaN(e)){let h=0;const d=new TransformStream({transform(f,u){if(h>=e){u.terminate();return}const m=e-h;f.length>m?(u.enqueue(f.slice(0,m)),u.terminate()):u.enqueue(f),h+=f.length}});i=i.pipeThrough(d)}const r=await Ir(i),s=[],n=r.getReader();for(;;){const{done:h,value:d}=await n.read();if(h)break;s.push(d)}const a=s.reduce((h,d)=>h+d.length,0),o=new ArrayBuffer(a),l=new Uint8Array(o);let c=0;for(const h of s)l.set(h,c),c+=h.length;return o}function Yh(t){const e=window.atob(t),i=e.length,r=new Uint8Array(i);for(let s=0;s<i;s++)r[s]=e.charCodeAt(s);return r.buffer}function Bi(t){const e=t.match(/\.([^.]+)(?:\.gz|\.bz2|\.xz)?$/);return e?e[1]:""}function Xh(t){if(!t.hdr)throw new Error("hdr undefined");const e=t.id,i=t.hdr.datatypeCode,r=t.hdr.dims,s=r[1],n=r[2],a=r[3],o=Math.max(1,r[4]),l=t.hdr.pixDims,c=l[1],h=l[2],d=l[3],f=l[4],u=Math.floor(t.hdr.numBitsPerVoxel/8);return{id:e,datatypeCode:i,nx:s,ny:n,nz:a,nt:o,dx:c,dy:h,dz:d,dt:f,bpv:u}}function Wh(t){return si("","",t.name,t._colormap,t.opacity,t.cal_min,t.cal_max,t.trustCalMinMax,t.percentileFrac,t.ignoreZeroVoxels,t.useQFormNotSForm,t.colormapNegative,t.frame4D,t.imageType,t.cal_minNeg,t.cal_maxNeg,t.colorbarVisible)}function Kh(t,e){t.hdr.cal_min=e.cal_min,t.hdr.cal_max=e.cal_max,Object.assign(t,e)}function Hh(t,e){if(!(e.datatypeCode===128||e.datatypeCode===2304||e.littleEndian===er()||e.numBitsPerVoxel<=8)){if(e.numBitsPerVoxel===16){const i=new Uint16Array(t);for(let r=0;r<i.length;r++){const s=i[r];i[r]=((s&255)<<8|s>>8&255)<<16>>16}}else if(e.numBitsPerVoxel===32){const i=new Uint32Array(t);for(let r=0;r<i.length;r++){const s=i[r];i[r]=(s&255)<<24|(s&65280)<<8|s>>8&65280|s>>24&255}}else if(e.numBitsPerVoxel===64){const i=e.numBitsPerVoxel/8,r=new Uint8Array(t);for(let s=0;s<r.length;s+=i){let n=i-1;for(let a=0;a<n;a++){const o=r[s+a];r[s+a]=r[s+n],r[s+n]=o,n--}}}}}function qh(t,e){switch(e.datatypeCode){case 2:return{img:new Uint8Array(t)};case 4:return{img:new Int16Array(t)};case 16:return{img:new Float32Array(t)};case 64:return{img:new Float64Array(t)};case 128:return{img:new Uint8Array(t)};case 512:return{img:new Uint16Array(t)};case 2304:return{img:new Uint8Array(t)};case 256:{const i=new Int8Array(t),r=i.length,s=new Int16Array(r);for(let n=0;n<r;n++)s[n]=i[n];return{img:s,updatedDatatypeCode:4,updatedNumBitsPerVoxel:16}}case 1:{const i=e.dims[1]*e.dims[2]*Math.max(1,e.dims[3])*Math.max(1,e.dims[4]),r=new Uint8Array(t),s=new Uint8Array(i),n=new Uint8Array(8);for(let o=0;o<8;o++)n[o]=Math.pow(2,o);let a=-1;for(let o=0;o<i;o++){const l=o%8;l===0&&a++,(r[a]&n[l])!==0&&(s[o]=1)}return{img:s,updatedDatatypeCode:2,updatedNumBitsPerVoxel:8}}case 768:{const i=new Uint32Array(t),r=i.length,s=new Float64Array(r);for(let n=0;n<r-1;n++)s[n]=i[n];return{img:s,updatedDatatypeCode:64}}case 8:{const i=new Int32Array(t),r=i.length,s=new Float64Array(r);for(let n=0;n<r-1;n++)s[n]=i[n];return{img:s,updatedDatatypeCode:64}}case 1024:{const i=new BigInt64Array(t),r=i.length,s=new Float64Array(r);for(let n=0;n<r-1;n++)s[n]=Number(i[n]);return{img:s,updatedDatatypeCode:64}}case 32:{const i=new Float32Array(t),r=Math.floor(i.length/2),s=new Float32Array(r),n=new Float32Array(r);let a=0;for(let o=0;o<r-1;o++)n[o]=i[a],s[o]=i[a+1],a+=2;return{img:n,imaginary:s,updatedDatatypeCode:16}}default:throw new Error("datatype "+e.datatypeCode+" not supported")}}function Qh(t){(t.pixDims[1]===0||t.pixDims[2]===0||t.pixDims[3]===0)&&F.error("pixDims not plausible",t)}function Zh(t){(isNaN(t.scl_slope)||t.scl_slope===0)&&(t.scl_slope=1),isNaN(t.scl_inter)&&(t.scl_inter=0)}function jh(t,e){const i=wn(t.affine);if(!e&&i&&t.qform_code<=t.sform_code)return;F.debug("spatial transform based on QForm");const r=t.quatern_b,s=t.quatern_c,n=t.quatern_d,a=Math.sqrt(1-(Math.pow(r,2)+Math.pow(s,2)+Math.pow(n,2))),o=t.pixDims[0]===0?1:t.pixDims[0],l=[[a*a+r*r-s*s-n*n,2*r*s-2*a*n,2*r*n+2*a*s],[2*r*s+2*a*n,a*a+s*s-r*r-n*n,2*s*n-2*a*r],[2*r*n-2*a*s,2*s*n+2*a*r,a*a+n*n-s*s-r*r]],c=t.affine;for(let h=0;h<3;h+=1)for(let d=0;d<3;d+=1)c[h][d]=l[h][d]*t.pixDims[d+1],d===2&&(c[h][d]*=o);c[0][3]=t.qoffset_x,c[1][3]=t.qoffset_y,c[2][3]=t.qoffset_z,t.affine=c}function _h(t){if(wn(t.affine))return;F.debug("Defective NIfTI: spatial transform does not make sense");let e=t.pixDims[1],i=t.pixDims[2],r=t.pixDims[3];(isNaN(e)||e===0)&&(e=1),(isNaN(i)||i===0)&&(i=1),(isNaN(r)||r===0)&&(r=1),t.pixDims[1]=e,t.pixDims[2]=i,t.pixDims[3]=r;const s=[[e,0,0,0],[0,i,0,0],[0,0,r,0],[0,0,0,1]];t.affine=s}function Jh(t,e){Qh(t),Zh(t),jh(t,e),_h(t)}async function $h(t){const e=new URL(t).searchParams,i=e.get("z"),r=e.get("y"),s=e.get("x"),n=i?we(parseInt(i),parseInt(i)+1):null,a=r?we(parseInt(r),parseInt(r)+1):null,o=s?we(parseInt(s),parseInt(s)+1):null,l=t.split("?")[0],c=new an(l),h=ji(c);let d;try{d=await De(h.resolve(t),{kind:"array"})}catch{d=await De(h,{kind:"array"})}let f;if(d.shape.length===4){const v=d.shape[2],b=d.shape[1],w=d.shape[0];n&&n[0]>=v&&(n[0]=v-1),a&&a[0]>=b&&(a[0]=b-1),o&&o[0]>=w&&(o[0]=w-1),f=await _i(d,[o,a,n,null])}else f=await _i(d,[o,a,n]);const u=f.data,[m,p,g,x]=f.shape;return{dataBuffer:u,zarrData:{data:u,width:p,height:m,depth:g,channels:x}}}async function e0(t,e={}){const i=await fetch(t,{headers:e});if(!i.ok)throw Error(i.statusText);if(!i.body)throw new Error("No readable stream available");const r=await Ir(i.body),s=[],n=r.getReader();for(;;){const{done:h,value:d}=await n.read();if(h)break;s.push(d)}const a=s.reduce((h,d)=>h+d.length,0),o=new ArrayBuffer(a),l=new Uint8Array(o);let c=0;for(const h of s)l.set(h,c),c+=h.length;return o}function t0(t,e,i){return i!==""?i:e.toUpperCase()==="HEAD"?t.substring(0,t.lastIndexOf("HEAD"))+"BRIK":e.toUpperCase()==="HDR"?t.substring(0,t.lastIndexOf("HDR"))+"IMG":null}async function i0(t,e={}){try{let i=await fetch(t,{headers:e});if(i.status===404&&(t.includes("BRIK")||t.includes("IMG"))&&(i=await fetch(`${t}.gz`,{headers:e})),!i.ok||!i.body)return null;const r=await Ir(i.body),s=[],n=r.getReader();for(;;){const{done:h,value:d}=await n.read();if(h)break;s.push(d)}const a=s.reduce((h,d)=>h+d.length,0),o=new ArrayBuffer(a),l=new Uint8Array(o);let c=0;for(const h of s)l.set(h,c),c+=h.length;return o}catch(i){return console.error("Error loading paired image data:",i),null}}var Vm={translation:[0,0,0],rotation:[0,0,0],scale:[1,1,1]};function Ui(t){return t*Math.PI/180}function r0(t,e,i){const r=J(),s=Ui(t),n=Ui(e),a=Ui(i);return Ut(r,r,s),Ca(r,r,n),Rt(r,r,a),r}function s0(t){const e=J();tt(e,e,t.translation);const i=r0(t.rotation[0],t.rotation[1],t.rotation[2]);return Ye(e,e,i),fr(e,e,t.scale),e}function n0(t){return Ee(t[0][0],t[1][0],t[2][0],t[3][0],t[0][1],t[1][1],t[2][1],t[3][1],t[0][2],t[1][2],t[2][2],t[3][2],t[0][3],t[1][3],t[2][3],t[3][3])}function a0(t){return[[t[0],t[4],t[8],t[12]],[t[1],t[5],t[9],t[13]],[t[2],t[6],t[10],t[14]],[t[3],t[7],t[11],t[15]]]}function o0(t,e){const i=n0(t),r=J();return Ye(r,e,i),a0(r)}function pt(t){return t.map(e=>[...e])}function Pm(t,e,i=1e-4){for(let r=0;r<3;r++)if(Math.abs(t.translation[r]-e.translation[r])>i||Math.abs(t.rotation[r]-e.rotation[r])>i||Math.abs(t.scale[r]-e.scale[r])>i)return!1;return!0}var l0=class{constructor(t){D(this,"store"),D(this,"baseUrl"),D(this,"arrays",new Map),D(this,"levelPaths",new Map),D(this,"axisMapping",null),this.baseUrl=t.baseUrl,this.store=new an(t.baseUrl)}async fetchInfo(){const t=ji(this.store),e=[];let i=null,r=null;try{const h=await De(t,{kind:"array"});e.push({index:0,path:"/",shape:[...h.shape],chunks:[...h.chunks],dtype:h.dtype}),this.arrays.set(0,h),this.levelPaths.set(0,"/")}catch{try{const d=(await De(t,{kind:"group"})).attrs;if(d.ome&&typeof d.ome=="object"){const f=d.ome;f.multiscales&&Array.isArray(f.multiscales)&&f.multiscales.length>0&&(r=f.multiscales[0])}else d.multiscales&&Array.isArray(d.multiscales)&&d.multiscales.length>0&&(r=d.multiscales[0])}catch{}if(r?.axes&&Array.isArray(r.axes)&&(i=r.axes),r&&r.datasets&&r.datasets.length>0)for(let h=0;h<r.datasets.length;h++){const d=r.datasets[h],f=d.path.startsWith("/")?d.path:`/${d.path}`;try{const u=t.resolve(f),m=await De(u,{kind:"array"});e.push({index:h,path:f,shape:[...m.shape],chunks:[...m.chunks],dtype:m.dtype}),this.arrays.set(h,m),this.levelPaths.set(h,f)}catch(u){console.warn(`Failed to open array at path ${f}:`,u)}}else for(let h=0;h<20;h++){const d=`/${h}`;try{const f=t.resolve(d),u=await De(f,{kind:"array"});e.push({index:h,path:d,shape:[...u.shape],chunks:[...u.chunks],dtype:u.dtype}),this.arrays.set(h,u),this.levelPaths.set(h,d)}catch{break}}}if(e.length===0)throw new Error(`No zarr arrays found at ${this.baseUrl}`);const s=e[0].shape.length,n=this.buildAxisMapping(s,e[0].chunks,i);this.axisMapping=n;let a;i&&(a=n.spatialIndices.map(h=>i[h]?.unit??""));const o=e.map(h=>{const d={index:h.index,path:h.path,shape:n.spatialIndices.map(f=>h.shape[f]),chunks:n.spatialIndices.map(f=>h.chunks[f]),dtype:h.dtype};if(r?.datasets?.[h.index]?.coordinateTransformations){const f=r.datasets[h.index].coordinateTransformations,u=f.find(p=>p.type==="scale"&&p.scale);u?.scale&&(d.scales=n.spatialIndices.map(p=>u.scale[p]));const m=f.find(p=>p.type==="translation"&&p.translation);m?.translation&&(d.translations=n.spatialIndices.map(p=>m.translation[p]))}return d}),l=n.spatialIndices.length,c=l>=3;return console.log(`Zarr axis mapping: original ndim=${s}, spatial ndim=${l}, spatial indices=${JSON.stringify(n.spatialIndices)}, non-spatial=${JSON.stringify(n.nonSpatialAxes.map(h=>h.name))}`),{name:this.baseUrl,levels:o,is3D:c,ndim:l,axisMapping:n,spatialUnits:a}}buildAxisMapping(t,e,i){const r=[],s=[],n=[];if(i&&i.length===t)for(let a=0;a<i.length;a++){const o=i[a];o.type==="space"?(r.push(a),s.push(o.name.toLowerCase())):n.push({index:a,name:o.name,chunkSize:e[a],defaultChunkCoord:0})}else if(i===null&&console.warn("No OME axes metadata found — inferring axis layout from array dimensions"),t<=3){const l=t===2?["y","x"]:["z","y","x"].slice(3-t);for(let c=0;c<t;c++)r.push(c),s.push(l[c])}else if(t===4)n.push({index:0,name:"c",chunkSize:e[0],defaultChunkCoord:0}),r.push(1,2,3),s.push("z","y","x");else if(t===5)n.push({index:0,name:"t",chunkSize:e[0],defaultChunkCoord:0}),n.push({index:1,name:"c",chunkSize:e[1],defaultChunkCoord:0}),r.push(2,3,4),s.push("z","y","x");else{for(let a=0;a<t-3;a++)n.push({index:a,name:`dim${a}`,chunkSize:e[a],defaultChunkCoord:0});for(let a=t-3;a<t;a++)r.push(a),s.push(["z","y","x"][a-(t-3)])}return{originalNdim:t,spatialIndices:r,spatialAxisNames:s,nonSpatialAxes:n}}async openLevel(t){if(this.arrays.has(t))return this.arrays.get(t);const e=ji(this.store),i=this.levelPaths.get(t)??(t===0?"/":`/${t}`);try{const r=e.resolve(i),s=await De(r,{kind:"array"});return this.arrays.set(t,s),this.levelPaths.set(t,i),s}catch{if(t===0){const r=await De(e,{kind:"array"});return this.arrays.set(t,r),this.levelPaths.set(t,"/"),r}throw new Error(`Cannot open zarr array at level ${t}`)}}async fetchChunk(t,e,i,r,s,n){try{const a=await this.openLevel(t),o=this.axisMapping;let l;if(o&&o.originalNdim>o.spatialIndices.length){l=new Array(o.originalNdim).fill(0);for(const f of o.nonSpatialAxes)l[f.index]=s?.[f.name]??f.defaultChunkCoord;const d=r!==void 0&&o.spatialIndices.length>=3?[r,i,e]:[i,e];for(let f=0;f<d.length&&f<o.spatialIndices.length;f++)l[o.spatialIndices[f]]=d[f]}else r!==void 0&&a.shape.length>=3?l=[r,i,e]:l=[i,e];let h=(await a.getChunk(l,{signal:n})).data;if(o&&o.nonSpatialAxes.length>0){const d=o.spatialIndices.reduce((f,u)=>f*a.chunks[u],1);if(h.length>d){let f=0,u=h.length;for(let m=0;m<o.originalNdim;m++)u=Math.floor(u/a.chunks[m]),o.spatialIndices.includes(m)||(f+=0*u);h=h.subarray(f,f+d)}}return h}catch(a){return console.warn(`Failed to fetch chunk at level ${t}, x=${e}, y=${i}, z=${r}:`,a),null}}async fetchChunks(t,e,i){const r=new Map,s=i.map(async n=>{const a=await this.fetchChunk(e,n.x,n.y,n.z);if(a){const o=n.z!==void 0?`${t}:${e}/${n.x}/${n.y}/${n.z}`:`${t}:${e}/${n.x}/${n.y}`;r.set(o,a)}});return await Promise.all(s),r}async fetchRegion(t,e){try{const i=await this.openLevel(t),r=this.axisMapping,s=[];if(r&&r.originalNdim>r.spatialIndices.length)for(let a=0;a<r.originalNdim;a++){const o=r.spatialIndices.indexOf(a);o===-1?s.push(0):r.spatialIndices.length>=3?o===0&&e.zStart!==void 0&&e.zEnd!==void 0?s.push(we(e.zStart,e.zEnd)):o===1?s.push(we(e.yStart,e.yEnd)):o===2?s.push(we(e.xStart,e.xEnd)):s.push(we(0,i.shape[a])):o===0?s.push(we(e.yStart,e.yEnd)):s.push(we(e.xStart,e.xEnd))}else e.zStart!==void 0&&e.zEnd!==void 0&&i.shape.length>=3?(s.push(we(e.zStart,e.zEnd)),s.push(we(e.yStart,e.yEnd)),s.push(we(e.xStart,e.xEnd))):(s.push(we(e.yStart,e.yEnd)),s.push(we(e.xStart,e.xEnd)));const n=await _i(i,s);return{data:n.data,shape:n.shape}}catch(i){return console.warn(`Failed to fetch region at level ${t}:`,i),null}}getUrl(){return this.baseUrl}clearArrayCache(){this.arrays.clear(),this.levelPaths.clear()}},Kt=class{constructor(t=500){D(this,"cache"),D(this,"loadingSet"),D(this,"maxChunks"),this.cache=new Map,this.loadingSet=new Set,this.maxChunks=t}static getKey(t,e,i,r,s){return s!==void 0?`${t}:${e}/${i}/${r}/${s}`:`${t}:${e}/${i}/${r}`}has(t){return this.cache.has(t)}get(t){const e=this.cache.get(t);return e&&(this.cache.delete(t),this.cache.set(t,e)),e}set(t,e){for(this.cache.has(t)&&this.cache.delete(t);this.cache.size>=this.maxChunks;){const i=this.cache.keys().next().value;if(i)this.cache.delete(i);else break}this.cache.set(t,e)}isLoading(t){return this.loadingSet.has(t)}startLoading(t){this.loadingSet.add(t)}doneLoading(t){this.loadingSet.delete(t)}get size(){return this.cache.size}get loadingCount(){return this.loadingSet.size}clear(){this.cache.clear(),this.loadingSet.clear()}delete(t){return this.loadingSet.delete(t),this.cache.delete(t)}keys(){return this.cache.keys()}};function c0(t){const e=t.toLowerCase().replace(/[<>|]/g,"");return e==="u1"||e==="uint8"?2:e==="i1"||e==="int8"?256:e==="u2"||e==="uint16"?512:e==="i2"||e==="int16"?4:e==="u4"||e==="uint32"?768:e==="i4"||e==="int32"?8:e==="f4"||e==="float32"?16:e==="f8"||e==="float64"?64:(console.warn(`Unknown zarr dtype: ${t}, defaulting to uint8`),2)}function h0(t){switch(t){case 2:case 256:return 1;case 512:case 4:return 2;case 768:case 8:case 16:return 4;case 64:return 8;default:return 1}}function d0(t,e){switch(t){case 2:case 256:return new Uint8Array(e);case 512:return new Uint16Array(e);case 4:return new Int16Array(e);case 8:return new Int32Array(e);case 768:return new Uint32Array(e);case 16:return new Float32Array(e);case 64:return new Float64Array(e);default:return new Uint8Array(e)}}function Pe(t,e){if(!e)return t;switch(e.toLowerCase()){case"micrometer":case"um":case"µm":return t/1e3;case"nanometer":case"nm":return t/1e6;case"millimeter":case"mm":return t;case"centimeter":case"cm":return t*10;case"meter":case"m":return t*1e3;default:return t}}var f0=class Nn{constructor(e){D(this,"hostImage"),D(this,"chunkClient"),D(this,"chunkCache"),D(this,"pyramidInfo"),D(this,"datatypeCode"),D(this,"pyramidLevel"),D(this,"levelDims"),D(this,"volumeDims"),D(this,"chunkSize"),D(this,"voxelScales"),D(this,"voxelTranslations"),D(this,"hasTranslations"),D(this,"convertUnitsToMm"),D(this,"worldOffsetMM",[0,0,0]),D(this,"centerX"),D(this,"centerY"),D(this,"centerZ"),D(this,"channel"),D(this,"nonSpatialCoords",{}),D(this,"isUpdating",!1),D(this,"needsUpdate",!1),D(this,"currentAbortController",null),D(this,"runningMin",1/0),D(this,"runningMax",-1/0),D(this,"calibrationDone",!1),D(this,"updateDebounceTimer",null),D(this,"UPDATE_DEBOUNCE_MS",50),D(this,"pendingChunkCount",0),D(this,"lastRenderedChunkCount",0),D(this,"centerAtDragStart",null),D(this,"onChunksUpdated"),D(this,"onAllChunksLoaded"),this.hostImage=e,this.chunkClient=null,this.chunkCache=null,this.pyramidInfo=null,this.datatypeCode=2,this.pyramidLevel=0,this.levelDims={width:0,height:0,depth:0},this.volumeDims={width:0,height:0,depth:0},this.chunkSize={width:0,height:0,depth:0},this.voxelScales={width:1,height:1,depth:1},this.voxelTranslations={width:0,height:0,depth:0},this.hasTranslations=!1,this.convertUnitsToMm=!0,this.centerX=0,this.centerY=0,this.centerZ=0,this.channel=0}static async create(e,i,r){const s=new Nn(e);s.chunkClient=new l0({baseUrl:i}),s.pyramidInfo=await s.chunkClient.fetchInfo(),s.chunkCache=new Kt(r.cacheSize??500);const n=r.maxTextureSize??2048,a=r.maxVolumeSize??256,l=s.pyramidInfo.levels[0].shape;l.every(f=>f<=a&&f<=n)?s.pyramidInfo.is3D&&l.length>=3?s.volumeDims={depth:l[0],height:l[1],width:l[2]}:s.volumeDims={height:l[0],width:l[1],depth:1}:s.volumeDims={width:Math.min(a,n),height:Math.min(a,n),depth:Math.min(a,n)},s.datatypeCode=c0(s.pyramidInfo.levels[0].dtype),s.convertUnitsToMm=r.convertUnitsToMm??!0,s.channel=r.channel??0;const h=s.pyramidInfo.axisMapping;for(const f of h.nonSpatialAxes)f.name==="c"&&(s.nonSpatialCoords[f.name]=s.channel);const d=Math.max(0,Math.min(r.level,s.pyramidInfo.levels.length-1));return s.pyramidLevel=d,s.updateLevelInfo(),s.centerX=s.levelDims.width/2,s.centerY=s.levelDims.height/2,s.centerZ=s.levelDims.depth/2,s.configureHostImage(),s}async loadInitialChunks(){await this.updateVolume()}updateLevelInfo(){const e=this.pyramidInfo.levels[this.pyramidLevel],i=e.shape;this.pyramidInfo.is3D&&i.length>=3?this.levelDims={depth:i[0],height:i[1],width:i[2]}:this.levelDims={height:i[0],width:i[1],depth:1};const r=e.chunks;this.pyramidInfo.is3D&&r.length>=3?this.chunkSize={depth:r[0],height:r[1],width:r[2]}:this.chunkSize={height:r[0],width:r[1],depth:1},e.scales?this.pyramidInfo.is3D&&e.scales.length>=3?this.voxelScales={depth:e.scales[0],height:e.scales[1],width:e.scales[2]}:e.scales.length>=2&&(this.voxelScales={height:e.scales[0],width:e.scales[1],depth:1}):this.voxelScales={width:1,height:1,depth:1},e.translations?(this.pyramidInfo.is3D&&e.translations.length>=3?this.voxelTranslations={depth:e.translations[0],height:e.translations[1],width:e.translations[2]}:e.translations.length>=2&&(this.voxelTranslations={height:e.translations[0],width:e.translations[1],depth:0}),this.hasTranslations=!0):(this.voxelTranslations={width:0,height:0,depth:0},this.hasTranslations=!1)}configureHostImage(){const{width:e,height:i,depth:r}=this.volumeDims,s=h0(this.datatypeCode),{scaleW:n,scaleH:a,scaleD:o}=this.getConvertedScales(),l=new G;l.littleEndian=!0,l.dims=[3,e,i,r,1,0,0,0],l.pixDims=[1,n,a,o,1,0,0,0],l.datatypeCode=this.datatypeCode,l.numBitsPerVoxel=s*8,l.scl_inter=0,l.scl_slope=1,l.sform_code=2,l.magic="n+1",l.vox_offset=352,l.affine=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];const c=this.hostImage;c.name=`zarr:${this.pyramidInfo.name}`,c.id=di(),c._colormap="gray",c._opacity=1,c.hdr=l,c.nFrame4D=1,c.frame4D=0,c.nTotalFrame4D=1,c.nVox3D=e*i*r,c.dims=[e,i,r],c.pixDims=[n,a,o],c.img=d0(this.datatypeCode,e*i*r),this.updateAffine(),c.originalAffine=pt(l.affine),c.cal_min=0,c.cal_max=0,c.robust_min=0,c.robust_max=0,c.global_min=0,c.global_max=0}getConvertedScales(){const e=this.pyramidInfo.spatialUnits;let i=this.voxelScales.depth,r=this.voxelScales.height,s=this.voxelScales.width;return this.convertUnitsToMm&&e&&(e.length>=3?(i=Pe(i,e[0]),r=Pe(r,e[1]),s=Pe(s,e[2])):e.length>=2&&(r=Pe(r,e[0]),s=Pe(s,e[1]))),{scaleW:s,scaleH:r,scaleD:i}}getConvertedTranslations(){const e=this.pyramidInfo.spatialUnits;let i=this.voxelTranslations.depth,r=this.voxelTranslations.height,s=this.voxelTranslations.width;return this.convertUnitsToMm&&e&&(e.length>=3?(i=Pe(i,e[0]),r=Pe(r,e[1]),s=Pe(s,e[2])):e.length>=2&&(r=Pe(r,e[0]),s=Pe(s,e[1]))),{transW:s,transH:r,transD:i}}updateAffine(){const e=this.hostImage.hdr;if(!e)return;const{width:i,height:r,depth:s}=this.volumeDims,n=this.pyramidInfo.axisMapping.spatialAxisNames;if(this.hasTranslations&&n.length>=3){const{scaleW:a,scaleH:o,scaleD:l}=this.getConvertedScales(),{transW:c,transH:h,transD:d}=this.getConvertedTranslations(),f=this.centerX-i/2,u=this.centerY-r/2,m=this.centerZ-s/2,p=[{name:n[n.length-1],scale:a,trans:c+f*a},{name:n[n.length-2],scale:o,trans:h+u*o},{name:n[n.length-3],scale:l,trans:d+m*l}],g=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]];for(let x=0;x<3;x++){const A=p[x].name==="x"?0:p[x].name==="y"?1:2;g[A][x]=p[x].scale,g[A][3]=p[x].trans}g[0][3]+=this.worldOffsetMM[0],g[1][3]+=this.worldOffsetMM[1],g[2][3]+=this.worldOffsetMM[2],e.affine=g}else{const{scaleW:a,scaleH:o,scaleD:l}=this.getConvertedScales(),c=this.centerX-i/2,h=this.centerY-r/2,d=this.centerZ-s/2;if(n.length>=2){const f=[{name:n[n.length-1],scale:a,trans:c*a},{name:n[n.length-2],scale:o,trans:h*o},{name:"z",scale:l,trans:d*l}],u=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]];for(let m=0;m<3;m++){const p=f[m].name==="x"?0:f[m].name==="y"?1:2;u[p][m]=f[m].scale,u[p][3]=f[m].trans}u[0][3]+=this.worldOffsetMM[0],u[1][3]+=this.worldOffsetMM[1],u[2][3]+=this.worldOffsetMM[2],e.affine=u}else e.affine=[[a,0,0,c*a+this.worldOffsetMM[0]],[0,-o,0,h*o+this.worldOffsetMM[1]],[0,0,-l,d*l+this.worldOffsetMM[2]],[0,0,0,1]]}this.hostImage.calculateRAS(),this.hostImage.originalAffine=pt(this.hostImage.hdr.affine)}beginDrag(){this.centerAtDragStart={x:this.centerX,y:this.centerY,z:this.centerZ}}endDrag(){this.centerAtDragStart=null}async panBy(e,i,r=0){this.centerX-=e,this.centerY-=i,this.centerZ-=r,this.clampCenter(),this.updateAffine(),await this.updateVolume()}async panTo(e,i,r){const s=this.centerX,n=this.centerY,a=this.centerZ;this.centerX=e,this.centerY=i,r!==void 0&&(this.centerZ=r),this.clampCenter(),!(Math.abs(this.centerX-s)<.001&&Math.abs(this.centerY-n)<.001&&Math.abs(this.centerZ-a)<.001)&&(this.updateAffine(),await this.updateVolume())}async setPyramidLevel(e){const i=Math.max(0,Math.min(this.pyramidInfo.levels.length-1,e));if(i===this.pyramidLevel)return;const r=this.levelDims;this.pyramidLevel=i,this.updateLevelInfo();const s=this.levelDims;this.centerX=this.centerX/r.width*s.width,this.centerY=this.centerY/r.height*s.height,this.centerZ=this.centerZ/r.depth*s.depth,this.clampCenter(),this.updateAffine(),await this.updateVolume()}getViewportState(){return{centerX:this.centerX,centerY:this.centerY,centerZ:this.centerZ,level:this.pyramidLevel}}getPyramidInfo(){return this.pyramidInfo}getPyramidLevel(){return this.pyramidLevel}getLevelDims(){return{...this.levelDims}}getVolumeDims(){return{...this.volumeDims}}getWorldOffset(){return[...this.worldOffsetMM]}setWorldCenter(e){const{scaleW:i,scaleH:r,scaleD:s}=this.getConvertedScales(),{transW:n,transH:a,transD:o}=this.getConvertedTranslations(),l=this.pyramidInfo.axisMapping.spatialAxisNames,c=this.levelDims.width/2*i+n,h=this.levelDims.height/2*r+a,d=this.levelDims.depth/2*s+o,f=[0,0,0],u=[{name:l[l.length-1],phys:c},{name:l[l.length-2],phys:h},{name:l.length>=3?l[l.length-3]:"z",phys:d}];for(const m of u){const p=m.name==="x"?0:m.name==="y"?1:2;f[p]=m.phys}this.worldOffsetMM=[e[0]-f[0],e[1]-f[1],e[2]-f[2]],this.centerX=this.levelDims.width/2,this.centerY=this.levelDims.height/2,this.centerZ=this.levelDims.depth/2,this.clampCenter(),this.updateAffine()}mmToLevelCoords(e,i,r){e-=this.worldOffsetMM[0],i-=this.worldOffsetMM[1],r-=this.worldOffsetMM[2];const{scaleW:s,scaleH:n,scaleD:a}=this.getConvertedScales(),o=this.pyramidInfo.axisMapping.spatialAxisNames,l={x:e,y:i,z:r};let c=0,h=0,d=0;if(o.length>=2){const f=o[o.length-1],u=o[o.length-2],m=o.length>=3?o[o.length-3]:"z",p=l[f]??e,g=l[u]??i,x=l[m]??r;if(this.hasTranslations){const{transW:A,transH:y,transD:v}=this.getConvertedTranslations();c=s!==0?(p-A)/s:0,h=n!==0?(g-y)/n:0,d=a!==0?(x-v)/a:0}else c=s!==0?p/s:0,h=n!==0?g/n:0,d=a!==0?x/a:0}else if(this.hasTranslations){const{transW:f,transH:u,transD:m}=this.getConvertedTranslations();c=s!==0?(e-f)/s:0,h=n!==0?(i-u)/n:0,d=a!==0?(r-m)/a:0}else c=s!==0?e/s:0,h=n!==0?i/n:0,d=a!==0?r/a:0;return{width:Math.round(c),height:Math.round(h),depth:Math.round(d),level:this.pyramidLevel,levelDims:{...this.levelDims}}}clampCenter(){const e=this.volumeDims.width/2,i=this.volumeDims.height/2,r=this.volumeDims.depth/2;this.centerX=Math.max(-e,Math.min(this.levelDims.width+e,this.centerX)),this.centerY=Math.max(-i,Math.min(this.levelDims.height+i,this.centerY)),this.centerZ=Math.max(-r,Math.min(this.levelDims.depth+r,this.centerZ))}getVisibleChunks(){const{width:i,height:r,depth:s}=this.volumeDims,n=this.pyramidLevel,a=Math.max(0,Math.floor(this.centerX-i/2)),o=Math.min(this.levelDims.width,Math.ceil(this.centerX+i/2)),l=Math.max(0,Math.floor(this.centerY-r/2)),c=Math.min(this.levelDims.height,Math.ceil(this.centerY+r/2)),h=Math.max(0,Math.floor(this.centerZ-s/2)),d=Math.min(this.levelDims.depth,Math.ceil(this.centerZ+s/2)),f=Math.max(0,Math.floor(a/this.chunkSize.width)),u=Math.max(0,Math.floor(l/this.chunkSize.height)),m=Math.max(0,Math.floor(h/this.chunkSize.depth)),p=Math.min(Math.ceil(this.levelDims.width/this.chunkSize.width),Math.ceil(o/this.chunkSize.width)),g=Math.min(Math.ceil(this.levelDims.height/this.chunkSize.height),Math.ceil(c/this.chunkSize.height)),x=Math.min(Math.ceil(this.levelDims.depth/this.chunkSize.depth),Math.ceil(d/this.chunkSize.depth)),A=[];for(let w=m;w<x;w++){for(let C=u;C<g;C++){for(let M=f;M<p&&(this.pyramidInfo.is3D?A.push({level:n,x:M,y:C,z:w}):A.push({level:n,x:M,y:C}),!(A.length>=1e3));M++);if(A.length>=1e3)break}if(A.length>=1e3)break}const y=(f+p)/2,v=(u+g)/2,b=(m+x)/2;return A.sort((w,C)=>{const M=(w.x-y)**2+(w.y-v)**2+((w.z??0)-b)**2,T=(C.x-y)**2+(C.y-v)**2+((C.z??0)-b)**2;return M-T}),A}async updateVolume(){if(this.isUpdating){this.needsUpdate=!0,this.currentAbortController?.abort();return}this.isUpdating=!0;try{do{this.needsUpdate=!1,this.currentAbortController?.abort();const e=new AbortController;this.currentAbortController=e,await new Promise(i=>{requestAnimationFrame(()=>i())}),!this.needsUpdate&&(this.clearVolumeData(),await this.assembleVisibleChunks(e.signal))}while(this.needsUpdate)}finally{this.isUpdating=!1}}clearVolumeData(){const e=this.hostImage.img;if(e.fill)e.fill(0);else for(let i=0;i<e.length;i++)e[i]=0;this.pendingChunkCount=0,this.lastRenderedChunkCount=0,this.updateDebounceTimer!==null&&(clearTimeout(this.updateDebounceTimer),this.updateDebounceTimer=null)}async assembleVisibleChunks(e){const i=this.getVisibleChunks(),r=this.pyramidInfo.name,s=this.pyramidLevel,n=[],a=[];for(const o of i){const l=Kt.getKey(r,o.level,o.x,o.y,o.z);this.chunkCache.has(l)?n.push(o):this.chunkCache.isLoading(l)||a.push(o)}for(const o of n){const l=Kt.getKey(r,o.level,o.x,o.y,o.z),c=this.chunkCache.get(l);c&&(this.assembleChunkIntoVolume(o,c),this.pendingChunkCount++)}if(n.length>0&&(this.updateCalibration(),this.onChunksUpdated?.()),a.length>0){const o=a.map(async l=>{const c=Kt.getKey(r,l.level,l.x,l.y,l.z);this.chunkCache.startLoading(c);try{const h=await this.chunkClient.fetchChunk(l.level,l.x,l.y,l.z,this.nonSpatialCoords,e);if(this.chunkCache.doneLoading(c),e?.aborted)return;h&&(this.chunkCache.set(c,h),this.pyramidLevel===s&&(this.assembleChunkIntoVolume(l,h),this.pendingChunkCount++,this.scheduleChunksUpdated()))}catch(h){if(this.chunkCache.doneLoading(c),h instanceof DOMException&&h.name==="AbortError")return;console.warn(`Failed to fetch chunk ${c}:`,h)}});await Promise.all(o),this.updateDebounceTimer!==null&&(clearTimeout(this.updateDebounceTimer),this.updateDebounceTimer=null),this.pendingChunkCount>this.lastRenderedChunkCount&&(this.lastRenderedChunkCount=this.pendingChunkCount,this.updateCalibration(),this.onChunksUpdated?.()),this.onAllChunksLoaded?.()}}assembleChunkIntoVolume(e,i){const{width:r,height:s,depth:n}=this.volumeDims,a=this.hostImage.img,o=e.x*this.chunkSize.width,l=e.y*this.chunkSize.height,c=(e.z??0)*this.chunkSize.depth,h=this.centerX-r/2,d=this.centerY-s/2,f=this.centerZ-n/2,u=Math.round(o-h),m=Math.round(l-d),p=Math.round(c-f),g=Math.min(this.chunkSize.width,this.levelDims.width-o),x=Math.min(this.chunkSize.height,this.levelDims.height-l),A=Math.min(this.chunkSize.depth,this.levelDims.depth-c);if(g<=0||x<=0||A<=0)return;if(!this.calibrationDone){const w=Math.max(1,Math.floor(i.length/2e3));for(let C=0;C<i.length;C+=w){const M=i[C];M<this.runningMin&&(this.runningMin=M),M>this.runningMax&&(this.runningMax=M)}}const y=this.chunkSize.width*this.chunkSize.height*this.chunkSize.depth,v=i.length>=y?this.chunkSize.width:g,b=i.length>=y?this.chunkSize.height:x;for(let w=0;w<A;w++){const C=p+w;if(!(C<0||C>=n))for(let M=0;M<x;M++){const T=m+M;if(!(T<0||T>=s))for(let E=0;E<g;E++){const I=u+E;if(I<0||I>=r)continue;const S=w*b*v+M*v+E,U=I+T*r+C*r*s;S>=0&&S<i.length&&U>=0&&U<a.length&&(a[U]=i[S])}}}}updateCalibration(){this.calibrationDone||this.runningMin<1/0&&this.runningMax>-1/0&&(this.hostImage.cal_min=this.runningMin,this.hostImage.cal_max=this.runningMax,this.hostImage.robust_min=this.runningMin,this.hostImage.robust_max=this.runningMax,this.hostImage.global_min=this.runningMin,this.hostImage.global_max=this.runningMax,this.calibrationDone=!0)}scheduleChunksUpdated(){this.pendingChunkCount!==this.lastRenderedChunkCount&&(this.updateDebounceTimer!==null&&clearTimeout(this.updateDebounceTimer),this.updateDebounceTimer=setTimeout(()=>{this.updateDebounceTimer=null,this.lastRenderedChunkCount=this.pendingChunkCount,this.updateCalibration(),this.onChunksUpdated?.()},this.UPDATE_DEBOUNCE_MS))}clearCache(){this.chunkCache.clear()}async refresh(){await this.updateVolume()}},Me=class ht{constructor(e=null,i="",r="gray",s=1,n=null,a=NaN,o=NaN,l=!0,c=.02,h=!1,d=!1,f="",u=0,m=j.UNKNOWN,p=NaN,g=NaN,x=!0,A=null,y=0){D(this,"name"),D(this,"id"),D(this,"url"),D(this,"headers"),D(this,"_colormap"),D(this,"_opacity"),D(this,"percentileFrac"),D(this,"ignoreZeroVoxels"),D(this,"trustCalMinMax"),D(this,"colormapNegative"),D(this,"colormapLabel"),D(this,"colormapInvert"),D(this,"nFrame4D"),D(this,"frame4D"),D(this,"nTotalFrame4D"),D(this,"cal_minNeg"),D(this,"cal_maxNeg"),D(this,"colorbarVisible",!0),D(this,"modulationImage",null),D(this,"modulateAlpha",0),D(this,"series",[]),D(this,"nVox3D"),D(this,"oblique_angle"),D(this,"maxShearDeg"),D(this,"useQFormNotSForm"),D(this,"colormapType"),D(this,"pixDims"),D(this,"matRAS"),D(this,"pixDimsRAS"),D(this,"obliqueRAS"),D(this,"dimsRAS"),D(this,"permRAS"),D(this,"img2RASstep"),D(this,"img2RASstart"),D(this,"toRAS"),D(this,"toRASvox"),D(this,"frac2mm"),D(this,"frac2mmOrtho"),D(this,"extentsMinOrtho"),D(this,"extentsMaxOrtho"),D(this,"mm2ortho"),D(this,"hdr",null),D(this,"extensions"),D(this,"imageType"),D(this,"img"),D(this,"imaginary"),D(this,"v1"),D(this,"fileObject"),D(this,"dims"),D(this,"onColormapChange",()=>{}),D(this,"onOpacityChange",()=>{}),D(this,"zarrHelper",null),D(this,"_hasExplicitZarrCenter",!1),D(this,"mm000"),D(this,"mm100"),D(this,"mm010"),D(this,"mm001"),D(this,"cal_min"),D(this,"cal_max"),D(this,"robust_min"),D(this,"robust_max"),D(this,"global_min"),D(this,"global_max"),D(this,"urlImgData"),D(this,"isManifest"),D(this,"limitFrames4D"),D(this,"originalAffine"),this.init(e,i,r,s,n,a,o,l,c,h,d,f,u,m,p,g,x,A,y)}init(e=null,i="",r="",s=1,n=null,a=NaN,o=NaN,l=!0,c=.02,h=!1,d=!1,f="",u=0,m=j.UNKNOWN,p=NaN,g=NaN,x=!0,A=null,y=0,v=null){const b=r==="";if(b&&(r="gray"),this.name=i,this.imageType=m,this.id=di(),this._colormap=r,this._opacity=s>1?1:s,this.percentileFrac=c,this.ignoreZeroVoxels=h,this.trustCalMinMax=l,this.colormapNegative=f,this.colormapLabel=A,this.frame4D=u,this.cal_minNeg=p,this.cal_maxNeg=g,this.colorbarVisible=x,this.colormapType=y,this.useQFormNotSForm=d,!e)return;if(b&&this.hdr&&this.hdr.intent_code===1002&&(r="random",this._colormap=r),this.hdr&&typeof this.hdr.magic=="number"&&(this.hdr.magic="n+1"),this.nFrame4D=1,this.hdr)for(let T=4;T<7;T++)this.hdr.dims[T]>1&&(this.nFrame4D*=this.hdr.dims[T]);if(this.frame4D=Math.min(this.frame4D,this.nFrame4D-1),this.nTotalFrame4D=this.nFrame4D,!this.hdr||!v)return;this.hdr.dims[1]===0&&this.hdr.dims[2]===0&&this.hdr.dims[3]===0&&F.warn("Invalid volume: First three dimensions are all zero"),this.hdr.dims[1]=Math.max(this.hdr.dims[1],1),this.hdr.dims[2]=Math.max(this.hdr.dims[2],1),this.hdr.dims[3]=Math.max(this.hdr.dims[3],1),this.nVox3D=this.hdr.dims[1]*this.hdr.dims[2]*this.hdr.dims[3];const w=this.nVox3D*(this.hdr.numBitsPerVoxel/8),C=v.byteLength/w;C!==this.nFrame4D&&(C>0&&C*w===v.byteLength?F.debug("Loading the first "+C+" of "+this.nFrame4D+" volumes"):F.warn("This header does not match voxel data",this.hdr,v.byteLength),this.nFrame4D=C),(this.hdr.intent_code===1007||this.hdr.intent_code===2003)&&this.nFrame4D===3&&this.hdr.datatypeCode===16&&(v=this.float32V1asRGBA(new Float32Array(v)).buffer),Jh(this.hdr,d),Hh(v,this.hdr);const M=qh(v,this.hdr);this.img=M.img,M.imaginary&&(this.imaginary=M.imaginary),M.updatedDatatypeCode!==void 0&&(this.hdr.datatypeCode=M.updatedDatatypeCode),M.updatedNumBitsPerVoxel!==void 0&&(this.hdr.numBitsPerVoxel=M.updatedNumBitsPerVoxel),this.calculateRAS(),this.originalAffine=pt(this.hdr.affine),isNaN(a)||(this.hdr.cal_min=a),isNaN(o)||(this.hdr.cal_max=o),this.calMinMax()}static async new(e=null,i="",r="",s=1,n=null,a=NaN,o=NaN,l=!0,c=.02,h=!1,d=!1,f="",u=0,m=j.UNKNOWN,p=NaN,g=NaN,x=!0,A=null,y=0,v){const b=new ht,w=/(?:\.([^.]+))?$/;let C=w.exec(i)[1]||"";C=C.toUpperCase(),C==="GZ"&&(C=w.exec(i.slice(0,-3))[1],C=C.toUpperCase());let M=null;if(m===j.UNKNOWN&&(m=j.parse(C)),e instanceof ArrayBuffer&&e.byteLength>=2&&m===j.DCM){const T=new Uint8Array(e);(T[0]===92&&T[1]===1||T[1]===92&&T[0]===1)&&(m=j.NII)}switch(b.imageType=m,m){case j.DCM_FOLDER:case j.DCM_MANIFEST:case j.DCM:return;case j.FIB:[M,b.v1]=await Mt.readFIB(b,e);break;case j.MIH:case j.MIF:M=await sr.readMIF(b,e,n);break;case j.NHDR:case j.NRRD:if(M=await Fn.readNrrd(b,e),M===null)throw new Error(`Failed to parse NHDR/NRRD file ${i}`);break;case j.MHD:case j.MHA:M=await rr.readMHA(b,e,n);break;case j.MGH:case j.MGZ:if(M=await Tn.readMgh(b,e,i),M===null)throw new Error(`Failed to parse MGH/MGZ file ${i}`);break;case j.SRC:M=await Mt.readSRC(b,e);break;case j.V:M=ir.readECAT(b,e);break;case j.V16:M=Ct.readV16(b,e);break;case j.VMR:M=Ct.readVMR(b,e);break;case j.HEAD:M=await tr.readHEAD(b,e,n);break;case j.BMP:M=await ni.readBMP(b,e);break;case j.NPY:M=await Dt.readNPY(b,e);break;case j.NPZ:M=await Dt.readNPZ(b,e);break;case j.ZARR:M=await nr.readZARR(b,e,v);break;case j.NII:if(M=await In.readNifti(b,e,n),M===null)throw new Error(`Failed to parse NIfTI file ${i}.`);break;default:throw new Error("Image type not supported")}return b.init(e,i,r,s,n,a,o,l,c,h,d,f,u,m,p,g,x,A,y,M),b}computeObliqueAngle(e){return Rn(e)}float32V1asRGBA(e){return Vn(this,e)}loadImgV1(e=!1,i=!1,r=!1){return Uh(this,e,i,r)}calculateOblique(){or(this)}readECAT(e){return ir.readECAT(this,e)}readV16(e){return Ct.readV16(this,e)}async readNPY(e){return Dt.readNPY(this,e)}async readNPZ(e){return Dt.readNPZ(this,e)}async imageDataFromArrayBuffer(e){return ni.imageDataFromArrayBuffer(e)}async readBMP(e){return ni.readBMP(this,e)}async readZARR(e,i){return nr.readZARR(this,e,i)}readVMR(e){return Ct.readVMR(this,e)}async readFIB(e){return Mt.readFIB(this,e)}async readSRC(e){return Mt.readSRC(this,e)}async readHEAD(e,i){return tr.readHEAD(this,e,i)}async readMHA(e,i){return rr.readMHA(this,e,i)}async readMIF(e,i){return sr.readMIF(this,e,i)}calculateRAS(){Ih(this)}getAffine(){if(!this.hdr)throw new Error("Image header not loaded");return pt(this.hdr.affine)}setAffine(e){if(!this.hdr)throw new Error("Image header not loaded");this.hdr.affine=pt(e),this.calculateRAS()}applyTransform(e){if(!this.hdr)throw new Error("Image header not loaded");const i=s0(e),r=o0(this.hdr.affine,i);this.hdr.affine=r,this.calculateRAS()}resetAffine(){if(!this.hdr)throw new Error("Image header not loaded");if(!this.originalAffine)throw new Error("Original affine not stored");this.hdr.affine=pt(this.originalAffine),this.calculateRAS()}async hdr2RAS(e=1){return Fh(this,e)}img2RAS(e=0){return Bh(this,e)}vox2mm(e,i){return Ge(this,e,i)}mm2vox(e,i=!1){return Un(this,e,i)}arrayEquals(e,i){return ar(e,i)}setColormap(e){Fi(this,e)}setColormapLabel(e){Vh(this,e)}async setColormapLabelFromUrl(e){return Ph(this,e)}get colormap(){return gs(this)}get colorMap(){return gs(this)}set colormap(e){Fi(this,e)}set colorMap(e){Fi(this,e)}get opacity(){return Nh(this)}set opacity(e){Lh(this,e)}calMinMax(e=Number.POSITIVE_INFINITY,i=!0){return Fr(this,e,i)}intensityRaw2Scaled(e){return Tt(this,e)}intensityScaled2Raw(e){return Rh(this,e)}async saveToUint8Array(e,i=null){return Cn(this,e,i)}async saveToDisk(e="",i=null){return ih(this,e,i)}static async fetchDicomData(e,i={}){return kh(e,i)}static async readFirstDecompressedBytes(e,i){return ai(e,i)}static extractFilenameFromUrl(e){return Oh(e)}static async loadInitialVolumesGz(e="",i={},r=NaN){return Pn(e,i,r)}static async loadInitialVolumes(e="",i={},r=NaN){return zh(e,i,r)}static async loadFromUrl({url:e="",urlImgData:i="",headers:r={},name:s="",colormap:n="",opacity:a=1,cal_min:o=NaN,cal_max:l=NaN,trustCalMinMax:c=!0,percentileFrac:h=.02,ignoreZeroVoxels:d=!1,useQFormNotSForm:f=!1,colormapNegative:u="",frame4D:m=0,isManifest:p=!1,limitFrames4D:g=NaN,imageType:x=j.UNKNOWN,colorbarVisible:A=!0,buffer:y=new ArrayBuffer(0),zarrLevel:v,zarrMaxVolumeSize:b,zarrChannel:w,zarrConvertUnits:C,zarrCenterMM:M}={}){if(e==="")throw Error("url must not be empty");let T=null,E=null,I=null;if(e instanceof Uint8Array&&(e=e.slice().buffer),y.byteLength>0&&(e=y),e instanceof ArrayBuffer)if(E=e,s!=="")e=s;else{const R=new Uint8Array(E);e=R[0]===31&&R[1]===139?"array.nii.gz":"array.nii"}let S="";if(s===""?S=Bi(e):S=Bi(s),x===j.UNKNOWN&&(x=j.parse(S)),x===j.UNKNOWN&&typeof e=="string"){const R=await fetch(e,{});if(R.redirected){const P=this.extractFilenameFromUrl(R.url);P&&P.length>0&&s===""&&(s=P,S=Bi(s),x=j.parse(S))}}if(x===j.ZARR){if(v!==void 0)return await ht.createChunkedZarr(e,{level:v,maxVolumeSize:b,channel:w,convertUnitsToMm:C,colormap:n,opacity:a,zarrCenterMM:M});const R=await $h(e);E=R.dataBuffer,I=R.zarrData}const U=x===j.DCM||j.NII;!E&&U&&(E=await this.loadInitialVolumes(e,r,g)),E||(p?(E=await ht.fetchDicomData(e,r),x=j.DCM_MANIFEST):E=await e0(e,r));const B=t0(e,S.toUpperCase(),i);let V=null;if(B&&(V=await i0(B,r)),!E)throw new Error("Unable to load buffer properly from volume");if(!s){let R;try{R=new URL(e).pathname.split("/")}catch{R=e.split("/")}s=R.slice(-1)[0],s.indexOf("?")>-1&&(s=s.slice(0,s.indexOf("?")))}return T=await this.new(E,s,n,a,V,o,l,c,h,d,f,u,m,x,NaN,NaN,!0,null,0,I),T.url=e,T.colorbarVisible=A,T}static async createChunkedZarr(e,i){const r=new ht;return r.zarrHelper=await f0.create(r,e,{url:e,level:i.level,maxVolumeSize:i.maxVolumeSize,maxTextureSize:i.maxTextureSize,channel:i.channel,cacheSize:i.cacheSize,convertUnitsToMm:i.convertUnitsToMm}),i.zarrCenterMM&&(r.zarrHelper.setWorldCenter(i.zarrCenterMM),r._hasExplicitZarrCenter=!0),i.colormap&&(r._colormap=i.colormap),i.opacity!==void 0&&(r._opacity=i.opacity),r.url=e,r}static async readFileAsync(e,i=NaN){return Gh(e,i)}static async loadFromFile({file:e,name:i="",colormap:r="",opacity:s=1,urlImgData:n=null,cal_min:a=NaN,cal_max:o=NaN,trustCalMinMax:l=!0,percentileFrac:c=.02,ignoreZeroVoxels:h=!1,useQFormNotSForm:d=!1,colormapNegative:f="",frame4D:u=0,limitFrames4D:m=NaN,imageType:p=j.UNKNOWN}){let g=null,x=[];try{if(Array.isArray(e))x=await Promise.all(e.map(y=>this.readFileAsync(y)));else{if(isNaN(m))x=await this.readFileAsync(e);else{const y=await this.readFileAsync(e,512),v=new Uint8Array(y);if(!(v[0]===92&&v[1]===1||v[1]===92&&v[0]===1))x=await this.readFileAsync(e);else{const w=await Nt(y);if(!w)throw new Error("could not read nifti header");const C=w.numBitsPerVoxel/8,M=[1,2,3].reduce((S,U)=>S*(w.dims[U]>1?w.dims[U]:1),1),T=[4,5,6].reduce((S,U)=>S*(w.dims[U]>1?w.dims[U]:1),1),E=Math.max(Math.min(m,T),1),I=w.vox_offset+E*M*C;x=await this.readFileAsync(e,I)}}i=e.name}let A=null;n&&(A=await this.readFileAsync(n)),g=await this.new(x,i,r,s,A,a,o,l,c,h,d,f,u,p,NaN,NaN,!0,null,0,null),g.fileObject=e}catch(A){throw F.error(A),new Error("could not build NVImage")}if(g===null)throw new Error("could not build NVImage");return g}static createNiftiArray(e=[256,256,256],i=[1,1,1],r=[1,0,0,-128,0,1,0,-128,0,0,1,-128,0,0,0,1],s=2,n=new Uint8Array){return th(e,i,r,s,n)}static createNiftiHeader(e=[256,256,256],i=[1,1,1],r=[1,0,0,-128,0,1,0,-128,0,0,1,-128,0,0,0,1],s=2){return yn(e,i,r,s)}getVolumeData(e=[-1,0,0],i=[0,0,0],r="same"){return sh(this,e,i,r)}setVolumeData(e=[-1,0,0],i=[0,0,0],r=new Uint8Array){nh(this,e,i,r)}static async loadFromBase64({base64:e,name:i="",colormap:r="",opacity:s=1,cal_min:n=NaN,cal_max:a=NaN,trustCalMinMax:o=!0,percentileFrac:l=.02,ignoreZeroVoxels:c=!1,useQFormNotSForm:h=!1,colormapNegative:d="",frame4D:f=0,imageType:u=j.UNKNOWN,cal_minNeg:m=NaN,cal_maxNeg:p=NaN,colorbarVisible:g=!0,colormapLabel:x=null}){let A=null;try{const y=Yh(e);A=await this.new(y,i,r,s,null,n,a,o,l,c,h,d,f,u,m,p,g,x,0,null)}catch(y){F.debug(y)}if(A===null)throw new Error("could not load NVImage");return A}clone(){const e=new ht;return e.id=di(),e.hdr=Object.assign({},this.hdr),e.img=this.img.slice(),e.calculateRAS(),e.calMinMax(),e}zeroImage(){this.img.fill(0)}getImageMetadata(){return Xh(this)}static zerosLike(e,i="same"){const r=e.clone();return r.zeroImage(),i==="uint8"&&(r.img=Uint8Array.from(r.img),r.hdr.datatypeCode=2,r.hdr.numBitsPerVoxel=8),i==="float32"&&(r.img=Float32Array.from(r.img),r.hdr.datatypeCode=16,r.hdr.numBitsPerVoxel=32),r}getValue(e,i,r,s=0,n=!1){return rh(this,e,i,r,s,n)}getValues(e,i,r,s=0,n=!1){return Mn(this,e,i,r,s,n)}applyOptionsUpdate(e){Kh(this,e)}getImageOptions(){return Wh(this)}toUint8Array(e=null){return bn(this,e)}convertVox2Frac(e){return Dh(this,e)}convertFrac2Vox(e){return Th(this,e)}convertFrac2MM(e,i=!1){return Sh(this,e,i)}convertMM2Frac(e,i=!1){return Eh(this,e,i)}};function Ln(t){return typeof t=="number"&&Number.isFinite(t)}function u0(t,e=12){if(!Ln(t))return t;const r=1e-9*Math.max(1,Math.abs(t)),s=Number(t.toFixed(e));return Math.abs(t-s)<=r?s:t}function dt(t,e=12){return t.map(i=>Array.isArray(i)?dt(i,e):Ln(i)?u0(i,e):i)}function Ri(t,e){return typeof e=="number"?Number.isNaN(e)?"NaN":e===1/0?"infinity":e===-1/0?"-infinity":e:e}function Re(t){if(t!=null){if(Array.isArray(t))return t.slice();if(ArrayBuffer.isView(t))try{return Array.from(t)}catch{}if(typeof t=="object"){if(Array.isArray(t.data))return t.data.slice();if(t.buffer&&Array.isArray(t.buffer.data))return t.buffer.data.slice();const e=Object.keys(t).filter(i=>/^\d+$/.test(i)).map(i=>Number(i)).sort((i,r)=>i-r);if(e.length>0)try{return e.map(i=>t[String(i)])}catch{}for(const i of["_data","source","values","elements","items"])if(Array.isArray(t[i]))return t[i].slice()}try{const e=Array.from(t);if(Array.isArray(e))return e}catch{}}}function oi(t){if(!t||typeof t!="object")return t;const e={...t||{}};if((e.pts===void 0||e.pts===null)&&(e.vertices!==void 0||e.positions!==void 0||e.verts!==void 0)){const i=[e.vertices,e.positions,e.verts];for(const r of i){const s=Re(r);if(s&&s.length>0){e.pts=dt(s);break}}}else if(e.pts!=null&&!Array.isArray(e.pts)&&ArrayBuffer.isView(e.pts)){const i=Re(e.pts);i&&(e.pts=dt(i))}else Array.isArray(e.pts)&&(e.pts=dt(e.pts));if((e.tris===void 0||e.tris===null)&&(e.indices!==void 0||e.faces!==void 0||e.cells!==void 0)){const i=[e.indices,e.faces,e.cells];for(const r of i){const s=Re(r);if(s&&s.length>0){e.tris=s;break}}}else if(e.tris!=null&&!Array.isArray(e.tris)&&ArrayBuffer.isView(e.tris)){const i=Re(e.tris);i&&(e.tris=i)}if((e.rgba255===void 0||e.rgba255===null)&&(e.rgba!==void 0||e.color!==void 0||e.colors!==void 0)){const i=[e.rgba,e.color,e.colors];for(const r of i){const s=Re(r);if(s&&s.length>0){e.rgba255=s;break}}}else if(e.rgba255!=null&&!Array.isArray(e.rgba255)&&ArrayBuffer.isView(e.rgba255)){const i=Re(e.rgba255);i&&(e.rgba255=i)}if(e.offsetPt0!=null&&!Array.isArray(e.offsetPt0)){const i=Re(e.offsetPt0);i&&(e.offsetPt0=i)}return Array.isArray(e.nodes)&&(e.nodes=e.nodes.length>0&&typeof e.nodes[0]=="object"?e.nodes.map(i=>({...i})):e.nodes.slice()),Array.isArray(e.edges)&&(e.edges=e.edges.length>0&&typeof e.edges[0]=="object"?e.edges.map(i=>({...i})):e.edges.slice()),Array.isArray(e.layers)&&(e.layers=e.layers.map(i=>{if(!i||typeof i!="object")return i;const r={...i||{}};"colorMap"in r&&("colormap"in r||(r.colormap=r.colorMap),delete r.colorMap),"colorMapNegative"in r&&("colormapNegative"in r||(r.colormapNegative=r.colorMapNegative),delete r.colorMapNegative);for(const s of["global_min","global_max","cal_min","cal_max","cal_minNeg","cal_maxNeg"])if(typeof r[s]=="string"){const n=r[s];if(n==="infinity")r[s]=1/0;else if(n==="-infinity")r[s]=-1/0;else if(n==="NaN")r[s]=NaN;else{const a=Number(n);Number.isNaN(a)||(r[s]=a)}}if(r.values!=null&&!Array.isArray(r.values)){const s=Re(r.values);s&&(r.values=dt(s))}else Array.isArray(r.values)&&(r.values=dt(r.values));if(r.atlasValues!=null&&!Array.isArray(r.atlasValues)){const s=Re(r.atlasValues);s&&(r.atlasValues=s)}return r})),e}function m0(t){if(typeof t!="string")return;if(t.trim().length===0)return t;try{const i=JSON.parse(t);if(Array.isArray(i)&&i.length>0&&typeof i[0]=="object"&&i[0]!==null&&"0"in i[0]&&"1"in i[0])try{const n=ul(i);if(Array.isArray(n)){const a=n.map(o=>oi(o));return JSON.stringify(a,Ri)}}catch(n){console.warn("legacy-migrate: structured-clone deserialize failed",n)}if(!Array.isArray(i)){const n=["value","data","0"];for(const a of n)if(i&&Array.isArray(i[a])){const l=i[a].map(c=>oi(c));return JSON.stringify(l,Ri)}return t}const s=i.map(n=>oi(n));return JSON.stringify(s,Ri)}catch{return t}}function Vi(t){if(!t||typeof t!="object")return t;const e={...t||{}};if("colorMap"in e&&!("colormap"in e)&&(e.colormap=e.colorMap),"colorMapNegative"in e&&!("colormapNegative"in e)&&(e.colormapNegative=e.colorMapNegative),Array.isArray(e.imageOptionsArray)&&(e.imageOptionsArray=e.imageOptionsArray.map(i=>{if(!i||typeof i!="object")return i;const r={...i||{}};for(const s of["cal_min","cal_max","cal_minNeg","cal_maxNeg"])if(typeof r[s]=="string")if(r[s]==="infinity")r[s]=1/0;else if(r[s]==="-infinity")r[s]=-1/0;else if(r[s]==="NaN")r[s]=NaN;else{const n=Number(r[s]);Number.isNaN(n)||(r[s]=n)}if(r.colormap&&typeof r.colormap!="string"&&!Array.isArray(r.colormap)){const s=Re(r.colormap);s&&(r.colormap=s)}if(r.colormapNegative&&typeof r.colormapNegative!="string"&&!Array.isArray(r.colormapNegative)){const s=Re(r.colormapNegative);s&&(r.colormapNegative=s)}return r})),typeof e.meshesString=="string"&&e.meshesString.trim().length>0){const i=m0(e.meshesString);typeof i=="string"&&(e.meshesString=i)}if(e.labels&&!Array.isArray(e.labels))try{e.labels=Array.from(e.labels)}catch{}if(e.connectomes&&!Array.isArray(e.connectomes))try{e.connectomes=Array.from(e.connectomes)}catch{}if(e.encodedImageBlobs&&!Array.isArray(e.encodedImageBlobs))try{e.encodedImageBlobs=Array.from(e.encodedImageBlobs)}catch{}return e}function ot(t){if(t!==void 0)return t===null?null:Number.isFinite(t)?t:t===1/0?"infinity":t===-1/0?"-infinity":"NaN"}function Ne(t){if(t===void 0)return;if(t===null)return null;if(typeof t=="number")return t;if(t==="NaN")return NaN;if(t==="infinity")return 1/0;if(t==="-infinity")return-1/0;const e=Number(t);return Number.isNaN(e)?NaN:e}function p0(t){if(t!=null){if(t instanceof Float32Array)return t;if(Array.isArray(t))return new Float32Array(t);if(ArrayBuffer.isView(t))return new Float32Array(Array.from(t));try{return new Float32Array(Array.from(t))}catch{return}}}function g0(t){if(t!=null){if(t instanceof Uint32Array)return t;if(Array.isArray(t))return new Uint32Array(t);if(ArrayBuffer.isView(t))return new Uint32Array(Array.from(t));try{return new Uint32Array(Array.from(t))}catch{return}}}function A0(t){if(t!=null){if(t instanceof Uint8Array)return t;if(Array.isArray(t))return new Uint8Array(t);if(ArrayBuffer.isView(t))return new Uint8Array(Array.from(t));try{return new Uint8Array(Array.from(t))}catch{return}}}function As(t,e){if(typeof e!="function"&&typeof e!="symbol")return ArrayBuffer.isView(e)?e instanceof DataView?Array.from(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)):Array.from(e):e instanceof ArrayBuffer?Array.from(new Uint8Array(e)):e}var lr=class kn{static decodeOptsFromJSON(e){if(e==null)return;const i=s=>{if(s!==void 0){if(s===null)return null;if(typeof s=="number")return s;if(typeof s=="string")return s==="NaN"?NaN:s==="infinity"?1/0:s==="-infinity"?-1/0:s;if(Array.isArray(s))return s.map(n=>i(n));if(typeof s=="object"){const n={};for(const a of Object.keys(s))n[a]=i(s[a]);return n}return s}},r={};for(const s of Object.keys(e)){const n=e[s];n!==void 0&&(r[s]=i(n))}return r}static serializeDocument(e,i=!0,r=!0){const s={encodedImageBlobs:[],previewImageDataURL:e.previewImageDataURL??"",imageOptionsMap:new Map};s.sceneData={...e.scene?.sceneData??{}},s.opts=e.opts??{},s.labels=Array.isArray(e.labels)?e.labels.map(c=>{const h={...c||{}};return delete h.onClick,h}):[],s.customData=e.customData??"",s.completedMeasurements=e.completedMeasurements?e.completedMeasurements.slice():[],s.completedAngles=e.completedAngles?e.completedAngles.slice():[];const n=[],a=e.volumes??[];if(a.length)for(let c=0;c<a.length;c++){const h=a[c];let d=e.getImageOptions?e.getImageOptions(h):null;if(d===null?d={name:h?.name??"",colormap:h?._colormap??"gray",opacity:h?._opacity??1,cal_min:h?.cal_min??NaN,cal_max:h?.cal_max??NaN,trustCalMinMax:h?.trustCalMinMax??!0,percentileFrac:h?.percentileFrac??.02,ignoreZeroVoxels:h?.ignoreZeroVoxels??!1,imageType:h?.imageType??j.NII,frame4D:h?.frame4D??0,limitFrames4D:h?.limitFrames4D??NaN,url:h?.url??"",urlImageData:h?.urlImgData??"",cal_minNeg:h?.cal_minNeg??NaN,cal_maxNeg:h?.cal_maxNeg??NaN,colorbarVisible:h?.colorbarVisible??!0,colormapNegative:h?.colormapNegative??"",colormapType:h?.colormapType??0}:"imageType"in d||(d.imageType=j.NII),d.colormap=h.colormap,d.colormapLabel=h.colormapLabel,d.opacity=h.opacity,d.cal_max=h.cal_max??NaN,d.cal_min=h.cal_min??NaN,d.colormapNegative=h.colormapNegative??"",d.cal_minNeg=h.cal_minNeg??NaN,d.cal_maxNeg=h.cal_maxNeg??NaN,d.colorbarVisible=h.colorbarVisible??!0,d.colormapType=h.colormapType??0,n.push(d),i){const f=H.uint8tob64(h.toUint8Array());s.encodedImageBlobs.push(f)}s.imageOptionsMap.set(h.id,c)}s.imageOptionsArray=n;const o=[],l=e.meshes||[];s.connectomes=[];for(const c of l){if(!c||typeof c!="object")continue;if(c.type==="connectome"){try{s.connectomes.push(JSON.stringify(c.json()))}catch(f){F.warn("serializeDocument: failed connectome export",f)}continue}const h=(c.layers||[]).map(f=>{const u={name:f?.name,key:f?.key,url:f?.url,headers:f?.headers,opacity:f?.opacity,colormap:f?.colorMap??f?.colormap,colormapNegative:f?.colorMapNegative??f?.colormapNegative,colormapInvert:f?.colormapInvert,colormapLabel:f?.colormapLabel,useNegativeCmap:f?.useNegativeCmap,global_min:ot(f?.global_min),global_max:ot(f?.global_max),cal_min:ot(f?.cal_min),cal_max:ot(f?.cal_max),cal_minNeg:ot(f?.cal_minNeg),cal_maxNeg:ot(f?.cal_maxNeg),isAdditiveBlend:f?.isAdditiveBlend,frame4D:f?.frame4D,nFrame4D:f?.nFrame4D,outlineBorder:f?.outlineBorder,isTransparentBelowCalMin:f?.isTransparentBelowCalMin,colormapType:f?.colormapType,base64:f?.base64,colorbarVisible:f?.colorbarVisible,showLegend:f?.showLegend};if(f?.values!=null){const m=Array.isArray(f.values)?f.values.slice():Array.from(f.values||[]);u.values=m.map(p=>{const g=Number(p);return Number.isFinite(g)?Math.round(g*1e12)/1e12:g})}return f?.atlasValues!=null&&(u.atlasValues=Array.isArray(f.atlasValues)?f.atlasValues.slice():Array.from(f.atlasValues||[])),Array.isArray(f?.labels)?u.labels=f.labels.map(m=>({...m||{}})):f?.labels!=null&&(u.labels=Array.from(f.labels||[])),u}),d={...Object.assign({},c||{}),rgba255:Array.from(c.rgba255||[]),layers:h,edges:Array.isArray(c?.edges)?c.edges.map(f=>({...f||{}})):[],nodes:Array.isArray(c?.nodes)?c.nodes.map(f=>({...f||{}})):c?.nodes,offsetPt0:Array.isArray(c?.offsetPt0)?[...c.offsetPt0]:c?.offsetPt0};Array.isArray(c.offsetPt0)&&c.offsetPt0.length>0&&(d.offsetPt0=Array.isArray(c.offsetPt0)?[...c.offsetPt0]:c.offsetPt0,Array.isArray(c.fiberGroupColormap)&&(d.fiberGroupColormap=[...c.fiberGroupColormap]),Array.isArray(c.fiberColor)&&(d.fiberColor=Array.from(c.fiberColor)),d.fiberDither=c.fiberDither,d.fiberRadius=c.fiberRadius,d.colormap=c.colormap),o.push(d)}try{s.meshesString=JSON.stringify(o,As)}catch(c){F.warn("serializeDocument: JSON.stringify failed for meshes",c);const h=[];for(let d=0;d<o.length;d++)try{h.push(JSON.stringify(o[d],As))}catch(f){F.error("serializeDocument: failed to serialize mesh at index",d,f,o[d]),h.push(JSON.stringify({name:o[d]?.name??"unknown",id:o[d]?.id??null}))}s.meshesString=`[${h.join(",")}]`}return r&&e.drawBitmap?s.encodedDrawingBlob=H.uint8tob64(e.drawBitmap):s.encodedDrawingBlob=e.encodedDrawingBlob??"",s.title=e.title??"untitled",s.customData=e.customData??"",s.labels=Array.isArray(e.labels)?e.labels.map(c=>{const h={...c||{}};return delete h.onClick,h}):[],s.completedMeasurements=(e.completedMeasurements||[]).map(c=>({...c,startMM:Array.isArray(c.startMM)?[...c.startMM]:c.startMM,endMM:Array.isArray(c.endMM)?[...c.endMM]:c.endMM})),s.completedAngles=(e.completedAngles||[]).map(c=>({...c,firstLineMM:{start:Array.isArray(c.firstLineMM?.start)?[...c.firstLineMM.start]:c.firstLineMM?.start,end:Array.isArray(c.firstLineMM?.end)?[...c.firstLineMM.end]:c.firstLineMM?.end},secondLineMM:{start:Array.isArray(c.secondLineMM?.start)?[...c.secondLineMM.start]:c.secondLineMM?.start,end:Array.isArray(c.secondLineMM?.end)?[...c.secondLineMM.end]:c.secondLineMM?.end}})),s.sceneData=s.sceneData??{...e.scene?.sceneData??{}},s.opts=s.opts??(e.opts?{...e.opts}:{}),s}static async rehydrateImages(e){const i=[],r=await Vi(e),s=r.encodedImageBlobs??[],n=r.imageOptionsArray??[];for(let a=0;a<n.length;a++){const o={...n[a]||{}};try{const l=s[a];if(!l){F.debug("NVSerializer.rehydrateImages: no blob for index",a);continue}const c=await H.b64toUint8(l);if(!c){F.warn("NVSerializer.rehydrateImages: b64toUint8 returned empty for index",a);continue}const h=o.name??o.url??`image-${a}`;let d=o.colormap??o.colorMap??"";typeof d!="string"&&(typeof o.colorMap=="string"?d=o.colorMap:d="");const f=o.opacity??1,u=o.pairedImgData?typeof o.pairedImgData=="string"?(await H.b64toUint8(o.pairedImgData)).buffer:o.pairedImgData:null,m=Ne(o.cal_min),p=Ne(o.cal_max),g=o.trustCalMinMax??!0,x=o.percentileFrac??.02,A=o.ignoreZeroVoxels??!1,y=o.useQFormNotSForm??!1,v=o.colormapNegative??"",b=o.frame4D??0,w="imageType"in o&&typeof o.imageType=="number"?o.imageType:o.imageType??j.UNKNOWN,C=Ne(o.cal_minNeg),M=Ne(o.cal_maxNeg),T=o.colorbarVisible??!0,E=o.colormapLabel??null,I=o.colormapType??0,S=o.zarrData??null;console.log(`Image ${a} buffer length: ${c.byteLength}`),!c.some(R=>R!==0)&&console.error(`CRITICAL: Base64 decoding for ${h} resulted in an all-zero array!`);const B=c.slice().buffer,V=await Me.new(B,h,d,f,u,m,p,g,x,A,y,v,b,w,C,M,T,E,I,S);i.push(V)}catch(l){F.warn("NVSerializer.rehydrateImages: failed for index",a,l)}}return i}static async rehydrateMeshes(e,i,r=!1){const s=[],a=(await Vi(e)).meshesString??"[]";let o=[];try{o=JSON.parse(a)}catch(l){console.warn("NVSerializer.rehydrateMeshes: failed to parse meshesString",l),o=[]}for(let l=0;l<o.length;l++){let c=o[l]||{};try{if(c=oi(c),Array.isArray(c.layers)){for(const g of c.layers)if(g){if("colorMap"in g&&!("colormap"in g)&&(g.colormap=g.colorMap,delete g.colorMap),"colorMapNegative"in g&&!("colormapNegative"in g)&&(g.colormapNegative=g.colorMapNegative,delete g.colorMapNegative),g.global_min=Ne(g.global_min),g.global_max=Ne(g.global_max),g.cal_min=Ne(g.cal_min),g.cal_max=Ne(g.cal_max),g.cal_minNeg=Ne(g.cal_minNeg),g.cal_maxNeg=Ne(g.cal_maxNeg),g.values!=null&&!Array.isArray(g.values))try{g.values=Array.from(g.values)}catch{}if(g.atlasValues!=null&&!Array.isArray(g.atlasValues))try{g.atlasValues=Array.from(g.atlasValues)}catch{}}}const h=A0(c.rgba255)??new Uint8Array([255,255,255,255]),d=p0(c.pts);let f=g0(c.tris);Array.isArray(c.nodes)&&(c.nodes=c.nodes.length>0&&typeof c.nodes[0]=="object"?c.nodes.map(g=>({...g})):c.nodes.slice()),Array.isArray(c.edges)&&(c.edges=c.edges.length>0&&typeof c.edges[0]=="object"?c.edges.map(g=>({...g})):c.edges.slice());const u=c.id!==void 0?c.id:null;if(!i){s.push(c);continue}Array.isArray(c.offsetPt0)&&c.offsetPt0.length>0&&(f=new Uint32Array(c.offsetPt0),h&&(h[3]=0));const m=new Uint8Array(Array.isArray(h)?h:Array.from(h)),p=new mt(d,f,c.name,m,c.opacity,c.visible,i,c.connectome,c.dpg,c.dps,c.dpv);if(u!==null&&(p.id=u),Array.isArray(c.offsetPt0)&&c.offsetPt0.length>0&&(p.fiberGroupColormap=c.fiberGroupColormap,p.fiberColor=c.fiberColor?c.fiberColor:void 0,p.fiberDither=c.fiberDither,p.fiberRadius=c.fiberRadius,p.colormap=c.colormap),p.meshShaderIndex=c.meshShaderIndex,p.layers=c.layers||[],r)try{p.updateMesh(i)}catch(g){console.warn("NVSerializer.rehydrateMeshes: updateMesh failed for idx",l,g)}s.push(p)}catch(h){console.warn("NVSerializer.rehydrateMeshes: failed idx",l,h),s.push(c)}}try{return Array.isArray(s)?s:(console.warn("NVSerializer.rehydrateMeshes: unexpected non-array output, coercing to array",{typeofOut:typeof s,isArray:Array.isArray(s),outPreview:s&&(typeof s=="object"?Object.keys(s).slice(0,10):s)}),s?[s]:[])}catch(l){return console.error("NVSerializer.rehydrateMeshes: final-return error",l),[]}}static async deserializeDocument(e){const i=await Vi(e),r=new St;Object.assign(r.data,{...i,imageOptionsArray:i.imageOptionsArray??[],encodedImageBlobs:i.encodedImageBlobs??[],labels:i.labels??[],meshOptionsArray:i.meshOptionsArray??[],connectomes:i.connectomes??[],encodedDrawingBlob:i.encodedDrawingBlob??"",previewImageDataURL:i.previewImageDataURL??"",customData:i.customData??"",title:i.title??"untitled"});const s=kn.decodeOptsFromJSON(i.opts);r.data.opts={...ke,...s||{}},r.data.opts.meshThicknessOn2D==="infinity"&&(r.data.opts.meshThicknessOn2D=1/0),r.scene.sceneData={...mi,...i.sceneData||{}};const n=i.sceneData||{};return n.clipPlane&&!n.clipPlanes&&(r.scene.sceneData.clipPlanes=[n.clipPlane]),n.clipPlaneDepthAziElev&&!n.clipPlaneDepthAziElevs&&(r.scene.sceneData.clipPlaneDepthAziElevs=[n.clipPlaneDepthAziElev]),i.completedMeasurements&&(r.completedMeasurements=i.completedMeasurements.map(a=>({...a,startMM:Ve(a.startMM),endMM:Ve(a.endMM)}))),i.completedAngles&&(r.completedAngles=i.completedAngles.map(a=>({...a,firstLineMM:{start:Ve(a.firstLineMM.start),end:Ve(a.firstLineMM.end)},secondLineMM:{start:Ve(a.secondLineMM.start),end:Ve(a.secondLineMM.end)}}))),r.data.connectomes=i.connectomes??[],r.data.encodedDrawingBlob=i.encodedDrawingBlob??"",r.data.previewImageDataURL=i.previewImageDataURL??"",r}},xs=lr,x0=(t=>(t[t.AXIAL=0]="AXIAL",t[t.CORONAL=1]="CORONAL",t[t.SAGITTAL=2]="SAGITTAL",t[t.MULTIPLANAR=3]="MULTIPLANAR",t[t.RENDER=4]="RENDER",t))(x0||{}),v0=(t=>(t[t.PEN=0]="PEN",t[t.RECTANGLE=1]="RECTANGLE",t[t.ELLIPSE=2]="ELLIPSE",t))(v0||{}),w0=(t=>(t[t.NEVER=0]="NEVER",t[t.ALWAYS=1]="ALWAYS",t[t.AUTO=2]="AUTO",t))(w0||{}),y0=(t=>(t[t.AUTO=0]="AUTO",t[t.COLUMN=1]="COLUMN",t[t.GRID=2]="GRID",t[t.ROW=3]="ROW",t))(y0||{}),On=(t=>(t[t.none=0]="none",t[t.contrast=1]="contrast",t[t.measurement=2]="measurement",t[t.pan=3]="pan",t[t.slicer3D=4]="slicer3D",t[t.callbackOnly=5]="callbackOnly",t[t.roiSelection=6]="roiSelection",t[t.angle=7]="angle",t[t.crosshair=8]="crosshair",t[t.windowing=9]="windowing",t))(On||{}),ke={textHeight:-1,fontSizeScaling:.4,fontMinPx:13,colorbarHeight:.05,colorbarWidth:-1,showColorbarBorder:!0,crosshairWidth:1,crosshairWidthUnit:"voxels",crosshairGap:0,rulerWidth:4,show3Dcrosshair:!1,backColor:[0,0,0,1],crosshairColor:[1,0,0,1],fontColor:[.5,.5,.5,1],selectionBoxColor:[1,1,1,.5],clipPlaneColor:[.7,0,.7,.5],isClipPlanesCutaway:!1,isClipAllVolumes:!1,paqdUniforms:[.3,.5,.5,1],rulerColor:[1,0,0,.8],colorbarMargin:.05,trustCalMinMax:!0,clipPlaneHotKey:"KeyC",cycleClipPlaneHotKey:"KeyP",viewModeHotKey:"KeyV",doubleTouchTimeout:500,longTouchTimeout:1e3,keyDebounceTime:50,isNearestInterpolation:!1,isResizeCanvas:!0,atlasOutline:0,atlasActiveIndex:0,isRuler:!1,isColorbar:!1,isOrientCube:!1,tileMargin:0,multiplanarPadPixels:0,multiplanarForceRender:!1,multiplanarEqualSize:!1,multiplanarShowRender:2,isRadiologicalConvention:!1,meshThicknessOn2D:1/0,dragMode:1,dragModePrimary:8,mouseEventConfig:void 0,touchEventConfig:void 0,yoke3Dto2DZoom:!1,isDepthPickMesh:!1,isCornerOrientationText:!1,isOrientationTextVisible:!0,showAllOrientationMarkers:!1,heroImageFraction:0,heroSliceType:4,sagittalNoseLeft:!1,isSliceMM:!1,isV1SliceShader:!1,forceDevicePixelRatio:0,logLevel:"info",loadingText:"loading ...",isForceMouseClickToVoxelCenters:!1,dragAndDropEnabled:!0,drawingEnabled:!1,penValue:1,penType:0,floodFillNeighbors:6,isFilledPen:!1,thumbnail:"",maxDrawUndoBitmaps:8,sliceType:3,meshXRay:0,isAntiAlias:null,limitFrames4D:NaN,isAdditiveBlend:!1,showLegend:!0,legendBackgroundColor:[.3,.3,.3,.5],legendTextColor:[1,1,1,1],multiplanarLayout:0,renderOverlayBlend:1,sliceMosaicString:"",centerMosaic:!1,penSize:1,interactive:!0,clickToSegment:!1,clickToSegmentRadius:3,clickToSegmentBright:!0,clickToSegmentAutoIntensity:!1,clickToSegmentIntensityMax:NaN,clickToSegmentIntensityMin:NaN,clickToSegmentPercent:0,clickToSegmentMaxDistanceMM:Number.POSITIVE_INFINITY,clickToSegmentIs2D:!1,selectionBoxLineThickness:4,selectionBoxIsOutline:!1,scrollRequiresFocus:!1,showMeasureUnits:!0,measureTextJustify:"center",measureTextColor:[1,0,0,1],measureLineColor:[1,0,0,1],measureTextHeight:.06,isAlphaClipDark:!1,gradientOrder:1,gradientOpacity:0,renderSilhouette:0,gradientAmount:0,invertScrollDirection:!1,is2DSliceShader:!1,bounds:null,showBoundsBorder:!1,boundsBorderColor:[1,1,1,1],windowingGainFactor:2,zarrCacheSize:1e3,zarrPrefetchRings:10,smoothDrawing:0},Nm={},mi={gamma:1,azimuth:110,elevation:10,crosshairPos:k(.5,.5,.5),clipPlanes:[[0,0,0,0]],clipPlaneDepthAziElevs:[[2,0,0]],volScaleMultiplier:1,pan2Dxyzmm:ae(0,0,0,1)},St=class cr{constructor(){D(this,"data",{title:"Untitled document",imageOptionsArray:[],meshOptionsArray:[],opts:{...ke},previewImageDataURL:"",labels:[],encodedImageBlobs:[],encodedDrawingBlob:""}),D(this,"scene"),D(this,"volumes",[]),D(this,"meshDataObjects"),D(this,"meshes",[]),D(this,"drawBitmap",null),D(this,"imageOptionsMap",new Map),D(this,"meshOptionsMap",new Map),D(this,"completedMeasurements",[]),D(this,"completedAngles",[]),D(this,"_optsProxy",null),D(this,"_optsChangeCallback",null),this.scene={onAzimuthElevationChange:()=>{},onZoom3DChange:()=>{},sceneData:{...mi,pan2Dxyzmm:ae(0,0,0,1),crosshairPos:k(.5,.5,.5)},get renderAzimuth(){return this.sceneData.azimuth},set renderAzimuth(e){this.sceneData.azimuth=e,this.onAzimuthElevationChange&&this.onAzimuthElevationChange(this.sceneData.azimuth,this.sceneData.elevation)},get renderElevation(){return this.sceneData.elevation},set renderElevation(e){this.sceneData.elevation=e,this.onAzimuthElevationChange&&this.onAzimuthElevationChange(this.sceneData.azimuth,this.sceneData.elevation)},get volScaleMultiplier(){return this.sceneData.volScaleMultiplier},set volScaleMultiplier(e){this.sceneData.volScaleMultiplier=e,this.onZoom3DChange(e)},get crosshairPos(){return this.sceneData.crosshairPos},set crosshairPos(e){this.sceneData.crosshairPos=e},get clipPlane(){return this.sceneData.clipPlanes[0]??[]},set clipPlane(e){this.sceneData.clipPlanes[0]=e},get clipPlanes(){return this.sceneData.clipPlanes},set clipPlanes(e){this.sceneData.clipPlanes=e},get clipPlaneDepthAziElevs(){return this.sceneData.clipPlaneDepthAziElevs},set clipPlaneDepthAziElevs(e){this.sceneData.clipPlaneDepthAziElevs=e},get pan2Dxyzmm(){return this.sceneData.pan2Dxyzmm},set pan2Dxyzmm(e){this.sceneData.pan2Dxyzmm=e},get gamma(){return this.sceneData.gamma},set gamma(e){this.sceneData.gamma=e}}}get title(){return this.data.title}get previewImageDataURL(){return this.data.previewImageDataURL}set previewImageDataURL(e){this.data.previewImageDataURL=e}set title(e){this.data.title=e}get imageOptionsArray(){return this.data.imageOptionsArray}get encodedImageBlobs(){return this.data.encodedImageBlobs}get encodedDrawingBlob(){return this.data.encodedDrawingBlob}get opts(){return this._optsProxy||this._createOptsProxy(),this._optsProxy}set opts(e){this.data.opts={...e},this._optsProxy=null}get labels(){return this.data.labels}set labels(e){this.data.labels=e}get customData(){return this.data.customData}set customData(e){this.data.customData=e}hasImage(e){return this.volumes.find(i=>i.id===e.id)!==void 0}hasImageFromUrl(e){return this.data.imageOptionsArray.find(i=>i.url===e)!==void 0}addImageOptions(e,i){if(!this.hasImage(e)&&!i.name)if(i.url){const s=/^(?:[a-z+]+:)?\/\//i.test(i.url)?new URL(i.url):new URL(i.url,window.location.href);i.name=s.pathname.split("/").pop(),i.name.toLowerCase().endsWith(".gz")&&(i.name=i.name.slice(0,-3)),i.name.toLowerCase().endsWith(".nii")||(i.name+=".nii")}else i.name="untitled.nii";i.imageType=j.NII,this.data.imageOptionsArray.push(i),this.imageOptionsMap.set(e.id,this.data.imageOptionsArray.length-1)}removeImage(e){if(this.imageOptionsMap.has(e.id)){const i=this.imageOptionsMap.get(e.id);this.data.imageOptionsArray.length>i&&this.data.imageOptionsArray.splice(i,1),this.imageOptionsMap.delete(e.id)}this.volumes=this.volumes.filter(i=>i.id!==e.id)}async fetchLinkedData(){if(this.data.encodedImageBlobs=[],!!this.imageOptionsArray?.length){for(const e of this.imageOptionsArray)if(e.url)try{const i=await fetch(e.url);if(!i.ok){console.warn("Failed to fetch image:",e.url);continue}const r=await i.arrayBuffer(),s=new Uint8Array(r),n=H.uint8tob64(s);this.data.encodedImageBlobs.push(n),console.info("fetch linked data fetched from ",e.url)}catch(i){console.warn(`Failed to fetch/encode image from ${e.url}:`,i)}}}getImageOptions(e){return this.imageOptionsMap.has(e.id)?this.data.imageOptionsArray[this.imageOptionsMap.get(e.id)]:null}json(e=!0,i=!0){return lr.serializeDocument(this,e,i)}async download(e,i,r={embedImages:!0}){const s=this.json(r.embedImages),n=JSON.stringify(s),a=i?"application/gzip":"application/json",o=i?await H.compressStringToArrayBuffer(n):n;H.download(o,e,a)}static async loadFromUrl(e){const r=await(await fetch(e)).arrayBuffer();let s;if(H.isArrayBufferCompressed(r)){const n=await H.decompressArrayBuffer(r);s=JSON.parse(n)}else{const n=new TextDecoder;s=JSON.parse(n.decode(r))}return cr.loadFromJSON(s)}static async loadFromFile(e){const i=await H.readFileAsync(e);let r;H.isArrayBufferCompressed(i)?r=await H.decompressArrayBuffer(i):r=new TextDecoder().decode(i);const s=JSON.parse(r);return cr.loadFromJSON(s)}static async loadFromJSON(e){return await lr.deserializeDocument(e)}setOptsChangeCallback(e){this._optsChangeCallback=e,this._optsProxy=null}removeOptsChangeCallback(){this._optsChangeCallback=null,this._optsProxy=null}_createOptsProxy(){const e=this.data.opts;this._optsProxy=new Proxy(e,{set:(i,r,s)=>{const n=i[r];return n!==s&&(i[r]=s,this._optsChangeCallback&&typeof r=="string"&&r in ke&&this._optsChangeCallback(r,s,n)),!0},get:(i,r)=>i[r]})}},vs=(t,e)=>{const i=Math.floor(Math.log(t)/Math.log(10)),r=t/Math.pow(10,i);let s;return e?r<1.5?s=1:r<3?s=2:r<7?s=5:s=10:r<=1?s=1:r<=2?s=2:r<=5?s=5:s=10,s*Math.pow(10,i)};function b0(t){return new Promise((e,i)=>{let r;t instanceof File?r=Promise.resolve(t):r=new Promise((s,n)=>{t.file(s,n)}),r.then(s=>{const n=new FileReader;n.onload=()=>{typeof n.result=="string"?e(n.result):i(new Error("Expected a string from FileReader.result"))},n.onerror=()=>{i(n.error??new Error("Unknown FileReader error"))},n.readAsDataURL(s)}).catch(s=>i(s))})}function C0(t){const e=t.hdr.dims,i=t.permRAS,r=e[1]*e[2]*e[3],s=new Int16Array(r),n=[0,0,0];for(let u=0;u<3;u++)for(let m=0;m<3;m++)Math.abs(i[u])-1===m&&(n[m]=u*Math.sign(i[u]));let a=1;const o=[1,1,1],l=[!1,!1,!1];for(let u=0;u<n.length;u++)for(let m=0;m<n.length;m++)Math.abs(n[m])===u&&(o[m]=a,(n[m]<0||Object.is(n[m],-0))&&(l[m]=!0),a*=e[m+1]);let c=H.range(0,e[1]-1,1);l[0]&&(c=H.range(e[1]-1,0,-1));for(let u=0;u<e[1];u++)c[u]*=o[0];let h=H.range(0,e[2]-1,1);l[1]&&(h=H.range(e[2]-1,0,-1));for(let u=0;u<e[2];u++)h[u]*=o[1];let d=H.range(0,e[3]-1,1);l[2]&&(d=H.range(e[3]-1,0,-1));for(let u=0;u<e[3];u++)d[u]*=o[2];let f=0;for(let u=0;u<e[3];u++)for(let m=0;m<e[2];m++)for(let p=0;p<e[1];p++)s[c[p]+h[m]+d[u]]=t.img[f],f++;return s}function M0(t){const e=[5960464477539063e-23,152587890625e-16,.00390625,1];return(t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3])/255}function ws(t,e){return t.scl_slope===0&&(t.scl_slope=1),e*t.scl_slope+t.scl_inter}function wt(t,e,i=4){const r=vs(e-t,!1),s=vs(r/(i-1),!0),n=Math.floor(t/s)*s,a=Math.ceil(e/s)*s;return[s,n,a,n===t&&a===e]}function ys(t,e){let i=wt(t,e,3);return i[3]||(i=wt(t,e,5)),i[3]||(i=wt(t,e,4)),i[3]||(i=wt(t,e,3)),i[3]||(i=wt(t,e,5)),[i[0],i[1],i[2]]}function qe(t){return t*(Math.PI/180)}function Pi(t,e,i,r){let s=-t,n=-e;return isFinite(i)&&isFinite(r)&&(s=i,n=r),s>n&&([s,n]=[n,s]),[s,n]}function he(t,e=[0,1,2]){const i=se();return i[0]=t[e[0]],i[1]=t[e[1]],i[2]=t[e[2]],i}function D0(t){const e=ae(1,0,0,0),i=Xe();return ve(i,e,t),i[0]}function T0(t,e,i,r){const s=ae(t,e,i,1),n=de(r);Se(n,n),s[0]=s[0]*2-1,s[1]=s[1]*2-1,s[2]=s[2]*2-1;const a=Xe();return ve(a,s,n),a[3]===0||(a[0]/=a[3],a[1]/=a[3],a[2]/=a[3]),a}function Br(t,e=!0){const{volumes:i,meshes:r,volumeObject3D:s}=t;let n=k(0,0,0),a=k(0,0,0);if(i.length>0){if(!s)throw new Error("volumeObject3D undefined");n=k(s.extentsMin[0],s.extentsMin[1],s.extentsMin[2]),a=k(s.extentsMax[0],s.extentsMax[1],s.extentsMax[2]),e||(n=k(i[0].extentsMinOrtho[0],i[0].extentsMinOrtho[1],i[0].extentsMinOrtho[2]),a=k(i[0].extentsMaxOrtho[0],i[0].extentsMaxOrtho[1],i[0].extentsMaxOrtho[2]))}if(r.length>0){if(i.length<1){const l=r[0].extentsMin,c=r[0].extentsMax;n=k(l[0],l[1],l[2]),a=k(c[0],c[1],c[2])}for(let l=0;l<r.length;l++){const c=r[l].extentsMin,h=r[l].extentsMax,d=k(c[0],c[1],c[2]);ur(n,n,d);const f=k(h[0],h[1],h[2]);mr(a,a,f)}}const o=se();return ne(o,a,n),[n,a,o]}function zn(t,e){const{volumes:i,meshes:r,volumeObject3D:s,volIdx:n=0,isSliceMM:a=!1}=e;if(i.length<1){const o=k(.1,.5,.5),[l,c,h]=Br({volumes:i,meshes:r,volumeObject3D:s},a);return o[0]=(t[0]-l[0])/h[0],o[1]=(t[1]-l[1])/h[1],o[2]=(t[2]-l[2])/h[2],isFinite(o[0])||(o[0]=.5),isFinite(o[1])||(o[1]=.5),isFinite(o[2])||(o[2]=.5),o}return i[n].convertMM2Frac(t,a)}function wi(t,e){const{volumes:i,meshes:r,volumeObject3D:s,volIdx:n=0,isSliceMM:a=!1}=e,o=ae(t[0],t[1],t[2],1);if(i.length>0)return i[n].convertFrac2MM(t,a);{const[l,c]=Br({volumes:i,meshes:r,volumeObject3D:s},a),h=(d,f,u)=>d*(1-u)+f*u;o[0]=h(l[0],c[0],t[0]),o[1]=h(l[1],c[1],t[1]),o[2]=h(l[2],c[2],t[2])}return o}function S0(t,e,i=0){return e[i].convertVox2Frac(t)}function E0(t,e,i=0){return e.length<=i?k(0,0,0):e[i].convertFrac2Vox(t)}function I0(t,e){return H.vox2mm(t,e)}function F0(t,e){return e===1?he(t,[0,2,1]):e===2?he(t,[1,2,0]):t}function Ur(t,e,i,r,s){const{volumes:n,meshes:a,volumeObject3D:o,isSliceMM:l=!1,restrict0to1:c=!0}=s,h=k(-1,-1,-1),d=i[r],f=d.axCorSag;if(f>2)return h;const u=d.leftTopWidthHeight.slice();let m=!1;u[2]<0&&(m=!0,u[0]+=u[2],u[2]=-u[2]);let p=(t-u[0])/u[2];m&&(p=1-p);const g=1-(e-u[1])/u[3];if(p<0||p>1||g<0||g>1||d.AxyzMxy.length<4)return h;let x=k(0,0,0);x[0]=d.leftTopMM[0]+p*d.fovMM[0],x[1]=d.leftTopMM[1]+g*d.fovMM[1];const A=d.AxyzMxy;x[2]=A[2]+A[4]*(x[1]-A[1])-A[3]*(x[0]-A[0]),f===1&&(x=he(x,[0,2,1])),f===2&&(x=he(x,[2,0,1]));const y=zn(x,{volumes:n,meshes:a,volumeObject3D:o,isSliceMM:l});return c&&(y[0]<0||y[0]>1||y[1]<0||y[1]>1||y[2]<0||y[2]>1)?h:y}function B0(t,e,i,r){const{volumes:s,meshes:n,volumeObject3D:a,isSliceMM:o=!1,forceSlice:l=-1}=r;for(let c=0;c<i.length;c++){let h=c;l>=0&&(h=l);const d=i[h];if(d.axCorSag>2)continue;const u=d.leftTopWidthHeight;if(t<u[0]||e<u[1]||t>u[0]+u[2]||e>u[1]+u[3])continue;const m=Ur(t,e,i,h,{volumes:s,meshes:n,volumeObject3D:a,isSliceMM:o,restrict0to1:!1});if(m[0]<0)continue;const p=wi(m,{volumes:s,meshes:n,volumeObject3D:a,isSliceMM:o});return ae(p[0],p[1],p[2],h)}return ae(NaN,NaN,NaN,NaN)}function U0(t,e,i){const{volumes:r,meshes:s,volumeObject3D:n,isSliceMM:a=!1}=i;for(let o=0;o<e.length;o++){const l=Ur(t[0],t[1],e,o,{volumes:r,meshes:s,volumeObject3D:n,isSliceMM:a});if(l[0]>=0)return l}return k(-1,-1,-1)}function R0(t,e,i){const{volumes:r,meshes:s,volumeObject3D:n,isSliceMM:a=!1,sliceType:o}=i,l=wi(t,{volumes:r,meshes:s,volumeObject3D:n,isSliceMM:a});let c={index:-1,distance:1/0};for(let h=0;h<e.length;h++){const d=e[h],f=d.axCorSag;if(f>2||d.AxyzMxy.length<4)continue;let u=k(l[0],l[1],l[2]);f===1&&(u=he(u,[0,2,1])),f===2&&(u=he(u,[1,2,0]));const m=d.AxyzMxy,p=m[2]+m[4]*(u[1]-m[1])-m[3]*(u[0]-m[0]),g=Math.abs(u[2]-p),x=o===3?1:.1;if(g<c.distance&&(c={index:h,distance:g}),g<=x){const A=(u[0]-d.leftTopMM[0])/d.fovMM[0],y=(u[1]-d.leftTopMM[1])/d.fovMM[1];if(A>=0&&A<=1&&y>=0&&y<=1){const v=d.leftTopWidthHeight.slice();let b=!1;v[2]<0&&(b=!0,v[0]+=v[2],v[2]=-v[2]);let w=A;b&&(w=1-A);const C=1-y,M=v[0]+w*v[2],T=v[1]+C*v[3];return[M,T]}}}if(c.index>=0&&c.distance<2){const h=c.index,d=e[h],f=d.axCorSag;let u=k(l[0],l[1],l[2]);f===1&&(u=he(u,[0,2,1])),f===2&&(u=he(u,[1,2,0]));const m=d.AxyzMxy;u[2]=m[2]+m[4]*(u[1]-m[1])-m[3]*(u[0]-m[0]);const p=(u[0]-d.leftTopMM[0])/d.fovMM[0],g=(u[1]-d.leftTopMM[1])/d.fovMM[1];if(p>=-.1&&p<=1.1&&g>=-.1&&g<=1.1){const x=Math.max(0,Math.min(1,p)),A=Math.max(0,Math.min(1,g)),y=d.leftTopWidthHeight.slice();let v=!1;y[2]<0&&(v=!0,y[0]+=y[2],y[2]=-y[2]);let b=x;v&&(b=1-x);const w=1-A,C=y[0]+b*y[2],M=y[1]+w*y[3];return[C,M]}}return null}function V0(t,e,i){const{volumes:r,meshes:s,volumeObject3D:n,isSliceMM:a=!1,preferredSliceType:o}=i,l=wi(t,{volumes:r,meshes:s,volumeObject3D:n,isSliceMM:a});let c={index:-1,distance:1/0};for(let h=0;h<e.length;h++){const d=e[h],f=d.axCorSag;if(f>2||d.AxyzMxy.length<4||o!==void 0&&f!==o)continue;let u=k(l[0],l[1],l[2]);f===1&&(u=he(u,[0,2,1])),f===2&&(u=he(u,[1,2,0]));const m=d.AxyzMxy,p=m[2]+m[4]*(u[1]-m[1])-m[3]*(u[0]-m[0]),g=Math.abs(u[2]-p);if(g<c.distance&&(c={index:h,distance:g}),g<=.1){const A=(u[0]-d.leftTopMM[0])/d.fovMM[0],y=(u[1]-d.leftTopMM[1])/d.fovMM[1];if(A>=0&&A<=1&&y>=0&&y<=1){const v=d.leftTopWidthHeight.slice();let b=!1;v[2]<0&&(b=!0,v[0]+=v[2],v[2]=-v[2]);let w=A;b&&(w=1-A);const C=1-y,M=v[0]+w*v[2],T=v[1]+C*v[3];return{pos:[M,T],tileIndex:h}}}}if(c.index>=0&&c.distance<2){const h=c.index,d=e[h],f=d.axCorSag;let u=k(l[0],l[1],l[2]);f===1&&(u=he(u,[0,2,1])),f===2&&(u=he(u,[1,2,0]));const m=d.AxyzMxy;u[2]=m[2]+m[4]*(u[1]-m[1])-m[3]*(u[0]-m[0]);const p=(u[0]-d.leftTopMM[0])/d.fovMM[0],g=(u[1]-d.leftTopMM[1])/d.fovMM[1];if(p>=-.1&&p<=1.1&&g>=-.1&&g<=1.1){const x=Math.max(0,Math.min(1,p)),A=Math.max(0,Math.min(1,g)),y=d.leftTopWidthHeight.slice();let v=!1;y[2]<0&&(v=!0,y[0]+=y[2],y[2]=-y[2]);let b=x;v&&(b=1-x);const w=1-A,C=y[0]+b*y[2],M=y[1]+w*y[3];return{pos:[C,M],tileIndex:h}}}return null}var P0=function(t,e,i){const r=t.createShader(t.VERTEX_SHADER);t.shaderSource(r,e),t.compileShader(r);const s=t.createShader(t.FRAGMENT_SHADER);t.shaderSource(s,i),t.compileShader(s);const n=t.createProgram();if(t.attachShader(n,r),t.attachShader(n,s),t.linkProgram(n),!t.getProgramParameter(n,t.LINK_STATUS))throw console.log(t.getProgramInfoLog(n)),t.getShaderParameter(r,t.COMPILE_STATUS)||console.log("Vertex shader compilation error:",t.getShaderInfoLog(r)),t.getShaderParameter(s,t.COMPILE_STATUS)||console.log("Fragment shader compilation error:",t.getShaderInfoLog(s)),F.error(t.getProgramInfoLog(n)),new Error("Shader failed to link, see console for log");return n},ee=class{constructor(t,e,i){D(this,"program"),D(this,"uniforms",{}),D(this,"isMatcap"),D(this,"isCrosscut"),this.program=P0(t,e,i);const r=/uniform[^;]+[ ](\w+);/g,s=/uniform[^;]+[ ](\w+);/,n=e.match(r),a=i.match(r);n&&n.forEach(o=>{const l=o.match(s);this.uniforms[l[1]]=-1}),a&&a.forEach(o=>{const l=o.match(s);this.uniforms[l[1]]=-1});for(const o in this.uniforms)this.uniforms[o]=t.getUniformLocation(this.program,o)}use(t){t.useProgram(this.program)}},Et=`#version 300 es
|
|
70
|
+
#line 4
|
|
71
|
+
layout(location=0) in vec3 pos;
|
|
72
|
+
layout(location=1) in vec3 texCoords;
|
|
73
|
+
uniform mat4 mvpMtx;
|
|
74
|
+
out vec3 vColor;
|
|
75
|
+
void main(void) {
|
|
76
|
+
gl_Position = mvpMtx * vec4(pos, 1.0);
|
|
77
|
+
vColor = texCoords;
|
|
78
|
+
}`,Rr=`
|
|
79
|
+
vec4 drawColor(float scalar, float drawOpacity) {
|
|
80
|
+
float nlayer = float(textureSize(colormap, 0).y);
|
|
81
|
+
float layer = (nlayer - 0.5) / nlayer;
|
|
82
|
+
vec4 dcolor = texture(colormap, vec2((scalar * 255.0)/256.0 + 0.5/256.0, layer)).rgba;
|
|
83
|
+
dcolor.a *= drawOpacity;
|
|
84
|
+
return dcolor;
|
|
85
|
+
}`,zt=`vec3 GetBackPosition(vec3 startPositionTex) {
|
|
86
|
+
vec3 startPosition = startPositionTex * volScale;
|
|
87
|
+
vec3 invR = 1.0 / rayDir;
|
|
88
|
+
vec3 tbot = invR * (vec3(0.0)-startPosition);
|
|
89
|
+
vec3 ttop = invR * (volScale-startPosition);
|
|
90
|
+
vec3 tmax = max(ttop, tbot);
|
|
91
|
+
vec2 t = min(tmax.xx, tmax.yz);
|
|
92
|
+
vec3 endPosition = startPosition + (rayDir * min(t.x, t.y));
|
|
93
|
+
//convert world position back to texture position:
|
|
94
|
+
endPosition = endPosition / volScale;
|
|
95
|
+
return endPosition;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
float distance2Plane(in vec4 samplePos, in vec4 clipPlane) {
|
|
99
|
+
// treat clipPlane.a > 1 as "no clip" sentinel (keeps existing behavior)
|
|
100
|
+
if (clipPlane.a > 1.0) {
|
|
101
|
+
return 1000.0; // sentinel large distance
|
|
102
|
+
}
|
|
103
|
+
vec3 n = clipPlane.xyz;
|
|
104
|
+
const float EPS = 1e-6;
|
|
105
|
+
float nlen = length(n);
|
|
106
|
+
if (nlen < EPS) {
|
|
107
|
+
return 1000.0; // invalid plane normal
|
|
108
|
+
}
|
|
109
|
+
// signed plane value: dot(n, p-0.5) + a
|
|
110
|
+
float signedDist = dot(n, samplePos.xyz - 0.5) + clipPlane.a;
|
|
111
|
+
// perpendicular (Euclidean) distance is |signedDist| / |n|
|
|
112
|
+
return abs(signedDist) / nlen;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// see if clip plane trims ray sampling range sampleStartEnd.x..y
|
|
116
|
+
void clipSampleRange(in vec3 dir, in vec4 rayStart, in vec4 clipPlane, inout vec2 sampleStartEnd, inout bool hasClip) {
|
|
117
|
+
const float CSR_EPS = 1e-6;
|
|
118
|
+
// quick exit: no clip plane
|
|
119
|
+
if (clipPlane.a > 1.0)
|
|
120
|
+
return;
|
|
121
|
+
hasClip = true;
|
|
122
|
+
// quick exit: empty range
|
|
123
|
+
if ((sampleStartEnd.y - sampleStartEnd.x) <= CSR_EPS)
|
|
124
|
+
return;
|
|
125
|
+
// Which side does the ray start on? (plane eqn: dot(n, p-0.5) + a = 0)
|
|
126
|
+
float sampleSide = dot(clipPlane.xyz, rayStart.xyz - 0.5) + clipPlane.a;
|
|
127
|
+
bool startsFront = (sampleSide < 0.0);
|
|
128
|
+
float dis = - 1.0;
|
|
129
|
+
// plane normal dot ray direction
|
|
130
|
+
float cdot = dot(dir, clipPlane.xyz);
|
|
131
|
+
// avoid division by 0 for near-parallel plne
|
|
132
|
+
if (abs(cdot) >= CSR_EPS)
|
|
133
|
+
dis = (-clipPlane.a - dot(clipPlane.xyz, rayStart.xyz - 0.5)) / cdot;
|
|
134
|
+
if (dis < 0.0 || dis > sampleStartEnd.y + CSR_EPS) {
|
|
135
|
+
if (startsFront)
|
|
136
|
+
sampleStartEnd = vec2(0.0, 0.0);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
bool frontface = (cdot > 0.0);
|
|
140
|
+
if (frontface)
|
|
141
|
+
sampleStartEnd.x = max(sampleStartEnd.x, dis);
|
|
142
|
+
else
|
|
143
|
+
sampleStartEnd.y = min(sampleStartEnd.y, dis);
|
|
144
|
+
// if nothing remains, mark empty
|
|
145
|
+
if (sampleStartEnd.y - sampleStartEnd.x <= CSR_EPS)
|
|
146
|
+
sampleStartEnd = vec2(0.0, 0.0);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
bool skipSample (float pos, vec2 sampleRange) {
|
|
150
|
+
return (pos < sampleRange.x || pos > sampleRange.y);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
float frac2ndc(vec3 frac) {
|
|
154
|
+
//https://stackoverflow.com/questions/7777913/how-to-render-depth-linearly-in-modern-opengl-with-gl-fragcoord-z-in-fragment-sh
|
|
155
|
+
vec4 pos = vec4(frac.xyz, 1.0); //fraction
|
|
156
|
+
vec4 dim = vec4(vec3(textureSize(volume, 0)), 1.0);
|
|
157
|
+
pos = pos * dim;
|
|
158
|
+
vec4 shim = vec4(-0.5, -0.5, -0.5, 0.0);
|
|
159
|
+
pos += shim;
|
|
160
|
+
vec4 mm = transpose(matRAS) * pos;
|
|
161
|
+
float z_ndc = (mvpMtx * vec4(mm.xyz, 1.0)).z;
|
|
162
|
+
return (z_ndc + 1.0) / 2.0;
|
|
163
|
+
}`+Rr,Vr=`void main() {
|
|
164
|
+
if (fColor.x > 2.0) {
|
|
165
|
+
fColor = vec4(1.0, 0.0, 0.0, 0.5);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
fColor = vec4(0.0,0.0,0.0,0.0);
|
|
169
|
+
vec4 clipPlaneColorX = clipPlaneColor;
|
|
170
|
+
//if (clipPlaneColor.a < 0.0)
|
|
171
|
+
// clipPlaneColorX.a = - 1.0;
|
|
172
|
+
bool isColorPlaneInVolume = false;
|
|
173
|
+
if (clipPlaneColorX.a < 0.0) {
|
|
174
|
+
isColorPlaneInVolume = true;
|
|
175
|
+
clipPlaneColorX.a = 0.0;
|
|
176
|
+
}
|
|
177
|
+
//fColor = vec4(vColor.rgb, 1.0); return;
|
|
178
|
+
vec3 start = vColor;
|
|
179
|
+
gl_FragDepth = 1.0;
|
|
180
|
+
vec3 backPosition = GetBackPosition(start);
|
|
181
|
+
// fColor = vec4(backPosition, 1.0); return;
|
|
182
|
+
vec3 dir = normalize(backPosition - start);
|
|
183
|
+
//clipVolumeStart(start, backPosition);
|
|
184
|
+
dir = normalize(dir);
|
|
185
|
+
float len = length(backPosition - start);
|
|
186
|
+
float lenVox = length((texVox * start) - (texVox * backPosition));
|
|
187
|
+
if ((lenVox < 0.5) || (len > 3.0)) { //length limit for parallel rays
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
float sliceSize = len / lenVox; //e.g. if ray length is 1.0 and traverses 50 voxels, each voxel is 0.02 in unit cube
|
|
191
|
+
float stepSize = sliceSize; //quality: larger step is faster traversal, but fewer samples
|
|
192
|
+
float opacityCorrection = stepSize/sliceSize;
|
|
193
|
+
vec4 deltaDir = vec4(dir.xyz * stepSize, stepSize);
|
|
194
|
+
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
195
|
+
|
|
196
|
+
vec2 sampleRange = vec2(0.0, len);
|
|
197
|
+
bool hasClip = false;
|
|
198
|
+
for (int i = 0; i < MAX_CLIP_PLANES; i++)
|
|
199
|
+
clipSampleRange(dir, samplePos, clipPlanes[i], sampleRange, hasClip);
|
|
200
|
+
bool isClip = (sampleRange.x > 0.0) || ((sampleRange.y < len) && (sampleRange.y > 0.0));
|
|
201
|
+
float stepSizeFast = sliceSize * 1.9;
|
|
202
|
+
vec4 deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
203
|
+
if ((isClipCutaway) && (sampleRange.x <= 0.0) && (sampleRange.y >= len)) {
|
|
204
|
+
//completely clipped, but ray does not intersect plane
|
|
205
|
+
if (hasClip)
|
|
206
|
+
samplePos.a = len + 1.0;
|
|
207
|
+
else
|
|
208
|
+
sampleRange = vec2(0.0, 0.0);
|
|
209
|
+
}
|
|
210
|
+
if ((!isClipCutaway) && (sampleRange.x >= sampleRange.y))
|
|
211
|
+
samplePos.a = len + 1.0;
|
|
212
|
+
while (samplePos.a <= len) {
|
|
213
|
+
if (skipSample(samplePos.a, sampleRange) ^^ isClipCutaway) {
|
|
214
|
+
samplePos += deltaDirFast;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
float val = texture(volume, samplePos.xyz).a;
|
|
218
|
+
if (val > 0.01)
|
|
219
|
+
break;
|
|
220
|
+
samplePos += deltaDirFast; //advance ray position
|
|
221
|
+
}
|
|
222
|
+
float drawOpacityA = renderDrawAmbientOcclusionXY.y;
|
|
223
|
+
if ((samplePos.a >= len) && (((overlays < 1.0) && (drawOpacityA <= 0.0) ) || (backgroundMasksOverlays > 0))) {
|
|
224
|
+
if (isClip)
|
|
225
|
+
fColor += clipPlaneColorX;
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
fColor = vec4(1.0, 1.0, 1.0, 1.0);
|
|
229
|
+
//gl_FragDepth = frac2ndc(samplePos.xyz); //crude due to fast pass resolution
|
|
230
|
+
if (samplePos.a > deltaDirFast.a )
|
|
231
|
+
samplePos -= deltaDirFast;
|
|
232
|
+
//end: fast pass
|
|
233
|
+
vec4 colAcc = vec4(0.0,0.0,0.0,0.0);
|
|
234
|
+
vec4 firstHit = vec4(0.0,0.0,0.0,2.0 * len);
|
|
235
|
+
const float earlyTermination = 0.95;
|
|
236
|
+
float backNearest = len; //assume no hit
|
|
237
|
+
float ran = fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453);
|
|
238
|
+
// clip planes create steep gradients: reduce aliasing with more jitter
|
|
239
|
+
if (isClip)
|
|
240
|
+
samplePos += deltaDir * ran * 1.41; //jitter ray
|
|
241
|
+
else
|
|
242
|
+
samplePos += deltaDir * ran; //jitter ray
|
|
243
|
+
vec2 overlaySampleRange = isClipAllVolumes ? sampleRange : vec2(0.0, len);
|
|
244
|
+
bool overlayIsClipCutaway = isClipAllVolumes && isClipCutaway;
|
|
245
|
+
`,yi=`
|
|
246
|
+
if (firstHit.a < len) {
|
|
247
|
+
gl_FragDepth = frac2ndc(firstHit.xyz);
|
|
248
|
+
vec4 paqdSample = texture(paqd, samplePos.xyz);
|
|
249
|
+
if (paqdSample.a > 0.0) {
|
|
250
|
+
//colAcc.rgb = paqdSample.rgb;
|
|
251
|
+
float a = max(abs(paqdUniforms[2]), abs(paqdUniforms[3]));
|
|
252
|
+
colAcc.rgb = mix(colAcc.rgb, paqdSample.rgb, 0.5 * paqdSample.a * a);
|
|
253
|
+
}
|
|
254
|
+
if (isClip) {
|
|
255
|
+
//shade voxels with clip color
|
|
256
|
+
if (clipPlaneColor.a < 0.0) {
|
|
257
|
+
float thresh = 4.0 * sliceSize;
|
|
258
|
+
float firstHit1 = firstHit.a + deltaDir.a;
|
|
259
|
+
if (isClipCutaway) {
|
|
260
|
+
float min1 = abs(firstHit1 - sampleRange.y);
|
|
261
|
+
float dx = samplePos.a - firstHit1;
|
|
262
|
+
if (min1 < thresh)
|
|
263
|
+
colAcc.rgb = mix(colAcc.rgb, clipPlaneColorX.rgb, abs(clipPlaneColor.a));
|
|
264
|
+
else if (( colAcc.a > earlyTermination ) && (dx > thresh)) {
|
|
265
|
+
min1 = abs(firstHit1 - sampleRange.x);
|
|
266
|
+
if (min1 < (thresh * 0.5)) {
|
|
267
|
+
colAcc.rgb = mix(colAcc.rgb , clipPlaneColorX.rgb, abs(clipPlaneColor.a)*0.5);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
if (abs(firstHit1 - sampleRange.x) < thresh)
|
|
273
|
+
colAcc.rgb = mix(colAcc.rgb, clipPlaneColorX.rgb, abs(clipPlaneColor.a));
|
|
274
|
+
} // clipPlaneColor.a < 0.0
|
|
275
|
+
}
|
|
276
|
+
//ambient occlusion: make creases dark
|
|
277
|
+
float min1 = 1000.0;
|
|
278
|
+
float min2 = 1000.0;
|
|
279
|
+
// find smallest and second-smallest distances
|
|
280
|
+
vec4 firstHit1 = firstHit - deltaDir;
|
|
281
|
+
for (int i = 0; i < MAX_CLIP_PLANES; i++) {
|
|
282
|
+
float d = distance2Plane(firstHit1, clipPlanes[i]);
|
|
283
|
+
if (d < min1) {
|
|
284
|
+
min2 = min1;
|
|
285
|
+
min1 = d;
|
|
286
|
+
} else if (d < min2) {
|
|
287
|
+
min2 = d;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
float thresh = 1.2 * sliceSize;
|
|
291
|
+
if ((isClipCutaway) && (min2 < thresh) && (sampleRange.x > 0.0)) {
|
|
292
|
+
if ((abs(sampleRange.x - firstHit.a) > ( 2.0 * thresh)) && ((abs(sampleRange.y - firstHit.a) > (2.0 * thresh))))
|
|
293
|
+
min2 = thresh;
|
|
294
|
+
}
|
|
295
|
+
// if second is 0 -> factor 0 (black), if second >= sliceSize -> factor 1 (unchanged)
|
|
296
|
+
const float aoFrac = 0.5;
|
|
297
|
+
float factor = (1.0 - aoFrac) + aoFrac * clamp(min2 / thresh, 0.0, 1.0);
|
|
298
|
+
// linear darkening: multiply color by factor (or use mix(vec3(0), colAcc.rgb, factor))
|
|
299
|
+
colAcc.rgb *= factor;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
colAcc.a = (colAcc.a / earlyTermination) * backOpacity;
|
|
303
|
+
fColor = colAcc;
|
|
304
|
+
float renderDrawAmbientOcclusionX = renderDrawAmbientOcclusionXY.x;
|
|
305
|
+
float drawOpacity = renderDrawAmbientOcclusionXY.y;
|
|
306
|
+
if ((overlays < 1.0) && (drawOpacity <= 0.0))
|
|
307
|
+
return;
|
|
308
|
+
//overlay pass
|
|
309
|
+
samplePos = vec4(start.xyz, 0.0); //ray position
|
|
310
|
+
//start: OPTIONAL fast pass: rapid traversal until first hit
|
|
311
|
+
stepSizeFast = sliceSize * 1.0;
|
|
312
|
+
deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
313
|
+
while (samplePos.a <= len) {
|
|
314
|
+
if (skipSample(samplePos.a, overlaySampleRange) ^^ overlayIsClipCutaway) {
|
|
315
|
+
samplePos += deltaDirFast;
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
float val = texture(overlay, samplePos.xyz).a;
|
|
319
|
+
if (drawOpacity > 0.0) {
|
|
320
|
+
if (smoothDrawing > 0.0) {
|
|
321
|
+
if (!isClipAllVolumes || !(skipSample(samplePos.a, sampleRange) ^^ isClipCutaway))
|
|
322
|
+
val = max(val, texture(drawSmoothed, samplePos.xyz).r * 2.0);
|
|
323
|
+
} else
|
|
324
|
+
val = max(val, texture(drawing, samplePos.xyz).r);
|
|
325
|
+
}
|
|
326
|
+
if (val > 0.001)
|
|
327
|
+
break;
|
|
328
|
+
samplePos += deltaDirFast; //advance ray position
|
|
329
|
+
}
|
|
330
|
+
if (samplePos.a >= len) {
|
|
331
|
+
if (isClip && (fColor.a == 0.0))
|
|
332
|
+
fColor += clipPlaneColorX;
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
samplePos -= deltaDirFast;
|
|
336
|
+
if (samplePos.a < 0.0)
|
|
337
|
+
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
338
|
+
//end: fast pass
|
|
339
|
+
float overFarthest = len;
|
|
340
|
+
colAcc = vec4(0.0, 0.0, 0.0, 0.0);
|
|
341
|
+
|
|
342
|
+
samplePos += deltaDir * ran; //jitter ray
|
|
343
|
+
vec4 overFirstHit = vec4(0.0,0.0,0.0,2.0 * len);
|
|
344
|
+
if (backgroundMasksOverlays > 0)
|
|
345
|
+
samplePos = firstHit;
|
|
346
|
+
bool firstDraw = true;
|
|
347
|
+
// Hoist per-ray constants used by the smooth drawing path.
|
|
348
|
+
vec3 vxSize = 1.0 / vec3(textureSize(drawing, 0));
|
|
349
|
+
vec3 nRayDir = normalize(rayDir);
|
|
350
|
+
// For smooth drawing with a clip plane: if the ray enters the unclipped region
|
|
351
|
+
// already inside the drawn volume, start with prevSmoothOut=false so no
|
|
352
|
+
// outside→inside transition is detected, suppressing the clip-plane cap face.
|
|
353
|
+
bool prevSmoothOut = true;
|
|
354
|
+
bool enteredFromOutside = false;
|
|
355
|
+
vec4 cachedSmoothColor = vec4(0.0);
|
|
356
|
+
if (isClipAllVolumes && isClip && !isClipCutaway && smoothDrawing > 0.0) {
|
|
357
|
+
vec3 clipEntry = start.xyz + dir * sampleRange.x;
|
|
358
|
+
if (texture(drawSmoothed, clipEntry).r >= 0.5)
|
|
359
|
+
prevSmoothOut = false;
|
|
360
|
+
}
|
|
361
|
+
while (samplePos.a <= len) {
|
|
362
|
+
if (skipSample(samplePos.a, overlaySampleRange) ^^ overlayIsClipCutaway) {
|
|
363
|
+
samplePos += deltaDirFast;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
vec4 colorSample = texture(overlay, samplePos.xyz);
|
|
367
|
+
if ((colorSample.a < 0.01) && (drawOpacity > 0.0)) {
|
|
368
|
+
if (smoothDrawing > 0.0) {
|
|
369
|
+
// Smooth drawing: isosurface rendering with gradient-based shading
|
|
370
|
+
// Clip the smooth surface only when isClipAllVolumes is set
|
|
371
|
+
if (isClipAllVolumes && (skipSample(samplePos.a, sampleRange) ^^ isClipCutaway)) {
|
|
372
|
+
samplePos += deltaDir;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
float smoothVal = texture(drawSmoothed, samplePos.xyz).r;
|
|
376
|
+
bool nowSmoothInside = (smoothVal > 0.5);
|
|
377
|
+
// Track entry transitions: only mark enteredFromOutside on a genuine
|
|
378
|
+
// outside→inside crossing; clear it when we exit.
|
|
379
|
+
if (!nowSmoothInside) {
|
|
380
|
+
prevSmoothOut = true;
|
|
381
|
+
enteredFromOutside = false;
|
|
382
|
+
} else if (prevSmoothOut) {
|
|
383
|
+
// First inside sample: compute gradient, pen color, and Phong shading
|
|
384
|
+
// once and cache the result for all subsequent interior steps.
|
|
385
|
+
prevSmoothOut = false;
|
|
386
|
+
enteredFromOutside = true;
|
|
387
|
+
float gx = texture(drawSmoothed, samplePos.xyz + vec3(vxSize.x, 0.0, 0.0)).r
|
|
388
|
+
- texture(drawSmoothed, samplePos.xyz - vec3(vxSize.x, 0.0, 0.0)).r;
|
|
389
|
+
float gy = texture(drawSmoothed, samplePos.xyz + vec3(0.0, vxSize.y, 0.0)).r
|
|
390
|
+
- texture(drawSmoothed, samplePos.xyz - vec3(0.0, vxSize.y, 0.0)).r;
|
|
391
|
+
float gz = texture(drawSmoothed, samplePos.xyz + vec3(0.0, 0.0, vxSize.z)).r
|
|
392
|
+
- texture(drawSmoothed, samplePos.xyz - vec3(0.0, 0.0, vxSize.z)).r;
|
|
393
|
+
vec3 grad = vec3(gx, gy, gz);
|
|
394
|
+
float gradLen = length(grad);
|
|
395
|
+
vec3 normal = gradLen > 0.001 ? normalize(grad) : vec3(0.0, 0.0, 1.0);
|
|
396
|
+
// Get pen color from original drawing texture.
|
|
397
|
+
float drawVal = texture(drawing, samplePos.xyz).r;
|
|
398
|
+
if (drawVal == 0.0) {
|
|
399
|
+
// Between painted voxels: step inward along the gradient
|
|
400
|
+
// to find the nearest painted voxel's pen color.
|
|
401
|
+
// (normal points inward toward higher smooth values)
|
|
402
|
+
for (int k = 1; k <= 8; k++) {
|
|
403
|
+
drawVal = texture(drawing, samplePos.xyz + normal * vxSize * float(k)).r;
|
|
404
|
+
if (drawVal > 0.0) break;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
vec4 draw = drawColor(max(drawVal, 1.0 / 255.0), drawOpacity);
|
|
408
|
+
// Phong shading with two-sided lighting.
|
|
409
|
+
float NdotL = abs(dot(normal, nRayDir));
|
|
410
|
+
vec3 reflected = reflect(nRayDir, normal);
|
|
411
|
+
float spec = pow(max(dot(reflected, -nRayDir), 0.0), 20.0);
|
|
412
|
+
draw.rgb *= (0.4 + 0.6 * NdotL);
|
|
413
|
+
draw.rgb += vec3(0.2 * spec);
|
|
414
|
+
cachedSmoothColor = draw;
|
|
415
|
+
}
|
|
416
|
+
// Use the cached shaded color for every interior step.
|
|
417
|
+
if (nowSmoothInside && enteredFromOutside) {
|
|
418
|
+
colorSample = cachedSmoothColor;
|
|
419
|
+
}
|
|
420
|
+
} else {
|
|
421
|
+
// Original discrete drawing path
|
|
422
|
+
float val = texture(drawing, samplePos.xyz).r;
|
|
423
|
+
vec4 draw = drawColor(val, drawOpacity);
|
|
424
|
+
if ((draw.a > 0.0) && (firstDraw)) {
|
|
425
|
+
firstDraw = false;
|
|
426
|
+
float sum = 0.0;
|
|
427
|
+
const float mn = 1.0 / 256.0;
|
|
428
|
+
const float sampleRadius = 1.1;
|
|
429
|
+
float dx = sliceSize * sampleRadius;
|
|
430
|
+
vec3 center = samplePos.xyz;
|
|
431
|
+
//six neighbors that share a face
|
|
432
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,0.0,+dx), dir)).r, mn);
|
|
433
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,0.0,-dx), dir)).r, mn);
|
|
434
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,+dx,0.0), dir)).r, mn);
|
|
435
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,-dx,0.0), dir)).r, mn);
|
|
436
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(+dx,0.0,0.0), dir)).r, mn);
|
|
437
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(-dx,0.0,0.0), dir)).r, mn);
|
|
438
|
+
//float proportion = (sum / mn) / 6.0;
|
|
439
|
+
|
|
440
|
+
//12 neighbors that share an edge
|
|
441
|
+
dx = sliceSize * sampleRadius * sqrt(2.0) * 0.5;
|
|
442
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,+dx,+dx), dir)).r, mn);
|
|
443
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(+dx,0.0,+dx), dir)).r, mn);
|
|
444
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(+dx,+dx,0.0), dir)).r, mn);
|
|
445
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,-dx,-dx), dir)).r, mn);
|
|
446
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(-dx,0.0,-dx), dir)).r, mn);
|
|
447
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(-dx,-dx,0.0), dir)).r, mn);
|
|
448
|
+
|
|
449
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,+dx,-dx), dir)).r, mn);
|
|
450
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(+dx,0.0,-dx), dir)).r, mn);
|
|
451
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(+dx,-dx,0.0), dir)).r, mn);
|
|
452
|
+
|
|
453
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(0.0,-dx,+dx), dir)).r, mn);
|
|
454
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(-dx,0.0,+dx), dir)).r, mn);
|
|
455
|
+
sum += min(texture(drawing, center.xyz + cross(vec3(-dx,+dx,0.0), dir)).r, mn);
|
|
456
|
+
float proportion = (sum / mn) / 18.0; //proportion of six neighbors is non-zero
|
|
457
|
+
|
|
458
|
+
//a high proportion of hits means crevice
|
|
459
|
+
//since the AO term adds shadows that darken most voxels, it will result in dark surfaces
|
|
460
|
+
//the term brighten adds a little illumination to balance this
|
|
461
|
+
// without brighten, only the most extreme ridges will not be darker
|
|
462
|
+
const float brighten = 1.2;
|
|
463
|
+
vec3 ao = draw.rgb * (1.0 - proportion) * brighten;
|
|
464
|
+
draw.rgb = mix (draw.rgb, ao , renderDrawAmbientOcclusionX);
|
|
465
|
+
}
|
|
466
|
+
colorSample = draw;
|
|
467
|
+
} // end else (discrete drawing path)
|
|
468
|
+
}
|
|
469
|
+
samplePos += deltaDir; //advance ray position
|
|
470
|
+
if (colorSample.a >= 0.01) {
|
|
471
|
+
if (overFirstHit.a > len)
|
|
472
|
+
overFirstHit = samplePos;
|
|
473
|
+
colorSample.a *= renderOverlayBlend;
|
|
474
|
+
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
475
|
+
colorSample.rgb *= colorSample.a;
|
|
476
|
+
colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
|
|
477
|
+
overFarthest = samplePos.a;
|
|
478
|
+
if ( colAcc.a > earlyTermination )
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
//if (samplePos.a >= len) {
|
|
483
|
+
if (colAcc.a <= 0.0) {
|
|
484
|
+
if (isClip && (fColor.a == 0.0))
|
|
485
|
+
fColor += clipPlaneColorX;
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (overFirstHit.a < firstHit.a)
|
|
489
|
+
gl_FragDepth = frac2ndc(overFirstHit.xyz);
|
|
490
|
+
float overMix = colAcc.a;
|
|
491
|
+
float overlayDepth = 0.3;
|
|
492
|
+
if (fColor.a <= 0.0)
|
|
493
|
+
overMix = 1.0;
|
|
494
|
+
else if (((overFarthest) > backNearest)) {
|
|
495
|
+
float dx = (overFarthest - backNearest)/1.73;
|
|
496
|
+
dx = fColor.a * pow(dx, overlayDepth);
|
|
497
|
+
overMix *= 1.0 - dx;
|
|
498
|
+
}
|
|
499
|
+
fColor.rgb = mix(fColor.rgb, colAcc.rgb, overMix);
|
|
500
|
+
fColor.a = max(fColor.a, colAcc.a);
|
|
501
|
+
}`,N0=`#version 300 es
|
|
502
|
+
#line 215
|
|
503
|
+
#define MAX_CLIP_PLANES 6
|
|
504
|
+
precision highp int;
|
|
505
|
+
precision highp float;
|
|
506
|
+
uniform vec3 rayDir;
|
|
507
|
+
uniform vec3 texVox;
|
|
508
|
+
uniform int backgroundMasksOverlays;
|
|
509
|
+
uniform vec3 volScale;
|
|
510
|
+
uniform vec4 clipPlane;
|
|
511
|
+
uniform vec4 clipPlanes[MAX_CLIP_PLANES];
|
|
512
|
+
uniform highp sampler3D volume, overlay;
|
|
513
|
+
uniform highp sampler3D paqd;
|
|
514
|
+
uniform vec4 paqdUniforms;
|
|
515
|
+
uniform float overlays;
|
|
516
|
+
uniform float backOpacity;
|
|
517
|
+
uniform mat4 mvpMtx;
|
|
518
|
+
uniform mat4 matRAS;
|
|
519
|
+
uniform vec4 clipPlaneColor;
|
|
520
|
+
uniform float renderOverlayBlend;
|
|
521
|
+
uniform highp sampler3D drawing;
|
|
522
|
+
uniform highp sampler3D drawSmoothed;
|
|
523
|
+
uniform float smoothDrawing;
|
|
524
|
+
uniform highp sampler2D colormap;
|
|
525
|
+
uniform vec2 renderDrawAmbientOcclusionXY;
|
|
526
|
+
uniform bool isClipAllVolumes;
|
|
527
|
+
in vec3 vColor;
|
|
528
|
+
out vec4 fColor;
|
|
529
|
+
`+zt+`
|
|
530
|
+
void main() {
|
|
531
|
+
vec3 start = vColor;
|
|
532
|
+
gl_FragDepth = 1.0;
|
|
533
|
+
vec3 backPosition = GetBackPosition(start);
|
|
534
|
+
vec3 dir = normalize(backPosition - start);
|
|
535
|
+
//clipVolumeStart(start, backPosition);
|
|
536
|
+
float len = length(backPosition - start);
|
|
537
|
+
float lenVox = length((texVox * start) - (texVox * backPosition));
|
|
538
|
+
if ((lenVox < 0.5) || (len > 3.0)) { //length limit for parallel rays
|
|
539
|
+
fColor = vec4(0.0,0.0,0.0,0.0);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
float sliceSize = len / lenVox; //e.g. if ray length is 1.0 and traverses 50 voxels, each voxel is 0.02 in unit cube
|
|
543
|
+
float stepSize = sliceSize; //quality: larger step is faster traversal, but fewer samples
|
|
544
|
+
float opacityCorrection = stepSize/sliceSize;
|
|
545
|
+
vec4 deltaDir = vec4(dir.xyz * stepSize, stepSize);
|
|
546
|
+
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
547
|
+
vec4 colAcc = vec4(0.0,0.0,0.0,0.0);
|
|
548
|
+
vec4 firstHit = vec4(0.0,0.0,0.0,2.0 * len);
|
|
549
|
+
const float earlyTermination = 0.95;
|
|
550
|
+
float backNearest = len; //assume no hit
|
|
551
|
+
float dis = len;
|
|
552
|
+
//check if axial plane is closest
|
|
553
|
+
vec4 aClip = vec4(0.0, 0.0, 1.0, (1.0- clipPlane.z) - 0.5);
|
|
554
|
+
float adis = (-aClip.a - dot(aClip.xyz, samplePos.xyz-0.5)) / dot(dir,aClip.xyz);
|
|
555
|
+
if (adis > 0.0)
|
|
556
|
+
dis = min(adis, dis);
|
|
557
|
+
//check of coronal plane is closest
|
|
558
|
+
vec4 cClip = vec4(0.0, 1.0, 0.0, (1.0- clipPlane.y) - 0.5);
|
|
559
|
+
float cdis = (-cClip.a - dot(cClip.xyz, samplePos.xyz-0.5)) / dot(dir,cClip.xyz);
|
|
560
|
+
if (cdis > 0.0)
|
|
561
|
+
dis = min(cdis, dis);
|
|
562
|
+
//check if coronal slice is closest
|
|
563
|
+
vec4 sClip = vec4(1.0, 0.0, 0.0, (1.0- clipPlane.x) - 0.5);
|
|
564
|
+
float sdis = (-sClip.a - dot(sClip.xyz, samplePos.xyz-0.5)) / dot(dir,sClip.xyz);
|
|
565
|
+
if (sdis > 0.0)
|
|
566
|
+
dis = min(sdis, dis);
|
|
567
|
+
if ((dis > 0.0) && (dis < len)) {
|
|
568
|
+
samplePos = vec4(samplePos.xyz+dir * dis, dis);
|
|
569
|
+
colAcc = texture(volume, samplePos.xyz);
|
|
570
|
+
colAcc.a = earlyTermination;
|
|
571
|
+
firstHit = samplePos;
|
|
572
|
+
backNearest = min(backNearest, samplePos.a);
|
|
573
|
+
}
|
|
574
|
+
//the following are only used by overlays
|
|
575
|
+
vec4 clipPlaneColorX = clipPlaneColor;
|
|
576
|
+
bool isColorPlaneInVolume = false;
|
|
577
|
+
bool isClip = false;
|
|
578
|
+
bool isClipCutaway = false;
|
|
579
|
+
vec2 sampleRange = vec2(0.0, len);
|
|
580
|
+
// vec4 clipPos = applyClip(dir, samplePos, len, isClip);
|
|
581
|
+
float stepSizeFast = sliceSize * 1.9;
|
|
582
|
+
vec4 deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
583
|
+
vec2 overlaySampleRange = vec2(0.0, len);
|
|
584
|
+
bool overlayIsClipCutaway = false;
|
|
585
|
+
if (samplePos.a < 0.0)
|
|
586
|
+
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
587
|
+
float ran = fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453);
|
|
588
|
+
samplePos += deltaDir * ran; //jitter ray
|
|
589
|
+
`+yi,L0=`#version 300 es
|
|
590
|
+
#line 215
|
|
591
|
+
#define MAX_CLIP_PLANES 6
|
|
592
|
+
precision highp int;
|
|
593
|
+
precision highp float;
|
|
594
|
+
uniform vec3 rayDir;
|
|
595
|
+
uniform vec3 texVox;
|
|
596
|
+
uniform int backgroundMasksOverlays;
|
|
597
|
+
uniform vec3 volScale;
|
|
598
|
+
uniform vec4 clipPlane;
|
|
599
|
+
uniform vec4 clipPlanes[MAX_CLIP_PLANES];
|
|
600
|
+
uniform bool isClipCutaway;
|
|
601
|
+
uniform highp sampler3D volume, overlay;
|
|
602
|
+
uniform highp sampler3D paqd;
|
|
603
|
+
uniform vec4 paqdUniforms;
|
|
604
|
+
uniform float overlays;
|
|
605
|
+
uniform float backOpacity;
|
|
606
|
+
uniform mat4 mvpMtx;
|
|
607
|
+
uniform mat4 matRAS;
|
|
608
|
+
uniform vec4 clipPlaneColor;
|
|
609
|
+
uniform float renderOverlayBlend;
|
|
610
|
+
uniform highp sampler3D drawing;
|
|
611
|
+
uniform highp sampler3D drawSmoothed;
|
|
612
|
+
uniform float smoothDrawing;
|
|
613
|
+
uniform highp sampler2D colormap;
|
|
614
|
+
uniform vec2 renderDrawAmbientOcclusionXY;
|
|
615
|
+
uniform bool isClipAllVolumes;
|
|
616
|
+
in vec3 vColor;
|
|
617
|
+
out vec4 fColor;
|
|
618
|
+
`+zt+Vr+`while (samplePos.a <= len) {
|
|
619
|
+
if (skipSample(samplePos.a, sampleRange) ^^ isClipCutaway) {
|
|
620
|
+
samplePos += deltaDirFast;
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
vec4 colorSample = texture(volume, samplePos.xyz);
|
|
624
|
+
samplePos += deltaDir; //advance ray position
|
|
625
|
+
if (colorSample.a >= 0.01) {
|
|
626
|
+
if (firstHit.a > len)
|
|
627
|
+
firstHit = samplePos;
|
|
628
|
+
// backNearest = min(backNearest, samplePos.a);
|
|
629
|
+
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
630
|
+
colorSample.rgb *= colorSample.a;
|
|
631
|
+
colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
|
|
632
|
+
if ( colAcc.a > earlyTermination )
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (firstHit.a < len)
|
|
637
|
+
backNearest = firstHit.a;
|
|
638
|
+
`+yi,Bt=192,Gn=`#version 300 es
|
|
639
|
+
#line 215
|
|
640
|
+
#define MAX_CLIP_PLANES 6
|
|
641
|
+
precision highp int;
|
|
642
|
+
precision highp float;
|
|
643
|
+
uniform vec3 rayDir;
|
|
644
|
+
uniform vec3 texVox;
|
|
645
|
+
uniform int backgroundMasksOverlays;
|
|
646
|
+
uniform vec3 volScale;
|
|
647
|
+
uniform vec4 clipPlane;
|
|
648
|
+
uniform vec4 clipPlanes[MAX_CLIP_PLANES];
|
|
649
|
+
uniform bool isClipCutaway;
|
|
650
|
+
uniform highp sampler3D volume, overlay;
|
|
651
|
+
uniform highp sampler3D paqd;
|
|
652
|
+
uniform vec4 paqdUniforms;
|
|
653
|
+
uniform float overlays;
|
|
654
|
+
uniform float backOpacity;
|
|
655
|
+
uniform mat4 mvpMtx;
|
|
656
|
+
uniform mat4 normMtx;
|
|
657
|
+
uniform mat4 matRAS;
|
|
658
|
+
uniform vec4 clipPlaneColor;
|
|
659
|
+
uniform float renderOverlayBlend;
|
|
660
|
+
uniform highp sampler3D drawing, gradient;
|
|
661
|
+
uniform highp sampler3D drawSmoothed;
|
|
662
|
+
uniform float smoothDrawing;
|
|
663
|
+
uniform highp sampler2D colormap;
|
|
664
|
+
uniform highp sampler2D matCap;
|
|
665
|
+
uniform vec2 renderDrawAmbientOcclusionXY;
|
|
666
|
+
uniform float gradientAmount;
|
|
667
|
+
uniform float silhouettePower;
|
|
668
|
+
uniform float gradientOpacity[${Bt}];
|
|
669
|
+
uniform bool isClipAllVolumes;
|
|
670
|
+
in vec3 vColor;
|
|
671
|
+
out vec4 fColor;
|
|
672
|
+
`,k0=Gn+zt+Vr+`
|
|
673
|
+
float startPos = samplePos.a;
|
|
674
|
+
float clipCloseThresh = 5.0 * deltaDir.a;
|
|
675
|
+
float clipClose = sampleRange.x;
|
|
676
|
+
if (isClipCutaway)
|
|
677
|
+
clipClose = sampleRange.y;
|
|
678
|
+
if (!isClip)
|
|
679
|
+
clipClose = -1.0;
|
|
680
|
+
float brighten = 2.0; //modulating makes average intensity darker 0.5 * 0.5 = 0.25
|
|
681
|
+
//vec4 prevGrad = vec4(0.0);
|
|
682
|
+
float silhouetteThreshold = 1.0 - silhouettePower;
|
|
683
|
+
while (samplePos.a <= len) {
|
|
684
|
+
if (skipSample(samplePos.a, sampleRange) ^^ isClipCutaway) {
|
|
685
|
+
samplePos += deltaDirFast;
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
vec4 colorSample = texture(volume, samplePos.xyz);
|
|
689
|
+
if (colorSample.a >= 0.0) {
|
|
690
|
+
vec4 grad = texture(gradient, samplePos.xyz);
|
|
691
|
+
grad.rgb = grad.rgb*2.0 - 1.0;
|
|
692
|
+
if (grad.a > 0.0)
|
|
693
|
+
grad.rgb = normalize(grad.rgb);
|
|
694
|
+
//if (grad.a < prevGrad.a)
|
|
695
|
+
// grad.rgb = prevGrad.rgb;
|
|
696
|
+
//prevGrad = grad;
|
|
697
|
+
vec3 n = mat3(normMtx) * grad.rgb;
|
|
698
|
+
n.y = - n.y;
|
|
699
|
+
vec4 mc = vec4(texture(matCap, n.xy * 0.5 + 0.5).rgb, 1.0) * brighten;
|
|
700
|
+
mc = mix(vec4(1.0), mc, gradientAmount);
|
|
701
|
+
if (abs(samplePos.a - clipClose) > clipCloseThresh)
|
|
702
|
+
colorSample.rgb *= mc.rgb;
|
|
703
|
+
if (firstHit.a > len)
|
|
704
|
+
firstHit = samplePos;
|
|
705
|
+
backNearest = min(backNearest, samplePos.a);
|
|
706
|
+
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
707
|
+
int gradIdx = int(grad.a * ${Bt}.0);
|
|
708
|
+
colorSample.a *= gradientOpacity[gradIdx];
|
|
709
|
+
float lightNormDot = dot(grad.rgb, rayDir);
|
|
710
|
+
// n.b. "lightNormDor" is cosTheta, "silhouettePower" is Fresnel effect exponent
|
|
711
|
+
colorSample.a *= pow(1.0 - abs(lightNormDot), silhouettePower);
|
|
712
|
+
float viewAlign = abs(lightNormDot); // 0 = perpendicular, 1 = aligned
|
|
713
|
+
// linearly map silhouettePower (0..1) to a threshold range, e.g., [1.0, 0.0]
|
|
714
|
+
// Cull voxels that are too aligned with the view direction
|
|
715
|
+
if (viewAlign > silhouetteThreshold)
|
|
716
|
+
colorSample.a = 0.0;
|
|
717
|
+
colorSample.rgb *= colorSample.a;
|
|
718
|
+
colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
|
|
719
|
+
if ( colAcc.a > earlyTermination )
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
samplePos += deltaDir; //advance ray position
|
|
723
|
+
}
|
|
724
|
+
`+yi,O0=Gn+zt+Vr+`
|
|
725
|
+
float startPos = samplePos.a;
|
|
726
|
+
//float clipClose = clipPos.a + 3.0 * deltaDir.a; //do not apply gradients near clip plane
|
|
727
|
+
float brighten = 2.0; //modulating makes average intensity darker 0.5 * 0.5 = 0.25
|
|
728
|
+
//vec4 prevGrad = vec4(0.0);
|
|
729
|
+
while (samplePos.a <= len) {
|
|
730
|
+
vec4 colorSample = texture(volume, samplePos.xyz);
|
|
731
|
+
if (colorSample.a >= 0.0) {
|
|
732
|
+
vec4 grad = texture(gradient, samplePos.xyz);
|
|
733
|
+
grad.rgb = grad.rgb*2.0 - 1.0;
|
|
734
|
+
if (grad.a > 0.0)
|
|
735
|
+
grad.rgb = normalize(grad.rgb);
|
|
736
|
+
colorSample.rgb = abs(grad.rgb);
|
|
737
|
+
if (firstHit.a > len)
|
|
738
|
+
firstHit = samplePos;
|
|
739
|
+
backNearest = min(backNearest, samplePos.a);
|
|
740
|
+
colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);
|
|
741
|
+
colorSample.rgb *= colorSample.a;
|
|
742
|
+
colAcc= (1.0 - colAcc.a) * colorSample + colAcc;
|
|
743
|
+
if ( colAcc.a > earlyTermination )
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
samplePos += deltaDir; //advance ray position
|
|
747
|
+
}
|
|
748
|
+
`+yi,li=`#version 300 es
|
|
749
|
+
#line 392
|
|
750
|
+
layout(location=0) in vec3 pos;
|
|
751
|
+
uniform int axCorSag;
|
|
752
|
+
uniform mat4 mvpMtx;
|
|
753
|
+
uniform mat4 frac2mm;
|
|
754
|
+
uniform float slice;
|
|
755
|
+
out vec3 texPos;
|
|
756
|
+
void main(void) {
|
|
757
|
+
texPos = vec3(pos.x, pos.y, slice);
|
|
758
|
+
if (axCorSag > 1)
|
|
759
|
+
texPos = vec3(slice, pos.x, pos.y);
|
|
760
|
+
else if (axCorSag > 0)
|
|
761
|
+
texPos = vec3(pos.x, slice, pos.y);
|
|
762
|
+
vec4 mm = frac2mm * vec4(texPos, 1.0);
|
|
763
|
+
gl_Position = mvpMtx * mm;
|
|
764
|
+
}`,Yn=`#version 300 es
|
|
765
|
+
#line 411
|
|
766
|
+
precision highp int;
|
|
767
|
+
precision highp float;
|
|
768
|
+
uniform highp sampler3D volume, overlay;
|
|
769
|
+
uniform highp sampler3D paqd;
|
|
770
|
+
uniform vec4 paqdUniforms;
|
|
771
|
+
uniform int backgroundMasksOverlays;
|
|
772
|
+
uniform float overlayOutlineWidth;
|
|
773
|
+
uniform float overlayAlphaShader;
|
|
774
|
+
uniform int axCorSag;
|
|
775
|
+
uniform float overlays;
|
|
776
|
+
uniform float opacity;
|
|
777
|
+
uniform float drawOpacity;
|
|
778
|
+
uniform float drawRimOpacity;
|
|
779
|
+
uniform bool isAlphaClipDark;
|
|
780
|
+
uniform highp sampler3D drawing;
|
|
781
|
+
uniform highp sampler2D colormap;
|
|
782
|
+
in vec3 texPos;
|
|
783
|
+
out vec4 color;
|
|
784
|
+
`+Rr+`
|
|
785
|
+
vec4 blendRGBA(vec4 foreground, vec4 background) {
|
|
786
|
+
float alphaOut = foreground.a + background.a * (1.0 - foreground.a);
|
|
787
|
+
vec3 colorOut = (foreground.rgb * foreground.a + background.rgb * background.a * (1.0 - foreground.a)) / alphaOut;
|
|
788
|
+
return vec4(colorOut, alphaOut);
|
|
789
|
+
}
|
|
790
|
+
float paqdEaseAlpha(float alpha) {
|
|
791
|
+
// t are alpha transitions
|
|
792
|
+
// <t0 -> y0
|
|
793
|
+
// t0..t1 -> mix between y0..y1
|
|
794
|
+
// t1..t2 -> mix between y1..y2
|
|
795
|
+
// >t2 -> y2
|
|
796
|
+
float t0 = paqdUniforms[0]; // 0.3;
|
|
797
|
+
float t1 = 0.5 * (paqdUniforms[0] + paqdUniforms[1]); // 0.4;
|
|
798
|
+
float t2 = paqdUniforms[1]; // 0.9;
|
|
799
|
+
float y0 = 0.0;
|
|
800
|
+
float y1 = abs(paqdUniforms[2]); // 1.0;
|
|
801
|
+
float y2 = abs(paqdUniforms[3]); //0.25;
|
|
802
|
+
if (alpha <= t0) {
|
|
803
|
+
return y0;
|
|
804
|
+
} else if (alpha <= t1) {
|
|
805
|
+
return mix(y0, y1, (alpha - t0) / (t1 - t0)); // LERP 0.0 → 1.0
|
|
806
|
+
} else if (alpha <= t2) {
|
|
807
|
+
return mix(y1, y2, (alpha - t1) / (t2 - t1)); // LERP 1.0 → 0.2
|
|
808
|
+
} else {
|
|
809
|
+
return y2;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
void main() {
|
|
814
|
+
//color = vec4(1.0, 0.0, 1.0, 1.0);return;
|
|
815
|
+
vec4 background = texture(volume, texPos);
|
|
816
|
+
color = vec4(background.rgb, opacity);
|
|
817
|
+
if ((isAlphaClipDark) && (background.a == 0.0)) color.a = 0.0; //FSLeyes clipping range
|
|
818
|
+
vec4 ocolor = vec4(0.0);
|
|
819
|
+
float overlayAlpha = overlayAlphaShader;
|
|
820
|
+
if (overlays > 0.0) {
|
|
821
|
+
ocolor = texture(overlay, texPos);
|
|
822
|
+
//dFdx for "boxing" issue 435 has aliasing on some implementations (coarse vs fine)
|
|
823
|
+
//however, this only identifies 50% of the edges due to aliasing effects
|
|
824
|
+
// http://www.aclockworkberry.com/shader-derivative-functions/
|
|
825
|
+
// https://bgolus.medium.com/distinctive-derivative-differences-cce38d36797b
|
|
826
|
+
//if ((ocolor.a >= 1.0) && ((dFdx(ocolor.a) != 0.0) || (dFdy(ocolor.a) != 0.0) ))
|
|
827
|
+
// ocolor.rbg = vec3(0.0, 0.0, 0.0);
|
|
828
|
+
bool isOutlineBelowNotAboveThreshold = true;
|
|
829
|
+
if (isOutlineBelowNotAboveThreshold) {
|
|
830
|
+
if ((overlayOutlineWidth > 0.0) && (ocolor.a < 1.0)) { //check voxel neighbors for edge
|
|
831
|
+
vec3 vx = (overlayOutlineWidth ) / vec3(textureSize(overlay, 0));
|
|
832
|
+
//6 voxel neighbors that share a face
|
|
833
|
+
vec3 vxR = vec3(texPos.x+vx.x, texPos.y, texPos.z);
|
|
834
|
+
vec3 vxL = vec3(texPos.x-vx.x, texPos.y, texPos.z);
|
|
835
|
+
vec3 vxA = vec3(texPos.x, texPos.y+vx.y, texPos.z);
|
|
836
|
+
vec3 vxP = vec3(texPos.x, texPos.y-vx.y, texPos.z);
|
|
837
|
+
vec3 vxS = vec3(texPos.x, texPos.y, texPos.z+vx.z);
|
|
838
|
+
vec3 vxI = vec3(texPos.x, texPos.y, texPos.z-vx.z);
|
|
839
|
+
float a = 0.0;
|
|
840
|
+
if (axCorSag != 2) {
|
|
841
|
+
a = max(a, texture(overlay, vxR).a);
|
|
842
|
+
a = max(a, texture(overlay, vxL).a);
|
|
843
|
+
}
|
|
844
|
+
if (axCorSag != 1) {
|
|
845
|
+
a = max(a, texture(overlay, vxA).a);
|
|
846
|
+
a = max(a, texture(overlay, vxP).a);
|
|
847
|
+
}
|
|
848
|
+
if (axCorSag != 0) {
|
|
849
|
+
a = max(a, texture(overlay, vxS).a);
|
|
850
|
+
a = max(a, texture(overlay, vxI).a);
|
|
851
|
+
}
|
|
852
|
+
bool isCheckCorners = true;
|
|
853
|
+
if (isCheckCorners) {
|
|
854
|
+
//12 voxel neighbors that share an edge
|
|
855
|
+
vec3 vxRA = vec3(texPos.x+vx.x, texPos.y+vx.y, texPos.z);
|
|
856
|
+
vec3 vxLA = vec3(texPos.x-vx.x, texPos.y+vx.y, texPos.z);
|
|
857
|
+
vec3 vxRP = vec3(texPos.x+vx.x, texPos.y-vx.y, texPos.z);
|
|
858
|
+
vec3 vxLP = vec3(texPos.x-vx.x, texPos.y-vx.y, texPos.z);
|
|
859
|
+
vec3 vxRS = vec3(texPos.x+vx.x, texPos.y, texPos.z+vx.z);
|
|
860
|
+
vec3 vxLS = vec3(texPos.x-vx.x, texPos.y, texPos.z+vx.z);
|
|
861
|
+
vec3 vxRI = vec3(texPos.x+vx.x, texPos.y, texPos.z-vx.z);
|
|
862
|
+
vec3 vxLI = vec3(texPos.x-vx.x, texPos.y, texPos.z-vx.z);
|
|
863
|
+
vec3 vxAS = vec3(texPos.x, texPos.y+vx.y, texPos.z+vx.z);
|
|
864
|
+
vec3 vxPS = vec3(texPos.x, texPos.y-vx.y, texPos.z+vx.z);
|
|
865
|
+
vec3 vxAI = vec3(texPos.x, texPos.y+vx.y, texPos.z-vx.z);
|
|
866
|
+
vec3 vxPI = vec3(texPos.x, texPos.y-vx.y, texPos.z-vx.z);
|
|
867
|
+
|
|
868
|
+
if (axCorSag == 0) { //axial corners
|
|
869
|
+
a = max(a, texture(overlay, vxRA).a);
|
|
870
|
+
a = max(a, texture(overlay, vxLA).a);
|
|
871
|
+
a = max(a, texture(overlay, vxRP).a);
|
|
872
|
+
a = max(a, texture(overlay, vxLP).a);
|
|
873
|
+
}
|
|
874
|
+
if (axCorSag == 1) { //coronal corners
|
|
875
|
+
a = max(a, texture(overlay, vxRS).a);
|
|
876
|
+
a = max(a, texture(overlay, vxLS).a);
|
|
877
|
+
a = max(a, texture(overlay, vxRI).a);
|
|
878
|
+
a = max(a, texture(overlay, vxLI).a);
|
|
879
|
+
}
|
|
880
|
+
if (axCorSag == 2) { //sagittal corners
|
|
881
|
+
a = max(a, texture(overlay, vxAS).a);
|
|
882
|
+
a = max(a, texture(overlay, vxPS).a);
|
|
883
|
+
a = max(a, texture(overlay, vxAI).a);
|
|
884
|
+
a = max(a, texture(overlay, vxPI).a);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
if (a >= 1.0) {
|
|
888
|
+
ocolor = vec4(0.0, 0.0, 0.0, 1.0);
|
|
889
|
+
overlayAlpha = 1.0;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
} else {
|
|
894
|
+
if ((overlayOutlineWidth > 0.0) && (ocolor.a >= 1.0)) { //check voxel neighbors for edge
|
|
895
|
+
vec3 vx = (overlayOutlineWidth ) / vec3(textureSize(overlay, 0));
|
|
896
|
+
vec3 vxR = vec3(texPos.x+vx.x, texPos.y, texPos.z);
|
|
897
|
+
vec3 vxL = vec3(texPos.x-vx.x, texPos.y, texPos.z);
|
|
898
|
+
vec3 vxA = vec3(texPos.x, texPos.y+vx.y, texPos.z);
|
|
899
|
+
vec3 vxP = vec3(texPos.x, texPos.y-vx.y, texPos.z);
|
|
900
|
+
vec3 vxS = vec3(texPos.x, texPos.y, texPos.z+vx.z);
|
|
901
|
+
vec3 vxI = vec3(texPos.x, texPos.y, texPos.z-vx.z);
|
|
902
|
+
float a = 1.0;
|
|
903
|
+
if (axCorSag != 2) {
|
|
904
|
+
a = min(a, texture(overlay, vxR).a);
|
|
905
|
+
a = min(a, texture(overlay, vxL).a);
|
|
906
|
+
}
|
|
907
|
+
if (axCorSag != 1) {
|
|
908
|
+
a = min(a, texture(overlay, vxA).a);
|
|
909
|
+
a = min(a, texture(overlay, vxP).a);
|
|
910
|
+
}
|
|
911
|
+
if (axCorSag != 0) {
|
|
912
|
+
a = min(a, texture(overlay, vxS).a);
|
|
913
|
+
a = min(a, texture(overlay, vxI).a);
|
|
914
|
+
}
|
|
915
|
+
if (a < 1.0) {
|
|
916
|
+
ocolor = vec4(0.0, 0.0, 0.0, 1.0);
|
|
917
|
+
overlayAlpha = 1.0;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
} //outline above threshold
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
`,z0=`#version 300 es
|
|
924
|
+
#line 411
|
|
925
|
+
precision highp int;
|
|
926
|
+
precision highp float;
|
|
927
|
+
uniform highp sampler2D volume, overlay;
|
|
928
|
+
uniform int backgroundMasksOverlays;
|
|
929
|
+
uniform float overlayOutlineWidth;
|
|
930
|
+
uniform float overlayAlphaShader;
|
|
931
|
+
uniform int axCorSag;
|
|
932
|
+
uniform float overlays;
|
|
933
|
+
uniform float opacity;
|
|
934
|
+
uniform float drawOpacity;
|
|
935
|
+
uniform bool isAlphaClipDark;
|
|
936
|
+
uniform highp sampler2D drawing;
|
|
937
|
+
uniform highp sampler2D colormap;
|
|
938
|
+
in vec3 texPos;
|
|
939
|
+
out vec4 color;`+Rr+`void main() {
|
|
940
|
+
//color = vec4(1.0, 0.0, 1.0, 1.0);return;
|
|
941
|
+
vec4 background = texture(volume, texPos.xy);
|
|
942
|
+
color = vec4(background.rgb, opacity);
|
|
943
|
+
if ((isAlphaClipDark) && (background.a == 0.0)) color.a = 0.0; //FSLeyes clipping range
|
|
944
|
+
vec4 dcolor = drawColor(texture(drawing, texPos.xy).r, drawOpacity);
|
|
945
|
+
if (dcolor.a > 0.0) {
|
|
946
|
+
color.rgb = mix(color.rgb, dcolor.rgb, dcolor.a);
|
|
947
|
+
color.a = max(drawOpacity, color.a);
|
|
948
|
+
}
|
|
949
|
+
}`,Xn=` ocolor.a *= overlayAlpha;
|
|
950
|
+
float drawV = texture(drawing, texPos).r;
|
|
951
|
+
vec4 dcolor = drawColor(drawV, drawOpacity);
|
|
952
|
+
if (dcolor.a > 0.0) {
|
|
953
|
+
if (drawRimOpacity >= 0.0) {
|
|
954
|
+
vec3 vx = 1.0 / vec3(textureSize(drawing, 0));
|
|
955
|
+
//6 voxel neighbors that share a face
|
|
956
|
+
vec3 offsetX = dFdx(texPos); // left-right spacing
|
|
957
|
+
vec3 offsetY = dFdy(texPos); // up-down spacing
|
|
958
|
+
float L = texture(drawing, texPos - offsetX).r;
|
|
959
|
+
float R = texture(drawing, texPos + offsetX).r;
|
|
960
|
+
float T = texture(drawing, texPos - offsetY).r;
|
|
961
|
+
float B = texture(drawing, texPos + offsetY).r;
|
|
962
|
+
if (L != drawV || R != drawV || T != drawV || B != drawV)
|
|
963
|
+
dcolor.a = drawRimOpacity;
|
|
964
|
+
}
|
|
965
|
+
color.rgb = mix(color.rgb, dcolor.rgb, dcolor.a);
|
|
966
|
+
color.a = max(drawOpacity, color.a);
|
|
967
|
+
}
|
|
968
|
+
vec4 pcolor = texture(paqd, texPos);
|
|
969
|
+
if (pcolor.a > 0.0) {
|
|
970
|
+
pcolor.a = paqdEaseAlpha(pcolor.a);
|
|
971
|
+
if (pcolor.a > 0.0) {
|
|
972
|
+
if (paqdUniforms[3] < 0.0)
|
|
973
|
+
ocolor = blendRGBA(pcolor, ocolor);
|
|
974
|
+
else
|
|
975
|
+
ocolor = blendRGBA(ocolor, pcolor);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
if ((backgroundMasksOverlays > 0) && (background.a == 0.0))
|
|
979
|
+
return;
|
|
980
|
+
float a = color.a + ocolor.a * (1.0 - color.a); // premultiplied alpha
|
|
981
|
+
if (a == 0.0) return;
|
|
982
|
+
color.rgb = mix(color.rgb, ocolor.rgb, ocolor.a / a);
|
|
983
|
+
color.a = a;
|
|
984
|
+
}`,G0=Yn+Xn,Y0=Yn+` if (ocolor.a > 0.0) {
|
|
985
|
+
//https://gamedev.stackexchange.com/questions/102889/is-it-possible-to-convert-vec4-to-int-in-glsl-using-opengl-es
|
|
986
|
+
uint alpha = uint(ocolor.a * 255.0);
|
|
987
|
+
vec3 xyzFlip = vec3(float((uint(1) & alpha) > uint(0)), float((uint(2) & alpha) > uint(0)), float((uint(4) & alpha) > uint(0)));
|
|
988
|
+
//convert from 0 and 1 to -1 and 1
|
|
989
|
+
xyzFlip = (xyzFlip * 2.0) - 1.0;
|
|
990
|
+
//https://math.stackexchange.com/questions/1905533/find-perpendicular-distance-from-point-to-line-in-3d
|
|
991
|
+
//v1 principle direction of tensor for this voxel
|
|
992
|
+
vec3 v1 = ocolor.rgb;
|
|
993
|
+
//flips encode polarity to convert from 0..1 to -1..1 (27 bits vs 24 bit precision)
|
|
994
|
+
v1 = normalize( v1 * xyzFlip);
|
|
995
|
+
vec3 vxl = fract(texPos * vec3(textureSize(volume, 0))) - 0.5;
|
|
996
|
+
//vxl coordinates now -0.5..+0.5 so 0,0,0 is origin
|
|
997
|
+
vxl.x = -vxl.x;
|
|
998
|
+
float t = dot(vxl,v1);
|
|
999
|
+
vec3 P = t * v1;
|
|
1000
|
+
float dx = length(P-vxl);
|
|
1001
|
+
ocolor.a = 1.0 - smoothstep(0.2,0.25, dx);
|
|
1002
|
+
//if modulation was applied, use that to scale alpha not color:
|
|
1003
|
+
ocolor.a *= length(ocolor.rgb);
|
|
1004
|
+
ocolor.rgb = normalize(ocolor.rgb);
|
|
1005
|
+
//compute distance one half voxel closer to viewer:
|
|
1006
|
+
float pan = 0.5;
|
|
1007
|
+
if (axCorSag == 0)
|
|
1008
|
+
vxl.z -= pan;
|
|
1009
|
+
if (axCorSag == 1)
|
|
1010
|
+
vxl.y -= pan;
|
|
1011
|
+
if (axCorSag == 2)
|
|
1012
|
+
vxl.x += pan;
|
|
1013
|
+
t = dot(vxl,v1);
|
|
1014
|
+
P = t * v1;
|
|
1015
|
+
float dx2 = length(P-vxl);
|
|
1016
|
+
ocolor.rgb += (dx2-dx-(0.5 * pan)) * 1.0;
|
|
1017
|
+
}
|
|
1018
|
+
`+Xn,Ni=`#version 300 es
|
|
1019
|
+
#line 480
|
|
1020
|
+
precision highp int;
|
|
1021
|
+
precision highp float;
|
|
1022
|
+
uniform vec4 lineColor;
|
|
1023
|
+
out vec4 color;
|
|
1024
|
+
void main() {
|
|
1025
|
+
color = lineColor;
|
|
1026
|
+
}`,X0=`#version 300 es
|
|
1027
|
+
#line 723
|
|
1028
|
+
precision highp int;
|
|
1029
|
+
precision highp float;
|
|
1030
|
+
|
|
1031
|
+
uniform vec4 lineColor;
|
|
1032
|
+
uniform vec4 leftTopWidthHeight;
|
|
1033
|
+
uniform float thickness; // line thickness in pixels
|
|
1034
|
+
uniform vec2 canvasWidthHeight;
|
|
1035
|
+
|
|
1036
|
+
out vec4 color;
|
|
1037
|
+
|
|
1038
|
+
void main() {
|
|
1039
|
+
// fragment position in screen coordinates
|
|
1040
|
+
vec2 fragCoord = gl_FragCoord.xy;
|
|
1041
|
+
|
|
1042
|
+
// canvas height
|
|
1043
|
+
float canvasHeight = canvasWidthHeight.y;
|
|
1044
|
+
|
|
1045
|
+
// 'top' and 'bottom' to match gl_FragCoord.y coordinate system
|
|
1046
|
+
float top = canvasHeight - leftTopWidthHeight.y;
|
|
1047
|
+
float bottom = top - leftTopWidthHeight.w;
|
|
1048
|
+
|
|
1049
|
+
// left and right edges
|
|
1050
|
+
float left = leftTopWidthHeight.x;
|
|
1051
|
+
float right = left + leftTopWidthHeight.z;
|
|
1052
|
+
|
|
1053
|
+
bool withinLeft = fragCoord.x >= left && fragCoord.x <= left + thickness;
|
|
1054
|
+
bool withinRight = fragCoord.x <= right && fragCoord.x >= right - thickness;
|
|
1055
|
+
bool withinTop = fragCoord.y <= top && fragCoord.y >= top - thickness;
|
|
1056
|
+
bool withinBottom = fragCoord.y >= bottom && fragCoord.y <= bottom + thickness;
|
|
1057
|
+
|
|
1058
|
+
bool isOutline = withinLeft || withinRight || withinTop || withinBottom;
|
|
1059
|
+
|
|
1060
|
+
if (isOutline) {
|
|
1061
|
+
color = lineColor;
|
|
1062
|
+
} else {
|
|
1063
|
+
discard;
|
|
1064
|
+
}
|
|
1065
|
+
}`,W0=`#version 300 es
|
|
1066
|
+
#line 490
|
|
1067
|
+
layout(location=0) in vec3 pos;
|
|
1068
|
+
uniform vec2 canvasWidthHeight;
|
|
1069
|
+
uniform vec4 leftTopWidthHeight;
|
|
1070
|
+
out vec2 vColor;
|
|
1071
|
+
void main(void) {
|
|
1072
|
+
//convert pixel x,y space 1..canvasWidth,1..canvasHeight to WebGL 1..-1,-1..1
|
|
1073
|
+
vec2 frac;
|
|
1074
|
+
frac.x = (leftTopWidthHeight.x + (pos.x * leftTopWidthHeight.z)) / canvasWidthHeight.x; //0..1
|
|
1075
|
+
frac.y = 1.0 - ((leftTopWidthHeight.y + ((1.0 - pos.y) * leftTopWidthHeight.w)) / canvasWidthHeight.y); //1..0
|
|
1076
|
+
frac = (frac * 2.0) - 1.0;
|
|
1077
|
+
gl_Position = vec4(frac, 0.0, 1.0);
|
|
1078
|
+
vColor = pos.xy;
|
|
1079
|
+
}`,K0=`#version 300 es
|
|
1080
|
+
#line 506
|
|
1081
|
+
precision highp int;
|
|
1082
|
+
precision highp float;
|
|
1083
|
+
uniform highp sampler2D colormap;
|
|
1084
|
+
uniform float layer;
|
|
1085
|
+
in vec2 vColor;
|
|
1086
|
+
out vec4 color;
|
|
1087
|
+
void main() {
|
|
1088
|
+
float nlayer = float(textureSize(colormap, 0).y);
|
|
1089
|
+
float fmap = (0.5 + layer) / nlayer;
|
|
1090
|
+
color = vec4(texture(colormap, vec2(vColor.x, fmap)).rgb, 1.0);
|
|
1091
|
+
}`,bs=`#version 300 es
|
|
1092
|
+
#line 520
|
|
1093
|
+
layout(location=0) in vec3 pos;
|
|
1094
|
+
uniform vec2 canvasWidthHeight;
|
|
1095
|
+
uniform vec4 leftTopWidthHeight;
|
|
1096
|
+
void main(void) {
|
|
1097
|
+
//convert pixel x,y space 1..canvasWidth,1..canvasHeight to WebGL 1..-1,-1..1
|
|
1098
|
+
vec2 frac;
|
|
1099
|
+
frac.x = (leftTopWidthHeight.x + (pos.x * leftTopWidthHeight.z)) / canvasWidthHeight.x; //0..1
|
|
1100
|
+
frac.y = 1.0 - ((leftTopWidthHeight.y + ((1.0 - pos.y) * leftTopWidthHeight.w)) / canvasWidthHeight.y); //1..0
|
|
1101
|
+
frac = (frac * 2.0) - 1.0;
|
|
1102
|
+
gl_Position = vec4(frac, 0.0, 1.0);
|
|
1103
|
+
}`,H0=`#version 300 es
|
|
1104
|
+
#line 534
|
|
1105
|
+
layout(location=0) in vec3 pos;
|
|
1106
|
+
uniform vec2 canvasWidthHeight;
|
|
1107
|
+
uniform float thickness;
|
|
1108
|
+
uniform vec4 startXYendXY;
|
|
1109
|
+
void main(void) {
|
|
1110
|
+
vec2 posXY = mix(startXYendXY.xy, startXYendXY.zw, pos.x);
|
|
1111
|
+
vec2 dir = normalize(startXYendXY.xy - startXYendXY.zw);
|
|
1112
|
+
posXY += vec2(-dir.y, dir.x) * thickness * (pos.y - 0.5);
|
|
1113
|
+
posXY.x = (posXY.x) / canvasWidthHeight.x; //0..1
|
|
1114
|
+
posXY.y = 1.0 - (posXY.y / canvasWidthHeight.y); //1..0
|
|
1115
|
+
gl_Position = vec4((posXY * 2.0) - 1.0, 0.0, 1.0);
|
|
1116
|
+
}`,q0=`#version 300 es
|
|
1117
|
+
#line 534
|
|
1118
|
+
layout(location=0) in vec3 pos;
|
|
1119
|
+
uniform vec2 canvasWidthHeight;
|
|
1120
|
+
uniform float thickness;
|
|
1121
|
+
uniform vec2 startXY;
|
|
1122
|
+
uniform vec3 endXYZ; // transformed XYZ point
|
|
1123
|
+
void main(void) {
|
|
1124
|
+
vec2 posXY = mix(startXY.xy, endXYZ.xy, pos.x);
|
|
1125
|
+
vec2 startDiff = endXYZ.xy - startXY.xy;
|
|
1126
|
+
float startDistance = length(startDiff);
|
|
1127
|
+
vec2 diff = endXYZ.xy - posXY;
|
|
1128
|
+
float currentDistance = length(diff);
|
|
1129
|
+
vec2 dir = normalize(startXY.xy - endXYZ.xy);
|
|
1130
|
+
posXY += vec2(-dir.y, dir.x) * thickness * (pos.y - 0.5);
|
|
1131
|
+
posXY.x = (posXY.x) / canvasWidthHeight.x; //0..1
|
|
1132
|
+
posXY.y = 1.0 - (posXY.y / canvasWidthHeight.y); //1..0
|
|
1133
|
+
float z = endXYZ.z * ( 1.0 - abs(currentDistance/startDistance));
|
|
1134
|
+
gl_Position = vec4((posXY * 2.0) - 1.0, z, 1.0);
|
|
1135
|
+
}`,Q0=`#version 300 es
|
|
1136
|
+
#line 549
|
|
1137
|
+
layout(location=0) in vec3 pos;
|
|
1138
|
+
uniform vec2 canvasWidthHeight;
|
|
1139
|
+
uniform vec4 leftTopWidthHeight;
|
|
1140
|
+
out vec2 vUV;
|
|
1141
|
+
void main(void) {
|
|
1142
|
+
//convert pixel x,y space 1..canvasWidth,1..canvasHeight to WebGL 1..-1,-1..1
|
|
1143
|
+
vec2 frac;
|
|
1144
|
+
frac.x = (leftTopWidthHeight.x + (pos.x * leftTopWidthHeight.z)) / canvasWidthHeight.x; //0..1
|
|
1145
|
+
frac.y = 1.0 - ((leftTopWidthHeight.y + ((1.0 - pos.y) * leftTopWidthHeight.w)) / canvasWidthHeight.y); //1..0
|
|
1146
|
+
frac = (frac * 2.0) - 1.0;
|
|
1147
|
+
gl_Position = vec4(frac, 0.0, 1.0);
|
|
1148
|
+
vUV = vec2(pos.x, 1.0 - pos.y);
|
|
1149
|
+
}`,Z0=`#version 300 es
|
|
1150
|
+
#line 565
|
|
1151
|
+
precision highp int;
|
|
1152
|
+
precision highp float;
|
|
1153
|
+
uniform highp sampler2D bmpTexture;
|
|
1154
|
+
in vec2 vUV;
|
|
1155
|
+
out vec4 color;
|
|
1156
|
+
void main() {
|
|
1157
|
+
color = texture(bmpTexture, vUV);
|
|
1158
|
+
}`,j0=`#version 300 es
|
|
1159
|
+
#line 576
|
|
1160
|
+
layout(location=0) in vec3 pos;
|
|
1161
|
+
uniform vec2 canvasWidthHeight;
|
|
1162
|
+
uniform vec4 leftTopWidthHeight;
|
|
1163
|
+
uniform vec4 uvLeftTopWidthHeight;
|
|
1164
|
+
out vec2 vUV;
|
|
1165
|
+
void main(void) {
|
|
1166
|
+
//convert pixel x,y space 1..canvasWidth,1..canvasHeight to WebGL 1..-1,-1..1
|
|
1167
|
+
vec2 frac;
|
|
1168
|
+
frac.x = (leftTopWidthHeight.x + (pos.x * leftTopWidthHeight.z)) / canvasWidthHeight.x; //0..1
|
|
1169
|
+
frac.y = 1.0 - ((leftTopWidthHeight.y + ((1.0 - pos.y) * leftTopWidthHeight.w)) / canvasWidthHeight.y); //1..0
|
|
1170
|
+
frac = (frac * 2.0) - 1.0;
|
|
1171
|
+
gl_Position = vec4(frac, 0.0, 1.0);
|
|
1172
|
+
vUV = vec2(uvLeftTopWidthHeight.x + (pos.x * uvLeftTopWidthHeight.z), uvLeftTopWidthHeight.y + ((1.0 - pos.y) * uvLeftTopWidthHeight.w) );
|
|
1173
|
+
}`,_0=`#version 300 es
|
|
1174
|
+
#line 593
|
|
1175
|
+
precision highp int;
|
|
1176
|
+
precision highp float;
|
|
1177
|
+
uniform highp sampler2D fontTexture;
|
|
1178
|
+
uniform vec4 fontColor;
|
|
1179
|
+
uniform float screenPxRange;
|
|
1180
|
+
in vec2 vUV;
|
|
1181
|
+
out vec4 color;
|
|
1182
|
+
float median(float r, float g, float b) {
|
|
1183
|
+
return max(min(r, g), min(max(r, g), b));
|
|
1184
|
+
}
|
|
1185
|
+
void main() {
|
|
1186
|
+
vec3 msd = texture(fontTexture, vUV).rgb;
|
|
1187
|
+
float sd = median(msd.r, msd.g, msd.b);
|
|
1188
|
+
float screenPxDistance = screenPxRange*(sd - 0.5);
|
|
1189
|
+
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
|
|
1190
|
+
color = vec4(fontColor.rgb , fontColor.a * opacity);
|
|
1191
|
+
}`,J0=`#version 300 es
|
|
1192
|
+
layout(location=0) in vec3 pos;
|
|
1193
|
+
uniform vec2 canvasWidthHeight;
|
|
1194
|
+
uniform vec4 leftTopWidthHeight;
|
|
1195
|
+
uniform vec4 uvLeftTopWidthHeight;
|
|
1196
|
+
out vec2 vUV;
|
|
1197
|
+
void main(void) {
|
|
1198
|
+
//convert pixel x,y space 1..canvasWidth,1..canvasHeight to WebGL 1..-1,-1..1
|
|
1199
|
+
vec2 frac;
|
|
1200
|
+
frac.x = (leftTopWidthHeight.x + (pos.x * leftTopWidthHeight.z)) / canvasWidthHeight.x; //0..1
|
|
1201
|
+
frac.y = 1.0 - ((leftTopWidthHeight.y + ((1.0 - pos.y) * leftTopWidthHeight.w)) / canvasWidthHeight.y); //1..0
|
|
1202
|
+
frac = (frac * 2.0) - 1.0;
|
|
1203
|
+
gl_Position = vec4(frac, 0.0, 1.0);
|
|
1204
|
+
vUV = pos.xy;
|
|
1205
|
+
}`,$0=`#version 300 es
|
|
1206
|
+
precision highp int;
|
|
1207
|
+
precision highp float;
|
|
1208
|
+
uniform vec4 circleColor;
|
|
1209
|
+
uniform float fillPercent;
|
|
1210
|
+
in vec2 vUV;
|
|
1211
|
+
out vec4 color;
|
|
1212
|
+
void main() {
|
|
1213
|
+
/* Check if the pixel is inside the circle
|
|
1214
|
+
and color it with a gradient. Otherwise, color it
|
|
1215
|
+
transparent */
|
|
1216
|
+
float distance = length(vUV-vec2(0.5,0.5));
|
|
1217
|
+
if ( distance < 0.5 && distance >= (1.0 - fillPercent) / 2.0){
|
|
1218
|
+
color = vec4(circleColor.r,circleColor.g,circleColor.b,circleColor.a) ;
|
|
1219
|
+
}else{
|
|
1220
|
+
color = vec4(0.0,0.0,0.0,0.0);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
`,Je=`#version 300 es
|
|
1224
|
+
#line 613
|
|
1225
|
+
precision highp int;
|
|
1226
|
+
precision highp float;
|
|
1227
|
+
in vec3 vPos;
|
|
1228
|
+
out vec2 TexCoord;
|
|
1229
|
+
void main() {
|
|
1230
|
+
TexCoord = vPos.xy;
|
|
1231
|
+
gl_Position = vec4( (vPos.xy-vec2(0.5,0.5)) * 2.0, 0.0, 1.0);
|
|
1232
|
+
}`,Ht=`#version 300 es
|
|
1233
|
+
uniform highp usampler3D intensityVol;
|
|
1234
|
+
`,Cs=`#version 300 es
|
|
1235
|
+
uniform highp isampler3D intensityVol;
|
|
1236
|
+
`,ed=`#version 300 es
|
|
1237
|
+
uniform highp sampler3D intensityVol;
|
|
1238
|
+
`,Ms=`#line 1042
|
|
1239
|
+
precision highp int;
|
|
1240
|
+
precision highp float;
|
|
1241
|
+
in vec2 TexCoord;
|
|
1242
|
+
out vec4 FragColor;
|
|
1243
|
+
uniform bool isAdditiveBlend;
|
|
1244
|
+
uniform float coordZ;
|
|
1245
|
+
uniform float layer;
|
|
1246
|
+
uniform highp sampler2D colormap;
|
|
1247
|
+
uniform lowp sampler3D blend3D;
|
|
1248
|
+
uniform float opacity;
|
|
1249
|
+
uniform uint activeIndex;
|
|
1250
|
+
uniform vec4 xyzaFrac;
|
|
1251
|
+
uniform mat4 mtx;
|
|
1252
|
+
float textureWidth;
|
|
1253
|
+
float nlayer;
|
|
1254
|
+
float layerY;
|
|
1255
|
+
|
|
1256
|
+
vec4 scalar2color(uint idx) {
|
|
1257
|
+
float fx = (float(idx) + 0.5) / textureWidth;
|
|
1258
|
+
vec4 clr = texture(colormap, vec2(fx, layerY)).rgba;
|
|
1259
|
+
if (clr.a > 0.0)
|
|
1260
|
+
clr.a = 1.0;
|
|
1261
|
+
clr.a *= opacity;
|
|
1262
|
+
return clr;
|
|
1263
|
+
}
|
|
1264
|
+
void main(void) {
|
|
1265
|
+
vec4 vx = vec4(TexCoord.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1266
|
+
uint idx = uint(texture(intensityVol, vx.xyz).r);
|
|
1267
|
+
if (idx == uint(0)) {
|
|
1268
|
+
if (layer < 1.0) {
|
|
1269
|
+
FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
FragColor = texture(blend3D, vec3(TexCoord.xy, coordZ));
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
textureWidth = float(textureSize(colormap, 0).x);
|
|
1276
|
+
nlayer = float(textureSize(colormap, 0).y);
|
|
1277
|
+
layerY = ((2.0 * layer) + 1.5) / nlayer;
|
|
1278
|
+
//idx = ((idx - uint(1)) % uint(100))+uint(1);
|
|
1279
|
+
FragColor = scalar2color(idx);
|
|
1280
|
+
bool isBorder = false;
|
|
1281
|
+
vx = vec4(TexCoord.x+xyzaFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1282
|
+
uint R = uint(texture(intensityVol, vx.xyz).r);
|
|
1283
|
+
vx = vec4(TexCoord.x-xyzaFrac.x, TexCoord.y, coordZ, 1.0) * mtx;
|
|
1284
|
+
uint L = uint(texture(intensityVol, vx.xyz).r);
|
|
1285
|
+
vx = vec4(TexCoord.x, TexCoord.y+xyzaFrac.y, coordZ, 1.0) * mtx;
|
|
1286
|
+
uint A = uint(texture(intensityVol, vx.xyz).r);
|
|
1287
|
+
vx = vec4(TexCoord.x, TexCoord.y-xyzaFrac.y, coordZ, 1.0) * mtx;
|
|
1288
|
+
uint P = uint(texture(intensityVol, vx.xyz).r);
|
|
1289
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ+xyzaFrac.z, 1.0) * mtx;
|
|
1290
|
+
uint S = uint(texture(intensityVol, vx.xyz).r);
|
|
1291
|
+
vx = vec4(TexCoord.x, TexCoord.y, coordZ-xyzaFrac.z, 1.0) * mtx;
|
|
1292
|
+
uint I = uint(texture(intensityVol, vx.xyz).r);
|
|
1293
|
+
vec4 centerColor = FragColor;
|
|
1294
|
+
FragColor.a += scalar2color(R).a;
|
|
1295
|
+
FragColor.a += scalar2color(L).a;
|
|
1296
|
+
FragColor.a += scalar2color(A).a;
|
|
1297
|
+
FragColor.a += scalar2color(P).a;
|
|
1298
|
+
FragColor.a += scalar2color(S).a;
|
|
1299
|
+
FragColor.a += scalar2color(I).a;
|
|
1300
|
+
FragColor.a /= 7.0;
|
|
1301
|
+
if ((!isBorder) &&(idx == activeIndex)) {
|
|
1302
|
+
if (centerColor.a > 0.5)
|
|
1303
|
+
FragColor.a *= 0.4;
|
|
1304
|
+
else
|
|
1305
|
+
FragColor.a =0.8;
|
|
1306
|
+
}
|
|
1307
|
+
if (xyzaFrac.a != 0.0) { //outline
|
|
1308
|
+
if ((idx != R) || (idx != L) || (idx != A) || (idx != P) || (idx != S) || (idx != I)) {
|
|
1309
|
+
isBorder = true;
|
|
1310
|
+
if (xyzaFrac.a > 0.0)
|
|
1311
|
+
FragColor.a = xyzaFrac.a;
|
|
1312
|
+
else
|
|
1313
|
+
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
if (layer < 1.0) return;
|
|
1317
|
+
vec4 prevColor = texture(blend3D, vec3(TexCoord.xy, coordZ));
|
|
1318
|
+
// https://en.wikipedia.org/wiki/Alpha_compositing
|
|
1319
|
+
float aout = FragColor.a + (1.0 - FragColor.a) * prevColor.a;
|
|
1320
|
+
if (aout <= 0.0) return;
|
|
1321
|
+
if (isAdditiveBlend)
|
|
1322
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a)) / aout;
|
|
1323
|
+
else
|
|
1324
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a * (1.0 - FragColor.a))) / aout;
|
|
1325
|
+
FragColor.a = aout;
|
|
1326
|
+
}`,Li=`#line 691
|
|
1327
|
+
precision highp int;
|
|
1328
|
+
precision highp float;
|
|
1329
|
+
in vec2 TexCoord;
|
|
1330
|
+
out vec4 FragColor;
|
|
1331
|
+
uniform float coordZ;
|
|
1332
|
+
uniform float layer;
|
|
1333
|
+
uniform float scl_slope;
|
|
1334
|
+
uniform float scl_inter;
|
|
1335
|
+
uniform float cal_max;
|
|
1336
|
+
uniform float cal_min;
|
|
1337
|
+
uniform float cal_maxNeg;
|
|
1338
|
+
uniform float cal_minNeg;
|
|
1339
|
+
uniform bool isAlphaThreshold;
|
|
1340
|
+
uniform bool isColorbarFromZero;
|
|
1341
|
+
uniform bool isAdditiveBlend;
|
|
1342
|
+
uniform highp sampler2D colormap;
|
|
1343
|
+
uniform lowp sampler3D blend3D;
|
|
1344
|
+
uniform int modulation;
|
|
1345
|
+
uniform highp sampler3D modulationVol;
|
|
1346
|
+
uniform float opacity;
|
|
1347
|
+
uniform mat4 mtx;
|
|
1348
|
+
void main(void) {
|
|
1349
|
+
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
1350
|
+
if ((vx.x < 0.0) || (vx.x > 1.0) || (vx.y < 0.0) || (vx.y > 1.0) || (vx.z < 0.0) || (vx.z > 1.0)) {
|
|
1351
|
+
//set transparent if out of range
|
|
1352
|
+
//https://webglfundamentals.org/webgl/webgl-3d-textures-repeat-clamp.html
|
|
1353
|
+
FragColor = texture(blend3D, vec3(TexCoord.xy, coordZ));
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
float f = (scl_slope * float(texture(intensityVol, vx.xyz).r)) + scl_inter;
|
|
1357
|
+
float mn = cal_min;
|
|
1358
|
+
float mx = cal_max;
|
|
1359
|
+
if ((isAlphaThreshold) || (isColorbarFromZero))
|
|
1360
|
+
mn = 0.0;
|
|
1361
|
+
float r = max(0.00001, abs(mx - mn));
|
|
1362
|
+
mn = min(mn, mx);
|
|
1363
|
+
float txl = mix(0.0, 1.0, (f - mn) / r);
|
|
1364
|
+
if (f > mn) { //issue1139: survives threshold, so round up to opaque voxel
|
|
1365
|
+
txl = max(txl, 2.0/256.0);
|
|
1366
|
+
}
|
|
1367
|
+
//https://stackoverflow.com/questions/5879403/opengl-texture-coordinates-in-pixel-space
|
|
1368
|
+
float nlayer = float(textureSize(colormap, 0).y);
|
|
1369
|
+
//each volume has two color maps:
|
|
1370
|
+
// (layer*2) = negative and (layer * 2) + 1 = positive
|
|
1371
|
+
float y = ((2.0 * layer) + 1.5)/nlayer;
|
|
1372
|
+
FragColor = texture(colormap, vec2(txl, y)).rgba;
|
|
1373
|
+
//negative colors
|
|
1374
|
+
mn = cal_minNeg;
|
|
1375
|
+
mx = cal_maxNeg;
|
|
1376
|
+
if ((isAlphaThreshold) || (isColorbarFromZero))
|
|
1377
|
+
mx = 0.0;
|
|
1378
|
+
//if ((!isnan(cal_minNeg)) && ( f < mx)) {
|
|
1379
|
+
if ((cal_minNeg < cal_maxNeg) && ( f < mx)) {
|
|
1380
|
+
r = max(0.00001, abs(mx - mn));
|
|
1381
|
+
mn = min(mn, mx);
|
|
1382
|
+
txl = 1.0 - mix(0.0, 1.0, (f - mn) / r);
|
|
1383
|
+
//issue1139: survives threshold, so round up to opaque voxel
|
|
1384
|
+
txl = max(txl, 2.0/256.0);
|
|
1385
|
+
y = ((2.0 * layer) + 0.5)/nlayer;
|
|
1386
|
+
FragColor = texture(colormap, vec2(txl, y));
|
|
1387
|
+
}
|
|
1388
|
+
if (layer > 0.7)
|
|
1389
|
+
FragColor.a = step(0.00001, FragColor.a);
|
|
1390
|
+
//if (modulation > 10)
|
|
1391
|
+
// FragColor.a *= texture(modulationVol, vx.xyz).r;
|
|
1392
|
+
// FragColor.rgb *= texture(modulationVol, vx.xyz).r;
|
|
1393
|
+
if (isAlphaThreshold) {
|
|
1394
|
+
if ((cal_minNeg != cal_maxNeg) && ( f < 0.0) && (f > cal_maxNeg))
|
|
1395
|
+
FragColor.a = pow(-f / -cal_maxNeg, 2.0);
|
|
1396
|
+
else if ((f > 0.0) && (cal_min > 0.0))
|
|
1397
|
+
FragColor.a *= pow(f / cal_min, 2.0); //issue435: A = (V/X)**2
|
|
1398
|
+
//FragColor.g = 0.0;
|
|
1399
|
+
} else if (isColorbarFromZero) {
|
|
1400
|
+
if ((cal_minNeg != cal_maxNeg) && ( f < 0.0) && (f > cal_maxNeg))
|
|
1401
|
+
FragColor.a = 0.0;
|
|
1402
|
+
else if ((f > 0.0) && (cal_min > 0.0) && (f < cal_min))
|
|
1403
|
+
FragColor.a *= 0.0;
|
|
1404
|
+
|
|
1405
|
+
}
|
|
1406
|
+
if (modulation == 1) {
|
|
1407
|
+
FragColor.rgb *= texture(modulationVol, vx.xyz).r;
|
|
1408
|
+
} else if (modulation == 2) {
|
|
1409
|
+
FragColor.a = texture(modulationVol, vx.xyz).r;
|
|
1410
|
+
}
|
|
1411
|
+
FragColor.a *= opacity;
|
|
1412
|
+
if (layer < 1.0) return;
|
|
1413
|
+
vec4 prevColor = texture(blend3D, vec3(TexCoord.xy, coordZ));
|
|
1414
|
+
// https://en.wikipedia.org/wiki/Alpha_compositing
|
|
1415
|
+
float aout = FragColor.a + (1.0 - FragColor.a) * prevColor.a;
|
|
1416
|
+
if (aout <= 0.0) return;
|
|
1417
|
+
if (isAdditiveBlend)
|
|
1418
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a)) / aout;
|
|
1419
|
+
else
|
|
1420
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a * (1.0 - FragColor.a))) / aout;
|
|
1421
|
+
FragColor.a = aout;
|
|
1422
|
+
}`,td=`#line 773
|
|
1423
|
+
precision highp int;
|
|
1424
|
+
precision highp float;
|
|
1425
|
+
in vec2 TexCoord;
|
|
1426
|
+
out vec4 FragColor;
|
|
1427
|
+
uniform float coordZ;
|
|
1428
|
+
uniform float layer;
|
|
1429
|
+
uniform float scl_slope;
|
|
1430
|
+
uniform float scl_inter;
|
|
1431
|
+
uniform float cal_max;
|
|
1432
|
+
uniform float cal_min;
|
|
1433
|
+
uniform highp sampler2D colormap;
|
|
1434
|
+
uniform lowp sampler3D blend3D;
|
|
1435
|
+
uniform float opacity;
|
|
1436
|
+
uniform mat4 mtx;
|
|
1437
|
+
uniform bool hasAlpha;
|
|
1438
|
+
uniform int modulation;
|
|
1439
|
+
uniform highp sampler3D modulationVol;
|
|
1440
|
+
float textureWidth;
|
|
1441
|
+
float nlayer;
|
|
1442
|
+
float layerY;
|
|
1443
|
+
|
|
1444
|
+
vec4 scalar2color(uint idx) {
|
|
1445
|
+
float fx = (float(idx) + 0.5) / textureWidth;
|
|
1446
|
+
vec4 clr = texture(colormap, vec2(fx, layerY)).rgba;
|
|
1447
|
+
if (clr.a > 0.0)
|
|
1448
|
+
clr.a = 1.0;
|
|
1449
|
+
clr.a *= opacity;
|
|
1450
|
+
return clr;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
vec4 paqd2color(uvec4 rgba) {
|
|
1454
|
+
// paqd r: max prob index, g: 2nd index, b: max prob a: 2nd prob
|
|
1455
|
+
float prob1 = float(rgba.b)/255.0;
|
|
1456
|
+
float prob2 = float(rgba.a)/255.0;
|
|
1457
|
+
vec4 clr1 = scalar2color(rgba.r);
|
|
1458
|
+
vec4 clr2 = scalar2color(rgba.g);
|
|
1459
|
+
float total = prob1 + prob2;
|
|
1460
|
+
vec4 clr = vec4(clr1.rgb, total);
|
|
1461
|
+
// vec4 clr = vec4(clr1.rgb, prob1);
|
|
1462
|
+
if (total > 0.0) {
|
|
1463
|
+
clr.rgb = mix(clr2.rgb, clr1.rgb, prob1 / total);
|
|
1464
|
+
}
|
|
1465
|
+
return clr;
|
|
1466
|
+
}
|
|
1467
|
+
void main(void) {
|
|
1468
|
+
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
1469
|
+
ivec3 voxelCoord = ivec3(vx.xyz * vec3(textureSize(intensityVol, 0)));
|
|
1470
|
+
uvec4 rgba = texelFetch(intensityVol, voxelCoord, 0);
|
|
1471
|
+
FragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
1472
|
+
if (rgba.r > uint(0)) {
|
|
1473
|
+
textureWidth = float(textureSize(colormap, 0).x);
|
|
1474
|
+
nlayer = float(textureSize(colormap, 0).y);
|
|
1475
|
+
layerY = ((2.0 * layer) + 1.5) / nlayer;
|
|
1476
|
+
FragColor = paqd2color(rgba);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
// if (layer > 2.0) return;
|
|
1480
|
+
// FragColor = texture(blend3D, vec3(TexCoord.xy, coordZ));
|
|
1481
|
+
}`,id=`#line 773
|
|
1482
|
+
precision highp int;
|
|
1483
|
+
precision highp float;
|
|
1484
|
+
in vec2 TexCoord;
|
|
1485
|
+
out vec4 FragColor;
|
|
1486
|
+
uniform float coordZ;
|
|
1487
|
+
uniform float layer;
|
|
1488
|
+
uniform float scl_slope;
|
|
1489
|
+
uniform float scl_inter;
|
|
1490
|
+
uniform float cal_max;
|
|
1491
|
+
uniform float cal_min;
|
|
1492
|
+
uniform highp sampler2D colormap;
|
|
1493
|
+
uniform lowp sampler3D blend3D;
|
|
1494
|
+
uniform float opacity;
|
|
1495
|
+
uniform mat4 mtx;
|
|
1496
|
+
uniform bool hasAlpha;
|
|
1497
|
+
uniform int modulation;
|
|
1498
|
+
uniform highp sampler3D modulationVol;
|
|
1499
|
+
void main(void) {
|
|
1500
|
+
vec4 vx = vec4(TexCoord.xy, coordZ, 1.0) * mtx;
|
|
1501
|
+
uvec4 aColor = texture(intensityVol, vx.xyz);
|
|
1502
|
+
FragColor = vec4(float(aColor.r) / 255.0, float(aColor.g) / 255.0, float(aColor.b) / 255.0, float(aColor.a) / 255.0);
|
|
1503
|
+
if (modulation == 1)
|
|
1504
|
+
FragColor.rgb *= texture(modulationVol, vx.xyz).r;
|
|
1505
|
+
if (!hasAlpha) {
|
|
1506
|
+
FragColor.a = (FragColor.r * 0.21 + FragColor.g * 0.72 + FragColor.b * 0.07);
|
|
1507
|
+
//next line: we could binarize alpha, but see rendering of visible human
|
|
1508
|
+
//FragColor.a = step(0.01, FragColor.a);
|
|
1509
|
+
}
|
|
1510
|
+
if (modulation == 2)
|
|
1511
|
+
FragColor.a = texture(modulationVol, vx.xyz).r;
|
|
1512
|
+
FragColor.a *= opacity;
|
|
1513
|
+
if (layer < 1.0) return;
|
|
1514
|
+
vec4 prevColor = texture(blend3D, vec3(TexCoord.xy, coordZ));
|
|
1515
|
+
// https://en.wikipedia.org/wiki/Alpha_compositing
|
|
1516
|
+
float aout = FragColor.a + (1.0 - FragColor.a) * prevColor.a;
|
|
1517
|
+
if (aout <= 0.0) return;
|
|
1518
|
+
FragColor.rgb = ((FragColor.rgb * FragColor.a) + (prevColor.rgb * prevColor.a * (1.0 - FragColor.a))) / aout;
|
|
1519
|
+
FragColor.a = aout;
|
|
1520
|
+
}`,rd=`#version 300 es
|
|
1521
|
+
#line 808
|
|
1522
|
+
precision highp int;
|
|
1523
|
+
precision highp float;
|
|
1524
|
+
in vec3 vPos;
|
|
1525
|
+
out vec2 TexCoord;
|
|
1526
|
+
void main() {
|
|
1527
|
+
TexCoord = vPos.xy;
|
|
1528
|
+
gl_Position = vec4((vPos.x - 0.5) * 2.0, (vPos.y - 0.5) * 2.0, 0.0, 1.0);
|
|
1529
|
+
}`,sd=`#version 300 es
|
|
1530
|
+
#line 829
|
|
1531
|
+
precision highp float;
|
|
1532
|
+
precision highp int;
|
|
1533
|
+
precision highp isampler3D;
|
|
1534
|
+
layout(location = 0) out int label;
|
|
1535
|
+
layout(location = 1) out int strength;
|
|
1536
|
+
in vec2 TexCoord;
|
|
1537
|
+
uniform int finalPass;
|
|
1538
|
+
uniform float coordZ;
|
|
1539
|
+
uniform lowp sampler3D in3D;
|
|
1540
|
+
uniform highp isampler3D backTex; // background
|
|
1541
|
+
uniform highp isampler3D labelTex; // label
|
|
1542
|
+
uniform highp isampler3D strengthTex; // strength
|
|
1543
|
+
void main(void) {
|
|
1544
|
+
vec3 interpolatedTextureCoordinate = vec3(TexCoord.xy, coordZ);
|
|
1545
|
+
ivec3 size = textureSize(backTex, 0);
|
|
1546
|
+
ivec3 texelIndex = ivec3(floor(interpolatedTextureCoordinate * vec3(size)));
|
|
1547
|
+
int background = texelFetch(backTex, texelIndex, 0).r;
|
|
1548
|
+
label = texelFetch(labelTex, texelIndex, 0).r;
|
|
1549
|
+
strength = texelFetch(strengthTex, texelIndex, 0).r;
|
|
1550
|
+
for (int k = -1; k <= 1; k++) {
|
|
1551
|
+
for (int j = -1; j <= 1; j++) {
|
|
1552
|
+
for (int i = -1; i <= 1; i++) {
|
|
1553
|
+
if (i != 0 && j != 0 && k != 0) {
|
|
1554
|
+
ivec3 neighborIndex = texelIndex + ivec3(i,j,k);
|
|
1555
|
+
int neighborBackground = texelFetch(backTex, neighborIndex, 0).r;
|
|
1556
|
+
int neighborStrength = texelFetch(strengthTex, neighborIndex, 0).r;
|
|
1557
|
+
int strengthCost = abs(neighborBackground - background);
|
|
1558
|
+
int takeoverStrength = neighborStrength - strengthCost;
|
|
1559
|
+
if (takeoverStrength > strength) {
|
|
1560
|
+
strength = takeoverStrength;
|
|
1561
|
+
label = texelFetch(labelTex, neighborIndex, 0).r;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
if (finalPass < 1)
|
|
1568
|
+
return;
|
|
1569
|
+
int ok = 1;
|
|
1570
|
+
ivec4 labelCount = ivec4(0,0,0,0);
|
|
1571
|
+
for (int k = -1; k <= 1; k++)
|
|
1572
|
+
for (int j = -1; j <= 1; j++)
|
|
1573
|
+
for (int i = -1; i <= 1; i++) {
|
|
1574
|
+
ivec3 neighborIndex = texelIndex + ivec3(i,j,k);
|
|
1575
|
+
int ilabel = texelFetch(labelTex, neighborIndex, 0).r;
|
|
1576
|
+
if ((ilabel < 0) || (ilabel > 3))
|
|
1577
|
+
ok = 0;
|
|
1578
|
+
else
|
|
1579
|
+
labelCount[ilabel]++;
|
|
1580
|
+
}
|
|
1581
|
+
if (ok != 1) {
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
int maxIdx = 0;
|
|
1585
|
+
for (int i = 1; i < 4; i++) {
|
|
1586
|
+
if (labelCount[i] > labelCount[maxIdx])
|
|
1587
|
+
maxIdx = i;
|
|
1588
|
+
}
|
|
1589
|
+
label = maxIdx;
|
|
1590
|
+
}`,nd=`#version 300 es
|
|
1591
|
+
layout(location=0) in vec3 pos;
|
|
1592
|
+
uniform mat4 mvpMtx;
|
|
1593
|
+
void main(void) {
|
|
1594
|
+
gl_Position = mvpMtx * vec4(pos, 1.0);
|
|
1595
|
+
}`,ad=`#version 300 es
|
|
1596
|
+
precision highp int;
|
|
1597
|
+
precision highp float;
|
|
1598
|
+
uniform vec4 surfaceColor;
|
|
1599
|
+
out vec4 color;
|
|
1600
|
+
void main() {
|
|
1601
|
+
color = surfaceColor;
|
|
1602
|
+
}`,od=`#version 300 es
|
|
1603
|
+
layout(location=0) in vec3 pos;
|
|
1604
|
+
layout(location=1) in vec4 clr;
|
|
1605
|
+
out vec4 vClr;
|
|
1606
|
+
uniform mat4 mvpMtx;
|
|
1607
|
+
void main(void) {
|
|
1608
|
+
gl_Position = mvpMtx * vec4(pos, 1.0);
|
|
1609
|
+
vClr = clr;
|
|
1610
|
+
}`,ld=`#version 300 es
|
|
1611
|
+
precision highp int;
|
|
1612
|
+
precision highp float;
|
|
1613
|
+
in vec4 vClr;
|
|
1614
|
+
out vec4 color;
|
|
1615
|
+
uniform float opacity;
|
|
1616
|
+
void main() {
|
|
1617
|
+
color = vec4(vClr.rgb, opacity);
|
|
1618
|
+
}`,Pr=`#version 300 es
|
|
1619
|
+
layout(location=0) in vec3 pos;
|
|
1620
|
+
layout(location=1) in vec4 norm;
|
|
1621
|
+
layout(location=2) in vec4 clr;
|
|
1622
|
+
uniform mat4 mvpMtx;
|
|
1623
|
+
//uniform mat4 modelMtx;
|
|
1624
|
+
uniform mat4 normMtx;
|
|
1625
|
+
out vec4 vClr;
|
|
1626
|
+
out vec3 vN;
|
|
1627
|
+
out vec4 vP;
|
|
1628
|
+
out vec4 vPc;
|
|
1629
|
+
void main(void) {
|
|
1630
|
+
vec3 lightPosition = vec3(0.0, 0.0, -10.0);
|
|
1631
|
+
vP = vec4(pos, 1.0);
|
|
1632
|
+
vPc = mvpMtx * vec4(pos, 1.0);
|
|
1633
|
+
gl_Position = vPc;
|
|
1634
|
+
vN = normalize((normMtx * vec4(norm.xyz,1.0)).xyz);
|
|
1635
|
+
//vV = -vec3(modelMtx*vec4(pos,1.0));
|
|
1636
|
+
vClr = clr;
|
|
1637
|
+
}`,cd=`#version 300 es
|
|
1638
|
+
precision highp int;
|
|
1639
|
+
precision highp float;
|
|
1640
|
+
uniform float opacity;
|
|
1641
|
+
out vec4 color;
|
|
1642
|
+
vec4 packFloatToVec4i(const float value) {
|
|
1643
|
+
const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
|
|
1644
|
+
const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
|
|
1645
|
+
vec4 res = fract(value * bitSh);
|
|
1646
|
+
res -= res.xxyz * bitMsk;
|
|
1647
|
+
return res;
|
|
1648
|
+
}
|
|
1649
|
+
void main() {
|
|
1650
|
+
color = packFloatToVec4i(gl_FragCoord.z);
|
|
1651
|
+
}`,hd=`#version 300 es
|
|
1652
|
+
precision highp int;
|
|
1653
|
+
precision highp float;
|
|
1654
|
+
uniform float opacity;
|
|
1655
|
+
in vec4 vClr;
|
|
1656
|
+
in vec3 vN;
|
|
1657
|
+
out vec4 color;
|
|
1658
|
+
float stepmix(float edge0, float edge1, float E, float x){
|
|
1659
|
+
float T = clamp(0.5 * (x - edge0 + E) / E, 0.0, 1.0);
|
|
1660
|
+
return mix(edge0, edge1, T);
|
|
1661
|
+
}
|
|
1662
|
+
void main() {
|
|
1663
|
+
vec3 r = vec3(0.0, 0.0, 1.0);
|
|
1664
|
+
float ambient = 0.3;
|
|
1665
|
+
float diffuse = 0.6;
|
|
1666
|
+
float specular = 0.5;
|
|
1667
|
+
float shininess = 50.0;
|
|
1668
|
+
vec3 n = normalize(vN);
|
|
1669
|
+
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
1670
|
+
vec3 l = normalize(lightPosition);
|
|
1671
|
+
float df = max(0.0, dot(n, l));
|
|
1672
|
+
float sf = pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1673
|
+
const float A = 0.1;
|
|
1674
|
+
const float B = 0.3;
|
|
1675
|
+
const float C = 0.6;
|
|
1676
|
+
const float D = 1.0;
|
|
1677
|
+
float E = fwidth(df);
|
|
1678
|
+
if (df > A - E && df < A + E) df = stepmix(A, B, E, df);
|
|
1679
|
+
else if (df > B - E && df < B + E) df = stepmix(B, C, E, df);
|
|
1680
|
+
else if (df > C - E && df < C + E) df = stepmix(C, D, E, df);
|
|
1681
|
+
else if (df < A) df = 0.0;
|
|
1682
|
+
else if (df < B) df = B;
|
|
1683
|
+
else if (df < C) df = C;
|
|
1684
|
+
else df = D;
|
|
1685
|
+
E = fwidth(sf);
|
|
1686
|
+
if (sf > 0.5 - E && sf < 0.5 + E)
|
|
1687
|
+
sf = smoothstep(0.5 - E, 0.5 + E, sf);
|
|
1688
|
+
else
|
|
1689
|
+
sf = step(0.5, sf);
|
|
1690
|
+
vec3 a = vClr.rgb * ambient;
|
|
1691
|
+
vec3 d = max(df, 0.0) * vClr.rgb * diffuse;
|
|
1692
|
+
color.rgb = a + d + (specular * sf);
|
|
1693
|
+
color.a = opacity;
|
|
1694
|
+
}`,dd=`#version 300 es
|
|
1695
|
+
precision highp int;
|
|
1696
|
+
precision highp float;
|
|
1697
|
+
uniform float opacity;
|
|
1698
|
+
in vec4 vClr;
|
|
1699
|
+
in vec3 vN;
|
|
1700
|
+
out vec4 color;
|
|
1701
|
+
void main() {
|
|
1702
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1703
|
+
float ambient = 0.3;
|
|
1704
|
+
float diffuse = 0.6;
|
|
1705
|
+
float specular = 0.25;
|
|
1706
|
+
float shininess = 10.0;
|
|
1707
|
+
float PenWidth = 0.6;
|
|
1708
|
+
vec3 n = normalize(vN);
|
|
1709
|
+
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
1710
|
+
vec3 l = normalize(lightPosition);
|
|
1711
|
+
float lightNormDot = dot(n, l);
|
|
1712
|
+
float view = abs(dot(n,r)); //with respect to viewer
|
|
1713
|
+
if (PenWidth < view) discard;
|
|
1714
|
+
vec3 a = vClr.rgb * ambient;
|
|
1715
|
+
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1716
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1717
|
+
color.rgb = a + d + s;
|
|
1718
|
+
color.a = opacity;
|
|
1719
|
+
}`,fd=`#version 300 es
|
|
1720
|
+
precision highp int;
|
|
1721
|
+
precision highp float;
|
|
1722
|
+
uniform float opacity;
|
|
1723
|
+
in vec4 vClr;
|
|
1724
|
+
in vec3 vN;
|
|
1725
|
+
out vec4 color;
|
|
1726
|
+
void main() {
|
|
1727
|
+
const float thresh = 0.4;
|
|
1728
|
+
const vec3 viewDir = vec3(0.0, 0.0, -1.0);
|
|
1729
|
+
vec3 n = normalize(vN);
|
|
1730
|
+
// use abs() for two-sided lighting, max() for one sided
|
|
1731
|
+
float cosTheta = abs(dot(n, viewDir));
|
|
1732
|
+
// float cosTheta = max(dot(n, viewDir), 0.0);
|
|
1733
|
+
// optional fresnel equation - adjust exponent
|
|
1734
|
+
// cosTheta = 1.0 - pow(1.0 - cosTheta, 2.0);
|
|
1735
|
+
// use step for binary edges, smoothstep for feathered edges
|
|
1736
|
+
// vec3 d = step(thresh, cosTheta) * vClr.rgb;
|
|
1737
|
+
vec3 d = smoothstep(thresh - 0.05, thresh + 0.05, cosTheta) * vClr.rgb;
|
|
1738
|
+
color = vec4(d, opacity);
|
|
1739
|
+
}`,ud=`#version 300 es
|
|
1740
|
+
precision highp int;
|
|
1741
|
+
precision highp float;
|
|
1742
|
+
uniform float opacity;
|
|
1743
|
+
in vec4 vClr;
|
|
1744
|
+
in vec3 vN;
|
|
1745
|
+
out vec4 color;
|
|
1746
|
+
void main() {
|
|
1747
|
+
const float edge0 = 0.1;
|
|
1748
|
+
const float edge1 = 0.25;
|
|
1749
|
+
const vec3 viewDir = vec3(0.0, 0.0, -1.0);
|
|
1750
|
+
vec3 n = normalize(vN);
|
|
1751
|
+
float cosTheta = abs(dot(n, viewDir));
|
|
1752
|
+
float alpha = 1.0 - smoothstep(edge0, edge1, cosTheta);
|
|
1753
|
+
if (alpha <= 0.0) {
|
|
1754
|
+
discard;
|
|
1755
|
+
}
|
|
1756
|
+
color = vec4(0.0, 0.0, 0.0, opacity * alpha);
|
|
1757
|
+
}`,md=`#version 300 es
|
|
1758
|
+
precision highp int;
|
|
1759
|
+
precision highp float;
|
|
1760
|
+
uniform float opacity;
|
|
1761
|
+
in vec4 vClr;
|
|
1762
|
+
in vec3 vN;
|
|
1763
|
+
out vec4 color;
|
|
1764
|
+
void main() {
|
|
1765
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1766
|
+
float diffuse = 1.0;
|
|
1767
|
+
float specular = 0.2;
|
|
1768
|
+
float shininess = 10.0;
|
|
1769
|
+
vec3 n = normalize(vN);
|
|
1770
|
+
vec3 lightPosition = vec3(0.0, 0.0, -5.0);
|
|
1771
|
+
vec3 l = normalize(lightPosition);
|
|
1772
|
+
float lightNormDot = max(dot(n, l), 0.0);
|
|
1773
|
+
vec3 d = lightNormDot * vClr.rgb * diffuse;
|
|
1774
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1775
|
+
color = vec4(d + s, opacity);
|
|
1776
|
+
}`,pd=`#version 300 es
|
|
1777
|
+
precision highp int;
|
|
1778
|
+
precision highp float;
|
|
1779
|
+
uniform float opacity;
|
|
1780
|
+
in vec4 vClr;
|
|
1781
|
+
in vec3 vN;
|
|
1782
|
+
out vec4 color;
|
|
1783
|
+
void main() {
|
|
1784
|
+
float diffuse = 1.4;
|
|
1785
|
+
vec3 l = vec3(0.0, 0.0, -1.0);
|
|
1786
|
+
float lightNormDot = max(dot(normalize(vN), l), 0.0);
|
|
1787
|
+
color = vec4(lightNormDot * vClr.rgb * diffuse, opacity);
|
|
1788
|
+
}`,gd=`#version 300 es
|
|
1789
|
+
precision highp int;
|
|
1790
|
+
precision highp float;
|
|
1791
|
+
uniform float opacity;
|
|
1792
|
+
in vec4 vClr;
|
|
1793
|
+
in vec3 vN;
|
|
1794
|
+
out vec4 color;
|
|
1795
|
+
void main() {
|
|
1796
|
+
float specularRGB = 0.7;
|
|
1797
|
+
float specularWhite = 0.3;
|
|
1798
|
+
float shininess = 10.0;
|
|
1799
|
+
float diffuse = 1.0;
|
|
1800
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1801
|
+
vec3 n = normalize(vN);
|
|
1802
|
+
vec3 l = vec3(0.0, 0.0, -1.0);
|
|
1803
|
+
float lightNormDot = max(dot(n, l), 0.0);
|
|
1804
|
+
vec3 d3 = lightNormDot * vClr.rgb * diffuse;
|
|
1805
|
+
float s = pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1806
|
+
vec3 s3 = specularRGB * s * vClr.rgb;
|
|
1807
|
+
s *= specularWhite;
|
|
1808
|
+
color = vec4(d3 + s3 + s, opacity);
|
|
1809
|
+
}`,Ad=`#version 300 es
|
|
1810
|
+
precision highp int;
|
|
1811
|
+
precision highp float;
|
|
1812
|
+
uniform float opacity;
|
|
1813
|
+
in vec4 vClr;
|
|
1814
|
+
in vec3 vN;
|
|
1815
|
+
in vec4 vPc;
|
|
1816
|
+
out vec4 color;
|
|
1817
|
+
void main() {
|
|
1818
|
+
vec3 n = normalize(vN);
|
|
1819
|
+
// Compute curvature
|
|
1820
|
+
vec3 dx = dFdx(n);
|
|
1821
|
+
vec3 dy = dFdy(n);
|
|
1822
|
+
vec3 xneg = n - dx;
|
|
1823
|
+
vec3 xpos = n + dx;
|
|
1824
|
+
vec3 yneg = n - dy;
|
|
1825
|
+
vec3 ypos = n + dy;
|
|
1826
|
+
float depth = length(vPc.xyz);
|
|
1827
|
+
float curv = (cross(xneg, xpos).y - cross(yneg, ypos).x) / depth;
|
|
1828
|
+
//at this stage 0.5 for flat, with valleys dark and ridges bright
|
|
1829
|
+
curv = 1.0 - (curv + 0.5);
|
|
1830
|
+
//clamp
|
|
1831
|
+
curv = min(max(curv, 0.0), 1.0);
|
|
1832
|
+
// easing function
|
|
1833
|
+
curv = pow(curv, 0.5);
|
|
1834
|
+
//modulate ambient and diffuse with curvature
|
|
1835
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1836
|
+
float ambient = 0.6;
|
|
1837
|
+
float diffuse = 0.6;
|
|
1838
|
+
float specular = 0.2;
|
|
1839
|
+
float shininess = 10.0;
|
|
1840
|
+
vec3 lightPosition = vec3(0.0, 10.0, -2.0);
|
|
1841
|
+
vec3 l = normalize(lightPosition);
|
|
1842
|
+
float lightNormDot = dot(n, l);
|
|
1843
|
+
vec3 a = vClr.rgb * ambient * curv;
|
|
1844
|
+
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1845
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1846
|
+
color = vec4(a + d + s, opacity);
|
|
1847
|
+
}`,xd=`#version 300 es
|
|
1848
|
+
precision highp int;
|
|
1849
|
+
precision highp float;
|
|
1850
|
+
uniform vec4 sliceMM;
|
|
1851
|
+
uniform float thickMM ;
|
|
1852
|
+
in vec4 vClr;
|
|
1853
|
+
in vec4 vP; // vertex position in mm
|
|
1854
|
+
out vec4 color;
|
|
1855
|
+
void main() {
|
|
1856
|
+
const float LINE_WIDTH_PX = 4.0; // target thickness in pixels
|
|
1857
|
+
//const float LINE_THRESH_MM = 1.5; // target thickness in pixels
|
|
1858
|
+
const float TILT_STRENGTH = 1.0; // >0 shrinks ribbon for oblique triangles
|
|
1859
|
+
// --- signed distances to each orthogonal plane (object space) ---
|
|
1860
|
+
vec3 d = vP.xyz - sliceMM.xyz;
|
|
1861
|
+
vec3 ad = abs(d);
|
|
1862
|
+
// --- derivatives to get pixel-consistent widths (per-axis) ---
|
|
1863
|
+
vec3 fd = fwidth(vP.xyz);
|
|
1864
|
+
//minDist is in mm not pixels
|
|
1865
|
+
float minDist = min(ad.x, min(ad.y, ad.z));
|
|
1866
|
+
if (minDist > sliceMM.w) discard;
|
|
1867
|
+
// --- per-plane obliqueness: use the two in-plane components' fwidth ---
|
|
1868
|
+
float tiltX = length(fd.yz); // for plane with normal X
|
|
1869
|
+
float tiltY = length(fd.xz); // for plane with normal Y
|
|
1870
|
+
float tiltZ = length(fd.xy); // for plane with normal Z
|
|
1871
|
+
float tfX = clamp(1.0 / (1.0 + TILT_STRENGTH * tiltX), 0.0, 1.0);
|
|
1872
|
+
float tfY = clamp(1.0 / (1.0 + TILT_STRENGTH * tiltY), 0.0, 1.0);
|
|
1873
|
+
float tfZ = clamp(1.0 / (1.0 + TILT_STRENGTH * tiltZ), 0.0, 1.0);
|
|
1874
|
+
// --- half-widths for each plane (apply per-axis tilt factor) ---
|
|
1875
|
+
vec3 halfWidth;
|
|
1876
|
+
halfWidth.x = (LINE_WIDTH_PX * 0.5) * fd.x * tfX;
|
|
1877
|
+
halfWidth.y = (LINE_WIDTH_PX * 0.5) * fd.y * tfY;
|
|
1878
|
+
halfWidth.z = (LINE_WIDTH_PX * 0.5) * fd.z * tfZ;
|
|
1879
|
+
// --- smooth alpha for each plane ---
|
|
1880
|
+
vec3 edgeA = 1.0 - smoothstep(vec3(0.0), halfWidth, ad);
|
|
1881
|
+
// combine planes (max of X,Y,Z ribbons)
|
|
1882
|
+
float edgeAlpha = max(edgeA.x, max(edgeA.y, edgeA.z));
|
|
1883
|
+
if (edgeAlpha <= 1e-4) discard; // outside ribbons
|
|
1884
|
+
color = vec4(vClr.rgb, vClr.a * edgeAlpha);
|
|
1885
|
+
}`,vd=`#version 300 es
|
|
1886
|
+
precision highp int;
|
|
1887
|
+
precision highp float;
|
|
1888
|
+
uniform float opacity;
|
|
1889
|
+
in vec4 vClr;
|
|
1890
|
+
in vec3 vN;
|
|
1891
|
+
out vec4 color;
|
|
1892
|
+
void main() {
|
|
1893
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1894
|
+
float ambient = 0.35;
|
|
1895
|
+
float diffuse = 0.5;
|
|
1896
|
+
float specular = 0.2;
|
|
1897
|
+
float shininess = 10.0;
|
|
1898
|
+
vec3 n = normalize(vN);
|
|
1899
|
+
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
1900
|
+
vec3 l = normalize(lightPosition);
|
|
1901
|
+
float lightNormDot = dot(n, l);
|
|
1902
|
+
vec3 a = vClr.rgb * ambient;
|
|
1903
|
+
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1904
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1905
|
+
color = vec4(a + d + s, opacity);
|
|
1906
|
+
}`,wd=`#version 300 es
|
|
1907
|
+
precision highp int;
|
|
1908
|
+
precision highp float;
|
|
1909
|
+
uniform float opacity;
|
|
1910
|
+
in vec4 vClr;
|
|
1911
|
+
in vec3 vN;
|
|
1912
|
+
uniform sampler2D matCap;
|
|
1913
|
+
out vec4 color;
|
|
1914
|
+
void main() {
|
|
1915
|
+
vec3 n = normalize(vN);
|
|
1916
|
+
vec2 uv = n.xy * 0.5 + 0.5;
|
|
1917
|
+
uv.y = 1.0 - uv.y;
|
|
1918
|
+
vec3 clr = texture(matCap,uv.xy).rgb * vClr.rgb;
|
|
1919
|
+
color = vec4(clr, opacity);
|
|
1920
|
+
}`,yd=`#version 300 es
|
|
1921
|
+
precision highp int;
|
|
1922
|
+
precision highp float;
|
|
1923
|
+
uniform float opacity;
|
|
1924
|
+
in vec4 vClr;
|
|
1925
|
+
in vec3 vN;
|
|
1926
|
+
out vec4 color;
|
|
1927
|
+
void main() {
|
|
1928
|
+
float ambient = 0.35;
|
|
1929
|
+
float diffuse = 0.6;
|
|
1930
|
+
vec3 n = normalize(vN);
|
|
1931
|
+
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
1932
|
+
vec3 l = normalize(lightPosition);
|
|
1933
|
+
float lightNormDot = dot(n, l);
|
|
1934
|
+
vec3 a = vClr.rgb * ambient;
|
|
1935
|
+
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1936
|
+
color = vec4(a + d, opacity);
|
|
1937
|
+
}`,bd=`#version 300 es
|
|
1938
|
+
precision highp int;
|
|
1939
|
+
precision highp float;
|
|
1940
|
+
uniform float opacity;
|
|
1941
|
+
in vec4 vClr;
|
|
1942
|
+
in vec3 vN;
|
|
1943
|
+
out vec4 color;
|
|
1944
|
+
void main() {
|
|
1945
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
1946
|
+
float ambient = 0.35;
|
|
1947
|
+
float diffuse = 0.5;
|
|
1948
|
+
float specular = 0.2;
|
|
1949
|
+
float shininess = 10.0;
|
|
1950
|
+
vec3 n = normalize(vN);
|
|
1951
|
+
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
1952
|
+
vec3 l = normalize(lightPosition);
|
|
1953
|
+
float lightNormDot = dot(n, l);
|
|
1954
|
+
vec3 up = vec3(0.0, 1.0, 0.0);
|
|
1955
|
+
float ax = dot(n, up) * 0.5 + 0.5; //Shreiner et al. (2013) OpenGL Programming Guide, 8th Ed., p 388. ISBN-10: 0321773039
|
|
1956
|
+
vec3 upClr = vec3(1.0, 1.0, 0.95);
|
|
1957
|
+
vec3 downClr = vec3(0.4, 0.4, 0.6);
|
|
1958
|
+
vec3 a = vClr.rgb * ambient;
|
|
1959
|
+
a *= mix(downClr, upClr, ax);
|
|
1960
|
+
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
1961
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
1962
|
+
color = vec4(a + d + s, opacity);
|
|
1963
|
+
}`,Cd=`#version 300 es
|
|
1964
|
+
precision highp int;
|
|
1965
|
+
precision highp float;
|
|
1966
|
+
uniform float opacity;
|
|
1967
|
+
in vec4 vClr;
|
|
1968
|
+
in vec3 vN;
|
|
1969
|
+
out vec4 color;
|
|
1970
|
+
//Spherical harmonics constants
|
|
1971
|
+
const float C1 = 0.429043;
|
|
1972
|
+
const float C2 = 0.511664;
|
|
1973
|
+
const float C3 = 0.743125;
|
|
1974
|
+
const float C4 = 0.886227;
|
|
1975
|
+
const float C5 = 0.247708;
|
|
1976
|
+
//Spherical harmonics coefficients
|
|
1977
|
+
// Ramamoorthi, R., and P. Hanrahan. 2001b. "An Efficient Representation for Irradiance Environment Maps." In Proceedings of SIGGRAPH 2001, pp. 497–500.
|
|
1978
|
+
// https://github.com/eskimoblood/processingSketches/blob/master/data/shader/shinyvert.glsl
|
|
1979
|
+
// https://github.com/eskimoblood/processingSketches/blob/master/data/shader/shinyvert.glsl
|
|
1980
|
+
// Constants for Eucalyptus Grove lighting
|
|
1981
|
+
const vec3 L00 = vec3( 0.3783264, 0.4260425, 0.4504587);
|
|
1982
|
+
const vec3 L1m1 = vec3( 0.2887813, 0.3586803, 0.4147053);
|
|
1983
|
+
const vec3 L10 = vec3( 0.0379030, 0.0295216, 0.0098567);
|
|
1984
|
+
const vec3 L11 = vec3(-0.1033028, -0.1031690, -0.0884924);
|
|
1985
|
+
const vec3 L2m2 = vec3(-0.0621750, -0.0554432, -0.0396779);
|
|
1986
|
+
const vec3 L2m1 = vec3( 0.0077820, -0.0148312, -0.0471301);
|
|
1987
|
+
const vec3 L20 = vec3(-0.0935561, -0.1254260, -0.1525629);
|
|
1988
|
+
const vec3 L21 = vec3(-0.0572703, -0.0502192, -0.0363410);
|
|
1989
|
+
const vec3 L22 = vec3( 0.0203348, -0.0044201, -0.0452180);
|
|
1990
|
+
vec3 SH(vec3 vNormal) {
|
|
1991
|
+
vNormal = vec3(vNormal.x,vNormal.z,vNormal.y);
|
|
1992
|
+
vec3 diffuseColor = C1 * L22 * (vNormal.x * vNormal.x - vNormal.y * vNormal.y) +
|
|
1993
|
+
C3 * L20 * vNormal.z * vNormal.z +
|
|
1994
|
+
C4 * L00 -
|
|
1995
|
+
C5 * L20 +
|
|
1996
|
+
2.0 * C1 * L2m2 * vNormal.x * vNormal.y +
|
|
1997
|
+
2.0 * C1 * L21 * vNormal.x * vNormal.z +
|
|
1998
|
+
2.0 * C1 * L2m1 * vNormal.y * vNormal.z +
|
|
1999
|
+
2.0 * C2 * L11 * vNormal.x +
|
|
2000
|
+
2.0 * C2 * L1m1 * vNormal.y +
|
|
2001
|
+
2.0 * C2 * L10 * vNormal.z;
|
|
2002
|
+
return diffuseColor;
|
|
2003
|
+
}
|
|
2004
|
+
void main() {
|
|
2005
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
2006
|
+
float ambient = 0.3;
|
|
2007
|
+
float diffuse = 0.6;
|
|
2008
|
+
float specular = 0.1;
|
|
2009
|
+
float shininess = 10.0;
|
|
2010
|
+
vec3 n = normalize(vN);
|
|
2011
|
+
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
2012
|
+
vec3 l = normalize(lightPosition);
|
|
2013
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
2014
|
+
vec3 a = vClr.rgb * ambient;
|
|
2015
|
+
vec3 d = vClr.rgb * diffuse * SH(-reflect(n, vec3(l.x, l.y, -l.z)) );
|
|
2016
|
+
color = vec4(a + d + s, opacity);
|
|
2017
|
+
}`,Md=`#version 300 es
|
|
2018
|
+
layout(location=0) in vec3 pos;
|
|
2019
|
+
layout(location=1) in vec4 norm;
|
|
2020
|
+
layout(location=2) in vec4 clr;
|
|
2021
|
+
uniform mat4 mvpMtx;
|
|
2022
|
+
//uniform mat4 modelMtx;
|
|
2023
|
+
uniform mat4 normMtx;
|
|
2024
|
+
out vec4 vClr;
|
|
2025
|
+
flat out vec3 vN;
|
|
2026
|
+
void main(void) {
|
|
2027
|
+
gl_Position = mvpMtx * vec4(pos, 1.0);
|
|
2028
|
+
vN = normalize((normMtx * vec4(norm.xyz,1.0)).xyz);
|
|
2029
|
+
//vV = -vec3(modelMtx*vec4(pos,1.0));
|
|
2030
|
+
vClr = clr;
|
|
2031
|
+
}`,Wn=`#version 300 es
|
|
2032
|
+
precision highp int;
|
|
2033
|
+
precision highp float;
|
|
2034
|
+
uniform float opacity;
|
|
2035
|
+
in vec4 vClr;
|
|
2036
|
+
flat in vec3 vN;
|
|
2037
|
+
out vec4 color;
|
|
2038
|
+
void main() {
|
|
2039
|
+
vec3 r = vec3(0.0, 0.0, 1.0); //rayDir: for orthographic projections moving in Z direction (no need for normal matrix)
|
|
2040
|
+
float ambient = 0.35;
|
|
2041
|
+
float diffuse = 0.5;
|
|
2042
|
+
float specular = 0.2;
|
|
2043
|
+
float shininess = 10.0;
|
|
2044
|
+
vec3 n = normalize(vN);
|
|
2045
|
+
vec3 lightPosition = vec3(0.0, 10.0, -5.0);
|
|
2046
|
+
vec3 l = normalize(lightPosition);
|
|
2047
|
+
float lightNormDot = dot(n, l);
|
|
2048
|
+
vec3 a = vClr.rgb * ambient;
|
|
2049
|
+
vec3 d = max(lightNormDot, 0.0) * vClr.rgb * diffuse;
|
|
2050
|
+
float s = specular * pow(max(dot(reflect(l, n), r), 0.0), shininess);
|
|
2051
|
+
color = vec4(a + d + s, opacity);
|
|
2052
|
+
}`,Dd=`#version 300 es
|
|
2053
|
+
#line 1260
|
|
2054
|
+
#define MAX_CLIP_PLANES 6
|
|
2055
|
+
//precision highp int;
|
|
2056
|
+
precision highp float;
|
|
2057
|
+
uniform vec3 rayDir;
|
|
2058
|
+
uniform vec3 volScale;
|
|
2059
|
+
uniform vec3 texVox;
|
|
2060
|
+
uniform vec4 clipPlane;
|
|
2061
|
+
uniform vec4 clipPlanes[MAX_CLIP_PLANES];
|
|
2062
|
+
uniform bool isClipCutaway;
|
|
2063
|
+
uniform highp sampler3D volume, overlay;
|
|
2064
|
+
uniform highp sampler3D paqd;
|
|
2065
|
+
uniform vec4 paqdUniforms;
|
|
2066
|
+
uniform float overlays;
|
|
2067
|
+
uniform mat4 matRAS;
|
|
2068
|
+
uniform mat4 mvpMtx;
|
|
2069
|
+
uniform float drawOpacity, renderOverlayBlend;
|
|
2070
|
+
uniform highp sampler3D drawing;
|
|
2071
|
+
uniform highp sampler2D colormap;
|
|
2072
|
+
uniform int backgroundMasksOverlays;
|
|
2073
|
+
in vec3 vColor;
|
|
2074
|
+
out vec4 fColor;
|
|
2075
|
+
`+zt+`
|
|
2076
|
+
void main() {
|
|
2077
|
+
int id = 254;
|
|
2078
|
+
vec3 start = vColor;
|
|
2079
|
+
gl_FragDepth = 1.0;
|
|
2080
|
+
fColor = vec4(0.0, 0.0, 0.0, 0.0); //assume no hit: ID = 0
|
|
2081
|
+
float fid = float(id & 255)/ 255.0;
|
|
2082
|
+
vec3 backPosition = GetBackPosition(start);
|
|
2083
|
+
vec3 dir = normalize(backPosition - start);
|
|
2084
|
+
//clipVolumeStart(start, backPosition);
|
|
2085
|
+
float len = length(backPosition - start);
|
|
2086
|
+
float lenVox = length((texVox * start) - (texVox * backPosition));
|
|
2087
|
+
if ((lenVox < 0.5) || (len > 3.0)) return;//discard; //length limit for parallel rays
|
|
2088
|
+
float sliceSize = len / lenVox; //e.g. if ray length is 1.0 and traverses 50 voxels, each voxel is 0.02 in unit cube
|
|
2089
|
+
float stepSize = sliceSize; //quality: larger step is faster traversal, but fewer samples
|
|
2090
|
+
float opacityCorrection = stepSize/sliceSize;
|
|
2091
|
+
dir = normalize(dir);
|
|
2092
|
+
vec4 samplePos = vec4(start.xyz, 0.0); //ray position
|
|
2093
|
+
bool hasClip = false;
|
|
2094
|
+
vec2 sampleRange = vec2(0.0, len);
|
|
2095
|
+
for (int i = 0; i < MAX_CLIP_PLANES; i++)
|
|
2096
|
+
clipSampleRange(dir, samplePos, clipPlanes[i], sampleRange, hasClip);
|
|
2097
|
+
bool isClip = (sampleRange.x > 0.0) || ((sampleRange.y < len) && (sampleRange.y > 0.0));
|
|
2098
|
+
//vec4 clipPos = applyClip(dir, samplePos, len, isClip);
|
|
2099
|
+
if (isClip) fColor = vec4(samplePos.xyz, 253.0 / 255.0); //assume no hit: ID = 0
|
|
2100
|
+
if ((isClipCutaway) && (sampleRange.x <= 0.0) && (sampleRange.y >= len)) {
|
|
2101
|
+
//completely clipped, but ray does not intersect plane
|
|
2102
|
+
if (hasClip)
|
|
2103
|
+
samplePos.a = len + 1.0;
|
|
2104
|
+
else
|
|
2105
|
+
sampleRange = vec2(0.0, 0.0);
|
|
2106
|
+
}
|
|
2107
|
+
//start: OPTIONAL fast pass: rapid traversal until first hit
|
|
2108
|
+
float stepSizeFast = sliceSize * 1.9;
|
|
2109
|
+
vec4 deltaDirFast = vec4(dir.xyz * stepSizeFast, stepSizeFast);
|
|
2110
|
+
while (samplePos.a <= len) {
|
|
2111
|
+
if (skipSample(samplePos.a, sampleRange) ^^ isClipCutaway) {
|
|
2112
|
+
samplePos += deltaDirFast;
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
float val = texture(volume, samplePos.xyz).a;
|
|
2116
|
+
if (val > 0.01) {
|
|
2117
|
+
fColor = vec4(samplePos.rgb, fid);
|
|
2118
|
+
gl_FragDepth = frac2ndc(samplePos.xyz);
|
|
2119
|
+
break;
|
|
2120
|
+
}
|
|
2121
|
+
samplePos += deltaDirFast; //advance ray position
|
|
2122
|
+
}
|
|
2123
|
+
//end: fast pass
|
|
2124
|
+
if ((overlays < 1.0) || (backgroundMasksOverlays > 0)) {
|
|
2125
|
+
return; //background hit, no overlays
|
|
2126
|
+
}
|
|
2127
|
+
//overlay pass
|
|
2128
|
+
len = min(len, samplePos.a); //only find overlay closer than background
|
|
2129
|
+
samplePos = vec4(start.xyz, 0.0); //ray position
|
|
2130
|
+
while (samplePos.a <= len) {
|
|
2131
|
+
float val = texture(overlay, samplePos.xyz).a;
|
|
2132
|
+
if (val > 0.01) {
|
|
2133
|
+
fColor = vec4(samplePos.rgb, fid);
|
|
2134
|
+
gl_FragDepth = frac2ndc(samplePos.xyz);
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
samplePos += deltaDirFast; //advance ray position
|
|
2138
|
+
}
|
|
2139
|
+
//if (fColor.a == 0.0) discard; //no hit in either background or overlays
|
|
2140
|
+
//you only get here if there is a hit with the background that is closer than any overlay
|
|
2141
|
+
}`,Td=`#version 300 es
|
|
2142
|
+
// an attribute is an input (in) to a vertex shader.
|
|
2143
|
+
// It will receive data from a buffer
|
|
2144
|
+
layout(location=0) in vec3 a_position;
|
|
2145
|
+
layout(location=1) in vec3 a_color;
|
|
2146
|
+
// A matrix to transform the positions by
|
|
2147
|
+
uniform mat4 u_matrix;
|
|
2148
|
+
out vec3 vColor;
|
|
2149
|
+
// all shaders have a main function
|
|
2150
|
+
void main() {
|
|
2151
|
+
// Multiply the position by the matrix.
|
|
2152
|
+
vec4 pos = vec4(a_position, 1.0);
|
|
2153
|
+
gl_Position = u_matrix * vec4(pos);
|
|
2154
|
+
vColor = a_color;
|
|
2155
|
+
}
|
|
2156
|
+
`,Sd=`#version 300 es
|
|
2157
|
+
precision highp float;
|
|
2158
|
+
uniform vec4 u_color;
|
|
2159
|
+
in vec3 vColor;
|
|
2160
|
+
out vec4 outColor;
|
|
2161
|
+
void main() {
|
|
2162
|
+
outColor = vec4(vColor, 1.0);
|
|
2163
|
+
}`,Ed=`#version 300 es
|
|
2164
|
+
#line 1359
|
|
2165
|
+
precision highp int;
|
|
2166
|
+
precision highp float;
|
|
2167
|
+
in vec3 vPos;
|
|
2168
|
+
out vec2 TexCoord;
|
|
2169
|
+
void main() {
|
|
2170
|
+
TexCoord = vPos.xy;
|
|
2171
|
+
vec2 viewCoord = (vPos.xy - 0.5) * 2.0;
|
|
2172
|
+
gl_Position = vec4((vPos.xy - 0.5) * 2.0, 0.0, 1.0);
|
|
2173
|
+
}`,Id=`#version 300 es
|
|
2174
|
+
precision highp int;
|
|
2175
|
+
precision highp float;
|
|
2176
|
+
in vec2 TexCoord;
|
|
2177
|
+
out vec4 FragColor;
|
|
2178
|
+
uniform float coordZ;
|
|
2179
|
+
uniform lowp sampler3D in3D;
|
|
2180
|
+
void main(void) {
|
|
2181
|
+
FragColor = texture(in3D, vec3(TexCoord.xy, coordZ));
|
|
2182
|
+
}`,qt=`#version 300 es
|
|
2183
|
+
#line 286
|
|
2184
|
+
precision highp int;
|
|
2185
|
+
precision highp float;
|
|
2186
|
+
in vec3 vPos;
|
|
2187
|
+
out vec2 TexCoord;
|
|
2188
|
+
void main() {
|
|
2189
|
+
TexCoord = vPos.xy;
|
|
2190
|
+
gl_Position = vec4( (vPos.xy-vec2(0.5,0.5))* 2.0, 0.0, 1.0);
|
|
2191
|
+
}`,Fd=`#version 300 es
|
|
2192
|
+
#line 298
|
|
2193
|
+
precision highp int;
|
|
2194
|
+
precision highp float;
|
|
2195
|
+
in vec2 TexCoord;
|
|
2196
|
+
out vec4 FragColor;
|
|
2197
|
+
uniform float coordZ;
|
|
2198
|
+
uniform float dX;
|
|
2199
|
+
uniform float dY;
|
|
2200
|
+
uniform float dZ;
|
|
2201
|
+
// Optional uniforms for parameterised (2r+1)^3 box blur. When kernelRadius
|
|
2202
|
+
// is 0 (default / gradient pipeline) the legacy 8-corner sample is used.
|
|
2203
|
+
uniform int kernelRadius;
|
|
2204
|
+
uniform bool binarize;
|
|
2205
|
+
uniform highp sampler3D intensityVol;
|
|
2206
|
+
void main(void) {
|
|
2207
|
+
vec3 vx = vec3(TexCoord.xy, coordZ);
|
|
2208
|
+
if (kernelRadius > 0) {
|
|
2209
|
+
vec4 sum = vec4(0.0);
|
|
2210
|
+
float count = 0.0;
|
|
2211
|
+
for (int k = -kernelRadius; k <= kernelRadius; k++) {
|
|
2212
|
+
for (int j = -kernelRadius; j <= kernelRadius; j++) {
|
|
2213
|
+
for (int i = -kernelRadius; i <= kernelRadius; i++) {
|
|
2214
|
+
vec3 off = vec3(float(i) * dX, float(j) * dY, float(k) * dZ);
|
|
2215
|
+
vec4 v = texture(intensityVol, vx + off);
|
|
2216
|
+
if (binarize) v = vec4(v.r > 0.0 ? 1.0 : 0.0, 0.0, 0.0, 0.0);
|
|
2217
|
+
sum += v;
|
|
2218
|
+
count += 1.0;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
FragColor = sum / count;
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2225
|
+
// Legacy 8-corner box blur (gradient pipeline)
|
|
2226
|
+
vec4 samp = texture(intensityVol,vx+vec3(+dX,+dY,+dZ));
|
|
2227
|
+
samp += texture(intensityVol,vx+vec3(+dX,+dY,-dZ));
|
|
2228
|
+
samp += texture(intensityVol,vx+vec3(+dX,-dY,+dZ));
|
|
2229
|
+
samp += texture(intensityVol,vx+vec3(+dX,-dY,-dZ));
|
|
2230
|
+
samp += texture(intensityVol,vx+vec3(-dX,+dY,+dZ));
|
|
2231
|
+
samp += texture(intensityVol,vx+vec3(-dX,+dY,-dZ));
|
|
2232
|
+
samp += texture(intensityVol,vx+vec3(-dX,-dY,+dZ));
|
|
2233
|
+
samp += texture(intensityVol,vx+vec3(-dX,-dY,-dZ));
|
|
2234
|
+
FragColor = samp*0.125;
|
|
2235
|
+
}`,Bd=`#version 300 es
|
|
2236
|
+
#line 298
|
|
2237
|
+
precision highp int;
|
|
2238
|
+
precision highp float;
|
|
2239
|
+
in vec2 TexCoord;
|
|
2240
|
+
out vec4 FragColor;
|
|
2241
|
+
uniform float coordZ;
|
|
2242
|
+
uniform float dX;
|
|
2243
|
+
uniform float dY;
|
|
2244
|
+
uniform float dZ;
|
|
2245
|
+
uniform highp sampler3D intensityVol;
|
|
2246
|
+
void main(void) {
|
|
2247
|
+
vec3 vx = vec3(TexCoord.xy, coordZ);
|
|
2248
|
+
// --- Z+ Plane (+dZ) ---
|
|
2249
|
+
float XYZ = texture(intensityVol, vx + vec3(+dX, +dY, +dZ)).a;
|
|
2250
|
+
float OYZ = texture(intensityVol, vx + vec3(0.0, +dY, +dZ)).a;
|
|
2251
|
+
float xYZ = texture(intensityVol, vx + vec3(-dX, +dY, +dZ)).a;
|
|
2252
|
+
float XOZ = texture(intensityVol, vx + vec3(+dX, 0.0, +dZ)).a;
|
|
2253
|
+
float OOZ = texture(intensityVol, vx + vec3(0.0, 0.0, +dZ)).a;
|
|
2254
|
+
float xOZ = texture(intensityVol, vx + vec3(-dX, 0.0, +dZ)).a;
|
|
2255
|
+
float XyZ = texture(intensityVol, vx + vec3(+dX, -dY, +dZ)).a;
|
|
2256
|
+
float OyZ = texture(intensityVol, vx + vec3(0.0, -dY, +dZ)).a;
|
|
2257
|
+
float xyZ = texture(intensityVol, vx + vec3(-dX, -dY, +dZ)).a;
|
|
2258
|
+
// --- Z0 Plane (0.0) ---
|
|
2259
|
+
float XYO = texture(intensityVol, vx + vec3(+dX, +dY, 0.0)).a;
|
|
2260
|
+
float OYO = texture(intensityVol, vx + vec3(0.0, +dY, 0.0)).a;
|
|
2261
|
+
float xYO = texture(intensityVol, vx + vec3(-dX, +dY, 0.0)).a;
|
|
2262
|
+
float XOO = texture(intensityVol, vx + vec3(+dX, 0.0, 0.0)).a;
|
|
2263
|
+
float OOO = texture(intensityVol, vx + vec3(0.0, 0.0, 0.0)).a;
|
|
2264
|
+
float xOO = texture(intensityVol, vx + vec3(-dX, 0.0, 0.0)).a;
|
|
2265
|
+
float XyO = texture(intensityVol, vx + vec3(+dX, -dY, 0.0)).a;
|
|
2266
|
+
float OyO = texture(intensityVol, vx + vec3(0.0, -dY, 0.0)).a;
|
|
2267
|
+
float xyO = texture(intensityVol, vx + vec3(-dX, -dY, 0.0)).a;
|
|
2268
|
+
// --- Z- Plane (-dZ) ---
|
|
2269
|
+
float XYz = texture(intensityVol, vx + vec3(+dX, +dY, -dZ)).a;
|
|
2270
|
+
float OYz = texture(intensityVol, vx + vec3(0.0, +dY, -dZ)).a;
|
|
2271
|
+
float xYz = texture(intensityVol, vx + vec3(-dX, +dY, -dZ)).a;
|
|
2272
|
+
float XOz = texture(intensityVol, vx + vec3(+dX, 0.0, -dZ)).a;
|
|
2273
|
+
float OOz = texture(intensityVol, vx + vec3(0.0, 0.0, -dZ)).a;
|
|
2274
|
+
float xOz = texture(intensityVol, vx + vec3(-dX, 0.0, -dZ)).a;
|
|
2275
|
+
float Xyz = texture(intensityVol, vx + vec3(+dX, -dY, -dZ)).a;
|
|
2276
|
+
float Oyz = texture(intensityVol, vx + vec3(0.0, -dY, -dZ)).a;
|
|
2277
|
+
float xyz = texture(intensityVol, vx + vec3(-dX, -dY, -dZ)).a;
|
|
2278
|
+
// --- Directional blur sums ---
|
|
2279
|
+
vec3 blurred;
|
|
2280
|
+
blurred.x = 2.0 * (xOz + xOZ + xyO + xYO + xOO + XOz + XOZ + XyO + XYO + XOO)
|
|
2281
|
+
+ xyz + xyZ + xYz + xYZ + Xyz + XyZ + XYz + XYZ;
|
|
2282
|
+
blurred.y = 2.0 * (Oyz + OyZ + xyO + XyO + OyO + OYz + OYZ + xYO + XYO + OYO)
|
|
2283
|
+
+ xyz + Xyz + xyZ + XyZ + xYz + XYz + xYZ + XYZ;
|
|
2284
|
+
blurred.z = 2.0 * (Oyz + OYz + xOz + XOz + OOz + OyZ + OYZ + xOZ + XOZ + OOZ)
|
|
2285
|
+
+ xyz + Xyz + xYz + XYz + xyZ + XyZ + xYZ + XYZ;
|
|
2286
|
+
float finalAlpha = 0.32 * (abs(blurred.x) + abs(blurred.y) + abs(blurred.z));
|
|
2287
|
+
// 0.0357 = 1/28 to account for weights, rescale to 2**16,
|
|
2288
|
+
FragColor = 0.0357 * vec4(blurred, finalAlpha);
|
|
2289
|
+
}`,Kn=`
|
|
2290
|
+
gradientSample.a = log2(gradientSample.r*gradientSample.r + gradientSample.g*gradientSample.g + gradientSample.b*gradientSample.b + 1.922337562475971e-06) + 18.988706873717717;
|
|
2291
|
+
`,Ud=`#version 300 es
|
|
2292
|
+
#line 323
|
|
2293
|
+
precision highp int;
|
|
2294
|
+
precision highp float;
|
|
2295
|
+
in vec2 TexCoord;
|
|
2296
|
+
out vec4 FragColor;
|
|
2297
|
+
uniform float coordZ;
|
|
2298
|
+
uniform float dX;
|
|
2299
|
+
uniform float dY;
|
|
2300
|
+
uniform float dZ;
|
|
2301
|
+
uniform highp sampler3D intensityVol;
|
|
2302
|
+
void main(void) {
|
|
2303
|
+
vec3 vx = vec3(TexCoord.xy, coordZ);
|
|
2304
|
+
//Neighboring voxels 'T'op/'B'ottom, 'A'nterior/'P'osterior, 'R'ight/'L'eft
|
|
2305
|
+
float TAR = texture(intensityVol,vx+vec3(+dX,+dY,+dZ)).a;
|
|
2306
|
+
float TAL = texture(intensityVol,vx+vec3(+dX,+dY,-dZ)).a;
|
|
2307
|
+
float TPR = texture(intensityVol,vx+vec3(+dX,-dY,+dZ)).a;
|
|
2308
|
+
float TPL = texture(intensityVol,vx+vec3(+dX,-dY,-dZ)).a;
|
|
2309
|
+
float BAR = texture(intensityVol,vx+vec3(-dX,+dY,+dZ)).a;
|
|
2310
|
+
float BAL = texture(intensityVol,vx+vec3(-dX,+dY,-dZ)).a;
|
|
2311
|
+
float BPR = texture(intensityVol,vx+vec3(-dX,-dY,+dZ)).a;
|
|
2312
|
+
float BPL = texture(intensityVol,vx+vec3(-dX,-dY,-dZ)).a;
|
|
2313
|
+
vec4 gradientSample = vec4 (0.0, 0.0, 0.0, 0.0);
|
|
2314
|
+
gradientSample.r = BAR+BAL+BPR+BPL -TAR-TAL-TPR-TPL;
|
|
2315
|
+
gradientSample.g = TPR+TPL+BPR+BPL -TAR-TAL-BAR-BAL;
|
|
2316
|
+
gradientSample.b = TAL+TPL+BAL+BPL -TAR-TPR-BAR-BPR;
|
|
2317
|
+
${Kn}
|
|
2318
|
+
// 0.04242020977371934 = 1/(log2(3*8) - log2(1/(255**2*8))) // 3*8 -> max for 1st order gradient
|
|
2319
|
+
gradientSample.a *= 0.04242020977371934;
|
|
2320
|
+
float gradLen = length(gradientSample.rgb);
|
|
2321
|
+
gradientSample.rgb = gradLen > 0.001 ? gradientSample.rgb / gradLen : vec3(0.0);
|
|
2322
|
+
gradientSample.rgb = (gradientSample.rgb * 0.5)+0.5;
|
|
2323
|
+
FragColor = gradientSample;
|
|
2324
|
+
}`,Rd=`#version 300 es
|
|
2325
|
+
#line 323
|
|
2326
|
+
precision highp int;
|
|
2327
|
+
precision highp float;
|
|
2328
|
+
in vec2 TexCoord;
|
|
2329
|
+
out vec4 FragColor;
|
|
2330
|
+
uniform float coordZ;
|
|
2331
|
+
uniform float dX;
|
|
2332
|
+
uniform float dY;
|
|
2333
|
+
uniform float dZ;
|
|
2334
|
+
uniform float dX2;
|
|
2335
|
+
uniform float dY2;
|
|
2336
|
+
uniform float dZ2;
|
|
2337
|
+
uniform highp sampler3D intensityVol;
|
|
2338
|
+
void main(void) {
|
|
2339
|
+
vec3 vx = vec3(TexCoord.xy, coordZ);
|
|
2340
|
+
//Neighboring voxels 'T'op/'B'ottom, 'A'nterior/'P'osterior, 'R'ight/'L'eft
|
|
2341
|
+
vec4 TAR = texture(intensityVol,vx+vec3(+dX,+dY,+dZ));
|
|
2342
|
+
vec4 TAL = texture(intensityVol,vx+vec3(+dX,+dY,-dZ));
|
|
2343
|
+
vec4 TPR = texture(intensityVol,vx+vec3(+dX,-dY,+dZ));
|
|
2344
|
+
vec4 TPL = texture(intensityVol,vx+vec3(+dX,-dY,-dZ));
|
|
2345
|
+
vec4 BAR = texture(intensityVol,vx+vec3(-dX,+dY,+dZ));
|
|
2346
|
+
vec4 BAL = texture(intensityVol,vx+vec3(-dX,+dY,-dZ));
|
|
2347
|
+
vec4 BPR = texture(intensityVol,vx+vec3(-dX,-dY,+dZ));
|
|
2348
|
+
vec4 BPL = texture(intensityVol,vx+vec3(-dX,-dY,-dZ));
|
|
2349
|
+
vec4 T = texture(intensityVol,vx+vec3(+dX2,0.0,0.0));
|
|
2350
|
+
vec4 A = texture(intensityVol,vx+vec3(0.0,+dY2,0.0));
|
|
2351
|
+
vec4 R = texture(intensityVol,vx+vec3(0.0,0.0,+dZ2));
|
|
2352
|
+
vec4 B = texture(intensityVol,vx+vec3(-dX2,0.0,0.0));
|
|
2353
|
+
vec4 P = texture(intensityVol,vx+vec3(0.0,-dY2,0.0));
|
|
2354
|
+
vec4 L = texture(intensityVol,vx+vec3(0.0,0.0,-dZ2));
|
|
2355
|
+
vec4 gradientSample = vec4 (0.0, 0.0, 0.0, 0.0);
|
|
2356
|
+
gradientSample.x = -4.0*B.x +8.0*(BAR.x+BAL.x+BPR.x+BPL.x) -8.0*(TAR.x+TAL.x+TPR.x+TPL.x) +4.0*T.x;
|
|
2357
|
+
gradientSample.y = -4.0*P.y +8.0*(TPR.y+TPL.y+BPR.y+BPL.y) -8.0*(TAR.y+TAL.y+BAR.y+BAL.y) +4.0*A.y;
|
|
2358
|
+
gradientSample.z = -4.0*L.z +8.0*(TAL.z+TPL.z+BAL.z+BPL.z) -8.0*(TAR.z+TPR.z+BAR.z+BPR.z) +4.0*R.z;
|
|
2359
|
+
${Kn}
|
|
2360
|
+
gradientSample.a *= 0.0325;
|
|
2361
|
+
float gradLen = length(gradientSample.xyz);
|
|
2362
|
+
gradientSample.xyz = gradLen > 0.001 ? gradientSample.xyz / gradLen : vec3(0.0);
|
|
2363
|
+
gradientSample.xyz = (gradientSample.xyz * 0.5)+0.5;
|
|
2364
|
+
FragColor = gradientSample;
|
|
2365
|
+
}`;function Vd(){return[{Name:"Phong",Frag:vd},{Name:"Matte",Frag:yd},{Name:"Harmonic",Frag:Cd},{Name:"Hemispheric",Frag:bd},{Name:"Crevice",Frag:Ad},{Name:"Edge",Frag:md},{Name:"Diffuse",Frag:pd},{Name:"Outline",Frag:dd},{Name:"Specular",Frag:gd},{Name:"Toon",Frag:hd},{Name:"Flat",Frag:Wn},{Name:"Matcap",Frag:wd},{Name:"Rim",Frag:fd},{Name:"Silhouette",Frag:ud},{Name:"Crosscut",Frag:xd}]}function It(t){const{gl:e,shader:i,gradientAmount:r=0,renderDrawAmbientOcclusion:s,renderSilhouette:n,gradientOpacity:a}=t;i.use(e),e.uniform1i(i.uniforms.volume,0),e.uniform1i(i.uniforms.colormap,1),e.uniform1i(i.uniforms.overlay,2),e.uniform1i(i.uniforms.drawing,7),e.uniform1i(i.uniforms.drawSmoothed,10),e.uniform1f(i.uniforms.smoothDrawing,0),e.uniform1i(i.uniforms.paqd,8),e.uniform1fv(i.uniforms.renderDrawAmbientOcclusion,[s,1]),e.uniform1f(i.uniforms.gradientAmount,r),e.uniform1f(i.uniforms.silhouettePower,n);const o=new Float32Array(Bt);for(let l=0;l<Bt;l++)a===0?o[l]=1:o[l]=Math.pow(l/(Bt-1),a*8);e.uniform1fv(e.getUniformLocation(i.program,"gradientOpacity"),o),i.uniforms.clipPlanes=e.getUniformLocation(i.program,"clipPlanes[0]")}function Pd(t){const{gl:e,fragmentShaderText:i,drawOpacity:r,customSliceShader:s}=t;if(s&&e.deleteProgram(s.program),!i)return null;const n=new ee(e,li,i);return n.use(e),e.uniform1i(n.uniforms.volume,0),e.uniform1i(n.uniforms.colormap,1),e.uniform1i(n.uniforms.overlay,2),e.uniform1i(n.uniforms.drawing,7),e.uniform1i(n.uniforms.paqd,8),e.uniform1f(n.uniforms.drawOpacity,r),n}function Hn(t,e){const i=t.toLowerCase();for(let r=0;r<e.length;r++)if(e[r].Name.toLowerCase()===i)return r}function Nd(t){const{gl:e,fragmentShaderText:i,name:r,meshShaders:s}=t;if(!i)throw new Error("Need fragment shader");const n=Hn(r,s);if(n!==void 0&&n>=0){const o=s[n].shader;o&&e.deleteProgram(o.program),s.splice(n,1)}const a=new ee(e,Pr,i);return a.use(e),{Name:r,Frag:i,shader:a}}function Ld(t,e=!0){const i=t.map(r=>r.Name);return e?i.sort():i}function kd(t,e){const i=new ee(t,li,z0);i.use(t),t.uniform1i(i.uniforms.volume,0),t.uniform1i(i.uniforms.colormap,1),t.uniform1i(i.uniforms.overlay,2),t.uniform1i(i.uniforms.drawing,7),t.uniform1f(i.uniforms.drawOpacity,e);const r=new ee(t,li,G0);r.use(t),t.uniform1i(r.uniforms.volume,0),t.uniform1i(r.uniforms.colormap,1),t.uniform1i(r.uniforms.overlay,2),t.uniform1i(r.uniforms.drawing,7),t.uniform1f(r.uniforms.drawOpacity,e);const s=new ee(t,li,Y0);return s.use(t),t.uniform1i(s.uniforms.volume,0),t.uniform1i(s.uniforms.colormap,1),t.uniform1i(s.uniforms.overlay,2),t.uniform1i(s.uniforms.drawing,7),t.uniform1f(s.uniforms.drawOpacity,e),{slice2DShader:i,sliceMMShader:r,sliceV1Shader:s}}function Od(t,e,i){const r=new ee(t,Td,Sd),s=t.createVertexArray();t.bindVertexArray(s);const n=t.createBuffer();return t.enableVertexAttribArray(0),t.enableVertexAttribArray(1),t.bindBuffer(t.ARRAY_BUFFER,n),t.bufferData(t.ARRAY_BUFFER,e,t.STATIC_DRAW),t.vertexAttribPointer(0,3,t.FLOAT,!1,24,0),t.enableVertexAttribArray(1),t.vertexAttribPointer(1,3,t.FLOAT,!1,24,12),t.bindVertexArray(i),{shader:r,vao:s}}function zd(t){const e=new ee(t,bs,Ni);e.use(t);const i=new ee(t,bs,X0);i.use(t);const r=new ee(t,H0,Ni);r.use(t);const s=new ee(t,q0,Ni);s.use(t);const n=new ee(t,J0,$0);return n.use(t),{rectShader:e,rectOutlineShader:i,lineShader:r,line3DShader:s,circleShader:n}}function Gd(t){const{gl:e,renderDrawAmbientOcclusion:i,renderSilhouette:r,gradientOpacity:s}=t,n=new ee(e,Et,L0);It({gl:e,shader:n,renderDrawAmbientOcclusion:i,renderSilhouette:r,gradientOpacity:s});const a=new ee(e,Et,N0);It({gl:e,shader:a,renderDrawAmbientOcclusion:i,renderSilhouette:r,gradientOpacity:s});const o=new ee(e,Et,k0);It({gl:e,shader:o,gradientAmount:.3,renderDrawAmbientOcclusion:i,renderSilhouette:r,gradientOpacity:s}),e.uniform1i(o.uniforms.matCap,5),e.uniform1i(o.uniforms.gradient,6);const l=new ee(e,Et,O0);return It({gl:e,shader:l,renderDrawAmbientOcclusion:i,renderSilhouette:r,gradientOpacity:s}),e.uniform1i(l.uniforms.matCap,5),e.uniform1i(l.uniforms.gradient,6),{renderVolumeShader:n,renderSliceShader:a,renderGradientShader:o,renderGradientValuesShader:l,renderShader:n}}function Yd(t){const e=new ee(t,W0,K0);return e.use(t),t.uniform1i(e.uniforms.colormap,1),e}function Xd(t){const e=new ee(t,qt,Fd),i=new ee(t,qt,Bd),r=new ee(t,qt,Ud),s=new ee(t,qt,Rd),n=new ee(t,rd,sd),a=new ee(t,Ed,Id);return{blurShader:e,gradientPrePassShader:i,sobelFirstOrderShader:r,sobelSecondOrderShader:s,growCutShader:n,passThroughShader:a}}function Wd(t){const e=new ee(t,Je,Ht.concat(Ms)),i=new ee(t,Je,Cs.concat(Ms)),r=new ee(t,Je,Ht.concat(Li)),s=new ee(t,Je,Cs.concat(Li)),n=new ee(t,Je,ed.concat(Li)),a=new ee(t,Je,Ht.concat(id)),o=new ee(t,Je,Ht.concat(td));return{orientShaderAtlasU:e,orientShaderAtlasI:i,orientShaderU:r,orientShaderI:s,orientShaderF:n,orientShaderRGBU:a,orientShaderPAQD:o}}function Kd(t){const e=new ee(t,nd,ad);e.use(t);const i=new ee(t,od,ld);return{surfaceShader:e,fiberShader:i}}function Hd(t){const e=new ee(t,Et,Dd);return e.use(t),e.uniforms.clipPlanes=t.getUniformLocation(e.program,"clipPlanes[0]"),t.uniform1i(e.uniforms.volume,0),t.uniform1i(e.uniforms.colormap,1),t.uniform1i(e.uniforms.overlay,2),t.uniform1i(e.uniforms.drawing,7),e}function qd(t,e){for(let i=0;i<e.length;i++){const r=e[i];r.Name==="Flat"?r.shader=new ee(t,Md,Wn):r.shader=new ee(t,Pr,r.Frag),r.shader.use(t),r.shader.isCrosscut=r.Name==="Crosscut",r.shader.isMatcap=r.Name==="Matcap",r.shader.isMatcap&&t.uniform1i(r.shader.uniforms.matCap,5)}}function Qd(t,e){const i=[...t,e],r=i.length===1?0:i.length-1;return{volumes:i,index:r}}function At(t,e){for(let i=0;i<t.length;i++)if(t[i].id===e)return i;return-1}function Zd(t,e){const i=t.slice(1);for(let r=0;r<i.length;r++)if(i[r].id===e)return r;return-1}function xt(t,e,i=0){const r=t.length;if(i>r)return{volumes:t,back:t.length>0?t[0]:null,overlays:t.slice(1)};const s=At(t,e.id),n=[...t];return i===0?(n.splice(s,1),n.unshift(e)):i<0?n.splice(s,1):(n.splice(s,1),n.splice(i,0,e)),{volumes:n,back:n.length>0?n[0]:null,overlays:n.slice(1)}}function qn(t,e){return{volumes:xt(t,e,-1).volumes,removed:e}}function jd(t,e){if(e>=t.length)throw new Error("Index of volume out of bounds");return qn(t,t[e])}function _d(t,e){return xt(t,e,0)}function Jd(t,e){const i=At(t,e.id);return xt(t,e,i+1)}function $d(t,e){const i=At(t,e.id);return xt(t,e,i-1)}function ef(t,e){return xt(t,e,t.length-1)}function tf(t,e,i){return t[e].opacity=i,t}function rf(t,e){return t[e].clone()}function sf(t,e,i){const r=At(t,e);if(r<0)return t;const s=t[r];let n=i;return n>s.nFrame4D-1&&(n=s.nFrame4D-1),n<0&&(n=0),n===s.frame4D||(s.frame4D=n),t}function nf(t,e){const i=At(t,e);return i<0?0:t[i].frame4D}function af(t){const e=t.hdr,i=e.dims[1]*e.dims[2]*e.dims[3],r=new Uint8ClampedArray(i*4),s=.2*Math.min(Math.min(e.dims[1],e.dims[2]),e.dims[3]),n=.5*e.dims[1],a=.5*e.dims[2],o=.5*e.dims[3];let l=0;for(let c=0;c<e.dims[3];c++)for(let h=0;h<e.dims[2];h++)for(let d=0;d<e.dims[1];d++){const f=Math.abs(d-n),u=Math.abs(h-a),m=Math.abs(c-o),p=Math.sqrt(f*f+u*u+m*m);let g=0;p<s&&(g=255),r[l++]=0,r[l++]=g,r[l++]=0,r[l++]=g*.5}return r}function of(t){let e=t.img;return t.frame4D>0&&t.frame4D<t.nFrame4D&&(e=t.img.slice(t.frame4D*t.nVox3D,(t.frame4D+1)*t.nVox3D)),e}function lf(t){const{hdr:e,max2D:i,max3D:r}=t,s=e.dims[1]>i||e.dims[2]>i,n=e.dims[1]>r||e.dims[2]>r||e.dims[3]>r;return{isAboveMax2D:s,isAboveMax3D:n}}function cf(t){const{gl:e,overlayItem:i,orientShader:r,createColormapTexture:s}=t;if(i.colormapLabel===null||i.colormapLabel.lut.length<=7)return{colormapLabelTexture:null,shouldCleanup:!1};const n=i.colormapLabel.max-i.colormapLabel.min+1,a=s(null,1,n);return e.texSubImage2D(e.TEXTURE_2D,0,0,0,n,1,e.RGBA,e.UNSIGNED_BYTE,i.colormapLabel.lut),e.uniform1f(r.uniforms.cal_min,i.colormapLabel.min-.5),e.uniform1f(r.uniforms.cal_max,i.colormapLabel.max+.5),e.bindTexture(e.TEXTURE_2D,a),{colormapLabelTexture:a,shouldCleanup:!0}}function hf(t){const{gl:e,overlayItem:i,hdr:r,volumes:s,orientShader:n,r8Tex:a,TEXTURE7:o}=t;if(i.modulationImage===null||i.modulationImage<0||i.modulationImage>=s.length)return e.uniform1i(n.uniforms.modulation,0),{modulateTexture:null};const l=s[i.modulationImage].hdr;if(l.dims[1]!==r.dims[1]||l.dims[2]!==r.dims[2]||l.dims[3]!==r.dims[3])return F.debug("Modulation image dimensions do not match target"),e.uniform1i(n.uniforms.modulation,0),{modulateTexture:null};F.debug("modulating",s),i.modulateAlpha?(e.uniform1i(n.uniforms.modulation,2),e.uniform1f(n.uniforms.opacity,1)):e.uniform1i(n.uniforms.modulation,1);const c=a(null,o,r.dims,!0);e.activeTexture(o),e.bindTexture(e.TEXTURE_3D,c);const h=r.dims[1]*r.dims[2]*r.dims[3],d=new Uint8Array(h),f=s[i.modulationImage].cal_min,u=1/(s[i.modulationImage].cal_max-f),m=s[i.modulationImage].img.buffer;let p=new Uint8Array(m);switch(l.datatypeCode){case 4:p=new Int16Array(m);break;case 16:p=new Float32Array(m);break;case 64:p=new Float64Array(m);break;case 128:p=new Uint8Array(m);break;case 512:p=new Uint16Array(m);break}F.debug(s[i.modulationImage]);const g=s[i.modulationImage].colormapNegative.length>0;let x=s[i.modulationImage].cal_min,A=s[i.modulationImage].cal_max;isFinite(s[i.modulationImage].cal_minNeg)&&isFinite(s[i.modulationImage].cal_maxNeg)&&(x=s[i.modulationImage].cal_minNeg,A=s[i.modulationImage].cal_maxNeg),x=Math.abs(x),A=Math.abs(A),x>A&&([x,A]=[A,x]);const y=1/(A-x);let v=Math.abs(i.modulateAlpha);v=Math.max(v,1);const b=s[i.modulationImage].frame4D*h;for(let w=0;w<h;w++){const C=p[w+b]*l.scl_slope+l.scl_inter;let M=(C-f)*u;g&&C<0&&(M=(Math.abs(C)-x)*y),M=Math.min(Math.max(M,0),1),M=Math.pow(M,v)*255,d[w]=M}return e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,r.dims[1],r.dims[2],r.dims[3],e.RED,e.UNSIGNED_BYTE,d),{modulateTexture:c}}function df(t,e,i){if(!t.dimsRAS||!t.matRAS||!t.pixDimsRAS||!t.vox2mm)throw new Error("Cannot create NiivueObject3D: Missing required RAS properties or vox2mm access on NVImage.");const r=t.dimsRAS,s=t.matRAS,n=t.pixDimsRAS,a=-.5,o=-.5,l=-.5,c=r[1]-1+.5,h=r[2]-1+.5,d=r[3]-1+.5,f=t.vox2mm,u=f.call(t,[a,o,l],s),m=f.call(t,[a,h,l],s),p=f.call(t,[a,o,d],s),g=f.call(t,[a,h,d],s),x=f.call(t,[c,o,l],s),A=f.call(t,[c,h,l],s),y=f.call(t,[c,o,d],s),v=f.call(t,[c,h,d],s),b=[...p,0,0,1,...y,1,0,1,...v,1,1,1,...g,0,1,1,...u,0,0,0,...m,0,1,0,...A,1,1,0,...x,1,0,0],w=i.createBuffer();if(!w)throw new Error("Failed to create GL index buffer");i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,w);const C=[0,3,2,2,1,0,4,7,6,6,5,4,5,6,2,2,3,5,4,0,1,1,7,4,7,1,2,2,6,7,4,5,3,3,0,4];i.bufferData(i.ELEMENT_ARRAY_BUFFER,new Uint16Array(C),i.STATIC_DRAW);const M=i.createBuffer();if(!M)throw new Error("Failed to create GL vertex buffer");i.bindBuffer(i.ARRAY_BUFFER,M),i.bufferData(i.ARRAY_BUFFER,new Float32Array(b),i.STATIC_DRAW);const T=i.createVertexArray();if(!T)throw new Error("Failed to create GL VAO");i.bindVertexArray(T),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,w),i.bindBuffer(i.ARRAY_BUFFER,M);const E=24;i.enableVertexAttribArray(0),i.vertexAttribPointer(0,3,i.FLOAT,!1,E,0),i.enableVertexAttribArray(1),i.vertexAttribPointer(1,3,i.FLOAT,!1,E,12),i.bindVertexArray(null);const I=new st(e,M,i.TRIANGLES,C.length,w,T),S=[...p,...y,...v,...g,...u,...m,...A,...x],U=eh(S);return I.extentsMin=U.min.slice(),I.extentsMax=U.max.slice(),I.furthestVertexFromOrigin=U.furthestVertexFromOrigin,I.originNegate=Ve(U.origin),Ia(I.originNegate,I.originNegate),I.fieldOfViewDeObliqueMM=[r[1]*n[1],r[2]*n[2],r[3]*n[3]],I}var ff=33984,uf=33986,Ds=33994;function mf(t){const{overlayItem:e,VOLUME_ID:i,gl:r}=t;return df(e,i,r)}function pf(t){const{overlayItem:e,mm2frac:i}=t,r=i(e.mm000,0,!0);let s=i(e.mm100,0,!0),n=i(e.mm010,0,!0),a=i(e.mm001,0,!0);s=ne(s,s,r),n=ne(n,n,r),a=ne(a,a,r);const o=Ee(s[0],n[0],a[0],r[0],s[1],n[1],a[1],r[1],s[2],n[2],a[2],r[2],0,0,0,1);return Se(o,o),o}function gf(t){const{layer:e,backDims:i,rgbaTex:r}=t;if(e===0)return{volumeTexture:r(null,ff,i)};if(e===1){const s=r(null,uf,i);return{overlayTexture:s,overlayTextureID:s}}return{}}function Af(t){const e=t.createFramebuffer();return t.bindFramebuffer(t.FRAMEBUFFER,e),t.disable(t.CULL_FACE),t.disable(t.BLEND),e}function xf(t){const{gl:e,layer:i,backDims:r,rgbaTex:s,passThroughShader:n}=t;if(i<=1)return s(null,Ds,[2,2,2,2]);const a=s(null,Ds,r);e.bindTexture(e.TEXTURE_3D,a),n.use(e),e.uniform1i(n.uniforms.in3D,2);for(let o=0;o<r[3];o++){const l=1/r[3]*(o+.5);e.uniform1f(n.uniforms.coordZ,l),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,a,0,o),e.drawArrays(e.TRIANGLE_STRIP,0,4)}return a}function vf(t){const{gl:e,overlayItem:i,orientShader:r,layer:s,isAdditiveBlend:n}=t,a=i.colormapType!==0?1:0,o=i.colormapType===1?1:0;e.uniform1i(r.uniforms.isAlphaThreshold,o),e.uniform1i(r.uniforms.isColorbarFromZero,a),e.uniform1i(r.uniforms.isAdditiveBlend,n?1:0);let l=Number.POSITIVE_INFINITY,c=Number.NEGATIVE_INFINITY;i.colormapNegative.length>0&&(l=Math.min(-i.cal_min,-i.cal_max),c=Math.max(-i.cal_min,-i.cal_max),isFinite(i.cal_minNeg)&&isFinite(i.cal_maxNeg)&&(l=Math.min(i.cal_minNeg,i.cal_maxNeg),c=Math.max(i.cal_minNeg,i.cal_maxNeg))),e.uniform1f(r.uniforms.layer??null,s),e.uniform1f(r.uniforms.cal_minNeg??null,l),e.uniform1f(r.uniforms.cal_maxNeg??null,c)}function wf(t){const{gl:e,orientShader:i,backDims:r,outTexture:s,mtx:n,hdr:a,intensityVolTextureUnit:o,blendTextureUnit:l,colormapTextureUnit:c,modulationTextureUnit:h,opacity:d,atlasOutline:f,atlasActiveIndex:u}=t;i.use(e),e.uniform1i(i.uniforms.intensityVol??null,o),e.uniform1i(i.uniforms.blend3D??null,l),e.uniform1i(i.uniforms.colormap??null,c),e.uniform1f(i.uniforms.scl_inter??null,a.scl_inter),e.uniform1f(i.uniforms.scl_slope??null,a.scl_slope),e.uniform1f(i.uniforms.opacity??null,d),e.uniform1i(i.uniforms.modulationVol??null,h),e.uniformMatrix4fv(i.uniforms.mtx,!1,n);let m=0;a.intent_code===1002&&(m=f,e.uniform1ui(i.uniforms.activeIndex,u|0)),e.uniform4fv(i.uniforms.xyzaFrac,[1/r[1],1/r[2],1/r[3],m]);for(let p=0;p<r[3];p++){const g=1/r[3]*(p+.5);e.uniform1f(i.uniforms.coordZ,g),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,s,0,p),e.drawArrays(e.TRIANGLE_STRIP,0,4)}}function yf(t){const{gl:e,renderShader:i,pickingImageShader:r,sliceShader:s,overlaysLength:n,clipPlaneColor:a,backOpacity:o,renderOverlayBlend:l,clipPlane:c,texVox:h,volScale:d,drawOpacity:f,paqdUniforms:u}=t;i.use(e),e.uniform1f(i.uniforms.overlays,n),e.uniform4fv(i.uniforms.clipPlaneColor,a),e.uniform1f(i.uniforms.backOpacity,o),e.uniform1f(i.uniforms.renderOverlayBlend,l),e.uniform4fv(i.uniforms.clipPlane,c),e.uniform3fv(i.uniforms.texVox,h),e.uniform3fv(i.uniforms.volScale,d),r.use(e),e.uniform1f(r.uniforms.overlays,n),e.uniform3fv(r.uniforms.texVox,h),s.use(e),e.uniform1f(s.uniforms.overlays,n),e.uniform1f(s.uniforms.drawOpacity,f),e.uniform4fv(s.uniforms.paqdUniforms,u)}function bf(t){const{is2DSliceShader:e,isV1SliceShader:i,sliceMMShader:r,slice2DShader:s,sliceV1Shader:n,customSliceShader:a}=t;let o=r;if(e&&(o=s),i&&(o=n),a&&(o=a),!o)throw new Error("slice shader undefined");return o}function Cf(t){const{gl:e,shader:i,is2DSliceShader:r,drawTexture:s,paqdTexture:n,TEXTURE7_DRAW:a,TEXTURE8_PAQD:o}=t;e.uniform1i(i.uniforms.drawing,7),e.activeTexture(a),r?e.bindTexture(e.TEXTURE_2D,s):e.bindTexture(e.TEXTURE_3D,s),e.uniform1i(i.uniforms.paqd,8),e.activeTexture(o),e.bindTexture(e.TEXTURE_3D,n)}function Mf(t){const{gl:e,TEXTURE9_ORIENT:i}=t,r=e.createTexture();return e.activeTexture(i),e.bindTexture(e.TEXTURE_3D,r),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_WRAP_R,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.pixelStorei(e.UNPACK_ALIGNMENT,1),r}var Df=2,Tf=4,Sf=16,Ef=64,If=128,Ff=512,Bf=2304,ki=1002;function Uf(t){const{gl:e,hdr:i,img:r,orientShaderU:s,orientShaderI:n,orientShaderF:a,orientShaderRGBU:o,orientShaderAtlasU:l,orientShaderAtlasI:c}=t;let h=s;if(i.datatypeCode===Df)i.intent_code===ki&&(h=l),e.texStorage3D(e.TEXTURE_3D,1,e.R8UI,i.dims[1],i.dims[2],i.dims[3]),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,i.dims[1],i.dims[2],i.dims[3],e.RED_INTEGER,e.UNSIGNED_BYTE,r);else if(i.datatypeCode===Tf)h=n,i.intent_code===ki&&(h=c),e.texStorage3D(e.TEXTURE_3D,1,e.R16I,i.dims[1],i.dims[2],i.dims[3]),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,i.dims[1],i.dims[2],i.dims[3],e.RED_INTEGER,e.SHORT,r);else if(i.datatypeCode===Sf)e.texStorage3D(e.TEXTURE_3D,1,e.R32F,i.dims[1],i.dims[2],i.dims[3]),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,i.dims[1],i.dims[2],i.dims[3],e.RED,e.FLOAT,r),h=a;else if(i.datatypeCode===Ef){const d=Float32Array.from(r);e.texStorage3D(e.TEXTURE_3D,1,e.R32F,i.dims[1],i.dims[2],i.dims[3]),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,i.dims[1],i.dims[2],i.dims[3],e.RED,e.FLOAT,d),h=a}else i.datatypeCode===If?(h=o,h.use(e),e.uniform1i(h.uniforms.hasAlpha,0),e.texStorage3D(e.TEXTURE_3D,1,e.RGB8UI,i.dims[1],i.dims[2],i.dims[3]),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,i.dims[1],i.dims[2],i.dims[3],e.RGB_INTEGER,e.UNSIGNED_BYTE,r)):i.datatypeCode===Ff&&(i.intent_code===ki&&(h=l),e.texStorage3D(e.TEXTURE_3D,1,e.R16UI,i.dims[1],i.dims[2],i.dims[3]),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,i.dims[1],i.dims[2],i.dims[3],e.RED_INTEGER,e.UNSIGNED_SHORT,r));return{orientShader:h}}function Rf(t){const{gl:e,hdr:i,img:r,overlayItem:s,layer:n,orientShaderRGBU:a,orientShaderPAQD:o,volumes:l,backDims:c,rgbaTex:h,paqdTexture:d,TEXTURE8_PAQD:f,TEXTURE9_ORIENT:u}=t;let m=a,p=null,g=d;if(s.colormapLabel){m=o;let x=!0;for(let A=0;A<n;A++){const y=l[A].hdr.datatypeCode===Bf,v=!!l[A].colormapLabel;y&&v&&(x=!1)}x&&(g=h(d,f,c)),p=g,e.activeTexture(u)}return m.use(e),e.uniform1i(m.uniforms.hasAlpha,1),e.texStorage3D(e.TEXTURE_3D,1,e.RGBA8UI,i.dims[1],i.dims[2],i.dims[3]),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,i.dims[1],i.dims[2],i.dims[3],e.RGBA_INTEGER,e.UNSIGNED_BYTE,r),{orientShader:m,outTexture:p,paqdTexture:g}}function Ze(t,e){if(typeof e=="number")return e>=t.length?-1:e;for(let i=0;i<t.length;i++)if(t[i].id===e)return i;return-1}function Vf(t,e){const i=[...t,e],r=i.length===1?0:i.length-1;return{meshes:i,index:r}}function Pf(t,e,i=0){const r=t.length;if(i>r)return{meshes:t};const s=Ze(t,e.id);if(s<0)return{meshes:t};const n=[...t];return i===0?(n.splice(s,1),n.unshift(e)):i<0?n.splice(s,1):(n.splice(s,1),n.splice(i,0,e)),{meshes:n}}function Nf(t){const{meshes:e,id:i,key:r,val:s,gl:n}=t,a=Ze(e,i);return a<0?(F.warn("setMeshProperty() id not loaded",i),-1):(e[a].setProperty(r,s,n),a)}function Lf(t){const{meshes:e,meshId:i,Xmm:r,Ymm:s,Zmm:n}=t,a=Ze(e,i);return a<0?(F.warn("indexNearestXYZmm() id not loaded",i),[NaN,NaN]):e[a].indexNearestXYZmm(r,s,n)}function kf(t){const{meshes:e,meshId:i,gl:r,order:s=3}=t,n=Ze(e,i);return n<0?(F.warn("decimateHierarchicalMesh() id not loaded",i),!1):e[n].decimateHierarchicalMesh(r,s)}function Of(t){const{meshes:e,meshId:i,gl:r}=t,s=Ze(e,i);return s<0?(F.warn("reverseFaces() id not loaded",i),!1):(e[s].reverseFaces(r),!0)}async function zf(t){const{meshes:e,meshId:i,layer:r,key:s,val:n,gl:a}=t,o=Ze(e,i);return o<0?(F.warn("setMeshLayerProperty() id not loaded",i),!1):(await e[o].setLayerProperty(r,s,n,a),!0)}function Gf(t){const{meshes:e,meshShaders:i,id:r,meshShaderNameOrNumber:s,meshShaderNameToNumber:n}=t;let a=0;if(typeof s=="number"?a=s:a=n(s),a===void 0)throw new Error("shaderIndex undefined");a=Math.min(a,i.length-1),a=Math.max(a,0);const o=Ze(e,r);return o>=e.length||o<0?(F.debug("Unable to change shader until mesh is loaded (maybe you need async)"),null):(e[o].meshShaderIndex=a,{meshIndex:o,shaderIndex:a})}var Qt={name:"untitled connectome",nodeColormap:"warm",nodeColormapNegative:"winter",nodeMinColor:0,nodeMaxColor:4,nodeScale:3,edgeColormap:"warm",edgeColormapNegative:"winter",edgeMin:2,edgeMax:6,edgeScale:1,legendLineThickness:0,showLegend:!0},ci=class Qn extends mt{constructor(e,i){super(new Float32Array([]),new Uint32Array([]),i.name,new Uint8Array([]),1,!0,e,i),D(this,"gl"),D(this,"nodesChanged"),this.gl=e,this.type="connectome",this.nodes&&this.updateLabels(),this.nodesChanged=new EventTarget}static convertLegacyConnectome(e){const i={nodes:[],edges:[],...Qt};for(const s in e)if(s in Qt){const n=s;i[n]=e[n]}const r=e.nodes;for(let s=0;s<r.names.length;s++)i.nodes.push({name:r.names[s],x:r.X[s],y:r.Y[s],z:r.Z[s],colorValue:r.Color[s],sizeValue:r.Size[s]});for(let s=0;s<r.names.length-1;s++)for(let n=s+1;n<r.names.length;n++){const a=e.edges[s*r.names.length+n];i.edges.push({first:s,second:n,colorValue:a})}return i}static convertFreeSurferConnectome(e,i="warm"){let r=!0;if("data_type"in e?e.data_type!=="fs_pointset"&&(r=!1):r=!1,"points"in e||(r=!1),!r)throw Error("not a valid FreeSurfer json pointset");const s=e.points.map(a=>({name:Array.isArray(a.comments)&&a.comments.length>0&&"text"in a.comments[0]?a.comments[0].text:"",x:a.coordinates.x,y:a.coordinates.y,z:a.coordinates.z,colorValue:1,sizeValue:1,metadata:a.comments}));return{...Qt,nodeColormap:i,edgeColormap:i,nodes:s,edges:[]}}updateLabels(){const e=this.nodes;if(e&&e.length>0){const i=e.reduce((c,h)=>c.sizeValue>h.sizeValue?c:h).sizeValue;let r,s;if(typeof this.nodeMinColor<"u"&&isFinite(this.nodeMinColor))r=this.nodeMinColor;else{r=e[0].colorValue;for(let c=1;c<e.length;c++)e[c].colorValue<r&&(r=e[c].colorValue)}if(typeof this.nodeMaxColor<"u"&&isFinite(this.nodeMaxColor))s=this.nodeMaxColor;else{s=e[0].colorValue;for(let c=1;c<e.length;c++)e[c].colorValue>s&&(s=e[c].colorValue)}const n=re.colormap(this.nodeColormap,this.colormapInvert),a=re.colormap(this.nodeColormapNegative,this.colormapInvert),o="nodeColormapNegative"in this;let l=this.legendLineThickness?this.legendLineThickness:0;this.showLegend===!1&&(l=0);for(let c=0;c<e.length;c++){let h=e[c].colorValue,d=!1;if(o&&h<0&&(d=!0,h=-h),r<s){if(h<r){F.warn("color value lower than min");continue}h=(h-r)/(s-r)}else h=1;h=Math.round(Math.max(Math.min(255,h*255)))*4;let f=[n[h],n[h+1],n[h+2],255];d&&(f=[a[h],a[h+1],a[h+2],255]),f=f.map(u=>u/255),F.debug("adding label for ",e[c]),e[c].label=new Er(e[c].name,{textColor:f,bulletScale:e[c].sizeValue/i,bulletColor:f,lineWidth:l,lineColor:f,textScale:1,textAlignment:"left",lineTerminator:"none"},[e[c].x,e[c].y,e[c].z]),F.debug("label for node:",e[c].label)}}}addConnectomeNode(e){if(F.debug("adding node",e),!this.nodes)throw new Error("nodes not defined");this.nodes.push(e),this.updateLabels(),this.nodesChanged.dispatchEvent(new CustomEvent("nodeAdded",{detail:{node:e}}))}deleteConnectomeNode(e){const i=this.nodes.indexOf(e),r=this.edges;r&&(this.edges=r.filter(s=>s.first!==i&&s.second!==i)),this.nodes=this.nodes.filter(s=>s!==e),this.updateLabels(),this.updateConnectome(this.gl),this.nodesChanged.dispatchEvent(new CustomEvent("nodeDeleted",{detail:{node:e}}))}updateConnectomeNodeByIndex(e,i){this.nodes[e]=i,this.updateLabels(),this.updateConnectome(this.gl),this.nodesChanged.dispatchEvent(new CustomEvent("nodeChanged",{detail:{node:i}}))}updateConnectomeNodeByPoint(e,i){const r=this.nodes;if(!r)throw new Error("Node to update does not exist");const s=r.find(a=>H.arraysAreEqual([a.x,a.y,a.z],e));if(!s)throw new Error(`Node with point ${e} to update does not exist`);const n=r.findIndex(a=>a===s);this.updateConnectomeNodeByIndex(n,i)}addConnectomeEdge(e,i,r){const s=this.edges;let n=s.find(a=>(a.first===e||a.second===e)&&a.first+a.second===e+i);return n||(n={first:e,second:i,colorValue:r},s.push(n),this.updateConnectome(this.gl),n)}deleteConnectomeEdge(e,i){const r=this.edges,s=r.find(n=>(n.first===e||n.first===i)&&n.first+n.second===e+i);if(s)this.edges=r.filter(n=>n!==s);else throw new Error(`edge between ${e} and ${i} not found`);return this.updateConnectome(this.gl),s}findClosestConnectomeNode(e,i){const r=this.nodes;if(!r||r.length===0)return null;const s=r.map((n,a)=>({node:n,distance:Math.sqrt(Math.pow(n.x-e[0],2)+Math.pow(n.y-e[1],2)+Math.pow(n.z-e[2],2)),index:a})).filter(n=>n.distance<i).sort((n,a)=>n.distance-a.distance);return s.length>0?s[0].node:null}updateConnectome(e){const i=[],r=[],s=[];let n=re.colormap(this.nodeColormap,this.colormapInvert),a=re.colormap(this.nodeColormapNegative,this.colormapInvert),o="nodeColormapNegative"in this;this.nodeMinColor===void 0&&(this.nodeMinColor=NaN),this.nodeMaxColor===void 0&&(this.nodeMaxColor=NaN),this.edgeMin===void 0&&(this.edgeMin=NaN),this.edgeMax===void 0&&(this.edgeMax=NaN);let l=this.nodeMinColor,c=this.nodeMaxColor;if(!isFinite(l)||!isFinite(l)){const x=this.nodes;l=x[0].colorValue,c=x[0].colorValue;for(let A=0;A<x.length;A++)l=Math.min(l,x[A].colorValue),c=Math.max(c,x[A].colorValue)}const h=this.nodes,d=h.length;for(let x=0;x<d;x++){const A=h[x].sizeValue*this.nodeScale;if(A<=0)continue;let y=h[x].colorValue,v=!1;if(o&&y<0&&(v=!0,y=-y),l<c){if(y<l)continue;y=(y-l)/(c-l)}else y=1;y=Math.round(Math.max(Math.min(255,y*255)))*4;let b=[n[y],n[y+1],n[y+2],255];v&&(b=[a[y],a[y+1],a[y+2],255]);const w=k(h[x].x,h[x].y,h[x].z);st.makeColoredSphere(r,i,s,A,w,b)}n=re.colormap(this.edgeColormap,this.colormapInvert),a=re.colormap(this.edgeColormapNegative,this.colormapInvert),o="edgeColormapNegative"in this;const f=this.edges;if(f!==void 0&&f.length>0){if(l=this.edgeMin,c=this.edgeMax,!isFinite(l)||!isFinite(l)){l=f[0].colorValue,c=f[0].colorValue;for(let x=0;x<f.length;x++)l=Math.min(l,f[x].colorValue),c=Math.max(c,f[x].colorValue)}for(const x of f){let A=x.colorValue;const y=o&&A<0;y&&(A=-A);const v=A*this.edgeScale;if(v<=0)continue;if(l<c){if(A<l)continue;A=(A-l)/(c-l)}else A=1;A=Math.round(Math.max(Math.min(255,A*255)))*4;let b=[n[A],n[A+1],n[A+2],255];y&&(b=[a[A],a[A+1],a[A+2],255]);const w=k(h[x.first].x,h[x.first].y,h[x.first].z),C=k(h[x.second].x,h[x.second].y,h[x.second].z);st.makeColoredCylinder(r,i,s,w,C,v,b)}}const u=new Float32Array(r),m=new Uint32Array(i),p=$e.getExtents(u);this.furthestVertexFromOrigin=p.mxDx,this.extentsMin=p.extentsMin,this.extentsMax=p.extentsMax;const g=this.generatePosNormClr(u,m,new Uint8Array(s));e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,Uint32Array.from(m),e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.vertexBuffer),e.bufferData(e.ARRAY_BUFFER,Float32Array.from(g),e.STATIC_DRAW),this.indexCount=i.length}updateMesh(e){this.updateConnectome(e),this.updateLabels()}json(){const e={};for(const i in this)(i in Qt||i==="nodes"||i==="edges")&&(e[i]=this[i]);return e}static async loadConnectomeFromUrl(e,i){const s=await(await fetch(i)).json();return new Qn(e,s)}};function Yf(t){const{gl:e,json:i}=t;let r=i;if("data_type"in i&&i.data_type==="fs_pointset")r=ci.convertFreeSurferConnectome(i),F.warn("converted FreeSurfer connectome",r);else if("nodes"in i){const s=i.nodes;"names"in s&&"X"in s&&"Y"in s&&"Z"in s&&"Color"in s&&"Size"in s&&(r=ci.convertLegacyConnectome(i))}else throw new Error("not a known connectome format");return new ci(e,r)}function Xf(t,e="none"){const i=[1,1,1,1];return{text:t.name,style:{textColor:i,bulletScale:1,bulletColor:i,lineWidth:0,lineColor:i,lineTerminator:e,textScale:1},position:[t.x,t.y,t.z]}}function Wf(t){const{meshes:e,documentLabels:i}=t,a=e.filter(l=>l.type==="connectome").flatMap(l=>l.nodes).map(l=>l.label).filter(l=>l!==void 0);return[...i,...a]}function Kf(t){const{meshes:e,documentLabels:i}=t,a=e.filter(h=>h.type==="connectome"&&h.showLegend!==!1).flatMap(h=>h.nodes).map(h=>h.label).filter(h=>h!==void 0&&h.text!==""),o=i.filter(h=>h.anchor==null||h.anchor===0),l=new Set(a);for(const h of o)l.add(h);const c=e.filter(h=>h.type==="mesh");for(let h=0;h<c.length;h++)for(let d=0;d<c[h].layers.length;d++)if(c[h].layers[d].labels)for(let f=0;f<c[h].layers[d].labels.length;f++)l.add(c[h].layers[d].labels[f]);return Array.from(l)}var Zn={};be(Zn,{MESH_EXTENSIONS:()=>Nr,getFileExt:()=>Lr,getLoader:()=>Hf,getMediaByUrl:()=>_n,handleDragEnter:()=>ea,handleDragOver:()=>ta,isDicomExtension:()=>qf,isMeshExt:()=>jn,readDirectory:()=>$n,readFileAsDataURL:()=>Qf,registerLoader:()=>Jn,traverseFileTree:()=>kr});var Nr=["ASC","BYU","DFS","FSM","PIAL","ORIG","INFLATED","SMOOTHWM","SPHERE","WHITE","G","GEO","GII","ICO","MZ3","NV","OBJ","OFF","PLY","SRF","STL","TCK","TRACT","TRI","TRK","TT","TRX","VTK","WRL","X3D","JCON","JSON"];function Lr(t,e=!0){let i;typeof t=="object"?(i=t.fullname,e=t.upperCase??!0):i=t,F.debug("fullname: ",i);const r=/(?:\.([^.]+))?$/;let s=r.exec(i)[1];if(s=s.toUpperCase(),s==="GZ")s=r.exec(i.slice(0,-3))[1],s=s.toUpperCase();else if(s==="CBOR"){const n=s;s=r.exec(i.slice(0,-5))[1],s=s.toUpperCase(),s=`${s}.${n}`}return e?s:s.toLowerCase()}function jn(t){const e=Lr(t);return F.debug("checking mesh ext:",e),Nr.includes(e)}function _n(t,e){return[...e.entries()].filter(i=>i[1]===t).map(i=>i[0]).pop()}function Jn(t){const{loaders:e,loader:i,fileExt:r,toExt:s}=t;return{...e,[r.toUpperCase()]:{loader:i,toExt:s}}}function Hf(t,e){return t[e.toUpperCase()]}function qf(t){return t.toUpperCase()==="DCM"}async function kr(t,e="",i){return new Promise(r=>{if(t.isFile)t.file(s=>{s.fullPath=e+s.name,s._webkitRelativePath=e+s.name,i.push(s),r(i)});else if(t.isDirectory){const s=t.createReader(),n=()=>{s.readEntries(a=>{if(a.length>0){const o=a.map(l=>kr(l,e+t.name+"/",i));Promise.all(o).then(n).catch(l=>{throw l})}else r(i)})};n()}})}function $n(t){const e=t.createReader();let i=[];const r=async n=>{const a=[],o=async l=>new Promise((c,h)=>l.file(c,h));for(let l=0;l<n.length;l++)a.push(await o(n[l]));return a},s=()=>{e.readEntries(n=>{n.length?(i=i.concat(n),s()):r(i).then(async()=>{}).catch(a=>{throw a})})};return s(),i}function Qf(t){return new Promise((e,i)=>{t.file(r=>{const s=new FileReader;s.onload=()=>e(s.result),s.onerror=()=>i(new Error("Failed to read file as data URL")),s.readAsDataURL(r)},r=>i(r))})}function ea(t){t.stopPropagation(),t.preventDefault()}function ta(t){t.stopPropagation(),t.preventDefault()}var Zf=33984,jf=33986;function _f(t){const{gl:e,layer:i,isForceLinear:r=!1,isNearestInterpolation:s,is2DSliceShader:n}=t;let a=e.LINEAR;!r&&s&&(a=e.NEAREST),i===0?(e.activeTexture(Zf),n?(e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,a),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,a)):(e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MIN_FILTER,a),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MAG_FILTER,a))):(e.activeTexture(jf),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MIN_FILTER,a),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MAG_FILTER,a))}function Ts(t,e,i,r){let s=i.slice(),n=r.slice();return t===1&&(s=e.slice()),t===2&&(s=e.slice(),n=i.slice()),{linesH:s,linesV:n}}function Jf(t,e,i,r){let s,n;switch(t){case 0:s=e[0],n=e[1];break;case 1:s=e[0],n=e[2];break;case 2:s=e[1],n=e[2];break;default:return[i,r]}const a=s/n,o=i/r;let l,c;return a>o?(l=i,c=i/a):(c=r,l=r*a),[l,c]}var $f=33984,Or=33990,Ss=33992;function bi(t,e){const i=-e*(Math.PI/180),r=(t-90)%360*(Math.PI/180),s=[Math.cos(i)*Math.cos(r),Math.cos(i)*Math.sin(r),Math.sin(i)],n=Math.sqrt(s[0]*s[0]+s[1]*s[1]+s[2]*s[2]);return n<=0||(s[0]/=n,s[1]/=n,s[2]/=n),s}function zr(t){const{azimuth:e,elevation:i,obliqueRAS:r}=t,s=J();if(s[0]=-1,Ut(s,s,qe(270-i)),Rt(s,s,qe(e-180)),r){const n=de(r);Ye(s,s,n)}return s}function ia(t){const{azimuth:e,elevation:i,obliqueRAS:r}=t,s=k(0,0,-1),n=zr({azimuth:e,elevation:i,obliqueRAS:r}),a=He(1,0,0,0,-1,0,0,0,-1),o=se();qr(o,s,a);const l=qi();wa(l,n);const c=qi();if(!ya(c,l))return k(0,0,1);const h=se();qr(h,o,c),Ie(h,h);const d=5e-5;for(let f=0;f<3;f++)Math.abs(h[f])<d&&(h[f]=Math.sign(h[f])*d||d);return h}function Es(t){const{gl:e,hdr:i,genericVAO:r,unusedVAO:s,volumeTexture:n,paqdTexture:a,gradientOrder:o,blurShader:l,gradientPrePassShader:c,sobelFirstOrderShader:h,sobelSecondOrderShader:d,rgbaTex:f}=t;let{gradientTexture:u}=t;e.bindVertexArray(r);const m=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,m),e.viewport(0,0,i.dims[1],i.dims[2]),e.disable(e.BLEND);const p=f(null,Ss,i.dims,!0),g=o===2?c:l;g.use(e),e.activeTexture($f),e.bindTexture(e.TEXTURE_3D,n),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MAG_FILTER,e.LINEAR);const x=.7;e.uniform1i(g.uniforms.intensityVol,0),e.uniform1f(g.uniforms.dX,x/i.dims[1]),e.uniform1f(g.uniforms.dY,x/i.dims[2]),e.uniform1f(g.uniforms.dZ,x/i.dims[3]),g.uniforms.kernelRadius&&e.uniform1i(g.uniforms.kernelRadius,0),g.uniforms.binarize&&e.uniform1i(g.uniforms.binarize,0);for(let v=0;v<i.dims[3];v++){const b=1/i.dims[3]*(v+.5);e.uniform1f(g.uniforms.coordZ,b),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,p,0,v);const w=e.checkFramebufferStatus(e.FRAMEBUFFER);w!==e.FRAMEBUFFER_COMPLETE&&F.error("blur shader: ",w),e.drawArrays(e.TRIANGLE_STRIP,0,4)}const A=o===2?d:h;A.use(e),e.activeTexture(Ss),e.bindTexture(e.TEXTURE_3D,p),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.uniform1i(A.uniforms.intensityVol,8);const y=.7;e.uniform1f(A.uniforms.dX,y/i.dims[1]),e.uniform1f(A.uniforms.dY,y/i.dims[2]),e.uniform1f(A.uniforms.dZ,y/i.dims[3]),o===2&&(e.uniform1f(A.uniforms.dX2,2*y/i.dims[1]),e.uniform1f(A.uniforms.dY2,2*y/i.dims[2]),e.uniform1f(A.uniforms.dZ2,2*y/i.dims[3])),e.uniform1f(A.uniforms.coordZ,.5),u!==null&&e.deleteTexture(u),u=f(u,Or,i.dims);for(let v=0;v<i.dims[3];v++){const b=1/i.dims[3]*(v+.5);e.uniform1f(A.uniforms.coordZ,b),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,u,0,v);const w=e.checkFramebufferStatus(e.FRAMEBUFFER);w!==e.FRAMEBUFFER_COMPLETE&&F.error("sobel shader: ",w),e.drawArrays(e.TRIANGLE_STRIP,0,4)}return e.deleteFramebuffer(m),e.deleteTexture(p),e.bindFramebuffer(e.FRAMEBUFFER,null),e.activeTexture(33992),e.bindTexture(e.TEXTURE_3D,a),e.bindVertexArray(s),u}function eu(t){const{gl:e,gradientTexture:i,dims:r}=t;if(!i||!r)return null;const s=r[1],n=r[2],a=r[3],o=s*n*a,l=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,l);const c=new Float32Array(o*4);try{for(let h=0;h<a;h++){e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,i,0,h);const d=e.checkFramebufferStatus(e.FRAMEBUFFER);if(d!==e.FRAMEBUFFER_COMPLETE){console.warn("Framebuffer not complete for gradient texture reading, slice",h,"status:",d.toString(16));continue}try{const f=new Uint8Array(s*n*4);e.readPixels(0,0,s,n,e.RGBA,e.UNSIGNED_BYTE,f);const u=new Float32Array(s*n*4);for(let p=0;p<f.length;p++)u[p]=f[p]/127.5-1;const m=h*s*n*4;c.set(u,m)}catch(f){console.warn("Failed to read pixels for slice",h,":",f);const u=h*s*n*4,m=new Float32Array(s*n*4);c.set(m,u)}}}catch(h){return console.error("Error reading gradient texture:",h),null}finally{e.deleteFramebuffer(l),e.bindFramebuffer(e.FRAMEBUFFER,null)}return c}function tu(t){const{gl:e,data:i,dims:r,backDims:s,gradientTextureAmount:n,hdr:a,gradientGLFn:o}=t;let{gradientTexture:l}=t;if(i===null)return a&&n>0&&o&&o(a),{gradientTexture:l,useCustomGradientTexture:!1};if(!r&&!s)return console.warn("No dimensions provided and no background volume loaded"),{gradientTexture:l,useCustomGradientTexture:!1};const c=r||s,h=c[1],d=c[2],f=c[3],u=h*d*f*4;if(i.length!==u)return console.warn(`Custom gradient data size mismatch. Expected ${u}, got ${i.length}`),{gradientTexture:l,useCustomGradientTexture:!1};l!==null&&e.deleteTexture(l),l=e.createTexture(),e.activeTexture(Or),e.bindTexture(e.TEXTURE_3D,l),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_WRAP_R,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_3D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.pixelStorei(e.UNPACK_ALIGNMENT,1);let m;if(i instanceof Float32Array){m=new Uint8Array(i.length);for(let p=0;p<i.length;p++){const g=Math.max(-1,Math.min(1,i[p]));m[p]=Math.round((g+1)*127.5)}}else m=i;return e.texStorage3D(e.TEXTURE_3D,1,e.RGBA8,h,d,f),e.texSubImage3D(e.TEXTURE_3D,0,0,0,0,h,d,f,e.RGBA,e.UNSIGNED_BYTE,m),{gradientTexture:l,useCustomGradientTexture:!0}}function iu(t){const{gl:e,mvpMatrix:i,azimuth:r,elevation:s,volumesLength:n,volumeObject3D:a,unusedVAO:o,renderShader:l,pickingImageShader:c,mouseDepthPicker:h,backgroundMasksOverlays:d,gradientTextureAmount:f,gradientTexture:u,drawBitmap:m,renderDrawAmbientOcclusion:p,drawOpacity:g,smoothDrawing:x,drawSmoothedTexture:A,paqdUniforms:y,matRAS:v,crosshairPos:b,clipPlaneDepthAziElevs:w,isClipPlanesCutaway:C,isClipAllVolumes:M,obliqueRAS:T}=t;if(n===0)return;const E=ia({azimuth:r,elevation:s,obliqueRAS:T}),I=a;if(I){e.enable(e.BLEND),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA),e.enable(e.CULL_FACE),e.cullFace(e.FRONT);let S=l;if(h&&(S=c),S.use(e),e.uniform1i(S.uniforms.backgroundMasksOverlays,d),f>0&&S.uniforms.normMtx&&u){e.activeTexture(Or),e.bindTexture(e.TEXTURE_3D,u);const U=zr({azimuth:r,elevation:s,obliqueRAS:T}),B=J();Se(B,U);const V=J();Te(V,B),e.uniformMatrix4fv(S.uniforms.normMtx,!1,V)}if(m&&m.length>8?(e.uniform2f(S.uniforms.renderDrawAmbientOcclusionXY,p,g),x>0&&A?(e.uniform1f(S.uniforms.smoothDrawing,x),e.activeTexture(e.TEXTURE10),e.bindTexture(e.TEXTURE_3D,A)):e.uniform1f(S.uniforms.smoothDrawing,0)):(e.uniform2f(S.uniforms.renderDrawAmbientOcclusionXY,p,0),e.uniform1f(S.uniforms.smoothDrawing,0)),e.uniform4fv(S.uniforms.paqdUniforms,y),e.uniformMatrix4fv(S.uniforms.mvpMtx,!1,i),e.uniformMatrix4fv(S.uniforms.matRAS,!1,v),e.uniform3fv(S.uniforms.rayDir,E),f<0)e.uniform4fv(S.uniforms.clipPlane,[b[0],b[1],b[2],30]);else{const B=new Float32Array(24).fill(2);for(let V=0;V<w.length;V++){const R=w[V],P=bi(R[1]+180,R[2]),L=[P[0],P[1],P[2],R[0]];B.set(L,V*4)}e.uniform4fv(S.uniforms.clipPlanes,B)}e.uniform1f(S.uniforms.drawOpacity,1),e.uniform1i(S.uniforms.isClipCutaway,C?1:0),e.uniform1i(S.uniforms.isClipAllVolumes,M?1:0),e.bindVertexArray(I.vao),e.drawElements(I.mode,I.indexCount,e.UNSIGNED_SHORT,0),e.bindVertexArray(o)}}var ru=33989;function su(t){const{visible:e,opacity:i,indexCount:r}=t;return e&&i>0&&r>=3}function nu(t){const{meshShaderIndex:e,meshShaders:i,pickingMeshShader:r,mouseDepthPicker:s}=t;return s?r:i[e]?.shader??null}function au(t){const{meshOpacity:e,globalAlpha:i}=t;return e*i}function ou(t){const{offsetPt0:e,fiberSides:i,fiberRadius:r}=t;return!!e&&(i<3||r<=0)}function lu(t){const{modelMtx:e,crosshairMM:i,is2D:r}=t,s=1e9,n=[i[0],i[1],i[2]];return r&&(Math.abs(e[2])+Math.abs(e[4])+Math.abs(e[9])>=2.95&&(n[1]=s,n[2]=s),Math.abs(e[0])+Math.abs(e[6])+Math.abs(e[9])>=2.95&&(n[0]=s,n[2]=s),Math.abs(e[0])+Math.abs(e[5])+Math.abs(e[10])>=2.95&&(n[0]=s,n[1]=s)),n}function cu(t){let e=Number(t);return Number.isFinite(e)||(e=1),e}function hu(t){const{gl:e,shader:i,modelMtx:r,sliceMM:s,meshThickness:n}=t;e.disable(e.DEPTH_TEST),e.disable(e.CULL_FACE),e.uniformMatrix4fv(i.uniforms.modelMtx,!1,r),e.uniform4fv(i.uniforms.sliceMM,[s[0],s[1],s[2],n])}function Is(t){const{gl:e,shader:i,mvpMtx:r,normMtx:s,opacity:n}=t;e.uniformMatrix4fv(i.uniforms.mvpMtx,!1,r),e.uniformMatrix4fv(i.uniforms.normMtx,!1,s),e.uniform1f(i.uniforms.opacity,n)}function du(t){const{gl:e,matCapTexture:i}=t;e.activeTexture(ru),e.bindTexture(e.TEXTURE_2D,i)}function Fs(t){const{gl:e,mesh:i,unusedVAO:r}=t;e.bindVertexArray(i.vao),e.drawElements(e.TRIANGLES,i.indexCount,e.UNSIGNED_INT,0),e.bindVertexArray(r)}function fu(t){const{gl:e,mesh:i,unusedVAO:r}=t;e.bindVertexArray(i.vaoFiber),e.drawElements(e.LINE_STRIP,i.indexCount,e.UNSIGNED_INT,0),e.bindVertexArray(r)}function uu(t){const{gl:e}=t;e.enable(e.BLEND),e.depthMask(!1),e.depthFunc(e.ALWAYS)}function mu(t){t.depthMask(!0),t.depthFunc(t.LEQUAL),t.disable(t.BLEND)}function pu(t){t.depthMask(!0),t.disable(t.BLEND)}function gu(t){const{gl:e,meshes:i,isDepthTest:r,alpha:s,mvpMatrix:n,modelMatrix:a,normalMatrix:o,is2D:l,meshShaders:c,pickingMeshShader:h,fiberShader:d,mouseDepthPicker:f,matCapTexture:u,unusedVAO:m,meshXRay:p,meshThicknessOn2D:g,frac2mm:x,crosshairPos:A}=t;if(i.length<1)return;e.enable(e.DEPTH_TEST),r?e.depthFunc(e.LEQUAL):e.depthFunc(e.ALWAYS),e.cullFace(e.BACK),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA);let y=!1;for(const v of i){if(!su({visible:v.visible,opacity:v.opacity,indexCount:v.indexCount}))continue;const b=au({meshOpacity:v.opacity,globalAlpha:s}),w=nu({meshShaderIndex:v.meshShaderIndex,meshShaders:c,pickingMeshShader:h,mouseDepthPicker:f});if(w){if(w.use(e),w.isCrosscut){const C=x([A[0],A[1],A[2]]),M=lu({modelMtx:a,crosshairMM:C,is2D:l}),T=cu(g);hu({gl:e,shader:w,modelMtx:a,sliceMM:M,meshThickness:T})}else e.enable(e.CULL_FACE),e.enable(e.DEPTH_TEST);if(Is({gl:e,shader:w,mvpMtx:n,normMtx:o,opacity:b}),b>=1?(e.disable(e.BLEND),e.depthMask(!0)):(e.enable(e.BLEND),e.depthMask(!1)),ou({offsetPt0:v.offsetPt0,fiberSides:v.fiberSides,fiberRadius:v.fiberRadius})){y=!0;continue}w.isMatcap&&du({gl:e,matCapTexture:u}),Fs({gl:e,mesh:v,unusedVAO:m})}}if(e.enable(e.CULL_FACE),p>0&&!y){uu({gl:e});for(const v of i){if(!v.visible||v.indexCount<3)continue;const b=c[v.meshShaderIndex]?.shader;b&&(b.use(e),Is({gl:e,shader:b,mvpMtx:n,normMtx:o,opacity:v.opacity*s*p}),Fs({gl:e,mesh:v,unusedVAO:m}))}mu(e)}if(y&&d){d.use(e),e.uniformMatrix4fv(d.uniforms.mvpMtx,!1,n),e.uniform1f(d.uniforms.opacity,s);for(const v of i)v.offsetPt0&&(v.fiberSides>=3&&v.fiberRadius>0||fu({gl:e,mesh:v,unusedVAO:m}))}pu(e)}function Au(t){const{canvasWidth:e,canvasHeight:i,leftTopWidthHeight:r,azimuth:s,elevation:n,furthestFromPivot:a,pivot3D:o,volScaleMultiplier:l,position:c}=t;let h=r;(h[2]===0||h[3]===0)&&(h=[0,0,e,i]);const d=h[2]/h[3];let f=a;const u=o,m=J();f=.8*f/l,d<1?hi(m,-f,f,-f/d,f/d,f*8,f*.01):hi(m,-f*d,f*d,-f,f,f*8,f*.01);const p=J();p[0]=-1;const g=k(0,0,-f*1.8);tt(p,p,g),c&&tt(p,p,c),Ut(p,p,qe(270-n)),Rt(p,p,qe(s-180)),tt(p,p,[-u[0],-u[1],-u[2]]);const x=J();Se(x,p);const A=J();Te(A,x);const y=J();return Ye(y,m,p),{mvpMatrix:y,modelMatrix:p,normalMatrix:A}}function xu(t){const{sceneMin:e,sceneMax:i}=t,r=se();it(r,e,i),Sa(r,r,.5);const s=se();return ne(s,i,e),{pivot3D:[r[0],r[1],r[2]],furthestFromPivot:Qe(s)*.5,extentsMin:e,extentsMax:i}}function vu(t){const{volumes:e}=t;if(e.length<1)return 0;let i=0;for(let r=0;r<e.length;r++)i=Math.max(i,e[r].nFrame4D??0);return i}function wu(t){const{fontMets:e,scale:i,str:r}=t;if(!r)return 0;let s=0;for(const n of r){const a=n.codePointAt(0),o=e.mets[a];if(o)s+=i*o.xadv;else{console.warn(`calculateTextWidth() : Missing font metric for code point ${a} in string "${r}"`);continue}}return s}function yu(t){const{fontMets:e,scale:i,str:r}=t;if(!r)return 0;let s=0;for(const n of r){const a=n.codePointAt(0),o=e.mets[a];o?.lbwh?.[3]>s&&(s=o.lbwh[3])}return i*s}function bu(t,e){const{xy:i,str:r,fontPx:s,canvasWidth:n}=t;let a=t.scale,o=s*a,l=e(o,r);l>n&&(a*=(n-2)/l,o=s*a,l=e(o,r));let c=i[0]-.5*e(o,r);return c=Math.max(c,1),c=Math.min(c,n-l-1),{x:c,y:i[1],scale:a}}function Cu(t,e){const{xy:i,str:r,fontPx:s,canvasWidth:n}=t;let a=t.scale,o=s*a,l=e(o,r);l>n&&(a*=(n-2)/l,o=s*a,l=e(o,r));let c=i[0]-.5*e(o,r);c=Math.max(c,1),c=Math.min(c,n-l-1);const h=i[1]-o;return{x:c,y:h,scale:a}}function Mu(t,e,i,r,s){const n=i*r,a=s(n,e),o=(t[0]+t[2])*.5-.5*a,l=(t[1]+t[3])*.5-.5*n;return{textX:o,textY:l,rectLTWH:[o-1,l-1,a+2,n+2]}}function Du(t,e){const i=t??e;return i&&i[0]+i[1]+i[2]>.8?[0,0,0,.5]:[1,1,1,.5]}function Tu(t){const{fovMM:e,ltwh:i,rulerWidth:r,regionBounds:s}=t;if(i.length<4||e.length<1)return null;const a=100/e[0]*i[2],o=Math.max(Math.round(a*.1),2),l=Math.floor(i[0]+.5*i[2]-.5*a),c=Math.floor(i[1]+i[3]-o)+.5*r,h=Math.max(s.x,l),d=Math.min(s.x+s.w,l+a),f=Math.min(s.y+s.h,c);return d<=h?null:{startXYendXY:[h,f,d,f],pix1cm:o,clipped:h>l||d<l+a}}function Su(t){return t[0]+t[1]+t[2]<.8?[1,1,1,1]:[0,0,0,1]}function Eu(t,e){const i=[],r=-.1*(t[0]-t[2]),s=t[1]-Math.floor(.5*e),n=Math.floor(s-.35*r),a=Math.floor(s-.7*r);for(let o=0;o<11;o++){let l=t[0]+o*r;l=Math.max(l,t[0]+.5*e),l=Math.min(l,t[2]-.5*e);const c=[l,s,l,o%5===0?a:n];i.push(c)}return i}function Iu(t){const{startXYendXY:e,distance:i}=t,r=e[0],s=e[1],n=e[2],a=e[3],o=r-n,l=s-a;if(o===0&&l===0)return{origin:[n+i,a],terminus:[n+i,a]};const c=Math.sqrt(o*o+l*l),h=i*o/c,d=i*l/c;return{origin:[r+h,s+d],terminus:[n-h,a-d]}}function Fu(t,e,i){const r=[],s=t[2]-t[0],n=t[3]-t[1],a=Math.sqrt(s*s+n*n);if(a===0)return r;const l=e*i/2,c=s/a,h=n/a,d=c*l,f=h*l;let u=Math.floor(a/l);a%l&&u++;let m=t[0],p=t[1];for(let g=0;g<u-1;g++)g%2===0&&r.push({startX:m,startY:p,endX:m+d,endY:p+f}),m+=d,p+=f;return r}function Bu(t,e,i){let r=e,s=e*i;return s>t&&(r=t/i,s=t),{left:(t-s)/2,top:(e-r)/2,width:s,height:r}}function ra(t,e){const i=e||t.target;if(!i)return;const r=i;if(typeof r.getBoundingClientRect!="function")return;const s=r.getBoundingClientRect();return{x:t.clientX-s.left,y:t.clientY-s.top}}function Uu(t,e){const i=e||t.target;return ra(t,i)}function Ru(t){const{forceDevicePixelRatio:e}=t;return e===0?window.devicePixelRatio||1:e<0?1:e}function Vu(t){const{canvas:e,isResizeCanvas:i,forceDevicePixelRatio:r}=t;if(!i)return{dpr:1,width:e.width,height:e.height,shouldDraw:!0};const s=Ru({forceDevicePixelRatio:r});let n,a;const o=e.parentElement;return o&&"width"in o?(n=o.width*s,a=o.height*s):(n=e.offsetWidth*s,a=e.offsetHeight*s),{dpr:s,width:n,height:a,shouldDraw:!0}}function Pu(t){return()=>{requestAnimationFrame(()=>{t()})}}function Nu(t){return new ResizeObserver(()=>{requestAnimationFrame(()=>{t()})})}function Lu(t){return new MutationObserver(t)}function Bs(t){t.style.width="100%",t.style.height="100%",t.style.display="block"}function ku(t,e){return t!==null&&e!==null}function Ou(t,e,i){i&&window.removeEventListener("resize",i),t&&t.disconnect(),e&&e.disconnect()}function zu(t){t&&t.abort()}var sa={};be(sa,{CENTER_MOUSE_BUTTON:()=>Gr,LEFT_MOUSE_BUTTON:()=>pi,RIGHT_MOUSE_BUTTON:()=>Yr,calculateMouseDownPosition:()=>hr,calculateMouseMovePosition:()=>aa,calculateWindowingValues:()=>Wu,createOffCanvasPosition:()=>la,createResetButtonState:()=>oa,determineButtonState:()=>Gu,getMouseButtonDragMode:()=>na,getNextAngleState:()=>Ku,hasDragMoved:()=>dr,initializeDragState:()=>Yu,isAngleMeasurementInProgress:()=>Hu,isFunction:()=>ca,isOffCanvas:()=>Xu,shouldTrackDrag:()=>qu});var pi=0,Gr=1,Yr=2;function na(t){const{button:e,shiftKey:i,ctrlKey:r,mouseConfig:s,dragMode:n,dragModePrimary:a}=t;return e===pi?s?.leftButton?i&&s.leftButton.withShift!==void 0?s.leftButton.withShift:r&&s.leftButton.withCtrl!==void 0?s.leftButton.withCtrl:s.leftButton.primary:r?8:a:e===Yr?s?.rightButton!==void 0?s.rightButton:n:e===Gr&&s?.centerButton!==void 0?s.centerButton:n}function Gu(t){const{button:e,shiftKey:i}=t;return e===pi&&i?{mouseButtonCenterDown:!0}:e===pi?{mouseButtonLeftDown:!0}:e===Yr?{mouseButtonRightDown:!0}:e===Gr?{mouseButtonCenterDown:!0}:{}}function hr(t){const{x:e,y:i,dpr:r}=t,s=e*r,n=i*r;return{scaledX:s,scaledY:n,mousePos:[s,n]}}function aa(t){const{x:e,y:i,dpr:r,currentMousePos:s}=t,n=e*r,a=i*r,o=(n-s[0])/r,l=(a-s[1])/r;return{scaledX:n,scaledY:a,dx:o,dy:l,mousePos:[n,a]}}function Yu(t){const{posX:e,posY:i,pan2Dxyzmm:r,clipPlaneDepthAziElev:s}=t;return{dragStart:[e,i],pan2DxyzmmAtMouseDown:ze(r),isDragging:!0,dragClipPlaneStartDepthAziElev:[...s]}}function oa(){return{mousedown:!1,mouseButtonLeftDown:!1,mouseButtonCenterDown:!1,mouseButtonRightDown:!1}}function dr(t,e){return t[0]!==e[0]||t[1]!==e[1]}function Xu(t){return t[0]<0||t[1]<0}function la(){return[-1,-1]}function Wu(t){const{currentX:e,currentY:i,windowX:r,windowY:s,calMin:n,calMax:a,robustMin:o,robustMax:l,windowRangeMultiplier:c}=t,d=(l-o)*c/100;let f=n,u=a;return i<s?(f=n-d,u=a-d):i>s&&(f=n+d,u=a+d),e>r?(f=f-d,u=u+d):e<r&&(f=f+d,u=u-d),{newCalMin:f,newCalMax:u,newWindowX:e,newWindowY:i}}function Ku(t){const{currentState:e,dragMode:i}=t;if(i!==7)return e;switch(e){case"none":return"drawing_first_line";case"drawing_first_line":return"drawing_second_line";case"drawing_second_line":return"complete";case"complete":return"drawing_first_line";default:return"none"}}function Hu(t){return t==="drawing_first_line"||t==="drawing_second_line"}function qu(t){return t!==8&&t!==9&&t!==0}function ca(t){return Object.prototype.toString.call(t).indexOf("Function")>-1}function Qu(t){const{isDoubleTouch:e,touchConfig:i,dragMode:r,dragModePrimary:s}=t;return e?i?.doubleTouch??r:i?.singleTouch??s}function Oi(t){const{touch:e,canvasRect:i}=t;return{x:e.clientX-i.left,y:e.clientY-i.top}}function Zu(t){const{currentTime:e,lastTouchTime:i,doubleTouchTimeout:r}=t,s=e-i;return{isDoubleTap:s<r&&s>0,timeSinceTouch:s}}function ju(t){const{currentTime:e,touchCount:i,isTouchdown:r}=t;return{touchdown:!0,currentTouchTime:e,multiTouchGesture:r&&i>=2}}function _u(){return{touchdown:!1,lastTwoTouchDistance:0,multiTouchGesture:!1}}function Ju(t){return{doubleTouch:!1,lastTouchTime:t}}function $u(t){return{doubleTouch:!0,lastTouchTime:t}}function e1(t){const{touch1:e,touch2:i,lastTwoTouchDistance:r}=t,s=Math.hypot(e.pageX-i.pageX,e.pageY-i.pageY);let n;r===0?n=0:s<r?n=-.01:n=.01;const a={x:(e.clientX+i.clientX)/2,y:(e.clientY+i.clientY)/2};return{distance:s,scrollDelta:n,centerPosition:a}}function t1(t,e){return t===2&&e===2}function i1(t){const{touch:e,canvasRect:i}=t;return{x:e.clientX-i.left,y:e.clientY-i.top,pageX:e.pageX,pageY:e.pageY}}function r1(t){const{touchdown:e,multiTouchGesture:i}=t;return e&&!i}function Us(t,e){return t&&e<2}function s1(t){const{touch:e,canvasRect:i}=t;return[e.clientX-i.left,e.clientY-i.top]}function n1(t){const{doubleTouch:e,isDragging:i}=t;return e&&i}function a1(t){return t===null}var o1=[[2,0,0],[0,270,0],[0,90,0],[0,0,0],[0,180,0],[0,0,-90],[0,0,90]];function l1(t){const{code:e,ctrlKey:i,shiftKey:r,sliceType:s}=t,n=s===4;return e==="KeyH"&&n?{action:"render_azimuth_decrease"}:e==="KeyL"&&n?{action:"render_azimuth_increase"}:e==="KeyJ"&&n?{action:"render_elevation_increase"}:e==="KeyK"&&n?{action:"render_elevation_decrease"}:e==="KeyH"&&!n?{action:"crosshair_left"}:e==="KeyL"&&!n?{action:"crosshair_right"}:e==="KeyU"&&!n&&i?{action:"crosshair_forward"}:e==="KeyD"&&!n&&i?{action:"crosshair_backward"}:e==="KeyJ"&&!n?{action:"crosshair_down"}:e==="KeyK"&&!n?{action:"crosshair_up"}:e==="KeyM"&&!n?{action:"cycle_drag_mode"}:e==="ArrowLeft"?{action:"frame_previous"}:e==="ArrowRight"?{action:"frame_next"}:e==="Slash"&&r?{action:"show_version"}:{action:"none"}}function c1(t){const e=t+1;return e>=4?0:e}function h1(t){const{currentTime:e,lastCalledTime:i,debounceTime:r}=t;return e-i>r}function d1(t){const{currentIndex:e,clipPlanesLength:i}=t,r=i||6;let s;return e==null?s=0:s=(e+1)%r,{newIndex:s,defaultClipPlane:[0,0,0,2],defaultDepthAziElev:[2,0,0]}}function f1(t){const{currentClipPlaneIndex:e}=t,i=(e+1)%7,r=o1[i];return{newIndex:i,depthAziElev:r}}function u1(t){const{currentSliceType:e,totalSliceTypes:i}=t;return(e+1)%i}function zi(t,e){return t===e}function m1(t){const{deltaY:e,invertScrollDirection:i}=t;let r=e<0?-.01:.01;return i&&(r=-r),r}function p1(t){const{dragMode:e,dragStart:i,dragEnd:r}=t;if(e!==6)return!1;const s=i.reduce((a,o)=>a+o,0),n=r.reduce((a,o)=>a+o,0);return s>0&&n>0}function g1(t){const{dragStart:e,dragEnd:i,delta:r}=t,s=[...e],n=[...i];return e[0]<i[0]?(s[0]=e[0]-r,n[0]=i[0]+r):(s[0]=e[0]+r,n[0]=i[0]-r),e[1]<i[1]?(s[1]=e[1]-r,n[1]=i[1]+r):(s[1]=e[1]+r,n[1]=i[1]-r),{newDragStart:s,newDragEnd:n}}function A1(t){return t>0?1:-1}function x1(t){const{currentZoom:e,scrollAmount:i}=t,r=i<0?1:-1;let s=e*(1+10*(.01*r));s=Math.round(s*10)/10;const n=e-s;return{newZoom:s,zoomChange:n}}function v1(t){const{currentPan:e,zoomChange:i,crosshairMM:r}=t;return[e[0]+i*r[0],e[1]+i*r[1],e[2]+i*r[2]]}function w1(t){const{currentPercent:e,scrollAmount:i}=t;let r=e;return i<0?(r-=.01,r=Math.max(r,0)):(r+=.01,r=Math.min(r,1)),r}function y1(t){const{thumbnailVisible:e,mosaicStringLength:i,eventInBounds:r,hasBounds:s}=t;return e||i>0?{shouldProcess:!1,showBoundsBorder:!1}:r?{shouldProcess:!0,showBoundsBorder:s}:{shouldProcess:!1,showBoundsBorder:!1}}function b1(t){const{dragMode:e,isInRenderTile:i}=t;return e===3&&!i}function C1(t,e,i){return[t-i.left,e-i.top]}var M1={none:0,contrast:1,measurement:2,angle:7,pan:3,slicer3D:4,callbackOnly:5,roiSelection:6,crosshair:8,windowing:9};function D1(t){if(typeof t=="string"){const e=M1[t];return e!==void 0?e:null}return t}function T1(t){const{activeDragMode:e,fallbackDragMode:i}=t;return e!==null?e:i}function S1(){return{activeDragMode:null,activeDragButton:null}}function E1(t,e){return{activeDragMode:t,activeDragButton:e}}function I1(t){if(t.length>2)throw new Error("array must not contain more than two values");return[Math.floor(Math.min(t[0],t[1])),Math.floor(Math.max(t[0],t[1]))]}function F1(t,e){const i=t[2],r=t[3],s=t[0]-i,n=t[1]-r,a=e[2]-i,o=e[3]-r,l=s*a+n*o,c=Math.sqrt(s*s+n*n),h=Math.sqrt(a*a+o*o);if(c===0||h===0)return 0;const d=Math.max(-1,Math.min(1,l/(c*h)));return Math.acos(d)*(180/Math.PI)}function B1(){return{angleState:"none",angleFirstLine:[0,0,0,0]}}function Rs(t,e,i){return[t*i,e*i]}function U1(t){const{startMM:e,endMM:i,pan2DxyzmmAtMouseDown:r}=t,s=Xe();Pa(s,i,e);const n=r[3];return{pan2Dxyzmm:[r[0]+n*s[0],r[1]+n*s[1],r[2]+n*s[2],n]}}function R1(t){const{startY:e,endY:i,pan2DxyzmmAtMouseDown:r,currentPan2Dxyzmm:s,crosshairMM:n,yoke3Dto2DZoom:a}=t;let o=r[3];const l=i-e;o+=l*.01,o=Math.max(o,.1),o=Math.min(o,10);const h=s[3]-o,d={zoom:o,pan2Dxyzmm:[s[0]+h*n[0],s[1]+h*n[1],s[2]+h*n[2],o]};return a&&(d.volScaleMultiplier=o),d}function V1(t){const{x:e,y:i,windowX:r,windowY:s,currentCalMin:n,currentCalMax:a,globalMin:o,globalMax:l,gainFactor:c}=t;let h=Number.isFinite(c)?c:.5;h<0&&(h=0);let d=n,f=a;const u=(i-s)*h,m=(e-r)*h;return u<0?(d+=Math.abs(u),f+=Math.abs(u)):u>0&&(d-=u,f-=u),m>0?(d-=m,f+=m):m<0&&(d+=Math.abs(m),f-=Math.abs(m)),f-d<1&&(f=d+1),d<o&&(d=o),f>l&&(f=l),d>f&&(d=f-1),{calMin:d,calMax:f,windowX:e,windowY:i}}function P1(t){const{xrange:e,yrange:i,zrange:r,dims:s,img:n}=t;let a=-Number.MAX_VALUE,o=Number.MAX_VALUE;const l=s[1],c=s[2];for(let h=r[0];h<r[1];h++){const d=h*l*c;for(let f=i[0];f<i[1];f++){const u=f*l;for(let m=e[0];m<e[1];m++){const p=d+u+m;o>n[p]&&(o=n[p]),a<n[p]&&(a=n[p])}}}return{lo:o,hi:a,hasVariation:o<a}}function N1(t,e,i,r,s){const n=[...i],a=[...r],o=[...s];return t[0]-e[0]===0?n[1]=t[0]+1:t[1]-e[1]===0?a[1]=t[1]+1:t[2]-e[2]===0&&(o[1]=t[2]+1),{xrange:n,yrange:a,zrange:o}}function L1(t){return t===7}function Vs(t){return Nr.includes(t)?"mesh":t==="NVD"?"document":"volume"}function k1(t){return t.lastIndexOf("BRIK")!==-1?"brik":t.toUpperCase().lastIndexOf("IMG")!==-1?"img":null}function O1(t,e){const i=t.name.lastIndexOf("HEAD");if(i===-1)return null;const r=t.name.substring(0,i);for(const s of Array.from(e)){const n=s.webkitGetAsEntry();if(!n)continue;const a=n.name.lastIndexOf("BRIK");if(a===-1)continue;const o=n.name.substring(0,a);if(r===o)return n}return null}function z1(t,e){const r=t.name.toUpperCase().lastIndexOf("HDR");if(r===-1)return null;const s=t.name.substring(0,r);for(const n of Array.from(e)){const a=n.webkitGetAsEntry();if(!a)continue;const l=a.name.toUpperCase().lastIndexOf("IMG");if(l===-1)continue;const c=a.name.substring(0,l);if(s.toUpperCase()===c.toUpperCase())return a}return null}function G1(t,e){const i=O1(t,e);return i||z1(t,e)}function Ps(t){return new Promise((e,i)=>{t.file(e,i)})}function Y1(t){const e=[];for(const i of Array.from(t)){const r=i.webkitGetAsEntry();if(!r){F.warn("could not get entry from dropped item");continue}if(r.isFile){if(k1(r.name))continue;const s=G1(r,t);e.push({entry:r,pairedEntry:s})}}return e}function X1(t){const e=[];for(const i of Array.from(t)){const r=i.webkitGetAsEntry();r?.isDirectory&&e.push(r)}return e}function W1(t){return t.getData("text/uri-list")||null}function K1(t){return t.items.length>0}function Xr(t){const{x:e,y:i,screenSlices:r}=t;for(let s=0;s<r.length;s++){const n=r[s].leftTopWidthHeight;if(e>n[0]&&i>n[1]&&e<n[0]+n[2]&&i<n[1]+n[3])return s}return-1}function H1(t){const{x:e,y:i,screenSlices:r}=t,s=Xr({x:e,y:i,screenSlices:r});return s>=0&&r[s].axCorSag===4?s:-1}function q1(t){const{x:e,y:i,graph:r,volumesLength:s,firstVolumeFrameCount:n}=t;if(r.opacity<=0||s<1||n<1||!r.plotLTWH||r.plotLTWH[2]<1||r.plotLTWH[3]<1)return!1;const a=[(e-r.LTWH[0])/r.LTWH[2],(i-r.LTWH[1])/r.LTWH[3]];return a[0]>0&&a[1]>0&&a[0]<=1&&a[1]<=1}function Q1(t){const{x:e,y:i,dpr:r,canvasHeight:s,boundsRegion:n}=t,[a,o,l,c]=n,h=e*r,d=s-i*r;return h>=a&&h<=a+l&&d>=o&&d<=o+c}function gi(t){const{sliceType:e,crosshairPos:i}=t;return e===0?i[2]:e===1?i[1]:e===2?i[0]:0}function Z1(t){const{dragStart:e,screenSlices:i,crosshairPos:r,currentSliceType:s,canvasPos2frac:n}=t,a=Xr({x:e[0],y:e[1],screenSlices:i});if(a>=0&&a<i.length){const l=i[a].axCorSag,c=gi({sliceType:l,crosshairPos:r});return{sliceIndex:a,sliceType:l,slicePosition:c}}let o=0;return s===0?o=r[2]:s===1?o=r[1]:s===2?o=r[0]:s===3&&n([e[0],e[1]])[0]>=0&&(o=r[2]),{sliceIndex:-1,sliceType:s,slicePosition:o}}function j1(t){const{sliceType:e,slicePosition:i,currentSliceTypeOpt:r,screenSlices:s,crosshairPos:n}=t;if(r===3){if(e>2)return!1;for(let c=0;c<s.length;c++)if(s[c].axCorSag===e){const h=gi({sliceType:e,crosshairPos:n});if(Math.abs(h-i)<.001)return!0}return!1}if(e!==r)return!1;const a=gi({sliceType:e,crosshairPos:n});return Math.abs(a-i)<.001}function _1(t){const{posChange:e,volumesLength:i,clipPlaneDepthAziElevs:r,activeClipPlaneIndex:s,volScaleMultiplier:n}=t;if(e===0)return{action:"none"};if(i>0&&r[s][0]<1.8){const o=r[s][0];let l=o;return e>0&&(l=Math.min(1.5,o+.025)),e<0&&(l=Math.max(-1.5,o-.025)),l!==o?{action:"clipPlane",newClipPlaneDepth:l}:{action:"none"}}let a=n;return e>0&&(a=Math.min(2,n*1.1)),e<0&&(a=Math.max(.5,n*.9)),{action:"zoom",newVolScaleMultiplier:a}}function J1(t){const{posChange:e,currentZoom:i,yoke3Dto2DZoom:r,crosshairMM:s}=t;let n=i*(1+10*e);n=Math.round(n*10)/10;const a=i-n;return{newZoom:n,zoomChange:a,panOffsetX:a*s[0],panOffsetY:a*s[1],panOffsetZ:a*s[2],newVolScaleMultiplier:r?n:void 0}}function $1(t){const{x:e,y:i,z:r,currentVox:s,dimsRAS:n}=t,a=Ve(s),o=a[2];return a[0]+=e,a[1]+=i,a[2]+=r,a[0]=Math.max(0,Math.min(a[0],n[1]-1)),a[1]=Math.max(0,Math.min(a[1],n[2]-1)),a[2]=Math.max(0,Math.min(a[2],n[3]-1)),{newVox:a,zChanged:o!==a[2]}}function e2(t){const{scrollRequiresFocus:e,canvasHasFocus:i}=t;return!e||i}function t2(t){const{posChange:e,dragMode:i,isInRenderTile:r}=t;return e!==0&&i===3&&!r}function i2(t){const{layout:e}=t;for(let i=0;i<e.length;i++){const[r,s,n,a]=e[i].position,o=r+n,l=s+a;for(let c=i+1;c<e.length;c++){const[h,d,f,u]=e[c].position,m=h+f,p=d+u,g=r<m&&o>h,x=s<p&&l>d;if(g&&x)return{valid:!1,error:`Custom layout is invalid. Tile ${i} overlaps with tile ${c}.`,overlappingTiles:[i,c]}}}return{valid:!0}}function r2(t){const{bounds:e,canvasWidth:i,canvasHeight:r,cssWidth:s,cssHeight:n,dpr:a}=t;if(!e)return[0,0,i,r];const[[o,l],[c,h]]=e,d=Math.floor(o*s*a),f=Math.ceil((c-o)*s*a);let u=Math.floor((1-h)*n*a),m=Math.ceil((h-l)*n*a);return u<0&&(m+=u,u=0),u+m>r&&(m=r-u),[d,u,f,m]}function s2(t){const{bounds:e,rectWidth:i,rectHeight:r}=t;if(!e)return[0,0,i,r];const[[s,n],[a,o]]=e,l=Math.round(s*i),c=Math.round((a-s)*i),h=Math.round(n*r),d=Math.round(o*r),f=d-h,u=r-d;return[l,u,c,f]}function n2(t){const{canvasHeight:e,bounds:i,colorbarHeight:r}=t;let s=e;if(i){const[[,n],[,a]]=i,o=Math.round(n*e);s=Math.round(a*e)-o}return s-r}function a2(t){const{canvasWidth:e,bounds:i,legendPanelWidth:r}=t;let s=e;if(i){const[[n],[a]]=i;s=Math.round((a-n)*e)}return s-r}function o2(t){const{forceVox:e,getScreenFieldOfViewMM:i,getScreenFieldOfViewVox:r,backDims:s}=t;let n=i(0);e&&(n=r(0));const a=Math.max(n[0],Math.max(n[1],n[2])),o=[n[0]/a,n[1]/a,n[2]/a],l=[s[1],s[2],s[3]];return{volScale:o,vox:l,longestAxis:a,dimsMM:n}}function l2(t){const{axCorSag:e,sliceFrac:i,frac2mm:r,swizzleVec3MM:s}=t;let n=2;e===1&&(n=1),e===2&&(n=0);const a=[0,0,0],o=[1,1,0],l=[1,0,1];a[n]=i,o[n]=i,l[n]=i;const c=r(a),h=r(o),d=r(l),f=s(k(c[0],c[1],c[2]),e),u=s(k(h[0],h[1],h[2]),e),m=s(k(d[0],d[1],d[2]),e),p=(u[0]-f[0])*(m[1]-f[1])-(m[0]-f[0])*(u[1]-f[1]);let g=(u[0]-f[0])*(m[2]-f[2])-(m[0]-f[0])*(u[2]-f[2]);g/=p;let x=(u[1]-f[1])*(m[2]-f[2])-(m[1]-f[1])*(u[2]-f[2]);x/=p;const A=[0,0,0,0,0];return A[0]=f[0],A[1]=f[1],A[2]=f[2],A[3]=x,A[4]=g,A}function c2(t){const{labels:e,fontPx:i,textHeight:r}=t;if(e.length===0)return 0;const s=e.length===1?e[0].style.bulletScale??1:e.reduce((l,c)=>(l.style.bulletScale??1)>(c.style.bulletScale??1)?l:c).style.bulletScale??1,n=e.length===1?e[0]:e.reduce((l,c)=>{const h=i*l.style.textScale,d=i*c.style.textScale;return r(h,l.text)>r(d,c.text)?l:c}),a=i*n.style.textScale;let o=r(a,n.text)*s;return o+=a,o}function h2(t){const{labels:e,showLegend:i,fontPx:r,canvasWidth:s,textWidth:n,getBulletMarginWidth:a}=t;if(!i||e.length===0)return 0;const l=r*1;let c=0;const h=e.reduce((m,p)=>{const g=r*m.style.textScale,x=r*p.style.textScale;return n(g,m.text)>n(x,p.text)?m:p}),d=r*h.style.textScale,f=n(d,h.text),u=a();return f&&(c=u+f,c+=l*2),c>=s?0:c}function d2(t){const{labels:e,fontPx:i,panelScale:r,textHeight:s}=t;let n=0;const a=i;for(const o of e){const l=i*o.style.textScale*r,c=s(l,o.text);n+=c}return n&&(n+=a/2*(e.length+1)*r),n}function f2(t){const{fontPx:e,boundsRegion:i,colorbarWidth:r}=t,s=3*e;if(s<0)return{leftTopWidthHeight:[0,0,0,0],colorbarHeight:0};const[n,a,o,l]=i,h=(r>0&&r<=1?r:1)*o;return{leftTopWidthHeight:[n+(o-h)/2,a+l-s,h,s],colorbarHeight:s+1}}function u2(t){const{x:e,y:i,boundsRegion:r}=t,[s,n,a,o]=r;return e>=s&&e<=s+a&&i>=n&&i<=n+o}function m2(t){const{mouseX:e,mouseY:i,boundsRegion:r}=t;if(e<0||i<0)return!1;const[s,n,a,o]=r;return e>=s&&e<=s+a&&i>=n&&i<=n+o}function p2(t){let e=t%360;return e<0&&(e+=360),e}function g2(t){const{currentAzimuth:e,currentElevation:i,deltaX:r,deltaY:s}=t,n=p2(e+r),a=i+s;return{azimuth:n,elevation:a}}function A2(t){const{dx:e,dy:i,threshold:r=1}=t;return Math.abs(e)>=r||Math.abs(i)>=r}var x2=[0,0,0,2],v2=[2,0,0],w2=1.8;function ha(t){const{depth:e,azimuth:i,elevation:r}=t,s=bi(i+180,r);return[s[0],s[1],s[2],e]}function y2(t){const{depth:e,azimuth:i,elevation:r}=t,s=bi(i,r);return[s[0],s[1],s[2],-e]}function b2(t){const{startDepthAziElev:e,dragDeltaX:i,dragDeltaY:r}=t,s=[e[0],(e[1]-i)%360,e[2]+r],n=s[1]!==e[1]||s[2]!==e[2];return{depthAziElev:s,changed:n}}function C2(t){const{index:e}=t,i=t.clipPlanes?[...t.clipPlanes]:[],r=t.clipPlaneDepthAziElevs?[...t.clipPlaneDepthAziElevs]:[];for(;i.length<=e;)i.push([...x2]);for(;r.length<=e;)r.push([...v2]);return{clipPlanes:i,clipPlaneDepthAziElevs:r}}function M2(t,e=w2){return t<e}function D2(t){const{depthAziElevs:e}=t,i=[],r=[];for(const s of e){const n=y2({depth:s[0],azimuth:s[1],elevation:s[2]});i.push(n),r.push([...s])}return{clipPlanes:i,clipPlaneDepthAziElevs:r}}function T2(t){const{isDragging:e,activeClipPlaneDepth:i,dragStartTileIndex:r}=t;return e&&M2(i)&&r>=0}function S2(t){const{index:e,depthAzimuthElevation:i}=t,{clipPlanes:r,clipPlaneDepthAziElevs:s}=C2({clipPlanes:t.clipPlanes,clipPlaneDepthAziElevs:t.clipPlaneDepthAziElevs,index:e}),n=ha({depth:i[0],azimuth:i[1],elevation:i[2]});return r[e]=n,s[e]=[...i],{clipPlanes:r,clipPlaneDepthAziElevs:s,clipPlane:n}}function E2(t){return!!t&&t.length>0}function I2(t){const e=t.length;let i=0;const r=new Uint8Array(e+Math.ceil(.01*e)),s=new Int8Array(r.buffer);let n=0;for(;i<e;){let a=t[i];i++;let o=1;for(;o<129&&i<e&&t[i]===a;)i++,o++;if(o>1){s[n]=-o+1,n++,r[n]=a,n++;continue}for(;i<e&&!(o>127||i+2<e&&a!==t[i]&&t[i+2]===t[i]&&t[i+1]===t[i]);)a=t[i],i++,o++;r[n]=o-1,n++;for(let l=0;l<o;l++)r[n]=t[i-o+l],n++}return F.debug("PackBits "+e+" -> "+n+" bytes (x"+e/n+")"),r.slice(0,n)}function Wr(t,e){const i=new Uint8Array(t.buffer),r=new Int8Array(i.buffer);let s=0;const n=new Uint8Array(e);let a=0;for(;s<i.length;){const o=r[s];if(s++,o<0){const l=r[s];s++;for(let c=0;c<1-o;c++)n[a]=l,a++}else for(let l=0;l<o+1;l++)n[a]=r[s],s++,a++}return n}var F2=({drawUndoBitmaps:t,currentDrawUndoBitmap:e,drawBitmap:i})=>{const r=t.length;if(r<1){F.debug("undo bitmaps not loaded");return}if(e--,e<0&&(e=r-1),e>=r&&(e=0),t[e].length<2){F.debug("drawUndo is misbehaving");return}return i=Wr(t[e],i.length),{drawBitmap:i,currentDrawUndoBitmap:e}};function B2(t,e,i){const{dimX:r,dimY:s,dimZ:n}=i;let a;if(t===0)a=n;else if(t===1)a=s;else if(t===2)a=r;else return null;let o=-1,l=-1;for(let c=0;c<a;c++){let h=!1;if(t===0){const d=c*r*s;for(let f=0;f<r*s;f++)if(e[d+f]>0){h=!0;break}}else if(t===1)for(let d=0;d<n;d++){for(let f=0;f<r;f++){const u=f+c*r+d*r*s;if(e[u]>0){h=!0;break}}if(h)break}else if(t===2)for(let d=0;d<n;d++){for(let f=0;f<s;f++){const u=c+f*r+d*r*s;if(e[u]>0){h=!0;break}}if(h)break}h&&(o===-1&&(o=c),l=c)}return o===-1||l===-1?null:{first:o,last:l}}function Gi(t,e,i,r){const{dimX:s,dimY:n,dimZ:a}=r;let o;if(e===0){o=new Float32Array(s*n);const l=t*s*n;for(let c=0;c<s*n;c++)o[c]=i[l+c]}else if(e===1){o=new Float32Array(s*a);for(let l=0;l<a;l++)for(let c=0;c<s;c++){const h=c+t*s+l*s*n,d=c+l*s;o[d]=i[h]}}else if(e===2){o=new Float32Array(n*a);for(let l=0;l<a;l++)for(let c=0;c<n;c++){const h=t+c*s+l*s*n,d=c+l*n;o[d]=i[h]}}else throw new Error("Invalid slice type");return o}function Yi(t,e,i,r,s){const{dimX:n,dimY:a,dimZ:o}=r;let l;if(e===0){l=new Float32Array(n*a);const c=t*n*a;for(let h=0;h<n*a;h++)l[h]=i[c+h]/s}else if(e===1){l=new Float32Array(n*o);for(let c=0;c<o;c++)for(let h=0;h<n;h++){const d=h+t*n+c*n*a,f=h+c*n;l[f]=i[d]/s}}else if(e===2){l=new Float32Array(a*o);for(let c=0;c<o;c++)for(let h=0;h<a;h++){const d=t+h*n+c*n*a,f=h+c*a;l[f]=i[d]/s}}else throw new Error("Invalid slice type");return l}function U2(t,e,i,r,s,n,a){const{dimX:o,dimY:l,dimZ:c}=s;if(i===0){const h=e*o*l;for(let d=0;d<t.length;d++)t[d]>=n&&(r[h+d]=a)}else if(i===1)for(let h=0;h<c;h++)for(let d=0;d<o;d++){const f=d+h*o,u=d+e*o+h*o*l;t[f]>=n&&(r[u]=a)}else if(i===2)for(let h=0;h<c;h++)for(let d=0;d<l;d++){const f=d+h*l,u=e+d*o+h*o*l;t[f]>=n&&(r[u]=a)}else throw new Error("Invalid slice type")}function Ns(t,e,i){if(e<3||i<3)return;const r=new Float32Array(t.length);for(let s=0;s<i;s++)for(let n=0;n<e;n++){const a=n+s*e;n===0||n===e-1?r[a]=t[a]:r[a]=(t[a-1]+2*t[a]+t[a+1])*.25}for(let s=0;s<i;s++)for(let n=0;n<e;n++){const a=n+s*e;s===0||s===i-1?t[a]=r[a]:t[a]=(r[a-e]+2*r[a]+r[a+e])*.25}}function R2(t,e,i,r){const s=Math.abs(i-t),n=Math.abs(i-e),a=Math.exp(-s*s/(2*r*r)),o=Math.exp(-n*n/(2*r*r)),l=a+o;return l<1e-6?.5:a/l}function V2(t,e,i,r,s,n){const a=(i-r)/(s-r),o=1-a;for(let l=0;l<t.length;l++)n[l]=t[l]*o+e[l]*a}function P2(t,e,i,r,s,n,a,o,l,c){const h=(i-r)/(s-r),d=1-h;for(let f=0;f<t.length;f++)if(t[f]>0||e[f]>0){const u=R2(o[f],l[f],c[f],a.intensitySigma),m=a.intensityWeight,p=m*u+(1-m)*d,g=1-p;n[f]=t[f]*p+e[f]*g}else n[f]=t[f]*d+e[f]*h}function N2(t,e,i,r,s,n,a,o){const{dimX:l,dimY:c,dimZ:h}=e,d=a.sliceType??0;let f,u,m;if(d===0)f=l,u=c,m=h-1;else if(d===1)f=l,u=h,m=c-1;else if(d===2)f=c,u=h,m=l-1;else throw new Error("Invalid slice type. Must be AXIAL, CORONAL, or SAGITTAL");const p={intensityWeight:a.intensityWeight??.7,binaryThreshold:a.binaryThreshold??.375,intensitySigma:a.intensitySigma??.1,applySmoothingToSlices:a.applySmoothingToSlices??!0,useIntensityGuided:a.useIntensityGuided??!0};if(s!==void 0&&n!==void 0){if(s>=n)throw new Error("Low slice index must be less than high slice index");if(s<0||n>m)throw new Error(`Slice indices out of bounds [0, ${m}]`)}const g=new Map;for(let x=0;x<=m;x++){const A=Gi(x,d,t,e);for(let y=0;y<A.length;y++){const v=A[y];if(v>0)if(!g.has(v))g.set(v,{min:x,max:x});else{const b=g.get(v);b.min=Math.min(b.min,x),b.max=Math.max(b.max,x)}}}for(const[x,A]of g){const y=s!==void 0?Math.max(s,A.min):A.min,v=n!==void 0?Math.min(n,A.max):A.max;if(y>=v||v-y<2)continue;const b=Gi(y,d,t,e),w=Gi(v,d,t,e),C=new Float32Array(b.length),M=new Float32Array(w.length);for(let T=0;T<b.length;T++)C[T]=b[T]===x?1:0,M[T]=w[T]===x?1:0;p.applySmoothingToSlices&&(Ns(C,f,u),Ns(M,f,u));for(let T=y+1;T<v;T++){const E=new Float32Array(f*u);if(p.useIntensityGuided&&i){const I=Yi(y,d,i,e,r),S=Yi(v,d,i,e,r),U=Yi(T,d,i,e,r);P2(C,M,T,y,v,E,p,I,S,U)}else V2(C,M,T,y,v,E);U2(E,T,d,t,e,p.binaryThreshold,x)}}o()}function L2(t,e){const i=[...t],r=e;if(!i||i.length<1)return{drawUndoBitmaps:i,currentDrawUndoBitmap:r};for(let s=i.length-1;s>=0;s--)i[s]=new Uint8Array;return{drawUndoBitmaps:i,currentDrawUndoBitmap:r}}function k2(t){const{drawBitmap:e,drawUndoBitmaps:i,currentDrawUndoBitmap:r,maxDrawUndoBitmaps:s,drawFillOverwrites:n}=t;if(!e||e.length<1)return F.debug("addUndoBitmap error: No drawing open"),{drawBitmap:e,drawUndoBitmaps:i,currentDrawUndoBitmap:r,needsRefresh:!1};const a=[...i];let o=e,l=!1;if(!n&&a.length>0){const h=e.length,d=Wr(a[r],h);o=new Uint8Array(e);for(let f=0;f<h;f++)d[f]>0&&(o[f]=d[f]);l=!0}let c=r+1;return c>=s&&(c=0),a[c]=I2(o),{drawBitmap:o,drawUndoBitmaps:a,currentDrawUndoBitmap:c,needsRefresh:l}}function Xi(t,e,i){const r=new Array(t);if(i)for(let s=0;s<t;s++)r[s]=(t-1-s)*e;else for(let s=0;s<t;s++)r[s]=s*e;return r}function O2(t){const{permRAS:e,dims:i}=t,r=[0,0,0];for(let h=0;h<3;h++)for(let d=0;d<3;d++)Math.abs(e[h])-1===d&&(r[d]=h*Math.sign(e[h]));let s=1;const n=[1,1,1],a=[!1,!1,!1];for(let h=0;h<r.length;h++)for(let d=0;d<r.length;d++)Math.abs(r[d])===h&&(n[d]=s,(r[d]<0||Object.is(r[d],-0))&&(a[d]=!0),s*=i[d+1]);const o=Xi(i[1],n[0],a[0]),l=Xi(i[2],n[1],a[1]),c=Xi(i[3],n[2],a[2]);return{instride:n,inflip:a,xlut:o,ylut:l,zlut:c}}function z2(t){const{inputData:e,dims:i,xlut:r,ylut:s,zlut:n}=t,a=i[1]*i[2]*i[3],o=new Uint8Array(a);let l=0;for(let c=0;c<i[3];c++)for(let h=0;h<i[2];h++)for(let d=0;d<i[1];d++)o[r[d]+s[h]+n[c]]=e[l],l++;return o}function G2(t){const{drawingDims:e,backgroundDims:i}=t;return e[1]===i[1]&&e[2]===i[2]&&e[3]===i[3]}function Wi(t){return!t||t.length<4?0:t[1]*t[2]*t[3]}function Ki(t){return new Uint8Array(t)}function Y2(t){let{useClickToSegmentBitmap:e,drawingEnabled:i,clickToSegment:r,drawBitmap:s,clickToSegmentGrowingBitmap:n}=t,a=null;e&&(!i||!r)&&(F.debug("determineBitmapDataSource: Conditions not met for clickToSegment bitmap, using drawBitmap."),e=!1);const o=e?n:s;return!o&&!e&&n?a="drawBitmap is null, but clickToSegmentGrowingBitmap exists. Check state.":!o&&e&&s?(a="clickToSegmentGrowingBitmap is null, falling back to drawBitmap.",e=!1):o||(a="Both bitmaps are null. Uploading empty data."),{bitmapDataSource:e?n:s,useClickToSegmentBitmap:e,warning:a}}function X2(t){const{clickToSegmentIsGrowing:e,drawShapePreviewBitmap:i,drawBitmap:r}=t;let s=r,n=!1;return e&&(n=!0),i&&(s=i),{clickToSegmentIsGrowing:!1,drawPenLocation:[NaN,NaN,NaN],drawPenAxCorSag:-1,drawPenFillPts:[],drawShapeStartLocation:[NaN,NaN,NaN],drawShapePreviewBitmap:null,drawBitmap:s,needsRefresh:n}}function W2(t,e){return t===8?[e[0],2,2,2,...e.slice(4)]:e}function K2(t,e){return t===8?!0:t===e}function Ls(t,e,i,r,s){return t+e*r+i*r*s}function Oe(t,e){return Math.min(Math.max(t,0),e-1)}function gt(t){const{x:e,y:i,z:r,penValue:s,drawBitmap:n,dims:a,penSize:o,penAxCorSag:l}=t,c=a[1],h=a[2],d=a[3],f=Oe(e,c),u=Oe(i,h),m=Oe(r,d);if(n[Ls(f,u,m,c,h)]=s,o>1){const p=Math.floor(o/2),g=l===0,x=l===1,A=l===2;for(let y=-p;y<=p;y++)for(let v=-p;v<=p;v++){let b,w,C;if(g)b=Oe(f+y,c),w=Oe(u+v,h),C=m;else if(x)b=Oe(f+y,c),w=u,C=Oe(m+v,d);else if(A)b=f,w=Oe(u+v,h),C=Oe(m+y,d);else continue;n[Ls(b,w,C,c,h)]=s}}}function H2(t){const{ptA:e,ptB:i,penValue:r,drawBitmap:s,dims:n,penSize:a,penAxCorSag:o}=t,l=Math.abs(e[0]-i[0]),c=Math.abs(e[1]-i[1]),h=Math.abs(e[2]-i[2]),d=i[0]>e[0]?1:-1,f=i[1]>e[1]?1:-1,u=i[2]>e[2]?1:-1;let m=e[0],p=e[1],g=e[2];const x=i[0],A=i[1],y=i[2],v={x:0,y:0,z:0,penValue:r,drawBitmap:s,dims:n,penSize:a,penAxCorSag:o};if(l>=c&&l>=h){let b=2*c-l,w=2*h-l;for(;m!==x;)m+=d,b>=0&&(p+=f,b-=2*l),w>=0&&(g+=u,w-=2*l),b+=2*c,w+=2*h,v.x=m,v.y=p,v.z=g,gt(v)}else if(c>=l&&c>=h){let b=2*l-c,w=2*h-c;for(;p!==A;)p+=f,b>=0&&(m+=d,b-=2*c),w>=0&&(g+=u,w-=2*c),b+=2*l,w+=2*h,v.x=m,v.y=p,v.z=g,gt(v)}else{let b=2*c-h,w=2*l-h;for(;g!==y;)g+=u,b>=0&&(p+=f,b-=2*h),w>=0&&(m+=d,w-=2*h),b+=2*c,w+=2*l,v.x=m,v.y=p,v.z=g,gt(v)}}function da(t){const{img2D:e,dims2D:i,minPt:r,maxPt:s}=t,n=i[0],[a,o]=r,[l,c]=s,h=4*(l-a+c-o+2),d=new Int32Array(h*2);let f=0,u=0;function m(x,A){if(x<a||x>l||A<o||A>c)return;const y=x+A*n;e[y]===0&&(e[y]=2,d[u]=x,d[u+1]=A,u=(u+2)%d.length)}function p(){if(f===u)return null;const x=d[f],A=d[f+1];return f=(f+2)%d.length,[x,A]}for(let x=a;x<=l;x++)m(x,o),m(x,c);for(let x=o+1;x<=c-1;x++)m(a,x),m(l,x);let g;for(;(g=p())!==null;){const[x,A]=g;m(x-1,A),m(x+1,A),m(x,A-1),m(x,A+1)}}function ks(t,e,i,r,s){const n=Math.abs(i[0]-r[0]),a=Math.abs(i[1]-r[1]);t[i[0]+i[1]*e[0]]=s,t[r[0]+r[1]*e[0]]=s;const o=r[0]>i[0]?1:-1,l=r[1]>i[1]?1:-1;let c=i[0],h=i[1];const d=r[0],f=r[1];if(n>=a){let u=2*a-n;for(;c!==d;)c+=o,u>=0&&(h+=l,u-=2*n),u+=2*a,t[c+h*e[0]]=s}else{let u=2*n-a;for(;h!==f;)h+=l,u>=0&&(c+=o,u-=2*a),u+=2*n,t[c+h*e[0]]=s}}function Os(t,e){const i=Math.min(Math.max(t[0],0),e[0]-1),r=Math.min(Math.max(t[1],0),e[1]-1);return[i,r]}function q2(t){let e=0,i=1;return t===1?i=2:t===2&&(e=1,i=2),[e,i]}function Q2(t){const{penFillPts:e,penAxCorSag:i,drawBitmap:r,dims:s,penValue:n,fillOverwrites:a,currentUndoBitmap:o}=t,l=e.length;if(l<2)return{drawBitmap:r,success:!1};const[c,h]=q2(i),d=[s[c+1],s[h+1]],f=new Uint8Array(d[0]*d[1]),u=1,m=Os([e[0][c],e[0][h]],d);let p=[...m],g=[...m],x=m;for(let w=1;w<l;w++){let C=[e[w][c],e[w][h]];C=Os(C,d),p=[Math.min(C[0],p[0]),Math.min(C[1],p[1])],g=[Math.max(C[0],g[0]),Math.max(C[1],g[1])],ks(f,d,x,C,u),x=C}ks(f,d,m,x,u);const A=1;p[0]=Math.max(0,p[0]-A),p[1]=Math.max(0,p[1]-A),g[0]=Math.min(d[0]-1,g[0]+A),g[1]=Math.min(d[1]-1,g[1]+A);for(let w=0;w<d[1];w++)for(let C=0;C<d[0];C++){if(C>=p[0]&&C<g[0]&&w>=p[1]&&w<=g[1])continue;const M=C+w*d[0];f[M]===0&&(f[M]=2)}const y=Date.now();da({img2D:f,dims2D:d,minPt:p,maxPt:g}),F.debug(`FloodFill ${Date.now()-y}`);const v=e[0][3-(c+h)],b=new Uint8Array(r);if(i===0){const w=v*d[0]*d[1];for(let C=0;C<d[0]*d[1];C++)f[C]!==2&&(b[C+w]=n)}else{let w=1;const C=s[1]*s[2];let M=v*s[1];i===2&&(w=s[1],M=v);let T=0;for(let E=0;E<d[1];E++)for(let I=0;I<d[0];I++)f[T]!==2&&(b[I*w+E*C+M]=n),T++}if(!a&&o&&o.length>0){const w=b.length,C=Wr(o,w);for(let M=0;M<w;M++)C[M]!==0&&(b[M]=C[M])}return{drawBitmap:b,success:!0}}function fa(t){const{ptA:e,ptB:i,dims:r}=t,s=r[1],n=r[2],a=r[3],o=Math.min(Math.max(Math.min(e[0],i[0]),0),s-1),l=Math.min(Math.max(Math.min(e[1],i[1]),0),n-1),c=Math.min(Math.max(Math.min(e[2],i[2]),0),a-1),h=Math.min(Math.max(Math.max(e[0],i[0]),0),s-1),d=Math.min(Math.max(Math.max(e[1],i[1]),0),n-1),f=Math.min(Math.max(Math.max(e[2],i[2]),0),a-1);return{x1:o,y1:l,z1:c,x2:h,y2:d,z2:f}}function Z2(t){const{x1:e,y1:i,z1:r,x2:s,y2:n,z2:a}=t,o=(e+s)/2,l=(i+n)/2,c=(r+a)/2,h=Math.abs(s-e)/2,d=Math.abs(n-i)/2,f=Math.abs(a-r)/2;return{centerX:o,centerY:l,centerZ:c,radiusX:h,radiusY:d,radiusZ:f}}function j2(t,e,i,r){const{centerX:s,centerY:n,centerZ:a,radiusX:o,radiusY:l,radiusZ:c}=r,h=(t-s)/(o+.5),d=(e-n)/(l+.5),f=(i-a)/(c+.5);return h*h+d*d+f*f<=1}function _2(t){const{ptA:e,ptB:i,penValue:r,drawBitmap:s,dims:n,penSize:a,penAxCorSag:o}=t,l=fa({ptA:e,ptB:i,dims:n}),{x1:c,y1:h,z1:d,x2:f,y2:u,z2:m}=l,p={x:0,y:0,z:0,penValue:r,drawBitmap:s,dims:n,penSize:a,penAxCorSag:o};for(let g=d;g<=m;g++)for(let x=h;x<=u;x++)for(let A=c;A<=f;A++)p.x=A,p.y=x,p.z=g,gt(p)}function J2(t){const{ptA:e,ptB:i,penValue:r,drawBitmap:s,dims:n,penSize:a,penAxCorSag:o}=t,l=fa({ptA:e,ptB:i,dims:n}),{x1:c,y1:h,z1:d,x2:f,y2:u,z2:m}=l,p=Z2(l),g={x:0,y:0,z:0,penValue:r,drawBitmap:s,dims:n,penSize:a,penAxCorSag:o};for(let x=d;x<=m;x++)for(let A=h;A<=u;A++)for(let y=c;y<=f;y++)j2(y,A,x,p)&&(g.x=y,g.y=A,g.z=x,gt(g))}function $2(t,e,i){return t[0]+t[1]*e+t[2]*i}function em(t,e,i){const r=Math.floor(t/i),s=Math.floor((t-r*i)/e);return[Math.floor(t%e),s,r]}function ua(t){const e=t[0],i=e*t[1],r=i*t[2];return{xyz2vx:s=>$2(s,e,i),vx2xyz:s=>em(s,e,i),nx:e,nxy:i,nxyz:r}}function tm(t,e){return t?e===0?2:e===1?1:e===2?0:-1:-1}var Hi={face:[[0,0,-1],[0,0,1],[0,-1,0],[0,1,0],[-1,0,0],[1,0,0]],edge:[[-1,-1,0],[1,-1,0],[-1,1,0],[1,1,0],[0,-1,-1],[0,1,-1],[-1,0,-1],[1,0,-1],[0,-1,1],[0,1,1],[-1,0,1],[1,0,1]],corner:[[-1,-1,-1],[1,-1,-1],[-1,1,-1],[1,1,-1],[-1,-1,1],[1,-1,1],[-1,1,1],[1,1,1]]};function im(t){const{img:e,seedVx:i,dims:r,neighbors:s=6}=t,n=ua(r),a=[];a.push(i),e[i]=2;const o=[...Hi.face];for(s>=18&&o.push(...Hi.edge),s>=26&&o.push(...Hi.corner);a.length>0;){const l=a.shift(),c=n.vx2xyz(l);for(const h of o){const d=[c[0]+h[0],c[1]+h[1],c[2]+h[2]];if(d[0]<0||d[1]<0||d[2]<0||d[0]>=r[0]||d[1]>=r[1]||d[2]>=r[2])continue;const f=n.xyz2vx(d);e[f]===1&&(e[f]=2,a.push(f))}}}function rm(t){const{voxelIntensity:e,thresholdPercent:i,calMin:r,calMax:s,autoIntensity:n,currentIntensityMin:a,currentIntensityMax:o,currentBright:l}=t;let c=a,h=o,d=l;if(n){if(i!==0){const f=e===0?.01:e;h=f*(1+i),c=f*(1-i)}d=e>(r+s)*.5}return{intensityMin:c,intensityMax:h,isBright:d}}function sm(t){return t?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY}function nm(t){const{sourceBitmap:e,targetBitmap:i}=t;if(!e||!i||e.length!==i.length)return!1;const r=i.length;for(let s=0;s<r;s++)i[s]=e[s];return!0}function am(t){let e=0;for(let i=0;i<t.length;i++)e+=t[i];return e}function om(t){const{clusterImg:e,backImg:i,nxyz:r,fallbackIntensity:s}=t;let n=0,a=0;for(let o=0;o<r;o++)e[o]===2&&(n+=i[o],a++);return a>0?n/a:s}function zs(t,e,i,r){return isFinite(i)&&isFinite(r)?[i,r]:t===Number.POSITIVE_INFINITY?[e,1/0]:t===Number.NEGATIVE_INFINITY?[-1/0,e]:[-1/0,1/0]}function lm(t,e){return!(t[0]<0||t[1]<0||t[2]<0||t[0]>=e[0]||t[1]>=e[1]||t[2]>=e[2])}function cm(t){return t!==0}function hm(t,e,i,r){return i&&r!==0?t!==0:t!==0||e===0}function dm(t){const{img:e,targetBitmap:i,originalBitmap:r,newColor:s,nxyz:n,isPreviewMode:a}=t;let o=0;for(let l=0;l<n;l++)e[l]===2?(i[l]=s,o++):a&&(i[l]=r[l]);return o}function fm(t){const{img:e,dims:i}=t,r=i[1]*i[2]*i[3],s=new Uint8Array(r);for(let n=0;n<r;n++)e[n]!==0&&(s[n]=1);return{img:s,datatypeCode:2,cal_min:0,cal_max:1}}function um(t){const{img:e,cal_min:i,cal_max:r,scl_inter:s,scl_slope:n,mlevel:a=2}=t,o=e.length;if(o<1)return[];const l=256,c=l-1,h=new Array(l).fill(0),d=i,f=r;if(f<=d)return[];const u=(f-d)/l;function m(v){return v*u+d}const p=(l-1)/Math.abs(f-d);for(let v=0;v<o;v++){let b=e[v]*n+s;b=Math.min(Math.max(b,d),f),b=Math.round((b-d)*p),h[b]++}const g=Array(l).fill(0).map(()=>Array(l).fill(0)),x=Array(l).fill(0).map(()=>Array(l).fill(0));for(let v=1;v<l;++v)g[v][v]=h[v],x[v][v]=v*h[v];for(let v=1;v<l-1;++v)g[1][v+1]=g[1][v]+h[v+1],x[1][v+1]=x[1][v]+(v+1)*h[v+1];for(let v=2;v<l;v++)for(let b=v+1;b<l;b++)g[v][b]=g[1][b]-g[1][v-1],x[v][b]=x[1][b]-x[1][v-1];for(let v=1;v<l;++v)for(let b=v+1;b<l;b++)g[v][b]!==0&&(g[v][b]=x[v][b]*x[v][b]/g[v][b]);let A=0;const y=[1/0,1/0,1/0];if(a>3)for(let v=0;v<l-3;v++)for(let b=v+1;b<l-2;b++)for(let w=b+1;w<l-1;w++){const C=g[0][v]+g[v+1][b]+g[b+1][w]+g[w+1][c];C>A&&(y[0]=v,y[1]=b,y[2]=w,A=C)}else if(a===3)for(let v=0;v<l-2;v++)for(let b=v+1;b<l-1;b++){const w=g[0][v]+g[v+1][b]+g[b+1][c];w>A&&(y[0]=v,y[1]=b,A=w)}else for(let v=0;v<l-1;v++){const b=g[0][v]+g[v+1][c];b>A&&(y[0]=v,A=b)}return[m(y[0]),m(y[1]),m(y[2])]}function mm(t){const{img:e,drawBitmap:i,thresholds:r}=t,s=e.length,n=new Uint8Array(i);for(let a=0;a<s;a++){if(n[a]!==0)continue;const o=e[a];o>r[0]&&(n[a]=1),o>r[1]&&(n[a]=2),o>r[2]&&(n[a]=3)}return n}function pm(t){const{level:e}=t;return e===5||e===1?4:e===4||e===2?3:2}function gm(t){const{level:e,thresholds:i}=t;return e===1?i[2]:e===2?i[1]:i[0]}function Am(t){const{img:e,scl_inter:i,scl_slope:r,global_min:s,threshold:n}=t,a=e.length;for(let o=0;o<a;o++)e[o]*r+i<n&&(e[o]=s)}function pe(t,e,i,r){return i*r[0]*r[1]+e*r[0]+t}function Kr(t,e,i){let r=0;const s=new Uint32Array(i+5).fill(0);let a=2147483647;for(let o=0;o<i;o++){let l=e[o];for(r=0;t[l-1]!==l;)if(l=t[l-1],r++,r>100){F.info(`
|
|
2366
|
+
Ooh no!!`);break}s[o]=l,a=Math.min(a,l)}for(let o=0;o<i;o++)t[s[o]-1]=a}function ma(t,e,i,r,s,n,a,o){const l=new Uint32Array(27);let c=0;if(!s)return 0;const h=t[pe(i,r,s,n)];if(a>=6){const d=pe(i,r,s-1,n);h===t[d]&&(l[c++]=e[d])}if(a>=18){if(i){const d=pe(i-1,r,s-1,n);h===t[d]&&(l[c++]=e[d])}if(r){const d=pe(i,r-1,s-1,n);h===t[d]&&(l[c++]=e[d])}if(i<n[0]-1){const d=pe(i+1,r,s-1,n);h===t[d]&&(l[c++]=e[d])}if(r<n[1]-1){const d=pe(i,r+1,s-1,n);h===t[d]&&(l[c++]=e[d])}}if(a===26){if(i&&r){const d=pe(i-1,r-1,s-1,n);h===t[d]&&(l[c++]=e[d])}if(i<n[0]-1&&r){const d=pe(i+1,r-1,s-1,n);h===t[d]&&(l[c++]=e[d])}if(i&&r<n[1]-1){const d=pe(i-1,r+1,s-1,n);h===t[d]&&(l[c++]=e[d])}if(i<n[0]-1&&r<n[1]-1){const d=pe(i+1,r+1,s-1,n);h===t[d]&&(l[c++]=e[d])}}return c?(Kr(o,l,c),l[0]):0}function pa(t,e,i){let r=1;const s=8192;let n=s,a=new Uint32Array(n).fill(0);const o=new Uint32Array(e[0]*e[1]*e[2]).fill(0),l=new Uint32Array(27);for(let c=0;c<e[2];c++)for(let h=0;h<e[1];h++)for(let d=0;d<e[0];d++){let f=0;const u=t[pe(d,h,c,e)];if(u!==0){if(l[0]=ma(t,o,d,h,c,e,i,a),l[0]&&(f+=1),i>=6){if(d){const m=pe(d-1,h,c,e);u===t[m]&&(l[f++]=o[m])}if(h){const m=pe(d,h-1,c,e);u===t[m]&&(l[f++]=o[m])}}if(i>=18){if(h&&d){const m=pe(d-1,h-1,c,e);u===t[m]&&(l[f++]=o[m])}if(h&&d<e[0]-1){const m=pe(d+1,h-1,c,e);u===t[m]&&(l[f++]=o[m])}}if(f)o[pe(d,h,c,e)]=l[0],Kr(a,l,f);else{if(o[pe(d,h,c,e)]=r,r>=n){n+=s;const m=new Uint32Array(n);m.set(a),a=m}a[r-1]=r,r++}}}for(let c=0;c<r-1;c++){let h=c;for(;a[h]!==h+1;)h=a[h]-1;a[c]=h+1}return{labelCount:r-1,translationTable:a,initialLabels:o}}function ga(t,e,i,r){const s=e[0]*e[1]*e[2];let n=0;const a=new Uint32Array(s).fill(0);for(let c=0;c<r;c++)n=Math.max(n,i[c]);const o=new Uint32Array(n).fill(0);let l=0;for(let c=0;c<s;c++)t[c]&&(o[i[t[c]-1]-1]||(l+=1,o[i[t[c]-1]-1]=l),a[c]=o[i[t[c]-1]-1]);return{clusterCount:l,labels:a}}function Aa(t,e,i){const r=t.length,s=new Uint32Array(e+1).fill(0),n=new Uint32Array(e+1).fill(0);for(let l=0;l<r;l++){const c=t[l],h=i[l];s[h]=c,n[h]++}let a=0;for(let l=0;l<e+1;l++){const c=s[l];a=Math.max(a,c);for(let h=0;h<e+1;h++)h!==l&&c===s[h]&&(n[l]<n[h]||n[l]===n[h]&&l<h)&&(s[l]=0)}const o=new Uint32Array(r).fill(0);for(let l=0;l<r;l++)o[l]=s[i[l]];return{maxValue:a,voxels:o}}function xm(t){const{img:e,dim:i,conn:r=26,binarize:s=!1,onlyLargestClusterPerClass:n=!1}=t,a=Date.now(),o=i[0]*i[1]*i[2],l=new Uint32Array(o).fill(0);if(![6,18,26].includes(r))return F.info("bwlabel: conn must be 6, 18 or 26."),{clusterCount:0,labels:l};if(i[0]<2||i[1]<2||i[2]<1)return F.info("bwlabel: img must be 2 or 3-dimensional"),{clusterCount:0,labels:l};if(s)for(let m=0;m<o;m++)e[m]!==0&&(l[m]=1);else l.set(e);let{labelCount:c,translationTable:h,initialLabels:d}=pa(l,i,r);h===void 0&&(h=new Uint32Array);const{clusterCount:f,labels:u}=ga(d,i,h,c);if(F.info(r+" neighbor clustering into "+f+" regions in "+(Date.now()-a)+"ms"),n){const{maxValue:m,voxels:p}=Aa(l,f,u);return{clusterCount:m,labels:p}}return{clusterCount:f,labels:u}}function vm(t,e=0,i=255,r,s){const n=t.length,a=new Uint8Array(n);for(let o=0;o<n;o++){let l=t[o];l=e+s*(l-r),l=Math.max(l,e),l=Math.min(l,i),a[o]=l}return a}function wm(t,e=0,i=1,r,s){const n=t.length,a=new Float32Array(n);for(let o=0;o<n;o++){let l=t[o];l=e+s*(l-r),l=Math.max(l,e),l=Math.min(l,i),a[o]=l}return a}function Gs(t){const{img:e,dims:i,global_min:r,global_max:s,datatypeCode:n,scl_slope:a,scl_inter:o,cal_min:l,cal_max:c,dst_min:h=0,dst_max:d=255,f_low:f=0,f_high:u=.999}=t;let m=r,p=s;if(n===2)return[m,1];if((!isFinite(f)||!isFinite(u))&&isFinite(l)&&isFinite(c)&&c>l){m=l,p=c;const I=(d-h)/(p-m);return F.info(" Robust Rescale: min: "+m+" max: "+p+" scale: "+I),[m,I]}const g=i[1]*i[2]*i[3];let x=e;if(a!==1||o!==0){const I=new Float32Array(g);for(let S=0;S<g;S++)I[S]=e[S]*a+o;x=I}if(m<0&&F.warn("WARNING: Input image has value(s) below 0.0 !"),F.info(" Input: min: "+m+" max: "+p),f===0&&u===1)return[m,1];let A=0;for(let I=0;I<g;I++)Math.abs(x[I])>=1e-15&&A++;const y=1e3,v=(p-m)/y,b=new Array(y).fill(0);for(let I=0;I<g;I++){const S=x[I];let U=Math.floor((S-m)/v);U=Math.min(U,y-1),b[U]++}const w=new Array(y).fill(0);w[0]=b[0];for(let I=1;I<y;I++)w[I]=w[I-1]+b[I];let C=Math.floor(f*g),M=0;for(;M<y&&!(w[M]>=C);)M++;const T=m;for(m=M*v+T,C=g-Math.floor((1-u)*A),M=0;M<y-1&&!(w[M+1]>=C);)M++;p=M*v+T;let E=1;return m!==p&&(E=(d-h)/(p-m)),F.info(" Rescale: min: "+m+" max: "+p+" scale: "+E),[m,E]}function ym(t){const{inDims:e,inAffine:i,outDim:r=256,outDims:s,outMM:n=1,toRAS:a=!1}=t,[o,l,c]=s??[r,r,r],h=i.flat(),d=Ee(h[0],h[1],h[2],h[3],h[4],h[5],h[6],h[7],h[8],h[9],h[10],h[11],h[12],h[13],h[14],h[15]),f=ae(e[1]/2,e[2]/2,e[3]/2,1),u=Xe(),m=J();Te(m,d),ve(u,f,m);const p=k(u[0],u[1],u[2]),g=k(n,n,n);let x=Ee(-1,0,0,0,0,0,1,0,0,-1,0,0,0,0,0,1);a&&(x=Ee(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)),Te(x,x);const A=ae(o,l,c,1),y=J();fr(y,x,g);const v=ae(A[0],A[1],A[2],1);ve(v,v,y),Va(v,v,.5);const b=se();ne(b,p,k(v[0],v[1],v[2]));const w=J();Te(w,y),w[3]=b[0],w[7]=b[1],w[11]=b[2];const C=J();Se(C,w);const M=J();Qs(M,d,C);const T=J();return Se(T,M),{outAffine:w,vox2vox:M,invVox2vox:T}}function bm(t){const{inImg:e,inDims:i,outDim:r,outDims:s,invVox2vox:n,isLinear:a}=t,[o,l,c]=s??[r??256,r??256,r??256],h=o*l*c,d=new Float32Array(h),f=i[1],u=i[2],m=i[3],p=f*u;function g(b,w,C){return b+w*f+C*p}const x=n[0],A=n[4],y=n[8];let v=-1;if(a)for(let b=0;b<c;b++)for(let w=0;w<l;w++){const C=w*n[1]+b*n[2]+n[3],M=w*n[5]+b*n[6]+n[7],T=w*n[9]+b*n[10]+n[11];for(let E=0;E<o;E++){const I=E*x+C,S=E*A+M,U=E*y+T,B=Math.floor(I),V=Math.floor(S),R=Math.floor(U);if(v++,B<0||V<0||R<0)continue;const P=Math.ceil(I),L=Math.ceil(S),N=Math.ceil(U);if(P>=f||L>=u||N>=m)continue;const Y=I-B,_=S-V,z=U-R,W=1-Y,K=1-_,Z=1-z,q=g(B,V,R);let te=0;te+=e[q]*W*K*Z,te+=e[q+p]*W*K*z,te+=e[q+f]*W*_*Z,te+=e[q+f+p]*W*_*z,te+=e[q+1]*Y*K*Z,te+=e[q+1+p]*Y*K*z,te+=e[q+1+f]*Y*_*Z,te+=e[q+1+f+p]*Y*_*z,d[v]=te}}else for(let b=0;b<c;b++)for(let w=0;w<l;w++){const C=w*n[1]+b*n[2]+n[3],M=w*n[5]+b*n[6]+n[7],T=w*n[9]+b*n[10]+n[11];for(let E=0;E<o;E++){const I=Math.round(E*x+C),S=Math.round(E*A+M),U=Math.round(E*y+T);v++,!(I<0||S<0||U<0)&&(I>=f||S>=u||U>=m||(d[v]=e[g(I,S,U)]))}}return d}function Cm(t,e,i,r,s){const n=new Uint8Array(t);n.fill(0);let a=-1;if(e[0]===i[0])a=0;else if(e[1]===i[1])a=1;else if(e[2]===i[2])a=2;else return console.error("Error: No constant dimension found."),null;const l=[0,1,2].filter(w=>w!==a),c=[];c[a]=e[a],c[l[0]]=(e[l[0]]+i[l[0]])/2,c[l[1]]=(e[l[1]]+i[l[1]])/2;const h=Math.abs(i[l[0]]-e[l[0]])/2,d=Math.abs(i[l[1]]-e[l[1]])/2,f=r.dims[1],u=r.dims[2],m=Math.max(0,Math.floor(c[l[0]]-h)),p=Math.min(r.dims[l[0]+1]-1,Math.ceil(c[l[0]]+h)),g=Math.max(0,Math.floor(c[l[1]]-d)),x=Math.min(r.dims[l[1]+1]-1,Math.ceil(c[l[1]]+d)),A=c[a];if(A<0||A>=r.dims[a+1])return console.error("Error: Constant dimension value is out of bounds."),null;for(let w=m;w<=p;w++)for(let C=g;C<=x;C++){const M=[];M[a]=A,M[l[0]]=w,M[l[1]]=C;const T=(M[l[0]]-c[l[0]])/h,E=(M[l[1]]-c[l[1]])/d;if(T*T+E*E<=1){const S=M[0],U=M[1],V=M[2]*f*u+U*f+S;n[V]=1}}const y=h*s[l[0]+1],v=d*s[l[1]+1],b=Math.PI*y*v;return{mask:n,area:b}}function Mm(t){const{nv:e,maskImages:i,drawBitmap:r,drawingIsMask:s,roiIsMask:n,startVox:a,endVox:o,hdr:l,pixDimsRAS:c}=t,h=new Uint8Array(e);h.fill(1);const d=null;if(i&&i.length>0){for(const f of i)if(f.length===e)for(let u=0;u<e;u++)(f[u]===0||isNaN(f[u]))&&(h[u]=0)}else if(s&&r)for(let f=0;f<e;f++)(r[f]===0||isNaN(r[f]))&&(h[f]=0);else if(n&&a&&o&&l&&c){const f=Cm(e,a,o,l,c);return f?{mask:f.mask,area:f.area}:{mask:h,area:null}}return{mask:h,area:d}}function Dm(t,e){const i=t.length;let r=0,s=0,n=0,a=Number.NEGATIVE_INFINITY,o=Number.POSITIVE_INFINITY,l=0,c=0,h=0;for(let p=0;p<i;p++){if(e[p]<1)continue;const g=t[p];r++;let x=s+(g-s)/r;n=n+(g-s)*(g-x),s=x,g!==0&&(l++,x=c+(g-c)/l,h=h+(g-c)*(g-x),c=x,o=Math.min(g,o),a=Math.max(g,a))}const d=Math.sqrt(n/(r-1)),f=Math.sqrt(h/(l-1)),u=o,m=a;return r!==l&&(o=Math.min(0,o),a=Math.max(0,a)),{mean:s,stdev:d,nvox:r,min:o,max:a,meanNot0:c,stdevNot0:f,nvoxNot0:l,minNot0:u,maxNot0:m}}function Tm(t,e,i){const r=t.length,s=new Float32Array(r);for(let n=0;n<r;n++)s[n]=t[n]*e+i;return s}var Sm=class extends CustomEvent{constructor(t,e){super(t,{detail:e})}},{version:Ys}=pl,{MESH_EXTENSIONS:Zt}=Zn,{LEFT_MOUSE_BUTTON:jt,CENTER_MOUSE_BUTTON:Xs,RIGHT_MOUSE_BUTTON:Ws}=sa,Ks={filename:"",isSaveDrawing:!1,volumeByIndex:0},ft,Lm=class extends EventTarget{constructor(t=ke){super(),D(this,"loaders",{}),D(this,"dicomLoader",null),D(this,"canvas",null),D(this,"_gl",null),D(this,"isBusy",!1),D(this,"needsRefresh",!1),D(this,"colormapTexture",null),D(this,"colormapLists",[]),D(this,"volumeTexture",null),D(this,"gradientTexture",null),D(this,"gradientTextureAmount",0),D(this,"useCustomGradientTexture",!1),D(this,"renderGradientValues",!1),D(this,"drawTexture",null),D(this,"drawSmoothedTexture",null),D(this,"paqdTexture",null),D(this,"drawUndoBitmaps",[]),D(this,"drawLut",re.makeDrawLut("$itksnap")),D(this,"drawOpacity",.8),D(this,"drawRimOpacity",-1),D(this,"clickToSegmentIsGrowing",!1),D(this,"clickToSegmentGrowingBitmap",null),D(this,"clickToSegmentXY",[0,0]),D(this,"renderDrawAmbientOcclusion",.4),D(this,"colorbarHeight",0),D(this,"drawPenLocation",[NaN,NaN,NaN]),D(this,"drawPenAxCorSag",-1),D(this,"drawFillOverwrites",!0),D(this,"drawPenFillPts",[]),D(this,"drawShapeStartLocation",[NaN,NaN,NaN]),D(this,"drawShapePreviewBitmap",null),D(this,"overlayTexture",null),D(this,"overlayTextureID",null),D(this,"sliceMMShader"),D(this,"slice2DShader"),D(this,"sliceV1Shader"),D(this,"orientCubeShader"),D(this,"orientCubeShaderVAO",null),D(this,"rectShader"),D(this,"rectOutlineShader"),D(this,"renderShader"),D(this,"lineShader"),D(this,"line3DShader"),D(this,"passThroughShader"),D(this,"renderGradientShader"),D(this,"renderGradientValuesShader"),D(this,"renderSliceShader"),D(this,"renderVolumeShader"),D(this,"pickingMeshShader"),D(this,"pickingImageShader"),D(this,"colorbarShader"),D(this,"customSliceShader",null),D(this,"fontShader",null),D(this,"fiberShader"),D(this,"fontTexture",null),D(this,"circleShader"),D(this,"matCapTexture",null),D(this,"bmpShader",null),D(this,"bmpTexture",null),D(this,"thumbnailVisible",!1),D(this,"bmpTextureWH",1),D(this,"growCutShader"),D(this,"orientShaderAtlasU",null),D(this,"orientShaderAtlasI",null),D(this,"orientShaderU",null),D(this,"orientShaderI",null),D(this,"orientShaderF",null),D(this,"orientShaderRGBU",null),D(this,"orientShaderPAQD",null),D(this,"surfaceShader",null),D(this,"blurShader",null),D(this,"gradientPrePassShader",null),D(this,"sobelFirstOrderShader",null),D(this,"sobelSecondOrderShader",null),D(this,"genericVAO",null),D(this,"unusedVAO",null),D(this,"crosshairs3D",null),D(this,"DEFAULT_FONT_GLYPH_SHEET",fs),D(this,"DEFAULT_FONT_METRICS",us),D(this,"fontMetrics"),D(this,"fontMets",null),D(this,"fontPx",12),D(this,"legendFontScaling",1),D(this,"backgroundMasksOverlays",0),D(this,"overlayOutlineWidth",0),D(this,"overlayAlphaShader",1),D(this,"position"),D(this,"extentsMin"),D(this,"extentsMax"),D(this,"resizeObserver",null),D(this,"resizeEventListener",null),D(this,"canvasObserver",null),D(this,"syncOpts",{"3d":!1,"2d":!1,zoomPan:!1,cal_min:!1,cal_max:!1,clipPlane:!1,gamma:!1,sliceType:!1,crosshair:!1}),D(this,"readyForSync",!1),D(this,"_skipDragInDraw",!1),D(this,"uiData",{mousedown:!1,touchdown:!1,mouseButtonLeftDown:!1,mouseButtonCenterDown:!1,mouseButtonRightDown:!1,mouseDepthPicker:!1,clickedTile:-1,pan2DxyzmmAtMouseDown:[0,0,0,1],prevX:0,prevY:0,currX:0,currY:0,currentTouchTime:0,lastTouchTime:0,touchTimer:null,doubleTouch:!1,isDragging:!1,dragStart:[0,0],dragEnd:[0,0],dragClipPlaneStartDepthAziElev:[0,0,0],lastTwoTouchDistance:0,multiTouchGesture:!1,windowX:0,windowY:0,activeDragMode:null,activeDragButton:null,angleFirstLine:[0,0,0,0],angleState:"none",activeClipPlaneIndex:0}),lt(this,ft,null),D(this,"back",null),D(this,"overlays",[]),D(this,"deferredVolumes",[]),D(this,"deferredMeshes",[]),D(this,"furthestVertexFromOrigin",100),D(this,"volScale",[]),D(this,"vox",[]),D(this,"mousePos",[0,0]),D(this,"screenSlices",[]),D(this,"cuboidVertexBuffer"),D(this,"otherNV",null),D(this,"volumeObject3D",null),D(this,"pivot3D",[0,0,0]),D(this,"furthestFromPivot",10),D(this,"currentClipPlaneIndex",0),D(this,"lastCalled",new Date().getTime()),D(this,"selectedObjectId",-1),D(this,"CLIP_PLANE_ID",1),D(this,"VOLUME_ID",254),D(this,"DISTANCE_FROM_CAMERA",-.54),D(this,"graph",{LTWH:[0,0,640,480],opacity:0,vols:[0],autoSizeMultiplanar:!1,normalizeValues:!1,isRangeCalMinMax:!1}),D(this,"customLayout",[]),D(this,"meshShaders",Vd()),D(this,"dragModes",{contrast:1,measurement:2,angle:7,none:0,pan:3,slicer3D:4,callbackOnly:5}),D(this,"sliceTypeAxial",0),D(this,"sliceTypeCoronal",1),D(this,"sliceTypeSagittal",2),D(this,"sliceTypeMultiplanar",3),D(this,"sliceTypeRender",4),D(this,"onDragRelease",()=>{}),D(this,"onMouseUp",()=>{}),D(this,"onLocationChange",()=>{}),D(this,"onIntensityChange",()=>{}),D(this,"onClickToSegment",()=>{}),D(this,"onImageLoaded",()=>{}),D(this,"onMeshLoaded",()=>{}),D(this,"onFrameChange",()=>{}),D(this,"onError",()=>{}),D(this,"onColormapChange",()=>{}),D(this,"onInfo",()=>{}),D(this,"onWarn",()=>{}),D(this,"onDebug",()=>{}),D(this,"onVolumeAddedFromUrl",()=>{}),D(this,"onVolumeWithUrlRemoved",()=>{}),D(this,"onVolumeUpdated",()=>{}),D(this,"onMeshAddedFromUrl",()=>{}),D(this,"onMeshAdded",()=>{}),D(this,"onMeshWithUrlRemoved",()=>{}),D(this,"onZoom3DChange",()=>{}),D(this,"onAzimuthElevationChange",()=>{}),D(this,"onClipPlaneChange",()=>{}),D(this,"onCustomMeshShaderAdded",()=>{}),D(this,"onMeshShaderChanged",()=>{}),D(this,"onMeshPropertyChanged",()=>{}),D(this,"onDicomLoaderFinishedWithImages",()=>{}),D(this,"onDocumentLoaded",()=>{}),D(this,"onOptsChange",()=>{}),D(this,"onMeasurementCompleted",()=>{}),D(this,"onAngleCompleted",()=>{}),D(this,"onPenValueChanged",()=>{}),D(this,"onDrawingToolChanged",()=>{}),D(this,"onVolumeRemoved",()=>{}),D(this,"onMeshRemoved",()=>{}),D(this,"onSliceTypeChange",()=>{}),D(this,"onDrawingChanged",()=>{}),D(this,"onDrawingEnabled",()=>{}),D(this,"onVolumeOrderChanged",()=>{}),D(this,"document",new St),D(this,"mediaUrlMap",new Map),D(this,"initialized",!1),D(this,"currentDrawUndoBitmap");for(const e in t)typeof t[e]=="function"?this[e]=t[e]:this.opts[e]=ke[e]===void 0?ke[e]:t[e];this.opts.forceDevicePixelRatio===0?this.uiData.dpr=window.devicePixelRatio||1:this.opts.forceDevicePixelRatio<0?this.uiData.dpr=1:this.uiData.dpr=this.opts.forceDevicePixelRatio,this.currentDrawUndoBitmap=this.opts.maxDrawUndoBitmaps,this.opts.drawingEnabled&&this.createEmptyDrawing(),this.opts.thumbnail.length>0&&(this.thumbnailVisible=!0),F.setLogLevel(this.opts.logLevel),this.document.setOptsChangeCallback((e,i,r)=>{this._emitEvent("optsChange",{propertyName:e,newValue:i,oldValue:r}),this.onOptsChange(e,i,r)}),this.scene.onZoom3DChange=e=>{this._emitEvent("zoom3DChange",{zoom:e}),this.onZoom3DChange(e)}}get scene(){return this.document.scene}get opts(){return this.document.opts}get sliceMosaicString(){return this.document.opts.sliceMosaicString||""}set sliceMosaicString(t){this.document.opts.sliceMosaicString=t}get isAlphaClipDark(){return this.document.opts.isAlphaClipDark}set isAlphaClipDark(t){this.document.opts.isAlphaClipDark=t}addEventListener(t,e,i){super.addEventListener(t,e,i)}removeEventListener(t,e,i){super.removeEventListener(t,e,i)}_emitEvent(t,e){try{const i=new Sm(t,e);this.dispatchEvent(i)}catch(i){console.error(`Error in ${t} event listener:`,i)}}cleanup(){Ou(this.resizeObserver,this.canvasObserver,this.resizeEventListener),this.resizeEventListener=null,this.resizeObserver=null,this.canvasObserver=null,zu(X(this,ft)),Ke(this,ft,null),this.document.removeOptsChangeCallback()}get volumes(){return this.document.volumes}set volumes(t){this.document.volumes=t}get meshes(){return this.document.meshes}set meshes(t){this.document.meshes=t}get drawBitmap(){return this.document.drawBitmap}set drawBitmap(t){this.document.drawBitmap=t}get volScaleMultiplier(){return this.scene.volScaleMultiplier}set volScaleMultiplier(t){this.setScale(t)}async saveScene(t="niivue.png"){function e(r,s){const n=document.createElement("a");document.body.appendChild(n),n.style.display="none";const a=window.URL.createObjectURL(r);n.href=a,n.download=s,n.click(),n.remove()}const i=this.canvas;if(!i)throw new Error("canvas not defined");this.drawScene(),i.toBlob(r=>{r&&(t===""&&(t=`niivue-screenshot-${new Date().toString()}.png`,t=t.replace(/\s/g,"_")),e(r,t))})}async attachTo(t,e=null){return await this.attachToCanvas(document.getElementById(t),e),F.debug("attached to element with id: ",t),this}async attachToCanvas(t,e=null){this.canvas=t,e===null&&(e=navigator.hardwareConcurrency>6,F.debug("AntiAlias ",e," Threads ",navigator.hardwareConcurrency));const{gl:i,max2D:r,max3D:s}=Kc(this.canvas,e);return this.gl=i,this.uiData.max2D=r,this.uiData.max3D=s,F.info("NIIVUE VERSION ",Ys),F.debug(`Max texture size 2D: ${this.uiData.max2D} 3D: ${this.uiData.max3D}`),this.canvas.parentElement.style.backgroundColor="black",this.opts.isResizeCanvas&&(Bs(this.canvas),this.canvas.width=this.canvas.offsetWidth,this.canvas.height=this.canvas.offsetHeight,this.resizeEventListener=Pu(()=>this.resizeListener()),window.addEventListener("resize",this.resizeEventListener),this.resizeObserver=Nu(()=>this.resizeListener()),this.resizeObserver.observe(this.canvas.parentElement),this.canvasObserver=Lu(n=>{for(const a of n)if(a.type==="childList"&&a.removedNodes.length>0&&Array.from(a.removedNodes).includes(this.canvas)){this.cleanup();break}}),this.canvasObserver.observe(this.canvas.parentElement,{childList:!0})),this.opts.interactive&&this.registerInteractions(),await this.init(),this.drawScene(),this}syncWith(t,e={"2d":!0,"3d":!0}){t instanceof Array||(t=[t]),this.otherNV=t,this.syncOpts={...e}}broadcastTo(t,e={"2d":!0,"3d":!0}){t instanceof Array||(t=[t]),this.otherNV=t,this.syncOpts=e}doSync3d(t){t.scene.renderAzimuth=this.scene.renderAzimuth,t.scene.renderElevation=this.scene.renderElevation,t.scene.volScaleMultiplier=this.scene.volScaleMultiplier}doSync2d(t){const e=this.frac2mm(this.scene.crosshairPos);t.scene.crosshairPos=t.mm2frac(e),t.scene.pan2Dxyzmm=ze(this.scene.pan2Dxyzmm)}doSyncGamma(t){const e=this.scene.gamma,i=t.scene.gamma;e!==i&&t.setGamma(e)}doSyncZoomPan(t){t.scene.pan2Dxyzmm=ze(this.scene.pan2Dxyzmm)}doSyncCrosshair(t){const e=this.frac2mm(this.scene.crosshairPos);t.scene.crosshairPos=t.mm2frac(e)}doSyncCalMin(t){this.volumes[0].cal_min!==t.volumes[0].cal_min&&(t.volumes[0].cal_min=this.volumes[0].cal_min,t.updateGLVolume())}doSyncCalMax(t){this.volumes[0].cal_max!==t.volumes[0].cal_max&&(t.volumes[0].cal_max=this.volumes[0].cal_max,t.updateGLVolume())}doSyncSliceType(t){t.setSliceType(this.opts.sliceType)}doSyncClipPlane(t){t.setClipPlane(this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex])}sync(){if(!(!this.gl||!this.otherNV||typeof this.otherNV>"u")&&this.gl.canvas.matches(":focus"))for(let t=0;t<this.otherNV.length;t++)this.otherNV[t]!==this&&(this.syncOpts.gamma&&this.doSyncGamma(this.otherNV[t]),this.syncOpts.crosshair&&this.doSyncCrosshair(this.otherNV[t]),this.syncOpts.zoomPan&&this.doSyncZoomPan(this.otherNV[t]),this.syncOpts.sliceType&&this.doSyncSliceType(this.otherNV[t]),this.syncOpts.cal_min&&this.doSyncCalMin(this.otherNV[t]),this.syncOpts.cal_max&&this.doSyncCalMax(this.otherNV[t]),this.syncOpts.clipPlane&&this.doSyncClipPlane(this.otherNV[t]),this.syncOpts["2d"]&&this.doSync2d(this.otherNV[t]),this.syncOpts["3d"]&&this.doSync3d(this.otherNV[t]),this.otherNV[t].canvas!==this.canvas&&this.otherNV[t].drawScene(),this.otherNV[t].createOnLocationChange())}arrayEquals(t,e){return Array.isArray(t)&&Array.isArray(e)&&t.length===e.length&&t.every((i,r)=>i===e[r])}textSizePoints(){this.opts.textHeight>=0&&(F.warn("textHeight is deprecated (use fontMinPx and fontSizeScaling)"),this.opts.fontMinPx=this.opts.textHeight*217,this.opts.fontSizeScaling=.4,this.opts.textHeight=-1);const t=this.uiData.dpr||1,e=this.opts.fontMinPx,i=this.gl.canvas.width/t,r=this.gl.canvas.height/t,s=i*r,n=800*600,a=Math.max(s/n,1),o=Math.pow(a,this.opts.fontSizeScaling),l=e*o*t;this.fontPx=l,F.debug(`${i.toFixed(0)}x${r.toFixed(0)} pts (dpi=${t}) => areaScale=${a.toFixed(2)}, scale=${o.toFixed(2)}, minPx=${this.opts.fontMinPx} fontScale=${this.opts.fontSizeScaling} fontPx=${l.toFixed(2)}`)}resizeListener(){if(!ku(this.canvas,this._gl))return;if(!this.opts.isResizeCanvas){this.opts.forceDevicePixelRatio>=0&&F.warn("this.opts.forceDevicePixelRatio requires isResizeCanvas"),this.drawScene();return}Bs(this.canvas);const t=Vu({canvas:this.canvas,gl:this.gl,isResizeCanvas:this.opts.isResizeCanvas,forceDevicePixelRatio:this.opts.forceDevicePixelRatio});this.uiData.dpr=t.dpr,F.debug("devicePixelRatio: "+this.uiData.dpr),this.canvas.width=t.width,this.canvas.height=t.height,this.gl.viewport(0,0,this.gl.canvas.width,this.gl.canvas.height),this.textSizePoints(),this.drawScene()}getRelativeMousePosition(t,e){return ra(t,e)}getNoPaddingNoBorderCanvasRelativeMousePosition(t,e){return Uu(t,e)}mouseContextMenuListener(t){t.preventDefault()}mouseDownListener(t){if(this.uiData.mousedown=!0,this.eventInBounds(t))this.opts.bounds&&(this.opts.showBoundsBorder=!0);else{this.opts.showBoundsBorder=!1,this.drawScene();return}t.preventDefault(),this.drawPenLocation=[NaN,NaN,NaN],this.drawPenAxCorSag=-1,this.drawShapeStartLocation=[NaN,NaN,NaN];const e=this.getNoPaddingNoBorderCanvasRelativeMousePosition(t,this.gl.canvas);if(this.opts.dragMode===7&&this.uiData.angleState==="drawing_second_line"||(this.setDragStart(e.x,e.y),this.setDragEnd(e.x,e.y)),F.debug("mouse down"),F.debug(t),!e)return;const[i,r]=[e.x*this.uiData.dpr,e.y*this.uiData.dpr];this.opts.clickToSegment&&(this.clickToSegmentXY=[i,r]);const s=this.getLabelAtPoint([i,r]);if(s){if(s.onClick){s.onClick(s,t);return}for(const n of this.meshes){if(n.type!=="connectome"){if(Array.isArray(s.points)&&s.points.length===3&&s.points.every(Number.isFinite)){const[a,o,l]=s.points;this.scene.crosshairPos=this.mm2frac([a,o,l]),this.updateGLVolume()}continue}for(const a of n.nodes)a.label===s&&(this.scene.crosshairPos=this.mm2frac([a.x,a.y,a.z]),this.updateGLVolume())}}this.uiData.clickedTile=this.tileIndex(i,r),t.button===jt&&t.shiftKey?(this.uiData.mouseButtonCenterDown=!0,this.setActiveDragMode(jt,!0,t.ctrlKey),this.handleMouseAction(this.uiData.activeDragMode,t,e)):t.button===jt?(this.uiData.mouseButtonLeftDown=!0,this.setActiveDragMode(jt,!1,t.ctrlKey),this.handleMouseAction(this.uiData.activeDragMode,t,e)):t.button===Ws?(this.uiData.mouseButtonRightDown=!0,this.setActiveDragMode(Ws,t.shiftKey,t.ctrlKey),this.handleMouseAction(this.uiData.activeDragMode,t,e)):t.button===Xs&&(this.uiData.mouseButtonCenterDown=!0,this.setActiveDragMode(Xs,t.shiftKey,t.ctrlKey),this.handleMouseAction(this.uiData.activeDragMode,t,e)),this.drawScene()}getMouseButtonDragMode(t,e,i){return na({button:t,shiftKey:e,ctrlKey:i,mouseConfig:this.opts.mouseEventConfig,dragMode:this.opts.dragMode,dragModePrimary:this.opts.dragModePrimary})}getTouchDragMode(t){return Qu({isDoubleTouch:t,touchConfig:this.opts.touchEventConfig,dragMode:this.opts.dragMode,dragModePrimary:this.opts.dragModePrimary})}setActiveDragMode(t,e,i){const r=this.getMouseButtonDragMode(t,e,i),s=E1(r,t);this.uiData.activeDragMode=s.activeDragMode,this.uiData.activeDragButton=s.activeDragButton}getCurrentDragMode(){return T1({activeDragMode:this.uiData.activeDragMode,fallbackDragMode:this.opts.dragMode})}clearActiveDragMode(){const t=S1();this.uiData.activeDragMode=t.activeDragMode,this.uiData.activeDragButton=t.activeDragButton}handleMouseAction(t,e,i){if(t===8)this.mouseDown(i.x,i.y),this.mouseClick(i.x,i.y);else if(t===9)this.uiData.windowX=i.x,this.uiData.windowY=i.y;else{if(this.mousePos=[i.x*this.uiData.dpr,i.y*this.uiData.dpr],t===0)return;if(t===7)if(this.uiData.angleState==="none")this.uiData.angleState="drawing_first_line";else if(this.uiData.angleState==="drawing_second_line"){const r=[i.x*this.uiData.dpr,i.y*this.uiData.dpr],s=this.tileIndex(r[0],r[1]);let n={sliceIndex:-1,sliceType:0,slicePosition:0};if(s>=0&&s<this.screenSlices.length){const d=this.screenSlices[s].axCorSag;let f=0;d===0?f=this.scene.crosshairPos[2]:d===1?f=this.scene.crosshairPos[1]:d===2&&(f=this.scene.crosshairPos[0]),n={sliceIndex:s,sliceType:d,slicePosition:f}}const a=[this.uiData.angleFirstLine[2],this.uiData.angleFirstLine[3],r[0],r[1]],o=this.canvasPos2frac([this.uiData.angleFirstLine[0],this.uiData.angleFirstLine[1]]),l=this.canvasPos2frac([this.uiData.angleFirstLine[2],this.uiData.angleFirstLine[3]]),c=this.canvasPos2frac([a[0],a[1]]),h=this.canvasPos2frac([a[2],a[3]]);if(o[0]>=0&&l[0]>=0&&c[0]>=0&&h[0]>=0){const d=this.frac2mm(o),f=this.frac2mm(l),u=this.frac2mm(c),m=this.frac2mm(h),p={firstLineMM:{start:k(d[0],d[1],d[2]),end:k(f[0],f[1],f[2])},secondLineMM:{start:k(u[0],u[1],u[2]),end:k(m[0],m[1],m[2])},sliceIndex:n.sliceIndex,sliceType:n.sliceType,slicePosition:n.slicePosition,angle:this.calculateAngleBetweenLines(this.uiData.angleFirstLine,a)};this.document.completedAngles.push(p),this._emitEvent("angleCompleted",p),this.onAngleCompleted(p)}this.resetAngleMeasurement(),this.uiData.angleState="complete",this.drawScene();return}else this.uiData.angleState==="complete"&&(this.resetAngleMeasurement(),this.uiData.angleState="drawing_first_line");if(this.setDragStart(i.x,i.y),!this.uiData.isDragging){this.uiData.pan2DxyzmmAtMouseDown=ze(this.scene.pan2Dxyzmm);for(const r of this.getZarrVolumes())r.zarrHelper?.beginDrag()}this.uiData.isDragging=!0,this.uiData.dragClipPlaneStartDepthAziElev=this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex]}}calculateMinMaxVoxIdx(t){return I1(t)}calculateNewRange({volIdx:t=0}={}){if(this.opts.sliceType===4&&this.sliceMosaicString.length<1||!dr(this.uiData.dragStart,this.uiData.dragEnd))return;let e=this.canvasPos2frac([this.uiData.dragStart[0],this.uiData.dragStart[1]]);if(e[0]<0)return;const i=this.frac2vox(e,t);if(e=this.canvasPos2frac([this.uiData.dragEnd[0],this.uiData.dragEnd[1]]),e[0]<0)return;const r=this.frac2vox(e,t),s=this.calculateMinMaxVoxIdx([i[0],r[0]]),n=this.calculateMinMaxVoxIdx([i[1],r[1]]),a=this.calculateMinMaxVoxIdx([i[2],r[2]]),o=N1(i,r,s,n,a),l=this.volumes[t].hdr,c=this.volumes[t].img;if(!l||!c)return;const h=P1({xrange:o.xrange,yrange:o.yrange,zrange:o.zrange,dims:l.dims,img:c});if(!h.hasVariation)return;const d=ws(l,h.lo),f=ws(l,h.hi);this.volumes[t].cal_min=d,this.volumes[t].cal_max=f,this._emitEvent("intensityChange",this.volumes[t]),this.onIntensityChange(this.volumes[t])}generateMouseUpCallback(t,e){const i=this.tileIndex(this.uiData.dragStart[0],this.uiData.dragStart[1]),r=this.tileIndex(this.uiData.dragEnd[0],this.uiData.dragEnd[1]);let s=-1;i===r&&(s=r);let n=-1;s>=0&&(n=this.screenSlices[s].axCorSag);const a=this.frac2mm(t),o=this.frac2mm(e),l=se();Qr(l,k(a[0],a[1],a[2]),k(o[0],o[1],o[2]));const c=Vt(l),h=this.frac2vox(t),d=this.frac2vox(e),f={fracStart:t,fracEnd:e,voxStart:h,voxEnd:d,mmStart:a,mmEnd:o,mmLength:c,tileIdx:s,axCorSag:n};this._emitEvent("dragRelease",f),this.onDragRelease(f)}mouseUpListener(){this.uiData.mousedown=!1;const t={mouseButtonRightDown:this.uiData.mouseButtonRightDown,mouseButtonCenterDown:this.uiData.mouseButtonCenterDown,isDragging:this.uiData.isDragging,mousePos:this.mousePos,fracPos:this.canvasPos2frac(this.mousePos)};this.uiData.mouseButtonRightDown=!1;const e=this.uiData.mouseButtonCenterDown;this.uiData.mouseButtonCenterDown=!1,this.uiData.mouseButtonLeftDown=!1;const i=this.getCurrentDragMode();if(this.drawPenFillPts.length>0?this.drawPenFilled():this.opts.drawingEnabled&&!isNaN(this.drawPenLocation[0])?(this.drawAddUndoBitmap(),this._emitEvent("drawingChanged",{action:"draw"}),this.onDrawingChanged("draw")):this.opts.drawingEnabled&&!isNaN(this.drawShapeStartLocation[0])&&(this.opts.penType===1||this.opts.penType===2)&&(this.opts.penValue===0?this.drawAddUndoBitmap():this.drawAddUndoBitmap(this.drawFillOverwrites),this.drawShapePreviewBitmap=null,this._emitEvent("drawingChanged",{action:"draw"}),this.onDrawingChanged("draw")),this.drawPenLocation=[NaN,NaN,NaN],this.drawPenAxCorSag=-1,this.drawShapeStartLocation=[NaN,NaN,NaN],this.drawShapePreviewBitmap&&(this.drawBitmap=this.drawShapePreviewBitmap,this.drawShapePreviewBitmap=null,this.refreshDrawing(!0,!1)),this._emitEvent("mouseUp",t),ca(this.onMouseUp)&&this.onMouseUp(t),this.uiData.isDragging){this.uiData.isDragging=!1;for(const n of this.getZarrVolumes())n.zarrHelper?.endDrag();if(i===7){if(this.uiData.angleState==="drawing_first_line"){this.uiData.angleFirstLine=[this.uiData.dragStart[0],this.uiData.dragStart[1],this.uiData.dragEnd[0],this.uiData.dragEnd[1]],this.uiData.angleState="drawing_second_line",this.uiData.isDragging=!0,this.drawScene();return}if(this.uiData.angleState==="drawing_second_line"){this.uiData.angleState="complete",this.clearActiveDragMode(),this.drawScene();return}}i===5&&this.drawScene();const r=this.canvasPos2frac([this.uiData.dragStart[0],this.uiData.dragStart[1]]),s=this.canvasPos2frac([this.uiData.dragEnd[0],this.uiData.dragEnd[1]]);if(this.generateMouseUpCallback(r,s),i===6){this.clearActiveDragMode();return}if(i===1){if(e){this.clearActiveDragMode();return}if(!dr(this.uiData.dragStart,this.uiData.dragEnd)){this.clearActiveDragMode();return}this.calculateNewRange({volIdx:0}),this.refreshLayers(this.volumes[0],0)}if(i===2){const n=this.getCurrentSliceInfo(),a=this.canvasPos2frac([this.uiData.dragStart[0],this.uiData.dragStart[1]]),o=this.canvasPos2frac([this.uiData.dragEnd[0],this.uiData.dragEnd[1]]);if(a[0]>=0&&o[0]>=0){const l=this.frac2mm(a),c=this.frac2mm(o),h={startMM:k(l[0],l[1],l[2]),endMM:k(c[0],c[1],c[2]),sliceIndex:n.sliceIndex,sliceType:n.sliceType,slicePosition:n.slicePosition,distance:Ea(k(l[0],l[1],l[2]),k(c[0],c[1],c[2]))};this.document.completedMeasurements.push(h),this._emitEvent("measurementCompleted",h),this.onMeasurementCompleted(h)}this.clearActiveDragMode(),this.drawScene();return}}this.clearActiveDragMode(),this.drawScene()}checkMultitouch(t){if(r1({touchdown:this.uiData.touchdown,multiTouchGesture:this.uiData.multiTouchGesture})){const e=this.canvas.getBoundingClientRect(),i=Oi({touch:t.touches[0],canvasRect:e});this.mouseDown(i.x,i.y),this.mouseClick(i.x,i.y)}}touchStartListener(t){t.preventDefault(),a1(this.uiData.touchTimer)&&(this.uiData.touchTimer=setTimeout(()=>{this.resetBriCon(t)},this.opts.longTouchTimeout));const e=new Date().getTime(),i=ju({currentTime:e,touchCount:t.touches.length,isTouchdown:this.uiData.touchdown});if(this.uiData.touchdown=i.touchdown,this.uiData.currentTouchTime=i.currentTouchTime,Zu({currentTime:e,lastTouchTime:this.uiData.lastTouchTime,doubleTouchTimeout:this.opts.doubleTouchTimeout}).isDoubleTap){const s=$u(e);this.uiData.doubleTouch=s.doubleTouch,this.uiData.lastTouchTime=s.lastTouchTime;const n=t.target.getBoundingClientRect(),a=Oi({touch:t.targetTouches[0],canvasRect:n});this.setDragStart(a.x,a.y),this.resetBriCon(t);return}else{const s=Ju(e);this.uiData.doubleTouch=s.doubleTouch,this.uiData.lastTouchTime=s.lastTouchTime,this.setDragStart(0,0),this.setDragEnd(0,0)}Us(this.uiData.touchdown,t.touches.length)?this.uiData.multiTouchGesture=!1:this.uiData.multiTouchGesture=!0,setTimeout(this.checkMultitouch.bind(this),1,t)}touchEndListener(t){t.preventDefault();const e=_u();if(this.uiData.touchdown=e.touchdown,this.uiData.lastTwoTouchDistance=e.lastTwoTouchDistance,this.uiData.multiTouchGesture=e.multiTouchGesture,this.uiData.touchTimer&&(clearTimeout(this.uiData.touchTimer),this.uiData.touchTimer=null),this.uiData.isDragging){this.uiData.isDragging=!1;for(const s of this.getZarrVolumes())s.zarrHelper?.endDrag();this.getCurrentDragMode()===1&&(this.calculateNewRange(),this.refreshLayers(this.volumes[0],0));const i=this.canvasPos2frac([this.uiData.dragStart[0],this.uiData.dragStart[1]]),r=this.canvasPos2frac([this.uiData.dragEnd[0],this.uiData.dragEnd[1]]);this.generateMouseUpCallback(i,r)}this.mouseUpListener()}windowingHandler(t,e,i=0){Math.sqrt((t-this.uiData.windowX)**2+(e-this.uiData.windowY)**2)>100&&(this.uiData.windowX=t,this.uiData.windowY=e);const s=V1({x:t,y:e,windowX:this.uiData.windowX,windowY:this.uiData.windowY,currentCalMin:this.volumes[i].cal_min,currentCalMax:this.volumes[i].cal_max,globalMin:this.volumes[i].global_min,globalMax:this.volumes[i].global_max,gainFactor:this.opts.windowingGainFactor??2});this.volumes[i].cal_min=s.calMin,this.volumes[i].cal_max=s.calMax,this.refreshLayers(this.volumes[i],0),this.uiData.windowX=s.windowX,this.uiData.windowY=s.windowY}mouseLeaveListener(){if(this.clickToSegmentIsGrowing&&(F.debug("Mouse left canvas, stopping clickToSegment preview."),this.clickToSegmentIsGrowing=!1,this.refreshDrawing(!0,!1)),this.opts.drawingEnabled&&!isNaN(this.drawPenLocation[0])&&(F.debug("Mouse left canvas during drawing, resetting pen state."),this.drawPenLocation=[NaN,NaN,NaN],this.drawPenAxCorSag=-1,this.drawPenFillPts=[]),this.opts.drawingEnabled&&!isNaN(this.drawShapeStartLocation[0])&&(F.debug("Mouse left canvas during shape drawing, resetting shape state."),this.drawShapeStartLocation=[NaN,NaN,NaN],this.drawShapePreviewBitmap&&(this.drawBitmap=this.drawShapePreviewBitmap,this.drawShapePreviewBitmap=null,this.refreshDrawing(!0,!1))),this.uiData.isDragging||this.uiData.mousedown){F.debug("Mouse left canvas during drag, resetting drag state."),this.uiData.isDragging=!1;for(const e of this.getZarrVolumes())e.zarrHelper?.endDrag();const t=oa();this.uiData.mouseButtonLeftDown=t.mouseButtonLeftDown,this.uiData.mouseButtonCenterDown=t.mouseButtonCenterDown,this.uiData.mouseButtonRightDown=t.mouseButtonRightDown,this.uiData.mousedown=t.mousedown,this.drawScene()}this.mousePos=la()}mouseMoveListener(t){this.uiData.mousedown&&this.drawScene();const e=this.getNoPaddingNoBorderCanvasRelativeMousePosition(t,this.gl.canvas);if(e){if(!this.eventInBounds(t)){this.updateMousePos(e.x,e.y);return}if(this.uiData.mousedown){this.canvas.focus();const i=e.x*this.uiData.dpr,r=e.y*this.uiData.dpr;if(this.tileIndex(i,r)!==this.uiData.clickedTile)return;const n=this.getCurrentDragMode();if(n===8){if(this.mouseMove(e.x,e.y),!!this.mouseClick(e.x,e.y)&&this.uiData.prevX===this.uiData.currX&&this.uiData.prevY===this.uiData.currY)return;this.mouseClick(e.x,e.y),this.drawScene(),this.uiData.prevX=this.uiData.currX,this.uiData.prevY=this.uiData.currY;return}if(n===9){this.windowingHandler(e.x,e.y),this.drawScene(),this.uiData.prevX=this.uiData.currX,this.uiData.prevY=this.uiData.currY;return}this.setDragEnd(e.x,e.y),this.drawScene(),this.uiData.prevX=this.uiData.currX,this.uiData.prevY=this.uiData.currY}else if(this.getCurrentDragMode()===7&&this.uiData.angleState==="drawing_second_line"){const i=this.getNoPaddingNoBorderCanvasRelativeMousePosition(t,this.gl.canvas);if(!i)return;this.setDragEnd(i.x,i.y),this.drawScene()}else if(!this.uiData.mousedown&&this.opts.clickToSegment){const i=this.getNoPaddingNoBorderCanvasRelativeMousePosition(t,this.gl.canvas);if(!i)return;const r=i.x*this.uiData.dpr,s=i.y*this.uiData.dpr;this.mousePos=[r,s];const n=this.tileIndex(r,s);n>=0&&this.opts.drawingEnabled&&this.screenSlices[n].axCorSag<=2&&(this.clickToSegmentXY=[r,s],this.clickToSegmentIsGrowing=!0,this.doClickToSegment({x:r,y:s,tileIndex:n}))}}}resetBriCon(t=null){if(this.uiData.isDragging)return;if(!this.eventInBounds(t)){this.opts.showBoundsBorder=!1;return}let e=!1;this.opts.sliceType===4&&(e=!0);let i=0,r=0;if(t!==null&&("targetTouches"in t?(i=t.targetTouches[0].clientX-t.target.getBoundingClientRect().left,r=t.targetTouches[0].clientY-t.target.getBoundingClientRect().top):(i=t.offsetX,r=t.offsetY),i*=this.uiData.dpr,r*=this.uiData.dpr,this.inRenderTile(i,r)>=0&&(e=!0)),e){this.uiData.mouseDepthPicker=!0,this.drawScene(),this.drawScene();return}this.getCurrentDragMode()!==4&&(this.volumes.length<1||this.uiData.doubleTouch||(this.volumes[0].cal_min=this.volumes[0].robust_min,this.volumes[0].cal_max=this.volumes[0].robust_max,this._emitEvent("intensityChange",this.volumes[0]),this.onIntensityChange(this.volumes[0]),this.refreshLayers(this.volumes[0],0),this.drawScene()))}setDragStart(t,e){const[i,r]=Rs(t,e,this.uiData.dpr);this.uiData.dragStart[0]=i,this.uiData.dragStart[1]=r}setDragEnd(t,e){const[i,r]=Rs(t,e,this.uiData.dpr);this.uiData.dragEnd[0]=i,this.uiData.dragEnd[1]=r}touchMoveListener(t){if(Us(this.uiData.touchdown,t.touches.length)){const e=this.canvas.getBoundingClientRect();if(!this.uiData.isDragging){this.uiData.pan2DxyzmmAtMouseDown=ze(this.scene.pan2Dxyzmm);for(const s of this.getZarrVolumes())s.zarrHelper?.beginDrag()}if(this.uiData.isDragging=!0,n1({doubleTouch:this.uiData.doubleTouch,isDragging:this.uiData.isDragging})){const s=Oi({touch:t.targetTouches[0],canvasRect:t.target.getBoundingClientRect()});this.setDragEnd(s.x,s.y),this.drawScene();return}const i=this.getTouchDragMode(!1),r=i1({touch:t.touches[0],canvasRect:e});i===8?(this.mouseClick(r.x,r.y),this.mouseMove(r.x,r.y)):i===9&&(this.windowingHandler(r.x,r.y),this.drawScene())}else this.handlePinchZoom(t)}handlePinchZoom(t){if(t1(t.targetTouches.length,t.changedTouches.length)){const e=this.canvas.getBoundingClientRect(),i=e1({touch1:t.touches[0],touch2:t.touches[1],lastTwoTouchDistance:this.uiData.lastTwoTouchDistance}),r=s1({touch:t.touches[0],canvasRect:e});this.mousePos=r,this.uiData.lastTwoTouchDistance>0&&this.sliceScroll2D(i.scrollDelta,r[0],r[1]),this.uiData.lastTwoTouchDistance=i.distance}}cycleActiveClipPlane(){const t=d1({currentIndex:this.uiData.activeClipPlaneIndex,clipPlanesLength:this.scene.clipPlanes.length});this.uiData.activeClipPlaneIndex=t.newIndex;const e=t.newIndex;return this.scene.clipPlanes[e]||(this.scene.clipPlanes[e]=t.defaultClipPlane),this.scene.clipPlaneDepthAziElevs[e]||(this.scene.clipPlaneDepthAziElevs[e]=t.defaultDepthAziElev),e}keyUpListener(t){if(!this.cursorInBounds()){this.opts.showBoundsBorder=!1,this.drawScene();return}const e=new Date().getTime(),i=h1({currentTime:e,lastCalledTime:this.lastCalled,debounceTime:this.opts.keyDebounceTime});if(zi(t.code,this.opts.cycleClipPlaneHotKey)&&i){const r=this.cycleActiveClipPlane();console.log("Active clip plane cycled to:",r),console.log("clip planes",this.scene.clipPlanes),this.lastCalled=e}if(zi(t.code,this.opts.clipPlaneHotKey)){if(i){const r=f1({currentClipPlaneIndex:this.currentClipPlaneIndex});this.currentClipPlaneIndex=r.newIndex,this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex]=r.depthAziElev,this.setClipPlane(this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex])}this.lastCalled=e}else if(zi(t.code,this.opts.viewModeHotKey)&&i){const r=u1({currentSliceType:this.opts.sliceType,totalSliceTypes:5});this.setSliceType(r),this.lastCalled=e}this.drawScene()}keyDownListener(t){if(!this.cursorInBounds()){this.opts.showBoundsBorder=!1,this.drawScene();return}const{action:e}=l1({code:t.code,ctrlKey:t.ctrlKey,shiftKey:t.shiftKey,sliceType:this.opts.sliceType});switch(e){case"render_azimuth_decrease":this.setRenderAzimuthElevation(this.scene.renderAzimuth-1,this.scene.renderElevation);break;case"render_azimuth_increase":this.setRenderAzimuthElevation(this.scene.renderAzimuth+1,this.scene.renderElevation);break;case"render_elevation_increase":this.setRenderAzimuthElevation(this.scene.renderAzimuth,this.scene.renderElevation+1);break;case"render_elevation_decrease":this.setRenderAzimuthElevation(this.scene.renderAzimuth,this.scene.renderElevation-1);break;case"crosshair_left":this.moveCrosshairInVox(-1,0,0);break;case"crosshair_right":this.moveCrosshairInVox(1,0,0);break;case"crosshair_up":this.moveCrosshairInVox(0,1,0);break;case"crosshair_down":this.moveCrosshairInVox(0,-1,0);break;case"crosshair_forward":this.moveCrosshairInVox(0,0,1);break;case"crosshair_backward":this.moveCrosshairInVox(0,0,-1);break;case"cycle_drag_mode":this.opts.dragMode=c1(this.opts.dragMode),F.info("drag mode changed to ",On[this.opts.dragMode]);break;case"frame_previous":this.setFrame4D(this.volumes[0].id,this.volumes[0].frame4D-1);break;case"frame_next":this.setFrame4D(this.volumes[0].id,this.volumes[0].frame4D+1);break;case"show_version":alert(`NIIVUE VERSION: ${Ys}`);break}this.drawScene()}wheelListener(t){const e=y1({thumbnailVisible:this.thumbnailVisible,mosaicStringLength:this.opts.sliceMosaicString.length,eventInBounds:this.eventInBounds(t),hasBounds:this.opts.bounds!==null});if(!e.shouldProcess){this.eventInBounds(t)||(this.opts.showBoundsBorder=!1,this.drawScene());return}if(this.opts.showBoundsBorder=e.showBoundsBorder,t.preventDefault(),t.stopPropagation(),p1({dragMode:this.getCurrentDragMode(),dragStart:this.uiData.dragStart,dragEnd:this.uiData.dragEnd})){const o=A1(t.deltaY),l=g1({dragStart:this.uiData.dragStart,dragEnd:this.uiData.dragEnd,delta:o});this.uiData.dragStart[0]=l.newDragStart[0],this.uiData.dragStart[1]=l.newDragStart[1],this.uiData.dragEnd[0]=l.newDragEnd[0],this.uiData.dragEnd[1]=l.newDragEnd[1],this.uiData.isDragging=!0,this.drawScene(),this.uiData.isDragging=!1;const c=this.tileIndex(this.uiData.dragStart[0],this.uiData.dragStart[1]);c>=0?this.generateMouseUpCallback(this.screenXY2TextureFrac(this.uiData.dragStart[0],this.uiData.dragStart[1],c),this.screenXY2TextureFrac(this.uiData.dragEnd[0],this.uiData.dragEnd[1],c)):F.warn("Could not generate drag release callback for ROI selection: Invalid tile index.");return}const i=m1({deltaY:t.deltaY,invertScrollDirection:this.opts.invertScrollDirection});if(this.opts.clickToSegment){this.opts.clickToSegmentPercent=w1({currentPercent:this.opts.clickToSegmentPercent,scrollAmount:i});const o=this.clickToSegmentXY[0],l=this.clickToSegmentXY[1],c=this.tileIndex(o,l);c>=0&&this.screenSlices[c].axCorSag<=2&&(F.debug(`Adjusting clickToSegment threshold: ${this.opts.clickToSegmentPercent.toFixed(3)}`),this.clickToSegmentIsGrowing=!0,this.doClickToSegment({x:o,y:l,tileIndex:c}));return}const r=this.canvas.getBoundingClientRect(),[s,n]=C1(t.clientX,t.clientY,r),a=this.inRenderTile(this.uiData.dpr*s,this.uiData.dpr*n)!==-1;if(b1({dragMode:this.getCurrentDragMode(),isInRenderTile:a})){const o=x1({currentZoom:this.scene.pan2Dxyzmm[3],scrollAmount:i});this.opts.yoke3Dto2DZoom&&(this.scene.volScaleMultiplier=o.newZoom),this.scene.pan2Dxyzmm[3]=o.newZoom;const l=this.frac2mm(this.scene.crosshairPos),c=v1({currentPan:[this.scene.pan2Dxyzmm[0],this.scene.pan2Dxyzmm[1],this.scene.pan2Dxyzmm[2]],zoomChange:o.zoomChange,crosshairMM:[l[0],l[1],l[2]]});this.scene.pan2Dxyzmm[0]=c[0],this.scene.pan2Dxyzmm[1]=c[1],this.scene.pan2Dxyzmm[2]=c[2],this.drawScene(),this.canvas.focus(),this.sync();return}this.sliceScroll2D(i,s,n)}registerInteractions(){if(!this.canvas)throw new Error("canvas undefined");Ke(this,ft,new AbortController);const{signal:t}=X(this,ft);this.canvas.addEventListener("mousedown",this.mouseDownListener.bind(this),{signal:t}),this.canvas.addEventListener("mouseup",this.mouseUpListener.bind(this),{signal:t}),this.canvas.addEventListener("mousemove",this.mouseMoveListener.bind(this),{signal:t}),this.canvas.addEventListener("mouseleave",this.mouseLeaveListener.bind(this),{signal:t}),this.canvas.addEventListener("touchstart",this.touchStartListener.bind(this),{signal:t}),this.canvas.addEventListener("touchend",this.touchEndListener.bind(this),{signal:t}),this.canvas.addEventListener("touchmove",this.touchMoveListener.bind(this),{signal:t}),this.canvas.addEventListener("wheel",this.wheelListener.bind(this),{signal:t}),this.canvas.addEventListener("contextmenu",this.mouseContextMenuListener.bind(this),{signal:t}),this.canvas.addEventListener("dblclick",this.resetBriCon.bind(this),{signal:t}),this.canvas.addEventListener("dragenter",this.dragEnterListener.bind(this),{signal:t}),this.canvas.addEventListener("dragover",this.dragOverListener.bind(this),{signal:t}),this.canvas.addEventListener("drop",e=>{this.dropListener(e).catch(console.error)},{signal:t}),this.canvas.setAttribute("tabindex","0"),this.canvas.addEventListener("keyup",this.keyUpListener.bind(this),{signal:t}),this.canvas.addEventListener("keydown",this.keyDownListener.bind(this),{signal:t})}dragEnterListener(t){ea(t)}dragOverListener(t){ta(t)}getFileExt(t,e=!0){return Lr(t,e)}async addVolumeFromUrl(t){const e=await Me.loadFromUrl(t);return this.document.addImageOptions(e,t),e.onColormapChange=this.onColormapChange,this.mediaUrlMap.set(e,t.url),this._emitEvent("volumeAddedFromUrl",{imageOptions:t,volume:e}),this.onVolumeAddedFromUrl&&this.onVolumeAddedFromUrl(t,e),this.addVolume(e),e}async addVolumesFromUrl(t){const e=t.map(async r=>{const s=this.getFileExt(r.name||r.url);if(s==="DCM")throw new Error("DICOM files must be loaded using useDicomLoader");if(this.loaders[s]){let o=r.url;const l=this.loaders[s].toExt;let c=r.name||r.url;if(c=c.split("/").pop(),typeof r.url=="string"){const d=r.url;try{const f=await fetch(d);if(!f.ok)throw new Error(`Failed to load file: ${f.statusText}`);o=await f.arrayBuffer()}catch(f){throw new Error(`Failed to load url ${d}: ${f}`)}}const h=await this.loaders[s].loader(o);r.url=h,r.name=`${c}.${l}`}const n={url:r.url,headers:r.headers,name:r.name,colormap:r.colormap?r.colormap:r.colorMap,colormapNegative:r.colormapNegative?r.colormapNegative:r.colorMapNegative,opacity:r.opacity,urlImgData:r.urlImgData,cal_min:r.cal_min,cal_max:r.cal_max,trustCalMinMax:this.opts.trustCalMinMax,isManifest:r.isManifest,frame4D:r.frame4D,limitFrames4D:r.limitFrames4D||this.opts.limitFrames4D,colorbarVisible:r.colorbarVisible,zarrLevel:r.zarrLevel,zarrMaxVolumeSize:r.zarrMaxVolumeSize,zarrChannel:r.zarrChannel,zarrConvertUnits:r.zarrConvertUnits,zarrCenterMM:r.zarrCenterMM},a=await Me.loadFromUrl(n);return this.document.addImageOptions(a,n),a.onColormapChange=this.onColormapChange,this.mediaUrlMap.set(a,n.url),this._emitEvent("volumeAddedFromUrl",{imageOptions:n,volume:a}),this.onVolumeAddedFromUrl&&this.onVolumeAddedFromUrl(n,a),a}),i=await Promise.all(e);for(let r=0;r<i.length;r++)this.addVolume(i[r]);return i}getMediaByUrl(t){return _n(t,this.mediaUrlMap)}removeVolumeByUrl(t){const e=this.getMediaByUrl(t);if(e)this.removeVolume(e);else throw new Error("No volume with URL present")}async traverseFileTree(t,e="",i){return kr(t,e,i)}readDirectory(t){return $n(t)}isMeshExt(t){return jn(t)}async loadFromArrayBuffer(t,e){const i=this.getFileExt(e);if(Zt.includes(i)){await this.addMeshFromUrl({url:e,buffer:t});return}const r=si(e);r.buffer=t,r.name=e,await this.addVolumeFromUrl(r)}async loadFromFile(t){const e=this.getFileExt(t.name);if(Zt.includes(e)){await mt.loadFromFile({file:t,gl:this.gl,name:t.name}).then(i=>{this.addMesh(i)});return}await Me.loadFromFile({file:t,name:t.name}).then(i=>{this.addVolume(i)})}useLoader(t,e,i){this.loaders=Jn({loaders:this.loaders,loader:t,fileExt:e,toExt:i})}useDicomLoader(t){this.dicomLoader=t}getDicomLoader(){return this.dicomLoader}async dropListener(t){if(this.eventInBounds(t))this.opts.bounds&&(this.opts.showBoundsBorder=!0);else{this.opts.showBoundsBorder=!1;return}if(t.stopPropagation(),t.preventDefault(),!this.opts.dragAndDropEnabled)return;const e=t.dataTransfer;if(!e)return;const i=W1(e);i?await this.handleUrlDrop(i):K1(e)&&await this.handleFilesDrop(e.items,t.shiftKey,t.altKey),this.drawScene()}async handleUrlDrop(t){const e=this.getFileExt(t);switch(F.debug("dropped ext:",e),Vs(e)){case"mesh":await this.addMeshFromUrl({url:t});break;case"document":await this.loadDocumentFromUrl(t);break;default:await this.addVolumeFromUrl(si(t))}}async handleFilesDrop(t,e,i){!e&&!i&&(this.volumes=[],this.overlays=[],this.meshes=[]),this.closeDrawing(),this.closePAQD();const r=Y1(t);for(const{entry:n,pairedEntry:a}of r)await this.handleFileEntry(n,a,i);const s=X1(t);for(const n of s)await this.handleDirectoryDrop(n)}async handleFileEntry(t,e,i){const r=this.getFileExt(t.name);if(this.loaders[r]){const a=await b0(t);await this.loadImages([{url:a,name:t.name}]);return}const s=await Ps(t);switch(Vs(r)){case"mesh":await this.handleMeshFileDrop(s);break;case"document":await this.handleDocumentFileDrop(s);break;default:await this.handleVolumeFileDrop(s,e,i)}}async handleMeshFileDrop(t){try{const e=await mt.loadFromFile({file:t,gl:this.gl,name:t.name});this.addMesh(e)}catch(e){console.error("Error loading mesh:",e)}}async handleDocumentFileDrop(t){try{const e=await St.loadFromFile(t);await this.loadDocument(e),F.debug("loaded document")}catch(e){console.error("Error loading document:",e)}}async handleVolumeFileDrop(t,e,i){try{let r;e&&(r=await Ps(e));const s=await Me.loadFromFile({file:t,urlImgData:r,limitFrames4D:this.opts.limitFrames4D});i?(F.debug("alt key detected: assuming this is a drawing overlay"),this.drawClearAllUndoBitmaps(),this.loadDrawing(s)):this.addVolume(s)}catch(r){console.error("Error loading volume:",r)}}async handleDirectoryDrop(t){try{const e=await this.traverseFileTree(t,"",[]),i=this.getDicomLoader().loader;if(!i)throw new Error("No loader for DICOM files");const s=(await i(e)).map(a=>Me.loadFromUrl({url:a.data,name:a.name,limitFrames4D:this.opts.limitFrames4D})),n=await Promise.all(s);this._emitEvent("dicomLoaderFinished",{files:n}),await this.onDicomLoaderFinishedWithImages(n)}catch(e){console.error("Error loading DICOM files:",e)}}setMultiplanarPadPixels(t){this.opts.multiplanarPadPixels=t,this.drawScene()}setMultiplanarLayout(t){typeof t=="string"&&(t=parseInt(t)),this.opts.multiplanarLayout=t,this.drawScene()}setCornerOrientationText(t){this.opts.isCornerOrientationText=t,this.updateGLVolume()}setIsOrientationTextVisible(t){this.opts.isOrientationTextVisible=t,this.drawScene()}setShowAllOrientationMarkers(t){this.opts.showAllOrientationMarkers=t,this.drawScene()}setHeroImage(t){this.opts.heroImageFraction=t,this.drawScene()}setCustomLayout(t){const e=i2({layout:t});if(!e.valid&&e.error)throw new Error(e.error);this.customLayout=t,this.drawScene()}clearCustomLayout(){this.customLayout=null,this.drawScene()}getCustomLayout(){return this.customLayout}setRadiologicalConvention(t){this.opts.isRadiologicalConvention=t,this.updateGLVolume()}setDefaults(t={},e=!1){this.document.opts={...ke},this.scene.sceneData={...mi};for(const i in t)typeof t[i]=="function"?this[i]=t[i]:this.opts[i]=ke[i]===void 0?ke[i]:t[i];if(this.scene.pan2Dxyzmm=[0,0,0,1],e&&this.volumes&&this.volumes.length>0)for(let i=0;i<this.volumes.length;i++)this.volumes[i].cal_min=this.volumes[i].robust_min,this.volumes[i].cal_max=this.volumes[i].robust_max;this.updateGLVolume()}setMeshThicknessOn2D(t){this.opts.meshThicknessOn2D=t,this.updateGLVolume()}setSliceMosaicString(t){this.sliceMosaicString=t,this.updateGLVolume()}setSliceMM(t){this.opts.isSliceMM=t,this.updateGLVolume()}setAdditiveBlend(t){this.opts.isAdditiveBlend=t,this.updateGLVolume()}getRadiologicalConvention(){return this.opts.isRadiologicalConvention}setHighResolutionCapable(t){typeof t=="boolean"&&(t=t?0:-1),this.opts.forceDevicePixelRatio=t,this.resizeListener(),this.drawScene()}watchOptsChanges(t){this.onOptsChange=t}unwatchOptsChanges(){this.onOptsChange=()=>{}}addVolume(t){const e=Qd(this.volumes,t);if(this.volumes=e.volumes,this.setVolume(t,e.index),this._emitEvent("imageLoaded",t),this.onImageLoaded(t),t.zarrHelper){if(!t._hasExplicitZarrCenter&&this.back&&this.back!==t&&this.back.hdr?.dims){const i=this.back,r=i.hdr.dims,s=i.hdr.affine,n=(r[1]-1)/2,a=(r[2]-1)/2,o=(r[3]-1)/2,l=[s[0][0]*n+s[0][1]*a+s[0][2]*o+s[0][3],s[1][0]*n+s[1][1]*a+s[1][2]*o+s[1][3],s[2][0]*n+s[2][1]*a+s[2][2]*o+s[2][3]];t.zarrHelper.setWorldCenter(l)}t.zarrHelper.onChunksUpdated=()=>{this.updateGLVolume(),this._skipDragInDraw=!0,this.drawScene(),this._skipDragInDraw=!1},t.zarrHelper.loadInitialChunks().catch(i=>F.error("Failed to load initial zarr chunks",i))}F.debug("loaded volume",t.name),F.debug(t)}addMesh(t){const e=Vf(this.meshes,t);this.meshes=e.meshes,this.setMesh(t,e.index),this._emitEvent("meshLoaded",t),this.onMeshLoaded(t)}getVolumeIndexByID(t){return At(this.volumes,t)}drawAddUndoBitmap(t=!0){const e=k2({drawBitmap:this.drawBitmap,drawUndoBitmaps:this.drawUndoBitmaps,currentDrawUndoBitmap:this.currentDrawUndoBitmap,maxDrawUndoBitmaps:this.opts.maxDrawUndoBitmaps,drawFillOverwrites:t});this.drawBitmap=e.drawBitmap,this.drawUndoBitmaps=e.drawUndoBitmaps,this.currentDrawUndoBitmap=e.currentDrawUndoBitmap,e.needsRefresh&&this.refreshDrawing(!1)}drawClearAllUndoBitmaps(){const t=L2(this.drawUndoBitmaps,this.opts.maxDrawUndoBitmaps);this.drawUndoBitmaps=t.drawUndoBitmaps,this.currentDrawUndoBitmap=t.currentDrawUndoBitmap}drawUndo(){const{drawBitmap:t,currentDrawUndoBitmap:e}=F2({drawUndoBitmaps:this.drawUndoBitmaps,currentDrawUndoBitmap:this.currentDrawUndoBitmap,drawBitmap:this.drawBitmap});this.drawBitmap=t,this.currentDrawUndoBitmap=e,this.refreshDrawing(!0),this._emitEvent("drawingChanged",{action:"undo"}),this.onDrawingChanged("undo")}loadDrawing(t){if(this.drawBitmap&&F.debug("Overwriting open drawing!"),!this.back)throw new Error("back undefined");this.drawClearAllUndoBitmaps();const e=t.hdr.dims;if(!G2({drawingDims:e,backgroundDims:this.back.hdr.dims}))return F.debug("drawing dimensions do not match background image"),!1;t.img.constructor!==Uint8Array&&F.debug("Drawings should be UINT8");const i=t.permRAS,r=Wi(e);this.drawBitmap=Ki(r),this.opts.is2DSliceShader?this.drawTexture=this.r8Tex2D(this.drawTexture,$.TEXTURE7_DRAW,this.back.dims,!0):this.drawTexture=this.r8Tex(this.drawTexture,$.TEXTURE7_DRAW,this.back.dims,!0);const s=O2({permRAS:i,dims:e});return this.drawBitmap=z2({inputData:t.img,dims:e,xlut:s.xlut,ylut:s.ylut,zlut:s.zlut}),this.drawAddUndoBitmap(),this.refreshDrawing(!1),this._emitEvent("drawingChanged",{action:"load"}),this.onDrawingChanged("load"),this.drawScene(),!0}binarize(t){const e=fm({img:t.img,dims:t.hdr.dims});t.img=e.img,t.hdr.datatypeCode=e.datatypeCode,t.hdr.cal_min=e.cal_min,t.hdr.cal_max=e.cal_max}async loadDrawingFromUrl(t,e=!1){this.drawBitmap&&F.debug("Overwriting open drawing!"),this.drawClearAllUndoBitmaps();let i=!1;try{const r=await Me.loadFromUrl(si(t));e&&await this.binarize(r),i=this.loadDrawing(r)}catch{F.error("loadDrawingFromUrl() failed to load "+t),this.drawClearAllUndoBitmaps()}return i}findOtsu(t=2){return this.volumes.length<1?[]:um({img:this.volumes[0].img,cal_min:this.volumes[0].cal_min,cal_max:this.volumes[0].cal_max,scl_inter:this.volumes[0].hdr.scl_inter,scl_slope:this.volumes[0].hdr.scl_slope,mlevel:t})}drawOtsu(t=2){if(this.volumes.length===0)return;const e=this.findOtsu(t);if(e.length<3)return;this.drawBitmap||this.createEmptyDrawing();const i=mm({img:this.volumes[0].img2RAS(),drawBitmap:this.drawBitmap,thresholds:e});this.drawBitmap.set(i),this.drawAddUndoBitmap(),this.refreshDrawing(!0)}removeHaze(t=5,e=0){const i=this.volumes[e].img,r=this.volumes[e].hdr,s=pm({level:t}),n=this.findOtsu(s);if(n.length<3)return;const a=gm({level:t,thresholds:n});Am({img:i,scl_inter:r.scl_inter,scl_slope:r.scl_slope,global_min:this.volumes[e].global_min,threshold:a}),this.refreshLayers(this.volumes[e],0),this.drawScene()}async saveImage(t=Ks){const e={...Ks,...t},{filename:i,isSaveDrawing:r,volumeByIndex:s}=e;return F.debug("saveImage",i,r,s),this.back?.dims===void 0?(F.debug("No voxelwise image open"),!1):r?this.drawBitmap?await this.volumes[0].saveToDisk(i,this.drawBitmap):(F.debug("No drawing open"),!1):(F.debug("saving image"),this.volumes[s].saveToDisk(i))}getMeshIndexByID(t){return Ze(this.meshes,t)}setMeshProperty(t,e,i){const r=Nf({meshes:this.meshes,id:t,key:e,val:i,gl:this.gl});r<0||(this.updateGLVolume(),this._emitEvent("meshPropertyChanged",{meshIndex:r,key:e,value:i}),this.onMeshPropertyChanged(r,e,i))}indexNearestXYZmm(t,e,i,r){return Lf({meshes:this.meshes,meshId:t,Xmm:e,Ymm:i,Zmm:r})}decimateHierarchicalMesh(t,e=3){const i=kf({meshes:this.meshes,meshId:t,gl:this.gl,order:e});return i&&this.updateGLVolume(),i}reverseFaces(t){Of({meshes:this.meshes,meshId:t,gl:this.gl})&&this.updateGLVolume()}async setMeshLayerProperty(t,e,i,r){await zf({meshes:this.meshes,meshId:t,layer:e,key:i,val:r,gl:this.gl})&&this.updateGLVolume()}setPan2Dxyzmm(t){this.scene.pan2Dxyzmm=t,this.opts.yoke3Dto2DZoom&&(this.scene.volScaleMultiplier=t[3]),this.drawScene()}setRenderAzimuthElevation(t,e){this.scene.renderAzimuth=t,this.scene.renderElevation=e,this._emitEvent("azimuthElevationChange",{azimuth:t,elevation:e}),this.onAzimuthElevationChange(t,e),this.drawScene()}getOverlayIndexByID(t){return Zd(this.volumes,t)}setVolume(t,e=0){const i=xt(this.volumes,t,e);this.volumes=i.volumes,this.back=i.back,this.overlays=i.overlays,this.updateGLVolume()}setMesh(t,e=0){this.meshes.forEach(r=>{F.debug("MESH: ",r.name)});const i=Pf(this.meshes,t,e);this.meshes=i.meshes,this.updateGLVolume(),this.meshes.forEach(r=>{F.debug(r.name)})}removeVolume(t){const e=this.volumes.indexOf(t),i=qn(this.volumes,t);if(this.volumes=i.volumes,this.back=this.volumes.length>0?this.volumes[0]:null,this.overlays=this.volumes.slice(1),this._emitEvent("volumeRemoved",{volume:t,index:e}),this.onVolumeRemoved(t,e),this.mediaUrlMap.has(t)){const r=this.mediaUrlMap.get(t);this._emitEvent("volumeWithUrlRemoved",{url:r}),this.onVolumeWithUrlRemoved(r),this.mediaUrlMap.delete(t)}this.updateGLVolume(),this.drawScene()}removeVolumeByIndex(t){const e=jd(this.volumes,t);e.removed&&this.removeVolume(e.removed)}removeMesh(t){if(this._emitEvent("meshRemoved",{mesh:t}),this.onMeshRemoved(t),t.unloadMesh(this.gl),this.setMesh(t,-1),this.mediaUrlMap.has(t)){const e=this.mediaUrlMap.get(t);this._emitEvent("meshWithUrlRemoved",{url:e}),this.onMeshWithUrlRemoved(e),this.mediaUrlMap.delete(t)}}removeMeshByUrl(t){const e=this.getMediaByUrl(t);e&&(this.removeMesh(e),this.mediaUrlMap.delete(e),this._emitEvent("meshWithUrlRemoved",{url:t}),this.onMeshWithUrlRemoved(t))}moveVolumeToBottom(t){const e=_d(this.volumes,t);this.volumes=e.volumes,this.back=e.back,this.overlays=e.overlays,this.updateGLVolume(),this._emitEvent("volumeOrderChanged",{volumes:this.volumes}),this.onVolumeOrderChanged(this.volumes)}moveVolumeUp(t){const e=Jd(this.volumes,t);this.volumes=e.volumes,this.back=e.back,this.overlays=e.overlays,this.updateGLVolume(),this._emitEvent("volumeOrderChanged",{volumes:this.volumes}),this.onVolumeOrderChanged(this.volumes)}moveVolumeDown(t){const e=$d(this.volumes,t);this.volumes=e.volumes,this.back=e.back,this.overlays=e.overlays,this.updateGLVolume(),this._emitEvent("volumeOrderChanged",{volumes:this.volumes}),this.onVolumeOrderChanged(this.volumes)}moveVolumeToTop(t){const e=ef(this.volumes,t);this.volumes=e.volumes,this.back=e.back,this.overlays=e.overlays,this.updateGLVolume(),this._emitEvent("volumeOrderChanged",{volumes:this.volumes}),this.onVolumeOrderChanged(this.volumes)}mouseDown(t,e){const i=hr({x:t,y:e,dpr:this.uiData.dpr});this.mousePos=i.mousePos}updateMousePos(t,e){const i=hr({x:t,y:e,dpr:this.uiData.dpr});return this.mousePos=i.mousePos,i.mousePos}mouseMove(t,e){const i=aa({x:t,y:e,dpr:this.uiData.dpr,currentMousePos:this.mousePos});if(this.mousePos=i.mousePos,this.inRenderTile(i.scaledX,i.scaledY)<0||!A2({dx:i.dx,dy:i.dy}))return;const r=g2({currentAzimuth:this.scene.renderAzimuth,currentElevation:this.scene.renderElevation,deltaX:i.dx,deltaY:i.dy});this.scene.renderAzimuth===r.azimuth&&this.scene.renderElevation===r.elevation||this.setRenderAzimuthElevation(r.azimuth,r.elevation)}sph2cartDeg(t,e){return bi(t,e)}setClipPlanes(t){const e=D2({depthAziElevs:t});this.scene.clipPlanes=e.clipPlanes,this.scene.clipPlaneDepthAziElevs=e.clipPlaneDepthAziElevs,this.drawScene()}setClipPlane(t){if(!E2(t))return;const e=this.uiData.activeClipPlaneIndex??0,i=S2({clipPlanes:this.scene.clipPlanes,clipPlaneDepthAziElevs:this.scene.clipPlaneDepthAziElevs,index:e,depthAzimuthElevation:t});this.scene.clipPlanes=i.clipPlanes,this.scene.clipPlaneDepthAziElevs=i.clipPlaneDepthAziElevs,this._emitEvent("clipPlaneChange",{clipPlane:i.clipPlane}),this.onClipPlaneChange(i.clipPlane),this.drawScene()}setCrosshairColor(t){this.opts.crosshairColor=t,this.drawScene()}setCrosshairWidth(t){this.opts.crosshairWidth=t,this.crosshairs3D&&(this.crosshairs3D.mm[0]=NaN),this.drawScene()}setDrawColormap(t){this.drawLut=re.makeDrawLut(t),this.updateGLVolume()}setDrawingEnabled(t){if(this.opts.drawingEnabled=t,this._emitEvent("drawingEnabled",{enabled:t}),this.onDrawingEnabled(t),this.opts.drawingEnabled)this.drawBitmap||this.createEmptyDrawing();else{const e=X2({clickToSegmentIsGrowing:this.clickToSegmentIsGrowing,drawPenLocation:this.drawPenLocation,drawPenAxCorSag:this.drawPenAxCorSag,drawPenFillPts:this.drawPenFillPts,drawShapeStartLocation:this.drawShapeStartLocation,drawShapePreviewBitmap:this.drawShapePreviewBitmap,drawBitmap:this.drawBitmap});this.clickToSegmentIsGrowing=e.clickToSegmentIsGrowing,this.drawPenLocation=e.drawPenLocation,this.drawPenAxCorSag=e.drawPenAxCorSag,this.drawPenFillPts=e.drawPenFillPts,this.drawShapeStartLocation=e.drawShapeStartLocation,this.drawShapePreviewBitmap=e.drawShapePreviewBitmap,this.drawBitmap=e.drawBitmap,e.needsRefresh&&this.refreshDrawing(!0,!1);const i=this._deriveDrawingTool(this.opts.penValue);this._emitEvent("drawingToolChanged",{tool:i,penValue:this.opts.penValue,isFilledPen:this.opts.isFilledPen}),this.onDrawingToolChanged(i,this.opts.penValue,this.opts.isFilledPen)}this.drawScene()}setPenValue(t,e=!1){this.opts.penValue=t,this.opts.isFilledPen=e,this._emitEvent("penValueChanged",{penValue:t,isFilledPen:e}),this.onPenValueChanged(t,e);const i=this._deriveDrawingTool(t);this._emitEvent("drawingToolChanged",{tool:i,penValue:t,isFilledPen:e}),this.onDrawingToolChanged(i,t,e),this.drawScene()}_deriveDrawingTool(t){return this.opts.drawingEnabled?this.opts.clickToSegment?"clickToSegment":Object.is(t,-0)?"eraseCluster":isNaN(t)?"growCluster":t===Number.POSITIVE_INFINITY?"growClusterBright":t===Number.NEGATIVE_INFINITY?"growClusterDark":t===0?"erase":"draw":"off"}setDrawOpacity(t){this.drawOpacity=t,this.drawScene()}setSelectionBoxColor(t){this.opts.selectionBoxColor=t}setBounds(t){if(!Array.isArray(t)||t.length!==4)throw new Error("setBounds: expected [x1,y1,x2,y2] array");this.opts.bounds=[[t[0],t[1]],[t[2],t[3]]],this.gl&&this.drawScene()}sliceScroll2D(t,e,i,r=!0){if(!e2({scrollRequiresFocus:this.opts.scrollRequiresFocus,canvasHasFocus:this.canvas===document.activeElement})){F.warn("Canvas element does not have focus. Scroll events will not be processed.");return}if(this.inGraphTile(e,i)){let n=this.volumes[0].frame4D;t>0&&n++,t<0&&n--,this.setFrame4D(this.volumes[0].id,n);return}const s=this.inRenderTile(this.uiData.dpr*e,this.uiData.dpr*i)!==-1;if(t2({posChange:t,dragMode:this.opts.dragMode,isInRenderTile:s})){const n=this.frac2mm(this.scene.crosshairPos),a=J1({posChange:t,currentZoom:this.scene.pan2Dxyzmm[3],yoke3Dto2DZoom:this.opts.yoke3Dto2DZoom,crosshairMM:n});a.newVolScaleMultiplier!==void 0&&(this.scene.volScaleMultiplier=a.newVolScaleMultiplier),this.scene.pan2Dxyzmm[3]=a.newZoom,this.scene.pan2Dxyzmm[0]+=a.panOffsetX,this.scene.pan2Dxyzmm[1]+=a.panOffsetY,this.scene.pan2Dxyzmm[2]+=a.panOffsetZ,this.drawScene(),this.canvas.focus(),this.sync();return}this.mouseClick(e,i,t,r)}setSliceType(t){return this.opts.sliceType=t,this._emitEvent("sliceTypeChange",{sliceType:t}),this.onSliceTypeChange(t),this.drawScene(),this}setOpacity(t,e){tf(this.volumes,t,e),this.updateGLVolume()}getVolumeAffine(t){if(t<0||t>=this.volumes.length)throw new Error(`Volume index ${t} out of range`);return this.volumes[t].getAffine()}setVolumeAffine(t,e){if(t<0||t>=this.volumes.length)throw new Error(`Volume index ${t} out of range`);this.volumes[t].setAffine(e),this.updateGLVolume()}applyVolumeTransform(t,e){if(t<0||t>=this.volumes.length)throw new Error(`Volume index ${t} out of range`);this.volumes[t].applyTransform(e),this.updateGLVolume()}resetVolumeAffine(t){if(t<0||t>=this.volumes.length)throw new Error(`Volume index ${t} out of range`);this.volumes[t].resetAffine(),this.updateGLVolume()}setScale(t){this.scene.volScaleMultiplier=t,this.drawScene()}setClipPlaneColor(t){this.opts.clipPlaneColor=t,this.renderShader.use(this.gl),this.gl.uniform4fv(this.renderShader.uniforms.clipPlaneColor,this.opts.clipPlaneColor),this.drawScene()}setClipPlaneThick(t){F.warn("setClipPlaneThick() has been removed. use setClipPlanes() instead.")}setClipVolume(t,e){F.warn("setClipVolume() has been removed. use setClipPlanes() instead.")}async setVolumeRenderIllumination(t=0){this.renderGradientValues=Number.isNaN(t),this.renderShader=this.renderVolumeShader,this.renderGradientValues?this.renderShader=this.renderGradientValuesShader:(this.opts.gradientAmount=t,t>0||this.opts.gradientOpacity>0?this.renderShader=this.renderGradientShader:t<0&&(this.renderShader=this.renderSliceShader)),this.initRenderShader(this.renderShader,t),this.renderShader.use(this.gl),this.setClipPlaneColor(this.opts.clipPlaneColor),Number.isNaN(t)?this.gradientTextureAmount=1:this.gradientTextureAmount=t,!(this.volumes.length<1)&&(await this.refreshLayers(this.volumes[0],0),this.drawScene())}async setGradientOpacity(t=0,e=0){this.opts.gradientOpacity=t,this.opts.renderSilhouette=e,this.renderGradientValues?this.renderShader=this.renderGradientValuesShader:this.gradientTextureAmount>0||t>0?this.renderShader=this.renderGradientShader:this.gradientTextureAmount<0&&(this.renderShader=this.renderSliceShader),this.initRenderShader(this.renderShader,this.gradientTextureAmount),this.renderShader.use(this.gl),this.gradientTextureAmount>0&&this.refreshLayers(this.volumes[0],0),this.drawScene()}overlayRGBA(t){return af(t)}vox2mm(t,e){return I0(t,e)}cloneVolume(t){return rf(this.volumes,t)}async loadDocumentFromUrl(t){const e=await St.loadFromUrl(t);await this.loadDocument(e)}async loadDocument(t){try{if(!t)throw new Error("loadDocument called with falsy document");if(!t.scene||typeof t.scene!="object"){const r=new St;t.scene=r.scene}t.scene.sceneData={...mi,...t.scene.sceneData||{}},t.scene.sceneData.pan2Dxyzmm||(t.scene.sceneData.pan2Dxyzmm=ae(0,0,0,1)),t.scene.sceneData.crosshairPos||(t.scene.sceneData.crosshairPos=k(.5,.5,.5)),t.data={...t.data||{},imageOptionsArray:t.data?.imageOptionsArray??[],encodedImageBlobs:t.data?.encodedImageBlobs??[],labels:t.data?.labels??[],meshOptionsArray:t.data?.meshOptionsArray??[],connectomes:t.data?.connectomes??[],encodedDrawingBlob:t.data?.encodedDrawingBlob??"",previewImageDataURL:t.data?.previewImageDataURL??"",customData:t.data?.customData??"",title:t.data?.title??t.title??"untitled"}}catch(r){console.warn("loadDocument: defensive initialization failed",r)}this.volumes=[],this.meshes=[],this.document=t,this.document.labels=this.document.labels?this.document.labels:[];const e={...ke,...t.opts||{}};this.scene.pan2Dxyzmm=t.scene.sceneData?.pan2Dxyzmm??[0,0,0,1],this.document.opts=e,this.scene.clipPlaneDepthAziElevs&&this.setClipPlane(this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex??0]),F.debug("load document",t),this.mediaUrlMap.clear(),this.createEmptyDrawing();try{const r=await xs.rehydrateImages(t.data);for(const s of r||[])try{this.addVolume(s)}catch(n){console.warn("Failed to add rehydrated image:",n,s)}}catch(r){console.warn("NVSerializer.rehydrateImages failed:",r)}this.volumes&&this.volumes.length>0?this.back=this.volumes[0]:this.volumes=[];try{const r=await xs.rehydrateMeshes(t.data,this.gl,!0);for(const s of r||[])try{typeof s.updateMesh=="function"&&s.updateMesh(this.gl),this.addMesh(s)}catch(n){console.error("Failed to add rehydrated mesh:",n,s)}}catch(r){console.warn("NVSerializer.rehydrateMeshes failed:",r)}if(t.data.connectomes)for(const r of t.data.connectomes)try{const s=JSON.parse(r),n=this.loadConnectomeAsMesh(s);n.updateMesh(this.gl),this.addMesh(n)}catch(s){console.warn("Failed to rehydrate connectome:",s)}this.createEmptyDrawing();const i=t.encodedDrawingBlob;if(i)try{const r=await H.b64toUint8(i);if(r){const s=this.back?.dims;if(!s)console.warn("No back image available; cannot validate drawBitmap size."),this.drawBitmap=r;else{let n=s[1]*s[2]*s[3];if(r.length-352===n&&(n+=352),r.length!==n)throw new Error(`drawBitmap size does not match the texture dimensions (${s[1]}×${s[2]}×${s[3]}) ${n} != ${s[1]*s[2]*s[3]}.`);this.drawBitmap=r,this.refreshDrawing()}}}catch(r){console.warn("Failed to decode drawBitmap:",r)}return await this.setGradientOpacity(this.opts.gradientOpacity),await this.setVolumeRenderIllumination(this.opts.gradientAmount),this.updateGLVolume(),this.drawScene(),this._emitEvent("documentLoaded",t),this.onDocumentLoaded(t),this}async generateLoadDocumentJavaScript(t,e){const i=this.json(),r=await H.compressToBase64String(JSON.stringify(i));return`
|
|
2367
|
+
${e}
|
|
2368
|
+
|
|
2369
|
+
async function saveNiivueAsHtml(pageName) {
|
|
2370
|
+
//get new docstring
|
|
2371
|
+
const docString = nv1.json();
|
|
2372
|
+
const html =
|
|
2373
|
+
document.getElementsByTagName("html")[0]
|
|
2374
|
+
.innerHTML.replace(base64, await NVUtilities.compressToBase64String(JSON.stringify(docString)));
|
|
2375
|
+
NVUtilities.download(html, pageName, "application/html");
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
var nv1 = new Niivue();
|
|
2379
|
+
await nv1.attachTo("${t}");
|
|
2380
|
+
var base64 = "${r}";
|
|
2381
|
+
NVUtilities.decompressBase64String(base64).then((jsonText) => {
|
|
2382
|
+
var json = JSON.parse(jsonText); // string -> JSON
|
|
2383
|
+
var doc = NVDocument.loadFromJSON(json);
|
|
2384
|
+
nv1.loadDocument(doc);
|
|
2385
|
+
nv1.updateGLVolume();
|
|
2386
|
+
});
|
|
2387
|
+
|
|
2388
|
+
`}async generateHTML(t="gl1",e){return`<!DOCTYPE html>
|
|
2389
|
+
<html lang="en">
|
|
2390
|
+
<head>
|
|
2391
|
+
<meta charset="utf-8" />
|
|
2392
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
2393
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
|
2394
|
+
<title>Save as HTML</title>
|
|
2395
|
+
<style>
|
|
2396
|
+
html {
|
|
2397
|
+
height: auto;
|
|
2398
|
+
min-height: 100%;
|
|
2399
|
+
margin: 0;
|
|
2400
|
+
}
|
|
2401
|
+
body {
|
|
2402
|
+
display: flex;
|
|
2403
|
+
flex-direction: column;
|
|
2404
|
+
margin: 0;
|
|
2405
|
+
min-height: 100%;
|
|
2406
|
+
width: 100%;
|
|
2407
|
+
position: absolute;
|
|
2408
|
+
font-family: system-ui, Arial, Helvetica, sans-serif;
|
|
2409
|
+
background: #ffffff;
|
|
2410
|
+
color: black;
|
|
2411
|
+
user-select: none; /* Standard syntax */
|
|
2412
|
+
}
|
|
2413
|
+
header {
|
|
2414
|
+
margin: 10px;
|
|
2415
|
+
}
|
|
2416
|
+
main {
|
|
2417
|
+
flex: 1;
|
|
2418
|
+
background: #000000;
|
|
2419
|
+
position: relative;
|
|
2420
|
+
}
|
|
2421
|
+
footer {
|
|
2422
|
+
margin: 10px;
|
|
2423
|
+
}
|
|
2424
|
+
canvas {
|
|
2425
|
+
position: absolute;
|
|
2426
|
+
cursor: crosshair;
|
|
2427
|
+
}
|
|
2428
|
+
canvas:focus {
|
|
2429
|
+
outline: 0px;
|
|
2430
|
+
}
|
|
2431
|
+
div {
|
|
2432
|
+
display: table-row;
|
|
2433
|
+
background-color: blue;
|
|
2434
|
+
}
|
|
2435
|
+
</style>
|
|
2436
|
+
</head>
|
|
2437
|
+
<body>
|
|
2438
|
+
<noscript>niivue requires JavaScript.</noscript>
|
|
2439
|
+
<header>
|
|
2440
|
+
Save the current scene as HTML
|
|
2441
|
+
<button id="save">Save as HTML</button>
|
|
2442
|
+
</header>
|
|
2443
|
+
<main>
|
|
2444
|
+
<canvas id="gl1"></canvas>
|
|
2445
|
+
</main>
|
|
2446
|
+
<script type="module" async>
|
|
2447
|
+
${await this.generateLoadDocumentJavaScript(t,e)}
|
|
2448
|
+
function saveAsHtml() {
|
|
2449
|
+
saveNiivueAsHtml("page.html");
|
|
2450
|
+
}
|
|
2451
|
+
// assign our event handler
|
|
2452
|
+
var button = document.getElementById("save");
|
|
2453
|
+
button.onclick = saveAsHtml;
|
|
2454
|
+
<\/script>
|
|
2455
|
+
</body>
|
|
2456
|
+
</html>`}async saveHTML(t="untitled.html",e="gl1",i){const r=await this.generateHTML(e,i);return H.download(r,t,"application/html")}json(){return this.document.opts=this.opts,this.document.scene=this.scene,this.document.volumes=this.volumes,this.document.meshes=this.meshes,this.drawScene(),this.document.previewImageDataURL=this.canvas.toDataURL(),this.document.json()}async saveDocument(t="untitled.nvd",e=!0,i={}){const{embedImages:r=!0,embedPreview:s=!0}=i;this.document.title=t,this.document.volumes=this.volumes,this.document.meshes=this.meshes,s?(this.drawScene(),this.document.previewImageDataURL=this.canvas.toDataURL()):this.document.previewImageDataURL="",await this.document.download(t,e,{embedImages:r})}async loadImages(t){const e=[],i=[];for(const r of t)if("url"in r){const s=this.getFileExt(r.name?r.name:r.url);if(this.loaders[s]){const n=this.loaders[s].toExt.toUpperCase();Zt.includes(n)?i.push(r):e.push(r);continue}Zt.includes(s.toUpperCase())?i.push(r):e.push(r)}return e.length>0&&await this.loadVolumes(e),i.length>0&&await this.loadMeshes(i),this}async loadDicoms(t){if(!this.getDicomLoader())throw new Error("No dicom loader set. Please set a dicom loader before loading dicoms");this.drawScene(),this.volumes=[];const e=t.map(async r=>{let s=null;if(r.isManifest)s=await Me.fetchDicomData(r.url);else{const h=await fetch(r.url);if(!h.ok)throw new Error(`Failed to load file: ${h.statusText}`);const d=await h.arrayBuffer();s=[{name:r.url.split("/").pop(),data:d}]}const n=this.getDicomLoader().loader,a=await n(s),o=a[0].name,l=a[0].data;return await Me.loadFromUrl({url:l,name:o})}),i=await Promise.all(e);return i.length===1?this.addVolume(i[0]):(this._emitEvent("dicomLoaderFinished",{files:i}),this.onDicomLoaderFinishedWithImages(i)),this}async loadVolumes(t){return this.drawScene(),this.thumbnailVisible?(this.deferredVolumes=t,this):(this.volumes=[],this.closePAQD(),await this.addVolumesFromUrl(t),this)}async addMeshFromUrl(t){const e=this.getFileExt(t.url);if(e==="JCON"||e==="JSON"){let r;if(t.buffer){const n=ArrayBuffer.isView(t.buffer)?t.buffer:new Uint8Array(t.buffer),a=new TextDecoder("utf-8").decode(n);r=JSON.parse(a)}else r=await(await fetch(t.url)).json();const s=this.loadConnectomeAsMesh(r);return this.mediaUrlMap.set(s,t.url),this._emitEvent("meshAddedFromUrl",{meshOptions:t,mesh:s}),this.onMeshAddedFromUrl(t,s),this.addMesh(s),s}const i=await mt.loadFromUrl({...t,gl:this.gl});return this.mediaUrlMap.set(i,t.url),this._emitEvent("meshAddedFromUrl",{meshOptions:t,mesh:i}),this.onMeshAddedFromUrl(t,i),this.addMesh(i),i}async addMeshesFromUrl(t){const e=t.map(async r=>{const s=this.getFileExt(r.name||r.url);if(this.loaders[s]){let a=r.url;const o=this.loaders[s].toExt;let l=r.name||r.url;if(l=l.split("/").pop(),typeof r.url=="string"){const p=r.url;try{const g=await fetch(p);if(!g.ok)throw new Error(`Failed to load file: ${g.statusText}`);a=await g.arrayBuffer()}catch(g){throw new Error(`Failed to load url ${p}: ${g}`)}}const{positions:c,indices:h,colors:d=null,scalars:f=null,colormapLabel:u=null}=await this.loaders[s].loader(a);r.name=`${l}.${o}`;const m=await $e.createMZ3Async(c,h,!1,d,f,u);r.buffer=m}if(s==="JCON"||s==="JSON"){const o=await(await fetch(r.url,{})).json(),l=this.loadConnectomeAsMesh(o);return this.mediaUrlMap.set(l,r.url),this._emitEvent("meshAddedFromUrl",{meshOptions:r,mesh:l}),this.onMeshAddedFromUrl(r,l),l}const n=await mt.loadFromUrl({...r,gl:this.gl});return this.mediaUrlMap.set(n,r.url),this._emitEvent("meshAddedFromUrl",{meshOptions:r,mesh:n}),this.onMeshAddedFromUrl(r,n),n}),i=await Promise.all(e);for(let r=0;r<i.length;r++)this.addMesh(i[r]);return i}async loadMeshes(t){return this.drawScene(),this.thumbnailVisible?(this.deferredMeshes=t,this):(this.initialized,this.meshes=[],await this.addMeshesFromUrl(t),this.updateGLVolume(),this.drawScene(),this)}async loadConnectomeFromUrl(t,e={}){const r=await(await fetch(t,{headers:e})).json();return this.loadConnectome(r)}async loadFreeSurferConnectomeFromUrl(t,e={}){const r=await(await fetch(t,{headers:e})).json();return this.loadFreeSurferConnectome(r)}async loadFreeSurferConnectome(t){const e=ci.convertFreeSurferConnectome(t);return this.loadConnectome(e)}handleNodeAdded(t){const e=Xf(t.detail.node);this.addLabel(e.text,e.style,e.position),this.drawScene()}loadConnectomeAsMesh(t){return Yf({gl:this.gl,json:t})}loadConnectome(t){this.drawScene(),this.meshes=[];const e=this.loadConnectomeAsMesh(t);return this.addMesh(e),this.drawScene(),this}createEmptyDrawing(){if(this.back===null||!this.back.dims||Math.min(Math.min(this.back.dims[1],this.back.dims[2]),this.back.dims[3])<1)return;const e=Wi(this.back.dims);this.drawBitmap=Ki(e),this.clickToSegmentGrowingBitmap=Ki(e),this.drawClearAllUndoBitmaps(),this.drawAddUndoBitmap(),this.opts.is2DSliceShader?this.drawTexture=this.r8Tex2D(this.drawTexture,$.TEXTURE7_DRAW,this.back.dims):this.drawTexture=this.r8Tex(this.drawTexture,$.TEXTURE7_DRAW,this.back.dims,!0),this.refreshDrawing(!1)}drawGrowCut(){if(!this.back||!this.back.dims)throw new Error("back not defined");const t=this.back.hdr,e=this.gl,i=t.dims[1]*t.dims[2]*t.dims[3];if(!this.drawBitmap||this.drawBitmap.length!==i){F.debug("bitmap dims are wrong");return}const r=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,r),e.disable(e.CULL_FACE),e.viewport(0,0,this.back.dims[1],this.back.dims[2]),e.disable(e.BLEND);let s=C0(this.back);const n=this.r16Tex(null,$.TEXTURE11_GC_BACK,this.back.dims,s);for(let v=1;v<i;v++)s[v]=this.drawBitmap[v];const a=this.r16Tex(null,$.TEXTURE14_GC_LABEL0,this.back.dims,s),o=this.r16Tex(null,$.TEXTURE15_GC_LABEL1,this.back.dims,s),l=1e4;for(let v=1;v<i;v++)s[v]>0&&(s[v]=l);const c=this.r16Tex(null,$.TEXTURE12_GC_STRENGTH0,this.back.dims,s),h=this.r16Tex(null,$.TEXTURE13_GC_STRENGTH1,this.back.dims,s);e.bindVertexArray(this.genericVAO);const d=this.growCutShader;d.use(e);const f=128;e.uniform1i(d.uniforms.finalPass,0),e.uniform1i(d.uniforms.backTex,11);for(let v=0;v<f;v++){e.uniform1i(d.uniforms.labelTex,14),e.uniform1i(d.uniforms.strengthTex,12);for(let b=0;b<this.back.dims[3];b++){const w=1/this.back.dims[3]*(b+.5);e.uniform1f(d.uniforms.coordZ,w),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,o,0,b),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT1,h,0,b),e.drawBuffers([e.COLOR_ATTACHMENT0,e.COLOR_ATTACHMENT1]),e.checkFramebufferStatus(e.FRAMEBUFFER)!==e.FRAMEBUFFER_COMPLETE&&F.error("Incomplete framebuffer"),e.drawArrays(e.TRIANGLE_STRIP,0,4)}v===f-1&&e.uniform1i(d.uniforms.finalPass,1),e.uniform1i(d.uniforms.labelTex,15),e.uniform1i(d.uniforms.strengthTex,13);for(let b=0;b<this.back.dims[3];b++){const w=1/this.back.dims[3]*(b+.5);e.uniform1f(d.uniforms.coordZ,w),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,a,0,b),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT1,c,0,b),e.drawBuffers([e.COLOR_ATTACHMENT0,e.COLOR_ATTACHMENT1]),e.checkFramebufferStatus(e.FRAMEBUFFER)!==e.FRAMEBUFFER_COMPLETE&&F.error("Incomplete framebuffer"),e.drawArrays(e.TRIANGLE_STRIP,0,4)}}e.drawBuffers([e.COLOR_ATTACHMENT0]);const u=e.COLOR_ATTACHMENT1,m=a;e.readBuffer(u);const p=e.getParameter(e.IMPLEMENTATION_COLOR_READ_FORMAT),g=e.getParameter(e.IMPLEMENTATION_COLOR_READ_TYPE);(p!==e.RED_INTEGER||g!==e.SHORT)&&F.debug("readPixels will fail."),s=new Int16Array;const x=this.back.dims[1]*this.back.dims[2],A=new Int16Array(x);for(let v=0;v<this.back.dims[3];v++)e.framebufferTextureLayer(e.FRAMEBUFFER,u,m,0,v),e.readPixels(0,0,this.back.dims[1],this.back.dims[2],p,g,A),s=Int16Array.from([...s,...A]);let y=s[0];for(let v=0;v<s.length;v++)y=Math.max(y,s[v]);for(let v=1;v<i;v++)this.drawBitmap[v]=s[v];e.deleteTexture(n),e.deleteTexture(c),e.deleteTexture(h),e.deleteTexture(a),e.deleteTexture(o),e.bindVertexArray(this.unusedVAO),e.viewport(0,0,e.canvas.width,e.canvas.height),e.bindFramebuffer(e.FRAMEBUFFER,null),e.deleteFramebuffer(r),this.drawAddUndoBitmap(),this.refreshDrawing(!0)}drawPt(t,e,i,r,s=null){const n=s??this.drawBitmap;if(!n)throw new Error("drawBitmap not set");if(!this.back?.dims)throw new Error("back.dims not set");gt({x:t,y:e,z:i,penValue:r,drawBitmap:n,dims:this.back.dims,penSize:this.opts.penSize,penAxCorSag:this.drawPenAxCorSag})}drawPenLine(t,e,i){if(!this.drawBitmap)throw new Error("drawBitmap not set");if(!this.back?.dims)throw new Error("back.dims not set");H2({ptA:t,ptB:e,penValue:i,drawBitmap:this.drawBitmap,dims:this.back.dims,penSize:this.opts.penSize,penAxCorSag:this.drawPenAxCorSag})}drawRectangleMask(t,e,i){if(!this.drawBitmap)throw new Error("drawBitmap not set");if(!this.back?.dims)throw new Error("back.dims not set");_2({ptA:t,ptB:e,penValue:i,drawBitmap:this.drawBitmap,dims:this.back.dims,penSize:this.opts.penSize,penAxCorSag:this.drawPenAxCorSag})}drawEllipseMask(t,e,i){if(!this.drawBitmap)throw new Error("drawBitmap not set");if(!this.back?.dims)throw new Error("back.dims not set");J2({ptA:t,ptB:e,penValue:i,drawBitmap:this.drawBitmap,dims:this.back.dims,penSize:this.opts.penSize,penAxCorSag:this.drawPenAxCorSag})}drawingBinaryDilationWithSeed(t,e=6){try{let i=function(g){return g[0]+g[1]*o+g[2]*l};const r=this.drawBitmap,s=this.back.dims[1],n=this.back.dims[2],a=this.back.dims[3],o=s,l=s*n,c=l*a,h=i(t);if(h<0||h>=c)throw new Error("Seed index is out of bounds.");const d=r[h];if(d===0)throw new Error("Seed voxel is not part of a filled cluster.");const f=r.slice();for(let g=0;g<c;g++)f[g]=f[g]===d?1:0;this.drawFloodFillCore(f,h,e);const u=r.slice(),m=[],p=[-l,l,-s,s,-1,1];m.push(...p),e>6&&m.push(-s-1,-s+1,s-1,s+1,-l-s,-l+s,-l-1,-l+1,l-s,l+s,l-1,l+1),e>18&&m.push(-l-s-1,-l-s+1,-l+s-1,-l+s+1,l-s-1,l-s+1,l+s-1,l+s+1);for(let g=0;g<c;g++)if(f[g]===2){const x=g%s,A=Math.floor(g%l/s),y=Math.floor(g/l);for(const v of m){const b=g+v;if(b<0||b>=c)continue;const w=b%s,C=Math.floor(b%l/s),M=Math.floor(b/l);Math.abs(w-x)>1||Math.abs(C-A)>1||Math.abs(M-y)>1||r[b]===0&&(u[b]=d)}}this.drawBitmap=u,this.drawAddUndoBitmap(),this.refreshDrawing(!0)}catch(i){F.error("Error in drawingBinaryDilationWithSeed:",i)}}drawFloodFillCore(t,e,i=6){if(!this.back?.dims)throw new Error("back.dims undefined");const r=[this.back.dims[1],this.back.dims[2],this.back.dims[3]];im({img:t,seedVx:e,dims:r,neighbors:i})}drawFloodFill(t,e=0,i=0,r=NaN,s=NaN,n=6,a=Number.POSITIVE_INFINITY,o=!1,l=null,c=!1){if(!this.drawBitmap&&(F.warn("drawFloodFill called without an initialized drawBitmap."),this.createEmptyDrawing(),!this.drawBitmap)){F.error("Failed to create drawing bitmap.");return}if(this.clickToSegmentIsGrowing&&!this.clickToSegmentGrowingBitmap){if(F.warn("drawFloodFill called in preview mode without initialized clickToSegmentGrowingBitmap."),this.drawBitmap)this.clickToSegmentGrowingBitmap=this.drawBitmap.slice();else{F.error("Cannot initialize growing bitmap as drawBitmap is null.");return}if(!this.clickToSegmentGrowingBitmap){F.error("Failed to create growing bitmap.");return}}if(l===null&&(l=this.drawBitmap),!l){F.error("drawFloodFill targetBitmap is null.");return}if(!this.back?.dims)throw new Error("back.dims undefined");e=Math.abs(e);const h=[this.back.dims[1],this.back.dims[2],this.back.dims[3]];if(!lm(t,h))return;const d=ua(h),{nxyz:f}=d,u=this.clickToSegmentIsGrowing?this.drawBitmap:l;if(!u){F.error("Could not determine original bitmap state.");return}const m=new Uint8Array(f).fill(0),p=tm(o,this.drawPenAxCorSag),g=d.vx2xyz,x=d.xyz2vx,A=T=>this.vox2mm(T,this.back.matRAS),y=A(t),v=a**2;function b(T){const E=g(T);if(p>=0&&E[p]!==t[p])return!1;const I=A(E);return(I[0]-y[0])**2+(I[1]-y[1])**2+(I[2]-y[2])**2<=v}const w=x(t),C=u[w];if(c&&!cm(C)){F.debug("Grow/Erase Cluster tool requires starting on a masked voxel."),this.clickToSegmentIsGrowing&&this.clickToSegmentGrowingBitmap&&this.drawBitmap&&(this.clickToSegmentGrowingBitmap.set(this.drawBitmap),this.refreshDrawing(!0,!0));return}if(i===0&&C===e&&!c&&e!==0&&(F.debug("drawFloodFill selected voxel is already desired color"),!this.clickToSegmentIsGrowing))return;let M=NaN;if(c&&(i===Number.POSITIVE_INFINITY||i===Number.NEGATIVE_INFINITY)){const T=u.slice();for(let U=0;U<f;U++)T[U]=T[U]===C&&b(U)?1:0;if(T[w]!==1){F.error("Seed voxel could not be marked for cluster ID.");return}this.drawFloodFillCore(T,w,n);const E=this.volumes[0].img2RAS();M=om({clusterImg:T,backImg:E,nxyz:f,fallbackIntensity:E[w]}),F.debug(`Grow Cluster using mean intensity: ${M.toFixed(2)} voxels.`);const[I,S]=zs(i,M,NaN,NaN);for(let U=0;U<f;U++)if(T[U]===2)m[U]=1;else if(u[U]===0){const B=E[U];B>=I&&B<=S&&b(U)&&(m[U]=1)}e=C}else if(i===0)if(c&&e===0){F.debug(`Erase Cluster: Identifying cluster with color ${C}`);for(let T=0;T<f;T++)m[T]=u[T]===C&&b(T)?1:0}else for(let T=0;T<f;T++)u[T]===C&&b(T)&&C!==0&&(m[T]=1);else{const T=this.volumes[0].img2RAS();M=T[w];const[E,I]=zs(i,M,r,s);for(let S=0;S<f;S++){const U=T[S];U>=E&&U<=I&&b(S)&&(m[S]=1)}e=u[w],e===0&&(e=this.opts.penValue,(e<1||!isFinite(e))&&(e=1))}if(m[w]!==1)if(hm(C,e,c,i)&&b(w))m[w]=1,F.debug("Forcing seed voxel to 1 in working buffer.");else{F.debug("Seed voxel not marked as candidate '1' and not valid originally."),this.clickToSegmentIsGrowing&&this.clickToSegmentGrowingBitmap&&this.drawBitmap&&this.clickToSegmentGrowingBitmap.set(this.drawBitmap);return}this.drawFloodFillCore(m,w,n),dm({img:m,targetBitmap:l,originalBitmap:u,newColor:e,nxyz:f,isPreviewMode:this.clickToSegmentIsGrowing&&l===this.clickToSegmentGrowingBitmap}),this.clickToSegmentIsGrowing?this.refreshDrawing(!0,!0):(this.drawAddUndoBitmap(),this.refreshDrawing(!0,!1))}floodFillSectionFIFO(t,e,i,r){da({img2D:t,dims2D:e,minPt:i,maxPt:r})}drawPenFilled(){if(this.drawPenFillPts.length<2){this.drawPenFillPts=[];return}if(!this.drawBitmap)throw new Error("drawBitmap undefined");if(!this.back?.dims)throw new Error("back.dims undefined");const t=this.drawUndoBitmaps[this.currentDrawUndoBitmap]?.length>0?this.drawUndoBitmaps[this.currentDrawUndoBitmap]:null,e=Q2({penFillPts:this.drawPenFillPts,penAxCorSag:this.drawPenAxCorSag,drawBitmap:this.drawBitmap,dims:this.back.dims,penValue:this.opts.penValue,fillOverwrites:this.drawFillOverwrites,currentUndoBitmap:t});e.success&&(this.drawBitmap=e.drawBitmap),this.drawPenFillPts=[],this.drawAddUndoBitmap(),this.refreshDrawing(!1),this._emitEvent("drawingChanged",{action:"draw"}),this.onDrawingChanged("draw")}blurDrawingGL(t){const e=this.gl,i=this.blurShader;if(!i||!this.drawTexture)return;const r=Math.max(1,Math.round(this.opts.smoothDrawing));this.drawSmoothedTexture=qc(e,this.drawSmoothedTexture,$.TEXTURE10_DRAW_SMOOTH,t);const s=$.TEXTURE11_GC_BACK,n=11;e.bindVertexArray(this.genericVAO);const a=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,a),e.viewport(0,0,t[1],t[2]),e.disable(e.BLEND),i.use(e),e.activeTexture(s),e.bindTexture(e.TEXTURE_3D,this.drawTexture),e.uniform1i(i.uniforms.intensityVol,n),e.uniform1f(i.uniforms.dX,1/t[1]),e.uniform1f(i.uniforms.dY,1/t[2]),e.uniform1f(i.uniforms.dZ,1/t[3]),e.uniform1i(i.uniforms.kernelRadius,r),e.uniform1i(i.uniforms.binarize,1);for(let o=0;o<t[3];o++)e.uniform1f(i.uniforms.coordZ,(o+.5)/t[3]),e.framebufferTextureLayer(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,this.drawSmoothedTexture,0,o),e.drawArrays(e.TRIANGLE_STRIP,0,4);e.deleteFramebuffer(a),e.bindFramebuffer(e.FRAMEBUFFER,null),e.bindVertexArray(this.unusedVAO)}closeDrawing(){this.drawClearAllUndoBitmaps(),this.drawTexture=this.rgbaTex(this.drawTexture,$.TEXTURE7_DRAW,[2,2,2,2],!0),this.drawSmoothedTexture&&(this.gl.deleteTexture(this.drawSmoothedTexture),this.drawSmoothedTexture=null),this.drawBitmap=null,this.clickToSegmentGrowingBitmap=null,this._emitEvent("drawingChanged",{action:"close"}),this.onDrawingChanged("close"),this.drawScene()}refreshDrawing(t=!0,e=!1){const i=Y2({useClickToSegmentBitmap:e,drawingEnabled:this.opts.drawingEnabled,clickToSegment:this.opts.clickToSegment,drawBitmap:this.drawBitmap,clickToSegmentGrowingBitmap:this.clickToSegmentGrowingBitmap});i.warning&&F.warn(`refreshDrawing: ${i.warning}`);const r=i.bitmapDataSource;if(!this.back?.dims){F.warn("refreshDrawing: back.dims undefined, cannot refresh drawing texture yet.");return}const s=Wi(this.back.dims);if(!r){F.warn(`refreshDrawing: Bitmap data source (${i.useClickToSegmentBitmap?"growing":"main"}) is null. Cannot update texture.`),t&&this.drawScene();return}const n=W2(r.length,this.back.dims.slice());if(K2(r.length,s)||F.warn(`Drawing bitmap length (${r.length}) must match the background image (${s})`),this.gl.activeTexture($.TEXTURE7_DRAW),this.opts.is2DSliceShader){const o=this.frac2vox(this.scene.crosshairPos),l=Math.min(Math.max(o[2],0),n[3]-1),c=n[1]*n[2],h=l*c;F.debug(`refresh huge 2D drawing x×y×z ${n[1]}×${n[2]}×${n[3]} slice ${h}`);const d=r.subarray(h,h+c);this.gl.bindTexture(this.gl.TEXTURE_2D,this.drawTexture),this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,0,0,n[1],n[2],this.gl.RED,this.gl.UNSIGNED_BYTE,d)}else this.gl.bindTexture(this.gl.TEXTURE_3D,this.drawTexture),this.gl.texSubImage3D(this.gl.TEXTURE_3D,0,0,0,0,n[1],n[2],n[3],this.gl.RED,this.gl.UNSIGNED_BYTE,r);if(!this.drawTexture){F.error("refreshDrawing: drawTexture (GPU texture) is null.");return}const a=r.some(o=>o!==0);this.opts.smoothDrawing>0&&!this.opts.is2DSliceShader&&a&&this.blurDrawingGL(n),t&&this.drawScene()}closePAQD(){!this._gl||!this.paqdTexture||(this.paqdTexture=this.rgbaTex(this.paqdTexture,$.TEXTURE8_PAQD,[2,2,2,2],!0))}r8Tex2D(t,e,i,r=!1){if(t&&this.gl.deleteTexture(t),t=this.gl.createTexture(),this.gl.activeTexture(e),this.gl.bindTexture(this.gl.TEXTURE_2D,t),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_R,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,1),this.gl.texStorage2D(this.gl.TEXTURE_2D,1,this.gl.R8,i[1],i[2]),r){const s=new Uint8Array(i[1]*i[2]);this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,0,0,i[1],i[2],this.gl.RED,this.gl.UNSIGNED_BYTE,s)}return t}initFontMets(){if(!this.fontMetrics)throw new Error("fontMetrics undefined");this.fontMets={distanceRange:this.fontMetrics.atlas.distanceRange,size:this.fontMetrics.atlas.size,mets:{}};const t=this.fontMetrics.atlas.width,e=this.fontMetrics.atlas.height;for(let i=0;i<this.fontMetrics.glyphs.length;i++){const r=this.fontMetrics.glyphs[i],s=r.unicode;if(this.fontMets.mets[s]||(this.fontMets.mets[s]={xadv:0,uv_lbwh:[0,0,0,0],lbwh:[0,0,0,0]}),this.fontMets.mets[s].xadv=r.advance,r.planeBounds===void 0)continue;let n=r.atlasBounds.left/t,a=(e-r.atlasBounds.top)/e,o=(r.atlasBounds.right-r.atlasBounds.left)/t,l=(r.atlasBounds.top-r.atlasBounds.bottom)/e;this.fontMets.mets[s].uv_lbwh=[n,a,o,l],n=r.planeBounds.left,a=r.planeBounds.bottom,o=r.planeBounds.right-r.planeBounds.left,l=r.planeBounds.top-r.planeBounds.bottom,this.fontMets.mets[s].lbwh=[n,a,o,l]}}async loadFont(t=fs,e=us){if(await this.loadFontTexture(t),typeof e=="string"){const i=await fetch(e);if(!i.ok)throw Error(i.statusText);this.fontMetrics=await i.json()}else this.fontMetrics=e;this.initFontMets(),this.fontShader.use(this.gl),this.drawScene()}async loadDefaultMatCap(){return this.loadMatCapTexture(Gc)}async loadDefaultFont(){await this.loadFontTexture(this.DEFAULT_FONT_GLYPH_SHEET),this.fontMetrics=this.DEFAULT_FONT_METRICS,this.initFontMets()}async initText(){this.fontShader=new ee(this.gl,j0,_0),this.fontShader.use(this.gl),await this.loadDefaultFont(),await this.loadDefaultMatCap(),this.drawLoadingText(this.opts.loadingText)}meshShaderNameToNumber(t="Phong"){return Hn(t,this.meshShaders)}setMeshShader(t,e=2){const i=Gf({meshes:this.meshes,meshShaders:this.meshShaders,id:t,meshShaderNameOrNumber:e,meshShaderNameToNumber:this.meshShaderNameToNumber.bind(this)});i!==null&&(this.updateGLVolume(),this._emitEvent("meshShaderChanged",{meshIndex:i.meshIndex,shaderIndex:i.shaderIndex}),this.onMeshShaderChanged(i.meshIndex,i.shaderIndex))}createCustomMeshShader(t,e="Custom"){return Nd({gl:this.gl,fragmentShaderText:t,name:e,meshShaders:this.meshShaders})}setCustomSliceShader(t=""){this.customSliceShader=Pd({gl:this.gl,fragmentShaderText:t,drawOpacity:this.drawOpacity,customSliceShader:this.customSliceShader}),this.updateGLVolume()}setCustomMeshShader(t="",e="Custom"){const i=this.createCustomMeshShader(t,e);return this.meshShaders.push(i),this._emitEvent("customMeshShaderAdded",{fragmentShaderText:t,name:e}),this.onCustomMeshShaderAdded(t,e),this.meshShaders.length-1}async setCustomMeshShaderFromUrl(t,e=""){try{const i=await fetch(t);if(!i.ok)throw new Error(`Failed to fetch shader from ${t}: ${i.status} ${i.statusText}`);const r=await i.text();return(!e||e.trim()==="")&&(e=(t.split("/").pop()??t).split("?")[0].split("#")[0].replace(/\.[^/.]+$/,"")),this.setCustomMeshShader(r,e)}catch(i){throw new Error(`setCustomMeshShaderFromUrl(${t}) failed: ${i.message}`)}}meshShaderNames(t=!0){return Ld(this.meshShaders,t)}initRenderShader(t,e=0){It({gl:this.gl,shader:t,gradientAmount:e,renderDrawAmbientOcclusion:this.renderDrawAmbientOcclusion,renderSilhouette:this.opts.renderSilhouette,gradientOpacity:this.opts.gradientOpacity})}async init(){const t=this.gl.getExtension("WEBGL_debug_renderer_info");if(t){const d=this.gl.getParameter(t.UNMASKED_VENDOR_WEBGL),f=this.gl.getParameter(t.UNMASKED_RENDERER_WEBGL);F.info("renderer vendor: ",d),F.info("renderer: ",f)}else F.info("debug_renderer_info unavailable");const e=this.gl.getParameter(this.gl.RENDERER);F.info("firefox renderer: ",e),this.gl.enable(this.gl.CULL_FACE),this.gl.cullFace(this.gl.FRONT),this.gl.enable(this.gl.BLEND),this.gl.blendFunc(this.gl.SRC_ALPHA,this.gl.ONE_MINUS_SRC_ALPHA),this.volumeTexture=this.rgbaTex(this.volumeTexture,$.TEXTURE0_BACK_VOL,[2,2,2,2],!0),this.overlayTexture=this.rgbaTex(this.overlayTexture,$.TEXTURE2_OVERLAY_VOL,[2,2,2,2],!0),this.drawTexture=this.r8Tex(this.drawTexture,$.TEXTURE7_DRAW,[2,2,2,2],!0),this.paqdTexture=this.rgbaTex(this.paqdTexture,$.TEXTURE8_PAQD,[2,2,2,2],!0);const i=[1,1,0,1,0,0,0,1,0,0,0,0],r=this.gl;this.cuboidVertexBuffer=r.createBuffer(),r.bindBuffer(r.ARRAY_BUFFER,this.cuboidVertexBuffer),r.bufferData(r.ARRAY_BUFFER,new Float32Array(i),r.STATIC_DRAW),this.genericVAO=r.createVertexArray(),r.bindVertexArray(this.genericVAO),r.bindBuffer(r.ARRAY_BUFFER,this.cuboidVertexBuffer),r.enableVertexAttribArray(0),r.vertexAttribPointer(0,3,r.FLOAT,!1,0,0),r.bindVertexArray(this.unusedVAO),this.pickingMeshShader=new ee(r,Pr,cd),this.pickingMeshShader.use(r),this.pickingImageShader=Hd(r);const s=kd(r,this.drawOpacity);this.slice2DShader=s.slice2DShader,this.sliceMMShader=s.sliceMMShader,this.sliceV1Shader=s.sliceV1Shader;const n=Od(r,gl,this.unusedVAO);this.orientCubeShader=n.shader,this.orientCubeShaderVAO=n.vao;const a=zd(r);this.rectShader=a.rectShader,this.rectOutlineShader=a.rectOutlineShader,this.lineShader=a.lineShader,this.line3DShader=a.line3DShader,this.circleShader=a.circleShader;const o=Gd({gl:r,renderDrawAmbientOcclusion:this.renderDrawAmbientOcclusion,renderSilhouette:this.opts.renderSilhouette,gradientOpacity:this.opts.gradientOpacity});this.renderVolumeShader=o.renderVolumeShader,this.renderSliceShader=o.renderSliceShader,this.renderGradientShader=o.renderGradientShader,this.renderGradientValuesShader=o.renderGradientValuesShader,this.renderShader=o.renderShader,this.colorbarShader=Yd(r);const l=Xd(r);this.blurShader=l.blurShader,this.gradientPrePassShader=l.gradientPrePassShader,this.sobelFirstOrderShader=l.sobelFirstOrderShader,this.sobelSecondOrderShader=l.sobelSecondOrderShader,this.growCutShader=l.growCutShader,this.passThroughShader=l.passThroughShader;const c=Wd(r);this.orientShaderAtlasU=c.orientShaderAtlasU,this.orientShaderAtlasI=c.orientShaderAtlasI,this.orientShaderU=c.orientShaderU,this.orientShaderI=c.orientShaderI,this.orientShaderF=c.orientShaderF,this.orientShaderRGBU=c.orientShaderRGBU,this.orientShaderPAQD=c.orientShaderPAQD;const h=Kd(r);return this.surfaceShader=h.surfaceShader,this.fiberShader=h.fiberShader,this.pickingImageShader.use(r),qd(r,this.meshShaders),this.bmpShader=new ee(r,Q0,Z0),await this.initText(),this.opts.thumbnail.length>0&&(await this.loadBmpTexture(this.opts.thumbnail),this.thumbnailVisible=!0),this.updateGLVolume(),this.initialized=!0,this.resizeListener(),this.drawScene(),this}gradientGL(t){this.gradientTexture=Es({gl:this.gl,hdr:t,genericVAO:this.genericVAO,unusedVAO:this.unusedVAO,volumeTexture:this.volumeTexture,paqdTexture:this.paqdTexture,gradientTexture:this.gradientTexture,gradientOrder:this.opts.gradientOrder,blurShader:this.blurShader,gradientPrePassShader:this.gradientPrePassShader,sobelFirstOrderShader:this.sobelFirstOrderShader,sobelSecondOrderShader:this.sobelSecondOrderShader,rgbaTex:this.rgbaTex.bind(this)})}getGradientTextureData(){return eu({gl:this.gl,gradientTexture:this.gradientTexture,dims:this.back?.dims??null})}setCustomGradientTexture(t,e){const i=tu({gl:this.gl,data:t,dims:e,backDims:this.back?.dims??null,gradientTexture:this.gradientTexture,gradientTextureAmount:this.gradientTextureAmount,hdr:this.back?.hdr??null,gradientGLFn:this.gradientGL.bind(this)});this.gradientTexture=i.gradientTexture,this.useCustomGradientTexture=i.useCustomGradientTexture,t!==null&&i.useCustomGradientTexture&&this.drawScene()}updateGLVolume(){let t=0;const e=this.volumes.length;this.refreshColormaps(),this.closePAQD();for(let i=0;i<e;i++)this.volumes[i].toRAS&&(this.refreshLayers(this.volumes[i],t),t++);if(this.furthestVertexFromOrigin=0,e>0&&(this.furthestVertexFromOrigin=this.volumeObject3D?.furthestVertexFromOrigin??0),this.meshes)for(let i=0;i<this.meshes.length;i++)this.furthestVertexFromOrigin=Math.max(this.furthestVertexFromOrigin,this.meshes[i].furthestVertexFromOrigin);this._emitEvent("volumeUpdated",void 0),this.onVolumeUpdated&&this.onVolumeUpdated(),this.drawScene()}getDescriptives(t){const{layer:e=0,masks:i=[],drawingIsMask:r=!1,roiIsMask:s=!1,startVox:n=[0,0,0],endVox:a=[0,0,0]}=t,o=this.volumes[e].hdr,l=this.volumes[e].pixDimsRAS,c=isNaN(o.scl_slope)?1:o.scl_slope,h=isNaN(o.scl_inter)?1:o.scl_inter,d=this.volumes[e].img,f=d.length,u=Tm(d,c,h),m=i.filter(A=>{const y=this.volumes[A].img.length===f;return y||F.debug("Mask resolution does not match image. Skipping masking layer "+A),y}).map(A=>this.volumes[A].img),{mask:p,area:g}=Mm({nv:f,maskImages:m.length>0?m:void 0,drawBitmap:this.drawBitmap,drawingIsMask:i.length<1&&r,roiIsMask:i.length<1&&s,startVox:n,endVox:a,hdr:o,pixDimsRAS:l}),x=Dm(u,p);return{...x,volumeMM3:x.nvox*o.pixDims[1]*o.pixDims[2]*o.pixDims[3],volumeML:x.nvox*o.pixDims[1]*o.pixDims[2]*o.pixDims[3]*.001,cal_min:this.volumes[e].cal_min,cal_max:this.volumes[e].cal_max,robust_min:this.volumes[e].robust_min,robust_max:this.volumes[e].robust_max,area:g}}refreshLayers(t,e){if(this.volumes.length<1)return;this.refreshColormaps();const i=t.hdr,r=of(t),s=t.opacity;if(e>1&&s===0)return;let n=null;if(!this.back)throw new Error("back undefined");this.gl.bindVertexArray(this.unusedVAO),this.crosshairs3D&&(this.crosshairs3D.mm[0]=NaN);let a=de(t.toRAS);if(e===0){this.volumeObject3D=mf({overlayItem:t,VOLUME_ID:this.VOLUME_ID,gl:this.gl}),Se(a,a),this.back.matRAS=t.matRAS,this.back.dims=t.dimsRAS,this.back.pixDims=t.pixDimsRAS;const{volScale:x,vox:A}=this.sliceScale(!0);this.volScale=x,this.vox=A,this.volumeObject3D.scale=Array.from(x);const{isAboveMax2D:y,isAboveMax3D:v}=lf({hdr:i,max2D:this.uiData.max2D,max3D:this.uiData.max3D});if(y&&F.error("Image dimensions exceed maximum texture size of hardware."),i.datatypeCode===2304&&i.dims[3]<2){F.info(`RGBA 2D image (${i.dims[1]}×${i.dims[2]}) using Texture2D`),this.opts.is2DSliceShader=!0,this.volumeTexture=this.rgbaTex2D(this.volumeTexture,$.TEXTURE0_BACK_VOL,t.dimsRAS,r,!1);return}if(v){F.info(`Large scalar image (>${this.uiData.max3D}) requires Texture2D (${i.dims[1]}×${i.dims[2]}×${i.dims[3]})`);const w=i.dims[1]*i.dims[2],C=this.frac2vox(this.scene.crosshairPos),T=Math.min(Math.max(C[2],0),i.dims[3]-1)*w,E=new Uint8Array(w*4),I=new Uint32Array(E.buffer),S=Math.floor(t.opacity*255),U=255*i.scl_slope/(t.cal_max-t.cal_min),B=255*(i.scl_inter-t.cal_min)/(t.cal_max-t.cal_min),V=new Uint8Array(this.colormap(t.colormap)),R=new Uint32Array(V.buffer);let P=-1;for(let L=0;L<w;L++){const N=r[L+T]*U+B,Y=Math.round(Math.min(255,Math.max(0,N)));I[L]=R[Y],E[P+=4]=S}this.opts.is2DSliceShader=!0,n=this.rgbaTex2D(this.volumeTexture,$.TEXTURE0_BACK_VOL,t.dimsRAS,E,!1);return}if(v&&F.warn(`dimensions exceed 3D limits ${i.dims}`),this.opts.is2DSliceShader=!1,n=this.rgbaTex(this.volumeTexture,$.TEXTURE0_BACK_VOL,t.dimsRAS),!this.renderShader)throw new Error("renderShader undefined");this.renderShader.use(this.gl),this.gl.uniform3fv(this.renderShader.uniforms.texVox,this.vox),this.gl.uniform3fv(this.renderShader.uniforms.volScale,this.volScale);const b=this.pickingImageShader;b.use(this.gl),this.gl.uniform1i(b.uniforms.volume,0),this.gl.uniform1i(b.uniforms.colormap,1),this.gl.uniform1i(b.uniforms.overlay,2),this.gl.uniform3fv(b.uniforms.volScale,this.volScale),F.debug(this.volumeObject3D)}else this.back?.dims===void 0&&F.error("Fatal error: Unable to render overlay: background dimensions not defined!"),a=pf({overlayItem:t,mm2frac:this.mm2frac.bind(this)}),e===1?(n=gf({gl:this.gl,layer:e,backDims:this.back.dims,rgbaTex:this.rgbaTex.bind(this)}).overlayTexture,this.overlayTexture=n,this.overlayTextureID=n):n=this.overlayTextureID;const o=Af(this.gl);this.gl.viewport(0,0,this.back.dims[1],this.back.dims[2]);const l=Mf({gl:this.gl,TEXTURE9_ORIENT:$.TEXTURE9_ORIENT});if(!i)throw new Error("hdr undefined");if(!r)throw new Error("img undefined");let c=this.orientShaderU;if(i.datatypeCode===2304){const x=Rf({gl:this.gl,hdr:i,img:r,overlayItem:t,layer:e,orientShaderRGBU:this.orientShaderRGBU,orientShaderPAQD:this.orientShaderPAQD,volumes:this.volumes,backDims:this.back.dims,rgbaTex:this.rgbaTex.bind(this),paqdTexture:this.paqdTexture,TEXTURE8_PAQD:$.TEXTURE8_PAQD,TEXTURE9_ORIENT:$.TEXTURE9_ORIENT});c=x.orientShader,x.outTexture!==null&&(n=x.outTexture),x.paqdTexture!==null&&(this.paqdTexture=x.paqdTexture)}else c=Uf({gl:this.gl,hdr:i,img:r,orientShaderU:this.orientShaderU,orientShaderI:this.orientShaderI,orientShaderF:this.orientShaderF,orientShaderRGBU:this.orientShaderRGBU,orientShaderAtlasU:this.orientShaderAtlasU,orientShaderAtlasI:this.orientShaderAtlasI}).orientShader;t.global_min===void 0&&t.calMinMax(),this.gl.bindVertexArray(this.genericVAO);const h=xf({gl:this.gl,layer:e,backDims:this.back.dims,rgbaTex:this.rgbaTex.bind(this),passThroughShader:this.passThroughShader});c.use(this.gl),this.gl.activeTexture($.TEXTURE1_COLORMAPS);const{colormapLabelTexture:d}=cf({gl:this.gl,overlayItem:t,orientShader:c,createColormapTexture:this.createColormapTexture.bind(this)});if(d===null&&(this.gl.bindTexture(this.gl.TEXTURE_2D,this.colormapTexture),this.gl.uniform1f(c.uniforms.cal_min,t.cal_min),this.gl.uniform1f(c.uniforms.cal_max,t.cal_max)),"alphaThreshold"in t&&(F.warn("alphaThreshold is deprecated: use colormapType"),t.alphaThreshold===!0&&(t.colormapType=2),t.alphaThreshold===!1&&(t.colormapType=1),delete t.alphaThreshold),!c)throw new Error("orientShader undefined");vf({gl:this.gl,overlayItem:t,orientShader:c,layer:e,isAdditiveBlend:this.opts.isAdditiveBlend});const{modulateTexture:f}=hf({gl:this.gl,overlayItem:t,hdr:i,volumes:this.volumes,orientShader:c,r8Tex:this.r8Tex.bind(this),TEXTURE7:this.gl.TEXTURE7});if(this.gl.activeTexture($.TEXTURE9_ORIENT),this.gl.bindTexture(this.gl.TEXTURE_3D,l),!this.back.dims)throw new Error("back.dims undefined");if(wf({gl:this.gl,orientShader:c,backDims:this.back.dims,outTexture:n,mtx:a,hdr:i,intensityVolTextureUnit:9,blendTextureUnit:10,colormapTextureUnit:1,modulationTextureUnit:7,opacity:s,atlasOutline:this.opts.atlasOutline,atlasActiveIndex:this.opts.atlasActiveIndex}),F.debug("back dims: ",this.back.dims),this.gl.bindVertexArray(this.unusedVAO),this.gl.deleteTexture(l),this.gl.deleteTexture(f),this.gl.deleteTexture(h),this.gl.viewport(0,0,this.gl.canvas.width,this.gl.canvas.height),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.deleteFramebuffer(o),e===0&&(this.volumeTexture=n,this.gradientTexture=Es({gl:this.gl,hdr:i,genericVAO:this.genericVAO,unusedVAO:this.unusedVAO,volumeTexture:this.volumeTexture,paqdTexture:this.paqdTexture,gradientTexture:this.gradientTexture,gradientOrder:this.opts.gradientOrder,blurShader:this.blurShader,gradientPrePassShader:this.gradientPrePassShader,sobelFirstOrderShader:this.sobelFirstOrderShader,sobelSecondOrderShader:this.sobelSecondOrderShader,rgbaTex:this.rgbaTex.bind(this)})),!this.renderShader)throw new Error("renderShader undefined");if(!this.pickingImageShader)throw new Error("pickingImageShader undefined");const u=this.sliceScale(!0),m=u.vox,p=u.volScale,g=bf({is2DSliceShader:this.opts.is2DSliceShader,isV1SliceShader:this.opts.isV1SliceShader,sliceMMShader:this.sliceMMShader,slice2DShader:this.slice2DShader,sliceV1Shader:this.sliceV1Shader,customSliceShader:this.customSliceShader});yf({gl:this.gl,renderShader:this.renderShader,pickingImageShader:this.pickingImageShader,sliceShader:g,overlaysLength:this.overlays.length,clipPlaneColor:this.opts.clipPlaneColor,backOpacity:this.volumes[0].opacity,renderOverlayBlend:this.opts.renderOverlayBlend,clipPlane:this.scene.clipPlane,texVox:m,volScale:p,drawOpacity:this.drawOpacity,paqdUniforms:this.opts.paqdUniforms}),d!==null&&(this.gl.deleteTexture(d),this.gl.activeTexture($.TEXTURE1_COLORMAPS),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colormapTexture)),Cf({gl:this.gl,shader:g,is2DSliceShader:this.opts.is2DSliceShader,drawTexture:this.drawTexture,paqdTexture:this.paqdTexture,TEXTURE7_DRAW:$.TEXTURE7_DRAW,TEXTURE8_PAQD:$.TEXTURE8_PAQD}),this.updateInterpolation(e)}colormaps(){return re.colormaps()}addColormap(t,e){re.addColormap(t,e)}setColormap(t,e){const i=this.getVolumeIndexByID(t);this.volumes[i].colormap=e,this.updateGLVolume()}idx(t,e,i,r){return pe(t,e,i,r)}check_previous_slice(t,e,i,r,s,n,a,o){return ma(t,e,i,r,s,n,a,o)}do_initial_labelling(t,e,i){const r=pa(t,e,i);return[r.labelCount,r.translationTable,r.initialLabels]}fill_tratab(t,e,i){Kr(t,e,i)}translate_labels(t,e,i,r){const s=ga(t,e,i,r);return[s.clusterCount,s.labels]}largest_original_cluster_labels(t,e,i){const r=Aa(t,e,i);return[r.maxValue,r.voxels]}bwlabel(t,e,i=26,r=!1,s=!1){const n=xm({img:t,dim:e,conn:i,binarize:r,onlyLargestClusterPerClass:s});return[n.clusterCount,n.labels]}async createConnectedLabelImage(t,e=26,i=!1,r=!1){const s=this.getVolumeIndexByID(t),n=Uint32Array.from(this.volumes[s].dims?.slice(1,4)??[]),a=Uint32Array.from(this.volumes[s].img?.slice()??[]),[o,l]=this.bwlabel(a,n,e,i,r),c=this.volumes[s].clone();c.opacity=.5,c.colormap="random";for(let h=0;h<c.img.length;h++)c.img[h]=l[h];return c.cal_min=0,c.cal_max=o,c}async createNiftiArray(t=[256,256,256],e=[1,1,1],i=[1,0,0,-128,0,1,0,-128,0,0,1,-128,0,0,0,1],r=2,s=new Uint8Array){return await Me.createNiftiArray(t,e,i,r,s)}async niftiArray2NVImage(t=new Uint8Array){return await Me.loadFromUrl({url:t})}async loadFromUrl(t){return await Me.loadFromUrl({url:t})}async conform(t,e=!1,i=!0,r=!1,s=!1,n=[256,256,256],a=1,o=!1){const[l,c,h]=n,d=a,{outAffine:f,invVox2vox:u}=ym({inDims:t.hdr.dims,inAffine:t.hdr.affine.flat(),outDims:[l,c,h],outMM:d,toRAS:e}),m=new Float32Array(t.img),p=t.hdr.dims[1]*t.hdr.dims[2]*t.hdr.dims[3];if(t.hdr.scl_slope!==1||t.hdr.scl_inter!==0)for(let A=0;A<p;A++)m[A]=m[A]*t.hdr.scl_slope+t.hdr.scl_inter;const g=bm({inImg:m,inDims:t.hdr.dims,outDims:[l,c,h],invVox2vox:u,isLinear:i});let x;if(o)x=await this.createNiftiArray([l,c,h],[d,d,d],Array.from(f),16,new Uint8Array(g.buffer));else if(r){const A=s?NaN:0,y={img:t.img,dims:t.hdr.dims,global_min:t.global_min,global_max:t.global_max,datatypeCode:t.hdr.datatypeCode,scl_slope:t.hdr.scl_slope,scl_inter:t.hdr.scl_inter,cal_min:t.cal_min,cal_max:t.cal_max,f_low:A};y.dst_min=0,y.dst_max=1;const[v,b]=Gs(y),w=wm(g,0,1,v,b);x=await this.createNiftiArray([l,c,h],[d,d,d],Array.from(f),16,new Uint8Array(w.buffer))}else{const A=s?NaN:0,y={img:t.img,dims:t.hdr.dims,global_min:t.global_min,global_max:t.global_max,datatypeCode:t.hdr.datatypeCode,scl_slope:t.hdr.scl_slope,scl_inter:t.hdr.scl_inter,cal_min:t.cal_min,cal_max:t.cal_max,f_low:A};y.dst_min=0,y.dst_max=255;const[v,b]=Gs(y),w=vm(g,0,255,v,b);x=await this.createNiftiArray([l,c,h],[d,d,d],Array.from(f),2,w)}return this.niftiArray2NVImage(x)}setRenderDrawAmbientOcclusion(t){if(!this.renderShader)throw new Error("renderShader undefined");this.renderDrawAmbientOcclusion=t,this.renderShader.use(this.gl),this.gl.uniform1fv(this.renderShader.uniforms.renderDrawAmbientOcclusion,[this.renderDrawAmbientOcclusion,1]),this.drawScene()}setColorMap(t,e){this.setColormap(t,e)}setColormapNegative(t,e){const i=this.getVolumeIndexByID(t);this.volumes[i].colormapNegative=e,this.updateGLVolume()}setModulationImage(t,e,i=0){const r=this.getVolumeIndexByID(t);let s=null;e.length>0&&(s=this.getVolumeIndexByID(e)),this.volumes[r].modulationImage=s,this.volumes[r].modulateAlpha=i,this.updateGLVolume()}setGamma(t=1){this.scene.gamma=t,re.gamma=t,this.updateGLVolume()}async loadDeferred4DVolumes(t){const e=this.getVolumeIndexByID(t),i=this.volumes[e];if(i.nTotalFrame4D<=i.nFrame4D)return;i.nTotalFrame4D=i.nFrame4D;let r;i.fileObject?r=await Me.loadFromFile({file:i.fileObject}):r=await Me.loadFromUrl({url:i.url}),r&&(i.img=r.img.slice(),i.nTotalFrame4D=r.nTotalFrame4D,i.nFrame4D=r.nFrame4D,this.updateGLVolume())}setFrame4D(t,e){const i=this.getVolumeIndexByID(t);if(i<0)return;const r=this.volumes[i].frame4D;sf(this.volumes,t,e),this.volumes[i].frame4D!==r&&(this.updateGLVolume(),this._emitEvent("frameChange",{volume:this.volumes[i],index:this.volumes[i].frame4D}),this.onFrameChange(this.volumes[i],this.volumes[i].frame4D),this.createOnLocationChange())}getFrame4D(t){return nf(this.volumes,t)}colormapFromKey(t){return re.colormapFromKey(t)}colormap(t="",e=!1){return re.colormap(t,e)}createColormapTexture(t=null,e=0,i=256){return t!==null&&this.gl.deleteTexture(t),e<1||i<1?null:(t=this.gl.createTexture(),this.gl.activeTexture($.TEXTURE1_COLORMAPS),this.gl.bindTexture(this.gl.TEXTURE_2D,t),this.gl.texStorage2D(this.gl.TEXTURE_2D,1,this.gl.RGBA8,i,e),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_R,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,1),t)}addColormapList(t="",e=NaN,i=NaN,r=!1,s=!1,n=!0,a=!1){t.length<1&&(n=!1),this.colormapLists.push({name:t,min:e,max:i,isColorbarFromZero:r,negative:s,visible:n,invert:a})}refreshColormaps(){if(this.colormapLists=[],this.volumes.length<1&&this.meshes.length<1)return;const t=this.volumes.length;if(t>0)for(let n=0;n<t;n++){const a=this.volumes[n],o=Pi(a.cal_min,a.cal_max,a.cal_minNeg,a.cal_maxNeg),l=a.colormapType!==0;this.addColormapList(a.colormapNegative,o[0],o[1],l,!0,a.colorbarVisible,a.colormapInvert),this.addColormapList(a.colormap,a.cal_min,a.cal_max,l,!1,a.colorbarVisible,a.colormapInvert)}const e=this.meshes.length;if(e>0)for(let n=0;n<e;n++){const a=this.meshes[n];if(!a.colorbarVisible)continue;const o=a.layers.length,l=a.fiberColor.toLowerCase();if(a.offsetPt0&&l.startsWith("dp")){let c=null;const h=parseInt(l.substring(3));l.startsWith("dpg")&&!a.fiberGroupColormap&&(c=h<a.dpg.length?a.dpg[h]:a.dpg[0]),l.startsWith("dps")&&(c=h<a.dps.length?a.dps[h]:a.dps[0]),l.startsWith("dpv")&&(c=h<a.dpv.length?a.dpv[h]:a.dpv[0]),c&&typeof a.colormap=="string"&&this.addColormapList(a.colormap,c.cal_min,c.cal_max,!1,!1,!0,a.colormapInvert)}if("edgeColormap"in a&&"edges"in a&&a.edges!==void 0){const c=Pi(a.edgeMin,a.edgeMax,NaN,NaN);this.addColormapList(a.edgeColormapNegative,c[0],c[1],!1,!0,!0,a.colormapInvert),this.addColormapList(a.edgeColormap,a.edgeMin,a.edgeMax,!1,!1,!0,a.colormapInvert)}if(!(o<1))for(let c=0;c<o;c++){const h=this.meshes[n].layers[c];if(!h.colorbarVisible||h.colormap.length<1)continue;const d=h.colormapType!==0;if(h.useNegativeCmap){const f=Pi(h.cal_min,h.cal_max,h.cal_minNeg,h.cal_maxNeg);this.addColormapList(h.colormapNegative,f[0],f[1],d,!0,!0,h.colormapInvert)}this.addColormapList(h.colormap,h.cal_min,h.cal_max,d,!1,!0,h.colormapInvert)}}const i=this.colormapLists.length;if(i<1)return;this.colormapTexture=this.createColormapTexture(this.colormapTexture,i+1);let r=new Uint8ClampedArray;function s(n){const a=new Uint8ClampedArray(r.length+n.length);a.set(r),a.set(n,r.length),r=a}for(let n=0;n<i;n++)s(Array.from(this.colormap(this.colormapLists[n].name,this.colormapLists[n].invert)));return s(Array.from(this.drawLut.lut)),this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,0,0,256,i+1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,r),this}sliceScale(t=!1){if(!this.back?.dims)throw new Error("back.dims undefined");return o2({forceVox:t,getScreenFieldOfViewMM:e=>this.screenFieldOfViewMM(e),getScreenFieldOfViewVox:e=>this.screenFieldOfViewVox(e),backDims:this.back.dims})}tileIndex(t,e){return Xr({x:t,y:e,screenSlices:this.screenSlices})}inRenderTile(t,e){return H1({x:t,y:e,screenSlices:this.screenSlices})}sliceScroll3D(t=0){const e=_1({posChange:t,volumesLength:this.volumes.length,clipPlaneDepthAziElevs:this.scene.clipPlaneDepthAziElevs,activeClipPlaneIndex:this.uiData.activeClipPlaneIndex,volScaleMultiplier:this.scene.volScaleMultiplier});if(e.action!=="none"){if(e.action==="clipPlane"&&e.newClipPlaneDepth!==void 0){const i=this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex].slice();return i[0]=e.newClipPlaneDepth,this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex]=i,this.setClipPlane(this.scene.clipPlaneDepthAziElevs[this.uiData.activeClipPlaneIndex])}e.action==="zoom"&&e.newVolScaleMultiplier!==void 0&&(this.scene.volScaleMultiplier=e.newVolScaleMultiplier,this.drawScene())}}inGraphTile(t,e){return q1({x:t,y:e,graph:this.graph,volumesLength:this.volumes.length,firstVolumeFrameCount:this.volumes.length>0?this.volumes[0].nFrame4D??0:0})}updateBitmapFromClickToSegment(){this.clickToSegmentGrowingBitmap===null||this.drawBitmap===null||nm({sourceBitmap:this.clickToSegmentGrowingBitmap,targetBitmap:this.drawBitmap})}sumBitmap(t){return am(t)}doClickToSegment(t){const{tileIndex:e}=t;if(e<0||e>=this.screenSlices.length){F.warn(`Invalid tileIndex ${e} received in doClickToSegment.`);return}const i=this.screenSlices[e].axCorSag;if(i>2){F.warn("ClickToSegment attempted on non-2D slice tile.");return}const r=this.screenXY2TextureFrac(this.clickToSegmentXY[0],this.clickToSegmentXY[1],e,!1);if(r[0]<0){F.debug("Click location outside valid texture fraction for the tile.");return}const s=this.frac2vox(r),n=this.back.getValue(s[0],s[1],s[2]),a=rm({voxelIntensity:n,thresholdPercent:this.opts.clickToSegmentPercent,calMin:this.back.cal_min,calMax:this.back.cal_max,autoIntensity:this.opts.clickToSegmentAutoIntensity,currentIntensityMin:this.opts.clickToSegmentIntensityMin,currentIntensityMax:this.opts.clickToSegmentIntensityMax,currentBright:this.opts.clickToSegmentBright});this.opts.clickToSegmentIntensityMin=a.intensityMin,this.opts.clickToSegmentIntensityMax=a.intensityMax,this.opts.clickToSegmentBright=a.isBright;const o=sm(a.isBright);this.drawPenAxCorSag=i;const l=this.clickToSegmentIsGrowing?this.clickToSegmentGrowingBitmap:this.drawBitmap;if(!l){if(F.error("Target bitmap for flood fill is null."),this.clickToSegmentIsGrowing){if(this.drawBitmap||this.createEmptyDrawing(),!this.drawBitmap)return;this.clickToSegmentGrowingBitmap=this.drawBitmap.slice()}else if(this.createEmptyDrawing(),!this.drawBitmap)return;F.warn("Initialized missing bitmap in doClickToSegment.")}if(this.drawFloodFill([s[0],s[1],s[2]],this.opts.penValue,o,this.opts.clickToSegmentIntensityMin,this.opts.clickToSegmentIntensityMax,this.opts.floodFillNeighbors,this.opts.clickToSegmentMaxDistanceMM,this.opts.clickToSegmentIs2D,l),!this.clickToSegmentIsGrowing&&(F.debug("Applying clickToSegment mask to drawBitmap."),this.drawBitmap?(this.refreshDrawing(!1,!1),this.drawScene()):F.error("Cannot refresh drawing after click-to-segment apply, drawBitmap is null."),this.drawBitmap)){const c=this.getDescriptives({layer:0,masks:[],drawingIsMask:!0}),h={mL:c.volumeML,mm3:c.volumeMM3};this._emitEvent("clickToSegment",h),this.onClickToSegment(h)}this.createOnLocationChange(i)}mouseClick(t,e,i=0,r=!0){if(t*=this.uiData.dpr,e*=this.uiData.dpr,this.canvas.focus(),this.thumbnailVisible)return this.thumbnailVisible=!1,Promise.all([this.loadVolumes(this.deferredVolumes),this.loadMeshes(this.deferredMeshes)]).catch(s=>{throw s}),!0;if(this.inGraphTile(t,e)){if(!this.graph.plotLTWH)throw new Error("plotLTWH undefined");const s=[(t-this.graph.plotLTWH[0])/this.graph.plotLTWH[2],(e-this.graph.plotLTWH[1])/this.graph.plotLTWH[3]];if(s[0]>0&&s[1]>0&&s[0]<=1&&s[1]<=1){const n=Math.round(s[0]*(this.volumes[0].nFrame4D-1));return this.setFrame4D(this.volumes[0].id,n),!0}return s[0]>.5&&s[1]>1&&this.loadDeferred4DVolumes(this.volumes[0].id).catch(n=>{throw n}),!1}if(this.inRenderTile(t,e)>=0)return i===0?!1:(this.sliceScroll3D(i),this.drawScene(),!0);if(this.screenSlices.length<1||this.gl.canvas.height<1||this.gl.canvas.width<1)return!1;for(let s=0;s<this.screenSlices.length;s++){const n=this.screenSlices[s].axCorSag;if(this.drawPenAxCorSag>=0&&this.drawPenAxCorSag!==n||n>2&&!this.opts.clickToSegment&&i===0)continue;const a=this.screenXY2TextureFrac(t,e,s,!0);if(a[0]<0)continue;if(i!==0||!r){if(!r)return n<=2&&(this.scene.crosshairPos[2-n]=i,this.drawScene(),this.createOnLocationChange(n)),!0;const c=i<0?-1:1,h=[0,0,0];return n<=2&&(h[2-n]=c,this.moveCrosshairInVox(h[0],h[1],h[2])),!0}const o=this.opts.isForceMouseClickToVoxelCenters?this.vox2frac(this.frac2vox(a)):a;if(!!Ua(this.scene.crosshairPos,o)&&!this.opts.drawingEnabled)return!1;if(this.scene.crosshairPos=Ve(o),this.opts.drawingEnabled){const c=this.frac2vox(this.scene.crosshairPos);if(!isFinite(this.opts.penValue)||this.opts.penValue<0||Object.is(this.opts.penValue,-0)){let h=0,d=Math.abs(this.opts.penValue);const f=!0;return Object.is(this.opts.penValue,-0)?(h=0,d=0,F.debug("Erase Cluster selected")):(h=this.opts.penValue,F.debug("Intensity Grow selected",h)),this.drawFloodFill(c,d,h,NaN,NaN,this.opts.floodFillNeighbors,Number.POSITIVE_INFINITY,!1,this.drawBitmap,f),this.drawScene(),this.createOnLocationChange(n),!0}else{if(this.opts.clickToSegment)return n<=2&&(this.clickToSegmentIsGrowing=!1,this.doClickToSegment({x:this.clickToSegmentXY[0],y:this.clickToSegmentXY[1],tileIndex:s})),this.createOnLocationChange(n),!0;if(this.opts.penType===0){if(isNaN(this.drawPenLocation[0]))this.drawPenAxCorSag=n,this.drawPenFillPts=[],this.drawPt(...c,this.opts.penValue);else{if(c[0]===this.drawPenLocation[0]&&c[1]===this.drawPenLocation[1]&&c[2]===this.drawPenLocation[2])return this.drawScene(),this.createOnLocationChange(n),!0;this.drawPenLine(c,this.drawPenLocation,this.opts.penValue)}this.drawPenLocation=c,this.opts.isFilledPen&&this.drawPenFillPts.push(c),this.refreshDrawing(!1,!1)}else(this.opts.penType===1||this.opts.penType===2)&&(isNaN(this.drawShapeStartLocation[0])?(this.drawPenAxCorSag=n,this.drawShapeStartLocation=[...c],this.drawBitmap&&(this.drawShapePreviewBitmap=this.drawBitmap.slice())):this.drawShapePreviewBitmap&&this.drawBitmap&&(this.drawBitmap.set(this.drawShapePreviewBitmap),this.opts.penType===1?this.drawRectangleMask(this.drawShapeStartLocation,c,this.opts.penValue):this.opts.penType===2&&this.drawEllipseMask(this.drawShapeStartLocation,c,this.opts.penValue),this.refreshDrawing(!1,!1)))}}return this.drawScene(),this.createOnLocationChange(n),!0}return!1}drawRuler(){let t=[],e=[];for(let c=0;c<this.screenSlices.length;c++)if(this.screenSlices[c].axCorSag!==4&&this.screenSlices[c].fovMM.length>1){e=this.screenSlices[c].leftTopWidthHeight,t=this.screenSlices[c].fovMM;break}if(e.length<4)return;const[i,r,s,n]=this.getBoundsRegion(),a=Number(this.opts.rulerWidth),o=Tu({fovMM:t,ltwh:e,rulerWidth:a,regionBounds:{x:i,y:r,w:s,h:n}});if(!o)return;const l=Su(this.opts.rulerColor);this.drawRuler10cm(o.startXYendXY,l,a+1),this.drawRuler10cm(o.startXYendXY,this.opts.rulerColor,a)}drawRuler10cm(t,e,i=1){if(!this.lineShader)throw new Error("lineShader undefined");this.gl.bindVertexArray(this.genericVAO),this.lineShader.use(this.gl),this.gl.uniform4fv(this.lineShader.uniforms.lineColor,e),this.gl.uniform2fv(this.lineShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.uniform1f(this.lineShader.uniforms.thickness,i),this.gl.uniform4fv(this.lineShader.uniforms.startXYendXY,t),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4);const r=Eu(t,this.opts.rulerWidth);for(const s of r)this.gl.uniform4fv(this.lineShader.uniforms.startXYendXY,s),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4);this.gl.bindVertexArray(this.unusedVAO)}screenXY2mm(t,e,i=-1){return B0(t,e,this.screenSlices,{volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D,isSliceMM:this.opts.isSliceMM,forceSlice:i})}dragForPanZoom(t){const i=this.getZarrVolumes().filter(a=>a.zarrHelper?.centerAtDragStart);if(i.length>0){const a=t[2]-t[0],o=t[3]-t[1];if(a===0&&o===0)return;let l=0;for(const f of this.screenSlices){if(f.axCorSag>2)continue;const u=f.leftTopWidthHeight,m=t[0],p=t[1];if(m>=u[0]&&p>=u[1]&&m<=u[0]+u[2]&&p<=u[1]+u[3]){l=f.axCorSag;break}}let c,h;l===0?(c=0,h=1):l===1?(c=0,h=2):(c=1,h=2);const d=[];for(const f of i){const u=f.zarrHelper,m=f.hdr.affine,p=[{col:0,sign:-1},{col:1,sign:-1},{col:2,sign:-1}];for(let T=0;T<3;T++){let E=0;for(let I=0;I<3;I++){const S=Math.abs(m[T][I]);S>E&&(E=S,p[T]={col:I,sign:m[T][I]<0?-1:1})}}const g=u.centerAtDragStart,x=[g.x,g.y,g.z];x[p[c].col]+=a*p[c].sign,x[p[h].col]+=-o*p[h].sign;const A=x[0],y=x[1],v=x[2],b=u.getViewportState(),w=Math.abs(A-b.centerX),C=Math.abs(y-b.centerY),M=Math.abs(v-b.centerZ);w<.001&&C<.001&&M<.001||d.push(u.panTo(A,y,v))}d.length>0&&Promise.all(d).then(()=>{this._skipDragInDraw=!0,this.drawScene(),this._skipDragInDraw=!1}).catch(f=>{F.error("Failed to pan Zarr:",f)}),this.canvas.focus();return}const r=this.screenXY2mm(t[2],t[3]);if(isNaN(r[0]))return;const s=this.screenXY2mm(t[0],t[1],r[3]);if(isNaN(s[0])||isNaN(r[0])||isNaN(r[3]))return;const n=U1({startMM:s,endMM:r,pan2DxyzmmAtMouseDown:this.uiData.pan2DxyzmmAtMouseDown});this.scene.pan2Dxyzmm[0]=n.pan2Dxyzmm[0],this.scene.pan2Dxyzmm[1]=n.pan2Dxyzmm[1],this.scene.pan2Dxyzmm[2]=n.pan2Dxyzmm[2],this.canvas.focus()}dragForCenterButton(t){this.dragForPanZoom(t)}dragForSlicer3D(t){const e=this.frac2mm(this.scene.crosshairPos),i=R1({startY:t[1],endY:t[3],pan2DxyzmmAtMouseDown:this.uiData.pan2DxyzmmAtMouseDown,currentPan2Dxyzmm:this.scene.pan2Dxyzmm,crosshairMM:e,yoke3Dto2DZoom:this.opts.yoke3Dto2DZoom});i.volScaleMultiplier!==void 0&&(this.scene.volScaleMultiplier=i.volScaleMultiplier),this.scene.pan2Dxyzmm[0]=i.pan2Dxyzmm[0],this.scene.pan2Dxyzmm[1]=i.pan2Dxyzmm[1],this.scene.pan2Dxyzmm[2]=i.pan2Dxyzmm[2],this.scene.pan2Dxyzmm[3]=i.pan2Dxyzmm[3]}drawMeasurementTool(t,e=!0){const i=(c,h,d,f,u)=>Iu({startXYendXY:[c,h,d,f],distance:u}),r=this.gl;if(r.viewport(0,0,r.canvas.width,r.canvas.height),r.bindVertexArray(this.genericVAO),r.depthFunc(r.ALWAYS),r.enable(r.BLEND),r.blendFunc(r.SRC_ALPHA,r.ONE_MINUS_SRC_ALPHA),!this.lineShader)throw new Error("lineShader undefined");this.lineShader.use(this.gl),r.uniform4fv(this.lineShader.uniforms.lineColor,this.opts.rulerColor),r.uniform2fv(this.lineShader.uniforms.canvasWidthHeight,[r.canvas.width,r.canvas.height]),r.uniform1f(this.lineShader.uniforms.thickness,this.opts.rulerWidth),r.uniform4fv(this.lineShader.uniforms.startXYendXY,t),r.drawArrays(r.TRIANGLE_STRIP,0,4);const s=this.opts.measureLineColor;s[3]=1,r.uniform4fv(this.lineShader.uniforms.lineColor,s);const n=this.opts.rulerWidth;r.uniform1f(this.lineShader.uniforms.thickness,n*2);let a=[t[0],t[1]-n,t[0],t[1]+n];r.uniform4fv(this.lineShader.uniforms.startXYendXY,a),r.drawArrays(r.TRIANGLE_STRIP,0,4),a=[t[2],t[3]-n,t[2],t[3]+n],r.uniform4fv(this.lineShader.uniforms.startXYendXY,a),r.drawArrays(r.TRIANGLE_STRIP,0,4);let o=this.canvasPos2frac([t[0],t[1]]),l=this.canvasPos2frac([t[2],t[3]]);if(o[0]>=0&&l[0]>=0){const c=this.frac2mm(o);o=k(c[0],c[1],c[2]);const h=this.frac2mm(l);l=k(h[0],h[1],h[2]);const d=se();Qr(d,o,l);const f=Vt(d);let u=2;f>9&&(u=1),f>99&&(u=0);let m=f.toFixed(u);this.opts.showMeasureUnits&&(m=`${m} mm`);let p=t;const[g,x,A,y]=t,{origin:v,terminus:b}=i(g,x,A,y,30);switch(this.opts.measureTextJustify){case"start":p=[...v,...v.map(w=>w+1)];break;case"end":p=p=[...b,...b.map(w=>w+1)];break;default:p=t;break}e&&this.drawTextBetween(p,m,this.opts.measureTextHeight/.06,this.opts.measureTextColor)}r.bindVertexArray(this.unusedVAO)}drawAngleMeasurementTool(){this.uiData.angleState==="drawing_first_line"?this.drawMeasurementTool([this.uiData.dragStart[0],this.uiData.dragStart[1],this.uiData.dragEnd[0],this.uiData.dragEnd[1]],!1):this.uiData.angleState==="drawing_second_line"&&(this.drawMeasurementTool(this.uiData.angleFirstLine,!1),this.drawMeasurementTool([this.uiData.angleFirstLine[2],this.uiData.angleFirstLine[3],this.uiData.dragEnd[0],this.uiData.dragEnd[1]],!1),this.drawAngleText())}drawAngleText(){const t=this.uiData.angleFirstLine,e=[this.uiData.angleFirstLine[2],this.uiData.angleFirstLine[3],this.uiData.dragEnd[0],this.uiData.dragEnd[1]],i=this.calculateAngleBetweenLines(t,e),r=this.uiData.angleFirstLine[2],s=this.uiData.angleFirstLine[3],n=`${i.toFixed(1)}°`;this.drawTextBetween([r,s,r+1,s+1],n,this.opts.measureTextHeight/.06,this.opts.measureTextColor)}drawAngleTextForAngle(t){const e=this.calculateAngleBetweenLines(t.firstLine,t.secondLine),i=t.firstLine[2],r=t.firstLine[3],s=`${e.toFixed(1)}°`;this.drawTextBetween([i,r,i+1,r+1],s,this.opts.measureTextHeight/.06,this.opts.measureTextColor)}calculateAngleBetweenLines(t,e){return F1(t,e)}resetAngleMeasurement(){const t=B1();this.uiData.angleState=t.angleState,this.uiData.angleFirstLine=t.angleFirstLine}getCurrentSliceInfo(){return Z1({dragStart:this.uiData.dragStart,screenSlices:this.screenSlices,crosshairPos:this.scene.crosshairPos,currentSliceType:this.opts.sliceType,canvasPos2frac:t=>this.canvasPos2frac(t)})}getCurrentSlicePosition(t){return gi({sliceType:t,crosshairPos:this.scene.crosshairPos})}shouldDrawOnCurrentSlice(t,e,i){return j1({sliceType:e,slicePosition:i,currentSliceTypeOpt:this.opts.sliceType,screenSlices:this.screenSlices,crosshairPos:this.scene.crosshairPos})}clearMeasurements(){this.document.completedMeasurements=[],this.drawScene()}clearAngles(){this.document.completedAngles=[],this.drawScene()}clearAllMeasurements(){this.document.completedMeasurements=[],this.document.completedAngles=[],this.drawScene()}setDragMode(t){const e=D1(t);if(e===null){console.warn(`Unknown drag mode: ${t}`);return}this.opts.dragMode=e,L1(this.opts.dragMode)||this.resetAngleMeasurement(),this.clearActiveDragMode()}setMouseEventConfig(t){this.opts.mouseEventConfig=t,this.clearActiveDragMode()}setTouchEventConfig(t){this.opts.touchEventConfig=t,this.clearActiveDragMode()}getMouseEventConfig(){return this.opts.mouseEventConfig}getTouchEventConfig(){return this.opts.touchEventConfig}drawRect(t,e=[1,0,0,-1]){if(e[3]<0&&(e=this.opts.crosshairColor),!this.rectShader)throw new Error("rectShader undefined");this.gl.disable(this.gl.CULL_FACE),this.opts.selectionBoxIsOutline?(this.drawCircle(t,e,.1),this.rectOutlineShader.use(this.gl),this.gl.enable(this.gl.BLEND),this.gl.uniform1f(this.rectOutlineShader.uniforms.thickness,this.opts.selectionBoxLineThickness),this.gl.uniform4fv(this.rectOutlineShader.uniforms.lineColor,e),this.gl.uniform2fv(this.rectOutlineShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.uniform4f(this.rectOutlineShader.uniforms.leftTopWidthHeight,t[0],t[1],t[2],t[3]),this.gl.bindVertexArray(this.genericVAO),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),this.gl.bindVertexArray(this.unusedVAO)):(this.rectShader.use(this.gl),this.gl.enable(this.gl.BLEND),this.gl.uniform4fv(this.rectShader.uniforms.lineColor,e),this.gl.uniform2fv(this.rectShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.uniform4f(this.rectShader.uniforms.leftTopWidthHeight,t[0],t[1],t[2],t[3]),this.gl.bindVertexArray(this.genericVAO),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),this.gl.bindVertexArray(this.unusedVAO))}getZarrVolume(){for(const t of this.volumes)if(t.zarrHelper)return t;return null}getZarrVolumes(){return this.volumes.filter(t=>t.zarrHelper)}drawBoundsBox(t,e,i=2){if(!this.rectOutlineShader)throw new Error("rectOutlineShader undefined");const r=this.gl,[s,n,a,o]=t;r.viewport(0,0,r.canvas.width,r.canvas.height),this.rectOutlineShader.use(r),r.enable(r.BLEND),r.uniform1f(this.rectOutlineShader.uniforms.thickness,i),r.uniform4fv(this.rectOutlineShader.uniforms.lineColor,e),r.uniform2fv(this.rectOutlineShader.uniforms.canvasWidthHeight,[r.canvas.width,r.canvas.height]),r.uniform4f(this.rectOutlineShader.uniforms.leftTopWidthHeight,s,n,a,o),r.bindVertexArray(this.genericVAO),r.drawArrays(r.TRIANGLE_STRIP,0,4),r.bindVertexArray(this.unusedVAO)}drawCircle(t,e=this.opts.fontColor,i=1){if(!this.circleShader)throw new Error("circleShader undefined");this.circleShader.use(this.gl),this.gl.enable(this.gl.BLEND),this.gl.uniform4fv(this.circleShader.uniforms.circleColor,e),this.gl.uniform2fv(this.circleShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.uniform4f(this.circleShader.uniforms.leftTopWidthHeight,t[0],t[1],t[2],t[3]),this.gl.uniform1f(this.circleShader.uniforms.fillPercent,i),this.gl.uniform4fv(this.circleShader.uniforms.circleColor,e),this.gl.bindVertexArray(this.genericVAO),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),this.gl.bindVertexArray(this.unusedVAO)}drawSelectionBox(t){if(this.gl.viewport(0,0,this.gl.canvas.width,this.gl.canvas.height),this.getCurrentDragMode()===6){this.drawCircle(t,this.opts.selectionBoxColor,.1);return}this.drawRect(t,this.opts.selectionBoxColor)}effectiveCanvasHeight(){return n2({canvasHeight:this.gl.canvas.height,bounds:this.opts.bounds,colorbarHeight:this.colorbarHeight})}effectiveCanvasWidth(){return a2({canvasWidth:this.gl.canvas.width,bounds:this.opts.bounds,legendPanelWidth:this.getLegendPanelWidth()})}getAllLabels(){return Wf({meshes:this.meshes,documentLabels:this.document.labels})}getConnectomeLabels(){return Kf({meshes:this.meshes,documentLabels:this.document.labels})}getBulletMarginWidth(){const t=this.getConnectomeLabels();return c2({labels:t,fontPx:this.fontPx,textHeight:(e,i)=>this.textHeight(e,i)})}getLegendPanelWidth(){const t=this.getConnectomeLabels();return h2({labels:t,showLegend:this.opts.showLegend,fontPx:this.fontPx,canvasWidth:this.gl.canvas.width,textWidth:(e,i)=>this.textWidth(e,i),getBulletMarginWidth:()=>this.getBulletMarginWidth()})}getLegendPanelHeight(t=1){const e=this.getConnectomeLabels();return d2({labels:e,fontPx:this.fontPx,panelScale:t,textHeight:(i,r)=>this.textHeight(i,r)})}reserveColorbarPanel(){const t=f2({fontPx:this.fontPx,boundsRegion:this.getBoundsRegion(),colorbarWidth:this.opts.colorbarWidth});return this.colorbarHeight=t.colorbarHeight,t.leftTopWidthHeight}drawColorbarCore(t=0,e=[0,0,0,0],i=!1,r=0,s=1,n){if(e[2]<=0||e[3]<=0)return;const a=this.fontPx;if(a<=0)return;this.gl.viewport(0,0,this.gl.canvas.width,this.gl.canvas.height);let o=a;const l=3*a;let c=a;if(e[3]<l){if(e[3]<3)return;o=1,c=e[3]-2}this.gl.disable(this.gl.DEPTH_TEST),this.colorbarHeight=e[3]+1;const h=[e[0]+o,e[1],e[2]-2*o,c],d=[h[0]-1,h[1]-1,h[2]+2,h[3]+2];if(this.opts.showColorbarBorder&&this.drawRect(d,this.opts.crosshairColor),!this.colorbarShader)throw new Error("colorbarShader undefined");this.colorbarShader.use(this.gl),this.gl.activeTexture($.TEXTURE1_COLORMAPS),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colormapTexture),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.NEAREST);const f=t;if(this.gl.uniform1f(this.colorbarShader.uniforms.layer,f),this.gl.uniform2fv(this.colorbarShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.disable(this.gl.CULL_FACE),i){const w=[h[0]+h[2],h[1],-h[2],h[3]];this.gl.uniform4fv(this.colorbarShader.uniforms.leftTopWidthHeight,w)}else this.gl.uniform4fv(this.colorbarShader.uniforms.leftTopWidthHeight,h);this.gl.bindVertexArray(this.genericVAO),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),this.gl.bindVertexArray(this.unusedVAO),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR);let u=0;if(n&&s<0&&i?(u=s,s=0):n&&r>0&&(u=r,r=0),r===s||a<1)return;const m=Math.abs(s-r);let[p,g]=ys(r,s);g<r&&(g+=p);function x(w){return w.toFixed(6).replace(/\.?0*$/,"")}let A=g;const y=[0,h[1]+h[3]-a*.5,2,a*.75],v=y[1]+y[3],b=1;for(;A<=s;){y[0]=h[0]+(A-r)/m*h[2],this.drawRect(y);const w=x(b*A);this.drawTextBelow([y[0],v],w),A+=p}if(u!==0){const w=[h[0]+(u-r)/m*h[2],h[1]-h[3]*.25,2,h[3]*1.5];this.drawRect(w)}}drawColorbar(){const t=this.colormapLists,e=t.length;if(e<1)return;let i=0;for(let a=0;a<e;a++)t[a].visible&&i++;if(i<1)return;let r=this.reserveColorbarPanel();const s=3*this.fontPx;if(s<0)return;let n=r[2]/i;(r[2]<=0||r[3]<=0)&&(n=this.gl.canvas.width/i,r=[0,this.gl.canvas.height-s,n,s]),r[2]=n;for(let a=0;a<e;a++)t[a].visible&&(this.drawColorbarCore(a,r,t[a].negative,t[a].min,t[a].max,t[a].isColorbarFromZero),r[0]+=n)}textWidth(t,e){return wu({fontMets:this.fontMets,scale:t,str:e})}textHeight(t,e){return yu({fontMets:this.fontMets,scale:t,str:e})}drawChar(t,e,i){if(!this.fontShader)throw new Error("fontShader undefined");const r=this.fontMets.mets[i];if(r){const s=t[0]+e*r.lbwh[0],n=-(e*r.lbwh[1]),a=e*r.lbwh[2],o=e*r.lbwh[3],l=t[1]+(n-o)+e;return this.gl.uniform4f(this.fontShader.uniforms.leftTopWidthHeight,s,l,a,o),this.gl.uniform4fv(this.fontShader.uniforms.uvLeftTopWidthHeight,r.uv_lbwh),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),e*r.xadv}else return console.warn(`drawChar() : Missing font metric for char : "${i}"`),0}drawLoadingText(t){if(!t)return;if(!this.canvas)throw new Error("canvas undefined");const[e,i,r,s]=this.getBoundsRegion();this.gl.viewport(e,i,r,s),this.gl.enable(this.gl.CULL_FACE),this.gl.enable(this.gl.BLEND);const n=e+r/2,a=i+s/2;this.drawTextBelow([n,a],t,3)}drawText(t,e,i=1,r=null){if(this.fontPx<=0)return;if(!this.fontShader)throw new Error("fontShader undefined");this.fontShader.use(this.gl);const s=this.fontPx*i;this.gl.enable(this.gl.BLEND),this.gl.uniform2f(this.fontShader.uniforms.canvasWidthHeight,this.gl.canvas.width,this.gl.canvas.height),r===null&&(r=this.opts.fontColor),this.gl.uniform4fv(this.fontShader.uniforms.fontColor,r);let n=s/this.fontMets.size*this.fontMets.distanceRange;n=Math.max(n,1),this.gl.uniform1f(this.fontShader.uniforms.screenPxRange,n),this.gl.bindVertexArray(this.genericVAO);for(const a of e){const o=a.codePointAt(0);t[0]+=this.drawChar(t,s,o)}this.gl.bindVertexArray(this.unusedVAO)}drawTextRight(t,e,i=1,r=null){this.fontPx<=0||(t[1]-=.5*this.fontPx,this.drawText(t,e,i,r))}drawTextLeft(t,e,i=1,r=null){if(this.fontPx<=0)return;const s=this.fontPx*i;t[0]-=this.textWidth(s,e),t[1]-=.5*s,this.drawText(t,e,i,r)}drawTextRightBelow(t,e,i=1,r=null){this.fontPx<=0||this.drawText(t,e,i,r)}drawTextBetween(t,e,i=1,r=null){if(this.fontPx<=0)return;const s=Mu(t,e,this.fontPx,i,(a,o)=>this.textWidth(a,o)),n=Du(r,this.opts.crosshairColor);this.drawRect(s.rectLTWH,n),this.drawText([s.textX,s.textY],e,i,r)}drawTextBelow(t,e,i=1,r=null){if(this.fontPx<=0)return;if(!this.canvas)throw new Error("canvas undefined");const s=bu({xy:t,str:e,fontPx:this.fontPx,scale:i,canvasWidth:this.canvas.width},(n,a)=>this.textWidth(n,a));this.drawText([s.x,s.y],e,s.scale,r)}drawTextAbove(t,e,i=1,r=null){if(this.fontPx<=0)return;if(!this.canvas)throw new Error("canvas undefined");const s=Cu({xy:t,str:e,fontPx:this.fontPx,scale:i,canvasWidth:this.canvas.width},(n,a)=>this.textWidth(n,a));this.drawText([s.x,s.y],e,s.scale,r)}updateInterpolation(t,e=!1){_f({gl:this.gl,layer:t,isForceLinear:e,isNearestInterpolation:this.opts.isNearestInterpolation,is2DSliceShader:this.opts.is2DSliceShader})}setAtlasOutline(t){this.opts.atlasOutline=t,this.updateGLVolume(),this.drawScene()}setInterpolation(t){this.opts.isNearestInterpolation=t;const e=this.volumes.length;if(!(e<1)){for(let i=0;i<e;i++)this.updateInterpolation(i);this.drawScene()}}getNearestInterpolation(){return this.opts.isNearestInterpolation}calculateMvpMatrix2D(t,e,i,r=1/0,s=0,n=0,a=0,o=!1){this.gl.viewport(t[0],this.gl.canvas.height-(t[1]+t[3]),t[2],t[3]);let c=e[0],h=i[0],d=[c,e[1]],f=[h-c,i[1]-e[1]];o&&(d=[i[0],e[1]],f=[e[0]-i[0],i[1]-e[1]],c=-i[0],h=-e[0]);const u=2*Math.max(Math.abs(e[2]),Math.abs(i[2])),m=J();let p=.01,g=u*8;if(r!==1/0){let w=o;a===0&&(n===0||n===180)&&(w=!w);let C=u*1.8-s;w||(C=u*1.8+s),g=C-r,p=C+r}hi(m,c,h,e[1],i[1],g,p);const x=J();x[0]=-1;const A=k(0,0,-u*1.8);tt(x,x,A),Ut(x,x,qe(270-a)),Rt(x,x,qe(n-180));const y=J();Se(y,x);const v=J();Te(v,y);const b=J();return Ye(b,m,x),{modelViewProjectionMatrix:b,modelMatrix:x,normalMatrix:v,leftTopMM:d,fovMM:f}}swizzleVec3MM(t,e){return F0(t,e)}screenFieldOfViewVox(t=0){const e=Ve(this.volumeObject3D.fieldOfViewDeObliqueMM);return this.swizzleVec3MM(e,t)}screenFieldOfViewMM(t=0,e=!1){if(this.volumes.length<1){let o=k(this.extentsMin[0],this.extentsMin[1],this.extentsMin[2]),l=k(this.extentsMax[0],this.extentsMax[1],this.extentsMax[2]);o=this.swizzleVec3MM(o,t),l=this.swizzleVec3MM(l,t);const c=se();return ne(c,l,o),c}if(!e&&!this.opts.isSliceMM)return this.screenFieldOfViewVox(t);const i=this.volumeObject3D.extentsMin,r=this.volumeObject3D.extentsMax;let s=k(i[0],i[1],i[2]),n=k(r[0],r[1],r[2]);s=this.swizzleVec3MM(s,t),n=this.swizzleVec3MM(n,t);const a=se();return ne(a,n,s),a}screenFieldOfViewExtendedVox(t=0){const e=this.volumes[0].extentsMinOrtho,i=this.volumes[0].extentsMaxOrtho;let r=k(e[0],e[1],e[2]),s=k(i[0],i[1],i[2]);const n=J();r=this.swizzleVec3MM(r,t),s=this.swizzleVec3MM(s,t);const a=se();return ne(a,s,r),{mnMM:r,mxMM:s,rotation:n,fovMM:a}}screenFieldOfViewExtendedMM(t=0){if(this.volumes.length<1){let o=k(this.extentsMin[0],this.extentsMin[1],this.extentsMin[2]),l=k(this.extentsMax[0],this.extentsMax[1],this.extentsMax[2]);const c=J();o=this.swizzleVec3MM(o,t),l=this.swizzleVec3MM(l,t);const h=se();return ne(h,l,o),{mnMM:o,mxMM:l,rotation:c,fovMM:h}}if(!this.volumeObject3D)throw new Error("volumeObject3D undefined");const e=this.volumeObject3D.extentsMin,i=this.volumeObject3D.extentsMax;let r=k(e[0],e[1],e[2]),s=k(i[0],i[1],i[2]);const n=J();r=this.swizzleVec3MM(r,t),s=this.swizzleVec3MM(s,t);const a=se();return ne(a,s,r),{mnMM:r,mxMM:s,rotation:n,fovMM:a}}drawSliceOrientationText(t,e,i=[NaN,NaN]){this.gl.viewport(0,0,this.gl.canvas.width,this.gl.canvas.height);let r="S";e===0&&(r="A");let s=this.opts.isRadiologicalConvention?"R":"L";e===2&&(s=this.opts.sagittalNoseLeft?"A":"P");let n="I";e===0&&(n="P");let a=this.opts.isRadiologicalConvention?"L":"R";if(e===2&&(a=this.opts.sagittalNoseLeft?"P":"A"),this.opts.isCornerOrientationText){this.drawTextRightBelow([t[0],t[1]],s+r);return}let o=!0,l=!0;const c=this.opts.showAllOrientationMarkers,h=this.opts.showAllOrientationMarkers;if(!isNaN(i[0])){const d=this.fontPx+2;i[1]>d&&(this.drawTextBelow([t[0]+t[2]*.5,t[1]+i[1]-d],r),o=!1);const f=this.textWidth(d,s)+2;i[0]>f&&(this.drawTextRight([t[0]+i[0]-f,t[1]+t[3]*.5],s),l=!1)}o&&this.drawTextBelow([t[0]+t[2]*.5,t[1]],r),l&&this.drawTextRight([t[0],t[1]+t[3]*.5],s),c&&this.drawTextAbove([t[0]+t[2]*.5,t[1]+t[3]],n),h&&this.drawTextLeft([t[0]+t[2],t[1]+t[3]*.5],a)}xyMM2xyzMM(t,e){return l2({axCorSag:t,sliceFrac:e,frac2mm:i=>this.frac2mm(i),swizzleVec3MM:(i,r)=>this.swizzleVec3MM(i,r)})}draw2DMain(t,e,i=NaN){let r=new Float32Array([0,0,0]);this.volumes.length>0&&(r=new Float32Array(this.volumes[0].frac2mm.slice()));let s=this.screenFieldOfViewExtendedMM(e),n=J();!this.opts.isSliceMM&&this.volumes.length>0&&(r=new Float32Array(this.volumes[0].frac2mmOrtho.slice()),n=de(this.volumes[0].mm2ortho),s=this.screenFieldOfViewExtendedVox(e));let a=this.opts.isRadiologicalConvention&&e<2;i===1/0||i===-1/0?(a=i!==1/0,e===1&&(a=!a)):this.opts.sagittalNoseLeft&&e===2&&(a=!a);let o=0,l=0;e===2?l=a?90:-90:e===1?l=a?180:0:(l=a?180:0,o=a?-90:90);const c=this.gl;let h=!1;if(t[2]===0||t[3]===0){h=!0;const A=c.canvas.width/s.fovMM[0],y=c.canvas.height/s.fovMM[1],v=Math.min(A,y),b=A/v,w=y/v;s.fovMM[0]*=b,s.fovMM[1]*=w;let C=(s.mnMM[0]+s.mxMM[0])*.5;s.mnMM[0]=C-s.fovMM[0]*.5,s.mxMM[0]=C+s.fovMM[0]*.5,C=(s.mnMM[1]+s.mxMM[1])*.5,s.mnMM[1]=C-s.fovMM[1]*.5,s.mxMM[1]=C+s.fovMM[1]*.5,t=[0,0,c.canvas.width,c.canvas.height]}if(isNaN(i)){const A=this.scene.pan2Dxyzmm,y=this.swizzleVec3MM(k(A[0],A[1],A[2]),e),v=this.scene.pan2Dxyzmm[3];s.mnMM[0]-=y[0],s.mxMM[0]-=y[0],s.mnMM[1]-=y[1],s.mxMM[1]-=y[1],s.mnMM[0]/=v,s.mxMM[0]/=v,s.mnMM[1]/=v,s.mxMM[1]/=v}let d=2;e===1&&(d=1),e===2&&(d=0);let f=this.scene.crosshairPos[d],u=this.frac2mm(this.scene.crosshairPos);!isNaN(i)&&i!==1/0&&i!==-1/0&&(u=this.frac2mm([.5,.5,.5]),u[d]=i,f=this.mm2frac(u)[d]);const m=u[d],p=c.canvas.height-t[1]-t[3],g=[t[0],p,t[2],t[3]];this.clearBounds(c.DEPTH_BUFFER_BIT,g),c.viewport(g[0],g[1],g[2],g[3]);let x=this.calculateMvpMatrix2D(t,s.mnMM,s.mxMM,1/0,0,l,o,a);if(i===1/0||i===-1/0){const A=t.slice();this.draw3D(t,x.modelViewProjectionMatrix,x.modelMatrix,x.normalMatrix,l,o);const y=this.screenSlices[this.screenSlices.length-1];y.leftTopWidthHeight=A,y.axCorSag=e,y.sliceFrac=1/0,y.AxyzMxy=this.xyMM2xyzMM(e,f),y.leftTopMM=x.leftTopMM,y.fovMM=x.fovMM;return}if(c.enable(c.DEPTH_TEST),c.blendFunc(c.SRC_ALPHA,c.ONE_MINUS_SRC_ALPHA),c.disable(c.BLEND),c.depthFunc(c.ALWAYS),c.disable(c.CULL_FACE),this.volumes.length>0){let A=this.sliceMMShader;if(this.opts.is2DSliceShader&&(A=this.slice2DShader),this.opts.isV1SliceShader&&(A=this.sliceV1Shader),this.customSliceShader&&(A=this.customSliceShader),!A)throw new Error("slice Shader undefined");A.use(this.gl),c.uniform1f(A.uniforms.overlayOutlineWidth,this.overlayOutlineWidth),c.uniform1f(A.uniforms.overlayAlphaShader,this.overlayAlphaShader),c.uniform1i(A.uniforms.isAlphaClipDark,this.isAlphaClipDark?1:0),c.uniform1i(A.uniforms.backgroundMasksOverlays,this.backgroundMasksOverlays),c.uniform1f(A.uniforms.drawOpacity,this.drawOpacity),c.uniform1f(A.uniforms.drawRimOpacity,this.drawRimOpacity),c.enable(c.BLEND),c.blendFunc(c.SRC_ALPHA,c.ONE_MINUS_SRC_ALPHA),c.uniform1f(A.uniforms.opacity,this.volumes[0].opacity),c.uniform1i(A.uniforms.axCorSag,e),c.uniform1f(A.uniforms.slice,f),c.uniformMatrix4fv(A.uniforms.frac2mm,!1,r),c.uniformMatrix4fv(A.uniforms.mvpMtx,!1,x.modelViewProjectionMatrix.slice()),c.bindVertexArray(this.genericVAO),c.drawArrays(c.TRIANGLE_STRIP,0,4),c.bindVertexArray(this.unusedVAO),this.screenSlices.push({leftTopWidthHeight:t,axCorSag:e,sliceFrac:f,AxyzMxy:this.xyMM2xyzMM(e,f),leftTopMM:x.leftTopMM,screen2frac:[],fovMM:x.fovMM})}if(c.depthMask(!0),c.depthFunc(c.LEQUAL),isNaN(i)&&this.drawCrosshairs3D(!0,1,x.modelViewProjectionMatrix,!0,this.opts.isSliceMM),this.opts.meshThicknessOn2D>0){this.opts.meshThicknessOn2D!==1/0&&(x=this.calculateMvpMatrix2D(t,s.mnMM,s.mxMM,this.opts.meshThicknessOn2D,m,l,o,a));const A=de(x.modelViewProjectionMatrix);Ye(A,A,n),this.drawMesh3D(!0,1,A,x.modelMatrix,x.normalMatrix,!0)}isNaN(i)&&this.drawCrosshairs3D(!1,.15,x.modelViewProjectionMatrix,!0,this.opts.isSliceMM),h&&this.opts.isOrientationTextVisible&&this.drawSliceOrientationText(t,e),this.readyForSync=!0}draw2D(t,e,i=NaN,r=[NaN,NaN]){const[s,n,a,o]=this.getBoundsRegion();let l;t[2]===0&&t[3]===0?this.opts.bounds?l=[s,n,a,o]:l=[0,0,this.gl.canvas.width,this.gl.canvas.height]:l=t.slice();const c=[NaN,NaN];if(r[0]===1/0){const h=this.sliceScale().volScale;let d=this.scaleSlice(h[0],h[1],[0,0],[l[2],l[3]]);e===1&&(d=this.scaleSlice(h[0],h[2],[0,0],[l[2],l[3]])),e===2&&(d=this.scaleSlice(h[1],h[2],[0,0],[l[2],l[3]])),r[0]=d[2],r[1]=d[3]}if(isNaN(r[0])){const h=t[2]===0&&t[3]===0;this.draw2DMain(h?[0,0,0,0]:l,e,i)}else{const h=[NaN,NaN];h[0]=Math.floor(.5*(l[2]-r[0])),h[1]=Math.floor(.5*(l[3]-r[1])),l[0]+=h[0],l[1]+=h[1],l[2]=r[0],l[3]=r[1],this.draw2DMain(l,e,i)}i===1/0||i===-1/0||e===4||l[2]!==0&&l[3]!==0&&this.opts.isOrientationTextVisible&&this.drawSliceOrientationText(l,e,c)}calculateMvpMatrix(t,e=[0,0,0,0],i,r){const s=Au({canvasWidth:this.gl.canvas.width,canvasHeight:this.gl.canvas.height,leftTopWidthHeight:e,azimuth:i,elevation:r,furthestFromPivot:this.furthestFromPivot,pivot3D:this.pivot3D,volScaleMultiplier:this.scene.volScaleMultiplier,position:this.position});return[s.mvpMatrix,s.modelMatrix,s.normalMatrix]}calculateModelMatrix(t,e){if(!this.back)throw new Error("back undefined");return zr({azimuth:t,elevation:e,obliqueRAS:this.back.obliqueRAS})}calculateRayDirection(t,e){return ia({azimuth:t,elevation:e,obliqueRAS:this.back?.obliqueRAS})}sceneExtentsMinMax(t=!0){return Br({volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D},t)}setPivot3D(){const[t,e]=this.sceneExtentsMinMax(),i=xu({sceneMin:t,sceneMax:e});this.pivot3D=i.pivot3D,this.furthestFromPivot=i.furthestFromPivot,this.extentsMin=i.extentsMin,this.extentsMax=i.extentsMax}getMaxVols(){return vu({volumes:this.volumes})}detectPartialllyLoaded4D(){if(this.volumes.length<1)return!1;for(let t=0;t<this.volumes.length;t++)if(this.volumes[t].nFrame4D<this.volumes[t].hdr.dims[4])return!0;return!1}drawGraph(){if(this.getMaxVols()<2)return;const t=this.graph,[e,i,r,s]=this.getBoundsRegion();let n=0;if(t.autoSizeMultiplanar&&this.opts.sliceType===3)for(let z=0;z<this.screenSlices.length;z++){const W=this.screenSlices[z].axCorSag;if(W===0&&(n=this.screenSlices[z].leftTopWidthHeight[1]),W!==2)continue;const K=this.screenSlices[z].leftTopWidthHeight.slice();K[1]===n?(t.LTWH[0]=K[0]+K[2],t.LTWH[1]=K[1]):(t.LTWH[0]=K[0],t.LTWH[1]=K[1]+K[3]),t.LTWH[2]=K[2],t.LTWH[3]=K[2]}if(t.LTWH[0]=Math.max(e,t.LTWH[0]),t.LTWH[1]=Math.max(i,t.LTWH[1]),t.LTWH[2]=Math.min(r,t.LTWH[2]),t.LTWH[3]=Math.min(s,t.LTWH[3]),t.opacity<=0||t.LTWH[2]<=5||t.LTWH[3]<=5||Math.floor(t.LTWH[0]+t.LTWH[2])>e+r||Math.floor(t.LTWH[1]+t.LTWH[3])>i+s)return;t.backColor=[.15,.15,.15,t.opacity],t.lineColor=[1,1,1,1],this.opts.backColor[0]+this.opts.backColor[1]+this.opts.backColor[2]>1.5&&(t.backColor=[.95,.95,.95,t.opacity],t.lineColor=[0,0,0,1]);const a=.2,o=.3;t.lineColor[3]=a,t.textColor=t.lineColor.slice(),t.textColor[3]=1,t.lineThickness=3,t.gridLineThickness=1,t.lineAlpha=1,t.lines=[];const l=[];if(t.vols.length<1)this.volumes[0]!=null&&l.push(0);else for(let z=0;z<t.vols.length;z++){const W=t.vols[z];this.volumes[W]==null||this.volumes[W].nFrame4D<2||l.push(W)}if(l.length<1)return;const c=this.volumes[l[0]].nFrame4D;if(this.graph.selectedColumn=this.volumes[l[0]].frame4D,c<2){F.debug("Unable to generate a graph: Selected volume is 3D not 4D");return}for(let z=0;z<l.length;z++){t.lines[z]=[];const W=this.frac2vox(this.scene.crosshairPos),K=this.volumes[l[z]];let Z=K.nFrame4D;Z=Math.min(Z,c);for(let q=0;q<Z;q++){const te=K.getValue(W[0],W[1],W[2],q);t.lines[z].push(te)}}t.lineRGB=[[.8,0,0],[0,.7,0],[0,0,.9],[.7,.7,0],[.8,0,.8],[0,.7,.7],[.6,.6,.6],[0,0,0]];let h=t.lines[0][0],d=t.lines[0][0];for(let z=0;z<t.lines.length;z++)for(let W=0;W<t.lines[z].length;W++){const K=t.lines[z][W];h=Math.min(K,h),d=Math.max(K,d)}const f=this.volumes[l[0]].cal_min,u=this.volumes[l[0]].cal_max;if(t.isRangeCalMinMax&&f<u&&isFinite(f)&&isFinite(u)&&(h=f,d=u),t.normalizeValues&&d>h){const z=d-h;for(let W=0;W<t.lines.length;W++)for(let K=0;K<t.lines[W].length;K++){const Z=t.lines[W][K];t.lines[W][K]=(Z-h)/z}h=0,d=1}h>=d&&(d=h+1),this.drawRect(t.LTWH,t.backColor);const[m,p,g]=ys(h,d),x=Math.max(0,-1*Math.floor(Math.log(m)/Math.log(10)));h=Math.min(p,h),d=Math.max(g,d);function A(z){return z.toFixed(6).replace(/\.?0*$/,"")}let y=this.fontPx*.7;const v=r/this.uiData.dpr,b=s/this.uiData.dpr,w=v*b,C=800*600;w<C?y=0:y=Math.max(y,this.opts.fontMinPx);const M=y/this.fontPx;let T=0,E=p;if(y>0)for(;E<=d;){const z=E.toFixed(x),W=this.textWidth(y,z);T=Math.max(W,T),E+=m}const I=.05,S=Math.abs(t.LTWH[2]),U=Math.abs(t.LTWH[3]),B=[t.LTWH[0]+I*S+T,t.LTWH[1]+I*U,t.LTWH[2]-T-2*I*S,t.LTWH[3]-y-2.5*I*U];this.graph.LTWH=t.LTWH,this.graph.plotLTWH=B,this.drawRect(B,this.opts.backColor);const V=d-h,R=B[3]/V,P=B[2]/(t.lines[0].length-1),L=B[1]+B[3];E=p+.5*m;const N=t.lineColor.slice();for(N[3]=.5*t.lineColor[3];E<=d;){const z=L-(E-h)*R;this.drawLine([B[0],z,B[0]+B[2],z],t.gridLineThickness,N),E+=m}E=p;const Y=.5*t.gridLineThickness;for(;E<=d;){const z=L-(E-h)*R;this.drawLine([B[0]-Y,z,B[0]+B[2]+t.gridLineThickness,z],t.gridLineThickness,t.lineColor);const W=E.toFixed(x);y>0&&this.drawTextLeft([B[0]-6,z],W,M,t.textColor),E+=m}let _=1;for(;t.lines[0].length/_>20;)_*=5;for(let z=0;z<t.lines[0].length;z+=_){const W=z*P+B[0];let K=t.gridLineThickness;if(z%2===1)K*=.5,this.drawLine([W,B[1],W,B[1]+B[3]],K,N);else{const Z=A(z);y>0&&this.drawTextBelow([W,2+B[1]+B[3]],Z,M,t.textColor),this.drawLine([W,B[1],W,B[1]+B[3]],K,t.lineColor)}}for(let z=0;z<t.lines.length;z++){let W=[1,0,0,t.lineAlpha];z<t.lineRGB.length&&(W=[t.lineRGB[z][0],t.lineRGB[z][1],t.lineRGB[z][2],t.lineAlpha]);for(let K=1;K<t.lines[z].length;K++){const Z=(K-1)*P,q=K*P,te=(t.lines[z][K-1]-h)*R,ue=(t.lines[z][K]-h)*R,le=[B[0]+Z,B[1]+B[3]-te,B[0]+q,B[1]+B[3]-ue];this.drawLine(le,t.lineThickness,W)}}if(t.selectedColumn>=0&&t.selectedColumn<t.lines[0].length){const z=t.selectedColumn*P+B[0];this.drawLine([z,B[1],z,B[1]+B[3]],t.lineThickness,[t.lineRGB[0][0],t.lineRGB[0][1],t.lineRGB[0][2],o])}y>0&&t.LTWH[1]+t.LTWH[3]>B[1]+B[3]+y*2.4&&this.drawTextBelow([B[0]+.5*B[2],B[1]+B[3]+y*1.2],"Volume",M,t.textColor),this.detectPartialllyLoaded4D()&&this.drawTextBelow([B[0]+B[2],B[1]+B[3]+y*.5],"...",M,t.textColor)}depthPicker(t,e){if(!this.uiData.mouseDepthPicker)return;this.uiData.mouseDepthPicker=!1;const i=this.gl,r=this.mousePos[0]*t[2]/t[2],s=i.canvas.height-this.mousePos[1]*t[3]/t[3]-1,n=new Uint8Array(4);if(i.readPixels(r,s,1,1,i.RGBA,i.UNSIGNED_BYTE,n),this.selectedObjectId=n[3],this.selectedObjectId===this.VOLUME_ID){this.scene.crosshairPos=new Float32Array(n.slice(0,3)).map(d=>d/255);return}const a=M0(n);if(a>1)return;const o=(this.mousePos[0]-t[0])/t[2],l=(i.canvas.height-this.mousePos[1]-t[1])/t[3],c=T0(o,l,a,e),h=this.mm2frac(c,0,!0);h[0]<0||h[0]>1||h[1]<0||h[1]>1||h[2]<0||h[2]>1||(this.scene.crosshairPos=this.mm2frac(c,0,!0))}drawImage3D(t,e,i){iu({gl:this.gl,mvpMatrix:t,azimuth:e,elevation:i,volumesLength:this.volumes.length,volumeObject3D:this.volumeObject3D,unusedVAO:this.unusedVAO,renderShader:this.renderShader,pickingImageShader:this.pickingImageShader,mouseDepthPicker:this.uiData.mouseDepthPicker,backgroundMasksOverlays:this.backgroundMasksOverlays,gradientTextureAmount:this.gradientTextureAmount,gradientTexture:this.gradientTexture,drawBitmap:this.drawBitmap,renderDrawAmbientOcclusion:this.renderDrawAmbientOcclusion,drawOpacity:this.drawOpacity,smoothDrawing:this.opts.smoothDrawing,drawSmoothedTexture:this.drawSmoothedTexture,paqdUniforms:this.opts.paqdUniforms,matRAS:this.back.matRAS,crosshairPos:this.scene.crosshairPos,clipPlaneDepthAziElevs:this.scene.clipPlaneDepthAziElevs,isClipPlanesCutaway:this.opts.isClipPlanesCutaway,isClipAllVolumes:this.opts.isClipAllVolumes,obliqueRAS:this.back?.obliqueRAS})}drawOrientationCube(t,e=0,i=0){if(!this.opts.isOrientCube)return;const r=.05*Math.min(t[2],t[3]);if(r<5)return;const s=this.gl;s.enable(s.CULL_FACE),s.cullFace(s.BACK),s.disable(s.DEPTH_TEST),this.orientCubeShader.use(this.gl),s.bindVertexArray(this.orientCubeShaderVAO);const n=J(),a=J();hi(a,0,s.canvas.width,0,s.canvas.height,-10*r,10*r);let o=0;t[1]===0&&(o=s.canvas.height-this.effectiveCanvasHeight()),tt(n,n,[1.8*r+t[0],o+1.8*r+t[1],0]),fr(n,n,[r,r,r]),Ut(n,n,qe(270-i)),Rt(n,n,qe(-e));const l=J();Ye(l,a,n),s.uniformMatrix4fv(this.orientCubeShader.uniforms.u_matrix,!1,l),s.drawArrays(s.TRIANGLE_STRIP,0,168),s.bindVertexArray(this.unusedVAO),this.gl.disable(this.gl.CULL_FACE)}createOnLocationChange(t=NaN){const[e,i,r]=this.sceneExtentsMinMax(!0),s=Math.max(Math.max(r[0],r[1]),r[2]);function n(d){return Math.max(0,-Math.ceil(Math.log10(Math.abs(d))))}let a=n(s*.001);const o=this.frac2mm(this.scene.crosshairPos,0,!0);function l(d,f=0){return parseFloat(Number(d).toFixed(f))}let c=l(o[0],a)+"×"+l(o[1],a)+"×"+l(o[2],a);if(this.volumes.length>0&&this.volumes[0].nFrame4D>0&&(c+="×"+l(this.volumes[0].frame4D)),this.volumes.length>0){let d=" = ";for(let m=0;m<this.volumes.length;m++){const p=this.volumes[m].mm2vox(o);let g=this.volumes[m].getValue(p[0],p[1],p[2],this.volumes[m].frame4D);if(a=3,this.volumes[m].colormapLabel!==null){const x=Math.round(g);if(this.volumes[m].hdr.intent_code===1002&&this.volumes[m].hdr.datatypeCode===2304){const A=this.volumes[m].getValues(p[0],p[1],p[2],this.volumes[m].frame4D);if(A[2]>2){const y=Math.round(100*A[2]/255);if(d+=this.volumes[m].colormapLabel.labels[A[0]]+` (${y}%)`,A[3]>2){const v=Math.round(100*A[3]/255);d+=" "+this.volumes[m].colormapLabel.labels[A[1]]+` (${v}%)`}}}else x>=0&&this.volumes[m].colormapLabel.labels&&x<this.volumes[m].colormapLabel.labels.length?d+=this.volumes[m].colormapLabel.labels[x]:d+="undefined("+l(g,a)+")"}else d+=l(g,a);this.volumes[m].imaginary&&(g=this.volumes[m].getValue(p[0],p[1],p[2],this.volumes[m].frame4D,!0),g>=0&&(d+="+"),d+=l(g,a)),d+=" "}c+=d;const f=this.back.dimsRAS,u=f[1]*f[2]*f[3];if(this.drawBitmap&&this.drawBitmap.length===u){const m=this.frac2vox(this.scene.crosshairPos),p=m[0]+m[1]*f[1]+m[2]*f[1]*f[2];c+=" "+this.drawLut.labels[this.drawBitmap[p]]}}const h={mm:this.frac2mm(this.scene.crosshairPos,0,!0),axCorSag:t,vox:this.frac2vox(this.scene.crosshairPos),frac:this.scene.crosshairPos,xy:[this.mousePos[0],this.mousePos[1]],values:this.volumes.map(d=>{const f=this.frac2mm(this.scene.crosshairPos,0,!0),u=d.mm2vox(f),m=d.getValue(u[0],u[1],u[2],d.frame4D);return{name:d.name,value:m,id:d.id,mm:f,vox:u}}),string:c};this._emitEvent("locationChange",h),this.onLocationChange(h)}addLabel(t,e,i,r,s){const n={textColor:this.opts.legendTextColor,textScale:1,textAlignment:"left",lineWidth:0,lineColor:this.opts.legendTextColor,lineTerminator:"none",bulletScale:0,bulletColor:this.opts.legendTextColor},a=e?{...n,...e}:{...n},o=new Er(t,{...a},i,r,s);return this.document.labels.push(o),o}calculateScreenPoint(t,e,i){const r=Xe();return ve(r,[...t,1],e),r[3]!==0&&(r[0]=(r[0]/r[3]+1)*.5*i[2],r[1]=(1-r[1]/r[3])*.5*i[3],r[2]/=r[3],r[0]+=i[0],r[1]+=i[1]),r}getLabelAtPoint(t){const e=this.legendFontScaling,i=this.fontPx*e,r=this.fontPx*e;for(const c of this.document.labels){if(c.anchor==null||c.anchor===0)continue;const h=this.fontPx*c.style.textScale*e,d=this.textHeight(h,c.text),f=this.textWidth(h,c.text);if(!(c.anchor&1&&t[0]>f)&&!(c.anchor&2&&(t[0]<(this.gl.canvas.width-f)/2||t[0]>(this.gl.canvas.width+f)/2))&&!(c.anchor&4&&t[0]<this.gl.canvas.width-f)&&!(c.anchor&8&&(t[1]<r/2||t[1]>d+r/2))&&!(c.anchor&16&&(t[1]<(this.gl.canvas.height-d-r)/2||t[1]>(this.gl.canvas.height+d-r/2)/2))&&!(c.anchor&32&&(t[1]<this.gl.canvas.height-d-r||t[1]>this.gl.canvas.height-r/2)))return c}F.debug("screenPoint",t);const s=this.getLegendPanelHeight(e),n=this.getLegendPanelWidth(),a=this.gl.canvas.width-n;let o=(this.canvas.height-s)/2;if(F.debug("panelrect",a,o,a+n,o+s),t[0]<a||t[1]<o||t[0]>a+n||t[1]>o+s)return null;const l=this.getConnectomeLabels();for(const c of l){const h=this.fontPx*c.style.textScale*e,d=this.textHeight(h,c.text);if(t[1]>=o&&t[1]<=o+d+i/2)return F.debug(`label clicked ${c.text}`),c;o+=d,o+=i/2}return null}drawLabelLine(t,e,i,r,s=!1){const n=Array.isArray(t.points)&&Array.isArray(t.points[0])?t.points:[t.points];for(const a of n){const o=this.calculateScreenPoint(a,i,r);s?this.drawDottedLine([...e,o[0],o[1]],t.style.lineWidth,t.style.lineColor):this.draw3DLine(e,[o[0],o[1],o[2]],t.style.lineWidth,t.style.lineColor)}}draw3DLabel(t,e,i,r,s,n,a,o=1){const l=t.text,c=e[0],h=e[1],d=this.fontPx*o,f=this.textHeight(t.style.textScale,l)*d;if(t.style.lineWidth>0&&Array.isArray(t.points)&&this.drawLabelLine(t,[c,h+f],i,r,a),t.style.bulletScale){const p=t.style.bulletScale*f,g=f-p,x=h+g/2+p/2,A=c+(s-p)/2;this.drawCircle([A,x,p,p],t.style.bulletColor)}let u=c;if(n)if(t.style.textAlignment!=="left"){const p=this.textWidth(t.style.textScale,t.text)*d;if(t.style.textAlignment==="right")u=c+n-d*1.5-p;else{const g=n-(s||d);u+=(g-p)/2}}else u+=s;const m=t.style.textScale;this.drawText([u,h],l,m,t.style.textColor)}draw3DLabels(t,e,i=!1){const r=this.getConnectomeLabels();if(!this.opts.showLegend||r.length===0)return;let s=this.getLegendPanelHeight(1);if(!this.canvas||s<1)return;const n=this.gl;if(n.disable(n.CULL_FACE),n.viewport(0,0,this.canvas.width,this.canvas.height),this.legendFontScaling=1,s>this.canvas.height){const u=10*this.uiData.dpr;this.legendFontScaling=Math.max(this.canvas.height-u,1)/s,F.debug(`Legend too large for screen, font reduction factor x${this.legendFontScaling}`),s=this.getLegendPanelHeight(this.legendFontScaling)}const a=this.fontPx*this.legendFontScaling,o=this.getBulletMarginWidth(),l=this.getLegendPanelWidth(),c=n.canvas.width-l;let h=(this.canvas.height-s)/2;this.drawRect([n.canvas.width-l,h,l-a,s],this.opts.legendBackgroundColor);const d=n.getParameter(n.BLEND),f=n.getParameter(n.DEPTH_FUNC);i||(n.disable(n.BLEND),n.depthFunc(n.LEQUAL));for(const u of r){this.draw3DLabel(u,[c,h],t,e,o,l,i,this.legendFontScaling);const m=this.fontPx*u.style.textScale,p=this.textHeight(m,u.text)*this.legendFontScaling;h+=p,h+=a/2}i||(n.depthFunc(f),d&&n.enable(n.BLEND))}drawAnchoredLabels(){const t=this.fontPx,e=this.document.labels.filter(i=>i.anchor!=null&&i.anchor!==0);for(const i of e){const r=i.text,s=this.textHeight(i.style.textScale,r)*t,n=this.textWidth(i.style.textScale,r)*t;let a,o;const c=this.fontPx*1,h=c;let d=c/4,f=0,u=0;i.anchor&1&&(a=0),i.anchor&4&&(a=this.canvas.width-n,f-=c/4),i.anchor&2&&(a=(this.canvas.width-n)/2,f-=c/4,d+=c/4),i.anchor&8&&(o=0),i.anchor&16&&(o=(this.canvas.height-s-c)/2,u-=c/4),i.anchor&32&&(o=this.canvas.height-s-c,u-=c/4),this.drawRect([a+f,o+u,n+d,s+h],i.style.backgroundColor),this.draw3DLabel(i,[a,o])}}draw3D(t=[0,0,0,0],e=null,i=null,r=null,s=null,n=0){const a=this.gl,[o,l,c,h]=this.getBoundsRegion();let d=[...t];(d[2]===0||d[3]===0)&&(d=this.opts.bounds?[o,l,c,h]:[0,0,a.canvas.width,a.canvas.height]);const f=s!==null;this.setPivot3D(),f||(s=this.scene.renderAzimuth,n=this.scene.renderElevation),e===null&&([e,i,r]=this.calculateMvpMatrix(null,d,s,n));const u=[...d];this.screenSlices.push({leftTopWidthHeight:d.slice(),axCorSag:4,sliceFrac:0,AxyzMxy:[],leftTopMM:[],fovMM:[D0(i),0]});const m=[d[0],a.canvas.height-d[3]-d[1],d[2],d[3]];if(d[1]=a.canvas.height-d[3]-d[1],a.clear(a.DEPTH_BUFFER_BIT),a.enable(a.DEPTH_TEST),a.depthFunc(a.ALWAYS),a.depthMask(!0),this.draw3DLabels(e,u,!1),this.gl.viewport(m[0],m[1],m[2],m[3]),this.volumes.length>0&&(this.updateInterpolation(0,!0),this.updateInterpolation(1,!0),this.drawImage3D(e,s,n)),this.updateInterpolation(0),this.updateInterpolation(1),f||this.drawCrosshairs3D(!0,1,e),this.drawMesh3D(!0,1,e,i,r),this.uiData.mouseDepthPicker){this.depthPicker(d,e),this.createOnLocationChange(),this.draw3D(u,e,i,r,s,n);return}this.opts.meshXRay>0&&this.drawMesh3D(!1,this.opts.meshXRay,e,i,r),this.gl.disable(this.gl.CULL_FACE),this.draw3DLabels(e,u,!1),a.viewport(d[0],d[1],d[2],d[3]),f||this.drawCrosshairs3D(!1,.15,e),a.viewport(o,l,c,h),this.drawOrientationCube(d,s,n);const p="azimuth: "+this.scene.renderAzimuth.toFixed(0)+" elevation: "+this.scene.renderElevation.toFixed(0);return this.readyForSync=!0,this.sync(),this.draw3DLabels(e,u,!0),p}drawMesh3D(t=!0,e=1,i,r,s,n=!1){this.meshes.length<1||(i||([i,r,s]=this.calculateMvpMatrix(this.volumeObject3D,void 0,this.scene.renderAzimuth,this.scene.renderElevation)),gu({gl:this.gl,meshes:this.meshes,isDepthTest:t,alpha:e,mvpMatrix:i,modelMatrix:r,normalMatrix:s,is2D:n,meshShaders:this.meshShaders,pickingMeshShader:this.pickingMeshShader,fiberShader:this.fiberShader,mouseDepthPicker:this.uiData.mouseDepthPicker,matCapTexture:this.matCapTexture,unusedVAO:this.unusedVAO,meshXRay:this.opts.meshXRay,meshThicknessOn2D:this.opts.meshThicknessOn2D,frac2mm:a=>this.frac2mm(a,0,this.opts.isSliceMM),crosshairPos:this.scene.crosshairPos}),this.readyForSync=!0)}drawCrosshairs3D(t=!0,e=1,i=null,r=!1,s=!0){if(!this.opts.show3Dcrosshair&&!r||this.opts.crosshairWidth<=0&&r)return;const n=this.gl,a=this.frac2mm(this.scene.crosshairPos,0,s);let o=1;const[l,c,h]=this.sceneExtentsMinMax(s);if(this.volumes.length>0){if(!this.back)throw new Error("back undefined");o=.5*Math.min(Math.min(this.back.pixDims[1],this.back.pixDims[2]),this.back.pixDims[3])}else(h[0]<50||h[0]>1e3)&&(o=h[0]*.02);if(o*=this.opts.crosshairWidth,this.opts?.crosshairWidthUnit==="percent"&&(o=h[0]*this.opts.crosshairWidth*.5*.01),this.opts?.crosshairWidthUnit==="mm"&&(o=this.opts.crosshairWidth*.5),(this.crosshairs3D===null||this.crosshairs3D.mm[0]!==a[0]||this.crosshairs3D.mm[1]!==a[1]||this.crosshairs3D.mm[2]!==a[2])&&(this.crosshairs3D!==null&&(n.deleteBuffer(this.crosshairs3D.indexBuffer),n.deleteBuffer(this.crosshairs3D.vertexBuffer)),this.crosshairs3D=st.generateCrosshairs(this.gl,1,a,l,c,o,20,this.opts.crosshairGap),this.crosshairs3D.mm=a),!this.surfaceShader)throw new Error("surfaceShader undefined");const d=this.surfaceShader;d.use(this.gl),i==null&&([i]=this.calculateMvpMatrix(this.crosshairs3D,void 0,this.scene.renderAzimuth,this.scene.renderElevation)),n.uniformMatrix4fv(d.uniforms.mvpMtx,!1,i),n.disable(n.CULL_FACE),n.bindBuffer(n.ELEMENT_ARRAY_BUFFER,this.crosshairs3D.indexBuffer),n.enable(n.DEPTH_TEST);const f=[...this.opts.crosshairColor];t?(n.disable(n.BLEND),n.depthFunc(n.LEQUAL)):(n.enable(n.BLEND),n.blendFunc(n.SRC_ALPHA,n.ONE_MINUS_SRC_ALPHA),n.depthFunc(n.ALWAYS)),f[3]=e,n.uniform4fv(d.uniforms.surfaceColor,f),n.bindVertexArray(this.crosshairs3D.vao),n.drawElements(n.TRIANGLES,this.crosshairs3D.indexCount,n.UNSIGNED_INT,0),n.bindVertexArray(this.unusedVAO)}mm2frac(t,e=0,i=!1){return zn(t,{volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D,volIdx:e,isSliceMM:i||this.opts.isSliceMM})}vox2frac(t,e=0){return S0(t,this.volumes,e)}frac2vox(t,e=0){return E0(t,this.volumes,e)}moveCrosshairInVox(t,e,i){const r=this.frac2vox(this.scene.crosshairPos),s=$1({x:t,y:e,z:i,currentVox:r,dimsRAS:this.volumes[0].dimsRAS});this.scene.crosshairPos=this.vox2frac(s.newVox),this.createOnLocationChange(),this.opts.is2DSliceShader&&s.zChanged&&(this.updateGLVolume(),this.refreshDrawing(!1)),this.drawScene()}frac2mm(t,e=0,i=!1){return wi(t,{volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D,volIdx:e,isSliceMM:i||this.opts.isSliceMM})}screenXY2TextureFrac(t,e,i,r=!0){return Ur(t,e,this.screenSlices,i,{volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D,isSliceMM:this.opts.isSliceMM,restrict0to1:r})}canvasPos2frac(t){return U0(t,this.screenSlices,{volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D,isSliceMM:this.opts.isSliceMM})}frac2canvasPosWithTile(t,e){return V0(t,this.screenSlices,{volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D,isSliceMM:this.opts.isSliceMM,preferredSliceType:e})}frac2canvasPos(t){return R0(t,this.screenSlices,{volumes:this.volumes,meshes:this.meshes,volumeObject3D:this.volumeObject3D,isSliceMM:this.opts.isSliceMM,sliceType:this.opts.sliceType})}scaleSlice(t,e,i=[0,0],r=[0,0]){const s=r[0]===0?this.effectiveCanvasWidth()-i[0]:r[0]-i[0],n=r[1]===0?this.effectiveCanvasHeight()-i[1]:r[1]-i[1];let a=s/t;e*a>n&&(a=n/e);const o=t*a,l=e*a;return[(s-o)*.5,(n-l)*.5,o,l,a]}drawThumbnail(){if(!this.bmpShader)throw new Error("bmpShader undefined");this.bmpShader.use(this.gl);const[t,e,i,r]=this.getBoundsRegion();this.gl.uniform2f(this.bmpShader.uniforms.canvasWidthHeight,i,r);const s=Bu(i,r,this.bmpTextureWH),n=t+s.left,a=e+s.top;this.gl.uniform4f(this.bmpShader.uniforms.leftTopWidthHeight,n,a,s.width,s.height),this.gl.bindVertexArray(this.genericVAO),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),this.gl.bindVertexArray(this.unusedVAO)}drawLine(t,e=1,i=[1,0,0,-1]){if(this.gl.bindVertexArray(this.genericVAO),!this.lineShader)throw new Error("lineShader undefined");this.lineShader.use(this.gl),i[3]<0&&(i=this.opts.crosshairColor),this.gl.uniform4fv(this.lineShader.uniforms.lineColor,i),this.gl.uniform2fv(this.lineShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.uniform1f(this.lineShader.uniforms.thickness,e),this.gl.uniform4fv(this.lineShader.uniforms.startXYendXY,t),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),this.gl.bindVertexArray(this.unusedVAO)}draw3DLine(t,e,i=1,r=[1,0,0,-1]){if(this.gl.bindVertexArray(this.genericVAO),!this.line3DShader)throw new Error("line3DShader undefined");this.line3DShader.use(this.gl),r[3]<0&&(r=this.opts.crosshairColor),this.gl.uniform4fv(this.line3DShader.uniforms.lineColor,r),this.gl.uniform2fv(this.line3DShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.uniform1f(this.line3DShader.uniforms.thickness,i),this.gl.uniform2fv(this.line3DShader.uniforms.startXY,t),this.gl.uniform3fv(this.line3DShader.uniforms.endXYZ,e),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4),this.gl.bindVertexArray(this.unusedVAO)}drawDottedLine(t,e=1,i=[1,0,0,-1]){if(this.gl.bindVertexArray(this.genericVAO),!this.lineShader)throw new Error("lineShader undefined");this.lineShader.use(this.gl);const r=i[3]<0?[...this.opts.crosshairColor]:[...i];r[3]=.3,this.gl.uniform4fv(this.lineShader.uniforms.lineColor,r),this.gl.uniform2fv(this.lineShader.uniforms.canvasWidthHeight,[this.gl.canvas.width,this.gl.canvas.height]),this.gl.uniform1f(this.lineShader.uniforms.thickness,e);const s=Fu(t,this.fontPx,1);for(const n of s)this.gl.uniform4fv(this.lineShader.uniforms.startXYendXY,[n.startX,n.startY,n.endX,n.endY]),this.gl.drawArrays(this.gl.TRIANGLE_STRIP,0,4);this.gl.bindVertexArray(this.unusedVAO)}drawGraphLine(t,e=[1,0,0,.5],i=2){this.drawLine(t,i,e)}drawCrossLinesMM(t,e,i,r,s){if(t<0||this.screenSlices.length<=t)return;const n=this.screenSlices[t];let a=n.sliceFrac;a===1/0&&F.debug("Rendering approximate cross lines in world view mode"),a===1/0&&(a=.5);const{linesH:l,linesV:c}=Ts(e,i,r,s),h=Math.max(1,this.opts.crosshairWidth),d=f=>{const u=La(0,0);return u[0]=n.leftTopWidthHeight[0]+(f[0]-n.leftTopMM[0])/n.fovMM[0]*n.leftTopWidthHeight[2],u[1]=n.leftTopWidthHeight[1]+n.leftTopWidthHeight[3]-(f[1]-n.leftTopMM[1])/n.fovMM[1]*n.leftTopWidthHeight[3],u};if(l.length>0&&e===0){const f=a,u=1;for(let m=0;m<l.length;m++){const p=this.frac2mm([.5,.5,.5]);p[u]=l[m];let g=this.mm2frac(p);g=g[u];let x=this.frac2mm([0,g,f]);x=he(x,[0,1,2]);let A=this.frac2mm([1,g,f]);A=he(A,[0,1,2]),x=d(x),A=d(A),this.drawLine([x[0],x[1],A[0],A[1]],h)}}if(l.length>0&&e===1){const f=a,u=2;for(let m=0;m<l.length;m++){const p=this.frac2mm([.5,.5,.5]);p[u]=l[m];let g=this.mm2frac(p);g=g[u];let x=this.frac2mm([0,f,g]);x=he(x,[0,2,1]);let A=this.frac2mm([1,f,g]);A=he(A,[0,2,1]),x=d(x),A=d(A),this.drawLine([x[0],x[1],A[0],A[1]],h)}}if(l.length>0&&e===2){const f=a,u=2;for(let m=0;m<l.length;m++){const p=this.frac2mm([.5,.5,.5]);p[u]=l[m];let g=this.mm2frac(p);g=g[u];let x=this.frac2mm([f,0,g]);x=he(x,[1,2,0]);let A=this.frac2mm([f,1,g]);A=he(A,[1,2,0]),x=d(x),A=d(A),this.drawLine([x[0],x[1],A[0],A[1]],h)}}if(c.length>0&&e===0){const f=a,u=0;for(let m=0;m<c.length;m++){const p=this.frac2mm([.5,.5,.5]);p[u]=c[m];let g=this.mm2frac(p);g=g[u];let x=this.frac2mm([g,0,f]);x=he(x,[0,1,2]);let A=this.frac2mm([g,1,f]);A=he(A,[0,1,2]),x=d(x),A=d(A),this.drawLine([x[0],x[1],A[0],A[1]],h)}}if(c.length>0&&e===1){const f=a,u=0;for(let m=0;m<c.length;m++){const p=this.frac2mm([.5,.5,.5]);p[u]=c[m];let g=this.mm2frac(p);g=g[u];let x=this.frac2mm([g,f,0]);x=he(x,[0,2,1]);let A=this.frac2mm([g,f,1]);A=he(A,[0,2,1]),x=d(x),A=d(A),this.drawLine([x[0],x[1],A[0],A[1]],h)}}if(c.length>0&&e===2){const f=a,u=1;for(let m=0;m<c.length;m++){const p=this.frac2mm([.5,.5,.5]);p[u]=c[m];let g=this.mm2frac(p);g=g[u];let x=this.frac2mm([f,g,0]);x=he(x,[1,2,0]);let A=this.frac2mm([f,g,1]);A=he(A,[1,2,0]),x=d(x),A=d(A),this.drawLine([x[0],x[1],A[0],A[1]],h)}}}drawCrossLines(t,e,i,r,s){if(t<0||this.screenSlices.length<=t)return;if(this.opts.isSliceMM)return this.drawCrossLinesMM(t,e,i,r,s);if(this.screenSlices[t].sliceFrac===1/0)return this.drawCrossLinesMM(t,e,i,r,s);const n=this.screenSlices[t],{linesH:a,linesV:o}=Ts(e,i,r,s);if(a.length>0){const l=n.leftTopWidthHeight.slice();let c=2;e===0&&(c=1);const h=this.frac2mm([.5,.5,.5]);for(let d=0;d<a.length;d++){h[c]=a[d];const f=this.mm2frac(h);this.drawRect([l[0],l[1]+l[3]-f[c]*l[3],l[2],1])}}if(o.length>0){const l=n.leftTopWidthHeight.slice(),c=n.fovMM[0]<0;let h=0;e===2&&(h=1);const d=this.frac2mm([.5,.5,.5]);for(let f=0;f<o.length;f++){d[h]=o[f];const u=this.mm2frac(d);c?this.drawRect([l[0]+(l[2]-u[h]*l[2]),l[1],1,l[3]]):this.drawRect([l[0]+u[h]*l[2],l[1],1,l[3]])}}}drawMosaic(t){this.screenSlices=[];const[e,i,r,s]=this.getBoundsRegion(),n=this.screenFieldOfViewMM(0,!0),a=this.screenFieldOfViewMM(0);t=t.replaceAll(";"," ;").trim();const o=[],l=[],c=[],h=t.split(/\s+/);let d=1;const f=this.fontPx;let u=0,m=0,p=0;this.volumes[0]?.dims||(p=Math.ceil(this.opts.tileMargin*.3));for(let g=0;g<2;g++){let x=!1,A=!1,y=0,v=0,b=0,w=0,C=!1,M=0,T=0,E=0,I=0;for(let B=0;B<h.length;B++){const V=h[B];if(V.includes("X")){A=!0;continue}if(V.includes("L")){C=!V.includes("-");continue}if(V.includes("H")){B++,T=Math.abs(Math.max(0,Math.min(1,parseFloat(h[B]))));continue}if(V.includes("V")){B++;continue}if(V.includes("A")){M=0;continue}if(V.includes("C")){M=1;continue}if(V.includes("S")){M=2;continue}if(V.includes("R")){x=!0;continue}if(V.includes(";")){b+=y,w=Math.max(w,v+E),y=0,v=0,E=0;continue}I=E,T>0&&!x&&(I=Math.round(I*(1-T))),v+=I,I=0;const R=parseFloat(V);if(isNaN(R))continue;let P=0,L=a;if(x&&(L=n),M===2?I=L[1]:I=L[0],M===0?P=L[1]:P=L[2],g===0)x||(M===0&&o.push(R),M===1&&l.push(R),M===2&&c.push(R));else{const N=[e+u+d*v,i+m+d*b,d*I,d*P];if(this.fontPx=C?f:0,x){let Y=R<0?-1/0:1/0;Object.is(R,-0)&&(Y=-1/0),this.draw2D(N,M,Y)}else this.draw2D(N,M,R);A&&this.drawCrossLines(this.screenSlices.length-1,M,o,l,c),x=!1,A=!1}E=I,v+=p,y=Math.max(y,P)}if(b+=y,w=Math.max(w,v+E),w<=0||b<=0)break;const S=(r-2*this.opts.tileMargin-p)/w,U=(s-2*this.opts.tileMargin)/b;d=Math.min(S,U),this.opts.centerMosaic?(u=Math.floor(.5*(r-w*d)),m=Math.floor(.5*(s-b*d))):(u=this.opts.tileMargin,m=this.opts.tileMargin)}this.fontPx=f}calculateWidthHeight(t,e,i,r){return Jf(t,e,i,r)}getBoundsRegionCSS(){const t=this.gl.canvas.getBoundingClientRect();return s2({bounds:this.opts.bounds,rectWidth:t.width,rectHeight:t.height})}eventInBounds(t){const e=this.gl.canvas.getBoundingClientRect();let i,r;if(t instanceof MouseEvent)i=t.clientX,r=t.clientY;else if(t instanceof TouchEvent){const a=t.touches[0]??t.changedTouches[0];if(!a)return!1;i=a.clientX,r=a.clientY}else i=t.clientX,r=t.clientY;const s=i-e.left,n=r-e.top;return u2({x:s,y:n,boundsRegion:this.getBoundsRegionCSS()})}cursorInBounds(){return m2({mouseX:this.mousePos[0],mouseY:this.mousePos[1],boundsRegion:this.getBoundsRegion()})}getBoundsRegion(){const t=this.gl,e=this.uiData?.dpr||window.devicePixelRatio||1,i=t.canvas;return r2({bounds:this.opts.bounds,canvasWidth:t.canvas.width,canvasHeight:t.canvas.height,cssWidth:i.clientWidth,cssHeight:i.clientHeight,dpr:e})}inBounds(t,e){return Q1({x:t,y:e,dpr:this.uiData.dpr,canvasHeight:this.gl.canvas.height,boundsRegion:this.getBoundsRegion()})}bindTextures(){this.gl.activeTexture($.TEXTURE0_BACK_VOL),this.opts.is2DSliceShader?this.gl.bindTexture(this.gl.TEXTURE_2D,this.volumeTexture):this.gl.bindTexture(this.gl.TEXTURE_3D,this.volumeTexture),this.gl.activeTexture($.TEXTURE2_OVERLAY_VOL),this.gl.bindTexture(this.gl.TEXTURE_3D,this.overlayTexture),this.gl.activeTexture($.TEXTURE8_PAQD),this.gl.bindTexture(this.gl.TEXTURE_3D,this.paqdTexture),this.gl.activeTexture($.TEXTURE3_FONT),this.gl.bindTexture(this.gl.TEXTURE_2D,this.fontTexture),this.gl.activeTexture($.TEXTURE1_COLORMAPS),this.gl.bindTexture(this.gl.TEXTURE_2D,this.colormapTexture),this.gl.activeTexture($.TEXTURE5_MATCAP),this.gl.bindTexture(this.gl.TEXTURE_2D,this.matCapTexture),this.gl.activeTexture($.TEXTURE6_GRADIENT),this.gl.bindTexture(this.gl.TEXTURE_3D,this.gradientTexture)}clearBounds(t=this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT,e){const i=this.gl,[r,s,n,a]=e??this.getBoundsRegion(),o=i.canvas.height-s-a;t&i.DEPTH_BUFFER_BIT&&i.clearDepth(1),i.enable(i.SCISSOR_TEST),i.scissor(r,o,n,a),t&i.COLOR_BUFFER_BIT&&i.clearColor(this.opts.backColor[0],this.opts.backColor[1],this.opts.backColor[2],this.opts.backColor[3]),i.clear(t),i.disable(i.SCISSOR_TEST)}drawBoundsBorder(){if(!this.opts.showBoundsBorder)return;const[t,e,i,r]=this.getBoundsRegion();this.drawBoundsBox([t,e,i,r],this.opts.boundsBorderColor,this.opts.selectionBoxLineThickness)}drawSceneCore(){if(!this.initialized)return;this.colorbarHeight=0;const[t,e,i,r]=this.getBoundsRegion();if(this.gl.viewport(t,e,i,r),this.clearBounds(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT),this.bindTextures(),this.bmpTexture&&this.thumbnailVisible){this.drawThumbnail();return}let s="";if(this.volumes.length===0||typeof this.volumes[0].dims>"u"){if(this.meshes.length>0){if(this.sliceMosaicString.length>0){this.opts.isColorbar&&this.reserveColorbarPanel(),this.drawMosaic(this.sliceMosaicString),this.opts.isColorbar&&this.drawColorbar();return}this.screenSlices=[],this.draw3D([t,e,i,r]),this.opts.isColorbar&&this.drawColorbar(),this.drawAnchoredLabels();return}this.drawLoadingText(this.opts.loadingText);return}const n=this.scene.clipPlaneDepthAziElevs?.[this.uiData.activeClipPlaneIndex]?.[0]??2;if(T2({isDragging:this.uiData.isDragging,activeClipPlaneDepth:n,dragStartTileIndex:this.inRenderTile(this.uiData.dragStart[0],this.uiData.dragStart[1])})){const d=this.uiData.dragStart[0]-this.uiData.dragEnd[0],f=this.uiData.dragStart[1]-this.uiData.dragEnd[1],u=b2({startDepthAziElev:this.uiData.dragClipPlaneStartDepthAziElev,dragDeltaX:d,dragDeltaY:f});if(u.changed){const m=this.uiData.activeClipPlaneIndex;this.scene.clipPlaneDepthAziElevs[m]=u.depthAziElev;const p=ha({depth:u.depthAziElev[0],azimuth:u.depthAziElev[1],elevation:u.depthAziElev[2]});this.scene.clipPlanes[m]=p,this._emitEvent("clipPlaneChange",{clipPlane:p}),this.onClipPlaneChange(p)}}if(this.sliceMosaicString.length<1&&this.opts.sliceType===4){this.opts.isColorbar&&this.reserveColorbarPanel(),this.screenSlices=[],this.draw3D(),this.opts.isColorbar&&this.drawColorbar(),this.drawAnchoredLabels();return}this.opts.isColorbar&&this.reserveColorbarPanel();const o=this.getMaxVols(),l=this.opts.sliceType===3&&o>1&&this.graph.autoSizeMultiplanar&&this.graph.opacity>0;if(this.sliceMosaicString.length>0)this.drawMosaic(this.sliceMosaicString);else{const d=[0,0];let f=!1;if(this.screenSlices=[],this.customLayout&&this.customLayout.length>0){this.screenSlices=[];const{volScale:u}=this.sliceScale();for(const m of this.customLayout){const{sliceType:p,position:g,sliceMM:x}=m,A=[t+g[0]*i,e+g[1]*r,g[2]*i,g[3]*r];if(A[0]+A[2]>t+i&&(F.warn("adjusting slice width because it would have been clipped"),A[2]=t+i-A[0]),A[1]+A[3]>e+r&&(F.warn("adjusting slice height because it would have been clipped"),A[3]=e+r-A[1]),p===4)this.draw3D(A);else{const y=this.calculateWidthHeight(p,u,A[2],A[3]);this.draw2D(A,p,x??NaN,y)}}}else if(this.opts.sliceType===0||this.opts.sliceType===1||this.opts.sliceType===2)this.draw2D([0,0,0,0],this.opts.sliceType,NaN);else{let u=function(q,te){return[(q-1)*A+q*y,(te-1)*A+te*y]},m=!1;this.opts.multiplanarForceRender?(m=!0,this.opts.multiplanarForceRender?this.opts.multiplanarShowRender=1:this.opts.multiplanarShowRender=2,delete this.opts.multiplanarForceRender):this.opts.multiplanarShowRender===1&&(m=!0);const p=isFinite(this.drawPenLocation[0])&&this.opts.drawingEnabled,{volScale:g}=this.sliceScale(),x=g.slice();this.opts.multiplanarEqualSize&&(g[0]=1,g[1]=1,g[2]=1),typeof this.opts.multiplanarPadPixels!="number"&&F.debug("multiplanarPadPixels must be numeric");const A=parseFloat(`${this.opts.multiplanarPadPixels}`)*this.uiData.dpr;let y=this.opts.tileMargin*this.uiData.dpr;y<0&&(y=2*(2+Math.ceil(this.fontPx)));const[v,b,w,C]=this.getBoundsRegion();let M=[this.effectiveCanvasWidth(),this.effectiveCanvasHeight()];this.opts.heroImageFraction>0&&this.opts.heroImageFraction<1&&(m=!1,f=!0,M[0]>M[1]&&this.opts.multiplanarLayout!==3?d[0]=M[0]*this.opts.heroImageFraction:d[1]=M[1]*this.opts.heroImageFraction,M=[M[0]-d[0],M[1]-d[1]]);const T=this.scaleSlice(g[0]+g[1],g[1]+g[2],u(2,2),M),E=Math.max(Math.max(g[1],g[2]),g[0]),I=this.scaleSlice(g[0]+g[0]+g[1],Math.max(g[1],g[2]),u(3,1),M),S=this.scaleSlice(g[0]+g[0]+g[1]+E,Math.max(g[1],g[2]),u(4,1),M),U=this.scaleSlice(E,g[1]+g[2]+g[2],u(1,3),M),B=this.scaleSlice(E,g[1]+g[2]+g[2]+E,u(1,4),M);let V=!p&&(o<2||!l),R=!1,P=!1,L=!1;this.opts.multiplanarLayout===1?R=!0:this.opts.multiplanarLayout===2?P=!0:this.opts.multiplanarLayout===3?L=!0:U[4]>I[4]&&U[4]>T[4]?R=!0:I[4]>T[4]?L=!0:P=!0;let N=T;if(R?(N=U,!f&&(m||this.opts.multiplanarShowRender===2&&B[4]>=U[4])?N=B:V=!1):L&&(N=I,!f&&(m||this.opts.multiplanarShowRender===2&&S[4]>=I[4])?N=S:V=!1),f){const q=d[0]===0?w:d[0],te=d[1]===0?C:d[1];if(this.opts?.heroSliceType===0||this.opts?.heroSliceType===1||this.opts?.heroSliceType===2)this.draw2D([v,b,q,te],this.opts.heroSliceType,NaN,[1/0,1/0]);else{const ue=N.slice();q===w&&(ue[0]=0),this.draw3D([v+ue[0],b,q,te])}N[0]+=d[0],N[1]+=d[1],V=!1}const Y=g[0]*N[4]+y,_=g[1]*N[4]+y,z=g[2]*N[4]+y,W=x[0]*N[4],K=x[1]*N[4],Z=x[2]*N[4];if(R){if(this.draw2D([v+N[0],b+N[1],Y,_],0,NaN,[W,K]),this.draw2D([v+N[0],b+N[1]+_+A,Y,z],1,NaN,[W,Z]),this.draw2D([v+N[0],b+N[1]+_+A+z+A,_,z],2,NaN,[K,Z]),V){const q=E*N[4];this.draw3D([v+N[0],b+N[1]+_+z+z+A*3,q,q])}}else if(L){if(this.draw2D([v+N[0],b+N[1],Y,_],0,NaN,[W,K]),this.draw2D([v+N[0]+Y+A,b+N[1],Y,z],1,NaN,[W,Z]),this.draw2D([v+N[0]+Y+Y+A*2,b+N[1],_,z],2,NaN,[K,Z]),V){const q=E*N[4];this.draw3D([v+N[0]+Y+Y+_+A*3,b+N[1],q,q])}}else P&&(m||(V=!1),this.opts.multiplanarShowRender===2&&(V=!0),f&&(V=!1),this.draw2D([v+N[0],b+N[1]+z+A,Y,_],0,NaN,[W,K]),this.draw2D([v+N[0],b+N[1],Y,z],1,NaN,[W,Z]),this.draw2D([v+N[0]+Y+A,b+N[1],_,z],2,NaN,[K,Z]),V&&this.draw3D([v+N[0]+Y+A,b+N[1]+z+A,_,_]))}}if(this.opts.isRuler&&this.drawRuler(),this.opts.isColorbar&&this.drawColorbar(),l&&this.drawGraph(),this.uiData.isDragging){if(this.uiData.mouseButtonCenterDown){this.dragForCenterButton([this.uiData.dragStart[0],this.uiData.dragStart[1],this.uiData.dragEnd[0],this.uiData.dragEnd[1]]);return}if(this.getCurrentDragMode()===4){this.dragForSlicer3D([this.uiData.dragStart[0],this.uiData.dragStart[1],this.uiData.dragEnd[0],this.uiData.dragEnd[1]]);return}if(this.getCurrentDragMode()===3&&!this._skipDragInDraw){this.dragForPanZoom([this.uiData.dragStart[0],this.uiData.dragStart[1],this.uiData.dragEnd[0],this.uiData.dragEnd[1]]);return}if(this.inRenderTile(this.uiData.dragStart[0],this.uiData.dragStart[1])>=0)return;this.getCurrentDragMode()===2&&this.drawMeasurementTool([this.uiData.dragStart[0],this.uiData.dragStart[1],this.uiData.dragEnd[0],this.uiData.dragEnd[1]]),this.getCurrentDragMode()===7&&this.drawAngleMeasurementTool();const d=this.getCurrentDragMode();if(d===1||d===6){const f=Math.abs(this.uiData.dragStart[0]-this.uiData.dragEnd[0]),u=Math.abs(this.uiData.dragStart[1]-this.uiData.dragEnd[1]);this.drawSelectionBox([Math.min(this.uiData.dragStart[0],this.uiData.dragEnd[0]),Math.min(this.uiData.dragStart[1],this.uiData.dragEnd[1]),f,u])}}for(const d of this.document.completedMeasurements)if(this.shouldDrawOnCurrentSlice(d.sliceIndex,d.sliceType,d.slicePosition)){const f=this.mm2frac(d.startMM),u=this.mm2frac(d.endMM),m=this.frac2canvasPosWithTile(f,d.sliceType),p=this.frac2canvasPosWithTile(u,d.sliceType);m&&p&&m.tileIndex===p.tileIndex&&this.drawMeasurementTool([m.pos[0],m.pos[1],p.pos[0],p.pos[1]])}for(let d=0;d<this.document.completedAngles.length;d++){const f=this.document.completedAngles[d];if(this.shouldDrawOnCurrentSlice(f.sliceIndex,f.sliceType,f.slicePosition)){const m=this.mm2frac(f.firstLineMM.start),p=this.mm2frac(f.firstLineMM.end),g=this.mm2frac(f.secondLineMM.start),x=this.mm2frac(f.secondLineMM.end),A=this.frac2canvasPosWithTile(m,f.sliceType),y=this.frac2canvasPosWithTile(p,f.sliceType),v=this.frac2canvasPosWithTile(g,f.sliceType),b=this.frac2canvasPosWithTile(x,f.sliceType);if(A&&y&&v&&b&&A.tileIndex===y.tileIndex&&A.tileIndex===v.tileIndex&&A.tileIndex===b.tileIndex){this.drawMeasurementTool([A.pos[0],A.pos[1],y.pos[0],y.pos[1]],!1),this.drawMeasurementTool([v.pos[0],v.pos[1],b.pos[0],b.pos[1]],!1);const w={firstLine:[A.pos[0],A.pos[1],y.pos[0],y.pos[1]],secondLine:[v.pos[0],v.pos[1],b.pos[0],b.pos[1]],sliceIndex:f.sliceIndex,sliceType:f.sliceType,slicePosition:f.slicePosition};this.drawAngleTextForAngle(w)}}}const c=this.frac2mm([this.scene.crosshairPos[0],this.scene.crosshairPos[1],this.scene.crosshairPos[2]]);return s=c[0].toFixed(2)+"×"+c[1].toFixed(2)+"×"+c[2].toFixed(2),this.readyForSync=!0,this.sync(),this.screenSlices.some(d=>d.axCorSag===4)||this.draw3DLabels(J(),[0,0,0,0],!0),this.drawAnchoredLabels(),this.drawBoundsBorder(),s}drawScene(){if(this.isBusy){this.needsRefresh=!0;return}this.isBusy=!1,this.needsRefresh=!1;let t=this.drawSceneCore();return this._gl!==null&&this.gl.finish(),this.needsRefresh&&(t=this.drawScene()),t}r8Tex(t,e,i,r=!1){return Hc(this.gl,t,e,i,r)}r16Tex(t,e,i,r){return Qc(this.gl,t,e,i,r)}r16fTex(t,e,i,r){return Zc(this.gl,t,e,i,r)}rgbaTex2D(t,e,i,r=null,s=!0){return jc(this.gl,t,e,i,r,s)}rgbaTex(t,e,i,r=!1){return _c(this.gl,t,e,i,r)}rgba16Tex(t,e,i,r=!1){return Jc(this.gl,t,e,i,r)}requestCORSIfNotSameOrigin(t,e){xn(t,e)}async loadPngAsTexture(t,e){const i=await $c(this.gl,t,e,this.fontShader,this.bmpShader,this.fontTexture,this.bmpTexture,this.matCapTexture,r=>{this.bmpTextureWH=r});return e===3?this.fontTexture=i:e===4?this.bmpTexture=i:e===5&&(this.matCapTexture=i),this.drawScene(),i}async loadFontTexture(t){return this.loadPngAsTexture(t,3)}async loadBmpTexture(t){return this.loadPngAsTexture(t,4)}async loadMatCapTexture(t){return this.loadPngAsTexture(t,5)}get gl(){if(!this._gl)throw new Error("unable to get WebGL context. Maybe the browser doesn't support WebGL2.");return this._gl}set gl(t){this._gl=t}findDrawingBoundarySlices(t){if(!this.back||!this.back.dims||!this.drawBitmap)return null;const e={dimX:this.back.dims[1],dimY:this.back.dims[2],dimZ:this.back.dims[3]};return B2(t,this.drawBitmap,e)}interpolateMaskSlices(t,e,i={}){if(!this.back||!this.back.dims||!this.drawBitmap)throw new Error("Background image and drawing bitmap must be loaded");const r={dimX:this.back.dims[1],dimY:this.back.dims[2],dimZ:this.back.dims[3]},s=this.back.img,n=this.back.global_max;N2(this.drawBitmap,r,s,n,t,e,i,()=>this.refreshDrawing(!0))}};ft=new WeakMap;export{ke as DEFAULT_OPTIONS,Nm as DEFAULT_SCENE_DATA,On as DRAG_MODE,mi as INITIAL_SCENE_DATA,Oc as LabelAnchorPoint,kc as LabelLineTerminator,Lc as LabelTextAlignment,Nr as MESH_EXTENSIONS,y0 as MULTIPLANAR_TYPE,St as NVDocument,Me as NVImage,si as NVImageFromUrlOptions,Er as NVLabel3D,Um as NVLabel3DStyle,mt as NVMesh,Rm as NVMeshFromUrlOptions,zc as NVMeshLayerDefaults,ce as NVMeshLoaders,$e as NVMeshUtilities,H as NVUtilities,f0 as NVZarrHelper,Lm as Niivue,Sm as NiivueEvent,v0 as PEN_TYPE,w0 as SHOW_RENDER,x0 as SLICE_TYPE,Kt as ZarrChunkCache,l0 as ZarrChunkClient,n0 as arrayToMat4,re as cmapper,Nc as colortables,pt as copyAffine,s0 as createTransformMatrix,Ui as degToRad,r0 as eulerToRotationMatrix,Lr as getFileExt,Hf as getLoader,_n as getMediaByUrl,ea as handleDragEnter,ta as handleDragOver,Vm as identityTransform,qf as isDicomExtension,jn as isMeshExt,a0 as mat4ToArray,o0 as multiplyAffine,$n as readDirectory,Qf as readFileAsDataURL,Jn as registerLoader,Pm as transformsEqual,kr as traverseFileTree};
|