diff --git a/dist/ngl.esm.js b/dist/ngl.esm.js index 070223c5..7e6ba922 100644 --- a/dist/ngl.esm.js +++ b/dist/ngl.esm.js @@ -1,4 +1,4 @@ -import{Vector2 as t,Vector3 as e,Matrix4 as i,Quaternion as r,Color as n,ShaderChunk as s,Points as o,Box3 as a,PerspectiveCamera as c,OrthographicCamera as l,StereoCamera as h,Scene as u,Group as d,Fog as m,DirectionalLight as f,AmbientLight as p,WebGLRenderer as g,WebGLRenderTarget as y,NearestFilter as b,RGBAFormat as _,UnsignedByteType as x,LinearFilter as v,HalfFloatType as w,Uniform as A,ShaderMaterial as S,AdditiveBlending as C,Mesh as P,PlaneGeometry as I,BufferGeometry as k,BufferAttribute as M,LineSegments as T,FloatType as D,Matrix3 as B,UniformsUtils as F,UniformsLib as E,DynamicDrawUsage as $,StaticDrawUsage as O,NoBlending as R,FrontSide as L,BackSide as N,DoubleSide as z,IcosahedronGeometry as U,DataTexture as V,NormalBlending as j,Euler as G,CanvasTexture as H,CylinderGeometry as q,ConeGeometry as W,BoxGeometry as X,OctahedronGeometry as Y,TetrahedronGeometry as K,TorusGeometry as Z}from"three";export{Box3,Color,Euler,Matrix3,Matrix4,Plane,Quaternion,Vector2,Vector3}from"three";import*as Q from"chroma-js";import*as J from"signals";import{Signal as tt}from"signals";export{Signal}from"signals";import{sprintf as et}from"sprintf-js";function it(t){if("undefined"==typeof window)return;const e=new RegExp(`${t}=([^&#=]*)`).exec(window.location.search);return e?decodeURIComponent(e[1]):void 0}function rt(t,e){return void 0!==t?t:e}function nt(t,e){const i=Object.assign({},t);for(const r in e){void 0===t[r]&&(i[r]=e[r])}return i}function st(t,e){for(const i in e){const r=e[i];void 0!==r&&(t[i]=r)}return t}function ot(t,e){e=rt(e,[]);for(let i=0;ie?(o&&(clearTimeout(o),o=null),a=l,s=t.apply(r,n),o||(r=n=null)):o||!1===i.trailing||(o=setTimeout(c,h)),s}}function dt(t,e){return te?1:0}function mt(t,e,i=dt){let r=0,n=t.length-1;for(;r<=n;){const s=r+n>>1,o=i(e,t[s]);if(o>0)r=s+1;else{if(!(o<0))return s;n=s-1}}return-r-1}function ft(t,e,i){const r=function(t,e){let i=t.length-1;if(t[i]>1;t[n]>=e?i=n-1:r=n+1}return i+1}(t,e),n=function(t,e){if(t[0]>e)return-1;let i=0,r=t.length-1;for(;i<=r;){const n=i+r>>1;t[n]>e?r=n-1:i=n+1}return i-1}(t,i);return-1===r||-1===n||r>n?0:n-r+1}function pt(t){return t.sort().filter((function(t,e,i){return 0===e||t!==i[e-1]}))}function gt(t){const e=28672;if(t.length>e){const i=[];for(let r=0;r65535?Uint32Array:Uint16Array)(t)}function _t(t){return t.buffer&&t.buffer instanceof ArrayBuffer?t.buffer:t}function xt(t,e){return void 0===t?t=new e:Array.isArray(t)&&(t=(new e).fromArray(t)),t}function vt(t){return xt(t,e)}function wt(t){return xt(t,i)}function At(t){return xt(t,r)}function St(t){return e=t,i=Float32Array,e instanceof i?e:new i(e);var e,i}function Ct(t){return rt(t,"").toString().toLowerCase()}class Pt{constructor(t){this.name=t,this._dict={}}add(t,e){this._dict[Ct(t)]=e}get(t){return this._dict[Ct(t)]}get names(){return Object.keys(this._dict)}}function It(t){return.01745*t}const kt="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),Mt=new Array(36);function Tt(){let t,e=0;for(let i=0;i<36;i++)8===i||13===i||18===i||23===i?Mt[i]="-":14===i?Mt[i]="4":(e<=2&&(e=33554432+16777216*Math.random()|0),t=15&e,e>>=4,Mt[i]=kt[19===i?3&t|8:t]);return Mt.join("")}function Dt(t,e,i){return Math.max(e,Math.min(i,t))}function Bt(t,e,i){return t+(e-t)*i}function Ft(t,e,i,r,n,s){const o=(i-t)*s,a=(r-e)*s,c=n*n;return(2*e-2*i+o+a)*(n*c)+(-3*e+3*i-2*o-a)*c+o*n+e}function Et(t,e,i){var r;return r=function(t,e,i){return(t-e)/(i-e)}(i,t,e),(i=Dt(r,0,1))*i*(3-2*i)}var $t="sRGB";const Ot={scale:"uniform",mode:"hcl",domain:[0,1],value:16777215,reverse:!1},Rt=new n;function Lt(t,e,i){const r=i.value;return i.value=function(t,e){let i=r.bind(this,t,e)();return"linear"==$t?(Rt.set(i),Rt.convertSRGBToLinear(),Rt.getHex()):i},i}class Nt{constructor(t={}){this.parameters=nt(t,Ot),"string"==typeof this.parameters.value&&(this.parameters.value=Rt.set(this.parameters.value).getHex()),this.parameters.structure&&(this.atomProxy=this.parameters.structure.getAtomProxy())}getScale(t={}){const e=nt(t,this.parameters);return"rainbow"===e.scale?e.scale=["red","orange","yellow","green","blue"]:"rwb"===e.scale&&(e.scale=["red","white","blue"]),e.reverse&&(e.domain=e.domain.slice().reverse()),Q.scale(e.scale).mode(e.mode).domain(e.domain).out("num")}colorToArray(t,e=[],i=0){return e[i]=(t>>16&255)/255,e[i+1]=(t>>8&255)/255,e[i+2]=(255&t)/255,e}atomColorToArray(t,e,i){return this.colorToArray(this.atomColor?this.atomColor(t):0,e,i)}bondColor(t,e){return this.atomProxy&&this.atomColor?(this.atomProxy.index=e?t.atomIndex1:t.atomIndex2,this.atomColor(this.atomProxy)):0}bondColorToArray(t,e,i,r){return this.colorToArray(this.bondColor(t,e),i,r)}volumeColorToArray(t,e,i){return this.colorToArray(this.volumeColor?this.volumeColor(t):0,e,i)}positionColorToArray(t,e,i){return this.colorToArray(this.positionColor?this.positionColor(t):0,e,i)}}var zt;!function(t){t[t.PROTEIN=1]="PROTEIN",t[t.NUCLEIC=2]="NUCLEIC",t[t.RNA=3]="RNA",t[t.DNA=4]="DNA",t[t.POLYMER=5]="POLYMER",t[t.WATER=6]="WATER",t[t.HELIX=7]="HELIX",t[t.SHEET=8]="SHEET",t[t.TURN=9]="TURN",t[t.BACKBONE=10]="BACKBONE",t[t.SIDECHAIN=11]="SIDECHAIN",t[t.ALL=12]="ALL",t[t.HETERO=13]="HETERO",t[t.ION=14]="ION",t[t.SACCHARIDE=15]="SACCHARIDE",t[t.SUGAR=15]="SUGAR",t[t.BONDED=16]="BONDED",t[t.RING=17]="RING",t[t.AROMATICRING=18]="AROMATICRING",t[t.METAL=19]="METAL",t[t.POLARH=20]="POLARH",t[t.NONE=21]="NONE"}(zt||(zt={}));const Ut=["*","","ALL"],Vt=["NONE"],jt=[zt.BACKBONE,zt.SIDECHAIN,zt.BONDED,zt.RING,zt.AROMATICRING,zt.METAL,zt.POLARH],Gt=[zt.POLYMER,zt.WATER],Ht=["ALA","GLY","SER"],qt=["CYS","SER","THR"],Wt=["ALA","ILE","LEU","MET","PHE","PRO","TRP","VAL"],Xt=["PHE","TRP","TYR","HIS"],Yt=["ASN","GLN"],Kt=["ASP","GLU"],Zt=["ARG","HIS","LYS"],Qt=["ARG","ASP","GLU","HIS","LYS"],Jt=["ASN","ARG","ASP","CYS","GLY","GLN","GLU","HIS","LYS","SER","THR","TYR"],te=["ALA","ILE","LEU","MET","PHE","PRO","TRP","VAL"],ee=["HIS","PHE","PRO","TRP","TYR"],ie=["ALA","GLY","ILE","LEU","VAL"];function re(t,e){if(void 0===e.atomname&&void 0===e.element&&void 0===e.altloc&&void 0===e.atomindex&&void 0===e.keyword&&void 0===e.inscode&&void 0===e.resname&&void 0===e.sstruc&&void 0===e.resno&&void 0===e.chainname&&void 0===e.model)return-1;if(void 0!==e.keyword){if(e.keyword===zt.BACKBONE&&!t.isBackbone())return!1;if(e.keyword===zt.SIDECHAIN&&!t.isSidechain())return!1;if(e.keyword===zt.BONDED&&!t.isBonded())return!1;if(e.keyword===zt.RING&&!t.isRing())return!1;if(e.keyword===zt.AROMATICRING&&!t.isAromatic())return!1;if(e.keyword===zt.HETERO&&!t.isHetero())return!1;if(e.keyword===zt.PROTEIN&&!t.isProtein())return!1;if(e.keyword===zt.NUCLEIC&&!t.isNucleic())return!1;if(e.keyword===zt.RNA&&!t.isRna())return!1;if(e.keyword===zt.DNA&&!t.isDna())return!1;if(e.keyword===zt.POLYMER&&!t.isPolymer())return!1;if(e.keyword===zt.WATER&&!t.isWater())return!1;if(e.keyword===zt.HELIX&&!t.isHelix())return!1;if(e.keyword===zt.SHEET&&!t.isSheet())return!1;if(e.keyword===zt.TURN&&!t.isTurn())return!1;if(e.keyword===zt.ION&&!t.isIon())return!1;if(e.keyword===zt.SACCHARIDE&&!t.isSaccharide())return!1;if(e.keyword===zt.METAL&&!t.isMetal())return!1;if(e.keyword===zt.POLARH&&!t.isPolarHydrogen())return!1}if(void 0!==e.atomname&&e.atomname!==t.atomname)return!1;if(void 0!==e.element&&e.element!==t.element)return!1;if(void 0!==e.altloc&&e.altloc!==t.altloc)return!1;if(void 0!==e.atomindex&&mt(e.atomindex,t.index)<0)return!1;if(void 0!==e.resname)if(Array.isArray(e.resname)){if(!e.resname.includes(t.resname))return!1}else if(e.resname!==t.resname)return!1;if(void 0!==e.sstruc&&e.sstruc!==t.sstruc)return!1;if(void 0!==e.resno)if(Array.isArray(e.resno)&&2===e.resno.length){if(e.resno[0]>t.resno||e.resno[1]t.resno||e.resno[1]0?t:null}function le(t,e=!1){let i=t;return e&&(i=ce(t,(function(t){return void 0!==t.keyword&&!jt.includes(t.keyword)||(void 0!==t.model||(void 0!==t.chainname||(void 0!==t.resname||(void 0!==t.resno||void 0!==t.sstruc))))}))),ae(i,re)}function he(t,e=!1){let i=t;return e&&(i=ce(t,(function(t){return!(void 0===t.keyword||!jt.includes(t.keyword))||(void 0!==t.model||(void 0!==t.chainname||(void 0!==t.atomname||(void 0!==t.element||void 0!==t.altloc))))}))),ae(i,ne)}function ue(t,e=!1){let i=t;return e&&(i=ce(t,(function(t){return void 0!==t.keyword&&!Gt.includes(t.keyword)||(void 0!==t.resname||(void 0!==t.resno||(void 0!==t.atomname||(void 0!==t.element||(void 0!==t.altloc||(void 0!==t.sstruc||void 0!==t.inscode))))))}))),ae(i,se)}function de(t,e=!1){let i=t;return e&&(i=ce(t,(function(t){return void 0!==t.keyword||(void 0!==t.chainname||(void 0!==t.resname||(void 0!==t.resno||(void 0!==t.atomname||(void 0!==t.element||(void 0!==t.altloc||(void 0!==t.sstruc||void 0!==t.inscode)))))))}))),ae(i,oe)}class me{constructor(t){this.signals={stringChanged:new tt},this.setString(t)}get type(){return"selection"}setString(t,e){if(void 0===t&&(t=this.string||""),t===this.string)return;try{this.selection=function(t){let e={operator:void 0,rules:[]};if(!t)return e;let i,r,n=e;const s=[];"("===(t=t.replace(/\(/g," ( ").replace(/\)/g," ) ").trim()).charAt(0)&&")"===t.substr(-1)&&(t=t.slice(1,-1).trim());const o=t.split(/\s+/),a=t=>{i={operator:t,rules:[]},void 0===n?(n=i,e=i):(n.rules.push(i),s.push(n),n=i)},c=function(t){r=n,n=s.pop(),void 0===n&&(a(t),l(r))},l=function(t){n.rules.push(t)};let h=!1;for(let t=0;t0)if("NOT"===i)h=1;else if(1===h)h=2;else{if(2!==h)throw new Error("something went wrong with 'not'");h=!1,c()}if("AND"===i){if("OR"===n.operator){const t=n.rules.pop();a("AND"),l(t)}else n.operator="AND";continue}if("OR"===i){"AND"===n.operator?c("OR"):n.operator="OR";continue}if("NOT"===e.toUpperCase()){h=1,a(),n.negate=!0;continue}if(+i!=+i){const t=zt[i];if(void 0!==t){l({keyword:t});continue}}if("HYDROGEN"===i){l({operator:"OR",rules:[{element:"H"},{element:"D"}]});continue}if("SMALL"===i){l({resname:Ht});continue}if("NUCLEOPHILIC"===i){l({resname:qt});continue}if("HYDROPHOBIC"===i){l({resname:Wt});continue}if("AROMATIC"===i){l({resname:Xt});continue}if("AMIDE"===i){l({resname:Yt});continue}if("ACIDIC"===i){l({resname:Kt});continue}if("BASIC"===i){l({resname:Zt});continue}if("CHARGED"===i){l({resname:Qt});continue}if("POLAR"===i){l({resname:Jt});continue}if("NONPOLAR"===i){l({resname:te});continue}if("CYCLIC"===i){l({resname:ee});continue}if("ALIPHATIC"===i){l({resname:ie});continue}if("SIDECHAINATTACHED"===i){l({operator:"OR",rules:[{keyword:zt.SIDECHAIN},{operator:"AND",negate:!1,rules:[{keyword:zt.PROTEIN},{operator:"OR",negate:!1,rules:[{atomname:"CA"},{atomname:"BB"}]}]},{operator:"AND",negate:!1,rules:[{resname:"PRO"},{atomname:"N"}]},{operator:"AND",negate:!1,rules:[{keyword:zt.NUCLEIC},{operator:"OR",negate:!0,rules:[{atomname:"P"},{atomname:"OP1"},{atomname:"OP2"},{atomname:"O3'"},{atomname:"O3*"},{atomname:"HO3'"},{atomname:"O5'"},{atomname:"O5*"},{atomname:"HO5'"},{atomname:"C5'"},{atomname:"C5*"},{atomname:"H5'"},{atomname:"H5''"}]}]}]});continue}if("APOLARH"===i){l({operator:"AND",negate:!1,rules:[{element:"H"},{negate:!0,operator:void 0,rules:[{keyword:zt.POLARH}]}]});continue}if("LIGAND"===i){l({operator:"AND",rules:[{operator:"OR",rules:[{operator:"AND",rules:[{keyword:zt.HETERO},{negate:!0,operator:void 0,rules:[{keyword:zt.POLYMER}]}]},{negate:!0,operator:void 0,rules:[{keyword:zt.POLYMER}]}]},{negate:!0,operator:void 0,rules:[{operator:"OR",rules:[{keyword:zt.WATER},{keyword:zt.ION}]}]}]});continue}if(-1!==Ut.indexOf(i)){l({keyword:zt.ALL});continue}if("@"===e.charAt(0)){const t=e.substr(1).split(",").map((t=>parseInt(t)));t.sort((function(t,e){return t-e})),l({atomindex:t});continue}if("#"===e.charAt(0)){console.error("# for element selection deprecated, use _"),l({element:i.substr(1)});continue}if("_"===e.charAt(0)){l({element:i.substr(1)});continue}if("["===e[0]&&"]"===e[e.length-1]){const t=i.substr(1,e.length-2).split(","),r=t.length>1?t:t[0];l({resname:r});continue}if(e.length>=1&&e.length<=4&&"^"!==e[0]&&":"!==e[0]&&"."!==e[0]&&"%"!==e[0]&&"/"!==e[0]&&isNaN(parseInt(e))){l({resname:i});continue}const r={operator:"AND",rules:[]},s=e.split("/");if(s.length>1&&s[1]){if(isNaN(parseInt(s[1])))throw new Error("model must be an integer");r.rules.push({model:parseInt(s[1])})}const u=s[0].split("%");u.length>1&&r.rules.push({altloc:u[1]});const d=u[0].split(".");if(d.length>1&&d[1]){if(d[1].length>4)throw new Error("atomname must be one to four characters");r.rules.push({atomname:d[1].substring(0,4).toUpperCase()})}const m=d[0].split(":");m.length>1&&m[1]&&r.rules.push({chainname:m[1]});const f=m[0].split("^");if(f.length>1&&r.rules.push({inscode:f[1]}),f[0]){let t,e;"-"===f[0][0]&&(f[0]=f[0].substr(1),t=!0),f[0].includes("--")&&(f[0]=f[0].replace("--","-"),e=!0);let i=f[0].split("-");if(1===i.length){let e=parseInt(i[0]);if(isNaN(e))throw new Error("resi must be an integer");t&&(e*=-1),r.rules.push({resno:e})}else{if(2!==i.length)throw new Error("resi range must contain one '-'");{const n=i.map((t=>parseInt(t)));t&&(n[0]*=-1),e&&(n[1]*=-1),r.rules.push({resno:[n[0],n[1]]})}}}if(1===r.rules.length)l(r.rules[0]);else{if(!(r.rules.length>1))throw new Error("empty selection chunk");l(r)}}return void 0===e.operator&&1===e.rules.length&&e.rules[0].hasOwnProperty("operator")&&(e=e.rules[0]),e}(t)}catch(t){this.selection={error:t.message}}const i=this.selection;this.string=t,this.test=le(i),this.residueTest=he(i),this.chainTest=ue(i),this.modelTest=de(i),this.atomOnlyTest=le(i,!0),this.residueOnlyTest=he(i,!0),this.chainOnlyTest=ue(i,!0),this.modelOnlyTest=de(i,!0),e||this.signals.stringChanged.dispatch(this.string)}isAllSelection(){return Ut.includes(this.string.toUpperCase())}isNoneSelection(){return Vt.includes(this.string.toUpperCase())}}class fe extends Nt{constructor(t){super(t),this.colormakerList=[],this.selectionList=[];(t.dataList||[]).forEach((t=>{const[e,i,r={}]=t;Oe.hasScheme(e)?Object.assign(r,{scheme:e,structure:this.parameters.structure}):Object.assign(r,{scheme:"uniform",value:new n(e).getHex()}),this.colormakerList.push(Oe.getScheme(r)),this.selectionList.push(new me(i))}))}atomColor(t){for(let e=0,i=this.selectionList.length;e{}),t)}catch(t){}const Ae="undefined"!=typeof window&&void 0!==window.orientation;let Se=!1;function Ce(t){Se=t}let Pe=!1;function Ie(t){Pe=t}const ke={log:Function.prototype.bind.call(console.log,console),info:Function.prototype.bind.call(console.info,console),warn:Function.prototype.bind.call(console.warn,console),error:Function.prototype.bind.call(console.error,console),time:Function.prototype.bind.call(console.time,console),timeEnd:Function.prototype.bind.call(console.timeEnd,console)};let Me={color:"green",labelColor:8421504,labelAttachment:"bottom-center",labelSize:.7,labelZOffset:.5,labelYOffset:.1,labelBorder:!0,labelBorderColor:13882323,labelBorderWidth:.25,lineOpacity:.8,linewidth:5,opacity:.6,labelUnit:"angstrom",arcVisible:!0,planeVisible:!1};function Te(t={}){Object.assign(Me,t)}let De=!!(Be=it("debug"))&&("string"!=typeof Be||/^1|true|t|yes|y$/i.test(Be));var Be;function Fe(t){De=t}const Ee=["ngl","js"],$e=new class{constructor(){this.activeWorkerCount=0,this._funcDict={},this._depsDict={},this._blobDict={}}add(t,e,i){this._funcDict[t]=e,this._depsDict[t]=i}get(t){return this._blobDict[t]||(this._blobDict[t]=xe(this._funcDict[t],this._depsDict[t])),this._blobDict[t]}},Oe=new class{constructor(){this.schemes={},this.userSchemes={}}getScheme(t){const e=((t||{}).scheme||"").toLowerCase();let i;return i=e in this.schemes?this.schemes[e]:e in this.userSchemes?this.userSchemes[e]:Nt,new i(t)}getSchemes(){const t={};return Object.keys(this.schemes).forEach((function(e){t[e]=e})),Object.keys(this.userSchemes).forEach((function(e){t[e]=e.split("|")[1]})),t}getScales(){return pe}getModes(){return ge}add(t,e){t=t.toLowerCase(),this.schemes[t]=e}addScheme(t,e){return function(t){return t instanceof Nt}(t)||(t=this._createScheme(t)),this._addUserScheme(t,e)}_addUserScheme(t,e){e=e||"";const i=`${Tt()}|${e}`.toLowerCase();return this.userSchemes[i]=t,i}removeScheme(t){t=t.toLowerCase(),delete this.userSchemes[t]}_createScheme(t){return class extends Nt{constructor(e){super(e),t.call(this,e)}}}addSelectionScheme(t,e){return this._addUserScheme(class extends fe{constructor(e){super(Object.assign({dataList:t},e))}},e)}hasScheme(t){return(t=t.toLowerCase())in this.schemes||t in this.userSchemes}},Re=new Pt("datasource"),Le=new Pt("representatation"),Ne=new class extends Pt{constructor(){super("parser")}__hasObjName(t,e){const i=this.get(t);return i&&i.prototype.__objName===e}isTrajectory(t){return this.__hasObjName(t,"frames")}isStructure(t){return this.__hasObjName(t,"structure")}isVolume(t){return this.__hasObjName(t,"volume")}isSurface(t){return this.__hasObjName(t,"surface")}isBinary(t){const e=this.get(t);return e&&e.prototype.isBinary}isXml(t){const e=this.get(t);return e&&e.prototype.isXml}isJson(t){const e=this.get(t);return e&&e.prototype.isJson}getTrajectoryExtensions(){return this.names.filter((t=>this.isTrajectory(t)))}getStructureExtensions(){return this.names.filter((t=>this.isStructure(t)))}getVolumeExtensions(){return this.names.filter((t=>this.isVolume(t)))}getSurfaceExtensions(){return this.names.filter((t=>this.isSurface(t)))}},ze=new Pt("shader"),Ue=new Pt("decompressor"),Ve=new Pt("component"),je=new Pt("buffer"),Ge=new Pt("picker");let He,qe;function We(t){He=t}function Xe(t){qe=t}class Ye{constructor(t,e={}){this.chunkSize=10485760,this.newline="\n",this.__pointer=0,this.__partialLine="",this.compressed=rt(e.compressed,!1),this.binary=rt(e.binary,!1),this.json=rt(e.json,!1),this.xml=rt(e.xml,!1),this.src=t}isBinary(){return this.binary||this.compressed}read(){return this._read().then((t=>{const e=this.compressed?Ue.get(this.compressed):void 0;return this.compressed&&e?this.data=e(t):((this.binary||this.compressed)&&t instanceof ArrayBuffer&&(t=new Uint8Array(t)),this.data=t),this.data}))}_chunk(t,e){return e=Math.min(this.data.length,e),0===t&&this.data.length===e?this.data:this.isBinary()?this.data.subarray(t,e):this.data.substring(t,e)}chunk(t){const e=t+this.chunkSize;return this._chunk(t,e)}peekLines(t){const e=this.data,i=e.length,r=this.isBinary()?this.newline.charCodeAt(0):this.newline;let n,s=0;for(n=0;ni).lines}chunkCount(){return Math.floor(this.data.length/this.chunkSize)+1}asText(){return this.isBinary()?gt(this.data):this.data}chunkToLines(t,e,i){const r=this.newline;if(!this.isBinary()&&t.length===this.data.length)return{lines:t.split(r),partialLine:""};let n=[];const s=this.isBinary()?gt(t):t,o=s.lastIndexOf(r);if(-1===o)e+=s;else{const t=e+s.substr(0,o);n=n.concat(t.split(r)),e=o===s.length-r.length?"":s.substr(o+r.length)}return i&&""!==e&&n.push(e),{lines:n,partialLine:e}}nextChunk(){const t=this.__pointer;if(!(t>this.data.length))return this.__pointer+=this.chunkSize,this.chunk(t)}nextChunkOfLines(){const t=this.nextChunk();if(void 0===t)return;const e=this.__pointer>this.data.length,i=this.chunkToLines(t,this.__partialLine,e);return this.__partialLine=i.partialLine,i.lines}eachChunk(t){const e=this.chunkSize,i=this.data.length,r=this.chunkCount();for(let n=0;n{const n=i===r+1,s=this.chunkToLines(e,this.__partialLine,n);this.__partialLine=s.partialLine,t(s.lines,i,r)}))}dispose(){delete this.src}}class Ke extends Ye{_read(){return new Promise(((t,e)=>{const i=this.src,r=new FileReader;r.onload=e=>{e.target&&t(e.target.result)},r.onerror=t=>e(t),this.binary||this.compressed?r.readAsArrayBuffer(i):r.readAsText(i)}))}}class Ze extends Ye{_read(){return new Promise(((t,e)=>{const i=this.src,r=new XMLHttpRequest;r.open("GET",i,!0),r.addEventListener("load",(()=>{if(200===r.status||304===r.status||0===r.status)try{t(r.response)}catch(t){e(t)}else e(r.statusText)}),!1),r.addEventListener("error",(t=>e("network error")),!1),this.isBinary()?r.responseType="arraybuffer":this.json?r.responseType="json":this.xml?r.responseType="document":r.responseType="text",r.send()}))}}class Qe{constructor(t,e={}){this.parameters=nt(e,{ext:"",compressed:!1,binary:Ne.isBinary(e.ext||""),name:"",dir:"",path:"",protocol:""});const i={compressed:this.parameters.compressed,binary:this.parameters.binary,json:Ne.isJson(this.parameters.ext),xml:Ne.isXml(this.parameters.ext)};"undefined"!=typeof File&&t instanceof File||"undefined"!=typeof Blob&&t instanceof Blob?this.streamer=new Ke(t,i):this.streamer=new Ze(t,i)}}class Je extends Qe{constructor(t,e={}){super(t,e),this.parserParams={voxelSize:e.voxelSize,firstModelOnly:e.firstModelOnly,asTrajectory:e.asTrajectory,cAlphaOnly:e.cAlphaOnly,delimiter:e.delimiter,comment:e.comment,columnNames:e.columnNames,inferBonds:e.inferBonds,name:this.parameters.name,path:this.parameters.path}}load(){return new(Ne.get(this.parameters.ext))(this.streamer,this.parserParams).parse()}}class ti{constructor(t,e,i){this.name=e,this.path=i,this.signals={elementAdded:new tt,elementRemoved:new tt,nameChanged:new tt},this.type="Script",this.dir=i.substring(0,i.lastIndexOf("/")+1);try{this.fn=new Function("stage","__name","__path","__dir",t)}catch(t){ke.error("Script compilation failed",t),this.fn=function(){}}}run(t){return new Promise(((e,i)=>{try{this.fn.apply(null,[t,this.name,this.path,this.dir]),e()}catch(t){ke.error("Script.fn",t),i(t)}}))}}class ei extends Qe{load(){return this.streamer.read().then((()=>new ti(this.streamer.asText(),this.parameters.name,this.parameters.path)))}}function ii(t){const e=Ue.names;let i,r,n="";i=t instanceof File?t.name:t instanceof Blob?"":t;const s=i.lastIndexOf("?"),o=-1!==s?i.substring(s):"";i=i.substring(0,-1===s?i.length:s);const a=i.replace(/^.*[\\/]/,"");let c=a.substring(0,a.lastIndexOf("."));const l=a.split(".");let h=l.length>1?(l.pop()||"").toLowerCase():"";const u=i.match(/^(.+):\/\/(.+)$/);u&&(n=u[1].toLowerCase(),i=u[2]||"");const d=i.substring(0,i.lastIndexOf("/")+1);if(e.includes(h)){r=h;const t=i.length-h.length-1;h=(i.substr(0,t).split(".").pop()||"").toLowerCase();const e=c.length-h.length-1;c=c.substr(0,e)}else r=!1;return{path:i,name:a,ext:h,base:c,dir:d,compressed:r,protocol:n,query:o,src:t}}function ri(t){let e=ii(t);const i=Re.get(e.protocol);return i&&(e=ii(i.getUrl(e.src)),!e.ext&&i.getExt&&(e.ext=i.getExt(t))),e}function ni(t,e={}){const i=Object.assign(ri(t),e);let r;return Ne.names.includes(i.ext)?r=new Je(i.src,i):Ee.includes(i.ext)&&(r=new ei(i.src,i)),r?r.load():Promise.reject(new Error(`autoLoad: ext '${i.ext}' unknown`))}class si{getBlob(){return new Blob([this.getData()],{type:this.mimeType})}download(t,e){t=rt(t,this.defaultName),e=rt(e,this.defaultExt),ht(this.getBlob(),`${t}.${e}`)}}class oi extends si{constructor(t,e){super(),this.mimeType="text/plain",this.defaultName="structure",this.defaultExt="pdb";const i=Object.assign({},e);this.renumberSerial=rt(i.renumberSerial,!0),this.remarks=function(t){return Array.isArray(t)?t:[t]}(rt(i.remarks,[])),this.structure=t,this._records=[]}_writeRecords(){this._records.length=0,this._writeTitle(),this._writeRemarks(),this._writeAtoms()}_writeTitle(){this._records.push(et("TITLE %-74s",this.structure.name))}_writeRemarks(){this.remarks.forEach((t=>{this._records.push(et("REMARK %-73s",t))})),this.structure.trajectory&&(this._records.push(et("REMARK %-73s","Trajectory '"+this.structure.trajectory.name+"'")),this._records.push(et("REMARK %-73s",`Frame ${this.structure.trajectory.frame}`)))}_writeAtoms(){let t=1,e=1,i=" ",r=" ";const n=this.structure.modelStore.count>1;this.structure.eachModel((s=>{n&&this._records.push(et("MODEL %4d%-66s",e++,"")),s.eachAtom((e=>{const n=e.hetero?"HETATM%5d %-4s %3s %1s%4d %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%1s%1s":"ATOM %5d %-4s %3s %1s%4d %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%1s%1s",s=this.renumberSerial?t:e.serial;let o=e.atomname;(1===o.length||o.length<4&&1===e.element.length&&o[0]===e.element)&&(o=" "+o),e.formalCharge?(i=Math.abs(e.formalCharge).toPrecision(1),r=e.formalCharge>0?"+":"-"):(i=" ",r=" "),this._records.push(et(n,s,o,e.resname,rt(e.chainname," "),e.resno,e.x,e.y,e.z,rt(e.occupancy,1),rt(e.bfactor,0),"",rt(e.element,""),i,r)),t+=1}),this.structure.getSelection()),n&&this._records.push(et("%-80s","ENDMDL"))})),this._records.push(et("%-80s","END"))}getString(){return console.warn("PdbWriter.getString() is deprecated, use .getData instead"),this.getData()}getData(){return this._writeRecords(),this._records.join("\n")}}class ai extends si{constructor(t){super(),this.mimeType="text/plain",this.defaultName="structure",this.defaultExt="sdf",this.structure=t,this._records=[]}get idString(){return this.structure.id}get titleString(){return" "+this.structure.title}get countsString(){return et("%3i%3i 0 0 0 0 0 0 0 0999 V2000",this.structure.atomCount,this.structure.bondCount)}get chargeLines(){const t=[];this.structure.eachAtom((e=>{null!=e.formalCharge&&0!==e.formalCharge&&t.push([e.index,e.formalCharge])}));const e=[];for(let i=0;i{this._records.push(this.formatAtom(t))})),this.structure.eachBond((t=>{this._records.push(this.formatBond(t))})),this.chargeLines.forEach((t=>{this._records.push(t)})),this._records.push("M END")}_writeFooter(){this._records.push("$$$$")}getData(){return this._writeRecords(),this._records.join("\n")}}const ci=[];class li{constructor(t,e={}){this._mark=0,this._marks=[],this.offset=0,this.littleEndian=!0;let i=!1;void 0===t&&(t=8192),"number"==typeof t?t=new ArrayBuffer(t):i=!0;const r=e.offset?e.offset>>>0:0;let n=t.byteLength-r,s=r;t instanceof ArrayBuffer||(t.byteLength!==t.buffer.byteLength&&(s=t.byteOffset+r),t=t.buffer),this._lastWrittenByte=i?n:0,this.buffer=t,this.length=n,this.byteLength=n,this.byteOffset=s,this._data=new DataView(this.buffer,s,n)}available(t){return void 0===t&&(t=1),this.offset+t<=this.length}isLittleEndian(){return this.littleEndian}setLittleEndian(){return this.littleEndian=!0,this}isBigEndian(){return!this.littleEndian}setBigEndian(){return this.littleEndian=!1,this}skip(t){return void 0===t&&(t=1),this.offset+=t,this}seek(t){return this.offset=t,this}mark(){return this._mark=this.offset,this}reset(){return this.offset=this._mark,this}pushMark(){return this._marks.push(this.offset),this}popMark(){const t=this._marks.pop();if(void 0===t)throw new Error("Mark stack empty");return this.seek(t),this}rewind(){return this.offset=0,this}ensureAvailable(t){if(void 0===t&&(t=1),!this.available(t)){const e=2*(this.offset+t),i=new Uint8Array(e);i.set(new Uint8Array(this.buffer)),this.buffer=i.buffer,this.length=this.byteLength=e,this._data=new DataView(this.buffer)}return this}readBoolean(){return 0!==this.readUint8()}readInt8(){return this._data.getInt8(this.offset++)}readUint8(){return this._data.getUint8(this.offset++)}readByte(){return this.readUint8()}readBytes(t){void 0===t&&(t=1);for(var e=new Uint8Array(t),i=0;ithis._lastWrittenByte&&(this._lastWrittenByte=this.offset)}}class hi extends si{constructor(t){super(),this.mimeType="application/vnd.ms-pki.stl",this.defaultName="surface",this.defaultExt="stl",this.surface=t}getData(){const t=this.surface.index.length/3,i=new li(2*t+3*t*4*4+80+4);i.skip(80),i.writeUint32(t);const r=new e,n=new e,s=new e,o=new e;for(let e=0;e{0===this.count&&(this.signals.countChanged.remove(i,this),t.call(e))};this.signals.countChanged.add(i,this)}}dispose(){this.clear(),this.signals.countChanged.dispose()}}ze.add("shader/BasicLine.vert","void main(){\n#include begin_vertex\n#include project_vertex\n}"),ze.add("shader/BasicLine.frag","uniform vec3 uColor;\n#include common\n#include fog_pars_fragment\nvoid main(){\ngl_FragColor = vec4( uColor, 1.0 );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n}"),ze.add("shader/Quad.vert","varying vec2 vUv;\nvoid main() {\nvUv = uv;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"),ze.add("shader/Quad.frag","varying vec2 vUv;\nuniform sampler2D tForeground;\nuniform float scale;\nvoid main() {\nvec4 foreground = texture2D( tForeground, vUv );\ngl_FragColor = foreground * scale;\n}");class di{constructor(){this.signals={updated:new J.Signal},this.maxDuration=-1/0,this.minDuration=1/0,this.avgDuration=14,this.lastDuration=1/0,this.prevFpsTime=0,this.lastFps=1/0,this.lastFrames=1,this.frames=0,this.count=0,this.begin()}update(){this.startTime=this.end(),this.currentTime=this.startTime,this.signals.updated.dispatch()}begin(){this.startTime=window.performance.now(),this.lastFrames=this.frames}end(){const t=window.performance.now();return this.count+=1,this.frames+=1,this.lastDuration=t-this.startTime,this.minDuration=Math.min(this.minDuration,this.lastDuration),this.maxDuration=Math.max(this.maxDuration,this.lastDuration),this.avgDuration-=this.avgDuration/30,this.avgDuration+=this.lastDuration/30,t>this.prevFpsTime+1e3&&(this.lastFps=this.frames,this.prevFpsTime=t,this.frames=0),t}}ze.add("shader/chunk/fog_fragment.glsl","#ifdef USE_FOG\nfloat depth = length( vViewPosition );\n#ifdef FOG_EXP2\nfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"),ze.add("shader/chunk/interior_fragment.glsl","if( gl_FrontFacing == false ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}"),ze.add("shader/chunk/matrix_scale.glsl","float matrixScale( in mat4 m ){\nvec4 r = m[ 0 ];\nreturn sqrt( r[ 0 ] * r[ 0 ] + r[ 1 ] * r[ 1 ] + r[ 2 ] * r[ 2 ] );\n}"),ze.add("shader/chunk/nearclip_vertex.glsl","#ifdef NEAR_CLIP\nif( vViewPosition.z < clipNear - 5.0 )\ngl_Position.z = 2.0 * gl_Position.w;\n#endif"),ze.add("shader/chunk/nearclip_fragment.glsl","#ifdef NEAR_CLIP\nif( vViewPosition.z < clipNear )\ndiscard;\n#endif"),ze.add("shader/chunk/opaque_back_fragment.glsl","#ifdef OPAQUE_BACK\n#ifdef FLIP_SIDED\nif( gl_FrontFacing == true ){\ngl_FragColor.a = 1.0;\n}\n#else\nif( gl_FrontFacing == false ){\ngl_FragColor.a = 1.0;\n}\n#endif\n#endif"),ze.add("shader/chunk/radiusclip_vertex.glsl","#ifdef RADIUS_CLIP\nif( distance( vViewPosition, vClipCenter ) > clipRadius + 5.0 )\ngl_Position.z = 2.0 * gl_Position.w;\n#endif"),ze.add("shader/chunk/radiusclip_fragment.glsl","#ifdef RADIUS_CLIP\nif( distance( vViewPosition, vClipCenter ) > clipRadius )\ndiscard;\n#endif"),ze.add("shader/chunk/unpack_color.glsl","vec3 unpackColor(float f) {\nvec3 color;\ncolor.r = floor(f / 256.0 / 256.0);\ncolor.g = floor((f - color.r * 256.0 * 256.0) / 256.0);\ncolor.b = floor(f - color.r * 256.0 * 256.0 - color.g * 256.0);\nreturn color / 255.0;\n}");const mi=/^(?!\/\/)\s*#include\s+(\S+)/gim,fi={};function pi(t,e={}){let i=t+"|";for(const t in e)i+=t+":"+e[t];if(!fi[i]){const r=function(t){if(void 0===t)return"";const e=[];for(const i in t){const r=t[i];r&&e.push(`#define ${i} ${r}`)}return e.join("\n")+"\n"}(e);let n=ze.get(`shader/${t}`);if(!n)throw new Error(`empty shader, '${t}'`);n=n.replace(mi,(function(t,e){const i=`shader/chunk/${e}.glsl`,r=ze.get(i)||s[e];if(!r)throw new Error(`empty chunk, '${e}'`);return r})),fi[i]=r+n}return fi[i]}if("undefined"!=typeof WebGLRenderingContext){const t=WebGLRenderingContext.prototype,e=t.getShaderParameter;t.getShaderParameter=function(){return!De||e.apply(this,arguments)};const i=t.getShaderInfoLog;t.getShaderInfoLog=function(){return De?i.apply(this,arguments):""};const r=t.getProgramParameter;t.getProgramParameter=function(e,i){return!De&&i===t.LINK_STATUS||r.apply(this,arguments)};const n=t.getProgramInfoLog;t.getProgramInfoLog=function(){return De?n.apply(this,arguments):""}}const gi=[[[0,0]],[[4,4],[-4,-4]],[[-2,-6],[6,-2],[-6,2],[2,6]],[[1,-3],[-1,3],[5,1],[-3,-5],[-5,5],[-7,-1],[3,7],[7,-7]],[[1,1],[-1,-3],[-3,2],[4,-1],[-5,-2],[2,5],[5,3],[3,-5],[-2,6],[0,-7],[-4,-6],[-6,4],[-8,0],[7,-4],[6,7],[-7,-8]],[[-4,-7],[-7,-5],[-3,-5],[-5,-4],[-1,-4],[-2,-2],[-6,-1],[-4,0],[-7,1],[-1,2],[-6,3],[-3,3],[-7,6],[-3,6],[-5,7],[-1,7],[5,-7],[1,-6],[6,-5],[4,-4],[2,-3],[7,-2],[1,-1],[4,-1],[2,1],[6,2],[0,4],[4,4],[2,5],[7,5],[5,6],[3,7]]];gi.forEach((t=>{t.forEach((t=>{t[0]*=.0625,t[1]*=.0625}))}));class yi{constructor(t,e,i,r){this.canvas=document.createElement("canvas"),this._viewer=i,this._factor=rt(r.factor,2),this._antialias=rt(r.antialias,!1),this._onProgress=r.onProgress,this._onFinish=r.onFinish,this._antialias&&(this._factor*=2),this._n=this._factor*this._factor,this._width=this._viewer.width,this._height=this._viewer.height,this._antialias?(this.canvas.width=this._width*this._factor/2,this.canvas.height=this._height*this._factor/2):(this.canvas.width=this._width*this._factor,this.canvas.height=this._height*this._factor),this._ctx=this.canvas.getContext("2d"),this._viewerSampleLevel=i.sampleLevel,this._viewer.setSampling(-1)}_renderTile(t){const e=this._viewer,i=this._width,r=this._height,n=this._factor,s=t%n*i,o=Math.floor(t/n)*r;if(e.camera.setViewOffset(i*n,r*n,s,o,i,r),e.render(),this._antialias){const t=Math.round((s+i)/2)-Math.round(s/2),n=Math.round((o+r)/2)-Math.round(o/2);this._ctx.drawImage(e.renderer.domElement,Math.round(s/2),Math.round(o/2),t,n)}else this._ctx.drawImage(e.renderer.domElement,Math.floor(s),Math.floor(o),Math.ceil(i),Math.ceil(r));"function"==typeof this._onProgress&&this._onProgress(t+1,this._n,!1)}_finalize(){this._viewer.setSampling(this._viewerSampleLevel),this._viewer.camera.view=null,"function"==typeof this._onFinish&&this._onFinish(this._n+1,this._n,!1)}render(){for(let t=0;t<=this._n;++t)t===this._n?this._finalize():this._renderTile(t)}renderAsync(){let t=0;const e=this._n,i=()=>{t===e?this._finalize():this._renderTile(t),t+=1};for(let t=0;t<=e;++t)setTimeout(i,0)}}const bi=2*Math.PI,_i=180/Math.PI;function xi(t,e,i=1,r=0,n){const s=n?n.length:t.length/i;let o=0,a=0;if(n)for(let c=0;ce&&(e=t[i]);return e}function Di(t){let e=1/0;for(let i=0,r=t.length;i=0;l--){for(c=o-1;c>=0;c--)if(u=4*(l*o+c),a[u]!==e||a[u+1]!==i||a[u+2]!==r||a[u+3]!==n){h=!0;break}if(h)break}const f=l;for(h=!1,c=o-1;c>=0;c--){for(l=s-1;l>=0;l--)if(u=4*(l*o+c),a[u]!==e||a[u+1]!==i||a[u+2]!==r||a[u+3]!==n){h=!0;break}if(h)break}const p=c,g=document.createElement("canvas");return g.width=p-m,g.height=f-d,g.getContext("2d").drawImage(t,m,d,g.width,g.height,0,0,g.width,g.height),g}(t,o?0:255*e.r,o?0:255*e.g,o?0:255*e.b,o?0:255)}return t}function m(t,i,r){"function"==typeof e.onProgress&&e.onProgress(t,i,r)}return new Promise((function(e,i){const n=new yi(a,c,t,{factor:r,antialias:s,onProgress:m,onFinish:function(r,s){d(n.canvas).toBlob((function(r){a.setClearAlpha(l),u(!0),t.requestRender(),m(s,s,!0),r?e(r):i("error creating image")}),"image/png")}});a.setClearAlpha(o?0:1),u(),n.renderAsync()}))}const Oi=new e,Ri=new i,Li=new i;const Ni=new t,zi=new i,Ui=new i;function Vi(t,e){zi.copy(e.projectionMatrix).invert(),Ui.copy(e.projectionMatrix).transpose(),t.traverse((function(t){const e=t.material;if(!e)return;const i=e.uniforms;i&&(i.projectionMatrixInverse&&i.projectionMatrixInverse.value.copy(zi),i.projectionMatrixTranspose&&i.projectionMatrixTranspose.value.copy(Ui))}))}function ji(t,e,i){const r=t.createShader(i);if(!r)return void console.log(`error creating WebGL shader ${i}`);t.shaderSource(r,e),t.compileShader(r);return t.getShaderParameter(r,t.COMPILE_STATUS)?r:(console.log(`error compiling shader ${r}: ${t.getShaderInfoLog(r)}`),t.deleteShader(r),null)}function Gi(t,e){const i=t.getExtension(e);return i||console.log(`extension '${e}' not available`),i}const Hi=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]);function qi(t){const e=document.createElement("canvas");e.width=16,e.height=16,e.style.width="16px",e.style.height="16px";const i=e.getContext("webgl")||e.getContext("experimental-webgl");if(!i)return console.log(`error creating webgl context for ${t}`),!1;if(!(i instanceof WebGLRenderingContext))return console.log("Got unexpected type for WebGL rendering context"),!1;Gi(i,"OES_texture_float"),Gi(i,"OES_texture_half_float"),Gi(i,"WEBGL_color_buffer_float");const r=ji(i,"\nattribute vec4 a_position;\n\nvoid main() {\n gl_Position = a_position;\n}",i.VERTEX_SHADER),n=ji(i,"\nprecision mediump float;\nuniform vec4 u_color;\nuniform sampler2D u_texture;\n\nvoid main() {\n gl_FragColor = texture2D(u_texture, vec2(0.5, 0.5)) * u_color;\n}",i.FRAGMENT_SHADER);if(!r||!n)return!1;const s=function(t,e,i,r){const n=t.createProgram();return n?(e.forEach((e=>t.attachShader(n,e))),i&&i.forEach(((e,i)=>{t.bindAttribLocation(n,r?r[i]:i,e)})),t.linkProgram(n),t.getProgramParameter(n,t.LINK_STATUS)?n:(console.log(`error linking program: ${t.getProgramInfoLog(n)}`),t.deleteProgram(n),null)):void console.log("error creating WebGL program")}(i,[r,n]);if(!s)return console.log("error creating WebGL program"),!1;i.useProgram(s);const o=i.getAttribLocation(s,"a_position"),a=i.getUniformLocation(s,"u_color");if(!a)return console.log("error getting 'u_color' uniform location"),!1;const c=i.createBuffer();i.bindBuffer(i.ARRAY_BUFFER,c),i.bufferData(i.ARRAY_BUFFER,Hi,i.STATIC_DRAW),i.enableVertexAttribArray(o),i.vertexAttribPointer(o,2,i.FLOAT,!1,0,0);const l=i.createTexture(),h=new Uint8Array([255,255,255,255]);i.bindTexture(i.TEXTURE_2D,l),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,1,1,0,i.RGBA,i.UNSIGNED_BYTE,h);const u=i.createTexture();i.bindTexture(i.TEXTURE_2D,u),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,1,1,0,i.RGBA,t,null),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.NEAREST),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.NEAREST);const d=i.createFramebuffer();i.bindFramebuffer(i.FRAMEBUFFER,d),i.framebufferTexture2D(i.FRAMEBUFFER,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,u,0);if(i.checkFramebufferStatus(i.FRAMEBUFFER)!==i.FRAMEBUFFER_COMPLETE)return console.log(`error creating framebuffer for ${t}`),!1;i.bindTexture(i.TEXTURE_2D,l),i.uniform4fv(a,[0,10,20,1]),i.drawArrays(i.TRIANGLES,0,6),i.bindTexture(i.TEXTURE_2D,u),i.bindFramebuffer(i.FRAMEBUFFER,null),i.clearColor(1,0,0,1),i.clear(i.COLOR_BUFFER_BIT),i.uniform4fv(a,[0,.1,.05,1]),i.drawArrays(i.TRIANGLES,0,6);const m=new Uint8Array(4);if(i.readPixels(0,0,1,1,i.RGBA,i.UNSIGNED_BYTE,m),0!==m[0]||m[1]<248||m[2]<248||m[3]<254)return console.log(`not able to actually render to ${t} texture`),!1;if(t===i.FLOAT){i.bindFramebuffer(i.FRAMEBUFFER,d);const t=new Float32Array(4);i.readPixels(0,0,1,1,i.RGBA,i.FLOAT,t);const e=i.getError();if(e)return console.log(`error reading pixels as float: '${function(t,e){switch(e){case t.NO_ERROR:return"no error";case t.INVALID_ENUM:return"invalid enum";case t.INVALID_VALUE:return"invalid value";case t.INVALID_OPERATION:return"invalid operation";case t.INVALID_FRAMEBUFFER_OPERATION:return"invalid framebuffer operation";case t.OUT_OF_MEMORY:return"out of memory";case t.CONTEXT_LOST_WEBGL:return"context lost"}return"unknown error"}(i,e)}'`),!1}return!0}const Wi=new Float32Array(100),Xi=new Uint8Array(100),Yi=[12,7,13,17,11,6,8,18,16,2,14,22,10,1,3,9,19,23,21,15,5,0,4,24,20],Ki=new i;function Zi(t,e,i,r,n){const s=n.uniforms,o=[];if(s&&(s.objectId&&(s.objectId.value=Se?this.id:this.id/255,o.push("objectId")),(s.modelViewMatrixInverse||s.modelViewMatrixInverseTranspose||s.modelViewProjectionMatrix||s.modelViewProjectionMatrixInverse)&&this.modelViewMatrix.multiplyMatrices(i.matrixWorldInverse,this.matrixWorld),s.modelViewMatrixInverse&&(s.modelViewMatrixInverse.value.copy(this.modelViewMatrix).invert(),o.push("modelViewMatrixInverse")),s.modelViewMatrixInverseTranspose&&(s.modelViewMatrixInverse?s.modelViewMatrixInverseTranspose.value.copy(s.modelViewMatrixInverse.value).transpose():s.modelViewMatrixInverseTranspose.value.copy(this.modelViewMatrix).invert().transpose(),o.push("modelViewMatrixInverseTranspose")),s.modelViewProjectionMatrix&&(s.modelViewProjectionMatrix.value.multiplyMatrices(i.projectionMatrix,this.modelViewMatrix),o.push("modelViewProjectionMatrix")),s.modelViewProjectionMatrixInverse&&(s.modelViewProjectionMatrix?(Ki.copy(s.modelViewProjectionMatrix.value),s.modelViewProjectionMatrixInverse.value.copy(Ki.invert())):(Ki.multiplyMatrices(i.projectionMatrix,this.modelViewMatrix),s.modelViewProjectionMatrixInverse.value.copy(Ki.invert())),o.push("modelViewProjectionMatrixInverse")),o.length)){const e=t.properties.get(n);if(e.program){const i=t.getContext(),r=e.program;i.useProgram(r.program);const n=r.getUniforms();o.forEach((function(t){n.setValue(i,t,s[t].value)}))}}}class Qi{constructor(t){if(this.boundingBox=new a,this.boundingBoxSize=new e,this.boundingBoxLength=0,this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}},this.distVector=new e,this.signals={ticked:new tt,rendered:new tt},"string"==typeof t){const e=document.getElementById(t);this.container=null===e?document.createElement("div"):e}else t instanceof HTMLElement?this.container=t:this.container=document.createElement("div");if(this.container===document.body)this.width=window.innerWidth||1,this.height=window.innerHeight||1;else{const t=this.container.getBoundingClientRect();this.width=t.width||1,this.height=t.height||1,this.container.style.overflow="hidden"}this.wrapper=document.createElement("div"),this.wrapper.style.position="relative",this.container.appendChild(this.wrapper),this._initParams(),this._initStats(),this._initCamera(),this._initScene(),!1!==this._initRenderer()?(this._initHelper(),this.setBackground(),this.setFog(),this.animate=this.animate.bind(this)):ke.error("Viewer: could not initialize renderer")}_initParams(){this.parameters={fogColor:new n(0),fogNear:50,fogFar:100,backgroundColor:new n(0),cameraType:"perspective",cameraFov:40,cameraEyeSep:.3,cameraZ:-80,clipNear:0,clipFar:100,clipDist:10,clipMode:"scene",clipScale:"relative",lightColor:new n(14540253),lightIntensity:1.2,ambientColor:new n(14540253),ambientIntensity:.3,sampleLevel:0,outputColorSpace:"srgb-linear"}}_initCamera(){const t=new e(0,0,0),{width:i,height:r}=this;this.perspectiveCamera=new c(this.parameters.cameraFov,i/r),this.perspectiveCamera.position.z=this.parameters.cameraZ,this.perspectiveCamera.lookAt(t),this.orthographicCamera=new l(i/-2,i/2,r/2,r/-2),this.orthographicCamera.position.z=this.parameters.cameraZ,this.orthographicCamera.lookAt(t),this.stereoCamera=new h,this.stereoCamera.aspect=.5,this.stereoCamera.eyeSep=this.parameters.cameraEyeSep;const n=this.parameters.cameraType;if("orthographic"===n)this.camera=this.orthographicCamera;else{if("perspective"!==n&&"stereo"!==n)throw new Error(`Unknown cameraType '${n}'`);this.camera=this.perspectiveCamera}this.camera.updateProjectionMatrix()}_initStats(){this.stats=new di}_initScene(){this.scene||(this.scene=new u,this.scene.name="scene"),this.rotationGroup=new d,this.rotationGroup.name="rotationGroup",this.scene.add(this.rotationGroup),this.translationGroup=new d,this.translationGroup.name="translationGroup",this.rotationGroup.add(this.translationGroup),this.modelGroup=new d,this.modelGroup.name="modelGroup",this.translationGroup.add(this.modelGroup),this.pickingGroup=new d,this.pickingGroup.name="pickingGroup",this.translationGroup.add(this.pickingGroup),this.backgroundGroup=new d,this.backgroundGroup.name="backgroundGroup",this.translationGroup.add(this.backgroundGroup),this.helperGroup=new d,this.helperGroup.name="helperGroup",this.translationGroup.add(this.helperGroup),this.scene.fog=new m(this.parameters.fogColor.getHex()),this.directionalLight=new f(this.parameters.lightColor.getHex(),this.parameters.lightIntensity),this.scene.add(this.directionalLight),this.ambientLight=new p(this.parameters.ambientColor.getHex(),this.parameters.ambientIntensity),this.scene.add(this.ambientLight)}_initRenderer(){const t=window.devicePixelRatio,{width:e,height:i}=this;try{this.renderer=new g({preserveDrawingBuffer:!0,alpha:!0,antialias:!0})}catch(t){return this.wrapper.innerHTML='

Your browser/graphics card does not seem to support WebGL.

Find out how to get it here.

',!1}this.renderer.setPixelRatio(t),this.renderer.setSize(e,i),this.renderer.autoClear=!1,this.renderer.sortObjects=!0,this.renderer.outputColorSpace=this.parameters.outputColorSpace,this.renderer.useLegacyLights=!0;const r=this.renderer.getContext();this.renderer.capabilities.isWebGL2?(Ie(!0),Ce(this.renderer.extensions.get("EXT_color_buffer_float")),this.supportsHalfFloat=!0):(Ie(this.renderer.extensions.get("EXT_frag_depth")),this.renderer.extensions.get("OES_element_index_uint"),Ce(this.renderer.extensions.get("OES_texture_float")&&this.renderer.extensions.get("WEBGL_color_buffer_float")||this.renderer.extensions.get("OES_texture_float")&&qi(r.FLOAT)),this.renderer.extensions.get("OES_texture_float"),this.supportsHalfFloat=this.renderer.extensions.get("OES_texture_half_float")&&qi(36193)),this.wrapper.appendChild(this.renderer.domElement);const n=e*t,s=i*t;De&&console.log(JSON.stringify({Browser:ve,OES_texture_float:!!this.renderer.extensions.get("OES_texture_float"),OES_texture_half_float:!!this.renderer.extensions.get("OES_texture_half_float"),WEBGL_color_buffer_float:!!this.renderer.extensions.get("WEBGL_color_buffer_float"),"testTextureSupport Float":qi(r.FLOAT),"testTextureSupport HalfFloat":qi(36193),"this.supportsHalfFloat":this.supportsHalfFloat,SupportsReadPixelsFloat:Se},null,2)),this.pickingTarget=new y(n,s,{minFilter:b,magFilter:b,stencilBuffer:!1,format:_,type:Se?D:x}),this.pickingTarget.texture.generateMipmaps=!1,this.pickingTarget.texture.colorSpace=this.parameters.outputColorSpace,this.renderer.setRenderTarget(this.pickingTarget),this.renderer.clear(),this.renderer.setRenderTarget(null),this.sampleTarget=new y(n,s,{minFilter:v,magFilter:v,format:_,type:this.supportsHalfFloat?w:Se?D:x}),this.sampleTarget.texture.colorSpace=this.parameters.outputColorSpace,this.holdTarget=new y(n,s,{minFilter:b,magFilter:b,format:_,type:this.supportsHalfFloat?w:Se?D:x}),this.holdTarget.texture.colorSpace=this.parameters.outputColorSpace,this.compositeUniforms={tForeground:new A(this.sampleTarget.texture),scale:new A(1)},this.compositeMaterial=new S({uniforms:this.compositeUniforms,vertexShader:pi("Quad.vert"),fragmentShader:pi("Quad.frag"),premultipliedAlpha:!0,transparent:!0,blending:C,depthTest:!1,depthWrite:!1}),this.compositeCamera=new l(-1,1,1,-1,0,1),this.compositeScene=new u,this.compositeScene.name="compositeScene",this.compositeScene.add(new P(new I(2,2),this.compositeMaterial))}_initHelper(){const t=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7]),e=new Float32Array(24),i=new k;i.setIndex(new M(t,1)),i.setAttribute("position",new M(e,3));const r=new S({uniforms:{uColor:{value:new n("skyblue")}},vertexShader:pi("BasicLine.vert"),fragmentShader:pi("BasicLine.frag")});this.boundingBoxMesh=new T(i,r),this.helperGroup.add(this.boundingBoxMesh)}updateHelper(){const t=this.boundingBoxMesh.geometry.attributes.position,e=t.array,{min:i,max:r}=this.boundingBox;e[0]=r.x,e[1]=r.y,e[2]=r.z,e[3]=i.x,e[4]=r.y,e[5]=r.z,e[6]=i.x,e[7]=i.y,e[8]=r.z,e[9]=r.x,e[10]=i.y,e[11]=r.z,e[12]=r.x,e[13]=r.y,e[14]=i.z,e[15]=i.x,e[16]=r.y,e[17]=i.z,e[18]=i.x,e[19]=i.y,e[20]=i.z,e[21]=r.x,e[22]=i.y,e[23]=i.z,t.needsUpdate=!0,this.boundingBox.isEmpty()||this.boundingBoxMesh.geometry.computeBoundingSphere()}get cameraDistance(){return Math.abs(this.camera.position.z)}set cameraDistance(t){this.camera.position.z=-t}add(t,e){e?e.forEach((e=>this.addBuffer(t,e))):this.addBuffer(t),t.group.name="meshGroup",t.wireframeGroup.name="wireframeGroup",t.parameters.background?(this.backgroundGroup.add(t.group),this.backgroundGroup.add(t.wireframeGroup)):(this.modelGroup.add(t.group),this.modelGroup.add(t.wireframeGroup)),t.pickable&&this.pickingGroup.add(t.pickingGroup),De&&this.updateHelper()}addBuffer(t,e){function i(r){r instanceof d?r.children.forEach(i):(r.userData.buffer=t,r.userData.instance=e,r.onBeforeRender=Zi)}const r=t.getMesh();e&&r.applyMatrix4(e.matrix),i(r),t.group.add(r);const n=t.getWireframeMesh();if(e&&(n.matrix.copy(r.matrix),n.position.copy(r.position),n.quaternion.copy(r.quaternion),n.scale.copy(r.scale)),i(n),t.wireframeGroup.add(n),t.pickable){const n=t.getPickingMesh();e&&(n.matrix.copy(r.matrix),n.position.copy(r.position),n.quaternion.copy(r.quaternion),n.scale.copy(r.scale)),i(n),t.pickingGroup.add(n)}e?this._updateBoundingBox(t.geometry,t.matrix,e.matrix):this._updateBoundingBox(t.geometry,t.matrix)}remove(t){this.translationGroup.children.forEach((function(e){e.remove(t.group),e.remove(t.wireframeGroup)})),t.pickable&&this.pickingGroup.remove(t.pickingGroup),this.updateBoundingBox(),De&&this.updateHelper()}_updateBoundingBox(t,e,i){const r=this.boundingBox;function n(t,e,i){null==t.boundingBox&&t.computeBoundingBox();const n=t.boundingBox.clone();e&&n.applyMatrix4(e),i&&n.applyMatrix4(i),n.min.equals(n.max)&&n.expandByScalar(5),r.union(n)}function s(t){if(void 0!==t.geometry){let e,i;t.userData.buffer&&(e=t.userData.buffer.matrix),t.userData.instance&&(i=t.userData.instance.matrix),n(t.geometry,e,i)}}t?n(t,e,i):(r.makeEmpty(),this.modelGroup.traverse(s),this.backgroundGroup.traverse(s)),r.getSize(this.boundingBoxSize),this.boundingBoxLength=this.boundingBoxSize.length()}updateBoundingBox(){this._updateBoundingBox(),De&&this.updateHelper()}getPickingPixels(){const{width:t,height:e}=this,i=t*e*4,r=Se?new Float32Array(i):new Uint8Array(i);return this.render(!0),this.renderer.readRenderTargetPixels(this.pickingTarget,0,0,t,e,r),r}getImage(t){return new Promise((e=>{if(t){const{width:t,height:i}=this,r=t*i*4;let n=this.getPickingPixels();if(Se){const t=new Uint8Array(r);for(let e=0;e500&&!this.isStill&&this.sampleLevel<3&&-1!==this.sampleLevel){const t=this.sampleLevel;this.sampleLevel=3,this.renderPending=!0,this.render(),this.isStill=!0,this.sampleLevel=t,De&&ke.log("rendered still frame")}this.frameRequest=window.requestAnimationFrame(this.animate)}pick(t,e){if("stereo"===this.parameters.cameraType)return{pid:0,instance:void 0,picker:void 0};t*=window.devicePixelRatio,e*=window.devicePixelRatio,t=Math.max(t-2,0),e=Math.max(e-2,0);let i,r,n=0;const s=Se?Wi:Xi;this.render(!0),this.renderer.readRenderTargetPixels(this.pickingTarget,t,e,5,5,s);for(let t=0;t22&&(this.stats.begin(),this.isStill=!1),this.renderPending=!0,window.requestAnimationFrame((()=>{this.render(),this.stats.update()})))}updateZoom(){const t=It(this.perspectiveCamera.fov),e=2*Math.tan(t/2)*this.cameraDistance;this.orthographicCamera.zoom=this.height/e}absoluteToRelative(t){return 50*(1-t/this.bRadius)}relativeToAbsolute(t){return this.bRadius*(1-t/50)}__updateClipping(){const t=this.parameters;this.bRadius=Math.max(10,.5*this.boundingBoxLength),isFinite(this.bRadius)||(this.bRadius=50),this.camera.getWorldPosition(this.distVector),this.cDist=this.distVector.length(),this.cDist||(this.cameraDistance=Math.abs(t.cameraZ),this.cDist=Math.abs(t.cameraZ));const e=this.scene.fog;if(e.color.set(t.fogColor),"camera"===t.clipMode)this.camera.near=t.clipNear,this.camera.far=t.clipFar,e.near=t.fogNear,e.far=t.fogFar;else if("absolute"===t.clipScale)this.camera.near=this.cDist-t.clipNear,this.camera.far=this.cDist+t.clipFar,e.near=this.cDist-t.fogNear,e.far=this.cDist+t.fogFar;else{const i=(50-t.clipNear)/50,r=-(50-t.clipFar)/50;this.camera.near=this.cDist-this.bRadius*i,this.camera.far=this.cDist+this.bRadius*r;const n=(50-t.fogNear)/50,s=-(50-t.fogFar)/50;e.near=this.cDist-this.bRadius*n,e.far=this.cDist+this.bRadius*s}"camera"!==t.clipMode&&("PerspectiveCamera"===this.camera.type?(this.camera.near=Math.max(.1,t.clipDist,this.camera.near),this.camera.far=Math.max(1,this.camera.far),e.near=Math.max(.1,e.near),e.far=Math.max(1,e.far)):"OrthographicCamera"===this.camera.type&&t.clipDist>0&&(this.camera.near=Math.max(t.clipDist,this.camera.near)))}__updateCamera(){const e=this.camera;e.updateMatrix(),e.updateMatrixWorld(!0),e.updateProjectionMatrix(),function(e,i,r,n,s){let o=new t;r.getSize(o);const a=o.height,c=r.getPixelRatio(),l="OrthographicCamera"===i.type;Ni.set(o.width,o.height),zi.copy(i.projectionMatrix).invert(),Ui.copy(i.projectionMatrix).transpose(),e.traverse((function(t){const e=t.material;if(!e)return;const i=e.uniforms;if(i){if(e.clipNear){const t=(50-e.clipNear)/50,r=n-s*t;i.clipNear.value=r}i.canvasHeight&&(i.canvasHeight.value=a),i.resolution&&i.resolution.value.copy(Ni),i.pixelRatio&&(i.pixelRatio.value=c),i.projectionMatrixInverse&&i.projectionMatrixInverse.value.copy(zi),i.projectionMatrixTranspose&&i.projectionMatrixTranspose.value.copy(Ui),i.ortho&&(i.ortho.value=l)}}))}(this.scene,e,this.renderer,this.cDist,this.bRadius),function(t,e){t.traverseVisible((function(t){if(!(t instanceof o&&t.userData.buffer.parameters.sortParticles))return;const i=t.geometry.attributes,r=i.position.count;if(0===r)return;let n,s,a,c,l,h,u,d;Ri.multiplyMatrices(e.matrixWorldInverse,t.matrixWorld),Li.multiplyMatrices(e.projectionMatrix,Ri),t.userData.sortData?(n=t.userData.sortData,a=n.__zArray,s=n.__sortArray,c=n.__cmpFn):(a=new Float32Array(r),s=new Uint32Array(r),c=function(t,e){const i=a[t],r=a[e];return i>r?1:ie?1:t=l&&e(t[o],s)>0;)t[o+1]=t[o],--o;t[o+1]=s}if(-1===c)break;h=n[c--],l=n[c--]}else{for(o=l+1,a=h,u(l+h>>1,o),e(t[l],t[h])>0&&u(l,h),e(t[o],t[h])>0&&u(o,h),e(t[l],t[o])>0&&u(l,o),s=t[o];;){do{o++}while(e(t[o],s)<0);do{a--}while(e(t[a],s)>0);if(a=a-l?(n[++c]=o,n[++c]=h,h=a-1):(n[++c]=l,n[++c]=a-1,l=o)}}(s,c);for(let t in i){const e=i[t],o=e.array,a=e.itemSize;n[t]||(n[t]=new Float32Array(a*r)),d=n[t],n[t]=o;for(let t=0;t0&&"stereo"!==this.parameters.cameraType?this.__renderSuperSample(e,i):this.__renderModelGroup(e,i)}render(t=!1,e){if(this.rendering)ke.warn("'tried to call 'render' from within 'render'");else{this.rendering=!0;try{this.__updateClipping(),this.__updateCamera(),this.__updateLights(),this.updateInfo(!0),"stereo"===this.parameters.cameraType?this.__renderStereo(t,e):this.__render(t,this.camera,e),this.lastRenderedPicking=t}finally{this.rendering=!1,this.renderPending=!1}this.signals.rendered.dispatch()}}clear(){ke.log("scene cleared"),this.scene.remove(this.rotationGroup),this._initScene(),this.renderer.clear()}dispose(){this.renderer.dispose(),window.cancelAnimationFrame(this.frameRequest)}}const Ji=1,tr=2,er=3;function ir(t){const e=t.touches[0].pageX-t.touches[1].pageX,i=t.touches[0].pageY-t.touches[1].pageY;return Math.sqrt(e*e+i*i)}class rr{constructor(e,i={}){this.domElement=e,this.signals={moved:new tt,scrolled:new tt,dragged:new tt,dropped:new tt,clicked:new tt,hovered:new tt,doubleClicked:new tt},this.position=new t,this.prevPosition=new t,this.down=new t,this.canvasPosition=new t,this.prevClickCP=new t,this.moving=!1,this.hovering=!0,this.scrolled=!1,this.lastMoved=1/0,this.which=0,this.buttons=0,this.pressed=!1,this.altKey=!1,this.ctrlKey=!1,this.metaKey=!1,this.shiftKey=!1,this.domElement.style.touchAction="none",this.hoverTimeout=rt(i.hoverTimeout,50),this.handleScroll=rt(i.handleScroll,!0),this.doubleClickSpeed=rt(i.doubleClickSpeed,500),this._listen=this._listen.bind(this),this._onMousewheel=this._onMousewheel.bind(this),this._onMousemove=this._onMousemove.bind(this),this._onMousedown=this._onMousedown.bind(this),this._onMouseup=this._onMouseup.bind(this),this._onContextmenu=this._onContextmenu.bind(this),this._onTouchstart=this._onTouchstart.bind(this),this._onTouchend=this._onTouchend.bind(this),this._onTouchmove=this._onTouchmove.bind(this),this._listen();const r={passive:!1};document.addEventListener("mousewheel",this._onMousewheel,r),document.addEventListener("wheel",this._onMousewheel,r),document.addEventListener("MozMousePixelScroll",this._onMousewheel,r),document.addEventListener("mousemove",this._onMousemove,r),document.addEventListener("mousedown",this._onMousedown,r),document.addEventListener("mouseup",this._onMouseup,r),document.addEventListener("contextmenu",this._onContextmenu,r),document.addEventListener("touchstart",this._onTouchstart,r),document.addEventListener("touchend",this._onTouchend,r),document.addEventListener("touchmove",this._onTouchmove,r)}get key(){let t=0;return this.altKey&&(t+=1),this.ctrlKey&&(t+=2),this.metaKey&&(t+=4),this.shiftKey&&(t+=8),t}setParameters(t={}){this.hoverTimeout=rt(t.hoverTimeout,this.hoverTimeout)}_listen(){const t=window.performance.now(),e=this.canvasPosition;this.doubleClickPending&&t-this.lastClicked>this.doubleClickSpeed&&(this.doubleClickPending=!1),t-this.lastMoved>this.hoverTimeout&&(this.moving=!1),(this.scrolled||!this.moving&&!this.hovering)&&(this.scrolled=!1,-1!==this.hoverTimeout&&this.overElement&&(this.hovering=!0,this.signals.hovered.dispatch(e.x,e.y))),this.frameRequest=window.requestAnimationFrame(this._listen)}_onMousewheel(t){if(t.target!==this.domElement||!this.handleScroll)return;t.preventDefault(),this._setKeys(t);let e=0;"deltaY"in t&&"deltaMode"in t&&void 0!==t.deltaY&&void 0!==t.deltaMode?e=t.deltaMode===WheelEvent.DOM_DELTA_PIXEL?.025*-t.deltaY:t.deltaMode===WheelEvent.DOM_DELTA_LINE?-t.deltaY*(2.5/3):2.5*-t.deltaY:"deltaY"in t&&!("detail"in t)?e=.025*-t.deltaY:void 0!==t.wheelDelta?e=.025*-t.wheelDelta:void 0!==t.wheelDeltaY?e=.025*-t.wheelDeltaY:void 0!==t.detail&&(e=-t.detail/3),this.signals.scrolled.dispatch(e),setTimeout((()=>{this.scrolled=!0}),this.hoverTimeout)}_onMousemove(t){t.target===this.domElement?(t.preventDefault(),this.overElement=!0):this.overElement=!1,this._setKeys(t),this.moving=!0,this.hovering=!1,this.lastMoved=window.performance.now(),this.prevPosition.copy(this.position),this.position.set(t.clientX,t.clientY),this._setCanvasPosition(t);const e=this.prevPosition.x-this.position.x,i=this.prevPosition.y-this.position.y;this.signals.moved.dispatch(e,i),this.pressed&&this.signals.dragged.dispatch(e,i)}_onMousedown(t){t.target===this.domElement&&(t.preventDefault(),this._setKeys(t),this.moving=!1,this.hovering=!1,this.down.set(t.clientX,t.clientY),this.position.set(t.clientX,t.clientY),this.which=t.which,this.buttons=function(t){if("object"==typeof t){if("buttons"in t)return t.buttons;if("which"in t){const e=t.which;if(2===e)return 4;if(3===e)return 2;if(e>0)return 1<=0)return 1<2&&this.handleScroll&&this.position.distanceTo(this.prevPosition)<2)this.which=0,this.buttons=0,this.signals.scrolled.dispatch(i/2);else{this.which=3,this.buttons=2;const t=this.prevPosition.x-this.position.x,e=this.prevPosition.y-this.position.y;this.signals.moved.dispatch(t,e),this.pressed&&this.signals.dragged.dispatch(t,e)}}}}_distance(){return this.position.distanceTo(this.down)}_setCanvasPosition(t){const e=this.domElement.getBoundingClientRect();let i,r;"clientX"in t&&"clientY"in t?(i=t.clientX-e.left,r=t.clientY-e.top):(i=t.offsetX,r=t.offsetY),this.canvasPosition.set(i,e.height-r)}_setKeys(t){this.altKey=t.altKey,this.ctrlKey=t.ctrlKey,this.metaKey=t.metaKey,this.shiftKey=t.shiftKey}dispose(){document.removeEventListener("mousewheel",this._onMousewheel),document.removeEventListener("wheel",this._onMousewheel),document.removeEventListener("MozMousePixelScroll",this._onMousewheel),document.removeEventListener("mousemove",this._onMousemove),document.removeEventListener("mousedown",this._onMousedown),document.removeEventListener("mouseup",this._onMouseup),document.removeEventListener("contextmenu",this._onContextmenu),document.removeEventListener("touchstart",this._onTouchstart),document.removeEventListener("touchend",this._onTouchend),document.removeEventListener("touchmove",this._onTouchmove),window.cancelAnimationFrame(this.frameRequest)}}const nr=new i,sr=new i,or=new i,ar=new i,cr=new i,lr=new e,hr=new r,ur=new r,dr=new i,mr=new e,fr=new e;class pr{constructor(t,e={}){this.stage=t,this.rotateSpeed=rt(e.rotateSpeed,2),this.zoomSpeed=rt(e.zoomSpeed,1.2),this.panSpeed=rt(e.panSpeed,1),this.viewer=t.viewer,this.mouse=t.mouseObserver,this.controls=t.viewerControls}get component(){return this.stage.transformComponent}get atom(){return this.stage.transformAtom}_setPanVector(t,e,i=0){const r=this.controls.getCanvasScaleFactor(i);mr.set(t,e,0),mr.multiplyScalar(this.panSpeed*r)}_getRotateXY(t,e){return[this.rotateSpeed*-t*.01,this.rotateSpeed*e*.01]}_getCameraRotation(t){return t.extractRotation(this.viewer.camera.matrixWorld),t.multiply(sr.makeRotationY(Math.PI)),t}_transformPanVector(){this.component&&(dr.extractRotation(this.component.transform),dr.premultiply(this.viewer.rotationGroup.matrix),dr.invert(),dr.multiply(this._getCameraRotation(ar)),mr.applyMatrix4(dr))}zoom(t){this.controls.zoom(this.zoomSpeed*t*.02)}pan(t,e){this._setPanVector(t,e),dr.copy(this.viewer.rotationGroup.matrix).invert(),dr.multiply(this._getCameraRotation(ar)),mr.applyMatrix4(dr),this.controls.translate(mr)}panComponent(t,e){this.component&&(this._setPanVector(t,e),this._transformPanVector(),this.component.position.add(mr),this.component.updateMatrix())}panAtom(t,e){this.atom&&this.component&&(this.atom.positionToVector3(fr),fr.add(this.viewer.translationGroup.position),fr.applyMatrix4(this.viewer.rotationGroup.matrix),this._setPanVector(t,e,fr.z),this._transformPanVector(),this.atom.positionAdd(mr),this.component.updateRepresentations({position:!0}))}rotate(t,e){const[i,r]=this._getRotateXY(t,e);this._getCameraRotation(ar),lr.set(1,0,0),lr.applyMatrix4(ar),hr.setFromAxisAngle(lr,r),lr.set(0,1,0),lr.applyMatrix4(ar),ur.setFromAxisAngle(lr,i),hr.multiply(ur),ar.makeRotationFromQuaternion(hr),this.controls.applyMatrix(ar)}zRotate(t,e){const i=this.rotateSpeed*((-t+e)/-2)*.01;or.makeRotationZ(i),this.controls.applyMatrix(or)}rotateComponent(t,e){if(!this.component)return;const[i,r]=this._getRotateXY(t,e);this._getCameraRotation(cr),ar.extractRotation(this.component.transform),ar.premultiply(this.viewer.rotationGroup.matrix),ar.invert(),ar.premultiply(cr),lr.set(1,0,0),lr.applyMatrix4(ar),nr.makeRotationAxis(lr,r),lr.set(0,1,0),lr.applyMatrix4(ar),sr.makeRotationAxis(lr,i),nr.multiply(sr),hr.setFromRotationMatrix(nr),this.component.quaternion.premultiply(hr),this.component.quaternion.normalize(),this.component.updateMatrix()}}const gr=new e;class yr{constructor(t,e){this.stage=e,this.pid=t.pid,this.picker=t.picker,this.instance=t.instance,this.stage=e,this.controls=e.viewerControls,this.mouse=e.mouseObserver}get type(){return this.picker.type}get altKey(){return this.mouse.altKey}get ctrlKey(){return this.mouse.ctrlKey}get metaKey(){return this.mouse.metaKey}get shiftKey(){return this.mouse.shiftKey}get canvasPosition(){return this.mouse.canvasPosition}get component(){return this.stage.getComponentsByObject(this.picker.data).list[0]}get object(){return this.picker.getObject(this.pid)}get position(){return this.picker.getPosition(this.pid,this.instance,this.component)}get closestBondAtom(){if("bond"!==this.type||!this.bond)return;const t=this.bond,e=this.controls,i=this.canvasPosition,r=t.atom1.positionToVector3(),n=t.atom2.positionToVector3();r.applyMatrix4(this.component.matrix),n.applyMatrix4(this.component.matrix);const s=e.getPositionOnCanvas(r),o=e.getPositionOnCanvas(n);return c=s,l=o,(a=i).distanceTo(c)=t.length))return new yr(i,this.stage);console.error("pid >= picker.array.length")}}}const _r=new r,xr=new e,vr=new e,wr=new e,Ar=new e,Sr=new i,Cr=new e,Pr=new i;class Ir{constructor(t){this.stage=t,this.signals={changed:new J.Signal},this.viewer=t.viewer}get position(){return this.viewer.translationGroup.position}get rotation(){return this.viewer.rotationGroup.quaternion}changed(){this.viewer.requestRender(),this.signals.changed.dispatch()}getPositionOnCanvas(e,i){const r=xt(i,t);const n=this.viewer;return wr.copy(e).add(n.translationGroup.position).applyMatrix4(n.rotationGroup.matrix).project(n.camera),r.set((wr.x+1)*n.width/2,(wr.y+1)*n.height/2)}getCanvasScaleFactor(t=0){const e=this.viewer.camera;if(e instanceof l)return 1/e.zoom;{t=Math.abs(t),t+=this.getCameraDistance();const i=It(e.fov);return 2*t*Math.tan(i/2)/this.viewer.height}}getOrientation(t){const e=wt(t);e.copy(this.viewer.rotationGroup.matrix);const i=this.getCameraDistance();return e.scale(Ar.set(i,i,i)),e.setPosition(this.viewer.translationGroup.position),e}orient(t){wt(t).decompose(xr,_r,vr);const e=this.viewer;e.rotationGroup.setRotationFromQuaternion(_r),e.translationGroup.position.copy(xr),e.cameraDistance=vr.z,e.updateZoom(),this.changed()}translate(t){this.viewer.translationGroup.position.add(vt(t)),this.changed()}center(t){this.viewer.translationGroup.position.copy(vt(t)).negate(),this.changed()}zoom(t){this.distance(this.getCameraDistance()*(1-t))}getCameraDistance(){return this.viewer.cameraDistance}distance(t){this.viewer.cameraDistance=Math.max(Math.abs(t),.2),this.viewer.updateZoom(),this.changed()}spin(t,e){Sr.copy(this.viewer.rotationGroup.matrix).invert(),Cr.copy(vt(t)).applyMatrix4(Sr),this.viewer.rotationGroup.rotateOnAxis(Cr,e),this.changed()}rotate(t){this.viewer.rotationGroup.setRotationFromQuaternion(At(t)),this.changed()}align(t){Pr.copy(wt(t)).invert(),this.viewer.rotationGroup.setRotationFromMatrix(Pr),this.changed()}applyMatrix(t){this.viewer.rotationGroup.applyMatrix4(wt(t)),this.changed()}}class kr{constructor(t,e,...i){this.pausedTime=-1,this.elapsedDuration=0,this.pausedDuration=0,this.ignoreGlobalToggle=!1,this._paused=!1,this._resolveList=[],this.duration=rt(t,1e3),this.controls=e,this.startTime=window.performance.now(),this._init(...i)}get done(){return 1===this.alpha}get paused(){return this._paused}tick(t){if(!this._paused)return this.elapsedDuration=t.currentTime-this.startTime-this.pausedDuration,0===this.duration?this.alpha=1:this.alpha=Et(0,1,this.elapsedDuration/this.duration),this._tick(t),this.done&&this._resolveList.forEach((t=>t())),this.done}pause(t){t&&(this._hold=!0),-1===this.pausedTime&&(this.pausedTime=window.performance.now()),this._paused=!0}resume(t){!t&&this._hold||(this.pausedDuration+=window.performance.now()-this.pausedTime,this._paused=!1,this._hold=!1,this.pausedTime=-1)}toggle(){this._paused?this.resume():this.pause()}then(t){let e;return e=this.done?Promise.resolve():new Promise((t=>this._resolveList.push(t))),e.then(t)}}class Mr extends kr{constructor(t,e,...i){super(rt(t,1/0),e,...i)}_init(t,i){Array.isArray(t)?this.axis=(new e).fromArray(t):this.axis=rt(t,new e(0,1,0)),this.angle=rt(i,.01)}_tick(t){this.axis&&this.angle&&this.controls.spin(this.axis,this.angle*t.lastDuration/16)}}class Tr extends kr{constructor(t,e,...i){super(rt(t,1/0),e,...i),this.angleSum=0,this.direction=1}_init(t,i,r){Array.isArray(t)?this.axis=(new e).fromArray(t):this.axis=rt(t,new e(0,1,0)),this.angleStep=rt(i,.01),this.angleEnd=rt(r,.2)}_tick(t){if(!this.axis||!this.angleStep||!this.angleEnd)return;const e=Et(0,1,Math.abs(this.angleSum)/this.angleEnd),i=this.angleStep*this.direction*(1.1-e);this.controls.spin(this.axis,i*t.lastDuration/16),this.angleSum+=this.angleStep,this.angleSum>=this.angleEnd&&(this.direction*=-1,this.angleSum=-this.angleEnd)}}class Dr extends kr{_init(t,i){this.moveFrom=vt(rt(t,new e)),this.moveTo=vt(rt(i,new e))}_tick(){this.controls.position.lerpVectors(this.moveFrom,this.moveTo,this.alpha).negate(),this.controls.changed()}}class Br extends kr{_init(t,e){this.zoomFrom=t,this.zoomTo=e}_tick(){this.controls.distance(Bt(this.zoomFrom,this.zoomTo,this.alpha))}}class Fr extends kr{constructor(){super(...arguments),this._currentRotation=new r}_init(t,e){this.rotateFrom=At(t),this.rotateTo=At(e),this._currentRotation=new r}_tick(){this._currentRotation.copy(this.rotateFrom).slerp(this.rotateTo,this.alpha),this.controls.rotate(this._currentRotation)}}class Er extends kr{_init(t,e,i){this.valueFrom=t,this.valueTo=e,this.callback=i}_tick(){this.callback(Bt(this.valueFrom,this.valueTo,this.alpha))}}class $r extends kr{_init(t){this.callback=t}_tick(){1===this.alpha&&this.callback()}}class Or{constructor(t=[]){this._resolveList=[],this._list=t}get done(){return this._list.every((t=>t.done))}then(t){let e;return e=this.done?Promise.resolve():new Promise((t=>{this._resolveList.push(t),this._list.forEach((t=>{t.then((()=>{this._resolveList.forEach((t=>{t()})),this._resolveList.length=0}))}))})),e.then(t)}}class Rr{constructor(t){this.stage=t,this.animationList=[],this.finishedList=[],this.viewer=t.viewer,this.controls=t.viewerControls}get paused(){return this.animationList.every((t=>t.paused))}add(t){return 0===t.duration?t.tick(this.viewer.stats):this.animationList.push(t),t}remove(t){const e=this.animationList,i=e.indexOf(t);i>-1&&e.splice(i,1)}run(t){const e=this.finishedList,i=this.animationList,r=i.length;for(let n=0;nt.pause()))}resume(){this.animationList.forEach((t=>t.resume()))}toggle(){this.paused?this.resume():this.pause()}clear(){this.animationList.length=0}dispose(){this.clear()}}class Lr{constructor(t,e){if(this.fn=t,this.queue=[],this.pending=!1,this.next=this.next.bind(this),e){for(let t=0,i=e.length;tthis.run(t)))):this.pending=!1}push(t){this.queue.push(t),this.pending||this.next()}kill(){this.queue.length=0}length(){return this.queue.length}}class Nr{constructor(t,e,i){this.type="",this.parameters={lazy:{type:"boolean"},clipNear:{type:"range",step:1,max:100,min:0,buffer:!0},clipRadius:{type:"number",precision:1,max:1e3,min:0,buffer:!0},clipCenter:{type:"vector3",precision:1,buffer:!0},flatShaded:{type:"boolean",buffer:!0},opacity:{type:"range",step:.01,max:1,min:0,buffer:!0},depthWrite:{type:"boolean",buffer:!0},side:{type:"select",buffer:!0,options:{front:"front",back:"back",double:"double"}},wireframe:{type:"boolean",buffer:!0},colorData:{type:"hidden",update:"color"},colorScheme:{type:"select",update:"color",options:{}},colorScale:{type:"select",update:"color",options:Oe.getScales()},colorReverse:{type:"boolean",update:"color"},colorValue:{type:"color",update:"color"},colorDomain:{type:"hidden",update:"color"},colorMode:{type:"select",update:"color",options:Oe.getModes()},roughness:{type:"range",step:.01,max:1,min:0,buffer:!0},metalness:{type:"range",step:.01,max:1,min:0,buffer:!0},diffuse:{type:"color",buffer:!0},diffuseInterior:{type:"boolean",buffer:!0},useInteriorColor:{type:"boolean",buffer:!0},interiorColor:{type:"color",buffer:!0},interiorDarkening:{type:"range",step:.01,max:1,min:0,buffer:!0},matrix:{type:"hidden",buffer:!0},disablePicking:{type:"boolean",rebuild:!0}},this.viewer=e,this.tasks=new ui,this.queue=new Lr(this.make.bind(this)),this.bufferList=[],this.parameters.colorScheme&&(this.parameters.colorScheme.options=Oe.getSchemes()),this.toBePrepared=!1}init(t){const r=t||{};this.clipNear=rt(r.clipNear,0),this.clipRadius=rt(r.clipRadius,0),this.clipCenter=rt(r.clipCenter,new e),this.flatShaded=rt(r.flatShaded,!1),this.side=rt(r.side,"double"),this.opacity=rt(r.opacity,1),this.depthWrite=rt(r.depthWrite,!0),this.wireframe=rt(r.wireframe,!1),this.setColor(r.color,r),this.colorData=rt(r.colorData,void 0),this.colorScheme=rt(r.colorScheme,"uniform"),this.colorScale=rt(r.colorScale,""),this.colorReverse=rt(r.colorReverse,!1),this.colorValue=rt(r.colorValue,9474192),this.colorDomain=rt(r.colorDomain,void 0),this.colorMode=rt(r.colorMode,"hcl"),this.visible=rt(r.visible,!0),this.quality=rt(r.quality,void 0),this.roughness=rt(r.roughness,.4),this.metalness=rt(r.metalness,0),this.diffuse=rt(r.diffuse,16777215),this.diffuseInterior=rt(r.diffuseInterior,!1),this.useInteriorColor=rt(r.useInteriorColor,!1),this.interiorColor=rt(r.interiorColor,2236962),this.interiorDarkening=rt(r.interiorDarkening,0),this.lazy=rt(r.lazy,!1),this.lazyProps={build:!1,bufferParams:{},what:{}},this.matrix=rt(r.matrix,new i),this.disablePicking=rt(r.disablePicking,!1);const n=this.parameters;!0===n.sphereDetail&&(n.sphereDetail={type:"integer",max:3,min:0,rebuild:"impostor"}),!0===n.radialSegments&&(n.radialSegments={type:"integer",max:25,min:5,rebuild:"impostor"}),!0===n.openEnded&&(n.openEnded={type:"boolean",rebuild:"impostor",buffer:!0}),!0===n.disableImpostor&&(n.disableImpostor={type:"boolean",rebuild:!0}),"low"===r.quality?(n.sphereDetail&&(this.sphereDetail=0),n.radialSegments&&(this.radialSegments=5)):"medium"===r.quality?(n.sphereDetail&&(this.sphereDetail=1),n.radialSegments&&(this.radialSegments=10)):"high"===r.quality?(n.sphereDetail&&(this.sphereDetail=2),n.radialSegments&&(this.radialSegments=20)):(n.sphereDetail&&(this.sphereDetail=rt(r.sphereDetail,1)),n.radialSegments&&(this.radialSegments=rt(r.radialSegments,10))),n.openEnded&&(this.openEnded=rt(r.openEnded,!0)),n.disableImpostor&&(this.disableImpostor=rt(r.disableImpostor,!1))}getColorParams(t){return Object.assign({data:this.colorData,scheme:this.colorScheme,scale:this.colorScale,reverse:this.colorReverse,value:this.colorValue,domain:this.colorDomain,mode:this.colorMode,colorSpace:this.colorSpace},t)}getBufferParams(t={}){return Object.assign({clipNear:this.clipNear,clipRadius:this.clipRadius,clipCenter:this.clipCenter,flatShaded:this.flatShaded,opacity:this.opacity,depthWrite:this.depthWrite,side:this.side,wireframe:this.wireframe,roughness:this.roughness,metalness:this.metalness,diffuse:this.diffuse,diffuseInterior:this.diffuseInterior,useInteriorColor:this.useInteriorColor,interiorColor:this.interiorColor,interiorDarkening:this.interiorDarkening,matrix:this.matrix,disablePicking:this.disablePicking},t)}setColor(t,e){const i=Object.keys(Oe.getSchemes());if("string"==typeof t&&i.includes(t.toLowerCase()))e?e.colorScheme=t:this.setParameters({colorScheme:t});else if(void 0!==t){let i=new n(t).getHex();e?(e.colorScheme="uniform",e.colorValue=i):this.setParameters({colorScheme:"uniform",colorValue:i})}return this}prepare(t){}create(){}update(t){this.build()}build(t){if(!this.lazy||this.visible&&this.opacity){if(!this.toBePrepared)return this.tasks.increment(),void this.make();this.queue.length()>0?(this.tasks.change(1-this.queue.length()),this.queue.kill()):this.tasks.increment(),this.queue.push(t||!1)}else this.lazyProps.build=!0}make(t,e){De&&ke.time("Representation.make "+this.type);const i=()=>{t?(this.update(t),this.viewer.requestRender(),this.tasks.decrement(),e&&e()):(this.clear(),this.create(),this.manualAttach||this.disposed||(De&&ke.time("Representation.attach "+this.type),this.attach((()=>{De&&ke.timeEnd("Representation.attach "+this.type),this.tasks.decrement(),e&&e()})))),De&&ke.timeEnd("Representation.make "+this.type)};this.toBePrepared?this.prepare(i):i()}attach(t){this.setVisibility(this.visible),t()}setVisibility(t,e){if(this.visible=t,this.visible&&this.opacity){const t=this.lazyProps,e=t.bufferParams,i=t.what;if(t.build)return t.build=!1,this.build(),this;(Object.keys(e).length||Object.keys(i).length)&&(t.bufferParams={},t.what={},this.updateParameters(e,i))}return this.bufferList.forEach((function(e){e.setVisibility(t)})),e||this.viewer.requestRender(),this}setParameters(t,e={},i=!1){const r=t||{},n=this.parameters,s={};this.opacity||void 0===r.opacity||(this.lazyProps.build?(this.lazyProps.build=!1,i=!0):(Object.assign(s,this.lazyProps.bufferParams),Object.assign(e,this.lazyProps.what),this.lazyProps.bufferParams={},this.lazyProps.what={})),this.setColor(r.color,r);for(let t in r)if(void 0!==r[t]&&null!=n[t]&&(n[t].int&&(r[t]=parseInt(r[t])),n[t].float&&(r[t]=parseFloat(r[t])),r[t]!==this[t]||r[t].equals&&!r[t].equals(this[t]))){if(this[t]&&this[t].copy&&r[t].copy?this[t].copy(r[t]):this[t]&&this[t].set?this[t].set(r[t]):this[t]=r[t],n[t].buffer)if(!0===n[t].buffer)s[t]=r[t];else{s[n[t].buffer]=r[t]}n[t].update&&(e[n[t].update]=!0),!n[t].rebuild||"impostor"===n[t].rebuild&&Pe&&!this.disableImpostor||(i=!0)}return i?this.build():this.updateParameters(s,e),this}updateParameters(t={},e){if(this.lazy&&(!this.visible||!this.opacity)&&!1===t.hasOwnProperty("opacity"))return Object.assign(this.lazyProps.bufferParams,t),void Object.assign(this.lazyProps.what,e);this.bufferList.forEach((function(e){e.setParameters(t)})),Object.keys(e).length&&this.update(e),this.viewer.requestRender()}getParameters(){const t={lazy:this.lazy,visible:this.visible,quality:this.quality};return Object.keys(this.parameters).forEach((e=>{null!==this.parameters[e]&&(t[e]=this[e])})),t}clear(){this.bufferList.forEach((t=>{this.viewer.remove(t),t.dispose()})),this.bufferList.length=0,this.viewer.requestRender()}dispose(){this.disposed=!0,this.queue.kill(),this.tasks.dispose(),this.clear()}}class zr{constructor(t){this.pending=0,this.postCount=0,this.onmessageDict={},this.onerrorDict={},this.name=t,this.blobUrl=window.URL.createObjectURL($e.get(t)),this.worker=new Worker(this.blobUrl),$e.activeWorkerCount+=1,this.worker.onmessage=e=>{this.pending-=1;const i=e.data.__postId;De&&ke.timeEnd("Worker.postMessage "+t+" #"+i);const r=this.onmessageDict[i];r&&r.call(this.worker,e),delete this.onmessageDict[i],delete this.onerrorDict[i]},this.worker.onerror=e=>{if(this.pending-=1,e.data){const i=e.data.__postId,r=this.onerrorDict[i];r?r.call(this.worker,e):ke.error("Worker.onerror",i,t,e),delete this.onmessageDict[i],delete this.onerrorDict[i]}else ke.error("Worker.onerror",t,e)}}post(t={},e,i,r){this.onmessageDict[this.postCount]=i,this.onerrorDict[this.postCount]=r,t.__name=this.name,t.__postId=this.postCount,t.__debug=De,De&&ke.time(`Worker.postMessage ${this.name} #${this.postCount}`);try{this.worker.postMessage(t,e)}catch(e){ke.error("worker.post:",e),this.worker.postMessage(t)}return this.pending+=1,this.postCount+=1,this}terminate(){this.worker?(this.worker.terminate(),window.URL.revokeObjectURL(this.blobUrl),$e.activeWorkerCount-=1):ke.log("no worker to terminate")}}class Ur{constructor(t,e=2){this.pool=[],this.count=0,this.maxCount=Math.min(8,e),this.name=t}post(t={},e,i,r){const n=this.getNextWorker();return n?n.post(t,e,i,r):console.error("unable to get worker from pool"),this}terminate(){this.pool.forEach((function(t){t.terminate()}))}getNextWorker(){let t,e=1/0;for(let i=0;i=this.count){t=new zr(this.name),this.pool.push(t),this.count+=1;break}const r=this.pool[i];if(0===r.pending){t=r;break}r.pendingn&&(n=c),l>s&&(s=l),h>o&&(o=h)}return[Xr([e,i,r]),Xr([n,s,o])]}function Hr(t,e){for(let i=0,r=e.length;i0){const o=1/Math.sqrt(s);t[e]=i*o,t[e+1]=r*o,t[e+2]=n*o}}}function Xr(t){return new Float32Array(t||3)}function Yr(t,e,i){const r=e[0],n=e[1],s=e[2],o=i[0],a=i[1],c=i[2];t[0]=n*c-s*a,t[1]=s*o-r*c,t[2]=r*a-n*o}function Kr(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function Zr(t,e,i){t[0]=e[0]-i[0],t[1]=e[1]-i[1],t[2]=e[2]-i[2]}function Qr(t,e,i){t[0]=e[0]+i[0],t[1]=e[1]+i[1],t[2]=e[2]+i[2]}function Jr(t,e,i=0){t[0]=e[i],t[1]=e[i+1],t[2]=e[i+2]}function tn(t,e,i=0){e[i]=t[0],e[i+1]=t[1],e[i+2]=t[2]}function en(t){return t[0]*t[0]+t[1]*t[1]+t[2]*t[2]}function rn(t){return Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2])}function nn(t,e,i){sn(t,e,1/i)}function sn(t,e,i){t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i}function on(t,e){const i=en(e);0==i?(t[0]=e[0],t[1]=e[1],t[2]=e[2]):sn(t,e,1/Math.sqrt(i))}function an(t,e,i){t[0]=e[0]-i,t[1]=e[1]-i,t[2]=e[2]-i}function cn(t,e,i){t[0]=e[0]+i,t[1]=e[1]+i,t[2]=e[2]+i}function ln(t,e){t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2])}function hn(t,e){t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2])}function un(t,e){t[0]=-e[0],t[1]=-e[1],t[2]=-e[2]}function dn(t,e){const i=t[0],r=t[1],n=t[2],s=e[0],o=e[1],a=e[2],c=r*a-n*o,l=n*s-i*a,h=i*o-r*s,u=Math.sqrt(c*c+l*l+h*h),d=i*s+r*o+n*a;return Math.atan2(u,d)}function mn(t,i=9){const r=Math.floor(i/2),n=t.position1.length/3,s=3*(r*n),o=1/i,a=wi(t.position1,t.position2),c=new Float32Array(s),l=new Float32Array(s),h=new e;for(let e=0;e0){const e=3*f;s[e]=t.position2[3*u-3],s[e+1]=t.position2[3*u-2],s[e+1]=t.position2[3*u-1]}const y=new Float32Array(n),b=new Float32Array(s),_=vi(y,b),x=new Float32Array(o),v={position:_,position1:y,position2:b,color:x,color2:x};return a&&(v.radius=new Float32Array(a)),c&&t.picking&&(t.picking.array=new Float32Array(c),v.picking=t.picking),l&&(v.primitiveId=new Float32Array(l)),v}Ur.prototype.constructor=Ur,Gr.__deps=[Xr],nn.__deps=[sn],on.__deps=[sn,en];const gn=new e;class yn{static get Picker(){return Ge.get(this.type)}static get Buffer(){return je.get(this.type)}static getShapeKey(t){return this.type+t[0].toUpperCase()+t.substr(1)}static expandBoundingBox(t,e){}static valueToShape(t,e,i){const r=t._primitiveData[this.getShapeKey(e)];switch(this.fields[e]){case"v3":case"c":!function(t,e){void 0!==t.toArray?t=t.toArray():void 0!==t.x?t=[t.x,t.y,t.z]:void 0!==t.r&&(t=[t.r,t.g,t.b]),e.push.apply(e,t)}(i,r);break;default:r.push(i)}}static objectToShape(t,e){Object.keys(this.fields).forEach((i=>{this.valueToShape(t,i,e[i])})),this.valueToShape(t,"name",e.name),this.expandBoundingBox(t.boundingBox,e)}static valueFromShape(t,i,r){const s=t._primitiveData[this.getShapeKey(r)];switch(this.fields[r]){case"v3":return(new e).fromArray(s,3*i);case"c":return(new n).fromArray(s,3*i);default:return s[i]}}static objectFromShape(t,e){let i=this.valueFromShape(t,e,"name");void 0===i&&(i=`${this.type}: ${e} (${t.name})`);const r={shape:t,name:i};return Object.keys(this.fields).forEach((i=>{r[i]=this.valueFromShape(t,e,i)})),r}static arrayFromShape(t,e){const i=t._primitiveData[this.getShapeKey(e)];return"s"===this.fields[e]?i:new Float32Array(i)}static dataFromShape(t){const e={};return this.Picker&&(e.picking=new this.Picker(t)),Object.keys(this.fields).forEach((i=>{e[i]=this.arrayFromShape(t,i)})),e}static bufferFromShape(t,e){return new this.Buffer(this.dataFromShape(t),e)}}yn.type="",yn.fields={};class bn extends yn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(gn.fromArray(e.position))}}bn.type="sphere",bn.fields={position:"v3",color:"c",radius:"f"};class _n extends yn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(gn.fromArray(e.position))}}_n.type="box",_n.fields={position:"v3",color:"c",size:"f",heightAxis:"v3",depthAxis:"v3"};class xn extends _n{}xn.type="octahedron";class vn extends _n{}vn.type="tetrahedron";class wn extends yn{static positionFromShape(t,e){const i=this.valueFromShape(t,e,"position1"),r=this.valueFromShape(t,e,"position2");return i.add(r).multiplyScalar(.5)}static expandBoundingBox(t,e){t.expandByPoint(gn.fromArray(e.position1)),t.expandByPoint(gn.fromArray(e.position2))}static bufferFromShape(t,e={}){let i=this.dataFromShape(t);return"cylinder"===this.type&&e.dashedCylinder&&(i=fn(i)),new this.Buffer(i,e)}}wn.type="cylinder",wn.fields={position1:"v3",position2:"v3",color:"c",radius:"f"};class An extends wn{}An.type="arrow";class Sn extends wn{}Sn.type="cone";class Cn extends bn{}Cn.type="ellipsoid",Cn.fields={position:"v3",color:"c",radius:"f",majorAxis:"v3",minorAxis:"v3"};class Pn extends Cn{}Pn.type="torus";class In extends yn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(gn.fromArray(e.position))}}In.type="text",In.fields={position:"v3",color:"c",size:"f",text:"s"};class kn extends yn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(gn.fromArray(e.position))}}kn.type="point",kn.fields={position:"v3",color:"c"};class Mn extends yn{static positionFromShape(t,e){const i=this.valueFromShape(t,e,"position1"),r=this.valueFromShape(t,e,"position2");return i.add(r).multiplyScalar(.5)}static expandBoundingBox(t,e){t.expandByPoint(gn.fromArray(e.position1)),t.expandByPoint(gn.fromArray(e.position2))}}Mn.type="wideline",Mn.fields={position1:"v3",position2:"v3",color:"c"};class Tn{constructor(t,e){this.exp=3;const i=e||function(t){const{x:e,y:i,z:r}=t,n=new a,s=e.length,{min:o,max:c}=n;for(let t=0;t>this.exp),this.boundY=1+(i.max.y-this.minY>>this.exp),this.boundZ=1+(i.max.z-this.minZ>>this.exp);const r=this.boundX*this.boundY*this.boundZ,n=void 0!==t.count?t.count:t.x.length,s=t.x,o=t.y,c=t.z;let l=0;const h=new Uint32Array(r),u=new Int32Array(n);for(let t=0;t>this.exp,i=o[t]-this.minY>>this.exp,r=c[t]-this.minZ>>this.exp,n=(e*this.boundY+i)*this.boundZ+r;1===(h[n]+=1)&&(l+=1),u[t]=n}const d=new Uint16Array(l);for(let t=0,e=0;t0&&(h[t]=e+1,d[e]=i,e+=1)}const m=new Uint32Array(l);for(let t=1;t0){const i=e-1;p[m[i]+f[i]]=t,f[i]+=1}}this.grid=h,this.bucketCount=d,this.bucketOffset=m,this.bucketArray=p,this.xArray=s,this.yArray=o,this.zArray=c}within(t,e,i,r){const n=[];return this.eachWithin(t,e,i,r,(t=>n.push(t))),n}eachWithin(t,e,i,r,n){const s=r*r,o=Math.max(0,t-r-this.minX>>this.exp),a=Math.max(0,e-r-this.minY>>this.exp),c=Math.max(0,i-r-this.minZ>>this.exp),l=Math.min(this.boundX,1+(t+r-this.minX>>this.exp)),h=Math.min(this.boundY,1+(e+r-this.minY>>this.exp)),u=Math.min(this.boundZ,1+(i+r-this.minZ>>this.exp));for(let r=o;r0){const r=l-1,o=this.bucketOffset[r],a=o+this.bucketCount[r];for(let r=o;rr?n.set(this[e].subarray(0,r)):n.set(this[e]),this[e]=n}}growIfFull(){if(this.count>=this.length){const t=Math.round(1.5*this.length);this.resize(Math.max(256,t))}}copyFrom(t,e,i,r){for(let n=0,s=this._fields.length;n0;)h-=1;l<=h&&(l===c?c=h:h===c&&(c=l),(o=l)!==(a=h)&&(i.copyFrom(e,0,o,1),e.copyWithin(o,a,1),e.copyFrom(i,a,0,1)),l+=1,h-=1)}while(l<=h);r(n,h),r(l,s)}var o,a}(0,this.count-1),ke.timeEnd("Store.sort")}clear(){this.count=0}dispose(){for(let t=0,e=this._fields.length;t>>1&1431655765))+(t>>>2&858993459))+(t>>>4)&252645135)>>>24}class En{constructor(t,e){this.length=t,this._words=new Uint32Array(t+32>>>5),!0===e&&this.setAll()}get(t){return!!(this._words[t>>>5]&1<>>5]|=1<>>5]&=~(1<>>5]^=1<>>5,o=e>>>5;for(let t=s+1;t>>5]|=1<>>5]|=1<>>5]|=1<>>5]&=~(1<>>5]&=~(1<>>5]&=~(1<>>5]|=1<>>5]&=~(1<>>i,this}_isRangeValue(t,e,i){if(e>>5,o=e>>>5;for(let t=s+1;t>>5]&1<>>5]&1<>>5]&1<>>5]&1<>>5]&1<0){const{types:r,groups:n,centers:s,atomSets:o}=t;r.push(e.type),n.push(e.group),s.x.push(e.x/i),s.y.push(e.y/i),s.z.push(e.z/i),o.push(e.atomSet)}}const Nn=0,zn=["D-BETA-PEPTIDE, C-GAMMA LINKING","D-GAMMA-PEPTIDE, C-DELTA LINKING","D-PEPTIDE COOH CARBOXY TERMINUS","D-PEPTIDE NH3 AMINO TERMINUS","D-PEPTIDE LINKING","L-BETA-PEPTIDE, C-GAMMA LINKING","L-GAMMA-PEPTIDE, C-DELTA LINKING","L-PEPTIDE COOH CARBOXY TERMINUS","L-PEPTIDE NH3 AMINO TERMINUS","L-PEPTIDE LINKING","PEPTIDE LINKING","PEPTIDE-LIKE"],Un=["RNA OH 3 PRIME TERMINUS","RNA OH 5 PRIME TERMINUS","RNA LINKING"],Vn=["DNA OH 3 PRIME TERMINUS","DNA OH 5 PRIME TERMINUS","DNA LINKING","L-DNA LINKING","L-RNA LINKING"],jn=["D-SACCHARIDE","D-SACCHARIDE 1,4 AND 1,4 LINKING","D-SACCHARIDE 1,4 AND 1,6 LINKING","L-SACCHARIDE","L-SACCHARIDE 1,4 AND 1,4 LINKING","L-SACCHARIDE 1,4 AND 1,6 LINKING","SACCHARIDE"],Gn=["NON-POLYMER"].concat(["OTHER"],jn),Hn=["h","g","i"],qn=["e","b"],Wn=["s","t","l",""],Xn={H:1,D:1,T:1,HE:2,LI:3,BE:4,B:5,C:6,N:7,O:8,F:9,NE:10,NA:11,MG:12,AL:13,SI:14,P:15,S:16,CL:17,AR:18,K:19,CA:20,SC:21,TI:22,V:23,CR:24,MN:25,FE:26,CO:27,NI:28,CU:29,ZN:30,GA:31,GE:32,AS:33,SE:34,BR:35,KR:36,RB:37,SR:38,Y:39,ZR:40,NB:41,MO:42,TC:43,RU:44,RH:45,PD:46,AG:47,CD:48,IN:49,SN:50,SB:51,TE:52,I:53,XE:54,CS:55,BA:56,LA:57,CE:58,PR:59,ND:60,PM:61,SM:62,EU:63,GD:64,TB:65,DY:66,HO:67,ER:68,TM:69,YB:70,LU:71,HF:72,TA:73,W:74,RE:75,OS:76,IR:77,PT:78,AU:79,HG:80,TL:81,PB:82,BI:83,PO:84,AT:85,RN:86,FR:87,RA:88,AC:89,TH:90,PA:91,U:92,NP:93,PU:94,AM:95,CM:96,BK:97,CF:98,ES:99,FM:100,MD:101,NO:102,LR:103,RF:104,DB:105,SG:106,BH:107,HS:108,MT:109,DS:110,RG:111,CN:112,NH:113,FL:114,MC:115,LV:116,TS:117,OG:118},Yn={1:1.1,2:1.4,3:1.81,4:1.53,5:1.92,6:1.7,7:1.55,8:1.52,9:1.47,10:1.54,11:2.27,12:1.73,13:1.84,14:2.1,15:1.8,16:1.8,17:1.75,18:1.88,19:2.75,20:2.31,21:2.3,22:2.15,23:2.05,24:2.05,25:2.05,26:2.05,27:2,28:2,29:2,30:2.1,31:1.87,32:2.11,33:1.85,34:1.9,35:1.83,36:2.02,37:3.03,38:2.49,39:2.4,40:2.3,41:2.15,42:2.1,43:2.05,44:2.05,45:2,46:2.05,47:2.1,48:2.2,49:2.2,50:1.93,51:2.17,52:2.06,53:1.98,54:2.16,55:3.43,56:2.68,57:2.5,58:2.48,59:2.47,60:2.45,61:2.43,62:2.42,63:2.4,64:2.38,65:2.37,66:2.35,67:2.33,68:2.32,69:2.3,70:2.28,71:2.27,72:2.25,73:2.2,74:2.1,75:2.05,76:2,77:2,78:2.05,79:2.1,80:2.05,81:1.96,82:2.02,83:2.07,84:1.97,85:2.02,86:2.2,87:3.48,88:2.83,89:2,90:2.4,91:2,92:2.3,93:2,94:2,95:2,96:2,97:2,98:2,99:2,100:2,101:2,102:2,103:2,104:2,105:2,106:2,107:2,108:2,109:2,110:2,111:2,112:2,113:2,114:2,115:2,116:2,117:2,118:2},Kn={1:.31,2:.28,3:1.28,4:.96,5:.84,6:.76,7:.71,8:.66,9:.57,10:.58,11:1.66,12:1.41,13:1.21,14:1.11,15:1.07,16:1.05,17:1.02,18:1.06,19:2.03,20:1.76,21:1.7,22:1.6,23:1.53,24:1.39,25:1.39,26:1.32,27:1.26,28:1.24,29:1.32,30:1.22,31:1.22,32:1.2,33:1.19,34:1.2,35:1.2,36:1.16,37:2.2,38:1.95,39:1.9,40:1.75,41:1.64,42:1.54,43:1.47,44:1.46,45:1.42,46:1.39,47:1.45,48:1.44,49:1.42,50:1.39,51:1.39,52:1.38,53:1.39,54:1.4,55:2.44,56:2.15,57:2.07,58:2.04,59:2.03,60:2.01,61:1.99,62:1.98,63:1.98,64:1.96,65:1.94,66:1.92,67:1.92,68:1.89,69:1.9,70:1.87,71:1.87,72:1.75,73:1.7,74:1.62,75:1.51,76:1.44,77:1.41,78:1.36,79:1.36,80:1.32,81:1.45,82:1.46,83:1.48,84:1.4,85:1.5,86:1.5,87:2.6,88:2.21,89:2.15,90:2.06,91:2,92:1.96,93:1.9,94:1.87,95:1.8,96:1.69,97:1.6,98:1.6,99:1.6,100:1.6,101:1.6,102:1.6,103:1.6,104:1.6,105:1.6,106:1.6,107:1.6,108:1.6,109:1.6,110:1.6,111:1.6,112:1.6,113:1.6,114:1.6,115:1.6,116:1.6,117:1.6,118:1.6},Zn={1:[1],2:[0],3:[1],4:[2],5:[3],6:[4],7:[3],8:[2],9:[1],10:[0],11:[1],12:[2],13:[6],14:[6],15:[3,5,7],16:[2,4,6],17:[1],18:[0],19:[1],20:[2],31:[3],32:[4],33:[3,5],34:[2,4,6],35:[1],36:[0],37:[1],38:[2],49:[3],50:[4],51:[3,5],52:[2],53:[1,2,5],54:[0,2],55:[1],56:[2],81:[3],82:[4],83:[3],84:[2],85:[1],86:[0],87:[1],88:[2]},Qn={1:1,2:2,3:1,4:2,5:3,6:4,7:5,8:6,9:7,10:8,11:1,12:2,13:3,14:4,15:5,16:6,17:7,18:8,19:1,20:2,21:3,22:4,23:5,24:6,25:7,26:8,27:9,28:10,29:11,30:2,31:3,32:4,33:5,34:6,35:7,36:8,37:1,38:2,39:3,40:4,41:5,42:6,43:7,44:8,45:9,46:10,47:11,48:2,49:3,50:4,51:5,52:6,53:7,54:8,55:1,56:2,57:3,58:4,59:3,60:4,61:5,62:6,63:7,64:8,65:9,66:10,67:11,68:12,69:13,70:14,71:15,72:4,73:5,74:6,75:7,76:8,77:9,78:10,79:11,80:2,81:3,82:4,83:5,84:6,85:7,86:8,87:1,88:2,89:3,90:4,91:3,92:4,93:5,94:6,95:7,96:8,97:9,98:10,99:11,100:12,101:13,102:14,103:15,104:2,105:2,106:2,107:2,108:2,109:2,110:2,111:2,112:2,113:3,114:4,115:5,116:6,117:7,118:8},Jn={ALA:[.17,.5,.33],ARG:[.81,1.81,1],ASN:[.42,.85,.43],ASP:[1.23,3.64,2.41],ASH:[-.07,.43,.5],CYS:[-.24,-.02,.22],GLN:[.58,.77,.19],GLU:[2.02,3.63,1.61],GLH:[-.01,.11,.12],GLY:[.01,1.15,1.14],HIS:[.17,.11,-.06],ILE:[-.31,-1.12,-.81],LEU:[-.56,-1.25,-.69],LYS:[.99,2.8,1.81],MET:[-.23,-.67,-.44],PHE:[-1.13,-1.71,-.58],PRO:[.45,.14,-.31],SER:[.13,.46,.33],THR:[.14,.25,.11],TRP:[-1.85,-2.09,-.24],TYR:[-.94,-.71,.23],VAL:[.07,-.46,-.53]},ts=[0,0,0],es={HIS:"H",ARG:"R",LYS:"K",ILE:"I",PHE:"F",LEU:"L",TRP:"W",ALA:"A",MET:"M",PRO:"P",CYS:"C",ASN:"N",VAL:"V",GLY:"G",SER:"S",GLN:"Q",TYR:"Y",ASP:"D",GLU:"E",THR:"T",SEC:"U",PYL:"O"},is=Object.keys(es),rs=["A","C","T","G","U","I"],ns=["DA","DC","DT","DG","DU","DI"],ss=["A","G","I","DA","DG","DI"],os=rs.concat(ns),as=["SOL","WAT","HOH","H2O","W","DOD","D3O","TIP3","TIP4","SPC"],cs=["118","119","1AL","1CU","2FK","2HP","2OF","3CO","3MT","3NI","3OF","3P8","4MO","4PU","543","6MO","ACT","AG","AL","ALF","AM","ATH","AU","AU3","AUC","AZI","BA","BCT","BEF","BF4","BO4","BR","BS3","BSY","CA","CAC","CD","CD1","CD3","CD5","CE","CHT","CL","CO","CO3","CO5","CON","CR","CS","CSB","CU","CU1","CU3","CUA","CUZ","CYN","DME","DMI","DSC","DTI","DY","E4N","EDR","EMC","ER3","EU","EU3","F","FE","FE2","FPO","GA","GD3","GEP","HAI","HG","HGC","IN","IOD","IR","IR3","IRI","IUM","K","KO4","LA","LCO","LCP","LI","LU","MAC","MG","MH2","MH3","MLI","MLT","MMC","MN","MN3","MN5","MN6","MO1","MO2","MO3","MO4","MO5","MO6","MOO","MOS","MOW","MW1","MW2","MW3","NA","NA2","NA5","NA6","NAO","NAW","NCO","NET","NH4","NI","NI1","NI2","NI3","NO2","NO3","NRU","O4M","OAA","OC1","OC2","OC3","OC4","OC5","OC6","OC7","OC8","OCL","OCM","OCN","OCO","OF1","OF2","OF3","OH","OS","OS4","OXL","PB","PBM","PD","PDV","PER","PI","PO3","PO4","PR","PT","PT4","PTN","RB","RH3","RHD","RU","SB","SCN","SE4","SEK","SM","SMO","SO3","SO4","SR","T1A","TB","TBA","TCN","TEA","TH","THE","TL","TMA","TRA","UNX","V","VN3","VO4","W","WO5","Y1","YB","YB2","YH","YT3","ZCM","ZN","ZN2","ZN3","ZNO","ZO3","OHX"],ls=["045","0AT","0BD","0MK","0NZ","0TS","0V4","0XY","0YT","10M","147","149","14T","15L","16G","18T","18Y","1AR","1BW","1GL","1GN","1JB","1LL","1NA","1S3","26M","26Q","26R","26V","26W","26Y","27C","289","291","293","2DG","2F8","2FG","2FL","2FP","2GL","2M4","2M5","32O","34V","3CM","3DO","3DY","3FM","3LR","3MF","3MG","3SA","3ZW","46D","46M","46Z","48Z","4CQ","4GC","4NN","50A","5DI","5GF","5MM","5RP","5SA","5SP","64K","6PG","6SA","7JZ","7SA","A1Q","A2G","AAB","AAL","AAO","ABC","ABD","ABE","ABF","ABL","ACG","ACI","ACR","ACX","ADA","ADG","ADR","AF1","AFD","AFL","AFO","AFP","AFR","AGC","AGH","AGL","AHR","AIG","ALL","ALX","AMU","AOG","AOS","ARA","ARB","ARE","ARI","ASG","ASO","AXP","AXR","B0D","B16","B2G","B4G","B6D","B8D","B9D","BBK","BCD","BDG","BDP","BDR","BEM","BFP","BGC","BGL","BGP","BGS","BHG","BMA","BMX","BNG","BNX","BOG","BRI","BXF","BXP","BXX","BXY","C3X","C4X","C5X","CAP","CBI","CBK","CBS","CDR","CEG","CGF","CHO","CR1","CR6","CRA","CT3","CTO","CTR","CTT","D6G","DAF","DAG","DDA","DDB","DDL","DEL","DFR","DFX","DG0","DGC","DGD","DGM","DGS","DIG","DLF","DLG","DMU","DNO","DOM","DP5","DQQ","DQR","DR2","DR3","DR4","DRI","DSR","DT6","DVC","E4P","E5G","EAG","EBG","EBQ","EGA","EJT","EPG","ERE","ERI","F1P","F1X","F6P","FBP","FCA","FCB","FCT","FDP","FDQ","FFC","FIX","FMO","FRU","FSI","FU4","FUB","FUC","FUD","FUL","FXP","G16","G1P","G2F","G3I","G4D","G4S","G6D","G6P","G6S","GAC","GAD","GAL","GC1","GC4","GCD","GCN","GCO","GCS","GCT","GCU","GCV","GCW","GCX","GE1","GFG","GFP","GIV","GL0","GL2","GL5","GL6","GL7","GL9","GLA","GLB","GLC","GLD","GLF","GLG","GLO","GLP","GLS","GLT","GLW","GMH","GN1","GNX","GP1","GP4","GPH","GPM","GQ1","GQ2","GQ4","GS1","GS4","GSA","GSD","GTE","GTH","GTK","GTR","GTZ","GU0","GU1","GU2","GU3","GU4","GU5","GU6","GU8","GU9","GUF","GUP","GUZ","GYP","GYV","H2P","HDL","HMS","HS2","HSD","HSG","HSH","HSJ","HSQ","HSR","HSU","HSX","HSY","HSZ","IAB","IDG","IDR","IDS","IDT","IDU","IDX","IDY","IMK","IN1","IPT","ISL","KBG","KD2","KDA","KDM","KDO","KFN","KO1","KO2","KTU","L6S","LAG","LAI","LAK","LAO","LAT","LB2","LBT","LCN","LDY","LGC","LGU","LM2","LMT","LMU","LOG","LOX","LPK","LSM","LTM","LVZ","LXB","LXZ","M1F","M3M","M6P","M8C","MA1","MA2","MA3","MAB","MAG","MAL","MAN","MAT","MAV","MAW","MBG","MCU","MDA","MDM","MDP","MFA","MFB","MFU","MG5","MGA","MGL","MLB","MMA","MMN","MN0","MRP","MTT","MUG","MVP","MXY","N1L","N9S","NAA","NAG","NBG","NDG","NED","NG1","NG6","NGA","NGB","NGC","NGE","NGF","NGL","NGS","NGY","NHF","NM6","NM9","NTF","NTO","NTP","NXD","NYT","OPG","OPM","ORP","OX2","P3M","P53","P6P","PA5","PNA","PNG","PNW","PRP","PSJ","PSV","PTQ","QDK","QPS","QV4","R1P","R1X","R2B","R5P","RAA","RAE","RAF","RAM","RAO","RAT","RB5","RBL","RCD","RDP","REL","RER","RF5","RG1","RGG","RHA","RIB","RIP","RNS","RNT","ROB","ROR","RPA","RST","RUB","RUU","RZM","S6P","S7P","SA0","SCR","SDD","SF6","SF9","SG4","SG5","SG6","SG7","SGA","SGC","SGD","SGN","SGS","SHB","SHG","SI3","SIO","SOE","SOL","SSG","SUC","SUP","SUS","T6P","T6T","TAG","TCB","TDG","TGK","TGY","TH1","TIA","TM5","TM6","TM9","TMR","TMX","TOA","TOC","TRE","TYV","UCD","UDC","VG1","X0X","X1X","X2F","X4S","X5S","X6X","XBP","XDN","XDP","XIF","XIM","XLF","XLS","XMM","XUL","XXR","XYP","XYS","YO5","Z3Q","Z6J","Z9M","ZDC","ZDM"],hs=["CA","C","N","O","O1","O2","OC1","OC2","OX1","OXT","OT1","OT2","H","H1","H2","H3","HA","HN","BB"],us=["P","OP1","OP2","HOP2","HOP3","O2'","O3'","O4'","O5'","C1'","C2'","C3'","C4'","C5'","H1'","H2'","H2''","HO2'","H3'","H4'","H5'","H5''","HO3'","HO5'","O2*","O3*","O4*","O5*","C1*","C2*","C3*","C4*","C5*"],ds={1:{trace:"CA",direction1:"C",direction2:["O","OC1","O1","OX1","OXT","OT1","OT2"],backboneStart:"N",backboneEnd:"C"},2:{trace:["C4'","C4*"],direction1:["C1'","C1*"],direction2:["C3'","C3*"],backboneStart:"P",backboneEnd:["O3'","O3*"]},3:{trace:["C3'","C3*"],direction1:["C2'","C2*"],direction2:["O4'","O4*"],backboneStart:"P",backboneEnd:["O3'","O3*"]},4:{trace:["CA","BB"],backboneStart:["CA","BB"],backboneEnd:["CA","BB"]},5:{trace:["C4'","C4*","P"],backboneStart:["C4'","C4*","P"],backboneEnd:["C4'","C4*","P"]},6:{trace:["C3'","C3*","C2'","P"],backboneStart:["C3'","C3*","C2'","P"],backboneEnd:["C3'","C3*","C2'","P"]}};ds[Nn]={};const ms={HD:"H",HS:"H",A:"C",NA:"N",NS:"N",OA:"O",OS:"O",SA:"S",G0:"C",G1:"C",G2:"C",G3:"C",CG0:"C",CG1:"C",CG2:"C",CG3:"C",W:"O"};function fs(t){switch(t){case 0:return 0;case 1:return 1;case 2:return 2;case 3:return 3;case 4:return 4;default:return 8}}const ps=new Map([[2,It(180)],[3,It(120)],[4,It(109.4721)],[6,It(90)]]);function gs(t,i){let r=[];const n=new e,s=new e;return n.subVectors(i,t),t.eachBondedAtom((e=>{1!==e.number&&(s.subVectors(e,t),r.push(n.angleTo(s)))})),r}function ys(t,i){const r=t.clone(),n=new e;n.subVectors(i,t);const s=[new e,new e];let o=0;if(t.eachBondedAtom((e=>{o>1||1!==e.number&&(r.index=e.index,s[o++].subVectors(e,t))})),1===o&&r.eachBondedAtom((e=>{o>1||1!==e.number&&e.index!==t.index&&s[o++].subVectors(e,t)})),2!==o)return;const a=s[0].cross(s[1]);return Math.abs(Math.PI/2-a.angleTo(n))}function bs(t,e){const i=t.structure,r=i.atomCount,n=new Int8Array(r),s=new Int8Array(r),o=new Int8Array(r),a=new Int8Array(r);return i.eachAtom((t=>{const i=t.index,[r,c,l,h]=function(t,e){const i=t.bondToElementCount(1);let r=t.formalCharge||0;const n="always"===e.assignCharge||"auto"===e.assignCharge&&0===r,s="always"===e.assignH||"auto"===e.assignH&&0===i,o=t.bondCount,a=function(t){let e=0;return t.eachBond((t=>e+=t.bondOrder)),e}(t),c=function(t){const e=t.structure.getBondProxy(),i=t.number,r=8===i||7===i;if(r&&4===t.bondCount)return!1;let n=!1;return t.eachBond((i=>{if(i.bondOrder>1)n=!0;else if(r){const r=i.getOtherAtom(t);r.eachBond((t=>{if(t.bondOrder>1){const e=r.number;if((15===e||16===e)&&8===t.getOtherAtom(r).number)return;n=!0}}),e)}})),n}(t),l=a-o>0;let h=0,u=8;switch(t.number){case 1:n&&(0===o?(r=1,u=0):1===o&&(r=0,u=1));break;case 6:n&&(r=0),s&&(h=Math.max(0,4-a-Math.abs(r))),u=fs(o+h+Math.max(0,-r));break;case 7:if(n)if(s)if(c&&a<4)r=o-i==1&&a-i==2?1:0;else{let e=!1;t.eachBondedAtom((t=>{(16===t.number||t.isMetal())&&(e=!0)})),r=e?0:1}else r=a-3;s&&(h=Math.max(0,3-a+r)),u=fs(c&&!l?o+h-r:o+h+1-r);break;case 8:n&&(s||(r=a-2),1===a&&t.eachBondedAtom((e=>{e.eachBond((i=>{const n=i.getOtherAtom(e);n.index!==t.index&&8===n.number&&2===i.bondOrder&&(r=-1)}))}))),s&&(h=Math.max(0,2-a+r)),u=fs(c&&!l?o+h-r+1:o+h-r+2);break;case 16:n&&(s||(r=a<=3&&!t.bondToElementCount(8)?a-2:0)),s&&a<2&&(h=Math.max(0,2-a+r)),a<=3&&(u=fs(o+h-r+2));break;case 9:case 17:case 35:case 53:case 85:n&&(r=a-1);break;case 3:case 11:case 19:case 37:case 55:case 87:n&&(r=1-a);break;case 4:case 12:case 20:case 38:case 56:case 88:n&&(r=2-a);break;default:console.warn("Requested charge, protonation for an unhandled element",t.element)}return[r,h,h+i,u]}(t,e);n[i]=r,s[i]=c,o[i]=l,a[i]=h})),{charge:n,implicitH:s,totalH:o,idealGeometry:a}}function _s(t){if(t["@valenceModel"])return t["@valenceModel"];const e=bs(t,{assignCharge:"auto",assignH:"auto"});return t["@valenceModel"]=e,e}function xs(t){return 15===t.number&&t.bondToElementCount(8)===t.bondCount}const vs=["ARG","HIS","LYS"],ws=["GLU","ASP"];function As(t,e){return 2===t&&1===e||1===t&&2===e}function Ss(t,e){return 3===t&&3===e}function Cs(t,e){return 3===t&&1===e||1===t&&3===e}function Ps(t){return"HIS"===t.resname&&7==t.number&&t.isRing()}function Is(t,e){return 5===t&&4===e||4===t&&5===e}function ks(t,e){return 9===t&&5===e||5===t&&9===e}const Ms=[3,11,19,37,55,12,20,38,56,13,31,49,81,21,50,82,83,51,80];function Ts(t,e){return 12===t?11===e||12===e:13===t?10===e:void 0}const Ds=[17,35,53,85];const Bs=[7,8,16],Fs=[6,7,15,16];const Es=It(180),$s=It(120);function Os(t,e,i){return!Ls(t,e,i)&&(t.modelIndex!==e.modelIndex||t.altloc&&e.altloc&&t.altloc!==e.altloc)}const Rs={maxHydrophobicDist:4,maxHbondDist:3.5,maxHbondSulfurDist:4.1,maxHbondAccAngle:45,maxHbondDonAngle:45,maxHbondAccPlaneAngle:90,maxHbondDonPlaneAngle:30,maxPiStackingDist:5.5,maxPiStackingOffset:2,maxPiStackingAngle:30,maxCationPiDist:6,maxCationPiOffset:2,maxIonicDist:5,maxHalogenBondDist:4,maxHalogenBondAngle:30,maxMetalDist:3,refineSaltBridges:!0,masterModelIndex:-1,lineOfSightDistFactor:1};function Ls(t,e,i){return t.modelIndex===i&&e.modelIndex!==i||e.modelIndex===i&&t.modelIndex!==i}function Ns(t,e,i){return!Ls(t,e,i)&&(t.modelIndex!==e.modelIndex||t.residueIndex===e.residueIndex||t.altloc&&e.altloc&&t.altloc!==e.altloc)}function zs(t){const e={types:[],groups:[],centers:{x:[],y:[],z:[]},atomSets:[]};return De&&ke.time("calculateFeatures"),function(t,e){const{charge:i}=_s(t.data),r={};t.eachResidue((t=>{if(vs.includes(t.resname)){const i=On(1);t.eachAtom((t=>{7===t.number&&t.isSidechain()&&Rn(i,t)})),Ln(e,i)}else is.includes(t.resname)||t.isNucleic()||(t.eachAtom((t=>{let i=!1;const n=On(1);!function(t){let e=0;return 6===t.number&&3===t.bondCount&&3===t.bondToElementCount(7)&&t.eachBondedAtom((t=>{t.bondCount-t.bondToElementCount(1)==1&&++e})),2===e}(t)?function(t){let e=0;return 6===t.number&&3===t.bondCount&&2===t.bondToElementCount(7)&&1===t.bondToElementCount(6)&&t.eachBondedAtom((t=>{t.bondCount-t.bondToElementCount(1)==1&&++e})),2===e}(t)&&(n.group=9,i=!0):(n.group=8,i=!0),i&&(t.eachBondedAtom((t=>{7===t.number&&(r[t.index]=!0,Rn(n,t))})),Ln(e,n))})),t.eachAtom((t=>{const n=On(1);i[t.index]>0&&(r[t.index]||(Rn(n,t),Ln(e,n)))})))}))}(t,e),function(t,e){const{charge:i}=_s(t.data),r={};t.eachResidue((t=>{if(ws.includes(t.resname)){const i=On(2);t.eachAtom((t=>{8===t.number&&t.isSidechain()&&Rn(i,t)})),Ln(e,i)}else if(os.includes(t.resname)){const i=On(2);t.eachAtom((t=>{xs(t)&&(i.group=6,t.eachBondedAtom((t=>{8===t.number&&Rn(i,t)})),Ln(e,i))}))}else is.includes(t.resname)||os.includes(t.resname)||(t.eachAtom((t=>{let i=!1;const n=On(2);!function(t){return 16===t.number&&3===t.bondToElementCount(8)}(t)?xs(t)?(n.group=6,i=!0):function(t){return 16===t.number&&4===t.bondToElementCount(8)}(t)?(n.group=5,i=!0):function(t){let e=0;return 6===t.number&&2===t.bondToElementCount(8)&&1===t.bondToElementCount(6)&&t.eachBondedAtom((t=>{8===t.number&&t.bondCount-t.bondToElementCount(1)==1&&++e})),2===e}(t)&&(n.group=10,i=!0):(n.group=4,i=!0),i&&(t.eachBondedAtom((t=>{8===t.number&&(r[t.index]=!0,Rn(n,t))})),Ln(e,n))})),t.eachAtom((t=>{const n=On(2);i[t.index]<0&&(r[t.index]||(Rn(n,t),Ln(e,n)))})))}))}(t,e),function(t,e){const i=t.getAtomProxy();t.eachResidue((t=>{const r=t.getAromaticRings();if(r){const n=t.atomOffset;r.forEach((t=>{const r=On(3);t.forEach((t=>{i.index=t+n,Rn(r,i)})),Ln(e,r)}))}}))}(t,e),function(t,e){const{charge:i,implicitH:r,idealGeometry:n}=_s(t.data);t.eachAtom((t=>{const s=On(5),o=t.number;if(8===o)Rn(s,t),Ln(e,s);else if(7===o){if(Ps(t))Rn(s,t),Ln(e,s);else if(i[t.index]<1){const i=t.bondCount+r[t.index],o=n[t.index];(4===o&&i<4||3===o&&i<3||2===o&&i<2)&&(Rn(s,t),Ln(e,s))}}else 16===o&&("CYS"!==t.resname&&"MET"!==t.resname&&-1!==t.formalCharge||(Rn(s,t),Ln(e,s)))}))}(t,e),function(t,e){const{totalH:i}=_s(t.data);t.eachAtom((t=>{const r=On(4),n=t.number;(Ps(t)||i[t.index]>0&&(7===n||8===n||16===n))&&(Rn(r,t),Ln(e,r))}))}(t,e),function(t,e){const{totalH:i}=_s(t.data);t.eachAtom((t=>{if(6===t.number&&i[t.index]>0&&(t.bondToElementCount(7)>0||t.bondToElementCount(8)>0||function(t){if(!t.isAromatic())return!1;const e=t.residueType.getRings();if(!e)return!1;let i=!1;return e.rings.forEach((e=>{i||e.some((e=>t.index-t.residueAtomOffset===e))&&(i=e.some((e=>{const i=t.residueType.atomTypeIdList[e],r=t.atomMap.get(i).number;return 7===r||8===r})))})),i}(t))){const i=On(9);Rn(i,t),Ln(e,i)}}))}(t,e),function(t,e){t.eachAtom((t=>{let i=!1,r=!1;const n=is.includes(t.resname),s=os.includes(t.resname);if(n||s?n?8===t.number?(["ASP","GLU","SER","THR","TYR","ASN","GLN"].includes(t.resname)&&t.isSidechain()||t.isBackbone())&&(i=!0,r=!0):16===t.number&&"CYS"===t.resname?(i=!0,r=!0):7===t.number&&"HIS"===t.resname&&t.isSidechain()&&(i=!0):s&&(8===t.number&&t.isBackbone()?(i=!0,r=!0):["N3","N4","N7"].includes(t.atomname)?i=!0:["O2","O4","O6"].includes(t.atomname)&&(i=!0,r=!0)):t.isHalogen()||8===t.number||16===t.number?(i=!0,r=!0):7===t.number&&(i=!0),i){const i=On(11);Rn(i,t),Ln(e,i)}if(r){const i=On(10);Rn(i,t),Ln(e,i)}}))}(t,e),function(t,e){t.eachAtom((t=>{if(t.isTransitionMetal()||30===t.number||48===t.number){const i=On(12);Rn(i,t),Ln(e,i)}else if(Ms.includes(t.number)){const i=On(13);Rn(i,t),Ln(e,i)}}))}(t,e),function(t,e){t.eachAtom((t=>{const i=On(8);let r=!1;6===t.number?(r=!0,t.eachBondedAtom((t=>{const e=t.number;6!==e&&1!==e&&(r=!1)}))):9===t.number&&(r=!0),r&&(Rn(i,t),Ln(e,i))}))}(t,e),function(t,e){t.eachAtom((t=>{if(Bs.includes(t.number)){let i=!1;if(t.eachBondedAtom((t=>{Fs.includes(t.number)&&(i=!0)})),i){const i=On(7);Rn(i,t),Ln(e,i)}}}))}(t,e),function(t,e){t.eachAtom((t=>{if(Ds.includes(t.number)&&1===t.bondToElementCount(6)){const i=On(6);Rn(i,t),Ln(e,i)}}))}(t,e),De&&ke.timeEnd("calculateFeatures"),e}function Us(t,i=Rs){const r=function(t){const{types:e,centers:i}=t;return{features:t,spatialHash:new Tn(i),contactStore:new Bn,featureSet:new En(e.length,!1)}}(zs(t));De&&ke.time("calculateContacts"),function(t,i,r={}){const n=rt(r.maxIonicDist,Rs.maxIonicDist),s=rt(r.maxPiStackingDist,Rs.maxPiStackingDist),o=rt(r.maxPiStackingOffset,Rs.maxPiStackingOffset),a=rt(r.maxPiStackingAngle,Rs.maxPiStackingAngle),c=rt(r.maxCationPiDist,Rs.maxCationPiDist),l=rt(r.maxCationPiOffset,Rs.maxCationPiOffset),h=rt(r.masterModelIndex,Rs.masterModelIndex),u=Math.max(n+2,s,c),d=s*s,m=c*c,{features:f,spatialHash:p,contactStore:g,featureSet:y}=i,{types:b,centers:_,atomSets:x}=f,{x:v,y:w,z:A}=_,S=b.length,C=t.atomStore.x,P=t.atomStore.y,I=t.atomStore.z,k=t.getAtomProxy(),M=t.getAtomProxy(),T=function(t,e,i){const r=t.length,n=e.length;for(let s=0;s{if(e<=t)return;if(k.index=x[t][0],M.index=x[e][0],Ns(k,M,h))return;const r=b[t],s=b[e];if(As(r,s))T(x[t],x[e],n)&&z(t,e,1);else if(Ss(r,s)){if(i<=d){L(x[t],O),L(x[e],R);const i=57.29578*O.angleTo(R);Math.min(N(t,e,R),N(e,t,O))<=o&&(i<=a||i>=180-a||i<=a+90&&i>=90-a)&&z(t,e,3)}}else if(Cs(r,s)&&i<=m){const[i,n]=3===r?[t,e]:[e,t];L(x[i],O),N(n,i,O)<=l&&z(i,n,2)}}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxHbondDist,Rs.maxHbondDist),n=rt(i.maxHbondSulfurDist,Rs.maxHbondSulfurDist),s=It(rt(i.maxHbondAccAngle,Rs.maxHbondAccAngle)),o=It(rt(i.maxHbondDonAngle,Rs.maxHbondDonAngle)),a=It(rt(i.maxHbondAccPlaneAngle,Rs.maxHbondAccPlaneAngle)),c=It(rt(i.maxHbondDonPlaneAngle,Rs.maxHbondDonPlaneAngle)),l=rt(i.masterModelIndex,Rs.masterModelIndex),h=Math.max(r,n),u=r*r,{features:d,spatialHash:m,contactStore:f,featureSet:p}=e,{types:g,centers:y,atomSets:b}=d,{x:_,y:x,z:v}=y,w=g.length,{idealGeometry:A}=_s(t.data),S=t.getAtomProxy(),C=t.getAtomProxy();for(let t=0;t{if(e<=t)return;const r=g[t],n=g[e],h=ks(r,n);if(!h&&!Is(r,n))return;const[d,m]=5===n?[t,e]:[e,t];if(S.index=b[d][0],C.index=b[m][0],C.index===S.index)return;if(Ns(S,C,l))return;if(16!==S.number&&16!==C.number&&i>u)return;if(S.connectedTo(C))return;const y=gs(S,C),_=ps.get(A[S.index])||It(120);if(y.some((t=>Math.abs(_-t)>o)))return;if(3===A[S.index]){const t=ys(S,C);if(void 0!==t&&t>c)return}const x=gs(C,S),v=ps.get(A[C.index])||It(120);if(x.some((t=>v-t>s)))return;if(3===A[C.index]){const t=ys(C,S);if(void 0!==t&&t>a)return}p.setBits(d,m);const w=h?8:function(t,e){return t.isWater()&&e.isWater()}(P=S,I=C)?9:function(t,e){return t.isBackbone()&&e.isBackbone()}(P,I)?10:4;var P,I;f.addContact(d,m,w)}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxMetalDist,Rs.maxMetalDist),n=rt(i.masterModelIndex,Rs.masterModelIndex),{features:s,spatialHash:o,contactStore:a,featureSet:c}=e,{types:l,centers:h,atomSets:u}=s,{x:d,y:m,z:f}=h,p=l.length,g=t.getAtomProxy(),y=t.getAtomProxy();for(let t=0;t{if(e<=t)return;if(g.index=u[t][0],y.index=u[e][0],Ns(g,y,n))return;const r=g.isMetal(),s=y.isMetal();if(!r&&!s)return;const[o,h]=r?[l[t],l[e]]:[l[e],l[t]];Ts(o,h)&&(c.setBits(t,e),a.addContact(t,e,7))}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxHydrophobicDist,Rs.maxHydrophobicDist),n=rt(i.masterModelIndex,Rs.masterModelIndex),{features:s,spatialHash:o,contactStore:a,featureSet:c}=e,{types:l,centers:h,atomSets:u}=s,{x:d,y:m,z:f}=h,p=l.length,g=t.getAtomProxy(),y=t.getAtomProxy();for(let t=0;t{var r,s;e<=t||(g.index=u[t][0],y.index=u[e][0],Ns(g,y,n)||9===g.number&&9===y.number||g.connectedTo(y)||(r=l[t],s=l[e],8===r&&8===s&&(c.setBits(t,e),a.addContact(t,e,6))))}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxHalogenBondDist,Rs.maxHalogenBondDist),n=It(rt(i.maxHalogenBondAngle,Rs.maxHalogenBondAngle)),s=rt(i.masterModelIndex,Rs.masterModelIndex),{features:o,spatialHash:a,contactStore:c,featureSet:l}=e,{types:h,centers:u,atomSets:d}=o,{x:m,y:f,z:p}=u,g=h.length,y=t.getAtomProxy(),b=t.getAtomProxy();for(let t=0;t{if(e<=t)return;if(y.index=d[t][0],b.index=d[e][0],Ns(y,b,s))return;if(r=h[t],o=h[e],!(7===r&&6===o||6===r&&7===o))return;var r,o;const[a,u]=6===h[t]?[y,b]:[b,y],m=gs(a,u);if(1!==m.length)return;if(Es-m[0]>n)return;const f=gs(u,a);0!==f.length&&(f.some((t=>$s-t>n))||(l.setBits(t,e),c.addContact(t,e,5)))}))}(t,r,i);const n=function(t){const{index1:e,index2:i,count:r}=t.contactStore,n=$n({nodeArray1:e,nodeArray2:i,edgeCount:r,nodeCount:t.featureSet.length}),s=new En(t.contactStore.count,!0);return Object.assign({adjacencyList:n,contactSet:s},t)}(r);return function(t,i,r={}){De&&ke.time("refineLineOfSight");const n=rt(r.lineOfSightDistFactor,Rs.lineOfSightDistFactor),s=rt(r.masterModelIndex,Rs.masterModelIndex),o=t.spatialHash,{contactSet:a,contactStore:c,features:l}=i,{index1:h,index2:u}=c,{centers:d,atomSets:m}=l,{x:f,y:p,z:g}=d,y=t.getAtomProxy(),b=t.getAtomProxy(),_=t.getAtomProxy(),x=new e,v=new e,w=3*n,A=n*n;a.forEach((t=>{x.set(f[h[t]],p[h[t]],g[h[t]]),v.set(f[u[t]],p[u[t]],g[u[t]]);const e=(x.x+v.x)/2,i=(x.y+v.y)/2,r=(x.z+v.z)/2,n=m[h[t]],c=m[u[t]];y.index=n[0],b.index=c[0],o.eachWithin(e,i,r,w,((e,i)=>{_.index=e,1!==_.number&&_.vdw*_.vdw*A>i&&!Os(y,_,s)&&!Os(b,_,s)&&!n.includes(e)&&!c.includes(e)&&x.distanceToSquared(_)>1&&v.distanceToSquared(_)>1&&(a.clear(t),De&&ke.log("removing",y.qualifiedName(),b.qualifiedName(),"because",_.qualifiedName()))}))})),De&&ke.timeEnd("refineLineOfSight")}(t,n,i),function(t,e){const{contactSet:i,contactStore:r,features:n}=e,{type:s,index1:o,index2:a}=r,{atomSets:c}=n,l=t.getAtomProxy(),h=t.getAtomProxy(),u={},d=function(t,e,r){const[n,s]=u[r]||[1/0,-1];t{if(6!==s[t])return;l.index=c[o[t]][0],h.index=c[a[t]][0];const e=l.distanceTo(h);d(e,t,`${l.index}|${h.residueIndex}`),d(e,t,`${h.index}|${l.residueIndex}`)}))}(t,n),i.refineSaltBridges&&function(t,e){const{contactSet:i,contactStore:r,features:n}=e,{type:s,index1:o,index2:a}=r,{atomSets:c}=n,l={},h=function(t,e){l[t]||(l[t]=[]),l[t].push(e)};i.forEach((t=>{1===s[t]&&(c[o[t]].forEach((e=>h(e,t))),c[a[t]].forEach((e=>h(e,t))))})),i.forEach((t=>{if(!function(t){return 4===t||9===t||10===t}(s[t]))return;const e=l[c[o[t]][0]],r=l[c[a[t]][0]];if(!e||!r)return;const n=e.length;for(let s=0;s{3===s[t]&&(c[o[t]].forEach((e=>h(e,t))),c[a[t]].forEach((e=>h(e,t))))})),i.forEach((t=>{if(6!==s[t]&&2!==s[t])return;const e=l[c[o[t]][0]],r=l[c[a[t]][0]];if(!e||!r)return;const n=e.length;for(let s=0;s{1===s[t]&&(c[o[t]].forEach((e=>h(e,t))),c[a[t]].forEach((e=>h(e,t))))})),i.forEach((t=>{if(7!==s[t])return;const e=l[c[o[t]][0]],r=l[c[a[t]][0]];if(!e||!r)return;const n=e.length;for(let t=0;te.getAtomSet(new me(t)))):e.getAtomSet(new me(r.filterSele))),o.forEach((t=>{const e=p[t];if(!n.includes(e))return;if(v){const e=l[m[t]][0],i=l[f[t]][0];if(Array.isArray(v)){if(!(v[0].isSet(e)&&v[1].isSet(i)||v[1].isSet(e)&&v[0].isSet(i)))return}else if(!v.isSet(e)&&!v.isSet(i))return}const i=m[t],s=f[t];g.push(h[i],u[i],d[i]),y.push(h[s],u[s],d[s]),b.push(...function(t){switch(t){case 4:case 9:case 10:return Gs.setHex(2851770).toArray();case 6:return Gs.setHex(8421504).toArray();case 5:return Gs.setHex(4259775).toArray();case 1:return Gs.setHex(15779860).toArray();case 7:return Gs.setHex(9191577).toArray();case 2:return Gs.setHex(16744448).toArray();case 3:return Gs.setHex(9220966).toArray();case 8:return Gs.setHex(12967404).toArray();default:return Gs.setHex(13421772).toArray()}}(e)),_.push(r.radius),x.push(t)})),{position1:new Float32Array(g),position2:new Float32Array(y),color:new Float32Array(b),color2:new Float32Array(b),radius:new Float32Array(_),picking:new Zs(x,t,e)}}class qs{constructor(t){this.array=t}get type(){return""}get data(){return{}}getIndex(t){return this.array?this.array[t]:t}getObject(t){return{}}_applyTransformations(t,e,i){return e&&t.applyMatrix4(e.matrix),i&&t.applyMatrix4(i.matrix),t}_getPosition(t){return new e}getPosition(t,e,i){return this._applyTransformations(this._getPosition(t),e,i)}}class Ws extends qs{constructor(t){super(),this.shape=t}get primitive(){}get data(){return this.shape}get type(){return this.primitive.type}getObject(t){return this.primitive.objectFromShape(this.shape,this.getIndex(t))}_getPosition(t){return this.primitive.positionFromShape(this.shape,this.getIndex(t))}}class Xs extends qs{constructor(t,e){super(t),this.structure=e}get type(){return"atom"}get data(){return this.structure}getObject(t){return this.structure.getAtomProxy(this.getIndex(t))}_getPosition(t){return(new e).copy(this.getObject(t))}}class Ys extends qs{constructor(t){super(),this.axes=t}get type(){return"axes"}get data(){return this.axes}getObject(){return{axes:this.axes}}_getPosition(){return this.axes.center.clone()}}class Ks extends qs{constructor(t,e,i){super(t),this.structure=e,this.bondStore=i||e.bondStore}get type(){return"bond"}get data(){return this.structure}getObject(t){const e=this.structure.getBondProxy(this.getIndex(t));return e.bondStore=this.bondStore,e}_getPosition(t){const i=this.getObject(t);return(new e).copy(i.atom1).add(i.atom2).multiplyScalar(.5)}}class Zs extends qs{constructor(t,e,i){super(t),this.contacts=e,this.structure=i}get type(){return"contact"}get data(){return this.contacts}getObject(t){const i=this.getIndex(t),{features:r,contactStore:n}=this.contacts,{centers:s,atomSets:o}=r,{x:a,y:c,z:l}=s,{index1:h,index2:u,type:d}=n,m=h[i],f=u[i];return{center1:new e(a[m],c[m],l[m]),center2:new e(a[f],c[f],l[f]),atom1:this.structure.getAtomProxy(o[m][0]),atom2:this.structure.getAtomProxy(o[f][0]),type:Vs(d[i])}}_getPosition(t){const{center1:i,center2:r}=this.getObject(t);return(new e).addVectors(i,r).multiplyScalar(.5)}}class Qs extends qs{constructor(t,e,i){super(t),this.validation=e,this.structure=i}get type(){return"clash"}get data(){return this.validation}getObject(t){const e=this.validation,i=this.getIndex(t);return{validation:e,index:i,clash:e.clashArray[i]}}_getAtomProxyFromSele(t){const e=new me(t),i=this.structure.getAtomIndices(e)[0];return this.structure.getAtomProxy(i)}_getPosition(t){const i=this.getObject(t).clash,r=this._getAtomProxyFromSele(i.sele1),n=this._getAtomProxyFromSele(i.sele2);return(new e).copy(r).add(n).multiplyScalar(.5)}}class Js extends Ks{get type(){return"distance"}}class to extends qs{get type(){return"ignore"}}class eo extends Ws{constructor(t,e){super(t),this.mesh=e}get type(){return"mesh"}getObject(){const t=this.mesh;return{shape:this.shape,name:t.name,serial:t.serial}}_getPosition(){return this.__position||(this.__position=Vr(this.mesh.position)),this.__position}}class io extends qs{constructor(t,e){super(t),this.surface=e}get type(){return"surface"}get data(){return this.surface}getObject(t){return{surface:this.surface,index:this.getIndex(t)}}_getPosition(){return this.surface.center.clone()}}class ro extends qs{constructor(t,e){super(),this.unitcell=t,this.structure=e}get type(){return"unitcell"}get data(){return this.unitcell}getObject(){return{unitcell:this.unitcell,structure:this.structure}}_getPosition(){return this.unitcell.getCenter(this.structure)}}class no extends qs{constructor(t,e){super(t),this.volume=e}get type(){return"volume"}get data(){return this.volume}getObject(t){const e=this.volume,i=this.getIndex(t);return{volume:e,index:i,value:e.data[i]}}_getPosition(t){const i=this.volume.position,r=this.getIndex(t);return new e(i[3*r],i[3*r+1],i[3*r+2])}}class so extends no{get type(){return"slice"}}function oo(){return new Uint32Array([0,265,515,778,1030,1295,1541,1804,2060,2309,2575,2822,3082,3331,3593,3840,400,153,915,666,1430,1183,1941,1692,2460,2197,2975,2710,3482,3219,3993,3728,560,825,51,314,1590,1855,1077,1340,2620,2869,2111,2358,3642,3891,3129,3376,928,681,419,170,1958,1711,1445,1196,2988,2725,2479,2214,4010,3747,3497,3232,1120,1385,1635,1898,102,367,613,876,3180,3429,3695,3942,2154,2403,2665,2912,1520,1273,2035,1786,502,255,1013,764,3580,3317,4095,3830,2554,2291,3065,2800,1616,1881,1107,1370,598,863,85,348,3676,3925,3167,3414,2650,2899,2137,2384,1984,1737,1475,1226,966,719,453,204,4044,3781,3535,3270,3018,2755,2505,2240,2240,2505,2755,3018,3270,3535,3781,4044,204,453,719,966,1226,1475,1737,1984,2384,2137,2899,2650,3414,3167,3925,3676,348,85,863,598,1370,1107,1881,1616,2800,3065,2291,2554,3830,4095,3317,3580,764,1013,255,502,1786,2035,1273,1520,2912,2665,2403,2154,3942,3695,3429,3180,876,613,367,102,1898,1635,1385,1120,3232,3497,3747,4010,2214,2479,2725,2988,1196,1445,1711,1958,170,419,681,928,3376,3129,3891,3642,2358,2111,2869,2620,1340,1077,1855,1590,314,51,825,560,3728,3993,3219,3482,2710,2975,2197,2460,1692,1941,1183,1430,666,915,153,400,3840,3593,3331,3082,2822,2575,2309,2060,1804,1541,1295,1030,778,515,265,0])}function ao(){return new Int32Array([-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,8,3,9,8,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,1,2,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,2,10,0,2,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,8,3,2,10,8,10,9,8,-1,-1,-1,-1,-1,-1,-1,3,11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,11,2,8,11,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,9,0,2,3,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,11,2,1,9,11,9,8,11,-1,-1,-1,-1,-1,-1,-1,3,10,1,11,10,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,10,1,0,8,10,8,11,10,-1,-1,-1,-1,-1,-1,-1,3,9,0,3,11,9,11,10,9,-1,-1,-1,-1,-1,-1,-1,9,8,10,10,8,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,7,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,3,0,7,3,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,8,4,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,1,9,4,7,1,7,3,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,8,4,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,4,7,3,0,4,1,2,10,-1,-1,-1,-1,-1,-1,-1,9,2,10,9,0,2,8,4,7,-1,-1,-1,-1,-1,-1,-1,2,10,9,2,9,7,2,7,3,7,9,4,-1,-1,-1,-1,8,4,7,3,11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,4,7,11,2,4,2,0,4,-1,-1,-1,-1,-1,-1,-1,9,0,1,8,4,7,2,3,11,-1,-1,-1,-1,-1,-1,-1,4,7,11,9,4,11,9,11,2,9,2,1,-1,-1,-1,-1,3,10,1,3,11,10,7,8,4,-1,-1,-1,-1,-1,-1,-1,1,11,10,1,4,11,1,0,4,7,11,4,-1,-1,-1,-1,4,7,8,9,0,11,9,11,10,11,0,3,-1,-1,-1,-1,4,7,11,4,11,9,9,11,10,-1,-1,-1,-1,-1,-1,-1,9,5,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,5,4,0,8,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,5,4,1,5,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,5,4,8,3,5,3,1,5,-1,-1,-1,-1,-1,-1,-1,1,2,10,9,5,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,8,1,2,10,4,9,5,-1,-1,-1,-1,-1,-1,-1,5,2,10,5,4,2,4,0,2,-1,-1,-1,-1,-1,-1,-1,2,10,5,3,2,5,3,5,4,3,4,8,-1,-1,-1,-1,9,5,4,2,3,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,11,2,0,8,11,4,9,5,-1,-1,-1,-1,-1,-1,-1,0,5,4,0,1,5,2,3,11,-1,-1,-1,-1,-1,-1,-1,2,1,5,2,5,8,2,8,11,4,8,5,-1,-1,-1,-1,10,3,11,10,1,3,9,5,4,-1,-1,-1,-1,-1,-1,-1,4,9,5,0,8,1,8,10,1,8,11,10,-1,-1,-1,-1,5,4,0,5,0,11,5,11,10,11,0,3,-1,-1,-1,-1,5,4,8,5,8,10,10,8,11,-1,-1,-1,-1,-1,-1,-1,9,7,8,5,7,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,3,0,9,5,3,5,7,3,-1,-1,-1,-1,-1,-1,-1,0,7,8,0,1,7,1,5,7,-1,-1,-1,-1,-1,-1,-1,1,5,3,3,5,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,7,8,9,5,7,10,1,2,-1,-1,-1,-1,-1,-1,-1,10,1,2,9,5,0,5,3,0,5,7,3,-1,-1,-1,-1,8,0,2,8,2,5,8,5,7,10,5,2,-1,-1,-1,-1,2,10,5,2,5,3,3,5,7,-1,-1,-1,-1,-1,-1,-1,7,9,5,7,8,9,3,11,2,-1,-1,-1,-1,-1,-1,-1,9,5,7,9,7,2,9,2,0,2,7,11,-1,-1,-1,-1,2,3,11,0,1,8,1,7,8,1,5,7,-1,-1,-1,-1,11,2,1,11,1,7,7,1,5,-1,-1,-1,-1,-1,-1,-1,9,5,8,8,5,7,10,1,3,10,3,11,-1,-1,-1,-1,5,7,0,5,0,9,7,11,0,1,0,10,11,10,0,-1,11,10,0,11,0,3,10,5,0,8,0,7,5,7,0,-1,11,10,5,7,11,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,6,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,5,10,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,0,1,5,10,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,8,3,1,9,8,5,10,6,-1,-1,-1,-1,-1,-1,-1,1,6,5,2,6,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,6,5,1,2,6,3,0,8,-1,-1,-1,-1,-1,-1,-1,9,6,5,9,0,6,0,2,6,-1,-1,-1,-1,-1,-1,-1,5,9,8,5,8,2,5,2,6,3,2,8,-1,-1,-1,-1,2,3,11,10,6,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,0,8,11,2,0,10,6,5,-1,-1,-1,-1,-1,-1,-1,0,1,9,2,3,11,5,10,6,-1,-1,-1,-1,-1,-1,-1,5,10,6,1,9,2,9,11,2,9,8,11,-1,-1,-1,-1,6,3,11,6,5,3,5,1,3,-1,-1,-1,-1,-1,-1,-1,0,8,11,0,11,5,0,5,1,5,11,6,-1,-1,-1,-1,3,11,6,0,3,6,0,6,5,0,5,9,-1,-1,-1,-1,6,5,9,6,9,11,11,9,8,-1,-1,-1,-1,-1,-1,-1,5,10,6,4,7,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,3,0,4,7,3,6,5,10,-1,-1,-1,-1,-1,-1,-1,1,9,0,5,10,6,8,4,7,-1,-1,-1,-1,-1,-1,-1,10,6,5,1,9,7,1,7,3,7,9,4,-1,-1,-1,-1,6,1,2,6,5,1,4,7,8,-1,-1,-1,-1,-1,-1,-1,1,2,5,5,2,6,3,0,4,3,4,7,-1,-1,-1,-1,8,4,7,9,0,5,0,6,5,0,2,6,-1,-1,-1,-1,7,3,9,7,9,4,3,2,9,5,9,6,2,6,9,-1,3,11,2,7,8,4,10,6,5,-1,-1,-1,-1,-1,-1,-1,5,10,6,4,7,2,4,2,0,2,7,11,-1,-1,-1,-1,0,1,9,4,7,8,2,3,11,5,10,6,-1,-1,-1,-1,9,2,1,9,11,2,9,4,11,7,11,4,5,10,6,-1,8,4,7,3,11,5,3,5,1,5,11,6,-1,-1,-1,-1,5,1,11,5,11,6,1,0,11,7,11,4,0,4,11,-1,0,5,9,0,6,5,0,3,6,11,6,3,8,4,7,-1,6,5,9,6,9,11,4,7,9,7,11,9,-1,-1,-1,-1,10,4,9,6,4,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,10,6,4,9,10,0,8,3,-1,-1,-1,-1,-1,-1,-1,10,0,1,10,6,0,6,4,0,-1,-1,-1,-1,-1,-1,-1,8,3,1,8,1,6,8,6,4,6,1,10,-1,-1,-1,-1,1,4,9,1,2,4,2,6,4,-1,-1,-1,-1,-1,-1,-1,3,0,8,1,2,9,2,4,9,2,6,4,-1,-1,-1,-1,0,2,4,4,2,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,3,2,8,2,4,4,2,6,-1,-1,-1,-1,-1,-1,-1,10,4,9,10,6,4,11,2,3,-1,-1,-1,-1,-1,-1,-1,0,8,2,2,8,11,4,9,10,4,10,6,-1,-1,-1,-1,3,11,2,0,1,6,0,6,4,6,1,10,-1,-1,-1,-1,6,4,1,6,1,10,4,8,1,2,1,11,8,11,1,-1,9,6,4,9,3,6,9,1,3,11,6,3,-1,-1,-1,-1,8,11,1,8,1,0,11,6,1,9,1,4,6,4,1,-1,3,11,6,3,6,0,0,6,4,-1,-1,-1,-1,-1,-1,-1,6,4,8,11,6,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,10,6,7,8,10,8,9,10,-1,-1,-1,-1,-1,-1,-1,0,7,3,0,10,7,0,9,10,6,7,10,-1,-1,-1,-1,10,6,7,1,10,7,1,7,8,1,8,0,-1,-1,-1,-1,10,6,7,10,7,1,1,7,3,-1,-1,-1,-1,-1,-1,-1,1,2,6,1,6,8,1,8,9,8,6,7,-1,-1,-1,-1,2,6,9,2,9,1,6,7,9,0,9,3,7,3,9,-1,7,8,0,7,0,6,6,0,2,-1,-1,-1,-1,-1,-1,-1,7,3,2,6,7,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,11,10,6,8,10,8,9,8,6,7,-1,-1,-1,-1,2,0,7,2,7,11,0,9,7,6,7,10,9,10,7,-1,1,8,0,1,7,8,1,10,7,6,7,10,2,3,11,-1,11,2,1,11,1,7,10,6,1,6,7,1,-1,-1,-1,-1,8,9,6,8,6,7,9,1,6,11,6,3,1,3,6,-1,0,9,1,11,6,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,8,0,7,0,6,3,11,0,11,6,0,-1,-1,-1,-1,7,11,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,6,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,8,11,7,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,11,7,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,1,9,8,3,1,11,7,6,-1,-1,-1,-1,-1,-1,-1,10,1,2,6,11,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,10,3,0,8,6,11,7,-1,-1,-1,-1,-1,-1,-1,2,9,0,2,10,9,6,11,7,-1,-1,-1,-1,-1,-1,-1,6,11,7,2,10,3,10,8,3,10,9,8,-1,-1,-1,-1,7,2,3,6,2,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,0,8,7,6,0,6,2,0,-1,-1,-1,-1,-1,-1,-1,2,7,6,2,3,7,0,1,9,-1,-1,-1,-1,-1,-1,-1,1,6,2,1,8,6,1,9,8,8,7,6,-1,-1,-1,-1,10,7,6,10,1,7,1,3,7,-1,-1,-1,-1,-1,-1,-1,10,7,6,1,7,10,1,8,7,1,0,8,-1,-1,-1,-1,0,3,7,0,7,10,0,10,9,6,10,7,-1,-1,-1,-1,7,6,10,7,10,8,8,10,9,-1,-1,-1,-1,-1,-1,-1,6,8,4,11,8,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,6,11,3,0,6,0,4,6,-1,-1,-1,-1,-1,-1,-1,8,6,11,8,4,6,9,0,1,-1,-1,-1,-1,-1,-1,-1,9,4,6,9,6,3,9,3,1,11,3,6,-1,-1,-1,-1,6,8,4,6,11,8,2,10,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,3,0,11,0,6,11,0,4,6,-1,-1,-1,-1,4,11,8,4,6,11,0,2,9,2,10,9,-1,-1,-1,-1,10,9,3,10,3,2,9,4,3,11,3,6,4,6,3,-1,8,2,3,8,4,2,4,6,2,-1,-1,-1,-1,-1,-1,-1,0,4,2,4,6,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,9,0,2,3,4,2,4,6,4,3,8,-1,-1,-1,-1,1,9,4,1,4,2,2,4,6,-1,-1,-1,-1,-1,-1,-1,8,1,3,8,6,1,8,4,6,6,10,1,-1,-1,-1,-1,10,1,0,10,0,6,6,0,4,-1,-1,-1,-1,-1,-1,-1,4,6,3,4,3,8,6,10,3,0,3,9,10,9,3,-1,10,9,4,6,10,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,9,5,7,6,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,4,9,5,11,7,6,-1,-1,-1,-1,-1,-1,-1,5,0,1,5,4,0,7,6,11,-1,-1,-1,-1,-1,-1,-1,11,7,6,8,3,4,3,5,4,3,1,5,-1,-1,-1,-1,9,5,4,10,1,2,7,6,11,-1,-1,-1,-1,-1,-1,-1,6,11,7,1,2,10,0,8,3,4,9,5,-1,-1,-1,-1,7,6,11,5,4,10,4,2,10,4,0,2,-1,-1,-1,-1,3,4,8,3,5,4,3,2,5,10,5,2,11,7,6,-1,7,2,3,7,6,2,5,4,9,-1,-1,-1,-1,-1,-1,-1,9,5,4,0,8,6,0,6,2,6,8,7,-1,-1,-1,-1,3,6,2,3,7,6,1,5,0,5,4,0,-1,-1,-1,-1,6,2,8,6,8,7,2,1,8,4,8,5,1,5,8,-1,9,5,4,10,1,6,1,7,6,1,3,7,-1,-1,-1,-1,1,6,10,1,7,6,1,0,7,8,7,0,9,5,4,-1,4,0,10,4,10,5,0,3,10,6,10,7,3,7,10,-1,7,6,10,7,10,8,5,4,10,4,8,10,-1,-1,-1,-1,6,9,5,6,11,9,11,8,9,-1,-1,-1,-1,-1,-1,-1,3,6,11,0,6,3,0,5,6,0,9,5,-1,-1,-1,-1,0,11,8,0,5,11,0,1,5,5,6,11,-1,-1,-1,-1,6,11,3,6,3,5,5,3,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,9,5,11,9,11,8,11,5,6,-1,-1,-1,-1,0,11,3,0,6,11,0,9,6,5,6,9,1,2,10,-1,11,8,5,11,5,6,8,0,5,10,5,2,0,2,5,-1,6,11,3,6,3,5,2,10,3,10,5,3,-1,-1,-1,-1,5,8,9,5,2,8,5,6,2,3,8,2,-1,-1,-1,-1,9,5,6,9,6,0,0,6,2,-1,-1,-1,-1,-1,-1,-1,1,5,8,1,8,0,5,6,8,3,8,2,6,2,8,-1,1,5,6,2,1,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,3,6,1,6,10,3,8,6,5,6,9,8,9,6,-1,10,1,0,10,0,6,9,5,0,5,6,0,-1,-1,-1,-1,0,3,8,5,6,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,5,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,5,10,7,5,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,5,10,11,7,5,8,3,0,-1,-1,-1,-1,-1,-1,-1,5,11,7,5,10,11,1,9,0,-1,-1,-1,-1,-1,-1,-1,10,7,5,10,11,7,9,8,1,8,3,1,-1,-1,-1,-1,11,1,2,11,7,1,7,5,1,-1,-1,-1,-1,-1,-1,-1,0,8,3,1,2,7,1,7,5,7,2,11,-1,-1,-1,-1,9,7,5,9,2,7,9,0,2,2,11,7,-1,-1,-1,-1,7,5,2,7,2,11,5,9,2,3,2,8,9,8,2,-1,2,5,10,2,3,5,3,7,5,-1,-1,-1,-1,-1,-1,-1,8,2,0,8,5,2,8,7,5,10,2,5,-1,-1,-1,-1,9,0,1,5,10,3,5,3,7,3,10,2,-1,-1,-1,-1,9,8,2,9,2,1,8,7,2,10,2,5,7,5,2,-1,1,3,5,3,7,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,7,0,7,1,1,7,5,-1,-1,-1,-1,-1,-1,-1,9,0,3,9,3,5,5,3,7,-1,-1,-1,-1,-1,-1,-1,9,8,7,5,9,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,5,8,4,5,10,8,10,11,8,-1,-1,-1,-1,-1,-1,-1,5,0,4,5,11,0,5,10,11,11,3,0,-1,-1,-1,-1,0,1,9,8,4,10,8,10,11,10,4,5,-1,-1,-1,-1,10,11,4,10,4,5,11,3,4,9,4,1,3,1,4,-1,2,5,1,2,8,5,2,11,8,4,5,8,-1,-1,-1,-1,0,4,11,0,11,3,4,5,11,2,11,1,5,1,11,-1,0,2,5,0,5,9,2,11,5,4,5,8,11,8,5,-1,9,4,5,2,11,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,5,10,3,5,2,3,4,5,3,8,4,-1,-1,-1,-1,5,10,2,5,2,4,4,2,0,-1,-1,-1,-1,-1,-1,-1,3,10,2,3,5,10,3,8,5,4,5,8,0,1,9,-1,5,10,2,5,2,4,1,9,2,9,4,2,-1,-1,-1,-1,8,4,5,8,5,3,3,5,1,-1,-1,-1,-1,-1,-1,-1,0,4,5,1,0,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,4,5,8,5,3,9,0,5,0,3,5,-1,-1,-1,-1,9,4,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,11,7,4,9,11,9,10,11,-1,-1,-1,-1,-1,-1,-1,0,8,3,4,9,7,9,11,7,9,10,11,-1,-1,-1,-1,1,10,11,1,11,4,1,4,0,7,4,11,-1,-1,-1,-1,3,1,4,3,4,8,1,10,4,7,4,11,10,11,4,-1,4,11,7,9,11,4,9,2,11,9,1,2,-1,-1,-1,-1,9,7,4,9,11,7,9,1,11,2,11,1,0,8,3,-1,11,7,4,11,4,2,2,4,0,-1,-1,-1,-1,-1,-1,-1,11,7,4,11,4,2,8,3,4,3,2,4,-1,-1,-1,-1,2,9,10,2,7,9,2,3,7,7,4,9,-1,-1,-1,-1,9,10,7,9,7,4,10,2,7,8,7,0,2,0,7,-1,3,7,10,3,10,2,7,4,10,1,10,0,4,0,10,-1,1,10,2,8,7,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,9,1,4,1,7,7,1,3,-1,-1,-1,-1,-1,-1,-1,4,9,1,4,1,7,0,8,1,8,7,1,-1,-1,-1,-1,4,0,3,7,4,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,8,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,10,8,10,11,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,9,3,9,11,11,9,10,-1,-1,-1,-1,-1,-1,-1,0,1,10,0,10,8,8,10,11,-1,-1,-1,-1,-1,-1,-1,3,1,10,11,3,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,11,1,11,9,9,11,8,-1,-1,-1,-1,-1,-1,-1,3,0,9,3,9,11,1,2,9,2,11,9,-1,-1,-1,-1,0,2,11,8,0,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,2,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,8,2,8,10,10,8,9,-1,-1,-1,-1,-1,-1,-1,9,10,2,0,9,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,8,2,8,10,0,1,8,1,10,8,-1,-1,-1,-1,1,10,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,3,8,9,1,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,9,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,3,8,-1,-1,-1,-1,-1,-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 co(t,e,i,r,n){var s,o,a,c,l,h,u,d=[[0,4,4,4,2,0,0,0,2,2,0,0],[4,0,4,4,0,8,0,0,0,8,8,0],[4,4,0,4,0,0,8,0,0,0,8,8],[4,4,4,0,0,0,0,1,1,0,0,1],[2,0,0,0,0,8,8,8,2,2,0,0],[0,8,0,0,8,0,8,8,0,8,8,0],[0,0,8,0,8,8,0,8,0,0,8,8],[0,0,0,1,8,8,8,0,1,0,0,1],[2,0,0,1,2,0,0,1,0,2,0,1],[2,8,0,0,2,8,0,0,2,0,8,0],[0,8,8,0,0,8,8,0,0,8,0,8],[0,0,8,1,0,0,8,1,1,0,8,0]],m=0,f=!1,p=!1,g=!1,y=!1,b=-1,_=e*i*r,x=e,v=e*i,w=new Int32Array(12),A=[],S=[],C=[],P=[],I=oo(),k=ao();function M(t,e,i){return t+(e-t)*i}function T(t,n,s){return v*(s=(s+u)%r)+x*(n=(n+h)%i)+(t=(t+l)%e)}function D(t,e,i,r,c,l,h){var u=3*t;if(o[u]<0){var d=(m-l)/(h-l),p=s,g=3*a;if(A[g]=i+d,A[g+1]=r,A[g+2]=c,!f){var y=3*t;S[g]=b*M(p[y],p[y+3],d),S[g+1]=b*M(p[y+1],p[y+4],d),S[g+2]=b*M(p[y+2],p[y+5],d)}n&&(P[a]=n[t+Math.round(d)]),o[u]=a,w[e]=a,a+=1}else w[e]=o[u]}function B(t,e,i,r,c,l,h){var u=3*t+1;if(o[u]<0){var d=(m-l)/(h-l),p=s,g=3*a;if(A[g]=i,A[g+1]=r+d,A[g+2]=c,!f){var y=3*t,_=y+3*x;S[g]=b*M(p[y],p[_],d),S[g+1]=b*M(p[y+1],p[_+1],d),S[g+2]=b*M(p[y+2],p[_+2],d)}n&&(P[a]=n[t+Math.round(d)*x]),o[u]=a,w[e]=a,a+=1}else w[e]=o[u]}function F(t,e,i,r,c,l,h){var u=3*t+2;if(o[u]<0){var d=(m-l)/(h-l),p=s,g=3*a;if(A[g]=i,A[g+1]=r,A[g+2]=c+d,!f){var y=3*t,_=y+3*v;S[g]=b*M(p[y],p[_],d),S[g+1]=b*M(p[y+1],p[_+1],d),S[g+2]=b*M(p[y+2],p[_+2],d)}n&&(P[a]=n[t+Math.round(d)*v]),o[u]=a,w[e]=a,a+=1}else w[e]=o[u]}function E(e){var i=3*e;0===s[i]&&(s[i]=t[(e-1+_)%_]-t[(e+1)%_],s[i+1]=t[(e-x+_)%_]-t[(e+x)%_],s[i+2]=t[(e-v+_)%_]-t[(e+v)%_])}function $(e,i,r,n,s){var o,a,l,h,u,b,_;g?(n=T(e,i,r),o=T(e+1,i,r),a=T(e,i+1,r),l=T(e,i,r+1),h=T(e+1,i+1,r),u=T(e+1,i,r+1),b=T(e,i+1,r+1),_=T(e+1,i+1,r+1)):(o=n+1,h=(a=n+x)+1,u=(l=n+v)+1,_=(b=a+v)+1);var A=0,S=t[n],P=t[o],M=t[a],$=t[h],O=t[l],R=t[u],L=t[b],N=t[_];S=m){F=b,M=!0;break}if(M)break}if(M)break}for(M=!1,y=s;y=m){B=y,M=!0;break}if(M)break}if(M)break}for(M=!1,p=n;p=m){D=p,M=!0;break}if(M)break}if(M)break}for(M=!1,b=h;b>=a;--b){for(y=l;y>=s;--y){for(p=c;p>=n;--p)if(u=e*i*b+e*y+p,t[u]>=m){R=b,M=!0;break}if(M)break}if(M)break}for(M=!1,y=l;y>=s;--y){for(b=R;b>=a;--b){for(p=c;p>=n;--p)if(u=e*i*b+e*y+p,t[u]>=m){O=y,M=!0;break}if(M)break}if(M)break}for(M=!1,p=c;p>=n;--p){for(y=O;y>=s;--y){for(b=R;b>=a;--b)if(u=e*i*b+e*y+p,t[u]>=m){E=p,M=!0;break}if(M)break}if(M)break}f?(n=Math.max(0,D-1),s=Math.max(0,B-1),a=Math.max(0,F-1),c=Math.min(e-1,E+1),l=Math.min(i-1,O+1),h=Math.min(r-1,R+1)):(n=Math.max(1,D-1),s=Math.max(1,B-1),a=Math.max(1,F-1),c=Math.min(e-2,E+1),l=Math.min(i-2,O+1),h=Math.min(r-2,R+1))}var L=15;for(b=a;b0?-1:1,s||(s=new Float32Array(3*_)));var I=3*_;if(o&&o.length===I||(o=new Int32Array(I)),a=0,c=0,void 0!==x){var k=x[0].map(Math.round),M=x[1].map(Math.round);l=e*Math.ceil(Math.abs(k[0])/e),h=i*Math.ceil(Math.abs(k[1])/i),u=r*Math.ceil(Math.abs(k[2])/r),O(k[0],k[1],k[2],M[0],M[1],M[2])}else l=h=u=0,O();return A.length=3*a,f||(S.length=3*a),C.length=c,n&&(P.length=a),{position:new Float32Array(A),normal:f?void 0:new Float32Array(S),index:bt(C,A.length/3),atomindex:n?new Int32Array(P):void 0,contour:p}}}Ge.add("arrow",class extends Ws{get primitive(){return An}}),Ge.add("box",class extends Ws{get primitive(){return _n}}),Ge.add("cone",class extends Ws{get primitive(){return Sn}}),Ge.add("cylinder",class extends Ws{get primitive(){return wn}}),Ge.add("ellipsoid",class extends Ws{get primitive(){return Cn}}),Ge.add("octahedron",class extends Ws{get primitive(){return xn}}),Ge.add("sphere",class extends Ws{get primitive(){return bn}}),Ge.add("tetrahedron",class extends Ws{get primitive(){return vn}}),Ge.add("torus",class extends Ws{get primitive(){return Pn}}),Ge.add("point",class extends Ws{get primitive(){return kn}}),Ge.add("wideline",class extends Ws{get primitive(){return Mn}}),Object.assign(co,{__deps:[oo,ao,bt]});class lo{constructor(t,e){this.cols=t,this.rows=e,this.size=this.cols*this.rows,this.data=new Float32Array(this.size)}copyTo(t){t.data.set(this.data)}}function ho(t,e){let i=0,r=0;const n=e.rows,s=e.cols;let o=0,a=0,c=0;const l=e.data,h=t.data;for(;i(e=Math.abs(e))?(e/=t,t*Math.sqrt(1+e*e)):e>0?(t/=e,e*Math.sqrt(1+t*t)):0}const bo=1.192092896e-7,_o=1e-37;function xo(t,e,i,r){let n=0,s=0;const o=t.rows,a=t.cols;let c=o,l=a;c>16?E:-E,t[h*e+d]=F;for(m=0;m<2;m++)for(u=0;u{const e=t.data.sd,i=t.data.p;o(this._makeSurface(e,i.isolevel,i.smooth))}),(a=>{console.warn("Volume.getSurfaceWorker error - trying without worker",a);const c=this.getSurface(t,e,i,r,n,s);o(c)}))}else{const a=this.getSurface(t,e,i,r,n,s);o(a)}}getValueForSigma(t){return this.mean+rt(t,2)*this.rms}getSigmaForValue(t){return(rt(t,0)-this.mean)/this.rms}get position(){if(!this._position){const t=this.nz,e=this.ny,i=this.nx,r=new Float32Array(i*e*t*3);let n=0;for(let s=0;si){const t=e;e=i,i=t}const r=t[e];return void 0===r?(t[e]=[i],!0):!r.includes(i)&&(r.push(i),!0)}const i=this.geometry,r=i.index;if(this.parameters.wireframe)if(r){const n=r.array;let s,o=n.length;if(i.drawRange.count!==1/0&&(o=i.drawRange.count),this.wireframeIndex&&this.wireframeIndex.length>2*o)s=this.wireframeIndex;else{s=bt(2*o,i.attributes.position.count)}let a=0;t.length=0;for(let t=0;t2*t?this.wireframeIndex:bt(2*t,t);for(let i=0,r=0;ithis.wireframeGeometry.index.array.length)this.wireframeGeometry.setIndex(new M(this.wireframeIndex,1).setUsage(this.dynamic?$:O));else{const t=this.wireframeGeometry.getIndex();if(!t)return void ke.error("Index is null");t.set(this.wireframeIndex),t.needsUpdate=this.wireframeIndexCount>0,t.updateRange.count=this.wireframeIndexCount}this.wireframeGeometry.setDrawRange(0,this.wireframeIndexCount)}}getRenderOrder(){let t=0;return this.isText?t=1:this.transparent&&(t=this.isSurface?3:2),t}_getMesh(t){this.material||this.makeMaterial();const e=this.geometry,i=this[t];let r;return r=this.isLine?new T(e,i):this.isPoint?new o(e,i):new P(e,i),r.frustumCulled=!1,r.renderOrder=this.getRenderOrder(),r}getMesh(){return this._getMesh("material")}getWireframeMesh(){let t;return this.material||this.makeMaterial(),this.wireframeGeometry||this.makeWireframeGeometry(),t=new T(this.wireframeGeometry,this.wireframeMaterial),t.frustumCulled=!1,t.renderOrder=this.getRenderOrder(),t}getPickingMesh(){return this._getMesh("pickingMaterial")}getShader(t,e){return pi(t,this.getDefines(e))}getVertexShader(t){return this.getShader(this.vertexShader,t)}getFragmentShader(t){return this.getShader(this.fragmentShader,t)}getDefines(t){const e={};return this.parameters.clipNear&&(e.NEAR_CLIP=1),this.parameters.clipRadius&&(e.RADIUS_CLIP=1),"picking"===t?e.PICKING=1:(("background"===t||this.parameters.background)&&(e.NOLIGHT=1),this.parameters.flatShaded&&(e.FLAT_SHADED=1),this.parameters.opaqueBack&&(e.OPAQUE_BACK=1),this.parameters.diffuseInterior&&(e.DIFFUSE_INTERIOR=1),this.parameters.useInteriorColor&&(e.USE_INTERIOR_COLOR=1)),e}getParameters(){return this.parameters}addUniforms(t){this.uniforms=F.merge([this.uniforms,t]),this.pickingUniforms=F.merge([this.pickingUniforms,t])}addAttributes(t){for(let e in t){let i;const r=t[e],n=this.attributeSize*Ro[r.type];r.value?(n!==r.value.length&&ke.error("attribute value has wrong length",e),i=r.value):i=yt("float32",n),this.geometry.setAttribute(e,new M(i,Ro[r.type]).setUsage(this.dynamic?$:O))}}updateRenderOrder(){const t=this.getRenderOrder();function e(e){e.renderOrder=t}this.group.children.forEach(e),this.pickingGroup&&this.pickingGroup.children.forEach(e)}updateShader(){const t=this.material,e=this.wireframeMaterial,i=this.pickingMaterial;t.vertexShader=this.getVertexShader(),t.fragmentShader=this.getFragmentShader(),t.needsUpdate=!0,e.vertexShader=this.getShader("Line.vert"),e.fragmentShader=this.getShader("Line.frag"),e.needsUpdate=!0,i.vertexShader=this.getVertexShader("picking"),i.fragmentShader=this.getFragmentShader("picking"),i.needsUpdate=!0}setParameters(t){const e=t,i=this.parameterTypes,r=this.parameters,n={},s={};let o=!1,a=!1;for(const t in e){const c=e[t];void 0!==c&&(r[t]=c,void 0!==i[t]&&(i[t].property&&(!0!==i[t].property?n[i[t].property]=c:n[t]=c),i[t].uniform&&(!0!==i[t].uniform?s[i[t].uniform]=c:s[t]=c),i[t].updateShader&&(o=!0),i[t].updateVisibility&&(a=!0),this.dynamic&&"wireframe"===t&&!0===c&&this.updateWireframeIndex(),"forceTransparent"===t&&(n.transparent=this.transparent),"matrix"===t&&(this.matrix=c)))}this.setProperties(n),this.setUniforms(s),o&&this.updateShader(),a&&this.setVisibility(this.visible)}setAttributes(t){const e=this.geometry,i=e.attributes;for(const r in t){if("picking"===r)continue;const n=t[r],s=n.length;if("index"===r){const t=e.getIndex();if(!t){ke.error("Index is null");continue}e.setDrawRange(0,1/0),s>t.array.length?e.setIndex(new M(n,1).setUsage(this.dynamic?$:O)):(t.set(n),t.needsUpdate=s>0,t.updateRange.count=s,e.setDrawRange(0,s)),this.indexVersion++,this.parameters.wireframe&&this.updateWireframeIndex()}else{const t=i[r];s>t.array.length?e.setAttribute(r,new M(n,t.itemSize).setUsage(this.dynamic?$:O)):(i[r].set(n),i[r].needsUpdate=s>0,i[r].updateRange.count=s)}}}setUniforms(t){if(!t)return;const e=this.material.uniforms,i=this.wireframeMaterial.uniforms,r=this.pickingMaterial.uniforms;for(let n in t)"opacity"===n&&this.setProperties({transparent:this.transparent}),void 0!==e[n]&&(e[n].value.isVector3?e[n].value.copy(t[n]):e[n].value.set?e[n].value.set(t[n]):e[n].value=t[n]),void 0!==i[n]&&(i[n].value.isVector3?i[n].value.copy(t[n]):i[n].value.set?i[n].value.set(t[n]):i[n].value=t[n]),void 0!==r[n]&&(r[n].value.isVector3?r[n].value.copy(t[n]):r[n].value.set?r[n].value.set(t[n]):r[n].value=t[n])}setProperties(t){if(!t)return;const e=this.material,i=this.wireframeMaterial,r=this.pickingMaterial;for(const n in t){const s=n;let o=t[s];"transparent"===s?this.updateRenderOrder():"side"===s&&(o=Oo(o)),e[s]=o,i[s]=o,r[s]=o}e.needsUpdate=!0,i.needsUpdate=!0,r.needsUpdate=!0}setVisibility(t){this.visible=t,this.parameters.wireframe?(this.group.visible=!1,this.wireframeGroup.visible=t,this.pickable&&(this.pickingGroup.visible=!1)):(this.group.visible=t,this.wireframeGroup.visible=!1,this.pickable&&(this.pickingGroup.visible=t))}dispose(){this.material&&this.material.dispose(),this.wireframeMaterial&&this.wireframeMaterial.dispose(),this.pickingMaterial&&this.pickingMaterial.dispose(),this.geometry.dispose(),this.wireframeGeometry&&this.wireframeGeometry.dispose()}toJSON(){var t={};for(var e in this)"group"!==e&&"wireframeGroup"!==e&&"pickingGroup"!=e&&"picking"!==e&&(t[e]=this[e]);return t}}class Vo extends Uo{constructor(t,e={}){super(t,e),this.vertexShader="Mesh.vert",this.fragmentShader="Mesh.frag",this.addAttributes({normal:{type:"v3",value:t.normal}}),void 0===t.normal&&this.geometry.computeVertexNormals()}}class jo extends Vo{constructor(){super(...arguments),this.isSurface=!0}}function Go(t){t.visible=!0}function Ho(t){t.visible=!1}class qo{constructor(t){this.group=new d,this.wireframeGroup=new d,this.pickingGroup=new d,this.frontMeshes=[],this.backMeshes=[],this.size=t.size,this.side=t.parameters.side,this.visible=t.visible,this.geometry=t.geometry,this.picking=t.picking,this.group=new d,this.wireframeGroup=new d,this.pickingGroup=new d,this.matrix=t.matrix;const e=t,i=new t.constructor({position:new Float32Array(0)});e.makeMaterial(),i.makeMaterial(),i.picking=t.picking,i.geometry=t.geometry,i.wireframeGeometry=t.wireframeGeometry,i.setParameters(t.getParameters()),i.updateShader(),e.setParameters({side:"front"}),i.setParameters({side:"back",opacity:i.parameters.opacity}),this.buffer=t,this.frontBuffer=e,this.backBuffer=i}set matrix(t){Uo.prototype.setMatrix.call(this,t)}get matrix(){return this.group.matrix.clone()}get pickable(){return!!this.picking&&!this.parameters.disablePicking}get parameters(){return this.buffer.parameters}getParameters(){const t=Object.assign({},this.buffer.parameters);return t.side=this.side,t}getMesh(t){let e,i;return t?(i=this.backBuffer.getPickingMesh(),e=this.frontBuffer.getPickingMesh()):(i=this.backBuffer.getMesh(),e=this.frontBuffer.getMesh()),this.frontMeshes.push(e),this.backMeshes.push(i),this.setParameters({side:this.side}),(new d).add(i,e)}getWireframeMesh(){return this.buffer.getWireframeMesh()}getPickingMesh(){return this.getMesh(!0)}setAttributes(t){this.buffer.setAttributes(t)}setParameters(t){"front"===(t=Object.assign({},t)).side?(this.frontMeshes.forEach(Go),this.backMeshes.forEach(Ho)):"back"===t.side?(this.frontMeshes.forEach(Ho),this.backMeshes.forEach(Go)):"double"===t.side&&(this.frontMeshes.forEach(Go),this.backMeshes.forEach(Go)),void 0!==t.side&&(this.side=t.side),delete t.side,void 0!==t.matrix&&(this.matrix=t.matrix),delete t.matrix,this.frontBuffer.setParameters(t),void 0!==t.wireframe&&(this.wireframe=t.wireframe,this.setVisibility(this.visible)),delete t.wireframe,this.backBuffer.setParameters(t)}setVisibility(t){this.visible=t,this.parameters.wireframe?(this.group.visible=!1,this.wireframeGroup.visible=t,this.pickable&&(this.pickingGroup.visible=!1)):(this.group.visible=t,this.wireframeGroup.visible=!1,this.pickable&&(this.pickingGroup.visible=t))}dispose(){this.frontBuffer.dispose(),this.backBuffer.dispose()}toJSON(){var t={};for(var e in this)["side","size","visible","matrix","parameters"].includes(e)&&(t[e]=this[e]);return t}}ze.add("shader/Line.vert","uniform float clipNear;\nuniform vec3 clipCenter;\nvarying vec3 vViewPosition;\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#include color_pars_vertex\nvoid main(){\n#include color_vertex\n#include begin_vertex\n#include project_vertex\nvViewPosition = -mvPosition.xyz;\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n#include nearclip_vertex\n}"),ze.add("shader/Line.frag","uniform float opacity;\nuniform float clipNear;\nuniform float clipRadius;\nvarying vec3 vViewPosition;\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#include common\n#include color_pars_fragment\n#include fog_pars_fragment\nvoid main(){\n#include nearclip_fragment\n#include radiusclip_fragment\ngl_FragColor = vec4( vColor, opacity );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n}");class Wo extends Uo{constructor(){super(...arguments),this.isLine=!0,this.vertexShader="Line.vert",this.fragmentShader="Line.frag"}}class Xo extends Nr{constructor(t,r,n){super(t,r,n),this.type="surface",this.parameters=Object.assign({isolevelType:{type:"select",options:{value:"value",sigma:"sigma"}},isolevel:{type:"number",precision:2,max:1e3,min:-1e3},negateIsolevel:{type:"boolean"},isolevelScroll:{type:"boolean"},smooth:{type:"integer",precision:1,max:10,min:0},background:{type:"boolean",rebuild:!0},opaqueBack:{type:"boolean",buffer:!0},boxSize:{type:"integer",precision:1,max:100,min:0},colorVolume:{type:"hidden"},contour:{type:"boolean",rebuild:!0},useWorker:{type:"boolean",rebuild:!0},wrap:{type:"boolean",rebuild:!0}},this.parameters),t instanceof $o?(this.surface=void 0,this.volume=t):(this.surface=t,this.volume=void 0),this.boxCenter=new e,this.__boxCenter=new e,this.box=new a,this.__box=new a,this._position=new e,this.inverseMatrix=new i,this.setBox=function(){this._position.copy(r.translationGroup.position).negate(),this._position.applyMatrix4(this.inverseMatrix),this._position.equals(this.boxCenter)||this.setParameters({boxCenter:this._position})},this.toBePrepared=!0,this.viewer.signals.ticked.add(this.setBox,this),this.init(n)}init(t){const e=t||{};e.colorScheme=rt(e.colorScheme,"uniform"),e.colorValue=rt(e.colorValue,14540253),this.isolevelType=rt(e.isolevelType,"sigma"),this.isolevel=rt(e.isolevel,2),this.negateIsolevel=rt(e.negateIsolevel,!1),this.isolevelScroll=rt(e.isolevelScroll,!1),this.smooth=rt(e.smooth,0),this.background=rt(e.background,!1),this.opaqueBack=rt(e.opaqueBack,!0),this.boxSize=rt(e.boxSize,0),this.colorVolume=rt(e.colorVolume,void 0),this.contour=rt(e.contour,!1),this.useWorker=rt(e.useWorker,!0),this.wrap=rt(e.wrap,!1),super.init(e),this.inverseMatrix.copy(this.matrix).invert(),this.build()}attach(t){this.bufferList.forEach((t=>{this.viewer.add(t)})),this.setVisibility(this.visible),t()}prepare(t){if(this.volume){let e;if(e="sigma"===this.isolevelType?this.volume.getValueForSigma(this.isolevel):this.isolevel,this.negateIsolevel&&(e*=-1),!this.surface||this.__isolevel!==e||this.__smooth!==this.smooth||this.__contour!==this.contour||this.__wrap!==this.wrap||this.__boxSize!==this.boxSize||this.boxSize>0&&!this.__boxCenter.equals(this.boxCenter)){this.__isolevel=e,this.__smooth=this.smooth,this.__contour=this.contour,this.__wrap=this.wrap,this.__boxSize=this.boxSize,this.__boxCenter.copy(this.boxCenter),this.__box.copy(this.box);const i=e=>{this.surface=e,t()};this.useWorker?this.volume.getSurfaceWorker(e,this.smooth,this.boxCenter,this.boxSize,this.contour,this.wrap,i):i(this.volume.getSurface(e,this.smooth,this.boxCenter,this.boxSize,this.contour,this.wrap))}else t()}else t()}create(){const t={position:this.surface.getPosition(),color:this.surface.getColor(this.getColorParams()),index:this.surface.getIndex()};let e;if(this.contour)e=new Wo(t,this.getBufferParams({wireframe:!1}));else{Object.assign(t,{normal:this.surface.getNormal(),picking:this.surface.getPicking()});const i=new jo(t,this.getBufferParams({background:this.background,opaqueBack:this.opaqueBack,dullInterior:!1}));e=new qo(i)}this.bufferList.push(e)}update(t){if(0===this.bufferList.length)return;const e={};(t=t||{}).position&&(e.position=this.surface.getPosition()),t.color&&(e.color=this.surface.getColor(this.getColorParams())),t.index&&(e.index=this.surface.getIndex()),t.normal&&(e.normal=this.surface.getNormal()),this.bufferList.forEach((function(t){t.setAttributes(e)}))}setParameters(t,e,i){return t&&void 0!==t.isolevelType&&this.volume&&("value"===this.isolevelType&&"sigma"===t.isolevelType?this.isolevel=this.volume.getSigmaForValue(this.isolevel):"sigma"===this.isolevelType&&"value"===t.isolevelType&&(this.isolevel=this.volume.getValueForSigma(this.isolevel)),this.isolevelType=t.isolevelType),t&&t.boxCenter&&(this.boxCenter.copy(t.boxCenter),delete t.boxCenter),t&&t.wireframe&&(t.contour||void 0===t.contour&&this.contour)&&(t.wireframe=!1),super.setParameters(t,e,i),t.matrix&&this.inverseMatrix.copy(t.matrix).invert(),this.volume&&this.volume.getBox(this.boxCenter,this.boxSize,this.box),t&&void 0!==t.colorVolume&&e&&(e.color=!0),this.surface&&(void 0!==t.isolevel||void 0!==t.negateIsolevel||void 0!==t.smooth||void 0!==t.wrap||void 0!==t.boxSize||this.boxSize>0&&!this.__box.equals(this.box))&&this.build({position:!0,color:!0,index:!0,normal:!this.contour}),this}getColorParams(){const t=super.getColorParams();return t.volume=this.colorVolume,t}dispose(){this.viewer.signals.ticked.remove(this.setBox,this),super.dispose()}}class Yo{static zoomScroll(t,e){t.trackballControls.zoom(e)}static clipNearScroll(t,e){const i=t.getParameters();t.setParameters({clipNear:i.clipNear+e/10})}static focusScroll(t,e){const i=t.getFocus(),r=Math.sign(e)*function(t,e,i){if(t>e)return t;const r=t/e;return((2*i-e)*r+(2*e-3*i))*r*r+i}((100-i)/10,5,.2);t.setFocus(i+r)}static zoomFocusScroll(t,e){t.trackballControls.zoom(e);const i=t.viewer.camera.position.z;t.setFocus(100-Math.abs(i/8))}static isolevelScroll(t,e){const i=Math.sign(e)/10;t.eachRepresentation(((t,e)=>{if(t.repr instanceof Xo){const e=t.getParameters();e.isolevelScroll&&t.setParameters({isolevel:e.isolevel+i})}}))}static panDrag(t,e,i){t.trackballControls.pan(e,i)}static rotateDrag(t,e,i){t.trackballControls.rotate(e,i)}static zRotateDrag(t,e,i){t.trackballControls.zRotate(e,i)}static zoomDrag(t,e,i){t.trackballControls.zoom((e+i)/-2)}static zoomFocusDrag(t,e,i){t.trackballControls.zoom((e+i)/-2);const r=t.viewer.camera.position.z;t.setFocus(100-Math.abs(r/8))}static panComponentDrag(t,e,i){t.trackballControls.panComponent(e,i)}static panAtomDrag(t,e,i){t.trackballControls.panAtom(e,i)}static rotateComponentDrag(t,e,i){t.trackballControls.rotateComponent(e,i)}static movePick(t,e){e&&t.animationControls.move(e.position.clone())}static tooltipPick(t,e){const i=t.tooltip;if(t.getParameters().tooltip&&e){const t=e.mouse.position;i.innerText=e.getLabel(),i.style.bottom=window.innerHeight-t.y+3+"px",i.style.left=t.x+3+"px",i.style.display="block"}else i.style.display="none"}static measurePick(t,e){if(e&&(e.atom||e.bond)){const t=e.atom||e.closestBondAtom;e.component.measurePick(t)}else t.measureClear()}}const Ko={default:[["scroll",Yo.zoomScroll],["scroll-shift",Yo.focusScroll],["scroll-ctrl",Yo.isolevelScroll],["scroll-shift-ctrl",Yo.zoomFocusScroll],["drag-left",Yo.rotateDrag],["drag-right",Yo.panDrag],["drag-ctrl-left",Yo.panDrag],["drag-ctrl-right",Yo.zRotateDrag],["drag-shift-left",Yo.zoomDrag],["drag-middle",Yo.zoomFocusDrag],["drag-ctrl-shift-right",Yo.panComponentDrag],["drag-ctrl-shift-left",Yo.rotateComponentDrag],["clickPick-right",Yo.measurePick],["clickPick-ctrl-left",Yo.measurePick],["clickPick-middle",Yo.movePick],["clickPick-left",Yo.movePick],["hoverPick",Yo.tooltipPick]],pymol:[["drag-left",Yo.rotateDrag],["drag-middle",Yo.panDrag],["drag-right",Yo.zoomDrag],["scroll",Yo.focusScroll],["drag-shift-right",Yo.focusScroll],["clickPick-ctrl+shift-middle",Yo.movePick],["hoverPick",Yo.tooltipPick]],coot:[["scroll",Yo.isolevelScroll],["drag-left",Yo.rotateDrag],["drag-middle",Yo.panDrag],["drag-ctrl-left",Yo.panDrag],["drag-right",Yo.zoomFocusDrag],["drag-ctrl-right",Yo.focusScroll],["clickPick-middle",Yo.movePick],["hoverPick",Yo.tooltipPick]],astexviewer:[["drag-left",Yo.rotateDrag],["drag-ctrl-left",Yo.panDrag],["drag-shift-left",Yo.zoomDrag],["scroll",Yo.focusScroll],["clickPick-middle",Yo.movePick],["hoverPick",Yo.tooltipPick]]};function Zo(t){const e=t.split(/[-+]/);let i="";e.includes("scroll")&&(i="scroll"),e.includes("drag")&&(i="drag"),e.includes("click")&&(i="click"),e.includes("doubleClick")&&(i="doubleClick"),e.includes("hover")&&(i="hover"),e.includes("clickPick")&&(i="clickPick"),e.includes("hoverPick")&&(i="hoverPick");let r=0;e.includes("alt")&&(r+=1),e.includes("ctrl")&&(r+=2),e.includes("meta")&&(r+=4),e.includes("shift")&&(r+=8);let n=0;return e.includes("left")&&(n+=1),e.includes("right")&&(n+=2),e.includes("middle")&&(n+=4),[i,r,n]}class Qo{constructor(t,e={}){this.stage=t,this.actionList=[],this.mouse=t.mouseObserver,this.disabled=e.disabled||!1,this.preset(e.preset||"default")}run(t,...e){if(this.disabled)return;const i=this.mouse.key||0,r=this.mouse.buttons||0;this.actionList.forEach((n=>{n.type===t&&n.key===i&&n.button===r&&n.callback(this.stage,...e)}))}add(t,e){const[i,r,n]=Zo(t);this.actionList.push({type:i,key:r,button:n,callback:e})}remove(t,e){const i=t.includes("*"),[r,n,s]=Zo(t),o=this.actionList.filter((function(t){return!((t.type===r||i&&""===r)&&(t.key===n||i&&0===n)&&(t.button===s||i&&0===s)&&(t.callback===e||void 0===e))}));this.actionList=o}preset(t){this.clear();(Ko[t]||[]).forEach((t=>this.add(t[0],t[1])))}clear(){this.actionList.length=0}}class Jo{static autoView(t){t.autoView(1e3)}static toggleAnimations(t){t.animationControls.toggle()}static toggleRock(t){t.toggleRock()}static toggleSpin(t){t.toggleSpin()}static toggleAntialiasing(t){const e=t.getParameters();t.setParameters({sampleLevel:-1===e.sampleLevel?0:-1})}}const ta={default:[["i",Jo.toggleSpin],["k",Jo.toggleRock],["p",Jo.toggleAnimations],["a",Jo.toggleAntialiasing],["r",Jo.autoView]]};class ea{constructor(t,e={}){this.stage=t,this.actionList=[],this.disabled=e.disabled||!1,this.preset(e.preset||"default")}run(t){this.disabled||this.actionList.forEach((e=>{e.key===t&&e.callback(this.stage)}))}add(t,e){this.actionList.push({key:t,callback:e})}remove(t,e){const i=this.actionList.filter((function(i){return!(i.key===t&&(i.callback===e||void 0===e))}));this.actionList=i}preset(t){this.clear();(ta[t]||[]).forEach((t=>this.add(t[0],t[1])))}clear(){this.actionList.length=0}}class ia{constructor(t){this.stage=t,this.stage=t,this.mouse=t.mouseObserver,this.controls=t.mouseControls,this.mouse.signals.clicked.add(this._onClick,this),this.mouse.signals.hovered.add(this._onHover,this)}_onClick(t,e){const i=this.stage.pickingControls.pick(t,e);this.stage.signals.clicked.dispatch(i),this.controls.run("clickPick",i)}_onHover(t,e){const i=this.stage.pickingControls.pick(t,e);i&&this.mouse.down.equals(this.mouse.position)&&(this.stage.transformComponent=i.component,this.stage.transformAtom=i.atom),this.stage.signals.hovered.dispatch(i),this.controls.run("hoverPick",i)}dispose(){this.mouse.signals.clicked.remove(this._onClick,this),this.mouse.signals.hovered.remove(this._onHover,this)}}class ra{constructor(t){this.stage=t,this.stage=t,this.mouse=t.mouseObserver,this.controls=t.mouseControls,this.mouse.signals.moved.add(this._onMove,this),this.mouse.signals.scrolled.add(this._onScroll,this),this.mouse.signals.dragged.add(this._onDrag,this),this.mouse.signals.clicked.add(this._onClick,this),this.mouse.signals.hovered.add(this._onHover,this),this.mouse.signals.doubleClicked.add(this._onDblclick,this)}_onMove(){this.stage.tooltip.style.display="none"}_onScroll(t){this.controls.run("scroll",t)}_onDrag(t,e){this.controls.run("drag",t,e)}_onClick(t,e){this.controls.run("click",t,e)}_onDblclick(t,e){this.controls.run("doubleClick",t,e)}_onHover(t,e){this.controls.run("hover",t,e)}dispose(){this.mouse.signals.moved.remove(this._onMove,this),this.mouse.signals.scrolled.remove(this._onScroll,this),this.mouse.signals.dragged.remove(this._onDrag,this),this.mouse.signals.clicked.remove(this._onClick,this),this.mouse.signals.hovered.remove(this._onHover,this)}}class na{constructor(t){this.stage=t,this.viewer=t.viewer,this.animationControls=t.animationControls,this.viewer.signals.ticked.add(this._onTick,this)}_onTick(t){this.animationControls.run(t)}dispose(){this.viewer.signals.ticked.remove(this._onTick,this)}}const sa=!!we&&{passive:!0};class oa{constructor(t){this.stage=t,this.stage=t,this.controls=t.keyControls,this.domElement=t.viewer.renderer.domElement,this.domElement.setAttribute("tabIndex","-1"),this.domElement.style.outline="none",this._focusDomElement=this._focusDomElement.bind(this),this._onKeydown=this._onKeydown.bind(this),this._onKeyup=this._onKeyup.bind(this),this._onKeypress=this._onKeypress.bind(this),this.domElement.addEventListener("mousedown",this._focusDomElement),this.domElement.addEventListener("touchstart",this._focusDomElement,sa),this.domElement.addEventListener("keydown",this._onKeydown),this.domElement.addEventListener("keyup",this._onKeyup),this.domElement.addEventListener("keypress",this._onKeypress)}_onKeydown(){}_onKeyup(){}_onKeypress(t){let e;e="key"in KeyboardEvent.prototype?t.key:String.fromCharCode(t.which||t.keyCode),this.controls.run(e)}_focusDomElement(){this.domElement.focus()}dispose(){this.domElement.removeEventListener("mousedown",this._focusDomElement),this.domElement.removeEventListener("touchstart",this._focusDomElement,sa),this.domElement.removeEventListener("keydown",this._onKeypress),this.domElement.removeEventListener("keyup",this._onKeypress),this.domElement.removeEventListener("keypress",this._onKeypress)}}class aa{constructor(i,r,n,s={}){this.component=i,this.position=r,this.offsetX=rt(s.offsetX,0),this.offsetY=rt(s.offsetY,0),this.visible=rt(s.visible,!0),this.stage=i.stage,this.viewer=i.stage.viewer,this._viewerPosition=new e,this._updateViewerPosition(),this._canvasPosition=new t,this._cameraPosition=new e,this.element=document.createElement("div"),Object.assign(this.element.style,{display:"block",position:"absolute",pointerEvents:"none",whiteSpace:"nowrap",left:"-10000px"}),this.viewer.wrapper.appendChild(this.element),this.setContent(n),this.updateVisibility(),this.viewer.signals.rendered.add(this._update,this),this.component.signals.matrixChanged.add(this._updateViewerPosition,this)}setContent(t){const e=this.element.style.display;if("none"===e&&(this.element.style.left="-10000px",this.element.style.display="block"),t instanceof HTMLElement)this.element.appendChild(t);else{const e=document.createElement("div");e.innerText=t,Object.assign(e.style,{backgroundColor:"rgba( 0, 0, 0, 0.6 )",color:"lightgrey",padding:"8px",fontFamily:"sans-serif"}),this.element.appendChild(e)}this._clientRect=this.element.getBoundingClientRect(),"none"===e&&(this.element.style.display=e)}setVisibility(t){this.visible=t,this.updateVisibility()}getVisibility(){return this.visible&&this.component.parameters.visible}updateVisibility(){this.element.style.display=this.getVisibility()?"block":"none"}_updateViewerPosition(){this._viewerPosition.copy(this.position).applyMatrix4(this.component.matrix)}_update(){if(!this.getVisibility())return;const t=this.element.style,e=this._canvasPosition,i=this._viewerPosition,r=this._clientRect;if(this._cameraPosition.copy(i).add(this.viewer.translationGroup.position).applyMatrix4(this.viewer.rotationGroup.matrix).sub(this.viewer.camera.position),this._cameraPosition.z<0)return void(t.display="none");t.display="block";const n=this._cameraPosition.length(),s=this.viewer.scene.fog;t.opacity=(1-Et(s.near,s.far,n)).toString(),t.zIndex=Math.round(100*(s.far-n)).toString(),this.stage.viewerControls.getPositionOnCanvas(i,e),t.bottom=this.offsetX+e.y+r.height/2+"px",t.left=this.offsetY+e.x-r.width/2+"px"}dispose(){this.viewer.wrapper.removeChild(this.element),this.viewer.signals.ticked.remove(this._update,this),this.component.signals.matrixChanged.remove(this._updateViewerPosition,this)}}const ca=new i,la=new e,ha=new r;class ua{constructor(t){this.component=t,this.signals={changed:new J.Signal},this.stage=t.stage,this.viewer=t.stage.viewer}get position(){return this.component.position}get rotation(){return this.component.quaternion}changed(){this.component.updateMatrix(),this.viewer.requestRender(),this.signals.changed.dispatch()}spin(t,e){ca.copy(this.viewer.rotationGroup.matrix).invert(),la.copy(vt(t)).applyMatrix4(ca),ca.extractRotation(this.component.transform),ca.premultiply(this.viewer.rotationGroup.matrix),ca.invert(),la.copy(vt(t)),la.applyMatrix4(ca),ca.makeRotationAxis(la,e),ha.setFromRotationMatrix(ca),this.component.quaternion.premultiply(ha),this.changed()}}const da={"":"",vdw:"by vdW radius",covalent:"by covalent radius",sstruc:"by secondary structure",bfactor:"by bfactor",size:"size",data:"data",explicit:"explicit"};class ma{constructor(t={}){this.max=10,this.type=rt(t.type,"size"),this.scale=rt(t.scale,1),this.size=rt(t.size,1),this.data=rt(t.data,{})}atomRadius(t){let e;switch(this.type){case"vdw":e=t.vdw;break;case"covalent":e=t.covalent;break;case"bfactor":e=t.bfactor||1;break;case"sstruc":const i=t.sstruc;e="h"===i||"g"===i||"i"===i||"e"===i||"b"===i?.25:us.includes(t.atomname)?.4:.1;break;case"data":e=rt(this.data[t.index],1);break;case"explicit":e=t.radius,null===e&&(e=this.size);break;default:e=this.size}return Math.min(e*this.scale,this.max)}}ma.types=da;const fa=new e(-1,-1,-1),pa=new i;class ga{constructor(t){const i=t.rows,r=i/3,n=new lo(i,3),s=new lo(3,3),o=new lo(1,3),a=new lo(3,3),c=new lo(3,3),l=fo(t);po(t,l),ho(n,t),uo(s,n,n),xo(s,o,a,c);const h=new e(l[0],l[1],l[2]),u=new e(a.data[0],a.data[3],a.data[6]),d=new e(a.data[1],a.data[4],a.data[7]),m=new e(a.data[2],a.data[5],a.data[8]),f=u.clone().multiplyScalar(Math.sqrt(o.data[0]/r)),p=d.clone().multiplyScalar(Math.sqrt(o.data[1]/r)),g=m.clone().multiplyScalar(Math.sqrt(o.data[2]/r));this.begA=h.clone().sub(f),this.endA=h.clone().add(f),this.begB=h.clone().sub(p),this.endB=h.clone().add(p),this.begC=h.clone().sub(g),this.endC=h.clone().add(g),this.center=h,this.vecA=f,this.vecB=p,this.vecC=g,this.normVecA=u,this.normVecB=d,this.normVecC=m}getBasisMatrix(t=new i){const e=t;return e.makeBasis(this.normVecB,this.normVecA,this.normVecC),e.determinant()<0&&e.scale(fa),e}getRotationQuaternion(t=new r){const e=t;return e.setFromRotationMatrix(this.getBasisMatrix(pa)),e.invert()}getProjectedScaleForAtoms(t){let i=-1/0,r=-1/0,n=-1/0,s=-1/0,o=-1/0,a=-1/0;const c=new e,l=new e,h=this.center,u=this.normVecA,d=this.normVecB,m=this.normVecC;return t.eachAtom((function(t){jr(c.copy(t),u,h);const e=l.subVectors(c,h).normalize().dot(u),f=c.distanceTo(h);e>0?f>i&&(i=f):f>r&&(r=f),jr(c.copy(t),d,h);const p=l.subVectors(c,h).normalize().dot(d),g=c.distanceTo(h);p>0?g>n&&(n=g):g>s&&(s=g),jr(c.copy(t),m,h);const y=l.subVectors(c,h).normalize().dot(m),b=c.distanceTo(h);y>0?b>o&&(o=b):b>a&&(a=b)})),{d1a:i,d2a:n,d3a:o,d1b:-r,d2b:-s,d3b:-a}}}class ya{constructor(t,e,i,r){this.volume=t,this.setFilter(e,i,r)}get header(){return this.volume.header}get matrix(){return this.volume.matrix}get normalMatrix(){return this.volume.normalMatrix}get inverseMatrix(){return this.volume.inverseMatrix}get center(){return this.volume.center}get boundingBox(){return this.volume.boundingBox}get min(){return this.volume.min}get max(){return this.volume.max}get mean(){return this.volume.mean}get rms(){return this.volume.rms}_getFilterHash(t,e,i){return JSON.stringify([t,e,i])}setFilter(t,e,i){isNaN(t)&&this.header&&(t=this.header.DMEAN+2*this.header.ARMS),t=void 0===t||isNaN(t)?-1/0:t,e=rt(e,1/0),i=rt(i,!1);const r=this.volume.data,n=this.volume.position,s=this.volume.atomindex,o=this._getFilterHash(t,e,i);if(o!==this._filterHash){if(t===-1/0&&e===1/0)this.data=r,this.position=n,this.atomindex=s;else{const o=r.length;this._dataBuffer||(this._dataBuffer=new ArrayBuffer(4*o),this._positionBuffer=new ArrayBuffer(3*o*4),s&&(this._atomindexBuffer=new ArrayBuffer(4*o)));const a=new Float32Array(this._dataBuffer),c=new Float32Array(this._positionBuffer);let l;s&&(l=new Uint32Array(this._atomindexBuffer));let h=0;for(let u=0;u=t&&d<=e||i&&(de)){const t=3*h;a[h]=d,c[t+0]=n[o+0],c[t+1]=n[o+1],c[t+2]=n[o+2],s&&l&&(l[h]=s[u]),h+=1}}this.data=new Float32Array(this._dataBuffer,0,h),this.position=new Float32Array(this._positionBuffer,0,3*h),s&&(this.atomindex=new Int32Array(this._atomindexBuffer,0,h))}this._filterHash=o}}}ya.prototype.getValueForSigma=$o.prototype.getValueForSigma,ya.prototype.getSigmaForValue=$o.prototype.getSigmaForValue,ya.prototype.getDataAtomindex=$o.prototype.getDataAtomindex,ya.prototype.getDataPosition=$o.prototype.getDataPosition,ya.prototype.getDataColor=$o.prototype.getDataColor,ya.prototype.getDataPicking=$o.prototype.getDataPicking,ya.prototype.getDataSize=$o.prototype.getDataSize;class ba{constructor(t,e){const i=$n({nodeArray1:t.atomIndex1,nodeArray2:t.atomIndex2,edgeCount:t.count,nodeCount:e});this.countArray=i.countArray,this.offsetArray=i.offsetArray,this.indexArray=i.indexArray}}class _a extends Dn{get _defaultFields(){return[["atomIndex1",1,"int32"],["atomIndex2",1,"int32"],["bondOrder",1,"int8"]]}addBond(t,e,i){this.growIfFull();const r=this.count,n=t.index,s=e.index;n0&&(a[e]=x.angleTo(v));const r=Math.cos(p.angleTo(g));h[e]=180/Math.PI*Math.acos(r);const n=p.length(),_=g.length();c[e]=Math.sqrt(_*n)/Math.max(2,2*(1-r)),l[e]=Math.abs(m.dot(x)),y.copy(p).multiplyScalar(c[e]/n),b.copy(g).multiplyScalar(c[e]/_),y.subVectors(P,y),b.subVectors(I,b),y.toArray(s,i+3),b.toArray(s,i+6),w.subVectors(C,A),w.toArray(u,i),v.copy(x),A.copy(y)}y.fromArray(s,3),b.fromArray(s,6),x.subVectors(y,b).normalize(),C.index=t.getAtomIndexByType(0,S),A.copy(C),_.copy(C),jr(_,x,y),_.toArray(s,0),w.subVectors(A,y),w.toArray(u,0),y.fromArray(s,3*r-6),b.fromArray(s,3*r-9),x.subVectors(y,b).normalize(),C.index=t.getAtomIndexByType(r-1,S),A.copy(C),_.copy(C),jr(_,x,y),_.toArray(s,3*r-3);for(let e=r-3;ei||h.bending[e]>t)&&(O=!0)),O){if(e-f<4){f=e,O=!1;continue}F.index=D.traceAtomIndex,I=h.axis.subarray(3*f+3,3*e),k=h.center.subarray(3*f,3*e+3),C=Vr(I).normalize(),P=Vr(k),M.fromArray(k),jr(M,C,P),T.fromArray(k,k.length-3),jr(T,C,P),C.subVectors(T,M),C.toArray(g,p),P.toArray(y,p),M.toArray(b,p),T.toArray(_,p),d.atomColorToArray(F,x,p),v.push(F.index),w.push(m.atomRadius(F)),A.push(l+f),S.push(l+e+1-f),p+=3,f=e,O=!1}const R=new Float32Array(v);return{axis:new Float32Array(g),center:new Float32Array(y),begin:new Float32Array(b),end:new Float32Array(_),color:new Float32Array(x),picking:new Xs(R,a),size:new Float32Array(w),residueOffset:A,residueCount:S}}}class Pa{constructor(t){this.scoreFunction=t,this.content=[],this.scoreFunction=t}push(t){this.content.push(t),this.bubbleUp(this.content.length-1)}pop(){const t=this.content[0],e=this.content.pop();return e&&this.content.length>0&&(this.content[0]=e,this.sinkDown(0)),t}peek(){return this.content[0]}remove(t){const e=this.content.length;for(let i=0;i0;){const i=Math.floor((t+1)/2)-1,r=this.content[i];if(!(this.scoreFunction(e)e?(o&&(clearTimeout(o),o=null),a=l,s=t.apply(r,n),o||(r=n=null)):o||!1===i.trailing||(o=setTimeout(c,h)),s}}function ut(t,e){return te?1:0}function dt(t,e,i=ut){let r=0,n=t.length-1;for(;r<=n;){const s=r+n>>1,o=i(e,t[s]);if(o>0)r=s+1;else{if(!(o<0))return s;n=s-1}}return-r-1}function mt(t,e,i){const r=function(t,e){let i=t.length-1;if(t[i]>1;t[n]>=e?i=n-1:r=n+1}return i+1}(t,e),n=function(t,e){if(t[0]>e)return-1;let i=0,r=t.length-1;for(;i<=r;){const n=i+r>>1;t[n]>e?r=n-1:i=n+1}return i-1}(t,i);return-1===r||-1===n||r>n?0:n-r+1}function ft(t){return t.sort().filter((function(t,e,i){return 0===e||t!==i[e-1]}))}function pt(t){const e=28672;if(t.length>e){const i=[];for(let r=0;r65535?Uint32Array:Uint16Array)(t)}function bt(t){return t.buffer&&t.buffer instanceof ArrayBuffer?t.buffer:t}function _t(t,e){return void 0===t?t=new e:Array.isArray(t)&&(t=(new e).fromArray(t)),t}function xt(t){return _t(t,e)}function vt(t){return _t(t,i)}function wt(t){return _t(t,r)}function At(t){return e=t,i=Float32Array,e instanceof i?e:new i(e);var e,i}function St(t){return rt(t,"").toString().toLowerCase()}class Ct{constructor(t){this.name=t,this._dict={}}add(t,e){this._dict[St(t)]=e}get(t){return this._dict[St(t)]}get names(){return Object.keys(this._dict)}}function Pt(t){return.01745*t}const It="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),kt=new Array(36);function Mt(){let t,e=0;for(let i=0;i<36;i++)8===i||13===i||18===i||23===i?kt[i]="-":14===i?kt[i]="4":(e<=2&&(e=33554432+16777216*Math.random()|0),t=15&e,e>>=4,kt[i]=It[19===i?3&t|8:t]);return kt.join("")}function Tt(t,e,i){return Math.max(e,Math.min(i,t))}function Dt(t,e,i){return t+(e-t)*i}function Bt(t,e,i,r,n,s){const o=(i-t)*s,a=(r-e)*s,c=n*n;return(2*e-2*i+o+a)*(n*c)+(-3*e+3*i-2*o-a)*c+o*n+e}function Ft(t,e,i){var r;return r=function(t,e,i){return(t-e)/(i-e)}(i,t,e),(i=Tt(r,0,1))*i*(3-2*i)}var Et="sRGB";const $t={scale:"uniform",mode:"hcl",domain:[0,1],value:16777215,reverse:!1},Ot=new n;function Rt(t,e,i){const r=i.value;return i.value=function(t,e){let i=r.bind(this,t,e)();return"linear"==Et?(Ot.set(i),Ot.convertSRGBToLinear(),Ot.getHex()):i},i}class Lt{constructor(t={}){this.parameters=nt(t,$t),"string"==typeof this.parameters.value&&(this.parameters.value=Ot.set(this.parameters.value).getHex()),this.parameters.structure&&(this.atomProxy=this.parameters.structure.getAtomProxy())}getScale(t={}){const e=nt(t,this.parameters);return"rainbow"===e.scale?e.scale=["red","orange","yellow","green","blue"]:"rwb"===e.scale&&(e.scale=["red","white","blue"]),e.reverse&&(e.domain=e.domain.slice().reverse()),Q.scale(e.scale).mode(e.mode).domain(e.domain).out("num")}colorToArray(t,e=[],i=0){return e[i]=(t>>16&255)/255,e[i+1]=(t>>8&255)/255,e[i+2]=(255&t)/255,e}atomColorToArray(t,e,i){return this.colorToArray(this.atomColor?this.atomColor(t):0,e,i)}bondColor(t,e){return this.atomProxy&&this.atomColor?(this.atomProxy.index=e?t.atomIndex1:t.atomIndex2,this.atomColor(this.atomProxy)):0}bondColorToArray(t,e,i,r){return this.colorToArray(this.bondColor(t,e),i,r)}volumeColorToArray(t,e,i){return this.colorToArray(this.volumeColor?this.volumeColor(t):0,e,i)}positionColorToArray(t,e,i){return this.colorToArray(this.positionColor?this.positionColor(t):0,e,i)}}var Nt;!function(t){t[t.PROTEIN=1]="PROTEIN",t[t.NUCLEIC=2]="NUCLEIC",t[t.RNA=3]="RNA",t[t.DNA=4]="DNA",t[t.POLYMER=5]="POLYMER",t[t.WATER=6]="WATER",t[t.HELIX=7]="HELIX",t[t.SHEET=8]="SHEET",t[t.TURN=9]="TURN",t[t.BACKBONE=10]="BACKBONE",t[t.SIDECHAIN=11]="SIDECHAIN",t[t.ALL=12]="ALL",t[t.HETERO=13]="HETERO",t[t.ION=14]="ION",t[t.SACCHARIDE=15]="SACCHARIDE",t[t.SUGAR=15]="SUGAR",t[t.BONDED=16]="BONDED",t[t.RING=17]="RING",t[t.AROMATICRING=18]="AROMATICRING",t[t.METAL=19]="METAL",t[t.POLARH=20]="POLARH",t[t.NONE=21]="NONE"}(Nt||(Nt={}));const zt=["*","","ALL"],Ut=["NONE"],Vt=[Nt.BACKBONE,Nt.SIDECHAIN,Nt.BONDED,Nt.RING,Nt.AROMATICRING,Nt.METAL,Nt.POLARH],jt=[Nt.POLYMER,Nt.WATER],Gt=["ALA","GLY","SER"],Ht=["CYS","SER","THR"],qt=["ALA","ILE","LEU","MET","PHE","PRO","TRP","VAL"],Wt=["PHE","TRP","TYR","HIS"],Xt=["ASN","GLN"],Yt=["ASP","GLU"],Kt=["ARG","HIS","LYS"],Zt=["ARG","ASP","GLU","HIS","LYS"],Qt=["ASN","ARG","ASP","CYS","GLY","GLN","GLU","HIS","LYS","SER","THR","TYR"],Jt=["ALA","ILE","LEU","MET","PHE","PRO","TRP","VAL"],te=["HIS","PHE","PRO","TRP","TYR"],ee=["ALA","GLY","ILE","LEU","VAL"];function ie(t,e){if(void 0===e.atomname&&void 0===e.element&&void 0===e.altloc&&void 0===e.atomindex&&void 0===e.keyword&&void 0===e.inscode&&void 0===e.resname&&void 0===e.sstruc&&void 0===e.resno&&void 0===e.chainname&&void 0===e.model)return-1;if(void 0!==e.keyword){if(e.keyword===Nt.BACKBONE&&!t.isBackbone())return!1;if(e.keyword===Nt.SIDECHAIN&&!t.isSidechain())return!1;if(e.keyword===Nt.BONDED&&!t.isBonded())return!1;if(e.keyword===Nt.RING&&!t.isRing())return!1;if(e.keyword===Nt.AROMATICRING&&!t.isAromatic())return!1;if(e.keyword===Nt.HETERO&&!t.isHetero())return!1;if(e.keyword===Nt.PROTEIN&&!t.isProtein())return!1;if(e.keyword===Nt.NUCLEIC&&!t.isNucleic())return!1;if(e.keyword===Nt.RNA&&!t.isRna())return!1;if(e.keyword===Nt.DNA&&!t.isDna())return!1;if(e.keyword===Nt.POLYMER&&!t.isPolymer())return!1;if(e.keyword===Nt.WATER&&!t.isWater())return!1;if(e.keyword===Nt.HELIX&&!t.isHelix())return!1;if(e.keyword===Nt.SHEET&&!t.isSheet())return!1;if(e.keyword===Nt.TURN&&!t.isTurn())return!1;if(e.keyword===Nt.ION&&!t.isIon())return!1;if(e.keyword===Nt.SACCHARIDE&&!t.isSaccharide())return!1;if(e.keyword===Nt.METAL&&!t.isMetal())return!1;if(e.keyword===Nt.POLARH&&!t.isPolarHydrogen())return!1}if(void 0!==e.atomname&&e.atomname!==t.atomname)return!1;if(void 0!==e.element&&e.element!==t.element)return!1;if(void 0!==e.altloc&&e.altloc!==t.altloc)return!1;if(void 0!==e.atomindex&&dt(e.atomindex,t.index)<0)return!1;if(void 0!==e.resname)if(Array.isArray(e.resname)){if(!e.resname.includes(t.resname))return!1}else if(e.resname!==t.resname)return!1;if(void 0!==e.sstruc&&e.sstruc!==t.sstruc)return!1;if(void 0!==e.resno)if(Array.isArray(e.resno)&&2===e.resno.length){if(e.resno[0]>t.resno||e.resno[1]t.resno||e.resno[1]0?t:null}function ce(t,e=!1){let i=t;return e&&(i=ae(t,(function(t){return void 0!==t.keyword&&!Vt.includes(t.keyword)||(void 0!==t.model||(void 0!==t.chainname||(void 0!==t.resname||(void 0!==t.resno||void 0!==t.sstruc))))}))),oe(i,ie)}function le(t,e=!1){let i=t;return e&&(i=ae(t,(function(t){return!(void 0===t.keyword||!Vt.includes(t.keyword))||(void 0!==t.model||(void 0!==t.chainname||(void 0!==t.atomname||(void 0!==t.element||void 0!==t.altloc))))}))),oe(i,re)}function he(t,e=!1){let i=t;return e&&(i=ae(t,(function(t){return void 0!==t.keyword&&!jt.includes(t.keyword)||(void 0!==t.resname||(void 0!==t.resno||(void 0!==t.atomname||(void 0!==t.element||(void 0!==t.altloc||(void 0!==t.sstruc||void 0!==t.inscode))))))}))),oe(i,ne)}function ue(t,e=!1){let i=t;return e&&(i=ae(t,(function(t){return void 0!==t.keyword||(void 0!==t.chainname||(void 0!==t.resname||(void 0!==t.resno||(void 0!==t.atomname||(void 0!==t.element||(void 0!==t.altloc||(void 0!==t.sstruc||void 0!==t.inscode)))))))}))),oe(i,se)}class de{constructor(t){this.signals={stringChanged:new tt},this.setString(t)}get type(){return"selection"}setString(t,e){if(void 0===t&&(t=this.string||""),t===this.string)return;try{this.selection=function(t){let e={operator:void 0,rules:[]};if(!t)return e;let i,r,n=e;const s=[];"("===(t=t.replace(/\(/g," ( ").replace(/\)/g," ) ").trim()).charAt(0)&&")"===t.substr(-1)&&(t=t.slice(1,-1).trim());const o=t.split(/\s+/),a=t=>{i={operator:t,rules:[]},void 0===n?(n=i,e=i):(n.rules.push(i),s.push(n),n=i)},c=function(t){r=n,n=s.pop(),void 0===n&&(a(t),l(r))},l=function(t){n.rules.push(t)};let h=!1;for(let t=0;t0)if("NOT"===i)h=1;else if(1===h)h=2;else{if(2!==h)throw new Error("something went wrong with 'not'");h=!1,c()}if("AND"===i){if("OR"===n.operator){const t=n.rules.pop();a("AND"),l(t)}else n.operator="AND";continue}if("OR"===i){"AND"===n.operator?c("OR"):n.operator="OR";continue}if("NOT"===e.toUpperCase()){h=1,a(),n.negate=!0;continue}if(+i!=+i){const t=Nt[i];if(void 0!==t){l({keyword:t});continue}}if("HYDROGEN"===i){l({operator:"OR",rules:[{element:"H"},{element:"D"}]});continue}if("SMALL"===i){l({resname:Gt});continue}if("NUCLEOPHILIC"===i){l({resname:Ht});continue}if("HYDROPHOBIC"===i){l({resname:qt});continue}if("AROMATIC"===i){l({resname:Wt});continue}if("AMIDE"===i){l({resname:Xt});continue}if("ACIDIC"===i){l({resname:Yt});continue}if("BASIC"===i){l({resname:Kt});continue}if("CHARGED"===i){l({resname:Zt});continue}if("POLAR"===i){l({resname:Qt});continue}if("NONPOLAR"===i){l({resname:Jt});continue}if("CYCLIC"===i){l({resname:te});continue}if("ALIPHATIC"===i){l({resname:ee});continue}if("SIDECHAINATTACHED"===i){l({operator:"OR",rules:[{keyword:Nt.SIDECHAIN},{operator:"AND",negate:!1,rules:[{keyword:Nt.PROTEIN},{operator:"OR",negate:!1,rules:[{atomname:"CA"},{atomname:"BB"}]}]},{operator:"AND",negate:!1,rules:[{resname:"PRO"},{atomname:"N"}]},{operator:"AND",negate:!1,rules:[{keyword:Nt.NUCLEIC},{operator:"OR",negate:!0,rules:[{atomname:"P"},{atomname:"OP1"},{atomname:"OP2"},{atomname:"O3'"},{atomname:"O3*"},{atomname:"HO3'"},{atomname:"O5'"},{atomname:"O5*"},{atomname:"HO5'"},{atomname:"C5'"},{atomname:"C5*"},{atomname:"H5'"},{atomname:"H5''"}]}]}]});continue}if("APOLARH"===i){l({operator:"AND",negate:!1,rules:[{element:"H"},{negate:!0,operator:void 0,rules:[{keyword:Nt.POLARH}]}]});continue}if("LIGAND"===i){l({operator:"AND",rules:[{operator:"OR",rules:[{operator:"AND",rules:[{keyword:Nt.HETERO},{negate:!0,operator:void 0,rules:[{keyword:Nt.POLYMER}]}]},{negate:!0,operator:void 0,rules:[{keyword:Nt.POLYMER}]}]},{negate:!0,operator:void 0,rules:[{operator:"OR",rules:[{keyword:Nt.WATER},{keyword:Nt.ION}]}]}]});continue}if(-1!==zt.indexOf(i)){l({keyword:Nt.ALL});continue}if("@"===e.charAt(0)){const t=e.substr(1).split(",").map((t=>parseInt(t)));t.sort((function(t,e){return t-e})),l({atomindex:t});continue}if("#"===e.charAt(0)){console.error("# for element selection deprecated, use _"),l({element:i.substr(1)});continue}if("_"===e.charAt(0)){l({element:i.substr(1)});continue}if("["===e[0]&&"]"===e[e.length-1]){const t=i.substr(1,e.length-2).split(","),r=t.length>1?t:t[0];l({resname:r});continue}if(e.length>=1&&e.length<=4&&"^"!==e[0]&&":"!==e[0]&&"."!==e[0]&&"%"!==e[0]&&"/"!==e[0]&&isNaN(parseInt(e))){l({resname:i});continue}const r={operator:"AND",rules:[]},s=e.split("/");if(s.length>1&&s[1]){if(isNaN(parseInt(s[1])))throw new Error("model must be an integer");r.rules.push({model:parseInt(s[1])})}const u=s[0].split("%");u.length>1&&r.rules.push({altloc:u[1]});const d=u[0].split(".");if(d.length>1&&d[1]){if(d[1].length>4)throw new Error("atomname must be one to four characters");r.rules.push({atomname:d[1].substring(0,4).toUpperCase()})}const m=d[0].split(":");m.length>1&&m[1]&&r.rules.push({chainname:m[1]});const f=m[0].split("^");if(f.length>1&&r.rules.push({inscode:f[1]}),f[0]){let t,e;"-"===f[0][0]&&(f[0]=f[0].substr(1),t=!0),f[0].includes("--")&&(f[0]=f[0].replace("--","-"),e=!0);let i=f[0].split("-");if(1===i.length){let e=parseInt(i[0]);if(isNaN(e))throw new Error("resi must be an integer");t&&(e*=-1),r.rules.push({resno:e})}else{if(2!==i.length)throw new Error("resi range must contain one '-'");{const n=i.map((t=>parseInt(t)));t&&(n[0]*=-1),e&&(n[1]*=-1),r.rules.push({resno:[n[0],n[1]]})}}}if(1===r.rules.length)l(r.rules[0]);else{if(!(r.rules.length>1))throw new Error("empty selection chunk");l(r)}}return void 0===e.operator&&1===e.rules.length&&e.rules[0].hasOwnProperty("operator")&&(e=e.rules[0]),e}(t)}catch(t){this.selection={error:t.message}}const i=this.selection;this.string=t,this.test=ce(i),this.residueTest=le(i),this.chainTest=he(i),this.modelTest=ue(i),this.atomOnlyTest=ce(i,!0),this.residueOnlyTest=le(i,!0),this.chainOnlyTest=he(i,!0),this.modelOnlyTest=ue(i,!0),e||this.signals.stringChanged.dispatch(this.string)}isAllSelection(){return zt.includes(this.string.toUpperCase())}isNoneSelection(){return Ut.includes(this.string.toUpperCase())}}class me extends Lt{constructor(t){super(t),this.colormakerList=[],this.selectionList=[];(t.dataList||[]).forEach((t=>{const[e,i,r={}]=t;$e.hasScheme(e)?Object.assign(r,{scheme:e,structure:this.parameters.structure}):Object.assign(r,{scheme:"uniform",value:new n(e).getHex()}),this.colormakerList.push($e.getScheme(r)),this.selectionList.push(new de(i))}))}atomColor(t){for(let e=0,i=this.selectionList.length;e{}),t)}catch(t){}const we="undefined"!=typeof window&&void 0!==window.orientation;let Ae=!1;function Se(t){Ae=t}let Ce=!1;function Pe(t){Ce=t}const Ie={log:Function.prototype.bind.call(console.log,console),info:Function.prototype.bind.call(console.info,console),warn:Function.prototype.bind.call(console.warn,console),error:Function.prototype.bind.call(console.error,console),time:Function.prototype.bind.call(console.time,console),timeEnd:Function.prototype.bind.call(console.timeEnd,console)};let ke={color:"green",labelColor:8421504,labelAttachment:"bottom-center",labelSize:.7,labelZOffset:.5,labelYOffset:.1,labelBorder:!0,labelBorderColor:13882323,labelBorderWidth:.25,lineOpacity:.8,linewidth:5,opacity:.6,labelUnit:"angstrom",arcVisible:!0,planeVisible:!1};function Me(t={}){Object.assign(ke,t)}let Te=!!(De=it("debug"))&&("string"!=typeof De||/^1|true|t|yes|y$/i.test(De));var De;function Be(t){Te=t}const Fe=["ngl","js"],Ee=new class{constructor(){this.activeWorkerCount=0,this._funcDict={},this._depsDict={},this._blobDict={}}add(t,e,i){this._funcDict[t]=e,this._depsDict[t]=i}get(t){return this._blobDict[t]||(this._blobDict[t]=_e(this._funcDict[t],this._depsDict[t])),this._blobDict[t]}},$e=new class{constructor(){this.schemes={},this.userSchemes={}}getScheme(t){const e=((t||{}).scheme||"").toLowerCase();let i;return i=e in this.schemes?this.schemes[e]:e in this.userSchemes?this.userSchemes[e]:Lt,new i(t)}getSchemes(){const t={};return Object.keys(this.schemes).forEach((function(e){t[e]=e})),Object.keys(this.userSchemes).forEach((function(e){t[e]=e.split("|")[1]})),t}getScales(){return fe}getModes(){return pe}add(t,e){t=t.toLowerCase(),this.schemes[t]=e}addScheme(t,e){return function(t){return t instanceof Lt}(t)||(t=this._createScheme(t)),this._addUserScheme(t,e)}_addUserScheme(t,e){e=e||"";const i=`${Mt()}|${e}`.toLowerCase();return this.userSchemes[i]=t,i}removeScheme(t){t=t.toLowerCase(),delete this.userSchemes[t]}_createScheme(t){return class extends Lt{constructor(e){super(e),t.call(this,e)}}}addSelectionScheme(t,e){return this._addUserScheme(class extends me{constructor(e){super(Object.assign({dataList:t},e))}},e)}hasScheme(t){return(t=t.toLowerCase())in this.schemes||t in this.userSchemes}},Oe=new Ct("datasource"),Re=new Ct("representatation"),Le=new class extends Ct{constructor(){super("parser")}__hasObjName(t,e){const i=this.get(t);return i&&i.prototype.__objName===e}isTrajectory(t){return this.__hasObjName(t,"frames")}isStructure(t){return this.__hasObjName(t,"structure")}isVolume(t){return this.__hasObjName(t,"volume")}isSurface(t){return this.__hasObjName(t,"surface")}isBinary(t){const e=this.get(t);return e&&e.prototype.isBinary}isXml(t){const e=this.get(t);return e&&e.prototype.isXml}isJson(t){const e=this.get(t);return e&&e.prototype.isJson}getTrajectoryExtensions(){return this.names.filter((t=>this.isTrajectory(t)))}getStructureExtensions(){return this.names.filter((t=>this.isStructure(t)))}getVolumeExtensions(){return this.names.filter((t=>this.isVolume(t)))}getSurfaceExtensions(){return this.names.filter((t=>this.isSurface(t)))}},Ne=new Ct("shader"),ze=new Ct("decompressor"),Ue=new Ct("component"),Ve=new Ct("buffer"),je=new Ct("picker");let Ge,He;function qe(t){Ge=t}function We(t){He=t}class Xe{constructor(t,e={}){this.chunkSize=10485760,this.newline="\n",this.__pointer=0,this.__partialLine="",this.compressed=rt(e.compressed,!1),this.binary=rt(e.binary,!1),this.json=rt(e.json,!1),this.xml=rt(e.xml,!1),this.src=t}isBinary(){return this.binary||this.compressed}read(){return this._read().then((t=>{const e=this.compressed?ze.get(this.compressed):void 0;return this.compressed&&e?this.data=e(t):((this.binary||this.compressed)&&t instanceof ArrayBuffer&&(t=new Uint8Array(t)),this.data=t),this.data}))}_chunk(t,e){return e=Math.min(this.data.length,e),0===t&&this.data.length===e?this.data:this.isBinary()?this.data.subarray(t,e):this.data.substring(t,e)}chunk(t){const e=t+this.chunkSize;return this._chunk(t,e)}peekLines(t){const e=this.data,i=e.length,r=this.isBinary()?this.newline.charCodeAt(0):this.newline;let n,s=0;for(n=0;ni).lines}chunkCount(){return Math.floor(this.data.length/this.chunkSize)+1}asText(){return this.isBinary()?pt(this.data):this.data}chunkToLines(t,e,i){const r=this.newline;if(!this.isBinary()&&t.length===this.data.length)return{lines:t.split(r),partialLine:""};let n=[];const s=this.isBinary()?pt(t):t,o=s.lastIndexOf(r);if(-1===o)e+=s;else{const t=e+s.substr(0,o);n=n.concat(t.split(r)),e=o===s.length-r.length?"":s.substr(o+r.length)}return i&&""!==e&&n.push(e),{lines:n,partialLine:e}}nextChunk(){const t=this.__pointer;if(!(t>this.data.length))return this.__pointer+=this.chunkSize,this.chunk(t)}nextChunkOfLines(){const t=this.nextChunk();if(void 0===t)return;const e=this.__pointer>this.data.length,i=this.chunkToLines(t,this.__partialLine,e);return this.__partialLine=i.partialLine,i.lines}eachChunk(t){const e=this.chunkSize,i=this.data.length,r=this.chunkCount();for(let n=0;n{const n=i===r+1,s=this.chunkToLines(e,this.__partialLine,n);this.__partialLine=s.partialLine,t(s.lines,i,r)}))}dispose(){delete this.src}}class Ye extends Xe{_read(){return new Promise(((t,e)=>{const i=this.src,r=new FileReader;r.onload=e=>{e.target&&t(e.target.result)},r.onerror=t=>e(t),this.binary||this.compressed?r.readAsArrayBuffer(i):r.readAsText(i)}))}}class Ke extends Xe{_read(){return new Promise(((t,e)=>{const i=this.src,r=new XMLHttpRequest;r.open("GET",i,!0),r.addEventListener("load",(()=>{if(200===r.status||304===r.status||0===r.status)try{t(r.response)}catch(t){e(t)}else e(r.statusText)}),!1),r.addEventListener("error",(t=>e("network error")),!1),this.isBinary()?r.responseType="arraybuffer":this.json?r.responseType="json":this.xml?r.responseType="document":r.responseType="text",r.send()}))}}class Ze{constructor(t,e={}){this.parameters=nt(e,{ext:"",compressed:!1,binary:Le.isBinary(e.ext||""),name:"",dir:"",path:"",protocol:""});const i={compressed:this.parameters.compressed,binary:this.parameters.binary,json:Le.isJson(this.parameters.ext),xml:Le.isXml(this.parameters.ext)};"undefined"!=typeof File&&t instanceof File||"undefined"!=typeof Blob&&t instanceof Blob?this.streamer=new Ye(t,i):this.streamer=new Ke(t,i)}}class Qe extends Ze{constructor(t,e={}){super(t,e),this.parserParams={voxelSize:e.voxelSize,firstModelOnly:e.firstModelOnly,asTrajectory:e.asTrajectory,cAlphaOnly:e.cAlphaOnly,delimiter:e.delimiter,comment:e.comment,columnNames:e.columnNames,inferBonds:e.inferBonds,name:this.parameters.name,path:this.parameters.path}}load(){return new(Le.get(this.parameters.ext))(this.streamer,this.parserParams).parse()}}class Je{constructor(t,e,i){this.name=e,this.path=i,this.signals={elementAdded:new tt,elementRemoved:new tt,nameChanged:new tt},this.type="Script",this.dir=i.substring(0,i.lastIndexOf("/")+1);try{this.fn=new Function("stage","__name","__path","__dir",t)}catch(t){Ie.error("Script compilation failed",t),this.fn=function(){}}}run(t){return new Promise(((e,i)=>{try{this.fn.apply(null,[t,this.name,this.path,this.dir]),e()}catch(t){Ie.error("Script.fn",t),i(t)}}))}}class ti extends Ze{load(){return this.streamer.read().then((()=>new Je(this.streamer.asText(),this.parameters.name,this.parameters.path)))}}function ei(t){const e=ze.names;let i,r,n="";i=t instanceof File?t.name:t instanceof Blob?"":t;const s=i.lastIndexOf("?"),o=-1!==s?i.substring(s):"";i=i.substring(0,-1===s?i.length:s);const a=i.replace(/^.*[\\/]/,"");let c=a.substring(0,a.lastIndexOf("."));const l=a.split(".");let h=l.length>1?(l.pop()||"").toLowerCase():"";const u=i.match(/^(.+):\/\/(.+)$/);u&&(n=u[1].toLowerCase(),i=u[2]||"");const d=i.substring(0,i.lastIndexOf("/")+1);if(e.includes(h)){r=h;const t=i.length-h.length-1;h=(i.substr(0,t).split(".").pop()||"").toLowerCase();const e=c.length-h.length-1;c=c.substr(0,e)}else r=!1;return{path:i,name:a,ext:h,base:c,dir:d,compressed:r,protocol:n,query:o,src:t}}function ii(t){let e=ei(t);const i=Oe.get(e.protocol);return i&&(e=ei(i.getUrl(e.src)),!e.ext&&i.getExt&&(e.ext=i.getExt(t))),e}function ri(t,e={}){const i=Object.assign(ii(t),e);let r;return Le.names.includes(i.ext)?r=new Qe(i.src,i):Fe.includes(i.ext)&&(r=new ti(i.src,i)),r?r.load():Promise.reject(new Error(`autoLoad: ext '${i.ext}' unknown`))}class ni{getBlob(){return new Blob([this.getData()],{type:this.mimeType})}download(t,e){t=rt(t,this.defaultName),e=rt(e,this.defaultExt),lt(this.getBlob(),`${t}.${e}`)}}class si extends ni{constructor(t,e){super(),this.mimeType="text/plain",this.defaultName="structure",this.defaultExt="pdb";const i=Object.assign({},e);this.renumberSerial=rt(i.renumberSerial,!0),this.remarks=function(t){return Array.isArray(t)?t:[t]}(rt(i.remarks,[])),this.structure=t,this._records=[]}_writeRecords(){this._records.length=0,this._writeTitle(),this._writeRemarks(),this._writeAtoms()}_writeTitle(){this._records.push(et("TITLE %-74s",this.structure.name))}_writeRemarks(){this.remarks.forEach((t=>{this._records.push(et("REMARK %-73s",t))})),this.structure.trajectory&&(this._records.push(et("REMARK %-73s","Trajectory '"+this.structure.trajectory.name+"'")),this._records.push(et("REMARK %-73s",`Frame ${this.structure.trajectory.frame}`)))}_writeAtoms(){let t=1,e=1,i=" ",r=" ";const n=this.structure.modelStore.count>1;this.structure.eachModel((s=>{n&&this._records.push(et("MODEL %4d%-66s",e++,"")),s.eachAtom((e=>{const n=e.hetero?"HETATM%5d %-4s %3s %1s%4d %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%1s%1s":"ATOM %5d %-4s %3s %1s%4d %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%1s%1s",s=this.renumberSerial?t:e.serial;let o=e.atomname;(1===o.length||o.length<4&&1===e.element.length&&o[0]===e.element)&&(o=" "+o),e.formalCharge?(i=Math.abs(e.formalCharge).toPrecision(1),r=e.formalCharge>0?"+":"-"):(i=" ",r=" "),this._records.push(et(n,s,o,e.resname,rt(e.chainname," "),e.resno,e.x,e.y,e.z,rt(e.occupancy,1),rt(e.bfactor,0),"",rt(e.element,""),i,r)),t+=1}),this.structure.getSelection()),n&&this._records.push(et("%-80s","ENDMDL"))})),this._records.push(et("%-80s","END"))}getString(){return console.warn("PdbWriter.getString() is deprecated, use .getData instead"),this.getData()}getData(){return this._writeRecords(),this._records.join("\n")}}class oi extends ni{constructor(t){super(),this.mimeType="text/plain",this.defaultName="structure",this.defaultExt="sdf",this.structure=t,this._records=[]}get idString(){return this.structure.id}get titleString(){return" "+this.structure.title}get countsString(){return et("%3i%3i 0 0 0 0 0 0 0 0999 V2000",this.structure.atomCount,this.structure.bondCount)}get chargeLines(){const t=[];this.structure.eachAtom((e=>{null!=e.formalCharge&&0!==e.formalCharge&&t.push([e.index,e.formalCharge])}));const e=[];for(let i=0;i{this._records.push(this.formatAtom(t))})),this.structure.eachBond((t=>{this._records.push(this.formatBond(t))})),this.chargeLines.forEach((t=>{this._records.push(t)})),this._records.push("M END")}_writeFooter(){this._records.push("$$$$")}getData(){return this._writeRecords(),this._records.join("\n")}}const ai=[];class ci{constructor(t,e={}){this._mark=0,this._marks=[],this.offset=0,this.littleEndian=!0;let i=!1;void 0===t&&(t=8192),"number"==typeof t?t=new ArrayBuffer(t):i=!0;const r=e.offset?e.offset>>>0:0;let n=t.byteLength-r,s=r;t instanceof ArrayBuffer||(t.byteLength!==t.buffer.byteLength&&(s=t.byteOffset+r),t=t.buffer),this._lastWrittenByte=i?n:0,this.buffer=t,this.length=n,this.byteLength=n,this.byteOffset=s,this._data=new DataView(this.buffer,s,n)}available(t){return void 0===t&&(t=1),this.offset+t<=this.length}isLittleEndian(){return this.littleEndian}setLittleEndian(){return this.littleEndian=!0,this}isBigEndian(){return!this.littleEndian}setBigEndian(){return this.littleEndian=!1,this}skip(t){return void 0===t&&(t=1),this.offset+=t,this}seek(t){return this.offset=t,this}mark(){return this._mark=this.offset,this}reset(){return this.offset=this._mark,this}pushMark(){return this._marks.push(this.offset),this}popMark(){const t=this._marks.pop();if(void 0===t)throw new Error("Mark stack empty");return this.seek(t),this}rewind(){return this.offset=0,this}ensureAvailable(t){if(void 0===t&&(t=1),!this.available(t)){const e=2*(this.offset+t),i=new Uint8Array(e);i.set(new Uint8Array(this.buffer)),this.buffer=i.buffer,this.length=this.byteLength=e,this._data=new DataView(this.buffer)}return this}readBoolean(){return 0!==this.readUint8()}readInt8(){return this._data.getInt8(this.offset++)}readUint8(){return this._data.getUint8(this.offset++)}readByte(){return this.readUint8()}readBytes(t){void 0===t&&(t=1);for(var e=new Uint8Array(t),i=0;ithis._lastWrittenByte&&(this._lastWrittenByte=this.offset)}}class li extends ni{constructor(t){super(),this.mimeType="application/vnd.ms-pki.stl",this.defaultName="surface",this.defaultExt="stl",this.surface=t}getData(){const t=this.surface.index.length/3,i=new ci(2*t+3*t*4*4+80+4);i.skip(80),i.writeUint32(t);const r=new e,n=new e,s=new e,o=new e;for(let e=0;e{0===this.count&&(this.signals.countChanged.remove(i,this),t.call(e))};this.signals.countChanged.add(i,this)}}dispose(){this.clear(),this.signals.countChanged.dispose()}}Ne.add("shader/BasicLine.vert","void main(){\n#include begin_vertex\n#include project_vertex\n}"),Ne.add("shader/BasicLine.frag","uniform vec3 uColor;\n#include common\n#include fog_pars_fragment\nvoid main(){\ngl_FragColor = vec4( uColor, 1.0 );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n}"),Ne.add("shader/Quad.vert","varying vec2 vUv;\nvoid main() {\nvUv = uv;\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"),Ne.add("shader/Quad.frag","varying vec2 vUv;\nuniform sampler2D tForeground;\nuniform float scale;\nvoid main() {\nvec4 foreground = texture2D( tForeground, vUv );\ngl_FragColor = foreground * scale;\n}");class ui{constructor(){this.signals={updated:new J.Signal},this.maxDuration=-1/0,this.minDuration=1/0,this.avgDuration=14,this.lastDuration=1/0,this.prevFpsTime=0,this.lastFps=1/0,this.lastFrames=1,this.frames=0,this.count=0,this.begin()}update(){this.startTime=this.end(),this.currentTime=this.startTime,this.signals.updated.dispatch()}begin(){this.startTime=window.performance.now(),this.lastFrames=this.frames}end(){const t=window.performance.now();return this.count+=1,this.frames+=1,this.lastDuration=t-this.startTime,this.minDuration=Math.min(this.minDuration,this.lastDuration),this.maxDuration=Math.max(this.maxDuration,this.lastDuration),this.avgDuration-=this.avgDuration/30,this.avgDuration+=this.lastDuration/30,t>this.prevFpsTime+1e3&&(this.lastFps=this.frames,this.prevFpsTime=t,this.frames=0),t}}Ne.add("shader/chunk/fog_fragment.glsl","#ifdef USE_FOG\nfloat depth = length( vViewPosition );\n#ifdef FOG_EXP2\nfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"),Ne.add("shader/chunk/interior_fragment.glsl","if( gl_FrontFacing == false ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}"),Ne.add("shader/chunk/matrix_scale.glsl","float matrixScale( in mat4 m ){\nvec4 r = m[ 0 ];\nreturn sqrt( r[ 0 ] * r[ 0 ] + r[ 1 ] * r[ 1 ] + r[ 2 ] * r[ 2 ] );\n}"),Ne.add("shader/chunk/nearclip_vertex.glsl","#ifdef NEAR_CLIP\nif( vViewPosition.z < clipNear - 5.0 )\ngl_Position.z = 2.0 * gl_Position.w;\n#endif"),Ne.add("shader/chunk/nearclip_fragment.glsl","#ifdef NEAR_CLIP\nif( vViewPosition.z < clipNear )\ndiscard;\n#endif"),Ne.add("shader/chunk/opaque_back_fragment.glsl","#ifdef OPAQUE_BACK\n#ifdef FLIP_SIDED\nif( gl_FrontFacing == true ){\ngl_FragColor.a = 1.0;\n}\n#else\nif( gl_FrontFacing == false ){\ngl_FragColor.a = 1.0;\n}\n#endif\n#endif"),Ne.add("shader/chunk/radiusclip_vertex.glsl","#ifdef RADIUS_CLIP\nif( distance( vViewPosition, vClipCenter ) > clipRadius + 5.0 )\ngl_Position.z = 2.0 * gl_Position.w;\n#endif"),Ne.add("shader/chunk/radiusclip_fragment.glsl","#ifdef RADIUS_CLIP\nif( distance( vViewPosition, vClipCenter ) > clipRadius )\ndiscard;\n#endif"),Ne.add("shader/chunk/unpack_color.glsl","vec3 unpackColor(float f) {\nvec3 color;\ncolor.r = floor(f / 256.0 / 256.0);\ncolor.g = floor((f - color.r * 256.0 * 256.0) / 256.0);\ncolor.b = floor(f - color.r * 256.0 * 256.0 - color.g * 256.0);\nreturn color / 255.0;\n}");const di=/^(?!\/\/)\s*#include\s+(\S+)/gim,mi={};function fi(t,e={}){let i=t+"|";for(const t in e)i+=t+":"+e[t];if(!mi[i]){const r=function(t){if(void 0===t)return"";const e=[];for(const i in t){const r=t[i];r&&e.push(`#define ${i} ${r}`)}return e.join("\n")+"\n"}(e);let n=Ne.get(`shader/${t}`);if(!n)throw new Error(`empty shader, '${t}'`);n=n.replace(di,(function(t,e){const i=`shader/chunk/${e}.glsl`,r=Ne.get(i)||s[e];if(!r)throw new Error(`empty chunk, '${e}'`);return r})),mi[i]=r+n}return mi[i]}if("undefined"!=typeof WebGLRenderingContext){const t=WebGLRenderingContext.prototype,e=t.getShaderParameter;t.getShaderParameter=function(){return!Te||e.apply(this,arguments)};const i=t.getShaderInfoLog;t.getShaderInfoLog=function(){return Te?i.apply(this,arguments):""};const r=t.getProgramParameter;t.getProgramParameter=function(e,i){return!Te&&i===t.LINK_STATUS||r.apply(this,arguments)};const n=t.getProgramInfoLog;t.getProgramInfoLog=function(){return Te?n.apply(this,arguments):""}}const pi=[[[0,0]],[[4,4],[-4,-4]],[[-2,-6],[6,-2],[-6,2],[2,6]],[[1,-3],[-1,3],[5,1],[-3,-5],[-5,5],[-7,-1],[3,7],[7,-7]],[[1,1],[-1,-3],[-3,2],[4,-1],[-5,-2],[2,5],[5,3],[3,-5],[-2,6],[0,-7],[-4,-6],[-6,4],[-8,0],[7,-4],[6,7],[-7,-8]],[[-4,-7],[-7,-5],[-3,-5],[-5,-4],[-1,-4],[-2,-2],[-6,-1],[-4,0],[-7,1],[-1,2],[-6,3],[-3,3],[-7,6],[-3,6],[-5,7],[-1,7],[5,-7],[1,-6],[6,-5],[4,-4],[2,-3],[7,-2],[1,-1],[4,-1],[2,1],[6,2],[0,4],[4,4],[2,5],[7,5],[5,6],[3,7]]];pi.forEach((t=>{t.forEach((t=>{t[0]*=.0625,t[1]*=.0625}))}));class gi{constructor(t,e,i,r){this.canvas=document.createElement("canvas"),this._viewer=i,this._factor=rt(r.factor,2),this._antialias=rt(r.antialias,!1),this._onProgress=r.onProgress,this._onFinish=r.onFinish,this._antialias&&(this._factor*=2),this._n=this._factor*this._factor,this._width=this._viewer.width,this._height=this._viewer.height,this._antialias?(this.canvas.width=this._width*this._factor/2,this.canvas.height=this._height*this._factor/2):(this.canvas.width=this._width*this._factor,this.canvas.height=this._height*this._factor),this._ctx=this.canvas.getContext("2d"),this._viewerSampleLevel=i.sampleLevel,this._viewer.setSampling(-1)}_renderTile(t){const e=this._viewer,i=this._width,r=this._height,n=this._factor,s=t%n*i,o=Math.floor(t/n)*r;if(e.camera.setViewOffset(i*n,r*n,s,o,i,r),e.render(),this._antialias){const t=Math.round((s+i)/2)-Math.round(s/2),n=Math.round((o+r)/2)-Math.round(o/2);this._ctx.drawImage(e.renderer.domElement,Math.round(s/2),Math.round(o/2),t,n)}else this._ctx.drawImage(e.renderer.domElement,Math.floor(s),Math.floor(o),Math.ceil(i),Math.ceil(r));"function"==typeof this._onProgress&&this._onProgress(t+1,this._n,!1)}_finalize(){this._viewer.setSampling(this._viewerSampleLevel),this._viewer.camera.view=null,"function"==typeof this._onFinish&&this._onFinish(this._n+1,this._n,!1)}render(){for(let t=0;t<=this._n;++t)t===this._n?this._finalize():this._renderTile(t)}renderAsync(){let t=0;const e=this._n,i=()=>{t===e?this._finalize():this._renderTile(t),t+=1};for(let t=0;t<=e;++t)setTimeout(i,0)}}const yi=2*Math.PI,bi=180/Math.PI;function _i(t,e,i=1,r=0,n){const s=n?n.length:t.length/i;let o=0,a=0;if(n)for(let c=0;ce&&(e=t[i]);return e}function Ti(t){let e=1/0;for(let i=0,r=t.length;i=0;l--){for(c=o-1;c>=0;c--)if(u=4*(l*o+c),a[u]!==e||a[u+1]!==i||a[u+2]!==r||a[u+3]!==n){h=!0;break}if(h)break}const f=l;for(h=!1,c=o-1;c>=0;c--){for(l=s-1;l>=0;l--)if(u=4*(l*o+c),a[u]!==e||a[u+1]!==i||a[u+2]!==r||a[u+3]!==n){h=!0;break}if(h)break}const p=c,g=document.createElement("canvas");return g.width=p-m,g.height=f-d,g.getContext("2d").drawImage(t,m,d,g.width,g.height,0,0,g.width,g.height),g}(t,o?0:255*e.r,o?0:255*e.g,o?0:255*e.b,o?0:255)}return t}function m(t,i,r){"function"==typeof e.onProgress&&e.onProgress(t,i,r)}return new Promise((function(e,i){const n=new gi(a,c,t,{factor:r,antialias:s,onProgress:m,onFinish:function(r,s){d(n.canvas).toBlob((function(r){a.setClearAlpha(l),u(!0),t.requestRender(),m(s,s,!0),r?e(r):i("error creating image")}),"image/png")}});a.setClearAlpha(o?0:1),u(),n.renderAsync()}))}const $i=new e,Oi=new i,Ri=new i;const Li=new t,Ni=new i,zi=new i;function Ui(t,e){Ni.copy(e.projectionMatrix).invert(),zi.copy(e.projectionMatrix).transpose(),t.traverse((function(t){const e=t.material;if(!e)return;const i=e.uniforms;i&&(i.projectionMatrixInverse&&i.projectionMatrixInverse.value.copy(Ni),i.projectionMatrixTranspose&&i.projectionMatrixTranspose.value.copy(zi))}))}function Vi(t,e,i){const r=t.createShader(i);if(!r)return void console.log(`error creating WebGL shader ${i}`);t.shaderSource(r,e),t.compileShader(r);return t.getShaderParameter(r,t.COMPILE_STATUS)?r:(console.log(`error compiling shader ${r}: ${t.getShaderInfoLog(r)}`),t.deleteShader(r),null)}function ji(t,e){const i=t.getExtension(e);return i||console.log(`extension '${e}' not available`),i}const Gi=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]);function Hi(t){const e=document.createElement("canvas");e.width=16,e.height=16,e.style.width="16px",e.style.height="16px";const i=e.getContext("webgl")||e.getContext("experimental-webgl");if(!i)return console.log(`error creating webgl context for ${t}`),!1;if(!(i instanceof WebGLRenderingContext))return console.log("Got unexpected type for WebGL rendering context"),!1;ji(i,"OES_texture_float"),ji(i,"OES_texture_half_float"),ji(i,"WEBGL_color_buffer_float");const r=Vi(i,"\nattribute vec4 a_position;\n\nvoid main() {\n gl_Position = a_position;\n}",i.VERTEX_SHADER),n=Vi(i,"\nprecision mediump float;\nuniform vec4 u_color;\nuniform sampler2D u_texture;\n\nvoid main() {\n gl_FragColor = texture2D(u_texture, vec2(0.5, 0.5)) * u_color;\n}",i.FRAGMENT_SHADER);if(!r||!n)return!1;const s=function(t,e,i,r){const n=t.createProgram();return n?(e.forEach((e=>t.attachShader(n,e))),i&&i.forEach(((e,i)=>{t.bindAttribLocation(n,r?r[i]:i,e)})),t.linkProgram(n),t.getProgramParameter(n,t.LINK_STATUS)?n:(console.log(`error linking program: ${t.getProgramInfoLog(n)}`),t.deleteProgram(n),null)):void console.log("error creating WebGL program")}(i,[r,n]);if(!s)return console.log("error creating WebGL program"),!1;i.useProgram(s);const o=i.getAttribLocation(s,"a_position"),a=i.getUniformLocation(s,"u_color");if(!a)return console.log("error getting 'u_color' uniform location"),!1;const c=i.createBuffer();i.bindBuffer(i.ARRAY_BUFFER,c),i.bufferData(i.ARRAY_BUFFER,Gi,i.STATIC_DRAW),i.enableVertexAttribArray(o),i.vertexAttribPointer(o,2,i.FLOAT,!1,0,0);const l=i.createTexture(),h=new Uint8Array([255,255,255,255]);i.bindTexture(i.TEXTURE_2D,l),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,1,1,0,i.RGBA,i.UNSIGNED_BYTE,h);const u=i.createTexture();i.bindTexture(i.TEXTURE_2D,u),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,1,1,0,i.RGBA,t,null),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.NEAREST),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.NEAREST);const d=i.createFramebuffer();i.bindFramebuffer(i.FRAMEBUFFER,d),i.framebufferTexture2D(i.FRAMEBUFFER,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,u,0);if(i.checkFramebufferStatus(i.FRAMEBUFFER)!==i.FRAMEBUFFER_COMPLETE)return console.log(`error creating framebuffer for ${t}`),!1;i.bindTexture(i.TEXTURE_2D,l),i.uniform4fv(a,[0,10,20,1]),i.drawArrays(i.TRIANGLES,0,6),i.bindTexture(i.TEXTURE_2D,u),i.bindFramebuffer(i.FRAMEBUFFER,null),i.clearColor(1,0,0,1),i.clear(i.COLOR_BUFFER_BIT),i.uniform4fv(a,[0,.1,.05,1]),i.drawArrays(i.TRIANGLES,0,6);const m=new Uint8Array(4);if(i.readPixels(0,0,1,1,i.RGBA,i.UNSIGNED_BYTE,m),0!==m[0]||m[1]<248||m[2]<248||m[3]<254)return console.log(`not able to actually render to ${t} texture`),!1;if(t===i.FLOAT){i.bindFramebuffer(i.FRAMEBUFFER,d);const t=new Float32Array(4);i.readPixels(0,0,1,1,i.RGBA,i.FLOAT,t);const e=i.getError();if(e)return console.log(`error reading pixels as float: '${function(t,e){switch(e){case t.NO_ERROR:return"no error";case t.INVALID_ENUM:return"invalid enum";case t.INVALID_VALUE:return"invalid value";case t.INVALID_OPERATION:return"invalid operation";case t.INVALID_FRAMEBUFFER_OPERATION:return"invalid framebuffer operation";case t.OUT_OF_MEMORY:return"out of memory";case t.CONTEXT_LOST_WEBGL:return"context lost"}return"unknown error"}(i,e)}'`),!1}return!0}const qi=new Float32Array(100),Wi=new Uint8Array(100),Xi=[12,7,13,17,11,6,8,18,16,2,14,22,10,1,3,9,19,23,21,15,5,0,4,24,20],Yi=new i;function Ki(t,e,i,r,n){const s=n.uniforms,o=[];if(s&&(s.objectId&&(s.objectId.value=Ae?this.id:this.id/255,o.push("objectId")),(s.modelViewMatrixInverse||s.modelViewMatrixInverseTranspose||s.modelViewProjectionMatrix||s.modelViewProjectionMatrixInverse)&&this.modelViewMatrix.multiplyMatrices(i.matrixWorldInverse,this.matrixWorld),s.modelViewMatrixInverse&&(s.modelViewMatrixInverse.value.copy(this.modelViewMatrix).invert(),o.push("modelViewMatrixInverse")),s.modelViewMatrixInverseTranspose&&(s.modelViewMatrixInverse?s.modelViewMatrixInverseTranspose.value.copy(s.modelViewMatrixInverse.value).transpose():s.modelViewMatrixInverseTranspose.value.copy(this.modelViewMatrix).invert().transpose(),o.push("modelViewMatrixInverseTranspose")),s.modelViewProjectionMatrix&&(s.modelViewProjectionMatrix.value.multiplyMatrices(i.projectionMatrix,this.modelViewMatrix),o.push("modelViewProjectionMatrix")),s.modelViewProjectionMatrixInverse&&(s.modelViewProjectionMatrix?(Yi.copy(s.modelViewProjectionMatrix.value),s.modelViewProjectionMatrixInverse.value.copy(Yi.invert())):(Yi.multiplyMatrices(i.projectionMatrix,this.modelViewMatrix),s.modelViewProjectionMatrixInverse.value.copy(Yi.invert())),o.push("modelViewProjectionMatrixInverse")),o.length)){const e=t.properties.get(n);if(e.program){const i=t.getContext(),r=e.program;i.useProgram(r.program);const n=r.getUniforms();o.forEach((function(t){n.setValue(i,t,s[t].value)}))}}}class Zi{constructor(t){if(this.boundingBox=new a,this.boundingBoxSize=new e,this.boundingBoxLength=0,this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}},this.distVector=new e,this.signals={ticked:new tt,rendered:new tt},"string"==typeof t){const e=document.getElementById(t);this.container=null===e?document.createElement("div"):e}else t instanceof HTMLElement?this.container=t:this.container=document.createElement("div");if(this.container===document.body)this.width=window.innerWidth||1,this.height=window.innerHeight||1;else{const t=this.container.getBoundingClientRect();this.width=t.width||1,this.height=t.height||1,this.container.style.overflow="hidden"}this.wrapper=document.createElement("div"),this.wrapper.style.position="relative",this.container.appendChild(this.wrapper),this._initParams(),this._initStats(),this._initCamera(),this._initScene(),!1!==this._initRenderer()?(this._initHelper(),this.setBackground(),this.setFog(),this.animate=this.animate.bind(this)):Ie.error("Viewer: could not initialize renderer")}_initParams(){this.parameters={fogColor:new n(0),fogNear:50,fogFar:100,backgroundColor:new n(0),cameraType:"perspective",cameraFov:40,cameraEyeSep:.3,cameraZ:-80,clipNear:0,clipFar:100,clipDist:10,clipMode:"scene",clipScale:"relative",lightColor:new n(14540253),lightIntensity:1.2,ambientColor:new n(14540253),ambientIntensity:.3,sampleLevel:0,outputColorSpace:"srgb-linear"}}_initCamera(){const t=new e(0,0,0),{width:i,height:r}=this;this.perspectiveCamera=new c(this.parameters.cameraFov,i/r),this.perspectiveCamera.position.z=this.parameters.cameraZ,this.perspectiveCamera.lookAt(t),this.orthographicCamera=new l(i/-2,i/2,r/2,r/-2),this.orthographicCamera.position.z=this.parameters.cameraZ,this.orthographicCamera.lookAt(t),this.stereoCamera=new h,this.stereoCamera.aspect=.5,this.stereoCamera.eyeSep=this.parameters.cameraEyeSep;const n=this.parameters.cameraType;if("orthographic"===n)this.camera=this.orthographicCamera;else{if("perspective"!==n&&"stereo"!==n)throw new Error(`Unknown cameraType '${n}'`);this.camera=this.perspectiveCamera}this.camera.updateProjectionMatrix()}_initStats(){this.stats=new ui}_initScene(){this.scene||(this.scene=new u,this.scene.name="scene"),this.rotationGroup=new d,this.rotationGroup.name="rotationGroup",this.scene.add(this.rotationGroup),this.translationGroup=new d,this.translationGroup.name="translationGroup",this.rotationGroup.add(this.translationGroup),this.modelGroup=new d,this.modelGroup.name="modelGroup",this.translationGroup.add(this.modelGroup),this.pickingGroup=new d,this.pickingGroup.name="pickingGroup",this.translationGroup.add(this.pickingGroup),this.backgroundGroup=new d,this.backgroundGroup.name="backgroundGroup",this.translationGroup.add(this.backgroundGroup),this.helperGroup=new d,this.helperGroup.name="helperGroup",this.translationGroup.add(this.helperGroup),this.scene.fog=new m(this.parameters.fogColor.getHex()),this.directionalLight=new f(this.parameters.lightColor.getHex(),this.parameters.lightIntensity),this.scene.add(this.directionalLight),this.ambientLight=new p(this.parameters.ambientColor.getHex(),this.parameters.ambientIntensity),this.scene.add(this.ambientLight)}_initRenderer(){const t=window.devicePixelRatio,{width:e,height:i}=this;try{this.renderer=new g({preserveDrawingBuffer:!0,alpha:!0,antialias:!0})}catch(t){return this.wrapper.innerHTML='

Your browser/graphics card does not seem to support WebGL.

Find out how to get it here.

',!1}this.renderer.setPixelRatio(t),this.renderer.setSize(e,i),this.renderer.autoClear=!1,this.renderer.sortObjects=!0,this.renderer.outputColorSpace=this.parameters.outputColorSpace,this.renderer.useLegacyLights=!0;const r=this.renderer.getContext();this.renderer.capabilities.isWebGL2?(Pe(!0),Se(this.renderer.extensions.get("EXT_color_buffer_float")),this.supportsHalfFloat=!0):(Pe(this.renderer.extensions.get("EXT_frag_depth")),this.renderer.extensions.get("OES_element_index_uint"),Se(this.renderer.extensions.get("OES_texture_float")&&this.renderer.extensions.get("WEBGL_color_buffer_float")||this.renderer.extensions.get("OES_texture_float")&&Hi(r.FLOAT)),this.renderer.extensions.get("OES_texture_float"),this.supportsHalfFloat=this.renderer.extensions.get("OES_texture_half_float")&&Hi(36193)),this.wrapper.appendChild(this.renderer.domElement);const n=e*t,s=i*t;Te&&console.log(JSON.stringify({Browser:xe,OES_texture_float:!!this.renderer.extensions.get("OES_texture_float"),OES_texture_half_float:!!this.renderer.extensions.get("OES_texture_half_float"),WEBGL_color_buffer_float:!!this.renderer.extensions.get("WEBGL_color_buffer_float"),"testTextureSupport Float":Hi(r.FLOAT),"testTextureSupport HalfFloat":Hi(36193),"this.supportsHalfFloat":this.supportsHalfFloat,SupportsReadPixelsFloat:Ae},null,2)),this.pickingTarget=new y(n,s,{minFilter:b,magFilter:b,stencilBuffer:!1,format:_,type:Ae?D:x}),this.pickingTarget.texture.generateMipmaps=!1,this.pickingTarget.texture.colorSpace=this.parameters.outputColorSpace,this.renderer.setRenderTarget(this.pickingTarget),this.renderer.clear(),this.renderer.setRenderTarget(null),this.sampleTarget=new y(n,s,{minFilter:v,magFilter:v,format:_,type:this.supportsHalfFloat?w:Ae?D:x}),this.sampleTarget.texture.colorSpace=this.parameters.outputColorSpace,this.holdTarget=new y(n,s,{minFilter:b,magFilter:b,format:_,type:this.supportsHalfFloat?w:Ae?D:x}),this.holdTarget.texture.colorSpace=this.parameters.outputColorSpace,this.compositeUniforms={tForeground:new A(this.sampleTarget.texture),scale:new A(1)},this.compositeMaterial=new S({uniforms:this.compositeUniforms,vertexShader:fi("Quad.vert"),fragmentShader:fi("Quad.frag"),premultipliedAlpha:!0,transparent:!0,blending:C,depthTest:!1,depthWrite:!1}),this.compositeCamera=new l(-1,1,1,-1,0,1),this.compositeScene=new u,this.compositeScene.name="compositeScene",this.compositeScene.add(new P(new I(2,2),this.compositeMaterial))}_initHelper(){const t=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7]),e=new Float32Array(24),i=new k;i.setIndex(new M(t,1)),i.setAttribute("position",new M(e,3));const r=new S({uniforms:{uColor:{value:new n("skyblue")}},vertexShader:fi("BasicLine.vert"),fragmentShader:fi("BasicLine.frag")});this.boundingBoxMesh=new T(i,r),this.helperGroup.add(this.boundingBoxMesh)}updateHelper(){const t=this.boundingBoxMesh.geometry.attributes.position,e=t.array,{min:i,max:r}=this.boundingBox;e[0]=r.x,e[1]=r.y,e[2]=r.z,e[3]=i.x,e[4]=r.y,e[5]=r.z,e[6]=i.x,e[7]=i.y,e[8]=r.z,e[9]=r.x,e[10]=i.y,e[11]=r.z,e[12]=r.x,e[13]=r.y,e[14]=i.z,e[15]=i.x,e[16]=r.y,e[17]=i.z,e[18]=i.x,e[19]=i.y,e[20]=i.z,e[21]=r.x,e[22]=i.y,e[23]=i.z,t.needsUpdate=!0,this.boundingBox.isEmpty()||this.boundingBoxMesh.geometry.computeBoundingSphere()}get cameraDistance(){return Math.abs(this.camera.position.z)}set cameraDistance(t){this.camera.position.z=-t}add(t,e){e?e.forEach((e=>this.addBuffer(t,e))):this.addBuffer(t),t.group.name="meshGroup",t.wireframeGroup.name="wireframeGroup",t.parameters.background?(this.backgroundGroup.add(t.group),this.backgroundGroup.add(t.wireframeGroup)):(this.modelGroup.add(t.group),this.modelGroup.add(t.wireframeGroup)),t.pickable&&this.pickingGroup.add(t.pickingGroup),Te&&this.updateHelper()}addBuffer(t,e){function i(r){r instanceof d?r.children.forEach(i):(r.userData.buffer=t,r.userData.instance=e,r.onBeforeRender=Ki)}const r=t.getMesh();e&&r.applyMatrix4(e.matrix),i(r),t.group.add(r);const n=t.getWireframeMesh();if(e&&(n.matrix.copy(r.matrix),n.position.copy(r.position),n.quaternion.copy(r.quaternion),n.scale.copy(r.scale)),i(n),t.wireframeGroup.add(n),t.pickable){const n=t.getPickingMesh();e&&(n.matrix.copy(r.matrix),n.position.copy(r.position),n.quaternion.copy(r.quaternion),n.scale.copy(r.scale)),i(n),t.pickingGroup.add(n)}e?this._updateBoundingBox(t.geometry,t.matrix,e.matrix):this._updateBoundingBox(t.geometry,t.matrix)}remove(t){this.translationGroup.children.forEach((function(e){e.remove(t.group),e.remove(t.wireframeGroup)})),t.pickable&&this.pickingGroup.remove(t.pickingGroup),this.updateBoundingBox(),Te&&this.updateHelper()}_updateBoundingBox(t,e,i){const r=this.boundingBox;function n(t,e,i){null==t.boundingBox&&t.computeBoundingBox();const n=t.boundingBox.clone();e&&n.applyMatrix4(e),i&&n.applyMatrix4(i),n.min.equals(n.max)&&n.expandByScalar(5),r.union(n)}function s(t){if(void 0!==t.geometry){let e,i;t.userData.buffer&&(e=t.userData.buffer.matrix),t.userData.instance&&(i=t.userData.instance.matrix),n(t.geometry,e,i)}}t?n(t,e,i):(r.makeEmpty(),this.modelGroup.traverse(s),this.backgroundGroup.traverse(s)),r.getSize(this.boundingBoxSize),this.boundingBoxLength=this.boundingBoxSize.length()}updateBoundingBox(){this._updateBoundingBox(),Te&&this.updateHelper()}getPickingPixels(){const{width:t,height:e}=this,i=t*e*4,r=Ae?new Float32Array(i):new Uint8Array(i);return this.render(!0),this.renderer.readRenderTargetPixels(this.pickingTarget,0,0,t,e,r),r}getImage(t){return new Promise((e=>{if(t){const{width:t,height:i}=this,r=t*i*4;let n=this.getPickingPixels();if(Ae){const t=new Uint8Array(r);for(let e=0;e500&&!this.isStill&&this.sampleLevel<3&&-1!==this.sampleLevel){const t=this.sampleLevel;this.sampleLevel=3,this.renderPending=!0,this.render(),this.isStill=!0,this.sampleLevel=t,Te&&Ie.log("rendered still frame")}this.frameRequest=window.requestAnimationFrame(this.animate)}pick(t,e){if("stereo"===this.parameters.cameraType)return{pid:0,instance:void 0,picker:void 0};t*=window.devicePixelRatio,e*=window.devicePixelRatio,t=Math.max(t-2,0),e=Math.max(e-2,0);let i,r,n=0;const s=Ae?qi:Wi;this.render(!0),this.renderer.readRenderTargetPixels(this.pickingTarget,t,e,5,5,s);for(let t=0;t22&&(this.stats.begin(),this.isStill=!1),this.renderPending=!0,window.requestAnimationFrame((()=>{this.render(),this.stats.update()})))}updateZoom(){const t=Pt(this.perspectiveCamera.fov),e=2*Math.tan(t/2)*this.cameraDistance;this.orthographicCamera.zoom=this.height/e}absoluteToRelative(t){return 50*(1-t/this.bRadius)}relativeToAbsolute(t){return this.bRadius*(1-t/50)}__updateClipping(){const t=this.parameters;this.bRadius=Math.max(10,.5*this.boundingBoxLength),isFinite(this.bRadius)||(this.bRadius=50),this.camera.getWorldPosition(this.distVector),this.cDist=this.distVector.length(),this.cDist||(this.cameraDistance=Math.abs(t.cameraZ),this.cDist=Math.abs(t.cameraZ));const e=this.scene.fog;if(e.color.set(t.fogColor),"camera"===t.clipMode)this.camera.near=t.clipNear,this.camera.far=t.clipFar,e.near=t.fogNear,e.far=t.fogFar;else if("absolute"===t.clipScale)this.camera.near=this.cDist-t.clipNear,this.camera.far=this.cDist+t.clipFar,e.near=this.cDist-t.fogNear,e.far=this.cDist+t.fogFar;else{const i=(50-t.clipNear)/50,r=-(50-t.clipFar)/50;this.camera.near=this.cDist-this.bRadius*i,this.camera.far=this.cDist+this.bRadius*r;const n=(50-t.fogNear)/50,s=-(50-t.fogFar)/50;e.near=this.cDist-this.bRadius*n,e.far=this.cDist+this.bRadius*s}"camera"!==t.clipMode&&("PerspectiveCamera"===this.camera.type?(this.camera.near=Math.max(.1,t.clipDist,this.camera.near),this.camera.far=Math.max(1,this.camera.far),e.near=Math.max(.1,e.near),e.far=Math.max(1,e.far)):"OrthographicCamera"===this.camera.type&&t.clipDist>0&&(this.camera.near=Math.max(t.clipDist,this.camera.near)))}__updateCamera(){const e=this.camera;e.updateMatrix(),e.updateMatrixWorld(!0),e.updateProjectionMatrix(),function(e,i,r,n,s){let o=new t;r.getSize(o);const a=o.height,c=r.getPixelRatio(),l="OrthographicCamera"===i.type;Li.set(o.width,o.height),Ni.copy(i.projectionMatrix).invert(),zi.copy(i.projectionMatrix).transpose(),e.traverse((function(t){const e=t.material;if(!e)return;const i=e.uniforms;if(i){if(e.clipNear){const t=(50-e.clipNear)/50,r=n-s*t;i.clipNear.value=r}i.canvasHeight&&(i.canvasHeight.value=a),i.resolution&&i.resolution.value.copy(Li),i.pixelRatio&&(i.pixelRatio.value=c),i.projectionMatrixInverse&&i.projectionMatrixInverse.value.copy(Ni),i.projectionMatrixTranspose&&i.projectionMatrixTranspose.value.copy(zi),i.ortho&&(i.ortho.value=l)}}))}(this.scene,e,this.renderer,this.cDist,this.bRadius),function(t,e){t.traverseVisible((function(t){if(!(t instanceof o&&t.userData.buffer.parameters.sortParticles))return;const i=t.geometry.attributes,r=i.position.count;if(0===r)return;let n,s,a,c,l,h,u,d;Oi.multiplyMatrices(e.matrixWorldInverse,t.matrixWorld),Ri.multiplyMatrices(e.projectionMatrix,Oi),t.userData.sortData?(n=t.userData.sortData,a=n.__zArray,s=n.__sortArray,c=n.__cmpFn):(a=new Float32Array(r),s=new Uint32Array(r),c=function(t,e){const i=a[t],r=a[e];return i>r?1:ie?1:t=l&&e(t[o],s)>0;)t[o+1]=t[o],--o;t[o+1]=s}if(-1===c)break;h=n[c--],l=n[c--]}else{for(o=l+1,a=h,u(l+h>>1,o),e(t[l],t[h])>0&&u(l,h),e(t[o],t[h])>0&&u(o,h),e(t[l],t[o])>0&&u(l,o),s=t[o];;){do{o++}while(e(t[o],s)<0);do{a--}while(e(t[a],s)>0);if(a=a-l?(n[++c]=o,n[++c]=h,h=a-1):(n[++c]=l,n[++c]=a-1,l=o)}}(s,c);for(let t in i){const e=i[t],o=e.array,a=e.itemSize;n[t]||(n[t]=new Float32Array(a*r)),d=n[t],n[t]=o;for(let t=0;t0&&"stereo"!==this.parameters.cameraType?this.__renderSuperSample(e,i):this.__renderModelGroup(e,i)}render(t=!1,e){if(this.rendering)Ie.warn("'tried to call 'render' from within 'render'");else{this.rendering=!0;try{this.__updateClipping(),this.__updateCamera(),this.__updateLights(),this.updateInfo(!0),"stereo"===this.parameters.cameraType?this.__renderStereo(t,e):this.__render(t,this.camera,e),this.lastRenderedPicking=t}finally{this.rendering=!1,this.renderPending=!1}this.signals.rendered.dispatch()}}clear(){Ie.log("scene cleared"),this.scene.remove(this.rotationGroup),this._initScene(),this.renderer.clear()}dispose(){this.renderer.dispose(),window.cancelAnimationFrame(this.frameRequest)}}const Qi=1,Ji=2,tr=3;function er(t){const e=t.touches[0].pageX-t.touches[1].pageX,i=t.touches[0].pageY-t.touches[1].pageY;return Math.sqrt(e*e+i*i)}class ir{constructor(e,i={}){this.domElement=e,this.signals={moved:new tt,scrolled:new tt,dragged:new tt,dropped:new tt,clicked:new tt,hovered:new tt,doubleClicked:new tt},this.position=new t,this.prevPosition=new t,this.down=new t,this.canvasPosition=new t,this.prevClickCP=new t,this.moving=!1,this.hovering=!0,this.scrolled=!1,this.lastMoved=1/0,this.which=0,this.buttons=0,this.pressed=!1,this.altKey=!1,this.ctrlKey=!1,this.metaKey=!1,this.shiftKey=!1,this.domElement.style.touchAction="none",this.hoverTimeout=rt(i.hoverTimeout,50),this.handleScroll=rt(i.handleScroll,!0),this.doubleClickSpeed=rt(i.doubleClickSpeed,500),this._listen=this._listen.bind(this),this._onMousewheel=this._onMousewheel.bind(this),this._onMousemove=this._onMousemove.bind(this),this._onMousedown=this._onMousedown.bind(this),this._onMouseup=this._onMouseup.bind(this),this._onContextmenu=this._onContextmenu.bind(this),this._onTouchstart=this._onTouchstart.bind(this),this._onTouchend=this._onTouchend.bind(this),this._onTouchmove=this._onTouchmove.bind(this),this._listen();const r={passive:!1};document.addEventListener("mousewheel",this._onMousewheel,r),document.addEventListener("wheel",this._onMousewheel,r),document.addEventListener("MozMousePixelScroll",this._onMousewheel,r),document.addEventListener("mousemove",this._onMousemove,r),document.addEventListener("mousedown",this._onMousedown,r),document.addEventListener("mouseup",this._onMouseup,r),document.addEventListener("contextmenu",this._onContextmenu,r),document.addEventListener("touchstart",this._onTouchstart,r),document.addEventListener("touchend",this._onTouchend,r),document.addEventListener("touchmove",this._onTouchmove,r)}get key(){let t=0;return this.altKey&&(t+=1),this.ctrlKey&&(t+=2),this.metaKey&&(t+=4),this.shiftKey&&(t+=8),t}setParameters(t={}){this.hoverTimeout=rt(t.hoverTimeout,this.hoverTimeout)}_listen(){const t=window.performance.now(),e=this.canvasPosition;this.doubleClickPending&&t-this.lastClicked>this.doubleClickSpeed&&(this.doubleClickPending=!1),t-this.lastMoved>this.hoverTimeout&&(this.moving=!1),(this.scrolled||!this.moving&&!this.hovering)&&(this.scrolled=!1,-1!==this.hoverTimeout&&this.overElement&&(this.hovering=!0,this.signals.hovered.dispatch(e.x,e.y))),this.frameRequest=window.requestAnimationFrame(this._listen)}_onMousewheel(t){if(t.target!==this.domElement||!this.handleScroll)return;t.preventDefault(),this._setKeys(t);let e=0;"deltaY"in t&&"deltaMode"in t&&void 0!==t.deltaY&&void 0!==t.deltaMode?e=t.deltaMode===WheelEvent.DOM_DELTA_PIXEL?.025*-t.deltaY:t.deltaMode===WheelEvent.DOM_DELTA_LINE?-t.deltaY*(2.5/3):2.5*-t.deltaY:"deltaY"in t&&!("detail"in t)?e=.025*-t.deltaY:void 0!==t.wheelDelta?e=.025*-t.wheelDelta:void 0!==t.wheelDeltaY?e=.025*-t.wheelDeltaY:void 0!==t.detail&&(e=-t.detail/3),this.signals.scrolled.dispatch(e),setTimeout((()=>{this.scrolled=!0}),this.hoverTimeout)}_onMousemove(t){t.target===this.domElement?(t.preventDefault(),this.overElement=!0):this.overElement=!1,this._setKeys(t),this.moving=!0,this.hovering=!1,this.lastMoved=window.performance.now(),this.prevPosition.copy(this.position),this.position.set(t.clientX,t.clientY),this._setCanvasPosition(t);const e=this.prevPosition.x-this.position.x,i=this.prevPosition.y-this.position.y;this.signals.moved.dispatch(e,i),this.pressed&&this.signals.dragged.dispatch(e,i)}_onMousedown(t){t.target===this.domElement&&(t.preventDefault(),this._setKeys(t),this.moving=!1,this.hovering=!1,this.down.set(t.clientX,t.clientY),this.position.set(t.clientX,t.clientY),this.which=t.which,this.buttons=function(t){if("object"==typeof t){if("buttons"in t)return t.buttons;if("which"in t){const e=t.which;if(2===e)return 4;if(3===e)return 2;if(e>0)return 1<=0)return 1<2&&this.handleScroll&&this.position.distanceTo(this.prevPosition)<2)this.which=0,this.buttons=0,this.signals.scrolled.dispatch(i/2);else{this.which=3,this.buttons=2;const t=this.prevPosition.x-this.position.x,e=this.prevPosition.y-this.position.y;this.signals.moved.dispatch(t,e),this.pressed&&this.signals.dragged.dispatch(t,e)}}}}_distance(){return this.position.distanceTo(this.down)}_setCanvasPosition(t){const e=this.domElement.getBoundingClientRect();let i,r;"clientX"in t&&"clientY"in t?(i=t.clientX-e.left,r=t.clientY-e.top):(i=t.offsetX,r=t.offsetY),this.canvasPosition.set(i,e.height-r)}_setKeys(t){this.altKey=t.altKey,this.ctrlKey=t.ctrlKey,this.metaKey=t.metaKey,this.shiftKey=t.shiftKey}dispose(){document.removeEventListener("mousewheel",this._onMousewheel),document.removeEventListener("wheel",this._onMousewheel),document.removeEventListener("MozMousePixelScroll",this._onMousewheel),document.removeEventListener("mousemove",this._onMousemove),document.removeEventListener("mousedown",this._onMousedown),document.removeEventListener("mouseup",this._onMouseup),document.removeEventListener("contextmenu",this._onContextmenu),document.removeEventListener("touchstart",this._onTouchstart),document.removeEventListener("touchend",this._onTouchend),document.removeEventListener("touchmove",this._onTouchmove),window.cancelAnimationFrame(this.frameRequest)}}const rr=new i,nr=new i,sr=new i,or=new i,ar=new i,cr=new e,lr=new r,hr=new r,ur=new i,dr=new e,mr=new e;class fr{constructor(t,e={}){this.stage=t,this.rotateSpeed=rt(e.rotateSpeed,2),this.zoomSpeed=rt(e.zoomSpeed,1.2),this.panSpeed=rt(e.panSpeed,1),this.viewer=t.viewer,this.mouse=t.mouseObserver,this.controls=t.viewerControls}get component(){return this.stage.transformComponent}get atom(){return this.stage.transformAtom}_setPanVector(t,e,i=0){const r=this.controls.getCanvasScaleFactor(i);dr.set(t,e,0),dr.multiplyScalar(this.panSpeed*r)}_getRotateXY(t,e){return[this.rotateSpeed*-t*.01,this.rotateSpeed*e*.01]}_getCameraRotation(t){return t.extractRotation(this.viewer.camera.matrixWorld),t.multiply(nr.makeRotationY(Math.PI)),t}_transformPanVector(){this.component&&(ur.extractRotation(this.component.transform),ur.premultiply(this.viewer.rotationGroup.matrix),ur.invert(),ur.multiply(this._getCameraRotation(or)),dr.applyMatrix4(ur))}zoom(t){this.controls.zoom(this.zoomSpeed*t*.02)}pan(t,e){this._setPanVector(t,e),ur.copy(this.viewer.rotationGroup.matrix).invert(),ur.multiply(this._getCameraRotation(or)),dr.applyMatrix4(ur),this.controls.translate(dr)}panComponent(t,e){this.component&&(this._setPanVector(t,e),this._transformPanVector(),this.component.position.add(dr),this.component.updateMatrix())}panAtom(t,e){this.atom&&this.component&&(this.atom.positionToVector3(mr),mr.add(this.viewer.translationGroup.position),mr.applyMatrix4(this.viewer.rotationGroup.matrix),this._setPanVector(t,e,mr.z),this._transformPanVector(),this.atom.positionAdd(dr),this.component.updateRepresentations({position:!0}))}rotate(t,e){const[i,r]=this._getRotateXY(t,e);this._getCameraRotation(or),cr.set(1,0,0),cr.applyMatrix4(or),lr.setFromAxisAngle(cr,r),cr.set(0,1,0),cr.applyMatrix4(or),hr.setFromAxisAngle(cr,i),lr.multiply(hr),or.makeRotationFromQuaternion(lr),this.controls.applyMatrix(or)}zRotate(t,e){const i=this.rotateSpeed*((-t+e)/-2)*.01;sr.makeRotationZ(i),this.controls.applyMatrix(sr)}rotateComponent(t,e){if(!this.component)return;const[i,r]=this._getRotateXY(t,e);this._getCameraRotation(ar),or.extractRotation(this.component.transform),or.premultiply(this.viewer.rotationGroup.matrix),or.invert(),or.premultiply(ar),cr.set(1,0,0),cr.applyMatrix4(or),rr.makeRotationAxis(cr,r),cr.set(0,1,0),cr.applyMatrix4(or),nr.makeRotationAxis(cr,i),rr.multiply(nr),lr.setFromRotationMatrix(rr),this.component.quaternion.premultiply(lr),this.component.quaternion.normalize(),this.component.updateMatrix()}}const pr=new e;class gr{constructor(t,e){this.stage=e,this.pid=t.pid,this.picker=t.picker,this.instance=t.instance,this.stage=e,this.controls=e.viewerControls,this.mouse=e.mouseObserver}get type(){return this.picker.type}get altKey(){return this.mouse.altKey}get ctrlKey(){return this.mouse.ctrlKey}get metaKey(){return this.mouse.metaKey}get shiftKey(){return this.mouse.shiftKey}get canvasPosition(){return this.mouse.canvasPosition}get component(){return this.stage.getComponentsByObject(this.picker.data).list[0]}get object(){return this.picker.getObject(this.pid)}get position(){return this.picker.getPosition(this.pid,this.instance,this.component)}get closestBondAtom(){if("bond"!==this.type||!this.bond)return;const t=this.bond,e=this.controls,i=this.canvasPosition,r=t.atom1.positionToVector3(),n=t.atom2.positionToVector3();r.applyMatrix4(this.component.matrix),n.applyMatrix4(this.component.matrix);const s=e.getPositionOnCanvas(r),o=e.getPositionOnCanvas(n);return c=s,l=o,(a=i).distanceTo(c)=t.length))return new gr(i,this.stage);console.error("pid >= picker.array.length")}}}const br=new r,_r=new e,xr=new e,vr=new e,wr=new e,Ar=new i,Sr=new e,Cr=new i;class Pr{constructor(t){this.stage=t,this.signals={changed:new J.Signal},this.viewer=t.viewer}get position(){return this.viewer.translationGroup.position}get rotation(){return this.viewer.rotationGroup.quaternion}changed(){this.viewer.requestRender(),this.signals.changed.dispatch()}getPositionOnCanvas(e,i){const r=_t(i,t);const n=this.viewer;return vr.copy(e).add(n.translationGroup.position).applyMatrix4(n.rotationGroup.matrix).project(n.camera),r.set((vr.x+1)*n.width/2,(vr.y+1)*n.height/2)}getCanvasScaleFactor(t=0){const e=this.viewer.camera;if(e instanceof l)return 1/e.zoom;{t=Math.abs(t),t+=this.getCameraDistance();const i=Pt(e.fov);return 2*t*Math.tan(i/2)/this.viewer.height}}getOrientation(t){const e=vt(t);e.copy(this.viewer.rotationGroup.matrix);const i=this.getCameraDistance();return e.scale(wr.set(i,i,i)),e.setPosition(this.viewer.translationGroup.position),e}orient(t){vt(t).decompose(_r,br,xr);const e=this.viewer;e.rotationGroup.setRotationFromQuaternion(br),e.translationGroup.position.copy(_r),e.cameraDistance=xr.z,e.updateZoom(),this.changed()}translate(t){this.viewer.translationGroup.position.add(xt(t)),this.changed()}center(t){this.viewer.translationGroup.position.copy(xt(t)).negate(),this.changed()}zoom(t){this.distance(this.getCameraDistance()*(1-t))}getCameraDistance(){return this.viewer.cameraDistance}distance(t){this.viewer.cameraDistance=Math.max(Math.abs(t),.2),this.viewer.updateZoom(),this.changed()}spin(t,e){Ar.copy(this.viewer.rotationGroup.matrix).invert(),Sr.copy(xt(t)).applyMatrix4(Ar),this.viewer.rotationGroup.rotateOnAxis(Sr,e),this.changed()}rotate(t){this.viewer.rotationGroup.setRotationFromQuaternion(wt(t)),this.changed()}align(t){Cr.copy(vt(t)).invert(),this.viewer.rotationGroup.setRotationFromMatrix(Cr),this.changed()}applyMatrix(t){this.viewer.rotationGroup.applyMatrix4(vt(t)),this.changed()}}class Ir{constructor(t,e,...i){this.pausedTime=-1,this.elapsedDuration=0,this.pausedDuration=0,this.ignoreGlobalToggle=!1,this._paused=!1,this._resolveList=[],this.duration=rt(t,1e3),this.controls=e,this.startTime=window.performance.now(),this._init(...i)}get done(){return 1===this.alpha}get paused(){return this._paused}tick(t){if(!this._paused)return this.elapsedDuration=t.currentTime-this.startTime-this.pausedDuration,0===this.duration?this.alpha=1:this.alpha=Ft(0,1,this.elapsedDuration/this.duration),this._tick(t),this.done&&this._resolveList.forEach((t=>t())),this.done}pause(t){t&&(this._hold=!0),-1===this.pausedTime&&(this.pausedTime=window.performance.now()),this._paused=!0}resume(t){!t&&this._hold||(this.pausedDuration+=window.performance.now()-this.pausedTime,this._paused=!1,this._hold=!1,this.pausedTime=-1)}toggle(){this._paused?this.resume():this.pause()}then(t){let e;return e=this.done?Promise.resolve():new Promise((t=>this._resolveList.push(t))),e.then(t)}}class kr extends Ir{constructor(t,e,...i){super(rt(t,1/0),e,...i)}_init(t,i){Array.isArray(t)?this.axis=(new e).fromArray(t):this.axis=rt(t,new e(0,1,0)),this.angle=rt(i,.01)}_tick(t){this.axis&&this.angle&&this.controls.spin(this.axis,this.angle*t.lastDuration/16)}}class Mr extends Ir{constructor(t,e,...i){super(rt(t,1/0),e,...i),this.angleSum=0,this.direction=1}_init(t,i,r){Array.isArray(t)?this.axis=(new e).fromArray(t):this.axis=rt(t,new e(0,1,0)),this.angleStep=rt(i,.01),this.angleEnd=rt(r,.2)}_tick(t){if(!this.axis||!this.angleStep||!this.angleEnd)return;const e=Ft(0,1,Math.abs(this.angleSum)/this.angleEnd),i=this.angleStep*this.direction*(1.1-e);this.controls.spin(this.axis,i*t.lastDuration/16),this.angleSum+=this.angleStep,this.angleSum>=this.angleEnd&&(this.direction*=-1,this.angleSum=-this.angleEnd)}}class Tr extends Ir{_init(t,i){this.moveFrom=xt(rt(t,new e)),this.moveTo=xt(rt(i,new e))}_tick(){this.controls.position.lerpVectors(this.moveFrom,this.moveTo,this.alpha).negate(),this.controls.changed()}}class Dr extends Ir{_init(t,e){this.zoomFrom=t,this.zoomTo=e}_tick(){this.controls.distance(Dt(this.zoomFrom,this.zoomTo,this.alpha))}}class Br extends Ir{constructor(){super(...arguments),this._currentRotation=new r}_init(t,e){this.rotateFrom=wt(t),this.rotateTo=wt(e),this._currentRotation=new r}_tick(){this._currentRotation.copy(this.rotateFrom).slerp(this.rotateTo,this.alpha),this.controls.rotate(this._currentRotation)}}class Fr extends Ir{_init(t,e,i){this.valueFrom=t,this.valueTo=e,this.callback=i}_tick(){this.callback(Dt(this.valueFrom,this.valueTo,this.alpha))}}class Er extends Ir{_init(t){this.callback=t}_tick(){1===this.alpha&&this.callback()}}class $r{constructor(t=[]){this._resolveList=[],this._list=t}get done(){return this._list.every((t=>t.done))}then(t){let e;return e=this.done?Promise.resolve():new Promise((t=>{this._resolveList.push(t),this._list.forEach((t=>{t.then((()=>{this._resolveList.forEach((t=>{t()})),this._resolveList.length=0}))}))})),e.then(t)}}class Or{constructor(t){this.stage=t,this.animationList=[],this.finishedList=[],this.viewer=t.viewer,this.controls=t.viewerControls}get paused(){return this.animationList.every((t=>t.paused))}add(t){return 0===t.duration?t.tick(this.viewer.stats):this.animationList.push(t),t}remove(t){const e=this.animationList,i=e.indexOf(t);i>-1&&e.splice(i,1)}run(t){const e=this.finishedList,i=this.animationList,r=i.length;for(let n=0;nt.pause()))}resume(){this.animationList.forEach((t=>t.resume()))}toggle(){this.paused?this.resume():this.pause()}clear(){this.animationList.length=0}dispose(){this.clear()}}class Rr{constructor(t,e){if(this.fn=t,this.queue=[],this.pending=!1,this.next=this.next.bind(this),e){for(let t=0,i=e.length;tthis.run(t)))):this.pending=!1}push(t){this.queue.push(t),this.pending||this.next()}kill(){this.queue.length=0}length(){return this.queue.length}}class Lr{constructor(t,e,i){this.type="",this.parameters={lazy:{type:"boolean"},clipNear:{type:"range",step:1,max:100,min:0,buffer:!0},clipRadius:{type:"number",precision:1,max:1e3,min:0,buffer:!0},clipCenter:{type:"vector3",precision:1,buffer:!0},flatShaded:{type:"boolean",buffer:!0},opacity:{type:"range",step:.01,max:1,min:0,buffer:!0},depthWrite:{type:"boolean",buffer:!0},side:{type:"select",buffer:!0,options:{front:"front",back:"back",double:"double"}},wireframe:{type:"boolean",buffer:!0},colorData:{type:"hidden",update:"color"},colorScheme:{type:"select",update:"color",options:{}},colorScale:{type:"select",update:"color",options:$e.getScales()},colorReverse:{type:"boolean",update:"color"},colorValue:{type:"color",update:"color"},colorDomain:{type:"hidden",update:"color"},colorMode:{type:"select",update:"color",options:$e.getModes()},roughness:{type:"range",step:.01,max:1,min:0,buffer:!0},metalness:{type:"range",step:.01,max:1,min:0,buffer:!0},diffuse:{type:"color",buffer:!0},diffuseInterior:{type:"boolean",buffer:!0},useInteriorColor:{type:"boolean",buffer:!0},interiorColor:{type:"color",buffer:!0},interiorDarkening:{type:"range",step:.01,max:1,min:0,buffer:!0},matrix:{type:"hidden",buffer:!0},disablePicking:{type:"boolean",rebuild:!0}},this.viewer=e,this.tasks=new hi,this.queue=new Rr(this.make.bind(this)),this.bufferList=[],this.parameters.colorScheme&&(this.parameters.colorScheme.options=$e.getSchemes()),this.toBePrepared=!1}init(t){const r=t||{};this.clipNear=rt(r.clipNear,0),this.clipRadius=rt(r.clipRadius,0),this.clipCenter=rt(r.clipCenter,new e),this.flatShaded=rt(r.flatShaded,!1),this.side=rt(r.side,"double"),this.opacity=rt(r.opacity,1),this.depthWrite=rt(r.depthWrite,!0),this.wireframe=rt(r.wireframe,!1),this.setColor(r.color,r),this.colorData=rt(r.colorData,void 0),this.colorScheme=rt(r.colorScheme,"uniform"),this.colorScale=rt(r.colorScale,""),this.colorReverse=rt(r.colorReverse,!1),this.colorValue=rt(r.colorValue,9474192),this.colorDomain=rt(r.colorDomain,void 0),this.colorMode=rt(r.colorMode,"hcl"),this.visible=rt(r.visible,!0),this.quality=rt(r.quality,void 0),this.roughness=rt(r.roughness,.4),this.metalness=rt(r.metalness,0),this.diffuse=rt(r.diffuse,16777215),this.diffuseInterior=rt(r.diffuseInterior,!1),this.useInteriorColor=rt(r.useInteriorColor,!1),this.interiorColor=rt(r.interiorColor,2236962),this.interiorDarkening=rt(r.interiorDarkening,0),this.lazy=rt(r.lazy,!1),this.lazyProps={build:!1,bufferParams:{},what:{}},this.matrix=rt(r.matrix,new i),this.disablePicking=rt(r.disablePicking,!1);const n=this.parameters;!0===n.sphereDetail&&(n.sphereDetail={type:"integer",max:3,min:0,rebuild:"impostor"}),!0===n.radialSegments&&(n.radialSegments={type:"integer",max:25,min:5,rebuild:"impostor"}),!0===n.openEnded&&(n.openEnded={type:"boolean",rebuild:"impostor",buffer:!0}),!0===n.disableImpostor&&(n.disableImpostor={type:"boolean",rebuild:!0}),"low"===r.quality?(n.sphereDetail&&(this.sphereDetail=0),n.radialSegments&&(this.radialSegments=5)):"medium"===r.quality?(n.sphereDetail&&(this.sphereDetail=1),n.radialSegments&&(this.radialSegments=10)):"high"===r.quality?(n.sphereDetail&&(this.sphereDetail=2),n.radialSegments&&(this.radialSegments=20)):(n.sphereDetail&&(this.sphereDetail=rt(r.sphereDetail,1)),n.radialSegments&&(this.radialSegments=rt(r.radialSegments,10))),n.openEnded&&(this.openEnded=rt(r.openEnded,!0)),n.disableImpostor&&(this.disableImpostor=rt(r.disableImpostor,!1))}getColorParams(t){return Object.assign({data:this.colorData,scheme:this.colorScheme,scale:this.colorScale,reverse:this.colorReverse,value:this.colorValue,domain:this.colorDomain,mode:this.colorMode,colorSpace:this.colorSpace},t)}getBufferParams(t={}){return Object.assign({clipNear:this.clipNear,clipRadius:this.clipRadius,clipCenter:this.clipCenter,flatShaded:this.flatShaded,opacity:this.opacity,depthWrite:this.depthWrite,side:this.side,wireframe:this.wireframe,roughness:this.roughness,metalness:this.metalness,diffuse:this.diffuse,diffuseInterior:this.diffuseInterior,useInteriorColor:this.useInteriorColor,interiorColor:this.interiorColor,interiorDarkening:this.interiorDarkening,matrix:this.matrix,disablePicking:this.disablePicking},t)}setColor(t,e){const i=Object.keys($e.getSchemes());if("string"==typeof t&&i.includes(t.toLowerCase()))e?e.colorScheme=t:this.setParameters({colorScheme:t});else if(void 0!==t){let i=new n(t).getHex();e?(e.colorScheme="uniform",e.colorValue=i):this.setParameters({colorScheme:"uniform",colorValue:i})}return this}prepare(t){}create(){}update(t){this.build()}build(t){if(!this.lazy||this.visible&&this.opacity){if(!this.toBePrepared)return this.tasks.increment(),void this.make();this.queue.length()>0?(this.tasks.change(1-this.queue.length()),this.queue.kill()):this.tasks.increment(),this.queue.push(t||!1)}else this.lazyProps.build=!0}make(t,e){Te&&Ie.time("Representation.make "+this.type);const i=()=>{t?(this.update(t),this.viewer.requestRender(),this.tasks.decrement(),e&&e()):(this.clear(),this.create(),this.manualAttach||this.disposed||(Te&&Ie.time("Representation.attach "+this.type),this.attach((()=>{Te&&Ie.timeEnd("Representation.attach "+this.type),this.tasks.decrement(),e&&e()})))),Te&&Ie.timeEnd("Representation.make "+this.type)};this.toBePrepared?this.prepare(i):i()}attach(t){this.setVisibility(this.visible),t()}setVisibility(t,e){if(this.visible=t,this.visible&&this.opacity){const t=this.lazyProps,e=t.bufferParams,i=t.what;if(t.build)return t.build=!1,this.build(),this;(Object.keys(e).length||Object.keys(i).length)&&(t.bufferParams={},t.what={},this.updateParameters(e,i))}return this.bufferList.forEach((function(e){e.setVisibility(t)})),e||this.viewer.requestRender(),this}setParameters(t,e={},i=!1){const r=t||{},n=this.parameters,s={};this.opacity||void 0===r.opacity||(this.lazyProps.build?(this.lazyProps.build=!1,i=!0):(Object.assign(s,this.lazyProps.bufferParams),Object.assign(e,this.lazyProps.what),this.lazyProps.bufferParams={},this.lazyProps.what={})),this.setColor(r.color,r);for(let t in r)if(void 0!==r[t]&&null!=n[t]&&(n[t].int&&(r[t]=parseInt(r[t])),n[t].float&&(r[t]=parseFloat(r[t])),r[t]!==this[t]||r[t].equals&&!r[t].equals(this[t]))){if(this[t]&&this[t].copy&&r[t].copy?this[t].copy(r[t]):this[t]&&this[t].set?this[t].set(r[t]):this[t]=r[t],n[t].buffer)if(!0===n[t].buffer)s[t]=r[t];else{s[n[t].buffer]=r[t]}n[t].update&&(e[n[t].update]=!0),!n[t].rebuild||"impostor"===n[t].rebuild&&Ce&&!this.disableImpostor||(i=!0)}return i?this.build():this.updateParameters(s,e),this}updateParameters(t={},e){if(this.lazy&&(!this.visible||!this.opacity)&&!1===t.hasOwnProperty("opacity"))return Object.assign(this.lazyProps.bufferParams,t),void Object.assign(this.lazyProps.what,e);this.bufferList.forEach((function(e){e.setParameters(t)})),Object.keys(e).length&&this.update(e),this.viewer.requestRender()}getParameters(){const t={lazy:this.lazy,visible:this.visible,quality:this.quality};return Object.keys(this.parameters).forEach((e=>{null!==this.parameters[e]&&(t[e]=this[e])})),t}clear(){this.bufferList.forEach((t=>{this.viewer.remove(t),t.dispose()})),this.bufferList.length=0,this.viewer.requestRender()}dispose(){this.disposed=!0,this.queue.kill(),this.tasks.dispose(),this.clear()}}class Nr{constructor(t){this.pending=0,this.postCount=0,this.onmessageDict={},this.onerrorDict={},this.name=t,this.blobUrl=window.URL.createObjectURL(Ee.get(t)),this.worker=new Worker(this.blobUrl),Ee.activeWorkerCount+=1,this.worker.onmessage=e=>{this.pending-=1;const i=e.data.__postId;Te&&Ie.timeEnd("Worker.postMessage "+t+" #"+i);const r=this.onmessageDict[i];r&&r.call(this.worker,e),delete this.onmessageDict[i],delete this.onerrorDict[i]},this.worker.onerror=e=>{if(this.pending-=1,e.data){const i=e.data.__postId,r=this.onerrorDict[i];r?r.call(this.worker,e):Ie.error("Worker.onerror",i,t,e),delete this.onmessageDict[i],delete this.onerrorDict[i]}else Ie.error("Worker.onerror",t,e)}}post(t={},e,i,r){this.onmessageDict[this.postCount]=i,this.onerrorDict[this.postCount]=r,t.__name=this.name,t.__postId=this.postCount,t.__debug=Te,Te&&Ie.time(`Worker.postMessage ${this.name} #${this.postCount}`);try{this.worker.postMessage(t,e)}catch(e){Ie.error("worker.post:",e),this.worker.postMessage(t)}return this.pending+=1,this.postCount+=1,this}terminate(){this.worker?(this.worker.terminate(),window.URL.revokeObjectURL(this.blobUrl),Ee.activeWorkerCount-=1):Ie.log("no worker to terminate")}}class zr{constructor(t,e=2){this.pool=[],this.count=0,this.maxCount=Math.min(8,e),this.name=t}post(t={},e,i,r){const n=this.getNextWorker();return n?n.post(t,e,i,r):console.error("unable to get worker from pool"),this}terminate(){this.pool.forEach((function(t){t.terminate()}))}getNextWorker(){let t,e=1/0;for(let i=0;i=this.count){t=new Nr(this.name),this.pool.push(t),this.count+=1;break}const r=this.pool[i];if(0===r.pending){t=r;break}r.pendingn&&(n=c),l>s&&(s=l),h>o&&(o=h)}return[Wr([e,i,r]),Wr([n,s,o])]}function Gr(t,e){for(let i=0,r=e.length;i0){const o=1/Math.sqrt(s);t[e]=i*o,t[e+1]=r*o,t[e+2]=n*o}}}function Wr(t){return new Float32Array(t||3)}function Xr(t,e,i){const r=e[0],n=e[1],s=e[2],o=i[0],a=i[1],c=i[2];t[0]=n*c-s*a,t[1]=s*o-r*c,t[2]=r*a-n*o}function Yr(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function Kr(t,e,i){t[0]=e[0]-i[0],t[1]=e[1]-i[1],t[2]=e[2]-i[2]}function Zr(t,e,i){t[0]=e[0]+i[0],t[1]=e[1]+i[1],t[2]=e[2]+i[2]}function Qr(t,e,i=0){t[0]=e[i],t[1]=e[i+1],t[2]=e[i+2]}function Jr(t,e,i=0){e[i]=t[0],e[i+1]=t[1],e[i+2]=t[2]}function tn(t){return t[0]*t[0]+t[1]*t[1]+t[2]*t[2]}function en(t){return Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2])}function rn(t,e,i){nn(t,e,1/i)}function nn(t,e,i){t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i}function sn(t,e){const i=tn(e);0==i?(t[0]=e[0],t[1]=e[1],t[2]=e[2]):nn(t,e,1/Math.sqrt(i))}function on(t,e,i){t[0]=e[0]-i,t[1]=e[1]-i,t[2]=e[2]-i}function an(t,e,i){t[0]=e[0]+i,t[1]=e[1]+i,t[2]=e[2]+i}function cn(t,e){t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2])}function ln(t,e){t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2])}function hn(t,e){t[0]=-e[0],t[1]=-e[1],t[2]=-e[2]}function un(t,e){const i=t[0],r=t[1],n=t[2],s=e[0],o=e[1],a=e[2],c=r*a-n*o,l=n*s-i*a,h=i*o-r*s,u=Math.sqrt(c*c+l*l+h*h),d=i*s+r*o+n*a;return Math.atan2(u,d)}function dn(t,i=9){const r=Math.floor(i/2),n=t.position1.length/3,s=3*(r*n),o=1/i,a=vi(t.position1,t.position2),c=new Float32Array(s),l=new Float32Array(s),h=new e;for(let e=0;e0){const e=3*f;s[e]=t.position2[3*u-3],s[e+1]=t.position2[3*u-2],s[e+1]=t.position2[3*u-1]}const y=new Float32Array(n),b=new Float32Array(s),_=xi(y,b),x=new Float32Array(o),v={position:_,position1:y,position2:b,color:x,color2:x};return a&&(v.radius=new Float32Array(a)),c&&t.picking&&(t.picking.array=new Float32Array(c),v.picking=t.picking),l&&(v.primitiveId=new Float32Array(l)),v}zr.prototype.constructor=zr,jr.__deps=[Wr],rn.__deps=[nn],sn.__deps=[nn,tn];const pn=new e;class gn{static get Picker(){return je.get(this.type)}static get Buffer(){return Ve.get(this.type)}static getShapeKey(t){return this.type+t[0].toUpperCase()+t.substr(1)}static expandBoundingBox(t,e){}static valueToShape(t,e,i){const r=t._primitiveData[this.getShapeKey(e)];switch(this.fields[e]){case"v3":case"c":!function(t,e){void 0!==t.toArray?t=t.toArray():void 0!==t.x?t=[t.x,t.y,t.z]:void 0!==t.r&&(t=[t.r,t.g,t.b]),e.push.apply(e,t)}(i,r);break;default:r.push(i)}}static objectToShape(t,e){Object.keys(this.fields).forEach((i=>{this.valueToShape(t,i,e[i])})),this.valueToShape(t,"name",e.name),this.expandBoundingBox(t.boundingBox,e)}static valueFromShape(t,i,r){const s=t._primitiveData[this.getShapeKey(r)];switch(this.fields[r]){case"v3":return(new e).fromArray(s,3*i);case"c":return(new n).fromArray(s,3*i);default:return s[i]}}static objectFromShape(t,e){let i=this.valueFromShape(t,e,"name");void 0===i&&(i=`${this.type}: ${e} (${t.name})`);const r={shape:t,name:i};return Object.keys(this.fields).forEach((i=>{r[i]=this.valueFromShape(t,e,i)})),r}static arrayFromShape(t,e){const i=t._primitiveData[this.getShapeKey(e)];return"s"===this.fields[e]?i:new Float32Array(i)}static dataFromShape(t){const e={};return this.Picker&&(e.picking=new this.Picker(t)),Object.keys(this.fields).forEach((i=>{e[i]=this.arrayFromShape(t,i)})),e}static bufferFromShape(t,e){return new this.Buffer(this.dataFromShape(t),e)}}gn.type="",gn.fields={};class yn extends gn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(pn.fromArray(e.position))}}yn.type="sphere",yn.fields={position:"v3",color:"c",radius:"f"};class bn extends gn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(pn.fromArray(e.position))}}bn.type="box",bn.fields={position:"v3",color:"c",size:"f",heightAxis:"v3",depthAxis:"v3"};class _n extends bn{}_n.type="octahedron";class xn extends bn{}xn.type="tetrahedron";class vn extends gn{static positionFromShape(t,e){const i=this.valueFromShape(t,e,"position1"),r=this.valueFromShape(t,e,"position2");return i.add(r).multiplyScalar(.5)}static expandBoundingBox(t,e){t.expandByPoint(pn.fromArray(e.position1)),t.expandByPoint(pn.fromArray(e.position2))}static bufferFromShape(t,e={}){let i=this.dataFromShape(t);return"cylinder"===this.type&&e.dashedCylinder&&(i=mn(i)),new this.Buffer(i,e)}}vn.type="cylinder",vn.fields={position1:"v3",position2:"v3",color:"c",radius:"f"};class wn extends vn{}wn.type="arrow";class An extends vn{}An.type="cone";class Sn extends yn{}Sn.type="ellipsoid",Sn.fields={position:"v3",color:"c",radius:"f",majorAxis:"v3",minorAxis:"v3"};class Cn extends Sn{}Cn.type="torus";class Pn extends gn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(pn.fromArray(e.position))}}Pn.type="text",Pn.fields={position:"v3",color:"c",size:"f",text:"s"};class In extends gn{static positionFromShape(t,e){return this.valueFromShape(t,e,"position")}static expandBoundingBox(t,e){t.expandByPoint(pn.fromArray(e.position))}}In.type="point",In.fields={position:"v3",color:"c"};class kn extends gn{static positionFromShape(t,e){const i=this.valueFromShape(t,e,"position1"),r=this.valueFromShape(t,e,"position2");return i.add(r).multiplyScalar(.5)}static expandBoundingBox(t,e){t.expandByPoint(pn.fromArray(e.position1)),t.expandByPoint(pn.fromArray(e.position2))}}kn.type="wideline",kn.fields={position1:"v3",position2:"v3",color:"c"};class Mn{constructor(t,e){this.exp=3;const i=e||function(t){const{x:e,y:i,z:r}=t,n=new a,s=e.length,{min:o,max:c}=n;for(let t=0;t>this.exp),this.boundY=1+(i.max.y-this.minY>>this.exp),this.boundZ=1+(i.max.z-this.minZ>>this.exp);const r=this.boundX*this.boundY*this.boundZ,n=void 0!==t.count?t.count:t.x.length,s=t.x,o=t.y,c=t.z;let l=0;const h=new Uint32Array(r),u=new Int32Array(n);for(let t=0;t>this.exp,i=o[t]-this.minY>>this.exp,r=c[t]-this.minZ>>this.exp,n=(e*this.boundY+i)*this.boundZ+r;1===(h[n]+=1)&&(l+=1),u[t]=n}const d=new Uint16Array(l);for(let t=0,e=0;t0&&(h[t]=e+1,d[e]=i,e+=1)}const m=new Uint32Array(l);for(let t=1;t0){const i=e-1;p[m[i]+f[i]]=t,f[i]+=1}}this.grid=h,this.bucketCount=d,this.bucketOffset=m,this.bucketArray=p,this.xArray=s,this.yArray=o,this.zArray=c}within(t,e,i,r){const n=[];return this.eachWithin(t,e,i,r,(t=>n.push(t))),n}eachWithin(t,e,i,r,n){const s=r*r,o=Math.max(0,t-r-this.minX>>this.exp),a=Math.max(0,e-r-this.minY>>this.exp),c=Math.max(0,i-r-this.minZ>>this.exp),l=Math.min(this.boundX,1+(t+r-this.minX>>this.exp)),h=Math.min(this.boundY,1+(e+r-this.minY>>this.exp)),u=Math.min(this.boundZ,1+(i+r-this.minZ>>this.exp));for(let r=o;r0){const r=l-1,o=this.bucketOffset[r],a=o+this.bucketCount[r];for(let r=o;rr?n.set(this[e].subarray(0,r)):n.set(this[e]),this[e]=n}}growIfFull(){if(this.count>=this.length){const t=Math.round(1.5*this.length);this.resize(Math.max(256,t))}}copyFrom(t,e,i,r){for(let n=0,s=this._fields.length;n0;)h-=1;l<=h&&(l===c?c=h:h===c&&(c=l),(o=l)!==(a=h)&&(i.copyFrom(e,0,o,1),e.copyWithin(o,a,1),e.copyFrom(i,a,0,1)),l+=1,h-=1)}while(l<=h);r(n,h),r(l,s)}var o,a}(0,this.count-1),Ie.timeEnd("Store.sort")}clear(){this.count=0}dispose(){for(let t=0,e=this._fields.length;t>>1&1431655765))+(t>>>2&858993459))+(t>>>4)&252645135)>>>24}class Fn{constructor(t,e){this.length=t,this._words=new Uint32Array(t+32>>>5),!0===e&&this.setAll()}get(t){return!!(this._words[t>>>5]&1<>>5]|=1<>>5]&=~(1<>>5]^=1<>>5,o=e>>>5;for(let t=s+1;t>>5]|=1<>>5]|=1<>>5]|=1<>>5]&=~(1<>>5]&=~(1<>>5]&=~(1<>>5]|=1<>>5]&=~(1<>>i,this}_isRangeValue(t,e,i){if(e>>5,o=e>>>5;for(let t=s+1;t>>5]&1<>>5]&1<>>5]&1<>>5]&1<>>5]&1<0){const{types:r,groups:n,centers:s,atomSets:o}=t;r.push(e.type),n.push(e.group),s.x.push(e.x/i),s.y.push(e.y/i),s.z.push(e.z/i),o.push(e.atomSet)}}const Ln=0,Nn=["D-BETA-PEPTIDE, C-GAMMA LINKING","D-GAMMA-PEPTIDE, C-DELTA LINKING","D-PEPTIDE COOH CARBOXY TERMINUS","D-PEPTIDE NH3 AMINO TERMINUS","D-PEPTIDE LINKING","L-BETA-PEPTIDE, C-GAMMA LINKING","L-GAMMA-PEPTIDE, C-DELTA LINKING","L-PEPTIDE COOH CARBOXY TERMINUS","L-PEPTIDE NH3 AMINO TERMINUS","L-PEPTIDE LINKING","PEPTIDE LINKING","PEPTIDE-LIKE"],zn=["RNA OH 3 PRIME TERMINUS","RNA OH 5 PRIME TERMINUS","RNA LINKING"],Un=["DNA OH 3 PRIME TERMINUS","DNA OH 5 PRIME TERMINUS","DNA LINKING","L-DNA LINKING","L-RNA LINKING"],Vn=["D-SACCHARIDE","D-SACCHARIDE 1,4 AND 1,4 LINKING","D-SACCHARIDE 1,4 AND 1,6 LINKING","L-SACCHARIDE","L-SACCHARIDE 1,4 AND 1,4 LINKING","L-SACCHARIDE 1,4 AND 1,6 LINKING","SACCHARIDE"],jn=["NON-POLYMER"].concat(["OTHER"],Vn),Gn=["h","g","i"],Hn=["e","b"],qn=["s","t","l",""],Wn={H:1,D:1,T:1,HE:2,LI:3,BE:4,B:5,C:6,N:7,O:8,F:9,NE:10,NA:11,MG:12,AL:13,SI:14,P:15,S:16,CL:17,AR:18,K:19,CA:20,SC:21,TI:22,V:23,CR:24,MN:25,FE:26,CO:27,NI:28,CU:29,ZN:30,GA:31,GE:32,AS:33,SE:34,BR:35,KR:36,RB:37,SR:38,Y:39,ZR:40,NB:41,MO:42,TC:43,RU:44,RH:45,PD:46,AG:47,CD:48,IN:49,SN:50,SB:51,TE:52,I:53,XE:54,CS:55,BA:56,LA:57,CE:58,PR:59,ND:60,PM:61,SM:62,EU:63,GD:64,TB:65,DY:66,HO:67,ER:68,TM:69,YB:70,LU:71,HF:72,TA:73,W:74,RE:75,OS:76,IR:77,PT:78,AU:79,HG:80,TL:81,PB:82,BI:83,PO:84,AT:85,RN:86,FR:87,RA:88,AC:89,TH:90,PA:91,U:92,NP:93,PU:94,AM:95,CM:96,BK:97,CF:98,ES:99,FM:100,MD:101,NO:102,LR:103,RF:104,DB:105,SG:106,BH:107,HS:108,MT:109,DS:110,RG:111,CN:112,NH:113,FL:114,MC:115,LV:116,TS:117,OG:118},Xn={1:1.1,2:1.4,3:1.81,4:1.53,5:1.92,6:1.7,7:1.55,8:1.52,9:1.47,10:1.54,11:2.27,12:1.73,13:1.84,14:2.1,15:1.8,16:1.8,17:1.75,18:1.88,19:2.75,20:2.31,21:2.3,22:2.15,23:2.05,24:2.05,25:2.05,26:2.05,27:2,28:2,29:2,30:2.1,31:1.87,32:2.11,33:1.85,34:1.9,35:1.83,36:2.02,37:3.03,38:2.49,39:2.4,40:2.3,41:2.15,42:2.1,43:2.05,44:2.05,45:2,46:2.05,47:2.1,48:2.2,49:2.2,50:1.93,51:2.17,52:2.06,53:1.98,54:2.16,55:3.43,56:2.68,57:2.5,58:2.48,59:2.47,60:2.45,61:2.43,62:2.42,63:2.4,64:2.38,65:2.37,66:2.35,67:2.33,68:2.32,69:2.3,70:2.28,71:2.27,72:2.25,73:2.2,74:2.1,75:2.05,76:2,77:2,78:2.05,79:2.1,80:2.05,81:1.96,82:2.02,83:2.07,84:1.97,85:2.02,86:2.2,87:3.48,88:2.83,89:2,90:2.4,91:2,92:2.3,93:2,94:2,95:2,96:2,97:2,98:2,99:2,100:2,101:2,102:2,103:2,104:2,105:2,106:2,107:2,108:2,109:2,110:2,111:2,112:2,113:2,114:2,115:2,116:2,117:2,118:2},Yn={1:.31,2:.28,3:1.28,4:.96,5:.84,6:.76,7:.71,8:.66,9:.57,10:.58,11:1.66,12:1.41,13:1.21,14:1.11,15:1.07,16:1.05,17:1.02,18:1.06,19:2.03,20:1.76,21:1.7,22:1.6,23:1.53,24:1.39,25:1.39,26:1.32,27:1.26,28:1.24,29:1.32,30:1.22,31:1.22,32:1.2,33:1.19,34:1.2,35:1.2,36:1.16,37:2.2,38:1.95,39:1.9,40:1.75,41:1.64,42:1.54,43:1.47,44:1.46,45:1.42,46:1.39,47:1.45,48:1.44,49:1.42,50:1.39,51:1.39,52:1.38,53:1.39,54:1.4,55:2.44,56:2.15,57:2.07,58:2.04,59:2.03,60:2.01,61:1.99,62:1.98,63:1.98,64:1.96,65:1.94,66:1.92,67:1.92,68:1.89,69:1.9,70:1.87,71:1.87,72:1.75,73:1.7,74:1.62,75:1.51,76:1.44,77:1.41,78:1.36,79:1.36,80:1.32,81:1.45,82:1.46,83:1.48,84:1.4,85:1.5,86:1.5,87:2.6,88:2.21,89:2.15,90:2.06,91:2,92:1.96,93:1.9,94:1.87,95:1.8,96:1.69,97:1.6,98:1.6,99:1.6,100:1.6,101:1.6,102:1.6,103:1.6,104:1.6,105:1.6,106:1.6,107:1.6,108:1.6,109:1.6,110:1.6,111:1.6,112:1.6,113:1.6,114:1.6,115:1.6,116:1.6,117:1.6,118:1.6},Kn={1:[1],2:[0],3:[1],4:[2],5:[3],6:[4],7:[3],8:[2],9:[1],10:[0],11:[1],12:[2],13:[6],14:[6],15:[3,5,7],16:[2,4,6],17:[1],18:[0],19:[1],20:[2],31:[3],32:[4],33:[3,5],34:[2,4,6],35:[1],36:[0],37:[1],38:[2],49:[3],50:[4],51:[3,5],52:[2],53:[1,2,5],54:[0,2],55:[1],56:[2],81:[3],82:[4],83:[3],84:[2],85:[1],86:[0],87:[1],88:[2]},Zn={1:1,2:2,3:1,4:2,5:3,6:4,7:5,8:6,9:7,10:8,11:1,12:2,13:3,14:4,15:5,16:6,17:7,18:8,19:1,20:2,21:3,22:4,23:5,24:6,25:7,26:8,27:9,28:10,29:11,30:2,31:3,32:4,33:5,34:6,35:7,36:8,37:1,38:2,39:3,40:4,41:5,42:6,43:7,44:8,45:9,46:10,47:11,48:2,49:3,50:4,51:5,52:6,53:7,54:8,55:1,56:2,57:3,58:4,59:3,60:4,61:5,62:6,63:7,64:8,65:9,66:10,67:11,68:12,69:13,70:14,71:15,72:4,73:5,74:6,75:7,76:8,77:9,78:10,79:11,80:2,81:3,82:4,83:5,84:6,85:7,86:8,87:1,88:2,89:3,90:4,91:3,92:4,93:5,94:6,95:7,96:8,97:9,98:10,99:11,100:12,101:13,102:14,103:15,104:2,105:2,106:2,107:2,108:2,109:2,110:2,111:2,112:2,113:3,114:4,115:5,116:6,117:7,118:8},Qn={ALA:[.17,.5,.33],ARG:[.81,1.81,1],ASN:[.42,.85,.43],ASP:[1.23,3.64,2.41],ASH:[-.07,.43,.5],CYS:[-.24,-.02,.22],GLN:[.58,.77,.19],GLU:[2.02,3.63,1.61],GLH:[-.01,.11,.12],GLY:[.01,1.15,1.14],HIS:[.17,.11,-.06],ILE:[-.31,-1.12,-.81],LEU:[-.56,-1.25,-.69],LYS:[.99,2.8,1.81],MET:[-.23,-.67,-.44],PHE:[-1.13,-1.71,-.58],PRO:[.45,.14,-.31],SER:[.13,.46,.33],THR:[.14,.25,.11],TRP:[-1.85,-2.09,-.24],TYR:[-.94,-.71,.23],VAL:[.07,-.46,-.53]},Jn=[0,0,0],ts={HIS:"H",ARG:"R",LYS:"K",ILE:"I",PHE:"F",LEU:"L",TRP:"W",ALA:"A",MET:"M",PRO:"P",CYS:"C",ASN:"N",VAL:"V",GLY:"G",SER:"S",GLN:"Q",TYR:"Y",ASP:"D",GLU:"E",THR:"T",SEC:"U",PYL:"O"},es=Object.keys(ts),is=["A","C","T","G","U","I"],rs=["DA","DC","DT","DG","DU","DI"],ns=["A","G","I","DA","DG","DI"],ss=is.concat(rs),os=["SOL","WAT","HOH","H2O","W","DOD","D3O","TIP3","TIP4","SPC"],as=["118","119","1AL","1CU","2FK","2HP","2OF","3CO","3MT","3NI","3OF","3P8","4MO","4PU","543","6MO","ACT","AG","AL","ALF","AM","ATH","AU","AU3","AUC","AZI","BA","BCT","BEF","BF4","BO4","BR","BS3","BSY","CA","CAC","CD","CD1","CD3","CD5","CE","CHT","CL","CO","CO3","CO5","CON","CR","CS","CSB","CU","CU1","CU3","CUA","CUZ","CYN","DME","DMI","DSC","DTI","DY","E4N","EDR","EMC","ER3","EU","EU3","F","FE","FE2","FPO","GA","GD3","GEP","HAI","HG","HGC","IN","IOD","IR","IR3","IRI","IUM","K","KO4","LA","LCO","LCP","LI","LU","MAC","MG","MH2","MH3","MLI","MLT","MMC","MN","MN3","MN5","MN6","MO1","MO2","MO3","MO4","MO5","MO6","MOO","MOS","MOW","MW1","MW2","MW3","NA","NA2","NA5","NA6","NAO","NAW","NCO","NET","NH4","NI","NI1","NI2","NI3","NO2","NO3","NRU","O4M","OAA","OC1","OC2","OC3","OC4","OC5","OC6","OC7","OC8","OCL","OCM","OCN","OCO","OF1","OF2","OF3","OH","OS","OS4","OXL","PB","PBM","PD","PDV","PER","PI","PO3","PO4","PR","PT","PT4","PTN","RB","RH3","RHD","RU","SB","SCN","SE4","SEK","SM","SMO","SO3","SO4","SR","T1A","TB","TBA","TCN","TEA","TH","THE","TL","TMA","TRA","UNX","V","VN3","VO4","W","WO5","Y1","YB","YB2","YH","YT3","ZCM","ZN","ZN2","ZN3","ZNO","ZO3","OHX"],cs=["045","0AT","0BD","0MK","0NZ","0TS","0V4","0XY","0YT","10M","147","149","14T","15L","16G","18T","18Y","1AR","1BW","1GL","1GN","1JB","1LL","1NA","1S3","26M","26Q","26R","26V","26W","26Y","27C","289","291","293","2DG","2F8","2FG","2FL","2FP","2GL","2M4","2M5","32O","34V","3CM","3DO","3DY","3FM","3LR","3MF","3MG","3SA","3ZW","46D","46M","46Z","48Z","4CQ","4GC","4NN","50A","5DI","5GF","5MM","5RP","5SA","5SP","64K","6PG","6SA","7JZ","7SA","A1Q","A2G","AAB","AAL","AAO","ABC","ABD","ABE","ABF","ABL","ACG","ACI","ACR","ACX","ADA","ADG","ADR","AF1","AFD","AFL","AFO","AFP","AFR","AGC","AGH","AGL","AHR","AIG","ALL","ALX","AMU","AOG","AOS","ARA","ARB","ARE","ARI","ASG","ASO","AXP","AXR","B0D","B16","B2G","B4G","B6D","B8D","B9D","BBK","BCD","BDG","BDP","BDR","BEM","BFP","BGC","BGL","BGP","BGS","BHG","BMA","BMX","BNG","BNX","BOG","BRI","BXF","BXP","BXX","BXY","C3X","C4X","C5X","CAP","CBI","CBK","CBS","CDR","CEG","CGF","CHO","CR1","CR6","CRA","CT3","CTO","CTR","CTT","D6G","DAF","DAG","DDA","DDB","DDL","DEL","DFR","DFX","DG0","DGC","DGD","DGM","DGS","DIG","DLF","DLG","DMU","DNO","DOM","DP5","DQQ","DQR","DR2","DR3","DR4","DRI","DSR","DT6","DVC","E4P","E5G","EAG","EBG","EBQ","EGA","EJT","EPG","ERE","ERI","F1P","F1X","F6P","FBP","FCA","FCB","FCT","FDP","FDQ","FFC","FIX","FMO","FRU","FSI","FU4","FUB","FUC","FUD","FUL","FXP","G16","G1P","G2F","G3I","G4D","G4S","G6D","G6P","G6S","GAC","GAD","GAL","GC1","GC4","GCD","GCN","GCO","GCS","GCT","GCU","GCV","GCW","GCX","GE1","GFG","GFP","GIV","GL0","GL2","GL5","GL6","GL7","GL9","GLA","GLB","GLC","GLD","GLF","GLG","GLO","GLP","GLS","GLT","GLW","GMH","GN1","GNX","GP1","GP4","GPH","GPM","GQ1","GQ2","GQ4","GS1","GS4","GSA","GSD","GTE","GTH","GTK","GTR","GTZ","GU0","GU1","GU2","GU3","GU4","GU5","GU6","GU8","GU9","GUF","GUP","GUZ","GYP","GYV","H2P","HDL","HMS","HS2","HSD","HSG","HSH","HSJ","HSQ","HSR","HSU","HSX","HSY","HSZ","IAB","IDG","IDR","IDS","IDT","IDU","IDX","IDY","IMK","IN1","IPT","ISL","KBG","KD2","KDA","KDM","KDO","KFN","KO1","KO2","KTU","L6S","LAG","LAI","LAK","LAO","LAT","LB2","LBT","LCN","LDY","LGC","LGU","LM2","LMT","LMU","LOG","LOX","LPK","LSM","LTM","LVZ","LXB","LXZ","M1F","M3M","M6P","M8C","MA1","MA2","MA3","MAB","MAG","MAL","MAN","MAT","MAV","MAW","MBG","MCU","MDA","MDM","MDP","MFA","MFB","MFU","MG5","MGA","MGL","MLB","MMA","MMN","MN0","MRP","MTT","MUG","MVP","MXY","N1L","N9S","NAA","NAG","NBG","NDG","NED","NG1","NG6","NGA","NGB","NGC","NGE","NGF","NGL","NGS","NGY","NHF","NM6","NM9","NTF","NTO","NTP","NXD","NYT","OPG","OPM","ORP","OX2","P3M","P53","P6P","PA5","PNA","PNG","PNW","PRP","PSJ","PSV","PTQ","QDK","QPS","QV4","R1P","R1X","R2B","R5P","RAA","RAE","RAF","RAM","RAO","RAT","RB5","RBL","RCD","RDP","REL","RER","RF5","RG1","RGG","RHA","RIB","RIP","RNS","RNT","ROB","ROR","RPA","RST","RUB","RUU","RZM","S6P","S7P","SA0","SCR","SDD","SF6","SF9","SG4","SG5","SG6","SG7","SGA","SGC","SGD","SGN","SGS","SHB","SHG","SI3","SIO","SOE","SOL","SSG","SUC","SUP","SUS","T6P","T6T","TAG","TCB","TDG","TGK","TGY","TH1","TIA","TM5","TM6","TM9","TMR","TMX","TOA","TOC","TRE","TYV","UCD","UDC","VG1","X0X","X1X","X2F","X4S","X5S","X6X","XBP","XDN","XDP","XIF","XIM","XLF","XLS","XMM","XUL","XXR","XYP","XYS","YO5","Z3Q","Z6J","Z9M","ZDC","ZDM"],ls=["CA","C","N","O","O1","O2","OC1","OC2","OX1","OXT","OT1","OT2","H","H1","H2","H3","HA","HN","BB"],hs=["P","OP1","OP2","HOP2","HOP3","O2'","O3'","O4'","O5'","C1'","C2'","C3'","C4'","C5'","H1'","H2'","H2''","HO2'","H3'","H4'","H5'","H5''","HO3'","HO5'","O2*","O3*","O4*","O5*","C1*","C2*","C3*","C4*","C5*"],us={1:{trace:"CA",direction1:"C",direction2:["O","OC1","O1","OX1","OXT","OT1","OT2"],backboneStart:"N",backboneEnd:"C"},2:{trace:["C4'","C4*"],direction1:["C1'","C1*"],direction2:["C3'","C3*"],backboneStart:"P",backboneEnd:["O3'","O3*"]},3:{trace:["C3'","C3*"],direction1:["C2'","C2*"],direction2:["O4'","O4*"],backboneStart:"P",backboneEnd:["O3'","O3*"]},4:{trace:["CA","BB"],backboneStart:["CA","BB"],backboneEnd:["CA","BB"]},5:{trace:["C4'","C4*","P"],backboneStart:["C4'","C4*","P"],backboneEnd:["C4'","C4*","P"]},6:{trace:["C3'","C3*","C2'","P"],backboneStart:["C3'","C3*","C2'","P"],backboneEnd:["C3'","C3*","C2'","P"]}};us[Ln]={};const ds={HD:"H",HS:"H",A:"C",NA:"N",NS:"N",OA:"O",OS:"O",SA:"S",G0:"C",G1:"C",G2:"C",G3:"C",CG0:"C",CG1:"C",CG2:"C",CG3:"C",W:"O"};function ms(t){switch(t){case 0:return 0;case 1:return 1;case 2:return 2;case 3:return 3;case 4:return 4;default:return 8}}const fs=new Map([[2,Pt(180)],[3,Pt(120)],[4,Pt(109.4721)],[6,Pt(90)]]);function ps(t,i){let r=[];const n=new e,s=new e;return n.subVectors(i,t),t.eachBondedAtom((e=>{1!==e.number&&(s.subVectors(e,t),r.push(n.angleTo(s)))})),r}function gs(t,i){const r=t.clone(),n=new e;n.subVectors(i,t);const s=[new e,new e];let o=0;if(t.eachBondedAtom((e=>{o>1||1!==e.number&&(r.index=e.index,s[o++].subVectors(e,t))})),1===o&&r.eachBondedAtom((e=>{o>1||1!==e.number&&e.index!==t.index&&s[o++].subVectors(e,t)})),2!==o)return;const a=s[0].cross(s[1]);return Math.abs(Math.PI/2-a.angleTo(n))}function ys(t,e){const i=t.structure,r=i.atomCount,n=new Int8Array(r),s=new Int8Array(r),o=new Int8Array(r),a=new Int8Array(r);return i.eachAtom((t=>{const i=t.index,[r,c,l,h]=function(t,e){const i=t.bondToElementCount(1);let r=t.formalCharge||0;const n="always"===e.assignCharge||"auto"===e.assignCharge&&0===r,s="always"===e.assignH||"auto"===e.assignH&&0===i,o=t.bondCount,a=function(t){let e=0;return t.eachBond((t=>e+=t.bondOrder)),e}(t),c=function(t){const e=t.structure.getBondProxy(),i=t.number,r=8===i||7===i;if(r&&4===t.bondCount)return!1;let n=!1;return t.eachBond((i=>{if(i.bondOrder>1)n=!0;else if(r){const r=i.getOtherAtom(t);r.eachBond((t=>{if(t.bondOrder>1){const e=r.number;if((15===e||16===e)&&8===t.getOtherAtom(r).number)return;n=!0}}),e)}})),n}(t),l=a-o>0;let h=0,u=8;switch(t.number){case 1:n&&(0===o?(r=1,u=0):1===o&&(r=0,u=1));break;case 6:n&&(r=0),s&&(h=Math.max(0,4-a-Math.abs(r))),u=ms(o+h+Math.max(0,-r));break;case 7:if(n)if(s)if(c&&a<4)r=o-i==1&&a-i==2?1:0;else{let e=!1;t.eachBondedAtom((t=>{(16===t.number||t.isMetal())&&(e=!0)})),r=e?0:1}else r=a-3;s&&(h=Math.max(0,3-a+r)),u=ms(c&&!l?o+h-r:o+h+1-r);break;case 8:n&&(s||(r=a-2),1===a&&t.eachBondedAtom((e=>{e.eachBond((i=>{const n=i.getOtherAtom(e);n.index!==t.index&&8===n.number&&2===i.bondOrder&&(r=-1)}))}))),s&&(h=Math.max(0,2-a+r)),u=ms(c&&!l?o+h-r+1:o+h-r+2);break;case 16:n&&(s||(r=a<=3&&!t.bondToElementCount(8)?a-2:0)),s&&a<2&&(h=Math.max(0,2-a+r)),a<=3&&(u=ms(o+h-r+2));break;case 9:case 17:case 35:case 53:case 85:n&&(r=a-1);break;case 3:case 11:case 19:case 37:case 55:case 87:n&&(r=1-a);break;case 4:case 12:case 20:case 38:case 56:case 88:n&&(r=2-a);break;default:console.warn("Requested charge, protonation for an unhandled element",t.element)}return[r,h,h+i,u]}(t,e);n[i]=r,s[i]=c,o[i]=l,a[i]=h})),{charge:n,implicitH:s,totalH:o,idealGeometry:a}}function bs(t){if(t["@valenceModel"])return t["@valenceModel"];const e=ys(t,{assignCharge:"auto",assignH:"auto"});return t["@valenceModel"]=e,e}function _s(t){return 15===t.number&&t.bondToElementCount(8)===t.bondCount}const xs=["ARG","HIS","LYS"],vs=["GLU","ASP"];function ws(t,e){return 2===t&&1===e||1===t&&2===e}function As(t,e){return 3===t&&3===e}function Ss(t,e){return 3===t&&1===e||1===t&&3===e}function Cs(t){return"HIS"===t.resname&&7==t.number&&t.isRing()}function Ps(t,e){return 5===t&&4===e||4===t&&5===e}function Is(t,e){return 9===t&&5===e||5===t&&9===e}const ks=[3,11,19,37,55,12,20,38,56,13,31,49,81,21,50,82,83,51,80];function Ms(t,e){return 12===t?11===e||12===e:13===t?10===e:void 0}const Ts=[17,35,53,85];const Ds=[7,8,16],Bs=[6,7,15,16];const Fs=Pt(180),Es=Pt(120);function $s(t,e,i){return!Rs(t,e,i)&&(t.modelIndex!==e.modelIndex||t.altloc&&e.altloc&&t.altloc!==e.altloc)}const Os={maxHydrophobicDist:4,maxHbondDist:3.5,maxHbondSulfurDist:4.1,maxHbondAccAngle:45,maxHbondDonAngle:45,maxHbondAccPlaneAngle:90,maxHbondDonPlaneAngle:30,maxPiStackingDist:5.5,maxPiStackingOffset:2,maxPiStackingAngle:30,maxCationPiDist:6,maxCationPiOffset:2,maxIonicDist:5,maxHalogenBondDist:4,maxHalogenBondAngle:30,maxMetalDist:3,refineSaltBridges:!0,masterModelIndex:-1,lineOfSightDistFactor:1};function Rs(t,e,i){return t.modelIndex===i&&e.modelIndex!==i||e.modelIndex===i&&t.modelIndex!==i}function Ls(t,e,i){return!Rs(t,e,i)&&(t.modelIndex!==e.modelIndex||t.residueIndex===e.residueIndex||t.altloc&&e.altloc&&t.altloc!==e.altloc)}function Ns(t){const e={types:[],groups:[],centers:{x:[],y:[],z:[]},atomSets:[]};return Te&&Ie.time("calculateFeatures"),function(t,e){const{charge:i}=bs(t.data),r={};t.eachResidue((t=>{if(xs.includes(t.resname)){const i=$n(1);t.eachAtom((t=>{7===t.number&&t.isSidechain()&&On(i,t)})),Rn(e,i)}else es.includes(t.resname)||t.isNucleic()||(t.eachAtom((t=>{let i=!1;const n=$n(1);!function(t){let e=0;return 6===t.number&&3===t.bondCount&&3===t.bondToElementCount(7)&&t.eachBondedAtom((t=>{t.bondCount-t.bondToElementCount(1)==1&&++e})),2===e}(t)?function(t){let e=0;return 6===t.number&&3===t.bondCount&&2===t.bondToElementCount(7)&&1===t.bondToElementCount(6)&&t.eachBondedAtom((t=>{t.bondCount-t.bondToElementCount(1)==1&&++e})),2===e}(t)&&(n.group=9,i=!0):(n.group=8,i=!0),i&&(t.eachBondedAtom((t=>{7===t.number&&(r[t.index]=!0,On(n,t))})),Rn(e,n))})),t.eachAtom((t=>{const n=$n(1);i[t.index]>0&&(r[t.index]||(On(n,t),Rn(e,n)))})))}))}(t,e),function(t,e){const{charge:i}=bs(t.data),r={};t.eachResidue((t=>{if(vs.includes(t.resname)){const i=$n(2);t.eachAtom((t=>{8===t.number&&t.isSidechain()&&On(i,t)})),Rn(e,i)}else if(ss.includes(t.resname)){const i=$n(2);t.eachAtom((t=>{_s(t)&&(i.group=6,t.eachBondedAtom((t=>{8===t.number&&On(i,t)})),Rn(e,i))}))}else es.includes(t.resname)||ss.includes(t.resname)||(t.eachAtom((t=>{let i=!1;const n=$n(2);!function(t){return 16===t.number&&3===t.bondToElementCount(8)}(t)?_s(t)?(n.group=6,i=!0):function(t){return 16===t.number&&4===t.bondToElementCount(8)}(t)?(n.group=5,i=!0):function(t){let e=0;return 6===t.number&&2===t.bondToElementCount(8)&&1===t.bondToElementCount(6)&&t.eachBondedAtom((t=>{8===t.number&&t.bondCount-t.bondToElementCount(1)==1&&++e})),2===e}(t)&&(n.group=10,i=!0):(n.group=4,i=!0),i&&(t.eachBondedAtom((t=>{8===t.number&&(r[t.index]=!0,On(n,t))})),Rn(e,n))})),t.eachAtom((t=>{const n=$n(2);i[t.index]<0&&(r[t.index]||(On(n,t),Rn(e,n)))})))}))}(t,e),function(t,e){const i=t.getAtomProxy();t.eachResidue((t=>{const r=t.getAromaticRings();if(r){const n=t.atomOffset;r.forEach((t=>{const r=$n(3);t.forEach((t=>{i.index=t+n,On(r,i)})),Rn(e,r)}))}}))}(t,e),function(t,e){const{charge:i,implicitH:r,idealGeometry:n}=bs(t.data);t.eachAtom((t=>{const s=$n(5),o=t.number;if(8===o)On(s,t),Rn(e,s);else if(7===o){if(Cs(t))On(s,t),Rn(e,s);else if(i[t.index]<1){const i=t.bondCount+r[t.index],o=n[t.index];(4===o&&i<4||3===o&&i<3||2===o&&i<2)&&(On(s,t),Rn(e,s))}}else 16===o&&("CYS"!==t.resname&&"MET"!==t.resname&&-1!==t.formalCharge||(On(s,t),Rn(e,s)))}))}(t,e),function(t,e){const{totalH:i}=bs(t.data);t.eachAtom((t=>{const r=$n(4),n=t.number;(Cs(t)||i[t.index]>0&&(7===n||8===n||16===n))&&(On(r,t),Rn(e,r))}))}(t,e),function(t,e){const{totalH:i}=bs(t.data);t.eachAtom((t=>{if(6===t.number&&i[t.index]>0&&(t.bondToElementCount(7)>0||t.bondToElementCount(8)>0||function(t){if(!t.isAromatic())return!1;const e=t.residueType.getRings();if(!e)return!1;let i=!1;return e.rings.forEach((e=>{i||e.some((e=>t.index-t.residueAtomOffset===e))&&(i=e.some((e=>{const i=t.residueType.atomTypeIdList[e],r=t.atomMap.get(i).number;return 7===r||8===r})))})),i}(t))){const i=$n(9);On(i,t),Rn(e,i)}}))}(t,e),function(t,e){t.eachAtom((t=>{let i=!1,r=!1;const n=es.includes(t.resname),s=ss.includes(t.resname);if(n||s?n?8===t.number?(["ASP","GLU","SER","THR","TYR","ASN","GLN"].includes(t.resname)&&t.isSidechain()||t.isBackbone())&&(i=!0,r=!0):16===t.number&&"CYS"===t.resname?(i=!0,r=!0):7===t.number&&"HIS"===t.resname&&t.isSidechain()&&(i=!0):s&&(8===t.number&&t.isBackbone()?(i=!0,r=!0):["N3","N4","N7"].includes(t.atomname)?i=!0:["O2","O4","O6"].includes(t.atomname)&&(i=!0,r=!0)):t.isHalogen()||8===t.number||16===t.number?(i=!0,r=!0):7===t.number&&(i=!0),i){const i=$n(11);On(i,t),Rn(e,i)}if(r){const i=$n(10);On(i,t),Rn(e,i)}}))}(t,e),function(t,e){t.eachAtom((t=>{if(t.isTransitionMetal()||30===t.number||48===t.number){const i=$n(12);On(i,t),Rn(e,i)}else if(ks.includes(t.number)){const i=$n(13);On(i,t),Rn(e,i)}}))}(t,e),function(t,e){t.eachAtom((t=>{const i=$n(8);let r=!1;6===t.number?(r=!0,t.eachBondedAtom((t=>{const e=t.number;6!==e&&1!==e&&(r=!1)}))):9===t.number&&(r=!0),r&&(On(i,t),Rn(e,i))}))}(t,e),function(t,e){t.eachAtom((t=>{if(Ds.includes(t.number)){let i=!1;if(t.eachBondedAtom((t=>{Bs.includes(t.number)&&(i=!0)})),i){const i=$n(7);On(i,t),Rn(e,i)}}}))}(t,e),function(t,e){t.eachAtom((t=>{if(Ts.includes(t.number)&&1===t.bondToElementCount(6)){const i=$n(6);On(i,t),Rn(e,i)}}))}(t,e),Te&&Ie.timeEnd("calculateFeatures"),e}function zs(t,i=Os){const r=function(t){const{types:e,centers:i}=t;return{features:t,spatialHash:new Mn(i),contactStore:new Dn,featureSet:new Fn(e.length,!1)}}(Ns(t));Te&&Ie.time("calculateContacts"),function(t,i,r={}){const n=rt(r.maxIonicDist,Os.maxIonicDist),s=rt(r.maxPiStackingDist,Os.maxPiStackingDist),o=rt(r.maxPiStackingOffset,Os.maxPiStackingOffset),a=rt(r.maxPiStackingAngle,Os.maxPiStackingAngle),c=rt(r.maxCationPiDist,Os.maxCationPiDist),l=rt(r.maxCationPiOffset,Os.maxCationPiOffset),h=rt(r.masterModelIndex,Os.masterModelIndex),u=Math.max(n+2,s,c),d=s*s,m=c*c,{features:f,spatialHash:p,contactStore:g,featureSet:y}=i,{types:b,centers:_,atomSets:x}=f,{x:v,y:w,z:A}=_,S=b.length,C=t.atomStore.x,P=t.atomStore.y,I=t.atomStore.z,k=t.getAtomProxy(),M=t.getAtomProxy(),T=function(t,e,i){const r=t.length,n=e.length;for(let s=0;s{if(e<=t)return;if(k.index=x[t][0],M.index=x[e][0],Ls(k,M,h))return;const r=b[t],s=b[e];if(ws(r,s))T(x[t],x[e],n)&&z(t,e,1);else if(As(r,s)){if(i<=d){L(x[t],O),L(x[e],R);const i=57.29578*O.angleTo(R);Math.min(N(t,e,R),N(e,t,O))<=o&&(i<=a||i>=180-a||i<=a+90&&i>=90-a)&&z(t,e,3)}}else if(Ss(r,s)&&i<=m){const[i,n]=3===r?[t,e]:[e,t];L(x[i],O),N(n,i,O)<=l&&z(i,n,2)}}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxHbondDist,Os.maxHbondDist),n=rt(i.maxHbondSulfurDist,Os.maxHbondSulfurDist),s=Pt(rt(i.maxHbondAccAngle,Os.maxHbondAccAngle)),o=Pt(rt(i.maxHbondDonAngle,Os.maxHbondDonAngle)),a=Pt(rt(i.maxHbondAccPlaneAngle,Os.maxHbondAccPlaneAngle)),c=Pt(rt(i.maxHbondDonPlaneAngle,Os.maxHbondDonPlaneAngle)),l=rt(i.masterModelIndex,Os.masterModelIndex),h=Math.max(r,n),u=r*r,{features:d,spatialHash:m,contactStore:f,featureSet:p}=e,{types:g,centers:y,atomSets:b}=d,{x:_,y:x,z:v}=y,w=g.length,{idealGeometry:A}=bs(t.data),S=t.getAtomProxy(),C=t.getAtomProxy();for(let t=0;t{if(e<=t)return;const r=g[t],n=g[e],h=Is(r,n);if(!h&&!Ps(r,n))return;const[d,m]=5===n?[t,e]:[e,t];if(S.index=b[d][0],C.index=b[m][0],C.index===S.index)return;if(Ls(S,C,l))return;if(16!==S.number&&16!==C.number&&i>u)return;if(S.connectedTo(C))return;const y=ps(S,C),_=fs.get(A[S.index])||Pt(120);if(y.some((t=>Math.abs(_-t)>o)))return;if(3===A[S.index]){const t=gs(S,C);if(void 0!==t&&t>c)return}const x=ps(C,S),v=fs.get(A[C.index])||Pt(120);if(x.some((t=>v-t>s)))return;if(3===A[C.index]){const t=gs(C,S);if(void 0!==t&&t>a)return}p.setBits(d,m);const w=h?8:function(t,e){return t.isWater()&&e.isWater()}(P=S,I=C)?9:function(t,e){return t.isBackbone()&&e.isBackbone()}(P,I)?10:4;var P,I;f.addContact(d,m,w)}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxMetalDist,Os.maxMetalDist),n=rt(i.masterModelIndex,Os.masterModelIndex),{features:s,spatialHash:o,contactStore:a,featureSet:c}=e,{types:l,centers:h,atomSets:u}=s,{x:d,y:m,z:f}=h,p=l.length,g=t.getAtomProxy(),y=t.getAtomProxy();for(let t=0;t{if(e<=t)return;if(g.index=u[t][0],y.index=u[e][0],Ls(g,y,n))return;const r=g.isMetal(),s=y.isMetal();if(!r&&!s)return;const[o,h]=r?[l[t],l[e]]:[l[e],l[t]];Ms(o,h)&&(c.setBits(t,e),a.addContact(t,e,7))}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxHydrophobicDist,Os.maxHydrophobicDist),n=rt(i.masterModelIndex,Os.masterModelIndex),{features:s,spatialHash:o,contactStore:a,featureSet:c}=e,{types:l,centers:h,atomSets:u}=s,{x:d,y:m,z:f}=h,p=l.length,g=t.getAtomProxy(),y=t.getAtomProxy();for(let t=0;t{var r,s;e<=t||(g.index=u[t][0],y.index=u[e][0],Ls(g,y,n)||9===g.number&&9===y.number||g.connectedTo(y)||(r=l[t],s=l[e],8===r&&8===s&&(c.setBits(t,e),a.addContact(t,e,6))))}))}(t,r,i),function(t,e,i={}){const r=rt(i.maxHalogenBondDist,Os.maxHalogenBondDist),n=Pt(rt(i.maxHalogenBondAngle,Os.maxHalogenBondAngle)),s=rt(i.masterModelIndex,Os.masterModelIndex),{features:o,spatialHash:a,contactStore:c,featureSet:l}=e,{types:h,centers:u,atomSets:d}=o,{x:m,y:f,z:p}=u,g=h.length,y=t.getAtomProxy(),b=t.getAtomProxy();for(let t=0;t{if(e<=t)return;if(y.index=d[t][0],b.index=d[e][0],Ls(y,b,s))return;if(r=h[t],o=h[e],!(7===r&&6===o||6===r&&7===o))return;var r,o;const[a,u]=6===h[t]?[y,b]:[b,y],m=ps(a,u);if(1!==m.length)return;if(Fs-m[0]>n)return;const f=ps(u,a);0!==f.length&&(f.some((t=>Es-t>n))||(l.setBits(t,e),c.addContact(t,e,5)))}))}(t,r,i);const n=function(t){const{index1:e,index2:i,count:r}=t.contactStore,n=En({nodeArray1:e,nodeArray2:i,edgeCount:r,nodeCount:t.featureSet.length}),s=new Fn(t.contactStore.count,!0);return Object.assign({adjacencyList:n,contactSet:s},t)}(r);return function(t,i,r={}){Te&&Ie.time("refineLineOfSight");const n=rt(r.lineOfSightDistFactor,Os.lineOfSightDistFactor),s=rt(r.masterModelIndex,Os.masterModelIndex),o=t.spatialHash,{contactSet:a,contactStore:c,features:l}=i,{index1:h,index2:u}=c,{centers:d,atomSets:m}=l,{x:f,y:p,z:g}=d,y=t.getAtomProxy(),b=t.getAtomProxy(),_=t.getAtomProxy(),x=new e,v=new e,w=3*n,A=n*n;a.forEach((t=>{x.set(f[h[t]],p[h[t]],g[h[t]]),v.set(f[u[t]],p[u[t]],g[u[t]]);const e=(x.x+v.x)/2,i=(x.y+v.y)/2,r=(x.z+v.z)/2,n=m[h[t]],c=m[u[t]];y.index=n[0],b.index=c[0],o.eachWithin(e,i,r,w,((e,i)=>{_.index=e,1!==_.number&&_.vdw*_.vdw*A>i&&!$s(y,_,s)&&!$s(b,_,s)&&!n.includes(e)&&!c.includes(e)&&x.distanceToSquared(_)>1&&v.distanceToSquared(_)>1&&(a.clear(t),Te&&Ie.log("removing",y.qualifiedName(),b.qualifiedName(),"because",_.qualifiedName()))}))})),Te&&Ie.timeEnd("refineLineOfSight")}(t,n,i),function(t,e){const{contactSet:i,contactStore:r,features:n}=e,{type:s,index1:o,index2:a}=r,{atomSets:c}=n,l=t.getAtomProxy(),h=t.getAtomProxy(),u={},d=function(t,e,r){const[n,s]=u[r]||[1/0,-1];t{if(6!==s[t])return;l.index=c[o[t]][0],h.index=c[a[t]][0];const e=l.distanceTo(h);d(e,t,`${l.index}|${h.residueIndex}`),d(e,t,`${h.index}|${l.residueIndex}`)}))}(t,n),i.refineSaltBridges&&function(t,e){const{contactSet:i,contactStore:r,features:n}=e,{type:s,index1:o,index2:a}=r,{atomSets:c}=n,l={},h=function(t,e){l[t]||(l[t]=[]),l[t].push(e)};i.forEach((t=>{1===s[t]&&(c[o[t]].forEach((e=>h(e,t))),c[a[t]].forEach((e=>h(e,t))))})),i.forEach((t=>{if(!function(t){return 4===t||9===t||10===t}(s[t]))return;const e=l[c[o[t]][0]],r=l[c[a[t]][0]];if(!e||!r)return;const n=e.length;for(let s=0;s{3===s[t]&&(c[o[t]].forEach((e=>h(e,t))),c[a[t]].forEach((e=>h(e,t))))})),i.forEach((t=>{if(6!==s[t]&&2!==s[t])return;const e=l[c[o[t]][0]],r=l[c[a[t]][0]];if(!e||!r)return;const n=e.length;for(let s=0;s{1===s[t]&&(c[o[t]].forEach((e=>h(e,t))),c[a[t]].forEach((e=>h(e,t))))})),i.forEach((t=>{if(7!==s[t])return;const e=l[c[o[t]][0]],r=l[c[a[t]][0]];if(!e||!r)return;const n=e.length;for(let t=0;te.getAtomSet(new de(t)))):e.getAtomSet(new de(r.filterSele))),o.forEach((t=>{const e=p[t];if(!n.includes(e))return;if(v){const e=l[m[t]][0],i=l[f[t]][0];if(Array.isArray(v)){if(!(v[0].isSet(e)&&v[1].isSet(i)||v[1].isSet(e)&&v[0].isSet(i)))return}else if(!v.isSet(e)&&!v.isSet(i))return}const i=m[t],s=f[t];g.push(h[i],u[i],d[i]),y.push(h[s],u[s],d[s]),b.push(...function(t){switch(t){case 4:case 9:case 10:return js.setHex(2851770).toArray();case 6:return js.setHex(8421504).toArray();case 5:return js.setHex(4259775).toArray();case 1:return js.setHex(15779860).toArray();case 7:return js.setHex(9191577).toArray();case 2:return js.setHex(16744448).toArray();case 3:return js.setHex(9220966).toArray();case 8:return js.setHex(12967404).toArray();default:return js.setHex(13421772).toArray()}}(e)),_.push(r.radius),x.push(t)})),{position1:new Float32Array(g),position2:new Float32Array(y),color:new Float32Array(b),color2:new Float32Array(b),radius:new Float32Array(_),picking:new Ks(x,t,e)}}class Hs{constructor(t){this.array=t}get type(){return""}get data(){return{}}getIndex(t){return this.array?this.array[t]:t}getObject(t){return{}}_applyTransformations(t,e,i){return e&&t.applyMatrix4(e.matrix),i&&t.applyMatrix4(i.matrix),t}_getPosition(t){return new e}getPosition(t,e,i){return this._applyTransformations(this._getPosition(t),e,i)}}class qs extends Hs{constructor(t){super(),this.shape=t}get primitive(){}get data(){return this.shape}get type(){return this.primitive.type}getObject(t){return this.primitive.objectFromShape(this.shape,this.getIndex(t))}_getPosition(t){return this.primitive.positionFromShape(this.shape,this.getIndex(t))}}class Ws extends Hs{constructor(t,e){super(t),this.structure=e}get type(){return"atom"}get data(){return this.structure}getObject(t){return this.structure.getAtomProxy(this.getIndex(t))}_getPosition(t){return(new e).copy(this.getObject(t))}}class Xs extends Hs{constructor(t){super(),this.axes=t}get type(){return"axes"}get data(){return this.axes}getObject(){return{axes:this.axes}}_getPosition(){return this.axes.center.clone()}}class Ys extends Hs{constructor(t,e,i){super(t),this.structure=e,this.bondStore=i||e.bondStore}get type(){return"bond"}get data(){return this.structure}getObject(t){const e=this.structure.getBondProxy(this.getIndex(t));return e.bondStore=this.bondStore,e}_getPosition(t){const i=this.getObject(t);return(new e).copy(i.atom1).add(i.atom2).multiplyScalar(.5)}}class Ks extends Hs{constructor(t,e,i){super(t),this.contacts=e,this.structure=i}get type(){return"contact"}get data(){return this.contacts}getObject(t){const i=this.getIndex(t),{features:r,contactStore:n}=this.contacts,{centers:s,atomSets:o}=r,{x:a,y:c,z:l}=s,{index1:h,index2:u,type:d}=n,m=h[i],f=u[i];return{center1:new e(a[m],c[m],l[m]),center2:new e(a[f],c[f],l[f]),atom1:this.structure.getAtomProxy(o[m][0]),atom2:this.structure.getAtomProxy(o[f][0]),type:Us(d[i])}}_getPosition(t){const{center1:i,center2:r}=this.getObject(t);return(new e).addVectors(i,r).multiplyScalar(.5)}}class Zs extends Hs{constructor(t,e,i){super(t),this.validation=e,this.structure=i}get type(){return"clash"}get data(){return this.validation}getObject(t){const e=this.validation,i=this.getIndex(t);return{validation:e,index:i,clash:e.clashArray[i]}}_getAtomProxyFromSele(t){const e=new de(t),i=this.structure.getAtomIndices(e)[0];return this.structure.getAtomProxy(i)}_getPosition(t){const i=this.getObject(t).clash,r=this._getAtomProxyFromSele(i.sele1),n=this._getAtomProxyFromSele(i.sele2);return(new e).copy(r).add(n).multiplyScalar(.5)}}class Qs extends Ys{get type(){return"distance"}}class Js extends Hs{get type(){return"ignore"}}class to extends qs{constructor(t,e){super(t),this.mesh=e}get type(){return"mesh"}getObject(){const t=this.mesh;return{shape:this.shape,name:t.name,serial:t.serial}}_getPosition(){return this.__position||(this.__position=Ur(this.mesh.position)),this.__position}}class eo extends Hs{constructor(t,e){super(t),this.surface=e}get type(){return"surface"}get data(){return this.surface}getObject(t){return{surface:this.surface,index:this.getIndex(t)}}_getPosition(){return this.surface.center.clone()}}class io extends Hs{constructor(t,e){super(),this.unitcell=t,this.structure=e}get type(){return"unitcell"}get data(){return this.unitcell}getObject(){return{unitcell:this.unitcell,structure:this.structure}}_getPosition(){return this.unitcell.getCenter(this.structure)}}class ro extends Hs{constructor(t,e){super(t),this.volume=e}get type(){return"volume"}get data(){return this.volume}getObject(t){const e=this.volume,i=this.getIndex(t);return{volume:e,index:i,value:e.data[i]}}_getPosition(t){const i=this.volume.position,r=this.getIndex(t);return new e(i[3*r],i[3*r+1],i[3*r+2])}}class no extends ro{get type(){return"slice"}}function so(){return new Uint32Array([0,265,515,778,1030,1295,1541,1804,2060,2309,2575,2822,3082,3331,3593,3840,400,153,915,666,1430,1183,1941,1692,2460,2197,2975,2710,3482,3219,3993,3728,560,825,51,314,1590,1855,1077,1340,2620,2869,2111,2358,3642,3891,3129,3376,928,681,419,170,1958,1711,1445,1196,2988,2725,2479,2214,4010,3747,3497,3232,1120,1385,1635,1898,102,367,613,876,3180,3429,3695,3942,2154,2403,2665,2912,1520,1273,2035,1786,502,255,1013,764,3580,3317,4095,3830,2554,2291,3065,2800,1616,1881,1107,1370,598,863,85,348,3676,3925,3167,3414,2650,2899,2137,2384,1984,1737,1475,1226,966,719,453,204,4044,3781,3535,3270,3018,2755,2505,2240,2240,2505,2755,3018,3270,3535,3781,4044,204,453,719,966,1226,1475,1737,1984,2384,2137,2899,2650,3414,3167,3925,3676,348,85,863,598,1370,1107,1881,1616,2800,3065,2291,2554,3830,4095,3317,3580,764,1013,255,502,1786,2035,1273,1520,2912,2665,2403,2154,3942,3695,3429,3180,876,613,367,102,1898,1635,1385,1120,3232,3497,3747,4010,2214,2479,2725,2988,1196,1445,1711,1958,170,419,681,928,3376,3129,3891,3642,2358,2111,2869,2620,1340,1077,1855,1590,314,51,825,560,3728,3993,3219,3482,2710,2975,2197,2460,1692,1941,1183,1430,666,915,153,400,3840,3593,3331,3082,2822,2575,2309,2060,1804,1541,1295,1030,778,515,265,0])}function oo(){return new Int32Array([-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,8,3,9,8,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,1,2,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,2,10,0,2,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,8,3,2,10,8,10,9,8,-1,-1,-1,-1,-1,-1,-1,3,11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,11,2,8,11,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,9,0,2,3,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,11,2,1,9,11,9,8,11,-1,-1,-1,-1,-1,-1,-1,3,10,1,11,10,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,10,1,0,8,10,8,11,10,-1,-1,-1,-1,-1,-1,-1,3,9,0,3,11,9,11,10,9,-1,-1,-1,-1,-1,-1,-1,9,8,10,10,8,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,7,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,3,0,7,3,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,8,4,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,1,9,4,7,1,7,3,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,8,4,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,4,7,3,0,4,1,2,10,-1,-1,-1,-1,-1,-1,-1,9,2,10,9,0,2,8,4,7,-1,-1,-1,-1,-1,-1,-1,2,10,9,2,9,7,2,7,3,7,9,4,-1,-1,-1,-1,8,4,7,3,11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,4,7,11,2,4,2,0,4,-1,-1,-1,-1,-1,-1,-1,9,0,1,8,4,7,2,3,11,-1,-1,-1,-1,-1,-1,-1,4,7,11,9,4,11,9,11,2,9,2,1,-1,-1,-1,-1,3,10,1,3,11,10,7,8,4,-1,-1,-1,-1,-1,-1,-1,1,11,10,1,4,11,1,0,4,7,11,4,-1,-1,-1,-1,4,7,8,9,0,11,9,11,10,11,0,3,-1,-1,-1,-1,4,7,11,4,11,9,9,11,10,-1,-1,-1,-1,-1,-1,-1,9,5,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,5,4,0,8,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,5,4,1,5,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,5,4,8,3,5,3,1,5,-1,-1,-1,-1,-1,-1,-1,1,2,10,9,5,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,8,1,2,10,4,9,5,-1,-1,-1,-1,-1,-1,-1,5,2,10,5,4,2,4,0,2,-1,-1,-1,-1,-1,-1,-1,2,10,5,3,2,5,3,5,4,3,4,8,-1,-1,-1,-1,9,5,4,2,3,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,11,2,0,8,11,4,9,5,-1,-1,-1,-1,-1,-1,-1,0,5,4,0,1,5,2,3,11,-1,-1,-1,-1,-1,-1,-1,2,1,5,2,5,8,2,8,11,4,8,5,-1,-1,-1,-1,10,3,11,10,1,3,9,5,4,-1,-1,-1,-1,-1,-1,-1,4,9,5,0,8,1,8,10,1,8,11,10,-1,-1,-1,-1,5,4,0,5,0,11,5,11,10,11,0,3,-1,-1,-1,-1,5,4,8,5,8,10,10,8,11,-1,-1,-1,-1,-1,-1,-1,9,7,8,5,7,9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,3,0,9,5,3,5,7,3,-1,-1,-1,-1,-1,-1,-1,0,7,8,0,1,7,1,5,7,-1,-1,-1,-1,-1,-1,-1,1,5,3,3,5,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,7,8,9,5,7,10,1,2,-1,-1,-1,-1,-1,-1,-1,10,1,2,9,5,0,5,3,0,5,7,3,-1,-1,-1,-1,8,0,2,8,2,5,8,5,7,10,5,2,-1,-1,-1,-1,2,10,5,2,5,3,3,5,7,-1,-1,-1,-1,-1,-1,-1,7,9,5,7,8,9,3,11,2,-1,-1,-1,-1,-1,-1,-1,9,5,7,9,7,2,9,2,0,2,7,11,-1,-1,-1,-1,2,3,11,0,1,8,1,7,8,1,5,7,-1,-1,-1,-1,11,2,1,11,1,7,7,1,5,-1,-1,-1,-1,-1,-1,-1,9,5,8,8,5,7,10,1,3,10,3,11,-1,-1,-1,-1,5,7,0,5,0,9,7,11,0,1,0,10,11,10,0,-1,11,10,0,11,0,3,10,5,0,8,0,7,5,7,0,-1,11,10,5,7,11,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,6,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,5,10,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,0,1,5,10,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,8,3,1,9,8,5,10,6,-1,-1,-1,-1,-1,-1,-1,1,6,5,2,6,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,6,5,1,2,6,3,0,8,-1,-1,-1,-1,-1,-1,-1,9,6,5,9,0,6,0,2,6,-1,-1,-1,-1,-1,-1,-1,5,9,8,5,8,2,5,2,6,3,2,8,-1,-1,-1,-1,2,3,11,10,6,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,0,8,11,2,0,10,6,5,-1,-1,-1,-1,-1,-1,-1,0,1,9,2,3,11,5,10,6,-1,-1,-1,-1,-1,-1,-1,5,10,6,1,9,2,9,11,2,9,8,11,-1,-1,-1,-1,6,3,11,6,5,3,5,1,3,-1,-1,-1,-1,-1,-1,-1,0,8,11,0,11,5,0,5,1,5,11,6,-1,-1,-1,-1,3,11,6,0,3,6,0,6,5,0,5,9,-1,-1,-1,-1,6,5,9,6,9,11,11,9,8,-1,-1,-1,-1,-1,-1,-1,5,10,6,4,7,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,3,0,4,7,3,6,5,10,-1,-1,-1,-1,-1,-1,-1,1,9,0,5,10,6,8,4,7,-1,-1,-1,-1,-1,-1,-1,10,6,5,1,9,7,1,7,3,7,9,4,-1,-1,-1,-1,6,1,2,6,5,1,4,7,8,-1,-1,-1,-1,-1,-1,-1,1,2,5,5,2,6,3,0,4,3,4,7,-1,-1,-1,-1,8,4,7,9,0,5,0,6,5,0,2,6,-1,-1,-1,-1,7,3,9,7,9,4,3,2,9,5,9,6,2,6,9,-1,3,11,2,7,8,4,10,6,5,-1,-1,-1,-1,-1,-1,-1,5,10,6,4,7,2,4,2,0,2,7,11,-1,-1,-1,-1,0,1,9,4,7,8,2,3,11,5,10,6,-1,-1,-1,-1,9,2,1,9,11,2,9,4,11,7,11,4,5,10,6,-1,8,4,7,3,11,5,3,5,1,5,11,6,-1,-1,-1,-1,5,1,11,5,11,6,1,0,11,7,11,4,0,4,11,-1,0,5,9,0,6,5,0,3,6,11,6,3,8,4,7,-1,6,5,9,6,9,11,4,7,9,7,11,9,-1,-1,-1,-1,10,4,9,6,4,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,10,6,4,9,10,0,8,3,-1,-1,-1,-1,-1,-1,-1,10,0,1,10,6,0,6,4,0,-1,-1,-1,-1,-1,-1,-1,8,3,1,8,1,6,8,6,4,6,1,10,-1,-1,-1,-1,1,4,9,1,2,4,2,6,4,-1,-1,-1,-1,-1,-1,-1,3,0,8,1,2,9,2,4,9,2,6,4,-1,-1,-1,-1,0,2,4,4,2,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,3,2,8,2,4,4,2,6,-1,-1,-1,-1,-1,-1,-1,10,4,9,10,6,4,11,2,3,-1,-1,-1,-1,-1,-1,-1,0,8,2,2,8,11,4,9,10,4,10,6,-1,-1,-1,-1,3,11,2,0,1,6,0,6,4,6,1,10,-1,-1,-1,-1,6,4,1,6,1,10,4,8,1,2,1,11,8,11,1,-1,9,6,4,9,3,6,9,1,3,11,6,3,-1,-1,-1,-1,8,11,1,8,1,0,11,6,1,9,1,4,6,4,1,-1,3,11,6,3,6,0,0,6,4,-1,-1,-1,-1,-1,-1,-1,6,4,8,11,6,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,10,6,7,8,10,8,9,10,-1,-1,-1,-1,-1,-1,-1,0,7,3,0,10,7,0,9,10,6,7,10,-1,-1,-1,-1,10,6,7,1,10,7,1,7,8,1,8,0,-1,-1,-1,-1,10,6,7,10,7,1,1,7,3,-1,-1,-1,-1,-1,-1,-1,1,2,6,1,6,8,1,8,9,8,6,7,-1,-1,-1,-1,2,6,9,2,9,1,6,7,9,0,9,3,7,3,9,-1,7,8,0,7,0,6,6,0,2,-1,-1,-1,-1,-1,-1,-1,7,3,2,6,7,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,11,10,6,8,10,8,9,8,6,7,-1,-1,-1,-1,2,0,7,2,7,11,0,9,7,6,7,10,9,10,7,-1,1,8,0,1,7,8,1,10,7,6,7,10,2,3,11,-1,11,2,1,11,1,7,10,6,1,6,7,1,-1,-1,-1,-1,8,9,6,8,6,7,9,1,6,11,6,3,1,3,6,-1,0,9,1,11,6,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,8,0,7,0,6,3,11,0,11,6,0,-1,-1,-1,-1,7,11,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,6,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,8,11,7,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,9,11,7,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,1,9,8,3,1,11,7,6,-1,-1,-1,-1,-1,-1,-1,10,1,2,6,11,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,10,3,0,8,6,11,7,-1,-1,-1,-1,-1,-1,-1,2,9,0,2,10,9,6,11,7,-1,-1,-1,-1,-1,-1,-1,6,11,7,2,10,3,10,8,3,10,9,8,-1,-1,-1,-1,7,2,3,6,2,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,7,0,8,7,6,0,6,2,0,-1,-1,-1,-1,-1,-1,-1,2,7,6,2,3,7,0,1,9,-1,-1,-1,-1,-1,-1,-1,1,6,2,1,8,6,1,9,8,8,7,6,-1,-1,-1,-1,10,7,6,10,1,7,1,3,7,-1,-1,-1,-1,-1,-1,-1,10,7,6,1,7,10,1,8,7,1,0,8,-1,-1,-1,-1,0,3,7,0,7,10,0,10,9,6,10,7,-1,-1,-1,-1,7,6,10,7,10,8,8,10,9,-1,-1,-1,-1,-1,-1,-1,6,8,4,11,8,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,6,11,3,0,6,0,4,6,-1,-1,-1,-1,-1,-1,-1,8,6,11,8,4,6,9,0,1,-1,-1,-1,-1,-1,-1,-1,9,4,6,9,6,3,9,3,1,11,3,6,-1,-1,-1,-1,6,8,4,6,11,8,2,10,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,3,0,11,0,6,11,0,4,6,-1,-1,-1,-1,4,11,8,4,6,11,0,2,9,2,10,9,-1,-1,-1,-1,10,9,3,10,3,2,9,4,3,11,3,6,4,6,3,-1,8,2,3,8,4,2,4,6,2,-1,-1,-1,-1,-1,-1,-1,0,4,2,4,6,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,9,0,2,3,4,2,4,6,4,3,8,-1,-1,-1,-1,1,9,4,1,4,2,2,4,6,-1,-1,-1,-1,-1,-1,-1,8,1,3,8,6,1,8,4,6,6,10,1,-1,-1,-1,-1,10,1,0,10,0,6,6,0,4,-1,-1,-1,-1,-1,-1,-1,4,6,3,4,3,8,6,10,3,0,3,9,10,9,3,-1,10,9,4,6,10,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,9,5,7,6,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,3,4,9,5,11,7,6,-1,-1,-1,-1,-1,-1,-1,5,0,1,5,4,0,7,6,11,-1,-1,-1,-1,-1,-1,-1,11,7,6,8,3,4,3,5,4,3,1,5,-1,-1,-1,-1,9,5,4,10,1,2,7,6,11,-1,-1,-1,-1,-1,-1,-1,6,11,7,1,2,10,0,8,3,4,9,5,-1,-1,-1,-1,7,6,11,5,4,10,4,2,10,4,0,2,-1,-1,-1,-1,3,4,8,3,5,4,3,2,5,10,5,2,11,7,6,-1,7,2,3,7,6,2,5,4,9,-1,-1,-1,-1,-1,-1,-1,9,5,4,0,8,6,0,6,2,6,8,7,-1,-1,-1,-1,3,6,2,3,7,6,1,5,0,5,4,0,-1,-1,-1,-1,6,2,8,6,8,7,2,1,8,4,8,5,1,5,8,-1,9,5,4,10,1,6,1,7,6,1,3,7,-1,-1,-1,-1,1,6,10,1,7,6,1,0,7,8,7,0,9,5,4,-1,4,0,10,4,10,5,0,3,10,6,10,7,3,7,10,-1,7,6,10,7,10,8,5,4,10,4,8,10,-1,-1,-1,-1,6,9,5,6,11,9,11,8,9,-1,-1,-1,-1,-1,-1,-1,3,6,11,0,6,3,0,5,6,0,9,5,-1,-1,-1,-1,0,11,8,0,5,11,0,1,5,5,6,11,-1,-1,-1,-1,6,11,3,6,3,5,5,3,1,-1,-1,-1,-1,-1,-1,-1,1,2,10,9,5,11,9,11,8,11,5,6,-1,-1,-1,-1,0,11,3,0,6,11,0,9,6,5,6,9,1,2,10,-1,11,8,5,11,5,6,8,0,5,10,5,2,0,2,5,-1,6,11,3,6,3,5,2,10,3,10,5,3,-1,-1,-1,-1,5,8,9,5,2,8,5,6,2,3,8,2,-1,-1,-1,-1,9,5,6,9,6,0,0,6,2,-1,-1,-1,-1,-1,-1,-1,1,5,8,1,8,0,5,6,8,3,8,2,6,2,8,-1,1,5,6,2,1,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,3,6,1,6,10,3,8,6,5,6,9,8,9,6,-1,10,1,0,10,0,6,9,5,0,5,6,0,-1,-1,-1,-1,0,3,8,5,6,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,5,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,5,10,7,5,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,5,10,11,7,5,8,3,0,-1,-1,-1,-1,-1,-1,-1,5,11,7,5,10,11,1,9,0,-1,-1,-1,-1,-1,-1,-1,10,7,5,10,11,7,9,8,1,8,3,1,-1,-1,-1,-1,11,1,2,11,7,1,7,5,1,-1,-1,-1,-1,-1,-1,-1,0,8,3,1,2,7,1,7,5,7,2,11,-1,-1,-1,-1,9,7,5,9,2,7,9,0,2,2,11,7,-1,-1,-1,-1,7,5,2,7,2,11,5,9,2,3,2,8,9,8,2,-1,2,5,10,2,3,5,3,7,5,-1,-1,-1,-1,-1,-1,-1,8,2,0,8,5,2,8,7,5,10,2,5,-1,-1,-1,-1,9,0,1,5,10,3,5,3,7,3,10,2,-1,-1,-1,-1,9,8,2,9,2,1,8,7,2,10,2,5,7,5,2,-1,1,3,5,3,7,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,8,7,0,7,1,1,7,5,-1,-1,-1,-1,-1,-1,-1,9,0,3,9,3,5,5,3,7,-1,-1,-1,-1,-1,-1,-1,9,8,7,5,9,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,5,8,4,5,10,8,10,11,8,-1,-1,-1,-1,-1,-1,-1,5,0,4,5,11,0,5,10,11,11,3,0,-1,-1,-1,-1,0,1,9,8,4,10,8,10,11,10,4,5,-1,-1,-1,-1,10,11,4,10,4,5,11,3,4,9,4,1,3,1,4,-1,2,5,1,2,8,5,2,11,8,4,5,8,-1,-1,-1,-1,0,4,11,0,11,3,4,5,11,2,11,1,5,1,11,-1,0,2,5,0,5,9,2,11,5,4,5,8,11,8,5,-1,9,4,5,2,11,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,5,10,3,5,2,3,4,5,3,8,4,-1,-1,-1,-1,5,10,2,5,2,4,4,2,0,-1,-1,-1,-1,-1,-1,-1,3,10,2,3,5,10,3,8,5,4,5,8,0,1,9,-1,5,10,2,5,2,4,1,9,2,9,4,2,-1,-1,-1,-1,8,4,5,8,5,3,3,5,1,-1,-1,-1,-1,-1,-1,-1,0,4,5,1,0,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,4,5,8,5,3,9,0,5,0,3,5,-1,-1,-1,-1,9,4,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,11,7,4,9,11,9,10,11,-1,-1,-1,-1,-1,-1,-1,0,8,3,4,9,7,9,11,7,9,10,11,-1,-1,-1,-1,1,10,11,1,11,4,1,4,0,7,4,11,-1,-1,-1,-1,3,1,4,3,4,8,1,10,4,7,4,11,10,11,4,-1,4,11,7,9,11,4,9,2,11,9,1,2,-1,-1,-1,-1,9,7,4,9,11,7,9,1,11,2,11,1,0,8,3,-1,11,7,4,11,4,2,2,4,0,-1,-1,-1,-1,-1,-1,-1,11,7,4,11,4,2,8,3,4,3,2,4,-1,-1,-1,-1,2,9,10,2,7,9,2,3,7,7,4,9,-1,-1,-1,-1,9,10,7,9,7,4,10,2,7,8,7,0,2,0,7,-1,3,7,10,3,10,2,7,4,10,1,10,0,4,0,10,-1,1,10,2,8,7,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,9,1,4,1,7,7,1,3,-1,-1,-1,-1,-1,-1,-1,4,9,1,4,1,7,0,8,1,8,7,1,-1,-1,-1,-1,4,0,3,7,4,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,4,8,7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,9,10,8,10,11,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,0,9,3,9,11,11,9,10,-1,-1,-1,-1,-1,-1,-1,0,1,10,0,10,8,8,10,11,-1,-1,-1,-1,-1,-1,-1,3,1,10,11,3,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,2,11,1,11,9,9,11,8,-1,-1,-1,-1,-1,-1,-1,3,0,9,3,9,11,1,2,9,2,11,9,-1,-1,-1,-1,0,2,11,8,0,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3,2,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,8,2,8,10,10,8,9,-1,-1,-1,-1,-1,-1,-1,9,10,2,0,9,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,2,3,8,2,8,10,0,1,8,1,10,8,-1,-1,-1,-1,1,10,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,3,8,9,1,8,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,9,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,3,8,-1,-1,-1,-1,-1,-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 ao(t,e,i,r,n){var s,o,a,c,l,h,u,d=[[0,4,4,4,2,0,0,0,2,2,0,0],[4,0,4,4,0,8,0,0,0,8,8,0],[4,4,0,4,0,0,8,0,0,0,8,8],[4,4,4,0,0,0,0,1,1,0,0,1],[2,0,0,0,0,8,8,8,2,2,0,0],[0,8,0,0,8,0,8,8,0,8,8,0],[0,0,8,0,8,8,0,8,0,0,8,8],[0,0,0,1,8,8,8,0,1,0,0,1],[2,0,0,1,2,0,0,1,0,2,0,1],[2,8,0,0,2,8,0,0,2,0,8,0],[0,8,8,0,0,8,8,0,0,8,0,8],[0,0,8,1,0,0,8,1,1,0,8,0]],m=0,f=!1,p=!1,g=!1,y=!1,b=-1,_=e*i*r,x=e,v=e*i,w=new Int32Array(12),A=[],S=[],C=[],P=[],I=so(),k=oo();function M(t,e,i){return t+(e-t)*i}function T(t,n,s){return v*(s=(s+u)%r)+x*(n=(n+h)%i)+(t=(t+l)%e)}function D(t,e,i,r,c,l,h){var u=3*t;if(o[u]<0){var d=(m-l)/(h-l),p=s,g=3*a;if(A[g]=i+d,A[g+1]=r,A[g+2]=c,!f){var y=3*t;S[g]=b*M(p[y],p[y+3],d),S[g+1]=b*M(p[y+1],p[y+4],d),S[g+2]=b*M(p[y+2],p[y+5],d)}n&&(P[a]=n[t+Math.round(d)]),o[u]=a,w[e]=a,a+=1}else w[e]=o[u]}function B(t,e,i,r,c,l,h){var u=3*t+1;if(o[u]<0){var d=(m-l)/(h-l),p=s,g=3*a;if(A[g]=i,A[g+1]=r+d,A[g+2]=c,!f){var y=3*t,_=y+3*x;S[g]=b*M(p[y],p[_],d),S[g+1]=b*M(p[y+1],p[_+1],d),S[g+2]=b*M(p[y+2],p[_+2],d)}n&&(P[a]=n[t+Math.round(d)*x]),o[u]=a,w[e]=a,a+=1}else w[e]=o[u]}function F(t,e,i,r,c,l,h){var u=3*t+2;if(o[u]<0){var d=(m-l)/(h-l),p=s,g=3*a;if(A[g]=i,A[g+1]=r,A[g+2]=c+d,!f){var y=3*t,_=y+3*v;S[g]=b*M(p[y],p[_],d),S[g+1]=b*M(p[y+1],p[_+1],d),S[g+2]=b*M(p[y+2],p[_+2],d)}n&&(P[a]=n[t+Math.round(d)*v]),o[u]=a,w[e]=a,a+=1}else w[e]=o[u]}function E(e){var i=3*e;0===s[i]&&(s[i]=t[(e-1+_)%_]-t[(e+1)%_],s[i+1]=t[(e-x+_)%_]-t[(e+x)%_],s[i+2]=t[(e-v+_)%_]-t[(e+v)%_])}function $(e,i,r,n,s){var o,a,l,h,u,b,_;g?(n=T(e,i,r),o=T(e+1,i,r),a=T(e,i+1,r),l=T(e,i,r+1),h=T(e+1,i+1,r),u=T(e+1,i,r+1),b=T(e,i+1,r+1),_=T(e+1,i+1,r+1)):(o=n+1,h=(a=n+x)+1,u=(l=n+v)+1,_=(b=a+v)+1);var A=0,S=t[n],P=t[o],M=t[a],$=t[h],O=t[l],R=t[u],L=t[b],N=t[_];S=m){F=b,M=!0;break}if(M)break}if(M)break}for(M=!1,y=s;y=m){B=y,M=!0;break}if(M)break}if(M)break}for(M=!1,p=n;p=m){D=p,M=!0;break}if(M)break}if(M)break}for(M=!1,b=h;b>=a;--b){for(y=l;y>=s;--y){for(p=c;p>=n;--p)if(u=e*i*b+e*y+p,t[u]>=m){R=b,M=!0;break}if(M)break}if(M)break}for(M=!1,y=l;y>=s;--y){for(b=R;b>=a;--b){for(p=c;p>=n;--p)if(u=e*i*b+e*y+p,t[u]>=m){O=y,M=!0;break}if(M)break}if(M)break}for(M=!1,p=c;p>=n;--p){for(y=O;y>=s;--y){for(b=R;b>=a;--b)if(u=e*i*b+e*y+p,t[u]>=m){E=p,M=!0;break}if(M)break}if(M)break}f?(n=Math.max(0,D-1),s=Math.max(0,B-1),a=Math.max(0,F-1),c=Math.min(e-1,E+1),l=Math.min(i-1,O+1),h=Math.min(r-1,R+1)):(n=Math.max(1,D-1),s=Math.max(1,B-1),a=Math.max(1,F-1),c=Math.min(e-2,E+1),l=Math.min(i-2,O+1),h=Math.min(r-2,R+1))}var L=15;for(b=a;b0?-1:1,s||(s=new Float32Array(3*_)));var I=3*_;if(o&&o.length===I||(o=new Int32Array(I)),a=0,c=0,void 0!==x){var k=x[0].map(Math.round),M=x[1].map(Math.round);l=e*Math.ceil(Math.abs(k[0])/e),h=i*Math.ceil(Math.abs(k[1])/i),u=r*Math.ceil(Math.abs(k[2])/r),O(k[0],k[1],k[2],M[0],M[1],M[2])}else l=h=u=0,O();return A.length=3*a,f||(S.length=3*a),C.length=c,n&&(P.length=a),{position:new Float32Array(A),normal:f?void 0:new Float32Array(S),index:yt(C,A.length/3),atomindex:n?new Int32Array(P):void 0,contour:p}}}je.add("arrow",class extends qs{get primitive(){return wn}}),je.add("box",class extends qs{get primitive(){return bn}}),je.add("cone",class extends qs{get primitive(){return An}}),je.add("cylinder",class extends qs{get primitive(){return vn}}),je.add("ellipsoid",class extends qs{get primitive(){return Sn}}),je.add("octahedron",class extends qs{get primitive(){return _n}}),je.add("sphere",class extends qs{get primitive(){return yn}}),je.add("tetrahedron",class extends qs{get primitive(){return xn}}),je.add("torus",class extends qs{get primitive(){return Cn}}),je.add("point",class extends qs{get primitive(){return In}}),je.add("wideline",class extends qs{get primitive(){return kn}}),Object.assign(ao,{__deps:[so,oo,yt]});class co{constructor(t,e){this.cols=t,this.rows=e,this.size=this.cols*this.rows,this.data=new Float32Array(this.size)}copyTo(t){t.data.set(this.data)}}function lo(t,e){let i=0,r=0;const n=e.rows,s=e.cols;let o=0,a=0,c=0;const l=e.data,h=t.data;for(;i(e=Math.abs(e))?(e/=t,t*Math.sqrt(1+e*e)):e>0?(t/=e,e*Math.sqrt(1+t*t)):0}const yo=1.192092896e-7,bo=1e-37;function _o(t,e,i,r){let n=0,s=0;const o=t.rows,a=t.cols;let c=o,l=a;c>16?E:-E,t[h*e+d]=F;for(m=0;m<2;m++)for(u=0;u{const e=t.data.sd,i=t.data.p;o(this._makeSurface(e,i.isolevel,i.smooth))}),(a=>{console.warn("Volume.getSurfaceWorker error - trying without worker",a);const c=this.getSurface(t,e,i,r,n,s);o(c)}))}else{const a=this.getSurface(t,e,i,r,n,s);o(a)}}getValueForSigma(t){return this.mean+rt(t,2)*this.rms}getSigmaForValue(t){return(rt(t,0)-this.mean)/this.rms}get position(){if(!this._position){const t=this.nz,e=this.ny,i=this.nx,r=new Float32Array(i*e*t*3);let n=0;for(let s=0;si){const t=e;e=i,i=t}const r=t[e];return void 0===r?(t[e]=[i],!0):!r.includes(i)&&(r.push(i),!0)}const i=this.geometry,r=i.index;if(this.parameters.wireframe)if(r){const n=r.array;let s,o=n.length;if(i.drawRange.count!==1/0&&(o=i.drawRange.count),this.wireframeIndex&&this.wireframeIndex.length>2*o)s=this.wireframeIndex;else{s=yt(2*o,i.attributes.position.count)}let a=0;t.length=0;for(let t=0;t2*t?this.wireframeIndex:yt(2*t,t);for(let i=0,r=0;ithis.wireframeGeometry.index.array.length)this.wireframeGeometry.setIndex(new M(this.wireframeIndex,1).setUsage(this.dynamic?$:O));else{const t=this.wireframeGeometry.getIndex();if(!t)return void Ie.error("Index is null");t.set(this.wireframeIndex),t.needsUpdate=this.wireframeIndexCount>0,t.updateRange.count=this.wireframeIndexCount}this.wireframeGeometry.setDrawRange(0,this.wireframeIndexCount)}}getRenderOrder(){let t=0;return this.isText?t=1:this.transparent&&(t=this.isSurface?3:2),t}_getMesh(t){this.material||this.makeMaterial();const e=this.geometry,i=this[t];let r;return r=this.isLine?new T(e,i):this.isPoint?new o(e,i):new P(e,i),r.frustumCulled=!1,r.renderOrder=this.getRenderOrder(),r}getMesh(){return this._getMesh("material")}getWireframeMesh(){let t;return this.material||this.makeMaterial(),this.wireframeGeometry||this.makeWireframeGeometry(),t=new T(this.wireframeGeometry,this.wireframeMaterial),t.frustumCulled=!1,t.renderOrder=this.getRenderOrder(),t}getPickingMesh(){return this._getMesh("pickingMaterial")}getShader(t,e){return fi(t,this.getDefines(e))}getVertexShader(t){return this.getShader(this.vertexShader,t)}getFragmentShader(t){return this.getShader(this.fragmentShader,t)}getDefines(t){const e={};return this.parameters.clipNear&&(e.NEAR_CLIP=1),this.parameters.clipRadius&&(e.RADIUS_CLIP=1),"picking"===t?e.PICKING=1:(("background"===t||this.parameters.background)&&(e.NOLIGHT=1),this.parameters.flatShaded&&(e.FLAT_SHADED=1),this.parameters.opaqueBack&&(e.OPAQUE_BACK=1),this.parameters.diffuseInterior&&(e.DIFFUSE_INTERIOR=1),this.parameters.useInteriorColor&&(e.USE_INTERIOR_COLOR=1)),e}getParameters(){return this.parameters}addUniforms(t){this.uniforms=F.merge([this.uniforms,t]),this.pickingUniforms=F.merge([this.pickingUniforms,t])}addAttributes(t){for(let e in t){let i;const r=t[e],n=this.attributeSize*Oo[r.type];r.value?(n!==r.value.length&&Ie.error("attribute value has wrong length",e),i=r.value):i=gt("float32",n),this.geometry.setAttribute(e,new M(i,Oo[r.type]).setUsage(this.dynamic?$:O))}}updateRenderOrder(){const t=this.getRenderOrder();function e(e){e.renderOrder=t}this.group.children.forEach(e),this.pickingGroup&&this.pickingGroup.children.forEach(e)}updateShader(){const t=this.material,e=this.wireframeMaterial,i=this.pickingMaterial;t.vertexShader=this.getVertexShader(),t.fragmentShader=this.getFragmentShader(),t.needsUpdate=!0,e.vertexShader=this.getShader("Line.vert"),e.fragmentShader=this.getShader("Line.frag"),e.needsUpdate=!0,i.vertexShader=this.getVertexShader("picking"),i.fragmentShader=this.getFragmentShader("picking"),i.needsUpdate=!0}setParameters(t){const e=t,i=this.parameterTypes,r=this.parameters,n={},s={};let o=!1,a=!1;for(const t in e){const c=e[t];void 0!==c&&(r[t]=c,void 0!==i[t]&&(i[t].property&&(!0!==i[t].property?n[i[t].property]=c:n[t]=c),i[t].uniform&&(!0!==i[t].uniform?s[i[t].uniform]=c:s[t]=c),i[t].updateShader&&(o=!0),i[t].updateVisibility&&(a=!0),this.dynamic&&"wireframe"===t&&!0===c&&this.updateWireframeIndex(),"forceTransparent"===t&&(n.transparent=this.transparent),"matrix"===t&&(this.matrix=c)))}this.setProperties(n),this.setUniforms(s),o&&this.updateShader(),a&&this.setVisibility(this.visible)}setAttributes(t){const e=this.geometry,i=e.attributes;for(const r in t){if("picking"===r)continue;const n=t[r],s=n.length;if("index"===r){const t=e.getIndex();if(!t){Ie.error("Index is null");continue}e.setDrawRange(0,1/0),s>t.array.length?e.setIndex(new M(n,1).setUsage(this.dynamic?$:O)):(t.set(n),t.needsUpdate=s>0,t.updateRange.count=s,e.setDrawRange(0,s)),this.indexVersion++,this.parameters.wireframe&&this.updateWireframeIndex()}else{const t=i[r];s>t.array.length?e.setAttribute(r,new M(n,t.itemSize).setUsage(this.dynamic?$:O)):(i[r].set(n),i[r].needsUpdate=s>0,i[r].updateRange.count=s)}}}setUniforms(t){if(!t)return;const e=this.material.uniforms,i=this.wireframeMaterial.uniforms,r=this.pickingMaterial.uniforms;for(let n in t)"opacity"===n&&this.setProperties({transparent:this.transparent}),void 0!==e[n]&&(e[n].value.isVector3?e[n].value.copy(t[n]):e[n].value.set?e[n].value.set(t[n]):e[n].value=t[n]),void 0!==i[n]&&(i[n].value.isVector3?i[n].value.copy(t[n]):i[n].value.set?i[n].value.set(t[n]):i[n].value=t[n]),void 0!==r[n]&&(r[n].value.isVector3?r[n].value.copy(t[n]):r[n].value.set?r[n].value.set(t[n]):r[n].value=t[n])}setProperties(t){if(!t)return;const e=this.material,i=this.wireframeMaterial,r=this.pickingMaterial;for(const n in t){const s=n;let o=t[s];"transparent"===s?this.updateRenderOrder():"side"===s&&(o=$o(o)),e[s]=o,i[s]=o,r[s]=o}e.needsUpdate=!0,i.needsUpdate=!0,r.needsUpdate=!0}setVisibility(t){this.visible=t,this.parameters.wireframe?(this.group.visible=!1,this.wireframeGroup.visible=t,this.pickable&&(this.pickingGroup.visible=!1)):(this.group.visible=t,this.wireframeGroup.visible=!1,this.pickable&&(this.pickingGroup.visible=t))}dispose(){this.material&&this.material.dispose(),this.wireframeMaterial&&this.wireframeMaterial.dispose(),this.pickingMaterial&&this.pickingMaterial.dispose(),this.geometry.dispose(),this.wireframeGeometry&&this.wireframeGeometry.dispose()}toJSON(){var t={};for(var e in this)"group"!==e&&"wireframeGroup"!==e&&"pickingGroup"!=e&&"picking"!==e&&(t[e]=this[e]);return t}}class Uo extends zo{constructor(t,e={}){super(t,e),this.vertexShader="Mesh.vert",this.fragmentShader="Mesh.frag",this.addAttributes({normal:{type:"v3",value:t.normal}}),void 0===t.normal&&this.geometry.computeVertexNormals()}}class Vo extends Uo{constructor(){super(...arguments),this.isSurface=!0}}function jo(t){t.visible=!0}function Go(t){t.visible=!1}class Ho{constructor(t){this.group=new d,this.wireframeGroup=new d,this.pickingGroup=new d,this.frontMeshes=[],this.backMeshes=[],this.size=t.size,this.side=t.parameters.side,this.visible=t.visible,this.geometry=t.geometry,this.picking=t.picking,this.group=new d,this.wireframeGroup=new d,this.pickingGroup=new d,this.matrix=t.matrix;const e=t,i=new t.constructor({position:new Float32Array(0)});e.makeMaterial(),i.makeMaterial(),i.picking=t.picking,i.geometry=t.geometry,i.wireframeGeometry=t.wireframeGeometry,i.setParameters(t.getParameters()),i.updateShader(),e.setParameters({side:"front"}),i.setParameters({side:"back",opacity:i.parameters.opacity}),this.buffer=t,this.frontBuffer=e,this.backBuffer=i}set matrix(t){zo.prototype.setMatrix.call(this,t)}get matrix(){return this.group.matrix.clone()}get pickable(){return!!this.picking&&!this.parameters.disablePicking}get parameters(){return this.buffer.parameters}getParameters(){const t=Object.assign({},this.buffer.parameters);return t.side=this.side,t}getMesh(t){let e,i;return t?(i=this.backBuffer.getPickingMesh(),e=this.frontBuffer.getPickingMesh()):(i=this.backBuffer.getMesh(),e=this.frontBuffer.getMesh()),this.frontMeshes.push(e),this.backMeshes.push(i),this.setParameters({side:this.side}),(new d).add(i,e)}getWireframeMesh(){return this.buffer.getWireframeMesh()}getPickingMesh(){return this.getMesh(!0)}setAttributes(t){this.buffer.setAttributes(t)}setParameters(t){"front"===(t=Object.assign({},t)).side?(this.frontMeshes.forEach(jo),this.backMeshes.forEach(Go)):"back"===t.side?(this.frontMeshes.forEach(Go),this.backMeshes.forEach(jo)):"double"===t.side&&(this.frontMeshes.forEach(jo),this.backMeshes.forEach(jo)),void 0!==t.side&&(this.side=t.side),delete t.side,void 0!==t.matrix&&(this.matrix=t.matrix),delete t.matrix,this.frontBuffer.setParameters(t),void 0!==t.wireframe&&(this.wireframe=t.wireframe,this.setVisibility(this.visible)),delete t.wireframe,this.backBuffer.setParameters(t)}setVisibility(t){this.visible=t,this.parameters.wireframe?(this.group.visible=!1,this.wireframeGroup.visible=t,this.pickable&&(this.pickingGroup.visible=!1)):(this.group.visible=t,this.wireframeGroup.visible=!1,this.pickable&&(this.pickingGroup.visible=t))}dispose(){this.frontBuffer.dispose(),this.backBuffer.dispose()}toJSON(){var t={};for(var e in this)["side","size","visible","matrix","parameters"].includes(e)&&(t[e]=this[e]);return t}}Ne.add("shader/Line.vert","uniform float clipNear;\nuniform vec3 clipCenter;\nvarying vec3 vViewPosition;\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#include color_pars_vertex\nvoid main(){\n#include color_vertex\n#include begin_vertex\n#include project_vertex\nvViewPosition = -mvPosition.xyz;\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n#include nearclip_vertex\n}"),Ne.add("shader/Line.frag","uniform float opacity;\nuniform float clipNear;\nuniform float clipRadius;\nvarying vec3 vViewPosition;\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#include common\n#include color_pars_fragment\n#include fog_pars_fragment\nvoid main(){\n#include nearclip_fragment\n#include radiusclip_fragment\ngl_FragColor = vec4( vColor, opacity );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n}");class qo extends zo{constructor(){super(...arguments),this.isLine=!0,this.vertexShader="Line.vert",this.fragmentShader="Line.frag"}}class Wo extends Lr{constructor(t,r,n){super(t,r,n),this.type="surface",this.parameters=Object.assign({isolevelType:{type:"select",options:{value:"value",sigma:"sigma"}},isolevel:{type:"number",precision:2,max:1e3,min:-1e3},negateIsolevel:{type:"boolean"},isolevelScroll:{type:"boolean"},smooth:{type:"integer",precision:1,max:10,min:0},background:{type:"boolean",rebuild:!0},opaqueBack:{type:"boolean",buffer:!0},boxSize:{type:"integer",precision:1,max:100,min:0},colorVolume:{type:"hidden"},contour:{type:"boolean",rebuild:!0},useWorker:{type:"boolean",rebuild:!0},wrap:{type:"boolean",rebuild:!0}},this.parameters),t instanceof Eo?(this.surface=void 0,this.volume=t):(this.surface=t,this.volume=void 0),this.boxCenter=new e,this.__boxCenter=new e,this.box=new a,this.__box=new a,this._position=new e,this.inverseMatrix=new i,this.setBox=function(){this._position.copy(r.translationGroup.position).negate(),this._position.applyMatrix4(this.inverseMatrix),this._position.equals(this.boxCenter)||this.setParameters({boxCenter:this._position})},this.toBePrepared=!0,this.viewer.signals.ticked.add(this.setBox,this),this.init(n)}init(t){const e=t||{};e.colorScheme=rt(e.colorScheme,"uniform"),e.colorValue=rt(e.colorValue,14540253),this.isolevelType=rt(e.isolevelType,"sigma"),this.isolevel=rt(e.isolevel,2),this.negateIsolevel=rt(e.negateIsolevel,!1),this.isolevelScroll=rt(e.isolevelScroll,!1),this.smooth=rt(e.smooth,0),this.background=rt(e.background,!1),this.opaqueBack=rt(e.opaqueBack,!0),this.boxSize=rt(e.boxSize,0),this.colorVolume=rt(e.colorVolume,void 0),this.contour=rt(e.contour,!1),this.useWorker=rt(e.useWorker,!0),this.wrap=rt(e.wrap,!1),super.init(e),this.inverseMatrix.copy(this.matrix).invert(),this.build()}attach(t){this.bufferList.forEach((t=>{this.viewer.add(t)})),this.setVisibility(this.visible),t()}prepare(t){if(this.volume){let e;if(e="sigma"===this.isolevelType?this.volume.getValueForSigma(this.isolevel):this.isolevel,this.negateIsolevel&&(e*=-1),!this.surface||this.__isolevel!==e||this.__smooth!==this.smooth||this.__contour!==this.contour||this.__wrap!==this.wrap||this.__boxSize!==this.boxSize||this.boxSize>0&&!this.__boxCenter.equals(this.boxCenter)){this.__isolevel=e,this.__smooth=this.smooth,this.__contour=this.contour,this.__wrap=this.wrap,this.__boxSize=this.boxSize,this.__boxCenter.copy(this.boxCenter),this.__box.copy(this.box);const i=e=>{this.surface=e,t()};this.useWorker?this.volume.getSurfaceWorker(e,this.smooth,this.boxCenter,this.boxSize,this.contour,this.wrap,i):i(this.volume.getSurface(e,this.smooth,this.boxCenter,this.boxSize,this.contour,this.wrap))}else t()}else t()}create(){const t={position:this.surface.getPosition(),color:this.surface.getColor(this.getColorParams()),index:this.surface.getIndex()};let e;if(this.contour)e=new qo(t,this.getBufferParams({wireframe:!1}));else{Object.assign(t,{normal:this.surface.getNormal(),picking:this.surface.getPicking()});const i=new Vo(t,this.getBufferParams({background:this.background,opaqueBack:this.opaqueBack,dullInterior:!1}));e=new Ho(i)}this.bufferList.push(e)}update(t){if(0===this.bufferList.length)return;const e={};(t=t||{}).position&&(e.position=this.surface.getPosition()),t.color&&(e.color=this.surface.getColor(this.getColorParams())),t.index&&(e.index=this.surface.getIndex()),t.normal&&(e.normal=this.surface.getNormal()),this.bufferList.forEach((function(t){t.setAttributes(e)}))}setParameters(t,e,i){return t&&void 0!==t.isolevelType&&this.volume&&("value"===this.isolevelType&&"sigma"===t.isolevelType?this.isolevel=this.volume.getSigmaForValue(this.isolevel):"sigma"===this.isolevelType&&"value"===t.isolevelType&&(this.isolevel=this.volume.getValueForSigma(this.isolevel)),this.isolevelType=t.isolevelType),t&&t.boxCenter&&(this.boxCenter.copy(t.boxCenter),delete t.boxCenter),t&&t.wireframe&&(t.contour||void 0===t.contour&&this.contour)&&(t.wireframe=!1),super.setParameters(t,e,i),t.matrix&&this.inverseMatrix.copy(t.matrix).invert(),this.volume&&this.volume.getBox(this.boxCenter,this.boxSize,this.box),t&&void 0!==t.colorVolume&&e&&(e.color=!0),this.surface&&(void 0!==t.isolevel||void 0!==t.negateIsolevel||void 0!==t.smooth||void 0!==t.wrap||void 0!==t.boxSize||this.boxSize>0&&!this.__box.equals(this.box))&&this.build({position:!0,color:!0,index:!0,normal:!this.contour}),this}getColorParams(){const t=super.getColorParams();return t.volume=this.colorVolume,t}dispose(){this.viewer.signals.ticked.remove(this.setBox,this),super.dispose()}}class Xo{static zoomScroll(t,e){t.trackballControls.zoom(e)}static clipNearScroll(t,e){const i=t.getParameters();t.setParameters({clipNear:i.clipNear+e/10})}static focusScroll(t,e){const i=t.getFocus(),r=Math.sign(e)*function(t,e,i){if(t>e)return t;const r=t/e;return((2*i-e)*r+(2*e-3*i))*r*r+i}((100-i)/10,5,.2);t.setFocus(i+r)}static zoomFocusScroll(t,e){t.trackballControls.zoom(e);const i=t.viewer.camera.position.z;t.setFocus(100-Math.abs(i/8))}static isolevelScroll(t,e){const i=Math.sign(e)/10;t.eachRepresentation(((t,e)=>{if(t.repr instanceof Wo){const e=t.getParameters();e.isolevelScroll&&t.setParameters({isolevel:e.isolevel+i})}}))}static panDrag(t,e,i){t.trackballControls.pan(e,i)}static rotateDrag(t,e,i){t.trackballControls.rotate(e,i)}static zRotateDrag(t,e,i){t.trackballControls.zRotate(e,i)}static zoomDrag(t,e,i){t.trackballControls.zoom((e+i)/-2)}static zoomFocusDrag(t,e,i){t.trackballControls.zoom((e+i)/-2);const r=t.viewer.camera.position.z;t.setFocus(100-Math.abs(r/8))}static panComponentDrag(t,e,i){t.trackballControls.panComponent(e,i)}static panAtomDrag(t,e,i){t.trackballControls.panAtom(e,i)}static rotateComponentDrag(t,e,i){t.trackballControls.rotateComponent(e,i)}static movePick(t,e){e&&t.animationControls.move(e.position.clone())}static tooltipPick(t,e){const i=t.tooltip;if(t.getParameters().tooltip&&e){const t=e.mouse.position;i.innerText=e.getLabel(),i.style.bottom=window.innerHeight-t.y+3+"px",i.style.left=t.x+3+"px",i.style.display="block"}else i.style.display="none"}static measurePick(t,e){if(e&&(e.atom||e.bond)){const t=e.atom||e.closestBondAtom;e.component.measurePick(t)}else t.measureClear()}}const Yo={default:[["scroll",Xo.zoomScroll],["scroll-shift",Xo.focusScroll],["scroll-ctrl",Xo.isolevelScroll],["scroll-shift-ctrl",Xo.zoomFocusScroll],["drag-left",Xo.rotateDrag],["drag-right",Xo.panDrag],["drag-ctrl-left",Xo.panDrag],["drag-ctrl-right",Xo.zRotateDrag],["drag-shift-left",Xo.zoomDrag],["drag-middle",Xo.zoomFocusDrag],["drag-ctrl-shift-right",Xo.panComponentDrag],["drag-ctrl-shift-left",Xo.rotateComponentDrag],["clickPick-right",Xo.measurePick],["clickPick-ctrl-left",Xo.measurePick],["clickPick-middle",Xo.movePick],["clickPick-left",Xo.movePick],["hoverPick",Xo.tooltipPick]],pymol:[["drag-left",Xo.rotateDrag],["drag-middle",Xo.panDrag],["drag-right",Xo.zoomDrag],["scroll",Xo.focusScroll],["drag-shift-right",Xo.focusScroll],["clickPick-ctrl+shift-middle",Xo.movePick],["hoverPick",Xo.tooltipPick]],coot:[["scroll",Xo.isolevelScroll],["drag-left",Xo.rotateDrag],["drag-middle",Xo.panDrag],["drag-ctrl-left",Xo.panDrag],["drag-right",Xo.zoomFocusDrag],["drag-ctrl-right",Xo.focusScroll],["clickPick-middle",Xo.movePick],["hoverPick",Xo.tooltipPick]],astexviewer:[["drag-left",Xo.rotateDrag],["drag-ctrl-left",Xo.panDrag],["drag-shift-left",Xo.zoomDrag],["scroll",Xo.focusScroll],["clickPick-middle",Xo.movePick],["hoverPick",Xo.tooltipPick]]};function Ko(t){const e=t.split(/[-+]/);let i="";e.includes("scroll")&&(i="scroll"),e.includes("drag")&&(i="drag"),e.includes("click")&&(i="click"),e.includes("doubleClick")&&(i="doubleClick"),e.includes("hover")&&(i="hover"),e.includes("clickPick")&&(i="clickPick"),e.includes("hoverPick")&&(i="hoverPick");let r=0;e.includes("alt")&&(r+=1),e.includes("ctrl")&&(r+=2),e.includes("meta")&&(r+=4),e.includes("shift")&&(r+=8);let n=0;return e.includes("left")&&(n+=1),e.includes("right")&&(n+=2),e.includes("middle")&&(n+=4),[i,r,n]}class Zo{constructor(t,e={}){this.stage=t,this.actionList=[],this.mouse=t.mouseObserver,this.disabled=e.disabled||!1,this.preset(e.preset||"default")}run(t,...e){if(this.disabled)return;const i=this.mouse.key||0,r=this.mouse.buttons||0;this.actionList.forEach((n=>{n.type===t&&n.key===i&&n.button===r&&n.callback(this.stage,...e)}))}add(t,e){const[i,r,n]=Ko(t);this.actionList.push({type:i,key:r,button:n,callback:e})}remove(t,e){const i=t.includes("*"),[r,n,s]=Ko(t),o=this.actionList.filter((function(t){return!((t.type===r||i&&""===r)&&(t.key===n||i&&0===n)&&(t.button===s||i&&0===s)&&(t.callback===e||void 0===e))}));this.actionList=o}preset(t){this.clear();(Yo[t]||[]).forEach((t=>this.add(t[0],t[1])))}clear(){this.actionList.length=0}}class Qo{static autoView(t){t.autoView(1e3)}static toggleAnimations(t){t.animationControls.toggle()}static toggleRock(t){t.toggleRock()}static toggleSpin(t){t.toggleSpin()}static toggleAntialiasing(t){const e=t.getParameters();t.setParameters({sampleLevel:-1===e.sampleLevel?0:-1})}}const Jo={default:[["i",Qo.toggleSpin],["k",Qo.toggleRock],["p",Qo.toggleAnimations],["a",Qo.toggleAntialiasing],["r",Qo.autoView]]};class ta{constructor(t,e={}){this.stage=t,this.actionList=[],this.disabled=e.disabled||!1,this.preset(e.preset||"default")}run(t){this.disabled||this.actionList.forEach((e=>{e.key===t&&e.callback(this.stage)}))}add(t,e){this.actionList.push({key:t,callback:e})}remove(t,e){const i=this.actionList.filter((function(i){return!(i.key===t&&(i.callback===e||void 0===e))}));this.actionList=i}preset(t){this.clear();(Jo[t]||[]).forEach((t=>this.add(t[0],t[1])))}clear(){this.actionList.length=0}}class ea{constructor(t){this.stage=t,this.stage=t,this.mouse=t.mouseObserver,this.controls=t.mouseControls,this.mouse.signals.clicked.add(this._onClick,this),this.mouse.signals.hovered.add(this._onHover,this)}_onClick(t,e){const i=this.stage.pickingControls.pick(t,e);this.stage.signals.clicked.dispatch(i),this.controls.run("clickPick",i)}_onHover(t,e){const i=this.stage.pickingControls.pick(t,e);i&&this.mouse.down.equals(this.mouse.position)&&(this.stage.transformComponent=i.component,this.stage.transformAtom=i.atom),this.stage.signals.hovered.dispatch(i),this.controls.run("hoverPick",i)}dispose(){this.mouse.signals.clicked.remove(this._onClick,this),this.mouse.signals.hovered.remove(this._onHover,this)}}class ia{constructor(t){this.stage=t,this.stage=t,this.mouse=t.mouseObserver,this.controls=t.mouseControls,this.mouse.signals.moved.add(this._onMove,this),this.mouse.signals.scrolled.add(this._onScroll,this),this.mouse.signals.dragged.add(this._onDrag,this),this.mouse.signals.clicked.add(this._onClick,this),this.mouse.signals.hovered.add(this._onHover,this),this.mouse.signals.doubleClicked.add(this._onDblclick,this)}_onMove(){this.stage.tooltip.style.display="none"}_onScroll(t){this.controls.run("scroll",t)}_onDrag(t,e){this.controls.run("drag",t,e)}_onClick(t,e){this.controls.run("click",t,e)}_onDblclick(t,e){this.controls.run("doubleClick",t,e)}_onHover(t,e){this.controls.run("hover",t,e)}dispose(){this.mouse.signals.moved.remove(this._onMove,this),this.mouse.signals.scrolled.remove(this._onScroll,this),this.mouse.signals.dragged.remove(this._onDrag,this),this.mouse.signals.clicked.remove(this._onClick,this),this.mouse.signals.hovered.remove(this._onHover,this)}}class ra{constructor(t){this.stage=t,this.viewer=t.viewer,this.animationControls=t.animationControls,this.viewer.signals.ticked.add(this._onTick,this)}_onTick(t){this.animationControls.run(t)}dispose(){this.viewer.signals.ticked.remove(this._onTick,this)}}const na=!!ve&&{passive:!0};class sa{constructor(t){this.stage=t,this.stage=t,this.controls=t.keyControls,this.domElement=t.viewer.renderer.domElement,this.domElement.setAttribute("tabIndex","-1"),this.domElement.style.outline="none",this._focusDomElement=this._focusDomElement.bind(this),this._onKeydown=this._onKeydown.bind(this),this._onKeyup=this._onKeyup.bind(this),this._onKeypress=this._onKeypress.bind(this),this.domElement.addEventListener("mousedown",this._focusDomElement),this.domElement.addEventListener("touchstart",this._focusDomElement,na),this.domElement.addEventListener("keydown",this._onKeydown),this.domElement.addEventListener("keyup",this._onKeyup),this.domElement.addEventListener("keypress",this._onKeypress)}_onKeydown(){}_onKeyup(){}_onKeypress(t){let e;e="key"in KeyboardEvent.prototype?t.key:String.fromCharCode(t.which||t.keyCode),this.controls.run(e)}_focusDomElement(){this.domElement.focus()}dispose(){this.domElement.removeEventListener("mousedown",this._focusDomElement),this.domElement.removeEventListener("touchstart",this._focusDomElement,na),this.domElement.removeEventListener("keydown",this._onKeypress),this.domElement.removeEventListener("keyup",this._onKeypress),this.domElement.removeEventListener("keypress",this._onKeypress)}}class oa{constructor(i,r,n,s={}){this.component=i,this.position=r,this.offsetX=rt(s.offsetX,0),this.offsetY=rt(s.offsetY,0),this.visible=rt(s.visible,!0),this.stage=i.stage,this.viewer=i.stage.viewer,this._viewerPosition=new e,this._updateViewerPosition(),this._canvasPosition=new t,this._cameraPosition=new e,this.element=document.createElement("div"),Object.assign(this.element.style,{display:"block",position:"absolute",pointerEvents:"none",whiteSpace:"nowrap",left:"-10000px"}),this.viewer.wrapper.appendChild(this.element),this.setContent(n),this.updateVisibility(),this.viewer.signals.rendered.add(this._update,this),this.component.signals.matrixChanged.add(this._updateViewerPosition,this)}setContent(t){const e=this.element.style.display;if("none"===e&&(this.element.style.left="-10000px",this.element.style.display="block"),t instanceof HTMLElement)this.element.appendChild(t);else{const e=document.createElement("div");e.innerText=t,Object.assign(e.style,{backgroundColor:"rgba( 0, 0, 0, 0.6 )",color:"lightgrey",padding:"8px",fontFamily:"sans-serif"}),this.element.appendChild(e)}this._clientRect=this.element.getBoundingClientRect(),"none"===e&&(this.element.style.display=e)}setVisibility(t){this.visible=t,this.updateVisibility()}getVisibility(){return this.visible&&this.component.parameters.visible}updateVisibility(){this.element.style.display=this.getVisibility()?"block":"none"}_updateViewerPosition(){this._viewerPosition.copy(this.position).applyMatrix4(this.component.matrix)}_update(){if(!this.getVisibility())return;const t=this.element.style,e=this._canvasPosition,i=this._viewerPosition,r=this._clientRect;if(this._cameraPosition.copy(i).add(this.viewer.translationGroup.position).applyMatrix4(this.viewer.rotationGroup.matrix).sub(this.viewer.camera.position),this._cameraPosition.z<0)return void(t.display="none");t.display="block";const n=this._cameraPosition.length(),s=this.viewer.scene.fog;t.opacity=(1-Ft(s.near,s.far,n)).toString(),t.zIndex=Math.round(100*(s.far-n)).toString(),this.stage.viewerControls.getPositionOnCanvas(i,e),t.bottom=this.offsetX+e.y+r.height/2+"px",t.left=this.offsetY+e.x-r.width/2+"px"}dispose(){this.viewer.wrapper.removeChild(this.element),this.viewer.signals.ticked.remove(this._update,this),this.component.signals.matrixChanged.remove(this._updateViewerPosition,this)}}const aa=new i,ca=new e,la=new r;class ha{constructor(t){this.component=t,this.signals={changed:new J.Signal},this.stage=t.stage,this.viewer=t.stage.viewer}get position(){return this.component.position}get rotation(){return this.component.quaternion}changed(){this.component.updateMatrix(),this.viewer.requestRender(),this.signals.changed.dispatch()}spin(t,e){aa.copy(this.viewer.rotationGroup.matrix).invert(),ca.copy(xt(t)).applyMatrix4(aa),aa.extractRotation(this.component.transform),aa.premultiply(this.viewer.rotationGroup.matrix),aa.invert(),ca.copy(xt(t)),ca.applyMatrix4(aa),aa.makeRotationAxis(ca,e),la.setFromRotationMatrix(aa),this.component.quaternion.premultiply(la),this.changed()}}const ua={"":"",vdw:"by vdW radius",covalent:"by covalent radius",sstruc:"by secondary structure",bfactor:"by bfactor",size:"size",data:"data",explicit:"explicit"};class da{constructor(t={}){this.max=10,this.type=rt(t.type,"size"),this.scale=rt(t.scale,1),this.size=rt(t.size,1),this.data=rt(t.data,{})}atomRadius(t){let e;switch(this.type){case"vdw":e=t.vdw;break;case"covalent":e=t.covalent;break;case"bfactor":e=t.bfactor||1;break;case"sstruc":const i=t.sstruc;e="h"===i||"g"===i||"i"===i||"e"===i||"b"===i?.25:hs.includes(t.atomname)?.4:.1;break;case"data":e=rt(this.data[t.index],1);break;case"explicit":e=t.radius,null===e&&(e=this.size);break;default:e=this.size}return Math.min(e*this.scale,this.max)}}da.types=ua;const ma=new e(-1,-1,-1),fa=new i;class pa{constructor(t){const i=t.rows,r=i/3,n=new co(i,3),s=new co(3,3),o=new co(1,3),a=new co(3,3),c=new co(3,3),l=mo(t);fo(t,l),lo(n,t),ho(s,n,n),_o(s,o,a,c);const h=new e(l[0],l[1],l[2]),u=new e(a.data[0],a.data[3],a.data[6]),d=new e(a.data[1],a.data[4],a.data[7]),m=new e(a.data[2],a.data[5],a.data[8]),f=u.clone().multiplyScalar(Math.sqrt(o.data[0]/r)),p=d.clone().multiplyScalar(Math.sqrt(o.data[1]/r)),g=m.clone().multiplyScalar(Math.sqrt(o.data[2]/r));this.begA=h.clone().sub(f),this.endA=h.clone().add(f),this.begB=h.clone().sub(p),this.endB=h.clone().add(p),this.begC=h.clone().sub(g),this.endC=h.clone().add(g),this.center=h,this.vecA=f,this.vecB=p,this.vecC=g,this.normVecA=u,this.normVecB=d,this.normVecC=m}getBasisMatrix(t=new i){const e=t;return e.makeBasis(this.normVecB,this.normVecA,this.normVecC),e.determinant()<0&&e.scale(ma),e}getRotationQuaternion(t=new r){const e=t;return e.setFromRotationMatrix(this.getBasisMatrix(fa)),e.invert()}getProjectedScaleForAtoms(t){let i=-1/0,r=-1/0,n=-1/0,s=-1/0,o=-1/0,a=-1/0;const c=new e,l=new e,h=this.center,u=this.normVecA,d=this.normVecB,m=this.normVecC;return t.eachAtom((function(t){Vr(c.copy(t),u,h);const e=l.subVectors(c,h).normalize().dot(u),f=c.distanceTo(h);e>0?f>i&&(i=f):f>r&&(r=f),Vr(c.copy(t),d,h);const p=l.subVectors(c,h).normalize().dot(d),g=c.distanceTo(h);p>0?g>n&&(n=g):g>s&&(s=g),Vr(c.copy(t),m,h);const y=l.subVectors(c,h).normalize().dot(m),b=c.distanceTo(h);y>0?b>o&&(o=b):b>a&&(a=b)})),{d1a:i,d2a:n,d3a:o,d1b:-r,d2b:-s,d3b:-a}}}class ga{constructor(t,e,i,r){this.volume=t,this.setFilter(e,i,r)}get header(){return this.volume.header}get matrix(){return this.volume.matrix}get normalMatrix(){return this.volume.normalMatrix}get inverseMatrix(){return this.volume.inverseMatrix}get center(){return this.volume.center}get boundingBox(){return this.volume.boundingBox}get min(){return this.volume.min}get max(){return this.volume.max}get mean(){return this.volume.mean}get rms(){return this.volume.rms}_getFilterHash(t,e,i){return JSON.stringify([t,e,i])}setFilter(t,e,i){isNaN(t)&&this.header&&(t=this.header.DMEAN+2*this.header.ARMS),t=void 0===t||isNaN(t)?-1/0:t,e=rt(e,1/0),i=rt(i,!1);const r=this.volume.data,n=this.volume.position,s=this.volume.atomindex,o=this._getFilterHash(t,e,i);if(o!==this._filterHash){if(t===-1/0&&e===1/0)this.data=r,this.position=n,this.atomindex=s;else{const o=r.length;this._dataBuffer||(this._dataBuffer=new ArrayBuffer(4*o),this._positionBuffer=new ArrayBuffer(3*o*4),s&&(this._atomindexBuffer=new ArrayBuffer(4*o)));const a=new Float32Array(this._dataBuffer),c=new Float32Array(this._positionBuffer);let l;s&&(l=new Uint32Array(this._atomindexBuffer));let h=0;for(let u=0;u=t&&d<=e||i&&(de)){const t=3*h;a[h]=d,c[t+0]=n[o+0],c[t+1]=n[o+1],c[t+2]=n[o+2],s&&l&&(l[h]=s[u]),h+=1}}this.data=new Float32Array(this._dataBuffer,0,h),this.position=new Float32Array(this._positionBuffer,0,3*h),s&&(this.atomindex=new Int32Array(this._atomindexBuffer,0,h))}this._filterHash=o}}}ga.prototype.getValueForSigma=Eo.prototype.getValueForSigma,ga.prototype.getSigmaForValue=Eo.prototype.getSigmaForValue,ga.prototype.getDataAtomindex=Eo.prototype.getDataAtomindex,ga.prototype.getDataPosition=Eo.prototype.getDataPosition,ga.prototype.getDataColor=Eo.prototype.getDataColor,ga.prototype.getDataPicking=Eo.prototype.getDataPicking,ga.prototype.getDataSize=Eo.prototype.getDataSize;class ya{constructor(t,e){const i=En({nodeArray1:t.atomIndex1,nodeArray2:t.atomIndex2,edgeCount:t.count,nodeCount:e});this.countArray=i.countArray,this.offsetArray=i.offsetArray,this.indexArray=i.indexArray}}class ba extends Tn{get _defaultFields(){return[["atomIndex1",1,"int32"],["atomIndex2",1,"int32"],["bondOrder",1,"int8"]]}addBond(t,e,i){this.growIfFull();const r=this.count,n=t.index,s=e.index;n0&&(a[e]=x.angleTo(v));const r=Math.cos(p.angleTo(g));h[e]=180/Math.PI*Math.acos(r);const n=p.length(),_=g.length();c[e]=Math.sqrt(_*n)/Math.max(2,2*(1-r)),l[e]=Math.abs(m.dot(x)),y.copy(p).multiplyScalar(c[e]/n),b.copy(g).multiplyScalar(c[e]/_),y.subVectors(P,y),b.subVectors(I,b),y.toArray(s,i+3),b.toArray(s,i+6),w.subVectors(C,A),w.toArray(u,i),v.copy(x),A.copy(y)}y.fromArray(s,3),b.fromArray(s,6),x.subVectors(y,b).normalize(),C.index=t.getAtomIndexByType(0,S),A.copy(C),_.copy(C),Vr(_,x,y),_.toArray(s,0),w.subVectors(A,y),w.toArray(u,0),y.fromArray(s,3*r-6),b.fromArray(s,3*r-9),x.subVectors(y,b).normalize(),C.index=t.getAtomIndexByType(r-1,S),A.copy(C),_.copy(C),Vr(_,x,y),_.toArray(s,3*r-3);for(let e=r-3;ei||h.bending[e]>t)&&(O=!0)),O){if(e-f<4){f=e,O=!1;continue}F.index=D.traceAtomIndex,I=h.axis.subarray(3*f+3,3*e),k=h.center.subarray(3*f,3*e+3),C=Ur(I).normalize(),P=Ur(k),M.fromArray(k),Vr(M,C,P),T.fromArray(k,k.length-3),Vr(T,C,P),C.subVectors(T,M),C.toArray(g,p),P.toArray(y,p),M.toArray(b,p),T.toArray(_,p),d.atomColorToArray(F,x,p),v.push(F.index),w.push(m.atomRadius(F)),A.push(l+f),S.push(l+e+1-f),p+=3,f=e,O=!1}const R=new Float32Array(v);return{axis:new Float32Array(g),center:new Float32Array(y),begin:new Float32Array(b),end:new Float32Array(_),color:new Float32Array(x),picking:new Ws(R,a),size:new Float32Array(w),residueOffset:A,residueCount:S}}}class Ca{constructor(t){this.scoreFunction=t,this.content=[],this.scoreFunction=t}push(t){this.content.push(t),this.bubbleUp(this.content.length-1)}pop(){const t=this.content[0],e=this.content.pop();return e&&this.content.length>0&&(this.content[0]=e,this.sinkDown(0)),t}peek(){return this.content[0]}remove(t){const e=this.content.length;for(let i=0;i0;){const i=Math.floor((t+1)/2)-1,r=this.content[i];if(!(this.scoreFunction(e)this.maxDepth&&(this.maxDepth=t);const n=r-i;if(0===n)return-1;const s=4*this.currentNode,o=this.nodes;if(this.currentNode+=1,1===n)return o[s]=i,o[s+1]=-1,o[s+2]=-1,o[s+3]=e,s;const a=this.indices,c=this.points,l=i+Math.floor(n/2),h=t%3;let u,d,m,f,p,g=i,y=r-1;for(;y>g;){for(m=g+y>>1,f=c[3*a[m]+h],d=a[m],a[m]=a[y],a[y]=d,p=g,u=g;u-t[1])),n=this.nodes,s=this.points,o=this.indices,a=c=>{let l,h;const u=this.getNodeDepth(c)%3,d=3*o[n[c]],m=[s[d+0],s[d+1],s[d+2]],f=this.metric(t,m);function p(t,i){r.push([t,i]),r.size()>e&&r.pop()}const g=n[c+1],y=n[c+2];if(-1===y&&-1===g)return void((r.size()s[3*o[n[t]]+r])throw new Error("left child is > parent!");i+=this.verify(a,e+1)}if(-1!==c){if(s[3*o[n[c]]+r]0}isBackbone(){const t=this.residueType.backboneIndexList;return t.length>0&&t.includes(this.index-this.residueAtomOffset)}isPolymer(){if(this.structure.entityList.length>0)return this.entity.isPolymer();{const t=this.residueType.moleculeType;return 3===t||4===t||5===t}}isSidechain(){return this.isPolymer()&&!this.isBackbone()}isCg(){const t=this.residueType.backboneType;return 4===t||5===t||6===t}isTrace(){return this.index===this.residueType.traceAtomIndex+this.residueAtomOffset}isHetero(){return 1===this.residueType.hetero}isProtein(){return 3===this.residueType.moleculeType}isNucleic(){const t=this.residueType.moleculeType;return 4===t||5===t}isRna(){return 4===this.residueType.moleculeType}isDna(){return 5===this.residueType.moleculeType}isWater(){return 1===this.residueType.moleculeType}isIon(){return 2===this.residueType.moleculeType}isSaccharide(){return 6===this.residueType.moleculeType}isHelix(){return Hn.includes(this.sstruc)}isSheet(){return qn.includes(this.sstruc)}isTurn(){return Wn.includes(this.sstruc)&&this.isProtein()}isBonded(){return 0!==this.bondHash.countArray[this.index]}isRing(){return void 0!==this.residueType.getRings().atomRings[this.index-this.residueAtomOffset]}isAromatic(){return 1===this.aromatic}isPolarHydrogen(){let t=!1;return 1!==this.number||(t=!this.hasBondToElement(6)),t}isMetal(){return this.atomType.isMetal()}isNonmetal(){return this.atomType.isNonmetal()}isMetalloid(){return this.atomType.isMetalloid()}isHalogen(){return this.atomType.isHalogen()}isDiatomicNonmetal(){return this.atomType.isDiatomicNonmetal()}isPolyatomicNonmetal(){return this.atomType.isPolyatomicNonmetal()}isAlkaliMetal(){return this.atomType.isAlkaliMetal()}isAlkalineEarthMetal(){return this.atomType.isAlkalineEarthMetal()}isNobleGas(){return this.atomType.isNobleGas()}isTransitionMetal(){return this.atomType.isTransitionMetal()}isPostTransitionMetal(){return this.atomType.isPostTransitionMetal()}isLanthanide(){return this.atomType.isLanthanide()}isActinide(){return this.atomType.isActinide()}getDefaultValence(){return this.atomType.getDefaultValence()}getValenceList(){return this.atomType.getValenceList()}getOuterShellElectronCount(){return this.atomType.getOuterShellElectronCount()}distanceTo(t){const e=this.atomStore,i=t.atomStore,r=this.index,n=t.index,s=e.x[r]-i.x[n],o=e.y[r]-i.y[n],a=e.z[r]-i.z[n],c=s*s+o*o+a*a;return Math.sqrt(c)}connectedTo(t){const e=this.atomStore,i=t.atomStore,r=this.index,n=t.index;if(e.altloc&&i.altloc){const t=e.altloc[r],s=i.altloc[n];if(0!==t&&0!==s&&32!==t&&32!==s&&t!==s)return!1}const s=e.x[r]-i.x[n],o=e.y[r]-i.y[n],a=e.z[r]-i.z[n],c=s*s+o*o+a*a;if(c<48&&this.isCg())return!0;if(isNaN(c))return!1;const l=this.covalent+t.covalent,h=l+.3,u=l-.5;return cu*u}positionFromArray(t,e=0){return this.x=t[e+0],this.y=t[e+1],this.z=t[e+2],this}positionToArray(t=[],e=0){const i=this.index,r=this.atomStore;return t[e+0]=r.x[i],t[e+1]=r.y[i],t[e+2]=r.z[i],t}positionToVector3(t){return void 0===t&&(t=new e),t.x=this.x,t.y=this.y,t.z=this.z,t}positionFromVector3(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}positionAdd(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}positionSub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}getResidueBonds(t=!1){const e=this.residueAtomOffset,i=this.index-this.residueAtomOffset,r=this.residueType.getBonds(),n=r.atomIndices1,s=r.atomIndices2;let o,a,c,l;for(t||(l=[]),o=n.indexOf(i);-1!==o;){if(c=s[o]+e,!l)return c;l.push(c),o=n.indexOf(i,o+1)}for(a=s.indexOf(i);-1!==a;){if(c=n[a]+e,!l)return c;l.push(c),a=s.indexOf(i,a+1)}return l}qualifiedName(t=!1){var e="";return this.resname&&!t&&(e+="["+this.resname+"]"),void 0!==this.resno&&(e+=this.resno),this.inscode&&(e+="^"+this.inscode),this.chainname&&(e+=":"+this.chainname),this.atomname&&(e+="."+this.atomname),this.altloc&&(e+="%"+this.altloc),this.structure.modelStore.count>1&&(e+="/"+this.modelIndex),e}clone(){return new ka(this.structure,this.index)}toObject(){return{index:this.index,residueIndex:this.residueIndex,resname:this.resname,x:this.x,y:this.y,z:this.z,element:this.element,chainname:this.chainname,resno:this.resno,serial:this.serial,vdw:this.vdw,covalent:this.covalent,hetero:this.hetero,bfactor:this.bfactor,altloc:this.altloc,atomname:this.atomname,modelIndex:this.modelIndex}}}function Ma(t,e){const i=t[0]-e[0],r=t[1]-e[1],n=t[2]-e[2];return i*i+r*r+n*n}function Ta(t,e){return Math.sqrt(Ma(t,e))}const Da=new Float32Array(3);class Ba{constructor(t,e=!1){De&&ke.time("Kdtree build");const i=e?Ma:Ta,r=new Float32Array(3*t.atomCount),n=new Uint32Array(t.atomCount);let s=0;t.eachAtom((function(t){r[s+0]=t.x,r[s+1]=t.y,r[s+2]=t.z,n[s/3]=t.index,s+=3})),this.atomIndices=n,this.points=r,this.kdtree=new Ia(r,i),De&&ke.timeEnd("Kdtree build")}nearest(t,i,r){t instanceof e?t.toArray(Da):t instanceof ka&&t.positionToArray(Da);const n=this.kdtree.nearest(Da,i,r),s=this.kdtree.indices,o=this.kdtree.nodes,a=this.atomIndices,c=[];for(let t=0,e=n.length;t":"3/4-Z","?":"X-Y","@":"Y-X",A:"Z+1/3",B:"Z+2/3",C:"X+2/3",D:"Y+1/3",E:"-Y+2/3",F:"X-Y+1/3",G:"Y-X+2/3",H:"-X+1/3",I:"X+1/3",J:"Y+2/3",K:"-Y+1/3",L:"X-Y+2/3",M:"Y-X+1/3",N:"-X+2/3",O:"2/3+X",P:"1/3+Y",Q:"1/3+Z",R:"2/3-Y",S:"1/3+X-Y",T:"2/3+Y-X",U:"1/3-X",V:"2/3-X",W:"1/3-Y",X:"1/3-Z",Y:"2/3+Y",Z:"1/3+Y-X","[":"2/3+X-Y","]":"1/3+X","^":"2/3+Z",_:"2/3-Z","`":"5/6+Z",a:"1/6+Z",b:"5/6-Z",c:"1/6-Z",d:"Z+5/6",e:"Z+1/6",f:"Z+1/4",g:"+Y"},Ea={"P 1":" !#","P -1":" !#$%&","P 1 2 1":" !#$!&","P 1 21 1":" !#$'&","C 1 2 1":" !#$!&()#*)&","P 1 m 1":" !# %#","P 1 c 1":" !# %+","C 1 m 1":" !# %#()#(,#","C 1 c 1":" !# %+()#(,+","P 1 2/m 1":" !# %#$!&$%&","P 1 21/m 1":" !#$)&$%& ,#","C 1 2/m 1":" !# %#$!&$%&()#(,#*)&*,&","P 1 2/c 1":" !#$!-$%& %+","P 1 21/c 1":" !#$%&$)- ,+","C 1 2/c 1":" !#$!-$%& %+()#*)-*,&(,+","P 2 2 2":" !#$%#$!& %&","P 2 2 21":" !#$%+$!- %&","P 21 21 2":" !#$%#*)&(,&","P 21 21 21":" !#*%+$)-(,&","C 2 2 21":" !#$%+$!- %&()#*,+*)-(,&","C 2 2 2":" !#$%#$!& %&()#*,#*)&(,&","F 2 2 2":" !#$%#$!& %& )+$,+$)- ,-(!+*%+*!-(%-()#*,#*)&(,&","I 2 2 2":" !#$%# %&$!&.'/01/.120'2","I 21 21 21":" !#*%+$)-(,&()+$,#*!& %-","P m m 2":" !#$%# %#$!#","P m c 21":" !#$%+ %+$!#","P c c 2":" !#$%# %+$!+","P m a 2":" !#$%#(%#*!#","P c a 21":" !#$%+(%#*!+","P n c 2":" !#$%# ,+$)+","P m n 21":" !#*%+(%+$!#","P b a 2":" !#$%#(,#*)#","P n a 21":" !#$%+(,#*)+","P n n 2":" !#$%#(,+*)+","C m m 2":" !#$%# %#$!#()#*,#(,#*)#","C m c 21":" !#$%+ %+$!#()#*,+(,+*)#","C c c 2":" !#$%# %+$!+()#*,#(,+*)+","A m m 2":" !#$%# %#$!# )+$,+ ,+$)+","A b m 2":" !#$%# ,#$)# )+$,+ %+$!+","A m a 2":" !#$%#(%#*!# )+$,+(,+*)+","A b a 2":" !#$%#(,#*)# )+$,+(%+*!+","F m m 2":" !#$%# %#$!# )+$,+ ,+$)+(!+*%+(%+*!+()#*,#(,#*)#","F d d 2":" !#$%#345675 )+$,+3896:9(!+*%+;49<79()#*,#;85<:5","I m m 2":" !#$%# %#$!#()+*,+(,+*)+","I b a 2":" !#$%#(,#*)#()+*,+ %+$!+","I m a 2":" !#$%#(%#*!#()+*,+ ,+$)+","P 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!#","P 2/n 2/n 2/n":" !#$%#$!& %&*,-()-(,+*)+","P 2/c 2/c 2/m":" !#$%#$!- %-$%& !& %+$!+","P 2/b 2/a 2/n":" !#$%#$!& %&*,&()&(,#*)#","P 21/m 2/m 2/a":" !#*%#$!&(%&$%&(!& %#*!#","P 2/n 21/n 2/a":" !#*%#*)- ,-$%&(!&(,+$)+","P 2/m 2/n 21/a":" !#*%+*!- %&$%&(!-(%+$!#","P 21/c 2/c 2/a":" !#*%#$!-(%-$%&(!& %+*!+","P 21/b 21/a 2/m":" !#$%#*)&(,&$%& !&(,#*)#","P 21/c 21/c 2/n":" !#*,#$)-(%-$%&()& ,+*!+","P 2/b 21/c 21/m":" !#$%+$)- ,&$%& !- ,+$)#","P 21/n 21/n 2/m":" !#$%#*)-(,-$%& !&(,+*)+","P 21/m 21/m 2/n":" !#$%#*'&.,&*,&.'& %#$!#","P 21/b 2/c 21/n":" !#*,+$!-(,&$%&()- %+*)#","P 21/b 21/c 21/a":" !#*%+$)-(,&$%&(!- ,+*)#","P 21/n 21/m 21/a":" !#0%/$'&.12$%&.!2 1#0'/","C 2/m 2/c 21/m":" !#$%+$!- %&$%& !- %+$!#()#*,+*)-(,&*,&()-(,+*)#","C 2/m 2/c 21/a":" !#$,+$)- %&$%& )- ,+$!#()#*%+*!-(,&*,&(!-(%+*)#","C 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!#()#*,#*)&(,&*,&()&(,#*)#","C 2/c 2/c 2/m":" !#$%#$!- %-$%& !& %+$!+()#*,#*)-(,-*,&()&(,+*)+","C 2/m 2/m 2/a":" !#$,#$)& %&$%& )& ,#$!#()#*%#*!&(,&*,&(!&(%#*)#","C 2/c 2/c 2/a":" !#*,#$!&(,&$,-(!- ,+*!+()#$%#*)& %&*%- )-(%+$)+","F 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!# )+$,+$)- ,-$,- )- ,+$)+(!+*%+*!-(%-*%-(!-(%+*!+()#*,#*)&(,&*,&()&(,#*)#","F 2/d 2/d 2/d":" !#$%#$!& %&64=37=345675 )+$,+$)- ,-68>3:>3896:9(!+*%+*!-(%-<4>;7>;49<79()#*,#*)&(,&<8=;:=;85<:5","I 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!#()+*,+*)-(,-*,-()-(,+*)+","I 2/b 2/a 2/m":" !#$%#*)&(,&$%& !&(,#*)#()+*,+$!- %-*,-()- %+$!+","I 21/b 21/c 21/a":" !#*%+$)-(,&$%&(!- ,+*)#()+$,#*!& %-*,- )&(%#$!+","I 21/m 21/m 21/a":" !#$,#$)& %&$%& )& ,#$!#()+*%+*!-(,-*,-(!-(%+*)+","P 4":" !#$%#% #!$#","P 41":" !#$%+% 5!$9","P 42":" !#$%#% +!$+","P 43":" !#$%+% 9!$5","I 4":" !#$%#% #!$#()+*,+,(+)*+","I 41":" !#*,+%(5)$9()+$%#, 9!*5","P -4":" !#$%#!$&% &","I -4":" !#$%#!$&% &()+*,+)*-,(-","P 4/m":" !#$%#% #!$#$%& !&!$&% &","P 42/m":" !#$%#% +!$+$%& !&!$-% -","P 4/n":" !#$%#,(#)*#*,&()&!$&% &","P 42/n":" !#$%#,(+)*+*,-()-!$&% &","I 4/m":" !#$%#% #!$#$%& !&!$&% &()+*,+,(+)*+*,-()-)*-,(-","I 41/a":" !#*,+%(5)$9$,=(!>!$&,(-()+$%#, 9!*5*%> )=)*-% &","P 4 2 2":" !#$%#% #!$#$!& %&! &%$&","P 4 21 2":" !#$%#,(#)*#*)&(,&! &%$&","P 41 2 2":" !#$%+% 5!$9$!& %-! >%$=","P 41 21 2":" !#$%+,(5)*9*)=(,>! &%$-","P 42 2 2":" !#$%#% +!$+$!& %&! -%$-","P 42 21 2":" !#$%#,(+)*+*)-(,-! &%$&","P 43 2 2":" !#$%+% 9!$5$!& %-! =%$>","P 43 21 2":" !#$%+,(9)*5*)>(,=! &%$-","I 4 2 2":" !#$%#% #!$#$!& %&! &%$&()+*,+,(+)*+*)-(,-)(-,*-","I 41 2 2":" !#*,+%(5)$9*!> ,=)(-%$&()+$%#, 9!*5$)=(%>! &,*-","P 4 m m":" !#$%#% #!$# %#$!#%$#! #","P 4 b m":" !#$%#% #!$#(,#*)#,*#)(#","P 42 c m":" !#$%#% +!$+ %+$!+%$#! #","P 42 n m":" !#$%#,(+)*+(,+*)+%$#! #","P 4 c c":" !#$%#% #!$# %+$!+%$+! +","P 4 n c":" !#$%#% #!$#(,+*)+,*+)(+","P 42 m c":" !#$%#% +!$+ %#$!#%$+! +","P 42 b c":" !#$%#% +!$+(,#*)#,*+)(+","I 4 m m":" !#$%#% #!$# %#$!#%$#! #()+*,+,(+)*+(,+*)+,*+)(+","I 4 c m":" !#$%#% #!$# %+$!+%$+! +()+*,+,(+)*+(,#*)#,*#)(#","I 41 m d":" !#*,+%(5)$9 %#*)+%*5) 9()+$%#, 9!*5(,+$!#,$9!(5","I 41 c d":" !#*,+%(5)$9 %+*)#%*9) 5()+$%#, 9!*5(,#$!+,$5!(9","P -4 2 m":" !#$%#% &!$&$!& %&%$#! #","P -4 2 c":" !#$%#% &!$&$!- %-%$+! +","P -4 21 m":" !#$%#% &!$&*)&(,&,*#)(#","P -4 21 c":" !#$%#% &!$&*)-(,-,*+)(+","P -4 m 2":" !#$%#!$&% & %#$!#! &%$&","P -4 c 2":" !#$%#% &!$& %+$!+! -%$-","P -4 b 2":" !#$%#% &!$&(,#*)#)(&,*&","P -4 n 2":" !#$%#% &!$&(,+*)+)(-,*-","I -4 m 2":" !#$%#% &!$& %#$!#! &%$&()+*,+,(-)*-(,+*)+)(-,*-","I -4 c 2":" !#$%#% &!$& %+$!+! -%$-()+*,+,(-)*-(,#*)#)(&,*&","I -4 2 m":" !#$%#% &!$&$!& %&%$#! #()+*,+,(-)*-*)-(,-,*+)(+","I -4 2 d":" !#$%#% &!$&*!>(%>,$9) 9()+*,+,(-)*-$)= ,=%*5!(5","P 4/m 2/m 2/m":" !#$%#% #!$#$!& %&! &%$&$%& !&!$&% & %#$!#%$#! #","P 4/m 2/c 2/c":" !#$%#% #!$#$!- %-! -%$-$%& !&!$&% & %+$!+%$+! +","P 4/n 2/b 2/m":" !#$%#% #!$#$!& %&! &%$&*,&()&)*&,(&(,#*)#,*#)(#","P 4/n 2/n 2/c":" !#$%#% #!$#$!& %&! &%$&*,-()-)*-,(-(,+*)+,*+)(+","P 4/m 21/b 2/m":" !#$%#% #!$#*)&(,&)(&,*&$%& !&!$&% &(,#*)#,*#)(#","P 4/m 21/n 2/c":" !#$%#% #!$#*)-(,-)(-,*-$%& !&!$&% &(,+*)+,*+)(+","P 4/n 21/m 2/m":" !#$%#,(#)*#*)&(,&! &%$&*,&()&!$&% & %#$!#,*#)(#","P 4/n 2/c 2/c":" !#$%#,(#)*#*)-(,-! -%$-*,&()&!$&% & %+$!+,*+)(+","P 42/m 2/m 2/c":" !#$%#% +!$+$!& %&! -%$-$%& !&!$-% - %#$!#%$+! +","P 42/m 2/c 2/m":" !#$%#% +!$+$!- %-! &%$&$%& !&!$-% - %+$!+%$#! #","P 42/n 2/b 2/c":" !#$%#,(+)*+$!- %-)(&,*&*,-()-!$&% &(,#*)#%$+! +","P 42/n 2/n 2/m":" !#$%#,(+)*+$!& %&)(-,*-*,-()-!$&% &(,+*)+%$#! #","P 42/m 21/b 2/c":" !#$%#% +!$+*)&(,&)(-,*-$%& !&!$-% -(,#*)#,*+)(+","P 42/m 21/n 2/m":" !#$%#,./'*/*'-.,-! &%$&$%& !&'*-,.-.,/*'/%$#! #","P 42/n 21/m 2/c":" !#$%#,(+)*+*)-(,-! &%$&*,-()-!$&% & %#$!#,*+)(+","P 42/n 21/c 2/m":" !#$%#,(+)*+*)&(,&! -%$-*,-()-!$&% & %+$!+,*#)(#","I 4/m 2/m 2/m":" !#$%#% #!$#$!& %&! &%$&$%& !&!$&% & %#$!#%$#! #()+*,+,(+)*+*)-(,-)(-,*-*,-()-)*-,(-(,+*)+,*+)(+","I 4/m 2/c 2/m":" !#$%#% #!$#$!- %-! -%$-$%& !&!$&% & %+$!+%$+! +()+*,+,(+)*+*)&(,&)(&,*&*,-()-)*-,(-(,#*)#,*#)(#","I 41/a 2/m 2/d":" !#*,+%(5)$9*!> ,=)(-%$&$,=(!>!$&,(-(,+$!#,$9!(5()+$%#, 9!*5$)=(%>! &,*-*%> )=)*-% & %#*)+%*5) 9","I 41/a 2/c 2/d":" !#*,+%(5)$9*!= ,>)(&%$-$,=(!>!$&,(-(,#$!+,$5!(9()+$%#, 9!*5$)>(%=! -,*&*%> )=)*-% & %+*)#%*9) 5","P 3":" !#%?#@$#","P 31":" !#%?A@$B","P 32":" !#%?B@$A","H 3":" !#%?#@$#CDAEFAGHAIJBKLBMNB","R 3":" !## !!# ","P -3":" !#%?#@$#$%&!@&? &","H -3":" !#%?#@$#$%&!@&? &OPQRSQTUQVWXYZX[]X]Y^W[^ZV^UR_PT_SO_","R -3":" !## !!# $%&&$%%&$","P 3 1 2":" !#%?#@$#%$&@!& ?&","P 3 2 1":" !#%?#@$#! &?%&$@&","P 31 1 2":" !#%?Q@$^%$_@!X ?&","P 31 2 1":" !#%?A@$B! &?%_$@X","P 32 1 2":" !#%?^@$Q%$X@!_ ?&","P 32 2 1":" !#%?B@$A! &?%X$@_","H 3 2":" !#%?#@$#! &?%&$@&OPQRSQTUQY]X[WXVZX]Y^W[^ZV^PO_SR_UT_","R 3 2":" !## !!# %$&$&%&%$","P 3 m 1":" !#%?#@$#%$#@!# ?#","P 3 1 m":" !#%?#@$#! #?%#$@#","P 3 c 1":" !#%?#@$#%$+@!+ ?+","P 3 1 c":" !#%?#@$#! +?%+$@+","H 3 m":" !#%?#@$#%$#@!# ?#OPQRSQTUQRUQTPQOSQ]Y^W[^ZV^WV^ZY^][^","R 3 m":" !## !!# ! # #!#! ","H 3 c":" !#%?#@$#%$+@!+ ?+OPQRSQTUQRU`TP`OS`]Y^W[^ZV^WVaZYa][a","R 3 c":" !## !!# '././'/'.","P -3 1 2/m":" !#%?#@$#%$&@!& ?&$%&!@&? &! #?%#$@#","P -3 1 2/c":" !#%?#@$#%$-@!- ?-$%&!@&? &! +?%+$@+","P -3 2/m 1":" !#%?#@$#! &?%&$@&$%&!@&? &%$#@!# ?#","P -3 2/c 1":" !#%?#@$#! -?%-$@-$%&!@&? &%$+@!+ ?+","H -3 2/m":" !#%?#@$#! &?%&$@&$%&!@&? &%$#@!# ?#OPQRSQTUQY]X[WXVZXVWXYZX[]XRUQTPQOSQ]Y^W[^ZV^PO_SR_UT_UR_PT_SO_WV^ZY^][^","R -3 2/m":" !## !!# %$&$&%&%$$%&&$%%&$! # #!#! ","H -3 2/c":" !#%?#@$#! -?%-$@-$%&!@&? &%$+@!+ ?+OPQRSQTUQY]b[WbVZbVWXYZX[]XRU`TP`OS`]Y^W[^ZV^POcSRcUTcUR_PT_SO_WVaZYa][a","R -3 2/c":" !## !!# 102021210$%&&$%%&$'././'/'.","P 6":" !#%?#@$#$%#!@#? #","P 61":" !#%?A@$B$%/!@d? e","P 65":" !#%?B@$A$%/!@e? d","P 62":" !#%?^@$Q$%#!@^? Q","P 64":" !#%?Q@$^$%#!@Q? ^","P 63":" !#%?#@$#$%+!@+? +","P -6":" !#%?#@$# !&%?&@$&","P 6/m":" !#%?#@$#$%#!@#? #$%&!@&? & !&%?&@$&","P 63/m":" !#%?#@$#$%+!@+? +$%&!@&? & !-%?-@$-","P 6 2 2":" !#%?#@$#$%#!@#? #! &?%&$@&%$&@!& ?&","P 61 2 2":" !#%?Q@$^$%+!@`? a! X?%&$@_%$b@!- ?c","P 65 2 2":" !#%?^@$Q$%+!@a? `! _?%&$@X%$c@!- ?b","P 62 2 2":" !#%?^@$Q$%#!@^? Q! _?%&$@X%$_@!& ?X","P 64 2 2":" !#%?Q@$^$%#!@Q? ^! X?%&$@_%$X@!& ?_","P 63 2 2":" !#%?#@$#$%+!@+? +! &?%&$@&%$-@!- ?-","P 6 m m":" !#%?#@$#$%#!@#? #%$#@!# ?#! #?%#$@#","P 6 c c":" !#%?#@$#$%#!@#? #%$+@!+ ?+! +?%+$@+","P 63 c m":" !#%?#@$#$%+!@+? +%$+@!+ ?+! #?%#$@#","P 63 m c":" !#%?#@$#$%+!@+? +%$#@!# ?#! +?%+$@+","P -6 m 2":" !#%?#@$# !&%?&@$&%$#@!# ?#%$&@!& ?&","P -6 c 2":" !#%?#@$# !-%?-@$-%$+@!+ ?+%$&@!& ?&","P -6 2 m":" !#%?#@$# !&%?&@$&! &?%&$@&! #?%#$@#","P -6 2 c":" !#%?#@$# !-%?-@$-! &?%&$@&! +?%+$@+","P 6/m 2/m 2/m":" !#%?#@$#$%#!@#? #! &?%&$@&%$&@!& ?&$%&!@&? & !&@$&%?&%$#@!# ?#! #?%#$@#","P 6/m 2/c 2/c":" !#%?#@$#$%#!@#? #! -?%-$@-%$-@!- ?-$%&!@&? & !&@$&%?&%$+@!+ ?+! +?%+$@+","P 63/m 2/c 2/m":" !#%?#@$#$%+!@+? +! -?%-$@-%$&@!& ?&$%&!@&? & !-@$-%?-%$+@!+ ?+! #?%#$@#","P 63/m 2/m 2/c":" !#%?#@$#$%+!@+? +! &?%&$@&%$-@!- ?-$%&!@&? & !-@$-%?-%$#@!# ?#! +?%+$@+","P 2 3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ","F 2 3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ","I 2 3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-(","P 21 3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(","I 21 3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- ","P 2/m -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$","P 2/n -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& *,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*","F 2/m -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$ )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-($,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(*%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- *,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$","F 2/d -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& 64=37=345675=64=375345674=67=3453756 )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(68>3:>3896:9=<8=;:5;85<:4><7>;49;79<(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(<4>;7>;49<79>68>3:93896:8=<:=;85;:5<()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- <8=;:=;8f<:f><4>;79;49<78>6:>3893:96","I 2/m -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-(*,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*","P 21/a -3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&($%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*","I 21/a -3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&($%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*()+$,#*g& %-+()#$,&*!- %)+(,#$!&*%- *,- )&(%#$!+-*,& )#(%+$!,-*)& %#(!+$","P 4 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$","P 42 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*","F 4 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$ )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(-%*-!*+%(+ +,$+)$-, -)#)*#,(&)(&,*(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() -,$-)$+, +(#,*#)*&,(&)+!*+%(-!(-%*()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(&,*&)*#,(#(+%*+!*-%(-!+)$+, -) -,$","F 41 3 2":" !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=46 )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<(!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>86","I 4 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*","P 43 3 2":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(7;>46=:<5839398<5:6=4;>75:<983>7;=46","P 41 3 2":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<","I 41 3 2":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- 7;>46=:<5839398<5:6=4;>75:<983>7;=46","P -4 3 m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% ","F -4 3 m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(+%*+!*-%(- +)$+,$-) -,#)(#,*&)*&,((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() +,$+)$-, -(#)*#,*&)(&,+!(+%*-!*-%(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(#,*#)*&,(&(+!*+%*-!(-%+) +,$-)$-, ","I -4 3 m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,(","P -4 3 n":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,(","F -4 3 c":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,( )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-() #,$#)$&, &(#!*#%*&!(&%+! +%$-!$-% (!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(!(#%*#!*&%(& +!$+%$-! -%#) #,$&)$&, ()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ! +%$+!$-% - #)$#,$&) &,#!(#%*&!*&%(","I -4 3 d":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(7354<9:6>8;=357<946>:;=857394<>:6=8;()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- :;98657<=43>;9:658<=73>49:;586=7<>43","P 4/m -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ","P 4/n -3 2/n":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$*,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(","P 42/m -3 2/n":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(","P 42/n -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,**,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ","F 4/m -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(-%*-!*+%(+ +,$+)$-, -)#)*#,(&)(&,*$,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*%*+!(+%(-!*-$-) -, +)$+,&,(&)*#,*#)((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() -,$-)$+, +(#,*#)*&,(&)+!*+%(-!(-%**%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*,$+) +, -)$-*&)(&,(#)*#,-%(-!*+%*+!(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(&,*&)*#,(#(+%*+!*-%(-!+)$+, -) -,$*,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$,*#)(#,(&)*&*-!(-%(+!*+%-, -)$+,$+) ","F 4/m -3 2/c":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)( )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-() &,$&)$#, #(#%*#!*&%(&!+!$+% -! -%$$,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*,$#) #, &)$&*&!(&%(#!*#%-% -!$+%$+! (!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(!(&%*&!*#%(# +%$+!$-% -!#)$#, &) &,$*%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*%*#!(#%(&!*&$-! -% +!$+%&, &)$#,$#) ()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ! -%$-!$+% + #,$#)$&, &)#!*#%(&!(&%**,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$%$+! +% -!$-$&) &, #)$#,&%(&!*#%*#!(","F 41/d -3 2/m":" !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=4664=3:>;85<79=64>3:5;89<74=6:>385;79<,$+! #%(-)*&*&)(-% #!$+,-%(&)*+,$#! )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<68>37=;49<:5=<8>;753496:4><:=;893756,*#!(+% &)$-*-!(&, +)$#%-, &!$+%*#)((!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<<4>;:=389675>68=379;45<:8=<7>;453:96%$#) +,(&!*-$&! -,(#)*+%&% -)$#,*+!(()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>86<8=;7>3456:9><4=;:9385678>67=349;:5<%*+)(#, -!$&$-) &%(+!*#,&,(-!*#%$+) ","F 41/d -3 2/c":" !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=46<8>;7=3496:5><8=;793456:8><7=;493:56%*#)(+, &!$-$-! &,(+)*#%&, -!$#%*+)( )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<<4=;:>385679>64=3:9;85<78=67>345;:9<%$+) #,(-!*&$&) -%(#!*+,&%(-)*#,$+! (!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<68=37>;45<:9=<4>;:5389674>6:=389;75<,*+!(#% -)$&*-)(&% +!$#,-,(&!*+%$#) ()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>8664>3:=;89<75=68>375;49<:4=<:>;853796,$#! +%(&)*-*&!(-, #)$+%-% &)$+,*#!(","I 4/m -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,**,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(","I 41/a -3 2/d":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<$%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*4<97358;=:6>6>:;=8357<94=8;>:694<573()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- 7;>46=:<5839398<5:6=4;>75:<983>7;=46*,- )&(%#$!+-*,& )#(%+$!,-*)& %#(!+$865:;943>7<=<=73>4;9:658>43=7<5869:;","P 1 1 2":" !#$%#","P 1 1 21":" !#$%+","B 1 1 2":" !#$%#(g+*%+","A 1 2 1":" !#$!& )+$)-","C 1 21 1":" !#$)&()#*!&","I 1 2 1":" !#$!&.'/0'2","I 1 21 1":" !#$)&.'/0!-","P 1 1 m":" !# !&","P 1 1 b":" !# )&","B 1 1 m":" !# !&(!+(!-","B 1 1 b":" !# )&(!+()-","P 1 1 2/m":" !# !&$%#$%&","P 1 1 21/m":" !#$%+$%& !-","B 1 1 2/m":" !# !&$%#$%&(!+(!-*%+*%-","P 1 1 2/b":" !#$,#$%& )&","P 1 1 21/b":" !#$%&$,+ )-","B 1 1 2/b":" !#$,#$%& )&(!+*,+*%-()-","P 21 2 2":" !#$!&(%&*%#","P 2 21 2":" !# ,&$)&$%#","P 21 21 2 (a)":" !#*,#.%&$'&","P 21 2 21":" !#$!&(%-*%+","P 2 21 21":" !# %&$)-$,+","C 2 2 21a)":" !#*%+(,&$)-()#$,+ %&*!-","C 2 2 2a":" !#*,#.%&$'&()#$%# ,&*!&","F 2 2 2a":" !#*,#.%&$'& '/*%/.12$!2.!/$,/ %20'2.'#$%# 1&0!&","I 2 2 2a":" !#*,#.%&$'&()+$%+*!- ,-","P 21/m 21/m 2/n a":" !#*,#$)&(%&$%&.'& ,#*!#","P 42 21 2a":" !#*,#%.+'$+$'&.%&! -,*-","I 2 3a":" !#*,#.%&$'&!# ,- '&$%/$# !-*!/$%&.%()+$%+ ,-*!-)+(%&(!-*,#*+()&$)#*,- ,"},$a=/^[1-9]$/;function Oa(t){let e="";return t.length>0&&(e=":"+pt(t).join(" OR :")),new me(e)}class Ra{constructor(t=""){this.name=t,this.partList=[]}get type(){return"Assembly"}addPart(t,e){const i=new La(t,e);return this.partList.push(i),i}getAtomCount(t){return this.partList.reduce(((e,i)=>e+i.getAtomCount(t)),0)}getResidueCount(t){return this.partList.reduce(((e,i)=>e+i.getResidueCount(t)),0)}getInstanceCount(){let t=0;return this.partList.forEach((function(e){t+=e.matrixList.length})),t}isIdentity(t){if(1!==this.partList.length)return!1;const e=this.partList[0];if(1!==e.matrixList.length)return!1;if(!(new i).equals(e.matrixList[0]))return!1;let r=[];return t.eachChain((function(t){r.push(t.chainname)})),r=pt(r),e.chainList.length===r.length}getBoundingBox(t){const e=new a;return this.partList.forEach((function(i){const r=i.getBoundingBox(t);e.expandByPoint(r.min),e.expandByPoint(r.max)})),e}getCenter(t){return this.getBoundingBox(t).getCenter(new e)}getSelection(){let t=[];return this.partList.forEach((function(e){t=t.concat(e.chainList)})),Oa(t)}}class La{constructor(t=[],e=[]){this.matrixList=t,this.chainList=e}get type(){return"AssemblyPart"}_getCount(t,e){let i=0;return t.eachChain((t=>{(0===this.chainList.length||this.chainList.includes(t.chainname))&&(i+=t[e])})),this.matrixList.length*i}getAtomCount(t){return this._getCount(t,"atomCount")}getResidueCount(t){return this._getCount(t,"residueCount")}getBoundingBox(t){const e=new a,i=new a,r=this.getSelection(),n=t.getBoundingBox(r);return this.matrixList.forEach((function(t){i.copy(n).applyMatrix4(t),e.expandByPoint(i.min),e.expandByPoint(i.max)})),e}getSelection(){return Oa(this.chainList)}getView(t){const e=this.getSelection();return e?t.getView(e):t}getInstanceList(){const t=[];for(let e=0,i=this.matrixList.length;e0&&this.addResidueType(this.ri-1),l.growIfFull(),l.resno[this.ri]=n,void 0!==o&&(l.sstruc[this.ri]=o.charCodeAt(0)),void 0!==a&&(l.inscode[this.ri]=a.charCodeAt(0)),l.atomOffset[this.ri]=this.ai,l.atomCount[this.ri]=0,l.count+=1,l.chainIndex[this.ri]=this.ci,h.residueCount[this.ci]+=1),c.count+=1,c.residueIndex[this.ai]=this.ri,l.atomCount[this.ri]+=1,this.currentModelindex=t,this.currentChainid=i,this.currentResname=r,this.currentResno=n,this.currentInscode=a,this.currentHetero=s}finalize(){this.previousResname=this.currentResname,this.previousHetero=this.currentHetero,this.ri>-1&&this.addResidueType(this.ri)}}function za(t,e){if(!e)return;De&&ke.time("assignSecondaryStructure");const i=[];t.eachModel((function(t){t.eachChain((function(t){i.push(t.chainname)}))}));const r=i.slice().sort(),n=[];r.forEach((function(t){n.push(i.indexOf(t))}));const s=e.helices.filter((function(t){return mt(r,t[0])>=0}));s.sort((function(t,e){const i=t[0],s=e[0],o=t[1],a=e[1];if(i===s)return o===a?0:o=0}));a.sort((function(t,e){const i=t[0],s=e[0];if(i===s)return 0;const o=mt(r,i),a=mt(r,s);return n[o]=t.residueCount)continue;o.index=s+n,a.index=s+n+e,c.index=o.traceAtomIndex,l.index=a.traceAtomIndex;const h=c.distanceTo(l);if(Math.abs(h-i[e-2])>r)return!1}return!0},i=function(e,i){return t(e,i,[5.45,5.18,6.37],2.1)},r=function(e,i){return t(e,i,[6.1,10.4,13],1.42)};return function(t){De&&ke.time("calculateSecondaryStructure"),t.eachPolymer((function(t){if(t.residueCount<4)return;if(t.isCg())!function(t){const i=t.residueStore,r=t.residueIndexStart,n=new Ca(t).position,s=new e,o=new e;for(let e=0,a=t.residueCount;e1&&n.bending[e]<20&&(i.sstruc[r+e]="h".charCodeAt(0),i.sstruc[r+e+1]="h".charCodeAt(0))}}(t);else{if(!t.isProtein())return;!function(t){const e=t.residueStore,n=t.residueIndexStart;for(let s=0,o=t.residueCount;s=e;)i=Math.floor(i/e),n+=Va[i%e],r+=1;return r>=5&&ke.warn("chainname overflow"),n}function Ga(t,e=!1){De&&ke.time("calculateChainnames");let i=!0;if(t.eachChain((function(t){t.chainname&&(i=!1)})),i){const i=t.modelStore,r=t.chainStore,n=t.residueStore,s=function(t,e,s,o){const a=r.count;for(let t=0;t{h.add(e),t.forEach((t=>{h.add(t)}))}))),t.eachResidue((function(t){if(!e&&l){const e=t.atomCount,n=t.atomOffset;if(e>500)return void ke.warn("more than 500 atoms, skip residue for auto-bonding",t.qualifiedName());if("auto"===i&&t.hetero)for(let e=t.atomOffset;e{d.forEach((i=>{e.push(t.clone().multiply(i))}))})),h.addPart(e)}else h.addPart(u);const m=new e,f=new Ra("SUPERCELL"),p=Array.prototype.concat.call(l(m.set(1,0,0)),l(m.set(0,1,0)),l(m.set(0,0,1)),l(m.set(-1,0,0)),l(m.set(0,-1,0)),l(m.set(0,0,-1)),l(m.set(1,1,0)),l(m.set(1,0,1)),l(m.set(0,1,1)),l(m.set(-1,-1,0)),l(m.set(-1,0,-1)),l(m.set(0,-1,-1)),l(m.set(1,-1,-1)),l(m.set(1,1,-1)),l(m.set(1,-1,1)),l(m.set(-1,1,1)),l(m.set(-1,-1,1)),l(m.set(-1,1,-1)),l(m.set(0,1,-1)),l(m.set(0,-1,1)),l(m.set(1,0,-1)),l(m.set(-1,0,1)),l(m.set(1,-1,0)),l(m.set(-1,1,0)),l(),l(m.set(1,1,1)),l(m.set(-1,-1,-1)));if(t.biomolDict.NCS){const t=[];p.forEach((function(e){d.forEach((function(i){t.push(e.clone().multiply(i))}))})),f.addPart(t)}else f.addPart(p);t.biomolDict.UNITCELL=h,t.biomolDict.SUPERCELL=f,De&&ke.timeEnd("buildUnitcellAssembly")}const Za=["H","C","O","N","S","P"],Qa=["NA","CL","FE"];function Ja(t){let e=t.toUpperCase(),i=0,r=0;for(let t=0;t0)break;++i}else r=t+1;(i>0||r=3&&-1!==Za.indexOf(e[0])?e[0]:""}function tc(t){const e=t.bondHash,i=e.countArray,r=e.offsetArray,n=e.indexArray,s=t.getBondProxy();t.eachResidue((function(t){const e=t.residueType;if(void 0!==e.bonds)return;var o=t.atomOffset,a=[],c=[],l=[],h={};const u=o+t.atomCount;t.eachAtom((function(t){const e=t.index,d=r[e];for(let t=0,r=i[e];t=u)continue;let i=s.atomIndex2;if(i=u)continue;if(e>i){const t=i;i=e,e=t}const r=e+"|"+i;void 0===h[r]&&(h[r]=!0,a.push(e-o),c.push(i-o),l.push(s.bondOrder))}})),e.bonds={atomIndices1:a,atomIndices2:c,bondOrders:l}}))}function ec(t,...e){De&&ke.time("concatStructures");const i=new Sc(t,""),r=new Na(i),n=i.atomStore,s=i.atomMap;n.addField("formalCharge",1,"int8"),n.addField("partialCharge",1,"float32");const o={};let a=0,c=0,l=0;e.forEach((t=>{t.eachAtom((t=>{n.growIfFull(),n.atomTypeId[a]=s.add(t.atomname,t.element),n.x[a]=t.x,n.y[a]=t.y,n.z[a]=t.z,n.serial[a]=t.serial,n.formalCharge[a]=t.formalCharge,n.partialCharge[a]=t.partialCharge,n.altloc[a]=t.altloc,n.occupancy[a]=t.occupancy,n.bfactor[a]=t.bfactor,r.addAtom(t.modelIndex+l,t.chainname,t.chainid,t.resname,t.resno,1===t.hetero,t.sstruc,t.inscode),o[t.index+c]=a,a+=1})),c+=t.atomStore.count,l+=t.modelStore.count}));const h=i.bondStore,u=i.getAtomProxy(),d=i.getAtomProxy();return c=0,e.forEach((t=>{t.eachBond((t=>{u.index=o[t.atomIndex1+c],d.index=o[t.atomIndex2+c],h.addBond(u,d,t.bondOrder)})),c+=t.atomStore.count})),r.finalize(),Ya(i,!0),Xa(i,!0),i.finalizeAtoms(),i.finalizeBonds(),tc(i),De&&ke.timeEnd("concatStructures"),i}const ic=[3,11,19,37,55,87],rc=[4,12,20,38,56,88],nc=[6,15,16,34],sc=[1,7,8,9,17,35,53],oc=[2,10,18,36,54,86],ac=[13,30,31,48,49,50,80,81,82,83,84,85,112],cc=[5,14,32,33,51,52,85],lc=[9,17,35,53,85];class hc{constructor(t,e,i){this.structure=t,this.atomname=e,i=i||Ja(e),this.element=i,this.number=Xn[i]||0,this.vdw=Yn[this.number]||2,this.covalent=Kn[this.number]||1.6}getDefaultValence(){const t=Zn[this.number];return t?t[0]:-1}getValenceList(){return Zn[this.number]||[]}getOuterShellElectronCount(){return Qn[this.number]||2}isMetal(){return this.isAlkaliMetal()||this.isAlkalineEarthMetal()||this.isLanthanide()||this.isActinide()||this.isTransitionMetal()||this.isPostTransitionMetal()}isNonmetal(){return this.isDiatomicNonmetal()||this.isPolyatomicNonmetal()||this.isNobleGas()}isMetalloid(){return cc.includes(this.number)}isHalogen(){return lc.includes(this.number)}isDiatomicNonmetal(){return sc.includes(this.number)}isPolyatomicNonmetal(){return nc.includes(this.number)}isAlkaliMetal(){return ic.includes(this.number)}isAlkalineEarthMetal(){return rc.includes(this.number)}isNobleGas(){return oc.includes(this.number)}isTransitionMetal(){const t=this.number;return t>=21&&t<=29||t>=39&&t<=47||t>=72&&t<=79||t>=104&&t<=108}isPostTransitionMetal(){return ac.includes(this.number)}isLanthanide(){return this.number>=57&&this.number<=71}isActinide(){return this.number>=89&&this.number<=103}}class uc{constructor(t){this.structure=t,this.dict={},this.list=[],this.structure=t}add(t,e){const i=function(t,e){return t+"|"+e}(t=t.toUpperCase(),e=e?e.toUpperCase():Ja(t));let r=this.dict[i];if(void 0===r){const n=new hc(this.structure,t,e);r=this.list.length,this.dict[i]=r,this.list.push(n)}return r}get(t){return this.list[t]}}class dc{constructor(t,e,i,r,n,s){this.structure=t,this.bondReferenceAtomIndices=[],this.resname=e,this.atomTypeIdList=i,this.hetero=r?1:0,this.chemCompType=n,this.bonds=s,this.atomCount=i.length,this.moleculeType=this.getMoleculeType(),this.backboneType=this.getBackboneType(0),this.backboneEndType=this.getBackboneType(-1),this.backboneStartType=this.getBackboneType(1),this.backboneIndexList=this.getBackboneIndexList();const o=ds[this.backboneType],a=ds[this.backboneStartType],c=ds[this.backboneEndType],l=this.getAtomIndexByName(o.trace);this.traceAtomIndex=rt(l,-1);const h=this.getAtomIndexByName(o.direction1);this.direction1AtomIndex=rt(h,-1);const u=this.getAtomIndexByName(o.direction2);this.direction2AtomIndex=rt(u,-1);const d=this.getAtomIndexByName(a.backboneStart);this.backboneStartAtomIndex=rt(d,-1);const m=this.getAtomIndexByName(c.backboneEnd);let f;this.backboneEndAtomIndex=rt(m,-1),f=ss.includes(e)?this.getAtomIndexByName("N1"):this.getAtomIndexByName("N3"),this.rungEndAtomIndex=rt(f,-1)}getBackboneIndexList(){const t=[];let e;switch(this.moleculeType){case 3:e=hs;break;case 4:case 5:e=us;break;default:return t}const i=this.structure.atomMap,r=this.atomTypeIdList;for(let n=0,s=this.atomCount;n500)De&&ke.warn("more than 500 atoms, skip residue for auto-bonding",t.qualifiedName());else if(n>50){const e=new Ba(t,!0),n=t.isCg()?1.2:2.3;for(let t=s;t=0||gc(t,e);this.rings={atomRings:t.atomRings,rings:t.rings}}isAromatic(t){return this.aromaticAtoms=this.getAromatic(t),1===this.aromaticAtoms[t.index-t.residueAtomOffset]}calculateAromatic(t){const e=this.aromaticAtoms=new Uint8Array(this.atomCount),i=this.getRings().rings,r=i.map((e=>function(t){if(t.some((t=>!mc.includes(t.number))))return!1;let e=0;const i=new lo(3,t.length),r=i.data;t.forEach((t=>{r[e+0]=t.x,r[e+1]=t.y,r[e+2]=t.z,e+=3}));return new ga(i).vecC.length()this.structure.getAtomProxy(e+t.atomOffset)))))),n=this.aromaticRings=[];i.forEach(((t,i)=>{r[i]&&(n.push(t),t.forEach((t=>e[t]=1)))}))}assignBondReferenceAtomIndices(){const t=this.getBondGraph(),e=this.getRings(),i=e.atomRings,r=e.rings,n=this.bonds,s=n.atomIndices1,o=n.atomIndices2,a=n.bondOrders,c=this.bondReferenceAtomIndices,l=n.atomIndices1.length;c.length=0;for(let e=0;e1)for(let i=0;i1)for(let i=0;i=0;t--)f[p++]=o[t];const g=t.rings.length;for(let e=0;e0?s[c]!==e&&s[e]!==c&&pc(t,e,c):(r[c]=1,n[a++]=c,s[c]=e)}}}const yc=4;class bc{constructor(t){this.structure=t,this.dict={},this.list=[]}add(t,e,i,r="",n){const s=function(t,e,i,r=""){return t+"|"+e.join(",")+"|"+(i?1:0)+"|"+r}(t=t.toUpperCase(),e,i,r);let o=this.dict[s];if(void 0===o){const a=new dc(this.structure,t,e,i,r,n);o=this.list.length,this.dict[s]=o,this.list.push(a)}return o}get(t){return this.list[t]}}class _c{constructor(t,i=0){this.structure=t,this.index=i,this.bondStore=t.bondStore,this._v12=new e,this._v13=new e,this._ap1=this.structure.getAtomProxy(),this._ap2=this.structure.getAtomProxy(),this._ap3=this.structure.getAtomProxy()}get atom1(){return this.structure.getAtomProxy(this.atomIndex1)}get atom2(){return this.structure.getAtomProxy(this.atomIndex2)}get atomIndex1(){return this.bondStore.atomIndex1[this.index]}set atomIndex1(t){this.bondStore.atomIndex1[this.index]=t}get atomIndex2(){return this.bondStore.atomIndex2[this.index]}set atomIndex2(t){this.bondStore.atomIndex2[this.index]=t}get bondOrder(){return this.bondStore.bondOrder[this.index]}set bondOrder(t){this.bondStore.bondOrder[this.index]=t}getOtherAtomIndex(t){return t===this.atomIndex1?this.atomIndex2:this.atomIndex1}getOtherAtom(t){return this.structure.getAtomProxy(this.getOtherAtomIndex(t.index))}getReferenceAtomIndex(){const t=this._ap1,e=this._ap2;if(t.index=this.atomIndex1,e.index=this.atomIndex2,t.residueIndex!==e.residueIndex)return;const i=t.index-t.residueAtomOffset,r=e.index-e.residueAtomOffset,n=t.residueType.getBondReferenceAtomIndex(i,r);if(void 0!==n)return n+t.residueAtomOffset;console.warn("No reference atom found",t.index,e.index)}calculateShiftDir(t=new e){const i=this._ap1,r=this._ap2,n=this._ap3,s=this._v12,o=this._v13;i.index=this.atomIndex1,r.index=this.atomIndex2;const a=this.getReferenceAtomIndex();s.subVectors(i,r).normalize(),void 0!==a?(n.index=a,o.subVectors(i,n)):o.copy(i),o.normalize();let c=s.dot(o);return 1-Math.abs(c)<1e-5&&(o.set(1,0,0),c=s.dot(o),1-Math.abs(c)<1e-5&&(o.set(0,1,0),c=s.dot(o))),t.copy(o.sub(s.multiplyScalar(c))).normalize()}qualifiedName(){return this.atomIndex1+"="+this.atomIndex2}clone(){return new _c(this.structure,this.index)}toObject(){return{atomIndex1:this.atomIndex1,atomIndex2:this.atomIndex2,bondOrder:this.bondOrder}}}class xc{constructor(t,e=0){this.structure=t,this.index=e,this.chainStore=t.chainStore,this.residueStore=t.residueStore,this.atomStore=t.atomStore,this.residueMap=t.residueMap,this.atomMap=t.atomMap}get entity(){return this.structure.entityList[this.entityIndex]}get entityIndex(){return this.chainStore.entityIndex[this.chainIndex]}get chain(){return this.structure.getChainProxy(this.chainIndex)}get chainIndex(){return this.residueStore.chainIndex[this.index]}set chainIndex(t){this.residueStore.chainIndex[this.index]=t}get atomOffset(){return this.residueStore.atomOffset[this.index]}set atomOffset(t){this.residueStore.atomOffset[this.index]=t}get atomCount(){return this.residueStore.atomCount[this.index]}set atomCount(t){this.residueStore.atomCount[this.index]=t}get atomEnd(){return this.atomOffset+this.atomCount-1}get modelIndex(){return this.chainStore.modelIndex[this.chainIndex]}get chainname(){return this.chainStore.getChainname(this.chainIndex)}get chainid(){return this.chainStore.getChainid(this.chainIndex)}get resno(){return this.residueStore.resno[this.index]}set resno(t){this.residueStore.resno[this.index]=t}get sstruc(){return this.residueStore.getSstruc(this.index)}set sstruc(t){this.residueStore.setSstruc(this.index,t)}get inscode(){return this.residueStore.getInscode(this.index)}set inscode(t){this.residueStore.setInscode(this.index,t)}get residueType(){return this.residueMap.get(this.residueStore.residueTypeId[this.index])}get resname(){return this.residueType.resname}get hetero(){return this.residueType.hetero}get moleculeType(){return this.residueType.moleculeType}get backboneType(){return this.residueType.backboneType}get backboneStartType(){return this.residueType.backboneStartType}get backboneEndType(){return this.residueType.backboneEndType}get traceAtomIndex(){return this.residueType.traceAtomIndex+this.atomOffset}get direction1AtomIndex(){return this.residueType.direction1AtomIndex+this.atomOffset}get direction2AtomIndex(){return this.residueType.direction2AtomIndex+this.atomOffset}get backboneStartAtomIndex(){return this.residueType.backboneStartAtomIndex+this.atomOffset}get backboneEndAtomIndex(){return this.residueType.backboneEndAtomIndex+this.atomOffset}get rungEndAtomIndex(){return this.residueType.rungEndAtomIndex+this.atomOffset}get x(){let t=0;for(let e=this.atomOffset;e<=this.atomEnd;++e)t+=this.atomStore.x[e];return t/this.atomCount}get y(){let t=0;for(let e=this.atomOffset;e<=this.atomEnd;++e)t+=this.atomStore.y[e];return t/this.atomCount}get z(){let t=0;for(let e=this.atomOffset;e<=this.atomEnd;++e)t+=this.atomStore.z[e];return t/this.atomCount}eachAtom(t,e){const i=this.atomCount,r=this.atomOffset,n=this.structure._ap,s=r+i;if(e&&e.atomOnlyTest){const i=e.atomOnlyTest;for(let e=r;e0)return this.entity.isPolymer();{const t=this.residueType.moleculeType;return 3===t||4===t||5===t}}isHetero(){return 1===this.residueType.hetero}isWater(){return 1===this.residueType.moleculeType}isIon(){return 2===this.residueType.moleculeType}isSaccharide(){return 6===this.residueType.moleculeType}isStandardAminoacid(){return this.residueType.isStandardAminoacid()}isStandardBase(){return this.residueType.isStandardBase()}isHelix(){return Hn.includes(this.sstruc)}isSheet(){return qn.includes(this.sstruc)}isTurn(){return Wn.includes(this.sstruc)&&this.isProtein()}getAtomType(t){return this.atomMap.get(this.atomStore.atomTypeId[t])}getResname1(){return es[this.resname.toUpperCase()]||"X"}getBackboneType(t){switch(t){case-1:return this.residueType.backboneStartType;case 1:return this.residueType.backboneEndType;default:return this.residueType.backboneType}}getAtomIndexByName(t){let e=this.residueType.getAtomIndexByName(t);return void 0!==e&&(e+=this.atomOffset),e}hasAtomWithName(t){return this.residueType.hasAtomWithName(t)}getAtomnameList(){console.warn("getAtomnameList - might be expensive");const t=this.atomCount,e=this.atomOffset,i=new Array(t);for(let r=0;r=e){const e=rt(t,this.structure.getResidueProxy());if(e.index=i,e.connectedTo(this))return e}else if(i===e-1){const i=this.chainStore.residueCount[this.chainIndex],r=rt(t,this.structure.getResidueProxy());if(r.index=e+i-1,r.connectedTo(this))return r}}getBonds(){return this.residueType.getBonds(this)}getRings(){return this.residueType.getRings()}getAromaticRings(){return this.residueType.getAromaticRings(this)}qualifiedName(t=!1){let e="";return this.resname&&!t&&(e+="["+this.resname+"]"),void 0!==this.resno&&(e+=this.resno),this.inscode&&(e+="^"+this.inscode),this.chain&&(e+=":"+this.chainname),e+="/"+this.modelIndex,e}clone(){return new xc(this.structure,this.index)}toObject(){return{index:this.index,chainIndex:this.chainIndex,atomOffset:this.atomOffset,atomCount:this.atomCount,resno:this.resno,resname:this.resname,sstruc:this.sstruc}}}class vc{constructor(t,e,i){this.structure=t,this.residueIndexStart=e,this.residueIndexEnd=i,this.chainStore=t.chainStore,this.residueStore=t.residueStore,this.atomStore=t.atomStore,this.residueCount=i-e+1;const r=this.structure.getResidueProxy(this.residueIndexStart),n=this.structure.getResidueProxy(this.residueIndexEnd);this.isPrevConnected=void 0!==r.getPreviousConnectedResidue();const s=n.getNextConnectedResidue();this.isNextConnected=void 0!==s,this.isNextNextConnected=void 0!==s&&void 0!==s.getNextConnectedResidue(),this.isCyclic=n.connectedTo(r),this.__residueProxy=this.structure.getResidueProxy()}get chainIndex(){return this.residueStore.chainIndex[this.residueIndexStart]}get modelIndex(){return this.chainStore.modelIndex[this.chainIndex]}get chainname(){return this.chainStore.getChainname(this.chainIndex)}isProtein(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.isProtein()}isCg(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.isCg()}isNucleic(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.isNucleic()}getMoleculeType(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.moleculeType}getBackboneType(t){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.getBackboneType(t)}getAtomIndexByType(t,e){this.isCyclic?-1===t?t=this.residueCount-1:t===this.residueCount&&(t=0):(-1!==t||this.isPrevConnected||(t+=1),t!==this.residueCount||this.isNextNextConnected||(t-=1));const i=this.__residueProxy;let r;switch(i.index=this.residueIndexStart+t,e){case"trace":r=i.traceAtomIndex;break;case"direction1":r=i.direction1AtomIndex;break;case"direction2":r=i.direction2AtomIndex;break;default:r=i.getAtomIndexByName(e)}return r}eachAtom(t,e){this.eachResidue((function(i){i.eachAtom(t,e)}))}eachAtomN(t,e,i){const r=this.residueCount,n=new Array(t);for(let e=0;e1&&t(new vc(s,i,l.index)),i=r)):(o!==Nn&&l.index-i>1&&t(new vc(s,i,l.index)),i=r)}r-i>1&&this.structure.getResidueProxy(i).backboneEndType&&t(new vc(s,i,r))}qualifiedName(){return":"+this.chainname+"/"+this.modelIndex}clone(){return new wc(this.structure,this.index)}toObject(){return{index:this.index,residueOffset:this.residueOffset,residueCount:this.residueCount,chainname:this.chainname}}}class Ac{constructor(t,e=0){this.structure=t,this.index=e,this.modelStore=t.modelStore,this.chainStore=t.chainStore,this.residueStore=t.residueStore}get chainOffset(){return this.modelStore.chainOffset[this.index]}set chainOffset(t){this.modelStore.chainOffset[this.index]=t}get chainCount(){return this.modelStore.chainCount[this.index]}set chainCount(t){this.modelStore.chainCount[this.index]=t}get residueOffset(){return this.chainStore.residueOffset[this.chainOffset]}get atomOffset(){return this.residueStore.atomOffset[this.residueOffset]}get chainEnd(){return this.chainOffset+this.chainCount-1}get residueEnd(){return this.chainStore.residueOffset[this.chainEnd]+this.chainStore.residueCount[this.chainEnd]-1}get atomEnd(){return this.residueStore.atomOffset[this.residueEnd]+this.residueStore.atomCount[this.residueEnd]-1}get residueCount(){return 0===this.chainCount?0:this.residueEnd-this.residueOffset+1}get atomCount(){return 0===this.residueCount?0:this.atomEnd-this.atomOffset+1}eachAtom(t,e){this.eachChain((function(i){i.eachAtom(t,e)}),e)}eachResidue(t,e){this.eachChain((function(i){i.eachResidue(t,e)}),e)}eachPolymer(t,e){if(e&&e.chainOnlyTest){const i=e.chainOnlyTest;this.eachChain((function(r){i(r)&&r.eachPolymer(t,e)}))}else this.eachChain((function(i){i.eachPolymer(t,e)}))}eachChain(t,e){const i=this.chainCount,r=this.chainOffset,n=this.structure._cp,s=r+i;if(e&&e.test){const i=e.chainOnlyTest;if(i)for(let e=r;e{const i=3*e;a.index=t,l&&a.positionToArray(l,i),h&&s.atomColorToArray(a,h,i),u&&(u.array[e]=t),d&&(d[e]=n.atomRadius(a)),m&&(m[e]=t)})),o}getBondData(t){const i=Object.assign({},t);i.colorParams&&(i.colorParams.structure=this.getStructure());const r=i.what,n=rt(i.bondSet,this.bondSet),s=rt(i.multipleBond,"off"),o="off"!==s,a="offset"===s,c=rt(i.bondScale,.4),l=rt(i.bondSpacing,1);let h,u;const d={},m=this.getBondProxy();i.bondStore&&(m.bondStore=i.bondStore);const f=this.getAtomProxy(),p=this.getAtomProxy();let g;if(o){const t=m.bondStore.bondOrder;g=0,n.forEach((function(e){g+=t[e]}))}else g=n.getSize();r&&!r.position||(d.position1=new Float32Array(3*g),d.position2=new Float32Array(3*g)),r&&!r.color||!i.colorParams||(d.color=new Float32Array(3*g),d.color2=new Float32Array(3*g),u=Oe.getScheme(i.colorParams)),r&&!r.picking||(d.picking=new Ks(new Float32Array(g),this.getStructure(),i.bondStore)),(!r||r.radius||o&&r.position)&&(h=new ma(i.radiusParams)),r&&!r.radius||(d.radius=new Float32Array(g),i.radius2&&(d.radius2=new Float32Array(g)));const{position1:y,position2:b,color:_,color2:x,picking:v,radius:w,radius2:A}=d;let S,C,P,I,k,M,T=0;const D=new e,B=new e,F=new e;return n.forEach((t=>{if(C=3*T,m.index=t,f.index=m.atomIndex1,p.index=m.atomIndex2,I=m.bondOrder,y)if(o&&I>1){const t=h.atomRadius(f);M=t*c/(.5*I),m.calculateShiftDir(F),a?(k=2*l*t,F.multiplyScalar(k),F.negate(),B.subVectors(p,f).multiplyScalar(Math.max(.1,k/1.88)),f.positionToArray(y,C),p.positionToArray(b,C),I>=2&&(D.addVectors(f,F).add(B).toArray(y,C+3),D.addVectors(p,F).sub(B).toArray(b,C+3),I>=3&&(D.subVectors(f,F).add(B).toArray(y,C+6),D.subVectors(p,F).sub(B).toArray(b,C+6)))):(k=(l-c)*t,F.multiplyScalar(k),2===I?(D.addVectors(f,F).toArray(y,C),D.subVectors(f,F).toArray(y,C+3),D.addVectors(p,F).toArray(b,C),D.subVectors(p,F).toArray(b,C+3)):3===I?(f.positionToArray(y,C),D.addVectors(f,F).toArray(y,C+3),D.subVectors(f,F).toArray(y,C+6),p.positionToArray(b,C),D.addVectors(p,F).toArray(b,C+3),D.subVectors(p,F).toArray(b,C+6)):(f.positionToArray(y,C),p.positionToArray(b,C)))}else f.positionToArray(y,C),p.positionToArray(b,C);if(_&&x&&(u.bondColorToArray(m,1,_,C),u.bondColorToArray(m,0,x,C),o&&I>1))for(S=1;S1))for(S=1;S1))for(M=w[T]*c/(a?1:.5*I),S=a?1:0;S1))for(M=A[T]*c/(a?1:.5*I),S=a?1:0;S{const e=t.x,a=t.y,l=t.z;es&&(s=e),a>o&&(o=a),l>c&&(c=l)}),t),e.min.set(i,r,n),e.max.set(s,o,c),De&&ke.timeEnd("getBoundingBox"),e}getPrincipalAxes(t){De&&ke.time("getPrincipalAxes");let e=0;const i=new lo(3,this.atomCount),r=i.data;return this.eachAtom((t=>{r[e+0]=t.x,r[e+1]=t.y,r[e+2]=t.z,e+=3}),t),De&&ke.timeEnd("getPrincipalAxes"),new ga(i)}atomCenter(t){return t?this.getBoundingBox(t).getCenter(new e):this.center.clone()}hasCoords(){if(void 0===this._hasCoords){const t=this.atomStore;this._hasCoords=0!==Di(t.x)||0!==Ti(t.x)||0!==Di(t.y)||0!==Ti(t.y)||0!==Di(t.z)||0!==Ti(t.z)||t.count/this.modelStore.count==1}return this._hasCoords}getSequence(t){const e=[],i=this.getResidueProxy();return this.eachAtom((function(t){i.index=t.residueIndex,t.index===i.traceAtomIndex&&e.push(i.getResname1())}),t),e}getAtomIndices(t){if(t&&t.string){const e=[];return this.eachAtom((function(t){e.push(t.index)}),t),new Uint32Array(e)}{const t={what:{index:!0}};return this.getAtomData(t).index}}getChainnameCount(t){const e=new Set;return this.eachChain((function(t){t.residueCount&&e.add(t.chainname)}),t),e.size}updatePosition(t,e=!0){let i=0;this.eachAtom((function(e){e.positionFromArray(t,i),i+=3}),void 0),this._hasCoords=void 0,e&&this.refreshPosition()}refreshPosition(){this.getBoundingBox(void 0,this.boundingBox),this.boundingBox.getCenter(this.center),this.spatialHash=new Tn(this.atomStore,this.boundingBox),this.signals.refreshed.dispatch(this)}dispose(){this.frames&&(this.frames.length=0),this.boxes&&(this.boxes.length=0),this.bondStore.dispose(),this.backboneBondStore.dispose(),this.rungBondStore.dispose(),this.atomStore.dispose(),this.residueStore.dispose(),this.chainStore.dispose(),this.modelStore.dispose(),delete this.bondSet,delete this.atomSet}}const Cc=new a,Pc=[An,_n,Sn,wn,Cn,xn,bn,vn,In,Pn,kn,Mn],Ic={aspectRatio:1.5,sphereDetail:2,radialSegments:50,disableImpostor:!1,openEnded:!1,dashedCylinder:!1,labelParams:{},pointSize:2,sizeAttenuation:!1,useTexture:!0,linewidth:2};class kc{constructor(t="shape",e={}){this.boundingBox=new a,this.bufferList=[],this.meshCount=0,this._primitiveData={},this.name=t,this.parameters=nt(e,Ic),Pc.forEach((t=>{Object.keys(t.fields).forEach((e=>{this._primitiveData[t.getShapeKey(e)]=[]})),this._primitiveData[t.getShapeKey("name")]=[]}))}addBuffer(t){this.bufferList.push(t);const e=t.geometry;return e.boundingBox||e.computeBoundingBox(),this.boundingBox.union(e.boundingBox),this}addMesh(t,e,i,r,n){let s;t=St(t),e=St(e),Array.isArray(i)&&(i=bt(i,t.length)),r&&(r=St(r)),s=void 0===r||0==r.length?{position:t,color:e,index:i}:{position:t,color:e,index:i,normal:r};const o=new eo(this,Object.assign({serial:this.meshCount,name:n},s)),a=new Vo(Object.assign({picking:o},s));return this.bufferList.push(a),Cc.setFromArray(t),this.boundingBox.union(Cc),this.meshCount+=1,this}addSphere(t,e,i,r){return bn.objectToShape(this,{position:t,color:e,radius:i,name:r}),this}addEllipsoid(t,e,i,r,n,s){return Cn.objectToShape(this,{position:t,color:e,radius:i,majorAxis:r,minorAxis:n,name:s}),this}addTorus(t,e,i,r,n,s){return Pn.objectToShape(this,{position:t,color:e,radius:i,majorAxis:r,minorAxis:n,name:s}),this}addCylinder(t,e,i,r,n){return wn.objectToShape(this,{position1:t,position2:e,color:i,radius:r,name:n}),this}addCone(t,e,i,r,n){return Sn.objectToShape(this,{position1:t,position2:e,color:i,radius:r,name:n}),this}addArrow(t,e,i,r,n){return An.objectToShape(this,{position1:t,position2:e,color:i,radius:r,name:n}),this}addBox(t,e,i,r,n,s){return _n.objectToShape(this,{position:t,color:e,size:i,heightAxis:r,depthAxis:n,name:s}),this}addOctahedron(t,e,i,r,n,s){return xn.objectToShape(this,{position:t,color:e,size:i,heightAxis:r,depthAxis:n,name:s}),this}addTetrahedron(t,e,i,r,n,s){return vn.objectToShape(this,{position:t,color:e,size:i,heightAxis:r,depthAxis:n,name:s}),this}addText(t,e,i,r){return In.objectToShape(this,{position:t,color:e,size:i,text:r}),this}addPoint(t,e,i){return kn.objectToShape(this,{position:t,color:e,name:i}),this}addWideline(t,e,i,r,n){return this.parameters.linewidth=r,Mn.objectToShape(this,{position1:t,position2:e,color:i,name:n}),this}addLabel(t,e,i,r){return console.warn("Shape.addLabel is deprecated, use .addText instead"),this.addText(t,e,i,r)}getBufferList(){const t=[];return Pc.forEach((e=>{this._primitiveData[e.getShapeKey("color")].length&&t.push(e.bufferFromShape(this,this.parameters))})),this.bufferList.concat(t)}dispose(){this.bufferList.forEach((function(t){t.dispose()})),this.bufferList.length=0,Pc.forEach((t=>{Object.keys(t.fields).forEach((e=>{this._primitiveData[t.getShapeKey(e)].length=0})),this._primitiveData[t.getShapeKey("name")].length=0}))}get center(){return this._center||(this._center=this.boundingBox.getCenter(new e)),this._center}get type(){return"Shape"}}class Mc extends Nr{constructor(t,e,i){Array.isArray(t)||(t=[t]),super(t,e,i),this.type="buffer",this.parameters=Object.assign({},this.parameters,{colorScheme:null,colorScale:null,colorValue:null,colorDomain:null,colorMode:null}),this.buffer=t,this.init(i)}init(t){super.init(t),this.build()}create(){this.bufferList.push.apply(this.bufferList,this.buffer)}attach(t){this.bufferList.forEach((t=>{this.viewer.add(t),t.setParameters(this.getBufferParams())})),this.setVisibility(this.visible),t()}}const Tc=new i,Dc=new B;class Bc extends Vo{constructor(t,e={},i){super(function(t,e){const i=e.attributes.position.array,r=e.index?e.index.array:void 0,n=t.position.length/3,s=i.length/3,o=n*s,a=new Float32Array(3*o),c=new Float32Array(3*o),l=new Float32Array(3*o);let h;return r&&(h=bt(n*r.length,o)),{position:a,color:l,index:h,normal:c,primitiveId:t.primitiveId||Pi(n,s),picking:t.picking}}(t,i),e),this.updateNormals=!1;const r=i.attributes.position.array,n=i.attributes.normal.array,s=i.index?i.index.array:void 0;this.geoPosition=r,this.geoNormal=n,this.geoIndex=s,this.positionCount=t.position.length/3,this.geoPositionCount=r.length/3,this.transformedGeoPosition=new Float32Array(3*this.geoPositionCount),this.transformedGeoNormal=new Float32Array(3*this.geoPositionCount);const o=this.geometry.attributes;if(this.meshPosition=o.position.array,this.meshColor=o.color.array,this.meshNormal=o.normal.array,this.setAttributes(t),s){const t=this.geometry.getIndex();if(!t)return void ke.error("Index is null");this.meshIndex=t.array,this.makeIndex()}}setAttributes(t={},e=!1){const i=this.geometry.attributes;let r,n,s,o,a,c,l,h,u;const d=this.updateNormals;t.position&&(r=t.position,s=this.geoPosition,l=this.meshPosition,a=this.transformedGeoPosition,i.position.needsUpdate=!0,(d||e)&&(o=this.geoNormal,u=this.meshNormal,c=this.transformedGeoNormal,i.normal.needsUpdate=!0)),t.color&&(n=t.color,h=this.meshColor,i.color.needsUpdate=!0);const m=this.positionCount,f=this.geoPositionCount;for(let t=0;t 0.0 ){\ncameraPos = rayDirection * posT + rayOrigin;\ninterior = true;\nflag2 = true;\n}\n#else\nif( calcDepth( cameraPos ) <= 0.0 ){\ncameraPos = rayDirection * posT + rayOrigin;\ninterior = true;\n}\n#endif\ncameraNormal = normalize( cameraPos - cameraSpherePos );\ncameraNormal *= float(!interior) * 2.0 - 1.0;\nreturn !interior;\n}\nvoid main(void){\nbool flag = Impostor( cameraPos, cameraNormal );\n#ifdef NEAR_CLIP\nif( calcClip( cameraPos ) > 0.0 )\ndiscard;\n#endif\ngl_FragDepthEXT = calcDepth( cameraPos );\nif( !flag ){\n#ifdef NEAR_CLIP\nif( flag2 ){\ngl_FragDepthEXT = max( 0.0, calcDepth( vec3( - ( clipNear - 0.5 ) ) ) + ( 0.0000001 / vRadius ) );\n}else if( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n#else\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n#endif\n}\nif (gl_FragDepthEXT < 0.0)\ndiscard;\nif (gl_FragDepthEXT > 1.0)\ndiscard;\n#ifdef PICKING\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 vNormal = cameraNormal;\nvec3 vViewPosition = -cameraPos;\nvec4 diffuseColor = vec4( diffuse, opacity );\nReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\nvec3 totalEmissiveLight = emissive;\n#include color_fragment\n#include roughnessmap_fragment\n#include metalnessmap_fragment\n#include normal_fragment_begin\n#include lights_physical_fragment\n#include lights_fragment_begin\n#include lights_fragment_end\nvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveLight;\nif( interior ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");class Oc extends Uo{constructor(t,e,i={}){super(e,i),this.index=bt(this.indexSize,this.attributeSize),this.makeIndex(),this.initIndex(this.index),this.addAttributes({mapping:{type:t,value:null}}),this.setAttributes({primitiveId:Ci(this.size)})}get attributeSize(){return this.size*this.mappingSize}get indexSize(){return this.size*this.mappingIndicesSize}addAttributes(t){const e={};for(const i in t){const r=t[i];e[i]={type:r.type,value:null}}super.addAttributes(e)}getAttributeIndex(t){return 3*t*this.mappingSize}setAttributes(t){t&&!t.position&&t.position1&&t.position2&&(t.position=vi(t.position1,t.position2));const e=this.size,i=this.mappingSize,r=this.geometry.attributes;let n,s,o,a,c,l,h;for(const u in t)if("index"!==u&&"picking"!==u){s=t[u],n=r[u],o=n.itemSize,a=n.array;for(let t=0;t0&&this.parameters.alphaTest<=1&&(e.USE_ALPHATEST=1),e}setUniforms(t){t&&void 0!==t.edgeBleach&&(this.makeTexture(),t.map=this.tex),super.setUniforms(t)}dispose(){super.dispose(),this.tex&&this.tex.dispose()}}je.add("point",Hc);class qc extends Nr{constructor(t,e,i){super(t,e,i),this.type="dot",this.parameters=Object.assign({thresholdType:{type:"select",rebuild:!0,options:{value:"value",sigma:"sigma"}},thresholdMin:{type:"number",precision:3,max:1/0,min:-1/0,rebuild:!0},thresholdMax:{type:"number",precision:3,max:1/0,min:-1/0,rebuild:!0},thresholdOut:{type:"boolean",rebuild:!0},dotType:{type:"select",rebuild:!0,options:{"":"",sphere:"sphere",point:"point"}},radiusType:{type:"select",options:{"":"",value:"value","abs-value":"abs-value","value-min":"value-min",deviation:"deviation",size:"size"}},radius:{type:"number",precision:3,max:10,min:.001,property:"size"},scale:{type:"number",precision:3,max:10,min:.001},sphereDetail:!0,disableImpostor:!0,pointSize:{type:"number",precision:1,max:100,min:0,buffer:!0},sizeAttenuation:{type:"boolean",buffer:!0},sortParticles:{type:"boolean",rebuild:!0},useTexture:{type:"boolean",buffer:!0},alphaTest:{type:"range",step:.001,max:1,min:0,buffer:!0},forceTransparent:{type:"boolean",buffer:!0},edgeBleach:{type:"range",step:.001,max:1,min:0,buffer:!0}},this.parameters,{colorScheme:{type:"select",update:"color",options:{"":"",value:"value",uniform:"uniform",random:"random"}}}),t instanceof $o?(this.surface=void 0,this.volume=new ya(t)):(this.surface=t,this.volume=void 0),this.init(i)}init(t){var e=t||{};e.colorScheme=rt(e.colorScheme,"uniform"),e.colorValue=rt(e.colorValue,14540253),this.thresholdType=rt(e.thresholdType,"sigma"),this.thresholdMin=rt(e.thresholdMin,2),this.thresholdMax=rt(e.thresholdMax,1/0),this.thresholdOut=rt(e.thresholdOut,!1),this.dotType=rt(e.dotType,"point"),this.radius=rt(e.radius,.1),this.scale=rt(e.scale,1),this.pointSize=rt(e.pointSize,1),this.sizeAttenuation=rt(e.sizeAttenuation,!0),this.sortParticles=rt(e.sortParticles,!1),this.useTexture=rt(e.useTexture,!1),this.alphaTest=rt(e.alphaTest,.5),this.forceTransparent=rt(e.forceTransparent,!1),this.edgeBleach=rt(e.edgeBleach,0),super.init(e),this.build()}attach(t){this.bufferList.forEach((t=>{this.viewer.add(t)})),this.setVisibility(this.visible),t()}create(){var t={};if(this.volume){var e,i,r=this.volume;"sigma"===this.thresholdType?(e=r.getValueForSigma(this.thresholdMin),i=r.getValueForSigma(this.thresholdMax)):(e=this.thresholdMin,i=this.thresholdMax),r.setFilter(e,i,this.thresholdOut),Object.assign(t,{position:r.getDataPosition(),color:r.getDataColor(this.getColorParams())}),"sphere"===this.dotType&&Object.assign(t,{radius:r.getDataSize(this.radius,this.scale),picking:r.getDataPicking()})}else{var n=this.surface;Object.assign(t,{position:n.getPosition(),color:n.getColor(this.getColorParams())}),"sphere"===this.dotType&&Object.assign(t,{radius:n.getSize(this.radius,this.scale),picking:n.getPicking()})}"sphere"===this.dotType?this.dotBuffer=new Uc(t,this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!1})):this.dotBuffer=new Hc(t,this.getBufferParams({pointSize:this.pointSize,sizeAttenuation:this.sizeAttenuation,sortParticles:this.sortParticles,useTexture:this.useTexture,alphaTest:this.alphaTest,forceTransparent:this.forceTransparent,edgeBleach:this.edgeBleach})),this.bufferList.push(this.dotBuffer)}update(t={}){if(0===this.bufferList.length)return;const e={};t.color&&(this.volume?Object.assign(e,{color:this.volume.getDataColor(this.getColorParams())}):Object.assign(e,{color:this.surface.getColor(this.getColorParams())})),"sphere"===this.dotType&&(t.radius||t.scale)&&(this.volume?Object.assign(e,{radius:this.volume.getDataSize(this.radius,this.scale)}):Object.assign(e,{radius:this.surface.getSize(this.radius,this.scale)})),this.dotBuffer.setAttributes(e)}setParameters(t,e={},i){return t&&void 0!==t.thresholdType&&this.volume instanceof $o&&("value"===this.thresholdType&&"sigma"===t.thresholdType?(this.thresholdMin=this.volume.getSigmaForValue(this.thresholdMin),this.thresholdMax=this.volume.getSigmaForValue(this.thresholdMax)):"sigma"===this.thresholdType&&"value"===t.thresholdType&&(this.thresholdMin=this.volume.getValueForSigma(this.thresholdMin),this.thresholdMax=this.volume.getValueForSigma(this.thresholdMax)),this.thresholdType=t.thresholdType),t&&void 0!==t.radiusType&&("radius"===t.radiusType?this.radius=.1:this.radius=parseFloat(t.radiusType),e.radius=!0,"sphere"!==this.dotType||Pe&&!this.disableImpostor||(i=!0)),t&&void 0!==t.radius&&(e.radius=!0,"sphere"!==this.dotType||Pe&&!this.disableImpostor||(i=!0)),t&&void 0!==t.scale&&(e.scale=!0,"sphere"!==this.dotType||Pe&&!this.disableImpostor||(i=!0)),super.setParameters(t,e,i),this}}ze.add("shader/Image.vert","uniform float clipRadius;\nuniform vec3 clipCenter;\nvarying vec2 vUv;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvarying vec3 vViewPosition;\n#endif\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\nvoid main() {\n#include begin_vertex\n#include project_vertex\nvUv = uv;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvViewPosition = -mvPosition.xyz;\n#endif\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n}"),ze.add("shader/Image.frag","uniform sampler2D map;\nuniform float opacity;\nuniform vec2 mapSize;\nuniform float clipNear;\nuniform float clipRadius;\nvarying vec2 vUv;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvarying vec3 vViewPosition;\n#endif\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#if defined( PICKING )\nuniform sampler2D pickingMap;\nuniform float objectId;\n#else\n#include fog_pars_fragment\n#endif\n#if defined( CUBIC_INTERPOLATION )\n#if defined( CATMULROM_FILTER ) || defined( MITCHELL_FILTER )\n#if defined( CATMULROM_FILTER )\nconst float B = 0.0;\nconst float C = 0.5;\n#elif defined( MITCHELL_FILTER )\nconst float B = 0.333;\nconst float C = 0.333;\n#endif\nfloat applyFilter( float x ){\nfloat f = x;\nif( f < 0.0 ){\nf = -f;\n}\nif( f < 1.0 ){\nreturn ( ( 12.0 - 9.0 * B - 6.0 * C ) * ( f * f * f ) +\n( -18.0 + 12.0 * B + 6.0 *C ) * ( f * f ) +\n( 6.0 - 2.0 * B ) ) / 6.0;\n}else if( f >= 1.0 && f < 2.0 ){\nreturn ( ( -B - 6.0 * C ) * ( f * f * f )\n+ ( 6.0 * B + 30.0 * C ) * ( f *f ) +\n( - ( 12.0 * B ) - 48.0 * C ) * f +\n8.0 * B + 24.0 * C ) / 6.0;\n}else{\nreturn 0.0;\n}\n}\n#elif defined( BSPLINE_FILTER )\nfloat applyFilter( float x ){\nfloat f = x;\nif( f < 0.0 ){\nf = -f;\n}\nif( f >= 0.0 && f <= 1.0 ){\nreturn ( 2.0 / 3.0 ) + ( 0.5 ) * ( f * f * f ) - ( f * f );\n}else if( f > 1.0 && f <= 2.0 ){\nreturn 1.0 / 6.0 * pow( ( 2.0 - f ), 3.0 );\n}\nreturn 1.0;\n}\n#else\nfloat applyFilter( float x ){\nreturn 1.0;\n}\n#endif\nvec4 biCubic( sampler2D tex, vec2 texCoord ){\nvec2 texelSize = 1.0 / mapSize;\ntexCoord -= texelSize / 2.0;\nvec4 nSum = vec4( 0.0 );\nfloat nDenom = 0.0;\nvec2 cell = fract( texCoord * mapSize );\nfor( float m = -1.0; m <= 2.0; ++m ){\nfor( float n = -1.0; n <= 2.0; ++n ){\nvec4 vecData = texture2D(\ntex, texCoord + texelSize * vec2( m, n )\n);\nfloat c = applyFilter( m - cell.x ) * applyFilter( -n + cell.y );\nnSum += vecData * c;\nnDenom += c;\n}\n}\nreturn nSum / nDenom;\n}\n#endif\nvoid main(){\n#include nearclip_fragment\n#include radiusclip_fragment\n#if defined( CUBIC_INTERPOLATION )\ngl_FragColor = biCubic( map, vUv );\n#else\ngl_FragColor = texture2D( map, vUv );\n#endif\n#if defined( PICKING )\nif( gl_FragColor.a < 0.3 )\ndiscard;\ngl_FragColor = vec4( texture2D( pickingMap, vUv ).xyz, objectId );\n#else\nif( gl_FragColor.a < 0.01 )\ndiscard;\ngl_FragColor.a *= opacity;\n#include fog_fragment\n#endif\n}");const Wc=new Uint16Array([0,1,2,1,3,2]),Xc=new Float32Array([0,1,0,0,1,1,1,0]),Yc=Object.assign({filter:"nearest",forceTransparent:!0},No),Kc=Object.assign({filter:{updateShader:!0,uniform:!0}},zo);class Zc extends Uo{constructor(e,i){super({position:e.position,index:Wc,picking:e.picking},i),this.parameterTypes=Kc,this.alwaysTransparent=!0,this.hasWireframe=!1,this.vertexShader="Image.vert",this.fragmentShader="Image.frag";const{imageData:r,width:n,height:s}=e,o=new V(r,n,s);o.flipY=!0,this.tex=o;const a=r.length,c=new Uint8Array(a);for(let t=0;t>16&255,c[t+1]=e>>8&255,c[t+2]=255&e}const l=new V(c,n,s);l.flipY=!0,l.minFilter=b,l.magFilter=b,this.pickingTex=l,this.addUniforms({map:{value:o},pickingMap:{value:l},mapSize:{value:new t(n,s)}}),this.geometry.setAttribute("uv",new M(Xc,2))}get defaultParameters(){return Yc}getDefines(t){const e=super.getDefines(t),i=this.parameters.filter;return i.startsWith("cubic")&&(e.CUBIC_INTERPOLATION=1,i.endsWith("bspline")?e.BSPLINE_FILTER=1:i.endsWith("catmulrom")?e.CATMULROM_FILTER=1:i.endsWith("mitchell")&&(e.MITCHELL_FILTER=1)),e}updateTexture(){const t=this.tex,e=this.parameters.filter;e.startsWith("cubic")?(t.minFilter=b,t.magFilter=b):"linear"===e?(t.minFilter=v,t.magFilter=v):(t.minFilter=b,t.magFilter=b),t.needsUpdate=!0,this.pickingTex.needsUpdate=!0}makeMaterial(){super.makeMaterial(),this.updateTexture();const t=this.material;t.uniforms.map.value=this.tex,t.blending=j,t.needsUpdate=!0;const e=this.wireframeMaterial;e.uniforms.map.value=this.tex,e.blending=j,e.needsUpdate=!0;const i=this.pickingMaterial;i.uniforms.map.value=this.tex,i.uniforms.pickingMap.value=this.pickingTex,i.blending=j,i.needsUpdate=!0}setUniforms(t){t&&void 0!==t.filter&&(this.updateTexture(),t.map=this.tex),super.setUniforms(t)}}class Qc{constructor(t,e){const i=e||{};this.dimension=rt(i.dimension,"x"),this.positionType=rt(i.positionType,"percent"),this.position=rt(i.position,30),this.thresholdType=rt(i.thresholdType,"sigma"),this.thresholdMin=rt(i.thresholdMin,-1/0),this.thresholdMax=rt(i.thresholdMax,1/0),this.normalize=rt(i.normalize,!1),this.volume=t}getPositionFromCoordinate(t){const i=this.dimension,r=this.volume,n=r.matrix,s=(new e).setFromMatrixPosition(n)[i],o=(new e).setFromMatrixScale(n)[i];let a;return a="x"===i?r.nx:"y"===i?r.ny:r.nz,Math.round(((t-s)/(a/100)+1)/o)}getData(t){t=t||{};const i=this.volume,r=i.data,n=i.matrix;let s;function o(t){return Math.round(t/100*(s-1))}function a(t,e,r,n){return 3*(r*i.ny*i.nx+e*i.nx+t)+n}s="coordinate"===this.positionType?this.getPositionFromCoordinate(this.position):this.position;const c=new Float32Array(12),l=new e;let h,u,d,m,f,p=0,g=0,y=0,b=i.nx,_=i.ny,x=i.nz;function v(t,e,i,r){l.set(t,e,i).applyMatrix4(n).toArray(c,r)}"x"===this.dimension?(d=o(i.nx),m=i.ny-1,f=i.nz-1,h=i.nz,u=i.ny,p=d,b=p+1,v(d,0,0,0),v(d,m,0,3),v(d,0,f,6),v(d,m,f,9)):"y"===this.dimension?(d=i.nx-1,m=o(i.ny),f=i.nz-1,h=i.nz,u=i.nx,g=m,_=g+1,v(0,m,0,0),v(d,m,0,3),v(0,m,f,6),v(d,m,f,9)):"z"===this.dimension&&(d=i.nx-1,m=i.ny-1,f=o(i.nz),h=i.nx,u=i.ny,y=f,x=y+1,v(0,0,f,0),v(0,m,f,3),v(d,0,f,6),v(d,m,f,9));let w=0,A=0;const S=new Uint8Array(h*u*4),C=new Float32Array(h*u);let P,I;"sigma"===this.thresholdType?(P=i.getValueForSigma(this.thresholdMin),I=i.getValueForSigma(this.thresholdMax)):(P=this.thresholdMin,I=this.thresholdMax);const k=Object.assign({},t.colorParams,{volume:i});this.normalize&&(k.domain=[0,1]);const M=Oe.getScheme(k),T=new Float32Array(3),D=M.getScale();let B,F=0,E=0;if(this.normalize){F=1/0,B=-1/0;for(let t=g;t<_;++t)for(let e=p;eB&&(B=n)}E=B-F}for(let t=g;t<_;++t)for(let e=p;eP&&s{this.viewer.add(t)})),this.setVisibility(this.visible),t()}create(){const t=new Qc(this.volume,{positionType:this.positionType,position:this.position,dimension:this.dimension,thresholdType:this.thresholdType,thresholdMin:this.thresholdMin,thresholdMax:this.thresholdMax,normalize:this.normalize}),e=new Zc(t.getData({colorParams:this.getColorParams()}),this.getBufferParams({filter:this.filter}));this.bufferList.push(e)}}function tl(t){ke.error(`makeRepresentation: representation type ${t} unknown`)}const el={name:"some element",status:""};class il{constructor(t,e={}){this.stage=t,this.signals={statusChanged:new tt,nameChanged:new tt,disposed:new tt},this.parameters=nt(e,this.defaultParameters),this.uuid=Tt()}get defaultParameters(){return el}get name(){return this.parameters.name}setStatus(t){return this.parameters.status=t,this.signals.statusChanged.dispatch(t),this}setName(t){return this.parameters.name=t,this.signals.nameChanged.dispatch(t),this}dispose(){this.signals.disposed.dispatch()}}const rl=Object.assign({visible:!0},el);class nl extends il{constructor(t,e,i={},r){super(t,Object.assign({name:e.type},i)),this.parent=r,this.signals=Object.assign({visibilityChanged:new tt,parametersChanged:new tt},this.signals),this.setRepresentation(e)}get defaultParameters(){return rl}get visible(){return this.parameters.visible}get type(){return"representation"}getType(){return this.repr.type}setRepresentation(t){this._disposeRepresentation(),this.repr=t,this.stage.tasks.listen(this.repr.tasks),this.updateVisibility()}_disposeRepresentation(){this.repr&&(this.stage.tasks.unlisten(this.repr.tasks),this.repr.dispose())}dispose(){this.parent&&this.parent.hasRepresentation(this)?this.parent.removeRepresentation(this):(this._disposeRepresentation(),this.signals.disposed.dispatch())}setVisibility(t){return this.parameters.visible=t,this.updateVisibility(),this.signals.visibilityChanged.dispatch(this.parameters.visible),this}getVisibility(){return this.parent?this.parent.parameters.visible&&this.parameters.visible:this.parameters.visible}toggleVisibility(){return this.setVisibility(!this.parameters.visible)}updateVisibility(){this.repr.setVisibility(this.getVisibility())}update(t){return this.repr.update(t),this}build(t){return this.repr.build(t),this}setSelection(t){const e=this.repr;return e.setSelection&&e.setSelection(t),this}setParameters(t){return this.repr.setParameters(t),this.signals.parametersChanged.dispatch(this.repr.getParameters()),this}getParameters(){return this.repr.getParameters()}setColor(t){return this.repr.setColor(t),this}}const sl=new i,ol=new e,al={name:"",status:"",visible:!0};class cl{constructor(t,n,s={}){this.stage=t,this.object=n,this.signals={representationAdded:new tt,representationRemoved:new tt,visibilityChanged:new tt,matrixChanged:new tt,statusChanged:new tt,nameChanged:new tt,disposed:new tt},this.reprList=[],this.annotationList=[],this.matrix=new i,this.position=new e,this.quaternion=new r,this.scale=new e(1,1,1),this.transform=new i,this.parameters=nt(s,this.defaultParameters),this.uuid=Tt(),this.viewer=t.viewer,this.controls=new ua(this)}get defaultParameters(){return al}get name(){return this.parameters.name}get status(){return this.parameters.status}get visible(){return this.parameters.visible}setPosition(t){return Array.isArray(t)?this.position.fromArray(t):this.position.copy(t),this.updateMatrix(),this}setRotation(t){if(Array.isArray(t))if(3===t.length){const e=(new G).fromArray(t);this.quaternion.setFromEuler(e)}else this.quaternion.fromArray(t);else t instanceof G?this.quaternion.setFromEuler(t):this.quaternion.copy(t);return this.updateMatrix(),this}setScale(t){return this.scale.set(t,t,t),this.updateMatrix(),this}setTransform(t){return this.transform.copy(t),this.updateMatrix(),this}updateMatrix(){const t=this.getCenterUntransformed(ol);this.matrix.makeTranslation(-t.x,-t.y,-t.z),sl.makeRotationFromQuaternion(this.quaternion),this.matrix.premultiply(sl),sl.makeScale(this.scale.x,this.scale.y,this.scale.z),this.matrix.premultiply(sl);const e=this.position;sl.makeTranslation(e.x+t.x,e.y+t.y,e.z+t.z),this.matrix.premultiply(sl),this.matrix.premultiply(this.transform),this.updateRepresentationMatrices(),this.stage.viewer.updateBoundingBox(),this.signals.matrixChanged.dispatch(this.matrix)}updateRepresentationMatrices(){this.reprList.forEach((t=>{t.setParameters({matrix:this.matrix})}))}addAnnotation(t,e,i){const r=new aa(this,t,e,i);return this.annotationList.push(r),r}eachAnnotation(t){this.annotationList.slice().forEach(t)}removeAnnotation(t){const e=this.annotationList.indexOf(t);-1!==e&&(this.annotationList.splice(e,1),t.dispose())}removeAllAnnotations(){this.eachAnnotation((t=>t.dispose())),this.annotationList.length=0}_addRepresentation(t,e,i,r=!1){const n=i||{},s=this.stage.getParameters();n.matrix=this.matrix.clone(),n.quality=n.quality||s.quality,n.disableImpostor=rt(n.disableImpostor,!s.impostor),n.useWorker=rt(n.useWorker,s.workerDefault),n.visible=rt(n.visible,!0);const o=Object.assign({},n,{visible:this.parameters.visible&&n.visible}),a=function(t,e,i,r){var n;if(De&&ke.time("makeRepresentation "+t),e instanceof Sc){if(!(n=Le.get(t)))return void tl(t)}else if(e instanceof Fo)if("surface"===t)n=Xo;else{if("dot"!==t)return void tl(t);n=qc}else if(e instanceof $o)if("surface"===t)n=Xo;else if("dot"===t)n=qc;else{if("slice"!==t)return void tl(t);n=Jc}else if(e instanceof kc)n=Mc,e=e.getBufferList();else{if("buffer"!==t)return void ke.error("makeRepresentation: object "+e+" unknown");n=Mc}const s=new n(e,i,r);return De&&ke.timeEnd("makeRepresentation "+t),s}(t,e,this.viewer,o),c=new nl(this.stage,a,n,this);return r||(this.reprList.push(c),this.signals.representationAdded.dispatch(c)),c}addBufferRepresentation(t,e){return this._addRepresentation.call(this,"buffer",t,e)}hasRepresentation(t){return-1!==this.reprList.indexOf(t)}eachRepresentation(t){this.reprList.slice().forEach(t)}removeRepresentation(t){const e=this.reprList.indexOf(t);-1!==e&&(this.reprList.splice(e,1),t.dispose(),this.signals.representationRemoved.dispatch(t))}updateRepresentations(t){this.reprList.forEach((e=>e.update(t))),this.stage.viewer.requestRender()}removeAllRepresentations(){this.eachRepresentation((t=>t.dispose()))}dispose(){this.removeAllAnnotations(),this.removeAllRepresentations(),this.reprList.length=0,this.signals.disposed.dispatch()}setVisibility(t){return this.parameters.visible=t,this.eachRepresentation((t=>t.updateVisibility())),this.eachAnnotation((t=>t.updateVisibility())),this.signals.visibilityChanged.dispatch(t),this}setStatus(t){return this.parameters.status=t,this.signals.statusChanged.dispatch(t),this}setName(t){return this.parameters.name=t,this.signals.nameChanged.dispatch(t),this}getBox(...t){return this.getBoxUntransformed(...t).clone().applyMatrix4(this.matrix)}getCenter(...t){return this.getCenterUntransformed(...t).clone().applyMatrix4(this.matrix)}getZoom(...t){return this.stage.getZoomForBox(this.getBox(...t))}getBoxUntransformed(...t){return new a}getCenterUntransformed(...t){return this.getBoxUntransformed().getCenter(new e)}autoView(t){this.stage.animationControls.zoomMove(this.getCenter(),this.getZoom(),rt(t,0))}}class ll{constructor(t=[]){this.list=t;const e=t.length;for(let i=0;i0?this.list[0]:void 0}forEach(t){return this.list.forEach(t),this}dispose(){return this.forEach((t=>t.dispose()))}}class hl extends ll{setParameters(t){return this.forEach((e=>e.setParameters(t)))}setVisibility(t){return this.forEach((e=>e.setVisibility(t)))}setSelection(t){return this.forEach((e=>e.setSelection(t)))}setColor(t){return this.forEach((e=>e.setColor(t)))}update(t){return this.forEach((e=>e.update(t)))}build(t){return this.forEach((e=>e.build(t)))}dispose(t){return this.forEach((t=>t.dispose()))}}const ul=Object.assign({defaultStep:1,defaultTimeout:50,defaultInterpolateType:"",defaultInterpolateStep:5,defaultMode:"loop",defaultDirection:"forward",initialFrame:0},el);class dl extends il{constructor(t,e,i={}){super(t,Object.assign({name:e.name},i)),this.trajectory=e,this.signals=Object.assign(this.signals,{frameChanged:new tt,playerChanged:new tt,countChanged:new tt,parametersChanged:new tt}),e.signals.frameChanged.add((t=>{this.signals.frameChanged.dispatch(t)})),e.signals.playerChanged.add((t=>{this.signals.playerChanged.dispatch(t)})),e.signals.countChanged.add((t=>{this.signals.countChanged.dispatch(t)})),void 0!==i.initialFrame&&this.setFrame(i.initialFrame)}get defaultParameters(){return ul}get type(){return"trajectory"}setFrame(t){this.trajectory.setFrame(t)}setParameters(t={}){this.trajectory.setParameters(t),this.signals.parametersChanged.dispatch(t)}dispose(){this.trajectory.dispose(),super.dispose()}}class ml{constructor(t,e){this.name=t,this.path=e,this.coordinates=[],this.boxes=[],this.times=[],this.timeOffset=0,this.deltaTime=1}get type(){return"Frames"}}class fl{constructor(t,e){let r,n;if(this.A=new lo(3,3),this.W=new lo(1,3),this.U=new lo(3,3),this.V=new lo(3,3),this.VH=new lo(3,3),this.R=new lo(3,3),this.tmp=new lo(3,3),this.c=new lo(3,3),t instanceof Sc)r=t.atomCount;else{if(!(t instanceof Float32Array))return;r=t.length/3}if(e instanceof Sc)n=e.atomCount;else{if(!(e instanceof Float32Array))return;n=e.length/3}const s=Math.min(r,n),o=new lo(3,s),a=new lo(3,s);this.coords1t=new lo(s,3),this.coords2t=new lo(s,3),this.transformationMatrix=new i,this.c.data.set([1,0,0,0,1,0,0,0,-1]),this.prepCoords(t,o,s,!1),this.prepCoords(e,a,s,!1),this._superpose(o,a)}_superpose(t,e){this.mean1=fo(t),this.mean2=fo(e),po(t,this.mean1),po(e,this.mean2),ho(this.coords1t,t),ho(this.coords2t,e),uo(this.A,this.coords2t,this.coords1t),xo(this.A,this.W,this.U,this.V),function(t,e){const i=t.data,r=e.data,n=i[4],s=i[8],o=i[5],a=i[7],c=i[0],l=c*n,h=c*o,u=i[3],d=i[1],m=u*d,f=i[2],p=u*f,g=i[6],y=g*d,b=g*f,_=1/(l*s-h*a-m*s+p*a+y*o-b*n);r[0]=(n*s-o*a)*_,r[1]=-(d*s-f*a)*_,r[2]=-(-d*o+f*n)*_,r[3]=-(u*s-o*g)*_,r[4]=(c*s-b)*_,r[5]=-(h-p)*_,r[6]=-(-u*a+n*g)*_,r[7]=-(c*a-y)*_,r[8]=(l-m)*_}(this.V,this.VH),mo(this.R,this.U,this.VH),function(t){const e=t.data;return e[0]*e[4]*e[8]-e[0]*e[5]*e[7]-e[3]*e[1]*e[8]+e[3]*e[2]*e[7]+e[6]*e[1]*e[5]-e[6]*e[2]*e[4]}(this.R)<0&&(De&&ke.log("R not a right handed system"),mo(this.tmp,this.c,this.VH),mo(this.R,this.U,this.tmp));const i=new lo(4,4),r=new lo(4,4),n=new lo(4,4),s=new lo(4,4),o=new lo(4,4),a=new lo(4,4),c=this.R.data,l=this.mean1,h=this.mean2;s.data.set([1,0,0,-l[0],0,1,0,-l[1],0,0,1,-l[2],0,0,0,1]),o.data.set([c[0],c[1],c[2],0,c[3],c[4],c[5],0,c[6],c[7],c[8],0,0,0,0,1]),a.data.set([1,0,0,h[0],0,1,0,h[1],0,0,1,h[2],0,0,0,1]),ho(r,s),uo(i,o,r),ho(n,i),uo(r,a,n),ho(i,r),this.transformationMatrix.elements=i.data}prepCoords(t,e,i,r){let n=0;const s=e.data;let o=3,a=3*i;if(r&&(a=4*i,o=4),t instanceof Sc)t.eachAtom((function(t){n{t!==this&&this.pause()}),this);const i=rt(t.frameCount,1);this.traj=t,this.parameters=nt(e,pl),this.parameters.end=Math.min(rt(e.end,i-1),i-1),this.parameters.step=rt(e.step,Math.ceil((i+1)/100)),this._currentFrame=this.parameters.start,this._direction="bounce"===this.parameters.direction?"forward":this.parameters.direction,t.signals.countChanged.add((t=>{this.parameters.end=Math.min(rt(this.parameters.end,t-1),t-1)}),this),this._animate=this._animate.bind(this)}get isRunning(){return this._run}setParameters(t={}){st(this.parameters,t),void 0!==t.direction&&"bounce"!==this.parameters.direction&&(this._direction=this.parameters.direction)}_animate(){if(!this._run)return;this._currentTime=window.performance.now();const t=this._currentTime-this._previousTime,e=this.parameters.interpolateType?this.parameters.interpolateStep:1,i=this.parameters.timeout/e,r=this.traj;if(r&&r.frameCount&&!r.inProgress&&t>=i)if(this.parameters.interpolateType)if(this._currentStep>this.parameters.interpolateStep&&(this._currentStep=1),1===this._currentStep&&(this._currentFrame=this._nextInterpolated()),r.hasFrame(this._currentFrame)){this._currentStep+=1;const t=this._currentStep/(this.parameters.interpolateStep+1),[e,i,n,s]=this._currentFrame;r.setFrameInterpolated(e,i,n,s,t,this.parameters.interpolateType),this._previousTime=this._currentTime}else r.loadFrame(this._currentFrame);else{const t=this._next();r.hasFrame(t)?(r.setFrame(t),this._previousTime=this._currentTime):r.loadFrame(t)}window.requestAnimationFrame(this._animate)}_next(){const t=this.parameters;let e;return e="forward"===this._direction?this.traj.currentFrame+t.step:this.traj.currentFrame-t.step,(e>t.end||e=t.end?i=t.start:"backward"===t.direction&&e<=t.start&&(i=t.end),this.traj.setFrame(i),this._run=!0,this._animate(),this.signals.startedRunning.dispatch()}}pause(){this._run=!1,this.signals.haltedRunning.dispatch()}stop(){this.pause(),this.traj.setFrame(this.parameters.start)}}class yl{constructor(t,e,i={}){this.signals={countChanged:new tt,frameChanged:new tt,playerChanged:new tt},this.frameCache={},this.loadQueue={},this.boxCache={},this.pathCache={},this.frameCacheSize=0,this._frameCount=0,this._currentFrame=-1,this._disposed=!1,this.deltaTime=rt(i.deltaTime,0),this.timeOffset=rt(i.timeOffset,0),this.centerPbc=rt(i.centerPbc,!1),this.removePbc=rt(i.removePbc,!1),this.removePeriodicity=rt(i.removePeriodicity,!1),this.superpose=rt(i.superpose,!1),this.name=t.replace(/^.*[\\/]/,""),this.trajPath=t,this.selection=new me(rt(i.sele,"backbone and not hydrogen")),this.selection.signals.stringChanged.add((()=>{this.selectionIndices=this.structure.getAtomIndices(this.selection),this._resetCache(),this._saveInitialCoords(),this.setFrame(this._currentFrame)}))}get frameCount(){return this._frameCount}get currentFrame(){return this._currentFrame}_init(t){this.setStructure(t),this._loadFrameCount(),this.setPlayer(new gl(this))}_loadFrameCount(){}setStructure(t){this.structure=t,this.atomCount=t.atomCount,this.backboneIndices=this._getIndices(new me("backbone and not hydrogen")),this._makeAtomIndices(),this._saveStructureCoords(),this.selectionIndices=this._getIndices(this.selection),this._resetCache(),this._saveInitialCoords(),this.setFrame(this._currentFrame)}_saveInitialCoords(){this.structure.hasCoords()?(this.initialCoords=new Float32Array(this.structureCoords),this._makeSuperposeCoords()):this.frameCache[0]?(this.initialCoords=new Float32Array(this.frameCache[0]),this._makeSuperposeCoords()):this.loadFrame(0,(()=>this._saveInitialCoords()))}_saveStructureCoords(){this.structureCoords=this.structure.getAtomData({what:{position:!0}}).position}setSelection(t){return this.selection.setString(t),this}_getIndices(t){let e=0;const i=t.test,r=[];return i&&this.structure.eachAtom((t=>{i(t)&&r.push(e),e+=1})),r}_makeSuperposeCoords(){const t=3*this.selectionIndices.length;this.coords1=new Float32Array(t),this.coords2=new Float32Array(t);const e=this.initialCoords,i=this.coords2;for(let r=0;r!!this.frameCache[t])):!!this.frameCache[t]}setFrame(t,e){return void 0===t||(this.inProgress=!0,-1===t||this.frameCache[t]?(this._updateStructure(t),e&&e()):this.loadFrame(t,(()=>{this._updateStructure(t),e&&e()}))),this}_interpolate(t,e,i,r,n,s){const o=this.frameCache;let a;a="spline"===s?function(t,e,i,r,n){const s=t.length,o=new Float32Array(s);for(let a=0;a{this._interpolate(t,e,i,r,n,s),o&&o()})):(this._interpolate(t,e,i,r,n,s),o&&o()),this}loadFrame(t,e){Array.isArray(t)?t.forEach((t=>{this.loadQueue[t]||this.frameCache[t]||(this.loadQueue[t]=!0,this._loadFrame(t,(()=>{delete this.loadQueue[t]})))})):this.loadQueue[t]||this.frameCache[t]||(this.loadQueue[t]=!0,this._loadFrame(t,(()=>{delete this.loadQueue[t],e&&e()})))}_loadFrame(t,e){ke.error("Trajectory._loadFrame not implemented",t,e)}_updateStructure(t){this._disposed?console.error("updateStructure: traj disposed"):(-1===t?this.structureCoords&&this.structure.updatePosition(this.structureCoords):this.structure.updatePosition(this.frameCache[t]),this.structure.trajectory={name:this.trajPath,frame:t},this._currentFrame=t,this.inProgress=!1,this.signals.frameChanged.dispatch(t))}_doSuperpose(t){const e=3*this.selectionIndices.length,i=this.coords1,r=this.coords2;for(let r=0;r0&&this.centerPbc){const t=[e[0],e[4],e[8]],r=function(t,e,i){return[xi(e,i[0],3,0,t),xi(e,i[1],3,1,t),xi(e,i[2],3,2,t)]}(this.backboneIndices,i,t);!function(t,e,i){if(0===i[0]||0===i[8]||0===i[4])return;const r=t.length,n=i[0],s=i[1],o=i[2],a=-e[0]+n+n/2,c=-e[1]+s+s/2,l=-e[2]+o+o/2;for(let e=0;e.5&&(t[n+r]-=e[3*r+r]*Math.round(s))}}(i,e,t)}this.removePbc&&function(t,e){if(0===e[0]||0===e[8]||0===e[4])return;const i=t.length;for(let r=3;r.9*e[3*i+i])if(n>0)for(let n=0;n<3;++n)t[r+n]-=e[3*i+n];else for(let n=0;n<3;++n)t[r+n]+=e[3*i+n]}}(i,e)}this.selectionIndices.length>0&&this.coords1&&this.superpose&&this._doSuperpose(i),this.frameCache[t]=i,this.boxCache[t]=e,this.frameCacheSize+=1}_setFrameCount(t){t!==this._frameCount&&(this._frameCount=t,this.signals.countChanged.dispatch(t))}dispose(){this._resetCache(),this._disposed=!0,this.player&&this.player.stop()}setPlayer(t){this.player=t,this.signals.playerChanged.dispatch(t)}getFrameTime(t){return this.timeOffset+t*this.deltaTime}}class bl extends yl{constructor(t,e,i){const r=i||{};r.timeOffset=rt(r.timeOffset,t.timeOffset),r.deltaTime=rt(r.deltaTime,t.deltaTime),super("",e,r),this.name=t.name,this.path=t.path,this.frames=t.coordinates,this.boxes=t.boxes,this._init(e)}get type(){return"frames"}_makeAtomIndices(){"StructureView"===this.structure.type?this.atomIndices=this.structure.getAtomIndices():this.atomIndices=void 0}_loadFrame(t,e){let i;const r=this.frames[t];if(this.atomIndices){const t=this.atomIndices,e=t.length;i=new Float32Array(3*e);for(let n=0;n{const n=i.response;if(!n)return void ke.error(`empty arrayBuffer for '${r}'`);const s=new Int32Array(n,0,1)[0],o=new Float32Array(n,8,9),a=new Float32Array(n,44);this._process(t,o,a,s),"function"==typeof e&&e()}),!1),i.send(n)}_loadFrameCount(){const t=new XMLHttpRequest,e=qe.getCountUrl(this.trajPath);t.open("GET",e,!0),t.addEventListener("load",(()=>{this._setFrameCount(parseInt(t.response))}),!1),t.send()}}class vl extends yl{constructor(t,e,i){super("",e,i),this.requestCallback=t,this._init(e)}get type(){return"callback"}_makeAtomIndices(){const t=[];if("StructureView"===this.structure.type){const e=this.structure.getAtomIndices(),i=e.length;let r=e[0],n=e[0];for(let s=1;s{this._process(t,i,r,n),"function"==typeof e&&e()}),t,this.atomIndices)}_loadFrameCount(){this.requestCallback((t=>this._setFrameCount(t)))}}Sc.prototype.getView=function(t){return new wl(this,t)};class wl extends Sc{constructor(t,i){super(),this.structure=t,this.selection=i,this.center=new e,this.boundingBox=new a,this._bp=this.getBondProxy(),this._ap=this.getAtomProxy(),this._rp=this.getResidueProxy(),this._cp=this.getChainProxy(),this.selection&&this.selection.signals.stringChanged.add(this.refresh,this),this.structure.signals.refreshed.add(this.refresh,this),this.refresh()}init(){}get type(){return"StructureView"}get name(){return this.structure.name}get path(){return this.structure.path}get title(){return this.structure.title}get id(){return this.structure.id}get data(){return this.structure.data}get atomSetDict(){return this.structure.atomSetDict}get biomolDict(){return this.structure.biomolDict}get entityList(){return this.structure.entityList}get unitcell(){return this.structure.unitcell}get frames(){return this.structure.frames}get boxes(){return this.structure.boxes}get validation(){return this.structure.validation}get bondStore(){return this.structure.bondStore}get backboneBondStore(){return this.structure.backboneBondStore}get rungBondStore(){return this.structure.rungBondStore}get atomStore(){return this.structure.atomStore}get residueStore(){return this.structure.residueStore}get chainStore(){return this.structure.chainStore}get modelStore(){return this.structure.modelStore}get atomMap(){return this.structure.atomMap}get residueMap(){return this.structure.residueMap}get bondHash(){return this.structure.bondHash}get spatialHash(){return this.structure.spatialHash}get _hasCoords(){return this.structure._hasCoords}set _hasCoords(t){this.structure._hasCoords=t}refresh(){De&&ke.time("StructureView.refresh"),this.atomSetCache={};const t=this.structure;if(this.selection.isAllSelection()&&t!==this&&t.atomSet&&t.bondSet){this.atomSet=t.atomSet.clone(),this.bondSet=t.bondSet.clone();for(let t in this.atomSetDict){const e=this.atomSetDict[t];this.atomSetCache["__"+t]=e.clone()}this.atomCount=t.atomCount,this.bondCount=t.bondCount,this.boundingBox.copy(t.boundingBox),this.center.copy(t.center)}else if(this.selection.isNoneSelection()&&t!==this&&t.atomSet&&t.bondSet){this.atomSet=new En(t.atomCount),this.bondSet=new En(t.bondCount);for(let e in this.atomSetDict)this.atomSetCache["__"+e]=new En(t.atomCount);this.atomCount=0,this.bondCount=0,this.boundingBox.makeEmpty(),this.center.set(0,0,0)}else{this.atomSet=this.getAtomSet(this.selection,!0),t.atomSet&&(this.atomSet=this.atomSet.intersection(t.atomSet)),this.bondSet=this.getBondSet();for(let t in this.atomSetDict){const e=this.atomSetDict[t];this.atomSetCache["__"+t]=e.makeIntersection(this.atomSet)}this.atomCount=this.atomSet.getSize(),this.bondCount=this.bondSet.getSize(),this.boundingBox=this.getBoundingBox(),this.center=this.boundingBox.getCenter(new e)}De&&ke.timeEnd("StructureView.refresh"),this.signals.refreshed.dispatch()}setSelection(t){this.selection=t,this.refresh()}getSelection(t){const e=[];t&&t.string&&e.push(t.string);const i=this.structure.getSelection();i&&i.string&&e.push(i.string),this.selection&&this.selection.string&&e.push(this.selection.string);let r="";return e.length>0&&(r=`( ${e.join(" ) AND ( ")} )`),new me(r)}getStructure(){return this.structure.getStructure()}eachBond(t,e){this.structure.eachBond(t,this.getSelection(e))}eachAtom(t,e){const i=this.getAtomProxy(),r=this.getAtomSet(e),n=this.atomStore.count;if(r.getSize()=this.V[i][r]?(e="S",this.score=this.S[i][r]):this.V[i][r]>=this.H[i][r]?(e="V",this.score=this.V[i][r]):(e="H",this.score=this.H[i][r]),De&&ke.log("Alignment: SCORE",this.score),De&&ke.log("Alignment: S, V, H",this.S[i][r],this.V[i][r],this.H[i][r]);i>0&&r>0;)"S"===e?this.S[i][r]===this.S[i-1][r-1]+t(i-1,r-1)?(this.ali1=this.seq1[i-1]+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--i,--r,e="S"):this.S[i][r]===this.V[i][r]?e="V":this.S[i][r]===this.H[i][r]?e="H":(--i,--r):"V"===e?this.V[i][r]===this.V[i-1][r]+this.gapExtensionPenalty?(this.ali1=this.seq1[i-1]+this.ali1,this.ali2="-"+this.ali2,--i,e="V"):this.V[i][r]===this.S[i-1][r]+this.gap(0)?(this.ali1=this.seq1[i-1]+this.ali1,this.ali2="-"+this.ali2,--i,e="S"):--i:"H"===e?this.H[i][r]===this.H[i][r-1]+this.gapExtensionPenalty?(this.ali1="-"+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--r,e="H"):this.H[i][r]===this.S[i][r-1]+this.gap(0)?(this.ali1="-"+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--r,e="S"):--r:ke.error("Alignment: no matrix");for(;i>0;)this.ali1=this.seq1[i-1]+this.ali1,this.ali2="-"+this.ali2,--i;for(;r>0;)this.ali1="-"+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--r;De&&ke.timeEnd("Alignment.trace"),De&&ke.log([this.ali1,this.ali2])}}function Il(t,e,i=!1,r="",n=""){let s,o,a,c,l;if(i){let i=t,h=e;r&&n&&(i=t.getView(new me(r)),h=e.getView(new me(n)));const u=i.getSequence(),d=h.getSequence(),m=new Pl(u.join(""),d.join(""));let f,p;m.calc(),m.trace(),s=0,o=0,a=m.ali1.length;const g=[],y=[];for(let t=0;tt[e]))}}}(),this.spacefillRepresentation=this.addRepresentation("spacefill",{sele:"none",opacity:Me.opacity,color:Me.color,disablePicking:!0,radiusType:"data"},!0),this.distanceRepresentation=this.addRepresentation("distance",Me,!0),this.angleRepresentation=this.addRepresentation("angle",Me,!0),this.dihedralRepresentation=this.addRepresentation("dihedral",Me,!0),this.measureRepresentations=new hl([this.spacefillRepresentation,this.distanceRepresentation,this.angleRepresentation,this.dihedralRepresentation]),this.setDefaultAssembly(this.parameters.defaultAssembly),this.structure.signals.refreshed.add((()=>{this.updateRepresentations({position:!0})}))}get defaultParameters(){return kl}get type(){return"structure"}initSelection(t){this.selection=new me(t),this.structureView=new wl(this.structure,this.selection),this.selection.signals.stringChanged.add((()=>{this.structureView.setSelection(this.selection),this.rebuildRepresentations(),this.rebuildTrajectories()}))}setSelection(t){return this.parameters.sele=t,this.selection.setString(t),this}setDefaultAssembly(t){if(void 0===this.structure.biomolDict[t]&&(t=""),this.parameters.defaultAssembly!==t){const e={defaultAssembly:t};this.reprList.forEach((t=>t.setParameters(e))),this.measureRepresentations.setParameters(e),this.parameters.defaultAssembly=t,this.signals.defaultAssemblyChanged.dispatch(t)}return this}rebuildRepresentations(){this.reprList.forEach((t=>{t.build()})),this.measureRepresentations.build()}rebuildTrajectories(){this.trajList.forEach((t=>{t.trajectory.setStructure(this.structureView)}))}updateRepresentations(t){super.updateRepresentations(t),this.measureRepresentations.update(t)}updateRepresentationMatrices(){super.updateRepresentationMatrices(),this.measureRepresentations.setParameters({matrix:this.matrix})}addRepresentation(t,e={},i=!1){e.defaultAssembly=this.parameters.defaultAssembly;const r=this._addRepresentation(t,this.structureView,e,i);return i||r.signals.parametersChanged.add((()=>this.measureUpdate())),r}addTrajectory(t="",e={}){const i=function(t,e,i){let r;return r=t&&t instanceof ml?new bl(t,e,i):!t&&e.frames?new _l(t,e,i):t&&"function"==typeof t?new vl(t,e,i):new xl(t,e,i),r}(t,this.structureView,e),r=new dl(this.stage,i,e);return this.trajList.push(r),this.signals.trajectoryAdded.dispatch(r),r}removeTrajectory(t){const e=this.trajList.indexOf(t);-1!==e&&this.trajList.splice(e,1),t.dispose(),this.signals.trajectoryRemoved.dispatch(t)}dispose(){this.trajList.slice().forEach((t=>t.dispose())),this.trajList.length=0,this.structure.dispose(),this.measureRepresentations.dispose(),super.dispose()}autoView(t,e){"number"==typeof t&&(e=t,t=""),this.stage.animationControls.zoomMove(this.getCenter(t),this.getZoom(t),rt(e,0))}getBoxUntransformed(t){let e;return e=t?this.structureView.getBoundingBox(new me(t)):this.structureView.boundingBox,e}getCenterUntransformed(t){return t&&"string"==typeof t?this.structure.atomCenter(new me(t)):this.structure.center}superpose(t,e,i,r){return Il(this.structureView,t.structureView,e,i,r),this.updateRepresentations({position:!0}),this}getMaxRepresentationRadius(t){let e=0;const i=this.structure.getAtomProxy(t);return this.eachRepresentation((t=>{if(t.getVisibility()){const r=t.repr;e=Math.max(r.getAtomRadius(i),e)}})),e}measurePick(t){const e=this.pickBuffer.count;if(this.lastPick===t.index&&e>=1){if(e>1){const t=this.pickBuffer.data,i=this.pickBuffer.data.sort();this.pickDict.has(i)?this.pickDict.del(i):this.pickDict.add(i,t),2===e?this.distanceRepresentation.setParameters({atomPair:this.pickDict.values.filter((t=>2===t.length))}):3===e?this.angleRepresentation.setParameters({atomTriple:this.pickDict.values.filter((t=>3===t.length))}):4===e&&this.dihedralRepresentation.setParameters({atomQuad:this.pickDict.values.filter((t=>4===t.length))})}this.pickBuffer.clear(),this.lastPick=void 0}else this.pickBuffer.has(t.index)||this.pickBuffer.push(t.index),this.lastPick=t.index;this.measureUpdate()}measureClear(){this.pickBuffer.clear(),this.lastPick=void 0,this.spacefillRepresentation.setSelection("none")}measureBuild(){const t=this.measureData();this.distanceRepresentation.setParameters({atomPair:t.distance}),this.angleRepresentation.setParameters({atomTriple:t.angle}),this.dihedralRepresentation.setParameters({atomQuad:t.dihedral})}measureUpdate(){const t=this.pickBuffer.data,e={};t.forEach((t=>{const i=Math.max(.1,this.getMaxRepresentationRadius(t));e[t]=i*(2.3-Et(.1,2,i))})),this.spacefillRepresentation.setSelection(t.length?"@"+t.join(","):"none"),t.length&&this.spacefillRepresentation.setParameters({radiusData:e})}measureData(){const t=this.pickDict.values;return{distance:t.filter((t=>2===t.length)),angle:t.filter((t=>3===t.length)),dihedral:t.filter((t=>4===t.length))}}removeAllMeasurements(t){const e=this.pickDict,i=e.values,r=function(t){i.filter((e=>e.length===t)).forEach((t=>e.del(t.slice().sort())))};(!t||1&t)&&r(2),(!t||2&t)&&r(3),(!t||4&t)&&r(4),this.measureBuild()}removeMeasurement(t){this.pickDict.del(t.slice().sort()),this.measureBuild()}addMeasurement(t){if(t.length<2||t.length>4)return;const e=t.slice().sort();this.pickDict.has(e)||this.pickDict.add(e,t),this.measureBuild()}}Ve.add("structure",Ml),Ve.add("structureview",Ml);class Tl extends cl{constructor(t,e,i={}){super(t,e,Object.assign({name:e.name},i)),this.surface=e}get type(){return"surface"}addRepresentation(t,e={}){return this._addRepresentation(t,this.surface,e)}getBoxUntransformed(){return this.surface.boundingBox}getCenterUntransformed(){return this.surface.center}dispose(){this.surface.dispose(),super.dispose()}}Ve.add("surface",Tl);class Dl extends cl{constructor(t,e,i={}){super(t,e,Object.assign({name:e.name},i)),this.volume=e}get type(){return"volume"}addRepresentation(t,e={}){return this._addRepresentation(t,this.volume,e)}getBoxUntransformed(){return this.volume.boundingBox}getCenterUntransformed(){return this.volume.center}dispose(){this.volume.dispose(),super.dispose()}}Ve.add("volume",Dl);class Bl extends ll{addRepresentation(t,e){return this.forEach((i=>i.addRepresentation(t,e)))}autoView(t){return this.forEach((e=>e.autoView(t)))}}function Fl(t,e){return t instanceof RegExp?null!==e.name.match(t):e.name===t}const El=new e,$l={impostor:!0,quality:"medium",workerDefault:!0,sampleLevel:0,backgroundColor:"black",rotateSpeed:2,zoomSpeed:1.2,panSpeed:1,clipNear:0,clipFar:100,clipDist:10,clipMode:"scene",clipScale:"relative",fogNear:50,fogFar:100,cameraFov:40,cameraEyeSep:.3,cameraType:"perspective",lightColor:14540253,lightIntensity:1.2,ambientColor:14540253,ambientIntensity:.3,hoverTimeout:0,tooltip:!0,mousePreset:"default"};class Ol{constructor(t,e={}){this.signals={parametersChanged:new tt,fullscreenChanged:new tt,componentAdded:new tt,componentRemoved:new tt,clicked:new tt,hovered:new tt},this.tasks=new ui,this.compList=[],this.defaultFileParams={},this.logList=[],this.viewer=new Qi(t),this.viewer.renderer&&(this.tooltip=document.createElement("div"),Object.assign(this.tooltip.style,{display:"none",position:"fixed",zIndex:"1000000",pointerEvents:"none",backgroundColor:"rgba( 0, 0, 0, 0.6 )",color:"lightgrey",padding:"8px",fontFamily:"sans-serif"}),this.viewer.container.appendChild(this.tooltip),this.mouseObserver=new rr(this.viewer.renderer.domElement),this.viewerControls=new Ir(this),this.trackballControls=new pr(this),this.pickingControls=new br(this),this.animationControls=new Rr(this),this.mouseControls=new Qo(this),this.keyControls=new ea(this),this.pickingBehavior=new ia(this),this.mouseBehavior=new ra(this),this.animationBehavior=new na(this),this.keyBehavior=new oa(this),this.spinAnimation=this.animationControls.spin([0,1,0],.005),this.spinAnimation.pause(!0),this.rockAnimation=this.animationControls.rock([0,1,0],.005),this.rockAnimation.pause(!0),this.parameters=nt(e,$l),this.setParameters(this.parameters),this.viewer.animate())}setParameters(t={}){st(this.parameters,t);const e=t,i=this.parameters,r=this.viewer,n=this.trackballControls;return void 0!==e.quality&&this.setQuality(i.quality),void 0!==e.impostor&&this.setImpostor(i.impostor),void 0!==e.rotateSpeed&&(n.rotateSpeed=i.rotateSpeed),void 0!==e.zoomSpeed&&(n.zoomSpeed=i.zoomSpeed),void 0!==e.panSpeed&&(n.panSpeed=i.panSpeed),void 0!==e.mousePreset&&this.mouseControls.preset(i.mousePreset),this.mouseObserver.setParameters({hoverTimeout:i.hoverTimeout}),r.setClip(i.clipNear,i.clipFar,i.clipDist,i.clipMode,i.clipScale),r.setFog(void 0,i.fogNear,i.fogFar),r.setCamera(i.cameraType,i.cameraFov,i.cameraEyeSep),r.setSampling(i.sampleLevel),r.setBackground(i.backgroundColor),r.setLight(i.lightColor,i.lightIntensity,i.ambientColor,i.ambientIntensity),this.signals.parametersChanged.dispatch(this.getParameters()),this}log(t){console.log("STAGE LOG",t),this.logList.push(t)}getParameters(){return Object.assign({},this.parameters)}defaultFileRepresentation(t){if(t instanceof Ml){let e,i,r;t.setSelection("/0");const n=t.structure;if(n.biomolDict.BU1){const s=n.biomolDict.BU1;e=s.getAtomCount(n),i=s.getResidueCount(n),r=s.getInstanceCount(),t.setDefaultAssembly("BU1")}else e=n.getModelProxy(0).atomCount,i=n.getModelProxy(0).residueCount,r=1;let s=e;Ae&&(s*=4);const o=n.atomStore.count/n.residueStore.count<2;o&&(s*=10);let a="chainname",c="RdYlBu",l=!1;if(1===n.getChainnameCount(new me("polymer and /0"))&&(a="residueindex",c="Spectral",l=!0),De&&console.log(s,e,r,o),i/r<4)t.addRepresentation("ball+stick",{colorScheme:"element",radiusScale:2,aspectRatio:1.5,bondScale:.3,bondSpacing:.75,quality:"auto"});else if(r>5&&s>15e3||s>7e5){let e=Math.min(2,Math.max(.1,6e3/(s/r)));o&&(e=Math.min(e,.5)),t.addRepresentation("surface",{colorScheme:a,colorScale:c,colorReverse:l,sele:"polymer",surfaceType:"av",probeRadius:1.4,scaleFactor:e,useWorker:!1})}else s>25e4?t.addRepresentation("backbone",{colorScheme:a,colorScale:c,colorReverse:l,lineOnly:!0}):s>1e5?t.addRepresentation("backbone",{colorScheme:a,colorScale:c,colorReverse:l,quality:"low",disableImpostor:!0,radiusScale:2}):s>8e4?t.addRepresentation("backbone",{colorScheme:a,colorScale:c,colorReverse:l,radiusScale:2}):(t.addRepresentation("cartoon",{colorScheme:a,colorScale:c,colorReverse:l,radiusScale:.7,aspectRatio:5,quality:"auto"}),s<5e4&&t.addRepresentation("base",{colorScheme:a,colorScale:c,colorReverse:l,quality:"auto"}),t.addRepresentation("ball+stick",{sele:"ligand",colorScheme:"element",radiusScale:2,aspectRatio:1.5,bondScale:.3,bondSpacing:.75,quality:"auto"}));t.structure.frames.length&&t.addTrajectory()}else(t instanceof Tl||t instanceof Dl)&&t.addRepresentation("surface");this.tasks.onZeroOnce(this.autoView,this)}loadFile(t,e={}){const i=Object.assign({},this.defaultFileParams,e),r=ii(t).name;this.tasks.increment(),this.log(`loading file '${r}'`);const n=rt(i.ext,ii(t).ext);let s;return s=Ne.isTrajectory(n)?Promise.reject(new Error(`loadFile: ext '${n}' is a trajectory and must be loaded into a structure component`)):ni(t,i),s.then((t=>{this.log(`loaded '${r}'`);const e=this.addComponentFromObject(t,i);return i.defaultRepresentation&&this.defaultFileRepresentation(e),this.tasks.decrement(),e}),(t=>{this.tasks.decrement();const e=`error loading file: '${t}'`;throw this.log(e),e}))}loadScript(t){const e=ii(t).name;return this.log(`loading script '${e}'`),ni(t).then((t=>{this.tasks.increment(),this.log(`running script '${e}'`),t.run(this).then((()=>{this.tasks.decrement(),this.log(`finished script '${e}'`)})),this.log(`called script '${e}'`)}),(t=>{this.tasks.decrement();const i=`errored script '${e}' "${t}"`;throw this.log(i),i}))}addComponent(t){t?(this.compList.push(t),this.signals.componentAdded.dispatch(t)):ke.warn("Stage.addComponent: no component given")}addComponentFromObject(t,e={}){const i=Ve.get(t.type);if(i){const r=new i(this,t,e);return this.addComponent(r),r}ke.warn("no component for object type",t.type)}removeComponent(t){const e=this.compList.indexOf(t);-1!==e&&(this.compList.splice(e,1),t.dispose(),this.signals.componentRemoved.dispatch(t))}removeAllComponents(){this.compList.slice().forEach((t=>this.removeComponent(t)))}handleResize(){this.viewer.handleResize()}setSize(t,e){const i=this.viewer.container;i!==document.body&&(void 0!==t&&(i.style.width=t),void 0!==e&&(i.style.height=e),this.handleResize())}toggleFullscreen(t){if(!(document.fullscreenEnabled||document.mozFullScreenEnabled||document.webkitFullscreenEnabled||document.msFullscreenEnabled))return void ke.log("fullscreen mode (currently) not possible");const e=this;function i(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement}function r(){if(!i()&&e.lastFullscreenElement){const t=e.lastFullscreenElement;t.style.width=t.dataset.normalWidth||"",t.style.height=t.dataset.normalHeight||"",document.removeEventListener("fullscreenchange",r),document.removeEventListener("mozfullscreenchange",r),document.removeEventListener("webkitfullscreenchange",r),document.removeEventListener("MSFullscreenChange",r),e.handleResize(),e.signals.fullscreenChanged.dispatch(!1)}}t=t||this.viewer.container,this.lastFullscreenElement=t,i()?document.exitFullscreen?document.exitFullscreen():document.msExitFullscreen?document.msExitFullscreen():document.mozCancelFullScreen?document.mozCancelFullScreen():document.webkitExitFullscreen&&document.webkitExitFullscreen():(t.dataset.normalWidth=t.style.width||"",t.dataset.normalHeight=t.style.height||"",t.style.width=window.screen.width+"px",t.style.height=window.screen.height+"px",t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.mozRequestFullScreen?t.mozRequestFullScreen():t.webkitRequestFullscreen&&t.webkitRequestFullscreen(),document.addEventListener("fullscreenchange",r),document.addEventListener("mozfullscreenchange",r),document.addEventListener("webkitfullscreenchange",r),document.addEventListener("MSFullscreenChange",r),this.handleResize(),this.signals.fullscreenChanged.dispatch(!0),setTimeout((function(){e.handleResize()}),100))}setSpin(t){t?(this.spinAnimation.resume(!0),this.rockAnimation.pause(!0)):this.spinAnimation.pause(!0)}setRock(t){t?(this.rockAnimation.resume(!0),this.spinAnimation.pause(!0)):this.rockAnimation.pause(!0)}toggleSpin(){this.setSpin(this.spinAnimation.paused)}toggleRock(){this.setRock(this.rockAnimation.paused)}getFocus(){const t=this.parameters;if("scene"!==t.clipMode)return 0;let e=t.clipNear;return"absolute"===t.clipScale&&(e=this.viewer.absoluteToRelative(e)),2*e}setFocus(t){if("scene"!==this.parameters.clipMode)return;let e,i,r,n;"relative"===this.parameters.clipScale?(e=Dt(t/2,0,49.9),i=100-e,r=50,n=function(t){return Dt(t,0,100)}(2*i-50)):(e=this.viewer.relativeToAbsolute(t/2),i=e,r=0,n=2*i),this.setParameters({clipNear:e,clipFar:i,fogNear:r,fogFar:n})}getZoomForBox(t){const e=t.getSize(El),i=Math.max(e.x,e.y,e.z),r=Math.min(e.x,e.y,e.z);let n=i+Math.sqrt(r);const s=It(this.viewer.perspectiveCamera.fov),o=this.viewer.width,a=this.viewer.height,c=a{this.tasks.onZeroOnce((()=>{this.tasks.increment(),this.viewer.makeImage(t).then((t=>{this.tasks.decrement(),e(t)})).catch((t=>{this.tasks.decrement(),i(t)}))}))}))}setImpostor(t){this.parameters.impostor=t;const e=["spacefill","ball+stick","licorice","hyperball","backbone","rocket","helixorient","contact","distance","dot"];this.eachRepresentation((function(i){if(!e.includes(i.getType()))return;const r=i.getParameters();r.disableImpostor=!t,i.build(r)}))}setQuality(t){this.parameters.quality=t;const e=["tube","cartoon","ribbon","trace","rope"],i=["spacefill","ball+stick","licorice","hyperball","backbone","rocket","helixorient","contact","distance","dot"];this.eachRepresentation((function(r){const n=r.getParameters();if(!e.includes(r.getType())){if(!i.includes(r.getType()))return;if(!n.disableImpostor)return void(r.repr.quality=t)}n.quality=t,r.build(n)}))}eachComponent(t,e){this.compList.slice().forEach((i=>{void 0!==e&&e!==i.type||t(i)}))}eachRepresentation(t,e){this.eachComponent((i=>{i.reprList.slice().forEach((r=>{void 0!==e&&e!==r.getType()||t(r,i)}))}))}getComponentsByName(t){const e=[];return this.eachComponent((i=>{(void 0===t||Fl(t,i))&&e.push(i)})),new Bl(e)}getComponentsByObject(t){const e=[];return this.eachComponent((i=>{i.object===t&&e.push(i)})),new Bl(e)}getRepresentationsByName(t){const e=[];return this.eachRepresentation(((i,r)=>{(void 0===t||Fl(t,i))&&e.push(i)})),new hl(e)}measureClear(){this.eachComponent((t=>t.measureClear()),"structure")}measureUpdate(){this.eachComponent((t=>t.measureUpdate()),"structure")}dispose(){this.tasks.dispose(),this.viewer.dispose(),this.mouseObserver.dispose()}}class Rl extends cl{constructor(t,e,i={}){super(t,e,Object.assign({name:e.name},i)),this.shape=e}get type(){return"shape"}addRepresentation(t,e={}){return this._addRepresentation(t,this.shape,e)}getBoxUntransformed(){return this.shape.boundingBox}getCenterUntransformed(){return this.shape.center}dispose(){this.shape.dispose(),super.dispose()}}function Ll(t,e,i,r){var n,s=arguments.length,o=s<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(t,e,i,r);else for(var a=t.length-1;a>=0;a--)(n=t[a])&&(o=(s<3?n(o):s>3?n(e,i,o):n(e,i))||o);return s>3&&o&&Object.defineProperty(e,i,o),o}function Nl(t,e,i,r){return new(i||(i=Promise))((function(n,s){function o(t){try{c(r.next(t))}catch(t){s(t)}}function a(t){try{c(r.throw(t))}catch(t){s(t)}}function c(t){t.done?n(t.value):function(t){return t instanceof i?t:new i((function(e){e(t)}))}(t.value).then(o,a)}c((r=r.apply(t,e||[])).next())}))}Ve.add("shape",Rl),"function"==typeof SuppressedError&&SuppressedError;class zl extends Nt{constructor(t){super(t),t.scale||(this.parameters.scale="rainbow",this.parameters.reverse=rt(t.reverse,!0)),this.scalePerModel={},t.structure.eachModel((t=>{this.parameters.domain=[t.atomOffset,t.atomEnd],this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){return this.scalePerModel[t.modelIndex](t.index)}}Ll([Lt],zl.prototype,"atomColor",null),Oe.add("atomindex",zl);class Ul extends Nt{constructor(t){if(super(t),t.scale||(this.parameters.scale="OrRd"),!t.domain){let e,i=1/0,r=-1/0;t.sele&&(e=new me(t.sele)),t.structure.eachAtom((function(t){const e=t.bfactor;i=Math.min(i,e),r=Math.max(r,e)}),e),this.parameters.domain=[i,r]}this.bfactorScale=this.getScale()}atomColor(t){return this.bfactorScale(t.bfactor)}}Ll([Lt],Ul.prototype,"atomColor",null),Oe.add("bfactor",Ul);class Vl extends Nt{constructor(t){super(t),this.chainidDictPerModel={},this.scalePerModel={},t.scale||(this.parameters.scale="Spectral"),t.structure.eachModel((t=>{let e=0;const i={};t.eachChain((function(t){void 0===i[t.chainid]&&(i[t.chainid]=e,e+=1)})),this.parameters.domain=[0,e-1],this.chainidDictPerModel[t.index]=i,this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){const e=this.chainidDictPerModel[t.modelIndex];return this.scalePerModel[t.modelIndex](e[t.chainid])}}Ll([Lt],Vl.prototype,"atomColor",null),Oe.add("chainid",Vl);class jl extends Nt{constructor(t){super(t),this.scalePerModel={},t.scale||(this.parameters.scale="Spectral"),t.structure.eachModel((t=>{this.parameters.domain=[t.chainOffset,t.chainEnd],this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){return this.scalePerModel[t.modelIndex](t.chainIndex)}}Ll([Lt],jl.prototype,"atomColor",null),Oe.add("chainindex",jl);class Gl extends Nt{constructor(t){super(t),this.chainnameDictPerModel={},this.scalePerModel={},t.scale||(this.parameters.scale="Spectral"),t.structure.eachModel((t=>{let e=0;const i={};t.eachChain((function(t){void 0===i[t.chainname]&&(i[t.chainname]=e,e+=1)})),this.parameters.domain=[0,e-1],this.chainnameDictPerModel[t.index]=i,this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){const e=this.chainnameDictPerModel[t.modelIndex];return this.scalePerModel[t.modelIndex](e[t.chainname])}}Ll([Lt],Gl.prototype,"atomColor",null),Oe.add("chainname",Gl);class Hl extends Nt{constructor(t){super(t),this.rsrzDict={},this.rsccDict={},t.scale||(this.parameters.scale="RdYlBu"),this.rsrzScale=this.getScale({domain:[2,0]}),this.rsccScale=this.getScale({domain:[.678,1]});const e=t.structure.validation;e&&(this.rsrzDict=e.rsrzDict,this.rsccDict=e.rsccDict)}atomColor(t){let e=t.resno+"";t.inscode&&(e+="^"+t.inscode),t.chainname&&(e+=":"+t.chainname),e+="/"+t.modelIndex;const i=this.rsrzDict[e];if(void 0!==i)return this.rsrzScale(i);const r=this.rsccDict[e];return void 0!==r?this.rsccScale(r):9474192}}Ll([Lt],Hl.prototype,"atomColor",null),Oe.add("densityfit",Hl);const ql={ARG:{CD:.1,CZ:.5,NE:-.1},ASN:{CG:.55,OD1:-.55},ASP:{CB:-.16,CG:.36,OD1:-.6,OD2:-.6},CYS:{CB:.19,SG:-.19},GLN:{CD:.55,OE1:-.55},GLU:{CD:.36,CG:-.16,OE1:-.6,OE2:-.6},HIS:{CB:.1,CD2:.2,CE1:.45,CG:.15,ND1:.05,NE2:.05},LYS:{CE:.25,NZ:.75},MET:{CE:.06,CG:.06,SD:-.12},PTR:{C:.55,CA:.1,CZ:.25,N:-.35,O:-.55,O1P:-.85,O2P:-.85,O3P:-.85,OG1:-1.1,P:1.4},SEP:{C:.55,CA:.1,CB:.25,N:-.35,O:-.55,O1P:-.85,O2P:-.85,O3P:-.85,OG1:-1.1,P:1.4},SER:{CB:.25,OG:-.25},THR:{CB:.25,OG1:-.25},TPO:{C:.55,CA:.1,CB:.25,N:-.35,O:-.55,OG1:-1.1,O1P:-.85,O2P:-.85,O3P:-.85,P:1.4},TRP:{CD1:.06,CD2:.1,CE2:-.04,CE3:-.03,CG:-.03,NE1:-.06},TYR:{CZ:.25,OH:-.25},backbone:{C:.55,O:-.55,N:-.35,CA:.1}};class Wl extends Nt{constructor(t){super(t),this.delta=new e,this.hCharges=[],t.scale||(this.parameters.scale="rwb"),t.domain||(this.parameters.domain=[-50,50]),this.scale=this.getScale(),this.charges=new Float32Array(t.structure.atomCount);const i=[];t.structure.eachAtom((t=>{var r;if(this.charges[t.index]=(null!==(r=t).partialCharge?r.partialCharge:r.isProtein()&&(ql[r.resname]&&ql[r.resname][r.atomname]||ql.backbone[r.atomname])||0)*t.occupancy,"N"===t.atomname){if(t.bondCount>=3)return;if(t.bondToElementCount(1))return;const r=function(t,i=new e){let r=!1,n=!1,s=!1;return i.set(2*t.x,2*t.y,2*t.z),t.eachBondedAtom((function(t){if(!r)return"H"===t.atomname?(i.set(t.x,t.y,t.z),void(r=!0)):void(n||"CA"!==t.atomname?s||"C"!==t.atomname||(s=!0,i.sub(t)):(i.sub(t),n=!0))})),r?i:n&&s?(i.normalize(),i.multiplyScalar(1.04),i.add(t),i):void 0}(t);void 0!==r&&(i.push(r),this.hCharges.push(.25*t.occupancy))}}));const r=t.structure.getBoundingBox();r.expandByScalar(1.04),this.hStore=function(t){const e=t.length,i=new Float32Array(e),r=new Float32Array(e),n=new Float32Array(e);for(let e=0;e{const n=e[t];0!==n&&(r+=n/i)})),this.hHash.eachWithin(t.x,t.y,t.z,12,((t,e)=>{const n=i[t];0!==n&&(r+=n/e)})),this.scale(332*r)}}Ll([Lt],Wl.prototype,"positionColor",null),Oe.add("electrostatic",Wl);const Xl={H:16777215,HE:14286847,LI:13402367,BE:12779264,B:16758197,C:9474192,N:3166456,O:16715021,F:9494608,NE:11789301,NA:11230450,MG:9109248,AL:12560038,SI:1578e4,P:16744448,S:16777008,CL:2093087,AR:8442339,K:9388244,CA:4062976,SC:15132390,TI:12567239,V:10921643,CR:9083335,MN:10255047,FE:14706227,CO:15765664,NI:5296208,CU:13140019,ZN:8224944,GA:12750735,GE:6721423,AS:12419299,SE:16752896,BR:10889513,KR:6076625,RB:7351984,SR:65280,Y:9764863,ZR:9756896,NB:7586505,MO:5551541,TC:3907230,RU:2396047,RH:687500,PD:27013,AG:12632256,CD:16767375,IN:10909043,SN:6717568,SB:10380213,TE:13924864,I:9699476,XE:9699476,CS:5707663,BA:51456,LA:7394559,CE:16777159,PR:14286791,ND:13107143,PM:10747847,SM:9437127,EU:6422471,GD:4587463,TB:3211207,DY:2097095,HO:65436,ER:58997,TM:54354,YB:48952,LU:43812,HF:5096191,TA:5089023,W:2200790,RE:2522539,OS:2516630,IR:1528967,PT:13684960,AU:16765219,HG:12105936,TL:10900557,PB:5724513,BI:10375093,PO:11230208,AT:7688005,RN:4358806,FR:4325478,RA:32e3,AC:7384058,TH:47871,PA:41471,U:36863,NP:33023,PU:27647,AM:5528818,CM:7888099,BK:9064419,CF:10565332,ES:11739092,FM:11739066,MD:11734438,NO:12389767,LR:13041766,RF:13369433,DB:13697103,SG:14221381,BH:14680120,HS:15073326,MT:15400998,DS:16777215,RG:16777215,CN:16777215,UUT:16777215,FL:16777215,UUP:16777215,LV:16777215,UUH:16777215,D:16777152,T:16777120};class Yl extends Nt{constructor(t){t.value=rt(t.value,Xl.C),super(t)}atomColor(t){const e=t.element;return"C"===e?this.parameters.value:Xl[e]||16777215}}Ll([Lt],Yl.prototype,"atomColor",null),Oe.add("element",Yl);class Kl extends Nt{constructor(t){super(t),t.scale||(this.parameters.scale="Spectral"),t.domain||(this.parameters.domain=[0,t.structure.entityList.length-1]),this.entityindexScale=this.getScale()}atomColor(t){return this.entityindexScale(t.entityIndex)}}Ll([Lt],Kl.prototype,"atomColor",null),Oe.add("entityindex",Kl);class Zl extends Nt{atomColor(t){const e=t.entity;switch(e?e.entityType:void 0){case 1:return 8374655;case 2:return 16629894;case 3:return 12496596;case 4:return 3697840;default:return 16777113}}}Ll([Lt],Zl.prototype,"atomColor",null),Oe.add("entitytype",Zl);class Ql extends Nt{constructor(t){super(t),this.geoAtomDict={},this.geoDict={};const e=t.structure.validation;e&&(this.geoAtomDict=e.geoAtomDict,this.geoDict=e.geoDict)}atomColor(t){let e,i=t.resno+"";t.inscode&&(i+="^"+t.inscode),t.chainname&&(i+=":"+t.chainname),i+="/"+t.modelIndex;const r=this.geoAtomDict[i];if(void 0!==r){const i=r[t.atomname]||0;n=i,e=16843009*((n=(858993459&(n-=n>>1&1431655765))+(n>>2&858993459))+(n>>4)&252645135)>>24}else e=this.geoDict[i]||0;var n;return 0===e?2188972:1===e?16703627:2===e?16018755:e>=3?10813478:9474192}}Ll([Lt],Ql.prototype,"atomColor",null),Oe.add("geoquality",Ql);class Jl extends Nt{constructor(t){super(t),this.resHF={},t.scale||(this.parameters.scale="RdYlGn");for(const t in Jn)this.resHF[t]=Jn[t][0];if(this.defaultResidueHydrophobicity=ts[0],!t.domain){let t=1/0,e=-1/0;for(const i in this.resHF){const r=this.resHF[i];t=Math.min(t,r),e=Math.max(e,r)}this.parameters.domain=[t,0,e]}this.hfScale=this.getScale()}atomColor(t){return this.hfScale(this.resHF[t.resname]||this.defaultResidueHydrophobicity)}}Ll([Lt],Jl.prototype,"atomColor",null),Oe.add("hydrophobicity",Jl);class th extends Nt{constructor(t){super(t),t.scale||(this.parameters.scale="rainbow"),t.domain||(this.parameters.domain=[0,t.structure.modelStore.count]),this.modelindexScale=this.getScale()}atomColor(t){return this.modelindexScale(t.modelIndex)}}Ll([Lt],th.prototype,"atomColor",null),Oe.add("modelindex",th);class eh extends Nt{atomColor(t){switch(t.residueType.moleculeType){case 1:return 3697840;case 2:return 15729279;case 3:return 12496596;case 4:return 16629894;case 5:return 12540695;case 6:return 8374655;default:return 16777113}}}Ll([Lt],eh.prototype,"atomColor",null),Oe.add("moleculetype",eh);class ih extends Nt{constructor(t){super(t),t.scale||(this.parameters.scale="PuBu"),t.domain||(this.parameters.domain=[0,1]),this.occupancyScale=this.getScale()}atomColor(t){return this.occupancyScale(t.occupancy)}}Ll([Lt],ih.prototype,"atomColor",null),Oe.add("occupancy",ih);class rh extends Nt{constructor(t){super(t),t.scale||(this.parameters.scale="rwb"),t.domain||(this.parameters.domain=[-1,1]),this.partialchargeScale=this.getScale()}atomColor(t){return this.partialchargeScale(t.partialCharge||0)}}function nh(){return 16777215*Math.random()}Ll([Lt],rh.prototype,"atomColor",null),Oe.add("partialcharge",rh);class sh extends Nt{atomColor(){return nh()}volumeColor(){return nh()}positionColor(){return nh()}}Ll([Lt],sh.prototype,"atomColor",null),Ll([Lt],sh.prototype,"volumeColor",null),Ll([Lt],sh.prototype,"positionColor",null),Oe.add("random",sh);class oh extends Nt{constructor(t){super(t),this.rciDict={},t.scale||(this.parameters.scale="RdYlBu"),this.rciScale=this.getScale({domain:[.6,0]});const e=t.structure.validation;e&&(this.rciDict=e.rciDict)}atomColor(t){let e=`[${t.resname}]${t.resno}`;t.chainname&&(e+=":"+t.chainname);const i=this.rciDict[e];return void 0!==i?this.rciScale(i):9474192}}Ll([Lt],oh.prototype,"atomColor",null),Oe.add("randomcoilindex",oh);class ah extends Nt{constructor(t){super(t),this.scalePerChain={},t.scale||(this.parameters.scale="rainbow",this.parameters.reverse=rt(t.reverse,!0)),t.structure.eachChain((t=>{this.parameters.domain=[t.residueOffset,t.residueEnd],this.scalePerChain[t.index]=this.getScale()}))}atomColor(t){return this.scalePerChain[t.chainIndex](t.residueIndex)}}Ll([Lt],ah.prototype,"atomColor",null),Oe.add("residueindex",ah);const ch={ALA:9240460,ARG:124,ASN:16743536,ASP:10485826,CYS:16777072,GLN:16731212,GLU:6684672,GLY:16777215,HIS:7368959,ILE:19456,LEU:4546117,LYS:4671416,MET:12099650,PHE:5459026,PRO:5395026,SER:16740418,THR:12078080,TRP:5195264,TYR:9203788,VAL:16747775,ASX:16711935,GLX:16711935,ASH:16711935,GLH:16711935,A:14423100,G:3329330,I:10145074,X:8190976,C:16766720,T:4286945,U:4251856,D:35723,DA:14423100,DG:3329330,DI:10145074,DX:8190976,DC:16766720,DT:4286945,DU:4251856,DD:35723};class lh extends Nt{atomColor(t){return ch[t.resname]||16711935}}Ll([Lt],lh.prototype,"atomColor",null),Oe.add("resname",lh);const hh=16711808,uh=10485888,dh=6291584,mh=16762880,fh=6324479,ph=16777215,gh=11403518,yh=16580962,bh=10921722;class _h extends Nt{constructor(t){super(t),this.residueProxy=t.structure.getResidueProxy()}atomColor(t){const e=t.sstruc,i=this.residueProxy;return"h"===e?hh:"g"===e?uh:"i"===e?dh:"e"===e||"b"===e?mh:"t"===e?fh:(i.index=t.residueIndex,i.isDna()?gh:i.isRna()?yh:i.isSaccharide()?bh:i.isProtein()||"s"===e||"l"===e?ph:8421504)}}Ll([Lt],_h.prototype,"atomColor",null),Oe.add("sstruc",_h);class xh extends Nt{constructor(t){var e,i;super(t),t.scale||(this.parameters.scale="rwb"),this.atomData=null===(e=this.parameters.data)||void 0===e?void 0:e.atomData,this.bondData=null===(i=this.parameters.data)||void 0===i?void 0:i.bondData,this.scale=this.getScale(this.parameters)}atomColor(t){var e;const i=null===(e=this.atomData)||void 0===e?void 0:e[t.index];return void 0!==i?this.scale(i):this.parameters.value}bondColor(t,e){var i;const r=null===(i=this.bondData)||void 0===i?void 0:i[t.index];return void 0!==r?this.scale(r):this.atomProxy?(this.atomProxy.index=e?t.atomIndex1:t.atomIndex2,this.atomColor(this.atomProxy)):this.parameters.value}}Ll([Lt],xh.prototype,"atomColor",null),Ll([Lt],xh.prototype,"bondColor",null),Oe.add("structuredata",xh);class vh extends Nt{atomColor(){return this.parameters.value}bondColor(){return this.parameters.value}valueColor(){return this.parameters.value}volumeColor(){return this.parameters.value}}Ll([Lt],vh.prototype,"atomColor",null),Ll([Lt],vh.prototype,"bondColor",null),Ll([Lt],vh.prototype,"valueColor",null),Ll([Lt],vh.prototype,"volumeColor",null),Oe.add("uniform",vh);class wh extends Nt{constructor(t){super(t),this.valueScale=this.getScale()}volumeColor(t){return this.valueScale(this.parameters.volume.data[t])}}Ll([Lt],wh.prototype,"volumeColor",null),Oe.add("value",wh);class Ah extends Nt{constructor(t){super(t),this.vec=new e,this.valueScale=this.getScale()}positionColor(t){const e=this.parameters.volume;if(!e||!e.inverseMatrix)return this.parameters.value;const i=this.vec,r=e.data,n=e.nx,s=e.ny,o=n*s;i.copy(t),i.applyMatrix4(e.inverseMatrix);const a=Math.floor(i.x),c=Math.floor(i.y),l=Math.floor(i.z),h=(l*s+c)*n+a,u=h+1,d=h+n,m=h+o,f=d+1,p=m+1,g=d+o,y=g+1,b=r[h],_=r[u],x=r[d],v=r[m],w=r[f],A=r[p],S=r[g],C=r[y],P=i.x-a,I=i.y-c,k=i.z-l,M=Bt(b,_,P),T=Bt(v,A,P),D=Bt(x,w,P),B=Bt(S,C,P),F=Bt(M,D,I),E=Bt(T,B,I),$=Bt(F,E,k);return this.valueScale($)}}Ll([Lt],Ah.prototype,"positionColor",null),Oe.add("volume",Ah);class Sh extends Nr{constructor(t,e,i){const r=i||{};if(super(t,e,r),this.type="structure",this.parameters=Object.assign({radiusType:{type:"select",options:ma.types},radiusData:{type:"hidden"},radiusSize:{type:"number",precision:3,max:10,min:.001},radiusScale:{type:"number",precision:3,max:10,min:.001},assembly:null,defaultAssembly:{type:"hidden"}},this.parameters),this.selection=new me(r.sele),this.dataList=[],this.structure=t,this.structureView=this.structure.getView(this.selection),t.biomolDict){const e={default:"default","":t.unitcell?"AU":"FULL"};Object.keys(t.biomolDict).forEach((function(t){e[t]=t})),this.parameters.assembly={type:"select",options:e,rebuild:!0}}else this.parameters.assembly=null}get defaultScale(){return{vdw:1,covalent:1,bfactor:.01,sstruc:1}}init(t){const e=t||{};e.colorScheme=rt(e.colorScheme,"element"),this.setRadius(e.radius,e),this.radiusType=rt(e.radiusType,"vdw"),this.radiusData=rt(e.radiusData,{}),this.radiusSize=rt(e.radiusSize,1),this.radiusScale=rt(e.radiusScale,1),this.assembly=rt(e.assembly,"default"),this.defaultAssembly=rt(e.defaultAssembly,""),"auto"===e.quality&&(e.quality=this.getQuality()),super.init(e),this.selection.signals.stringChanged.add((()=>{this.build()})),this.build()}setRadius(t,e){const i=Object.keys(da);return"string"==typeof t&&i.includes(t.toLowerCase())?e.radiusType=t:void 0!==t&&(e.radiusType="size",e.radiusSize=t),this}getAssembly(){const t="default"===this.assembly?this.defaultAssembly:this.assembly;return this.structure.biomolDict[t]}getQuality(){let t;const e=this.structureView,i=this.getAssembly();t=i?i.getAtomCount(e):e.atomCount,Ae&&(t*=4);return e.atomStore.count/e.residueStore.count<2&&(t*=10),t<15e3?"high":t<8e4?"medium":"low"}create(){if(0===this.structureView.atomCount)return;if(!this.structureView.hasCoords())return void(this.needsBuild=!0);this.needsBuild=!1;const t=this.getAssembly();if(t)t.partList.forEach(((t,e)=>{const i=t.getView(this.structureView);if(0===i.atomCount)return;const r=this.createData(i,e);r&&(r.sview=i,r.instanceList=t.getInstanceList(),this.dataList.push(r))}));else{const t=this.createData(this.structureView,0);t&&(t.sview=this.structureView,this.dataList.push(t))}}update(t){!this.lazy||this.visible?this.needsBuild?this.build():this.dataList.forEach((e=>{e.bufferList.length>0&&this.updateData(t,e)}),this):Object.assign(this.lazyProps.what,t)}updateData(t,e){this.build()}getColorParams(){return Object.assign(Object.assign({},super.getColorParams()),{structure:this.structure})}getRadiusParams(t){return{type:this.radiusType,scale:this.radiusScale,size:this.radiusSize,data:this.radiusData}}getAtomParams(t,e){return Object.assign({what:t,colorParams:this.getColorParams(),radiusParams:this.getRadiusParams()},e)}getBondParams(t,e){return Object.assign({what:t,colorParams:this.getColorParams(),radiusParams:this.getRadiusParams()},e)}getAtomRadius(t){if(this.structureView.atomSet.isSet(t.index)){return new ma(this.getRadiusParams()).atomRadius(t)}return 0}setSelection(t,e){return this.selection.setString(t,e),this}setParameters(t,e={},i=!1){const r=t||{};return this.setRadius(r.radius,r),void 0===r.radiusType&&void 0===r.radiusData&&void 0===r.radiusSize&&void 0===r.radiusScale||(e.radius=!0,Pe&&!this.disableImpostor||(i=!0)),void 0!==r.defaultAssembly&&r.defaultAssembly!==this.defaultAssembly&&("default"===this.assembly&&void 0===r.assembly||"default"===r.assembly)&&(i=!0),super.setParameters(r,e,i),this}getParameters(){return Object.assign(super.getParameters(),{sele:this.selection?this.selection.string:void 0,defaultAssembly:this.defaultAssembly})}attach(t){const e=this.viewer,i=this.bufferList;this.dataList.forEach((function(t){t.bufferList.forEach((function(r){i.push(r),e.add(r,t.instanceList)}))})),this.setVisibility(this.visible),t()}clear(){this.dataList.length=0,super.clear()}dispose(){this.structureView.dispose(),super.dispose()}}class Ch extends Sh{constructor(t,e,i){super(t,e,i),this.n=0,this.parameters=Object.assign({labelVisible:{type:"boolean"},labelSize:{type:"number",precision:3,max:10,min:.001},labelColor:{type:"color"},labelFontFamily:{type:"select",options:{"sans-serif":"sans-serif",monospace:"monospace",serif:"serif"},buffer:"fontFamily"},labelFontStyle:{type:"select",options:{normal:"normal",italic:"italic"},buffer:"fontStyle"},labelFontWeight:{type:"select",options:{normal:"normal",bold:"bold"},buffer:"fontWeight"},labelsdf:{type:"boolean",buffer:"sdf"},labelXOffset:{type:"number",precision:1,max:20,min:-20,buffer:"xOffset"},labelYOffset:{type:"number",precision:1,max:20,min:-20,buffer:"yOffset"},labelZOffset:{type:"number",precision:1,max:20,min:-20,buffer:"zOffset"},labelAttachment:{type:"select",options:{"bottom-left":"bottom-left","bottom-center":"bottom-center","bottom-right":"bottom-right","middle-left":"middle-left","middle-center":"middle-center","middle-right":"middle-right","top-left":"top-left","top-center":"top-center","top-right":"top-right"},rebuild:!0},labelBorder:{type:"boolean",buffer:"showBorder"},labelBorderColor:{type:"color",buffer:"borderColor"},labelBorderWidth:{type:"number",precision:2,max:.3,min:0,buffer:"borderWidth"},labelBackground:{type:"boolean",rebuild:!0},labelBackgroundColor:{type:"color",buffer:"backgroundColor"},labelBackgroundMargin:{type:"number",precision:2,max:2,min:0,rebuild:!0},labelBackgroundOpacity:{type:"range",step:.01,max:1,min:0,buffer:"backgroundOpacity"},labelFixedSize:{type:"boolean",buffer:"fixedSize"},lineOpacity:{type:"range",min:0,max:1,step:.01},linewidth:{type:"integer",max:50,min:1,buffer:!0}},this.parameters,{flatShaded:null})}init(t){const e=t||{};this.labelVisible=rt(e.labelVisible,!0),this.labelSize=rt(e.labelSize,2),this.labelColor=rt(e.labelColor,16777215),this.labelFontFamily=rt(e.labelFontFamily,"sans-serif"),this.labelFontStyle=rt(e.labelFontstyle,"normal"),this.labelFontWeight=rt(e.labelFontWeight,"bold"),this.labelsdf=rt(e.labelsdf,"Chrome"===ve),this.labelXOffset=rt(e.labelXOffset,0),this.labelYOffset=rt(e.labelYOffset,0),this.labelZOffset=rt(e.labelZOffset,.5),this.labelAttachment=rt(e.labelAttachment,"bottom-left"),this.labelBorder=rt(e.labelBorder,!1),this.labelBorderColor=rt(e.labelBorderColor,"lightgrey"),this.labelBorderWidth=rt(e.labelBorderWidth,.15),this.labelBackground=rt(e.labelBackground,!1),this.labelBackgroundColor=rt(e.labelBackgroundColor,"lightgrey"),this.labelBackgroundMargin=rt(e.labelBackgroundMargin,.5),this.labelBackgroundOpacity=rt(e.labelBackgroundOpacity,1),this.labelFixedSize=rt(e.labelFixedSize,!1),this.lineOpacity=rt(e.lineOpacity,1),this.linewidth=rt(e.linewidth,2),super.init(e)}update(t){t.position?this.build():super.update(t)}updateData(t,e){const i={};if(t&&!t.labelSize||Object.assign(i,{size:Ai(this.n,this.labelSize)}),!t||t.labelColor){const t=new n(this.labelColor);Object.assign(i,{color:Si(this.n,t.r,t.g,t.b)})}this.textBuffer.setAttributes(i)}setParameters(t,e={},i=!1){return t&&t.labelSize&&(e.labelSize=!0),t&&(t.labelColor||0===t.labelColor)&&(e.labelColor=!0,i=!0),super.setParameters(t,e,i),t&&void 0!==t.opacity&&this.textBuffer.setParameters({opacity:1}),t&&void 0!==t.labelVisible&&this.setVisibility(this.visible),this}setVisibility(t,e){return super.setVisibility(t,!0),this.textBuffer&&this.textBuffer.setVisibility(this.labelVisible&&this.visible),e||this.viewer.requestRender(),this}getLabelBufferParams(t={}){return super.getBufferParams(Object.assign({fontFamily:this.labelFontFamily,fontStyle:this.labelFontStyle,fontWeight:this.labelFontWeight,sdf:this.labelsdf,xOffset:this.labelXOffset,yOffset:this.labelYOffset,zOffset:this.labelZOffset,attachment:this.labelAttachment,showBorder:this.labelBorder,borderColor:this.labelBorderColor,borderWidth:this.labelBorderWidth,showBackground:this.labelBackground,backgroundColor:this.labelBackgroundColor,backgroundMargin:this.labelBackgroundMargin,backgroundOpacity:this.labelBackgroundOpacity,fixedSize:this.labelFixedSize,disablePicking:!0,visible:this.labelVisible},t,{opacity:1}))}getAtomRadius(){return 0}}function Ph(t,e){const i=t.getAtomProxy(),r=new me,n=e.length;if(0===n)return new Float32Array(0);const s=e[0].length,o=t.getAtomSet(),a=new Float32Array(n*s*3);let c=0;return e.forEach((function(e){let n=!1;for(let l=0;l 1.0 ){\ngl_FragColor = vec4( backgroundColor, backgroundOpacity );\n}else{\nfloat sdf = texture2D( fontTexture, texCoord ).a;\nif( showBorder ) sdf += borderWidth;\nfloat a = smoothstep(padding - gamma, padding + gamma, sdf);\nif( a < 0.2 ) discard;\na *= opacity;\nvec3 outgoingLight = vColor;\nif( showBorder && sdf < ( padding + borderWidth ) ){\noutgoingLight = borderColor;\n}\ngl_FragColor = vec4( outgoingLight, a );\n}\n#if defined( PICKING )\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Th={};const Dh={font:"sans-serif",size:36,style:"normal",variant:"normal",weight:"normal",outline:3,width:1024,height:1024};class Bh{constructor(t={}){this.gamma=1,this.mapped={},this.scratchW=0,this.scratchH=0,this.currentX=0,this.currentY=0,this.cutoff=.25,this.parameters=nt(t,Dh);const e=this.parameters;this.radius=e.size/8,this.padding=e.size/3;const i=this.lineHeight=e.size+2*e.outline+Math.round(e.size/4),r=this.maxWidth=e.width/4,n=this.canvas=document.createElement("canvas");n.width=r,n.height=i;const s=this.context=this.canvas.getContext("2d",{willReadFrequently:!0});s.font=`${e.style} ${e.variant} ${e.weight} ${e.size}px ${e.font}`,s.fillStyle="black",s.textAlign="left",s.textBaseline="bottom",s.lineJoin="round",this.gridOuter=new Float64Array(i*r),this.gridInner=new Float64Array(i*r),this.f=new Float64Array(Math.max(i,r)),this.d=new Float64Array(Math.max(i,r)),this.z=new Float64Array(Math.max(i,r)+1),this.v=new Int16Array(Math.max(i,r)),this.data=new Uint8Array(e.width*e.height*4),this.canvas2=document.createElement("canvas"),this.canvas2.width=e.width,this.canvas2.height=e.height,this.context2=this.canvas2.getContext("2d"),this.placeholder=this.map(String.fromCharCode(65533));for(let t=32;t<=126;++t)this.map(String.fromCharCode(t));this.map(String.fromCharCode(176)),this.map(String.fromCharCode(8491)),this.texture=new H(this.canvas2),this.texture.flipY=!1,this.texture.needsUpdate=!0}map(t){const e=this.parameters;return void 0===this.mapped[t]&&(this.draw(t),this.currentX+this.scratchW>e.width&&(this.currentX=0,this.currentY+=this.scratchH),this.currentY+this.scratchH>e.height&&console.warn("canvas to small"),this.mapped[t]={x:this.currentX,y:this.currentY,w:this.scratchW,h:this.scratchH},this.context2.drawImage(this.canvas,0,0,this.scratchW,this.scratchH,this.currentX,this.currentY,this.scratchW,this.scratchH),this.currentX+=this.scratchW),this.mapped[t]}get(t){return this.mapped[t]||this.placeholder}draw(t){const e=this.parameters,i=this.lineHeight,r=e.outline,n=this.context,s=this.maxWidth,o=r,a=i-e.outline,c=n.measureText(t),l=Math.min(s,Math.ceil(c.width+2*o+1)),h=l*i;n.clearRect(0,0,l,i),n.fillText(t,o,a);const u=n.getImageData(0,0,l,i),d=u.data;for(let t=0;t= 0.0 ) {\ntrimSegment( start, end );\n} else if ( end.z < 0.0 && start.z >= 0.0 ) {\ntrimSegment( end, start );\n}\n}\nvec4 clipStart = projectionMatrix * start;\nvec4 clipEnd = projectionMatrix * end;\nvec2 ndcStart = clipStart.xy / clipStart.w;\nvec2 ndcEnd = clipEnd.xy / clipEnd.w;\nvec2 dir = ndcEnd - ndcStart;\ndir.x *= aspect;\ndir = normalize( dir );\nvec2 offset = vec2( dir.y, - dir.x );\ndir.x /= aspect;\noffset.x /= aspect;\nif ( mapping.x < 0.0 ) offset *= - 1.0;\noffset *= linewidth;\noffset /= resolution.y;\nvec4 clip = ( mapping.y < 0.5 ) ? clipStart : clipEnd;\noffset *= clip.w;\nclip.xy += offset;\ngl_Position = clip;\n#ifndef PICKING\nvViewPosition = ( projectionMatrixInverse * clip ).xyz;\n#endif\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n#include nearclip_vertex\n}"),ze.add("shader/WideLine.frag","uniform vec3 diffuse;\nuniform float opacity;\nuniform float clipNear;\nuniform float clipRadius;\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#ifdef PICKING\nuniform float objectId;\nvarying vec3 vPickingColor;\n#else\n#include common\n#include fog_pars_fragment\nvarying vec3 vViewPosition;\nvarying vec3 vColor;\nvarying vec3 vColor2;\nvarying float flag;\n#endif\nvoid main() {\n#include nearclip_fragment\n#include radiusclip_fragment\n#if defined( PICKING )\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 outgoingLight = vec3( 0.0 );\nvec4 diffuseColor = vec4( diffuse, 1.0 );\nif ( flag < 0.0 ) {\ndiffuseColor.rgb *= vColor;\n} else {\ndiffuseColor.rgb *= vColor2;\n}\n#include alphatest_fragment\noutgoingLight = diffuseColor.rgb;\ngl_FragColor = vec4( outgoingLight, diffuseColor.a * opacity );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Rh=Object.assign({linewidth:2},No),Lh=Object.assign({linewidth:{uniform:!0}},zo);class Nh extends Nc{constructor(e,r={}){super(e,r),this.parameterTypes=Lh,this.vertexShader="WideLine.vert",this.fragmentShader="WideLine.frag",!e.color2&&e.color&&(e.color2=e.color),this.addUniforms({linewidth:{value:this.parameters.linewidth},resolution:{value:new t},projectionMatrixInverse:{value:new i}}),this.addAttributes({position1:{type:"v3",value:null},position2:{type:"v3",value:null},color2:{type:"c",value:null}}),this.setAttributes(e),this.makeMapping()}get defaultParameters(){return Rh}setParameters(t){super.setParameters(t)}}je.add("wideline",Nh);class zh extends Ch{constructor(t,e,i){super(t,e,i),this.type="angle",this.parameters=Object.assign({atomTriple:{type:"hidden",rebuild:!0},vectorVisible:{type:"boolean",default:!0},arcVisible:{type:"boolean",default:!0},sectorVisible:{type:"boolean",default:!0}},this.parameters),this.init(i)}init(t){const e=t||{};e.side=rt(e.side,"double"),e.opacity=rt(e.opacity,.5),this.atomTriple=rt(e.atomTriple,[]),this.arcVisible=rt(e.arcVisible,!0),this.sectorVisible=rt(e.sectorVisible,!0),this.vectorVisible=rt(e.vectorVisible,!0),super.init(e)}createData(t){if(!t.atomCount||!this.atomTriple.length)return;const e=function(t,e){return function(t){const e=[],i=t.length/9;for(let r=0;r radius2) {\ndiscard;\n}\n#ifdef CAP\nsurface_point = front_point;\n_normal = axis;\n#else\nsurface_point = ray_target + ( (-a1 - sqrt(d)) / a2 ) * ray_direction;\ndNV = dot(-axis, ray_direction);\nnear = dot(axis, end) / dNV;\nnew_point2 = ray_direction * near + ray_origin;\nif (dot(new_point2 - end, new_point2-base) < radius2) {\ndiscard;\n}\ninterior = true;\n#endif\n}\nif( end_cap_test > 0.0 )\n{\nfloat dNV;\nfloat near;\nvec3 end_point;\nif ( ortho == 1.0 ) {\nend_point = ray_target;\n} else {\ndNV = dot(axis, ray_direction);\nif (dNV < 0.0) {\ndiscard;\n}\nnear = dot(axis, end) / dNV;\nend_point = ray_direction * near + ray_origin;\n}\nif( dot(end_point - end, end_point-base) > radius2 ) {\ndiscard;\n}\n#ifdef CAP\nsurface_point = end_point;\n_normal = axis;\n#else\nsurface_point = ray_target + ( (-a1 - sqrt(d)) / a2 ) * ray_direction;\ndNV = dot(-axis, ray_direction);\nnear = dot(-axis, (base)) / dNV;\nnew_point2 = ray_direction * near + ray_origin;\nif (dot(new_point2 - base, new_point2-base) < radius2) {\ndiscard;\n}\ninterior = true;\n#endif\n}\ngl_FragDepthEXT = calcDepth( surface_point );\n#ifdef NEAR_CLIP\nif( calcClip( surface_point ) > 0.0 ){\ndist = (-a1 - sqrt(d)) / a2;\nsurface_point = ray_target + dist * ray_direction;\nif( calcClip( surface_point ) > 0.0 ) {\ndiscard;\n}\ninterior = true;\ngl_FragDepthEXT = calcDepth( surface_point );\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = max( 0.0, calcDepth( vec3( - ( clipNear - 0.5 ) ) ) + ( 0.0000001 / vRadius ) );\n}\n}else if( gl_FragDepthEXT <= 0.0 ){\ndist = (-a1 - sqrt(d)) / a2;\nsurface_point = ray_target + dist * ray_direction;\ninterior = true;\ngl_FragDepthEXT = calcDepth( surface_point );\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n}\n#else\nif( gl_FragDepthEXT <= 0.0 ){\ndist = (-a1 - sqrt(d)) / a2;\nsurface_point = ray_target + dist * ray_direction;\ninterior = true;\ngl_FragDepthEXT = calcDepth( surface_point );\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n}\n#endif\nif (gl_FragDepthEXT < 0.0) {\ndiscard;\n}\nif (gl_FragDepthEXT > 1.0) {\ndiscard;\n}\n#ifdef PICKING\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 vViewPosition = -surface_point;\nvec3 vNormal = _normal;\nvec3 vColor;\nif( distSq3( surface_point, end ) < distSq3( surface_point, base ) ){\nif( b < 0.0 ){\nvColor = vColor1;\n}else{\nvColor = vColor2;\n}\n}else{\nif( b > 0.0 ){\nvColor = vColor1;\n}else{\nvColor = vColor2;\n}\n}\nvec4 diffuseColor = vec4( diffuse, opacity );\nReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\nvec3 totalEmissiveLight = emissive;\n#include color_fragment\n#include roughnessmap_fragment\n#include metalnessmap_fragment\nvec3 normal = normalize( vNormal );\nvec3 nonPerturbedNormal = normal;\n#include lights_physical_fragment\n#include lights_fragment_begin\n#include lights_fragment_end\nvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveLight;\nif( interior ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Xh=new Float32Array([-1,1,-1,-1,-1,-1,1,1,-1,1,1,1,1,-1,-1,1,-1,1]),Yh=new Uint16Array([0,1,2,1,4,2,2,4,3,4,5,3]);class Kh extends Oc{constructor(t,e={}){super("v3",t,e)}get mapping(){return Xh}get mappingIndices(){return Yh}get mappingIndicesSize(){return 12}get mappingSize(){return 6}get mappingItemSize(){return 3}}const Zh=Object.assign({openEnded:!1},No),Qh=Object.assign({openEnded:{updateShader:!0}},zo);class Jh extends Kh{constructor(t,e={}){super(t,e),this.parameterTypes=Qh,this.isImpostor=!0,this.vertexShader="CylinderImpostor.vert",this.fragmentShader="CylinderImpostor.frag",this.addUniforms({modelViewMatrixInverse:{value:new i},ortho:{value:0}}),this.addAttributes({position1:{type:"v3",value:null},position2:{type:"v3",value:null},color2:{type:"c",value:null},radius:{type:"f",value:null}}),this.setAttributes(t),this.makeMapping()}get defaultParameters(){return Zh}getDefines(t){const e=Kh.prototype.getDefines.call(this,t);return this.parameters.openEnded||(e.CAP=1),e}}Object.assign({disableImpostor:!1},Hh,Zh);const tu=class{constructor(t,e={}){return!t.color2&&t.color&&(t.color2=t.color),!Pe||e&&e.disableImpostor?new Wh(t,e):new Jh(t,e)}};je.add("cylinder",tu);class eu extends Sh{constructor(t,e,i){super(t,e,i),this.type="axes",this.parameters=Object.assign({radiusSize:{type:"number",precision:3,max:10,min:.001},sphereDetail:!0,radialSegments:!0,disableImpostor:!0,showAxes:{type:"boolean",rebuild:!0},showBox:{type:"boolean",rebuild:!0}},this.parameters,{assembly:null}),this.init(i)}init(t){const e=t||{};e.radiusSize=rt(e.radiusSize,.5),e.colorValue=rt(e.colorValue,"lightgreen"),e.useInteriorColor=rt(e.useInteriorColor,!0),this.showAxes=rt(e.showAxes,!0),this.showBox=rt(e.showBox,!1),super.init(e)}getPrincipalAxes(){let t;const e=this.getAssembly();return e&&(t=e.partList[0].getSelection()),this.structureView.getPrincipalAxes(t)}getAxesData(t){const i=this.getPrincipalAxes(),r=new n(this.colorValue);let s=0,o=0;this.showAxes&&(s+=6,o+=3),this.showBox&&(s+=8,o+=12);const a=new Float32Array(3*s),c=Si(s,r.r,r.g,r.b),l=Ai(s,this.radiusSize),h=new Float32Array(3*o),u=new Float32Array(3*o),d=Si(o,r.r,r.g,r.b),m=Ai(o,this.radiusSize);let f=0;if(this.showAxes){const t=function(t,e){t.toArray(a,2*f),e.toArray(a,2*f+3),t.toArray(h,f),e.toArray(u,f),f+=3};t(i.begA,i.endA),t(i.begB,i.endB),t(i.begC,i.endC)}if(this.showBox){const r=new e,{d1a:n,d2a:s,d3a:o,d1b:c,d2b:l,d3b:d}=i.getProjectedScaleForAtoms(t);let m=2*f;const p=function(t,e,n){r.copy(i.center).addScaledVector(i.normVecA,t).addScaledVector(i.normVecB,e).addScaledVector(i.normVecC,n),r.toArray(a,m),m+=3};p(n,s,o),p(n,s,d),p(n,l,d),p(n,l,o),p(c,l,d),p(c,l,o),p(c,s,o),p(c,s,d);let g=f;const y=function(t,e){r.fromArray(a,2*f+3*t).toArray(h,g),r.fromArray(a,2*f+3*e).toArray(u,g),g+=3};y(0,1),y(0,3),y(0,6),y(1,2),y(1,7),y(2,3),y(2,4),y(3,5),y(4,5),y(4,7),y(5,6),y(6,7)}const p=new Ys(i);return{vertex:{position:a,color:c,radius:l,picking:p},edge:{position1:h,position2:u,color:d,color2:d,radius:m,picking:p}}}create(){const t=this.getAxesData(this.structureView);this.sphereBuffer=new Uc(t.vertex,this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!0})),this.cylinderBuffer=new tu(t.edge,this.getBufferParams({openEnded:!0,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0})),this.dataList.push({sview:this.structureView,bufferList:[this.sphereBuffer,this.cylinderBuffer]})}createData(t){}updateData(t,e){const i=this.getAxesData(e.sview),r={},n={};t&&!t.position||(Object.assign(r,{position:i.vertex.position}),Object.assign(n,{position1:i.edge.position1,position2:i.edge.position2})),t&&!t.color||(Object.assign(r,{color:i.vertex.color}),Object.assign(n,{color:i.edge.color,color2:i.edge.color})),t&&!t.radius||(Object.assign(r,{radius:i.vertex.radius}),Object.assign(n,{radius:i.edge.radius})),this.sphereBuffer.setAttributes(r),this.cylinderBuffer.setAttributes(n)}}Le.add("axes",eu);class iu extends Sh{constructor(t,e,i){super(t,e,i),this.type="ball+stick",this.parameters=Object.assign({sphereDetail:!0,radialSegments:!0,openEnded:!0,disableImpostor:!0,aspectRatio:{type:"number",precision:1,max:10,min:1},lineOnly:{type:"boolean",rebuild:!0},cylinderOnly:{type:"boolean",rebuild:!0},multipleBond:{type:"select",rebuild:!0,options:{off:"off",symmetric:"symmetric",offset:"offset"}},bondScale:{type:"number",precision:2,max:1,min:.01},bondSpacing:{type:"number",precision:2,max:2,min:.5},linewidth:{type:"integer",max:50,min:1,buffer:!0}},this.parameters),this.init(i)}init(t){var e=t||{};e.radiusType=rt(e.radiusType,"size"),e.radiusSize=rt(e.radiusSize,.15),e.useInteriorColor=rt(e.useInteriorColor,!0),this.aspectRatio=rt(e.aspectRatio,2),this.lineOnly=rt(e.lineOnly,!1),this.cylinderOnly=rt(e.cylinderOnly,!1),this.multipleBond=rt(e.multipleBond,"off"),this.bondSpacing=rt(e.bondSpacing,1),this.bondScale=rt(e.bondScale,.4),this.linewidth=rt(e.linewidth,2),super.init(e)}getAtomRadius(t){return this.aspectRatio*super.getAtomRadius(t)}getAtomParams(t,e){var i=super.getAtomParams(t,e);return i.radiusParams.scale*=this.aspectRatio,i}getAtomData(t,e,i){return t.getAtomData(this.getAtomParams(e,i))}getBondParams(t,e){return e=Object.assign({multipleBond:this.multipleBond,bondSpacing:this.bondSpacing,bondScale:this.bondScale},e),super.getBondParams(t,e)}getBondData(t,e,i){return t.getBondData(this.getBondParams(e,i))}createData(t){const e=[];if(this.lineOnly)this.lineBuffer=new Nh(this.getBondData(t,{position:!0,color:!0,picking:!0}),this.getBufferParams({linewidth:this.linewidth})),e.push(this.lineBuffer);else{const i=new tu(this.getBondData(t),this.getBufferParams({openEnded:this.openEnded,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0}));if(e.push(i),!this.cylinderOnly){const i=new Uc(this.getAtomData(t),this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!0}));e.push(i)}}return{bufferList:e}}updateData(t,e){"off"!==this.multipleBond&&t&&t.radius&&(t.position=!0);const i=this.getBondData(e.sview,t);if(this.lineOnly){const r={};t&&!t.position||Object.assign(r,{position1:i.position1,position2:i.position2}),t&&!t.color||Object.assign(r,{color:i.color,color2:i.color2}),e.bufferList[0].setAttributes(r)}else{var r={};if(t&&!t.position||Object.assign(r,{position1:i.position1,position2:i.position2}),t&&!t.color||Object.assign(r,{color:i.color,color2:i.color2}),t&&!t.radius||Object.assign(r,{radius:i.radius}),e.bufferList[0].setAttributes(r),!this.cylinderOnly){var n=this.getAtomData(e.sview,t),s={};t&&!t.position||Object.assign(s,{position:n.position}),t&&!t.color||Object.assign(s,{color:n.color}),t&&!t.radius||Object.assign(s,{radius:n.radius}),e.bufferList[1].setAttributes(s)}}}setParameters(t={}){let e=!1;const i={};return(t.aspectRatio||t.bondSpacing||t.bondScale)&&(Object.assign(i,{radius:!0}),Pe&&!this.disableImpostor||(e=!0)),super.setParameters(t,i,e),this}}Le.add("ball+stick",iu);class ru extends iu{constructor(t,e,i){super(t,e,i),this.type="backbone",this.parameters=Object.assign({},this.parameters,{multipleBond:null,bondSpacing:null}),this.init(i)}init(t){var e=t||{};e.aspectRatio=rt(e.aspectRatio,1),e.radiusSize=rt(e.radiusSize,.25),super.init(e)}getAtomRadius(t){return t.isTrace()?super.getAtomRadius(t):0}getAtomData(t,e,i){return t.getBackboneAtomData(this.getAtomParams(e,i))}getBondData(t,e,i){return t.getBackboneBondData(this.getBondParams(e,i))}}Le.add("backbone",ru);class nu extends iu{constructor(t,e,i){super(t,e,i),this.type="base",this.parameters=Object.assign({},this.parameters,{multipleBond:null,bondSpacing:null})}init(t){let e=t||{};e.aspectRatio=rt(e.aspectRatio,1),e.radiusSize=rt(e.radiusSize,.3),super.init(e)}getAtomData(t,e,i){return t.getRungAtomData(this.getAtomParams(e,i))}getBondData(t,e,i){let r=this.getBondParams(e,i);return Object.assign(r.colorParams,{rung:!0}),t.getRungBondData(r)}}Le.add("base",nu);class su{constructor(t,i){this.m=t,this.tension=i,this.dt=1/this.m,this.delta=1e-4,this.vec1=new e,this.vec2=new e,this.vDir=new e,this.vTan=new e,this.vNorm=new e,this.vBin=new e,this.m2=Math.ceil(this.m/2)}interpolateToArr(t,e,i,r,n,s,o){s[o+0]=Ft(t.x,e.x,i.x,r.x,n,this.tension),s[o+1]=Ft(t.y,e.y,i.y,r.y,n,this.tension),s[o+2]=Ft(t.z,e.z,i.z,r.z,n,this.tension)}interpolateToVec(t,e,i,r,n,s){s.x=Ft(t.x,e.x,i.x,r.x,n,this.tension),s.y=Ft(t.y,e.y,i.y,r.y,n,this.tension),s.z=Ft(t.z,e.z,i.z,r.z,n,this.tension)}interpolatePosition(t,e,i,r,n,s){for(var o=0;o1&&(l=1),this.interpolateToVec(t,e,i,r,c,this.vec1),this.interpolateToVec(t,e,i,r,l,this.vec2),this.vec2.sub(this.vec1).normalize(),this.vec2.toArray(n,h)}}vectorSubdivide(t,e,i,r,n){let s,o=e.next(),a=e.next(),c=e.next();const l=e.size,h=l-1;let u=r||0;for(let r=0;r0&&e{if(t.residueCount<4)return;i.push(t);const r=this.getSpline(t),n=this.getAspectRatio(t),s=r.getSubdividedPosition(),o=r.getSubdividedOrientation(),a=r.getSubdividedColor(this.getColorParams()),c=r.getSubdividedPicking(),l=r.getSubdividedSize(this.getRadiusParams());e.push(new hu(Object.assign({},s,o,a,c,l),this.getBufferParams({radialSegments:this.radialSegments,aspectRatio:n,capped:this.capped})))}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){De&&ke.time(this.type+" repr update"),t=t||{};for(var i=0,r=e.polymerList.length;i0;Zr(w,b,A);const n=Kr(w,x)<0;if(sn(w,x,Kr(x,_)),Zr(S,_,w),sn(w,x,Kr(x,v)),Zr(C,v,w),0===rn(S)||0===rn(C))continue;on(S,S),on(C,C);const B=s[T]=dn(S,C);a[T]=(_i*B).toFixed(1)+String.fromCharCode(176),Yr(k,S,x),on(k,k),Kr(k,C)<0&&un(k,k),Ih(w,A,S,k,B/2),tn(w,o,3*T);const F=Math.ceil(B/i),E=F+(e.extendLine?4:2),$=e.extendLine?36:0,O=new Float32Array(3*E),R=new Float32Array(3*E),L=new Float32Array(9*F),N=new Float32Array($);c[T]=O,l[T]=R,h[T]=L,u[T]=N,e.extendLine&&(r?(Zr(w,p,y),on(w,w),sn(P,w,1/Kr(S,w)),Qr(P,P,y)):(sn(P,_,1/Kr(S,_)),Qr(P,P,g)),n?(Zr(w,b,g),on(w,w),sn(I,w,1/Kr(C,w)),Qr(I,I,g)):(sn(I,v,1/Kr(C,v)),Qr(I,I,y))),Qr(M,A,S);let z=0;e.extendLine?(tn(p,O,z),tn(P,R,z),z+=3,tn(P,O,z),tn(M,R,z),z+=3,tn(P,N,0),tn(M,N,3),tn(r?y:g,N,6),tn(r?y:g,N,9),tn(M,N,12),tn(A,N,15)):(tn(A,O,z),tn(M,R,z),z+=3);const U=function(t,e){const i=9*e;tn(A,L,i),tn(M,L,i+3),tn(M,O,z),Ih(M,A,S,k,t),tn(M,L,i+6),tn(M,R,z),z+=3};let V=0;for(let t=i;t{const e=fu(i,t);Object.assign(t,e)})),e.side=rt(e.side,"double"),e.opacity=rt(e.opacity,.5),e.radiusType=rt(e.radiusType,"size"),e.radiusSize=rt(e.radiusSize,.15),super.init(e)}getHistogramBinBorderBufferParameters(){return this.getBufferParams({linewidth:this.histogramBinBorderWidth,visible:this.histogramBinBorderVisible,opacity:this.histogramBinBorderOpacity})}getBondArrowsBufferParameters(){return this.getBufferParams({linewidth:this.bondArrowWidth,visible:this.bondArrowVisible,opacity:this.bondArrowOpacity})}getOpaqueMiddleDiscBufferParameters(){return this.getBufferParams({visible:this.opaqueMiddleDiscVisible,opacity:this.opaqueMiddleDiscOpacity})}getHistogramBufferParameters(){return this.getBufferParams({visible:!0,opacity:this.histogramOpacity,side:"double"})}createData(t){if(!t.atomCount||!this.histogramsData.length)return;this.histogramsData.forEach((e=>e.atomPositions=Ph(t,[e.atomQuad])));const e=this.scaleBinToSectorArea?function(t){return Math.sqrt(t)}:function(t){return t};function i(t){const e=t.map((t=>t.length)),i=new Float32Array(Bi(e));let r=0;for(let e=0;et.startPoints))),position2:i(t.map((t=>t.endPoints))),color:i(t.map((t=>t.startColors))),color2:i(t.map((t=>t.endColors)))},e)}function n(t,e){return new Vo({position:i(t.map((t=>t.triangles))),color:i(t.map((t=>t.triangleColors)))},e)}this.histogramsData.forEach((t=>t.histogram360Scaled=t.histogram360.map(e)));const s=[];for(let t=0;t=3&&(e=yu(i)),void 0!==e&&s.push(e)}return this.frontHistogramBinBordersBuffer=r(s.map((t=>t.frontHistogramBinBorders)),this.getHistogramBinBorderBufferParameters()),this.backHistogramBinBordersBuffer=r(s.map((t=>t.backHistogramBinBorders)),this.getHistogramBinBorderBufferParameters()),this.adjacentBondArrowsBuffer=r(s.map((t=>t.adjacentBondArrows)),this.getBondArrowsBufferParameters()),this.distantBondArrowsBuffer=r(s.map((t=>t.distantBondArrows)),this.getBondArrowsBufferParameters()),this.opaqueMiddleDiscBuffer=n(s.map((t=>t.opaqueMiddleDisc)),this.getOpaqueMiddleDiscBufferParameters()),this.frontHistogramBuffer=n(s.map((t=>t.frontHistogram)),this.getHistogramBufferParameters()),this.backHistogramBuffer=n(s.map((t=>t.backHistogram)),this.getHistogramBufferParameters()),{bufferList:[].concat(this.frontHistogramBinBordersBuffer,this.backHistogramBinBordersBuffer,this.adjacentBondArrowsBuffer,this.distantBondArrowsBuffer,this.opaqueMiddleDiscBuffer,this.frontHistogramBuffer,this.backHistogramBuffer)}}setParameters(t){return super.setParameters(t,{},!1),t&&void 0!==t.histogramBinBorderVisible&&this.setVisibility(this.visible),this}setVisibility(t,e){return super.setVisibility(t,!0),this.frontHistogramBinBordersBuffer&&this.frontHistogramBinBordersBuffer.setVisibility(this.histogramBinBorderVisible),this.backHistogramBinBordersBuffer&&this.backHistogramBinBordersBuffer.setVisibility(this.histogramBinBorderVisible),e||this.viewer.requestRender(),this}}function yu(t){const e=t.atomPositions,i=t.histogram360Scaled,r=i.length<=180?360:2*i.length,n={triangles:new Float32Array(3*r*3),triangleColors:pu(t.opaqueMiddleDiscColor,3*r)},s={triangles:new Float32Array(3*i.length*3),triangleColors:pu(t.frontHistogramColor,3*i.length)},o={triangles:new Float32Array(3*i.length*3),triangleColors:pu(t.backHistogramColor,3*i.length)},a={startPoints:new Float32Array(3*i.length),endPoints:new Float32Array(3*i.length),startColors:pu(t.histogramBinBorderColor,i.length),endColors:pu(t.histogramBinBorderColor,i.length)},c={startPoints:new Float32Array(3*i.length),endPoints:new Float32Array(3*i.length),startColors:pu(t.histogramBinBorderColor,i.length),endColors:pu(t.histogramBinBorderColor,i.length)},l={startPoints:new Float32Array(6),endPoints:new Float32Array(6),startColors:pu(t.adjacentBondArrowColor,i.length),endColors:pu(t.adjacentBondArrowColor,i.length)},h={startPoints:new Float32Array(6),endPoints:new Float32Array(6),startColors:pu(t.distantBondArrowColor,i.length),endColors:pu(t.distantBondArrowColor,i.length)},u=Xr(),d=Xr(),m=Xr(),f=Xr(),p=Xr(),g=Xr(),y=Xr(),b=Xr(),_=Xr(),x=Xr(),v=Xr(),w=Xr(),A=Xr(),S=Xr(),C=Xr(),P=Xr(),I=[u,d,m,f];for(let t=0;t{let d=e[0],m=e[1];if("number"==typeof d&&Number.isInteger(d)&&"number"==typeof m&&Number.isInteger(m)){if(!u.get(d)||!u.get(m))return void(h+=1);c.index=d,l.index=m}else{s.setString(d),o.setString(m);var f=t.getAtomIndices(s),p=t.getAtomIndices(o);if(!f.length||!p.length)return void(h+=1);c.index=f[0],l.index=p[0]}a.addBond(c,l,1),i-=h;var g=c.distanceTo(l);switch(this.labelUnit){case"angstrom":r[i]=g.toFixed(2)+" "+String.fromCharCode(8491);break;case"nm":r[i]=(g/10).toFixed(2)+" nm";break;default:r[i]=g.toFixed(2)}var y=3*i;n[y+0]=(c.x+l.x)/2,n[y+1]=(c.y+l.y)/2,n[y+2]=(c.z+l.z)/2})),h>0&&(i-=h,n=n.subarray(0,3*i));var d=new En(a.count,!0);return{text:r,position:n,bondSet:d,bondStore:a}}getBondData(t,e,i){const r=t.getBondData(this.getBondParams(e,i));return r.picking&&(r.picking=new Js(r.picking.array,r.picking.structure,i.bondStore)),r}createData(t){if(!t.atomCount||!this.atomPair.length)return;const e=this.atomPair.length,i=new n(this.labelColor),r=this.getDistanceData(t,this.atomPair);this.textBuffer=new Oh({position:r.position,size:Ai(e,this.labelSize),color:Si(e,i.r,i.g,i.b),text:r.text},this.getLabelBufferParams());const s={bondSet:r.bondSet,bondStore:r.bondStore},o=this.getBondData(t,{position:!0,color:!0,picking:!0,radius:this.useCylinder},s);return this.useCylinder?this.distanceBuffer=new tu(o,this.getBufferParams({openEnded:this.openEnded,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0})):this.distanceBuffer=new Nh(fn(o),this.getBufferParams({linewidth:this.linewidth,visible:this.lineVisible,opacity:this.lineOpacity})),{bondSet:r.bondSet,bondStore:r.bondStore,position:r.position,bufferList:[this.textBuffer,this.distanceBuffer]}}updateData(t,e){super.updateData(t,e);const i={bondSet:e.bondSet,bondStore:e.bondStore},r=this.getBondData(e.sview,t,i),n={};t&&!t.color||Object.assign(n,{color:r.color,color2:r.color2}),t&&!t.radius||Object.assign(n,{radius:r.radius}),this.distanceBuffer.setAttributes(n)}setParameters(t){return super.setParameters(t,{},!1),this.useCylinder||(t&&t.lineOpacity&&this.distanceBuffer.setParameters({opacity:t.lineOpacity}),t&&void 0!==t.opacity&&this.distanceBuffer.setParameters({opacity:this.lineOpacity}),t&&t.linewidth&&this.distanceBuffer.setParameters({linewidth:t.linewidth})),this}}function _u(t){return 2*(t.position.length/3)*3}Le.add("distance",bu);const xu=Object.assign({scale:1,color:"grey"},No);class vu extends Uo{constructor(t,e={}){super({position:new Float32Array(_u(t)),color:new Float32Array(_u(t))},e),this.isLine=!0,this.vertexShader="Line.vert",this.fragmentShader="Line.frag";const i=new n(this.parameters.color),r=this.geometry.attributes;Si(_u(t)/3,i.r,i.g,i.b,r.color.array),this.setAttributes(t)}get defaultParameters(){return xu}setAttributes(t={}){const e=this.geometry.attributes;let i,r,n;t.position&&t.vector&&(i=t.position,r=t.vector,n=e.position.array,e.position.needsUpdate=!0);const s=this.size/2,o=this.parameters.scale;if(i&&r)for(let t=0;t{if(t.residueCount<4)return;i.push(t);const r=new Sa(t),n=r.getPosition(),s=r.getColor(this.getColorParams()),o=r.getSize(this.getRadiusParams()),a=r.getPicking();e.push(new Uc({position:n.center,color:s.color,radius:o.size,picking:a.picking},this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!0})),new vu({position:n.center,vector:n.axis},this.getBufferParams({color:"skyblue",scale:1})),new vu({position:n.center,vector:n.resdir},this.getBufferParams({color:"lightgreen",scale:1})))}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){De&&ke.time(this.type+" repr update"),t=t||{};for(let i=0,r=e.polymerList.length;i radius2) {\nspaceposition.y = mapping.y * 1.5 * radius1;\nspaceposition.x = mapping.x * 1.5 * radius1;\n} else {\nspaceposition.y = mapping.y * 1.5 * radius2;\nspaceposition.x = mapping.x * 1.5 * radius2;\n}\nspaceposition.w = 1.0;\nvec4 e3 = vec4( 1.0 );\nvec3 e1, e1_temp, e2, e2_temp;\ne3.xyz = normalize(position_atom1-position_atom2);\nif (e3.z == 0.0) { e3.z = 0.0000000000001;}\nif ( (position_atom1.x - position_atom2.x) == 0.0) { position_atom1.x += 0.001;}\nif ( (position_atom1.y - position_atom2.y) == 0.0) { position_atom1.y += 0.001;}\nif ( (position_atom1.z - position_atom2.z) == 0.0) { position_atom1.z += 0.001;}\nvec4 focus = vec4( 1.0 );\nfocus.x = ( position_atom1.x*position_atom1.x - position_atom2.x*position_atom2.x +\n( radius2*radius2 - radius1*radius1 )*e3.x*e3.x/shrink )/(2.0*(position_atom1.x - position_atom2.x));\nfocus.y = ( position_atom1.y*position_atom1.y - position_atom2.y*position_atom2.y +\n( radius2*radius2 - radius1*radius1 )*e3.y*e3.y/shrink )/(2.0*(position_atom1.y - position_atom2.y));\nfocus.z = ( position_atom1.z*position_atom1.z - position_atom2.z*position_atom2.z +\n( radius2*radius2 - radius1*radius1 )*e3.z*e3.z/shrink )/(2.0*(position_atom1.z - position_atom2.z));\ne1.x = 1.0;\ne1.y = 1.0;\ne1.z = ( (e3.x*focus.x + e3.y*focus.y + e3.z*focus.z) - e1.x*e3.x - e1.y*e3.y)/e3.z;\ne1_temp = e1 - focus.xyz;\ne1 = normalize(e1_temp);\ne2_temp = e1.yzx * e3.zxy - e1.zxy * e3.yzx;\ne2 = normalize(e2_temp);\nmat3 R= mat3( e1.xyz, e2.xyz, e3.xyz );\nvertex_position.xyz = R * spaceposition.xyz;\nvertex_position.w = 1.0;\nvertex_position.x += (position_atom1.x+position_atom2.x) / 2.0;\nvertex_position.y += (position_atom1.y+position_atom2.y) / 2.0;\nvertex_position.z += (position_atom1.z+position_atom2.z) / 2.0;\ngl_Position = modelViewProjectionMatrix * vertex_position;\nvec4 i_near, i_far;\nvec4 near = gl_Position;\nnear.z = 0.0 ;\nnear = modelViewProjectionMatrixInverse * near;\ni_near = near;\nvec4 far = gl_Position;\nfar.z = far.w ;\ni_far = modelViewProjectionMatrixInverse * far;\nprime1 = vec4( position_atom1 - (position_atom1 - focus.xyz)*shrink, 1.0 );\nprime2 = vec4( position_atom2 - (position_atom2 - focus.xyz)*shrink, 1.0 );\nfloat Rsquare = (radius1*radius1/shrink) - (\n(position_atom1.x - focus.x)*(position_atom1.x - focus.x) +\n(position_atom1.y - focus.y)*(position_atom1.y - focus.y) +\n(position_atom1.z - focus.z)*(position_atom1.z - focus.z)\n);\nfocus.w = Rsquare;\nmatrix_near = mat4( i_near, i_far, focus, e3 );\ngl_Position.z = 1.0;\n}"),ze.add("shader/HyperballStickImpostor.frag","#define STANDARD\n#define IMPOSTOR\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 interiorColor;\nuniform float interiorDarkening;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\nuniform float clipNear;\nuniform float shrink;\nuniform mat4 modelViewMatrix;\nuniform mat4 modelViewProjectionMatrix;\nuniform mat4 modelViewMatrixInverseTranspose;\nuniform mat4 projectionMatrix;\nvarying mat4 matrix_near;\nvarying vec4 prime1;\nvarying vec4 prime2;\nvarying float vRadius;\nvarying float vRadius2;\n#ifdef PICKING\nuniform float objectId;\nvarying vec3 vPickingColor;\n#else\nvarying vec3 vColor1;\nvarying vec3 vColor2;\n#include common\n#include fog_pars_fragment\n#include bsdfs\n#include lights_pars_begin\n#include lights_physical_pars_fragment\n#endif\nbool interior = false;\nfloat calcClip( vec4 cameraPos ){\nreturn dot( cameraPos, vec4( 0.0, 0.0, 1.0, clipNear - 0.5 ) );\n}\nfloat calcClip( vec3 cameraPos ){\nreturn calcClip( vec4( cameraPos, 1.0 ) );\n}\nfloat calcDepth( in vec3 cameraPos ){\nvec2 clipZW = cameraPos.z * projectionMatrix[2].zw + projectionMatrix[3].zw;\nreturn 0.5 + 0.5 * clipZW.x / clipZW.y;\n}\nstruct Ray {\nvec3 origin ;\nvec3 direction ;\n};\nbool cutoff_plane (vec3 M, vec3 cutoff, vec3 x3){\nfloat a = x3.x;\nfloat b = x3.y;\nfloat c = x3.z;\nfloat d = -x3.x*cutoff.x-x3.y*cutoff.y-x3.z*cutoff.z;\nfloat l = a*M.x+b*M.y+c*M.z+d;\nif (l<0.0) {return true;}\nelse{return false;}\n}\nvec3 isect_surf(Ray r, mat4 matrix_coef){\nvec4 direction = vec4(r.direction, 0.0);\nvec4 origin = vec4(r.origin, 1.0);\nfloat a = dot(direction,(matrix_coef*direction));\nfloat b = dot(origin,(matrix_coef*direction));\nfloat c = dot(origin,(matrix_coef*origin));\nfloat delta =b*b-a*c;\ngl_FragColor.a = 1.0;\nif (delta<0.0){\ndiscard;\n}\nfloat t1 =(-b-sqrt(delta))/a;\nreturn r.origin+t1*r.direction;\n}\nvec3 isect_surf2(Ray r, mat4 matrix_coef){\nvec4 direction = vec4(r.direction, 0.0);\nvec4 origin = vec4(r.origin, 1.0);\nfloat a = dot(direction,(matrix_coef*direction));\nfloat b = dot(origin,(matrix_coef*direction));\nfloat c = dot(origin,(matrix_coef*origin));\nfloat delta =b*b-a*c;\ngl_FragColor.a = 1.0;\nif (delta<0.0){\ndiscard;\n}\nfloat t2 =(-b+sqrt(delta))/a;\nreturn r.origin+t2*r.direction;\n}\nRay primary_ray(vec4 near1, vec4 far1){\nvec3 near=near1.xyz/near1.w;\nvec3 far=far1.xyz/far1.w;\nreturn Ray(near,far-near);\n}\nfloat update_z_buffer(vec3 M, mat4 ModelViewP){\nfloat depth1;\nvec4 Ms=(ModelViewP*vec4(M,1.0));\nreturn depth1=(1.0+Ms.z/Ms.w)/2.0;\n}\nvoid main(){\nfloat radius = max( vRadius, vRadius2 );\nvec4 i_near, i_far, focus;\nvec3 e3, e1, e1_temp, e2;\ni_near = vec4(matrix_near[0][0],matrix_near[0][1],matrix_near[0][2],matrix_near[0][3]);\ni_far = vec4(matrix_near[1][0],matrix_near[1][1],matrix_near[1][2],matrix_near[1][3]);\nfocus = vec4(matrix_near[2][0],matrix_near[2][1],matrix_near[2][2],matrix_near[2][3]);\ne3 = vec3(matrix_near[3][0],matrix_near[3][1],matrix_near[3][2]);\ne1.x = 1.0;\ne1.y = 1.0;\ne1.z = ( (e3.x*focus.x + e3.y*focus.y + e3.z*focus.z) - e1.x*e3.x - e1.y*e3.y)/e3.z;\ne1_temp = e1 - focus.xyz;\ne1 = normalize(e1_temp);\ne2 = normalize(cross(e1,e3));\nvec4 equation = focus;\nfloat shrinkfactor = shrink;\nfloat t1 = -1.0/(1.0-shrinkfactor);\nfloat t2 = 1.0/(shrinkfactor);\nvec4 colonne1, colonne2, colonne3, colonne4;\nmat4 mat;\nvec3 equation1 = vec3(t2,t2,t1);\nfloat A1 = - e1.x*equation.x - e1.y*equation.y - e1.z*equation.z;\nfloat A2 = - e2.x*equation.x - e2.y*equation.y - e2.z*equation.z;\nfloat A3 = - e3.x*equation.x - e3.y*equation.y - e3.z*equation.z;\nfloat A11 = equation1.x*e1.x*e1.x + equation1.y*e2.x*e2.x + equation1.z*e3.x*e3.x;\nfloat A21 = equation1.x*e1.x*e1.y + equation1.y*e2.x*e2.y + equation1.z*e3.x*e3.y;\nfloat A31 = equation1.x*e1.x*e1.z + equation1.y*e2.x*e2.z + equation1.z*e3.x*e3.z;\nfloat A41 = equation1.x*e1.x*A1 + equation1.y*e2.x*A2 + equation1.z*e3.x*A3;\nfloat A22 = equation1.x*e1.y*e1.y + equation1.y*e2.y*e2.y + equation1.z*e3.y*e3.y;\nfloat A32 = equation1.x*e1.y*e1.z + equation1.y*e2.y*e2.z + equation1.z*e3.y*e3.z;\nfloat A42 = equation1.x*e1.y*A1 + equation1.y*e2.y*A2 + equation1.z*e3.y*A3;\nfloat A33 = equation1.x*e1.z*e1.z + equation1.y*e2.z*e2.z + equation1.z*e3.z*e3.z;\nfloat A43 = equation1.x*e1.z*A1 + equation1.y*e2.z*A2 + equation1.z*e3.z*A3;\nfloat A44 = equation1.x*A1*A1 + equation1.y*A2*A2 + equation1.z*A3*A3 - equation.w;\ncolonne1 = vec4(A11,A21,A31,A41);\ncolonne2 = vec4(A21,A22,A32,A42);\ncolonne3 = vec4(A31,A32,A33,A43);\ncolonne4 = vec4(A41,A42,A43,A44);\nmat = mat4(colonne1,colonne2,colonne3,colonne4);\nRay ray = primary_ray(i_near,i_far) ;\nvec3 M;\nM = isect_surf(ray, mat);\nif (cutoff_plane(M, prime1.xyz, -e3) || cutoff_plane(M, prime2.xyz, e3)){ discard; }\nvec4 M1 = vec4(M,1.0);\nvec4 M2 = mat*M1;\nvec3 _normal = ( modelViewMatrixInverseTranspose * M2 ).xyz;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix) ;\n#ifdef NEAR_CLIP\nif( calcClip( modelViewMatrix * vec4( M, 1.0 ) ) > 0.0 ){\nM = isect_surf2(ray, mat);\nif( calcClip( modelViewMatrix * vec4( M, 1.0 ) ) > 0.0 )\ndiscard;\ninterior = true;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix) ;\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = max( 0.0, calcDepth( vec3( - ( clipNear - 0.5 ) ) ) + ( 0.0000001 / radius ) );\n}\n}else if( gl_FragDepthEXT <= 0.0 ){\nM = isect_surf2(ray, mat);\ninterior = true;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix);\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / radius );\n}\n}\n#else\nif( gl_FragDepthEXT <= 0.0 ){\nM = isect_surf2(ray, mat);\ninterior = true;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix) ;\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / radius );\n}\n}\n#endif\nif (cutoff_plane(M, prime1.xyz, -e3) || cutoff_plane(M, prime2.xyz, e3)){ discard; }\nif (gl_FragDepthEXT < 0.0)\ndiscard;\nif (gl_FragDepthEXT > 1.0)\ndiscard;\nfloat distance_ratio = ((M.x-prime2.x)*e3.x + (M.y-prime2.y)*e3.y +(M.z-prime2.z)*e3.z) /\ndistance(prime2.xyz,prime1.xyz);\n#ifdef PICKING\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 vViewPosition = -( modelViewMatrix * vec4( M, 1.0 ) ).xyz;\nvec3 vNormal = _normal;\nvec3 vColor;\nif( distance_ratio>0.5 ){\nvColor = vColor1;\n}else{\nvColor = vColor2;\n}\nvec4 diffuseColor = vec4( diffuse, opacity );\nReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\nvec3 totalEmissiveLight = emissive;\n#include color_fragment\n#include roughnessmap_fragment\n#include metalnessmap_fragment\nvec3 normal = normalize( vNormal );\nvec3 nonPerturbedNormal = normal;\n#include lights_physical_fragment\n#include lights_fragment_begin\n#include lights_fragment_end\nvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveLight;\nif( interior ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Su=new Float32Array([-1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,-1,1,-1,1,1,-1,1,1,1,-1,1,1]),Cu=new Uint16Array([0,1,2,0,2,3,1,5,6,1,6,2,4,6,5,4,7,6,0,7,4,0,3,7,0,5,1,0,4,5,3,2,6,3,6,7]);class Pu extends Oc{constructor(t,e={}){super("v3",t,e)}get mapping(){return Su}get mappingIndices(){return Cu}get mappingIndicesSize(){return 36}get mappingSize(){return 8}get mappingItemSize(){return 3}}const Iu=Object.assign({shrink:.14},No),ku=Object.assign({shrink:{uniform:!0}},zo);class Mu extends Pu{constructor(t,e={}){super(t,e),this.parameterTypes=ku,this.isImpostor=!0,this.vertexShader="HyperballStickImpostor.vert",this.fragmentShader="HyperballStickImpostor.frag",this.addUniforms({modelViewProjectionMatrix:{value:new i},modelViewProjectionMatrixInverse:{value:new i},modelViewMatrixInverseTranspose:{value:new i},shrink:{value:this.parameters.shrink}}),this.addAttributes({position1:{type:"v3",value:null},position2:{type:"v3",value:null},color2:{type:"c",value:null},radius:{type:"f",value:null},radius2:{type:"f",value:null}}),this.setAttributes(t),this.makeMapping()}get defaultParameters(){return Iu}}Object.assign({disableImpostor:!1},Hh,Iu);const Tu=class{constructor(t,e={}){return!Pe||e&&e.disableImpostor?(t.radius=function(t,e){const i=t.length,r=new Float32Array(i);for(let n=0;na.push(r.atomLabel(t)))))}else if("residue"===this.labelGrouping){e&&!e.position||(c=[]),e&&!e.color||(h=[]),e&&!e.radius||(l=[]),e&&!e.text||(a=[]),i.colorParams&&(i.colorParams.structure=t.getStructure());const u=Oe.getScheme(i.colorParams),d=new ma(i.radiusParams),m=t.getAtomProxy();let f=0;t.eachResidue((t=>{const i=3*f;t.isProtein()||t.isNucleic()?(m.index=t.traceAtomIndex,e&&!e.position||m.positionToArray(c,i)):(m.index=t.atomOffset,e&&!e.position||t.positionToArray(c,i)),e&&!e.color||u.atomColorToArray(m,h,i),e&&!e.radius||(l[f]=d.atomRadius(m)),e&&!e.text||a.push(r.atomLabel(m)),++f})),e&&!e.position||(n=new Float32Array(c)),e&&!e.color||(o=new Float32Array(h)),e&&!e.radius||(s=new Float32Array(l))}return{position:n,size:s,color:o,text:a}}createData(t){return{bufferList:[new Oh(this.getTextData(t,{position:!0,color:!0,radius:!0,text:!0}),this.getBufferParams({fontFamily:this.fontFamily,fontStyle:this.fontStyle,fontWeight:this.fontWeight,xOffset:this.xOffset,yOffset:this.yOffset,zOffset:this.zOffset,attachment:this.attachment,showBorder:this.showBorder,borderColor:this.borderColor,borderWidth:this.borderWidth,showBackground:this.showBackground,backgroundColor:this.backgroundColor,backgroundMargin:this.backgroundMargin,backgroundOpacity:this.backgroundOpacity,fixedSize:this.fixedSize}))]}}updateData(t,e){e.bufferList[0].setAttributes(this.getTextData(e.sview,t))}getAtomRadius(){return 0}}function Eu(t){const e=t.getAtomSet(),i=t.getBondSet(),r=t.getBondProxy();return i.forEach((function(t){r.index=t,e.clear(r.atomIndex1),e.clear(r.atomIndex2)})),e}Le.add("label",Fu);class $u extends Sh{constructor(t,e,i){super(t,e,i),this.type="line",this.parameters=Object.assign({multipleBond:{type:"select",rebuild:!0,options:{off:"off",symmetric:"symmetric",offset:"offset"}},bondSpacing:{type:"number",precision:2,max:2,min:.5},linewidth:{type:"integer",max:50,min:1,buffer:!0},lines:{type:"boolean",rebuild:!0},crosses:{type:"select",rebuild:!0,options:{off:"off",lone:"lone",all:"all"}},crossSize:{type:"number",precision:2,max:2,min:.1}},this.parameters,{flatShaded:null,side:null,wireframe:null,roughness:null,metalness:null}),this.init(i)}init(t){var e=t||{};this.multipleBond=rt(e.multipleBond,"off"),this.bondSpacing=rt(e.bondSpacing,1),this.linewidth=rt(e.linewidth,2),this.lines=rt(e.lines,!0),this.crosses=rt(e.crosses,"lone"),this.crossSize=rt(e.crossSize,.4),super.init(e)}getAtomRadius(t){return.1}getBondParams(t,e){return e=Object.assign({multipleBond:this.multipleBond,bondSpacing:this.bondSpacing,radiusParams:{type:"size",size:.1,scale:1}},e),super.getBondParams(t,e)}_crossData(t,e){if(t&&!t.position&&!t.color)return;const i={};"lone"===this.crosses&&Object.assign(i,{atomSet:Eu(e)});const r=e.getAtomData(this.getAtomParams(t,i)),n={},s=r.position,o=r.color,a=r.picking,c=(s||o).length,l=3*c;let h=new Float32Array(0),u=new Float32Array(0),d=new Float32Array(0),m=new Float32Array(0),f=0,p=new Float32Array(0);t&&!t.position||(h=n.position1=new Float32Array(l),u=n.position2=new Float32Array(l),f=this.crossSize/2),t&&!t.color||(d=n.color=new Float32Array(l),m=n.color2=new Float32Array(l)),t&&!t.picking||(p=new Float32Array(3*r.picking.array.length));for(let e=0;el?d[p]=-1:(c=Math.sqrt(l-a),d[p]=Math.floor(c)),++p;f[g]=u,m[g]=d}}function k(i){var r,n,s,a,u,p,b,x,v,w,S,C,P,I,k,M,T,D,B=3*i,F=i;r=Math.floor(.5+o*(t[B]+d[0])),n=Math.floor(.5+o*(t[B+1]+d[1])),s=Math.floor(.5+o*(t[B+2]+d[2]));var E,$=e[F],O=m[$],R=0,L=l*h,N=f[$];for(w=0;w=c||I>=l||k>=h)){var z=P*L+I*h+k;if(g)if(y[z]&A){if(y[z]&A){var U=_[z];U!==B&&b*b+x*x+v*v<(a=r+b-Math.floor(.5+o*(t[U]+d[0])))*a+(u=n+x-Math.floor(.5+o*(t[U+1]+d[1])))*u+(p=s+v-Math.floor(.5+o*(t[U+2]+d[2])))*p&&(_[z]=i)}}else y[z]|=A,_[z]=i;else y[z]|=A}R++}}function M(e){var i,r;for(console.time("EDTSurface fillvoxels"),i=0,r=y.length;i=c||A>=l||C>=h)){var L=w*R+A*h+C;if(y[L]&S){if(g){var N=_[L];b*b+x*x+v*v<(a=Math.floor(.5+o*(t[N]+d[0])))*a+(u=Math.floor(.5+o*(t[N+1]+d[1])))*u+(p=Math.floor(.5+o*(t[N+2]+d[2])))*p&&(_[L]=i)}}else y[L]|=S,g&&(_[L]=i)}$++}}function D(){var t,e,i,r;console.time("EDTSurface fastdistancemap");var n,s=Ou(c,l,h,Uint16Array,3),o=l*h,u=p*p,d=0;for(t=0;t0);var w,P=a*a,I=new Uint16Array(3);for(t=0;t=P)||(y[n]|=C,g&&y[n]&S&&(s.toArray(t,e,i,I),w=I[0]*o+I[1]*h+I[2],_[n]=_[w])));console.timeEnd("EDTSurface fastdistancemap")}function B(t,e,i,r){var n,s,o,a,u,d,m,f,p,g,_,x,v=new Uint16Array(3),w=0;if(0===i)return w;var I=-1,k=-1,M=-1,T=l*h;for(m=0,p=i;m-1&&k-1&&M-1&&(y[_=I*T+h*k+M]&A&&!(y[_]&S)?(e.fromArray(I,k,M,v),g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d,b[_]=g,y[_]|=S,y[_]|=C,r[w]=I,r[w+1]=k,r[w+2]=M,w+=3):y[_]&A&&y[_]&S&&(g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d)-1&&k-1&&M-1&&(y[_=I*T+h*k+M]&A&&!(y[_]&S)?(e.fromArray(I,k,M,v),g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d,b[_]=g,y[_]|=S,y[_]|=C,r[w]=I,r[w+1]=k,r[w+2]=M,w+=3):y[_]&A&&y[_]&S&&(g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d)-1&&k-1&&M-1&&(y[_=I*T+h*k+M]&A&&!(y[_]&S)?(e.fromArray(I,k,M,v),g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d,b[_]=g,y[_]|=S,y[_]|=C,r[w]=I,r[w+1]=k,r[w+2]=M,w+=3):y[_]&A&&y[_]&S&&(g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d)-1&&o-1&&u-1&&aT&&(T=E)}return{neighbourListLength:27*T+1,withinRadii:function(n,s,o,a,u){for(var d=0,m=f(n,c),p=f(s,l),g=f(o,h),y=Math.max(0,m-1),v=Math.max(0,p-1),A=Math.max(0,g-1),S=Math.min(b,m+2),C=Math.min(_,p+2),M=Math.min(x,g+2),T=y;Td&&(d=h[t]);!function(){const t=Bo(c,l,d,f,0);f=t.scaleFactor,y=t.dim,b=t.matrix,F=Math.max(5,2+Math.floor(m*f)),_=Ai(y[0]*y[1]*y[2],-1001),x=new Int32Array(_.length),v=new Float32Array(y[0]),w=new Float32Array(y[1]),A=new Float32Array(y[2]),$(v,c[0],1/f),$(w,c[1],1/f),$(A,c[2],1/f)}(),function(){var t=0,e=2*Math.PI/g;C=new Float32Array(g),S=new Float32Array(g);for(var i=0;i=0;){if(s!==r&&s!==n&&R(s,t,e,i))return k=s,s;s=I[++o]}return k=-1,-1}function R(e,i,r,n){var s=3*e,o=u[e],a=t[s]-i,c=t[s+1]-r,l=t[s+2]-n;return a*a+c*c+l*l0&&d=0;)t{e(this._makeSurface(t.data.sd,i))}),(t=>{console.warn("MolecularSurface.getSurfaceWorker error - trying without worker",t),this.worker.terminate(),this.worker=void 0;const r=this.getSurface(i);e(r)}))}else{const t=this.getSurface(i);e(t)}}dispose(){this.worker&&this.worker.terminate()}}class Uu extends Sh{constructor(t,e,i){super(t,e,i),this.type="surface",this.parameters=Object.assign({surfaceType:{type:"select",rebuild:!0,options:{vws:"vws",sas:"sas",ms:"ms",ses:"ses",av:"av"}},probeRadius:{type:"number",precision:1,max:20,min:0,rebuild:!0},smooth:{type:"integer",precision:1,max:10,min:0,rebuild:!0},scaleFactor:{type:"number",precision:1,max:5,min:0,rebuild:!0},cutoff:{type:"number",precision:2,max:50,min:0,rebuild:!0},contour:{type:"boolean",rebuild:!0},background:{type:"boolean",rebuild:!0},opaqueBack:{type:"boolean",buffer:!0},filterSele:{type:"text",rebuild:!0},colorVolume:{type:"hidden"},useWorker:{type:"boolean",rebuild:!0}},this.parameters,{radius:null,scale:null}),this.__infoList=[],this.structure.signals.refreshed.add((()=>{this.__forceNewMolsurf=!0})),this.toBePrepared=!0,this.init(i)}init(t){const e=t||{};e.colorScheme=rt(e.colorScheme,"uniform"),e.colorValue=rt(e.colorValue,14540253),e.disablePicking=rt(e.disablePicking,!0),this.surfaceType=rt(e.surfaceType,"ms"),this.probeRadius=rt(e.probeRadius,1.4),this.smooth=rt(e.smooth,2),this.scaleFactor=rt(e.scaleFactor,2),this.cutoff=rt(e.cutoff,0),this.contour=rt(e.contour,!1),this.background=rt(e.background,!1),this.opaqueBack=rt(e.opaqueBack,!0),this.filterSele=rt(e.filterSele,""),this.colorVolume=rt(e.colorVolume,void 0),this.useWorker=rt(e.useWorker,!0),super.init(t)}prepareData(t,i,r){let n=this.__infoList[i];if(n||(n={},this.__infoList[i]=n),n.molsurf&&n.sele===t.selection.string)r(i);else{if(this.filterSele){const n=t.structure.getView(new me(this.filterSele)),s=n.boundingBox.getSize(new e),o=Math.max(s.x,s.y,s.z),a=t.getAtomSetWithinPoint(n.center,o/2+6);if(0===(t=t.getView(new me(t.getAtomSetWithinSelection(a,3).toSeleString()))).atomCount)return void r(i)}n.sele=t.selection.string,n.molsurf=new zu(t);const s=this.getSurfaceParams(),o=t=>{n.surface=t,r(i)};this.useWorker?n.molsurf.getSurfaceWorker(s,o):o(n.molsurf.getSurface(s))}}prepare(t){if((this.__forceNewMolsurf||this.__sele!==this.selection.string||this.__surfaceParams!==JSON.stringify(this.getSurfaceParams()))&&(this.__infoList.forEach((t=>{t&&t.molsurf&&t.molsurf.dispose()})),this.__infoList.length=0),0===this.structureView.atomCount)return void t();const e=()=>{this.__sele=this.selection.string,this.__surfaceParams=JSON.stringify(this.getSurfaceParams()),this.__forceNewMolsurf=!1,t()},i="default"===this.assembly?this.defaultAssembly:this.assembly,r=this.structure.biomolDict[i];r?r.partList.forEach(((t,i)=>{const n=t.getView(this.structureView);this.prepareData(n,i,(t=>{t===r.partList.length-1&&e()}))})):this.prepareData(this.structureView,0,e)}createData(t,e){const i=this.__infoList[e],r=i.surface;if(!r)return;const n={position:r.getPosition(),color:r.getColor(this.getColorParams()),index:r.getFilteredIndex(this.filterSele,t)},s=[];if(r.contour){const t=new Wo(n,this.getBufferParams({wireframe:!1}));s.push(t)}else{Object.assign(n,{normal:r.getNormal(),picking:r.getPicking(t.getStructure())});const e=new jo(n,this.getBufferParams({background:this.background,opaqueBack:this.opaqueBack,dullInterior:!1}));if("double"==this.getBufferParams().side){const t=new qo(e);s.push(t)}else s.push(e)}return{bufferList:s,info:i}}updateData(t,e){const i={};if(t.position||t.radius)return this.__forceNewMolsurf=!0,void this.build();t.color&&(i.color=e.info.surface.getColor(this.getColorParams())),t.index&&(i.index=e.info.surface.getFilteredIndex(this.filterSele,e.sview)),e.bufferList[0].setAttributes(i)}setParameters(t,e={},i){return t&&t.filterSele&&(e.index=!0),t&&void 0!==t.colorVolume&&(e.color=!0),t&&t.wireframe&&(t.contour||void 0===t.contour&&this.contour)&&(t.wireframe=!1),super.setParameters(t,e,i),this}getSurfaceParams(t={}){return Object.assign({type:this.surfaceType,probeRadius:this.probeRadius,scaleFactor:this.scaleFactor,smooth:this.smooth&&!this.contour,cutoff:this.cutoff,contour:this.contour,useWorker:this.useWorker,radiusParams:this.getRadiusParams()},t)}getColorParams(){const t=super.getColorParams();return t.volume=this.colorVolume,t}getAtomRadius(){return 0}clear(){super.clear()}dispose(){this.__infoList.forEach((t=>{t&&t.molsurf&&t.molsurf.dispose()})),this.__infoList.length=0,super.dispose()}}Le.add("surface",Uu);class Vu extends Sh{constructor(t,e,i){super(t,e,i),this.type="point",this.parameters=Object.assign({pointSize:{type:"number",precision:1,max:100,min:0,buffer:!0},sizeAttenuation:{type:"boolean",buffer:!0},sortParticles:{type:"boolean",rebuild:!0},useTexture:{type:"boolean",buffer:!0},alphaTest:{type:"range",step:.001,max:1,min:0,buffer:!0},forceTransparent:{type:"boolean",buffer:!0},edgeBleach:{type:"range",step:.001,max:1,min:0,buffer:!0}},this.parameters,{flatShaded:null,wireframe:null,linewidth:null,side:null,roughness:null,metalness:null}),this.init(i)}init(t){var e=t||{};this.pointSize=rt(e.pointSize,1),this.sizeAttenuation=rt(e.sizeAttenuation,!0),this.sortParticles=rt(e.sortParticles,!1),this.useTexture=rt(e.useTexture,!1),this.alphaTest=rt(e.alphaTest,.5),this.forceTransparent=rt(e.forceTransparent,!1),this.edgeBleach=rt(e.edgeBleach,0),super.init(e)}createData(t){var e=t.getAtomData(this.getAtomParams({position:!0,color:!0,picking:!0}));return{bufferList:[new Hc(e,this.getBufferParams({pointSize:this.pointSize,sizeAttenuation:this.sizeAttenuation,sortParticles:this.sortParticles,useTexture:this.useTexture,alphaTest:this.alphaTest,forceTransparent:this.forceTransparent,edgeBleach:this.edgeBleach}))]}}updateData(t,e){var i=e.sview.getAtomData(this.getAtomParams(t)),r={};t&&!t.position||Object.assign(r,{position:i.position}),t&&!t.color||Object.assign(r,{color:i.color}),e.bufferList[0].setAttributes(r)}getAtomRadius(){return.1}}Le.add("point",Vu),ze.add("shader/Ribbon.vert","#define STANDARD\nuniform float clipNear;\nuniform vec3 clipCenter;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvarying vec3 vViewPosition;\n#endif\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\nattribute vec3 dir;\nattribute float size;\n#ifdef PICKING\n#include unpack_color\nattribute float primitiveId;\nvarying vec3 vPickingColor;\n#else\n#include color_pars_vertex\n#ifndef FLAT_SHADED\nvarying vec3 vNormal;\n#endif\n#endif\n#include common\nvoid main(void){\n#ifdef PICKING\nvPickingColor = unpackColor( primitiveId );\n#else\n#include color_vertex\n#include beginnormal_vertex\n#include defaultnormal_vertex\n#ifndef FLAT_SHADED\nvNormal = normalize( transformedNormal );\n#endif\n#endif\n#include begin_vertex\ntransformed += normalize( dir ) * size;\n#include project_vertex\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvViewPosition = -mvPosition.xyz;\n#endif\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n#include nearclip_vertex\n}");const ju=new Uint16Array([0,1,2,1,3,2]);function Gu(t){return 3*(4*(t.position.length/3-1))}class Hu extends Vo{constructor(t,e={}){super({position:new Float32Array(Gu(t)),color:new Float32Array(Gu(t)),index:bt(Gu(t),Gu(t)/3),normal:new Float32Array(Gu(t)),picking:t.picking},e),this.vertexShader="Ribbon.vert";const i=t.position.length/3-1,r=4*i,n=3*r;this.addAttributes({dir:{type:"v3",value:new Float32Array(n)}}),this.addAttributes({size:{type:"f",value:new Float32Array(r)}}),t.primitiveId=Ci(i),this.setAttributes(t),this.makeIndex()}setAttributes(t={}){const e=this.size/4,i=this.geometry.attributes;let r,n,s,o,a,c,l,h,u,d,m,f,p,g,y,b,_,x,v;t.position&&(r=t.position,l=i.position.array,i.position.needsUpdate=!0),t.normal&&(n=t.normal,h=i.normal.array,i.normal.needsUpdate=!0),t.size&&(s=t.size,u=i.size.array,i.size.needsUpdate=!0),t.dir&&(o=t.dir,d=i.dir.array,i.dir.needsUpdate=!0),t.color&&(a=t.color,m=i.color.array,i.color.needsUpdate=!0),t.primitiveId&&(c=t.primitiveId,f=i.primitiveId.array,i.primitiveId.needsUpdate=!0);let w=s?s[0]:null;for(p=0;p{if(!(t.residueCount<4)){i.push(t);var r=new ou(t,this.getSplineParams()),n=r.getSubdividedPosition(),s=r.getSubdividedOrientation(),o=r.getSubdividedColor(this.getColorParams()),a=r.getSubdividedPicking(),c=r.getSubdividedSize(this.getRadiusParams());e.push(new Hu({position:n.position,normal:s.binormal,dir:s.normal,color:o.color,size:c.size,picking:a.picking},this.getBufferParams()))}}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){t=t||{};var i=0,r=e.polymerList.length;for(i=0;i{if(t.residueCount<4||t.isNucleic())return;const n=new Ca(t),s=n.getAxis(this.localAngle,this.centerDist,this.ssBorder,this.getColorParams(),this.getRadiusParams());e+=s.size.length,i.push(s),r.push(n)}),t.getSelection());const n={begin:new Float32Array(3*e),end:new Float32Array(3*e),size:new Float32Array(e),color:new Float32Array(3*e),picking:{}};let s=new Float32Array(e),o=0;i.forEach((function(t){n.begin.set(t.begin,3*o),n.end.set(t.end,3*o),n.size.set(t.size,o),n.color.set(t.color,3*o),s.set(t.picking.array,o),o+=t.size.length})),e&&(n.picking=new Xs(s,t.getStructure()));return{bufferList:[new tu({position1:n.begin,position2:n.end,color:n.color,color2:n.color,radius:n.size,picking:n.picking},this.getBufferParams({openEnded:this.openEnded,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0}))],axisList:i,helixbundleList:r,axisData:n}}updateData(t,e){if((t=t||{}).position)this.build();else{var i={};if(t.color||t.radius){var r=0;e.helixbundleList.forEach((i=>{var n=i.getAxis(this.localAngle,this.centerDist,this.ssBorder,this.getColorParams(),this.getRadiusParams());t.color&&e.axisData.color.set(n.color,3*r),(t.radius||t.scale)&&e.axisData.size.set(n.size,r),r+=n.size.length})),t.color&&Object.assign(i,{color:e.axisData.color,color2:e.axisData.color}),(t.radius||t.scale)&&Object.assign(i,{radius:e.axisData.size})}e.bufferList[0].setAttributes(i)}}}Le.add("rocket",Wu);class Xu extends uu{constructor(t,e,i){super(t,e,i),this.type="rope",this.parameters=Object.assign({smooth:{type:"integer",max:15,min:0,rebuild:!0}},this.parameters,{aspectRatio:null,smoothSheet:null})}init(t){var e=t||{};e.aspectRatio=1,e.tension=rt(e.tension,.5),e.radiusScale=rt(e.radiusScale,5),e.smoothSheet=!1,this.smooth=rt(e.smooth,2),super.init(e)}getSpline(t){var e=new Sa(t);return new ou(t,this.getSplineParams({directional:!1,positionIterator:e.getCenterIterator(this.smooth)}))}}Le.add("rope",Xu);class Yu extends Sh{constructor(t,e,i){super(t,e,i),this.type="spacefill",this.parameters=Object.assign({sphereDetail:!0,disableImpostor:!0},this.parameters),this.init(i)}init(t){var e=t||{};e.useInteriorColor=rt(e.useInteriorColor,!0),super.init(e)}createData(t){return{bufferList:[new Uc(t.getAtomData(this.getAtomParams()),this.getBufferParams({sphereDetail:this.sphereDetail,dullInterior:!0,disableImpostor:this.disableImpostor}))]}}updateData(t,e){var i=e.sview.getAtomData(this.getAtomParams(t)),r={};t&&!t.position||Object.assign(r,{position:i.position}),t&&!t.color||Object.assign(r,{color:i.color}),t&&!t.radius||Object.assign(r,{radius:i.radius}),e.bufferList[0].setAttributes(r)}}function Ku(t){return 3*(t.position.length/3-1)*2}Le.add("spacefill",Yu);class Zu extends Uo{constructor(t,e={}){super({position:new Float32Array(Ku(t)),color:new Float32Array(Ku(t))},e),this.isLine=!0,this.vertexShader="Line.vert",this.fragmentShader="Line.frag",this.setAttributes(t)}setAttributes(t){let e,i,r,n;const s=this.geometry.attributes;if(t.position&&(e=t.position,r=s.position.array,s.position.needsUpdate=!0),t.color&&(i=t.color,n=s.color.array,s.color.needsUpdate=!0),!e&&!i)return void ke.warn("TraceBuffer.prototype.setAttributes no data");let o,a;const c=this.size-1;for(let t=0;t{if(!(t.residueCount<4)){i.push(t);var r=new ou(t,this.getSplineParams()),n=r.getSubdividedPosition(),s=r.getSubdividedColor(this.getColorParams());e.push(new Zu(Object.assign({},n,s),this.getBufferParams()))}}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){t=t||{};var i=0,r=e.polymerList.length;for(i=0;i{t.boundingBox||t.computeBoundingBox(),this.boundingBox.union(t.boundingBox)}))}}const ld=Object.assign({aspectRatio:1.5,radialSegments:50,openEnded:!1,disableImpostor:!1},No);class hd{constructor(t,e={}){this.group=new d,this.wireframeGroup=new d,this.pickingGroup=new d,this.visible=!0,this.parameters=nt(e,this.defaultParameters),this.splitPosition=new Float32Array(t.position1.length),this.cylinderRadius=new Float32Array(t.radius.length);const r=this.makeAttributes(t),n={radialSegments:this.parameters.radialSegments,openEnded:this.parameters.openEnded,disableImpostor:this.parameters.disableImpostor};this.cylinderBuffer=new tu(r.cylinder,n),this.coneBuffer=new ad(r.cone,n),this.geometry=new cd([this.cylinderBuffer.geometry,this.coneBuffer.geometry]),this.matrix=rt(e.matrix,new i),this.picking=t.picking}get defaultParameters(){return ld}set matrix(t){Uo.prototype.setMatrix.call(this,t)}get matrix(){return this.group.matrix.clone()}get pickable(){return!!this.picking}makeAttributes(t={}){const i=this.splitPosition,r=this.cylinderRadius,n=this.parameters.aspectRatio;let s,o;const a={},c={};if(t.radius){for(s=0,o=r.length;s0&&(s=1/Math.sqrt(s),t[0]=e[0]*s,t[1]=e[1]*s,t[2]=e[2]*s),t}function u(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function d(t,e,i){const r=e[0],n=e[1],s=e[2],o=i[0],a=i[1],c=i[2];return t[0]=n*c-s*a,t[1]=s*o-r*c,t[2]=r*a-n*o,t}t.zero=e,t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i},t.isFinite=function(t){return Xd(t[0])&&Xd(t[1])&&Xd(t[2])},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])||isNaN(t[2])},t.setNaN=function(t){return t[0]=NaN,t[1]=NaN,t[2]=NaN,t},t.fromObj=function(t){return i(t.x,t.y,t.z)},t.toObj=function(t){return{x:t[0],y:t[1],z:t[2]}},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e},t.create=i,t.ofArray=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i},t.set=function(t,e,i,r){return t[0]=e,t[1]=i,t[2]=r,t},t.copy=r,t.add=n,t.sub=s,t.mul=function(t,e,i){return t[0]=e[0]*i[0],t[1]=e[1]*i[1],t[2]=e[2]*i[2],t},t.div=function(t,e,i){return t[0]=e[0]/i[0],t[1]=e[1]/i[1],t[2]=e[2]/i[2],t},t.scale=o,t.scaleAndAdd=a,t.scaleAndSub=function(t,e,i,r){return t[0]=e[0]-i[0]*r,t[1]=e[1]-i[1]*r,t[2]=e[2]-i[2]*r,t},t.addScalar=function(t,e,i){return t[0]=e[0]+i,t[1]=e[1]+i,t[2]=e[2]+i,t},t.subScalar=function(t,e,i){return t[0]=e[0]-i,t[1]=e[1]-i,t[2]=e[2]-i,t},t.round=function(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t},t.ceil=function(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t},t.floor=function(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t},t.trunc=function(t,e){return t[0]=Math.trunc(e[0]),t[1]=Math.trunc(e[1]),t[2]=Math.trunc(e[2]),t},t.abs=function(t,e){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t},t.min=function(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},t.max=function(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},t.clamp=function(t,e,i,r){return t[0]=Math.max(i[0],Math.min(r[0],e[0])),t[1]=Math.max(i[1],Math.min(r[1],e[1])),t[2]=Math.max(i[2],Math.min(r[2],e[2])),t},t.distance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2];return Math.sqrt(i*i+r*r+n*n)},t.squaredDistance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2];return i*i+r*r+n*n},t.magnitude=function(t){const e=t[0],i=t[1],r=t[2];return Math.sqrt(e*e+i*i+r*r)},t.squaredMagnitude=c,t.setMagnitude=function(t,e,i){return o(t,h(t,e),i)},t.negate=l,t.inverse=function(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t},t.normalize=h,t.dot=u,t.cross=d,t.lerp=function(t,e,i,r){const n=e[0],s=e[1],o=e[2];return t[0]=n+r*(i[0]-n),t[1]=s+r*(i[1]-s),t[2]=o+r*(i[2]-o),t};const m=e();function f(t,e){const i=Math.sqrt(c(t)*c(e));if(0===i)return Math.PI/2;const r=u(t,e)/i;return Math.acos(Hd(r,-1,1))}t.slerp=function(t,e,i,r){const s=Hd(u(e,i),-1,1),c=Math.acos(s)*r;return a(m,i,e,-s),h(m,m),n(t,o(t,e,Math.cos(c)),o(m,m,Math.sin(c)))},t.hermite=function(t,e,i,r,n,s){const o=s*s,a=o*(2*s-3)+1,c=o*(s-2)+s,l=o*(s-1),h=o*(3-2*s);return t[0]=e[0]*a+i[0]*c+r[0]*l+n[0]*h,t[1]=e[1]*a+i[1]*c+r[1]*l+n[1]*h,t[2]=e[2]*a+i[2]*c+r[2]*l+n[2]*h,t},t.bezier=function(t,e,i,r,n,s){const o=1-s,a=o*o,c=s*s,l=a*o,h=3*s*a,u=3*c*o,d=c*s;return t[0]=e[0]*l+i[0]*h+r[0]*u+n[0]*d,t[1]=e[1]*l+i[1]*h+r[1]*u+n[1]*d,t[2]=e[2]*l+i[2]*h+r[2]*u+n[2]*d,t},t.quadraticBezier=function(t,e,i,r,n){return t[0]=Wd(e[0],i[0],r[0],n),t[1]=Wd(e[1],i[1],r[1],n),t[2]=Wd(e[2],i[2],r[2],n),t},t.spline=function(t,e,i,r,n,s,o){return t[0]=qd(e[0],i[0],r[0],n[0],s,o),t[1]=qd(e[1],i[1],r[1],n[1],s,o),t[2]=qd(e[2],i[2],r[2],n[2],s,o),t},t.random=function(t,e){const i=2*Math.random()*Math.PI,r=2*Math.random()-1,n=Math.sqrt(1-r*r)*e;return t[0]=Math.cos(i)*n,t[1]=Math.sin(i)*n,t[2]=r*e,t},t.transformMat4=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=1/(i[3]*r+i[7]*n+i[11]*s+i[15]||1);return t[0]=(i[0]*r+i[4]*n+i[8]*s+i[12])*o,t[1]=(i[1]*r+i[5]*n+i[9]*s+i[13])*o,t[2]=(i[2]*r+i[6]*n+i[10]*s+i[14])*o,t},t.transformDirection=function(t,e,i){const r=e[0],n=e[1],s=e[2];return t[0]=i[0]*r+i[4]*n+i[8]*s,t[1]=i[1]*r+i[5]*n+i[9]*s,t[2]=i[2]*r+i[6]*n+i[10]*s,h(t,t)},t.transformMat4Offset=function(t,e,i,r,n,s){const o=e[0+n],a=e[1+n],c=e[2+n],l=1/(i[3+s]*o+i[7+s]*a+i[11+s]*c+i[15+s]||1);return t[0+r]=(i[0+s]*o+i[4+s]*a+i[8+s]*c+i[12+s])*l,t[1+r]=(i[1+s]*o+i[5+s]*a+i[9+s]*c+i[13+s])*l,t[2+r]=(i[2+s]*o+i[6+s]*a+i[10+s]*c+i[14+s])*l,t},t.transformDirectionOffset=function(t,e,i,r,n,s){const o=e[0+n],a=e[1+n],c=e[2+n];t[0+r]=i[0+s]*o+i[4+s]*a+i[8+s]*c,t[1+r]=i[1+s]*o+i[5+s]*a+i[9+s]*c,t[2+r]=i[2+s]*o+i[6+s]*a+i[10+s]*c;const l=Math.hypot(t[0+r],t[1+r],t[2+r]);return l>0&&(t[0+r]/=l,t[1+r]/=l,t[2+r]/=l),t},t.transformMat3=function(t,e,i){const r=e[0],n=e[1],s=e[2];return t[0]=r*i[0]+n*i[3]+s*i[6],t[1]=r*i[1]+n*i[4]+s*i[7],t[2]=r*i[2]+n*i[5]+s*i[8],t},t.transformQuat=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=i[0],a=i[1],c=i[2],l=i[3],h=l*r+a*s-c*n,u=l*n+c*r-o*s,d=l*s+o*n-a*r,m=-o*r-a*n-c*s;return t[0]=h*l+m*-o+u*-c-d*-a,t[1]=u*l+m*-a+d*-o-h*-c,t[2]=d*l+m*-c+h*-a-u*-o,t},t.angle=f;const p=e(),g=e(),y=e(),b=e(),_=e(),x=e(),v=e();t.dihedralAngle=function(t,e,i,r){s(p,t,e),s(g,i,e),s(y,e,i),s(b,r,i),d(_,p,g),d(x,y,b);const n=f(_,x);return d(v,_,x),u(g,v)>0?n:-n},t.directionFromSpherical=function(e,i,r,n){return t.set(e,n*Math.cos(r)*Math.sin(i),n*Math.sin(r)*Math.sin(i),n*Math.cos(i))},t.exactEquals=function(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]},t.equals=function(t,e){const i=t[0],r=t[1],n=t[2],s=e[0],o=e[1],a=e[2];return Math.abs(i-s)<=jd*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(r-o)<=jd*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(n-a)<=jd*Math.max(1,Math.abs(n),Math.abs(a))};const w=e();t.makeRotation=function(e,i,r){const n=f(i,r);if(Math.abs(n)<1e-4)return Qd.setIdentity(e);if(Math.abs(n-Math.PI)0?r(t,e):l(t,r(t,e)),t};const P=e(),I=e();t.triangleNormal=function(t,e,i,r){return s(P,i,e),s(I,r,e),h(t,d(t,P,I))},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)} ${t[2].toPrecision(e)}]`},t.origin=i(0,0,0),t.unit=i(1,1,1),t.negUnit=i(-1,-1,-1),t.unitX=i(1,0,0),t.unitY=i(0,1,0),t.unitZ=i(0,0,1),t.negUnitX=i(-1,0,0),t.negUnitY=i(0,-1,0),t.negUnitZ=i(0,0,-1)}(Yd||(Yd={}));const Kd=Math.PI/180;function Zd(t){return t*Kd}function Qd(){return Qd.zero()}function Jd(){return Jd.zero()}function tm(){return tm.zero()}function em(){return em.zero()}function im(t){throw new Error("unreachable")}function rm(){return rm.zero()}var nm,sm,om,am;function cm(t,e,i){let r=e,n=0,s=1;for(45===t.charCodeAt(r)?(s=-1,++r):43===t.charCodeAt(r)&&++r;r9||e<0)return s*n|0;n=10*n+e|0}return s*n}function lm(t,e,i,r){return 43===e.charCodeAt(i)&&i++,t*Math.pow(10,cm(e,i,r))}function hm(t,e,i){let r=e,n=1,s=0,o=0,a=1;for(45===t.charCodeAt(r)?(n=-1,++r):43===t.charCodeAt(r)&&++r;r=0&&e<10)){if(-2===e){for(++r;r=0&&e<10))return 53===e||21===e?lm(n*(s+o/a),t,r+1,i):n*(s+o/a);o=10*o+e,a*=10,++r}return n*(s+o/a)}if(53===e||21===e)return lm(n*s,t,r+1,i);break}s=10*s+e,++r}return n*s}function um(t,e,i,r){return{schema:i,__array:void 0,isDefined:0===r,rowCount:e,value:e=>t,valueKind:t=>r,toArray:i=>{const{array:r}=Nd(e,i);for(let e=0,i=r.length;e!0}}function dm({value:t,valueKind:e,areValuesEqual:i,rowCount:r,schema:n}){return{schema:n,__array:void 0,isDefined:!0,rowCount:r,value:t,valueKind:e||(t=>0),toArray:e=>{const{array:i,start:n}=Nd(r,e);for(let e=0,r=i.length;et(e)===t(i))}}function mm({array:t,schema:e,valueKind:i}){const r=t.length,n=e.T,s="str"===e.valueType?"lowercase"===e.transform?e=>{const i=t[e];return"string"==typeof i?i.toLowerCase():`${null!=i?i:n}`.toLowerCase()}:"uppercase"===e.transform?e=>{const i=t[e];return"string"==typeof i?i.toUpperCase():`${null!=i?i:n}`.toUpperCase()}:e=>{const i=t[e];return"string"==typeof i?i:`${null!=i?i:n}`}:e=>t[e],o=Ud(t);return{schema:e,__array:t,isDefined:!0,rowCount:r,value:s,valueKind:i||(t=>0),toArray:"str"===e.valueType?"lowercase"===e.transform?e=>{const{start:i,end:s}=Ld(r,e),o=new(e&&void 0!==e.array?e.array:t.constructor)(s-i);for(let e=0,r=s-i;e{const{start:i,end:s}=Ld(r,e),o=new(e&&void 0!==e.array?e.array:t.constructor)(s-i);for(let e=0,r=s-i;e{const{start:i,end:s}=Ld(r,e),o=new(e&&void 0!==e.array?e.array:t.constructor)(s-i);for(let e=0,r=s-i;eVd(t,e):e=>{const{start:i,end:n}=Ld(r,e);if(0===i&&n===t.length)return t;const s=new(e&&void 0!==e.array?e.array:t.constructor)(n-i);for(let e=0,r=n-i;et[e]===t[i]}}function fm(t,e,i){return t.isDefined?0===e&&i===t.rowCount?t:t.__array&&Ud(t.__array)?function(t,e,i){const r=Vd(t.__array,{start:e,end:i}),n=t.valueKind;return mm({array:r,schema:t.schema,valueKind:t=>n(e+t)})}(t,e,i):function(t,e,i){const r=t.value,n=t.valueKind,s=t.areValuesEqual,o=0===e?r:t=>r(t+e),a=i-e;return{schema:t.schema,__array:void 0,isDefined:t.isDefined,rowCount:a,value:o,valueKind:0===e?n:t=>n(t+e),toArray:t=>{const{array:i}=Nd(a,t);for(let t=0,n=i.length;ts(t+e,i+e)}}(t,e,i):sm.Undefined(i-e,t.schema)}function pm(t,e,i){return 0===t.rowCount||i&&function(t,e){if(t.length!==e)return!1;for(let e=0,i=t.length;en(e[t])})}(t,e):function(t,e){const i=t.value,r=t.valueKind,n=t.areValuesEqual,s=t=>i(e[t]),o=e.length;return{schema:t.schema,__array:void 0,isDefined:t.isDefined,rowCount:o,value:s,valueKind:t=>r(e[t]),toArray:t=>{const{array:r}=Nd(o,t);for(let t=0,n=r.length;tn(e[t],e[i])}}(t,e)}function gm(t,e,i){return t[e]-t[i]}function ym(t,e,i){const r=t[e];t[e]=t[i],t[i]=r}function bm(t,e,i,r){const n=i+r>>1;return e(t,i,r)>0?e(t,i,n)>0?e(t,n,r)>0?n:r:i:e(t,r,n)>0?e(t,n,i)>0?n:i:r}function _m(t,e,i){const{cmp:r,swap:n,data:s,parts:o}=t;let a=e+1,c=i;for(n(s,e,bm(s,r,e,i));r(s,c,e)>0;)--c;for(let t=e+1;t<=c;t++){const i=r(s,t,e);if(i>0){for(n(s,t,c),--c;r(s,c,e)>0;)--c;t--}else 0===i&&(n(s,t,a),a++)}for(let t=e;t=r&&e(t,n,n+1)>0;)i(t,n,n+1),n-=1}}function vm(t,e,i){const{parts:r}=t;for(;eo;)--s;for(let e=i+1;e<=s;e++){const i=t[e];if(i>o){for(ym(t,e,s),--s;t[s]>o;)--s;e--}else i===o&&(ym(t,e,n),++n)}for(let e=i;e=e&&t[n]>i;)t[n+1]=t[n],n-=1;t[n+1]=i}}function Sm(t,e,i,r){for(;ii)return!1;return!0}function a(t,e,i,r){t[4*i+e]=r}function c(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 l(t,e){const i=e[0]+e[5]+e[10];let r=0;return i>0?(r=2*Math.sqrt(i+1),t[3]=.25*r,t[0]=(e[6]-e[9])/r,t[1]=(e[8]-e[2])/r,t[2]=(e[1]-e[4])/r):e[0]>e[5]&&e[0]>e[10]?(r=2*Math.sqrt(1+e[0]-e[5]-e[10]),t[3]=(e[6]-e[9])/r,t[0]=.25*r,t[1]=(e[1]+e[4])/r,t[2]=(e[8]+e[2])/r):e[5]>e[10]?(r=2*Math.sqrt(1+e[5]-e[0]-e[10]),t[3]=(e[8]-e[2])/r,t[0]=(e[1]+e[4])/r,t[1]=.25*r,t[2]=(e[6]+e[9])/r):(r=2*Math.sqrt(1+e[10]-e[0]-e[5]),t[3]=(e[1]-e[4])/r,t[0]=(e[8]+e[2])/r,t[1]=(e[6]+e[9])/r,t[2]=.25*r),t}function h(t,e){const i=e[0],r=e[1],n=e[2],s=e[3],o=e[4],a=e[5],c=e[6],l=e[7],h=e[8],u=e[9],d=e[10],m=e[11],f=e[12],p=e[13],g=e[14],y=e[15],b=i*a-r*o,_=i*c-n*o,x=i*l-s*o,v=r*c-n*a,w=r*l-s*a,A=n*l-s*c,S=h*p-u*f,C=h*g-d*f,P=h*y-m*f,I=u*g-d*p,k=u*y-m*p,M=d*y-m*g;let T=b*M-_*k+x*I+v*P-w*C+A*S;return!!T&&(T=1/T,t[0]=(a*M-c*k+l*I)*T,t[1]=(n*k-r*M-s*I)*T,t[2]=(p*A-g*w+y*v)*T,t[3]=(d*w-u*A-m*v)*T,t[4]=(c*P-o*M-l*C)*T,t[5]=(i*M-n*P+s*C)*T,t[6]=(g*x-f*A-y*_)*T,t[7]=(h*A-d*x+m*_)*T,t[8]=(o*k-a*P+l*S)*T,t[9]=(r*P-i*k-s*S)*T,t[10]=(f*w-p*x+y*b)*T,t[11]=(u*x-h*w-m*b)*T,t[12]=(a*C-o*I-c*S)*T,t[13]=(i*I-r*C+n*S)*T,t[14]=(p*_-f*v-g*b)*T,t[15]=(h*v-u*_+d*b)*T,!0)}function u(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3],a=e[4],c=e[5],l=e[6],h=e[7],u=e[8],d=e[9],m=e[10],f=e[11],p=e[12],g=e[13],y=e[14],b=e[15];let _=i[0],x=i[1],v=i[2],w=i[3];return t[0]=_*r+x*a+v*u+w*p,t[1]=_*n+x*c+v*d+w*g,t[2]=_*s+x*l+v*m+w*y,t[3]=_*o+x*h+v*f+w*b,_=i[4],x=i[5],v=i[6],w=i[7],t[4]=_*r+x*a+v*u+w*p,t[5]=_*n+x*c+v*d+w*g,t[6]=_*s+x*l+v*m+w*y,t[7]=_*o+x*h+v*f+w*b,_=i[8],x=i[9],v=i[10],w=i[11],t[8]=_*r+x*a+v*u+w*p,t[9]=_*n+x*c+v*d+w*g,t[10]=_*s+x*l+v*m+w*y,t[11]=_*o+x*h+v*f+w*b,_=i[12],x=i[13],v=i[14],w=i[15],t[12]=_*r+x*a+v*u+w*p,t[13]=_*n+x*c+v*d+w*g,t[14]=_*s+x*l+v*m+w*y,t[15]=_*o+x*h+v*f+w*b,t}function d(t,e,i){let n=i[0],s=i[1],o=i[2],a=Math.sqrt(n*n+s*s+o*o);if(Math.abs(a)0&&(m=1/Math.sqrt(m),h*=m,u*=m,d*=m);let f=c*d-l*u,p=l*h-a*d,g=a*u-c*h;return m=f*f+p*p+g*g,m>0&&(m=1/Math.sqrt(m),f*=m,p*=m,g*=m),t[0]=f,t[1]=p,t[2]=g,t[3]=0,t[4]=u*g-d*p,t[5]=d*f-h*g,t[6]=h*p-u*f,t[7]=0,t[8]=h,t[9]=u,t[10]=d,t[11]=0,t[12]=n,t[13]=s,t[14]=o,t[15]=1,t},t.fromPermutation=function(t,e){n(t);for(let i=0;i<4;i++){a(t,i,e[i],1)}return t},t.getMaxScaleOnAxis=function(t){const e=t[0]*t[0]+t[1]*t[1]+t[2]*t[2],i=t[4]*t[4]+t[5]*t[5]+t[6]*t[6],r=t[8]*t[8]+t[9]*t[9]+t[10]*t[10];return Math.sqrt(Math.max(e,i,r))};const g=[1,0,0],y=[0,1,0],b=[0,0,1];t.rotX90=d(e(),Zd(90),g),t.rotX180=d(e(),Zd(180),g),t.rotY90=d(e(),Zd(90),y),t.rotY180=d(e(),Zd(180),y),t.rotY270=d(e(),Zd(270),y),t.rotZ90=d(e(),Zd(90),b),t.rotZ180=d(e(),Zd(180),b),t.rotXY90=u(e(),t.rotX90,t.rotY90),t.rotZY90=u(e(),t.rotZ90,t.rotY90),t.rotZYZ90=u(e(),t.rotZY90,t.rotZ90),t.rotZ90X180=u(e(),t.rotZ90,t.rotX180),t.rotY90Z180=u(e(),t.rotY90,t.rotZ180),t.id=i()}(Qd||(Qd={})),function(t){function e(){const t=[.1,0,0,0,0,0,0,0,0];return t[0]=0,t}function i(){const t=e();return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function r(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}t.zero=e,t.identity=i,t.setIdentity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e[i+3]=t[3],e[i+4]=t[4],e[i+5]=t[5],e[i+6]=t[6],e[i+7]=t[7],e[i+8]=t[8],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=e[i+3],t[4]=e[i+4],t[5]=e[i+5],t[6]=e[i+6],t[7]=e[i+7],t[8]=e[i+8],t},t.fromColumns=function(t,e,i,r){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=i[0],t[4]=i[1],t[5]=i[2],t[6]=r[0],t[7]=r[1],t[8]=r[2],t},t.fromMat4=r;const n=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];t.fromEuler=function(t,e,i){return Qd.fromEuler(n,e,i),r(t,n)},t.create=function(t,i,r,n,s,o,a,c,l){const h=e();return h[0]=t,h[1]=i,h[2]=r,h[3]=n,h[4]=s,h[5]=o,h[6]=a,h[7]=c,h[8]=l,h};const s=i();function o(t,e,i){for(let r=0;r<9;r++)if(Math.abs(t[r]-e[r])>i)return!1;return!0}function a(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}function c(t,e){if(t===e){const i=e[1],r=e[2],n=e[5];t[1]=e[3],t[2]=e[6],t[3]=i,t[5]=e[7],t[6]=r,t[7]=n}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8];return t}function l(t,e){const i=e[0],r=e[1],n=e[2],s=e[3],o=e[4],a=e[5],c=e[6],l=e[7],h=e[8],u=h*o-a*l,d=-h*s+a*c,m=l*s-o*c;let f=i*u+r*d+n*m;return f?(f=1/f,t[0]=u*f,t[1]=(-h*r+n*l)*f,t[2]=(a*r-n*o)*f,t[3]=d*f,t[4]=(h*i-n*c)*f,t[5]=(-a*i+n*s)*f,t[6]=m*f,t[7]=(-l*i+r*c)*f,t[8]=(o*i-r*s)*f,t):(console.warn("non-invertible matrix.",e),t)}function h(t){const e=t[0],i=t[1],r=t[2],n=t[3],s=t[4],o=t[5],a=t[6],c=t[7],l=t[8];return e*(l*s-o*c)+i*(-l*n+o*a)+r*(c*n-s*a)}function u(t){return t[0]+t[4]+t[8]}function d(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[4]=e[4]-i[4],t[5]=e[5]-i[5],t[6]=e[6]-i[6],t[7]=e[7]-i[7],t[8]=e[8]-i[8],t}function m(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}t.isIdentity=function(t,e){return o(t,s,void 0===e?jd:e)},t.hasNaN=function(t){for(let e=0;e<9;e++)if(isNaN(t[e]))return!0;return!1},t.clone=function(t){return a(e(),t)},t.areEqual=o,t.setValue=function(t,e,i,r){t[3*i+e]=r},t.getValue=function(t,e,i){return t[3*i+e]},t.copy=a,t.transpose=c,t.invert=l,t.symmtricFromUpper=function(t,e){return t===e?(t[3]=e[1],t[6]=e[2],t[7]=e[5]):(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[1],t[4]=e[4],t[5]=e[5],t[6]=e[2],t[7]=e[5],t[8]=e[8]),t},t.symmtricFromLower=function(t,e){return t===e?(t[1]=e[3],t[2]=e[6],t[5]=e[7]):(t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[3],t[4]=e[4],t[5]=e[7],t[6]=e[6],t[7]=e[7],t[8]=e[8]),t},t.determinant=h,t.trace=u,t.sub=d,t.add=function(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[4]=e[4]+i[4],t[5]=e[5]+i[5],t[6]=e[6]+i[6],t[7]=e[7]+i[7],t[8]=e[8]+i[8],t},t.mul=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3],a=e[4],c=e[5],l=e[6],h=e[7],u=e[8],d=i[0],m=i[1],f=i[2],p=i[3],g=i[4],y=i[5],b=i[6],_=i[7],x=i[8];return t[0]=d*r+m*o+f*l,t[1]=d*n+m*a+f*h,t[2]=d*s+m*c+f*u,t[3]=p*r+g*o+y*l,t[4]=p*n+g*a+y*h,t[5]=p*s+g*c+y*u,t[6]=b*r+_*o+x*l,t[7]=b*n+_*a+x*h,t[8]=b*s+_*c+x*u,t},t.subScalar=function(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},t.addScalar=function(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},t.mulScalar=m;const f=Math.PI/3,p=e();t.symmetricEigenvalues=function(e,i){const r=i[1]*i[1]+i[2]*i[2]+i[5]*i[5];if(0===r)e[0]=i[0],e[1]=i[4],e[2]=i[8];else{const n=u(i)/3,s=i[0]-n,o=i[4]-n,a=i[8]-n,c=s*s+o*o+a*a+2*r,l=Math.sqrt(c/6);m(p,t.Identity,n),d(p,i,p),m(p,p,1/l);const g=h(p)/2,y=g<=-1?f:g>=1?0:Math.acos(g)/3;e[0]=n+2*l*Math.cos(y),e[2]=n+2*l*Math.cos(y+2*f),e[1]=3*n-e[0]-e[2]}return e};const g=[.1,0,0],y=[.1,0,0],b=[.1,0,0],_=[.1,0,0],x=[.1,0,0],v=[.1,0,0];t.eigenvector=function(t,e,i){Yd.set(g,e[0]-i,e[1],e[2]),Yd.set(y,e[1],e[4]-i,e[5]),Yd.set(b,e[2],e[5],e[8]-i),Yd.cross(_,g,y),Yd.cross(x,g,b),Yd.cross(v,y,b);const r=Yd.dot(_,_),n=Yd.dot(x,x),s=Yd.dot(v,v);let o=r,a=0;return n>o&&(o=n,a=1),s>o&&(a=2),0===a?Yd.scale(t,_,1/Math.sqrt(r)):1===a?Yd.scale(t,x,1/Math.sqrt(n)):Yd.scale(t,v,1/Math.sqrt(s)),t},t.directionTransform=function(t,e){return r(t,e),l(t,t),c(t,t),t},t.Identity=i(),t.innerProduct=function(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]}}(Jd||(Jd={})),function(t){function e(){const t=[.1,0];return t[0]=0,t}t.zero=e,t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i},t.create=function(t,i){const r=e();return r[0]=t,r[1]=i,r},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t},t.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t},t.set=function(t,e,i){return t[0]=e,t[1]=i,t},t.add=function(t,e,i){return t[0]=e[0]+i[0],t[1]=e[1]+i[1],t},t.sub=function(t,e,i){return t[0]=e[0]-i[0],t[1]=e[1]-i[1],t},t.mul=function(t,e,i){return t[0]=e[0]*i[0],t[1]=e[1]*i[1],t},t.div=function(t,e,i){return t[0]=e[0]/i[0],t[1]=e[1]/i[1],t},t.scale=function(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t},t.round=function(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t},t.ceil=function(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t},t.floor=function(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t},t.distance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1];return Math.sqrt(i*i+r*r)},t.squaredDistance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1];return i*i+r*r},t.magnitude=function(t){const e=t[0],i=t[1];return Math.sqrt(e*e+i*i)},t.squaredMagnitude=function(t){const e=t[0],i=t[1];return e*e+i*i},t.inverse=function(t,e){return t[0]=1/e[0],t[1]=1/e[1],t},t.areEqual=function(t,e){return t[0]===e[0]&&t[1]===e[1]},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)}}]`}}(tm||(tm={})),function(t){function e(){const t=[.1,0,0,0];return t[0]=0,t}function i(t,e){return t[0]=e.center[0],t[1]=e.center[1],t[2]=e.center[2],t[3]=e.radius,t}t.zero=e,t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i[3]=t[3],i},t.create=function(t,i,r,n){const s=e();return s[0]=t,s[1]=i,s[2]=r,s[3]=n,s},t.fromSphere=i,t.ofSphere=function(t){return i(e(),t)},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])||isNaN(t[2])||isNaN(t[3])},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e[i+3]=t[3],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=e[i+3],t},t.toVec3Array=function(t,e,i){e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2]},t.fromVec3Array=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=0,t},t.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},t.set=function(t,e,i,r,n){return t[0]=e,t[1]=i,t[2]=r,t[3]=n,t},t.add=function(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},t.distance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2],s=e[3]-t[3];return Math.sqrt(i*i+r*r+n*n+s*s)},t.scale=function(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i,t[4]=e[4]*i,t},t.round=function(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t[3]=Math.round(e[3]),t},t.ceil=function(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t[3]=Math.ceil(e[3]),t},t.floor=function(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t[3]=Math.floor(e[3]),t},t.squaredDistance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2],s=e[3]-t[3];return i*i+r*r+n*n+s*s},t.norm=function(t){const e=t[0],i=t[1],r=t[2],n=t[3];return Math.sqrt(e*e+i*i+r*r+n*n)},t.squaredNorm=function(t){const e=t[0],i=t[1],r=t[2],n=t[3];return e*e+i*i+r*r+n*n},t.transformMat4=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3];return t[0]=i[0]*r+i[4]*n+i[8]*s+i[12]*o,t[1]=i[1]*r+i[5]*n+i[9]*s+i[13]*o,t[2]=i[2]*r+i[6]*n+i[10]*s+i[14]*o,t[3]=i[3]*r+i[7]*n+i[11]*s+i[15]*o,t},t.dot=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]},t.inverse=function(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t[3]=1/e[3],t},t.exactEquals=function(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]},t.equals=function(t,e){const i=t[0],r=t[1],n=t[2],s=t[3],o=e[0],a=e[1],c=e[2],l=e[3];return Math.abs(i-o)<=jd*Math.max(1,Math.abs(i),Math.abs(o))&&Math.abs(r-a)<=jd*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(n-c)<=jd*Math.max(1,Math.abs(n),Math.abs(c))&&Math.abs(s-l)<=jd*Math.max(1,Math.abs(s),Math.abs(l))},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)} ${t[2].toPrecision(e)} ${t[3].toPrecision(e)}]`}}(em||(em={})),function(t){function e(){const t=[.1,0,0,0];return t[0]=0,t}function i(){const t=e();return t[3]=1,t}function r(t,e,i){i*=.5;const r=Math.sin(i);return t[0]=r*e[0],t[1]=r*e[1],t[2]=r*e[2],t[3]=Math.cos(i),t}function n(t,e,i,r){const n=e[0],s=e[1],o=e[2],a=e[3];let c,l,h,u,d,m=i[0],f=i[1],p=i[2],g=i[3];return l=n*m+s*f+o*p+a*g,l<0&&(l=-l,m=-m,f=-f,p=-p,g=-g),1-l>1e-6?(c=Math.acos(l),h=Math.sin(c),u=Math.sin((1-r)*c)/h,d=Math.sin(r*c)/h):(u=1-r,d=r),t[0]=u*n+d*m,t[1]=u*s+d*f,t[2]=u*o+d*p,t[3]=u*a+d*g,t}function s(t,e){const i=e[0]+e[4]+e[8];let r;if(i>0)r=Math.sqrt(i+1),t[3]=.5*r,r=.5/r,t[0]=(e[5]-e[7])*r,t[1]=(e[6]-e[2])*r,t[2]=(e[1]-e[3])*r;else{let i=0;e[4]>e[0]&&(i=1),e[8]>e[3*i+i]&&(i=2);const n=(i+1)%3,s=(i+2)%3;r=Math.sqrt(e[3*i+i]-e[3*n+n]-e[3*s+s]+1),t[i]=.5*r,r=.5/r,t[3]=(e[3*n+s]-e[3*s+n])*r,t[n]=(e[3*n+i]+e[3*i+n])*r,t[s]=(e[3*s+i]+e[3*i+s])*r}return t}t.zero=e,t.identity=i,t.setIdentity=function(t){t[0]=0,t[1]=0,t[2]=0,t[3]=1},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])||isNaN(t[2])||isNaN(t[3])},t.create=function(t,e,r,n){const s=i();return s[0]=t,s[1]=e,s[2]=r,s[3]=n,s},t.setAxisAngle=r,t.getAxisAngle=function(t,e){const i=2*Math.acos(e[3]),r=Math.sin(i/2);return 0!==r?(t[0]=e[0]/r,t[1]=e[1]/r,t[2]=e[2]/r):(t[0]=1,t[1]=0,t[2]=0),i},t.multiply=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3],a=i[0],c=i[1],l=i[2],h=i[3];return t[0]=r*h+o*a+n*l-s*c,t[1]=n*h+o*c+s*a-r*l,t[2]=s*h+o*l+r*c-n*a,t[3]=o*h-r*a-n*c-s*l,t},t.rotateX=function(t,e,i){i*=.5;const r=e[0],n=e[1],s=e[2],o=e[3],a=Math.sin(i),c=Math.cos(i);return t[0]=r*c+o*a,t[1]=n*c+s*a,t[2]=s*c-n*a,t[3]=o*c-r*a,t},t.rotateY=function(t,e,i){i*=.5;const r=e[0],n=e[1],s=e[2],o=e[3],a=Math.sin(i),c=Math.cos(i);return t[0]=r*c-s*a,t[1]=n*c+o*a,t[2]=s*c+r*a,t[3]=o*c-n*a,t},t.rotateZ=function(t,e,i){i*=.5;const r=e[0],n=e[1],s=e[2],o=e[3],a=Math.sin(i),c=Math.cos(i);return t[0]=r*c+n*a,t[1]=n*c-r*a,t[2]=s*c+o*a,t[3]=o*c-s*a,t},t.calculateW=function(t,e){const i=e[0],r=e[1],n=e[2];return t[0]=i,t[1]=r,t[2]=n,t[3]=Math.sqrt(Math.abs(1-i*i-r*r-n*n)),t},t.slerp=n,t.invert=function(t,e){const i=e[0],r=e[1],n=e[2],s=e[3],o=i*i+r*r+n*n+s*s,a=o?1/o:0;return t[0]=-i*a,t[1]=-r*a,t[2]=-n*a,t[3]=s*a,t},t.conjugate=function(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t},t.dot=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]},t.fromMat3=s,t.fromEuler=function(t,e,i){const[r,n,s]=e,o=Math.cos(r/2),a=Math.cos(n/2),c=Math.cos(s/2),l=Math.sin(r/2),h=Math.sin(n/2),u=Math.sin(s/2);switch(i){case"XYZ":t[0]=l*a*c+o*h*u,t[1]=o*h*c-l*a*u,t[2]=o*a*u+l*h*c,t[3]=o*a*c-l*h*u;break;case"YXZ":t[0]=l*a*c+o*h*u,t[1]=o*h*c-l*a*u,t[2]=o*a*u-l*h*c,t[3]=o*a*c+l*h*u;break;case"ZXY":t[0]=l*a*c-o*h*u,t[1]=o*h*c+l*a*u,t[2]=o*a*u+l*h*c,t[3]=o*a*c-l*h*u;break;case"ZYX":t[0]=l*a*c-o*h*u,t[1]=o*h*c+l*a*u,t[2]=o*a*u-l*h*c,t[3]=o*a*c+l*h*u;break;case"YZX":t[0]=l*a*c+o*h*u,t[1]=o*h*c+l*a*u,t[2]=o*a*u-l*h*c,t[3]=o*a*c-l*h*u;break;case"XZY":t[0]=l*a*c-o*h*u,t[1]=o*h*c-l*a*u,t[2]=o*a*u+l*h*c,t[3]=o*a*c+l*h*u;break;default:im()}return t};const o=[0,0,0];function a(t,e){const i=e[0],r=e[1],n=e[2],s=e[3];let o=i*i+r*r+n*n+s*s;return o>0&&(o=1/Math.sqrt(o),t[0]=i*o,t[1]=r*o,t[2]=n*o,t[3]=s*o),t}t.fromUnitVec3=function(t,e,i){let r=Yd.dot(e,i)+1;return rMath.abs(e[2])?Yd.set(o,-e[1],e[0],0):Yd.set(o,0,-e[2],e[1])):Yd.cross(o,e,i),t[0]=o[0],t[1]=o[1],t[2]=o[2],t[3]=r,a(t,t),t},t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i[3]=t[3],i},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e[i+3]=t[3],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=e[i+3],t},t.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},t.set=function(t,e,i,r,n){return t[0]=e,t[1]=i,t[2]=r,t[3]=n,t},t.exactEquals=function(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]},t.equals=function(t,e){const i=t[0],r=t[1],n=t[2],s=t[3],o=e[0],a=e[1],c=e[2],l=e[3];return Math.abs(i-o)<=jd*Math.max(1,Math.abs(i),Math.abs(o))&&Math.abs(r-a)<=jd*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(n-c)<=jd*Math.max(1,Math.abs(n),Math.abs(c))&&Math.abs(s-l)<=jd*Math.max(1,Math.abs(s),Math.abs(l))},t.add=function(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},t.normalize=a;const c=[0,0,0],l=[1,0,0],h=[0,1,0];t.rotationTo=function(t,e,i){const n=Yd.dot(e,i);return n<-.999999?(Yd.cross(c,l,e),Yd.magnitude(c)<1e-6&&Yd.cross(c,h,e),Yd.normalize(c,c),r(t,c,Math.PI),t):n>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(Yd.cross(c,e,i),t[0]=c[0],t[1]=c[1],t[2]=c[2],t[3]=1+n,a(t,t))};const u=e(),d=e();t.sqlerp=function(t,e,i,r,s,o){return n(u,e,s,o),n(d,i,r,o),n(t,u,d,2*o*(1-o)),t};const m=[0,0,0,0,0,0,0,0,0];t.setAxes=function(t,e,i,r){return m[0]=i[0],m[3]=i[1],m[6]=i[2],m[1]=r[0],m[4]=r[1],m[7]=r[2],m[2]=-e[0],m[5]=-e[1],m[8]=-e[2],a(t,s(t,m))},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)} ${t[2].toPrecision(e)} ${t[3].toPrecision(e)}]`},t.Identity=i()}(rm||(rm={})),function(t){function e(t,e,n){const s=function(t,e,i){const r=[];for(let t=0;tt[e],set:(t,e,i)=>t[e]=i,add:(t,e,i)=>t[e]+=i,dataOffset:t=>t,getCoords:(t,e)=>(e[0]=t,e)};case 2:if(0===i[0]&&1===i[1]){const t=e[0];return{get:(e,i,r)=>e[r*t+i],set:(e,i,r,n)=>e[r*t+i]=n,add:(e,i,r,n)=>e[r*t+i]+=n,dataOffset:(e,i)=>i*t+e,getCoords:(e,i)=>(i[0]=e%t,i[1]=Math.floor(e/t),i)}}if(1===i[0]&&0===i[1]){const t=e[1];return{get:(e,i,r)=>e[i*t+r],set:(e,i,r,n)=>e[i*t+r]=n,add:(e,i,r,n)=>e[i*t+r]+=n,dataOffset:(e,i)=>e*t+i,getCoords:(e,i)=>(i[0]=Math.floor(e/t),i[1]=e%t,i)}}throw new Error("bad axis order");case 3:if(0===i[0]&&1===i[1]&&2===i[2]){const t=e[0],i=e[1],r=t*i;return{get:(e,i,n,s)=>e[i+n*t+s*r],set:(e,i,n,s,o)=>e[i+n*t+s*r]=o,add:(e,i,n,s,o)=>e[i+n*t+s*r]+=o,dataOffset:(e,i,n)=>e+i*t+n*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=e%t,r[1]=n%i,r[2]=Math.floor(n/i),r}}}if(0===i[0]&&2===i[1]&&1===i[2]){const t=e[0],i=e[2],r=t*i;return{get:(e,i,n,s)=>e[i+s*t+n*r],set:(e,i,n,s,o)=>e[i+s*t+n*r]=o,add:(e,i,n,s,o)=>e[i+s*t+n*r]+=o,dataOffset:(e,i,n)=>e+n*t+i*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=e%t,r[1]=Math.floor(n/i),r[2]=n%i,r}}}if(1===i[0]&&0===i[1]&&2===i[2]){const t=e[1],i=e[0],r=t*i;return{get:(e,i,n,s)=>e[n+i*t+s*r],set:(e,i,n,s,o)=>e[n+i*t+s*r]=o,add:(e,i,n,s,o)=>e[n+i*t+s*r]+=o,dataOffset:(e,i,n)=>i+e*t+n*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=n%i,r[1]=e%t,r[2]=Math.floor(n/i),r}}}if(1===i[0]&&2===i[1]&&0===i[2]){const t=e[1],i=e[2],r=t*i;return{get:(e,i,n,s)=>e[n+s*t+i*r],set:(e,i,n,s,o)=>e[n+s*t+i*r]=o,add:(e,i,n,s,o)=>e[n+s*t+i*r]+=o,dataOffset:(e,i,n)=>i+n*t+e*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=Math.floor(n/i),r[1]=e%t,r[2]=n%i,r}}}if(2===i[0]&&0===i[1]&&1===i[2]){const t=e[2],i=e[0],r=t*i;return{get:(e,i,n,s)=>e[s+i*t+n*r],set:(e,i,n,s,o)=>e[s+i*t+n*r]=o,add:(e,i,n,s,o)=>e[s+i*t+n*r]+=o,dataOffset:(e,i,n)=>n+e*t+i*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=n%i,r[1]=Math.floor(n/i),r[2]=e%t,r}}}if(2===i[0]&&1===i[1]&&0===i[2]){const t=e[2],i=e[1],r=t*i;return{get:(e,i,n,s)=>e[s+n*t+i*r],set:(e,i,n,s,o)=>e[s+n*t+i*r]=o,add:(e,i,n,s,o)=>e[s+n*t+i*r]+=o,dataOffset:(e,i,n)=>n+i*t+e*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=Math.floor(n/i),r[1]=n%i,r[2]=e%t,r}}}throw new Error("bad axis order");default:return{get:(e,...i)=>e[n(t,i)],set:(e,...i)=>e[n(t,i)]=i[i.length-1],add:(e,...i)=>e[n(t,i)]+=i[i.length-1],dataOffset:(...e)=>n(t,e),getCoords:(e,i)=>function(t,e,i){const{dimensions:r,axisOrderFastToSlow:n}=t,s=r.length;let o=e;for(let t=0;tnew(e||t.defaultCtor)(i)}function n(t,e){const{accessDimensions:i,axisOrderFastToSlow:r}=t,n=i.length-1;let s=i[n]*e[r[n]];for(let t=n-1;t>=0;t--)s=(s+e[r[t]])*i[t];return s}function s(t,e){const i=[];for(let r=0;rs(t,e)},t.convertToCanonicalAxisIndicesSlowToFast=function(t){const e=new Int32Array(t.length);for(let i=0;is(t,e)}}(nm||(nm={})),function(t){let e;function i(t,e){return um(e.T,t,e,1)}function r(t){return dm(t)}!function(t){function e(e,i=t.float){return{"@type":"tensor",T:e.create(),space:e,valueType:"tensor",baseType:i}}t.str={"@type":"str",T:"",valueType:"str"},t.ustr={"@type":"str",T:"",valueType:"str",transform:"uppercase"},t.lstr={"@type":"str",T:"",valueType:"str",transform:"lowercase"},t.int={"@type":"int",T:0,valueType:"int"},t.coord={"@type":"coord",T:0,valueType:"float"},t.float={"@type":"float",T:0,valueType:"float"},t.Str=function(t){var e;return{"@type":"str",T:null!==(e=null==t?void 0:t.defaultValue)&&void 0!==e?e:"",transform:null==t?void 0:t.transform,valueType:"str"}},t.Int=function(t=0){return{"@type":"int",T:t,valueType:"int"}},t.Float=function(t=0){return{"@type":"float",T:t,valueType:"float"}},t.Tensor=e,t.Vector=function(i,r=t.float){return e(nm.Vector(i,"int"===r["@type"]?Int32Array:Float64Array),r)},t.Matrix=function(i,r,n=t.float){return e(nm.ColumnMajorMatrix(i,r,"int"===n["@type"]?Int32Array:Float64Array),n)},t.Aliased=function(t){return t},t.List=function(t,e,i=[]){return{"@type":"list",T:i,separator:t,itemParse:e,valueType:"list"}}}(e=t.Schema||(t.Schema={})),t.is=function(t){return!!t&&!!t.schema&&!!t.value},t.ValueKind={Present:0,NotPresent:1,Unknown:2},t.Undefined=i,t.ofConst=function(t,e,i){return um(t,e,i,0)},t.ofLambda=r,t.range=function(t,i){return r({value:e=>e+t,rowCount:Math.max(i-t+1,0),schema:e.int})},t.ofArray=function(t){return mm(t)},t.ofIntArray=function(t){return mm({array:t,schema:e.int})},t.ofFloatArray=function(t){return mm({array:t,schema:e.float})},t.ofStringArray=function(t){return mm({array:t,schema:e.str})},t.ofStringAliasArray=function(t){return mm({array:t,schema:e.Aliased(e.str)})},t.ofStringListArray=function(t,i=","){return mm({array:t,schema:e.List(i,(t=>t))})},t.ofIntTokens=function(t){const{count:i,data:r,indices:n}=t;return dm({value:t=>cm(r,n[2*t],n[2*t+1])||0,rowCount:i,schema:e.int})},t.ofFloatTokens=function(t){const{count:i,data:r,indices:n}=t;return dm({value:t=>hm(r,n[2*t],n[2*t+1])||0,rowCount:i,schema:e.float})},t.ofStringTokens=function(t){const{count:i,data:r,indices:n}=t;return dm({value:t=>{const e=r.substring(n[2*t],n[2*t+1]);return"."===e||"?"===e?"":e},rowCount:i,schema:e.str})},t.window=function(t,e,i){return fm(t,e,i)},t.view=function(t,e,i=!0){return pm(t,e,i)},t.createFirstIndexMap=function(t){return function(t){const e=new Map;for(let i=0,r=t.rowCount;ie.has(t)?e.get(t):-1}(t)},t.mapToArray=function(t,e,i){return function(t,e,i){const r=new i(t.rowCount);for(let i=0,n=t.rowCount;i0&&(t.chunks[t.chunks.length]=t.current.length===t.offset?t.current.join(""):t.current.slice(0,t.offset).join("")),t.chunks.join("")):t.current.length===t.offset?t.current.join(""):t.current.splice(0,t.offset).join("")},t.getSize=function(t){let e=0;for(const i of t.chunks)e+=i.length;for(let i=0;i0&&(t.current.length===t.offset?t.chunks[t.chunks.length]=t.current.join(""):t.chunks[t.chunks.length]=t.current.slice(0,t.offset).join(""),t.offset=0),t.chunks};const e=[];function i(t,i){i>0&&r(t,e[i])}function r(t,e){t.offset===t.capacity&&(t.chunks[t.chunks.length]=t.current.join(""),t.offset=0),t.current[t.offset++]=e}!function(){let t="";for(let i=0;i<512;i++)e[i]=t,t+=" "}(),t.newline=function(t){r(t,"\n")},t.whitespace=i,t.whitespace1=function(t){r(t," ")},t.write=function(t,e){e&&(t.offset===t.capacity&&(t.chunks[t.chunks.length]=t.current.join(""),t.offset=0),t.current[t.offset++]=e)},t.writeSafe=r,t.writePadLeft=function(t,e,n){if(!e)return void i(t,n);i(t,n-e.length),r(t,e)},t.writePadRight=function(t,e,n){if(!e)return void i(t,n);const s=n-e.length;r(t,e),i(t,s)},t.writeInteger=function(t,e){r(t,""+e)},t.writeIntegerAndSpace=function(t,e){r(t,e+" ")},t.writeIntegerPadLeft=function(t,e,n){const s=""+e;i(t,n-s.length),r(t,s)},t.writeIntegerPadRight=function(t,e,n){const s=""+e,o=n-s.length;r(t,s),i(t,o)},t.writeFloat=function(t,e,i){r(t,""+Math.round(i*e)/i)},t.writeFloatPadLeft=function(t,e,n,s){const o=""+Math.round(n*e)/n;i(t,s-o.length),r(t,o)},t.writeFloatPadRight=function(t,e,n,s){const o=""+Math.round(n*e)/n,a=s-o.length;r(t,o),i(t,a)}}(am||(am={}));const Pm=function(){if("undefined"!=typeof window&&window.performance){const t=window.performance;return()=>t.now()}return"undefined"!=typeof process&&"undefined"!==process.hrtime&&"function"==typeof process.hrtime?()=>{const t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:Date.now?()=>Date.now():()=>+new Date}();var Im,km,Mm;function Tm(t,e){return t-e}function Dm(t=0,e=Number.MAX_SAFE_INTEGER){let i=t;return()=>{const t=i;return i=(i+1)%e,t}}!function(t){const e="undefined"!=typeof btoa?btoa:t=>Buffer.from(t).toString("base64"),i=[];t.create22=function(){let t=+new Date+Pm();for(let e=0;e<16;e++)i[e]=String.fromCharCode((t+255*Math.random())%255|0),t=Math.floor(t/255);return e(i.join("")).replace(/\+/g,"-").replace(/\//g,"_").substr(0,22)},t.createv4=function(){let t=+new Date+Pm();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){const i=(t+16*Math.random())%16|0;return t=Math.floor(t/16),("x"===e?i:3&i|8).toString(16)}))},t.is=function(t){return"string"==typeof t}}(Im||(Im={})),function(t){class e{has(t){return!1}forEach(t,e){return e}constructor(){this.size=0}}class i{has(t){return t===this.idx}forEach(t,e){return t(this.idx,e),e}constructor(t){this.idx=t,this.size=1}}class r{has(t){return tt[e++]=i)),function(t){Array.prototype.sort.call(t,Tm)}(t),this._flat=t,this._flat}forEach(t,e){return this._forEach(t,e),e}constructor(t){this.set=t,this._flat=void 0,this.size=t.size}}function o(t){return new s(t)}function a(t,e){return new r(t,e)}t.always=function(t){return new n(t)},t.never=new e,t.ofSet=o,t.singleton=function(t){return new i(t)},t.ofUniqueIndices=function(t){const o=t.length;if(0===o)return new e;if(1===o)return new i(t[0]);let a=0;for(const e of t)e>a&&(a=e);if(o===a)return new n(o);if(o/a<1/12){const e=new Set;for(const i of t)e.add(i);return new s(e)}const c=new Int8Array(a+1);for(const e of t)c[e]=1;return new r(c,t.length)},t.ofMask=a,t.hasAny=function(t,e){for(const i of e)if(t.has(i))return!0;return!1},t.complement=function(t,e){let i=0,r=0;if(e.forEach((e=>{t.has(e)||(i++,e>r&&(r=e))})),i/r<1/12){const i=new Set;return e.forEach((e=>{t.has(e)||i.add(e)})),o(i)}{const n=new Uint8Array(r+1);return e.forEach((e=>{t.has(e)||(n[e]=1)})),a(n,i)}}}(km||(km={})),function(t){t.create=function(t){return{ref:t}},t.set=function(t,e){return t.ref=e,t}}(Mm||(Mm={}));const Bm=Dm(0,2147483647);var Fm,Em,$m,Om,Rm;function Lm(t){const{data:e,indices:i}=t;return function(t,r){const n=i[2*t],s=i[2*r],o=i[2*t+1]-n;if(o!==i[2*r+1]-s)return!1;for(let t=0;tr[t]}}!function(t){t.create=function(t,e){return{id:Bm(),version:0,value:t,metadata:e}},t.withValue=function(t,e){return{id:t.id,version:t.version+1,value:e,metadata:t.metadata}}}(Fm||(Fm={})),function(t){function e(t,e){return Mm.set(t,Fm.withValue(t.ref,e))}t.create=function(t,e){return Mm.create(Fm.create(t,e))},t.update=e,t.set=function(t,e){return Mm.set(t,e)},t.updateIfChanged=function(t,i){return t.ref.value!==i?e(t,i):t}}(Em||(Em={})),function(t){function e(t,e,i){const r=Object.create(null),n=Object.keys(e);r._rowCount=i.length,r._columns=n,r._schema=e;for(const e of n)r[e]=sm.view(t[e],i);return r}function i(t,e){const i=Object.create(null),{_columns:r}=t;for(let n=0;ne[t][s],valueKind:t=>void 0===e[t][s]?1:0});return i},t.ofArrays=function(t,e){var i;const r=Object.create(null),n=Object.keys(t);r._rowCount=0,r._columns=n,r._schema=t;for(const s of n)void 0!==e[s]?(r[s]=sm.ofArray({array:e[s],schema:t[s]}),r._rowCount=null===(i=e[s])||void 0===i?void 0:i.length):r[s]=sm.Undefined(r._rowCount,t[s]);return r},t.view=e,t.pick=function(t,i,r){const n=[];for(let e=0,i=t._rowCount;ee(i,r)));let r=!0;for(let t=0,e=i.length;t0?e[i[0]].rowCount:0,name:t,fieldNames:i,getField:t=>e[t]}}t.empty=function(t){return{rowCount:0,name:t,fieldNames:[],getField(t){}}},t.ofFields=e,t.ofTable=function(t,i){const r={};for(const t of i._columns)r[t]=Rm.ofColumn(i[t]);return e(t,r)}}(Um||(Um={})),function(t){function e(t){const e=t.length,i=e=>{const i=t[e];return i&&"."!==i&&"?"!==i?i:""},r=e=>{const i=t[e];return cm(i,0,i.length)||0},n=e=>{const i=t[e];return hm(i,0,i.length)||0};return{__array:void 0,binaryEncoding:void 0,isDefined:!0,rowCount:e,str:i,int:r,float:n,valueKind:e=>{const i=t[e],r=i.length;if(r>1)return 0;if(0===r)return 1;const n=i.charCodeAt(0);return 46===n?1:63===n?2:0},areValuesEqual:(e,i)=>t[e]===t[i],toStringArray:r=>r?zd(e,i,r):t,toIntArray:t=>zd(e,r,t),toFloatArray:t=>zd(e,n,t)}}function i(t){const{rowCount:e,valueKind:i,areValuesEqual:r,isDefined:n}=t;let s,o,a;switch(t.schema.valueType){case"float":case"int":s=e=>""+t.value(e),o=t.value,a=t.value;break;case"str":s=t.value,o=e=>{const i=t.value(e);return cm(i,0,i.length)||0},a=e=>{const i=t.value(e);return hm(i,0,i.length)||0};break;case"list":const{separator:e}=t.schema;s=i=>t.value(i).join(e),o=t=>NaN,a=t=>NaN;break;default:throw new Error(`unsupported valueType '${t.schema.valueType}'`)}return{__array:void 0,binaryEncoding:void 0,isDefined:n,rowCount:e,str:s,int:o,float:a,valueKind:i,areValuesEqual:r,toStringArray:t=>zd(e,s,t),toIntArray:t=>zd(e,o,t),toFloatArray:t=>zd(e,a,t)}}t.ofString=function(t){return e([t])},t.ofStrings=e,t.ofNumbers=function(t){const e=t.length,i=e=>""+t[e],r=e=>t[e],n=i=>!i||i.array&&t instanceof i.array?t:zd(e,r,i);return{__array:void 0,binaryEncoding:void 0,isDefined:!0,rowCount:e,str:i,int:r,float:r,valueKind:t=>0,areValuesEqual:(e,i)=>t[e]===t[i],toStringArray:t=>zd(e,i,t),toIntArray:n,toFloatArray:n}},t.ofTokens=function(t){const{data:e,indices:i,count:r}=t,n=t=>{const r=e.substring(i[2*t],i[2*t+1]);return"."===r||"?"===r?"":r},s=t=>cm(e,i[2*t],i[2*t+1])||0,o=t=>hm(e,i[2*t],i[2*t+1])||0;return{__array:void 0,binaryEncoding:void 0,isDefined:!0,rowCount:r,str:n,int:s,float:o,valueKind:t=>{const r=i[2*t],n=i[2*t+1]-r;if(n>1)return 0;if(0===n)return 1;const s=e.charCodeAt(r);return 46===s?1:63===s?2:0},areValuesEqual:Lm(t),toStringArray:t=>zd(r,n,t),toIntArray:t=>zd(r,s,t),toFloatArray:t=>zd(r,o,t)}},t.ofColumn=i,t.ofUndefined=function(t,e){return i(sm.Undefined(t,e))}}(Rm||(Rm={}));const Vm="undefined"!=typeof setImmediate?"undefined"!=typeof window?{setImmediate:(t,...e)=>window.setImmediate(t,...e),clearImmediate:t=>window.clearImmediate(t)}:{setImmediate:setImmediate,clearImmediate:clearImmediate}:function(){const t=function(){const t="undefined"!=typeof window&&window,e="undefined"!=typeof self&&"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&self,i="undefined"!=typeof global&&global;return t||i||e}(),e={},i="undefined"!=typeof document?document:void 0;let r,n=1;function s(t){delete e[t]}function o(t){const i=e[t];s(t),function(t){const e=t.callback,i=t.args;switch(i.length){case 0:e();break;case 1:e(i[0]);break;case 2:e(i[0],i[1]);break;case 3:e(i[0],i[1],i[2]);break;default:e.apply(void 0,i)}}(i)}return"undefined"!=typeof process&&"[object process]"==={}.toString.call(process)?r=function(t){process.nextTick((function(){o(t)}))}:function(){if(t&&t.postMessage&&!t.importScripts){let e=!0;const i=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=i,e}}()?function(){const e="setImmediate$"+Math.random()+"$",i=function(i){i.source===t&&"string"==typeof i.data&&0===i.data.indexOf(e)&&o(+i.data.slice(e.length))};window.addEventListener?window.addEventListener("message",i,!1):window.attachEvent("onmessage",i),r=function(t){window.postMessage(e+t,"*")}}():"undefined"!=typeof MessageChannel?function(){const t=new MessageChannel;t.port1.onmessage=function(t){o(t.data)},r=function(e){t.port2.postMessage(e)}}():i&&"onreadystatechange"in i.createElement("script")?function(){const t=i.documentElement;r=function(e){let r=i.createElement("script");r.onreadystatechange=function(){o(e),r.onreadystatechange=null,t.removeChild(r),r=null},t.appendChild(r)}}():r=function(t){setTimeout(o,0,t)},{setImmediate:function(t,...i){"function"!=typeof t&&(t=new Function(""+t));const s={callback:t,args:i};return e[n]=s,r(n),n++},clearImmediate:s}}();function jm(t){Vm.setImmediate(t)}const Gm={setImmediate:Vm.setImmediate,clearImmediate:Vm.clearImmediate,immediatePromise:()=>new Promise(jm),delay:(t,e=void 0)=>new Promise((i=>setTimeout(i,t,e)))};!function(){try{return"production"===process.env.NODE_ENV}catch(t){return!1}}(),function(){try{const t=process.env.DEBUG;return"*"===t||"molstar"===t}catch(t){return!1}}();const Hm="undefined"!=typeof performance&&!!performance.mark&&performance.measure&&!1;var qm;function Wm(t,e,i=250){const r=function(t,e,i){const r={abortRequested:!1,treeAborted:!1,reason:""};return{updateRateMs:i,lastNotified:Pm(),observer:e,abortToken:r,taskId:t.id,root:{progress:Xm(t),children:[]},tryAbort:Ym(r)}}(t,e,i);return Qm(t,new rf(r,r.root))}function Xm(t){return{taskId:t.id,taskName:t.name,message:"",startedTime:0,canAbort:!0,isIndeterminate:!0,current:0,max:0}}function Ym(t){return e=>{t.abortRequested=!0,t.reason=e||t.reason}}function Km(t){return{progress:{...t.progress},children:t.children.map(Km)}}function Zm(t){return t.progress.canAbort&&t.children.every(Zm)}async function Qm(t,e){qm.markStart(t),e.node.progress.startedTime=Pm();try{const i=await t.f(e);return qm.markEnd(t),qm.measure(t),e.info.abortToken.abortRequested&&Jm(e.info),i}catch(i){throw sf.isAbort(i)&&(e.isAborted=!0,e.node.children.length>0&&await new Promise((t=>{e.onChildrenFinished=t})),t.onAbort&&t.onAbort()),i}}function Jm(t){throw t.abortToken.treeAborted||(t.abortToken.treeAborted=!0,tf(t.root),ef(t,Pm())),sf.Aborted(t.abortToken.reason)}function tf(t){const e=t.progress;e.isIndeterminate=!0,e.canAbort=!1,e.message="Aborting...";for(const e of t.children)tf(e)}function ef(t,e){t.lastNotified=e;const i=function(t){return{root:Km(t.root),canAbort:Zm(t.root),requestAbort:t.tryAbort}}(t);t.observer(i)}!function(t){function e(t){return`startTask${t.id}`}function i(t){return`endTask${t.id}`}t.markStart=function(t){Hm&&performance.mark(e(t))},t.markEnd=function(t){Hm&&performance.mark(i(t))},t.measure=function(t){Hm&&performance.measure(`✳️ ${t.name}`,e(t),i(t))}}(qm||(qm={}));class rf{checkAborted(){this.info.abortToken.abortRequested&&(this.isAborted=!0,Jm(this.info))}get shouldUpdate(){return this.checkAborted(),Pm()-this.lastUpdatedTime>this.info.updateRateMs}updateProgress(t){if(this.checkAborted(),!t)return;const e=this.node.progress;"string"==typeof t?(e.message=t,e.isIndeterminate=!0):(void 0!==t.canAbort&&(e.canAbort=t.canAbort),void 0!==t.message&&(e.message=t.message),void 0!==t.current&&(e.current=t.current),void 0!==t.max&&(e.max=t.max),e.isIndeterminate=void 0===e.current||void 0===e.max,void 0!==t.isIndeterminate&&(e.isIndeterminate=t.isIndeterminate))}update(t,e){if(this.lastUpdatedTime=Pm(),this.updateProgress(t),!e)return ef(this.info,this.lastUpdatedTime),this.checkAborted(),Gm.immediatePromise()}async runChild(t,e){this.updateProgress(e);const i={progress:Xm(t),children:[]},r=this.node.children;r.push(i);const n=new rf(this.info,i);try{return await Qm(t,n)}catch(t){if(sf.isAbort(t)&&this.isAborted)return;throw t}finally{const t=r.indexOf(i);if(t>=0){for(let e=t,i=r.length-1;e0;){o+=l;const e=Pm()-c;h+=e,a+=e,t.shouldUpdate&&(await n(t,i,o),s=Math.round(h*o/a)+1,c=Pm(),h=0)}return t.shouldUpdate&&await n(t,i,o),i}function df(t){return{data:t,position:0,length:t.length,lineNumber:1,tokenStart:0,tokenEnd:0}}function mf(t){for(;t.position=t.length)return void(t.tokenType=6);t.tokenStart=t.position,t.tokenEnd=t.position,t.isEscaped=!1;const i=t.data.charCodeAt(t.position);switch(i){case 35:!function(t){for(;t.position=5&&95===t.data.charCodeAt(t.tokenStart+4)?!function(t){let e=t.data.charCodeAt(t.tokenStart);return!(68!==e&&100!==e||(e=t.data.charCodeAt(t.tokenStart+1),65!==e&&97!==e||(e=t.data.charCodeAt(t.tokenStart+2),84!==e&&116!==e||(e=t.data.charCodeAt(t.tokenStart+3),65!==e&&97!==e))))}(t)?!function(t){let e=t.data.charCodeAt(t.tokenStart);return!(83!==e&&115!==e||(e=t.data.charCodeAt(t.tokenStart+1),65!==e&&97!==e||(e=t.data.charCodeAt(t.tokenStart+2),86!==e&&118!==e||(e=t.data.charCodeAt(t.tokenStart+3),69!==e&&101!==e))))}(t)?!function(t){if(t.tokenEnd-t.tokenStart!=5)return!1;let e=t.data.charCodeAt(t.tokenStart);return!(76!==e&&108!==e||(e=t.data.charCodeAt(t.tokenStart+1),79!==e&&111!==e||(e=t.data.charCodeAt(t.tokenStart+2),79!==e&&111!==e||(e=t.data.charCodeAt(t.tokenStart+3),80!==e&&112!==e))))}(t)?t.tokenType=3:t.tokenType=2:t.tokenType=1:t.tokenType=0:t.tokenType=3}}function xf(t){for(_f(t);5===t.tokenType;)_f(t)}function vf(){return{categoryNames:[],categoryData:Object.create(null)}}function wf(t,e){const i=Object.create(null);for(const r of t){const t=e[r];i[r]=Um(t.name,t.rowCount,t.fieldNames,t.fields)}return i}function Af(t,e,i){return zm(t.categoryNames,wf(t.categoryNames,t.categoryData),e,i)}function Sf(t,e){return zm(t.categoryNames,wf(t.categoryNames,t.categoryData),e)}function Cf(t,e,i,r,n){if(e in t.categoryData){const i=t.categoryData[e];i.fieldNames.push(...r),Object.assign(i.fields,n)}else t.categoryData[e]={name:e,rowCount:i,fieldNames:r,fields:n},t.categoryNames.push(e)}function Pf(t,e){const i=t.tokenStart,r=gf(t),n=yf(t,r),s=Object.create(null),o=[];let a=!0;for(;a;){if(4!==t.tokenType||!pf(t,i,r)){a=!1;break}const e=bf(t).substring(n.length+1);if(xf(t),3!==t.tokenType)return{hasError:!0,errorLine:t.lineNumber,errorMessage:"Expected value."};s[e]=Rm.ofTokens({data:t.data,indices:[t.tokenStart,t.tokenEnd],count:1}),o[o.length]=e,xf(t)}return Cf(e,n.substr(1),1,o,s),{hasError:!1,errorLine:0,errorMessage:""}}function If(t,e){const{tokenizer:i,tokens:r,fieldCount:n}=e;let s=e.tokenCount,o=0;for(;3===i.tokenType&&o0&&i.push(Af(s,n,o)),n=t.substring(r.tokenStart+5,r.tokenEnd),s=vf(),o=[],xf(r)}else if(1===e){if(r.tokenEnd-r.tokenStart==5)a.categoryNames.length>0&&(o[o.length]=Sf(a,l)),r.inSaveFrame=!1;else{if(r.inSaveFrame)return Tf(r.lineNumber,"Save frames cannot be nested.");r.inSaveFrame=!0,l=t.substring(r.tokenStart+5,r.tokenEnd),a=vf()}xf(r)}else if(2===e){const t=await Mf(r,r.inSaveFrame?a:s);if(t.hasError)return Tf(t.errorLine,t.errorMessage)}else{if(4!==e)return console.log(r.tokenType,df.getTokenString(r)),Tf(r.lineNumber,"Unexpected token. Expected data_, loop_, or data name.");{const t=Pf(r,r.inSaveFrame?a:s);if(t.hasError)return Tf(t.errorLine,t.errorMessage)}}}return r.inSaveFrame?Tf(r.lineNumber,`Unfinished save frame (${c.header}).`):((s.categoryNames.length>0||o.length>0)&&i.push(Af(s,n,o)),function(t){return lf.success(t)}(Nm(i)))}function Bf(t){return sf.create("Parse CIF",(async e=>await Df(t,e)))}!function(t){class e{run(t,e=250){return t?Wm(this,t,e):this.f(nf)}runAsChild(t,e){return t.isSynchronous?this.f(nf):function(t,e,i){return t.runChild(e,i)}(t,this,e)}runInContext(t){return t.isSynchronous?this.f(nf):function(t,e){return Qm(e,t)}(t,this)}constructor(t,e,i){this.name=t,this.f=e,this.onAbort=i,this.id=n()}}function i(t){const e=t;return!!t&&"number"==typeof e.id&&"string"==typeof e.name&&!!e.run}function r(t,i,r){return new e(t,i,r)}t.is=i,t.isAbort=function(t){return!!t&&!!t.isAborted},t.Aborted=function(t){return{isAborted:!0,reason:t,toString:()=>"Aborted"+(t?": "+t:"")}},t.create=r,t.constant=function(t,e){return r(t,(async t=>e))},t.empty=function(){return r("",(async t=>{}))},t.fail=function(t,e){return r(t,(async t=>{throw new Error(e)}))},t.resolveInContext=function(t,e){return i(t)?e?t.runInContext(e):t.run():t};const n=Dm(0,1073741823)}(sf||(sf={})),function(t){t.Synchronous=nf}(of||(of={})),function(t){function e(t,i=""){const r=t.progress;if(!t.children.length)return r.isIndeterminate?`${i}${r.taskName}: ${r.message}`:`${i}${r.taskName}: [${r.current}/${r.max}] ${r.message}`;const n=i+" |_ ",s=t.children.map((t=>e(t,n)));return r.isIndeterminate?`${i}${r.taskName}: ${r.message}\n${s.join("\n")}`:`${i}${r.taskName}: [${r.current}/${r.max}] ${r.message}\n${s.join("\n")}`}t.format=function(t){return e(t.root)}}(af||(af={})),function(t){function e(t){return t.data.substring(t.tokenStart,t.tokenEnd)}function i(t){const{data:e}=t;for(;t.position=n;)o=r.charCodeAt(--s);return t.tokenStart=n,t.tokenEnd=s+1,t.position=i,t}t.getTokenString=e,t.reset=function(t){t.position=0,t.lineNumber=1,t.tokenStart=0,t.tokenEnd=0},t.eatLine=i,t.markStart=function(t){t.tokenStart=t.position},t.markLine=r,t.readLine=function(t){return r(t),e(t)},t.readLineTrim=function(t){r(t);const i=t.position;return s(t,t.tokenStart,t.tokenEnd),t.position=i,e(t)},t.markLines=function(t,e){const i=cf.create(t.data,2*e);return n(t,e,i),i},t.readLines=function(e,i){const r=[];for(let n=0;n{const r=Math.min(e-o,t);return n(i,r,s),o+=r,r}),((t,e)=>t.update({message:"Parsing...",current:e.position,max:e.length}))),s},t.readAllLines=function(e){const i=t(e),n=cf.create(i.data,Math.max(e.length/80,2));for(;r(i);)cf.add(n,i.tokenStart,i.tokenEnd);return n},t.readAllLinesAsync=async function(e,i,n=1e5){const s=t(e),o=cf.create(s.data,Math.max(e.length/80,2));return await uf(i,n,s,((t,e)=>(function(t,e,i){let n=0;for(let s=0;st.update({message:"Parsing...",current:e.position,max:e.length}))),o},t.eatValue=function(t){for(;t.positionr.indicesLenMinus2&&function(t){const e=new Uint32Array(1.61*t.indices.length|0);e.set(t.indices),t.indices=e,t.indicesLenMinus2=e.length-2|0}(r),r.indices[r.offset++]=e,r.indices[r.offset++]=i,t.count++}t.add=e,t.addToken=function(t,i){e(t,i.tokenStart,i.tokenEnd)},t.addUnchecked=function(t,e,i){t.indices[t.offset++]=e,t.indices[t.offset++]=i,t.count++},t.create=function(t,e){return{data:t,indicesLenMinus2:(e=Math.max(10,e))-2|0,count:0,offset:0,indices:new Uint32Array(e)}}}(cf||(cf={})),function(t){t.error=function(t,i=-1){return new e(t,i)},t.success=function(t,e=[]){return new i(t,e)};class e{toString(){return this.line>=0?`[Line ${this.line}] ${this.message}`:this.message}constructor(t,e){this.message=t,this.line=e,this.isError=!0}}t.Error=e;class i{constructor(t,e){this.result=t,this.warnings=e,this.isError=!1}}t.Success=i}(lf||(lf={})),function(t){var e,i;(e=t.IntDataType||(t.IntDataType={}))[e.Int8=1]="Int8",e[e.Int16=2]="Int16",e[e.Int32=3]="Int32",e[e.Uint8=4]="Uint8",e[e.Uint16=5]="Uint16",e[e.Uint32=6]="Uint32",(i=t.FloatDataType||(t.FloatDataType={}))[i.Float32=32]="Float32",i[i.Float64=33]="Float64",t.getDataType=function(e){let i;return i=e instanceof Int8Array?t.IntDataType.Int8:e instanceof Int16Array?t.IntDataType.Int16:e instanceof Int32Array?t.IntDataType.Int32:e instanceof Uint8Array?t.IntDataType.Uint8:e instanceof Uint16Array?t.IntDataType.Uint16:e instanceof Uint32Array?t.IntDataType.Uint32:e instanceof Float32Array?t.FloatDataType.Float32:e instanceof Float64Array?t.FloatDataType.Float64:t.IntDataType.Int32,i},t.isSignedIntegerDataType=function(t){if(t instanceof Int8Array||t instanceof Int16Array||t instanceof Int32Array)return!0;for(let e=0,i=t.length;e=0;i--)e=$f(e,t.encoding[i]);return e}function $f(t,e){switch(e.kind){case"ByteArray":switch(e.type){case hf.IntDataType.Uint8:return t;case hf.IntDataType.Int8:return function(t){return new Int8Array(t.buffer,t.byteOffset)}(t);case hf.IntDataType.Int16:return function(t){return Lf(t,2,Int16Array)}(t);case hf.IntDataType.Uint16:return function(t){return Lf(t,2,Uint16Array)}(t);case hf.IntDataType.Int32:return function(t){return Lf(t,4,Int32Array)}(t);case hf.IntDataType.Uint32:return function(t){return Lf(t,4,Uint32Array)}(t);case hf.FloatDataType.Float32:return function(t){return Lf(t,4,Float32Array)}(t);case hf.FloatDataType.Float64:return function(t){return Lf(t,8,Float64Array)}(t);default:im(e.type)}case"FixedPoint":return function(t,e){const i=t.length,r=Rf(e.srcType,i),n=1/e.factor;for(let e=0;e=t.currentSize)o.set(c,a);else for(let t=0,e=c.length;t=t.currentSize&&e(t);const o=t.currentChunk,a=t.currentIndex;return o[a]=i,o[a+1]=r,o[a+2]=n,o[a+3]=s,t.currentIndex+=4,t.elementCount++},t.add3=function(t,i,r,n){t.currentIndex>=t.currentSize&&e(t);const s=t.currentChunk,o=t.currentIndex;return s[o]=i,s[o+1]=r,s[o+2]=n,t.currentIndex+=3,t.elementCount++},t.add2=function(t,i,r){t.currentIndex>=t.currentSize&&e(t);const n=t.currentChunk,s=t.currentIndex;return n[s]=i,n[s+1]=r,t.currentIndex+=2,t.elementCount++},t.add=function(t,i){return t.currentIndex>=t.currentSize&&e(t),t.currentChunk[t.currentIndex]=i,t.currentIndex+=1,t.elementCount++},t.addRepeat=function(t,i,r){for(let n=0;n=t.currentSize&&e(t),t.currentChunk[t.currentIndex++]=r,t.elementCount++;return t.elementCount},t.addMany=function(t,i){const{elementSize:r}=t;for(let n=0,s=i.length;n=t.currentSize&&e(t);const{currentChunk:s}=t;for(let e=0;e=0?Math.ceil((t+1)/e):Math.ceil((t+1)/(-e-1))}function i({limit8:t,limit16:i},r,n){r.pack8+=e(n,t),r.pack16+=e(n,i),r.count+=1}function r(t,i){t.pack8+=e(i,127),t.pack16+=e(i,32767),t.count+=1}function n(t){return 4*t.count<2*t.pack16?{length:4*t.count,elem:4}:2*t.pack16t.length-e.length)),i}t.getSize=l,t.classify=function(t){if(t.length<2)return jf.by(jf.byteArray);switch(l(t)[0].kind){case"pack":return jf.by(jf.integerPacking);case"rle":return jf.by(jf.runLength).and(jf.integerPacking);case"delta":return jf.by(jf.delta).and(jf.integerPacking);case"delta-rle":return jf.by(jf.delta).and(jf.runLength).and(jf.integerPacking);default:im()}}}(zf||(zf={})),function(t){t.classify=function(t){const{mantissaDigits:e,integerDigits:i}=function(t,e,i){let r=1,n=0;for(let s=0,o=t.length;s=0){const n=Gf(t[s],e,i);n<0?r=-1:n>r&&(r=n)}const o=Math.abs(t[s]);if(o>i){const t=Math.floor(Math.log10(Math.abs(o)))+1;t>n&&(n=t)}}return{mantissaDigits:r,integerDigits:n}}(t,4,1e-6);if(e<0||e+i>10)return jf.by(jf.byteArray);if(0===e)return zf.classify(t);const r=function(t){let e=1;for(let i=0;i=0?s/e|0:s/i|0}return r+=t.length,r}t.byteArray=r,t.fixedPoint=function(t){return e=>function(t,e){const i=hf.getDataType(t),r=new Int32Array(t.length);for(let i=0,n=t.length;ifunction(t,e,i,r,n){const s=hf.getDataType(t);if(!t.length)return{encodings:[{kind:"IntervalQuantization",min:e,max:i,numSteps:r,srcType:s}],data:new Int32Array(0)};if(i=i?r-1:0|Math.round((s-e)/o)}return{encodings:[{kind:"IntervalQuantization",min:e,max:i,numSteps:r,srcType:s}],data:a}}(n,t,e,i,r)},t.runLength=function(t){let e=hf.getDataType(t);if(void 0===e&&(t=new Int32Array(t),e=hf.IntDataType.Int32),!t.length)return{encodings:[{kind:"RunLength",srcType:e,srcSize:0}],data:new Int32Array(0)};let i=2;for(let e=1,r=t.length;e=0)for(;r>=i;)o[a]=i,++a,r-=i;else for(;r<=n;)o[a]=n,++a,r-=n;o[a]=r,++a}const c=r(o);return{encodings:[{kind:"IntegerPacking",byteCount:e.bytesPerElement,isUnsigned:!e.isSigned,srcSize:s},c.encodings[0]],data:c.data}}(t,e)},t.stringArray=function(t){const e=Object.create(null),i=[],r=new Int32Array(t.length),n=Nf.create(Int32Array,1,Math.min(1024,t.length<32?t.length+1:Math.round(t.length/8)+1));Nf.add(n,0);let s=0,o=0;for(const a of t){if(null==a){r[o++]=-1;continue}let t=e[a];void 0===t&&(s+=a.length,t=i.length,i[t]=a,e[a]=t,Nf.add(n,s)),r[o++]=t}const a=Nf.compact(n),c=Hf(a).encode(a),l=Hf(r).encode(r);return{encodings:[{kind:"StringArray",dataEncoding:l.encoding,stringData:i.join(""),offsetEncoding:c.encoding,offsets:c.data}],data:l.data}}}(jf||(jf={}));const Wf=function(){const t=[];for(let e=0;e<1024;e++)t[e]=String.fromCharCode(e);return t}();function Xf(t){throw new Error(t)}const Yf="undefined"!=typeof TextDecoder?new TextDecoder:void 0;function Kf(t,e,i){if(Yf){const r=e||i!==t.length?t.subarray(e,e+i):t;return Yf.decode(r)}return function(t,e,i){const r=Wf;let n,s=0;const o=[];for(let a=e,c=e+i;a0&&(n[n.length]=o.slice(0,s).join("")),n.join("")):o.slice(0,s).join("")}(t,e,i)}function Zf(t,e){const i={};for(let r=0;rt.name)),getField(t){const r=e[t];if(r)return i[t]||(i[t]=function(t){const e=t.mask?Ef(t.mask):void 0,i=Ef(t.data),r=Ud(i),n=r?e?t=>0===e[t]?""+i[t]:"":t=>""+i[t]:e?t=>0===e[t]?i[t]:"":t=>i[t],s=r?t=>i[t]:t=>{const e=i[t];return cm(e,0,e.length)},o=r?t=>i[t]:t=>{const e=i[t];return hm(e,0,e.length)},a=e?t=>e[t]:t=>0,c=i.length;return{__array:i,binaryEncoding:t.data.encoding,isDefined:!0,rowCount:c,str:n,int:s,float:o,valueKind:a,areValuesEqual:(t,e)=>i[t]===i[e],toStringArray:t=>zd(c,n,t),toIntArray:r?t=>Vd(i,t):t=>zd(c,s,t),toFloatArray:r?t=>Vd(i,t):t=>zd(c,o,t)}}(r)),i[t]}}}function rp(t){return sf.create("Parse BinaryCIF",(async e=>{const i=[0,3];try{const e=ep({buffer:r=t,offset:0,dataView:new DataView(r.buffer)});if(!function(t,e){for(let i=0;i<2;i++)if(t[i]>e[i])return!1;return!0}(i,e.version.match(/(\d)\.(\d)\.\d/).slice(1).map((t=>+t))))return lf.error(`Unsupported format version. Current ${e.version}, required ${i.join(".")}.`);const n=Nm(e.dataBlocks.map((t=>{const e=Object.create(null);for(const i of t.categories)e[i.name.substr(1)]=ip(i);return zm(t.categories.map((t=>t.name.substr(1))),e,t.header)})));return lf.success(n)}catch(t){return lf.error(""+t)}var r}))}var np;function sp(t,e,i){return function(t,e,i){const r=Object.create(null);for(const n of Object.keys(t))r[n]=dp(n,t[n],e,i);return Om.ofTables(e.header,t,r)}(t,e,i)}function op(t){switch(t.valueType){case"str":return(e,i,r)=>function(t,e,i,r){return{schema:t,__array:e.__array,isDefined:e.isDefined,rowCount:e.rowCount,value:"lowercase"===t.transform?t=>i(t).toLowerCase():"uppercase"===t.transform?t=>i(t).toUpperCase():i,valueKind:e.valueKind,areValuesEqual:e.areValuesEqual,toArray:"lowercase"===t.transform?t=>Array.from(r(t)).map((t=>t.toLowerCase())):"uppercase"===t.transform?t=>Array.from(r(t)).map((t=>t.toUpperCase())):r}}(t,e,e.str,e.toStringArray);case"int":return(e,i,r)=>ap(t,e,e.int,e.toIntArray);case"float":return(e,i,r)=>ap(t,e,e.float,e.toFloatArray);case"list":throw new Error("Use createListColumn instead.");case"tensor":throw new Error("Use createTensorColumn instead.")}}function ap(t,e,i,r){return{schema:t,__array:e.__array,isDefined:e.isDefined,rowCount:e.rowCount,value:i,valueKind:e.valueKind,areValuesEqual:e.areValuesEqual,toArray:r}}function cp(t,e,i){const r=t.separator,n=t.itemParse,s=e.getField(i),o=s?t=>s.str(t).split(r).map((t=>n(t.trim()))).filter((t=>!!t)):t=>[];return{schema:t,__array:void 0,isDefined:!!s,rowCount:e.rowCount,value:o,valueKind:s?s.valueKind:()=>1,areValuesEqual:(t,e)=>function(t,e){const i=t.length;if(i!==e.length)return!1;for(let r=0;rzd(e.rowCount,o,t)}}function lp(t,e,i){const r=t.space,n=e.fieldNames.includes(`${i}[0]`)||e.fieldNames.includes(`${i}[0][0]`)||e.fieldNames.includes(`${i}[0][0][0]`),s=n?0:1,o=e.fieldNames.includes(`${i}_1`)||e.fieldNames.includes(`${i}_11`)||e.fieldNames.includes(`${i}_111`)?"underscore":"brackets",a=function(t,e,i,r){const n=i?0:1;switch(e){case 1:return"brackets"===r?e=>`${t}[${e+n}]`:e=>`${t}_${e+n}`;case 2:return"brackets"===r?(e,i)=>`${t}[${e+n}][${i+n}]`:(e,i)=>`${t}_${e+n}${i+n}`;case 3:return"brackets"===r?(e,i,r)=>`${t}[${e+n}][${i+n}][${r+n}]`:(e,i,r)=>`${t}_${e+n}${i+n}${r+n}`;default:throw new Error("Tensors with rank > 3 or rank 0 are currently not supported.")}}(i,r.rank,n,o),c=e.getField(a(s,s,s))||sm.Undefined(e.rowCount,t),l=t=>function(t,e,i,r){const n=e.create();if(1===e.rank){const s=e.dimensions[0];for(let o=0;o 3 or rank 0 are currently not supported.");{const s=e.dimensions[0],o=e.dimensions[1],a=e.dimensions[2];for(let c=0;cnm.areEqualExact(l(t),l(e)),toArray:t=>zd(e.rowCount,l,t)}}!function(t){function e(t){return t.replace(".","_").replace(/\[/,"_").replace(/(\[|\])/g,"")}t.canonical=e,t.equal=function(t,i){return e(t)===e(i)},t.create=function(t,i,r=!1){const n=`${t}${i?`.${i}`:""}`;return r?e(n):n}}(np||(np={}));class hp{constructor(t,e,i){this._isDefined=i;const r=Object.keys(e);this._rowCount=t.rowCount,this._columns=r,this._schema=e;const n=Object.create(null);for(const i of r)Object.defineProperty(this,i,{get:function(){if(n[i])return n[i];const r=e[i];if("list"===r.valueType)n[i]=cp(r,t,i);else if("tensor"===r.valueType)n[i]=lp(r,t,i);else{const e=op(r),s=t.getField(i);n[i]=s?e(s,t,i):sm.Undefined(t.rowCount,r)}return n[i]},enumerable:!0,configurable:!1})}}function up(t,e,i,r){const n=np.create(e,t),s=np.canonical(n);if(s in i)return i[s];if(r&&n in r)for(const t of r[n]){const e=np.canonical(t);if(e in i)return i[e]}}function dp(t,e,i,r){let n=i.categories[t];if(r){const s=function(t){const e=Object.create(null);for(const i of Object.keys(t.categories))for(const r of t.categories[i].fieldNames)e[np.create(i,r,!0)]=t.categories[i].getField(r);return e}(i),o=Object.create(null),a=[];let c=0;for(const i of Object.keys(e)){const e=up(i,t,s,r);e&&(o[i]=e,a.push(i),c=e.rowCount)}n={rowCount:c,name:t,fieldNames:[...a],getField:t=>o[t]}}return new hp(n||Um.empty(t),e,!!n)}var mp=sm.Schema;const fp=mp.str,pp=mp.int,gp=mp.float,yp=mp.coord,bp=mp.Aliased,_p=mp.Matrix,xp=mp.Vector,vp=mp.lstr,wp=mp.List,Ap={atom_site:{auth_asym_id:fp,auth_atom_id:fp,auth_comp_id:fp,auth_seq_id:pp,B_iso_or_equiv:gp,Cartn_x:yp,Cartn_y:yp,Cartn_z:yp,group_PDB:bp(fp),id:pp,label_alt_id:fp,label_asym_id:fp,label_atom_id:fp,label_comp_id:fp,label_entity_id:fp,label_seq_id:pp,occupancy:gp,type_symbol:fp,pdbx_PDB_ins_code:fp,pdbx_PDB_model_num:pp,pdbx_formal_charge:pp,pdbx_label_index:pp,pdbx_sifts_xref_db_name:fp,pdbx_sifts_xref_db_acc:fp,pdbx_sifts_xref_db_num:fp,pdbx_sifts_xref_db_res:fp,ihm_model_id:pp},atom_site_anisotrop:{id:pp,type_symbol:fp,U:_p(3,3),U_esd:_p(3,3),pdbx_auth_seq_id:fp,pdbx_auth_asym_id:fp,pdbx_auth_atom_id:fp,pdbx_auth_comp_id:fp,pdbx_label_seq_id:pp,pdbx_label_alt_id:fp,pdbx_label_asym_id:fp,pdbx_label_atom_id:fp,pdbx_label_comp_id:fp,pdbx_PDB_ins_code:fp},atom_sites:{entry_id:fp,fract_transf_matrix:_p(3,3),fract_transf_vector:xp(3)},audit_author:{name:fp,pdbx_ordinal:pp,identifier_ORCID:fp},audit_conform:{dict_location:fp,dict_name:fp,dict_version:fp},cell:{angle_alpha:gp,angle_beta:gp,angle_gamma:gp,entry_id:fp,length_a:gp,length_b:gp,length_c:gp,Z_PDB:pp,pdbx_unique_axis:fp},chem_comp:{formula:fp,formula_weight:gp,id:fp,mon_nstd_flag:bp(vp),name:fp,type:bp(vp),pdbx_synonyms:wp(";",(t=>t))},chem_comp_bond:{atom_id_1:fp,atom_id_2:fp,comp_id:fp,value_order:bp(vp),pdbx_ordinal:pp,pdbx_stereo_config:bp(vp),pdbx_aromatic_flag:bp(vp)},citation:{book_publisher:fp,country:fp,id:fp,journal_abbrev:fp,journal_id_ASTM:fp,journal_id_CSD:fp,journal_id_ISSN:fp,journal_volume:fp,page_first:fp,page_last:fp,title:fp,year:pp,pdbx_database_id_DOI:fp,pdbx_database_id_PubMed:pp},citation_author:{citation_id:fp,name:fp,ordinal:pp},database_2:{database_id:bp(vp),database_code:fp},entity:{details:fp,formula_weight:gp,id:fp,src_method:bp(vp),type:bp(vp),pdbx_description:wp(",",(t=>t)),pdbx_number_of_molecules:pp,pdbx_mutation:fp,pdbx_fragment:fp,pdbx_ec:wp(",",(t=>t))},entity_poly:{entity_id:fp,nstd_linkage:bp(vp),nstd_monomer:bp(vp),type:bp(fp),pdbx_strand_id:wp(",",(t=>t)),pdbx_seq_one_letter_code:fp,pdbx_seq_one_letter_code_can:fp,pdbx_target_identifier:fp},entity_poly_seq:{entity_id:fp,hetero:bp(vp),mon_id:fp,num:pp},entry:{id:fp},exptl:{entry_id:fp,method:bp(fp)},software:{classification:fp,date:fp,description:fp,name:fp,type:bp(vp),version:fp,pdbx_ordinal:pp},struct:{entry_id:fp,title:fp,pdbx_descriptor:fp},struct_asym:{details:fp,entity_id:fp,id:fp,pdbx_modified:fp,pdbx_blank_PDB_chainid_flag:bp(fp)},struct_conf:{beg_label_asym_id:fp,beg_label_comp_id:fp,beg_label_seq_id:pp,beg_auth_asym_id:fp,beg_auth_comp_id:fp,beg_auth_seq_id:pp,conf_type_id:bp(vp),details:fp,end_label_asym_id:fp,end_label_comp_id:fp,end_label_seq_id:pp,end_auth_asym_id:fp,end_auth_comp_id:fp,end_auth_seq_id:pp,id:fp,pdbx_beg_PDB_ins_code:fp,pdbx_end_PDB_ins_code:fp,pdbx_PDB_helix_class:fp,pdbx_PDB_helix_length:pp,pdbx_PDB_helix_id:fp},struct_conn:{conn_type_id:bp(vp),details:fp,id:fp,ptnr1_label_asym_id:fp,ptnr1_label_atom_id:fp,ptnr1_label_comp_id:fp,ptnr1_label_seq_id:pp,ptnr1_auth_asym_id:fp,ptnr1_auth_comp_id:fp,ptnr1_auth_seq_id:pp,ptnr1_symmetry:fp,ptnr2_label_asym_id:fp,ptnr2_label_atom_id:fp,ptnr2_label_comp_id:fp,ptnr2_label_seq_id:pp,ptnr2_auth_asym_id:fp,ptnr2_auth_comp_id:fp,ptnr2_auth_seq_id:pp,ptnr2_symmetry:fp,pdbx_ptnr1_PDB_ins_code:fp,pdbx_ptnr1_label_alt_id:fp,pdbx_ptnr1_standard_comp_id:fp,pdbx_ptnr2_PDB_ins_code:fp,pdbx_ptnr2_label_alt_id:fp,pdbx_ptnr3_PDB_ins_code:fp,pdbx_ptnr3_label_alt_id:fp,pdbx_ptnr3_label_asym_id:fp,pdbx_ptnr3_label_atom_id:fp,pdbx_ptnr3_label_comp_id:fp,pdbx_ptnr3_label_seq_id:pp,pdbx_PDB_id:fp,pdbx_dist_value:gp,pdbx_value_order:bp(vp)},struct_conn_type:{criteria:fp,id:bp(vp),reference:fp},struct_keywords:{entry_id:fp,text:wp(",",(t=>t)),pdbx_keywords:fp},struct_ncs_oper:{code:bp(fp),details:fp,id:pp,matrix:_p(3,3),vector:xp(3)},struct_sheet_range:{beg_label_asym_id:fp,beg_label_comp_id:fp,beg_label_seq_id:pp,end_label_asym_id:fp,end_label_comp_id:fp,end_label_seq_id:pp,beg_auth_asym_id:fp,beg_auth_comp_id:fp,beg_auth_seq_id:pp,end_auth_asym_id:fp,end_auth_comp_id:fp,end_auth_seq_id:pp,id:fp,sheet_id:fp,pdbx_beg_PDB_ins_code:fp,pdbx_end_PDB_ins_code:fp},struct_site:{details:fp,id:fp,pdbx_num_residues:pp,pdbx_evidence_code:fp,pdbx_auth_asym_id:fp,pdbx_auth_comp_id:fp,pdbx_auth_seq_id:fp,pdbx_auth_ins_code:fp},struct_site_gen:{details:fp,id:fp,label_alt_id:fp,label_asym_id:fp,label_atom_id:fp,label_comp_id:fp,label_seq_id:pp,auth_asym_id:fp,auth_comp_id:fp,auth_seq_id:fp,site_id:fp,symmetry:fp,pdbx_auth_ins_code:fp,pdbx_num_res:pp},symmetry:{entry_id:fp,cell_setting:bp(vp),Int_Tables_number:pp,space_group_name_Hall:fp,"space_group_name_H-M":fp},pdbx_database_status:{status_code:bp(fp),status_code_sf:bp(fp),status_code_mr:bp(fp),entry_id:fp,recvd_initial_deposition_date:fp,SG_entry:bp(vp),deposit_site:bp(fp),process_site:bp(fp),status_code_cs:bp(fp),methods_development_category:bp(fp),pdb_format_compatible:bp(vp)},pdbx_nonpoly_scheme:{asym_id:fp,entity_id:fp,mon_id:fp,pdb_strand_id:fp,ndb_seq_num:fp,pdb_seq_num:fp,auth_seq_num:fp,pdb_mon_id:fp,auth_mon_id:fp,pdb_ins_code:fp},pdbx_database_related:{db_name:fp,details:fp,db_id:fp,content_type:bp(fp)},pdbx_entity_nonpoly:{entity_id:fp,comp_id:fp,name:fp},pdbx_chem_comp_synonyms:{name:fp,comp_id:fp,provenance:bp(fp)},pdbx_chem_comp_identifier:{comp_id:fp,identifier:fp,type:bp(fp),program:fp,program_version:fp},pdbx_unobs_or_zero_occ_residues:{id:pp,polymer_flag:bp(vp),occupancy_flag:bp(pp),PDB_model_num:pp,auth_asym_id:fp,auth_comp_id:fp,auth_seq_id:fp,PDB_ins_code:fp,label_asym_id:fp,label_comp_id:fp,label_seq_id:pp},pdbx_struct_mod_residue:{id:pp,auth_asym_id:fp,auth_comp_id:fp,auth_seq_id:pp,PDB_ins_code:fp,label_asym_id:fp,label_comp_id:fp,label_seq_id:pp,parent_comp_id:fp,details:fp},pdbx_struct_oper_list:{id:fp,type:bp(fp),name:fp,symmetry_operation:fp,matrix:_p(3,3),vector:xp(3)},pdbx_struct_assembly:{method_details:fp,oligomeric_details:fp,oligomeric_count:pp,details:fp,id:fp},pdbx_struct_assembly_gen:{asym_id_list:wp(",",(t=>t)),assembly_id:fp,oper_expression:fp},pdbx_reference_entity_list:{prd_id:fp,ref_entity_id:fp,type:bp(vp),details:fp,component_id:pp},pdbx_reference_entity_link:{link_id:pp,prd_id:fp,details:fp,ref_entity_id_1:fp,ref_entity_id_2:fp,entity_seq_num_1:pp,entity_seq_num_2:pp,comp_id_1:fp,comp_id_2:fp,atom_id_1:fp,atom_id_2:fp,value_order:bp(vp),component_1:pp,component_2:pp,link_class:bp(fp)},pdbx_reference_entity_poly_link:{link_id:pp,prd_id:fp,ref_entity_id:fp,component_id:pp,entity_seq_num_1:pp,entity_seq_num_2:pp,comp_id_1:fp,comp_id_2:fp,atom_id_1:fp,atom_id_2:fp,value_order:bp(vp)},pdbx_molecule:{prd_id:fp,instance_id:pp,asym_id:fp},pdbx_molecule_features:{prd_id:fp,class:bp(vp),type:bp(vp),name:fp,details:fp},entity_src_nat:{entity_id:fp,pdbx_organism_scientific:fp,pdbx_plasmid_name:fp,pdbx_src_id:pp,pdbx_beg_seq_num:pp,pdbx_end_seq_num:pp},entity_src_gen:{entity_id:fp,pdbx_gene_src_gene:wp(",",(t=>t)),pdbx_gene_src_scientific_name:fp,plasmid_name:fp,pdbx_src_id:pp,pdbx_beg_seq_num:pp,pdbx_end_seq_num:pp},pdbx_entity_src_syn:{organism_scientific:fp,entity_id:fp,pdbx_src_id:pp,pdbx_beg_seq_num:pp,pdbx_end_seq_num:pp},pdbx_entity_branch_descriptor:{entity_id:fp,descriptor:fp,type:bp(vp),program:fp,program_version:fp,ordinal:pp},pdbx_entity_instance_feature:{details:fp,feature_type:bp(fp),auth_asym_id:fp,asym_id:fp,auth_seq_num:fp,seq_num:pp,comp_id:fp,auth_comp_id:fp,ordinal:pp},pdbx_entity_branch_list:{entity_id:fp,hetero:bp(vp),comp_id:fp,num:pp},pdbx_entity_branch_link:{link_id:pp,details:fp,entity_id:fp,entity_branch_list_num_1:pp,entity_branch_list_num_2:pp,comp_id_1:fp,comp_id_2:fp,atom_id_1:fp,leaving_atom_id_1:fp,atom_stereo_config_1:bp(vp),atom_id_2:fp,leaving_atom_id_2:fp,atom_stereo_config_2:bp(vp),value_order:bp(vp)},pdbx_entity_branch:{entity_id:fp,type:bp(fp)},pdbx_branch_scheme:{entity_id:fp,hetero:bp(vp),asym_id:fp,mon_id:fp,num:pp,pdb_asym_id:fp,pdb_seq_num:fp,pdb_mon_id:fp,auth_asym_id:fp,auth_seq_num:fp,auth_mon_id:fp},pdbx_chem_comp_related:{comp_id:fp,related_comp_id:fp,relationship_type:bp(fp),details:fp},ihm_starting_model_details:{starting_model_id:fp,entity_id:fp,entity_description:fp,asym_id:fp,entity_poly_segment_id:pp,starting_model_source:bp(fp),starting_model_auth_asym_id:fp,starting_model_sequence_offset:pp,dataset_list_id:pp},ihm_starting_comparative_models:{id:pp,starting_model_id:fp,starting_model_auth_asym_id:fp,starting_model_seq_id_begin:pp,starting_model_seq_id_end:pp,template_auth_asym_id:fp,template_seq_id_begin:pp,template_seq_id_end:pp,template_sequence_identity:gp,template_sequence_identity_denominator:bp(pp),template_dataset_list_id:pp,alignment_file_id:pp},ihm_starting_model_seq_dif:{id:pp,entity_id:fp,asym_id:fp,seq_id:pp,comp_id:fp,starting_model_id:fp,db_asym_id:fp,db_seq_id:pp,db_comp_id:fp,details:fp},ihm_model_representation:{id:pp,name:fp,details:fp},ihm_model_representation_details:{id:pp,representation_id:pp,entity_poly_segment_id:pp,entity_id:fp,entity_description:fp,entity_asym_id:fp,model_object_primitive:bp(fp),starting_model_id:fp,model_mode:bp(fp),model_granularity:bp(fp),model_object_count:pp},ihm_struct_assembly_details:{id:pp,assembly_id:pp,parent_assembly_id:pp,entity_description:fp,entity_id:fp,asym_id:fp,entity_poly_segment_id:pp},ihm_struct_assembly:{id:pp,name:fp,description:fp},ihm_modeling_protocol:{id:pp,num_steps:pp,protocol_name:fp},ihm_modeling_protocol_details:{id:pp,protocol_id:pp,step_id:pp,struct_assembly_id:pp,dataset_group_id:pp,struct_assembly_description:fp,step_name:fp,step_method:fp,num_models_begin:pp,num_models_end:pp,multi_scale_flag:bp(vp),multi_state_flag:bp(vp),ordered_flag:bp(vp),script_file_id:pp,software_id:pp},ihm_multi_state_modeling:{state_id:pp,state_group_id:pp,population_fraction:gp,population_fraction_sd:gp,state_type:fp,state_name:fp,experiment_type:bp(fp),details:fp},ihm_modeling_post_process:{id:pp,protocol_id:pp,analysis_id:pp,step_id:pp,type:bp(fp),feature:bp(fp),num_models_begin:pp,num_models_end:pp},ihm_ensemble_info:{ensemble_id:pp,ensemble_name:fp,post_process_id:pp,model_group_id:pp,ensemble_clustering_method:bp(fp),ensemble_clustering_feature:bp(fp),num_ensemble_models:pp,num_ensemble_models_deposited:pp,ensemble_precision_value:gp,ensemble_file_id:pp},ihm_model_list:{model_id:pp,model_name:fp,assembly_id:pp,protocol_id:pp,representation_id:pp},ihm_model_group:{id:pp,name:fp,details:fp},ihm_model_group_link:{model_id:pp,group_id:pp},ihm_model_representative:{id:pp,model_group_id:pp,model_id:pp,selection_criteria:bp(fp)},ihm_dataset_list:{id:pp,data_type:bp(fp),database_hosted:bp(vp)},ihm_dataset_group:{id:pp,name:fp,application:bp(fp),details:fp},ihm_dataset_group_link:{dataset_list_id:pp,group_id:pp},ihm_related_datasets:{dataset_list_id_derived:pp,dataset_list_id_primary:pp},ihm_dataset_related_db_reference:{id:pp,dataset_list_id:pp,db_name:bp(fp),accession_code:fp,version:fp,details:fp},ihm_external_reference_info:{reference_id:pp,reference_provider:fp,reference_type:bp(fp),reference:fp,refers_to:bp(fp),associated_url:fp},ihm_external_files:{id:pp,reference_id:pp,file_path:fp,content_type:bp(fp),file_size_bytes:gp,details:fp},ihm_dataset_external_reference:{id:pp,dataset_list_id:pp,file_id:pp},ihm_localization_density_files:{id:pp,file_id:pp,ensemble_id:pp,entity_id:fp,entity_poly_segment_id:pp,asym_id:fp},ihm_predicted_contact_restraint:{id:pp,group_id:pp,entity_id_1:fp,entity_id_2:fp,asym_id_1:fp,asym_id_2:fp,comp_id_1:fp,comp_id_2:fp,seq_id_1:pp,seq_id_2:pp,rep_atom_1:bp(fp),rep_atom_2:bp(fp),distance_lower_limit:gp,distance_upper_limit:gp,probability:gp,restraint_type:bp(fp),model_granularity:bp(fp),dataset_list_id:pp,software_id:pp},ihm_cross_link_list:{id:pp,group_id:pp,entity_description_1:fp,entity_description_2:fp,entity_id_1:fp,entity_id_2:fp,comp_id_1:fp,comp_id_2:fp,seq_id_1:pp,seq_id_2:pp,linker_type:bp(fp),dataset_list_id:pp},ihm_cross_link_restraint:{id:pp,group_id:pp,entity_id_1:fp,entity_id_2:fp,asym_id_1:fp,asym_id_2:fp,comp_id_1:fp,comp_id_2:fp,seq_id_1:pp,seq_id_2:pp,atom_id_1:fp,atom_id_2:fp,restraint_type:bp(fp),conditional_crosslink_flag:bp(fp),model_granularity:bp(fp),distance_threshold:gp,psi:gp,sigma_1:gp,sigma_2:gp},ihm_cross_link_result_parameters:{id:pp,restraint_id:pp,model_id:pp,psi:gp,sigma_1:gp,sigma_2:gp},ihm_2dem_class_average_restraint:{id:pp,dataset_list_id:pp,number_raw_micrographs:pp,pixel_size_width:gp,pixel_size_height:gp,image_resolution:gp,image_segment_flag:bp(vp),number_of_projections:pp,struct_assembly_id:pp,details:fp},ihm_2dem_class_average_fitting:{id:pp,restraint_id:pp,model_id:pp,cross_correlation_coefficient:gp,rot_matrix:_p(3,3),tr_vector:xp(3)},ihm_3dem_restraint:{id:pp,dataset_list_id:pp,model_id:pp,struct_assembly_id:pp,fitting_method:fp,number_of_gaussians:pp,cross_correlation_coefficient:gp},ihm_sas_restraint:{id:pp,dataset_list_id:pp,model_id:pp,struct_assembly_id:pp,profile_segment_flag:bp(vp),fitting_atom_type:fp,fitting_method:fp,fitting_state:bp(fp),radius_of_gyration:gp,chi_value:gp,details:fp},ihm_starting_model_coord:{ordinal_id:pp,starting_model_id:fp,group_PDB:bp(fp),id:pp,type_symbol:fp,entity_id:fp,atom_id:fp,comp_id:fp,seq_id:pp,asym_id:fp,Cartn_x:gp,Cartn_y:gp,Cartn_z:gp,B_iso_or_equiv:gp},ihm_sphere_obj_site:{id:pp,entity_id:fp,seq_id_begin:pp,seq_id_end:pp,asym_id:fp,Cartn_x:gp,Cartn_y:gp,Cartn_z:gp,object_radius:gp,rmsf:gp,model_id:pp},ihm_gaussian_obj_site:{id:pp,entity_id:fp,seq_id_begin:pp,seq_id_end:pp,asym_id:fp,mean_Cartn_x:gp,mean_Cartn_y:gp,mean_Cartn_z:gp,weight:gp,covariance_matrix:_p(3,3),model_id:pp},ihm_gaussian_obj_ensemble:{id:pp,entity_id:fp,seq_id_begin:pp,seq_id_end:pp,asym_id:fp,mean_Cartn_x:gp,mean_Cartn_y:gp,mean_Cartn_z:gp,weight:gp,covariance_matrix:_p(3,3),ensemble_id:pp},ihm_feature_list:{feature_id:pp,feature_type:bp(fp),entity_type:bp(fp)},ihm_poly_residue_feature:{ordinal_id:pp,feature_id:pp,entity_id:fp,asym_id:fp,comp_id_begin:fp,comp_id_end:fp,seq_id_begin:pp,seq_id_end:pp},ihm_derived_distance_restraint:{id:pp,group_id:pp,feature_id_1:pp,feature_id_2:pp,group_conditionality:bp(fp),random_exclusion_fraction:gp,distance_upper_limit:gp,restraint_type:bp(fp),dataset_list_id:pp},ma_model_list:{ordinal_id:pp,model_id:pp,model_group_id:pp,model_name:fp,model_group_name:fp,model_type:bp(fp),data_id:pp},ma_target_entity:{entity_id:fp,data_id:pp,origin:bp(fp)},ma_target_entity_instance:{asym_id:fp,entity_id:fp,details:fp},ma_target_ref_db_details:{target_entity_id:fp,db_name:bp(fp),db_code:fp,db_accession:fp,seq_db_isoform:fp,seq_db_align_begin:fp,seq_db_align_end:fp,ncbi_taxonomy_id:fp,organism_scientific:fp},ma_data:{id:pp,content_type:bp(fp),content_type_other_details:fp,name:fp},ma_software_group:{ordinal_id:pp,group_id:pp,software_id:pp},ma_qa_metric:{id:pp,name:fp,type:bp(fp),mode:bp(fp),software_group_id:pp},ma_qa_metric_global:{ordinal_id:pp,model_id:pp,metric_id:pp,metric_value:gp},ma_qa_metric_local:{ordinal_id:pp,model_id:pp,label_asym_id:fp,label_seq_id:pp,label_comp_id:fp,metric_id:pp,metric_value:gp}};var Sp=sm.Schema;const Cp=Sp.str,Pp=Sp.float,Ip=Sp.List,kp=Sp.lstr,Mp=Sp.Aliased,Tp=Sp.int,Dp=Sp.coord,Bp={chem_comp:{formula:Cp,formula_weight:Pp,id:Cp,mon_nstd_parent_comp_id:Ip(",",(t=>t)),name:Cp,one_letter_code:Cp,three_letter_code:Cp,type:Mp(kp),pdbx_synonyms:Ip(";",(t=>t)),pdbx_type:Cp,pdbx_ambiguous_flag:Cp,pdbx_replaced_by:Cp,pdbx_replaces:Cp,pdbx_formal_charge:Tp,pdbx_model_coordinates_details:Cp,pdbx_model_coordinates_db_code:Cp,pdbx_ideal_coordinates_details:Cp,pdbx_ideal_coordinates_missing_flag:Mp(kp),pdbx_model_coordinates_missing_flag:Mp(kp),pdbx_initial_date:Cp,pdbx_modified_date:Cp,pdbx_release_status:Mp(Cp),pdbx_processing_site:Mp(Cp)},chem_comp_atom:{alt_atom_id:Cp,atom_id:Cp,charge:Tp,model_Cartn_x:Dp,model_Cartn_y:Dp,model_Cartn_z:Dp,comp_id:Cp,type_symbol:Cp,pdbx_align:Tp,pdbx_ordinal:Tp,pdbx_model_Cartn_x_ideal:Dp,pdbx_model_Cartn_y_ideal:Dp,pdbx_model_Cartn_z_ideal:Dp,pdbx_stereo_config:Mp(kp),pdbx_aromatic_flag:Mp(kp),pdbx_leaving_atom_flag:Mp(kp)},chem_comp_bond:{atom_id_1:Cp,atom_id_2:Cp,comp_id:Cp,value_order:Mp(kp),pdbx_ordinal:Tp,pdbx_stereo_config:Mp(kp),pdbx_aromatic_flag:Mp(kp)},pdbx_chem_comp_descriptor:{comp_id:Cp,descriptor:Cp,type:Mp(kp),program:Cp,program_version:Cp},pdbx_chem_comp_identifier:{comp_id:Cp,identifier:Cp,type:Mp(Cp),program:Cp,program_version:Cp}};var Fp=sm.Schema;const Ep=Fp.str,$p=Fp.float,Op=Fp.lstr,Rp=Fp.Aliased,Lp=Fp.int,Np={pdbx_reference_molecule:{prd_id:Ep,formula_weight:$p,formula:Ep,type:Rp(Op),type_evidence_code:Ep,class:Rp(Op),class_evidence_code:Ep,name:Ep,represent_as:Rp(Op),chem_comp_id:Ep,compound_details:Ep,description:Ep,representative_PDB_id_code:Ep,release_status:Rp(Op),replaces:Ep,replaced_by:Ep},pdbx_reference_entity_list:{prd_id:Ep,ref_entity_id:Ep,type:Rp(Op),details:Ep,component_id:Lp},pdbx_reference_entity_nonpoly:{prd_id:Ep,ref_entity_id:Ep,name:Ep,chem_comp_id:Ep},pdbx_reference_entity_link:{link_id:Lp,prd_id:Ep,details:Ep,ref_entity_id_1:Ep,ref_entity_id_2:Ep,entity_seq_num_1:Lp,entity_seq_num_2:Lp,comp_id_1:Ep,comp_id_2:Ep,atom_id_1:Ep,atom_id_2:Ep,value_order:Rp(Op),component_1:Lp,component_2:Lp,link_class:Rp(Ep)},pdbx_reference_entity_poly_link:{link_id:Lp,prd_id:Ep,ref_entity_id:Ep,component_id:Lp,entity_seq_num_1:Lp,entity_seq_num_2:Lp,comp_id_1:Ep,comp_id_2:Ep,atom_id_1:Ep,atom_id_2:Ep,value_order:Rp(Op)},pdbx_reference_entity_poly:{prd_id:Ep,ref_entity_id:Ep,type:Rp(Ep),db_code:Ep,db_name:Ep},pdbx_reference_entity_poly_seq:{prd_id:Ep,ref_entity_id:Ep,mon_id:Ep,parent_mon_id:Ep,num:Lp,observed:Rp(Op),hetero:Rp(Op)},pdbx_reference_entity_sequence:{prd_id:Ep,ref_entity_id:Ep,type:Rp(Ep),NRP_flag:Rp(Ep),one_letter_codes:Ep},pdbx_reference_entity_src_nat:{prd_id:Ep,ref_entity_id:Ep,ordinal:Lp,organism_scientific:Ep,taxid:Ep,db_code:Ep,db_name:Ep},pdbx_prd_audit:{prd_id:Ep,date:Ep,processing_site:Rp(Ep),action_type:Rp(Ep)}};var zp=sm.Schema;const Up=zp.str,Vp={datablock:{id:Up,description:Up},dictionary:{title:Up,datablock_id:Up,version:Up},dictionary_history:{version:Up,update:Up,revision:Up},sub_category:{id:Up,description:Up},category_group_list:{id:Up,parent_id:Up,description:Up},item_type_list:{code:Up,primitive_code:Up,construct:Up,detail:Up},item_units_list:{code:Up,detail:Up},item_units_conversion:{from_code:Up,to_code:Up,operator:Up,factor:zp.float}};var jp=sm.Schema;const Gp=jp.str,Hp=jp.int,qp=jp.float,Wp=jp.Aliased,Xp=jp.Vector;Wp(Gp),Wp(Gp),Wp(Gp),Wp(Gp),Xp(3),Xp(3);const Yp={volume_data_3d_info:{name:Gp,axis_order:Xp(3,Hp),origin:Xp(3),dimensions:Xp(3),sample_rate:Hp,sample_count:Xp(3,Hp),spacegroup_number:Hp,spacegroup_cell_size:Xp(3),spacegroup_cell_angles:Xp(3),mean_source:qp,mean_sampled:qp,sigma_source:qp,sigma_sampled:qp,min_source:qp,min_sampled:qp,max_source:qp,max_sampled:qp},volume_data_3d:{values:qp}};var Kp=sm.Schema;const Zp=Kp.float,Qp=Kp.int,Jp=Kp.str,tg={cell:{angle_alpha:Zp,angle_beta:Zp,angle_gamma:Zp,formula_units_z:Qp,length_a:Zp,length_b:Zp,length_c:Zp,volume:Zp},chemical:{melting_point:Zp,name_common:Jp,name_systematic:Jp},chemical_formula:{moiety:Jp,sum:Jp,weight:Zp},space_group:{crystal_system:Jp,it_number:Qp,"name_h-m_full":Jp},space_group_symop:{operation_xyz:Jp},geom_bond:{atom_site_label_1:Jp,atom_site_label_2:Jp,distance:Zp,publ_flag:Jp,site_symmetry_1:Jp,site_symmetry_2:Jp,valence:Zp},audit:{block_doi:Jp},database_code:{cod:Jp,csd:Jp,depnum_ccdc_archive:Jp,depnum_ccdc_fiz:Jp,icsd:Jp,mdf:Jp,nbs:Jp},atom_site:{adp_type:Jp,calc_flag:Jp,disorder_assembly:Jp,disorder_group:Jp,fract_x:Zp,fract_y:Zp,fract_z:Zp,label:Jp,occupancy:Zp,refinement_flags:Jp,site_symmetry_multiplicity:Qp,type_symbol:Jp,u_iso_or_equiv:Zp},atom_site_aniso:{label:Jp,u_11:Zp,u:(0,Kp.Matrix)(3,3),u_12:Zp,u_13:Zp,u_22:Zp,u_23:Zp,u_33:Zp},atom_type:{description:Jp,symbol:Jp},atom_type_scat:{dispersion_imag:Zp,dispersion_real:Zp,source:Jp}},eg={"cell.formula_units_z":["cell_formula_units_Z"],"space_group.it_number":["space_group_IT_number","symmetry_Int_Tables_number"],"space_group.name_h-m_full":["symmetry_space_group_name_H-M"],"space_group_symop.operation_xyz":["symmetry_equiv_pos_as_xyz"],"geom_bond.atom_site_label_1":["geom_bond_atom_site_id_1"],"geom_bond.atom_site_label_2":["geom_bond_atom_site_id_2"],"geom_bond.distance":["geom_bond_dist"],"audit.block_doi":["audit_block_DOI"],"database_code.cod":["database_code_COD"],"database_code.csd":["database_code_CSD"],"database_code.depnum_ccdc_archive":["database_code_depnum_CCDC_archive"],"database_code.depnum_ccdc_fiz":["database_code_depnum_CCDC_fiz"],"database_code.icsd":["database_code_ICSD"],"database_code.mdf":["database_code_MDF"],"database_code.nbs":["database_code_NBS"],"atom_site.adp_type":["atom_site_ADP_type","atom_site_thermal_displace_type"],"atom_site.label":["atom_site_id"],"atom_site.site_symmetry_multiplicity":["atom_site_symmetry_multiplicity"],"atom_site.u_iso_or_equiv":["atom_site_U_iso_or_equiv"],"atom_site_aniso.label":["atom_site_anisotrop_id"],"atom_site_aniso.u_11":["atom_site_aniso_U_11","atom_site_anisotrop_U_11"],"atom_site_aniso.u_12":["atom_site_aniso_U_12","atom_site_anisotrop_U_12"],"atom_site_aniso.u_13":["atom_site_aniso_U_13","atom_site_anisotrop_U_13"],"atom_site_aniso.u_22":["atom_site_aniso_U_22","atom_site_anisotrop_U_22"],"atom_site_aniso.u_23":["atom_site_aniso_U_23","atom_site_anisotrop_U_23"],"atom_site_aniso.u_33":["atom_site_aniso_U_33","atom_site_anisotrop_U_33"]};const ig=sm.Schema.int,rg={volume_data_3d_info:Yp.volume_data_3d_info,segmentation_data_table:{set_id:ig,segment_id:ig},segmentation_data_3d:{values:ig}},ng={parse:t=>"string"==typeof t?Bf(t):rp(t),parseText:Bf,parseBinary:rp,toDatabaseCollection:function(t,e,i){const r={};for(const n of e.blocks)r[n.header]=sp(t,n,i);return r},toDatabase:sp,schema:{mmCIF:t=>sp(Ap,t),CCD:t=>sp(Bp,t),BIRD:t=>sp(Np,t),dic:t=>sp(Vp,t),cifCore:t=>sp(tg,t,eg),densityServer:t=>sp(Yp,t),segmentation:t=>sp(rg,t)}};class sg{constructor(t,e){var i=e||{};this.streamer=t,this.name=rt(i.name,""),this.path=rt(i.path,"")}get type(){return""}get __objName(){return""}get isBinary(){return!1}get isJson(){return!1}get isXml(){return!1}parse(){return this.streamer.read().then((()=>Nl(this,void 0,void 0,(function*(){return yield this._beforeParse(),yield this._parse(),yield this._afterParse(),this[this.__objName]}))))}_parse(){}_beforeParse(){}_afterParse(){De&&ke.log(this[this.__objName])}}class og extends sg{constructor(t,e){var i=e||{};super(t,i),this.firstModelOnly=rt(i.firstModelOnly,!1),this.asTrajectory=rt(i.asTrajectory,!1),this.cAlphaOnly=rt(i.cAlphaOnly,!1),this.structure=new Sc(this.name,this.path),this.structureBuilder=new Na(this.structure)}get type(){return"structure"}get __objName(){return"structure"}}class ag{constructor(t,e,i="",r,n=[]){this.structure=t,this.index=e,this.description=i,this.entityType=function(t){switch(t=t.toLowerCase()){case"polymer":return 1;case"non-polymer":return 2;case"macrolide":return 3;case"water":return 4;default:return 0}}(r||""),this.chainIndexList=n,n.forEach((function(i){t.chainStore.entityIndex[i]=e}))}get type(){return function(t){switch(t){case 1:return"polymer";case 2:return"non-polymer";case 3:return"macrolide";case 4:return"water";default:return}}(this.entityType)}getEntityType(){return this.entityType}isPolymer(){return 1===this.entityType}isNonPolymer(){return 2===this.entityType}isMacrolide(){return 3===this.entityType}isWater(){return 4===this.entityType}eachChain(t){const e=this.structure.getChainProxy();this.chainIndexList.forEach((function(i){e.index=i,t(e)}))}}const cg={a:1,b:1,c:1,alpha:90,beta:90,gamma:90,spacegroup:"P 1"};class lg{constructor(t=cg){this.cartToFrac=new i,this.fracToCart=new i,this.a=t.a,this.b=t.b,this.c=t.c,this.alpha=t.alpha,this.beta=t.beta,this.gamma=t.gamma,this.spacegroup=t.spacegroup;const e=It(this.alpha),r=It(this.beta),n=It(this.gamma),s=Math.cos(e),o=Math.cos(r),a=Math.cos(n),c=Math.sin(r),l=Math.sin(n);if(this.volume=this.a*this.b*this.c*Math.sqrt(1-s*s-o*o-a*a+2*s*o*a),void 0===t.cartToFrac){const t=this.a*this.b*l/this.volume,e=(o*a-s)/(c*l);this.fracToCart.set(this.a,0,0,0,this.b*a,this.b*l,0,0,this.c*o,-this.c*c*e,1/t,0,0,0,0,1).transpose(),this.cartToFrac.copy(this.fracToCart).invert()}else this.cartToFrac.copy(t.cartToFrac),this.fracToCart.copy(this.cartToFrac).invert()}getPosition(t){const i=new Float32Array(24);if(t.unitcell){const r=t.unitcell,n=t.center.clone().applyMatrix4(r.cartToFrac).floor(),s=new e;let o=0;const a=function(t,e,a){s.set(t,e,a).add(n).applyMatrix4(r.fracToCart).toArray(i,o),o+=3};a(0,0,0),a(1,0,0),a(0,1,0),a(0,0,1),a(1,1,0),a(1,0,1),a(0,1,1),a(1,1,1)}return i}getCenter(t){return function(t,i=new e){const r=t.length;for(let e=0;e0)continue;let e,i,r,n,a,g=0;if(s){if(n=S.split(mg),g=10===n.length?1:0,B=n[2],f&&"CA"!==B)continue;e=parseFloat(n[6-g]),i=parseFloat(n[7-g]),r=parseFloat(n[8-g])}else{if(B=S.substr(12,4).trim(),f&&"CA"!==B)continue;e=parseFloat(S.substr(30,8)),i=parseFloat(S.substr(38,8)),r=parseFloat(S.substr(46,8))}if(m){const t=3*b;if(y[t+0]=e,y[t+1]=i,y[t+2]=r,b+=1,_)continue}s?(P=parseInt(n[1]),a="",F="H"===S[0],I=g?"":n[4],k=parseInt(n[5-g]),D="",M=n[3],$="",T=1):(P=parseInt(S.substr(6,5),h),l&&99999===P&&(h=16),F="H"===S[0],I=S[21].trim(),k=parseInt(S.substr(22,4),u),l&&9999===k&&(u=16),D=S[26].trim(),M=S.substr(17,4).trim()||"MOL",E=parseFloat(S.substr(60,6)),$=S[16].trim(),T=parseFloat(S.substr(54,6)),t||(o?(a=S.substr(76,3).trim(),a in ms&&(a=ms[a])):(a=S.substr(76,2).trim(),I||(I=S.substr(72,4).trim())),O=parseInt((S.substr(79,1)+S.substr(78,1)).trim()))),ut.growIfFull(),ut.atomTypeId[ft]=ht.add(B,a),ut.x[ft]=e,ut.y[ft]=i,ut.z[ft]=r,ut.serial[ft]=P,ut.altloc[ft]=$.charCodeAt(0),ut.occupancy[ft]=isNaN(T)?0:T,s?(ut.partialCharge[ft]=parseFloat(n[9-g]),ut.radius[ft]=parseFloat(n[10-g])):(ut.bfactor[ft]=isNaN(E)?0:E,o&&(ut.partialCharge[ft]=parseFloat(S.substr(70,6))),isFinite(O)&&(ut.formalCharge||ut.addField("formalCharge",1,"int8"),ut.formalCharge[ft]=O));const x=fg(k,I,D);!F||K[x]||ug.includes(M)?tt||et===I||(Q+=1,J=Q.toString()):et===I&&rt===M&&(as.includes(M)||it===k&&nt===D)||(Q+=1,J=Q.toString(),it=k,rt=M,nt=D),c.addAtom(pt,I,J,M,k,F,void 0,D),j[P]=ft,ft+=1,tt=!1,et=I}else if("CONECT"===C){const t=j[parseInt(S.substr(6,5))],e=[11,16,21,26],i={};if(void 0===t)continue;for(let r=0;r<4;++r){let n=parseInt(S.substr(e[r],5));if(!Number.isNaN(n)&&(n=j[n],void 0!==n))if(t{var i;return[null===(i=n.get(t))||void 0===i?void 0:i.atomname,e]}))),o=[],a=[],c=[];let l,h;for(let t=0;t{var b;const _=c.getField(f),x=c.getField(p),v=c.getField(g),w=y*o;for(let c=0;cc*c)return a.growIfFull(),a.atomTypeId[w]=a.atomTypeId[t],a.x[w]=_.x,a.y[w]=_.y,a.z[w]=_.z,a.occupancy[w]=a.occupancy[t],a.serial[w]=w,a.altloc[w]="A".charCodeAt(0),n.addAtom(0,"","","HET",1,!0),void(w+=1)}}}))}}(B,A,S),S.finalize(),A.finalizeAtoms(),Ha(A),A.finalizeBonds();else{const e={},T={},D=A.atomMap,F=A.atomStore,E=B.categories.atom_site;let $=E.rowCount;const O=E.getField("pdbx_PDB_model_num");if(!(null===(t=null==O?void 0:O.areValuesEqual(0,$-1))||void 0===t||t)&&(P||C)){const t=O.int(0);for(let e=0;e<$;e++)if(O.int(e)>t){$=e;break}}A.chemCompMap=new gg(A);const R=B.categories.chem_comp;let L=R.getField("id");const N=R.getField("type");for(let t=0;t{const r=t.getField(e);return r?r.toFloatArray({array:Float32Array,start:0,end:i}):new Float32Array(i)};F.resize($),F.x=z(E,"Cartn_x",$),F.y=z(E,"Cartn_y",$),F.z=z(E,"Cartn_z",$),F.serial=E.getField("id").toIntArray({start:0,end:$}),F.bfactor=z(E,"B_iso_or_equiv",$),F.occupancy=z(E,"occupancy",$);const U=E.getField("label_alt_id");(null==U?void 0:U.isDefined)&&(F.altloc=Uint8Array.from(U.toStringArray(),(t=>t.charCodeAt(0))));const V=E.getField("label_atom_id"),j=E.getField("type_symbol");L=E.getField("label_comp_id");const G=null!==(r=E.getField("auth_seq_id"))&&void 0!==r?r:E.getField("label_seq_id"),H=E.getField("pdbx_PDB_ins_code"),q=E.getField("auth_asym_id"),W=E.getField("label_asym_id"),X=E.getField("group_PDB"),Y=E.getField("label_entity_id");for(let t=0;t<$;t++){const i=null!==(n=null==O?void 0:O.int(t))&&void 0!==n?n:1,r=null!==(s=null==q?void 0:q.str(t))&&void 0!==s?s:"",u=null!==(o=null==W?void 0:W.str(t))&&void 0!==o?o:"",d=null!==(a=null==L?void 0:L.str(t))&&void 0!==a?a:"",m=null!==(c=null==G?void 0:G.int(t))&&void 0!==c?c:0,f="H"===(null==X?void 0:X.str(t)[0]),p=null!==(l=null==H?void 0:H.str(t))&&void 0!==l?l:"",g=null!==(h=null==Y?void 0:Y.int(t))&&void 0!==h?h:1;F.atomTypeId[t]=D.add((null==V?void 0:V.str(t))||"",null==j?void 0:j.str(t)),S.addAtom(i-1,r,u,d,m,f,void 0,p),e[u]=r,T[g]||(T[g]=new Set),T[g].add(A.chainStore.count-1)}if(P){const t=E.rowCount/$|0,e=E.getField("Cartn_x"),i=E.getField("Cartn_y"),r=E.getField("Cartn_z");for(let n=0;n0){const[t,e]=h.split("(").filter((t=>!!t)),r=o(t),s=o(e);Object.keys(r).forEach((function(t){Object.keys(s).forEach((function(e){const o=new i;o.multiplyMatrices(r[t],s[e]),n[t+"x"+e]=o}))}))}else n=o(h);const u=[];for(let t in n)u.push(n[t]);let d=""+e;/^(0|[1-9][0-9]*)$/.test(d)&&(d="BU"+d);const m=l.str(t).split(",").map((t=>r[t]));void 0===s[d]&&(s[d]=new Ra(d)),s[d].addPart(u,m)}}if(t.struct_ncs_oper){const e=t.struct_ncs_oper,r="NCS";s[r]=new Ra(r);const n=s[r].addPart(),o=e.getField("code"),a=e.getField("matrix[1][1]"),c=e.getField("matrix[1][2]"),l=e.getField("matrix[1][3]"),h=e.getField("matrix[2][1]"),u=e.getField("matrix[2][2]"),d=e.getField("matrix[2][3]"),m=e.getField("matrix[3][1]"),f=e.getField("matrix[3][2]"),p=e.getField("matrix[3][3]"),g=e.getField("vector[1]"),y=e.getField("vector[2]"),b=e.getField("vector[3]");for(let t=0;ts&&([n,s]=[s,n],[P,T]=[T,P]),0!==n&&0!==s)for(let i=0;ib)continue}u=I.substr(5,5).trim(),d=parseInt(I.substr(0,5)),m=parseInt(I.substr(15,5)),x.growIfFull(),x.atomTypeId[v]=_.add(h),x.x[v]=T,x.y[v]=D,x.z[v]=B,x.serial[v]=m,r.addAtom(w,"","",u,d,!1,"l"),v+=1}}}(0,i.length,i)})),r.finalize(),i.finalizeAtoms(),Ga(i),Ha(i),i.finalizeBonds(),Ua(i),De&&ke.timeEnd("GroParser._parse "+this.name)}});var wg=["mmtfVersion","mmtfProducer","unitCell","spaceGroup","structureId","title","depositionDate","releaseDate","experimentalMethods","resolution","rFree","rWork","bioAssemblyList","ncsOperatorList","entityList","groupList","numBonds","numAtoms","numGroups","numChains","numModels","groupsPerChain","chainsPerModel"].concat(["xCoordList","yCoordList","zCoordList","groupIdList","groupTypeList","chainIdList","bFactorList","atomIdList","altLocList","occupancyList","secStructList","insCodeList","sequenceIndexList","chainNameList","bondAtomList","bondOrderList"]);function Ag(t,e,i){return e?new t(e.buffer,e.byteOffset,e.byteLength/(i||1)):void 0}function Sg(t){return Ag(DataView,t)}function Cg(t){return Ag(Int8Array,t)}function Pg(t){return Ag(Int32Array,t,4)}function Ig(t,e){var i=t.length/2;e||(e=new Int16Array(i));for(var r=0,n=0;rs&&++a;e=new Int32Array(a)}for(i=0,r=0;in){for(var s=[],o=0;o0&&(o.biomolDict[t]=e)}const E=a.unitCell;E&&Array.isArray(E)&&E[0]?o.unitcell=new lg({a:E[0],b:E[1],c:E[2],alpha:E[3],beta:E[4],gamma:E[5],spacegroup:a.spaceGroup}):o.unitcell=void 0,Ya(o,!0),Xa(o,!0),o.finalizeAtoms(),o.finalizeBonds(),Ka(o),De&&ke.timeEnd("MmtfParser._parse "+this.name)}});const Ng=/\s+/,zg={1:1,2:2,3:3,am:1,ar:1,du:1,un:1,nc:0};Ne.add("mol2",class extends og{get type(){return"mol2"}_parse(){De&&ke.time("Mol2Parser._parse "+this.name);const t=this.structure,e=this.structureBuilder,i=this.firstModelOnly,r=this.asTrajectory,n=t.frames;let s,o,a=!1;const c=t.atomMap,l=t.atomStore;l.resize(Math.round(this.streamer.data.length/60)),l.addField("partialCharge",1,"float32");let h=0,u=0,d=0,m=-1,f=0,p=0;const g=t.getAtomProxy(),y=t.getAtomProxy();this.streamer.eachChunkOfLines((function(b){!function(b,_,x){for(let v=b;v<_;++v){const b=x[v].trim();if(""!==b&&"#"!==b[0])if("@"===b[0])"@MOLECULE"===b?(p=1,u=0,++m):"@ATOM"===b?(p=2,d=l.count,r&&(o=0,s=new Float32Array(3*f),n.push(s),m>0&&(a=!0))):p="@BOND"===b?3:0;else if(1===p){if(0===u)t.title=b,t.id=b;else if(1===u){const t=b.split(Ng);f=parseInt(t[0])}++u}else if(2===p){const t=b.split(Ng);if(i&&m>0)continue;const n=parseFloat(t[2]),u=parseFloat(t[3]),d=parseFloat(t[4]);if(r){const t=3*o;if(s[t+0]=n,s[t+1]=u,s[t+2]=d,o+=1,a)continue}const f=t[0],p=t[1],g=t[5].split(".")[0],y=t[6]?parseInt(t[6]):1,_=t[7]?t[7]:"",x=t[8]?parseFloat(t[8]):0;l.growIfFull(),l.atomTypeId[h]=c.add(p,g),l.x[h]=n,l.y[h]=u,l.z[h]=d,l.serial[h]=+f,l.partialCharge[h]=x,e.addAtom(m,"","",_,y,!0),h+=1}else if(3===p){if(i&&m>0)continue;if(r&&m>0)continue;const e=b.split(Ng);g.index=parseInt(e[1])-1+d,y.index=parseInt(e[2])-1+d;const n=zg[e[3]];t.bondStore.addBond(g,y,n)}}}(0,b.length,b)})),e.finalize(),t.finalizeAtoms(),Ga(t),Xa(t,!0),Ya(t,!0),t.finalizeBonds(),tc(t),Ua(t),De&&ke.timeEnd("Mol2Parser._parse "+this.name)}});Ne.add("pdbqt",class extends pg{get type(){return"pdbqt"}});Ne.add("pqr",class extends pg{get type(){return"pqr"}});const Ug=/> +<(.+)>/;class Vg extends og{get type(){return"sdf"}_parse(){De&&ke.time("SdfParser._parse "+this.name);const t=this.structure,e=this.structureBuilder,i=this.firstModelOnly,r=this.asTrajectory,n=this.streamer.peekLines(2);t.id=n[0].trim(),t.title=n[1].trim();const s=t.frames;let o,a,c=!1;const l=t.atomMap,h=t.atomStore;h.resize(Math.round(this.streamer.data.length/50)),h.addField("formalCharge",1,"int8");const u=t.getAtomProxy(),d=t.getAtomProxy();let m=0,f=0,p=0,g=0;const y=[];let b,_,x,v,w,A,S,C,P,I,k,M,T,D,B=!1,F={};t.extraData.sdf=y;let E=!1,$=!1,O=!1,R=[],L=[];const N=new Map;this.streamer.eachChunkOfLines((function(n){!function(n,z,U){for(let V=n;V-1,E?N.clear():(_=parseInt(n.substr(0,3)),x=parseInt(n.substr(3,3)),v=4,w=v+_,A=w,S=A+x,r&&(a=0,o=new Float32Array(3*_),s.push(o),p>0&&(c=!0)));else if(E&&"COUNTS"===R[0])_=parseInt(R[1]),r&&(a=0,o=new Float32Array(3*_),s.push(o),p>0&&(c=!0));else if(E&&2==R.length)"ATOM"===R[1]?"BEGIN"===R[0]?$=!0:"END"===R[0]&&($=!1):"BOND"===R[1]&&("BEGIN"===R[0]?O=!0:"END"===R[0]&&(O=!1));else if($||!E&&f>=v&&f0)continue;let t=0;if(E){if(C=parseFloat(R[2]),P=parseFloat(R[3]),I=parseFloat(R[4]),M=R[1],T=parseInt(R[0]),N.set(T,m),k=M+T,R.length>6){let e=R.slice(6).find((t=>0===t.indexOf("CHG=")));e&&(t=parseInt(e.substring(4)))}}else C=parseFloat(n.substr(0,10)),P=parseFloat(n.substr(10,10)),I=parseFloat(n.substr(20,10)),M=n.substr(31,3).trim(),k=M+(m-g+1);if(r){const t=3*a;if(o[t+0]=C,o[t+1]=P,o[t+2]=I,a+=1,c)continue}h.growIfFull(),h.atomTypeId[m]=l.add(k,M),h.x[m]=C,h.y[m]=P,h.z[m]=I,h.serial[m]=E?T:m,h.formalCharge[m]=t,e.addAtom(p,"","","HET",1,!0),m+=1}else if(O||!E&&f>=A&&f0)continue;if(r&&p>0)continue;E?(u.index=N.get(parseInt(R[2])),d.index=N.get(parseInt(R[3])),D=parseInt(R[1])):(u.index=parseInt(n.substr(0,3))-1+g,d.index=parseInt(n.substr(3,3))-1+g,D=parseInt(n.substr(6,3))),t.bondStore.addBond(u,d,D)}else if("M CHG"===n.substr(0,6)){const t=parseInt(n.substr(6,3));for(let e=0,i=10;e"===n.charAt(0)&&(b=n.match(Ug))?(B=b[1],F[B]=[]):!1!==B&&n&&F[B].push(n);++f}}}(0,n.length,n)})),e.finalize(),t.finalizeAtoms(),t.finalizeBonds(),tc(t),De&&ke.timeEnd("SdfParser._parse "+this.name)}_postProcess(){tc(this.structure)}}Ne.add("sdf",Vg),Ne.add("sd",Vg),Ne.add("mol",Vg);function jg(t,e,i){return parseInt(t.substr(e,i).trim())}class Gg extends og{get type(){return"prmtop"}_parse(){De&&ke.time("PrmtopParser._parse "+this.name);const t=this.structure,e=this.structureBuilder,i=t.atomMap,r=t.atomStore;r.addField("partialCharge",1,"float32"),r.addField("radius",1,"float32");const n=[],s={},o=["NATOM","NTYPES","NBONH","MBONA","NTHETH","MTHETA","NPHIH","MPHIA","NHPARM","NPARM","NNB","NRES","NBONA","NTHETA","NPHIA","NUMBND","NUMANG","NPTRA","NATYP","NPHB","IFPERT","NBPER","NGPER","NDPER","MBPER","MGPER","MDPER","IFBOX","NMXRS","IFCAP","NUMEXTRA","NCOPY"];let a,c,l,h,u;o.forEach((t=>{s[t]=0}));let d,m,f,p,g,y=new Uint8Array(0);this.streamer.eachChunkOfLines((function(t){!function(t,e,i){for(let b=t;b0)return void ke.error("dcd format with fixed atoms unsupported, aborting");const f=s.NATOM,p=4*f;for(let i=0,a=s.NSET;i=1&&(i.timeOffset=(s.ISTART-1)*i.deltaTime),De&&ke.timeEnd("DcdParser._parse "+this.name)}});const Jg={BYTE:1,CHAR:2,SHORT:3,INT:4,FLOAT:5,DOUBLE:6};function ty(t){switch(Number(t)){case Jg.BYTE:return"byte";case Jg.CHAR:return"char";case Jg.SHORT:return"short";case Jg.INT:return"int";case Jg.FLOAT:return"float";case Jg.DOUBLE:return"double";default:return"undefined"}}function ey(t){switch(Number(t)){case Jg.BYTE:case Jg.CHAR:return 1;case Jg.SHORT:return 2;case Jg.INT:case Jg.FLOAT:return 4;case Jg.DOUBLE:return 8;default:return-1}}function iy(t){switch(String(t)){case"byte":return Jg.BYTE;case"char":return Jg.CHAR;case"short":return Jg.SHORT;case"int":return Jg.INT;case"float":return Jg.FLOAT;case"double":return Jg.DOUBLE;default:return-1}}function ry(t,e){if(1!==t){const i=new Array(t);for(let r=0;r6,"non valid type "+h);const u=t.readUint32();let d=t.readUint32();2===i&&(Kg(d>0,"offsets larger than 4GB not supported"),d=t.readUint32()),c[0]===e&&(s+=u),n[r]={name:o,dimensions:c,attributes:l,type:ty(h),size:u,offset:d,record:c[0]===e}}}return{variables:n,recordStep:s}}(t,r.recordId,e);return i.variables=n.variables,i.recordDimension.recordStep=n.recordStep,i}function hy(t){let e;const i=t.readUint32();if(i===sy)return Kg(t.readUint32()!==sy,"wrong empty tag for list of attributes"),[];{Kg(i!==cy,"wrong tag for list of attributes");const r=t.readUint32();e=new Array(r);for(let i=0;i6,"non valid type "+n);const s=t.readUint32(),o=ny(t,n,s);Zg(t),e[i]={name:r,type:ty(n),value:o}}}return e}class uy{constructor(t){const e=new li(t);e.setBigEndian(),Kg("CDF"!==e.readChars(3),"should start with CDF");const i=e.readByte();Kg(i>2,"unknown version"),this.header=ly(e,i),this.buffer=e}get version(){return 1===this.header.version?"classic format":"64-bit offset format"}get recordDimension(){return this.header.recordDimension}get dimensions(){return this.header.dimensions}get globalAttributes(){return this.header.globalAttributes}get variables(){return this.header.variables}hasDataVariable(t){return-1!==this.header.variables.findIndex((function(e){return e.name===t}))}getDataVariable(t){let e;return e="string"==typeof t?this.header.variables.find((function(e){return e.name===t})):t,Kg(void 0===e,"variable not found"),this.buffer.seek(e.offset),e.record?function(t,e,i){const r=iy(e.type),n=e.size?e.size/ey(r):1,s=i.length,o=new Array(s),a=i.recordStep;for(let e=0;e=1&&(e.timeOffset=n[0]),n.length>=2&&(e.deltaTime=n[1]-n[0]),De&&ke.timeEnd("NctrajParser._parse "+this.name)}}Ne.add("nctraj",dy),Ne.add("ncdf",dy),Ne.add("nc",dy);Ne.add("trr",class extends Yg{get type(){return"trr"}get isBinary(){return!0}_parse(){De&&ke.time("TrrParser._parse "+this.name);const t=_t(this.streamer.data),e=new DataView(t),i=this.frames,r=i.coordinates,n=i.boxes,s=i.times;let o=0;for(;;){o+=8;const i=e.getInt32(o);o+=4,o+=i;const a=e.getInt32(o+8),c=e.getInt32(o+12),l=e.getInt32(o+16),h=e.getInt32(o+28),u=e.getInt32(o+32),d=e.getInt32(o+36),m=e.getInt32(o+40);o+=52;const f=a/9,p=3*m;if(8===f?s.push(e.getFloat64(o)):s.push(e.getFloat32(o)),o+=2*f,a){const t=new Float32Array(9);if(8===f)for(let i=0;i<9;++i)t[i]=10*e.getFloat64(o),o+=8;else for(let i=0;i<9;++i)t[i]=10*e.getFloat32(o),o+=4;n.push(t)}if(o+=c,o+=l,h){let i;if(8===f){i=new Float32Array(p);for(let t=0;t>8&65280|i>>24&255}i=new Float32Array(t,o,p);for(let t=0;t=t.byteLength)break}s.length>=1&&(i.timeOffset=s[0]),s.length>=2&&(i.deltaTime=s[1]-s[0]),De&&ke.timeEnd("TrrParser._parse "+this.name)}});const my=new Uint32Array([0,0,0,0,0,0,0,0,0,8,10,12,16,20,25,32,40,50,64,80,101,128,161,203,256,322,406,512,645,812,1024,1290,1625,2048,2580,3250,4096,5060,6501,8192,10321,13003,16384,20642,26007,32768,41285,52015,65536,82570,104031,131072,165140,208063,262144,330280,416127,524287,660561,832255,1048576,1321122,1664510,2097152,2642245,3329021,4194304,5284491,6658042,8388607,10568983,13316085,16777216]);function fy(t){let e=1,i=0;for(;t>=e&&i<32;)i++,e<<=1;return i}const py=new Uint8Array(32);function gy(t,e){let i=1,r=0;py[0]=1;for(let r=0;r>=8;for(;0!==n;)py[t++]=255&n,n>>=8;i=t}let n=1;for(i--;py[i]>=n;)r++,n*=2;return r+8*i}function yy(t,e,i,r){const n=(1<=8;)o=o<<8|e[a++],c|=o>>s<0&&(s>s&(1<8;)by[a++]=yy(t,e,8,o),r-=8;r>0&&(by[a++]=yy(t,e,r,o));for(let t=i-1;t>0;t--){let e=0;for(let i=a-1;i>=0;i--){e=e<<8|by[i];const r=e/n[t]|0;by[i]=r,e-=r*n[t]}s[t]=e}s[0]=by[0]|by[1]<<8|by[2]<<16|by[3]<<24}Ne.add("xtc",class extends Yg{get type(){return"xtc"}get isBinary(){return!0}_parse(){De&&ke.time("XtcParser._parse "+this.name);const t=_t(this.streamer.data),e=new DataView(t),i=this.frames,r=i.coordinates,n=i.boxes,s=i.times,o=new Int32Array(6),a=new Int32Array(3),c=new Int32Array(3),l=new Uint32Array(3),h=new Float32Array(3),u=new Float32Array(3);let d=0;const m=new Int32Array(3),f=new Uint32Array(m.buffer);for(;;){let i;const p=e.getInt32(d+4);d+=12;const g=3*p;s.push(e.getFloat32(d)),d+=4;const y=new Float32Array(9);for(let t=0;t<9;++t)y[t]=10*e.getFloat32(d),d+=4;if(n.push(y),p<=9){i=new Float32Array(p);for(let t=0;t16777215?(c[0]=fy(a[0]),c[1]=fy(a[1]),c[2]=fy(a[2]),p=0):p=gy(3,a);let y=e.getInt32(d);d+=4;let b=y-1;b=9>b?9:b;let _=my[b]/2|0,x=my[y]/2|0;l[0]=l[1]=l[2]=my[y];let v=4*Math.ceil(e.getInt32(d)/4);d+=4;const w=1/s;let A=0,S=0;const C=new Uint8Array(t,d);for(h[0]=h[1]=h[2]=0;S0){h[0]=h[1]=h[2]=0;for(let t=0;t9?my[y-1]/2|0:0):t>0&&(_=x,x=my[y]/2|0),l[0]=l[1]=l[2]=my[y],0===l[0]||0===l[1]||0===l[2])return void console.error("(xdrfile error) Undefined error.")}d+=v}for(let t=0;t=t.byteLength)break}s.length>=1&&(i.timeOffset=s[0]),s.length>=2&&(i.deltaTime=s[1]-s[0]),De&&ke.timeEnd("XtcParser._parse "+this.name)}});class xy extends sg{constructor(t,e){const i=e||{};super(t,i),this.volume=new $o(this.name,this.path),this.voxelSize=rt(i.voxelSize,1)}get type(){return"volume"}get __objName(){return"volume"}_afterParse(){this.volume.setMatrix(this.getMatrix()),super._afterParse()}getMatrix(){return new i}}const vy=/\s+/,wy=/-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?/g,Ay=.529177210859;class Sy extends xy{get type(){return"cube"}_parse(){De&&ke.time("CubeParser._parse "+this.name);const t=this.volume,i=this.streamer.peekLines(6),r={},n=Ay*this.voxelSize;function s(t,e){var r=i[t].trim().split(vy)[e];return parseFloat(r)}r.atomCount=Math.abs(s(2,0)),r.originX=s(2,1)*Ay,r.originY=s(2,2)*Ay,r.originZ=s(2,3)*Ay,r.NVX=s(3,0),r.NVY=s(4,0),r.NVZ=s(5,0),r.basisX=new e(s(3,1),s(3,2),s(3,3)).multiplyScalar(n),r.basisY=new e(s(4,1),s(4,2),s(4,3)).multiplyScalar(n),r.basisZ=new e(s(5,1),s(5,2),s(5,3)).multiplyScalar(n);const o=new Float32Array(r.NVX*r.NVY*r.NVZ);let a=0,c=0;const l=s(2,0)>0?0:1;this.streamer.eachChunkOfLines((function(t){!function(t,e,i){for(let n=t;n=r.atomCount+6+l){const e=t.match(wy);for(let t=0,i=e.length;t>8&255}e.xStart=s[0],e.yStart=s[1],e.zStart=s[2],e.xExtent=s[3],e.yExtent=s[4],e.zExtent=s[5],e.xRate=s[6],e.yRate=s[7],e.zRate=s[8];const t=1/s[17],n=t*this.voxelSize;e.xlen=s[9]*n,e.ylen=s[10]*n,e.zlen=s[11]*n,e.alpha=s[12]*t,e.beta=s[13]*t,e.gamma=s[14]*t,i=s[15]/100,r=s[16],e.gamma=s[14]*t}t.header=e,De&&ke.log(e,i,r);const c=new Float32Array(e.xExtent*e.yExtent*e.zExtent);let l=512;const h=Math.ceil(e.xExtent/8),u=Math.ceil(e.yExtent/8),d=Math.ceil(e.zExtent/8);for(var m=0;mn){const t=i[r].trim();if(""!==t){const e=t.split(Py);for(let t=0,i=e.length;t=n&&(f-n)%d!=0&&m=0?i-1:i+e/3)},parseNormalIndex:function(t,e){var i=parseInt(t,10);return 3*(i>=0?i-1:i+e/3)},addVertex:function(t,e,i){var r=this.vertices,n=this.object.geometry.vertices;n.push(r[t+0]),n.push(r[t+1]),n.push(r[t+2]),n.push(r[e+0]),n.push(r[e+1]),n.push(r[e+2]),n.push(r[i+0]),n.push(r[i+1]),n.push(r[i+2])},addVertexLine:function(t){var e=this.vertices,i=this.object.geometry.vertices;i.push(e[t+0]),i.push(e[t+1]),i.push(e[t+2])},addNormal:function(t,e,i){var r=this.normals,n=this.object.geometry.normals;n.push(r[t+0]),n.push(r[t+1]),n.push(r[t+2]),n.push(r[e+0]),n.push(r[e+1]),n.push(r[e+2]),n.push(r[i+0]),n.push(r[i+1]),n.push(r[i+2])},addFace:function(t,e,i,r,n,s,o,a){var c,l=this.vertices.length,h=this.parseVertexIndex(t,l),u=this.parseVertexIndex(e,l),d=this.parseVertexIndex(i,l);if(void 0===r?this.addVertex(h,u,d):(c=this.parseVertexIndex(r,l),this.addVertex(h,u,c),this.addVertex(u,d,c)),void 0!==n){var m=this.normals.length;h=this.parseNormalIndex(n,m),u=n===s?h:this.parseNormalIndex(s,m),d=n===o?h:this.parseNormalIndex(o,m),void 0===r?this.addNormal(h,u,d):(c=this.parseNormalIndex(a,m),this.addNormal(h,u,c),this.addNormal(u,d,c))}},addLineGeometry:function(t){this.object.geometry.type="Line";for(var e=this.vertices.length,i=0,r=t.length;i0?_.setAttribute("normal",new M(new Float32Array(b.normals),3)):_.computeVertexNormals(),y.push(_)}}return y}};Ne.add("obj",class extends Gy{get type(){return"obj"}getLoader(){return new Hy}});Ne.add("csv",class extends sg{constructor(t,e){const i=e||{};super(t,i),this.delimiter=rt(i.delimiter,","),this.comment=rt(i.comment,"#"),this.columnNames=rt(i.columnNames,!1),this.table={name:this.name,path:this.path,columnNames:[],data:[]}}get type(){return"csv"}get __objName(){return"table"}_parse(){const t=this.table.data,e=new RegExp("\\s*"+this.delimiter+"\\s*");let i=0;this.streamer.eachChunkOfLines((r=>{const n=r.length;for(let s=0;s/g,""),{declaration:e(),root:i()};function e(){if(!n(/^<\?xml\s*/))return;const t={attributes:{}};for(;!s()&&!o("?>");){const e=r();if(!e)return t;t.attributes[e.name]=e.value}return n(/\?>\s*/),t}function i(){const t=n(Xy);if(!t)return;const e={name:t[1],attributes:{},children:[]};for(;!(s()||o(">")||o("?>")||o("/>"));){const t=r();if(!t)return e;e.attributes[t.name]=t.value}if(n(/^\s*\/>\s*/))return e;let a;for(n(/\??>\s*/),e.content=function(){const t=n(Yy);return t?t[1]:""}();a=i();)e.children.push(a);return n(/^<\/[\w-:.]+>\s*/),e}function r(){const t=n(Ky);var e;if(t)return{name:t[1],value:(e=t[2],e.replace(Wy,""))}}function n(e){const i=t.match(e);if(i)return t=t.slice(i[0].length),i}function s(){return 0===t.length}function o(e){return 0===t.indexOf(e)}}class Qy extends sg{constructor(t,e){const i=e||{};super(t,i),this.useDomParser=rt(i.useDomParser,!1),this.xml={name:this.name,path:this.path,data:{}}}get type(){return"xml"}get __objName(){return"xml"}get isXml(){return!0}__xmlParser(t){return Zy(t)}__domParser(t){return(new window.DOMParser).parseFromString(t,"text/xml")}_parse(){De&&ke.time("XmlParser._parse "+this.name),this.useDomParser?this.streamer.data instanceof Document?this.xml.data=this.streamer.data:this.xml.data=this.__domParser(this.streamer.asText()):this.xml.data=this.__xmlParser(this.streamer.asText()),De&&ke.timeEnd("XmlParser._parse "+this.name)}}function Jy(t,e){const i=t.getNamedItem(e);return null!==i?i.value:""}function tb(t,e,i=!1){const r=Jy(t,"icode").trim(),n=Jy(t,"chain").trim(),s=Jy(t,"altcode");let o=Jy(t,"resnum");return r&&(o+="^"+r),n&&(o+=":"+n),e&&(o+="."+e),i&&s.trim()&&(o+="%"+s),o+="/"+(parseInt(Jy(t,"model"))-1),o}function eb(t){const e=Jy(t,"chain").trim();let i=`[${Jy(t,"rescode")}]${Jy(t,"resnum")}`;return e&&(i+=`:${e}`),i}function ib(t,e,i){void 0===t[e]?t[e]=i:t[e]|=i}function rb(t,e){return null!==t&&t.value===e}function nb(t,e,i){let r=0;const n=e.getElementsByTagName("clash");for(let e=0,i=n.length;e0&&(r+=1);e.getElementsByTagName("bond-outlier").length>0&&(r+=1);return e.getElementsByTagName("plane-outlier").length>0&&(r+=1),rb(i.getNamedItem("rota"),"OUTLIER")&&(r+=1),rb(i.getNamedItem("rama"),"OUTLIER")&&(r+=1),rb(i.getNamedItem("RNApucker"),"outlier")&&(r+=1),r}Ne.add("xml",Qy);class sb{constructor(t,e){this.name=t,this.path=e,this.rsrzDict={},this.rsccDict={},this.rciDict={},this.clashDict={},this.clashArray=[],this.geoDict={},this.geoAtomDict={},this.atomDict={},this.clashSele="NONE"}get type(){return"validation"}fromXml(t){De&&ke.time("Validation.fromXml");const e=this.rsrzDict,i=this.rsccDict,r=this.rciDict,n=this.clashDict,s=this.clashArray,o=this.geoDict,a=this.geoAtomDict,c=this.atomDict,l=t.getElementsByTagName("Entry");if(1===l.length){const t=l[0].getElementsByTagName("chemical_shift_list");if(1===t.length){const e=t[0].getElementsByTagName("random_coil_index");for(let t=0,i=e.length;t0&&(o[r]=t)}else{const t=e.getElementsByTagName("clash"),i=e.getElementsByTagName("mog-bond-outlier"),s=e.getElementsByTagName("mog-angle-outlier");if(i.length>0||s.length>0||t.length>0){const e={};a[r]=e;for(let i=0,r=t.length;i>>16&65535,o=0;0!==i;){i-=o=i>2e3?2e3:i;do{s=s+(n=n+e[r++]|0)|0}while(--o);n%=65521,s%=65521}return n|s<<16}Ne.add("validation",class extends Qy{constructor(t,e){super(t,e||{}),this.useDomParser=!0,this.validation=new sb(this.name,this.path)}get __objName(){return"validation"}get isXml(){return!0}_parse(){super._parse(),De&&ke.time("ValidationParser._parse "+this.name),this.validation.fromXml(this.xml.data),De&&ke.timeEnd("ValidationParser._parse "+this.name)}});var lb=function(){for(var t,e=[],i=0;i<256;i++){t=i;for(var r=0;r<8;r++)t=1&t?3988292384^t>>>1:t>>>1;e[i]=t}return e}();function hb(t,e,i,r){var n=lb,s=r+i;t^=-1;for(var o=r;o>>8^n[255&(t^e[o])];return~t}var ub=30,db=12;function mb(t,e){var i,r,n,s,o,a,c,l,h,u,d,m,f,p,g,y,b,_,x,v,w,A,S,C,P;i=t.state,r=t.next_in,C=t.input,n=r+(t.avail_in-5),s=t.next_out,P=t.output,o=s-(e-t.avail_out),a=s+(t.avail_out-257),c=i.dmax,l=i.wsize,h=i.whave,u=i.wnext,d=i.window,m=i.hold,f=i.bits,p=i.lencode,g=i.distcode,y=(1<>>=x=_>>>24,f-=x,0===(x=_>>>16&255))P[s++]=65535&_;else{if(!(16&x)){if(64&x){if(32&x){i.mode=db;break t}t.msg="invalid literal/length code",i.mode=ub;break t}_=p[(65535&_)+(m&(1<>>=x,f-=x),f<15&&(m+=C[r++]<>>=x=_>>>24,f-=x,16&(x=_>>>16&255)){if(w=65535&_,f<(x&=15)&&(m+=C[r++]<c){t.msg="invalid distance too far back",i.mode=ub;break t}if(m>>>=x,f-=x,w>(x=s-o)){if((x=w-x)>h&&i.sane){t.msg="invalid distance too far back",i.mode=ub;break t}if(A=0,S=d,0===u){if(A+=l-x,x2;)P[s++]=S[A++],P[s++]=S[A++],P[s++]=S[A++],v-=3;v&&(P[s++]=S[A++],v>1&&(P[s++]=S[A++]))}else{A=s-w;do{P[s++]=P[A++],P[s++]=P[A++],P[s++]=P[A++],v-=3}while(v>2);v&&(P[s++]=P[A++],v>1&&(P[s++]=P[A++]))}break}if(64&x){t.msg="invalid distance code",i.mode=ub;break t}_=g[(65535&_)+(m&(1<>3,m&=(1<<(f-=v<<3))-1,t.next_in=r,t.next_out=s,t.avail_in=r=1&&0===T[v];v--);if(w>v&&(w=v),0===v)return n[s++]=20971520,n[s++]=20971520,a.bits=1,0;for(x=1;x0&&(t===yb||1!==v))return-1;for(D[1]=0,b=1;bpb||t===_b&&P>gb)return 1;for(;;){f=b-S,o[_]m?(p=B[F+o[_]],g=k[M+o[_]]):(p=96,g=0),c=1<>S)+(l-=c)]=f<<24|p<<16|g}while(0!==l);for(c=1<>=1;if(0!==c?(I&=c-1,I+=c):I=0,_++,0==--T[b]){if(b===v)break;b=e[i+o[_]]}if(b>w&&(I&u)!==h){for(0===S&&(S=w),d+=x,C=1<<(A=b-S);A+Spb||t===_b&&P>gb)return 1;n[h=I&u]=w<<24|A<<16|d-s}}return 0!==I&&(n[d+I]=b-S<<24|64<<16),a.bits=w,0}var Cb=1,Pb=2,Ib=0,kb=-2,Mb=1,Tb=12,Db=30,Bb=852,Fb=592;function Eb(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function $b(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new Uint16Array(320),this.work=new Uint16Array(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function Ob(t){var e;return t&&t.state?((e=t.state).wsize=0,e.whave=0,e.wnext=0,function(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=Mb,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new Int32Array(Bb),e.distcode=e.distdyn=new Int32Array(Fb),e.sane=1,e.back=-1,Ib):kb}(t)):kb}function Rb(t,e){var i,r;return t?(r=new $b,t.state=r,r.window=null,i=function(t,e){var i,r;return t&&t.state?(r=t.state,e<0?(i=0,e=-e):(i=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?kb:(null!==r.window&&r.wbits!==e&&(r.window=null),r.wrap=i,r.wbits=e,Ob(t))):kb}(t,e),i!==Ib&&(t.state=null),i):kb}var Lb,Nb,zb=!0;function Ub(t){if(zb){var e;for(Lb=new Int32Array(512),Nb=new Int32Array(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(Sb(Cb,t.lens,0,288,Lb,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;Sb(Pb,t.lens,0,32,Nb,0,t.work,{bits:5}),zb=!1}t.lencode=Lb,t.lenbits=9,t.distcode=Nb,t.distbits=5}function Vb(t,e,i,r){var n,s=t.state;return null===s.window&&(s.wsize=1<=s.wsize?(ab(s.window,e,i-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):((n=s.wsize-s.wnext)>r&&(n=r),ab(s.window,e,i-r,n,s.wnext),(r-=n)?(ab(s.window,e,i-r,r,0),s.wnext=r,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,i.check=hb(i.check,I,2,0),l=0,h=0,i.mode=2;break}if(i.flags=0,i.head&&(i.head.done=!1),!(1&i.wrap)||(((255&l)<<8)+(l>>8))%31){t.msg="incorrect header check",i.mode=Db;break}if(8!=(15&l)){t.msg="unknown compression method",i.mode=Db;break}if(h-=4,w=8+(15&(l>>>=4)),0===i.wbits)i.wbits=w;else if(w>i.wbits){t.msg="invalid window size",i.mode=Db;break}i.dmax=1<>8&1),512&i.flags&&(I[0]=255&l,I[1]=l>>>8&255,i.check=hb(i.check,I,2,0)),l=0,h=0,i.mode=3;case 3:for(;h<32;){if(0===a)break t;a--,l+=r[s++]<>>8&255,I[2]=l>>>16&255,I[3]=l>>>24&255,i.check=hb(i.check,I,4,0)),l=0,h=0,i.mode=4;case 4:for(;h<16;){if(0===a)break t;a--,l+=r[s++]<>8),512&i.flags&&(I[0]=255&l,I[1]=l>>>8&255,i.check=hb(i.check,I,2,0)),l=0,h=0,i.mode=5;case 5:if(1024&i.flags){for(;h<16;){if(0===a)break t;a--,l+=r[s++]<>>8&255,i.check=hb(i.check,I,2,0)),l=0,h=0}else i.head&&(i.head.extra=null);i.mode=6;case 6:if(1024&i.flags&&((m=i.length)>a&&(m=a),m&&(i.head&&(w=i.head.extra_len-i.length,i.head.extra||(i.head.extra=new Array(i.head.extra_len)),ab(i.head.extra,r,s,m,w)),512&i.flags&&(i.check=hb(i.check,r,m,s)),a-=m,s+=m,i.length-=m),i.length))break t;i.length=0,i.mode=7;case 7:if(2048&i.flags){if(0===a)break t;m=0;do{w=r[s+m++],i.head&&w&&i.length<65536&&(i.head.name+=String.fromCharCode(w))}while(w&&m>9&1,i.head.done=!0),t.adler=i.check=0,i.mode=Tb;break;case 10:for(;h<32;){if(0===a)break t;a--,l+=r[s++]<>>=7&h,h-=7&h,i.mode=27;break}for(;h<3;){if(0===a)break t;a--,l+=r[s++]<>>=1)){case 0:i.mode=14;break;case 1:if(Ub(i),i.mode=20,6===e){l>>>=2,h-=2;break t}break;case 2:i.mode=17;break;case 3:t.msg="invalid block type",i.mode=Db}l>>>=2,h-=2;break;case 14:for(l>>>=7&h,h-=7&h;h<32;){if(0===a)break t;a--,l+=r[s++]<>>16^65535)){t.msg="invalid stored block lengths",i.mode=Db;break}if(i.length=65535&l,l=0,h=0,i.mode=15,6===e)break t;case 15:i.mode=16;case 16:if(m=i.length){if(m>a&&(m=a),m>c&&(m=c),0===m)break t;ab(n,r,s,m,o),a-=m,s+=m,c-=m,o+=m,i.length-=m;break}i.mode=Tb;break;case 17:for(;h<14;){if(0===a)break t;a--,l+=r[s++]<>>=5,h-=5,i.ndist=1+(31&l),l>>>=5,h-=5,i.ncode=4+(15&l),l>>>=4,h-=4,i.nlen>286||i.ndist>30){t.msg="too many length or distance symbols",i.mode=Db;break}i.have=0,i.mode=18;case 18:for(;i.have>>=3,h-=3}for(;i.have<19;)i.lens[k[i.have++]]=0;if(i.lencode=i.lendyn,i.lenbits=7,S={bits:i.lenbits},A=Sb(0,i.lens,0,19,i.lencode,0,i.work,S),i.lenbits=S.bits,A){t.msg="invalid code lengths set",i.mode=Db;break}i.have=0,i.mode=19;case 19:for(;i.have>>16&255,b=65535&P,!((g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>>=g,h-=g,i.lens[i.have++]=b;else{if(16===b){for(C=g+2;h>>=g,h-=g,0===i.have){t.msg="invalid bit length repeat",i.mode=Db;break}w=i.lens[i.have-1],m=3+(3&l),l>>>=2,h-=2}else if(17===b){for(C=g+3;h>>=g)),l>>>=3,h-=3}else{for(C=g+7;h>>=g)),l>>>=7,h-=7}if(i.have+m>i.nlen+i.ndist){t.msg="invalid bit length repeat",i.mode=Db;break}for(;m--;)i.lens[i.have++]=w}}if(i.mode===Db)break;if(0===i.lens[256]){t.msg="invalid code -- missing end-of-block",i.mode=Db;break}if(i.lenbits=9,S={bits:i.lenbits},A=Sb(Cb,i.lens,0,i.nlen,i.lencode,0,i.work,S),i.lenbits=S.bits,A){t.msg="invalid literal/lengths set",i.mode=Db;break}if(i.distbits=6,i.distcode=i.distdyn,S={bits:i.distbits},A=Sb(Pb,i.lens,i.nlen,i.ndist,i.distcode,0,i.work,S),i.distbits=S.bits,A){t.msg="invalid distances set",i.mode=Db;break}if(i.mode=20,6===e)break t;case 20:i.mode=21;case 21:if(a>=6&&c>=258){t.next_out=o,t.avail_out=c,t.next_in=s,t.avail_in=a,i.hold=l,i.bits=h,mb(t,d),o=t.next_out,n=t.output,c=t.avail_out,s=t.next_in,r=t.input,a=t.avail_in,l=i.hold,h=i.bits,i.mode===Tb&&(i.back=-1);break}for(i.back=0;y=(P=i.lencode[l&(1<>>16&255,b=65535&P,!((g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>_)])>>>16&255,b=65535&P,!(_+(g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>>=_,h-=_,i.back+=_}if(l>>>=g,h-=g,i.back+=g,i.length=b,0===y){i.mode=26;break}if(32&y){i.back=-1,i.mode=Tb;break}if(64&y){t.msg="invalid literal/length code",i.mode=Db;break}i.extra=15&y,i.mode=22;case 22:if(i.extra){for(C=i.extra;h>>=i.extra,h-=i.extra,i.back+=i.extra}i.was=i.length,i.mode=23;case 23:for(;y=(P=i.distcode[l&(1<>>16&255,b=65535&P,!((g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>_)])>>>16&255,b=65535&P,!(_+(g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>>=_,h-=_,i.back+=_}if(l>>>=g,h-=g,i.back+=g,64&y){t.msg="invalid distance code",i.mode=Db;break}i.offset=b,i.extra=15&y,i.mode=24;case 24:if(i.extra){for(C=i.extra;h>>=i.extra,h-=i.extra,i.back+=i.extra}if(i.offset>i.dmax){t.msg="invalid distance too far back",i.mode=Db;break}i.mode=25;case 25:if(0===c)break t;if(m=d-c,i.offset>m){if((m=i.offset-m)>i.whave&&i.sane){t.msg="invalid distance too far back",i.mode=Db;break}m>i.wnext?(m-=i.wnext,f=i.wsize-m):f=i.wnext-m,m>i.length&&(m=i.length),p=i.window}else p=n,f=o-i.offset,m=i.length;m>c&&(m=c),c-=m,i.length-=m;do{n[o++]=p[f++]}while(--m);0===i.length&&(i.mode=21);break;case 26:if(0===c)break t;n[o++]=i.length,c--,i.mode=21;break;case 27:if(i.wrap){for(;h<32;){if(0===a)break t;a--,l|=r[s++]<=252?6:Xb>=248?5:Xb>=240?4:Xb>=224?3:Xb>=192?2:1;function Yb(t){var e,i,r,n,s,o=t.length,a=0;for(n=0;n>>6,e[s++]=128|63&i):i<65536?(e[s++]=224|i>>>12,e[s++]=128|i>>>6&63,e[s++]=128|63&i):(e[s++]=240|i>>>18,e[s++]=128|i>>>12&63,e[s++]=128|i>>>6&63,e[s++]=128|63&i);return e}function Kb(t,e){var i,r,n,s,o=e||t.length,a=new Array(2*o);for(r=0,i=0;i4)a[r++]=65533,i+=s-1;else{for(n&=2===s?31:3===s?15:7;s>1&&i1?a[r++]=65533:n<65536?a[r++]=n:(n-=65536,a[r++]=55296|n>>10&1023,a[r++]=56320|1023&n)}return function(t,e){if(e<65537&&(t.subarray&&qb||!t.subarray&&Hb))return String.fromCharCode.apply(null,ob(t,e));for(var i="",r=0;rt.length&&(e=t.length),i=e-1;i>=0&&128==(192&t[i]);)i--;return i<0||0===i?e:i+Wb[t[i]]>e?i:e}Wb[254]=Wb[254]=1;var Qb=0,Jb={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"};function t_(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}function e_(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}var i_=Object.prototype.toString;function r_(t){if(!(this instanceof r_))return new r_(t);this.options=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var i=e.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(var r in i)i.hasOwnProperty(r)&&(t[r]=i[r])}}return t}({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&(15&e.windowBits||(e.windowBits|=15)),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new t_,this.strm.avail_out=0;var i,r,n,s=Rb(this.strm,e.windowBits);if(s!==Qb)throw new Error(Jb[s]);this.header=new e_,i=this.strm,r=this.header,i&&i.state&&2&(n=i.state).wrap&&(n.head=r,r.done=!1)}r_.prototype.push=function(t,e){var i,r,n,s,o,a,c=this.strm,l=this.options.chunkSize,h=this.options.dictionary,u=!1;if(this.ended)return!1;r=e===~~e?e:!0===e?4:0,"string"==typeof t?c.input=function(t){for(var e=new Uint8Array(t.length),i=0,r=e.length;i0||0===c.avail_out)&&1!==i);return 1===i&&(r=4),4===r?(i=function(t){if(!t||!t.state)return kb;var e=t.state;return e.window&&(e.window=null),t.state=null,Ib}(this.strm),this.onEnd(i),this.ended=!0,i===Qb):2!==r||(this.onEnd(Qb),c.avail_out=0,!0)},r_.prototype.onData=function(t){this.chunks.push(t)},r_.prototype.onEnd=function(t){t===Qb&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=function(t){var e,i,r,n,s,o;for(r=0,e=0,i=t.length;e-1?e.name:e.name.substring(0,4);let r;return!["pdb","cif"].includes(e.ext)||!1!==e.compressed&&"gz"!==e.compressed?"mmtf"===e.ext?(ke.warn("MMTF files distribution is discontinued by RCSB PDB as of July 2, 2024.\n Consider using bcif format instead. See https://www.rcsb.org/news/65a1af31c76ca3abcc925d0c for the deprecation notice"),r=e.base.endsWith(".bb")?a_+i:o_+i):"bcif"!==e.ext||!1!==e.compressed&&"gz"!==e.compressed?e.ext?(ke.warn("unsupported ext",e.ext),r=c_+i+".bcif.gz"):(ke.warn('mmCif files available from RCSB PDB lack connectivity information.\n Consider using PDBe as the data provider for using "Updated mmCif files" that contain residues connectivity records.'),r=c_+i+".bcif.gz"):r=c_+e.path:r="//files.rcsb.org/download/"+e.path,at()+r}getExt(t){const e=ii(t).ext;return e||"mmtf"}});const l_="//www.ebi.ac.uk/pdbe/entry-files/download/";Re.add("pdbe",new class extends n_{getUrl(t){const e=ii(t);let i,r=e.name.indexOf("_")>-1?e.name:e.name.substring(0,4);switch(e.ext){case"cif":i=l_+r+"_updated.cif";break;case"pdb":case"ent":r.startsWith("pdb")||(r="pdb"+r),i=l_+r+".ent";break;case"bcif":i=l_+e.path;break;case"":i=l_+r+".bcif";break;default:ke.warn("unsupported ext",e.ext),i=l_+r+".bcif"}return"https://"+i}getExt(t){const e=ii(t).ext;return e||"mmtf"}});const h_="//pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/",u_="/SDF?record_type=3d";Re.add("pubchem",new class extends n_{getUrl(t){const e=ii(t),i=e.name;let r;return e.ext&&"sdf"!==e.ext?(ke.warn("unsupported ext",e.ext),r=h_+i+u_):r=h_+i+u_,at()+r}getExt(t){const e=ii(t).ext;return e||"sdf"}});class d_ extends n_{getUrl(t){return t}getExt(t){return ii(t).ext}}Re.add("ftp",new d_),Re.add("http",new d_),Re.add("https",new d_);const m_="//alphafold.ebi.ac.uk/files/AF-",f_="-F1-model_v4.pdb";Re.add("alphafold",new class extends n_{getUrl(t){const e=ii(t),i=e.name;let r;return e.ext&&"pdb"!==e.ext?(ke.warn("unsupported AF ext",e.ext),r=m_+i+f_):r=m_+i+f_,"https://"+r}getExt(t){const e=ii(t).ext;return e||"pdb"}});const p_=/^((http|https|ftp):)*\/\//;class g_ extends n_{constructor(t=""){super(),this.baseUrl=t}getUrl(t){const e=ii(t);let i=this.baseUrl+e.path;return p_.test(this.baseUrl)||(i=function(t){const e=window.location,i=e.pathname,r=i.substring(0,i.lastIndexOf("/")+1);return e.origin+r+t}(i)),i}getExt(t){return ii(t).ext}}class y_ extends n_{constructor(t=""){super(),this.baseUrl=t}getListing(t=""){let e=`${this.baseUrl}dir/${t}`;return"/"!==e[e.length-1]&&(e+="/"),ni(e,{ext:"json"}).then((e=>({path:t,data:e.data})))}getUrl(t){const e=ii(t);return`${this.baseUrl}file/${e.path}${e.query}`}getCountUrl(t){const e=ii(t);return`${this.baseUrl}traj/numframes/${e.path}${e.query}`}getFrameUrl(t,e){const i=ii(t);return`${this.baseUrl}traj/frame/${e}/${i.path}${i.query}`}getFrameParams(t,e){return`atomIndices=${e.join(";")}`}getPathUrl(t,e){const i=ii(t);return`${this.baseUrl}traj/path/${e}/${i.path}${i.query}`}getExt(t){return ii(t).ext}}function b_(t,e){return{type:"integer",max:t,min:e}}function __(t,e,i){return{type:"number",precision:t,max:e,min:i}}function x_(t,e,i){return{type:"range",step:t,max:e,min:i}}function v_(...t){return{type:"select",options:t.reduce(((t,e)=>Object.assign(Object.assign({},t),{[e]:e})),{})}}const w_={backgroundColor:{type:"color"},quality:v_("auto","low","medium","high"),sampleLevel:x_(1,5,-1),impostor:{type:"boolean"},workerDefault:{type:"boolean"},rotateSpeed:__(1,10,0),zoomSpeed:__(1,10,0),panSpeed:__(1,10,0),clipNear:x_(1,100,0),clipFar:x_(1,100,0),clipDist:b_(200,0),clipMode:v_("scene","camera"),clipScale:v_("relative","absolute"),fogNear:x_(1,100,0),fogFar:x_(1,100,0),cameraType:v_("perspective","orthographic","stereo"),cameraEyeSep:__(3,1,.01),cameraFov:x_(1,120,15),lightColor:{type:"color"},lightIntensity:__(2,10,0),ambientColor:{type:"color"},ambientIntensity:__(2,10,0),hoverTimeout:b_(1e4,-1),tooltip:{type:"boolean"},mousePreset:v_(...Object.keys(Ko))};const A_="2.3.0";export{zh as AngleRepresentation,hd as ArrowBuffer,Ra as Assembly,eu as AxesRepresentation,ru as BackboneRepresentation,iu as BallAndStickRepresentation,nu as BaseRepresentation,pd as BoxBuffer,Mc as BufferRepresentation,uu as CartoonRepresentation,ll as Collection,Nt as Colormaker,Oe as ColormakerRegistry,cl as Component,Bl as ComponentCollection,ad as ConeBuffer,du as ContactRepresentation,ui as Counter,tu as CylinderBuffer,Re as DatasourceRegistry,De as Debug,Ue as DecompressorRegistry,gu as DihedralHistogramRepresentation,mu as DihedralRepresentation,bu as DistanceRepresentation,vd as EllipsoidBuffer,ml as Frames,wu as HelixorientRepresentation,Du as HyperballRepresentation,Ba as Kdtree,Jo as KeyActions,Fu as LabelRepresentation,Ji as LeftMouseButton,Au as LicoriceRepresentation,$u as LineRepresentation,He as ListingDatasource,y_ as MdsrvDatasource,Me as MeasurementDefaultParams,Vo as MeshBuffer,tr as MiddleMouseButton,zu as MolecularSurface,Uu as MolecularSurfaceRepresentation,Yo as MouseActions,Pd as OctahedronBuffer,Ne as ParserRegistry,oi as PdbWriter,yr as PickingProxy,Hc as PointBuffer,Vu as PointRepresentation,Lr as Queue,hl as RepresentationCollection,nl as RepresentationElement,Le as RepresentationRegistry,qu as RibbonRepresentation,er as RightMouseButton,Wu as RocketRepresentation,Xu as RopeRepresentation,Ee as ScriptExtensions,ai as SdfWriter,me as Selection,kc as Shape,Rl as ShapeComponent,Yu as SpacefillRepresentation,Tn as SpatialHash,Uc as SphereBuffer,Ol as Stage,g_ as StaticDatasource,hi as StlWriter,Sc as Structure,Ml as StructureComponent,kl as StructureComponentDefaultParameters,Sh as StructureRepresentation,fl as Superposition,Tl as SurfaceComponent,Dd as TetrahedronBuffer,Oh as TextBuffer,Rd as TorusBuffer,Qu as TraceRepresentation,qe as TrajectoryDatasource,gl as TrajectoryPlayer,Ju as TubeRepresentation,w_ as UIStageParameters,td as UnitcellRepresentation,ed as ValidationRepresentation,A_ as Version,Qi as Viewer,$o as Volume,Dl as VolumeComponent,Nh as WidelineBuffer,ni as autoLoad,ec as concatStructures,ht as download,ot as flatten,ri as getDataInfo,ii as getFileInfo,it as getQuery,Ja as guessElement,Fe as setDebug,We as setListingDatasource,Te as setMeasurementDefaultParams,Xe as setTrajectoryDatasource,Il as superpose,ut as throttle,pt as uniqueArray}; + */class Pa{constructor(t,e){this.points=t,this.metric=e,this.maxDepth=0,this.currentNode=0;const i=t.length/3,r=new Uint32Array(i);for(let t=0;tthis.maxDepth&&(this.maxDepth=t);const n=r-i;if(0===n)return-1;const s=4*this.currentNode,o=this.nodes;if(this.currentNode+=1,1===n)return o[s]=i,o[s+1]=-1,o[s+2]=-1,o[s+3]=e,s;const a=this.indices,c=this.points,l=i+Math.floor(n/2),h=t%3;let u,d,m,f,p,g=i,y=r-1;for(;y>g;){for(m=g+y>>1,f=c[3*a[m]+h],d=a[m],a[m]=a[y],a[y]=d,p=g,u=g;u-t[1])),n=this.nodes,s=this.points,o=this.indices,a=c=>{let l,h;const u=this.getNodeDepth(c)%3,d=3*o[n[c]],m=[s[d+0],s[d+1],s[d+2]],f=this.metric(t,m);function p(t,i){r.push([t,i]),r.size()>e&&r.pop()}const g=n[c+1],y=n[c+2];if(-1===y&&-1===g)return void((r.size()s[3*o[n[t]]+r])throw new Error("left child is > parent!");i+=this.verify(a,e+1)}if(-1!==c){if(s[3*o[n[c]]+r]0}isBackbone(){const t=this.residueType.backboneIndexList;return t.length>0&&t.includes(this.index-this.residueAtomOffset)}isPolymer(){if(this.structure.entityList.length>0)return this.entity.isPolymer();{const t=this.residueType.moleculeType;return 3===t||4===t||5===t}}isSidechain(){return this.isPolymer()&&!this.isBackbone()}isCg(){const t=this.residueType.backboneType;return 4===t||5===t||6===t}isTrace(){return this.index===this.residueType.traceAtomIndex+this.residueAtomOffset}isHetero(){return 1===this.residueType.hetero}isProtein(){return 3===this.residueType.moleculeType}isNucleic(){const t=this.residueType.moleculeType;return 4===t||5===t}isRna(){return 4===this.residueType.moleculeType}isDna(){return 5===this.residueType.moleculeType}isWater(){return 1===this.residueType.moleculeType}isIon(){return 2===this.residueType.moleculeType}isSaccharide(){return 6===this.residueType.moleculeType}isHelix(){return Gn.includes(this.sstruc)}isSheet(){return Hn.includes(this.sstruc)}isTurn(){return qn.includes(this.sstruc)&&this.isProtein()}isBonded(){return 0!==this.bondHash.countArray[this.index]}isRing(){return void 0!==this.residueType.getRings().atomRings[this.index-this.residueAtomOffset]}isAromatic(){return 1===this.aromatic}isPolarHydrogen(){let t=!1;return 1!==this.number||(t=!this.hasBondToElement(6)),t}isMetal(){return this.atomType.isMetal()}isNonmetal(){return this.atomType.isNonmetal()}isMetalloid(){return this.atomType.isMetalloid()}isHalogen(){return this.atomType.isHalogen()}isDiatomicNonmetal(){return this.atomType.isDiatomicNonmetal()}isPolyatomicNonmetal(){return this.atomType.isPolyatomicNonmetal()}isAlkaliMetal(){return this.atomType.isAlkaliMetal()}isAlkalineEarthMetal(){return this.atomType.isAlkalineEarthMetal()}isNobleGas(){return this.atomType.isNobleGas()}isTransitionMetal(){return this.atomType.isTransitionMetal()}isPostTransitionMetal(){return this.atomType.isPostTransitionMetal()}isLanthanide(){return this.atomType.isLanthanide()}isActinide(){return this.atomType.isActinide()}getDefaultValence(){return this.atomType.getDefaultValence()}getValenceList(){return this.atomType.getValenceList()}getOuterShellElectronCount(){return this.atomType.getOuterShellElectronCount()}distanceTo(t){const e=this.atomStore,i=t.atomStore,r=this.index,n=t.index,s=e.x[r]-i.x[n],o=e.y[r]-i.y[n],a=e.z[r]-i.z[n],c=s*s+o*o+a*a;return Math.sqrt(c)}connectedTo(t){const e=this.atomStore,i=t.atomStore,r=this.index,n=t.index;if(e.altloc&&i.altloc){const t=e.altloc[r],s=i.altloc[n];if(0!==t&&0!==s&&32!==t&&32!==s&&t!==s)return!1}const s=e.x[r]-i.x[n],o=e.y[r]-i.y[n],a=e.z[r]-i.z[n],c=s*s+o*o+a*a;if(c<48&&this.isCg())return!0;if(isNaN(c))return!1;const l=this.covalent+t.covalent,h=l+.3,u=l-.5;return cu*u}positionFromArray(t,e=0){return this.x=t[e+0],this.y=t[e+1],this.z=t[e+2],this}positionToArray(t=[],e=0){const i=this.index,r=this.atomStore;return t[e+0]=r.x[i],t[e+1]=r.y[i],t[e+2]=r.z[i],t}positionToVector3(t){return void 0===t&&(t=new e),t.x=this.x,t.y=this.y,t.z=this.z,t}positionFromVector3(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}positionAdd(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}positionSub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}getResidueBonds(t=!1){const e=this.residueAtomOffset,i=this.index-this.residueAtomOffset,r=this.residueType.getBonds(),n=r.atomIndices1,s=r.atomIndices2;let o,a,c,l;for(t||(l=[]),o=n.indexOf(i);-1!==o;){if(c=s[o]+e,!l)return c;l.push(c),o=n.indexOf(i,o+1)}for(a=s.indexOf(i);-1!==a;){if(c=n[a]+e,!l)return c;l.push(c),a=s.indexOf(i,a+1)}return l}qualifiedName(t=!1){var e="";return this.resname&&!t&&(e+="["+this.resname+"]"),void 0!==this.resno&&(e+=this.resno),this.inscode&&(e+="^"+this.inscode),this.chainname&&(e+=":"+this.chainname),this.atomname&&(e+="."+this.atomname),this.altloc&&(e+="%"+this.altloc),this.structure.modelStore.count>1&&(e+="/"+this.modelIndex),e}clone(){return new Ia(this.structure,this.index)}toObject(){return{index:this.index,residueIndex:this.residueIndex,resname:this.resname,x:this.x,y:this.y,z:this.z,element:this.element,chainname:this.chainname,resno:this.resno,serial:this.serial,vdw:this.vdw,covalent:this.covalent,hetero:this.hetero,bfactor:this.bfactor,altloc:this.altloc,atomname:this.atomname,modelIndex:this.modelIndex}}}function ka(t,e){const i=t[0]-e[0],r=t[1]-e[1],n=t[2]-e[2];return i*i+r*r+n*n}function Ma(t,e){return Math.sqrt(ka(t,e))}const Ta=new Float32Array(3);class Da{constructor(t,e=!1){Te&&Ie.time("Kdtree build");const i=e?ka:Ma,r=new Float32Array(3*t.atomCount),n=new Uint32Array(t.atomCount);let s=0;t.eachAtom((function(t){r[s+0]=t.x,r[s+1]=t.y,r[s+2]=t.z,n[s/3]=t.index,s+=3})),this.atomIndices=n,this.points=r,this.kdtree=new Pa(r,i),Te&&Ie.timeEnd("Kdtree build")}nearest(t,i,r){t instanceof e?t.toArray(Ta):t instanceof Ia&&t.positionToArray(Ta);const n=this.kdtree.nearest(Ta,i,r),s=this.kdtree.indices,o=this.kdtree.nodes,a=this.atomIndices,c=[];for(let t=0,e=n.length;t":"3/4-Z","?":"X-Y","@":"Y-X",A:"Z+1/3",B:"Z+2/3",C:"X+2/3",D:"Y+1/3",E:"-Y+2/3",F:"X-Y+1/3",G:"Y-X+2/3",H:"-X+1/3",I:"X+1/3",J:"Y+2/3",K:"-Y+1/3",L:"X-Y+2/3",M:"Y-X+1/3",N:"-X+2/3",O:"2/3+X",P:"1/3+Y",Q:"1/3+Z",R:"2/3-Y",S:"1/3+X-Y",T:"2/3+Y-X",U:"1/3-X",V:"2/3-X",W:"1/3-Y",X:"1/3-Z",Y:"2/3+Y",Z:"1/3+Y-X","[":"2/3+X-Y","]":"1/3+X","^":"2/3+Z",_:"2/3-Z","`":"5/6+Z",a:"1/6+Z",b:"5/6-Z",c:"1/6-Z",d:"Z+5/6",e:"Z+1/6",f:"Z+1/4",g:"+Y"},Fa={"P 1":" !#","P -1":" !#$%&","P 1 2 1":" !#$!&","P 1 21 1":" !#$'&","C 1 2 1":" !#$!&()#*)&","P 1 m 1":" !# %#","P 1 c 1":" !# %+","C 1 m 1":" !# %#()#(,#","C 1 c 1":" !# %+()#(,+","P 1 2/m 1":" !# %#$!&$%&","P 1 21/m 1":" !#$)&$%& ,#","C 1 2/m 1":" !# %#$!&$%&()#(,#*)&*,&","P 1 2/c 1":" !#$!-$%& %+","P 1 21/c 1":" !#$%&$)- ,+","C 1 2/c 1":" !#$!-$%& %+()#*)-*,&(,+","P 2 2 2":" !#$%#$!& %&","P 2 2 21":" !#$%+$!- %&","P 21 21 2":" !#$%#*)&(,&","P 21 21 21":" !#*%+$)-(,&","C 2 2 21":" !#$%+$!- %&()#*,+*)-(,&","C 2 2 2":" !#$%#$!& %&()#*,#*)&(,&","F 2 2 2":" !#$%#$!& %& )+$,+$)- ,-(!+*%+*!-(%-()#*,#*)&(,&","I 2 2 2":" !#$%# %&$!&.'/01/.120'2","I 21 21 21":" !#*%+$)-(,&()+$,#*!& %-","P m m 2":" !#$%# %#$!#","P m c 21":" !#$%+ %+$!#","P c c 2":" !#$%# %+$!+","P m a 2":" !#$%#(%#*!#","P c a 21":" !#$%+(%#*!+","P n c 2":" !#$%# ,+$)+","P m n 21":" !#*%+(%+$!#","P b a 2":" !#$%#(,#*)#","P n a 21":" !#$%+(,#*)+","P n n 2":" !#$%#(,+*)+","C m m 2":" !#$%# %#$!#()#*,#(,#*)#","C m c 21":" !#$%+ %+$!#()#*,+(,+*)#","C c c 2":" !#$%# %+$!+()#*,#(,+*)+","A m m 2":" !#$%# %#$!# )+$,+ ,+$)+","A b m 2":" !#$%# ,#$)# )+$,+ %+$!+","A m a 2":" !#$%#(%#*!# )+$,+(,+*)+","A b a 2":" !#$%#(,#*)# )+$,+(%+*!+","F m m 2":" !#$%# %#$!# )+$,+ ,+$)+(!+*%+(%+*!+()#*,#(,#*)#","F d d 2":" !#$%#345675 )+$,+3896:9(!+*%+;49<79()#*,#;85<:5","I m m 2":" !#$%# %#$!#()+*,+(,+*)+","I b a 2":" !#$%#(,#*)#()+*,+ %+$!+","I m a 2":" !#$%#(%#*!#()+*,+ ,+$)+","P 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!#","P 2/n 2/n 2/n":" !#$%#$!& %&*,-()-(,+*)+","P 2/c 2/c 2/m":" !#$%#$!- %-$%& !& %+$!+","P 2/b 2/a 2/n":" !#$%#$!& %&*,&()&(,#*)#","P 21/m 2/m 2/a":" !#*%#$!&(%&$%&(!& %#*!#","P 2/n 21/n 2/a":" !#*%#*)- ,-$%&(!&(,+$)+","P 2/m 2/n 21/a":" !#*%+*!- %&$%&(!-(%+$!#","P 21/c 2/c 2/a":" !#*%#$!-(%-$%&(!& %+*!+","P 21/b 21/a 2/m":" !#$%#*)&(,&$%& !&(,#*)#","P 21/c 21/c 2/n":" !#*,#$)-(%-$%&()& ,+*!+","P 2/b 21/c 21/m":" !#$%+$)- ,&$%& !- ,+$)#","P 21/n 21/n 2/m":" !#$%#*)-(,-$%& !&(,+*)+","P 21/m 21/m 2/n":" !#$%#*'&.,&*,&.'& %#$!#","P 21/b 2/c 21/n":" !#*,+$!-(,&$%&()- %+*)#","P 21/b 21/c 21/a":" !#*%+$)-(,&$%&(!- ,+*)#","P 21/n 21/m 21/a":" !#0%/$'&.12$%&.!2 1#0'/","C 2/m 2/c 21/m":" !#$%+$!- %&$%& !- %+$!#()#*,+*)-(,&*,&()-(,+*)#","C 2/m 2/c 21/a":" !#$,+$)- %&$%& )- ,+$!#()#*%+*!-(,&*,&(!-(%+*)#","C 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!#()#*,#*)&(,&*,&()&(,#*)#","C 2/c 2/c 2/m":" !#$%#$!- %-$%& !& %+$!+()#*,#*)-(,-*,&()&(,+*)+","C 2/m 2/m 2/a":" !#$,#$)& %&$%& )& ,#$!#()#*%#*!&(,&*,&(!&(%#*)#","C 2/c 2/c 2/a":" !#*,#$!&(,&$,-(!- ,+*!+()#$%#*)& %&*%- )-(%+$)+","F 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!# )+$,+$)- ,-$,- )- ,+$)+(!+*%+*!-(%-*%-(!-(%+*!+()#*,#*)&(,&*,&()&(,#*)#","F 2/d 2/d 2/d":" !#$%#$!& %&64=37=345675 )+$,+$)- ,-68>3:>3896:9(!+*%+*!-(%-<4>;7>;49<79()#*,#*)&(,&<8=;:=;85<:5","I 2/m 2/m 2/m":" !#$%#$!& %&$%& !& %#$!#()+*,+*)-(,-*,-()-(,+*)+","I 2/b 2/a 2/m":" !#$%#*)&(,&$%& !&(,#*)#()+*,+$!- %-*,-()- %+$!+","I 21/b 21/c 21/a":" !#*%+$)-(,&$%&(!- ,+*)#()+$,#*!& %-*,- )&(%#$!+","I 21/m 21/m 21/a":" !#$,#$)& %&$%& )& ,#$!#()+*%+*!-(,-*,-(!-(%+*)+","P 4":" !#$%#% #!$#","P 41":" !#$%+% 5!$9","P 42":" !#$%#% +!$+","P 43":" !#$%+% 9!$5","I 4":" !#$%#% #!$#()+*,+,(+)*+","I 41":" !#*,+%(5)$9()+$%#, 9!*5","P -4":" !#$%#!$&% &","I -4":" !#$%#!$&% &()+*,+)*-,(-","P 4/m":" !#$%#% #!$#$%& !&!$&% &","P 42/m":" !#$%#% +!$+$%& !&!$-% -","P 4/n":" !#$%#,(#)*#*,&()&!$&% &","P 42/n":" !#$%#,(+)*+*,-()-!$&% &","I 4/m":" !#$%#% #!$#$%& !&!$&% &()+*,+,(+)*+*,-()-)*-,(-","I 41/a":" !#*,+%(5)$9$,=(!>!$&,(-()+$%#, 9!*5*%> )=)*-% &","P 4 2 2":" !#$%#% #!$#$!& %&! &%$&","P 4 21 2":" !#$%#,(#)*#*)&(,&! &%$&","P 41 2 2":" !#$%+% 5!$9$!& %-! >%$=","P 41 21 2":" !#$%+,(5)*9*)=(,>! &%$-","P 42 2 2":" !#$%#% +!$+$!& %&! -%$-","P 42 21 2":" !#$%#,(+)*+*)-(,-! &%$&","P 43 2 2":" !#$%+% 9!$5$!& %-! =%$>","P 43 21 2":" !#$%+,(9)*5*)>(,=! &%$-","I 4 2 2":" !#$%#% #!$#$!& %&! &%$&()+*,+,(+)*+*)-(,-)(-,*-","I 41 2 2":" !#*,+%(5)$9*!> ,=)(-%$&()+$%#, 9!*5$)=(%>! &,*-","P 4 m m":" !#$%#% #!$# %#$!#%$#! #","P 4 b m":" !#$%#% #!$#(,#*)#,*#)(#","P 42 c m":" !#$%#% +!$+ %+$!+%$#! #","P 42 n m":" !#$%#,(+)*+(,+*)+%$#! #","P 4 c c":" !#$%#% #!$# %+$!+%$+! +","P 4 n c":" !#$%#% #!$#(,+*)+,*+)(+","P 42 m c":" !#$%#% +!$+ %#$!#%$+! +","P 42 b c":" !#$%#% +!$+(,#*)#,*+)(+","I 4 m m":" !#$%#% #!$# %#$!#%$#! #()+*,+,(+)*+(,+*)+,*+)(+","I 4 c m":" !#$%#% #!$# %+$!+%$+! +()+*,+,(+)*+(,#*)#,*#)(#","I 41 m d":" !#*,+%(5)$9 %#*)+%*5) 9()+$%#, 9!*5(,+$!#,$9!(5","I 41 c d":" !#*,+%(5)$9 %+*)#%*9) 5()+$%#, 9!*5(,#$!+,$5!(9","P -4 2 m":" !#$%#% &!$&$!& %&%$#! #","P -4 2 c":" !#$%#% &!$&$!- %-%$+! +","P -4 21 m":" !#$%#% &!$&*)&(,&,*#)(#","P -4 21 c":" !#$%#% &!$&*)-(,-,*+)(+","P -4 m 2":" !#$%#!$&% & %#$!#! &%$&","P -4 c 2":" !#$%#% &!$& %+$!+! -%$-","P -4 b 2":" !#$%#% &!$&(,#*)#)(&,*&","P -4 n 2":" !#$%#% &!$&(,+*)+)(-,*-","I -4 m 2":" !#$%#% &!$& %#$!#! &%$&()+*,+,(-)*-(,+*)+)(-,*-","I -4 c 2":" !#$%#% &!$& %+$!+! -%$-()+*,+,(-)*-(,#*)#)(&,*&","I -4 2 m":" !#$%#% &!$&$!& %&%$#! #()+*,+,(-)*-*)-(,-,*+)(+","I -4 2 d":" !#$%#% &!$&*!>(%>,$9) 9()+*,+,(-)*-$)= ,=%*5!(5","P 4/m 2/m 2/m":" !#$%#% #!$#$!& %&! &%$&$%& !&!$&% & %#$!#%$#! #","P 4/m 2/c 2/c":" !#$%#% #!$#$!- %-! -%$-$%& !&!$&% & %+$!+%$+! +","P 4/n 2/b 2/m":" !#$%#% #!$#$!& %&! &%$&*,&()&)*&,(&(,#*)#,*#)(#","P 4/n 2/n 2/c":" !#$%#% #!$#$!& %&! &%$&*,-()-)*-,(-(,+*)+,*+)(+","P 4/m 21/b 2/m":" !#$%#% #!$#*)&(,&)(&,*&$%& !&!$&% &(,#*)#,*#)(#","P 4/m 21/n 2/c":" !#$%#% #!$#*)-(,-)(-,*-$%& !&!$&% &(,+*)+,*+)(+","P 4/n 21/m 2/m":" !#$%#,(#)*#*)&(,&! &%$&*,&()&!$&% & %#$!#,*#)(#","P 4/n 2/c 2/c":" !#$%#,(#)*#*)-(,-! -%$-*,&()&!$&% & %+$!+,*+)(+","P 42/m 2/m 2/c":" !#$%#% +!$+$!& %&! -%$-$%& !&!$-% - %#$!#%$+! +","P 42/m 2/c 2/m":" !#$%#% +!$+$!- %-! &%$&$%& !&!$-% - %+$!+%$#! #","P 42/n 2/b 2/c":" !#$%#,(+)*+$!- %-)(&,*&*,-()-!$&% &(,#*)#%$+! +","P 42/n 2/n 2/m":" !#$%#,(+)*+$!& %&)(-,*-*,-()-!$&% &(,+*)+%$#! #","P 42/m 21/b 2/c":" !#$%#% +!$+*)&(,&)(-,*-$%& !&!$-% -(,#*)#,*+)(+","P 42/m 21/n 2/m":" !#$%#,./'*/*'-.,-! &%$&$%& !&'*-,.-.,/*'/%$#! #","P 42/n 21/m 2/c":" !#$%#,(+)*+*)-(,-! &%$&*,-()-!$&% & %#$!#,*+)(+","P 42/n 21/c 2/m":" !#$%#,(+)*+*)&(,&! -%$-*,-()-!$&% & %+$!+,*#)(#","I 4/m 2/m 2/m":" !#$%#% #!$#$!& %&! &%$&$%& !&!$&% & %#$!#%$#! #()+*,+,(+)*+*)-(,-)(-,*-*,-()-)*-,(-(,+*)+,*+)(+","I 4/m 2/c 2/m":" !#$%#% #!$#$!- %-! -%$-$%& !&!$&% & %+$!+%$+! +()+*,+,(+)*+*)&(,&)(&,*&*,-()-)*-,(-(,#*)#,*#)(#","I 41/a 2/m 2/d":" !#*,+%(5)$9*!> ,=)(-%$&$,=(!>!$&,(-(,+$!#,$9!(5()+$%#, 9!*5$)=(%>! &,*-*%> )=)*-% & %#*)+%*5) 9","I 41/a 2/c 2/d":" !#*,+%(5)$9*!= ,>)(&%$-$,=(!>!$&,(-(,#$!+,$5!(9()+$%#, 9!*5$)>(%=! -,*&*%> )=)*-% & %+*)#%*9) 5","P 3":" !#%?#@$#","P 31":" !#%?A@$B","P 32":" !#%?B@$A","H 3":" !#%?#@$#CDAEFAGHAIJBKLBMNB","R 3":" !## !!# ","P -3":" !#%?#@$#$%&!@&? &","H -3":" !#%?#@$#$%&!@&? &OPQRSQTUQVWXYZX[]X]Y^W[^ZV^UR_PT_SO_","R -3":" !## !!# $%&&$%%&$","P 3 1 2":" !#%?#@$#%$&@!& ?&","P 3 2 1":" !#%?#@$#! &?%&$@&","P 31 1 2":" !#%?Q@$^%$_@!X ?&","P 31 2 1":" !#%?A@$B! &?%_$@X","P 32 1 2":" !#%?^@$Q%$X@!_ ?&","P 32 2 1":" !#%?B@$A! &?%X$@_","H 3 2":" !#%?#@$#! &?%&$@&OPQRSQTUQY]X[WXVZX]Y^W[^ZV^PO_SR_UT_","R 3 2":" !## !!# %$&$&%&%$","P 3 m 1":" !#%?#@$#%$#@!# ?#","P 3 1 m":" !#%?#@$#! #?%#$@#","P 3 c 1":" !#%?#@$#%$+@!+ ?+","P 3 1 c":" !#%?#@$#! +?%+$@+","H 3 m":" !#%?#@$#%$#@!# ?#OPQRSQTUQRUQTPQOSQ]Y^W[^ZV^WV^ZY^][^","R 3 m":" !## !!# ! # #!#! ","H 3 c":" !#%?#@$#%$+@!+ ?+OPQRSQTUQRU`TP`OS`]Y^W[^ZV^WVaZYa][a","R 3 c":" !## !!# '././'/'.","P -3 1 2/m":" !#%?#@$#%$&@!& ?&$%&!@&? &! #?%#$@#","P -3 1 2/c":" !#%?#@$#%$-@!- ?-$%&!@&? &! +?%+$@+","P -3 2/m 1":" !#%?#@$#! &?%&$@&$%&!@&? &%$#@!# ?#","P -3 2/c 1":" !#%?#@$#! -?%-$@-$%&!@&? &%$+@!+ ?+","H -3 2/m":" !#%?#@$#! &?%&$@&$%&!@&? &%$#@!# ?#OPQRSQTUQY]X[WXVZXVWXYZX[]XRUQTPQOSQ]Y^W[^ZV^PO_SR_UT_UR_PT_SO_WV^ZY^][^","R -3 2/m":" !## !!# %$&$&%&%$$%&&$%%&$! # #!#! ","H -3 2/c":" !#%?#@$#! -?%-$@-$%&!@&? &%$+@!+ ?+OPQRSQTUQY]b[WbVZbVWXYZX[]XRU`TP`OS`]Y^W[^ZV^POcSRcUTcUR_PT_SO_WVaZYa][a","R -3 2/c":" !## !!# 102021210$%&&$%%&$'././'/'.","P 6":" !#%?#@$#$%#!@#? #","P 61":" !#%?A@$B$%/!@d? e","P 65":" !#%?B@$A$%/!@e? d","P 62":" !#%?^@$Q$%#!@^? Q","P 64":" !#%?Q@$^$%#!@Q? ^","P 63":" !#%?#@$#$%+!@+? +","P -6":" !#%?#@$# !&%?&@$&","P 6/m":" !#%?#@$#$%#!@#? #$%&!@&? & !&%?&@$&","P 63/m":" !#%?#@$#$%+!@+? +$%&!@&? & !-%?-@$-","P 6 2 2":" !#%?#@$#$%#!@#? #! &?%&$@&%$&@!& ?&","P 61 2 2":" !#%?Q@$^$%+!@`? a! X?%&$@_%$b@!- ?c","P 65 2 2":" !#%?^@$Q$%+!@a? `! _?%&$@X%$c@!- ?b","P 62 2 2":" !#%?^@$Q$%#!@^? Q! _?%&$@X%$_@!& ?X","P 64 2 2":" !#%?Q@$^$%#!@Q? ^! X?%&$@_%$X@!& ?_","P 63 2 2":" !#%?#@$#$%+!@+? +! &?%&$@&%$-@!- ?-","P 6 m m":" !#%?#@$#$%#!@#? #%$#@!# ?#! #?%#$@#","P 6 c c":" !#%?#@$#$%#!@#? #%$+@!+ ?+! +?%+$@+","P 63 c m":" !#%?#@$#$%+!@+? +%$+@!+ ?+! #?%#$@#","P 63 m c":" !#%?#@$#$%+!@+? +%$#@!# ?#! +?%+$@+","P -6 m 2":" !#%?#@$# !&%?&@$&%$#@!# ?#%$&@!& ?&","P -6 c 2":" !#%?#@$# !-%?-@$-%$+@!+ ?+%$&@!& ?&","P -6 2 m":" !#%?#@$# !&%?&@$&! &?%&$@&! #?%#$@#","P -6 2 c":" !#%?#@$# !-%?-@$-! &?%&$@&! +?%+$@+","P 6/m 2/m 2/m":" !#%?#@$#$%#!@#? #! &?%&$@&%$&@!& ?&$%&!@&? & !&@$&%?&%$#@!# ?#! #?%#$@#","P 6/m 2/c 2/c":" !#%?#@$#$%#!@#? #! -?%-$@-%$-@!- ?-$%&!@&? & !&@$&%?&%$+@!+ ?+! +?%+$@+","P 63/m 2/c 2/m":" !#%?#@$#$%+!@+? +! -?%-$@-%$&@!& ?&$%&!@&? & !-@$-%?-%$+@!+ ?+! #?%#$@#","P 63/m 2/m 2/c":" !#%?#@$#$%+!@+? +! &?%&$@&%$-@!- ?-$%&!@&? & !-@$-%?-%$#@!# ?#! +?%+$@+","P 2 3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ","F 2 3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ","I 2 3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-(","P 21 3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(","I 21 3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- ","P 2/m -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$","P 2/n -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& *,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*","F 2/m -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$ )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-($,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(*%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- *,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$","F 2/d -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& 64=37=345675=64=375345674=67=3453756 )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(68>3:>3896:9=<8=;:5;85<:4><7>;49;79<(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(<4>;7>;49<79>68>3:93896:8=<:=;85;:5<()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- <8=;:=;8f<:f><4>;79;49<78>6:>3893:96","I 2/m -3":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-(*,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*","P 21/a -3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&($%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*","I 21/a -3":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&($%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*()+$,#*g& %-+()#$,&*!- %)+(,#$!&*%- *,- )&(%#$!+-*,& )#(%+$!,-*)& %#(!+$","P 4 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$","P 42 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*","F 4 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$ )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(-%*-!*+%(+ +,$+)$-, -)#)*#,(&)(&,*(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() -,$-)$+, +(#,*#)*&,(&)+!*+%(-!(-%*()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(&,*&)*#,(#(+%*+!*-%(-!+)$+, -) -,$","F 41 3 2":" !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=46 )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<(!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>86","I 4 3 2":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*","P 43 3 2":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(7;>46=:<5839398<5:6=4;>75:<983>7;=46","P 41 3 2":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<","I 41 3 2":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- 7;>46=:<5839398<5:6=4;>75:<983>7;=46","P -4 3 m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% ","F -4 3 m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(+%*+!*-%(- +)$+,$-) -,#)(#,*&)*&,((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() +,$+)$-, -(#)*#,*&)(&,+!(+%*-!*-%(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(#,*#)*&,(&(+!*+%*-!(-%+) +,$-)$-, ","I -4 3 m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,(","P -4 3 n":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,(","F -4 3 c":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,( )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-() #,$#)$&, &(#!*#%*&!(&%+! +%$-!$-% (!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(!(#%*#!*&%(& +!$+%$-! -%#) #,$&)$&, ()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ! +%$+!$-% - #)$#,$&) &,#!(#%*&!*&%(","I -4 3 d":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(7354<9:6>8;=357<946>:;=857394<>:6=8;()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- :;98657<=43>;9:658<=73>49:;586=7<>43","P 4/m -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ","P 4/n -3 2/n":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$*,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(","P 42/m -3 2/n":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(","P 42/n -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,**,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ","F 4/m -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(-%*-!*+%(+ +,$+)$-, -)#)*#,(&)(&,*$,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*%*+!(+%(-!*-$-) -, +)$+,&,(&)*#,*#)((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() -,$-)$+, +(#,*#)*&,(&)+!*+%(-!(-%**%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*,$+) +, -)$-*&)(&,(#)*#,-%(-!*+%*+!(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(&,*&)*#,(#(+%*+!*-%(-!+)$+, -) -,$*,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$,*#)(#,(&)*&*-!(-%(+!*+%-, -)$+,$+) ","F 4/m -3 2/c":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)( )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-() &,$&)$#, #(#%*#!*&%(&!+!$+% -! -%$$,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*,$#) #, &)$&*&!(&%(#!*#%-% -!$+%$+! (!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(!(&%*&!*#%(# +%$+!$-% -!#)$#, &) &,$*%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*%*#!(#%(&!*&$-! -% +!$+%&, &)$#,$#) ()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ! -%$-!$+% + #,$#)$&, &)#!*#%(&!(&%**,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$%$+! +% -!$-$&) &, #)$#,&%(&!*#%*#!(","F 41/d -3 2/m":" !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=4664=3:>;85<79=64>3:5;89<74=6:>385;79<,$+! #%(-)*&*&)(-% #!$+,-%(&)*+,$#! )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<68>37=;49<:5=<8>;753496:4><:=;893756,*#!(+% &)$-*-!(&, +)$#%-, &!$+%*#)((!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<<4>;:=389675>68=379;45<:8=<7>;453:96%$#) +,(&!*-$&! -,(#)*+%&% -)$#,*+!(()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>86<8=;7>3456:9><4=;:9385678>67=349;:5<%*+)(#, -!$&$-) &%(+!*#,&,(-!*#%$+) ","F 41/d -3 2/c":" !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=46<8>;7=3496:5><8=;793456:8><7=;493:56%*#)(+, &!$-$-! &,(+)*#%&, -!$#%*+)( )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<<4=;:>385679>64=3:9;85<78=67>345;:9<%$+) #,(-!*&$&) -%(#!*+,&%(-)*#,$+! (!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<68=37>;45<:9=<4>;:5389674>6:=389;75<,*+!(#% -)$&*-)(&% +!$#,-,(&!*+%$#) ()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>8664>3:=;89<75=68>375;49<:4=<:>;853796,$#! +%(&)*-*&!(-, #)$+%-% &)$+,*#!(","I 4/m -3 2/m":" !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,**,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(","I 41/a -3 2/d":" !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<$%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*4<97358;=:6>6>:;=8357<94=8;>:694<573()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- 7;>46=:<5839398<5:6=4;>75:<983>7;=46*,- )&(%#$!+-*,& )#(%+$!,-*)& %#(!+$865:;943>7<=<=73>4;9:658>43=7<5869:;","P 1 1 2":" !#$%#","P 1 1 21":" !#$%+","B 1 1 2":" !#$%#(g+*%+","A 1 2 1":" !#$!& )+$)-","C 1 21 1":" !#$)&()#*!&","I 1 2 1":" !#$!&.'/0'2","I 1 21 1":" !#$)&.'/0!-","P 1 1 m":" !# !&","P 1 1 b":" !# )&","B 1 1 m":" !# !&(!+(!-","B 1 1 b":" !# )&(!+()-","P 1 1 2/m":" !# !&$%#$%&","P 1 1 21/m":" !#$%+$%& !-","B 1 1 2/m":" !# !&$%#$%&(!+(!-*%+*%-","P 1 1 2/b":" !#$,#$%& )&","P 1 1 21/b":" !#$%&$,+ )-","B 1 1 2/b":" !#$,#$%& )&(!+*,+*%-()-","P 21 2 2":" !#$!&(%&*%#","P 2 21 2":" !# ,&$)&$%#","P 21 21 2 (a)":" !#*,#.%&$'&","P 21 2 21":" !#$!&(%-*%+","P 2 21 21":" !# %&$)-$,+","C 2 2 21a)":" !#*%+(,&$)-()#$,+ %&*!-","C 2 2 2a":" !#*,#.%&$'&()#$%# ,&*!&","F 2 2 2a":" !#*,#.%&$'& '/*%/.12$!2.!/$,/ %20'2.'#$%# 1&0!&","I 2 2 2a":" !#*,#.%&$'&()+$%+*!- ,-","P 21/m 21/m 2/n a":" !#*,#$)&(%&$%&.'& ,#*!#","P 42 21 2a":" !#*,#%.+'$+$'&.%&! -,*-","I 2 3a":" !#*,#.%&$'&!# ,- '&$%/$# !-*!/$%&.%()+$%+ ,-*!-)+(%&(!-*,#*+()&$)#*,- ,"},Ea=/^[1-9]$/;function $a(t){let e="";return t.length>0&&(e=":"+ft(t).join(" OR :")),new de(e)}class Oa{constructor(t=""){this.name=t,this.partList=[]}get type(){return"Assembly"}addPart(t,e){const i=new Ra(t,e);return this.partList.push(i),i}getAtomCount(t){return this.partList.reduce(((e,i)=>e+i.getAtomCount(t)),0)}getResidueCount(t){return this.partList.reduce(((e,i)=>e+i.getResidueCount(t)),0)}getInstanceCount(){let t=0;return this.partList.forEach((function(e){t+=e.matrixList.length})),t}isIdentity(t){if(1!==this.partList.length)return!1;const e=this.partList[0];if(1!==e.matrixList.length)return!1;if(!(new i).equals(e.matrixList[0]))return!1;let r=[];return t.eachChain((function(t){r.push(t.chainname)})),r=ft(r),e.chainList.length===r.length}getBoundingBox(t){const e=new a;return this.partList.forEach((function(i){const r=i.getBoundingBox(t);e.expandByPoint(r.min),e.expandByPoint(r.max)})),e}getCenter(t){return this.getBoundingBox(t).getCenter(new e)}getSelection(){let t=[];return this.partList.forEach((function(e){t=t.concat(e.chainList)})),$a(t)}}class Ra{constructor(t=[],e=[]){this.matrixList=t,this.chainList=e}get type(){return"AssemblyPart"}_getCount(t,e){let i=0;return t.eachChain((t=>{(0===this.chainList.length||this.chainList.includes(t.chainname))&&(i+=t[e])})),this.matrixList.length*i}getAtomCount(t){return this._getCount(t,"atomCount")}getResidueCount(t){return this._getCount(t,"residueCount")}getBoundingBox(t){const e=new a,i=new a,r=this.getSelection(),n=t.getBoundingBox(r);return this.matrixList.forEach((function(t){i.copy(n).applyMatrix4(t),e.expandByPoint(i.min),e.expandByPoint(i.max)})),e}getSelection(){return $a(this.chainList)}getView(t){const e=this.getSelection();return e?t.getView(e):t}getInstanceList(){const t=[];for(let e=0,i=this.matrixList.length;e0&&this.addResidueType(this.ri-1),l.growIfFull(),l.resno[this.ri]=n,void 0!==o&&(l.sstruc[this.ri]=o.charCodeAt(0)),void 0!==a&&(l.inscode[this.ri]=a.charCodeAt(0)),l.atomOffset[this.ri]=this.ai,l.atomCount[this.ri]=0,l.count+=1,l.chainIndex[this.ri]=this.ci,h.residueCount[this.ci]+=1),c.count+=1,c.residueIndex[this.ai]=this.ri,l.atomCount[this.ri]+=1,this.currentModelindex=t,this.currentChainid=i,this.currentResname=r,this.currentResno=n,this.currentInscode=a,this.currentHetero=s}finalize(){this.previousResname=this.currentResname,this.previousHetero=this.currentHetero,this.ri>-1&&this.addResidueType(this.ri)}}function Na(t,e){if(!e)return;Te&&Ie.time("assignSecondaryStructure");const i=[];t.eachModel((function(t){t.eachChain((function(t){i.push(t.chainname)}))}));const r=i.slice().sort(),n=[];r.forEach((function(t){n.push(i.indexOf(t))}));const s=e.helices.filter((function(t){return dt(r,t[0])>=0}));s.sort((function(t,e){const i=t[0],s=e[0],o=t[1],a=e[1];if(i===s)return o===a?0:o=0}));a.sort((function(t,e){const i=t[0],s=e[0];if(i===s)return 0;const o=dt(r,i),a=dt(r,s);return n[o]=t.residueCount)continue;o.index=s+n,a.index=s+n+e,c.index=o.traceAtomIndex,l.index=a.traceAtomIndex;const h=c.distanceTo(l);if(Math.abs(h-i[e-2])>r)return!1}return!0},i=function(e,i){return t(e,i,[5.45,5.18,6.37],2.1)},r=function(e,i){return t(e,i,[6.1,10.4,13],1.42)};return function(t){Te&&Ie.time("calculateSecondaryStructure"),t.eachPolymer((function(t){if(t.residueCount<4)return;if(t.isCg())!function(t){const i=t.residueStore,r=t.residueIndexStart,n=new Sa(t).position,s=new e,o=new e;for(let e=0,a=t.residueCount;e1&&n.bending[e]<20&&(i.sstruc[r+e]="h".charCodeAt(0),i.sstruc[r+e+1]="h".charCodeAt(0))}}(t);else{if(!t.isProtein())return;!function(t){const e=t.residueStore,n=t.residueIndexStart;for(let s=0,o=t.residueCount;s=e;)i=Math.floor(i/e),n+=Ua[i%e],r+=1;return r>=5&&Ie.warn("chainname overflow"),n}function ja(t,e=!1){Te&&Ie.time("calculateChainnames");let i=!0;if(t.eachChain((function(t){t.chainname&&(i=!1)})),i){const i=t.modelStore,r=t.chainStore,n=t.residueStore,s=function(t,e,s,o){const a=r.count;for(let t=0;t{h.add(e),t.forEach((t=>{h.add(t)}))}))),t.eachResidue((function(t){if(!e&&l){const e=t.atomCount,n=t.atomOffset;if(e>500)return void Ie.warn("more than 500 atoms, skip residue for auto-bonding",t.qualifiedName());if("auto"===i&&t.hetero)for(let e=t.atomOffset;e{d.forEach((i=>{e.push(t.clone().multiply(i))}))})),h.addPart(e)}else h.addPart(u);const m=new e,f=new Oa("SUPERCELL"),p=Array.prototype.concat.call(l(m.set(1,0,0)),l(m.set(0,1,0)),l(m.set(0,0,1)),l(m.set(-1,0,0)),l(m.set(0,-1,0)),l(m.set(0,0,-1)),l(m.set(1,1,0)),l(m.set(1,0,1)),l(m.set(0,1,1)),l(m.set(-1,-1,0)),l(m.set(-1,0,-1)),l(m.set(0,-1,-1)),l(m.set(1,-1,-1)),l(m.set(1,1,-1)),l(m.set(1,-1,1)),l(m.set(-1,1,1)),l(m.set(-1,-1,1)),l(m.set(-1,1,-1)),l(m.set(0,1,-1)),l(m.set(0,-1,1)),l(m.set(1,0,-1)),l(m.set(-1,0,1)),l(m.set(1,-1,0)),l(m.set(-1,1,0)),l(),l(m.set(1,1,1)),l(m.set(-1,-1,-1)));if(t.biomolDict.NCS){const t=[];p.forEach((function(e){d.forEach((function(i){t.push(e.clone().multiply(i))}))})),f.addPart(t)}else f.addPart(p);t.biomolDict.UNITCELL=h,t.biomolDict.SUPERCELL=f,Te&&Ie.timeEnd("buildUnitcellAssembly")}const Ka=["H","C","O","N","S","P"],Za=["NA","CL","FE"];function Qa(t){let e=t.toUpperCase(),i=0,r=0;for(let t=0;t0)break;++i}else r=t+1;(i>0||r=3&&-1!==Ka.indexOf(e[0])?e[0]:""}function Ja(t){const e=t.bondHash,i=e.countArray,r=e.offsetArray,n=e.indexArray,s=t.getBondProxy();t.eachResidue((function(t){const e=t.residueType;if(void 0!==e.bonds)return;var o=t.atomOffset,a=[],c=[],l=[],h={};const u=o+t.atomCount;t.eachAtom((function(t){const e=t.index,d=r[e];for(let t=0,r=i[e];t=u)continue;let i=s.atomIndex2;if(i=u)continue;if(e>i){const t=i;i=e,e=t}const r=e+"|"+i;void 0===h[r]&&(h[r]=!0,a.push(e-o),c.push(i-o),l.push(s.bondOrder))}})),e.bonds={atomIndices1:a,atomIndices2:c,bondOrders:l}}))}function tc(t,...e){Te&&Ie.time("concatStructures");const i=new Ac(t,""),r=new La(i),n=i.atomStore,s=i.atomMap;n.addField("formalCharge",1,"int8"),n.addField("partialCharge",1,"float32");const o={};let a=0,c=0,l=0;e.forEach((t=>{t.eachAtom((t=>{n.growIfFull(),n.atomTypeId[a]=s.add(t.atomname,t.element),n.x[a]=t.x,n.y[a]=t.y,n.z[a]=t.z,n.serial[a]=t.serial,n.formalCharge[a]=t.formalCharge,n.partialCharge[a]=t.partialCharge,n.altloc[a]=t.altloc,n.occupancy[a]=t.occupancy,n.bfactor[a]=t.bfactor,r.addAtom(t.modelIndex+l,t.chainname,t.chainid,t.resname,t.resno,1===t.hetero,t.sstruc,t.inscode),o[t.index+c]=a,a+=1})),c+=t.atomStore.count,l+=t.modelStore.count}));const h=i.bondStore,u=i.getAtomProxy(),d=i.getAtomProxy();return c=0,e.forEach((t=>{t.eachBond((t=>{u.index=o[t.atomIndex1+c],d.index=o[t.atomIndex2+c],h.addBond(u,d,t.bondOrder)})),c+=t.atomStore.count})),r.finalize(),Xa(i,!0),Wa(i,!0),i.finalizeAtoms(),i.finalizeBonds(),Ja(i),Te&&Ie.timeEnd("concatStructures"),i}const ec=[3,11,19,37,55,87],ic=[4,12,20,38,56,88],rc=[6,15,16,34],nc=[1,7,8,9,17,35,53],sc=[2,10,18,36,54,86],oc=[13,30,31,48,49,50,80,81,82,83,84,85,112],ac=[5,14,32,33,51,52,85],cc=[9,17,35,53,85];class lc{constructor(t,e,i){this.structure=t,this.atomname=e,i=i||Qa(e),this.element=i,this.number=Wn[i]||0,this.vdw=Xn[this.number]||2,this.covalent=Yn[this.number]||1.6}getDefaultValence(){const t=Kn[this.number];return t?t[0]:-1}getValenceList(){return Kn[this.number]||[]}getOuterShellElectronCount(){return Zn[this.number]||2}isMetal(){return this.isAlkaliMetal()||this.isAlkalineEarthMetal()||this.isLanthanide()||this.isActinide()||this.isTransitionMetal()||this.isPostTransitionMetal()}isNonmetal(){return this.isDiatomicNonmetal()||this.isPolyatomicNonmetal()||this.isNobleGas()}isMetalloid(){return ac.includes(this.number)}isHalogen(){return cc.includes(this.number)}isDiatomicNonmetal(){return nc.includes(this.number)}isPolyatomicNonmetal(){return rc.includes(this.number)}isAlkaliMetal(){return ec.includes(this.number)}isAlkalineEarthMetal(){return ic.includes(this.number)}isNobleGas(){return sc.includes(this.number)}isTransitionMetal(){const t=this.number;return t>=21&&t<=29||t>=39&&t<=47||t>=72&&t<=79||t>=104&&t<=108}isPostTransitionMetal(){return oc.includes(this.number)}isLanthanide(){return this.number>=57&&this.number<=71}isActinide(){return this.number>=89&&this.number<=103}}class hc{constructor(t){this.structure=t,this.dict={},this.list=[],this.structure=t}add(t,e){const i=function(t,e){return t+"|"+e}(t=t.toUpperCase(),e=e?e.toUpperCase():Qa(t));let r=this.dict[i];if(void 0===r){const n=new lc(this.structure,t,e);r=this.list.length,this.dict[i]=r,this.list.push(n)}return r}get(t){return this.list[t]}}class uc{constructor(t,e,i,r,n,s){this.structure=t,this.bondReferenceAtomIndices=[],this.resname=e,this.atomTypeIdList=i,this.hetero=r?1:0,this.chemCompType=n,this.bonds=s,this.atomCount=i.length,this.moleculeType=this.getMoleculeType(),this.backboneType=this.getBackboneType(0),this.backboneEndType=this.getBackboneType(-1),this.backboneStartType=this.getBackboneType(1),this.backboneIndexList=this.getBackboneIndexList();const o=us[this.backboneType],a=us[this.backboneStartType],c=us[this.backboneEndType],l=this.getAtomIndexByName(o.trace);this.traceAtomIndex=rt(l,-1);const h=this.getAtomIndexByName(o.direction1);this.direction1AtomIndex=rt(h,-1);const u=this.getAtomIndexByName(o.direction2);this.direction2AtomIndex=rt(u,-1);const d=this.getAtomIndexByName(a.backboneStart);this.backboneStartAtomIndex=rt(d,-1);const m=this.getAtomIndexByName(c.backboneEnd);let f;this.backboneEndAtomIndex=rt(m,-1),f=ns.includes(e)?this.getAtomIndexByName("N1"):this.getAtomIndexByName("N3"),this.rungEndAtomIndex=rt(f,-1)}getBackboneIndexList(){const t=[];let e;switch(this.moleculeType){case 3:e=ls;break;case 4:case 5:e=hs;break;default:return t}const i=this.structure.atomMap,r=this.atomTypeIdList;for(let n=0,s=this.atomCount;n500)Te&&Ie.warn("more than 500 atoms, skip residue for auto-bonding",t.qualifiedName());else if(n>50){const e=new Da(t,!0),n=t.isCg()?1.2:2.3;for(let t=s;t=0||pc(t,e);this.rings={atomRings:t.atomRings,rings:t.rings}}isAromatic(t){return this.aromaticAtoms=this.getAromatic(t),1===this.aromaticAtoms[t.index-t.residueAtomOffset]}calculateAromatic(t){const e=this.aromaticAtoms=new Uint8Array(this.atomCount),i=this.getRings().rings,r=i.map((e=>function(t){if(t.some((t=>!dc.includes(t.number))))return!1;let e=0;const i=new co(3,t.length),r=i.data;t.forEach((t=>{r[e+0]=t.x,r[e+1]=t.y,r[e+2]=t.z,e+=3}));return new pa(i).vecC.length()this.structure.getAtomProxy(e+t.atomOffset)))))),n=this.aromaticRings=[];i.forEach(((t,i)=>{r[i]&&(n.push(t),t.forEach((t=>e[t]=1)))}))}assignBondReferenceAtomIndices(){const t=this.getBondGraph(),e=this.getRings(),i=e.atomRings,r=e.rings,n=this.bonds,s=n.atomIndices1,o=n.atomIndices2,a=n.bondOrders,c=this.bondReferenceAtomIndices,l=n.atomIndices1.length;c.length=0;for(let e=0;e1)for(let i=0;i1)for(let i=0;i=0;t--)f[p++]=o[t];const g=t.rings.length;for(let e=0;e0?s[c]!==e&&s[e]!==c&&fc(t,e,c):(r[c]=1,n[a++]=c,s[c]=e)}}}const gc=4;class yc{constructor(t){this.structure=t,this.dict={},this.list=[]}add(t,e,i,r="",n){const s=function(t,e,i,r=""){return t+"|"+e.join(",")+"|"+(i?1:0)+"|"+r}(t=t.toUpperCase(),e,i,r);let o=this.dict[s];if(void 0===o){const a=new uc(this.structure,t,e,i,r,n);o=this.list.length,this.dict[s]=o,this.list.push(a)}return o}get(t){return this.list[t]}}class bc{constructor(t,i=0){this.structure=t,this.index=i,this.bondStore=t.bondStore,this._v12=new e,this._v13=new e,this._ap1=this.structure.getAtomProxy(),this._ap2=this.structure.getAtomProxy(),this._ap3=this.structure.getAtomProxy()}get atom1(){return this.structure.getAtomProxy(this.atomIndex1)}get atom2(){return this.structure.getAtomProxy(this.atomIndex2)}get atomIndex1(){return this.bondStore.atomIndex1[this.index]}set atomIndex1(t){this.bondStore.atomIndex1[this.index]=t}get atomIndex2(){return this.bondStore.atomIndex2[this.index]}set atomIndex2(t){this.bondStore.atomIndex2[this.index]=t}get bondOrder(){return this.bondStore.bondOrder[this.index]}set bondOrder(t){this.bondStore.bondOrder[this.index]=t}getOtherAtomIndex(t){return t===this.atomIndex1?this.atomIndex2:this.atomIndex1}getOtherAtom(t){return this.structure.getAtomProxy(this.getOtherAtomIndex(t.index))}getReferenceAtomIndex(){const t=this._ap1,e=this._ap2;if(t.index=this.atomIndex1,e.index=this.atomIndex2,t.residueIndex!==e.residueIndex)return;const i=t.index-t.residueAtomOffset,r=e.index-e.residueAtomOffset,n=t.residueType.getBondReferenceAtomIndex(i,r);if(void 0!==n)return n+t.residueAtomOffset;console.warn("No reference atom found",t.index,e.index)}calculateShiftDir(t=new e){const i=this._ap1,r=this._ap2,n=this._ap3,s=this._v12,o=this._v13;i.index=this.atomIndex1,r.index=this.atomIndex2;const a=this.getReferenceAtomIndex();s.subVectors(i,r).normalize(),void 0!==a?(n.index=a,o.subVectors(i,n)):o.copy(i),o.normalize();let c=s.dot(o);return 1-Math.abs(c)<1e-5&&(o.set(1,0,0),c=s.dot(o),1-Math.abs(c)<1e-5&&(o.set(0,1,0),c=s.dot(o))),t.copy(o.sub(s.multiplyScalar(c))).normalize()}qualifiedName(){return this.atomIndex1+"="+this.atomIndex2}clone(){return new bc(this.structure,this.index)}toObject(){return{atomIndex1:this.atomIndex1,atomIndex2:this.atomIndex2,bondOrder:this.bondOrder}}}class _c{constructor(t,e=0){this.structure=t,this.index=e,this.chainStore=t.chainStore,this.residueStore=t.residueStore,this.atomStore=t.atomStore,this.residueMap=t.residueMap,this.atomMap=t.atomMap}get entity(){return this.structure.entityList[this.entityIndex]}get entityIndex(){return this.chainStore.entityIndex[this.chainIndex]}get chain(){return this.structure.getChainProxy(this.chainIndex)}get chainIndex(){return this.residueStore.chainIndex[this.index]}set chainIndex(t){this.residueStore.chainIndex[this.index]=t}get atomOffset(){return this.residueStore.atomOffset[this.index]}set atomOffset(t){this.residueStore.atomOffset[this.index]=t}get atomCount(){return this.residueStore.atomCount[this.index]}set atomCount(t){this.residueStore.atomCount[this.index]=t}get atomEnd(){return this.atomOffset+this.atomCount-1}get modelIndex(){return this.chainStore.modelIndex[this.chainIndex]}get chainname(){return this.chainStore.getChainname(this.chainIndex)}get chainid(){return this.chainStore.getChainid(this.chainIndex)}get resno(){return this.residueStore.resno[this.index]}set resno(t){this.residueStore.resno[this.index]=t}get sstruc(){return this.residueStore.getSstruc(this.index)}set sstruc(t){this.residueStore.setSstruc(this.index,t)}get inscode(){return this.residueStore.getInscode(this.index)}set inscode(t){this.residueStore.setInscode(this.index,t)}get residueType(){return this.residueMap.get(this.residueStore.residueTypeId[this.index])}get resname(){return this.residueType.resname}get hetero(){return this.residueType.hetero}get moleculeType(){return this.residueType.moleculeType}get backboneType(){return this.residueType.backboneType}get backboneStartType(){return this.residueType.backboneStartType}get backboneEndType(){return this.residueType.backboneEndType}get traceAtomIndex(){return this.residueType.traceAtomIndex+this.atomOffset}get direction1AtomIndex(){return this.residueType.direction1AtomIndex+this.atomOffset}get direction2AtomIndex(){return this.residueType.direction2AtomIndex+this.atomOffset}get backboneStartAtomIndex(){return this.residueType.backboneStartAtomIndex+this.atomOffset}get backboneEndAtomIndex(){return this.residueType.backboneEndAtomIndex+this.atomOffset}get rungEndAtomIndex(){return this.residueType.rungEndAtomIndex+this.atomOffset}get x(){let t=0;for(let e=this.atomOffset;e<=this.atomEnd;++e)t+=this.atomStore.x[e];return t/this.atomCount}get y(){let t=0;for(let e=this.atomOffset;e<=this.atomEnd;++e)t+=this.atomStore.y[e];return t/this.atomCount}get z(){let t=0;for(let e=this.atomOffset;e<=this.atomEnd;++e)t+=this.atomStore.z[e];return t/this.atomCount}eachAtom(t,e){const i=this.atomCount,r=this.atomOffset,n=this.structure._ap,s=r+i;if(e&&e.atomOnlyTest){const i=e.atomOnlyTest;for(let e=r;e0)return this.entity.isPolymer();{const t=this.residueType.moleculeType;return 3===t||4===t||5===t}}isHetero(){return 1===this.residueType.hetero}isWater(){return 1===this.residueType.moleculeType}isIon(){return 2===this.residueType.moleculeType}isSaccharide(){return 6===this.residueType.moleculeType}isStandardAminoacid(){return this.residueType.isStandardAminoacid()}isStandardBase(){return this.residueType.isStandardBase()}isHelix(){return Gn.includes(this.sstruc)}isSheet(){return Hn.includes(this.sstruc)}isTurn(){return qn.includes(this.sstruc)&&this.isProtein()}getAtomType(t){return this.atomMap.get(this.atomStore.atomTypeId[t])}getResname1(){return ts[this.resname.toUpperCase()]||"X"}getBackboneType(t){switch(t){case-1:return this.residueType.backboneStartType;case 1:return this.residueType.backboneEndType;default:return this.residueType.backboneType}}getAtomIndexByName(t){let e=this.residueType.getAtomIndexByName(t);return void 0!==e&&(e+=this.atomOffset),e}hasAtomWithName(t){return this.residueType.hasAtomWithName(t)}getAtomnameList(){console.warn("getAtomnameList - might be expensive");const t=this.atomCount,e=this.atomOffset,i=new Array(t);for(let r=0;r=e){const e=rt(t,this.structure.getResidueProxy());if(e.index=i,e.connectedTo(this))return e}else if(i===e-1){const i=this.chainStore.residueCount[this.chainIndex],r=rt(t,this.structure.getResidueProxy());if(r.index=e+i-1,r.connectedTo(this))return r}}getBonds(){return this.residueType.getBonds(this)}getRings(){return this.residueType.getRings()}getAromaticRings(){return this.residueType.getAromaticRings(this)}qualifiedName(t=!1){let e="";return this.resname&&!t&&(e+="["+this.resname+"]"),void 0!==this.resno&&(e+=this.resno),this.inscode&&(e+="^"+this.inscode),this.chain&&(e+=":"+this.chainname),e+="/"+this.modelIndex,e}clone(){return new _c(this.structure,this.index)}toObject(){return{index:this.index,chainIndex:this.chainIndex,atomOffset:this.atomOffset,atomCount:this.atomCount,resno:this.resno,resname:this.resname,sstruc:this.sstruc}}}class xc{constructor(t,e,i){this.structure=t,this.residueIndexStart=e,this.residueIndexEnd=i,this.chainStore=t.chainStore,this.residueStore=t.residueStore,this.atomStore=t.atomStore,this.residueCount=i-e+1;const r=this.structure.getResidueProxy(this.residueIndexStart),n=this.structure.getResidueProxy(this.residueIndexEnd);this.isPrevConnected=void 0!==r.getPreviousConnectedResidue();const s=n.getNextConnectedResidue();this.isNextConnected=void 0!==s,this.isNextNextConnected=void 0!==s&&void 0!==s.getNextConnectedResidue(),this.isCyclic=n.connectedTo(r),this.__residueProxy=this.structure.getResidueProxy()}get chainIndex(){return this.residueStore.chainIndex[this.residueIndexStart]}get modelIndex(){return this.chainStore.modelIndex[this.chainIndex]}get chainname(){return this.chainStore.getChainname(this.chainIndex)}isProtein(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.isProtein()}isCg(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.isCg()}isNucleic(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.isNucleic()}getMoleculeType(){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.moleculeType}getBackboneType(t){return this.__residueProxy.index=this.residueIndexStart,this.__residueProxy.getBackboneType(t)}getAtomIndexByType(t,e){this.isCyclic?-1===t?t=this.residueCount-1:t===this.residueCount&&(t=0):(-1!==t||this.isPrevConnected||(t+=1),t!==this.residueCount||this.isNextNextConnected||(t-=1));const i=this.__residueProxy;let r;switch(i.index=this.residueIndexStart+t,e){case"trace":r=i.traceAtomIndex;break;case"direction1":r=i.direction1AtomIndex;break;case"direction2":r=i.direction2AtomIndex;break;default:r=i.getAtomIndexByName(e)}return r}eachAtom(t,e){this.eachResidue((function(i){i.eachAtom(t,e)}))}eachAtomN(t,e,i){const r=this.residueCount,n=new Array(t);for(let e=0;e1&&t(new xc(s,i,l.index)),i=r)):(o!==Ln&&l.index-i>1&&t(new xc(s,i,l.index)),i=r)}r-i>1&&this.structure.getResidueProxy(i).backboneEndType&&t(new xc(s,i,r))}qualifiedName(){return":"+this.chainname+"/"+this.modelIndex}clone(){return new vc(this.structure,this.index)}toObject(){return{index:this.index,residueOffset:this.residueOffset,residueCount:this.residueCount,chainname:this.chainname}}}class wc{constructor(t,e=0){this.structure=t,this.index=e,this.modelStore=t.modelStore,this.chainStore=t.chainStore,this.residueStore=t.residueStore}get chainOffset(){return this.modelStore.chainOffset[this.index]}set chainOffset(t){this.modelStore.chainOffset[this.index]=t}get chainCount(){return this.modelStore.chainCount[this.index]}set chainCount(t){this.modelStore.chainCount[this.index]=t}get residueOffset(){return this.chainStore.residueOffset[this.chainOffset]}get atomOffset(){return this.residueStore.atomOffset[this.residueOffset]}get chainEnd(){return this.chainOffset+this.chainCount-1}get residueEnd(){return this.chainStore.residueOffset[this.chainEnd]+this.chainStore.residueCount[this.chainEnd]-1}get atomEnd(){return this.residueStore.atomOffset[this.residueEnd]+this.residueStore.atomCount[this.residueEnd]-1}get residueCount(){return 0===this.chainCount?0:this.residueEnd-this.residueOffset+1}get atomCount(){return 0===this.residueCount?0:this.atomEnd-this.atomOffset+1}eachAtom(t,e){this.eachChain((function(i){i.eachAtom(t,e)}),e)}eachResidue(t,e){this.eachChain((function(i){i.eachResidue(t,e)}),e)}eachPolymer(t,e){if(e&&e.chainOnlyTest){const i=e.chainOnlyTest;this.eachChain((function(r){i(r)&&r.eachPolymer(t,e)}))}else this.eachChain((function(i){i.eachPolymer(t,e)}))}eachChain(t,e){const i=this.chainCount,r=this.chainOffset,n=this.structure._cp,s=r+i;if(e&&e.test){const i=e.chainOnlyTest;if(i)for(let e=r;e{const i=3*e;a.index=t,l&&a.positionToArray(l,i),h&&s.atomColorToArray(a,h,i),u&&(u.array[e]=t),d&&(d[e]=n.atomRadius(a)),m&&(m[e]=t)})),o}getBondData(t){const i=Object.assign({},t);i.colorParams&&(i.colorParams.structure=this.getStructure());const r=i.what,n=rt(i.bondSet,this.bondSet),s=rt(i.multipleBond,"off"),o="off"!==s,a="offset"===s,c=rt(i.bondScale,.4),l=rt(i.bondSpacing,1);let h,u;const d={},m=this.getBondProxy();i.bondStore&&(m.bondStore=i.bondStore);const f=this.getAtomProxy(),p=this.getAtomProxy();let g;if(o){const t=m.bondStore.bondOrder;g=0,n.forEach((function(e){g+=t[e]}))}else g=n.getSize();r&&!r.position||(d.position1=new Float32Array(3*g),d.position2=new Float32Array(3*g)),r&&!r.color||!i.colorParams||(d.color=new Float32Array(3*g),d.color2=new Float32Array(3*g),u=$e.getScheme(i.colorParams)),r&&!r.picking||(d.picking=new Ys(new Float32Array(g),this.getStructure(),i.bondStore)),(!r||r.radius||o&&r.position)&&(h=new da(i.radiusParams)),r&&!r.radius||(d.radius=new Float32Array(g),i.radius2&&(d.radius2=new Float32Array(g)));const{position1:y,position2:b,color:_,color2:x,picking:v,radius:w,radius2:A}=d;let S,C,P,I,k,M,T=0;const D=new e,B=new e,F=new e;return n.forEach((t=>{if(C=3*T,m.index=t,f.index=m.atomIndex1,p.index=m.atomIndex2,I=m.bondOrder,y)if(o&&I>1){const t=h.atomRadius(f);M=t*c/(.5*I),m.calculateShiftDir(F),a?(k=2*l*t,F.multiplyScalar(k),F.negate(),B.subVectors(p,f).multiplyScalar(Math.max(.1,k/1.88)),f.positionToArray(y,C),p.positionToArray(b,C),I>=2&&(D.addVectors(f,F).add(B).toArray(y,C+3),D.addVectors(p,F).sub(B).toArray(b,C+3),I>=3&&(D.subVectors(f,F).add(B).toArray(y,C+6),D.subVectors(p,F).sub(B).toArray(b,C+6)))):(k=(l-c)*t,F.multiplyScalar(k),2===I?(D.addVectors(f,F).toArray(y,C),D.subVectors(f,F).toArray(y,C+3),D.addVectors(p,F).toArray(b,C),D.subVectors(p,F).toArray(b,C+3)):3===I?(f.positionToArray(y,C),D.addVectors(f,F).toArray(y,C+3),D.subVectors(f,F).toArray(y,C+6),p.positionToArray(b,C),D.addVectors(p,F).toArray(b,C+3),D.subVectors(p,F).toArray(b,C+6)):(f.positionToArray(y,C),p.positionToArray(b,C)))}else f.positionToArray(y,C),p.positionToArray(b,C);if(_&&x&&(u.bondColorToArray(m,1,_,C),u.bondColorToArray(m,0,x,C),o&&I>1))for(S=1;S1))for(S=1;S1))for(M=w[T]*c/(a?1:.5*I),S=a?1:0;S1))for(M=A[T]*c/(a?1:.5*I),S=a?1:0;S{const e=t.x,a=t.y,l=t.z;es&&(s=e),a>o&&(o=a),l>c&&(c=l)}),t),e.min.set(i,r,n),e.max.set(s,o,c),Te&&Ie.timeEnd("getBoundingBox"),e}getPrincipalAxes(t){Te&&Ie.time("getPrincipalAxes");let e=0;const i=new co(3,this.atomCount),r=i.data;return this.eachAtom((t=>{r[e+0]=t.x,r[e+1]=t.y,r[e+2]=t.z,e+=3}),t),Te&&Ie.timeEnd("getPrincipalAxes"),new pa(i)}atomCenter(t){return t?this.getBoundingBox(t).getCenter(new e):this.center.clone()}hasCoords(){if(void 0===this._hasCoords){const t=this.atomStore;this._hasCoords=0!==Ti(t.x)||0!==Mi(t.x)||0!==Ti(t.y)||0!==Mi(t.y)||0!==Ti(t.z)||0!==Mi(t.z)||t.count/this.modelStore.count==1}return this._hasCoords}getSequence(t){const e=[],i=this.getResidueProxy();return this.eachAtom((function(t){i.index=t.residueIndex,t.index===i.traceAtomIndex&&e.push(i.getResname1())}),t),e}getAtomIndices(t){if(t&&t.string){const e=[];return this.eachAtom((function(t){e.push(t.index)}),t),new Uint32Array(e)}{const t={what:{index:!0}};return this.getAtomData(t).index}}getChainnameCount(t){const e=new Set;return this.eachChain((function(t){t.residueCount&&e.add(t.chainname)}),t),e.size}updatePosition(t,e=!0){let i=0;this.eachAtom((function(e){e.positionFromArray(t,i),i+=3}),void 0),this._hasCoords=void 0,e&&this.refreshPosition()}refreshPosition(){this.getBoundingBox(void 0,this.boundingBox),this.boundingBox.getCenter(this.center),this.spatialHash=new Mn(this.atomStore,this.boundingBox),this.signals.refreshed.dispatch(this)}dispose(){this.frames&&(this.frames.length=0),this.boxes&&(this.boxes.length=0),this.bondStore.dispose(),this.backboneBondStore.dispose(),this.rungBondStore.dispose(),this.atomStore.dispose(),this.residueStore.dispose(),this.chainStore.dispose(),this.modelStore.dispose(),delete this.bondSet,delete this.atomSet}}const Sc=new a,Cc=[wn,bn,An,vn,Sn,_n,yn,xn,Pn,Cn,In,kn],Pc={aspectRatio:1.5,sphereDetail:2,radialSegments:50,disableImpostor:!1,openEnded:!1,dashedCylinder:!1,labelParams:{},pointSize:2,sizeAttenuation:!1,useTexture:!0,linewidth:2};class Ic{constructor(t="shape",e={}){this.boundingBox=new a,this.bufferList=[],this.meshCount=0,this._primitiveData={},this.name=t,this.parameters=nt(e,Pc),Cc.forEach((t=>{Object.keys(t.fields).forEach((e=>{this._primitiveData[t.getShapeKey(e)]=[]})),this._primitiveData[t.getShapeKey("name")]=[]}))}addBuffer(t){this.bufferList.push(t);const e=t.geometry;return e.boundingBox||e.computeBoundingBox(),this.boundingBox.union(e.boundingBox),this}addMesh(t,e,i,r,n){let s;t=At(t),e=At(e),Array.isArray(i)&&(i=yt(i,t.length)),r&&(r=At(r)),s=void 0===r||0==r.length?{position:t,color:e,index:i}:{position:t,color:e,index:i,normal:r};const o=new to(this,Object.assign({serial:this.meshCount,name:n},s)),a=new Uo(Object.assign({picking:o},s));return this.bufferList.push(a),Sc.setFromArray(t),this.boundingBox.union(Sc),this.meshCount+=1,this}addSphere(t,e,i,r){return yn.objectToShape(this,{position:t,color:e,radius:i,name:r}),this}addEllipsoid(t,e,i,r,n,s){return Sn.objectToShape(this,{position:t,color:e,radius:i,majorAxis:r,minorAxis:n,name:s}),this}addTorus(t,e,i,r,n,s){return Cn.objectToShape(this,{position:t,color:e,radius:i,majorAxis:r,minorAxis:n,name:s}),this}addCylinder(t,e,i,r,n){return vn.objectToShape(this,{position1:t,position2:e,color:i,radius:r,name:n}),this}addCone(t,e,i,r,n){return An.objectToShape(this,{position1:t,position2:e,color:i,radius:r,name:n}),this}addArrow(t,e,i,r,n){return wn.objectToShape(this,{position1:t,position2:e,color:i,radius:r,name:n}),this}addBox(t,e,i,r,n,s){return bn.objectToShape(this,{position:t,color:e,size:i,heightAxis:r,depthAxis:n,name:s}),this}addOctahedron(t,e,i,r,n,s){return _n.objectToShape(this,{position:t,color:e,size:i,heightAxis:r,depthAxis:n,name:s}),this}addTetrahedron(t,e,i,r,n,s){return xn.objectToShape(this,{position:t,color:e,size:i,heightAxis:r,depthAxis:n,name:s}),this}addText(t,e,i,r){return Pn.objectToShape(this,{position:t,color:e,size:i,text:r}),this}addPoint(t,e,i){return In.objectToShape(this,{position:t,color:e,name:i}),this}addWideline(t,e,i,r,n){return this.parameters.linewidth=r,kn.objectToShape(this,{position1:t,position2:e,color:i,name:n}),this}addLabel(t,e,i,r){return console.warn("Shape.addLabel is deprecated, use .addText instead"),this.addText(t,e,i,r)}getBufferList(){const t=[];return Cc.forEach((e=>{this._primitiveData[e.getShapeKey("color")].length&&t.push(e.bufferFromShape(this,this.parameters))})),this.bufferList.concat(t)}dispose(){this.bufferList.forEach((function(t){t.dispose()})),this.bufferList.length=0,Cc.forEach((t=>{Object.keys(t.fields).forEach((e=>{this._primitiveData[t.getShapeKey(e)].length=0})),this._primitiveData[t.getShapeKey("name")].length=0}))}get center(){return this._center||(this._center=this.boundingBox.getCenter(new e)),this._center}get type(){return"Shape"}}class kc extends Lr{constructor(t,e,i){Array.isArray(t)||(t=[t]),super(t,e,i),this.type="buffer",this.parameters=Object.assign({},this.parameters,{colorScheme:null,colorScale:null,colorValue:null,colorDomain:null,colorMode:null}),this.buffer=t,this.init(i)}init(t){super.init(t),this.build()}create(){this.bufferList.push.apply(this.bufferList,this.buffer)}attach(t){this.bufferList.forEach((t=>{this.viewer.add(t),t.setParameters(this.getBufferParams())})),this.setVisibility(this.visible),t()}}const Mc=new i,Tc=new B;class Dc extends Uo{constructor(t,e={},i){super(function(t,e){const i=e.attributes.position.array,r=e.index?e.index.array:void 0,n=t.position.length/3,s=i.length/3,o=n*s,a=new Float32Array(3*o),c=new Float32Array(3*o),l=new Float32Array(3*o);let h;return r&&(h=yt(n*r.length,o)),{position:a,color:l,index:h,normal:c,primitiveId:t.primitiveId||Ci(n,s),picking:t.picking}}(t,i),e),this.updateNormals=!1;const r=i.attributes.position.array,n=i.attributes.normal.array,s=i.index?i.index.array:void 0;this.geoPosition=r,this.geoNormal=n,this.geoIndex=s,this.positionCount=t.position.length/3,this.geoPositionCount=r.length/3,this.transformedGeoPosition=new Float32Array(3*this.geoPositionCount),this.transformedGeoNormal=new Float32Array(3*this.geoPositionCount);const o=this.geometry.attributes;if(this.meshPosition=o.position.array,this.meshColor=o.color.array,this.meshNormal=o.normal.array,this.setAttributes(t),s){const t=this.geometry.getIndex();if(!t)return void Ie.error("Index is null");this.meshIndex=t.array,this.makeIndex()}}setAttributes(t={},e=!1){const i=this.geometry.attributes;let r,n,s,o,a,c,l,h,u;const d=this.updateNormals;t.position&&(r=t.position,s=this.geoPosition,l=this.meshPosition,a=this.transformedGeoPosition,i.position.needsUpdate=!0,(d||e)&&(o=this.geoNormal,u=this.meshNormal,c=this.transformedGeoNormal,i.normal.needsUpdate=!0)),t.color&&(n=t.color,h=this.meshColor,i.color.needsUpdate=!0);const m=this.positionCount,f=this.geoPositionCount;for(let t=0;t 0.0 ){\ncameraPos = rayDirection * posT + rayOrigin;\ninterior = true;\nflag2 = true;\n}\n#else\nif( calcDepth( cameraPos ) <= 0.0 ){\ncameraPos = rayDirection * posT + rayOrigin;\ninterior = true;\n}\n#endif\ncameraNormal = normalize( cameraPos - cameraSpherePos );\ncameraNormal *= float(!interior) * 2.0 - 1.0;\nreturn !interior;\n}\nvoid main(void){\nbool flag = Impostor( cameraPos, cameraNormal );\n#ifdef NEAR_CLIP\nif( calcClip( cameraPos ) > 0.0 )\ndiscard;\n#endif\ngl_FragDepthEXT = calcDepth( cameraPos );\nif( !flag ){\n#ifdef NEAR_CLIP\nif( flag2 ){\ngl_FragDepthEXT = max( 0.0, calcDepth( vec3( - ( clipNear - 0.5 ) ) ) + ( 0.0000001 / vRadius ) );\n}else if( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n#else\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n#endif\n}\nif (gl_FragDepthEXT < 0.0)\ndiscard;\nif (gl_FragDepthEXT > 1.0)\ndiscard;\n#ifdef PICKING\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 vNormal = cameraNormal;\nvec3 vViewPosition = -cameraPos;\nvec4 diffuseColor = vec4( diffuse, opacity );\nReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\nvec3 totalEmissiveLight = emissive;\n#include color_fragment\n#include roughnessmap_fragment\n#include metalnessmap_fragment\n#include normal_fragment_begin\n#include lights_physical_fragment\n#include lights_fragment_begin\n#include lights_fragment_end\nvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveLight;\nif( interior ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");class $c extends zo{constructor(t,e,i={}){super(e,i),this.index=yt(this.indexSize,this.attributeSize),this.makeIndex(),this.initIndex(this.index),this.addAttributes({mapping:{type:t,value:null}}),this.setAttributes({primitiveId:Si(this.size)})}get attributeSize(){return this.size*this.mappingSize}get indexSize(){return this.size*this.mappingIndicesSize}addAttributes(t){const e={};for(const i in t){const r=t[i];e[i]={type:r.type,value:null}}super.addAttributes(e)}getAttributeIndex(t){return 3*t*this.mappingSize}setAttributes(t){t&&!t.position&&t.position1&&t.position2&&(t.position=xi(t.position1,t.position2));const e=this.size,i=this.mappingSize,r=this.geometry.attributes;let n,s,o,a,c,l,h;for(const u in t)if("index"!==u&&"picking"!==u){s=t[u],n=r[u],o=n.itemSize,a=n.array;for(let t=0;t0&&this.parameters.alphaTest<=1&&(e.USE_ALPHATEST=1),e}setUniforms(t){t&&void 0!==t.edgeBleach&&(this.makeTexture(),t.map=this.tex),super.setUniforms(t)}dispose(){super.dispose(),this.tex&&this.tex.dispose()}}Ve.add("point",Gc);class Hc extends Lr{constructor(t,e,i){super(t,e,i),this.type="dot",this.parameters=Object.assign({thresholdType:{type:"select",rebuild:!0,options:{value:"value",sigma:"sigma"}},thresholdMin:{type:"number",precision:3,max:1/0,min:-1/0,rebuild:!0},thresholdMax:{type:"number",precision:3,max:1/0,min:-1/0,rebuild:!0},thresholdOut:{type:"boolean",rebuild:!0},dotType:{type:"select",rebuild:!0,options:{"":"",sphere:"sphere",point:"point"}},radiusType:{type:"select",options:{"":"",value:"value","abs-value":"abs-value","value-min":"value-min",deviation:"deviation",size:"size"}},radius:{type:"number",precision:3,max:10,min:.001,property:"size"},scale:{type:"number",precision:3,max:10,min:.001},sphereDetail:!0,disableImpostor:!0,pointSize:{type:"number",precision:1,max:100,min:0,buffer:!0},sizeAttenuation:{type:"boolean",buffer:!0},sortParticles:{type:"boolean",rebuild:!0},useTexture:{type:"boolean",buffer:!0},alphaTest:{type:"range",step:.001,max:1,min:0,buffer:!0},forceTransparent:{type:"boolean",buffer:!0},edgeBleach:{type:"range",step:.001,max:1,min:0,buffer:!0}},this.parameters,{colorScheme:{type:"select",update:"color",options:{"":"",value:"value",uniform:"uniform",random:"random"}}}),t instanceof Eo?(this.surface=void 0,this.volume=new ga(t)):(this.surface=t,this.volume=void 0),this.init(i)}init(t){var e=t||{};e.colorScheme=rt(e.colorScheme,"uniform"),e.colorValue=rt(e.colorValue,14540253),this.thresholdType=rt(e.thresholdType,"sigma"),this.thresholdMin=rt(e.thresholdMin,2),this.thresholdMax=rt(e.thresholdMax,1/0),this.thresholdOut=rt(e.thresholdOut,!1),this.dotType=rt(e.dotType,"point"),this.radius=rt(e.radius,.1),this.scale=rt(e.scale,1),this.pointSize=rt(e.pointSize,1),this.sizeAttenuation=rt(e.sizeAttenuation,!0),this.sortParticles=rt(e.sortParticles,!1),this.useTexture=rt(e.useTexture,!1),this.alphaTest=rt(e.alphaTest,.5),this.forceTransparent=rt(e.forceTransparent,!1),this.edgeBleach=rt(e.edgeBleach,0),super.init(e),this.build()}attach(t){this.bufferList.forEach((t=>{this.viewer.add(t)})),this.setVisibility(this.visible),t()}create(){var t={};if(this.volume){var e,i,r=this.volume;"sigma"===this.thresholdType?(e=r.getValueForSigma(this.thresholdMin),i=r.getValueForSigma(this.thresholdMax)):(e=this.thresholdMin,i=this.thresholdMax),r.setFilter(e,i,this.thresholdOut),Object.assign(t,{position:r.getDataPosition(),color:r.getDataColor(this.getColorParams())}),"sphere"===this.dotType&&Object.assign(t,{radius:r.getDataSize(this.radius,this.scale),picking:r.getDataPicking()})}else{var n=this.surface;Object.assign(t,{position:n.getPosition(),color:n.getColor(this.getColorParams())}),"sphere"===this.dotType&&Object.assign(t,{radius:n.getSize(this.radius,this.scale),picking:n.getPicking()})}"sphere"===this.dotType?this.dotBuffer=new zc(t,this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!1})):this.dotBuffer=new Gc(t,this.getBufferParams({pointSize:this.pointSize,sizeAttenuation:this.sizeAttenuation,sortParticles:this.sortParticles,useTexture:this.useTexture,alphaTest:this.alphaTest,forceTransparent:this.forceTransparent,edgeBleach:this.edgeBleach})),this.bufferList.push(this.dotBuffer)}update(t={}){if(0===this.bufferList.length)return;const e={};t.color&&(this.volume?Object.assign(e,{color:this.volume.getDataColor(this.getColorParams())}):Object.assign(e,{color:this.surface.getColor(this.getColorParams())})),"sphere"===this.dotType&&(t.radius||t.scale)&&(this.volume?Object.assign(e,{radius:this.volume.getDataSize(this.radius,this.scale)}):Object.assign(e,{radius:this.surface.getSize(this.radius,this.scale)})),this.dotBuffer.setAttributes(e)}setParameters(t,e={},i){return t&&void 0!==t.thresholdType&&this.volume instanceof Eo&&("value"===this.thresholdType&&"sigma"===t.thresholdType?(this.thresholdMin=this.volume.getSigmaForValue(this.thresholdMin),this.thresholdMax=this.volume.getSigmaForValue(this.thresholdMax)):"sigma"===this.thresholdType&&"value"===t.thresholdType&&(this.thresholdMin=this.volume.getValueForSigma(this.thresholdMin),this.thresholdMax=this.volume.getValueForSigma(this.thresholdMax)),this.thresholdType=t.thresholdType),t&&void 0!==t.radiusType&&("radius"===t.radiusType?this.radius=.1:this.radius=parseFloat(t.radiusType),e.radius=!0,"sphere"!==this.dotType||Ce&&!this.disableImpostor||(i=!0)),t&&void 0!==t.radius&&(e.radius=!0,"sphere"!==this.dotType||Ce&&!this.disableImpostor||(i=!0)),t&&void 0!==t.scale&&(e.scale=!0,"sphere"!==this.dotType||Ce&&!this.disableImpostor||(i=!0)),super.setParameters(t,e,i),this}}Ne.add("shader/Image.vert","uniform float clipRadius;\nuniform vec3 clipCenter;\nvarying vec2 vUv;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvarying vec3 vViewPosition;\n#endif\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\nvoid main() {\n#include begin_vertex\n#include project_vertex\nvUv = uv;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvViewPosition = -mvPosition.xyz;\n#endif\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n}"),Ne.add("shader/Image.frag","uniform sampler2D map;\nuniform float opacity;\nuniform vec2 mapSize;\nuniform float clipNear;\nuniform float clipRadius;\nvarying vec2 vUv;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvarying vec3 vViewPosition;\n#endif\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#if defined( PICKING )\nuniform sampler2D pickingMap;\nuniform float objectId;\n#else\n#include fog_pars_fragment\n#endif\n#if defined( CUBIC_INTERPOLATION )\n#if defined( CATMULROM_FILTER ) || defined( MITCHELL_FILTER )\n#if defined( CATMULROM_FILTER )\nconst float B = 0.0;\nconst float C = 0.5;\n#elif defined( MITCHELL_FILTER )\nconst float B = 0.333;\nconst float C = 0.333;\n#endif\nfloat applyFilter( float x ){\nfloat f = x;\nif( f < 0.0 ){\nf = -f;\n}\nif( f < 1.0 ){\nreturn ( ( 12.0 - 9.0 * B - 6.0 * C ) * ( f * f * f ) +\n( -18.0 + 12.0 * B + 6.0 *C ) * ( f * f ) +\n( 6.0 - 2.0 * B ) ) / 6.0;\n}else if( f >= 1.0 && f < 2.0 ){\nreturn ( ( -B - 6.0 * C ) * ( f * f * f )\n+ ( 6.0 * B + 30.0 * C ) * ( f *f ) +\n( - ( 12.0 * B ) - 48.0 * C ) * f +\n8.0 * B + 24.0 * C ) / 6.0;\n}else{\nreturn 0.0;\n}\n}\n#elif defined( BSPLINE_FILTER )\nfloat applyFilter( float x ){\nfloat f = x;\nif( f < 0.0 ){\nf = -f;\n}\nif( f >= 0.0 && f <= 1.0 ){\nreturn ( 2.0 / 3.0 ) + ( 0.5 ) * ( f * f * f ) - ( f * f );\n}else if( f > 1.0 && f <= 2.0 ){\nreturn 1.0 / 6.0 * pow( ( 2.0 - f ), 3.0 );\n}\nreturn 1.0;\n}\n#else\nfloat applyFilter( float x ){\nreturn 1.0;\n}\n#endif\nvec4 biCubic( sampler2D tex, vec2 texCoord ){\nvec2 texelSize = 1.0 / mapSize;\ntexCoord -= texelSize / 2.0;\nvec4 nSum = vec4( 0.0 );\nfloat nDenom = 0.0;\nvec2 cell = fract( texCoord * mapSize );\nfor( float m = -1.0; m <= 2.0; ++m ){\nfor( float n = -1.0; n <= 2.0; ++n ){\nvec4 vecData = texture2D(\ntex, texCoord + texelSize * vec2( m, n )\n);\nfloat c = applyFilter( m - cell.x ) * applyFilter( -n + cell.y );\nnSum += vecData * c;\nnDenom += c;\n}\n}\nreturn nSum / nDenom;\n}\n#endif\nvoid main(){\n#include nearclip_fragment\n#include radiusclip_fragment\n#if defined( CUBIC_INTERPOLATION )\ngl_FragColor = biCubic( map, vUv );\n#else\ngl_FragColor = texture2D( map, vUv );\n#endif\n#if defined( PICKING )\nif( gl_FragColor.a < 0.3 )\ndiscard;\ngl_FragColor = vec4( texture2D( pickingMap, vUv ).xyz, objectId );\n#else\nif( gl_FragColor.a < 0.01 )\ndiscard;\ngl_FragColor.a *= opacity;\n#include fog_fragment\n#endif\n}");const qc=new Uint16Array([0,1,2,1,3,2]),Wc=new Float32Array([0,1,0,0,1,1,1,0]),Xc=Object.assign({filter:"nearest",forceTransparent:!0},Lo),Yc=Object.assign({filter:{updateShader:!0,uniform:!0}},No);class Kc extends zo{constructor(e,i){super({position:e.position,index:qc,picking:e.picking},i),this.parameterTypes=Yc,this.alwaysTransparent=!0,this.hasWireframe=!1,this.vertexShader="Image.vert",this.fragmentShader="Image.frag";const{imageData:r,width:n,height:s}=e,o=new V(r,n,s);o.flipY=!0,this.tex=o;const a=r.length,c=new Uint8Array(a);for(let t=0;t>16&255,c[t+1]=e>>8&255,c[t+2]=255&e}const l=new V(c,n,s);l.flipY=!0,l.minFilter=b,l.magFilter=b,this.pickingTex=l,this.addUniforms({map:{value:o},pickingMap:{value:l},mapSize:{value:new t(n,s)}}),this.geometry.setAttribute("uv",new M(Wc,2))}get defaultParameters(){return Xc}getDefines(t){const e=super.getDefines(t),i=this.parameters.filter;return i.startsWith("cubic")&&(e.CUBIC_INTERPOLATION=1,i.endsWith("bspline")?e.BSPLINE_FILTER=1:i.endsWith("catmulrom")?e.CATMULROM_FILTER=1:i.endsWith("mitchell")&&(e.MITCHELL_FILTER=1)),e}updateTexture(){const t=this.tex,e=this.parameters.filter;e.startsWith("cubic")?(t.minFilter=b,t.magFilter=b):"linear"===e?(t.minFilter=v,t.magFilter=v):(t.minFilter=b,t.magFilter=b),t.needsUpdate=!0,this.pickingTex.needsUpdate=!0}makeMaterial(){super.makeMaterial(),this.updateTexture();const t=this.material;t.uniforms.map.value=this.tex,t.blending=j,t.needsUpdate=!0;const e=this.wireframeMaterial;e.uniforms.map.value=this.tex,e.blending=j,e.needsUpdate=!0;const i=this.pickingMaterial;i.uniforms.map.value=this.tex,i.uniforms.pickingMap.value=this.pickingTex,i.blending=j,i.needsUpdate=!0}setUniforms(t){t&&void 0!==t.filter&&(this.updateTexture(),t.map=this.tex),super.setUniforms(t)}}class Zc{constructor(t,e){const i=e||{};this.dimension=rt(i.dimension,"x"),this.positionType=rt(i.positionType,"percent"),this.position=rt(i.position,30),this.thresholdType=rt(i.thresholdType,"sigma"),this.thresholdMin=rt(i.thresholdMin,-1/0),this.thresholdMax=rt(i.thresholdMax,1/0),this.normalize=rt(i.normalize,!1),this.volume=t}getPositionFromCoordinate(t){const i=this.dimension,r=this.volume,n=r.matrix,s=(new e).setFromMatrixPosition(n)[i],o=(new e).setFromMatrixScale(n)[i];let a;return a="x"===i?r.nx:"y"===i?r.ny:r.nz,Math.round(((t-s)/(a/100)+1)/o)}getData(t){t=t||{};const i=this.volume,r=i.data,n=i.matrix;let s;function o(t){return Math.round(t/100*(s-1))}function a(t,e,r,n){return 3*(r*i.ny*i.nx+e*i.nx+t)+n}s="coordinate"===this.positionType?this.getPositionFromCoordinate(this.position):this.position;const c=new Float32Array(12),l=new e;let h,u,d,m,f,p=0,g=0,y=0,b=i.nx,_=i.ny,x=i.nz;function v(t,e,i,r){l.set(t,e,i).applyMatrix4(n).toArray(c,r)}"x"===this.dimension?(d=o(i.nx),m=i.ny-1,f=i.nz-1,h=i.nz,u=i.ny,p=d,b=p+1,v(d,0,0,0),v(d,m,0,3),v(d,0,f,6),v(d,m,f,9)):"y"===this.dimension?(d=i.nx-1,m=o(i.ny),f=i.nz-1,h=i.nz,u=i.nx,g=m,_=g+1,v(0,m,0,0),v(d,m,0,3),v(0,m,f,6),v(d,m,f,9)):"z"===this.dimension&&(d=i.nx-1,m=i.ny-1,f=o(i.nz),h=i.nx,u=i.ny,y=f,x=y+1,v(0,0,f,0),v(0,m,f,3),v(d,0,f,6),v(d,m,f,9));let w=0,A=0;const S=new Uint8Array(h*u*4),C=new Float32Array(h*u);let P,I;"sigma"===this.thresholdType?(P=i.getValueForSigma(this.thresholdMin),I=i.getValueForSigma(this.thresholdMax)):(P=this.thresholdMin,I=this.thresholdMax);const k=Object.assign({},t.colorParams,{volume:i});this.normalize&&(k.domain=[0,1]);const M=$e.getScheme(k),T=new Float32Array(3),D=M.getScale();let B,F=0,E=0;if(this.normalize){F=1/0,B=-1/0;for(let t=g;t<_;++t)for(let e=p;eB&&(B=n)}E=B-F}for(let t=g;t<_;++t)for(let e=p;eP&&s{this.viewer.add(t)})),this.setVisibility(this.visible),t()}create(){const t=new Zc(this.volume,{positionType:this.positionType,position:this.position,dimension:this.dimension,thresholdType:this.thresholdType,thresholdMin:this.thresholdMin,thresholdMax:this.thresholdMax,normalize:this.normalize}),e=new Kc(t.getData({colorParams:this.getColorParams()}),this.getBufferParams({filter:this.filter}));this.bufferList.push(e)}}function Jc(t){Ie.error(`makeRepresentation: representation type ${t} unknown`)}const tl={name:"some element",status:""};class el{constructor(t,e={}){this.stage=t,this.signals={statusChanged:new tt,nameChanged:new tt,disposed:new tt},this.parameters=nt(e,this.defaultParameters),this.uuid=Mt()}get defaultParameters(){return tl}get name(){return this.parameters.name}setStatus(t){return this.parameters.status=t,this.signals.statusChanged.dispatch(t),this}setName(t){return this.parameters.name=t,this.signals.nameChanged.dispatch(t),this}dispose(){this.signals.disposed.dispatch()}}const il=Object.assign({visible:!0},tl);class rl extends el{constructor(t,e,i={},r){super(t,Object.assign({name:e.type},i)),this.parent=r,this.signals=Object.assign({visibilityChanged:new tt,parametersChanged:new tt},this.signals),this.setRepresentation(e)}get defaultParameters(){return il}get visible(){return this.parameters.visible}get type(){return"representation"}getType(){return this.repr.type}setRepresentation(t){this._disposeRepresentation(),this.repr=t,this.stage.tasks.listen(this.repr.tasks),this.updateVisibility()}_disposeRepresentation(){this.repr&&(this.stage.tasks.unlisten(this.repr.tasks),this.repr.dispose())}dispose(){this.parent&&this.parent.hasRepresentation(this)?this.parent.removeRepresentation(this):(this._disposeRepresentation(),this.signals.disposed.dispatch())}setVisibility(t){return this.parameters.visible=t,this.updateVisibility(),this.signals.visibilityChanged.dispatch(this.parameters.visible),this}getVisibility(){return this.parent?this.parent.parameters.visible&&this.parameters.visible:this.parameters.visible}toggleVisibility(){return this.setVisibility(!this.parameters.visible)}updateVisibility(){this.repr.setVisibility(this.getVisibility())}update(t){return this.repr.update(t),this}build(t){return this.repr.build(t),this}setSelection(t){const e=this.repr;return e.setSelection&&e.setSelection(t),this}setParameters(t){return this.repr.setParameters(t),this.signals.parametersChanged.dispatch(this.repr.getParameters()),this}getParameters(){return this.repr.getParameters()}setColor(t){return this.repr.setColor(t),this}}const nl=new i,sl=new e,ol={name:"",status:"",visible:!0};class al{constructor(t,n,s={}){this.stage=t,this.object=n,this.signals={representationAdded:new tt,representationRemoved:new tt,visibilityChanged:new tt,matrixChanged:new tt,statusChanged:new tt,nameChanged:new tt,disposed:new tt},this.reprList=[],this.annotationList=[],this.matrix=new i,this.position=new e,this.quaternion=new r,this.scale=new e(1,1,1),this.transform=new i,this.parameters=nt(s,this.defaultParameters),this.uuid=Mt(),this.viewer=t.viewer,this.controls=new ha(this)}get defaultParameters(){return ol}get name(){return this.parameters.name}get status(){return this.parameters.status}get visible(){return this.parameters.visible}setPosition(t){return Array.isArray(t)?this.position.fromArray(t):this.position.copy(t),this.updateMatrix(),this}setRotation(t){if(Array.isArray(t))if(3===t.length){const e=(new G).fromArray(t);this.quaternion.setFromEuler(e)}else this.quaternion.fromArray(t);else t instanceof G?this.quaternion.setFromEuler(t):this.quaternion.copy(t);return this.updateMatrix(),this}setScale(t){return this.scale.set(t,t,t),this.updateMatrix(),this}setTransform(t){return this.transform.copy(t),this.updateMatrix(),this}updateMatrix(){const t=this.getCenterUntransformed(sl);this.matrix.makeTranslation(-t.x,-t.y,-t.z),nl.makeRotationFromQuaternion(this.quaternion),this.matrix.premultiply(nl),nl.makeScale(this.scale.x,this.scale.y,this.scale.z),this.matrix.premultiply(nl);const e=this.position;nl.makeTranslation(e.x+t.x,e.y+t.y,e.z+t.z),this.matrix.premultiply(nl),this.matrix.premultiply(this.transform),this.updateRepresentationMatrices(),this.stage.viewer.updateBoundingBox(),this.signals.matrixChanged.dispatch(this.matrix)}updateRepresentationMatrices(){this.reprList.forEach((t=>{t.setParameters({matrix:this.matrix})}))}addAnnotation(t,e,i){const r=new oa(this,t,e,i);return this.annotationList.push(r),r}eachAnnotation(t){this.annotationList.slice().forEach(t)}removeAnnotation(t){const e=this.annotationList.indexOf(t);-1!==e&&(this.annotationList.splice(e,1),t.dispose())}removeAllAnnotations(){this.eachAnnotation((t=>t.dispose())),this.annotationList.length=0}_addRepresentation(t,e,i,r=!1){const n=i||{},s=this.stage.getParameters();n.matrix=this.matrix.clone(),n.quality=n.quality||s.quality,n.disableImpostor=rt(n.disableImpostor,!s.impostor),n.useWorker=rt(n.useWorker,s.workerDefault),n.visible=rt(n.visible,!0);const o=Object.assign({},n,{visible:this.parameters.visible&&n.visible}),a=function(t,e,i,r){var n;if(Te&&Ie.time("makeRepresentation "+t),e instanceof Ac){if(!(n=Re.get(t)))return void Jc(t)}else if(e instanceof Bo)if("surface"===t)n=Wo;else{if("dot"!==t)return void Jc(t);n=Hc}else if(e instanceof Eo)if("surface"===t)n=Wo;else if("dot"===t)n=Hc;else{if("slice"!==t)return void Jc(t);n=Qc}else if(e instanceof Ic)n=kc,e=e.getBufferList();else{if("buffer"!==t)return void Ie.error("makeRepresentation: object "+e+" unknown");n=kc}const s=new n(e,i,r);return Te&&Ie.timeEnd("makeRepresentation "+t),s}(t,e,this.viewer,o),c=new rl(this.stage,a,n,this);return r||(this.reprList.push(c),this.signals.representationAdded.dispatch(c)),c}addBufferRepresentation(t,e){return this._addRepresentation.call(this,"buffer",t,e)}hasRepresentation(t){return-1!==this.reprList.indexOf(t)}eachRepresentation(t){this.reprList.slice().forEach(t)}removeRepresentation(t){const e=this.reprList.indexOf(t);-1!==e&&(this.reprList.splice(e,1),t.dispose(),this.signals.representationRemoved.dispatch(t))}updateRepresentations(t){this.reprList.forEach((e=>e.update(t))),this.stage.viewer.requestRender()}removeAllRepresentations(){this.eachRepresentation((t=>t.dispose()))}dispose(){this.removeAllAnnotations(),this.removeAllRepresentations(),this.reprList.length=0,this.signals.disposed.dispatch()}setVisibility(t){return this.parameters.visible=t,this.eachRepresentation((t=>t.updateVisibility())),this.eachAnnotation((t=>t.updateVisibility())),this.signals.visibilityChanged.dispatch(t),this}setStatus(t){return this.parameters.status=t,this.signals.statusChanged.dispatch(t),this}setName(t){return this.parameters.name=t,this.signals.nameChanged.dispatch(t),this}getBox(...t){return this.getBoxUntransformed(...t).clone().applyMatrix4(this.matrix)}getCenter(...t){return this.getCenterUntransformed(...t).clone().applyMatrix4(this.matrix)}getZoom(...t){return this.stage.getZoomForBox(this.getBox(...t))}getBoxUntransformed(...t){return new a}getCenterUntransformed(...t){return this.getBoxUntransformed().getCenter(new e)}autoView(t){this.stage.animationControls.zoomMove(this.getCenter(),this.getZoom(),rt(t,0))}}class cl{constructor(t=[]){this.list=t;const e=t.length;for(let i=0;i0?this.list[0]:void 0}forEach(t){return this.list.forEach(t),this}dispose(){return this.forEach((t=>t.dispose()))}}class ll extends cl{setParameters(t){return this.forEach((e=>e.setParameters(t)))}setVisibility(t){return this.forEach((e=>e.setVisibility(t)))}setSelection(t){return this.forEach((e=>e.setSelection(t)))}setColor(t){return this.forEach((e=>e.setColor(t)))}update(t){return this.forEach((e=>e.update(t)))}build(t){return this.forEach((e=>e.build(t)))}dispose(t){return this.forEach((t=>t.dispose()))}}const hl=Object.assign({defaultStep:1,defaultTimeout:50,defaultInterpolateType:"",defaultInterpolateStep:5,defaultMode:"loop",defaultDirection:"forward",initialFrame:0},tl);class ul extends el{constructor(t,e,i={}){super(t,Object.assign({name:e.name},i)),this.trajectory=e,this.signals=Object.assign(this.signals,{frameChanged:new tt,playerChanged:new tt,countChanged:new tt,parametersChanged:new tt}),e.signals.frameChanged.add((t=>{this.signals.frameChanged.dispatch(t)})),e.signals.playerChanged.add((t=>{this.signals.playerChanged.dispatch(t)})),e.signals.countChanged.add((t=>{this.signals.countChanged.dispatch(t)})),void 0!==i.initialFrame&&this.setFrame(i.initialFrame)}get defaultParameters(){return hl}get type(){return"trajectory"}setFrame(t){this.trajectory.setFrame(t)}setParameters(t={}){this.trajectory.setParameters(t),this.signals.parametersChanged.dispatch(t)}dispose(){this.trajectory.dispose(),super.dispose()}}class dl{constructor(t,e){this.name=t,this.path=e,this.coordinates=[],this.boxes=[],this.times=[],this.timeOffset=0,this.deltaTime=1}get type(){return"Frames"}}class ml{constructor(t,e){let r,n;if(this.A=new co(3,3),this.W=new co(1,3),this.U=new co(3,3),this.V=new co(3,3),this.VH=new co(3,3),this.R=new co(3,3),this.tmp=new co(3,3),this.c=new co(3,3),t instanceof Ac)r=t.atomCount;else{if(!(t instanceof Float32Array))return;r=t.length/3}if(e instanceof Ac)n=e.atomCount;else{if(!(e instanceof Float32Array))return;n=e.length/3}const s=Math.min(r,n),o=new co(3,s),a=new co(3,s);this.coords1t=new co(s,3),this.coords2t=new co(s,3),this.transformationMatrix=new i,this.c.data.set([1,0,0,0,1,0,0,0,-1]),this.prepCoords(t,o,s,!1),this.prepCoords(e,a,s,!1),this._superpose(o,a)}_superpose(t,e){this.mean1=mo(t),this.mean2=mo(e),fo(t,this.mean1),fo(e,this.mean2),lo(this.coords1t,t),lo(this.coords2t,e),ho(this.A,this.coords2t,this.coords1t),_o(this.A,this.W,this.U,this.V),function(t,e){const i=t.data,r=e.data,n=i[4],s=i[8],o=i[5],a=i[7],c=i[0],l=c*n,h=c*o,u=i[3],d=i[1],m=u*d,f=i[2],p=u*f,g=i[6],y=g*d,b=g*f,_=1/(l*s-h*a-m*s+p*a+y*o-b*n);r[0]=(n*s-o*a)*_,r[1]=-(d*s-f*a)*_,r[2]=-(-d*o+f*n)*_,r[3]=-(u*s-o*g)*_,r[4]=(c*s-b)*_,r[5]=-(h-p)*_,r[6]=-(-u*a+n*g)*_,r[7]=-(c*a-y)*_,r[8]=(l-m)*_}(this.V,this.VH),uo(this.R,this.U,this.VH),function(t){const e=t.data;return e[0]*e[4]*e[8]-e[0]*e[5]*e[7]-e[3]*e[1]*e[8]+e[3]*e[2]*e[7]+e[6]*e[1]*e[5]-e[6]*e[2]*e[4]}(this.R)<0&&(Te&&Ie.log("R not a right handed system"),uo(this.tmp,this.c,this.VH),uo(this.R,this.U,this.tmp));const i=new co(4,4),r=new co(4,4),n=new co(4,4),s=new co(4,4),o=new co(4,4),a=new co(4,4),c=this.R.data,l=this.mean1,h=this.mean2;s.data.set([1,0,0,-l[0],0,1,0,-l[1],0,0,1,-l[2],0,0,0,1]),o.data.set([c[0],c[1],c[2],0,c[3],c[4],c[5],0,c[6],c[7],c[8],0,0,0,0,1]),a.data.set([1,0,0,h[0],0,1,0,h[1],0,0,1,h[2],0,0,0,1]),lo(r,s),ho(i,o,r),lo(n,i),ho(r,a,n),lo(i,r),this.transformationMatrix.elements=i.data}prepCoords(t,e,i,r){let n=0;const s=e.data;let o=3,a=3*i;if(r&&(a=4*i,o=4),t instanceof Ac)t.eachAtom((function(t){n{t!==this&&this.pause()}),this);const i=rt(t.frameCount,1);this.traj=t,this.parameters=nt(e,fl),this.parameters.end=Math.min(rt(e.end,i-1),i-1),this.parameters.step=rt(e.step,Math.ceil((i+1)/100)),this._currentFrame=this.parameters.start,this._direction="bounce"===this.parameters.direction?"forward":this.parameters.direction,t.signals.countChanged.add((t=>{this.parameters.end=Math.min(rt(this.parameters.end,t-1),t-1)}),this),this._animate=this._animate.bind(this)}get isRunning(){return this._run}setParameters(t={}){st(this.parameters,t),void 0!==t.direction&&"bounce"!==this.parameters.direction&&(this._direction=this.parameters.direction)}_animate(){if(!this._run)return;this._currentTime=window.performance.now();const t=this._currentTime-this._previousTime,e=this.parameters.interpolateType?this.parameters.interpolateStep:1,i=this.parameters.timeout/e,r=this.traj;if(r&&r.frameCount&&!r.inProgress&&t>=i)if(this.parameters.interpolateType)if(this._currentStep>this.parameters.interpolateStep&&(this._currentStep=1),1===this._currentStep&&(this._currentFrame=this._nextInterpolated()),r.hasFrame(this._currentFrame)){this._currentStep+=1;const t=this._currentStep/(this.parameters.interpolateStep+1),[e,i,n,s]=this._currentFrame;r.setFrameInterpolated(e,i,n,s,t,this.parameters.interpolateType),this._previousTime=this._currentTime}else r.loadFrame(this._currentFrame);else{const t=this._next();r.hasFrame(t)?(r.setFrame(t),this._previousTime=this._currentTime):r.loadFrame(t)}window.requestAnimationFrame(this._animate)}_next(){const t=this.parameters;let e;return e="forward"===this._direction?this.traj.currentFrame+t.step:this.traj.currentFrame-t.step,(e>t.end||e=t.end?i=t.start:"backward"===t.direction&&e<=t.start&&(i=t.end),this.traj.setFrame(i),this._run=!0,this._animate(),this.signals.startedRunning.dispatch()}}pause(){this._run=!1,this.signals.haltedRunning.dispatch()}stop(){this.pause(),this.traj.setFrame(this.parameters.start)}}class gl{constructor(t,e,i={}){this.signals={countChanged:new tt,frameChanged:new tt,playerChanged:new tt},this.frameCache={},this.loadQueue={},this.boxCache={},this.pathCache={},this.frameCacheSize=0,this._frameCount=0,this._currentFrame=-1,this._disposed=!1,this.deltaTime=rt(i.deltaTime,0),this.timeOffset=rt(i.timeOffset,0),this.centerPbc=rt(i.centerPbc,!1),this.removePbc=rt(i.removePbc,!1),this.removePeriodicity=rt(i.removePeriodicity,!1),this.superpose=rt(i.superpose,!1),this.name=t.replace(/^.*[\\/]/,""),this.trajPath=t,this.selection=new de(rt(i.sele,"backbone and not hydrogen")),this.selection.signals.stringChanged.add((()=>{this.selectionIndices=this.structure.getAtomIndices(this.selection),this._resetCache(),this._saveInitialCoords(),this.setFrame(this._currentFrame)}))}get frameCount(){return this._frameCount}get currentFrame(){return this._currentFrame}_init(t){this.setStructure(t),this._loadFrameCount(),this.setPlayer(new pl(this))}_loadFrameCount(){}setStructure(t){this.structure=t,this.atomCount=t.atomCount,this.backboneIndices=this._getIndices(new de("backbone and not hydrogen")),this._makeAtomIndices(),this._saveStructureCoords(),this.selectionIndices=this._getIndices(this.selection),this._resetCache(),this._saveInitialCoords(),this.setFrame(this._currentFrame)}_saveInitialCoords(){this.structure.hasCoords()?(this.initialCoords=new Float32Array(this.structureCoords),this._makeSuperposeCoords()):this.frameCache[0]?(this.initialCoords=new Float32Array(this.frameCache[0]),this._makeSuperposeCoords()):this.loadFrame(0,(()=>this._saveInitialCoords()))}_saveStructureCoords(){this.structureCoords=this.structure.getAtomData({what:{position:!0}}).position}setSelection(t){return this.selection.setString(t),this}_getIndices(t){let e=0;const i=t.test,r=[];return i&&this.structure.eachAtom((t=>{i(t)&&r.push(e),e+=1})),r}_makeSuperposeCoords(){const t=3*this.selectionIndices.length;this.coords1=new Float32Array(t),this.coords2=new Float32Array(t);const e=this.initialCoords,i=this.coords2;for(let r=0;r!!this.frameCache[t])):!!this.frameCache[t]}setFrame(t,e){return void 0===t||(this.inProgress=!0,-1===t||this.frameCache[t]?(this._updateStructure(t),e&&e()):this.loadFrame(t,(()=>{this._updateStructure(t),e&&e()}))),this}_interpolate(t,e,i,r,n,s){const o=this.frameCache;let a;a="spline"===s?function(t,e,i,r,n){const s=t.length,o=new Float32Array(s);for(let a=0;a{this._interpolate(t,e,i,r,n,s),o&&o()})):(this._interpolate(t,e,i,r,n,s),o&&o()),this}loadFrame(t,e){Array.isArray(t)?t.forEach((t=>{this.loadQueue[t]||this.frameCache[t]||(this.loadQueue[t]=!0,this._loadFrame(t,(()=>{delete this.loadQueue[t]})))})):this.loadQueue[t]||this.frameCache[t]||(this.loadQueue[t]=!0,this._loadFrame(t,(()=>{delete this.loadQueue[t],e&&e()})))}_loadFrame(t,e){Ie.error("Trajectory._loadFrame not implemented",t,e)}_updateStructure(t){this._disposed?console.error("updateStructure: traj disposed"):(-1===t?this.structureCoords&&this.structure.updatePosition(this.structureCoords):this.structure.updatePosition(this.frameCache[t]),this.structure.trajectory={name:this.trajPath,frame:t},this._currentFrame=t,this.inProgress=!1,this.signals.frameChanged.dispatch(t))}_doSuperpose(t){const e=3*this.selectionIndices.length,i=this.coords1,r=this.coords2;for(let r=0;r0&&this.centerPbc){const t=[e[0],e[4],e[8]],r=function(t,e,i){return[_i(e,i[0],3,0,t),_i(e,i[1],3,1,t),_i(e,i[2],3,2,t)]}(this.backboneIndices,i,t);!function(t,e,i){if(0===i[0]||0===i[8]||0===i[4])return;const r=t.length,n=i[0],s=i[1],o=i[2],a=-e[0]+n+n/2,c=-e[1]+s+s/2,l=-e[2]+o+o/2;for(let e=0;e.5&&(t[n+r]-=e[3*r+r]*Math.round(s))}}(i,e,t)}this.removePbc&&function(t,e){if(0===e[0]||0===e[8]||0===e[4])return;const i=t.length;for(let r=3;r.9*e[3*i+i])if(n>0)for(let n=0;n<3;++n)t[r+n]-=e[3*i+n];else for(let n=0;n<3;++n)t[r+n]+=e[3*i+n]}}(i,e)}this.selectionIndices.length>0&&this.coords1&&this.superpose&&this._doSuperpose(i),this.frameCache[t]=i,this.boxCache[t]=e,this.frameCacheSize+=1}_setFrameCount(t){t!==this._frameCount&&(this._frameCount=t,this.signals.countChanged.dispatch(t))}dispose(){this._resetCache(),this._disposed=!0,this.player&&this.player.stop()}setPlayer(t){this.player=t,this.signals.playerChanged.dispatch(t)}getFrameTime(t){return this.timeOffset+t*this.deltaTime}}class yl extends gl{constructor(t,e,i){const r=i||{};r.timeOffset=rt(r.timeOffset,t.timeOffset),r.deltaTime=rt(r.deltaTime,t.deltaTime),super("",e,r),this.name=t.name,this.path=t.path,this.frames=t.coordinates,this.boxes=t.boxes,this._init(e)}get type(){return"frames"}_makeAtomIndices(){"StructureView"===this.structure.type?this.atomIndices=this.structure.getAtomIndices():this.atomIndices=void 0}_loadFrame(t,e){let i;const r=this.frames[t];if(this.atomIndices){const t=this.atomIndices,e=t.length;i=new Float32Array(3*e);for(let n=0;n{const n=i.response;if(!n)return void Ie.error(`empty arrayBuffer for '${r}'`);const s=new Int32Array(n,0,1)[0],o=new Float32Array(n,8,9),a=new Float32Array(n,44);this._process(t,o,a,s),"function"==typeof e&&e()}),!1),i.send(n)}_loadFrameCount(){const t=new XMLHttpRequest,e=He.getCountUrl(this.trajPath);t.open("GET",e,!0),t.addEventListener("load",(()=>{this._setFrameCount(parseInt(t.response))}),!1),t.send()}}class xl extends gl{constructor(t,e,i){super("",e,i),this.requestCallback=t,this._init(e)}get type(){return"callback"}_makeAtomIndices(){const t=[];if("StructureView"===this.structure.type){const e=this.structure.getAtomIndices(),i=e.length;let r=e[0],n=e[0];for(let s=1;s{this._process(t,i,r,n),"function"==typeof e&&e()}),t,this.atomIndices)}_loadFrameCount(){this.requestCallback((t=>this._setFrameCount(t)))}}Ac.prototype.getView=function(t){return new vl(this,t)};class vl extends Ac{constructor(t,i){super(),this.structure=t,this.selection=i,this.center=new e,this.boundingBox=new a,this._bp=this.getBondProxy(),this._ap=this.getAtomProxy(),this._rp=this.getResidueProxy(),this._cp=this.getChainProxy(),this.selection&&this.selection.signals.stringChanged.add(this.refresh,this),this.structure.signals.refreshed.add(this.refresh,this),this.refresh()}init(){}get type(){return"StructureView"}get name(){return this.structure.name}get path(){return this.structure.path}get title(){return this.structure.title}get id(){return this.structure.id}get data(){return this.structure.data}get atomSetDict(){return this.structure.atomSetDict}get biomolDict(){return this.structure.biomolDict}get entityList(){return this.structure.entityList}get unitcell(){return this.structure.unitcell}get frames(){return this.structure.frames}get boxes(){return this.structure.boxes}get validation(){return this.structure.validation}get bondStore(){return this.structure.bondStore}get backboneBondStore(){return this.structure.backboneBondStore}get rungBondStore(){return this.structure.rungBondStore}get atomStore(){return this.structure.atomStore}get residueStore(){return this.structure.residueStore}get chainStore(){return this.structure.chainStore}get modelStore(){return this.structure.modelStore}get atomMap(){return this.structure.atomMap}get residueMap(){return this.structure.residueMap}get bondHash(){return this.structure.bondHash}get spatialHash(){return this.structure.spatialHash}get _hasCoords(){return this.structure._hasCoords}set _hasCoords(t){this.structure._hasCoords=t}refresh(){Te&&Ie.time("StructureView.refresh"),this.atomSetCache={};const t=this.structure;if(this.selection.isAllSelection()&&t!==this&&t.atomSet&&t.bondSet){this.atomSet=t.atomSet.clone(),this.bondSet=t.bondSet.clone();for(let t in this.atomSetDict){const e=this.atomSetDict[t];this.atomSetCache["__"+t]=e.clone()}this.atomCount=t.atomCount,this.bondCount=t.bondCount,this.boundingBox.copy(t.boundingBox),this.center.copy(t.center)}else if(this.selection.isNoneSelection()&&t!==this&&t.atomSet&&t.bondSet){this.atomSet=new Fn(t.atomCount),this.bondSet=new Fn(t.bondCount);for(let e in this.atomSetDict)this.atomSetCache["__"+e]=new Fn(t.atomCount);this.atomCount=0,this.bondCount=0,this.boundingBox.makeEmpty(),this.center.set(0,0,0)}else{this.atomSet=this.getAtomSet(this.selection,!0),t.atomSet&&(this.atomSet=this.atomSet.intersection(t.atomSet)),this.bondSet=this.getBondSet();for(let t in this.atomSetDict){const e=this.atomSetDict[t];this.atomSetCache["__"+t]=e.makeIntersection(this.atomSet)}this.atomCount=this.atomSet.getSize(),this.bondCount=this.bondSet.getSize(),this.boundingBox=this.getBoundingBox(),this.center=this.boundingBox.getCenter(new e)}Te&&Ie.timeEnd("StructureView.refresh"),this.signals.refreshed.dispatch()}setSelection(t){this.selection=t,this.refresh()}getSelection(t){const e=[];t&&t.string&&e.push(t.string);const i=this.structure.getSelection();i&&i.string&&e.push(i.string),this.selection&&this.selection.string&&e.push(this.selection.string);let r="";return e.length>0&&(r=`( ${e.join(" ) AND ( ")} )`),new de(r)}getStructure(){return this.structure.getStructure()}eachBond(t,e){this.structure.eachBond(t,this.getSelection(e))}eachAtom(t,e){const i=this.getAtomProxy(),r=this.getAtomSet(e),n=this.atomStore.count;if(r.getSize()=this.V[i][r]?(e="S",this.score=this.S[i][r]):this.V[i][r]>=this.H[i][r]?(e="V",this.score=this.V[i][r]):(e="H",this.score=this.H[i][r]),Te&&Ie.log("Alignment: SCORE",this.score),Te&&Ie.log("Alignment: S, V, H",this.S[i][r],this.V[i][r],this.H[i][r]);i>0&&r>0;)"S"===e?this.S[i][r]===this.S[i-1][r-1]+t(i-1,r-1)?(this.ali1=this.seq1[i-1]+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--i,--r,e="S"):this.S[i][r]===this.V[i][r]?e="V":this.S[i][r]===this.H[i][r]?e="H":(--i,--r):"V"===e?this.V[i][r]===this.V[i-1][r]+this.gapExtensionPenalty?(this.ali1=this.seq1[i-1]+this.ali1,this.ali2="-"+this.ali2,--i,e="V"):this.V[i][r]===this.S[i-1][r]+this.gap(0)?(this.ali1=this.seq1[i-1]+this.ali1,this.ali2="-"+this.ali2,--i,e="S"):--i:"H"===e?this.H[i][r]===this.H[i][r-1]+this.gapExtensionPenalty?(this.ali1="-"+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--r,e="H"):this.H[i][r]===this.S[i][r-1]+this.gap(0)?(this.ali1="-"+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--r,e="S"):--r:Ie.error("Alignment: no matrix");for(;i>0;)this.ali1=this.seq1[i-1]+this.ali1,this.ali2="-"+this.ali2,--i;for(;r>0;)this.ali1="-"+this.ali1,this.ali2=this.seq2[r-1]+this.ali2,--r;Te&&Ie.timeEnd("Alignment.trace"),Te&&Ie.log([this.ali1,this.ali2])}}function Pl(t,e,i=!1,r="",n=""){let s,o,a,c,l;if(i){let i=t,h=e;r&&n&&(i=t.getView(new de(r)),h=e.getView(new de(n)));const u=i.getSequence(),d=h.getSequence(),m=new Cl(u.join(""),d.join(""));let f,p;m.calc(),m.trace(),s=0,o=0,a=m.ali1.length;const g=[],y=[];for(let t=0;tt[e]))}}}(),this.spacefillRepresentation=this.addRepresentation("spacefill",{sele:"none",opacity:ke.opacity,color:ke.color,disablePicking:!0,radiusType:"data"},!0),this.distanceRepresentation=this.addRepresentation("distance",ke,!0),this.angleRepresentation=this.addRepresentation("angle",ke,!0),this.dihedralRepresentation=this.addRepresentation("dihedral",ke,!0),this.measureRepresentations=new ll([this.spacefillRepresentation,this.distanceRepresentation,this.angleRepresentation,this.dihedralRepresentation]),this.setDefaultAssembly(this.parameters.defaultAssembly),this.structure.signals.refreshed.add((()=>{this.updateRepresentations({position:!0})}))}get defaultParameters(){return Il}get type(){return"structure"}initSelection(t){this.selection=new de(t),this.structureView=new vl(this.structure,this.selection),this.selection.signals.stringChanged.add((()=>{this.structureView.setSelection(this.selection),this.rebuildRepresentations(),this.rebuildTrajectories()}))}setSelection(t){return this.parameters.sele=t,this.selection.setString(t),this}setDefaultAssembly(t){if(void 0===this.structure.biomolDict[t]&&(t=""),this.parameters.defaultAssembly!==t){const e={defaultAssembly:t};this.reprList.forEach((t=>t.setParameters(e))),this.measureRepresentations.setParameters(e),this.parameters.defaultAssembly=t,this.signals.defaultAssemblyChanged.dispatch(t)}return this}rebuildRepresentations(){this.reprList.forEach((t=>{t.build()})),this.measureRepresentations.build()}rebuildTrajectories(){this.trajList.forEach((t=>{t.trajectory.setStructure(this.structureView)}))}updateRepresentations(t){super.updateRepresentations(t),this.measureRepresentations.update(t)}updateRepresentationMatrices(){super.updateRepresentationMatrices(),this.measureRepresentations.setParameters({matrix:this.matrix})}addRepresentation(t,e={},i=!1){e.defaultAssembly=this.parameters.defaultAssembly;const r=this._addRepresentation(t,this.structureView,e,i);return i||r.signals.parametersChanged.add((()=>this.measureUpdate())),r}addTrajectory(t="",e={}){const i=function(t,e,i){let r;return r=t&&t instanceof dl?new yl(t,e,i):!t&&e.frames?new bl(t,e,i):t&&"function"==typeof t?new xl(t,e,i):new _l(t,e,i),r}(t,this.structureView,e),r=new ul(this.stage,i,e);return this.trajList.push(r),this.signals.trajectoryAdded.dispatch(r),r}removeTrajectory(t){const e=this.trajList.indexOf(t);-1!==e&&this.trajList.splice(e,1),t.dispose(),this.signals.trajectoryRemoved.dispatch(t)}dispose(){this.trajList.slice().forEach((t=>t.dispose())),this.trajList.length=0,this.structure.dispose(),this.measureRepresentations.dispose(),super.dispose()}autoView(t,e){"number"==typeof t&&(e=t,t=""),this.stage.animationControls.zoomMove(this.getCenter(t),this.getZoom(t),rt(e,0))}getBoxUntransformed(t){let e;return e=t?this.structureView.getBoundingBox(new de(t)):this.structureView.boundingBox,e}getCenterUntransformed(t){return t&&"string"==typeof t?this.structure.atomCenter(new de(t)):this.structure.center}superpose(t,e,i,r){return Pl(this.structureView,t.structureView,e,i,r),this.updateRepresentations({position:!0}),this}getMaxRepresentationRadius(t){let e=0;const i=this.structure.getAtomProxy(t);return this.eachRepresentation((t=>{if(t.getVisibility()){const r=t.repr;e=Math.max(r.getAtomRadius(i),e)}})),e}measurePick(t){const e=this.pickBuffer.count;if(this.lastPick===t.index&&e>=1){if(e>1){const t=this.pickBuffer.data,i=this.pickBuffer.data.sort();this.pickDict.has(i)?this.pickDict.del(i):this.pickDict.add(i,t),2===e?this.distanceRepresentation.setParameters({atomPair:this.pickDict.values.filter((t=>2===t.length))}):3===e?this.angleRepresentation.setParameters({atomTriple:this.pickDict.values.filter((t=>3===t.length))}):4===e&&this.dihedralRepresentation.setParameters({atomQuad:this.pickDict.values.filter((t=>4===t.length))})}this.pickBuffer.clear(),this.lastPick=void 0}else this.pickBuffer.has(t.index)||this.pickBuffer.push(t.index),this.lastPick=t.index;this.measureUpdate()}measureClear(){this.pickBuffer.clear(),this.lastPick=void 0,this.spacefillRepresentation.setSelection("none")}measureBuild(){const t=this.measureData();this.distanceRepresentation.setParameters({atomPair:t.distance}),this.angleRepresentation.setParameters({atomTriple:t.angle}),this.dihedralRepresentation.setParameters({atomQuad:t.dihedral})}measureUpdate(){const t=this.pickBuffer.data,e={};t.forEach((t=>{const i=Math.max(.1,this.getMaxRepresentationRadius(t));e[t]=i*(2.3-Ft(.1,2,i))})),this.spacefillRepresentation.setSelection(t.length?"@"+t.join(","):"none"),t.length&&this.spacefillRepresentation.setParameters({radiusData:e})}measureData(){const t=this.pickDict.values;return{distance:t.filter((t=>2===t.length)),angle:t.filter((t=>3===t.length)),dihedral:t.filter((t=>4===t.length))}}removeAllMeasurements(t){const e=this.pickDict,i=e.values,r=function(t){i.filter((e=>e.length===t)).forEach((t=>e.del(t.slice().sort())))};(!t||1&t)&&r(2),(!t||2&t)&&r(3),(!t||4&t)&&r(4),this.measureBuild()}removeMeasurement(t){this.pickDict.del(t.slice().sort()),this.measureBuild()}addMeasurement(t){if(t.length<2||t.length>4)return;const e=t.slice().sort();this.pickDict.has(e)||this.pickDict.add(e,t),this.measureBuild()}}Ue.add("structure",kl),Ue.add("structureview",kl);class Ml extends al{constructor(t,e,i={}){super(t,e,Object.assign({name:e.name},i)),this.surface=e}get type(){return"surface"}addRepresentation(t,e={}){return this._addRepresentation(t,this.surface,e)}getBoxUntransformed(){return this.surface.boundingBox}getCenterUntransformed(){return this.surface.center}dispose(){this.surface.dispose(),super.dispose()}}Ue.add("surface",Ml);class Tl extends al{constructor(t,e,i={}){super(t,e,Object.assign({name:e.name},i)),this.volume=e}get type(){return"volume"}addRepresentation(t,e={}){return this._addRepresentation(t,this.volume,e)}getBoxUntransformed(){return this.volume.boundingBox}getCenterUntransformed(){return this.volume.center}dispose(){this.volume.dispose(),super.dispose()}}Ue.add("volume",Tl);class Dl extends cl{addRepresentation(t,e){return this.forEach((i=>i.addRepresentation(t,e)))}autoView(t){return this.forEach((e=>e.autoView(t)))}}function Bl(t,e){return t instanceof RegExp?null!==e.name.match(t):e.name===t}const Fl=new e,El={impostor:!0,quality:"medium",workerDefault:!0,sampleLevel:0,backgroundColor:"black",rotateSpeed:2,zoomSpeed:1.2,panSpeed:1,clipNear:0,clipFar:100,clipDist:10,clipMode:"scene",clipScale:"relative",fogNear:50,fogFar:100,cameraFov:40,cameraEyeSep:.3,cameraType:"perspective",lightColor:14540253,lightIntensity:1.2,ambientColor:14540253,ambientIntensity:.3,hoverTimeout:0,tooltip:!0,mousePreset:"default"};class $l{constructor(t,e={}){this.signals={parametersChanged:new tt,fullscreenChanged:new tt,componentAdded:new tt,componentRemoved:new tt,clicked:new tt,hovered:new tt},this.tasks=new hi,this.compList=[],this.defaultFileParams={},this.logList=[],this.viewer=new Zi(t),this.viewer.renderer&&(this.tooltip=document.createElement("div"),Object.assign(this.tooltip.style,{display:"none",position:"fixed",zIndex:"1000000",pointerEvents:"none",backgroundColor:"rgba( 0, 0, 0, 0.6 )",color:"lightgrey",padding:"8px",fontFamily:"sans-serif"}),this.viewer.container.appendChild(this.tooltip),this.mouseObserver=new ir(this.viewer.renderer.domElement),this.viewerControls=new Pr(this),this.trackballControls=new fr(this),this.pickingControls=new yr(this),this.animationControls=new Or(this),this.mouseControls=new Zo(this),this.keyControls=new ta(this),this.pickingBehavior=new ea(this),this.mouseBehavior=new ia(this),this.animationBehavior=new ra(this),this.keyBehavior=new sa(this),this.spinAnimation=this.animationControls.spin([0,1,0],.005),this.spinAnimation.pause(!0),this.rockAnimation=this.animationControls.rock([0,1,0],.005),this.rockAnimation.pause(!0),this.parameters=nt(e,El),this.setParameters(this.parameters),this.viewer.animate())}setParameters(t={}){st(this.parameters,t);const e=t,i=this.parameters,r=this.viewer,n=this.trackballControls;return void 0!==e.quality&&this.setQuality(i.quality),void 0!==e.impostor&&this.setImpostor(i.impostor),void 0!==e.rotateSpeed&&(n.rotateSpeed=i.rotateSpeed),void 0!==e.zoomSpeed&&(n.zoomSpeed=i.zoomSpeed),void 0!==e.panSpeed&&(n.panSpeed=i.panSpeed),void 0!==e.mousePreset&&this.mouseControls.preset(i.mousePreset),this.mouseObserver.setParameters({hoverTimeout:i.hoverTimeout}),r.setClip(i.clipNear,i.clipFar,i.clipDist,i.clipMode,i.clipScale),r.setFog(void 0,i.fogNear,i.fogFar),r.setCamera(i.cameraType,i.cameraFov,i.cameraEyeSep),r.setSampling(i.sampleLevel),r.setBackground(i.backgroundColor),r.setLight(i.lightColor,i.lightIntensity,i.ambientColor,i.ambientIntensity),this.signals.parametersChanged.dispatch(this.getParameters()),this}log(t){console.log("STAGE LOG",t),this.logList.push(t)}getParameters(){return Object.assign({},this.parameters)}defaultFileRepresentation(t){if(t instanceof kl){let e,i,r;t.setSelection("/0");const n=t.structure;if(n.biomolDict.BU1){const s=n.biomolDict.BU1;e=s.getAtomCount(n),i=s.getResidueCount(n),r=s.getInstanceCount(),t.setDefaultAssembly("BU1")}else e=n.getModelProxy(0).atomCount,i=n.getModelProxy(0).residueCount,r=1;let s=e;we&&(s*=4);const o=n.atomStore.count/n.residueStore.count<2;o&&(s*=10);let a="chainname",c="RdYlBu",l=!1;if(1===n.getChainnameCount(new de("polymer and /0"))&&(a="residueindex",c="Spectral",l=!0),Te&&console.log(s,e,r,o),i/r<4)t.addRepresentation("ball+stick",{colorScheme:"element",radiusScale:2,aspectRatio:1.5,bondScale:.3,bondSpacing:.75,quality:"auto"});else if(r>5&&s>15e3||s>7e5){let e=Math.min(2,Math.max(.1,6e3/(s/r)));o&&(e=Math.min(e,.5)),t.addRepresentation("surface",{colorScheme:a,colorScale:c,colorReverse:l,sele:"polymer",surfaceType:"av",probeRadius:1.4,scaleFactor:e,useWorker:!1})}else s>25e4?t.addRepresentation("backbone",{colorScheme:a,colorScale:c,colorReverse:l,lineOnly:!0}):s>1e5?t.addRepresentation("backbone",{colorScheme:a,colorScale:c,colorReverse:l,quality:"low",disableImpostor:!0,radiusScale:2}):s>8e4?t.addRepresentation("backbone",{colorScheme:a,colorScale:c,colorReverse:l,radiusScale:2}):(t.addRepresentation("cartoon",{colorScheme:a,colorScale:c,colorReverse:l,radiusScale:.7,aspectRatio:5,quality:"auto"}),s<5e4&&t.addRepresentation("base",{colorScheme:a,colorScale:c,colorReverse:l,quality:"auto"}),t.addRepresentation("ball+stick",{sele:"ligand",colorScheme:"element",radiusScale:2,aspectRatio:1.5,bondScale:.3,bondSpacing:.75,quality:"auto"}));t.structure.frames.length&&t.addTrajectory()}else(t instanceof Ml||t instanceof Tl)&&t.addRepresentation("surface");this.tasks.onZeroOnce(this.autoView,this)}loadFile(t,e={}){const i=Object.assign({},this.defaultFileParams,e),r=ei(t).name;this.tasks.increment(),this.log(`loading file '${r}'`);const n=rt(i.ext,ei(t).ext);let s;return s=Le.isTrajectory(n)?Promise.reject(new Error(`loadFile: ext '${n}' is a trajectory and must be loaded into a structure component`)):ri(t,i),s.then((t=>{this.log(`loaded '${r}'`);const e=this.addComponentFromObject(t,i);return i.defaultRepresentation&&this.defaultFileRepresentation(e),this.tasks.decrement(),e}),(t=>{this.tasks.decrement();const e=`error loading file: '${t}'`;throw this.log(e),e}))}loadScript(t){const e=ei(t).name;return this.log(`loading script '${e}'`),ri(t).then((t=>{this.tasks.increment(),this.log(`running script '${e}'`),t.run(this).then((()=>{this.tasks.decrement(),this.log(`finished script '${e}'`)})),this.log(`called script '${e}'`)}),(t=>{this.tasks.decrement();const i=`errored script '${e}' "${t}"`;throw this.log(i),i}))}addComponent(t){t?(this.compList.push(t),this.signals.componentAdded.dispatch(t)):Ie.warn("Stage.addComponent: no component given")}addComponentFromObject(t,e={}){const i=Ue.get(t.type);if(i){const r=new i(this,t,e);return this.addComponent(r),r}Ie.warn("no component for object type",t.type)}removeComponent(t){const e=this.compList.indexOf(t);-1!==e&&(this.compList.splice(e,1),t.dispose(),this.signals.componentRemoved.dispatch(t))}removeAllComponents(){this.compList.slice().forEach((t=>this.removeComponent(t)))}handleResize(){this.viewer.handleResize()}setSize(t,e){const i=this.viewer.container;i!==document.body&&(void 0!==t&&(i.style.width=t),void 0!==e&&(i.style.height=e),this.handleResize())}toggleFullscreen(t){if(!(document.fullscreenEnabled||document.mozFullScreenEnabled||document.webkitFullscreenEnabled||document.msFullscreenEnabled))return void Ie.log("fullscreen mode (currently) not possible");const e=this;function i(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement}function r(){if(!i()&&e.lastFullscreenElement){const t=e.lastFullscreenElement;t.style.width=t.dataset.normalWidth||"",t.style.height=t.dataset.normalHeight||"",document.removeEventListener("fullscreenchange",r),document.removeEventListener("mozfullscreenchange",r),document.removeEventListener("webkitfullscreenchange",r),document.removeEventListener("MSFullscreenChange",r),e.handleResize(),e.signals.fullscreenChanged.dispatch(!1)}}t=t||this.viewer.container,this.lastFullscreenElement=t,i()?document.exitFullscreen?document.exitFullscreen():document.msExitFullscreen?document.msExitFullscreen():document.mozCancelFullScreen?document.mozCancelFullScreen():document.webkitExitFullscreen&&document.webkitExitFullscreen():(t.dataset.normalWidth=t.style.width||"",t.dataset.normalHeight=t.style.height||"",t.style.width=window.screen.width+"px",t.style.height=window.screen.height+"px",t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.mozRequestFullScreen?t.mozRequestFullScreen():t.webkitRequestFullscreen&&t.webkitRequestFullscreen(),document.addEventListener("fullscreenchange",r),document.addEventListener("mozfullscreenchange",r),document.addEventListener("webkitfullscreenchange",r),document.addEventListener("MSFullscreenChange",r),this.handleResize(),this.signals.fullscreenChanged.dispatch(!0),setTimeout((function(){e.handleResize()}),100))}setSpin(t){t?(this.spinAnimation.resume(!0),this.rockAnimation.pause(!0)):this.spinAnimation.pause(!0)}setRock(t){t?(this.rockAnimation.resume(!0),this.spinAnimation.pause(!0)):this.rockAnimation.pause(!0)}toggleSpin(){this.setSpin(this.spinAnimation.paused)}toggleRock(){this.setRock(this.rockAnimation.paused)}getFocus(){const t=this.parameters;if("scene"!==t.clipMode)return 0;let e=t.clipNear;return"absolute"===t.clipScale&&(e=this.viewer.absoluteToRelative(e)),2*e}setFocus(t){if("scene"!==this.parameters.clipMode)return;let e,i,r,n;"relative"===this.parameters.clipScale?(e=Tt(t/2,0,49.9),i=100-e,r=50,n=function(t){return Tt(t,0,100)}(2*i-50)):(e=this.viewer.relativeToAbsolute(t/2),i=e,r=0,n=2*i),this.setParameters({clipNear:e,clipFar:i,fogNear:r,fogFar:n})}getZoomForBox(t){const e=t.getSize(Fl),i=Math.max(e.x,e.y,e.z),r=Math.min(e.x,e.y,e.z);let n=i+Math.sqrt(r);const s=Pt(this.viewer.perspectiveCamera.fov),o=this.viewer.width,a=this.viewer.height,c=a{this.tasks.onZeroOnce((()=>{this.tasks.increment(),this.viewer.makeImage(t).then((t=>{this.tasks.decrement(),e(t)})).catch((t=>{this.tasks.decrement(),i(t)}))}))}))}setImpostor(t){this.parameters.impostor=t;const e=["spacefill","ball+stick","licorice","hyperball","backbone","rocket","helixorient","contact","distance","dot"];this.eachRepresentation((function(i){if(!e.includes(i.getType()))return;const r=i.getParameters();r.disableImpostor=!t,i.build(r)}))}setQuality(t){this.parameters.quality=t;const e=["tube","cartoon","ribbon","trace","rope"],i=["spacefill","ball+stick","licorice","hyperball","backbone","rocket","helixorient","contact","distance","dot"];this.eachRepresentation((function(r){const n=r.getParameters();if(!e.includes(r.getType())){if(!i.includes(r.getType()))return;if(!n.disableImpostor)return void(r.repr.quality=t)}n.quality=t,r.build(n)}))}eachComponent(t,e){this.compList.slice().forEach((i=>{void 0!==e&&e!==i.type||t(i)}))}eachRepresentation(t,e){this.eachComponent((i=>{i.reprList.slice().forEach((r=>{void 0!==e&&e!==r.getType()||t(r,i)}))}))}getComponentsByName(t){const e=[];return this.eachComponent((i=>{(void 0===t||Bl(t,i))&&e.push(i)})),new Dl(e)}getComponentsByObject(t){const e=[];return this.eachComponent((i=>{i.object===t&&e.push(i)})),new Dl(e)}getRepresentationsByName(t){const e=[];return this.eachRepresentation(((i,r)=>{(void 0===t||Bl(t,i))&&e.push(i)})),new ll(e)}measureClear(){this.eachComponent((t=>t.measureClear()),"structure")}measureUpdate(){this.eachComponent((t=>t.measureUpdate()),"structure")}dispose(){this.tasks.dispose(),this.viewer.dispose(),this.mouseObserver.dispose()}}class Ol extends al{constructor(t,e,i={}){super(t,e,Object.assign({name:e.name},i)),this.shape=e}get type(){return"shape"}addRepresentation(t,e={}){return this._addRepresentation(t,this.shape,e)}getBoxUntransformed(){return this.shape.boundingBox}getCenterUntransformed(){return this.shape.center}dispose(){this.shape.dispose(),super.dispose()}}function Rl(t,e,i,r){var n,s=arguments.length,o=s<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(t,e,i,r);else for(var a=t.length-1;a>=0;a--)(n=t[a])&&(o=(s<3?n(o):s>3?n(e,i,o):n(e,i))||o);return s>3&&o&&Object.defineProperty(e,i,o),o}function Ll(t,e,i,r){return new(i||(i=Promise))((function(n,s){function o(t){try{c(r.next(t))}catch(t){s(t)}}function a(t){try{c(r.throw(t))}catch(t){s(t)}}function c(t){t.done?n(t.value):function(t){return t instanceof i?t:new i((function(e){e(t)}))}(t.value).then(o,a)}c((r=r.apply(t,e||[])).next())}))}Ue.add("shape",Ol),"function"==typeof SuppressedError&&SuppressedError;class Nl extends Lt{constructor(t){super(t),t.scale||(this.parameters.scale="rainbow",this.parameters.reverse=rt(t.reverse,!0)),this.scalePerModel={},t.structure.eachModel((t=>{this.parameters.domain=[t.atomOffset,t.atomEnd],this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){return this.scalePerModel[t.modelIndex](t.index)}}Rl([Rt],Nl.prototype,"atomColor",null),$e.add("atomindex",Nl);class zl extends Lt{constructor(t){if(super(t),t.scale||(this.parameters.scale="OrRd"),!t.domain){let e,i=1/0,r=-1/0;t.sele&&(e=new de(t.sele)),t.structure.eachAtom((function(t){const e=t.bfactor;i=Math.min(i,e),r=Math.max(r,e)}),e),this.parameters.domain=[i,r]}this.bfactorScale=this.getScale()}atomColor(t){return this.bfactorScale(t.bfactor)}}Rl([Rt],zl.prototype,"atomColor",null),$e.add("bfactor",zl);class Ul extends Lt{constructor(t){super(t),this.chainidDictPerModel={},this.scalePerModel={},t.scale||(this.parameters.scale="Spectral"),t.structure.eachModel((t=>{let e=0;const i={};t.eachChain((function(t){void 0===i[t.chainid]&&(i[t.chainid]=e,e+=1)})),this.parameters.domain=[0,e-1],this.chainidDictPerModel[t.index]=i,this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){const e=this.chainidDictPerModel[t.modelIndex];return this.scalePerModel[t.modelIndex](e[t.chainid])}}Rl([Rt],Ul.prototype,"atomColor",null),$e.add("chainid",Ul);class Vl extends Lt{constructor(t){super(t),this.scalePerModel={},t.scale||(this.parameters.scale="Spectral"),t.structure.eachModel((t=>{this.parameters.domain=[t.chainOffset,t.chainEnd],this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){return this.scalePerModel[t.modelIndex](t.chainIndex)}}Rl([Rt],Vl.prototype,"atomColor",null),$e.add("chainindex",Vl);class jl extends Lt{constructor(t){super(t),this.chainnameDictPerModel={},this.scalePerModel={},t.scale||(this.parameters.scale="Spectral"),t.structure.eachModel((t=>{let e=0;const i={};t.eachChain((function(t){void 0===i[t.chainname]&&(i[t.chainname]=e,e+=1)})),this.parameters.domain=[0,e-1],this.chainnameDictPerModel[t.index]=i,this.scalePerModel[t.index]=this.getScale()}))}atomColor(t){const e=this.chainnameDictPerModel[t.modelIndex];return this.scalePerModel[t.modelIndex](e[t.chainname])}}Rl([Rt],jl.prototype,"atomColor",null),$e.add("chainname",jl);class Gl extends Lt{constructor(t){super(t),this.rsrzDict={},this.rsccDict={},t.scale||(this.parameters.scale="RdYlBu"),this.rsrzScale=this.getScale({domain:[2,0]}),this.rsccScale=this.getScale({domain:[.678,1]});const e=t.structure.validation;e&&(this.rsrzDict=e.rsrzDict,this.rsccDict=e.rsccDict)}atomColor(t){let e=t.resno+"";t.inscode&&(e+="^"+t.inscode),t.chainname&&(e+=":"+t.chainname),e+="/"+t.modelIndex;const i=this.rsrzDict[e];if(void 0!==i)return this.rsrzScale(i);const r=this.rsccDict[e];return void 0!==r?this.rsccScale(r):9474192}}Rl([Rt],Gl.prototype,"atomColor",null),$e.add("densityfit",Gl);const Hl={ARG:{CD:.1,CZ:.5,NE:-.1},ASN:{CG:.55,OD1:-.55},ASP:{CB:-.16,CG:.36,OD1:-.6,OD2:-.6},CYS:{CB:.19,SG:-.19},GLN:{CD:.55,OE1:-.55},GLU:{CD:.36,CG:-.16,OE1:-.6,OE2:-.6},HIS:{CB:.1,CD2:.2,CE1:.45,CG:.15,ND1:.05,NE2:.05},LYS:{CE:.25,NZ:.75},MET:{CE:.06,CG:.06,SD:-.12},PTR:{C:.55,CA:.1,CZ:.25,N:-.35,O:-.55,O1P:-.85,O2P:-.85,O3P:-.85,OG1:-1.1,P:1.4},SEP:{C:.55,CA:.1,CB:.25,N:-.35,O:-.55,O1P:-.85,O2P:-.85,O3P:-.85,OG1:-1.1,P:1.4},SER:{CB:.25,OG:-.25},THR:{CB:.25,OG1:-.25},TPO:{C:.55,CA:.1,CB:.25,N:-.35,O:-.55,OG1:-1.1,O1P:-.85,O2P:-.85,O3P:-.85,P:1.4},TRP:{CD1:.06,CD2:.1,CE2:-.04,CE3:-.03,CG:-.03,NE1:-.06},TYR:{CZ:.25,OH:-.25},backbone:{C:.55,O:-.55,N:-.35,CA:.1}};class ql extends Lt{constructor(t){super(t),this.delta=new e,this.hCharges=[],t.scale||(this.parameters.scale="rwb"),t.domain||(this.parameters.domain=[-50,50]),this.scale=this.getScale(),this.charges=new Float32Array(t.structure.atomCount);const i=[];t.structure.eachAtom((t=>{var r;if(this.charges[t.index]=(null!==(r=t).partialCharge?r.partialCharge:r.isProtein()&&(Hl[r.resname]&&Hl[r.resname][r.atomname]||Hl.backbone[r.atomname])||0)*t.occupancy,"N"===t.atomname){if(t.bondCount>=3)return;if(t.bondToElementCount(1))return;const r=function(t,i=new e){let r=!1,n=!1,s=!1;return i.set(2*t.x,2*t.y,2*t.z),t.eachBondedAtom((function(t){if(!r)return"H"===t.atomname?(i.set(t.x,t.y,t.z),void(r=!0)):void(n||"CA"!==t.atomname?s||"C"!==t.atomname||(s=!0,i.sub(t)):(i.sub(t),n=!0))})),r?i:n&&s?(i.normalize(),i.multiplyScalar(1.04),i.add(t),i):void 0}(t);void 0!==r&&(i.push(r),this.hCharges.push(.25*t.occupancy))}}));const r=t.structure.getBoundingBox();r.expandByScalar(1.04),this.hStore=function(t){const e=t.length,i=new Float32Array(e),r=new Float32Array(e),n=new Float32Array(e);for(let e=0;e{const n=e[t];0!==n&&(r+=n/i)})),this.hHash.eachWithin(t.x,t.y,t.z,12,((t,e)=>{const n=i[t];0!==n&&(r+=n/e)})),this.scale(332*r)}}Rl([Rt],ql.prototype,"positionColor",null),$e.add("electrostatic",ql);const Wl={H:16777215,HE:14286847,LI:13402367,BE:12779264,B:16758197,C:9474192,N:3166456,O:16715021,F:9494608,NE:11789301,NA:11230450,MG:9109248,AL:12560038,SI:1578e4,P:16744448,S:16777008,CL:2093087,AR:8442339,K:9388244,CA:4062976,SC:15132390,TI:12567239,V:10921643,CR:9083335,MN:10255047,FE:14706227,CO:15765664,NI:5296208,CU:13140019,ZN:8224944,GA:12750735,GE:6721423,AS:12419299,SE:16752896,BR:10889513,KR:6076625,RB:7351984,SR:65280,Y:9764863,ZR:9756896,NB:7586505,MO:5551541,TC:3907230,RU:2396047,RH:687500,PD:27013,AG:12632256,CD:16767375,IN:10909043,SN:6717568,SB:10380213,TE:13924864,I:9699476,XE:9699476,CS:5707663,BA:51456,LA:7394559,CE:16777159,PR:14286791,ND:13107143,PM:10747847,SM:9437127,EU:6422471,GD:4587463,TB:3211207,DY:2097095,HO:65436,ER:58997,TM:54354,YB:48952,LU:43812,HF:5096191,TA:5089023,W:2200790,RE:2522539,OS:2516630,IR:1528967,PT:13684960,AU:16765219,HG:12105936,TL:10900557,PB:5724513,BI:10375093,PO:11230208,AT:7688005,RN:4358806,FR:4325478,RA:32e3,AC:7384058,TH:47871,PA:41471,U:36863,NP:33023,PU:27647,AM:5528818,CM:7888099,BK:9064419,CF:10565332,ES:11739092,FM:11739066,MD:11734438,NO:12389767,LR:13041766,RF:13369433,DB:13697103,SG:14221381,BH:14680120,HS:15073326,MT:15400998,DS:16777215,RG:16777215,CN:16777215,UUT:16777215,FL:16777215,UUP:16777215,LV:16777215,UUH:16777215,D:16777152,T:16777120};class Xl extends Lt{constructor(t){t.value=rt(t.value,Wl.C),super(t)}atomColor(t){const e=t.element;return"C"===e?this.parameters.value:Wl[e]||16777215}}Rl([Rt],Xl.prototype,"atomColor",null),$e.add("element",Xl);class Yl extends Lt{constructor(t){super(t),t.scale||(this.parameters.scale="Spectral"),t.domain||(this.parameters.domain=[0,t.structure.entityList.length-1]),this.entityindexScale=this.getScale()}atomColor(t){return this.entityindexScale(t.entityIndex)}}Rl([Rt],Yl.prototype,"atomColor",null),$e.add("entityindex",Yl);class Kl extends Lt{atomColor(t){const e=t.entity;switch(e?e.entityType:void 0){case 1:return 8374655;case 2:return 16629894;case 3:return 12496596;case 4:return 3697840;default:return 16777113}}}Rl([Rt],Kl.prototype,"atomColor",null),$e.add("entitytype",Kl);class Zl extends Lt{constructor(t){super(t),this.geoAtomDict={},this.geoDict={};const e=t.structure.validation;e&&(this.geoAtomDict=e.geoAtomDict,this.geoDict=e.geoDict)}atomColor(t){let e,i=t.resno+"";t.inscode&&(i+="^"+t.inscode),t.chainname&&(i+=":"+t.chainname),i+="/"+t.modelIndex;const r=this.geoAtomDict[i];if(void 0!==r){const i=r[t.atomname]||0;n=i,e=16843009*((n=(858993459&(n-=n>>1&1431655765))+(n>>2&858993459))+(n>>4)&252645135)>>24}else e=this.geoDict[i]||0;var n;return 0===e?2188972:1===e?16703627:2===e?16018755:e>=3?10813478:9474192}}Rl([Rt],Zl.prototype,"atomColor",null),$e.add("geoquality",Zl);class Ql extends Lt{constructor(t){super(t),this.resHF={},t.scale||(this.parameters.scale="RdYlGn");for(const t in Qn)this.resHF[t]=Qn[t][0];if(this.defaultResidueHydrophobicity=Jn[0],!t.domain){let t=1/0,e=-1/0;for(const i in this.resHF){const r=this.resHF[i];t=Math.min(t,r),e=Math.max(e,r)}this.parameters.domain=[t,0,e]}this.hfScale=this.getScale()}atomColor(t){return this.hfScale(this.resHF[t.resname]||this.defaultResidueHydrophobicity)}}Rl([Rt],Ql.prototype,"atomColor",null),$e.add("hydrophobicity",Ql);class Jl extends Lt{constructor(t){super(t),t.scale||(this.parameters.scale="rainbow"),t.domain||(this.parameters.domain=[0,t.structure.modelStore.count]),this.modelindexScale=this.getScale()}atomColor(t){return this.modelindexScale(t.modelIndex)}}Rl([Rt],Jl.prototype,"atomColor",null),$e.add("modelindex",Jl);class th extends Lt{atomColor(t){switch(t.residueType.moleculeType){case 1:return 3697840;case 2:return 15729279;case 3:return 12496596;case 4:return 16629894;case 5:return 12540695;case 6:return 8374655;default:return 16777113}}}Rl([Rt],th.prototype,"atomColor",null),$e.add("moleculetype",th);class eh extends Lt{constructor(t){super(t),t.scale||(this.parameters.scale="PuBu"),t.domain||(this.parameters.domain=[0,1]),this.occupancyScale=this.getScale()}atomColor(t){return this.occupancyScale(t.occupancy)}}Rl([Rt],eh.prototype,"atomColor",null),$e.add("occupancy",eh);class ih extends Lt{constructor(t){super(t),t.scale||(this.parameters.scale="rwb"),t.domain||(this.parameters.domain=[-1,1]),this.partialchargeScale=this.getScale()}atomColor(t){return this.partialchargeScale(t.partialCharge||0)}}function rh(){return 16777215*Math.random()}Rl([Rt],ih.prototype,"atomColor",null),$e.add("partialcharge",ih);class nh extends Lt{atomColor(){return rh()}volumeColor(){return rh()}positionColor(){return rh()}}Rl([Rt],nh.prototype,"atomColor",null),Rl([Rt],nh.prototype,"volumeColor",null),Rl([Rt],nh.prototype,"positionColor",null),$e.add("random",nh);class sh extends Lt{constructor(t){super(t),this.rciDict={},t.scale||(this.parameters.scale="RdYlBu"),this.rciScale=this.getScale({domain:[.6,0]});const e=t.structure.validation;e&&(this.rciDict=e.rciDict)}atomColor(t){let e=`[${t.resname}]${t.resno}`;t.chainname&&(e+=":"+t.chainname);const i=this.rciDict[e];return void 0!==i?this.rciScale(i):9474192}}Rl([Rt],sh.prototype,"atomColor",null),$e.add("randomcoilindex",sh);class oh extends Lt{constructor(t){super(t),this.scalePerChain={},t.scale||(this.parameters.scale="rainbow",this.parameters.reverse=rt(t.reverse,!0)),t.structure.eachChain((t=>{this.parameters.domain=[t.residueOffset,t.residueEnd],this.scalePerChain[t.index]=this.getScale()}))}atomColor(t){return this.scalePerChain[t.chainIndex](t.residueIndex)}}Rl([Rt],oh.prototype,"atomColor",null),$e.add("residueindex",oh);const ah={ALA:9240460,ARG:124,ASN:16743536,ASP:10485826,CYS:16777072,GLN:16731212,GLU:6684672,GLY:16777215,HIS:7368959,ILE:19456,LEU:4546117,LYS:4671416,MET:12099650,PHE:5459026,PRO:5395026,SER:16740418,THR:12078080,TRP:5195264,TYR:9203788,VAL:16747775,ASX:16711935,GLX:16711935,ASH:16711935,GLH:16711935,A:14423100,G:3329330,I:10145074,X:8190976,C:16766720,T:4286945,U:4251856,D:35723,DA:14423100,DG:3329330,DI:10145074,DX:8190976,DC:16766720,DT:4286945,DU:4251856,DD:35723};class ch extends Lt{atomColor(t){return ah[t.resname]||16711935}}Rl([Rt],ch.prototype,"atomColor",null),$e.add("resname",ch);const lh=16711808,hh=10485888,uh=6291584,dh=16762880,mh=6324479,fh=16777215,ph=11403518,gh=16580962,yh=10921722;class bh extends Lt{constructor(t){super(t),this.residueProxy=t.structure.getResidueProxy()}atomColor(t){const e=t.sstruc,i=this.residueProxy;return"h"===e?lh:"g"===e?hh:"i"===e?uh:"e"===e||"b"===e?dh:"t"===e?mh:(i.index=t.residueIndex,i.isDna()?ph:i.isRna()?gh:i.isSaccharide()?yh:i.isProtein()||"s"===e||"l"===e?fh:8421504)}}Rl([Rt],bh.prototype,"atomColor",null),$e.add("sstruc",bh);class _h extends Lt{constructor(t){var e,i;super(t),t.scale||(this.parameters.scale="rwb"),this.atomData=null===(e=this.parameters.data)||void 0===e?void 0:e.atomData,this.bondData=null===(i=this.parameters.data)||void 0===i?void 0:i.bondData,this.scale=this.getScale(this.parameters)}atomColor(t){var e;const i=null===(e=this.atomData)||void 0===e?void 0:e[t.index];return void 0!==i?this.scale(i):this.parameters.value}bondColor(t,e){var i;const r=null===(i=this.bondData)||void 0===i?void 0:i[t.index];return void 0!==r?this.scale(r):this.atomProxy?(this.atomProxy.index=e?t.atomIndex1:t.atomIndex2,this.atomColor(this.atomProxy)):this.parameters.value}}Rl([Rt],_h.prototype,"atomColor",null),Rl([Rt],_h.prototype,"bondColor",null),$e.add("structuredata",_h);class xh extends Lt{atomColor(){return this.parameters.value}bondColor(){return this.parameters.value}valueColor(){return this.parameters.value}volumeColor(){return this.parameters.value}}Rl([Rt],xh.prototype,"atomColor",null),Rl([Rt],xh.prototype,"bondColor",null),Rl([Rt],xh.prototype,"valueColor",null),Rl([Rt],xh.prototype,"volumeColor",null),$e.add("uniform",xh);class vh extends Lt{constructor(t){super(t),this.valueScale=this.getScale()}volumeColor(t){return this.valueScale(this.parameters.volume.data[t])}}Rl([Rt],vh.prototype,"volumeColor",null),$e.add("value",vh);class wh extends Lt{constructor(t){super(t),this.vec=new e,this.valueScale=this.getScale()}positionColor(t){const e=this.parameters.volume;if(!e||!e.inverseMatrix)return this.parameters.value;const i=this.vec,r=e.data,n=e.nx,s=e.ny,o=n*s;i.copy(t),i.applyMatrix4(e.inverseMatrix);const a=Math.floor(i.x),c=Math.floor(i.y),l=Math.floor(i.z),h=(l*s+c)*n+a,u=h+1,d=h+n,m=h+o,f=d+1,p=m+1,g=d+o,y=g+1,b=r[h],_=r[u],x=r[d],v=r[m],w=r[f],A=r[p],S=r[g],C=r[y],P=i.x-a,I=i.y-c,k=i.z-l,M=Dt(b,_,P),T=Dt(v,A,P),D=Dt(x,w,P),B=Dt(S,C,P),F=Dt(M,D,I),E=Dt(T,B,I),$=Dt(F,E,k);return this.valueScale($)}}Rl([Rt],wh.prototype,"positionColor",null),$e.add("volume",wh);class Ah extends Lr{constructor(t,e,i){const r=i||{};if(super(t,e,r),this.type="structure",this.parameters=Object.assign({radiusType:{type:"select",options:da.types},radiusData:{type:"hidden"},radiusSize:{type:"number",precision:3,max:10,min:.001},radiusScale:{type:"number",precision:3,max:10,min:.001},assembly:null,defaultAssembly:{type:"hidden"}},this.parameters),this.selection=new de(r.sele),this.dataList=[],this.structure=t,this.structureView=this.structure.getView(this.selection),t.biomolDict){const e={default:"default","":t.unitcell?"AU":"FULL"};Object.keys(t.biomolDict).forEach((function(t){e[t]=t})),this.parameters.assembly={type:"select",options:e,rebuild:!0}}else this.parameters.assembly=null}get defaultScale(){return{vdw:1,covalent:1,bfactor:.01,sstruc:1}}init(t){const e=t||{};e.colorScheme=rt(e.colorScheme,"element"),this.setRadius(e.radius,e),this.radiusType=rt(e.radiusType,"vdw"),this.radiusData=rt(e.radiusData,{}),this.radiusSize=rt(e.radiusSize,1),this.radiusScale=rt(e.radiusScale,1),this.assembly=rt(e.assembly,"default"),this.defaultAssembly=rt(e.defaultAssembly,""),"auto"===e.quality&&(e.quality=this.getQuality()),super.init(e),this.selection.signals.stringChanged.add((()=>{this.build()})),this.build()}setRadius(t,e){const i=Object.keys(ua);return"string"==typeof t&&i.includes(t.toLowerCase())?e.radiusType=t:void 0!==t&&(e.radiusType="size",e.radiusSize=t),this}getAssembly(){const t="default"===this.assembly?this.defaultAssembly:this.assembly;return this.structure.biomolDict[t]}getQuality(){let t;const e=this.structureView,i=this.getAssembly();t=i?i.getAtomCount(e):e.atomCount,we&&(t*=4);return e.atomStore.count/e.residueStore.count<2&&(t*=10),t<15e3?"high":t<8e4?"medium":"low"}create(){if(0===this.structureView.atomCount)return;if(!this.structureView.hasCoords())return void(this.needsBuild=!0);this.needsBuild=!1;const t=this.getAssembly();if(t)t.partList.forEach(((t,e)=>{const i=t.getView(this.structureView);if(0===i.atomCount)return;const r=this.createData(i,e);r&&(r.sview=i,r.instanceList=t.getInstanceList(),this.dataList.push(r))}));else{const t=this.createData(this.structureView,0);t&&(t.sview=this.structureView,this.dataList.push(t))}}update(t){!this.lazy||this.visible?this.needsBuild?this.build():this.dataList.forEach((e=>{e.bufferList.length>0&&this.updateData(t,e)}),this):Object.assign(this.lazyProps.what,t)}updateData(t,e){this.build()}getColorParams(){return Object.assign(Object.assign({},super.getColorParams()),{structure:this.structure})}getRadiusParams(t){return{type:this.radiusType,scale:this.radiusScale,size:this.radiusSize,data:this.radiusData}}getAtomParams(t,e){return Object.assign({what:t,colorParams:this.getColorParams(),radiusParams:this.getRadiusParams()},e)}getBondParams(t,e){return Object.assign({what:t,colorParams:this.getColorParams(),radiusParams:this.getRadiusParams()},e)}getAtomRadius(t){if(this.structureView.atomSet.isSet(t.index)){return new da(this.getRadiusParams()).atomRadius(t)}return 0}setSelection(t,e){return this.selection.setString(t,e),this}setParameters(t,e={},i=!1){const r=t||{};return this.setRadius(r.radius,r),void 0===r.radiusType&&void 0===r.radiusData&&void 0===r.radiusSize&&void 0===r.radiusScale||(e.radius=!0,Ce&&!this.disableImpostor||(i=!0)),void 0!==r.defaultAssembly&&r.defaultAssembly!==this.defaultAssembly&&("default"===this.assembly&&void 0===r.assembly||"default"===r.assembly)&&(i=!0),super.setParameters(r,e,i),this}getParameters(){return Object.assign(super.getParameters(),{sele:this.selection?this.selection.string:void 0,defaultAssembly:this.defaultAssembly})}attach(t){const e=this.viewer,i=this.bufferList;this.dataList.forEach((function(t){t.bufferList.forEach((function(r){i.push(r),e.add(r,t.instanceList)}))})),this.setVisibility(this.visible),t()}clear(){this.dataList.length=0,super.clear()}dispose(){this.structureView.dispose(),super.dispose()}}class Sh extends Ah{constructor(t,e,i){super(t,e,i),this.n=0,this.parameters=Object.assign({labelVisible:{type:"boolean"},labelSize:{type:"number",precision:3,max:10,min:.001},labelColor:{type:"color"},labelFontFamily:{type:"select",options:{"sans-serif":"sans-serif",monospace:"monospace",serif:"serif"},buffer:"fontFamily"},labelFontStyle:{type:"select",options:{normal:"normal",italic:"italic"},buffer:"fontStyle"},labelFontWeight:{type:"select",options:{normal:"normal",bold:"bold"},buffer:"fontWeight"},labelsdf:{type:"boolean",buffer:"sdf"},labelXOffset:{type:"number",precision:1,max:20,min:-20,buffer:"xOffset"},labelYOffset:{type:"number",precision:1,max:20,min:-20,buffer:"yOffset"},labelZOffset:{type:"number",precision:1,max:20,min:-20,buffer:"zOffset"},labelAttachment:{type:"select",options:{"bottom-left":"bottom-left","bottom-center":"bottom-center","bottom-right":"bottom-right","middle-left":"middle-left","middle-center":"middle-center","middle-right":"middle-right","top-left":"top-left","top-center":"top-center","top-right":"top-right"},rebuild:!0},labelBorder:{type:"boolean",buffer:"showBorder"},labelBorderColor:{type:"color",buffer:"borderColor"},labelBorderWidth:{type:"number",precision:2,max:.3,min:0,buffer:"borderWidth"},labelBackground:{type:"boolean",rebuild:!0},labelBackgroundColor:{type:"color",buffer:"backgroundColor"},labelBackgroundMargin:{type:"number",precision:2,max:2,min:0,rebuild:!0},labelBackgroundOpacity:{type:"range",step:.01,max:1,min:0,buffer:"backgroundOpacity"},labelFixedSize:{type:"boolean",buffer:"fixedSize"},lineOpacity:{type:"range",min:0,max:1,step:.01},linewidth:{type:"integer",max:50,min:1,buffer:!0}},this.parameters,{flatShaded:null})}init(t){const e=t||{};this.labelVisible=rt(e.labelVisible,!0),this.labelSize=rt(e.labelSize,2),this.labelColor=rt(e.labelColor,16777215),this.labelFontFamily=rt(e.labelFontFamily,"sans-serif"),this.labelFontStyle=rt(e.labelFontstyle,"normal"),this.labelFontWeight=rt(e.labelFontWeight,"bold"),this.labelsdf=rt(e.labelsdf,"Chrome"===xe),this.labelXOffset=rt(e.labelXOffset,0),this.labelYOffset=rt(e.labelYOffset,0),this.labelZOffset=rt(e.labelZOffset,.5),this.labelAttachment=rt(e.labelAttachment,"bottom-left"),this.labelBorder=rt(e.labelBorder,!1),this.labelBorderColor=rt(e.labelBorderColor,"lightgrey"),this.labelBorderWidth=rt(e.labelBorderWidth,.15),this.labelBackground=rt(e.labelBackground,!1),this.labelBackgroundColor=rt(e.labelBackgroundColor,"lightgrey"),this.labelBackgroundMargin=rt(e.labelBackgroundMargin,.5),this.labelBackgroundOpacity=rt(e.labelBackgroundOpacity,1),this.labelFixedSize=rt(e.labelFixedSize,!1),this.lineOpacity=rt(e.lineOpacity,1),this.linewidth=rt(e.linewidth,2),super.init(e)}update(t){t.position?this.build():super.update(t)}updateData(t,e){const i={};if(t&&!t.labelSize||Object.assign(i,{size:wi(this.n,this.labelSize)}),!t||t.labelColor){const t=new n(this.labelColor);Object.assign(i,{color:Ai(this.n,t.r,t.g,t.b)})}this.textBuffer.setAttributes(i)}setParameters(t,e={},i=!1){return t&&t.labelSize&&(e.labelSize=!0),t&&(t.labelColor||0===t.labelColor)&&(e.labelColor=!0,i=!0),super.setParameters(t,e,i),t&&void 0!==t.opacity&&this.textBuffer.setParameters({opacity:1}),t&&void 0!==t.labelVisible&&this.setVisibility(this.visible),this}setVisibility(t,e){return super.setVisibility(t,!0),this.textBuffer&&this.textBuffer.setVisibility(this.labelVisible&&this.visible),e||this.viewer.requestRender(),this}getLabelBufferParams(t={}){return super.getBufferParams(Object.assign({fontFamily:this.labelFontFamily,fontStyle:this.labelFontStyle,fontWeight:this.labelFontWeight,sdf:this.labelsdf,xOffset:this.labelXOffset,yOffset:this.labelYOffset,zOffset:this.labelZOffset,attachment:this.labelAttachment,showBorder:this.labelBorder,borderColor:this.labelBorderColor,borderWidth:this.labelBorderWidth,showBackground:this.labelBackground,backgroundColor:this.labelBackgroundColor,backgroundMargin:this.labelBackgroundMargin,backgroundOpacity:this.labelBackgroundOpacity,fixedSize:this.labelFixedSize,disablePicking:!0,visible:this.labelVisible},t,{opacity:1}))}getAtomRadius(){return 0}}function Ch(t,e){const i=t.getAtomProxy(),r=new de,n=e.length;if(0===n)return new Float32Array(0);const s=e[0].length,o=t.getAtomSet(),a=new Float32Array(n*s*3);let c=0;return e.forEach((function(e){let n=!1;for(let l=0;l 1.0 ){\ngl_FragColor = vec4( backgroundColor, backgroundOpacity );\n}else{\nfloat sdf = texture2D( fontTexture, texCoord ).a;\nif( showBorder ) sdf += borderWidth;\nfloat a = smoothstep(padding - gamma, padding + gamma, sdf);\nif( a < 0.2 ) discard;\na *= opacity;\nvec3 outgoingLight = vColor;\nif( showBorder && sdf < ( padding + borderWidth ) ){\noutgoingLight = borderColor;\n}\ngl_FragColor = vec4( outgoingLight, a );\n}\n#if defined( PICKING )\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Mh={};const Th={font:"sans-serif",size:36,style:"normal",variant:"normal",weight:"normal",outline:3,width:1024,height:1024};class Dh{constructor(t={}){this.gamma=1,this.mapped={},this.scratchW=0,this.scratchH=0,this.currentX=0,this.currentY=0,this.cutoff=.25,this.parameters=nt(t,Th);const e=this.parameters;this.radius=e.size/8,this.padding=e.size/3;const i=this.lineHeight=e.size+2*e.outline+Math.round(e.size/4),r=this.maxWidth=e.width/4,n=this.canvas=document.createElement("canvas");n.width=r,n.height=i;const s=this.context=this.canvas.getContext("2d",{willReadFrequently:!0});s.font=`${e.style} ${e.variant} ${e.weight} ${e.size}px ${e.font}`,s.fillStyle="black",s.textAlign="left",s.textBaseline="bottom",s.lineJoin="round",this.gridOuter=new Float64Array(i*r),this.gridInner=new Float64Array(i*r),this.f=new Float64Array(Math.max(i,r)),this.d=new Float64Array(Math.max(i,r)),this.z=new Float64Array(Math.max(i,r)+1),this.v=new Int16Array(Math.max(i,r)),this.data=new Uint8Array(e.width*e.height*4),this.canvas2=document.createElement("canvas"),this.canvas2.width=e.width,this.canvas2.height=e.height,this.context2=this.canvas2.getContext("2d"),this.placeholder=this.map(String.fromCharCode(65533));for(let t=32;t<=126;++t)this.map(String.fromCharCode(t));this.map(String.fromCharCode(176)),this.map(String.fromCharCode(8491)),this.texture=new H(this.canvas2),this.texture.flipY=!1,this.texture.needsUpdate=!0}map(t){const e=this.parameters;return void 0===this.mapped[t]&&(this.draw(t),this.currentX+this.scratchW>e.width&&(this.currentX=0,this.currentY+=this.scratchH),this.currentY+this.scratchH>e.height&&console.warn("canvas to small"),this.mapped[t]={x:this.currentX,y:this.currentY,w:this.scratchW,h:this.scratchH},this.context2.drawImage(this.canvas,0,0,this.scratchW,this.scratchH,this.currentX,this.currentY,this.scratchW,this.scratchH),this.currentX+=this.scratchW),this.mapped[t]}get(t){return this.mapped[t]||this.placeholder}draw(t){const e=this.parameters,i=this.lineHeight,r=e.outline,n=this.context,s=this.maxWidth,o=r,a=i-e.outline,c=n.measureText(t),l=Math.min(s,Math.ceil(c.width+2*o+1)),h=l*i;n.clearRect(0,0,l,i),n.fillText(t,o,a);const u=n.getImageData(0,0,l,i),d=u.data;for(let t=0;t= 0.0 ) {\ntrimSegment( start, end );\n} else if ( end.z < 0.0 && start.z >= 0.0 ) {\ntrimSegment( end, start );\n}\n}\nvec4 clipStart = projectionMatrix * start;\nvec4 clipEnd = projectionMatrix * end;\nvec2 ndcStart = clipStart.xy / clipStart.w;\nvec2 ndcEnd = clipEnd.xy / clipEnd.w;\nvec2 dir = ndcEnd - ndcStart;\ndir.x *= aspect;\ndir = normalize( dir );\nvec2 offset = vec2( dir.y, - dir.x );\ndir.x /= aspect;\noffset.x /= aspect;\nif ( mapping.x < 0.0 ) offset *= - 1.0;\noffset *= linewidth;\noffset /= resolution.y;\nvec4 clip = ( mapping.y < 0.5 ) ? clipStart : clipEnd;\noffset *= clip.w;\nclip.xy += offset;\ngl_Position = clip;\n#ifndef PICKING\nvViewPosition = ( projectionMatrixInverse * clip ).xyz;\n#endif\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n#include nearclip_vertex\n}"),Ne.add("shader/WideLine.frag","uniform vec3 diffuse;\nuniform float opacity;\nuniform float clipNear;\nuniform float clipRadius;\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\n#ifdef PICKING\nuniform float objectId;\nvarying vec3 vPickingColor;\n#else\n#include common\n#include fog_pars_fragment\nvarying vec3 vViewPosition;\nvarying vec3 vColor;\nvarying vec3 vColor2;\nvarying float flag;\n#endif\nvoid main() {\n#include nearclip_fragment\n#include radiusclip_fragment\n#if defined( PICKING )\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 outgoingLight = vec3( 0.0 );\nvec4 diffuseColor = vec4( diffuse, 1.0 );\nif ( flag < 0.0 ) {\ndiffuseColor.rgb *= vColor;\n} else {\ndiffuseColor.rgb *= vColor2;\n}\n#include alphatest_fragment\noutgoingLight = diffuseColor.rgb;\ngl_FragColor = vec4( outgoingLight, diffuseColor.a * opacity );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Oh=Object.assign({linewidth:2},Lo),Rh=Object.assign({linewidth:{uniform:!0}},No);class Lh extends Lc{constructor(e,r={}){super(e,r),this.parameterTypes=Rh,this.vertexShader="WideLine.vert",this.fragmentShader="WideLine.frag",!e.color2&&e.color&&(e.color2=e.color),this.addUniforms({linewidth:{value:this.parameters.linewidth},resolution:{value:new t},projectionMatrixInverse:{value:new i}}),this.addAttributes({position1:{type:"v3",value:null},position2:{type:"v3",value:null},color2:{type:"c",value:null}}),this.setAttributes(e),this.makeMapping()}get defaultParameters(){return Oh}setParameters(t){super.setParameters(t)}}Ve.add("wideline",Lh);class Nh extends Sh{constructor(t,e,i){super(t,e,i),this.type="angle",this.parameters=Object.assign({atomTriple:{type:"hidden",rebuild:!0},vectorVisible:{type:"boolean",default:!0},arcVisible:{type:"boolean",default:!0},sectorVisible:{type:"boolean",default:!0}},this.parameters),this.init(i)}init(t){const e=t||{};e.side=rt(e.side,"double"),e.opacity=rt(e.opacity,.5),this.atomTriple=rt(e.atomTriple,[]),this.arcVisible=rt(e.arcVisible,!0),this.sectorVisible=rt(e.sectorVisible,!0),this.vectorVisible=rt(e.vectorVisible,!0),super.init(e)}createData(t){if(!t.atomCount||!this.atomTriple.length)return;const e=function(t,e){return function(t){const e=[],i=t.length/9;for(let r=0;r radius2) {\ndiscard;\n}\n#ifdef CAP\nsurface_point = front_point;\n_normal = axis;\n#else\nsurface_point = ray_target + ( (-a1 - sqrt(d)) / a2 ) * ray_direction;\ndNV = dot(-axis, ray_direction);\nnear = dot(axis, end) / dNV;\nnew_point2 = ray_direction * near + ray_origin;\nif (dot(new_point2 - end, new_point2-base) < radius2) {\ndiscard;\n}\ninterior = true;\n#endif\n}\nif( end_cap_test > 0.0 )\n{\nfloat dNV;\nfloat near;\nvec3 end_point;\nif ( ortho == 1.0 ) {\nend_point = ray_target;\n} else {\ndNV = dot(axis, ray_direction);\nif (dNV < 0.0) {\ndiscard;\n}\nnear = dot(axis, end) / dNV;\nend_point = ray_direction * near + ray_origin;\n}\nif( dot(end_point - end, end_point-base) > radius2 ) {\ndiscard;\n}\n#ifdef CAP\nsurface_point = end_point;\n_normal = axis;\n#else\nsurface_point = ray_target + ( (-a1 - sqrt(d)) / a2 ) * ray_direction;\ndNV = dot(-axis, ray_direction);\nnear = dot(-axis, (base)) / dNV;\nnew_point2 = ray_direction * near + ray_origin;\nif (dot(new_point2 - base, new_point2-base) < radius2) {\ndiscard;\n}\ninterior = true;\n#endif\n}\ngl_FragDepthEXT = calcDepth( surface_point );\n#ifdef NEAR_CLIP\nif( calcClip( surface_point ) > 0.0 ){\ndist = (-a1 - sqrt(d)) / a2;\nsurface_point = ray_target + dist * ray_direction;\nif( calcClip( surface_point ) > 0.0 ) {\ndiscard;\n}\ninterior = true;\ngl_FragDepthEXT = calcDepth( surface_point );\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = max( 0.0, calcDepth( vec3( - ( clipNear - 0.5 ) ) ) + ( 0.0000001 / vRadius ) );\n}\n}else if( gl_FragDepthEXT <= 0.0 ){\ndist = (-a1 - sqrt(d)) / a2;\nsurface_point = ray_target + dist * ray_direction;\ninterior = true;\ngl_FragDepthEXT = calcDepth( surface_point );\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n}\n#else\nif( gl_FragDepthEXT <= 0.0 ){\ndist = (-a1 - sqrt(d)) / a2;\nsurface_point = ray_target + dist * ray_direction;\ninterior = true;\ngl_FragDepthEXT = calcDepth( surface_point );\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / vRadius );\n}\n}\n#endif\nif (gl_FragDepthEXT < 0.0) {\ndiscard;\n}\nif (gl_FragDepthEXT > 1.0) {\ndiscard;\n}\n#ifdef PICKING\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 vViewPosition = -surface_point;\nvec3 vNormal = _normal;\nvec3 vColor;\nif( distSq3( surface_point, end ) < distSq3( surface_point, base ) ){\nif( b < 0.0 ){\nvColor = vColor1;\n}else{\nvColor = vColor2;\n}\n}else{\nif( b > 0.0 ){\nvColor = vColor1;\n}else{\nvColor = vColor2;\n}\n}\nvec4 diffuseColor = vec4( diffuse, opacity );\nReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\nvec3 totalEmissiveLight = emissive;\n#include color_fragment\n#include roughnessmap_fragment\n#include metalnessmap_fragment\nvec3 normal = normalize( vNormal );\nvec3 nonPerturbedNormal = normal;\n#include lights_physical_fragment\n#include lights_fragment_begin\n#include lights_fragment_end\nvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveLight;\nif( interior ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Wh=new Float32Array([-1,1,-1,-1,-1,-1,1,1,-1,1,1,1,1,-1,-1,1,-1,1]),Xh=new Uint16Array([0,1,2,1,4,2,2,4,3,4,5,3]);class Yh extends $c{constructor(t,e={}){super("v3",t,e)}get mapping(){return Wh}get mappingIndices(){return Xh}get mappingIndicesSize(){return 12}get mappingSize(){return 6}get mappingItemSize(){return 3}}const Kh=Object.assign({openEnded:!1},Lo),Zh=Object.assign({openEnded:{updateShader:!0}},No);class Qh extends Yh{constructor(t,e={}){super(t,e),this.parameterTypes=Zh,this.isImpostor=!0,this.vertexShader="CylinderImpostor.vert",this.fragmentShader="CylinderImpostor.frag",this.addUniforms({modelViewMatrixInverse:{value:new i},ortho:{value:0}}),this.addAttributes({position1:{type:"v3",value:null},position2:{type:"v3",value:null},color2:{type:"c",value:null},radius:{type:"f",value:null}}),this.setAttributes(t),this.makeMapping()}get defaultParameters(){return Kh}getDefines(t){const e=Yh.prototype.getDefines.call(this,t);return this.parameters.openEnded||(e.CAP=1),e}}Object.assign({disableImpostor:!1},Gh,Kh);const Jh=class{constructor(t,e={}){return!t.color2&&t.color&&(t.color2=t.color),!Ce||e&&e.disableImpostor?new qh(t,e):new Qh(t,e)}};Ve.add("cylinder",Jh);class tu extends Ah{constructor(t,e,i){super(t,e,i),this.type="axes",this.parameters=Object.assign({radiusSize:{type:"number",precision:3,max:10,min:.001},sphereDetail:!0,radialSegments:!0,disableImpostor:!0,showAxes:{type:"boolean",rebuild:!0},showBox:{type:"boolean",rebuild:!0}},this.parameters,{assembly:null}),this.init(i)}init(t){const e=t||{};e.radiusSize=rt(e.radiusSize,.5),e.colorValue=rt(e.colorValue,"lightgreen"),e.useInteriorColor=rt(e.useInteriorColor,!0),this.showAxes=rt(e.showAxes,!0),this.showBox=rt(e.showBox,!1),super.init(e)}getPrincipalAxes(){let t;const e=this.getAssembly();return e&&(t=e.partList[0].getSelection()),this.structureView.getPrincipalAxes(t)}getAxesData(t){const i=this.getPrincipalAxes(),r=new n(this.colorValue);let s=0,o=0;this.showAxes&&(s+=6,o+=3),this.showBox&&(s+=8,o+=12);const a=new Float32Array(3*s),c=Ai(s,r.r,r.g,r.b),l=wi(s,this.radiusSize),h=new Float32Array(3*o),u=new Float32Array(3*o),d=Ai(o,r.r,r.g,r.b),m=wi(o,this.radiusSize);let f=0;if(this.showAxes){const t=function(t,e){t.toArray(a,2*f),e.toArray(a,2*f+3),t.toArray(h,f),e.toArray(u,f),f+=3};t(i.begA,i.endA),t(i.begB,i.endB),t(i.begC,i.endC)}if(this.showBox){const r=new e,{d1a:n,d2a:s,d3a:o,d1b:c,d2b:l,d3b:d}=i.getProjectedScaleForAtoms(t);let m=2*f;const p=function(t,e,n){r.copy(i.center).addScaledVector(i.normVecA,t).addScaledVector(i.normVecB,e).addScaledVector(i.normVecC,n),r.toArray(a,m),m+=3};p(n,s,o),p(n,s,d),p(n,l,d),p(n,l,o),p(c,l,d),p(c,l,o),p(c,s,o),p(c,s,d);let g=f;const y=function(t,e){r.fromArray(a,2*f+3*t).toArray(h,g),r.fromArray(a,2*f+3*e).toArray(u,g),g+=3};y(0,1),y(0,3),y(0,6),y(1,2),y(1,7),y(2,3),y(2,4),y(3,5),y(4,5),y(4,7),y(5,6),y(6,7)}const p=new Xs(i);return{vertex:{position:a,color:c,radius:l,picking:p},edge:{position1:h,position2:u,color:d,color2:d,radius:m,picking:p}}}create(){const t=this.getAxesData(this.structureView);this.sphereBuffer=new zc(t.vertex,this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!0})),this.cylinderBuffer=new Jh(t.edge,this.getBufferParams({openEnded:!0,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0})),this.dataList.push({sview:this.structureView,bufferList:[this.sphereBuffer,this.cylinderBuffer]})}createData(t){}updateData(t,e){const i=this.getAxesData(e.sview),r={},n={};t&&!t.position||(Object.assign(r,{position:i.vertex.position}),Object.assign(n,{position1:i.edge.position1,position2:i.edge.position2})),t&&!t.color||(Object.assign(r,{color:i.vertex.color}),Object.assign(n,{color:i.edge.color,color2:i.edge.color})),t&&!t.radius||(Object.assign(r,{radius:i.vertex.radius}),Object.assign(n,{radius:i.edge.radius})),this.sphereBuffer.setAttributes(r),this.cylinderBuffer.setAttributes(n)}}Re.add("axes",tu);class eu extends Ah{constructor(t,e,i){super(t,e,i),this.type="ball+stick",this.parameters=Object.assign({sphereDetail:!0,radialSegments:!0,openEnded:!0,disableImpostor:!0,aspectRatio:{type:"number",precision:1,max:10,min:1},lineOnly:{type:"boolean",rebuild:!0},cylinderOnly:{type:"boolean",rebuild:!0},multipleBond:{type:"select",rebuild:!0,options:{off:"off",symmetric:"symmetric",offset:"offset"}},bondScale:{type:"number",precision:2,max:1,min:.01},bondSpacing:{type:"number",precision:2,max:2,min:.5},linewidth:{type:"integer",max:50,min:1,buffer:!0}},this.parameters),this.init(i)}init(t){var e=t||{};e.radiusType=rt(e.radiusType,"size"),e.radiusSize=rt(e.radiusSize,.15),e.useInteriorColor=rt(e.useInteriorColor,!0),this.aspectRatio=rt(e.aspectRatio,2),this.lineOnly=rt(e.lineOnly,!1),this.cylinderOnly=rt(e.cylinderOnly,!1),this.multipleBond=rt(e.multipleBond,"off"),this.bondSpacing=rt(e.bondSpacing,1),this.bondScale=rt(e.bondScale,.4),this.linewidth=rt(e.linewidth,2),super.init(e)}getAtomRadius(t){return this.aspectRatio*super.getAtomRadius(t)}getAtomParams(t,e){var i=super.getAtomParams(t,e);return i.radiusParams.scale*=this.aspectRatio,i}getAtomData(t,e,i){return t.getAtomData(this.getAtomParams(e,i))}getBondParams(t,e){return e=Object.assign({multipleBond:this.multipleBond,bondSpacing:this.bondSpacing,bondScale:this.bondScale},e),super.getBondParams(t,e)}getBondData(t,e,i){return t.getBondData(this.getBondParams(e,i))}createData(t){const e=[];if(this.lineOnly)this.lineBuffer=new Lh(this.getBondData(t,{position:!0,color:!0,picking:!0}),this.getBufferParams({linewidth:this.linewidth})),e.push(this.lineBuffer);else{const i=new Jh(this.getBondData(t),this.getBufferParams({openEnded:this.openEnded,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0}));if(e.push(i),!this.cylinderOnly){const i=new zc(this.getAtomData(t),this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!0}));e.push(i)}}return{bufferList:e}}updateData(t,e){"off"!==this.multipleBond&&t&&t.radius&&(t.position=!0);const i=this.getBondData(e.sview,t);if(this.lineOnly){const r={};t&&!t.position||Object.assign(r,{position1:i.position1,position2:i.position2}),t&&!t.color||Object.assign(r,{color:i.color,color2:i.color2}),e.bufferList[0].setAttributes(r)}else{var r={};if(t&&!t.position||Object.assign(r,{position1:i.position1,position2:i.position2}),t&&!t.color||Object.assign(r,{color:i.color,color2:i.color2}),t&&!t.radius||Object.assign(r,{radius:i.radius}),e.bufferList[0].setAttributes(r),!this.cylinderOnly){var n=this.getAtomData(e.sview,t),s={};t&&!t.position||Object.assign(s,{position:n.position}),t&&!t.color||Object.assign(s,{color:n.color}),t&&!t.radius||Object.assign(s,{radius:n.radius}),e.bufferList[1].setAttributes(s)}}}setParameters(t={}){let e=!1;const i={};return(t.aspectRatio||t.bondSpacing||t.bondScale)&&(Object.assign(i,{radius:!0}),Ce&&!this.disableImpostor||(e=!0)),super.setParameters(t,i,e),this}}Re.add("ball+stick",eu);class iu extends eu{constructor(t,e,i){super(t,e,i),this.type="backbone",this.parameters=Object.assign({},this.parameters,{multipleBond:null,bondSpacing:null}),this.init(i)}init(t){var e=t||{};e.aspectRatio=rt(e.aspectRatio,1),e.radiusSize=rt(e.radiusSize,.25),super.init(e)}getAtomRadius(t){return t.isTrace()?super.getAtomRadius(t):0}getAtomData(t,e,i){return t.getBackboneAtomData(this.getAtomParams(e,i))}getBondData(t,e,i){return t.getBackboneBondData(this.getBondParams(e,i))}}Re.add("backbone",iu);class ru extends eu{constructor(t,e,i){super(t,e,i),this.type="base",this.parameters=Object.assign({},this.parameters,{multipleBond:null,bondSpacing:null})}init(t){let e=t||{};e.aspectRatio=rt(e.aspectRatio,1),e.radiusSize=rt(e.radiusSize,.3),super.init(e)}getAtomData(t,e,i){return t.getRungAtomData(this.getAtomParams(e,i))}getBondData(t,e,i){let r=this.getBondParams(e,i);return Object.assign(r.colorParams,{rung:!0}),t.getRungBondData(r)}}Re.add("base",ru);class nu{constructor(t,i){this.m=t,this.tension=i,this.dt=1/this.m,this.delta=1e-4,this.vec1=new e,this.vec2=new e,this.vDir=new e,this.vTan=new e,this.vNorm=new e,this.vBin=new e,this.m2=Math.ceil(this.m/2)}interpolateToArr(t,e,i,r,n,s,o){s[o+0]=Bt(t.x,e.x,i.x,r.x,n,this.tension),s[o+1]=Bt(t.y,e.y,i.y,r.y,n,this.tension),s[o+2]=Bt(t.z,e.z,i.z,r.z,n,this.tension)}interpolateToVec(t,e,i,r,n,s){s.x=Bt(t.x,e.x,i.x,r.x,n,this.tension),s.y=Bt(t.y,e.y,i.y,r.y,n,this.tension),s.z=Bt(t.z,e.z,i.z,r.z,n,this.tension)}interpolatePosition(t,e,i,r,n,s){for(var o=0;o1&&(l=1),this.interpolateToVec(t,e,i,r,c,this.vec1),this.interpolateToVec(t,e,i,r,l,this.vec2),this.vec2.sub(this.vec1).normalize(),this.vec2.toArray(n,h)}}vectorSubdivide(t,e,i,r,n){let s,o=e.next(),a=e.next(),c=e.next();const l=e.size,h=l-1;let u=r||0;for(let r=0;r0&&e{if(t.residueCount<4)return;i.push(t);const r=this.getSpline(t),n=this.getAspectRatio(t),s=r.getSubdividedPosition(),o=r.getSubdividedOrientation(),a=r.getSubdividedColor(this.getColorParams()),c=r.getSubdividedPicking(),l=r.getSubdividedSize(this.getRadiusParams());e.push(new lu(Object.assign({},s,o,a,c,l),this.getBufferParams({radialSegments:this.radialSegments,aspectRatio:n,capped:this.capped})))}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){Te&&Ie.time(this.type+" repr update"),t=t||{};for(var i=0,r=e.polymerList.length;i0;Kr(w,b,A);const n=Yr(w,x)<0;if(nn(w,x,Yr(x,_)),Kr(S,_,w),nn(w,x,Yr(x,v)),Kr(C,v,w),0===en(S)||0===en(C))continue;sn(S,S),sn(C,C);const B=s[T]=un(S,C);a[T]=(bi*B).toFixed(1)+String.fromCharCode(176),Xr(k,S,x),sn(k,k),Yr(k,C)<0&&hn(k,k),Ph(w,A,S,k,B/2),Jr(w,o,3*T);const F=Math.ceil(B/i),E=F+(e.extendLine?4:2),$=e.extendLine?36:0,O=new Float32Array(3*E),R=new Float32Array(3*E),L=new Float32Array(9*F),N=new Float32Array($);c[T]=O,l[T]=R,h[T]=L,u[T]=N,e.extendLine&&(r?(Kr(w,p,y),sn(w,w),nn(P,w,1/Yr(S,w)),Zr(P,P,y)):(nn(P,_,1/Yr(S,_)),Zr(P,P,g)),n?(Kr(w,b,g),sn(w,w),nn(I,w,1/Yr(C,w)),Zr(I,I,g)):(nn(I,v,1/Yr(C,v)),Zr(I,I,y))),Zr(M,A,S);let z=0;e.extendLine?(Jr(p,O,z),Jr(P,R,z),z+=3,Jr(P,O,z),Jr(M,R,z),z+=3,Jr(P,N,0),Jr(M,N,3),Jr(r?y:g,N,6),Jr(r?y:g,N,9),Jr(M,N,12),Jr(A,N,15)):(Jr(A,O,z),Jr(M,R,z),z+=3);const U=function(t,e){const i=9*e;Jr(A,L,i),Jr(M,L,i+3),Jr(M,O,z),Ph(M,A,S,k,t),Jr(M,L,i+6),Jr(M,R,z),z+=3};let V=0;for(let t=i;t{const e=mu(i,t);Object.assign(t,e)})),e.side=rt(e.side,"double"),e.opacity=rt(e.opacity,.5),e.radiusType=rt(e.radiusType,"size"),e.radiusSize=rt(e.radiusSize,.15),super.init(e)}getHistogramBinBorderBufferParameters(){return this.getBufferParams({linewidth:this.histogramBinBorderWidth,visible:this.histogramBinBorderVisible,opacity:this.histogramBinBorderOpacity})}getBondArrowsBufferParameters(){return this.getBufferParams({linewidth:this.bondArrowWidth,visible:this.bondArrowVisible,opacity:this.bondArrowOpacity})}getOpaqueMiddleDiscBufferParameters(){return this.getBufferParams({visible:this.opaqueMiddleDiscVisible,opacity:this.opaqueMiddleDiscOpacity})}getHistogramBufferParameters(){return this.getBufferParams({visible:!0,opacity:this.histogramOpacity,side:"double"})}createData(t){if(!t.atomCount||!this.histogramsData.length)return;this.histogramsData.forEach((e=>e.atomPositions=Ch(t,[e.atomQuad])));const e=this.scaleBinToSectorArea?function(t){return Math.sqrt(t)}:function(t){return t};function i(t){const e=t.map((t=>t.length)),i=new Float32Array(Di(e));let r=0;for(let e=0;et.startPoints))),position2:i(t.map((t=>t.endPoints))),color:i(t.map((t=>t.startColors))),color2:i(t.map((t=>t.endColors)))},e)}function n(t,e){return new Uo({position:i(t.map((t=>t.triangles))),color:i(t.map((t=>t.triangleColors)))},e)}this.histogramsData.forEach((t=>t.histogram360Scaled=t.histogram360.map(e)));const s=[];for(let t=0;t=3&&(e=gu(i)),void 0!==e&&s.push(e)}return this.frontHistogramBinBordersBuffer=r(s.map((t=>t.frontHistogramBinBorders)),this.getHistogramBinBorderBufferParameters()),this.backHistogramBinBordersBuffer=r(s.map((t=>t.backHistogramBinBorders)),this.getHistogramBinBorderBufferParameters()),this.adjacentBondArrowsBuffer=r(s.map((t=>t.adjacentBondArrows)),this.getBondArrowsBufferParameters()),this.distantBondArrowsBuffer=r(s.map((t=>t.distantBondArrows)),this.getBondArrowsBufferParameters()),this.opaqueMiddleDiscBuffer=n(s.map((t=>t.opaqueMiddleDisc)),this.getOpaqueMiddleDiscBufferParameters()),this.frontHistogramBuffer=n(s.map((t=>t.frontHistogram)),this.getHistogramBufferParameters()),this.backHistogramBuffer=n(s.map((t=>t.backHistogram)),this.getHistogramBufferParameters()),{bufferList:[].concat(this.frontHistogramBinBordersBuffer,this.backHistogramBinBordersBuffer,this.adjacentBondArrowsBuffer,this.distantBondArrowsBuffer,this.opaqueMiddleDiscBuffer,this.frontHistogramBuffer,this.backHistogramBuffer)}}setParameters(t){return super.setParameters(t,{},!1),t&&void 0!==t.histogramBinBorderVisible&&this.setVisibility(this.visible),this}setVisibility(t,e){return super.setVisibility(t,!0),this.frontHistogramBinBordersBuffer&&this.frontHistogramBinBordersBuffer.setVisibility(this.histogramBinBorderVisible),this.backHistogramBinBordersBuffer&&this.backHistogramBinBordersBuffer.setVisibility(this.histogramBinBorderVisible),e||this.viewer.requestRender(),this}}function gu(t){const e=t.atomPositions,i=t.histogram360Scaled,r=i.length<=180?360:2*i.length,n={triangles:new Float32Array(3*r*3),triangleColors:fu(t.opaqueMiddleDiscColor,3*r)},s={triangles:new Float32Array(3*i.length*3),triangleColors:fu(t.frontHistogramColor,3*i.length)},o={triangles:new Float32Array(3*i.length*3),triangleColors:fu(t.backHistogramColor,3*i.length)},a={startPoints:new Float32Array(3*i.length),endPoints:new Float32Array(3*i.length),startColors:fu(t.histogramBinBorderColor,i.length),endColors:fu(t.histogramBinBorderColor,i.length)},c={startPoints:new Float32Array(3*i.length),endPoints:new Float32Array(3*i.length),startColors:fu(t.histogramBinBorderColor,i.length),endColors:fu(t.histogramBinBorderColor,i.length)},l={startPoints:new Float32Array(6),endPoints:new Float32Array(6),startColors:fu(t.adjacentBondArrowColor,i.length),endColors:fu(t.adjacentBondArrowColor,i.length)},h={startPoints:new Float32Array(6),endPoints:new Float32Array(6),startColors:fu(t.distantBondArrowColor,i.length),endColors:fu(t.distantBondArrowColor,i.length)},u=Wr(),d=Wr(),m=Wr(),f=Wr(),p=Wr(),g=Wr(),y=Wr(),b=Wr(),_=Wr(),x=Wr(),v=Wr(),w=Wr(),A=Wr(),S=Wr(),C=Wr(),P=Wr(),I=[u,d,m,f];for(let t=0;t{let d=e[0],m=e[1];if("number"==typeof d&&Number.isInteger(d)&&"number"==typeof m&&Number.isInteger(m)){if(!u.get(d)||!u.get(m))return void(h+=1);c.index=d,l.index=m}else{s.setString(d),o.setString(m);var f=t.getAtomIndices(s),p=t.getAtomIndices(o);if(!f.length||!p.length)return void(h+=1);c.index=f[0],l.index=p[0]}a.addBond(c,l,1),i-=h;var g=c.distanceTo(l);switch(this.labelUnit){case"angstrom":r[i]=g.toFixed(2)+" "+String.fromCharCode(8491);break;case"nm":r[i]=(g/10).toFixed(2)+" nm";break;default:r[i]=g.toFixed(2)}var y=3*i;n[y+0]=(c.x+l.x)/2,n[y+1]=(c.y+l.y)/2,n[y+2]=(c.z+l.z)/2})),h>0&&(i-=h,n=n.subarray(0,3*i));var d=new Fn(a.count,!0);return{text:r,position:n,bondSet:d,bondStore:a}}getBondData(t,e,i){const r=t.getBondData(this.getBondParams(e,i));return r.picking&&(r.picking=new Qs(r.picking.array,r.picking.structure,i.bondStore)),r}createData(t){if(!t.atomCount||!this.atomPair.length)return;const e=this.atomPair.length,i=new n(this.labelColor),r=this.getDistanceData(t,this.atomPair);this.textBuffer=new $h({position:r.position,size:wi(e,this.labelSize),color:Ai(e,i.r,i.g,i.b),text:r.text},this.getLabelBufferParams());const s={bondSet:r.bondSet,bondStore:r.bondStore},o=this.getBondData(t,{position:!0,color:!0,picking:!0,radius:this.useCylinder},s);return this.useCylinder?this.distanceBuffer=new Jh(o,this.getBufferParams({openEnded:this.openEnded,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0})):this.distanceBuffer=new Lh(mn(o),this.getBufferParams({linewidth:this.linewidth,visible:this.lineVisible,opacity:this.lineOpacity})),{bondSet:r.bondSet,bondStore:r.bondStore,position:r.position,bufferList:[this.textBuffer,this.distanceBuffer]}}updateData(t,e){super.updateData(t,e);const i={bondSet:e.bondSet,bondStore:e.bondStore},r=this.getBondData(e.sview,t,i),n={};t&&!t.color||Object.assign(n,{color:r.color,color2:r.color2}),t&&!t.radius||Object.assign(n,{radius:r.radius}),this.distanceBuffer.setAttributes(n)}setParameters(t){return super.setParameters(t,{},!1),this.useCylinder||(t&&t.lineOpacity&&this.distanceBuffer.setParameters({opacity:t.lineOpacity}),t&&void 0!==t.opacity&&this.distanceBuffer.setParameters({opacity:this.lineOpacity}),t&&t.linewidth&&this.distanceBuffer.setParameters({linewidth:t.linewidth})),this}}function bu(t){return 2*(t.position.length/3)*3}Re.add("distance",yu);const _u=Object.assign({scale:1,color:"grey"},Lo);class xu extends zo{constructor(t,e={}){super({position:new Float32Array(bu(t)),color:new Float32Array(bu(t))},e),this.isLine=!0,this.vertexShader="Line.vert",this.fragmentShader="Line.frag";const i=new n(this.parameters.color),r=this.geometry.attributes;Ai(bu(t)/3,i.r,i.g,i.b,r.color.array),this.setAttributes(t)}get defaultParameters(){return _u}setAttributes(t={}){const e=this.geometry.attributes;let i,r,n;t.position&&t.vector&&(i=t.position,r=t.vector,n=e.position.array,e.position.needsUpdate=!0);const s=this.size/2,o=this.parameters.scale;if(i&&r)for(let t=0;t{if(t.residueCount<4)return;i.push(t);const r=new Aa(t),n=r.getPosition(),s=r.getColor(this.getColorParams()),o=r.getSize(this.getRadiusParams()),a=r.getPicking();e.push(new zc({position:n.center,color:s.color,radius:o.size,picking:a.picking},this.getBufferParams({sphereDetail:this.sphereDetail,disableImpostor:this.disableImpostor,dullInterior:!0})),new xu({position:n.center,vector:n.axis},this.getBufferParams({color:"skyblue",scale:1})),new xu({position:n.center,vector:n.resdir},this.getBufferParams({color:"lightgreen",scale:1})))}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){Te&&Ie.time(this.type+" repr update"),t=t||{};for(let i=0,r=e.polymerList.length;i radius2) {\nspaceposition.y = mapping.y * 1.5 * radius1;\nspaceposition.x = mapping.x * 1.5 * radius1;\n} else {\nspaceposition.y = mapping.y * 1.5 * radius2;\nspaceposition.x = mapping.x * 1.5 * radius2;\n}\nspaceposition.w = 1.0;\nvec4 e3 = vec4( 1.0 );\nvec3 e1, e1_temp, e2, e2_temp;\ne3.xyz = normalize(position_atom1-position_atom2);\nif (e3.z == 0.0) { e3.z = 0.0000000000001;}\nif ( (position_atom1.x - position_atom2.x) == 0.0) { position_atom1.x += 0.001;}\nif ( (position_atom1.y - position_atom2.y) == 0.0) { position_atom1.y += 0.001;}\nif ( (position_atom1.z - position_atom2.z) == 0.0) { position_atom1.z += 0.001;}\nvec4 focus = vec4( 1.0 );\nfocus.x = ( position_atom1.x*position_atom1.x - position_atom2.x*position_atom2.x +\n( radius2*radius2 - radius1*radius1 )*e3.x*e3.x/shrink )/(2.0*(position_atom1.x - position_atom2.x));\nfocus.y = ( position_atom1.y*position_atom1.y - position_atom2.y*position_atom2.y +\n( radius2*radius2 - radius1*radius1 )*e3.y*e3.y/shrink )/(2.0*(position_atom1.y - position_atom2.y));\nfocus.z = ( position_atom1.z*position_atom1.z - position_atom2.z*position_atom2.z +\n( radius2*radius2 - radius1*radius1 )*e3.z*e3.z/shrink )/(2.0*(position_atom1.z - position_atom2.z));\ne1.x = 1.0;\ne1.y = 1.0;\ne1.z = ( (e3.x*focus.x + e3.y*focus.y + e3.z*focus.z) - e1.x*e3.x - e1.y*e3.y)/e3.z;\ne1_temp = e1 - focus.xyz;\ne1 = normalize(e1_temp);\ne2_temp = e1.yzx * e3.zxy - e1.zxy * e3.yzx;\ne2 = normalize(e2_temp);\nmat3 R= mat3( e1.xyz, e2.xyz, e3.xyz );\nvertex_position.xyz = R * spaceposition.xyz;\nvertex_position.w = 1.0;\nvertex_position.x += (position_atom1.x+position_atom2.x) / 2.0;\nvertex_position.y += (position_atom1.y+position_atom2.y) / 2.0;\nvertex_position.z += (position_atom1.z+position_atom2.z) / 2.0;\ngl_Position = modelViewProjectionMatrix * vertex_position;\nvec4 i_near, i_far;\nvec4 near = gl_Position;\nnear.z = 0.0 ;\nnear = modelViewProjectionMatrixInverse * near;\ni_near = near;\nvec4 far = gl_Position;\nfar.z = far.w ;\ni_far = modelViewProjectionMatrixInverse * far;\nprime1 = vec4( position_atom1 - (position_atom1 - focus.xyz)*shrink, 1.0 );\nprime2 = vec4( position_atom2 - (position_atom2 - focus.xyz)*shrink, 1.0 );\nfloat Rsquare = (radius1*radius1/shrink) - (\n(position_atom1.x - focus.x)*(position_atom1.x - focus.x) +\n(position_atom1.y - focus.y)*(position_atom1.y - focus.y) +\n(position_atom1.z - focus.z)*(position_atom1.z - focus.z)\n);\nfocus.w = Rsquare;\nmatrix_near = mat4( i_near, i_far, focus, e3 );\ngl_Position.z = 1.0;\n}"),Ne.add("shader/HyperballStickImpostor.frag","#define STANDARD\n#define IMPOSTOR\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 interiorColor;\nuniform float interiorDarkening;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\nuniform float clipNear;\nuniform float shrink;\nuniform mat4 modelViewMatrix;\nuniform mat4 modelViewProjectionMatrix;\nuniform mat4 modelViewMatrixInverseTranspose;\nuniform mat4 projectionMatrix;\nvarying mat4 matrix_near;\nvarying vec4 prime1;\nvarying vec4 prime2;\nvarying float vRadius;\nvarying float vRadius2;\n#ifdef PICKING\nuniform float objectId;\nvarying vec3 vPickingColor;\n#else\nvarying vec3 vColor1;\nvarying vec3 vColor2;\n#include common\n#include fog_pars_fragment\n#include bsdfs\n#include lights_pars_begin\n#include lights_physical_pars_fragment\n#endif\nbool interior = false;\nfloat calcClip( vec4 cameraPos ){\nreturn dot( cameraPos, vec4( 0.0, 0.0, 1.0, clipNear - 0.5 ) );\n}\nfloat calcClip( vec3 cameraPos ){\nreturn calcClip( vec4( cameraPos, 1.0 ) );\n}\nfloat calcDepth( in vec3 cameraPos ){\nvec2 clipZW = cameraPos.z * projectionMatrix[2].zw + projectionMatrix[3].zw;\nreturn 0.5 + 0.5 * clipZW.x / clipZW.y;\n}\nstruct Ray {\nvec3 origin ;\nvec3 direction ;\n};\nbool cutoff_plane (vec3 M, vec3 cutoff, vec3 x3){\nfloat a = x3.x;\nfloat b = x3.y;\nfloat c = x3.z;\nfloat d = -x3.x*cutoff.x-x3.y*cutoff.y-x3.z*cutoff.z;\nfloat l = a*M.x+b*M.y+c*M.z+d;\nif (l<0.0) {return true;}\nelse{return false;}\n}\nvec3 isect_surf(Ray r, mat4 matrix_coef){\nvec4 direction = vec4(r.direction, 0.0);\nvec4 origin = vec4(r.origin, 1.0);\nfloat a = dot(direction,(matrix_coef*direction));\nfloat b = dot(origin,(matrix_coef*direction));\nfloat c = dot(origin,(matrix_coef*origin));\nfloat delta =b*b-a*c;\ngl_FragColor.a = 1.0;\nif (delta<0.0){\ndiscard;\n}\nfloat t1 =(-b-sqrt(delta))/a;\nreturn r.origin+t1*r.direction;\n}\nvec3 isect_surf2(Ray r, mat4 matrix_coef){\nvec4 direction = vec4(r.direction, 0.0);\nvec4 origin = vec4(r.origin, 1.0);\nfloat a = dot(direction,(matrix_coef*direction));\nfloat b = dot(origin,(matrix_coef*direction));\nfloat c = dot(origin,(matrix_coef*origin));\nfloat delta =b*b-a*c;\ngl_FragColor.a = 1.0;\nif (delta<0.0){\ndiscard;\n}\nfloat t2 =(-b+sqrt(delta))/a;\nreturn r.origin+t2*r.direction;\n}\nRay primary_ray(vec4 near1, vec4 far1){\nvec3 near=near1.xyz/near1.w;\nvec3 far=far1.xyz/far1.w;\nreturn Ray(near,far-near);\n}\nfloat update_z_buffer(vec3 M, mat4 ModelViewP){\nfloat depth1;\nvec4 Ms=(ModelViewP*vec4(M,1.0));\nreturn depth1=(1.0+Ms.z/Ms.w)/2.0;\n}\nvoid main(){\nfloat radius = max( vRadius, vRadius2 );\nvec4 i_near, i_far, focus;\nvec3 e3, e1, e1_temp, e2;\ni_near = vec4(matrix_near[0][0],matrix_near[0][1],matrix_near[0][2],matrix_near[0][3]);\ni_far = vec4(matrix_near[1][0],matrix_near[1][1],matrix_near[1][2],matrix_near[1][3]);\nfocus = vec4(matrix_near[2][0],matrix_near[2][1],matrix_near[2][2],matrix_near[2][3]);\ne3 = vec3(matrix_near[3][0],matrix_near[3][1],matrix_near[3][2]);\ne1.x = 1.0;\ne1.y = 1.0;\ne1.z = ( (e3.x*focus.x + e3.y*focus.y + e3.z*focus.z) - e1.x*e3.x - e1.y*e3.y)/e3.z;\ne1_temp = e1 - focus.xyz;\ne1 = normalize(e1_temp);\ne2 = normalize(cross(e1,e3));\nvec4 equation = focus;\nfloat shrinkfactor = shrink;\nfloat t1 = -1.0/(1.0-shrinkfactor);\nfloat t2 = 1.0/(shrinkfactor);\nvec4 colonne1, colonne2, colonne3, colonne4;\nmat4 mat;\nvec3 equation1 = vec3(t2,t2,t1);\nfloat A1 = - e1.x*equation.x - e1.y*equation.y - e1.z*equation.z;\nfloat A2 = - e2.x*equation.x - e2.y*equation.y - e2.z*equation.z;\nfloat A3 = - e3.x*equation.x - e3.y*equation.y - e3.z*equation.z;\nfloat A11 = equation1.x*e1.x*e1.x + equation1.y*e2.x*e2.x + equation1.z*e3.x*e3.x;\nfloat A21 = equation1.x*e1.x*e1.y + equation1.y*e2.x*e2.y + equation1.z*e3.x*e3.y;\nfloat A31 = equation1.x*e1.x*e1.z + equation1.y*e2.x*e2.z + equation1.z*e3.x*e3.z;\nfloat A41 = equation1.x*e1.x*A1 + equation1.y*e2.x*A2 + equation1.z*e3.x*A3;\nfloat A22 = equation1.x*e1.y*e1.y + equation1.y*e2.y*e2.y + equation1.z*e3.y*e3.y;\nfloat A32 = equation1.x*e1.y*e1.z + equation1.y*e2.y*e2.z + equation1.z*e3.y*e3.z;\nfloat A42 = equation1.x*e1.y*A1 + equation1.y*e2.y*A2 + equation1.z*e3.y*A3;\nfloat A33 = equation1.x*e1.z*e1.z + equation1.y*e2.z*e2.z + equation1.z*e3.z*e3.z;\nfloat A43 = equation1.x*e1.z*A1 + equation1.y*e2.z*A2 + equation1.z*e3.z*A3;\nfloat A44 = equation1.x*A1*A1 + equation1.y*A2*A2 + equation1.z*A3*A3 - equation.w;\ncolonne1 = vec4(A11,A21,A31,A41);\ncolonne2 = vec4(A21,A22,A32,A42);\ncolonne3 = vec4(A31,A32,A33,A43);\ncolonne4 = vec4(A41,A42,A43,A44);\nmat = mat4(colonne1,colonne2,colonne3,colonne4);\nRay ray = primary_ray(i_near,i_far) ;\nvec3 M;\nM = isect_surf(ray, mat);\nif (cutoff_plane(M, prime1.xyz, -e3) || cutoff_plane(M, prime2.xyz, e3)){ discard; }\nvec4 M1 = vec4(M,1.0);\nvec4 M2 = mat*M1;\nvec3 _normal = ( modelViewMatrixInverseTranspose * M2 ).xyz;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix) ;\n#ifdef NEAR_CLIP\nif( calcClip( modelViewMatrix * vec4( M, 1.0 ) ) > 0.0 ){\nM = isect_surf2(ray, mat);\nif( calcClip( modelViewMatrix * vec4( M, 1.0 ) ) > 0.0 )\ndiscard;\ninterior = true;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix) ;\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = max( 0.0, calcDepth( vec3( - ( clipNear - 0.5 ) ) ) + ( 0.0000001 / radius ) );\n}\n}else if( gl_FragDepthEXT <= 0.0 ){\nM = isect_surf2(ray, mat);\ninterior = true;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix);\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / radius );\n}\n}\n#else\nif( gl_FragDepthEXT <= 0.0 ){\nM = isect_surf2(ray, mat);\ninterior = true;\ngl_FragDepthEXT = update_z_buffer(M, modelViewProjectionMatrix) ;\nif( gl_FragDepthEXT >= 0.0 ){\ngl_FragDepthEXT = 0.0 + ( 0.0000001 / radius );\n}\n}\n#endif\nif (cutoff_plane(M, prime1.xyz, -e3) || cutoff_plane(M, prime2.xyz, e3)){ discard; }\nif (gl_FragDepthEXT < 0.0)\ndiscard;\nif (gl_FragDepthEXT > 1.0)\ndiscard;\nfloat distance_ratio = ((M.x-prime2.x)*e3.x + (M.y-prime2.y)*e3.y +(M.z-prime2.z)*e3.z) /\ndistance(prime2.xyz,prime1.xyz);\n#ifdef PICKING\nif( opacity < 0.3 )\ndiscard;\ngl_FragColor = vec4( vPickingColor, objectId );\n#else\nvec3 vViewPosition = -( modelViewMatrix * vec4( M, 1.0 ) ).xyz;\nvec3 vNormal = _normal;\nvec3 vColor;\nif( distance_ratio>0.5 ){\nvColor = vColor1;\n}else{\nvColor = vColor2;\n}\nvec4 diffuseColor = vec4( diffuse, opacity );\nReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\nvec3 totalEmissiveLight = emissive;\n#include color_fragment\n#include roughnessmap_fragment\n#include metalnessmap_fragment\nvec3 normal = normalize( vNormal );\nvec3 nonPerturbedNormal = normal;\n#include lights_physical_fragment\n#include lights_fragment_begin\n#include lights_fragment_end\nvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveLight;\nif( interior ){\n#ifdef USE_INTERIOR_COLOR\noutgoingLight.xyz = interiorColor;\n#else\n#ifdef DIFFUSE_INTERIOR\noutgoingLight.xyz = vColor;\n#endif\n#endif\noutgoingLight.xyz *= 1.0 - interiorDarkening;\n}\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );\n#include premultiplied_alpha_fragment\n#include tonemapping_fragment\n#include colorspace_fragment\n#include fog_fragment\n#endif\n}");const Au=new Float32Array([-1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,-1,1,-1,1,1,-1,1,1,1,-1,1,1]),Su=new Uint16Array([0,1,2,0,2,3,1,5,6,1,6,2,4,6,5,4,7,6,0,7,4,0,3,7,0,5,1,0,4,5,3,2,6,3,6,7]);class Cu extends $c{constructor(t,e={}){super("v3",t,e)}get mapping(){return Au}get mappingIndices(){return Su}get mappingIndicesSize(){return 36}get mappingSize(){return 8}get mappingItemSize(){return 3}}const Pu=Object.assign({shrink:.14},Lo),Iu=Object.assign({shrink:{uniform:!0}},No);class ku extends Cu{constructor(t,e={}){super(t,e),this.parameterTypes=Iu,this.isImpostor=!0,this.vertexShader="HyperballStickImpostor.vert",this.fragmentShader="HyperballStickImpostor.frag",this.addUniforms({modelViewProjectionMatrix:{value:new i},modelViewProjectionMatrixInverse:{value:new i},modelViewMatrixInverseTranspose:{value:new i},shrink:{value:this.parameters.shrink}}),this.addAttributes({position1:{type:"v3",value:null},position2:{type:"v3",value:null},color2:{type:"c",value:null},radius:{type:"f",value:null},radius2:{type:"f",value:null}}),this.setAttributes(t),this.makeMapping()}get defaultParameters(){return Pu}}Object.assign({disableImpostor:!1},Gh,Pu);const Mu=class{constructor(t,e={}){return!Ce||e&&e.disableImpostor?(t.radius=function(t,e){const i=t.length,r=new Float32Array(i);for(let n=0;na.push(r.atomLabel(t)))))}else if("residue"===this.labelGrouping){e&&!e.position||(c=[]),e&&!e.color||(h=[]),e&&!e.radius||(l=[]),e&&!e.text||(a=[]),i.colorParams&&(i.colorParams.structure=t.getStructure());const u=$e.getScheme(i.colorParams),d=new da(i.radiusParams),m=t.getAtomProxy();let f=0;t.eachResidue((t=>{const i=3*f;t.isProtein()||t.isNucleic()?(m.index=t.traceAtomIndex,e&&!e.position||m.positionToArray(c,i)):(m.index=t.atomOffset,e&&!e.position||t.positionToArray(c,i)),e&&!e.color||u.atomColorToArray(m,h,i),e&&!e.radius||(l[f]=d.atomRadius(m)),e&&!e.text||a.push(r.atomLabel(m)),++f})),e&&!e.position||(n=new Float32Array(c)),e&&!e.color||(o=new Float32Array(h)),e&&!e.radius||(s=new Float32Array(l))}return{position:n,size:s,color:o,text:a}}createData(t){return{bufferList:[new $h(this.getTextData(t,{position:!0,color:!0,radius:!0,text:!0}),this.getBufferParams({fontFamily:this.fontFamily,fontStyle:this.fontStyle,fontWeight:this.fontWeight,xOffset:this.xOffset,yOffset:this.yOffset,zOffset:this.zOffset,attachment:this.attachment,showBorder:this.showBorder,borderColor:this.borderColor,borderWidth:this.borderWidth,showBackground:this.showBackground,backgroundColor:this.backgroundColor,backgroundMargin:this.backgroundMargin,backgroundOpacity:this.backgroundOpacity,fixedSize:this.fixedSize}))]}}updateData(t,e){e.bufferList[0].setAttributes(this.getTextData(e.sview,t))}getAtomRadius(){return 0}}function Fu(t){const e=t.getAtomSet(),i=t.getBondSet(),r=t.getBondProxy();return i.forEach((function(t){r.index=t,e.clear(r.atomIndex1),e.clear(r.atomIndex2)})),e}Re.add("label",Bu);class Eu extends Ah{constructor(t,e,i){super(t,e,i),this.type="line",this.parameters=Object.assign({multipleBond:{type:"select",rebuild:!0,options:{off:"off",symmetric:"symmetric",offset:"offset"}},bondSpacing:{type:"number",precision:2,max:2,min:.5},linewidth:{type:"integer",max:50,min:1,buffer:!0},lines:{type:"boolean",rebuild:!0},crosses:{type:"select",rebuild:!0,options:{off:"off",lone:"lone",all:"all"}},crossSize:{type:"number",precision:2,max:2,min:.1}},this.parameters,{flatShaded:null,side:null,wireframe:null,roughness:null,metalness:null}),this.init(i)}init(t){var e=t||{};this.multipleBond=rt(e.multipleBond,"off"),this.bondSpacing=rt(e.bondSpacing,1),this.linewidth=rt(e.linewidth,2),this.lines=rt(e.lines,!0),this.crosses=rt(e.crosses,"lone"),this.crossSize=rt(e.crossSize,.4),super.init(e)}getAtomRadius(t){return.1}getBondParams(t,e){return e=Object.assign({multipleBond:this.multipleBond,bondSpacing:this.bondSpacing,radiusParams:{type:"size",size:.1,scale:1}},e),super.getBondParams(t,e)}_crossData(t,e){if(t&&!t.position&&!t.color)return;const i={};"lone"===this.crosses&&Object.assign(i,{atomSet:Fu(e)});const r=e.getAtomData(this.getAtomParams(t,i)),n={},s=r.position,o=r.color,a=r.picking,c=(s||o).length,l=3*c;let h=new Float32Array(0),u=new Float32Array(0),d=new Float32Array(0),m=new Float32Array(0),f=0,p=new Float32Array(0);t&&!t.position||(h=n.position1=new Float32Array(l),u=n.position2=new Float32Array(l),f=this.crossSize/2),t&&!t.color||(d=n.color=new Float32Array(l),m=n.color2=new Float32Array(l)),t&&!t.picking||(p=new Float32Array(3*r.picking.array.length));for(let e=0;el?d[p]=-1:(c=Math.sqrt(l-a),d[p]=Math.floor(c)),++p;f[g]=u,m[g]=d}}function k(i){var r,n,s,a,u,p,b,x,v,w,S,C,P,I,k,M,T,D,B=3*i,F=i;r=Math.floor(.5+o*(t[B]+d[0])),n=Math.floor(.5+o*(t[B+1]+d[1])),s=Math.floor(.5+o*(t[B+2]+d[2]));var E,$=e[F],O=m[$],R=0,L=l*h,N=f[$];for(w=0;w=c||I>=l||k>=h)){var z=P*L+I*h+k;if(g)if(y[z]&A){if(y[z]&A){var U=_[z];U!==B&&b*b+x*x+v*v<(a=r+b-Math.floor(.5+o*(t[U]+d[0])))*a+(u=n+x-Math.floor(.5+o*(t[U+1]+d[1])))*u+(p=s+v-Math.floor(.5+o*(t[U+2]+d[2])))*p&&(_[z]=i)}}else y[z]|=A,_[z]=i;else y[z]|=A}R++}}function M(e){var i,r;for(console.time("EDTSurface fillvoxels"),i=0,r=y.length;i=c||A>=l||C>=h)){var L=w*R+A*h+C;if(y[L]&S){if(g){var N=_[L];b*b+x*x+v*v<(a=Math.floor(.5+o*(t[N]+d[0])))*a+(u=Math.floor(.5+o*(t[N+1]+d[1])))*u+(p=Math.floor(.5+o*(t[N+2]+d[2])))*p&&(_[L]=i)}}else y[L]|=S,g&&(_[L]=i)}$++}}function D(){var t,e,i,r;console.time("EDTSurface fastdistancemap");var n,s=$u(c,l,h,Uint16Array,3),o=l*h,u=p*p,d=0;for(t=0;t0);var w,P=a*a,I=new Uint16Array(3);for(t=0;t=P)||(y[n]|=C,g&&y[n]&S&&(s.toArray(t,e,i,I),w=I[0]*o+I[1]*h+I[2],_[n]=_[w])));console.timeEnd("EDTSurface fastdistancemap")}function B(t,e,i,r){var n,s,o,a,u,d,m,f,p,g,_,x,v=new Uint16Array(3),w=0;if(0===i)return w;var I=-1,k=-1,M=-1,T=l*h;for(m=0,p=i;m-1&&k-1&&M-1&&(y[_=I*T+h*k+M]&A&&!(y[_]&S)?(e.fromArray(I,k,M,v),g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d,b[_]=g,y[_]|=S,y[_]|=C,r[w]=I,r[w+1]=k,r[w+2]=M,w+=3):y[_]&A&&y[_]&S&&(g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d)-1&&k-1&&M-1&&(y[_=I*T+h*k+M]&A&&!(y[_]&S)?(e.fromArray(I,k,M,v),g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d,b[_]=g,y[_]|=S,y[_]|=C,r[w]=I,r[w+1]=k,r[w+2]=M,w+=3):y[_]&A&&y[_]&S&&(g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d)-1&&k-1&&M-1&&(y[_=I*T+h*k+M]&A&&!(y[_]&S)?(e.fromArray(I,k,M,v),g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d,b[_]=g,y[_]|=S,y[_]|=C,r[w]=I,r[w+1]=k,r[w+2]=M,w+=3):y[_]&A&&y[_]&S&&(g=(a=I-v[0])*a+(u=k-v[1])*u+(d=M-v[2])*d)-1&&o-1&&u-1&&aT&&(T=E)}return{neighbourListLength:27*T+1,withinRadii:function(n,s,o,a,u){for(var d=0,m=f(n,c),p=f(s,l),g=f(o,h),y=Math.max(0,m-1),v=Math.max(0,p-1),A=Math.max(0,g-1),S=Math.min(b,m+2),C=Math.min(_,p+2),M=Math.min(x,g+2),T=y;Td&&(d=h[t]);!function(){const t=Do(c,l,d,f,0);f=t.scaleFactor,y=t.dim,b=t.matrix,F=Math.max(5,2+Math.floor(m*f)),_=wi(y[0]*y[1]*y[2],-1001),x=new Int32Array(_.length),v=new Float32Array(y[0]),w=new Float32Array(y[1]),A=new Float32Array(y[2]),$(v,c[0],1/f),$(w,c[1],1/f),$(A,c[2],1/f)}(),function(){var t=0,e=2*Math.PI/g;C=new Float32Array(g),S=new Float32Array(g);for(var i=0;i=0;){if(s!==r&&s!==n&&R(s,t,e,i))return k=s,s;s=I[++o]}return k=-1,-1}function R(e,i,r,n){var s=3*e,o=u[e],a=t[s]-i,c=t[s+1]-r,l=t[s+2]-n;return a*a+c*c+l*l0&&d=0;)t{e(this._makeSurface(t.data.sd,i))}),(t=>{console.warn("MolecularSurface.getSurfaceWorker error - trying without worker",t),this.worker.terminate(),this.worker=void 0;const r=this.getSurface(i);e(r)}))}else{const t=this.getSurface(i);e(t)}}dispose(){this.worker&&this.worker.terminate()}}class zu extends Ah{constructor(t,e,i){super(t,e,i),this.type="surface",this.parameters=Object.assign({surfaceType:{type:"select",rebuild:!0,options:{vws:"vws",sas:"sas",ms:"ms",ses:"ses",av:"av"}},probeRadius:{type:"number",precision:1,max:20,min:0,rebuild:!0},smooth:{type:"integer",precision:1,max:10,min:0,rebuild:!0},scaleFactor:{type:"number",precision:1,max:5,min:0,rebuild:!0},cutoff:{type:"number",precision:2,max:50,min:0,rebuild:!0},contour:{type:"boolean",rebuild:!0},background:{type:"boolean",rebuild:!0},opaqueBack:{type:"boolean",buffer:!0},filterSele:{type:"text",rebuild:!0},colorVolume:{type:"hidden"},useWorker:{type:"boolean",rebuild:!0}},this.parameters,{radius:null,scale:null}),this.__infoList=[],this.structure.signals.refreshed.add((()=>{this.__forceNewMolsurf=!0})),this.toBePrepared=!0,this.init(i)}init(t){const e=t||{};e.colorScheme=rt(e.colorScheme,"uniform"),e.colorValue=rt(e.colorValue,14540253),e.disablePicking=rt(e.disablePicking,!0),this.surfaceType=rt(e.surfaceType,"ms"),this.probeRadius=rt(e.probeRadius,1.4),this.smooth=rt(e.smooth,2),this.scaleFactor=rt(e.scaleFactor,2),this.cutoff=rt(e.cutoff,0),this.contour=rt(e.contour,!1),this.background=rt(e.background,!1),this.opaqueBack=rt(e.opaqueBack,!0),this.filterSele=rt(e.filterSele,""),this.colorVolume=rt(e.colorVolume,void 0),this.useWorker=rt(e.useWorker,!0),super.init(t)}prepareData(t,i,r){let n=this.__infoList[i];if(n||(n={},this.__infoList[i]=n),n.molsurf&&n.sele===t.selection.string)r(i);else{if(this.filterSele){const n=t.structure.getView(new de(this.filterSele)),s=n.boundingBox.getSize(new e),o=Math.max(s.x,s.y,s.z),a=t.getAtomSetWithinPoint(n.center,o/2+6);if(0===(t=t.getView(new de(t.getAtomSetWithinSelection(a,3).toSeleString()))).atomCount)return void r(i)}n.sele=t.selection.string,n.molsurf=new Nu(t);const s=this.getSurfaceParams(),o=t=>{n.surface=t,r(i)};this.useWorker?n.molsurf.getSurfaceWorker(s,o):o(n.molsurf.getSurface(s))}}prepare(t){if((this.__forceNewMolsurf||this.__sele!==this.selection.string||this.__surfaceParams!==JSON.stringify(this.getSurfaceParams()))&&(this.__infoList.forEach((t=>{t&&t.molsurf&&t.molsurf.dispose()})),this.__infoList.length=0),0===this.structureView.atomCount)return void t();const e=()=>{this.__sele=this.selection.string,this.__surfaceParams=JSON.stringify(this.getSurfaceParams()),this.__forceNewMolsurf=!1,t()},i="default"===this.assembly?this.defaultAssembly:this.assembly,r=this.structure.biomolDict[i];r?r.partList.forEach(((t,i)=>{const n=t.getView(this.structureView);this.prepareData(n,i,(t=>{t===r.partList.length-1&&e()}))})):this.prepareData(this.structureView,0,e)}createData(t,e){const i=this.__infoList[e],r=i.surface;if(!r)return;const n={position:r.getPosition(),color:r.getColor(this.getColorParams()),index:r.getFilteredIndex(this.filterSele,t)},s=[];if(r.contour){const t=new qo(n,this.getBufferParams({wireframe:!1}));s.push(t)}else{Object.assign(n,{normal:r.getNormal(),picking:r.getPicking(t.getStructure())});const e=new Vo(n,this.getBufferParams({background:this.background,opaqueBack:this.opaqueBack,dullInterior:!1}));if("double"==this.getBufferParams().side){const t=new Ho(e);s.push(t)}else s.push(e)}return{bufferList:s,info:i}}updateData(t,e){const i={};if(t.position||t.radius)return this.__forceNewMolsurf=!0,void this.build();t.color&&(i.color=e.info.surface.getColor(this.getColorParams())),t.index&&(i.index=e.info.surface.getFilteredIndex(this.filterSele,e.sview)),e.bufferList[0].setAttributes(i)}setParameters(t,e={},i){return t&&t.filterSele&&(e.index=!0),t&&void 0!==t.colorVolume&&(e.color=!0),t&&t.wireframe&&(t.contour||void 0===t.contour&&this.contour)&&(t.wireframe=!1),super.setParameters(t,e,i),this}getSurfaceParams(t={}){return Object.assign({type:this.surfaceType,probeRadius:this.probeRadius,scaleFactor:this.scaleFactor,smooth:this.smooth&&!this.contour,cutoff:this.cutoff,contour:this.contour,useWorker:this.useWorker,radiusParams:this.getRadiusParams()},t)}getColorParams(){const t=super.getColorParams();return t.volume=this.colorVolume,t}getAtomRadius(){return 0}clear(){super.clear()}dispose(){this.__infoList.forEach((t=>{t&&t.molsurf&&t.molsurf.dispose()})),this.__infoList.length=0,super.dispose()}}Re.add("surface",zu);class Uu extends Ah{constructor(t,e,i){super(t,e,i),this.type="point",this.parameters=Object.assign({pointSize:{type:"number",precision:1,max:100,min:0,buffer:!0},sizeAttenuation:{type:"boolean",buffer:!0},sortParticles:{type:"boolean",rebuild:!0},useTexture:{type:"boolean",buffer:!0},alphaTest:{type:"range",step:.001,max:1,min:0,buffer:!0},forceTransparent:{type:"boolean",buffer:!0},edgeBleach:{type:"range",step:.001,max:1,min:0,buffer:!0}},this.parameters,{flatShaded:null,wireframe:null,linewidth:null,side:null,roughness:null,metalness:null}),this.init(i)}init(t){var e=t||{};this.pointSize=rt(e.pointSize,1),this.sizeAttenuation=rt(e.sizeAttenuation,!0),this.sortParticles=rt(e.sortParticles,!1),this.useTexture=rt(e.useTexture,!1),this.alphaTest=rt(e.alphaTest,.5),this.forceTransparent=rt(e.forceTransparent,!1),this.edgeBleach=rt(e.edgeBleach,0),super.init(e)}createData(t){var e=t.getAtomData(this.getAtomParams({position:!0,color:!0,picking:!0}));return{bufferList:[new Gc(e,this.getBufferParams({pointSize:this.pointSize,sizeAttenuation:this.sizeAttenuation,sortParticles:this.sortParticles,useTexture:this.useTexture,alphaTest:this.alphaTest,forceTransparent:this.forceTransparent,edgeBleach:this.edgeBleach}))]}}updateData(t,e){var i=e.sview.getAtomData(this.getAtomParams(t)),r={};t&&!t.position||Object.assign(r,{position:i.position}),t&&!t.color||Object.assign(r,{color:i.color}),e.bufferList[0].setAttributes(r)}getAtomRadius(){return.1}}Re.add("point",Uu),Ne.add("shader/Ribbon.vert","#define STANDARD\nuniform float clipNear;\nuniform vec3 clipCenter;\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvarying vec3 vViewPosition;\n#endif\n#if defined( RADIUS_CLIP )\nvarying vec3 vClipCenter;\n#endif\nattribute vec3 dir;\nattribute float size;\n#ifdef PICKING\n#include unpack_color\nattribute float primitiveId;\nvarying vec3 vPickingColor;\n#else\n#include color_pars_vertex\n#ifndef FLAT_SHADED\nvarying vec3 vNormal;\n#endif\n#endif\n#include common\nvoid main(void){\n#ifdef PICKING\nvPickingColor = unpackColor( primitiveId );\n#else\n#include color_vertex\n#include beginnormal_vertex\n#include defaultnormal_vertex\n#ifndef FLAT_SHADED\nvNormal = normalize( transformedNormal );\n#endif\n#endif\n#include begin_vertex\ntransformed += normalize( dir ) * size;\n#include project_vertex\n#if defined( NEAR_CLIP ) || defined( RADIUS_CLIP ) || !defined( PICKING )\nvViewPosition = -mvPosition.xyz;\n#endif\n#if defined( RADIUS_CLIP )\nvClipCenter = -( modelViewMatrix * vec4( clipCenter, 1.0 ) ).xyz;\n#endif\n#include nearclip_vertex\n}");const Vu=new Uint16Array([0,1,2,1,3,2]);function ju(t){return 3*(4*(t.position.length/3-1))}class Gu extends Uo{constructor(t,e={}){super({position:new Float32Array(ju(t)),color:new Float32Array(ju(t)),index:yt(ju(t),ju(t)/3),normal:new Float32Array(ju(t)),picking:t.picking},e),this.vertexShader="Ribbon.vert";const i=t.position.length/3-1,r=4*i,n=3*r;this.addAttributes({dir:{type:"v3",value:new Float32Array(n)}}),this.addAttributes({size:{type:"f",value:new Float32Array(r)}}),t.primitiveId=Si(i),this.setAttributes(t),this.makeIndex()}setAttributes(t={}){const e=this.size/4,i=this.geometry.attributes;let r,n,s,o,a,c,l,h,u,d,m,f,p,g,y,b,_,x,v;t.position&&(r=t.position,l=i.position.array,i.position.needsUpdate=!0),t.normal&&(n=t.normal,h=i.normal.array,i.normal.needsUpdate=!0),t.size&&(s=t.size,u=i.size.array,i.size.needsUpdate=!0),t.dir&&(o=t.dir,d=i.dir.array,i.dir.needsUpdate=!0),t.color&&(a=t.color,m=i.color.array,i.color.needsUpdate=!0),t.primitiveId&&(c=t.primitiveId,f=i.primitiveId.array,i.primitiveId.needsUpdate=!0);let w=s?s[0]:null;for(p=0;p{if(!(t.residueCount<4)){i.push(t);var r=new su(t,this.getSplineParams()),n=r.getSubdividedPosition(),s=r.getSubdividedOrientation(),o=r.getSubdividedColor(this.getColorParams()),a=r.getSubdividedPicking(),c=r.getSubdividedSize(this.getRadiusParams());e.push(new Gu({position:n.position,normal:s.binormal,dir:s.normal,color:o.color,size:c.size,picking:a.picking},this.getBufferParams()))}}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){t=t||{};var i=0,r=e.polymerList.length;for(i=0;i{if(t.residueCount<4||t.isNucleic())return;const n=new Sa(t),s=n.getAxis(this.localAngle,this.centerDist,this.ssBorder,this.getColorParams(),this.getRadiusParams());e+=s.size.length,i.push(s),r.push(n)}),t.getSelection());const n={begin:new Float32Array(3*e),end:new Float32Array(3*e),size:new Float32Array(e),color:new Float32Array(3*e),picking:{}};let s=new Float32Array(e),o=0;i.forEach((function(t){n.begin.set(t.begin,3*o),n.end.set(t.end,3*o),n.size.set(t.size,o),n.color.set(t.color,3*o),s.set(t.picking.array,o),o+=t.size.length})),e&&(n.picking=new Ws(s,t.getStructure()));return{bufferList:[new Jh({position1:n.begin,position2:n.end,color:n.color,color2:n.color,radius:n.size,picking:n.picking},this.getBufferParams({openEnded:this.openEnded,radialSegments:this.radialSegments,disableImpostor:this.disableImpostor,dullInterior:!0}))],axisList:i,helixbundleList:r,axisData:n}}updateData(t,e){if((t=t||{}).position)this.build();else{var i={};if(t.color||t.radius){var r=0;e.helixbundleList.forEach((i=>{var n=i.getAxis(this.localAngle,this.centerDist,this.ssBorder,this.getColorParams(),this.getRadiusParams());t.color&&e.axisData.color.set(n.color,3*r),(t.radius||t.scale)&&e.axisData.size.set(n.size,r),r+=n.size.length})),t.color&&Object.assign(i,{color:e.axisData.color,color2:e.axisData.color}),(t.radius||t.scale)&&Object.assign(i,{radius:e.axisData.size})}e.bufferList[0].setAttributes(i)}}}Re.add("rocket",qu);class Wu extends hu{constructor(t,e,i){super(t,e,i),this.type="rope",this.parameters=Object.assign({smooth:{type:"integer",max:15,min:0,rebuild:!0}},this.parameters,{aspectRatio:null,smoothSheet:null})}init(t){var e=t||{};e.aspectRatio=1,e.tension=rt(e.tension,.5),e.radiusScale=rt(e.radiusScale,5),e.smoothSheet=!1,this.smooth=rt(e.smooth,2),super.init(e)}getSpline(t){var e=new Aa(t);return new su(t,this.getSplineParams({directional:!1,positionIterator:e.getCenterIterator(this.smooth)}))}}Re.add("rope",Wu);class Xu extends Ah{constructor(t,e,i){super(t,e,i),this.type="spacefill",this.parameters=Object.assign({sphereDetail:!0,disableImpostor:!0},this.parameters),this.init(i)}init(t){var e=t||{};e.useInteriorColor=rt(e.useInteriorColor,!0),super.init(e)}createData(t){return{bufferList:[new zc(t.getAtomData(this.getAtomParams()),this.getBufferParams({sphereDetail:this.sphereDetail,dullInterior:!0,disableImpostor:this.disableImpostor}))]}}updateData(t,e){var i=e.sview.getAtomData(this.getAtomParams(t)),r={};t&&!t.position||Object.assign(r,{position:i.position}),t&&!t.color||Object.assign(r,{color:i.color}),t&&!t.radius||Object.assign(r,{radius:i.radius}),e.bufferList[0].setAttributes(r)}}function Yu(t){return 3*(t.position.length/3-1)*2}Re.add("spacefill",Xu);class Ku extends zo{constructor(t,e={}){super({position:new Float32Array(Yu(t)),color:new Float32Array(Yu(t))},e),this.isLine=!0,this.vertexShader="Line.vert",this.fragmentShader="Line.frag",this.setAttributes(t)}setAttributes(t){let e,i,r,n;const s=this.geometry.attributes;if(t.position&&(e=t.position,r=s.position.array,s.position.needsUpdate=!0),t.color&&(i=t.color,n=s.color.array,s.color.needsUpdate=!0),!e&&!i)return void Ie.warn("TraceBuffer.prototype.setAttributes no data");let o,a;const c=this.size-1;for(let t=0;t{if(!(t.residueCount<4)){i.push(t);var r=new su(t,this.getSplineParams()),n=r.getSubdividedPosition(),s=r.getSubdividedColor(this.getColorParams());e.push(new Ku(Object.assign({},n,s),this.getBufferParams()))}}),t.getSelection()),{bufferList:e,polymerList:i}}updateData(t,e){t=t||{};var i=0,r=e.polymerList.length;for(i=0;i{t.boundingBox||t.computeBoundingBox(),this.boundingBox.union(t.boundingBox)}))}}const cd=Object.assign({aspectRatio:1.5,radialSegments:50,openEnded:!1,disableImpostor:!1},Lo);class ld{constructor(t,e={}){this.group=new d,this.wireframeGroup=new d,this.pickingGroup=new d,this.visible=!0,this.parameters=nt(e,this.defaultParameters),this.splitPosition=new Float32Array(t.position1.length),this.cylinderRadius=new Float32Array(t.radius.length);const r=this.makeAttributes(t),n={radialSegments:this.parameters.radialSegments,openEnded:this.parameters.openEnded,disableImpostor:this.parameters.disableImpostor};this.cylinderBuffer=new Jh(r.cylinder,n),this.coneBuffer=new od(r.cone,n),this.geometry=new ad([this.cylinderBuffer.geometry,this.coneBuffer.geometry]),this.matrix=rt(e.matrix,new i),this.picking=t.picking}get defaultParameters(){return cd}set matrix(t){zo.prototype.setMatrix.call(this,t)}get matrix(){return this.group.matrix.clone()}get pickable(){return!!this.picking}makeAttributes(t={}){const i=this.splitPosition,r=this.cylinderRadius,n=this.parameters.aspectRatio;let s,o;const a={},c={};if(t.radius){for(s=0,o=r.length;s0&&(s=1/Math.sqrt(s),t[0]=e[0]*s,t[1]=e[1]*s,t[2]=e[2]*s),t}function u(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function d(t,e,i){const r=e[0],n=e[1],s=e[2],o=i[0],a=i[1],c=i[2];return t[0]=n*c-s*a,t[1]=s*o-r*c,t[2]=r*a-n*o,t}t.zero=e,t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i},t.isFinite=function(t){return Wd(t[0])&&Wd(t[1])&&Wd(t[2])},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])||isNaN(t[2])},t.setNaN=function(t){return t[0]=NaN,t[1]=NaN,t[2]=NaN,t},t.fromObj=function(t){return i(t.x,t.y,t.z)},t.toObj=function(t){return{x:t[0],y:t[1],z:t[2]}},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e},t.create=i,t.ofArray=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i},t.set=function(t,e,i,r){return t[0]=e,t[1]=i,t[2]=r,t},t.copy=r,t.add=n,t.sub=s,t.mul=function(t,e,i){return t[0]=e[0]*i[0],t[1]=e[1]*i[1],t[2]=e[2]*i[2],t},t.div=function(t,e,i){return t[0]=e[0]/i[0],t[1]=e[1]/i[1],t[2]=e[2]/i[2],t},t.scale=o,t.scaleAndAdd=a,t.scaleAndSub=function(t,e,i,r){return t[0]=e[0]-i[0]*r,t[1]=e[1]-i[1]*r,t[2]=e[2]-i[2]*r,t},t.addScalar=function(t,e,i){return t[0]=e[0]+i,t[1]=e[1]+i,t[2]=e[2]+i,t},t.subScalar=function(t,e,i){return t[0]=e[0]-i,t[1]=e[1]-i,t[2]=e[2]-i,t},t.round=function(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t},t.ceil=function(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t},t.floor=function(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t},t.trunc=function(t,e){return t[0]=Math.trunc(e[0]),t[1]=Math.trunc(e[1]),t[2]=Math.trunc(e[2]),t},t.abs=function(t,e){return t[0]=Math.abs(e[0]),t[1]=Math.abs(e[1]),t[2]=Math.abs(e[2]),t},t.min=function(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},t.max=function(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},t.clamp=function(t,e,i,r){return t[0]=Math.max(i[0],Math.min(r[0],e[0])),t[1]=Math.max(i[1],Math.min(r[1],e[1])),t[2]=Math.max(i[2],Math.min(r[2],e[2])),t},t.distance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2];return Math.sqrt(i*i+r*r+n*n)},t.squaredDistance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2];return i*i+r*r+n*n},t.magnitude=function(t){const e=t[0],i=t[1],r=t[2];return Math.sqrt(e*e+i*i+r*r)},t.squaredMagnitude=c,t.setMagnitude=function(t,e,i){return o(t,h(t,e),i)},t.negate=l,t.inverse=function(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t},t.normalize=h,t.dot=u,t.cross=d,t.lerp=function(t,e,i,r){const n=e[0],s=e[1],o=e[2];return t[0]=n+r*(i[0]-n),t[1]=s+r*(i[1]-s),t[2]=o+r*(i[2]-o),t};const m=e();function f(t,e){const i=Math.sqrt(c(t)*c(e));if(0===i)return Math.PI/2;const r=u(t,e)/i;return Math.acos(Gd(r,-1,1))}t.slerp=function(t,e,i,r){const s=Gd(u(e,i),-1,1),c=Math.acos(s)*r;return a(m,i,e,-s),h(m,m),n(t,o(t,e,Math.cos(c)),o(m,m,Math.sin(c)))},t.hermite=function(t,e,i,r,n,s){const o=s*s,a=o*(2*s-3)+1,c=o*(s-2)+s,l=o*(s-1),h=o*(3-2*s);return t[0]=e[0]*a+i[0]*c+r[0]*l+n[0]*h,t[1]=e[1]*a+i[1]*c+r[1]*l+n[1]*h,t[2]=e[2]*a+i[2]*c+r[2]*l+n[2]*h,t},t.bezier=function(t,e,i,r,n,s){const o=1-s,a=o*o,c=s*s,l=a*o,h=3*s*a,u=3*c*o,d=c*s;return t[0]=e[0]*l+i[0]*h+r[0]*u+n[0]*d,t[1]=e[1]*l+i[1]*h+r[1]*u+n[1]*d,t[2]=e[2]*l+i[2]*h+r[2]*u+n[2]*d,t},t.quadraticBezier=function(t,e,i,r,n){return t[0]=qd(e[0],i[0],r[0],n),t[1]=qd(e[1],i[1],r[1],n),t[2]=qd(e[2],i[2],r[2],n),t},t.spline=function(t,e,i,r,n,s,o){return t[0]=Hd(e[0],i[0],r[0],n[0],s,o),t[1]=Hd(e[1],i[1],r[1],n[1],s,o),t[2]=Hd(e[2],i[2],r[2],n[2],s,o),t},t.random=function(t,e){const i=2*Math.random()*Math.PI,r=2*Math.random()-1,n=Math.sqrt(1-r*r)*e;return t[0]=Math.cos(i)*n,t[1]=Math.sin(i)*n,t[2]=r*e,t},t.transformMat4=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=1/(i[3]*r+i[7]*n+i[11]*s+i[15]||1);return t[0]=(i[0]*r+i[4]*n+i[8]*s+i[12])*o,t[1]=(i[1]*r+i[5]*n+i[9]*s+i[13])*o,t[2]=(i[2]*r+i[6]*n+i[10]*s+i[14])*o,t},t.transformDirection=function(t,e,i){const r=e[0],n=e[1],s=e[2];return t[0]=i[0]*r+i[4]*n+i[8]*s,t[1]=i[1]*r+i[5]*n+i[9]*s,t[2]=i[2]*r+i[6]*n+i[10]*s,h(t,t)},t.transformMat4Offset=function(t,e,i,r,n,s){const o=e[0+n],a=e[1+n],c=e[2+n],l=1/(i[3+s]*o+i[7+s]*a+i[11+s]*c+i[15+s]||1);return t[0+r]=(i[0+s]*o+i[4+s]*a+i[8+s]*c+i[12+s])*l,t[1+r]=(i[1+s]*o+i[5+s]*a+i[9+s]*c+i[13+s])*l,t[2+r]=(i[2+s]*o+i[6+s]*a+i[10+s]*c+i[14+s])*l,t},t.transformDirectionOffset=function(t,e,i,r,n,s){const o=e[0+n],a=e[1+n],c=e[2+n];t[0+r]=i[0+s]*o+i[4+s]*a+i[8+s]*c,t[1+r]=i[1+s]*o+i[5+s]*a+i[9+s]*c,t[2+r]=i[2+s]*o+i[6+s]*a+i[10+s]*c;const l=Math.hypot(t[0+r],t[1+r],t[2+r]);return l>0&&(t[0+r]/=l,t[1+r]/=l,t[2+r]/=l),t},t.transformMat3=function(t,e,i){const r=e[0],n=e[1],s=e[2];return t[0]=r*i[0]+n*i[3]+s*i[6],t[1]=r*i[1]+n*i[4]+s*i[7],t[2]=r*i[2]+n*i[5]+s*i[8],t},t.transformQuat=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=i[0],a=i[1],c=i[2],l=i[3],h=l*r+a*s-c*n,u=l*n+c*r-o*s,d=l*s+o*n-a*r,m=-o*r-a*n-c*s;return t[0]=h*l+m*-o+u*-c-d*-a,t[1]=u*l+m*-a+d*-o-h*-c,t[2]=d*l+m*-c+h*-a-u*-o,t},t.angle=f;const p=e(),g=e(),y=e(),b=e(),_=e(),x=e(),v=e();t.dihedralAngle=function(t,e,i,r){s(p,t,e),s(g,i,e),s(y,e,i),s(b,r,i),d(_,p,g),d(x,y,b);const n=f(_,x);return d(v,_,x),u(g,v)>0?n:-n},t.directionFromSpherical=function(e,i,r,n){return t.set(e,n*Math.cos(r)*Math.sin(i),n*Math.sin(r)*Math.sin(i),n*Math.cos(i))},t.exactEquals=function(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]},t.equals=function(t,e){const i=t[0],r=t[1],n=t[2],s=e[0],o=e[1],a=e[2];return Math.abs(i-s)<=Vd*Math.max(1,Math.abs(i),Math.abs(s))&&Math.abs(r-o)<=Vd*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(n-a)<=Vd*Math.max(1,Math.abs(n),Math.abs(a))};const w=e();t.makeRotation=function(e,i,r){const n=f(i,r);if(Math.abs(n)<1e-4)return Zd.setIdentity(e);if(Math.abs(n-Math.PI)0?r(t,e):l(t,r(t,e)),t};const P=e(),I=e();t.triangleNormal=function(t,e,i,r){return s(P,i,e),s(I,r,e),h(t,d(t,P,I))},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)} ${t[2].toPrecision(e)}]`},t.origin=i(0,0,0),t.unit=i(1,1,1),t.negUnit=i(-1,-1,-1),t.unitX=i(1,0,0),t.unitY=i(0,1,0),t.unitZ=i(0,0,1),t.negUnitX=i(-1,0,0),t.negUnitY=i(0,-1,0),t.negUnitZ=i(0,0,-1)}(Xd||(Xd={}));const Yd=Math.PI/180;function Kd(t){return t*Yd}function Zd(){return Zd.zero()}function Qd(){return Qd.zero()}function Jd(){return Jd.zero()}function tm(){return tm.zero()}function em(t){throw new Error("unreachable")}function im(){return im.zero()}var rm,nm,sm,om;function am(t,e,i){let r=e,n=0,s=1;for(45===t.charCodeAt(r)?(s=-1,++r):43===t.charCodeAt(r)&&++r;r9||e<0)return s*n|0;n=10*n+e|0}return s*n}function cm(t,e,i,r){return 43===e.charCodeAt(i)&&i++,t*Math.pow(10,am(e,i,r))}function lm(t,e,i){let r=e,n=1,s=0,o=0,a=1;for(45===t.charCodeAt(r)?(n=-1,++r):43===t.charCodeAt(r)&&++r;r=0&&e<10)){if(-2===e){for(++r;r=0&&e<10))return 53===e||21===e?cm(n*(s+o/a),t,r+1,i):n*(s+o/a);o=10*o+e,a*=10,++r}return n*(s+o/a)}if(53===e||21===e)return cm(n*s,t,r+1,i);break}s=10*s+e,++r}return n*s}function hm(t,e,i,r){return{schema:i,__array:void 0,isDefined:0===r,rowCount:e,value:e=>t,valueKind:t=>r,toArray:i=>{const{array:r}=Ld(e,i);for(let e=0,i=r.length;e!0}}function um({value:t,valueKind:e,areValuesEqual:i,rowCount:r,schema:n}){return{schema:n,__array:void 0,isDefined:!0,rowCount:r,value:t,valueKind:e||(t=>0),toArray:e=>{const{array:i,start:n}=Ld(r,e);for(let e=0,r=i.length;et(e)===t(i))}}function dm({array:t,schema:e,valueKind:i}){const r=t.length,n=e.T,s="str"===e.valueType?"lowercase"===e.transform?e=>{const i=t[e];return"string"==typeof i?i.toLowerCase():`${null!=i?i:n}`.toLowerCase()}:"uppercase"===e.transform?e=>{const i=t[e];return"string"==typeof i?i.toUpperCase():`${null!=i?i:n}`.toUpperCase()}:e=>{const i=t[e];return"string"==typeof i?i:`${null!=i?i:n}`}:e=>t[e],o=zd(t);return{schema:e,__array:t,isDefined:!0,rowCount:r,value:s,valueKind:i||(t=>0),toArray:"str"===e.valueType?"lowercase"===e.transform?e=>{const{start:i,end:s}=Rd(r,e),o=new(e&&void 0!==e.array?e.array:t.constructor)(s-i);for(let e=0,r=s-i;e{const{start:i,end:s}=Rd(r,e),o=new(e&&void 0!==e.array?e.array:t.constructor)(s-i);for(let e=0,r=s-i;e{const{start:i,end:s}=Rd(r,e),o=new(e&&void 0!==e.array?e.array:t.constructor)(s-i);for(let e=0,r=s-i;eUd(t,e):e=>{const{start:i,end:n}=Rd(r,e);if(0===i&&n===t.length)return t;const s=new(e&&void 0!==e.array?e.array:t.constructor)(n-i);for(let e=0,r=n-i;et[e]===t[i]}}function mm(t,e,i){return t.isDefined?0===e&&i===t.rowCount?t:t.__array&&zd(t.__array)?function(t,e,i){const r=Ud(t.__array,{start:e,end:i}),n=t.valueKind;return dm({array:r,schema:t.schema,valueKind:t=>n(e+t)})}(t,e,i):function(t,e,i){const r=t.value,n=t.valueKind,s=t.areValuesEqual,o=0===e?r:t=>r(t+e),a=i-e;return{schema:t.schema,__array:void 0,isDefined:t.isDefined,rowCount:a,value:o,valueKind:0===e?n:t=>n(t+e),toArray:t=>{const{array:i}=Ld(a,t);for(let t=0,n=i.length;ts(t+e,i+e)}}(t,e,i):nm.Undefined(i-e,t.schema)}function fm(t,e,i){return 0===t.rowCount||i&&function(t,e){if(t.length!==e)return!1;for(let e=0,i=t.length;en(e[t])})}(t,e):function(t,e){const i=t.value,r=t.valueKind,n=t.areValuesEqual,s=t=>i(e[t]),o=e.length;return{schema:t.schema,__array:void 0,isDefined:t.isDefined,rowCount:o,value:s,valueKind:t=>r(e[t]),toArray:t=>{const{array:r}=Ld(o,t);for(let t=0,n=r.length;tn(e[t],e[i])}}(t,e)}function pm(t,e,i){return t[e]-t[i]}function gm(t,e,i){const r=t[e];t[e]=t[i],t[i]=r}function ym(t,e,i,r){const n=i+r>>1;return e(t,i,r)>0?e(t,i,n)>0?e(t,n,r)>0?n:r:i:e(t,r,n)>0?e(t,n,i)>0?n:i:r}function bm(t,e,i){const{cmp:r,swap:n,data:s,parts:o}=t;let a=e+1,c=i;for(n(s,e,ym(s,r,e,i));r(s,c,e)>0;)--c;for(let t=e+1;t<=c;t++){const i=r(s,t,e);if(i>0){for(n(s,t,c),--c;r(s,c,e)>0;)--c;t--}else 0===i&&(n(s,t,a),a++)}for(let t=e;t=r&&e(t,n,n+1)>0;)i(t,n,n+1),n-=1}}function xm(t,e,i){const{parts:r}=t;for(;eo;)--s;for(let e=i+1;e<=s;e++){const i=t[e];if(i>o){for(gm(t,e,s),--s;t[s]>o;)--s;e--}else i===o&&(gm(t,e,n),++n)}for(let e=i;e=e&&t[n]>i;)t[n+1]=t[n],n-=1;t[n+1]=i}}function Am(t,e,i,r){for(;ii)return!1;return!0}function a(t,e,i,r){t[4*i+e]=r}function c(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 l(t,e){const i=e[0]+e[5]+e[10];let r=0;return i>0?(r=2*Math.sqrt(i+1),t[3]=.25*r,t[0]=(e[6]-e[9])/r,t[1]=(e[8]-e[2])/r,t[2]=(e[1]-e[4])/r):e[0]>e[5]&&e[0]>e[10]?(r=2*Math.sqrt(1+e[0]-e[5]-e[10]),t[3]=(e[6]-e[9])/r,t[0]=.25*r,t[1]=(e[1]+e[4])/r,t[2]=(e[8]+e[2])/r):e[5]>e[10]?(r=2*Math.sqrt(1+e[5]-e[0]-e[10]),t[3]=(e[8]-e[2])/r,t[0]=(e[1]+e[4])/r,t[1]=.25*r,t[2]=(e[6]+e[9])/r):(r=2*Math.sqrt(1+e[10]-e[0]-e[5]),t[3]=(e[1]-e[4])/r,t[0]=(e[8]+e[2])/r,t[1]=(e[6]+e[9])/r,t[2]=.25*r),t}function h(t,e){const i=e[0],r=e[1],n=e[2],s=e[3],o=e[4],a=e[5],c=e[6],l=e[7],h=e[8],u=e[9],d=e[10],m=e[11],f=e[12],p=e[13],g=e[14],y=e[15],b=i*a-r*o,_=i*c-n*o,x=i*l-s*o,v=r*c-n*a,w=r*l-s*a,A=n*l-s*c,S=h*p-u*f,C=h*g-d*f,P=h*y-m*f,I=u*g-d*p,k=u*y-m*p,M=d*y-m*g;let T=b*M-_*k+x*I+v*P-w*C+A*S;return!!T&&(T=1/T,t[0]=(a*M-c*k+l*I)*T,t[1]=(n*k-r*M-s*I)*T,t[2]=(p*A-g*w+y*v)*T,t[3]=(d*w-u*A-m*v)*T,t[4]=(c*P-o*M-l*C)*T,t[5]=(i*M-n*P+s*C)*T,t[6]=(g*x-f*A-y*_)*T,t[7]=(h*A-d*x+m*_)*T,t[8]=(o*k-a*P+l*S)*T,t[9]=(r*P-i*k-s*S)*T,t[10]=(f*w-p*x+y*b)*T,t[11]=(u*x-h*w-m*b)*T,t[12]=(a*C-o*I-c*S)*T,t[13]=(i*I-r*C+n*S)*T,t[14]=(p*_-f*v-g*b)*T,t[15]=(h*v-u*_+d*b)*T,!0)}function u(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3],a=e[4],c=e[5],l=e[6],h=e[7],u=e[8],d=e[9],m=e[10],f=e[11],p=e[12],g=e[13],y=e[14],b=e[15];let _=i[0],x=i[1],v=i[2],w=i[3];return t[0]=_*r+x*a+v*u+w*p,t[1]=_*n+x*c+v*d+w*g,t[2]=_*s+x*l+v*m+w*y,t[3]=_*o+x*h+v*f+w*b,_=i[4],x=i[5],v=i[6],w=i[7],t[4]=_*r+x*a+v*u+w*p,t[5]=_*n+x*c+v*d+w*g,t[6]=_*s+x*l+v*m+w*y,t[7]=_*o+x*h+v*f+w*b,_=i[8],x=i[9],v=i[10],w=i[11],t[8]=_*r+x*a+v*u+w*p,t[9]=_*n+x*c+v*d+w*g,t[10]=_*s+x*l+v*m+w*y,t[11]=_*o+x*h+v*f+w*b,_=i[12],x=i[13],v=i[14],w=i[15],t[12]=_*r+x*a+v*u+w*p,t[13]=_*n+x*c+v*d+w*g,t[14]=_*s+x*l+v*m+w*y,t[15]=_*o+x*h+v*f+w*b,t}function d(t,e,i){let n=i[0],s=i[1],o=i[2],a=Math.sqrt(n*n+s*s+o*o);if(Math.abs(a)0&&(m=1/Math.sqrt(m),h*=m,u*=m,d*=m);let f=c*d-l*u,p=l*h-a*d,g=a*u-c*h;return m=f*f+p*p+g*g,m>0&&(m=1/Math.sqrt(m),f*=m,p*=m,g*=m),t[0]=f,t[1]=p,t[2]=g,t[3]=0,t[4]=u*g-d*p,t[5]=d*f-h*g,t[6]=h*p-u*f,t[7]=0,t[8]=h,t[9]=u,t[10]=d,t[11]=0,t[12]=n,t[13]=s,t[14]=o,t[15]=1,t},t.fromPermutation=function(t,e){n(t);for(let i=0;i<4;i++){a(t,i,e[i],1)}return t},t.getMaxScaleOnAxis=function(t){const e=t[0]*t[0]+t[1]*t[1]+t[2]*t[2],i=t[4]*t[4]+t[5]*t[5]+t[6]*t[6],r=t[8]*t[8]+t[9]*t[9]+t[10]*t[10];return Math.sqrt(Math.max(e,i,r))};const g=[1,0,0],y=[0,1,0],b=[0,0,1];t.rotX90=d(e(),Kd(90),g),t.rotX180=d(e(),Kd(180),g),t.rotY90=d(e(),Kd(90),y),t.rotY180=d(e(),Kd(180),y),t.rotY270=d(e(),Kd(270),y),t.rotZ90=d(e(),Kd(90),b),t.rotZ180=d(e(),Kd(180),b),t.rotXY90=u(e(),t.rotX90,t.rotY90),t.rotZY90=u(e(),t.rotZ90,t.rotY90),t.rotZYZ90=u(e(),t.rotZY90,t.rotZ90),t.rotZ90X180=u(e(),t.rotZ90,t.rotX180),t.rotY90Z180=u(e(),t.rotY90,t.rotZ180),t.id=i()}(Zd||(Zd={})),function(t){function e(){const t=[.1,0,0,0,0,0,0,0,0];return t[0]=0,t}function i(){const t=e();return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function r(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}t.zero=e,t.identity=i,t.setIdentity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e[i+3]=t[3],e[i+4]=t[4],e[i+5]=t[5],e[i+6]=t[6],e[i+7]=t[7],e[i+8]=t[8],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=e[i+3],t[4]=e[i+4],t[5]=e[i+5],t[6]=e[i+6],t[7]=e[i+7],t[8]=e[i+8],t},t.fromColumns=function(t,e,i,r){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=i[0],t[4]=i[1],t[5]=i[2],t[6]=r[0],t[7]=r[1],t[8]=r[2],t},t.fromMat4=r;const n=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];t.fromEuler=function(t,e,i){return Zd.fromEuler(n,e,i),r(t,n)},t.create=function(t,i,r,n,s,o,a,c,l){const h=e();return h[0]=t,h[1]=i,h[2]=r,h[3]=n,h[4]=s,h[5]=o,h[6]=a,h[7]=c,h[8]=l,h};const s=i();function o(t,e,i){for(let r=0;r<9;r++)if(Math.abs(t[r]-e[r])>i)return!1;return!0}function a(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}function c(t,e){if(t===e){const i=e[1],r=e[2],n=e[5];t[1]=e[3],t[2]=e[6],t[3]=i,t[5]=e[7],t[6]=r,t[7]=n}else t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8];return t}function l(t,e){const i=e[0],r=e[1],n=e[2],s=e[3],o=e[4],a=e[5],c=e[6],l=e[7],h=e[8],u=h*o-a*l,d=-h*s+a*c,m=l*s-o*c;let f=i*u+r*d+n*m;return f?(f=1/f,t[0]=u*f,t[1]=(-h*r+n*l)*f,t[2]=(a*r-n*o)*f,t[3]=d*f,t[4]=(h*i-n*c)*f,t[5]=(-a*i+n*s)*f,t[6]=m*f,t[7]=(-l*i+r*c)*f,t[8]=(o*i-r*s)*f,t):(console.warn("non-invertible matrix.",e),t)}function h(t){const e=t[0],i=t[1],r=t[2],n=t[3],s=t[4],o=t[5],a=t[6],c=t[7],l=t[8];return e*(l*s-o*c)+i*(-l*n+o*a)+r*(c*n-s*a)}function u(t){return t[0]+t[4]+t[8]}function d(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[4]=e[4]-i[4],t[5]=e[5]-i[5],t[6]=e[6]-i[6],t[7]=e[7]-i[7],t[8]=e[8]-i[8],t}function m(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}t.isIdentity=function(t,e){return o(t,s,void 0===e?Vd:e)},t.hasNaN=function(t){for(let e=0;e<9;e++)if(isNaN(t[e]))return!0;return!1},t.clone=function(t){return a(e(),t)},t.areEqual=o,t.setValue=function(t,e,i,r){t[3*i+e]=r},t.getValue=function(t,e,i){return t[3*i+e]},t.copy=a,t.transpose=c,t.invert=l,t.symmtricFromUpper=function(t,e){return t===e?(t[3]=e[1],t[6]=e[2],t[7]=e[5]):(t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[1],t[4]=e[4],t[5]=e[5],t[6]=e[2],t[7]=e[5],t[8]=e[8]),t},t.symmtricFromLower=function(t,e){return t===e?(t[1]=e[3],t[2]=e[6],t[5]=e[7]):(t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[3],t[4]=e[4],t[5]=e[7],t[6]=e[6],t[7]=e[7],t[8]=e[8]),t},t.determinant=h,t.trace=u,t.sub=d,t.add=function(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[4]=e[4]+i[4],t[5]=e[5]+i[5],t[6]=e[6]+i[6],t[7]=e[7]+i[7],t[8]=e[8]+i[8],t},t.mul=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3],a=e[4],c=e[5],l=e[6],h=e[7],u=e[8],d=i[0],m=i[1],f=i[2],p=i[3],g=i[4],y=i[5],b=i[6],_=i[7],x=i[8];return t[0]=d*r+m*o+f*l,t[1]=d*n+m*a+f*h,t[2]=d*s+m*c+f*u,t[3]=p*r+g*o+y*l,t[4]=p*n+g*a+y*h,t[5]=p*s+g*c+y*u,t[6]=b*r+_*o+x*l,t[7]=b*n+_*a+x*h,t[8]=b*s+_*c+x*u,t},t.subScalar=function(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},t.addScalar=function(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},t.mulScalar=m;const f=Math.PI/3,p=e();t.symmetricEigenvalues=function(e,i){const r=i[1]*i[1]+i[2]*i[2]+i[5]*i[5];if(0===r)e[0]=i[0],e[1]=i[4],e[2]=i[8];else{const n=u(i)/3,s=i[0]-n,o=i[4]-n,a=i[8]-n,c=s*s+o*o+a*a+2*r,l=Math.sqrt(c/6);m(p,t.Identity,n),d(p,i,p),m(p,p,1/l);const g=h(p)/2,y=g<=-1?f:g>=1?0:Math.acos(g)/3;e[0]=n+2*l*Math.cos(y),e[2]=n+2*l*Math.cos(y+2*f),e[1]=3*n-e[0]-e[2]}return e};const g=[.1,0,0],y=[.1,0,0],b=[.1,0,0],_=[.1,0,0],x=[.1,0,0],v=[.1,0,0];t.eigenvector=function(t,e,i){Xd.set(g,e[0]-i,e[1],e[2]),Xd.set(y,e[1],e[4]-i,e[5]),Xd.set(b,e[2],e[5],e[8]-i),Xd.cross(_,g,y),Xd.cross(x,g,b),Xd.cross(v,y,b);const r=Xd.dot(_,_),n=Xd.dot(x,x),s=Xd.dot(v,v);let o=r,a=0;return n>o&&(o=n,a=1),s>o&&(a=2),0===a?Xd.scale(t,_,1/Math.sqrt(r)):1===a?Xd.scale(t,x,1/Math.sqrt(n)):Xd.scale(t,v,1/Math.sqrt(s)),t},t.directionTransform=function(t,e){return r(t,e),l(t,t),c(t,t),t},t.Identity=i(),t.innerProduct=function(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]}}(Qd||(Qd={})),function(t){function e(){const t=[.1,0];return t[0]=0,t}t.zero=e,t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i},t.create=function(t,i){const r=e();return r[0]=t,r[1]=i,r},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t},t.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t},t.set=function(t,e,i){return t[0]=e,t[1]=i,t},t.add=function(t,e,i){return t[0]=e[0]+i[0],t[1]=e[1]+i[1],t},t.sub=function(t,e,i){return t[0]=e[0]-i[0],t[1]=e[1]-i[1],t},t.mul=function(t,e,i){return t[0]=e[0]*i[0],t[1]=e[1]*i[1],t},t.div=function(t,e,i){return t[0]=e[0]/i[0],t[1]=e[1]/i[1],t},t.scale=function(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t},t.round=function(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t},t.ceil=function(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t},t.floor=function(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t},t.distance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1];return Math.sqrt(i*i+r*r)},t.squaredDistance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1];return i*i+r*r},t.magnitude=function(t){const e=t[0],i=t[1];return Math.sqrt(e*e+i*i)},t.squaredMagnitude=function(t){const e=t[0],i=t[1];return e*e+i*i},t.inverse=function(t,e){return t[0]=1/e[0],t[1]=1/e[1],t},t.areEqual=function(t,e){return t[0]===e[0]&&t[1]===e[1]},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)}}]`}}(Jd||(Jd={})),function(t){function e(){const t=[.1,0,0,0];return t[0]=0,t}function i(t,e){return t[0]=e.center[0],t[1]=e.center[1],t[2]=e.center[2],t[3]=e.radius,t}t.zero=e,t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i[3]=t[3],i},t.create=function(t,i,r,n){const s=e();return s[0]=t,s[1]=i,s[2]=r,s[3]=n,s},t.fromSphere=i,t.ofSphere=function(t){return i(e(),t)},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])||isNaN(t[2])||isNaN(t[3])},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e[i+3]=t[3],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=e[i+3],t},t.toVec3Array=function(t,e,i){e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2]},t.fromVec3Array=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=0,t},t.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},t.set=function(t,e,i,r,n){return t[0]=e,t[1]=i,t[2]=r,t[3]=n,t},t.add=function(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},t.distance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2],s=e[3]-t[3];return Math.sqrt(i*i+r*r+n*n+s*s)},t.scale=function(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t[2]=e[2]*i,t[4]=e[4]*i,t},t.round=function(t,e){return t[0]=Math.round(e[0]),t[1]=Math.round(e[1]),t[2]=Math.round(e[2]),t[3]=Math.round(e[3]),t},t.ceil=function(t,e){return t[0]=Math.ceil(e[0]),t[1]=Math.ceil(e[1]),t[2]=Math.ceil(e[2]),t[3]=Math.ceil(e[3]),t},t.floor=function(t,e){return t[0]=Math.floor(e[0]),t[1]=Math.floor(e[1]),t[2]=Math.floor(e[2]),t[3]=Math.floor(e[3]),t},t.squaredDistance=function(t,e){const i=e[0]-t[0],r=e[1]-t[1],n=e[2]-t[2],s=e[3]-t[3];return i*i+r*r+n*n+s*s},t.norm=function(t){const e=t[0],i=t[1],r=t[2],n=t[3];return Math.sqrt(e*e+i*i+r*r+n*n)},t.squaredNorm=function(t){const e=t[0],i=t[1],r=t[2],n=t[3];return e*e+i*i+r*r+n*n},t.transformMat4=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3];return t[0]=i[0]*r+i[4]*n+i[8]*s+i[12]*o,t[1]=i[1]*r+i[5]*n+i[9]*s+i[13]*o,t[2]=i[2]*r+i[6]*n+i[10]*s+i[14]*o,t[3]=i[3]*r+i[7]*n+i[11]*s+i[15]*o,t},t.dot=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]},t.inverse=function(t,e){return t[0]=1/e[0],t[1]=1/e[1],t[2]=1/e[2],t[3]=1/e[3],t},t.exactEquals=function(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]},t.equals=function(t,e){const i=t[0],r=t[1],n=t[2],s=t[3],o=e[0],a=e[1],c=e[2],l=e[3];return Math.abs(i-o)<=Vd*Math.max(1,Math.abs(i),Math.abs(o))&&Math.abs(r-a)<=Vd*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(n-c)<=Vd*Math.max(1,Math.abs(n),Math.abs(c))&&Math.abs(s-l)<=Vd*Math.max(1,Math.abs(s),Math.abs(l))},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)} ${t[2].toPrecision(e)} ${t[3].toPrecision(e)}]`}}(tm||(tm={})),function(t){function e(){const t=[.1,0,0,0];return t[0]=0,t}function i(){const t=e();return t[3]=1,t}function r(t,e,i){i*=.5;const r=Math.sin(i);return t[0]=r*e[0],t[1]=r*e[1],t[2]=r*e[2],t[3]=Math.cos(i),t}function n(t,e,i,r){const n=e[0],s=e[1],o=e[2],a=e[3];let c,l,h,u,d,m=i[0],f=i[1],p=i[2],g=i[3];return l=n*m+s*f+o*p+a*g,l<0&&(l=-l,m=-m,f=-f,p=-p,g=-g),1-l>1e-6?(c=Math.acos(l),h=Math.sin(c),u=Math.sin((1-r)*c)/h,d=Math.sin(r*c)/h):(u=1-r,d=r),t[0]=u*n+d*m,t[1]=u*s+d*f,t[2]=u*o+d*p,t[3]=u*a+d*g,t}function s(t,e){const i=e[0]+e[4]+e[8];let r;if(i>0)r=Math.sqrt(i+1),t[3]=.5*r,r=.5/r,t[0]=(e[5]-e[7])*r,t[1]=(e[6]-e[2])*r,t[2]=(e[1]-e[3])*r;else{let i=0;e[4]>e[0]&&(i=1),e[8]>e[3*i+i]&&(i=2);const n=(i+1)%3,s=(i+2)%3;r=Math.sqrt(e[3*i+i]-e[3*n+n]-e[3*s+s]+1),t[i]=.5*r,r=.5/r,t[3]=(e[3*n+s]-e[3*s+n])*r,t[n]=(e[3*n+i]+e[3*i+n])*r,t[s]=(e[3*s+i]+e[3*i+s])*r}return t}t.zero=e,t.identity=i,t.setIdentity=function(t){t[0]=0,t[1]=0,t[2]=0,t[3]=1},t.hasNaN=function(t){return isNaN(t[0])||isNaN(t[1])||isNaN(t[2])||isNaN(t[3])},t.create=function(t,e,r,n){const s=i();return s[0]=t,s[1]=e,s[2]=r,s[3]=n,s},t.setAxisAngle=r,t.getAxisAngle=function(t,e){const i=2*Math.acos(e[3]),r=Math.sin(i/2);return 0!==r?(t[0]=e[0]/r,t[1]=e[1]/r,t[2]=e[2]/r):(t[0]=1,t[1]=0,t[2]=0),i},t.multiply=function(t,e,i){const r=e[0],n=e[1],s=e[2],o=e[3],a=i[0],c=i[1],l=i[2],h=i[3];return t[0]=r*h+o*a+n*l-s*c,t[1]=n*h+o*c+s*a-r*l,t[2]=s*h+o*l+r*c-n*a,t[3]=o*h-r*a-n*c-s*l,t},t.rotateX=function(t,e,i){i*=.5;const r=e[0],n=e[1],s=e[2],o=e[3],a=Math.sin(i),c=Math.cos(i);return t[0]=r*c+o*a,t[1]=n*c+s*a,t[2]=s*c-n*a,t[3]=o*c-r*a,t},t.rotateY=function(t,e,i){i*=.5;const r=e[0],n=e[1],s=e[2],o=e[3],a=Math.sin(i),c=Math.cos(i);return t[0]=r*c-s*a,t[1]=n*c+o*a,t[2]=s*c+r*a,t[3]=o*c-n*a,t},t.rotateZ=function(t,e,i){i*=.5;const r=e[0],n=e[1],s=e[2],o=e[3],a=Math.sin(i),c=Math.cos(i);return t[0]=r*c+n*a,t[1]=n*c-r*a,t[2]=s*c+o*a,t[3]=o*c-s*a,t},t.calculateW=function(t,e){const i=e[0],r=e[1],n=e[2];return t[0]=i,t[1]=r,t[2]=n,t[3]=Math.sqrt(Math.abs(1-i*i-r*r-n*n)),t},t.slerp=n,t.invert=function(t,e){const i=e[0],r=e[1],n=e[2],s=e[3],o=i*i+r*r+n*n+s*s,a=o?1/o:0;return t[0]=-i*a,t[1]=-r*a,t[2]=-n*a,t[3]=s*a,t},t.conjugate=function(t,e){return t[0]=-e[0],t[1]=-e[1],t[2]=-e[2],t[3]=e[3],t},t.dot=function(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]+t[3]*e[3]},t.fromMat3=s,t.fromEuler=function(t,e,i){const[r,n,s]=e,o=Math.cos(r/2),a=Math.cos(n/2),c=Math.cos(s/2),l=Math.sin(r/2),h=Math.sin(n/2),u=Math.sin(s/2);switch(i){case"XYZ":t[0]=l*a*c+o*h*u,t[1]=o*h*c-l*a*u,t[2]=o*a*u+l*h*c,t[3]=o*a*c-l*h*u;break;case"YXZ":t[0]=l*a*c+o*h*u,t[1]=o*h*c-l*a*u,t[2]=o*a*u-l*h*c,t[3]=o*a*c+l*h*u;break;case"ZXY":t[0]=l*a*c-o*h*u,t[1]=o*h*c+l*a*u,t[2]=o*a*u+l*h*c,t[3]=o*a*c-l*h*u;break;case"ZYX":t[0]=l*a*c-o*h*u,t[1]=o*h*c+l*a*u,t[2]=o*a*u-l*h*c,t[3]=o*a*c+l*h*u;break;case"YZX":t[0]=l*a*c+o*h*u,t[1]=o*h*c+l*a*u,t[2]=o*a*u-l*h*c,t[3]=o*a*c-l*h*u;break;case"XZY":t[0]=l*a*c-o*h*u,t[1]=o*h*c-l*a*u,t[2]=o*a*u+l*h*c,t[3]=o*a*c+l*h*u;break;default:em()}return t};const o=[0,0,0];function a(t,e){const i=e[0],r=e[1],n=e[2],s=e[3];let o=i*i+r*r+n*n+s*s;return o>0&&(o=1/Math.sqrt(o),t[0]=i*o,t[1]=r*o,t[2]=n*o,t[3]=s*o),t}t.fromUnitVec3=function(t,e,i){let r=Xd.dot(e,i)+1;return rMath.abs(e[2])?Xd.set(o,-e[1],e[0],0):Xd.set(o,0,-e[2],e[1])):Xd.cross(o,e,i),t[0]=o[0],t[1]=o[1],t[2]=o[2],t[3]=r,a(t,t),t},t.clone=function(t){const i=e();return i[0]=t[0],i[1]=t[1],i[2]=t[2],i[3]=t[3],i},t.toArray=function(t,e,i){return e[i+0]=t[0],e[i+1]=t[1],e[i+2]=t[2],e[i+3]=t[3],e},t.fromArray=function(t,e,i){return t[0]=e[i+0],t[1]=e[i+1],t[2]=e[i+2],t[3]=e[i+3],t},t.copy=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},t.set=function(t,e,i,r,n){return t[0]=e,t[1]=i,t[2]=r,t[3]=n,t},t.exactEquals=function(t,e){return t[0]===e[0]&&t[1]===e[1]&&t[2]===e[2]&&t[3]===e[3]},t.equals=function(t,e){const i=t[0],r=t[1],n=t[2],s=t[3],o=e[0],a=e[1],c=e[2],l=e[3];return Math.abs(i-o)<=Vd*Math.max(1,Math.abs(i),Math.abs(o))&&Math.abs(r-a)<=Vd*Math.max(1,Math.abs(r),Math.abs(a))&&Math.abs(n-c)<=Vd*Math.max(1,Math.abs(n),Math.abs(c))&&Math.abs(s-l)<=Vd*Math.max(1,Math.abs(s),Math.abs(l))},t.add=function(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},t.normalize=a;const c=[0,0,0],l=[1,0,0],h=[0,1,0];t.rotationTo=function(t,e,i){const n=Xd.dot(e,i);return n<-.999999?(Xd.cross(c,l,e),Xd.magnitude(c)<1e-6&&Xd.cross(c,h,e),Xd.normalize(c,c),r(t,c,Math.PI),t):n>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(Xd.cross(c,e,i),t[0]=c[0],t[1]=c[1],t[2]=c[2],t[3]=1+n,a(t,t))};const u=e(),d=e();t.sqlerp=function(t,e,i,r,s,o){return n(u,e,s,o),n(d,i,r,o),n(t,u,d,2*o*(1-o)),t};const m=[0,0,0,0,0,0,0,0,0];t.setAxes=function(t,e,i,r){return m[0]=i[0],m[3]=i[1],m[6]=i[2],m[1]=r[0],m[4]=r[1],m[7]=r[2],m[2]=-e[0],m[5]=-e[1],m[8]=-e[2],a(t,s(t,m))},t.toString=function(t,e){return`[${t[0].toPrecision(e)} ${t[1].toPrecision(e)} ${t[2].toPrecision(e)} ${t[3].toPrecision(e)}]`},t.Identity=i()}(im||(im={})),function(t){function e(t,e,n){const s=function(t,e,i){const r=[];for(let t=0;tt[e],set:(t,e,i)=>t[e]=i,add:(t,e,i)=>t[e]+=i,dataOffset:t=>t,getCoords:(t,e)=>(e[0]=t,e)};case 2:if(0===i[0]&&1===i[1]){const t=e[0];return{get:(e,i,r)=>e[r*t+i],set:(e,i,r,n)=>e[r*t+i]=n,add:(e,i,r,n)=>e[r*t+i]+=n,dataOffset:(e,i)=>i*t+e,getCoords:(e,i)=>(i[0]=e%t,i[1]=Math.floor(e/t),i)}}if(1===i[0]&&0===i[1]){const t=e[1];return{get:(e,i,r)=>e[i*t+r],set:(e,i,r,n)=>e[i*t+r]=n,add:(e,i,r,n)=>e[i*t+r]+=n,dataOffset:(e,i)=>e*t+i,getCoords:(e,i)=>(i[0]=Math.floor(e/t),i[1]=e%t,i)}}throw new Error("bad axis order");case 3:if(0===i[0]&&1===i[1]&&2===i[2]){const t=e[0],i=e[1],r=t*i;return{get:(e,i,n,s)=>e[i+n*t+s*r],set:(e,i,n,s,o)=>e[i+n*t+s*r]=o,add:(e,i,n,s,o)=>e[i+n*t+s*r]+=o,dataOffset:(e,i,n)=>e+i*t+n*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=e%t,r[1]=n%i,r[2]=Math.floor(n/i),r}}}if(0===i[0]&&2===i[1]&&1===i[2]){const t=e[0],i=e[2],r=t*i;return{get:(e,i,n,s)=>e[i+s*t+n*r],set:(e,i,n,s,o)=>e[i+s*t+n*r]=o,add:(e,i,n,s,o)=>e[i+s*t+n*r]+=o,dataOffset:(e,i,n)=>e+n*t+i*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=e%t,r[1]=Math.floor(n/i),r[2]=n%i,r}}}if(1===i[0]&&0===i[1]&&2===i[2]){const t=e[1],i=e[0],r=t*i;return{get:(e,i,n,s)=>e[n+i*t+s*r],set:(e,i,n,s,o)=>e[n+i*t+s*r]=o,add:(e,i,n,s,o)=>e[n+i*t+s*r]+=o,dataOffset:(e,i,n)=>i+e*t+n*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=n%i,r[1]=e%t,r[2]=Math.floor(n/i),r}}}if(1===i[0]&&2===i[1]&&0===i[2]){const t=e[1],i=e[2],r=t*i;return{get:(e,i,n,s)=>e[n+s*t+i*r],set:(e,i,n,s,o)=>e[n+s*t+i*r]=o,add:(e,i,n,s,o)=>e[n+s*t+i*r]+=o,dataOffset:(e,i,n)=>i+n*t+e*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=Math.floor(n/i),r[1]=e%t,r[2]=n%i,r}}}if(2===i[0]&&0===i[1]&&1===i[2]){const t=e[2],i=e[0],r=t*i;return{get:(e,i,n,s)=>e[s+i*t+n*r],set:(e,i,n,s,o)=>e[s+i*t+n*r]=o,add:(e,i,n,s,o)=>e[s+i*t+n*r]+=o,dataOffset:(e,i,n)=>n+e*t+i*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=n%i,r[1]=Math.floor(n/i),r[2]=e%t,r}}}if(2===i[0]&&1===i[1]&&0===i[2]){const t=e[2],i=e[1],r=t*i;return{get:(e,i,n,s)=>e[s+n*t+i*r],set:(e,i,n,s,o)=>e[s+n*t+i*r]=o,add:(e,i,n,s,o)=>e[s+n*t+i*r]+=o,dataOffset:(e,i,n)=>n+i*t+e*r,getCoords:(e,r)=>{const n=Math.floor(e/t);return r[0]=Math.floor(n/i),r[1]=n%i,r[2]=e%t,r}}}throw new Error("bad axis order");default:return{get:(e,...i)=>e[n(t,i)],set:(e,...i)=>e[n(t,i)]=i[i.length-1],add:(e,...i)=>e[n(t,i)]+=i[i.length-1],dataOffset:(...e)=>n(t,e),getCoords:(e,i)=>function(t,e,i){const{dimensions:r,axisOrderFastToSlow:n}=t,s=r.length;let o=e;for(let t=0;tnew(e||t.defaultCtor)(i)}function n(t,e){const{accessDimensions:i,axisOrderFastToSlow:r}=t,n=i.length-1;let s=i[n]*e[r[n]];for(let t=n-1;t>=0;t--)s=(s+e[r[t]])*i[t];return s}function s(t,e){const i=[];for(let r=0;rs(t,e)},t.convertToCanonicalAxisIndicesSlowToFast=function(t){const e=new Int32Array(t.length);for(let i=0;is(t,e)}}(rm||(rm={})),function(t){let e;function i(t,e){return hm(e.T,t,e,1)}function r(t){return um(t)}!function(t){function e(e,i=t.float){return{"@type":"tensor",T:e.create(),space:e,valueType:"tensor",baseType:i}}t.str={"@type":"str",T:"",valueType:"str"},t.ustr={"@type":"str",T:"",valueType:"str",transform:"uppercase"},t.lstr={"@type":"str",T:"",valueType:"str",transform:"lowercase"},t.int={"@type":"int",T:0,valueType:"int"},t.coord={"@type":"coord",T:0,valueType:"float"},t.float={"@type":"float",T:0,valueType:"float"},t.Str=function(t){var e;return{"@type":"str",T:null!==(e=null==t?void 0:t.defaultValue)&&void 0!==e?e:"",transform:null==t?void 0:t.transform,valueType:"str"}},t.Int=function(t=0){return{"@type":"int",T:t,valueType:"int"}},t.Float=function(t=0){return{"@type":"float",T:t,valueType:"float"}},t.Tensor=e,t.Vector=function(i,r=t.float){return e(rm.Vector(i,"int"===r["@type"]?Int32Array:Float64Array),r)},t.Matrix=function(i,r,n=t.float){return e(rm.ColumnMajorMatrix(i,r,"int"===n["@type"]?Int32Array:Float64Array),n)},t.Aliased=function(t){return t},t.List=function(t,e,i=[]){return{"@type":"list",T:i,separator:t,itemParse:e,valueType:"list"}}}(e=t.Schema||(t.Schema={})),t.is=function(t){return!!t&&!!t.schema&&!!t.value},t.ValueKind={Present:0,NotPresent:1,Unknown:2},t.Undefined=i,t.ofConst=function(t,e,i){return hm(t,e,i,0)},t.ofLambda=r,t.range=function(t,i){return r({value:e=>e+t,rowCount:Math.max(i-t+1,0),schema:e.int})},t.ofArray=function(t){return dm(t)},t.ofIntArray=function(t){return dm({array:t,schema:e.int})},t.ofFloatArray=function(t){return dm({array:t,schema:e.float})},t.ofStringArray=function(t){return dm({array:t,schema:e.str})},t.ofStringAliasArray=function(t){return dm({array:t,schema:e.Aliased(e.str)})},t.ofStringListArray=function(t,i=","){return dm({array:t,schema:e.List(i,(t=>t))})},t.ofIntTokens=function(t){const{count:i,data:r,indices:n}=t;return um({value:t=>am(r,n[2*t],n[2*t+1])||0,rowCount:i,schema:e.int})},t.ofFloatTokens=function(t){const{count:i,data:r,indices:n}=t;return um({value:t=>lm(r,n[2*t],n[2*t+1])||0,rowCount:i,schema:e.float})},t.ofStringTokens=function(t){const{count:i,data:r,indices:n}=t;return um({value:t=>{const e=r.substring(n[2*t],n[2*t+1]);return"."===e||"?"===e?"":e},rowCount:i,schema:e.str})},t.window=function(t,e,i){return mm(t,e,i)},t.view=function(t,e,i=!0){return fm(t,e,i)},t.createFirstIndexMap=function(t){return function(t){const e=new Map;for(let i=0,r=t.rowCount;ie.has(t)?e.get(t):-1}(t)},t.mapToArray=function(t,e,i){return function(t,e,i){const r=new i(t.rowCount);for(let i=0,n=t.rowCount;i0&&(t.chunks[t.chunks.length]=t.current.length===t.offset?t.current.join(""):t.current.slice(0,t.offset).join("")),t.chunks.join("")):t.current.length===t.offset?t.current.join(""):t.current.splice(0,t.offset).join("")},t.getSize=function(t){let e=0;for(const i of t.chunks)e+=i.length;for(let i=0;i0&&(t.current.length===t.offset?t.chunks[t.chunks.length]=t.current.join(""):t.chunks[t.chunks.length]=t.current.slice(0,t.offset).join(""),t.offset=0),t.chunks};const e=[];function i(t,i){i>0&&r(t,e[i])}function r(t,e){t.offset===t.capacity&&(t.chunks[t.chunks.length]=t.current.join(""),t.offset=0),t.current[t.offset++]=e}!function(){let t="";for(let i=0;i<512;i++)e[i]=t,t+=" "}(),t.newline=function(t){r(t,"\n")},t.whitespace=i,t.whitespace1=function(t){r(t," ")},t.write=function(t,e){e&&(t.offset===t.capacity&&(t.chunks[t.chunks.length]=t.current.join(""),t.offset=0),t.current[t.offset++]=e)},t.writeSafe=r,t.writePadLeft=function(t,e,n){if(!e)return void i(t,n);i(t,n-e.length),r(t,e)},t.writePadRight=function(t,e,n){if(!e)return void i(t,n);const s=n-e.length;r(t,e),i(t,s)},t.writeInteger=function(t,e){r(t,""+e)},t.writeIntegerAndSpace=function(t,e){r(t,e+" ")},t.writeIntegerPadLeft=function(t,e,n){const s=""+e;i(t,n-s.length),r(t,s)},t.writeIntegerPadRight=function(t,e,n){const s=""+e,o=n-s.length;r(t,s),i(t,o)},t.writeFloat=function(t,e,i){r(t,""+Math.round(i*e)/i)},t.writeFloatPadLeft=function(t,e,n,s){const o=""+Math.round(n*e)/n;i(t,s-o.length),r(t,o)},t.writeFloatPadRight=function(t,e,n,s){const o=""+Math.round(n*e)/n,a=s-o.length;r(t,o),i(t,a)}}(om||(om={}));const Cm=function(){if("undefined"!=typeof window&&window.performance){const t=window.performance;return()=>t.now()}return"undefined"!=typeof process&&"undefined"!==process.hrtime&&"function"==typeof process.hrtime?()=>{const t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:Date.now?()=>Date.now():()=>+new Date}();var Pm,Im,km;function Mm(t,e){return t-e}function Tm(t=0,e=Number.MAX_SAFE_INTEGER){let i=t;return()=>{const t=i;return i=(i+1)%e,t}}!function(t){const e="undefined"!=typeof btoa?btoa:t=>Buffer.from(t).toString("base64"),i=[];t.create22=function(){let t=+new Date+Cm();for(let e=0;e<16;e++)i[e]=String.fromCharCode((t+255*Math.random())%255|0),t=Math.floor(t/255);return e(i.join("")).replace(/\+/g,"-").replace(/\//g,"_").substr(0,22)},t.createv4=function(){let t=+new Date+Cm();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){const i=(t+16*Math.random())%16|0;return t=Math.floor(t/16),("x"===e?i:3&i|8).toString(16)}))},t.is=function(t){return"string"==typeof t}}(Pm||(Pm={})),function(t){class e{has(t){return!1}forEach(t,e){return e}constructor(){this.size=0}}class i{has(t){return t===this.idx}forEach(t,e){return t(this.idx,e),e}constructor(t){this.idx=t,this.size=1}}class r{has(t){return tt[e++]=i)),function(t){Array.prototype.sort.call(t,Mm)}(t),this._flat=t,this._flat}forEach(t,e){return this._forEach(t,e),e}constructor(t){this.set=t,this._flat=void 0,this.size=t.size}}function o(t){return new s(t)}function a(t,e){return new r(t,e)}t.always=function(t){return new n(t)},t.never=new e,t.ofSet=o,t.singleton=function(t){return new i(t)},t.ofUniqueIndices=function(t){const o=t.length;if(0===o)return new e;if(1===o)return new i(t[0]);let a=0;for(const e of t)e>a&&(a=e);if(o===a)return new n(o);if(o/a<1/12){const e=new Set;for(const i of t)e.add(i);return new s(e)}const c=new Int8Array(a+1);for(const e of t)c[e]=1;return new r(c,t.length)},t.ofMask=a,t.hasAny=function(t,e){for(const i of e)if(t.has(i))return!0;return!1},t.complement=function(t,e){let i=0,r=0;if(e.forEach((e=>{t.has(e)||(i++,e>r&&(r=e))})),i/r<1/12){const i=new Set;return e.forEach((e=>{t.has(e)||i.add(e)})),o(i)}{const n=new Uint8Array(r+1);return e.forEach((e=>{t.has(e)||(n[e]=1)})),a(n,i)}}}(Im||(Im={})),function(t){t.create=function(t){return{ref:t}},t.set=function(t,e){return t.ref=e,t}}(km||(km={}));const Dm=Tm(0,2147483647);var Bm,Fm,Em,$m,Om;function Rm(t){const{data:e,indices:i}=t;return function(t,r){const n=i[2*t],s=i[2*r],o=i[2*t+1]-n;if(o!==i[2*r+1]-s)return!1;for(let t=0;tr[t]}}!function(t){t.create=function(t,e){return{id:Dm(),version:0,value:t,metadata:e}},t.withValue=function(t,e){return{id:t.id,version:t.version+1,value:e,metadata:t.metadata}}}(Bm||(Bm={})),function(t){function e(t,e){return km.set(t,Bm.withValue(t.ref,e))}t.create=function(t,e){return km.create(Bm.create(t,e))},t.update=e,t.set=function(t,e){return km.set(t,e)},t.updateIfChanged=function(t,i){return t.ref.value!==i?e(t,i):t}}(Fm||(Fm={})),function(t){function e(t,e,i){const r=Object.create(null),n=Object.keys(e);r._rowCount=i.length,r._columns=n,r._schema=e;for(const e of n)r[e]=nm.view(t[e],i);return r}function i(t,e){const i=Object.create(null),{_columns:r}=t;for(let n=0;ne[t][s],valueKind:t=>void 0===e[t][s]?1:0});return i},t.ofArrays=function(t,e){var i;const r=Object.create(null),n=Object.keys(t);r._rowCount=0,r._columns=n,r._schema=t;for(const s of n)void 0!==e[s]?(r[s]=nm.ofArray({array:e[s],schema:t[s]}),r._rowCount=null===(i=e[s])||void 0===i?void 0:i.length):r[s]=nm.Undefined(r._rowCount,t[s]);return r},t.view=e,t.pick=function(t,i,r){const n=[];for(let e=0,i=t._rowCount;ee(i,r)));let r=!0;for(let t=0,e=i.length;t0?e[i[0]].rowCount:0,name:t,fieldNames:i,getField:t=>e[t]}}t.empty=function(t){return{rowCount:0,name:t,fieldNames:[],getField(t){}}},t.ofFields=e,t.ofTable=function(t,i){const r={};for(const t of i._columns)r[t]=Om.ofColumn(i[t]);return e(t,r)}}(zm||(zm={})),function(t){function e(t){const e=t.length,i=e=>{const i=t[e];return i&&"."!==i&&"?"!==i?i:""},r=e=>{const i=t[e];return am(i,0,i.length)||0},n=e=>{const i=t[e];return lm(i,0,i.length)||0};return{__array:void 0,binaryEncoding:void 0,isDefined:!0,rowCount:e,str:i,int:r,float:n,valueKind:e=>{const i=t[e],r=i.length;if(r>1)return 0;if(0===r)return 1;const n=i.charCodeAt(0);return 46===n?1:63===n?2:0},areValuesEqual:(e,i)=>t[e]===t[i],toStringArray:r=>r?Nd(e,i,r):t,toIntArray:t=>Nd(e,r,t),toFloatArray:t=>Nd(e,n,t)}}function i(t){const{rowCount:e,valueKind:i,areValuesEqual:r,isDefined:n}=t;let s,o,a;switch(t.schema.valueType){case"float":case"int":s=e=>""+t.value(e),o=t.value,a=t.value;break;case"str":s=t.value,o=e=>{const i=t.value(e);return am(i,0,i.length)||0},a=e=>{const i=t.value(e);return lm(i,0,i.length)||0};break;case"list":const{separator:e}=t.schema;s=i=>t.value(i).join(e),o=t=>NaN,a=t=>NaN;break;default:throw new Error(`unsupported valueType '${t.schema.valueType}'`)}return{__array:void 0,binaryEncoding:void 0,isDefined:n,rowCount:e,str:s,int:o,float:a,valueKind:i,areValuesEqual:r,toStringArray:t=>Nd(e,s,t),toIntArray:t=>Nd(e,o,t),toFloatArray:t=>Nd(e,a,t)}}t.ofString=function(t){return e([t])},t.ofStrings=e,t.ofNumbers=function(t){const e=t.length,i=e=>""+t[e],r=e=>t[e],n=i=>!i||i.array&&t instanceof i.array?t:Nd(e,r,i);return{__array:void 0,binaryEncoding:void 0,isDefined:!0,rowCount:e,str:i,int:r,float:r,valueKind:t=>0,areValuesEqual:(e,i)=>t[e]===t[i],toStringArray:t=>Nd(e,i,t),toIntArray:n,toFloatArray:n}},t.ofTokens=function(t){const{data:e,indices:i,count:r}=t,n=t=>{const r=e.substring(i[2*t],i[2*t+1]);return"."===r||"?"===r?"":r},s=t=>am(e,i[2*t],i[2*t+1])||0,o=t=>lm(e,i[2*t],i[2*t+1])||0;return{__array:void 0,binaryEncoding:void 0,isDefined:!0,rowCount:r,str:n,int:s,float:o,valueKind:t=>{const r=i[2*t],n=i[2*t+1]-r;if(n>1)return 0;if(0===n)return 1;const s=e.charCodeAt(r);return 46===s?1:63===s?2:0},areValuesEqual:Rm(t),toStringArray:t=>Nd(r,n,t),toIntArray:t=>Nd(r,s,t),toFloatArray:t=>Nd(r,o,t)}},t.ofColumn=i,t.ofUndefined=function(t,e){return i(nm.Undefined(t,e))}}(Om||(Om={}));const Um="undefined"!=typeof setImmediate?"undefined"!=typeof window?{setImmediate:(t,...e)=>window.setImmediate(t,...e),clearImmediate:t=>window.clearImmediate(t)}:{setImmediate:setImmediate,clearImmediate:clearImmediate}:function(){const t=function(){const t="undefined"!=typeof window&&window,e="undefined"!=typeof self&&"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&self,i="undefined"!=typeof global&&global;return t||i||e}(),e={},i="undefined"!=typeof document?document:void 0;let r,n=1;function s(t){delete e[t]}function o(t){const i=e[t];s(t),function(t){const e=t.callback,i=t.args;switch(i.length){case 0:e();break;case 1:e(i[0]);break;case 2:e(i[0],i[1]);break;case 3:e(i[0],i[1],i[2]);break;default:e.apply(void 0,i)}}(i)}return"undefined"!=typeof process&&"[object process]"==={}.toString.call(process)?r=function(t){process.nextTick((function(){o(t)}))}:function(){if(t&&t.postMessage&&!t.importScripts){let e=!0;const i=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=i,e}}()?function(){const e="setImmediate$"+Math.random()+"$",i=function(i){i.source===t&&"string"==typeof i.data&&0===i.data.indexOf(e)&&o(+i.data.slice(e.length))};window.addEventListener?window.addEventListener("message",i,!1):window.attachEvent("onmessage",i),r=function(t){window.postMessage(e+t,"*")}}():"undefined"!=typeof MessageChannel?function(){const t=new MessageChannel;t.port1.onmessage=function(t){o(t.data)},r=function(e){t.port2.postMessage(e)}}():i&&"onreadystatechange"in i.createElement("script")?function(){const t=i.documentElement;r=function(e){let r=i.createElement("script");r.onreadystatechange=function(){o(e),r.onreadystatechange=null,t.removeChild(r),r=null},t.appendChild(r)}}():r=function(t){setTimeout(o,0,t)},{setImmediate:function(t,...i){"function"!=typeof t&&(t=new Function(""+t));const s={callback:t,args:i};return e[n]=s,r(n),n++},clearImmediate:s}}();function Vm(t){Um.setImmediate(t)}const jm={setImmediate:Um.setImmediate,clearImmediate:Um.clearImmediate,immediatePromise:()=>new Promise(Vm),delay:(t,e=void 0)=>new Promise((i=>setTimeout(i,t,e)))};!function(){try{return"production"===process.env.NODE_ENV}catch(t){return!1}}(),function(){try{const t=process.env.DEBUG;return"*"===t||"molstar"===t}catch(t){return!1}}();const Gm="undefined"!=typeof performance&&!!performance.mark&&performance.measure&&!1;var Hm;function qm(t,e,i=250){const r=function(t,e,i){const r={abortRequested:!1,treeAborted:!1,reason:""};return{updateRateMs:i,lastNotified:Cm(),observer:e,abortToken:r,taskId:t.id,root:{progress:Wm(t),children:[]},tryAbort:Xm(r)}}(t,e,i);return Zm(t,new ef(r,r.root))}function Wm(t){return{taskId:t.id,taskName:t.name,message:"",startedTime:0,canAbort:!0,isIndeterminate:!0,current:0,max:0}}function Xm(t){return e=>{t.abortRequested=!0,t.reason=e||t.reason}}function Ym(t){return{progress:{...t.progress},children:t.children.map(Ym)}}function Km(t){return t.progress.canAbort&&t.children.every(Km)}async function Zm(t,e){Hm.markStart(t),e.node.progress.startedTime=Cm();try{const i=await t.f(e);return Hm.markEnd(t),Hm.measure(t),e.info.abortToken.abortRequested&&Qm(e.info),i}catch(i){throw nf.isAbort(i)&&(e.isAborted=!0,e.node.children.length>0&&await new Promise((t=>{e.onChildrenFinished=t})),t.onAbort&&t.onAbort()),i}}function Qm(t){throw t.abortToken.treeAborted||(t.abortToken.treeAborted=!0,Jm(t.root),tf(t,Cm())),nf.Aborted(t.abortToken.reason)}function Jm(t){const e=t.progress;e.isIndeterminate=!0,e.canAbort=!1,e.message="Aborting...";for(const e of t.children)Jm(e)}function tf(t,e){t.lastNotified=e;const i=function(t){return{root:Ym(t.root),canAbort:Km(t.root),requestAbort:t.tryAbort}}(t);t.observer(i)}!function(t){function e(t){return`startTask${t.id}`}function i(t){return`endTask${t.id}`}t.markStart=function(t){Gm&&performance.mark(e(t))},t.markEnd=function(t){Gm&&performance.mark(i(t))},t.measure=function(t){Gm&&performance.measure(`✳️ ${t.name}`,e(t),i(t))}}(Hm||(Hm={}));class ef{checkAborted(){this.info.abortToken.abortRequested&&(this.isAborted=!0,Qm(this.info))}get shouldUpdate(){return this.checkAborted(),Cm()-this.lastUpdatedTime>this.info.updateRateMs}updateProgress(t){if(this.checkAborted(),!t)return;const e=this.node.progress;"string"==typeof t?(e.message=t,e.isIndeterminate=!0):(void 0!==t.canAbort&&(e.canAbort=t.canAbort),void 0!==t.message&&(e.message=t.message),void 0!==t.current&&(e.current=t.current),void 0!==t.max&&(e.max=t.max),e.isIndeterminate=void 0===e.current||void 0===e.max,void 0!==t.isIndeterminate&&(e.isIndeterminate=t.isIndeterminate))}update(t,e){if(this.lastUpdatedTime=Cm(),this.updateProgress(t),!e)return tf(this.info,this.lastUpdatedTime),this.checkAborted(),jm.immediatePromise()}async runChild(t,e){this.updateProgress(e);const i={progress:Wm(t),children:[]},r=this.node.children;r.push(i);const n=new ef(this.info,i);try{return await Zm(t,n)}catch(t){if(nf.isAbort(t)&&this.isAborted)return;throw t}finally{const t=r.indexOf(i);if(t>=0){for(let e=t,i=r.length-1;e0;){o+=l;const e=Cm()-c;h+=e,a+=e,t.shouldUpdate&&(await n(t,i,o),s=Math.round(h*o/a)+1,c=Cm(),h=0)}return t.shouldUpdate&&await n(t,i,o),i}function uf(t){return{data:t,position:0,length:t.length,lineNumber:1,tokenStart:0,tokenEnd:0}}function df(t){for(;t.position=t.length)return void(t.tokenType=6);t.tokenStart=t.position,t.tokenEnd=t.position,t.isEscaped=!1;const i=t.data.charCodeAt(t.position);switch(i){case 35:!function(t){for(;t.position=5&&95===t.data.charCodeAt(t.tokenStart+4)?!function(t){let e=t.data.charCodeAt(t.tokenStart);return!(68!==e&&100!==e||(e=t.data.charCodeAt(t.tokenStart+1),65!==e&&97!==e||(e=t.data.charCodeAt(t.tokenStart+2),84!==e&&116!==e||(e=t.data.charCodeAt(t.tokenStart+3),65!==e&&97!==e))))}(t)?!function(t){let e=t.data.charCodeAt(t.tokenStart);return!(83!==e&&115!==e||(e=t.data.charCodeAt(t.tokenStart+1),65!==e&&97!==e||(e=t.data.charCodeAt(t.tokenStart+2),86!==e&&118!==e||(e=t.data.charCodeAt(t.tokenStart+3),69!==e&&101!==e))))}(t)?!function(t){if(t.tokenEnd-t.tokenStart!=5)return!1;let e=t.data.charCodeAt(t.tokenStart);return!(76!==e&&108!==e||(e=t.data.charCodeAt(t.tokenStart+1),79!==e&&111!==e||(e=t.data.charCodeAt(t.tokenStart+2),79!==e&&111!==e||(e=t.data.charCodeAt(t.tokenStart+3),80!==e&&112!==e))))}(t)?t.tokenType=3:t.tokenType=2:t.tokenType=1:t.tokenType=0:t.tokenType=3}}function _f(t){for(bf(t);5===t.tokenType;)bf(t)}function xf(){return{categoryNames:[],categoryData:Object.create(null)}}function vf(t,e){const i=Object.create(null);for(const r of t){const t=e[r];i[r]=zm(t.name,t.rowCount,t.fieldNames,t.fields)}return i}function wf(t,e,i){return Nm(t.categoryNames,vf(t.categoryNames,t.categoryData),e,i)}function Af(t,e){return Nm(t.categoryNames,vf(t.categoryNames,t.categoryData),e)}function Sf(t,e,i,r,n){if(e in t.categoryData){const i=t.categoryData[e];i.fieldNames.push(...r),Object.assign(i.fields,n)}else t.categoryData[e]={name:e,rowCount:i,fieldNames:r,fields:n},t.categoryNames.push(e)}function Cf(t,e){const i=t.tokenStart,r=pf(t),n=gf(t,r),s=Object.create(null),o=[];let a=!0;for(;a;){if(4!==t.tokenType||!ff(t,i,r)){a=!1;break}const e=yf(t).substring(n.length+1);if(_f(t),3!==t.tokenType)return{hasError:!0,errorLine:t.lineNumber,errorMessage:"Expected value."};s[e]=Om.ofTokens({data:t.data,indices:[t.tokenStart,t.tokenEnd],count:1}),o[o.length]=e,_f(t)}return Sf(e,n.substr(1),1,o,s),{hasError:!1,errorLine:0,errorMessage:""}}function Pf(t,e){const{tokenizer:i,tokens:r,fieldCount:n}=e;let s=e.tokenCount,o=0;for(;3===i.tokenType&&o0&&i.push(wf(s,n,o)),n=t.substring(r.tokenStart+5,r.tokenEnd),s=xf(),o=[],_f(r)}else if(1===e){if(r.tokenEnd-r.tokenStart==5)a.categoryNames.length>0&&(o[o.length]=Af(a,l)),r.inSaveFrame=!1;else{if(r.inSaveFrame)return Mf(r.lineNumber,"Save frames cannot be nested.");r.inSaveFrame=!0,l=t.substring(r.tokenStart+5,r.tokenEnd),a=xf()}_f(r)}else if(2===e){const t=await kf(r,r.inSaveFrame?a:s);if(t.hasError)return Mf(t.errorLine,t.errorMessage)}else{if(4!==e)return console.log(r.tokenType,uf.getTokenString(r)),Mf(r.lineNumber,"Unexpected token. Expected data_, loop_, or data name.");{const t=Cf(r,r.inSaveFrame?a:s);if(t.hasError)return Mf(t.errorLine,t.errorMessage)}}}return r.inSaveFrame?Mf(r.lineNumber,`Unfinished save frame (${c.header}).`):((s.categoryNames.length>0||o.length>0)&&i.push(wf(s,n,o)),function(t){return cf.success(t)}(Lm(i)))}function Df(t){return nf.create("Parse CIF",(async e=>await Tf(t,e)))}!function(t){class e{run(t,e=250){return t?qm(this,t,e):this.f(rf)}runAsChild(t,e){return t.isSynchronous?this.f(rf):function(t,e,i){return t.runChild(e,i)}(t,this,e)}runInContext(t){return t.isSynchronous?this.f(rf):function(t,e){return Zm(e,t)}(t,this)}constructor(t,e,i){this.name=t,this.f=e,this.onAbort=i,this.id=n()}}function i(t){const e=t;return!!t&&"number"==typeof e.id&&"string"==typeof e.name&&!!e.run}function r(t,i,r){return new e(t,i,r)}t.is=i,t.isAbort=function(t){return!!t&&!!t.isAborted},t.Aborted=function(t){return{isAborted:!0,reason:t,toString:()=>"Aborted"+(t?": "+t:"")}},t.create=r,t.constant=function(t,e){return r(t,(async t=>e))},t.empty=function(){return r("",(async t=>{}))},t.fail=function(t,e){return r(t,(async t=>{throw new Error(e)}))},t.resolveInContext=function(t,e){return i(t)?e?t.runInContext(e):t.run():t};const n=Tm(0,1073741823)}(nf||(nf={})),function(t){t.Synchronous=rf}(sf||(sf={})),function(t){function e(t,i=""){const r=t.progress;if(!t.children.length)return r.isIndeterminate?`${i}${r.taskName}: ${r.message}`:`${i}${r.taskName}: [${r.current}/${r.max}] ${r.message}`;const n=i+" |_ ",s=t.children.map((t=>e(t,n)));return r.isIndeterminate?`${i}${r.taskName}: ${r.message}\n${s.join("\n")}`:`${i}${r.taskName}: [${r.current}/${r.max}] ${r.message}\n${s.join("\n")}`}t.format=function(t){return e(t.root)}}(of||(of={})),function(t){function e(t){return t.data.substring(t.tokenStart,t.tokenEnd)}function i(t){const{data:e}=t;for(;t.position=n;)o=r.charCodeAt(--s);return t.tokenStart=n,t.tokenEnd=s+1,t.position=i,t}t.getTokenString=e,t.reset=function(t){t.position=0,t.lineNumber=1,t.tokenStart=0,t.tokenEnd=0},t.eatLine=i,t.markStart=function(t){t.tokenStart=t.position},t.markLine=r,t.readLine=function(t){return r(t),e(t)},t.readLineTrim=function(t){r(t);const i=t.position;return s(t,t.tokenStart,t.tokenEnd),t.position=i,e(t)},t.markLines=function(t,e){const i=af.create(t.data,2*e);return n(t,e,i),i},t.readLines=function(e,i){const r=[];for(let n=0;n{const r=Math.min(e-o,t);return n(i,r,s),o+=r,r}),((t,e)=>t.update({message:"Parsing...",current:e.position,max:e.length}))),s},t.readAllLines=function(e){const i=t(e),n=af.create(i.data,Math.max(e.length/80,2));for(;r(i);)af.add(n,i.tokenStart,i.tokenEnd);return n},t.readAllLinesAsync=async function(e,i,n=1e5){const s=t(e),o=af.create(s.data,Math.max(e.length/80,2));return await hf(i,n,s,((t,e)=>(function(t,e,i){let n=0;for(let s=0;st.update({message:"Parsing...",current:e.position,max:e.length}))),o},t.eatValue=function(t){for(;t.positionr.indicesLenMinus2&&function(t){const e=new Uint32Array(1.61*t.indices.length|0);e.set(t.indices),t.indices=e,t.indicesLenMinus2=e.length-2|0}(r),r.indices[r.offset++]=e,r.indices[r.offset++]=i,t.count++}t.add=e,t.addToken=function(t,i){e(t,i.tokenStart,i.tokenEnd)},t.addUnchecked=function(t,e,i){t.indices[t.offset++]=e,t.indices[t.offset++]=i,t.count++},t.create=function(t,e){return{data:t,indicesLenMinus2:(e=Math.max(10,e))-2|0,count:0,offset:0,indices:new Uint32Array(e)}}}(af||(af={})),function(t){t.error=function(t,i=-1){return new e(t,i)},t.success=function(t,e=[]){return new i(t,e)};class e{toString(){return this.line>=0?`[Line ${this.line}] ${this.message}`:this.message}constructor(t,e){this.message=t,this.line=e,this.isError=!0}}t.Error=e;class i{constructor(t,e){this.result=t,this.warnings=e,this.isError=!1}}t.Success=i}(cf||(cf={})),function(t){var e,i;(e=t.IntDataType||(t.IntDataType={}))[e.Int8=1]="Int8",e[e.Int16=2]="Int16",e[e.Int32=3]="Int32",e[e.Uint8=4]="Uint8",e[e.Uint16=5]="Uint16",e[e.Uint32=6]="Uint32",(i=t.FloatDataType||(t.FloatDataType={}))[i.Float32=32]="Float32",i[i.Float64=33]="Float64",t.getDataType=function(e){let i;return i=e instanceof Int8Array?t.IntDataType.Int8:e instanceof Int16Array?t.IntDataType.Int16:e instanceof Int32Array?t.IntDataType.Int32:e instanceof Uint8Array?t.IntDataType.Uint8:e instanceof Uint16Array?t.IntDataType.Uint16:e instanceof Uint32Array?t.IntDataType.Uint32:e instanceof Float32Array?t.FloatDataType.Float32:e instanceof Float64Array?t.FloatDataType.Float64:t.IntDataType.Int32,i},t.isSignedIntegerDataType=function(t){if(t instanceof Int8Array||t instanceof Int16Array||t instanceof Int32Array)return!0;for(let e=0,i=t.length;e=0;i--)e=Ef(e,t.encoding[i]);return e}function Ef(t,e){switch(e.kind){case"ByteArray":switch(e.type){case lf.IntDataType.Uint8:return t;case lf.IntDataType.Int8:return function(t){return new Int8Array(t.buffer,t.byteOffset)}(t);case lf.IntDataType.Int16:return function(t){return Rf(t,2,Int16Array)}(t);case lf.IntDataType.Uint16:return function(t){return Rf(t,2,Uint16Array)}(t);case lf.IntDataType.Int32:return function(t){return Rf(t,4,Int32Array)}(t);case lf.IntDataType.Uint32:return function(t){return Rf(t,4,Uint32Array)}(t);case lf.FloatDataType.Float32:return function(t){return Rf(t,4,Float32Array)}(t);case lf.FloatDataType.Float64:return function(t){return Rf(t,8,Float64Array)}(t);default:em(e.type)}case"FixedPoint":return function(t,e){const i=t.length,r=Of(e.srcType,i),n=1/e.factor;for(let e=0;e=t.currentSize)o.set(c,a);else for(let t=0,e=c.length;t=t.currentSize&&e(t);const o=t.currentChunk,a=t.currentIndex;return o[a]=i,o[a+1]=r,o[a+2]=n,o[a+3]=s,t.currentIndex+=4,t.elementCount++},t.add3=function(t,i,r,n){t.currentIndex>=t.currentSize&&e(t);const s=t.currentChunk,o=t.currentIndex;return s[o]=i,s[o+1]=r,s[o+2]=n,t.currentIndex+=3,t.elementCount++},t.add2=function(t,i,r){t.currentIndex>=t.currentSize&&e(t);const n=t.currentChunk,s=t.currentIndex;return n[s]=i,n[s+1]=r,t.currentIndex+=2,t.elementCount++},t.add=function(t,i){return t.currentIndex>=t.currentSize&&e(t),t.currentChunk[t.currentIndex]=i,t.currentIndex+=1,t.elementCount++},t.addRepeat=function(t,i,r){for(let n=0;n=t.currentSize&&e(t),t.currentChunk[t.currentIndex++]=r,t.elementCount++;return t.elementCount},t.addMany=function(t,i){const{elementSize:r}=t;for(let n=0,s=i.length;n=t.currentSize&&e(t);const{currentChunk:s}=t;for(let e=0;e=0?Math.ceil((t+1)/e):Math.ceil((t+1)/(-e-1))}function i({limit8:t,limit16:i},r,n){r.pack8+=e(n,t),r.pack16+=e(n,i),r.count+=1}function r(t,i){t.pack8+=e(i,127),t.pack16+=e(i,32767),t.count+=1}function n(t){return 4*t.count<2*t.pack16?{length:4*t.count,elem:4}:2*t.pack16t.length-e.length)),i}t.getSize=l,t.classify=function(t){if(t.length<2)return Vf.by(Vf.byteArray);switch(l(t)[0].kind){case"pack":return Vf.by(Vf.integerPacking);case"rle":return Vf.by(Vf.runLength).and(Vf.integerPacking);case"delta":return Vf.by(Vf.delta).and(Vf.integerPacking);case"delta-rle":return Vf.by(Vf.delta).and(Vf.runLength).and(Vf.integerPacking);default:em()}}}(Nf||(Nf={})),function(t){t.classify=function(t){const{mantissaDigits:e,integerDigits:i}=function(t,e,i){let r=1,n=0;for(let s=0,o=t.length;s=0){const n=jf(t[s],e,i);n<0?r=-1:n>r&&(r=n)}const o=Math.abs(t[s]);if(o>i){const t=Math.floor(Math.log10(Math.abs(o)))+1;t>n&&(n=t)}}return{mantissaDigits:r,integerDigits:n}}(t,4,1e-6);if(e<0||e+i>10)return Vf.by(Vf.byteArray);if(0===e)return Nf.classify(t);const r=function(t){let e=1;for(let i=0;i=0?s/e|0:s/i|0}return r+=t.length,r}t.byteArray=r,t.fixedPoint=function(t){return e=>function(t,e){const i=lf.getDataType(t),r=new Int32Array(t.length);for(let i=0,n=t.length;ifunction(t,e,i,r,n){const s=lf.getDataType(t);if(!t.length)return{encodings:[{kind:"IntervalQuantization",min:e,max:i,numSteps:r,srcType:s}],data:new Int32Array(0)};if(i=i?r-1:0|Math.round((s-e)/o)}return{encodings:[{kind:"IntervalQuantization",min:e,max:i,numSteps:r,srcType:s}],data:a}}(n,t,e,i,r)},t.runLength=function(t){let e=lf.getDataType(t);if(void 0===e&&(t=new Int32Array(t),e=lf.IntDataType.Int32),!t.length)return{encodings:[{kind:"RunLength",srcType:e,srcSize:0}],data:new Int32Array(0)};let i=2;for(let e=1,r=t.length;e=0)for(;r>=i;)o[a]=i,++a,r-=i;else for(;r<=n;)o[a]=n,++a,r-=n;o[a]=r,++a}const c=r(o);return{encodings:[{kind:"IntegerPacking",byteCount:e.bytesPerElement,isUnsigned:!e.isSigned,srcSize:s},c.encodings[0]],data:c.data}}(t,e)},t.stringArray=function(t){const e=Object.create(null),i=[],r=new Int32Array(t.length),n=Lf.create(Int32Array,1,Math.min(1024,t.length<32?t.length+1:Math.round(t.length/8)+1));Lf.add(n,0);let s=0,o=0;for(const a of t){if(null==a){r[o++]=-1;continue}let t=e[a];void 0===t&&(s+=a.length,t=i.length,i[t]=a,e[a]=t,Lf.add(n,s)),r[o++]=t}const a=Lf.compact(n),c=Gf(a).encode(a),l=Gf(r).encode(r);return{encodings:[{kind:"StringArray",dataEncoding:l.encoding,stringData:i.join(""),offsetEncoding:c.encoding,offsets:c.data}],data:l.data}}}(Vf||(Vf={}));const qf=function(){const t=[];for(let e=0;e<1024;e++)t[e]=String.fromCharCode(e);return t}();function Wf(t){throw new Error(t)}const Xf="undefined"!=typeof TextDecoder?new TextDecoder:void 0;function Yf(t,e,i){if(Xf){const r=e||i!==t.length?t.subarray(e,e+i):t;return Xf.decode(r)}return function(t,e,i){const r=qf;let n,s=0;const o=[];for(let a=e,c=e+i;a0&&(n[n.length]=o.slice(0,s).join("")),n.join("")):o.slice(0,s).join("")}(t,e,i)}function Kf(t,e){const i={};for(let r=0;rt.name)),getField(t){const r=e[t];if(r)return i[t]||(i[t]=function(t){const e=t.mask?Ff(t.mask):void 0,i=Ff(t.data),r=zd(i),n=r?e?t=>0===e[t]?""+i[t]:"":t=>""+i[t]:e?t=>0===e[t]?i[t]:"":t=>i[t],s=r?t=>i[t]:t=>{const e=i[t];return am(e,0,e.length)},o=r?t=>i[t]:t=>{const e=i[t];return lm(e,0,e.length)},a=e?t=>e[t]:t=>0,c=i.length;return{__array:i,binaryEncoding:t.data.encoding,isDefined:!0,rowCount:c,str:n,int:s,float:o,valueKind:a,areValuesEqual:(t,e)=>i[t]===i[e],toStringArray:t=>Nd(c,n,t),toIntArray:r?t=>Ud(i,t):t=>Nd(c,s,t),toFloatArray:r?t=>Ud(i,t):t=>Nd(c,o,t)}}(r)),i[t]}}}function ip(t){return nf.create("Parse BinaryCIF",(async e=>{const i=[0,3];try{const e=tp({buffer:r=t,offset:0,dataView:new DataView(r.buffer)});if(!function(t,e){for(let i=0;i<2;i++)if(t[i]>e[i])return!1;return!0}(i,e.version.match(/(\d)\.(\d)\.\d/).slice(1).map((t=>+t))))return cf.error(`Unsupported format version. Current ${e.version}, required ${i.join(".")}.`);const n=Lm(e.dataBlocks.map((t=>{const e=Object.create(null);for(const i of t.categories)e[i.name.substr(1)]=ep(i);return Nm(t.categories.map((t=>t.name.substr(1))),e,t.header)})));return cf.success(n)}catch(t){return cf.error(""+t)}var r}))}var rp;function np(t,e,i){return function(t,e,i){const r=Object.create(null);for(const n of Object.keys(t))r[n]=up(n,t[n],e,i);return $m.ofTables(e.header,t,r)}(t,e,i)}function sp(t){switch(t.valueType){case"str":return(e,i,r)=>function(t,e,i,r){return{schema:t,__array:e.__array,isDefined:e.isDefined,rowCount:e.rowCount,value:"lowercase"===t.transform?t=>i(t).toLowerCase():"uppercase"===t.transform?t=>i(t).toUpperCase():i,valueKind:e.valueKind,areValuesEqual:e.areValuesEqual,toArray:"lowercase"===t.transform?t=>Array.from(r(t)).map((t=>t.toLowerCase())):"uppercase"===t.transform?t=>Array.from(r(t)).map((t=>t.toUpperCase())):r}}(t,e,e.str,e.toStringArray);case"int":return(e,i,r)=>op(t,e,e.int,e.toIntArray);case"float":return(e,i,r)=>op(t,e,e.float,e.toFloatArray);case"list":throw new Error("Use createListColumn instead.");case"tensor":throw new Error("Use createTensorColumn instead.")}}function op(t,e,i,r){return{schema:t,__array:e.__array,isDefined:e.isDefined,rowCount:e.rowCount,value:i,valueKind:e.valueKind,areValuesEqual:e.areValuesEqual,toArray:r}}function ap(t,e,i){const r=t.separator,n=t.itemParse,s=e.getField(i),o=s?t=>s.str(t).split(r).map((t=>n(t.trim()))).filter((t=>!!t)):t=>[];return{schema:t,__array:void 0,isDefined:!!s,rowCount:e.rowCount,value:o,valueKind:s?s.valueKind:()=>1,areValuesEqual:(t,e)=>function(t,e){const i=t.length;if(i!==e.length)return!1;for(let r=0;rNd(e.rowCount,o,t)}}function cp(t,e,i){const r=t.space,n=e.fieldNames.includes(`${i}[0]`)||e.fieldNames.includes(`${i}[0][0]`)||e.fieldNames.includes(`${i}[0][0][0]`),s=n?0:1,o=e.fieldNames.includes(`${i}_1`)||e.fieldNames.includes(`${i}_11`)||e.fieldNames.includes(`${i}_111`)?"underscore":"brackets",a=function(t,e,i,r){const n=i?0:1;switch(e){case 1:return"brackets"===r?e=>`${t}[${e+n}]`:e=>`${t}_${e+n}`;case 2:return"brackets"===r?(e,i)=>`${t}[${e+n}][${i+n}]`:(e,i)=>`${t}_${e+n}${i+n}`;case 3:return"brackets"===r?(e,i,r)=>`${t}[${e+n}][${i+n}][${r+n}]`:(e,i,r)=>`${t}_${e+n}${i+n}${r+n}`;default:throw new Error("Tensors with rank > 3 or rank 0 are currently not supported.")}}(i,r.rank,n,o),c=e.getField(a(s,s,s))||nm.Undefined(e.rowCount,t),l=t=>function(t,e,i,r){const n=e.create();if(1===e.rank){const s=e.dimensions[0];for(let o=0;o 3 or rank 0 are currently not supported.");{const s=e.dimensions[0],o=e.dimensions[1],a=e.dimensions[2];for(let c=0;crm.areEqualExact(l(t),l(e)),toArray:t=>Nd(e.rowCount,l,t)}}!function(t){function e(t){return t.replace(".","_").replace(/\[/,"_").replace(/(\[|\])/g,"")}t.canonical=e,t.equal=function(t,i){return e(t)===e(i)},t.create=function(t,i,r=!1){const n=`${t}${i?`.${i}`:""}`;return r?e(n):n}}(rp||(rp={}));class lp{constructor(t,e,i){this._isDefined=i;const r=Object.keys(e);this._rowCount=t.rowCount,this._columns=r,this._schema=e;const n=Object.create(null);for(const i of r)Object.defineProperty(this,i,{get:function(){if(n[i])return n[i];const r=e[i];if("list"===r.valueType)n[i]=ap(r,t,i);else if("tensor"===r.valueType)n[i]=cp(r,t,i);else{const e=sp(r),s=t.getField(i);n[i]=s?e(s,t,i):nm.Undefined(t.rowCount,r)}return n[i]},enumerable:!0,configurable:!1})}}function hp(t,e,i,r){const n=rp.create(e,t),s=rp.canonical(n);if(s in i)return i[s];if(r&&n in r)for(const t of r[n]){const e=rp.canonical(t);if(e in i)return i[e]}}function up(t,e,i,r){let n=i.categories[t];if(r){const s=function(t){const e=Object.create(null);for(const i of Object.keys(t.categories))for(const r of t.categories[i].fieldNames)e[rp.create(i,r,!0)]=t.categories[i].getField(r);return e}(i),o=Object.create(null),a=[];let c=0;for(const i of Object.keys(e)){const e=hp(i,t,s,r);e&&(o[i]=e,a.push(i),c=e.rowCount)}n={rowCount:c,name:t,fieldNames:[...a],getField:t=>o[t]}}return new lp(n||zm.empty(t),e,!!n)}var dp=nm.Schema;const mp=dp.str,fp=dp.int,pp=dp.float,gp=dp.coord,yp=dp.Aliased,bp=dp.Matrix,_p=dp.Vector,xp=dp.lstr,vp=dp.List,wp={atom_site:{auth_asym_id:mp,auth_atom_id:mp,auth_comp_id:mp,auth_seq_id:fp,B_iso_or_equiv:pp,Cartn_x:gp,Cartn_y:gp,Cartn_z:gp,group_PDB:yp(mp),id:fp,label_alt_id:mp,label_asym_id:mp,label_atom_id:mp,label_comp_id:mp,label_entity_id:mp,label_seq_id:fp,occupancy:pp,type_symbol:mp,pdbx_PDB_ins_code:mp,pdbx_PDB_model_num:fp,pdbx_formal_charge:fp,pdbx_label_index:fp,pdbx_sifts_xref_db_name:mp,pdbx_sifts_xref_db_acc:mp,pdbx_sifts_xref_db_num:mp,pdbx_sifts_xref_db_res:mp,ihm_model_id:fp},atom_site_anisotrop:{id:fp,type_symbol:mp,U:bp(3,3),U_esd:bp(3,3),pdbx_auth_seq_id:mp,pdbx_auth_asym_id:mp,pdbx_auth_atom_id:mp,pdbx_auth_comp_id:mp,pdbx_label_seq_id:fp,pdbx_label_alt_id:mp,pdbx_label_asym_id:mp,pdbx_label_atom_id:mp,pdbx_label_comp_id:mp,pdbx_PDB_ins_code:mp},atom_sites:{entry_id:mp,fract_transf_matrix:bp(3,3),fract_transf_vector:_p(3)},audit_author:{name:mp,pdbx_ordinal:fp,identifier_ORCID:mp},audit_conform:{dict_location:mp,dict_name:mp,dict_version:mp},cell:{angle_alpha:pp,angle_beta:pp,angle_gamma:pp,entry_id:mp,length_a:pp,length_b:pp,length_c:pp,Z_PDB:fp,pdbx_unique_axis:mp},chem_comp:{formula:mp,formula_weight:pp,id:mp,mon_nstd_flag:yp(xp),name:mp,type:yp(xp),pdbx_synonyms:vp(";",(t=>t))},chem_comp_bond:{atom_id_1:mp,atom_id_2:mp,comp_id:mp,value_order:yp(xp),pdbx_ordinal:fp,pdbx_stereo_config:yp(xp),pdbx_aromatic_flag:yp(xp)},citation:{book_publisher:mp,country:mp,id:mp,journal_abbrev:mp,journal_id_ASTM:mp,journal_id_CSD:mp,journal_id_ISSN:mp,journal_volume:mp,page_first:mp,page_last:mp,title:mp,year:fp,pdbx_database_id_DOI:mp,pdbx_database_id_PubMed:fp},citation_author:{citation_id:mp,name:mp,ordinal:fp},database_2:{database_id:yp(xp),database_code:mp},entity:{details:mp,formula_weight:pp,id:mp,src_method:yp(xp),type:yp(xp),pdbx_description:vp(",",(t=>t)),pdbx_number_of_molecules:fp,pdbx_mutation:mp,pdbx_fragment:mp,pdbx_ec:vp(",",(t=>t))},entity_poly:{entity_id:mp,nstd_linkage:yp(xp),nstd_monomer:yp(xp),type:yp(mp),pdbx_strand_id:vp(",",(t=>t)),pdbx_seq_one_letter_code:mp,pdbx_seq_one_letter_code_can:mp,pdbx_target_identifier:mp},entity_poly_seq:{entity_id:mp,hetero:yp(xp),mon_id:mp,num:fp},entry:{id:mp},exptl:{entry_id:mp,method:yp(mp)},software:{classification:mp,date:mp,description:mp,name:mp,type:yp(xp),version:mp,pdbx_ordinal:fp},struct:{entry_id:mp,title:mp,pdbx_descriptor:mp},struct_asym:{details:mp,entity_id:mp,id:mp,pdbx_modified:mp,pdbx_blank_PDB_chainid_flag:yp(mp)},struct_conf:{beg_label_asym_id:mp,beg_label_comp_id:mp,beg_label_seq_id:fp,beg_auth_asym_id:mp,beg_auth_comp_id:mp,beg_auth_seq_id:fp,conf_type_id:yp(xp),details:mp,end_label_asym_id:mp,end_label_comp_id:mp,end_label_seq_id:fp,end_auth_asym_id:mp,end_auth_comp_id:mp,end_auth_seq_id:fp,id:mp,pdbx_beg_PDB_ins_code:mp,pdbx_end_PDB_ins_code:mp,pdbx_PDB_helix_class:mp,pdbx_PDB_helix_length:fp,pdbx_PDB_helix_id:mp},struct_conn:{conn_type_id:yp(xp),details:mp,id:mp,ptnr1_label_asym_id:mp,ptnr1_label_atom_id:mp,ptnr1_label_comp_id:mp,ptnr1_label_seq_id:fp,ptnr1_auth_asym_id:mp,ptnr1_auth_comp_id:mp,ptnr1_auth_seq_id:fp,ptnr1_symmetry:mp,ptnr2_label_asym_id:mp,ptnr2_label_atom_id:mp,ptnr2_label_comp_id:mp,ptnr2_label_seq_id:fp,ptnr2_auth_asym_id:mp,ptnr2_auth_comp_id:mp,ptnr2_auth_seq_id:fp,ptnr2_symmetry:mp,pdbx_ptnr1_PDB_ins_code:mp,pdbx_ptnr1_label_alt_id:mp,pdbx_ptnr1_standard_comp_id:mp,pdbx_ptnr2_PDB_ins_code:mp,pdbx_ptnr2_label_alt_id:mp,pdbx_ptnr3_PDB_ins_code:mp,pdbx_ptnr3_label_alt_id:mp,pdbx_ptnr3_label_asym_id:mp,pdbx_ptnr3_label_atom_id:mp,pdbx_ptnr3_label_comp_id:mp,pdbx_ptnr3_label_seq_id:fp,pdbx_PDB_id:mp,pdbx_dist_value:pp,pdbx_value_order:yp(xp)},struct_conn_type:{criteria:mp,id:yp(xp),reference:mp},struct_keywords:{entry_id:mp,text:vp(",",(t=>t)),pdbx_keywords:mp},struct_ncs_oper:{code:yp(mp),details:mp,id:fp,matrix:bp(3,3),vector:_p(3)},struct_sheet_range:{beg_label_asym_id:mp,beg_label_comp_id:mp,beg_label_seq_id:fp,end_label_asym_id:mp,end_label_comp_id:mp,end_label_seq_id:fp,beg_auth_asym_id:mp,beg_auth_comp_id:mp,beg_auth_seq_id:fp,end_auth_asym_id:mp,end_auth_comp_id:mp,end_auth_seq_id:fp,id:mp,sheet_id:mp,pdbx_beg_PDB_ins_code:mp,pdbx_end_PDB_ins_code:mp},struct_site:{details:mp,id:mp,pdbx_num_residues:fp,pdbx_evidence_code:mp,pdbx_auth_asym_id:mp,pdbx_auth_comp_id:mp,pdbx_auth_seq_id:mp,pdbx_auth_ins_code:mp},struct_site_gen:{details:mp,id:mp,label_alt_id:mp,label_asym_id:mp,label_atom_id:mp,label_comp_id:mp,label_seq_id:fp,auth_asym_id:mp,auth_comp_id:mp,auth_seq_id:mp,site_id:mp,symmetry:mp,pdbx_auth_ins_code:mp,pdbx_num_res:fp},symmetry:{entry_id:mp,cell_setting:yp(xp),Int_Tables_number:fp,space_group_name_Hall:mp,"space_group_name_H-M":mp},pdbx_database_status:{status_code:yp(mp),status_code_sf:yp(mp),status_code_mr:yp(mp),entry_id:mp,recvd_initial_deposition_date:mp,SG_entry:yp(xp),deposit_site:yp(mp),process_site:yp(mp),status_code_cs:yp(mp),methods_development_category:yp(mp),pdb_format_compatible:yp(xp)},pdbx_nonpoly_scheme:{asym_id:mp,entity_id:mp,mon_id:mp,pdb_strand_id:mp,ndb_seq_num:mp,pdb_seq_num:mp,auth_seq_num:mp,pdb_mon_id:mp,auth_mon_id:mp,pdb_ins_code:mp},pdbx_database_related:{db_name:mp,details:mp,db_id:mp,content_type:yp(mp)},pdbx_entity_nonpoly:{entity_id:mp,comp_id:mp,name:mp},pdbx_chem_comp_synonyms:{name:mp,comp_id:mp,provenance:yp(mp)},pdbx_chem_comp_identifier:{comp_id:mp,identifier:mp,type:yp(mp),program:mp,program_version:mp},pdbx_unobs_or_zero_occ_residues:{id:fp,polymer_flag:yp(xp),occupancy_flag:yp(fp),PDB_model_num:fp,auth_asym_id:mp,auth_comp_id:mp,auth_seq_id:mp,PDB_ins_code:mp,label_asym_id:mp,label_comp_id:mp,label_seq_id:fp},pdbx_struct_mod_residue:{id:fp,auth_asym_id:mp,auth_comp_id:mp,auth_seq_id:fp,PDB_ins_code:mp,label_asym_id:mp,label_comp_id:mp,label_seq_id:fp,parent_comp_id:mp,details:mp},pdbx_struct_oper_list:{id:mp,type:yp(mp),name:mp,symmetry_operation:mp,matrix:bp(3,3),vector:_p(3)},pdbx_struct_assembly:{method_details:mp,oligomeric_details:mp,oligomeric_count:fp,details:mp,id:mp},pdbx_struct_assembly_gen:{asym_id_list:vp(",",(t=>t)),assembly_id:mp,oper_expression:mp},pdbx_reference_entity_list:{prd_id:mp,ref_entity_id:mp,type:yp(xp),details:mp,component_id:fp},pdbx_reference_entity_link:{link_id:fp,prd_id:mp,details:mp,ref_entity_id_1:mp,ref_entity_id_2:mp,entity_seq_num_1:fp,entity_seq_num_2:fp,comp_id_1:mp,comp_id_2:mp,atom_id_1:mp,atom_id_2:mp,value_order:yp(xp),component_1:fp,component_2:fp,link_class:yp(mp)},pdbx_reference_entity_poly_link:{link_id:fp,prd_id:mp,ref_entity_id:mp,component_id:fp,entity_seq_num_1:fp,entity_seq_num_2:fp,comp_id_1:mp,comp_id_2:mp,atom_id_1:mp,atom_id_2:mp,value_order:yp(xp)},pdbx_molecule:{prd_id:mp,instance_id:fp,asym_id:mp},pdbx_molecule_features:{prd_id:mp,class:yp(xp),type:yp(xp),name:mp,details:mp},entity_src_nat:{entity_id:mp,pdbx_organism_scientific:mp,pdbx_plasmid_name:mp,pdbx_src_id:fp,pdbx_beg_seq_num:fp,pdbx_end_seq_num:fp},entity_src_gen:{entity_id:mp,pdbx_gene_src_gene:vp(",",(t=>t)),pdbx_gene_src_scientific_name:mp,plasmid_name:mp,pdbx_src_id:fp,pdbx_beg_seq_num:fp,pdbx_end_seq_num:fp},pdbx_entity_src_syn:{organism_scientific:mp,entity_id:mp,pdbx_src_id:fp,pdbx_beg_seq_num:fp,pdbx_end_seq_num:fp},pdbx_entity_branch_descriptor:{entity_id:mp,descriptor:mp,type:yp(xp),program:mp,program_version:mp,ordinal:fp},pdbx_entity_instance_feature:{details:mp,feature_type:yp(mp),auth_asym_id:mp,asym_id:mp,auth_seq_num:mp,seq_num:fp,comp_id:mp,auth_comp_id:mp,ordinal:fp},pdbx_entity_branch_list:{entity_id:mp,hetero:yp(xp),comp_id:mp,num:fp},pdbx_entity_branch_link:{link_id:fp,details:mp,entity_id:mp,entity_branch_list_num_1:fp,entity_branch_list_num_2:fp,comp_id_1:mp,comp_id_2:mp,atom_id_1:mp,leaving_atom_id_1:mp,atom_stereo_config_1:yp(xp),atom_id_2:mp,leaving_atom_id_2:mp,atom_stereo_config_2:yp(xp),value_order:yp(xp)},pdbx_entity_branch:{entity_id:mp,type:yp(mp)},pdbx_branch_scheme:{entity_id:mp,hetero:yp(xp),asym_id:mp,mon_id:mp,num:fp,pdb_asym_id:mp,pdb_seq_num:mp,pdb_mon_id:mp,auth_asym_id:mp,auth_seq_num:mp,auth_mon_id:mp},pdbx_chem_comp_related:{comp_id:mp,related_comp_id:mp,relationship_type:yp(mp),details:mp},ihm_starting_model_details:{starting_model_id:mp,entity_id:mp,entity_description:mp,asym_id:mp,entity_poly_segment_id:fp,starting_model_source:yp(mp),starting_model_auth_asym_id:mp,starting_model_sequence_offset:fp,dataset_list_id:fp},ihm_starting_comparative_models:{id:fp,starting_model_id:mp,starting_model_auth_asym_id:mp,starting_model_seq_id_begin:fp,starting_model_seq_id_end:fp,template_auth_asym_id:mp,template_seq_id_begin:fp,template_seq_id_end:fp,template_sequence_identity:pp,template_sequence_identity_denominator:yp(fp),template_dataset_list_id:fp,alignment_file_id:fp},ihm_starting_model_seq_dif:{id:fp,entity_id:mp,asym_id:mp,seq_id:fp,comp_id:mp,starting_model_id:mp,db_asym_id:mp,db_seq_id:fp,db_comp_id:mp,details:mp},ihm_model_representation:{id:fp,name:mp,details:mp},ihm_model_representation_details:{id:fp,representation_id:fp,entity_poly_segment_id:fp,entity_id:mp,entity_description:mp,entity_asym_id:mp,model_object_primitive:yp(mp),starting_model_id:mp,model_mode:yp(mp),model_granularity:yp(mp),model_object_count:fp},ihm_struct_assembly_details:{id:fp,assembly_id:fp,parent_assembly_id:fp,entity_description:mp,entity_id:mp,asym_id:mp,entity_poly_segment_id:fp},ihm_struct_assembly:{id:fp,name:mp,description:mp},ihm_modeling_protocol:{id:fp,num_steps:fp,protocol_name:mp},ihm_modeling_protocol_details:{id:fp,protocol_id:fp,step_id:fp,struct_assembly_id:fp,dataset_group_id:fp,struct_assembly_description:mp,step_name:mp,step_method:mp,num_models_begin:fp,num_models_end:fp,multi_scale_flag:yp(xp),multi_state_flag:yp(xp),ordered_flag:yp(xp),script_file_id:fp,software_id:fp},ihm_multi_state_modeling:{state_id:fp,state_group_id:fp,population_fraction:pp,population_fraction_sd:pp,state_type:mp,state_name:mp,experiment_type:yp(mp),details:mp},ihm_modeling_post_process:{id:fp,protocol_id:fp,analysis_id:fp,step_id:fp,type:yp(mp),feature:yp(mp),num_models_begin:fp,num_models_end:fp},ihm_ensemble_info:{ensemble_id:fp,ensemble_name:mp,post_process_id:fp,model_group_id:fp,ensemble_clustering_method:yp(mp),ensemble_clustering_feature:yp(mp),num_ensemble_models:fp,num_ensemble_models_deposited:fp,ensemble_precision_value:pp,ensemble_file_id:fp},ihm_model_list:{model_id:fp,model_name:mp,assembly_id:fp,protocol_id:fp,representation_id:fp},ihm_model_group:{id:fp,name:mp,details:mp},ihm_model_group_link:{model_id:fp,group_id:fp},ihm_model_representative:{id:fp,model_group_id:fp,model_id:fp,selection_criteria:yp(mp)},ihm_dataset_list:{id:fp,data_type:yp(mp),database_hosted:yp(xp)},ihm_dataset_group:{id:fp,name:mp,application:yp(mp),details:mp},ihm_dataset_group_link:{dataset_list_id:fp,group_id:fp},ihm_related_datasets:{dataset_list_id_derived:fp,dataset_list_id_primary:fp},ihm_dataset_related_db_reference:{id:fp,dataset_list_id:fp,db_name:yp(mp),accession_code:mp,version:mp,details:mp},ihm_external_reference_info:{reference_id:fp,reference_provider:mp,reference_type:yp(mp),reference:mp,refers_to:yp(mp),associated_url:mp},ihm_external_files:{id:fp,reference_id:fp,file_path:mp,content_type:yp(mp),file_size_bytes:pp,details:mp},ihm_dataset_external_reference:{id:fp,dataset_list_id:fp,file_id:fp},ihm_localization_density_files:{id:fp,file_id:fp,ensemble_id:fp,entity_id:mp,entity_poly_segment_id:fp,asym_id:mp},ihm_predicted_contact_restraint:{id:fp,group_id:fp,entity_id_1:mp,entity_id_2:mp,asym_id_1:mp,asym_id_2:mp,comp_id_1:mp,comp_id_2:mp,seq_id_1:fp,seq_id_2:fp,rep_atom_1:yp(mp),rep_atom_2:yp(mp),distance_lower_limit:pp,distance_upper_limit:pp,probability:pp,restraint_type:yp(mp),model_granularity:yp(mp),dataset_list_id:fp,software_id:fp},ihm_cross_link_list:{id:fp,group_id:fp,entity_description_1:mp,entity_description_2:mp,entity_id_1:mp,entity_id_2:mp,comp_id_1:mp,comp_id_2:mp,seq_id_1:fp,seq_id_2:fp,linker_type:yp(mp),dataset_list_id:fp},ihm_cross_link_restraint:{id:fp,group_id:fp,entity_id_1:mp,entity_id_2:mp,asym_id_1:mp,asym_id_2:mp,comp_id_1:mp,comp_id_2:mp,seq_id_1:fp,seq_id_2:fp,atom_id_1:mp,atom_id_2:mp,restraint_type:yp(mp),conditional_crosslink_flag:yp(mp),model_granularity:yp(mp),distance_threshold:pp,psi:pp,sigma_1:pp,sigma_2:pp},ihm_cross_link_result_parameters:{id:fp,restraint_id:fp,model_id:fp,psi:pp,sigma_1:pp,sigma_2:pp},ihm_2dem_class_average_restraint:{id:fp,dataset_list_id:fp,number_raw_micrographs:fp,pixel_size_width:pp,pixel_size_height:pp,image_resolution:pp,image_segment_flag:yp(xp),number_of_projections:fp,struct_assembly_id:fp,details:mp},ihm_2dem_class_average_fitting:{id:fp,restraint_id:fp,model_id:fp,cross_correlation_coefficient:pp,rot_matrix:bp(3,3),tr_vector:_p(3)},ihm_3dem_restraint:{id:fp,dataset_list_id:fp,model_id:fp,struct_assembly_id:fp,fitting_method:mp,number_of_gaussians:fp,cross_correlation_coefficient:pp},ihm_sas_restraint:{id:fp,dataset_list_id:fp,model_id:fp,struct_assembly_id:fp,profile_segment_flag:yp(xp),fitting_atom_type:mp,fitting_method:mp,fitting_state:yp(mp),radius_of_gyration:pp,chi_value:pp,details:mp},ihm_starting_model_coord:{ordinal_id:fp,starting_model_id:mp,group_PDB:yp(mp),id:fp,type_symbol:mp,entity_id:mp,atom_id:mp,comp_id:mp,seq_id:fp,asym_id:mp,Cartn_x:pp,Cartn_y:pp,Cartn_z:pp,B_iso_or_equiv:pp},ihm_sphere_obj_site:{id:fp,entity_id:mp,seq_id_begin:fp,seq_id_end:fp,asym_id:mp,Cartn_x:pp,Cartn_y:pp,Cartn_z:pp,object_radius:pp,rmsf:pp,model_id:fp},ihm_gaussian_obj_site:{id:fp,entity_id:mp,seq_id_begin:fp,seq_id_end:fp,asym_id:mp,mean_Cartn_x:pp,mean_Cartn_y:pp,mean_Cartn_z:pp,weight:pp,covariance_matrix:bp(3,3),model_id:fp},ihm_gaussian_obj_ensemble:{id:fp,entity_id:mp,seq_id_begin:fp,seq_id_end:fp,asym_id:mp,mean_Cartn_x:pp,mean_Cartn_y:pp,mean_Cartn_z:pp,weight:pp,covariance_matrix:bp(3,3),ensemble_id:fp},ihm_feature_list:{feature_id:fp,feature_type:yp(mp),entity_type:yp(mp)},ihm_poly_residue_feature:{ordinal_id:fp,feature_id:fp,entity_id:mp,asym_id:mp,comp_id_begin:mp,comp_id_end:mp,seq_id_begin:fp,seq_id_end:fp},ihm_derived_distance_restraint:{id:fp,group_id:fp,feature_id_1:fp,feature_id_2:fp,group_conditionality:yp(mp),random_exclusion_fraction:pp,distance_upper_limit:pp,restraint_type:yp(mp),dataset_list_id:fp},ma_model_list:{ordinal_id:fp,model_id:fp,model_group_id:fp,model_name:mp,model_group_name:mp,model_type:yp(mp),data_id:fp},ma_target_entity:{entity_id:mp,data_id:fp,origin:yp(mp)},ma_target_entity_instance:{asym_id:mp,entity_id:mp,details:mp},ma_target_ref_db_details:{target_entity_id:mp,db_name:yp(mp),db_code:mp,db_accession:mp,seq_db_isoform:mp,seq_db_align_begin:mp,seq_db_align_end:mp,ncbi_taxonomy_id:mp,organism_scientific:mp},ma_data:{id:fp,content_type:yp(mp),content_type_other_details:mp,name:mp},ma_software_group:{ordinal_id:fp,group_id:fp,software_id:fp},ma_qa_metric:{id:fp,name:mp,type:yp(mp),mode:yp(mp),software_group_id:fp},ma_qa_metric_global:{ordinal_id:fp,model_id:fp,metric_id:fp,metric_value:pp},ma_qa_metric_local:{ordinal_id:fp,model_id:fp,label_asym_id:mp,label_seq_id:fp,label_comp_id:mp,metric_id:fp,metric_value:pp}};var Ap=nm.Schema;const Sp=Ap.str,Cp=Ap.float,Pp=Ap.List,Ip=Ap.lstr,kp=Ap.Aliased,Mp=Ap.int,Tp=Ap.coord,Dp={chem_comp:{formula:Sp,formula_weight:Cp,id:Sp,mon_nstd_parent_comp_id:Pp(",",(t=>t)),name:Sp,one_letter_code:Sp,three_letter_code:Sp,type:kp(Ip),pdbx_synonyms:Pp(";",(t=>t)),pdbx_type:Sp,pdbx_ambiguous_flag:Sp,pdbx_replaced_by:Sp,pdbx_replaces:Sp,pdbx_formal_charge:Mp,pdbx_model_coordinates_details:Sp,pdbx_model_coordinates_db_code:Sp,pdbx_ideal_coordinates_details:Sp,pdbx_ideal_coordinates_missing_flag:kp(Ip),pdbx_model_coordinates_missing_flag:kp(Ip),pdbx_initial_date:Sp,pdbx_modified_date:Sp,pdbx_release_status:kp(Sp),pdbx_processing_site:kp(Sp)},chem_comp_atom:{alt_atom_id:Sp,atom_id:Sp,charge:Mp,model_Cartn_x:Tp,model_Cartn_y:Tp,model_Cartn_z:Tp,comp_id:Sp,type_symbol:Sp,pdbx_align:Mp,pdbx_ordinal:Mp,pdbx_model_Cartn_x_ideal:Tp,pdbx_model_Cartn_y_ideal:Tp,pdbx_model_Cartn_z_ideal:Tp,pdbx_stereo_config:kp(Ip),pdbx_aromatic_flag:kp(Ip),pdbx_leaving_atom_flag:kp(Ip)},chem_comp_bond:{atom_id_1:Sp,atom_id_2:Sp,comp_id:Sp,value_order:kp(Ip),pdbx_ordinal:Mp,pdbx_stereo_config:kp(Ip),pdbx_aromatic_flag:kp(Ip)},pdbx_chem_comp_descriptor:{comp_id:Sp,descriptor:Sp,type:kp(Ip),program:Sp,program_version:Sp},pdbx_chem_comp_identifier:{comp_id:Sp,identifier:Sp,type:kp(Sp),program:Sp,program_version:Sp}};var Bp=nm.Schema;const Fp=Bp.str,Ep=Bp.float,$p=Bp.lstr,Op=Bp.Aliased,Rp=Bp.int,Lp={pdbx_reference_molecule:{prd_id:Fp,formula_weight:Ep,formula:Fp,type:Op($p),type_evidence_code:Fp,class:Op($p),class_evidence_code:Fp,name:Fp,represent_as:Op($p),chem_comp_id:Fp,compound_details:Fp,description:Fp,representative_PDB_id_code:Fp,release_status:Op($p),replaces:Fp,replaced_by:Fp},pdbx_reference_entity_list:{prd_id:Fp,ref_entity_id:Fp,type:Op($p),details:Fp,component_id:Rp},pdbx_reference_entity_nonpoly:{prd_id:Fp,ref_entity_id:Fp,name:Fp,chem_comp_id:Fp},pdbx_reference_entity_link:{link_id:Rp,prd_id:Fp,details:Fp,ref_entity_id_1:Fp,ref_entity_id_2:Fp,entity_seq_num_1:Rp,entity_seq_num_2:Rp,comp_id_1:Fp,comp_id_2:Fp,atom_id_1:Fp,atom_id_2:Fp,value_order:Op($p),component_1:Rp,component_2:Rp,link_class:Op(Fp)},pdbx_reference_entity_poly_link:{link_id:Rp,prd_id:Fp,ref_entity_id:Fp,component_id:Rp,entity_seq_num_1:Rp,entity_seq_num_2:Rp,comp_id_1:Fp,comp_id_2:Fp,atom_id_1:Fp,atom_id_2:Fp,value_order:Op($p)},pdbx_reference_entity_poly:{prd_id:Fp,ref_entity_id:Fp,type:Op(Fp),db_code:Fp,db_name:Fp},pdbx_reference_entity_poly_seq:{prd_id:Fp,ref_entity_id:Fp,mon_id:Fp,parent_mon_id:Fp,num:Rp,observed:Op($p),hetero:Op($p)},pdbx_reference_entity_sequence:{prd_id:Fp,ref_entity_id:Fp,type:Op(Fp),NRP_flag:Op(Fp),one_letter_codes:Fp},pdbx_reference_entity_src_nat:{prd_id:Fp,ref_entity_id:Fp,ordinal:Rp,organism_scientific:Fp,taxid:Fp,db_code:Fp,db_name:Fp},pdbx_prd_audit:{prd_id:Fp,date:Fp,processing_site:Op(Fp),action_type:Op(Fp)}};var Np=nm.Schema;const zp=Np.str,Up={datablock:{id:zp,description:zp},dictionary:{title:zp,datablock_id:zp,version:zp},dictionary_history:{version:zp,update:zp,revision:zp},sub_category:{id:zp,description:zp},category_group_list:{id:zp,parent_id:zp,description:zp},item_type_list:{code:zp,primitive_code:zp,construct:zp,detail:zp},item_units_list:{code:zp,detail:zp},item_units_conversion:{from_code:zp,to_code:zp,operator:zp,factor:Np.float}};var Vp=nm.Schema;const jp=Vp.str,Gp=Vp.int,Hp=Vp.float,qp=Vp.Aliased,Wp=Vp.Vector;qp(jp),qp(jp),qp(jp),qp(jp),Wp(3),Wp(3);const Xp={volume_data_3d_info:{name:jp,axis_order:Wp(3,Gp),origin:Wp(3),dimensions:Wp(3),sample_rate:Gp,sample_count:Wp(3,Gp),spacegroup_number:Gp,spacegroup_cell_size:Wp(3),spacegroup_cell_angles:Wp(3),mean_source:Hp,mean_sampled:Hp,sigma_source:Hp,sigma_sampled:Hp,min_source:Hp,min_sampled:Hp,max_source:Hp,max_sampled:Hp},volume_data_3d:{values:Hp}};var Yp=nm.Schema;const Kp=Yp.float,Zp=Yp.int,Qp=Yp.str,Jp={cell:{angle_alpha:Kp,angle_beta:Kp,angle_gamma:Kp,formula_units_z:Zp,length_a:Kp,length_b:Kp,length_c:Kp,volume:Kp},chemical:{melting_point:Kp,name_common:Qp,name_systematic:Qp},chemical_formula:{moiety:Qp,sum:Qp,weight:Kp},space_group:{crystal_system:Qp,it_number:Zp,"name_h-m_full":Qp},space_group_symop:{operation_xyz:Qp},geom_bond:{atom_site_label_1:Qp,atom_site_label_2:Qp,distance:Kp,publ_flag:Qp,site_symmetry_1:Qp,site_symmetry_2:Qp,valence:Kp},audit:{block_doi:Qp},database_code:{cod:Qp,csd:Qp,depnum_ccdc_archive:Qp,depnum_ccdc_fiz:Qp,icsd:Qp,mdf:Qp,nbs:Qp},atom_site:{adp_type:Qp,calc_flag:Qp,disorder_assembly:Qp,disorder_group:Qp,fract_x:Kp,fract_y:Kp,fract_z:Kp,label:Qp,occupancy:Kp,refinement_flags:Qp,site_symmetry_multiplicity:Zp,type_symbol:Qp,u_iso_or_equiv:Kp},atom_site_aniso:{label:Qp,u_11:Kp,u:(0,Yp.Matrix)(3,3),u_12:Kp,u_13:Kp,u_22:Kp,u_23:Kp,u_33:Kp},atom_type:{description:Qp,symbol:Qp},atom_type_scat:{dispersion_imag:Kp,dispersion_real:Kp,source:Qp}},tg={"cell.formula_units_z":["cell_formula_units_Z"],"space_group.it_number":["space_group_IT_number","symmetry_Int_Tables_number"],"space_group.name_h-m_full":["symmetry_space_group_name_H-M"],"space_group_symop.operation_xyz":["symmetry_equiv_pos_as_xyz"],"geom_bond.atom_site_label_1":["geom_bond_atom_site_id_1"],"geom_bond.atom_site_label_2":["geom_bond_atom_site_id_2"],"geom_bond.distance":["geom_bond_dist"],"audit.block_doi":["audit_block_DOI"],"database_code.cod":["database_code_COD"],"database_code.csd":["database_code_CSD"],"database_code.depnum_ccdc_archive":["database_code_depnum_CCDC_archive"],"database_code.depnum_ccdc_fiz":["database_code_depnum_CCDC_fiz"],"database_code.icsd":["database_code_ICSD"],"database_code.mdf":["database_code_MDF"],"database_code.nbs":["database_code_NBS"],"atom_site.adp_type":["atom_site_ADP_type","atom_site_thermal_displace_type"],"atom_site.label":["atom_site_id"],"atom_site.site_symmetry_multiplicity":["atom_site_symmetry_multiplicity"],"atom_site.u_iso_or_equiv":["atom_site_U_iso_or_equiv"],"atom_site_aniso.label":["atom_site_anisotrop_id"],"atom_site_aniso.u_11":["atom_site_aniso_U_11","atom_site_anisotrop_U_11"],"atom_site_aniso.u_12":["atom_site_aniso_U_12","atom_site_anisotrop_U_12"],"atom_site_aniso.u_13":["atom_site_aniso_U_13","atom_site_anisotrop_U_13"],"atom_site_aniso.u_22":["atom_site_aniso_U_22","atom_site_anisotrop_U_22"],"atom_site_aniso.u_23":["atom_site_aniso_U_23","atom_site_anisotrop_U_23"],"atom_site_aniso.u_33":["atom_site_aniso_U_33","atom_site_anisotrop_U_33"]};const eg=nm.Schema.int,ig={volume_data_3d_info:Xp.volume_data_3d_info,segmentation_data_table:{set_id:eg,segment_id:eg},segmentation_data_3d:{values:eg}},rg={parse:t=>"string"==typeof t?Df(t):ip(t),parseText:Df,parseBinary:ip,toDatabaseCollection:function(t,e,i){const r={};for(const n of e.blocks)r[n.header]=np(t,n,i);return r},toDatabase:np,schema:{mmCIF:t=>np(wp,t),CCD:t=>np(Dp,t),BIRD:t=>np(Lp,t),dic:t=>np(Up,t),cifCore:t=>np(Jp,t,tg),densityServer:t=>np(Xp,t),segmentation:t=>np(ig,t)}};class ng{constructor(t,e){var i=e||{};this.streamer=t,this.name=rt(i.name,""),this.path=rt(i.path,"")}get type(){return""}get __objName(){return""}get isBinary(){return!1}get isJson(){return!1}get isXml(){return!1}parse(){return this.streamer.read().then((()=>Ll(this,void 0,void 0,(function*(){return yield this._beforeParse(),yield this._parse(),yield this._afterParse(),this[this.__objName]}))))}_parse(){}_beforeParse(){}_afterParse(){Te&&Ie.log(this[this.__objName])}}class sg extends ng{constructor(t,e){var i=e||{};super(t,i),this.firstModelOnly=rt(i.firstModelOnly,!1),this.asTrajectory=rt(i.asTrajectory,!1),this.cAlphaOnly=rt(i.cAlphaOnly,!1),this.structure=new Ac(this.name,this.path),this.structureBuilder=new La(this.structure)}get type(){return"structure"}get __objName(){return"structure"}}class og{constructor(t,e,i="",r,n=[]){this.structure=t,this.index=e,this.description=i,this.entityType=function(t){switch(t=t.toLowerCase()){case"polymer":return 1;case"non-polymer":return 2;case"macrolide":return 3;case"water":return 4;default:return 0}}(r||""),this.chainIndexList=n,n.forEach((function(i){t.chainStore.entityIndex[i]=e}))}get type(){return function(t){switch(t){case 1:return"polymer";case 2:return"non-polymer";case 3:return"macrolide";case 4:return"water";default:return}}(this.entityType)}getEntityType(){return this.entityType}isPolymer(){return 1===this.entityType}isNonPolymer(){return 2===this.entityType}isMacrolide(){return 3===this.entityType}isWater(){return 4===this.entityType}eachChain(t){const e=this.structure.getChainProxy();this.chainIndexList.forEach((function(i){e.index=i,t(e)}))}}const ag={a:1,b:1,c:1,alpha:90,beta:90,gamma:90,spacegroup:"P 1"};class cg{constructor(t=ag){this.cartToFrac=new i,this.fracToCart=new i,this.a=t.a,this.b=t.b,this.c=t.c,this.alpha=t.alpha,this.beta=t.beta,this.gamma=t.gamma,this.spacegroup=t.spacegroup;const e=Pt(this.alpha),r=Pt(this.beta),n=Pt(this.gamma),s=Math.cos(e),o=Math.cos(r),a=Math.cos(n),c=Math.sin(r),l=Math.sin(n);if(this.volume=this.a*this.b*this.c*Math.sqrt(1-s*s-o*o-a*a+2*s*o*a),void 0===t.cartToFrac){const t=this.a*this.b*l/this.volume,e=(o*a-s)/(c*l);this.fracToCart.set(this.a,0,0,0,this.b*a,this.b*l,0,0,this.c*o,-this.c*c*e,1/t,0,0,0,0,1).transpose(),this.cartToFrac.copy(this.fracToCart).invert()}else this.cartToFrac.copy(t.cartToFrac),this.fracToCart.copy(this.cartToFrac).invert()}getPosition(t){const i=new Float32Array(24);if(t.unitcell){const r=t.unitcell,n=t.center.clone().applyMatrix4(r.cartToFrac).floor(),s=new e;let o=0;const a=function(t,e,a){s.set(t,e,a).add(n).applyMatrix4(r.fracToCart).toArray(i,o),o+=3};a(0,0,0),a(1,0,0),a(0,1,0),a(0,0,1),a(1,1,0),a(1,0,1),a(0,1,1),a(1,1,1)}return i}getCenter(t){return function(t,i=new e){const r=t.length;for(let e=0;e0)continue;let e,i,r,n,a,g=0;if(s){if(n=S.split(dg),g=10===n.length?1:0,B=n[2],f&&"CA"!==B)continue;e=parseFloat(n[6-g]),i=parseFloat(n[7-g]),r=parseFloat(n[8-g])}else{if(B=S.substr(12,4).trim(),f&&"CA"!==B)continue;e=parseFloat(S.substr(30,8)),i=parseFloat(S.substr(38,8)),r=parseFloat(S.substr(46,8))}if(m){const t=3*b;if(y[t+0]=e,y[t+1]=i,y[t+2]=r,b+=1,_)continue}s?(P=parseInt(n[1]),a="",F="H"===S[0],I=g?"":n[4],k=parseInt(n[5-g]),D="",M=n[3],$="",T=1):(P=parseInt(S.substr(6,5),h),l&&99999===P&&(h=16),F="H"===S[0],I=S[21].trim(),k=parseInt(S.substr(22,4),u),l&&9999===k&&(u=16),D=S[26].trim(),M=S.substr(17,4).trim()||"MOL",E=parseFloat(S.substr(60,6)),$=S[16].trim(),T=parseFloat(S.substr(54,6)),t||(o?(a=S.substr(76,3).trim(),a in ds&&(a=ds[a])):(a=S.substr(76,2).trim(),I||(I=S.substr(72,4).trim())),O=parseInt((S.substr(79,1)+S.substr(78,1)).trim()))),ut.growIfFull(),ut.atomTypeId[ft]=ht.add(B,a),ut.x[ft]=e,ut.y[ft]=i,ut.z[ft]=r,ut.serial[ft]=P,ut.altloc[ft]=$.charCodeAt(0),ut.occupancy[ft]=isNaN(T)?0:T,s?(ut.partialCharge[ft]=parseFloat(n[9-g]),ut.radius[ft]=parseFloat(n[10-g])):(ut.bfactor[ft]=isNaN(E)?0:E,o&&(ut.partialCharge[ft]=parseFloat(S.substr(70,6))),isFinite(O)&&(ut.formalCharge||ut.addField("formalCharge",1,"int8"),ut.formalCharge[ft]=O));const x=mg(k,I,D);!F||K[x]||hg.includes(M)?tt||et===I||(Q+=1,J=Q.toString()):et===I&&rt===M&&(os.includes(M)||it===k&&nt===D)||(Q+=1,J=Q.toString(),it=k,rt=M,nt=D),c.addAtom(pt,I,J,M,k,F,void 0,D),j[P]=ft,ft+=1,tt=!1,et=I}else if("CONECT"===C){const t=j[parseInt(S.substr(6,5))],e=[11,16,21,26],i={};if(void 0===t)continue;for(let r=0;r<4;++r){let n=parseInt(S.substr(e[r],5));if(!Number.isNaN(n)&&(n=j[n],void 0!==n))if(t{var i;return[null===(i=n.get(t))||void 0===i?void 0:i.atomname,e]}))),o=[],a=[],c=[];let l,h;for(let t=0;t{var b;const _=c.getField(f),x=c.getField(p),v=c.getField(g),w=y*o;for(let c=0;cc*c)return a.growIfFull(),a.atomTypeId[w]=a.atomTypeId[t],a.x[w]=_.x,a.y[w]=_.y,a.z[w]=_.z,a.occupancy[w]=a.occupancy[t],a.serial[w]=w,a.altloc[w]="A".charCodeAt(0),n.addAtom(0,"","","HET",1,!0),void(w+=1)}}}))}}(B,A,S),S.finalize(),A.finalizeAtoms(),Ga(A),A.finalizeBonds();else{const e={},T={},D=A.atomMap,F=A.atomStore,E=B.categories.atom_site;let $=E.rowCount;const O=E.getField("pdbx_PDB_model_num");if(!(null===(t=null==O?void 0:O.areValuesEqual(0,$-1))||void 0===t||t)&&(P||C)){const t=O.int(0);for(let e=0;e<$;e++)if(O.int(e)>t){$=e;break}}A.chemCompMap=new pg(A);const R=B.categories.chem_comp;let L=R.getField("id");const N=R.getField("type");for(let t=0;t{const r=t.getField(e);return r?r.toFloatArray({array:Float32Array,start:0,end:i}):new Float32Array(i)};F.resize($),F.x=z(E,"Cartn_x",$),F.y=z(E,"Cartn_y",$),F.z=z(E,"Cartn_z",$),F.serial=E.getField("id").toIntArray({start:0,end:$}),F.bfactor=z(E,"B_iso_or_equiv",$),F.occupancy=z(E,"occupancy",$);const U=E.getField("label_alt_id");(null==U?void 0:U.isDefined)&&(F.altloc=Uint8Array.from(U.toStringArray(),(t=>t.charCodeAt(0))));const V=E.getField("label_atom_id"),j=E.getField("type_symbol");L=E.getField("label_comp_id");const G=null!==(r=E.getField("auth_seq_id"))&&void 0!==r?r:E.getField("label_seq_id"),H=E.getField("pdbx_PDB_ins_code"),q=E.getField("auth_asym_id"),W=E.getField("label_asym_id"),X=E.getField("group_PDB"),Y=E.getField("label_entity_id");for(let t=0;t<$;t++){const i=null!==(n=null==O?void 0:O.int(t))&&void 0!==n?n:1,r=null!==(s=null==q?void 0:q.str(t))&&void 0!==s?s:"",u=null!==(o=null==W?void 0:W.str(t))&&void 0!==o?o:"",d=null!==(a=null==L?void 0:L.str(t))&&void 0!==a?a:"",m=null!==(c=null==G?void 0:G.int(t))&&void 0!==c?c:0,f="H"===(null==X?void 0:X.str(t)[0]),p=null!==(l=null==H?void 0:H.str(t))&&void 0!==l?l:"",g=null!==(h=null==Y?void 0:Y.int(t))&&void 0!==h?h:1;F.atomTypeId[t]=D.add((null==V?void 0:V.str(t))||"",null==j?void 0:j.str(t)),S.addAtom(i-1,r,u,d,m,f,void 0,p),e[u]=r,T[g]||(T[g]=new Set),T[g].add(A.chainStore.count-1)}if(P){const t=E.rowCount/$|0,e=E.getField("Cartn_x"),i=E.getField("Cartn_y"),r=E.getField("Cartn_z");for(let n=0;n0){const[t,e]=h.split("(").filter((t=>!!t)),r=o(t),s=o(e);Object.keys(r).forEach((function(t){Object.keys(s).forEach((function(e){const o=new i;o.multiplyMatrices(r[t],s[e]),n[t+"x"+e]=o}))}))}else n=o(h);const u=[];for(let t in n)u.push(n[t]);let d=""+e;/^(0|[1-9][0-9]*)$/.test(d)&&(d="BU"+d);const m=l.str(t).split(",").map((t=>r[t]));void 0===s[d]&&(s[d]=new Oa(d)),s[d].addPart(u,m)}}if(t.struct_ncs_oper){const e=t.struct_ncs_oper,r="NCS";s[r]=new Oa(r);const n=s[r].addPart(),o=e.getField("code"),a=e.getField("matrix[1][1]"),c=e.getField("matrix[1][2]"),l=e.getField("matrix[1][3]"),h=e.getField("matrix[2][1]"),u=e.getField("matrix[2][2]"),d=e.getField("matrix[2][3]"),m=e.getField("matrix[3][1]"),f=e.getField("matrix[3][2]"),p=e.getField("matrix[3][3]"),g=e.getField("vector[1]"),y=e.getField("vector[2]"),b=e.getField("vector[3]");for(let t=0;ts&&([n,s]=[s,n],[P,T]=[T,P]),0!==n&&0!==s)for(let i=0;ib)continue}u=I.substr(5,5).trim(),d=parseInt(I.substr(0,5)),m=parseInt(I.substr(15,5)),x.growIfFull(),x.atomTypeId[v]=_.add(h),x.x[v]=T,x.y[v]=D,x.z[v]=B,x.serial[v]=m,r.addAtom(w,"","",u,d,!1,"l"),v+=1}}}(0,i.length,i)})),r.finalize(),i.finalizeAtoms(),ja(i),Ga(i),i.finalizeBonds(),za(i),Te&&Ie.timeEnd("GroParser._parse "+this.name)}});var vg=["mmtfVersion","mmtfProducer","unitCell","spaceGroup","structureId","title","depositionDate","releaseDate","experimentalMethods","resolution","rFree","rWork","bioAssemblyList","ncsOperatorList","entityList","groupList","numBonds","numAtoms","numGroups","numChains","numModels","groupsPerChain","chainsPerModel"].concat(["xCoordList","yCoordList","zCoordList","groupIdList","groupTypeList","chainIdList","bFactorList","atomIdList","altLocList","occupancyList","secStructList","insCodeList","sequenceIndexList","chainNameList","bondAtomList","bondOrderList"]);function wg(t,e,i){return e?new t(e.buffer,e.byteOffset,e.byteLength/(i||1)):void 0}function Ag(t){return wg(DataView,t)}function Sg(t){return wg(Int8Array,t)}function Cg(t){return wg(Int32Array,t,4)}function Pg(t,e){var i=t.length/2;e||(e=new Int16Array(i));for(var r=0,n=0;rs&&++a;e=new Int32Array(a)}for(i=0,r=0;in){for(var s=[],o=0;o0&&(o.biomolDict[t]=e)}const E=a.unitCell;E&&Array.isArray(E)&&E[0]?o.unitcell=new cg({a:E[0],b:E[1],c:E[2],alpha:E[3],beta:E[4],gamma:E[5],spacegroup:a.spaceGroup}):o.unitcell=void 0,Xa(o,!0),Wa(o,!0),o.finalizeAtoms(),o.finalizeBonds(),Ya(o),Te&&Ie.timeEnd("MmtfParser._parse "+this.name)}});const Lg=/\s+/,Ng={1:1,2:2,3:3,am:1,ar:1,du:1,un:1,nc:0};Le.add("mol2",class extends sg{get type(){return"mol2"}_parse(){Te&&Ie.time("Mol2Parser._parse "+this.name);const t=this.structure,e=this.structureBuilder,i=this.firstModelOnly,r=this.asTrajectory,n=t.frames;let s,o,a=!1;const c=t.atomMap,l=t.atomStore;l.resize(Math.round(this.streamer.data.length/60)),l.addField("partialCharge",1,"float32");let h=0,u=0,d=0,m=-1,f=0,p=0;const g=t.getAtomProxy(),y=t.getAtomProxy();this.streamer.eachChunkOfLines((function(b){!function(b,_,x){for(let v=b;v<_;++v){const b=x[v].trim();if(""!==b&&"#"!==b[0])if("@"===b[0])"@MOLECULE"===b?(p=1,u=0,++m):"@ATOM"===b?(p=2,d=l.count,r&&(o=0,s=new Float32Array(3*f),n.push(s),m>0&&(a=!0))):p="@BOND"===b?3:0;else if(1===p){if(0===u)t.title=b,t.id=b;else if(1===u){const t=b.split(Lg);f=parseInt(t[0])}++u}else if(2===p){const t=b.split(Lg);if(i&&m>0)continue;const n=parseFloat(t[2]),u=parseFloat(t[3]),d=parseFloat(t[4]);if(r){const t=3*o;if(s[t+0]=n,s[t+1]=u,s[t+2]=d,o+=1,a)continue}const f=t[0],p=t[1],g=t[5].split(".")[0],y=t[6]?parseInt(t[6]):1,_=t[7]?t[7]:"",x=t[8]?parseFloat(t[8]):0;l.growIfFull(),l.atomTypeId[h]=c.add(p,g),l.x[h]=n,l.y[h]=u,l.z[h]=d,l.serial[h]=+f,l.partialCharge[h]=x,e.addAtom(m,"","",_,y,!0),h+=1}else if(3===p){if(i&&m>0)continue;if(r&&m>0)continue;const e=b.split(Lg);g.index=parseInt(e[1])-1+d,y.index=parseInt(e[2])-1+d;const n=Ng[e[3]];t.bondStore.addBond(g,y,n)}}}(0,b.length,b)})),e.finalize(),t.finalizeAtoms(),ja(t),Wa(t,!0),Xa(t,!0),t.finalizeBonds(),Ja(t),za(t),Te&&Ie.timeEnd("Mol2Parser._parse "+this.name)}});Le.add("pdbqt",class extends fg{get type(){return"pdbqt"}});Le.add("pqr",class extends fg{get type(){return"pqr"}});const zg=/> +<(.+)>/;class Ug extends sg{get type(){return"sdf"}_parse(){Te&&Ie.time("SdfParser._parse "+this.name);const t=this.structure,e=this.structureBuilder,i=this.firstModelOnly,r=this.asTrajectory,n=this.streamer.peekLines(2);t.id=n[0].trim(),t.title=n[1].trim();const s=t.frames;let o,a,c=!1;const l=t.atomMap,h=t.atomStore;h.resize(Math.round(this.streamer.data.length/50)),h.addField("formalCharge",1,"int8");const u=t.getAtomProxy(),d=t.getAtomProxy();let m=0,f=0,p=0,g=0;const y=[];let b,_,x,v,w,A,S,C,P,I,k,M,T,D,B=!1,F={};t.extraData.sdf=y;let E=!1,$=!1,O=!1,R=[],L=[];const N=new Map;this.streamer.eachChunkOfLines((function(n){!function(n,z,U){for(let V=n;V-1,E?N.clear():(_=parseInt(n.substr(0,3)),x=parseInt(n.substr(3,3)),v=4,w=v+_,A=w,S=A+x,r&&(a=0,o=new Float32Array(3*_),s.push(o),p>0&&(c=!0)));else if(E&&"COUNTS"===R[0])_=parseInt(R[1]),r&&(a=0,o=new Float32Array(3*_),s.push(o),p>0&&(c=!0));else if(E&&2==R.length)"ATOM"===R[1]?"BEGIN"===R[0]?$=!0:"END"===R[0]&&($=!1):"BOND"===R[1]&&("BEGIN"===R[0]?O=!0:"END"===R[0]&&(O=!1));else if($||!E&&f>=v&&f0)continue;let t=0;if(E){if(C=parseFloat(R[2]),P=parseFloat(R[3]),I=parseFloat(R[4]),M=R[1],T=parseInt(R[0]),N.set(T,m),k=M+T,R.length>6){let e=R.slice(6).find((t=>0===t.indexOf("CHG=")));e&&(t=parseInt(e.substring(4)))}}else C=parseFloat(n.substr(0,10)),P=parseFloat(n.substr(10,10)),I=parseFloat(n.substr(20,10)),M=n.substr(31,3).trim(),k=M+(m-g+1);if(r){const t=3*a;if(o[t+0]=C,o[t+1]=P,o[t+2]=I,a+=1,c)continue}h.growIfFull(),h.atomTypeId[m]=l.add(k,M),h.x[m]=C,h.y[m]=P,h.z[m]=I,h.serial[m]=E?T:m,h.formalCharge[m]=t,e.addAtom(p,"","","HET",1,!0),m+=1}else if(O||!E&&f>=A&&f0)continue;if(r&&p>0)continue;E?(u.index=N.get(parseInt(R[2])),d.index=N.get(parseInt(R[3])),D=parseInt(R[1])):(u.index=parseInt(n.substr(0,3))-1+g,d.index=parseInt(n.substr(3,3))-1+g,D=parseInt(n.substr(6,3))),t.bondStore.addBond(u,d,D)}else if("M CHG"===n.substr(0,6)){const t=parseInt(n.substr(6,3));for(let e=0,i=10;e"===n.charAt(0)&&(b=n.match(zg))?(B=b[1],F[B]=[]):!1!==B&&n&&F[B].push(n);++f}}}(0,n.length,n)})),e.finalize(),t.finalizeAtoms(),t.finalizeBonds(),Ja(t),Te&&Ie.timeEnd("SdfParser._parse "+this.name)}_postProcess(){Ja(this.structure)}}Le.add("sdf",Ug),Le.add("sd",Ug),Le.add("mol",Ug);function Vg(t,e,i){return parseInt(t.substr(e,i).trim())}class jg extends sg{get type(){return"prmtop"}_parse(){Te&&Ie.time("PrmtopParser._parse "+this.name);const t=this.structure,e=this.structureBuilder,i=t.atomMap,r=t.atomStore;r.addField("partialCharge",1,"float32"),r.addField("radius",1,"float32");const n=[],s={},o=["NATOM","NTYPES","NBONH","MBONA","NTHETH","MTHETA","NPHIH","MPHIA","NHPARM","NPARM","NNB","NRES","NBONA","NTHETA","NPHIA","NUMBND","NUMANG","NPTRA","NATYP","NPHB","IFPERT","NBPER","NGPER","NDPER","MBPER","MGPER","MDPER","IFBOX","NMXRS","IFCAP","NUMEXTRA","NCOPY"];let a,c,l,h,u;o.forEach((t=>{s[t]=0}));let d,m,f,p,g,y=new Uint8Array(0);this.streamer.eachChunkOfLines((function(t){!function(t,e,i){for(let b=t;b0)return void Ie.error("dcd format with fixed atoms unsupported, aborting");const f=s.NATOM,p=4*f;for(let i=0,a=s.NSET;i=1&&(i.timeOffset=(s.ISTART-1)*i.deltaTime),Te&&Ie.timeEnd("DcdParser._parse "+this.name)}});const Qg={BYTE:1,CHAR:2,SHORT:3,INT:4,FLOAT:5,DOUBLE:6};function Jg(t){switch(Number(t)){case Qg.BYTE:return"byte";case Qg.CHAR:return"char";case Qg.SHORT:return"short";case Qg.INT:return"int";case Qg.FLOAT:return"float";case Qg.DOUBLE:return"double";default:return"undefined"}}function ty(t){switch(Number(t)){case Qg.BYTE:case Qg.CHAR:return 1;case Qg.SHORT:return 2;case Qg.INT:case Qg.FLOAT:return 4;case Qg.DOUBLE:return 8;default:return-1}}function ey(t){switch(String(t)){case"byte":return Qg.BYTE;case"char":return Qg.CHAR;case"short":return Qg.SHORT;case"int":return Qg.INT;case"float":return Qg.FLOAT;case"double":return Qg.DOUBLE;default:return-1}}function iy(t,e){if(1!==t){const i=new Array(t);for(let r=0;r6,"non valid type "+h);const u=t.readUint32();let d=t.readUint32();2===i&&(Yg(d>0,"offsets larger than 4GB not supported"),d=t.readUint32()),c[0]===e&&(s+=u),n[r]={name:o,dimensions:c,attributes:l,type:Jg(h),size:u,offset:d,record:c[0]===e}}}return{variables:n,recordStep:s}}(t,r.recordId,e);return i.variables=n.variables,i.recordDimension.recordStep=n.recordStep,i}function ly(t){let e;const i=t.readUint32();if(i===ny)return Yg(t.readUint32()!==ny,"wrong empty tag for list of attributes"),[];{Yg(i!==ay,"wrong tag for list of attributes");const r=t.readUint32();e=new Array(r);for(let i=0;i6,"non valid type "+n);const s=t.readUint32(),o=ry(t,n,s);Kg(t),e[i]={name:r,type:Jg(n),value:o}}}return e}class hy{constructor(t){const e=new ci(t);e.setBigEndian(),Yg("CDF"!==e.readChars(3),"should start with CDF");const i=e.readByte();Yg(i>2,"unknown version"),this.header=cy(e,i),this.buffer=e}get version(){return 1===this.header.version?"classic format":"64-bit offset format"}get recordDimension(){return this.header.recordDimension}get dimensions(){return this.header.dimensions}get globalAttributes(){return this.header.globalAttributes}get variables(){return this.header.variables}hasDataVariable(t){return-1!==this.header.variables.findIndex((function(e){return e.name===t}))}getDataVariable(t){let e;return e="string"==typeof t?this.header.variables.find((function(e){return e.name===t})):t,Yg(void 0===e,"variable not found"),this.buffer.seek(e.offset),e.record?function(t,e,i){const r=ey(e.type),n=e.size?e.size/ty(r):1,s=i.length,o=new Array(s),a=i.recordStep;for(let e=0;e=1&&(e.timeOffset=n[0]),n.length>=2&&(e.deltaTime=n[1]-n[0]),Te&&Ie.timeEnd("NctrajParser._parse "+this.name)}}Le.add("nctraj",uy),Le.add("ncdf",uy),Le.add("nc",uy);Le.add("trr",class extends Xg{get type(){return"trr"}get isBinary(){return!0}_parse(){Te&&Ie.time("TrrParser._parse "+this.name);const t=bt(this.streamer.data),e=new DataView(t),i=this.frames,r=i.coordinates,n=i.boxes,s=i.times;let o=0;for(;;){o+=8;const i=e.getInt32(o);o+=4,o+=i;const a=e.getInt32(o+8),c=e.getInt32(o+12),l=e.getInt32(o+16),h=e.getInt32(o+28),u=e.getInt32(o+32),d=e.getInt32(o+36),m=e.getInt32(o+40);o+=52;const f=a/9,p=3*m;if(8===f?s.push(e.getFloat64(o)):s.push(e.getFloat32(o)),o+=2*f,a){const t=new Float32Array(9);if(8===f)for(let i=0;i<9;++i)t[i]=10*e.getFloat64(o),o+=8;else for(let i=0;i<9;++i)t[i]=10*e.getFloat32(o),o+=4;n.push(t)}if(o+=c,o+=l,h){let i;if(8===f){i=new Float32Array(p);for(let t=0;t>8&65280|i>>24&255}i=new Float32Array(t,o,p);for(let t=0;t=t.byteLength)break}s.length>=1&&(i.timeOffset=s[0]),s.length>=2&&(i.deltaTime=s[1]-s[0]),Te&&Ie.timeEnd("TrrParser._parse "+this.name)}});const dy=new Uint32Array([0,0,0,0,0,0,0,0,0,8,10,12,16,20,25,32,40,50,64,80,101,128,161,203,256,322,406,512,645,812,1024,1290,1625,2048,2580,3250,4096,5060,6501,8192,10321,13003,16384,20642,26007,32768,41285,52015,65536,82570,104031,131072,165140,208063,262144,330280,416127,524287,660561,832255,1048576,1321122,1664510,2097152,2642245,3329021,4194304,5284491,6658042,8388607,10568983,13316085,16777216]);function my(t){let e=1,i=0;for(;t>=e&&i<32;)i++,e<<=1;return i}const fy=new Uint8Array(32);function py(t,e){let i=1,r=0;fy[0]=1;for(let r=0;r>=8;for(;0!==n;)fy[t++]=255&n,n>>=8;i=t}let n=1;for(i--;fy[i]>=n;)r++,n*=2;return r+8*i}function gy(t,e,i,r){const n=(1<=8;)o=o<<8|e[a++],c|=o>>s<0&&(s>s&(1<8;)yy[a++]=gy(t,e,8,o),r-=8;r>0&&(yy[a++]=gy(t,e,r,o));for(let t=i-1;t>0;t--){let e=0;for(let i=a-1;i>=0;i--){e=e<<8|yy[i];const r=e/n[t]|0;yy[i]=r,e-=r*n[t]}s[t]=e}s[0]=yy[0]|yy[1]<<8|yy[2]<<16|yy[3]<<24}Le.add("xtc",class extends Xg{get type(){return"xtc"}get isBinary(){return!0}_parse(){Te&&Ie.time("XtcParser._parse "+this.name);const t=bt(this.streamer.data),e=new DataView(t),i=this.frames,r=i.coordinates,n=i.boxes,s=i.times,o=new Int32Array(6),a=new Int32Array(3),c=new Int32Array(3),l=new Uint32Array(3),h=new Float32Array(3),u=new Float32Array(3);let d=0;const m=new Int32Array(3),f=new Uint32Array(m.buffer);for(;;){let i;const p=e.getInt32(d+4);d+=12;const g=3*p;s.push(e.getFloat32(d)),d+=4;const y=new Float32Array(9);for(let t=0;t<9;++t)y[t]=10*e.getFloat32(d),d+=4;if(n.push(y),p<=9){i=new Float32Array(p);for(let t=0;t16777215?(c[0]=my(a[0]),c[1]=my(a[1]),c[2]=my(a[2]),p=0):p=py(3,a);let y=e.getInt32(d);d+=4;let b=y-1;b=9>b?9:b;let _=dy[b]/2|0,x=dy[y]/2|0;l[0]=l[1]=l[2]=dy[y];let v=4*Math.ceil(e.getInt32(d)/4);d+=4;const w=1/s;let A=0,S=0;const C=new Uint8Array(t,d);for(h[0]=h[1]=h[2]=0;S0){h[0]=h[1]=h[2]=0;for(let t=0;t9?dy[y-1]/2|0:0):t>0&&(_=x,x=dy[y]/2|0),l[0]=l[1]=l[2]=dy[y],0===l[0]||0===l[1]||0===l[2])return void console.error("(xdrfile error) Undefined error.")}d+=v}for(let t=0;t=t.byteLength)break}s.length>=1&&(i.timeOffset=s[0]),s.length>=2&&(i.deltaTime=s[1]-s[0]),Te&&Ie.timeEnd("XtcParser._parse "+this.name)}});class _y extends ng{constructor(t,e){const i=e||{};super(t,i),this.volume=new Eo(this.name,this.path),this.voxelSize=rt(i.voxelSize,1)}get type(){return"volume"}get __objName(){return"volume"}_afterParse(){this.volume.setMatrix(this.getMatrix()),super._afterParse()}getMatrix(){return new i}}const xy=/\s+/,vy=/-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?/g,wy=.529177210859;class Ay extends _y{get type(){return"cube"}_parse(){Te&&Ie.time("CubeParser._parse "+this.name);const t=this.volume,i=this.streamer.peekLines(6),r={},n=wy*this.voxelSize;function s(t,e){var r=i[t].trim().split(xy)[e];return parseFloat(r)}r.atomCount=Math.abs(s(2,0)),r.originX=s(2,1)*wy,r.originY=s(2,2)*wy,r.originZ=s(2,3)*wy,r.NVX=s(3,0),r.NVY=s(4,0),r.NVZ=s(5,0),r.basisX=new e(s(3,1),s(3,2),s(3,3)).multiplyScalar(n),r.basisY=new e(s(4,1),s(4,2),s(4,3)).multiplyScalar(n),r.basisZ=new e(s(5,1),s(5,2),s(5,3)).multiplyScalar(n);const o=new Float32Array(r.NVX*r.NVY*r.NVZ);let a=0,c=0;const l=s(2,0)>0?0:1;this.streamer.eachChunkOfLines((function(t){!function(t,e,i){for(let n=t;n=r.atomCount+6+l){const e=t.match(vy);for(let t=0,i=e.length;t>8&255}e.xStart=s[0],e.yStart=s[1],e.zStart=s[2],e.xExtent=s[3],e.yExtent=s[4],e.zExtent=s[5],e.xRate=s[6],e.yRate=s[7],e.zRate=s[8];const t=1/s[17],n=t*this.voxelSize;e.xlen=s[9]*n,e.ylen=s[10]*n,e.zlen=s[11]*n,e.alpha=s[12]*t,e.beta=s[13]*t,e.gamma=s[14]*t,i=s[15]/100,r=s[16],e.gamma=s[14]*t}t.header=e,Te&&Ie.log(e,i,r);const c=new Float32Array(e.xExtent*e.yExtent*e.zExtent);let l=512;const h=Math.ceil(e.xExtent/8),u=Math.ceil(e.yExtent/8),d=Math.ceil(e.zExtent/8);for(var m=0;mn){const t=i[r].trim();if(""!==t){const e=t.split(Cy);for(let t=0,i=e.length;t=n&&(f-n)%d!=0&&m=0?i-1:i+e/3)},parseNormalIndex:function(t,e){var i=parseInt(t,10);return 3*(i>=0?i-1:i+e/3)},addVertex:function(t,e,i){var r=this.vertices,n=this.object.geometry.vertices;n.push(r[t+0]),n.push(r[t+1]),n.push(r[t+2]),n.push(r[e+0]),n.push(r[e+1]),n.push(r[e+2]),n.push(r[i+0]),n.push(r[i+1]),n.push(r[i+2])},addVertexLine:function(t){var e=this.vertices,i=this.object.geometry.vertices;i.push(e[t+0]),i.push(e[t+1]),i.push(e[t+2])},addNormal:function(t,e,i){var r=this.normals,n=this.object.geometry.normals;n.push(r[t+0]),n.push(r[t+1]),n.push(r[t+2]),n.push(r[e+0]),n.push(r[e+1]),n.push(r[e+2]),n.push(r[i+0]),n.push(r[i+1]),n.push(r[i+2])},addFace:function(t,e,i,r,n,s,o,a){var c,l=this.vertices.length,h=this.parseVertexIndex(t,l),u=this.parseVertexIndex(e,l),d=this.parseVertexIndex(i,l);if(void 0===r?this.addVertex(h,u,d):(c=this.parseVertexIndex(r,l),this.addVertex(h,u,c),this.addVertex(u,d,c)),void 0!==n){var m=this.normals.length;h=this.parseNormalIndex(n,m),u=n===s?h:this.parseNormalIndex(s,m),d=n===o?h:this.parseNormalIndex(o,m),void 0===r?this.addNormal(h,u,d):(c=this.parseNormalIndex(a,m),this.addNormal(h,u,c),this.addNormal(u,d,c))}},addLineGeometry:function(t){this.object.geometry.type="Line";for(var e=this.vertices.length,i=0,r=t.length;i0?_.setAttribute("normal",new M(new Float32Array(b.normals),3)):_.computeVertexNormals(),y.push(_)}}return y}};Le.add("obj",class extends jy{get type(){return"obj"}getLoader(){return new Gy}});Le.add("csv",class extends ng{constructor(t,e){const i=e||{};super(t,i),this.delimiter=rt(i.delimiter,","),this.comment=rt(i.comment,"#"),this.columnNames=rt(i.columnNames,!1),this.table={name:this.name,path:this.path,columnNames:[],data:[]}}get type(){return"csv"}get __objName(){return"table"}_parse(){const t=this.table.data,e=new RegExp("\\s*"+this.delimiter+"\\s*");let i=0;this.streamer.eachChunkOfLines((r=>{const n=r.length;for(let s=0;s/g,""),{declaration:e(),root:i()};function e(){if(!n(/^<\?xml\s*/))return;const t={attributes:{}};for(;!s()&&!o("?>");){const e=r();if(!e)return t;t.attributes[e.name]=e.value}return n(/\?>\s*/),t}function i(){const t=n(Wy);if(!t)return;const e={name:t[1],attributes:{},children:[]};for(;!(s()||o(">")||o("?>")||o("/>"));){const t=r();if(!t)return e;e.attributes[t.name]=t.value}if(n(/^\s*\/>\s*/))return e;let a;for(n(/\??>\s*/),e.content=function(){const t=n(Xy);return t?t[1]:""}();a=i();)e.children.push(a);return n(/^<\/[\w-:.]+>\s*/),e}function r(){const t=n(Yy);var e;if(t)return{name:t[1],value:(e=t[2],e.replace(qy,""))}}function n(e){const i=t.match(e);if(i)return t=t.slice(i[0].length),i}function s(){return 0===t.length}function o(e){return 0===t.indexOf(e)}}class Zy extends ng{constructor(t,e){const i=e||{};super(t,i),this.useDomParser=rt(i.useDomParser,!1),this.xml={name:this.name,path:this.path,data:{}}}get type(){return"xml"}get __objName(){return"xml"}get isXml(){return!0}__xmlParser(t){return Ky(t)}__domParser(t){return(new window.DOMParser).parseFromString(t,"text/xml")}_parse(){Te&&Ie.time("XmlParser._parse "+this.name),this.useDomParser?this.streamer.data instanceof Document?this.xml.data=this.streamer.data:this.xml.data=this.__domParser(this.streamer.asText()):this.xml.data=this.__xmlParser(this.streamer.asText()),Te&&Ie.timeEnd("XmlParser._parse "+this.name)}}function Qy(t,e){const i=t.getNamedItem(e);return null!==i?i.value:""}function Jy(t,e,i=!1){const r=Qy(t,"icode").trim(),n=Qy(t,"chain").trim(),s=Qy(t,"altcode");let o=Qy(t,"resnum");return r&&(o+="^"+r),n&&(o+=":"+n),e&&(o+="."+e),i&&s.trim()&&(o+="%"+s),o+="/"+(parseInt(Qy(t,"model"))-1),o}function tb(t){const e=Qy(t,"chain").trim();let i=`[${Qy(t,"rescode")}]${Qy(t,"resnum")}`;return e&&(i+=`:${e}`),i}function eb(t,e,i){void 0===t[e]?t[e]=i:t[e]|=i}function ib(t,e){return null!==t&&t.value===e}function rb(t,e,i){let r=0;const n=e.getElementsByTagName("clash");for(let e=0,i=n.length;e0&&(r+=1);e.getElementsByTagName("bond-outlier").length>0&&(r+=1);return e.getElementsByTagName("plane-outlier").length>0&&(r+=1),ib(i.getNamedItem("rota"),"OUTLIER")&&(r+=1),ib(i.getNamedItem("rama"),"OUTLIER")&&(r+=1),ib(i.getNamedItem("RNApucker"),"outlier")&&(r+=1),r}Le.add("xml",Zy);class nb{constructor(t,e){this.name=t,this.path=e,this.rsrzDict={},this.rsccDict={},this.rciDict={},this.clashDict={},this.clashArray=[],this.geoDict={},this.geoAtomDict={},this.atomDict={},this.clashSele="NONE"}get type(){return"validation"}fromXml(t){Te&&Ie.time("Validation.fromXml");const e=this.rsrzDict,i=this.rsccDict,r=this.rciDict,n=this.clashDict,s=this.clashArray,o=this.geoDict,a=this.geoAtomDict,c=this.atomDict,l=t.getElementsByTagName("Entry");if(1===l.length){const t=l[0].getElementsByTagName("chemical_shift_list");if(1===t.length){const e=t[0].getElementsByTagName("random_coil_index");for(let t=0,i=e.length;t0&&(o[r]=t)}else{const t=e.getElementsByTagName("clash"),i=e.getElementsByTagName("mog-bond-outlier"),s=e.getElementsByTagName("mog-angle-outlier");if(i.length>0||s.length>0||t.length>0){const e={};a[r]=e;for(let i=0,r=t.length;i>>16&65535,o=0;0!==i;){i-=o=i>2e3?2e3:i;do{s=s+(n=n+e[r++]|0)|0}while(--o);n%=65521,s%=65521}return n|s<<16}Le.add("validation",class extends Zy{constructor(t,e){super(t,e||{}),this.useDomParser=!0,this.validation=new nb(this.name,this.path)}get __objName(){return"validation"}get isXml(){return!0}_parse(){super._parse(),Te&&Ie.time("ValidationParser._parse "+this.name),this.validation.fromXml(this.xml.data),Te&&Ie.timeEnd("ValidationParser._parse "+this.name)}});var cb=function(){for(var t,e=[],i=0;i<256;i++){t=i;for(var r=0;r<8;r++)t=1&t?3988292384^t>>>1:t>>>1;e[i]=t}return e}();function lb(t,e,i,r){var n=cb,s=r+i;t^=-1;for(var o=r;o>>8^n[255&(t^e[o])];return~t}var hb=30,ub=12;function db(t,e){var i,r,n,s,o,a,c,l,h,u,d,m,f,p,g,y,b,_,x,v,w,A,S,C,P;i=t.state,r=t.next_in,C=t.input,n=r+(t.avail_in-5),s=t.next_out,P=t.output,o=s-(e-t.avail_out),a=s+(t.avail_out-257),c=i.dmax,l=i.wsize,h=i.whave,u=i.wnext,d=i.window,m=i.hold,f=i.bits,p=i.lencode,g=i.distcode,y=(1<>>=x=_>>>24,f-=x,0===(x=_>>>16&255))P[s++]=65535&_;else{if(!(16&x)){if(64&x){if(32&x){i.mode=ub;break t}t.msg="invalid literal/length code",i.mode=hb;break t}_=p[(65535&_)+(m&(1<>>=x,f-=x),f<15&&(m+=C[r++]<>>=x=_>>>24,f-=x,16&(x=_>>>16&255)){if(w=65535&_,f<(x&=15)&&(m+=C[r++]<c){t.msg="invalid distance too far back",i.mode=hb;break t}if(m>>>=x,f-=x,w>(x=s-o)){if((x=w-x)>h&&i.sane){t.msg="invalid distance too far back",i.mode=hb;break t}if(A=0,S=d,0===u){if(A+=l-x,x2;)P[s++]=S[A++],P[s++]=S[A++],P[s++]=S[A++],v-=3;v&&(P[s++]=S[A++],v>1&&(P[s++]=S[A++]))}else{A=s-w;do{P[s++]=P[A++],P[s++]=P[A++],P[s++]=P[A++],v-=3}while(v>2);v&&(P[s++]=P[A++],v>1&&(P[s++]=P[A++]))}break}if(64&x){t.msg="invalid distance code",i.mode=hb;break t}_=g[(65535&_)+(m&(1<>3,m&=(1<<(f-=v<<3))-1,t.next_in=r,t.next_out=s,t.avail_in=r=1&&0===T[v];v--);if(w>v&&(w=v),0===v)return n[s++]=20971520,n[s++]=20971520,a.bits=1,0;for(x=1;x0&&(t===gb||1!==v))return-1;for(D[1]=0,b=1;bfb||t===bb&&P>pb)return 1;for(;;){f=b-S,o[_]m?(p=B[F+o[_]],g=k[M+o[_]]):(p=96,g=0),c=1<>S)+(l-=c)]=f<<24|p<<16|g}while(0!==l);for(c=1<>=1;if(0!==c?(I&=c-1,I+=c):I=0,_++,0==--T[b]){if(b===v)break;b=e[i+o[_]]}if(b>w&&(I&u)!==h){for(0===S&&(S=w),d+=x,C=1<<(A=b-S);A+Sfb||t===bb&&P>pb)return 1;n[h=I&u]=w<<24|A<<16|d-s}}return 0!==I&&(n[d+I]=b-S<<24|64<<16),a.bits=w,0}var Sb=1,Cb=2,Pb=0,Ib=-2,kb=1,Mb=12,Tb=30,Db=852,Bb=592;function Fb(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function Eb(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new Uint16Array(320),this.work=new Uint16Array(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function $b(t){var e;return t&&t.state?((e=t.state).wsize=0,e.whave=0,e.wnext=0,function(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=kb,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new Int32Array(Db),e.distcode=e.distdyn=new Int32Array(Bb),e.sane=1,e.back=-1,Pb):Ib}(t)):Ib}function Ob(t,e){var i,r;return t?(r=new Eb,t.state=r,r.window=null,i=function(t,e){var i,r;return t&&t.state?(r=t.state,e<0?(i=0,e=-e):(i=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?Ib:(null!==r.window&&r.wbits!==e&&(r.window=null),r.wrap=i,r.wbits=e,$b(t))):Ib}(t,e),i!==Pb&&(t.state=null),i):Ib}var Rb,Lb,Nb=!0;function zb(t){if(Nb){var e;for(Rb=new Int32Array(512),Lb=new Int32Array(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(Ab(Sb,t.lens,0,288,Rb,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;Ab(Cb,t.lens,0,32,Lb,0,t.work,{bits:5}),Nb=!1}t.lencode=Rb,t.lenbits=9,t.distcode=Lb,t.distbits=5}function Ub(t,e,i,r){var n,s=t.state;return null===s.window&&(s.wsize=1<=s.wsize?(ob(s.window,e,i-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):((n=s.wsize-s.wnext)>r&&(n=r),ob(s.window,e,i-r,n,s.wnext),(r-=n)?(ob(s.window,e,i-r,r,0),s.wnext=r,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,i.check=lb(i.check,I,2,0),l=0,h=0,i.mode=2;break}if(i.flags=0,i.head&&(i.head.done=!1),!(1&i.wrap)||(((255&l)<<8)+(l>>8))%31){t.msg="incorrect header check",i.mode=Tb;break}if(8!=(15&l)){t.msg="unknown compression method",i.mode=Tb;break}if(h-=4,w=8+(15&(l>>>=4)),0===i.wbits)i.wbits=w;else if(w>i.wbits){t.msg="invalid window size",i.mode=Tb;break}i.dmax=1<>8&1),512&i.flags&&(I[0]=255&l,I[1]=l>>>8&255,i.check=lb(i.check,I,2,0)),l=0,h=0,i.mode=3;case 3:for(;h<32;){if(0===a)break t;a--,l+=r[s++]<>>8&255,I[2]=l>>>16&255,I[3]=l>>>24&255,i.check=lb(i.check,I,4,0)),l=0,h=0,i.mode=4;case 4:for(;h<16;){if(0===a)break t;a--,l+=r[s++]<>8),512&i.flags&&(I[0]=255&l,I[1]=l>>>8&255,i.check=lb(i.check,I,2,0)),l=0,h=0,i.mode=5;case 5:if(1024&i.flags){for(;h<16;){if(0===a)break t;a--,l+=r[s++]<>>8&255,i.check=lb(i.check,I,2,0)),l=0,h=0}else i.head&&(i.head.extra=null);i.mode=6;case 6:if(1024&i.flags&&((m=i.length)>a&&(m=a),m&&(i.head&&(w=i.head.extra_len-i.length,i.head.extra||(i.head.extra=new Array(i.head.extra_len)),ob(i.head.extra,r,s,m,w)),512&i.flags&&(i.check=lb(i.check,r,m,s)),a-=m,s+=m,i.length-=m),i.length))break t;i.length=0,i.mode=7;case 7:if(2048&i.flags){if(0===a)break t;m=0;do{w=r[s+m++],i.head&&w&&i.length<65536&&(i.head.name+=String.fromCharCode(w))}while(w&&m>9&1,i.head.done=!0),t.adler=i.check=0,i.mode=Mb;break;case 10:for(;h<32;){if(0===a)break t;a--,l+=r[s++]<>>=7&h,h-=7&h,i.mode=27;break}for(;h<3;){if(0===a)break t;a--,l+=r[s++]<>>=1)){case 0:i.mode=14;break;case 1:if(zb(i),i.mode=20,6===e){l>>>=2,h-=2;break t}break;case 2:i.mode=17;break;case 3:t.msg="invalid block type",i.mode=Tb}l>>>=2,h-=2;break;case 14:for(l>>>=7&h,h-=7&h;h<32;){if(0===a)break t;a--,l+=r[s++]<>>16^65535)){t.msg="invalid stored block lengths",i.mode=Tb;break}if(i.length=65535&l,l=0,h=0,i.mode=15,6===e)break t;case 15:i.mode=16;case 16:if(m=i.length){if(m>a&&(m=a),m>c&&(m=c),0===m)break t;ob(n,r,s,m,o),a-=m,s+=m,c-=m,o+=m,i.length-=m;break}i.mode=Mb;break;case 17:for(;h<14;){if(0===a)break t;a--,l+=r[s++]<>>=5,h-=5,i.ndist=1+(31&l),l>>>=5,h-=5,i.ncode=4+(15&l),l>>>=4,h-=4,i.nlen>286||i.ndist>30){t.msg="too many length or distance symbols",i.mode=Tb;break}i.have=0,i.mode=18;case 18:for(;i.have>>=3,h-=3}for(;i.have<19;)i.lens[k[i.have++]]=0;if(i.lencode=i.lendyn,i.lenbits=7,S={bits:i.lenbits},A=Ab(0,i.lens,0,19,i.lencode,0,i.work,S),i.lenbits=S.bits,A){t.msg="invalid code lengths set",i.mode=Tb;break}i.have=0,i.mode=19;case 19:for(;i.have>>16&255,b=65535&P,!((g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>>=g,h-=g,i.lens[i.have++]=b;else{if(16===b){for(C=g+2;h>>=g,h-=g,0===i.have){t.msg="invalid bit length repeat",i.mode=Tb;break}w=i.lens[i.have-1],m=3+(3&l),l>>>=2,h-=2}else if(17===b){for(C=g+3;h>>=g)),l>>>=3,h-=3}else{for(C=g+7;h>>=g)),l>>>=7,h-=7}if(i.have+m>i.nlen+i.ndist){t.msg="invalid bit length repeat",i.mode=Tb;break}for(;m--;)i.lens[i.have++]=w}}if(i.mode===Tb)break;if(0===i.lens[256]){t.msg="invalid code -- missing end-of-block",i.mode=Tb;break}if(i.lenbits=9,S={bits:i.lenbits},A=Ab(Sb,i.lens,0,i.nlen,i.lencode,0,i.work,S),i.lenbits=S.bits,A){t.msg="invalid literal/lengths set",i.mode=Tb;break}if(i.distbits=6,i.distcode=i.distdyn,S={bits:i.distbits},A=Ab(Cb,i.lens,i.nlen,i.ndist,i.distcode,0,i.work,S),i.distbits=S.bits,A){t.msg="invalid distances set",i.mode=Tb;break}if(i.mode=20,6===e)break t;case 20:i.mode=21;case 21:if(a>=6&&c>=258){t.next_out=o,t.avail_out=c,t.next_in=s,t.avail_in=a,i.hold=l,i.bits=h,db(t,d),o=t.next_out,n=t.output,c=t.avail_out,s=t.next_in,r=t.input,a=t.avail_in,l=i.hold,h=i.bits,i.mode===Mb&&(i.back=-1);break}for(i.back=0;y=(P=i.lencode[l&(1<>>16&255,b=65535&P,!((g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>_)])>>>16&255,b=65535&P,!(_+(g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>>=_,h-=_,i.back+=_}if(l>>>=g,h-=g,i.back+=g,i.length=b,0===y){i.mode=26;break}if(32&y){i.back=-1,i.mode=Mb;break}if(64&y){t.msg="invalid literal/length code",i.mode=Tb;break}i.extra=15&y,i.mode=22;case 22:if(i.extra){for(C=i.extra;h>>=i.extra,h-=i.extra,i.back+=i.extra}i.was=i.length,i.mode=23;case 23:for(;y=(P=i.distcode[l&(1<>>16&255,b=65535&P,!((g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>_)])>>>16&255,b=65535&P,!(_+(g=P>>>24)<=h);){if(0===a)break t;a--,l+=r[s++]<>>=_,h-=_,i.back+=_}if(l>>>=g,h-=g,i.back+=g,64&y){t.msg="invalid distance code",i.mode=Tb;break}i.offset=b,i.extra=15&y,i.mode=24;case 24:if(i.extra){for(C=i.extra;h>>=i.extra,h-=i.extra,i.back+=i.extra}if(i.offset>i.dmax){t.msg="invalid distance too far back",i.mode=Tb;break}i.mode=25;case 25:if(0===c)break t;if(m=d-c,i.offset>m){if((m=i.offset-m)>i.whave&&i.sane){t.msg="invalid distance too far back",i.mode=Tb;break}m>i.wnext?(m-=i.wnext,f=i.wsize-m):f=i.wnext-m,m>i.length&&(m=i.length),p=i.window}else p=n,f=o-i.offset,m=i.length;m>c&&(m=c),c-=m,i.length-=m;do{n[o++]=p[f++]}while(--m);0===i.length&&(i.mode=21);break;case 26:if(0===c)break t;n[o++]=i.length,c--,i.mode=21;break;case 27:if(i.wrap){for(;h<32;){if(0===a)break t;a--,l|=r[s++]<=252?6:Wb>=248?5:Wb>=240?4:Wb>=224?3:Wb>=192?2:1;function Xb(t){var e,i,r,n,s,o=t.length,a=0;for(n=0;n>>6,e[s++]=128|63&i):i<65536?(e[s++]=224|i>>>12,e[s++]=128|i>>>6&63,e[s++]=128|63&i):(e[s++]=240|i>>>18,e[s++]=128|i>>>12&63,e[s++]=128|i>>>6&63,e[s++]=128|63&i);return e}function Yb(t,e){var i,r,n,s,o=e||t.length,a=new Array(2*o);for(r=0,i=0;i4)a[r++]=65533,i+=s-1;else{for(n&=2===s?31:3===s?15:7;s>1&&i1?a[r++]=65533:n<65536?a[r++]=n:(n-=65536,a[r++]=55296|n>>10&1023,a[r++]=56320|1023&n)}return function(t,e){if(e<65537&&(t.subarray&&Hb||!t.subarray&&Gb))return String.fromCharCode.apply(null,sb(t,e));for(var i="",r=0;rt.length&&(e=t.length),i=e-1;i>=0&&128==(192&t[i]);)i--;return i<0||0===i?e:i+qb[t[i]]>e?i:e}qb[254]=qb[254]=1;var Zb=0,Qb={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"};function Jb(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}function t_(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}var e_=Object.prototype.toString;function i_(t){if(!(this instanceof i_))return new i_(t);this.options=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var i=e.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(var r in i)i.hasOwnProperty(r)&&(t[r]=i[r])}}return t}({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&(15&e.windowBits||(e.windowBits|=15)),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new Jb,this.strm.avail_out=0;var i,r,n,s=Ob(this.strm,e.windowBits);if(s!==Zb)throw new Error(Qb[s]);this.header=new t_,i=this.strm,r=this.header,i&&i.state&&2&(n=i.state).wrap&&(n.head=r,r.done=!1)}i_.prototype.push=function(t,e){var i,r,n,s,o,a,c=this.strm,l=this.options.chunkSize,h=this.options.dictionary,u=!1;if(this.ended)return!1;r=e===~~e?e:!0===e?4:0,"string"==typeof t?c.input=function(t){for(var e=new Uint8Array(t.length),i=0,r=e.length;i0||0===c.avail_out)&&1!==i);return 1===i&&(r=4),4===r?(i=function(t){if(!t||!t.state)return Ib;var e=t.state;return e.window&&(e.window=null),t.state=null,Pb}(this.strm),this.onEnd(i),this.ended=!0,i===Zb):2!==r||(this.onEnd(Zb),c.avail_out=0,!0)},i_.prototype.onData=function(t){this.chunks.push(t)},i_.prototype.onEnd=function(t){t===Zb&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=function(t){var e,i,r,n,s,o;for(r=0,e=0,i=t.length;e-1?e.name:e.name.substring(0,4);return!["pdb","cif"].includes(e.ext)||!1!==e.compressed&&"gz"!==e.compressed?("mmtf"===e.ext&&(Ie.warn("MMTF files distribution has been discontinued by RCSB PDB as of July 2024.\n Defaulting to bcif format instead. See https://www.rcsb.org/news/65a1af31c76ca3abcc925d0c for the deprecation notice"),e.base.endsWith(".bb")&&Ie.warn("Backbone only files are not available from RCSB PDB anymore."),e.ext=""),e.ext?Ie.warn("unsupported ext",e.ext):Ie.warn('mmCif files available from RCSB PDB lack connectivity information.\n Consider using PDBe as the data provider for using "Updated mmCif files" that contain residues connectivity records.'),n_+"//models.rcsb.org/"+i+".bcif.gz"):n_+"//files.rcsb.org/download/"+e.path}getExt(t){const e=ei(t).ext;return e||"bcif"}});const s_="//www.ebi.ac.uk/pdbe/entry-files/download/";Oe.add("pdbe",new class extends r_{getUrl(t){const e=ei(t);let i,r=e.name.indexOf("_")>-1?e.name:e.name.substring(0,4);switch(e.ext){case"cif":i=s_+r+"_updated.cif";break;case"pdb":case"ent":r.startsWith("pdb")||(r="pdb"+r),i=s_+r+".ent";break;case"bcif":i=s_+e.path;break;case"":i=s_+r+".bcif";break;default:Ie.warn("unsupported ext",e.ext),i=s_+r+".bcif"}return"https://"+i}getExt(t){const e=ei(t).ext;return e||"bcif"}});const o_="//pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/",a_="/SDF?record_type=3d";Oe.add("pubchem",new class extends r_{getUrl(t){const e=ei(t),i=e.name;let r;return e.ext&&"sdf"!==e.ext?(Ie.warn("unsupported ext",e.ext),r=o_+i+a_):r=o_+i+a_,function(){const t=window.location.protocol;return null===t.match(/http(s)?:/gi)?"http:":t}()+r}getExt(t){const e=ei(t).ext;return e||"sdf"}});class c_ extends r_{getUrl(t){return t}getExt(t){return ei(t).ext}}Oe.add("ftp",new c_),Oe.add("http",new c_),Oe.add("https",new c_);const l_="//alphafold.ebi.ac.uk/files/AF-",h_="-F1-model_v4.pdb";Oe.add("alphafold",new class extends r_{getUrl(t){const e=ei(t),i=e.name;let r;return e.ext&&"pdb"!==e.ext?(Ie.warn("unsupported AF ext",e.ext),r=l_+i+h_):r=l_+i+h_,"https://"+r}getExt(t){const e=ei(t).ext;return e||"pdb"}});const u_=/^((http|https|ftp):)*\/\//;class d_ extends r_{constructor(t=""){super(),this.baseUrl=t}getUrl(t){const e=ei(t);let i=this.baseUrl+e.path;return u_.test(this.baseUrl)||(i=function(t){const e=window.location,i=e.pathname,r=i.substring(0,i.lastIndexOf("/")+1);return e.origin+r+t}(i)),i}getExt(t){return ei(t).ext}}class m_ extends r_{constructor(t=""){super(),this.baseUrl=t}getListing(t=""){let e=`${this.baseUrl}dir/${t}`;return"/"!==e[e.length-1]&&(e+="/"),ri(e,{ext:"json"}).then((e=>({path:t,data:e.data})))}getUrl(t){const e=ei(t);return`${this.baseUrl}file/${e.path}${e.query}`}getCountUrl(t){const e=ei(t);return`${this.baseUrl}traj/numframes/${e.path}${e.query}`}getFrameUrl(t,e){const i=ei(t);return`${this.baseUrl}traj/frame/${e}/${i.path}${i.query}`}getFrameParams(t,e){return`atomIndices=${e.join(";")}`}getPathUrl(t,e){const i=ei(t);return`${this.baseUrl}traj/path/${e}/${i.path}${i.query}`}getExt(t){return ei(t).ext}}function f_(t,e){return{type:"integer",max:t,min:e}}function p_(t,e,i){return{type:"number",precision:t,max:e,min:i}}function g_(t,e,i){return{type:"range",step:t,max:e,min:i}}function y_(...t){return{type:"select",options:t.reduce(((t,e)=>Object.assign(Object.assign({},t),{[e]:e})),{})}}const b_={backgroundColor:{type:"color"},quality:y_("auto","low","medium","high"),sampleLevel:g_(1,5,-1),impostor:{type:"boolean"},workerDefault:{type:"boolean"},rotateSpeed:p_(1,10,0),zoomSpeed:p_(1,10,0),panSpeed:p_(1,10,0),clipNear:g_(1,100,0),clipFar:g_(1,100,0),clipDist:f_(200,0),clipMode:y_("scene","camera"),clipScale:y_("relative","absolute"),fogNear:g_(1,100,0),fogFar:g_(1,100,0),cameraType:y_("perspective","orthographic","stereo"),cameraEyeSep:p_(3,1,.01),cameraFov:g_(1,120,15),lightColor:{type:"color"},lightIntensity:p_(2,10,0),ambientColor:{type:"color"},ambientIntensity:p_(2,10,0),hoverTimeout:f_(1e4,-1),tooltip:{type:"boolean"},mousePreset:y_(...Object.keys(Yo))};const __="2.3.1";export{Nh as AngleRepresentation,ld as ArrowBuffer,Oa as Assembly,tu as AxesRepresentation,iu as BackboneRepresentation,eu as BallAndStickRepresentation,ru as BaseRepresentation,fd as BoxBuffer,kc as BufferRepresentation,hu as CartoonRepresentation,cl as Collection,Lt as Colormaker,$e as ColormakerRegistry,al as Component,Dl as ComponentCollection,od as ConeBuffer,uu as ContactRepresentation,hi as Counter,Jh as CylinderBuffer,Oe as DatasourceRegistry,Te as Debug,ze as DecompressorRegistry,pu as DihedralHistogramRepresentation,du as DihedralRepresentation,yu as DistanceRepresentation,xd as EllipsoidBuffer,dl as Frames,vu as HelixorientRepresentation,Tu as HyperballRepresentation,Da as Kdtree,Qo as KeyActions,Bu as LabelRepresentation,Qi as LeftMouseButton,wu as LicoriceRepresentation,Eu as LineRepresentation,Ge as ListingDatasource,m_ as MdsrvDatasource,ke as MeasurementDefaultParams,Uo as MeshBuffer,Ji as MiddleMouseButton,Nu as MolecularSurface,zu as MolecularSurfaceRepresentation,Xo as MouseActions,Cd as OctahedronBuffer,Le as ParserRegistry,si as PdbWriter,gr as PickingProxy,Gc as PointBuffer,Uu as PointRepresentation,Rr as Queue,ll as RepresentationCollection,rl as RepresentationElement,Re as RepresentationRegistry,Hu as RibbonRepresentation,tr as RightMouseButton,qu as RocketRepresentation,Wu as RopeRepresentation,Fe as ScriptExtensions,oi as SdfWriter,de as Selection,Ic as Shape,Ol as ShapeComponent,Xu as SpacefillRepresentation,Mn as SpatialHash,zc as SphereBuffer,$l as Stage,d_ as StaticDatasource,li as StlWriter,Ac as Structure,kl as StructureComponent,Il as StructureComponentDefaultParameters,Ah as StructureRepresentation,ml as Superposition,Ml as SurfaceComponent,Td as TetrahedronBuffer,$h as TextBuffer,Od as TorusBuffer,Zu as TraceRepresentation,He as TrajectoryDatasource,pl as TrajectoryPlayer,Qu as TubeRepresentation,b_ as UIStageParameters,Ju as UnitcellRepresentation,td as ValidationRepresentation,__ as Version,Zi as Viewer,Eo as Volume,Tl as VolumeComponent,Lh as WidelineBuffer,ri as autoLoad,tc as concatStructures,lt as download,ot as flatten,ii as getDataInfo,ei as getFileInfo,it as getQuery,Qa as guessElement,Be as setDebug,qe as setListingDatasource,Me as setMeasurementDefaultParams,We as setTrajectoryDatasource,Pl as superpose,ht as throttle,ft as uniqueArray}; //# sourceMappingURL=ngl.esm.js.map diff --git a/dist/ngl.esm.js.map b/dist/ngl.esm.js.map index b1352697..21893e56 100644 --- a/dist/ngl.esm.js.map +++ b/dist/ngl.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"ngl.esm.js","sources":["../src/utils.ts","../src/utils/registry.ts","../src/math/math-utils.ts","../src/color/colormaker.ts","../src/selection/selection-constants.ts","../src/selection/selection-test.ts","../src/selection/selection.ts","../src/selection/selection-parser.ts","../src/color/selection-colormaker.ts","../src/color/colormaker-registry.ts","../src/worker/worker-utils.ts","../src/globals.ts","../src/worker/worker-registry.ts","../src/parser/parser-registry.ts","../src/streamer/streamer.ts","../src/streamer/file-streamer.ts","../src/streamer/network-streamer.ts","../src/loader/loader.ts","../src/loader/parser-loader.ts","../src/script.ts","../src/loader/script-loader.ts","../src/loader/loader-utils.ts","../src/writer/writer.ts","../src/writer/pdb-writer.ts","../src/writer/sdf-writer.ts","../src/utils/io-buffer.ts","../src/writer/stl-writer.ts","../src/utils/counter.ts","../src/viewer/stats.ts","../src/shader/shader-utils.ts","../src/viewer/viewer-constants.ts","../src/viewer/tiled-renderer.ts","../src/math/math-constants.ts","../src/math/array-utils.ts","../src/viewer/viewer-utils.ts","../src/viewer/gl-utils.ts","../src/viewer/viewer.ts","../src/constants.ts","../src/stage/mouse-observer.ts","../src/controls/trackball-controls.ts","../src/controls/picking-proxy.ts","../src/controls/picking-controls.ts","../src/controls/viewer-controls.ts","../src/animation/animation.ts","../src/controls/animation-controls.ts","../src/utils/queue.ts","../src/representation/representation.ts","../src/worker/worker.ts","../src/worker/worker-pool.ts","../src/math/vector-utils.ts","../src/geometry/dash.ts","../src/geometry/primitive.ts","../src/geometry/spatial-hash.ts","../src/store/store.ts","../src/store/contact-store.ts","../src/utils/bitarray.ts","../src/utils/adjacency-list.ts","../src/chemistry/interactions/features.ts","../src/structure/structure-constants.ts","../src/chemistry/geometry.ts","../src/chemistry/valence-model.ts","../src/structure/data.ts","../src/chemistry/functional-groups.ts","../src/chemistry/interactions/charged.ts","../src/chemistry/interactions/hydrogen-bonds.ts","../src/chemistry/interactions/metal-binding.ts","../src/chemistry/interactions/halogen-bonds.ts","../src/chemistry/interactions/refine-contacts.ts","../src/chemistry/interactions/contact.ts","../src/chemistry/interactions/hydrophobic.ts","../src/utils/picker.ts","../src/surface/marching-cubes.ts","../src/math/matrix-utils.ts","../src/surface/surface-utils.ts","../src/surface/surface.ts","../src/surface/volume.ts","../src/buffer/buffer.ts","../src/buffer/mesh-buffer.ts","../src/buffer/surface-buffer.ts","../src/buffer/doublesided-buffer.ts","../src/buffer/contour-buffer.ts","../src/representation/surface-representation.ts","../src/controls/mouse-actions.ts","../src/controls/mouse-controls.ts","../src/controls/key-actions.ts","../src/controls/key-controls.ts","../src/stage/picking-behavior.ts","../src/stage/mouse-behavior.ts","../src/stage/animation-behavior.ts","../src/stage/key-behavior.ts","../src/component/annotation.ts","../src/controls/component-controls.ts","../src/utils/radius-factory.ts","../src/math/principal-axes.ts","../src/surface/filtered-volume.ts","../src/store/bond-hash.ts","../src/store/bond-store.ts","../src/store/atom-store.ts","../src/store/residue-store.ts","../src/store/chain-store.ts","../src/store/model-store.ts","../src/geometry/helixorient.ts","../src/geometry/helixbundle.ts","../src/utils/binary-heap.ts","../src/utils/kdtree.ts","../src/proxy/atom-proxy.ts","../src/geometry/kdtree.ts","../src/symmetry/symmetry-constants.ts","../src/symmetry/symmetry-utils.ts","../src/symmetry/assembly.ts","../src/structure/structure-builder.ts","../src/structure/structure-utils.ts","../src/store/atom-type.ts","../src/store/atom-map.ts","../src/store/residue-type.ts","../src/store/residue-map.ts","../src/proxy/bond-proxy.ts","../src/proxy/residue-proxy.ts","../src/proxy/polymer.ts","../src/proxy/chain-proxy.ts","../src/proxy/model-proxy.ts","../src/structure/structure.ts","../src/geometry/shape.ts","../src/representation/buffer-representation.ts","../src/buffer/geometry-buffer.ts","../src/buffer/spheregeometry-buffer.ts","../src/buffer/mapped-buffer.ts","../src/buffer/mappedquad-buffer.ts","../src/buffer/sphereimpostor-buffer.ts","../src/buffer/sphere-buffer.ts","../src/buffer/point-buffer.ts","../src/representation/dot-representation.ts","../src/buffer/image-buffer.ts","../src/surface/volume-slice.ts","../src/representation/slice-representation.ts","../src/representation/representation-utils.ts","../src/component/element.ts","../src/component/representation-element.ts","../src/component/component.ts","../src/component/collection.ts","../src/component/representation-collection.ts","../src/component/trajectory-element.ts","../src/trajectory/frames.ts","../src/align/superposition.ts","../src/trajectory/trajectory-player.ts","../src/trajectory/trajectory.ts","../src/trajectory/frames-trajectory.ts","../src/trajectory/structure-trajectory.ts","../src/trajectory/remote-trajectory.ts","../src/trajectory/callback-trajectory.ts","../src/structure/structure-view.ts","../src/align/alignment.ts","../src/align/align-utils.ts","../src/component/structure-component.ts","../src/trajectory/trajectory-utils.ts","../src/component/surface-component.ts","../src/component/volume-component.ts","../src/component/component-collection.ts","../src/stage/stage.ts","../src/component/shape-component.ts","../node_modules/tslib/tslib.es6.js","../src/color/atomindex-colormaker.ts","../src/color/bfactor-colormaker.ts","../src/color/chainid-colormaker.ts","../src/color/chainindex-colormaker.ts","../src/color/chainname-colormaker.ts","../src/color/densityfit-colormaker.ts","../src/color/electrostatic-colormaker.ts","../src/color/element-colormaker.ts","../src/color/entityindex-colormaker.ts","../src/color/entitytype-colormaker.ts","../src/color/geoquality-colormaker.ts","../src/color/hydrophobicity-colormaker.ts","../src/color/modelindex-colormaker.ts","../src/color/moleculetype-colormaker.ts","../src/color/occupancy-colormaker.ts","../src/color/partialcharge-colormaker.ts","../src/color/random-colormaker.ts","../src/color/randomcoilindex-colormaker.ts","../src/color/residueindex-colormaker.ts","../src/color/resname-colormaker.ts","../src/color/sstruc-colormaker.ts","../src/color/structuredata-colormaker.ts","../src/color/uniform-colormaker.ts","../src/color/value-colormaker.ts","../src/color/volume-colormaker.ts","../src/representation/structure-representation.ts","../src/representation/measurement-representation.ts","../src/utils/edt.ts","../src/buffer/text-buffer.ts","../src/buffer/wideline-buffer.ts","../src/representation/angle-representation.ts","../src/buffer/cylindergeometry-buffer.ts","../src/buffer/mappedalignedbox-buffer.ts","../src/buffer/cylinderimpostor-buffer.ts","../src/buffer/cylinder-buffer.ts","../src/representation/axes-representation.ts","../src/representation/ballandstick-representation.ts","../src/representation/backbone-representation.ts","../src/representation/base-representation.ts","../src/geometry/spline.ts","../src/buffer/tubemesh-buffer.ts","../src/representation/cartoon-representation.ts","../src/representation/contact-representation.ts","../src/representation/dihedral-representation.ts","../src/representation/dihedral-histogram-representation.ts","../src/representation/distance-representation.ts","../src/buffer/vector-buffer.ts","../src/representation/helixorient-representation.ts","../src/representation/licorice-representation.ts","../src/buffer/mappedbox-buffer.ts","../src/buffer/hyperballstickimpostor-buffer.ts","../src/buffer/hyperballstick-buffer.ts","../src/representation/hyperball-representation.ts","../src/utils/label-factory.ts","../src/representation/label-representation.ts","../src/representation/line-representation.ts","../src/geometry/grid.ts","../src/surface/edt-surface.ts","../src/surface/av-surface.ts","../src/surface/molecular-surface.ts","../src/representation/molecularsurface-representation.ts","../src/representation/point-representation.ts","../src/buffer/ribbon-buffer.ts","../src/representation/ribbon-representation.ts","../src/representation/rocket-representation.ts","../src/representation/rope-representation.ts","../src/representation/spacefill-representation.ts","../src/buffer/trace-buffer.ts","../src/representation/trace-representation.ts","../src/representation/tube-representation.ts","../src/representation/unitcell-representation.ts","../src/representation/validation-representation.ts","../src/buffer/cone-buffer.ts","../src/viewer/geometry-group.ts","../src/buffer/arrow-buffer.ts","../src/buffer/box-buffer.ts","../src/buffer/ellipsoid-buffer.ts","../src/buffer/octahedron-buffer.ts","../src/buffer/tetrahedron-buffer.ts","../src/buffer/torus-buffer.ts","../node_modules/molstar/lib/mol-data/db/column-helpers.js","../node_modules/molstar/lib/mol-math/linear-algebra/3d/common.js","../node_modules/molstar/lib/mol-math/interpolate.js","../node_modules/molstar/lib/mol-math/linear-algebra/3d/vec3.js","../node_modules/molstar/lib/mol-math/misc.js","../node_modules/molstar/lib/mol-math/linear-algebra/3d/mat4.js","../node_modules/molstar/lib/mol-math/linear-algebra/3d/mat3.js","../node_modules/molstar/lib/mol-math/linear-algebra/3d/vec2.js","../node_modules/molstar/lib/mol-math/linear-algebra/3d/vec4.js","../node_modules/molstar/lib/mol-util/type-helpers.js","../node_modules/molstar/lib/mol-math/linear-algebra/3d/quat.js","../node_modules/molstar/lib/mol-math/linear-algebra/tensor.js","../node_modules/molstar/lib/mol-data/db/column.js","../node_modules/molstar/lib/mol-util/bit-flags.js","../node_modules/molstar/lib/mol-util/string-builder.js","../node_modules/molstar/lib/mol-io/reader/common/text/number-parser.js","../node_modules/molstar/lib/mol-data/util/sort.js","../node_modules/molstar/lib/mol-util/now.js","../node_modules/molstar/lib/mol-util/uuid.js","../node_modules/molstar/lib/mol-util/mask.js","../node_modules/molstar/lib/mol-util/value-cell.js","../node_modules/molstar/lib/mol-util/id-factory.js","../node_modules/molstar/lib/mol-data/db/table.js","../node_modules/molstar/lib/mol-data/db/database.js","../node_modules/molstar/lib/mol-io/reader/cif/data-model.js","../node_modules/molstar/lib/mol-io/reader/common/text/column/token.js","../node_modules/molstar/lib/mol-task/util/scheduler.js","../node_modules/molstar/lib/mol-util/debug.js","../node_modules/molstar/lib/mol-task/util/user-timing.js","../node_modules/molstar/lib/mol-task/execution/observable.js","../node_modules/molstar/lib/mol-task/execution/synchronous.js","../node_modules/molstar/lib/mol-task/task.js","../node_modules/molstar/lib/mol-task/execution/runtime-context.js","../node_modules/molstar/lib/mol-task/execution/progress.js","../node_modules/molstar/lib/mol-io/reader/common/text/tokenizer.js","../node_modules/molstar/lib/mol-io/reader/result.js","../node_modules/molstar/lib/mol-io/common/binary-cif/encoding.js","../node_modules/molstar/lib/mol-task/util/chunked.js","../node_modules/molstar/lib/mol-io/reader/cif/text/parser.js","../node_modules/molstar/lib/mol-io/common/binary.js","../node_modules/molstar/lib/mol-io/common/binary-cif/decoder.js","../node_modules/molstar/lib/mol-data/util/chunked-array.js","../node_modules/molstar/lib/mol-io/common/binary-cif/classifier.js","../node_modules/molstar/lib/mol-io/common/binary-cif/array-encoder.js","../node_modules/molstar/lib/mol-util/number.js","../node_modules/molstar/lib/mol-io/common/utf8.js","../node_modules/molstar/lib/mol-io/common/msgpack/decode.js","../node_modules/molstar/lib/mol-io/reader/cif/binary/parser.js","../node_modules/molstar/lib/mol-io/reader/cif/binary/field.js","../node_modules/molstar/lib/mol-io/reader/cif/schema.js","../node_modules/molstar/lib/mol-util/index.js","../node_modules/molstar/lib/mol-io/reader/cif/schema/mmcif.js","../node_modules/molstar/lib/mol-io/reader/cif/schema/ccd.js","../node_modules/molstar/lib/mol-io/reader/cif/schema/bird.js","../node_modules/molstar/lib/mol-io/reader/cif/schema/dic.js","../node_modules/molstar/lib/mol-io/reader/cif/schema/density-server.js","../node_modules/molstar/lib/mol-io/reader/cif/schema/cif-core.js","../node_modules/molstar/lib/mol-io/reader/cif/schema/segmentation.js","../node_modules/molstar/lib/mol-io/reader/cif.js","../src/parser/parser.ts","../src/parser/structure-parser.ts","../src/structure/entity.ts","../src/symmetry/unitcell.ts","../src/parser/pdb-parser.ts","../src/store/chemcomp-map.ts","../src/parser/cif-parser.ts","../src/parser/gro-parser.ts","../lib/mmtf.es6.js","../src/parser/mmtf-parser.ts","../src/parser/mol2-parser.ts","../src/parser/pdbqt-parser.ts","../src/parser/pqr-parser.ts","../src/parser/sdf-parser.ts","../src/parser/prmtop-parser.ts","../src/parser/psf-parser.ts","../src/parser/top-parser.ts","../src/parser/trajectory-parser.ts","../src/utils/netcdf-reader.ts","../src/parser/dcd-parser.ts","../src/parser/nctraj-parser.ts","../src/parser/trr-parser.ts","../src/parser/xtc-parser.ts","../src/parser/volume-parser.ts","../src/parser/cube-parser.ts","../src/parser/dsn6-parser.ts","../src/parser/dx-parser.ts","../src/parser/dxbin-parser.ts","../src/parser/mrc-parser.ts","../src/parser/xplor-parser.ts","../src/parser/kin-parser.ts","../src/parser/surface-parser.ts","../src/parser/obj-parser.ts","../src/parser/csv-parser.ts","../src/parser/json-parser.ts","../src/parser/msgpack-parser.ts","../src/parser/netcdf-parser.ts","../src/parser/text-parser.ts","../src/utils/parse-xml.ts","../src/parser/xml-parser.ts","../src/structure/validation.ts","../lib/pako_inflate.es6.js","../src/parser/validation-parser.ts","../src/utils/gzip-decompressor.ts","../src/datasource/datasource.ts","../src/datasource/rcsb-datasource.ts","../src/datasource/pdbe-datasource.ts","../src/datasource/pubchem-datasource.ts","../src/datasource/passthrough-datasource.ts","../src/datasource/alphafold-datasource.ts","../src/datasource/static-datasource.ts","../src/datasource/mdsrv-datasource.ts","../src/ui/parameters.ts","../src/version.ts"],"sourcesContent":["/**\n * @file Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector2, Vector3, Matrix4, Quaternion } from 'three'\n\nexport function getQuery (id: string) {\n if (typeof window === 'undefined') return undefined\n\n const a = new RegExp(`${id}=([^&#=]*)`)\n const m = a.exec(window.location.search)\n\n if (m) {\n return decodeURIComponent(m[1])\n } else {\n return undefined\n }\n}\n\nexport function boolean (value: any) {\n if (!value) {\n return false\n }\n\n if (typeof value === 'string') {\n return /^1|true|t|yes|y$/i.test(value)\n }\n\n return true\n}\n\nexport function defaults (value: any, defaultValue: any) {\n return value !== undefined ? value : defaultValue\n}\n\nexport function createParams (params: {[k in keyof T]?: any}, defaultParams: T) {\n const o: any = Object.assign({}, params)\n for (const k in defaultParams) {\n const value = params[k]\n if (value === undefined) o[k] = defaultParams[k]\n }\n return o as T\n}\n\nexport function updateParams (params: T, newParams: {[k in keyof T]?: any}) {\n for (const k in newParams) {\n const value = newParams[k]\n if (value !== undefined) params[k] = value\n }\n return params as T\n}\n\nexport function pick (object: { [index: string]: any }) {\n const properties = [].slice.call(arguments, 1)\n return properties.reduce((a: { [index: string]: any }, e: any) => {\n a[ e ] = object[ e ]\n return a\n }, {})\n}\n\nexport function flatten (array: any[], ret: any[]) {\n ret = defaults(ret, [])\n for (let i = 0; i < array.length; i++) {\n if (Array.isArray(array[i])) {\n flatten(array[i], ret)\n } else {\n ret.push(array[i])\n }\n }\n return ret\n}\n\nexport function getProtocol () {\n const protocol = window.location.protocol\n return protocol.match(/http(s)?:/gi) === null ? 'http:' : protocol\n}\n\nexport function getBrowser () {\n if (typeof window === 'undefined') return false\n\n const ua = window.navigator.userAgent\n\n if (/Opera|OPR/.test(ua)) {\n return 'Opera'\n } else if (/Chrome/i.test(ua)) {\n return 'Chrome'\n } else if (/Firefox/i.test(ua)) {\n return 'Firefox'\n } else if (/Mobile(\\/.*)? Safari/i.test(ua)) {\n return 'Mobile Safari'\n } else if (/MSIE/i.test(ua)) {\n return 'Internet Explorer'\n } else if (/Safari/i.test(ua)) {\n return 'Safari'\n }\n\n return false\n}\n\nexport function getAbsolutePath (relativePath: string) {\n const loc = window.location\n const pn = loc.pathname\n const basePath = pn.substring(0, pn.lastIndexOf('/') + 1)\n\n return loc.origin + basePath + relativePath\n}\n\nexport function deepCopy (src: any) {\n if (typeof src !== 'object') {\n return src\n }\n\n const dst: { [index: string]: any } = Array.isArray(src) ? [] : {}\n\n for (let key in src) {\n dst[ key ] = deepCopy(src[ key ])\n }\n\n return dst\n}\n\nexport function deepEqual(a: any, b: any) {\n // from https://github.com/epoberezkin/fast-deep-equal MIT\n if (a === b) return true;\n\n const arrA = Array.isArray(a)\n const arrB = Array.isArray(b)\n\n if (arrA && arrB) {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!deepEqual(a[i], b[i])) return false\n }\n return true\n }\n\n if (arrA !== arrB) return false\n\n if (a && b && typeof a === 'object' && typeof b === 'object') {\n const keys = Object.keys(a)\n if (keys.length !== Object.keys(b).length) return false;\n\n const dateA = a instanceof Date\n const dateB = b instanceof Date\n if (dateA && dateB) return a.getTime() === b.getTime()\n if (dateA !== dateB) return false\n\n const regexpA = a instanceof RegExp\n const regexpB = b instanceof RegExp\n if (regexpA && regexpB) return a.toString() === b.toString()\n if (regexpA !== regexpB) return false\n\n for (let i = 0; i < keys.length; i++) {\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false\n }\n\n for (let i = 0; i < keys.length; i++) {\n if(!deepEqual(a[keys[i]], b[keys[i]])) return false\n }\n\n return true\n }\n\n return false\n}\n\nfunction openUrl (url: string) {\n const opened = window.open(url, '_blank')\n if (!opened) {\n window.location.href = url\n }\n}\n\nexport function download (data: Blob|string, downloadName = 'download') {\n // using ideas from https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js\n\n if (!data) return\n\n const isSafari = getBrowser() === 'Safari'\n const isChromeIos = /CriOS\\/[\\d]+/.test(window.navigator.userAgent)\n\n const a = document.createElement('a')\n\n function open (str: string) {\n openUrl(isChromeIos ? str : str.replace(/^data:[^;]*;/, 'data:attachment/file;'))\n }\n\n if (typeof navigator !== 'undefined' && (navigator as any).msSaveOrOpenBlob) {\n // native saveAs in IE 10+\n (navigator as any).msSaveOrOpenBlob(data, downloadName)\n } else if ((isSafari || isChromeIos) && FileReader) {\n if (data instanceof Blob) {\n // no downloading of blob urls in Safari\n var reader = new FileReader()\n reader.onloadend = function () {\n open(reader.result as string)\n }\n reader.readAsDataURL(data)\n } else {\n open(data)\n }\n } else {\n let objectUrlCreated = false\n if (data instanceof Blob) {\n data = URL.createObjectURL(data)\n objectUrlCreated = true\n }\n\n if ('download' in a) {\n // download link available\n a.style.display = 'hidden'\n document.body.appendChild(a)\n a.href = data\n a.download = downloadName\n a.target = '_blank'\n a.click()\n document.body.removeChild(a)\n } else {\n openUrl(data)\n }\n\n if (objectUrlCreated) {\n window.URL.revokeObjectURL(data)\n }\n }\n}\n\nexport function submit (url: string, data: FormData, callback: Function, onerror: Function) {\n const xhr = new XMLHttpRequest()\n xhr.open('POST', url)\n\n xhr.addEventListener('load', function () {\n if (xhr.status === 200 || xhr.status === 304) {\n callback(xhr.response)\n } else {\n if (typeof onerror === 'function') {\n onerror(xhr.status)\n }\n }\n }, false)\n\n xhr.send(data)\n}\n\ninterface HTMLInputEvent extends Event {\n target: HTMLInputElement & EventTarget\n}\n\nexport function open (callback: Function, extensionList = ['*']) {\n const fileInput = document.createElement('input')\n fileInput.type = 'file'\n fileInput.multiple = true\n fileInput.style.display = 'hidden'\n document.body.appendChild(fileInput)\n fileInput.accept = '.' + extensionList.join(',.')\n fileInput.addEventListener('change', function (e: HTMLInputEvent) {\n callback(e.target.files)\n }, false)\n\n fileInput.click()\n}\n\nexport function throttle (func: Function, wait: number, options: { leading?: boolean, trailing?: boolean }) {\n // from http://underscorejs.org/docs/underscore.html\n\n let context: any\n let args: any\n let result: any\n let timeout: any = null\n let previous = 0\n\n if (!options) options = {}\n\n function later () {\n previous = options.leading === false ? 0 : Date.now()\n timeout = null\n result = func.apply(context, args)\n if (!timeout) context = args = null\n }\n\n return function throttle (this: any) {\n var now = Date.now()\n if (!previous && options.leading === false) previous = now\n var remaining = wait - (now - previous)\n context = this\n args = arguments\n if (remaining <= 0 || remaining > wait) {\n if (timeout) {\n clearTimeout(timeout)\n timeout = null\n }\n previous = now\n result = func.apply(context, args)\n if (!timeout) context = args = null\n } else if (!timeout && options.trailing !== false) {\n timeout = setTimeout(later, remaining)\n }\n\n return result\n }\n}\n\nexport function lexicographicCompare (elm1: T, elm2: T) {\n if (elm1 < elm2) return -1\n if (elm1 > elm2) return 1\n return 0\n}\n\n/**\n * Does a binary search to get the index of an element in the input array\n * @function\n * @example\n * var array = [ 1, 2, 3, 4, 5, 6 ];\n * var element = 4;\n * binarySearchIndexOf( array, element ); // returns 3\n *\n * @param {Array} array - sorted array\n * @param {Anything} element - element to search for in the array\n * @param {Function} [compareFunction] - compare function\n * @return {Number} the index of the element or -1 if not in the array\n */\nexport function binarySearchIndexOf (array: T[], element: T, compareFunction = lexicographicCompare) {\n let low = 0\n let high = array.length - 1\n while (low <= high) {\n const mid = (low + high) >> 1\n const cmp = compareFunction(element, array[ mid ])\n if (cmp > 0) {\n low = mid + 1\n } else if (cmp < 0) {\n high = mid - 1\n } else {\n return mid\n }\n }\n return -low - 1\n}\n\nexport function binarySearchForLeftRange (array: number[], leftRange: number) {\n let high = array.length - 1\n if (array[ high ] < leftRange) return -1\n let low = 0\n while (low <= high) {\n const mid = (low + high) >> 1\n if (array[ mid ] >= leftRange) {\n high = mid - 1\n } else {\n low = mid + 1\n }\n }\n return high + 1\n}\n\nexport function binarySearchForRightRange (array: number[], rightRange: number) {\n if (array[ 0 ] > rightRange) return -1\n let low = 0\n let high = array.length - 1\n while (low <= high) {\n const mid = (low + high) >> 1\n if (array[ mid ] > rightRange) {\n high = mid - 1\n } else {\n low = mid + 1\n }\n }\n return low - 1\n}\n\nexport function rangeInSortedArray (array: number[], min: number, max: number) {\n const indexLeft = binarySearchForLeftRange(array, min)\n const indexRight = binarySearchForRightRange(array, max)\n if (indexLeft === -1 || indexRight === -1 || indexLeft > indexRight) {\n return 0\n } else {\n return indexRight - indexLeft + 1\n }\n}\n\nexport function dataURItoImage (dataURI: string) {\n const img = document.createElement('img')\n img.src = dataURI\n return img\n}\n\nexport function uniqueArray (array: any[]) {\n return array.sort().filter(function (value, index, sorted) {\n return (index === 0) || (value !== sorted[ index - 1 ])\n })\n}\n\n// String/arraybuffer conversion\n\nexport function uint8ToString (u8a: Uint8Array) {\n const chunkSize = 0x7000\n\n if (u8a.length > chunkSize) {\n const c = []\n\n for (let i = 0; i < u8a.length; i += chunkSize) {\n c.push(String.fromCharCode.apply(\n null, u8a.subarray(i, i + chunkSize)\n ))\n }\n\n return c.join('')\n } else {\n return String.fromCharCode.apply(null, u8a)\n }\n}\n\nexport function uint8ToLines (u8a: Uint8Array, chunkSize = 1024 * 1024 * 10, newline = '\\n') {\n let partialLine = ''\n let lines: string[] = []\n\n for (let i = 0; i < u8a.length; i += chunkSize) {\n const str = uint8ToString(u8a.subarray(i, i + chunkSize))\n const idx = str.lastIndexOf(newline)\n\n if (idx === -1) {\n partialLine += str\n } else {\n const str2 = partialLine + str.substr(0, idx)\n lines = lines.concat(str2.split(newline))\n\n if (idx === str.length - newline.length) {\n partialLine = ''\n } else {\n partialLine = str.substr(idx + newline.length)\n }\n }\n }\n\n if (partialLine !== '') {\n lines.push(partialLine)\n }\n\n return lines\n}\n\nexport type TypedArrayString = 'int8'|'int16'|'int32'|'uint8'|'uint16'|'uint32'|'float32'\nexport function getTypedArray (arrayType: TypedArrayString, arraySize: number) {\n switch (arrayType) {\n case 'int8':\n return new Int8Array(arraySize)\n case 'int16':\n return new Int16Array(arraySize)\n case 'int32':\n return new Int32Array(arraySize)\n case 'uint8':\n return new Uint8Array(arraySize)\n case 'uint16':\n return new Uint16Array(arraySize)\n case 'uint32':\n return new Uint32Array(arraySize)\n case 'float32':\n return new Float32Array(arraySize)\n default:\n throw new Error('arrayType unknown: ' + arrayType)\n }\n}\n\nexport function getUintArray (sizeOrArray: any, maxUint: number) { // TODO\n const TypedArray = maxUint > 65535 ? Uint32Array : Uint16Array\n return new TypedArray(sizeOrArray)\n}\n\nexport function ensureArray (value: any) {\n return Array.isArray(value) ? value : [value]\n}\n\nexport function ensureBuffer (a: any) { // TODO\n return (a.buffer && a.buffer instanceof ArrayBuffer) ? a.buffer : a\n}\n\nfunction _ensureClassFromArg (arg: any, constructor: { new (arg: any): any }) {\n return arg instanceof constructor ? arg : new constructor(arg)\n}\n\nfunction _ensureClassFromArray (array: any, constructor: { new (): any }) {\n if (array === undefined) {\n array = new constructor()\n } else if (Array.isArray(array)) {\n array = new constructor().fromArray(array)\n }\n return array\n}\n\nexport function ensureVector2 (v?: number[]|Vector2) {\n return _ensureClassFromArray(v, Vector2)\n}\n\nexport function ensureVector3 (v?: number[]|Vector3) {\n return _ensureClassFromArray(v, Vector3)\n}\n\nexport function ensureMatrix4 (m?: number[]|Matrix4) {\n return _ensureClassFromArray(m, Matrix4)\n}\n\nexport function ensureQuaternion (q?: number[]|Quaternion) {\n return _ensureClassFromArray(q, Quaternion)\n}\n\nexport function ensureFloat32Array (a?: number[]|Float32Array) {\n return _ensureClassFromArg(a, Float32Array)\n}\n\nexport interface RingBuffer {\n has: (value: T) => boolean\n get: (value: number) => T\n push: (value: T) => void\n count: number\n data: T[]\n clear: () => void\n}\n\nexport function createRingBuffer (length: number): RingBuffer {\n let pointer = 0\n let count = 0\n const buffer: T[] = []\n\n return {\n has: function (value: any) { return buffer.indexOf(value) !== -1 },\n get: function (idx: number) { return buffer[idx] },\n push: function (item: any) {\n buffer[pointer] = item\n pointer = (length + pointer + 1) % length\n ++count\n },\n get count () { return count },\n get data () { return buffer.slice(0, Math.min(count, length)) },\n clear: function () {\n count = 0\n pointer = 0\n buffer.length = 0\n }\n }\n}\n\nexport interface SimpleDict {\n has: (k: K) => boolean\n add: (k: K, v: V) => void\n del: (k: K) => void\n values: V[]\n}\n\nexport function createSimpleDict (): SimpleDict {\n const set: { [k: string]: V } = {}\n\n return {\n has: function (k: K) { return set[JSON.stringify(k)] !== undefined },\n add: function (k: K, v: V) { set[JSON.stringify(k)] = v },\n del: function (k: K) { delete set[JSON.stringify(k)] },\n get values () { return Object.keys(set).map(k => set[k]) }\n }\n}\n\nexport interface SimpleSet {\n has: (value: T) => boolean\n add: (value: T) => void\n del: (value: T) => void\n list: T[]\n}\n\nexport function createSimpleSet (): SimpleSet {\n const set: { [k: string]: T } = {}\n\n return {\n has: function (v: T) { return set[JSON.stringify(v)] !== undefined },\n add: function (v: T) { set[JSON.stringify(v)] = v },\n del: function (v: T) { delete set[JSON.stringify(v)] },\n get list () { return Object.keys(set).map(k => set[k]) },\n }\n}\n","/**\n * @file Registry\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\n\nfunction toLowerCaseString (value: string) {\n return defaults(value, '').toString().toLowerCase()\n}\n\nexport default class Registry {\n name: string\n private _dict: {[k: string]: any}\n\n constructor (name: string) {\n this.name = name\n this._dict = {}\n }\n\n add (key: string, value: any) {\n this._dict[ toLowerCaseString(key) ] = value\n }\n\n get (key: string) {\n return this._dict[ toLowerCaseString(key) ]\n }\n\n get names () {\n return Object.keys(this._dict)\n }\n}","/**\n * @file Math Utils\n * @author Alexander Rose \n * @private\n */\n\nexport function degToRad (deg: number) {\n return deg * 0.01745 // deg * Math.PI / 180\n}\n\nexport function radToDeg (rad: number) {\n return rad * 57.29578 // rad * 180 / Math.PI\n}\n\n// http://www.broofa.com/Tools/Math.uuid.htm\nconst chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')\nconst uuid = new Array(36)\n\nexport function generateUUID () {\n let rnd = 0\n let r\n\n for (let i = 0; i < 36; i++) {\n if (i === 8 || i === 13 || i === 18 || i === 23) {\n uuid[ i ] = '-'\n } else if (i === 14) {\n uuid[ i ] = '4'\n } else {\n if (rnd <= 0x02) rnd = 0x2000000 + (Math.random() * 0x1000000) | 0\n r = rnd & 0xf\n rnd = rnd >> 4\n uuid[ i ] = chars[ (i === 19) ? (r & 0x3) | 0x8 : r ]\n }\n }\n\n return uuid.join('')\n}\n\nexport function countSetBits (i: number) {\n i = i - ((i >> 1) & 0x55555555)\n i = (i & 0x33333333) + ((i >> 2) & 0x33333333)\n return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24\n}\n\nexport function normalize (value: number, min: number, max: number) {\n return (value - min) / (max - min)\n}\n\nexport function clamp (value: number, min: number, max: number) {\n return Math.max(min, Math.min(max, value))\n}\n\nexport function pclamp (value: number) {\n return clamp(value, 0, 100)\n}\n\nexport function saturate (value: number) {\n return clamp(value, 0, 1)\n}\n\nexport function lerp (start: number, stop: number, alpha: number) {\n return start + (stop - start) * alpha\n}\n\nexport function spline (p0: number, p1: number, p2: number, p3: number, t: number, tension: number) {\n const v0 = (p2 - p0) * tension\n const v1 = (p3 - p1) * tension\n const t2 = t * t\n const t3 = t * t2\n return (2 * p1 - 2 * p2 + v0 + v1) * t3 +\n (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 +\n v0 * t + p1\n}\n\nexport function smoothstep (min: number, max: number, x: number) {\n x = saturate(normalize(x, min, max))\n return x * x * (3 - 2 * x)\n}\n\nexport function smootherstep (min: number, max: number, x: number) {\n x = saturate(normalize(x, min, max))\n return x * x * x * (x * (x * 6 - 15) + 10)\n}\n\nexport function smootheststep (min: number, max: number, x: number) {\n x = saturate(normalize(x, min, max))\n return (\n -20 * Math.pow(x, 7) +\n 70 * Math.pow(x, 6) -\n 84 * Math.pow(x, 5) +\n 35 * Math.pow(x, 4)\n )\n}\n\nexport function almostIdentity (value: number, start: number, stop: number) {\n if (value > start) return value\n const a = 2 * stop - start\n const b = 2 * start - 3 * stop\n const t = value / start\n return (a * t + b) * t * t + stop\n}","/**\n * @file Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Color } from 'three'\nimport * as chroma from 'chroma-js'\n\nimport { createParams } from '../utils'\nimport { NumberArray } from '../types'\nimport Structure from '../structure/structure'\nimport Surface from '../surface/surface'\nimport Volume from '../surface/volume'\nimport AtomProxy from '../proxy/atom-proxy'\nimport BondProxy from '../proxy/bond-proxy'\n\nexport type ColorMode = 'rgb'|'hsv'|'hsl'|'hsi'|'lab'|'hcl'\nexport type ColorSpace = 'sRGB' | 'linear'\n\n/**\n * Internal color space for all colors (global).\n * Colors are always specified as sRGB; if this is set to\n * 'linear' then colors get linearized when used internally\n * as vertex or texture colors.\n * @see setColorSpace/getColorSpace.\n */\nvar colorSpace: ColorSpace = 'sRGB' // default: don't linearize\n\n/** Set the global internal color space for colormakers */\nexport function setColorSpace(space: ColorSpace) {\n colorSpace = space\n}\n\n/** Get the global internal color space for colormakers */\nexport function getColorSpace() {\n return colorSpace\n}\n\nexport const ScaleDefaultParameters = {\n scale: 'uniform' as string|string[],\n mode: 'hcl' as ColorMode,\n domain: [ 0, 1 ] as number[],\n value: 0xFFFFFF,\n reverse: false,\n}\nexport type ScaleParameters = typeof ScaleDefaultParameters\n\nexport interface ColorData {\n atomData?: number[],\n bondData?: number[]\n}\n\nexport interface ColormakerParameters extends ScaleParameters {\n structure?: Structure\n volume?: Volume\n surface?: Surface\n data?: ColorData\n}\n\nexport type StuctureColormakerParams = { structure: Structure } & Partial\nexport type VolumeColormakerParams = { volume: Volume } & Partial\nexport type ColormakerScale = (v: number) => number\nexport type ColormakerConstructor = new (...p: ConstructorParameters) => Colormaker\n\nconst tmpColor = new Color()\n\n/** Decorator for optionally linearizing a numeric color */\ntype colorFuncType = (value: any, fromTo?: boolean) => number // decorator applies to functions with this shape\nexport function manageColor\n (_target: Object,\n _name: string | symbol,\n descriptor: TypedPropertyDescriptor): PropertyDescriptor {\n const originalMethod = descriptor.value\n const linearize: colorFuncType = function (this: T, value: any, fromTo?: boolean) {\n let result = originalMethod!.bind(this, value, fromTo)()\n if (colorSpace == 'linear') {\n tmpColor.set(result)\n tmpColor.convertSRGBToLinear()\n return tmpColor.getHex()\n } else {\n return result\n }\n }\n descriptor.value = linearize\n return descriptor\n }\n\n/**\n * Class for making colors.\n * @interface\n */\nabstract class Colormaker {\n parameters: ColormakerParameters\n atomProxy?: AtomProxy\n\n /**\n * Create a colormaker instance\n * @param {ColormakerParameters} params - colormaker parameter\n */\n constructor (params: Partial = {}) {\n this.parameters = createParams(params, ScaleDefaultParameters)\n\n if (typeof this.parameters.value === 'string') {\n this.parameters.value = tmpColor.set(this.parameters.value).getHex()\n }\n\n if (this.parameters.structure) {\n this.atomProxy = this.parameters.structure.getAtomProxy()\n }\n }\n\n getScale (params: Partial = {}) {\n const p = createParams(params, this.parameters)\n\n if (p.scale === 'rainbow') {\n p.scale = [ 'red', 'orange', 'yellow', 'green', 'blue' ]\n } else if (p.scale === 'rwb') {\n p.scale = [ 'red', 'white', 'blue' ]\n }\n\n if (p.reverse) {\n p.domain = p.domain.slice().reverse()\n }\n return chroma\n .scale(p.scale as any) // TODO\n .mode(p.mode)\n .domain(p.domain)\n .out('num' as any) // returns RGB color as numeric (not string \"#ffffff\")\n }\n\n /**\n * save a color to an array\n * @param {Integer} color - hex color value\n * @param {Array|TypedArray} array - destination\n * @param {Integer} offset - index into the array\n * @return {Array} the destination array\n */\n colorToArray (color: number, array: NumberArray = [], offset = 0) {\n array[ offset ] = (color >> 16 & 255) / 255\n array[ offset + 1 ] = (color >> 8 & 255) / 255\n array[ offset + 2 ] = (color & 255) / 255\n\n return array\n }\n\n atomColor? (atom: AtomProxy): number\n\n /**\n * save an atom color to an array\n * @param {AtomProxy} atom - atom to get color for\n * @param {Array|TypedArray} array - destination\n * @param {Integer} offset - index into the array\n * @return {Array} the destination array\n */\n atomColorToArray (atom: AtomProxy, array: NumberArray, offset: number) {\n return this.colorToArray(\n this.atomColor ? this.atomColor(atom) : 0x000000, array, offset\n )\n }\n\n /**\n * return the color for an bond\n * @param {BondProxy} bond - bond to get color for\n * @param {Boolean} fromTo - whether to use the first or second atom of the bond\n * @return {Integer} hex bond color\n */\n bondColor (bond: BondProxy, fromTo: boolean) {\n if (this.atomProxy && this.atomColor) {\n this.atomProxy.index = fromTo ? bond.atomIndex1 : bond.atomIndex2\n return this.atomColor(this.atomProxy)\n } else {\n return 0x000000\n }\n }\n\n /**\n * safe a bond color to an array\n * @param {BondProxy} bond - bond to get color for\n * @param {Boolean} fromTo - whether to use the first or second atom of the bond\n * @param {Array|TypedArray} array - destination\n * @param {Integer} offset - index into the array\n * @return {Array} the destination array\n */\n bondColorToArray (bond: BondProxy, fromTo: boolean, array: NumberArray, offset: number) {\n return this.colorToArray(\n this.bondColor(bond, fromTo), array, offset\n )\n }\n\n volumeColor? (index: number): number\n\n /**\n * safe a volume cell color to an array\n * @param {Integer} index - volume cell index\n * @param {Array|TypedArray} array - destination\n * @param {Integer} offset - index into the array\n * @return {Array} the destination array\n */\n volumeColorToArray (index: number, array: NumberArray, offset: number) {\n return this.colorToArray(\n this.volumeColor ? this.volumeColor(index) : 0x000000, array, offset\n )\n }\n\n positionColor? (position: Vector3): number\n\n /**\n * safe a color for coordinates in space to an array\n * @param {Vector3} coords - xyz coordinates\n * @param {Array|TypedArray} array - destination\n * @param {Integer} offset - index into the array\n * @return {Array} the destination array\n */\n positionColorToArray (coords: Vector3, array: NumberArray, offset: number) {\n return this.colorToArray(\n this.positionColor ? this.positionColor(coords) : 0x000000, array, offset\n )\n }\n}\n\nexport default Colormaker\n","/**\n * @file Selection Constants\n * @author Alexander Rose \n * @private\n */\n\nexport enum kwd {\n PROTEIN = 1,\n NUCLEIC = 2,\n RNA = 3,\n DNA = 4,\n POLYMER = 5,\n WATER = 6,\n HELIX = 7,\n SHEET = 8,\n TURN = 9,\n BACKBONE = 10,\n SIDECHAIN = 11,\n ALL = 12,\n HETERO = 13,\n ION = 14,\n SACCHARIDE = 15,\n SUGAR = 15,\n BONDED = 16,\n RING = 17,\n AROMATICRING = 18,\n METAL = 19,\n POLARH = 20,\n NONE = 21\n}\n\nexport const SelectAllKeyword = [ '*', '', 'ALL' ]\nexport const SelectNoneKeyword = [ 'NONE' ]\n\nexport const AtomOnlyKeywords = [\n kwd.BACKBONE, kwd.SIDECHAIN, kwd.BONDED, kwd.RING, kwd.AROMATICRING, kwd.METAL, kwd.POLARH\n]\n\nexport const ChainKeywords = [\n kwd.POLYMER, kwd.WATER\n]\n\nexport const SmallResname = [ 'ALA', 'GLY', 'SER' ]\nexport const NucleophilicResname = [ 'CYS', 'SER', 'THR' ]\nexport const HydrophobicResname = [ 'ALA', 'ILE', 'LEU', 'MET', 'PHE', 'PRO', 'TRP', 'VAL' ]\nexport const AromaticResname = [ 'PHE', 'TRP', 'TYR', 'HIS' ]\nexport const AmideResname = [ 'ASN', 'GLN' ]\nexport const AcidicResname = [ 'ASP', 'GLU' ]\nexport const BasicResname = [ 'ARG', 'HIS', 'LYS' ]\nexport const ChargedResname = [ 'ARG', 'ASP', 'GLU', 'HIS', 'LYS' ]\nexport const PolarResname = [ 'ASN', 'ARG', 'ASP', 'CYS', 'GLY', 'GLN', 'GLU', 'HIS', 'LYS', 'SER', 'THR', 'TYR' ]\nexport const NonpolarResname = [ 'ALA', 'ILE', 'LEU', 'MET', 'PHE', 'PRO', 'TRP', 'VAL' ]\nexport const CyclicResname = [ 'HIS', 'PHE', 'PRO', 'TRP', 'TYR' ]\nexport const AliphaticResname = [ 'ALA', 'GLY', 'ILE', 'LEU', 'VAL' ]\n","/**\n * @file Selection Test\n * @author Alexander Rose \n * @private\n */\n\nimport { binarySearchIndexOf, rangeInSortedArray } from '../utils'\nimport { kwd, AtomOnlyKeywords, ChainKeywords } from './selection-constants'\n\nimport AtomProxy from '../proxy/atom-proxy'\nimport ResidueProxy from '../proxy/residue-proxy'\nimport ChainProxy from '../proxy/chain-proxy'\nimport ModelProxy from '../proxy/model-proxy'\n\nexport type ProxyEntity = AtomProxy|ResidueProxy|ChainProxy|ModelProxy\ntype TestEntityFn = (e: ProxyEntity, s: SelectionRule) => boolean|-1\ntype FilterFn = (s: SelectionRule) => boolean\nexport type SelectionTest = false|((e: ProxyEntity) => boolean|-1)\n\nexport type SelectionOperator = 'AND'|'OR'\nexport interface SelectionRule {\n keyword?: any\n atomname?: string\n element?: string\n atomindex?: number[]\n altloc?: string\n inscode?: string\n resname?: string|string[]\n sstruc?: string\n resno?: number|[number, number]\n chainname?: string\n model?: number\n\n error?: string\n rules?: SelectionRule[]\n negate?: boolean\n operator?: SelectionOperator\n}\n\nfunction atomTestFn (a: AtomProxy, s: SelectionRule) {\n // returning -1 means the rule is not applicable\n if (s.atomname === undefined && s.element === undefined &&\n s.altloc === undefined && s.atomindex === undefined &&\n s.keyword === undefined && s.inscode === undefined &&\n s.resname === undefined && s.sstruc === undefined &&\n s.resno === undefined && s.chainname === undefined &&\n s.model === undefined\n ) return -1\n\n if (s.keyword !== undefined) {\n if (s.keyword === kwd.BACKBONE && !a.isBackbone()) return false\n if (s.keyword === kwd.SIDECHAIN && !a.isSidechain()) return false\n if (s.keyword === kwd.BONDED && !a.isBonded()) return false\n if (s.keyword === kwd.RING && !a.isRing()) return false\n if (s.keyword === kwd.AROMATICRING && !a.isAromatic()) return false\n\n if (s.keyword === kwd.HETERO && !a.isHetero()) return false\n if (s.keyword === kwd.PROTEIN && !a.isProtein()) return false\n if (s.keyword === kwd.NUCLEIC && !a.isNucleic()) return false\n if (s.keyword === kwd.RNA && !a.isRna()) return false\n if (s.keyword === kwd.DNA && !a.isDna()) return false\n if (s.keyword === kwd.POLYMER && !a.isPolymer()) return false\n if (s.keyword === kwd.WATER && !a.isWater()) return false\n if (s.keyword === kwd.HELIX && !a.isHelix()) return false\n if (s.keyword === kwd.SHEET && !a.isSheet()) return false\n if (s.keyword === kwd.TURN && !a.isTurn()) return false\n if (s.keyword === kwd.ION && !a.isIon()) return false\n if (s.keyword === kwd.SACCHARIDE && !a.isSaccharide()) return false\n if (s.keyword === kwd.METAL && !a.isMetal()) return false\n if (s.keyword === kwd.POLARH && !a.isPolarHydrogen()) return false\n }\n\n if (s.atomname !== undefined && s.atomname !== a.atomname) return false\n if (s.element !== undefined && s.element !== a.element) return false\n if (s.altloc !== undefined && s.altloc !== a.altloc) return false\n\n if (s.atomindex !== undefined &&\n binarySearchIndexOf(s.atomindex, a.index) < 0\n ) return false\n\n if (s.resname !== undefined) {\n if (Array.isArray(s.resname)) {\n if (!s.resname.includes(a.resname)) return false\n } else {\n if (s.resname !== a.resname) return false\n }\n }\n if (s.sstruc !== undefined && s.sstruc !== a.sstruc) return false\n if (s.resno !== undefined) {\n if (Array.isArray(s.resno) && s.resno.length === 2) {\n if (s.resno[0] > a.resno || s.resno[1] < a.resno) return false\n } else {\n if (s.resno !== a.resno) return false\n }\n }\n if (s.inscode !== undefined && s.inscode !== a.inscode) return false\n\n if (s.chainname !== undefined && s.chainname !== a.chainname) return false\n if (s.model !== undefined && s.model !== a.modelIndex) return false\n\n return true\n}\n\nfunction residueTestFn (r: ResidueProxy, s: SelectionRule) {\n // returning -1 means the rule is not applicable\n if (s.resname === undefined && s.resno === undefined && s.inscode === undefined &&\n s.sstruc === undefined && s.model === undefined && s.chainname === undefined &&\n s.atomindex === undefined &&\n (s.keyword === undefined || AtomOnlyKeywords.includes(s.keyword))\n ) return -1\n\n if (s.keyword !== undefined) {\n if (s.keyword === kwd.HETERO && !r.isHetero()) return false\n if (s.keyword === kwd.PROTEIN && !r.isProtein()) return false\n if (s.keyword === kwd.NUCLEIC && !r.isNucleic()) return false\n if (s.keyword === kwd.RNA && !r.isRna()) return false\n if (s.keyword === kwd.DNA && !r.isDna()) return false\n if (s.keyword === kwd.POLYMER && !r.isPolymer()) return false\n if (s.keyword === kwd.WATER && !r.isWater()) return false\n if (s.keyword === kwd.HELIX && !r.isHelix()) return false\n if (s.keyword === kwd.SHEET && !r.isSheet()) return false\n if (s.keyword === kwd.TURN && !r.isTurn()) return false\n if (s.keyword === kwd.ION && !r.isIon()) return false\n if (s.keyword === kwd.SACCHARIDE && !r.isSaccharide()) return false\n }\n\n if (s.atomindex !== undefined &&\n rangeInSortedArray(s.atomindex, r.atomOffset, r.atomEnd) === 0\n ) return false\n\n if (s.resname !== undefined) {\n if (Array.isArray(s.resname)) {\n if (!s.resname.includes(r.resname)) return false\n } else {\n if (s.resname !== r.resname) return false\n }\n }\n if (s.sstruc !== undefined && s.sstruc !== r.sstruc) return false\n if (s.resno !== undefined) {\n if (Array.isArray(s.resno) && s.resno.length === 2) {\n if (s.resno[0] > r.resno || s.resno[1] < r.resno) return false\n } else {\n if (s.resno !== r.resno) return false\n }\n }\n if (s.inscode !== undefined && s.inscode !== r.inscode) return false\n\n if (s.chainname !== undefined && s.chainname !== r.chainname) return false\n if (s.model !== undefined && s.model !== r.modelIndex) return false\n\n return true\n}\n\nfunction chainTestFn (c: ChainProxy, s: SelectionRule) {\n // returning -1 means the rule is not applicable\n if (s.chainname === undefined && s.model === undefined && s.atomindex === undefined &&\n (s.keyword === undefined || !ChainKeywords.includes(s.keyword) || !c.entity)\n ) return -1\n\n if (s.keyword !== undefined) {\n if (s.keyword === kwd.POLYMER && !c.entity.isPolymer()) return false\n if (s.keyword === kwd.WATER && !c.entity.isWater()) return false\n }\n\n if (s.atomindex !== undefined &&\n rangeInSortedArray(s.atomindex, c.atomOffset, c.atomEnd) === 0\n ) return false\n\n if (s.chainname !== undefined && s.chainname !== c.chainname) return false\n\n if (s.model !== undefined && s.model !== c.modelIndex) return false\n\n return true\n}\n\nfunction modelTestFn (m: ModelProxy, s: SelectionRule) {\n // returning -1 means the rule is not applicable\n if (s.model === undefined && s.atomindex === undefined) return -1\n\n if (s.atomindex !== undefined &&\n rangeInSortedArray(s.atomindex, m.atomOffset, m.atomEnd) === 0\n ) return false\n\n if (s.model !== undefined && s.model !== m.index) return false\n\n return true\n}\n\nfunction makeTest (selection: SelectionRule|null, fn: TestEntityFn) {\n if (selection === null) return false\n if (selection.error) return false\n if (!selection.rules || selection.rules.length === 0) return false\n\n const n = selection.rules.length\n\n const t = !selection.negate\n const f = !!selection.negate\n\n const subTests: SelectionTest[] = []\n for (let i = 0; i < n; ++i) {\n const s = selection.rules[ i ]\n if (s.hasOwnProperty('operator')) {\n subTests[ i ] = makeTest(s, fn) as SelectionTest // TODO\n }\n }\n\n // ( x and y ) can short circuit on false\n // ( x or y ) can short circuit on true\n // not ( x and y )\n\n return function test (entity: ProxyEntity) {\n const and = selection.operator === 'AND'\n let na = false\n\n for (let i = 0; i < n; ++i) {\n const s = selection.rules![ i ] // TODO\n let ret\n\n if (s.hasOwnProperty('operator')) {\n const test = subTests[ i ]\n if (test !== false) {\n ret = test(entity)\n } else {\n ret = -1\n }\n\n if (ret === -1) {\n na = true\n continue\n } else if (ret === true) {\n if (and) { continue } else { return t }\n } else {\n if (and) { return f } else { continue }\n }\n } else {\n if (s.keyword === kwd.ALL) {\n if (and) { continue } else { return t }\n } else if (s.keyword === kwd.NONE) {\n if (and) { continue } else { return f }\n }\n\n ret = fn(entity, s)\n\n // console.log( entity.qualifiedName(), ret, s, selection.negate, \"t\", t, \"f\", f )\n\n if (ret === -1) {\n na = true\n continue\n } else if (ret === true) {\n if (and) { continue } else { return t }\n } else {\n if (and) { return f } else { continue }\n }\n }\n }\n\n if (na) {\n return -1\n } else {\n if (and) { return t } else { return f }\n }\n } as SelectionTest\n}\n\nfunction filter (selection: SelectionRule, fn: FilterFn) {\n if (selection.error) return selection\n if (!selection.rules || selection.rules.length === 0) return selection\n\n const n = selection.rules.length\n\n const filtered: SelectionRule = {\n operator: selection.operator,\n rules: []\n }\n if (selection.hasOwnProperty('negate')) {\n filtered.negate = selection.negate\n }\n\n for (let i = 0; i < n; ++i) {\n const s = selection.rules[ i ]\n if (s.hasOwnProperty('operator')) {\n const fs = filter(s, fn)\n if (fs !== null) filtered.rules!.push(fs) // TODO\n } else if (!fn(s)) {\n filtered.rules!.push(s) // TODO\n }\n }\n\n if (filtered.rules!.length > 0) { // TODO\n // TODO maybe the filtered rules could be returned\n // in some case, but the way how tests are applied\n // e.g. when traversing a structure would also need\n // to change\n return selection\n // return filtered;\n } else {\n return null\n }\n}\n\nfunction makeAtomTest (selection: SelectionRule, atomOnly = false) {\n let filteredSelection: SelectionRule|null = selection\n if (atomOnly) {\n filteredSelection = filter(selection, function (s) {\n if (s.keyword !== undefined && !AtomOnlyKeywords.includes(s.keyword)) return true\n if (s.model !== undefined) return true\n if (s.chainname !== undefined) return true\n if (s.resname !== undefined) return true\n if (s.resno !== undefined) return true\n if (s.sstruc !== undefined) return true\n return false\n })\n }\n return makeTest(filteredSelection, atomTestFn)\n}\n\nfunction makeResidueTest (selection: SelectionRule, residueOnly = false) {\n let filteredSelection: SelectionRule|null = selection\n if (residueOnly) {\n filteredSelection = filter(selection, function (s) {\n if (s.keyword !== undefined && AtomOnlyKeywords.includes(s.keyword)) return true\n if (s.model !== undefined) return true\n if (s.chainname !== undefined) return true\n if (s.atomname !== undefined) return true\n if (s.element !== undefined) return true\n if (s.altloc !== undefined) return true\n return false\n })\n }\n return makeTest(filteredSelection, residueTestFn)\n}\n\nfunction makeChainTest (selection: SelectionRule, chainOnly = false) {\n let filteredSelection: SelectionRule|null = selection\n if (chainOnly) {\n filteredSelection = filter(selection, function (s) {\n if (s.keyword !== undefined && !ChainKeywords.includes(s.keyword)) return true\n // if( s.model!==undefined ) return true;\n if (s.resname !== undefined) return true\n if (s.resno !== undefined) return true\n if (s.atomname !== undefined) return true\n if (s.element !== undefined) return true\n if (s.altloc !== undefined) return true\n if (s.sstruc !== undefined) return true\n if (s.inscode !== undefined) return true\n return false\n })\n }\n return makeTest(filteredSelection, chainTestFn)\n}\n\nfunction makeModelTest (selection: SelectionRule, modelOnly = false) {\n let filteredSelection: SelectionRule|null = selection\n if (modelOnly) {\n filteredSelection = filter(selection, function (s) {\n if (s.keyword !== undefined) return true\n if (s.chainname !== undefined) return true\n if (s.resname !== undefined) return true\n if (s.resno !== undefined) return true\n if (s.atomname !== undefined) return true\n if (s.element !== undefined) return true\n if (s.altloc !== undefined) return true\n if (s.sstruc !== undefined) return true\n if (s.inscode !== undefined) return true\n return false\n })\n }\n return makeTest(filteredSelection, modelTestFn)\n}\n\nexport {\n makeAtomTest,\n makeResidueTest,\n makeChainTest,\n makeModelTest\n}\n","/**\n * @file Selection\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\n\nimport { parseSele } from './selection-parser'\nimport {\n SelectionTest, SelectionRule,\n makeAtomTest, makeResidueTest, makeChainTest, makeModelTest\n} from './selection-test'\nimport { SelectAllKeyword, SelectNoneKeyword } from './selection-constants'\n\nexport type SelectionSignals = {\n stringChanged: Signal\n}\n\n/**\n * Selection\n */\nclass Selection {\n signals: SelectionSignals\n string: string\n selection: SelectionRule\n\n test: SelectionTest\n residueTest: SelectionTest\n chainTest: SelectionTest\n modelTest: SelectionTest\n\n atomOnlyTest: SelectionTest\n residueOnlyTest: SelectionTest\n chainOnlyTest: SelectionTest\n modelOnlyTest: SelectionTest\n\n /**\n * Create Selection\n * @param {String} string - selection string, see {@tutorial selection-language}\n */\n constructor (string?: string) {\n this.signals = {\n stringChanged: new Signal()\n }\n\n this.setString(string)\n }\n\n get type () { return 'selection' }\n\n setString (string?: string, silent?: boolean) {\n if (string === undefined) string = this.string || ''\n if (string === this.string) return\n\n try {\n this.selection = parseSele(string)\n } catch (e) {\n // Log.error( e.stack );\n this.selection = { 'error': e.message }\n }\n const selection = this.selection\n\n this.string = string\n\n this.test = makeAtomTest(selection)\n this.residueTest = makeResidueTest(selection)\n this.chainTest = makeChainTest(selection)\n this.modelTest = makeModelTest(selection)\n\n this.atomOnlyTest = makeAtomTest(selection, true)\n this.residueOnlyTest = makeResidueTest(selection, true)\n this.chainOnlyTest = makeChainTest(selection, true)\n this.modelOnlyTest = makeModelTest(selection, true)\n\n if (!silent) {\n this.signals.stringChanged.dispatch(this.string)\n }\n }\n\n isAllSelection () {\n return SelectAllKeyword.includes(this.string.toUpperCase())\n }\n\n isNoneSelection () {\n return SelectNoneKeyword.includes(this.string.toUpperCase())\n }\n}\n\nexport default Selection\n","/**\n * @file Selection Parser\n * @author Alexander Rose \n * @private\n */\n\nimport { SelectionRule, SelectionOperator } from './selection-test'\nimport {\n kwd, SelectAllKeyword,\n SmallResname, NucleophilicResname, HydrophobicResname, AromaticResname,\n AmideResname, AcidicResname, BasicResname, ChargedResname,\n PolarResname, NonpolarResname, CyclicResname, AliphaticResname\n} from './selection-constants'\n\nfunction parseSele (string: string) {\n let retSelection: SelectionRule = {\n operator: undefined,\n rules: []\n }\n\n if (!string) {\n return retSelection\n }\n\n let selection = retSelection\n let newSelection: SelectionRule\n let oldSelection: SelectionRule\n const selectionStack: SelectionRule[] = []\n\n string = string.replace(/\\(/g, ' ( ').replace(/\\)/g, ' ) ').trim()\n if (string.charAt(0) === '(' && string.substr(-1) === ')') {\n string = string.slice(1, -1).trim()\n }\n const chunks = string.split(/\\s+/)\n\n // Log.log( string, chunks )\n\n const createNewContext = (operator?: SelectionOperator) => {\n newSelection = {\n operator,\n rules: []\n }\n if (selection === undefined) {\n selection = newSelection\n retSelection = newSelection\n } else {\n selection.rules!.push(newSelection)\n selectionStack.push(selection)\n selection = newSelection\n }\n }\n\n const getPrevContext = function (operator?: SelectionOperator) {\n oldSelection = selection\n selection = selectionStack.pop()!\n if (selection === undefined) {\n createNewContext(operator)\n pushRule(oldSelection)\n }\n }\n\n const pushRule = function (rule: SelectionRule) {\n selection.rules!.push(rule)\n }\n\n let not: false|0|1|2 = false\n\n for (let i = 0; i < chunks.length; ++i) {\n const c = chunks[ i ]\n const cu = c.toUpperCase()\n\n // handle parens\n\n if (c === '(') {\n // Log.log( \"(\" );\n not = false\n createNewContext()\n continue\n } else if (c === ')') {\n // Log.log( \")\" );\n getPrevContext()\n if (selection.negate) {\n getPrevContext()\n }\n continue\n }\n\n // leave 'not' context\n\n if (not > 0) {\n if (cu === 'NOT') {\n not = 1\n } else if (not === 1) {\n not = 2\n } else if (not === 2) {\n not = false\n getPrevContext()\n } else {\n throw new Error(\"something went wrong with 'not'\")\n }\n }\n\n // handle logic operators\n\n if (cu === 'AND') {\n // Log.log( \"AND\" );\n if (selection.operator === 'OR') {\n const lastRule = selection.rules!.pop()!\n createNewContext('AND')\n pushRule(lastRule)\n } else {\n selection.operator = 'AND'\n }\n continue\n } else if (cu === 'OR') {\n // Log.log( \"OR\" );\n if (selection.operator === 'AND') {\n getPrevContext('OR')\n } else {\n selection.operator = 'OR'\n }\n continue\n } else if (c.toUpperCase() === 'NOT') {\n // Log.log( \"NOT\", j );\n not = 1\n createNewContext()\n selection.negate = true\n continue\n } else {\n // Log.log( \"chunk\", c, j, selection );\n }\n\n // handle keyword attributes\n\n // ensure `cu` is not a number before testing if it is in the\n // kwd enum dictionary which includes the enum numbers as well...\n if (+cu !== +cu) {\n const keyword = (kwd as any)[ cu ]\n if (keyword !== undefined) {\n pushRule({ keyword })\n continue\n }\n }\n\n if (cu === 'HYDROGEN') {\n pushRule({\n operator: 'OR',\n rules: [\n { element: 'H' },\n { element: 'D' }\n ]\n })\n continue\n }\n\n if (cu === 'SMALL') {\n pushRule({ resname: SmallResname })\n continue\n }\n\n if (cu === 'NUCLEOPHILIC') {\n pushRule({ resname: NucleophilicResname })\n continue\n }\n\n if (cu === 'HYDROPHOBIC') {\n pushRule({ resname: HydrophobicResname })\n continue\n }\n\n if (cu === 'AROMATIC') {\n pushRule({ resname: AromaticResname })\n continue\n }\n\n if (cu === 'AMIDE') {\n pushRule({ resname: AmideResname })\n continue\n }\n\n if (cu === 'ACIDIC') {\n pushRule({ resname: AcidicResname })\n continue\n }\n\n if (cu === 'BASIC') {\n pushRule({ resname: BasicResname })\n continue\n }\n\n if (cu === 'CHARGED') {\n pushRule({ resname: ChargedResname })\n continue\n }\n\n if (cu === 'POLAR') {\n pushRule({ resname: PolarResname })\n continue\n }\n\n if (cu === 'NONPOLAR') {\n pushRule({ resname: NonpolarResname })\n continue\n }\n\n if (cu === 'CYCLIC') {\n pushRule({ resname: CyclicResname })\n continue\n }\n\n if (cu === 'ALIPHATIC') {\n pushRule({ resname: AliphaticResname })\n continue\n }\n\n if (cu === 'SIDECHAINATTACHED') {\n pushRule({\n operator: 'OR',\n rules: [\n { keyword: kwd.SIDECHAIN },\n {\n operator: 'AND',\n negate: false,\n rules: [\n { keyword: kwd.PROTEIN },\n {\n operator: 'OR',\n negate: false,\n rules: [\n { atomname: 'CA' },\n { atomname: 'BB' }\n ]\n }\n ]\n },\n {\n operator: 'AND',\n negate: false,\n rules: [\n { resname: 'PRO' },\n { atomname: 'N' }\n ]\n },\n {\n operator: 'AND',\n negate: false,\n rules: [\n { keyword: kwd.NUCLEIC },\n {\n operator: 'OR',\n negate: true,\n rules: [\n { atomname: 'P' },\n { atomname: 'OP1' },\n { atomname: 'OP2' },\n { atomname: \"O3'\" },\n { atomname: 'O3*' },\n { atomname: \"HO3'\"},\n { atomname: \"O5'\" },\n { atomname: 'O5*' },\n { atomname: \"HO5'\"},\n { atomname: \"C5'\" },\n { atomname: 'C5*' },\n { atomname: \"H5'\" },\n { atomname: \"H5''\"}\n ]\n }\n ]\n }\n ]\n })\n continue\n }\n\n if (cu === 'APOLARH') {\n pushRule({\n operator: 'AND',\n negate: false,\n rules: [\n { element: 'H' },\n {\n negate: true,\n operator: undefined,\n rules: [\n { keyword: kwd.POLARH }\n ]\n }\n ]\n })\n continue\n }\n\n if (cu === 'LIGAND') {\n pushRule({\n operator: 'AND',\n rules: [\n {\n operator: 'OR',\n rules: [\n {\n operator: 'AND',\n rules: [\n { keyword: kwd.HETERO },\n {\n negate: true,\n operator: undefined,\n rules: [\n { keyword: kwd.POLYMER }\n ]\n }\n ]\n },\n {\n negate: true,\n operator: undefined,\n rules: [\n { keyword: kwd.POLYMER }\n ]\n }\n ]\n },\n {\n negate: true,\n operator: undefined,\n rules: [\n {\n operator: 'OR',\n rules: [\n { keyword: kwd.WATER },\n { keyword: kwd.ION }\n ]\n }\n ]\n }\n ]\n })\n continue\n }\n\n if (SelectAllKeyword.indexOf(cu) !== -1) {\n pushRule({ keyword: kwd.ALL })\n continue\n }\n\n // handle atom expressions\n\n if (c.charAt(0) === '@') {\n const indexList = c.substr(1).split(',').map(x => parseInt(x))\n indexList.sort(function (a, b) { return a - b })\n pushRule({ atomindex: indexList })\n continue\n }\n\n if (c.charAt(0) === '#') {\n console.error('# for element selection deprecated, use _')\n pushRule({ element: cu.substr(1) })\n continue\n }\n if (c.charAt(0) === '_') {\n pushRule({ element: cu.substr(1) })\n continue\n }\n\n if (c[0] === '[' && c[c.length - 1] === ']') {\n const resnameList = cu.substr(1, c.length - 2).split(',')\n const resname = resnameList.length > 1 ? resnameList : resnameList[ 0 ]\n pushRule({ resname: resname })\n continue\n } else if (\n (c.length >= 1 && c.length <= 4) &&\n c[0] !== '^' && c[0] !== ':' && c[0] !== '.' && c[0] !== '%' && c[0] !== '/' &&\n isNaN(parseInt(c))\n ) {\n pushRule({ resname: cu })\n continue\n }\n\n // there must be only one constraint per rule\n // otherwise a test quickly becomes not applicable\n // e.g. chainTest for chainname when resno is present too\n\n const sele: SelectionRule = {\n operator: 'AND',\n rules: []\n }\n\n const model = c.split('/')\n if (model.length > 1 && model[1]) {\n if (isNaN(parseInt(model[1]))) {\n throw new Error('model must be an integer')\n }\n sele.rules!.push({\n model: parseInt(model[1])\n })\n }\n\n const altloc = model[0].split('%')\n if (altloc.length > 1) {\n sele.rules!.push({\n altloc: altloc[1]\n })\n }\n\n const atomname = altloc[0].split('.')\n if (atomname.length > 1 && atomname[1]) {\n if (atomname[1].length > 4) {\n throw new Error('atomname must be one to four characters')\n }\n sele.rules!.push({\n atomname: atomname[1].substring(0, 4).toUpperCase()\n })\n }\n\n const chain = atomname[0].split(':')\n if (chain.length > 1 && chain[1]) {\n sele.rules!.push({\n chainname: chain[1]\n })\n }\n\n const inscode = chain[0].split('^')\n if (inscode.length > 1) {\n sele.rules!.push({\n inscode: inscode[1]\n })\n }\n\n if (inscode[0]) {\n let negate, negate2\n if (inscode[0][0] === '-') {\n inscode[0] = inscode[0].substr(1)\n negate = true\n }\n if (inscode[0].includes('--')) {\n inscode[0] = inscode[0].replace('--', '-')\n negate2 = true\n }\n let resi = inscode[0].split('-')\n if (resi.length === 1) {\n let resiSingle = parseInt(resi[0])\n if (isNaN(resiSingle)) {\n throw new Error('resi must be an integer')\n }\n if (negate) resiSingle *= -1\n sele.rules!.push({\n resno: resiSingle\n })\n } else if (resi.length === 2) {\n const resiRange = resi.map(x => parseInt(x))\n if (negate) resiRange[0] *= -1\n if (negate2) resiRange[1] *= -1\n sele.rules!.push({\n resno: [resiRange[0], resiRange[1]]\n })\n } else {\n throw new Error(\"resi range must contain one '-'\")\n }\n }\n\n // round up\n\n if (sele.rules!.length === 1) {\n pushRule(sele.rules![ 0 ])\n } else if (sele.rules!.length > 1) {\n pushRule(sele)\n } else {\n throw new Error('empty selection chunk')\n }\n }\n\n // cleanup\n\n if (\n retSelection.operator === undefined &&\n retSelection.rules!.length === 1 &&\n retSelection.rules![ 0 ].hasOwnProperty('operator')\n ) {\n retSelection = retSelection.rules![ 0 ]\n }\n\n return retSelection\n}\n\nexport {\n parseSele\n}\n","/**\n * @file Selection Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { Color } from 'three'\n\nimport { ColormakerRegistry } from '../globals'\nimport Selection from '../selection/selection'\nimport Colormaker, { ColormakerParameters } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport Structure from '../structure/structure'\n\nexport type SelectionSchemeData = [ string, string, ColormakerParameters|undefined ]\n\n/**\n * Color based on {@link Selection}\n */\nclass SelectionColormaker extends Colormaker {\n colormakerList: any[] = [] // TODO\n selectionList: Selection[] = []\n\n constructor (params: { structure: Structure, dataList: SelectionSchemeData[] } & Partial) {\n super(params)\n\n const dataList = params.dataList || []\n\n dataList.forEach((data: SelectionSchemeData) => {\n const [ scheme, sele, params = {} ] = data\n\n if (ColormakerRegistry.hasScheme(scheme)) {\n Object.assign(params, {\n scheme: scheme,\n structure: this.parameters.structure\n })\n } else {\n Object.assign(params, {\n scheme: 'uniform',\n value: new Color(scheme).getHex()\n })\n }\n\n this.colormakerList.push(ColormakerRegistry.getScheme(params as { scheme: string } & ColormakerParameters))\n this.selectionList.push(new Selection(sele))\n })\n }\n\n // NOT NEEDED @manageColor\n atomColor (a: AtomProxy) {\n for (let i = 0, n = this.selectionList.length; i < n; ++i) {\n const test = this.selectionList[ i ].test\n if (test && test(a)) {\n return this.colormakerList[ i ].atomColor(a)\n }\n }\n\n return 0xFFFFFF\n }\n}\n\nexport default SelectionColormaker\n","/**\n * @file Colormaker Registry\n * @author Alexander Rose \n * @private\n */\n\nimport { generateUUID } from '../math/math-utils'\nimport Colormaker, { ColormakerConstructor, ColormakerParameters } from './colormaker'\nimport SelectionColormaker, { SelectionSchemeData } from './selection-colormaker'\nimport Structure from '../structure/structure'\n\ntype ColormakerDefinitionFunction = ((this: Colormaker, param?: ColormakerParameters) => void)\n\nconst ColormakerScales = {\n '': '',\n\n // Sequential\n OrRd: '[S] Orange-Red',\n PuBu: '[S] Purple-Blue',\n BuPu: '[S] Blue-Purple',\n Oranges: '[S] Oranges',\n BuGn: '[S] Blue-Green',\n YlOrBr: '[S] Yellow-Orange-Brown',\n YlGn: '[S] Yellow-Green',\n Reds: '[S] Reds',\n RdPu: '[S] Red-Purple',\n Greens: '[S] Greens',\n YlGnBu: '[S] Yellow-Green-Blue',\n Purples: '[S] Purples',\n GnBu: '[S] Green-Blue',\n Greys: '[S] Greys',\n YlOrRd: '[S] Yellow-Orange-Red',\n PuRd: '[S] Purple-Red',\n Blues: '[S] Blues',\n PuBuGn: '[S] Purple-Blue-Green',\n\n // Diverging\n Viridis: '[D] Viridis',\n Spectral: '[D] Spectral',\n RdYlGn: '[D] Red-Yellow-Green',\n RdBu: '[D] Red-Blue',\n PiYG: '[D] Pink-Yellowgreen',\n PRGn: '[D] Purplered-Green',\n RdYlBu: '[D] Red-Yellow-Blue',\n BrBG: '[D] Brown-Bluegreen',\n RdGy: '[D] Red-Grey',\n PuOr: '[D] Purple-Orange',\n\n // Qualitative\n Set1: '[Q] Set1',\n Set2: '[Q] Set2',\n Set3: '[Q] Set3',\n Dark2: '[Q] Dark2',\n Paired: '[Q] Paired',\n Pastel1: '[Q] Pastel1',\n Pastel2: '[Q] Pastel2',\n Accent: '[Q] Accent',\n\n // Other\n rainbow: '[?] Rainbow',\n rwb: '[?] Red-White-Blue'\n}\n\nconst ColormakerModes = {\n '': '',\n\n rgb: 'Red Green Blue',\n hsv: 'Hue Saturation Value',\n hsl: 'Hue Saturation Lightness',\n hsi: 'Hue Saturation Intensity',\n lab: 'CIE L*a*b*',\n hcl: 'Hue Chroma Lightness'\n}\n\n/**\n * Class for registering {@link Colormaker}s. Generally use the\n * global {@link src/globals.js~ColormakerRegistry} instance.\n */\nclass ColormakerRegistry {\n schemes: { [k: string]: ColormakerConstructor }\n userSchemes: { [k: string]: ColormakerConstructor }\n\n constructor () {\n this.schemes = {}\n this.userSchemes = {}\n }\n\n getScheme (params: Partial<{ scheme: string } & ColormakerParameters>) {\n const p = params || {}\n const id = (p.scheme || '').toLowerCase()\n\n let SchemeClass: ColormakerConstructor\n\n if (id in this.schemes) {\n SchemeClass = this.schemes[ id ]\n } else if (id in this.userSchemes) {\n SchemeClass = this.userSchemes[ id ]\n } else {\n //@ts-expect-error abstract class used as a constructor\n SchemeClass = Colormaker\n }\n\n return new SchemeClass(params)\n }\n\n /**\n * Get an description of available schemes as an\n * object with id-label as key-value pairs\n * @return {Object} available schemes\n */\n getSchemes () {\n const types: { [k: string]: string } = {}\n\n Object.keys(this.schemes).forEach(function (k) {\n types[ k ] = k\n })\n\n Object.keys(this.userSchemes).forEach(function (k) {\n types[ k ] = k.split('|')[ 1 ]\n })\n\n return types\n }\n\n /**\n * Get an description of available scales as an\n * object with id-label as key-value pairs\n * @return {Object} available scales\n */\n getScales () {\n return ColormakerScales\n }\n\n getModes () {\n return ColormakerModes\n }\n\n /**\n * Add a scheme with a hardcoded id\n * @param {String} id - the id\n * @param {Colormaker} scheme - the colormaker\n * @return {undefined}\n */\n add (id: string, scheme: ColormakerConstructor) {\n id = id.toLowerCase()\n this.schemes[ id ] = scheme\n }\n\n /**\n * Register a custom scheme\n *\n * @example\n * // Create a class with a `atomColor` method that returns a hex color.\n * var schemeId = NGL.ColormakerRegistry.addScheme( function( params ){\n * this.atomColor = function( atom ){\n * if( atom.serial < 1000 ){\n * return 0x0000FF; // blue\n * }else if( atom.serial > 2000 ){\n * return 0xFF0000; // red\n * }else{\n * return 0x00FF00; // green\n * }\n * };\n * } );\n *\n * stage.loadFile( \"rcsb://3dqb.pdb\" ).then( function( o ){\n * o.addRepresentation( \"cartoon\", { color: schemeId } ); // pass schemeId here\n * o.autoView();\n * } );\n *\n * @param {Function|Colormaker} scheme - constructor or {@link Colormaker} instance\n * @param {String} label - scheme label\n * @return {String} id to refer to the registered scheme\n */\n addScheme (scheme: ColormakerConstructor|ColormakerDefinitionFunction, label?: string) {\n if (!(isColormakerSubClass(scheme))) {\n scheme = this._createScheme(scheme)\n }\n\n return this._addUserScheme(scheme, label)\n }\n\n /**\n * Add a user-defined scheme\n * @param {Colormaker} scheme - the user-defined scheme\n * @param {String} [label] - scheme label\n * @return {String} id to refer to the registered scheme\n */\n _addUserScheme (scheme: ColormakerConstructor, label?: string) {\n label = label || ''\n const id = `${generateUUID()}|${label}`.toLowerCase()\n this.userSchemes[ id ] = scheme\n\n return id\n }\n\n /**\n * Remove the scheme with the given id\n * @param {String} id - scheme to remove\n * @return {undefined}\n */\n removeScheme (id: string) {\n id = id.toLowerCase()\n delete this.userSchemes[ id ]\n }\n\n _createScheme (constructor: ColormakerDefinitionFunction): ColormakerConstructor {\n class _Colormaker extends Colormaker {\n constructor (params: ColormakerParameters) {\n super(params)\n constructor.call(this, params)\n }\n }\n return _Colormaker\n }\n\n /**\n * Create and a selection-based coloring scheme. Supply a list with pairs\n * of colorname and selection for coloring by selections. Use the last\n * entry as a default (catch all) coloring definition.\n *\n * @example\n * var schemeId = NGL.ColormakerRegistry.addSelectionScheme( [\n * [ \"red\", \"64-74 or 134-154 or 222-254 or 310-310 or 322-326\" ],\n * [ \"green\", \"311-322\" ],\n * [ \"yellow\", \"40-63 or 75-95 or 112-133 or 155-173 or 202-221 or 255-277 or 289-309\" ],\n * [ \"blue\", \"1-39 or 96-112 or 174-201 or 278-288\" ],\n * [ \"white\", \"*\" ]\n * ], \"Transmembrane 3dqb\" );\n *\n * stage.loadFile( \"rcsb://3dqb.pdb\" ).then( function( o ){\n * o.addRepresentation( \"cartoon\", { color: schemeId } ); // pass schemeId here\n * o.autoView();\n * } );\n *\n * @param {Array} dataList - cloror-selection pairs\n * @param {String} label - scheme name\n * @return {String} id to refer to the registered scheme\n */\n addSelectionScheme (dataList: SelectionSchemeData[], label?: string) {\n class MySelectionColormaker extends SelectionColormaker {\n constructor (params: { structure: Structure } & ColormakerParameters) {\n super(Object.assign({ dataList }, params))\n }\n }\n\n return this._addUserScheme(MySelectionColormaker, label)\n }\n\n /**\n * Check if a scheme with the given id exists\n * @param {String} id - the id to check\n * @return {Boolean} flag indicating if the scheme exists\n */\n hasScheme (id: string) {\n id = id.toLowerCase()\n return id in this.schemes || id in this.userSchemes\n }\n}\n\nfunction isColormakerSubClass (\n scheme: ColormakerConstructor|((this: Colormaker, param?: ColormakerParameters) => void)\n): scheme is ColormakerConstructor {\n return (scheme instanceof Colormaker)\n}\n\nexport default ColormakerRegistry\n","/**\n * @file Worker Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { uniqueArray } from '../utils'\n\nexport type FunctionWithDeps = { __deps?: Function[] } & Function\nexport interface WorkerEvent {\n data: {\n __name: string\n __postId: string\n }\n}\n\nfunction getWorkerDeps (vars: FunctionWithDeps[]) {\n const deps = vars\n vars.forEach(function (sym) {\n if (sym.__deps) {\n Array.prototype.push.apply(deps, getWorkerDeps(sym.__deps))\n }\n })\n return deps\n}\n\nfunction makeWorkerString (vars: any) {\n const deps = uniqueArray(getWorkerDeps(vars))\n return deps.map(function (sym) {\n return sym.toString()\n }).join('\\n\\n\\n')\n}\n\nfunction onmessage (e: WorkerEvent) {\n const name = e.data.__name\n const postId = e.data.__postId\n\n /* global self */\n if (name === undefined) {\n console.error('message __name undefined')\n } else if ((self as any).func === undefined) {\n console.error('worker func undefined', name)\n } else {\n const callback = function (aMessage: any, transferList: any[]) {\n aMessage = aMessage || {}\n if (postId !== undefined) aMessage.__postId = postId\n\n try {\n (self as any).postMessage(aMessage, transferList)\n } catch (error) {\n console.error('self.postMessage:', error);\n (self as any).postMessage(aMessage)\n }\n };\n (self as any).func(e, callback)\n }\n}\n\nexport function makeWorkerBlob (func: Function, deps: Function[]) {\n let str = \"'use strict';\\n\\n\" + makeWorkerString(deps)\n str += '\\n\\n\\nself.func = ' + func.toString() + ';'\n str += '\\n\\n\\nself.onmessage = ' + onmessage.toString() + ';'\n // console.log(str);\n return new Blob([ str ], { type: 'application/javascript' })\n}\n","/**\n * @file Globals\n * @author Alexander Rose \n * @private\n */\n\nimport { getBrowser, getQuery, boolean } from './utils'\nimport Registry from './utils/registry'\nimport _ColormakerRegistry from './color/colormaker-registry'\nimport _ParserRegistry from './parser/parser-registry'\nimport _WorkerRegistry from './worker/worker-registry'\nimport { MeasurementRepresentationParameters } from './representation/measurement-representation';\n\n/**\n * The browser name: \"Opera\", \"Chrome\", \"Firefox\", \"Mobile Safari\",\n * \"Internet Explorer\", \"Safari\" or false.\n */\nexport const Browser = getBrowser()\n\n/**\n * Flag indicating support for the 'passive' option for event handler\n */\nexport let SupportsPassiveEventHandler = false\ntry {\n // Test via a getter in the options object to see if the passive property is accessed\n const opts = Object.defineProperty({}, 'passive', {\n get: function () {\n SupportsPassiveEventHandler = true\n }\n })\n window.addEventListener('test', e => {}, opts)\n} catch (e) {}\n\n/**\n * Flag indicating a mobile browser\n */\nexport const Mobile = typeof window !== 'undefined' ? typeof window.orientation !== 'undefined' : false\n\nexport let SupportsReadPixelsFloat = false\nexport function setSupportsReadPixelsFloat (value: boolean) {\n SupportsReadPixelsFloat = value\n}\n\n/**\n * Flag indicating support for the `EXT_frag_depth` WebGL extension\n * (Always present in WebGL2)\n */\nexport let ExtensionFragDepth = false\nexport function setExtensionFragDepth (value: boolean) {\n ExtensionFragDepth = value\n}\n\nexport const Log = {\n log: Function.prototype.bind.call(console.log, console),\n info: Function.prototype.bind.call(console.info, console),\n warn: Function.prototype.bind.call(console.warn, console),\n error: Function.prototype.bind.call(console.error, console),\n time: Function.prototype.bind.call(console.time, console),\n timeEnd: Function.prototype.bind.call(console.timeEnd, console)\n}\n\nexport let MeasurementDefaultParams: Partial = {\n color: 'green',\n labelColor: 0x808080,\n labelAttachment: 'bottom-center',\n labelSize: 0.7,\n labelZOffset: 0.5,\n labelYOffset: 0.1,\n labelBorder: true,\n labelBorderColor: 0xd3d3d3,\n labelBorderWidth: 0.25,\n lineOpacity: 0.8,\n linewidth: 5.0,\n opacity: 0.6,\n\n labelUnit: 'angstrom',\n arcVisible: true,\n planeVisible: false\n}\nexport function setMeasurementDefaultParams (params = {}) {\n Object.assign(MeasurementDefaultParams, params)\n}\n\nexport let Debug = boolean(getQuery('debug'))\nexport function setDebug (value: boolean) {\n Debug = value\n}\n\nexport const WebglErrorMessage = '

Your browser/graphics card does not seem to support WebGL.

Find out how to get it here.

'\n\n/**\n * List of file extensions to be recognized as scripts\n */\nexport const ScriptExtensions = [ 'ngl', 'js' ]\n\nexport const WorkerRegistry = new _WorkerRegistry()\nexport const ColormakerRegistry = new _ColormakerRegistry()\nexport const DatasourceRegistry = new Registry('datasource')\nexport const RepresentationRegistry = new Registry('representatation')\nexport const ParserRegistry = new _ParserRegistry()\nexport const ShaderRegistry = new Registry('shader')\nexport const DecompressorRegistry = new Registry('decompressor')\nexport const ComponentRegistry = new Registry('component')\nexport const BufferRegistry = new Registry('buffer')\nexport const PickerRegistry = new Registry('picker')\n\nexport let ListingDatasource: any\nexport function setListingDatasource (value: any) {\n ListingDatasource = value\n}\n\nexport let TrajectoryDatasource: any // TODO should accept mdsrvDatasource\nexport function setTrajectoryDatasource (value: any) {\n TrajectoryDatasource = value\n}\n","/**\n * @file Worker Registry\n * @author Alexander Rose \n * @private\n */\n\nimport { makeWorkerBlob } from './worker-utils'\n\nclass WorkerRegistry {\n activeWorkerCount = 0\n\n private _funcDict: { [k: string]: Function } = {}\n private _depsDict: { [k: string]: Function[] } = {}\n private _blobDict: { [k: string]: Blob } = {}\n\n add (name: string, func: Function, deps: Function[]) {\n this._funcDict[ name ] = func\n this._depsDict[ name ] = deps\n }\n\n get (name: string) {\n if (!this._blobDict[ name ]) {\n this._blobDict[ name ] = makeWorkerBlob(\n this._funcDict[ name ], this._depsDict[ name ]\n )\n }\n return this._blobDict[ name ]\n }\n}\n\nexport default WorkerRegistry\n","/**\n * @file Parser Registry\n * @author Alexander Rose \n * @private\n */\n\nimport Registry from '../utils/registry'\n\nclass ParserRegistry extends Registry {\n constructor () {\n super('parser')\n }\n\n __hasObjName (key: string, objName: string) {\n const parser = this.get(key)\n return parser && parser.prototype.__objName === objName\n }\n\n isTrajectory (key: string) {\n return this.__hasObjName(key, 'frames')\n }\n\n isStructure (key: string) {\n return this.__hasObjName(key, 'structure')\n }\n\n isVolume (key: string) {\n return this.__hasObjName(key, 'volume')\n }\n\n isSurface (key: string) {\n return this.__hasObjName(key, 'surface')\n }\n\n isBinary (key: string) {\n const parser = this.get(key)\n return parser && parser.prototype.isBinary\n }\n\n isXml (key: string) {\n const parser = this.get(key)\n return parser && parser.prototype.isXml\n }\n\n isJson (key: string) {\n const parser = this.get(key)\n return parser && parser.prototype.isJson\n }\n\n getTrajectoryExtensions () {\n return this.names.filter(name => this.isTrajectory(name))\n }\n\n getStructureExtensions () {\n return this.names.filter(name => this.isStructure(name))\n }\n\n getVolumeExtensions () {\n return this.names.filter(name => this.isVolume(name))\n }\n\n getSurfaceExtensions () {\n return this.names.filter(name => this.isSurface(name))\n }\n}\n\nexport default ParserRegistry\n","/**\n * @file Streamer\n * @author Alexander Rose \n * @private\n */\n\nimport { DecompressorRegistry } from '../globals'\nimport { uint8ToString, defaults } from '../utils'\n\nexport interface StreamerParams {\n compressed?: string|false\n binary?: boolean\n json?: boolean\n xml?: boolean\n}\n\nabstract class Streamer {\n src: any\n data: any\n\n compressed: string|false\n binary: boolean\n json: boolean\n xml: boolean\n\n chunkSize = 1024 * 1024 * 10\n newline = '\\n'\n\n protected __pointer = 0\n protected __partialLine = ''\n\n constructor (src: any, params: StreamerParams = {}) {\n this.compressed = defaults(params.compressed, false)\n this.binary = defaults(params.binary, false)\n this.json = defaults(params.json, false)\n this.xml = defaults(params.xml, false)\n\n this.src = src\n }\n\n isBinary () {\n return this.binary || this.compressed\n }\n\n read () {\n return this._read().then(data => {\n const decompressFn = this.compressed ? DecompressorRegistry.get(this.compressed) : undefined\n\n if (this.compressed && decompressFn) {\n this.data = decompressFn(data)\n } else {\n if ((this.binary || this.compressed) && data instanceof ArrayBuffer) {\n data = new Uint8Array(data)\n }\n this.data = data\n }\n\n return this.data\n })\n }\n\n protected abstract _read (): Promise\n\n protected _chunk (start: number, end: number) {\n end = Math.min(this.data.length, end)\n\n if (start === 0 && this.data.length === end) {\n return this.data\n } else {\n if (this.isBinary()) {\n return this.data.subarray(start, end)\n } else {\n return this.data.substring(start, end)\n }\n }\n }\n\n chunk (start: number) {\n const end = start + this.chunkSize\n\n return this._chunk(start, end)\n }\n\n peekLines (m: number) {\n const data = this.data\n const n = data.length\n\n // FIXME does not work for multi-char newline\n const newline = this.isBinary() ? this.newline.charCodeAt(0) : this.newline\n\n let i\n let count = 0\n for (i = 0; i < n; ++i) {\n if (data[ i ] === newline) ++count\n if (count === m) break\n }\n\n const chunk = this._chunk(0, i + 1)\n const d = this.chunkToLines(chunk, '', i > n)\n\n return d.lines\n }\n\n chunkCount () {\n return Math.floor(this.data.length / this.chunkSize) + 1\n }\n\n asText () {\n return this.isBinary() ? uint8ToString(this.data) : this.data\n }\n\n chunkToLines (chunk: string|Uint8Array, partialLine: string, isLast: boolean) {\n const newline = this.newline\n\n if (!this.isBinary() && chunk.length === this.data.length) {\n return {\n lines: (chunk as string).split(newline),\n partialLine: ''\n }\n }\n\n let lines: string[] = []\n const str = this.isBinary() ? uint8ToString(chunk as Uint8Array) : chunk\n const idx = str.lastIndexOf(newline)\n\n if (idx === -1) {\n partialLine += str\n } else {\n const str2 = partialLine + str.substr(0, idx)\n lines = lines.concat(str2.split(newline))\n\n if (idx === str.length - newline.length) {\n partialLine = ''\n } else {\n partialLine = str.substr(idx + newline.length)\n }\n }\n\n if (isLast && partialLine !== '') {\n lines.push(partialLine)\n }\n\n return {\n lines: lines,\n partialLine: partialLine\n }\n }\n\n nextChunk () {\n const start = this.__pointer\n\n if (start > this.data.length) {\n return undefined\n }\n\n this.__pointer += this.chunkSize\n return this.chunk(start)\n }\n\n nextChunkOfLines () {\n const chunk = this.nextChunk()\n\n if (chunk === undefined) {\n return undefined\n }\n\n const isLast = this.__pointer > this.data.length\n const d = this.chunkToLines(chunk, this.__partialLine, isLast)\n\n this.__partialLine = d.partialLine\n\n return d.lines\n }\n\n eachChunk (callback: (chunk: string|Uint8Array, chunkNo: number, chunkCount: number) => void) {\n const chunkSize = this.chunkSize\n const n = this.data.length\n const chunkCount = this.chunkCount()\n\n for (let i = 0; i < n; i += chunkSize) {\n const chunk = this.chunk(i)\n const chunkNo = Math.round(i / chunkSize)\n\n callback(chunk, chunkNo, chunkCount)\n }\n }\n\n eachChunkOfLines (callback: (chunk: string[], chunkNo: number, chunkCount: number) => void) {\n this.eachChunk((chunk, chunkNo, chunkCount) => {\n const isLast = chunkNo === chunkCount + 1\n const d = this.chunkToLines(chunk, this.__partialLine, isLast)\n\n this.__partialLine = d.partialLine\n\n callback(d.lines, chunkNo, chunkCount)\n })\n }\n\n dispose () {\n delete this.src\n }\n}\n\nexport default Streamer\n","/**\n * @file File Streamer\n * @author Alexander Rose \n * @private\n */\n\nimport Streamer from './streamer'\n\ninterface FileReaderEventTarget extends EventTarget {\n result:string | ArrayBuffer | null\n}\n\ninterface FileReaderEvent extends ProgressEvent {\n target: FileReaderEventTarget | null;\n}\n\nclass FileStreamer extends Streamer {\n _read () {\n return new Promise((resolve, reject) => {\n const file = this.src\n const reader = new FileReader()\n\n reader.onload = (event: FileReaderEvent) => {\n if(event.target) resolve(event.target.result)\n }\n\n // if (typeof this.onprogress === 'function') {\n // reader.onprogress = event => this.onprogress(event)\n // }\n\n reader.onerror = event => reject(event)\n\n if (this.binary || this.compressed) {\n reader.readAsArrayBuffer(file)\n } else {\n reader.readAsText(file)\n }\n })\n }\n}\n\nexport default FileStreamer\n","/**\n * @file Network Streamer\n * @author Alexander Rose \n * @private\n */\n\nimport Streamer from './streamer'\n\nclass NetworkStreamer extends Streamer {\n _read () {\n return new Promise((resolve, reject) => {\n const url = this.src\n const xhr = new XMLHttpRequest()\n\n xhr.open('GET', url, true)\n\n xhr.addEventListener('load', () => {\n if (xhr.status === 200 || xhr.status === 304 ||\n // when requesting from local file system\n // the status in Google Chrome/Chromium is 0\n xhr.status === 0\n ) {\n try {\n resolve(xhr.response)\n } catch (e) {\n reject(e)\n }\n } else {\n reject(xhr.statusText)\n }\n }, false)\n\n // if (typeof this.onprogress === 'function') {\n // xhr.addEventListener('progress', event => this.onprogress(event), false);\n // }\n\n xhr.addEventListener('error', event => reject('network error'), false)\n\n if (this.isBinary()) {\n xhr.responseType = 'arraybuffer'\n } else if (this.json) {\n xhr.responseType = 'json'\n } else if (this.xml) {\n xhr.responseType = 'document'\n } else {\n xhr.responseType = 'text'\n }\n // xhr.crossOrigin = true;\n\n xhr.send()\n })\n }\n}\n\nexport default NetworkStreamer\n","/**\n * @file Loader\n * @author Alexander Rose \n * @private\n */\n\nimport { ParserRegistry } from '../globals'\nimport { createParams } from '../utils'\nimport FileStreamer from '../streamer/file-streamer'\nimport NetworkStreamer from '../streamer/network-streamer'\nimport { LoaderParameters, LoaderInput } from './loader-utils'\n\n/**\n * Loader parameter object.\n * @typedef {Object} LoaderParameters - loader parameters\n * @property {String} ext - file extension, determines file type\n * @property {Boolean} compressed - flag data as compressed\n * @property {Boolean} binary - flag data as binary\n * @property {String} name - set data name\n */\n\n/**\n * Loader base class\n */\nabstract class Loader {\n parameters: LoaderParameters\n streamer: FileStreamer | NetworkStreamer\n\n /**\n * Construct a loader object\n * @param {String|File|Blob} src - data source, string is interpreted as an URL\n * @param {LoaderParameters} params - parameters object\n */\n constructor (src: LoaderInput, params: Partial = {}) {\n this.parameters = createParams(params, {\n ext: '',\n compressed: false,\n binary: ParserRegistry.isBinary(params.ext || ''),\n name: '',\n\n dir: '',\n path: '',\n protocol: ''\n } as LoaderParameters)\n\n const streamerParams = {\n compressed: this.parameters.compressed as string|false,\n binary: this.parameters.binary,\n json: ParserRegistry.isJson(this.parameters.ext),\n xml: ParserRegistry.isXml(this.parameters.ext)\n }\n\n if ((typeof File !== 'undefined' && src instanceof File) ||\n (typeof Blob !== 'undefined' && src instanceof Blob)\n ) {\n this.streamer = new FileStreamer(src, streamerParams)\n } else {\n this.streamer = new NetworkStreamer(src, streamerParams)\n }\n }\n\n /**\n * Load data\n * @abstract\n * @return {Promise} resolves to the loaded data {@link Object}\n */\n abstract load (): Promise\n}\n\nexport default Loader\n","/**\n * @file Parser Loader\n * @author Alexander Rose \n * @private\n */\n\nimport { ParserRegistry } from '../globals'\nimport type { InferBondsOptions } from '../structure/structure-utils'\nimport Loader from './loader'\nimport { LoaderParameters, LoaderInput } from './loader-utils'\n\nexport interface ParserParams {\n voxelSize?: number\n firstModelOnly?: boolean\n asTrajectory?: boolean\n cAlphaOnly?: boolean\n name?: string\n path?: string\n delimiter?: string\n comment?: string\n columnNames?: string\n inferBonds?: InferBondsOptions\n}\n\n/**\n * Parser loader class\n * @extends Loader\n */\nclass ParserLoader extends Loader {\n parserParams: ParserParams\n\n constructor (src: LoaderInput, params: Partial & ParserParams = {}) {\n super(src, params)\n this.parserParams = {\n voxelSize: params.voxelSize,\n firstModelOnly: params.firstModelOnly,\n asTrajectory: params.asTrajectory,\n cAlphaOnly: params.cAlphaOnly,\n delimiter: params.delimiter,\n comment: params.comment,\n columnNames: params.columnNames,\n inferBonds: params.inferBonds,\n name: this.parameters.name,\n path: this.parameters.path\n }\n }\n\n /**\n * Load parsed object\n * @return {Promise} resolves to the loaded & parsed {@link Structure},\n * {@link Volume}, {@link Surface} or data object\n */\n load () {\n var ParserClass = ParserRegistry.get(this.parameters.ext)\n var parser = new ParserClass(this.streamer, this.parserParams)\n\n return parser.parse()\n }\n}\n\nexport default ParserLoader\n","/**\n * @file Script\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\n\nimport { Log } from './globals'\nimport Stage from './stage/stage'\n\nexport interface ScriptSignals {\n elementAdded: Signal\n elementRemoved: Signal\n nameChanged: Signal\n}\n\n/**\n * Script class\n */\nclass Script {\n readonly signals: ScriptSignals = {\n elementAdded: new Signal(),\n elementRemoved: new Signal(),\n nameChanged: new Signal()\n }\n\n readonly dir: string\n readonly fn: Function\n\n readonly type = 'Script'\n\n /**\n * Create a script instance\n * @param {String} functionBody - the function source\n * @param {String} name - name of the script\n * @param {String} path - path of the script\n */\n constructor (functionBody: string, readonly name: string, readonly path: string) {\n this.dir = path.substring(0, path.lastIndexOf('/') + 1)\n\n try {\n /* eslint-disable no-new-func */\n this.fn = new Function('stage', '__name', '__path', '__dir', functionBody)\n } catch (e) {\n Log.error('Script compilation failed', e)\n this.fn = function () {}\n }\n }\n\n /**\n * Execute the script\n * @param {Stage} stage - the stage context\n * @return {Promise} - resolve when script finished running\n */\n run (stage: Stage): Promise {\n return new Promise((resolve, reject) => {\n try {\n this.fn.apply(null, [ stage, this.name, this.path, this.dir ])\n resolve()\n } catch (e) {\n Log.error('Script.fn', e)\n reject(e)\n }\n })\n }\n}\n\nexport default Script\n","/**\n * @file Script Loader\n * @author Alexander Rose \n * @private\n */\n\nimport Loader from './loader'\nimport Script from '../script'\n\n/**\n * Script loader class\n * @extends Loader\n */\nclass ScriptLoader extends Loader {\n /**\n * Load script\n * @return {Promise} resolves to the loaded {@link Script}\n */\n load () {\n return this.streamer.read().then(() => {\n return new Script(\n this.streamer.asText(), this.parameters.name, this.parameters.path\n )\n })\n }\n}\n\nexport default ScriptLoader\n","/**\n * @file Loader Utils\n * @author Alexander Rose \n * @private\n */\n\nimport {\n DatasourceRegistry, DecompressorRegistry, ParserRegistry, ScriptExtensions\n} from '../globals'\nimport ParserLoader, { ParserParams } from './parser-loader'\nimport ScriptLoader from './script-loader'\n\nexport interface LoaderParameters {\n ext: string // file extension, determines file type\n compressed: string|false // flag data as compressed\n binary: boolean // flag data as binary\n name: string // set data name\n\n dir: string\n path: string\n protocol: string\n}\n\nexport type LoaderInput = File|Blob|string\n\nexport function getFileInfo (file: LoaderInput) {\n const compressedExtList = DecompressorRegistry.names\n\n let path: string\n let compressed: string|false\n let protocol = ''\n\n if (file instanceof File) {\n path = file.name\n } else if (file instanceof Blob) {\n path = ''\n } else {\n path = file\n }\n const queryIndex = path.lastIndexOf('?')\n const query = queryIndex !== -1 ? path.substring(queryIndex) : ''\n path = path.substring(0, queryIndex === -1 ? path.length : queryIndex)\n\n const name = path.replace(/^.*[\\\\/]/, '')\n let base = name.substring(0, name.lastIndexOf('.'))\n\n const nameSplit = name.split('.')\n let ext = nameSplit.length > 1 ? (nameSplit.pop() || '').toLowerCase() : ''\n\n const protocolMatch = path.match(/^(.+):\\/\\/(.+)$/)\n if (protocolMatch) {\n protocol = protocolMatch[ 1 ].toLowerCase()\n path = protocolMatch[ 2 ] || ''\n }\n\n const dir = path.substring(0, path.lastIndexOf('/') + 1)\n\n if (compressedExtList.includes(ext)) {\n compressed = ext\n const n = path.length - ext.length - 1\n ext = (path.substr(0, n).split('.').pop() || '').toLowerCase()\n const m = base.length - ext.length - 1\n base = base.substr(0, m)\n } else {\n compressed = false\n }\n\n return { path, name, ext, base, dir, compressed, protocol, query, 'src': file }\n}\n\nexport function getDataInfo (src: LoaderInput) {\n let info = getFileInfo(src)\n const datasource = DatasourceRegistry.get(info.protocol)\n if (datasource) {\n info = getFileInfo(datasource.getUrl(info.src))\n if (!info.ext && datasource.getExt) {\n info.ext = datasource.getExt(src)\n }\n }\n return info\n}\n\n/**\n * Load a file\n *\n * @example\n * // load from URL\n * NGL.autoLoad( \"http://files.rcsb.org/download/5IOS.cif\" );\n *\n * @example\n * // load binary data in CCP4 format via a Blob\n * var binaryBlob = new Blob( [ ccp4Data ], { type: 'application/octet-binary'} );\n * NGL.autoLoad( binaryBlob, { ext: \"ccp4\" } );\n *\n * @example\n * // load string data in PDB format via a Blob\n * var stringBlob = new Blob( [ pdbData ], { type: 'text/plain'} );\n * NGL.autoLoad( stringBlob, { ext: \"pdb\" } );\n *\n * @example\n * // load a File object\n * NGL.autoLoad( file );\n *\n * @param {String|File|Blob} file - either a URL or an object containing the file data\n * @param {LoaderParameters} params - loading parameters\n * @return {Promise} Promise resolves to the loaded data\n */\nexport function autoLoad (file: LoaderInput, params: Partial = {}) {\n const p = Object.assign(getDataInfo(file), params)\n\n let loader\n if (ParserRegistry.names.includes(p.ext)) {\n loader = new ParserLoader(p.src, p)\n } else if (ScriptExtensions.includes(p.ext)) {\n loader = new ScriptLoader(p.src, p)\n }\n\n if (loader) {\n return loader.load()\n } else {\n return Promise.reject(new Error(`autoLoad: ext '${p.ext}' unknown`))\n }\n}\n","/**\n * @file Writer\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults, download } from '../utils'\n\n/**\n * Base class for writers\n * @interface\n */\nabstract class Writer {\n readonly mimeType: string\n readonly defaultName: string\n readonly defaultExt: string\n\n /**\n * @abstract\n * @return {Anything} the data to be written\n */\n abstract getData (): any\n\n /**\n * Get a blob with the written data\n * @return {Blob} the blob\n */\n getBlob () {\n return new Blob([ this.getData() ], { type: this.mimeType })\n }\n\n /**\n * Trigger a download of the\n * @param {[type]} name [description]\n * @param {[type]} ext [description]\n * @return {[type]} [description]\n */\n download (name?: string, ext?: string) {\n name = defaults(name, this.defaultName)\n ext = defaults(ext, this.defaultExt)\n\n download(this.getBlob(), `${name}.${ext}`)\n }\n}\n\nexport default Writer","/**\n * @file Pdb Writer\n * @author Alexander Rose \n * @private\n */\n\nimport { sprintf } from 'sprintf-js'\n\nimport Writer from './writer'\nimport { defaults, ensureArray } from '../utils'\nimport Structure from '../structure/structure'\nimport AtomProxy from '../proxy/atom-proxy'\n\n// http://www.wwpdb.org/documentation/file-format\n\n// Sample PDB line, the coords X,Y,Z are fields 5,6,7 on each line.\n// ATOM 1 N ARG 1 29.292 13.212 -12.751 1.00 33.78 1BPT 108\n\nconst AtomFormat =\n 'ATOM %5d %-4s %3s %1s%4d %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%1s%1s'\n\nconst HetatmFormat =\n 'HETATM%5d %-4s %3s %1s%4d %8.3f%8.3f%8.3f%6.2f%6.2f %4s%2s%1s%1s'\n\nexport interface PdbWriterParams {\n renumberSerial: boolean\n remarks: string[]\n}\n\n/**\n * Create a PDB file from a Structure object\n */\nexport default class PdbWriter extends Writer {\n readonly mimeType = 'text/plain'\n readonly defaultName = 'structure'\n readonly defaultExt = 'pdb'\n\n renumberSerial: boolean\n remarks: string[]\n\n structure: Structure\n private _records: string[]\n\n /**\n * @param {Structure} structure - the structure object\n * @param {Object} params - parameters]\n */\n constructor (structure: Structure, params?: PdbWriterParams) {\n super()\n\n const p = Object.assign({}, params)\n\n this.renumberSerial = defaults(p.renumberSerial, true)\n this.remarks = ensureArray(defaults(p.remarks, []))\n\n this.structure = structure\n this._records = []\n }\n\n private _writeRecords () {\n this._records.length = 0\n\n this._writeTitle()\n this._writeRemarks()\n this._writeAtoms()\n }\n\n private _writeTitle () {\n // FIXME multiline if title line longer than 80 chars\n this._records.push(sprintf('TITLE %-74s', this.structure.name))\n }\n\n private _writeRemarks () {\n this.remarks.forEach(str => {\n this._records.push(sprintf('REMARK %-73s', str))\n })\n\n if (this.structure.trajectory) {\n this._records.push(sprintf(\n 'REMARK %-73s',\n \"Trajectory '\" + this.structure.trajectory.name + \"'\"\n ))\n this._records.push(sprintf(\n 'REMARK %-73s',\n `Frame ${(this.structure.trajectory as any).frame}` // TODO\n ))\n }\n }\n\n private _writeAtoms () {\n let ia = 1\n let im = 1\n let charge = \" \"\n let chargeSign = \" \"\n const hasModels = this.structure.modelStore.count > 1\n\n this.structure.eachModel(m => {\n if (hasModels) this._records.push(sprintf('MODEL %4d%-66s', im++, ''))\n\n m.eachAtom((a: AtomProxy) => {\n const formatString = a.hetero ? HetatmFormat : AtomFormat\n const serial = this.renumberSerial ? ia : a.serial\n\n // Formal PDB spec\n // Alignment of one-letter atom name such as C starts at column 14,\n // while two-letter atom name such as FE starts at column 13.\n\n // This, however, leaves Calcium and C-alpha ambiguous\n // The convention (from earlier versions of the spec, see 1992, and also: \n // https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/tutorials/pdbintro.html#misalignment)\n // is that element is right-justified in 13-14, modifiers are left justified in columns 15-16\n // A single-character element symmbol should not appear in column 13 unless the atom name has four characters\n let atomname = a.atomname\n\n if (atomname.length === 1) {\n // Simple case\n atomname = ' ' + atomname\n } else if (atomname.length < 4) {\n // 2 or 3-letter name, if element symbol is single char and matches name, add a space\n if (a.element.length === 1 && atomname[0] === a.element) {\n atomname = ' ' + atomname\n }\n }\n\n if (a.formalCharge) { // Skip nulls and zeros\n charge = Math.abs(a.formalCharge).toPrecision(1)\n chargeSign = (a.formalCharge > 0) ? \"+\" : \"-\"\n } else {\n charge = \" \"\n chargeSign = \" \"\n }\n\n this._records.push(sprintf(\n formatString,\n\n serial,\n atomname,\n a.resname,\n defaults(a.chainname, ' '),\n a.resno,\n a.x, a.y, a.z,\n defaults(a.occupancy, 1.0),\n defaults(a.bfactor, 0.0),\n '', // segid\n defaults(a.element, ''),\n charge,\n chargeSign\n ))\n ia += 1\n }, this.structure.getSelection())\n\n if (hasModels) this._records.push(sprintf('%-80s', 'ENDMDL'))\n })\n\n this._records.push(sprintf('%-80s', 'END'))\n }\n\n getString () {\n console.warn('PdbWriter.getString() is deprecated, use .getData instead')\n return this.getData()\n }\n\n /**\n * Get string containing the PDB file data\n * @return {String} PDB file\n */\n getData () {\n this._writeRecords()\n return this._records.join('\\n')\n }\n}\n","/**\n * Writer class for sdf/mol files.\n */\n\nimport { sprintf } from 'sprintf-js'\n\nimport Writer from './writer'\nimport Structure from '../structure/structure'\nimport AtomProxy from '../proxy/atom-proxy'\nimport BondProxy from '../proxy/bond-proxy'\n\n// Hard-coded chiral as false as we don't specify it any atoms\nconst CountFormat = '%3i%3i 0 0 0 0 0 0 0 0999 V2000'\nconst AtomLine = '%10.4f%10.4f%10.4f %-3s 0%3i 0 0 0'\nconst BondFormat = '%3i%3i%3i 0 0 0'\n\nclass SdfWriter extends Writer {\n readonly mimeType = 'text/plain'\n readonly defaultName = 'structure'\n readonly defaultExt = 'sdf'\n\n structure: Structure\n private _records: string[]\n\n /**\n * @param {Structure} structure - structure to write\n * @param {Object} params - parameters\n */\n constructor (structure: Structure) {\n super()\n\n this.structure = structure\n // Follow the pdb-writer example:\n this._records = []\n }\n\n get idString () {\n return this.structure.id\n }\n\n get titleString () {\n return ' ' + this.structure.title\n }\n\n get countsString () {\n return sprintf(\n CountFormat,\n this.structure.atomCount,\n this.structure.bondCount\n )\n }\n\n get chargeLines () {\n const pairs: [number, number][] = []\n this.structure.eachAtom(ap => {\n if (ap.formalCharge != null && ap.formalCharge !== 0) {\n pairs.push([ap.index, ap.formalCharge])\n }\n })\n const lines = []\n for (let i = 0; i < pairs.length; i += 8) {\n const nCharges = Math.min(8, pairs.length - i)\n let s = sprintf('M CHG%3i', nCharges)\n for (let j = i; j < i + nCharges; j++) {\n s += sprintf(' %3i %3i', pairs[j][0] + 1, pairs[j][1])\n }\n lines.push(s)\n }\n return lines\n }\n\n formatAtom (ap: AtomProxy) {\n let charge = 0\n if (ap.formalCharge != null && ap.formalCharge !== 0) {\n charge = 4 - ap.formalCharge\n }\n const line = sprintf(\n AtomLine, ap.x, ap.y, ap.z, ap.element, charge\n )\n if (line.length !== 48) { throw new Error('Incompatible atom for sdf format') }\n\n return line\n }\n\n formatBond (bp: BondProxy) {\n return sprintf(\n BondFormat,\n bp.atomIndex1 + 1,\n bp.atomIndex2 + 1,\n bp.bondOrder)\n }\n\n _writeRecords () {\n this._records.length = 0\n this._writeHeader()\n this._writeCTab()\n this._writeFooter()\n }\n\n _writeHeader () {\n this._records.push(this.idString, this.titleString, '')\n }\n\n _writeCTab () {\n this._records.push(this.countsString)\n this.structure.eachAtom(ap => {\n this._records.push(this.formatAtom(ap))\n })\n this.structure.eachBond(bp => {\n this._records.push(this.formatBond(bp))\n })\n this.chargeLines.forEach(line => {\n this._records.push(line)\n })\n this._records.push('M END')\n }\n\n _writeFooter () {\n this._records.push('$$$$')\n }\n\n getData () {\n this._writeRecords()\n return this._records.join('\\n')\n }\n}\n\nexport default SdfWriter\n","/**\n * @file IO Buffer\n * @author Alexander Rose \n * @private\n *\n * Adapted and converted to TypeScript from https://github.com/image-js/iobuffer\n * MIT License, Copyright (c) 2015 Michaël Zasso\n */\n\nimport { TypedArray } from '../types'\n\nconst defaultByteLength = 1024 * 8\nconst charArray: string[] = []\n\nexport interface IOBufferParameters {\n offset?: number // Ignore the first n bytes of the ArrayBuffer\n}\n\n/**\n * Class for writing and reading binary data\n */\nclass IOBuffer {\n private _lastWrittenByte: number\n private _mark = 0\n private _marks: number[] = []\n private _data: DataView\n\n offset = 0 // The current offset of the buffer's pointer\n littleEndian = true\n buffer: ArrayBuffer // Reference to the internal ArrayBuffer object\n length: number // Byte length of the internal ArrayBuffer\n byteLength: number // Byte length of the internal ArrayBuffer\n byteOffset: number // Byte offset of the internal ArrayBuffer\n\n /**\n * If it's a number, it will initialize the buffer with the number as\n * the buffer's length. If it's undefined, it will initialize the buffer\n * with a default length of 8 Kb. If its an ArrayBuffer, a TypedArray,\n * it will create a view over the underlying ArrayBuffer.\n */\n constructor (data: number|ArrayBuffer|TypedArray, params: IOBufferParameters = {}) {\n let dataIsGiven = false\n if (data === undefined) {\n data = defaultByteLength\n }\n if (typeof data === 'number') {\n data = new ArrayBuffer(data)\n } else {\n dataIsGiven = true\n }\n\n const offset = params.offset ? params.offset >>> 0 : 0\n let byteLength = data.byteLength - offset\n let dvOffset = offset\n if (!(data instanceof ArrayBuffer)) {\n if (data.byteLength !== data.buffer.byteLength) {\n dvOffset = data.byteOffset + offset\n }\n data = data.buffer\n }\n if (dataIsGiven) {\n this._lastWrittenByte = byteLength\n } else {\n this._lastWrittenByte = 0\n }\n\n this.buffer = data\n this.length = byteLength\n this.byteLength = byteLength\n this.byteOffset = dvOffset\n\n this._data = new DataView(this.buffer, dvOffset, byteLength)\n }\n\n /**\n * Checks if the memory allocated to the buffer is sufficient to store more bytes after the offset\n * @param {number} [byteLength=1] The needed memory in bytes\n * @return {boolean} Returns true if there is sufficient space and false otherwise\n */\n available (byteLength: number) {\n if (byteLength === undefined) byteLength = 1\n return (this.offset + byteLength) <= this.length\n }\n\n /**\n * Check if little-endian mode is used for reading and writing multi-byte values\n * @return {boolean} Returns true if little-endian mode is used, false otherwise\n */\n isLittleEndian () {\n return this.littleEndian\n }\n\n /**\n * Set little-endian mode for reading and writing multi-byte values\n * @return {IOBuffer}\n */\n setLittleEndian () {\n this.littleEndian = true\n return this\n }\n\n /**\n * Check if big-endian mode is used for reading and writing multi-byte values\n * @return {boolean} Returns true if big-endian mode is used, false otherwise\n */\n isBigEndian () {\n return !this.littleEndian\n }\n\n /**\n * Switches to big-endian mode for reading and writing multi-byte values\n * @return {IOBuffer}\n */\n setBigEndian () {\n this.littleEndian = false\n return this\n }\n\n /**\n * Move the pointer n bytes forward\n * @param {number} n\n * @return {IOBuffer}\n */\n skip (n: number) {\n if (n === undefined) n = 1\n this.offset += n\n return this\n }\n\n /**\n * Move the pointer to the given offset\n * @param {number} offset\n * @return {IOBuffer}\n */\n seek (offset: number) {\n this.offset = offset\n return this\n }\n\n /**\n * Store the current pointer offset.\n * @see {@link IOBuffer#reset}\n * @return {IOBuffer}\n */\n mark () {\n this._mark = this.offset\n return this\n }\n\n /**\n * Move the pointer back to the last pointer offset set by mark\n * @see {@link IOBuffer#mark}\n * @return {IOBuffer}\n */\n reset () {\n this.offset = this._mark\n return this\n }\n\n /**\n * Push the current pointer offset to the mark stack\n * @see {@link IOBuffer#popMark}\n * @return {IOBuffer}\n */\n pushMark () {\n this._marks.push(this.offset)\n return this\n }\n\n /**\n * Pop the last pointer offset from the mark stack, and set the current pointer offset to the popped value\n * @see {@link IOBuffer#pushMark}\n * @return {IOBuffer}\n */\n popMark () {\n const offset = this._marks.pop()\n if (offset === undefined) throw new Error('Mark stack empty')\n this.seek(offset)\n return this\n }\n\n /**\n * Move the pointer offset back to 0\n * @return {IOBuffer}\n */\n rewind () {\n this.offset = 0\n return this\n }\n\n /**\n * Make sure the buffer has sufficient memory to write a given byteLength at the current pointer offset\n * If the buffer's memory is insufficient, this method will create a new buffer (a copy) with a length\n * that is twice (byteLength + current offset)\n * @param {number} [byteLength = 1]\n * @return {IOBuffer}\n */\n ensureAvailable (byteLength: number) {\n if (byteLength === undefined) byteLength = 1\n if (!this.available(byteLength)) {\n const lengthNeeded = this.offset + byteLength\n const newLength = lengthNeeded * 2\n const newArray = new Uint8Array(newLength)\n newArray.set(new Uint8Array(this.buffer))\n this.buffer = newArray.buffer\n this.length = this.byteLength = newLength\n this._data = new DataView(this.buffer)\n }\n return this\n }\n\n /**\n * Read a byte and return false if the byte's value is 0, or true otherwise\n * Moves pointer forward\n * @return {boolean}\n */\n readBoolean () {\n return this.readUint8() !== 0\n }\n\n /**\n * Read a signed 8-bit integer and move pointer forward\n * @return {number}\n */\n readInt8 () {\n return this._data.getInt8(this.offset++)\n }\n\n /**\n * Read an unsigned 8-bit integer and move pointer forward\n * @return {number}\n */\n readUint8 () {\n return this._data.getUint8(this.offset++)\n }\n\n /**\n * Alias for {@link IOBuffer#readUint8}\n * @return {number}\n */\n readByte () {\n return this.readUint8()\n }\n\n /**\n * Read n bytes and move pointer forward.\n * @param {number} n\n * @return {Uint8Array}\n */\n readBytes (n: number) {\n if (n === undefined) n = 1\n var bytes = new Uint8Array(n)\n for (var i = 0; i < n; i++) {\n bytes[i] = this.readByte()\n }\n return bytes\n }\n\n /**\n * Read a 16-bit signed integer and move pointer forward\n * @return {number}\n */\n readInt16 () {\n var value = this._data.getInt16(this.offset, this.littleEndian)\n this.offset += 2\n return value\n }\n\n /**\n * Read a 16-bit unsigned integer and move pointer forward\n * @return {number}\n */\n readUint16 () {\n var value = this._data.getUint16(this.offset, this.littleEndian)\n this.offset += 2\n return value\n }\n\n /**\n * Read a 32-bit signed integer and move pointer forward\n * @return {number}\n */\n readInt32 () {\n var value = this._data.getInt32(this.offset, this.littleEndian)\n this.offset += 4\n return value\n }\n\n /**\n * Read a 32-bit unsigned integer and move pointer forward\n * @return {number}\n */\n readUint32 () {\n var value = this._data.getUint32(this.offset, this.littleEndian)\n this.offset += 4\n return value\n }\n\n /**\n * Read a 32-bit floating number and move pointer forward\n * @return {number}\n */\n readFloat32 () {\n var value = this._data.getFloat32(this.offset, this.littleEndian)\n this.offset += 4\n return value\n }\n\n /**\n * Read a 64-bit floating number and move pointer forward\n * @return {number}\n */\n readFloat64 () {\n var value = this._data.getFloat64(this.offset, this.littleEndian)\n this.offset += 8\n return value\n }\n\n /**\n * Read 1-byte ascii character and move pointer forward\n * @return {string}\n */\n readChar () {\n return String.fromCharCode(this.readInt8())\n }\n\n /**\n * Read n 1-byte ascii characters and move pointer forward\n * @param {number} n\n * @return {string}\n */\n readChars (n = 1) {\n charArray.length = n\n for (var i = 0; i < n; i++) {\n charArray[i] = this.readChar()\n }\n return charArray.join('')\n }\n\n /**\n * Write 0xff if the passed value is truthy, 0x00 otherwise\n * @param {any} value\n * @return {IOBuffer}\n */\n writeBoolean (value = false) {\n this.writeUint8(value ? 0xff : 0x00)\n return this\n }\n\n /**\n * Write value as an 8-bit signed integer\n * @param {number} value\n * @return {IOBuffer}\n */\n writeInt8 (value: number) {\n this.ensureAvailable(1)\n this._data.setInt8(this.offset++, value)\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write value as a 8-bit unsigned integer\n * @param {number} value\n * @return {IOBuffer}\n */\n writeUint8 (value: number) {\n this.ensureAvailable(1)\n this._data.setUint8(this.offset++, value)\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * An alias for {@link IOBuffer#writeUint8}\n * @param {number} value\n * @return {IOBuffer}\n */\n writeByte (value: number) {\n return this.writeUint8(value)\n }\n\n /**\n * Write bytes\n * @param {Array|Uint8Array} bytes\n * @return {IOBuffer}\n */\n writeBytes (bytes: number[]|Uint8Array) {\n this.ensureAvailable(bytes.length)\n for (var i = 0; i < bytes.length; i++) {\n this._data.setUint8(this.offset++, bytes[i])\n }\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write value as an 16-bit signed integer\n * @param {number} value\n * @return {IOBuffer}\n */\n writeInt16 (value: number) {\n this.ensureAvailable(2)\n this._data.setInt16(this.offset, value, this.littleEndian)\n this.offset += 2\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write value as a 16-bit unsigned integer\n * @param {number} value\n * @return {IOBuffer}\n */\n writeUint16 (value: number) {\n this.ensureAvailable(2)\n this._data.setUint16(this.offset, value, this.littleEndian)\n this.offset += 2\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write a 32-bit signed integer at the current pointer offset\n * @param {number} value\n * @return {IOBuffer}\n */\n writeInt32 (value: number) {\n this.ensureAvailable(4)\n this._data.setInt32(this.offset, value, this.littleEndian)\n this.offset += 4\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write a 32-bit unsigned integer at the current pointer offset\n * @param {number} value - The value to set\n * @return {IOBuffer}\n */\n writeUint32 (value: number) {\n this.ensureAvailable(4)\n this._data.setUint32(this.offset, value, this.littleEndian)\n this.offset += 4\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write a 32-bit floating number at the current pointer offset\n * @param {number} value - The value to set\n * @return {IOBuffer}\n */\n writeFloat32 (value: number) {\n this.ensureAvailable(4)\n this._data.setFloat32(this.offset, value, this.littleEndian)\n this.offset += 4\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write a 64-bit floating number at the current pointer offset\n * @param {number} value\n * @return {IOBuffer}\n */\n writeFloat64 (value: number) {\n this.ensureAvailable(8)\n this._data.setFloat64(this.offset, value, this.littleEndian)\n this.offset += 8\n this._updateLastWrittenByte()\n return this\n }\n\n /**\n * Write the charCode of the passed string's first character to the current pointer offset\n * @param {string} str - The character to set\n * @return {IOBuffer}\n */\n writeChar (str: string) {\n return this.writeUint8(str.charCodeAt(0))\n }\n\n /**\n * Write the charCodes of the passed string's characters to the current pointer offset\n * @param {string} str\n * @return {IOBuffer}\n */\n writeChars (str: string) {\n for (var i = 0; i < str.length; i++) {\n this.writeUint8(str.charCodeAt(i))\n }\n return this\n }\n\n /**\n * Export a Uint8Array view of the internal buffer.\n * The view starts at the byte offset and its length\n * is calculated to stop at the last written byte or the original length.\n * @return {Uint8Array}\n */\n toArray () {\n return new Uint8Array(this.buffer, this.byteOffset, this._lastWrittenByte)\n }\n\n /**\n * Update the last written byte offset\n * @private\n */\n _updateLastWrittenByte () {\n if (this.offset > this._lastWrittenByte) {\n this._lastWrittenByte = this.offset\n }\n }\n}\n\nexport default IOBuffer\n","/**\n * @file STL Writer\n * @author Paul Pillot \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport Writer from './writer'\nimport IOBuffer from '../utils/io-buffer'\nimport Surface from '../surface/surface'\n\n// https://en.wikipedia.org/wiki/STL_(file_format)#ASCII_STL\n\n/**\n * Create an STL File from a surface Object (e.g. for 3D printing)\n *\n * @example\n * molsurf = new MolecularSurface(structure)\n * surf = molsurf.getSurface({type: 'av', probeRadius: 1.4})\n * stl = new StlWriter(surf)\n * stl.download('myFileName')\n */\nexport default class StlWriter extends Writer {\n readonly mimeType = 'application/vnd.ms-pki.stl'\n readonly defaultName = 'surface'\n readonly defaultExt = 'stl'\n\n surface: any // TODO\n\n /**\n * @param {Surface} surface - the surface to write out\n */\n constructor (surface: Surface) {\n super()\n\n this.surface = surface\n }\n\n /*\n * Get STL Binary data\n *\n * Adapted from: https://github.com/mrdoob/three.js/blob/master/examples/js/exporters/STLBinaryExporter.js\n * see https://en.wikipedia.org/wiki/STL_(file_format)#Binary_STL for the file format description\n *\n * @return {DataView} the data\n */\n getData () {\n const triangles = this.surface.index.length / 3\n const bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4\n const output = new IOBuffer(bufferLength)\n\n output.skip(80) // skip header\n output.writeUint32(triangles)\n\n const vector = new Vector3()\n const vectorNorm1 = new Vector3()\n const vectorNorm2 = new Vector3()\n const vectorNorm3 = new Vector3()\n\n // traversing vertices\n for (let i = 0; i < triangles; i++) {\n const indices = [\n this.surface.index[i * 3],\n this.surface.index[i * 3 + 1],\n this.surface.index[i * 3 + 2]\n ]\n\n vectorNorm1.fromArray(this.surface.normal, indices[0] * 3)\n vectorNorm2.fromArray(this.surface.normal, indices[1] * 3)\n vectorNorm3.fromArray(this.surface.normal, indices[2] * 3)\n\n vector.addVectors(vectorNorm1, vectorNorm2).add(vectorNorm3).normalize()\n\n output.writeFloat32(vector.x)\n output.writeFloat32(vector.y)\n output.writeFloat32(vector.z)\n\n for (let j = 0; j < 3; j++) {\n vector.fromArray(this.surface.position, indices[j] * 3)\n\n output.writeFloat32(vector.x) // vertices\n output.writeFloat32(vector.y)\n output.writeFloat32(vector.z)\n }\n\n output.writeUint16(0) // attribute byte count\n }\n\n return new DataView(output.buffer)\n }\n}","/**\n * @file Counter\n * @author Alexander Rose \n * @private\n */\n\nimport { Log } from '../globals'\n\nimport * as signalsWrapper from 'signals'\n\n/**\n * {@link Signal}, dispatched when the `count` changes\n * @example\n * counter.signals.countChanged.add( function( delta ){ ... } );\n * @event Counter#countChanged\n * @type {Integer}\n */\n\nexport interface CounterSignals {\n countChanged: signalsWrapper.Signal\n}\n\n/**\n * Counter class for keeping track of counts\n */\nclass Counter {\n count = 0\n\n signals: CounterSignals = {\n countChanged: new signalsWrapper.Signal()\n }\n\n /**\n * Set the `count` to zero\n * @return {undefined}\n */\n clear () {\n this.change(-this.count)\n }\n\n /**\n * Change the `count`\n * @fires Counter#countChanged\n * @param {Integer} delta - count change\n * @return {undefined}\n */\n change (delta: number) {\n this.count += delta\n this.signals.countChanged.dispatch(delta, this.count)\n\n if (this.count < 0) {\n Log.warn('Counter.count below zero', this.count)\n }\n }\n\n /**\n * Increments the `count` by one.\n * @return {undefined}\n */\n increment () {\n this.change(1)\n }\n\n /**\n * Decrements the `count` by one.\n * @return {undefined}\n */\n decrement () {\n this.change(-1)\n }\n\n /**\n * Listen to another counter object and change this `count` by the\n * same amount\n * @param {Counter} counter - the counter object to listen to\n * @return {undefined}\n */\n listen (counter: Counter) {\n this.change(counter.count)\n counter.signals.countChanged.add(this.change, this)\n }\n\n /**\n * Stop listening to the other counter object\n * @param {Counter} counter - the counter object to stop listening to\n * @return {undefined}\n */\n unlisten (counter: Counter) {\n const countChanged = counter.signals.countChanged\n if (countChanged.has(this.change, this)) {\n countChanged.remove(this.change, this)\n }\n }\n\n /**\n * Invole the callback function once, when the `count` becomes zero\n * @param {Function} callback - the callback function\n * @param {Object} context - the context for the callback function\n * @return {undefined}\n */\n onZeroOnce (callback: () => void, context?: any) {\n if (this.count === 0) {\n callback.call(context)\n } else {\n const fn = () => {\n if (this.count === 0) {\n this.signals.countChanged.remove(fn, this)\n callback.call(context)\n }\n }\n this.signals.countChanged.add(fn, this)\n }\n }\n\n dispose () {\n this.clear()\n this.signals.countChanged.dispose()\n }\n}\n\nexport default Counter\n","/**\n * @file Stats\n * @author Alexander Rose \n * @private\n */\n\nimport * as signalsWrapper from 'signals'\n\nexport default class Stats {\n signals = {\n updated: new signalsWrapper.Signal()\n }\n\n maxDuration = -Infinity\n minDuration = Infinity\n avgDuration = 14\n lastDuration = Infinity\n\n prevFpsTime = 0\n lastFps = Infinity\n lastFrames = 1\n frames = 0\n count = 0\n\n startTime: number\n currentTime: number\n\n constructor () {\n this.begin()\n }\n\n update () {\n this.startTime = this.end()\n this.currentTime = this.startTime\n this.signals.updated.dispatch()\n }\n\n begin () {\n this.startTime = window.performance.now()\n this.lastFrames = this.frames\n }\n\n end () {\n const time = window.performance.now()\n\n this.count += 1\n this.frames += 1\n\n this.lastDuration = time - this.startTime\n this.minDuration = Math.min(this.minDuration, this.lastDuration)\n this.maxDuration = Math.max(this.maxDuration, this.lastDuration)\n this.avgDuration -= this.avgDuration / 30\n this.avgDuration += this.lastDuration / 30\n\n if (time > this.prevFpsTime + 1000) {\n this.lastFps = this.frames\n this.prevFpsTime = time\n this.frames = 0\n }\n\n return time\n }\n}","/**\n * @file Shader Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { ShaderChunk } from 'three'\n\nimport './chunk/fog_fragment.glsl'\nimport './chunk/interior_fragment.glsl'\nimport './chunk/matrix_scale.glsl'\nimport './chunk/nearclip_vertex.glsl'\nimport './chunk/nearclip_fragment.glsl'\nimport './chunk/opaque_back_fragment.glsl'\nimport './chunk/radiusclip_vertex.glsl'\nimport './chunk/radiusclip_fragment.glsl'\nimport './chunk/unpack_color.glsl'\n\nimport { ShaderRegistry } from '../globals'\n\nexport type ShaderDefine = (\n 'NEAR_CLIP'|'RADIUS_CLIP'|'PICKING'|'NOLIGHT'|'FLAT_SHADED'|'OPAQUE_BACK'|\n 'DIFFUSE_INTERIOR'|'USE_INTERIOR_COLOR'|\n 'USE_SIZEATTENUATION'|'USE_MAP'|'USE_ALPHATEST'|'SDF'|'FIXED_SIZE'|\n 'CUBIC_INTERPOLATION'|'BSPLINE_FILTER'|'CATMULROM_FILTER'|'MITCHELL_FILTER'\n)\nexport type ShaderDefines = {\n [k in ShaderDefine]?: number|string\n}\n\nfunction getDefines (defines: ShaderDefines) {\n if (defines === undefined) return ''\n\n const lines = []\n\n for (const name in defines) {\n const value = defines[ name as keyof ShaderDefines ]\n\n if (!value) continue\n\n lines.push(`#define ${name} ${value}`)\n }\n\n return lines.join('\\n') + '\\n'\n}\n\nconst reInclude = /^(?!\\/\\/)\\s*#include\\s+(\\S+)/gmi\nconst shaderCache: { [k: string]: string } = {}\n\nexport function getShader (name: string, defines: ShaderDefines = {}) {\n let hash = name + '|'\n for (const key in defines) {\n hash += key + ':' + defines[ key as keyof ShaderDefines ]\n }\n\n if (!shaderCache[ hash ]) {\n const definesText = getDefines(defines)\n\n let shaderText = ShaderRegistry.get(`shader/${name}`) as string\n if (!shaderText) {\n throw new Error(`empty shader, '${name}'`)\n }\n shaderText = shaderText.replace(reInclude, function (match, p1: keyof typeof ShaderChunk) {\n const path = `shader/chunk/${p1}.glsl`\n const chunk = ShaderRegistry.get(path) || ShaderChunk[ p1 ]\n if (!chunk) {\n throw new Error(`empty chunk, '${p1}'`)\n }\n return chunk\n })\n\n shaderCache[ hash ] = definesText + shaderText\n }\n\n return shaderCache[ hash ]\n}\n","/**\n * @file Viewer Constants\n * @author Alexander Rose \n * @private\n */\n\nimport { Debug } from '../globals'\n\nif (typeof WebGLRenderingContext !== 'undefined') {\n const wrcp = WebGLRenderingContext.prototype\n\n // wrap WebGL debug function used by three.js and\n // ignore calls to them when the debug flag is not set\n\n const _getShaderParameter = wrcp.getShaderParameter\n wrcp.getShaderParameter = function getShaderParameter (this: WebGLRenderingContext) {\n if (Debug) {\n return _getShaderParameter.apply(this, arguments)\n } else {\n return true\n }\n }\n\n const _getShaderInfoLog = wrcp.getShaderInfoLog\n wrcp.getShaderInfoLog = function getShaderInfoLog (this: WebGLRenderingContext) {\n if (Debug) {\n return _getShaderInfoLog.apply(this, arguments)\n } else {\n return ''\n }\n }\n\n const _getProgramParameter = wrcp.getProgramParameter\n wrcp.getProgramParameter = function getProgramParameter (this: WebGLRenderingContext, program, pname) {\n if (Debug || pname !== wrcp.LINK_STATUS) {\n return _getProgramParameter.apply(this, arguments)\n } else {\n return true\n }\n }\n\n const _getProgramInfoLog = wrcp.getProgramInfoLog\n wrcp.getProgramInfoLog = function getProgramInfoLog (this: WebGLRenderingContext) {\n if (Debug) {\n return _getProgramInfoLog.apply(this, arguments)\n } else {\n return ''\n }\n }\n}\n\nexport const JitterVectors = [\n [\n [ 0, 0 ]\n ],\n [\n [ 4, 4 ], [ -4, -4 ]\n ],\n [\n [ -2, -6 ], [ 6, -2 ], [ -6, 2 ], [ 2, 6 ]\n ],\n [\n [ 1, -3 ], [ -1, 3 ], [ 5, 1 ], [ -3, -5 ],\n [ -5, 5 ], [ -7, -1 ], [ 3, 7 ], [ 7, -7 ]\n ],\n [\n [ 1, 1 ], [ -1, -3 ], [ -3, 2 ], [ 4, -1 ],\n [ -5, -2 ], [ 2, 5 ], [ 5, 3 ], [ 3, -5 ],\n [ -2, 6 ], [ 0, -7 ], [ -4, -6 ], [ -6, 4 ],\n [ -8, 0 ], [ 7, -4 ], [ 6, 7 ], [ -7, -8 ]\n ],\n [\n [ -4, -7 ], [ -7, -5 ], [ -3, -5 ], [ -5, -4 ],\n [ -1, -4 ], [ -2, -2 ], [ -6, -1 ], [ -4, 0 ],\n [ -7, 1 ], [ -1, 2 ], [ -6, 3 ], [ -3, 3 ],\n [ -7, 6 ], [ -3, 6 ], [ -5, 7 ], [ -1, 7 ],\n [ 5, -7 ], [ 1, -6 ], [ 6, -5 ], [ 4, -4 ],\n [ 2, -3 ], [ 7, -2 ], [ 1, -1 ], [ 4, -1 ],\n [ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ],\n [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ]\n ]\n]\n\nJitterVectors.forEach(offsetList => {\n offsetList.forEach(offset => {\n // 0.0625 = 1 / 16\n offset[ 0 ] *= 0.0625\n offset[ 1 ] *= 0.0625\n })\n})\n","/**\n * @file Tiled Renderer\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport { Camera, WebGLRenderer } from 'three'\nimport Viewer from './viewer'\n\nexport interface TiledRendererParams {\n factor?: number\n antialias?: boolean\n onProgress?: Function\n onFinish?: Function\n}\n\nclass TiledRenderer {\n canvas = document.createElement('canvas')\n\n private _width: number\n private _height: number\n private _n: number\n private _factor: number\n private _antialias: boolean\n private _viewerSampleLevel: number\n\n private _viewer: Viewer\n private _onProgress?: Function\n private _onFinish?: Function\n private _ctx: CanvasRenderingContext2D\n\n constructor(renderer: WebGLRenderer, camera: Camera, viewer: Viewer, params: TiledRendererParams) {\n this._viewer = viewer\n\n this._factor = defaults(params.factor, 2)\n this._antialias = defaults(params.antialias, false)\n\n this._onProgress = params.onProgress\n this._onFinish = params.onFinish\n\n if (this._antialias) this._factor *= 2\n this._n = this._factor * this._factor\n\n // canvas\n\n this._width = this._viewer.width\n this._height = this._viewer.height\n\n if (this._antialias) {\n this.canvas.width = this._width * this._factor / 2\n this.canvas.height = this._height * this._factor / 2\n } else {\n this.canvas.width = this._width * this._factor\n this.canvas.height = this._height * this._factor\n }\n\n this._ctx = this.canvas.getContext('2d')!\n\n this._viewerSampleLevel = viewer.sampleLevel\n this._viewer.setSampling(-1)\n }\n\n private _renderTile (i: number) {\n const viewer = this._viewer\n const width = this._width\n const height = this._height\n const factor = this._factor\n\n const x = i % factor\n const y = Math.floor(i / factor)\n\n const offsetX = x * width\n const offsetY = y * height\n\n viewer.camera.setViewOffset(\n width * factor,\n height * factor,\n offsetX,\n offsetY,\n width,\n height\n )\n\n viewer.render()\n\n if (this._antialias) {\n const w = Math.round((offsetX + width) / 2) - Math.round (offsetX / 2);\n const h = Math.round((offsetY + height) / 2) - Math.round (offsetY / 2);\n this._ctx.drawImage(\n viewer.renderer.domElement,\n Math.round(offsetX / 2),\n Math.round(offsetY / 2),\n w,\n h\n )\n } else {\n this._ctx.drawImage(\n viewer.renderer.domElement,\n Math.floor(offsetX),\n Math.floor(offsetY),\n Math.ceil(width),\n Math.ceil(height)\n )\n }\n\n if (typeof this._onProgress === 'function') {\n this._onProgress(i + 1, this._n, false)\n }\n }\n\n private _finalize () {\n this._viewer.setSampling(this._viewerSampleLevel)\n this._viewer.camera.view = null! // TODO\n\n if (typeof this._onFinish === 'function') {\n this._onFinish(this._n + 1, this._n, false)\n }\n }\n\n render () {\n for (let i = 0; i <= this._n; ++i) {\n if (i === this._n) {\n this._finalize()\n } else {\n this._renderTile(i)\n }\n }\n }\n\n renderAsync () {\n let count = 0\n const n = this._n\n\n const fn = () => {\n if (count === n) {\n this._finalize()\n } else {\n this._renderTile(count)\n }\n count += 1\n }\n\n for (let i = 0; i <= n; ++i) {\n setTimeout(fn, 0)\n }\n }\n}\n\nexport default TiledRenderer\n","/**\n * @file Math Constants\n * @author Alexander Rose \n * @private\n */\n\nexport const EPS = 0.0000001\nexport const TwoPI = 2 * Math.PI\n\nexport const DEG2RAD = Math.PI / 180\nexport const RAD2DEG = 180 / Math.PI\n","/**\n * @file Array Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { NumberArray } from '../types'\nimport { TwoPI } from './math-constants'\n\nexport function circularMean (array: NumberArray, max: number, stride = 1, offset = 0, indices?: NumberArray) {\n // http://en.wikipedia.org/wiki/Center_of_mass#Systems_with_periodic_boundary_conditions\n\n // Bai, Linge; Breen, David (2008). Calculating Center of Mass in an Unbounded 2D Environment. Journal of Graphics, GPU, and Game Tools 13 (4): 53–60.\n\n // http://stackoverflow.com/questions/18166507/using-fft-to-find-the-center-of-mass-under-periodic-boundary-conditions\n\n const n = indices ? indices.length : array.length / stride\n\n let cosMean = 0\n let sinMean = 0\n\n if (indices) {\n for (let i = 0; i < n; ++i) {\n const c = (array[ indices[ i ] * stride + offset ] + max) % max\n const angle = (c / max) * TwoPI - Math.PI\n\n cosMean += Math.cos(angle)\n sinMean += Math.sin(angle)\n }\n } else {\n for (let i = offset; i < n; i += stride) {\n const c = (array[ i ] + max) % max\n const angle = (c / max) * TwoPI - Math.PI\n\n cosMean += Math.cos(angle)\n sinMean += Math.sin(angle)\n }\n }\n\n cosMean /= n\n sinMean /= n\n\n const meanAngle = Math.atan2(sinMean, cosMean)\n const mean = (meanAngle + Math.PI) / TwoPI * max\n\n return mean\n}\n\nexport function calculateCenterArray (array1: NumberArray, array2: NumberArray, center?: T, offset = 0): T {\n const n = array1.length\n const c = center || new Float32Array(n)\n\n for (let i = 0; i < n; i += 3) {\n c[ offset + i + 0 ] = (array1[ i + 0 ] + array2[ i + 0 ]) / 2.0\n c[ offset + i + 1 ] = (array1[ i + 1 ] + array2[ i + 1 ]) / 2.0\n c[ offset + i + 2 ] = (array1[ i + 2 ] + array2[ i + 2 ]) / 2.0\n }\n\n return c as T\n}\n\nexport function calculateDirectionArray (array1: NumberArray, array2: NumberArray) {\n const n = array1.length\n const direction = new Float32Array(n)\n\n for (let i = 0; i < n; i += 3) {\n direction[ i + 0 ] = array2[ i + 0 ] - array1[ i + 0 ]\n direction[ i + 1 ] = array2[ i + 1 ] - array1[ i + 1 ]\n direction[ i + 2 ] = array2[ i + 2 ] - array1[ i + 2 ]\n }\n\n return direction\n}\n\nexport function uniformArray (n: number, a: number, optionalTarget?: T): T {\n const array = optionalTarget || new Float32Array(n)\n\n for (let i = 0; i < n; ++i) {\n array[ i ] = a\n }\n\n return array as T\n}\n\nexport function uniformArray3 (n: number, a: number, b: number, c: number, optionalTarget?: NumberArray) {\n const array = optionalTarget || new Float32Array(n * 3)\n\n for (let i = 0; i < n; ++i) {\n const j = i * 3\n\n array[ j + 0 ] = a\n array[ j + 1 ] = b\n array[ j + 2 ] = c\n }\n\n return array\n}\n\nexport function centerArray3 (array: NumberArray, center = new Vector3()) {\n const n = array.length\n\n for (let i = 0; i < n; i += 3) {\n center.x += array[ i ]\n center.y += array[ i + 1 ]\n center.z += array[ i + 2 ]\n }\n\n center.divideScalar(n / 3)\n\n return center\n}\n\nexport function serialArray (n: number) {\n const array = new Float32Array(n)\n\n for (let i = 0; i < n; ++i) {\n array[ i ] = i\n }\n\n return array\n}\n\nexport function serialBlockArray (n: number, b: number, offset = 0, optionalTarget?: NumberArray) {\n const array = optionalTarget || new Float32Array(n * b)\n\n for (let i = 0; i < n; ++i) {\n const k = offset + i * b\n\n for (let j = 0; j < b; ++j) {\n array[ k + j ] = i\n }\n }\n\n return array\n}\n\nexport function randomColorArray (n: number) {\n const array = new Float32Array(n * 3)\n\n for (let i = 0; i < n; ++i) {\n const j = i * 3\n\n array[ j + 0 ] = Math.random()\n array[ j + 1 ] = Math.random()\n array[ j + 2 ] = Math.random()\n }\n\n return array\n}\n\nexport function replicateArrayEntries (array: NumberArray, m: number) {\n const n = array.length\n const repArr = new Float32Array(n * m)\n\n for (let i = 0; i < n; ++i) {\n const k = i * m\n const a = array[ i ]\n\n for (let j = 0; j < m; ++j) {\n repArr[ k + j ] = a\n }\n }\n\n return repArr\n}\n\nexport function replicateArray3Entries (array: NumberArray, m: number) {\n const n = array.length / 3\n const repArr = new Float32Array(n * m * 3)\n\n for (let i = 0; i < n; ++i) {\n const v = i * 3\n const k = i * m * 3\n\n const a = array[ v + 0 ]\n const b = array[ v + 1 ]\n const c = array[ v + 2 ]\n\n for (let j = 0; j < m; ++j) {\n const l = k + j * 3\n\n repArr[ l + 0 ] = a\n repArr[ l + 1 ] = b\n repArr[ l + 2 ] = c\n }\n }\n\n return repArr\n}\n\nexport function calculateMeanArray (array1: NumberArray, array2: NumberArray) {\n const n = array1.length\n const mean = new Float32Array(n)\n\n for (let i = 0; i < n; i++) {\n mean[ i ] = (array1[ i ] + array2[ i ]) / 2.0\n }\n\n return mean\n}\n\nexport function calculateMinArray (array1: NumberArray, array2: NumberArray) {\n const n = array1.length\n const min = new Float32Array(n)\n\n for (let i = 0; i < n; i++) {\n min[ i ] = Math.min(array1[ i ], array2[ i ])\n }\n\n return min\n}\n\nexport function copyArray (src: T, dst: T, srcOffset: number, dstOffset: number, length: number) {\n for (let i = 0; i < length; ++i) {\n dst[ dstOffset + i ] = src[ srcOffset + i ]\n }\n}\n\nexport function copyWithin (array: NumberArray|any[], srcOffset: number, dstOffset: number, length: number) {\n copyArray(array, array, srcOffset, dstOffset, length)\n}\n\nconst swap = new Float32Array(4)\nconst temp = new Float32Array(4)\n/**\n * quicksortIP\n * @function\n * @author Roman Bolzern , 2013\n * @author I4DS http://www.fhnw.ch/i4ds, 2013\n * @license MIT License \n * @description\n * In-place quicksort for typed arrays (e.g. for Float32Array)\n * provides fast sorting\n * useful e.g. for a custom shader and/or BufferGeometry\n * Complexity: http://bigocheatsheet.com/ see Quicksort\n *\n * @example\n * points: [x, y, z, x, y, z, x, y, z, ...]\n * eleSize: 3 //because of (x, y, z)\n * orderElement: 0 //order according to x\n *\n * @param {TypedArray} arr - array to be sorted\n * @param {Integer} eleSize - element size\n * @param {Integer} orderElement - index of element used for sorting, < eleSize\n * @param {Integer} [begin] - start index for range to be sorted\n * @param {Integer} [end] - end index for range to be sorted\n * @return {TypedArray} the input array\n */\nexport function quicksortIP (arr: NumberArray, eleSize: number, orderElement: number, begin = 0, end?: number) {\n end = (end || (arr.length / eleSize)) - 1\n\n const stack = []\n let sp = -1\n let left = begin\n let right = end\n let tmp = 0.0\n let x = 0\n let y = 0\n\n const swapF = function (a: number, b: number) {\n a *= eleSize; b *= eleSize\n for (y = 0; y < eleSize; y++) {\n tmp = arr[ a + y ]\n arr[ a + y ] = arr[ b + y ]\n arr[ b + y ] = tmp\n }\n }\n\n let i, j\n\n while (true) {\n if (right - left <= 25) {\n for (j = left + 1; j <= right; j++) {\n for (x = 0; x < eleSize; x++) {\n swap[ x ] = arr[ j * eleSize + x ]\n }\n\n i = j - 1\n\n while (i >= left && arr[ i * eleSize + orderElement ] > swap[ orderElement ]) {\n for (x = 0; x < eleSize; x++) {\n arr[ (i + 1) * eleSize + x ] = arr[ i * eleSize + x ]\n }\n i--\n }\n\n for (x = 0; x < eleSize; x++) {\n arr[ (i + 1) * eleSize + x ] = swap[ x ]\n }\n }\n\n if (sp === -1) break\n\n right = stack[ sp-- ] // ?\n left = stack[ sp-- ]\n } else {\n const median = (left + right) >> 1\n\n i = left + 1\n j = right\n\n swapF(median, i)\n\n if (arr[ left * eleSize + orderElement ] > arr[ right * eleSize + orderElement ]) {\n swapF(left, right)\n }\n\n if (arr[ i * eleSize + orderElement ] > arr[ right * eleSize + orderElement ]) {\n swapF(i, right)\n }\n\n if (arr[ left * eleSize + orderElement ] > arr[ i * eleSize + orderElement ]) {\n swapF(left, i)\n }\n\n for (x = 0; x < eleSize; x++) {\n temp[ x ] = arr[ i * eleSize + x ]\n }\n\n while (true) {\n do i++; while (arr[ i * eleSize + orderElement ] < temp[ orderElement ])\n do j--; while (arr[ j * eleSize + orderElement ] > temp[ orderElement ])\n if (j < i) break\n swapF(i, j)\n }\n\n for (x = 0; x < eleSize; x++) {\n arr[ (left + 1) * eleSize + x ] = arr[ j * eleSize + x ]\n arr[ j * eleSize + x ] = temp[ x ]\n }\n\n if (right - i + 1 >= j - left) {\n stack[ ++sp ] = i\n stack[ ++sp ] = right\n right = j - 1\n } else {\n stack[ ++sp ] = left\n stack[ ++sp ] = j - 1\n left = i\n }\n }\n }\n\n return arr\n}\n\nexport function quicksortCmp (arr: NumberArray|T[], cmp?: (a: number|T, b: number|T) => number, begin = 0, end?: number) {\n cmp = cmp || function cmp (a, b) {\n if (a > b) return 1\n if (a < b) return -1\n return 0\n }\n end = (end || arr.length) - 1\n\n const stack = []\n let sp = -1\n let left = begin\n let right = end\n let tmp: number|T\n\n function swap (a: number, b: number) {\n const tmp2 = arr[ a ]\n arr[ a ] = arr[ b ]\n arr[ b ] = tmp2\n }\n\n let i, j\n\n while (true) {\n if (right - left <= 25) {\n for (let k = left + 1; k <= right; ++k) {\n tmp = arr[ k ]\n i = k - 1\n\n while (i >= left && cmp(arr[ i ], tmp) > 0) {\n arr[ i + 1 ] = arr[ i ]\n --i\n }\n\n arr[ i + 1 ] = tmp\n }\n\n if (sp === -1) break\n\n right = stack[ sp-- ] // ?\n left = stack[ sp-- ]\n } else {\n const median = (left + right) >> 1\n\n i = left + 1\n j = right\n\n swap(median, i)\n\n if (cmp(arr[ left ], arr[ right ]) > 0) {\n swap(left, right)\n }\n\n if (cmp(arr[ i ], arr[ right ]) > 0) {\n swap(i, right)\n }\n\n if (cmp(arr[ left ], arr[ i ]) > 0) {\n swap(left, i)\n }\n\n tmp = arr[ i ]\n\n while (true) {\n do i++; while (cmp(arr[ i ], tmp) < 0)\n do j--; while (cmp(arr[ j ], tmp) > 0)\n if (j < i) break\n swap(i, j)\n }\n\n arr[ left + 1 ] = arr[ j ]\n arr[ j ] = tmp\n\n if (right - i + 1 >= j - left) {\n stack[ ++sp ] = i\n stack[ ++sp ] = right\n right = j - 1\n } else {\n stack[ ++sp ] = left\n stack[ ++sp ] = j - 1\n left = i\n }\n }\n }\n\n return arr\n}\n\nexport function quickselectCmp (arr: NumberArray|T[], n: number, cmp?: (a: number|T, b: number|T) => number, left = 0, right?: number) {\n cmp = cmp || function cmp (a, b) {\n if (a > b) return 1\n if (a < b) return -1\n return 0\n }\n right = (right || arr.length) - 1\n\n let pivotIndex, pivotValue, storeIndex\n\n function swap (a: number, b: number) {\n const tmp = arr[ a ]\n arr[ a ] = arr[ b ]\n arr[ b ] = tmp\n }\n\n while (true) {\n if (left === right) {\n return arr[ left ]\n }\n pivotIndex = (left + right) >> 1\n pivotValue = arr[ pivotIndex ]\n swap(pivotIndex, right)\n storeIndex = left\n for (let i = left; i < right; ++i) {\n if (cmp(arr[ i ], pivotValue) < 0) {\n swap(storeIndex, i)\n ++storeIndex\n }\n }\n swap(right, storeIndex)\n pivotIndex = storeIndex\n if (n === pivotIndex) {\n return arr[ n ]\n } else if (n < pivotIndex) {\n right = pivotIndex - 1\n } else {\n left = pivotIndex + 1\n }\n }\n}\n\nexport function arrayMax (array: NumberArray) {\n let max = -Infinity\n for (let i = 0, il = array.length; i < il; ++i) {\n if (array[ i ] > max) max = array[ i ]\n }\n return max\n}\n\nexport function arrayMin (array: NumberArray) {\n let min = Infinity\n for (let i = 0, il = array.length; i < il; ++i) {\n if (array[ i ] < min) min = array[ i ]\n }\n return min\n}\n\nexport function arraySum (array: NumberArray, stride = 1, offset = 0) {\n const n = array.length\n let sum = 0\n for (let i = offset; i < n; i += stride) {\n sum += array[ i ]\n }\n return sum\n}\n\nexport function arrayMean (array: NumberArray, stride = 1, offset = 0) {\n return arraySum(array, stride, offset) / (array.length / stride)\n}\n\nexport function arrayRms (array: NumberArray) {\n const n = array.length\n let sumSq = 0\n for (let i = 0; i < n; ++i) {\n const di = array[ i ]\n sumSq += di * di\n }\n return Math.sqrt(sumSq / n)\n}\n\nexport function arraySorted (array: NumberArray) {\n for (let i = 1, il = array.length; i < il; ++i) {\n if (array[ i - 1 ] > array[ i ]) return false\n }\n return true\n}\n\nexport function arraySortedCmp (array: NumberArray|T[], cmp: (a: number|T, b: number|T) => number) {\n for (let i = 1, il = array.length; i < il; ++i) {\n if (cmp(array[ i - 1 ], array[ i ]) > 0) return false\n }\n return true\n}\n","/**\n * @file Viewer Utils\n * @author Alexander Rose \n * @private\n */\n\nimport {\n Vector2, Vector3, Matrix4, Points, Scene, Camera,\n Object3D, WebGLRenderer, Color\n} from 'three'\n\nimport { createParams } from '../utils'\nimport TiledRenderer from './tiled-renderer'\nimport { quicksortCmp } from '../math/array-utils'\nimport Viewer from './viewer'\n\nfunction _trimCanvas (canvas: HTMLCanvasElement, r: number, g: number, b: number, a: number) {\n const canvasHeight = canvas.height\n const canvasWidth = canvas.width\n\n const ctx = canvas.getContext('2d')!\n const pixels = ctx.getImageData(0, 0, canvasWidth, canvasHeight).data\n\n let x, y, doBreak, off\n\n doBreak = false\n for (y = 0; y < canvasHeight; y++) {\n for (x = 0; x < canvasWidth; x++) {\n off = (y * canvasWidth + x) * 4\n if (pixels[ off ] !== r || pixels[ off + 1 ] !== g ||\n pixels[ off + 2 ] !== b || pixels[ off + 3 ] !== a\n ) {\n doBreak = true\n break\n }\n }\n if (doBreak) {\n break\n }\n }\n const topY = y\n\n doBreak = false\n for (x = 0; x < canvasWidth; x++) {\n for (y = 0; y < canvasHeight; y++) {\n off = (y * canvasWidth + x) * 4\n if (pixels[ off ] !== r || pixels[ off + 1 ] !== g ||\n pixels[ off + 2 ] !== b || pixels[ off + 3 ] !== a\n ) {\n doBreak = true\n break\n }\n }\n if (doBreak) {\n break\n }\n }\n const topX = x\n\n doBreak = false\n for (y = canvasHeight - 1; y >= 0; y--) {\n for (x = canvasWidth - 1; x >= 0; x--) {\n off = (y * canvasWidth + x) * 4\n if (pixels[ off ] !== r || pixels[ off + 1 ] !== g ||\n pixels[ off + 2 ] !== b || pixels[ off + 3 ] !== a\n ) {\n doBreak = true\n break\n }\n }\n if (doBreak) {\n break\n }\n }\n const bottomY = y\n\n doBreak = false\n for (x = canvasWidth - 1; x >= 0; x--) {\n for (y = canvasHeight - 1; y >= 0; y--) {\n off = (y * canvasWidth + x) * 4\n if (pixels[ off ] !== r || pixels[ off + 1 ] !== g ||\n pixels[ off + 2 ] !== b || pixels[ off + 3 ] !== a\n ) {\n doBreak = true\n break\n }\n }\n if (doBreak) {\n break\n }\n }\n const bottomX = x\n\n const trimedCanvas = document.createElement('canvas')\n trimedCanvas.width = bottomX - topX\n trimedCanvas.height = bottomY - topY\n\n const trimedCtx = trimedCanvas.getContext('2d')!\n trimedCtx.drawImage(\n canvas,\n topX, topY,\n trimedCanvas.width, trimedCanvas.height,\n 0, 0,\n trimedCanvas.width, trimedCanvas.height\n )\n\n return trimedCanvas\n}\n\n/**\n * Image parameter object.\n * @typedef {Object} ImageParameters - image generation parameters\n * @property {Boolean} trim - trim the image\n * @property {Integer} factor - scaling factor to apply to the viewer canvas\n * @property {Boolean} antialias - antialias the image\n * @property {Boolean} transparent - transparent image background\n */\n\nexport const ImageDefaultParameters = {\n trim: false,\n factor: 1,\n antialias: false,\n transparent: false,\n onProgress: undefined as Function|undefined\n}\nexport type ImageParameters = typeof ImageDefaultParameters\n\n/**\n * Make image from what is shown in a viewer canvas\n * @param {Viewer} viewer - the viewer\n * @param {ImageParameters} params - parameters object\n * @return {Promise} A Promise object that resolves to an image {@link Blob}.\n */\nexport function makeImage (viewer: Viewer, params: Partial = {}) {\n const {trim, factor, antialias, transparent} = createParams(params, ImageDefaultParameters)\n\n const renderer = viewer.renderer\n const camera = viewer.camera\n\n const originalClearAlpha = renderer.getClearAlpha()\n const backgroundColor = renderer.getClearColor(new Color())\n\n function setLineWidthAndPixelSize (invert = false) {\n let _factor = factor\n if (antialias) _factor *= 2\n if (invert) _factor = 1 / _factor\n viewer.scene.traverse(function (o: any) { // TODO\n const m = o.material\n if (m && m.linewidth) {\n m.linewidth *= _factor\n }\n if (m && m.uniforms && m.uniforms.size) {\n if (m.uniforms.size.__seen === undefined) {\n m.uniforms.size.value *= _factor\n m.uniforms.size.__seen = true\n }\n }\n if (m && m.uniforms && m.uniforms.linewidth) {\n if (m.uniforms.linewidth.__seen === undefined) {\n m.uniforms.linewidth.value *= _factor\n m.uniforms.linewidth.__seen = true\n }\n }\n })\n viewer.scene.traverse(function (o: any) { // TODO\n const m = o.material\n if (m && m.uniforms && m.uniforms.size) {\n delete m.uniforms.size.__seen\n }\n if (m && m.uniforms && m.uniforms.linewidth) {\n delete m.uniforms.linewidth.__seen\n }\n })\n }\n\n function trimCanvas (canvas: HTMLCanvasElement) {\n if (trim) {\n const bg = backgroundColor\n const r = transparent ? 0 : bg.r * 255\n const g = transparent ? 0 : bg.g * 255\n const b = transparent ? 0 : bg.b * 255\n const a = transparent ? 0 : 255\n return _trimCanvas(canvas, r, g, b, a)\n } else {\n return canvas\n }\n }\n\n function onProgress (i: number, n: number, finished: boolean) {\n if (typeof params.onProgress === 'function') {\n params.onProgress(i, n, finished)\n }\n }\n\n return new Promise(function (resolve, reject) {\n const tiledRenderer = new TiledRenderer(\n renderer, camera, viewer,\n { factor, antialias, onProgress, onFinish }\n )\n\n renderer.setClearAlpha(transparent ? 0 : 1)\n setLineWidthAndPixelSize()\n tiledRenderer.renderAsync()\n\n function onFinish (i: number, n: number) {\n const canvas = trimCanvas(tiledRenderer.canvas)\n canvas.toBlob(\n function (blob) {\n renderer.setClearAlpha(originalClearAlpha)\n setLineWidthAndPixelSize(true)\n viewer.requestRender()\n onProgress(n, n, true)\n if (blob) {\n resolve(blob)\n } else {\n reject('error creating image')\n }\n },\n 'image/png'\n )\n }\n })\n}\n\nconst vertex = new Vector3()\nconst matrix = new Matrix4()\nconst modelViewProjectionMatrix = new Matrix4()\n\nexport function sortProjectedPosition (scene: Scene, camera: Camera) {\n // console.time( \"sort\" );\n\n scene.traverseVisible(function (o) {\n if (!(o instanceof Points) || !o.userData.buffer.parameters.sortParticles) {\n return\n }\n\n const attributes = (o.geometry as any).attributes // TODO\n const n = attributes.position.count\n\n if (n === 0) return\n\n matrix.multiplyMatrices(\n camera.matrixWorldInverse, o.matrixWorld\n )\n modelViewProjectionMatrix.multiplyMatrices(\n camera.projectionMatrix, matrix\n )\n\n let sortData, sortArray, zArray: Float32Array, cmpFn\n\n if (!o.userData.sortData) {\n zArray = new Float32Array(n)\n sortArray = new Uint32Array(n)\n cmpFn = function (ai: number, bi: number) {\n const a = zArray[ ai ]\n const b = zArray[ bi ]\n if (a > b) return 1\n if (a < b) return -1\n return 0\n }\n\n sortData = {\n __zArray: zArray,\n __sortArray: sortArray,\n __cmpFn: cmpFn\n }\n\n o.userData.sortData = sortData\n } else {\n sortData = o.userData.sortData\n zArray = sortData.__zArray\n sortArray = sortData.__sortArray\n cmpFn = sortData.__cmpFn\n }\n\n for (let i = 0; i < n; ++i) {\n vertex.fromArray(attributes.position.array, i * 3)\n vertex.applyMatrix4(modelViewProjectionMatrix)\n\n // negate, so that sorting order is reversed\n zArray[ i ] = -vertex.z\n sortArray[ i ] = i\n }\n\n quicksortCmp(sortArray, cmpFn)\n\n let index, indexSrc, indexDst, tmpTab\n\n for (let name in attributes) {\n const attr = attributes[ name ]\n const array = attr.array\n const itemSize = attr.itemSize\n\n if (!sortData[ name ]) {\n sortData[ name ] = new Float32Array(itemSize * n)\n }\n\n tmpTab = sortData[ name ]\n sortData[ name ] = array\n\n for (let i = 0; i < n; ++i) {\n index = sortArray[ i ]\n\n for (let j = 0; j < itemSize; ++j) {\n indexSrc = index * itemSize + j\n indexDst = i * itemSize + j\n tmpTab[ indexDst ] = array[ indexSrc ]\n }\n }\n\n attributes[ name ].array = tmpTab\n attributes[ name ].needsUpdate = true\n }\n })\n\n // console.timeEnd( \"sort\" );\n}\n\nconst resolution = new Vector2()\nconst projectionMatrixInverse = new Matrix4()\nconst projectionMatrixTranspose = new Matrix4()\n\nexport function updateMaterialUniforms (group: Object3D, camera: Camera, renderer: WebGLRenderer, cDist: number, bRadius: number) {\n let size = new Vector2()\n renderer.getSize(size)\n const canvasHeight = size.height\n const pixelRatio = renderer.getPixelRatio()\n const ortho = camera.type === 'OrthographicCamera'\n\n resolution.set(size.width, size.height)\n projectionMatrixInverse.copy(camera.projectionMatrix).invert()\n projectionMatrixTranspose.copy(camera.projectionMatrix).transpose()\n\n group.traverse(function (o: any) {\n const m = o.material\n if (!m) return\n\n const u = m.uniforms\n if (!u) return\n\n if (m.clipNear) {\n const nearFactor = (50 - m.clipNear) / 50\n const nearClip = cDist - (bRadius * nearFactor)\n u.clipNear.value = nearClip\n }\n\n if (u.canvasHeight) {\n u.canvasHeight.value = canvasHeight\n }\n\n if (u.resolution) {\n u.resolution.value.copy(resolution)\n }\n\n if (u.pixelRatio) {\n u.pixelRatio.value = pixelRatio\n }\n\n if (u.projectionMatrixInverse) {\n u.projectionMatrixInverse.value.copy(projectionMatrixInverse)\n }\n\n if (u.projectionMatrixTranspose) {\n u.projectionMatrixTranspose.value.copy(projectionMatrixTranspose)\n }\n\n if (u.ortho) {\n u.ortho.value = ortho\n }\n })\n}\n\nexport function updateCameraUniforms (group: Object3D, camera: Camera) {\n projectionMatrixInverse.copy(camera.projectionMatrix).invert()\n projectionMatrixTranspose.copy(camera.projectionMatrix).transpose()\n\n group.traverse(function (o: any) {\n const m = o.material\n if (!m) return\n\n const u = m.uniforms\n if (!u) return\n\n if (u.projectionMatrixInverse) {\n u.projectionMatrixInverse.value.copy(projectionMatrixInverse)\n }\n\n if (u.projectionMatrixTranspose) {\n u.projectionMatrixTranspose.value.copy(projectionMatrixTranspose)\n }\n })\n}\n","/**\n * @file Viewer\n * @author Alexander Rose \n * @private\n */\n\n// adapted from https://webglfundamentals.org/webgl/resources/webgl-utils.js\n// Copyright 2012, Gregg Tavares. Modified BSD License\n\nexport function createProgram(gl: WebGLRenderingContext, shaders: WebGLShader[], attribs?: string[], locations?: number[]) {\n const program = gl.createProgram()\n if (!program) {\n console.log(`error creating WebGL program`)\n return\n }\n shaders.forEach(shader => gl.attachShader(program, shader))\n if (attribs) {\n attribs.forEach((attrib, i) => {\n gl.bindAttribLocation(program, locations ? locations[i] : i, attrib)\n })\n }\n gl.linkProgram(program);\n\n // Check the link status\n const linked = gl.getProgramParameter(program, gl.LINK_STATUS)\n if (!linked) {\n console.log(`error linking program: ${gl.getProgramInfoLog(program)}`)\n gl.deleteProgram(program)\n return null\n }\n return program\n}\n\nexport function loadShader(gl: WebGLRenderingContext, shaderSource: string, shaderType: number) {\n const shader = gl.createShader(shaderType)\n if (!shader) {\n console.log(`error creating WebGL shader ${shaderType}`)\n return // can't create shader\n }\n gl.shaderSource(shader, shaderSource)\n gl.compileShader(shader)\n\n // Check the compile status\n const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS)\n if (!compiled) {\n console.log(`error compiling shader ${shader}: ${gl.getShaderInfoLog(shader)}`)\n gl.deleteShader(shader)\n return null\n }\n\n return shader\n}\n\n//\n\nexport function getErrorDescription(gl: WebGLRenderingContext, error: number) {\n switch (error) {\n case gl.NO_ERROR: return 'no error'\n case gl.INVALID_ENUM: return 'invalid enum'\n case gl.INVALID_VALUE: return 'invalid value'\n case gl.INVALID_OPERATION: return 'invalid operation'\n case gl.INVALID_FRAMEBUFFER_OPERATION: return 'invalid framebuffer operation'\n case gl.OUT_OF_MEMORY: return 'out of memory'\n case gl.CONTEXT_LOST_WEBGL: return 'context lost'\n }\n return 'unknown error'\n}\n\nexport function getExtension (gl: WebGLRenderingContext, name: string) {\n const ext = gl.getExtension(name)\n if (!ext) console.log(`extension '${name}' not available`)\n return ext\n}\n\nconst TextureTestVertShader = `\nattribute vec4 a_position;\n\nvoid main() {\n gl_Position = a_position;\n}`\n\nconst TextureTestFragShader = `\nprecision mediump float;\nuniform vec4 u_color;\nuniform sampler2D u_texture;\n\nvoid main() {\n gl_FragColor = texture2D(u_texture, vec2(0.5, 0.5)) * u_color;\n}`\n\nconst TextureTestTexCoords = new Float32Array([\n -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0\n])\n\nexport function testTextureSupport (type: number) {\n // adapted from\n // https://stackoverflow.com/questions/28827511/webgl-ios-render-to-floating-point-texture\n\n // Get A WebGL context\n const canvas = document.createElement('canvas')\n canvas.width = 16\n canvas.height = 16\n canvas.style.width = 16 + 'px'\n canvas.style.height = 16 + 'px'\n const gl = canvas.getContext(\"webgl\") || canvas.getContext(\"experimental-webgl\");\n if (!gl) {\n console.log(`error creating webgl context for ${type}`)\n return false\n }\n if (!(gl instanceof WebGLRenderingContext)) {\n console.log(`Got unexpected type for WebGL rendering context`)\n return false\n }\n\n getExtension(gl, 'OES_texture_float')\n getExtension(gl, 'OES_texture_half_float')\n getExtension(gl, 'WEBGL_color_buffer_float')\n\n // setup shaders\n const vertShader = loadShader(gl, TextureTestVertShader, gl.VERTEX_SHADER)\n const fragShader = loadShader(gl, TextureTestFragShader, gl.FRAGMENT_SHADER)\n if (!vertShader || !fragShader) return false\n\n // setup program\n const program = createProgram(gl, [ vertShader, fragShader ])\n if (!program) {\n console.log(`error creating WebGL program`)\n return false\n }\n gl.useProgram(program);\n\n // look up where the vertex data needs to go.\n const positionLocation = gl.getAttribLocation(program, \"a_position\");\n const colorLoc = gl.getUniformLocation(program, \"u_color\");\n if (!colorLoc) {\n console.log(`error getting 'u_color' uniform location`)\n return false\n }\n\n // provide texture coordinates for the rectangle.\n const positionBuffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)\n gl.bufferData(gl.ARRAY_BUFFER, TextureTestTexCoords, gl.STATIC_DRAW)\n gl.enableVertexAttribArray(positionLocation)\n gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0)\n\n const whiteTex = gl.createTexture()\n const whiteData = new Uint8Array([255, 255, 255, 255])\n gl.bindTexture(gl.TEXTURE_2D, whiteTex)\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, whiteData)\n\n const tex = gl.createTexture()\n gl.bindTexture(gl.TEXTURE_2D, tex)\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, type, null)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n\n const fb = gl.createFramebuffer()\n gl.bindFramebuffer(gl.FRAMEBUFFER, fb)\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER)\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n console.log(`error creating framebuffer for ${type}`)\n return false\n }\n\n // Draw the rectangle.\n gl.bindTexture(gl.TEXTURE_2D, whiteTex)\n gl.uniform4fv(colorLoc, [0, 10, 20, 1])\n gl.drawArrays(gl.TRIANGLES, 0, 6)\n\n gl.bindTexture(gl.TEXTURE_2D, tex)\n gl.bindFramebuffer(gl.FRAMEBUFFER, null)\n gl.clearColor(1, 0, 0, 1)\n gl.clear(gl.COLOR_BUFFER_BIT)\n gl.uniform4fv(colorLoc, [0, 1/10, 1/20, 1])\n gl.drawArrays(gl.TRIANGLES, 0, 6)\n\n // Check if rendered correctly\n const pixel = new Uint8Array(4)\n gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel)\n if (pixel[0] !== 0 || pixel[1] < 248 || pixel[2] < 248 || pixel[3] < 254) {\n console.log(`not able to actually render to ${type} texture`)\n return false\n }\n\n // Check reading from float texture\n if (type === gl.FLOAT) {\n gl.bindFramebuffer(gl.FRAMEBUFFER, fb)\n const floatPixel = new Float32Array(4)\n gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, floatPixel)\n const error = gl.getError()\n if (error) {\n console.log(`error reading pixels as float: '${getErrorDescription(gl, error)}'`)\n return false\n }\n }\n\n return true\n}\n","/**\n * @file Viewer\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\nimport {\n PerspectiveCamera, OrthographicCamera, StereoCamera,\n Vector2, Box3, Vector3, Matrix4, Color,\n WebGLRenderer, WebGLRenderTarget,\n NearestFilter, LinearFilter, AdditiveBlending,\n RGBAFormat, FloatType, /*HalfFloatType, */UnsignedByteType,\n ShaderMaterial,\n PlaneGeometry,\n Scene, Mesh, Group, Object3D, Uniform,\n Fog, DirectionalLight, AmbientLight,\n BufferGeometry, BufferAttribute,\n LineSegments, ColorSpace,\n HalfFloatType\n} from 'three'\nimport '../shader/BasicLine.vert'\nimport '../shader/BasicLine.frag'\nimport '../shader/Quad.vert'\nimport '../shader/Quad.frag'\n\nimport {\n Debug, Log, WebglErrorMessage, Browser,\n setExtensionFragDepth, SupportsReadPixelsFloat, setSupportsReadPixelsFloat\n} from '../globals'\nimport { degToRad } from '../math/math-utils'\nimport Stats from './stats'\nimport { getShader } from '../shader/shader-utils'\nimport { setColorSpace } from '../color/colormaker'\nimport { JitterVectors } from './viewer-constants'\nimport {\n makeImage, ImageParameters,\n sortProjectedPosition, updateMaterialUniforms, updateCameraUniforms\n} from './viewer-utils'\nimport { testTextureSupport } from './gl-utils'\n\nimport Buffer from '../buffer/buffer'\n\nconst pixelBufferFloat = new Float32Array(4 * 25)\nconst pixelBufferUint = new Uint8Array(4 * 25)\n\n// When picking, we read a 25 pixel (5x5) array (readRenderTargetPixels)\n// We read the pixels in the order below to find what was picked.\n// This starts at the center and tries successively further points.\n// (Many points will be at equal distance to the center, their order\n// is arbitrary).\nconst pixelOrder = [12,7,13,17,11,6,8,18,16,2,14,22,10,1,3,9,19,23,21,15,5,0,4,24,20]\n\n\nconst tmpMatrix = new Matrix4()\n\nfunction onBeforeRender (this: Object3D, renderer: WebGLRenderer, scene: Scene, camera: PerspectiveCamera|OrthographicCamera, geometry: BufferGeometry, material: ShaderMaterial/*, group */) {\n const u = material.uniforms\n const updateList = []\n\n if (!u) return // See #908 - some materials may not have uniforms, ignore these\n\n if (u.objectId) {\n u.objectId.value = SupportsReadPixelsFloat ? this.id : this.id / 255\n updateList.push('objectId')\n }\n\n if (u.modelViewMatrixInverse || u.modelViewMatrixInverseTranspose ||\n u.modelViewProjectionMatrix || u.modelViewProjectionMatrixInverse\n ) {\n this.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, this.matrixWorld)\n }\n\n if (u.modelViewMatrixInverse) {\n u.modelViewMatrixInverse.value.copy(this.modelViewMatrix).invert()\n updateList.push('modelViewMatrixInverse')\n }\n\n if (u.modelViewMatrixInverseTranspose) {\n if (u.modelViewMatrixInverse) {\n u.modelViewMatrixInverseTranspose.value.copy(\n u.modelViewMatrixInverse.value\n ).transpose()\n } else {\n u.modelViewMatrixInverseTranspose.value\n .copy(this.modelViewMatrix).invert()\n .transpose()\n }\n updateList.push('modelViewMatrixInverseTranspose')\n }\n\n if (u.modelViewProjectionMatrix) {\n u.modelViewProjectionMatrix.value.multiplyMatrices(\n camera.projectionMatrix, this.modelViewMatrix\n )\n updateList.push('modelViewProjectionMatrix')\n }\n\n if (u.modelViewProjectionMatrixInverse) {\n if (u.modelViewProjectionMatrix) {\n tmpMatrix.copy(\n u.modelViewProjectionMatrix.value\n )\n u.modelViewProjectionMatrixInverse.value.copy(\n tmpMatrix.invert()\n )\n } else {\n tmpMatrix.multiplyMatrices(\n camera.projectionMatrix, this.modelViewMatrix\n )\n u.modelViewProjectionMatrixInverse.value.copy(\n tmpMatrix.invert()\n )\n }\n updateList.push('modelViewProjectionMatrixInverse')\n }\n\n if (updateList.length) {\n const materialProperties = renderer.properties.get(material)\n\n if (materialProperties.program) {\n const gl = renderer.getContext()\n const p = materialProperties.program\n gl.useProgram(p.program)\n const pu = p.getUniforms()\n\n updateList.forEach(function (name) {\n pu.setValue(gl, name, u[ name ].value)\n })\n }\n }\n}\n\nexport type CameraType = 'perspective'|'orthographic'|'stereo'\nexport type ColorWorkflow = 'linear' | 'sRGB'\n\nexport interface ViewerSignals {\n ticked: Signal,\n rendered: Signal\n}\n\nexport interface ViewerParameters {\n fogColor: Color\n fogNear: number\n fogFar: number\n\n backgroundColor: Color\n\n cameraType: CameraType\n cameraFov: number\n cameraEyeSep: number\n cameraZ: number\n\n clipNear: number\n clipFar: number\n clipDist: number\n clipMode: string // \"scene\" or \"camera\"\n clipScale: string // \"relative\" or \"absolute\"\n\n lightColor: Color\n lightIntensity: number\n ambientColor: Color\n ambientIntensity: number\n\n sampleLevel: number\n\n outputColorSpace: ColorSpace // default is three.LinearEncoding; three.sRGBEncoding gives more correct results\n}\n\nexport interface BufferInstance {\n matrix: Matrix4\n}\n\n/**\n * Viewer class\n * @class\n * @param {String|Element} [idOrElement] - dom id or element\n */\nexport default class Viewer {\n signals: ViewerSignals\n\n container: HTMLElement\n wrapper: HTMLElement\n\n private rendering: boolean\n private renderPending: boolean\n private lastRenderedPicking: boolean\n private isStill: boolean\n private frameRequest: number\n\n sampleLevel: number\n private cDist: number\n private bRadius: number\n\n private parameters: ViewerParameters\n stats: Stats\n\n perspectiveCamera: PerspectiveCamera\n private orthographicCamera: OrthographicCamera\n private stereoCamera: StereoCamera\n camera: PerspectiveCamera|OrthographicCamera\n\n width: number\n height: number\n\n scene: Scene\n private directionalLight: DirectionalLight\n private ambientLight: AmbientLight\n rotationGroup: Group\n translationGroup: Group\n private modelGroup: Group\n private pickingGroup: Group\n private backgroundGroup: Group\n private helperGroup: Group\n\n renderer: WebGLRenderer\n private supportsHalfFloat: boolean\n\n private pickingTarget: WebGLRenderTarget\n private sampleTarget: WebGLRenderTarget\n private holdTarget: WebGLRenderTarget\n\n private compositeUniforms: {\n tForeground: Uniform\n scale: Uniform\n }\n private compositeMaterial: ShaderMaterial\n private compositeCamera: OrthographicCamera\n private compositeScene: Scene\n\n private boundingBoxMesh: LineSegments\n boundingBox = new Box3()\n private boundingBoxSize = new Vector3()\n private boundingBoxLength = 0\n\n private info = {\n memory: {\n programs: 0,\n geometries: 0,\n textures: 0\n },\n render: {\n calls: 0,\n vertices: 0,\n faces: 0,\n points: 0\n }\n }\n\n private distVector = new Vector3()\n\n constructor (idOrElement: string|HTMLElement) {\n this.signals = {\n ticked: new Signal(),\n rendered: new Signal()\n }\n\n if (typeof idOrElement === 'string') {\n const elm = document.getElementById(idOrElement)\n if (elm === null) {\n this.container = document.createElement('div')\n }else {\n this.container = elm\n }\n } else if (idOrElement instanceof HTMLElement) {\n this.container = idOrElement\n } else {\n this.container = document.createElement('div')\n }\n\n if (this.container === document.body) {\n this.width = window.innerWidth || 1\n this.height = window.innerHeight || 1\n } else {\n const box = this.container.getBoundingClientRect()\n this.width = box.width || 1\n this.height = box.height || 1\n this.container.style.overflow = 'hidden'\n }\n\n this.wrapper = document.createElement('div')\n this.wrapper.style.position = 'relative'\n this.container.appendChild(this.wrapper)\n\n this._initParams()\n this._initStats()\n this._initCamera()\n this._initScene()\n\n if (this._initRenderer() === false) {\n Log.error('Viewer: could not initialize renderer')\n return\n }\n\n this._initHelper()\n\n // fog & background\n this.setBackground()\n this.setFog()\n\n this.animate = this.animate.bind(this)\n }\n\n private _initParams () {\n this.parameters = {\n fogColor: new Color(0x000000),\n fogNear: 50,\n fogFar: 100,\n\n backgroundColor: new Color(0x000000),\n\n cameraType: 'perspective',\n cameraFov: 40,\n cameraEyeSep: 0.3,\n cameraZ: -80, // FIXME initial value should be automatically determined\n\n clipNear: 0,\n clipFar: 100,\n clipDist: 10,\n clipMode: 'scene',\n clipScale: 'relative',\n\n lightColor: new Color(0xdddddd),\n lightIntensity: 1.2,\n ambientColor: new Color(0xdddddd),\n ambientIntensity: 0.3,\n\n sampleLevel: 0,\n\n // output encoding: use srgb for a linear internal workflow, srgb-linear for traditional sRGB workflow.\n outputColorSpace: 'srgb-linear',\n }\n }\n\n private _initCamera () {\n const lookAt = new Vector3(0, 0, 0)\n const {width, height} = this\n\n this.perspectiveCamera = new PerspectiveCamera(\n this.parameters.cameraFov, width / height\n )\n this.perspectiveCamera.position.z = this.parameters.cameraZ\n this.perspectiveCamera.lookAt(lookAt)\n\n this.orthographicCamera = new OrthographicCamera(\n width / -2, width / 2, height / 2, height / -2\n )\n this.orthographicCamera.position.z = this.parameters.cameraZ\n this.orthographicCamera.lookAt(lookAt)\n\n this.stereoCamera = new StereoCamera()\n this.stereoCamera.aspect = 0.5\n this.stereoCamera.eyeSep = this.parameters.cameraEyeSep\n\n const cameraType = this.parameters.cameraType\n if (cameraType === 'orthographic') {\n this.camera = this.orthographicCamera\n } else if(cameraType === 'perspective' || cameraType === 'stereo') {\n this.camera = this.perspectiveCamera\n } else {\n throw new Error(`Unknown cameraType '${cameraType}'`)\n }\n this.camera.updateProjectionMatrix()\n }\n\n private _initStats () {\n this.stats = new Stats()\n }\n\n private _initScene () {\n if (!this.scene) {\n this.scene = new Scene()\n this.scene.name = 'scene'\n }\n\n this.rotationGroup = new Group()\n this.rotationGroup.name = 'rotationGroup'\n this.scene.add(this.rotationGroup)\n\n this.translationGroup = new Group()\n this.translationGroup.name = 'translationGroup'\n this.rotationGroup.add(this.translationGroup)\n\n this.modelGroup = new Group()\n this.modelGroup.name = 'modelGroup'\n this.translationGroup.add(this.modelGroup)\n\n this.pickingGroup = new Group()\n this.pickingGroup.name = 'pickingGroup'\n this.translationGroup.add(this.pickingGroup)\n\n this.backgroundGroup = new Group()\n this.backgroundGroup.name = 'backgroundGroup'\n this.translationGroup.add(this.backgroundGroup)\n\n this.helperGroup = new Group()\n this.helperGroup.name = 'helperGroup'\n this.translationGroup.add(this.helperGroup)\n\n // fog\n\n this.scene.fog = new Fog(this.parameters.fogColor.getHex())\n\n // light\n\n this.directionalLight = new DirectionalLight(\n this.parameters.lightColor.getHex(), this.parameters.lightIntensity\n )\n this.scene.add(this.directionalLight)\n\n this.ambientLight = new AmbientLight(\n this.parameters.ambientColor.getHex(), this.parameters.ambientIntensity\n )\n this.scene.add(this.ambientLight)\n }\n\n private _initRenderer () {\n const dpr = window.devicePixelRatio\n const {width, height} = this\n\n try {\n this.renderer = new WebGLRenderer({\n preserveDrawingBuffer: true,\n alpha: true,\n antialias: true\n })\n } catch (e) {\n this.wrapper.innerHTML = WebglErrorMessage\n return false\n }\n this.renderer.setPixelRatio(dpr)\n this.renderer.setSize(width, height)\n this.renderer.autoClear = false\n this.renderer.sortObjects = true\n this.renderer.outputColorSpace = this.parameters.outputColorSpace\n this.renderer.useLegacyLights = true\n\n const gl = this.renderer.getContext()\n // console.log(gl.getContextAttributes().antialias)\n // console.log(gl.getParameter(gl.SAMPLES))\n\n // For WebGL1, extensions must be explicitly enabled.\n // The following are builtin to WebGL2 (and don't appear as\n // extensions)\n // EXT_frag_depth, OES_element_index_uint, OES_texture_float\n // OES_texture_half_float\n\n // The WEBGL_color_buffer_float extension is replaced by\n // EXT_color_buffer_float\n\n // If not webgl2 context, explicitly check for these\n if (!this.renderer.capabilities.isWebGL2) {\n setExtensionFragDepth(this.renderer.extensions.get('EXT_frag_depth'))\n this.renderer.extensions.get('OES_element_index_uint')\n\n setSupportsReadPixelsFloat(\n (this.renderer.extensions.get('OES_texture_float') &&\n this.renderer.extensions.get('WEBGL_color_buffer_float')) ||\n (this.renderer.extensions.get('OES_texture_float') &&\n testTextureSupport(gl.FLOAT))\n )\n // picking texture\n\n this.renderer.extensions.get('OES_texture_float')\n\n this.supportsHalfFloat = (\n this.renderer.extensions.get('OES_texture_half_float') &&\n testTextureSupport(0x8D61)\n )\n\n } else {\n setExtensionFragDepth(true)\n setSupportsReadPixelsFloat(\n this.renderer.extensions.get('EXT_color_buffer_float')\n )\n this.supportsHalfFloat = true\n }\n\n this.wrapper.appendChild(this.renderer.domElement)\n\n const dprWidth = width * dpr\n const dprHeight = height * dpr\n\n\n if (Debug) {\n console.log(JSON.stringify({\n 'Browser': Browser,\n 'OES_texture_float': !!this.renderer.extensions.get('OES_texture_float'),\n 'OES_texture_half_float': !!this.renderer.extensions.get('OES_texture_half_float'),\n 'WEBGL_color_buffer_float': !!this.renderer.extensions.get('WEBGL_color_buffer_float'),\n 'testTextureSupport Float': testTextureSupport(gl.FLOAT),\n 'testTextureSupport HalfFloat': testTextureSupport(0x8D61),\n 'this.supportsHalfFloat': this.supportsHalfFloat,\n 'SupportsReadPixelsFloat': SupportsReadPixelsFloat\n }, null, 2))\n }\n\n this.pickingTarget = new WebGLRenderTarget(\n dprWidth, dprHeight,\n {\n minFilter: NearestFilter,\n magFilter: NearestFilter,\n stencilBuffer: false,\n format: RGBAFormat,\n type: SupportsReadPixelsFloat ? FloatType : UnsignedByteType\n }\n )\n this.pickingTarget.texture.generateMipmaps = false\n this.pickingTarget.texture.colorSpace = this.parameters.outputColorSpace\n\n // workaround to reset the gl state after using testTextureSupport\n // fixes some bug where nothing is rendered to the canvas\n // when animations are started on page load\n this.renderer.setRenderTarget(this.pickingTarget)\n this.renderer.clear()\n this.renderer.setRenderTarget(null!)\n\n // ssaa textures\n\n this.sampleTarget = new WebGLRenderTarget(\n dprWidth, dprHeight,\n {\n minFilter: LinearFilter,\n magFilter: LinearFilter,\n format: RGBAFormat,\n type: this.supportsHalfFloat ? HalfFloatType : (\n SupportsReadPixelsFloat ? FloatType : UnsignedByteType\n )\n }\n )\n this.sampleTarget.texture.colorSpace = this.parameters.outputColorSpace\n\n this.holdTarget = new WebGLRenderTarget(\n dprWidth, dprHeight,\n {\n minFilter: NearestFilter,\n magFilter: NearestFilter,\n format: RGBAFormat,\n type: this.supportsHalfFloat ? HalfFloatType : (\n SupportsReadPixelsFloat ? FloatType : UnsignedByteType\n )\n }\n )\n this.holdTarget.texture.colorSpace = this.parameters.outputColorSpace\n\n this.compositeUniforms = {\n 'tForeground': new Uniform(this.sampleTarget.texture),\n 'scale': new Uniform(1.0)\n }\n\n this.compositeMaterial = new ShaderMaterial({\n uniforms: this.compositeUniforms,\n vertexShader: getShader('Quad.vert'),\n fragmentShader: getShader('Quad.frag'),\n premultipliedAlpha: true,\n transparent: true,\n blending: AdditiveBlending,\n depthTest: false,\n depthWrite: false\n })\n\n this.compositeCamera = new OrthographicCamera(-1, 1, 1, -1, 0, 1)\n this.compositeScene = new Scene()\n this.compositeScene.name = 'compositeScene'\n this.compositeScene.add(new Mesh(\n new PlaneGeometry(2, 2), this.compositeMaterial\n ))\n }\n\n private _initHelper () {\n const indices = new Uint16Array([\n 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6,\n 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7\n ])\n const positions = new Float32Array(8 * 3)\n\n const bbGeometry = new BufferGeometry()\n bbGeometry.setIndex(new BufferAttribute(indices, 1))\n bbGeometry.setAttribute('position', new BufferAttribute(positions, 3))\n const bbMaterial = new ShaderMaterial({\n uniforms: { 'uColor': { value: new Color('skyblue') } },\n vertexShader: getShader('BasicLine.vert'),\n fragmentShader: getShader('BasicLine.frag')\n })\n\n this.boundingBoxMesh = new LineSegments(bbGeometry, bbMaterial)\n this.helperGroup.add(this.boundingBoxMesh)\n }\n\n updateHelper () {\n const position = ((this.boundingBoxMesh.geometry as BufferGeometry).attributes as any).position // TODO\n const array = position.array\n const {min, max} = this.boundingBox\n\n array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z\n array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z\n array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z\n array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z\n array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z\n array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z\n array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z\n array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z\n\n position.needsUpdate = true\n\n if (!this.boundingBox.isEmpty()) {\n this.boundingBoxMesh.geometry.computeBoundingSphere()\n }\n }\n\n /** Distance from origin (lookAt point) */\n get cameraDistance(): number {\n return Math.abs(this.camera.position.z)\n }\n\n /** Set distance from origin (lookAt point); along the -z axis */\n set cameraDistance(d: number) {\n this.camera.position.z = -d\n }\n\n add (buffer: Buffer, instanceList?: BufferInstance[]) {\n // Log.time( \"Viewer.add\" );\n\n if (instanceList) {\n instanceList.forEach(instance => this.addBuffer(buffer, instance))\n } else {\n this.addBuffer(buffer)\n }\n\n buffer.group.name = 'meshGroup'\n buffer.wireframeGroup.name = 'wireframeGroup'\n if (buffer.parameters.background) {\n this.backgroundGroup.add(buffer.group)\n this.backgroundGroup.add(buffer.wireframeGroup)\n } else {\n this.modelGroup.add(buffer.group)\n this.modelGroup.add(buffer.wireframeGroup)\n }\n\n if (buffer.pickable) {\n this.pickingGroup.add(buffer.pickingGroup)\n }\n\n if (Debug) this.updateHelper()\n\n // Log.timeEnd( \"Viewer.add\" );\n }\n\n addBuffer (buffer: Buffer, instance?: BufferInstance) {\n // Log.time( \"Viewer.addBuffer\" );\n\n function setUserData (object: Object3D) {\n if (object instanceof Group) {\n object.children.forEach(setUserData)\n } else {\n object.userData.buffer = buffer\n object.userData.instance = instance\n object.onBeforeRender = onBeforeRender\n }\n }\n\n const mesh = buffer.getMesh()\n if (instance) {\n mesh.applyMatrix4(instance.matrix)\n }\n setUserData(mesh)\n buffer.group.add(mesh)\n\n const wireframeMesh = buffer.getWireframeMesh()\n if (instance) {\n // wireframeMesh.applyMatrix( instance.matrix );\n wireframeMesh.matrix.copy(mesh.matrix)\n wireframeMesh.position.copy(mesh.position)\n wireframeMesh.quaternion.copy(mesh.quaternion)\n wireframeMesh.scale.copy(mesh.scale)\n }\n setUserData(wireframeMesh)\n buffer.wireframeGroup.add(wireframeMesh)\n\n if (buffer.pickable) {\n const pickingMesh = buffer.getPickingMesh()\n if (instance) {\n // pickingMesh.applyMatrix( instance.matrix );\n pickingMesh.matrix.copy(mesh.matrix)\n pickingMesh.position.copy(mesh.position)\n pickingMesh.quaternion.copy(mesh.quaternion)\n pickingMesh.scale.copy(mesh.scale)\n }\n setUserData(pickingMesh)\n buffer.pickingGroup.add(pickingMesh)\n }\n\n if (instance) {\n this._updateBoundingBox(buffer.geometry, buffer.matrix, instance.matrix)\n } else {\n this._updateBoundingBox(buffer.geometry, buffer.matrix)\n }\n\n // Log.timeEnd( \"Viewer.addBuffer\" );\n }\n\n remove (buffer: Buffer) {\n this.translationGroup.children.forEach(function (group) {\n group.remove(buffer.group)\n group.remove(buffer.wireframeGroup)\n })\n\n if (buffer.pickable) {\n this.pickingGroup.remove(buffer.pickingGroup)\n }\n\n this.updateBoundingBox()\n if (Debug) this.updateHelper()\n\n // this.requestRender();\n }\n\n private _updateBoundingBox (geometry?: BufferGeometry, matrix?: Matrix4, instanceMatrix?: Matrix4) {\n const boundingBox = this.boundingBox\n\n function updateGeometry (geometry: BufferGeometry, matrix?: Matrix4, instanceMatrix?: Matrix4) {\n if (geometry.boundingBox == null) {\n geometry.computeBoundingBox()\n }\n\n const geoBoundingBox = (geometry.boundingBox as Box3).clone()\n\n if (matrix) {\n geoBoundingBox.applyMatrix4(matrix)\n }\n if (instanceMatrix) {\n geoBoundingBox.applyMatrix4(instanceMatrix)\n }\n\n if (geoBoundingBox.min.equals(geoBoundingBox.max)) {\n // mainly to give a single impostor geometry some volume\n // as it is only expanded in the shader on the GPU\n geoBoundingBox.expandByScalar(5)\n }\n\n boundingBox.union(geoBoundingBox)\n }\n\n function updateNode (node: Mesh) {\n if (node.geometry !== undefined) {\n let matrix, instanceMatrix\n if (node.userData.buffer) {\n matrix = node.userData.buffer.matrix\n }\n if (node.userData.instance) {\n instanceMatrix = node.userData.instance.matrix\n }\n updateGeometry(node.geometry as BufferGeometry, matrix, instanceMatrix) // TODO\n }\n }\n\n if (geometry) {\n updateGeometry(geometry, matrix, instanceMatrix)\n } else {\n boundingBox.makeEmpty()\n this.modelGroup.traverse(updateNode)\n this.backgroundGroup.traverse(updateNode)\n }\n\n boundingBox.getSize(this.boundingBoxSize)\n this.boundingBoxLength = this.boundingBoxSize.length()\n }\n\n updateBoundingBox () {\n this._updateBoundingBox()\n if (Debug) this.updateHelper()\n }\n\n getPickingPixels () {\n const {width, height} = this\n\n const n = width * height * 4\n const imgBuffer = SupportsReadPixelsFloat ? new Float32Array(n) : new Uint8Array(n)\n\n this.render(true)\n this.renderer.readRenderTargetPixels(\n this.pickingTarget, 0, 0, width, height, imgBuffer\n )\n\n return imgBuffer\n }\n\n getImage (picking: boolean) {\n return new Promise(resolve => {\n if (picking) {\n const {width, height} = this\n const n = width * height * 4\n let imgBuffer = this.getPickingPixels()\n\n if (SupportsReadPixelsFloat) {\n const imgBuffer2 = new Uint8Array(n)\n for (let i = 0; i < n; ++i) {\n imgBuffer2[ i ] = Math.round(imgBuffer[ i ] * 255)\n }\n imgBuffer = imgBuffer2\n }\n\n const canvas = document.createElement('canvas')\n canvas.width = width\n canvas.height = height\n const ctx = canvas.getContext('2d')! // TODO\n const imgData = ctx.getImageData(0, 0, width, height)\n imgData.data.set(imgBuffer as any) // TODO\n ctx.putImageData(imgData, 0, 0)\n canvas.toBlob(resolve as any, 'image/png') // TODO\n } else {\n this.renderer.domElement.toBlob(resolve as any, 'image/png') // TODO\n }\n })\n }\n\n makeImage (params: Partial = {}) {\n return makeImage(this, params)\n }\n\n setLight (color: Color|number|string, intensity: number, ambientColor: Color|number|string, ambientIntensity: number) {\n const p = this.parameters\n\n if (color !== undefined) p.lightColor.set(color as string) // TODO\n if (intensity !== undefined) p.lightIntensity = intensity\n if (ambientColor !== undefined) p.ambientColor.set(ambientColor as string) // TODO\n if (ambientIntensity !== undefined) p.ambientIntensity = ambientIntensity\n\n this.requestRender()\n }\n\n setFog (color?: Color|number|string, near?: number, far?: number) {\n const p = this.parameters\n\n if (color !== undefined) p.fogColor.set(color as string) // TODO\n if (near !== undefined) p.fogNear = near\n if (far !== undefined) p.fogFar = far\n\n this.requestRender()\n }\n\n setBackground (color?: Color|number|string) {\n const p = this.parameters\n\n if (color) p.backgroundColor.set(color as string) // TODO\n\n this.setFog(p.backgroundColor)\n this.renderer.setClearColor(p.backgroundColor, 0)\n this.renderer.domElement.style.backgroundColor = p.backgroundColor.getStyle()\n\n this.requestRender()\n }\n\n setSampling (level: number) {\n if (level !== undefined) {\n this.parameters.sampleLevel = level\n this.sampleLevel = level\n }\n\n this.requestRender()\n }\n\n /**\n * Set the output color encoding, i.e. how the renderer translates\n * colorspaces as it renders to the screen.\n\n * The default is LinearEncoding, because the internals of NGL are\n * already sRGB so no translation is needed to show sRGB colors.\n * Set to sRGBEncoding to create a linear workflow, and also call\n * `setColorEncoding(LinearEncoding)` to linearize colors on input.\n * @see setColorEncoding\n */\n private setOutputEncoding (colorspace: ColorSpace) {\n this.parameters.outputColorSpace = colorspace\n this.renderer.outputColorSpace = colorspace\n this.pickingTarget.texture.colorSpace = colorspace\n this.sampleTarget.texture.colorSpace = colorspace\n this.holdTarget.texture.colorSpace = colorspace\n }\n\n /**\n * Set the internal color workflow, linear or sRGB.\n * sRGB, the default, is more \"vibrant\" at the cost of accuracy.\n * Linear gives more accurate results, especially for transparent objects.\n * In all cases, the output is always sRGB; this just affects how colors are computed internally.\n * Call this just after creating the viewer, before loading any models.\n */\n setColorWorkflow (colorspace: ColorSpace) {\n if (colorspace != 'srgb-linear' && colorspace != 'srgb')\n throw new Error(`setColorWorkflow: invalid color workflow ${colorspace}`)\n setColorSpace(colorspace == 'srgb-linear' ? 'linear' : 'sRGB')\n this.setOutputEncoding(colorspace == 'srgb-linear' ? 'srgb' : 'srgb-linear')\n // Note: this doesn't rebuild models, so existing geometry will have\n // the old color encoding.\n this.requestRender()\n }\n\n setCamera (type: CameraType, fov?: number, eyeSep?: number) {\n const p = this.parameters\n\n if (type) p.cameraType = type\n if (fov) p.cameraFov = fov\n if (eyeSep) p.cameraEyeSep = eyeSep\n\n if (p.cameraType === 'orthographic') {\n if (this.camera !== this.orthographicCamera) {\n this.camera = this.orthographicCamera\n this.camera.position.copy(this.perspectiveCamera.position)\n this.camera.up.copy(this.perspectiveCamera.up)\n this.updateZoom()\n }\n } else if (p.cameraType === 'perspective' || p.cameraType === 'stereo') {\n if (this.camera !== this.perspectiveCamera) {\n this.camera = this.perspectiveCamera\n this.camera.position.copy(this.orthographicCamera.position)\n this.camera.up.copy(this.orthographicCamera.up)\n }\n } else {\n throw new Error(`Unknown cameraType '${p.cameraType}'`)\n }\n\n this.perspectiveCamera.fov = p.cameraFov\n this.stereoCamera.eyeSep = p.cameraEyeSep\n this.camera.updateProjectionMatrix()\n\n this.requestRender()\n }\n\n setClip (near: number, far: number, dist: number, clipMode?: string, clipScale?: string) {\n const p = this.parameters\n\n if (near !== undefined) p.clipNear = near\n if (far !== undefined) p.clipFar = far\n if (dist !== undefined) p.clipDist = dist\n if (clipMode !== undefined) p.clipMode = clipMode\n if (clipScale !== undefined) p.clipScale = clipScale\n\n this.requestRender()\n }\n\n setSize (width: number, height: number) {\n this.width = width || 1\n this.height = height || 1\n\n this.perspectiveCamera.aspect = this.width / this.height\n this.orthographicCamera.left = -this.width / 2\n this.orthographicCamera.right = this.width / 2\n this.orthographicCamera.top = this.height / 2\n this.orthographicCamera.bottom = -this.height / 2\n this.camera.updateProjectionMatrix()\n\n const dpr = window.devicePixelRatio\n\n this.renderer.setPixelRatio(dpr)\n this.renderer.setSize(width, height)\n\n const dprWidth = this.width * dpr\n const dprHeight = this.height * dpr\n\n this.pickingTarget.setSize(dprWidth, dprHeight)\n this.sampleTarget.setSize(dprWidth, dprHeight)\n this.holdTarget.setSize(dprWidth, dprHeight)\n\n this.requestRender()\n }\n\n handleResize () {\n if (this.container === document.body) {\n this.setSize(window.innerWidth, window.innerHeight)\n } else {\n const box = this.container.getBoundingClientRect()\n this.setSize(box.width, box.height)\n }\n }\n\n updateInfo (reset?: boolean) {\n const { memory, render } = this.info\n\n if (reset) {\n memory.programs = 0\n memory.geometries = 0\n memory.textures = 0\n\n render.calls = 0\n render.vertices = 0\n render.points = 0\n } else {\n const rInfo = this.renderer.info\n const rMemory = rInfo.memory\n const rRender = rInfo.render\n\n memory.geometries = rMemory.geometries\n memory.textures = rMemory.textures\n\n render.calls += rRender.calls\n render.faces += rRender.triangles\n render.points += rRender.points\n }\n }\n\n animate () {\n this.signals.ticked.dispatch(this.stats)\n const delta = window.performance.now() - this.stats.startTime\n\n if (delta > 500 && !this.isStill && this.sampleLevel < 3 && this.sampleLevel !== -1) {\n const currentSampleLevel = this.sampleLevel\n this.sampleLevel = 3\n this.renderPending = true\n this.render()\n this.isStill = true\n this.sampleLevel = currentSampleLevel\n if (Debug) Log.log('rendered still frame')\n }\n\n this.frameRequest = window.requestAnimationFrame(this.animate)\n }\n\n pick (x: number, y: number) {\n if (this.parameters.cameraType === 'stereo') {\n // TODO picking broken for stereo camera\n return {\n 'pid': 0,\n 'instance': undefined,\n 'picker': undefined\n }\n }\n\n x *= window.devicePixelRatio\n y *= window.devicePixelRatio\n\n x = Math.max(x - 2, 0)\n y = Math.max(y - 2, 0)\n\n let pid = 0, instance, picker\n const pixelBuffer = SupportsReadPixelsFloat ? pixelBufferFloat : pixelBufferUint\n\n this.render(true)\n this.renderer.readRenderTargetPixels(\n this.pickingTarget, x, y, 5, 5, pixelBuffer\n )\n\n for (let i = 0; i < pixelOrder.length; i++) {\n\n const offset = pixelOrder[i] * 4\n\n const oid = Math.round(pixelBuffer[ offset + 3 ])\n const object = this.pickingGroup.getObjectById(oid)\n if (object) {\n instance = object.userData.instance\n picker = object.userData.buffer.picking\n } else {\n continue\n }\n\n if (SupportsReadPixelsFloat) {\n pid =\n ((Math.round(pixelBuffer[offset] * 255) << 16) & 0xFF0000) |\n ((Math.round(pixelBuffer[offset + 1] * 255) << 8) & 0x00FF00) |\n ((Math.round(pixelBuffer[offset + 2] * 255)) & 0x0000FF)\n } else {\n pid =\n (pixelBuffer[offset] << 16) |\n (pixelBuffer[offset + 1] << 8) |\n (pixelBuffer[offset + 2])\n }\n }\n // if( Debug ){\n // const rgba = Array.apply( [], pixelBuffer );\n // Log.log( pixelBuffer );\n // Log.log(\n // \"picked color\",\n // rgba.map( c => { return c.toPrecision( 2 ) } )\n // );\n // Log.log( \"picked pid\", pid );\n // Log.log( \"picked oid\", oid );\n // Log.log( \"picked object\", object );\n // Log.log( \"picked instance\", instance );\n // Log.log( \"picked position\", x, y );\n // Log.log( \"devicePixelRatio\", window.devicePixelRatio );\n // }\n\n return { pid, instance, picker }\n }\n\n requestRender () {\n if (this.renderPending) {\n // Log.info(\"there is still a 'render' call pending\")\n return\n }\n\n // start gathering stats anew after inactivity\n if (window.performance.now() - this.stats.startTime > 22) {\n this.stats.begin()\n this.isStill = false\n }\n\n this.renderPending = true\n\n window.requestAnimationFrame(() => {\n this.render()\n this.stats.update()\n })\n }\n\n updateZoom () {\n const fov = degToRad(this.perspectiveCamera.fov)\n const height = 2 * Math.tan(fov / 2) * this.cameraDistance\n this.orthographicCamera.zoom = this.height / height\n }\n\n /**\n * Convert an absolute clip value to a relative one using bRadius.\n *\n * 0.0 -> 50.0\n * bRadius -> 0.0\n */\n absoluteToRelative (d: number) :number {\n return 50 * (1 - d / this.bRadius)\n }\n\n /**\n * Convert a relative clip value to an absolute one using bRadius\n *\n * 0.0 -> bRadius\n * 50.0 -> 0.0\n */\n relativeToAbsolute (d: number) : number {\n return this.bRadius * (1 - d / 50)\n }\n\n /**\n * Intepret clipMode, clipScale and set the camera and fog clipping.\n * Also ensures bRadius and cDist are valid\n */\n private __updateClipping () {\n const p = this.parameters\n\n // bRadius must always be updated for material-based clipping\n // and for focus calculations\n this.bRadius = Math.max(10, this.boundingBoxLength * 0.5)\n\n // FL: Removed below, but leaving commented as I don't understand intention\n // this.bRadius += this.boundingBox.getCenter(this.distVector).length()\n\n if (!isFinite(this.bRadius)) {\n this.bRadius = 50\n }\n\n this.camera.getWorldPosition(this.distVector)\n this.cDist = this.distVector.length()\n if (!this.cDist) {\n // recover from a broken (NaN) camera position\n this.cameraDistance = Math.abs(p.cameraZ)\n this.cDist = Math.abs(p.cameraZ)\n }\n\n // fog\n const fog = this.scene.fog as Fog\n fog.color.set(p.fogColor)\n\n if (p.clipMode === 'camera') {\n // Always interpret clipScale as absolute for clipMode camera\n\n this.camera.near = p.clipNear\n this.camera.far = p.clipFar\n fog.near = p.fogNear\n fog.far = p.fogFar\n\n } else {\n // scene mode\n\n if (p.clipScale === 'absolute') {\n // absolute scene mode; offset clip planes from scene center\n // (note: positive values move near plane towards camera and rear plane away)\n\n this.camera.near = this.cDist - p.clipNear\n this.camera.far = this.cDist + p.clipFar\n fog.near = this.cDist - p.fogNear\n fog.far = this.cDist + p.fogFar\n\n } else {\n // relative scene mode (default): convert pecentages to Angstroms\n\n const nearFactor = (50 - p.clipNear) / 50\n const farFactor = -(50 - p.clipFar) / 50\n this.camera.near = this.cDist - (this.bRadius * nearFactor)\n this.camera.far = this.cDist + (this.bRadius * farFactor)\n\n const fogNearFactor = (50 - p.fogNear) / 50\n const fogFarFactor = -(50 - p.fogFar) / 50\n fog.near = this.cDist - (this.bRadius * fogNearFactor)\n fog.far = this.cDist + (this.bRadius * fogFarFactor)\n }\n }\n\n if (p.clipMode !== 'camera') {\n\n if (this.camera.type === 'PerspectiveCamera') {\n\n this.camera.near = Math.max(0.1, p.clipDist, this.camera.near)\n this.camera.far = Math.max(1, this.camera.far)\n fog.near = Math.max(0.1, fog.near)\n fog.far = Math.max(1, fog.far)\n } else if (this.camera.type === 'OrthographicCamera') {\n\n if (p.clipDist > 0) {\n this.camera.near = Math.max(p.clipDist, this.camera.near)\n }\n }\n }\n }\n\n private __updateCamera () {\n const camera = this.camera\n camera.updateMatrix()\n camera.updateMatrixWorld(true)\n camera.updateProjectionMatrix()\n\n updateMaterialUniforms(this.scene, camera, this.renderer, this.cDist, this.bRadius)\n sortProjectedPosition(this.scene, camera)\n }\n\n private __setVisibility (model: boolean, picking: boolean, background: boolean, helper: boolean) {\n this.modelGroup.visible = model\n this.pickingGroup.visible = picking\n this.backgroundGroup.visible = background\n this.helperGroup.visible = helper\n }\n\n private __updateLights () {\n this.directionalLight.color.set(this.parameters.lightColor)\n this.directionalLight.intensity = this.parameters.lightIntensity\n\n this.distVector.copy(this.camera.position).setLength(this.boundingBoxLength * 100)\n this.directionalLight.position.copy(this.camera.position).add(this.distVector)\n\n this.ambientLight.color.set(this.parameters.ambientColor)\n this.ambientLight.intensity = this.parameters.ambientIntensity\n }\n\n private __renderPickingGroup (camera: PerspectiveCamera|OrthographicCamera) {\n this.renderer.setRenderTarget(this.pickingTarget || null)\n this.renderer.clear()\n this.__setVisibility(false, true, false, false)\n this.renderer.render(this.scene, camera)\n // back to standard render target\n this.renderer.setRenderTarget(null)\n this.updateInfo()\n\n // if (Debug) {\n // this.__setVisibility(false, true, false, true);\n\n // this.renderer.clear();\n // this.renderer.render(this.scene, camera);\n // }\n }\n\n private __renderModelGroup (camera: PerspectiveCamera|OrthographicCamera, renderTarget?: WebGLRenderTarget) {\n this.renderer.setRenderTarget(renderTarget || null)\n this.renderer.clear()\n this.__setVisibility(false, false, true, false)\n this.renderer.render(this.scene, camera)\n this.renderer.clear(false, true, true)\n this.updateInfo()\n\n this.__setVisibility(true, false, false, Debug)\n this.renderer.render(this.scene, camera)\n this.renderer.setRenderTarget(null) // set back to default canvas\n this.updateInfo()\n }\n\n private __renderSuperSample (camera: PerspectiveCamera|OrthographicCamera, renderTarget?: WebGLRenderTarget) {\n // based on the Supersample Anti-Aliasing Render Pass\n // contributed to three.js by bhouston / http://clara.io/\n //\n // This manual approach to SSAA re-renders the scene ones for\n // each sample with camera jitter and accumulates the results.\n // References: https://en.wikipedia.org/wiki/Supersampling\n const offsetList = JitterVectors[ Math.max(0, Math.min(this.sampleLevel, 5)) ]\n\n const baseSampleWeight = 1.0 / offsetList.length\n const roundingRange = 1 / 32\n\n this.compositeUniforms.tForeground.value = this.sampleTarget.texture\n\n let width = this.sampleTarget.width\n const height = this.sampleTarget.height\n if (this.parameters.cameraType === 'stereo') {\n width /= 2\n }\n\n // render the scene multiple times, each slightly jitter offset\n // from the last and accumulate the results.\n for (let i = 0; i < offsetList.length; ++i) {\n const offset = offsetList[ i ]\n camera.setViewOffset(\n width, height, offset[ 0 ], offset[ 1 ], width, height\n )\n camera.updateProjectionMatrix()\n updateCameraUniforms(this.scene, camera)\n\n let sampleWeight = baseSampleWeight\n // the theory is that equal weights for each sample lead to an\n // accumulation of rounding errors.\n // The following equation varies the sampleWeight per sample\n // so that it is uniformly distributed across a range of values\n // whose rounding errors cancel each other out.\n const uniformCenteredDistribution = -0.5 + (i + 0.5) / offsetList.length\n sampleWeight += roundingRange * uniformCenteredDistribution\n this.compositeUniforms.scale.value = sampleWeight\n\n this.__renderModelGroup(camera, this.sampleTarget)\n this.renderer.setRenderTarget(this.holdTarget)\n if (i === 0) {\n this.renderer.clear()\n }\n\n this.renderer.render(this.compositeScene, this.compositeCamera)\n }\n\n this.compositeUniforms.scale.value = 1.0\n this.compositeUniforms.tForeground.value = this.holdTarget.texture\n\n camera.clearViewOffset()\n this.renderer.setRenderTarget(renderTarget || null)\n this.renderer.clear()\n this.renderer.render(this.compositeScene, this.compositeCamera)\n }\n\n private __renderStereo (picking = false, _renderTarget?: WebGLRenderTarget) {\n const stereoCamera = this.stereoCamera\n stereoCamera.update(this.perspectiveCamera);\n\n const renderer = this.renderer\n let size = new Vector2()\n renderer.getSize(size)\n\n renderer.setScissorTest(true)\n\n renderer.setScissor(0, 0, size.width / 2, size.height)\n renderer.setViewport(0, 0, size.width / 2, size.height)\n updateCameraUniforms(this.scene, stereoCamera.cameraL)\n this.__render(picking, stereoCamera.cameraL)\n\n renderer.setScissor(size.width / 2, 0, size.width / 2, size.height)\n renderer.setViewport(size.width / 2, 0, size.width / 2, size.height)\n updateCameraUniforms(this.scene, stereoCamera.cameraR)\n this.__render(picking, stereoCamera.cameraR)\n\n renderer.setScissorTest(false)\n renderer.setViewport(0, 0, size.width, size.height)\n }\n\n private __render(picking = false, camera: PerspectiveCamera|OrthographicCamera, renderTarget?: WebGLRenderTarget) {\n if (picking) {\n if (!this.lastRenderedPicking) this.__renderPickingGroup(camera)\n } else if (this.sampleLevel > 0 && this.parameters.cameraType !== 'stereo') {\n // TODO super sample broken for stereo camera\n this.__renderSuperSample(camera, renderTarget)\n } else {\n this.__renderModelGroup(camera, renderTarget)\n }\n }\n\n render (picking = false, renderTarget?: WebGLRenderTarget) {\n if (this.rendering) {\n Log.warn(\"'tried to call 'render' from within 'render'\")\n return\n }\n\n // Log.time('Viewer.render')\n\n this.rendering = true\n\n try {\n this.__updateClipping()\n this.__updateCamera()\n this.__updateLights()\n this.updateInfo(true)\n\n // render\n if (this.parameters.cameraType === 'stereo') {\n this.__renderStereo(picking, renderTarget)\n } else {\n this.__render(picking, this.camera, renderTarget)\n }\n this.lastRenderedPicking = picking\n } finally {\n this.rendering = false\n this.renderPending = false\n }\n this.signals.rendered.dispatch()\n\n // Log.timeEnd('Viewer.render')\n // Log.log(this.info.memory, this.info.render)\n }\n\n clear () {\n Log.log('scene cleared')\n this.scene.remove(this.rotationGroup)\n this._initScene()\n this.renderer.clear()\n }\n\n dispose () {\n this.renderer.dispose()\n window.cancelAnimationFrame(this.frameRequest)\n }\n}\n","/**\n * @file Constants\n * @author Alexander Rose \n * @private\n */\n\nexport const LeftMouseButton = 1\nexport const MiddleMouseButton = 2\nexport const RightMouseButton = 3\n","/**\n * @file Mouse Observer\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector2 } from 'three'\nimport { Signal } from 'signals'\n\nimport { LeftMouseButton, RightMouseButton } from '../constants'\nimport { defaults } from '../utils'\nimport Viewer from '../viewer/viewer'\nimport MouseControls from '../controls/mouse-controls'\n\ntype Optional = Pick, K> & Omit;\n\n/**\n * @example\n * mouseObserver.signals.scrolled.add( function( delta ){ ... } );\n *\n * @typedef {Object} MouseSignals\n * @property {Signal} moved - on move: deltaX, deltaY\n * @property {Signal} scrolled - on scroll: delta\n * @property {Signal} dragged - on drag: deltaX, deltaY\n * @property {Signal} dropped - on drop\n * @property {Signal} clicked - on click\n * @property {Signal} hovered - on hover\n */\n\nfunction getTouchDistance (event: TouchEvent) {\n const dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX\n const dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY\n return Math.sqrt(dx * dx + dy * dy)\n}\n\nfunction getMouseButtons (event: MouseEvent) {\n if (typeof event === 'object') {\n if ('buttons' in event) {\n return event.buttons\n } else if ('which' in event as any) {\n const b = (event as any).which\n if (b === 2) {\n return 4\n } else if (b === 3) {\n return 2\n } else if (b > 0) {\n return 1 << (b - 1)\n }\n } else if ('button' in event as any) {\n const b = (event as any).button\n if (b === 1) {\n return 4\n } else if (b === 2) {\n return 2\n } else if (b >= 0) {\n return 1 << b\n }\n }\n }\n return 0\n}\n\nexport interface MouseSignals {\n moved: Signal // on move: deltaX, deltaY\n scrolled: Signal // on scroll: delta\n dragged: Signal // on drag: deltaX, deltaY\n dropped: Signal // on drop\n clicked: Signal // on click\n hovered: Signal // on hover\n doubleClicked: Signal\n}\n\nexport interface MouseParams {\n hoverTimeout?: number\n handleScroll?:boolean\n doubleClickSpeed?: number\n}\n\n/**\n * Mouse observer\n *\n * @example\n * // listen to mouse moving (and touch-moving) events\n * mouseObserver.moved.moved.add( function( deltaX, deltaY ){ ... } );\n *\n * @example\n * // listen to scrolling (and pinching) events\n * mouseObserver.signals.scrolled.add( function( delta ){ ... } );\n *\n * @example\n * // listen to dragging (and touch-dragging) events\n * mouseObserver.signals.dragged.add( function( deltaX, deltaY ){ ... } );\n *\n * @example\n * // listen to clicking (and tapping) events\n * mouseObserver.signals.clicked.add( function(){ ... } );\n *\n * @example\n * // listen to double clicking (and double tapping) events\n * mouseObserver.signals.doubleClicked.add( function(){ ... } );\n *\n * @example\n * // listen to hovering events\n * mouseObserver.signals.hovered.add( function(){ ... } );\n */\nclass MouseObserver {\n signals: MouseSignals = {\n moved: new Signal(),\n scrolled: new Signal(),\n dragged: new Signal(),\n dropped: new Signal(),\n clicked: new Signal(),\n hovered: new Signal(),\n doubleClicked: new Signal()\n }\n\n hoverTimeout: number\n handleScroll:boolean\n doubleClickSpeed: number\n\n viewer: Viewer\n mouse: MouseObserver\n controls: MouseControls\n\n position = new Vector2() // Position on page\n prevPosition = new Vector2() // Previous position on page\n down = new Vector2() // Position on page when clicked\n canvasPosition = new Vector2() // Position on dom element\n prevClickCP = new Vector2()\n\n moving = false // Flag indicating if the mouse is moving\n hovering = true // Flag indicating if the mouse is hovering\n scrolled = false // Flag indicating if there was a scolling event since the last mouse move\n lastMoved = Infinity // Timestamp of last mouse move\n which? = 0 // 0: No button; 1: Left button; 2: Middle button; 3: Right button\n buttons? = 0 // 0: No button; 1: Left button; 2: Right button; 4: Middle button\n pressed? = false // Flag indicating if the mouse is pressed down\n altKey = false // Flag indicating if the alt key is pressed\n ctrlKey = false // Flag indicating if the ctrl key is pressed\n metaKey = false // Flag indicating if the meta key is pressed\n shiftKey = false // Flag indicating if the shift key is pressed\n\n doubleClickPending: boolean\n lastClicked: number\n overElement: boolean\n lastTouchDistance: number\n private frameRequest: number\n\n /**\n * @param {Element} domElement - the dom element to observe mouse events in\n * @param {Object} params - parameters object\n * @param {Integer} params.hoverTimeout - timeout in ms until the {@link MouseSignals.hovered}\n * signal is fired, set to -1 to ignore hovering\n * @param {Boolean} params.handleScroll - whether or not to handle scroll events\n * @param {Integer} params.doubleClickSpeed - max time in ms to trigger double click\n */\n constructor (readonly domElement: HTMLCanvasElement, params: MouseParams = {}) {\n this.domElement.style.touchAction = 'none'\n\n this.hoverTimeout = defaults(params.hoverTimeout, 50)\n this.handleScroll = defaults(params.handleScroll, true)\n this.doubleClickSpeed = defaults(params.doubleClickSpeed, 500)\n\n this._listen = this._listen.bind(this)\n this._onMousewheel = this._onMousewheel.bind(this)\n this._onMousemove = this._onMousemove.bind(this)\n this._onMousedown = this._onMousedown.bind(this)\n this._onMouseup = this._onMouseup.bind(this)\n this._onContextmenu = this._onContextmenu.bind(this)\n this._onTouchstart = this._onTouchstart.bind(this)\n this._onTouchend = this._onTouchend.bind(this)\n this._onTouchmove = this._onTouchmove.bind(this)\n\n this._listen()\n\n const opt = { passive: false } // treat as 'passive' so preventDefault can be called\n document.addEventListener('mousewheel', this._onMousewheel, opt)\n document.addEventListener('wheel', this._onMousewheel, opt)\n document.addEventListener('MozMousePixelScroll', this._onMousewheel, opt)\n document.addEventListener('mousemove', this._onMousemove, opt)\n document.addEventListener('mousedown', this._onMousedown, opt)\n document.addEventListener('mouseup', this._onMouseup, opt)\n document.addEventListener('contextmenu', this._onContextmenu, opt)\n document.addEventListener('touchstart', this._onTouchstart, opt)\n document.addEventListener('touchend', this._onTouchend, opt)\n document.addEventListener('touchmove', this._onTouchmove, opt)\n }\n\n get key () {\n let key = 0\n if (this.altKey) key += 1\n if (this.ctrlKey) key += 2\n if (this.metaKey) key += 4\n if (this.shiftKey) key += 8\n return key\n }\n\n setParameters (params: MouseParams = {}) {\n this.hoverTimeout = defaults(params.hoverTimeout, this.hoverTimeout)\n }\n\n /**\n * listen to mouse actions\n * @emits {MouseSignals.clicked} when clicked\n * @emits {MouseSignals.hovered} when hovered\n * @return {undefined}\n */\n _listen () {\n const now = window.performance.now()\n const cp = this.canvasPosition\n if (this.doubleClickPending && now - this.lastClicked > this.doubleClickSpeed) {\n this.doubleClickPending = false\n }\n if (now - this.lastMoved > this.hoverTimeout) {\n this.moving = false\n }\n if (this.scrolled || (!this.moving && !this.hovering)) {\n this.scrolled = false\n if (this.hoverTimeout !== -1 && this.overElement) {\n this.hovering = true\n this.signals.hovered.dispatch(cp.x, cp.y)\n }\n }\n this.frameRequest = window.requestAnimationFrame(this._listen)\n }\n\n /**\n * handle mouse scroll\n * @emits {MouseSignals.scrolled} when scrolled\n * @param {Event} event - mouse event\n * @return {undefined}\n */\n _onMousewheel(event: Optional & { wheelDelta?: number, wheelDeltaY?: number }) {\n if (event.target !== this.domElement || !this.handleScroll) {\n return\n }\n event.preventDefault()\n this._setKeys(event as any)\n\n let delta = 0\n // This has to be written in a particular way to handle old browsers that\n // all send events with different properties set in different ways.\n if ('deltaY' in event && 'deltaMode' in event &&\n event.deltaY !== undefined && event.deltaMode !== undefined) {\n // all modern browsers, using WheelEvent; deltaY + down (toward user)\n if (event.deltaMode === WheelEvent.DOM_DELTA_PIXEL)\n // everything except Firefox: normally 100 per wheel click\n delta = -event.deltaY * (2.5 / 100.0)\n else if (event.deltaMode === WheelEvent.DOM_DELTA_LINE)\n // Firefox in line mode, normally 3 per wheel click\n delta = -event.deltaY * (2.5 / 3.0)\n else // page mode: 1 per wheel click\n delta = -event.deltaY * 2.5\n } else if ('deltaY' in event && !('detail' in event)) {\n // Old Firefox or IE 11: deltaY but no deltaMode; treat as pixels\n delta = -event.deltaY * (2.5 / 100.0)\n } else if (event.wheelDelta !== undefined) {\n delta = -event.wheelDelta * (2.5 / 100)\n } else if (event.wheelDeltaY !== undefined) {\n delta = -event.wheelDeltaY * (2.5 / 100)\n } else if (event.detail !== undefined){\n // Old Firefox, MouseWheelEvent\n delta = -event.detail / 3\n }\n this.signals.scrolled.dispatch(delta)\n\n setTimeout(() => {\n this.scrolled = true\n }, this.hoverTimeout)\n }\n\n /**\n * handle mouse move\n * @emits {MouseSignals.moved} when moved\n * @emits {MouseSignals.dragged} when dragged\n * @param {Event} event - mouse event\n * @return {undefined}\n */\n _onMousemove (event: MouseEvent) {\n if (event.target === this.domElement) {\n event.preventDefault()\n this.overElement = true\n } else {\n this.overElement = false\n }\n this._setKeys(event)\n this.moving = true\n this.hovering = false\n this.lastMoved = window.performance.now()\n this.prevPosition.copy(this.position)\n this.position.set(event.clientX, event.clientY)\n this._setCanvasPosition(event)\n const dx = this.prevPosition.x - this.position.x\n const dy = this.prevPosition.y - this.position.y\n this.signals.moved.dispatch(dx, dy)\n if (this.pressed) {\n this.signals.dragged.dispatch(dx, dy)\n }\n }\n\n _onMousedown (event: MouseEvent) {\n if (event.target !== this.domElement) {\n return\n }\n event.preventDefault()\n this._setKeys(event)\n this.moving = false\n this.hovering = false\n this.down.set(event.clientX, event.clientY)\n this.position.set(event.clientX, event.clientY)\n this.which = event.which\n this.buttons = getMouseButtons(event)\n this.pressed = true\n this._setCanvasPosition(event)\n }\n\n /**\n * handle mouse up\n * @emits {MouseSignals.doubleClicked} when double clicked\n * @emits {MouseSignals.dropped} when dropped\n * @param {Event} event - mouse event\n * @return {undefined}\n */\n _onMouseup (event: MouseEvent) {\n if (event.target === this.domElement) {\n event.preventDefault()\n }\n this._setKeys(event)\n const cp = this.canvasPosition\n if (this._distance() < 4) {\n this.lastClicked = window.performance.now()\n if (this.doubleClickPending && this.prevClickCP.distanceTo(cp) < 4) {\n this.signals.doubleClicked.dispatch(cp.x, cp.y)\n this.doubleClickPending = false\n }\n this.signals.clicked.dispatch(cp.x, cp.y)\n this.doubleClickPending = true\n this.prevClickCP.copy(cp)\n }\n this.which = undefined\n this.buttons = undefined\n this.pressed = undefined\n // if (this._distance() > 3 || event.which === RightMouseButton) {\n // this.signals.dropped.dispatch();\n // }\n }\n\n _onContextmenu (event: MouseEvent) {\n if (event.target === this.domElement) {\n event.preventDefault()\n }\n }\n\n _onTouchstart (event: TouchEvent) {\n if (event.target !== this.domElement) {\n return\n }\n event.preventDefault()\n this.pressed = true\n switch (event.touches.length) {\n case 1: {\n this.moving = false\n this.hovering = false\n this.down.set(\n event.touches[ 0 ].pageX,\n event.touches[ 0 ].pageY\n )\n this.position.set(\n event.touches[ 0 ].pageX,\n event.touches[ 0 ].pageY\n )\n this._setCanvasPosition(event.touches[ 0 ])\n break\n }\n\n case 2: {\n this.down.set(\n (event.touches[ 0 ].pageX + event.touches[ 1 ].pageX) / 2,\n (event.touches[ 0 ].pageY + event.touches[ 1 ].pageY) / 2\n )\n this.position.set(\n (event.touches[ 0 ].pageX + event.touches[ 1 ].pageX) / 2,\n (event.touches[ 0 ].pageY + event.touches[ 1 ].pageY) / 2\n )\n this.lastTouchDistance = getTouchDistance(event)\n }\n }\n }\n\n _onTouchend (event: TouchEvent) {\n if (event.target === this.domElement) {\n event.preventDefault()\n }\n this.which = undefined\n this.buttons = undefined\n this.pressed = undefined\n }\n\n _onTouchmove (event: TouchEvent) {\n if (event.target === this.domElement) {\n event.preventDefault()\n this.overElement = true\n } else {\n this.overElement = false\n }\n switch (event.touches.length) {\n case 1: {\n this._setKeys(event)\n this.which = LeftMouseButton\n this.buttons = 1\n this.moving = true\n this.hovering = false\n this.lastMoved = window.performance.now()\n this.prevPosition.copy(this.position)\n this.position.set(\n event.touches[ 0 ].pageX,\n event.touches[ 0 ].pageY\n )\n this._setCanvasPosition(event.touches[ 0 ])\n const dx = this.prevPosition.x - this.position.x\n const dy = this.prevPosition.y - this.position.y\n this.signals.moved.dispatch(dx, dy)\n if (this.pressed) {\n this.signals.dragged.dispatch(dx, dy)\n }\n break\n }\n\n case 2: {\n const touchDistance = getTouchDistance(event)\n const delta = touchDistance - this.lastTouchDistance\n this.lastTouchDistance = touchDistance\n this.prevPosition.copy(this.position)\n this.position.set(\n (event.touches[ 0 ].pageX + event.touches[ 1 ].pageX) / 2,\n (event.touches[ 0 ].pageY + event.touches[ 1 ].pageY) / 2\n )\n if (Math.abs(delta) > 2 && this.handleScroll &&\n this.position.distanceTo(this.prevPosition) < 2\n ) {\n this.which = 0\n this.buttons = 0\n this.signals.scrolled.dispatch(delta / 2)\n } else {\n this.which = RightMouseButton\n this.buttons = 2\n const dx = this.prevPosition.x - this.position.x\n const dy = this.prevPosition.y - this.position.y\n this.signals.moved.dispatch(dx, dy)\n if (this.pressed) {\n this.signals.dragged.dispatch(dx, dy)\n }\n }\n }\n }\n }\n\n _distance () {\n return this.position.distanceTo(this.down)\n }\n\n _setCanvasPosition (event: any) { // TODO\n const box = this.domElement.getBoundingClientRect()\n let offsetX, offsetY;\n if ('clientX' in event && 'clientY' in event) {\n offsetX = event.clientX - box.left\n offsetY = event.clientY - box.top\n } else {\n offsetX = event.offsetX\n offsetY = event.offsetY\n }\n this.canvasPosition.set(offsetX, box.height - offsetY)\n }\n\n _setKeys (event: MouseEvent|TouchEvent) {\n this.altKey = event.altKey\n this.ctrlKey = event.ctrlKey\n this.metaKey = event.metaKey\n this.shiftKey = event.shiftKey\n }\n\n dispose () {\n document.removeEventListener('mousewheel', this._onMousewheel)\n document.removeEventListener('wheel', this._onMousewheel)\n document.removeEventListener('MozMousePixelScroll', this._onMousewheel)\n document.removeEventListener('mousemove', this._onMousemove)\n document.removeEventListener('mousedown', this._onMousedown)\n document.removeEventListener('mouseup', this._onMouseup)\n document.removeEventListener('contextmenu', this._onContextmenu)\n document.removeEventListener('touchstart', this._onTouchstart)\n document.removeEventListener('touchend', this._onTouchend)\n document.removeEventListener('touchmove', this._onTouchmove)\n window.cancelAnimationFrame(this.frameRequest)\n }\n}\n\nexport default MouseObserver\n","/**\n * @file Trackball Controls\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Matrix4, Quaternion } from 'three'\n\nimport { defaults } from '../utils'\nimport Stage from '../stage/stage'\nimport MouseObserver from '../stage/mouse-observer'\nimport Viewer from '../viewer/viewer'\nimport ViewerControls from './viewer-controls'\nimport AtomProxy from '../proxy/atom-proxy';\nimport Component from '../component/component';\n\nconst tmpRotateXMatrix = new Matrix4()\nconst tmpRotateYMatrix = new Matrix4()\nconst tmpRotateZMatrix = new Matrix4()\nconst tmpRotateMatrix = new Matrix4()\nconst tmpRotateCameraMatrix = new Matrix4()\nconst tmpRotateVector = new Vector3()\nconst tmpRotateQuaternion = new Quaternion()\nconst tmpRotateQuaternion2 = new Quaternion()\nconst tmpPanMatrix = new Matrix4()\nconst tmpPanVector = new Vector3()\nconst tmpAtomVector = new Vector3()\n\nexport interface TrackballControlsParams {\n rotateSpeed?: number\n zoomSpeed?: number\n panSpeed?: number\n}\n\n/**\n * Trackball controls\n */\nclass TrackballControls {\n viewer: Viewer\n mouse: MouseObserver\n controls: ViewerControls\n\n rotateSpeed: number\n zoomSpeed: number\n panSpeed: number\n\n constructor (readonly stage: Stage, params: TrackballControlsParams = {}) {\n this.rotateSpeed = defaults(params.rotateSpeed, 2.0)\n this.zoomSpeed = defaults(params.zoomSpeed, 1.2)\n this.panSpeed = defaults(params.panSpeed, 1.0)\n\n this.viewer = stage.viewer\n this.mouse = stage.mouseObserver\n this.controls = stage.viewerControls\n }\n\n get component (): Component|undefined {\n return this.stage.transformComponent\n }\n\n get atom (): AtomProxy|undefined {\n return this.stage.transformAtom\n }\n\n private _setPanVector (x: number, y: number, z = 0) {\n const scaleFactor = this.controls.getCanvasScaleFactor(z)\n tmpPanVector.set(x, y, 0)\n tmpPanVector.multiplyScalar(this.panSpeed * scaleFactor)\n }\n\n private _getRotateXY (x: number, y: number) {\n return [\n this.rotateSpeed * -x * 0.01,\n this.rotateSpeed * y * 0.01\n ]\n }\n\n private _getCameraRotation(m: Matrix4) {\n m.extractRotation(this.viewer.camera.matrixWorld)\n m.multiply(tmpRotateYMatrix.makeRotationY(Math.PI))\n\n return m\n }\n\n private _transformPanVector () {\n if (!this.component) return\n\n // Adjust for component and scene rotation\n tmpPanMatrix.extractRotation(this.component.transform)\n tmpPanMatrix.premultiply(this.viewer.rotationGroup.matrix)\n tmpPanMatrix.invert()\n\n // Adjust for camera rotation\n tmpPanMatrix.multiply(this._getCameraRotation(tmpRotateMatrix))\n\n tmpPanVector.applyMatrix4(tmpPanMatrix)\n }\n\n zoom (delta: number) {\n this.controls.zoom(this.zoomSpeed * delta * 0.02)\n }\n\n pan (x: number, y: number) {\n this._setPanVector(x, y)\n\n // Adjust for scene rotation\n tmpPanMatrix.copy(this.viewer.rotationGroup.matrix).invert()\n\n // Adjust for camera rotation\n tmpPanMatrix.multiply(this._getCameraRotation(tmpRotateMatrix))\n\n tmpPanVector.applyMatrix4(tmpPanMatrix)\n this.controls.translate(tmpPanVector)\n }\n\n panComponent (x: number, y: number) {\n if (!this.component) return\n\n this._setPanVector(x, y)\n this._transformPanVector()\n\n this.component.position.add(tmpPanVector)\n this.component.updateMatrix()\n }\n\n panAtom (x: number, y: number) {\n if (!this.atom || !this.component) return\n\n this.atom.positionToVector3(tmpAtomVector)\n tmpAtomVector.add(this.viewer.translationGroup.position)\n tmpAtomVector.applyMatrix4(this.viewer.rotationGroup.matrix)\n\n this._setPanVector(x, y, tmpAtomVector.z)\n this._transformPanVector()\n\n this.atom.positionAdd(tmpPanVector)\n this.component.updateRepresentations({ 'position': true })\n }\n\n rotate (x: number, y: number) {\n const [ dx, dy ] = this._getRotateXY(x, y)\n\n // rotate around screen X then screen Y\n this._getCameraRotation(tmpRotateMatrix)\n tmpRotateVector.set(1, 0, 0) // X axis\n tmpRotateVector.applyMatrix4(tmpRotateMatrix) // screen X\n tmpRotateQuaternion.setFromAxisAngle(tmpRotateVector, dy)\n\n tmpRotateVector.set(0, 1, 0) // Y axis\n tmpRotateVector.applyMatrix4(tmpRotateMatrix) // screen Y\n tmpRotateQuaternion2.setFromAxisAngle(tmpRotateVector, dx)\n\n tmpRotateQuaternion.multiply(tmpRotateQuaternion2)\n tmpRotateMatrix.makeRotationFromQuaternion(tmpRotateQuaternion)\n this.controls.applyMatrix(tmpRotateMatrix)\n }\n\n zRotate (x: number, y: number) {\n const dz = this.rotateSpeed * ((-x + y) / -2) * 0.01\n\n tmpRotateZMatrix.makeRotationZ(dz)\n this.controls.applyMatrix(tmpRotateZMatrix)\n }\n\n rotateComponent (x: number, y: number) {\n if (!this.component) return\n\n const [ dx, dy ] = this._getRotateXY(x, y)\n\n this._getCameraRotation(tmpRotateCameraMatrix)\n\n tmpRotateMatrix.extractRotation(this.component.transform)\n tmpRotateMatrix.premultiply(this.viewer.rotationGroup.matrix)\n tmpRotateMatrix.invert()\n tmpRotateMatrix.premultiply(tmpRotateCameraMatrix)\n\n tmpRotateVector.set(1, 0, 0)\n tmpRotateVector.applyMatrix4(tmpRotateMatrix)\n tmpRotateXMatrix.makeRotationAxis(tmpRotateVector, dy)\n\n tmpRotateVector.set(0, 1, 0)\n tmpRotateVector.applyMatrix4(tmpRotateMatrix)\n tmpRotateYMatrix.makeRotationAxis(tmpRotateVector, dx)\n\n tmpRotateXMatrix.multiply(tmpRotateYMatrix)\n tmpRotateQuaternion.setFromRotationMatrix(tmpRotateXMatrix)\n this.component.quaternion.premultiply(tmpRotateQuaternion)\n this.component.quaternion.normalize()\n this.component.updateMatrix()\n }\n}\n\nexport default TrackballControls\n","/**\n * @file Picking Proxy\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Matrix4, Vector2 } from 'three'\n\nimport Stage from '../stage/stage'\nimport StructureComponent from '../component/structure-component'\nimport MouseObserver from '../stage/mouse-observer'\nimport { Picker } from '../utils/picker'\nimport ViewerControls from './viewer-controls'\nimport Shape from '../geometry/shape'\nimport Structure from '../structure/structure'\nimport BondProxy from '../proxy/bond-proxy'\nimport AtomProxy from '../proxy/atom-proxy'\nimport Surface from '../surface/surface'\nimport Volume from '../surface/volume'\nimport Unitcell from '../symmetry/unitcell'\nimport Component from '../component/component';\n\nconst tmpVec = new Vector3()\n\nexport interface ShapePrimitive {\n name: string\n shape: Shape\n}\n\nfunction closer (x: Vector3, a: Vector3, b: Vector3) {\n return x.distanceTo(a) < x.distanceTo(b)\n}\n\n/**\n * Picking data object.\n * @typedef {Object} PickingData - picking data\n * @property {Number} [pid] - picking id\n * @property {Object} [instance] - instance data\n * @property {Integer} instance.id - instance id\n * @property {String|Integer} instance.name - instance name\n * @property {Matrix4} instance.matrix - transformation matrix of the instance\n * @property {Picker} [picker] - picker object\n */\n\nexport interface InstanceData {\n id: number\n name: number|string\n matrix: Matrix4\n}\n\nexport interface PickingData {\n pid: number\n instance: InstanceData\n picker: Picker\n}\n\n/**\n * Picking proxy class.\n */\nclass PickingProxy {\n pid: number\n picker: Picker\n instance: InstanceData\n controls: ViewerControls\n mouse: MouseObserver\n\n /**\n * Create picking proxy object\n * @param {PickingData} pickingData - picking data\n * @param {Stage} stage - stage object\n */\n constructor (pickingData: PickingData, readonly stage: Stage) {\n this.pid = pickingData.pid\n this.picker = pickingData.picker\n\n /**\n * @type {Object}\n */\n this.instance = pickingData.instance\n\n /**\n * @type {Stage}\n */\n this.stage = stage\n /**\n * @type {ViewerControls}\n */\n this.controls = stage.viewerControls\n /**\n * @type {MouseObserver}\n */\n this.mouse = stage.mouseObserver\n }\n\n /**\n * Kind of the picked data\n * @type {String}\n */\n get type () { return this.picker.type }\n\n /**\n * If the `alt` key was pressed\n * @type {Boolean}\n */\n get altKey () { return this.mouse.altKey }\n /**\n * If the `ctrl` key was pressed\n * @type {Boolean}\n */\n get ctrlKey () { return this.mouse.ctrlKey }\n /**\n * If the `meta` key was pressed\n * @type {Boolean}\n */\n get metaKey () { return this.mouse.metaKey }\n /**\n * If the `shift` key was pressed\n * @type {Boolean}\n */\n get shiftKey () { return this.mouse.shiftKey }\n\n /**\n * Position of the mouse on the canvas\n * @type {Vector2}\n */\n get canvasPosition (): Vector2 { return this.mouse.canvasPosition }\n\n /**\n * The component the picked data is part of\n * @type {Component}\n */\n get component (): Component {\n return this.stage.getComponentsByObject(this.picker.data as any).list[ 0 ] // TODO\n }\n\n /**\n * The picked object data\n * @type {Object}\n */\n get object () {\n return this.picker.getObject(this.pid)\n }\n\n /**\n * The 3d position in the scene of the picked object\n * @type {Vector3}\n */\n get position () {\n return this.picker.getPosition(this.pid, this.instance, this.component)\n }\n\n /**\n * The atom of a picked bond that is closest to the mouse\n * @type {AtomProxy}\n */\n get closestBondAtom (): AtomProxy|undefined {\n if (this.type !== 'bond' || !this.bond) return undefined\n\n const bond = this.bond\n const controls = this.controls\n const cp = this.canvasPosition\n\n const v1 = bond.atom1.positionToVector3()\n const v2 = bond.atom2.positionToVector3()\n\n v1.applyMatrix4(this.component.matrix)\n v2.applyMatrix4(this.component.matrix)\n\n const acp1 = controls.getPositionOnCanvas(v1)\n const acp2 = controls.getPositionOnCanvas(v2)\n\n return closer(cp as any, acp1, acp2) ? bond.atom1 : bond.atom2\n }\n\n /**\n * Close-by atom\n * @type {AtomProxy}\n */\n get closeAtom (): AtomProxy|undefined {\n const cp = this.canvasPosition\n const ca = this.closestBondAtom\n if (!ca) return undefined\n\n const v = ca.positionToVector3().applyMatrix4(this.component.matrix)\n\n const acp = this.controls.getPositionOnCanvas(v)\n\n ca.positionToVector3(tmpVec)\n if (this.instance) tmpVec.applyMatrix4(this.instance.matrix)\n tmpVec.applyMatrix4(this.component.matrix)\n const viewer = this.controls.viewer\n tmpVec.add(viewer.translationGroup.position)\n tmpVec.applyMatrix4(viewer.rotationGroup.matrix)\n\n const scaleFactor = this.controls.getCanvasScaleFactor(tmpVec.z)\n const sc = this.component as StructureComponent\n const radius = sc.getMaxRepresentationRadius(ca.index)\n //console.log(scaleFactor, cp.distanceTo(acp), radius/scaleFactor, radius)\n\n if (cp.distanceTo(acp) <= radius/scaleFactor) {\n return ca\n } else {\n return undefined\n }\n }\n\n /**\n * @type {Object}\n */\n get arrow () { return this._objectIfType('arrow') as ShapePrimitive }\n /**\n * @type {AtomProxy}\n */\n get atom () { return this._objectIfType('atom') as AtomProxy }\n /**\n * @type {Object}\n */\n get axes () { return this._objectIfType('axes') }\n /**\n * @type {BondProxy}\n */\n get bond () { return this._objectIfType('bond') as BondProxy }\n /**\n * @type {Object}\n */\n get box () { return this._objectIfType('box') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get cone () { return this._objectIfType('cone') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get clash () { return this._objectIfType('clash') as { clash: { sele1: string, sele2: string } } }\n /**\n * @type {BondProxy}\n */\n get contact () { return this._objectIfType('contact') as { type: string, atom1: AtomProxy, atom2: AtomProxy } }\n /**\n * @type {Object}\n */\n get cylinder () { return this._objectIfType('cylinder') as ShapePrimitive }\n /**\n * @type {BondProxy}\n */\n get distance () { return this._objectIfType('distance') as BondProxy }\n /**\n * @type {Object}\n */\n get ellipsoid () { return this._objectIfType('ellipsoid') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get octahedron () { return this._objectIfType('octahedron') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get point () { return this._objectIfType('point') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get mesh () { return this._objectIfType('mesh') as { name: string, shape: Shape, serial: number } }\n /**\n * @type {Object}\n */\n get slice () { return this._objectIfType('slice') as { volume: Volume, value: number } }\n /**\n * @type {Object}\n */\n get sphere () { return this._objectIfType('sphere') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get tetrahedron () { return this._objectIfType('tetrahedron') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get torus () { return this._objectIfType('torus') as ShapePrimitive }\n /**\n * @type {Object}\n */\n get surface () { return this._objectIfType('surface') as { surface: Surface, index: number } }\n /**\n * @type {Object}\n */\n get unitcell () { return this._objectIfType('unitcell') as { unitcell: Unitcell, structure: Structure } }\n /**\n * @type {Object}\n */\n get unknown () { return this._objectIfType('unknown') }\n /**\n * @type {Object}\n */\n get volume () { return this._objectIfType('volume') as { volume: Volume, value: number } }\n /**\n * @type {Object}\n */\n get wideline () { return this._objectIfType('wideline') as ShapePrimitive }\n\n _objectIfType (type: string) {\n return this.type === type ? this.object : undefined\n }\n\n getLabel () {\n const atom = this.atom || this.closeAtom\n let msg = 'nothing'\n if (this.arrow) {\n msg = this.arrow.name\n } else if (atom) {\n msg = `atom: ${atom.qualifiedName()} (${atom.structure.name})`\n } else if (this.axes) {\n msg = 'axes'\n } else if (this.bond) {\n msg = `bond: ${this.bond.atom1.qualifiedName()} - ${this.bond.atom2.qualifiedName()} (${this.bond.structure.name})`\n } else if (this.box) {\n msg = this.box.name\n } else if (this.cone) {\n msg = this.cone.name\n } else if (this.clash) {\n msg = `clash: ${this.clash.clash.sele1} - ${this.clash.clash.sele2}`\n } else if (this.contact) {\n msg = `${this.contact.type}: ${this.contact.atom1.qualifiedName()} - ${this.contact.atom2.qualifiedName()} (${this.contact.atom1.structure.name})`\n } else if (this.cylinder) {\n msg = this.cylinder.name\n } else if (this.distance) {\n msg = `distance: ${this.distance.atom1.qualifiedName()} - ${this.distance.atom2.qualifiedName()} (${this.distance.structure.name})`\n } else if (this.ellipsoid) {\n msg = this.ellipsoid.name\n } else if (this.octahedron) {\n msg = this.octahedron.name\n } else if (this.point) {\n msg = this.point.name\n } else if (this.mesh) {\n msg = `mesh: ${this.mesh.name || this.mesh.serial} (${this.mesh.shape.name})`\n } else if (this.slice) {\n msg = `slice: ${this.slice.value.toPrecision(3)} (${this.slice.volume.name})`\n } else if (this.sphere) {\n msg = this.sphere.name\n } else if (this.surface) {\n msg = `surface: ${this.surface.surface.name}`\n } else if (this.tetrahedron) {\n msg = this.tetrahedron.name\n } else if (this.torus) {\n msg = this.torus.name\n } else if (this.unitcell) {\n msg = `unitcell: ${this.unitcell.unitcell.spacegroup} (${this.unitcell.structure.name})`\n } else if (this.unknown) {\n msg = 'unknown'\n } else if (this.volume) {\n msg = `volume: ${this.volume.value.toPrecision(3)} (${this.volume.volume.name})`\n } else if (this.wideline) {\n msg = this.wideline.name\n }\n return msg\n }\n}\n\nexport default PickingProxy\n","/**\n * @file Picking Controls\n * @author Alexander Rose \n * @private\n */\n\nimport PickingProxy from './picking-proxy'\nimport Stage from '../stage/stage'\nimport Viewer from '../viewer/viewer'\n\n/**\n * Picking controls\n */\nclass PickingControls {\n viewer: Viewer\n\n constructor (readonly stage: Stage) {\n this.viewer = stage.viewer\n }\n\n /**\n * get picking data\n * @param {Number} x - canvas x coordinate\n * @param {Number} y - canvas y coordinate\n * @return {PickingProxy|undefined} picking proxy\n */\n pick (x: number, y: number) {\n const pickingData = this.viewer.pick(x, y)\n\n if (pickingData.picker &&\n pickingData.picker.type !== 'ignore' &&\n pickingData.pid !== undefined\n ) {\n const pickerArray = pickingData.picker.array\n if (pickerArray && pickingData.pid >= pickerArray.length) {\n console.error('pid >= picker.array.length')\n } else {\n return new PickingProxy(pickingData, this.stage)\n }\n }\n }\n}\n\nexport default PickingControls\n","/**\n * @file Viewer Controls\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector2, Vector3, Matrix4, Quaternion, OrthographicCamera } from 'three'\nimport * as signalsWrapper from 'signals'\n\nimport {\n ensureVector2, ensureVector3, ensureMatrix4, ensureQuaternion\n} from '../utils'\nimport { degToRad } from '../math/math-utils'\nimport Stage from '../stage/stage'\nimport Viewer from '../viewer/viewer'\n\n/**\n * Orientation matrix, a 4x4 transformation matrix with rotation part\n * used for scene rotation, scale part for scene camera distance and\n * position part for scene translation\n * @typedef {Matrix4} OrientationMatrix - orientation matrix\n */\n\nconst tmpQ = new Quaternion()\nconst tmpP = new Vector3()\nconst tmpS = new Vector3()\n\nconst tmpCanvasVector = new Vector3()\nconst tmpScaleVector = new Vector3()\nconst tmpRotateMatrix = new Matrix4()\nconst tmpRotateVector = new Vector3()\nconst tmpAlignMatrix = new Matrix4()\n\n/**\n * Viewer controls\n */\nclass ViewerControls {\n signals = {\n changed: new signalsWrapper.Signal()\n }\n\n viewer: Viewer\n\n /**\n * @param {Stage} stage - the stage object\n */\n constructor (readonly stage: Stage) {\n this.viewer = stage.viewer\n }\n\n /**\n * scene center position\n * @type {Vector3}\n */\n get position () {\n return this.viewer.translationGroup.position\n }\n\n /**\n * scene rotation\n * @type {Quaternion}\n */\n get rotation () {\n return this.viewer.rotationGroup.quaternion\n }\n\n /**\n * Trigger render and emit changed event\n * @emits {ViewerControls.signals.changed}\n * @return {undefined}\n */\n changed () {\n this.viewer.requestRender()\n this.signals.changed.dispatch()\n }\n\n getPositionOnCanvas (position: Vector3, optionalTarget?: Vector2) {\n const canvasPosition = ensureVector2(optionalTarget)\n const viewer = this.viewer\n\n tmpCanvasVector.copy(position)\n .add(viewer.translationGroup.position)\n .applyMatrix4(viewer.rotationGroup.matrix)\n .project(viewer.camera)\n\n return canvasPosition.set(\n (tmpCanvasVector.x + 1) * viewer.width / 2,\n (tmpCanvasVector.y + 1) * viewer.height / 2\n )\n }\n\n getCanvasScaleFactor (z = 0) {\n const camera = this.viewer.camera\n if (camera instanceof OrthographicCamera) {\n return 1 / camera.zoom\n } else {\n z = Math.abs(z)\n z += this.getCameraDistance()\n const fov = degToRad(camera.fov)\n const unitHeight = 2.0 * z * Math.tan(fov / 2)\n return unitHeight / this.viewer.height\n }\n }\n\n /**\n * get scene orientation\n * @param {Matrix4} optionalTarget - pre-allocated target matrix\n * @return {OrientationMatrix} scene orientation\n */\n getOrientation (optionalTarget?: Matrix4) {\n const m = ensureMatrix4(optionalTarget)\n\n m.copy(this.viewer.rotationGroup.matrix)\n const z = this.getCameraDistance()\n m.scale(tmpScaleVector.set(z, z, z))\n m.setPosition(this.viewer.translationGroup.position)\n\n return m\n }\n\n /**\n * set scene orientation\n * @param {OrientationMatrix|Array} orientation - scene orientation\n * @return {undefined}\n */\n orient (orientation?: Matrix4) {\n ensureMatrix4(orientation).decompose(tmpP, tmpQ, tmpS)\n\n const v = this.viewer\n v.rotationGroup.setRotationFromQuaternion(tmpQ)\n v.translationGroup.position.copy(tmpP)\n v.cameraDistance = tmpS.z\n v.updateZoom()\n this.changed()\n }\n\n /**\n * translate scene\n * @param {Vector3|Array} vector - translation vector\n * @return {undefined}\n */\n translate (vector: Vector3|number[]) {\n this.viewer.translationGroup.position\n .add(ensureVector3(vector))\n this.changed()\n }\n\n /**\n * center scene\n * @param {Vector3|Array} position - center position\n * @return {undefined}\n */\n center (position: Vector3|number[]) {\n this.viewer.translationGroup.position\n .copy(ensureVector3(position)).negate()\n this.changed()\n }\n\n /**\n * \"zoom\" scene by moving camera closer to origin\n * @param {Number} delta - zoom change\n * @return {undefined}\n */\n zoom (delta: number) {\n this.distance(this.getCameraDistance() * (1 - delta))\n }\n\n /**\n * get camera distance\n */\n getCameraDistance(): number {\n return this.viewer.cameraDistance\n }\n\n /**\n * camera distance\n * @param {Number} z - distance\n * @return {undefined}\n */\n distance (distance: number) {\n // Math.abs because distance used to be \"z\", normally negative.\n // Math.max to prevent us from getting _too_ close.\n this.viewer.cameraDistance = Math.max(Math.abs(distance), 0.2)\n this.viewer.updateZoom()\n this.changed()\n }\n\n /**\n * spin scene on axis\n * @param {Vector3|Array} axis - rotation axis\n * @param {Number} angle - amount to spin\n * @return {undefined}\n */\n spin (axis: Vector3|number[], angle: number) {\n tmpRotateMatrix.copy(this.viewer.rotationGroup.matrix).invert()\n tmpRotateVector\n .copy(ensureVector3(axis)).applyMatrix4(tmpRotateMatrix)\n\n this.viewer.rotationGroup.rotateOnAxis(tmpRotateVector, angle)\n this.changed()\n }\n\n /**\n * rotate scene\n * @param {Quaternion|Array} quaternion - rotation quaternion\n * @return {undefined}\n */\n rotate (quaternion: Quaternion|number[]) {\n this.viewer.rotationGroup\n .setRotationFromQuaternion(ensureQuaternion(quaternion))\n this.changed()\n }\n\n /**\n * align scene to basis matrix\n * @param {Matrix4|Array} basis - basis matrix\n * @return {undefined}\n */\n align (basis: Matrix4|number[]) {\n tmpAlignMatrix.copy(ensureMatrix4(basis)).invert()\n\n this.viewer.rotationGroup.setRotationFromMatrix(tmpAlignMatrix)\n this.changed()\n }\n\n /**\n * apply rotation matrix to scene\n * @param {Matrix4|Array} matrix - rotation matrix\n * @return {undefined}\n */\n applyMatrix (matrix: Matrix4|number[]) {\n this.viewer.rotationGroup.applyMatrix4(ensureMatrix4(matrix))\n this.changed()\n }\n}\n\nexport default ViewerControls\n","/**\n * @file Animation\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Quaternion } from 'three'\n\nimport { defaults, ensureVector3, ensureQuaternion } from '../utils'\nimport { lerp, smoothstep } from '../math/math-utils'\nimport ViewerControls from '../controls/viewer-controls'\nimport Stats from '../viewer/stats'\n\n/**\n * Animation. Base animation class.\n * @interface\n */\nabstract class Animation {\n duration: number\n controls: ViewerControls\n\n alpha: number\n startTime: number\n\n pausedTime = -1\n elapsedDuration = 0\n pausedDuration = 0\n ignoreGlobalToggle = false\n\n private _paused = false\n private _resolveList: Function[] = []\n private _hold: boolean\n\n constructor (duration: number|undefined, controls: ViewerControls, ...args: any[]) {\n this.duration = defaults(duration, 1000)\n this.controls = controls\n\n this.startTime = window.performance.now()\n\n this._init(...args)\n }\n\n /**\n * True when animation has finished\n */\n get done () {\n return this.alpha === 1\n }\n\n /**\n * True when animation is paused\n */\n get paused () {\n return this._paused\n }\n\n /**\n * init animation\n */\n abstract _init (...args: any[]): void\n\n /**\n * called on every tick\n */\n abstract _tick (stats?: Stats): void\n\n tick (stats: Stats) {\n if (this._paused) return\n\n this.elapsedDuration = stats.currentTime - this.startTime - this.pausedDuration\n\n if (this.duration === 0) {\n this.alpha = 1\n } else {\n this.alpha = smoothstep(0, 1, this.elapsedDuration / this.duration)\n }\n\n this._tick(stats)\n\n if (this.done) {\n this._resolveList.forEach(resolve => resolve())\n }\n\n return this.done\n }\n\n /**\n * Pause animation\n * @param {boolean} [hold] - put animation on a hold which\n * must be release before it can be resumed\n */\n pause (hold?: boolean) {\n if (hold) this._hold = true\n\n if (this.pausedTime === -1) {\n this.pausedTime = window.performance.now()\n }\n this._paused = true\n }\n\n /**\n * Resume animation\n * @param {Boolean} [releaseHold] - release a hold on the animation\n */\n resume (releaseHold?: boolean) {\n if (!releaseHold && this._hold) return\n\n this.pausedDuration += window.performance.now() - this.pausedTime\n this._paused = false\n this._hold = false\n this.pausedTime = -1\n }\n\n /**\n * Toggle animation\n */\n toggle () {\n if (this._paused) {\n this.resume()\n } else {\n this.pause()\n }\n }\n\n /**\n * Promise-like interface\n */\n then (callback: Function) {\n let p: Promise\n\n if (this.done) {\n p = Promise.resolve()\n } else {\n p = new Promise(resolve => this._resolveList.push(resolve))\n }\n\n return p.then(callback as any)\n }\n}\n\nexport default Animation\n\n/**\n * Spin animation. Spin around an axis.\n */\nexport class SpinAnimation extends Animation {\n axis: Vector3\n angle: number\n\n constructor (duration: number|undefined, controls: ViewerControls, ...args: any[]) {\n super(defaults(duration, Infinity), controls, ...args)\n }\n\n _init (axis: number[]|Vector3, angle: number) {\n if (Array.isArray(axis)) {\n this.axis = new Vector3().fromArray(axis)\n } else {\n this.axis = defaults(axis, new Vector3(0, 1, 0))\n }\n this.angle = defaults(angle, 0.01)\n }\n\n _tick (stats: Stats) {\n if (!this.axis || !this.angle) return\n\n this.controls.spin(\n this.axis, this.angle * stats.lastDuration / 16\n )\n }\n}\n\n/**\n * Rock animation. Rock around an axis.\n */\nexport class RockAnimation extends Animation {\n axis: Vector3\n angleStep: number\n angleEnd: number\n angleSum = 0\n direction = 1\n\n constructor (duration: number|undefined, controls: ViewerControls, ...args: any[]) {\n super(defaults(duration, Infinity), controls, ...args)\n }\n\n _init (axis: number[]|Vector3, angleStep: number, angleEnd: number) {\n if (Array.isArray(axis)) {\n this.axis = new Vector3().fromArray(axis)\n } else {\n this.axis = defaults(axis, new Vector3(0, 1, 0))\n }\n this.angleStep = defaults(angleStep, 0.01)\n this.angleEnd = defaults(angleEnd, 0.2)\n }\n\n _tick (stats: Stats) {\n if (!this.axis || !this.angleStep || !this.angleEnd) return\n\n const alpha = smoothstep(\n 0, 1, Math.abs(this.angleSum) / this.angleEnd\n )\n const angle = this.angleStep * this.direction * (1.1 - alpha)\n\n this.controls.spin(\n this.axis, angle * stats.lastDuration / 16\n )\n\n this.angleSum += this.angleStep\n\n if (this.angleSum >= this.angleEnd) {\n this.direction *= -1\n this.angleSum = -this.angleEnd\n }\n }\n}\n\n/**\n * Move animation. Move from one position to another.\n */\nexport class MoveAnimation extends Animation {\n moveFrom: Vector3\n moveTo: Vector3\n\n _init (moveFrom: number[]|Vector3, moveTo: number[]|Vector3) {\n this.moveFrom = ensureVector3(defaults(moveFrom, new Vector3()))\n this.moveTo = ensureVector3(defaults(moveTo, new Vector3()))\n }\n\n _tick (/* stats */) {\n this.controls.position.lerpVectors(\n this.moveFrom, this.moveTo, this.alpha\n ).negate()\n this.controls.changed()\n }\n}\n\n/**\n * Zoom animation. Gradually change the zoom level.\n */\nexport class ZoomAnimation extends Animation {\n zoomFrom: number\n zoomTo: number\n\n _init (zoomFrom: number, zoomTo: number) {\n this.zoomFrom = zoomFrom\n this.zoomTo = zoomTo\n }\n\n _tick () {\n this.controls.distance(lerp(this.zoomFrom, this.zoomTo, this.alpha))\n }\n}\n\n/**\n * Rotate animation. Rotate from one orientation to another.\n */\nexport class RotateAnimation extends Animation {\n rotateFrom: Quaternion\n rotateTo: Quaternion\n\n private _currentRotation = new Quaternion()\n\n _init (rotateFrom: number[]|Quaternion, rotateTo: number[]|Quaternion) {\n this.rotateFrom = ensureQuaternion(rotateFrom)\n this.rotateTo = ensureQuaternion(rotateTo)\n\n this._currentRotation = new Quaternion()\n }\n\n _tick () {\n this._currentRotation\n .copy(this.rotateFrom)\n .slerp(this.rotateTo, this.alpha)\n\n this.controls.rotate(this._currentRotation)\n }\n}\n\n/**\n * Value animation. Call callback with interpolated value.\n */\nexport class ValueAnimation extends Animation {\n valueFrom: number\n valueTo: number\n callback: Function\n\n _init (valueFrom: number, valueTo: number, callback: Function) {\n this.valueFrom = valueFrom\n this.valueTo = valueTo\n\n this.callback = callback\n }\n\n _tick (/* stats */) {\n this.callback(lerp(this.valueFrom, this.valueTo, this.alpha))\n }\n}\n\n/**\n * Timeout animation. Call callback after duration.\n */\nexport class TimeoutAnimation extends Animation {\n callback: Function\n\n _init (callback: Function) {\n this.callback = callback\n }\n\n _tick () {\n if (this.alpha === 1) this.callback()\n }\n}\n\n/**\n * Animation list.\n */\nexport class AnimationList {\n _list: Animation[]\n _resolveList: Function[] = []\n\n constructor (list: Animation[] = []) {\n this._list = list\n }\n\n /**\n * True when all animations have finished\n */\n get done () {\n return this._list.every(animation => {\n return animation.done\n })\n }\n\n /**\n * Promise-like interface\n */\n then (callback: Function) {\n let p: Promise\n\n if (this.done) {\n p = Promise.resolve()\n } else {\n p = new Promise(resolve => {\n this._resolveList.push(resolve)\n this._list.forEach(animation => {\n animation.then(() => {\n this._resolveList.forEach(callback => {\n callback()\n })\n this._resolveList.length = 0\n })\n })\n })\n }\n\n return p.then(callback as any)\n }\n}\n","/**\n * @file Animation Controls\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Quaternion, Matrix4 } from 'three'\n\nimport { ensureMatrix4 } from '../utils'\nimport Animation, {\n SpinAnimation, RockAnimation, MoveAnimation, ZoomAnimation,\n RotateAnimation, ValueAnimation, TimeoutAnimation, AnimationList\n} from '../animation/animation'\nimport Stage from '../stage/stage'\nimport Component from '../component/component'\nimport Viewer from '../viewer/viewer'\nimport Stats from '../viewer/stats'\nimport ViewerControls from './viewer-controls'\n\n/**\n * Animation controls\n */\nclass AnimationControls {\n viewer: Viewer\n controls: ViewerControls\n\n animationList: Animation[] = []\n finishedList: Animation[] = []\n\n /**\n * Create animation controls\n * @param {Stage} stage - the stage object\n */\n constructor (readonly stage: Stage) {\n this.viewer = stage.viewer\n this.controls = stage.viewerControls\n }\n\n /**\n * True when all animations are paused\n * @type {Boolean}\n */\n get paused () {\n return this.animationList.every((animation: Animation) => animation.paused)\n }\n\n /**\n * Add an animation\n */\n add (animation: Animation) {\n if (animation.duration === 0) {\n animation.tick(this.viewer.stats)\n } else {\n this.animationList.push(animation)\n }\n\n return animation\n }\n\n /**\n * Remove an animation\n */\n remove (animation: Animation) {\n const list = this.animationList\n const index = list.indexOf(animation)\n\n if (index > -1) {\n list.splice(index, 1)\n }\n }\n\n /**\n * Run all animations\n */\n run (stats: Stats) {\n const finishedList = this.finishedList\n const animationList = this.animationList\n\n const n = animationList.length\n for (let i = 0; i < n; ++i) {\n const animation = animationList[ i ]\n // tick returns true when finished\n if (animation.tick(stats)) {\n finishedList.push(animation)\n }\n }\n\n const m = finishedList.length\n if (m) {\n for (let j = 0; j < m; ++j) {\n this.remove(finishedList[ j ])\n }\n finishedList.length = 0\n }\n }\n\n /**\n * Add a spin animation\n * @param {Vector3} axis - axis to spin around\n * @param {Number} angle - amount to spin per frame, radians\n * @param {Number} duration - animation time in milliseconds\n * @return {SpinAnimation} the animation\n */\n spin (axis: Vector3|number[], angle?: number, duration?: number) {\n return this.add(\n new SpinAnimation(duration, this.controls, axis, angle)\n )\n }\n\n /**\n * Add a rock animation\n * @param {Vector3} axis - axis to rock around\n * @param {Number} angle - amount to spin per frame, radians\n * @param {Number} end - maximum extend of motion, radians\n * @param {Number} duration - animation time in milliseconds\n * @return {SpinAnimation} the animation\n */\n rock (axis: Vector3|number[], angle?: number, end?: number, duration?: number) {\n return this.add(\n new RockAnimation(duration, this.controls, axis, angle, end)\n )\n }\n\n /**\n * Add a rotate animation\n * @param {Quaternion} rotateTo - target rotation\n * @param {Number} duration - animation time in milliseconds\n * @return {RotateAnimation} the animation\n */\n rotate (rotateTo: Quaternion|number[], duration?: number) {\n const rotateFrom = this.viewer.rotationGroup.quaternion.clone()\n\n return this.add(\n new RotateAnimation(duration, this.controls, rotateFrom, rotateTo)\n )\n }\n\n /**\n * Add a move animation\n * @param {Vector3} moveTo - target position\n * @param {Number} duration - animation time in milliseconds\n * @return {MoveAnimation} the animation\n */\n move (moveTo: Vector3|number[], duration?: number) {\n const moveFrom = this.controls.position.clone().negate()\n\n return this.add(\n new MoveAnimation(duration, this.controls, moveFrom, moveTo)\n )\n }\n\n /**\n * Add a zoom animation\n * @param {Number} zoomTo - target distance\n * @param {Number} duration - animation time in milliseconds\n * @return {ZoomAnimation} the animation\n */\n zoom (zoomTo: number, duration?: number) {\n const zoomFrom = this.viewer.camera.position.z\n\n return this.add(\n new ZoomAnimation(duration, this.controls, zoomFrom, zoomTo)\n )\n }\n\n /**\n * Add a zoom and a move animation\n * @param {Vector3} moveTo - target position\n * @param {Number} zoomTo - target distance\n * @param {Number} duration - animation time in milliseconds\n * @return {Array} the animations\n */\n zoomMove (moveTo: Vector3, zoomTo: number, duration?: number) {\n return new AnimationList([\n this.move(moveTo, duration),\n this.zoom(zoomTo, duration)\n ])\n }\n\n /**\n * Add an orient animation\n * @param {OrientationMatrix|Array} orientTo - target orientation\n * @param {Number} duration - animation time in milliseconds\n * @return {Array} the animations\n */\n orient (orientTo: Matrix4|number[], duration?: number) {\n const p = new Vector3()\n const q = new Quaternion()\n const s = new Vector3()\n\n ensureMatrix4(orientTo).decompose(p, q, s)\n\n return new AnimationList([\n this.move(p.negate(), duration),\n this.rotate(q, duration),\n this.zoom(-s.x, duration)\n ])\n }\n\n /**\n * Add a value animation\n * @param {Number} valueFrom - start value\n * @param {Number} valueTo - target value\n * @param {Function} callback - called on every tick\n * @param {Number} duration - animation time in milliseconds\n * @return {ValueAnimation} the animation\n */\n value (valueFrom: number, valueTo: number, callback: Function, duration?: number) {\n return this.add(\n new ValueAnimation(duration, this.controls, valueFrom, valueTo, callback)\n )\n }\n\n /**\n * Add a timeout animation\n * @param {Function} callback - called after duration\n * @param {Number} duration - timeout in milliseconds\n * @return {TimeoutAnimation} the animation\n */\n timeout (callback: Function, duration?: number) {\n return this.add(\n new TimeoutAnimation(duration, this.controls, callback)\n )\n }\n\n /**\n * Add a component spin animation\n * @param {Component} component - object to move\n * @param {Vector3} axis - axis to spin around\n * @param {Number} angle - amount to spin per frame, radians\n * @param {Number} duration - animation time in milliseconds\n * @return {SpinAnimation} the animation\n */\n spinComponent (component: Component, axis?: Vector3|number[], angle?: number, duration?: number) {\n return this.add(\n // TODO\n new SpinAnimation(duration, component.controls as any, axis, angle)\n )\n }\n\n /**\n * Add a component rock animation\n * @param {Component} component - object to move\n * @param {Vector3} axis - axis to rock around\n * @param {Number} angle - amount to spin per frame, radians\n * @param {Number} end - maximum extend of motion, radians\n * @param {Number} duration - animation time in milliseconds\n * @return {SpinAnimation} the animation\n */\n rockComponent (component: Component, axis: Vector3|number[], angle?: number, end?: number, duration?: number) {\n return this.add(\n // TODO\n new RockAnimation(duration, component.controls as any, axis, angle, end)\n )\n }\n\n /**\n * Add a component move animation\n * @param {Component} component - object to move\n * @param {Vector3} moveTo - target position\n * @param {Number} duration - animation time in milliseconds\n * @return {MoveAnimation} the animation\n */\n moveComponent (component: Component, moveTo: Vector3|number[], duration?: number) {\n const moveFrom = component.controls.position.clone().negate()\n\n return this.add(\n // TODO\n new MoveAnimation(duration, component.controls as any, moveFrom, moveTo)\n )\n }\n\n /**\n * Pause all animations\n * @return {undefined}\n */\n pause () {\n this.animationList.forEach(animation => animation.pause())\n }\n\n /**\n * Resume all animations\n * @return {undefined}\n */\n resume () {\n this.animationList.forEach(animation => animation.resume())\n }\n\n /**\n * Toggle all animations\n * @return {undefined}\n */\n toggle () {\n if (this.paused) {\n this.resume()\n } else {\n this.pause()\n }\n }\n\n /**\n * Clear all animations\n * @return {undefined}\n */\n clear () {\n this.animationList.length = 0\n }\n\n dispose () {\n this.clear()\n }\n}\n\nexport default AnimationControls\n","/**\n * @file Queue\n * @author Alexander Rose \n * @private\n */\n\nclass Queue {\n queue: T[] = []\n pending = false\n\n constructor(readonly fn: Function, argList?: T[]) {\n this.next = this.next.bind(this)\n\n if (argList) {\n for (let i = 0, il = argList.length; i < il; ++i) {\n this.queue.push(argList[ i ])\n }\n this.next()\n }\n }\n\n private run (arg: any) {\n this.fn(arg, this.next)\n }\n\n private next () {\n const arg = this.queue.shift()\n if (arg !== undefined) {\n this.pending = true\n setTimeout(() => this.run(arg))\n } else {\n this.pending = false\n }\n }\n\n push (arg: T) {\n this.queue.push(arg)\n if (!this.pending) this.next()\n }\n\n kill () {\n this.queue.length = 0\n }\n\n length () {\n return this.queue.length\n }\n}\n\nexport default Queue\n","/**\n * @file Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { Color, Vector3, Matrix4 } from 'three'\n\nimport { Debug, Log, ColormakerRegistry, ExtensionFragDepth } from '../globals'\nimport { defaults } from '../utils'\nimport Queue from '../utils/queue'\nimport Counter from '../utils/counter'\nimport Viewer from '../viewer/viewer'\nimport { BufferParameters, BufferSide, default as Buffer } from '../buffer/buffer';\nimport { ColorData, ColormakerParameters, ColorMode } from '../color/colormaker';\nimport { GenericColor } from '../types'\n\nexport interface RepresentationParameters {\n name: string\n lazy: boolean,\n clipNear: number,\n clipRadius: number,\n clipCenter: Vector3,\n flatShaded: boolean,\n opacity: number,\n depthWrite: boolean,\n side: BufferSide,\n wireframe: boolean,\n colorData: ColorData,\n colorScheme: string,\n colorScale: string | number[],\n colorReverse: boolean,\n colorValue: GenericColor,\n colorDomain: number[],\n colorMode: ColorMode,\n colorSpace: 'sRGB' | 'linear',\n roughness: number,\n metalness: number,\n diffuse: GenericColor,\n diffuseInterior: boolean,\n useInteriorColor: boolean,\n interiorColor: GenericColor,\n interiorDarkening: number,\n disablePicking: boolean,\n matrix: Matrix4\n quality: string,\n visible: boolean,\n color: GenericColor,\n sphereDetail: number,\n radialSegments: number,\n openEnded: boolean\n disableImpostor: boolean\n [key: string]: any//boolean | number | undefined | Color | string | Vector3 | Matrix4 | number[]\n}\n/**\n * Representation parameter object.\n * @typedef {Object} RepresentationParameters - representation parameters\n * @property {Boolean} [lazy] - only build & update the representation when visible\n * otherwise defer changes until set visible again\n * @property {Integer} [clipNear] - position of camera near/front clipping plane\n * in percent of scene bounding box\n * @property {Integer} [clipRadius] - radius of clipping sphere\n * @property {Vector3} [clipCenter] - position of for spherical clipping\n * @property {Boolean} [flatShaded] - render flat shaded\n * @property {Float} [opacity] - translucency: 1 is fully opaque, 0 is fully transparent\n * @property {Boolean} [depthWrite] - depth write\n * @property {String} [side] - which triangle sides to render, \"front\" front-side,\n * \"back\" back-side, \"double\" front- and back-side\n * @property {Boolean} [wireframe] - render as wireframe\n * @property {ColorData} [colorData] - atom or bond indexed data for coloring\n * @property {String} [colorScheme] - color scheme\n * @property {String} [colorScale] - color scale, either a string for a\n * predefined scale or an array of\n * colors to be used as the scale\n * @property {Boolean} [colorReverse] - reverse color scale\n * @property {Color} [colorValue] - color value\n * @property {Integer[]} [colorDomain] - scale value range\n * @property {Integer} colorDomain.0 - min value\n * @property {Integer} colorDomain.1 - max value\n * @property {String} [colorMode] - color mode, one of rgb, hsv, hsl, hsi, lab, hcl\n * @property {Float} [roughness] - how rough the material is, between 0 and 1\n * @property {Float} [metalness] - how metallic the material is, between 0 and 1\n * @property {Color} [diffuse] - diffuse color for lighting\n * @property {Boolean} [diffuseInterior] - diffuse interior, i.e. ignore normal\n * @property {Boolean} [useInteriorColor] - use interior color\n * @property {Color} [interiorColor] - interior color\n * @property {Float} [interiorDarkening] - interior darkening: 0 no darking, 1 fully darkened\n * @property {Boolean} [disablePicking] - disable picking\n */\n\n/**\n * Representation object\n * @interface\n * @param {Object} object - the object to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {RepresentationParameters} [params] - representation parameters\n */\nclass Representation {\n parameters: any\n type: string\n viewer: Viewer\n tasks: Counter\n private queue: Queue\n bufferList: Buffer[]\n\n lazy: boolean\n lazyProps: { build: boolean, bufferParams: BufferParameters | {}, what: {}}\n protected name: string\n protected clipNear: number\n protected clipRadius: number\n protected clipCenter: Vector3\n protected flatShaded: boolean\n protected opacity: number\n protected depthWrite: boolean\n protected side: BufferSide\n protected wireframe: boolean\n protected colorData: ColorData\n protected colorScheme: string\n protected colorScale: string | string[]\n protected colorReverse: boolean\n protected colorValue: number\n protected colorDomain: number[]\n protected colorMode: ColorMode\n protected roughness: number\n protected metalness: number\n protected diffuse: GenericColor\n protected diffuseInterior?: boolean\n protected useInteriorColor?: boolean\n protected interiorColor: GenericColor\n protected interiorDarkening: number\n protected disablePicking: boolean\n protected sphereDetail: number\n protected radialSegments: number\n protected openEnded: boolean\n protected disableImpostor: boolean\n protected disposed: boolean\n\n protected matrix: Matrix4\n\n private quality: string\n visible: boolean\n\n protected manualAttach: ()=> any\n\n protected toBePrepared: boolean\n\n [key: string]: any\n\n constructor (object: any, viewer: Viewer, params: Partial) {\n // eslint-disable-next-line no-unused-vars\n // const p = params || {}\n\n this.type = ''\n\n this.parameters = {\n\n lazy: {\n type: 'boolean'\n },\n\n clipNear: {\n type: 'range', step: 1, max: 100, min: 0, buffer: true\n },\n clipRadius: {\n type: 'number', precision: 1, max: 1000, min: 0, buffer: true\n },\n clipCenter: {\n type: 'vector3', precision: 1, buffer: true\n },\n flatShaded: {\n type: 'boolean', buffer: true\n },\n opacity: {\n type: 'range', step: 0.01, max: 1, min: 0, buffer: true\n },\n depthWrite: {\n type: 'boolean', buffer: true\n },\n side: {\n type: 'select',\n buffer: true,\n options: { front: 'front', back: 'back', double: 'double' }\n },\n wireframe: {\n type: 'boolean', buffer: true\n },\n\n colorData: {\n type: 'hidden',\n update: 'color',\n },\n\n colorScheme: {\n type: 'select',\n update: 'color',\n options: {}\n },\n colorScale: {\n type: 'select',\n update: 'color',\n options: ColormakerRegistry.getScales()\n },\n colorReverse: {\n type: 'boolean', update: 'color'\n },\n colorValue: {\n type: 'color', update: 'color'\n },\n colorDomain: {\n type: 'hidden', update: 'color'\n },\n colorMode: {\n type: 'select',\n update: 'color',\n options: ColormakerRegistry.getModes()\n },\n\n roughness: {\n type: 'range', step: 0.01, max: 1, min: 0, buffer: true\n },\n metalness: {\n type: 'range', step: 0.01, max: 1, min: 0, buffer: true\n },\n diffuse: {\n type: 'color', buffer: true\n },\n\n diffuseInterior: {\n type: 'boolean', buffer: true\n },\n useInteriorColor: {\n type: 'boolean', buffer: true\n },\n interiorColor: {\n type: 'color', buffer: true\n },\n interiorDarkening: {\n type: 'range', step: 0.01, max: 1, min: 0, buffer: true\n },\n\n matrix: {\n type: 'hidden', buffer: true\n },\n\n disablePicking: {\n type: 'boolean', rebuild: true\n }\n\n }\n\n /**\n * @type {Viewer}\n */\n this.viewer = viewer\n\n /**\n * Counter that keeps track of tasks related to the creation of\n * the representation, including surface calculations.\n * @type {Counter}\n */\n this.tasks = new Counter()\n\n /**\n * @type {Queue}\n * @private\n */\n this.queue = new Queue(this.make.bind(this))\n\n /**\n * @type {Array}\n * @private\n */\n this.bufferList = []\n\n if (this.parameters.colorScheme) {\n this.parameters.colorScheme.options = ColormakerRegistry.getSchemes()\n }\n\n this.toBePrepared = false\n }\n\n init (params: Partial) {\n const p = params || {}\n\n this.clipNear = defaults(p.clipNear, 0)\n this.clipRadius = defaults(p.clipRadius, 0)\n this.clipCenter = defaults(p.clipCenter, new Vector3())\n this.flatShaded = defaults(p.flatShaded, false)\n this.side = defaults(p.side, 'double')\n this.opacity = defaults(p.opacity, 1.0)\n this.depthWrite = defaults(p.depthWrite, true)\n this.wireframe = defaults(p.wireframe, false)\n\n this.setColor(p.color, p)\n\n this.colorData = defaults(p.colorData, undefined)\n this.colorScheme = defaults(p.colorScheme, 'uniform')\n this.colorScale = defaults(p.colorScale, '')\n this.colorReverse = defaults(p.colorReverse, false)\n this.colorValue = defaults(p.colorValue, 0x909090)\n this.colorDomain = defaults(p.colorDomain, undefined)\n this.colorMode = defaults(p.colorMode, 'hcl')\n\n this.visible = defaults(p.visible, true)\n this.quality = defaults(p.quality, undefined)\n\n this.roughness = defaults(p.roughness, 0.4)\n this.metalness = defaults(p.metalness, 0.0)\n this.diffuse = defaults(p.diffuse, 0xffffff)\n\n this.diffuseInterior = defaults(p.diffuseInterior, false)\n this.useInteriorColor = defaults(p.useInteriorColor, false)\n this.interiorColor = defaults(p.interiorColor, 0x222222)\n this.interiorDarkening = defaults(p.interiorDarkening, 0)\n\n this.lazy = defaults(p.lazy, false)\n this.lazyProps = {\n build: false,\n bufferParams: {},\n what: {}\n }\n\n this.matrix = defaults(p.matrix, new Matrix4())\n\n this.disablePicking = defaults(p.disablePicking, false)\n\n // handle common parameters when applicable\n\n const tp = this.parameters\n\n if (tp.sphereDetail === true) {\n tp.sphereDetail = {\n type: 'integer', max: 3, min: 0, rebuild: 'impostor'\n }\n }\n if (tp.radialSegments === true) {\n tp.radialSegments = {\n type: 'integer', max: 25, min: 5, rebuild: 'impostor'\n }\n }\n if (tp.openEnded === true) {\n tp.openEnded = {\n type: 'boolean', rebuild: 'impostor', buffer: true\n }\n }\n if (tp.disableImpostor === true) {\n tp.disableImpostor = {\n type: 'boolean', rebuild: true\n }\n }\n\n if (p.quality === 'low') {\n if (tp.sphereDetail) this.sphereDetail = 0\n if (tp.radialSegments) this.radialSegments = 5\n } else if (p.quality === 'medium') {\n if (tp.sphereDetail) this.sphereDetail = 1\n if (tp.radialSegments) this.radialSegments = 10\n } else if (p.quality === 'high') {\n if (tp.sphereDetail) this.sphereDetail = 2\n if (tp.radialSegments) this.radialSegments = 20\n } else {\n if (tp.sphereDetail) {\n this.sphereDetail = defaults(p.sphereDetail, 1)\n }\n if (tp.radialSegments) {\n this.radialSegments = defaults(p.radialSegments, 10)\n }\n }\n\n if (tp.openEnded) {\n this.openEnded = defaults(p.openEnded, true)\n }\n\n if (tp.disableImpostor) {\n this.disableImpostor = defaults(p.disableImpostor, false)\n }\n\n }\n\n getColorParams (p?: {[k: string]: any}): { scheme: string, [k: string]: any } & ColormakerParameters {\n return Object.assign({\n\n data: this.colorData,\n scheme: this.colorScheme,\n scale: this.colorScale,\n reverse: this.colorReverse,\n value: this.colorValue,\n domain: this.colorDomain,\n mode: this.colorMode,\n colorSpace: this.colorSpace,\n\n }, p)\n }\n\n getBufferParams (p: {[k: string]: any} = {}) {\n return Object.assign({\n\n clipNear: this.clipNear,\n clipRadius: this.clipRadius,\n clipCenter: this.clipCenter,\n flatShaded: this.flatShaded,\n opacity: this.opacity,\n depthWrite: this.depthWrite,\n side: this.side,\n wireframe: this.wireframe,\n\n roughness: this.roughness,\n metalness: this.metalness,\n diffuse: this.diffuse,\n\n diffuseInterior: this.diffuseInterior,\n useInteriorColor: this.useInteriorColor,\n interiorColor: this.interiorColor,\n interiorDarkening: this.interiorDarkening,\n\n matrix: this.matrix,\n\n disablePicking: this.disablePicking\n\n }, p)\n }\n\n setColor (value: number | string | Color | undefined , p?: Partial) {\n const types = Object.keys(ColormakerRegistry.getSchemes())\n\n if (typeof value === 'string' && types.includes(value.toLowerCase())) {\n if (p) {\n p.colorScheme = value\n } else {\n this.setParameters({ colorScheme: value })\n }\n } else if (value !== undefined) {\n let val = new Color(value as string).getHex() //TODO\n if (p) {\n p.colorScheme = 'uniform'\n p.colorValue = val\n } else {\n this.setParameters({\n colorScheme: 'uniform', colorValue: val\n })\n }\n }\n\n return this\n }\n\n // TODO\n prepare (cb: ()=> void) {\n\n }\n\n create () {\n // this.bufferList.length = 0;\n }\n\n update (what?: any) {\n this.build()\n }\n\n build (updateWhat?: {[k: string]: boolean}) {\n if (this.lazy && (!this.visible || !this.opacity)) {\n this.lazyProps.build = true\n return\n }\n\n if (!this.toBePrepared) {\n this.tasks.increment()\n this.make()\n return\n }\n\n // don't let tasks accumulate\n if (this.queue.length() > 0) {\n this.tasks.change(1 - this.queue.length())\n this.queue.kill()\n } else {\n this.tasks.increment()\n }\n\n this.queue.push(updateWhat || false)\n }\n\n make (updateWhat?: boolean, callback?: () => void) {\n if (Debug) Log.time('Representation.make ' + this.type)\n\n const _make = () => {\n if (updateWhat) {\n this.update(updateWhat)\n this.viewer.requestRender()\n this.tasks.decrement()\n if (callback) callback()\n } else {\n this.clear()\n this.create()\n if (!this.manualAttach && !this.disposed) {\n if (Debug) Log.time('Representation.attach ' + this.type)\n this.attach(() => {\n if (Debug) Log.timeEnd('Representation.attach ' + this.type)\n this.tasks.decrement()\n if (callback) callback()\n })\n }\n }\n\n if (Debug) Log.timeEnd('Representation.make ' + this.type)\n }\n\n if (this.toBePrepared) {\n this.prepare(_make)\n } else {\n _make()\n }\n }\n\n attach (callback: () => void) {\n this.setVisibility(this.visible)\n\n callback()\n }\n\n /**\n * Set the visibility of the representation\n * @param {Boolean} value - visibility flag\n * @param {Boolean} [noRenderRequest] - whether or not to request a re-render from the viewer\n * @return {Representation} this object\n */\n setVisibility (value: boolean, noRenderRequest?: boolean): Representation {\n this.visible = value\n\n if (this.visible && this.opacity) {\n const lazyProps = this.lazyProps\n const bufferParams = lazyProps.bufferParams\n const what = lazyProps.what\n\n if (lazyProps.build) {\n lazyProps.build = false\n this.build()\n return this\n } else if (Object.keys(bufferParams).length || Object.keys(what).length) {\n lazyProps.bufferParams = {}\n lazyProps.what = {}\n this.updateParameters(bufferParams, what)\n }\n }\n\n this.bufferList.forEach(function (buffer) {\n buffer.setVisibility(value)\n })\n\n if (!noRenderRequest) this.viewer.requestRender()\n\n return this\n }\n\n /**\n * Set the visibility of the representation\n * @param {RepresentationParameters} params - parameters object\n * @param {Object} [what] - buffer data attributes to be updated,\n * note that this needs to be implemented in the\n * derived classes. Generally it allows more\n * fine-grained control over updating than\n * forcing a rebuild.\n * @param {Boolean} what.position - update position data\n * @param {Boolean} what.color - update color data\n * @param {Boolean} [rebuild] - whether or not to rebuild the representation\n * @return {Representation} this object\n */\n setParameters (params: Partial, what:{[propName: string]: any} = {}, rebuild = false) {\n const p = params || {}\n const tp = this.parameters\n const bufferParams: BufferParameters = {}\n\n if (!this.opacity && p.opacity !== undefined) {\n if (this.lazyProps.build) {\n this.lazyProps.build = false\n rebuild = true\n } else {\n Object.assign(bufferParams, this.lazyProps.bufferParams)\n Object.assign(what, this.lazyProps.what)\n this.lazyProps.bufferParams = {}\n this.lazyProps.what = {}\n }\n }\n\n this.setColor(p.color, p)\n\n for (let name in p) {\n if (p[ name ] === undefined) continue\n if (tp[ name ] == undefined ) continue // Skip nulls as well as undefined\n\n if (tp[ name ].int) p[ name ] = parseInt(p[ name ] as string)\n if (tp[ name ].float) p[ name ] = parseFloat(p[ name ] as string)\n\n // no value change\n if (p[ name ] === this[ name ] && (\n !p[ name ].equals || p[ name ].equals(this[ name ])\n )) continue\n\n if (this[ name ] && this[ name ].copy && p[ name ].copy) {\n this[ name ].copy(p[ name ])\n } else if (this[ name ] && this[ name ].set) {\n this[ name ].set(p[ name ])\n } else {\n this[ name ] = p[ name ]\n }\n\n // buffer param\n if (tp[ name ].buffer) {\n if (tp[ name ].buffer === true) {\n (bufferParams[ name as keyof BufferParameters ] as any) = p[ name ]\n } else {\n let key: (keyof BufferParameters) = tp[ name ].buffer;\n (bufferParams[ key ] as any) = p[ name ]\n }\n }\n\n // mark for update\n if (tp[ name ].update) {\n what[ tp[ name ].update ] = true\n }\n\n // mark for rebuild\n if (tp[ name ].rebuild &&\n !(tp[ name ].rebuild === 'impostor' &&\n ExtensionFragDepth && !this.disableImpostor)\n ) {\n rebuild = true\n }\n }\n\n //\n\n if (rebuild) {\n this.build()\n } else {\n this.updateParameters(bufferParams, what)\n }\n\n return this\n }\n\n updateParameters (bufferParams: BufferParameters | {} = {}, what?: any) {\n if (this.lazy && (!this.visible || !this.opacity) && bufferParams.hasOwnProperty('opacity') === false) {\n Object.assign(this.lazyProps.bufferParams, bufferParams)\n Object.assign(this.lazyProps.what, what)\n return\n }\n\n this.bufferList.forEach(function (buffer) {\n buffer.setParameters(bufferParams)\n })\n\n if (Object.keys(what).length) {\n this.update(what) // update buffer attribute\n }\n\n this.viewer.requestRender()\n }\n\n getParameters () {\n const params: Partial = {\n lazy: this.lazy,\n visible: this.visible,\n quality: this.quality\n }\n\n Object.keys(this.parameters).forEach(name => {\n if (this.parameters[ name ] !== null) {\n params[ name ] = this[ name ]\n }\n })\n\n return params\n }\n\n clear () {\n this.bufferList.forEach(buffer => {\n this.viewer.remove(buffer)\n buffer.dispose()\n })\n this.bufferList.length = 0\n\n this.viewer.requestRender()\n }\n\n dispose () {\n this.disposed = true\n this.queue.kill()\n this.tasks.dispose()\n this.clear()\n }\n}\n\nexport default Representation\n","/**\n * @file Worker\n * @author Alexander Rose \n * @private\n */\n\nimport { Log, Debug, WorkerRegistry } from '../globals'\n\nexport default class _Worker {\n\n pending = 0\n postCount = 0\n onmessageDict: { [k: number]: Function|undefined } = {}\n onerrorDict: { [k: number]: Function|undefined } = {}\n\n name: string\n blobUrl: string\n worker: Worker\n\n constructor (name: string) {\n\n this.name = name\n this.blobUrl = window.URL.createObjectURL(WorkerRegistry.get(name))\n this.worker = new Worker(this.blobUrl)\n\n WorkerRegistry.activeWorkerCount += 1\n\n this.worker.onmessage = (event: any) => {\n this.pending -= 1\n const postId = event.data.__postId\n\n if (Debug) Log.timeEnd('Worker.postMessage ' + name + ' #' + postId)\n\n const onmessage = this.onmessageDict[ postId ]\n if (onmessage) {\n onmessage.call(this.worker, event)\n } else {\n // Log.debug('No onmessage', postId, name)\n }\n\n delete this.onmessageDict[ postId ]\n delete this.onerrorDict[ postId ]\n }\n\n this.worker.onerror = (event: any) => {\n this.pending -= 1\n if (event.data) {\n const postId = event.data.__postId\n\n const onerror = this.onerrorDict[ postId ]\n if (onerror) {\n onerror.call(this.worker, event)\n } else {\n Log.error('Worker.onerror', postId, name, event)\n }\n\n delete this.onmessageDict[ postId ]\n delete this.onerrorDict[ postId ]\n } else {\n Log.error('Worker.onerror', name, event)\n }\n }\n }\n\n post (aMessage: any = {}, transferList?: any, onmessage?: Function, onerror?: Function) {\n this.onmessageDict[ this.postCount ] = onmessage\n this.onerrorDict[ this.postCount ] = onerror\n\n aMessage.__name = this.name\n aMessage.__postId = this.postCount\n aMessage.__debug = Debug\n\n if (Debug) Log.time(`Worker.postMessage ${this.name} #${this.postCount}`)\n\n try {\n this.worker.postMessage(aMessage, transferList)\n } catch (error) {\n Log.error('worker.post:', error)\n this.worker.postMessage(aMessage)\n }\n\n this.pending += 1\n this.postCount += 1\n\n return this\n }\n\n terminate () {\n if (this.worker) {\n this.worker.terminate()\n window.URL.revokeObjectURL(this.blobUrl)\n WorkerRegistry.activeWorkerCount -= 1\n } else {\n Log.log('no worker to terminate')\n }\n }\n}\n","/**\n * @file Worker Pool\n * @author Alexander Rose \n * @private\n */\n\nimport Worker from './worker'\n\nclass WorkerPool {\n maxCount: number\n pool: Worker[] = []\n count = 0\n name: string\n\n constructor (name: string, maxCount = 2) {\n this.maxCount = Math.min(8, maxCount)\n this.name = name\n }\n\n post (aMessage: any = {}, transferList?: any, onmessage?: Function, onerror?: Function) {\n const worker = this.getNextWorker()\n if (worker) {\n worker.post(aMessage, transferList, onmessage, onerror)\n } else {\n console.error('unable to get worker from pool')\n }\n\n return this\n }\n\n terminate () {\n this.pool.forEach(function (worker) {\n worker.terminate()\n })\n }\n\n getNextWorker () {\n let nextWorker\n let minPending = Infinity\n\n for (let i = 0; i < this.maxCount; ++i) {\n if (i >= this.count) {\n nextWorker = new Worker(this.name)\n this.pool.push(nextWorker)\n this.count += 1\n break\n }\n\n const worker = this.pool[ i ]\n\n if (worker.pending === 0) {\n nextWorker = worker\n break\n } else if (worker.pending < minPending) {\n minPending = worker.pending\n nextWorker = worker\n }\n }\n\n return nextWorker\n }\n}\n\nWorkerPool.prototype.constructor = WorkerPool\n\nexport default WorkerPool\n","/**\n * @file Vector Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { NumberArray } from '../types'\nimport { EPS } from './math-constants'\n\n/**\n * Calculate the two intersection points\n * Converted to JavaScript from\n * {@link http://paulbourke.net/geometry/pointlineplane/lineline.c}\n */\nexport function lineLineIntersect (p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3) {\n const p13 = new Vector3()\n const p43 = new Vector3()\n const p21 = new Vector3()\n let d1343, d4321, d1321, d4343, d2121\n let denom, numer\n\n p13.x = p1.x - p3.x\n p13.y = p1.y - p3.y\n p13.z = p1.z - p3.z\n p43.x = p4.x - p3.x\n p43.y = p4.y - p3.y\n p43.z = p4.z - p3.z\n if (Math.abs(p43.x) < EPS && Math.abs(p43.y) < EPS && Math.abs(p43.z) < EPS) { return null }\n\n p21.x = p2.x - p1.x\n p21.y = p2.y - p1.y\n p21.z = p2.z - p1.z\n if (Math.abs(p21.x) < EPS && Math.abs(p21.y) < EPS && Math.abs(p21.z) < EPS) { return null }\n\n d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z\n d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z\n d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z\n d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z\n d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z\n\n denom = d2121 * d4343 - d4321 * d4321\n if (Math.abs(denom) < EPS) { return null }\n numer = d1343 * d4321 - d1321 * d4343\n\n const mua = numer / denom\n const mub = (d1343 + d4321 * mua) / d4343\n\n const pa = new Vector3(\n p1.x + mua * p21.x,\n p1.y + mua * p21.y,\n p1.z + mua * p21.z\n )\n const pb = new Vector3(\n p3.x + mub * p43.x,\n p3.y + mub * p43.y,\n p3.z + mub * p43.z\n )\n\n return [ pa, pb ]\n}\n\nexport function calculateMeanVector3 (array: NumberArray) {\n const n = array.length\n const m = n / 3\n\n let x = 0\n let y = 0\n let z = 0\n\n for (let i = 0; i < n; i += 3) {\n x += array[ i + 0 ]\n y += array[ i + 1 ]\n z += array[ i + 2 ]\n }\n\n return new Vector3(x / m, y / m, z / m)\n}\n\nexport function isPointOnSegment (p: Vector3, l1: Vector3, l2: Vector3) {\n const len = l1.distanceTo(l2)\n\n return p.distanceTo(l1) <= len && p.distanceTo(l2) <= len\n}\n\nexport function projectPointOnVector (point: Vector3, vector: Vector3, origin?: Vector3) {\n if (origin) {\n point.sub(origin).projectOnVector(vector).add(origin)\n } else {\n point.projectOnVector(vector)\n }\n\n return point\n}\n\nexport function computeBoundingBox (array: NumberArray) {\n let minX = +Infinity\n let minY = +Infinity\n let minZ = +Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n let maxZ = -Infinity\n for (let i = 0, l = array.length; i < l; i += 3) {\n const x = array[ i ]\n const y = array[ i + 1 ]\n const z = array[ i + 2 ]\n if (x < minX) minX = x\n if (y < minY) minY = y\n if (z < minZ) minZ = z\n if (x > maxX) maxX = x\n if (y > maxY) maxY = y\n if (z > maxZ) maxZ = z\n }\n return [\n v3new([ minX, minY, minZ ]),\n v3new([ maxX, maxY, maxZ ])\n ]\n}\n(computeBoundingBox as any).__deps = [ v3new ]\n\nexport function applyMatrix4toVector3array (m: Float32Array, a: Float32Array) {\n for (let i = 0, il = a.length; i < il; i += 3) {\n const x = a[ i ]\n const y = a[ i + 1 ]\n const z = a[ i + 2 ]\n a[ i ] = m[ 0 ] * x + m[ 4 ] * y + m[ 8 ] * z + m[ 12 ]\n a[ i + 1 ] = m[ 1 ] * x + m[ 5 ] * y + m[ 9 ] * z + m[ 13 ]\n a[ i + 2 ] = m[ 2 ] * x + m[ 6 ] * y + m[ 10 ] * z + m[ 14 ]\n }\n}\n\nexport function applyMatrix3toVector3array (m: Float32Array, a: Float32Array) {\n for (let i = 0, il = a.length; i < il; i += 3) {\n const x = a[ i ]\n const y = a[ i + 1 ]\n const z = a[ i + 2 ]\n a[ i ] = m[ 0 ] * x + m[ 3 ] * y + m[ 6 ] * z\n a[ i + 1 ] = m[ 1 ] * x + m[ 4 ] * y + m[ 7 ] * z\n a[ i + 2 ] = m[ 2 ] * x + m[ 5 ] * y + m[ 8 ] * z\n }\n}\n\nexport function normalizeVector3array (a: Float32Array) {\n for (let i = 0, il = a.length; i < il; i += 3) {\n const x = a[ i ]\n const y = a[ i + 1 ]\n const z = a[ i + 2 ]\n const len2 = x * x + y * y + z * z\n if (len2 > 0) { // avoid divide by zero\n const s = 1 / Math.sqrt(len2)\n a[ i ] = x * s\n a[ i + 1 ] = y * s\n a[ i + 2 ] = z * s\n }\n // else leave as all zeros\n }\n}\n\nexport function v3new (array?: NumberArray) {\n return new Float32Array(array as any || 3) // TODO\n}\n\nexport function v3cross (out: Float32Array, a: Float32Array, b: Float32Array) {\n const ax = a[0]\n const ay = a[1]\n const az = a[2]\n const bx = b[0]\n const by = b[1]\n const bz = b[2]\n out[0] = ay * bz - az * by\n out[1] = az * bx - ax * bz\n out[2] = ax * by - ay * bx\n}\n\nexport function v3dot (a: Float32Array, b: Float32Array) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n}\n\nexport function v3sub (out: Float32Array, a: Float32Array, b: Float32Array) {\n out[0] = a[0] - b[0]\n out[1] = a[1] - b[1]\n out[2] = a[2] - b[2]\n}\n\nexport function v3add (out: Float32Array, a: Float32Array, b: Float32Array) {\n out[0] = a[0] + b[0]\n out[1] = a[1] + b[1]\n out[2] = a[2] + b[2]\n}\n\nexport function v3fromArray (out: Float32Array, array: Float32Array, offset = 0) {\n out[0] = array[offset]\n out[1] = array[offset + 1]\n out[2] = array[offset + 2]\n}\n\nexport function v3toArray (input: Float32Array, array: Float32Array, offset = 0) {\n array[offset] = input[0]\n array[offset + 1] = input[1]\n array[offset + 2] = input[2]\n}\n\nexport function v3forEach (array: Float32Array, fn: (i: Float32Array, j: Float32Array, k: Float32Array) => void, b: Float32Array) {\n const a = v3new()\n for (let i = 0, n = array.length; i < n; i += 3) {\n v3fromArray(a, array, i)\n fn(a, a, b)\n v3toArray(a, array, i)\n }\n}\n(v3forEach as any).__deps = [ v3new, v3fromArray, v3toArray ]\n\nexport function v3length2 (a: Float32Array) {\n return a[0] * a[0] + a[1] * a[1] + a[2] * a[2]\n}\n\nexport function v3length (a: Float32Array) {\n return Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2])\n}\n\nexport function v3divide (out: Float32Array, a: Float32Array, b: Float32Array) {\n out[0] = a[0] / b[0]\n out[1] = a[1] / b[1]\n out[2] = a[2] / b[2]\n}\n\nexport function v3multiply (out: Float32Array, a: Float32Array, b: Float32Array) {\n out[0] = a[0] * b[0]\n out[1] = a[1] * b[1]\n out[2] = a[2] * b[2]\n}\n\nexport function v3divideScalar (out: Float32Array, a: Float32Array, s: number) {\n v3multiplyScalar(out, a, 1 / s)\n}\n(v3divideScalar as any).__deps = [ v3multiplyScalar ]\n\nexport function v3multiplyScalar (out: Float32Array, a: Float32Array, s: number) {\n out[0] = a[0] * s\n out[1] = a[1] * s\n out[2] = a[2] * s\n}\n\nexport function v3normalize (out: Float32Array, a: Float32Array) {\n const length2 = v3length2(a)\n if (length2 == 0) {\n out[0] = a[0]\n out[1] = a[1]\n out[2] = a[2]\n } else {\n v3multiplyScalar(out, a, 1 / Math.sqrt(length2))\n }\n}\n(v3normalize as any).__deps = [ v3multiplyScalar, v3length2 ]\n\nexport function v3subScalar (out: Float32Array, a: Float32Array, s: number) {\n out[0] = a[0] - s\n out[1] = a[1] - s\n out[2] = a[2] - s\n}\n\nexport function v3addScalar (out: Float32Array, a: Float32Array, s: number) {\n out[0] = a[0] + s\n out[1] = a[1] + s\n out[2] = a[2] + s\n}\n\nexport function v3floor (out: Float32Array, a: Float32Array) {\n out[0] = Math.floor(a[0])\n out[1] = Math.floor(a[1])\n out[2] = Math.floor(a[2])\n}\n\nexport function v3ceil (out: Float32Array, a: Float32Array) {\n out[0] = Math.ceil(a[0])\n out[1] = Math.ceil(a[1])\n out[2] = Math.ceil(a[2])\n}\n\nexport function v3round (out: Float32Array, a: Float32Array) {\n out[0] = Math.round(a[0])\n out[1] = Math.round(a[1])\n out[2] = Math.round(a[2])\n}\n\nexport function v3negate (out: Float32Array, a: Float32Array) {\n out[0] = -a[0]\n out[1] = -a[1]\n out[2] = -a[2]\n}\n\nexport function v3angle (a: Float32Array, b: Float32Array) {\n const ax = a[0]\n const ay = a[1]\n const az = a[2]\n const bx = b[0]\n const by = b[1]\n const bz = b[2]\n const cx = ay * bz - az * by\n const cy = az * bx - ax * bz\n const cz = ax * by - ay * bx\n const s = Math.sqrt(cx * cx + cy * cy + cz * cz)\n const c = ax * bx + ay * by + az * bz\n return Math.atan2(s, c)\n}\n","/**\n * @file Dash\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { CylinderBufferData } from '../buffer/cylinder-buffer'\nimport { WideLineBufferData } from '../buffer/wideline-buffer'\nimport {\n calculateDirectionArray, calculateCenterArray,\n replicateArrayEntries, replicateArray3Entries\n} from '../math/array-utils'\n\nexport function getFixedCountDashData (data: T, segmentCount: number = 9) {\n\n const s = Math.floor(segmentCount / 2)\n const n = data.position1.length / 3\n const sn = s * n\n const sn3 = sn * 3\n const step = 1 / segmentCount\n\n const direction = calculateDirectionArray(data.position1, data.position2)\n const position1 = new Float32Array(sn3)\n const position2 = new Float32Array(sn3)\n\n const v = new Vector3()\n\n for (let i = 0; i < n; ++i) {\n const i3 = i * 3\n v.set(direction[ i3 ], direction[ i3 + 1 ], direction[ i3 + 2 ])\n\n const x = data.position1[ i3 ]\n const y = data.position1[ i3 + 1 ]\n const z = data.position1[ i3 + 2 ]\n\n for (let j = 0; j < s; ++j) {\n const j3 = s * i3 + j * 3\n\n const f1 = step * (j * 2 + 1)\n const f2 = step * (j * 2 + 2)\n\n position1[ j3 ] = x + v.x * f1\n position1[ j3 + 1 ] = y + v.y * f1\n position1[ j3 + 2 ] = z + v.z * f1\n\n position2[ j3 ] = x + v.x * f2\n position2[ j3 + 1 ] = y + v.y * f2\n position2[ j3 + 2 ] = z + v.z * f2\n }\n }\n\n const position = calculateCenterArray(position1, position2) as Float32Array\n const color = replicateArray3Entries(data.color!, s) // TODO\n const color2 = color\n\n const d: any = { position, position1, position2, color, color2 }\n\n if ((data as any).radius) { // TODO\n d.radius = replicateArrayEntries((data as any).radius, s) // TODO\n }\n\n if (data.picking && data.picking.array) {\n data.picking.array = replicateArrayEntries(data.picking.array, s)\n d.picking = data.picking\n }\n if (data.primitiveId) {\n d.primitiveId = replicateArrayEntries(data.primitiveId, s)\n }\n\n return d as T\n}\n\nexport function getFixedLengthDashData (data: T, segmentLength: number = 0.1) {\n\n const direction = calculateDirectionArray(data.position1, data.position2)\n const pos1: number[] = []\n const pos2: number[] = []\n const col: number[] = []\n const rad: number[]|undefined = (data as any).radius ? [] : undefined\n const pick: number[]|undefined = (data as any).picking ? [] : undefined\n const id: number[]|undefined = (data as any).primitiveId ? [] : undefined\n\n const v = new Vector3()\n const n = data.position1.length / 3\n\n let k = 0\n\n for (let i = 0; i < n; ++i) {\n const i3 = i * 3\n v.set(direction[ i3 ], direction[ i3 + 1 ], direction[ i3 + 2 ])\n\n const vl = v.length()\n const segmentCount = vl / segmentLength\n const s = Math.floor(segmentCount / 2)\n const step = 1 / segmentCount\n\n const x = data.position1[ i3 ]\n const y = data.position1[ i3 + 1 ]\n const z = data.position1[ i3 + 2 ]\n\n for (let j = 0; j < s; ++j) {\n const j3 = k * 3 + j * 3\n\n const f1 = step * (j * 2 + 1)\n const f2 = step * (j * 2 + 2)\n\n pos1[ j3 ] = x + v.x * f1\n pos1[ j3 + 1 ] = y + v.y * f1\n pos1[ j3 + 2 ] = z + v.z * f1\n\n pos2[ j3 ] = x + v.x * f2\n pos2[ j3 + 1 ] = y + v.y * f2\n pos2[ j3 + 2 ] = z + v.z * f2\n\n if (data.color) {\n col[ j3 ] = data.color[ i3 ]\n col[ j3 + 1 ] = data.color[ i3 + 1 ]\n col[ j3 + 2 ] = data.color[ i3 + 2 ]\n }\n\n if (rad) rad[ k + j ] = (data as any).radius[ i ]\n if (pick) {\n if ((data as any).picking.array) {\n pick[ k + j ] = (data as any).picking.array[ i ]\n } else {\n pick[ k + j ] = i\n }\n }\n if (id) id[ k + j ] = (data as any).primitiveId[ i ]\n }\n\n k += s\n }\n\n const position1 = new Float32Array(pos1)\n const position2 = new Float32Array(pos2)\n const position = calculateCenterArray(position1, position2) as Float32Array\n const color = new Float32Array(col)\n const color2 = color\n\n const d: any = { position, position1, position2, color, color2 }\n\n if (rad) d.radius = new Float32Array(rad)\n if (pick && data.picking) {\n data.picking.array = new Float32Array(pick)\n d.picking = data.picking\n }\n if (id) d.primitiveId = new Float32Array(id)\n\n return d as T\n}\n\nexport function getFixedLengthWrappedDashData (data: T, segmentLength: number = 0.1) {\n\n const direction = calculateDirectionArray(data.position1, data.position2)\n const pos1: number[] = []\n const pos2: number[] = []\n const col: number[] = []\n const rad: number[]|undefined = (data as any).radius ? [] : undefined\n const pick: number[]|undefined = (data as any).picking ? [] : undefined\n const id: number[]|undefined = (data as any).primitiveId ? [] : undefined\n\n const v = new Vector3()\n const n = data.position1.length / 3\n\n let remaining = segmentLength\n let drawing = true\n\n let k = 0\n let k3 = 0\n let kprev = 0\n\n for (let i = 0; i < n; ++i) {\n const i3 = i * 3\n const x = data.position1[ i3 ]\n const y = data.position1[ i3 + 1 ]\n const z = data.position1[ i3 + 2 ]\n\n v.set(direction[ i3 ], direction[ i3 + 1 ], direction[ i3 + 2 ])\n const vl = v.length()\n\n if (drawing) {\n pos1[ k3 ] = x\n pos1[ k3 + 1 ] = y\n pos1[ k3 + 2 ] = z\n }\n\n let dist = remaining\n const inv = 1 / vl\n while (dist < vl) {\n const a = drawing ? pos2 : pos1\n a[ k3 ] = x + v.x * dist * inv\n a[ k3 + 1 ] = y + v.y * dist * inv\n a[ k3 + 2 ] = z + v.z * dist * inv\n if (drawing) {\n k++\n k3 = k * 3\n }\n drawing = !drawing\n remaining = segmentLength\n dist += segmentLength\n }\n\n if (drawing) {\n pos2[ k3 ] = data.position2[ i3 ]\n pos2[ k3 + 1 ] = data.position2[ i3 + 1 ]\n pos2[ k3 + 2 ] = data.position2[ i3 + 2 ]\n k++\n k3 = k * 3\n }\n\n remaining = dist - vl\n\n for (let j = kprev; j < k ; j++){\n if (data.color) {\n const j3 = j * 3\n col[ j3 ] = data.color[ i3 ]\n col[ j3 + 1 ] = data.color[ i3 + 1 ]\n col[ j3 + 2 ] = data.color[ i3 + 2 ]\n }\n\n if (rad) rad[ j ] = (data as any).radius[ i ]\n if (pick) {\n if ((data as any).picking.array) {\n pick[ j ] = (data as any).picking.array[ i ]\n } else {\n pick[ j ] = i\n }\n }\n if (id) id[ j ] = (data as any).primitiveId[ i ]\n }\n\n kprev = k\n\n }\n\n if (!drawing && n > 0) {\n const k3 = k * 3\n pos2[ k3 ] = data.position2[ 3 * n - 3 ]\n pos2[ k3 + 1 ] = data.position2[ 3 * n - 2 ]\n pos2[ k3 + 1 ] = data.position2[ 3 * n - 1 ]\n }\n\n const position1 = new Float32Array(pos1)\n const position2 = new Float32Array(pos2)\n const position = calculateCenterArray(position1, position2) as Float32Array\n const color = new Float32Array(col)\n const color2 = color\n\n const d: any = { position, position1, position2, color, color2 }\n\n if (rad) d.radius = new Float32Array(rad)\n if (pick && data.picking) {\n data.picking.array = new Float32Array(pick)\n d.picking = data.picking\n }\n if (id) d.primitiveId = new Float32Array(id)\n\n return d as T\n}\n","/**\n * @file Primitive\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Color, Box3 } from 'three'\n\nimport { BufferRegistry, PickerRegistry } from '../globals'\nimport Shape from './shape'\nimport { getFixedLengthDashData } from './dash'\n\nfunction addElement (elm: any, array: any[]) {\n if (elm.toArray !== undefined) {\n elm = elm.toArray()\n } else if (elm.x !== undefined) {\n elm = [ elm.x, elm.y, elm.z ]\n } else if (elm.r !== undefined) {\n elm = [ elm.r, elm.g, elm.b ]\n }\n array.push.apply(array, elm)\n}\n\nconst tmpVec = new Vector3()\n\nexport type PrimitiveFields = { [k: string]: string }\n\n/**\n * Base class for geometry primitives\n * @interface\n */\nexport abstract class Primitive {\n static type = ''\n static fields: PrimitiveFields = {}\n\n static get Picker () { return PickerRegistry.get(this.type) }\n static get Buffer () { return BufferRegistry.get(this.type) }\n\n static getShapeKey (name: string) {\n return this.type + name[0].toUpperCase() + name.substr(1)\n }\n\n static expandBoundingBox (box: Box3, data: any) {}\n\n static valueToShape (shape: Shape, name: string, value: any) {\n const data = shape._primitiveData[this.getShapeKey(name)]\n const type = this.fields[name]\n\n switch (type) {\n case 'v3':\n case 'c':\n addElement(value, data)\n break\n default:\n data.push(value)\n }\n }\n\n static objectToShape (shape: Shape, data: any) {\n Object.keys(this.fields).forEach(name => {\n this.valueToShape(shape, name, data[name])\n })\n this.valueToShape(shape, 'name', data.name)\n this.expandBoundingBox(shape.boundingBox, data)\n }\n\n static valueFromShape (shape: Shape, pid: number, name: string) {\n const data = shape._primitiveData[this.getShapeKey(name)]\n const type = this.fields[name]\n\n switch (type) {\n case 'v3':\n return new Vector3().fromArray(data, 3 * pid)\n case 'c':\n return new Color().fromArray(data, 3 * pid)\n default:\n return data[pid]\n }\n }\n\n static objectFromShape (shape: Shape, pid: number) {\n let name = this.valueFromShape(shape, pid, 'name')\n if (name === undefined) {\n name = `${this.type}: ${pid} (${shape.name})`\n }\n const o: any = { shape, name }\n\n Object.keys(this.fields).forEach(name => {\n o[name] = this.valueFromShape(shape, pid, name)\n })\n\n return o\n }\n\n static arrayFromShape (shape: Shape, name: string) {\n const data = shape._primitiveData[this.getShapeKey(name)]\n const type = this.fields[name]\n\n switch (type) {\n case 's':\n return data\n default:\n return new Float32Array(data)\n }\n }\n\n static dataFromShape (shape: Shape) {\n const data: any = {}\n\n if (this.Picker) {\n data.picking = new this.Picker(shape)\n }\n\n Object.keys(this.fields).forEach(name => {\n data[name] = this.arrayFromShape(shape, name)\n })\n\n return data\n }\n\n static bufferFromShape (shape: Shape, params: any) {\n return new this.Buffer(this.dataFromShape(shape), params)\n }\n}\n\n/**\n * Sphere geometry primitive\n */\nexport class SpherePrimitive extends Primitive {\n static type = 'sphere'\n\n static fields = {\n position: 'v3',\n color: 'c',\n radius: 'f'\n }\n\n static positionFromShape (shape: Shape, pid: number) {\n return this.valueFromShape(shape, pid, 'position')\n }\n\n static expandBoundingBox (box: Box3, data: any) {\n box.expandByPoint(tmpVec.fromArray(data.position))\n }\n}\n\n/**\n * Box geometry primitive\n */\nexport class BoxPrimitive extends Primitive {\n static type = 'box'\n\n static fields = {\n position: 'v3',\n color: 'c',\n size: 'f',\n heightAxis: 'v3',\n depthAxis: 'v3'\n }\n\n static positionFromShape (shape: Shape, pid: number) {\n return this.valueFromShape(shape, pid, 'position')\n }\n\n static expandBoundingBox (box: Box3, data: any) {\n box.expandByPoint(tmpVec.fromArray(data.position))\n }\n}\n\n/**\n * Octahedron geometry primitive\n */\nexport class OctahedronPrimitive extends BoxPrimitive {\n static type = 'octahedron'\n}\n\n/**\n * Tetrahedron geometry primitive\n */\nexport class TetrahedronPrimitive extends BoxPrimitive {\n static type = 'tetrahedron'\n}\n\n/**\n * Cylinder geometry primitive\n */\nexport class CylinderPrimitive extends Primitive {\n static type = 'cylinder'\n\n static fields = {\n position1: 'v3',\n position2: 'v3',\n color: 'c',\n radius: 'f'\n }\n\n static positionFromShape (shape: Shape, pid: number) {\n const p1 = this.valueFromShape(shape, pid, 'position1')\n const p2 = this.valueFromShape(shape, pid, 'position2')\n return p1.add(p2).multiplyScalar(0.5)\n }\n\n static expandBoundingBox (box: Box3, data: any) {\n box.expandByPoint(tmpVec.fromArray(data.position1))\n box.expandByPoint(tmpVec.fromArray(data.position2))\n }\n\n static bufferFromShape (shape: Shape, params: any = {}) {\n let data = this.dataFromShape(shape)\n if (this.type === 'cylinder' && params.dashedCylinder) {\n data = getFixedLengthDashData(data)\n }\n return new this.Buffer(data, params)\n }\n}\n\n/**\n * Arrow geometry primitive\n */\nexport class ArrowPrimitive extends CylinderPrimitive {\n static type = 'arrow'\n}\n\n/**\n * Cone geometry primitive\n */\nexport class ConePrimitive extends CylinderPrimitive {\n static type = 'cone'\n}\n\n/**\n * Ellipsoid geometry primitive\n */\nexport class EllipsoidPrimitive extends SpherePrimitive {\n static type = 'ellipsoid'\n\n static fields = {\n position: 'v3',\n color: 'c',\n radius: 'f',\n majorAxis: 'v3',\n minorAxis: 'v3'\n }\n}\n\n/**\n * Torus geometry primitive\n */\nexport class TorusPrimitive extends EllipsoidPrimitive {\n static type = 'torus'\n}\n\n/**\n * Text geometry primitive\n */\nexport class TextPrimitive extends Primitive {\n static type = 'text'\n\n static fields = {\n position: 'v3',\n color: 'c',\n size: 'f',\n text: 's'\n }\n\n static positionFromShape (shape: Shape, pid: number) {\n return this.valueFromShape(shape, pid, 'position')\n }\n\n static expandBoundingBox (box: Box3, data: any) {\n box.expandByPoint(tmpVec.fromArray(data.position))\n }\n}\n\n/**\n * Point primitive\n */\nexport class PointPrimitive extends Primitive {\n static type = 'point'\n\n static fields = {\n position: 'v3',\n color: 'c',\n }\n\n static positionFromShape (shape: Shape, pid: number) {\n return this.valueFromShape(shape, pid, 'position')\n }\n\n static expandBoundingBox (box: Box3, data: any) {\n box.expandByPoint(tmpVec.fromArray(data.position))\n }\n}\n\n/**\n * Wideline geometry primitive\n */\nexport class WidelinePrimitive extends Primitive {\n static type = 'wideline'\n\n static fields = {\n position1: 'v3',\n position2: 'v3',\n color: 'c'\n }\n\n static positionFromShape (shape: Shape, pid: number) {\n const p1 = this.valueFromShape(shape, pid, 'position1')\n const p2 = this.valueFromShape(shape, pid, 'position2')\n return p1.add(p2).multiplyScalar(0.5)\n }\n\n static expandBoundingBox (box: Box3, data: any) {\n box.expandByPoint(tmpVec.fromArray(data.position1))\n box.expandByPoint(tmpVec.fromArray(data.position2))\n }\n}\n","/**\n * @file Spatial Hash\n * @author Alexander Rose \n * @private\n */\n\nimport { Box3 } from 'three'\n\nexport type Positions = {\n x: ArrayLike,\n y: ArrayLike,\n z: ArrayLike,\n count?:number\n}\n\nfunction createBoundingBox(positions: Positions) {\n const { x, y, z } = positions\n const boundingBox = new Box3()\n const count = x.length\n const { min, max } = boundingBox\n\n for (let i = 0; i < count; i++) {\n min.x = Math.min(x[i], min.x)\n min.y = Math.min(y[i], min.y)\n min.z = Math.min(z[i], min.z)\n max.x = Math.max(x[i], max.x)\n max.y = Math.max(y[i], max.y)\n max.z = Math.max(z[i], max.z)\n }\n\n return boundingBox\n}\n\nexport default class SpatialHash {\n exp = 3\n\n minX: number\n minY: number\n minZ: number\n\n boundX: number\n boundY: number\n boundZ: number\n\n grid: Uint32Array\n bucketCount: Uint16Array\n bucketOffset: Uint32Array\n bucketArray: Int32Array\n\n xArray: ArrayLike\n yArray: ArrayLike\n zArray: ArrayLike\n\n constructor(positions: Positions, boundingBox?: Box3) {\n const bb = boundingBox || createBoundingBox(positions)\n this.minX = bb.min.x\n this.minY = bb.min.y\n this.minZ = bb.min.z\n this.boundX = ((bb.max.x - this.minX) >> this.exp) + 1\n this.boundY = ((bb.max.y - this.minY) >> this.exp) + 1\n this.boundZ = ((bb.max.z - this.minZ) >> this.exp) + 1\n\n const n = this.boundX * this.boundY * this.boundZ\n const an = (positions.count !== undefined) ? positions.count : positions.x.length\n\n const xArray = positions.x\n const yArray = positions.y\n const zArray = positions.z\n\n let count = 0\n const grid = new Uint32Array(n)\n const bucketIndex = new Int32Array(an)\n for (let i = 0; i < an; ++i) {\n const x = (xArray[ i ] - this.minX) >> this.exp\n const y = (yArray[ i ] - this.minY) >> this.exp\n const z = (zArray[ i ] - this.minZ) >> this.exp\n const idx = (((x * this.boundY) + y) * this.boundZ) + z\n if ((grid[ idx ] += 1) === 1) {\n count += 1\n }\n bucketIndex[ i ] = idx\n }\n\n const bucketCount = new Uint16Array(count)\n for (let i = 0, j = 0; i < n; ++i) {\n const c = grid[ i ]\n if (c > 0) {\n grid[ i ] = j + 1\n bucketCount[ j ] = c\n j += 1\n }\n }\n\n const bucketOffset = new Uint32Array(count)\n for (let i = 1; i < count; ++i) {\n bucketOffset[ i ] += bucketOffset[ i - 1 ] + bucketCount[ i - 1 ]\n }\n\n const bucketFill = new Uint16Array(count)\n const bucketArray = new Int32Array(an)\n for (let i = 0; i < an; ++i) {\n const bucketIdx = grid[ bucketIndex[ i ] ]\n if (bucketIdx > 0) {\n const k = bucketIdx - 1\n bucketArray[ bucketOffset[ k ] + bucketFill[ k ] ] = i\n bucketFill[ k ] += 1\n }\n }\n\n this.grid = grid\n this.bucketCount = bucketCount\n this.bucketOffset = bucketOffset\n this.bucketArray = bucketArray\n\n this.xArray = xArray\n this.yArray = yArray\n this.zArray = zArray\n }\n\n within (x: number, y: number, z: number, r: number) {\n const result: number[] = []\n\n this.eachWithin(x, y, z, r, atomIndex => result.push(atomIndex))\n\n return result\n }\n\n eachWithin (x: number, y: number, z: number, r: number, callback: (atomIndex: number, dSq: number) => void) {\n const rSq = r * r\n\n const loX = Math.max(0, (x - r - this.minX) >> this.exp)\n const loY = Math.max(0, (y - r - this.minY) >> this.exp)\n const loZ = Math.max(0, (z - r - this.minZ) >> this.exp)\n\n const hiX = Math.min(this.boundX, ((x + r - this.minX) >> this.exp) + 1)\n const hiY = Math.min(this.boundY, ((y + r - this.minY) >> this.exp) + 1)\n const hiZ = Math.min(this.boundZ, ((z + r - this.minZ) >> this.exp) + 1)\n\n for (let ix = loX; ix < hiX; ++ix) {\n for (let iy = loY; iy < hiY; ++iy) {\n for (let iz = loZ; iz < hiZ; ++iz) {\n const idx = (((ix * this.boundY) + iy) * this.boundZ) + iz\n const bucketIdx = this.grid[ idx ]\n\n if (bucketIdx > 0) {\n const k = bucketIdx - 1\n const offset = this.bucketOffset[ k ]\n const count = this.bucketCount[ k ]\n const end = offset + count\n\n for (let i = offset; i < end; ++i) {\n const atomIndex = this.bucketArray[ i ]\n const dx = this.xArray[ atomIndex ] - x\n const dy = this.yArray[ atomIndex ] - y\n const dz = this.zArray[ atomIndex ] - z\n\n const dSq = dx * dx + dy * dy + dz * dz\n if (dSq <= rSq) callback(atomIndex, dSq)\n }\n }\n }\n }\n }\n }\n}","/**\n * @file Store\n * @author Alexander Rose \n * @private\n */\n\nimport { Log } from '../globals'\nimport { getTypedArray, TypedArrayString } from '../utils'\n\nexport type StoreField = [string, number, TypedArrayString]\n\n/**\n * Store base class\n * @interface\n */\nexport default class Store {\n [k: string]: any\n\n length: number\n count: number\n\n _fields: StoreField[]\n get _defaultFields(): StoreField[] { return [] }\n\n /**\n * @param {Integer} [size] - initial size\n */\n constructor (size = 0) {\n this._fields = this._defaultFields\n this._init(0)\n }\n\n /**\n * Initialize the store\n * @param {Integer} size - size to initialize\n * @return {undefined}\n */\n _init (size: number) {\n this.length = size\n this.count = 0\n\n for (let i = 0, il = this._fields.length; i < il; ++i) {\n const [name, size, type]: StoreField = this._fields[ i ]\n this._initField(name, size, type)\n }\n }\n\n /**\n * Initialize a field\n * @param {String} name - field name\n * @param {Integer} size - element size\n * @param {String} type - data type, one of int8, int16, int32,\n * uint8, uint16, uint32, float32\n * @return {undefined}\n */\n _initField (name: string, size: number, type: TypedArrayString) {\n this[ name ] = getTypedArray(type, this.length * size)\n }\n\n /**\n * Add a field\n * @param {String} name - field name\n * @param {Integer} size - element size\n * @param {String} type - data type, one of int8, int16, int32,\n * uint8, uint16, uint32, float32\n * @return {undefined}\n */\n addField (name: string, size: number, type: TypedArrayString) {\n this._fields.push([name, size, type])\n this._initField(name, size, type)\n }\n\n /**\n * Resize the store to the new size\n * @param {Integer} size - new size\n * @return {undefined}\n */\n resize (size?: number) {\n // Log.time( \"Store.resize\" );\n\n this.length = Math.round(size || 0)\n this.count = Math.min(this.count, this.length)\n\n for (let i = 0, il = this._fields.length; i < il; ++i) {\n const name = this._fields[ i ][ 0 ]\n const itemSize = this._fields[ i ][ 1 ]\n const arraySize = this.length * itemSize\n const tmpArray = new this[ name ].constructor(arraySize)\n\n if (this[ name ].length > arraySize) {\n tmpArray.set(this[ name ].subarray(0, arraySize))\n } else {\n tmpArray.set(this[ name ])\n }\n this[ name ] = tmpArray\n }\n\n // Log.timeEnd( \"Store.resize\" );\n }\n\n /**\n * Resize the store to 1.5 times its current size if full\n * @return {undefined}\n */\n growIfFull () {\n if (this.count >= this.length) {\n const size = Math.round(this.length * 1.5)\n this.resize(Math.max(256, size))\n }\n }\n\n /**\n * Copy data from one store to another\n * @param {Store} other - store to copy from\n * @param {Integer} thisOffset - offset to start copying to\n * @param {Integer} otherOffset - offset to start copying from\n * @param {Integer} length - number of entries to copy\n * @return {undefined}\n */\n copyFrom (other: Store, thisOffset: number, otherOffset: number, length: number) {\n for (let i = 0, il = this._fields.length; i < il; ++i) {\n const name = this._fields[ i ][ 0 ]\n const itemSize = this._fields[ i ][ 1 ]\n const thisField = this[ name ]\n const otherField = other[ name ]\n\n for (let j = 0; j < length; ++j) {\n const thisIndex = itemSize * (thisOffset + j)\n const otherIndex = itemSize * (otherOffset + j)\n for (let k = 0; k < itemSize; ++k) {\n thisField[ thisIndex + k ] = otherField[ otherIndex + k ]\n }\n }\n }\n }\n\n /**\n * Copy data within this store\n * @param {Integer} thisOffset - offset to start copying to\n * @param {Integer} otherOffset - offset to start copying from\n * @param {Integer} length - number of entries to copy\n * @return {undefined}\n */\n copyWithin (offsetTarget: number, offsetSource: number, length: number) {\n for (let i = 0, il = this._fields.length; i < il; ++i) {\n const name = this._fields[ i ][ 0 ]\n const itemSize = this._fields[ i ][ 1 ]\n const thisField = this[ name ]\n\n for (let j = 0; j < length; ++j) {\n const targetIndex = itemSize * (offsetTarget + j)\n const sourceIndex = itemSize * (offsetSource + j)\n for (let k = 0; k < itemSize; ++k) {\n thisField[ targetIndex + k ] = thisField[ sourceIndex + k ]\n }\n }\n }\n }\n\n /**\n * Sort entries in the store given the compare function\n * @param {[type]} compareFunction - function to sort by\n * @return {undefined}\n */\n sort (compareFunction: (a: any, b: any) => number) {\n Log.time('Store.sort')\n\n const thisStore = this\n const tmpStore = new (this.constructor as any)(1)\n\n function swap (index1: number, index2: number) {\n if (index1 === index2) return\n tmpStore.copyFrom(thisStore, 0, index1, 1)\n thisStore.copyWithin(index1, index2, 1)\n thisStore.copyFrom(tmpStore, index2, 0, 1)\n }\n\n function quicksort (left: number, right: number) {\n if (left < right) {\n let pivot = Math.floor((left + right) / 2)\n let leftNew = left\n let rightNew = right\n do {\n while (compareFunction(leftNew, pivot) < 0) {\n leftNew += 1\n }\n while (compareFunction(rightNew, pivot) > 0) {\n rightNew -= 1\n }\n if (leftNew <= rightNew) {\n if (leftNew === pivot) {\n pivot = rightNew\n } else if (rightNew === pivot) {\n pivot = leftNew\n }\n swap(leftNew, rightNew)\n leftNew += 1\n rightNew -= 1\n }\n } while (leftNew <= rightNew)\n quicksort(left, rightNew)\n quicksort(leftNew, right)\n }\n }\n\n quicksort(0, this.count - 1)\n\n Log.timeEnd('Store.sort')\n }\n\n /**\n * Empty the store\n * @return {undefined}\n */\n clear () {\n this.count = 0\n }\n\n /**\n * Dispose of the store entries and fields\n * @return {undefined}\n */\n dispose () {\n\n for (let i = 0, il = this._fields.length; i < il; ++i) {\n const name = this._fields[ i ][ 0 ]\n delete this[ name ]\n }\n }\n}\n","/**\n * @file Contact Store\n * @author Alexander Rose \n * @private\n */\n\nimport Store, { StoreField } from './store'\n\n/**\n * Bond store\n */\nexport default class ContactStore extends Store {\n index1: Uint32Array\n index2: Uint32Array\n type: Uint8Array\n\n get _defaultFields () {\n return [\n [ 'index1', 1, 'int32' ],\n [ 'index2', 1, 'int32' ],\n [ 'type', 1, 'int8' ]\n ] as StoreField[]\n }\n\n addContact (index1: number, index2: number, type?: number) {\n this.growIfFull()\n\n const i = this.count\n\n if (index1 < index2) {\n this.index1[ i ] = index1\n this.index2[ i ] = index2\n } else {\n this.index2[ i ] = index1\n this.index1[ i ] = index2\n }\n if (type) this.type[ i ] = type\n\n this.count += 1\n }\n}","/**\n * @file Bit array\n * @author Alexander Rose \n * @author Paul Pillot \n * @private\n */\n\n/**\n * Compute the Hamming weight of a 32-bit unsigned integer\n * @param {Integer} v - a 32-bit unsigned integer\n * @return {Integer} the Hamming weight\n */\nfunction hammingWeight (v: number) {\n // works with signed or unsigned shifts\n v -= ((v >>> 1) & 0x55555555)\n v = (v & 0x33333333) + ((v >>> 2) & 0x33333333)\n return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24\n}\n\n/**\n * Bit array\n *\n * Based heavily on https://github.com/lemire/FastBitSet.js\n * which is licensed under the Apache License, Version 2.0.\n */\nexport default class BitArray {\n private _words: Uint32Array\n public length: number\n\n /**\n * @param {Integer} length - array length\n * @param {Boolean} [setAll] - initialize with true\n */\n constructor (length: number, setAll?: boolean) {\n this.length = length\n this._words = new Uint32Array((length + 32) >>> 5)\n if (setAll === true) {\n this.setAll()\n }\n }\n\n /**\n * Get value at index\n * @param {Integer} index - the index\n * @return {Boolean} value\n */\n get (index: number) {\n return (this._words[ index >>> 5 ] & (1 << index)) !== 0\n }\n\n /**\n * Set value at index to true\n * @param {Integer} index - the index\n * @return {undefined}\n */\n set (index: number) {\n this._words[ index >>> 5 ] |= 1 << index\n }\n\n /**\n * Set value at index to false\n * @param {Integer} index - the index\n * @return {undefined}\n */\n clear (index: number) {\n this._words[ index >>> 5 ] &= ~(1 << index)\n }\n\n /**\n * Flip value at index\n * @param {Integer} index - the index\n * @return {undefined}\n */\n flip (index: number) {\n this._words[ index >>> 5 ] ^= 1 << index\n }\n\n _assignRange (start: number, end: number, value: boolean) {\n if (end < start) return\n const words = this._words\n const wordValue = value === true ? 0xFFFFFFFF : 0\n const wordStart = start >>> 5\n const wordEnd = end >>> 5\n // set complete words when applicable\n for (let k = wordStart + 1; k < wordEnd; ++k) {\n words[ k ] = wordValue\n }\n // set parts of the range not spanning complete words\n const startWord = wordStart << 5\n const endWord = wordEnd << 5\n if (value === true) {\n if (end - start < 32) {\n for (let i = start, n = end + 1; i < n; ++i) {\n words[ i >>> 5 ] |= 1 << i\n }\n } else {\n for (let i = start, n = startWord + 32; i < n; ++i) {\n words[ i >>> 5 ] |= 1 << i\n }\n for (let i = endWord, n = end + 1; i < n; ++i) {\n words[ i >>> 5 ] |= 1 << i\n }\n }\n } else {\n if (end - start < 32) {\n for (let i = start, n = end + 1; i < n; ++i) {\n words[ i >>> 5 ] &= ~(1 << i)\n }\n } else {\n for (let i = start, n = startWord + 32; i < n; ++i) {\n words[ i >>> 5 ] &= ~(1 << i)\n }\n for (let i = endWord, n = end + 1; i < n; ++i) {\n words[ i >>> 5 ] &= ~(1 << i)\n }\n }\n }\n return this\n }\n\n /**\n * Set bits of the given range\n * @param {Integer} start - start index\n * @param {Integer} end - end index\n * @return {BitArray} this object\n */\n setRange (start: number, end: number) {\n return this._assignRange(start, end, true)\n }\n\n /**\n * Clear bits of the given range\n * @param {Integer} start - start index\n * @param {Integer} end - end index\n * @return {BitArray} this object\n */\n clearRange (start: number, end: number) {\n return this._assignRange(start, end, false)\n }\n\n /**\n * Set bits at all given indices\n * @param {...Integer} arguments - indices\n * @return {Boolean} this object\n */\n setBits (...indices: number[]) {\n const words = this._words\n const n = indices.length\n for (let i = 0; i < n; ++i) {\n const index = indices[ i ]\n words[ index >>> 5 ] |= 1 << index\n }\n return this\n }\n\n /**\n * Clear bits at all given indices\n * @param {...Integer} arguments - indices\n * @return {Boolean} this object\n */\n clearBits (...indices: number[]) {\n const words = this._words\n const n = indices.length\n for (let i = 0; i < n; ++i) {\n const index = indices[ i ]\n words[ index >>> 5 ] &= ~(1 << index)\n }\n return this\n }\n\n /**\n * Set all bits of the array\n * @return {BitArray} this object\n */\n setAll () {\n return this._assignRange(0, this.length - 1, true)\n }\n\n /**\n * Clear all bits of the array\n * @return {BitArray} this object\n */\n clearAll () {\n return this._assignRange(0, this.length - 1, false)\n }\n\n /**\n * Flip all the values in the array\n * @return {BitArray} this object\n */\n flipAll () {\n const count = this._words.length\n const words = this._words\n const bs = 32 - this.length % 32\n for (let k = 0; k < count - 1; ++k) {\n words[k] = ~words[ k ]\n }\n words[ count - 1 ] = (~(words[ count - 1 ] << bs)) >>> bs\n return this\n }\n\n _isRangeValue (start: number, end: number, value: boolean) {\n if (end < start) return\n const words = this._words\n const wordValue = value === true ? 0xFFFFFFFF : 0\n const wordStart = start >>> 5\n const wordEnd = end >>> 5\n // set complete words when applicable\n for (let k = wordStart + 1; k < wordEnd; ++k) {\n if (words[ k ] !== wordValue) return false\n }\n // set parts of the range not spanning complete words\n if (end - start < 32) {\n for (let i = start, n = end + 1; i < n; ++i) {\n if (!!(words[ i >>> 5 ] & (1 << i)) !== value) return false\n }\n } else {\n const startWord = wordStart << 5\n const endWord = wordEnd << 5\n for (let i = start, n = startWord + 32; i < n; ++i) {\n if (!!(words[ i >>> 5 ] & (1 << i)) !== value) return false\n }\n for (let i = endWord, n = end + 1; i < n; ++i) {\n if (!!(words[ i >>> 5 ] & (1 << i)) !== value) return false\n }\n }\n return true\n }\n\n /**\n * Test if bits in given range are set\n * @param {Integer} start - start index\n * @param {Integer} end - end index\n * @return {BitArray} this object\n */\n isRangeSet (start: number, end: number) {\n return this._isRangeValue(start, end, true)\n }\n\n /**\n * Test if bits in given range are clear\n * @param {Integer} start - start index\n * @param {Integer} end - end index\n * @return {BitArray} this object\n */\n isRangeClear (start: number, end: number) {\n return this._isRangeValue(start, end, false)\n }\n\n /**\n * Test if all bits in the array are set\n * @return {Boolean} test result\n */\n isAllSet () {\n return this._isRangeValue(0, this.length - 1, true)\n }\n\n /**\n * Test if all bits in the array are clear\n * @return {Boolean} test result\n */\n isAllClear () {\n return this._isRangeValue(0, this.length - 1, false)\n }\n\n /**\n * Test if bits at all given indices are set\n * @param {...Integer} arguments - indices\n * @return {Boolean} test result\n */\n isSet (...indices: number[]) {\n const words = this._words\n const n = indices.length\n for (let i = 0; i < n; ++i) {\n const index = indices[ i ]\n if ((words[ index >>> 5 ] & (1 << index)) === 0) return false\n }\n return true\n }\n\n /**\n * Test if bits at all given indices are clear\n * @param {...Integer} arguments - indices\n * @return {Boolean} test result\n */\n isClear (...indices: number[]) {\n const words = this._words\n const n = indices.length\n for (let i = 0; i < n; ++i) {\n const index = indices[ i ]\n if ((words[ index >>> 5 ] & (1 << index)) !== 0) return false\n }\n return true\n }\n\n /**\n * Test if two BitArrays are identical in all their values\n * @param {BitArray} otherBitarray - the other BitArray\n * @return {Boolean} test result\n */\n isEqualTo (otherBitarray: BitArray) {\n const words1 = this._words\n const words2 = otherBitarray._words\n const count = Math.min(words1.length, words2.length)\n for (let k = 0; k < count; ++k) {\n if (words1[ k ] !== words2[ k ]) {\n return false\n }\n }\n return true\n }\n\n /**\n * How many set bits?\n * @return {Integer} number of set bits\n */\n getSize () {\n const count = this._words.length\n const words = this._words\n let size = 0\n for (let i = 0; i < count; ++i) {\n size += hammingWeight(words[ i ])\n }\n return size\n }\n\n /**\n * Calculate difference betwen this and another bit array.\n * Store result in this object.\n * @param {BitArray} otherBitarray - the other bit array\n * @return {BitArray} this object\n */\n difference (otherBitarray: BitArray) {\n const words1 = this._words\n const words2 = otherBitarray._words\n const count = Math.min(words1.length, words2.length)\n for (let k = 0; k < count; ++k) {\n words1[ k ] = words1[ k ] & ~words2[ k ]\n }\n for (let k = words1.length; k < count; ++k) {\n words1[ k ] = 0\n }\n return this\n }\n\n /**\n * Calculate union betwen this and another bit array.\n * Store result in this object.\n * @param {BitArray} otherBitarray - the other bit array\n * @return {BitArray} this object\n */\n union (otherBitarray: BitArray) {\n const words1 = this._words\n const words2 = otherBitarray._words\n const count = Math.min(words1.length, words2.length)\n for (let k = 0; k < count; ++k) {\n words1[ k ] |= words2[ k ]\n }\n for (let k = words1.length; k < count; ++k) {\n words1[ k ] = 0\n }\n return this\n }\n\n /**\n * Calculate intersection betwen this and another bit array.\n * Store result in this object.\n * @param {BitArray} otherBitarray - the other bit array\n * @return {BitArray} this object\n */\n intersection (otherBitarray: BitArray) {\n const words1 = this._words\n const words2 = otherBitarray._words\n const count = Math.min(words1.length, words2.length)\n for (let k = 0; k < count; ++k) {\n words1[ k ] &= words2[ k ]\n }\n for (let k = words1.length; k < count; ++k) {\n words1[ k ] = 0\n }\n return this\n }\n\n /**\n * Test if there is any intersection betwen this and another bit array.\n * @param {BitArray} otherBitarray - the other bit array\n * @return {Boolean} test result\n */\n intersects (otherBitarray: BitArray) {\n const words1 = this._words\n const words2 = otherBitarray._words\n const count = Math.min(words1.length, words2.length)\n for (let k = 0; k < count; ++k) {\n if ((words1[ k ] & words2[ k ]) !== 0) {\n return true\n }\n }\n return false\n }\n\n /**\n * Calculate the number of bits in common betwen this and another bit array.\n * @param {BitArray} otherBitarray - the other bit array\n * @return {Integer} size\n */\n getIntersectionSize (otherBitarray: BitArray) {\n const words1 = this._words\n const words2 = otherBitarray._words\n const count = Math.min(words1.length, words2.length)\n let size = 0\n for (let k = 0; k < count; ++k) {\n size += hammingWeight(words1[ k ] & words2[ k ])\n }\n return size\n }\n\n /**\n * Calculate intersection betwen this and another bit array.\n * Store result in a new bit array.\n * @param {BitArray} otherBitarray - the other bit array\n * @return {BitArray} the new bit array\n */\n makeIntersection (otherBitarray: BitArray) {\n const words1 = this._words\n const words2 = otherBitarray._words\n const count = Math.min(words1.length, words2.length)\n const wordsA = new Uint32Array(count)\n const intersection = Object.create(BitArray.prototype)\n intersection._words = wordsA\n intersection.length = Math.min(this.length, otherBitarray.length)\n for (let k = 0; k < count; ++k) {\n wordsA[ k ] = words1[ k ] & words2[ k ]\n }\n return intersection\n }\n\n /**\n * Iterate over all set bits in the array\n * @param {function( index: Integer, i: Integer )} callback - the callback\n * @return {undefined}\n */\n forEach (callback: (index: number, i: number) => any) {\n const count = this._words.length\n const words = this._words\n let i = 0\n for (let k = 0; k < count; ++k) {\n let w = words[ k ]\n while (w !== 0) {\n const t = w & -w\n const index = (k << 5) + hammingWeight(t - 1)\n callback(index, i)\n w ^= t\n ++i\n }\n }\n }\n\n /**\n * Get an array with the set bits\n * @return {Array} bit indices\n */\n toArray () {\n const words = this._words\n const answer = new Array(this.getSize())\n const count = this._words.length\n let pos = 0\n for (let k = 0; k < count; ++k) {\n let w = words[ k ]\n while (w !== 0) {\n const t = w & -w\n answer[ pos++ ] = (k << 5) + hammingWeight(t - 1)\n w ^= t\n }\n }\n return answer\n }\n\n toString () {\n return '{' + this.toArray().join(',') + '}'\n }\n\n toSeleString () {\n const sele = this.toArray().join(',')\n return sele ? '@' + sele : 'NONE'\n }\n\n /**\n * Clone this object\n * @return {BitArray} the cloned object\n */\n clone () {\n const clone = Object.create(BitArray.prototype)\n clone.length = this.length\n clone._words = new Uint32Array(this._words)\n return clone\n }\n}","/**\n * @file Adjacency List\n * @author Alexander Rose \n * @private\n */\n\nexport interface Edges {\n nodeArray1: ArrayLike\n nodeArray2: ArrayLike\n edgeCount: number\n nodeCount: number\n}\n\nexport interface AdjacencyList {\n /* number of edges for each node */\n countArray: Uint8Array\n /* offset into indexArray for each node */\n offsetArray: Int32Array\n /* edge indices, grouped by nodes */\n indexArray: Int32Array\n}\n\nexport function createAdjacencyList (edges: Edges): AdjacencyList {\n const { edgeCount, nodeCount, nodeArray1, nodeArray2 } = edges\n\n const countArray = new Uint8Array(nodeCount)\n const offsetArray = new Int32Array(nodeCount)\n\n // count edges per node\n for (let i = 0; i < edgeCount; ++i) {\n countArray[ nodeArray1[ i ] ] += 1\n countArray[ nodeArray2[ i ] ] += 1\n }\n\n // get offsets to node edges\n for (let i = 1; i < nodeCount; ++i) {\n offsetArray[ i ] += offsetArray[ i - 1 ] + countArray[ i - 1 ]\n }\n\n // prepare index array\n const bondCount2 = edgeCount * 2\n const indexArray = new Int32Array(bondCount2)\n for (let j = 0; j < bondCount2; ++j) {\n indexArray[ j ] = -1\n }\n\n // build index array\n for (let i = 0; i < edgeCount; ++i) {\n const idx1 = nodeArray1[ i ]\n const idx2 = nodeArray2[ i ]\n let j1 = offsetArray[ idx1 ]\n while (indexArray[ j1 ] !== -1 && j1 < bondCount2) {\n j1 += 1\n }\n indexArray[ j1 ] = i\n let j2 = offsetArray[ idx2 ]\n while (indexArray[ j2 ] !== -1 && j2 < bondCount2) {\n j2 += 1\n }\n indexArray[ j2 ] = i\n }\n\n return { countArray, offsetArray, indexArray }\n}\n","/**\n * @file Features\n * @author Alexander Rose \n */\n\nimport AtomProxy from '../../proxy/atom-proxy'\n\nexport interface Features {\n types: FeatureType[]\n groups: FeatureGroup[]\n centers: { x: number[], y: number[], z: number[] }\n atomSets: number[][]\n}\n\nexport const enum FeatureType {\n Unknown = 0,\n PositiveCharge = 1,\n NegativeCharge = 2,\n AromaticRing = 3,\n HydrogenDonor = 4,\n HydrogenAcceptor = 5,\n HalogenDonor = 6,\n HalogenAcceptor = 7,\n Hydrophobic = 8,\n WeakHydrogenDonor = 9,\n IonicTypePartner = 10,\n DativeBondPartner = 11,\n TransitionMetal = 12,\n IonicTypeMetal = 13\n}\n\nexport const enum FeatureGroup {\n Unknown = 0,\n QuaternaryAmine = 1,\n TertiaryAmine = 2,\n Sulfonium = 3,\n SulfonicAcid = 4,\n Sulfate = 5,\n Phosphate = 6,\n Halocarbon = 7,\n Guanidine = 8,\n Acetamidine = 9,\n Carboxylate = 10\n}\n\nexport function createFeatures (): Features {\n return {\n types: [],\n groups: [],\n centers: { x: [], y: [], z: [] },\n atomSets: []\n }\n}\n\nexport interface FeatureState {\n type: FeatureType\n group: FeatureGroup\n x: number\n y: number\n z: number\n atomSet: number[]\n}\n\nexport function createFeatureState(type = FeatureType.Unknown, group = FeatureGroup.Unknown): FeatureState {\n return { type, group, x: 0, y: 0, z: 0, atomSet: [] }\n}\n\nexport function addAtom (state: FeatureState, atom: AtomProxy) {\n state.x += atom.x\n state.y += atom.y\n state.z += atom.z\n state.atomSet.push(atom.index)\n}\n\nexport function addFeature (features: Features, state: FeatureState) {\n const n = state.atomSet.length\n if (n > 0) {\n const { types, groups, centers, atomSets } = features\n types.push(state.type)\n groups.push(state.group)\n centers.x.push(state.x / n)\n centers.y.push(state.y / n)\n centers.z.push(state.z / n)\n atomSets.push(state.atomSet)\n }\n}\n","/**\n * @file Structure Constants\n * @author Alexander Rose \n * @private\n */\n\n// entity types\nexport const UnknownEntity = 0\nexport const PolymerEntity = 1\nexport const NonPolymerEntity = 2\nexport const MacrolideEntity = 3\nexport const WaterEntity = 4\n\n// molecule types\nexport const UnknownType = 0\nexport const WaterType = 1\nexport const IonType = 2\nexport const ProteinType = 3\nexport const RnaType = 4\nexport const DnaType = 5\nexport const SaccharideType = 6\n\n// backbone types\nexport const UnknownBackboneType = 0\nexport const ProteinBackboneType = 1\nexport const RnaBackboneType = 2\nexport const DnaBackboneType = 3\nexport const CgProteinBackboneType = 4\nexport const CgRnaBackboneType = 5\nexport const CgDnaBackboneType = 6\n\n// chemical component types\nexport const ChemCompProtein = [\n 'D-BETA-PEPTIDE, C-GAMMA LINKING', 'D-GAMMA-PEPTIDE, C-DELTA LINKING',\n 'D-PEPTIDE COOH CARBOXY TERMINUS', 'D-PEPTIDE NH3 AMINO TERMINUS', 'D-PEPTIDE LINKING',\n 'L-BETA-PEPTIDE, C-GAMMA LINKING', 'L-GAMMA-PEPTIDE, C-DELTA LINKING',\n 'L-PEPTIDE COOH CARBOXY TERMINUS', 'L-PEPTIDE NH3 AMINO TERMINUS', 'L-PEPTIDE LINKING',\n 'PEPTIDE LINKING', 'PEPTIDE-LIKE'\n]\nexport const ChemCompRna = [\n 'RNA OH 3 PRIME TERMINUS', 'RNA OH 5 PRIME TERMINUS', 'RNA LINKING'\n]\nexport const ChemCompDna = [\n 'DNA OH 3 PRIME TERMINUS', 'DNA OH 5 PRIME TERMINUS', 'DNA LINKING',\n 'L-DNA LINKING', 'L-RNA LINKING'\n]\nexport const ChemCompSaccharide = [\n 'D-SACCHARIDE', 'D-SACCHARIDE 1,4 AND 1,4 LINKING', 'D-SACCHARIDE 1,4 AND 1,6 LINKING',\n 'L-SACCHARIDE', 'L-SACCHARIDE 1,4 AND 1,4 LINKING', 'L-SACCHARIDE 1,4 AND 1,6 LINKING',\n 'SACCHARIDE'\n]\nexport const ChemCompOther = [\n 'OTHER'\n]\nexport const ChemCompNonPolymer = [\n 'NON-POLYMER'\n]\nexport const ChemCompHetero = ChemCompNonPolymer.concat(ChemCompOther, ChemCompSaccharide)\n\n// secondary structure\nexport const SecStrucHelix = [ 'h', 'g', 'i' ]\nexport const SecStrucSheet = [ 'e', 'b' ]\nexport const SecStrucTurn = [ 's', 't', 'l', '' ]\n\nexport const AtomicNumbers: { [e: string]: number | undefined } = {\n 'H': 1, 'D': 1, 'T': 1, 'HE': 2, 'LI': 3, 'BE': 4, 'B': 5, 'C': 6, 'N': 7, 'O': 8, 'F': 9, 'NE': 10, 'NA': 11, 'MG': 12, 'AL': 13, 'SI': 14, 'P': 15, 'S': 16, 'CL': 17, 'AR': 18, 'K': 19, 'CA': 20, 'SC': 21, 'TI': 22, 'V': 23, 'CR': 24, 'MN': 25, 'FE': 26, 'CO': 27, 'NI': 28, 'CU': 29, 'ZN': 30, 'GA': 31, 'GE': 32, 'AS': 33, 'SE': 34, 'BR': 35, 'KR': 36, 'RB': 37, 'SR': 38, 'Y': 39, 'ZR': 40, 'NB': 41, 'MO': 42, 'TC': 43, 'RU': 44, 'RH': 45, 'PD': 46, 'AG': 47, 'CD': 48, 'IN': 49, 'SN': 50, 'SB': 51, 'TE': 52, 'I': 53, 'XE': 54, 'CS': 55, 'BA': 56, 'LA': 57, 'CE': 58, 'PR': 59, 'ND': 60, 'PM': 61, 'SM': 62, 'EU': 63, 'GD': 64, 'TB': 65, 'DY': 66, 'HO': 67, 'ER': 68, 'TM': 69, 'YB': 70, 'LU': 71, 'HF': 72, 'TA': 73, 'W': 74, 'RE': 75, 'OS': 76, 'IR': 77, 'PT': 78, 'AU': 79, 'HG': 80, 'TL': 81, 'PB': 82, 'BI': 83, 'PO': 84, 'AT': 85, 'RN': 86, 'FR': 87, 'RA': 88, 'AC': 89, 'TH': 90, 'PA': 91, 'U': 92, 'NP': 93, 'PU': 94, 'AM': 95, 'CM': 96, 'BK': 97, 'CF': 98, 'ES': 99, 'FM': 100, 'MD': 101, 'NO': 102, 'LR': 103, 'RF': 104, 'DB': 105, 'SG': 106, 'BH': 107, 'HS': 108, 'MT': 109, 'DS': 110, 'RG': 111, 'CN': 112, 'NH': 113, 'FL': 114, 'MC': 115, 'LV': 116, 'TS': 117, 'OG': 118\n}\nexport const DefaultAtomicNumber = 0\n\n/**\n * Enum mapping element to atomic number\n */\nexport const enum Elements {\n H = 1, D = 1, T = 1, HE = 2, LI = 3, BE = 4, B = 5, C = 6, N = 7, O = 8, F = 9, NE = 10, NA = 11, MG = 12, AL = 13, SI = 14, P = 15, S = 16, CL = 17, AR = 18, K = 19, CA = 20, SC = 21, TI = 22, V = 23, CR = 24, MN = 25, FE = 26, CO = 27, NI = 28, CU = 29, ZN = 30, GA = 31, GE = 32, AS = 33, SE = 34, BR = 35, KR = 36, RB = 37, SR = 38, Y = 39, ZR = 40, NB = 41, MO = 42, TC = 43, RU = 44, RH = 45, PD = 46, AG = 47, CD = 48, IN = 49, SN = 50, SB = 51, TE = 52, I = 53, XE = 54, CS = 55, BA = 56, LA = 57, CE = 58, PR = 59, ND = 60, PM = 61, SM = 62, EU = 63, GD = 64, TB = 65, DY = 66, HO = 67, ER = 68, TM = 69, YB = 70, LU = 71, HF = 72, TA = 73, W = 74, RE = 75, OS = 76, IR = 77, PT = 78, AU = 79, HG = 80, TL = 81, PB = 82, BI = 83, PO = 84, AT = 85, RN = 86, FR = 87, RA = 88, AC = 89, TH = 90, PA = 91, U = 92, NP = 93, PU = 94, AM = 95, CM = 96, BK = 97, CF = 98, ES = 99, FM = 100, MD = 101, NO = 102, LR = 103, RF = 104, DB = 105, SG = 106, BH = 107, HS = 108, MT = 109, DS = 110, RG = 111, CN = 112, NH = 113, FL = 114, MC = 115, LV = 116, TS = 117, OG = 118\n}\n\n// https://doi.org/10.1515/pac-2015-0305 (table 2, 3, and 4)\nexport const AtomWeights: { [e: number]: number | undefined } = {\n 1: 1.008, 2: 4.0026, 3: 6.94, 4: 9.0122, 5: 10.81, 6: 10.81, 7: 14.007, 8: 15.999, 9: 18.998, 10: 20.180, 11: 22.990, 12: 24.305, 13: 26.982, 14: 28.085, 15: 30.974, 16: 32.06, 17: 35.45, 18: 39.948, 19: 39.098, 20: 40.078, 21: 44.956, 22: 47.867, 23: 50.942, 24: 51.996, 25: 54.938, 26: 55.845, 27: 58.933, 28: 58.693, 29: 63.546, 30: 65.38, 31: 69.723, 32: 72.630, 33: 74.922, 34: 78.971, 35: 79.904, 36: 83.798, 37: 85.468, 38: 87.62, 39: 88.906, 40: 91.224, 41: 92.906, 42: 95.95, 43: 96.906, 44: 101.07, 45: 102.91, 46: 106.42, 47: 107.87, 48: 112.41, 49: 114.82, 50: 118.71, 51: 121.76, 52: 127.60, 53: 127.60, 54: 131.29, 55: 132.91, 56: 137.33, 57: 138.91, 58: 140.12, 59: 140.91, 60: 144.24, 61: 144.912, 62: 150.36, 63: 151.96, 64: 157.25, 65: 158.93, 66: 162.50, 67: 164.93, 68: 167.26, 69: 168.93, 70: 173.05, 71: 174.97, 72: 178.49, 73: 180.95, 74: 183.84, 75: 186.21, 76: 190.23, 77: 192.22, 78: 195.08, 79: 196.97, 80: 200.59, 81: 204.38, 82: 207.2, 83: 208.98, 84: 1.97, 85: 2.02, 86: 2.2, 87: 3.48, 88: 2.83, 89: 2.0, 90: 232.04, 91: 231.04, 92: 238.03, 93: 237.048, 94: 244.064, 95: 243.061, 96: 247.070, 97: 247.070, 98: 251.079, 99: 252.083, 100: 257.095, 101: 258.098, 102: 259.101, 103: 262.110, 104: 267.122, 105: 270.131, 106: 271.134, 107: 270.133, 108: 270.134, 109: 278.156, 110: 281.165, 111: 281.166, 112: 285.177, 113: 286.182, 114: 289.190, 115: 289.194, 116: 293.204, 117: 293.208, 118: 294.214\n}\nexport const DefaultAtomWeight = 10.81 // C\n\n// http://dx.doi.org/10.1021/jp8111556 (or 2.0)\nexport const VdwRadii: { [e: number]: number | undefined } = {\n 1: 1.1, 2: 1.4, 3: 1.81, 4: 1.53, 5: 1.92, 6: 1.7, 7: 1.55, 8: 1.52, 9: 1.47, 10: 1.54, 11: 2.27, 12: 1.73, 13: 1.84, 14: 2.1, 15: 1.8, 16: 1.8, 17: 1.75, 18: 1.88, 19: 2.75, 20: 2.31, 21: 2.3, 22: 2.15, 23: 2.05, 24: 2.05, 25: 2.05, 26: 2.05, 27: 2.0, 28: 2.0, 29: 2.0, 30: 2.1, 31: 1.87, 32: 2.11, 33: 1.85, 34: 1.9, 35: 1.83, 36: 2.02, 37: 3.03, 38: 2.49, 39: 2.4, 40: 2.3, 41: 2.15, 42: 2.1, 43: 2.05, 44: 2.05, 45: 2.0, 46: 2.05, 47: 2.1, 48: 2.2, 49: 2.2, 50: 1.93, 51: 2.17, 52: 2.06, 53: 1.98, 54: 2.16, 55: 3.43, 56: 2.68, 57: 2.5, 58: 2.48, 59: 2.47, 60: 2.45, 61: 2.43, 62: 2.42, 63: 2.4, 64: 2.38, 65: 2.37, 66: 2.35, 67: 2.33, 68: 2.32, 69: 2.3, 70: 2.28, 71: 2.27, 72: 2.25, 73: 2.2, 74: 2.1, 75: 2.05, 76: 2.0, 77: 2.0, 78: 2.05, 79: 2.1, 80: 2.05, 81: 1.96, 82: 2.02, 83: 2.07, 84: 1.97, 85: 2.02, 86: 2.2, 87: 3.48, 88: 2.83, 89: 2.0, 90: 2.4, 91: 2.0, 92: 2.3, 93: 2.0, 94: 2.0, 95: 2.0, 96: 2.0, 97: 2.0, 98: 2.0, 99: 2.0, 100: 2.0, 101: 2.0, 102: 2.0, 103: 2.0, 104: 2.0, 105: 2.0, 106: 2.0, 107: 2.0, 108: 2.0, 109: 2.0, 110: 2.0, 111: 2.0, 112: 2.0, 113: 2.0, 114: 2.0, 115: 2.0, 116: 2.0, 117: 2.0, 118: 2.0\n}\nexport const DefaultVdwRadius = 2.0 // C\n\n// Peter Rose (peter.rose@rcsb.org), private communication, average accross PDB\nexport const ResidueRadii: { [k: string]: number } = {\n '2QY': 6.58,\n 'CY0': 11.98,\n '2QZ': 2.52,\n 'CY1': 6.59,\n 'HHK': 5.11,\n 'CXM': 4.69,\n 'HHI': 4.58,\n 'CY4': 4.57,\n 'S12': 18.57,\n 'CY3': 2.79,\n 'C5C': 5.35,\n 'PFX': 11.84,\n '2R3': 6.94,\n '2R1': 3.78,\n 'ILX': 4.99,\n '32S': 5.68,\n 'BTK': 8.59,\n '32T': 5.72,\n 'FAK': 9.8,\n 'B27': 2.78,\n 'ILM': 3.84,\n 'C4R': 5.63,\n '32L': 6.75,\n 'SYS': 3.01,\n '1MH': 5.04,\n 'ILE': 3.65,\n 'YNM': 6.39,\n '2RX': 4.91,\n 'B3A': 2.48,\n 'GEE': 4.76,\n '7MN': 7.34,\n 'B3E': 5.4,\n 'ARG': 6.33,\n '200': 6.89,\n 'HIP': 5.47,\n 'HIA': 4.64,\n 'B3K': 5.89,\n 'HIC': 5.76,\n 'B3L': 4.96,\n 'B3M': 5.07,\n 'ARM': 6.86,\n 'ARO': 7.35,\n 'AR4': 8.42,\n 'PG1': 10.67,\n 'YOF': 6.44,\n 'IML': 3.74,\n 'SXE': 6.65,\n 'HIQ': 7.98,\n 'PFF': 6.31,\n 'HIS': 4.52,\n '0TD': 3.62,\n 'C3Y': 5.24,\n '1OP': 11.55,\n '02Y': 4.77,\n '02V': 4.83,\n 'ASB': 5.59,\n '30V': 8.53,\n 'S2P': 4.81,\n 'ASP': 3.55,\n 'ASN': 3.54,\n '2OR': 6.91,\n 'QMM': 6.13,\n '2P0': 8.52,\n 'ASL': 5.36,\n 'HFA': 5.14,\n '5PG': 5.69,\n 'B3X': 4.38,\n 'AS9': 4.1,\n 'ARV': 7.59,\n 'B3U': 6.06,\n 'S2C': 7.54,\n 'B3T': 3.34,\n '175': 5.64,\n 'GFT': 8.18,\n 'HG7': 6.8,\n 'B3Q': 4.48,\n 'ASA': 3.64,\n '02K': 2.94,\n 'B3Y': 7.45,\n 'PHD': 5.35,\n 'C6C': 6.42,\n 'BUC': 5.8,\n 'HGL': 8.07,\n 'PHE': 5.06,\n '03Y': 2.6,\n 'PHA': 5.11,\n 'OCY': 5.0,\n '4PH': 6.79,\n '5OH': 4.7,\n '31Q': 10.46,\n 'BTR': 7.98,\n '3PX': 4.7,\n '1PA': 8.07,\n 'ASX': 3.54,\n 'IOR': 7.23,\n '03E': 3.38,\n 'PHL': 5.17,\n 'KWS': 5.09,\n 'PHI': 7.12,\n 'NAL': 7.22,\n 'S1H': 19.21,\n '2ML': 3.86,\n '2MR': 7.35,\n 'GHG': 4.83,\n 'TYY': 6.54,\n '2MT': 3.67,\n '56A': 13.01,\n 'SVA': 5.46,\n 'TYX': 8.31,\n 'TYS': 8.59,\n 'TYR': 6.38,\n 'TYQ': 6.43,\n 'HLU': 3.99,\n 'MYK': 19.47,\n 'TYO': 7.71,\n 'HLX': 4.98,\n 'TYN': 9.87,\n 'TYJ': 6.25,\n 'TYI': 6.49,\n 'LYH': 5.13,\n 'LYF': 12.19,\n 'SUN': 6.73,\n 'LYR': 18.28,\n 'TYB': 6.46,\n '11W': 14.39,\n 'LYS': 5.54,\n 'LYN': 4.8,\n '11Q': 4.85,\n 'LYO': 4.71,\n 'LYZ': 1.76,\n 'TXY': 6.44,\n 'MYN': 4.71,\n 'TY5': 10.6,\n 'HMR': 5.09,\n '01W': 8.55,\n 'LYX': 13.36,\n 'TY8': 7.22,\n 'TY2': 6.49,\n 'KYN': 6.18,\n 'KYQ': 9.75,\n 'CZZ': 5.14,\n 'IIL': 3.81,\n 'HNC': 10.41,\n 'OIC': 4.62,\n 'LVN': 2.89,\n 'QIL': 3.84,\n 'JJL': 8.3,\n 'VAH': 3.88,\n 'JJJ': 7.5,\n 'JJK': 7.43,\n 'VAD': 2.56,\n 'CYW': 4.65,\n '0QL': 5.72,\n '143': 8.22,\n 'SVX': 7.04,\n 'CYJ': 11.64,\n 'SVY': 7.1,\n 'SVZ': 6.6,\n 'CYG': 8.03,\n 'CYF': 13.54,\n 'SVV': 5.09,\n 'GL3': 2.72,\n '8SP': 14.26,\n 'CYS': 2.78,\n '004': 4.33,\n 'CYR': 10.33,\n 'PLJ': 3.71,\n 'EXY': 7.37,\n 'HL2': 3.75,\n 'A5N': 5.21,\n 'CYQ': 5.67,\n 'CZ2': 5.16,\n 'LWY': 4.12,\n 'PM3': 8.78,\n 'OHS': 6.98,\n 'OHI': 5.35,\n '3TY': 8.42,\n 'CYD': 8.55,\n 'DYS': 7.87,\n 'DAH': 6.47,\n '4IK': 11.81,\n '3EG': 3.66,\n 'AYA': 3.65,\n '4IN': 6.31,\n 'DAB': 3.48,\n '4HT': 6.03,\n 'RGL': 7.03,\n 'DAM': 2.49,\n 'NFA': 5.04,\n 'WFP': 6.07,\n '2JC': 2.97,\n 'HAR': 7.55,\n '2JG': 5.67,\n 'MH6': 1.72,\n '2JF': 9.13,\n '3FG': 4.96,\n 'MGN': 4.84,\n 'AZH': 5.36,\n 'AZK': 6.03,\n 'ZBZ': 7.79,\n 'TBG': 2.58,\n 'VAL': 2.51,\n 'MGG': 7.34,\n 'AZS': 5.61,\n 'FHL': 9.75,\n '2JH': 4.56,\n 'IEL': 7.07,\n 'FHO': 6.75,\n 'DA2': 7.79,\n 'FH7': 6.99,\n 'ME0': 4.52,\n '3GL': 4.84,\n 'MDO': 5.03,\n 'AZY': 7.37,\n 'A8E': 3.76,\n 'ZCL': 6.71,\n 'MDH': 2.58,\n 'LA2': 14.07,\n '4FW': 6.1,\n 'YCM': 5.32,\n 'MDF': 4.95,\n 'YCP': 3.01,\n 'TEF': 8.63,\n 'FGP': 4.34,\n 'UF0': 19.72,\n 'XCN': 4.57,\n 'FGL': 2.56,\n 'MF3': 6.37,\n 'MEQ': 5.13,\n 'LAA': 3.23,\n 'IGL': 5.52,\n 'MET': 4.49,\n 'NIY': 6.81,\n 'QCS': 5.18,\n 'TCQ': 8.56,\n 'MEN': 4.33,\n '4HL': 8.79,\n 'MEA': 4.95,\n 'EFC': 5.28,\n 'LAL': 2.41,\n '2HF': 5.52,\n 'KBE': 5.64,\n 'OCS': 3.94,\n 'CAF': 5.46,\n 'NC1': 11.4,\n 'NBQ': 9.82,\n 'CAB': 4.19,\n 'MBQ': 9.55,\n '193': 7.38,\n '192': 2.44,\n '0WZ': 7.61,\n 'CAS': 5.35,\n 'NB8': 11.98,\n 'OBS': 11.71,\n '1AC': 2.42,\n 'PCA': 3.48,\n 'MCL': 9.73,\n 'LBY': 7.75,\n 'GAU': 4.67,\n 'PBF': 9.75,\n 'MCG': 6.46,\n 'DDE': 6.86,\n '19W': 3.94,\n 'MD5': 9.33,\n 'MD6': 6.44,\n 'MD3': 8.41,\n 'MCS': 7.56,\n 'OBF': 3.64,\n 'UAL': 4.68,\n 'PAT': 6.05,\n 'IAM': 8.88,\n 'PAQ': 8.77,\n 'FDL': 9.49,\n 'NCB': 3.45,\n 'LCK': 9.81,\n 'DDZ': 2.52,\n '2FM': 5.54,\n 'IAR': 6.77,\n 'OAS': 4.8,\n 'HBN': 8.8,\n 'TA4': 5.55,\n '1C3': 7.43,\n 'ECX': 5.51,\n 'PF5': 6.28,\n 'RE3': 5.29,\n 'FCL': 6.25,\n 'ECC': 4.79,\n 'LDH': 7.06,\n 'NCY': 2.91,\n 'CCS': 4.58,\n 'PEC': 6.54,\n '2CO': 4.45,\n 'LE1': 2.72,\n 'HCM': 5.53,\n '07O': 8.05,\n 'HCL': 4.96,\n 'NEP': 6.94,\n 'PE1': 8.01,\n 'LEF': 4.37,\n 'FC0': 5.18,\n 'LED': 4.34,\n 'HCS': 4.09,\n 'DBU': 2.49,\n 'RE0': 5.53,\n 'LEN': 3.82,\n '1E3': 8.71,\n 'BB9': 2.56,\n 'BB8': 5.14,\n 'PCS': 5.05,\n 'BB7': 4.56,\n 'BB6': 2.62,\n 'LEU': 3.83,\n 'DBZ': 7.08,\n 'LET': 11.29,\n 'DBY': 6.46,\n 'ICY': 7.76,\n 'MAA': 2.4,\n 'CGA': 7.91,\n '5CS': 8.34,\n 'UGY': 3.7,\n 'LGY': 11.71,\n 'N10': 8.96,\n 'AAR': 6.39,\n 'FT6': 7.5,\n 'MOD': 12.62,\n '5CW': 7.21,\n 'PVH': 4.58,\n 'BBC': 6.42,\n 'YYA': 7.3,\n 'O12': 14.08,\n 'NOT': 7.15,\n 'KGC': 9.88,\n 'MP4': 5.86,\n '0CS': 4.07,\n 'MP8': 3.75,\n 'VLL': 2.54,\n 'VLM': 2.51,\n 'BCS': 8.03,\n 'MNL': 4.9,\n 'AA4': 4.47,\n 'SAC': 3.49,\n 'BCX': 2.99,\n '3CF': 6.47,\n 'SAH': 11.7,\n 'NNH': 6.86,\n 'CGU': 4.71,\n 'SIB': 12.41,\n 'TLY': 8.78,\n 'SIC': 4.81,\n 'VMS': 8.82,\n 'TMD': 6.76,\n 'MMO': 6.53,\n 'PXU': 2.46,\n '4AW': 6.22,\n 'OTH': 3.6,\n 'DLS': 6.84,\n 'MME': 4.99,\n 'DM0': 6.99,\n '0FL': 2.76,\n 'SBL': 8.96,\n 'CDV': 3.72,\n 'OTY': 6.51,\n 'PYA': 7.75,\n '2AS': 3.57,\n 'DMH': 4.92,\n 'ELY': 7.42,\n 'GVL': 9.6,\n 'FVA': 2.9,\n 'SAR': 2.48,\n '4BF': 6.92,\n 'EME': 4.69,\n 'CDE': 2.51,\n '3AR': 7.86,\n '3AH': 9.11,\n 'AC5': 2.44,\n 'FTR': 6.08,\n 'MLL': 3.76,\n 'NPH': 11.66,\n 'NPI': 6.9,\n 'DMT': 6.67,\n 'PYX': 11.3,\n 'MLE': 3.87,\n 'PYL': 9.67,\n 'ZZU': 6.94,\n 'H5M': 3.61,\n 'SCH': 4.46,\n 'DMK': 3.52,\n 'FTY': 9.07,\n '2AG': 3.7,\n 'ABA': 2.55,\n 'ZZJ': 2.44,\n 'MLZ': 6.8,\n 'MLY': 6.88,\n 'KCX': 7.28,\n 'ZZD': 8.16,\n '3A5': 5.37,\n 'LHC': 7.75,\n '9AT': 2.47,\n 'OZT': 3.4,\n 'THO': 2.62,\n 'THR': 2.5,\n 'DFI': 3.93,\n 'MKD': 6.42,\n '4CY': 4.6,\n 'SDP': 6.07,\n 'DFO': 3.94,\n '0A0': 3.45,\n '4DB': 9.73,\n 'ML3': 6.26,\n 'BG1': 8.02,\n 'SD4': 4.57,\n 'THC': 3.8,\n 'SCS': 5.48,\n 'TH5': 4.65,\n 'BFD': 5.33,\n 'AEI': 6.34,\n 'TH6': 2.85,\n 'SCY': 4.53,\n 'TIS': 4.81,\n 'SEE': 4.53,\n 'BHD': 3.48,\n 'SEB': 8.18,\n 'SEC': 2.96,\n 'SEP': 4.8,\n 'CLH': 7.13,\n 'TIH': 5.02,\n 'CLG': 13.62,\n 'SEN': 6.43,\n 'XXA': 7.34,\n 'SEL': 2.46,\n 'SE7': 4.19,\n '4CF': 7.72,\n 'G8M': 3.57,\n 'BH2': 3.51,\n 'UN2': 3.22,\n 'VR0': 10.51,\n 'MK8': 4.76,\n 'DHA': 2.32,\n 'LMQ': 4.69,\n 'SFE': 5.01,\n 'AHB': 3.47,\n 'OXX': 7.05,\n 'BIF': 9.63,\n 'IZO': 4.47,\n 'NMM': 8.25,\n '0BN': 7.0,\n 'HZP': 3.12,\n 'NMC': 4.23,\n 'DHL': 2.69,\n '9DS': 9.29,\n 'SER': 2.41,\n 'CHG': 4.2,\n 'MIR': 6.54,\n 'AGQ': 7.79,\n 'SET': 2.46,\n 'MIS': 6.32,\n '4FB': 3.08,\n '0AR': 8.46,\n 'LME': 3.99,\n 'FZN': 24.42,\n 'AGT': 9.04,\n 'IYR': 6.46,\n '9DN': 9.31,\n 'CHP': 5.75,\n 'UNK': 1.64,\n 'XX1': 9.92,\n 'AGM': 6.57,\n '0AH': 5.78,\n 'LLP': 10.22,\n '0AF': 6.72,\n '4DP': 9.28,\n 'HYP': 2.25,\n 'DIR': 5.8,\n 'LLY': 8.71,\n '0AK': 6.11,\n 'NLE': 4.67,\n 'OYL': 6.42,\n 'WVL': 4.69,\n '0A8': 8.1,\n 'NLY': 6.37,\n 'MHO': 4.89,\n 'VOL': 2.55,\n '0A1': 7.1,\n 'MHL': 3.92,\n 'NLP': 4.81,\n 'NLQ': 4.65,\n 'MHW': 2.74,\n 'BIL': 4.7,\n 'NLO': 4.8,\n 'MHU': 7.51,\n 'XW1': 9.36,\n 'LLO': 10.13,\n 'SGB': 6.88,\n 'MHV': 3.6,\n 'MHS': 4.51,\n '0A9': 5.17,\n '0LF': 9.96,\n 'HT7': 6.82,\n 'X2W': 6.6,\n 'YPZ': 9.38,\n 'I58': 6.73,\n 'FLA': 2.4,\n 'M0H': 4.83,\n 'HSL': 2.46,\n 'FLE': 6.17,\n 'KOR': 10.1,\n '1VR': 3.89,\n 'HSO': 4.56,\n 'TTS': 9.41,\n 'RVX': 7.01,\n 'TTQ': 7.71,\n 'H14': 5.27,\n 'HTI': 7.8,\n 'ONH': 6.14,\n 'LP6': 8.58,\n 'ONL': 4.83,\n 'AHH': 5.06,\n 'HS8': 7.4,\n 'HS9': 4.71,\n 'BL2': 5.82,\n 'AHP': 5.26,\n '6HN': 7.34,\n 'HRP': 5.46,\n 'POM': 3.6,\n 'WPA': 5.11,\n '2ZC': 4.29,\n 'CPC': 2.65,\n 'AIB': 2.4,\n 'XSN': 3.47,\n 'M2S': 5.28,\n 'GND': 6.67,\n 'GNC': 4.6,\n 'MVA': 2.56,\n 'OLZ': 5.32,\n 'M2L': 6.15,\n 'TRF': 6.69,\n 'NZH': 7.66,\n 'SRZ': 5.27,\n 'OLD': 10.47,\n 'CME': 5.86,\n 'CMH': 5.3,\n 'ALA': 2.38,\n 'TRQ': 7.36,\n 'PPN': 7.24,\n 'TRP': 6.07,\n 'TRO': 5.82,\n 'TRN': 5.95,\n 'NYS': 8.1,\n 'ALC': 5.26,\n 'U3X': 11.7,\n 'HVA': 2.58,\n 'TS9': 3.92,\n 'TRX': 7.27,\n 'TRW': 11.8,\n 'LPL': 7.51,\n 'GMA': 4.4,\n 'OMT': 5.07,\n 'CMT': 3.54,\n 'GME': 4.66,\n 'NYB': 6.07,\n 'PR3': 5.12,\n 'LPD': 2.48,\n 'GLU': 4.49,\n '1X6': 6.84,\n 'LPG': 2.39,\n 'GLX': 4.52,\n 'PR4': 4.52,\n 'CML': 6.16,\n 'FME': 4.52,\n 'HTR': 6.48,\n 'PR7': 4.66,\n 'Z3E': 7.2,\n 'GLZ': 2.39,\n 'BMT': 6.37,\n 'WRP': 8.16,\n 'GLY': 2.37,\n 'OMY': 6.11,\n 'MTY': 5.46,\n 'OMX': 6.15,\n 'GLN': 4.46,\n '2XA': 8.25,\n '28X': 7.84,\n '7JA': 9.46,\n 'FLT': 9.65,\n 'GLJ': 3.7,\n 'OMH': 5.26,\n 'TSY': 4.26,\n 'PRV': 4.28,\n 'CS4': 11.21,\n 'DOA': 12.33,\n '23P': 5.42,\n 'CS3': 8.24,\n '6CL': 6.47,\n 'PRR': 5.58,\n 'KST': 11.58,\n 'CS1': 7.23,\n 'PRS': 2.63,\n 'ZYJ': 11.4,\n 'IT1': 9.75,\n 'UU5': 4.98,\n 'ESB': 6.69,\n 'UU4': 2.49,\n 'ESC': 5.65,\n 'LSO': 10.58,\n 'ZYK': 11.45,\n '9NV': 8.99,\n '23F': 5.27,\n 'ORN': 4.25,\n 'HOX': 6.61,\n 'CSD': 3.95,\n 'FP9': 3.03,\n 'DO2': 4.44,\n 'SLL': 11.53,\n 'P3Q': 9.54,\n 'ORQ': 6.04,\n 'MSL': 5.21,\n 'DNP': 2.45,\n 'CSB': 3.51,\n 'WLU': 4.24,\n 'CSA': 5.7,\n 'MT2': 5.51,\n 'CSO': 3.53,\n 'TPO': 4.73,\n 'MSP': 13.11,\n '23S': 6.09,\n 'MSO': 4.96,\n 'PRO': 2.41,\n 'TPL': 5.41,\n 'DNS': 8.79,\n 'CSK': 3.91,\n 'Z70': 7.4,\n 'CSJ': 7.51,\n 'DNW': 7.97,\n 'PRK': 9.15,\n 'GSU': 11.81,\n 'LTA': 6.57,\n 'HPE': 6.63,\n 'TPQ': 6.48,\n 'PRJ': 5.26,\n 'PSW': 4.65,\n 'L3O': 3.89,\n 'CSU': 4.89,\n 'ALY': 7.38,\n 'M3L': 7.12,\n 'CSW': 3.68,\n 'XPR': 7.68,\n 'D4P': 5.66,\n 'FOE': 8.17,\n 'SLZ': 5.69,\n 'CSP': 5.26,\n 'TQI': 7.68,\n 'ALT': 2.72,\n 'CSR': 5.42,\n 'CSS': 3.61,\n 'M3R': 7.18,\n 'ALO': 2.57,\n 'R4K': 4.67,\n 'SMF': 9.0,\n 'MSA': 2.73,\n 'SMC': 3.39,\n 'CSX': 3.47,\n 'SME': 4.8,\n 'ETA': 2.4,\n 'CSZ': 3.6,\n '22G': 8.8,\n 'MSE': 4.62,\n 'ALN': 6.16,\n 'PSH': 7.26,\n 'CTE': 7.27,\n 'DON': 6.72,\n 'CTH': 3.45,\n 'U2X': 11.54,\n '6CW': 7.56,\n 'TQZ': 6.97,\n '3YM': 6.52,\n 'OSE': 4.49,\n '2VA': 9.82,\n 'TQQ': 7.76,\n 'NRG': 8.35,\n 'BPE': 7.24,\n 'F2F': 6.25,\n '1TQ': 8.58,\n 'I2M': 3.13,\n 'NVA': 3.76,\n 'R1A': 8.2,\n 'QPA': 6.95,\n 'C1X': 11.63,\n 'FRD': 5.05,\n 'HR7': 6.98,\n 'SNC': 3.93,\n 'QPH': 5.15,\n '26B': 8.39,\n 'DPQ': 6.54,\n 'DPP': 2.51,\n '2TY': 8.65,\n 'TNR': 6.88,\n 'PTH': 8.35,\n 'DPL': 3.58,\n 'APK': 8.79,\n '1TY': 8.84,\n 'HRG': 7.36,\n 'PTM': 8.74,\n '1U8': 3.62,\n 'PTR': 8.64,\n 'LVG': 3.01,\n '6FL': 4.85,\n 'SOC': 4.05,\n 'KPI': 9.79,\n 'IPG': 2.91,\n 'P2Y': 2.51,\n 'N2C': 3.55,\n 'T0I': 7.34,\n 'MPH': 5.29,\n 'R2T': 4.71,\n 'TOX': 6.78,\n 'P2Q': 9.8,\n 'GPL': 10.77,\n 'MPJ': 5.07,\n 'F2Y': 6.2,\n 'T11': 8.58,\n '9NR': 9.33,\n 'FPR': 8.85,\n '9NF': 8.93,\n 'KPY': 10.17,\n '9NE': 9.77,\n 'TOQ': 7.5,\n 'MPQ': 4.2,\n 'FPK': 3.08,\n 'HQA': 7.25,\n 'SOY': 10.94\n}\nexport const DefaultResidueRadius = 5.0\n\n// http://dx.doi.org/10.1039/b801115j (or 1.6)\nexport const CovalentRadii: { [e: number]: number | undefined } = {\n 1: 0.31, 2: 0.28, 3: 1.28, 4: 0.96, 5: 0.84, 6: 0.76, 7: 0.71, 8: 0.66, 9: 0.57, 10: 0.58, 11: 1.66, 12: 1.41, 13: 1.21, 14: 1.11, 15: 1.07, 16: 1.05, 17: 1.02, 18: 1.06, 19: 2.03, 20: 1.76, 21: 1.7, 22: 1.6, 23: 1.53, 24: 1.39, 25: 1.39, 26: 1.32, 27: 1.26, 28: 1.24, 29: 1.32, 30: 1.22, 31: 1.22, 32: 1.2, 33: 1.19, 34: 1.2, 35: 1.2, 36: 1.16, 37: 2.2, 38: 1.95, 39: 1.9, 40: 1.75, 41: 1.64, 42: 1.54, 43: 1.47, 44: 1.46, 45: 1.42, 46: 1.39, 47: 1.45, 48: 1.44, 49: 1.42, 50: 1.39, 51: 1.39, 52: 1.38, 53: 1.39, 54: 1.4, 55: 2.44, 56: 2.15, 57: 2.07, 58: 2.04, 59: 2.03, 60: 2.01, 61: 1.99, 62: 1.98, 63: 1.98, 64: 1.96, 65: 1.94, 66: 1.92, 67: 1.92, 68: 1.89, 69: 1.9, 70: 1.87, 71: 1.87, 72: 1.75, 73: 1.7, 74: 1.62, 75: 1.51, 76: 1.44, 77: 1.41, 78: 1.36, 79: 1.36, 80: 1.32, 81: 1.45, 82: 1.46, 83: 1.48, 84: 1.4, 85: 1.5, 86: 1.5, 87: 2.6, 88: 2.21, 89: 2.15, 90: 2.06, 91: 2.0, 92: 1.96, 93: 1.9, 94: 1.87, 95: 1.8, 96: 1.69, 97: 1.6, 98: 1.6, 99: 1.6, 100: 1.6, 101: 1.6, 102: 1.6, 103: 1.6, 104: 1.6, 105: 1.6, 106: 1.6, 107: 1.6, 108: 1.6, 109: 1.6, 110: 1.6, 111: 1.6, 112: 1.6, 113: 1.6, 114: 1.6, 115: 1.6, 116: 1.6, 117: 1.6, 118: 1.6\n}\nexport const DefaultCovalentRadius = 1.6\n\nexport const Valences: { [e: number]: number[] | undefined } = {\n 1: [ 1 ],\n 2: [ 0 ],\n 3: [ 1 ],\n 4: [ 2 ],\n 5: [ 3 ],\n 6: [ 4 ],\n 7: [ 3 ],\n 8: [ 2 ],\n 9: [ 1 ],\n 10: [ 0 ],\n 11: [ 1 ],\n 12: [ 2 ],\n 13: [ 6 ],\n 14: [ 6 ],\n 15: [ 3, 5, 7 ],\n 16: [ 2, 4, 6 ],\n 17: [ 1 ],\n 18: [ 0 ],\n 19: [ 1 ],\n 20: [ 2 ],\n\n 31: [ 3 ],\n 32: [ 4 ],\n 33: [ 3, 5 ],\n 34: [ 2, 4, 6 ],\n 35: [ 1 ],\n 36: [ 0 ],\n 37: [ 1 ],\n 38: [ 2 ],\n\n 49: [ 3 ],\n 50: [ 4 ],\n 51: [ 3, 5 ],\n 52: [ 2 ],\n 53: [ 1, 2, 5 ],\n 54: [ 0, 2 ],\n 55: [ 1 ],\n 56: [ 2 ],\n\n 81: [ 3 ],\n 82: [ 4 ],\n 83: [ 3 ],\n 84: [ 2 ],\n 85: [ 1 ],\n 86: [ 0 ],\n 87: [ 1 ],\n 88: [ 2 ]\n}\nexport const DefaultValence = -1\n\nexport const OuterShellElectronCounts: { [e: number]: number | undefined } = {\n1: 1, 2: 2, 3: 1, 4: 2, 5: 3, 6: 4, 7: 5, 8: 6, 9: 7, 10: 8, 11: 1, 12: 2, 13: 3, 14: 4, 15: 5, 16: 6, 17: 7, 18: 8, 19: 1, 20: 2, 21: 3, 22: 4, 23: 5, 24: 6, 25: 7, 26: 8, 27: 9, 28: 10, 29: 11, 30: 2, 31: 3, 32: 4, 33: 5, 34: 6, 35: 7, 36: 8, 37: 1, 38: 2, 39: 3, 40: 4, 41: 5, 42: 6, 43: 7, 44: 8, 45: 9, 46: 10, 47: 11, 48: 2, 49: 3, 50: 4, 51: 5, 52: 6, 53: 7, 54: 8, 55: 1, 56: 2, 57: 3, 58: 4, 59: 3, 60: 4, 61: 5, 62: 6, 63: 7, 64: 8, 65: 9, 66: 10, 67: 11, 68: 12, 69: 13, 70: 14, 71: 15, 72: 4, 73: 5, 74: 6, 75: 7, 76: 8, 77: 9, 78: 10, 79: 11, 80: 2, 81: 3, 82: 4, 83: 5, 84: 6, 85: 7, 86: 8, 87: 1, 88: 2, 89: 3, 90: 4, 91: 3, 92: 4, 93: 5, 94: 6, 95: 7, 96: 8, 97: 9, 98: 10, 99: 11, 100: 12, 101: 13, 102: 14, 103: 15, 104: 2, 105: 2, 106: 2, 107: 2, 108: 2, 109: 2, 110: 2, 111: 2, 112: 2, 113: 3, 114: 4, 115: 5, 116: 6, 117: 7, 118: 8\n}\nexport const DefaultOuterShellElectronCount = 2\n\n// http://blanco.biomol.uci.edu/Whole_residue_HFscales.txt\n// https://www.nature.com/articles/nsb1096-842\nexport const ResidueHydrophobicity: { [k: string]: [number, number, number] } = {\n // AA DGwif DGwoct Oct-IF\n 'ALA': [ 0.17, 0.50, 0.33 ],\n 'ARG': [ 0.81, 1.81, 1.00 ],\n 'ASN': [ 0.42, 0.85, 0.43 ],\n 'ASP': [ 1.23, 3.64, 2.41 ],\n 'ASH': [ -0.07, 0.43, 0.50 ],\n 'CYS': [ -0.24, -0.02, 0.22 ],\n 'GLN': [ 0.58, 0.77, 0.19 ],\n 'GLU': [ 2.02, 3.63, 1.61 ],\n 'GLH': [ -0.01, 0.11, 0.12 ],\n 'GLY': [ 0.01, 1.15, 1.14 ],\n // \"His+\": [ 0.96, 2.33, 1.37 ],\n 'HIS': [ 0.17, 0.11, -0.06 ],\n 'ILE': [ -0.31, -1.12, -0.81 ],\n 'LEU': [ -0.56, -1.25, -0.69 ],\n 'LYS': [ 0.99, 2.80, 1.81 ],\n 'MET': [ -0.23, -0.67, -0.44 ],\n 'PHE': [ -1.13, -1.71, -0.58 ],\n 'PRO': [ 0.45, 0.14, -0.31 ],\n 'SER': [ 0.13, 0.46, 0.33 ],\n 'THR': [ 0.14, 0.25, 0.11 ],\n 'TRP': [ -1.85, -2.09, -0.24 ],\n 'TYR': [ -0.94, -0.71, 0.23 ],\n 'VAL': [ 0.07, -0.46, -0.53 ]\n}\nexport const DefaultResidueHydrophobicity = [ 0.00, 0.00, 0.00 ]\n\nexport const AA1: { [k: string]: string } = {\n 'HIS': 'H',\n 'ARG': 'R',\n 'LYS': 'K',\n 'ILE': 'I',\n 'PHE': 'F',\n 'LEU': 'L',\n 'TRP': 'W',\n 'ALA': 'A',\n 'MET': 'M',\n 'PRO': 'P',\n 'CYS': 'C',\n 'ASN': 'N',\n 'VAL': 'V',\n 'GLY': 'G',\n 'SER': 'S',\n 'GLN': 'Q',\n 'TYR': 'Y',\n 'ASP': 'D',\n 'GLU': 'E',\n 'THR': 'T',\n\n 'SEC': 'U', // as per IUPAC definition\n 'PYL': 'O', // as per IUPAC definition\n}\n\nexport const AA3 = Object.keys(AA1)\n\nexport const RnaBases = [ 'A', 'C', 'T', 'G', 'U', 'I' ]\n\nexport const DnaBases = [ 'DA', 'DC', 'DT', 'DG', 'DU', 'DI' ]\n\nexport const PurinBases = [ 'A', 'G', 'I', 'DA', 'DG', 'DI' ]\n\nexport const Bases = RnaBases.concat(DnaBases)\n\nexport const WaterNames = [\n 'SOL', 'WAT', 'HOH', 'H2O', 'W', 'DOD', 'D3O', 'TIP3', 'TIP4', 'SPC'\n]\n\n// all chemical components with the word \"ion\" in their name, Sep 2016\n//\n// SET SESSION group_concat_max_len = 1000000;\n// SELECT GROUP_CONCAT(id_ ORDER BY id_ ASC SEPARATOR '\", \"') from\n// (\n// SELECT count(obj_id) as c, id_\n// FROM pdb.chem_comp WHERE name LIKE \"% ION%\"\n// GROUP BY id_\n// ) AS t1;\nexport const IonNames = [\n '118', '119', '1AL', '1CU', '2FK', '2HP', '2OF', '3CO',\n '3MT', '3NI', '3OF', '3P8', '4MO', '4PU', '543', '6MO', 'ACT', 'AG', 'AL',\n 'ALF', 'AM', 'ATH', 'AU', 'AU3', 'AUC', 'AZI', 'BA', 'BCT', 'BEF', 'BF4', 'BO4',\n 'BR', 'BS3', 'BSY', 'CA', 'CAC', 'CD', 'CD1', 'CD3', 'CD5', 'CE', 'CHT', 'CL',\n 'CO', 'CO3', 'CO5', 'CON', 'CR', 'CS', 'CSB', 'CU', 'CU1', 'CU3', 'CUA', 'CUZ',\n 'CYN', 'DME', 'DMI', 'DSC', 'DTI', 'DY', 'E4N', 'EDR', 'EMC', 'ER3', 'EU',\n 'EU3', 'F', 'FE', 'FE2', 'FPO', 'GA', 'GD3', 'GEP', 'HAI', 'HG', 'HGC', 'IN',\n 'IOD', 'IR', 'IR3', 'IRI', 'IUM', 'K', 'KO4', 'LA', 'LCO', 'LCP', 'LI', 'LU',\n 'MAC', 'MG', 'MH2', 'MH3', 'MLI', 'MLT', 'MMC', 'MN', 'MN3', 'MN5', 'MN6',\n 'MO1', 'MO2', 'MO3', 'MO4', 'MO5', 'MO6', 'MOO', 'MOS', 'MOW', 'MW1', 'MW2',\n 'MW3', 'NA', 'NA2', 'NA5', 'NA6', 'NAO', 'NAW', 'NCO', 'NET', 'NH4', 'NI',\n 'NI1', 'NI2', 'NI3', 'NO2', 'NO3', 'NRU', 'O4M', 'OAA', 'OC1', 'OC2', 'OC3',\n 'OC4', 'OC5', 'OC6', 'OC7', 'OC8', 'OCL', 'OCM', 'OCN', 'OCO', 'OF1', 'OF2',\n 'OF3', 'OH', 'OS', 'OS4', 'OXL', 'PB', 'PBM', 'PD', 'PDV', 'PER', 'PI', 'PO3',\n 'PO4', 'PR', 'PT', 'PT4', 'PTN', 'RB', 'RH3', 'RHD', 'RU', 'SB', 'SCN', 'SE4',\n 'SEK', 'SM', 'SMO', 'SO3', 'SO4', 'SR', 'T1A', 'TB', 'TBA', 'TCN', 'TEA', 'TH',\n 'THE', 'TL', 'TMA', 'TRA', 'UNX', 'V', 'VN3', 'VO4', 'W', 'WO5', 'Y1', 'YB',\n 'YB2', 'YH', 'YT3', 'ZCM', 'ZN', 'ZN2', 'ZN3', 'ZNO', 'ZO3',\n // additional ion names\n 'OHX'\n]\n\n// all chemical components with the word \"%saccharide%\" in their type, Sep 2016\n//\n// SET SESSION group_concat_max_len = 1000000;\n// select GROUP_CONCAT(id_ ORDER BY id_ ASC SEPARATOR '\", \"') from\n// (\n// SELECT count(obj_id), id_\n// FROM pdb.chem_comp WHERE type like \"%SACCHARIDE%\"\n// GROUP BY id_\n// ) AS t1;\nexport const SaccharideNames = [\n '045', '0AT', '0BD', '0MK', '0NZ', '0TS', '0V4', '0XY', '0YT', '10M',\n '147', '149', '14T', '15L', '16G', '18T', '18Y', '1AR', '1BW', '1GL', '1GN',\n '1JB', '1LL', '1NA', '1S3', '26M', '26Q', '26R', '26V', '26W', '26Y', '27C',\n '289', '291', '293', '2DG', '2F8', '2FG', '2FL', '2FP', '2GL', '2M4', '2M5',\n '32O', '34V', '3CM', '3DO', '3DY', '3FM', '3LR', '3MF', '3MG', '3SA', '3ZW',\n '46D', '46M', '46Z', '48Z', '4CQ', '4GC', '4NN', '50A', '5DI', '5GF', '5MM',\n '5RP', '5SA', '5SP', '64K', '6PG', '6SA', '7JZ', '7SA', 'A1Q', 'A2G', 'AAB',\n 'AAL', 'AAO', 'ABC', 'ABD', 'ABE', 'ABF', 'ABL', 'ACG', 'ACI', 'ACR', 'ACX',\n 'ADA', 'ADG', 'ADR', 'AF1', 'AFD', 'AFL', 'AFO', 'AFP', 'AFR', 'AGC', 'AGH',\n 'AGL', 'AHR', 'AIG', 'ALL', 'ALX', 'AMU', 'AOG', 'AOS', 'ARA', 'ARB', 'ARE',\n 'ARI', 'ASG', 'ASO', 'AXP', 'AXR', 'B0D', 'B16', 'B2G', 'B4G', 'B6D', 'B8D',\n 'B9D', 'BBK', 'BCD', 'BDG', 'BDP', 'BDR', 'BEM', 'BFP', 'BGC', 'BGL', 'BGP',\n 'BGS', 'BHG', 'BMA', 'BMX', 'BNG', 'BNX', 'BOG', 'BRI', 'BXF', 'BXP', 'BXX',\n 'BXY', 'C3X', 'C4X', 'C5X', 'CAP', 'CBI', 'CBK', 'CBS', 'CDR', 'CEG', 'CGF',\n 'CHO', 'CR1', 'CR6', 'CRA', 'CT3', 'CTO', 'CTR', 'CTT', 'D6G', 'DAF', 'DAG',\n 'DDA', 'DDB', 'DDL', 'DEL', 'DFR', 'DFX', 'DG0', 'DGC', 'DGD', 'DGM', 'DGS',\n 'DIG', 'DLF', 'DLG', 'DMU', 'DNO', 'DOM', 'DP5', 'DQQ', 'DQR', 'DR2', 'DR3',\n 'DR4', 'DRI', 'DSR', 'DT6', 'DVC', 'E4P', 'E5G', 'EAG', 'EBG', 'EBQ', 'EGA',\n 'EJT', 'EPG', 'ERE', 'ERI', 'F1P', 'F1X', 'F6P', 'FBP', 'FCA', 'FCB', 'FCT',\n 'FDP', 'FDQ', 'FFC', 'FIX', 'FMO', 'FRU', 'FSI', 'FU4', 'FUB', 'FUC', 'FUD',\n 'FUL', 'FXP', 'G16', 'G1P', 'G2F', 'G3I', 'G4D', 'G4S', 'G6D', 'G6P', 'G6S',\n 'GAC', 'GAD', 'GAL', 'GC1', 'GC4', 'GCD', 'GCN', 'GCO', 'GCS', 'GCT', 'GCU',\n 'GCV', 'GCW', 'GCX', 'GE1', 'GFG', 'GFP', 'GIV', 'GL0', 'GL2', 'GL5', 'GL6',\n 'GL7', 'GL9', 'GLA', 'GLB', 'GLC', 'GLD', 'GLF', 'GLG', 'GLO', 'GLP', 'GLS',\n 'GLT', 'GLW', 'GMH', 'GN1', 'GNX', 'GP1', 'GP4', 'GPH', 'GPM', 'GQ1', 'GQ2',\n 'GQ4', 'GS1', 'GS4', 'GSA', 'GSD', 'GTE', 'GTH', 'GTK', 'GTR', 'GTZ', 'GU0',\n 'GU1', 'GU2', 'GU3', 'GU4', 'GU5', 'GU6', 'GU8', 'GU9', 'GUF', 'GUP', 'GUZ',\n 'GYP', 'GYV', 'H2P', 'HDL', 'HMS', 'HS2', 'HSD', 'HSG', 'HSH', 'HSJ', 'HSQ',\n 'HSR', 'HSU', 'HSX', 'HSY', 'HSZ', 'IAB', 'IDG', 'IDR', 'IDS', 'IDT', 'IDU',\n 'IDX', 'IDY', 'IMK', 'IN1', 'IPT', 'ISL', 'KBG', 'KD2', 'KDA', 'KDM', 'KDO',\n 'KFN', 'KO1', 'KO2', 'KTU', 'L6S', 'LAG', 'LAI', 'LAK', 'LAO', 'LAT', 'LB2',\n 'LBT', 'LCN', 'LDY', 'LGC', 'LGU', 'LM2', 'LMT', 'LMU', 'LOG', 'LOX', 'LPK',\n 'LSM', 'LTM', 'LVZ', 'LXB', 'LXZ', 'M1F', 'M3M', 'M6P', 'M8C', 'MA1', 'MA2',\n 'MA3', 'MAB', 'MAG', 'MAL', 'MAN', 'MAT', 'MAV', 'MAW', 'MBG', 'MCU', 'MDA',\n 'MDM', 'MDP', 'MFA', 'MFB', 'MFU', 'MG5', 'MGA', 'MGL', 'MLB', 'MMA', 'MMN',\n 'MN0', 'MRP', 'MTT', 'MUG', 'MVP', 'MXY', 'N1L', 'N9S', 'NAA', 'NAG', 'NBG',\n 'NDG', 'NED', 'NG1', 'NG6', 'NGA', 'NGB', 'NGC', 'NGE', 'NGF', 'NGL', 'NGS',\n 'NGY', 'NHF', 'NM6', 'NM9', 'NTF', 'NTO', 'NTP', 'NXD', 'NYT', 'OPG', 'OPM',\n 'ORP', 'OX2', 'P3M', 'P53', 'P6P', 'PA5', 'PNA', 'PNG', 'PNW', 'PRP', 'PSJ',\n 'PSV', 'PTQ', 'QDK', 'QPS', 'QV4', 'R1P', 'R1X', 'R2B', 'R5P', 'RAA', 'RAE',\n 'RAF', 'RAM', 'RAO', 'RAT', 'RB5', 'RBL', 'RCD', 'RDP', 'REL', 'RER', 'RF5',\n 'RG1', 'RGG', 'RHA', 'RIB', 'RIP', 'RNS', 'RNT', 'ROB', 'ROR', 'RPA', 'RST',\n 'RUB', 'RUU', 'RZM', 'S6P', 'S7P', 'SA0', 'SCR', 'SDD', 'SF6', 'SF9', 'SG4',\n 'SG5', 'SG6', 'SG7', 'SGA', 'SGC', 'SGD', 'SGN', 'SGS', 'SHB', 'SHG', 'SI3',\n 'SIO', 'SOE', 'SOL', 'SSG', 'SUC', 'SUP', 'SUS', 'T6P', 'T6T', 'TAG', 'TCB',\n 'TDG', 'TGK', 'TGY', 'TH1', 'TIA', 'TM5', 'TM6', 'TM9', 'TMR', 'TMX', 'TOA',\n 'TOC', 'TRE', 'TYV', 'UCD', 'UDC', 'VG1', 'X0X', 'X1X', 'X2F', 'X4S', 'X5S',\n 'X6X', 'XBP', 'XDN', 'XDP', 'XIF', 'XIM', 'XLF', 'XLS', 'XMM', 'XUL', 'XXR',\n 'XYP', 'XYS', 'YO5', 'Z3Q', 'Z6J', 'Z9M', 'ZDC', 'ZDM'\n]\n\nexport const ProteinBackboneAtoms = [\n 'CA', 'C', 'N', 'O',\n 'O1', 'O2', 'OC1', 'OC2', 'OX1', 'OXT', 'OT1', 'OT2',\n 'H', 'H1', 'H2', 'H3', 'HA', 'HN',\n 'BB'\n]\n\nexport const NucleicBackboneAtoms = [\n 'P', 'OP1', 'OP2', 'HOP2', 'HOP3',\n \"O2'\", \"O3'\", \"O4'\", \"O5'\", \"C1'\", \"C2'\", \"C3'\", \"C4'\", \"C5'\",\n \"H1'\", \"H2'\", \"H2''\", \"HO2'\", \"H3'\", \"H4'\", \"H5'\", \"H5''\", \"HO3'\", \"HO5'\",\n 'O2*', 'O3*', 'O4*', 'O5*', 'C1*', 'C2*', 'C3*', 'C4*', 'C5*'\n]\n\nexport const ResidueTypeAtoms: { [k: number]: { [k: string]: string|string[] } } = {}\n\nResidueTypeAtoms[ ProteinBackboneType ] = {\n trace: 'CA',\n direction1: 'C',\n direction2: [ 'O', 'OC1', 'O1', 'OX1', 'OXT', 'OT1', 'OT2' ],\n backboneStart: 'N',\n backboneEnd: 'C'\n}\n\nResidueTypeAtoms[ RnaBackboneType ] = {\n trace: [ \"C4'\", 'C4*' ],\n direction1: [ \"C1'\", 'C1*' ],\n direction2: [ \"C3'\", 'C3*' ],\n backboneStart: 'P',\n backboneEnd: [ \"O3'\", 'O3*' ]\n}\n\nResidueTypeAtoms[ DnaBackboneType ] = {\n trace: [ \"C3'\", 'C3*' ],\n direction1: [ \"C2'\", 'C2*' ],\n direction2: [ \"O4'\", 'O4*' ],\n backboneStart: 'P',\n backboneEnd: [ \"O3'\", 'O3*' ]\n}\n\nResidueTypeAtoms[ CgProteinBackboneType ] = {\n trace: [ 'CA', 'BB' ],\n backboneStart: [ 'CA', 'BB' ],\n backboneEnd: [ 'CA', 'BB' ]\n}\n\nResidueTypeAtoms[ CgRnaBackboneType ] = {\n trace: [ \"C4'\", 'C4*', 'P' ],\n backboneStart: [ \"C4'\", 'C4*', 'P' ],\n backboneEnd: [ \"C4'\", 'C4*', 'P' ]\n}\n\nResidueTypeAtoms[ CgDnaBackboneType ] = {\n trace: [ \"C3'\", 'C3*', \"C2'\", 'P' ], // C2' is used in martini ff\n backboneStart: [ \"C3'\", 'C3*', \"C2'\", 'P' ],\n backboneEnd: [ \"C3'\", 'C3*', \"C2'\", 'P' ]\n}\n\nResidueTypeAtoms[ UnknownBackboneType ] = {}\n\n// Mappings taken from Meeko: https://github.com/forlilab/Meeko/blob/develop/meeko/utils/autodock4_atom_types_elements.py\nexport const PDBQTSpecialElements = {\n 'HD': 'H',\n 'HS': 'H',\n 'A': 'C',\n 'NA': 'N',\n 'NS': 'N',\n 'OA': 'O',\n 'OS': 'O',\n 'SA': 'S',\n 'G0': 'C',\n 'G1': 'C',\n 'G2': 'C',\n 'G3': 'C',\n 'CG0': 'C',\n 'CG1': 'C',\n 'CG2': 'C',\n 'CG3': 'C',\n 'W': 'O'\n}","/**\n * @file Geometry\n * @author Fred Ludlow \n * @author Alexander Rose \n */\n\nimport { Vector3 } from 'three'\n\nimport { Elements } from '../structure/structure-constants'\nimport { degToRad } from '../math/math-utils'\nimport AtomProxy from '../proxy/atom-proxy'\n\n// Changed numbering so they're mostly inline with coordination number\n// from VSEPR\nexport const enum AtomGeometry {\n Spherical = 0,\n Terminal = 1,\n Linear = 2,\n Trigonal = 3,\n Tetrahedral = 4,\n TrigonalBiPyramidal = 5,\n Octahedral = 6,\n SquarePlanar = 7, // Okay, it breaks down somewhere!\n Unknown = 8\n}\n\nexport function assignGeometry (totalCoordination: number): AtomGeometry {\n switch(totalCoordination){\n case 0:\n return AtomGeometry.Spherical\n case 1:\n return AtomGeometry.Terminal\n case 2:\n return AtomGeometry.Linear\n case 3:\n return AtomGeometry.Trigonal\n case 4:\n return AtomGeometry.Tetrahedral\n default:\n return AtomGeometry.Unknown\n }\n}\n\nexport const Angles = new Map([\n [ AtomGeometry.Linear, degToRad(180) ],\n [ AtomGeometry.Trigonal, degToRad(120) ],\n [ AtomGeometry.Tetrahedral, degToRad(109.4721) ],\n [ AtomGeometry.Octahedral, degToRad(90) ]\n])\n\n/**\n * Calculate the angles x-1-2 for all x where x is a heavy atom bonded to ap1.\n * @param {AtomProxy} ap1 First atom (angle centre)\n * @param {AtomProxy} ap2 Second atom\n * @return {number[]} Angles in radians\n */\nexport function calcAngles (ap1: AtomProxy, ap2: AtomProxy): number[] {\n let angles: number[] = []\n const d1 = new Vector3()\n const d2 = new Vector3()\n d1.subVectors(ap2 as any, ap1 as any)\n ap1.eachBondedAtom( x => {\n if (x.number !== Elements.H) {\n d2.subVectors(x as any, ap1 as any)\n angles.push(d1.angleTo(d2))\n }\n })\n return angles\n}\n\n/**\n * Find two neighbours of ap1 to define a plane (if possible) and\n * measure angle out of plane to ap2\n * @param {AtomProxy} ap1 First atom (angle centre)\n * @param {AtomProxy} ap2 Second atom (out-of-plane)\n * @return {number} Angle from plane to second atom\n */\nexport function calcPlaneAngle (ap1: AtomProxy, ap2: AtomProxy): number | undefined {\n const x1 = ap1.clone()\n\n const v12 = new Vector3()\n v12.subVectors(ap2 as any, ap1 as any)\n\n const neighbours = [new Vector3(), new Vector3()]\n let ni = 0\n ap1.eachBondedAtom( x => {\n if (ni > 1) { return }\n if (x.number !== Elements.H) {\n x1.index = x.index\n neighbours[ni++].subVectors(x as any, ap1 as any)\n }\n })\n if (ni === 1) {\n x1.eachBondedAtom( x => {\n if (ni > 1) { return }\n if (x.number !== Elements.H && x.index !== ap1.index){\n neighbours[ni++].subVectors(x as any, ap1 as any)\n }\n })\n }\n if (ni !== 2) {\n return\n }\n\n const cp = neighbours[0].cross(neighbours[1])\n return Math.abs((Math.PI / 2) - cp.angleTo(v12))\n}\n","/**\n * @file Valence Model\n * @author Fred Ludlow \n * @author Alexander Rose \n */\n\n/**\n * Reworked ValenceModel\n *\n * TODO:\n * Ensure proper treatment of disorder/models. e.g. V257 N in 5vim\n * Formal charge of 255 for SO4 anion (e.g. 5ghl)\n * Have removed a lot of explicit features (as I think they're more\n * generally captured by better VM).\n * Could we instead have a \"delocalised negative/positive\" charge\n * feature and flag these up?\n *\n */\nimport { Data } from '../structure/data'\nimport AtomProxy from '../proxy/atom-proxy'\nimport { AtomGeometry, assignGeometry } from './geometry'\nimport { Elements } from '../structure/structure-constants'\n\n/**\n * Are we involved in some kind of pi system. Either explicitly forming\n * double bond or N, O next to a double bond, except:\n *\n * N,O with degree 4 cannot be conjugated.\n * N,O adjacent to P=O or S=O do not qualify (keeps sulfonamide N sp3 geom)\n */\nfunction isConjugated (a: AtomProxy) {\n const _bp = a.structure.getBondProxy()\n const atomicNumber = a.number\n const hetero = atomicNumber === Elements.O || atomicNumber === Elements.N\n\n if (hetero && a.bondCount === 4) {\n return false\n }\n\n let flag = false\n\n a.eachBond(b => {\n if (b.bondOrder > 1) {\n flag = true\n return\n }\n if (hetero) {\n const a2 = b.getOtherAtom(a)\n\n a2.eachBond(b2 => {\n if (b2.bondOrder > 1) {\n const atomicNumber2 = a2.number\n if (\n (atomicNumber2 === Elements.P || atomicNumber2 === Elements.S) &&\n b2.getOtherAtom(a2).number === Elements.O\n ) {\n return\n }\n flag = true\n }\n }, _bp) // Avoid reuse of structure._bp\n }\n })\n\n return flag\n}\n\n/* function hasExplicitCharge(r: ResidueProxy) {\n let flag = false\n r.eachAtom(a => {\n if (a.formalCharge != null && a.formalCharge !== 0) flag = true\n })\n return flag\n}\n\nfunction hasExplicitHydrogen(r: ResidueProxy) {\n let flag = false\n r.eachAtom(a => {\n if (a.number === Elements.H) flag = true\n })\n return flag\n} */\n\nexport function explicitValence (a: AtomProxy) {\n let v = 0\n a.eachBond(b => v += b.bondOrder)\n return v\n}\n\n/**\n * Attempts to produce a consistent charge and implicit\n * H-count for an atom.\n *\n * If both params.assignCharge and params.assignH, this\n * approximately followsthe rules described in\n * https://docs.eyesopen.com/toolkits/python/oechemtk/valence.html#openeye-hydrogen-count-model\n *\n * If only charge or hydrogens are to be assigned it takes\n * a much simpler view and deduces one from the other\n *\n * @param {AtomProxy} a Atom to analyze\n * @param {assignChargeHParams} params What to assign\n */\nexport function calculateHydrogensCharge (a: AtomProxy, params: ValenceModelParams) {\n const hydrogenCount = a.bondToElementCount(Elements.H)\n let charge = a.formalCharge || 0\n\n const assignCharge = (params.assignCharge === 'always' ||\n (params.assignCharge === 'auto' && charge === 0))\n const assignH = (params.assignH === 'always' ||\n (params.assignH === 'auto' && hydrogenCount === 0))\n\n const degree = a.bondCount\n const valence = explicitValence(a)\n\n const conjugated = isConjugated(a)\n const multiBond = (valence - degree > 0)\n\n\n let implicitHCount = 0\n let geom = AtomGeometry.Unknown\n\n switch (a.number) {\n case Elements.H:\n if (assignCharge){\n if (degree === 0){\n charge = 1\n geom = AtomGeometry.Spherical\n } else if (degree === 1) {\n charge = 0\n geom = AtomGeometry.Terminal\n }\n }\n break\n\n case Elements.C:\n // TODO: Isocyanide?\n if (assignCharge) {\n charge = 0 // Assume carbon always neutral\n }\n if (assignH) {\n // Carbocation/carbanion are 3-valent\n implicitHCount = Math.max(0, 4 - valence - Math.abs(charge))\n }\n // Carbocation is planar, carbanion is tetrahedral\n geom = assignGeometry(degree + implicitHCount + Math.max(0, -charge))\n break\n\n case Elements.N:\n if (assignCharge) {\n if (!assignH) { // Trust input H explicitly:\n charge = valence - 3\n } else if (conjugated && valence < 4) {\n // Neutral unless amidine/guanidine double-bonded N:\n if (degree - hydrogenCount === 1 && valence - hydrogenCount === 2) {\n charge = 1\n } else {\n charge = 0\n }\n } else {\n // Sulfonamide nitrogen and classed as sp3 in conjugation model but\n // they won't be charged\n // Don't assign charge to nitrogens bound to metals\n let flag = false\n a.eachBondedAtom(ba => {\n if (ba.number === Elements.S || ba.isMetal()) flag = true\n })\n if (flag) charge = 0\n else charge = 1\n // TODO: Planarity sanity check?\n }\n\n }\n\n if (assignH) {\n // NH4+ -> 4, 1' amide -> 2, nitro N/N+ depiction -> 0\n implicitHCount = Math.max(0, 3 - valence + charge)\n }\n\n if (conjugated && !multiBond) {\n // Amide, anilinic N etc. cannot consider lone-pair for geometry purposes\n // Anilinic N geometry is depenent on ring electronics, for our purposes we\n // assume it's trigonal!\n geom = assignGeometry(degree + implicitHCount - charge)\n } else {\n // Everything else, pyridine, amine, nitrile, lp plays normal role:\n geom = assignGeometry(degree + implicitHCount + 1 - charge)\n }\n break\n\n case Elements.O:\n if (assignCharge) {\n if (!assignH) {\n charge = valence - 2 //\n }\n if (valence === 1) {\n a.eachBondedAtom(ba => {\n ba.eachBond(b => {\n const oa = b.getOtherAtom(ba)\n if (oa.index !== a.index && oa.number === Elements.O && b.bondOrder === 2){\n charge = -1\n }\n })\n })\n }\n }\n if (assignH) {\n // ethanol -> 1, carboxylate -> -1\n implicitHCount = Math.max(0, 2 - valence + charge)\n }\n if (conjugated && !multiBond){\n // carboxylate OH, phenol OH, one lone-pair taken up with conjugation\n geom = assignGeometry(degree + implicitHCount - charge + 1)\n } else {\n // Carbonyl (trigonal)\n geom = assignGeometry(degree + implicitHCount - charge + 2)\n }\n break\n\n // Only handles thiols/thiolates/thioether/sulfonium. Sulfoxides and higher\n // oxidiation states are assumed neutral S (charge carried on O if required)\n case Elements.S:\n if (assignCharge) {\n if (!assignH) {\n if (valence <= 3 && !a.bondToElementCount(Elements.O)) {\n charge = valence - 2 // e.g. explicitly deprotonated thiol\n } else {\n charge = 0\n }\n }\n }\n if (assignH){\n if (valence < 2){\n implicitHCount = Math.max(0, 2 - valence + charge)\n }\n }\n if (valence <= 3){\n // Thiol, thiolate, tioether -> tetrahedral\n geom = assignGeometry(degree + implicitHCount - charge + 2)\n }\n\n break\n\n case Elements.F:\n case Elements.CL:\n case Elements.BR:\n case Elements.I:\n case Elements.AT:\n // Never implicitly protonate halides\n if (assignCharge) {\n charge = valence - 1\n }\n break\n\n case Elements.LI:\n case Elements.NA:\n case Elements.K:\n case Elements.RB:\n case Elements.CS:\n case Elements.FR:\n if (assignCharge) {\n charge = 1 - valence\n }\n break\n\n case Elements.BE:\n case Elements.MG:\n case Elements.CA:\n case Elements.SR:\n case Elements.BA:\n case Elements.RA:\n if (assignCharge) {\n charge = 2 - valence\n }\n break\n\n default:\n console.warn('Requested charge, protonation for an unhandled element', a.element)\n }\n\n return [ charge, implicitHCount, implicitHCount + hydrogenCount, geom ]\n}\n\n\nexport interface ValenceModel {\n charge: Int8Array,\n implicitH: Int8Array,\n totalH: Int8Array,\n idealGeometry: Int8Array\n}\n\nexport interface ValenceModelParams {\n assignCharge: string,\n assignH: string\n}\n\nexport function ValenceModel (data: Data, params: ValenceModelParams) {\n const structure = data.structure\n const n = structure.atomCount\n\n const charge = new Int8Array(n)\n const implicitH = new Int8Array(n)\n const totalH = new Int8Array(n)\n const idealGeometry = new Int8Array(n)\n\n structure.eachAtom(a => {\n const i = a.index\n const [ chg, implH, totH, geom ] = calculateHydrogensCharge(a, params)\n charge[ i ] = chg\n implicitH[ i ] = implH\n totalH[ i ] = totH\n idealGeometry[ i ] = geom\n })\n\n return { charge, implicitH, totalH, idealGeometry }\n}","\nimport Structure from './structure'\nimport SpatialHash from '../geometry/spatial-hash'\nimport { ValenceModel } from '../chemistry/valence-model'\n\nexport interface Data {\n structure: Structure\n '@spatialLookup': SpatialHash | undefined\n '@valenceModel': ValenceModel | undefined\n}\n\nexport function createData(structure: Structure): Data {\n return {\n structure,\n '@spatialLookup': undefined,\n '@valenceModel': undefined\n }\n}\n\nexport function spatialLookup(data: Data): SpatialHash {\n if (data['@spatialLookup']) return data['@spatialLookup']!\n const lookup = new SpatialHash(data.structure.atomStore, data.structure.boundingBox)\n data['@spatialLookup'] = lookup\n return lookup\n}\n\nexport function valenceModel(data: Data): ValenceModel {\n if (data['@valenceModel']) return data['@valenceModel']!\n const valenceModel = ValenceModel(data, {assignCharge: 'auto', assignH: 'auto'})\n data['@valenceModel'] = valenceModel\n return valenceModel\n}\n","/**\n * @file Functional Groups\n * @author Alexander Rose \n */\n\nimport AtomProxy from '../proxy/atom-proxy'\nimport { Elements } from '../structure/structure-constants'\n\n/**\n * Nitrogen in a quaternary amine\n */\nexport function isQuaternaryAmine (a: AtomProxy) {\n return (\n a.number === 7 &&\n a.bondCount === 4 &&\n a.bondToElementCount(Elements.H) === 0\n )\n}\n\n/**\n * Nitrogen in a tertiary amine\n */\nexport function isTertiaryAmine (a: AtomProxy, idealValence: number) {\n return (\n a.number === 7 &&\n a.bondCount >= 3 &&\n idealValence === 3\n )\n}\n\n/**\n * Nitrogen in an imide\n */\nexport function isImide (a: AtomProxy) {\n let flag = false\n if (a.number === Elements.N && (a.bondCount - a.bondToElementCount(Elements.H)) === 2) {\n let carbonylCount = 0\n a.eachBondedAtom(ba => {\n if (isCarbonyl(ba)) ++carbonylCount\n })\n flag = carbonylCount === 2\n }\n return flag\n}\n\n/**\n * Nitrogen in an amide\n */\nexport function isAmide (a: AtomProxy) {\n let flag = false\n if (a.number === Elements.N && (a.bondCount - a.bondToElementCount(Elements.H)) === 2) {\n let carbonylCount = 0\n a.eachBondedAtom(ba => {\n if (isCarbonyl(ba)) ++carbonylCount\n })\n flag = carbonylCount === 1\n }\n return flag\n}\n\n/**\n * Sulfur in a sulfonium group\n */\nexport function isSulfonium (a: AtomProxy) {\n return (\n a.number === 16 &&\n a.bondCount === 3 &&\n a.bondToElementCount(Elements.H) === 0\n )\n}\n\n/**\n * Sulfur in a sulfonic acid or sulfonate group\n */\nexport function isSulfonicAcid (a: AtomProxy) {\n return (\n a.number === 16 &&\n a.bondToElementCount(Elements.O) === 3\n )\n}\n\n/**\n * Sulfur in a sulfate group\n */\nexport function isSulfate (a: AtomProxy) {\n return (\n a.number === 16 &&\n a.bondToElementCount(Elements.O) === 4\n )\n}\n\n/**\n * Phosphor in a phosphate group\n */\nexport function isPhosphate (a: AtomProxy) {\n return (\n a.number === 15 &&\n a.bondToElementCount(Elements.O) === a.bondCount\n )\n}\n\n/**\n * Halogen with one bond to a carbon\n */\nexport function isHalocarbon (a: AtomProxy) {\n return (\n a.isHalogen() &&\n a.bondCount === 1 &&\n a.bondToElementCount(Elements.C) === 1\n )\n}\n\n/**\n * Carbon in a carbonyl/acyl group\n */\nexport function isCarbonyl (a: AtomProxy) {\n let flag = false\n if (a.number === Elements.C) {\n a.eachBond(b => {\n if (b.bondOrder === 2 && b.getOtherAtom(a).number === Elements.O) {\n flag = true\n }\n })\n }\n return flag\n}\n\n/**\n * Carbon in a carboxylate group\n */\nexport function isCarboxylate (a: AtomProxy) {\n let terminalOxygenCount = 0\n if (\n a.number === 6 &&\n a.bondToElementCount(Elements.O) === 2 &&\n a.bondToElementCount(Elements.C) === 1\n ) {\n a.eachBondedAtom(ba => {\n if (ba.number === 8 && ba.bondCount - ba.bondToElementCount(Elements.H) === 1) {\n ++terminalOxygenCount\n }\n })\n }\n return terminalOxygenCount === 2\n}\n\n/**\n * Carbon in a guanidine group\n */\nexport function isGuanidine (a: AtomProxy) {\n let terminalNitrogenCount = 0\n if (\n a.number === 6 &&\n a.bondCount === 3 &&\n a.bondToElementCount(Elements.N) === 3\n ) {\n a.eachBondedAtom(ba => {\n if (ba.bondCount - ba.bondToElementCount(Elements.H) === 1) {\n ++terminalNitrogenCount\n }\n })\n }\n return terminalNitrogenCount === 2\n}\n\n/**\n * Carbon in a acetamidine group\n */\nexport function isAcetamidine (a: AtomProxy) {\n let terminalNitrogenCount = 0\n if (\n a.number === 6 &&\n a.bondCount === 3 &&\n a.bondToElementCount(Elements.N) === 2 &&\n a.bondToElementCount(Elements.C) === 1\n ) {\n a.eachBondedAtom(ba => {\n if (ba.bondCount - ba.bondToElementCount(Elements.H) === 1) {\n ++terminalNitrogenCount\n }\n })\n }\n return terminalNitrogenCount === 2\n}\n\nconst PolarElements = [\n Elements.N, Elements.O, Elements.S,\n Elements.F, Elements.CL, Elements.BR, Elements.I\n]\n\nexport function isPolar (a: AtomProxy) {\n return PolarElements.includes(a.number)\n}\n\nexport function hasPolarNeighbour (a: AtomProxy) {\n let flag = false\n a.eachBondedAtom(ba => {\n if (isPolar(ba)) flag = true\n })\n return flag\n}\n\nexport function hasAromaticNeighbour (a: AtomProxy) {\n let flag = false\n a.eachBondedAtom(function (bap) {\n if (bap.aromatic) flag = true\n })\n return flag\n}\n","/**\n * @file Charged\n * @author Alexander Rose \n * @author Fred Ludlow \n */\n\nimport { Vector3 } from 'three'\n\nimport { defaults } from '../../utils'\nimport { radToDeg } from '../../math/math-utils'\nimport Structure from '../../structure/structure'\nimport { AA3, Bases, Elements } from '../../structure/structure-constants'\nimport { valenceModel } from '../../structure/data'\nimport {\n isGuanidine, isAcetamidine, isSulfonicAcid, isPhosphate, isSulfate, isCarboxylate\n} from '../functional-groups'\nimport {\n Features, FeatureType, FeatureGroup,\n addAtom, addFeature, createFeatureState,\n} from './features'\nimport { Contacts, ContactType, ContactDefaultParams, invalidAtomContact } from './contact'\n\nconst PositvelyCharged = [ 'ARG', 'HIS', 'LYS' ]\nconst NegativelyCharged = [ 'GLU', 'ASP' ]\n\nexport function addPositiveCharges (structure: Structure, features: Features) {\n const { charge } = valenceModel(structure.data)\n const atomInGroupDict: { [atomIndex: number]: true } = {}\n\n structure.eachResidue(r => {\n if (PositvelyCharged.includes(r.resname)) {\n const state = createFeatureState(FeatureType.PositiveCharge)\n r.eachAtom(a => {\n if (a.number === Elements.N && a.isSidechain()) {\n addAtom(state, a)\n }\n })\n addFeature(features, state)\n } else if(!AA3.includes(r.resname) && !r.isNucleic()) {\n r.eachAtom(a => {\n let addGroup = false\n const state = createFeatureState(FeatureType.PositiveCharge)\n if (isGuanidine(a)) {\n state.group = FeatureGroup.Guanidine\n addGroup = true\n } else if (isAcetamidine(a)) {\n state.group = FeatureGroup.Acetamidine\n addGroup = true\n }\n if (addGroup) {\n a.eachBondedAtom(a => {\n if (a.number === Elements.N) {\n atomInGroupDict[a.index] = true\n addAtom(state, a)\n }\n })\n addFeature(features, state)\n }\n })\n r.eachAtom(a => {\n const state = createFeatureState(FeatureType.PositiveCharge)\n if (charge[a.index] > 0) {\n if (!atomInGroupDict[a.index]) {\n addAtom(state, a)\n addFeature(features, state)\n }\n }\n })\n }\n })\n}\n\nexport function addNegativeCharges (structure: Structure, features: Features) {\n const { charge } = valenceModel(structure.data)\n const atomInGroupDict: { [atomIndex: number]: true } = {}\n\n structure.eachResidue(r => {\n if (NegativelyCharged.includes(r.resname)) {\n const state = createFeatureState(FeatureType.NegativeCharge)\n r.eachAtom(a => {\n if (a.number === Elements.O && a.isSidechain()) {\n addAtom(state, a)\n }\n })\n addFeature(features, state)\n } else if (Bases.includes(r.resname)) {\n const state = createFeatureState(FeatureType.NegativeCharge)\n r.eachAtom(a => {\n if (isPhosphate(a)) {\n state.group = FeatureGroup.Phosphate\n a.eachBondedAtom(a => {\n if (a.number === Elements.O) addAtom(state, a)\n })\n addFeature(features, state)\n }\n })\n } else if(!AA3.includes(r.resname) && !Bases.includes(r.resname)) {\n r.eachAtom(a => {\n let addGroup = false\n const state = createFeatureState(FeatureType.NegativeCharge)\n if (isSulfonicAcid(a)) {\n state.group = FeatureGroup.SulfonicAcid\n addGroup = true\n } else if (isPhosphate(a)) {\n state.group = FeatureGroup.Phosphate\n addGroup = true\n } else if (isSulfate(a)) {\n state.group = FeatureGroup.Sulfate\n addGroup = true\n } else if (isCarboxylate(a)) {\n state.group = FeatureGroup.Carboxylate\n addGroup = true\n }\n if (addGroup) {\n a.eachBondedAtom(a => {\n if (a.number === Elements.O) {\n atomInGroupDict[a.index] = true\n addAtom(state, a)\n }\n })\n addFeature(features, state)\n }\n })\n r.eachAtom(a => {\n const state = createFeatureState(FeatureType.NegativeCharge)\n if (charge[a.index] < 0) {\n if (!atomInGroupDict[a.index]) {\n addAtom(state, a)\n addFeature(features, state)\n }\n }\n })\n }\n })\n}\n\nexport function addAromaticRings (structure: Structure, features: Features) {\n const a = structure.getAtomProxy()\n structure.eachResidue(r => {\n const rings = r.getAromaticRings()\n if (rings) {\n const offset = r.atomOffset\n rings.forEach(ring => {\n const state = createFeatureState(FeatureType.AromaticRing)\n ring.forEach(i => {\n a.index = i + offset\n addAtom(state, a)\n })\n addFeature(features, state)\n })\n }\n })\n}\n\nfunction isIonicInteraction (ti: FeatureType, tj: FeatureType) {\n return (\n (ti === FeatureType.NegativeCharge && tj === FeatureType.PositiveCharge) ||\n (ti === FeatureType.PositiveCharge && tj === FeatureType.NegativeCharge)\n )\n}\n\nfunction isPiStacking (ti: FeatureType, tj: FeatureType) {\n return ti === FeatureType.AromaticRing && tj === FeatureType.AromaticRing\n}\n\nfunction isCationPi (ti: FeatureType, tj: FeatureType) {\n return (\n (ti === FeatureType.AromaticRing && tj === FeatureType.PositiveCharge) ||\n (ti === FeatureType.PositiveCharge && tj === FeatureType.AromaticRing)\n )\n}\n\nexport interface ChargedContactsParams {\n maxIonicDist?: number\n maxPiStackingDist?: number\n maxPiStackingOffset?: number\n maxPiStackingAngle?: number\n maxCationPiDist?: number\n maxCationPiOffset?: number\n masterModelIndex?: number\n}\n\nexport function addChargedContacts (structure: Structure, contacts: Contacts, params: ChargedContactsParams = {}) {\n const maxIonicDist = defaults(params.maxIonicDist, ContactDefaultParams.maxIonicDist)\n const maxPiStackingDist = defaults(params.maxPiStackingDist, ContactDefaultParams.maxPiStackingDist)\n const maxPiStackingOffset = defaults(params.maxPiStackingOffset, ContactDefaultParams.maxPiStackingOffset)\n const maxPiStackingAngle = defaults(params.maxPiStackingAngle, ContactDefaultParams.maxPiStackingAngle)\n const maxCationPiDist = defaults(params.maxCationPiDist, ContactDefaultParams.maxCationPiDist)\n const maxCationPiOffset = defaults(params.maxCationPiOffset, ContactDefaultParams.maxCationPiOffset)\n const masterIdx = defaults(params.masterModelIndex, ContactDefaultParams.masterModelIndex)\n\n const maxDistance = Math.max(maxIonicDist + 2, maxPiStackingDist, maxCationPiDist)\n // const maxSaltBridgeDistSq = maxSaltBridgeDist * maxSaltBridgeDist\n const maxPiStackingDistSq = maxPiStackingDist * maxPiStackingDist\n const maxCationPiDistSq = maxCationPiDist * maxCationPiDist\n\n const { features, spatialHash, contactStore, featureSet } = contacts\n const { types, centers, atomSets } = features\n const { x, y, z } = centers\n const n = types.length\n\n const ax = structure.atomStore.x\n const ay = structure.atomStore.y\n const az = structure.atomStore.z\n\n const ap1 = structure.getAtomProxy()\n const ap2 = structure.getAtomProxy()\n\n const areAtomSetsWithinDist = function (atomSet1: number[], atomSet2: number[], maxDist: number) {\n const sn = atomSet1.length\n const sm = atomSet2.length\n for (let si = 0; si < sn; ++si) {\n ap1.index = atomSet1[ si ]\n for (let sj = 0; sj < sm; ++sj) {\n ap2.index = atomSet2[ sj ]\n if (ap1.distanceTo(ap2) <= maxDist) {\n return true\n }\n }\n }\n return false\n }\n\n const v1 = new Vector3()\n const v2 = new Vector3()\n const v3 = new Vector3()\n const d1 = new Vector3()\n const d2 = new Vector3()\n const n1 = new Vector3()\n const n2 = new Vector3()\n\n const getNormal = function (atoms: number[], normal: Vector3) {\n v1.set(ax[ atoms[ 0 ] ], ay[ atoms[ 0 ] ], az[ atoms[ 0 ] ])\n v2.set(ax[ atoms[ 1 ] ], ay[ atoms[ 1 ] ], az[ atoms[ 1 ] ])\n v3.set(ax[ atoms[ 2 ] ], ay[ atoms[ 2 ] ], az[ atoms[ 2 ] ])\n d1.subVectors(v1, v2)\n d2.subVectors(v1, v3)\n normal.crossVectors(d1, d2)\n }\n\n const getOffset = function (i: number, j: number, normal: Vector3) {\n v1.set(x[ i ], y[ i ], z[ i ])\n v2.set(x[ j ], y[ j ], z[ j ])\n return v1.sub(v2).projectOnPlane(normal).add(v2).distanceTo(v2)\n }\n\n const add = function (i: number, j: number, ct: ContactType) {\n featureSet.setBits(i, j)\n contactStore.addContact(i, j, ct)\n }\n\n for (let i = 0; i < n; ++i) {\n spatialHash.eachWithin(x[i], y[i], z[i], maxDistance, (j, dSq) => {\n if (j <= i) return\n\n ap1.index = atomSets[ i ][ 0 ]\n ap2.index = atomSets[ j ][ 0 ]\n\n if (invalidAtomContact(ap1, ap2, masterIdx)) return\n\n const ti = types[ i ]\n const tj = types[ j ]\n\n if (isIonicInteraction(ti, tj)) {\n if (areAtomSetsWithinDist(atomSets[ i ], atomSets[ j ], maxIonicDist)) {\n add(i, j, ContactType.IonicInteraction)\n }\n } else if (isPiStacking(ti, tj)) {\n if (dSq <= maxPiStackingDistSq) {\n getNormal(atomSets[ i ], n1)\n getNormal(atomSets[ j ], n2)\n\n const angle = radToDeg(n1.angleTo(n2))\n const offset = Math.min(getOffset(i, j, n2), getOffset(j, i, n1))\n if (offset <= maxPiStackingOffset) {\n if (angle <= maxPiStackingAngle || angle >= 180 - maxPiStackingAngle) {\n add(i, j, ContactType.PiStacking) // parallel\n } else if (angle <= maxPiStackingAngle + 90 && angle >= 90 - maxPiStackingAngle) {\n add(i, j, ContactType.PiStacking) // t-shaped\n }\n }\n }\n } else if (isCationPi(ti, tj)) {\n if (dSq <= maxCationPiDistSq) {\n const [ l, k ] = ti === FeatureType.AromaticRing ? [ i, j ] : [ j, i ]\n\n getNormal(atomSets[ l ], n1)\n const offset = getOffset(k, l, n1)\n if (offset <= maxCationPiOffset) {\n add(l, k, ContactType.CationPi)\n }\n }\n }\n })\n }\n}\n","/**\n * @file Hydrogen Bonds\n * @author Alexander Rose \n * @author Fred Ludlow \n */\nimport { defaults } from '../../utils'\nimport { degToRad } from '../../math/math-utils'\nimport Structure from '../../structure/structure'\nimport AtomProxy from '../../proxy/atom-proxy'\nimport { valenceModel } from '../../structure/data'\nimport { Elements } from '../../structure/structure-constants'\nimport { Angles, AtomGeometry, calcAngles, calcPlaneAngle } from '../geometry'\nimport {\n Features, FeatureType,\n addAtom, addFeature, createFeatureState,\n} from './features'\nimport { Contacts, ContactType, ContactDefaultParams, invalidAtomContact } from './contact'\n\n\n// Geometric characteristics of hydrogen bonds involving sulfur atoms in proteins\n// https://doi.org/10.1002/prot.22327\n\n// Satisfying Hydrogen Bonding Potential in Proteins (HBPLUS)\n// https://doi.org/10.1006/jmbi.1994.1334\n// http://www.csb.yale.edu/userguides/datamanip/hbplus/hbplus_descrip.html\n\n/**\n * Potential hydrogen donor\n */\nexport function addHydrogenDonors (structure: Structure, features: Features) {\n const { totalH } = valenceModel(structure.data)\n\n structure.eachAtom(a => {\n const state = createFeatureState(FeatureType.HydrogenDonor)\n\n const an = a.number\n if (isHistidineNitrogen(a)) {\n // include both nitrogen atoms in histidine due to\n // their often ambiguous protonation assignment\n addAtom(state, a)\n addFeature(features, state)\n } else if (\n totalH[ a.index ] > 0 &&\n (an === Elements.N || an === Elements.O || an === Elements.S)\n ) {\n addAtom(state, a)\n addFeature(features, state)\n }\n })\n}\n\n/**\n * Weak hydrogen donor.\n */\nexport function addWeakHydrogenDonors (structure: Structure, features: Features) {\n const { totalH } = valenceModel(structure.data)\n\n structure.eachAtom(a => {\n if (\n a.number === Elements.C &&\n totalH[ a.index ] > 0 &&\n (\n a.bondToElementCount(Elements.N) > 0 ||\n a.bondToElementCount(Elements.O) > 0 ||\n inAromaticRingWithElectronNegativeElement(a)\n )\n ) {\n const state = createFeatureState(FeatureType.WeakHydrogenDonor)\n addAtom(state, a)\n addFeature(features, state)\n }\n })\n}\n\nfunction inAromaticRingWithElectronNegativeElement (a: AtomProxy) {\n if (!a.isAromatic()) return false\n\n const ringData = a.residueType.getRings()\n if (!ringData) return false\n\n let hasElement = false\n const rings = ringData.rings\n rings.forEach(ring => {\n if (hasElement) return // already found one\n if (ring.some(idx => (a.index - a.residueAtomOffset) === idx)) { // in ring\n hasElement = ring.some(idx => {\n const atomTypeId = a.residueType.atomTypeIdList[ idx ]\n const number = a.atomMap.get(atomTypeId).number\n return number === Elements.N || number === Elements.O\n })\n }\n })\n\n return hasElement\n}\n\n/**\n * Potential hydrogen acceptor\n */\nexport function addHydrogenAcceptors (structure: Structure, features: Features) {\n const { charge, implicitH, idealGeometry } = valenceModel(structure.data)\n\n structure.eachAtom(a => {\n const state = createFeatureState(FeatureType.HydrogenAcceptor)\n\n const an = a.number\n if (an === Elements.O) {\n // Basically assume all oxygen atoms are acceptors!\n addAtom(state, a)\n addFeature(features, state)\n }else if (an === Elements.N) {\n if (isHistidineNitrogen(a)) {\n // include both nitrogen atoms in histidine due to\n // their often ambiguous protonation assignment\n addAtom(state, a)\n addFeature(features, state)\n } else if (charge[ a.index ] < 1){\n // Neutral nitrogen might be an acceptor\n // It must have at least one lone pair not conjugated\n const totalBonds = a.bondCount + implicitH[ a.index ]\n const ig = idealGeometry[ a.index ]\n if (\n (ig === AtomGeometry.Tetrahedral && totalBonds < 4) ||\n (ig === AtomGeometry.Trigonal && totalBonds < 3) ||\n (ig === AtomGeometry.Linear && totalBonds < 2)\n ) {\n addAtom(state, a)\n addFeature(features, state)\n }\n }\n }else if (an === 16) { // S\n if (a.resname === 'CYS' || a.resname === 'MET' || a.formalCharge === -1) {\n addAtom(state, a)\n addFeature(features, state)\n }\n }\n })\n}\n\n/**\n * Atom that is only bound to carbon or hydrogen\n */\n// function isHydrocarbon (atom: AtomProxy) {\n// let flag = true\n// atom.eachBondedAtom(ap => {\n// const e = ap.element\n// if (e !== 'C' && e !== 'H') flag = false\n// })\n// return flag\n// }\n\nfunction isHistidineNitrogen (ap: AtomProxy) {\n return ap.resname === 'HIS' && ap.number == Elements.N && ap.isRing()\n}\n\nfunction isBackboneHydrogenBond (ap1: AtomProxy, ap2: AtomProxy) {\n return ap1.isBackbone() && ap2.isBackbone()\n}\n\nfunction isWaterHydrogenBond (ap1: AtomProxy, ap2: AtomProxy) {\n return ap1.isWater() && ap2.isWater()\n}\n\nfunction isHydrogenBond (ti: FeatureType, tj: FeatureType) {\n return (\n (ti === FeatureType.HydrogenAcceptor && tj === FeatureType.HydrogenDonor) ||\n (ti === FeatureType.HydrogenDonor && tj === FeatureType.HydrogenAcceptor)\n )\n}\n\nfunction isWeakHydrogenBond (ti: FeatureType, tj: FeatureType){\n return (\n (ti === FeatureType.WeakHydrogenDonor && tj === FeatureType.HydrogenAcceptor) ||\n (ti === FeatureType.HydrogenAcceptor && tj === FeatureType.WeakHydrogenDonor)\n )\n}\n\nfunction getHydrogenBondType (ap1: AtomProxy, ap2: AtomProxy) {\n if (isWaterHydrogenBond(ap1, ap2)) {\n return ContactType.WaterHydrogenBond\n } else if (isBackboneHydrogenBond(ap1, ap2)) {\n return ContactType.BackboneHydrogenBond\n } else {\n return ContactType.HydrogenBond\n }\n}\n\nexport interface HydrogenBondParams {\n maxHbondDist?: number\n maxHbondSulfurDist?: number\n maxHbondAccAngle?: number\n maxHbondDonAngle?: number\n maxHbondAccPlaneAngle?: number\n maxHbondDonPlaneAngle?: number\n backboneHbond?: boolean\n waterHbond?: boolean\n masterModelIndex?: number\n}\n\n/**\n * All pairs of hydrogen donor and acceptor atoms\n */\nexport function addHydrogenBonds (structure: Structure, contacts: Contacts, params: HydrogenBondParams = {}) {\n const maxHbondDist = defaults(params.maxHbondDist, ContactDefaultParams.maxHbondDist)\n const maxHbondSulfurDist = defaults(params.maxHbondSulfurDist, ContactDefaultParams.maxHbondSulfurDist)\n const maxHbondAccAngle = degToRad(defaults(params.maxHbondAccAngle, ContactDefaultParams.maxHbondAccAngle))\n const maxHbondDonAngle = degToRad(defaults(params.maxHbondDonAngle, ContactDefaultParams.maxHbondDonAngle))\n const maxHbondAccPlaneAngle = degToRad(defaults(params.maxHbondAccPlaneAngle, ContactDefaultParams.maxHbondAccPlaneAngle))\n const maxHbondDonPlaneAngle = degToRad(defaults(params.maxHbondDonPlaneAngle, ContactDefaultParams.maxHbondDonPlaneAngle))\n const masterIdx = defaults(params.masterModelIndex, ContactDefaultParams.masterModelIndex)\n\n const maxDist = Math.max(maxHbondDist, maxHbondSulfurDist)\n const maxHbondDistSq = maxHbondDist * maxHbondDist\n\n const { features, spatialHash, contactStore, featureSet } = contacts\n const { types, centers, atomSets } = features\n const { x, y, z } = centers\n const n = types.length\n\n const { idealGeometry } = valenceModel(structure.data)\n\n const donor = structure.getAtomProxy()\n const acceptor = structure.getAtomProxy()\n\n for (let i = 0; i < n; ++i) {\n spatialHash.eachWithin(x[i], y[i], z[i], maxDist, (j, dSq) => {\n if (j <= i) return\n\n const ti = types[ i ]\n const tj = types[ j ]\n\n const isWeak = isWeakHydrogenBond(ti, tj)\n if (!isWeak && !isHydrogenBond(ti, tj)) return\n\n const [ l, k ] = tj === FeatureType.HydrogenAcceptor ? [ i, j ] : [ j, i ]\n\n donor.index = atomSets[ l ][ 0 ]\n acceptor.index = atomSets[ k ][ 0 ]\n\n if (acceptor.index === donor.index) return // DA to self\n\n if (invalidAtomContact(donor, acceptor, masterIdx)) return\n if (donor.number !== Elements.S && acceptor.number !== Elements.S && dSq > maxHbondDistSq) return\n if (donor.connectedTo(acceptor)) return\n\n const donorAngles = calcAngles(donor, acceptor)\n const idealDonorAngle = Angles.get(idealGeometry[donor.index]) || degToRad(120)\n if (donorAngles.some(donorAngle => {\n return Math.abs(idealDonorAngle - donorAngle) > maxHbondDonAngle\n })) return\n\n if (idealGeometry[donor.index] === AtomGeometry.Trigonal){\n const outOfPlane = calcPlaneAngle(donor, acceptor)\n if (outOfPlane !== undefined && outOfPlane > maxHbondDonPlaneAngle) return\n }\n\n const acceptorAngles = calcAngles(acceptor, donor)\n const idealAcceptorAngle = Angles.get(idealGeometry[acceptor.index]) || degToRad(120)\n if (acceptorAngles.some(acceptorAngle => {\n // Do not limit large acceptor angles\n return idealAcceptorAngle - acceptorAngle > maxHbondAccAngle\n })) return\n\n if (idealGeometry[acceptor.index] === AtomGeometry.Trigonal){\n const outOfPlane = calcPlaneAngle(acceptor, donor)\n if (outOfPlane !== undefined && outOfPlane > maxHbondAccPlaneAngle) return\n }\n\n featureSet.setBits(l, k)\n const bondType = isWeak ? ContactType.WeakHydrogenBond : getHydrogenBondType(donor, acceptor)\n contactStore.addContact(l, k, bondType)\n })\n }\n}\n","/**\n * @file Metal Binding\n * @author Alexander Rose \n */\n\nimport { defaults } from '../../utils'\nimport Structure from '../../structure/structure'\n// import { valenceModel } from '../../structure/data'\nimport { Elements, AA3, Bases } from '../../structure/structure-constants'\n// import { hasAromaticNeighbour } from '../functional-groups'\nimport {\n Features, FeatureType,\n addAtom, addFeature, createFeatureState,\n} from './features'\nimport { Contacts, ContactType, ContactDefaultParams, invalidAtomContact } from './contact'\n\nconst IonicTypeMetals = [\n Elements.LI, Elements.NA, Elements.K, Elements.RB, Elements.CS,\n Elements.MG, Elements.CA, Elements.SR, Elements.BA, Elements.AL,\n Elements.GA, Elements.IN, Elements.TL, Elements.SC, Elements.SN,\n Elements.PB, Elements.BI, Elements.SB, Elements.HG\n]\n\n/**\n * Metal binding partners (dative bond or ionic-type interaction)\n */\nexport function addMetalBinding (structure: Structure, features: Features) {\n structure.eachAtom(a => {\n let dative = false\n let ionic = false\n\n const isStandardAminoacid = AA3.includes(a.resname)\n const isStandardBase = Bases.includes(a.resname)\n\n if (!isStandardAminoacid && !isStandardBase) {\n if (a.isHalogen() || a.number === Elements.O || a.number === Elements.S) {\n dative = true\n ionic = true\n } else if (a.number === Elements.N) {\n dative = true\n }\n } else if (isStandardAminoacid){\n // main chain oxygen atom or oxygen, nitrogen and sulfur from specific amino acids\n if (a.number === Elements.O) {\n if(['ASP', 'GLU', 'SER', 'THR', 'TYR', 'ASN', 'GLN'].includes(a.resname) && a.isSidechain()) {\n dative = true\n ionic = true\n } else if (a.isBackbone()) {\n dative = true\n ionic = true\n }\n } else if (a.number === Elements.S && 'CYS' === a.resname) {\n dative = true\n ionic = true\n } else if (a.number === Elements.N) {\n if(a.resname === 'HIS' && a.isSidechain()) {\n dative = true\n }\n }\n } else if (isStandardBase){\n // http://pubs.acs.org/doi/pdf/10.1021/acs.accounts.6b00253\n // http://onlinelibrary.wiley.com/doi/10.1002/anie.200900399/full\n if (a.number === Elements.O && a.isBackbone()) {\n dative = true\n ionic = true\n } else if(['N3', 'N4', 'N7'].includes(a.atomname)) {\n dative = true\n } else if(['O2', 'O4', 'O6'].includes(a.atomname)) {\n dative = true\n ionic = true\n }\n }\n if (dative) {\n const state = createFeatureState(FeatureType.DativeBondPartner)\n addAtom(state, a)\n addFeature(features, state)\n }\n if (ionic) {\n const state = createFeatureState(FeatureType.IonicTypePartner)\n addAtom(state, a)\n addFeature(features, state)\n }\n })\n}\n\n/**\n * Metal Pi complexation partner\n */\n// export function addMetalPiPartners (structure: Structure, features: Features) {\n// const { charge } = valenceModel(structure.data)\n\n// structure.eachAtom(a => {\n// const state = createFeatureState(FeatureType.MetalPiPartner)\n\n// const resname = a.resname\n// const element = a.element\n// const atomname = a.atomname\n// if (!a.isPolymer()) {\n// // water oxygen, as well as oxygen from carboxylate, phosphoryl, phenolate, alcohol;\n// // nitrogen from imidazole; sulfur from thiolate\n// if (element === 'O') {\n// // Water oxygen\n// if (a.bondCount === 0 || a.isWater()) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// // Oxygen in alcohol (R-[O]-H)\n// if (a.bondCount === 2 && charge[ a.index ] || a.hasBondToElement('H')) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// // Phenolate oxygen\n// if (hasAromaticNeighbour(a) && !a.aromatic) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// // Carboxylic acid oxygen\n// if (a.bondToElementCount('C') === 1) {\n// let flag = false\n// a.eachBondedAtom(ba => {\n// if (ba.element === 'C' && ba.bondToElementCount('O') === 2 && ba.bondToElementCount('C') === 1) {\n// flag = true\n// }\n// })\n// if (flag) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// }\n// // Phosphoryl oxygen\n// if (a.bondToElementCount('P') === 1) {\n// let flag = false\n// a.eachBondedAtom(ba => {\n// if (ba.element === 'P' && ba.bondToElementCount('O') >= 3) {\n// flag = true\n// }\n// })\n// if (flag) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// }\n// } else if (element === 'N') {\n// // Imidazole/pyrrole or similar\n// if (a.bondToElementCount('C') === 2) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// } else if (element === 'S') {\n// // Thiolate\n// if (hasAromaticNeighbour(a) && !a.aromatic) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// // Sulfur in Iron sulfur cluster\n// const ironCount = a.bondToElementCount('FE')\n// if (ironCount > 0 && ironCount === a.bondCount) {\n// addAtom(state, a)\n// addFeature(features, state)\n// return\n// }\n// }\n// }\n// })\n// }\n\nexport function addMetals (structure: Structure, features: Features) {\n structure.eachAtom(a => {\n if (a.isTransitionMetal() || a.number === Elements.ZN || a.number === Elements.CD) {\n const state = createFeatureState(FeatureType.TransitionMetal)\n addAtom(state, a)\n addFeature(features, state)\n } else if (IonicTypeMetals.includes(a.number)) {\n const state = createFeatureState(FeatureType.IonicTypeMetal)\n addAtom(state, a)\n addFeature(features, state)\n }\n })\n}\n\nfunction isMetalComplex (ti: FeatureType, tj: FeatureType) {\n if (ti === FeatureType.TransitionMetal) {\n return (\n tj === FeatureType.DativeBondPartner ||\n tj === FeatureType.TransitionMetal\n )\n } else if (ti === FeatureType.IonicTypeMetal) {\n return (\n tj === FeatureType.IonicTypePartner\n )\n }\n}\n\nexport interface MetalComplexationParams {\n maxMetalDist?: number\n masterModelIndex?: number\n}\n\n/**\n * Metal complexes of metals and appropriate groups in protein and ligand, including water\n */\nexport function addMetalComplexation (structure: Structure, contacts: Contacts, params: MetalComplexationParams = {}) {\n const maxMetalDist = defaults(params.maxMetalDist, ContactDefaultParams.maxMetalDist)\n const masterIdx = defaults(params.masterModelIndex, ContactDefaultParams.masterModelIndex)\n\n const { features, spatialHash, contactStore, featureSet } = contacts\n const { types, centers, atomSets } = features\n const { x, y, z } = centers\n const n = types.length\n\n const ap1 = structure.getAtomProxy()\n const ap2 = structure.getAtomProxy()\n\n for (let i = 0; i < n; ++i) {\n spatialHash.eachWithin(x[i], y[i], z[i], maxMetalDist, (j, dSq) => {\n if (j <= i) return\n\n ap1.index = atomSets[ i ][ 0 ]\n ap2.index = atomSets[ j ][ 0 ]\n\n if (invalidAtomContact(ap1, ap2, masterIdx)) return\n\n const m1 = ap1.isMetal()\n const m2 = ap2.isMetal()\n if (!m1 && !m2) return\n\n const [ ti, tj ] = m1 ? [ types[ i ],types[ j ] ] : [ types[ j ],types[ i ] ]\n\n if (isMetalComplex(ti, tj)) {\n featureSet.setBits(i, j)\n contactStore.addContact(i, j, ContactType.MetalCoordination)\n }\n })\n }\n}\n","/**\n * @file Halogen Bonds\n * @author Alexander Rose \n * @author Fred Ludlow \n */\n\nimport { defaults } from '../../utils'\nimport Structure from '../../structure/structure'\nimport { Elements } from '../../structure/structure-constants'\nimport { degToRad } from '../../math/math-utils'\nimport {\n Features, FeatureType,\n addAtom, addFeature, createFeatureState,\n} from './features'\nimport { Contacts, ContactType, ContactDefaultParams, invalidAtomContact } from './contact'\nimport { calcAngles } from '../geometry'\n\nconst halBondElements = [17, 35, 53, 85]\n\n/**\n * Halogen bond donors (X-C, with X one of Cl, Br, I or At) not F!\n */\nexport function addHalogenDonors (structure: Structure, features: Features) {\n structure.eachAtom(a => {\n if (halBondElements.includes(a.number) && a.bondToElementCount(Elements.C) === 1) {\n const state = createFeatureState(FeatureType.HalogenDonor)\n addAtom(state, a)\n addFeature(features, state)\n }\n })\n}\n\nconst X = [ Elements.N, Elements.O, Elements.S ]\nconst Y = [ Elements.C, Elements.N, Elements.P, Elements.S ]\n\n/**\n * Halogen bond acceptors (Y-{O|N|S}, with Y=C,P,N,S)\n */\nexport function addHalogenAcceptors (structure: Structure, features: Features) {\n structure.eachAtom(a => {\n if (X.includes(a.number)) {\n let flag = false\n a.eachBondedAtom(ba => {\n if (Y.includes(ba.number)) {\n flag = true\n }\n })\n if (flag) {\n const state = createFeatureState(FeatureType.HalogenAcceptor)\n addAtom(state, a)\n addFeature(features, state)\n }\n }\n })\n}\n\nfunction isHalogenBond (ti: FeatureType, tj: FeatureType) {\n return (\n (ti === FeatureType.HalogenAcceptor && tj === FeatureType.HalogenDonor) ||\n (ti === FeatureType.HalogenDonor && tj === FeatureType.HalogenAcceptor)\n )\n}\n\nexport interface HalogenBondsParams {\n maxHalogenBondDist?: number\n maxHalogenBondAngle?: number\n masterModelIndex?: number\n}\n\n// http://www.pnas.org/content/101/48/16789.full\nconst OptimalHalogenAngle = degToRad(180) // adjusted from 165 to account for spherical statistics\nconst OptimalAcceptorAngle = degToRad(120)\n\n/**\n * All pairs of halogen donor and acceptor atoms\n */\nexport function addHalogenBonds (structure: Structure, contacts: Contacts, params: HalogenBondsParams = {}) {\n const maxHalogenBondDist = defaults(params.maxHalogenBondDist, ContactDefaultParams.maxHalogenBondDist)\n const maxHalogenBondAngle = degToRad(defaults(params.maxHalogenBondAngle, ContactDefaultParams.maxHalogenBondAngle))\n const masterIdx = defaults(params.masterModelIndex, ContactDefaultParams.masterModelIndex)\n\n const { features, spatialHash, contactStore, featureSet } = contacts\n const { types, centers, atomSets } = features\n const { x, y, z } = centers\n const n = types.length\n\n const ap1 = structure.getAtomProxy()\n const ap2 = structure.getAtomProxy()\n\n for (let i = 0; i < n; ++i) {\n spatialHash.eachWithin(x[i], y[i], z[i], maxHalogenBondDist, (j, dSq) => {\n if (j <= i) return\n\n ap1.index = atomSets[ i ][ 0 ]\n ap2.index = atomSets[ j ][ 0 ]\n\n if (invalidAtomContact(ap1, ap2, masterIdx)) return\n if (!isHalogenBond(types[ i ], types[ j ])) return\n\n const [ halogen, acceptor ] = types[ i ] === FeatureType.HalogenDonor ? [ ap1, ap2 ] : [ ap2, ap1 ]\n\n const halogenAngles = calcAngles(halogen, acceptor)\n // Singly bonded halogen only (not bromide ion for example)\n if (halogenAngles.length !== 1) return\n if (OptimalHalogenAngle - halogenAngles[0] > maxHalogenBondAngle) return\n\n const acceptorAngles = calcAngles(acceptor, halogen)\n // Angle must be defined. Excludes water as acceptor. Debatable\n if (acceptorAngles.length === 0) return\n if (acceptorAngles.some(acceptorAngle => {\n return (OptimalAcceptorAngle - acceptorAngle > maxHalogenBondAngle)\n })) return\n\n\n featureSet.setBits(i, j)\n contactStore.addContact(i, j, ContactType.HalogenBond)\n\n })\n }\n}\n","/**\n * @file Refine Contacts\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { Debug, Log } from '../../globals'\nimport { defaults } from '../../utils'\nimport Structure from '../../structure/structure'\nimport AtomProxy from '../../proxy/atom-proxy'\nimport { Elements } from '../../structure/structure-constants'\nimport { FrozenContacts, ContactType, ContactDefaultParams, isMasterContact } from './contact'\nimport { FeatureType } from './features'\n\nexport interface LineOfSightParams {\n lineOfSightDistFactor?: number\n masterModelIndex?: number\n}\n\n// also allows intra-residue contacts\nexport function invalidAtomContact (ap1: AtomProxy, ap2: AtomProxy, masterIdx: number) {\n return !isMasterContact(ap1, ap2, masterIdx) && (\n ap1.modelIndex !== ap2.modelIndex ||\n (ap1.altloc && ap2.altloc && ap1.altloc !== ap2.altloc)\n )\n}\n\nexport function refineLineOfSight (structure: Structure, contacts: FrozenContacts, params: LineOfSightParams = {}) {\n if (Debug) Log.time('refineLineOfSight')\n\n const lineOfSightDistFactor = defaults(params.lineOfSightDistFactor, ContactDefaultParams.lineOfSightDistFactor)\n const masterIdx = defaults(params.masterModelIndex, ContactDefaultParams.masterModelIndex)\n\n const spatialHash = structure.spatialHash!\n const { contactSet, contactStore, features } = contacts\n const { index1, index2 } = contactStore\n const { centers, atomSets } = features\n const { x, y, z } = centers\n\n const ac1 = structure.getAtomProxy()\n const ac2 = structure.getAtomProxy()\n const aw = structure.getAtomProxy()\n\n const c1 = new Vector3()\n const c2 = new Vector3()\n\n const lineOfSightDist = 3 * lineOfSightDistFactor\n const lineOfSightDistFactorSq = lineOfSightDistFactor * lineOfSightDistFactor\n\n contactSet.forEach(i => {\n c1.set(x[index1[i]], y[index1[i]], z[index1[i]])\n c2.set(x[index2[i]], y[index2[i]], z[index2[i]])\n\n const cx = ( c1.x + c2.x ) / 2\n const cy = ( c1.y + c2.y ) / 2\n const cz = ( c1.z + c2.z ) / 2\n\n const as1 = atomSets[ index1[ i ] ]\n const as2 = atomSets[ index2[ i ] ]\n\n ac1.index = as1[ 0 ]\n ac2.index = as2[ 0 ]\n\n spatialHash.eachWithin(cx, cy, cz, lineOfSightDist, (j, dSq) => {\n aw.index = j\n if (\n aw.number !== Elements.H &&\n (aw.vdw * aw.vdw * lineOfSightDistFactorSq) > dSq &&\n !invalidAtomContact(ac1, aw, masterIdx) &&\n !invalidAtomContact(ac2, aw, masterIdx) &&\n !as1.includes(j) &&\n !as2.includes(j) &&\n // to ignore atoms in the center of functional groups\n c1.distanceToSquared(aw as any) > 1 &&\n c2.distanceToSquared(aw as any) > 1\n ) {\n contactSet.clear(i)\n if (Debug) Log.log('removing', ac1.qualifiedName(), ac2.qualifiedName(), 'because', aw.qualifiedName())\n }\n })\n })\n\n if (Debug) Log.timeEnd('refineLineOfSight')\n}\n\n/**\n * For atoms interacting with several atoms in the same residue\n * only the one with the closest distance is kept.\n */\nexport function refineHydrophobicContacts (structure: Structure, contacts: FrozenContacts) {\n const { contactSet, contactStore, features } = contacts\n const { type, index1, index2 } = contactStore\n const { atomSets } = features\n\n const ap1 = structure.getAtomProxy()\n const ap2 = structure.getAtomProxy()\n\n const residueContactDict: { [k: string]: number[] } = {}\n\n /* keep only closest contact between residues */\n const handleResidueContact = function (dist: number, i: number, key: string) {\n const [ minDist, minIndex ] = residueContactDict[ key ] || [ Infinity, -1 ]\n if (dist < minDist) {\n if (minIndex !== -1) contactSet.clear(minIndex)\n residueContactDict[ key ] = [ dist, i ]\n } else {\n contactSet.clear(i)\n }\n }\n\n contactSet.forEach(i => {\n if (type[ i ] !== ContactType.Hydrophobic) return\n\n ap1.index = atomSets[ index1[ i ] ][ 0 ]\n ap2.index = atomSets[ index2[ i ] ][ 0 ]\n\n const dist = ap1.distanceTo(ap2)\n handleResidueContact(dist, i, `${ap1.index}|${ap2.residueIndex}`)\n handleResidueContact(dist, i, `${ap2.index}|${ap1.residueIndex}`)\n })\n}\n\nfunction isHydrogenBondType (type: number) {\n return (\n type === ContactType.HydrogenBond ||\n type === ContactType.WaterHydrogenBond ||\n type === ContactType.BackboneHydrogenBond\n )\n}\n\n/**\n * Remove weak hydrogen bonds when the acceptor is involved in\n * a normal/strong hydrogen bond\n */\nexport function refineWeakHydrogenBonds (structure: Structure, contacts: FrozenContacts) {\n const { contactSet, contactStore, features, adjacencyList } = contacts\n const { type, index1, index2 } = contactStore\n const { types } = features\n\n contactSet.forEach(i => {\n if (type[ i ] !== ContactType.WeakHydrogenBond) return\n\n let accFeat: number\n if (types[ index1[ i ] ] === FeatureType.WeakHydrogenDonor) {\n accFeat = index2[ i ]\n } else {\n accFeat = index1[ i ]\n }\n\n const n = adjacencyList.countArray[ accFeat ]\n const offset = adjacencyList.offsetArray[ accFeat ]\n for (let j = 0; j < n; ++j) {\n const ci = adjacencyList.indexArray[ offset + j ]\n if (isHydrogenBondType(type[ ci ])) {\n contactSet.clear(i)\n return\n }\n }\n })\n}\n\n/**\n * Remove hydrogen bonds between groups that also form\n * a salt bridge between each other\n */\nexport function refineSaltBridges (structure: Structure, contacts: FrozenContacts) {\n const { contactSet, contactStore, features } = contacts\n const { type, index1, index2 } = contactStore\n const { atomSets } = features\n\n const ionicInteractionDict: { [atomIndex: number]: number[] } = {}\n\n const add = function(idx: number, i: number) {\n if (!ionicInteractionDict[ idx ]) ionicInteractionDict[ idx ] = []\n ionicInteractionDict[ idx ].push(i)\n }\n\n contactSet.forEach(i => {\n if (type[ i ] !== ContactType.IonicInteraction) return\n atomSets[ index1[ i ] ].forEach(idx => add(idx, i))\n atomSets[ index2[ i ] ].forEach(idx => add(idx, i))\n })\n\n contactSet.forEach(i => {\n if (!isHydrogenBondType(type[ i ])) return\n\n const iil1 = ionicInteractionDict[ atomSets[ index1[ i ] ][ 0 ] ]\n const iil2 = ionicInteractionDict[ atomSets[ index2[ i ] ][ 0 ] ]\n if (!iil1 || !iil2) return\n\n const n = iil1.length\n for (let j = 0; j < n; ++j) {\n if (iil2.includes(iil1[j])) {\n contactSet.clear(i)\n return\n }\n }\n })\n}\n\n/**\n * Remove hydrophobic and cation-pi interactions between groups that also form\n * a pi-stacking interaction between each other\n */\nexport function refinePiStacking (structure: Structure, contacts: FrozenContacts) {\n const { contactSet, contactStore, features } = contacts\n const { type, index1, index2 } = contactStore\n const { atomSets } = features\n\n const piStackingDict: { [atomIndex: number]: number[] } = {}\n\n const add = function(idx: number, i: number) {\n if (!piStackingDict[ idx ]) piStackingDict[ idx ] = []\n piStackingDict[ idx ].push(i)\n }\n\n contactSet.forEach(i => {\n if (type[ i ] !== ContactType.PiStacking) return\n atomSets[ index1[ i ] ].forEach(idx => add(idx, i))\n atomSets[ index2[ i ] ].forEach(idx => add(idx, i))\n })\n\n contactSet.forEach(i => {\n if (\n type[ i ] !== ContactType.Hydrophobic &&\n type[ i ] !== ContactType.CationPi\n ) return\n\n const pil1 = piStackingDict[ atomSets[ index1[ i ] ][ 0 ] ]\n const pil2 = piStackingDict[ atomSets[ index2[ i ] ][ 0 ] ]\n if (!pil1 || !pil2) return\n\n const n = pil1.length\n for (let j = 0; j < n; ++j) {\n if (pil2.includes(pil1[j])) {\n contactSet.clear(i)\n return\n }\n }\n })\n}\n\n/**\n * Remove ionic interactions between groups that also form\n * a metal coordination between each other\n */\nexport function refineMetalCoordination (structure: Structure, contacts: FrozenContacts) {\n const { contactSet, contactStore, features } = contacts\n const { type, index1, index2 } = contactStore\n const { atomSets } = features\n\n const ionicInteractionDict: { [atomIndex: number]: number[] } = {}\n\n const add = function(idx: number, i: number) {\n if (!ionicInteractionDict[ idx ]) ionicInteractionDict[ idx ] = []\n ionicInteractionDict[ idx ].push(i)\n }\n\n contactSet.forEach(i => {\n if (type[ i ] !== ContactType.IonicInteraction) return\n atomSets[ index1[ i ] ].forEach(idx => add(idx, i))\n atomSets[ index2[ i ] ].forEach(idx => add(idx, i))\n })\n\n contactSet.forEach(i => {\n if (type[ i ] !== ContactType.MetalCoordination) return\n\n const iil1 = ionicInteractionDict[ atomSets[ index1[ i ] ][ 0 ] ]\n const iil2 = ionicInteractionDict[ atomSets[ index2[ i ] ][ 0 ] ]\n if (!iil1 || !iil2) return\n\n const n = iil1.length\n for (let j = 0; j < n; ++j) {\n if (iil2.includes(iil1[j])) {\n contactSet.clear(iil1[j])\n return\n }\n }\n })\n}\n\n// TODO: refactor refineSaltBridges, refinePiStacking and refineMetalCoordination to be DRY\n","/**\n * @file Contact\n * @author Alexander Rose \n */\n\nimport { Color } from 'three'\n\nimport { Debug, Log } from '../../globals'\nimport { createParams } from '../../utils'\nimport { TextBufferData } from '../../buffer/text-buffer'\nimport Structure from '../../structure/structure'\nimport AtomProxy from '../../proxy/atom-proxy'\nimport SpatialHash from '../../geometry/spatial-hash'\nimport { calculateCenterArray, calculateDirectionArray, uniformArray } from '../../math/array-utils'\nimport ContactStore from '../../store/contact-store'\nimport BitArray from '../../utils/bitarray'\nimport Selection from '../../selection/selection'\nimport { ContactPicker } from '../../utils/picker'\nimport { createAdjacencyList, AdjacencyList } from '../../utils/adjacency-list'\nimport { createFeatures, Features } from './features'\nimport { addAromaticRings, addNegativeCharges, addPositiveCharges, addChargedContacts } from './charged'\nimport { addHydrogenAcceptors, addHydrogenDonors, addHydrogenBonds, addWeakHydrogenDonors } from './hydrogen-bonds'\nimport { addMetalBinding, addMetals, addMetalComplexation } from './metal-binding'\nimport { addHydrophobic, addHydrophobicContacts } from './hydrophobic'\nimport { addHalogenAcceptors, addHalogenDonors, addHalogenBonds } from './halogen-bonds'\nimport {\n refineLineOfSight,\n refineHydrophobicContacts, refineSaltBridges, refinePiStacking, refineMetalCoordination\n} from './refine-contacts'\n\nexport interface Contacts {\n features: Features\n spatialHash: SpatialHash\n contactStore: ContactStore\n featureSet: BitArray\n}\n\nexport interface FrozenContacts extends Contacts {\n contactSet: BitArray\n adjacencyList: AdjacencyList\n}\n\nexport const enum ContactType {\n Unknown = 0,\n IonicInteraction = 1,\n CationPi = 2,\n PiStacking = 3,\n HydrogenBond = 4,\n HalogenBond = 5,\n Hydrophobic = 6,\n MetalCoordination = 7,\n WeakHydrogenBond = 8,\n WaterHydrogenBond = 9,\n BackboneHydrogenBond = 10\n}\n\nexport const ContactDefaultParams = {\n maxHydrophobicDist: 4.0,\n maxHbondDist: 3.5,\n maxHbondSulfurDist: 4.1,\n maxHbondAccAngle: 45,\n maxHbondDonAngle: 45,\n maxHbondAccPlaneAngle: 90,\n maxHbondDonPlaneAngle: 30,\n maxPiStackingDist: 5.5,\n maxPiStackingOffset: 2.0,\n maxPiStackingAngle: 30,\n maxCationPiDist: 6.0,\n maxCationPiOffset: 2.0,\n maxIonicDist: 5.0,\n maxHalogenBondDist: 4.0,\n maxHalogenBondAngle: 30,\n maxMetalDist: 3.0,\n refineSaltBridges: true,\n masterModelIndex: -1,\n lineOfSightDistFactor: 1.0\n}\n\nexport function isMasterContact (ap1: AtomProxy, ap2: AtomProxy, masterIdx: number) {\n return (\n (ap1.modelIndex === masterIdx && ap2.modelIndex !== masterIdx) ||\n (ap2.modelIndex === masterIdx && ap1.modelIndex !== masterIdx)\n )\n}\n\nexport function invalidAtomContact (ap1: AtomProxy, ap2: AtomProxy, masterIdx: number) {\n return !isMasterContact(ap1, ap2, masterIdx) && (\n ap1.modelIndex !== ap2.modelIndex ||\n ap1.residueIndex === ap2.residueIndex ||\n (ap1.altloc && ap2.altloc && ap1.altloc !== ap2.altloc)\n )\n}\n\nexport function createContacts (features: Features): Contacts {\n const { types, centers } = features\n\n const spatialHash = new SpatialHash(centers)\n const contactStore = new ContactStore()\n const featureSet = new BitArray(types.length, false)\n\n return { features, spatialHash, contactStore, featureSet }\n}\n\nexport function createFrozenContacts (contacts: Contacts): FrozenContacts {\n const { index1, index2, count } = contacts.contactStore\n\n const adjacencyList = createAdjacencyList({\n nodeArray1: index1,\n nodeArray2: index2,\n edgeCount: count,\n nodeCount: contacts.featureSet.length\n })\n const contactSet = new BitArray(contacts.contactStore.count, true)\n\n return Object.assign({ adjacencyList, contactSet }, contacts)\n}\n\nfunction calculateFeatures (structure: Structure) {\n const features = createFeatures()\n\n if (Debug) Log.time('calculateFeatures')\n\n addPositiveCharges(structure, features)\n addNegativeCharges(structure, features)\n addAromaticRings(structure, features)\n\n addHydrogenAcceptors(structure, features)\n addHydrogenDonors(structure, features)\n addWeakHydrogenDonors(structure, features)\n\n addMetalBinding(structure, features)\n addMetals(structure, features)\n\n addHydrophobic(structure, features)\n\n addHalogenAcceptors(structure, features)\n addHalogenDonors(structure, features)\n\n if (Debug) Log.timeEnd('calculateFeatures')\n\n return features\n}\n\nexport function calculateContacts (structure: Structure, params = ContactDefaultParams) {\n const features = calculateFeatures(structure)\n const contacts = createContacts(features)\n\n if (Debug) Log.time('calculateContacts')\n\n addChargedContacts(structure, contacts, params)\n addHydrogenBonds(structure, contacts, params)\n addMetalComplexation(structure, contacts, params)\n addHydrophobicContacts(structure, contacts, params)\n addHalogenBonds(structure, contacts, params)\n\n const frozenContacts = createFrozenContacts(contacts)\n\n refineLineOfSight(structure, frozenContacts, params)\n refineHydrophobicContacts(structure, frozenContacts)\n if (params.refineSaltBridges) refineSaltBridges(structure, frozenContacts)\n refinePiStacking(structure, frozenContacts)\n refineMetalCoordination(structure, frozenContacts)\n\n if (Debug) Log.timeEnd('calculateContacts')\n\n return frozenContacts\n}\n\nexport function contactTypeName (type: ContactType) {\n switch (type) {\n case ContactType.HydrogenBond:\n case ContactType.WaterHydrogenBond:\n case ContactType.BackboneHydrogenBond:\n return 'hydrogen bond'\n case ContactType.Hydrophobic:\n return 'hydrophobic contact'\n case ContactType.HalogenBond:\n return 'halogen bond'\n case ContactType.IonicInteraction:\n return 'ionic interaction'\n case ContactType.MetalCoordination:\n return 'metal coordination'\n case ContactType.CationPi:\n return 'cation-pi interaction'\n case ContactType.PiStacking:\n return 'pi-pi stacking'\n case ContactType.WeakHydrogenBond:\n return 'weak hydrogen bond'\n default:\n return 'unknown contact'\n }\n}\n\nexport const ContactDataDefaultParams = {\n hydrogenBond: true,\n hydrophobic: true,\n halogenBond: true,\n ionicInteraction: true,\n metalCoordination: true,\n cationPi: true,\n piStacking: true,\n weakHydrogenBond: true,\n waterHydrogenBond: true,\n backboneHydrogenBond: true,\n radius: 1,\n filterSele: ''\n}\nexport type ContactDataParams = typeof ContactDataDefaultParams\n | { filterSele: string|[string, string] }\n\nexport const ContactLabelDefaultParams = {\n unit: '',\n size: 2.0\n}\n\nexport type ContactLabelParams = typeof ContactLabelDefaultParams\n\nconst tmpColor = new Color()\nfunction contactColor (type: ContactType) {\n switch (type) {\n case ContactType.HydrogenBond:\n case ContactType.WaterHydrogenBond:\n case ContactType.BackboneHydrogenBond:\n return tmpColor.setHex(0x2B83BA).toArray()\n case ContactType.Hydrophobic:\n return tmpColor.setHex(0x808080).toArray()\n case ContactType.HalogenBond:\n return tmpColor.setHex(0x40FFBF).toArray()\n case ContactType.IonicInteraction:\n return tmpColor.setHex(0xF0C814).toArray()\n case ContactType.MetalCoordination:\n return tmpColor.setHex(0x8C4099).toArray()\n case ContactType.CationPi:\n return tmpColor.setHex(0xFF8000).toArray()\n case ContactType.PiStacking:\n return tmpColor.setHex(0x8CB366).toArray()\n case ContactType.WeakHydrogenBond:\n return tmpColor.setHex(0xC5DDEC).toArray()\n default:\n return tmpColor.setHex(0xCCCCCC).toArray()\n }\n}\n\nexport interface ContactData {\n position1: Float32Array,\n position2: Float32Array,\n color: Float32Array,\n color2: Float32Array,\n radius: Float32Array,\n picking: ContactPicker\n}\n\nexport function getContactData (contacts: FrozenContacts, structure: Structure, params: ContactDataParams): ContactData {\n const p = createParams(params, ContactDataDefaultParams)\n const types: ContactType[] = []\n if (p.hydrogenBond) types.push(ContactType.HydrogenBond)\n if (p.hydrophobic) types.push(ContactType.Hydrophobic)\n if (p.halogenBond) types.push(ContactType.HalogenBond)\n if (p.ionicInteraction) types.push(ContactType.IonicInteraction)\n if (p.metalCoordination) types.push(ContactType.MetalCoordination)\n if (p.cationPi) types.push(ContactType.CationPi)\n if (p.piStacking) types.push(ContactType.PiStacking)\n if (p.weakHydrogenBond) types.push(ContactType.WeakHydrogenBond)\n if (p.waterHydrogenBond) types.push(ContactType.WaterHydrogenBond)\n if (p.backboneHydrogenBond) types.push(ContactType.BackboneHydrogenBond)\n\n const { features, contactSet, contactStore } = contacts\n const { centers, atomSets } = features\n const { x, y, z } = centers\n const { index1, index2, type } = contactStore\n\n const position1: number[] = []\n const position2: number[] = []\n const color: number[] = []\n const radius: number[] = []\n const picking: number[] = []\n\n let filterSet: BitArray | BitArray[] | undefined\n if (p.filterSele) {\n if (Array.isArray(p.filterSele)) {\n filterSet = p.filterSele.map(sele => {\n return structure.getAtomSet(new Selection(sele))\n })\n } else {\n filterSet = structure.getAtomSet(new Selection(p.filterSele))\n }\n }\n\n contactSet.forEach(i => {\n const ti = type[ i ]\n if (!types.includes(ti)) return\n\n if (filterSet) {\n const idx1 = atomSets[index1[i]][0]\n const idx2 = atomSets[index2[i]][0]\n\n if (Array.isArray(filterSet)) {\n if (!(filterSet[0].isSet(idx1) && filterSet[1].isSet(idx2) || (filterSet[1].isSet(idx1) && filterSet[0].isSet(idx2)))) return\n } else {\n if (!filterSet.isSet(idx1) && !filterSet.isSet(idx2)) return\n }\n }\n\n const k = index1[i]\n const l = index2[i]\n position1.push(x[k], y[k], z[k])\n position2.push(x[l], y[l], z[l])\n color.push(...contactColor(ti))\n radius.push(p.radius)\n picking.push(i)\n })\n\n return {\n position1: new Float32Array(position1),\n position2: new Float32Array(position2),\n color: new Float32Array(color),\n color2: new Float32Array(color),\n radius: new Float32Array(radius),\n picking: new ContactPicker(picking, contacts, structure)\n }\n}\n\nexport function getLabelData (contactData: ContactData, params: ContactLabelParams): TextBufferData {\n\n const position = calculateCenterArray(contactData.position1, contactData.position2)\n const text: string[] = []\n\n const direction = calculateDirectionArray(contactData.position1, contactData.position2)\n\n const n = direction.length / 3\n for (let i=0; i\n */\n\nimport { defaults } from '../../utils'\nimport Structure from '../../structure/structure'\nimport { Elements } from '../../structure/structure-constants'\nimport {\n Features, FeatureType,\n addAtom, addFeature, createFeatureState,\n} from './features'\nimport { Contacts, ContactType, ContactDefaultParams, invalidAtomContact } from './contact'\n\n/**\n * Hydrophobic carbon (only bonded to carbon or hydrogen); fluorine\n */\nexport function addHydrophobic (structure: Structure, features: Features) {\n structure.eachAtom(a => {\n const state = createFeatureState(FeatureType.Hydrophobic)\n let flag = false\n if (a.number === Elements.C) {\n flag = true\n a.eachBondedAtom(ap => {\n const an = ap.number\n if (an !== Elements.C && an !== Elements.H) flag = false\n })\n } else if (a.number === Elements.F) {\n flag = true\n }\n if (flag) {\n addAtom(state, a)\n addFeature(features, state)\n }\n })\n}\n\nfunction isHydrophobicContact (ti: FeatureType, tj: FeatureType) {\n return ti === FeatureType.Hydrophobic && tj === FeatureType.Hydrophobic\n}\n\nexport interface HydrophobicContactsParams {\n maxHydrophobicDist?: number\n masterModelIndex?: number\n}\n\n/**\n * All hydrophobic contacts\n */\nexport function addHydrophobicContacts (structure: Structure, contacts: Contacts, params: HydrophobicContactsParams = {}) {\n const maxHydrophobicDist = defaults(params.maxHydrophobicDist, ContactDefaultParams.maxHydrophobicDist)\n const masterIdx = defaults(params.masterModelIndex, ContactDefaultParams.masterModelIndex)\n\n const { features, spatialHash, contactStore, featureSet } = contacts\n const { types, centers, atomSets } = features\n const { x, y, z } = centers\n const n = types.length\n\n const ap1 = structure.getAtomProxy()\n const ap2 = structure.getAtomProxy()\n\n for (let i = 0; i < n; ++i) {\n spatialHash.eachWithin(x[i], y[i], z[i], maxHydrophobicDist, (j, dSq) => {\n if (j <= i) return\n\n ap1.index = atomSets[ i ][ 0 ]\n ap2.index = atomSets[ j ][ 0 ]\n\n if (invalidAtomContact(ap1, ap2, masterIdx)) return\n if (ap1.number === Elements.F && ap2.number === Elements.F) return\n if (ap1.connectedTo(ap2)) return\n\n if (isHydrophobicContact(types[ i ], types[ j ])) {\n featureSet.setBits(i, j)\n contactStore.addContact(i, j, ContactType.Hydrophobic)\n }\n })\n }\n}\n","/**\n * @file Picker\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { PickerRegistry } from '../globals'\nimport { calculateMeanVector3 } from '../math/vector-utils'\nimport Selection from '../selection/selection'\nimport {\n ArrowPrimitive, BoxPrimitive, ConePrimitive, CylinderPrimitive,\n EllipsoidPrimitive, OctahedronPrimitive, SpherePrimitive,\n TetrahedronPrimitive, TorusPrimitive, PointPrimitive, WidelinePrimitive\n} from '../geometry/primitive'\nimport { contactTypeName, Contacts } from '../chemistry/interactions/contact'\nimport { TypedArray } from '../types';\nimport Component from '../component/component';\nimport { Shape, Structure, Volume } from '../ngl';\nimport BondStore from '../store/bond-store';\nimport Validation from '../structure/validation';\nimport PrincipalAxes from '../math/principal-axes';\nimport Surface from '../surface/surface';\nimport Unitcell from '../symmetry/unitcell';\nimport BondProxy from '../proxy/bond-proxy';\nimport AtomProxy from '../proxy/atom-proxy';\n\n/**\n * Picker class\n * @interface\n */\nclass Picker {\n array: number[]|TypedArray|undefined\n /**\n * @param {Array|TypedArray} [array] - mapping\n */\n constructor (array?: number[]|TypedArray) {\n this.array = array\n }\n\n get type () { return '' }\n get data () { return {} }\n\n /**\n * Get the index for the given picking id\n * @param {Integer} pid - the picking id\n * @return {Integer} the index\n */\n getIndex (pid: number) {\n return this.array ? this.array[ pid ] : pid\n }\n\n /**\n * Get object data\n * @abstract\n * @param {Integer} pid - the picking id\n * @return {Object} the object data\n */\n getObject (pid: number) {\n return {}\n }\n\n _applyTransformations (vector: Vector3, instance: any, component: Component) {\n if (instance) {\n vector.applyMatrix4(instance.matrix)\n }\n if (component) {\n vector.applyMatrix4(component.matrix)\n }\n return vector\n }\n\n /**\n * Get object position\n * @abstract\n * @param {Integer} pid - the picking id\n * @return {Vector3} the object position\n */\n _getPosition (pid: number) {\n return new Vector3()\n }\n\n /**\n * Get position for the given picking id\n * @param {Integer} pid - the picking id\n * @param {Object} instance - the instance that should be applied\n * @param {Component} component - the component of the picked object\n * @return {Vector3} the position\n */\n getPosition (pid: number, instance: any, component: Component) {\n return this._applyTransformations(\n this._getPosition(pid), instance, component\n )\n }\n}\n\n/**\n * Shape picker class\n * @interface\n */\nclass ShapePicker extends Picker {\n shape: Shape\n /**\n * @param {Shape} shape - shape object\n */\n constructor (shape: Shape) {\n super()\n this.shape = shape\n }\n\n get primitive (): any { return }\n\n get data () { return this.shape }\n get type () { return this.primitive.type }\n\n getObject (pid: number) {\n return this.primitive.objectFromShape(this.shape, this.getIndex(pid))\n }\n\n _getPosition (pid: number) {\n return this.primitive.positionFromShape(this.shape, this.getIndex(pid))\n }\n}\n\n//\n\nclass CylinderPicker extends ShapePicker {\n get primitive () { return CylinderPrimitive }\n}\n\nclass ArrowPicker extends ShapePicker {\n get primitive () { return ArrowPrimitive }\n}\n\nclass AtomPicker extends Picker {\n structure: Structure\n constructor (array: Float32Array, structure: Structure) {\n super(array)\n this.structure = structure\n }\n\n get type () { return 'atom' }\n get data () { return this.structure }\n\n getObject (pid: number): AtomProxy {\n return this.structure.getAtomProxy(this.getIndex(pid))\n }\n\n _getPosition (pid: number) {\n return new Vector3().copy(this.getObject(pid) as any)\n }\n}\n\nclass AxesPicker extends Picker {\n axes: PrincipalAxes\n constructor (axes: PrincipalAxes) {\n super()\n this.axes = axes\n }\n\n get type () { return 'axes' }\n get data () { return this.axes }\n\n getObject (/* pid */) {\n return {\n axes: this.axes\n }\n }\n\n _getPosition (/* pid */) {\n return this.axes.center.clone()\n }\n}\n\nclass BondPicker extends Picker {\n structure: Structure\n bondStore: BondStore\n constructor (array: number[]|TypedArray|undefined, structure: Structure, bondStore?: BondStore) {\n super(array)\n this.structure = structure\n this.bondStore = bondStore || structure.bondStore\n }\n\n get type () { return 'bond' }\n get data () { return this.structure }\n\n getObject (pid: number): BondProxy {\n const bp = this.structure.getBondProxy(this.getIndex(pid))\n bp.bondStore = this.bondStore\n return bp\n }\n\n _getPosition (pid: number) {\n const b = this.getObject(pid)\n return new Vector3()\n .copy(b.atom1 as any)\n .add(b.atom2 as any)\n .multiplyScalar(0.5)\n }\n}\n\nclass ContactPicker extends Picker {\n contacts: Contacts\n structure: Structure\n constructor (array: number[]|TypedArray|undefined, contacts: Contacts, structure: Structure) {\n super(array)\n this.contacts = contacts\n this.structure = structure\n }\n\n get type () { return 'contact' }\n get data () { return this.contacts }\n\n getObject (pid: number) {\n const idx = this.getIndex(pid)\n const { features, contactStore } = this.contacts\n const { centers, atomSets } = features\n const { x, y, z } = centers\n const { index1, index2, type } = contactStore\n const k = index1[idx]\n const l = index2[idx]\n return {\n center1: new Vector3(x[k], y[k], z[k]),\n center2: new Vector3(x[l], y[l], z[l]),\n atom1: this.structure.getAtomProxy(atomSets[k][0]),\n atom2: this.structure.getAtomProxy(atomSets[l][0]),\n type: contactTypeName(type[idx])\n }\n }\n\n _getPosition (pid: number) {\n const { center1, center2 } = this.getObject(pid)\n return new Vector3().addVectors(center1, center2).multiplyScalar(0.5)\n }\n}\n\nclass ConePicker extends ShapePicker {\n get primitive () { return ConePrimitive }\n}\n\nclass ClashPicker extends Picker {\n validation: Validation\n structure: Structure\n constructor (array: number[]|TypedArray|undefined, validation: Validation, structure: Structure) {\n super(array)\n this.validation = validation\n this.structure = structure\n }\n\n get type () { return 'clash' }\n get data () { return this.validation }\n\n getObject (pid: number) {\n const val = this.validation\n const idx = this.getIndex(pid)\n return {\n validation: val,\n index: idx,\n clash: val.clashArray[ idx ]\n }\n }\n\n _getAtomProxyFromSele (sele: string) {\n const selection = new Selection(sele)\n const idx = this.structure.getAtomIndices(selection)![ 0 ]\n return this.structure.getAtomProxy(idx)\n }\n\n _getPosition (pid: number) {\n const clash = this.getObject(pid).clash\n const ap1 = this._getAtomProxyFromSele(clash.sele1)\n const ap2 = this._getAtomProxyFromSele(clash.sele2)\n return new Vector3().copy(ap1 as any).add(ap2 as any).multiplyScalar(0.5)\n }\n}\n\nclass DistancePicker extends BondPicker {\n get type () { return 'distance' }\n}\n\nclass EllipsoidPicker extends ShapePicker {\n get primitive () { return EllipsoidPrimitive }\n}\n\nclass OctahedronPicker extends ShapePicker {\n get primitive () { return OctahedronPrimitive }\n}\n\nclass BoxPicker extends ShapePicker {\n get primitive () { return BoxPrimitive }\n}\n\nclass IgnorePicker extends Picker {\n get type () { return 'ignore' }\n}\n\nexport interface MeshData {\n name: string|undefined\n serial: number\n index: Uint32Array|Uint16Array|number[]\n normal?: Float32Array|number[]\n position: Float32Array|number[]\n color: Float32Array|number[]\n}\nclass MeshPicker extends ShapePicker {\n mesh: MeshData\n __position: Vector3\n\n constructor (shape: Shape, mesh: MeshData) {\n super(shape)\n this.mesh = mesh\n }\n\n get type () { return 'mesh' }\n\n getObject (/* pid */) {\n const m = this.mesh\n return {\n shape: this.shape,\n name: m.name,\n serial: m.serial\n }\n }\n\n _getPosition (/* pid */) {\n if (!this.__position) {\n this.__position = calculateMeanVector3(this.mesh.position as any)\n }\n return this.__position\n }\n}\n\nclass SpherePicker extends ShapePicker {\n get primitive () { return SpherePrimitive }\n}\n\nclass SurfacePicker extends Picker {\n surface: Surface\n constructor (array: number[]|TypedArray|undefined, surface: Surface) {\n super(array)\n this.surface = surface\n }\n\n get type () { return 'surface' }\n get data () { return this.surface }\n\n getObject (pid: number) {\n return {\n surface: this.surface,\n index: this.getIndex(pid)\n }\n }\n\n _getPosition (/* pid */) {\n return this.surface.center.clone()\n }\n}\n\nclass TetrahedronPicker extends ShapePicker {\n get primitive () { return TetrahedronPrimitive }\n}\n\nclass TorusPicker extends ShapePicker {\n get primitive () { return TorusPrimitive }\n}\n\nclass UnitcellPicker extends Picker {\n unitcell: Unitcell\n structure: Structure\n\n constructor (unitcell: Unitcell, structure: Structure) {\n super()\n this.unitcell = unitcell\n this.structure = structure\n }\n\n get type () { return 'unitcell' }\n get data () { return this.unitcell }\n\n getObject (/* pid */) {\n return {\n unitcell: this.unitcell,\n structure: this.structure\n }\n }\n\n _getPosition (/* pid */) {\n return this.unitcell.getCenter(this.structure)\n }\n}\n\nclass UnknownPicker extends Picker {\n get type () { return 'unknown' }\n}\n\nclass VolumePicker extends Picker {\n volume: Volume\n constructor (array: TypedArray, volume: Volume) {\n super(array)\n this.volume = volume\n }\n\n get type () { return 'volume' }\n get data () { return this.volume }\n\n getObject (pid: number) {\n const vol = this.volume\n const idx = this.getIndex(pid)\n return {\n volume: vol,\n index: idx,\n value: vol.data[ idx ]\n }\n }\n\n _getPosition (pid: number) {\n const dp = this.volume.position\n const idx = this.getIndex(pid)\n return new Vector3(\n dp[ idx * 3 ],\n dp[ idx * 3 + 1 ],\n dp[ idx * 3 + 2 ]\n )\n }\n}\n\nclass SlicePicker extends VolumePicker {\n get type () { return 'slice' }\n}\n\nclass PointPicker extends ShapePicker {\n get primitive () { return PointPrimitive }\n}\n\nclass WidelinePicker extends ShapePicker {\n get primitive () { return WidelinePrimitive }\n}\n\nPickerRegistry.add('arrow', ArrowPicker)\nPickerRegistry.add('box', BoxPicker)\nPickerRegistry.add('cone', ConePicker)\nPickerRegistry.add('cylinder', CylinderPicker)\nPickerRegistry.add('ellipsoid', EllipsoidPicker)\nPickerRegistry.add('octahedron', OctahedronPicker)\nPickerRegistry.add('sphere', SpherePicker)\nPickerRegistry.add('tetrahedron', TetrahedronPicker)\nPickerRegistry.add('torus', TorusPicker)\nPickerRegistry.add('point', PointPicker)\nPickerRegistry.add('wideline', WidelinePicker)\n\nexport {\n Picker,\n ShapePicker,\n ArrowPicker,\n AtomPicker,\n AxesPicker,\n BondPicker,\n BoxPicker,\n ConePicker,\n ContactPicker,\n CylinderPicker,\n ClashPicker,\n DistancePicker,\n EllipsoidPicker,\n IgnorePicker,\n OctahedronPicker,\n MeshPicker,\n SlicePicker,\n SpherePicker,\n SurfacePicker,\n TetrahedronPicker,\n TorusPicker,\n UnitcellPicker,\n UnknownPicker,\n VolumePicker,\n PointPicker,\n WidelinePicker\n}\n","/**\n * @file Marching Cubes\n * @author Alexander Rose \n * @private\n */\n\nimport { getUintArray } from '../utils'\n\nfunction getEdgeTable () {\n return new Uint32Array([\n 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,\n 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,\n 0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,\n 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,\n 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,\n 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,\n 0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,\n 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,\n 0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,\n 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,\n 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,\n 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,\n 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,\n 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,\n 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,\n 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,\n 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,\n 0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,\n 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,\n 0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,\n 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,\n 0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,\n 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,\n 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,\n 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,\n 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,\n 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,\n 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,\n 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,\n 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,\n 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,\n 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0\n ])\n}\n\nfunction getTriTable (): Int32Array {\n return new Int32Array([\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1,\n 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1,\n 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1,\n 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1,\n 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1,\n 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1,\n 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1,\n 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1,\n 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1,\n 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1,\n 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1,\n 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1,\n 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1,\n 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1,\n 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1,\n 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1,\n 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1,\n 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1,\n 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1,\n 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1,\n 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1,\n 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1,\n 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1,\n 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1,\n 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1,\n 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1,\n 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1,\n 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1,\n 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1,\n 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1,\n 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1,\n 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1,\n 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1,\n 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1,\n 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1,\n 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1,\n 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1,\n 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1,\n 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1,\n 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1,\n 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1,\n 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1,\n 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1,\n 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1,\n 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1,\n 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1,\n 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1,\n 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1,\n 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1,\n 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1,\n 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1,\n 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1,\n 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1,\n 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1,\n 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1,\n 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1,\n 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1,\n 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1,\n 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1,\n 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1,\n 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1,\n 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1,\n 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1,\n 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1,\n 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1,\n 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1,\n 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1,\n 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1,\n 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1,\n 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1,\n 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1,\n 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1,\n 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1,\n 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1,\n 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1,\n 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1,\n 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1,\n 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1,\n 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1,\n 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1,\n 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1,\n 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1,\n 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1,\n 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1,\n 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1,\n 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1,\n 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1,\n 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1,\n 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1,\n 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1,\n 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1,\n 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1,\n 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1,\n 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1,\n 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1,\n 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1,\n 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1,\n 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1,\n 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1,\n 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1,\n 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1,\n 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1,\n 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1,\n 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1,\n 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1,\n 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1,\n 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1,\n 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1,\n 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1,\n 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1,\n 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1,\n 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1,\n 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1,\n 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1,\n 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1,\n 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1,\n 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1,\n 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1,\n 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1,\n 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1,\n 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1,\n 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1,\n 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1,\n 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1,\n 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1,\n 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1,\n 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1,\n 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1,\n 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1,\n 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1,\n 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1,\n 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1,\n 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1,\n 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1,\n 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1,\n 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1,\n 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1,\n 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1,\n 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1,\n 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1,\n 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1,\n 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1,\n 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1,\n 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1,\n 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1,\n 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1,\n 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1,\n 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1,\n 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1,\n 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1,\n 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1,\n 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1,\n 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1,\n 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1,\n 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1,\n 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1,\n 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1,\n 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1,\n 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1,\n 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1,\n 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1,\n 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1,\n 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1,\n 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1,\n 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1,\n 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1,\n 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1,\n 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1,\n 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1,\n 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1,\n 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1,\n 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1,\n 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1,\n 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1,\n 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1,\n 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1,\n 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1,\n 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1,\n 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1,\n 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\n ])\n}\n\ninterface MarchingCubes {\n new (field: number[], nx: number, ny: number, nz: number, atomindex: number[]): void\n triangulate: (_isolevel: number, _noNormals: boolean, _box: number[][]|undefined, _contour: boolean, _wrap: boolean) => {\n position: Float32Array\n normal: undefined|Float32Array\n index: Uint32Array|Uint16Array\n atomindex: Int32Array|undefined\n contour: boolean\n }\n}\nfunction MarchingCubes (this: MarchingCubes, field: number[], nx: number, ny: number, nz: number, atomindex: number[]) {\n // Based on alteredq / http://alteredqualia.com/\n // port of greggman's ThreeD version of marching cubes to Three.js\n // http://webglsamples.googlecode.com/hg/blob/blob.html\n //\n // Adapted for NGL by Alexander Rose\n\n // Triangles are constructed between points on cube edges.\n // allowedContours[edge1][edge1] indicates which lines from a given\n // triangle should be shown in line mode.\n\n // Values are bitmasks:\n // In loop over cubes we keep another bitmask indicating whether our current\n // cell is the first x-value (1),\n // first y-value (2) or first z-value (4) of the current loop.\n // We draw all lines on leading faces but only draw trailing face lines the first\n // time through the loop\n // A value of 8 below means the edge is always drawn (leading face)\n\n // E.g. the first row, lines between edge0 and other edges in the bottom\n // x-y plane are only drawn for the first value of z, edges in the\n // x-z plane are only drawn for the first value of y. No other lines\n // are drawn as they're redundant\n // The line between edge 1 and 5 is always drawn as it's on the leading edge\n var allowedContours = [\n\n [ 0, 4, 4, 4, 2, 0, 0, 0, 2, 2, 0, 0 ], // 1 2 3 4 8 9\n [ 4, 0, 4, 4, 0, 8, 0, 0, 0, 8, 8, 0 ], // 0 2 3 5 9 10\n [ 4, 4, 0, 4, 0, 0, 8, 0, 0, 0, 8, 8 ], // 0 1 3 6 10 11\n [ 4, 4, 4, 0, 0, 0, 0, 1, 1, 0, 0, 1 ], // 0 1 2 7 8 11\n [ 2, 0, 0, 0, 0, 8, 8, 8, 2, 2, 0, 0 ], // 0 5 6 7 8 9\n [ 0, 8, 0, 0, 8, 0, 8, 8, 0, 8, 8, 0 ], // And rotate it\n [ 0, 0, 8, 0, 8, 8, 0, 8, 0, 0, 8, 8 ],\n [ 0, 0, 0, 1, 8, 8, 8, 0, 1, 0, 0, 1 ],\n [ 2, 0, 0, 1, 2, 0, 0, 1, 0, 2, 0, 1 ], // 0 3 4 7 9 11\n [ 2, 8, 0, 0, 2, 8, 0, 0, 2, 0, 8, 0 ], // And rotate some more\n [ 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8 ],\n [ 0, 0, 8, 1, 0, 0, 8, 1, 1, 0, 8, 0 ]\n\n ]\n\n var isolevel = 0\n var noNormals = false\n var contour = false\n var wrap = false\n var isNegativeIso = false\n var normalFactor = -1\n\n\n var n = nx * ny * nz\n\n // deltas\n var yd = nx\n var zd = nx * ny\n\n var normalCache: Float32Array, vertexIndex: Int32Array\n var count: number, icount: number\n\n var ilist = new Int32Array(12)\n\n var positionArray: number[] = []\n var normalArray: number[] = []\n var indexArray: number[] = []\n var atomindexArray: number[] = []\n\n var edgeTable = getEdgeTable()\n var triTable = getTriTable()\n\n var mx: number, my: number, mz: number\n\n //\n\n this.triangulate = function (_isolevel: number, _noNormals: boolean, _box: number[][]|undefined, _contour: boolean, _wrap: boolean) {\n isolevel = _isolevel\n isNegativeIso = isolevel < 0.0\n contour = _contour\n wrap = _wrap\n // Normals currently disabled in contour mode for performance (unused)\n noNormals = _noNormals || contour\n\n if (!noNormals) {\n normalFactor = isolevel > 0 ? -1.0 : 1.0\n if (!normalCache) {\n normalCache = new Float32Array(n * 3)\n } \n }\n\n var vIndexLength = n * 3\n\n if (!vertexIndex || vertexIndex.length !== vIndexLength) {\n vertexIndex = new Int32Array(vIndexLength)\n }\n\n count = 0\n icount = 0\n\n if (_box !== undefined) {\n var min = _box[ 0 ].map(Math.round)\n var max = _box[ 1 ].map(Math.round)\n\n mx = nx * Math.ceil(Math.abs(min[ 0 ]) / nx)\n my = ny * Math.ceil(Math.abs(min[ 1 ]) / ny)\n mz = nz * Math.ceil(Math.abs(min[ 2 ]) / nz)\n\n triangulate(\n min[ 0 ], min[ 1 ], min[ 2 ],\n max[ 0 ], max[ 1 ], max[ 2 ]\n )\n } else {\n mx = my = mz = 0\n\n triangulate()\n }\n\n positionArray.length = count * 3\n if (!noNormals) normalArray.length = count * 3\n indexArray.length = icount\n if (atomindex) atomindexArray.length = count\n\n return {\n position: new Float32Array(positionArray),\n normal: noNormals ? undefined : new Float32Array(normalArray),\n index: getUintArray(indexArray, positionArray.length / 3),\n atomindex: atomindex ? new Int32Array(atomindexArray) : undefined,\n contour: contour\n }\n }\n\n // polygonization\n\n function lerp (a: number, b: number, t: number) { return a + (b - a) * t }\n\n function index (x: number, y: number, z: number) {\n x = (x + mx) % nx\n y = (y + my) % ny\n z = (z + mz) % nz\n return ((zd * z) + yd * y) + x\n }\n\n function VIntX (q: number, offset: number, x: number, y: number, z: number, valp1: number, valp2: number) {\n var _q = 3 * q\n\n if (vertexIndex[ _q ] < 0) {\n var mu = (isolevel - valp1) / (valp2 - valp1)\n var nc = normalCache\n\n var c = count * 3\n\n positionArray[ c ] = x + mu\n positionArray[ c + 1 ] = y\n positionArray[ c + 2 ] = z\n\n if (!noNormals) {\n var q3 = q * 3\n\n normalArray[ c ] = normalFactor * lerp(nc[ q3 ], nc[ q3 + 3 ], mu)\n normalArray[ c + 1 ] = normalFactor * lerp(nc[ q3 + 1 ], nc[ q3 + 4 ], mu)\n normalArray[ c + 2 ] = normalFactor * lerp(nc[ q3 + 2 ], nc[ q3 + 5 ], mu)\n }\n\n if (atomindex) atomindexArray[ count ] = atomindex[ q + Math.round(mu) ]\n\n vertexIndex[ _q ] = count\n ilist[ offset ] = count\n\n count += 1\n } else {\n ilist[ offset ] = vertexIndex[ _q ]\n }\n }\n\n function VIntY (q: number, offset: number, x: number, y: number, z: number, valp1: number, valp2: number) {\n var _q = 3 * q + 1\n\n if (vertexIndex[ _q ] < 0) {\n var mu = (isolevel - valp1) / (valp2 - valp1)\n var nc = normalCache\n\n var c = count * 3\n\n positionArray[ c ] = x\n positionArray[ c + 1 ] = y + mu\n positionArray[ c + 2 ] = z\n\n if (!noNormals) {\n var q3 = q * 3\n var q6 = q3 + yd * 3\n\n normalArray[ c ] = normalFactor * lerp(nc[ q3 ], nc[ q6 ], mu)\n normalArray[ c + 1 ] = normalFactor * lerp(nc[ q3 + 1 ], nc[ q6 + 1 ], mu)\n normalArray[ c + 2 ] = normalFactor * lerp(nc[ q3 + 2 ], nc[ q6 + 2 ], mu)\n }\n\n if (atomindex) atomindexArray[ count ] = atomindex[ q + Math.round(mu) * yd ]\n\n vertexIndex[ _q ] = count\n ilist[ offset ] = count\n\n count += 1\n } else {\n ilist[ offset ] = vertexIndex[ _q ]\n }\n }\n\n function VIntZ (q: number, offset: number, x: number, y: number, z: number, valp1: number, valp2: number) {\n var _q = 3 * q + 2\n\n if (vertexIndex[ _q ] < 0) {\n var mu = (isolevel - valp1) / (valp2 - valp1)\n var nc = normalCache\n\n var c = count * 3\n\n positionArray[ c ] = x\n positionArray[ c + 1 ] = y\n positionArray[ c + 2 ] = z + mu\n\n if (!noNormals) {\n var q3 = q * 3\n var q6 = q3 + zd * 3\n\n normalArray[ c ] = normalFactor * lerp(nc[ q3 ], nc[ q6 ], mu)\n normalArray[ c + 1 ] = normalFactor * lerp(nc[ q3 + 1 ], nc[ q6 + 1 ], mu)\n normalArray[ c + 2 ] = normalFactor * lerp(nc[ q3 + 2 ], nc[ q6 + 2 ], mu)\n }\n\n if (atomindex) atomindexArray[ count ] = atomindex[ q + Math.round(mu) * zd ]\n\n vertexIndex[ _q ] = count\n ilist[ offset ] = count\n\n count += 1\n } else {\n ilist[ offset ] = vertexIndex[ _q ]\n }\n }\n\n function compNorm (q: number) {\n var q3 = q * 3\n\n if (normalCache[ q3 ] === 0.0) {\n normalCache[ q3 ] = field[ (q - 1 + n) % n ] - field[ (q + 1) % n ]\n normalCache[ q3 + 1 ] = field[ (q - yd + n) % n ] - field[ (q + yd) % n ]\n normalCache[ q3 + 2 ] = field[ (q - zd + n) % n ] - field[ (q + zd) % n ]\n }\n }\n\n function polygonize (fx: number, fy: number, fz: number, q: number, edgeFilter: number) {\n // cache indices\n var q1\n var qy\n var qz\n var q1y\n var q1z\n var qyz\n var q1yz\n if (wrap) {\n q = index(fx, fy, fz)\n q1 = index(fx + 1, fy, fz)\n qy = index(fx, fy + 1, fz)\n qz = index(fx, fy, fz + 1)\n q1y = index(fx + 1, fy + 1, fz)\n q1z = index(fx + 1, fy, fz + 1)\n qyz = index(fx, fy + 1, fz + 1)\n q1yz = index(fx + 1, fy + 1, fz + 1)\n } else {\n q1 = q + 1\n qy = q + yd\n qz = q + zd\n q1y = qy + 1\n q1z = qz + 1\n qyz = qy + zd\n q1yz = qyz + 1\n }\n\n var cubeindex = 0\n var field0 = field[ q ]\n var field1 = field[ q1 ]\n var field2 = field[ qy ]\n var field3 = field[ q1y ]\n var field4 = field[ qz ]\n var field5 = field[ q1z ]\n var field6 = field[ qyz ]\n var field7 = field[ q1yz ]\n\n if (field0 < isolevel) cubeindex |= 1\n if (field1 < isolevel) cubeindex |= 2\n if (field2 < isolevel) cubeindex |= 8\n if (field3 < isolevel) cubeindex |= 4\n if (field4 < isolevel) cubeindex |= 16\n if (field5 < isolevel) cubeindex |= 32\n if (field6 < isolevel) cubeindex |= 128\n if (field7 < isolevel) cubeindex |= 64\n\n // if cube is entirely in/out of the surface - bail, nothing to draw\n\n var bits = edgeTable[ cubeindex ]\n if (bits === 0) return 0\n\n var fx2 = fx + 1\n var fy2 = fy + 1\n var fz2 = fz + 1\n\n // top of the cube\n\n if (bits & 1) {\n if (!noNormals) {\n compNorm(q)\n compNorm(q1)\n }\n VIntX(q, 0, fx, fy, fz, field0, field1)\n }\n\n if (bits & 2) {\n if (!noNormals) {\n compNorm(q1)\n compNorm(q1y)\n }\n VIntY(q1, 1, fx2, fy, fz, field1, field3)\n }\n\n if (bits & 4) {\n if (!noNormals) {\n compNorm(qy)\n compNorm(q1y)\n }\n VIntX(qy, 2, fx, fy2, fz, field2, field3)\n }\n\n if (bits & 8) {\n if (!noNormals) {\n compNorm(q)\n compNorm(qy)\n }\n VIntY(q, 3, fx, fy, fz, field0, field2)\n }\n\n // bottom of the cube\n\n if (bits & 16) {\n if (!noNormals) {\n compNorm(qz)\n compNorm(q1z)\n }\n VIntX(qz, 4, fx, fy, fz2, field4, field5)\n }\n\n if (bits & 32) {\n if (!noNormals) {\n compNorm(q1z)\n compNorm(q1yz)\n }\n VIntY(q1z, 5, fx2, fy, fz2, field5, field7)\n }\n\n if (bits & 64) {\n if (!noNormals) {\n compNorm(qyz)\n compNorm(q1yz)\n }\n VIntX(qyz, 6, fx, fy2, fz2, field6, field7)\n }\n\n if (bits & 128) {\n if (!noNormals) {\n compNorm(qz)\n compNorm(qyz)\n }\n VIntY(qz, 7, fx, fy, fz2, field4, field6)\n }\n\n // vertical lines of the cube\n\n if (bits & 256) {\n if (!noNormals) {\n compNorm(q)\n compNorm(qz)\n }\n VIntZ(q, 8, fx, fy, fz, field0, field4)\n }\n\n if (bits & 512) {\n if (!noNormals) {\n compNorm(q1)\n compNorm(q1z)\n }\n VIntZ(q1, 9, fx2, fy, fz, field1, field5)\n }\n\n if (bits & 1024) {\n if (!noNormals) {\n compNorm(q1y)\n compNorm(q1yz)\n }\n VIntZ(q1y, 10, fx2, fy2, fz, field3, field7)\n }\n\n if (bits & 2048) {\n if (!noNormals) {\n compNorm(qy)\n compNorm(qyz)\n }\n VIntZ(qy, 11, fx, fy2, fz, field2, field6)\n }\n\n var triIndex = cubeindex << 4 // re-purpose cubeindex into an offset into triTable\n\n var e1\n var e2\n var e3\n var i = 0\n\n // here is where triangles are created\n\n while (triTable[ triIndex + i ] !== -1) {\n e1 = triTable[ triIndex + i ]\n e2 = triTable[ triIndex + i + 1 ]\n e3 = triTable[ triIndex + i + 2 ]\n\n if (contour) {\n if (allowedContours[ e1 ][ e2 ] & edgeFilter) {\n indexArray[ icount++ ] = ilist[ e1 ]\n indexArray[ icount++ ] = ilist[ e2 ]\n }\n if (allowedContours[ e2 ][ e3 ] & edgeFilter) {\n indexArray[ icount++ ] = ilist[ e2 ]\n indexArray[ icount++ ] = ilist[ e3 ]\n }\n if (allowedContours[ e1 ][ e3 ] & edgeFilter) {\n indexArray[ icount++ ] = ilist[ e1 ]\n indexArray[ icount++ ] = ilist[ e3 ]\n }\n } else {\n indexArray[ icount++ ] = ilist[ isNegativeIso ? e1 : e2 ]\n indexArray[ icount++ ] = ilist[ isNegativeIso ? e2 : e1 ]\n indexArray[ icount++ ] = ilist[ e3 ]\n }\n\n i += 3\n }\n }\n\n function triangulate (xBeg?: number, yBeg?: number, zBeg?: number, xEnd?: number, yEnd?: number, zEnd?: number) {\n let q\n let q3\n let x\n let y\n let z\n let yOffset\n let zOffset\n\n xBeg = xBeg !== undefined ? xBeg : 0\n yBeg = yBeg !== undefined ? yBeg : 0\n zBeg = zBeg !== undefined ? zBeg : 0\n\n xEnd = xEnd !== undefined ? xEnd : nx - 1\n yEnd = yEnd !== undefined ? yEnd : ny - 1\n zEnd = zEnd !== undefined ? zEnd : nz - 1\n\n if (!wrap) {\n if (noNormals) {\n xBeg = Math.max(0, xBeg)\n yBeg = Math.max(0, yBeg)\n zBeg = Math.max(0, zBeg)\n\n xEnd = Math.min(nx - 1, xEnd)\n yEnd = Math.min(ny - 1, yEnd)\n zEnd = Math.min(nz - 1, zEnd)\n } else {\n xBeg = Math.max(1, xBeg)\n yBeg = Math.max(1, yBeg)\n zBeg = Math.max(1, zBeg)\n\n xEnd = Math.min(nx - 2, xEnd)\n yEnd = Math.min(ny - 2, yEnd)\n zEnd = Math.min(nz - 2, zEnd)\n }\n }\n\n let xBeg2, yBeg2, zBeg2, xEnd2, yEnd2, zEnd2\n\n if (!wrap) {\n // init part of the vertexIndex\n // (takes a significant amount of time to do for all)\n\n xBeg2 = Math.max(0, xBeg - 2)\n yBeg2 = Math.max(0, yBeg - 2)\n zBeg2 = Math.max(0, zBeg - 2)\n\n xEnd2 = Math.min(nx, xEnd + 2)\n yEnd2 = Math.min(ny, yEnd + 2)\n zEnd2 = Math.min(nz, zEnd + 2)\n\n for (z = zBeg2; z < zEnd2; ++z) {\n zOffset = zd * z\n for (y = yBeg2; y < yEnd2; ++y) {\n yOffset = zOffset + yd * y\n for (x = xBeg2; x < xEnd2; ++x) {\n q = 3 * (yOffset + x)\n vertexIndex[ q ] = -1\n vertexIndex[ q + 1 ] = -1\n vertexIndex[ q + 2 ] = -1\n }\n }\n }\n } else {\n xBeg2 = xBeg - 2\n yBeg2 = yBeg - 2\n zBeg2 = zBeg - 2\n\n xEnd2 = xEnd + 2\n yEnd2 = yEnd + 2\n zEnd2 = zEnd + 2\n\n for (z = zBeg2; z < zEnd2; ++z) {\n for (y = yBeg2; y < yEnd2; ++y) {\n for (x = xBeg2; x < xEnd2; ++x) {\n q3 = index(x, y, z) * 3\n vertexIndex[ q3 ] = -1\n vertexIndex[ q3 + 1 ] = -1\n vertexIndex[ q3 + 2 ] = -1\n }\n }\n }\n }\n\n if (!wrap) {\n // clip space where the isovalue is too low\n\n var __break\n var __xBeg = xBeg; var __yBeg = yBeg; var __zBeg = zBeg\n var __xEnd = xEnd; var __yEnd = yEnd; var __zEnd = zEnd\n\n __break = false\n for (z = zBeg; z < zEnd; ++z) {\n for (y = yBeg; y < yEnd; ++y) {\n for (x = xBeg; x < xEnd; ++x) {\n q = ((nx * ny) * z) + (nx * y) + x\n if (field[ q ] >= isolevel) {\n __zBeg = z\n __break = true\n break\n }\n }\n if (__break) break\n }\n if (__break) break\n }\n\n __break = false\n for (y = yBeg; y < yEnd; ++y) {\n for (z = __zBeg; z < zEnd; ++z) {\n for (x = xBeg; x < xEnd; ++x) {\n q = ((nx * ny) * z) + (nx * y) + x\n if (field[ q ] >= isolevel) {\n __yBeg = y\n __break = true\n break\n }\n }\n if (__break) break\n }\n if (__break) break\n }\n\n __break = false\n for (x = xBeg; x < xEnd; ++x) {\n for (y = __yBeg; y < yEnd; ++y) {\n for (z = __zBeg; z < zEnd; ++z) {\n q = ((nx * ny) * z) + (nx * y) + x\n if (field[ q ] >= isolevel) {\n __xBeg = x\n __break = true\n break\n }\n }\n if (__break) break\n }\n if (__break) break\n }\n\n __break = false\n for (z = zEnd; z >= zBeg; --z) {\n for (y = yEnd; y >= yBeg; --y) {\n for (x = xEnd; x >= xBeg; --x) {\n q = ((nx * ny) * z) + (nx * y) + x\n if (field[ q ] >= isolevel) {\n __zEnd = z\n __break = true\n break\n }\n }\n if (__break) break\n }\n if (__break) break\n }\n\n __break = false\n for (y = yEnd; y >= yBeg; --y) {\n for (z = __zEnd; z >= zBeg; --z) {\n for (x = xEnd; x >= xBeg; --x) {\n q = ((nx * ny) * z) + (nx * y) + x\n if (field[ q ] >= isolevel) {\n __yEnd = y\n __break = true\n break\n }\n }\n if (__break) break\n }\n if (__break) break\n }\n\n __break = false\n for (x = xEnd; x >= xBeg; --x) {\n for (y = __yEnd; y >= yBeg; --y) {\n for (z = __zEnd; z >= zBeg; --z) {\n q = ((nx * ny) * z) + (nx * y) + x\n if (field[ q ] >= isolevel) {\n __xEnd = x\n __break = true\n break\n }\n }\n if (__break) break\n }\n if (__break) break\n }\n\n //\n\n if (noNormals) {\n xBeg = Math.max(0, __xBeg - 1)\n yBeg = Math.max(0, __yBeg - 1)\n zBeg = Math.max(0, __zBeg - 1)\n\n xEnd = Math.min(nx - 1, __xEnd + 1)\n yEnd = Math.min(ny - 1, __yEnd + 1)\n zEnd = Math.min(nz - 1, __zEnd + 1)\n } else {\n xBeg = Math.max(1, __xBeg - 1)\n yBeg = Math.max(1, __yBeg - 1)\n zBeg = Math.max(1, __zBeg - 1)\n\n xEnd = Math.min(nx - 2, __xEnd + 1)\n yEnd = Math.min(ny - 2, __yEnd + 1)\n zEnd = Math.min(nz - 2, __zEnd + 1)\n }\n }\n\n // polygonize part of the grid\n var edgeFilter = 15\n for (z = zBeg; z < zEnd; ++z, edgeFilter &= ~4) {\n zOffset = zd * z\n edgeFilter |= 2\n for (y = yBeg; y < yEnd; ++y, edgeFilter &= ~2) {\n yOffset = zOffset + yd * y\n edgeFilter |= 1\n for (x = xBeg; x < xEnd; ++x, edgeFilter &= ~1) {\n q = yOffset + x\n polygonize(x, y, z, q, edgeFilter)\n }\n }\n }\n }\n}\nObject.assign(MarchingCubes, {__deps: [ getEdgeTable, getTriTable, getUintArray ]})\n\nexport default MarchingCubes\n","/**\n * @file Matrix Utils\n * @private\n * @author Alexander Rose \n *\n * svd methods from Eugene Zatepyakin / http://inspirit.github.io/jsfeat/\n */\n\nimport { NumberArray } from '../types'\nimport { v3new, v3cross } from './vector-utils'\n\nexport class Matrix {\n size: number\n data: Float32Array\n\n constructor (readonly cols: number, readonly rows: number) {\n this.size = this.cols * this.rows\n this.data = new Float32Array(this.size)\n }\n\n copyTo (matrix: Matrix) {\n matrix.data.set(this.data)\n }\n}\n\nexport function transpose (At: Matrix, A: Matrix) {\n let i = 0\n let j = 0\n const nrows = A.rows\n const ncols = A.cols\n let Ai = 0\n let Ati = 0\n let pAt = 0\n const ad = A.data\n const atd = At.data\n\n for (; i < nrows; Ati += 1, Ai += ncols, i++) {\n pAt = Ati\n for (j = 0; j < ncols; pAt += nrows, j++) atd[pAt] = ad[Ai + j]\n }\n}\n\n// C = A * B\nexport function multiply (C: Matrix, A: Matrix, B: Matrix) {\n let i = 0\n let j = 0\n let k = 0\n let Ap = 0\n let pA = 0\n let pB = 0\n let _pB = 0\n let Cp = 0\n const ncols = A.cols\n const nrows = A.rows\n const mcols = B.cols\n const ad = A.data\n const bd = B.data\n const cd = C.data\n let sum = 0.0\n\n for (; i < nrows; Ap += ncols, i++) {\n for (_pB = 0, j = 0; j < mcols; Cp++, _pB++, j++) {\n pB = _pB\n pA = Ap\n sum = 0.0\n for (k = 0; k < ncols; pA++, pB += mcols, k++) {\n sum += ad[pA] * bd[pB]\n }\n cd[Cp] = sum\n }\n }\n}\n\n// C = A * B'\nexport function multiplyABt (C: Matrix, A: Matrix, B: Matrix) {\n let i = 0\n let j = 0\n let k = 0\n let Ap = 0\n let pA = 0\n let pB = 0\n let Cp = 0\n const ncols = A.cols\n const nrows = A.rows\n const mrows = B.rows\n const ad = A.data\n const bd = B.data\n const cd = C.data\n let sum = 0.0\n\n for (; i < nrows; Ap += ncols, i++) {\n for (pB = 0, j = 0; j < mrows; Cp++, j++) {\n pA = Ap\n sum = 0.0\n for (k = 0; k < ncols; pA++, pB++, k++) {\n sum += ad[pA] * bd[pB]\n }\n cd[Cp] = sum\n }\n }\n}\n\n// C = A' * B\nexport function multiplyAtB (C: Matrix, A: Matrix, B: Matrix) {\n let i = 0\n let j = 0\n let k = 0\n let Ap = 0\n let pA = 0\n let pB = 0\n let _pB = 0\n let Cp = 0\n const ncols = A.cols\n const nrows = A.rows\n const mcols = B.cols\n const ad = A.data\n const bd = B.data\n const cd = C.data\n let sum = 0.0\n\n for (; i < ncols; Ap++, i++) {\n for (_pB = 0, j = 0; j < mcols; Cp++, _pB++, j++) {\n pB = _pB\n pA = Ap\n sum = 0.0\n for (k = 0; k < nrows; pA += ncols, pB += mcols, k++) {\n sum += ad[pA] * bd[pB]\n }\n cd[Cp] = sum\n }\n }\n}\n\nexport function invert3x3 (from: Matrix, to: Matrix) {\n const A = from.data\n const invA = to.data\n const t1 = A[4]\n const t2 = A[8]\n const t4 = A[5]\n const t5 = A[7]\n const t8 = A[0]\n\n const t9 = t8 * t1\n const t11 = t8 * t4\n const t13 = A[3]\n const t14 = A[1]\n const t15 = t13 * t14\n const t17 = A[2]\n const t18 = t13 * t17\n const t20 = A[6]\n const t21 = t20 * t14\n const t23 = t20 * t17\n const t26 = 1.0 / (t9 * t2 - t11 * t5 - t15 * t2 + t18 * t5 + t21 * t4 - t23 * t1)\n invA[0] = (t1 * t2 - t4 * t5) * t26\n invA[1] = -(t14 * t2 - t17 * t5) * t26\n invA[2] = -(-t14 * t4 + t17 * t1) * t26\n invA[3] = -(t13 * t2 - t4 * t20) * t26\n invA[4] = (t8 * t2 - t23) * t26\n invA[5] = -(t11 - t18) * t26\n invA[6] = -(-t13 * t5 + t1 * t20) * t26\n invA[7] = -(t8 * t5 - t21) * t26\n invA[8] = (t9 - t15) * t26\n}\n\nexport function mat3x3determinant (M: Matrix) {\n const md = M.data\n return md[0] * md[4] * md[8] -\n md[0] * md[5] * md[7] -\n md[3] * md[1] * md[8] +\n md[3] * md[2] * md[7] +\n md[6] * md[1] * md[5] -\n md[6] * md[2] * md[4]\n}\n\n// C = A * B\nexport function multiply3x3 (C: Matrix, A: Matrix, B: Matrix) {\n const Cd = C.data\n const Ad = A.data\n const Bd = B.data\n const m10 = Ad[0]\n const m11 = Ad[1]\n const m12 = Ad[2]\n const m13 = Ad[3]\n const m14 = Ad[4]\n const m15 = Ad[5]\n const m16 = Ad[6]\n const m17 = Ad[7]\n const m18 = Ad[8]\n\n const m20 = Bd[0]\n const m21 = Bd[1]\n const m22 = Bd[2]\n const m23 = Bd[3]\n const m24 = Bd[4]\n const m25 = Bd[5]\n const m26 = Bd[6]\n const m27 = Bd[7]\n const m28 = Bd[8]\n\n Cd[0] = m10 * m20 + m11 * m23 + m12 * m26\n Cd[1] = m10 * m21 + m11 * m24 + m12 * m27\n Cd[2] = m10 * m22 + m11 * m25 + m12 * m28\n Cd[3] = m13 * m20 + m14 * m23 + m15 * m26\n Cd[4] = m13 * m21 + m14 * m24 + m15 * m27\n Cd[5] = m13 * m22 + m14 * m25 + m15 * m28\n Cd[6] = m16 * m20 + m17 * m23 + m18 * m26\n Cd[7] = m16 * m21 + m17 * m24 + m18 * m27\n Cd[8] = m16 * m22 + m17 * m25 + m18 * m28\n}\n\nexport function meanRows (A: Matrix) {\n const nrows = A.rows\n const ncols = A.cols\n const Ad = A.data\n const mean = new Array(ncols)\n\n for (let j = 0; j < ncols; ++j) {\n mean[ j ] = 0.0\n }\n\n for (let i = 0, p = 0; i < nrows; ++i) {\n for (let j = 0; j < ncols; ++j, ++p) {\n mean[ j ] += Ad[ p ]\n }\n }\n\n for (let j = 0; j < ncols; ++j) {\n mean[ j ] /= nrows\n }\n\n return mean\n}\n\nexport function meanCols (A: Matrix) {\n const nrows = A.rows\n const ncols = A.cols\n const Ad = A.data\n const mean = new Array(nrows)\n\n for (let j = 0; j < nrows; ++j) {\n mean[ j ] = 0.0\n }\n\n for (let i = 0, p = 0; i < ncols; ++i) {\n for (let j = 0; j < nrows; ++j, ++p) {\n mean[ j ] += Ad[ p ]\n }\n }\n\n for (let j = 0; j < nrows; ++j) {\n mean[ j ] /= ncols\n }\n\n return mean\n}\n\nexport function subRows (A: Matrix, row: number[]) {\n const nrows = A.rows\n const ncols = A.cols\n const Ad = A.data\n\n for (let i = 0, p = 0; i < nrows; ++i) {\n for (let j = 0; j < ncols; ++j, ++p) {\n Ad[ p ] -= row[ j ]\n }\n }\n}\n\nexport function subCols (A: Matrix, col: number[]) {\n const nrows = A.rows\n const ncols = A.cols\n const Ad = A.data\n\n for (let i = 0, p = 0; i < ncols; ++i) {\n for (let j = 0; j < nrows; ++j, ++p) {\n Ad[ p ] -= col[ j ]\n }\n }\n}\n\nexport function addRows (A: Matrix, row: number[]) {\n const nrows = A.rows\n const ncols = A.cols\n const Ad = A.data\n\n for (let i = 0, p = 0; i < nrows; ++i) {\n for (let j = 0; j < ncols; ++j, ++p) {\n Ad[ p ] += row[ j ]\n }\n }\n}\n\nexport function addCols (A: Matrix, col: number[]) {\n const nrows = A.rows\n const ncols = A.cols\n const Ad = A.data\n\n for (let i = 0, p = 0; i < ncols; ++i) {\n for (let j = 0; j < nrows; ++j, ++p) {\n Ad[ p ] += col[ j ]\n }\n }\n}\n\nexport function swap (A: NumberArray, i0: number, i1: number, t: number) {\n t = A[i0]\n A[i0] = A[i1]\n A[i1] = t\n}\n\nexport function hypot (a: number, b: number) {\n a = Math.abs(a)\n b = Math.abs(b)\n if (a > b) {\n b /= a\n return a * Math.sqrt(1.0 + b * b)\n }\n if (b > 0) {\n a /= b\n return b * Math.sqrt(1.0 + a * a)\n }\n return 0.0\n}\n\nconst EPSILON = 0.0000001192092896\nconst FLT_MIN = 1E-37\n\nexport function JacobiSVDImpl (At: NumberArray, astep: number, _W: NumberArray, Vt: NumberArray, vstep: number, m: number, n: number, n1: number) {\n const eps = EPSILON * 2.0\n const minval = FLT_MIN\n let i = 0\n let j = 0\n let k = 0\n let iter = 0\n const maxIter = Math.max(m, 30)\n let Ai = 0\n let Aj = 0\n let Vi = 0\n let Vj = 0\n let changed = 0\n let c = 0.0\n let s = 0.0\n let t = 0.0\n let t0 = 0.0\n let t1 = 0.0\n let sd = 0.0\n let beta = 0.0\n let gamma = 0.0\n let delta = 0.0\n let a = 0.0\n let p = 0.0\n let b = 0.0\n let seed = 0x1234\n let val = 0.0\n let val0 = 0.0\n let asum = 0.0\n\n const W = new Float64Array(n << 3)\n\n for (; i < n; i++) {\n for (k = 0, sd = 0; k < m; k++) {\n t = At[i * astep + k]\n sd += t * t\n }\n W[i] = sd\n\n if (Vt) {\n for (k = 0; k < n; k++) {\n Vt[i * vstep + k] = 0\n }\n Vt[i * vstep + i] = 1\n }\n }\n\n for (; iter < maxIter; iter++) {\n changed = 0\n\n for (i = 0; i < n - 1; i++) {\n for (j = i + 1; j < n; j++) {\n Ai = (i * astep) | 0\n Aj = (j * astep) | 0\n a = W[i]\n p = 0\n b = W[j]\n\n k = 2\n p += At[Ai] * At[Aj]\n p += At[Ai + 1] * At[Aj + 1]\n\n for (; k < m; k++) { p += At[Ai + k] * At[Aj + k] }\n\n if (Math.abs(p) <= eps * Math.sqrt(a * b)) continue\n\n p *= 2.0\n beta = a - b\n gamma = hypot(p, beta)\n if (beta < 0) {\n delta = (gamma - beta) * 0.5\n s = Math.sqrt(delta / gamma)\n c = (p / (gamma * s * 2.0))\n } else {\n c = Math.sqrt((gamma + beta) / (gamma * 2.0))\n s = (p / (gamma * c * 2.0))\n }\n\n a = 0.0\n b = 0.0\n\n k = 2 // unroll\n t0 = c * At[Ai] + s * At[Aj]\n t1 = -s * At[Ai] + c * At[Aj]\n At[Ai] = t0; At[Aj] = t1\n a += t0 * t0; b += t1 * t1\n\n t0 = c * At[Ai + 1] + s * At[Aj + 1]\n t1 = -s * At[Ai + 1] + c * At[Aj + 1]\n At[Ai + 1] = t0; At[Aj + 1] = t1\n a += t0 * t0; b += t1 * t1\n\n for (; k < m; k++) {\n t0 = c * At[Ai + k] + s * At[Aj + k]\n t1 = -s * At[Ai + k] + c * At[Aj + k]\n At[Ai + k] = t0; At[Aj + k] = t1\n\n a += t0 * t0; b += t1 * t1\n }\n\n W[i] = a\n W[j] = b\n\n changed = 1\n\n if (Vt) {\n Vi = (i * vstep) | 0\n Vj = (j * vstep) | 0\n\n k = 2\n t0 = c * Vt[Vi] + s * Vt[Vj]\n t1 = -s * Vt[Vi] + c * Vt[Vj]\n Vt[Vi] = t0; Vt[Vj] = t1\n\n t0 = c * Vt[Vi + 1] + s * Vt[Vj + 1]\n t1 = -s * Vt[Vi + 1] + c * Vt[Vj + 1]\n Vt[Vi + 1] = t0; Vt[Vj + 1] = t1\n\n for (; k < n; k++) {\n t0 = c * Vt[Vi + k] + s * Vt[Vj + k]\n t1 = -s * Vt[Vi + k] + c * Vt[Vj + k]\n Vt[Vi + k] = t0; Vt[Vj + k] = t1\n }\n }\n }\n }\n if (changed === 0) break\n }\n\n for (i = 0; i < n; i++) {\n for (k = 0, sd = 0; k < m; k++) {\n t = At[i * astep + k]\n sd += t * t\n }\n W[i] = Math.sqrt(sd)\n }\n\n for (i = 0; i < n - 1; i++) {\n j = i\n for (k = i + 1; k < n; k++) {\n if (W[j] < W[k]) { j = k }\n }\n if (i !== j) {\n swap(W, i, j, sd)\n if (Vt) {\n for (k = 0; k < m; k++) {\n swap(At, i * astep + k, j * astep + k, t)\n }\n\n for (k = 0; k < n; k++) {\n swap(Vt, i * vstep + k, j * vstep + k, t)\n }\n }\n }\n }\n\n for (i = 0; i < n; i++) {\n _W[i] = W[i]\n }\n\n if (!Vt) {\n return\n }\n\n for (i = 0; i < n1; i++) {\n sd = i < n ? W[i] : 0\n\n while (sd <= minval) {\n // if we got a zero singular value, then in order to get the corresponding left singular vector\n // we generate a random vector, project it to the previously computed left singular vectors,\n // subtract the projection and normalize the difference.\n val0 = (1.0 / m)\n for (k = 0; k < m; k++) {\n seed = (seed * 214013 + 2531011)\n val = (((seed >> 16) & 0x7fff) & 256) !== 0 ? val0 : -val0\n At[i * astep + k] = val\n }\n for (iter = 0; iter < 2; iter++) {\n for (j = 0; j < i; j++) {\n sd = 0\n for (k = 0; k < m; k++) {\n sd += At[i * astep + k] * At[j * astep + k]\n }\n asum = 0.0\n for (k = 0; k < m; k++) {\n t = (At[i * astep + k] - sd * At[j * astep + k])\n At[i * astep + k] = t\n asum += Math.abs(t)\n }\n asum = asum ? 1.0 / asum : 0\n for (k = 0; k < m; k++) {\n At[i * astep + k] *= asum\n }\n }\n }\n sd = 0\n for (k = 0; k < m; k++) {\n t = At[i * astep + k]\n sd += t * t\n }\n sd = Math.sqrt(sd)\n }\n\n s = (1.0 / sd)\n for (k = 0; k < m; k++) {\n At[i * astep + k] *= s\n }\n }\n}\n\nexport function svd (A: Matrix, W: Matrix, U: Matrix, V: Matrix) {\n let at = 0\n let i = 0\n const _m = A.rows\n const _n = A.cols\n let m = _m\n let n = _n\n\n if (m < n) {\n at = 1\n i = m\n m = n\n n = i\n }\n\n const amt = new Matrix(m, m)\n const wmt = new Matrix(1, n)\n const vmt = new Matrix(n, n)\n\n if (at === 0) {\n transpose(amt, A)\n } else {\n for (i = 0; i < _n * _m; i++) {\n amt.data[i] = A.data[i]\n }\n for (; i < n * m; i++) {\n amt.data[i] = 0\n }\n }\n\n JacobiSVDImpl(amt.data, m, wmt.data, vmt.data, n, m, n, m)\n\n if (W) {\n for (i = 0; i < n; i++) {\n W.data[i] = wmt.data[i]\n }\n for (; i < _n; i++) {\n W.data[i] = 0\n }\n }\n\n if (at === 0) {\n if (U) transpose(U, amt)\n if (V) transpose(V, vmt)\n } else {\n if (U) transpose(U, vmt)\n if (V) transpose(V, amt)\n }\n}\n\n//\n\nexport function m4new () {\n return new Float32Array([\n 1, 0, 0, 0,\n 0, 1, 0, 0,\n 0, 0, 1, 0,\n 0, 0, 0, 1\n ])\n}\n\nexport function m4set (out: Float32Array, n11: number, n12: number, n13: number, n14: number, n21: number, n22: number, n23: number, n24: number, n31: number, n32: number, n33: number, n34: number, n41: number, n42: number, n43: number, n44: number) {\n out[ 0 ] = n11; out[ 4 ] = n12; out[ 8 ] = n13; out[ 12 ] = n14\n out[ 1 ] = n21; out[ 5 ] = n22; out[ 9 ] = n23; out[ 13 ] = n24\n out[ 2 ] = n31; out[ 6 ] = n32; out[ 10 ] = n33; out[ 14 ] = n34\n out[ 3 ] = n41; out[ 7 ] = n42; out[ 11 ] = n43; out[ 15 ] = n44\n}\n\nexport function m4identity (out: Float32Array) {\n m4set(out,\n 1, 0, 0, 0,\n 0, 1, 0, 0,\n 0, 0, 1, 0,\n 0, 0, 0, 1\n )\n}\n(m4identity as any).__deps = [ m4set ]\n\nexport function m4multiply (out: Float32Array, a: Float32Array, b: Float32Array) {\n const a11 = a[ 0 ]\n const a12 = a[ 4 ]\n const a13 = a[ 8 ]\n const a14 = a[ 12 ]\n const a21 = a[ 1 ]\n const a22 = a[ 5 ]\n const a23 = a[ 9 ]\n const a24 = a[ 13 ]\n const a31 = a[ 2 ]\n const a32 = a[ 6 ]\n const a33 = a[ 10 ]\n const a34 = a[ 14 ]\n const a41 = a[ 3 ]\n const a42 = a[ 7 ]\n const a43 = a[ 11 ]\n const a44 = a[ 15 ]\n\n const b11 = b[ 0 ]\n const b12 = b[ 4 ]\n const b13 = b[ 8 ]\n const b14 = b[ 12 ]\n const b21 = b[ 1 ]\n const b22 = b[ 5 ]\n const b23 = b[ 9 ]\n const b24 = b[ 13 ]\n const b31 = b[ 2 ]\n const b32 = b[ 6 ]\n const b33 = b[ 10 ]\n const b34 = b[ 14 ]\n const b41 = b[ 3 ]\n const b42 = b[ 7 ]\n const b43 = b[ 11 ]\n const b44 = b[ 15 ]\n\n out[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41\n out[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42\n out[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43\n out[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44\n\n out[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41\n out[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42\n out[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43\n out[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44\n\n out[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41\n out[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42\n out[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43\n out[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44\n\n out[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41\n out[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42\n out[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43\n out[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44\n}\n\nexport function m4makeScale (out: Float32Array, x: number, y: number, z: number) {\n m4set(out,\n x, 0, 0, 0,\n 0, y, 0, 0,\n 0, 0, z, 0,\n 0, 0, 0, 1\n )\n}\n(m4makeScale as any).__deps = [ m4set ]\n\nexport function m4makeTranslation (out: Float32Array, x: number, y: number, z: number) {\n m4set(out,\n 1, 0, 0, x,\n 0, 1, 0, y,\n 0, 0, 1, z,\n 0, 0, 0, 1\n )\n}\n(m4makeTranslation as any).__deps = [ m4set ]\n\nexport function m4makeRotationY (out: Float32Array, theta: number) {\n const c = Math.cos(theta)\n const s = Math.sin(theta)\n m4set(out,\n c, 0, s, 0,\n 0, 1, 0, 0,\n -s, 0, c, 0,\n 0, 0, 0, 1\n )\n}\n(m4makeRotationY as any).__deps = [ m4set ]\n\n//\n\nexport function m3new () {\n return new Float32Array([\n 1, 0, 0,\n 0, 1, 0,\n 0, 0, 1\n ])\n}\n\nexport function m3makeNormal (out: Float32Array, m4: Float32Array) {\n const r0 = v3new([ m4[0], m4[1], m4[2] ])\n const r1 = v3new([ m4[4], m4[5], m4[6] ])\n const r2 = v3new([ m4[8], m4[9], m4[10] ])\n const cp = v3new()\n // [ r0 ] [ r1 x r2 ]\n // M3x3 = [ r1 ] N = [ r2 x r0 ]\n // [ r2 ] [ r0 x r1 ]\n v3cross(cp, r1, r2)\n out[ 0 ] = cp[ 0 ]\n out[ 1 ] = cp[ 1 ]\n out[ 2 ] = cp[ 2 ]\n v3cross(cp, r2, r0)\n out[ 3 ] = cp[ 0 ]\n out[ 4 ] = cp[ 1 ]\n out[ 5 ] = cp[ 2 ]\n v3cross(cp, r0, r1)\n out[ 6 ] = cp[ 0 ]\n out[ 7 ] = cp[ 1 ]\n out[ 8 ] = cp[ 2 ]\n}\n(m3makeNormal as any).__deps = [ v3new, v3cross ]\n","/**\n * @file Surface Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { degToRad } from '../math/math-utils'\nimport {\n m4new, m4multiply, m4makeTranslation, m4makeScale, m4makeRotationY\n} from '../math/matrix-utils'\nimport {\n v3addScalar, v3subScalar, v3divideScalar, v3multiplyScalar,\n v3floor, v3ceil, v3sub, v3negate,\n v3cross, v3fromArray, normalizeVector3array\n} from '../math/vector-utils'\nimport { NumberArray } from '../types'\n\nfunction laplacianSmooth (verts: Float32Array, faces: Float32Array, numiter: number, inflate: boolean) {\n // based on D. Xu, Y. Zhang (2009) Generating Triangulated Macromolecular\n // Surfaces by Euclidean Distance Transform. PLoS ONE 4(12): e8140.\n //\n // Permission to use, copy, modify, and distribute this program for\n // any purpose, with or without fee, is hereby granted, provided that\n // the notices on the head, the reference information, and this\n // copyright notice appear in all copies or substantial portions of\n // the Software. It is provided \"as is\" without express or implied\n // warranty.\n //\n // ported to JavaScript and adapted to NGL by Alexander Rose\n\n numiter = numiter || 1\n inflate = inflate || true\n\n const nv = verts.length / 3\n const nf = faces.length / 3\n let norms: Float32Array | undefined = undefined\n\n if (inflate) {\n norms = new Float32Array(nv * 3)\n }\n\n const tps = new Float32Array(nv * 3)\n\n let i\n const ndeg = 20\n const vertdeg = new Array(ndeg)\n\n for (i = 0; i < ndeg; ++i) {\n vertdeg[ i ] = new Uint32Array(nv)\n }\n\n for (i = 0; i < nv; ++i) {\n vertdeg[ 0 ][ i ] = 0\n }\n\n let j, jl\n let flagvert: boolean\n\n // for each face\n\n for (i = 0; i < nf; ++i) {\n var ao = i * 3\n var bo = i * 3 + 1\n var co = i * 3 + 2\n\n // vertex a\n\n flagvert = true\n for (j = 0, jl = vertdeg[ 0 ][ faces[ao] ]; j < jl; ++j) {\n if (faces[ bo ] === vertdeg[ j + 1 ][ faces[ ao ] ]) {\n flagvert = false\n break\n }\n }\n if (flagvert) {\n vertdeg[ 0 ][ faces[ ao ] ]++\n vertdeg[ vertdeg[ 0 ][ faces[ ao ] ] ][ faces[ ao ] ] = faces[ bo ]\n }\n\n flagvert = true\n for (j = 0, jl = vertdeg[ 0 ][ faces[ ao ] ]; j < jl; ++j) {\n if (faces[ co ] === vertdeg[ j + 1 ][ faces[ ao ] ]) {\n flagvert = false\n break\n }\n }\n if (flagvert) {\n vertdeg[ 0 ][ faces[ ao ] ]++\n vertdeg[ vertdeg[ 0 ][ faces[ ao ] ] ][ faces[ ao ] ] = faces[ co ]\n }\n\n // vertex b\n\n flagvert = true\n for (j = 0, jl = vertdeg[ 0 ][ faces[ bo ] ]; j < jl; ++j) {\n if (faces[ ao ] === vertdeg[ j + 1 ][ faces[ bo ] ]) {\n flagvert = false\n break\n }\n }\n if (flagvert) {\n vertdeg[ 0 ][ faces[ bo ] ]++\n vertdeg[ vertdeg[ 0 ][ faces[ bo ] ] ][ faces[ bo ] ] = faces[ ao ]\n }\n\n flagvert = true\n for (j = 0, jl = vertdeg[ 0 ][ faces[ bo ] ]; j < jl; ++j) {\n if (faces[ co ] === vertdeg[ j + 1 ][ faces[ bo ] ]) {\n flagvert = false\n break\n }\n }\n if (flagvert) {\n vertdeg[ 0 ][ faces[ bo ] ]++\n vertdeg[ vertdeg[ 0 ][ faces[ bo ] ] ][ faces[ bo ] ] = faces[ co ]\n }\n\n // vertex c\n\n flagvert = true\n for (j = 0; j < vertdeg[ 0 ][ faces[ co ] ]; ++j) {\n if (faces[ ao ] === vertdeg[ j + 1 ][ faces[ co ] ]) {\n flagvert = false\n break\n }\n }\n if (flagvert) {\n vertdeg[ 0 ][ faces[ co ] ]++\n vertdeg[ vertdeg[ 0 ][ faces[ co ] ] ][ faces[ co ] ] = faces[ ao ]\n }\n\n flagvert = true\n for (j = 0, jl = vertdeg[ 0 ][ faces[ co ] ]; j < jl; ++j) {\n if (faces[ bo ] === vertdeg[ j + 1 ][ faces[ co ] ]) {\n flagvert = false\n break\n }\n }\n if (flagvert) {\n vertdeg[ 0 ][ faces[ co ] ]++\n vertdeg[ vertdeg[ 0 ][ faces[ co ] ] ][ faces[ co ] ] = faces[ bo ]\n }\n }\n\n var wt = 1.0\n var wt2 = 0.5\n var i3, vi3, vdi, wtvi, wt2vi\n var ssign = -1\n var scaleFactor = 1\n var outwt = 0.75 / (scaleFactor + 3.5) // area-preserving\n\n // smoothing iterations\n\n for (var k = 0; k < numiter; ++k) {\n // for each vertex\n\n for (i = 0; i < nv; ++i) {\n i3 = i * 3\n vdi = vertdeg[ 0 ][ i ]\n\n if (vdi < 3) {\n tps[ i3 ] = verts[ i3 ]\n tps[ i3 + 1 ] = verts[ i3 + 1 ]\n tps[ i3 + 2 ] = verts[ i3 + 2 ]\n } else if (vdi === 3 || vdi === 4) {\n tps[ i3 ] = 0\n tps[ i3 + 1 ] = 0\n tps[ i3 + 2 ] = 0\n\n for (j = 0; j < vdi; ++j) {\n vi3 = vertdeg[ j + 1 ][ i ] * 3\n tps[ i3 ] += verts[ vi3 ]\n tps[ i3 + 1 ] += verts[ vi3 + 1 ]\n tps[ i3 + 2 ] += verts[ vi3 + 2 ]\n }\n\n tps[ i3 ] += wt2 * verts[ i3 ]\n tps[ i3 + 1 ] += wt2 * verts[ i3 + 1 ]\n tps[ i3 + 2 ] += wt2 * verts[ i3 + 2 ]\n\n wt2vi = wt2 + vdi\n tps[ i3 ] /= wt2vi\n tps[ i3 + 1 ] /= wt2vi\n tps[ i3 + 2 ] /= wt2vi\n } else {\n tps[ i3 ] = 0\n tps[ i3 + 1 ] = 0\n tps[ i3 + 2 ] = 0\n\n for (j = 0; j < vdi; ++j) {\n vi3 = vertdeg[ j + 1 ][ i ] * 3\n tps[ i3 ] += verts[ vi3 ]\n tps[ i3 + 1 ] += verts[ vi3 + 1 ]\n tps[ i3 + 2 ] += verts[ vi3 + 2 ]\n }\n\n tps[ i3 ] += wt * verts[ i3 ]\n tps[ i3 + 1 ] += wt * verts[ i3 + 1 ]\n tps[ i3 + 2 ] += wt * verts[ i3 + 2 ]\n\n wtvi = wt + vdi\n tps[ i3 ] /= wtvi\n tps[ i3 + 1 ] /= wtvi\n tps[ i3 + 2 ] /= wtvi\n }\n }\n\n verts.set(tps) // copy smoothed positions\n\n if (inflate) {\n computeVertexNormals(verts, faces, norms)\n var nv3 = nv * 3\n\n for (i3 = 0; i3 < nv3; i3 += 3) {\n // if(verts[i].inout) ssign=1;\n // else ssign=-1;\n\n verts[ i3 ] += ssign * outwt * norms![ i3 ]\n verts[ i3 + 1 ] += ssign * outwt * norms![ i3 + 1 ]\n verts[ i3 + 2 ] += ssign * outwt * norms![ i3 + 2 ]\n }\n }\n }\n}\nObject.assign(laplacianSmooth, {__deps: [ computeVertexNormals ]})\n\nfunction computeVertexNormals (position: Float32Array, index?: NumberArray, normal?: Float32Array) {\n var i, il\n\n if (normal === undefined) {\n normal = new Float32Array(position.length)\n } else {\n // reset existing normals to zero\n for (i = 0, il = normal.length; i < il; i++) {\n normal[ i ] = 0\n }\n }\n\n var a = new Float32Array(3)\n var b = new Float32Array(3)\n var c = new Float32Array(3)\n var cb = new Float32Array(3)\n var ab = new Float32Array(3)\n\n if (index) {\n // indexed elements\n for (i = 0, il = index.length; i < il; i += 3) {\n var ai = index[ i ] * 3\n var bi = index[ i + 1 ] * 3\n var ci = index[ i + 2 ] * 3\n\n v3fromArray(a, position, ai)\n v3fromArray(b, position, bi)\n v3fromArray(c, position, ci)\n\n v3sub(cb, c, b)\n v3sub(ab, a, b)\n v3cross(cb, cb, ab)\n\n normal[ ai ] += cb[ 0 ]\n normal[ ai + 1 ] += cb[ 1 ]\n normal[ ai + 2 ] += cb[ 2 ]\n\n normal[ bi ] += cb[ 0 ]\n normal[ bi + 1 ] += cb[ 1 ]\n normal[ bi + 2 ] += cb[ 2 ]\n\n normal[ ci ] += cb[ 0 ]\n normal[ ci + 1 ] += cb[ 1 ]\n normal[ ci + 2 ] += cb[ 2 ]\n }\n } else {\n // non-indexed elements (unconnected triangle soup)\n for (i = 0, il = position.length; i < il; i += 9) {\n v3fromArray(a, position, i)\n v3fromArray(b, position, i + 3)\n v3fromArray(c, position, i + 6)\n\n v3sub(cb, c, b)\n v3sub(ab, a, b)\n v3cross(cb, cb, ab)\n\n normal[ i ] = cb[ 0 ]\n normal[ i + 1 ] = cb[ 1 ]\n normal[ i + 2 ] = cb[ 2 ]\n\n normal[ i + 3 ] = cb[ 0 ]\n normal[ i + 4 ] = cb[ 1 ]\n normal[ i + 5 ] = cb[ 2 ]\n\n normal[ i + 6 ] = cb[ 0 ]\n normal[ i + 7 ] = cb[ 1 ]\n normal[ i + 8 ] = cb[ 2 ]\n }\n }\n\n normalizeVector3array(normal)\n\n return normal\n}\nObject.assign(computeVertexNormals, {__deps: [\n v3sub, v3cross, v3fromArray, normalizeVector3array\n]})\n\nfunction getRadiusDict (radiusList: number[]) {\n var radiusDict: {[k: number]: boolean} = {}\n for (var i = 0, il = radiusList.length; i < il; ++i) {\n radiusDict[ radiusList[ i ] ] = true\n }\n return radiusDict\n}\n\nfunction getSurfaceGrid (min: Float32Array, max: Float32Array, maxRadius: number, scaleFactor: number, extraMargin: number) {\n // need margin to avoid boundary/round off effects\n var margin = (1 / scaleFactor) * 3\n margin += maxRadius\n\n v3subScalar(min, min, extraMargin + margin)\n v3addScalar(max, max, extraMargin + margin)\n\n v3multiplyScalar(min, min, scaleFactor)\n v3floor(min, min)\n v3divideScalar(min, min, scaleFactor)\n\n v3multiplyScalar(max, max, scaleFactor)\n v3ceil(max, max)\n v3divideScalar(max, max, scaleFactor)\n\n var dim = new Float32Array(3)\n v3sub(dim, max, min)\n v3multiplyScalar(dim, dim, scaleFactor)\n v3ceil(dim, dim)\n v3addScalar(dim, dim, 1)\n\n var maxSize = Math.pow(10, 6) * 256\n var tmpSize = dim[ 0 ] * dim[ 1 ] * dim[ 2 ] * 3\n\n if (maxSize <= tmpSize) {\n scaleFactor *= Math.pow(maxSize / tmpSize, 1 / 3)\n\n v3multiplyScalar(min, min, scaleFactor)\n v3floor(min, min)\n v3divideScalar(min, min, scaleFactor)\n\n v3multiplyScalar(max, max, scaleFactor)\n v3ceil(max, max)\n v3divideScalar(max, max, scaleFactor)\n\n v3sub(dim, max, min)\n v3multiplyScalar(dim, dim, scaleFactor)\n v3ceil(dim, dim)\n v3addScalar(dim, dim, 1)\n }\n\n var tran = new Float32Array(min)\n v3negate(tran, tran)\n\n // coordinate transformation matrix\n var matrix = m4new()\n var mroty = m4new()\n m4makeRotationY(mroty, degToRad(90))\n m4multiply(matrix, matrix, mroty)\n\n var mscale = m4new()\n m4makeScale(\n mscale,\n -1 / scaleFactor,\n 1 / scaleFactor,\n 1 / scaleFactor\n )\n m4multiply(matrix, matrix, mscale)\n\n var mtrans = m4new()\n m4makeTranslation(\n mtrans,\n -scaleFactor * tran[2],\n -scaleFactor * tran[1],\n -scaleFactor * tran[0]\n )\n m4multiply(matrix, matrix, mtrans)\n\n return {\n dim: dim,\n tran: tran,\n matrix: matrix,\n scaleFactor: scaleFactor\n }\n}\nObject.assign(getSurfaceGrid, {__deps: [\n degToRad,\n v3subScalar, v3addScalar, v3divideScalar, v3multiplyScalar,\n v3floor, v3ceil, v3sub, v3negate,\n m4new, m4multiply, m4makeTranslation, m4makeScale, m4makeRotationY\n]})\n\nexport {\n laplacianSmooth,\n computeVertexNormals,\n getRadiusDict,\n getSurfaceGrid\n}\n","/**\n * @file Surface\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Box3, BufferGeometry, Group, Color } from 'three'\n\nimport { Debug, Log, ColormakerRegistry } from '../globals'\nimport { getUintArray } from '../utils'\nimport { AtomPicker, SurfacePicker } from '../utils/picker'\nimport { uniformArray, uniformArray3, serialArray } from '../math/array-utils'\nimport Selection from '../selection/selection'\nimport { ColormakerParameters } from '../color/colormaker';\nimport { Structure, Volume } from '../ngl';\n\nexport interface SurfaceData {\n position: Float32Array\n index: Uint32Array|Uint16Array|undefined\n normal: Float32Array\n color: Float32Array\n atomindex: Int32Array\n contour: boolean\n}\n/**\n * Surface\n */\nclass Surface {\n name: string\n path: string\n position: Float32Array\n index: Uint32Array|Uint16Array|undefined\n normal: Float32Array|undefined\n color: Float32Array|undefined\n atomindex: Int32Array|undefined\n contour: boolean\n center: Vector3\n boundingBox: Box3\n size: number\n info: {\n type?: string\n probeRadius?: number\n scaleFactor?: number\n smooth?: number\n cutoff?: number\n isolevel?: number\n volume?: Volume\n }\n\n /**\n * @param {String} name - surface name\n * @param {String} path - source path\n * @param {Object} data - surface data\n * @param {Float32Array} data.position - surface positions\n * @param {Int32Array} data.index - surface indices\n * @param {Float32Array} data.normal - surface normals\n * @param {Float32Array} data.color - surface colors\n * @param {Int32Array} data.atomindex - atom indices\n * @param {boolean} data.contour - contour mode flag\n */\n constructor (name: string, path: string, data?: SurfaceData) {\n this.name = name || ''\n this.path = path || ''\n this.info = {}\n\n this.center = new Vector3()\n this.boundingBox = new Box3()\n\n if (data instanceof BufferGeometry ||\n data instanceof Group\n ) {\n // to be removed\n this.fromGeometry(data)\n } else if (data) {\n this.set(\n data.position,\n data.index,\n data.normal,\n data.color,\n data.atomindex,\n data.contour\n )\n\n this.boundingBox.setFromArray(data.position)\n this.boundingBox.getCenter(this.center)\n }\n }\n\n get type () { return 'Surface' }\n\n /**\n * set surface data\n * @param {Float32Array} position - surface positions\n * @param {Int32Array} index - surface indices\n * @param {Float32Array} normal - surface normals\n * @param {Float32Array} color - surface colors\n * @param {Int32Array} atomindex - atom indices\n * @param {boolean} contour - contour mode flag\n * @return {undefined}\n */\n set (position: Float32Array,\n index: Uint32Array|Uint16Array|undefined,\n normal: Float32Array|undefined,\n color: Float32Array|undefined,\n atomindex: Int32Array|undefined,\n contour: boolean = false) {\n /**\n * @type {Float32Array}\n */\n this.position = position\n /**\n * @type {Uint32Array|Uint16Array|undefined}\n */\n this.index = index\n /**\n * @type {Float32Array|undefined}\n */\n this.normal = normal\n /**\n * @type {Float32Array|undefined}\n */\n this.color = color\n /**\n * @type {Int32Array|undefined}\n */\n this.atomindex = atomindex\n\n this.size = position.length / 3\n this.contour = contour\n }\n\n fromGeometry (geometry: BufferGeometry|Group) {\n if (Debug) Log.time('GeometrySurface.fromGeometry')\n\n let geo\n\n if (geometry instanceof BufferGeometry) {\n geo = geometry\n } else {\n geo = (geometry as any)[ 0 ]\n }\n\n if (!geo.boundingBox) geo.computeBoundingBox()\n\n this.boundingBox.copy(geo.boundingBox)\n this.boundingBox.getCenter(this.center)\n\n let position, color, index, normal\n\n if (geo instanceof BufferGeometry) {\n const attr = geo.attributes\n const an = (attr as any).normal ? (attr as any).normal.array : false\n\n // assume there are no normals if the first is zero\n if (!an || (an[ 0 ] === 0 && an[ 1 ] === 0 && an[ 2 ] === 0)) {\n geo.computeVertexNormals()\n }\n\n position = (attr).position.array\n index = (attr).index ? (attr).index.array : null\n normal = (attr).normal.array\n }\n\n this.set(position, index, normal, color, undefined)\n\n if (Debug) Log.timeEnd('GeometrySurface.setGeometry')\n }\n\n getPosition () {\n return this.position\n }\n\n getColor (params: ColormakerParameters&{ scheme: string}) {\n const p = params || {}\n p.surface = this\n\n const n = this.size\n const array = new Float32Array(n * 3)\n const colormaker = ColormakerRegistry.getScheme(p)\n\n if (colormaker.volumeColor || p.scheme === 'random') {\n for (let i = 0; i < n; ++i) {\n colormaker.volumeColorToArray(i, array, i * 3)\n }\n } else if (colormaker.positionColor) {\n const v = new Vector3()\n const pos = this.position\n\n for (let i = 0; i < n; ++i) {\n var i3 = i * 3\n v.set(pos[ i3 ], pos[ i3 + 1 ], pos[ i3 + 2 ])\n colormaker.positionColorToArray(v, array, i3)\n }\n } else if (colormaker.atomColor && this.atomindex) {\n const atomProxy = p.structure!.getAtomProxy()\n const atomindex = this.atomindex\n\n for (let i = 0; i < n; ++i) {\n atomProxy.index = atomindex[ i ]\n colormaker.atomColorToArray(atomProxy, array, i * 3)\n }\n } else {\n const tc = new Color(p.value)\n uniformArray3(n, tc.r, tc.g, tc.b, array)\n }\n\n return array\n }\n\n getPicking (structure?: Structure) {\n if (this.atomindex && structure) {\n return new AtomPicker(this.atomindex as any, structure)\n } else {\n return new SurfacePicker(serialArray(this.size), this)\n }\n }\n\n getNormal () {\n return this.normal\n }\n\n getSize (size: number, scale: number) {\n return uniformArray(this.size, size * scale)\n }\n\n getIndex () {\n return this.index\n }\n\n getFilteredIndex (sele: string, structure: Structure) {\n if (sele && this.atomindex) {\n const selection = new Selection(sele)\n const atomSet = structure.getAtomSet(selection)\n const filteredIndex = []\n\n const atomindex = this.atomindex\n const index = this.index\n const n = index!.length\n const elementSize = this.contour ? 2 : 3\n\n let j = 0\n\n for (let i = 0; i < n; i += elementSize) {\n let include = true\n\n for (let a = 0; a < elementSize; a++) {\n const idx = index![ i + a ]\n const ai = atomindex[ idx ]\n if (!atomSet.get(ai)) {\n include = false\n break\n }\n }\n\n if (!include) { continue }\n\n for (let a = 0; a < elementSize; a++, j++) {\n filteredIndex[ j ] = index![ i + a ]\n }\n }\n\n return getUintArray(filteredIndex, this.position.length / 3)\n } else {\n return this.index\n }\n }\n\n getAtomindex () {\n return this.atomindex\n }\n\n dispose () {\n\n //\n\n }\n}\n\nexport default Surface\n","/**\n * @file Volume\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Box3, Matrix3, Matrix4 } from 'three'\n\nimport { WorkerRegistry, ColormakerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport WorkerPool from '../worker/worker-pool'\nimport { VolumePicker } from '../utils/picker'\nimport {\n uniformArray, serialArray,\n arrayMin, arrayMax, arraySum, arrayMean, arrayRms\n} from '../math/array-utils'\nimport MarchingCubes from './marching-cubes'\nimport { laplacianSmooth, computeVertexNormals } from './surface-utils'\nimport {\n applyMatrix4toVector3array, applyMatrix3toVector3array\n} from '../math/vector-utils'\nimport { m3new, m3makeNormal } from '../math/matrix-utils'\nimport Surface from './surface'\nimport { NumberArray } from '../types';\nimport { ColormakerParameters } from '../color/colormaker';\n\nexport interface VolumeSurface {\n new (data: NumberArray, nx: number, ny: number, nz: number, atomindex: NumberArray): void\n getSurface: (isolevel: number, smooth: boolean|number, box: number[][]|undefined, matrix: Float32Array, contour: boolean, wrap?: boolean) => {\n position: Float32Array\n normal: undefined|Float32Array\n index: Uint32Array|Uint16Array\n atomindex: Int32Array|undefined\n contour: boolean\n }\n}\nexport function VolumeSurface (this: VolumeSurface,data: NumberArray, nx: number, ny: number, nz: number, atomindex: NumberArray) {\n var mc = new (MarchingCubes as any)(data, nx, ny, nz, atomindex) as MarchingCubes\n\n function getSurface (isolevel: number, smooth: boolean|number, box: number[][]|undefined, matrix: Float32Array, contour: boolean, wrap: boolean = false) {\n const sd = mc.triangulate(isolevel, smooth as boolean, box, contour, wrap)\n if (smooth && !contour) {\n laplacianSmooth(sd.position, sd.index as any, smooth as number, true)\n sd.normal = computeVertexNormals(sd.position, sd.index as any)\n }\n if (matrix) {\n applyMatrix4toVector3array(matrix, sd.position)\n if (sd.normal) {\n const normalMatrix = m3new()\n m3makeNormal(normalMatrix, matrix)\n applyMatrix3toVector3array(normalMatrix, sd.normal)\n }\n }\n return sd\n }\n\n this.getSurface = getSurface\n}\nObject.assign(VolumeSurface, {__deps: [\n laplacianSmooth, computeVertexNormals, MarchingCubes,\n applyMatrix4toVector3array, applyMatrix3toVector3array,\n m3new, m3makeNormal\n]})\n\nWorkerRegistry.add('surf', function func (e: any, callback: (data: any, transferList: any) => void) {\n const a = e.data.args\n const p = e.data.params\n if (a) {\n /* global self */\n (self as any).volsurf = new (VolumeSurface as any)(a[0], a[1], a[2], a[3], a[4]) as VolumeSurface\n }\n if (p) {\n const sd = ((self as any).volsurf as VolumeSurface).getSurface(\n p.isolevel, p.smooth, p.box, p.matrix, p.contour, p.wrap\n )\n const transferList = [ sd.position.buffer, sd.index.buffer ]\n if (sd.normal) transferList.push(sd.normal.buffer)\n if (sd.atomindex) transferList.push(sd.atomindex.buffer)\n const data = {\n sd: sd,\n p: p\n }\n callback(data, transferList)\n }\n}, [ VolumeSurface ])\n\nexport type VolumeSize = 'value'|'abs-value'|'value-min'|'deviation'\n/**\n * Volume\n */\nclass Volume {\n name: string\n path: string\n\n matrix: Matrix4\n normalMatrix: Matrix3\n inverseMatrix: Matrix4\n center: Vector3\n boundingBox: Box3\n\n nx: number\n ny: number\n nz: number\n data: Float32Array\n\n worker: Worker\n workerPool: WorkerPool\n _position: Float32Array|undefined\n _min: number|undefined\n _max: number|undefined\n _mean: number|undefined\n _rms: number|undefined\n _sum: number|undefined\n __box: Box3|undefined\n\n atomindex: Int32Array|undefined\n volsurf: VolumeSurface|undefined\n header: any\n /**\n * Make Volume instance\n * @param {String} name - volume name\n * @param {String} path - source path\n * @param {Float32array} data - volume 3d grid\n * @param {Integer} nx - x dimension of the 3d volume\n * @param {Integer} ny - y dimension of the 3d volume\n * @param {Integer} nz - z dimension of the 3d volume\n * @param {Int32Array} atomindex - atom indices corresponding to the cells in the 3d grid\n */\n constructor (name: string, path: string, data?: Float32Array, nx?: number, ny?: number, nz?: number, atomindex?: Int32Array) {\n this.name = name\n this.path = path\n\n this.matrix = new Matrix4()\n this.normalMatrix = new Matrix3()\n this.inverseMatrix = new Matrix4()\n this.center = new Vector3()\n this.boundingBox = new Box3()\n\n this.setData(data, nx, ny, nz, atomindex)\n }\n\n get type () { return 'Volume' }\n\n /**\n * set volume data\n * @param {Float32array} data - volume 3d grid\n * @param {Integer} nx - x dimension of the 3d volume\n * @param {Integer} ny - y dimension of the 3d volume\n * @param {Integer} nz - z dimension of the 3d volume\n * @param {Int32Array} atomindex - atom indices corresponding to the cells in the 3d grid\n * @return {undefined}\n */\n setData (data?: Float32Array, nx?: number, ny?: number, nz?: number, atomindex?: Int32Array) {\n this.nx = nx || 1\n this.ny = ny || 1\n this.nz = nz || 1\n\n this.data = data || new Float32Array(1)\n this.setAtomindex(atomindex)\n\n delete this._position\n\n delete this._min\n delete this._max\n delete this._mean\n delete this._rms\n\n if (this.worker) this.worker.terminate()\n }\n\n /**\n * Set statistics, which can be different from the data in this volume,\n * if this volume is a slice of a bigger volume\n * @param {Number|undefined} min - minimum value of the whole data set\n * @param {Number|undefined} max - maximum value of the whole data set\n * @param {Number|undefined} mean - average value of the whole data set\n * @param {Number|undefined} rms - sigma value of the whole data set\n */\n setStats (min: number|undefined, max: number|undefined, mean: number|undefined, rms: number|undefined) {\n this._min = min\n this._max = max\n this._mean = mean\n this._rms = rms\n }\n\n /**\n * set transformation matrix\n * @param {Matrix4} matrix - 4x4 transformation matrix\n * @return {undefined}\n */\n setMatrix (matrix: Matrix4) {\n this.matrix.copy(matrix)\n\n const bb = this.boundingBox\n const v = this.center // temporary re-purposing\n\n const x = this.nx - 1\n const y = this.ny - 1\n const z = this.nz - 1\n\n bb.makeEmpty()\n\n bb.expandByPoint(v.set(x, y, z))\n bb.expandByPoint(v.set(x, y, 0))\n bb.expandByPoint(v.set(x, 0, z))\n bb.expandByPoint(v.set(x, 0, 0))\n bb.expandByPoint(v.set(0, y, z))\n bb.expandByPoint(v.set(0, 0, z))\n bb.expandByPoint(v.set(0, y, 0))\n bb.expandByPoint(v.set(0, 0, 0))\n\n bb.applyMatrix4(this.matrix)\n bb.getCenter(this.center)\n\n // make normal matrix\n\n const me = this.matrix.elements\n const r0 = new Vector3(me[0], me[1], me[2])\n const r1 = new Vector3(me[4], me[5], me[6])\n const r2 = new Vector3(me[8], me[9], me[10])\n const cp = new Vector3()\n // [ r0 ] [ r1 x r2 ]\n // M3x3 = [ r1 ] N = [ r2 x r0 ]\n // [ r2 ] [ r0 x r1 ]\n const ne = this.normalMatrix.elements\n cp.crossVectors(r1, r2)\n ne[ 0 ] = cp.x\n ne[ 1 ] = cp.y\n ne[ 2 ] = cp.z\n cp.crossVectors(r2, r0)\n ne[ 3 ] = cp.x\n ne[ 4 ] = cp.y\n ne[ 5 ] = cp.z\n cp.crossVectors(r0, r1)\n ne[ 6 ] = cp.x\n ne[ 7 ] = cp.y\n ne[ 8 ] = cp.z\n\n this.inverseMatrix.copy(this.matrix).invert()\n }\n\n /**\n * set atom indices\n * @param {Int32Array} atomindex - atom indices corresponding to the cells in the 3d grid\n * @return {undefined}\n */\n setAtomindex (atomindex?: Int32Array) {\n this.atomindex = atomindex\n }\n\n getBox (center: Vector3, size: number, target: Box3) {\n if (!target) target = new Box3()\n\n target.set(center, center)\n target.expandByScalar(size)\n target.applyMatrix4(this.inverseMatrix)\n\n target.min.round()\n target.max.round()\n\n return target\n }\n\n _getBox (center: Vector3|undefined, size: number) {\n if (!center || !size) return\n\n if (!this.__box) this.__box = new Box3()\n const box = this.getBox(center, size, this.__box)\n return [ box.min.toArray(), box.max.toArray() ]\n }\n\n _makeSurface (sd: any, isolevel: number, smooth: number) {\n const name = this.name + '@' + isolevel.toPrecision(2)\n const surface = new Surface(name, '', sd)\n surface.info.isolevel = isolevel\n surface.info.smooth = smooth\n surface.info.volume = this\n\n return surface\n }\n\n getSurface (isolevel: number, smooth: number, center: Vector3, size: number, contour: boolean, wrap: boolean = false) {\n isolevel = isNaN(isolevel) ? this.getValueForSigma(2) : isolevel\n smooth = defaults(smooth, 0)\n\n //\n\n if (this.volsurf === undefined) {\n this.volsurf = new (VolumeSurface as any)(\n this.data, this.nx, this.ny, this.nz, this.atomindex\n ) as VolumeSurface\n }\n\n const box = this._getBox(center, size)\n const sd = this.volsurf.getSurface(\n isolevel, smooth, box!, this.matrix.elements as unknown as Float32Array, contour, wrap\n )\n\n return this._makeSurface(sd, isolevel, smooth)\n }\n\n getSurfaceWorker (isolevel: number, smooth: number, center: Vector3, size: number, contour: boolean, wrap: boolean, callback: (s: Surface) => void) {\n isolevel = isNaN(isolevel) ? this.getValueForSigma(2) : isolevel\n smooth = smooth || 0\n\n //\n\n if (window.hasOwnProperty('Worker')) {\n if (this.workerPool === undefined) {\n this.workerPool = new WorkerPool('surf', 2)\n }\n\n const msg = {}\n const worker = this.workerPool.getNextWorker()\n\n if (worker!.postCount === 0) {\n Object.assign(msg, {\n args: [\n this.data, this.nx, this.ny, this.nz, this.atomindex\n ]\n })\n }\n\n Object.assign(msg, {\n params: {\n isolevel: isolevel,\n smooth: smooth,\n box: this._getBox(center, size),\n matrix: this.matrix.elements,\n contour: contour,\n wrap: wrap\n }\n })\n\n worker!.post(msg, undefined,\n (e: any) => {\n const sd = e.data.sd\n const p = e.data.p\n callback(this._makeSurface(sd, p.isolevel, p.smooth))\n },\n (e : string) => {\n console.warn(\n 'Volume.getSurfaceWorker error - trying without worker', e\n )\n const surface = this.getSurface(isolevel, smooth, center, size, contour, wrap)\n callback(surface)\n }\n )\n } else {\n const surface = this.getSurface(isolevel, smooth, center, size, contour, wrap)\n callback(surface)\n }\n }\n\n getValueForSigma (sigma: number) {\n return this.mean + defaults(sigma, 2) * this.rms\n }\n\n getSigmaForValue (value: number) {\n return (defaults(value, 0) - this.mean) / this.rms\n }\n\n get position () {\n if (!this._position) {\n const nz = this.nz\n const ny = this.ny\n const nx = this.nx\n const position = new Float32Array(nx * ny * nz * 3)\n\n let p = 0\n for (let z = 0; z < nz; ++z) {\n for (let y = 0; y < ny; ++y) {\n for (let x = 0; x < nx; ++x) {\n position[ p + 0 ] = x\n position[ p + 1 ] = y\n position[ p + 2 ] = z\n p += 3\n }\n }\n }\n\n applyMatrix4toVector3array(this.matrix.elements as unknown as Float32Array, position)\n this._position = position\n }\n\n return this._position\n }\n\n getDataAtomindex () {\n return this.atomindex\n }\n\n getDataPosition () {\n return this.position\n }\n\n getDataColor (params: ColormakerParameters & {scheme: string}) {\n const p = params || {}\n p.volume = this\n p.scale = p.scale || 'Spectral'\n p.domain = p.domain || [ this.min, this.max ]\n\n const colormaker = ColormakerRegistry.getScheme(p)\n\n const n = this.position.length / 3\n const array = new Float32Array(n * 3)\n\n // var atoms = p.structure.atoms;\n // var atomindex = this.atomindex;\n\n for (let i = 0; i < n; ++i) {\n colormaker.volumeColorToArray(i, array, i * 3)\n // a = atoms[ atomindex[ i ] ];\n // if( a ) colormaker.atomColorToArray( a, array, i * 3 );\n }\n\n return array\n }\n\n getDataPicking () {\n const picking = serialArray(this.position.length / 3)\n return new VolumePicker(picking, this)\n }\n\n getDataSize (size: VolumeSize|number, scale: number) {\n const data = this.data\n const n = this.position.length / 3\n let array\n\n switch (size) {\n case 'value':\n array = new Float32Array(data)\n break\n\n case 'abs-value':\n array = new Float32Array(data)\n for (let i = 0; i < n; ++i) {\n array[ i ] = Math.abs(array[ i ])\n }\n break\n\n case 'value-min': {\n array = new Float32Array(data)\n const min = this.min\n for (let i = 0; i < n; ++i) {\n array[ i ] -= min\n }\n break\n }\n\n case 'deviation':\n array = new Float32Array(data)\n break\n\n default:\n array = uniformArray(n, size)\n break\n }\n\n if (scale !== 1.0) {\n for (let i = 0; i < n; ++i) {\n array[ i ] *= scale\n }\n }\n\n return array\n }\n\n get min () {\n if (this._min === undefined) {\n this._min = arrayMin(this.data)\n }\n return this._min\n }\n\n get max () {\n if (this._max === undefined) {\n this._max = arrayMax(this.data)\n }\n return this._max\n }\n\n get sum () {\n if (this._sum === undefined) {\n this._sum = arraySum(this.data)\n }\n return this._sum\n }\n\n get mean () {\n if (this._mean === undefined) {\n this._mean = arrayMean(this.data)\n }\n return this._mean\n }\n\n get rms () {\n if (this._rms === undefined) {\n this._rms = arrayRms(this.data)\n }\n return this._rms\n }\n\n clone () {\n const vol = new Volume(\n this.name,\n this.path,\n\n this.data,\n\n this.nx,\n this.ny,\n this.nz,\n\n this.atomindex\n )\n\n vol.matrix.copy(this.matrix)\n vol.header = Object.assign({}, this.header)\n\n return vol\n }\n\n dispose () {\n if (this.workerPool) this.workerPool.terminate()\n }\n}\n\nexport default Volume\n","/**\n * @file Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport {\n Color, Vector3, Matrix4,\n FrontSide, BackSide, DoubleSide,\n // VertexColors,\n NoBlending,\n BufferGeometry, BufferAttribute,\n UniformsUtils, UniformsLib, Uniform,\n Group, LineSegments, Points, Mesh, Object3D,\n ShaderMaterial,\n DynamicDrawUsage,\n StaticDrawUsage\n} from 'three'\n\nimport { Log } from '../globals'\nimport { createParams, getTypedArray, getUintArray } from '../utils'\nimport { GenericColor, TypedArray } from '../types'\nimport { getShader, ShaderDefines } from '../shader/shader-utils'\nimport { serialArray } from '../math/array-utils'\nimport { Picker } from '../utils/picker'\n\nexport type BufferSide = 'front'|'back'|'double'\n\nfunction getThreeSide (side: BufferSide) {\n if (side === 'front') {\n return FrontSide\n } else if (side === 'back') {\n return BackSide\n } else if (side === 'double') {\n return DoubleSide\n } else {\n return DoubleSide\n }\n}\n\nconst itemSize = {\n 'f': 1, 'v2': 2, 'v3': 3, 'c': 3\n}\n\nfunction setObjectMatrix (object: Object3D, matrix: Matrix4) {\n object.matrix.copy(matrix)\n object.matrix.decompose(object.position, object.quaternion, object.scale)\n object.matrixWorldNeedsUpdate = true\n}\n\nexport type BufferTypes = 'picking'|'background'\nexport type BufferMaterials = 'material'|'wireframeMaterial'|'pickingMaterial'\n\nexport interface _BufferAttribute {\n type: 'f'|'v2'|'v3'|'c'\n value?: TypedArray\n}\n\nexport type Uniforms = { [k: string]: Uniform|{ value: any } }\n\nexport const BufferDefaultParameters = {\n opaqueBack: false,\n side: 'double' as BufferSide, // which triangle sides to render\n opacity: 1.0, // translucency: 1 is fully opaque, 0 is fully transparent\n depthWrite: true,\n clipNear: 0, // position of camera near/front clipping plane in percent of scene bounding box\n clipRadius: 0,\n clipCenter: new Vector3(),\n flatShaded: false, // render flat shaded\n wireframe: false, // render as wireframe\n roughness: 0.4, // how rough the material is, between 0 and 1\n metalness: 0.0, // how metallic the material is, between 0 and 1\n diffuse: 0xffffff, // diffuse color for lighting\n diffuseInterior: false,\n useInteriorColor: false, // render back-side with interior color\n interiorColor: 0xdddddd, // interior color\n interiorDarkening: 0, // interior darkening factor\n forceTransparent: false, // force the material to allow transparency\n matrix: new Matrix4(), // additional transformation matrix\n disablePicking: false, // disable picking\n sortParticles: false,\n background: false\n}\nexport type BufferParameters = Omit & { diffuse: GenericColor; interiorColor: GenericColor }\n\nexport const BufferParameterTypes = {\n opaqueBack: { updateShader: true },\n side: { updateShader: true, property: true },\n opacity: { uniform: true },\n depthWrite: { property: true },\n clipNear: { updateShader: true, property: true },\n clipRadius: { updateShader: true, uniform: true },\n clipCenter: { uniform: true },\n flatShaded: { updateShader: true },\n background: { updateShader: true },\n wireframe: { updateVisibility: true },\n roughness: { uniform: true },\n metalness: { uniform: true },\n diffuse: { uniform: true },\n diffuseInterior: { updateShader: true },\n useInteriorColor: { updateShader: true },\n interiorColor: { uniform: true },\n interiorDarkening: { uniform: true },\n matrix: {}\n}\n\nexport interface BufferData {\n position?: Float32Array\n position1?: Float32Array // TODO\n color?: Float32Array\n index?: Uint32Array|Uint16Array\n normal?: Float32Array\n\n picking?: Picker\n primitiveId?: Float32Array\n}\n\n/**\n * Buffer class. Base class for buffers.\n * @interface\n */\nclass Buffer {\n parameterTypes = BufferParameterTypes\n get defaultParameters() { return BufferDefaultParameters }\n parameters: BufferParameters\n uniforms: Uniforms\n pickingUniforms: Uniforms\n\n private _positionDataSize: number\n\n geometry = new BufferGeometry()\n indexVersion = 0\n wireframeIndexVersion = -1\n group = new Group()\n wireframeGroup = new Group()\n pickingGroup = new Group()\n\n vertexShader = ''\n fragmentShader = ''\n isImpostor = false\n isText = false\n isSurface = false\n isPoint = false\n isLine = false\n dynamic = true\n visible = true\n\n picking?: Picker\n\n material: ShaderMaterial\n wireframeMaterial: ShaderMaterial\n pickingMaterial: ShaderMaterial\n\n wireframeIndex?: Uint32Array|Uint16Array\n wireframeIndexCount = 0\n wireframeGeometry?: BufferGeometry\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {Uint32Array|Uint16Array} data.index - triangle indices\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} params - parameters object\n */\n constructor (data: BufferData, params: Partial = {}) {\n this.parameters = createParams(params, this.defaultParameters)\n\n this.uniforms = UniformsUtils.merge([\n UniformsLib.common,\n {\n fogColor: { value: new Color(0x000000) },\n fogNear: { value: 0.0 },\n fogFar: { value: 0.0 },\n opacity: { value: this.parameters.opacity },\n clipNear: { value: 0.0 },\n clipRadius: { value: this.parameters.clipRadius },\n clipCenter: { value: this.parameters.clipCenter }\n },\n {\n emissive: { value: new Color(0x000000) },\n roughness: { value: this.parameters.roughness },\n metalness: { value: this.parameters.metalness },\n interiorColor: { value: new Color(this.parameters.interiorColor) },\n interiorDarkening: { value: this.parameters.interiorDarkening },\n },\n UniformsLib.lights\n ])\n\n this.uniforms.diffuse.value.set(this.parameters.diffuse)\n\n this.pickingUniforms = {\n clipNear: { value: 0.0 },\n objectId: { value: 0 },\n opacity: { value: this.parameters.opacity }\n }\n\n //\n\n const position = data.position || data.position1\n this._positionDataSize = position ? position.length / 3 : 0\n\n if (!data.primitiveId) {\n data.primitiveId = serialArray(this._positionDataSize)\n }\n\n this.addAttributes({\n position: { type: 'v3', value: data.position },\n color: { type: 'c', value: data.color },\n primitiveId: { type: 'f', value: data.primitiveId }\n })\n\n if (params.matrix) {\n this.matrix = params.matrix\n }\n\n if (data.index) {\n this.initIndex(data.index)\n }\n this.picking = data.picking\n\n this.makeWireframeGeometry()\n }\n\n set matrix (m) {\n this.setMatrix(m)\n }\n get matrix () {\n return this.group.matrix.clone()\n }\n\n get transparent () {\n return this.parameters.opacity < 1 || this.parameters.forceTransparent\n }\n\n get size () {\n return this._positionDataSize\n }\n\n get attributeSize () {\n return this.size\n }\n\n get pickable () {\n return !!this.picking && !this.parameters.disablePicking\n }\n\n setMatrix (m: Matrix4) {\n setObjectMatrix(this.group, m)\n setObjectMatrix(this.wireframeGroup, m)\n setObjectMatrix(this.pickingGroup, m)\n }\n\n initIndex (index: Uint32Array|Uint16Array) {\n this.geometry.setIndex(\n new BufferAttribute(index, 1)\n )\n const nindex = this.geometry.getIndex();\n if (!nindex) { Log.error('Index is null'); return; }\n nindex.setUsage(this.dynamic ? DynamicDrawUsage : StaticDrawUsage)\n }\n\n makeMaterial () {\n const side = getThreeSide(this.parameters.side)\n\n const m = new ShaderMaterial({\n uniforms: this.uniforms,\n vertexShader: '',\n fragmentShader: '',\n depthTest: true,\n transparent: this.transparent,\n depthWrite: this.parameters.depthWrite,\n lights: true,\n fog: true,\n side: side\n })\n m.vertexColors = true\n m.extensions.derivatives = true\n m.extensions.fragDepth = this.isImpostor\n\n const wm = new ShaderMaterial({\n uniforms: this.uniforms,\n vertexShader: '',\n fragmentShader: '',\n depthTest: true,\n transparent: this.transparent,\n depthWrite: this.parameters.depthWrite,\n lights: false,\n fog: true,\n side: side\n })\n wm.vertexColors = true\n\n const pm = new ShaderMaterial({\n uniforms: this.pickingUniforms,\n vertexShader: '',\n fragmentShader: '',\n depthTest: true,\n transparent: false,\n depthWrite: this.parameters.depthWrite,\n lights: false,\n fog: false,\n side: side,\n blending: NoBlending\n })\n pm.vertexColors = true\n pm.extensions.fragDepth = this.isImpostor\n\n ;(m as any).clipNear = this.parameters.clipNear\n ;(wm as any).clipNear = this.parameters.clipNear\n ;(pm as any).clipNear = this.parameters.clipNear\n\n this.material = m\n this.wireframeMaterial = wm\n this.pickingMaterial = pm\n\n // also sets vertexShader/fragmentShader\n this.updateShader()\n }\n\n makeWireframeGeometry () {\n this.makeWireframeIndex()\n\n const geometry = this.geometry\n const wireframeIndex = this.wireframeIndex\n const wireframeGeometry = new BufferGeometry()\n\n wireframeGeometry.attributes = geometry.attributes\n if (wireframeIndex) {\n wireframeGeometry.setIndex(\n new BufferAttribute(wireframeIndex, 1).setUsage(this.dynamic ? DynamicDrawUsage : StaticDrawUsage)\n )\n wireframeGeometry.setDrawRange(0, this.wireframeIndexCount)\n }\n\n this.wireframeGeometry = wireframeGeometry\n }\n\n makeWireframeIndex () {\n const edges: number[][] = []\n\n function checkEdge (a: number, b: number) {\n if (a > b) {\n const tmp = a\n a = b\n b = tmp\n }\n\n const list = edges[ a ]\n\n if (list === undefined) {\n edges[ a ] = [ b ]\n return true\n } else if (!list.includes(b)) {\n list.push(b)\n return true\n }\n\n return false\n }\n\n const geometry = this.geometry\n const index = geometry.index\n\n if (!this.parameters.wireframe) {\n this.wireframeIndex = new Uint16Array(0)\n this.wireframeIndexCount = 0\n } else if (index) {\n const array = index.array\n let n = array.length\n if (geometry.drawRange.count !== Infinity) {\n n = geometry.drawRange.count\n }\n let wireframeIndex\n if (this.wireframeIndex && this.wireframeIndex.length > n * 2) {\n wireframeIndex = this.wireframeIndex\n } else {\n const count = (geometry.attributes as any).position.count // TODO\n wireframeIndex = getUintArray(n * 2, count)\n }\n\n let j = 0\n edges.length = 0\n\n for (let i = 0; i < n; i += 3) {\n const a = array[ i + 0 ]\n const b = array[ i + 1 ]\n const c = array[ i + 2 ]\n\n if (checkEdge(a, b)) {\n wireframeIndex[ j + 0 ] = a\n wireframeIndex[ j + 1 ] = b\n j += 2\n }\n if (checkEdge(b, c)) {\n wireframeIndex[ j + 0 ] = b\n wireframeIndex[ j + 1 ] = c\n j += 2\n }\n if (checkEdge(c, a)) {\n wireframeIndex[ j + 0 ] = c\n wireframeIndex[ j + 1 ] = a\n j += 2\n }\n }\n\n this.wireframeIndex = wireframeIndex\n this.wireframeIndexCount = j\n this.wireframeIndexVersion = this.indexVersion\n } else {\n const n = (geometry.attributes as any).position.count // TODO\n\n let wireframeIndex\n if (this.wireframeIndex && this.wireframeIndex.length > n * 2) {\n wireframeIndex = this.wireframeIndex\n } else {\n wireframeIndex = getUintArray(n * 2, n)\n }\n\n for (let i = 0, j = 0; i < n; i += 3) {\n wireframeIndex[ j + 0 ] = i\n wireframeIndex[ j + 1 ] = i + 1\n wireframeIndex[ j + 2 ] = i + 1\n wireframeIndex[ j + 3 ] = i + 2\n wireframeIndex[ j + 4 ] = i + 2\n wireframeIndex[ j + 5 ] = i\n\n j += 6\n }\n\n this.wireframeIndex = wireframeIndex\n this.wireframeIndexCount = n * 2\n this.wireframeIndexVersion = this.indexVersion\n }\n }\n\n updateWireframeIndex () {\n if (!this.wireframeGeometry || !this.wireframeIndex) return\n\n this.wireframeGeometry.setDrawRange(0, Infinity)\n if (this.wireframeIndexVersion < this.indexVersion) this.makeWireframeIndex()\n\n if (this.wireframeGeometry.index &&\n this.wireframeIndex.length > this.wireframeGeometry.index.array.length) {\n this.wireframeGeometry.setIndex(\n new BufferAttribute(this.wireframeIndex, 1).setUsage(this.dynamic ? DynamicDrawUsage : StaticDrawUsage)\n )\n } else {\n const index = this.wireframeGeometry.getIndex()\n if (!index) { Log.error('Index is null'); return; }\n index.set(this.wireframeIndex)\n index.needsUpdate = this.wireframeIndexCount > 0\n index.updateRange.count = this.wireframeIndexCount\n }\n\n this.wireframeGeometry.setDrawRange(0, this.wireframeIndexCount)\n }\n\n getRenderOrder () {\n let renderOrder = 0\n\n if (this.isText) {\n renderOrder = 1\n } else if (this.transparent) {\n if (this.isSurface) {\n renderOrder = 3\n } else {\n renderOrder = 2\n }\n }\n\n return renderOrder\n }\n\n _getMesh (materialName: BufferMaterials) {\n if (!this.material) this.makeMaterial()\n\n const g = this.geometry\n const m = this[ materialName ]\n\n let mesh\n\n if (this.isLine) {\n mesh = new LineSegments(g, m)\n } else if (this.isPoint) {\n mesh = new Points(g, m)\n } else {\n mesh = new Mesh(g, m)\n }\n\n mesh.frustumCulled = false\n mesh.renderOrder = this.getRenderOrder()\n\n return mesh\n }\n\n getMesh () {\n return this._getMesh('material')\n }\n\n getWireframeMesh () {\n let mesh\n\n if (!this.material) this.makeMaterial()\n if (!this.wireframeGeometry) this.makeWireframeGeometry()\n\n mesh = new LineSegments(\n this.wireframeGeometry, this.wireframeMaterial\n )\n\n mesh.frustumCulled = false\n mesh.renderOrder = this.getRenderOrder()\n\n return mesh\n }\n\n getPickingMesh () {\n return this._getMesh('pickingMaterial')\n }\n\n getShader (name: string, type?: BufferTypes) {\n return getShader(name, this.getDefines(type))\n }\n\n getVertexShader (type?: BufferTypes) {\n return this.getShader(this.vertexShader, type)\n }\n\n getFragmentShader (type?: BufferTypes) {\n return this.getShader(this.fragmentShader, type)\n }\n\n getDefines (type?: BufferTypes) {\n const defines: ShaderDefines = {}\n\n if (this.parameters.clipNear) {\n defines.NEAR_CLIP = 1\n }\n\n if (this.parameters.clipRadius) {\n defines.RADIUS_CLIP = 1\n }\n\n if (type === 'picking') {\n defines.PICKING = 1\n } else {\n if (type === 'background' || this.parameters.background) {\n defines.NOLIGHT = 1\n }\n if (this.parameters.flatShaded) {\n defines.FLAT_SHADED = 1\n }\n if (this.parameters.opaqueBack) {\n defines.OPAQUE_BACK = 1\n }\n if (this.parameters.diffuseInterior) {\n defines.DIFFUSE_INTERIOR = 1\n }\n if (this.parameters.useInteriorColor) {\n defines.USE_INTERIOR_COLOR = 1\n }\n }\n\n return defines\n }\n\n getParameters () {\n return this.parameters\n }\n\n addUniforms (uniforms: Uniforms) {\n this.uniforms = UniformsUtils.merge(\n [ this.uniforms, uniforms ]\n )\n\n this.pickingUniforms = UniformsUtils.merge(\n [ this.pickingUniforms, uniforms ]\n )\n }\n\n addAttributes (attributes: { [k: string]: _BufferAttribute }) {\n for (let name in attributes) {\n let buf\n const a = attributes[ name ]\n const arraySize = this.attributeSize * itemSize[ a.type ]\n\n if (a.value) {\n if (arraySize !== a.value.length) {\n Log.error('attribute value has wrong length', name)\n }\n buf = a.value\n } else {\n buf = getTypedArray('float32', arraySize)\n }\n\n this.geometry.setAttribute(\n name,\n new BufferAttribute(buf, itemSize[ a.type ]).setUsage(this.dynamic ? DynamicDrawUsage : StaticDrawUsage)\n )\n }\n }\n\n updateRenderOrder () {\n const renderOrder = this.getRenderOrder()\n function setRenderOrder (mesh: Object3D) {\n mesh.renderOrder = renderOrder\n }\n\n this.group.children.forEach(setRenderOrder)\n if (this.pickingGroup) {\n this.pickingGroup.children.forEach(setRenderOrder)\n }\n }\n\n updateShader () {\n const m = this.material\n const wm = this.wireframeMaterial\n const pm = this.pickingMaterial\n\n m.vertexShader = this.getVertexShader()\n m.fragmentShader = this.getFragmentShader()\n m.needsUpdate = true\n\n wm.vertexShader = this.getShader('Line.vert')\n wm.fragmentShader = this.getShader('Line.frag')\n wm.needsUpdate = true\n\n pm.vertexShader = this.getVertexShader('picking')\n pm.fragmentShader = this.getFragmentShader('picking')\n pm.needsUpdate = true\n }\n\n /**\n * Set buffer parameters\n * @param {BufferParameters} params - buffer parameters object\n * @return {undefined}\n */\n setParameters (params: Partial) {\n const p = params as any\n const pt = this.parameterTypes as any\n const pv = this.parameters as any\n\n const propertyData: { [k: string]: any } = {}\n const uniformData: { [k: string]: any } = {}\n let doShaderUpdate = false\n let doVisibilityUpdate = false\n\n for (const name in p) {\n const value = p[ name ]\n\n if (value === undefined) continue\n pv[ name ] = value\n\n if (pt[ name ] === undefined) continue\n\n if (pt[ name ].property) {\n if (pt[ name ].property !== true) {\n propertyData[ pt[ name ].property as any ] = value\n } else {\n propertyData[ name ] = value\n }\n }\n\n if (pt[ name ].uniform) {\n if (pt[ name ].uniform !== true) {\n uniformData[ pt[ name ].uniform as any ] = value\n } else {\n uniformData[ name ] = value\n }\n }\n\n if (pt[ name ].updateShader) {\n doShaderUpdate = true\n }\n\n if (pt[ name ].updateVisibility) {\n doVisibilityUpdate = true\n }\n\n if (this.dynamic && name === 'wireframe' && value === true) {\n this.updateWireframeIndex()\n }\n\n if (name === 'forceTransparent') {\n propertyData.transparent = this.transparent\n }\n\n if (name === 'matrix') {\n this.matrix = value\n }\n }\n\n this.setProperties(propertyData)\n this.setUniforms(uniformData)\n if (doShaderUpdate) this.updateShader()\n if (doVisibilityUpdate) this.setVisibility(this.visible)\n }\n\n /**\n * Sets buffer attributes\n * @param {Object} data - An object where the keys are the attribute names\n * and the values are the attribute data.\n * @example\n * var buffer = new Buffer();\n * buffer.setAttributes({ attrName: attrData });\n */\n setAttributes (data: any) { // TODO\n const geometry = this.geometry\n const attributes = geometry.attributes as any // TODO\n\n for (const name in data) {\n if (name === 'picking') continue\n\n const array = data[ name ]\n const length = array.length\n\n if (name === 'index') {\n const index = geometry.getIndex()\n if (!index) { Log.error('Index is null'); continue; }\n geometry.setDrawRange(0, Infinity)\n\n if (length > index.array.length) {\n geometry.setIndex(\n new BufferAttribute(array, 1)\n .setUsage(this.dynamic ? DynamicDrawUsage : StaticDrawUsage)\n )\n } else {\n index.set(array)\n index.needsUpdate = length > 0\n index.updateRange.count = length\n geometry.setDrawRange(0, length)\n }\n\n this.indexVersion++\n if (this.parameters.wireframe) this.updateWireframeIndex()\n } else {\n const attribute = attributes[ name ]\n\n if (length > attribute.array.length) {\n geometry.setAttribute(\n name,\n new BufferAttribute(array, attribute.itemSize)\n .setUsage(this.dynamic ? DynamicDrawUsage : StaticDrawUsage)\n )\n } else {\n attributes[ name ].set(array)\n attributes[ name ].needsUpdate = length > 0\n attributes[ name ].updateRange.count = length\n }\n }\n }\n }\n\n setUniforms (data: any) { // TODO\n if (!data) return\n\n const u = this.material.uniforms\n const wu = this.wireframeMaterial.uniforms\n const pu = this.pickingMaterial.uniforms\n\n for (let name in data) {\n if (name === 'opacity') {\n this.setProperties({ transparent: this.transparent })\n }\n\n if (u[ name ] !== undefined) {\n if (u[ name ].value.isVector3) {\n u[ name ].value.copy(data[ name ])\n } else if (u[ name ].value.set) {\n u[ name ].value.set(data[ name ])\n } else {\n u[ name ].value = data[ name ]\n }\n }\n\n if (wu[ name ] !== undefined) {\n if (wu[ name ].value.isVector3) {\n wu[ name ].value.copy(data[ name ])\n } else if (wu[ name ].value.set) {\n wu[ name ].value.set(data[ name ])\n } else {\n wu[ name ].value = data[ name ]\n }\n }\n\n if (pu[ name ] !== undefined) {\n if (pu[ name ].value.isVector3) {\n pu[ name ].value.copy(data[ name ])\n } else if (pu[ name ].value.set) {\n pu[ name ].value.set(data[ name ])\n } else {\n pu[ name ].value = data[ name ]\n }\n }\n }\n }\n\n setProperties (data: any) { // TODO\n if (!data) return\n\n const m = this.material\n const wm = this.wireframeMaterial\n const pm = this.pickingMaterial\n\n for (const _name in data) {\n const name = _name as 'side'|'transparent' // TODO\n\n let value = data[ name ]\n\n if (name === 'transparent') {\n this.updateRenderOrder()\n } else if (name === 'side') {\n value = getThreeSide(value)\n }\n\n (m[ name ] as any) = value;\n (wm[ name ] as any) = value;\n (pm[ name ] as any) = value\n }\n\n m.needsUpdate = true\n wm.needsUpdate = true\n pm.needsUpdate = true\n }\n\n /**\n * Set buffer visibility\n * @param {Boolean} value - visibility value\n * @return {undefined}\n */\n setVisibility (value: boolean) {\n this.visible = value\n\n if (this.parameters.wireframe) {\n this.group.visible = false\n this.wireframeGroup.visible = value\n if (this.pickable) {\n this.pickingGroup.visible = false\n }\n } else {\n this.group.visible = value\n this.wireframeGroup.visible = false\n if (this.pickable) {\n this.pickingGroup.visible = value\n }\n }\n }\n\n /**\n * Free buffer resources\n * @return {undefined}\n */\n dispose () {\n if (this.material) this.material.dispose()\n if (this.wireframeMaterial) this.wireframeMaterial.dispose()\n if (this.pickingMaterial) this.pickingMaterial.dispose()\n\n this.geometry.dispose()\n if (this.wireframeGeometry) this.wireframeGeometry.dispose()\n }\n\n /**\n * Customize JSON serialization to avoid circular references\n */\n toJSON () {\n var result: any = {};\n for (var x in this) {\n if (x !== \"group\" && x !== \"wireframeGroup\" && x != \"pickingGroup\"\n && x !== \"picking\") {\n result[x] = this[x];\n }\n }\n return result;\n }\n}\n\nexport default Buffer\n","/**\n * @file Mesh Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport '../shader/Mesh.vert'\nimport '../shader/Mesh.frag'\n\nimport Buffer, { BufferParameters, BufferData } from './buffer'\n\n/**\n * Mesh buffer. Draws a triangle mesh.\n *\n * @example\n * var meshBuffer = new MeshBuffer({\n * position: new Float32Array(\n * [ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1 ]\n * ),\n * color: new Float32Array(\n * [ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 ]\n * )\n * });\n */\nclass MeshBuffer extends Buffer {\n vertexShader = 'Mesh.vert'\n fragmentShader = 'Mesh.frag'\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} [data.index] - triangle indices\n * @param {Float32Array} [data.normal] - radii\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: BufferData, params: Partial = {}) {\n super(data, params)\n\n this.addAttributes({\n 'normal': { type: 'v3', value: data.normal }\n })\n\n if (data.normal === undefined) {\n this.geometry.computeVertexNormals()\n }\n }\n}\n\nexport default MeshBuffer\n","/**\n * @file Surface Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport MeshBuffer from './mesh-buffer'\n\n/**\n * Surface buffer. Like a {@link MeshBuffer}, but with `.isSurface` set to `true`.\n */\nclass SurfaceBuffer extends MeshBuffer {\n isSurface = true\n}\n\nexport default SurfaceBuffer\n","/**\n * @file Double Sided Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3, Matrix4 required for declaration only\nimport { Group, BufferGeometry, Object3D, Mesh, LineSegments, Vector3, Matrix4 } from 'three'\n\nimport Buffer, { BufferSide } from './buffer'\nimport { Picker } from '../utils/picker'\n\nfunction setVisibilityTrue (m: Object3D) { m.visible = true }\nfunction setVisibilityFalse (m: Object3D) { m.visible = false }\n\n/**\n * A double-sided mesh buffer. Takes a buffer and renders the front and\n * the back as seperate objects to avoid some artifacts when rendering\n * transparent meshes. Also allows to render the back of a mesh opaque\n * while the front is transparent.\n * @implements {Buffer}\n *\n * @example\n * var sphereGeometryBuffer = new SphereGeometryBuffer({\n * position: new Float32Array([ 0, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n * var doubleSidedBuffer = new DoubleSidedBuffer(sphereGeometryBuffer);\n */\nclass DoubleSidedBuffer {\n size: number\n side: BufferSide\n visible: boolean\n wireframe: boolean\n geometry: BufferGeometry\n\n picking?: Picker\n\n group = new Group()\n wireframeGroup = new Group()\n pickingGroup = new Group()\n\n frontMeshes: (Mesh|LineSegments)[] = []\n backMeshes: (Mesh|LineSegments)[] = []\n\n buffer: Buffer\n frontBuffer: Buffer\n backBuffer: Buffer\n\n /**\n * Create a double sided buffer\n * @param {Buffer} buffer - the buffer to be rendered double-sided\n */\n constructor (buffer: Buffer) {\n this.size = buffer.size\n this.side = buffer.parameters.side\n this.visible = buffer.visible\n this.geometry = buffer.geometry\n this.picking = buffer.picking\n\n this.group = new Group()\n this.wireframeGroup = new Group()\n this.pickingGroup = new Group()\n\n // requires Group objects to be present\n this.matrix = buffer.matrix\n\n const frontBuffer = buffer\n const backBuffer = new (buffer as any).constructor({ // TODO\n position: new Float32Array(0)\n }) as Buffer\n\n frontBuffer.makeMaterial()\n backBuffer.makeMaterial()\n\n backBuffer.picking = buffer.picking\n backBuffer.geometry = buffer.geometry\n backBuffer.wireframeGeometry = buffer.wireframeGeometry\n backBuffer.setParameters(buffer.getParameters())\n backBuffer.updateShader()\n\n frontBuffer.setParameters({\n side: 'front'\n })\n backBuffer.setParameters({\n side: 'back',\n opacity: backBuffer.parameters.opacity\n })\n\n this.buffer = buffer\n this.frontBuffer = frontBuffer\n this.backBuffer = backBuffer\n }\n\n set matrix (m) {\n Buffer.prototype.setMatrix.call(this, m)\n }\n get matrix () {\n return this.group.matrix.clone()\n }\n\n get pickable () {\n return !!this.picking && !this.parameters.disablePicking\n }\n\n get parameters () {\n return this.buffer.parameters\n }\n\n getParameters () {\n const p = Object.assign({}, this.buffer.parameters)\n p.side = this.side\n return p\n }\n\n getMesh (picking: boolean) {\n let front, back\n\n if (picking) {\n back = this.backBuffer.getPickingMesh()\n front = this.frontBuffer.getPickingMesh()\n } else {\n back = this.backBuffer.getMesh()\n front = this.frontBuffer.getMesh()\n }\n\n this.frontMeshes.push(front)\n this.backMeshes.push(back)\n\n this.setParameters({ side: this.side })\n\n return new Group().add(back, front)\n }\n\n getWireframeMesh () {\n return this.buffer.getWireframeMesh()\n }\n\n getPickingMesh () {\n return this.getMesh(true)\n }\n\n setAttributes (data: any) { // TODO\n this.buffer.setAttributes(data)\n }\n\n setParameters (data: any) { // TODO\n data = Object.assign({}, data)\n\n if (data.side === 'front') {\n this.frontMeshes.forEach(setVisibilityTrue)\n this.backMeshes.forEach(setVisibilityFalse)\n } else if (data.side === 'back') {\n this.frontMeshes.forEach(setVisibilityFalse)\n this.backMeshes.forEach(setVisibilityTrue)\n } else if (data.side === 'double') {\n this.frontMeshes.forEach(setVisibilityTrue)\n this.backMeshes.forEach(setVisibilityTrue)\n }\n\n if (data.side !== undefined) {\n this.side = data.side\n }\n delete data.side\n\n if (data.matrix !== undefined) {\n this.matrix = data.matrix\n }\n delete data.matrix\n\n this.frontBuffer.setParameters(data)\n\n if (data.wireframe !== undefined) {\n this.wireframe = data.wireframe\n this.setVisibility(this.visible)\n }\n delete data.wireframe\n\n this.backBuffer.setParameters(data)\n }\n\n setVisibility (value: boolean) {\n this.visible = value\n\n if (this.parameters.wireframe) {\n this.group.visible = false\n this.wireframeGroup.visible = value\n if (this.pickable) {\n this.pickingGroup.visible = false\n }\n } else {\n this.group.visible = value\n this.wireframeGroup.visible = false\n if (this.pickable) {\n this.pickingGroup.visible = value\n }\n }\n }\n\n dispose () {\n this.frontBuffer.dispose()\n this.backBuffer.dispose()\n }\n\n /**\n * Customize JSON serialization to avoid circular references.\n * Only export simple params which could be useful.\n */\n toJSON () {\n var result: any = {};\n for (var x in this) {\n if (['side', 'size', 'visible', 'matrix', 'parameters'].includes(x)) {\n result[x] = this[x];\n }\n }\n return result;\n }\n}\n\nexport default DoubleSidedBuffer\n","/**\n * @file Contour Buffer\n * @author Fred ludlow \n * @private\n */\n\nimport '../shader/Line.vert'\nimport '../shader/Line.frag'\n\nimport Buffer from './buffer'\n\n/**\n * Contour buffer. A buffer that draws lines (instead of triangle meshes).\n */\nclass ContourBuffer extends Buffer {\n isLine = true\n vertexShader = 'Line.vert'\n fragmentShader = 'Line.frag'\n}\n\nexport default ContourBuffer\n","/**\n * @file Surface Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4, Vector3, Box3 } from 'three'\n\nimport { defaults } from '../utils'\nimport Representation, { RepresentationParameters } from './representation'\nimport Volume from '../surface/volume'\nimport SurfaceBuffer from '../buffer/surface-buffer'\nimport DoubleSidedBuffer from '../buffer/doublesided-buffer'\nimport ContourBuffer from '../buffer/contour-buffer'\nimport Surface from '../surface/surface';\nimport Viewer from '../viewer/viewer';\nimport {SurfaceData} from '../surface/surface'\n// @ts-ignore: unused import ColormakerParameters required for declaration only\nimport { ColormakerParameters } from '../color/colormaker';\nexport type SurfaceDataFields = {position: boolean, color: boolean, index: boolean, normal: boolean, radius: boolean}\n\n/**\n * Surface representation parameter object. Extends {@link RepresentationParameters}\n *\n * @typedef {Object} SurfaceRepresentationParameters - surface representation parameters\n *\n * @property {String} isolevelType - Meaning of the isolevel value. Either *value* for the literal value or *sigma* as a factor of the sigma of the data. For volume data only.\n * @property {Float} isolevel - The value at which to create the isosurface. For volume data only.\n * @property {Boolean} negateIsolevel - For volume data only.\n * @property {Boolean} isolevelScroll - For volume data only\n * @property {Integer} smooth - How many iterations of laplacian smoothing after surface triangulation. For volume data only.\n * @property {Boolean} background - Render the surface in the background, unlit.\n * @property {Boolean} opaqueBack - Render the back-faces (where normals point away from the camera) of the surface opaque, ignoring the transparency parameter.\n * @property {Integer} boxSize - Size of the box to triangulate volume data in. Set to zero to triangulate the whole volume. For volume data only.\n * @property {Boolean} useWorker - Weather or not to triangulate the volume asynchronously in a Web Worker. For volume data only.\n * @property {Boolean} wrap - Wrap volume data around the edges; use in conjuction with boxSize but not larger than the volume dimension. For volume data only.\n */\nexport interface SurfaceRepresentationParameters extends RepresentationParameters {\n isolevelType: 'value'|'sigma'\n isolevel: number\n smooth: number\n background: boolean\n opaqueBack: boolean\n boxSize: number\n useWorker: boolean\n wrap: boolean\n}\n/**\n * Surface representation\n */\n/**\n * Create Surface representation object\n * @param {Surface|Volume} surface - the surface or volume to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {SurfaceRepresentationParameters} params - surface representation parameters\n */\nclass SurfaceRepresentation extends Representation {\n protected surface: Surface|Volume|undefined\n protected volume: Volume|undefined\n protected boxCenter: Vector3\n protected __boxCenter: Vector3\n protected box: Box3\n protected __box: Box3\n protected _position: Vector3\n protected isolevelType: 'value'|'sigma'\n protected isolevel: number\n protected negateIsolevel: boolean\n protected isolevelScroll: boolean\n protected smooth: number\n protected background: boolean\n protected opaqueBack: boolean\n protected boxSize: number\n protected inverseMatrix: Matrix4\n protected colorVolume: Volume\n protected contour: boolean\n protected useWorker: boolean\n protected wrap: boolean\n\n protected __isolevel: number\n protected __smooth: number\n protected __contour: boolean\n protected __wrap: boolean\n protected __boxSize: number\n\n setBox: () => void\n\n constructor (surface: Surface, viewer: Viewer, params: Partial) {\n super(surface, viewer, params)\n\n this.type = 'surface'\n\n this.parameters = Object.assign({\n\n isolevelType: {\n type: 'select',\n options: {\n 'value': 'value', 'sigma': 'sigma'\n }\n },\n isolevel: {\n type: 'number', precision: 2, max: 1000, min: -1000\n },\n negateIsolevel: {\n type: 'boolean'\n },\n isolevelScroll: {\n type: 'boolean'\n },\n smooth: {\n type: 'integer', precision: 1, max: 10, min: 0\n },\n background: {\n type: 'boolean', rebuild: true // FIXME\n },\n opaqueBack: {\n type: 'boolean', buffer: true\n },\n boxSize: {\n type: 'integer', precision: 1, max: 100, min: 0\n },\n colorVolume: {\n type: 'hidden'\n },\n contour: {\n type: 'boolean', rebuild: true\n },\n useWorker: {\n type: 'boolean', rebuild: true\n },\n wrap: {\n type: 'boolean', rebuild: true\n }\n\n }, this.parameters)\n\n if (surface instanceof Volume) {\n this.surface = undefined\n this.volume = surface\n } else {\n this.surface = surface\n this.volume = undefined\n }\n\n this.boxCenter = new Vector3()\n this.__boxCenter = new Vector3()\n this.box = new Box3()\n this.__box = new Box3()\n\n this._position = new Vector3()\n this.inverseMatrix = new Matrix4()\n\n this.setBox = function setBox () {\n this._position.copy(viewer.translationGroup.position).negate()\n this._position.applyMatrix4(this.inverseMatrix)\n if (!this._position.equals(this.boxCenter)) {\n this.setParameters({ 'boxCenter': this._position })\n }\n }\n\n this.toBePrepared = true\n\n this.viewer.signals.ticked.add(this.setBox, this)\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'uniform')\n p.colorValue = defaults(p.colorValue, 0xDDDDDD)\n\n this.isolevelType = defaults(p.isolevelType, 'sigma')\n this.isolevel = defaults(p.isolevel, 2.0)\n this.negateIsolevel = defaults(p.negateIsolevel, false)\n this.isolevelScroll = defaults(p.isolevelScroll, false)\n this.smooth = defaults(p.smooth, 0)\n this.background = defaults(p.background, false)\n this.opaqueBack = defaults(p.opaqueBack, true)\n this.boxSize = defaults(p.boxSize, 0)\n this.colorVolume = defaults(p.colorVolume, undefined)\n this.contour = defaults(p.contour, false)\n this.useWorker = defaults(p.useWorker, true)\n this.wrap = defaults(p.wrap, false)\n\n super.init(p)\n\n this.inverseMatrix.copy(this.matrix).invert()\n\n this.build()\n }\n\n attach (callback: () => void) {\n this.bufferList.forEach(buffer => {\n this.viewer.add(buffer)\n })\n\n this.setVisibility(this.visible)\n\n callback()\n }\n\n prepare (callback: () => void) {\n if (this.volume) {\n let isolevel\n\n if (this.isolevelType === 'sigma') {\n isolevel = this.volume.getValueForSigma(this.isolevel)\n } else {\n isolevel = this.isolevel\n }\n if (this.negateIsolevel) isolevel *= -1\n\n if (!this.surface ||\n this.__isolevel !== isolevel ||\n this.__smooth !== this.smooth ||\n this.__contour !== this.contour ||\n this.__wrap !== this.wrap ||\n this.__boxSize !== this.boxSize ||\n (this.boxSize > 0 &&\n !this.__boxCenter.equals(this.boxCenter))\n ) {\n this.__isolevel = isolevel\n this.__smooth = this.smooth\n this.__contour = this.contour\n this.__wrap = this.wrap\n this.__boxSize = this.boxSize\n this.__boxCenter.copy(this.boxCenter)\n this.__box.copy(this.box)\n\n const onSurfaceFinish = (surface: Surface) => {\n this.surface = surface\n callback()\n }\n\n if (this.useWorker) {\n this.volume.getSurfaceWorker(\n isolevel, this.smooth, this.boxCenter, this.boxSize,\n this.contour, this.wrap, onSurfaceFinish\n )\n } else {\n onSurfaceFinish(\n this.volume.getSurface(\n isolevel, this.smooth, this.boxCenter, this.boxSize,\n this.contour, this.wrap\n )\n )\n }\n } else {\n callback()\n }\n } else {\n callback()\n }\n }\n\n create () {\n const sd = {\n position: (this.surface as Surface).getPosition(),\n color: (this.surface as Surface).getColor(this.getColorParams()),\n index: (this.surface as Surface).getIndex()\n }\n\n let buffer\n\n if (this.contour) {\n buffer = new ContourBuffer(\n sd,\n this.getBufferParams({ wireframe: false })\n )\n } else {\n Object.assign(sd, {\n normal: (this.surface as Surface).getNormal(),\n picking: (this.surface as Surface).getPicking()\n })\n\n const surfaceBuffer = new SurfaceBuffer(\n sd,\n this.getBufferParams({\n background: this.background,\n opaqueBack: this.opaqueBack,\n dullInterior: false\n })\n )\n\n buffer = new DoubleSidedBuffer(surfaceBuffer)\n }\n\n this.bufferList.push(buffer as ContourBuffer)\n }\n\n update (what: SurfaceDataFields) {\n if (this.bufferList.length === 0) return\n\n what = what || {}\n\n const surfaceData: Partial = {}\n\n if (what.position) {\n surfaceData.position = (this.surface as Surface).getPosition()\n }\n\n if (what.color) {\n surfaceData.color = (this.surface as Surface).getColor(\n this.getColorParams()\n )\n }\n\n if (what.index) {\n surfaceData.index = (this.surface as Surface).getIndex()\n }\n\n if (what.normal) {\n surfaceData.normal = (this.surface as Surface).getNormal()\n }\n\n this.bufferList.forEach(function (buffer) {\n buffer.setAttributes(surfaceData)\n })\n }\n\n /**\n * Set representation parameters\n * @alias SurfaceRepresentation#setParameters\n * @param {SurfaceRepresentationParameters} params - surface parameter object\n * @param {Object} [what] - buffer data attributes to be updated,\n * note that this needs to be implemented in the\n * derived classes. Generally it allows more\n * fine-grained control over updating than\n * forcing a rebuild.\n * @param {Boolean} what.position - update position data\n * @param {Boolean} what.color - update color data\n * @param {Boolean} [rebuild] - whether or not to rebuild the representation\n * @return {SurfaceRepresentation} this object\n */\n setParameters (params: Partial, what?: SurfaceDataFields, rebuild?: boolean) {\n if (params && params.isolevelType !== undefined &&\n this.volume\n ) {\n if (this.isolevelType === 'value' &&\n params.isolevelType === 'sigma'\n ) {\n this.isolevel = this.volume.getSigmaForValue(this.isolevel)\n } else if (this.isolevelType === 'sigma' &&\n params.isolevelType === 'value'\n ) {\n this.isolevel = this.volume.getValueForSigma(this.isolevel)\n }\n\n this.isolevelType = params.isolevelType\n }\n\n if (params && params.boxCenter) {\n this.boxCenter.copy(params.boxCenter)\n delete params.boxCenter\n }\n\n // Forbid wireframe && contour as in molsurface\n if (params && params.wireframe && (\n params.contour || (params.contour === undefined && this.contour)\n )) {\n params.wireframe = false\n }\n\n super.setParameters(params, what, rebuild)\n\n if (params.matrix) {\n this.inverseMatrix.copy(params.matrix).invert()\n }\n\n if (this.volume) {\n this.volume.getBox(this.boxCenter, this.boxSize, this.box)\n }\n\n if (params && params.colorVolume !== undefined) {\n if (what) what.color = true\n }\n\n if (this.surface && (\n params.isolevel !== undefined ||\n params.negateIsolevel !== undefined ||\n params.smooth !== undefined ||\n params.wrap !== undefined ||\n params.boxSize !== undefined ||\n (this.boxSize > 0 &&\n !this.__box.equals(this.box))\n )) {\n this.build({\n 'position': true,\n 'color': true,\n 'index': true,\n 'normal': !this.contour\n })\n }\n\n return this\n }\n\n getColorParams () {\n const p = super.getColorParams()\n\n p.volume = this.colorVolume\n\n return p\n }\n\n dispose () {\n this.viewer.signals.ticked.remove(this.setBox, this)\n\n super.dispose()\n }\n}\n\nexport default SurfaceRepresentation\n","/**\n * @file Mouse Actions\n * @author Alexander Rose \n * @private\n */\n\nimport PickingProxy from './picking-proxy'\nimport { almostIdentity } from '../math/math-utils'\nimport Stage from '../stage/stage'\nimport StructureComponent from '../component/structure-component'\nimport SurfaceRepresentation from '../representation/surface-representation'\n\nexport type ScrollCallback = (stage: Stage, delta: number) => void\nexport type DragCallback = (stage: Stage, dx: number, dy: number) => void\nexport type PickCallback = (stage: Stage, pickingProxy: PickingProxy) => void\nexport type MouseActionCallback = ScrollCallback | DragCallback | PickCallback\n\n/**\n * Mouse actions provided as static methods\n */\nclass MouseActions {\n /**\n * Zoom scene based on scroll-delta\n * @param {Stage} stage - the stage\n * @param {Number} delta - amount to zoom\n * @return {undefined}\n */\n static zoomScroll (stage: Stage, delta: number) {\n stage.trackballControls.zoom(delta)\n }\n\n /**\n * Move near clipping plane based on scroll-delta\n * @param {Stage} stage - the stage\n * @param {Number} delta - amount to move clipping plane\n * @return {undefined}\n */\n static clipNearScroll (stage: Stage, delta: number) {\n const sp = stage.getParameters()\n stage.setParameters({ clipNear: sp.clipNear + delta / 10 })\n }\n\n /**\n * Move clipping planes based on scroll-delta.\n * @param {Stage} stage - the stage\n * @param {Number} delta - direction to move planes\n * @return {undefined}\n */\n static focusScroll (stage: Stage, delta: number) {\n const focus = stage.getFocus()\n const sign = Math.sign(delta)\n const step = sign * almostIdentity((100 - focus) / 10, 5, 0.2)\n stage.setFocus(focus + step)\n }\n\n /**\n * Zoom scene based on scroll-delta and\n * move focus planes based on camera position (zoom)\n * @param {Stage} stage - the stage\n * @param {Number} delta - amount to move focus planes and zoom\n * @return {undefined}\n */\n static zoomFocusScroll (stage: Stage, delta: number) {\n stage.trackballControls.zoom(delta)\n const z = stage.viewer.camera.position.z\n stage.setFocus(100 - Math.abs(z / 8))\n }\n\n /**\n * Change isolevel of volume surfaces based on scroll-delta\n * @param {Stage} stage - the stage\n * @param {Number} delta - amount to change isolevel\n * @return {undefined}\n */\n static isolevelScroll (stage: Stage, delta: number) {\n const d = Math.sign(delta) / 10\n stage.eachRepresentation((reprElem, comp) => {\n if (reprElem.repr instanceof SurfaceRepresentation) {\n const p = reprElem.getParameters() as any // TODO\n if (p.isolevelScroll) {\n reprElem.setParameters({ isolevel: p.isolevel + d })\n }\n }\n })\n }\n\n /**\n * Pan scene based on mouse coordinate changes\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to pan in x direction\n * @param {Number} dy - amount to pan in y direction\n * @return {undefined}\n */\n static panDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.pan(dx, dy)\n }\n\n /**\n * Rotate scene based on mouse coordinate changes\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to rotate in x direction\n * @param {Number} dy - amount to rotate in y direction\n * @return {undefined}\n */\n static rotateDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.rotate(dx, dy)\n }\n\n /**\n * Rotate scene around z axis based on mouse coordinate changes\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to rotate in x direction\n * @param {Number} dy - amount to rotate in y direction\n * @return {undefined}\n */\n static zRotateDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.zRotate(dx, dy)\n }\n\n /**\n * Zoom scene based on mouse coordinate changes\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to zoom\n * @param {Number} dy - amount to zoom\n * @return {undefined}\n */\n static zoomDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.zoom((dx + dy) / -2)\n }\n\n /**\n * Zoom scene based on mouse coordinate changes and\n * move focus planes based on camera position (zoom)\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to zoom and focus\n * @param {Number} dy - amount to zoom and focus\n * @return {undefined}\n */\n static zoomFocusDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.zoom((dx + dy) / -2)\n const z = stage.viewer.camera.position.z\n stage.setFocus(100 - Math.abs(z / 8))\n }\n\n /**\n * Pan picked component based on mouse coordinate changes\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to pan in x direction\n * @param {Number} dy - amount to pan in y direction\n * @return {undefined}\n */\n static panComponentDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.panComponent(dx, dy)\n }\n\n /**\n * Pan picked atom based on mouse coordinate changes\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to pan in x direction\n * @param {Number} dy - amount to pan in y direction\n * @return {undefined}\n */\n static panAtomDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.panAtom(dx, dy)\n }\n\n /**\n * Rotate picked component based on mouse coordinate changes\n * @param {Stage} stage - the stage\n * @param {Number} dx - amount to rotate in x direction\n * @param {Number} dy - amount to rotate in y direction\n * @return {undefined}\n */\n static rotateComponentDrag (stage: Stage, dx: number, dy: number) {\n stage.trackballControls.rotateComponent(dx, dy)\n }\n\n /**\n * Move picked element to the center of the screen\n * @param {Stage} stage - the stage\n * @param {PickingProxy} pickingProxy - the picking data object\n * @return {undefined}\n */\n static movePick (stage: Stage, pickingProxy: PickingProxy) {\n if (pickingProxy) {\n stage.animationControls.move(pickingProxy.position.clone())\n }\n }\n\n /**\n * Show tooltip with information of picked element\n * @param {Stage} stage - the stage\n * @param {PickingProxy} pickingProxy - the picking data object\n * @return {undefined}\n */\n static tooltipPick (stage: Stage, pickingProxy: PickingProxy) {\n const tt = stage.tooltip\n const sp = stage.getParameters() as any\n if (sp.tooltip && pickingProxy) {\n const mp = pickingProxy.mouse.position\n tt.innerText = pickingProxy.getLabel()\n tt.style.bottom = (window.innerHeight - mp.y + 3) + 'px'\n tt.style.left = (mp.x + 3) + 'px'\n tt.style.display = 'block'\n } else {\n tt.style.display = 'none'\n }\n }\n\n static measurePick (stage: Stage, pickingProxy: PickingProxy) {\n if (pickingProxy && (pickingProxy.atom || pickingProxy.bond)) {\n const atom = pickingProxy.atom || pickingProxy.closestBondAtom\n const sc = pickingProxy.component as StructureComponent\n sc.measurePick(atom)\n } else {\n stage.measureClear()\n }\n }\n}\n\ntype MouseActionPreset = [ string, MouseActionCallback ][]\nexport const MouseActionPresets = {\n default: [\n [ 'scroll', MouseActions.zoomScroll ],\n [ 'scroll-shift', MouseActions.focusScroll ],\n [ 'scroll-ctrl', MouseActions.isolevelScroll ],\n [ 'scroll-shift-ctrl', MouseActions.zoomFocusScroll ],\n\n [ 'drag-left', MouseActions.rotateDrag ],\n [ 'drag-right', MouseActions.panDrag ],\n [ 'drag-ctrl-left', MouseActions.panDrag ],\n [ 'drag-ctrl-right', MouseActions.zRotateDrag ],\n [ 'drag-shift-left', MouseActions.zoomDrag ],\n [ 'drag-middle', MouseActions.zoomFocusDrag ],\n\n [ 'drag-ctrl-shift-right', MouseActions.panComponentDrag ],\n [ 'drag-ctrl-shift-left', MouseActions.rotateComponentDrag ],\n\n [ 'clickPick-right', MouseActions.measurePick ],\n [ 'clickPick-ctrl-left', MouseActions.measurePick ],\n [ 'clickPick-middle', MouseActions.movePick ],\n [ 'clickPick-left', MouseActions.movePick ],\n [ 'hoverPick', MouseActions.tooltipPick ]\n ] as MouseActionPreset,\n pymol: [\n [ 'drag-left', MouseActions.rotateDrag ],\n [ 'drag-middle', MouseActions.panDrag ],\n [ 'drag-right', MouseActions.zoomDrag ],\n [ 'scroll', MouseActions.focusScroll ],\n [ 'drag-shift-right', MouseActions.focusScroll ],\n\n [ 'clickPick-ctrl+shift-middle', MouseActions.movePick ],\n [ 'hoverPick', MouseActions.tooltipPick ]\n ] as MouseActionPreset,\n coot: [\n [ 'scroll', MouseActions.isolevelScroll ],\n\n [ 'drag-left', MouseActions.rotateDrag ],\n [ 'drag-middle', MouseActions.panDrag ],\n [ 'drag-ctrl-left', MouseActions.panDrag ],\n [ 'drag-right', MouseActions.zoomFocusDrag ],\n [ 'drag-ctrl-right', MouseActions.focusScroll ],\n\n [ 'clickPick-middle', MouseActions.movePick ],\n [ 'hoverPick', MouseActions.tooltipPick ]\n ] as MouseActionPreset,\n astexviewer: [\n [ 'drag-left', MouseActions.rotateDrag ],\n [ 'drag-ctrl-left', MouseActions.panDrag ],\n [ 'drag-shift-left', MouseActions.zoomDrag ],\n [ 'scroll', MouseActions.focusScroll ],\n [ 'clickPick-middle', MouseActions.movePick ],\n [ 'hoverPick', MouseActions.tooltipPick ]\n ] as MouseActionPreset\n}\n\nexport default MouseActions\n","/**\n * @file Mouse Controls\n * @author Alexander Rose \n * @private\n */\n\nimport { MouseActionPresets, MouseActionCallback } from './mouse-actions'\nimport Stage from '../stage/stage'\nimport MouseObserver from '../stage/mouse-observer'\n\nexport type MouseControlPreset = keyof typeof MouseActionPresets\nexport interface MouseControlsParams {\n preset?: MouseControlPreset\n disabled?: boolean\n}\n\nexport type MouseActionType = ''|'scroll'|'drag'|'click'|'doubleClick'|'hover'|'clickPick'|'hoverPick'\nexport interface MouseAction {\n type: MouseActionType\n key: number\n button: number\n callback: MouseActionCallback\n}\n\n/**\n * Strings to describe mouse events (including optional keyboard modifiers).\n * Must contain an event type: \"scroll\", \"drag\", \"click\", \"doubleClick\",\n * \"hover\", \"clickPick\" or \"hoverPick\". Optionally contain one or more\n * (seperated by plus signs) keyboard modifiers: \"alt\", \"ctrl\", \"meta\" or\n * \"shift\". Can contain the mouse button performing the event: \"left\",\n * \"middle\" or \"right\". The type, key and button parts must be seperated by\n * dashes.\n *\n * @example\n * // triggered on scroll event (no key or button)\n * \"scroll\"\n *\n * @example\n * // triggered on scroll event while shift key is pressed\n * \"scroll-shift\"\n *\n * @example\n * // triggered on drag event with left mouse button\n * \"drag-left\"\n *\n * @example\n * // triggered on drag event with right mouse button\n * // while ctrl and shift keys are pressed\n * \"drag-right-ctrl+shift\"\n *\n * @typedef {String} TriggerString\n */\n\n/**\n * Get event type, key and button\n * @param {TriggerString} str - input trigger string\n * @return {Array} event type, key and button\n */\nfunction triggerFromString (str: string) {\n const tokens = str.split(/[-+]/)\n\n let type = ''\n if (tokens.includes('scroll')) type = 'scroll'\n if (tokens.includes('drag')) type = 'drag'\n if (tokens.includes('click')) type = 'click'\n if (tokens.includes('doubleClick')) type = 'doubleClick'\n if (tokens.includes('hover')) type = 'hover'\n if (tokens.includes('clickPick')) type = 'clickPick'\n if (tokens.includes('hoverPick')) type = 'hoverPick'\n\n let key = 0\n if (tokens.includes('alt')) key += 1\n if (tokens.includes('ctrl')) key += 2\n if (tokens.includes('meta')) key += 4\n if (tokens.includes('shift')) key += 8\n\n let button = 0\n if (tokens.includes('left')) button += 1\n if (tokens.includes('right')) button += 2\n if (tokens.includes('middle')) button += 4\n\n return [ type, key, button ] as [ MouseActionType, number, number ]\n}\n\n/**\n * Mouse controls\n */\nclass MouseControls {\n actionList: MouseAction[] = []\n mouse: MouseObserver\n\n disabled: boolean // Flag to disable all actions\n\n /**\n * @param {Stage} stage - the stage object\n * @param {Object} [params] - the parameters\n * @param {String} params.preset - one of \"default\", \"pymol\", \"coot\"\n * @param {String} params.disabled - flag to disable all actions\n */\n constructor (readonly stage: Stage, params: MouseControlsParams = {}) {\n this.mouse = stage.mouseObserver\n this.disabled = params.disabled || false\n this.preset(params.preset || 'default')\n }\n\n run (type: MouseActionType, ...args: any[]) {\n if (this.disabled) return\n\n const key = this.mouse.key || 0\n const button = this.mouse.buttons || 0\n\n this.actionList.forEach(a => {\n if (a.type === type && a.key === key && a.button === button) {\n (a.callback as any)(this.stage, ...args) // TODO\n }\n })\n }\n\n /**\n * Add a new mouse action triggered by an event, key and button combination.\n * The {@link MouseActions} class provides a number of static methods for\n * use as callback functions.\n *\n * @example\n * // change ambient light intensity on mouse scroll\n * // while the ctrl and shift keys are pressed\n * stage.mouseControls.add( \"scroll-ctrl+shift\", function( stage, delta ){\n * var ai = stage.getParameters().ambientIntensity;\n * stage.setParameters( { ambientIntensity: Math.max( 0, ai + delta / 50 ) } );\n * } );\n *\n * @example\n * // Call the MouseActions.zoomDrag method on mouse drag events\n * // with left and right mouse buttons simultaneous\n * stage.mouseControls.add( \"drag-left+right\", MouseActions.zoomDrag );\n *\n * @param {TriggerString} triggerStr - the trigger for the action\n * @param {function(stage: Stage, ...args: Any)} callback - the callback function for the action\n * @return {undefined}\n */\n add (triggerStr: string, callback: MouseActionCallback) {\n const [ type, key, button ] = triggerFromString(triggerStr)\n\n this.actionList.push({ type, key, button, callback })\n }\n\n /**\n * Remove a mouse action. The trigger string can contain an asterix (*)\n * as a wildcard for any key or mouse button. When the callback function\n * is given, only actions that call that function are removed.\n *\n * @example\n * // remove actions triggered solely by a scroll event\n * stage.mouseControls.remove( \"scroll\" );\n *\n * @example\n * // remove actions triggered by a scroll event, including\n * // those requiring a key pressed or mouse button used\n * stage.mouseControls.remove( \"scroll-*\" );\n *\n * @example\n * // remove actions triggered by a scroll event\n * // while the shift key is pressed\n * stage.mouseControls.remove( \"scroll-shift\" );\n *\n * @param {TriggerString} triggerStr - the trigger for the action\n * @param {Function} [callback] - the callback function for the action\n * @return {undefined}\n */\n remove (triggerStr: string, callback?: MouseActionCallback) {\n const wildcard = triggerStr.includes('*')\n const [ type, key, button ] = triggerFromString(triggerStr)\n\n const actionList = this.actionList.filter(function (a) {\n return !(\n (a.type === type || (wildcard && type === '')) &&\n (a.key === key || (wildcard && key === 0)) &&\n (a.button === button || (wildcard && button === 0)) &&\n (a.callback === callback || callback === undefined)\n )\n })\n\n this.actionList = actionList\n }\n\n /**\n * Set mouse action preset\n * @param {String} name - one of \"default\", \"pymol\", \"coot\"\n * @return {undefined}\n */\n preset (name: MouseControlPreset) {\n this.clear()\n\n const list = MouseActionPresets[ name ] || []\n\n list.forEach(action => this.add(action[0], action[1]))\n }\n\n /**\n * Remove all mouse actions\n * @return {undefined}\n */\n clear () {\n this.actionList.length = 0\n }\n}\n\nexport default MouseControls\n","/**\n * @file Key Actions\n * @author Alexander Rose \n * @private\n */\n\nimport Stage from '../stage/stage'\n\nexport type KeyActionCallback = (stage: Stage) => void\n\n/**\n * Key actions provided as static methods\n */\nclass KeyActions {\n /**\n * Stage auto view\n */\n static autoView (stage: Stage) {\n stage.autoView(1000)\n }\n\n /**\n * Toggle stage animations\n */\n static toggleAnimations (stage: Stage) {\n stage.animationControls.toggle()\n }\n\n /**\n * Toggle stage rocking\n */\n static toggleRock (stage: Stage) {\n stage.toggleRock()\n }\n\n /**\n * Toggle stage spinning\n */\n static toggleSpin (stage: Stage) {\n stage.toggleSpin()\n }\n\n /**\n * Toggle anti-aliasing\n */\n static toggleAntialiasing (stage: Stage) {\n const p = stage.getParameters()\n stage.setParameters({ sampleLevel: p.sampleLevel === -1 ? 0 : -1 })\n }\n}\n\ntype KeyActionPreset = [ string, KeyActionCallback ][]\nexport const KeyActionPresets = {\n default: [\n [ 'i', KeyActions.toggleSpin ],\n [ 'k', KeyActions.toggleRock ],\n [ 'p', KeyActions.toggleAnimations ],\n [ 'a', KeyActions.toggleAntialiasing ],\n [ 'r', KeyActions.autoView ]\n ] as KeyActionPreset\n}\n\nexport default KeyActions\n","/**\n * @file Key Controls\n * @author Alexander Rose \n * @private\n */\n\nimport { KeyActionPresets, KeyActionCallback } from './key-actions'\nimport Stage from '../stage/stage'\n\nexport type KeyControlPreset = keyof typeof KeyActionPresets\nexport interface KeyControlsParams {\n preset?: KeyControlPreset\n disabled?: boolean\n}\n\nexport interface KeyAction {\n key: string,\n callback: KeyActionCallback\n}\n\n/**\n * Mouse controls\n */\nclass KeyControls {\n actionList: KeyAction[] = []\n\n disabled: boolean // Flag to disable all actions\n\n /**\n * @param {Stage} stage - the stage object\n * @param {Object} [params] - the parameters\n * @param {String} params.preset - one of \"default\"\n * @param {String} params.disabled - flag to disable all actions\n */\n constructor (readonly stage: Stage, params: KeyControlsParams = {}) {\n this.disabled = params.disabled || false\n this.preset(params.preset || 'default')\n }\n\n run (key: string) {\n if (this.disabled) return\n\n this.actionList.forEach(a => {\n if (a.key === key) {\n a.callback(this.stage)\n }\n })\n }\n\n /**\n * Add a key action triggered by pressing the given character.\n * The {@link KeyActions} class provides a number of static methods for\n * use as callback functions.\n *\n * @example\n * // call KeyActions.toggleRock when \"k\" is pressed\n * stage.keyControls.remove( \"k\", KeyActions.toggleRock );\n *\n * @param {Char} char - the key/character\n * @param {Function} callback - the callback function for the action\n * @return {undefined}\n */\n add (char: string, callback: KeyActionCallback) {\n this.actionList.push({ key: char, callback })\n }\n\n /**\n * Remove a key action. When the callback function\n * is given, only actions that call that function are removed.\n *\n * @example\n * // remove all actions triggered by pressing \"k\"\n * stage.keyControls.remove( \"k\" );\n *\n * @example\n * // remove action `toggleRock` triggered by pressing \"k\"\n * stage.keyControls.remove( \"k\", toggleRock );\n *\n * @param {Char} char - the key/character\n * @param {Function} [callback] - the callback function for the action\n * @return {undefined}\n */\n remove (char: string, callback: KeyActionCallback) {\n\n const actionList = this.actionList.filter(function (a) {\n return !(\n (a.key === char) &&\n (a.callback === callback || callback === undefined)\n )\n })\n\n this.actionList = actionList\n }\n\n /**\n * Set key action preset\n * @param {String} name - one of \"default\"\n * @return {undefined}\n */\n preset (name: KeyControlPreset) {\n this.clear()\n\n const list = KeyActionPresets[ name ] || []\n\n list.forEach(action => this.add(action[0], action[1]))\n }\n\n /**\n * Remove all key actions\n * @return {undefined}\n */\n clear () {\n this.actionList.length = 0\n }\n}\n\nexport default KeyControls\n","/**\n * @file Picking Behavior\n * @author Alexander Rose \n * @private\n */\n\nimport Stage from './stage'\nimport MouseObserver from './mouse-observer'\nimport Viewer from '../viewer/viewer'\nimport MouseControls from '../controls/mouse-controls'\n\nclass PickingBehavior {\n viewer: Viewer\n mouse: MouseObserver\n controls: MouseControls\n\n constructor (readonly stage: Stage) {\n this.stage = stage\n this.mouse = stage.mouseObserver\n this.controls = stage.mouseControls\n\n this.mouse.signals.clicked.add(this._onClick, this)\n this.mouse.signals.hovered.add(this._onHover, this)\n }\n\n _onClick (x: number, y: number) {\n const pickingProxy = this.stage.pickingControls.pick(x, y)\n this.stage.signals.clicked.dispatch(pickingProxy)\n this.controls.run('clickPick', pickingProxy)\n }\n\n _onHover (x: number, y: number) {\n const pickingProxy = this.stage.pickingControls.pick(x, y)\n if (pickingProxy && this.mouse.down.equals(this.mouse.position)) {\n this.stage.transformComponent = pickingProxy.component\n this.stage.transformAtom = pickingProxy.atom\n }\n this.stage.signals.hovered.dispatch(pickingProxy)\n this.controls.run('hoverPick', pickingProxy)\n }\n\n dispose () {\n this.mouse.signals.clicked.remove(this._onClick, this)\n this.mouse.signals.hovered.remove(this._onHover, this)\n }\n}\n\nexport default PickingBehavior\n","/**\n * @file Mouse Behavior\n * @author Alexander Rose \n * @private\n */\n\nimport Stage from './stage'\nimport MouseObserver from './mouse-observer'\nimport Viewer from '../viewer/viewer'\nimport MouseControls from '../controls/mouse-controls'\n\nclass MouseBehavior {\n viewer: Viewer\n mouse: MouseObserver\n controls: MouseControls\n domElement: HTMLCanvasElement\n\n constructor (readonly stage: Stage) {\n this.stage = stage\n this.mouse = stage.mouseObserver\n this.controls = stage.mouseControls\n\n this.mouse.signals.moved.add(this._onMove, this)\n this.mouse.signals.scrolled.add(this._onScroll, this)\n this.mouse.signals.dragged.add(this._onDrag, this)\n this.mouse.signals.clicked.add(this._onClick, this)\n this.mouse.signals.hovered.add(this._onHover, this)\n this.mouse.signals.doubleClicked.add(this._onDblclick, this)\n }\n\n _onMove (/* x, y */) {\n this.stage.tooltip.style.display = 'none'\n }\n\n _onScroll (delta: number) {\n this.controls.run('scroll', delta)\n }\n\n _onDrag (dx: number, dy: number) {\n this.controls.run('drag', dx, dy)\n }\n\n _onClick (x: number, y: number) {\n this.controls.run('click', x, y)\n }\n\n _onDblclick (x: number, y: number) {\n this.controls.run('doubleClick', x, y)\n }\n\n _onHover (x: number, y: number) {\n this.controls.run('hover', x, y)\n }\n\n dispose () {\n this.mouse.signals.moved.remove(this._onMove, this)\n this.mouse.signals.scrolled.remove(this._onScroll, this)\n this.mouse.signals.dragged.remove(this._onDrag, this)\n this.mouse.signals.clicked.remove(this._onClick, this)\n this.mouse.signals.hovered.remove(this._onHover, this)\n }\n}\n\nexport default MouseBehavior\n","/**\n * @file Animation Behavior\n * @author Alexander Rose \n * @private\n */\n\nimport Stage from './stage'\nimport Viewer from '../viewer/viewer'\nimport Stats from '../viewer/stats'\nimport AnimationControls from '../controls/animation-controls'\n\nclass AnimationBehavior {\n viewer: Viewer\n animationControls: AnimationControls\n\n constructor (readonly stage: Stage) {\n this.viewer = stage.viewer\n this.animationControls = stage.animationControls\n\n this.viewer.signals.ticked.add(this._onTick, this)\n }\n\n _onTick (stats: Stats) {\n this.animationControls.run(stats)\n }\n\n dispose () {\n this.viewer.signals.ticked.remove(this._onTick, this)\n }\n}\n\nexport default AnimationBehavior\n","/**\n * @file Key Behavior\n * @author Alexander Rose \n * @private\n */\n\nimport { SupportsPassiveEventHandler } from '../globals'\nimport Stage from './stage'\nimport Viewer from '../viewer/viewer'\nimport KeyControls from '../controls/key-controls'\n\nconst passive = SupportsPassiveEventHandler ? { passive: true } : false\n\nclass KeyBehavior {\n viewer: Viewer\n controls: KeyControls\n domElement: HTMLCanvasElement\n\n /**\n * @param {Stage} stage - the stage object\n */\n constructor (readonly stage: Stage) {\n this.stage = stage\n this.controls = stage.keyControls\n this.domElement = stage.viewer.renderer.domElement\n\n // ensure the domElement is focusable\n this.domElement.setAttribute('tabIndex', '-1')\n this.domElement.style.outline = 'none'\n\n this._focusDomElement = this._focusDomElement.bind(this)\n this._onKeydown = this._onKeydown.bind(this)\n this._onKeyup = this._onKeyup.bind(this)\n this._onKeypress = this._onKeypress.bind(this)\n\n this.domElement.addEventListener('mousedown', this._focusDomElement)\n this.domElement.addEventListener('touchstart', this._focusDomElement, passive as any) // TODO\n this.domElement.addEventListener('keydown', this._onKeydown)\n this.domElement.addEventListener('keyup', this._onKeyup)\n this.domElement.addEventListener('keypress', this._onKeypress)\n }\n\n /**\n * handle key down\n * @param {Event} event - key event\n * @return {undefined}\n */\n _onKeydown (/* event */) {\n // console.log( \"down\", event.keyCode, String.fromCharCode( event.keyCode ) );\n }\n\n /**\n * handle key up\n * @param {Event} event - key event\n * @return {undefined}\n */\n _onKeyup (/* event */) {\n // console.log( \"up\", event.keyCode, String.fromCharCode( event.keyCode ) );\n }\n\n /**\n * handle key press\n * @param {Event} event - key event\n * @return {undefined}\n */\n _onKeypress (event: KeyboardEvent) {\n // console.log( \"press\", event.keyCode, String.fromCharCode( event.keyCode ) );\n let pressedKey: string;\n if (\"key\" in KeyboardEvent.prototype) {\n pressedKey = event.key;\n // some mobile browsers don't support this attribute\n } else {\n pressedKey = String.fromCharCode(event.which || event.keyCode);\n }\n this.controls.run(pressedKey);\n }\n\n _focusDomElement () {\n this.domElement.focus()\n }\n\n dispose () {\n this.domElement.removeEventListener('mousedown', this._focusDomElement)\n this.domElement.removeEventListener('touchstart', this._focusDomElement, passive as any) // TODO\n this.domElement.removeEventListener('keydown', this._onKeypress)\n this.domElement.removeEventListener('keyup', this._onKeypress)\n this.domElement.removeEventListener('keypress', this._onKeypress)\n }\n}\n\nexport default KeyBehavior\n","/**\n * @file Annotation\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector2, Vector3 } from 'three'\n\nimport { defaults } from '../utils'\nimport { smoothstep } from '../math/math-utils'\nimport Stage from '../stage/stage'\nimport Viewer from '../viewer/viewer'\nimport Component from './component'\n\nexport interface AnnotationParams {\n offsetX?: number\n offsetY?: number\n visible?: boolean\n}\n\n/**\n * Annotation HTML element floating on top of a position rendered in 3d\n */\nexport default class Annotation {\n offsetX: number\n offsetY: number\n visible: boolean\n\n stage: Stage\n viewer: Viewer\n element: HTMLElement\n\n private _viewerPosition: Vector3\n private _canvasPosition: Vector2\n private _cameraPosition: Vector3\n private _clientRect: ClientRect\n\n /**\n * @param {Component} component - the associated component\n * @param {Vector3} position - position in 3d\n * @param {String|Element} content - HTML content\n * @param {Object} [params] - parameters\n * @param {Integer} params.offsetX - 2d offset in x direction\n * @param {Integer} params.offsetY - 2d offset in y direction\n * @param {Boolean} params.visible - visibility flag\n */\n constructor (readonly component: Component, readonly position: Vector3, content: string|HTMLElement, params: AnnotationParams = {}) {\n this.offsetX = defaults(params.offsetX, 0)\n this.offsetY = defaults(params.offsetY, 0)\n this.visible = defaults(params.visible, true)\n\n this.stage = component.stage\n this.viewer = component.stage.viewer\n\n this._viewerPosition = new Vector3()\n this._updateViewerPosition()\n this._canvasPosition = new Vector2()\n this._cameraPosition = new Vector3()\n\n this.element = document.createElement('div')\n Object.assign(this.element.style, {\n display: 'block',\n position: 'absolute',\n pointerEvents: 'none',\n whiteSpace: 'nowrap',\n left: '-10000px'\n })\n\n this.viewer.wrapper.appendChild(this.element)\n this.setContent(content)\n this.updateVisibility()\n this.viewer.signals.rendered.add(this._update, this)\n this.component.signals.matrixChanged.add(this._updateViewerPosition, this)\n }\n\n /**\n * Set HTML content of the annotation\n * @param {String|Element} value - HTML content\n * @return {undefined}\n */\n setContent (value: string|HTMLElement) {\n const displayValue = this.element.style.display\n if (displayValue === 'none') {\n this.element.style.left = '-10000px'\n this.element.style.display = 'block'\n }\n\n if (value instanceof HTMLElement) {\n this.element.appendChild(value)\n } else {\n const content = document.createElement('div')\n content.innerText = value\n Object.assign(content.style, {\n backgroundColor: 'rgba( 0, 0, 0, 0.6 )',\n color: 'lightgrey',\n padding: '8px',\n fontFamily: 'sans-serif',\n })\n this.element.appendChild(content)\n }\n\n this._clientRect = this.element.getBoundingClientRect()\n\n if (displayValue === 'none') {\n this.element.style.display = displayValue\n }\n }\n\n /**\n * Set visibility of the annotation\n * @param {Boolean} value - visibility flag\n * @return {undefined}\n */\n setVisibility (value: boolean) {\n this.visible = value\n this.updateVisibility()\n }\n\n getVisibility () {\n return this.visible && this.component.parameters.visible\n }\n\n updateVisibility () {\n this.element.style.display = this.getVisibility() ? 'block' : 'none'\n }\n\n _updateViewerPosition () {\n this._viewerPosition\n .copy(this.position)\n .applyMatrix4(this.component.matrix)\n }\n\n _update () {\n if (!this.getVisibility()) return\n\n const s = this.element.style\n const cp = this._canvasPosition\n const vp = this._viewerPosition\n const cr = this._clientRect\n\n this._cameraPosition.copy(vp)\n .add(this.viewer.translationGroup.position)\n .applyMatrix4(this.viewer.rotationGroup.matrix)\n .sub(this.viewer.camera.position)\n\n if (this._cameraPosition.z < 0) {\n s.display = 'none'\n return\n } else {\n s.display = 'block'\n }\n\n const depth = this._cameraPosition.length()\n const fog = this.viewer.scene.fog as any // TODO\n\n s.opacity = (1 - smoothstep(fog.near, fog.far, depth)).toString()\n s.zIndex = (Math.round((fog.far - depth) * 100)).toString()\n\n this.stage.viewerControls.getPositionOnCanvas(vp, cp)\n\n s.bottom = (this.offsetX + cp.y + cr.height / 2) + 'px'\n s.left = (this.offsetY + cp.x - cr.width / 2) + 'px'\n }\n\n /**\n * Safely remove the annotation\n * @return {undefined}\n */\n dispose () {\n this.viewer.wrapper.removeChild(this.element)\n this.viewer.signals.ticked.remove(this._update, this)\n this.component.signals.matrixChanged.remove(this._updateViewerPosition, this)\n }\n}","/**\n * @file Component Controls\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Matrix4, Quaternion } from 'three'\nimport * as signalsWrapper from 'signals'\n\nimport { ensureVector3 } from '../utils'\nimport Component from '../component/component'\nimport Stage from '../stage/stage'\nimport Viewer from '../viewer/viewer'\n\nconst tmpRotateMatrix = new Matrix4()\nconst tmpRotateVector = new Vector3()\nconst tmpRotateQuaternion = new Quaternion()\n\n/**\n * Component controls\n */\nclass ComponentControls {\n signals = {\n changed: new signalsWrapper.Signal()\n }\n\n stage: Stage\n viewer: Viewer\n\n /**\n * @param {Component} component - the component object\n */\n constructor (readonly component: Component) {\n this.stage = component.stage\n this.viewer = component.stage.viewer\n }\n\n /**\n * component center position\n * @type {Vector3}\n */\n get position () {\n return this.component.position\n }\n\n /**\n * component rotation\n * @type {Quaternion}\n */\n get rotation () {\n return this.component.quaternion\n }\n\n /**\n * Trigger render and emit changed event\n * @emits {ComponentControls.signals.changed}\n * @return {undefined}\n */\n changed () {\n this.component.updateMatrix()\n this.viewer.requestRender()\n this.signals.changed.dispatch()\n }\n\n /**\n * spin component on axis\n * @param {Vector3|Array} axis - rotation axis\n * @param {Number} angle - amount to spin\n * @return {undefined}\n */\n spin (axis: Vector3, angle: number) {\n tmpRotateMatrix.copy(this.viewer.rotationGroup.matrix).invert()\n tmpRotateVector\n .copy(ensureVector3(axis)).applyMatrix4(tmpRotateMatrix)\n\n tmpRotateMatrix.extractRotation(this.component.transform)\n tmpRotateMatrix.premultiply(this.viewer.rotationGroup.matrix)\n tmpRotateMatrix.invert()\n\n tmpRotateVector.copy(ensureVector3(axis))\n tmpRotateVector.applyMatrix4(tmpRotateMatrix)\n tmpRotateMatrix.makeRotationAxis(tmpRotateVector, angle)\n tmpRotateQuaternion.setFromRotationMatrix(tmpRotateMatrix)\n\n this.component.quaternion.premultiply(tmpRotateQuaternion)\n this.changed()\n }\n}\n\nexport default ComponentControls\n","/**\n * @file Radius Factory\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport { NucleicBackboneAtoms } from '../structure/structure-constants'\nimport AtomProxy from '../proxy/atom-proxy'\n\nexport const RadiusFactoryTypes = {\n '': '',\n 'vdw': 'by vdW radius',\n 'covalent': 'by covalent radius',\n 'sstruc': 'by secondary structure',\n 'bfactor': 'by bfactor',\n 'size': 'size',\n 'data': 'data',\n 'explicit' : 'explicit'\n}\nexport type RadiusType = keyof typeof RadiusFactoryTypes\n\nexport interface RadiusParams {\n type?: RadiusType\n scale?: number\n size?: number\n data?: { [k: number]: number }\n}\n\nclass RadiusFactory {\n max = 10\n\n static types = RadiusFactoryTypes\n\n readonly type: RadiusType\n readonly scale: number\n readonly size: number\n readonly data: { [k: number]: number }\n\n constructor (params: RadiusParams = {}) {\n this.type = defaults(params.type, 'size')\n this.scale = defaults(params.scale, 1)\n this.size = defaults(params.size, 1)\n this.data = defaults(params.data, {})\n }\n\n atomRadius (a: AtomProxy) {\n let r\n\n switch (this.type) {\n case 'vdw':\n r = a.vdw\n break\n\n case 'covalent':\n r = a.covalent\n break\n\n case 'bfactor':\n r = a.bfactor || 1.0\n break\n\n case 'sstruc':\n const sstruc = a.sstruc\n if (sstruc === 'h') {\n r = 0.25\n } else if (sstruc === 'g') {\n r = 0.25\n } else if (sstruc === 'i') {\n r = 0.25\n } else if (sstruc === 'e') {\n r = 0.25\n } else if (sstruc === 'b') {\n r = 0.25\n } else if (NucleicBackboneAtoms.includes(a.atomname)) {\n r = 0.4\n } else {\n r = 0.1\n }\n break\n\n case 'data':\n r = defaults(this.data[ a.index ], 1.0)\n break\n\n case 'explicit':\n // defaults is inappropriate as AtomProxy.radius returns\n // null for missing radii\n r = a.radius\n if (r === null) r = this.size\n break\n\n default:\n r = this.size\n break\n }\n\n return Math.min(r * this.scale, this.max)\n }\n\n}\n\nexport default RadiusFactory\n","/**\n * @file Principal Axes\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Matrix4, Quaternion } from 'three'\n\nimport {\n Matrix, meanRows, subRows, transpose, multiplyABt, svd\n} from './matrix-utils'\nimport { projectPointOnVector } from './vector-utils'\nimport Structure from '../structure/structure'\nimport AtomProxy from '../proxy/atom-proxy'\n\nconst negateVector = new Vector3(-1, -1, -1)\nconst tmpMatrix = new Matrix4()\n\n/**\n * Principal axes\n */\nclass PrincipalAxes {\n begA: Vector3\n endA: Vector3\n begB: Vector3\n endB: Vector3\n begC: Vector3\n endC: Vector3\n\n center: Vector3\n\n vecA: Vector3\n vecB: Vector3\n vecC: Vector3\n\n normVecA: Vector3\n normVecB: Vector3\n normVecC: Vector3\n\n /**\n * @param {Matrix} points - 3 by N matrix\n */\n constructor (points: Matrix) {\n // console.time( \"PrincipalAxes\" );\n\n const n = points.rows\n const n3 = n / 3\n const pointsT = new Matrix(n, 3)\n const A = new Matrix(3, 3)\n const W = new Matrix(1, 3)\n const U = new Matrix(3, 3)\n const V = new Matrix(3, 3)\n\n // calculate\n const mean = meanRows(points)\n subRows(points, mean)\n transpose(pointsT, points)\n multiplyABt(A, pointsT, pointsT)\n svd(A, W, U, V)\n\n // console.log( points, pointsT, mean )\n // console.log( n, A, W, U, V );\n\n // center\n const vm = new Vector3(mean[0], mean[1], mean[2])\n\n // normalized\n const van = new Vector3(U.data[0], U.data[3], U.data[6])\n const vbn = new Vector3(U.data[1], U.data[4], U.data[7])\n const vcn = new Vector3(U.data[2], U.data[5], U.data[8])\n\n // scaled\n const va = van.clone().multiplyScalar(Math.sqrt(W.data[0] / n3))\n const vb = vbn.clone().multiplyScalar(Math.sqrt(W.data[1] / n3))\n const vc = vcn.clone().multiplyScalar(Math.sqrt(W.data[2] / n3))\n\n // points\n this.begA = vm.clone().sub(va)\n this.endA = vm.clone().add(va)\n this.begB = vm.clone().sub(vb)\n this.endB = vm.clone().add(vb)\n this.begC = vm.clone().sub(vc)\n this.endC = vm.clone().add(vc)\n\n //\n\n this.center = vm\n\n this.vecA = va\n this.vecB = vb\n this.vecC = vc\n\n this.normVecA = van\n this.normVecB = vbn\n this.normVecC = vcn\n\n // console.timeEnd( \"PrincipalAxes\" );\n }\n\n /**\n * Get the basis matrix descriping the axes\n * @param {Matrix4} [optionalTarget] - target object\n * @return {Matrix4} the basis\n */\n getBasisMatrix (optionalTarget = new Matrix4()) {\n const basis = optionalTarget\n\n basis.makeBasis(this.normVecB, this.normVecA, this.normVecC)\n if (basis.determinant() < 0) {\n basis.scale(negateVector)\n }\n\n return basis\n }\n\n /**\n * Get a quaternion descriping the axes rotation\n * @param {Quaternion} [optionalTarget] - target object\n * @return {Quaternion} the rotation\n */\n getRotationQuaternion (optionalTarget = new Quaternion()) {\n const q = optionalTarget\n q.setFromRotationMatrix(this.getBasisMatrix(tmpMatrix))\n\n return q.invert()\n }\n\n /**\n * Get the scale/length for each dimension for a box around the axes\n * to enclose the atoms of a structure\n * @param {Structure|StructureView} structure - the structure\n * @return {{d1a: Number, d2a: Number, d3a: Number, d1b: Number, d2b: Number, d3b: Number}} scale\n */\n getProjectedScaleForAtoms (structure: Structure) {\n let d1a = -Infinity\n let d1b = -Infinity\n let d2a = -Infinity\n let d2b = -Infinity\n let d3a = -Infinity\n let d3b = -Infinity\n\n const p = new Vector3()\n const t = new Vector3()\n\n const center = this.center\n const ax1 = this.normVecA\n const ax2 = this.normVecB\n const ax3 = this.normVecC\n\n structure.eachAtom(function (ap: AtomProxy) {\n projectPointOnVector(p.copy(ap as any), ax1, center) // TODO\n const dp1 = t.subVectors(p, center).normalize().dot(ax1)\n const dt1 = p.distanceTo(center)\n if (dp1 > 0) {\n if (dt1 > d1a) d1a = dt1\n } else {\n if (dt1 > d1b) d1b = dt1\n }\n\n projectPointOnVector(p.copy(ap as any), ax2, center)\n const dp2 = t.subVectors(p, center).normalize().dot(ax2)\n const dt2 = p.distanceTo(center)\n if (dp2 > 0) {\n if (dt2 > d2a) d2a = dt2\n } else {\n if (dt2 > d2b) d2b = dt2\n }\n\n projectPointOnVector(p.copy(ap as any), ax3, center)\n const dp3 = t.subVectors(p, center).normalize().dot(ax3)\n const dt3 = p.distanceTo(center)\n if (dp3 > 0) {\n if (dt3 > d3a) d3a = dt3\n } else {\n if (dt3 > d3b) d3b = dt3\n }\n })\n\n return {\n d1a: d1a,\n d2a: d2a,\n d3a: d3a,\n d1b: -d1b,\n d2b: -d2b,\n d3b: -d3b\n }\n }\n}\n\nexport default PrincipalAxes\n","/**\n * @file Filtered Volume\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport Volume from './volume'\nimport { Box3, Matrix4, Matrix3, Vector3 } from 'three';\n\nclass FilteredVolume {\n volume: Volume\n data: Float32Array\n position: Float32Array\n atomindex: Int32Array\n _filterHash: string\n _dataBuffer: ArrayBuffer\n _positionBuffer: ArrayBuffer\n _atomindexBuffer: ArrayBuffer\n getValueForSigma: typeof Volume.prototype.getValueForSigma\n getSigmaForValue: typeof Volume.prototype.getSigmaForValue\n getDataAtomindex: typeof Volume.prototype.getDataAtomindex\n getDataPosition: typeof Volume.prototype.getDataPosition\n getDataColor: typeof Volume.prototype.getDataColor\n getDataPicking: typeof Volume.prototype.getDataPicking\n getDataSize: typeof Volume.prototype.getDataSize\n\n\n constructor (volume: Volume, minValue?: number, maxValue?: number, outside?: boolean) {\n this.volume = volume\n this.setFilter(minValue, maxValue, outside)\n }\n\n get header () { return this.volume.header }\n get matrix (): Matrix4 { return this.volume.matrix }\n get normalMatrix (): Matrix3 { return this.volume.normalMatrix }\n get inverseMatrix (): Matrix4 { return this.volume.inverseMatrix }\n get center (): Vector3 { return this.volume.center }\n get boundingBox (): Box3 { return this.volume.boundingBox }\n get min () { return this.volume.min }\n get max () { return this.volume.max }\n get mean () { return this.volume.mean }\n get rms () { return this.volume.rms }\n\n _getFilterHash (minValue: number, maxValue: number, outside: boolean) {\n return JSON.stringify([ minValue, maxValue, outside ])\n }\n\n setFilter (minValue: number|undefined, maxValue: number|undefined, outside: boolean|undefined) {\n if (isNaN(minValue) && this.header) {\n minValue = this.header.DMEAN + 2.0 * this.header.ARMS\n }\n\n minValue = (minValue !== undefined && !isNaN(minValue)) ? minValue : -Infinity\n maxValue = defaults(maxValue, Infinity) as number\n outside = defaults(outside, false) as boolean\n\n const data = this.volume.data\n const position = this.volume.position\n const atomindex = this.volume.atomindex\n\n const filterHash = this._getFilterHash(minValue, maxValue, outside)\n\n if (filterHash === this._filterHash) {\n // already filtered\n return\n } else if (minValue === -Infinity && maxValue === Infinity) {\n this.data = data\n this.position = position\n this.atomindex = atomindex!\n } else {\n const n = data.length\n\n if (!this._dataBuffer) {\n // ArrayBuffer for re-use as Float32Array backend\n\n this._dataBuffer = new ArrayBuffer(n * 4)\n this._positionBuffer = new ArrayBuffer(n * 3 * 4)\n if (atomindex) this._atomindexBuffer = new ArrayBuffer(n * 4)\n }\n\n const filteredData = new Float32Array(this._dataBuffer)\n const filteredPosition = new Float32Array(this._positionBuffer)\n let filteredAtomindex\n if (atomindex) filteredAtomindex = new Uint32Array(this._atomindexBuffer)\n\n let j = 0\n\n for (let i = 0; i < n; ++i) {\n const i3 = i * 3\n const v = data[ i ]\n\n if ((!outside && v >= minValue && v <= maxValue) ||\n (outside && (v < minValue || v > maxValue))\n ) {\n const j3 = j * 3\n\n filteredData[ j ] = v\n\n filteredPosition[ j3 + 0 ] = position[ i3 + 0 ]\n filteredPosition[ j3 + 1 ] = position[ i3 + 1 ]\n filteredPosition[ j3 + 2 ] = position[ i3 + 2 ]\n\n if (atomindex && filteredAtomindex) filteredAtomindex[ j ] = atomindex[ i ]\n\n j += 1\n }\n }\n\n // set views\n\n this.data = new Float32Array(this._dataBuffer, 0, j)\n this.position = new Float32Array(this._positionBuffer, 0, j * 3)\n if (atomindex) this.atomindex = new Int32Array(this._atomindexBuffer, 0, j)\n }\n\n this._filterHash = filterHash\n }\n}\n\nFilteredVolume.prototype.getValueForSigma = Volume.prototype.getValueForSigma\nFilteredVolume.prototype.getSigmaForValue = Volume.prototype.getSigmaForValue\n\nFilteredVolume.prototype.getDataAtomindex = Volume.prototype.getDataAtomindex\nFilteredVolume.prototype.getDataPosition = Volume.prototype.getDataPosition\nFilteredVolume.prototype.getDataColor = Volume.prototype.getDataColor\nFilteredVolume.prototype.getDataPicking = Volume.prototype.getDataPicking\nFilteredVolume.prototype.getDataSize = Volume.prototype.getDataSize\n\nexport default FilteredVolume\n","/**\n * @file Bond Hash\n * @author Alexander Rose \n * @private\n */\n\nimport BondStore from './bond-store'\nimport { createAdjacencyList } from '../utils/adjacency-list'\n\nclass BondHash {\n countArray: Uint8Array\n offsetArray: Int32Array\n indexArray: Int32Array\n\n constructor (bondStore: BondStore, atomCount: number) {\n const al = createAdjacencyList({\n nodeArray1: bondStore.atomIndex1,\n nodeArray2: bondStore.atomIndex2,\n edgeCount: bondStore.count,\n nodeCount: atomCount\n })\n\n this.countArray = al.countArray\n this.offsetArray = al.offsetArray\n this.indexArray = al.indexArray\n }\n}\n\nexport default BondHash\n","/**\n * @file Bond Store\n * @author Alexander Rose \n * @private\n */\n\nimport Store, { StoreField } from './store'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Bond store\n */\nexport default class BondStore extends Store {\n atomIndex1: Uint32Array\n atomIndex2: Uint32Array\n bondOrder: Uint8Array\n\n get _defaultFields () {\n return [\n [ 'atomIndex1', 1, 'int32' ],\n [ 'atomIndex2', 1, 'int32' ],\n [ 'bondOrder', 1, 'int8' ]\n ] as StoreField[]\n }\n\n addBond (atom1: AtomProxy, atom2: AtomProxy, bondOrder?: number) {\n this.growIfFull()\n\n const i = this.count\n const ai1 = atom1.index\n const ai2 = atom2.index\n\n if (ai1 < ai2) {\n this.atomIndex1[ i ] = ai1\n this.atomIndex2[ i ] = ai2\n } else {\n this.atomIndex2[ i ] = ai1\n this.atomIndex1[ i ] = ai2\n }\n if (bondOrder) this.bondOrder[ i ] = bondOrder\n\n this.count += 1\n }\n\n addBondIfConnected (atom1: AtomProxy, atom2: AtomProxy, bondOrder?: number) {\n if (atom1.connectedTo(atom2)) {\n this.addBond(atom1, atom2, bondOrder)\n return true\n }\n\n return false\n }\n}","/**\n * @file Atom Store\n * @author Alexander Rose \n * @private\n */\n\nimport Store, { StoreField } from './store'\n\n/**\n * Atom store\n */\nexport default class AtomStore extends Store {\n residueIndex: Uint32Array\n atomTypeId: Uint16Array\n\n x: Float32Array\n y: Float32Array\n z: Float32Array\n serial: Int32Array\n bfactor: Float32Array\n altloc: Uint8Array\n occupancy: Float32Array\n\n partialCharge?: Float32Array\n formalCharge?: Int8Array\n\n get _defaultFields () {\n return [\n [ 'residueIndex', 1, 'uint32' ],\n [ 'atomTypeId', 1, 'uint16' ],\n\n [ 'x', 1, 'float32' ],\n [ 'y', 1, 'float32' ],\n [ 'z', 1, 'float32' ],\n [ 'serial', 1, 'int32' ],\n [ 'bfactor', 1, 'float32' ],\n [ 'altloc', 1, 'uint8' ],\n [ 'occupancy', 1, 'float32' ]\n ] as StoreField[]\n }\n\n setAltloc (i: number, str: string) {\n this.altloc[ i ] = str.charCodeAt(0)\n }\n\n getAltloc (i: number) {\n const code = this.altloc[ i ]\n return code ? String.fromCharCode(code) : ''\n }\n}","/**\n * @file Residue Store\n * @author Alexander Rose \n * @private\n */\n\nimport Store, { StoreField } from './store'\n\n/**\n * Residue store\n */\nexport default class ResidueStore extends Store {\n chainIndex: Uint32Array\n atomOffset: Uint32Array\n atomCount: Uint32Array\n residueTypeId: Uint16Array\n\n resno: Uint32Array\n sstruc: Uint8Array\n inscode: Uint8Array\n\n get _defaultFields () {\n return [\n [ 'chainIndex', 1, 'uint32' ],\n [ 'atomOffset', 1, 'uint32' ],\n [ 'atomCount', 1, 'uint32' ],\n [ 'residueTypeId', 1, 'uint16' ],\n\n [ 'resno', 1, 'int32' ],\n [ 'sstruc', 1, 'uint8' ],\n [ 'inscode', 1, 'uint8' ]\n ] as StoreField[]\n }\n\n setSstruc (i: number, str: string) {\n this.sstruc[ i ] = str.charCodeAt(0)\n }\n\n getSstruc (i: number) {\n const code = this.sstruc[ i ]\n return code ? String.fromCharCode(code) : ''\n }\n\n setInscode (i: number, str: string) {\n this.inscode[ i ] = str.charCodeAt(0)\n }\n\n getInscode (i: number) {\n const code = this.inscode[ i ]\n return code ? String.fromCharCode(code) : ''\n }\n}","/**\n * @file Chain Store\n * @author Alexander Rose \n * @private\n */\n\nimport Store, { StoreField } from './store'\n\n/**\n * Chain store\n */\nexport default class ChainStore extends Store {\n entityIndex: Uint16Array\n modelIndex: Uint16Array\n residueOffset: Uint32Array\n residueCount: Uint32Array\n\n chainname: Uint8Array\n chainid: Uint8Array\n\n get _defaultFields () {\n return [\n [ 'entityIndex', 1, 'uint16' ],\n [ 'modelIndex', 1, 'uint16' ],\n [ 'residueOffset', 1, 'uint32' ],\n [ 'residueCount', 1, 'uint32' ],\n\n [ 'chainname', 4, 'uint8' ],\n [ 'chainid', 4, 'uint8' ]\n ] as StoreField[]\n }\n\n setChainname (i: number, str: string) {\n const j = 4 * i\n this.chainname[ j ] = str.charCodeAt(0)\n this.chainname[ j + 1 ] = str.charCodeAt(1)\n this.chainname[ j + 2 ] = str.charCodeAt(2)\n this.chainname[ j + 3 ] = str.charCodeAt(3)\n }\n\n getChainname (i: number) {\n let chainname = ''\n for (let k = 0; k < 4; ++k) {\n const code = this.chainname[ 4 * i + k ]\n if (code) {\n chainname += String.fromCharCode(code)\n } else {\n break\n }\n }\n return chainname\n }\n\n setChainid (i: number, str: string) {\n const j = 4 * i\n this.chainid[ j ] = str.charCodeAt(0)\n this.chainid[ j + 1 ] = str.charCodeAt(1)\n this.chainid[ j + 2 ] = str.charCodeAt(2)\n this.chainid[ j + 3 ] = str.charCodeAt(3)\n }\n\n getChainid (i: number) {\n let chainid = ''\n for (let k = 0; k < 4; ++k) {\n const code = this.chainid[ 4 * i + k ]\n if (code) {\n chainid += String.fromCharCode(code)\n } else {\n break\n }\n }\n return chainid\n }\n}\n","/**\n * @file Model Store\n * @author Alexander Rose \n * @private\n */\n\nimport Store, { StoreField } from './store'\n\n/**\n * Model store\n */\nexport default class ModelStore extends Store {\n\tchainOffset: Uint32Array\n\tchainCount: Uint32Array\n\n get _defaultFields () {\n return [\n [ 'chainOffset', 1, 'uint32' ],\n [ 'chainCount', 1, 'uint32' ]\n ] as StoreField[]\n }\n}","/**\n * @file Helixorient\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { ColormakerRegistry } from '../globals'\nimport { ColormakerParameters } from '../color/colormaker'\nimport { AtomPicker } from '../utils/picker'\nimport RadiusFactory, { RadiusParams } from '../utils/radius-factory'\nimport { copyArray } from '../math/array-utils'\nimport { projectPointOnVector } from '../math/vector-utils'\nimport Polymer from '../proxy/polymer'\n\nexport interface HelixIterator {\n size: number\n next: () => Vector3\n get: (idx: number) => Vector3\n reset: () => void\n}\n\nexport interface HelixPosition {\n center: Float32Array\n axis: Float32Array\n bending: Float32Array\n radius: Float32Array\n rise: Float32Array\n twist: Float32Array\n resdir: Float32Array\n}\n\nclass Helixorient {\n size: number\n\n constructor (readonly polymer: Polymer) {\n this.size = polymer.residueCount\n }\n\n getCenterIterator (smooth = 0): HelixIterator {\n const center = this.getPosition().center\n const size = center.length / 3\n\n let i = 0\n let j = -1\n\n const cache = [\n new Vector3(),\n new Vector3(),\n new Vector3(),\n new Vector3()\n ]\n\n function next (this: HelixIterator) {\n const vector = this.get(j)\n j += 1\n return vector\n }\n\n function get (idx: number) {\n idx = Math.min(size - 1, Math.max(0, idx))\n const v = cache[ i % 4 ]\n const idx3 = 3 * idx\n v.fromArray(center as any, idx3) // TODO\n if (smooth) {\n const w = Math.min(smooth, idx, size - idx - 1)\n for (let k = 1; k <= w; ++k) {\n const l = k * 3\n const t = (w + 1 - k) / (w + 1)\n v.x += t * center[ idx3 - l + 0 ] + t * center[ idx3 + l + 0 ]\n v.y += t * center[ idx3 - l + 1 ] + t * center[ idx3 + l + 1 ]\n v.z += t * center[ idx3 - l + 2 ] + t * center[ idx3 + l + 2 ]\n }\n v.x /= w + 1\n v.y /= w + 1\n v.z /= w + 1\n }\n i += 1\n return v\n }\n\n function reset () {\n i = 0\n j = -1\n }\n\n return { size, next, get, reset }\n }\n\n getColor (params: { scheme: string } & ColormakerParameters) {\n const polymer = this.polymer\n const structure = polymer.structure\n const n = polymer.residueCount\n const residueIndexStart = polymer.residueIndexStart\n\n const col = new Float32Array(n * 3)\n\n const p = params || {}\n p.structure = structure\n\n const colormaker = ColormakerRegistry.getScheme(p)\n\n const rp = structure.getResidueProxy()\n const ap = structure.getAtomProxy()\n\n for (let i = 0; i < n; ++i) {\n rp.index = residueIndexStart + i\n ap.index = rp.traceAtomIndex\n\n colormaker.atomColorToArray(ap, col, i * 3)\n }\n\n return {\n 'color': col\n }\n }\n\n getPicking () {\n const polymer = this.polymer\n const structure = polymer.structure\n const n = polymer.residueCount\n const residueIndexStart = polymer.residueIndexStart\n\n const pick = new Float32Array(n)\n const rp = structure.getResidueProxy()\n\n for (let i = 0; i < n; ++i) {\n rp.index = residueIndexStart + i\n pick[ i ] = rp.traceAtomIndex\n }\n\n return {\n 'picking': new AtomPicker(pick, structure)\n }\n }\n\n getSize (params: RadiusParams) {\n const polymer = this.polymer\n const structure = polymer.structure\n const n = polymer.residueCount\n const residueIndexStart = polymer.residueIndexStart\n\n const size = new Float32Array(n)\n const radiusFactory = new RadiusFactory(params)\n\n const rp = structure.getResidueProxy()\n const ap = structure.getAtomProxy()\n\n for (let i = 0; i < n; ++i) {\n rp.index = residueIndexStart + i\n ap.index = rp.traceAtomIndex\n size[ i ] = radiusFactory.atomRadius(ap)\n }\n\n return { size }\n }\n\n getPosition (): HelixPosition {\n const polymer = this.polymer\n const structure = polymer.structure\n const n = polymer.residueCount\n const n3 = n - 3\n\n const center = new Float32Array(3 * n)\n const axis = new Float32Array(3 * n)\n const diff = new Float32Array(n)\n const radius = new Float32Array(n)\n const rise = new Float32Array(n)\n const twist = new Float32Array(n)\n const resdir = new Float32Array(3 * n)\n\n const r12 = new Vector3()\n const r23 = new Vector3()\n const r34 = new Vector3()\n\n const diff13 = new Vector3()\n const diff24 = new Vector3()\n\n const v1 = new Vector3()\n const v2 = new Vector3()\n const vt = new Vector3()\n\n const _axis = new Vector3()\n const _prevAxis = new Vector3()\n\n const _resdir = new Vector3()\n const _center = new Vector3(0, 0, 0)\n\n const type = 'trace'\n const a1 = structure.getAtomProxy()\n const a2 = structure.getAtomProxy(polymer.getAtomIndexByType(0, type))\n const a3 = structure.getAtomProxy(polymer.getAtomIndexByType(1, type))\n const a4 = structure.getAtomProxy(polymer.getAtomIndexByType(2, type))\n\n for (let i = 0; i < n3; ++i) {\n a1.index = a2.index\n a2.index = a3.index\n a3.index = a4.index\n a4.index = polymer.getAtomIndexByType(i + 3, type)! // TODO\n\n const j = 3 * i\n\n // ported from GROMACS src/tools/gmx_helixorient.c\n\n r12.subVectors(a2 as any, a1 as any) // TODO\n r23.subVectors(a3 as any, a2 as any) // TODO\n r34.subVectors(a4 as any, a3 as any) // TODO\n\n diff13.subVectors(r12, r23)\n diff24.subVectors(r23, r34)\n\n _axis.crossVectors(diff13, diff24).normalize()\n _axis.toArray(axis as any, j) // TODO\n\n if (i > 0) {\n diff[ i ] = _axis.angleTo(_prevAxis)\n }\n\n const tmp = Math.cos(diff13.angleTo(diff24))\n twist[ i ] = 180.0 / Math.PI * Math.acos(tmp)\n\n const diff13Length = diff13.length()\n const diff24Length = diff24.length()\n\n radius[ i ] = (\n Math.sqrt(diff24Length * diff13Length) /\n // clamp, to avoid instabilities for when\n // angle between diff13 and diff24 is near 0\n Math.max(2.0, 2.0 * (1.0 - tmp))\n )\n\n rise[ i ] = Math.abs(r23.dot(_axis))\n\n //\n\n v1.copy(diff13).multiplyScalar(radius[ i ] / diff13Length)\n v2.copy(diff24).multiplyScalar(radius[ i ] / diff24Length)\n\n v1.subVectors(a2 as any, v1) // TODO\n v2.subVectors(a3 as any, v2) // TODO\n\n v1.toArray(center as any, j + 3) // TODO\n v2.toArray(center as any, j + 6) // TODO\n\n //\n\n _resdir.subVectors(a1 as any, _center) // TODO\n _resdir.toArray(resdir as any, j) // TODO\n\n _prevAxis.copy(_axis)\n _center.copy(v1)\n }\n\n //\n\n // calc axis as dir of second and third center pos\n // project first traceAtom onto axis to get first center pos\n v1.fromArray(center as any, 3) // TODO\n v2.fromArray(center as any, 6) // TODO\n _axis.subVectors(v1, v2).normalize()\n // _center.copy( res[ 0 ].getTraceAtom() );\n a1.index = polymer.getAtomIndexByType(0, type)! // TODO\n _center.copy(a1 as any) // TODO\n vt.copy(a1 as any) // TODO\n projectPointOnVector(vt, _axis, v1)\n vt.toArray(center as any, 0) // TODO\n\n // calc first resdir\n _resdir.subVectors(_center, v1)\n _resdir.toArray(resdir as any, 0) // TODO\n\n // calc axis as dir of n-1 and n-2 center pos\n // project last traceAtom onto axis to get last center pos\n v1.fromArray(center as any, 3 * n - 6) // TODO\n v2.fromArray(center as any, 3 * n - 9) // TODO\n _axis.subVectors(v1, v2).normalize()\n // _center.copy( res[ n - 1 ].getTraceAtom() );\n a1.index = polymer.getAtomIndexByType(n - 1, type)! // TODO\n _center.copy(a1 as any) // TODO\n vt.copy(a1 as any) // TODO\n projectPointOnVector(vt, _axis, v1)\n vt.toArray(center as any, 3 * n - 3) // TODO\n\n // calc last three resdir\n for (let i = n - 3; i < n; ++i) {\n v1.fromArray(center as any, 3 * i) // TODO\n // _center.copy( res[ i ].getTraceAtom() );\n a1.index = polymer.getAtomIndexByType(i, type)! // TODO\n _center.copy(a1 as any) // TODO\n\n _resdir.subVectors(_center, v1)\n _resdir.toArray(resdir as any, 3 * i) // TODO\n }\n\n // average measures to define them on the residues\n\n const resRadius = new Float32Array(n)\n const resTwist = new Float32Array(n)\n const resRise = new Float32Array(n)\n const resBending = new Float32Array(n)\n\n resRadius[ 1 ] = radius[ 0 ]\n resTwist[ 1 ] = twist[ 0 ]\n resRise[ 1 ] = radius[ 0 ]\n\n for (let i = 2; i < n - 2; ++i) {\n resRadius[ i ] = 0.5 * (radius[ i - 2 ] + radius[ i - 1 ])\n resTwist[ i ] = 0.5 * (twist[ i - 2 ] + twist[ i - 1 ])\n resRise[ i ] = 0.5 * (rise[ i - 2 ] + rise[ i - 1 ])\n\n v1.fromArray(axis as any, 3 * (i - 2)) // TODO\n v2.fromArray(axis as any, 3 * (i - 1)) // TODO\n resBending[ i ] = 180.0 / Math.PI * Math.acos(Math.cos(v1.angleTo(v2)))\n }\n\n resRadius[ n - 2 ] = radius[ n - 4 ]\n resTwist[ n - 2 ] = twist[ n - 4 ]\n resRise[ n - 2 ] = rise[ n - 4 ]\n\n // average helix axes to define them on the residues\n\n const resAxis = new Float32Array(3 * n)\n\n copyArray(axis, resAxis, 0, 0, 3)\n copyArray(axis, resAxis, 0, 3, 3)\n\n for (let i = 2; i < n - 2; ++i) {\n v1.fromArray(axis as any, 3 * (i - 2)) // TODO\n v2.fromArray(axis as any, 3 * (i - 1)) // TODO\n\n _axis.addVectors(v2, v1).multiplyScalar(0.5).normalize()\n _axis.toArray(resAxis as any, 3 * i) // TODO\n }\n\n copyArray(axis, resAxis, 3 * n - 12, 3 * n - 6, 3)\n copyArray(axis, resAxis, 3 * n - 12, 3 * n - 3, 3)\n\n return {\n center,\n axis: resAxis,\n bending: resBending,\n radius: resRadius,\n rise: resRise,\n twist: resTwist,\n resdir: resdir\n }\n }\n\n}\n\nexport default Helixorient\n","/**\n * @file Helixbundle\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { ColormakerRegistry } from '../globals'\nimport { AtomPicker } from '../utils/picker'\nimport RadiusFactory, { RadiusParams } from '../utils/radius-factory'\nimport Helixorient, { HelixPosition } from './helixorient'\nimport { calculateMeanVector3, projectPointOnVector } from '../math/vector-utils'\nimport Polymer from '../proxy/polymer'\nimport { ColormakerParameters } from '../color/colormaker';\n\nexport interface Axis {\n axis: Float32Array\n center: Float32Array\n begin: Float32Array\n end: Float32Array\n color: Float32Array\n picking: AtomPicker\n size: Float32Array\n residueOffset: number[]\n residueCount: number[]\n}\n\nclass Helixbundle {\n helixorient: Helixorient;\n position: HelixPosition;\n\n constructor (readonly polymer: Polymer) {\n\n this.helixorient = new Helixorient(polymer)\n this.position = this.helixorient.getPosition()\n }\n\n getAxis (localAngle: number, centerDist: number, ssBorder: boolean, colorParams: { scheme: string} & ColormakerParameters, radiusParams: RadiusParams): Axis {\n localAngle = localAngle || 30\n centerDist = centerDist || 2.5\n ssBorder = ssBorder === undefined ? false : ssBorder\n\n const polymer = this.polymer\n const structure = polymer.structure\n const n = polymer.residueCount\n const residueIndexStart = polymer.residueIndexStart\n\n const pos = this.position\n\n const cp = colorParams || {}\n cp.structure = structure\n\n const colormaker = ColormakerRegistry.getScheme(cp)\n\n const radiusFactory = new RadiusFactory(radiusParams)\n\n let j = 0\n let k = 0\n\n const axis: number[] = []\n const center: number[] = []\n const beg: number[] = []\n const end: number[] = []\n const col: number[] = []\n const pick = []\n const size = []\n const residueOffset = []\n const residueCount = []\n\n let tmpAxis = new Float32Array(n * 3)\n let tmpCenter = new Float32Array(n * 3)\n\n let _axis, _center\n const _beg = new Vector3()\n const _end = new Vector3()\n\n const rp1 = structure.getResidueProxy()\n const rp2 = structure.getResidueProxy()\n const ap = structure.getAtomProxy()\n\n const c1 = new Vector3()\n const c2 = new Vector3()\n\n let split = false\n\n for (let i = 0; i < n; ++i) {\n rp1.index = residueIndexStart + i\n c1.fromArray(pos.center as any, i * 3)\n\n if (i === n - 1) {\n split = true\n } else {\n rp2.index = residueIndexStart + i + 1\n c2.fromArray(pos.center as any, i * 3 + 3)\n\n if (ssBorder && rp1.sstruc !== rp2.sstruc) {\n split = true\n } else if (c1.distanceTo(c2) > centerDist) {\n split = true\n } else if (pos.bending[ i ] > localAngle) {\n split = true\n }\n }\n\n if (split) {\n if (i - j < 4) {\n j = i\n split = false\n continue\n }\n\n ap.index = rp1.traceAtomIndex\n\n // ignore first and last axis\n tmpAxis = pos.axis.subarray(j * 3 + 3, i * 3)\n tmpCenter = pos.center.subarray(j * 3, i * 3 + 3)\n\n _axis = calculateMeanVector3(tmpAxis).normalize()\n _center = calculateMeanVector3(tmpCenter)\n\n _beg.fromArray(tmpCenter as any)\n projectPointOnVector(_beg, _axis, _center)\n\n _end.fromArray(tmpCenter as any, tmpCenter.length - 3)\n projectPointOnVector(_end, _axis, _center)\n\n _axis.subVectors(_end, _beg)\n\n _axis.toArray(axis as any, k)\n _center.toArray(center as any, k)\n _beg.toArray(beg as any, k)\n _end.toArray(end as any, k)\n\n colormaker.atomColorToArray(ap, col, k)\n\n pick.push(ap.index)\n\n size.push(radiusFactory.atomRadius(ap))\n\n residueOffset.push(residueIndexStart + j)\n residueCount.push(residueIndexStart + i + 1 - j)\n\n k += 3\n j = i\n split = false\n }\n }\n\n const picking = new Float32Array(pick)\n\n return {\n axis: new Float32Array(axis),\n center: new Float32Array(center),\n begin: new Float32Array(beg),\n end: new Float32Array(end),\n color: new Float32Array(col),\n picking: new AtomPicker(picking, structure),\n size: new Float32Array(size),\n residueOffset: residueOffset,\n residueCount: residueCount\n }\n }\n}\n\nexport default Helixbundle\n","/**\n * @file Binary Heap\n * @author Alexander Rose \n * @private\n */\n\n/**\n * Binary heap implementation\n * @class\n * @author http://eloquentjavascript.net/appendix2.htm\n * @param {Function} scoreFunction - the heap scoring function\n */\nclass BinaryHeap {\n content: T[] = []\n\n constructor(readonly scoreFunction: (x: T) => number) {\n\n this.scoreFunction = scoreFunction\n }\n\n push (element: T) {\n // Add the new element to the end of the array.\n this.content.push(element)\n\n // Allow it to bubble up.\n this.bubbleUp(this.content.length - 1)\n }\n\n pop () {\n // Store the first element so we can return it later.\n const result = this.content[ 0 ]\n\n // Get the element at the end of the array.\n const end = this.content.pop()\n\n // If there are any elements left, put the end element at the\n // start, and let it sink down.\n if (end && this.content.length > 0) {\n this.content[ 0 ] = end\n this.sinkDown(0)\n }\n\n return result\n }\n\n peek () {\n return this.content[ 0 ]\n }\n\n remove (element: T) {\n const len = this.content.length\n\n // To remove a value, we must search through the array to find it.\n for (let i = 0; i < len; i++) {\n if (this.content[ i ] === element) {\n // When it is found, the process seen in 'pop' is repeated\n // to fill up the hole.\n const end = this.content.pop()\n\n if (end && i !== len - 1) {\n this.content[ i ] = end\n\n if (this.scoreFunction(end) < this.scoreFunction(element)) {\n this.bubbleUp(i)\n } else {\n this.sinkDown(i)\n }\n }\n\n return\n }\n }\n\n throw new Error('Node not found.')\n }\n\n size () {\n return this.content.length\n }\n\n bubbleUp (n: number) {\n // Fetch the element that has to be moved.\n const element = this.content[ n ]\n\n // When at 0, an element can not go up any further.\n while (n > 0) {\n // Compute the parent element's index, and fetch it.\n const parentN = Math.floor((n + 1) / 2) - 1\n const parent = this.content[ parentN ]\n\n // Swap the elements if the parent is greater.\n if (this.scoreFunction(element) < this.scoreFunction(parent)) {\n this.content[ parentN ] = element\n this.content[ n ] = parent\n\n // Update 'n' to continue at the new position.\n n = parentN\n } else {\n // Found a parent that is less, no need to move it further.\n break\n }\n }\n }\n\n sinkDown (n: number) {\n // Look up the target element and its score.\n const length = this.content.length\n const element = this.content[ n ]\n const elemScore = this.scoreFunction(element)\n\n let child1Score = 0\n let child2Score = 0\n\n while (true) {\n // Compute the indices of the child elements.\n const child2N = (n + 1) * 2\n const child1N = child2N - 1\n\n // This is used to store the new position of the element, if any.\n let swap = null\n\n // If the first child exists (is inside the array)...\n if (child1N < length) {\n // Look it up and compute its score.\n const child1 = this.content[ child1N ]\n child1Score = this.scoreFunction(child1)\n\n // If the score is less than our element's, we need to swap.\n if (child1Score < elemScore) swap = child1N\n }\n\n // Do the same checks for the other child.\n if (child2N < length) {\n const child2 = this.content[ child2N ]\n child2Score = this.scoreFunction(child2)\n\n if (child2Score < (swap === null ? elemScore : child1Score)) swap = child2N\n }\n\n // If the element needs to be moved, swap it, and continue.\n if (swap !== null) {\n this.content[ n ] = this.content[ swap ]\n this.content[ swap ] = element\n n = swap\n } else {\n // Otherwise, we are done.\n break\n }\n }\n }\n\n}\n\nexport default BinaryHeap\n","/**\n * @file Kdtree\n * @author Alexander Rose \n * @private\n */\n\nimport { NumberArray } from '../types'\nimport BinaryHeap from './binary-heap'\n\n/**\n * Kdtree\n * @class\n * @author Alexander Rose , 2016\n * @author Roman Bolzern , 2013\n * @author I4DS http://www.fhnw.ch/i4ds, 2013\n * @license MIT License \n * @description\n * k-d Tree for typed arrays of 3d points (e.g. for Float32Array), in-place\n * provides fast nearest neighbour search\n *\n * Based on https://github.com/ubilabs/kd-tree-javascript by Ubilabs\n *\n * Further information (including mathematical properties)\n * http://en.wikipedia.org/wiki/Binary_tree\n * http://en.wikipedia.org/wiki/K-d_tree\n *\n * @example\n * points: [x, y, z, x, y, z, x, y, z, ...]\n * metric: function(a, b){\n * return Math.pow(a[0]-b[0], 2) + Math.pow(a[1]-b[1], 2) + Math.pow(a[2]-b[2], 2);\n * }\n *\n * @param {Float32Array} points - points\n * @param {Function} metric - metric\n */\nclass Kdtree {\n indices: Uint32Array\n nodes: Int32Array\n rootIndex: number\n\n maxDepth = 0\n currentNode = 0\n\n constructor(readonly points: NumberArray, readonly metric: (a: NumberArray, b: NumberArray) => number) {\n const n = points.length / 3\n\n const indices = new Uint32Array(n)\n for (let i = 0; i < n; ++i) {\n indices[ i ] = i\n }\n this.indices = indices\n this.nodes = new Int32Array(n * 4)\n this.rootIndex = this.buildTree(0, -1, 0, n)\n }\n\n buildTree (depth: number, parent: number, arrBegin: number, arrEnd: number) {\n if (depth > this.maxDepth) this.maxDepth = depth\n\n const plength = arrEnd - arrBegin\n if (plength === 0) {\n return -1\n }\n\n const nodeIndex = this.currentNode * 4\n const nodes = this.nodes\n\n this.currentNode += 1\n if (plength === 1) {\n nodes[ nodeIndex ] = arrBegin\n nodes[ nodeIndex + 1 ] = -1\n nodes[ nodeIndex + 2 ] = -1\n nodes[ nodeIndex + 3 ] = parent\n return nodeIndex\n }\n // if(plength <= 32){\n // return nodeIndex;\n // }\n\n const indices = this.indices\n const points = this.points\n\n const arrMedian = arrBegin + Math.floor(plength / 2)\n const currentDim = depth % 3\n\n // inlined quickselect function\n let j, tmp, pivotIndex, pivotValue, storeIndex\n let left = arrBegin\n let right = arrEnd - 1\n while (right > left) {\n pivotIndex = (left + right) >> 1\n pivotValue = points[ indices[ pivotIndex ] * 3 + currentDim ]\n // swap( pivotIndex, right );\n tmp = indices[ pivotIndex ]\n indices[ pivotIndex ] = indices[ right ]\n indices[ right ] = tmp\n storeIndex = left\n for (j = left; j < right; ++j) {\n if (points[ indices[ j ] * 3 + currentDim ] < pivotValue) {\n // swap( storeIndex, j );\n tmp = indices[ storeIndex ]\n indices[ storeIndex ] = indices[ j ]\n indices[ j ] = tmp\n ++storeIndex\n }\n }\n // swap( right, storeIndex );\n tmp = indices[ right ]\n indices[ right ] = indices[ storeIndex ]\n indices[ storeIndex ] = tmp\n pivotIndex = storeIndex\n if (arrMedian === pivotIndex) {\n break\n } else if (arrMedian < pivotIndex) {\n right = pivotIndex - 1\n } else {\n left = pivotIndex + 1\n }\n }\n\n nodes[ nodeIndex ] = arrMedian\n nodes[ nodeIndex + 1 ] = this.buildTree(depth + 1, nodeIndex, arrBegin, arrMedian)\n nodes[ nodeIndex + 2 ] = this.buildTree(depth + 1, nodeIndex, arrMedian + 1, arrEnd)\n nodes[ nodeIndex + 3 ] = parent\n\n return nodeIndex\n }\n\n getNodeDepth (nodeIndex: number): number {\n const parentIndex = this.nodes[ nodeIndex + 3 ]\n return (parentIndex === -1) ? 0 : this.getNodeDepth(parentIndex) + 1\n }\n\n // TODO\n // function getNodePos (node) {}\n\n /**\n * find nearest points\n * @param {Array} point - array of size 3\n * @param {Integer} maxNodes - max amount of nodes to return\n * @param {Float} maxDistance - maximum distance of point to result nodes\n * @return {Array} array of point, distance pairs\n */\n nearest (point: NumberArray, maxNodes: number, maxDistance: number) {\n const bestNodes = new BinaryHeap<[number, number]>(e => -e[ 1 ])\n\n const nodes = this.nodes\n const points = this.points\n const indices = this.indices\n\n const nearestSearch = (nodeIndex: number) => {\n let bestChild, otherChild\n const dimension = this.getNodeDepth(nodeIndex) % 3\n const pointIndex = indices[ nodes[ nodeIndex ] ] * 3\n const ownPoint = [\n points[ pointIndex + 0 ],\n points[ pointIndex + 1 ],\n points[ pointIndex + 2 ]\n ]\n const ownDistance = this.metric(point, ownPoint)\n\n function saveNode (nodeIndex: number, distance: number) {\n bestNodes.push([ nodeIndex, distance ])\n if (bestNodes.size() > maxNodes) {\n bestNodes.pop()\n }\n }\n\n const leftIndex = nodes[ nodeIndex + 1 ]\n const rightIndex = nodes[ nodeIndex + 2 ]\n\n // if it's a leaf\n if (rightIndex === -1 && leftIndex === -1) {\n if ((bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[ 1 ]) &&\n ownDistance <= maxDistance\n ) {\n saveNode(nodeIndex, ownDistance)\n }\n return\n }\n\n if (rightIndex === -1) {\n bestChild = leftIndex\n } else if (leftIndex === -1) {\n bestChild = rightIndex\n } else {\n if (point[ dimension ] <= points[ pointIndex + dimension ]) {\n bestChild = leftIndex\n } else {\n bestChild = rightIndex\n }\n }\n\n // recursive search\n nearestSearch(bestChild)\n\n if ((bestNodes.size() < maxNodes || ownDistance < bestNodes.peek()[ 1 ]) &&\n ownDistance <= maxDistance\n ) {\n saveNode(nodeIndex, ownDistance)\n }\n\n // if there's still room or the current distance is nearer than the best distance\n const linearPoint = []\n for (let i = 0; i < 3; i += 1) {\n if (i === dimension) {\n linearPoint[ i ] = point[ i ]\n } else {\n linearPoint[ i ] = points[ pointIndex + i ]\n }\n }\n const linearDistance = this.metric(linearPoint, ownPoint)\n\n if ((bestNodes.size() < maxNodes || Math.abs(linearDistance) < bestNodes.peek()[ 1 ]) &&\n Math.abs(linearDistance) <= maxDistance\n ) {\n if (bestChild === leftIndex) {\n otherChild = rightIndex\n } else {\n otherChild = leftIndex\n }\n if (otherChild !== -1) {\n nearestSearch(otherChild)\n }\n }\n }\n\n nearestSearch(this.rootIndex)\n\n const result = []\n for (let i = 0, il = Math.min(bestNodes.size(), maxNodes); i < il; i += 1) {\n result.push(bestNodes.content[ i ])\n }\n\n return result\n }\n\n verify (nodeIndex?: number, depth = 0) {\n let count = 1\n\n if (nodeIndex === undefined) {\n nodeIndex = this.rootIndex\n }\n\n if (nodeIndex === -1) {\n throw new Error('node is null')\n }\n\n const dim = depth % 3\n const nodes = this.nodes\n const points = this.points\n const indices = this.indices\n\n const leftIndex = nodes[ nodeIndex + 1 ]\n const rightIndex = nodes[ nodeIndex + 2 ]\n\n if (leftIndex !== -1) {\n if (points[ indices[ nodes[ leftIndex ] ] * 3 + dim ] >\n points[ indices[ nodes[ nodeIndex ] ] * 3 + dim ]\n ) {\n throw new Error('left child is > parent!')\n }\n count += this.verify(leftIndex, depth + 1)\n }\n\n if (rightIndex !== -1) {\n if (points[ indices[ nodes[ rightIndex ] ] * 3 + dim ] <\n points[ indices[ nodes[ nodeIndex ] ] * 3 + dim ]\n ) {\n throw new Error('right child is < parent!')\n }\n count += this.verify(rightIndex, depth + 1)\n }\n\n return count\n }\n}\n\nexport default Kdtree\n","/**\n * @file Atom Proxy\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { NumberArray } from '../types'\nimport {\n Elements,\n SecStrucHelix, SecStrucSheet, SecStrucTurn,\n ProteinType, RnaType, DnaType, WaterType, IonType, SaccharideType,\n CgProteinBackboneType, CgRnaBackboneType, CgDnaBackboneType\n} from '../structure/structure-constants'\n\nimport Structure from '../structure/structure'\n\nimport ChainStore from '../store/chain-store'\nimport ResidueStore from '../store/residue-store'\nimport AtomStore from '../store/atom-store'\n\nimport AtomMap from '../store/atom-map'\nimport ResidueMap from '../store/residue-map'\n\nimport BondProxy from '../proxy/bond-proxy'\nimport AtomType from '../store/atom-type';\nimport ResidueType from '../store/residue-type';\nimport ResidueProxy from './residue-proxy';\nimport Entity from '../structure/entity';\nimport BondHash from '../store/bond-hash';\n\n/**\n * Atom proxy\n */\nclass AtomProxy {\n index: number\n\n chainStore: ChainStore\n residueStore: ResidueStore\n atomStore: AtomStore\n\n residueMap: ResidueMap\n atomMap: AtomMap\n\n /**\n * @param {Structure} structure - the structure\n * @param {Integer} index - the index\n */\n constructor (readonly structure: Structure, index = 0) {\n this.index = index\n this.chainStore = structure.chainStore\n this.residueStore = structure.residueStore\n this.atomStore = structure.atomStore\n this.residueMap = structure.residueMap\n this.atomMap = structure.atomMap\n }\n\n /**\n * @type {BondHash}\n */\n get bondHash (): BondHash|undefined { return this.structure.bondHash }\n\n /**\n * Molecular enity\n * @type {Entity}\n */\n get entity (): Entity {\n return this.structure.entityList[ this.entityIndex ]\n }\n get entityIndex () {\n return this.chainStore.entityIndex[ this.chainIndex ]\n }\n get modelIndex () {\n return this.chainStore.modelIndex[ this.chainIndex ]\n }\n get chainIndex () {\n return this.residueStore.chainIndex[ this.residueIndex ]\n }\n /**\n * @type {ResidueProxy}\n */\n get residue (): ResidueProxy {\n console.warn('residue - might be expensive')\n return this.structure.getResidueProxy(this.residueIndex)\n }\n\n get residueIndex () {\n return this.atomStore.residueIndex[ this.index ]\n }\n set residueIndex (value) {\n this.atomStore.residueIndex[ this.index ] = value\n }\n\n //\n\n /**\n * Secondary structure code\n * @type {String}\n */\n get sstruc () {\n return this.residueStore.getSstruc(this.residueIndex)\n }\n /**\n * Insertion code\n * @type {String}\n */\n get inscode () {\n return this.residueStore.getInscode(this.residueIndex)\n }\n /**\n * Residue number/label\n * @type {Integer}\n */\n get resno () {\n return this.residueStore.resno[ this.residueIndex ]\n }\n /**\n * Chain name\n * @type {String}\n */\n get chainname () {\n return this.chainStore.getChainname(this.chainIndex)\n }\n /**\n * Chain id\n * @type {String}\n */\n get chainid () {\n return this.chainStore.getChainid(this.chainIndex)\n }\n\n //\n\n /**\n * @type {ResidueType}\n */\n get residueType (): ResidueType {\n return this.residueMap.get(this.residueStore.residueTypeId[ this.residueIndex ])\n }\n /**\n * @type {AtomType}\n */\n get atomType (): AtomType {\n return this.atomMap.get(this.atomStore.atomTypeId[ this.index ])\n }\n get residueAtomOffset () {\n return this.residueStore.atomOffset[ this.residueIndex ]\n }\n\n //\n\n /**\n * Residue name\n */\n get resname () {\n return this.residueType.resname\n }\n /**\n * Hetero flag\n */\n get hetero () {\n return this.residueType.hetero\n }\n\n //\n\n /**\n * Atom name\n */\n get atomname () {\n return this.atomType.atomname\n }\n /**\n * Atomic number\n */\n get number () {\n return this.atomType.number\n }\n /**\n * Element\n */\n get element () {\n return this.atomType.element\n }\n /**\n * Van-der-Waals radius\n */\n get vdw () {\n return this.atomType.vdw\n }\n /**\n * Covalent radius\n */\n get covalent () {\n return this.atomType.covalent\n }\n\n //\n\n /**\n * X coordinate\n */\n get x () {\n return this.atomStore.x[ this.index ]\n }\n set x (value) {\n this.atomStore.x[ this.index ] = value\n }\n\n /**\n * Y coordinate\n */\n get y () {\n return this.atomStore.y[ this.index ]\n }\n set y (value) {\n this.atomStore.y[ this.index ] = value\n }\n\n /**\n * Z coordinate\n */\n get z () {\n return this.atomStore.z[ this.index ]\n }\n set z (value) {\n this.atomStore.z[ this.index ] = value\n }\n\n /**\n * Serial number\n */\n get serial () {\n return this.atomStore.serial[ this.index ]\n }\n set serial (value) {\n this.atomStore.serial[ this.index ] = value\n }\n\n /**\n * B-factor value\n */\n get bfactor () {\n return this.atomStore.bfactor[ this.index ]\n }\n set bfactor (value) {\n this.atomStore.bfactor[ this.index ] = value\n }\n\n /**\n * Occupancy value\n */\n get occupancy () {\n return this.atomStore.occupancy[ this.index ]\n }\n set occupancy (value) {\n this.atomStore.occupancy[ this.index ] = value\n }\n\n /**\n * Alternate location identifier\n */\n get altloc () {\n return this.atomStore.getAltloc(this.index)\n }\n set altloc (value) {\n this.atomStore.setAltloc(this.index, value)\n }\n\n /**\n * Partial charge\n */\n get partialCharge () {\n return this.atomStore.partialCharge ? this.atomStore.partialCharge[ this.index ] : null\n }\n set partialCharge (value) {\n if (this.atomStore.partialCharge) {\n this.atomStore.partialCharge[ this.index ] = value as number\n }\n }\n\n /**\n * Explicit radius\n */\n get radius () {\n return this.atomStore.radius ? this.atomStore.radius[ this.index ] : null\n }\n set radius (value) {\n if (this.atomStore.radius) {\n this.atomStore.radius[ this.index ] = value as number\n }\n }\n\n /**\n * Formal charge\n */\n get formalCharge () {\n return this.atomStore.formalCharge ? this.atomStore.formalCharge[ this.index ] : null\n }\n set formalCharge (value) {\n if (this.atomStore.formalCharge) {\n this.atomStore.formalCharge[ this.index ] = value as number\n }\n }\n\n /**\n * Aromaticity flag\n */\n get aromatic () {\n if (this.atomStore.aromatic) {\n return this.atomStore.aromatic[ this.index ] as number\n } else {\n return this.residueType.isAromatic(this) ? 1 : 0\n }\n }\n set aromatic (value) {\n if (this.atomStore.aromatic) {\n this.atomStore.aromatic[ this.index ] = value as number\n }\n }\n\n //\n\n get bondCount () {\n return this.bondHash!.countArray[ this.index ] // TODO\n }\n\n //\n\n /**\n * Iterate over each bond\n * @param {function(bond: BondProxy)} callback - iterator callback function\n * @param {BondProxy} [bp] - optional target bond proxy for use in the callback\n * @return {undefined}\n */\n eachBond (callback: (bp: BondProxy) => void, bp?: BondProxy) {\n bp = bp || this.structure._bp\n const idx = this.index\n const bondHash = this.bondHash! // TODO\n const indexArray = bondHash.indexArray\n const n = bondHash.countArray[ idx ]\n const offset = bondHash.offsetArray[ idx ]\n\n for (let i = 0; i < n; ++i) {\n bp.index = indexArray[ offset + i ]\n callback(bp)\n }\n }\n\n /**\n * Iterate over each bonded atom\n * @param {function(atom: AtomProxy)} callback - iterator callback function\n * @param {AtomProxy} [ap] - optional target atom proxy for use in the callback\n * @return {undefined}\n */\n eachBondedAtom (callback: (ap: AtomProxy) => void, _ap?: AtomProxy) {\n const ap = _ap ? _ap : this.structure._ap\n const idx = this.index\n\n this.eachBond(function (bp) {\n ap.index = idx !== bp.atomIndex1 ? bp.atomIndex1 : bp.atomIndex2\n callback(ap)\n })\n this.index = idx\n }\n\n /**\n * Check if this atom is bonded to the given atom,\n * assumes both atoms are from the same structure\n * @param {AtomProxy} ap - the given atom\n * @return {Boolean} whether a bond exists or not\n */\n hasBondTo (ap: AtomProxy) {\n let flag = false\n this.eachBondedAtom(function (bap) {\n if (ap.index === bap.index) flag = true\n })\n return flag\n }\n\n bondToElementCount (element: Elements) {\n let count = 0\n const idx = this.index // Avoid reentrancy problems\n this.eachBondedAtom(function (bap) {\n if (bap.number === element) count += 1\n })\n this.index = idx\n return count\n }\n\n hasBondToElement (element: Elements) {\n return this.bondToElementCount(element) > 0\n }\n\n //\n\n /**\n * If atom is part of a backbone\n * @return {Boolean} flag\n */\n isBackbone () {\n const backboneIndexList = this.residueType.backboneIndexList\n if (backboneIndexList.length > 0) {\n return backboneIndexList.includes(this.index - this.residueAtomOffset)\n } else {\n return false\n }\n }\n\n /**\n * If atom is part of a polymer\n * @return {Boolean} flag\n */\n isPolymer () {\n if (this.structure.entityList.length > 0) {\n return this.entity.isPolymer()\n } else {\n const moleculeType = this.residueType.moleculeType\n return (\n moleculeType === ProteinType ||\n moleculeType === RnaType ||\n moleculeType === DnaType\n )\n }\n }\n\n /**\n * If atom is part of a sidechin\n * @return {Boolean} flag\n */\n isSidechain () {\n return this.isPolymer() && !this.isBackbone()\n }\n\n /**\n * If atom is part of a coarse-grain group\n * @return {Boolean} flag\n */\n isCg () {\n const backboneType = this.residueType.backboneType\n return (\n backboneType === CgProteinBackboneType ||\n backboneType === CgRnaBackboneType ||\n backboneType === CgDnaBackboneType\n )\n }\n\n isTrace () {\n return this.index === (this.residueType.traceAtomIndex + this.residueAtomOffset)\n }\n\n /**\n * If atom is part of a hetero group\n * @return {Boolean} flag\n */\n isHetero () {\n return this.residueType.hetero === 1\n }\n\n /**\n * If atom is part of a protein molecule\n * @return {Boolean} flag\n */\n isProtein () {\n return this.residueType.moleculeType === ProteinType\n }\n\n /**\n * If atom is part of a nucleic molecule\n * @return {Boolean} flag\n */\n isNucleic () {\n const moleculeType = this.residueType.moleculeType\n return moleculeType === RnaType || moleculeType === DnaType\n }\n\n /**\n * If atom is part of a rna\n * @return {Boolean} flag\n */\n isRna () {\n return this.residueType.moleculeType === RnaType\n }\n\n /**\n * If atom is part of a dna\n * @return {Boolean} flag\n */\n isDna () {\n return this.residueType.moleculeType === DnaType\n }\n\n /**\n * If atom is part of a water molecule\n * @return {Boolean} flag\n */\n isWater () {\n return this.residueType.moleculeType === WaterType\n }\n\n /**\n * If atom is part of an ion\n * @return {Boolean} flag\n */\n isIon () {\n return this.residueType.moleculeType === IonType\n }\n\n /**\n * If atom is part of a saccharide\n * @return {Boolean} flag\n */\n isSaccharide () {\n return this.residueType.moleculeType === SaccharideType\n }\n\n /**\n * If atom is part of a helix\n * @return {Boolean} flag\n */\n isHelix () {\n return SecStrucHelix.includes(this.sstruc)\n }\n\n /**\n * If atom is part of a sheet\n * @return {Boolean} flag\n */\n isSheet () {\n return SecStrucSheet.includes(this.sstruc)\n }\n\n /**\n * If atom is part of a turn\n * @return {Boolean} flag\n */\n isTurn () {\n return SecStrucTurn.includes(this.sstruc) && this.isProtein()\n }\n\n isBonded () {\n return this.bondHash!.countArray[ this.index ] !== 0 // TODO\n }\n\n /**\n * If atom is part of a ring\n * @return {Boolean} flag\n */\n isRing () {\n const atomRings = this.residueType.getRings()!.atomRings // TODO\n return atomRings[ this.index - this.residueAtomOffset ] !== undefined\n }\n\n isAromatic () {\n return this.aromatic === 1\n }\n\n isPolarHydrogen () {\n let result = false\n\n if (this.number !== 1) return result\n\n result = !this.hasBondToElement(Elements.C)\n\n return result\n }\n\n isMetal () { return this.atomType.isMetal() }\n isNonmetal () { return this.atomType.isNonmetal() }\n isMetalloid () { return this.atomType.isMetalloid() }\n isHalogen () { return this.atomType.isHalogen() }\n isDiatomicNonmetal () { return this.atomType.isDiatomicNonmetal() }\n isPolyatomicNonmetal () { return this.atomType.isPolyatomicNonmetal() }\n isAlkaliMetal () { return this.atomType.isAlkaliMetal() }\n isAlkalineEarthMetal () { return this.atomType.isAlkalineEarthMetal() }\n isNobleGas () { return this.atomType.isNobleGas() }\n isTransitionMetal () { return this.atomType.isTransitionMetal() }\n isPostTransitionMetal () { return this.atomType.isPostTransitionMetal() }\n isLanthanide () { return this.atomType.isLanthanide() }\n isActinide () { return this.atomType.isActinide() }\n\n getDefaultValence () { return this.atomType.getDefaultValence() }\n getValenceList () { return this.atomType.getValenceList() }\n getOuterShellElectronCount () { return this.atomType.getOuterShellElectronCount() }\n\n /**\n * Distance to another atom\n * @param {AtomProxy} atom - the other atom\n * @return {Number} the distance\n */\n distanceTo (atom: AtomProxy) {\n const taa = this.atomStore\n const aaa = atom.atomStore\n const ti = this.index\n const ai = atom.index\n const x = taa.x[ ti ] - aaa.x[ ai ]\n const y = taa.y[ ti ] - aaa.y[ ai ]\n const z = taa.z[ ti ] - aaa.z[ ai ]\n const distSquared = x * x + y * y + z * z\n return Math.sqrt(distSquared)\n }\n\n /**\n * If connected to another atom\n * @param {AtomProxy} atom - the other atom\n * @return {Boolean} flag\n */\n connectedTo (atom: AtomProxy) {\n const taa = this.atomStore\n const aaa = atom.atomStore\n const ti = this.index\n const ai = atom.index\n\n if (taa.altloc && aaa.altloc) {\n const ta = taa.altloc[ ti ] // use Uint8 value to compare\n const aa = aaa.altloc[ ai ] // no need to convert to char\n // 0 is the Null character, 32 is the space character\n if (!(ta === 0 || aa === 0 || ta === 32 || aa === 32 || (ta === aa))) return false\n }\n\n const x = taa.x[ ti ] - aaa.x[ ai ]\n const y = taa.y[ ti ] - aaa.y[ ai ]\n const z = taa.z[ ti ] - aaa.z[ ai ]\n\n const distSquared = x * x + y * y + z * z\n\n // if( this.isCg() ) console.log( this.qualifiedName(), Math.sqrt( distSquared ), distSquared )\n if (distSquared < 48.0 && this.isCg()) return true\n\n if (isNaN(distSquared)) return false\n\n const d = this.covalent + atom.covalent\n const d1 = d + 0.3\n const d2 = d - 0.5\n\n return distSquared < (d1 * d1) && distSquared > (d2 * d2)\n }\n\n /**\n * Set atom position from array\n * @param {Array|TypedArray} array - input array\n * @param {Integer} [offset] - the offset\n * @return {AtomProxy} this object\n */\n positionFromArray (array: NumberArray, offset = 0) {\n this.x = array[ offset + 0 ]\n this.y = array[ offset + 1 ]\n this.z = array[ offset + 2 ]\n\n return this\n }\n\n /**\n * Write atom position to array\n * @param {Array|TypedArray} [array] - target array\n * @param {Integer} [offset] - the offset\n * @return {Array|TypedArray} target array\n */\n positionToArray (array: NumberArray = [], offset = 0) {\n const index = this.index\n const atomStore = this.atomStore\n\n array[ offset + 0 ] = atomStore.x[ index ]\n array[ offset + 1 ] = atomStore.y[ index ]\n array[ offset + 2 ] = atomStore.z[ index ]\n\n return array\n }\n\n /**\n * Write atom position to vector\n * @param {Vector3} [v] - target vector\n * @return {Vector3} target vector\n */\n positionToVector3 (v?: Vector3) {\n if (v === undefined) v = new Vector3()\n\n v.x = this.x\n v.y = this.y\n v.z = this.z\n\n return v\n }\n\n /**\n * Set atom position from vector\n * @param {Vector3} v - input vector\n * @return {AtomProxy} this object\n */\n positionFromVector3 (v: Vector3) {\n this.x = v.x\n this.y = v.y\n this.z = v.z\n\n return this\n }\n\n /**\n * Add vector to atom position\n * @param {Vector3} v - input vector\n * @return {AtomProxy} this object\n */\n positionAdd (v: Vector3|AtomProxy) {\n this.x += v.x\n this.y += v.y\n this.z += v.z\n\n return this\n }\n\n /**\n * Subtract vector from atom position\n * @param {Vector3} v - input vector\n * @return {AtomProxy} this object\n */\n positionSub (v: Vector3|AtomProxy) {\n this.x -= v.x\n this.y -= v.y\n this.z -= v.z\n\n return this\n }\n\n /**\n * Get intra group/residue bonds\n * @param {Boolean} firstOnly - immediately return the first connected atomIndex\n * @return {Integer[]|Integer|undefined} connected atomIndices\n */\n getResidueBonds (firstOnly = false) {\n const residueAtomOffset = this.residueAtomOffset\n const relativeIndex = this.index - this.residueAtomOffset\n const bonds = this.residueType.getBonds()! // TODO\n const atomIndices1 = bonds.atomIndices1\n const atomIndices2 = bonds.atomIndices2\n let idx1, idx2, connectedAtomIndex\n let connectedAtomIndices: number[]|undefined\n\n if (!firstOnly) connectedAtomIndices = []\n\n idx1 = atomIndices1.indexOf(relativeIndex)\n while (idx1 !== -1) {\n connectedAtomIndex = atomIndices2[ idx1 ] + residueAtomOffset\n if (connectedAtomIndices) {\n connectedAtomIndices.push(connectedAtomIndex)\n idx1 = atomIndices1.indexOf(relativeIndex, idx1 + 1)\n } else {\n return connectedAtomIndex\n }\n }\n\n idx2 = atomIndices2.indexOf(relativeIndex)\n while (idx2 !== -1) {\n connectedAtomIndex = atomIndices1[ idx2 ] + residueAtomOffset\n if (connectedAtomIndices) {\n connectedAtomIndices.push(connectedAtomIndex)\n idx2 = atomIndices2.indexOf(relativeIndex, idx2 + 1)\n } else {\n return connectedAtomIndex\n }\n }\n\n return connectedAtomIndices\n }\n\n //\n\n qualifiedName (noResname = false) {\n var name = ''\n if (this.resname && !noResname) name += '[' + this.resname + ']'\n if (this.resno !== undefined) name += this.resno\n if (this.inscode) name += '^' + this.inscode\n if (this.chainname) name += ':' + this.chainname\n if (this.atomname) name += '.' + this.atomname\n if (this.altloc) name += '%' + this.altloc\n if (this.structure.modelStore.count > 1) name += '/' + this.modelIndex\n return name\n }\n\n /**\n * Clone object\n * @return {AtomProxy} cloned atom\n */\n clone () {\n return new AtomProxy(this.structure, this.index)\n }\n\n toObject () {\n return {\n index: this.index,\n residueIndex: this.residueIndex,\n\n resname: this.resname,\n x: this.x,\n y: this.y,\n z: this.z,\n element: this.element,\n chainname: this.chainname,\n resno: this.resno,\n serial: this.serial,\n vdw: this.vdw,\n covalent: this.covalent,\n hetero: this.hetero,\n bfactor: this.bfactor,\n altloc: this.altloc,\n atomname: this.atomname,\n modelIndex: this.modelIndex\n }\n }\n}\n\nexport default AtomProxy\n","/**\n * @file Kdtree\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { Debug, Log } from '../globals'\nimport _Kdtree from '../utils/kdtree'\nimport Structure from '../structure/structure'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ResidueProxy from '../proxy/residue-proxy'\n\nfunction euclideanDistSq(a: number[], b: number[]) {\n const dx = a[0] - b[0]\n const dy = a[1] - b[1]\n const dz = a[2] - b[2]\n return dx * dx + dy * dy + dz * dz\n}\n\nfunction euclideanDist(a: number[], b: number[]) {\n return Math.sqrt(euclideanDistSq(a, b))\n}\n\nconst pointArray = new Float32Array(3)\n\nclass Kdtree {\n points: Float32Array\n atomIndices: Uint32Array\n kdtree: _Kdtree\n\n constructor(structure: Structure|ResidueProxy, useSquaredDist = false) {\n if (Debug) Log.time('Kdtree build')\n\n const metric = useSquaredDist ? euclideanDistSq : euclideanDist\n\n const points = new Float32Array(structure.atomCount * 3)\n const atomIndices = new Uint32Array(structure.atomCount)\n let i = 0\n\n structure.eachAtom(function (ap) {\n points[ i + 0 ] = ap.x\n points[ i + 1 ] = ap.y\n points[ i + 2 ] = ap.z\n atomIndices[ i / 3 ] = ap.index\n i += 3\n })\n\n this.atomIndices = atomIndices\n this.points = points\n this.kdtree = new _Kdtree(points, metric)\n\n if (Debug) Log.timeEnd('Kdtree build')\n\n // console.log(\"this.kdtree.verify()\", this.kdtree.verify())\n }\n\n nearest (point: number[]|Vector3, maxNodes: number, maxDistance: number) {\n // Log.time( \"Kdtree nearest\" );\n\n if (point instanceof Vector3) {\n point.toArray(pointArray as any)\n } else if (point instanceof AtomProxy) {\n point.positionToArray(pointArray)\n }\n\n const nodeList = this.kdtree.nearest(pointArray, maxNodes, maxDistance)\n\n const indices = this.kdtree.indices\n const nodes = this.kdtree.nodes\n const atomIndices = this.atomIndices\n const resultList = []\n\n for (let i = 0, n = nodeList.length; i < n; ++i) {\n const d = nodeList[ i ]\n const nodeIndex = d[ 0 ]\n const dist = d[ 1 ]\n\n resultList.push({\n index: atomIndices[ indices[ nodes[ nodeIndex ] ] ],\n distance: dist\n })\n }\n\n // Log.timeEnd( \"Kdtree nearest\" );\n\n return resultList\n }\n}\n\nexport default Kdtree\n","/**\n * @file Symmetry Constants\n * @author Alexander Rose \n * @private\n */\n\nexport const SymOpCode: { [k: string]: string } = {\n ' ': 'X',\n '!': 'Y',\n '#': 'Z',\n '$': '-X',\n '%': '-Y',\n '&': '-Z',\n \"'\": 'Y+1/2',\n '(': '1/2+X',\n ')': '1/2+Y',\n '*': '1/2-X',\n '+': '1/2+Z',\n ',': '1/2-Y',\n '-': '1/2-Z',\n '.': 'X+1/2',\n '/': 'Z+1/2',\n '0': '-X+1/2',\n '1': '-Y+1/2',\n '2': '-Z+1/2',\n '3': '1/4+X',\n '4': '1/4-Y',\n '5': '1/4+Z',\n '6': '1/4-X',\n '7': '1/4+Y',\n '8': '3/4-Y',\n '9': '3/4+Z',\n ':': '3/4+Y',\n ';': '3/4+X',\n '<': '3/4-X',\n '=': '1/4-Z',\n '>': '3/4-Z',\n '?': 'X-Y',\n '@': 'Y-X',\n 'A': 'Z+1/3',\n 'B': 'Z+2/3',\n 'C': 'X+2/3',\n 'D': 'Y+1/3',\n 'E': '-Y+2/3',\n 'F': 'X-Y+1/3',\n 'G': 'Y-X+2/3',\n 'H': '-X+1/3',\n 'I': 'X+1/3',\n 'J': 'Y+2/3',\n 'K': '-Y+1/3',\n 'L': 'X-Y+2/3',\n 'M': 'Y-X+1/3',\n 'N': '-X+2/3',\n 'O': '2/3+X',\n 'P': '1/3+Y',\n 'Q': '1/3+Z',\n 'R': '2/3-Y',\n 'S': '1/3+X-Y',\n 'T': '2/3+Y-X',\n 'U': '1/3-X',\n 'V': '2/3-X',\n 'W': '1/3-Y',\n 'X': '1/3-Z',\n 'Y': '2/3+Y',\n 'Z': '1/3+Y-X',\n '[': '2/3+X-Y',\n ']': '1/3+X',\n '^': '2/3+Z',\n '_': '2/3-Z',\n '`': '5/6+Z',\n 'a': '1/6+Z',\n 'b': '5/6-Z',\n 'c': '1/6-Z',\n 'd': 'Z+5/6',\n 'e': 'Z+1/6',\n 'f': 'Z+1/4',\n 'g': '+Y'\n}\n\n// encoded, originally from CCP4 symop.lib\nexport const EncodedSymOp: { [k: string]: string } = {\n 'P 1': ' !#',\n 'P -1': ' !#$%&',\n 'P 1 2 1': ' !#$!&',\n 'P 1 21 1': \" !#$'&\",\n 'C 1 2 1': ' !#$!&()#*)&',\n 'P 1 m 1': ' !# %#',\n 'P 1 c 1': ' !# %+',\n 'C 1 m 1': ' !# %#()#(,#',\n 'C 1 c 1': ' !# %+()#(,+',\n 'P 1 2/m 1': ' !# %#$!&$%&',\n 'P 1 21/m 1': ' !#$)&$%& ,#',\n 'C 1 2/m 1': ' !# %#$!&$%&()#(,#*)&*,&',\n 'P 1 2/c 1': ' !#$!-$%& %+',\n 'P 1 21/c 1': ' !#$%&$)- ,+',\n 'C 1 2/c 1': ' !#$!-$%& %+()#*)-*,&(,+',\n 'P 2 2 2': ' !#$%#$!& %&',\n 'P 2 2 21': ' !#$%+$!- %&',\n 'P 21 21 2': ' !#$%#*)&(,&',\n 'P 21 21 21': ' !#*%+$)-(,&',\n 'C 2 2 21': ' !#$%+$!- %&()#*,+*)-(,&',\n 'C 2 2 2': ' !#$%#$!& %&()#*,#*)&(,&',\n 'F 2 2 2': ' !#$%#$!& %& )+$,+$)- ,-(!+*%+*!-(%-()#*,#*)&(,&',\n 'I 2 2 2': \" !#$%# %&$!&.'/01/.120'2\",\n 'I 21 21 21': ' !#*%+$)-(,&()+$,#*!& %-',\n 'P m m 2': ' !#$%# %#$!#',\n 'P m c 21': ' !#$%+ %+$!#',\n 'P c c 2': ' !#$%# %+$!+',\n 'P m a 2': ' !#$%#(%#*!#',\n 'P c a 21': ' !#$%+(%#*!+',\n 'P n c 2': ' !#$%# ,+$)+',\n 'P m n 21': ' !#*%+(%+$!#',\n 'P b a 2': ' !#$%#(,#*)#',\n 'P n a 21': ' !#$%+(,#*)+',\n 'P n n 2': ' !#$%#(,+*)+',\n 'C m m 2': ' !#$%# %#$!#()#*,#(,#*)#',\n 'C m c 21': ' !#$%+ %+$!#()#*,+(,+*)#',\n 'C c c 2': ' !#$%# %+$!+()#*,#(,+*)+',\n 'A m m 2': ' !#$%# %#$!# )+$,+ ,+$)+',\n 'A b m 2': ' !#$%# ,#$)# )+$,+ %+$!+',\n 'A m a 2': ' !#$%#(%#*!# )+$,+(,+*)+',\n 'A b a 2': ' !#$%#(,#*)# )+$,+(%+*!+',\n 'F m m 2': ' !#$%# %#$!# )+$,+ ,+$)+(!+*%+(%+*!+()#*,#(,#*)#',\n 'F d d 2': ' !#$%#345675 )+$,+3896:9(!+*%+;49<79()#*,#;85<:5',\n 'I m m 2': ' !#$%# %#$!#()+*,+(,+*)+',\n 'I b a 2': ' !#$%#(,#*)#()+*,+ %+$!+',\n 'I m a 2': ' !#$%#(%#*!#()+*,+ ,+$)+',\n 'P 2/m 2/m 2/m': ' !#$%#$!& %&$%& !& %#$!#',\n 'P 2/n 2/n 2/n': ' !#$%#$!& %&*,-()-(,+*)+',\n 'P 2/c 2/c 2/m': ' !#$%#$!- %-$%& !& %+$!+',\n 'P 2/b 2/a 2/n': ' !#$%#$!& %&*,&()&(,#*)#',\n 'P 21/m 2/m 2/a': ' !#*%#$!&(%&$%&(!& %#*!#',\n 'P 2/n 21/n 2/a': ' !#*%#*)- ,-$%&(!&(,+$)+',\n 'P 2/m 2/n 21/a': ' !#*%+*!- %&$%&(!-(%+$!#',\n 'P 21/c 2/c 2/a': ' !#*%#$!-(%-$%&(!& %+*!+',\n 'P 21/b 21/a 2/m': ' !#$%#*)&(,&$%& !&(,#*)#',\n 'P 21/c 21/c 2/n': ' !#*,#$)-(%-$%&()& ,+*!+',\n 'P 2/b 21/c 21/m': ' !#$%+$)- ,&$%& !- ,+$)#',\n 'P 21/n 21/n 2/m': ' !#$%#*)-(,-$%& !&(,+*)+',\n 'P 21/m 21/m 2/n': \" !#$%#*'&.,&*,&.'& %#$!#\",\n 'P 21/b 2/c 21/n': ' !#*,+$!-(,&$%&()- %+*)#',\n 'P 21/b 21/c 21/a': ' !#*%+$)-(,&$%&(!- ,+*)#',\n 'P 21/n 21/m 21/a': \" !#0%/$'&.12$%&.!2 1#0'/\",\n 'C 2/m 2/c 21/m': ' !#$%+$!- %&$%& !- %+$!#()#*,+*)-(,&*,&()-(,+*)#',\n 'C 2/m 2/c 21/a': ' !#$,+$)- %&$%& )- ,+$!#()#*%+*!-(,&*,&(!-(%+*)#',\n 'C 2/m 2/m 2/m': ' !#$%#$!& %&$%& !& %#$!#()#*,#*)&(,&*,&()&(,#*)#',\n 'C 2/c 2/c 2/m': ' !#$%#$!- %-$%& !& %+$!+()#*,#*)-(,-*,&()&(,+*)+',\n 'C 2/m 2/m 2/a': ' !#$,#$)& %&$%& )& ,#$!#()#*%#*!&(,&*,&(!&(%#*)#',\n 'C 2/c 2/c 2/a': ' !#*,#$!&(,&$,-(!- ,+*!+()#$%#*)& %&*%- )-(%+$)+',\n 'F 2/m 2/m 2/m': ' !#$%#$!& %&$%& !& %#$!# )+$,+$)- ,-$,- )- ,+$)+(!+*%+*!-(%-*%-(!-(%+*!+()#*,#*)&(,&*,&()&(,#*)#',\n 'F 2/d 2/d 2/d': ' !#$%#$!& %&64=37=345675 )+$,+$)- ,-68>3:>3896:9(!+*%+*!-(%-<4>;7>;49<79()#*,#*)&(,&<8=;:=;85<:5',\n 'I 2/m 2/m 2/m': ' !#$%#$!& %&$%& !& %#$!#()+*,+*)-(,-*,-()-(,+*)+',\n 'I 2/b 2/a 2/m': ' !#$%#*)&(,&$%& !&(,#*)#()+*,+$!- %-*,-()- %+$!+',\n 'I 21/b 21/c 21/a': ' !#*%+$)-(,&$%&(!- ,+*)#()+$,#*!& %-*,- )&(%#$!+',\n 'I 21/m 21/m 21/a': ' !#$,#$)& %&$%& )& ,#$!#()+*%+*!-(,-*,-(!-(%+*)+',\n 'P 4': ' !#$%#% #!$#',\n 'P 41': ' !#$%+% 5!$9',\n 'P 42': ' !#$%#% +!$+',\n 'P 43': ' !#$%+% 9!$5',\n 'I 4': ' !#$%#% #!$#()+*,+,(+)*+',\n 'I 41': ' !#*,+%(5)$9()+$%#, 9!*5',\n 'P -4': ' !#$%#!$&% &',\n 'I -4': ' !#$%#!$&% &()+*,+)*-,(-',\n 'P 4/m': ' !#$%#% #!$#$%& !&!$&% &',\n 'P 42/m': ' !#$%#% +!$+$%& !&!$-% -',\n 'P 4/n': ' !#$%#,(#)*#*,&()&!$&% &',\n 'P 42/n': ' !#$%#,(+)*+*,-()-!$&% &',\n 'I 4/m': ' !#$%#% #!$#$%& !&!$&% &()+*,+,(+)*+*,-()-)*-,(-',\n 'I 41/a': ' !#*,+%(5)$9$,=(!>!$&,(-()+$%#, 9!*5*%> )=)*-% &',\n 'P 4 2 2': ' !#$%#% #!$#$!& %&! &%$&',\n 'P 4 21 2': ' !#$%#,(#)*#*)&(,&! &%$&',\n 'P 41 2 2': ' !#$%+% 5!$9$!& %-! >%$=',\n 'P 41 21 2': ' !#$%+,(5)*9*)=(,>! &%$-',\n 'P 42 2 2': ' !#$%#% +!$+$!& %&! -%$-',\n 'P 42 21 2': ' !#$%#,(+)*+*)-(,-! &%$&',\n 'P 43 2 2': ' !#$%+% 9!$5$!& %-! =%$>',\n 'P 43 21 2': ' !#$%+,(9)*5*)>(,=! &%$-',\n 'I 4 2 2': ' !#$%#% #!$#$!& %&! &%$&()+*,+,(+)*+*)-(,-)(-,*-',\n 'I 41 2 2': ' !#*,+%(5)$9*!> ,=)(-%$&()+$%#, 9!*5$)=(%>! &,*-',\n 'P 4 m m': ' !#$%#% #!$# %#$!#%$#! #',\n 'P 4 b m': ' !#$%#% #!$#(,#*)#,*#)(#',\n 'P 42 c m': ' !#$%#% +!$+ %+$!+%$#! #',\n 'P 42 n m': ' !#$%#,(+)*+(,+*)+%$#! #',\n 'P 4 c c': ' !#$%#% #!$# %+$!+%$+! +',\n 'P 4 n c': ' !#$%#% #!$#(,+*)+,*+)(+',\n 'P 42 m c': ' !#$%#% +!$+ %#$!#%$+! +',\n 'P 42 b c': ' !#$%#% +!$+(,#*)#,*+)(+',\n 'I 4 m m': ' !#$%#% #!$# %#$!#%$#! #()+*,+,(+)*+(,+*)+,*+)(+',\n 'I 4 c m': ' !#$%#% #!$# %+$!+%$+! +()+*,+,(+)*+(,#*)#,*#)(#',\n 'I 41 m d': ' !#*,+%(5)$9 %#*)+%*5) 9()+$%#, 9!*5(,+$!#,$9!(5',\n 'I 41 c d': ' !#*,+%(5)$9 %+*)#%*9) 5()+$%#, 9!*5(,#$!+,$5!(9',\n 'P -4 2 m': ' !#$%#% &!$&$!& %&%$#! #',\n 'P -4 2 c': ' !#$%#% &!$&$!- %-%$+! +',\n 'P -4 21 m': ' !#$%#% &!$&*)&(,&,*#)(#',\n 'P -4 21 c': ' !#$%#% &!$&*)-(,-,*+)(+',\n 'P -4 m 2': ' !#$%#!$&% & %#$!#! &%$&',\n 'P -4 c 2': ' !#$%#% &!$& %+$!+! -%$-',\n 'P -4 b 2': ' !#$%#% &!$&(,#*)#)(&,*&',\n 'P -4 n 2': ' !#$%#% &!$&(,+*)+)(-,*-',\n 'I -4 m 2': ' !#$%#% &!$& %#$!#! &%$&()+*,+,(-)*-(,+*)+)(-,*-',\n 'I -4 c 2': ' !#$%#% &!$& %+$!+! -%$-()+*,+,(-)*-(,#*)#)(&,*&',\n 'I -4 2 m': ' !#$%#% &!$&$!& %&%$#! #()+*,+,(-)*-*)-(,-,*+)(+',\n 'I -4 2 d': ' !#$%#% &!$&*!>(%>,$9) 9()+*,+,(-)*-$)= ,=%*5!(5',\n 'P 4/m 2/m 2/m': ' !#$%#% #!$#$!& %&! &%$&$%& !&!$&% & %#$!#%$#! #',\n 'P 4/m 2/c 2/c': ' !#$%#% #!$#$!- %-! -%$-$%& !&!$&% & %+$!+%$+! +',\n 'P 4/n 2/b 2/m': ' !#$%#% #!$#$!& %&! &%$&*,&()&)*&,(&(,#*)#,*#)(#',\n 'P 4/n 2/n 2/c': ' !#$%#% #!$#$!& %&! &%$&*,-()-)*-,(-(,+*)+,*+)(+',\n 'P 4/m 21/b 2/m': ' !#$%#% #!$#*)&(,&)(&,*&$%& !&!$&% &(,#*)#,*#)(#',\n 'P 4/m 21/n 2/c': ' !#$%#% #!$#*)-(,-)(-,*-$%& !&!$&% &(,+*)+,*+)(+',\n 'P 4/n 21/m 2/m': ' !#$%#,(#)*#*)&(,&! &%$&*,&()&!$&% & %#$!#,*#)(#',\n 'P 4/n 2/c 2/c': ' !#$%#,(#)*#*)-(,-! -%$-*,&()&!$&% & %+$!+,*+)(+',\n 'P 42/m 2/m 2/c': ' !#$%#% +!$+$!& %&! -%$-$%& !&!$-% - %#$!#%$+! +',\n 'P 42/m 2/c 2/m': ' !#$%#% +!$+$!- %-! &%$&$%& !&!$-% - %+$!+%$#! #',\n 'P 42/n 2/b 2/c': ' !#$%#,(+)*+$!- %-)(&,*&*,-()-!$&% &(,#*)#%$+! +',\n 'P 42/n 2/n 2/m': ' !#$%#,(+)*+$!& %&)(-,*-*,-()-!$&% &(,+*)+%$#! #',\n 'P 42/m 21/b 2/c': ' !#$%#% +!$+*)&(,&)(-,*-$%& !&!$-% -(,#*)#,*+)(+',\n 'P 42/m 21/n 2/m': \" !#$%#,./'*/*'-.,-! &%$&$%& !&'*-,.-.,/*'/%$#! #\",\n 'P 42/n 21/m 2/c': ' !#$%#,(+)*+*)-(,-! &%$&*,-()-!$&% & %#$!#,*+)(+',\n 'P 42/n 21/c 2/m': ' !#$%#,(+)*+*)&(,&! -%$-*,-()-!$&% & %+$!+,*#)(#',\n 'I 4/m 2/m 2/m': ' !#$%#% #!$#$!& %&! &%$&$%& !&!$&% & %#$!#%$#! #()+*,+,(+)*+*)-(,-)(-,*-*,-()-)*-,(-(,+*)+,*+)(+',\n 'I 4/m 2/c 2/m': ' !#$%#% #!$#$!- %-! -%$-$%& !&!$&% & %+$!+%$+! +()+*,+,(+)*+*)&(,&)(&,*&*,-()-)*-,(-(,#*)#,*#)(#',\n 'I 41/a 2/m 2/d': ' !#*,+%(5)$9*!> ,=)(-%$&$,=(!>!$&,(-(,+$!#,$9!(5()+$%#, 9!*5$)=(%>! &,*-*%> )=)*-% & %#*)+%*5) 9',\n 'I 41/a 2/c 2/d': ' !#*,+%(5)$9*!= ,>)(&%$-$,=(!>!$&,(-(,#$!+,$5!(9()+$%#, 9!*5$)>(%=! -,*&*%> )=)*-% & %+*)#%*9) 5',\n 'P 3': ' !#%?#@$#',\n 'P 31': ' !#%?A@$B',\n 'P 32': ' !#%?B@$A',\n 'H 3': ' !#%?#@$#CDAEFAGHAIJBKLBMNB',\n 'R 3': ' !## !!# ',\n 'P -3': ' !#%?#@$#$%&!@&? &',\n 'H -3': ' !#%?#@$#$%&!@&? &OPQRSQTUQVWXYZX[]X]Y^W[^ZV^UR_PT_SO_',\n 'R -3': ' !## !!# $%&&$%%&$',\n 'P 3 1 2': ' !#%?#@$#%$&@!& ?&',\n 'P 3 2 1': ' !#%?#@$#! &?%&$@&',\n 'P 31 1 2': ' !#%?Q@$^%$_@!X ?&',\n 'P 31 2 1': ' !#%?A@$B! &?%_$@X',\n 'P 32 1 2': ' !#%?^@$Q%$X@!_ ?&',\n 'P 32 2 1': ' !#%?B@$A! &?%X$@_',\n 'H 3 2': ' !#%?#@$#! &?%&$@&OPQRSQTUQY]X[WXVZX]Y^W[^ZV^PO_SR_UT_',\n 'R 3 2': ' !## !!# %$&$&%&%$',\n 'P 3 m 1': ' !#%?#@$#%$#@!# ?#',\n 'P 3 1 m': ' !#%?#@$#! #?%#$@#',\n 'P 3 c 1': ' !#%?#@$#%$+@!+ ?+',\n 'P 3 1 c': ' !#%?#@$#! +?%+$@+',\n 'H 3 m': ' !#%?#@$#%$#@!# ?#OPQRSQTUQRUQTPQOSQ]Y^W[^ZV^WV^ZY^][^',\n 'R 3 m': ' !## !!# ! # #!#! ',\n 'H 3 c': ' !#%?#@$#%$+@!+ ?+OPQRSQTUQRU`TP`OS`]Y^W[^ZV^WVaZYa][a',\n 'R 3 c': \" !## !!# '././'/'.\",\n 'P -3 1 2/m': ' !#%?#@$#%$&@!& ?&$%&!@&? &! #?%#$@#',\n 'P -3 1 2/c': ' !#%?#@$#%$-@!- ?-$%&!@&? &! +?%+$@+',\n 'P -3 2/m 1': ' !#%?#@$#! &?%&$@&$%&!@&? &%$#@!# ?#',\n 'P -3 2/c 1': ' !#%?#@$#! -?%-$@-$%&!@&? &%$+@!+ ?+',\n 'H -3 2/m': ' !#%?#@$#! &?%&$@&$%&!@&? &%$#@!# ?#OPQRSQTUQY]X[WXVZXVWXYZX[]XRUQTPQOSQ]Y^W[^ZV^PO_SR_UT_UR_PT_SO_WV^ZY^][^',\n 'R -3 2/m': ' !## !!# %$&$&%&%$$%&&$%%&$! # #!#! ',\n 'H -3 2/c': ' !#%?#@$#! -?%-$@-$%&!@&? &%$+@!+ ?+OPQRSQTUQY]b[WbVZbVWXYZX[]XRU`TP`OS`]Y^W[^ZV^POcSRcUTcUR_PT_SO_WVaZYa][a',\n 'R -3 2/c': \" !## !!# 102021210$%&&$%%&$'././'/'.\",\n 'P 6': ' !#%?#@$#$%#!@#? #',\n 'P 61': ' !#%?A@$B$%/!@d? e',\n 'P 65': ' !#%?B@$A$%/!@e? d',\n 'P 62': ' !#%?^@$Q$%#!@^? Q',\n 'P 64': ' !#%?Q@$^$%#!@Q? ^',\n 'P 63': ' !#%?#@$#$%+!@+? +',\n 'P -6': ' !#%?#@$# !&%?&@$&',\n 'P 6/m': ' !#%?#@$#$%#!@#? #$%&!@&? & !&%?&@$&',\n 'P 63/m': ' !#%?#@$#$%+!@+? +$%&!@&? & !-%?-@$-',\n 'P 6 2 2': ' !#%?#@$#$%#!@#? #! &?%&$@&%$&@!& ?&',\n 'P 61 2 2': ' !#%?Q@$^$%+!@`? a! X?%&$@_%$b@!- ?c',\n 'P 65 2 2': ' !#%?^@$Q$%+!@a? `! _?%&$@X%$c@!- ?b',\n 'P 62 2 2': ' !#%?^@$Q$%#!@^? Q! _?%&$@X%$_@!& ?X',\n 'P 64 2 2': ' !#%?Q@$^$%#!@Q? ^! X?%&$@_%$X@!& ?_',\n 'P 63 2 2': ' !#%?#@$#$%+!@+? +! &?%&$@&%$-@!- ?-',\n 'P 6 m m': ' !#%?#@$#$%#!@#? #%$#@!# ?#! #?%#$@#',\n 'P 6 c c': ' !#%?#@$#$%#!@#? #%$+@!+ ?+! +?%+$@+',\n 'P 63 c m': ' !#%?#@$#$%+!@+? +%$+@!+ ?+! #?%#$@#',\n 'P 63 m c': ' !#%?#@$#$%+!@+? +%$#@!# ?#! +?%+$@+',\n 'P -6 m 2': ' !#%?#@$# !&%?&@$&%$#@!# ?#%$&@!& ?&',\n 'P -6 c 2': ' !#%?#@$# !-%?-@$-%$+@!+ ?+%$&@!& ?&',\n 'P -6 2 m': ' !#%?#@$# !&%?&@$&! &?%&$@&! #?%#$@#',\n 'P -6 2 c': ' !#%?#@$# !-%?-@$-! &?%&$@&! +?%+$@+',\n 'P 6/m 2/m 2/m': ' !#%?#@$#$%#!@#? #! &?%&$@&%$&@!& ?&$%&!@&? & !&@$&%?&%$#@!# ?#! #?%#$@#',\n 'P 6/m 2/c 2/c': ' !#%?#@$#$%#!@#? #! -?%-$@-%$-@!- ?-$%&!@&? & !&@$&%?&%$+@!+ ?+! +?%+$@+',\n 'P 63/m 2/c 2/m': ' !#%?#@$#$%+!@+? +! -?%-$@-%$&@!& ?&$%&!@&? & !-@$-%?-%$+@!+ ?+! #?%#$@#',\n 'P 63/m 2/m 2/c': ' !#%?#@$#$%+!@+? +! &?%&$@&%$-@!- ?-$%&!@&? & !-@$-%?-%$#@!# ?#! +?%+$@+',\n 'P 2 3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ',\n 'F 2 3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ',\n 'I 2 3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-(',\n 'P 21 3': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(',\n 'I 21 3': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- ',\n 'P 2/m -3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$',\n 'P 2/n -3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& *,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*',\n 'F 2/m -3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$ )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-($,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(*%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- *,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$',\n 'F 2/d -3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& 64=37=345675=64=375345674=67=3453756 )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(68>3:>3896:9=<8=;:5;85<:4><7>;49;79<(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(<4>;7>;49<79>68>3:93896:8=<:=;85;:5<()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- <8=;:=;8f<:f><4>;79;49<78>6:>3893:96',\n 'I 2/m -3': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& $%& !& %#$!#&$%& !# %#$!%&$!& %# !#$()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-(*,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*',\n 'P 21/a -3': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&($%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*',\n 'I 21/a -3': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&($%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*()+$,#*g& %-+()#$,&*!- %)+(,#$!&*%- *,- )&(%#$!+-*,& )#(%+$!,-*)& %#(!+$',\n 'P 4 3 2': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$',\n 'P 42 3 2': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*',\n 'F 4 3 2': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$ )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(-%*-!*+%(+ +,$+)$-, -)#)*#,(&)(&,*(!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() -,$-)$+, +(#,*#)*&,(&)+!*+%(-!(-%*()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(&,*&)*#,(#(+%*+!*-%(-!+)$+, -) -,$',\n 'F 41 3 2': ' !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=46 )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<(!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>86',\n 'I 4 3 2': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*',\n 'P 43 3 2': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(7;>46=:<5839398<5:6=4;>75:<983>7;=46',\n 'P 41 3 2': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<',\n 'I 41 3 2': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- 7;>46=:<5839398<5:6=4;>75:<983>7;=46',\n 'P -4 3 m': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% ',\n 'F -4 3 m': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(+%*+!*-%(- +)$+,$-) -,#)(#,*&)*&,((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() +,$+)$-, -(#)*#,*&)(&,+!(+%*-!*-%(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(#,*#)*&,(&(+!*+%*-!(-%+) +,$-)$-, ',\n 'I -4 3 m': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! #%$#!$&% & #!$#%$&! &%#! #%$&!$&% ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,(',\n 'P -4 3 n': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,(',\n 'F -4 3 c': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(+,*+)*-,(-(+)*+,*-)(-,+)(+,*-)*-,( )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-() #,$#)$&, &(#!*#%*&!(&%+! +%$-!$-% (!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(!(#%*#!*&%(& +!$+%$-! -%#) #,$&)$&, ()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ! +%$+!$-% - #)$#,$&) &,#!(#%*&!*&%(',\n 'I -4 3 d': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(7354<9:6>8;=357<946>:;=857394<>:6=8;()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- :;98657<=43>;9:658<=73>49:;586=7<>43',\n 'P 4/m -3 2/m': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ',\n 'P 4/n -3 2/n': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$*,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(',\n 'P 42/m -3 2/n': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(',\n 'P 42/n -3 2/m': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,**,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ',\n 'F 4/m -3 2/m': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-(!(-%*-!*+%(+ +,$+)$-, -)#)*#,(&)(&,*$,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*%*+!(+%(-!*-$-) -, +)$+,&,(&)*#,*#)((!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&() -,$-)$+, +(#,*#)*&,(&)+!*+%(-!(-%**%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*,$+) +, -)$-*&)(&,(#)*#,-%(-!*+%*+!(()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- )(&,*&)*#,(#(+%*+!*-%(-!+)$+, -) -,$*,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$,*#)(#,(&)*&*-!(-%(+!*+%-, -)$+,$+) ',\n 'F 4/m -3 2/c': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& )(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,*$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)( )+$,+$)- ,-#()#*,&*)&(,!+(%+*!-*%-() &,$&)$#, #(#%*#!*&%(&!+!$+% -! -%$$,- )- ,+$)+&*,&()#(,#*)%-*!-(%+(!+*,$#) #, &)$&*&!(&%(#!*#%-% -!$+%$+! (!+*%+*!-(%-+ )+$,-$)- ,)#(,#*)&*,&(!(&%*&!*#%(# +%$+!$-% -!#)$#, &) &,$*%-(!-(%+*!+-$,- )+ ,+$),&*)&(,#()#*%*#!(#%(&!*&$-! -% +!$+%&, &)$#,$#) ()#*,#*)&(,&+(!+*%-*!-(%)+ ,+$)-$,- ! -%$-!$+% + #,$#)$&, &)#!*#%(&!(&%**,&()&(,#*)#-*%-(!+(%+*!,-$)- ,+ )+$%$+! +% -!$-$&) &, #)$#,&%(&!*#%*#!(',\n 'F 41/d -3 2/m': ' !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=4664=3:>;85<79=64>3:5;89<74=6:>385;79<,$+! #%(-)*&*&)(-% #!$+,-%(&)*+,$#! )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<68>37=;49<:5=<8>;753496:4><:=;893756,*#!(+% &)$-*-!(&, +)$#%-, &!$+%*#)((!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<<4>;:=389675>68=379;45<:8=<7>;453:96%$#) +,(&!*-$&! -,(#)*+%&% -)$#,*+!(()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>86<8=;7>3456:9><4=;:9385678>67=349;:5<%*+)(#, -!$&$-) &%(+!*#,&,(-!*#%$+) ',\n 'F 41/d -3 2/c': ' !#$,+*)&(%-# !+$,&*)-(%!# ,+$)&*%-(:3>46=7<98;5;58<976=43>:97<58;>:3=46<8>;7=3496:5><8=;793456:8><7=;493:56%*#)(+, &!$-$-! &,(+)*#%&, -!$#%*+)( )+$%#*!-(,&#()+*%&$!- ,!+(,#*)-$%& :;=4<>765839;94<5:6>83=79:6543>7;=8<<4=;:>385679>64=3:9;85<78=67>345;:9<%$+) #,(-!*&$&) -%(#!*+,&%(-)*#,$+! (!+*,#$)- %&+ )#$%-*!&(,)#(%+*!&$,- 73=86>:<54;935469:<=8;>7576983=:;>4<68=37>;45<:9=<4>;:5389674>6:=389;75<,*+!(#% -)$&*-)(&% +!$#,-,(&!*+%$#) ()#*%+$!& ,-+(!#*,-$)& %)+ %#$!-*,&(7;>8<=:69435398657<>4;=:5:<94;=73>8664>3:=;89<75=68>375;49<:4=<:>;853796,$#! +%(&)*-*&!(-, #)$+%-% &)$+,*#!(',\n 'I 4/m -3 2/m': ' !#$%#$!& %&# !#$%&$!& %!# %#$!&$%& ! &%$&!$#% # #%$#!$&% &!#!$#% &! &%$$%& !& %#$!#&$%& !# %#$!%&$!& %# !#$%$#! #% &!$&$&! &% #!$#%&% &!$#%$#! ()+*,+*)-(,-+()+*,-*)-(,)+(,+*)-*,-()(-,*-)*+,(+(+,*+)*-,(-)+)*+,(-)(-,**,-()-(,+*)+-*,-()+(,+*),-*)-(,+()+*,*+)(+,(-)*-*-)(-,(+)*+,-,(-)*+,*+)(',\n 'I 41/a -3 2/d': ' !#*%+$)-(,&# !+*%-$)&(,!# %+*)-$,&(:3=8<>7694;5;54697<>83=:97654;=:3>8<$%&(!- ,+*)#&$%-(!+ ,#*)%&$!-(,+ )#*4<97358;=:6>6>:;=8357<94=8;>:694<573()+$,#*!& %-+()#$,&*!- %)+(,#$!&*%- 7;>46=:<5839398<5:6=4;>75:<983>7;=46*,- )&(%#$!+-*,& )#(%+$!,-*)& %#(!+$865:;943>7<=<=73>4;9:658>43=7<5869:;',\n 'P 1 1 2': ' !#$%#',\n 'P 1 1 21': ' !#$%+',\n 'B 1 1 2': ' !#$%#(g+*%+',\n 'A 1 2 1': ' !#$!& )+$)-',\n 'C 1 21 1': ' !#$)&()#*!&',\n 'I 1 2 1': \" !#$!&.'/0'2\",\n 'I 1 21 1': \" !#$)&.'/0!-\",\n 'P 1 1 m': ' !# !&',\n 'P 1 1 b': ' !# )&',\n 'B 1 1 m': ' !# !&(!+(!-',\n 'B 1 1 b': ' !# )&(!+()-',\n 'P 1 1 2/m': ' !# !&$%#$%&',\n 'P 1 1 21/m': ' !#$%+$%& !-',\n 'B 1 1 2/m': ' !# !&$%#$%&(!+(!-*%+*%-',\n 'P 1 1 2/b': ' !#$,#$%& )&',\n 'P 1 1 21/b': ' !#$%&$,+ )-',\n 'B 1 1 2/b': ' !#$,#$%& )&(!+*,+*%-()-',\n 'P 21 2 2': ' !#$!&(%&*%#',\n 'P 2 21 2': ' !# ,&$)&$%#',\n 'P 21 21 2 (a)': \" !#*,#.%&$'&\",\n 'P 21 2 21': ' !#$!&(%-*%+',\n 'P 2 21 21': ' !# %&$)-$,+',\n 'C 2 2 21a)': ' !#*%+(,&$)-()#$,+ %&*!-',\n 'C 2 2 2a': \" !#*,#.%&$'&()#$%# ,&*!&\",\n 'F 2 2 2a': \" !#*,#.%&$'& '/*%/.12$!2.!/$,/ %20'2.'#$%# 1&0!&\",\n 'I 2 2 2a': \" !#*,#.%&$'&()+$%+*!- ,-\",\n 'P 21/m 21/m 2/n a': \" !#*,#$)&(%&$%&.'& ,#*!#\",\n 'P 42 21 2a': \" !#*,#%.+'$+$'&.%&! -,*-\",\n 'I 2 3a': \" !#*,#.%&$'&!# ,- '&$%/$# !-*!/$%&.%()+$%+ ,-*!-)+(%&(!-*,#*+()&$)#*,- ,\"\n}\n","/**\n * @file Symmetry Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4 } from 'three'\n\nimport { Log } from '../globals'\nimport { EncodedSymOp, SymOpCode } from './symmetry-constants'\n\nconst reInteger = /^[1-9]$/\n\nexport function getSymmetryOperations (spacegroup: string) {\n const encodedSymopList = EncodedSymOp[ spacegroup ]\n const matrixDict: { [k: string]: Matrix4 } = {}\n\n if (encodedSymopList === undefined) {\n console.warn(`spacegroup '${spacegroup}' not found in symop library`)\n return matrixDict\n }\n\n const symopList = []\n for (let i = 0, il = encodedSymopList.length; i < il; i += 3) {\n const symop = []\n for (let j = 0; j < 3; ++j) {\n symop.push(SymOpCode[ encodedSymopList[ i + j ] ])\n }\n symopList.push(symop)\n }\n\n symopList.forEach(function (symop) {\n let row = 0\n const matrix = new Matrix4().set(\n 0, 0, 0, 0,\n 0, 0, 0, 0,\n 0, 0, 0, 0,\n 0, 0, 0, 1\n )\n const me = matrix.elements\n\n matrixDict[ symop.toString() ] = matrix\n\n symop.forEach(function (elm) {\n let negate = false\n let denominator = false\n\n for (let i = 0, n = elm.length; i < n; ++i) {\n const c = elm[ i ]\n\n if (c === '-') {\n negate = true\n } else if (c === '+') {\n negate = false\n } else if (c === '/') {\n denominator = true\n } else if (c === 'X') {\n me[ 0 + row ] = negate ? -1 : 1\n } else if (c === 'Y') {\n me[ 4 + row ] = negate ? -1 : 1\n } else if (c === 'Z') {\n me[ 8 + row ] = negate ? -1 : 1\n } else if (reInteger.test(c)) {\n const integer = parseInt(c)\n if (denominator) {\n me[ 12 + row ] /= integer\n } else {\n me[ 12 + row ] = integer\n }\n } else {\n Log.warn(`getSymmetryOperations: unknown token '${c}'`)\n }\n }\n\n row += 1\n })\n })\n\n return matrixDict\n}\n","/**\n * @file Assembly\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4, Box3, Vector3 } from 'three'\n\nimport { uniqueArray } from '../utils'\nimport Selection from '../selection/selection'\nimport Structure from '../structure/structure'\nimport StructureView from '../structure/structure-view';\n\nfunction selectionFromChains (chainList: string[]) {\n let sele = ''\n if (chainList.length > 0) {\n sele = ':' + uniqueArray(chainList).join(' OR :')\n }\n return new Selection(sele)\n}\n\n/**\n * Assembly of transformed parts of a {@link Structure}\n */\nclass Assembly {\n partList: AssemblyPart[] = []\n\n /**\n * @param {String} name - assembly name\n */\n constructor (readonly name = '') {}\n\n get type () { return 'Assembly' }\n\n /**\n * Add transformed parts to the assembly\n * @example\n * var m1 = new NGL.Matrix4().set( ... );\n * var m2 = new NGL.Matrix4().set( ... );\n * var assembly = new NGL.Assembly( \"myAssembly\" );\n * // add part that transforms chain 'A' and 'B' using matrices `m1` and `m2`\n * assembly.addPart( [ m1, m2 ], [ \"A\", \"B\" ] )\n *\n * @param {Matrix4[]} matrixList - array of 4x4 transformation matrices\n * @param {String[]} chainList - array of chain names\n * @return {AssemblyPart} the added assembly part\n */\n addPart (matrixList?: Matrix4[], chainList?: string[]) {\n const part = new AssemblyPart(matrixList, chainList)\n this.partList.push(part)\n return part\n }\n\n /**\n * Get the number of atom for a given structure\n * @param {Structure} structure - the given structure\n * @return {Integer} number of atoms in the assembly\n */\n getAtomCount (structure: Structure) {\n return this.partList.reduce(\n (count, part) => count + part.getAtomCount(structure), 0\n )\n }\n\n /**\n * Get the number of residues for a given structure\n * @param {Structure} structure - the given structure\n * @return {Integer} number of residues in the assembly\n */\n getResidueCount (structure: Structure) {\n return this.partList.reduce(\n (count, part) => count + part.getResidueCount(structure), 0\n )\n }\n\n /**\n * Get number of instances the assembly will produce, i.e.\n * the number of transformations performed by the assembly\n * @return {Integer} number of instances\n */\n getInstanceCount () {\n let instanceCount = 0\n\n this.partList.forEach(function (part) {\n instanceCount += part.matrixList.length\n })\n\n return instanceCount\n }\n\n /**\n * Determine if the assembly is the full and untransformed structure\n * @param {Structure} structure - the given structure\n * @return {Boolean} whether the assembly is identical to the structure\n */\n isIdentity (structure: Structure) {\n if (this.partList.length !== 1) return false\n\n const part = this.partList[ 0 ]\n if (part.matrixList.length !== 1) return false\n\n const identityMatrix = new Matrix4()\n if (!identityMatrix.equals(part.matrixList[ 0 ])) return false\n\n let structureChainList: string[] = []\n structure.eachChain(function (cp) {\n structureChainList.push(cp.chainname)\n })\n structureChainList = uniqueArray(structureChainList)\n if (part.chainList.length !== structureChainList.length) return false\n\n return true\n }\n\n getBoundingBox (structure: Structure) {\n const boundingBox = new Box3()\n\n this.partList.forEach(function (part) {\n const partBox = part.getBoundingBox(structure)\n boundingBox.expandByPoint(partBox.min)\n boundingBox.expandByPoint(partBox.max)\n })\n\n return boundingBox\n }\n\n getCenter (structure: Structure) {\n return this.getBoundingBox(structure).getCenter(new Vector3())\n }\n\n getSelection () {\n let chainList: string[] = []\n this.partList.forEach(function (part) {\n chainList = chainList.concat(part.chainList)\n })\n return selectionFromChains(chainList)\n }\n}\n\nexport class AssemblyPart {\n constructor (readonly matrixList: Matrix4[] = [], readonly chainList: string[] = []) {}\n\n get type () { return 'AssemblyPart' }\n\n _getCount (structure: Structure, propertyName: 'atomCount'|'residueCount') {\n let count = 0\n\n structure.eachChain(cp => {\n if (this.chainList.length === 0 || this.chainList.includes(cp.chainname)) {\n count += cp[ propertyName ]\n }\n })\n\n return this.matrixList.length * count\n }\n\n getAtomCount (structure: Structure) {\n return this._getCount(structure, 'atomCount')\n }\n\n getResidueCount (structure: Structure) {\n return this._getCount(structure, 'residueCount')\n }\n\n getBoundingBox (structure: Structure) {\n const partBox = new Box3()\n const instanceBox = new Box3()\n\n const selection = this.getSelection()\n const structureBox = structure.getBoundingBox(selection)\n\n this.matrixList.forEach(function (matrix) {\n instanceBox.copy(structureBox).applyMatrix4(matrix)\n partBox.expandByPoint(instanceBox.min)\n partBox.expandByPoint(instanceBox.max)\n })\n\n return partBox\n }\n\n getSelection () {\n return selectionFromChains(this.chainList)\n }\n\n getView (structure: Structure): Structure | StructureView {\n const selection = this.getSelection()\n if (selection) {\n return structure.getView(selection)\n } else {\n return structure\n }\n }\n\n getInstanceList () {\n const instanceList = []\n for (let j = 0, jl = this.matrixList.length; j < jl; ++j) {\n instanceList.push({\n id: j + 1,\n name: j,\n matrix: this.matrixList[ j ]\n })\n }\n return instanceList\n }\n}\n\nexport default Assembly\n","/**\n * @file Structure Builder\n * @author Alexander Rose \n * @private\n */\n\nimport Structure from './structure'\n\nclass StructureBuilder {\n currentModelindex: number|null = null\n currentChainid: string|null = null\n currentResname: string|null = null\n currentResno: number|null = null\n currentInscode: string|undefined = undefined\n currentHetero: boolean|null = null\n\n previousResname: string|null = ''\n previousHetero: boolean|null = null\n\n ai = -1\n ri = -1\n ci = -1\n mi = -1\n\n constructor(readonly structure: Structure) {}\n\n addResidueType (ri: number) {\n const atomStore = this.structure.atomStore\n const residueStore = this.structure.residueStore\n const residueMap = this.structure.residueMap\n const cc = this.structure.chemCompMap?.dict[this.previousResname!]\n\n const count = residueStore.atomCount[ ri ]\n const offset = residueStore.atomOffset[ ri ]\n const atomTypeIdList = new Array(count)\n for (let i = 0; i < count; ++i) {\n atomTypeIdList[ i ] = atomStore.atomTypeId[ offset + i ]\n }\n const chemCompType = cc?.chemCompType\n const bonds = cc ? this.structure.chemCompMap?.getBonds(this.previousResname!, atomTypeIdList) : undefined\n residueStore.residueTypeId[ ri ] = residueMap.add(\n this.previousResname!, atomTypeIdList, this.previousHetero!, chemCompType, bonds\n )\n }\n\n addAtom (modelindex: number, chainname: string, chainid: string, resname: string, resno: number, hetero: boolean, sstruc?: string|undefined, inscode?: string|undefined) {\n const atomStore = this.structure.atomStore\n const residueStore = this.structure.residueStore\n const chainStore = this.structure.chainStore\n const modelStore = this.structure.modelStore\n\n let addModel = false\n let addChain = false\n let addResidue = false\n\n if (this.currentModelindex !== modelindex) {\n addModel = true\n addChain = true\n addResidue = true\n this.mi += 1\n this.ci += 1\n this.ri += 1\n } else if (this.currentChainid !== chainid) {\n addChain = true\n addResidue = true\n this.ci += 1\n this.ri += 1\n } else if (this.currentResno !== resno || this.currentResname !== resname || this.currentInscode !== inscode) {\n addResidue = true\n this.ri += 1\n }\n this.ai += 1\n\n if (addModel) {\n modelStore.growIfFull()\n modelStore.chainOffset[ this.mi ] = this.ci\n modelStore.chainCount[ this.mi ] = 0\n modelStore.count += 1\n chainStore.modelIndex[ this.ci ] = this.mi\n }\n\n if (addChain) {\n chainStore.growIfFull()\n chainStore.setChainname(this.ci, chainname)\n chainStore.setChainid(this.ci, chainid)\n chainStore.residueOffset[ this.ci ] = this.ri\n chainStore.residueCount[ this.ci ] = 0\n chainStore.count += 1\n chainStore.modelIndex[ this.ci ] = this.mi\n modelStore.chainCount[ this.mi ] += 1\n residueStore.chainIndex[ this.ri ] = this.ci\n }\n\n if (addResidue) {\n this.previousResname = this.currentResname\n this.previousHetero = this.currentHetero\n if (this.ri > 0) this.addResidueType(this.ri - 1)\n residueStore.growIfFull()\n residueStore.resno[ this.ri ] = resno\n if (sstruc !== undefined) {\n residueStore.sstruc[ this.ri ] = sstruc.charCodeAt(0)\n }\n if (inscode !== undefined) {\n residueStore.inscode[ this.ri ] = inscode.charCodeAt(0)\n }\n residueStore.atomOffset[ this.ri ] = this.ai\n residueStore.atomCount[ this.ri ] = 0\n residueStore.count += 1\n residueStore.chainIndex[ this.ri ] = this.ci\n chainStore.residueCount[ this.ci ] += 1\n }\n\n atomStore.count += 1\n atomStore.residueIndex[ this.ai ] = this.ri\n residueStore.atomCount[ this.ri ] += 1\n\n this.currentModelindex = modelindex\n this.currentChainid = chainid\n this.currentResname = resname\n this.currentResno = resno\n this.currentInscode = inscode\n this.currentHetero = hetero\n }\n\n finalize () {\n this.previousResname = this.currentResname\n this.previousHetero = this.currentHetero\n if (this.ri > -1) this.addResidueType(this.ri)\n }\n}\n\nexport default StructureBuilder\n","/**\n * @file Structure Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Matrix4 } from 'three'\n\nimport { Debug, Log } from '../globals'\nimport { binarySearchIndexOf } from '../utils'\nimport Helixbundle from '../geometry/helixbundle'\nimport Kdtree from '../geometry/kdtree'\nimport { getSymmetryOperations } from '../symmetry/symmetry-utils'\nimport Assembly from '../symmetry/assembly'\nimport Structure from '../structure/structure'\nimport StructureBuilder from '../structure/structure-builder'\nimport Polymer from '../proxy/polymer'\nimport ResidueProxy from '../proxy/residue-proxy'\n\nimport { UnknownBackboneType, AA3, Bases, AtomicNumbers } from './structure-constants'\n\nexport function reorderAtoms (structure: Structure) {\n if (Debug) Log.time('reorderAtoms')\n\n var ap1 = structure.getAtomProxy()\n var ap2 = structure.getAtomProxy()\n\n function compareModelChainResno (index1: number, index2: number) {\n ap1.index = index1\n ap2.index = index2\n if (ap1.modelIndex < ap2.modelIndex) {\n return -1\n } else if (ap1.modelIndex > ap2.modelIndex) {\n return 1\n } else {\n if (ap1.chainname < ap2.chainname) {\n return -1\n } else if (ap1.chainname > ap2.chainname) {\n return 1\n } else {\n if (ap1.resno < ap2.resno) {\n return -1\n } else if (ap1.resno > ap2.resno) {\n return 1\n } else {\n return 0\n }\n }\n }\n }\n\n structure.atomStore.sort(compareModelChainResno)\n\n if (Debug) Log.timeEnd('reorderAtoms')\n}\n\nexport interface SecStruct {\n helices: [string, number, string, string, number, string, number][]\n sheets: [string, number, string, string, number, string][]\n}\n\nexport function assignSecondaryStructure (structure: Structure, secStruct: SecStruct) {\n if (!secStruct) return\n\n if (Debug) Log.time('assignSecondaryStructure')\n\n const chainnames: string[] = []\n structure.eachModel(function (mp) {\n mp.eachChain(function (cp) {\n chainnames.push(cp.chainname)\n })\n })\n\n const chainnamesSorted = chainnames.slice().sort()\n const chainnamesIndex: number[] = []\n chainnamesSorted.forEach(function (c) {\n chainnamesIndex.push(chainnames.indexOf(c))\n })\n\n // helix assignment\n\n const helices = secStruct.helices.filter(function (h) {\n return binarySearchIndexOf(chainnamesSorted, h[ 0 ]) >= 0\n })\n\n helices.sort(function (h1, h2) {\n const c1 = h1[ 0 ]\n const c2 = h2[ 0 ]\n const r1 = h1[ 1 ]\n const r2 = h2[ 1 ]\n\n if (c1 === c2) {\n if (r1 === r2) {\n return 0\n } else {\n return r1 < r2 ? -1 : 1\n }\n } else {\n const idx1 = binarySearchIndexOf(chainnamesSorted, c1)\n const idx2 = binarySearchIndexOf(chainnamesSorted, c2)\n return chainnamesIndex[ idx1 ] < chainnamesIndex[ idx2 ] ? -1 : 1\n }\n })\n\n const residueStore = structure.residueStore\n\n structure.eachModel(function (mp) {\n let i = 0\n const n = helices.length\n if (n === 0) return\n let helix = helices[ i ]\n let helixRun = false\n let done = false\n\n mp.eachChain(function (cp) {\n let chainChange = false\n\n if (cp.chainname === helix[ 0 ]) {\n const count = cp.residueCount\n const offset = cp.residueOffset\n const end = offset + count\n\n for (let j = offset; j < end; ++j) {\n if (residueStore.resno[ j ] === helix[ 1 ] && // resnoBeg\n residueStore.getInscode(j) === helix[ 2 ] // inscodeBeg\n ) {\n helixRun = true\n }\n\n if (helixRun) {\n residueStore.sstruc[ j ] = helix[ 6 ]\n\n if (residueStore.resno[ j ] === helix[ 4 ] && // resnoEnd\n residueStore.getInscode(j) === helix[ 5 ] // inscodeEnd\n ) {\n helixRun = false\n i += 1\n\n if (i < n) {\n // must look at previous residues as\n // residues may not be ordered by resno\n j = offset - 1\n helix = helices[ i ]\n chainChange = cp.chainname !== helix[ 0 ]\n } else {\n done = true\n }\n }\n }\n\n if (chainChange || done) return\n }\n }\n })\n })\n\n // sheet assignment\n\n const sheets = secStruct.sheets.filter(function (s) {\n return binarySearchIndexOf(chainnamesSorted, s[ 0 ]) >= 0\n })\n\n sheets.sort(function (s1, s2) {\n const c1 = s1[ 0 ]\n const c2 = s2[ 0 ]\n\n if (c1 === c2) return 0\n const idx1 = binarySearchIndexOf(chainnamesSorted, c1)\n const idx2 = binarySearchIndexOf(chainnamesSorted, c2)\n return chainnamesIndex[ idx1 ] < chainnamesIndex[ idx2 ] ? -1 : 1\n })\n\n const strandCharCode = 'e'.charCodeAt(0)\n structure.eachModel(function (mp) {\n let i = 0\n const n = sheets.length\n if (n === 0) return\n let sheet = sheets[ i ]\n let sheetRun = false\n let done = false\n\n mp.eachChain(function (cp) {\n let chainChange = false\n\n if (cp.chainname === sheet[ 0 ]) {\n const count = cp.residueCount\n const offset = cp.residueOffset\n const end = offset + count\n\n for (let j = offset; j < end; ++j) {\n if (residueStore.resno[ j ] === sheet[ 1 ] && // resnoBeg\n residueStore.getInscode(j) === sheet[ 2 ] // inscodeBeg\n ) {\n sheetRun = true\n }\n\n if (sheetRun) {\n residueStore.sstruc[ j ] = strandCharCode\n\n if (residueStore.resno[ j ] === sheet[ 4 ] && // resnoEnd\n residueStore.getInscode(j) === sheet[ 5 ] // inscodeEnd\n ) {\n sheetRun = false\n i += 1\n\n if (i < n) {\n // must look at previous residues as\n // residues may not be ordered by resno\n j = offset - 1\n sheet = sheets[ i ]\n chainChange = cp.chainname !== sheet[ 0 ]\n } else {\n done = true\n }\n }\n }\n\n if (chainChange || done) return\n }\n }\n })\n })\n\n if (Debug) Log.timeEnd('assignSecondaryStructure')\n}\n\nexport const calculateSecondaryStructure = (function () {\n // Implementation for proteins based on \"pv\"\n //\n // assigns secondary structure information based on a simple and very fast\n // algorithm published by Zhang and Skolnick in their TM-align paper.\n // Reference:\n //\n // TM-align: a protein structure alignment algorithm based on the Tm-score\n // (2005) NAR, 33(7) 2302-2309\n\n const zhangSkolnickSS = function (polymer: Polymer, i: number, distances: number[], delta: number) {\n const structure = polymer.structure\n const offset = polymer.residueIndexStart\n const rp1 = structure.getResidueProxy()\n const rp2 = structure.getResidueProxy()\n const ap1 = structure.getAtomProxy()\n const ap2 = structure.getAtomProxy()\n\n for (let j = Math.max(0, i - 2); j <= i; ++j) {\n for (let k = 2; k < 5; ++k) {\n if (j + k >= polymer.residueCount) {\n continue\n }\n\n rp1.index = offset + j\n rp2.index = offset + j + k\n ap1.index = rp1.traceAtomIndex\n ap2.index = rp2.traceAtomIndex\n\n const d = ap1.distanceTo(ap2)\n\n if (Math.abs(d - distances[ k - 2 ]) > delta) {\n return false\n }\n }\n }\n\n return true\n }\n\n const isHelical = function (polymer: Polymer, i: number) {\n const helixDistances = [ 5.45, 5.18, 6.37 ]\n const helixDelta = 2.1\n return zhangSkolnickSS(polymer, i, helixDistances, helixDelta)\n }\n\n const isSheet = function (polymer: Polymer, i: number) {\n const sheetDistances = [ 6.1, 10.4, 13.0 ]\n const sheetDelta = 1.42\n return zhangSkolnickSS(polymer, i, sheetDistances, sheetDelta)\n }\n\n const proteinPolymer = function (p: Polymer) {\n const residueStore = p.residueStore\n const offset = p.residueIndexStart\n for (let i = 0, il = p.residueCount; i < il; ++i) {\n let sstruc = 'c'\n if (isHelical(p, i)) {\n sstruc = 'h'\n } else if (isSheet(p, i)) {\n sstruc = 'e'\n }\n residueStore.sstruc[ offset + i ] = sstruc.charCodeAt(0)\n }\n }\n\n const cgPolymer = function (p: Polymer) {\n const localAngle = 20\n const centerDist = 2.0\n\n const residueStore = p.residueStore\n const offset = p.residueIndexStart\n\n const helixbundle = new Helixbundle(p)\n const pos = helixbundle.position\n\n const c1 = new Vector3()\n const c2 = new Vector3()\n\n for (let i = 0, il = p.residueCount; i < il; ++i) {\n c1.fromArray(pos.center as any, i * 3) // TODO\n c2.fromArray(pos.center as any, i * 3 + 3) // TODO\n const d = c1.distanceTo(c2)\n\n if (d < centerDist && d > 1.0 && pos.bending[ i ] < localAngle) {\n residueStore.sstruc[ offset + i ] = 'h'.charCodeAt(0)\n residueStore.sstruc[ offset + i + 1 ] = 'h'.charCodeAt(0)\n }\n }\n }\n\n return function calculateSecondaryStructure (structure: Structure) {\n if (Debug) Log.time('calculateSecondaryStructure')\n\n structure.eachPolymer(function (p) {\n // assign secondary structure\n if (p.residueCount < 4) return\n if (p.isCg()) {\n cgPolymer(p)\n } else if (p.isProtein()) {\n proteinPolymer(p)\n } else {\n return\n }\n\n // set lone secondary structure assignments to \"c\"\n let prevSstruc: string\n let sstrucCount = 0\n p.eachResidue(function (r: ResidueProxy) {\n if (r.sstruc === prevSstruc) {\n sstrucCount += 1\n } else {\n if (sstrucCount === 1) {\n r.index -= 1\n r.sstruc = 'c'\n }\n sstrucCount = 1\n prevSstruc = r.sstruc\n }\n })\n })\n\n if (Debug) Log.timeEnd('calculateSecondaryStructure')\n }\n}())\n\n// const ChainnameAlphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" +\n// \"abcdefghijklmnopqrstuvwxyz\" +\n// \"0123456789\";\nconst ChainnameAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\nexport function getChainname (index: number) {\n const n = ChainnameAlphabet.length\n let j = index\n let k = 0\n let chainname = ChainnameAlphabet[j % n]\n while (j >= n) {\n j = Math.floor(j / n)\n chainname += ChainnameAlphabet[j % n]\n k += 1\n }\n if (k >= 5) {\n Log.warn('chainname overflow')\n }\n return chainname\n}\n\ninterface ChainData {\n mIndex: number\n chainname: string\n rStart: number\n rCount: number\n}\n\n/**\n * When no chain names are set for the given structure, calculates\n * chains based on:\n * - polymer connectivity: when adjacent residues are not bonded, a new chain is created.\n * - non polymer chemical type: adjacent residues which are not polymers but are of the same\n * chemical type (e.g. water molecules) are grouped into the same chain.\n **/\nexport function calculateChainnames (structure: Structure, useExistingBonds = false) {\n if (Debug) Log.time('calculateChainnames')\n\n let doAutoChainName = true\n structure.eachChain(function (c) {\n if (c.chainname) doAutoChainName = false\n })\n\n if (doAutoChainName) {\n const modelStore = structure.modelStore\n const chainStore = structure.chainStore\n const residueStore = structure.residueStore\n\n const addChain = function (mIndex: number, chainname: string, rOffset: number, rCount: number) {\n const ci = chainStore.count\n for (let i = 0; i < rCount; ++i) {\n residueStore.chainIndex[ rOffset + i ] = ci\n }\n chainStore.growIfFull()\n chainStore.modelIndex[ ci ] = mIndex\n chainStore.setChainname(ci, chainname)\n chainStore.setChainid(ci, chainname)\n chainStore.residueOffset[ ci ] = rOffset\n chainStore.residueCount[ ci ] = rCount\n chainStore.count += 1\n modelStore.chainCount[ mIndex ] += 1\n }\n\n const ap1 = structure.getAtomProxy()\n const ap2 = structure.getAtomProxy()\n\n let i = 0\n let mi = 0\n let rStart = 0\n let rEnd = 0\n const chainData: ChainData[] = []\n\n if (residueStore.count === 1) {\n chainData.push({\n mIndex: 0,\n chainname: 'A',\n rStart: 0,\n rCount: 1\n })\n } else {\n structure.eachResidueN(2, function (rp1: ResidueProxy, rp2: ResidueProxy) {\n let newChain = false\n\n const bbType1 = rp1.backboneType\n const bbType2 = rp2.backboneType\n const bbTypeUnk = UnknownBackboneType\n\n rEnd = rp1.index\n\n if (rp1.modelIndex !== rp2.modelIndex) {\n newChain = true\n } else if (rp1.moleculeType !== rp2.moleculeType) {\n newChain = true\n } else if (bbType1 !== bbTypeUnk && bbType1 === bbType2) {\n ap1.index = rp1.backboneEndAtomIndex\n ap2.index = rp2.backboneStartAtomIndex\n if (useExistingBonds) {\n newChain = !ap1.hasBondTo(ap2)\n } else {\n newChain = !ap1.connectedTo(ap2)\n }\n }\n\n // current chain goes to end of the structure\n if (!newChain && rp2.index === residueStore.count - 1) {\n newChain = true\n rEnd = rp2.index\n }\n\n if (newChain) {\n chainData.push({\n mIndex: mi,\n chainname: getChainname(i),\n rStart: rStart,\n rCount: rEnd - rStart + 1\n })\n\n i += 1\n\n if (rp1.modelIndex !== rp2.modelIndex) {\n i = 0\n mi += 1\n }\n\n // new chain for the last residue of the structure\n if (rp2.index === residueStore.count - 1 && rEnd !== rp2.index) {\n chainData.push({\n mIndex: mi,\n chainname: getChainname(i),\n rStart: residueStore.count - 1,\n rCount: 1\n })\n }\n\n rStart = rp2.index\n rEnd = rp2.index\n }\n })\n }\n\n //\n\n chainStore.count = 0\n modelStore.chainCount.fill(0, 0, modelStore.count)\n modelStore.chainOffset.fill(0, 0, modelStore.count)\n chainData.forEach(function (d) {\n addChain(d.mIndex, d.chainname, d.rStart, d.rCount)\n })\n\n let chainOffset = 0\n structure.eachModel(function (mp) {\n modelStore.chainOffset[ mp.index ] = chainOffset\n chainOffset += modelStore.chainCount[ mp.index ]\n })\n }\n\n if (Debug) Log.timeEnd('calculateChainnames')\n}\n\nexport function calculateBonds (structure: Structure, inferBonds: InferBondsOptions='all') {\n if (inferBonds === 'none') return \n if (Debug) Log.time('calculateBonds')\n\n calculateBondsWithin(structure, false, inferBonds)\n calculateBondsBetween(structure)\n\n if (Debug) Log.timeEnd('calculateBonds')\n}\n\n/**\n * Should Bonds be inferred for `all` atoms, `none` or `auto`\n * If `auto`, any hetgroup residue with at least one CONECT record will \n * not have bonding inferred, and will rely on the CONECT records\n */\nexport type InferBondsOptions = 'all' | 'none' | 'auto'\n\nexport interface ResidueBonds {\n atomIndices1: number[]\n atomIndices2: number[]\n bondOrders: number[]\n}\n\n\nconst BondOrderTable: { [k: string]: number } = {\n 'HIS|CD2|CG': 2,\n 'HIS|CE1|ND1': 2,\n 'ARG|CZ|NH2': 2,\n 'PHE|CE1|CZ': 2,\n 'PHE|CD2|CE2': 2,\n 'PHE|CD1|CG': 2,\n 'TRP|CD1|CG': 2,\n 'TRP|CD2|CE2': 2,\n 'TRP|CE3|CZ3': 2,\n 'TRP|CH2|CZ2': 2,\n 'ASN|CG|OD1': 2,\n 'GLN|CD|OE1': 2,\n 'TYR|CD1|CG': 2,\n 'TYR|CD2|CE2': 2,\n 'TYR|CE1|CZ': 2,\n 'ASP|CG|OD1': 2,\n 'GLU|CD|OE1': 2,\n\n 'G|C8|N7': 2,\n 'G|C4|C5': 2,\n 'G|C2|N3': 2,\n 'G|C6|O6': 2,\n 'C|C4|N3': 2,\n 'C|C5|C6': 2,\n 'C|C2|O2': 2,\n 'A|C2|N3': 2,\n 'A|C6|N1': 2,\n 'A|C4|C5': 2,\n 'A|C8|N7': 2,\n 'U|C5|C6': 2,\n 'U|C2|O2': 2,\n 'U|C4|O4': 2,\n\n 'DG|C8|N7': 2,\n 'DG|C4|C5': 2,\n 'DG|C2|N3': 2,\n 'DG|C6|O6': 2,\n 'DC|C4|N3': 2,\n 'DC|C5|C6': 2,\n 'DC|C2|O2': 2,\n 'DA|C2|N3': 2,\n 'DA|C6|N1': 2,\n 'DA|C4|C5': 2,\n 'DA|C8|N7': 2,\n 'DT|C5|C6': 2,\n 'DT|C2|O2': 2,\n 'DT|C4|O4': 2\n}\nfunction getBondOrderFromTable (resname: string, atomname1: string, atomname2: string) {\n [ atomname1, atomname2 ] = atomname1 < atomname2 ? [ atomname1, atomname2 ] : [ atomname2, atomname1 ]\n if (AA3.includes(resname) && atomname1 === 'C' && atomname2 === 'O') return 2\n if (Bases.includes(resname) && atomname1 === 'OP1' && atomname2 === 'P') return 2\n return BondOrderTable[ `${resname}|${atomname1}|${atomname2}` ] || 1\n}\n\nexport function calculateResidueBonds (r: ResidueProxy) {\n const structure = r.structure\n const a1 = structure.getAtomProxy()\n const a2 = structure.getAtomProxy()\n\n const count = r.atomCount\n const offset = r.atomOffset\n const end = offset + count\n const end1 = end - 1\n\n const atomIndices1 = []\n const atomIndices2 = []\n const bondOrders = []\n\n if (count > 500) {\n if (Debug) Log.warn('more than 500 atoms, skip residue for auto-bonding', r.qualifiedName())\n } else {\n if (count > 50) {\n const kdtree = new Kdtree(r, true)\n const radius = r.isCg() ? 1.2 : 2.3\n\n for (let i = offset; i < end1; ++i) {\n a1.index = i\n const maxd = a1.covalent + radius + 0.3\n const nearestAtoms = kdtree.nearest(a1 as any, Infinity, maxd * maxd) // TODO\n const m = nearestAtoms.length\n for (let j = 0; j < m; ++j) {\n a2.index = nearestAtoms[ j ].index\n if (a1.index < a2.index) {\n if (a1.connectedTo(a2)) {\n atomIndices1.push(a1.index - offset)\n atomIndices2.push(a2.index - offset)\n bondOrders.push(getBondOrderFromTable(a1.resname, a1.atomname, a2.atomname))\n }\n }\n }\n }\n } else {\n for (let i = offset; i < end1; ++i) {\n a1.index = i\n for (let j = i + 1; j <= end1; ++j) {\n a2.index = j\n if (a1.connectedTo(a2)) {\n atomIndices1.push(i - offset)\n atomIndices2.push(j - offset)\n bondOrders.push(getBondOrderFromTable(a1.resname, a1.atomname, a2.atomname))\n }\n }\n }\n }\n }\n\n return {\n atomIndices1: atomIndices1,\n atomIndices2: atomIndices2,\n bondOrders: bondOrders\n }\n}\n\nexport function calculateAtomBondMap (structure: Structure) {\n if (Debug) Log.time('calculateAtomBondMap')\n\n var atomBondMap: number[][] = []\n\n structure.eachBond(function (bp) {\n var ai1 = bp.atomIndex1\n var ai2 = bp.atomIndex2\n if (atomBondMap[ ai1 ] === undefined) atomBondMap[ ai1 ] = []\n atomBondMap[ ai1 ][ ai2 ] = bp.index\n })\n\n if (Debug) Log.timeEnd('calculateAtomBondMap')\n\n return atomBondMap\n}\n\nexport function calculateBondsWithin (structure: Structure, onlyAddRung = false, inferBonds: InferBondsOptions='all') {\n if (Debug) Log.time('calculateBondsWithin')\n\n const bondStore = structure.bondStore\n const rungBondStore = structure.rungBondStore\n const rungAtomSet = structure.getAtomSet(false)\n const a1 = structure.getAtomProxy()\n const a2 = structure.getAtomProxy()\n const bp = structure.getBondProxy()\n const atomBondMap = onlyAddRung ? null : calculateAtomBondMap(structure)\n\n let bondedAtoms: Set\n if (!onlyAddRung && inferBonds === 'auto') {\n bondedAtoms = new Set()\n atomBondMap!.forEach((a, i) => {\n bondedAtoms.add(i)\n a.forEach(j => {bondedAtoms.add(j)})\n })\n }\n\n structure.eachResidue(function (r) {\n if (!onlyAddRung && atomBondMap) {\n const count = r.atomCount\n const offset = r.atomOffset\n\n if (count > 500) {\n Log.warn('more than 500 atoms, skip residue for auto-bonding', r.qualifiedName())\n return\n }\n\n if (inferBonds === 'auto' && r.hetero) {\n // Are bonds present on this residue?\n for (let rai=r.atomOffset; rai {\n ncsMatrixList.forEach(nm => {\n ncsUnitcellMatrixList.push(sm.clone().multiply(nm))\n })\n })\n unitcellAssembly.addPart(ncsUnitcellMatrixList)\n } else {\n unitcellAssembly.addPart(unitcellMatrixList)\n }\n\n const vec = new Vector3()\n const supercellAssembly = new Assembly('SUPERCELL')\n const supercellMatrixList = Array.prototype.concat.call(\n getMatrixList(vec.set(1, 0, 0)), // 655\n getMatrixList(vec.set(0, 1, 0)), // 565\n getMatrixList(vec.set(0, 0, 1)), // 556\n\n getMatrixList(vec.set(-1, 0, 0)), // 455\n getMatrixList(vec.set(0, -1, 0)), // 545\n getMatrixList(vec.set(0, 0, -1)), // 554\n\n getMatrixList(vec.set(1, 1, 0)), // 665\n getMatrixList(vec.set(1, 0, 1)), // 656\n getMatrixList(vec.set(0, 1, 1)), // 566\n\n getMatrixList(vec.set(-1, -1, 0)), // 445\n getMatrixList(vec.set(-1, 0, -1)), // 454\n getMatrixList(vec.set(0, -1, -1)), // 544\n\n getMatrixList(vec.set(1, -1, -1)), // 644\n getMatrixList(vec.set(1, 1, -1)), // 664\n getMatrixList(vec.set(1, -1, 1)), // 646\n getMatrixList(vec.set(-1, 1, 1)), // 466\n getMatrixList(vec.set(-1, -1, 1)), // 446\n getMatrixList(vec.set(-1, 1, -1)), // 464\n\n getMatrixList(vec.set(0, 1, -1)), // 564\n getMatrixList(vec.set(0, -1, 1)), // 546\n getMatrixList(vec.set(1, 0, -1)), // 654\n getMatrixList(vec.set(-1, 0, 1)), // 456\n getMatrixList(vec.set(1, -1, 0)), // 645\n getMatrixList(vec.set(-1, 1, 0)), // 465\n\n getMatrixList(), // 555\n getMatrixList(vec.set(1, 1, 1)), // 666\n getMatrixList(vec.set(-1, -1, -1)) // 444\n )\n if (structure.biomolDict.NCS) {\n const ncsSupercellMatrixList: Matrix4[] = []\n supercellMatrixList.forEach(function (sm: Matrix4) {\n ncsMatrixList.forEach(function (nm) {\n ncsSupercellMatrixList.push(sm.clone().multiply(nm))\n })\n })\n supercellAssembly.addPart(ncsSupercellMatrixList)\n } else {\n supercellAssembly.addPart(supercellMatrixList)\n }\n\n structure.biomolDict.UNITCELL = unitcellAssembly\n structure.biomolDict.SUPERCELL = supercellAssembly\n\n if (Debug) Log.timeEnd('buildUnitcellAssembly')\n}\n\nconst elm1 = [ 'H', 'C', 'O', 'N', 'S', 'P' ]\nconst elm2 = [ 'NA', 'CL', 'FE' ]\n\nexport function guessElement (atomName: string) {\n // Retain first group of letters in atomName\n let at = atomName.toUpperCase()\n let begin = 0, end = 0\n for (let i = 0; i < at.length ; i++) {\n if (at.charCodeAt(i) < 65) {\n if (end > 0) break\n ++begin\n }\n else end = i + 1\n }\n if (begin > 0 || end < at.length) at = at.substring(begin, end)\n \n const n = at.length\n\n if (n === 0) return ''\n if (n === 1) return at\n if (n === 2) {\n if (elm2.indexOf(at) !== -1) return at\n if (elm1.indexOf(at[0]) !== -1) return at[0]\n if (at in AtomicNumbers) return at\n }\n if (n >= 3) {\n if (elm1.indexOf(at[0]) !== -1) return at[0]\n }\n return ''\n}\n\n/**\n * Assigns ResidueType bonds.\n * @param {Structure} structure - the structure object\n * @return {undefined}\n */\nexport function assignResidueTypeBonds (structure: Structure) {\n // if( Debug ) Log.time( \"assignResidueTypeBonds\" )\n\n const bondHash = structure.bondHash! // TODO\n const countArray = bondHash.countArray\n const offsetArray = bondHash.offsetArray\n const indexArray = bondHash.indexArray\n const bp = structure.getBondProxy()\n\n structure.eachResidue(function (rp) {\n const residueType = rp.residueType\n if (residueType.bonds !== undefined) return\n\n var atomOffset = rp.atomOffset\n var atomIndices1: number[] = []\n var atomIndices2: number[] = []\n var bondOrders: number[] = []\n var bondDict: { [k: string]: boolean } = {}\n\n const nextAtomOffset = atomOffset + rp.atomCount\n\n rp.eachAtom(function (ap) {\n const index = ap.index\n const offset = offsetArray[ index ]\n const count = countArray[ index ]\n for (let i = 0, il = count; i < il; ++i) {\n bp.index = indexArray[ offset + i ]\n let idx1 = bp.atomIndex1\n if (idx1 < atomOffset || idx1 >= nextAtomOffset) {\n // Don't add bonds outside of this resiude\n continue\n }\n let idx2 = bp.atomIndex2\n if (idx2 < atomOffset || idx2 >= nextAtomOffset) {\n continue\n }\n\n if (idx1 > idx2) {\n const tmp = idx2\n idx2 = idx1\n idx1 = tmp\n }\n const hash = idx1 + '|' + idx2\n if (bondDict[ hash ] === undefined) {\n bondDict[ hash ] = true\n atomIndices1.push(idx1 - atomOffset)\n atomIndices2.push(idx2 - atomOffset)\n bondOrders.push(bp.bondOrder)\n }\n }\n })\n\n residueType.bonds = {\n atomIndices1: atomIndices1,\n atomIndices2: atomIndices2,\n bondOrders: bondOrders\n }\n })\n\n // if( Debug ) Log.timeEnd( \"assignResidueTypeBonds\" )\n}\n\nexport function concatStructures (name: string, ...structures: Structure[]) {\n if( Debug ) Log.time( \"concatStructures\" )\n\n const s = new Structure(name, '')\n const sb = new StructureBuilder(s)\n\n const atomStore = s.atomStore as any\n const atomMap = s.atomMap\n atomStore.addField('formalCharge', 1, 'int8')\n atomStore.addField('partialCharge', 1, 'float32')\n\n const atomIndexDict: { [k: number]: number } = {}\n\n let idx = 0\n let atomCount = 0\n let modelCount = 0\n structures.forEach(structure => {\n structure.eachAtom(a => {\n atomStore.growIfFull()\n atomStore.atomTypeId[ idx ] = atomMap.add(a.atomname, a.element)\n\n atomStore.x[ idx ] = a.x\n atomStore.y[ idx ] = a.y\n atomStore.z[ idx ] = a.z\n atomStore.serial[ idx ] = a.serial\n atomStore.formalCharge[ idx ] = a.formalCharge\n atomStore.partialCharge[ idx ] = a.partialCharge\n atomStore.altloc[ idx ] = a.altloc\n atomStore.occupancy[ idx ] = a.occupancy\n atomStore.bfactor[ idx ] = a.bfactor\n\n sb.addAtom(\n a.modelIndex + modelCount,\n a.chainname,\n a.chainid,\n a.resname,\n a.resno,\n a.hetero === 1,\n a.sstruc,\n a.inscode\n )\n\n atomIndexDict[a.index + atomCount] = idx\n idx += 1\n })\n atomCount += structure.atomStore.count\n modelCount += structure.modelStore.count\n })\n\n const bondStore = s.bondStore\n const a1 = s.getAtomProxy()\n const a2 = s.getAtomProxy()\n\n atomCount = 0\n structures.forEach(structure => {\n structure.eachBond(b => {\n a1.index = atomIndexDict[ b.atomIndex1 + atomCount ]\n a2.index = atomIndexDict[ b.atomIndex2 + atomCount ]\n bondStore.addBond(a1, a2, b.bondOrder)\n })\n atomCount += structure.atomStore.count\n })\n\n sb.finalize()\n\n calculateBondsBetween(s, true) // calculate backbone bonds\n calculateBondsWithin(s, true) // calculate rung bonds\n\n s.finalizeAtoms()\n s.finalizeBonds()\n assignResidueTypeBonds(s)\n\n if( Debug ) Log.timeEnd( \"concatStructures\" )\n\n return s\n}\n","/**\n * @file Atom Type\n * @author Alexander Rose \n * @private\n */\n\nimport { guessElement } from '../structure/structure-utils'\nimport {\n AtomicNumbers, DefaultAtomicNumber,\n VdwRadii, DefaultVdwRadius,\n CovalentRadii, DefaultCovalentRadius,\n Valences, DefaultValence,\n OuterShellElectronCounts, DefaultOuterShellElectronCount\n} from '../structure/structure-constants'\nimport Structure from '../structure/structure'\n\n// Li, Na, K, Rb, Cs Fr\nconst AlkaliMetals = [ 3, 11, 19, 37, 55, 87 ]\n\n// Be, Mg, Ca, Sr, Ba, Ra\nconst AlkalineEarthMetals = [ 4, 12, 20, 38, 56, 88 ]\n\n// C, P, S, Se\nconst PolyatomicNonmetals = [ 6, 15, 16, 34, ]\n\n// H, N, O, F, Cl, Br, I\nconst DiatomicNonmetals = [ 1, 7, 8, 9, 17, 35, 53 ]\n\n// He, Ne, Ar, Kr, Xe, Rn\nconst NobleGases = [ 2, 10, 18, 36, 54, 86 ]\n\n// Zn, Ga, Cd, In, Sn, Hg, Ti, Pb, Bi, Po, Cn\nconst PostTransitionMetals = [ 13, 30, 31, 48, 49, 50, 80, 81, 82, 83, 84, 85, 112 ]\n\n// B, Si, Ge, As, Sb, Te, At\nconst Metalloids = [ 5, 14, 32, 33, 51, 52, 85 ]\n\n// F, Cl, Br, I, At\nconst Halogens = [ 9, 17, 35, 53, 85 ]\n\n/**\n * Atom type\n */\nclass AtomType {\n element: string\n number: number\n vdw: number\n covalent: number\n\n /**\n * @param {Structure} structure - the structure object\n * @param {String} atomname - the name of the atom\n * @param {String} element - the chemical element\n */\n constructor (readonly structure: Structure, readonly atomname: string, element?: string) {\n element = element || guessElement(atomname)\n\n this.element = element\n this.number = AtomicNumbers[ element ] || DefaultAtomicNumber\n this.vdw = VdwRadii[ this.number ] || DefaultVdwRadius\n this.covalent = CovalentRadii[ this.number ] || DefaultCovalentRadius\n }\n\n getDefaultValence() {\n const vl = Valences[ this.number ]\n return vl ? vl[ 0 ] : DefaultValence\n }\n\n getValenceList () {\n return Valences[ this.number ] || []\n }\n\n getOuterShellElectronCount () {\n return OuterShellElectronCounts[ this.number ] || DefaultOuterShellElectronCount\n }\n\n isMetal () {\n return (\n this.isAlkaliMetal() ||\n this.isAlkalineEarthMetal() ||\n this.isLanthanide() ||\n this.isActinide() ||\n this.isTransitionMetal() ||\n this.isPostTransitionMetal()\n )\n }\n\n isNonmetal () {\n return (\n this.isDiatomicNonmetal() ||\n this.isPolyatomicNonmetal() ||\n this.isNobleGas()\n )\n }\n\n isMetalloid () {\n return Metalloids.includes(this.number)\n }\n\n isHalogen () {\n return Halogens.includes(this.number)\n }\n\n isDiatomicNonmetal () {\n return DiatomicNonmetals.includes(this.number)\n }\n\n isPolyatomicNonmetal () {\n return PolyatomicNonmetals.includes(this.number)\n }\n\n isAlkaliMetal () {\n return AlkaliMetals.includes(this.number)\n }\n\n isAlkalineEarthMetal () {\n return AlkalineEarthMetals.includes(this.number)\n }\n\n isNobleGas () {\n return NobleGases.includes(this.number)\n }\n\n isTransitionMetal () {\n const no = this.number\n return (\n (no >= 21 && no <= 29) ||\n (no >= 39 && no <= 47) ||\n (no >= 72 && no <= 79) ||\n (no >= 104 && no <= 108)\n )\n }\n\n isPostTransitionMetal () {\n return PostTransitionMetals.includes(this.number)\n }\n\n isLanthanide () {\n return this.number >= 57 && this.number <= 71\n }\n\n isActinide () {\n return this.number >= 89 && this.number <= 103\n }\n\n}\n\nexport default AtomType","/**\n * @file Atom Map\n * @author Alexander Rose \n * @private\n */\n\nimport AtomType from './atom-type'\nimport { guessElement } from '../structure/structure-utils'\nimport Structure from '../structure/structure'\n\nfunction getHash (atomname: string, element: string) {\n return atomname + '|' + element\n}\n\nclass AtomMap {\n dict: { [k: string]: number } = {}\n list: AtomType[] = []\n\n constructor (readonly structure: Structure) {\n this.structure = structure\n }\n\n add (atomname: string, element?: string) {\n atomname = atomname.toUpperCase()\n if (!element) {\n element = guessElement(atomname)\n } else {\n element = element.toUpperCase()\n }\n const hash = getHash(atomname, element)\n let id = this.dict[ hash ]\n if (id === undefined) {\n const atomType = new AtomType(this.structure, atomname, element)\n id = this.list.length\n this.dict[ hash ] = id\n this.list.push(atomType)\n }\n return id\n }\n\n get (id: number) {\n return this.list[ id ]\n }\n}\n\nexport default AtomMap\n","/**\n * @file Residue Type\n * @author Alexander Rose \n * @author Fred Ludlow\n * @private\n */\n\nimport { defaults } from '../utils'\nimport PrincipalAxes from '../math/principal-axes'\nimport { Matrix } from '../math/matrix-utils'\nimport { calculateResidueBonds, ResidueBonds } from '../structure/structure-utils'\nimport {\n Elements,\n ProteinType, RnaType, DnaType, WaterType, IonType, SaccharideType, UnknownType,\n ProteinBackboneType, RnaBackboneType, DnaBackboneType, UnknownBackboneType,\n CgProteinBackboneType, CgRnaBackboneType, CgDnaBackboneType,\n ChemCompProtein, ChemCompRna, ChemCompDna, ChemCompSaccharide,\n AA3, PurinBases, RnaBases, DnaBases, Bases, IonNames, WaterNames, SaccharideNames,\n ProteinBackboneAtoms, NucleicBackboneAtoms, ResidueTypeAtoms\n} from '../structure/structure-constants'\nimport Structure from '../structure/structure'\nimport ResidueProxy from '../proxy/residue-proxy'\nimport AtomProxy from '../proxy/atom-proxy'\n\nexport interface BondGraph {\n [k: number]: number[]\n}\n\nexport interface RingData {\n atomRings: number[][] // sparse array:\n // atomRings[atomIdx] -> array of ring indices\n rings: number[][] // rings as arrays of indices\n}\n\n/**\n * Residue type\n */\nexport default class ResidueType {\n resname: string\n atomTypeIdList: number[]\n hetero: number\n chemCompType: string\n bonds?: ResidueBonds\n rings?: RingData\n bondGraph?: BondGraph\n aromaticAtoms?: Uint8Array\n aromaticRings?: number[][]\n\n atomCount: number\n\n moleculeType: number\n backboneType: number\n backboneEndType: number\n backboneStartType: number\n backboneIndexList: number[]\n\n traceAtomIndex: number\n direction1AtomIndex: number\n direction2AtomIndex: number\n backboneStartAtomIndex: number\n backboneEndAtomIndex: number\n rungEndAtomIndex: number\n\n // Sparse array containing the reference atom index for each bond.\n bondReferenceAtomIndices: number[] = []\n\n /**\n * @param {Structure} structure - the structure object\n * @param {String} resname - name of the residue\n * @param {Array} atomTypeIdList - list of IDs of {@link AtomType}s corresponding\n * to the atoms of the residue\n * @param {Boolean} hetero - hetero flag\n * @param {String} chemCompType - chemical component type\n * @param {Object} [bonds] - TODO\n */\n constructor (readonly structure: Structure, resname: string, atomTypeIdList: number[], hetero: boolean, chemCompType: string, bonds?: ResidueBonds) {\n this.resname = resname\n this.atomTypeIdList = atomTypeIdList\n this.hetero = hetero ? 1 : 0\n this.chemCompType = chemCompType\n this.bonds = bonds\n this.atomCount = atomTypeIdList.length\n\n this.moleculeType = this.getMoleculeType()\n this.backboneType = this.getBackboneType(0)\n this.backboneEndType = this.getBackboneType(-1)\n this.backboneStartType = this.getBackboneType(1)\n this.backboneIndexList = this.getBackboneIndexList()\n\n const atomnames = ResidueTypeAtoms[ this.backboneType ]\n const atomnamesStart = ResidueTypeAtoms[ this.backboneStartType ]\n const atomnamesEnd = ResidueTypeAtoms[ this.backboneEndType ]\n\n const traceIndex = this.getAtomIndexByName(atomnames.trace)\n this.traceAtomIndex = defaults(traceIndex, -1)\n\n const dir1Index = this.getAtomIndexByName(atomnames.direction1)\n this.direction1AtomIndex = defaults(dir1Index, -1)\n\n const dir2Index = this.getAtomIndexByName(atomnames.direction2)\n this.direction2AtomIndex = defaults(dir2Index, -1)\n\n const bbStartIndex = this.getAtomIndexByName(atomnamesStart.backboneStart)\n this.backboneStartAtomIndex = defaults(bbStartIndex, -1)\n\n const bbEndIndex = this.getAtomIndexByName(atomnamesEnd.backboneEnd)\n this.backboneEndAtomIndex = defaults(bbEndIndex, -1)\n\n let rungEndIndex\n if (PurinBases.includes(resname)) {\n rungEndIndex = this.getAtomIndexByName('N1')\n } else {\n rungEndIndex = this.getAtomIndexByName('N3')\n }\n this.rungEndAtomIndex = defaults(rungEndIndex, -1)\n }\n\n getBackboneIndexList () {\n const backboneIndexList: number[] = []\n let atomnameList\n switch (this.moleculeType) {\n case ProteinType:\n atomnameList = ProteinBackboneAtoms\n break\n case RnaType:\n case DnaType:\n atomnameList = NucleicBackboneAtoms\n break\n default:\n return backboneIndexList\n }\n const atomMap = this.structure.atomMap\n const atomTypeIdList = this.atomTypeIdList\n for (let i = 0, il = this.atomCount; i < il; ++i) {\n const atomType = atomMap.get(atomTypeIdList[ i ])\n if (atomnameList.includes(atomType.atomname)) {\n backboneIndexList.push(i)\n }\n }\n return backboneIndexList\n }\n\n getMoleculeType () {\n if (this.isProtein()) {\n return ProteinType\n } else if (this.isRna()) {\n return RnaType\n } else if (this.isDna()) {\n return DnaType\n } else if (this.isWater()) {\n return WaterType\n } else if (this.isIon()) {\n return IonType\n } else if (this.isSaccharide()) {\n return SaccharideType\n } else {\n return UnknownType\n }\n }\n\n getBackboneType (position: number) {\n if (this.hasProteinBackbone(position)) {\n return ProteinBackboneType\n } else if (this.hasRnaBackbone(position)) {\n return RnaBackboneType\n } else if (this.hasDnaBackbone(position)) {\n return DnaBackboneType\n } else if (this.hasCgProteinBackbone(position)) {\n return CgProteinBackboneType\n } else if (this.hasCgRnaBackbone(position)) {\n return CgRnaBackboneType\n } else if (this.hasCgDnaBackbone(position)) {\n return CgDnaBackboneType\n } else {\n return UnknownBackboneType\n }\n }\n\n isProtein () {\n if (this.chemCompType) {\n return ChemCompProtein.includes(this.chemCompType)\n } else {\n return (\n this.hasAtomWithName('CA', 'C', 'N') ||\n AA3.includes(this.resname)\n )\n }\n }\n\n isCg () {\n const backboneType = this.backboneType\n return (\n backboneType === CgProteinBackboneType ||\n backboneType === CgRnaBackboneType ||\n backboneType === CgDnaBackboneType\n )\n }\n\n isNucleic () {\n return this.isRna() || this.isDna()\n }\n\n isRna () {\n if (this.chemCompType) {\n return ChemCompRna.includes(this.chemCompType)\n } else if (this.hetero === 1) {\n return false\n } else {\n return (\n this.hasAtomWithName(\n [ 'P', \"O3'\", 'O3*' ], [ \"C4'\", 'C4*' ], [ \"O2'\", 'O2*', \"F2'\", 'F2*' ]\n ) ||\n (RnaBases.includes(this.resname) &&\n (this.hasAtomWithName([ \"O2'\", 'O2*', \"F2'\", 'F2*' ])))\n )\n }\n }\n\n isDna () {\n if (this.chemCompType) {\n return ChemCompDna.includes(this.chemCompType)\n } else if (this.hetero === 1) {\n return false\n } else {\n return (\n (this.hasAtomWithName([ 'P', \"O3'\", 'O3*' ], [ \"C3'\", 'C3*' ]) &&\n !this.hasAtomWithName([ \"O2'\", 'O2*', \"F2'\", 'F2*' ])) ||\n DnaBases.includes(this.resname)\n )\n }\n }\n\n isHetero () {\n return this.hetero === 1\n }\n\n isIon () {\n return IonNames.includes(this.resname)\n }\n\n isWater () {\n return WaterNames.includes(this.resname)\n }\n\n isSaccharide () {\n if (this.chemCompType) {\n return ChemCompSaccharide.includes(this.chemCompType)\n } else {\n return SaccharideNames.includes(this.resname)\n }\n }\n\n isStandardAminoacid () {\n return AA3.includes(this.resname)\n }\n\n isStandardBase () {\n return Bases.includes(this.resname)\n }\n\n hasBackboneAtoms (position: number, type: number) {\n const atomnames = ResidueTypeAtoms[ type ]\n if (position === -1) {\n return this.hasAtomWithName(\n atomnames.trace,\n atomnames.backboneEnd,\n atomnames.direction1,\n atomnames.direction2\n )\n } else if (position === 0) {\n return this.hasAtomWithName(\n atomnames.trace,\n atomnames.direction1,\n atomnames.direction2\n )\n } else if (position === 1) {\n return this.hasAtomWithName(\n atomnames.trace,\n atomnames.backboneStart,\n atomnames.direction1,\n atomnames.direction2\n )\n } else {\n return this.hasAtomWithName(\n atomnames.trace,\n atomnames.backboneStart,\n atomnames.backboneEnd,\n atomnames.direction1,\n atomnames.direction2\n )\n }\n }\n\n hasProteinBackbone (position: number) {\n return (\n this.isProtein() &&\n this.hasBackboneAtoms(position, ProteinBackboneType)\n )\n }\n\n hasRnaBackbone (position: number) {\n return (\n this.isRna() &&\n this.hasBackboneAtoms(position, RnaBackboneType)\n )\n }\n\n hasDnaBackbone (position: number) {\n return (\n this.isDna() &&\n this.hasBackboneAtoms(position, DnaBackboneType)\n )\n }\n\n hasCgProteinBackbone (position: number) {\n return (\n this.atomCount < 7 &&\n this.isProtein() &&\n this.hasBackboneAtoms(position, CgProteinBackboneType)\n )\n }\n\n hasCgRnaBackbone (position: number) {\n return (\n this.atomCount < 11 &&\n this.isRna() &&\n this.hasBackboneAtoms(position, CgRnaBackboneType)\n )\n }\n\n hasCgDnaBackbone (position: number) {\n return (\n this.atomCount < 11 &&\n this.isDna() &&\n this.hasBackboneAtoms(position, CgDnaBackboneType)\n )\n }\n\n hasBackbone (position: number) {\n return (\n this.hasProteinBackbone(position) ||\n this.hasRnaBackbone(position) ||\n this.hasDnaBackbone(position) ||\n this.hasCgProteinBackbone(position) ||\n this.hasCgRnaBackbone(position) ||\n this.hasCgDnaBackbone(position)\n )\n }\n\n getAtomIndexByName (atomname: string|string[]) {\n const n = this.atomCount\n const atomMap = this.structure.atomMap\n const atomTypeIdList = this.atomTypeIdList\n if (Array.isArray(atomname)) {\n for (let i = 0; i < n; ++i) {\n const index = atomTypeIdList[ i ]\n if (atomname.includes(atomMap.get(index).atomname)) {\n return i\n }\n }\n } else {\n for (let i = 0; i < n; ++i) {\n const index = atomTypeIdList[ i ]\n if (atomname === atomMap.get(index).atomname) {\n return i\n }\n }\n }\n return undefined\n }\n\n hasAtomWithName (...atomnames: (string|string[])[]) {\n const n = atomnames.length\n for (let i = 0; i < n; ++i) {\n if (atomnames[ i ] === undefined) continue\n if (this.getAtomIndexByName(atomnames[ i ]) === undefined) {\n return false\n }\n }\n return true\n }\n\n getBonds (r?: ResidueProxy) {\n if (this.bonds === undefined) {\n this.bonds = calculateResidueBonds(r!) // TODO\n }\n return this.bonds\n }\n\n getRings () {\n if (this.rings === undefined) {\n this.calculateRings()\n }\n return this.rings\n }\n\n getBondGraph () {\n if (this.bondGraph === undefined) {\n this.calculateBondGraph()\n }\n return this.bondGraph\n }\n\n getAromatic (a?: AtomProxy) {\n if (this.aromaticAtoms === undefined) {\n this.calculateAromatic(this.structure.getResidueProxy((a!).residueIndex)) // TODO\n }\n return this.aromaticAtoms\n }\n\n getAromaticRings (r?: ResidueProxy) {\n if (this.aromaticRings === undefined) {\n this.calculateAromatic(r!) // TODO\n }\n return this.aromaticRings\n }\n\n /**\n * @return {Object} bondGraph - represents the bonding in this\n * residue: { ai1: [ ai2, ai3, ...], ...}\n */\n calculateBondGraph () {\n const bondGraph: BondGraph = this.bondGraph = {}\n const bonds = this.getBonds()\n const nb = bonds.atomIndices1.length\n const atomIndices1 = bonds.atomIndices1\n const atomIndices2 = bonds.atomIndices2\n\n for (let i = 0; i < nb; ++i) {\n const ai1 = atomIndices1[i]\n const ai2 = atomIndices2[i]\n\n const a1 = bondGraph[ ai1 ] = bondGraph[ ai1 ] || []\n a1.push(ai2)\n\n const a2 = bondGraph[ ai2 ] = bondGraph[ ai2 ] || []\n a2.push(ai1)\n }\n }\n\n /**\n * Find all rings up to 2 * RingFinderMaxDepth\n */\n calculateRings () {\n const bondGraph = this.getBondGraph()! // TODO\n const state = RingFinderState(bondGraph, this.atomCount)\n\n for (let i = 0; i < state.count; i++) {\n if (state.visited[i] >= 0) continue\n findRings(state, i)\n }\n\n this.rings = { atomRings: state.atomRings, rings: state.rings }\n }\n\n isAromatic (atom: AtomProxy) {\n this.aromaticAtoms = this.getAromatic(atom)! // TODO\n return this.aromaticAtoms[atom.index - atom.residueAtomOffset] === 1\n }\n\n calculateAromatic (r: ResidueProxy) {\n const aromaticAtoms = this.aromaticAtoms = new Uint8Array(this.atomCount)\n const rings = this.getRings()!.rings\n\n const aromaticRingFlags = rings.map(ring => {\n return isRingAromatic(ring.map(idx => {\n return this.structure.getAtomProxy(idx + r.atomOffset)\n }))\n })\n\n const aromaticRings: number[][] = this.aromaticRings = []\n rings.forEach((ring, i) => {\n if (aromaticRingFlags[i]) {\n aromaticRings.push(ring)\n ring.forEach(idx => aromaticAtoms[idx] = 1)\n }\n })\n }\n\n /**\n * For bonds with order > 1, pick a reference atom\n * @return {undefined}\n */\n assignBondReferenceAtomIndices () {\n const bondGraph = this.getBondGraph()! // TODO\n const rings = this.getRings()! // TODO\n const atomRings = rings.atomRings\n const ringData = rings.rings\n\n const bonds = this.bonds! // TODO\n const atomIndices1 = bonds.atomIndices1\n const atomIndices2 = bonds.atomIndices2\n const bondOrders = bonds.bondOrders\n const bondReferenceAtomIndices = this.bondReferenceAtomIndices\n\n const nb = bonds.atomIndices1.length\n\n bondReferenceAtomIndices.length = 0 // reset array\n\n for (let i = 0; i < nb; ++i) {\n // Not required for single bonds\n if (bondOrders[i] <= 1) continue\n\n let refRing\n\n const ai1 = atomIndices1[i]\n const ai2 = atomIndices2[i]\n\n const rings1 = atomRings[ ai1 ]\n const rings2 = atomRings[ ai2 ]\n // Are both atoms in a ring?\n if (rings1 && rings2) {\n // Are they in the same ring? (If not, ignore ring info)\n for (let ri1 = 0; ri1 < rings1.length; ri1++){\n if (rings2.indexOf(rings1[ ri1 ]) !== -1) {\n refRing = ringData[ rings1[ ri1 ] ]\n break\n }\n }\n }\n\n // Find the first neighbour.\n if (bondGraph[ ai1 ].length > 1) {\n for (let j = 0; j < bondGraph[ ai1 ].length; ++j) {\n const ai3 = bondGraph[ ai1 ][ j ]\n if (ai3 !== ai2) {\n if (refRing === undefined || refRing.indexOf(ai3) !== -1){\n bondReferenceAtomIndices[i] = ai3\n break\n }\n }\n }\n } else if (bondGraph[ ai2 ].length > 1) {\n for (let j = 0; j < bondGraph[ ai2 ].length; ++j) {\n const ai3 = bondGraph[ ai2 ][ j ]\n if (ai3 !== ai1) {\n if (refRing === undefined || refRing.indexOf(ai3) !== -1){\n bondReferenceAtomIndices[i] = ai3\n break\n }\n }\n }\n } // No reference atom could be found (e.g. diatomic molecule/fragment)\n }\n }\n\n getBondIndex (atomIndex1: number, atomIndex2: number) {\n const bonds = this.bonds! // TODO\n const atomIndices1 = bonds.atomIndices1\n const atomIndices2 = bonds.atomIndices2\n let idx1 = atomIndices1.indexOf(atomIndex1)\n let idx2 = atomIndices2.indexOf(atomIndex2)\n const _idx2 = idx2\n while (idx1 !== -1) {\n while (idx2 !== -1) {\n if (idx1 === idx2) return idx1\n idx2 = atomIndices2.indexOf(atomIndex2, idx2 + 1)\n }\n idx1 = atomIndices1.indexOf(atomIndex1, idx1 + 1)\n idx2 = _idx2\n }\n // returns undefined when no bond is found\n }\n\n getBondReferenceAtomIndex (atomIndex1: number, atomIndex2: number) {\n const bondIndex = this.getBondIndex(atomIndex1, atomIndex2)\n if (bondIndex === undefined) return undefined\n if (this.bondReferenceAtomIndices.length === 0) {\n this.assignBondReferenceAtomIndices()\n }\n return this.bondReferenceAtomIndices[ bondIndex ]\n }\n}\n\n//\n\nconst AromaticRingElements = [\n Elements.B, Elements.C, Elements.N, Elements.O,\n Elements.SI, Elements.P, Elements.S,\n Elements.GE, Elements.AS,\n Elements.SN, Elements.SB,\n Elements.BI\n]\nconst AromaticRingPlanarityThreshold = 0.05\n\nfunction isRingAromatic (ring: AtomProxy[]) {\n if (ring.some(a => !AromaticRingElements.includes(a.number))) return false\n\n let i = 0\n const coords = new Matrix(3, ring.length)\n const cd = coords.data\n\n ring.forEach(a => {\n cd[ i + 0 ] = a.x\n cd[ i + 1 ] = a.y\n cd[ i + 2 ] = a.z\n i += 3\n })\n\n const pa = new PrincipalAxes(coords)\n\n return pa.vecC.length() < AromaticRingPlanarityThreshold\n}\n\n//\n\n/**\n * Ring finding code below adapted from MolQL\n * Copyright (c) 2017 MolQL contributors, licensed under MIT\n * @author David Sehnal \n */\n\nfunction addRing(state: RingFinderState, a: number, b: number) {\n // only \"monotonous\" rings\n if (b < a) return\n\n const { pred, color, left, right } = state\n const nc = ++state.currentColor\n\n let current = a\n\n for (let t = 0; t < RingFinderMaxDepth; t++) {\n color[current] = nc\n current = pred[current]\n if (current < 0) break\n }\n\n let leftOffset = 0\n let rightOffset = 0\n\n let found = false\n let target = 0\n current = b\n for (let t = 0; t < RingFinderMaxDepth; t++) {\n if (color[current] === nc) {\n target = current\n found = true\n break\n }\n right[rightOffset++] = current\n current = pred[current]\n if (current < 0) break\n }\n if (!found) return\n\n current = a\n for (let t = 0; t < RingFinderMaxDepth; t++) {\n left[leftOffset++] = current\n if (target === current) break\n current = pred[current]\n if (current < 0) break\n }\n\n const rn = leftOffset + rightOffset\n const ring: number[] = new Array(rn)\n let ringOffset = 0;\n for (let t = 0; t < leftOffset; t++) {\n ring[ringOffset++] = left[t]\n }\n for (let t = rightOffset - 1; t >= 0; t--) {\n ring[ringOffset++] = right[t]\n }\n\n const ri = state.rings.length\n // set atomRing indices:\n for (let i = 0; i < rn; ++i) {\n const ai = ring[i]\n if (state.atomRings[ai]) {\n state.atomRings[ai].push(ri)\n } else {\n state.atomRings[ai] = [ri]\n }\n }\n\n state.rings.push(ring)\n}\n\nfunction findRings(state: RingFinderState, from: number) {\n const { bonds, visited, queue, pred } = state\n\n visited[from] = 1\n queue[0] = from\n\n let head = 0\n let size = 1\n\n while (head < size) {\n const top = queue[head++]\n const start = 0\n if (bonds[top] === undefined) {\n continue\n }\n const end = bonds[top].length\n\n for (let i = start; i < end; i++) {\n const other = bonds[top][i]\n\n if (visited[other] > 0) {\n if (pred[other] !== top && pred[top] !== other) {\n addRing(state, top, other)\n }\n continue\n }\n\n visited[other] = 1\n queue[size++] = other\n pred[other] = top\n }\n }\n}\n\nconst RingFinderMaxDepth = 4\n\ninterface RingFinderState {\n count: number,\n visited: Int32Array,\n queue: Int32Array,\n color: Int32Array,\n pred: Int32Array,\n\n left: Int32Array,\n right: Int32Array,\n\n currentColor: number,\n\n rings: number[][],\n atomRings: number[][],\n\n bonds: BondGraph\n}\n\nfunction RingFinderState(bonds: BondGraph, capacity: number): RingFinderState {\n const state = {\n count: capacity,\n visited: new Int32Array(capacity),\n queue: new Int32Array(capacity),\n pred: new Int32Array(capacity),\n left: new Int32Array(RingFinderMaxDepth),\n right: new Int32Array(RingFinderMaxDepth),\n color: new Int32Array(capacity),\n currentColor: 0,\n rings: [],\n atomRings: [],\n bonds\n }\n for (let i = 0; i < capacity; i++) {\n state.visited[i] = -1\n state.pred[i] = -1\n }\n return state\n}\n","/**\n * @file Residue Map\n * @author Alexander Rose \n * @private\n */\n\nimport Structure from '../structure/structure'\nimport { ResidueBonds } from '../structure/structure-utils'\nimport ResidueType from './residue-type'\n\nfunction getHash (resname: string, atomTypeIdList: number[], hetero: boolean, chemCompType = '') {\n return (\n resname + '|' +\n atomTypeIdList.join(',') + '|' +\n (hetero ? 1 : 0) + '|' +\n chemCompType\n )\n}\n\nclass ResidueMap {\n dict: { [k: string]: number } = {}\n list: ResidueType[] = []\n\n constructor (readonly structure: Structure) {}\n\n add (resname: string, atomTypeIdList: number[], hetero: boolean, chemCompType = '', bonds?: ResidueBonds) {\n resname = resname.toUpperCase()\n const hash = getHash(resname, atomTypeIdList, hetero, chemCompType)\n let id = this.dict[ hash ]\n if (id === undefined) {\n const residueType = new ResidueType(\n this.structure, resname, atomTypeIdList, hetero, chemCompType, bonds\n )\n id = this.list.length\n this.dict[ hash ] = id\n this.list.push(residueType)\n }\n return id\n }\n\n get (id: number) {\n return this.list[ id ]\n }\n}\n\nexport default ResidueMap\n","/**\n * @file Bond Proxy\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport Structure from '../structure/structure'\nimport BondStore from '../store/bond-store'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Bond proxy\n */\nclass BondProxy {\n index: number\n\n bondStore: BondStore\n\n private _v12: Vector3\n private _v13: Vector3\n private _ap1: AtomProxy\n private _ap2: AtomProxy\n private _ap3: AtomProxy\n\n /**\n * @param {Structure} structure - the structure\n * @param {Integer} index - the index\n */\n constructor (readonly structure: Structure, index = 0) {\n this.index = index\n this.bondStore = structure.bondStore\n\n this._v12 = new Vector3()\n this._v13 = new Vector3()\n this._ap1 = this.structure.getAtomProxy()\n this._ap2 = this.structure.getAtomProxy()\n this._ap3 = this.structure.getAtomProxy()\n }\n\n /**\n * @type {AtomProxy}\n */\n get atom1 () {\n return this.structure.getAtomProxy(this.atomIndex1)\n }\n\n /**\n * @type {AtomProxy}\n */\n get atom2 () {\n return this.structure.getAtomProxy(this.atomIndex2)\n }\n\n /**\n * @type {Integer}\n */\n get atomIndex1 () {\n return this.bondStore.atomIndex1[ this.index ]\n }\n set atomIndex1 (value) {\n this.bondStore.atomIndex1[ this.index ] = value\n }\n\n /**\n * @type {Integer}\n */\n get atomIndex2 () {\n return this.bondStore.atomIndex2[ this.index ]\n }\n set atomIndex2 (value) {\n this.bondStore.atomIndex2[ this.index ] = value\n }\n\n /**\n * @type {Integer}\n */\n get bondOrder () {\n return this.bondStore.bondOrder[ this.index ]\n }\n set bondOrder (value) {\n this.bondStore.bondOrder[ this.index ] = value\n }\n\n getOtherAtomIndex (atomIndex: number) {\n return atomIndex === this.atomIndex1 ? this.atomIndex2 : this.atomIndex1\n }\n\n getOtherAtom (atom: AtomProxy) {\n return this.structure.getAtomProxy(this.getOtherAtomIndex(atom.index))\n }\n\n /**\n * Get reference atom index for the bond\n * @return {Integer|undefined} atom index, or `undefined` if unavailable\n */\n getReferenceAtomIndex () {\n const ap1 = this._ap1\n const ap2 = this._ap2\n ap1.index = this.atomIndex1\n ap2.index = this.atomIndex2\n if (ap1.residueIndex !== ap2.residueIndex) {\n return undefined // Bond between residues, for now ignore (could detect)\n }\n const typeAtomIndex1 = ap1.index - ap1.residueAtomOffset\n const typeAtomIndex2 = ap2.index - ap2.residueAtomOffset\n const residueType = ap1.residueType\n const ix = residueType.getBondReferenceAtomIndex(typeAtomIndex1, typeAtomIndex2)\n if (ix !== undefined) {\n return ix + ap1.residueAtomOffset\n } else {\n console.warn('No reference atom found', ap1.index, ap2.index)\n }\n }\n\n /**\n * calculate shift direction for displaying double/triple bonds\n * @param {Vector3} [v] pre-allocated output vector\n * @return {Vector3} the shift direction vector\n */\n calculateShiftDir (v = new Vector3()) {\n const ap1 = this._ap1\n const ap2 = this._ap2\n const ap3 = this._ap3\n const v12 = this._v12\n const v13 = this._v13\n\n ap1.index = this.atomIndex1\n ap2.index = this.atomIndex2\n const ai3 = this.getReferenceAtomIndex()\n\n v12.subVectors(ap1 as any, ap2 as any).normalize() // TODO\n if (ai3 !== undefined) {\n ap3.index = ai3\n v13.subVectors(ap1 as any, ap3 as any) // TODO\n } else {\n v13.copy(ap1 as any) // no reference point, use origin // TODO\n }\n v13.normalize()\n\n // make sure v13 and v12 are not colinear\n let dp = v12.dot(v13)\n if (1 - Math.abs(dp) < 1e-5) {\n v13.set(1, 0, 0)\n dp = v12.dot(v13)\n if (1 - Math.abs(dp) < 1e-5) {\n v13.set(0, 1, 0)\n dp = v12.dot(v13)\n }\n }\n\n return v.copy(v13.sub(v12.multiplyScalar(dp))).normalize()\n }\n\n qualifiedName () {\n return this.atomIndex1 + '=' + this.atomIndex2\n }\n\n /**\n * Clone object\n * @return {BondProxy} cloned bond\n */\n clone () {\n return new BondProxy(this.structure, this.index)\n }\n\n toObject () {\n return {\n atomIndex1: this.atomIndex1,\n atomIndex2: this.atomIndex2,\n bondOrder: this.bondOrder\n }\n }\n}\n\nexport default BondProxy\n","/**\n * @file Residue Proxy\n * @author Alexander Rose \n * @private\n */\n\nimport { NumberArray } from '../types'\nimport { defaults } from '../utils'\nimport {\n SecStrucHelix, SecStrucSheet, SecStrucTurn,\n ProteinType, RnaType, DnaType, WaterType, IonType, SaccharideType,\n CgProteinBackboneType, CgRnaBackboneType, CgDnaBackboneType,\n AA1\n} from '../structure/structure-constants'\n\nimport Structure from '../structure/structure'\nimport Selection from '../selection/selection'\n\nimport ChainStore from '../store/chain-store'\nimport ResidueStore from '../store/residue-store'\nimport AtomStore from '../store/atom-store'\n\nimport AtomMap from '../store/atom-map'\nimport ResidueMap from '../store/residue-map'\n\nimport AtomProxy from '../proxy/atom-proxy'\nimport ResidueType, { RingData } from '../store/residue-type';\nimport { ResidueBonds } from '../structure/structure-utils';\nimport AtomType from '../store/atom-type';\nimport ChainProxy from './chain-proxy';\nimport Entity from '../structure/entity';\n\n/**\n * Residue proxy\n */\nclass ResidueProxy {\n index: number\n\n chainStore: ChainStore\n residueStore: ResidueStore\n atomStore: AtomStore\n\n residueMap: ResidueMap\n atomMap: AtomMap\n\n /**\n * @param {Structure} structure - the structure\n * @param {Integer} index - the index\n */\n constructor (readonly structure: Structure, index = 0) {\n this.index = index\n this.chainStore = structure.chainStore\n this.residueStore = structure.residueStore\n this.atomStore = structure.atomStore\n this.residueMap = structure.residueMap\n this.atomMap = structure.atomMap\n }\n\n /**\n * Entity\n * @type {Entity}\n */\n get entity (): Entity {\n return this.structure.entityList[ this.entityIndex ]\n }\n get entityIndex () {\n return this.chainStore.entityIndex[ this.chainIndex ]\n }\n /**\n * Chain\n * @type {ChainProxy}\n */\n get chain (): ChainProxy {\n return this.structure.getChainProxy(this.chainIndex)\n }\n\n get chainIndex () {\n return this.residueStore.chainIndex[ this.index ]\n }\n set chainIndex (value) {\n this.residueStore.chainIndex[ this.index ] = value\n }\n\n get atomOffset () {\n return this.residueStore.atomOffset[ this.index ]\n }\n set atomOffset (value) {\n this.residueStore.atomOffset[ this.index ] = value\n }\n\n /**\n * Atom count\n * @type {Integer}\n */\n get atomCount () {\n return this.residueStore.atomCount[ this.index ]\n }\n set atomCount (value) {\n this.residueStore.atomCount[ this.index ] = value\n }\n\n get atomEnd () {\n return this.atomOffset + this.atomCount - 1\n }\n\n //\n\n get modelIndex () {\n return this.chainStore.modelIndex[ this.chainIndex ]\n }\n /**\n * Chain name\n * @type {String}\n */\n get chainname () {\n return this.chainStore.getChainname(this.chainIndex)\n }\n /**\n * Chain id\n * @type {String}\n */\n get chainid () {\n return this.chainStore.getChainid(this.chainIndex)\n }\n\n //\n\n /**\n * Residue number/label\n * @type {Integer}\n */\n get resno () {\n return this.residueStore.resno[ this.index ]\n }\n set resno (value) {\n this.residueStore.resno[ this.index ] = value\n }\n\n /**\n * Secondary structure code\n * @type {String}\n */\n get sstruc () {\n return this.residueStore.getSstruc(this.index)\n }\n set sstruc (value) {\n this.residueStore.setSstruc(this.index, value)\n }\n\n /**\n * Insertion code\n * @type {String}\n */\n get inscode () {\n return this.residueStore.getInscode(this.index)\n }\n set inscode (value) {\n this.residueStore.setInscode(this.index, value)\n }\n\n //\n\n get residueType (): ResidueType {\n return this.residueMap.get(this.residueStore.residueTypeId[ this.index ])\n }\n\n /**\n * Residue name\n * @type {String}\n */\n get resname () {\n return this.residueType.resname\n }\n /**\n * Hetero flag\n * @type {Boolean}\n */\n get hetero () {\n return this.residueType.hetero\n }\n get moleculeType () {\n return this.residueType.moleculeType\n }\n get backboneType () {\n return this.residueType.backboneType\n }\n get backboneStartType () {\n return this.residueType.backboneStartType\n }\n get backboneEndType () {\n return this.residueType.backboneEndType\n }\n get traceAtomIndex () {\n return this.residueType.traceAtomIndex + this.atomOffset\n }\n get direction1AtomIndex () {\n return this.residueType.direction1AtomIndex + this.atomOffset\n }\n get direction2AtomIndex () {\n return this.residueType.direction2AtomIndex + this.atomOffset\n }\n get backboneStartAtomIndex () {\n return this.residueType.backboneStartAtomIndex + this.atomOffset\n }\n get backboneEndAtomIndex () {\n return this.residueType.backboneEndAtomIndex + this.atomOffset\n }\n get rungEndAtomIndex () {\n return this.residueType.rungEndAtomIndex + this.atomOffset\n }\n\n //\n\n get x () {\n let x = 0\n for (let i = this.atomOffset; i <= this.atomEnd; ++i) {\n x += this.atomStore.x[ i ]\n }\n return x / this.atomCount\n }\n\n get y () {\n let y = 0\n for (let i = this.atomOffset; i <= this.atomEnd; ++i) {\n y += this.atomStore.y[ i ]\n }\n return y / this.atomCount\n }\n\n get z () {\n let z = 0\n for (let i = this.atomOffset; i <= this.atomEnd; ++i) {\n z += this.atomStore.z[ i ]\n }\n return z / this.atomCount\n }\n\n //\n\n /**\n * Atom iterator\n * @param {function(atom: AtomProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachAtom (callback: (ap: AtomProxy) => void, selection?: Selection) {\n const count = this.atomCount\n const offset = this.atomOffset\n const ap = this.structure._ap\n const end = offset + count\n\n if (selection && selection.atomOnlyTest) {\n const atomOnlyTest = selection.atomOnlyTest\n for (let i = offset; i < end; ++i) {\n ap.index = i\n if (atomOnlyTest(ap)) callback(ap)\n }\n } else {\n for (let i = offset; i < end; ++i) {\n ap.index = i\n callback(ap)\n }\n }\n }\n\n //\n\n /**\n * Write residue center position to array\n * @param {Array|TypedArray} [array] - target array\n * @param {Integer} [offset] - the offset\n * @return {Array|TypedArray} target array\n */\n positionToArray (array: NumberArray = [], offset = 0) {\n array[ offset + 0 ] = this.x\n array[ offset + 1 ] = this.y\n array[ offset + 2 ] = this.z\n\n return array\n }\n\n //\n\n /**\n * If residue is from a protein\n * @return {Boolean} flag\n */\n isProtein () {\n return this.residueType.moleculeType === ProteinType\n }\n\n /**\n * If residue is nucleic\n * @return {Boolean} flag\n */\n isNucleic () {\n const moleculeType = this.residueType.moleculeType\n return moleculeType === RnaType || moleculeType === DnaType\n }\n\n /**\n * If residue is rna\n * @return {Boolean} flag\n */\n isRna () {\n return this.residueType.moleculeType === RnaType\n }\n\n /**\n * If residue is dna\n * @return {Boolean} flag\n */\n isDna () {\n return this.residueType.moleculeType === DnaType\n }\n\n /**\n * If residue is coarse-grain\n * @return {Boolean} flag\n */\n isCg () {\n const backboneType = this.residueType.backboneType\n return (\n backboneType === CgProteinBackboneType ||\n backboneType === CgRnaBackboneType ||\n backboneType === CgDnaBackboneType\n )\n }\n\n /**\n * If residue is from a polymer\n * @return {Boolean} flag\n */\n isPolymer () {\n if (this.structure.entityList.length > 0) {\n return this.entity.isPolymer()\n } else {\n const moleculeType = this.residueType.moleculeType\n return (\n moleculeType === ProteinType ||\n moleculeType === RnaType ||\n moleculeType === DnaType\n )\n }\n }\n\n /**\n * If residue is hetero\n * @return {Boolean} flag\n */\n isHetero () {\n return this.residueType.hetero === 1\n }\n\n /**\n * If residue is a water molecule\n * @return {Boolean} flag\n */\n isWater () {\n return this.residueType.moleculeType === WaterType\n }\n\n /**\n * If residue is an ion\n * @return {Boolean} flag\n */\n isIon () {\n return this.residueType.moleculeType === IonType\n }\n\n /**\n * If residue is a saccharide\n * @return {Boolean} flag\n */\n isSaccharide () {\n return this.residueType.moleculeType === SaccharideType\n }\n\n isStandardAminoacid () {\n return this.residueType.isStandardAminoacid()\n }\n\n isStandardBase () {\n return this.residueType.isStandardBase()\n }\n\n /**\n * If residue is part of a helix\n * @return {Boolean} flag\n */\n isHelix () {\n return SecStrucHelix.includes(this.sstruc)\n }\n\n /**\n * If residue is part of a sheet\n * @return {Boolean} flag\n */\n isSheet () {\n return SecStrucSheet.includes(this.sstruc)\n }\n\n /**\n * If residue is part of a turn\n * @return {Boolean} flag\n */\n isTurn () {\n return SecStrucTurn.includes(this.sstruc) && this.isProtein()\n }\n\n getAtomType (index: number): AtomType {\n return this.atomMap.get(this.atomStore.atomTypeId[ index ])\n }\n\n getResname1 () {\n // FIXME nucleic support\n return AA1[ this.resname.toUpperCase() ] || 'X'\n }\n\n getBackboneType (position: number) {\n switch (position) {\n case -1:\n return this.residueType.backboneStartType\n case 1:\n return this.residueType.backboneEndType\n default:\n return this.residueType.backboneType\n }\n }\n\n getAtomIndexByName (atomname: string) {\n let index = this.residueType.getAtomIndexByName(atomname)\n if (index !== undefined) {\n index += this.atomOffset\n }\n return index\n }\n\n hasAtomWithName (atomname: string) {\n return this.residueType.hasAtomWithName(atomname)\n }\n\n getAtomnameList () {\n console.warn('getAtomnameList - might be expensive')\n\n const n = this.atomCount\n const offset = this.atomOffset\n const list = new Array(n)\n for (let i = 0; i < n; ++i) {\n list[ i ] = this.getAtomType(offset + i).atomname\n }\n return list\n }\n\n /**\n * If residue is connected to another\n * @param {ResidueProxy} rNext - the other residue\n * @return {Boolean} - flag\n */\n connectedTo (rNext: ResidueProxy) {\n const bbAtomEnd = this.structure.getAtomProxy(this.backboneEndAtomIndex)\n const bbAtomStart = this.structure.getAtomProxy(rNext.backboneStartAtomIndex)\n if (bbAtomEnd && bbAtomStart) {\n return bbAtomEnd.connectedTo(bbAtomStart)\n } else {\n return false\n }\n }\n\n getNextConnectedResidue () {\n const rOffset = this.chainStore.residueOffset[ this.chainIndex ]\n const rCount = this.chainStore.residueCount[ this.chainIndex ]\n const nextIndex = this.index + 1\n if (nextIndex < rOffset + rCount) {\n const rpNext = this.structure.getResidueProxy(nextIndex)\n if (this.connectedTo(rpNext)) {\n return rpNext\n }\n } else if (nextIndex === rOffset + rCount) { // cyclic\n const rpFirst = this.structure.getResidueProxy(rOffset)\n if (this.connectedTo(rpFirst)) {\n return rpFirst\n }\n }\n return undefined\n }\n\n getPreviousConnectedResidue (residueProxy?: ResidueProxy) {\n const rOffset = this.chainStore.residueOffset[ this.chainIndex ]\n const prevIndex = this.index - 1\n if (prevIndex >= rOffset) {\n const rpPrev = defaults(residueProxy, this.structure.getResidueProxy())\n rpPrev.index = prevIndex\n if (rpPrev.connectedTo(this)) {\n return rpPrev\n }\n } else if (prevIndex === rOffset - 1) { // cyclic\n const rCount = this.chainStore.residueCount[ this.chainIndex ]\n const rpLast = defaults(residueProxy, this.structure.getResidueProxy())\n rpLast.index = rOffset + rCount - 1\n if (rpLast.connectedTo(this)) {\n return rpLast\n }\n }\n return undefined\n }\n\n getBonds (): ResidueBonds {\n return this.residueType.getBonds(this)\n }\n\n getRings (): RingData|undefined {\n return this.residueType.getRings()\n }\n\n getAromaticRings () {\n return this.residueType.getAromaticRings(this)\n }\n\n qualifiedName (noResname = false) {\n let name = ''\n if (this.resname && !noResname) name += '[' + this.resname + ']'\n if (this.resno !== undefined) name += this.resno\n if (this.inscode) name += '^' + this.inscode\n if (this.chain) name += ':' + this.chainname\n name += '/' + this.modelIndex\n return name\n }\n\n /**\n * Clone object\n * @return {ResidueProxy} cloned residue\n */\n clone () {\n return new ResidueProxy(this.structure, this.index)\n }\n\n toObject () {\n return {\n index: this.index,\n chainIndex: this.chainIndex,\n atomOffset: this.atomOffset,\n atomCount: this.atomCount,\n\n resno: this.resno,\n resname: this.resname,\n sstruc: this.sstruc\n }\n }\n}\n\nexport default ResidueProxy\n","/**\n * @file Polymer\n * @author Alexander Rose \n * @private\n */\n\n// import { Log } from '../globals'\n\nimport Structure from '../structure/structure'\nimport Selection from '../selection/selection'\n\nimport ChainStore from '../store/chain-store'\nimport ResidueStore from '../store/residue-store'\nimport AtomStore from '../store/atom-store'\n\nimport ResidueProxy from '../proxy/residue-proxy'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Polymer\n */\nclass Polymer {\n chainStore: ChainStore\n residueStore: ResidueStore\n atomStore: AtomStore\n\n residueCount: number\n\n isPrevConnected: boolean\n isNextConnected: boolean\n isNextNextConnected: boolean\n isCyclic: boolean\n\n private __residueProxy: ResidueProxy\n\n /**\n * @param {Structure} structure - the structure\n * @param {Integer} residueIndexStart - the index of the first residue\n * @param {Integer} residueIndexEnd - the index of the last residue\n */\n constructor (readonly structure: Structure, readonly residueIndexStart: number, readonly residueIndexEnd: number) {\n this.chainStore = structure.chainStore\n this.residueStore = structure.residueStore\n this.atomStore = structure.atomStore\n\n /**\n * @type {Integer}\n */\n this.residueCount = residueIndexEnd - residueIndexStart + 1\n\n const rpStart = this.structure.getResidueProxy(this.residueIndexStart)\n const rpEnd = this.structure.getResidueProxy(this.residueIndexEnd)\n this.isPrevConnected = rpStart.getPreviousConnectedResidue() !== undefined\n const rpNext = rpEnd.getNextConnectedResidue()\n this.isNextConnected = rpNext !== undefined\n this.isNextNextConnected = rpNext !== undefined && rpNext.getNextConnectedResidue() !== undefined\n this.isCyclic = rpEnd.connectedTo(rpStart)\n\n this.__residueProxy = this.structure.getResidueProxy()\n\n // console.log( this.qualifiedName(), this );\n }\n\n get chainIndex () {\n return this.residueStore.chainIndex[ this.residueIndexStart ]\n }\n get modelIndex () {\n return this.chainStore.modelIndex[ this.chainIndex ]\n }\n\n /**\n * @type {String}\n */\n get chainname () {\n return this.chainStore.getChainname(this.chainIndex)\n }\n\n //\n\n /**\n * If first residue is from aprotein\n * @return {Boolean} flag\n */\n isProtein () {\n this.__residueProxy.index = this.residueIndexStart\n return this.__residueProxy.isProtein()\n }\n\n /**\n * If atom is part of a coarse-grain group\n * @return {Boolean} flag\n */\n isCg () {\n this.__residueProxy.index = this.residueIndexStart\n return this.__residueProxy.isCg()\n }\n\n /**\n * If atom is part of a nucleic molecule\n * @return {Boolean} flag\n */\n isNucleic () {\n this.__residueProxy.index = this.residueIndexStart\n return this.__residueProxy.isNucleic()\n }\n\n getMoleculeType () {\n this.__residueProxy.index = this.residueIndexStart\n return this.__residueProxy.moleculeType\n }\n\n getBackboneType (position: number) {\n this.__residueProxy.index = this.residueIndexStart\n return this.__residueProxy.getBackboneType(position)\n }\n\n getAtomIndexByType (index: number, type: string) {\n // TODO pre-calculate, add to residueStore???\n\n if (this.isCyclic) {\n if (index === -1) {\n index = this.residueCount - 1\n } else if (index === this.residueCount) {\n index = 0\n }\n } else {\n if (index === -1 && !this.isPrevConnected) index += 1\n if (index === this.residueCount && !this.isNextNextConnected) index -= 1\n // if( index === this.residueCount - 1 && !this.isNextConnected ) index -= 1;\n }\n\n const rp = this.__residueProxy\n rp.index = this.residueIndexStart + index\n let aIndex\n\n switch (type) {\n case 'trace':\n aIndex = rp.traceAtomIndex\n break\n case 'direction1':\n aIndex = rp.direction1AtomIndex\n break\n case 'direction2':\n aIndex = rp.direction2AtomIndex\n break\n default:\n aIndex = rp.getAtomIndexByName(type)\n }\n\n // if (!ap){\n // console.log(this, type, rp.residueType)\n // // console.log(rp.qualifiedName(), rp.index, index, this.residueCount - 1)\n // // rp.index = this.residueIndexStart;\n // // console.log(rp.qualifiedName(), this.residueIndexStart)\n // // rp.index = this.residueIndexEnd;\n // // console.log(rp.qualifiedName(), this.residueIndexEnd)\n // }\n\n return aIndex\n }\n\n /**\n * Atom iterator\n * @param {function(atom: AtomProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachAtom (callback: (ap: AtomProxy) => void, selection?: Selection) {\n this.eachResidue(function (rp) {\n rp.eachAtom(callback, selection)\n })\n }\n\n eachAtomN (n: number, callback: (...apArray: AtomProxy[]) => void, type: string) {\n const m = this.residueCount\n const array: AtomProxy[] = new Array(n)\n\n for (let i = 0; i < n; ++i) {\n array[ i ] = this.structure.getAtomProxy(this.getAtomIndexByType(i, type))\n }\n callback.apply(this, array)\n\n for (var j = n; j < m; ++j) {\n for (let i = 1; i < n; ++i) {\n array[ i - 1 ].index = array[ i ].index\n }\n array[ n - 1 ].index = this.getAtomIndexByType(j, type)! // TODO\n callback.apply(this, array)\n }\n }\n\n /**\n * Residue iterator\n * @param {function(residue: ResidueProxy)} callback - the callback\n * @return {undefined}\n */\n eachResidue (callback: (rp: ResidueProxy) => void) {\n const rp = this.structure.getResidueProxy()\n const n = this.residueCount\n const rStartIndex = this.residueIndexStart\n\n for (let i = 0; i < n; ++i) {\n rp.index = rStartIndex + i\n callback(rp)\n }\n }\n\n qualifiedName () {\n const rpStart = this.structure.getResidueProxy(this.residueIndexStart)\n const rpEnd = this.structure.getResidueProxy(this.residueIndexEnd)\n return rpStart.qualifiedName() + ' - ' + rpEnd.qualifiedName()\n }\n}\n\nexport default Polymer\n","/**\n * @file Chain Proxy\n * @author Alexander Rose \n * @private\n */\n\nimport { UnknownBackboneType } from '../structure/structure-constants'\n\nimport Structure from '../structure/structure'\nimport Selection from '../selection/selection'\n\nimport ChainStore from '../store/chain-store'\nimport ResidueStore from '../store/residue-store'\n\nimport Polymer from '../proxy/polymer'\nimport ResidueProxy from '../proxy/residue-proxy'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ModelProxy from './model-proxy';\nimport Entity from '../structure/entity';\n\n/**\n * Chain proxy\n */\nclass ChainProxy {\n index: number\n\n chainStore: ChainStore\n residueStore: ResidueStore\n\n /**\n * @param {Structure} structure - the structure\n * @param {Integer} index - the index\n */\n constructor (readonly structure: Structure, index = 0) {\n this.index = index\n this.chainStore = structure.chainStore\n this.residueStore = structure.residueStore\n }\n\n /**\n * Entity\n * @type {Entity}\n */\n get entity (): Entity {\n return this.structure.entityList[ this.entityIndex ]\n }\n /**\n * Model\n * @type {ModelProxy}\n */\n get model (): ModelProxy {\n return this.structure.getModelProxy(this.modelIndex)\n }\n\n get entityIndex () {\n return this.chainStore.entityIndex[ this.index ]\n }\n set entityIndex (value) {\n this.chainStore.entityIndex[ this.index ] = value\n }\n\n get modelIndex () {\n return this.chainStore.modelIndex[ this.index ]\n }\n set modelIndex (value) {\n this.chainStore.modelIndex[ this.index ] = value\n }\n\n get residueOffset () {\n return this.chainStore.residueOffset[ this.index ]\n }\n set residueOffset (value) {\n this.chainStore.residueOffset[ this.index ] = value\n }\n\n /**\n * Residue count\n * @type {Integer}\n */\n get residueCount () {\n return this.chainStore.residueCount[ this.index ]\n }\n set residueCount (value) {\n this.chainStore.residueCount[ this.index ] = value\n }\n\n get residueEnd () {\n return this.residueOffset + this.residueCount - 1\n }\n\n get atomOffset () {\n return this.residueStore.atomOffset[ this.residueOffset ]\n }\n get atomEnd () {\n return (\n this.residueStore.atomOffset[ this.residueEnd ] +\n this.residueStore.atomCount[ this.residueEnd ] - 1\n )\n }\n /**\n * Atom count\n * @type {Integer}\n */\n get atomCount () {\n if (this.residueCount === 0) {\n return 0\n } else {\n return this.atomEnd - this.atomOffset + 1\n }\n }\n\n //\n\n /**\n * Chain name\n * @type {String}\n */\n get chainname () {\n return this.chainStore.getChainname(this.index)\n }\n set chainname (value) {\n this.chainStore.setChainname(this.index, value)\n }\n\n /**\n * Chain id\n * @type {String}\n */\n get chainid () {\n return this.chainStore.getChainid(this.index)\n }\n set chainid (value) {\n this.chainStore.setChainid(this.index, value)\n }\n\n //\n\n /**\n * Atom iterator\n * @param {function(atom: AtomProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachAtom (callback: (ap: AtomProxy) => void, selection?: Selection) {\n this.eachResidue(function (rp) {\n rp.eachAtom(callback, selection)\n }, selection)\n }\n\n /**\n * Residue iterator\n * @param {function(residue: ResidueProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachResidue (callback: (rp: ResidueProxy) => void, selection?: Selection) {\n const count = this.residueCount\n const offset = this.residueOffset\n const rp = this.structure._rp\n const end = offset + count\n\n if (selection && selection.test) {\n const residueOnlyTest = selection.residueOnlyTest\n if (residueOnlyTest) {\n for (let i = offset; i < end; ++i) {\n rp.index = i\n if (residueOnlyTest(rp)) {\n callback(rp)\n }\n }\n } else {\n for (let i = offset; i < end; ++i) {\n rp.index = i\n callback(rp)\n }\n }\n } else {\n for (let i = offset; i < end; ++i) {\n rp.index = i\n callback(rp)\n }\n }\n }\n\n /**\n * Multi-residue iterator\n * @param {Integer} n - window size\n * @param {function(residueList: ResidueProxy[])} callback - the callback\n * @return {undefined}\n */\n eachResidueN (n: number, callback: (...rpArray: ResidueProxy[]) => void) {\n const count = this.residueCount\n const offset = this.residueOffset\n const end = offset + count\n if (count < n) return\n const array: ResidueProxy[] = new Array(n)\n\n for (let i = 0; i < n; ++i) {\n array[ i ] = this.structure.getResidueProxy(offset + i)\n }\n callback.apply(this, array)\n\n for (let j = offset + n; j < end; ++j) {\n for (let i = 0; i < n; ++i) {\n array[ i ].index += 1\n }\n callback.apply(this, array)\n }\n }\n\n /**\n * Polymer iterator\n * @param {function(polymer: Polymer)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachPolymer (callback: (p: Polymer) => void, selection?: Selection) {\n let rStartIndex = 0\n let rNextIndex = 0\n const test = selection ? selection.residueOnlyTest : undefined\n const structure = this.model.structure\n\n const count = this.residueCount\n const offset = this.residueOffset\n const end = offset + count\n\n const rp1 = this.structure.getResidueProxy()\n const rp2 = this.structure.getResidueProxy(offset)\n\n const ap1 = this.structure.getAtomProxy()\n const ap2 = this.structure.getAtomProxy()\n\n let first = true\n\n for (let i = offset + 1; i < end; ++i) {\n rp1.index = rp2.index\n rp2.index = i\n\n const bbType1 = first ? rp1.backboneEndType : rp1.backboneType\n const bbType2 = rp2.backboneType\n\n if (first) {\n rStartIndex = rp1.index\n first = false\n }\n rNextIndex = rp2.index\n\n if (bbType1 !== UnknownBackboneType && bbType1 === bbType2) {\n ap1.index = rp1.backboneEndAtomIndex\n ap2.index = rp2.backboneStartAtomIndex\n } else {\n if (bbType1 !== UnknownBackboneType) {\n if (rp1.index - rStartIndex > 1) {\n // console.log(\"FOO1\",rStartIndex, rp1.index)\n callback(new Polymer(structure, rStartIndex, rp1.index))\n }\n }\n rStartIndex = rNextIndex\n\n continue\n }\n\n if (!ap1 || !ap2 || !ap1.connectedTo(ap2) ||\n (test && (!test(rp1) || !test(rp2)))\n ) {\n if (rp1.index - rStartIndex > 1) {\n // console.log(\"FOO2\",rStartIndex, rp1.index)\n callback(new Polymer(structure, rStartIndex, rp1.index))\n }\n rStartIndex = rNextIndex\n }\n }\n\n if (rNextIndex - rStartIndex > 1) {\n if (this.structure.getResidueProxy(rStartIndex).backboneEndType) {\n // console.log(\"FOO3\",rStartIndex, rNextIndex)\n callback(new Polymer(structure, rStartIndex, rNextIndex))\n }\n }\n }\n\n //\n\n qualifiedName () {\n var name = ':' + this.chainname + '/' + this.modelIndex\n return name\n }\n\n /**\n * Clone object\n * @return {ChainProxy} cloned chain\n */\n clone () {\n return new ChainProxy(this.structure, this.index)\n }\n\n toObject () {\n return {\n index: this.index,\n residueOffset: this.residueOffset,\n residueCount: this.residueCount,\n\n chainname: this.chainname\n }\n }\n}\n\nexport default ChainProxy\n","/**\n * @file Model Proxy\n * @author Alexander Rose \n * @private\n */\n\nimport Structure from '../structure/structure'\nimport Selection from '../selection/selection'\n\nimport ModelStore from '../store/model-store'\nimport ChainStore from '../store/chain-store'\nimport ResidueStore from '../store/residue-store'\n\nimport ChainProxy from '../proxy/chain-proxy'\nimport Polymer from '../proxy/polymer'\nimport ResidueProxy from '../proxy/residue-proxy'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Model proxy\n */\nclass ModelProxy {\n index: number\n\n modelStore: ModelStore\n chainStore: ChainStore\n residueStore: ResidueStore\n\n /**\n * @param {Structure} structure - the structure\n * @param {Integer} index - the index\n */\n constructor (readonly structure: Structure, index = 0) {\n this.index = index\n this.modelStore = structure.modelStore\n this.chainStore = structure.chainStore\n this.residueStore = structure.residueStore\n }\n\n get chainOffset () {\n return this.modelStore.chainOffset[ this.index ]\n }\n set chainOffset (value) {\n this.modelStore.chainOffset[ this.index ] = value\n }\n\n get chainCount () {\n return this.modelStore.chainCount[ this.index ]\n }\n set chainCount (value) {\n this.modelStore.chainCount[ this.index ] = value\n }\n\n get residueOffset () {\n return this.chainStore.residueOffset[ this.chainOffset ]\n }\n get atomOffset () {\n return this.residueStore.atomOffset[ this.residueOffset ]\n }\n\n get chainEnd () {\n return this.chainOffset + this.chainCount - 1\n }\n get residueEnd () {\n return (\n this.chainStore.residueOffset[ this.chainEnd ] +\n this.chainStore.residueCount[ this.chainEnd ] - 1\n )\n }\n get atomEnd () {\n return (\n this.residueStore.atomOffset[ this.residueEnd ] +\n this.residueStore.atomCount[ this.residueEnd ] - 1\n )\n }\n\n /**\n * Residue count\n * @type {Integer}\n */\n get residueCount () {\n if (this.chainCount === 0) {\n return 0\n } else {\n return this.residueEnd - this.residueOffset + 1\n }\n }\n\n /**\n * Atom count\n * @type {Integer}\n */\n get atomCount () {\n if (this.residueCount === 0) {\n return 0\n } else {\n return this.atomEnd - this.atomOffset + 1\n }\n }\n\n //\n\n /**\n * Atom iterator\n * @param {function(atom: AtomProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachAtom (callback: (ap: AtomProxy) => void, selection?: Selection) {\n this.eachChain(function (cp) {\n cp.eachAtom(callback, selection)\n }, selection)\n }\n\n /**\n * Residue iterator\n * @param {function(residue: ResidueProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachResidue (callback: (rp: ResidueProxy) => void, selection?: Selection) {\n this.eachChain(function (cp) {\n cp.eachResidue(callback, selection)\n }, selection)\n }\n\n /**\n * Polymer iterator\n * @param {function(polymer: Polymer)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachPolymer (callback: (p: Polymer) => void, selection?: Selection) {\n if (selection && selection.chainOnlyTest) {\n const chainOnlyTest = selection.chainOnlyTest\n\n this.eachChain(function (cp) {\n if (chainOnlyTest(cp)) {\n cp.eachPolymer(callback, selection)\n }\n })\n } else {\n this.eachChain(function (cp) {\n cp.eachPolymer(callback, selection)\n })\n }\n }\n\n /**\n * Chain iterator\n * @param {function(chain: ChainProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachChain (callback: (cp: ChainProxy) => void, selection?: Selection) {\n const count = this.chainCount\n const offset = this.chainOffset\n const cp = this.structure._cp\n const end = offset + count\n\n if (selection && selection.test) {\n const chainOnlyTest = selection.chainOnlyTest\n if (chainOnlyTest) {\n for (let i = offset; i < end; ++i) {\n cp.index = i\n if (chainOnlyTest(cp)) {\n callback(cp)\n }\n }\n } else {\n for (let i = offset; i < end; ++i) {\n cp.index = i\n callback(cp)\n }\n }\n } else {\n for (let i = offset; i < end; ++i) {\n cp.index = i\n callback(cp)\n }\n }\n }\n\n //\n\n qualifiedName () {\n const name = '/' + this.index\n return name\n }\n\n /**\n * Clone object\n * @return {ModelProxy} cloned model\n */\n clone () {\n return new ModelProxy(this.structure, this.index)\n }\n\n toObject () {\n return {\n index: this.index,\n chainOffset: this.chainOffset,\n chainCount: this.chainCount\n }\n }\n}\n\nexport default ModelProxy\n","/**\n * @file Structure\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Box3 } from 'three'\nimport { Signal } from 'signals'\nimport { CifBlock } from 'molstar/lib/mol-io/reader/cif'\n\nimport { Debug, Log, ColormakerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { AtomPicker, BondPicker } from '../utils/picker'\nimport { copyWithin, arrayMin, arrayMax } from '../math/array-utils'\nimport BitArray from '../utils/bitarray'\nimport RadiusFactory, { RadiusParams } from '../utils/radius-factory'\nimport { Matrix } from '../math/matrix-utils'\nimport PrincipalAxes from '../math/principal-axes'\nimport SpatialHash from '../geometry/spatial-hash'\nimport FilteredVolume from '../surface/filtered-volume'\nimport StructureView from './structure-view'\nimport { AtomDataParams, AtomData, BondDataParams, BondData } from './structure-data'\nimport { Data, createData } from './data'\n\nimport Entity from './entity'\nimport Unitcell from '../symmetry/unitcell'\nimport Validation from './validation'\nimport Selection from '../selection/selection'\nimport Assembly from '../symmetry/assembly'\nimport Volume from '../surface/volume'\nimport Polymer from '../proxy/polymer'\n\nimport BondHash from '../store/bond-hash'\nimport BondStore from '../store/bond-store'\nimport AtomStore from '../store/atom-store'\nimport ResidueStore from '../store/residue-store'\nimport ChainStore from '../store/chain-store'\nimport ModelStore from '../store/model-store'\n\nimport AtomMap from '../store/atom-map'\nimport ResidueMap from '../store/residue-map'\n\nimport BondProxy from '../proxy/bond-proxy'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ResidueProxy from '../proxy/residue-proxy'\nimport ChainProxy from '../proxy/chain-proxy'\nimport ModelProxy from '../proxy/model-proxy'\nimport ChemCompMap from '../store/chemcomp-map'\n\ninterface Structure {\n signals: StructureSignals\n\n name: string\n path: string\n title: string\n id: string\n\n data: Data\n\n atomCount: number\n bondCount: number\n\n header: StructureHeader\n extraData: StructureExtraData\n\n atomSetCache: { [k: string]: BitArray }\n atomSetDict: { [k: string]: BitArray }\n biomolDict: { [k: string]: Assembly }\n\n entityList: Entity[]\n unitcell?: Unitcell\n\n frames: Float32Array[]\n boxes: Float32Array[]\n\n validation?: Validation\n\n bondStore: BondStore\n backboneBondStore: BondStore\n rungBondStore: BondStore\n atomStore: AtomStore\n residueStore: ResidueStore\n chainStore: ChainStore\n modelStore: ModelStore\n\n atomMap: AtomMap\n residueMap: ResidueMap\n chemCompMap?: ChemCompMap\n\n bondHash?: BondHash\n spatialHash?: SpatialHash\n\n atomSet?: BitArray\n bondSet?: BitArray\n\n center: Vector3\n boundingBox: Box3\n\n trajectory?: {\n name: string\n frame: number\n }\n\n getView(selection: Selection): StructureView\n\n _hasCoords?: boolean\n\n _bp: BondProxy\n _ap: AtomProxy\n _rp: ResidueProxy\n _cp: ChainProxy\n}\n\nexport type StructureHeader = {\n releaseDate?: string\n depositionDate?: string\n resolution?: number\n rFree?: number\n rWork?: number\n experimentalMethods?: string[]\n}\n\nexport type StructureExtraData = {\n cif?: CifBlock\n sdf?: object[]\n}\n\nexport type StructureSignals = {\n refreshed: Signal\n}\n\n/**\n * Structure\n */\nclass Structure implements Structure{\n signals: StructureSignals = {\n refreshed: new Signal()\n }\n\n /**\n * @param {String} name - structure name\n * @param {String} path - source path\n */\n constructor (name = '', path = '') {\n this.init(name, path)\n }\n\n init (name: string, path: string) {\n this.name = name\n this.path = path\n this.title = ''\n this.id = ''\n\n this.data = createData(this)\n\n this.header = {}\n this.extraData = {}\n\n this.atomSetCache = {}\n this.atomSetDict = {}\n this.biomolDict = {}\n\n this.entityList = []\n this.unitcell = undefined\n\n this.frames = []\n this.boxes = []\n\n this.validation = undefined\n\n this.bondStore = new BondStore(0)\n this.backboneBondStore = new BondStore(0)\n this.rungBondStore = new BondStore(0)\n this.atomStore = new AtomStore(0)\n this.residueStore = new ResidueStore(0)\n this.chainStore = new ChainStore(0)\n this.modelStore = new ModelStore(0)\n\n this.atomMap = new AtomMap(this)\n this.residueMap = new ResidueMap(this)\n this.chemCompMap = undefined\n\n this.bondHash = undefined\n this.spatialHash = undefined\n\n this.atomSet = undefined\n this.bondSet = undefined\n\n this.center = new Vector3()\n this.boundingBox = new Box3()\n\n this._bp = this.getBondProxy()\n this._ap = this.getAtomProxy()\n this._rp = this.getResidueProxy()\n this._cp = this.getChainProxy()\n }\n\n get type () { return 'Structure' }\n\n finalizeAtoms () {\n this.atomSet = this.getAtomSet()\n this.atomCount = this.atomStore.count\n this.boundingBox = this.getBoundingBox(undefined, this.boundingBox)\n this.center = this.boundingBox.getCenter(new Vector3())\n this.spatialHash = new SpatialHash(this.atomStore, this.boundingBox)\n }\n\n finalizeBonds () {\n this.bondSet = this.getBondSet()\n this.bondCount = this.bondStore.count\n this.bondHash = new BondHash(this.bondStore, this.atomStore.count)\n\n this.atomSetCache = {}\n if (!this.atomSetDict.rung) {\n this.atomSetDict.rung = this.getAtomSet(false)\n }\n\n for (let name in this.atomSetDict) {\n this.atomSetCache[ '__' + name ] = this.atomSetDict[ name ].clone()\n }\n }\n\n //\n\n getBondProxy (index?: number) {\n return new BondProxy(this, index)\n }\n\n getAtomProxy (index?: number) {\n return new AtomProxy(this, index)\n }\n\n getResidueProxy (index?: number) {\n return new ResidueProxy(this, index)\n }\n\n getChainProxy (index?: number) {\n return new ChainProxy(this, index)\n }\n\n getModelProxy (index?: number) {\n return new ModelProxy(this, index)\n }\n\n //\n\n getBondSet (/* selection */) {\n // TODO implement selection parameter\n\n const n = this.bondStore.count\n const bondSet = new BitArray(n)\n const atomSet = this.atomSet\n\n if (atomSet) {\n if (atomSet.isAllSet()) {\n bondSet.setAll()\n } else if (atomSet.isAllClear()) {\n bondSet.clearAll()\n } else {\n const bp = this.getBondProxy()\n\n for (let i = 0; i < n; ++i) {\n bp.index = i\n if (atomSet.isSet(bp.atomIndex1, bp.atomIndex2)) {\n bondSet.set(bp.index)\n }\n }\n }\n } else {\n bondSet.setAll()\n }\n\n return bondSet\n }\n\n getBackboneBondSet (/* selection */) {\n // TODO implement selection parameter\n\n const n = this.backboneBondStore.count\n const backboneBondSet = new BitArray(n)\n const backboneAtomSet = this.atomSetCache.__backbone\n\n if (backboneAtomSet) {\n const bp = this.getBondProxy()\n bp.bondStore = this.backboneBondStore\n\n for (let i = 0; i < n; ++i) {\n bp.index = i\n if (backboneAtomSet.isSet(bp.atomIndex1, bp.atomIndex2)) {\n backboneBondSet.set(bp.index)\n }\n }\n } else {\n backboneBondSet.setAll()\n }\n\n return backboneBondSet\n }\n\n getRungBondSet (/* selection */) {\n // TODO implement selection parameter\n\n const n = this.rungBondStore.count\n const rungBondSet = new BitArray(n)\n const rungAtomSet = this.atomSetCache.__rung\n\n if (rungAtomSet) {\n const bp = this.getBondProxy()\n bp.bondStore = this.rungBondStore\n\n for (let i = 0; i < n; ++i) {\n bp.index = i\n if (rungAtomSet.isSet(bp.atomIndex1, bp.atomIndex2)) {\n rungBondSet.set(bp.index)\n }\n }\n } else {\n rungBondSet.setAll()\n }\n\n return rungBondSet\n }\n\n /**\n * Get a set of atoms\n * @param {Boolean|Selection|BitArray} selection - object defining how to\n * initialize the atom set.\n * Boolean: init with value;\n * Selection: init with selection;\n * BitArray: return bit array\n * @return {BitArray} set of atoms\n */\n getAtomSet (selection?: boolean|Selection|BitArray) {\n const n = this.atomStore.count\n\n if (selection === undefined) {\n return new BitArray(n, true)\n } else if (selection instanceof BitArray) {\n return selection\n } else if (selection === true) {\n return new BitArray(n, true)\n } else if (selection && selection.test) {\n const seleString = selection.string\n if (seleString in this.atomSetCache) {\n return this.atomSetCache[ seleString ]\n } else {\n if (seleString === '') {\n return new BitArray(n, true)\n } else {\n const atomSet = new BitArray(n)\n this.eachAtom(function (ap: AtomProxy) {\n atomSet.set(ap.index)\n }, selection)\n this.atomSetCache[ seleString ] = atomSet\n return atomSet\n }\n }\n } else if (selection === false) {\n return new BitArray(n)\n }\n\n return new BitArray(n, true)\n }\n\n /**\n * Get set of atoms around a set of atoms from a selection\n * @param {Selection} selection - the selection object\n * @param {Number} radius - radius to select within\n * @return {BitArray} set of atoms\n */\n getAtomSetWithinSelection (selection: boolean|Selection|BitArray, radius: number) {\n const spatialHash = this.spatialHash\n const atomSet = this.getAtomSet(false)\n const ap = this.getAtomProxy()\n\n if (!spatialHash) return atomSet\n\n this.getAtomSet(selection).forEach(function (idx: number) {\n ap.index = idx\n spatialHash.within(ap.x, ap.y, ap.z, radius).forEach(function (idx2: number) {\n atomSet.set(idx2)\n })\n })\n\n return atomSet\n }\n\n /**\n * Get set of atoms around a point\n * @param {Vector3|AtomProxy} point - the point\n * @param {Number} radius - radius to select within\n * @return {BitArray} set of atoms\n */\n getAtomSetWithinPoint (point: Vector3|AtomProxy, radius: number) {\n const p = point\n const atomSet = this.getAtomSet(false)\n\n if (!this.spatialHash) return atomSet\n\n this.spatialHash.within(p.x, p.y, p.z, radius).forEach(function (idx: number) {\n atomSet.set(idx)\n })\n\n return atomSet\n }\n\n /**\n * Get set of atoms within a volume\n * @param {Volume} volume - the volume\n * @param {Number} radius - radius to select within\n * @param {[type]} minValue - minimum value to be considered as within the volume\n * @param {[type]} maxValue - maximum value to be considered as within the volume\n * @param {[type]} outside - use only values falling outside of the min/max values\n * @return {BitArray} set of atoms\n */\n getAtomSetWithinVolume (volume: Volume, radius: number, minValue: number, maxValue: number, outside: boolean) {\n const fv = new FilteredVolume(volume, minValue, maxValue, outside) as any // TODO\n\n const dp = fv.getDataPosition()\n const n = dp.length\n const r = fv.matrix.getMaxScaleOnAxis()\n const atomSet = this.getAtomSet(false)\n\n if (!this.spatialHash) return atomSet\n\n for (let i = 0; i < n; i += 3) {\n this.spatialHash.within(dp[ i ], dp[ i + 1 ], dp[ i + 2 ], r).forEach(function (idx) {\n atomSet.set(idx)\n })\n }\n\n return atomSet\n }\n\n /**\n * Get set of all atoms within the groups of a selection\n * @param {Selection} selection - the selection object\n * @return {BitArray} set of atoms\n */\n getAtomSetWithinGroup (selection: boolean|Selection|BitArray) {\n const atomResidueIndex = this.atomStore.residueIndex\n const atomSet = this.getAtomSet(false)\n const rp = this.getResidueProxy()\n\n this.getAtomSet(selection).forEach(function (idx) {\n rp.index = atomResidueIndex[ idx ]\n for (let idx2 = rp.atomOffset; idx2 <= rp.atomEnd; ++idx2) {\n atomSet.set(idx2)\n }\n })\n\n return atomSet\n }\n\n //\n\n getSelection (): undefined|Selection {\n return\n }\n\n getStructure (): Structure|StructureView {\n return this\n }\n\n /**\n * Entity iterator\n * @param {function(entity: Entity)} callback - the callback\n * @param {EntityType} type - entity type\n * @return {undefined}\n */\n eachEntity (callback: (entity: Entity) => void, type: number) {\n this.entityList.forEach(function (entity) {\n if (type === undefined || entity.getEntityType() === type) {\n callback(entity)\n }\n })\n }\n\n /**\n * Bond iterator\n * @param {function(bond: BondProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachBond (callback: (entity: BondProxy) => void, selection?: Selection) {\n const bp = this.getBondProxy()\n let bondSet\n\n if (selection && selection.test) {\n bondSet = this.getBondSet(/*selection*/)\n if (this.bondSet) {\n bondSet.intersection(this.bondSet)\n }\n }\n\n if (bondSet) {\n bondSet.forEach(function (index) {\n bp.index = index\n callback(bp)\n })\n } else {\n const n = this.bondStore.count\n for (let i = 0; i < n; ++i) {\n bp.index = i\n callback(bp)\n }\n }\n }\n\n /**\n * Atom iterator\n * @param {function(atom: AtomProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachAtom (callback: (entity: AtomProxy) => void, selection?: Selection) {\n if (selection && selection.test) {\n this.eachModel(function (mp) {\n mp.eachAtom(callback, selection)\n }, selection)\n } else {\n const an = this.atomStore.count\n const ap = this.getAtomProxy()\n for (let i = 0; i < an; ++i) {\n ap.index = i\n callback(ap)\n }\n }\n }\n\n /**\n * Residue iterator\n * @param {function(residue: ResidueProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachResidue (callback: (entity: ResidueProxy) => void, selection?: Selection) {\n if (selection && selection.test) {\n const mn = this.modelStore.count\n const mp = this.getModelProxy()\n const modelOnlyTest = selection.modelOnlyTest\n if (modelOnlyTest) {\n for (let i = 0; i < mn; ++i) {\n mp.index = i\n if (modelOnlyTest(mp)) {\n mp.eachResidue(callback, selection)\n }\n }\n } else {\n for (let i = 0; i < mn; ++i) {\n mp.index = i\n mp.eachResidue(callback, selection)\n }\n }\n } else {\n const rn = this.residueStore.count\n const rp = this.getResidueProxy()\n for (let i = 0; i < rn; ++i) {\n rp.index = i\n callback(rp)\n }\n }\n }\n\n /**\n * Multi-residue iterator\n * @param {Integer} n - window size\n * @param {function(residueList: ResidueProxy[])} callback - the callback\n * @return {undefined}\n */\n eachResidueN (n: number, callback: (...entityArray: ResidueProxy[]) => void) {\n const rn = this.residueStore.count\n if (rn < n) return\n const array: ResidueProxy[] = new Array(n)\n\n for (let i = 0; i < n; ++i) {\n array[ i ] = this.getResidueProxy(i)\n }\n callback.apply(this, array)\n\n for (let j = n; j < rn; ++j) {\n for (let i = 0; i < n; ++i) {\n array[ i ].index += 1\n }\n callback.apply(this, array)\n }\n }\n\n /**\n * Polymer iterator\n * @param {function(polymer: Polymer)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachPolymer (callback: (entity: Polymer) => void, selection?: Selection) {\n if (selection && selection.modelOnlyTest) {\n const modelOnlyTest = selection.modelOnlyTest\n\n this.eachModel(function (mp) {\n if (modelOnlyTest(mp)) {\n mp.eachPolymer(callback, selection)\n }\n })\n } else {\n this.eachModel(function (mp) {\n mp.eachPolymer(callback, selection)\n })\n }\n }\n\n /**\n * Chain iterator\n * @param {function(chain: ChainProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachChain (callback: (entity: ChainProxy) => void, selection?: Selection) {\n if (selection && selection.test) {\n this.eachModel(function (mp) {\n mp.eachChain(callback, selection)\n })\n } else {\n const cn = this.chainStore.count\n const cp = this.getChainProxy()\n for (let i = 0; i < cn; ++i) {\n cp.index = i\n callback(cp)\n }\n }\n }\n\n /**\n * Model iterator\n * @param {function(model: ModelProxy)} callback - the callback\n * @param {Selection} [selection] - the selection\n * @return {undefined}\n */\n eachModel (callback: (entity: ModelProxy) => void, selection?: Selection) {\n const n = this.modelStore.count\n const mp = this.getModelProxy()\n\n if (selection && selection.test) {\n const modelOnlyTest = selection.modelOnlyTest\n if (modelOnlyTest) {\n for (let i = 0; i < n; ++i) {\n mp.index = i\n if (modelOnlyTest(mp)) {\n callback(mp)\n }\n }\n } else {\n for (let i = 0; i < n; ++i) {\n mp.index = i\n callback(mp)\n }\n }\n } else {\n for (let i = 0; i < n; ++i) {\n mp.index = i\n callback(mp)\n }\n }\n }\n\n //\n\n getAtomData (params: AtomDataParams) {\n const p = Object.assign({}, params)\n if (p.colorParams) p.colorParams.structure = this.getStructure()\n\n const what = p.what\n const atomSet = defaults(p.atomSet, this.atomSet)\n\n let radiusFactory: any // TODO\n let colormaker: any // TODO\n\n const atomData: AtomData = {}\n const ap = this.getAtomProxy()\n const atomCount = atomSet.getSize()\n\n if (!what || what.position) {\n atomData.position = new Float32Array(atomCount * 3)\n }\n if ((!what || what.color) && p.colorParams) {\n atomData.color = new Float32Array(atomCount * 3)\n colormaker = ColormakerRegistry.getScheme(p.colorParams)\n }\n if (!what || what.picking) {\n atomData.picking = new AtomPicker(new Float32Array(atomCount), this.getStructure())\n }\n if (!what || what.radius) {\n atomData.radius = new Float32Array(atomCount)\n radiusFactory = new RadiusFactory(p.radiusParams as RadiusParams)\n }\n if (!what || what.index) {\n atomData.index = new Uint32Array(atomCount)\n }\n\n const {position, color, picking, radius, index} = atomData\n\n atomSet.forEach((idx: number, i: number) => {\n const i3 = i * 3\n ap.index = idx\n if (position) {\n ap.positionToArray(position, i3)\n }\n if (color) {\n colormaker.atomColorToArray(ap, color, i3)\n }\n if (picking) {\n picking.array![ i ] = idx\n }\n if (radius) {\n radius[ i ] = radiusFactory.atomRadius(ap)\n }\n if (index) {\n index[ i ] = idx\n }\n })\n return atomData\n }\n\n getBondData (params: BondDataParams) {\n const p = Object.assign({}, params)\n if (p.colorParams) p.colorParams.structure = this.getStructure()\n\n const what = p.what\n const bondSet = defaults(p.bondSet, this.bondSet)\n const multipleBond = defaults(p.multipleBond, 'off')\n const isMulti = multipleBond !== 'off'\n const isOffset = multipleBond === 'offset'\n const bondScale = defaults(p.bondScale, 0.4)\n const bondSpacing = defaults(p.bondSpacing, 1.0)\n\n let radiusFactory: any // TODO\n let colormaker: any // TODO\n\n const bondData: BondData = {}\n const bp = this.getBondProxy()\n if (p.bondStore) bp.bondStore = p.bondStore\n const ap1 = this.getAtomProxy()\n const ap2 = this.getAtomProxy()\n\n let bondCount: number\n if (isMulti) {\n const storeBondOrder = bp.bondStore.bondOrder\n bondCount = 0\n bondSet.forEach(function (index: number) {\n bondCount += storeBondOrder[ index ]\n })\n } else {\n bondCount = bondSet.getSize()\n }\n\n if (!what || what.position) {\n bondData.position1 = new Float32Array(bondCount * 3)\n bondData.position2 = new Float32Array(bondCount * 3)\n }\n if ((!what || what.color) && p.colorParams) {\n bondData.color = new Float32Array(bondCount * 3)\n bondData.color2 = new Float32Array(bondCount * 3)\n colormaker = ColormakerRegistry.getScheme(p.colorParams)\n }\n if (!what || what.picking) {\n bondData.picking = new BondPicker(new Float32Array(bondCount), this.getStructure(), p.bondStore)\n }\n if (!what || what.radius || (isMulti && what.position)) {\n radiusFactory = new RadiusFactory(p.radiusParams as RadiusParams)\n }\n if (!what || what.radius) {\n bondData.radius = new Float32Array(bondCount)\n if (p.radius2) {\n bondData.radius2 = new Float32Array(bondCount)\n }\n }\n\n const {position1, position2, color, color2, picking, radius, radius2} = bondData\n\n let i = 0\n let j, i3, k, bondOrder, absOffset\n let multiRadius\n\n const vt = new Vector3()\n const vShortening = new Vector3()\n const vShift = new Vector3()\n\n bondSet.forEach((index: number) => {\n i3 = i * 3\n bp.index = index\n ap1.index = bp.atomIndex1\n ap2.index = bp.atomIndex2\n bondOrder = bp.bondOrder\n if (position1) {\n if (isMulti && bondOrder > 1) {\n const atomRadius = radiusFactory.atomRadius(ap1)\n multiRadius = atomRadius * bondScale / (0.5 * bondOrder)\n\n bp.calculateShiftDir(vShift)\n\n if (isOffset) {\n absOffset = 2 * bondSpacing * atomRadius\n vShift.multiplyScalar(absOffset)\n vShift.negate()\n\n // Shortening is calculated so that neighbouring double\n // bonds on tetrahedral geometry (e.g. sulphonamide)\n // are not quite touching (arccos(1.9 / 2) ~ 109deg)\n // but don't shorten beyond 10% each end or it looks odd\n vShortening.subVectors(ap2 as any, ap1 as any).multiplyScalar( // TODO\n Math.max(0.1, absOffset / 1.88)\n )\n ap1.positionToArray(position1, i3)\n ap2.positionToArray(position2, i3)\n\n if (bondOrder >= 2) {\n vt.addVectors(ap1 as any, vShift).add(vShortening).toArray(position1 as any, i3 + 3) // TODO\n vt.addVectors(ap2 as any, vShift).sub(vShortening).toArray(position2 as any, i3 + 3) // TODO\n\n if (bondOrder >= 3) {\n vt.subVectors(ap1 as any, vShift).add(vShortening).toArray(position1 as any, i3 + 6) // TODO\n vt.subVectors(ap2 as any, vShift).sub(vShortening).toArray(position2 as any, i3 + 6) // TODO\n }\n }\n } else {\n absOffset = (bondSpacing - bondScale) * atomRadius\n vShift.multiplyScalar(absOffset)\n\n if (bondOrder === 2) {\n vt.addVectors(ap1 as any, vShift).toArray(position1 as any, i3) // TODO\n vt.subVectors(ap1 as any, vShift).toArray(position1 as any, i3 + 3) // TODO\n vt.addVectors(ap2 as any, vShift).toArray(position2 as any, i3) // TODO\n vt.subVectors(ap2 as any, vShift).toArray(position2 as any, i3 + 3) // TODO\n } else if (bondOrder === 3) {\n ap1.positionToArray(position1, i3)\n vt.addVectors(ap1 as any, vShift).toArray(position1 as any, i3 + 3) // TODO\n vt.subVectors(ap1 as any, vShift).toArray(position1 as any, i3 + 6) // TODO\n ap2.positionToArray(position2, i3)\n vt.addVectors(ap2 as any, vShift).toArray(position2 as any, i3 + 3) // TODO\n vt.subVectors(ap2 as any, vShift).toArray(position2 as any, i3 + 6) // TODO\n } else {\n // todo, better fallback\n ap1.positionToArray(position1, i3)\n ap2.positionToArray(position2, i3)\n }\n }\n } else {\n ap1.positionToArray(position1, i3)\n ap2.positionToArray(position2, i3)\n }\n }\n if (color && color2) {\n colormaker.bondColorToArray(bp, 1, color, i3)\n colormaker.bondColorToArray(bp, 0, color2, i3)\n if (isMulti && bondOrder > 1) {\n for (j = 1; j < bondOrder; ++j) {\n k = j * 3 + i3\n copyWithin(color, i3, k, 3)\n copyWithin(color2, i3, k, 3)\n }\n }\n }\n if (picking && picking.array) {\n picking.array[ i ] = index\n if (isMulti && bondOrder > 1) {\n for (j = 1; j < bondOrder; ++j) {\n picking.array[ i + j ] = index\n }\n }\n }\n if (radius) {\n radius[ i ] = radiusFactory.atomRadius(ap1)\n if (isMulti && bondOrder > 1) {\n multiRadius = radius[ i ] * bondScale / (isOffset ? 1 : (0.5 * bondOrder))\n for (j = isOffset ? 1 : 0; j < bondOrder; ++j) {\n radius[ i + j ] = multiRadius\n }\n }\n }\n if (radius2) {\n radius2[ i ] = radiusFactory.atomRadius(ap2)\n if (isMulti && bondOrder > 1) {\n multiRadius = radius2[ i ] * bondScale / (isOffset ? 1 : (0.5 * bondOrder))\n for (j = isOffset ? 1 : 0; j < bondOrder; ++j) {\n radius2[ i + j ] = multiRadius\n }\n }\n }\n i += isMulti ? bondOrder : 1\n })\n\n return bondData\n }\n\n getBackboneAtomData (params: AtomDataParams) {\n params = Object.assign({\n atomSet: this.atomSetCache.__backbone\n }, params)\n\n return this.getAtomData(params)\n }\n\n getBackboneBondData (params: BondDataParams) {\n params = Object.assign({\n bondSet: this.getBackboneBondSet(),\n bondStore: this.backboneBondStore\n }, params)\n\n return this.getBondData(params)\n }\n\n getRungAtomData (params: AtomDataParams) {\n params = Object.assign({\n atomSet: this.atomSetCache.__rung\n }, params)\n\n return this.getAtomData(params)\n }\n\n getRungBondData (params: BondDataParams) {\n params = Object.assign({\n bondSet: this.getRungBondSet(),\n bondStore: this.rungBondStore\n }, params)\n\n return this.getBondData(params)\n }\n\n //\n\n /**\n * Gets the bounding box of the (selected) structure atoms\n * @param {Selection} [selection] - the selection\n * @param {Box3} [box] - optional target\n * @return {Vector3} the box\n */\n getBoundingBox (selection?: Selection, box?: Box3) {\n if (Debug) Log.time('getBoundingBox')\n\n box = box || new Box3()\n\n let minX = +Infinity\n let minY = +Infinity\n let minZ = +Infinity\n\n let maxX = -Infinity\n let maxY = -Infinity\n let maxZ = -Infinity\n\n this.eachAtom(ap => {\n const x = ap.x\n const y = ap.y\n const z = ap.z\n\n if (x < minX) minX = x\n if (y < minY) minY = y\n if (z < minZ) minZ = z\n\n if (x > maxX) maxX = x\n if (y > maxY) maxY = y\n if (z > maxZ) maxZ = z\n }, selection)\n\n box.min.set(minX, minY, minZ)\n box.max.set(maxX, maxY, maxZ)\n\n if (Debug) Log.timeEnd('getBoundingBox')\n\n return box\n }\n\n /**\n * Gets the principal axes of the (selected) structure atoms\n * @param {Selection} [selection] - the selection\n * @return {PrincipalAxes} the principal axes\n */\n getPrincipalAxes (selection?: Selection) {\n if (Debug) Log.time('getPrincipalAxes')\n\n let i = 0\n const coords = new Matrix(3, this.atomCount)\n const cd = coords.data\n\n this.eachAtom(a => {\n cd[ i + 0 ] = a.x\n cd[ i + 1 ] = a.y\n cd[ i + 2 ] = a.z\n i += 3\n }, selection)\n\n if (Debug) Log.timeEnd('getPrincipalAxes')\n\n return new PrincipalAxes(coords)\n }\n\n /**\n * Gets the center of the (selected) structure atoms\n * @param {Selection} [selection] - the selection\n * @return {Vector3} the center\n */\n atomCenter (selection?: Selection) {\n if (selection) {\n return this.getBoundingBox(selection).getCenter(new Vector3())\n } else {\n return this.center.clone()\n }\n }\n\n hasCoords () {\n if (this._hasCoords === undefined) {\n const atomStore = this.atomStore\n this._hasCoords = (\n arrayMin(atomStore.x) !== 0 || arrayMax(atomStore.x) !== 0 ||\n arrayMin(atomStore.y) !== 0 || arrayMax(atomStore.y) !== 0 ||\n arrayMin(atomStore.z) !== 0 || arrayMax(atomStore.z) !== 0\n ) || (\n // allow models with a single atom at the origin\n atomStore.count / this.modelStore.count === 1\n )\n }\n return this._hasCoords;\n }\n\n getSequence (selection?: Selection) {\n const seq: string[] = []\n const rp = this.getResidueProxy()\n\n this.eachAtom(function (ap: AtomProxy) {\n rp.index = ap.residueIndex\n if (ap.index === rp.traceAtomIndex) {\n seq.push(rp.getResname1())\n }\n }, selection)\n\n return seq\n }\n\n getAtomIndices (selection?: Selection) {\n if (selection && selection.string) {\n const indices: number[] = []\n this.eachAtom(function (ap: AtomProxy) {\n indices.push(ap.index)\n }, selection)\n return new Uint32Array(indices)\n } else {\n const p = { what: { index: true } }\n return this.getAtomData(p).index\n }\n }\n\n /**\n * Get number of unique chainnames\n * @param {Selection} selection - limit count to selection\n * @return {Integer} count\n */\n getChainnameCount (selection?: Selection) {\n const chainnames = new Set()\n this.eachChain(function (cp: ChainProxy) {\n if (cp.residueCount) {\n chainnames.add(cp.chainname)\n }\n }, selection)\n\n return chainnames.size\n }\n\n /**\n * Update atomic positions\n * @param position - Array to copy positions from\n * @param refresh - Whether or not to issue a full refresh (automatically\n * triggers re-calculation of bounding boxes, spatial hash,\n * representations etc etc). This provides compatibility with\n * the old behaviour\n */\n updatePosition (position: Float32Array|number[], refresh: boolean = true) {\n let i = 0\n\n this.eachAtom(function (ap: AtomProxy) {\n ap.positionFromArray(position, i)\n i += 3\n }, undefined)\n\n this._hasCoords = undefined // to trigger recalculation (of the _hasCoords value)\n\n if (refresh) { \n this.refreshPosition() // Recalculate bounds - structure-component listener will \n // trigger representation rebuild\n }\n\n }\n\n refreshPosition () {\n this.getBoundingBox(undefined, this.boundingBox)\n this.boundingBox.getCenter(this.center)\n this.spatialHash = new SpatialHash(this.atomStore, this.boundingBox)\n\n this.signals.refreshed.dispatch(this)\n }\n\n /**\n * Calls dispose() method of property objects.\n * Unsets properties to help garbage collection.\n * @return {undefined}\n */\n dispose () {\n if (this.frames) this.frames.length = 0\n if (this.boxes) this.boxes.length = 0\n\n this.bondStore.dispose()\n this.backboneBondStore.dispose()\n this.rungBondStore.dispose()\n this.atomStore.dispose()\n this.residueStore.dispose()\n this.chainStore.dispose()\n this.modelStore.dispose()\n\n // can't delete non-optional properties as of TS 4\n // and since we've already disposed them, don't need to.\n\n delete this.bondSet\n delete this.atomSet\n }\n}\n\nexport default Structure\n","/**\n * @file Shape\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Matrix4 required for declaration only\nimport { Box3, Vector3, Color, Matrix4 } from 'three'\n\nimport { createParams, ensureFloat32Array, getUintArray } from '../utils'\nimport {\n ArrowPrimitive, BoxPrimitive, ConePrimitive, CylinderPrimitive, EllipsoidPrimitive,\n OctahedronPrimitive, SpherePrimitive, TetrahedronPrimitive, TextPrimitive,\n TorusPrimitive, PointPrimitive, WidelinePrimitive\n} from './primitive'\nimport { MeshPicker } from '../utils/picker'\nimport Buffer from '../buffer/buffer'\nimport MeshBuffer from '../buffer/mesh-buffer'\nimport { TextBufferParameters } from '../buffer/text-buffer'\n\nconst tmpBox = new Box3()\n\nconst Primitives = [\n ArrowPrimitive, BoxPrimitive, ConePrimitive, CylinderPrimitive,\n EllipsoidPrimitive, OctahedronPrimitive, SpherePrimitive, TetrahedronPrimitive,\n TextPrimitive, TorusPrimitive, PointPrimitive, WidelinePrimitive\n]\n\nexport const ShapeDefaultParameters = {\n aspectRatio: 1.5,\n sphereDetail: 2,\n radialSegments: 50,\n disableImpostor: false,\n openEnded: false,\n dashedCylinder: false,\n labelParams: {} as Partial,\n pointSize: 2,\n sizeAttenuation: false,\n useTexture: true,\n linewidth: 2\n}\nexport type ShapeParameters = typeof ShapeDefaultParameters\n\n/**\n * Class for building custom shapes.\n *\n * @example\n * var shape = new NGL.Shape('shape', { disableImpostor: true });\n * shape.addSphere([ 0, 0, 9 ], [ 1, 0, 0 ], 1.5 );\n * shape.addEllipsoid([ 6, 0, 0 ], [ 1, 0, 0 ], 1.5, [ 3, 0, 0 ], [ 0, 2, 0 ]);\n * shape.addCylinder([ 0, 2, 7 ], [ 0, 0, 9 ], [ 1, 1, 0 ], 0.5);\n * shape.addCone([ 0, 2, 7 ], [ 0, 3, 3 ], [ 1, 1, 0 ], 1.5);\n * shape.addArrow([ 1, 2, 7 ], [ 30, 3, 3 ], [ 1, 0, 1 ], 1.0);\n * shape.addBox([ 0, 3, 0 ], [ 1, 0, 1 ], 2, [ 0, 1, 1 ], [ 1, 0, 1 ]);\n * var shapeComp = stage.addComponentFromObject(shape);\n * geoComp.addRepresentation('buffer');\n */\nclass Shape {\n name: string\n parameters: ShapeParameters\n\n boundingBox = new Box3()\n bufferList: Buffer[] = []\n meshCount = 0\n\n _center?: Vector3\n _primitiveData: { [k: string]: any } = {}\n\n /**\n * @param {String} name - name\n * @param {Object} params - parameter object\n * @param {Integer} params.aspectRatio - arrow aspect ratio, used for cylinder radius and cone length\n * @param {Integer} params.sphereDetail - sphere quality (icosahedron subdivisions)\n * @param {Integer} params.radialSegments - cylinder quality (number of segments)\n * @param {Boolean} params.disableImpostor - disable use of raycasted impostors for rendering\n * @param {Boolean} params.openEnded - capped or not\n * @param {TextBufferParameters} params.labelParams - label parameters\n */\n constructor (name = 'shape', params: Partial = {}) {\n this.name = name\n\n this.parameters = createParams(params, ShapeDefaultParameters)\n\n Primitives.forEach(P => {\n Object.keys(P.fields).forEach(name => {\n this._primitiveData[ P.getShapeKey(name) ] = []\n })\n this._primitiveData[ P.getShapeKey('name') ] = []\n })\n }\n\n /**\n * Add a buffer\n * @param {Buffer} buffer - buffer object\n * @return {Shape} this object\n */\n addBuffer (buffer: Buffer) {\n this.bufferList.push(buffer)\n\n const geometry = (buffer as any).geometry // TODO\n if (!geometry.boundingBox) {\n geometry.computeBoundingBox()\n }\n this.boundingBox.union(geometry.boundingBox)\n\n return this\n }\n\n /**\n * Add a mesh\n * @example\n * shape.addMesh(\n * [ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1 ],\n * [ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 ]\n * );\n *\n * @param {Float32Array|Array} position - positions\n * @param {Float32Array|Array} color - colors\n * @param {Uint32Array|Uint16Array|Array} [index] - indices\n * @param {Float32Array|Array} [normal] - normals\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addMesh (position: Float32Array|number[], color:Float32Array|number[], index: Uint32Array|Uint16Array|number[], normal?: Float32Array|number[], name?: string) {\n position = ensureFloat32Array(position)\n color = ensureFloat32Array(color)\n\n if (Array.isArray(index)) {\n index = getUintArray(index, position.length)\n }\n if (normal) {\n normal = ensureFloat32Array(normal)\n }\n\n let data\n if (normal === undefined || normal.length == 0 ) {\n data = { position, color, index }\n } else {\n data = { position, color, index, normal }\n }\n //const data = { position, color, index, normal }\n const picking = new MeshPicker(\n this, Object.assign({ serial: this.meshCount, name }, data)\n )\n const meshBuffer = new MeshBuffer(\n Object.assign({ picking }, data) as any\n )\n this.bufferList.push(meshBuffer)\n\n tmpBox.setFromArray(position)\n this.boundingBox.union(tmpBox)\n this.meshCount += 1\n\n return this\n }\n\n /**\n * Add a sphere\n * @example\n * shape.addSphere([ 0, 0, 9 ], [ 1, 0, 0 ], 1.5);\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} radius - radius value\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addSphere (position: Vector3|[number, number, number], color: Color|[number, number, number], radius: number, name: string) {\n SpherePrimitive.objectToShape(\n this, { position, color, radius, name }\n )\n return this\n }\n\n /**\n * Add an ellipsoid\n * @example\n * shape.addEllipsoid([ 6, 0, 0 ], [ 1, 0, 0 ], 1.5, [ 3, 0, 0 ], [ 0, 2, 0 ]);\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} radius - radius value\n * @param {Vector3|Array} majorAxis - major axis vector or array\n * @param {Vector3|Array} minorAxis - minor axis vector or array\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addEllipsoid (position: Vector3|[number, number, number], color: Color|[number, number, number], radius: number, majorAxis: Vector3|[number, number, number], minorAxis: Vector3|[number, number, number], name: string) {\n EllipsoidPrimitive.objectToShape(\n this, { position, color, radius, majorAxis, minorAxis, name }\n )\n return this\n }\n\n /**\n * Add a torus\n * @example\n * shape.addTorus([ 6, 0, 0 ], [ 1, 0, 0 ], 1.5, [ 3, 0, 0 ], [ 0, 2, 0 ]);\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} radius - radius value\n * @param {Vector3|Array} majorAxis - major axis vector or array\n * @param {Vector3|Array} minorAxis - minor axis vector or array\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addTorus (position: Vector3|[number, number, number], color: Color|[number, number, number], radius: number, majorAxis: Vector3|[number, number, number], minorAxis: Vector3|[number, number, number], name: string) {\n TorusPrimitive.objectToShape(\n this, { position, color, radius, majorAxis, minorAxis, name }\n )\n return this\n }\n\n /**\n * Add a cylinder\n * @example\n * shape.addCylinder([ 0, 2, 7 ], [ 0, 0, 9 ], [ 1, 1, 0 ], 0.5);\n *\n * @param {Vector3|Array} position1 - from position vector or array\n * @param {Vector3|Array} position2 - to position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} radius - radius value\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addCylinder (position1: Vector3|[number, number, number], position2: Vector3|[number, number, number], color: Color|[number, number, number], radius: number, name: string) {\n CylinderPrimitive.objectToShape(\n this, { position1, position2, color, radius, name }\n )\n return this\n }\n\n /**\n * Add a cone\n * @example\n * shape.addCone([ 0, 2, 7 ], [ 0, 3, 3 ], [ 1, 1, 0 ], 1.5);\n *\n * @param {Vector3|Array} position1 - from position vector or array\n * @param {Vector3|Array} position2 - to position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} radius - radius value\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addCone (position1: Vector3|[number, number, number], position2: Vector3|[number, number, number], color: Color|[number, number, number], radius: number, name: string) {\n ConePrimitive.objectToShape(\n this, { position1, position2, color, radius, name }\n )\n return this\n }\n\n /**\n * Add an arrow\n * @example\n * shape.addArrow([ 0, 2, 7 ], [ 0, 0, 9 ], [ 1, 1, 0 ], 0.5);\n *\n * @param {Vector3|Array} position1 - from position vector or array\n * @param {Vector3|Array} position2 - to position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} radius - radius value\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addArrow (position1: Vector3|[number, number, number], position2: Vector3|[number, number, number], color: Color|[number, number, number], radius: number, name: string) {\n ArrowPrimitive.objectToShape(\n this, { position1, position2, color, radius, name }\n )\n return this\n }\n\n /**\n * Add a box\n * @example\n * shape.addBox([ 0, 3, 0 ], [ 1, 0, 1 ], 2, [ 0, 1, 1 ], [ 1, 0, 1 ]);\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} size - size value\n * @param {Vector3|Array} heightAxis - height axis vector or array\n * @param {Vector3|Array} depthAxis - depth axis vector or array\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addBox (position: Vector3|[number, number, number], color: Color|[number, number, number], size: number, heightAxis: Vector3|[number, number, number], depthAxis: Vector3|[number, number, number], name: string) {\n BoxPrimitive.objectToShape(\n this, { position, color, size, heightAxis, depthAxis, name }\n )\n return this\n }\n\n /**\n * Add an octahedron\n * @example\n * shape.addOctahedron([ 0, 3, 0 ], [ 1, 0, 1 ], 2, [ 0, 1, 1 ], [ 1, 0, 1 ]);\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} size - size value\n * @param {Vector3|Array} heightAxis - height axis vector or array\n * @param {Vector3|Array} depthAxis - depth axis vector or array\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addOctahedron (position: Vector3|[number, number, number], color: Color|[number, number, number], size: number, heightAxis: Vector3|[number, number, number], depthAxis: Vector3|[number, number, number], name: string) {\n OctahedronPrimitive.objectToShape(\n this, { position, color, size, heightAxis, depthAxis, name }\n )\n return this\n }\n\n /**\n * Add a tetrahedron\n * @example\n * shape.addTetrahedron([ 0, 3, 0 ], [ 1, 0, 1 ], 2, [ 0, 1, 1 ], [ 1, 0, 1 ]);\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} size - size value\n * @param {Vector3|Array} heightAxis - height axis vector or array\n * @param {Vector3|Array} depthAxis - depth axis vector or array\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addTetrahedron (position: Vector3|[number, number, number], color: Color|[number, number, number], size: number, heightAxis: Vector3|[number, number, number], depthAxis: Vector3|[number, number, number], name: string) {\n TetrahedronPrimitive.objectToShape(\n this, { position, color, size, heightAxis, depthAxis, name }\n )\n return this\n }\n\n /**\n * Add text\n * @example\n * shape.addText([ 10, -2, 4 ], [ 0.2, 0.5, 0.8 ], 0.5, \"Hello\");\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {Float} size - size value\n * @param {String} text - text value\n * @return {Shape} this object\n */\n addText (position: Vector3|[number, number, number], color: Color|[number, number, number], size: number, text: string) {\n TextPrimitive.objectToShape(\n this, { position, color, size, text }\n )\n return this\n }\n\n /**\n * Add point\n * @example\n * shape.addPoint([ 10, -2, 4 ], [ 0.2, 0.5, 0.8 ]);\n *\n * @param {Vector3|Array} position - position vector or array\n * @param {Color|Array} color - color object or array\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addPoint (position: Vector3|[number, number, number], color: Color|[number, number, number], name: string) {\n PointPrimitive.objectToShape(\n this, { position, color, name }\n )\n return this\n }\n\n /**\n * Add a wideline\n * @example\n * shape.addWideline([ 0, 2, 7 ], [ 0, 0, 9 ], [ 1, 1, 0 ]);\n *\n * @param {Vector3|Array} position1 - from position vector or array\n * @param {Vector3|Array} position2 - to position vector or array\n * @param {Color|Array} color - color object or array\n * @param {String} [name] - text\n * @return {Shape} this object\n */\n addWideline (position1: Vector3|[number, number, number], position2: Vector3|[number, number, number], color: Color|[number, number, number], linewidth: number, name: string) {\n this.parameters.linewidth = linewidth\n WidelinePrimitive.objectToShape(\n this, { position1, position2, color, name }\n )\n return this\n }\n\n /**\n * Deprecated, use `.addText`\n */\n addLabel (position: Vector3|[number, number, number], color: Color|[number, number, number], size: number, text: string) {\n console.warn('Shape.addLabel is deprecated, use .addText instead')\n return this.addText(position, color, size, text)\n }\n\n getBufferList () {\n const buffers: Buffer[] = []\n\n Primitives.forEach(P => {\n if (this._primitiveData[ P.getShapeKey('color') ].length) {\n buffers.push(P.bufferFromShape(this, this.parameters))\n }\n })\n\n return this.bufferList.concat(buffers)\n }\n\n dispose () {\n this.bufferList.forEach(function (buffer) {\n buffer.dispose()\n })\n this.bufferList.length = 0\n\n Primitives.forEach(P => {\n Object.keys(P.fields).forEach(name => {\n this._primitiveData[ P.getShapeKey(name) ].length = 0\n })\n this._primitiveData[ P.getShapeKey('name') ].length = 0\n })\n }\n\n get center () {\n if (!this._center) {\n this._center = this.boundingBox.getCenter(new Vector3())\n }\n return this._center\n }\n\n get type () { return 'Shape' }\n}\n\nexport default Shape\n","/**\n * @file Buffer Representation\n * @author Alexander Rose \n * @private\n */\n\nimport Representation, { RepresentationParameters } from './representation'\nimport Viewer from '../viewer/viewer';\n\n/**\n * Representation for showing buffer objects. Good for efficiently showing\n * large amounts of geometric primitives e.g. spheres via {@link SphereBuffer}.\n * Smaller numbers of geometric primitives are more easily shown with help\n * from the {@link Shape} class.\n *\n * __Name:__ _buffer_\n *\n * @example\n * // add a single red sphere from a buffer to a shape instance\n * var shape = new NGL.Shape( \"shape\" );\n * var sphereBuffer = new NGL.SphereBuffer( {\n * position: new Float32Array( [ 0, 0, 0 ] ),\n * color: new Float32Array( [ 1, 0, 0 ] ),\n * radius: new Float32Array( [ 1 ] )\n * } );\n * shape.addBuffer( sphereBuffer );\n * var shapeComp = stage.addComponentFromObject( shape );\n * shapeComp.addRepresentation( \"buffer\" );\n *\n * @example\n * // add a single red sphere from a buffer to a structure component instance\n * stage.loadFile( \"rcsb://1crn\" ).then( function( o ){\n * var sphereBuffer = new NGL.SphereBuffer( {\n * position: new Float32Array( [ 0, 0, 0 ] ),\n * color: new Float32Array( [ 1, 0, 0 ] ),\n * radius: new Float32Array( [ 1 ] )\n * } );\n * o.addBufferRepresentation( sphereBuffer, { opacity: 0.5 } );\n * } );\n */\nclass BufferRepresentation extends Representation {\n buffer: Buffer[]\n /**\n * Create Buffer representation\n * @param {Buffer} buffer - a buffer object\n * @param {Viewer} viewer - a viewer object\n * @param {RepresentationParameters} params - representation parameters\n */\n constructor (buffer: Buffer|Buffer[], viewer: Viewer, params: Partial) {\n if (!Array.isArray(buffer)) {\n buffer = [ buffer ]\n }\n\n super(buffer, viewer, params)\n\n this.type = 'buffer'\n\n this.parameters = Object.assign({\n\n }, this.parameters, {\n\n colorScheme: null,\n colorScale: null,\n colorValue: null,\n colorDomain: null,\n colorMode: null\n\n })\n\n this.buffer = buffer\n\n this.init(params)\n }\n\n init (params: Partial) {\n super.init(params)\n\n this.build()\n }\n\n create () {\n this.bufferList.push.apply(this.bufferList, this.buffer)\n }\n\n attach (callback: ()=> void) {\n this.bufferList.forEach(buffer => {\n this.viewer.add(buffer)\n buffer.setParameters(this.getBufferParams())\n })\n this.setVisibility(this.visible)\n\n callback()\n }\n}\n\nexport default BufferRepresentation\n","/**\n * @file Geometry Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3 required for declaration only\n import { Vector3, Matrix4, Matrix3, BufferGeometry } from 'three'\n\nimport { getUintArray } from '../utils'\nimport { serialBlockArray } from '../math/array-utils'\nimport { applyMatrix3toVector3array, applyMatrix4toVector3array } from '../math/vector-utils'\nimport MeshBuffer from './mesh-buffer'\nimport { BufferParameters, BufferData } from './buffer'\nimport {Log} from \"../globals\";\n\nconst matrix = new Matrix4()\nconst normalMatrix = new Matrix3()\n\nfunction getData(data: BufferData, geo: BufferGeometry){\n const geoPosition = (geo.attributes as any).position.array\n const geoIndex = geo.index ? geo.index.array : undefined\n\n const n = data.position!.length / 3\n const m = geoPosition.length / 3\n\n const size = n * m\n\n const meshPosition = new Float32Array(size * 3)\n const meshNormal = new Float32Array(size * 3)\n const meshColor = new Float32Array(size * 3)\n\n let meshIndex\n if (geoIndex) {\n meshIndex = getUintArray(n * geoIndex.length, size)\n }\n\n return {\n position: meshPosition,\n color: meshColor,\n index: meshIndex,\n normal: meshNormal,\n primitiveId: data.primitiveId || serialBlockArray(n, m) as Float32Array,\n picking: data.picking\n }\n}\n\n/**\n * Geometry buffer. Base class for geometry-based buffers. Used to draw\n * geometry primitives given a mesh.\n * @interface\n */\nabstract class GeometryBuffer extends MeshBuffer {\n updateNormals = false\n\n geoPosition: Float32Array\n geoNormal: Float32Array\n geoIndex?: Uint32Array|Uint16Array\n\n positionCount: number\n geoPositionCount: number\n\n transformedGeoPosition: Float32Array\n transformedGeoNormal: Float32Array\n\n meshPosition: Float32Array\n meshColor: Float32Array\n meshIndex: Uint32Array|Uint16Array\n meshNormal: Float32Array\n\n /**\n * @param {Object} data - buffer data\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} [params] - parameters object\n * @param {BufferGeometry} geo - geometry object\n */\n constructor (data: BufferData, params: Partial = {}, geo: BufferGeometry) {\n super(getData(data, geo), params)\n\n const geoPosition = (geo.attributes as any).position.array\n const geoNormal = (geo.attributes as any).normal.array\n const geoIndex = geo.index ? (geo.index.array as Uint32Array|Uint16Array) : undefined\n\n this.geoPosition = geoPosition\n this.geoNormal = geoNormal\n this.geoIndex = geoIndex\n\n this.positionCount = data.position!.length / 3\n this.geoPositionCount = geoPosition.length / 3\n\n this.transformedGeoPosition = new Float32Array(this.geoPositionCount * 3)\n this.transformedGeoNormal = new Float32Array(this.geoPositionCount * 3)\n\n const attributes = this.geometry.attributes as any // TODO\n this.meshPosition = attributes.position.array\n this.meshColor = attributes.color.array\n this.meshNormal = attributes.normal.array\n\n this.setAttributes(data)\n\n if (geoIndex) {\n const index = this.geometry.getIndex()\n if (!index) { Log.error('Index is null'); return; }\n this.meshIndex = index.array as Uint32Array|Uint16Array\n this.makeIndex()\n }\n }\n\n abstract applyPositionTransform (matrix: Matrix4, i: number, i3?: number): void\n\n setAttributes (data: Partial = {}, initNormals = false) {\n const attributes = this.geometry.attributes as any // TODO\n\n let position, color\n let geoPosition, geoNormal\n let transformedGeoPosition, transformedGeoNormal\n let meshPosition, meshColor, meshNormal\n\n const updateNormals = this.updateNormals\n\n if (data.position) {\n position = data.position\n geoPosition = this.geoPosition\n meshPosition = this.meshPosition\n transformedGeoPosition = this.transformedGeoPosition\n attributes.position.needsUpdate = true\n if (updateNormals || initNormals) {\n geoNormal = this.geoNormal\n meshNormal = this.meshNormal\n transformedGeoNormal = this.transformedGeoNormal\n attributes.normal.needsUpdate = true\n }\n }\n\n if (data.color) {\n color = data.color\n meshColor = this.meshColor\n attributes.color.needsUpdate = true\n }\n\n const n = this.positionCount\n const m = this.geoPositionCount\n\n for (let i = 0; i < n; ++i) {\n let j, l\n const k = i * m * 3\n const i3 = i * 3\n\n if (position && transformedGeoPosition && meshPosition && meshNormal && geoPosition && geoNormal) {\n transformedGeoPosition.set(geoPosition)\n matrix.makeTranslation(\n position[ i3 ], position[ i3 + 1 ], position[ i3 + 2 ]\n )\n this.applyPositionTransform(matrix, i, i3)\n applyMatrix4toVector3array(matrix.elements as unknown as Float32Array,\n transformedGeoPosition)\n\n meshPosition.set(transformedGeoPosition, k)\n\n if (updateNormals && transformedGeoNormal) {\n transformedGeoNormal.set(geoNormal)\n normalMatrix.getNormalMatrix(matrix)\n applyMatrix3toVector3array(normalMatrix.elements as unknown as Float32Array,\n transformedGeoNormal)\n\n meshNormal.set(transformedGeoNormal, k)\n } else if (initNormals) {\n meshNormal.set(geoNormal, k)\n }\n }\n\n if (color && meshColor) {\n for (j = 0; j < m; ++j) {\n l = k + 3 * j\n\n meshColor[ l ] = color[ i3 ]\n meshColor[ l + 1 ] = color[ i3 + 1 ]\n meshColor[ l + 2 ] = color[ i3 + 2 ]\n }\n }\n }\n }\n\n makeIndex () {\n const geoIndex = this.geoIndex\n const meshIndex = this.meshIndex\n\n if (!geoIndex) return\n\n const n = this.positionCount\n const m = this.geoPositionCount\n const o = geoIndex.length / 3\n\n const o3 = o * 3\n\n for (let i = 0; i < n; ++i) {\n const j = i * o3\n const q = j + o3\n\n meshIndex.set(geoIndex, j)\n for (let p = j; p < q; ++p) meshIndex[ p ] += i * m\n }\n }\n}\n\nexport default GeometryBuffer\n","/**\n * @file Sphere Geometry Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { IcosahedronGeometry, Vector3, Matrix4 } from 'three'\nimport { defaults } from '../utils'\nimport GeometryBuffer from './geometry-buffer'\nimport { SphereBufferData } from './sphere-buffer'\nimport { BufferDefaultParameters, BufferParameters } from './buffer'\n\nconst scale = new Vector3()\n\nexport const SphereGeometryBufferDefaultParameters = Object.assign({\n sphereDetail: 1\n}, BufferDefaultParameters)\nexport type SphereGeometryBufferParameters = BufferParameters & { sphereDetail: number }\n\n/**\n * Sphere geometry buffer.\n *\n * @example\n * var sphereGeometryBuffer = new SphereGeometryBuffer({\n * position: new Float32Array([ 0, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n */\nclass SphereGeometryBuffer extends GeometryBuffer {\n get defaultParameters() { return SphereGeometryBufferDefaultParameters }\n parameters: SphereGeometryBufferParameters\n\n private _radius: Float32Array\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: SphereBufferData, params: Partial = {}) {\n super(data, params, new IcosahedronGeometry(1, defaults(params.sphereDetail, 1)))\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number) {\n const r = this._radius[ i ]\n scale.set(r, r, r)\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n if (data.radius) this._radius = data.radius\n\n super.setAttributes(data, initNormals)\n }\n}\n\nexport default SphereGeometryBuffer\n","/**\n * @file Mapped Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { getUintArray } from '../utils'\nimport { calculateCenterArray, serialArray } from '../math/array-utils'\nimport Buffer, { BufferParameters, BufferData } from './buffer'\n\nexport type MappingType = 'v2'|'v3'\n\n/**\n * Mapped buffer. Sends mapping attribute to the GPU and repeats data in\n * others attributes. Used to render imposters.\n * @interface\n */\nabstract class MappedBuffer extends Buffer {\n index: Uint32Array|Uint16Array\n\n constructor (mappingType: MappingType, data: BufferData, params: Partial = {}) {\n super(data, params)\n\n this.index = getUintArray(this.indexSize, this.attributeSize)\n this.makeIndex()\n this.initIndex(this.index)\n\n this.addAttributes({\n 'mapping': { type: mappingType, value: null }\n })\n\n this.setAttributes({ primitiveId: serialArray(this.size) })\n }\n\n abstract get mapping (): Float32Array\n abstract get mappingIndices (): Uint32Array|Uint16Array\n abstract get mappingIndicesSize (): number\n abstract get mappingSize (): number\n abstract get mappingItemSize (): number\n\n get attributeSize () {\n return this.size * this.mappingSize\n }\n\n get indexSize () {\n return this.size * this.mappingIndicesSize\n }\n\n addAttributes (attributes: any) {\n const nullValueAttributes: any = {}\n for (const name in attributes) {\n const a = attributes[ name ]\n nullValueAttributes[ name ] = {\n type: a.type,\n value: null\n }\n }\n\n super.addAttributes(nullValueAttributes)\n }\n\n getAttributeIndex (dataIndex: number) {\n return dataIndex * 3 * this.mappingSize\n }\n\n setAttributes (data: any) { // TODO\n if (data && !data.position && data.position1 && data.position2) {\n data.position = calculateCenterArray(data.position1, data.position2)\n }\n\n const size = this.size\n const mappingSize = this.mappingSize\n const attributes = this.geometry.attributes as any // TODO\n\n let a, d, itemSize, array, n, i, j\n\n for (const name in data) {\n if (name === 'index' || name === 'picking') continue\n\n d = data[ name ]\n a = attributes[ name ]\n itemSize = a.itemSize\n array = a.array\n\n for (let k = 0; k < size; ++k) {\n n = k * itemSize\n i = n * mappingSize\n\n for (let l = 0; l < mappingSize; ++l) {\n j = i + (itemSize * l)\n\n for (let m = 0; m < itemSize; ++m) {\n array[ j + m ] = d[ n + m ]\n }\n }\n }\n\n a.needsUpdate = true\n }\n }\n\n makeMapping () {\n const size = this.size\n const mapping = this.mapping\n const mappingSize = this.mappingSize\n const mappingItemSize = this.mappingItemSize\n\n const attributes = this.geometry.attributes as any // TODO\n const aMapping = attributes.mapping.array\n\n for (let v = 0; v < size; v++) {\n aMapping.set(mapping, v * mappingItemSize * mappingSize)\n }\n }\n\n makeIndex () {\n const size = this.size\n const mappingSize = this.mappingSize\n const mappingIndices = this.mappingIndices\n const mappingIndicesSize = this.mappingIndicesSize\n\n const index = this.index\n\n for (let v = 0; v < size; v++) {\n const ix = v * mappingIndicesSize\n const it = v * mappingSize\n\n index.set(mappingIndices, ix)\n\n for (let s = 0; s < mappingIndicesSize; ++s) {\n index[ ix + s ] += it\n }\n }\n }\n}\n\nexport default MappedBuffer\n","/**\n * @file Mapped Quad Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { BufferParameters, BufferData } from './buffer'\nimport MappedBuffer from './mapped-buffer'\n\nconst mapping = new Float32Array([\n -1.0, 1.0,\n -1.0, -1.0,\n 1.0, 1.0,\n 1.0, -1.0\n])\n\nconst mappingIndices = new Uint16Array([\n 0, 1, 2,\n 1, 3, 2\n])\n\n/**\n * Mapped Quad buffer. Draws screen-aligned quads. Used to render impostors.\n * @interface\n */\nclass MappedQuadBuffer extends MappedBuffer {\n constructor(data: BufferData, params: Partial = {}) {\n super('v2', data, params)\n }\n get mapping () { return mapping }\n get mappingIndices () { return mappingIndices }\n get mappingIndicesSize () { return 6 }\n get mappingSize () { return 4 }\n get mappingItemSize () { return 2 }\n}\n\nexport default MappedQuadBuffer\n","/**\n * @file Sphere Impostor Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4 } from 'three'\n\nimport '../shader/SphereImpostor.vert'\nimport '../shader/SphereImpostor.frag'\n\nimport MappedQuadBuffer from './mappedquad-buffer'\nimport { SphereBufferData } from './sphere-buffer'\nimport { BufferParameters } from './buffer'\n\n/**\n * Sphere impostor buffer.\n *\n * @example\n * var sphereImpostorBuffer = new SphereImpostorBuffer({\n * position: new Float32Array([ 0, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n */\nclass SphereImpostorBuffer extends MappedQuadBuffer {\n isImpostor = true\n vertexShader = 'SphereImpostor.vert'\n fragmentShader = 'SphereImpostor.frag'\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: SphereBufferData, params: Partial = {}) {\n super(data, params)\n\n this.addUniforms({\n 'projectionMatrixInverse': { value: new Matrix4() },\n 'ortho': { value: 0.0 }\n })\n\n this.addAttributes({\n 'radius': { type: 'f', value: null }\n })\n\n this.setAttributes(data)\n this.makeMapping()\n }\n}\n\nexport default SphereImpostorBuffer\n","/**\n * @file Sphere Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3, Matrix4 required for declaration only \nimport { Vector3, Matrix4 } from 'three'\nimport { BufferRegistry, ExtensionFragDepth } from '../globals'\nimport SphereGeometryBuffer, { SphereGeometryBufferDefaultParameters, SphereGeometryBufferParameters } from './spheregeometry-buffer'\nimport SphereImpostorBuffer from './sphereimpostor-buffer'\nimport { BufferData } from './buffer'\n\nexport interface SphereBufferData extends BufferData {\n radius: Float32Array\n}\n\nexport const SphereBufferDefaultParameters = Object.assign({\n disableImpostor: false\n}, SphereGeometryBufferDefaultParameters)\nexport type SphereBufferParameters = SphereGeometryBufferParameters & { disableImpostor: boolean }\n\nclass SphereBufferImpl {\n /**\n * @param {Object} data - buffer data\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} params - parameters object\n * @return {SphereGeometryBuffer|SphereImpostorBuffer} the buffer object\n */\n constructor (data: SphereBufferData, params: SphereBufferParameters) {\n if (!ExtensionFragDepth || (params && params.disableImpostor)) {\n return new SphereGeometryBuffer(data, params)\n } else {\n return new SphereImpostorBuffer(data, params)\n }\n }\n}\n\n/**\n * Sphere buffer. Depending on the value {@link ExtensionFragDepth} and\n * `params.disableImpostor` the constructor returns either a\n * {@link SphereGeometryBuffer} or a {@link SphereImpostorBuffer}\n * @implements {Buffer}\n *\n * @example\n * var sphereBuffer = new SphereBuffer( {\n * position: new Float32Array( [ 0, 0, 0 ] ),\n * color: new Float32Array( [ 1, 0, 0 ] ),\n * radius: new Float32Array( [ 1 ] )\n * } );\n */\n//@ts-expect-error Incompatible constructor signatures\nconst SphereBuffer: {\n new(data: SphereBufferData, params: SphereBufferParameters): SphereGeometryBuffer | SphereImpostorBuffer;\n} = SphereBufferImpl;\n\ntype SphereBuffer = SphereGeometryBuffer | SphereImpostorBuffer;\n\nBufferRegistry.add('sphere', SphereBuffer)\n\nexport default SphereBuffer\n","/**\n * @file Point Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3, Matrix4 required for declaration only\nimport { DataTexture, Vector3, Matrix4 } from 'three'\n\nimport '../shader/Point.vert'\nimport '../shader/Point.frag'\n\nimport { BufferRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { smoothstep } from '../math/math-utils'\nimport Buffer, { BufferDefaultParameters, BufferParameterTypes, BufferData, BufferTypes, BufferParameters } from './buffer'\n\nfunction distance (x0: number, y0: number, x1: number, y1: number) {\n const dx = x1 - x0\n const dy = y1 - y0\n return Math.sqrt(dx * dx + dy * dy)\n}\n\ninterface PointTextureParams {\n width?: number\n height?: number\n delta?: number\n}\n\nfunction makePointTexture (params: PointTextureParams) {\n const p = params || {}\n\n const width = defaults(p.width, 256)\n const height = defaults(p.height, 256)\n const center = [ width / 2, height / 2 ]\n const radius = Math.min(width / 2, height / 2)\n const delta = defaults(p.delta, 1 / (radius + 1)) * radius\n\n let x = 0\n let y = 0\n const data = new Uint8Array(width * height * 4)\n\n for (let i = 0, il = data.length; i < il; i += 4) {\n const dist = distance(x, y, center[ 0 ], center[ 1 ])\n const value = 1 - smoothstep(radius - delta, radius, dist)\n\n data[ i ] = value * 255\n data[ i + 1 ] = value * 255\n data[ i + 2 ] = value * 255\n data[ i + 3 ] = value * 255\n\n if (++x === width) {\n x = 0\n y++\n }\n }\n\n const tex = new DataTexture(data, width, height)\n tex.needsUpdate = true\n\n return tex\n}\n\nexport const PointBufferDefaultParameters = Object.assign({\n pointSize: 1,\n sizeAttenuation: true,\n sortParticles: false,\n alphaTest: 0.5,\n useTexture: false,\n forceTransparent: false,\n edgeBleach: 0.0\n}, BufferDefaultParameters)\nexport type PointBufferParameters = BufferParameters & {\n pointSize: number,\n sizeAttenuation: boolean,\n sortParticles: boolean,\n alphaTest: number,\n useTexture: boolean,\n forceTransparent: boolean,\n edgeBleach: number\n}\n\nconst PointBufferParameterTypes = Object.assign({\n pointSize: { uniform: 'size' },\n sizeAttenuation: { updateShader: true },\n sortParticles: {},\n alphaTest: { uniform: true },\n useTexture: { updateShader: true },\n forceTransparent: {},\n edgeBleach: { uniform: true }\n}, BufferParameterTypes)\n\n/**\n * Point buffer. Draws points. Optionally textured.\n *\n * @example\n * var pointBuffer = new PointBuffer( {\n * position: new Float32Array( [ 0, 0, 0 ] ),\n * color: new Float32Array( [ 1, 0, 0 ] )\n * } );\n */\nclass PointBuffer extends Buffer {\n parameterTypes = PointBufferParameterTypes\n get defaultParameters() { return PointBufferDefaultParameters }\n parameters: PointBufferParameters\n\n vertexShader = 'Point.vert'\n fragmentShader ='Point.frag'\n\n isPoint = true\n tex: DataTexture\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: BufferData, params: Partial = {}) {\n super(data, params)\n\n this.addUniforms({\n 'size': { value: this.parameters.pointSize },\n 'canvasHeight': { value: 1.0 },\n 'pixelRatio': { value: 1.0 },\n 'map': { value: null },\n 'alphaTest': {value: this.parameters.alphaTest}\n })\n }\n\n makeMaterial () {\n super.makeMaterial()\n\n this.makeTexture()\n\n const m = this.material\n const wm = this.wireframeMaterial\n const pm = this.pickingMaterial\n\n m.uniforms.map.value = this.tex\n m.needsUpdate = true\n\n wm.uniforms.map.value = this.tex\n wm.needsUpdate = true\n\n pm.uniforms.map.value = this.tex\n pm.needsUpdate = true\n }\n\n makeTexture () {\n if (this.tex) this.tex.dispose()\n this.tex = makePointTexture({ delta: this.parameters.edgeBleach })\n }\n\n getDefines (type?: BufferTypes) {\n const defines = super.getDefines(type)\n\n if (this.parameters.sizeAttenuation) {\n defines.USE_SIZEATTENUATION = 1\n }\n\n if (this.parameters.useTexture) {\n defines.USE_MAP = 1\n }\n\n if (this.parameters.alphaTest > 0 && this.parameters.alphaTest <= 1) {\n defines.USE_ALPHATEST = 1\n }\n\n return defines\n }\n\n setUniforms (data: any) {\n if (data && data.edgeBleach !== undefined) {\n this.makeTexture()\n data.map = this.tex\n }\n\n super.setUniforms(data)\n }\n\n dispose () {\n super.dispose()\n\n if (this.tex) this.tex.dispose()\n }\n}\n\nBufferRegistry.add('point', PointBuffer)\n\nexport default PointBuffer\n","/**\n * @file Dot Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { ExtensionFragDepth } from '../globals'\nimport { defaults } from '../utils'\nimport Representation, { RepresentationParameters } from './representation'\nimport Volume from '../surface/volume'\nimport FilteredVolume from '../surface/filtered-volume'\nimport SphereBuffer, { SphereBufferData, SphereBufferParameters } from '../buffer/sphere-buffer'\nimport PointBuffer from '../buffer/point-buffer'\nimport Surface from '../surface/surface';\nimport Viewer from '../viewer/viewer';\nimport SphereGeometryBuffer from '../buffer/spheregeometry-buffer';\n\nexport interface DotDataFields {\n color?: boolean,\n radius?: boolean,\n scale?: boolean\n}\n\n/**\n * Dot representation parameter object. Extends {@link RepresentationParameters}\n *\n * @typedef {Object} DotRepresentationParameters - dot representation parameters\n *\n * @property {String} thresholdType - Meaning of the threshold values. Either *value* for the literal value or *sigma* as a factor of the sigma of the data. For volume data only.\n * @property {Number} thresholdMin - Minimum value to be displayed. For volume data only.\n * @property {Number} thresholdMax - Maximum value to be displayed. For volume data only.\n * @property {Number} thresholdOut - Show only values falling outside of the treshold minumum and maximum. For volume data only.\n */\nexport interface DotRepresentationParameters extends RepresentationParameters {\n thresholdType: 'value'|'value'|'sigma'|'sigma'\n thresholdMin: number\n thresholdMax: number\n thresholdOut: boolean\n dotType: ''|'sphere'|'point'\n radiusType: ''|'value'|'abs-value'|'value-min'|'deviation'|'size'|'radius' //TODO had to add 'radius' because of test in line 333\n radius: number\n scale: number\n sphereDetail: number\n disableImpostor: boolean\n pointSize: number\n sizeAttenuation: boolean\n sortParticles: boolean\n useTexture: boolean\n alphaTest: number\n forceTransparent: boolean\n edgeBleach: number\n}\n/**\n * Dot representation\n */\nclass DotRepresentation extends Representation {\n protected thresholdType: 'value'|'value'|'sigma'|'sigma'\n protected thresholdMin: number\n protected thresholdMax: number\n protected thresholdOut: boolean\n protected dotType: ''|'sphere'|'point'\n protected radiusType: ''|'value'|'abs-value'|'value-min'|'deviation'|'size'|'radius' //TODO had to add 'radius' because of test in line 333\n protected radius: number\n protected scale: number\n protected sphereDetail: number\n protected disableImpostor: boolean\n protected pointSize: number\n protected sizeAttenuation: boolean\n protected sortParticles: boolean\n protected useTexture: boolean\n protected alphaTest: number\n protected forceTransparent: boolean\n protected edgeBleach: number\n\n protected surface: Surface|undefined\n protected volume: FilteredVolume|undefined\n protected dotBuffer: SphereBuffer|PointBuffer\n /**\n * Create Dot representation object\n * @param {Surface|Volume} surface - the surface or volume to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {DotRepresentationParameters} params - dot representation parameters\n */\n constructor (surface: Surface, viewer: Viewer, params: Partial) {\n super(surface, viewer, params)\n\n this.type = 'dot'\n\n this.parameters = Object.assign({\n\n thresholdType: {\n type: 'select',\n rebuild: true,\n options: {\n 'value': 'value', 'sigma': 'sigma'\n }\n },\n thresholdMin: {\n type: 'number', precision: 3, max: Infinity, min: -Infinity, rebuild: true\n },\n thresholdMax: {\n type: 'number', precision: 3, max: Infinity, min: -Infinity, rebuild: true\n },\n thresholdOut: {\n type: 'boolean', rebuild: true\n },\n dotType: {\n type: 'select',\n rebuild: true,\n options: {\n '': '',\n 'sphere': 'sphere',\n 'point': 'point'\n }\n },\n radiusType: {\n type: 'select',\n options: {\n '': '',\n 'value': 'value',\n 'abs-value': 'abs-value',\n 'value-min': 'value-min',\n 'deviation': 'deviation',\n 'size': 'size'\n }\n },\n radius: {\n type: 'number', precision: 3, max: 10.0, min: 0.001, property: 'size'\n },\n scale: {\n type: 'number', precision: 3, max: 10.0, min: 0.001\n },\n sphereDetail: true,\n disableImpostor: true,\n\n pointSize: {\n type: 'number', precision: 1, max: 100, min: 0, buffer: true\n },\n sizeAttenuation: {\n type: 'boolean', buffer: true\n },\n sortParticles: {\n type: 'boolean', rebuild: true\n },\n useTexture: {\n type: 'boolean', buffer: true\n },\n alphaTest: {\n type: 'range', step: 0.001, max: 1, min: 0, buffer: true\n },\n forceTransparent: {\n type: 'boolean', buffer: true\n },\n edgeBleach: {\n type: 'range', step: 0.001, max: 1, min: 0, buffer: true\n }\n\n }, this.parameters, {\n\n colorScheme: {\n type: 'select',\n update: 'color',\n options: {\n '': '',\n 'value': 'value',\n 'uniform': 'uniform',\n 'random': 'random'\n }\n }\n\n })\n\n if (surface instanceof Volume) {\n this.surface = undefined\n this.volume = new FilteredVolume(surface)\n } else {\n this.surface = surface\n this.volume = undefined\n }\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'uniform')\n p.colorValue = defaults(p.colorValue, 0xDDDDDD)\n\n this.thresholdType = defaults(p.thresholdType, 'sigma')\n this.thresholdMin = defaults(p.thresholdMin, 2.0)\n this.thresholdMax = defaults(p.thresholdMax, Infinity)\n this.thresholdOut = defaults(p.thresholdOut, false)\n this.dotType = defaults(p.dotType, 'point')\n this.radius = defaults(p.radius, 0.1)\n this.scale = defaults(p.scale, 1.0)\n\n this.pointSize = defaults(p.pointSize, 1)\n this.sizeAttenuation = defaults(p.sizeAttenuation, true)\n this.sortParticles = defaults(p.sortParticles, false)\n this.useTexture = defaults(p.useTexture, false)\n this.alphaTest = defaults(p.alphaTest, 0.5)\n this.forceTransparent = defaults(p.forceTransparent, false)\n this.edgeBleach = defaults(p.edgeBleach, 0.0)\n\n super.init(p)\n\n this.build()\n }\n\n attach (callback: () => void) {\n this.bufferList.forEach(buffer => {\n this.viewer.add(buffer)\n })\n this.setVisibility(this.visible)\n\n callback()\n }\n\n create () {\n var dotData: SphereBufferData|{} = {}\n\n if (this.volume) {\n var volume = this.volume\n var thresholdMin, thresholdMax\n\n if (this.thresholdType === 'sigma') {\n thresholdMin = volume.getValueForSigma(this.thresholdMin)\n thresholdMax = volume.getValueForSigma(this.thresholdMax)\n } else {\n thresholdMin = this.thresholdMin\n thresholdMax = this.thresholdMax\n }\n volume.setFilter(thresholdMin, thresholdMax, this.thresholdOut)\n\n Object.assign(dotData, {\n position: volume.getDataPosition(),\n color: volume.getDataColor(this.getColorParams())\n })\n if (this.dotType === 'sphere') {\n Object.assign(dotData, {\n radius: volume.getDataSize(this.radius, this.scale),\n picking: volume.getDataPicking()\n })\n }\n } else {\n var surface = this.surface\n Object.assign(dotData, {\n position: (surface as Surface).getPosition(),\n color: (surface as Surface).getColor(this.getColorParams())\n })\n if (this.dotType === 'sphere') {\n Object.assign(dotData, {\n radius: (surface as Surface).getSize(this.radius, this.scale),\n picking: (surface as Surface).getPicking()\n })\n }\n }\n\n if (this.dotType === 'sphere') {\n this.dotBuffer = new SphereBuffer(\n dotData as SphereBufferData,\n this.getBufferParams({\n sphereDetail: this.sphereDetail,\n disableImpostor: this.disableImpostor,\n dullInterior: false\n }) as SphereBufferParameters\n ) as SphereGeometryBuffer\n } else {\n this.dotBuffer = new PointBuffer(\n dotData,\n this.getBufferParams({\n pointSize: this.pointSize,\n sizeAttenuation: this.sizeAttenuation,\n sortParticles: this.sortParticles,\n useTexture: this.useTexture,\n alphaTest: this.alphaTest,\n forceTransparent: this.forceTransparent,\n edgeBleach: this.edgeBleach\n })\n )\n }\n\n this.bufferList.push(this.dotBuffer as SphereGeometryBuffer)\n }\n\n update (what: DotDataFields = {}) {\n if (this.bufferList.length === 0) return\n\n const dotData: SphereBufferData|{} = {}\n\n if (what.color) {\n if (this.volume) {\n Object.assign(dotData, {\n color: this.volume.getDataColor(\n this.getColorParams()\n )\n })\n } else {\n Object.assign(dotData, {\n color: (this.surface as Surface).getColor(\n this.getColorParams()\n )\n })\n }\n }\n\n if (this.dotType === 'sphere' && (what.radius || what.scale)) {\n if (this.volume) {\n Object.assign(dotData, {\n radius: this.volume.getDataSize(\n this.radius, this.scale\n )\n })\n } else {\n Object.assign(dotData, {\n radius: (this.surface as Surface).getSize(\n this.radius, this.scale\n )\n })\n }\n }\n\n (this.dotBuffer as SphereGeometryBuffer).setAttributes(dotData)\n }\n\n setParameters (params: Partial, what: DotDataFields = {}, rebuild: boolean) {\n \n if (params && params.thresholdType !== undefined &&\n this.volume instanceof Volume\n ) {\n if (this.thresholdType === 'value' &&\n params.thresholdType === 'sigma'\n ) {\n this.thresholdMin = this.volume.getSigmaForValue(\n this.thresholdMin\n )\n this.thresholdMax = this.volume.getSigmaForValue(\n this.thresholdMax\n )\n } else if (this.thresholdType === 'sigma' &&\n params.thresholdType === 'value'\n ) {\n this.thresholdMin = this.volume.getValueForSigma(\n this.thresholdMin\n )\n this.thresholdMax = this.volume.getValueForSigma(\n this.thresholdMax\n )\n }\n\n this.thresholdType = params.thresholdType\n }\n\n if (params && params.radiusType !== undefined) {\n if (params.radiusType === 'radius') {\n this.radius = 0.1\n } else {\n this.radius = parseFloat(params.radiusType)\n }\n what.radius = true\n if (this.dotType === 'sphere' &&\n (!ExtensionFragDepth || this.disableImpostor)\n ) {\n rebuild = true\n }\n }\n\n if (params && params.radius !== undefined) {\n what.radius = true\n if (this.dotType === 'sphere' &&\n (!ExtensionFragDepth || this.disableImpostor)\n ) {\n rebuild = true\n }\n }\n\n if (params && params.scale !== undefined) {\n what.scale = true\n if (this.dotType === 'sphere' &&\n (!ExtensionFragDepth || this.disableImpostor)\n ) {\n rebuild = true\n }\n }\n\n super.setParameters(params, what, rebuild)\n\n return this\n }\n}\n\nexport default DotRepresentation\n","/**\n * @file Image Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport {\n // @ts-ignore: unused import Vector3, Matrix4 required for declaration only\n Vector2, Vector3, Matrix4, BufferAttribute, DataTexture,\n NormalBlending, NearestFilter, LinearFilter\n} from 'three'\n\nimport '../shader/Image.vert'\nimport '../shader/Image.frag'\n\nimport { Picker } from '../utils/picker'\nimport Buffer, { BufferDefaultParameters, BufferParameterTypes, BufferTypes } from './buffer'\n\n\nconst quadIndices = new Uint16Array([\n 0, 1, 2,\n 1, 3, 2\n])\n\nconst quadUvs = new Float32Array([\n 0, 1,\n 0, 0,\n 1, 1,\n 1, 0\n])\n\ntype ImageFilterTypes = 'nearest'|'linear'|'cubic-bspline'|'cubic-catmulrom'|'cubic-mitchell'\n\nexport interface ImageBufferData {\n position: Float32Array\n imageData: Uint8Array\n width: number\n height: number\n\n picking?: Picker\n}\n\nexport const ImageBufferDefaultParameters = Object.assign({\n filter: 'nearest' as ImageFilterTypes,\n forceTransparent: true\n}, BufferDefaultParameters)\nexport type ImageBufferParameters = typeof ImageBufferDefaultParameters\n\nexport const ImageBufferParameterTypes = Object.assign({\n filter: { updateShader: true, uniform: true }\n}, BufferParameterTypes)\n\n/**\n * Image buffer. Draw a single image. Optionally interpolate.\n */\nclass ImageBuffer extends Buffer {\n parameterTypes = ImageBufferParameterTypes\n get defaultParameters() { return ImageBufferDefaultParameters }\n parameters: ImageBufferParameters\n\n alwaysTransparent = true\n hasWireframe = false\n vertexShader = 'Image.vert'\n fragmentShader = 'Image.frag'\n\n tex: DataTexture\n pickingTex: DataTexture\n\n /**\n * @param {Object} data - buffer data\n * @param {Float32Array} data.position - image position\n * @param {Float32Array} data.imageData - image data, rgba channels\n * @param {Float32Array} data.width - image width\n * @param {Float32Array} data.height - image height\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} [params] - parameters object\n */\n constructor (data: ImageBufferData, params: ImageBufferParameters) {\n super({\n position: data.position,\n index: quadIndices,\n picking: data.picking\n }, params)\n\n const {imageData, width, height} = data\n\n const tex = new DataTexture(imageData, width, height)\n tex.flipY = true\n this.tex = tex\n\n const n = imageData.length\n const pickingData = new Uint8Array(n)\n for (let i = 0; i < n; i += 4) {\n const j = i / 4\n pickingData[ i ] = j >> 16 & 255\n pickingData[ i + 1 ] = j >> 8 & 255\n pickingData[ i + 2 ] = j & 255\n }\n\n const pickingTex = new DataTexture(pickingData, width, height)\n pickingTex.flipY = true\n pickingTex.minFilter = NearestFilter\n pickingTex.magFilter = NearestFilter\n this.pickingTex = pickingTex\n\n this.addUniforms({\n 'map': { value: tex },\n 'pickingMap': { value: pickingTex },\n 'mapSize': { value: new Vector2(width, height) }\n })\n\n this.geometry.setAttribute('uv', new BufferAttribute(quadUvs, 2))\n }\n\n getDefines (type: BufferTypes) {\n const defines = super.getDefines(type)\n const filter = this.parameters.filter\n\n if (filter.startsWith('cubic')) {\n defines.CUBIC_INTERPOLATION = 1\n if (filter.endsWith('bspline')) {\n defines.BSPLINE_FILTER = 1\n } else if (filter.endsWith('catmulrom')) {\n defines.CATMULROM_FILTER = 1\n } else if (filter.endsWith('mitchell')) {\n defines.MITCHELL_FILTER = 1\n }\n }\n\n return defines\n }\n\n updateTexture () {\n const tex = this.tex\n const filter = this.parameters.filter\n\n if (filter.startsWith('cubic')) {\n tex.minFilter = NearestFilter\n tex.magFilter = NearestFilter\n } else if (filter === 'linear') {\n tex.minFilter = LinearFilter\n tex.magFilter = LinearFilter\n } else { // filter === \"nearest\"\n tex.minFilter = NearestFilter\n tex.magFilter = NearestFilter\n }\n\n tex.needsUpdate = true\n this.pickingTex.needsUpdate = true\n }\n\n makeMaterial () {\n super.makeMaterial()\n this.updateTexture()\n\n const m = this.material\n m.uniforms.map.value = this.tex\n m.blending = NormalBlending\n m.needsUpdate = true\n\n const wm = this.wireframeMaterial\n wm.uniforms.map.value = this.tex\n wm.blending = NormalBlending\n wm.needsUpdate = true\n\n const pm = this.pickingMaterial\n pm.uniforms.map.value = this.tex\n pm.uniforms.pickingMap.value = this.pickingTex\n pm.blending = NormalBlending\n pm.needsUpdate = true\n }\n\n setUniforms (data: any) { // TODO\n if (data && data.filter !== undefined) {\n this.updateTexture()\n data.map = this.tex\n }\n\n super.setUniforms(data)\n }\n}\n\nexport default ImageBuffer\n","/**\n * @file Volume Slice\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { ColormakerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { SlicePicker } from '../utils/picker'\nimport { Volume } from '../ngl';\nimport { SliceRepresentationParameters } from '../representation/slice-representation';\n\nclass VolumeSlice {\n dimension: 'x'|'y'|'z'\n positionType: 'percent'|'coordinate'\n position: number\n thresholdType: 'sigma'|'value'\n thresholdMin: number\n thresholdMax: number\n normalize: boolean\n volume: Volume\n\n constructor (volume: Volume, params: Partial) {\n const p = params || {}\n\n this.dimension = defaults(p.dimension, 'x')\n this.positionType = defaults(p.positionType, 'percent')\n this.position = defaults(p.position, 30)\n this.thresholdType = defaults(p.thresholdType, 'sigma')\n this.thresholdMin = defaults(p.thresholdMin, -Infinity)\n this.thresholdMax = defaults(p.thresholdMax, Infinity)\n this.normalize = defaults(p.normalize, false)\n\n this.volume = volume\n }\n\n getPositionFromCoordinate (coord: number) {\n const dim = this.dimension\n const v = this.volume\n const m = v.matrix\n\n const mp = new Vector3().setFromMatrixPosition(m)[ dim ]\n const ms = new Vector3().setFromMatrixScale(m)[ dim ]\n\n let vn\n if (dim === 'x') {\n vn = v.nx\n } else if (dim === 'y') {\n vn = v.ny\n } else {\n vn = v.nz\n }\n\n return Math.round((((coord - mp) / (vn / 100)) + 1) / ms)\n }\n\n getData (params: any) {\n params = params || {}\n\n const v = this.volume\n const d = v.data\n const m = v.matrix\n\n let p: number\n if (this.positionType === 'coordinate') {\n p = this.getPositionFromCoordinate(this.position)\n } else {\n p = this.position\n }\n\n function pos (dimLen: number) {\n return Math.round((dimLen / 100) * (p - 1))\n }\n\n function index (x: number, y: number, z: number, i: number) {\n return (z * v.ny * v.nx + y * v.nx + x) * 3 + i\n }\n\n const position = new Float32Array(4 * 3)\n const vec = new Vector3()\n\n let width, height\n let x\n let y\n let z\n let x0 = 0\n let y0 = 0\n let z0 = 0\n let nx = v.nx\n let ny = v.ny\n let nz = v.nz\n\n function setVec (x: number, y: number, z: number, offset: number) {\n vec.set(x, y, z).applyMatrix4(m).toArray(position as any, offset)\n }\n\n if (this.dimension === 'x') {\n x = pos(v.nx)\n y = v.ny - 1\n z = v.nz - 1\n\n width = v.nz\n height = v.ny\n\n x0 = x\n nx = x0 + 1\n\n setVec(x, 0, 0, 0)\n setVec(x, y, 0, 3)\n setVec(x, 0, z, 6)\n setVec(x, y, z, 9)\n } else if (this.dimension === 'y') {\n x = v.nx - 1\n y = pos(v.ny)\n z = v.nz - 1\n\n width = v.nz\n height = v.nx\n\n y0 = y\n ny = y0 + 1\n\n setVec(0, y, 0, 0)\n setVec(x, y, 0, 3)\n setVec(0, y, z, 6)\n setVec(x, y, z, 9)\n } else if (this.dimension === 'z') {\n x = v.nx - 1\n y = v.ny - 1\n z = pos(v.nz)\n\n width = v.nx\n height = v.ny\n\n z0 = z\n nz = z0 + 1\n\n setVec(0, 0, z, 0)\n setVec(0, y, z, 3)\n setVec(x, 0, z, 6)\n setVec(x, y, z, 9)\n }\n\n let i = 0\n let j = 0\n const imageData = new Uint8Array(width * height * 4)\n const pickingArray = new Float32Array(width * height)\n\n let tMin, tMax\n if (this.thresholdType === 'sigma') {\n tMin = v.getValueForSigma(this.thresholdMin)\n tMax = v.getValueForSigma(this.thresholdMax)\n } else {\n tMin = this.thresholdMin\n tMax = this.thresholdMax\n }\n\n const cp = Object.assign({}, params.colorParams, { volume: v })\n if (this.normalize) {\n cp.domain = [ 0, 1 ]\n }\n const colormaker = ColormakerRegistry.getScheme(cp)\n const tmp = new Float32Array(3)\n const scale = colormaker.getScale()\n\n let min = 0, max, diff = 0\n if (this.normalize) {\n min = +Infinity\n max = -Infinity\n for (let iy = y0; iy < ny; ++iy) {\n for (let ix = x0; ix < nx; ++ix) {\n for (let iz = z0; iz < nz; ++iz) {\n const idx = index(ix, iy, iz, 0) / 3\n const val = d[ idx ]\n if (val < min) min = val\n if (val > max) max = val\n }\n }\n }\n diff = max - min\n }\n\n for (let iy = y0; iy < ny; ++iy) {\n for (let ix = x0; ix < nx; ++ix) {\n for (let iz = z0; iz < nz; ++iz) {\n const idx = index(ix, iy, iz, 0) / 3\n let val = d[ idx ]\n if (this.normalize) {\n val = (val - min) / diff\n }\n\n colormaker.colorToArray(scale(val), tmp)\n imageData[ i ] = Math.round(tmp[ 0 ] * 255)\n imageData[ i + 1 ] = Math.round(tmp[ 1 ] * 255)\n imageData[ i + 2 ] = Math.round(tmp[ 2 ] * 255)\n imageData[ i + 3 ] = (val > tMin && val < tMax) ? 255 : 0\n\n pickingArray[ j ] = idx\n\n ++j\n i += 4\n }\n }\n }\n\n const picking = new SlicePicker(pickingArray, v)\n\n return { position, imageData, width, height, picking }\n }\n}\n\nexport default VolumeSlice\n","/**\n * @file Slice Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport Representation, { RepresentationParameters } from './representation'\nimport ImageBuffer, { ImageBufferParameters, ImageBufferData } from '../buffer/image-buffer'\nimport VolumeSlice from '../surface/volume-slice'\nimport Viewer from '../viewer/viewer';\nimport { Volume } from '../ngl';\n\n/**\n * Slice representation parameter object. Extends {@link RepresentationParameters}\n *\n * @typedef {Object} SliceRepresentationParameters - slice representation parameters\n *\n * @property {String} filter - filter applied to map the volume data on the slice, one of \"nearest\", \"linear\", \"cubic-bspline\", \"cubic-catmulrom\", \"cubic-mitchell\".\n * @property {String} positionType - Meaning of the position value. Either \"percent\" od \"coordinate\".\n * @property {Number} position - position of the slice.\n * @property {String} dimension - one of \"x\", \"y\" or \"z\"\n * @property {String} thresholdType - Meaning of the threshold values. Either *value* for the literal value or *sigma* as a factor of the sigma of the data. For volume data only.\n * @property {Number} thresholdMin - Minimum value to be displayed. For volume data only.\n * @property {Number} thresholdMax - Maximum value to be displayed. For volume data only.\n * @property {Boolean} normalize - Flag indicating wheather to normalize the data in a slice when coloring.\n */\nexport interface SliceRepresentationParameters extends RepresentationParameters {\n filter: 'nearest'|'linear'|'cubic-bspline'|'cubic-catmulrom'|'cubic-mitchell'\n positionType: 'percent'|'coordinate'\n position: number\n dimension: 'x'|'y'|'z'\n thresholdType: 'value'|'sigma'\n thresholdMin: number\n thresholdMax: number\n normalize: boolean\n}\n/**\n * Slice representation\n */\nclass SliceRepresentation extends Representation {\n protected filter: 'nearest'|'linear'|'cubic-bspline'|'cubic-catmulrom'|'cubic-mitchell'\n protected positionType: 'percent'|'coordinate'\n protected position: number\n protected dimension: 'x'|'y'|'z'\n protected thresholdType: 'value'|'sigma'\n protected thresholdMin: number\n protected thresholdMax: number\n protected normalize: boolean\n protected volume: Volume\n /**\n * Create Slice representation object\n * @param {Volume} surface - the volume to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {SliceRepresentationParameters} params - slice representation parameters\n */\n constructor (volume: Volume, viewer: Viewer, params: Partial) {\n super(volume, viewer, params)\n\n this.type = 'slice'\n\n this.parameters = Object.assign({\n\n filter: {\n type: 'select',\n buffer: true,\n options: {\n 'nearest': 'nearest',\n 'linear': 'linear',\n 'cubic-bspline': 'cubic-bspline',\n 'cubic-catmulrom': 'cubic-catmulrom',\n 'cubic-mitchell': 'cubic-mitchell'\n }\n },\n positionType: {\n type: 'select',\n rebuild: true,\n options: {\n 'percent': 'percent', 'coordinate': 'coordinate'\n }\n },\n position: {\n type: 'range',\n step: 0.1,\n max: 100,\n min: 1,\n rebuild: true\n },\n dimension: {\n type: 'select',\n rebuild: true,\n options: {\n 'x': 'x', 'y': 'y', 'z': 'z'\n }\n },\n thresholdType: {\n type: 'select',\n rebuild: true,\n options: {\n 'value': 'value', 'sigma': 'sigma'\n }\n },\n thresholdMin: {\n type: 'number', precision: 3, max: Infinity, min: -Infinity, rebuild: true\n },\n thresholdMax: {\n type: 'number', precision: 3, max: Infinity, min: -Infinity, rebuild: true\n },\n normalize: {\n type: 'boolean', rebuild: true\n }\n\n }, this.parameters, {\n\n flatShaded: null,\n side: null,\n wireframe: null,\n linewidth: null,\n colorScheme: null,\n\n roughness: null,\n metalness: null,\n diffuse: null\n\n })\n\n this.volume = volume\n\n this.init(params)\n }\n\n init (params: Partial) {\n const v = this.volume\n const p = params || {}\n p.colorDomain = defaults(p.colorDomain, [ v.min, v.max ])\n p.colorScheme = defaults(p.colorScheme, 'value')\n p.colorScale = defaults(p.colorScale, 'Spectral')\n\n this.colorScheme = 'value'\n this.dimension = defaults(p.dimension, 'x')\n this.filter = defaults(p.filter, 'cubic-bspline')\n this.positionType = defaults(p.positionType, 'percent')\n this.position = defaults(p.position, 30)\n this.thresholdType = defaults(p.thresholdType, 'sigma')\n this.thresholdMin = defaults(p.thresholdMin, -Infinity)\n this.thresholdMax = defaults(p.thresholdMax, Infinity)\n this.normalize = defaults(p.normalize, false)\n\n super.init(p)\n\n this.build()\n }\n\n attach (callback: () => void) {\n this.bufferList.forEach(buffer => {\n this.viewer.add(buffer)\n })\n this.setVisibility(this.visible)\n\n callback()\n }\n\n create () {\n const volumeSlice = new VolumeSlice(this.volume, {\n positionType: this.positionType,\n position: this.position,\n dimension: this.dimension,\n thresholdType: this.thresholdType,\n thresholdMin: this.thresholdMin,\n thresholdMax: this.thresholdMax,\n normalize: this.normalize\n })\n\n const sliceBuffer = new ImageBuffer(\n volumeSlice.getData({ colorParams: this.getColorParams() }) as ImageBufferData,\n this.getBufferParams({\n filter: this.filter\n }) as ImageBufferParameters\n )\n\n this.bufferList.push(sliceBuffer)\n }\n}\n\nexport default SliceRepresentation\n","/**\n * @file Representation Utils\n * @author Alexander Rose \n * @private\n */\n\nimport { Debug, Log, RepresentationRegistry } from '../globals'\n\nimport Viewer from '../viewer/viewer'\nimport Structure from '../structure/structure'\nimport Surface from '../surface/surface'\nimport Volume from '../surface/volume'\nimport Shape from '../geometry/shape'\n\nimport BufferRepresentation from './buffer-representation'\nimport SurfaceRepresentation from './surface-representation'\nimport DotRepresentation from './dot-representation'\nimport SliceRepresentation from './slice-representation'\n\nfunction logReprUnknown (type: string) {\n Log.error(`makeRepresentation: representation type ${type} unknown`)\n}\n\nexport function makeRepresentation (type: string, object: any, viewer: Viewer, params: any) { // TODO\n if (Debug) Log.time('makeRepresentation ' + type)\n\n var ReprClass\n\n if (object instanceof Structure) {\n ReprClass = RepresentationRegistry.get(type)\n\n if (!ReprClass) {\n logReprUnknown(type)\n return\n }\n } else if (object instanceof Surface) {\n if (type === 'surface') {\n ReprClass = SurfaceRepresentation\n } else if (type === 'dot') {\n ReprClass = DotRepresentation\n } else {\n logReprUnknown(type)\n return\n }\n } else if (object instanceof Volume) {\n if (type === 'surface') {\n ReprClass = SurfaceRepresentation\n } else if (type === 'dot') {\n ReprClass = DotRepresentation\n } else if (type === 'slice') {\n ReprClass = SliceRepresentation\n } else {\n logReprUnknown(type)\n return\n }\n } else if (object instanceof Shape) {\n ReprClass = BufferRepresentation\n object = object.getBufferList()\n } else if (type === 'buffer') {\n ReprClass = BufferRepresentation\n } else {\n Log.error('makeRepresentation: object ' + object + ' unknown')\n return\n }\n\n const repr = new ReprClass(object, viewer, params)\n\n if (Debug) Log.timeEnd('makeRepresentation ' + type)\n\n return repr\n}\n","/**\n * @file Element\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\n\nimport { createParams } from '../utils'\nimport { generateUUID } from '../math/math-utils'\nimport Stage from '../stage/stage'\n\nexport const ElementDefaultParameters = {\n name: 'some element',\n status: ''\n}\nexport type ElementParameters = typeof ElementDefaultParameters\n\nexport interface ElementSignals {\n statusChanged: Signal // on status change\n nameChanged: Signal // on name change\n disposed: Signal // on dispose\n}\n\n/**\n * Element base class\n */\nabstract class Element {\n /**\n * Events emitted by the element\n */\n signals: ElementSignals = {\n statusChanged: new Signal(),\n nameChanged: new Signal(),\n disposed: new Signal()\n }\n readonly parameters: ElementParameters\n readonly uuid: string\n\n get defaultParameters() { return ElementDefaultParameters }\n\n /**\n * @param {Stage} stage - stage object the component belongs to\n * @param {ElementParameters} params - component parameters\n */\n constructor (readonly stage: Stage, params: Partial = {}) {\n this.parameters = createParams(params, this.defaultParameters)\n this.uuid = generateUUID()\n }\n\n abstract get type (): string\n\n get name () { return this.parameters.name }\n\n setStatus (value: string) {\n this.parameters.status = value\n this.signals.statusChanged.dispatch(value)\n\n return this\n }\n\n setName (value: string) {\n this.parameters.name = value\n this.signals.nameChanged.dispatch(value)\n\n return this\n }\n\n dispose () {\n this.signals.disposed.dispatch()\n }\n}\n\nexport default Element\n","/**\n * @file Representation Element\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\nimport { Color } from 'three'\n\nimport Stage from '../stage/stage'\nimport Representation, { RepresentationParameters } from '../representation/representation'\nimport Component from './component'\nimport Element, { ElementDefaultParameters, ElementSignals } from './element'\n\nexport const RepresentationElementDefaultParameters = Object.assign({\n visible: true\n}, ElementDefaultParameters)\nexport type RepresentationElementParameters = typeof RepresentationElementDefaultParameters\n\nexport interface RepresentationElementSignals extends ElementSignals {\n visibilityChanged: Signal // on visibility change\n parametersChanged: Signal // on parameters change\n}\n\n/**\n * Element wrapping a {@link Representation} object\n */\nclass RepresentationElement extends Element {\n signals: RepresentationElementSignals\n parameters: RepresentationElementParameters\n get defaultParameters() { return RepresentationElementDefaultParameters }\n\n repr: Representation\n\n /**\n * Create representation component\n * @param {Stage} stage - stage object the component belongs to\n * @param {Representation} repr - representation object to wrap\n * @param {RepresentationParameters} [params] - component parameters\n * @param {Component} [parent] - parent component\n */\n constructor (stage: Stage, repr: Representation, params: Partial = {}, readonly parent: Component) {\n super(stage, Object.assign({ name: repr.type }, params))\n\n this.signals = Object.assign({\n visibilityChanged: new Signal(),\n parametersChanged: new Signal()\n }, this.signals)\n\n this.setRepresentation(repr)\n }\n\n get visible () { return this.parameters.visible }\n\n /**\n * Component type\n * @type {String}\n */\n get type () { return 'representation' }\n\n getType () {\n return this.repr.type\n }\n\n setRepresentation (repr: Representation) {\n this._disposeRepresentation()\n this.repr = repr\n // this.name = repr.type;\n this.stage.tasks.listen(this.repr.tasks)\n this.updateVisibility()\n }\n\n _disposeRepresentation () {\n if (this.repr) {\n this.stage.tasks.unlisten(this.repr.tasks)\n this.repr.dispose()\n }\n }\n\n dispose () {\n if (this.parent && this.parent.hasRepresentation(this)) {\n this.parent.removeRepresentation(this)\n } else {\n this._disposeRepresentation()\n this.signals.disposed.dispatch()\n }\n }\n\n /**\n * Set the visibility of the component, takes parent visibility into account\n * @param {Boolean} value - visibility flag\n * @return {RepresentationElement} this object\n */\n setVisibility (value: boolean) {\n this.parameters.visible = value\n this.updateVisibility()\n this.signals.visibilityChanged.dispatch(this.parameters.visible)\n\n return this\n }\n\n getVisibility () {\n if (this.parent) {\n return this.parent.parameters.visible && this.parameters.visible\n } else {\n return this.parameters.visible\n }\n }\n\n /**\n * Toggle visibility of the component, takes parent visibility into account\n * @return {RepresentationElement} this object\n */\n toggleVisibility () {\n return this.setVisibility(!this.parameters.visible)\n }\n\n updateVisibility () {\n this.repr.setVisibility(this.getVisibility())\n }\n\n /**\n * Set selection\n * @param {Object} what - flags indicating what attributes to update\n * @param {Boolean} what.position - update position attribute\n * @param {Boolean} what.color - update color attribute\n * @param {Boolean} what.radius - update radius attribute\n * @return {RepresentationElement} this object\n */\n update (what: any) { // TODO\n (this.repr as any).update(what) // TODO\n\n return this\n }\n\n build (params?: any) { // TODO\n this.repr.build(params)\n\n return this\n }\n\n /**\n * Set selection\n * @param {String} string - selection string\n * @return {RepresentationElement} this object\n */\n setSelection (string: string) {\n const repr: any = this.repr // TODO\n\n if (repr.setSelection) {\n repr.setSelection(string)\n }\n\n return this\n }\n\n /**\n * Set representation parameters\n * @param {RepresentationParameters} params - parameter object\n * @return {RepresentationElement} this object\n */\n setParameters (params: any) { // TODO\n this.repr.setParameters(params)\n this.signals.parametersChanged.dispatch(\n this.repr.getParameters()\n )\n\n return this\n }\n\n /**\n * Get representation parameters\n * @return {RepresentationParameters} parameter object\n */\n getParameters (): Partial {\n return this.repr.getParameters()\n }\n\n /**\n * Set color\n * @param {String|Color|Hex} value - color value\n * @return {RepresentationElement} this object\n */\n setColor (value: string|number|Color) {\n this.repr.setColor(value)\n\n return this\n }\n}\n\nexport default RepresentationElement\n","\n/**\n * @file Component\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Quaternion, Matrix4, Euler, Box3 } from 'three'\nimport { Signal } from 'signals'\n\nimport { defaults, createParams } from '../utils'\nimport { generateUUID } from '../math/math-utils'\nimport Annotation, { AnnotationParams } from '../component/annotation'\nimport ComponentControls from '../controls/component-controls'\nimport { makeRepresentation } from '../representation/representation-utils'\nimport RepresentationElement from './representation-element'\nimport Stage from '../stage/stage'\nimport Viewer from '../viewer/viewer'\n\nconst _m = new Matrix4()\nconst _v = new Vector3()\n\nexport const ComponentDefaultParameters = {\n name: '',\n status: '',\n visible: true\n}\nexport type ComponentParameters = typeof ComponentDefaultParameters\n\n\nexport interface ComponentSignals {\n representationAdded: Signal // when a representation is added\n representationRemoved: Signal // when a representation is removed\n visibilityChanged: Signal // on visibility change\n matrixChanged: Signal // on matrix change\n statusChanged: Signal // on status change\n nameChanged: Signal // on name change\n disposed: Signal // on dispose\n}\n\n/**\n * Base class for components\n */\nabstract class Component {\n /**\n * Events emitted by the component\n */\n readonly signals: ComponentSignals = {\n representationAdded: new Signal(),\n representationRemoved: new Signal(),\n visibilityChanged: new Signal(),\n matrixChanged: new Signal(),\n statusChanged: new Signal(),\n nameChanged: new Signal(),\n disposed: new Signal()\n }\n\n readonly parameters: ComponentParameters\n get defaultParameters () { return ComponentDefaultParameters }\n\n readonly uuid: string\n readonly viewer: Viewer\n\n reprList: RepresentationElement[] = []\n annotationList: Annotation[] = []\n\n matrix = new Matrix4()\n position = new Vector3()\n quaternion = new Quaternion()\n scale = new Vector3(1, 1, 1)\n transform = new Matrix4()\n\n controls: ComponentControls\n\n /**\n * @param {Stage} stage - stage object the component belongs to\n * @param {ComponentParameters} params - parameter object\n */\n constructor (readonly stage: Stage, readonly object: any, params: Partial = {}) {\n this.parameters = createParams(params, this.defaultParameters)\n this.uuid = generateUUID()\n this.viewer = stage.viewer\n\n this.controls = new ComponentControls(this)\n }\n\n abstract get type (): string\n\n get name () { return this.parameters.name }\n get status () { return this.parameters.status }\n get visible () { return this.parameters.visible }\n\n /**\n * Set position transform\n *\n * @example\n * // translate by 25 angstrom along x axis\n * component.setPosition([ 25, 0, 0 ]);\n *\n * @param {Vector3|Array} p - the coordinates\n * @return {Component} this object\n */\n setPosition (p: [number, number, number]|Vector3) {\n if (Array.isArray(p)) {\n this.position.fromArray(p)\n } else {\n this.position.copy(p)\n }\n this.updateMatrix()\n\n return this\n }\n\n /**\n * Set local rotation transform\n * (for global rotation use setTransform)\n *\n * @example\n * // rotate by 2 degree radians on x axis\n * component.setRotation( [ 2, 0, 0 ] );\n *\n * @param {Quaternion|Euler|Array} r - the rotation\n * @return {Component} this object\n */\n setRotation (r: [number, number, number]|Euler|Quaternion) {\n if (Array.isArray(r)) {\n if (r.length === 3) {\n const e = new Euler().fromArray(r)\n this.quaternion.setFromEuler(e)\n } else {\n this.quaternion.fromArray(r)\n }\n } else if (r instanceof Euler) {\n this.quaternion.setFromEuler(r)\n } else {\n this.quaternion.copy(r)\n }\n this.updateMatrix()\n\n return this\n }\n\n /**\n * Set scale transform\n *\n * @example\n * // scale by factor of two\n * component.setScale( 2 );\n *\n * @param {Number} s - the scale\n * @return {Component} this object\n */\n setScale (s: number) {\n this.scale.set(s, s, s)\n this.updateMatrix()\n\n return this\n }\n\n /**\n * Set general transform. Is applied before and in addition\n * to the position, rotation and scale transformations\n *\n * @example\n * component.setTransform( matrix );\n *\n * @param {Matrix4} m - the matrix\n * @return {Component} this object\n */\n setTransform (m: Matrix4) {\n this.transform.copy(m)\n this.updateMatrix()\n\n return this\n }\n\n updateMatrix () {\n const c = this.getCenterUntransformed(_v)\n this.matrix.makeTranslation(-c.x, -c.y, -c.z)\n\n _m.makeRotationFromQuaternion(this.quaternion)\n this.matrix.premultiply(_m)\n\n _m.makeScale(this.scale.x, this.scale.y, this.scale.z)\n this.matrix.premultiply(_m)\n\n const p = this.position\n _m.makeTranslation(p.x + c.x, p.y + c.y, p.z + c.z)\n this.matrix.premultiply(_m)\n\n this.matrix.premultiply(this.transform)\n\n this.updateRepresentationMatrices()\n\n this.stage.viewer.updateBoundingBox()\n\n this.signals.matrixChanged.dispatch(this.matrix)\n }\n\n /**\n * Propogates our matrix to each representation\n */\n updateRepresentationMatrices () {\n this.reprList.forEach(repr => {\n repr.setParameters({ matrix: this.matrix })\n })\n }\n\n /**\n * Add an anotation object\n * @param {Vector3} position - the 3d position\n * @param {String|Element} content - the HTML content\n * @param {Object} [params] - parameters\n * @param {Integer} params.offsetX - 2d offset in x direction\n * @param {Integer} params.offsetY - 2d offset in y direction\n * @return {Annotation} the added annotation object\n */\n addAnnotation (position: Vector3, content: string|HTMLElement, params: AnnotationParams) {\n const annotation = new Annotation(this, position, content, params)\n this.annotationList.push(annotation)\n\n return annotation\n }\n\n /**\n * Iterator over each annotation and executing the callback\n * @param {Function} callback - function to execute\n * @return {undefined}\n */\n eachAnnotation (callback: (a: Annotation) => void) {\n this.annotationList.slice().forEach(callback)\n }\n\n /**\n * Remove the give annotation from the component\n * @param {Annotation} annotation - the annotation to remove\n * @return {undefined}\n */\n removeAnnotation (annotation: Annotation) {\n const idx = this.annotationList.indexOf(annotation)\n if (idx !== -1) {\n this.annotationList.splice(idx, 1)\n annotation.dispose()\n }\n }\n\n /**\n * Remove all annotations from the component\n * @return {undefined}\n */\n removeAllAnnotations () {\n this.eachAnnotation(annotation => annotation.dispose())\n this.annotationList.length = 0\n }\n\n /**\n * Add a new representation to the component\n * @param {String} type - the name of the representation\n * @param {Object} object - the object on which the representation should be based\n * @param {RepresentationParameters} [params] - representation parameters\n * @return {RepresentationElement} the created representation wrapped into\n * a representation element object\n */\n protected _addRepresentation (type: string, object: any, params: any, hidden = false) { // TODO\n const p = params || {}\n const sp = this.stage.getParameters() as any // TODO\n p.matrix = this.matrix.clone()\n p.quality = p.quality || sp.quality\n p.disableImpostor = defaults(p.disableImpostor, !sp.impostor)\n p.useWorker = defaults(p.useWorker, sp.workerDefault)\n p.visible = defaults(p.visible, true)\n\n const p2 = Object.assign({}, p, { visible: this.parameters.visible && p.visible })\n const repr = makeRepresentation(type, object, this.viewer, p2)\n const reprElem = new RepresentationElement(this.stage, repr, p, this)\n\n if (!hidden) {\n this.reprList.push(reprElem)\n this.signals.representationAdded.dispatch(reprElem)\n }\n return reprElem\n }\n\n abstract addRepresentation (type: any, params: any): any\n\n addBufferRepresentation (buffer: any, params: any) { // TODO\n return this._addRepresentation.call(this, 'buffer', buffer, params)\n }\n\n hasRepresentation (repr: RepresentationElement) {\n return this.reprList.indexOf(repr) !== -1\n }\n\n /**\n * Iterator over each representation and executing the callback\n * @param {Function} callback - function to execute\n * @return {undefined}\n */\n eachRepresentation (callback: (repr: RepresentationElement) => void) {\n this.reprList.slice().forEach(callback)\n }\n\n /**\n * Removes a representation component\n * @param {RepresentationElement} repr - the representation element\n * @return {undefined}\n */\n removeRepresentation (repr: RepresentationElement) {\n const idx = this.reprList.indexOf(repr)\n if (idx !== -1) {\n this.reprList.splice(idx, 1)\n repr.dispose()\n this.signals.representationRemoved.dispatch(repr)\n }\n }\n\n updateRepresentations (what: any) { // TODO\n this.reprList.forEach(repr => repr.update(what))\n this.stage.viewer.requestRender()\n }\n\n /**\n * Removes all representation components\n * @return {undefined}\n */\n removeAllRepresentations () {\n this.eachRepresentation(repr => repr.dispose())\n }\n\n dispose () {\n this.removeAllAnnotations()\n this.removeAllRepresentations()\n\n this.reprList.length = 0\n\n this.signals.disposed.dispatch()\n }\n\n /**\n * Set the visibility of the component, including added representations\n * @param {Boolean} value - visibility flag\n * @return {Component} this object\n */\n setVisibility (value: boolean) {\n this.parameters.visible = value\n\n this.eachRepresentation((repr: RepresentationElement) => repr.updateVisibility())\n this.eachAnnotation((annotation: Annotation) => annotation.updateVisibility())\n\n this.signals.visibilityChanged.dispatch(value)\n\n return this\n }\n\n setStatus (value: string) {\n this.parameters.status = value\n this.signals.statusChanged.dispatch(value)\n\n return this\n }\n\n setName (value: string) {\n this.parameters.name = value\n this.signals.nameChanged.dispatch(value)\n\n return this\n }\n\n /**\n * @return {Box3} the component's bounding box\n */\n getBox (...args: any[]) {\n return this.getBoxUntransformed(...args)\n .clone().applyMatrix4(this.matrix)\n }\n\n /**\n * @return {Vector3} the component's center position\n */\n getCenter (...args: any[]) {\n return this.getCenterUntransformed(...args)\n .clone().applyMatrix4(this.matrix)\n }\n\n getZoom (...args: any[]) {\n return this.stage.getZoomForBox(this.getBox(...args))\n }\n\n /**\n * @abstract\n * @return {Box3} the untransformed component's bounding box\n */\n getBoxUntransformed (...args: any[]): Box3 {\n return new Box3()\n }\n\n getCenterUntransformed (...args: any[]) {\n return this.getBoxUntransformed().getCenter(new Vector3())\n }\n\n /**\n * Automatically center and zoom the component\n * @param {Integer} [duration] - duration of the animation, defaults to 0\n * @return {undefined}\n */\n autoView (duration?: number) {\n this.stage.animationControls.zoomMove(\n this.getCenter(),\n this.getZoom(),\n defaults(duration, 0)\n )\n }\n}\n\nexport default Component\n","/**\n * @file Collection\n * @author Alexander Rose \n * @private\n */\n\nimport Component from './component'\nimport Element from './element'\n\nclass Collection {\n constructor (readonly list: T[] = []) {\n // remove elements from list when they get disposed\n const n = list.length\n\n for (let i = 0; i < n; ++i) {\n const elm = list[ i ]\n elm.signals.disposed.add(this._remove, this)\n }\n }\n\n _remove (elm: T) {\n const idx = this.list.indexOf(elm)\n\n if (idx !== -1) {\n this.list.splice(idx, 1)\n }\n }\n\n get first () {\n return this.list.length > 0 ? this.list[0] : undefined\n }\n\n forEach (fn: (x: T) => any) {\n this.list.forEach(fn)\n\n return this\n }\n\n dispose () {\n return this.forEach((elm) => elm.dispose())\n }\n}\n\nexport default Collection\n","/**\n * @file Component Collection\n * @author Alexander Rose \n * @private\n */\n\nimport RepresentationElement from './representation-element'\nimport Collection from './collection'\nimport { GenericColor } from '../types'\n\nclass RepresentationCollection extends Collection {\n setParameters (params: any) {\n return this.forEach((repr) => repr.setParameters(params))\n }\n\n setVisibility (value: boolean) {\n return this.forEach((repr) => repr.setVisibility(value))\n }\n\n setSelection (string: string) {\n return this.forEach((repr) => repr.setSelection(string))\n }\n\n setColor (color: GenericColor) {\n return this.forEach((repr) => repr.setColor(color))\n }\n\n update (what: any) {\n return this.forEach((repr) => repr.update(what))\n }\n\n build (params?: any) {\n return this.forEach((repr) => repr.build(params))\n }\n\n dispose (params?: any) {\n return this.forEach((repr) => repr.dispose())\n }\n}\n\nexport default RepresentationCollection\n","/**\n * @file Trajectory Component\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\n\nimport Element, { ElementSignals, ElementDefaultParameters } from './element'\nimport Stage from '../stage/stage'\nimport Trajectory, { TrajectoryParameters } from '../trajectory/trajectory'\nimport TrajectoryPlayer, {\n TrajectoryPlayerDirection, TrajectoryPlayerMode, TrajectoryPlayerInterpolateType\n} from '../trajectory/trajectory-player'\n\n/**\n * Trajectory component parameter object.\n * @typedef {Object} TrajectoryComponentParameters - component parameters\n *\n * @property {String} name - component name\n * @property {Integer} initialFrame - initial frame the trajectory is set to\n * @property {Integer} defaultStep - default step size to be used by trajectory players\n * @property {Integer} defaultTimeout - default timeout to be used by trajectory players\n * @property {String} defaultInterpolateType - one of \"\" (empty string), \"linear\" or \"spline\"\n * @property {Integer} defaultInterpolateStep - window size used for interpolation\n * @property {String} defaultMode - either \"loop\" or \"once\"\n * @property {String} defaultDirection - either \"forward\" or \"backward\"\n */\n\nexport const TrajectoryElementDefaultParameters = Object.assign({\n defaultStep: 1,\n defaultTimeout: 50,\n defaultInterpolateType: '' as TrajectoryPlayerInterpolateType,\n defaultInterpolateStep: 5,\n defaultMode: 'loop' as TrajectoryPlayerMode,\n defaultDirection: 'forward' as TrajectoryPlayerDirection,\n initialFrame: 0\n}, ElementDefaultParameters)\nexport type TrajectoryElementParameters = typeof TrajectoryElementDefaultParameters\n\nexport interface TrajectoryElementSignals extends ElementSignals {\n frameChanged: Signal // on frame change\n playerChanged: Signal // on player change\n countChanged: Signal // when frame count is available\n parametersChanged: Signal // on parameters change\n}\n\n/**\n * Component wrapping a {@link Trajectory} object\n */\nclass TrajectoryElement extends Element {\n signals: TrajectoryElementSignals\n parameters: TrajectoryElementParameters\n get defaultParameters () { return TrajectoryElementDefaultParameters }\n\n /**\n * @param {Stage} stage - stage object the component belongs to\n * @param {Trajectory} trajectory - the trajectory object\n * @param {TrajectoryComponentParameters} params - component parameters\n * @param {StructureComponent} parent - the parent structure\n */\n constructor (stage: Stage, readonly trajectory: Trajectory, params: Partial = {}) {\n super(stage, Object.assign({ name: trajectory.name }, params))\n\n this.signals = Object.assign(this.signals, {\n frameChanged: new Signal(),\n playerChanged: new Signal(),\n countChanged: new Signal(),\n parametersChanged: new Signal()\n })\n\n // signals\n\n trajectory.signals.frameChanged.add((i: number) => {\n this.signals.frameChanged.dispatch(i)\n })\n\n trajectory.signals.playerChanged.add((player: TrajectoryPlayer) => {\n this.signals.playerChanged.dispatch(player)\n })\n\n trajectory.signals.countChanged.add((n: number) => {\n this.signals.countChanged.dispatch(n)\n })\n\n //\n\n if (params.initialFrame !== undefined) {\n this.setFrame(params.initialFrame)\n }\n }\n\n /**\n * Component type\n * @type {String}\n */\n get type () { return 'trajectory' }\n\n /**\n * Set the frame of the trajectory\n * @param {Integer} i - frame number\n * @return {undefined}\n */\n setFrame (i: number) {\n this.trajectory.setFrame(i)\n }\n\n /**\n * Set trajectory parameters\n * @param {TrajectoryParameters} params - trajectory parameters\n * @return {undefined}\n */\n setParameters (params: Partial = {}) {\n this.trajectory.setParameters(params)\n this.signals.parametersChanged.dispatch(params)\n }\n\n dispose () {\n this.trajectory.dispose()\n super.dispose()\n }\n}\n\nexport default TrajectoryElement\n","/**\n * @file Frames\n * @author Alexander Rose \n * @private\n */\n\nexport default class Frames {\n coordinates = []\n boxes = []\n times = []\n\n timeOffset = 0\n deltaTime = 1\n\n constructor (readonly name: string, readonly path: string) {}\n\n get type () { return 'Frames' }\n}\n","/**\n * @file Superposition\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4 } from 'three'\nimport { Debug, Log } from '../globals'\nimport {\n Matrix, svd, meanRows, subRows, transpose,\n multiplyABt, invert3x3, multiply3x3, mat3x3determinant, multiply\n} from '../math/matrix-utils'\nimport Structure from '../structure/structure'\n\nclass Superposition {\n coords1t: Matrix\n coords2t: Matrix\n\n transformationMatrix: Matrix4\n\n mean1: number[]\n mean2: number[]\n\n A = new Matrix(3, 3)\n W = new Matrix(1, 3)\n U = new Matrix(3, 3)\n V = new Matrix(3, 3)\n VH = new Matrix(3, 3)\n R = new Matrix(3, 3)\n\n private tmp = new Matrix(3, 3)\n private c = new Matrix(3, 3)\n\n constructor (atoms1: Structure|Float32Array, atoms2: Structure|Float32Array) {\n // allocate & init data structures\n\n let n1\n if (atoms1 instanceof Structure) {\n n1 = atoms1.atomCount\n } else if (atoms1 instanceof Float32Array) {\n n1 = atoms1.length / 3\n } else {\n return\n }\n\n let n2\n if (atoms2 instanceof Structure) {\n n2 = atoms2.atomCount\n } else if (atoms2 instanceof Float32Array) {\n n2 = atoms2.length / 3\n } else {\n return\n }\n\n const n = Math.min(n1, n2)\n\n const coords1 = new Matrix(3, n)\n const coords2 = new Matrix(3, n)\n\n this.coords1t = new Matrix(n, 3)\n this.coords2t = new Matrix(n, 3)\n\n this.transformationMatrix = new Matrix4()\n\n this.c.data.set([ 1, 0, 0, 0, 1, 0, 0, 0, -1 ])\n\n // prep coords\n\n this.prepCoords(atoms1, coords1, n, false)\n this.prepCoords(atoms2, coords2, n, false)\n\n // superpose\n\n this._superpose(coords1, coords2)\n }\n\n _superpose (coords1: Matrix, coords2: Matrix) {\n this.mean1 = meanRows(coords1)\n this.mean2 = meanRows(coords2)\n\n subRows(coords1, this.mean1)\n subRows(coords2, this.mean2)\n\n transpose(this.coords1t, coords1)\n transpose(this.coords2t, coords2)\n\n multiplyABt(this.A, this.coords2t, this.coords1t)\n\n svd(this.A, this.W, this.U, this.V)\n\n invert3x3(this.V, this.VH)\n multiply3x3(this.R, this.U, this.VH)\n\n if (mat3x3determinant(this.R) < 0.0) {\n if (Debug) Log.log('R not a right handed system')\n\n multiply3x3(this.tmp, this.c, this.VH)\n multiply3x3(this.R, this.U, this.tmp)\n }\n\n //get the transformation matrix\n\n const transformMat_ = new Matrix(4,4)\n const tmp_1 = new Matrix(4,4)\n const tmp_2 = new Matrix(4,4)\n\n const sub = new Matrix(4,4)\n const mult = new Matrix(4,4)\n const add = new Matrix(4,4)\n\n const R = this.R.data\n const M1 = this.mean1\n const M2 = this.mean2\n\n sub.data.set([ 1, 0, 0, -M1[0],\n 0, 1, 0, -M1[1],\n 0, 0, 1, -M1[2],\n 0, 0, 0, 1 ])\n\n mult.data.set([ R[0], R[1], R[2], 0,\n R[3], R[4], R[5], 0,\n R[6], R[7], R[8], 0,\n 0, 0, 0, 1 ])\n\n add.data.set([ 1, 0, 0, M2[0],\n 0, 1, 0, M2[1],\n 0, 0, 1, M2[2],\n 0, 0, 0, 1 ])\n\n transpose(tmp_1,sub)\n multiplyABt(transformMat_,mult,tmp_1)\n transpose(tmp_2,transformMat_)\n multiplyABt(tmp_1,add,tmp_2)\n\n transpose(transformMat_,tmp_1)\n this.transformationMatrix.elements = transformMat_.data as unknown as number[]\n\n }\n\n prepCoords (atoms: Structure|Float32Array, coords: Matrix, n: number, is4X4: boolean) {\n let i = 0\n const cd = coords.data\n\n let c = 3\n let d = n * 3\n\n if (is4X4) {\n d = n * 4\n c = 4\n }\n if (atoms instanceof Structure) {\n atoms.eachAtom(function (a) {\n if (i < d) {\n cd[ i + 0 ] = a.x\n cd[ i + 1 ] = a.y\n cd[ i + 2 ] = a.z\n if (is4X4) cd[ i + 3 ] = 1\n\n i += c\n }\n })\n } else if (atoms instanceof Float32Array) {\n for (; i < d; i += c){\n if (i < d) {\n cd[ i ] = atoms[ i ]\n cd[ i + 1 ] = atoms[ i + 1 ]\n cd[ i + 2 ] = atoms[ i + 2 ]\n if (is4X4) cd[ i + 3 ] = 1\n }\n }\n } else {\n Log.warn('prepCoords: input type unknown')\n }\n }\n\n transform (atoms: Structure|Float32Array) {\n // allocate data structures\n\n let n\n if (atoms instanceof Structure) {\n n = atoms.atomCount\n } else if (atoms instanceof Float32Array) {\n n = atoms.length / 3\n } else {\n return\n }\n\n const coords = new Matrix(4, n)\n const tCoords = new Matrix(n,4)\n\n // prep coords\n\n this.prepCoords(atoms, coords, n, true)\n\n // check for transformation matrix correctness\n\n const transform = this.transformationMatrix\n const det = transform.determinant()\n if (!det){\n return det\n }\n\n // do transform\n\n const mult = new Matrix(4,4)\n mult.data = transform.elements as unknown as Float32Array\n multiply(tCoords,coords,mult)\n\n let i = 0\n const cd = tCoords.data\n if (atoms instanceof Structure) {\n atoms.eachAtom(function (a) {\n a.x = cd[ i ]\n a.y = cd[ i + 1 ]\n a.z = cd[ i + 2 ]\n i += 4\n })\n\n //update transformation matrices for each assembly\n\n const invertTrasform = new Matrix4()\n invertTrasform.copy(transform).invert()\n\n const biomolDict = atoms.biomolDict\n\n for (let key in biomolDict) {\n\n if (biomolDict.hasOwnProperty(key)) {\n let assembly = biomolDict[key]\n\n assembly.partList.forEach(function(part){\n\n part.matrixList.forEach(function(mat){\n\n mat.premultiply(transform)\n mat.multiply(invertTrasform)\n\n })\n })\n }\n }\n } else if (atoms instanceof Float32Array) {\n\n const n4 = n * 4\n for (; i < n4; i += 4){\n\n atoms[ i ] = cd[ i ]\n atoms[ i + 1 ] = cd[ i + 1 ]\n atoms[ i + 2 ] = cd[ i + 2 ]\n\n }\n } else {\n Log.warn('transform: input type unknown')\n }\n\n return this.transformationMatrix\n }\n}\nexport default Superposition\n","/**\n * @file Trajectory Player\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\n\nimport { defaults, createParams, updateParams } from '../utils'\nimport Trajectory from './trajectory'\n\nexport type TrajectoryPlayerInterpolateType = ''|'linear'|'spline'\nexport type TrajectoryPlayerMode = 'loop'|'once'\nexport type TrajectoryPlayerDirection = 'forward'|'backward'|'bounce'\n\nexport const TrajectoryPlayerDefaultParameters = {\n step: 1, // how many frames to advance when playing\n timeout: 50, // how many milliseconds to wait between playing frames\n start: 0, // first frame to play\n end: 0, // last frame to play\n interpolateType: '' as TrajectoryPlayerInterpolateType,\n interpolateStep: 5, // window size used for interpolation\n mode: 'loop' as TrajectoryPlayerMode,\n direction: 'forward' as TrajectoryPlayerDirection\n}\nexport type TrajectoryPlayerParameters = typeof TrajectoryPlayerDefaultParameters\n\nexport interface TrajectoryPlayerSignals {\n startedRunning: Signal\n haltedRunning: Signal\n}\n\n/**\n * Trajectory player for animating coordinate frames\n * @example\n * var player = new TrajectoryPlayer(trajectory, {step: 1, timeout: 50});\n * player.play();\n */\nclass TrajectoryPlayer {\n signals: TrajectoryPlayerSignals = {\n startedRunning: new Signal(),\n haltedRunning: new Signal()\n }\n\n parameters: TrajectoryPlayerParameters\n traj: Trajectory\n\n private _run = false\n private _previousTime = 0\n private _currentTime = 0\n private _currentStep = 1\n private _currentFrame: number|[number, number, number, number]\n private _direction: TrajectoryPlayerDirection\n\n /**\n * make trajectory player\n * @param {Trajectory} traj - the trajectory\n * @param {TrajectoryPlayerParameters} [params] - parameter object\n */\n constructor (traj: Trajectory, params: Partial = {}) {\n traj.signals.playerChanged.add((player: TrajectoryPlayer) => {\n if (player !== this) {\n this.pause()\n }\n }, this)\n\n const n = defaults(traj.frameCount, 1)\n\n this.traj = traj\n this.parameters = createParams(params, TrajectoryPlayerDefaultParameters)\n this.parameters.end = Math.min(defaults(params.end, n - 1), n - 1)\n this.parameters.step = defaults(params.step, Math.ceil((n + 1) / 100))\n\n this._currentFrame = this.parameters.start\n this._direction = this.parameters.direction === 'bounce' ? 'forward' : this.parameters.direction\n\n traj.signals.countChanged.add((n: number) => {\n this.parameters.end = Math.min(defaults(this.parameters.end, n - 1), n - 1)\n }, this)\n\n this._animate = this._animate.bind(this)\n }\n\n get isRunning () { return this._run }\n\n /**\n * set player parameters\n * @param {TrajectoryPlayerParameters} [params] - parameter object\n */\n setParameters (params: Partial = {}) {\n updateParams(this.parameters, params)\n\n if (params.direction !== undefined && this.parameters.direction !== 'bounce') {\n this._direction = this.parameters.direction\n }\n }\n\n _animate () {\n if (!this._run) return\n\n this._currentTime = window.performance.now()\n const dt = this._currentTime - this._previousTime\n const step = this.parameters.interpolateType ? this.parameters.interpolateStep : 1\n const timeout = this.parameters.timeout / step\n const traj = this.traj\n\n if (traj && traj.frameCount && !traj.inProgress && dt >= timeout) {\n if (this.parameters.interpolateType) {\n if (this._currentStep > this.parameters.interpolateStep) {\n this._currentStep = 1\n }\n if (this._currentStep === 1) {\n this._currentFrame = this._nextInterpolated()\n }\n if (traj.hasFrame(this._currentFrame)) {\n this._currentStep += 1\n const t = this._currentStep / (this.parameters.interpolateStep + 1)\n const [i, ip, ipp, ippp] = this._currentFrame as [number, number, number, number]\n traj.setFrameInterpolated(\n i, ip, ipp, ippp, t, this.parameters.interpolateType\n )\n this._previousTime = this._currentTime\n } else {\n traj.loadFrame(this._currentFrame)\n }\n } else {\n const i = this._next()\n if (traj.hasFrame(i)) {\n traj.setFrame(i)\n this._previousTime = this._currentTime\n } else {\n traj.loadFrame(i)\n }\n }\n }\n\n window.requestAnimationFrame(this._animate)\n }\n\n _next () {\n const p = this.parameters\n let i\n\n if (this._direction === 'forward') {\n i = this.traj.currentFrame + p.step\n } else {\n i = this.traj.currentFrame - p.step\n }\n\n if (i > p.end || i < p.start) {\n if (p.direction === 'bounce') {\n if (this._direction === 'forward') {\n this._direction = 'backward'\n } else {\n this._direction = 'forward'\n }\n }\n\n if (p.mode === 'once') {\n this.pause()\n\n if (p.direction === 'forward') {\n i = p.end\n } else if (p.direction === 'backward') {\n i = p.start\n } else {\n if (this._direction === 'forward') {\n i = p.start\n } else {\n i = p.end\n }\n }\n } else {\n if (this._direction === 'forward') {\n i = p.start\n if (p.interpolateType) {\n i = Math.min(p.end, i + p.step)\n }\n } else {\n i = p.end\n if (p.interpolateType) {\n i = Math.max(p.start, i - p.step)\n }\n }\n }\n }\n\n return i\n }\n\n _nextInterpolated () {\n const p = this.parameters\n const i = this._next()\n let ip, ipp, ippp\n\n if (this._direction === 'forward') {\n ip = Math.max(p.start, i - p.step)\n ipp = Math.max(p.start, i - 2 * p.step)\n ippp = Math.max(p.start, i - 3 * p.step)\n } else {\n ip = Math.min(p.end, i + p.step)\n ipp = Math.min(p.end, i + 2 * p.step)\n ippp = Math.min(p.end, i + 3 * p.step)\n }\n\n return [i, ip, ipp, ippp] as [number, number, number, number]\n }\n\n /**\n * toggle between playing and pausing the animation\n * @return {undefined}\n */\n toggle () {\n if (this._run) {\n this.pause()\n } else {\n this.play()\n }\n }\n\n /**\n * start the animation\n * @return {undefined}\n */\n play () {\n if (!this._run) {\n if (this.traj.player !== this) {\n this.traj.setPlayer(this)\n }\n this._currentStep = 1\n\n const p = this.parameters\n const frame = this.traj.currentFrame\n\n // snap to the grid implied by this.step division and multiplication\n // thus minimizing cache misses\n let i = Math.ceil(frame / p.step) * p.step\n // wrap when restarting from the limit (i.e. end or start)\n if (p.direction === 'forward' && frame >= p.end) {\n i = p.start\n } else if (p.direction === 'backward' && frame <= p.start) {\n i = p.end\n }\n\n this.traj.setFrame(i)\n\n this._run = true\n this._animate()\n this.signals.startedRunning.dispatch()\n }\n }\n\n /**\n * pause the animation\n * @return {undefined}\n */\n pause () {\n this._run = false\n this.signals.haltedRunning.dispatch()\n }\n\n /**\n * stop the animation (pause and go to start-frame)\n * @return {undefined}\n */\n stop () {\n this.pause()\n this.traj.setFrame(this.parameters.start)\n }\n}\n\nexport default TrajectoryPlayer\n","/**\n * @file Trajectory\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\n\nimport { Log } from '../globals'\nimport { defaults } from '../utils'\nimport { NumberArray } from '../types'\nimport { circularMean, arrayMean } from '../math/array-utils'\nimport { lerp, spline } from '../math/math-utils'\nimport Selection from '../selection/selection'\nimport Superposition from '../align/superposition'\nimport Structure from '../structure/structure'\nimport AtomProxy from '../proxy/atom-proxy'\nimport TrajectoryPlayer, { TrajectoryPlayerInterpolateType } from './trajectory-player'\n\n\nfunction centerPbc (coords: NumberArray, mean: number[], box: ArrayLike) {\n if (box[ 0 ] === 0 || box[ 8 ] === 0 || box[ 4 ] === 0) {\n return\n }\n\n const n = coords.length\n\n const bx = box[ 0 ]\n const by = box[ 1 ]\n const bz = box[ 2 ]\n const mx = mean[ 0 ]\n const my = mean[ 1 ]\n const mz = mean[ 2 ]\n\n const fx = -mx + bx + bx / 2\n const fy = -my + by + by / 2\n const fz = -mz + bz + bz / 2\n\n for (let i = 0; i < n; i += 3) {\n coords[ i + 0 ] = (coords[ i + 0 ] + fx) % bx\n coords[ i + 1 ] = (coords[ i + 1 ] + fy) % by\n coords[ i + 2 ] = (coords[ i + 2 ] + fz) % bz\n }\n}\n\nfunction removePbc (x: NumberArray, box: ArrayLike) {\n if (box[ 0 ] === 0 || box[ 8 ] === 0 || box[ 4 ] === 0) {\n return\n }\n\n // ported from GROMACS src/gmxlib/rmpbc.c:rm_gropbc()\n // in-place\n\n const n = x.length\n\n for (let i = 3; i < n; i += 3) {\n for (let j = 0; j < 3; ++j) {\n const dist = x[ i + j ] - x[ i - 3 + j ]\n\n if (Math.abs(dist) > 0.9 * box[ j * 3 + j ]) {\n if (dist > 0) {\n for (let d = 0; d < 3; ++d) {\n x[ i + d ] -= box[ j * 3 + d ]\n }\n } else {\n for (let d = 0; d < 3; ++d) {\n x[ i + d ] += box[ j * 3 + d ]\n }\n }\n }\n }\n }\n\n return x\n}\n\nfunction removePeriodicity (x: NumberArray, box: ArrayLike, mean: number[]) {\n if (box[ 0 ] === 0 || box[ 8 ] === 0 || box[ 4 ] === 0) {\n return\n }\n\n const n = x.length\n for (let i = 3; i < n; i += 3) {\n for (let j = 0; j < 3; ++j) {\n const f = (x[ i + j ] - mean[ j ]) / box[ j * 3 + j ]\n if (Math.abs(f) > 0.5) {\n x[ i + j ] -= box[ j * 3 + j ] * Math.round(f)\n }\n }\n }\n\n return x\n}\n\nfunction circularMean3 (indices: NumberArray, coords: NumberArray, box: ArrayLike) {\n return [\n circularMean(coords, box[ 0 ], 3, 0, indices),\n circularMean(coords, box[ 1 ], 3, 1, indices),\n circularMean(coords, box[ 2 ], 3, 2, indices)\n ]\n}\n\nfunction arrayMean3 (coords: NumberArray) {\n return [\n arrayMean(coords, 3, 0),\n arrayMean(coords, 3, 1),\n arrayMean(coords, 3, 2)\n ]\n}\n\nfunction interpolateSpline (c: NumberArray, cp: NumberArray, cpp: NumberArray, cppp: NumberArray, t: number) {\n const m = c.length\n const coords = new Float32Array(m)\n\n for (let j0 = 0; j0 < m; j0 += 3) {\n const j1 = j0 + 1\n const j2 = j0 + 2\n coords[ j0 ] = spline(cppp[ j0 ], cpp[ j0 ], cp[ j0 ], c[ j0 ], t, 1)\n coords[ j1 ] = spline(cppp[ j1 ], cpp[ j1 ], cp[ j1 ], c[ j1 ], t, 1)\n coords[ j2 ] = spline(cppp[ j2 ], cpp[ j2 ], cp[ j2 ], c[ j2 ], t, 1)\n }\n\n return coords\n}\n\nfunction interpolateLerp (c: NumberArray, cp: NumberArray, t: number) {\n const m = c.length\n const coords = new Float32Array(m)\n\n for (let j0 = 0; j0 < m; j0 += 3) {\n const j1 = j0 + 1\n const j2 = j0 + 2\n coords[ j0 ] = lerp(cp[ j0 ], c[ j0 ], t)\n coords[ j1 ] = lerp(cp[ j1 ], c[ j1 ], t)\n coords[ j2 ] = lerp(cp[ j2 ], c[ j2 ], t)\n }\n\n return coords\n}\n\n/**\n * Trajectory parameter object.\n * @typedef {Object} TrajectoryParameters - parameters\n *\n * @property {Number} deltaTime - timestep between frames in picoseconds\n * @property {Number} timeOffset - starting time of frames in picoseconds\n * @property {String} sele - to restrict atoms used for superposition\n * @property {Boolean} centerPbc - center on initial frame\n * @property {Boolean} removePeriodicity - move atoms into the origin box\n * @property {Boolean} remo - try fixing periodic boundary discontinuities\n * @property {Boolean} superpose - superpose on initial frame\n */\n\n/**\n * @example\n * trajectory.signals.frameChanged.add( function(i){ ... } );\n *\n * @typedef {Object} TrajectorySignals\n * @property {Signal} countChanged - when the frame count is changed\n * @property {Signal} frameChanged - when the set frame is changed\n * @property {Signal} playerChanged - when the player is changed\n */\n\nexport interface TrajectoryParameters {\n deltaTime: number // timestep between frames in picoseconds\n timeOffset: number // starting time of frames in picoseconds\n sele: string // to restrict atoms used for superposition\n centerPbc: boolean // center on initial frame\n removePbc: boolean // move atoms into the origin box\n removePeriodicity: boolean // try fixing periodic boundary discontinuities\n superpose: boolean // superpose on initial frame\n}\n\nexport interface TrajectorySignals {\n countChanged: Signal\n frameChanged: Signal\n playerChanged: Signal\n}\n\n/**\n * Base class for trajectories, tying structures and coordinates together\n * @interface\n */\nclass Trajectory {\n signals: TrajectorySignals = {\n countChanged: new Signal(),\n frameChanged: new Signal(),\n playerChanged: new Signal()\n }\n\n deltaTime: number\n timeOffset: number\n sele: string\n centerPbc: boolean\n removePbc: boolean\n removePeriodicity: boolean\n superpose: boolean\n\n name: string\n frame: number\n trajPath: string\n\n initialCoords: Float32Array\n structureCoords: Float32Array\n selectionIndices: NumberArray\n backboneIndices: NumberArray\n\n coords1: Float32Array\n coords2: Float32Array\n\n frameCache: { [k: number]: Float32Array } = {}\n loadQueue: { [k: number]: boolean } = {}\n boxCache: { [k: number]: ArrayLike } = {}\n pathCache = {}\n frameCacheSize = 0\n\n atomCount: number\n inProgress: boolean\n\n selection: Selection // selection to restrict atoms used for superposition\n structure: Structure\n player: TrajectoryPlayer\n\n private _frameCount = 0\n private _currentFrame = -1\n private _disposed = false\n\n /**\n * @param {String} trajPath - trajectory source\n * @param {Structure} structure - the structure object\n * @param {TrajectoryParameters} params - trajectory parameters\n */\n constructor (trajPath: string, structure: Structure, params: Partial = {}) {\n this.deltaTime = defaults(params.deltaTime, 0)\n this.timeOffset = defaults(params.timeOffset, 0)\n this.centerPbc = defaults(params.centerPbc, false)\n this.removePbc = defaults(params.removePbc, false)\n this.removePeriodicity = defaults(params.removePeriodicity, false)\n this.superpose = defaults(params.superpose, false)\n\n this.name = trajPath.replace(/^.*[\\\\/]/, '')\n this.trajPath = trajPath\n\n this.selection = new Selection(\n defaults(params.sele, 'backbone and not hydrogen')\n )\n\n this.selection.signals.stringChanged.add(() => {\n this.selectionIndices = this.structure.getAtomIndices(this.selection)!\n this._resetCache()\n this._saveInitialCoords()\n this.setFrame(this._currentFrame)\n })\n }\n\n /**\n * Number of frames in the trajectory\n */\n get frameCount () {\n return this._frameCount\n }\n\n /**\n * Currently set frame of the trajectory\n */\n get currentFrame () {\n return this._currentFrame\n }\n\n _init (structure: Structure) {\n this.setStructure(structure)\n this._loadFrameCount()\n this.setPlayer(new TrajectoryPlayer(this))\n }\n\n _loadFrameCount () {}\n\n setStructure (structure: Structure) {\n this.structure = structure\n this.atomCount = structure.atomCount\n\n this.backboneIndices = this._getIndices(\n new Selection('backbone and not hydrogen')\n )\n this._makeAtomIndices()\n this._saveStructureCoords()\n\n this.selectionIndices = this._getIndices(this.selection)\n this._resetCache()\n this._saveInitialCoords()\n this.setFrame(this._currentFrame)\n }\n\n _saveInitialCoords () {\n if (this.structure.hasCoords()) {\n this.initialCoords = new Float32Array(this.structureCoords)\n this._makeSuperposeCoords()\n } else if (this.frameCache[0]) {\n this.initialCoords = new Float32Array(this.frameCache[0])\n this._makeSuperposeCoords()\n } else {\n this.loadFrame(0, () => this._saveInitialCoords())\n }\n }\n\n _saveStructureCoords () {\n const p = { what: { position: true } }\n this.structureCoords = this.structure.getAtomData(p).position!\n }\n\n setSelection (string: string) {\n this.selection.setString(string)\n return this\n }\n\n _getIndices (selection: Selection) {\n let i = 0\n const test = selection.test\n const indices: number[] = []\n\n if (test) {\n this.structure.eachAtom((ap: AtomProxy) => {\n if (test(ap)) indices.push(i)\n i += 1\n })\n }\n\n return indices\n }\n\n _makeSuperposeCoords () {\n const n = this.selectionIndices.length * 3\n\n this.coords1 = new Float32Array(n)\n this.coords2 = new Float32Array(n)\n\n const y = this.initialCoords\n const coords2 = this.coords2\n\n for (let i = 0; i < n; i += 3) {\n const j = this.selectionIndices[ i / 3 ] * 3\n\n coords2[ i + 0 ] = y[ j + 0 ]\n coords2[ i + 1 ] = y[ j + 1 ]\n coords2[ i + 2 ] = y[ j + 2 ]\n }\n }\n\n _makeAtomIndices () {\n Log.error('Trajectory._makeAtomIndices not implemented')\n }\n\n _resetCache () {\n this.frameCache = {}\n this.loadQueue = {}\n this.boxCache = {}\n this.pathCache = {}\n this.frameCacheSize = 0\n this.initialCoords = new Float32Array(0)\n }\n\n setParameters (params: Partial = {}) {\n let resetCache = false\n\n if (params.centerPbc !== undefined && params.centerPbc !== this.centerPbc) {\n this.centerPbc = params.centerPbc\n resetCache = true\n }\n\n if (params.removePeriodicity !== undefined && params.removePeriodicity !== this.removePeriodicity) {\n this.removePeriodicity = params.removePeriodicity\n resetCache = true\n }\n\n if (params.removePbc !== undefined && params.removePbc !== this.removePbc) {\n this.removePbc = params.removePbc\n resetCache = true\n }\n\n if (params.superpose !== undefined && params.superpose !== this.superpose) {\n this.superpose = params.superpose\n resetCache = true\n }\n\n this.deltaTime = defaults(params.deltaTime, this.deltaTime)\n this.timeOffset = defaults(params.timeOffset, this.timeOffset)\n\n if (resetCache) {\n this._resetCache()\n this.setFrame(this._currentFrame)\n }\n }\n\n /**\n * Check if a frame is available\n * @param {Integer|Integer[]} i - the frame index\n * @return {Boolean} frame availability\n */\n hasFrame (i: number|number[]) {\n if (Array.isArray(i)) {\n return i.every(j => !!this.frameCache[j])\n } else {\n return !!this.frameCache[i]\n }\n }\n\n /**\n * Set trajectory to a frame index\n * @param {Integer} i - the frame index\n * @param {Function} [callback] - fired when the frame has been set\n */\n setFrame (i: number, callback?: Function) {\n if (i === undefined) return this\n\n this.inProgress = true\n\n // i = parseInt(i) // TODO\n\n if (i === -1 || this.frameCache[ i ]) {\n this._updateStructure(i)\n if (callback) callback()\n } else {\n this.loadFrame(i, () => {\n this._updateStructure(i)\n if (callback) callback()\n })\n }\n\n return this\n }\n\n _interpolate (i: number, ip: number, ipp: number, ippp: number, t: number, type: TrajectoryPlayerInterpolateType) {\n const fc = this.frameCache\n\n let coords\n if (type === 'spline') {\n coords = interpolateSpline(fc[ i ], fc[ ip ], fc[ ipp ], fc[ ippp ], t)\n } else {\n coords = interpolateLerp(fc[ i ], fc[ ip ], t)\n }\n\n this.structure.updatePosition(coords)\n this._currentFrame = i\n this.signals.frameChanged.dispatch(i)\n }\n\n /**\n * Interpolated and set trajectory to frame indices\n * @param {Integer} i - the frame index\n * @param {Integer} ip - one before frame index\n * @param {Integer} ipp - two before frame index\n * @param {Integer} ippp - three before frame index\n * @param {Number} t - interpolation step [0,1]\n * @param {String} type - interpolation type, '', 'spline' or 'linear'\n * @param {Function} callback - fired when the frame has been set\n */\n setFrameInterpolated (i: number, ip: number, ipp: number, ippp: number, t: number, type: TrajectoryPlayerInterpolateType, callback?: Function) {\n if (i === undefined) return this\n\n const fc = this.frameCache\n const iList: number[] = []\n\n if (!fc[ ippp ]) iList.push(ippp)\n if (!fc[ ipp ]) iList.push(ipp)\n if (!fc[ ip ]) iList.push(ip)\n if (!fc[ i ]) iList.push(i)\n\n if (iList.length) {\n this.loadFrame(iList, () => {\n this._interpolate(i, ip, ipp, ippp, t, type)\n if (callback) callback()\n })\n } else {\n this._interpolate(i, ip, ipp, ippp, t, type)\n if (callback) callback()\n }\n\n return this\n }\n\n /**\n * Load frame index\n * @param {Integer|Integer[]} i - the frame index\n * @param {Function} callback - fired when the frame has been loaded\n */\n loadFrame (i: number|number[], callback?: Function) {\n if (Array.isArray(i)) {\n i.forEach(j => {\n if (!this.loadQueue[j] && !this.frameCache[j]) {\n this.loadQueue[j] = true\n this._loadFrame(j, () => {\n delete this.loadQueue[j]\n })\n }\n })\n } else {\n if (!this.loadQueue[i] && !this.frameCache[i]) {\n this.loadQueue[i] = true\n this._loadFrame(i, () => {\n delete this.loadQueue[i]\n if (callback) callback()\n })\n }\n }\n }\n\n /**\n * Load frame index\n * @abstract\n * @param {Integer} i - the frame index\n * @param {Function} callback - fired when the frame has been loaded\n */\n _loadFrame (i: number, callback?: Function) {\n Log.error('Trajectory._loadFrame not implemented', i, callback)\n }\n\n _updateStructure (i: number) {\n if (this._disposed) {\n console.error('updateStructure: traj disposed')\n return\n }\n\n if (i === -1) {\n if (this.structureCoords) {\n this.structure.updatePosition(this.structureCoords)\n }\n } else {\n this.structure.updatePosition(this.frameCache[ i ])\n }\n\n this.structure.trajectory = {\n name: this.trajPath,\n frame: i\n }\n\n this._currentFrame = i\n this.inProgress = false\n this.signals.frameChanged.dispatch(i)\n }\n\n _doSuperpose (x: Float32Array) {\n const n = this.selectionIndices.length * 3\n\n const coords1 = this.coords1\n const coords2 = this.coords2\n\n for (let i = 0; i < n; i += 3) {\n const j = this.selectionIndices[ i / 3 ] * 3\n\n coords1[ i + 0 ] = x[ j + 0 ]\n coords1[ i + 1 ] = x[ j + 1 ]\n coords1[ i + 2 ] = x[ j + 2 ]\n }\n\n // TODO re-use superposition object\n const sp = new Superposition(coords1, coords2)\n sp.transform(x)\n }\n\n _process (i: number, box: ArrayLike, coords: Float32Array, frameCount: number) {\n this._setFrameCount(frameCount)\n\n if (box) {\n if (this.backboneIndices.length > 0 && this.centerPbc) {\n const box2 = [ box[ 0 ], box[ 4 ], box[ 8 ] ]\n const circMean = circularMean3(this.backboneIndices, coords, box2)\n centerPbc(coords, circMean, box2)\n }\n\n if (this.removePeriodicity) {\n const mean = arrayMean3(coords)\n removePeriodicity(coords, box, mean)\n }\n\n if (this.removePbc) {\n removePbc(coords, box)\n }\n }\n\n if (this.selectionIndices.length > 0 && this.coords1 && this.superpose) {\n this._doSuperpose(coords)\n }\n\n this.frameCache[ i ] = coords\n this.boxCache[ i ] = box\n this.frameCacheSize += 1\n }\n\n _setFrameCount (n: number) {\n if (n !== this._frameCount) {\n this._frameCount = n\n this.signals.countChanged.dispatch(n)\n }\n }\n\n /**\n * Dispose of the trajectory object\n * @return {undefined}\n */\n dispose () {\n this._resetCache() // aid GC\n this._disposed = true\n if (this.player) this.player.stop()\n }\n\n /**\n * Set player for this trajectory\n * @param {TrajectoryPlayer} player - the player\n */\n setPlayer (player: TrajectoryPlayer) {\n this.player = player\n this.signals.playerChanged.dispatch(player)\n }\n\n /**\n * Get time for frame\n * @param {Integer} i - frame index\n * @return {Number} time in picoseconds\n */\n getFrameTime (i: number) {\n return this.timeOffset + i * this.deltaTime\n }\n}\n\nexport default Trajectory\n","/**\n * @file Frames Trajectory\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport Structure from '../structure/structure'\nimport Frames from './frames'\nimport Trajectory, { TrajectoryParameters } from './trajectory'\n\n/**\n * Frames trajectory class. Gets data from a frames object.\n */\nclass FramesTrajectory extends Trajectory {\n path: string\n\n frames: ArrayLike[]\n boxes: ArrayLike[]\n\n atomIndices?: ArrayLike\n\n constructor (frames: Frames, structure: Structure, params: TrajectoryParameters) {\n const p = params || {}\n p.timeOffset = defaults(p.timeOffset, frames.timeOffset)\n p.deltaTime = defaults(p.deltaTime, frames.deltaTime)\n\n super('', structure, p)\n\n this.name = frames.name\n this.path = frames.path\n\n this.frames = frames.coordinates\n this.boxes = frames.boxes\n\n this._init(structure)\n }\n\n get type () { return 'frames' }\n\n _makeAtomIndices () {\n if (this.structure.type === 'StructureView') {\n this.atomIndices = this.structure.getAtomIndices()\n } else {\n this.atomIndices = undefined\n }\n }\n\n _loadFrame (i: number, callback?: Function) {\n let coords\n const frame = this.frames[ i ]\n\n if (this.atomIndices) {\n const indices = this.atomIndices\n const m = indices.length\n\n coords = new Float32Array(m * 3)\n\n for (let j = 0; j < m; ++j) {\n const j3 = j * 3\n const idx3 = indices[ j ] * 3\n\n coords[ j3 + 0 ] = frame[ idx3 + 0 ]\n coords[ j3 + 1 ] = frame[ idx3 + 1 ]\n coords[ j3 + 2 ] = frame[ idx3 + 2 ]\n }\n } else {\n coords = new Float32Array(frame)\n }\n\n const box = this.boxes[ i ]\n const frameCount = this.frames.length\n\n this._process(i, box, coords, frameCount)\n\n if (typeof callback === 'function') {\n callback()\n }\n }\n\n _loadFrameCount () {\n if (this.frames) {\n this._setFrameCount(this.frames.length)\n }\n }\n}\n\nexport default FramesTrajectory\n","/**\n * @file Structure Trajectory\n * @author Alexander Rose \n * @private\n */\n\nimport Structure from '../structure/structure'\nimport Trajectory, { TrajectoryParameters } from './trajectory'\n\n/**\n * Structure trajectory class. Gets data from a structure object.\n */\nclass StructureTrajectory extends Trajectory {\n atomIndices?: ArrayLike\n\n constructor (trajPath: string, structure: Structure, params: TrajectoryParameters) {\n super('', structure, params)\n this._init(structure)\n }\n\n get type () { return 'structure' }\n\n _makeAtomIndices () {\n if (this.structure.atomSet && this.structure.atomSet.getSize() < this.structure.atomStore.count) {\n this.atomIndices = this.structure.getAtomIndices()\n } else {\n this.atomIndices = undefined\n }\n }\n\n _loadFrame (i: number, callback?: Function) {\n let coords\n const structure = this.structure\n const frame = structure.frames[ i ]\n\n if (this.atomIndices) {\n const indices = this.atomIndices\n const m = indices.length\n\n coords = new Float32Array(m * 3)\n\n for (let j = 0; j < m; ++j) {\n const j3 = j * 3\n const idx3 = indices[ j ] * 3\n\n coords[ j3 + 0 ] = frame[ idx3 + 0 ]\n coords[ j3 + 1 ] = frame[ idx3 + 1 ]\n coords[ j3 + 2 ] = frame[ idx3 + 2 ]\n }\n } else {\n coords = new Float32Array(frame)\n }\n\n const box = structure.boxes[ i ]\n const frameCount = structure.frames.length\n\n this._process(i, box, coords, frameCount)\n\n if (typeof callback === 'function') {\n callback()\n }\n }\n\n _loadFrameCount () {\n this._setFrameCount(this.structure.frames.length)\n }\n}\n\nexport default StructureTrajectory\n","/**\n * @file Remote Trajectory\n * @author Alexander Rose \n * @private\n */\n\nimport { Log, TrajectoryDatasource } from '../globals'\nimport Structure from '../structure/structure'\nimport Trajectory, { TrajectoryParameters } from './trajectory'\n\n/**\n * Remote trajectory class. Gets data from an MDsrv instance.\n */\nclass RemoteTrajectory extends Trajectory {\n atomIndices: number[][]\n\n constructor (trajPath: string, structure: Structure, params: TrajectoryParameters) {\n super(trajPath, structure, params)\n this._init(structure)\n }\n\n get type () { return 'remote' }\n\n _makeAtomIndices () {\n const atomIndices = []\n\n if (this.structure.type === 'StructureView') {\n const indices = this.structure.getAtomIndices()! // TODO\n const n = indices.length\n\n let p = indices[ 0 ]\n let q = indices[ 0 ]\n\n for (let i = 1; i < n; ++i) {\n const r = indices[ i ]\n\n if (q + 1 < r) {\n atomIndices.push([ p, q + 1 ])\n p = r\n }\n\n q = r\n }\n\n atomIndices.push([ p, q + 1 ])\n } else {\n atomIndices.push([ 0, this.atomCount ])\n }\n\n this.atomIndices = atomIndices\n }\n\n _loadFrame (i: number, callback?: Function) {\n // TODO implement max frameCache size, re-use arrays\n\n const request = new XMLHttpRequest()\n\n const url = TrajectoryDatasource.getFrameUrl(this.trajPath, i)\n const params = TrajectoryDatasource.getFrameParams(this.trajPath, this.atomIndices)\n\n request.open('POST', url, true)\n request.responseType = 'arraybuffer'\n request.setRequestHeader(\n 'Content-type', 'application/x-www-form-urlencoded'\n )\n\n request.addEventListener('load', () => {\n const arrayBuffer = request.response\n if (!arrayBuffer) {\n Log.error(`empty arrayBuffer for '${url}'`)\n return\n }\n\n const frameCount = new Int32Array(arrayBuffer, 0, 1)[ 0 ]\n // const time = new Float32Array( arrayBuffer, 1 * 4, 1 )[ 0 ];\n const box = new Float32Array(arrayBuffer, 2 * 4, 9)\n const coords = new Float32Array(arrayBuffer, 11 * 4)\n\n this._process(i, box, coords, frameCount)\n if (typeof callback === 'function') {\n callback()\n }\n }, false)\n\n request.send(params)\n }\n\n _loadFrameCount () {\n const request = new XMLHttpRequest()\n\n const url = TrajectoryDatasource.getCountUrl(this.trajPath)\n\n request.open('GET', url, true)\n request.addEventListener('load', () => {\n this._setFrameCount(parseInt(request.response))\n }, false)\n request.send()\n }\n}\n\nexport default RemoteTrajectory\n","/**\n * @file Callback Trajectory\n * @author Tarn W. Burton \n * @private\n */\n\nimport Structure from '../structure/structure'\nimport Trajectory, { TrajectoryParameters } from './trajectory'\n\ntype RequestCallback = (responseCallback: Function, i?: number, atomIndices?: number[][]) => void\n\n/**\n * Callback trajectory class. Gets data from an JavaScript function.\n */\nclass CallbackTrajectory extends Trajectory {\n atomIndices: number[][]\n requestCallback: RequestCallback\n\n constructor (requestCallback: RequestCallback, structure: Structure, params: TrajectoryParameters) {\n super('', structure, params)\n this.requestCallback = requestCallback;\n this._init(structure)\n }\n\n get type () { return 'callback' }\n\n _makeAtomIndices () {\n const atomIndices = []\n\n if (this.structure.type === 'StructureView') {\n const indices = this.structure.getAtomIndices()! // TODO\n const n = indices.length\n\n let p = indices[ 0 ]\n let q = indices[ 0 ]\n\n for (let i = 1; i < n; ++i) {\n const r = indices[ i ]\n\n if (q + 1 < r) {\n atomIndices.push([ p, q + 1 ])\n p = r\n }\n\n q = r\n }\n\n atomIndices.push([ p, q + 1 ])\n } else {\n atomIndices.push([ 0, this.atomCount ])\n }\n\n this.atomIndices = atomIndices\n }\n\n _loadFrame (i: number, callback?: Function) {\n this.requestCallback(\n (i: number, box: ArrayLike, coords: Float32Array, frameCount: number) => {\n this._process(i, box, coords, frameCount)\n if (typeof callback === 'function') {\n callback()\n }\n }, i, this.atomIndices)\n }\n\n _loadFrameCount () {\n this.requestCallback((count: number) => this._setFrameCount(count))\n }\n}\n\nexport default CallbackTrajectory\n\n","/**\n * @file Structure View\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Box3 } from 'three'\n\nimport { Debug, Log } from '../globals'\nimport Structure from './structure'\nimport Selection from '../selection/selection'\nimport BitArray from '../utils/bitarray'\n\nimport BondProxy from '../proxy/bond-proxy'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ResidueProxy from '../proxy/residue-proxy'\nimport ChainProxy from '../proxy/chain-proxy'\nimport ModelProxy from '../proxy/model-proxy'\nimport SpatialHash from '../geometry/spatial-hash';\nimport BondHash from '../store/bond-hash';\nimport ResidueMap from '../store/residue-map';\nimport AtomMap from '../store/atom-map';\nimport ModelStore from '../store/model-store';\nimport ChainStore from '../store/chain-store';\nimport ResidueStore from '../store/residue-store';\nimport AtomStore from '../store/atom-store';\nimport BondStore from '../store/bond-store';\nimport Validation from './validation';\nimport Unitcell from '../symmetry/unitcell';\nimport Entity from './entity';\nimport Assembly from '../symmetry/assembly';\nimport { Data } from './data';\n\n/**\n * Get view on structure restricted to the selection\n * @param {Selection} selection - the selection\n * @return {StructureView} the view on the structure\n */\nStructure.prototype.getView = function (this: Structure, selection: Selection) {\n // added here to avoid cyclic import dependency\n return new StructureView(this, selection)\n}\n\n/**\n * View on the structure, restricted to the selection\n */\nclass StructureView extends Structure {\n structure: Structure\n selection: Selection\n\n /**\n * @param {Structure} structure - the structure\n * @param {Selection} selection - the selection\n */\n constructor (structure: Structure, selection: Selection) {\n super()\n\n this.structure = structure\n this.selection = selection\n\n this.center = new Vector3()\n this.boundingBox = new Box3()\n\n this._bp = this.getBondProxy()\n this._ap = this.getAtomProxy()\n this._rp = this.getResidueProxy()\n this._cp = this.getChainProxy()\n\n if (this.selection) {\n this.selection.signals.stringChanged.add(this.refresh, this)\n }\n\n this.structure.signals.refreshed.add(this.refresh, this)\n\n this.refresh()\n }\n\n init () {}\n\n get type () { return 'StructureView' }\n\n get name () { return this.structure.name }\n get path () { return this.structure.path }\n get title () { return this.structure.title }\n get id () { return this.structure.id }\n get data (): Data { return this.structure.data }\n get atomSetDict () { return this.structure.atomSetDict }\n get biomolDict (): {[k: string]: Assembly} { return this.structure.biomolDict }\n get entityList (): Entity[] { return this.structure.entityList }\n get unitcell (): Unitcell|undefined { return this.structure.unitcell }\n get frames () { return this.structure.frames }\n get boxes () { return this.structure.boxes }\n get validation (): Validation|undefined { return this.structure.validation }\n get bondStore () { return this.structure.bondStore }\n get backboneBondStore () { return this.structure.backboneBondStore }\n get rungBondStore (): BondStore { return this.structure.rungBondStore }\n get atomStore (): AtomStore { return this.structure.atomStore }\n get residueStore (): ResidueStore { return this.structure.residueStore }\n get chainStore (): ChainStore { return this.structure.chainStore }\n get modelStore (): ModelStore { return this.structure.modelStore }\n get atomMap (): AtomMap { return this.structure.atomMap }\n get residueMap (): ResidueMap { return this.structure.residueMap }\n get bondHash (): BondHash|undefined { return this.structure.bondHash }\n get spatialHash (): SpatialHash|undefined { return this.structure.spatialHash }\n\n get _hasCoords () { return this.structure._hasCoords }\n set _hasCoords (value) { this.structure._hasCoords = value }\n\n /**\n * Updates atomSet, bondSet, atomSetCache, atomCount, bondCount, boundingBox, center.\n * @emits {Structure.signals.refreshed} when refreshed\n * @return {undefined}\n */\n refresh () {\n if (Debug) Log.time('StructureView.refresh')\n\n this.atomSetCache = {}\n const structure = this.structure\n\n if (this.selection.isAllSelection() &&\n structure !== this && structure.atomSet && structure.bondSet\n ) {\n this.atomSet = structure.atomSet.clone()\n this.bondSet = structure.bondSet.clone()\n\n for (let name in this.atomSetDict) {\n const atomSet = this.atomSetDict[ name ]\n this.atomSetCache[ '__' + name ] = atomSet.clone()\n }\n\n this.atomCount = structure.atomCount\n this.bondCount = structure.bondCount\n\n this.boundingBox.copy(structure.boundingBox)\n this.center.copy(structure.center)\n } else if (this.selection.isNoneSelection() &&\n structure !== this && structure.atomSet && structure.bondSet\n ) {\n this.atomSet = new BitArray(structure.atomCount)\n this.bondSet = new BitArray(structure.bondCount)\n\n for (let name in this.atomSetDict) {\n this.atomSetCache[ '__' + name ] = new BitArray(structure.atomCount)\n }\n\n this.atomCount = 0\n this.bondCount = 0\n\n this.boundingBox.makeEmpty()\n this.center.set(0, 0, 0)\n } else {\n this.atomSet = this.getAtomSet(this.selection, true)\n if (structure.atomSet) {\n this.atomSet = this.atomSet.intersection(structure.atomSet)\n }\n\n this.bondSet = this.getBondSet()\n\n for (let name in this.atomSetDict) {\n const atomSet = this.atomSetDict[ name ]\n this.atomSetCache[ '__' + name ] = atomSet.makeIntersection(this.atomSet)\n }\n\n this.atomCount = this.atomSet.getSize()\n this.bondCount = this.bondSet.getSize()\n\n this.boundingBox = this.getBoundingBox()\n this.center = this.boundingBox.getCenter(new Vector3())\n }\n\n if (Debug) Log.timeEnd('StructureView.refresh')\n\n this.signals.refreshed.dispatch()\n }\n\n //\n\n setSelection (selection: Selection) {\n this.selection = selection\n\n this.refresh()\n }\n\n getSelection (selection?: Selection) {\n const seleList: string[] = []\n\n if (selection && selection.string) {\n seleList.push(selection.string)\n }\n\n const parentSelection = this.structure.getSelection()\n if (parentSelection && parentSelection.string) {\n seleList.push(parentSelection.string)\n }\n\n if (this.selection && this.selection.string) {\n seleList.push(this.selection.string)\n }\n\n let sele = ''\n if (seleList.length > 0) {\n sele = `( ${seleList.join(' ) AND ( ')} )`\n }\n\n return new Selection(sele)\n }\n\n getStructure () {\n return this.structure.getStructure()\n }\n\n //\n\n eachBond (callback: (entity: BondProxy) => any, selection?: Selection) {\n this.structure.eachBond(callback, this.getSelection(selection))\n }\n\n eachAtom (callback: (entity: AtomProxy) => any, selection?: Selection) {\n const ap = this.getAtomProxy()\n const atomSet = this.getAtomSet(selection)\n const n = this.atomStore.count\n\n if (atomSet.getSize() < n) {\n atomSet.forEach(function (index) {\n ap.index = index\n callback(ap)\n })\n } else {\n for (let i = 0; i < n; ++i) {\n ap.index = i\n callback(ap)\n }\n }\n }\n\n eachResidue (callback: (entity: ResidueProxy) => any, selection?: Selection) {\n this.structure.eachResidue(callback, this.getSelection(selection))\n }\n\n /**\n * Not implemented\n * @alias StructureView#eachResidueN\n * @return {undefined}\n */\n eachResidueN (n: number, callback: (entity: ResidueProxy) => any) {\n console.error('StructureView.eachResidueN() not implemented')\n }\n\n eachChain (callback: (entity: ChainProxy) => any, selection?: Selection) {\n this.structure.eachChain(callback, this.getSelection(selection))\n }\n\n eachModel (callback: (entity: ModelProxy) => any, selection?: Selection) {\n this.structure.eachModel(callback, this.getSelection(selection))\n }\n\n //\n\n getAtomSet (selection?: boolean|Selection|BitArray, ignoreView = false) {\n let atomSet = this.structure.getAtomSet(selection)\n if (!ignoreView && this.atomSet) {\n atomSet = atomSet.makeIntersection(this.atomSet)\n }\n\n return atomSet\n }\n\n //\n\n getAtomIndices (selection?: Selection) {\n return this.structure.getAtomIndices(this.getSelection(selection))\n }\n\n refreshPosition () {\n return this.structure.refreshPosition()\n }\n\n //\n\n dispose () {\n if (this.selection) {\n this.selection.signals.stringChanged.remove(this.refresh, this)\n }\n\n this.structure.signals.refreshed.remove(this.refresh, this)\n\n this.structure = new Structure() // delete old data\n\n delete this.atomSet\n delete this.bondSet\n\n }\n}\n\nexport default StructureView\n","/**\n * @file Alignment\n * @author Alexander Rose \n * @private\n */\n\nimport { Debug, Log } from '../globals'\n\n// const nucleotides = 'ACTG';\nconst aminoacidsX = 'ACDEFGHIKLMNPQRSTVWY'\nconst aminoacids = 'ARNDCQEGHILKMFPSTWYVBZ?'\n\nconst blosum62x = [\n [4, 0, -2, -1, -2, 0, -2, -1, -1, -1, -1, -2, -1, -1, -1, 1, 0, 0, -3, -2], // A\n [0, 9, -3, -4, -2, -3, -3, -1, -3, -1, -1, -3, -3, -3, -3, -1, -1, -1, -2, -2], // C\n [-2, -3, 6, 2, -3, -1, -1, -3, -1, -4, -3, 1, -1, 0, -2, 0, -1, -3, -4, -3], // D\n [-1, -4, 2, 5, -3, -2, 0, -3, 1, -3, -2, 0, -1, 2, 0, 0, -1, -2, -3, -2], // E\n [-2, -2, -3, -3, 6, -3, -1, 0, -3, 0, 0, -3, -4, -3, -3, -2, -2, -1, 1, 3], // F\n [0, -3, -1, -2, -3, 6, -2, -4, -2, -4, -3, 0, -2, -2, -2, 0, -2, -3, -2, -3], // G\n [-2, -3, -1, 0, -1, -2, 8, -3, -1, -3, -2, 1, -2, 0, 0, -1, -2, -3, -2, 2], // H\n [-1, -1, -3, -3, 0, -4, -3, 4, -3, 2, 1, -3, -3, -3, -3, -2, -1, 3, -3, -1], // I\n [-1, -3, -1, 1, -3, -2, -1, -3, 5, -2, -1, 0, -1, 1, 2, 0, -1, -2, -3, -2], // K\n [-1, -1, -4, -3, 0, -4, -3, 2, -2, 4, 2, -3, -3, -2, -2, -2, -1, 1, -2, -1], // L\n [-1, -1, -3, -2, 0, -3, -2, 1, -1, 2, 5, -2, -2, 0, -1, -1, -1, 1, -1, -1], // M\n [-2, -3, 1, 0, -3, 0, 1, -3, 0, -3, -2, 6, -2, 0, 0, 1, 0, -3, -4, -2], // N\n [-1, -3, -1, -1, -4, -2, -2, -3, -1, -3, -2, -2, 7, -1, -2, -1, -1, -2, -4, -3], // P\n [-1, -3, 0, 2, -3, -2, 0, -3, 1, -2, 0, 0, -1, 5, 1, 0, -1, -2, -2, -1], // Q\n [-1, -3, -2, 0, -3, -2, 0, -3, 2, -2, -1, 0, -2, 1, 5, -1, -1, -3, -3, -2], // R\n [1, -1, 0, 0, -2, 0, -1, -2, 0, -2, -1, 1, -1, 0, -1, 4, 1, -2, -3, -2], // S\n [0, -1, -1, -1, -2, -2, -2, -1, -1, -1, -1, 0, -1, -1, -1, 1, 5, 0, -2, -2], // T\n [0, -1, -3, -2, -1, -3, -3, 3, -2, 1, 1, -3, -2, -2, -3, -2, 0, 4, -3, -1], // V\n [-3, -2, -4, -3, 1, -2, -2, -3, -3, -2, -1, -4, -4, -2, -3, -3, -2, -3, 11, 2], // W\n [-2, -2, -3, -2, 3, -3, 2, -1, -2, -1, -1, -2, -3, -1, -2, -2, -2, -1, 2, 7] // Y\n]\n\nconst blosum62 = [\n // A R N D C Q E G H I L K M F P S T W Y V B Z X\n [4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0], // A\n [-1, 5, 0, -2, -3, 1, 0, -2, 0, -3, -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1], // R\n [-2, 0, 6, 1, -3, 0, 0, 0, 1, -3, -3, 0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1], // N\n [-2, -2, 1, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1], // D\n [0, -3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2], // C\n [-1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1], // Q\n [-1, 0, 0, 2, -4, 2, 5, -2, 0, -3, -3, 1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1], // E\n [0, -2, 0, -1, -3, -2, -2, 6, -2, -4, -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1], // G\n [-2, 0, 1, -1, -3, 0, 0, -2, 8, -3, -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1], // H\n [-1, -3, -3, -3, -1, -3, -3, -4, -3, 4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1], // I\n [-1, -2, -3, -4, -1, -2, -3, -4, -3, 2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1], // L\n [-1, 2, 0, -1, -3, 1, 1, -2, -1, -3, -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1], // K\n [-1, -1, -2, -3, -1, 0, -2, -3, -2, 1, 2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1], // M\n [-2, -3, -3, -3, -2, -3, -3, -3, -1, 0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1], // F\n [-1, -2, -2, -1, -3, -1, -1, -2, -2, -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2], // P\n [1, -1, 1, 0, -1, 0, 0, 0, -1, -2, -2, 0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0], // S\n [0, -1, 0, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0], // T\n [-3, -3, -4, -4, -2, -2, -3, -2, -2, -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2], // W\n [-2, -2, -2, -3, -2, -1, -2, -3, 2, -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1], // Y\n [0, -3, -3, -3, -1, -2, -2, -3, -3, 3, 1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1], // V\n [-2, -1, 3, 4, -3, 0, 1, -1, 0, -3, -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1], // B\n [-1, 0, 0, 1, -3, 3, 4, -2, 0, -3, -3, 1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1], // Z\n [0, -1, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1] // X\n]\n\nfunction prepareMatrix (cellNames: string, mat: number[][]) {\n let j: number\n let i = 0\n const matDict: { [k: string]: { [k: string]: number } } = {}\n mat.forEach(function (row) {\n j = 0\n const rowDict: { [k: string]: number } = {}\n row.forEach(function (elm) {\n rowDict[ cellNames[ j++ ] ] = elm\n })\n matDict[ cellNames[ i++ ] ] = rowDict\n })\n return matDict\n}\n\nconst SubstitutionMatrices = (function () {\n return {\n blosum62: prepareMatrix(aminoacids, blosum62),\n blosum62x: prepareMatrix(aminoacidsX, blosum62x)\n }\n}())\nexport type SubstitutionMatrix = ''|'blosum62'|'blosum62x'\n\nclass Alignment {\n substMatrix: { [k: string]: { [k: string]: number } }\n\n n: number\n m: number\n score?: number\n ali: string\n\n S: number[][]\n V: number[][]\n H: number[][]\n\n ali1: string\n ali2: string\n\n constructor (readonly seq1: string, readonly seq2: string, readonly gapPenalty = -10, readonly gapExtensionPenalty = -1, substMatrix: SubstitutionMatrix = 'blosum62') {\n // TODO try encoding seqs as integers and use array subst matrix, maybe faster\n\n if (substMatrix) {\n this.substMatrix = SubstitutionMatrices[ substMatrix ]\n }\n }\n\n initMatrices () {\n this.n = this.seq1.length\n this.m = this.seq2.length\n\n // Log.log(this.n, this.m);\n\n this.score = undefined\n this.ali = ''\n\n this.S = []\n this.V = []\n this.H = []\n\n for (let i = 0; i <= this.n; ++i) {\n this.S[ i ] = []\n this.V[ i ] = []\n this.H[ i ] = []\n\n for (let j = 0; j <= this.m; ++j) {\n this.S[ i ][ j ] = 0\n this.V[ i ][ j ] = 0\n this.H[ i ][ j ] = 0\n }\n }\n\n for (let i = 0; i <= this.n; ++i) {\n this.S[ i ][ 0 ] = this.gap(0)\n this.H[ i ][ 0 ] = -Infinity\n }\n\n for (let j = 0; j <= this.m; ++j) {\n this.S[ 0 ][ j ] = this.gap(0)\n this.V[ 0 ][ j ] = -Infinity\n }\n\n this.S[ 0 ][ 0 ] = 0\n\n // Log.log(this.S, this.V, this.H);\n }\n\n gap (len: number) {\n return this.gapPenalty + len * this.gapExtensionPenalty\n }\n\n makeScoreFn () {\n const seq1 = this.seq1\n const seq2 = this.seq2\n\n const substMatrix = this.substMatrix\n\n if (substMatrix) {\n return function score (i: number, j: number) {\n const c1 = seq1[ i ]\n const c2 = seq2[ j ]\n\n try {\n return substMatrix[ c1 ][ c2 ]\n } catch (e) {\n return -4\n }\n }\n } else {\n Log.warn('Alignment: no subst matrix')\n\n return function scoreNoSubstMat (i: number, j: number) {\n const c1 = seq1[ i ]\n const c2 = seq2[ j ]\n\n return c1 === c2 ? 5 : -3\n }\n }\n }\n\n calc () {\n if (Debug) Log.time('Alignment.calc')\n\n this.initMatrices()\n\n const gap0 = this.gap(0)\n const scoreFn = this.makeScoreFn()\n const gapExtensionPenalty = this.gapExtensionPenalty\n\n const V = this.V\n const H = this.H\n const S = this.S\n\n const n = this.n\n const m = this.m\n\n let Vi1, Si1, Vi, Hi, Si\n\n for (let i = 1; i <= n; ++i) {\n Si1 = S[ i - 1 ]\n Vi1 = V[ i - 1 ]\n\n Vi = V[ i ]\n Hi = H[ i ]\n Si = S[ i ]\n\n for (let j = 1; j <= m; ++j) {\n Vi[j] = Math.max(\n Si1[ j ] + gap0,\n Vi1[ j ] + gapExtensionPenalty\n )\n\n Hi[j] = Math.max(\n Si[ j - 1 ] + gap0,\n Hi[ j - 1 ] + gapExtensionPenalty\n )\n\n Si[j] = Math.max(\n Si1[ j - 1 ] + scoreFn(i - 1, j - 1), // match\n Vi[ j ], // del\n Hi[ j ] // ins\n )\n }\n }\n\n if (Debug) Log.timeEnd('Alignment.calc')\n\n if (Debug) Log.log(this.S, this.V, this.H)\n }\n\n trace () {\n if (Debug) Log.time('Alignment.trace')\n\n this.ali1 = ''\n this.ali2 = ''\n\n const scoreFn = this.makeScoreFn()\n\n let i = this.n\n let j = this.m\n let mat\n\n if (this.S[i][j] >= this.V[i][j]) {\n mat = 'S'\n this.score = this.S[i][j]\n } else if (this.V[i][j] >= this.H[i][j]) {\n mat = 'V'\n this.score = this.V[i][j]\n } else {\n mat = 'H'\n this.score = this.H[i][j]\n }\n\n if (Debug) Log.log('Alignment: SCORE', this.score)\n if (Debug) Log.log('Alignment: S, V, H', this.S[i][j], this.V[i][j], this.H[i][j])\n\n while (i > 0 && j > 0) {\n if (mat === 'S') {\n if (this.S[i][j] === this.S[i - 1][j - 1] + scoreFn(i - 1, j - 1)) {\n this.ali1 = this.seq1[i - 1] + this.ali1\n this.ali2 = this.seq2[j - 1] + this.ali2\n --i\n --j\n mat = 'S'\n } else if (this.S[i][j] === this.V[i][j]) {\n mat = 'V'\n } else if (this.S[i][j] === this.H[i][j]) {\n mat = 'H'\n } else {\n // Log.debug('Alignment: S');\n --i\n --j\n }\n } else if (mat === 'V') {\n if (this.V[i][j] === this.V[i - 1][j] + this.gapExtensionPenalty) {\n this.ali1 = this.seq1[i - 1] + this.ali1\n this.ali2 = '-' + this.ali2\n --i\n mat = 'V'\n } else if (this.V[i][j] === this.S[i - 1][j] + this.gap(0)) {\n this.ali1 = this.seq1[i - 1] + this.ali1\n this.ali2 = '-' + this.ali2\n --i\n mat = 'S'\n } else {\n // Log.debug('Alignment: V');\n --i\n }\n } else if (mat === 'H') {\n if (this.H[i][j] === this.H[i][j - 1] + this.gapExtensionPenalty) {\n this.ali1 = '-' + this.ali1\n this.ali2 = this.seq2[j - 1] + this.ali2\n --j\n mat = 'H'\n } else if (this.H[i][j] === this.S[i][j - 1] + this.gap(0)) {\n this.ali1 = '-' + this.ali1\n this.ali2 = this.seq2[j - 1] + this.ali2\n --j\n mat = 'S'\n } else {\n // Log.debug('Alignment: H');\n --j\n }\n } else {\n Log.error('Alignment: no matrix')\n }\n }\n\n while (i > 0) {\n this.ali1 = this.seq1[ i - 1 ] + this.ali1\n this.ali2 = '-' + this.ali2\n --i\n }\n\n while (j > 0) {\n this.ali1 = '-' + this.ali1\n this.ali2 = this.seq2[ j - 1 ] + this.ali2\n --j\n }\n\n if (Debug) Log.timeEnd('Alignment.trace')\n\n if (Debug) Log.log([this.ali1, this.ali2])\n }\n}\n\nexport default Alignment\n","/**\n * @file Align Utils\n * @author Alexander Rose \n * @private\n */\n\nimport Structure from '../structure/structure'\nimport Selection from '../selection/selection'\nimport Alignment from './alignment'\nimport Superposition from './superposition'\n\n/**\n * Perform structural superposition of two structures,\n * optionally guided by a sequence alignment\n * @param {Structure|StructureView} s1 - structure 1 which is superposed onto structure 2\n * @param {Structure|StructureView} s2 - structure 2 onto which structure 1 is superposed\n * @param {Boolean} [align] - guide the superposition by a sequence alignment\n * @param {String} [sele1] - selection string for structure 1\n * @param {String} [sele2] - selection string for structure 2\n * @return {undefined}\n */\nfunction superpose (s1: Structure, s2: Structure, align = false, sele1 = '', sele2 = '') {\n let i: number\n let j: number\n let n: number\n let atoms1\n let atoms2\n\n if (align) {\n let _s1 = s1\n let _s2 = s2\n\n if (sele1 && sele2) {\n _s1 = s1.getView(new Selection(sele1))\n _s2 = s2.getView(new Selection(sele2))\n }\n\n const seq1 = _s1.getSequence()\n const seq2 = _s2.getSequence()\n\n // Log.log( seq1.join(\"\") );\n // Log.log( seq2.join(\"\") );\n\n const ali = new Alignment(seq1.join(''), seq2.join(''))\n\n ali.calc()\n ali.trace()\n\n // Log.log( \"superpose alignment score\", ali.score );\n\n // Log.log( ali.ali1 );\n // Log.log( ali.ali2 );\n\n let _i, _j\n i = 0\n j = 0\n n = ali.ali1.length\n const aliIdx1: boolean[] = []\n const aliIdx2: boolean[] = []\n\n for (let l = 0; l < n; ++l) {\n const x = ali.ali1[ l ]\n const y = ali.ali2[ l ]\n\n _i = 0\n _j = 0\n\n if (x === '-') {\n aliIdx2[ j ] = false\n } else {\n aliIdx2[ j ] = true\n _i = 1\n }\n\n if (y === '-') {\n aliIdx1[ i ] = false\n } else {\n aliIdx1[ i ] = true\n _j = 1\n }\n\n i += _i\n j += _j\n }\n\n // Log.log( i, j );\n\n // Log.log( aliIdx1 );\n // Log.log( aliIdx2 );\n\n const _atoms1: number[] = []\n const _atoms2: number[] = []\n const ap1 = _s1.getAtomProxy()\n const ap2 = _s2.getAtomProxy()\n\n i = 0\n _s1.eachResidue(function (r) {\n if (r.traceAtomIndex === undefined ||\n r.traceAtomIndex !== r.getAtomIndexByName('CA')) return\n\n if (aliIdx1[ i ]) {\n ap1.index = r.getAtomIndexByName('CA')! // TODO\n _atoms1.push(ap1.x, ap1.y, ap1.z)\n }\n i += 1\n })\n\n i = 0\n _s2.eachResidue(function (r) {\n if (r.traceAtomIndex === undefined ||\n r.traceAtomIndex !== r.getAtomIndexByName('CA')) return\n\n if (aliIdx2[ i ]) {\n ap2.index = r.getAtomIndexByName('CA')! // TODO\n _atoms2.push(ap2.x, ap2.y, ap2.z)\n }\n i += 1\n })\n\n atoms1 = new Float32Array(_atoms1)\n atoms2 = new Float32Array(_atoms2)\n } else {\n const sviewCa1 = s1.getView(new Selection(`${sele1} and .CA`))\n const sviewCa2 = s2.getView(new Selection(`${sele2} and .CA`))\n\n atoms1 = sviewCa1\n atoms2 = sviewCa2\n }\n\n const superpose = new Superposition(atoms1, atoms2)\n const result = superpose.transform(s1)\n s1.refreshPosition()\n return result\n}\n\nexport {\n superpose\n}\n","/**\n * @file Sturucture Component\n * @author Alexander Rose \n * @private\n */\n\nimport { Signal } from 'signals'\n\nimport { ComponentRegistry, MeasurementDefaultParams } from '../globals'\nimport {\n defaults, /*deepEqual, */createRingBuffer, RingBuffer, createSimpleDict, SimpleDict\n} from '../utils'\nimport { smoothstep } from '../math/math-utils'\nimport Component, { ComponentSignals, ComponentDefaultParameters } from './component'\nimport RepresentationCollection from './representation-collection'\nimport TrajectoryElement from './trajectory-element'\nimport RepresentationElement from './representation-element'\nimport { makeTrajectory } from '../trajectory/trajectory-utils'\nimport { TrajectoryParameters } from '../trajectory/trajectory'\nimport Selection from '../selection/selection'\nimport Structure from '../structure/structure'\nimport StructureView from '../structure/structure-view'\nimport { superpose } from '../align/align-utils'\nimport Stage from '../stage/stage'\nimport StructureRepresentation, { StructureRepresentationParameters } from '../representation/structure-representation'\nimport AtomProxy from '../proxy/atom-proxy'\nimport { Vector3, Box3 } from 'three';\nimport { AngleRepresentationParameters } from '../representation/angle-representation';\nimport { AxesRepresentationParameters } from '../representation/axes-representation';\nimport { BallAndStickRepresentationParameters } from '../representation/ballandstick-representation';\nimport { CartoonRepresentationParameters } from '../representation/cartoon-representation';\nimport { ContactRepresentationParameters } from '../representation/contact-representation';\nimport { DihedralRepresentationParameters } from '../representation/dihedral-representation';\nimport { DihedralHistogramRepresentationParameters } from '../representation/dihedral-histogram-representation';\nimport { DistanceRepresentationParameters } from '../representation/distance-representation';\nimport { HyperballRepresentationParameters } from '../representation/hyperball-representation';\nimport { LabelRepresentationParameters } from '../representation/label-representation';\nimport { LineRepresentationParameters } from '../representation/line-representation';\nimport { PointRepresentationParameters } from '../representation/point-representation';\nimport { SurfaceRepresentationParameters } from '../representation/surface-representation';\nimport { RibbonRepresentationParameters } from '../representation/ribbon-representation';\nimport { RocketRepresentationParameters } from '../representation/rocket-representation';\nimport { TraceRepresentationParameters } from '../representation/trace-representation';\nimport { UnitcellRepresentationParameters } from '../representation/unitcell-representation';\nimport { SliceRepresentationParameters } from '../representation/slice-representation'\nimport { MolecularSurfaceRepresentationParameters } from '../representation/molecularsurface-representation'\nimport { DotRepresentationParameters } from '../representation/dot-representation'\n\nexport type StructureRepresentationType = keyof StructureRepresentationParametersMap\n\ninterface StructureRepresentationParametersMap {\n 'angle': AngleRepresentationParameters,\n 'axes' : AxesRepresentationParameters,\n 'backbone': BallAndStickRepresentationParameters,\n 'ball+stick': BallAndStickRepresentationParameters,\n 'base': BallAndStickRepresentationParameters,\n 'cartoon': CartoonRepresentationParameters,\n 'contact': ContactRepresentationParameters,\n 'dihedral': DihedralRepresentationParameters,\n 'dihedral-histogram': DihedralHistogramRepresentationParameters,\n 'distance': DistanceRepresentationParameters,\n 'dot': DotRepresentationParameters,\n 'helixorient': StructureRepresentationParameters,\n 'hyperball': HyperballRepresentationParameters,\n 'label': LabelRepresentationParameters,\n 'licorice': BallAndStickRepresentationParameters,\n 'line': LineRepresentationParameters,\n 'molecularsurface': MolecularSurfaceRepresentationParameters,\n 'point': PointRepresentationParameters,\n 'ribbon': RibbonRepresentationParameters,\n 'rocket': RocketRepresentationParameters,\n 'rope': CartoonRepresentationParameters,\n 'slice': SliceRepresentationParameters,\n 'spacefill': BallAndStickRepresentationParameters,\n 'surface': SurfaceRepresentationParameters,\n 'trace': TraceRepresentationParameters,\n 'tube': CartoonRepresentationParameters,\n 'unitcell': UnitcellRepresentationParameters,\n 'validation': StructureRepresentationParameters\n}\n\nexport const StructureComponentDefaultParameters = Object.assign({\n sele: '',\n defaultAssembly: ''\n}, ComponentDefaultParameters)\nexport type StructureComponentParameters = typeof StructureComponentDefaultParameters\n\nexport interface StructureComponentSignals extends ComponentSignals {\n trajectoryAdded: Signal // when a trajectory is added\n trajectoryRemoved: Signal // when a trajectory is removed\n defaultAssemblyChanged: Signal // on default assembly change\n}\n\n/**\n * Component wrapping a {@link Structure} object\n *\n * @example\n * // get a structure component by loading a structure file into the stage\n * stage.loadFile( \"rcsb://4opj\" ).then( function( structureComponent ){\n * structureComponent.addRepresentation( \"cartoon\" );\n * structureComponent.autoView();\n * } );\n */\nclass StructureComponent extends Component {\n readonly signals: StructureComponentSignals\n readonly parameters: StructureComponentParameters\n get defaultParameters () { return StructureComponentDefaultParameters }\n\n selection: Selection\n structureView: StructureView\n readonly trajList: TrajectoryElement[] = []\n\n pickBuffer: RingBuffer\n pickDict: SimpleDict\n lastPick?: number\n\n spacefillRepresentation: RepresentationElement\n distanceRepresentation: RepresentationElement\n angleRepresentation: RepresentationElement\n dihedralRepresentation: RepresentationElement\n\n measureRepresentations: RepresentationCollection\n\n constructor (stage: Stage, readonly structure: Structure, params: Partial = {}) {\n super(stage, structure, Object.assign({ name: structure.name }, params))\n\n this.signals = Object.assign(this.signals, {\n trajectoryAdded: new Signal(),\n trajectoryRemoved: new Signal(),\n defaultAssemblyChanged: new Signal()\n })\n\n this.initSelection(this.parameters.sele)\n\n //\n\n this.pickBuffer = createRingBuffer(4)\n this.pickDict = createSimpleDict()\n\n this.spacefillRepresentation = this.addRepresentation('spacefill', {\n sele: 'none',\n opacity: MeasurementDefaultParams.opacity,\n color: MeasurementDefaultParams.color,\n disablePicking: true,\n radiusType: 'data'\n }, true)\n\n this.distanceRepresentation = this.addRepresentation(\n 'distance', MeasurementDefaultParams, true\n )\n this.angleRepresentation = this.addRepresentation(\n 'angle', MeasurementDefaultParams, true\n )\n this.dihedralRepresentation = this.addRepresentation(\n 'dihedral', MeasurementDefaultParams, true\n )\n\n this.measureRepresentations = new RepresentationCollection([\n this.spacefillRepresentation,\n this.distanceRepresentation,\n this.angleRepresentation,\n this.dihedralRepresentation\n ])\n\n //\n\n this.setDefaultAssembly(this.parameters.defaultAssembly)\n\n this.structure.signals.refreshed.add(() => {\n this.updateRepresentations({ position: true })\n })\n }\n\n /**\n * Component type\n * @type {String}\n */\n get type () { return 'structure' }\n\n /**\n * Initialize selection\n * @private\n * @param {String} sele - selection string\n * @return {undefined}\n */\n initSelection (sele: string) {\n /**\n * Selection for {@link StructureComponent#structureView}\n * @private\n * @type {Selection}\n */\n this.selection = new Selection(sele)\n\n /**\n * View on {@link StructureComponent#structure}.\n * Change its selection via {@link StructureComponent#setSelection}.\n * @type {StructureView}\n */\n this.structureView = new StructureView(\n this.structure, this.selection\n )\n\n this.selection.signals.stringChanged.add(() => {\n this.structureView.setSelection(this.selection)\n\n this.rebuildRepresentations()\n this.rebuildTrajectories()\n })\n }\n\n /**\n * Set selection of {@link StructureComponent#structureView}\n * @param {String} string - selection string\n * @return {StructureComponent} this object\n */\n setSelection (string: string) {\n this.parameters.sele = string\n this.selection.setString(string)\n return this\n }\n\n /**\n * Set the default assembly\n * @param {String} value - assembly name\n * @return {undefined}\n */\n setDefaultAssembly (value:string) {\n // filter out non-exsisting assemblies\n if (this.structure.biomolDict[value] === undefined) value = ''\n // only set default assembly when changed\n if (this.parameters.defaultAssembly !== value) {\n const reprParams = { defaultAssembly: value }\n this.reprList.forEach(repr => repr.setParameters(reprParams))\n this.measureRepresentations.setParameters(reprParams)\n this.parameters.defaultAssembly = value\n this.signals.defaultAssemblyChanged.dispatch(value)\n }\n return this\n }\n\n /**\n * Rebuild all representations\n * @return {undefined}\n */\n rebuildRepresentations () {\n this.reprList.forEach((repr: RepresentationElement) => {\n repr.build()\n })\n this.measureRepresentations.build()\n }\n\n /**\n * Rebuild all trajectories\n * @return {undefined}\n */\n rebuildTrajectories () {\n this.trajList.forEach(trajComp => {\n trajComp.trajectory.setStructure(this.structureView)\n })\n }\n\n updateRepresentations (what: any) {\n super.updateRepresentations(what)\n this.measureRepresentations.update(what)\n }\n\n /**\n * Overrides {@link Component.updateRepresentationMatrices} \n * to also update matrix for measureRepresentations \n */\n updateRepresentationMatrices () {\n super.updateRepresentationMatrices()\n this.measureRepresentations.setParameters({ matrix: this.matrix })\n }\n\n addRepresentation (\n type: K,\n params: Partial|{defaultAssembly: string} = {},\n hidden = false\n ) {\n params.defaultAssembly = this.parameters.defaultAssembly\n\n const reprComp = this._addRepresentation(type, this.structureView, params, hidden)\n if (!hidden) {\n reprComp.signals.parametersChanged.add(() => this.measureUpdate())\n }\n return reprComp\n }\n\n /**\n * Add a new trajectory component to the structure\n */\n addTrajectory (trajPath = '', params: { [k: string]: any } = {}) {\n const traj = makeTrajectory(trajPath, this.structureView, params as TrajectoryParameters)\n\n const trajComp = new TrajectoryElement(this.stage, traj, params)\n this.trajList.push(trajComp)\n this.signals.trajectoryAdded.dispatch(trajComp)\n\n return trajComp\n }\n\n removeTrajectory (traj: TrajectoryElement) {\n const idx = this.trajList.indexOf(traj)\n if (idx !== -1) {\n this.trajList.splice(idx, 1)\n }\n\n traj.dispose()\n\n this.signals.trajectoryRemoved.dispatch(traj)\n }\n\n dispose () {\n // copy via .slice because side effects may change trajList\n this.trajList.slice().forEach(traj => traj.dispose())\n\n this.trajList.length = 0\n this.structure.dispose()\n this.measureRepresentations.dispose()\n\n super.dispose()\n }\n\n /**\n * Automatically center and zoom the component\n * @param {String|Integer} [sele] - selection string or duration if integer\n * @param {Integer} [duration] - duration of the animation, defaults to 0\n * @return {undefined}\n */\n autoView (sele?: string|number, duration?: number) {\n if (typeof sele === 'number') {\n duration = sele\n sele = ''\n }\n\n this.stage.animationControls.zoomMove(\n this.getCenter(sele),\n this.getZoom(sele),\n defaults(duration, 0)\n )\n }\n\n getBoxUntransformed (sele: string): Box3 {\n let bb\n\n if (sele) {\n bb = this.structureView.getBoundingBox(new Selection(sele))\n } else {\n bb = this.structureView.boundingBox\n }\n\n return bb\n }\n\n getCenterUntransformed (sele: string): Vector3 {\n if (sele && typeof sele === 'string') {\n return this.structure.atomCenter(new Selection(sele))\n } else {\n return this.structure.center\n }\n }\n\n superpose (component: StructureComponent, align: boolean, sele1: string, sele2: string) {\n superpose(\n this.structureView, component.structureView, align, sele1, sele2\n )\n\n this.updateRepresentations({ 'position': true })\n\n return this\n }\n\n getMaxRepresentationRadius (atomIndex: number) {\n let maxRadius = 0\n const atom = this.structure.getAtomProxy(atomIndex)\n this.eachRepresentation(reprElem => {\n if (reprElem.getVisibility()) {\n const repr: StructureRepresentation = reprElem.repr as any // TODO\n maxRadius = Math.max(repr.getAtomRadius(atom), maxRadius)\n }\n })\n return maxRadius\n }\n\n measurePick (atom: AtomProxy) {\n const pickCount = this.pickBuffer.count\n\n if (this.lastPick === atom.index && pickCount >= 1) {\n if (pickCount > 1) {\n const atomList = this.pickBuffer.data\n const atomListSorted = this.pickBuffer.data.sort()\n if (this.pickDict.has(atomListSorted)) {\n this.pickDict.del(atomListSorted)\n } else {\n this.pickDict.add(atomListSorted, atomList)\n }\n if (pickCount === 2) {\n this.distanceRepresentation.setParameters({\n atomPair: this.pickDict.values.filter(l => l.length === 2)\n })\n } else if (pickCount === 3) {\n this.angleRepresentation.setParameters({\n atomTriple: this.pickDict.values.filter(l => l.length === 3)\n })\n } else if (pickCount === 4) {\n this.dihedralRepresentation.setParameters({\n atomQuad: this.pickDict.values.filter(l => l.length === 4)\n })\n }\n }\n this.pickBuffer.clear()\n this.lastPick = undefined\n } else {\n if (!this.pickBuffer.has(atom.index)) {\n this.pickBuffer.push(atom.index)\n }\n this.lastPick = atom.index\n }\n\n this.measureUpdate()\n }\n\n measureClear () {\n this.pickBuffer.clear()\n this.lastPick = undefined\n this.spacefillRepresentation.setSelection('none')\n }\n\n measureBuild () {\n const md = this.measureData()\n this.distanceRepresentation.setParameters({ atomPair: md.distance })\n this.angleRepresentation.setParameters({ atomTriple: md.angle })\n this.dihedralRepresentation.setParameters({ atomQuad: md.dihedral })\n }\n\n measureUpdate () {\n const pickData = this.pickBuffer.data\n const radiusData: { [k: number]: number } = {}\n pickData.forEach(ai => {\n const r = Math.max(0.1, this.getMaxRepresentationRadius(ai))\n radiusData[ ai ] = r * (2.3 - smoothstep(0.1, 2, r))\n })\n this.spacefillRepresentation.setSelection(\n pickData.length ? ( '@' + pickData.join(',') ) : 'none'\n )\n if (pickData.length)\n this.spacefillRepresentation.setParameters({ radiusData })\n }\n\n measureData () {\n const pv = this.pickDict.values\n return {\n distance: pv.filter(l => l.length === 2),\n angle: pv.filter(l => l.length === 3),\n dihedral: pv.filter(l => l.length === 4)\n }\n }\n\n /**\n * Remove all measurements, optionally limit to distance, angle or dihedral\n */\n removeAllMeasurements (type?: MeasurementFlags) {\n const pd = this.pickDict\n const pv = pd.values\n const remove = function (len: number) {\n pv.filter(l => l.length === len).forEach(l => pd.del(l.slice().sort()))\n }\n if (!type || type & MeasurementFlags.Distance) remove(2)\n if (!type || type & MeasurementFlags.Angle) remove(3)\n if (!type || type & MeasurementFlags.Dihedral) remove(4)\n this.measureBuild()\n }\n\n /**\n * Remove a measurement given as a pair, triple, quad of atom indices\n */\n removeMeasurement (atomList: number[]) {\n this.pickDict.del(atomList.slice().sort())\n this.measureBuild()\n }\n\n /**\n * Add a measurement given as a pair, triple, quad of atom indices\n */\n addMeasurement (atomList: number[]) {\n if (atomList.length < 2 || atomList.length > 4) return\n const atomListSorted = atomList.slice().sort()\n if (!this.pickDict.has(atomListSorted)) {\n this.pickDict.add(atomListSorted, atomList)\n }\n this.measureBuild()\n }\n}\n\nexport const enum MeasurementFlags {\n Distance = 0x1,\n Angle = 0x2,\n Dihedral = 0x4\n}\n\nComponentRegistry.add('structure', StructureComponent)\nComponentRegistry.add('structureview', StructureComponent)\n\nexport default StructureComponent\n","/**\n * @file Trajectory Utils\n * @author Alexander Rose \n * @private\n */\n\nimport Structure from '../structure/structure'\nimport Frames from './frames'\nimport { TrajectoryParameters } from './trajectory'\nimport FramesTrajectory from './frames-trajectory'\nimport StructureTrajectory from './structure-trajectory'\nimport RemoteTrajectory from './remote-trajectory'\nimport CallbackTrajectory from './callback-trajectory'\n\nexport function makeTrajectory (trajSrc: string|Frames, structure: Structure, params: TrajectoryParameters) {\n let traj\n\n if (trajSrc && trajSrc instanceof Frames) {\n traj = new FramesTrajectory(trajSrc, structure, params)\n } else if (!trajSrc && structure.frames) {\n traj = new StructureTrajectory(trajSrc, structure, params)\n } else if (trajSrc && typeof trajSrc === 'function') {\n traj = new CallbackTrajectory(trajSrc, structure, params)\n } else {\n traj = new RemoteTrajectory(trajSrc, structure, params)\n }\n\n return traj\n}\n\n","/**\n * @file Surface Component\n * @author Alexander Rose \n * @private\n */\n\nimport { ComponentRegistry } from '../globals'\nimport Component, { ComponentParameters } from './component'\nimport Stage from '../stage/stage'\nimport Surface from '../surface/surface'\nimport { Vector3, Box3 } from 'three';\nimport RepresentationElement from './representation-element';\n\nexport type SurfaceRepresentationType = 'surface'|'dot'\n\n/**\n * Component wrapping a {@link Surface} object\n *\n * @example\n * // get a surface component by loading a surface file into the stage\n * stage.loadFile( \"url/for/surface\" ).then( function( surfaceComponent ){\n * surfaceComponent.addRepresentation( \"surface\" );\n * surfaceComponent.autoView();\n * } );\n */\nclass SurfaceComponent extends Component {\n /**\n * @param {Stage} stage - stage object the component belongs to\n * @param {Surface} surface - surface object to wrap\n * @param {ComponentParameters} params - component parameters\n */\n constructor (stage: Stage, readonly surface: Surface, params: Partial = {}) {\n super(stage, surface, Object.assign({ name: surface.name }, params))\n }\n\n /**\n * Component type\n * @type {String}\n */\n get type () { return 'surface' }\n\n /**\n * Add a new surface representation to the component\n * @param {String} type - the name of the representation, one of:\n * surface, dot.\n * @param {SurfaceRepresentationParameters} params - representation parameters\n * @return {RepresentationComponent} the created representation wrapped into\n * a representation component object\n */\n addRepresentation (type: SurfaceRepresentationType, params: { [k: string]: any } = {}): RepresentationElement {\n return this._addRepresentation(type, this.surface, params)\n }\n\n getBoxUntransformed (): Box3 {\n return this.surface.boundingBox\n }\n\n getCenterUntransformed (): Vector3 {\n return this.surface.center\n }\n\n dispose () {\n this.surface.dispose()\n super.dispose()\n }\n}\n\nComponentRegistry.add('surface', SurfaceComponent)\n\nexport default SurfaceComponent\n","/**\n * @file Volume Component\n * @author Alexander Rose \n * @private\n */\n\nimport { ComponentRegistry } from '../globals'\nimport Component, { ComponentParameters } from './component'\nimport Stage from '../stage/stage'\nimport Volume from '../surface/volume'\nimport { Box3, Vector3 } from 'three';\nimport RepresentationElement from './representation-element';\n\nexport type VolumeRepresentationType = 'surface'|'slice'|'dot'\n\n/**\n * Component wrapping a {@link Volume} object\n *\n * @example\n * // get a volume component by loading a volume file into the stage\n * stage.loadFile( \"url/for/volume\" ).then(function(volumeComponent){\n * volumeComponent.addRepresentation('surface');\n * volumeComponent.autoView();\n * });\n */\nclass VolumeComponent extends Component {\n /**\n * @param {Stage} stage - stage object the component belongs to\n * @param {Volume} volume - volume object to wrap\n * @param {ComponentParameters} params - component parameters\n */\n constructor (stage: Stage, readonly volume: Volume, params: Partial = {}) {\n super(stage, volume, Object.assign({ name: volume.name }, params))\n }\n\n /**\n * Component type\n * @type {String}\n */\n get type () { return 'volume' }\n\n /**\n * Add a new volume representation to the component\n */\n addRepresentation (type: VolumeRepresentationType, params: { [k: string]: any } = {}): RepresentationElement {\n return this._addRepresentation(type, this.volume, params)\n }\n\n getBoxUntransformed (): Box3 {\n return this.volume.boundingBox\n }\n\n getCenterUntransformed (): Vector3 {\n return this.volume.center\n }\n\n dispose () {\n this.volume.dispose()\n\n super.dispose()\n }\n}\n\nComponentRegistry.add('volume', VolumeComponent)\n\nexport default VolumeComponent\n","/**\n * @file Component Collection\n * @author Alexander Rose \n * @private\n */\n\nimport Component from './component'\nimport Collection from './collection'\n\nclass ComponentCollection extends Collection {\n addRepresentation (name: string, params: any) {\n \treturn this.forEach((comp) => comp.addRepresentation(name, params))\n }\n\n autoView (duration: number) {\n return this.forEach((comp) => comp.autoView(duration))\n }\n}\n\nexport default ComponentCollection\n","/**\n * @file Stage\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3, Box3 } from 'three'\nimport { Signal } from 'signals'\n\nimport {\n Debug, Log, Mobile, ComponentRegistry, ParserRegistry\n} from '../globals'\nimport { defaults, createParams, updateParams } from '../utils'\nimport { degToRad, clamp, pclamp } from '../math/math-utils'\nimport Counter from '../utils/counter'\nimport Viewer from '../viewer/viewer'\nimport { ImageParameters } from '../viewer/viewer-utils'\nimport MouseObserver from './mouse-observer'\n\nimport TrackballControls from '../controls/trackball-controls'\nimport PickingControls from '../controls/picking-controls'\nimport ViewerControls from '../controls/viewer-controls'\nimport AnimationControls from '../controls/animation-controls'\nimport MouseControls, { MouseControlPreset } from '../controls/mouse-controls'\nimport KeyControls from '../controls/key-controls'\n\nimport PickingBehavior from './picking-behavior'\nimport MouseBehavior from './mouse-behavior'\nimport AnimationBehavior from './animation-behavior'\nimport KeyBehavior from './key-behavior'\n\nimport Component, { ComponentParameters } from '../component/component'\nimport RepresentationElement from '../component/representation-element'\nimport StructureComponent from '../component/structure-component'\nimport SurfaceComponent from '../component/surface-component'\nimport VolumeComponent from '../component/volume-component'\nimport ComponentCollection from '../component/component-collection'\nimport RepresentationCollection from '../component/representation-collection'\nimport { autoLoad, getFileInfo, LoaderParameters } from '../loader/loader-utils'\nimport { ParserParams } from '../loader/parser-loader'\nimport AtomProxy from '../proxy/atom-proxy'\nimport Animation from '../animation/animation'\nimport Selection from '../selection/selection'\n\nimport Structure from '../structure/structure'\nimport Surface from '../surface/surface'\nimport Volume from '../surface/volume'\nimport Shape from '../geometry/shape'\nimport Script from '../script'\nimport { GenericColor } from '../types'\n\nfunction matchName (name: string|RegExp, object: { name: string }) {\n if (name instanceof RegExp) {\n return object.name.match(name) !== null\n } else {\n return object.name === name\n }\n}\n\nconst tmpZoomVector = new Vector3()\n\ndeclare global {\n interface Document {\n mozFullScreen: boolean\n mozFullScreenEnabled: boolean\n mozFullScreenElement: Element\n mozCancelFullScreen(): void\n\n msFullscreenEnabled: boolean\n msFullscreenElement: Element\n msExitFullscreen(): void\n }\n\n interface Element {\n mozRequestFullScreen(): void\n msRequestFullscreen(): void\n }\n}\n\n/**\n * Stage parameter object.\n * @typedef {Object} StageParameters - stage parameters\n * @property {Color} backgroundColor - background color\n * @property {Integer} sampleLevel - sampling level for antialiasing, between -1 and 5;\n * -1: no sampling, 0: only sampling when not moving\n * @property {Boolean} workerDefault - default value for useWorker parameter of representations\n * @property {Float} rotateSpeed - camera-controls rotation speed, between 0 and 10\n * @property {Float} zoomSpeed - camera-controls zoom speed, between 0 and 10\n * @property {Float} panSpeed - camera-controls pan speed, between 0 and 10\n * @property {Float} clipNear - position of camera near/front clipping plane\n * in percent of scene bounding box\n * @property {Float} clipFar - position of camera far/back clipping plane\n * in percent of scene bounding box\n * @property {Float} clipDist - camera clipping distance in Angstrom\n * @property {String} clipMode - how to interpret clipNear/Far and fogNear/Far values: \"scene\" for scene-relative, \"camera\" for camera-relative\n * @property {String} clipScale - \"relative\" or \"absolute\": interpret clipNear/Far and fogNear/Far as percentage of bounding box or absolute Angstroms (ignored when clipMode==camera)\n * @property {Float} fogNear - position of the start of the fog effect\n * in percent of scene bounding box\n * @property {Float} fogFar - position where the fog is in full effect\n * in percent of scene bounding box\n * @property {String} cameraType - type of camera, either 'persepective' or 'orthographic'\n * @property {Float} cameraFov - perspective camera field of view in degree, between 15 and 120\n * @property {Float} cameraEyeSep - stereo camera eye seperation\n * @property {Color} lightColor - point light color\n * @property {Float} lightIntensity - point light intensity\n * @property {Color} ambientColor - ambient light color\n * @property {Float} ambientIntensity - ambient light intensity\n * @property {Integer} hoverTimeout - timeout for hovering\n */\n\nexport interface StageSignals {\n parametersChanged: Signal\n fullscreenChanged: Signal\n componentAdded: Signal\n componentRemoved: Signal\n clicked: Signal\n hovered: Signal\n}\n\nexport type RenderQualityType = 'auto'|'low'|'medium'|'high'\n\nexport const StageDefaultParameters = {\n impostor: true,\n quality: 'medium' as RenderQualityType,\n workerDefault: true,\n sampleLevel: 0,\n backgroundColor: 'black' as GenericColor,\n rotateSpeed: 2.0,\n zoomSpeed: 1.2,\n panSpeed: 1.0,\n clipNear: 0,\n clipFar: 100,\n clipDist: 10,\n clipMode: 'scene',\n clipScale: 'relative',\n fogNear: 50,\n fogFar: 100,\n cameraFov: 40,\n cameraEyeSep: 0.3,\n cameraType: 'perspective' as 'perspective'|'orthographic'|'stereo',\n lightColor: 0xdddddd as GenericColor,\n lightIntensity: 1.2,\n ambientColor: 0xdddddd as GenericColor,\n ambientIntensity: 0.3,\n hoverTimeout: 0,\n tooltip: true,\n mousePreset: 'default' as MouseControlPreset\n}\nexport type StageParameters = typeof StageDefaultParameters\n\nexport interface StageLoadFileParams extends LoaderParameters {\n defaultRepresentation: boolean,\n assembly: string\n}\n\n/**\n * Stage class, central for creating molecular scenes with NGL.\n *\n * @example\n * var stage = new Stage( \"elementId\", { backgroundColor: \"white\" } );\n */\nclass Stage {\n signals: StageSignals = {\n parametersChanged: new Signal(),\n fullscreenChanged: new Signal(),\n componentAdded: new Signal(),\n componentRemoved: new Signal(),\n clicked: new Signal(),\n hovered: new Signal()\n }\n parameters: StageParameters\n\n /**\n * Counter that keeps track of various potentially long-running tasks,\n * including file loading and surface calculation.\n */\n tasks = new Counter()\n compList: Component[] = []\n defaultFileParams = {}\n logList: string[] = []\n\n transformComponent?: Component\n transformAtom?: AtomProxy\n\n viewer: Viewer\n tooltip: HTMLElement\n lastFullscreenElement: HTMLElement\n\n mouseObserver: MouseObserver\n viewerControls: ViewerControls\n trackballControls: TrackballControls\n pickingControls: PickingControls\n animationControls: AnimationControls\n mouseControls: MouseControls\n keyControls: KeyControls\n\n pickingBehavior: PickingBehavior\n mouseBehavior: MouseBehavior\n animationBehavior: AnimationBehavior\n keyBehavior: KeyBehavior\n\n spinAnimation: Animation\n rockAnimation: Animation\n\n constructor (idOrElement: string|HTMLElement, params: Partial = {}) {\n this.viewer = new Viewer(idOrElement)\n if (!this.viewer.renderer) return\n\n this.tooltip = document.createElement('div')\n Object.assign(this.tooltip.style, {\n display: 'none',\n position: 'fixed',\n zIndex: '1000000',\n pointerEvents: 'none',\n backgroundColor: 'rgba( 0, 0, 0, 0.6 )',\n color: 'lightgrey',\n padding: '8px',\n fontFamily: 'sans-serif'\n })\n this.viewer.container.appendChild(this.tooltip)\n\n this.mouseObserver = new MouseObserver(this.viewer.renderer.domElement)\n this.viewerControls = new ViewerControls(this)\n this.trackballControls = new TrackballControls(this)\n this.pickingControls = new PickingControls(this)\n this.animationControls = new AnimationControls(this)\n this.mouseControls = new MouseControls(this)\n this.keyControls = new KeyControls(this)\n\n this.pickingBehavior = new PickingBehavior(this)\n this.mouseBehavior = new MouseBehavior(this)\n this.animationBehavior = new AnimationBehavior(this)\n this.keyBehavior = new KeyBehavior(this)\n\n this.spinAnimation = this.animationControls.spin([ 0, 1, 0 ], 0.005)\n this.spinAnimation.pause(true)\n this.rockAnimation = this.animationControls.rock([ 0, 1, 0 ], 0.005)\n this.rockAnimation.pause(true)\n\n // must come after the viewer has been instantiated\n this.parameters = createParams(params, StageDefaultParameters)\n this.setParameters(this.parameters)\n\n this.viewer.animate()\n }\n\n /**\n * Set stage parameters\n */\n setParameters (params: Partial = {}) {\n updateParams(this.parameters, params)\n\n const p = params\n const tp = this.parameters\n\n const viewer = this.viewer\n const controls = this.trackballControls\n\n // apply parameters\n if (p.quality !== undefined) this.setQuality(tp.quality)\n if (p.impostor !== undefined) this.setImpostor(tp.impostor)\n if (p.rotateSpeed !== undefined) controls.rotateSpeed = tp.rotateSpeed\n if (p.zoomSpeed !== undefined) controls.zoomSpeed = tp.zoomSpeed\n if (p.panSpeed !== undefined) controls.panSpeed = tp.panSpeed\n if (p.mousePreset !== undefined) this.mouseControls.preset(tp.mousePreset)\n this.mouseObserver.setParameters({ hoverTimeout: tp.hoverTimeout })\n viewer.setClip(tp.clipNear, tp.clipFar, tp.clipDist, tp.clipMode, tp.clipScale)\n viewer.setFog(undefined, tp.fogNear, tp.fogFar)\n viewer.setCamera(tp.cameraType, tp.cameraFov, tp.cameraEyeSep)\n viewer.setSampling(tp.sampleLevel)\n viewer.setBackground(tp.backgroundColor)\n viewer.setLight(tp.lightColor, tp.lightIntensity, tp.ambientColor, tp.ambientIntensity)\n\n this.signals.parametersChanged.dispatch(this.getParameters())\n\n return this\n }\n\n log (msg: string) {\n console.log('STAGE LOG', msg)\n this.logList.push(msg)\n }\n\n /**\n * Get stage parameters\n */\n getParameters () {\n return Object.assign({}, this.parameters)\n }\n\n /**\n * Create default representations for the given component\n * @param {StructureComponent|SurfaceComponent} object - component to create the representations for\n * @return {undefined}\n */\n defaultFileRepresentation (component: Component) {\n if (component instanceof StructureComponent) {\n component.setSelection('/0')\n\n let atomCount, residueCount, instanceCount\n const structure = component.structure\n\n if (structure.biomolDict.BU1) {\n const assembly = structure.biomolDict.BU1\n atomCount = assembly.getAtomCount(structure)\n residueCount = assembly.getResidueCount(structure)\n instanceCount = assembly.getInstanceCount()\n component.setDefaultAssembly('BU1')\n } else {\n atomCount = structure.getModelProxy(0).atomCount\n residueCount = structure.getModelProxy(0).residueCount\n instanceCount = 1\n }\n\n let sizeScore = atomCount\n\n if (Mobile) {\n sizeScore *= 4\n }\n\n const backboneOnly = structure.atomStore.count / structure.residueStore.count < 2\n if (backboneOnly) {\n sizeScore *= 10\n }\n\n let colorScheme = 'chainname'\n let colorScale = 'RdYlBu'\n let colorReverse = false\n if (structure.getChainnameCount(new Selection('polymer and /0')) === 1) {\n colorScheme = 'residueindex'\n colorScale = 'Spectral'\n colorReverse = true\n }\n\n if (Debug) console.log(sizeScore, atomCount, instanceCount, backboneOnly)\n\n if (residueCount / instanceCount < 4) {\n component.addRepresentation('ball+stick', {\n colorScheme: 'element',\n radiusScale: 2.0,\n aspectRatio: 1.5,\n bondScale: 0.3,\n bondSpacing: 0.75,\n quality: 'auto'\n })\n } else if ((instanceCount > 5 && sizeScore > 15000) || sizeScore > 700000) {\n let scaleFactor = (\n Math.min(\n 2.0,\n Math.max(\n 0.1,\n 6000 / (sizeScore / instanceCount)\n )\n )\n )\n if (backboneOnly) scaleFactor = Math.min(scaleFactor, 0.5)\n\n component.addRepresentation('surface', {\n colorScheme, colorScale, colorReverse,\n sele: 'polymer',\n surfaceType: 'av',\n probeRadius: 1.4,\n scaleFactor: scaleFactor,\n useWorker: false\n })\n } else if (sizeScore > 250000) {\n component.addRepresentation('backbone', {\n colorScheme, colorScale, colorReverse,\n lineOnly: true\n })\n } else if (sizeScore > 100000) {\n component.addRepresentation('backbone', {\n colorScheme, colorScale, colorReverse,\n quality: 'low',\n disableImpostor: true,\n radiusScale: 2.0\n })\n } else if (sizeScore > 80000) {\n component.addRepresentation('backbone', {\n colorScheme, colorScale, colorReverse,\n radiusScale: 2.0\n })\n } else {\n component.addRepresentation('cartoon', {\n colorScheme, colorScale, colorReverse,\n radiusScale: 0.7,\n aspectRatio: 5,\n quality: 'auto'\n })\n if (sizeScore < 50000) {\n component.addRepresentation('base', {\n colorScheme, colorScale, colorReverse,\n quality: 'auto'\n })\n }\n component.addRepresentation('ball+stick', {\n sele: 'ligand',\n colorScheme: 'element',\n radiusScale: 2.0,\n aspectRatio: 1.5,\n bondScale: 0.3,\n bondSpacing: 0.75,\n quality: 'auto'\n })\n }\n\n // add frames as trajectory\n if (component.structure.frames.length) {\n component.addTrajectory()\n }\n } else if (component instanceof SurfaceComponent) {\n component.addRepresentation('surface')\n } else if (component instanceof VolumeComponent) {\n component.addRepresentation('surface')\n }\n\n this.tasks.onZeroOnce(this.autoView, this)\n }\n\n /**\n * Load a file onto the stage\n *\n * @example\n * // load from URL\n * stage.loadFile( \"http://files.rcsb.org/download/5IOS.cif\" );\n *\n * @example\n * // load binary data in CCP4 format via a Blob\n * var binaryBlob = new Blob( [ ccp4Data ], { type: 'application/octet-binary'} );\n * stage.loadFile( binaryBlob, { ext: \"ccp4\" } );\n *\n * @example\n * // load string data in PDB format via a Blob\n * var stringBlob = new Blob( [ pdbData ], { type: 'text/plain'} );\n * stage.loadFile( stringBlob, { ext: \"pdb\" } );\n *\n * @example\n * // load a File object\n * stage.loadFile( file );\n *\n * @example\n * // load from URL and add a 'ball+stick' representation with double/triple bonds\n * stage.loadFile( \"http://files.rcsb.org/download/1crn.cif\" ).then( function( comp ){\n * comp.addRepresentation( \"ball+stick\", { multipleBond: true } );\n * } );\n *\n * @param {String|File|Blob} path - either a URL or an object containing the file data\n * @param {LoaderParameters} params - loading parameters\n * @param {Boolean} params.asTrajectory - load multi-model structures as a trajectory\n * @return {Promise} A Promise object that resolves to a {@link StructureComponent},\n * a {@link SurfaceComponent} or a {@link ScriptComponent} object,\n * depending on the type of the loaded file.\n */\n loadFile (path: string|File|Blob, params: Partial = {}) {\n const p = Object.assign({}, this.defaultFileParams, params)\n const name = getFileInfo(path).name\n\n this.tasks.increment()\n this.log(`loading file '${name}'`)\n\n const onLoadFn = (object: Structure|Surface|Volume) => {\n this.log(`loaded '${name}'`)\n\n const component = this.addComponentFromObject(object, p)\n if (p.defaultRepresentation) {\n this.defaultFileRepresentation(component as Component)\n }\n this.tasks.decrement()\n\n return component\n }\n\n const onErrorFn = (e: Error|string) => {\n this.tasks.decrement()\n const errorMsg = `error loading file: '${e}'`\n this.log(errorMsg)\n throw errorMsg // throw so it can be catched\n }\n\n const ext = defaults(p.ext, getFileInfo(path).ext)\n let promise: Promise\n\n if (ParserRegistry.isTrajectory(ext)) {\n promise = Promise.reject(\n new Error(`loadFile: ext '${ext}' is a trajectory and must be loaded into a structure component`)\n )\n } else {\n promise = autoLoad(path, p)\n }\n\n return promise.then(onLoadFn, onErrorFn)\n }\n\n loadScript (path: string|File|Blob) {\n const name = getFileInfo(path).name\n\n this.log(`loading script '${name}'`)\n\n return autoLoad(path).then(\n (script: Script) => {\n this.tasks.increment()\n this.log(`running script '${name}'`)\n script.run(this).then(() => {\n this.tasks.decrement()\n this.log(`finished script '${name}'`)\n })\n this.log(`called script '${name}'`)\n },\n (error: Error|string) => {\n this.tasks.decrement()\n const errorMsg = `errored script '${name}' \"${error}\"`\n this.log(errorMsg)\n throw errorMsg // throw so it can be catched\n }\n )\n }\n\n /**\n * Add the given component to the stage\n * @param {Component} component - the component to add\n * @return {undefined}\n */\n addComponent (component: Component) {\n if (!component) {\n Log.warn('Stage.addComponent: no component given')\n return\n }\n\n this.compList.push(component)\n this.signals.componentAdded.dispatch(component)\n }\n\n /**\n * Create a component from the given object and add to the stage\n */\n addComponentFromObject (object: Structure|Surface|Volume|Shape, params: Partial = {}): void|Component {\n const CompClass = ComponentRegistry.get(object.type)\n\n if (CompClass) {\n const component = new CompClass(this, object, params)\n this.addComponent(component)\n return component\n }\n\n Log.warn('no component for object type', object.type)\n }\n\n /**\n * Remove the given component\n * @param {Component} component - the component to remove\n * @return {undefined}\n */\n removeComponent (component: Component) {\n const idx = this.compList.indexOf(component)\n if (idx !== -1) {\n this.compList.splice(idx, 1)\n component.dispose()\n this.signals.componentRemoved.dispatch(component)\n }\n }\n\n /**\n * Remove all components from the stage\n */\n removeAllComponents () {\n this.compList.slice().forEach(o => this.removeComponent(o))\n }\n\n /**\n * Handle any size-changes of the container element\n * @return {undefined}\n */\n handleResize () {\n this.viewer.handleResize()\n }\n\n /**\n * Set width and height\n * @param {String} width - CSS width value\n * @param {String} height - CSS height value\n * @return {undefined}\n */\n setSize (width: string, height: string) {\n const container = this.viewer.container\n\n if (container !== document.body) {\n if (width !== undefined) container.style.width = width\n if (height !== undefined) container.style.height = height\n this.handleResize()\n }\n }\n\n /**\n * Toggle fullscreen\n * @param {Element} [element] - document element to put into fullscreen,\n * defaults to the viewer container\n * @return {undefined}\n */\n toggleFullscreen (element: HTMLElement) {\n if (!document.fullscreenEnabled && !document.mozFullScreenEnabled &&\n !(document as any).webkitFullscreenEnabled && !document.msFullscreenEnabled\n ) {\n Log.log('fullscreen mode (currently) not possible')\n return\n }\n\n const self = this\n element = element || this.viewer.container\n this.lastFullscreenElement = element\n\n //\n\n function getFullscreenElement () {\n return document.fullscreenElement || document.mozFullScreenElement ||\n (document as any).webkitFullscreenElement || document.msFullscreenElement\n }\n\n function resizeElement () {\n if (!getFullscreenElement() && self.lastFullscreenElement) {\n const element = self.lastFullscreenElement\n element.style.width = element.dataset.normalWidth || ''\n element.style.height = element.dataset.normalHeight || ''\n\n document.removeEventListener('fullscreenchange', resizeElement)\n document.removeEventListener('mozfullscreenchange', resizeElement)\n document.removeEventListener('webkitfullscreenchange', resizeElement)\n document.removeEventListener('MSFullscreenChange', resizeElement)\n\n self.handleResize()\n self.signals.fullscreenChanged.dispatch(false)\n }\n }\n\n //\n\n if (!getFullscreenElement()) {\n element.dataset.normalWidth = element.style.width || ''\n element.dataset.normalHeight = element.style.height || ''\n element.style.width = window.screen.width + 'px'\n element.style.height = window.screen.height + 'px'\n\n if (element.requestFullscreen) {\n element.requestFullscreen()\n } else if (element.msRequestFullscreen) {\n element.msRequestFullscreen()\n } else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen()\n } else if ((element as any).webkitRequestFullscreen) {\n (element as any).webkitRequestFullscreen()\n }\n\n document.addEventListener('fullscreenchange', resizeElement)\n document.addEventListener('mozfullscreenchange', resizeElement)\n document.addEventListener('webkitfullscreenchange', resizeElement)\n document.addEventListener('MSFullscreenChange', resizeElement)\n\n this.handleResize()\n this.signals.fullscreenChanged.dispatch(true)\n\n // workaround for Safari\n setTimeout(function () { self.handleResize() }, 100)\n } else {\n if (document.exitFullscreen) {\n document.exitFullscreen()\n } else if (document.msExitFullscreen) {\n document.msExitFullscreen()\n } else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen()\n } else if ((document as any).webkitExitFullscreen) {\n (document as any).webkitExitFullscreen()\n }\n }\n }\n\n /**\n * Set spin\n * @param {Boolean} flag - if true start rocking and stop spinning\n * @return {undefined}\n */\n setSpin (flag: boolean) {\n if (flag) {\n this.spinAnimation.resume(true)\n this.rockAnimation.pause(true)\n } else {\n this.spinAnimation.pause(true)\n }\n }\n\n /**\n * Set rock\n * @param {Boolean} flag - if true start rocking and stop spinning\n * @return {undefined}\n */\n setRock (flag: boolean) {\n if (flag) {\n this.rockAnimation.resume(true)\n this.spinAnimation.pause(true)\n } else {\n this.rockAnimation.pause(true)\n }\n }\n\n /**\n * Toggle spin\n * @return {undefined}\n */\n toggleSpin () {\n this.setSpin(this.spinAnimation.paused)\n }\n\n /**\n * Toggle rock\n * @return {undefined}\n */\n toggleRock () {\n this.setRock(this.rockAnimation.paused)\n }\n\n /**\n * Get the current focus from the current clipNear value expressed\n * as 0 (full view) to 100 (completely clipped)\n * Negative values may be returned in some cases.\n *\n * In 'camera' clipMode focus isn't applicable, this method returns 0.0\n *\n * @return {number} focus\n */\n getFocus () : number {\n const p = this.parameters\n if (p.clipMode !== 'scene') return 0.0\n\n let clipNear = p.clipNear\n if (p.clipScale === 'absolute') {\n clipNear = this.viewer.absoluteToRelative(clipNear)\n }\n return clipNear * 2\n }\n\n\n /**\n * Set the focus, a value of 0 sets clipping planes to show full scene,\n * while a value of 100 will compltely clip the scene.\n *\n * @param {number} value focus\n */\n setFocus (value: number) {\n if (this.parameters.clipMode !== 'scene') return\n\n let clipNear\n let clipFar\n let fogNear\n let fogFar\n\n if (this.parameters.clipScale === 'relative') {\n clipNear = clamp(value / 2.0, 0.0, 49.9)\n clipFar = 100 - clipNear\n fogNear = 50\n fogFar = pclamp(2 * clipFar - 50)\n\n } else {\n clipNear = this.viewer.relativeToAbsolute(value / 2.0)\n clipFar = clipNear\n fogNear = 0\n fogFar = 2 * clipFar\n }\n\n this.setParameters({ clipNear, clipFar, fogNear, fogFar })\n }\n\n getZoomForBox (boundingBox: Box3) {\n const bbSize = boundingBox.getSize(tmpZoomVector)\n const maxSize = Math.max(bbSize.x, bbSize.y, bbSize.z)\n const minSize = Math.min(bbSize.x, bbSize.y, bbSize.z)\n let distance = maxSize + Math.sqrt(minSize)\n\n const fov = degToRad(this.viewer.perspectiveCamera.fov)\n const width = this.viewer.width\n const height = this.viewer.height\n const aspect = width / height\n const aspectFactor = (height < width ? 1 : aspect)\n\n distance = Math.abs(\n ((distance * 0.5) / aspectFactor) / Math.sin(fov / 2)\n )\n distance += this.parameters.clipDist\n return -distance\n }\n\n getBox () {\n return this.viewer.boundingBox\n }\n\n getZoom () {\n return this.getZoomForBox(this.getBox())\n }\n\n getCenter (optionalTarget?: Vector3) {\n return this.getBox().getCenter(optionalTarget || new Vector3())\n }\n\n /**\n * Add a zoom and a move animation with automatic targets\n * @param {Integer} duration - animation time in milliseconds\n * @return {undefined}\n */\n autoView (duration?: number) {\n this.animationControls.zoomMove(\n this.getCenter(),\n this.getZoom(),\n defaults(duration, 0)\n )\n }\n\n /**\n * Make image from what is shown in a viewer canvas\n */\n makeImage (params: Partial = {}) {\n return new Promise((resolve, reject) => {\n this.tasks.onZeroOnce(() => {\n this.tasks.increment()\n this.viewer.makeImage(params).then(blob => {\n this.tasks.decrement()\n resolve(blob)\n }).catch(e => {\n this.tasks.decrement()\n reject(e)\n })\n })\n })\n }\n\n setImpostor (value: boolean) {\n this.parameters.impostor = value\n\n const types = [\n 'spacefill', 'ball+stick', 'licorice', 'hyperball',\n 'backbone', 'rocket', 'helixorient', 'contact', 'distance',\n 'dot'\n ]\n\n this.eachRepresentation(function (reprElem) {\n if (!types.includes(reprElem.getType())) return\n\n const p = reprElem.getParameters() as any // TODO\n p.disableImpostor = !value\n reprElem.build(p)\n })\n }\n\n setQuality (value: RenderQualityType) {\n this.parameters.quality = value\n\n const types = [\n 'tube', 'cartoon', 'ribbon', 'trace', 'rope'\n ]\n\n const impostorTypes = [\n 'spacefill', 'ball+stick', 'licorice', 'hyperball',\n 'backbone', 'rocket', 'helixorient', 'contact', 'distance',\n 'dot'\n ]\n\n this.eachRepresentation(function (repr) {\n const p = repr.getParameters() as any // TODO\n\n if (!types.includes(repr.getType())) {\n if (!impostorTypes.includes(repr.getType())) return\n\n if (!p.disableImpostor) {\n (repr.repr as any).quality = value // TODO\n return\n }\n }\n\n p.quality = value\n repr.build(p)\n })\n }\n\n /**\n * Iterator over each component and executing the callback\n */\n eachComponent (callback: (comp: Component) => void, type?: string) {\n this.compList.slice().forEach(comp => {\n if (type === undefined || type === comp.type) callback(comp)\n })\n }\n\n /**\n * Iterator over each representation and executing the callback\n */\n eachRepresentation (callback: (reprElem: RepresentationElement, comp: Component) => void, type?: string) {\n this.eachComponent(comp => {\n comp.reprList.slice().forEach(reprElem => {\n if (type === undefined || type === reprElem.getType()) callback(reprElem, comp)\n })\n })\n }\n\n /**\n * Get collection of components by name\n */\n getComponentsByName (name: string|RegExp) {\n const compList: Component[] = []\n\n this.eachComponent(comp => {\n if (name === undefined || matchName(name, comp)) compList.push(comp)\n })\n\n return new ComponentCollection(compList)\n }\n\n /**\n * Get collection of components by object\n */\n getComponentsByObject (object: Structure|Surface|Volume|Shape) {\n const compList: Component[] = []\n\n this.eachComponent(comp => {\n if (comp.object === object) compList.push(comp)\n })\n\n return new ComponentCollection(compList)\n }\n\n /**\n * Get collection of representations by name\n */\n getRepresentationsByName (name: string|RegExp) {\n const reprList: RepresentationElement[] = []\n\n this.eachRepresentation((repr, comp) => {\n if (name === undefined || matchName(name, repr)) reprList.push(repr)\n })\n\n return new RepresentationCollection(reprList)\n }\n\n measureClear () {\n this.eachComponent((sc: StructureComponent) => sc.measureClear(), 'structure')\n }\n\n measureUpdate () {\n this.eachComponent((sc: StructureComponent) => sc.measureUpdate(), 'structure')\n }\n\n /**\n * Cleanup when disposing of a stage object\n */\n dispose () {\n this.tasks.dispose()\n this.viewer.dispose()\n this.mouseObserver.dispose()\n }\n}\n\nexport default Stage\n","/**\n * @file Shape Component\n * @author Alexander Rose \n * @private\n */\n\nimport { ComponentRegistry } from '../globals'\nimport Component, { ComponentParameters } from './component'\nimport Stage from '../stage/stage'\nimport Shape from '../geometry/shape'\nimport { Vector3, Box3 } from 'three';\nimport RepresentationElement from './representation-element';\n\nexport type ShapeRepresentationType = 'buffer'\n\n/**\n * Component wrapping a {@link Shape} object\n *\n * @example\n * // get a shape component by adding a shape object to the stage\n * var shape = new NGL.Shape( \"shape\" );\n * shape.addSphere( [ 0, 0, 0 ], [ 1, 0, 0 ], 1.5 );\n * var shapeComponent = stage.addComponentFromObject( shape );\n * shapeComponent.addRepresentation( \"buffer\" );\n */\nclass ShapeComponent extends Component {\n constructor (stage: Stage, readonly shape: Shape, params: Partial = {}) {\n super(stage, shape, Object.assign({ name: shape.name }, params))\n }\n\n /**\n * Component type\n * @type {String}\n */\n get type () { return 'shape' }\n\n /**\n * Add a new shape representation to the component\n * @param {String} type - the name of the representation, one of:\n * buffer.\n * @param {BufferRepresentationParameters} params - representation parameters\n * @return {RepresentationComponent} the created representation wrapped into\n * a representation component object\n */\n addRepresentation (type: ShapeRepresentationType, params: { [k: string]: any } = {}): RepresentationElement {\n return this._addRepresentation(type, this.shape, params)\n }\n\n getBoxUntransformed (): Box3 {\n return this.shape.boundingBox\n }\n\n getCenterUntransformed (): Vector3 {\n return this.shape.center\n }\n\n dispose () {\n this.shape.dispose()\n super.dispose()\n }\n}\n\nComponentRegistry.add('shape', ShapeComponent)\n\nexport default ShapeComponent\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","/**\n * @file Atomindex Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ModelProxy from '../proxy/model-proxy'\n\n/**\n * Color by atom index. The {@link AtomProxy.index} property is used for coloring.\n * Each {@link ModelProxy} of a {@link Structure} is colored seperately. The\n * `params.domain` parameter is ignored.\n *\n * __Name:__ _atomindex_\n *\n * @example\n * stage.loadFile( \"rcsb://1crn\" ).then( function( o ){\n * o.addRepresentation( \"ball+stick\", { colorScheme: \"atomindex\" } );\n * o.autoView();\n * } );\n */\nclass AtomindexColormaker extends Colormaker {\n scalePerModel: { [k: number]: ColormakerScale }\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'rainbow'\n this.parameters.reverse = defaults(params.reverse, true)\n }\n\n this.scalePerModel = {}\n\n params.structure.eachModel((mp: ModelProxy) => {\n this.parameters.domain = [ mp.atomOffset, mp.atomEnd ]\n this.scalePerModel[ mp.index ] = this.getScale() // TODO\n })\n }\n\n /**\n * get color for an atom\n * @param {AtomProxy} atom - atom to get color for\n * @return {Integer} hex atom color\n */\n @manageColor\n atomColor (atom: AtomProxy) {\n return this.scalePerModel[ atom.modelIndex ](atom.index)\n }\n}\n\nColormakerRegistry.add('atomindex', AtomindexColormaker)\n\nexport default AtomindexColormaker\n","/**\n * @file Bfactor Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport Selection from '../selection/selection'\n\n/**\n * Color by b-factor. The {@link AtomProxy.bfactor} property is used for coloring.\n * By default the min and max b-factor values are used for the scale`s domain.\n *\n * __Name:__ _bfactor_\n *\n * @example\n * stage.loadFile( \"rcsb://1crn\" ).then( function( o ){\n * o.addRepresentation( \"ball+stick\", { colorScheme: \"bfactor\" } );\n * o.autoView();\n * } );\n */\nclass BfactorColormaker extends Colormaker {\n bfactorScale: ColormakerScale\n\n constructor (params: { sele?: string } & StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'OrRd'\n }\n\n if (!params.domain) {\n let selection\n let min = Infinity\n let max = -Infinity\n\n if (params.sele) {\n selection = new Selection(params.sele)\n }\n\n params.structure.eachAtom(function (a) {\n const bfactor = a.bfactor\n min = Math.min(min, bfactor)\n max = Math.max(max, bfactor)\n }, selection)\n\n this.parameters.domain = [ min, max ]\n }\n\n this.bfactorScale = this.getScale()\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.bfactorScale(a.bfactor)\n }\n}\n\nColormakerRegistry.add('bfactor', BfactorColormaker)\n\nexport default BfactorColormaker\n","/**\n * @file Chainid Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ChainProxy from '../proxy/chain-proxy'\nimport ModelProxy from '../proxy/model-proxy'\n\nexport type ChainidDict = { [k: string]: number }\n\n/**\n * Color by chain id\n */\nclass ChainidColormaker extends Colormaker {\n chainidDictPerModel: { [k: number]: ChainidDict } = {}\n scalePerModel: { [k: number]: ColormakerScale } = {}\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'Spectral'\n }\n\n params.structure.eachModel((mp: ModelProxy) => {\n let i = 0\n const chainidDict: ChainidDict = {}\n mp.eachChain(function (cp: ChainProxy) {\n if (chainidDict[ cp.chainid ] === undefined) {\n chainidDict[ cp.chainid ] = i\n i += 1\n }\n })\n this.parameters.domain = [ 0, i - 1 ]\n this.chainidDictPerModel[ mp.index ] = chainidDict\n this.scalePerModel[ mp.index ] = this.getScale()\n })\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n const chainidDict = this.chainidDictPerModel[ a.modelIndex ]\n return this.scalePerModel[ a.modelIndex ](chainidDict[ a.chainid ])\n }\n}\n\nColormakerRegistry.add('chainid', ChainidColormaker)\n\nexport default ChainidColormaker\n","/**\n * @file Chainindex Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ModelProxy from '../proxy/model-proxy'\n\n/**\n * Color by chain index\n */\nclass ChainindexColormaker extends Colormaker {\n scalePerModel: { [k: number]: ColormakerScale } = {}\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'Spectral'\n }\n\n params.structure.eachModel((mp: ModelProxy) => {\n this.parameters.domain = [ mp.chainOffset, mp.chainEnd ]\n this.scalePerModel[ mp.index ] = this.getScale()\n })\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.scalePerModel[ a.modelIndex ](a.chainIndex)\n }\n}\n\nColormakerRegistry.add('chainindex', ChainindexColormaker)\n\nexport default ChainindexColormaker\n","/**\n * @file Chainname Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ChainProxy from '../proxy/chain-proxy'\nimport ModelProxy from '../proxy/model-proxy'\n\nexport type ChainnameDict = { [k: string]: number }\n\n/**\n * Color by chain name\n */\nclass ChainnameColormaker extends Colormaker {\n chainnameDictPerModel: { [k: number]: ChainnameDict } = {}\n scalePerModel: { [k: number]: ColormakerScale } = {}\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'Spectral'\n }\n\n params.structure.eachModel((mp: ModelProxy) => {\n let i = 0\n const chainnameDict: ChainnameDict = {}\n mp.eachChain(function (cp: ChainProxy) {\n if (chainnameDict[ cp.chainname ] === undefined) {\n chainnameDict[ cp.chainname ] = i\n i += 1\n }\n })\n this.parameters.domain = [ 0, i - 1 ]\n this.chainnameDictPerModel[ mp.index ] = chainnameDict\n this.scalePerModel[ mp.index ] = this.getScale()\n })\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n const chainnameDict = this.chainnameDictPerModel[ a.modelIndex ]\n return this.scalePerModel[ a.modelIndex ](chainnameDict[ a.chainname ])\n }\n}\n\nColormakerRegistry.add('chainname', ChainnameColormaker)\n\nexport default ChainnameColormaker\n","/**\n * @file Densityfit Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Color by validation density fit\n */\nclass DensityfitColormaker extends Colormaker {\n rsrzScale: ColormakerScale\n rsccScale: ColormakerScale\n\n rsrzDict: { [k: string]: number|undefined } = {}\n rsccDict: { [k: string]: number|undefined } = {}\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'RdYlBu'\n }\n\n this.rsrzScale = this.getScale({ domain: [ 2, 0 ] })\n this.rsccScale = this.getScale({ domain: [ 0.678, 1.0 ] })\n\n const val = params.structure.validation\n if (val) {\n this.rsrzDict = val.rsrzDict\n this.rsccDict = val.rsccDict\n }\n\n }\n\n @manageColor\n atomColor (atom: AtomProxy) {\n let sele = atom.resno + ''\n if (atom.inscode) sele += '^' + atom.inscode\n if (atom.chainname) sele += ':' + atom.chainname\n sele += '/' + atom.modelIndex\n\n const rsrz = this.rsrzDict[ sele ]\n if (rsrz !== undefined) {\n return this.rsrzScale(rsrz)\n }\n\n const rscc = this.rsccDict[ sele ]\n if (rscc !== undefined) {\n return this.rsccScale(rscc)\n }\n\n return 0x909090\n }\n}\n\nColormakerRegistry.add('densityfit', DensityfitColormaker)\n\nexport default DensityfitColormaker\n","/**\n * @file Atomindex Colormaker\n * @author Fred Ludlow \n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport SpatialHash from '../geometry/spatial-hash'\n\n// from CHARMM\nconst partialCharges: { [k: string]: { [k: string]: number } } = {\n 'ARG': {\n 'CD': 0.1,\n 'CZ': 0.5,\n 'NE': -0.1\n },\n 'ASN': {\n 'CG': 0.55,\n 'OD1': -0.55\n },\n 'ASP': {\n 'CB': -0.16,\n 'CG': 0.36,\n 'OD1': -0.6,\n 'OD2': -0.6\n },\n 'CYS': {\n 'CB': 0.19,\n 'SG': -0.19\n },\n 'GLN': {\n 'CD': 0.55,\n 'OE1': -0.55\n },\n 'GLU': {\n 'CD': 0.36,\n 'CG': -0.16,\n 'OE1': -0.6,\n 'OE2': -0.6\n },\n 'HIS': {\n 'CB': 0.1,\n 'CD2': 0.2,\n 'CE1': 0.45,\n 'CG': 0.15,\n 'ND1': 0.05,\n 'NE2': 0.05\n },\n 'LYS': {\n 'CE': 0.25,\n 'NZ': 0.75\n },\n 'MET': {\n 'CE': 0.06,\n 'CG': 0.06,\n 'SD': -0.12\n },\n 'PTR': {\n 'C': 0.55,\n 'CA': 0.1,\n 'CZ': 0.25,\n 'N': -0.35,\n 'O': -0.55,\n 'O1P': -0.85,\n 'O2P': -0.85,\n 'O3P': -0.85,\n 'OG1': -1.1,\n 'P': 1.4\n },\n 'SEP': {\n 'C': 0.55,\n 'CA': 0.1,\n 'CB': 0.25,\n 'N': -0.35,\n 'O': -0.55,\n 'O1P': -0.85,\n 'O2P': -0.85,\n 'O3P': -0.85,\n 'OG1': -1.1,\n 'P': 1.4\n },\n 'SER': {\n 'CB': 0.25,\n 'OG': -0.25\n },\n 'THR': {\n 'CB': 0.25,\n 'OG1': -0.25\n },\n 'TPO': {\n 'C': 0.55,\n 'CA': 0.1,\n 'CB': 0.25,\n 'N': -0.35,\n 'O': -0.55,\n 'OG1': -1.1,\n 'O1P': -0.85,\n 'O2P': -0.85,\n 'O3P': -0.85,\n 'P': 1.4\n },\n 'TRP': {\n 'CD1': 0.06,\n 'CD2': 0.1,\n 'CE2': -0.04,\n 'CE3': -0.03,\n 'CG': -0.03,\n 'NE1': -0.06\n },\n 'TYR': {\n 'CZ': 0.25,\n 'OH': -0.25\n },\n 'backbone': {\n 'C': 0.55,\n 'O': -0.55,\n 'N': -0.35,\n 'CA': 0.1\n }\n}\n\nconst maxRadius = 12.0\nconst nHBondDistance = 1.04\nconst nHCharge = 0.25\n\n/**\n * Populates position vector with location of implicit or explicit H\n * Returns position or undefined if not able to locate H\n *\n * @param {AtomProxy} ap - the nitrogen atom\n * @param {Vector3} [position] - optional target\n * @return {Vectors|undefined} the hydrogen atom position\n */\nfunction backboneNHPosition (ap: AtomProxy, position = new Vector3()) {\n let h = false\n let ca = false\n let c = false\n position.set(2 * ap.x, 2 * ap.y, 2 * ap.z)\n\n ap.eachBondedAtom(function (a2: AtomProxy) {\n // Any time we detect H, reset position and skip\n // future tests\n if (h) return\n if (a2.atomname === 'H') {\n position.set(a2.x, a2.y, a2.z)\n h = true\n return\n }\n if (!ca && a2.atomname === 'CA') {\n position.sub(a2 as any) // TODO\n ca = true\n } else if (!c && a2.atomname === 'C') {\n c = true\n position.sub(a2 as any) // TODO\n }\n })\n\n if (h) { return position }\n\n if (ca && c) {\n position.normalize()\n position.multiplyScalar(nHBondDistance)\n position.add(ap as any)\n return position\n }\n}\n\n/**\n * Takes an array of Vector3 objects and\n * converts to an object that looks like an AtomStore\n *\n * @param {Vector3[]} positions - array of positions\n * @return {Object} AtomStore-like object\n */\nfunction buildStoreLike (positions: Vector3[]) {\n const n = positions.length\n const x = new Float32Array(n)\n const y = new Float32Array(n)\n const z = new Float32Array(n)\n\n for (let i = 0; i < positions.length; i++) {\n const v = positions[ i ]\n x[ i ] = v.x\n y[ i ] = v.y\n z[ i ] = v.z\n }\n\n return { x: x, y: y, z: z, count: n }\n}\n\nfunction chargeForAtom (a: AtomProxy): number {\n if (a.partialCharge !== null) return a.partialCharge\n if (!a.isProtein()) { return 0.0 }\n return (\n (partialCharges[ a.resname ] &&\n partialCharges[ a.resname ][ a.atomname ]) ||\n partialCharges[ 'backbone' ][ a.atomname ] || 0.0\n )\n}\n\n/**\n * Color a surface by electrostatic charge. This is a highly approximate\n * calculation! The partial charges are CHARMM with hydrogens added to heavy\n * atoms and hydrogen positions generated for amides.\n *\n * __Name:__ _electrostatic_\n *\n * @example\n * stage.loadFile( \"rcsb://3dqb\" ).then( function( o ){\n * o.addRepresentation( \"surface\", { colorScheme: \"electrostatic\" } );\n * o.autoView();\n * } );\n */\nclass ElectrostaticColormaker extends Colormaker {\n scale: ColormakerScale\n hHash: SpatialHash\n hash: SpatialHash\n charges: Float32Array\n hStore: { x: Float32Array, y: Float32Array, z: Float32Array, count: number }\n atomProxy: AtomProxy\n\n delta = new Vector3()\n hCharges: number[] = []\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'rwb'\n }\n if (!params.domain) {\n this.parameters.domain = [ -50, 50 ]\n }\n\n this.scale = this.getScale()\n\n this.charges = new Float32Array(params.structure.atomCount)\n const hPositions: Vector3[] = []\n\n params.structure.eachAtom((ap: AtomProxy) => {\n this.charges[ ap.index ] = chargeForAtom(ap) * ap.occupancy\n if (ap.atomname === 'N') {\n\n // In the specific case where N forms two bonds to\n // CA and C, try and place a dummy hydrogen\n\n if (ap.bondCount >= 3) return; // Skip if 3 bonds already (e.g. PRO)\n\n if (ap.bondToElementCount(1)) return; // Skip if any H specificed\n\n const hPos = backboneNHPosition(ap)\n if (hPos !== undefined) {\n hPositions.push(hPos)\n this.hCharges.push(nHCharge * ap.occupancy)\n }\n }\n })\n\n const bbox = params.structure.getBoundingBox()\n bbox.expandByScalar(nHBondDistance) // Worst case\n\n // SpatialHash requires x,y,z and count\n this.hStore = buildStoreLike(hPositions)\n this.hHash = new SpatialHash(this.hStore as any, bbox) // TODO\n this.hash = new SpatialHash(params.structure.atomStore, bbox)\n }\n\n @manageColor\n positionColor (v: Vector3) {\n\n const charges = this.charges\n const hCharges = this.hCharges\n\n let p = 0.0\n this.hash.eachWithin(v.x, v.y, v.z, maxRadius, (atomIndex, dSq) => {\n const charge = charges[atomIndex]\n if (charge === 0.0) return\n p += charge / dSq\n })\n\n this.hHash.eachWithin(v.x, v.y, v.z, maxRadius, (atomIndex, dSq) => {\n const charge = hCharges[atomIndex]\n if (charge === 0.0) return\n p += charge / dSq\n })\n\n return this.scale(p * 332) // 332 to convert to kcal/mol\n }\n}\n\nColormakerRegistry.add('electrostatic', ElectrostaticColormaker)\n\nexport default ElectrostaticColormaker\n","/**\n * @file Element Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport Colormaker, { ColormakerParameters, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n// from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF)\nconst ElementColors: { [k: string]: number } = {\n 'H': 0xFFFFFF,\n 'HE': 0xD9FFFF,\n 'LI': 0xCC80FF,\n 'BE': 0xC2FF00,\n 'B': 0xFFB5B5,\n 'C': 0x909090,\n 'N': 0x3050F8,\n 'O': 0xFF0D0D,\n 'F': 0x90E050,\n 'NE': 0xB3E3F5,\n 'NA': 0xAB5CF2,\n 'MG': 0x8AFF00,\n 'AL': 0xBFA6A6,\n 'SI': 0xF0C8A0,\n 'P': 0xFF8000,\n 'S': 0xFFFF30,\n 'CL': 0x1FF01F,\n 'AR': 0x80D1E3,\n 'K': 0x8F40D4,\n 'CA': 0x3DFF00,\n 'SC': 0xE6E6E6,\n 'TI': 0xBFC2C7,\n 'V': 0xA6A6AB,\n 'CR': 0x8A99C7,\n 'MN': 0x9C7AC7,\n 'FE': 0xE06633,\n 'CO': 0xF090A0,\n 'NI': 0x50D050,\n 'CU': 0xC88033,\n 'ZN': 0x7D80B0,\n 'GA': 0xC28F8F,\n 'GE': 0x668F8F,\n 'AS': 0xBD80E3,\n 'SE': 0xFFA100,\n 'BR': 0xA62929,\n 'KR': 0x5CB8D1,\n 'RB': 0x702EB0,\n 'SR': 0x00FF00,\n 'Y': 0x94FFFF,\n 'ZR': 0x94E0E0,\n 'NB': 0x73C2C9,\n 'MO': 0x54B5B5,\n 'TC': 0x3B9E9E,\n 'RU': 0x248F8F,\n 'RH': 0x0A7D8C,\n 'PD': 0x006985,\n 'AG': 0xC0C0C0,\n 'CD': 0xFFD98F,\n 'IN': 0xA67573,\n 'SN': 0x668080,\n 'SB': 0x9E63B5,\n 'TE': 0xD47A00,\n 'I': 0x940094,\n 'XE': 0x940094,\n 'CS': 0x57178F,\n 'BA': 0x00C900,\n 'LA': 0x70D4FF,\n 'CE': 0xFFFFC7,\n 'PR': 0xD9FFC7,\n 'ND': 0xC7FFC7,\n 'PM': 0xA3FFC7,\n 'SM': 0x8FFFC7,\n 'EU': 0x61FFC7,\n 'GD': 0x45FFC7,\n 'TB': 0x30FFC7,\n 'DY': 0x1FFFC7,\n 'HO': 0x00FF9C,\n 'ER': 0x00E675,\n 'TM': 0x00D452,\n 'YB': 0x00BF38,\n 'LU': 0x00AB24,\n 'HF': 0x4DC2FF,\n 'TA': 0x4DA6FF,\n 'W': 0x2194D6,\n 'RE': 0x267DAB,\n 'OS': 0x266696,\n 'IR': 0x175487,\n 'PT': 0xD0D0E0,\n 'AU': 0xFFD123,\n 'HG': 0xB8B8D0,\n 'TL': 0xA6544D,\n 'PB': 0x575961,\n 'BI': 0x9E4FB5,\n 'PO': 0xAB5C00,\n 'AT': 0x754F45,\n 'RN': 0x428296,\n 'FR': 0x420066,\n 'RA': 0x007D00,\n 'AC': 0x70ABFA,\n 'TH': 0x00BAFF,\n 'PA': 0x00A1FF,\n 'U': 0x008FFF,\n 'NP': 0x0080FF,\n 'PU': 0x006BFF,\n 'AM': 0x545CF2,\n 'CM': 0x785CE3,\n 'BK': 0x8A4FE3,\n 'CF': 0xA136D4,\n 'ES': 0xB31FD4,\n 'FM': 0xB31FBA,\n 'MD': 0xB30DA6,\n 'NO': 0xBD0D87,\n 'LR': 0xC70066,\n 'RF': 0xCC0059,\n 'DB': 0xD1004F,\n 'SG': 0xD90045,\n 'BH': 0xE00038,\n 'HS': 0xE6002E,\n 'MT': 0xEB0026,\n 'DS': 0xFFFFFF,\n 'RG': 0xFFFFFF,\n 'CN': 0xFFFFFF,\n 'UUT': 0xFFFFFF,\n 'FL': 0xFFFFFF,\n 'UUP': 0xFFFFFF,\n 'LV': 0xFFFFFF,\n 'UUH': 0xFFFFFF,\n\n 'D': 0xFFFFC0,\n 'T': 0xFFFFA0\n}\nconst DefaultElementColor = 0xFFFFFF\n\n/**\n * Color by element\n */\nclass ElementColormaker extends Colormaker {\n constructor (params: ColormakerParameters) {\n params.value = defaults(params.value, ElementColors.C)\n\n super(params)\n }\n\n\n @manageColor\n atomColor (a: AtomProxy) {\n const element = a.element\n\n if (element === 'C') {\n return this.parameters.value\n } else {\n return ElementColors[ element ] || DefaultElementColor\n }\n }\n}\n\nColormakerRegistry.add('element', ElementColormaker)\n\nexport default ElementColormaker\n","/**\n * @file Entityindex Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Color by entity index\n */\nclass EntityindexColormaker extends Colormaker {\n entityindexScale: ColormakerScale\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'Spectral'\n }\n if (!params.domain) {\n this.parameters.domain = [ 0, params.structure.entityList.length - 1 ]\n }\n\n this.entityindexScale = this.getScale()\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.entityindexScale(a.entityIndex)\n }\n}\n\nColormakerRegistry.add('entityindex', EntityindexColormaker)\n\nexport default EntityindexColormaker\n","/**\n * @file Entitytype Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\nimport {\n PolymerEntity, NonPolymerEntity, MacrolideEntity, WaterEntity\n} from '../structure/structure-constants'\n\n/**\n * Color by entity type\n */\nclass EntitytypeColormaker extends Colormaker {\n @manageColor\n atomColor (a: AtomProxy) {\n const e = a.entity\n const et = e ? e.entityType : undefined\n switch (et) {\n case PolymerEntity:\n return 0x7fc97f\n case NonPolymerEntity:\n return 0xfdc086\n case MacrolideEntity:\n return 0xbeaed4\n case WaterEntity:\n return 0x386cb0\n default:\n return 0xffff99\n }\n }\n}\n\nColormakerRegistry.add('entitytype', EntitytypeColormaker)\n\nexport default EntitytypeColormaker\n","/**\n * @file Geoquality Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport { countSetBits } from '../math/math-utils'\n\n/**\n * Color by validation gometry quality\n */\nclass GeoqualityColormaker extends Colormaker {\n geoAtomDict: { [k: string]: { [k: string]: number } } = {}\n geoDict: { [k: string]: number|undefined } = {}\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n const val = params.structure.validation\n if (val) {\n this.geoAtomDict = val.geoAtomDict\n this.geoDict = val.geoDict\n }\n }\n\n @manageColor\n atomColor (atom: AtomProxy) {\n let sele = atom.resno + ''\n if (atom.inscode) sele += '^' + atom.inscode\n if (atom.chainname) sele += ':' + atom.chainname\n sele += '/' + atom.modelIndex\n\n let geoProblemCount\n const geoAtom = this.geoAtomDict[ sele ]\n if (geoAtom !== undefined) {\n const atomProblems: number = geoAtom[ atom.atomname ] || 0\n geoProblemCount = countSetBits(atomProblems)\n } else {\n geoProblemCount = this.geoDict[ sele ] || 0\n }\n\n if (geoProblemCount === 0) {\n return 0x2166ac\n } else if (geoProblemCount === 1) {\n return 0xfee08b\n } else if (geoProblemCount === 2) {\n return 0xf46d43\n } else if (geoProblemCount >= 3) {\n return 0xa50026\n }\n return 0x909090\n }\n}\n\nColormakerRegistry.add('geoquality', GeoqualityColormaker)\n\nexport default GeoqualityColormaker\n","/**\n * @file Hydrophobicity Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { ColormakerParameters, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\nimport {\n ResidueHydrophobicity, DefaultResidueHydrophobicity\n} from '../structure/structure-constants'\n\n/**\n * Color by hydrophobicity\n */\nclass HydrophobicityColormaker extends Colormaker {\n hfScale: ColormakerScale\n resHF: { [k: string]: number } = {}\n defaultResidueHydrophobicity: number\n\n constructor (params: ColormakerParameters) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'RdYlGn'\n }\n\n const idx = 0 // 0: DGwif, 1: DGwoct, 2: Oct-IF\n\n for (const name in ResidueHydrophobicity) {\n this.resHF[ name ] = ResidueHydrophobicity[ name ][ idx ]\n }\n this.defaultResidueHydrophobicity = DefaultResidueHydrophobicity[idx]\n\n if (!params.domain) {\n let min = Infinity\n let max = -Infinity\n\n for (const name in this.resHF) {\n const val = this.resHF[ name ]\n min = Math.min(min, val)\n max = Math.max(max, val)\n }\n\n this.parameters.domain = [ min, 0, max ]\n }\n\n this.hfScale = this.getScale()\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.hfScale(this.resHF[ a.resname ] || this.defaultResidueHydrophobicity)\n }\n}\n\nColormakerRegistry.add('hydrophobicity', HydrophobicityColormaker)\n\nexport default HydrophobicityColormaker\n","/**\n * @file Modelindex Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Color by model index\n */\nclass ModelindexColormaker extends Colormaker {\n modelindexScale: ColormakerScale\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'rainbow'\n }\n if (!params.domain) {\n this.parameters.domain = [ 0, params.structure.modelStore.count ]\n }\n\n this.modelindexScale = this.getScale()\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.modelindexScale(a.modelIndex)\n }\n}\n\nColormakerRegistry.add('modelindex', ModelindexColormaker)\n\nexport default ModelindexColormaker\n","/**\n * @file Moleculetype Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\nimport {\n WaterType, IonType, ProteinType, RnaType, DnaType, SaccharideType\n} from '../structure/structure-constants'\n\n/**\n * Color by molecule type\n */\nclass MoleculetypeColormaker extends Colormaker {\n @manageColor\n atomColor (a: AtomProxy) {\n switch (a.residueType.moleculeType) {\n case WaterType:\n return 0x386cb0\n case IonType:\n return 0xf0027f\n case ProteinType:\n return 0xbeaed4\n case RnaType:\n return 0xfdc086\n case DnaType:\n return 0xbf5b17\n case SaccharideType:\n return 0x7fc97f\n default:\n return 0xffff99\n }\n }\n}\n\nColormakerRegistry.add('moleculetype', MoleculetypeColormaker)\n\nexport default MoleculetypeColormaker\n","/**\n * @file Occupancy Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { ColormakerParameters, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Color by occupancy\n */\nclass OccupancyColormaker extends Colormaker {\n occupancyScale: ColormakerScale\n\n constructor (params: ColormakerParameters) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'PuBu'\n }\n\n if (!params.domain) {\n this.parameters.domain = [ 0.0, 1.0 ]\n }\n\n this.occupancyScale = this.getScale()\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.occupancyScale(a.occupancy)\n }\n}\n\nColormakerRegistry.add('occupancy', OccupancyColormaker)\n\nexport default OccupancyColormaker\n","/**\n * @file Partialcharge Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { ColormakerParameters, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Color by partial charge. The {@link AtomProxy.partialCharge} property is used for coloring.\n * The default domain is [-1, 1].\n *\n * __Name:__ _partialCharge_\n *\n * @example\n * stage.loadFile(\"rcsb://1crn\").then(function (o) {\n * o.addRepresentation(\"ball+stick\", {colorScheme: \"partialCharge\"});\n * o.autoView();\n * });\n */\nclass PartialchargeColormaker extends Colormaker {\n partialchargeScale: ColormakerScale\n\n constructor (params: ColormakerParameters) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'rwb'\n }\n\n if (!params.domain) {\n this.parameters.domain = [-1, 1]\n }\n\n this.partialchargeScale = this.getScale()\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.partialchargeScale(a.partialCharge || 0)\n }\n}\n\nColormakerRegistry.add('partialcharge', PartialchargeColormaker)\n\nexport default PartialchargeColormaker\n","/**\n * @file Random Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { manageColor } from './colormaker'\n\nfunction randomColor () {\n return Math.random() * 0xFFFFFF\n}\n\n/**\n * Class by random color\n */\nclass RandomColormaker extends Colormaker {\n /**\n * get color for an atom\n * @return {Integer} random hex color\n */\n @manageColor\n atomColor () {\n return randomColor()\n }\n\n /**\n * get color for volume cell\n * @return {Integer} random hex color\n */\n @manageColor\n volumeColor () {\n return randomColor()\n }\n\n /**\n * get color for coordinates in space\n * @return {Integer} random hex color\n */\n @manageColor\n positionColor () {\n return randomColor()\n }\n}\n\nColormakerRegistry.add('random', RandomColormaker)\n\nexport default RandomColormaker\n","/**\n * @file Randomcoilindex Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n/**\n * Color by random coil index\n */\nclass RandomcoilindexColormaker extends Colormaker {\n rciScale: ColormakerScale\n rciDict: { [k: string]: number|undefined } = {}\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'RdYlBu'\n }\n\n this.rciScale = this.getScale({ domain: [ 0.6, 0 ] })\n\n const val = params.structure.validation\n if (val) this.rciDict = val.rciDict\n\n }\n\n @manageColor\n atomColor (atom: AtomProxy) {\n let sele = `[${atom.resname}]${atom.resno}`\n if (atom.chainname) sele += ':' + atom.chainname\n\n const rci = this.rciDict[ sele ]\n return rci !== undefined ? this.rciScale(rci) : 0x909090\n }\n}\n\nColormakerRegistry.add('randomcoilindex', RandomcoilindexColormaker)\n\nexport default RandomcoilindexColormaker\n","/**\n * @file Residueindex Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport Colormaker, { StuctureColormakerParams, ColormakerScale, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ChainProxy from '../proxy/chain-proxy'\n\n/**\n * Color by residue index\n */\nclass ResidueindexColormaker extends Colormaker {\n scalePerChain: { [k: number]: ColormakerScale } = {}\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n if (!params.scale) {\n this.parameters.scale = 'rainbow'\n this.parameters.reverse = defaults(params.reverse, true)\n }\n\n params.structure.eachChain((cp: ChainProxy) => {\n this.parameters.domain = [ cp.residueOffset, cp.residueEnd ]\n this.scalePerChain[ cp.index ] = this.getScale()\n })\n }\n\n @manageColor\n atomColor (a: AtomProxy) {\n return this.scalePerChain[ a.chainIndex ](a.residueIndex)\n }\n}\n\nColormakerRegistry.add('residueindex', ResidueindexColormaker)\n\nexport default ResidueindexColormaker\n","/**\n * @file Resname Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\n\n// protein colors from Jmol http://jmol.sourceforge.net/jscolors/\nconst ResidueColors: { [k: string]: number } = {\n 'ALA': 0x8CFF8C,\n 'ARG': 0x00007C,\n 'ASN': 0xFF7C70,\n 'ASP': 0xA00042,\n 'CYS': 0xFFFF70,\n 'GLN': 0xFF4C4C,\n 'GLU': 0x660000,\n 'GLY': 0xFFFFFF,\n 'HIS': 0x7070FF,\n 'ILE': 0x004C00,\n 'LEU': 0x455E45,\n 'LYS': 0x4747B8,\n 'MET': 0xB8A042,\n 'PHE': 0x534C52,\n 'PRO': 0x525252,\n 'SER': 0xFF7042,\n 'THR': 0xB84C00,\n 'TRP': 0x4F4600,\n 'TYR': 0x8C704C,\n 'VAL': 0xFF8CFF,\n\n 'ASX': 0xFF00FF,\n 'GLX': 0xFF00FF,\n 'ASH': 0xFF00FF,\n 'GLH': 0xFF00FF,\n\n 'A': 0xDC143C, // Crimson Red\n 'G': 0x32CD32, // Lime Green\n 'I': 0x9ACD32, // Yellow Green\n 'X': 0x7CFC00, // Lawn Green\n 'C': 0xFFD700, // Gold Yellow\n 'T': 0x4169E1, // Royal Blue\n 'U': 0x40E0D0, // Turquoise Cyan\n 'D': 0x008B8B, // Dark Cyan\n\n 'DA': 0xDC143C,\n 'DG': 0x32CD32,\n 'DI': 0x9ACD32,\n 'DX': 0x7CFC00,\n 'DC': 0xFFD700,\n 'DT': 0x4169E1,\n 'DU': 0x40E0D0,\n 'DD': 0x008B8B\n}\nconst DefaultResidueColor = 0xFF00FF\n\n/**\n * Color by residue name\n */\nclass ResnameColormaker extends Colormaker {\n @manageColor\n atomColor (a: AtomProxy) {\n return ResidueColors[ a.resname ] || DefaultResidueColor\n }\n}\n\nColormakerRegistry.add('resname', ResnameColormaker)\n\nexport default ResnameColormaker\n","/**\n * @file Sstruc Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { StuctureColormakerParams, manageColor } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport ResidueProxy from '../proxy/residue-proxy'\n\n// from Jmol http://jmol.sourceforge.net/jscolors/ (shapely)\nconst StructureColors = {\n 'alphaHelix': 0xFF0080,\n 'threeTenHelix': 0xA00080,\n 'piHelix': 0x600080,\n 'betaStrand': 0xFFC800,\n 'betaTurn': 0x6080FF,\n 'coil': 0xFFFFFF,\n\n 'dna': 0xAE00FE,\n 'rna': 0xFD0162,\n\n 'carbohydrate': 0xA6A6FA\n}\nconst DefaultStructureColor = 0x808080\n\n/**\n * Color by secondary structure\n */\nclass SstrucColormaker extends Colormaker {\n residueProxy: ResidueProxy\n\n constructor (params: StuctureColormakerParams) {\n super(params)\n\n this.residueProxy = params.structure.getResidueProxy()\n }\n\n @manageColor\n atomColor (ap: AtomProxy) {\n const sstruc = ap.sstruc\n const rp = this.residueProxy\n\n if (sstruc === 'h') {\n return StructureColors.alphaHelix\n } else if (sstruc === 'g') {\n return StructureColors.threeTenHelix\n } else if (sstruc === 'i') {\n return StructureColors.piHelix\n } else if (sstruc === 'e' || sstruc === 'b') {\n return StructureColors.betaStrand\n } else if (sstruc === 't') {\n return StructureColors.betaTurn\n } else {\n rp.index = ap.residueIndex\n if (rp.isDna()) {\n return StructureColors.dna\n } else if (rp.isRna()) {\n return StructureColors.rna\n } else if (rp.isSaccharide()) {\n return StructureColors.carbohydrate\n } else if (rp.isProtein() || sstruc === 's' || sstruc === 'l') {\n return StructureColors.coil\n } else {\n return DefaultStructureColor\n }\n }\n }\n}\n\nColormakerRegistry.add('sstruc', SstrucColormaker)\n\nexport default SstrucColormaker\n","/**\n * @file Colordata Colormaker\n * @author Fred Ludlow \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { ColorData, ColormakerScale, manageColor, StuctureColormakerParams } from './colormaker'\nimport AtomProxy from '../proxy/atom-proxy'\nimport BondProxy from '../proxy/bond-proxy'\n\n\nclass StructuredataColormaker extends Colormaker {\n atomData?: ColorData['atomData']\n bondData?: ColorData['bondData']\n scale: ColormakerScale\n\n constructor(params: StuctureColormakerParams) {\n super(params)\n if (!params.scale) {\n this.parameters.scale = 'rwb'\n }\n this.atomData = this.parameters.data?.atomData\n this.bondData = this.parameters.data?.bondData\n this.scale = this.getScale(this.parameters)\n }\n\n @manageColor\n atomColor(a: AtomProxy) {\n const val = this.atomData?.[a.index]\n return (val !== undefined) ? this.scale(val) : this.parameters.value\n }\n\n @manageColor\n bondColor(bond: BondProxy, fromTo: boolean) {\n const val = this.bondData?.[bond.index]\n \n // Explicit bond data?\n if (val !== undefined) return this.scale(val)\n \n \n if (this.atomProxy) {\n this.atomProxy.index = fromTo ? bond.atomIndex1 : bond.atomIndex2\n return this.atomColor(this.atomProxy)\n } \n \n // Fallback\n return this.parameters.value\n }\n}\n\nColormakerRegistry.add('structuredata', StructuredataColormaker)\n\nexport default StructuredataColormaker","/**\n * @file Uniform Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { manageColor } from './colormaker'\n\n/**\n * Color by uniform color\n */\nclass UniformColormaker extends Colormaker {\n @manageColor\n atomColor () {\n return this.parameters.value\n }\n\n @manageColor\n bondColor () {\n return this.parameters.value\n }\n\n @manageColor\n valueColor () {\n return this.parameters.value\n }\n\n @manageColor\n volumeColor () {\n return this.parameters.value\n }\n}\n\nColormakerRegistry.add('uniform', UniformColormaker)\n\nexport default UniformColormaker\n","/**\n * @file Value Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { VolumeColormakerParams, ColormakerScale, manageColor } from './colormaker'\n\n/**\n * Color by volume value\n */\nclass ValueColormaker extends Colormaker {\n valueScale: ColormakerScale\n\n constructor (params: VolumeColormakerParams) {\n super(params)\n this.valueScale = this.getScale()\n }\n\n /**\n * return the color for a volume cell\n * @param {Integer} index - volume cell index\n * @return {Integer} hex cell color\n */\n @manageColor\n volumeColor (index: number) {\n return this.valueScale((this.parameters.volume! as any).data[ index ]) // TODO\n }\n}\n\nColormakerRegistry.add('value', ValueColormaker)\n\nexport default ValueColormaker\n","/**\n * @file Volume Colormaker\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\nimport { lerp } from '../math/math-utils'\n\nimport { ColormakerRegistry } from '../globals'\nimport Colormaker, { VolumeColormakerParams, ColormakerScale, manageColor } from './colormaker'\n\n/**\n * Color by volume position\n */\nclass VolumeColormaker extends Colormaker {\n valueScale: ColormakerScale\n vec = new Vector3()\n\n constructor (params: VolumeColormakerParams) {\n super(params)\n this.valueScale = this.getScale()\n }\n\n /**\n * return the color for coordinates in space\n * @param {Vector3} coords - xyz coordinates\n * @return {Integer} hex coords color\n */\n @manageColor\n positionColor (coords: Vector3) {\n const volume = this.parameters.volume as any // TODO\n\n if (!volume || !volume.inverseMatrix) {\n return this.parameters.value\n }\n\n const vec = this.vec\n const data = volume.data\n const nx = volume.nx\n const ny = volume.ny\n const nxy = nx * ny\n\n vec.copy(coords)\n vec.applyMatrix4(volume.inverseMatrix)\n\n // position of grid cell\n const x0 = Math.floor(vec.x)\n const y0 = Math.floor(vec.y)\n const z0 = Math.floor(vec.z)\n\n // Indices\n const i = ((((z0 * ny) + y0) * nx) + x0)\n const i1 = i + 1\n const iy = i + nx\n const iz = i + nxy\n const i1y = iy + 1\n const i1z = iz + 1\n const iyz = iy + nxy\n const i1yz = iyz + 1\n\n // Values\n const v = data[ i ]\n const v1 = data[ i1 ]\n const vy = data[ iy ]\n const vz = data[ iz ]\n const v1y = data[ i1y ]\n const v1z = data[ i1z ]\n const vyz = data[ iyz ]\n const v1yz = data[ i1yz ]\n\n // Position of point in fraction of grid\n const xd = vec.x - x0\n const yd = vec.y - y0\n const zd = vec.z - z0\n\n // 1st Dimension\n const c00 = lerp(v, v1, xd)\n const c01 = lerp(vz, v1z, xd)\n const c10 = lerp(vy, v1y, xd)\n const c11 = lerp(vyz, v1yz, xd)\n\n // 2nd Dimension\n const c0 = lerp(c00, c10, yd)\n const c1 = lerp(c01, c11, yd)\n\n // 3rd Dimension\n const c = lerp(c0, c1, zd)\n\n return this.valueScale(c)\n }\n}\n\nColormakerRegistry.add('volume', VolumeColormaker)\n\nexport default VolumeColormaker\n","/**\n * @file Structure Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { ExtensionFragDepth, Mobile } from '../globals'\nimport { defaults } from '../utils'\nimport { RepresentationParameters, default as Representation } from './representation'\nimport Selection from '../selection/selection'\nimport RadiusFactory, { RadiusFactoryTypes, RadiusType } from '../utils/radius-factory'\nimport Structure from '../structure/structure'\nimport Viewer from '../viewer/viewer'\n// @ts-ignore: unused import Volume required for declaration only\nimport { Assembly, Volume } from '../ngl';\nimport StructureView from '../structure/structure-view';\nimport AtomProxy from '../proxy/atom-proxy';\nimport Polymer from '../proxy/polymer';\nimport Buffer from '../buffer/buffer';\nimport { AtomDataFields, BondDataFields, AtomDataParams, BondDataParams } from '../structure/structure-data';\n// @ts-ignore: unused import Surface required for declaration only\nimport Surface from '../surface/surface'\n\n/**\n * Structure representation parameter object.\n * @typedef {Object} StructureRepresentationParameters - structure representation parameters\n * @mixes RepresentationParameters\n *\n * @property {String} radiusType - A list of possible sources of the radius used for rendering the representation. The radius can be based on the *vdW radius*, the *covalent radius* or the *B-factor* value of the corresponding atom. Additionally the radius can be based on the *secondary structure*. Alternatively, when set to *size*, the value from the *radius* parameter is used for all atoms.\n * @property {Float} radius - A number providing a fixed radius used for rendering the representation.\n * @property {Float} scale - A number that scales the value defined by the *radius* or the *radiusType* parameter.\n * @property {String} assembly - name of an assembly object. Included are the asymmetric unit (*AU*) corresponding to the coordinates given in the structure file, biological assemblies from *PDB*, *mmCIF* or *MMTF* files (*BU1*, *BU2*, ...), a filled (crystallographic) unitcell of a given space group (*UNITCELL*), a supercell consisting of a center unitcell and its 26 direct neighbors (*SUPERCELL*). Set to *default* to use the default asemmbly of the structure object.\n */\nexport interface StructureRepresentationParameters extends RepresentationParameters {\n radiusType: string\n radius: number\n scale: number\n assembly: string\n}\nexport interface StructureRepresentationData {\n bufferList: Buffer[]\n polymerList?: Polymer[]\n sview?: StructureView | Structure\n [k: string]: any\n}\n/**\n * Structure representation\n * @interface\n */\nabstract class StructureRepresentation extends Representation {\n\n protected selection: Selection\n protected dataList: StructureRepresentationData[]\n structure: Structure\n structureView: StructureView\n\n protected radiusType: RadiusType\n protected radiusData: {[k: number]: number}\n protected radiusSize: number\n protected radiusScale: number\n protected assembly: string\n protected defaultAssembly: string\n protected needsBuild: boolean\n\n /**\n * Create Structure representation object\n * @param {Structure} structure - the structure to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {StructureRepresentationParameters} params - structure representation parameters\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n const p = params || {}\n\n super(structure, viewer, p)\n\n this.type = 'structure'\n\n this.parameters = Object.assign({\n radiusType: {\n type: 'select', options: RadiusFactory.types\n },\n radiusData: {\n type: 'hidden'\n },\n radiusSize: {\n type: 'number', precision: 3, max: 10.0, min: 0.001\n },\n radiusScale: {\n type: 'number', precision: 3, max: 10.0, min: 0.001\n },\n assembly: null,\n defaultAssembly: {\n type: 'hidden'\n }\n }, this.parameters)\n\n /**\n * @type {Selection}\n * @private\n */\n this.selection = new Selection(p.sele)\n\n /**\n * @type {Array}\n * @private\n */\n this.dataList = []\n\n /**\n * @type {Structure}\n */\n this.structure = structure\n\n /**\n * @type {StructureView}\n */\n this.structureView = this.structure.getView(this.selection)\n\n if (structure.biomolDict) {\n const biomolOptions:{[key: string]: string} = {\n 'default': 'default',\n '': (structure.unitcell ? 'AU' : 'FULL')\n }\n Object.keys(structure.biomolDict).forEach(function (k) {\n biomolOptions[ k ] = k\n })\n this.parameters.assembly = {\n type: 'select',\n options: biomolOptions,\n rebuild: true\n }\n } else {\n this.parameters.assembly = null\n }\n }\n\n get defaultScale () {\n return {\n 'vdw': 1.0,\n 'covalent': 1.0,\n 'bfactor': 0.01,\n 'sstruc': 1.0\n }\n }\n\n init (params: Partial) {\n const p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'element')\n\n this.setRadius(p.radius, p)\n\n this.radiusType = defaults(p.radiusType, 'vdw')\n this.radiusData = defaults(p.radiusData, {})\n this.radiusSize = defaults(p.radiusSize, 1.0)\n this.radiusScale = defaults(p.radiusScale, 1.0)\n this.assembly = defaults(p.assembly, 'default')\n this.defaultAssembly = defaults(p.defaultAssembly, '')\n\n if (p.quality === 'auto') {\n p.quality = this.getQuality()\n }\n\n super.init(p)\n\n this.selection.signals.stringChanged.add((/* sele */) => {\n this.build()\n })\n\n this.build()\n }\n\n setRadius (value: string | number | undefined, p: Partial) {\n const types = Object.keys(RadiusFactoryTypes)\n\n if (typeof value === 'string' && types.includes(value.toLowerCase())) {\n p.radiusType = value\n } else if (value !== undefined) {\n p.radiusType = 'size'\n p.radiusSize = value\n }\n\n return this\n }\n\n getAssembly (): Assembly {\n const name = this.assembly === 'default' ? this.defaultAssembly : this.assembly\n return this.structure.biomolDict[ name ]\n }\n\n getQuality () {\n let atomCount\n const s = this.structureView\n const assembly = this.getAssembly()\n if (assembly) {\n atomCount = assembly.getAtomCount(s)\n } else {\n atomCount = s.atomCount\n }\n if (Mobile) {\n atomCount *= 4\n }\n const backboneOnly = s.atomStore.count / s.residueStore.count < 2\n if (backboneOnly) {\n atomCount *= 10\n }\n\n if (atomCount < 15000) {\n return 'high'\n } else if (atomCount < 80000) {\n return 'medium'\n } else {\n return 'low'\n }\n }\n\n create () {\n if (this.structureView.atomCount === 0) return\n\n if (!this.structureView.hasCoords()) {\n this.needsBuild = true\n return\n } else {\n this.needsBuild = false\n }\n\n const assembly = this.getAssembly()\n\n if (assembly) {\n assembly.partList.forEach((part, i) => {\n const sview = part.getView(this.structureView)\n if (sview.atomCount === 0) return\n const data = this.createData(sview, i)\n if (data) {\n data.sview = sview\n data.instanceList = part.getInstanceList()\n this.dataList.push(data)\n }\n })\n } else {\n const data = this.createData(this.structureView, 0)\n if (data) {\n data.sview = this.structureView\n this.dataList.push(data)\n }\n }\n }\n\n abstract createData (sview: StructureView, k?: number): StructureRepresentationData|undefined\n\n update (what: AtomDataFields|BondDataFields) {\n if (this.lazy && !this.visible) {\n Object.assign(this.lazyProps.what, what)\n return\n }\n\n if (this.needsBuild) {\n this.build()\n return\n }\n\n this.dataList.forEach((data) => {\n if (data.bufferList.length > 0) {\n this.updateData(what, data)\n }\n }, this)\n }\n\n updateData (what?: AtomDataFields|BondDataFields, data?: any) {\n this.build()\n }\n\n getColorParams () {\n return {\n ...super.getColorParams(),\n structure: this.structure\n }\n }\n\n getRadiusParams (param?: any) {\n return {\n type: this.radiusType,\n scale: this.radiusScale,\n size: this.radiusSize,\n data: this.radiusData\n }\n }\n\n getAtomParams (what?: AtomDataFields, params?: AtomDataParams) {\n return Object.assign({\n what: what,\n colorParams: this.getColorParams(),\n radiusParams: this.getRadiusParams()\n }, params)\n }\n\n getBondParams (what?: BondDataFields, params?: BondDataParams) {\n return Object.assign({\n what: what,\n colorParams: this.getColorParams(),\n radiusParams: this.getRadiusParams()\n }, params)\n }\n\n getAtomRadius (atom: AtomProxy) {\n if (this.structureView.atomSet!.isSet(atom.index)) {\n const radiusFactory = new RadiusFactory(this.getRadiusParams())\n return radiusFactory.atomRadius(atom)\n }\n return 0\n }\n\n /**\n * Set representation parameters\n * @alias StructureRepresentation#setSelection\n * @param {String} string - selection string, see {@tutorial selection-language}\n * @param {Boolean} [silent] - don't trigger a change event in the selection\n * @return {StructureRepresentation} this object\n */\n setSelection (string: string, silent?: boolean) {\n this.selection.setString(string, silent)\n\n return this\n }\n\n /**\n * Set representation parameters\n * @alias StructureRepresentation#setParameters\n * @param {StructureRepresentationParameters} params - structure parameter object\n * @param {Object} [what] - buffer data attributes to be updated,\n * note that this needs to be implemented in the\n * derived classes. Generally it allows more\n * fine-grained control over updating than\n * forcing a rebuild.\n * @param {Boolean} what.position - update position data\n * @param {Boolean} what.color - update color data\n * @param {Boolean} [rebuild] - whether or not to rebuild the representation\n * @return {StructureRepresentation} this object\n */\n setParameters (params: Partial, what: AtomDataFields = {}, rebuild = false) {\n const p = params || {}\n\n this.setRadius(p.radius, p)\n\n if (p.radiusType !== undefined || p.radiusData !== undefined || p.radiusSize !== undefined || p.radiusScale !== undefined) {\n what.radius = true\n if (!ExtensionFragDepth || this.disableImpostor) {\n rebuild = true\n }\n }\n\n if (p.defaultAssembly !== undefined &&\n p.defaultAssembly !== this.defaultAssembly &&\n ((this.assembly === 'default' && p.assembly === undefined) ||\n p.assembly === 'default')\n ) {\n rebuild = true\n }\n\n super.setParameters(p, what, rebuild)\n\n return this\n }\n\n getParameters () {\n const params = Object.assign(\n super.getParameters(),\n {\n sele: this.selection ? this.selection.string : undefined,\n defaultAssembly: this.defaultAssembly\n }\n )\n\n return params\n }\n\n attach (callback: ()=> void) {\n const viewer = this.viewer\n const bufferList = this.bufferList\n\n this.dataList.forEach(function (data) {\n data.bufferList.forEach(function (buffer) {\n bufferList.push(buffer)\n viewer.add(buffer, data.instanceList)\n })\n })\n\n this.setVisibility(this.visible)\n callback()\n }\n\n clear () {\n this.dataList.length = 0\n\n super.clear()\n }\n\n dispose () {\n this.structureView.dispose()\n\n super.dispose()\n }\n}\n\nexport default StructureRepresentation\n","/**\n * @file Measurement Representation\n * @author Fred Ludlow \n * @private\n */\n\n// @ts-ignore: unused import Vector3, Matrix4 required for declaration only\nimport { Color, Vector3, Matrix4 } from 'three'\n\nimport Selection from '../selection/selection'\nimport { Browser } from '../globals'\nimport { defaults } from '../utils'\nimport StructureRepresentation, { StructureRepresentationParameters } from './structure-representation'\nimport { uniformArray, uniformArray3 } from '../math/array-utils'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport { LabelRepresentationParameters } from './label-representation';\nimport TextBuffer, { TextBufferData } from '../buffer/text-buffer';\nimport { GenericColor } from '../types'\n\nexport interface LabelDataField {\n position?: boolean\n labelColor?: boolean\n labelSize?: boolean\n radius?: boolean\n labelText?: boolean\n}\n\n/**\n * Measurement representation parameter object.\n * @typedef {Object} MeasurementRepresentationParameters - measurement representation parameters\n * @mixes RepresentationParameters\n * @mixes StructureRepresentationParameters\n *\n * @property {Float} labelSize - size of the distance label\n * @property {Color} labelColor - color of the distance label\n * @property {Boolean} labelVisible - visibility of the distance label\n * @property {Float} labelZOffset - offset in z-direction (i.e. in camera direction)\n */\nexport interface MeasurementRepresentationParameters extends StructureRepresentationParameters {\n labelVisible: boolean\n labelSize: number\n labelColor: GenericColor\n labelType: 'atomname'|'atomindex'|'occupancy'|'bfactor'|'serial'|'element'|'atom'|'resname'|'resno'|'res'|'text'|'qualified'\n labelText: string\n labelFormat: string\n labelGrouping: 'atom'|'residue'\n labelFontFamily: 'sans-serif'|'monospace'|'serif'\n labelFontStyle: 'normal'|'italic'\n labelFontWeight: 'normal'|'bold'\n labelsdf: boolean\n labelXOffset: number\n labelYOffset: number\n labelZOffset: number\n labelAttachment: 'bottom-left'|'bottom-center'|'bottom-right'|'middle-left'|'middle-center'|'middle-right'|'top-left'|'top-center'|'top-right'\n labelBorder: boolean\n labelBorderColor: GenericColor\n labelBorderWidth: number\n labelBackground: boolean\n labelBackgroundColor: GenericColor\n labelBackgroundMargin: number\n labelBackgroundOpacity: number\n labelFixedSize: boolean\n lineOpacity: number\n linewidth: number\n}\n\n/**\n * Measurement representation\n * @interface\n */\nabstract class MeasurementRepresentation extends StructureRepresentation {\n protected n: number\n protected labelVisible: boolean\n protected labelSize: number\n protected labelColor: GenericColor\n protected labelType: 'atomname'|'atomindex'|'occupancy'|'bfactor'|'serial'|'element'|'atom'|'resname'|'resno'|'res'|'text'|'qualified'\n protected labelText: string\n protected labelFormat: string\n protected labelGrouping: 'atom'|'residue'\n protected labelFontFamily: 'sans-serif'|'monospace'|'serif'\n protected labelFontStyle: 'normal'|'italic'\n protected labelFontWeight: 'normal'|'bold'\n protected labelsdf: boolean\n protected labelXOffset: number\n protected labelYOffset: number\n protected labelZOffset: number\n protected labelAttachment: 'bottom-left'|'bottom-center'|'bottom-right'|'middle-left'|'middle-center'|'middle-right'|'top-left'|'top-center'|'top-right'\n protected labelBorder: boolean\n protected labelBorderColor: GenericColor\n protected labelBorderWidth: number\n protected labelBackground: boolean\n protected labelBackgroundColor: GenericColor\n protected labelBackgroundMargin: number\n protected labelBackgroundOpacity: number\n protected labelFixedSize: boolean\n protected lineOpacity: number\n protected linewidth: number\n protected lineVisible: boolean\n\n protected textBuffer: TextBuffer\n /**\n * Handles common label settings and position logic for\n * distance, angle and dihedral representations\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.n = 0 // Subclass create sets value\n this.parameters = Object.assign({\n labelVisible: {\n type: 'boolean'\n },\n labelSize: {\n type: 'number', precision: 3, max: 10.0, min: 0.001\n },\n labelColor: {\n type: 'color'\n },\n labelFontFamily: {\n type: 'select',\n options: {\n 'sans-serif': 'sans-serif',\n 'monospace': 'monospace',\n 'serif': 'serif'\n },\n buffer: 'fontFamily'\n },\n labelFontStyle: {\n type: 'select',\n options: {\n 'normal': 'normal',\n 'italic': 'italic'\n },\n buffer: 'fontStyle'\n },\n labelFontWeight: {\n type: 'select',\n options: {\n 'normal': 'normal',\n 'bold': 'bold'\n },\n buffer: 'fontWeight'\n },\n labelsdf: {\n type: 'boolean', buffer: 'sdf'\n },\n labelXOffset: {\n type: 'number', precision: 1, max: 20, min: -20, buffer: 'xOffset'\n },\n labelYOffset: {\n type: 'number', precision: 1, max: 20, min: -20, buffer: 'yOffset'\n },\n labelZOffset: {\n type: 'number', precision: 1, max: 20, min: -20, buffer: 'zOffset'\n },\n labelAttachment: {\n type: 'select',\n options: {\n 'bottom-left': 'bottom-left',\n 'bottom-center': 'bottom-center',\n 'bottom-right': 'bottom-right',\n 'middle-left': 'middle-left',\n 'middle-center': 'middle-center',\n 'middle-right': 'middle-right',\n 'top-left': 'top-left',\n 'top-center': 'top-center',\n 'top-right': 'top-right'\n },\n rebuild: true\n },\n labelBorder: {\n type: 'boolean', buffer: 'showBorder'\n },\n labelBorderColor: {\n type: 'color', buffer: 'borderColor'\n },\n labelBorderWidth: {\n type: 'number', precision: 2, max: 0.3, min: 0, buffer: 'borderWidth'\n },\n labelBackground: {\n type: 'boolean', rebuild: true\n },\n labelBackgroundColor: {\n type: 'color', buffer: 'backgroundColor'\n },\n labelBackgroundMargin: {\n type: 'number', precision: 2, max: 2, min: 0, rebuild: true\n },\n labelBackgroundOpacity: {\n type: 'range', step: 0.01, max: 1, min: 0, buffer: 'backgroundOpacity'\n },\n labelFixedSize: {\n type: 'boolean', buffer: 'fixedSize'\n },\n lineOpacity: {\n type: 'range', min: 0.0, max: 1.0, step: 0.01\n },\n linewidth: {\n type: 'integer', max: 50, min: 1, buffer: true\n }\n }, this.parameters, {\n flatShaded: null\n })\n }\n\n init (params: Partial) {\n const p = params || {}\n this.labelVisible = defaults(p.labelVisible, true)\n this.labelSize = defaults(p.labelSize, 2.0)\n this.labelColor = defaults(p.labelColor, 0xFFFFFF)\n this.labelFontFamily = defaults(p.labelFontFamily, 'sans-serif')\n this.labelFontStyle = defaults(p.labelFontstyle, 'normal')\n this.labelFontWeight = defaults(p.labelFontWeight, 'bold')\n this.labelsdf = defaults(p.labelsdf, Browser === 'Chrome')\n this.labelXOffset = defaults(p.labelXOffset, 0.0)\n this.labelYOffset = defaults(p.labelYOffset, 0.0)\n this.labelZOffset = defaults(p.labelZOffset, 0.5)\n this.labelAttachment = defaults(p.labelAttachment, 'bottom-left')\n this.labelBorder = defaults(p.labelBorder, false)\n this.labelBorderColor = defaults(p.labelBorderColor, 'lightgrey')\n this.labelBorderWidth = defaults(p.labelBorderWidth, 0.15)\n this.labelBackground = defaults(p.labelBackground, false)\n this.labelBackgroundColor = defaults(p.labelBackgroundColor, 'lightgrey')\n this.labelBackgroundMargin = defaults(p.labelBackgroundMargin, 0.5)\n this.labelBackgroundOpacity = defaults(p.labelBackgroundOpacity, 1.0)\n this.labelFixedSize = defaults(p.labelFixedSize, false)\n this.lineOpacity = defaults(p.lineOpacity, 1.0)\n this.linewidth = defaults(p.linewidth, 2)\n\n super.init(p)\n }\n\n // All measurements need to rebuild on position change\n update (what: LabelDataField) {\n if (what.position) {\n this.build()\n } else {\n super.update(what)\n }\n }\n\n updateData (what: LabelDataField & {[k: string]: any}, data: any) {\n const textData: TextBufferData | {} = {}\n if (!what || what.labelSize) {\n Object.assign(textData, {size: uniformArray(this.n, this.labelSize)})\n }\n\n if (!what || what.labelColor) {\n const c = new Color(this.labelColor)\n Object.assign(textData, {color: uniformArray3(this.n, c.r, c.g, c.b)})\n }\n\n this.textBuffer.setAttributes(textData as TextBufferData)\n }\n\n setParameters (params: Partial, what: LabelDataField = {}, rebuild = false) {\n if (params && params.labelSize) {\n what.labelSize = true\n }\n\n if (params && (params.labelColor || params.labelColor === 0x000000)) {\n what.labelColor = true\n rebuild = true\n }\n\n super.setParameters(params, what, rebuild)\n\n if (params && params.opacity !== undefined) {\n this.textBuffer.setParameters({ opacity: 1.0 }) // only opaque labels\n }\n\n if (params && params.labelVisible !== undefined) {\n this.setVisibility(this.visible)\n }\n\n return this\n }\n\n setVisibility (value: boolean, noRenderRequest?: boolean) {\n super.setVisibility(value, true)\n if (this.textBuffer) {\n this.textBuffer.setVisibility(\n this.labelVisible && this.visible\n )\n }\n\n if (!noRenderRequest) this.viewer.requestRender()\n\n return this\n }\n\n getLabelBufferParams (params: Partial = {}) {\n return super.getBufferParams(Object.assign({\n fontFamily: this.labelFontFamily,\n fontStyle: this.labelFontStyle,\n fontWeight: this.labelFontWeight,\n sdf: this.labelsdf,\n xOffset: this.labelXOffset,\n yOffset: this.labelYOffset,\n zOffset: this.labelZOffset,\n attachment: this.labelAttachment,\n showBorder: this.labelBorder,\n borderColor: this.labelBorderColor,\n borderWidth: this.labelBorderWidth,\n showBackground: this.labelBackground,\n backgroundColor: this.labelBackgroundColor,\n backgroundMargin: this.labelBackgroundMargin,\n backgroundOpacity: this.labelBackgroundOpacity,\n fixedSize: this.labelFixedSize,\n disablePicking: true,\n visible: this.labelVisible\n }, params, {\n opacity: 1.0 // only opaque labels\n }))\n }\n\n getAtomRadius () {\n return 0\n }\n}\n\n/**\n * MeasurementRepresentations take atom[Pair|Triple|Quad] parameters.\n *\n * Parses nested array of either integer atom indices or selection\n * expressions into a flat array of coordinates.\n *\n * @param {Structure} sview The structure to which the atoms refer\n * @param {Array} atoms Nested array of atom pairs|triples|quads as\n * Integer indices or selection expressions\n * @return {Float32Array} Flattened array of position coordinates\n */\nfunction parseNestedAtoms (sview: StructureView, atoms: (number|string)[][]) {\n const ap = sview.getAtomProxy()\n const sele = new Selection()\n\n const nSets = atoms.length\n if (nSets === 0) return new Float32Array(0)\n\n // Peek-ahead at first item to determine order and parse mode\n const order = atoms[ 0 ].length\n const selected = sview.getAtomSet()\n\n const a = new Float32Array(nSets * order * 3)\n\n let p = 0\n atoms.forEach(function (group) {\n let _break = false\n for (let j = 0; j < order; j++) {\n const value = group[ j ]\n if (typeof (value) === 'number' && Number.isInteger(value)) {\n if (selected.get(value)) {\n ap.index = value\n } else {\n _break = true\n break\n }\n } else {\n sele.setString(value as string)\n const atomIndices = sview.getAtomIndices(sele)\n if (atomIndices!.length) {\n ap.index = atomIndices![ 0 ]\n } else {\n _break = true\n break\n }\n }\n\n let offset = p + j * 3\n a[ offset++ ] = ap.x\n a[ offset++ ] = ap.y\n a[ offset++ ] = ap.z\n }\n if (!_break) p += 3 * order\n })\n\n return a.subarray(0, p)\n}\n\n/* out = v1 * cos(angle) + v2 * sin(angle) */\nfunction calcArcPoint (out: Float32Array, center: Float32Array, v1: Float32Array, v2: Float32Array, angle: number) {\n const x = Math.cos(angle)\n const y = Math.sin(angle)\n out[ 0 ] = center[ 0 ] + v1[ 0 ] * x + v2[ 0 ] * y\n out[ 1 ] = center[ 1 ] + v1[ 1 ] * x + v2[ 1 ] * y\n out[ 2 ] = center[ 2 ] + v1[ 2 ] * x + v2[ 2 ] * y\n}\n\nexport {\n MeasurementRepresentation as default,\n calcArcPoint,\n parseNestedAtoms\n}\n","/**\n * @file Edt\n * @author Alexander Rose \n * @private\n */\n\nimport { NumberArray } from '../types'\n\n// 2D Euclidean distance transform by Felzenszwalb & Huttenlocher https://cs.brown.edu/~pff/papers/dt-final.pdf\nexport function edt(data: NumberArray, width: number, height: number, f: NumberArray, d: NumberArray, v: NumberArray, z: NumberArray) {\n for (let x = 0; x < width; x++) {\n for (let y = 0; y < height; y++) {\n f[y] = data[y * width + x]\n }\n edt1d(f, d, v, z, height)\n for (let y = 0; y < height; y++) {\n data[y * width + x] = d[y]\n }\n }\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n f[x] = data[y * width + x]\n }\n edt1d(f, d, v, z, width)\n for (let x = 0; x < width; x++) {\n data[y * width + x] = Math.sqrt(d[x])\n }\n }\n}\n\n// 1D squared distance transform\nfunction edt1d(f: NumberArray, d: NumberArray, v: NumberArray, z: NumberArray, n: number) {\n v[0] = 0\n z[0] = Number.MIN_SAFE_INTEGER\n z[1] = Number.MAX_SAFE_INTEGER\n\n for (let q = 1, k = 0; q < n; q++) {\n let s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k])\n while (s <= z[k]) {\n k--\n s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k])\n }\n k++\n v[k] = q\n z[k] = s\n z[k + 1] = Number.MAX_SAFE_INTEGER\n }\n\n for (let q = 0, k = 0; q < n; q++) {\n while (z[k + 1] < q) k++\n d[q] = (q - v[k]) * (q - v[k]) + f[v[k]]\n }\n}\n","/**\n * @file Text Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3, Matrix4 required for declaration only\nimport { Color, CanvasTexture, Vector3, Matrix4 } from 'three'\n\nimport '../shader/SDFFont.vert'\nimport '../shader/SDFFont.frag'\n\nimport { BufferRegistry } from '../globals'\nimport { createParams } from '../utils'\nimport MappedQuadBuffer from './mappedquad-buffer'\nimport { IgnorePicker } from '../utils/picker'\nimport { edt } from '../utils/edt'\nimport { BufferDefaultParameters, BufferParameterTypes, BufferData, BufferTypes, BufferParameters } from './buffer'\nimport { GenericColor } from '../types'\n\nconst TextAtlasCache: { [k: string]: TextAtlas } = {}\n\nfunction getTextAtlas (params: Partial) {\n const hash = JSON.stringify(params)\n if (TextAtlasCache[ hash ] === undefined) {\n TextAtlasCache[ hash ] = new TextAtlas(params)\n }\n return TextAtlasCache[ hash ]\n}\n\ntype TextFonts = 'sans-serif'|'monospace'|'serif'\ntype TextStyles = 'normal'|'italic'\ntype TextVariants = 'normal'\ntype TextWeights = 'normal'|'bold'\n\nexport const TextAtlasDefaultParams = {\n font: 'sans-serif' as TextFonts,\n size: 36,\n style: 'normal' as TextStyles,\n variant: 'normal' as TextVariants,\n weight: 'normal' as TextWeights,\n outline: 3,\n width: 1024,\n height: 1024\n}\nexport type TextAtlasParams = typeof TextAtlasDefaultParams\n\nexport type TextAtlasMap = { x: number, y: number, w: number, h: number }\n\nexport class TextAtlas {\n parameters: TextAtlasParams\n\n gamma = 1\n mapped: { [k: string]: TextAtlasMap } = {}\n scratchW = 0\n scratchH = 0\n currentX = 0\n currentY = 0\n\n cutoff = 0.25\n padding: number\n radius: number\n\n gridOuter: Float64Array\n gridInner: Float64Array\n f: Float64Array\n d: Float64Array\n z: Float64Array\n v: Int16Array\n\n paddedSize: number\n middle: number\n\n texture: CanvasTexture\n canvas: HTMLCanvasElement\n context: CanvasRenderingContext2D\n\n lineHeight: number\n maxWidth: number\n colors: string[]\n scratch: Uint8Array\n canvas2: HTMLCanvasElement\n context2: CanvasRenderingContext2D\n data: Uint8Array\n\n placeholder: TextAtlasMap\n\n constructor (params: Partial = {}) {\n this.parameters = createParams(params, TextAtlasDefaultParams)\n const p = this.parameters\n\n this.radius = p.size / 8\n this.padding = p.size / 3\n\n // Prepare line-height with room for outline and descenders/ascenders\n const lineHeight = this.lineHeight = p.size + 2 * p.outline + Math.round(p.size / 4)\n const maxWidth = this.maxWidth = p.width / 4\n\n // Prepare scratch canvas\n const canvas = this.canvas = document.createElement('canvas')\n canvas.width = maxWidth\n canvas.height = lineHeight\n\n const ctx = this.context = this.canvas.getContext('2d', { willReadFrequently: true})!\n ctx.font = `${p.style} ${p.variant} ${p.weight} ${p.size}px ${p.font}`\n ctx.fillStyle = 'black'\n ctx.textAlign = 'left'\n ctx.textBaseline = 'bottom'\n ctx.lineJoin = 'round'\n\n // temporary arrays for the distance transform\n this.gridOuter = new Float64Array(lineHeight * maxWidth)\n this.gridInner = new Float64Array(lineHeight * maxWidth)\n this.f = new Float64Array(Math.max(lineHeight, maxWidth))\n this.d = new Float64Array(Math.max(lineHeight, maxWidth))\n this.z = new Float64Array(Math.max(lineHeight, maxWidth) + 1)\n this.v = new Int16Array(Math.max(lineHeight, maxWidth))\n\n //\n this.data = new Uint8Array(p.width * p.height * 4)\n this.canvas2 = document.createElement('canvas')\n this.canvas2.width = p.width\n this.canvas2.height = p.height\n this.context2 = this.canvas2.getContext('2d')!\n\n // Replacement Character\n this.placeholder = this.map(String.fromCharCode(0xFFFD))\n\n // Basic Latin (subset)\n for (let i = 0x0020; i <= 0x007E; ++i) {\n this.map(String.fromCharCode(i))\n }\n\n // TODO: to slow to always prepare them\n // // Latin-1 Supplement (subset)\n // for (let i = 0x00A1; i <= 0x00FF; ++i) {\n // this.map(String.fromCharCode(i))\n // }\n\n // Degree sign\n this.map(String.fromCharCode(0x00B0))\n\n // // Greek and Coptic (subset)\n // for (let i = 0x0391; i <= 0x03C9; ++i) {\n // this.map(String.fromCharCode(i))\n // }\n\n // // Cyrillic (subset)\n // for (let i = 0x0400; i <= 0x044F; ++i) {\n // this.map(String.fromCharCode(i))\n // }\n\n // Angstrom Sign\n this.map(String.fromCharCode(0x212B))\n\n this.texture = new CanvasTexture(this.canvas2)\n this.texture.flipY = false\n this.texture.needsUpdate = true\n }\n\n map (text: string) {\n const p = this.parameters\n\n if (this.mapped[ text ] === undefined) {\n this.draw(text)\n\n if (this.currentX + this.scratchW > p.width) {\n this.currentX = 0\n this.currentY += this.scratchH\n }\n if (this.currentY + this.scratchH > p.height) {\n console.warn('canvas to small')\n }\n\n this.mapped[ text ] = {\n x: this.currentX,\n y: this.currentY,\n w: this.scratchW,\n h: this.scratchH\n }\n\n this.context2.drawImage(\n this.canvas,\n 0, 0,\n this.scratchW, this.scratchH,\n this.currentX, this.currentY,\n this.scratchW, this.scratchH\n )\n\n this.currentX += this.scratchW\n }\n\n return this.mapped[ text ]\n }\n\n get (text: string) {\n return this.mapped[ text ] || this.placeholder\n }\n\n draw (text: string) {\n const p = this.parameters\n\n const h = this.lineHeight\n const o = p.outline\n const ctx = this.context\n // const dst = this.scratch\n const max = this.maxWidth\n // const colors = this.colors\n\n // Bottom aligned, take outline into account\n const x = o\n const y = h - p.outline\n\n // Measure text\n const m = ctx.measureText(text)\n const w = Math.min(max, Math.ceil(m.width + 2 * x + 1))\n\n const n = w * h\n\n // Clear scratch area\n ctx.clearRect(0, 0, w, h)\n\n // Draw text\n ctx.fillText(text, x, y)\n\n const imageData = ctx.getImageData(0, 0, w, h)\n const data = imageData.data\n\n for (let i = 0; i < n; i++) {\n const a = imageData.data[i * 4 + 3] / 255; // alpha value\n this.gridOuter[i] = a === 1 ? 0 : a === 0 ? Number.MAX_SAFE_INTEGER : Math.pow(Math.max(0, 0.5 - a), 2);\n this.gridInner[i] = a === 1 ? Number.MAX_SAFE_INTEGER : a === 0 ? 0 : Math.pow(Math.max(0, a - 0.5), 2);\n }\n\n edt(this.gridOuter, w, h, this.f, this.d, this.v, this.z);\n edt(this.gridInner, w, h, this.f, this.d, this.v, this.z);\n\n for (let i = 0; i < n; i++) {\n const d = this.gridOuter[i] - this.gridInner[i];\n data[i * 4 + 3] = Math.max(0, Math.min(255, Math.round(255 - 255 * (d / this.radius + this.cutoff))));\n }\n\n ctx.putImageData(imageData, 0, 0)\n this.scratchW = w\n this.scratchH = h\n }\n}\n\n/**\n * Text buffer parameter object.\n * @typedef {Object} TextBufferParameters - text buffer parameters\n *\n * @property {Float} opacity - translucency: 1 is fully opaque, 0 is fully transparent\n * @property {Integer} clipNear - position of camera near/front clipping plane\n * in percent of scene bounding box\n * @property {String} labelType - type of the label, one of:\n * \"atomname\", \"atomindex\", \"occupancy\", \"bfactor\",\n * \"serial\", \"element\", \"atom\", \"resname\", \"resno\",\n * \"res\", \"text\", \"qualified\". When set to \"text\", the\n * `labelText` list is used.\n * @property {String[]} labelText - list of label strings, must set `labelType` to \"text\"\n * to take effect\n * @property {String} fontFamily - font family, one of: \"sans-serif\", \"monospace\", \"serif\"\n * @property {String} fontStyle - font style, \"normal\" or \"italic\"\n * @property {String} fontWeight - font weight, \"normal\" or \"bold\"\n * @property {Float} xOffset - offset in x-direction\n * @property {Float} yOffset - offset in y-direction\n * @property {Float} zOffset - offset in z-direction (i.e. in camera direction)\n * @property {String} attachment - attachment of the label, one of:\n * \"bottom-left\", \"bottom-center\", \"bottom-right\",\n * \"middle-left\", \"middle-center\", \"middle-right\",\n * \"top-left\", \"top-center\", \"top-right\"\n * @property {Boolean} showBorder - show border/outline\n * @property {Color} borderColor - color of the border/outline\n * @property {Float} borderWidth - width of the border/outline\n * @property {Boolean} showBackground - show background rectangle\n * @property {Color} backgroundColor - color of the background\n * @property {Float} backgroundMargin - width of the background\n * @property {Float} backgroundOpacity - opacity of the background\n * @property {Boolean} fixedSize - show text with a fixed pixel size\n */\n\nexport interface TextBufferData extends BufferData {\n size: Float32Array\n text: string[]\n}\n\ntype TextAttachments = 'bottom-left'|'bottom-center'|'bottom-right'|'middle-left'|'middle-center'|'middle-right'|'top-left'|'top-center'|'top-right'\n\nexport const TextBufferDefaultParameters = Object.assign({\n fontFamily: 'sans-serif' as TextFonts,\n fontStyle: 'normal' as TextStyles,\n fontWeight: 'bold' as TextWeights,\n fontSize: 36,\n xOffset: 0.0,\n yOffset: 0.0,\n zOffset: 0.5,\n attachment: 'bottom-left' as TextAttachments,\n showBorder: false,\n borderColor: 'lightgrey' as number|string,\n borderWidth: 0.15,\n showBackground: false,\n backgroundColor: 'lightgrey' as number|string,\n backgroundMargin: 0.5,\n backgroundOpacity: 1.0,\n forceTransparent: true,\n fixedSize: false\n}, BufferDefaultParameters)\nexport type TextBufferParameters = BufferParameters & {\n fontFamily: TextFonts,\n fontStyle: TextStyles,\n fontWeight: TextWeights,\n fontSize: number,\n xOffset: number,\n yOffset: number,\n zOffset: number,\n attachment: TextAttachments,\n showBorder: boolean,\n borderColor: GenericColor,\n borderWidth: number,\n showBackground: boolean,\n backgroundColor: GenericColor,\n backgroundMargin: number,\n backgroundOpacity: number,\n forceTransparent: boolean,\n fixedSize: boolean\n}\n\nconst TextBufferParameterTypes = Object.assign({\n fontFamily: { uniform: true },\n fontStyle: { uniform: true },\n fontWeight: { uniform: true },\n fontSize: { uniform: true },\n xOffset: { uniform: true },\n yOffset: { uniform: true },\n zOffset: { uniform: true },\n showBorder: { uniform: true },\n borderColor: { uniform: true },\n borderWidth: { uniform: true },\n backgroundColor: { uniform: true },\n backgroundOpacity: { uniform: true },\n fixedSize: { updateShader: true }\n}, BufferParameterTypes)\n\nfunction getCharCount (data: TextBufferData, params: Partial) {\n const n = data.position!.length / 3\n let charCount = 0\n for (let i = 0; i < n; ++i) {\n charCount += data.text[ i ].length\n }\n if (params.showBackground) charCount += n\n\n return charCount\n}\n\n/**\n * Text buffer. Renders screen-aligned text strings.\n *\n * @example\n * var textBuffer = new TextBuffer({\n * position: new Float32Array([ 0, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * size: new Float32Array([ 2 ]),\n * text: [ \"Hello\" ]\n * });\n */\nclass TextBuffer extends MappedQuadBuffer {\n parameterTypes = TextBufferParameterTypes\n get defaultParameters() { return TextBufferDefaultParameters }\n parameters: TextBufferParameters\n\n alwaysTransparent = true\n hasWireframe = false\n isText = true\n vertexShader = 'SDFFont.vert'\n fragmentShader = 'SDFFont.frag'\n\n text: string[]\n positionCount: number\n texture: CanvasTexture\n textAtlas: TextAtlas\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.size - sizes\n * @param {String[]} data.text - text strings\n * @param {TextBufferParameters} params - parameters object\n */\n constructor (data: TextBufferData, params: Partial = {}) {\n super({\n position: new Float32Array(getCharCount(data, params) * 3),\n color: new Float32Array(getCharCount(data, params) * 3),\n picking: new IgnorePicker()\n }, params)\n\n this.text = data.text\n this.positionCount = data.position!.length / 3\n\n this.addUniforms({\n 'fontTexture': { value: null },\n 'xOffset': { value: this.parameters.xOffset },\n 'yOffset': { value: this.parameters.yOffset },\n 'zOffset': { value: this.parameters.zOffset },\n 'ortho': { value: false },\n 'showBorder': { value: this.parameters.showBorder },\n 'borderColor': { value: new Color(this.parameters.borderColor as number) },\n 'borderWidth': { value: this.parameters.borderWidth },\n 'backgroundColor': { value: new Color(this.parameters.backgroundColor as number) },\n 'backgroundOpacity': { value: this.parameters.backgroundOpacity },\n 'canvasHeight': { value: 1.0 },\n 'pixelRatio': { value: 1.0 }\n })\n\n this.addAttributes({\n 'inputTexCoord': { type: 'v2', value: null },\n 'inputSize': { type: 'f', value: null }\n })\n\n this.setAttributes(data)\n\n this.makeTexture()\n this.makeMapping()\n }\n\n makeMaterial () {\n super.makeMaterial()\n\n const tex = this.texture\n\n const m = this.material\n m.transparent = true\n m.extensions.derivatives = true\n m.lights = false\n m.uniforms.fontTexture.value = tex\n m.needsUpdate = true\n\n const wm = this.wireframeMaterial\n wm.transparent = true\n wm.extensions.derivatives = true\n wm.lights = false\n wm.uniforms.fontTexture.value = tex\n wm.needsUpdate = true\n\n const pm = this.pickingMaterial\n pm.extensions.derivatives = true\n pm.lights = false\n pm.uniforms.fontTexture.value = tex\n pm.needsUpdate = true\n }\n\n setAttributes (data: Partial = {}) {\n let position, size, color\n let aPosition, inputSize, aColor\n\n const text = this.text\n const attributes = this.geometry.attributes as any // TODO\n\n if (data.position) {\n position = data.position\n aPosition = attributes.position.array\n attributes.position.needsUpdate = true\n }\n\n if (data.size) {\n size = data.size\n inputSize = attributes.inputSize.array\n attributes.inputSize.needsUpdate = true\n }\n\n if (data.color) {\n color = data.color\n aColor = attributes.color.array\n attributes.color.needsUpdate = true\n }\n\n const n = this.positionCount\n\n let j, o\n let iCharAll = 0\n let txt, iChar, nChar\n\n for (let v = 0; v < n; ++v) {\n o = 3 * v\n txt = text[ v ]\n nChar = txt.length\n if (this.parameters.showBackground) nChar += 1\n\n for (iChar = 0; iChar < nChar; ++iChar, ++iCharAll) {\n for (let m = 0; m < 4; m++) {\n j = iCharAll * 4 * 3 + (3 * m)\n\n if (position) {\n aPosition[ j ] = position[ o ]\n aPosition[ j + 1 ] = position[ o + 1 ]\n aPosition[ j + 2 ] = position[ o + 2 ]\n }\n\n if (size) {\n inputSize[ (iCharAll * 4) + m ] = size[ v ]\n }\n\n if (color) {\n aColor[ j ] = color[ o ]\n aColor[ j + 1 ] = color[ o + 1 ]\n aColor[ j + 2 ] = color[ o + 2 ]\n }\n }\n }\n }\n }\n\n makeTexture () {\n this.textAtlas = getTextAtlas({\n font: this.parameters.fontFamily,\n style: this.parameters.fontStyle,\n weight: this.parameters.fontWeight,\n size: this.parameters.fontSize\n })\n\n this.texture = this.textAtlas.texture\n }\n\n makeMapping () {\n const ta = this.textAtlas\n const text = this.text\n const attachment = this.parameters.attachment\n const margin = (ta.lineHeight * this.parameters.backgroundMargin * 0.1) - 10\n\n const attribs = this.geometry.attributes as any // TODO\n const inputTexCoord = attribs.inputTexCoord.array\n const inputMapping = attribs.mapping.array\n\n const n = this.positionCount\n let iCharAll = 0\n let c, i, txt, xadvance, iChar, nChar, xShift, yShift\n\n for (let v = 0; v < n; ++v) {\n txt = text[ v ]\n xadvance = 0\n nChar = txt.length\n\n // calculate width\n for (iChar = 0; iChar < nChar; ++iChar) {\n c = ta.get(txt[ iChar ])\n xadvance += c.w - 2 * ta.parameters.outline\n }\n\n // attachment\n if (attachment.startsWith('top')) {\n yShift = ta.lineHeight / 1.25\n } else if (attachment.startsWith('middle')) {\n yShift = ta.lineHeight / 2.5\n } else {\n yShift = 0 // \"bottom\"\n }\n if (attachment.endsWith('right')) {\n xShift = xadvance\n } else if (attachment.endsWith('center')) {\n xShift = xadvance / 2\n } else {\n xShift = 0 // \"left\"\n }\n xShift += ta.parameters.outline\n yShift += ta.parameters.outline\n\n // background\n if (this.parameters.showBackground) {\n i = iCharAll * 2 * 4\n inputMapping[ i + 0 ] = -ta.lineHeight / 6 - xShift - margin // top left\n inputMapping[ i + 1 ] = ta.lineHeight - yShift + margin\n inputMapping[ i + 2 ] = -ta.lineHeight / 6 - xShift - margin // bottom left\n inputMapping[ i + 3 ] = 0 - yShift - margin\n inputMapping[ i + 4 ] = xadvance + ta.lineHeight / 6 - xShift + 2 * ta.parameters.outline + margin // top right\n inputMapping[ i + 5 ] = ta.lineHeight - yShift + margin\n inputMapping[ i + 6 ] = xadvance + ta.lineHeight / 6 - xShift + 2 * ta.parameters.outline + margin // bottom right\n inputMapping[ i + 7 ] = 0 - yShift - margin\n inputTexCoord[ i + 0 ] = 10\n inputTexCoord[ i + 2 ] = 10\n inputTexCoord[ i + 4 ] = 10\n inputTexCoord[ i + 6 ] = 10\n iCharAll += 1\n }\n\n xadvance = 0\n\n for (iChar = 0; iChar < nChar; ++iChar, ++iCharAll) {\n c = ta.get(txt[ iChar ])\n i = iCharAll * 2 * 4\n\n inputMapping[ i + 0 ] = xadvance - xShift // top left\n inputMapping[ i + 1 ] = c.h - yShift\n inputMapping[ i + 2 ] = xadvance - xShift // bottom left\n inputMapping[ i + 3 ] = 0 - yShift\n inputMapping[ i + 4 ] = xadvance + c.w - xShift // top right\n inputMapping[ i + 5 ] = c.h - yShift\n inputMapping[ i + 6 ] = xadvance + c.w - xShift // bottom right\n inputMapping[ i + 7 ] = 0 - yShift\n\n const texWidth = ta.parameters.width\n const texHeight = ta.parameters.height\n\n const texCoords = [\n c.x / texWidth, c.y / texHeight, // top left\n c.x / texWidth, (c.y + c.h) / texHeight, // bottom left\n (c.x + c.w) / texWidth, c.y / texHeight, // top right\n (c.x + c.w) / texWidth, (c.y + c.h) / texHeight // bottom right\n ]\n inputTexCoord.set(texCoords, i)\n\n xadvance += c.w - 2 * ta.parameters.outline\n }\n }\n\n attribs.inputTexCoord.needsUpdate = true\n attribs.mapping.needsUpdate = true\n }\n\n getDefines (type: BufferTypes) {\n const defines = super.getDefines(type)\n\n if (this.parameters.fixedSize) {\n defines.FIXED_SIZE = 1\n }\n\n return defines\n }\n\n setUniforms (data: any) { // TODO\n if (data && (\n data.fontFamily !== undefined ||\n data.fontStyle !== undefined ||\n data.fontWeight !== undefined ||\n data.fontSize !== undefined\n )) {\n this.makeTexture()\n this.makeMapping()\n this.texture.needsUpdate = true\n data.fontTexture = this.texture\n }\n\n super.setUniforms(data)\n }\n}\n\nBufferRegistry.add('text', TextBuffer)\n\nexport default TextBuffer\n","/**\n * @file Wide Line Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3 required for declaration only\nimport { Vector2, Vector3, Matrix4 } from 'three'\n\nimport '../shader/WideLine.vert'\nimport '../shader/WideLine.frag'\n\nimport { BufferRegistry } from '../globals'\nimport MappedQuadBuffer from './mappedquad-buffer'\nimport { BufferDefaultParameters, BufferParameterTypes, BufferData, BufferParameters } from './buffer'\n\nexport interface WideLineBufferData extends BufferData {\n position1: Float32Array\n position2: Float32Array\n color2: Float32Array\n}\n\nexport const WideLineBufferDefaultParameters = Object.assign({\n linewidth: 2\n}, BufferDefaultParameters)\nexport type WideLineBufferParameters = BufferParameters & { linewidth: number }\n\nconst WideLineBufferParameterTypes = Object.assign({\n linewidth: { uniform: true }\n}, BufferParameterTypes)\n\n/**\n * Wide Line buffer. Draws lines with a fixed width in pixels.\n *\n * @example\n * var lineBuffer = new WideLineBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 1, 1, 1 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * color2: new Float32Array([ 0, 1, 0 ])\n * });\n */\nclass WideLineBuffer extends MappedQuadBuffer {\n parameterTypes = WideLineBufferParameterTypes\n get defaultParameters() { return WideLineBufferDefaultParameters }\n parameters: WideLineBufferParameters\n\n vertexShader = 'WideLine.vert'\n fragmentShader ='WideLine.frag'\n\n constructor (data: Partial, params: Partial = {}) {\n super(data, params)\n\n if (!data.color2 && data.color) data.color2 = data.color\n\n this.addUniforms({\n 'linewidth': { value: this.parameters.linewidth },\n 'resolution': { value: new Vector2() },\n 'projectionMatrixInverse': { value: new Matrix4() }\n })\n\n this.addAttributes({\n 'position1': { type: 'v3', value: null },\n 'position2': { type: 'v3', value: null },\n 'color2': { type: 'c', value: null }\n })\n\n this.setAttributes(data)\n this.makeMapping()\n }\n\n setParameters (params: Partial) {\n super.setParameters(params)\n }\n}\n\nBufferRegistry.add('wideline', WideLineBuffer)\n\nexport default WideLineBuffer\n","/**\n * @file Angle Representation\n * @author Fred Ludlow \n * @private\n */\nimport { Color } from 'three'\n\nimport { RepresentationRegistry } from '../globals'\nimport MeasurementRepresentation, { parseNestedAtoms, calcArcPoint, MeasurementRepresentationParameters, LabelDataField } from './measurement-representation'\nimport { defaults } from '../utils'\n\nimport MeshBuffer from '../buffer/mesh-buffer'\nimport TextBuffer, { TextBufferData, TextBufferParameters } from '../buffer/text-buffer'\nimport WideLineBuffer, { WideLineBufferData } from '../buffer/wideline-buffer'\n\nimport { v3add, v3cross, v3dot, v3fromArray, v3length, v3new,\n v3normalize, v3sub, v3toArray } from '../math/vector-utils'\nimport { copyArray, uniformArray, uniformArray3 } from '../math/array-utils'\nimport { RAD2DEG } from '../math/math-constants'\nimport { getFixedLengthWrappedDashData } from '../geometry/dash'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport { BufferData } from '../buffer/buffer';\nimport { StructureRepresentationData, StructureRepresentationParameters } from './structure-representation';\n\n/**\n * @typedef {Object} AngleRepresentationParameters - angle representation parameters\n * @mixes RepresentationParameters\n * @mixes StructureRepresentationParameters\n * @mixes MeasurementRepresentationParameters\n *\n * @property {String} atomTriple - list of triplets of selection strings\n * or atom indices\n * @property {Boolean} vectorVisible - Indicate the 3 points for each angle by drawing lines 1-2-3\n * @property {Boolean} arcVisible - Show the arc outline for each angle\n * @property {Number} lineOpacity - opacity for the line part of the representation\n * @property {Number} linewidth - width for line part of representation\n * @property {Boolean} sectorVisible - Show the filled arc for each angle\n */\n\nexport interface AngleRepresentationParameters extends MeasurementRepresentationParameters {\n atomTriple: (number|string)[][]\n vectorVisible: boolean\n arcVisible: boolean\n lineOpacity: number\n lineWidth: number\n sectorVisible: boolean\n}\n\n/**\n * Angle representation object\n *\n * Reperesentation consists of four parts, visibility can be set for each\n * label - the text label with the angle size\n * vectors - lines joining the three points\n * sector - triangles representing the angle\n * arc - line bordering the sector\n *\n * @param {Structure} structure - the structure to measure angles in\n * @param {Viewer} viewer - a viewer object\n * @param {AngleRepresentationParameters} params - angle representation parameters\n */\nclass AngleRepresentation extends MeasurementRepresentation {\n protected atomTriple: (number|string)[][]\n protected vectorVisible: boolean\n protected arcVisible: boolean\n protected lineOpacity: number\n protected lineWidth: number\n protected sectorVisible: boolean\n protected vectorBuffer: WideLineBuffer\n arcLength: number\n sectorLength: number\n arcBuffer: WideLineBuffer\n sectorBuffer: MeshBuffer\n\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'angle'\n\n this.parameters = Object.assign({\n atomTriple: {\n type: 'hidden', rebuild: true\n },\n vectorVisible: {\n type: 'boolean', default: true\n },\n arcVisible: {\n type: 'boolean', default: true\n },\n sectorVisible: {\n type: 'boolean', default: true\n }\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.side = defaults(p.side, 'double')\n p.opacity = defaults(p.opacity, 0.5)\n\n this.atomTriple = defaults(p.atomTriple, [])\n this.arcVisible = defaults(p.arcVisible, true)\n this.sectorVisible = defaults(p.sectorVisible, true)\n this.vectorVisible = defaults(p.vectorVisible, true)\n\n super.init(p)\n }\n\n createData (sview: StructureView) {\n if (!sview.atomCount || !this.atomTriple.length) return\n\n const atomPosition = atomTriplePositions(sview, this.atomTriple)\n const angleData = getAngleData(atomPosition)\n const n = this.n = angleData.labelPosition.length / 3\n\n const labelColor = new Color(this.labelColor)\n\n // Create buffers\n this.textBuffer = new TextBuffer({\n position: angleData.labelPosition,\n size: uniformArray(n, this.labelSize),\n color: uniformArray3(n, labelColor.r, labelColor.g, labelColor.b),\n text: angleData.labelText\n } as TextBufferData, this.getLabelBufferParams() as TextBufferParameters)\n\n const c = new Color(this.colorValue)\n\n this.vectorBuffer = new WideLineBuffer(\n getFixedLengthWrappedDashData({\n position1: angleData.vectorPosition1,\n position2: angleData.vectorPosition2,\n color: uniformArray3(2 * n, c.r, c.g, c.b),\n color2: uniformArray3(2 * n, c.r, c.g, c.b)\n } as WideLineBufferData),\n this.getBufferParams({\n linewidth: this.linewidth,\n visible: this.vectorVisible,\n opacity: this.lineOpacity\n })\n )\n\n this.arcLength = angleData.arcPosition1.length / 3\n\n this.arcBuffer = new WideLineBuffer(\n getFixedLengthWrappedDashData({\n position1: angleData.arcPosition1,\n position2: angleData.arcPosition2,\n color: uniformArray3(this.arcLength, c.r, c.g, c.b),\n color2: uniformArray3(this.arcLength, c.r, c.g, c.b)\n } as WideLineBufferData), this.getBufferParams({\n linewidth: this.linewidth,\n visible: this.arcVisible,\n opacity: this.lineOpacity\n }))\n\n this.sectorLength = angleData.sectorPosition.length / 3\n\n this.sectorBuffer = new MeshBuffer({\n position: angleData.sectorPosition,\n color: uniformArray3(this.sectorLength, c.r, c.g, c.b)\n } as BufferData, this.getBufferParams({\n visible: this.sectorVisible\n }))\n\n return {\n bufferList: [\n this.textBuffer,\n this.vectorBuffer,\n this.arcBuffer,\n this.sectorBuffer\n ]\n }\n }\n\n updateData (what: LabelDataField & {color?: boolean}, data: StructureRepresentationData) {\n super.updateData(what, data)\n const vectorData = {}\n const arcData = {}\n const sectorData = {}\n\n if (what.color) {\n const c = new Color(this.colorValue)\n Object.assign(vectorData, {\n color: uniformArray3(this.n * 2, c.r, c.g, c.b),\n color2: uniformArray3(this.n * 2, c.r, c.g, c.b)\n })\n Object.assign(arcData, {\n color: uniformArray3(this.arcLength, c.r, c.g, c.b),\n color2: uniformArray3(this.arcLength, c.r, c.g, c.b)\n })\n Object.assign(sectorData, {\n color: uniformArray3(this.sectorLength, c.r, c.g, c.b)\n })\n }\n\n // if (what.sectorOpacity) {\n // this.sectorBuffer.opacity = what.sectorOpacity\n // }\n\n this.vectorBuffer.setAttributes(vectorData)\n this.arcBuffer.setAttributes(arcData)\n this.sectorBuffer.setAttributes(sectorData)\n }\n\n setParameters (params: Partial) {\n var rebuild = false\n var what = {}\n\n super.setParameters(params, what, rebuild)\n\n if (params && (\n params.vectorVisible !== undefined ||\n params.arcVisible !== undefined ||\n params.sectorVisible !== undefined)) {\n this.setVisibility(this.visible)\n }\n\n if (params && params.lineOpacity) {\n this.vectorBuffer.setParameters({ opacity: params.lineOpacity })\n this.arcBuffer.setParameters({ opacity: params.lineOpacity })\n }\n\n if (params && params.opacity !== undefined) {\n this.vectorBuffer.setParameters({ opacity: this.lineOpacity })\n this.arcBuffer.setParameters({ opacity: this.lineOpacity })\n }\n\n if (params && params.linewidth) {\n this.vectorBuffer.setParameters({ linewidth: params.linewidth })\n this.arcBuffer.setParameters({ linewidth: params.linewidth })\n }\n\n return this\n }\n\n setVisibility (value: boolean, noRenderRequest?: boolean) {\n super.setVisibility(value, true)\n\n if (this.vectorBuffer) {\n this.vectorBuffer.setVisibility(this.vectorVisible && this.visible)\n }\n\n if (this.arcBuffer) {\n this.arcBuffer.setVisibility(this.arcVisible && this.visible)\n }\n\n if (this.sectorBuffer) {\n this.sectorBuffer.setVisibility(this.sectorVisible && this.visible)\n }\n\n if (!noRenderRequest) this.viewer.requestRender()\n\n return this\n }\n}\n\n/**\n * Ensure mid point does not coincide with first or second\n * @param {Float32Array} position 9*nAngle array of coordinates\n * @return {Float32Array} Filtered position array, may be shorter\n */\nfunction validatePositions (position: Float32Array) {\n const include = []\n const n = position.length / 9\n for (let i = 0; i < n; i++) {\n // Check that first point not same as second and that second not same as third\n let okay = true\n for (let j = i; j < i + 3; j += 3) {\n if (position[j] === position[j + 3] &&\n position[j + 1] === position[j + 4] &&\n position[j + 2] === position[j + 5]) {\n okay = false\n }\n }\n if (okay) include.push(i)\n }\n const outPosition = new Float32Array(include.length * 9)\n let outIdx = 0\n include.forEach(function (i) {\n copyArray(position, outPosition, i * 9, outIdx * 9, 9)\n outIdx++\n })\n return outPosition\n}\n\nfunction atomTriplePositions (sview: StructureView, atomTriple: (number|string)[][]) {\n return validatePositions(parseNestedAtoms(sview, atomTriple))\n}\n\n/**\n * Converts triple positions into data required to build various buffers.\n */\nfunction getAngleData (position: Float32Array, params: Partial = {}) {\n const angleStep = defaults(params.angleStep, Math.PI / 90)\n const n = position.length / 9\n const angles = new Float32Array(n)\n const labelPosition = new Float32Array(n * 3)\n const labelText = new Array(n)\n\n const vectorPosition1 = new Float32Array(n * 6) // Two lines per angle\n const vectorPosition2 = new Float32Array(n * 6)\n\n const arcPositionTmp1 = new Array(n) // Start points for arc lines\n const arcPositionTmp2 = new Array(n) // End points for arc lines\n const sectorPositionTmp = new Array(n) // Triangle points\n\n let totalSegments = 0\n\n // Re-used vectors etc\n const p1 = v3new() // Positions of points for each angel\n const p2 = v3new()\n const p3 = v3new()\n const v21 = v3new() // Vectors\n const v23 = v3new()\n const cross = v3new() // Cross product v21xv23\n const cross2 = v3new() // In-plane cross product v21 x (v21 x v23)\n const labelTmp = v3new()\n const arcPoint = v3new()\n\n for (var i = 0; i < n; i++) {\n let p = 9 * i\n v3fromArray(p1, position, p)\n v3fromArray(p2, position, p + 3)\n v3fromArray(p3, position, p + 6)\n\n let v = 6 * i\n v3toArray(p1, vectorPosition1, v)\n v3toArray(p2, vectorPosition2, v)\n v3toArray(p2, vectorPosition1, v + 3)\n v3toArray(p3, vectorPosition2, v + 3)\n\n v3sub(v21, p1, p2)\n v3sub(v23, p3, p2)\n\n v3normalize(v21, v21) // validatePositions ensures valid\n v3normalize(v23, v23)\n\n v3cross(cross, v21, v23)\n const crossLength = v3length(cross)\n const dot = v3dot(v21, v23)\n\n const angle = angles[i] = Math.atan2(crossLength, dot)\n labelText[i] = (RAD2DEG * angle).toFixed(1) + String.fromCharCode(0x00B0)\n\n if (v3length(cross) === 0.0) {\n // Angle exactly 0/180, pick an arbitrary direction\n cross[ 0 ] = 1.0\n cross[ 1 ] = 0.0\n cross[ 2 ] = 0.0\n }\n v3cross(cross2, cross, v21)\n v3normalize(cross2, cross2)\n\n calcArcPoint(labelTmp, p2, v21, cross2, angle / 2.0)\n // TODO: Scale label position?\n v3toArray(labelTmp, labelPosition, 3 * i)\n\n // Build the arc and sector\n\n const nSegments = Math.ceil(angle / angleStep)\n const sectorVertices = new Float32Array(nSegments * 9)\n sectorPositionTmp[ i ] = sectorVertices\n const arcVertices1 = new Float32Array(nSegments * 3)\n const arcVertices2 = new Float32Array(nSegments * 3)\n arcPositionTmp1[ i ] = arcVertices1\n arcPositionTmp2[ i ] = arcVertices2\n\n v3add(arcPoint, p2, v21) // Our initial arc point\n\n const appendArcSection = function (a: number, j: number) {\n const si = j * 9\n const ai = j * 3\n v3toArray(p2, sectorVertices, si)\n v3toArray(arcPoint, sectorVertices, si + 3)\n v3toArray(arcPoint, arcVertices1, ai)\n\n calcArcPoint(arcPoint, p2, v21, cross2, a)\n\n v3toArray(arcPoint, sectorVertices, si + 6)\n v3toArray(arcPoint, arcVertices2, ai)\n }\n\n let j = 0\n for (let a = angleStep; a < angle; a += angleStep) {\n appendArcSection(a, j)\n j++\n }\n appendArcSection(angle, j)\n totalSegments += nSegments\n }\n\n // Flatten nested arrays of arc/segment points\n const arcSize = totalSegments * 3\n const sectorSize = totalSegments * 9\n const arcPosition1 = new Float32Array(arcSize)\n const arcPosition2 = new Float32Array(arcSize)\n const sectorPosition = new Float32Array(sectorSize)\n\n let sectorOffset = 0\n let arcOffset = 0\n for (let i = 0; i < n; i++) {\n const ap1 = arcPositionTmp1[ i ]\n const ap2 = arcPositionTmp2[ i ]\n copyArray(ap1, arcPosition1, 0, arcOffset, ap1.length)\n copyArray(ap2, arcPosition2, 0, arcOffset, ap2.length)\n arcOffset += ap1.length // === ap2.length\n\n const sp = sectorPositionTmp[ i ]\n copyArray(sp, sectorPosition, 0, sectorOffset, sp.length)\n sectorOffset += sp.length\n }\n\n return {\n labelPosition,\n labelText,\n vectorPosition1,\n vectorPosition2,\n arcPosition1,\n arcPosition2,\n sectorPosition\n }\n}\n\nRepresentationRegistry.add('angle', AngleRepresentation)\n\nexport default AngleRepresentation\n","/**\n * @file Cylinder Geometry Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4, Vector3, CylinderGeometry } from 'three'\n\nimport { defaults } from '../utils'\nimport { calculateCenterArray, serialBlockArray } from '../math/array-utils'\nimport GeometryBuffer from './geometry-buffer'\nimport { CylinderBufferData } from './cylinder-buffer'\nimport { BufferDefaultParameters, BufferParameters } from './buffer'\n\nconst scale = new Vector3()\nconst eye = new Vector3()\nconst target = new Vector3()\nconst up = new Vector3(0, 1, 0)\n\nexport const CylinderGeometryBufferDefaultParameters = Object.assign({\n radialSegments: 1,\n openEnded: true\n}, BufferDefaultParameters)\nexport type CylinderGeometryBufferParameters = BufferParameters & {radialSegments: number, openEnded: boolean}\n\nfunction getData (data: CylinderBufferData, params: Partial = {}) {\n const geo = getGeo(params)\n\n const n = data.position1.length\n\n const geoLength = (geo.attributes as any).position.array.length / 3\n const count = n / 3\n const primitiveId = new Float32Array(count * 2 * geoLength)\n serialBlockArray(count, geoLength, 0, primitiveId)\n serialBlockArray(count, geoLength, count * geoLength, primitiveId)\n\n const position = new Float32Array(n * 2)\n const color = new Float32Array(n * 2)\n\n return {\n position, color, primitiveId, picking: data.picking\n }\n}\n\nfunction getGeo (params: Partial = {}) {\n const radialSegments = defaults(params.radialSegments, 10)\n const openEnded = defaults(params.openEnded, true)\n const matrix = new Matrix4().makeRotationX(Math.PI / 2)\n\n const geo = new CylinderGeometry(\n 1, // radiusTop,\n 1, // radiusBottom,\n 1, // height,\n radialSegments, // radialSegments,\n 1, // heightSegments,\n openEnded // openEnded\n )\n geo.applyMatrix4(matrix)\n\n return geo\n}\n\n/**\n * Cylinder geometry buffer.\n *\n * @example\n * var cylinderGeometryBuffer = new CylinderGeometryBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 1, 1, 1 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * color2: new Float32Array([ 0, 1, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n */\nclass CylinderGeometryBuffer extends GeometryBuffer {\n updateNormals = true\n\n get defaultParameters() { return CylinderGeometryBufferDefaultParameters }\n parameters: CylinderGeometryBufferParameters\n\n __center: Float32Array\n _position: Float32Array\n _color: Float32Array\n _from: Float32Array\n _to: Float32Array\n _radius: Float32Array\n\n /**\n * @param {Object} data - buffer data\n * @param {Float32Array} data.position1 - from positions\n * @param {Float32Array} data.position2 - to positions\n * @param {Float32Array} data.color - from colors\n * @param {Float32Array} data.color2 - to colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} [params] - parameters object\n */\n constructor (data: CylinderBufferData, params: Partial = {}) {\n super(getData(data, params), params, getGeo(params))\n\n const n = data.position1.length\n const m = data.radius.length\n\n this.__center = new Float32Array(n)\n this._position = new Float32Array(n * 2)\n this._color = new Float32Array(n * 2)\n this._from = new Float32Array(n * 2)\n this._to = new Float32Array(n * 2)\n this._radius = new Float32Array(m * 2)\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number, i3: number) {\n eye.fromArray(this._from as any, i3)\n target.fromArray(this._to as any, i3)\n matrix.lookAt(eye, target, up)\n\n const r = this._radius[ i ]\n scale.set(r, r, eye.distanceTo(target))\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n const meshData: Partial = {}\n\n if (data.position1 && data.position2) {\n calculateCenterArray(\n data.position1, data.position2, this.__center\n )\n calculateCenterArray(\n data.position1, this.__center, this._position\n )\n calculateCenterArray(\n this.__center, data.position2, this._position, data.position1.length\n )\n this._from.set(data.position1)\n this._from.set(this.__center, data.position1.length)\n this._to.set(this.__center)\n this._to.set(data.position2, this.__center.length)\n meshData.position = this._position\n }\n\n if (data.color && data.color2) {\n this._color.set(data.color)\n this._color.set(data.color2, data.color.length)\n meshData.color = this._color\n }\n\n if (data.radius) {\n this._radius.set(data.radius)\n this._radius.set(data.radius, data.radius.length)\n meshData.radius = this._radius\n }\n\n super.setAttributes(meshData, initNormals)\n }\n}\n\nexport default CylinderGeometryBuffer\n","/**\n * @file Mapped Aligned Box Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { BufferParameters, BufferData } from './buffer'\nimport MappedBuffer from './mapped-buffer'\n\n// +Y /\n// 0**********2\n// * | / **\n// * |/ * *\n// -----------3---- +X\n// * /| * *\n// * / | * *\n// 1/**|******4\n// / | * *\n// / | ** \n// +Z | 5 \nconst mapping = new Float32Array([\n -1.0, 1.0, -1.0,\n -1.0, -1.0, -1.0,\n 1.0, 1.0, -1.0,\n 1.0, 1.0, 1.0,\n 1.0, -1.0, -1.0,\n 1.0, -1.0, 1.0\n])\n\nconst mappingIndices = new Uint16Array([\n 0, 1, 2,\n 1, 4, 2,\n 2, 4, 3,\n 4, 5, 3\n])\n\n/**\n * Mapped Aligned box buffer. Draws boxes where one side is always screen-space aligned.\n * Used to render cylinder imposters.\n * @interface\n */\nclass MappedAlignedBoxBuffer extends MappedBuffer {\n constructor(data: BufferData, params: Partial = {}) {\n super('v3', data, params)\n }\n get mapping () { return mapping }\n get mappingIndices () { return mappingIndices }\n get mappingIndicesSize () { return 12 }\n get mappingSize () { return 6 }\n get mappingItemSize () { return 3 }\n}\n\nexport default MappedAlignedBoxBuffer\n","/**\n * @file Cylinder Impostor Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3 required for declaration only\nimport { Matrix4, Vector3 } from 'three'\n\nimport '../shader/CylinderImpostor.vert'\nimport '../shader/CylinderImpostor.frag'\n\nimport MappedAlignedBoxBuffer from './mappedalignedbox-buffer'\nimport { BufferDefaultParameters, BufferParameters, BufferParameterTypes, BufferTypes } from './buffer'\nimport { CylinderBufferData } from './cylinder-buffer'\n\nexport const CylinderImpostorBufferDefaultParameters = Object.assign({\n openEnded: false\n}, BufferDefaultParameters)\nexport type CylinderImpostorBufferParameters = BufferParameters & { openEnded: boolean }\n\nconst CylinderImpostorBufferParameterTypes = Object.assign({\n openEnded: { updateShader: true }\n}, BufferParameterTypes)\n\n/**\n * Cylinder impostor buffer.\n *\n * @example\n * var cylinderimpostorBuffer = new CylinderImpostorBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 1, 1, 1 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * color2: new Float32Array([ 0, 1, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n */\nclass CylinderImpostorBuffer extends MappedAlignedBoxBuffer {\n parameterTypes = CylinderImpostorBufferParameterTypes\n get defaultParameters() { return CylinderImpostorBufferDefaultParameters }\n parameters: CylinderImpostorBufferParameters\n\n isImpostor = true\n vertexShader = 'CylinderImpostor.vert'\n fragmentShader = 'CylinderImpostor.frag'\n\n /**\n * make cylinder impostor buffer\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position1 - from positions\n * @param {Float32Array} data.position2 - to positions\n * @param {Float32Array} data.color - from colors\n * @param {Float32Array} data.color2 - to colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} data.picking - picking ids\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: CylinderBufferData, params: Partial = {}) {\n super(data, params)\n\n this.addUniforms({\n 'modelViewMatrixInverse': { value: new Matrix4() },\n 'ortho': { value: 0.0 }\n })\n\n this.addAttributes({\n 'position1': { type: 'v3', value: null },\n 'position2': { type: 'v3', value: null },\n 'color2': { type: 'c', value: null },\n 'radius': { type: 'f', value: null }\n })\n\n this.setAttributes(data)\n this.makeMapping()\n }\n\n getDefines (type?: BufferTypes) {\n const defines = MappedAlignedBoxBuffer.prototype.getDefines.call(this, type)\n\n if (!this.parameters.openEnded) {\n defines.CAP = 1\n }\n\n return defines\n }\n}\n\nexport default CylinderImpostorBuffer\n","/**\n * @file Cylinder Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import required for declaration only\nimport { Vector3, Matrix4 } from 'three'\nimport { BufferRegistry, ExtensionFragDepth } from '../globals'\nimport CylinderGeometryBuffer, { CylinderGeometryBufferDefaultParameters, CylinderGeometryBufferParameters } from './cylindergeometry-buffer'\nimport CylinderImpostorBuffer, { CylinderImpostorBufferDefaultParameters, CylinderImpostorBufferParameters } from './cylinderimpostor-buffer'\nimport { BufferData } from './buffer'\n\nexport interface CylinderBufferData extends BufferData {\n position1: Float32Array\n position2: Float32Array\n color2: Float32Array\n radius: Float32Array\n}\n\nexport const CylinderBufferDefaultParameters = Object.assign({\n disableImpostor: false\n}, CylinderGeometryBufferDefaultParameters, CylinderImpostorBufferDefaultParameters)\nexport type CylinderBufferParameters = (CylinderGeometryBufferParameters & {disableImpostor: boolean}) | (CylinderImpostorBufferParameters & {disableImpostor: boolean})\n\nclass CylinderBufferImpl {\n constructor (data: CylinderBufferData, params: Partial = {}) {\n if (!data.color2 && data.color) data.color2 = data.color\n if (!ExtensionFragDepth || (params && params.disableImpostor)) {\n return new CylinderGeometryBuffer(data, params)\n } else {\n return new CylinderImpostorBuffer(data, params)\n }\n }\n}\n\n/**\n * Cylinder buffer. Depending on the value {@link ExtensionFragDepth} and\n * `params.disableImpostor` the constructor returns either a\n * {@link CylinderGeometryBuffer} or a {@link CylinderImpostorBuffer}\n * @implements {Buffer}\n *\n * @example\n * var cylinderBuffer = new CylinderBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 1, 1, 1 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * color2: new Float32Array([ 0, 1, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n */\n//@ts-expect-error Incompatible constructor signatures\nconst CylinderBuffer: {\n new(data: CylinderBufferData, params: Partial): CylinderGeometryBuffer | CylinderImpostorBuffer;\n} = CylinderBufferImpl;\n\ntype CylinderBuffer = CylinderGeometryBuffer | CylinderImpostorBuffer;\n\nBufferRegistry.add('cylinder', CylinderBuffer)\n\nexport default CylinderBuffer\n","/**\n * @file Axes Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { Color, Vector3 } from 'three'\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { AxesPicker } from '../utils/picker'\nimport { uniformArray, uniformArray3 } from '../math/array-utils'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport SphereBuffer, { SphereBufferData, SphereBufferParameters } from '../buffer/sphere-buffer'\nimport CylinderBuffer, { CylinderBufferData } from '../buffer/cylinder-buffer'\nimport StructureView from '../structure/structure-view';\nimport Viewer from '../viewer/viewer';\nimport { Structure } from '../ngl';\nimport { AtomDataFields } from '../structure/structure-data';\nimport SphereGeometryBuffer from '../buffer/spheregeometry-buffer';\nimport CylinderGeometryBuffer from '../buffer/cylindergeometry-buffer';\nimport PrincipalAxes from '../math/principal-axes';\n\nexport interface AxesRepresentationParameters extends StructureRepresentationParameters {\n showAxes: boolean\n showBox: boolean\n}\n\n/**\n * Axes representation. Show principal axes and/or a box aligned with them\n * that fits the structure or selection.\n *\n * __Name:__ _axes_\n *\n * @example\n * stage.loadFile( \"rcsb://3pqr\", {\n * assembly: \"BU1\"\n * } ).then( function( o ){\n * o.addRepresentation( \"cartoon\" );\n * o.addRepresentation( \"axes\", {\n * sele: \"RET\", showAxes: false, showBox: true, radius: 0.2\n * } );\n * o.addRepresentation( \"ball+stick\", { sele: \"RET\" } );\n * o.addRepresentation( \"axes\", {\n * sele: \":B and backbone\", showAxes: false, showBox: true, radius: 0.2\n * } );\n * stage.autoView();\n * var pa = o.structure.getPrincipalAxes();\n * stage.animationControls.rotate( pa.getRotationQuaternion(), 1500 );\n * } );\n */\nclass AxesRepresentation extends StructureRepresentation {\n \n protected showAxes: boolean\n protected showBox: boolean\n protected sphereBuffer: SphereBuffer\n protected cylinderBuffer: CylinderBuffer\n /**\n * @param {Structure} structure - the structure object\n * @param {Viewer} viewer - the viewer object\n * @param {StructureRepresentationParameters} params - parameters object\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'axes'\n\n this.parameters = Object.assign({\n\n radiusSize: {\n type: 'number', precision: 3, max: 10.0, min: 0.001\n },\n sphereDetail: true,\n radialSegments: true,\n disableImpostor: true,\n showAxes: {\n type: 'boolean', rebuild: true\n },\n showBox: {\n type: 'boolean', rebuild: true\n }\n\n }, this.parameters, {\n assembly: null\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.radiusSize = defaults(p.radiusSize, 0.5)\n p.colorValue = defaults(p.colorValue, 'lightgreen')\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n this.showAxes = defaults(p.showAxes, true)\n this.showBox = defaults(p.showBox, false)\n\n super.init(p)\n }\n\n getPrincipalAxes (): PrincipalAxes {\n let selection\n const assembly = this.getAssembly()\n\n if (assembly) {\n selection = assembly.partList[ 0 ].getSelection()\n }\n\n return this.structureView.getPrincipalAxes(selection)\n }\n\n getAxesData (sview: StructureView) {\n const pa = this.getPrincipalAxes()\n const c = new Color(this.colorValue)\n\n let vn = 0\n let en = 0\n\n if (this.showAxes) {\n vn += 6\n en += 3\n }\n\n if (this.showBox) {\n vn += 8\n en += 12\n }\n\n const vertexPosition = new Float32Array(3 * vn)\n const vertexColor = uniformArray3(vn, c.r, c.g, c.b)\n const vertexRadius = uniformArray(vn, this.radiusSize)\n\n const edgePosition1 = new Float32Array(3 * en)\n const edgePosition2 = new Float32Array(3 * en)\n const edgeColor = uniformArray3(en, c.r, c.g, c.b)\n const edgeRadius = uniformArray(en, this.radiusSize)\n\n let offset = 0\n\n if (this.showAxes) {\n const addAxis = function (v1: Vector3, v2: Vector3) {\n v1.toArray(vertexPosition as any, offset * 2)\n v2.toArray(vertexPosition as any, offset * 2 + 3)\n v1.toArray(edgePosition1 as any, offset)\n v2.toArray(edgePosition2 as any, offset)\n offset += 3\n }\n\n addAxis(pa.begA, pa.endA)\n addAxis(pa.begB, pa.endB)\n addAxis(pa.begC, pa.endC)\n }\n\n if (this.showBox) {\n const v = new Vector3()\n const { d1a, d2a, d3a, d1b, d2b, d3b } = pa.getProjectedScaleForAtoms(sview)\n\n // console.log(d1a, d2a, d3a, d1b, d2b, d3b)\n\n let offset2 = offset * 2\n const addCorner = function (d1: number, d2: number, d3: number) {\n v.copy(pa.center)\n .addScaledVector(pa.normVecA, d1)\n .addScaledVector(pa.normVecB, d2)\n .addScaledVector(pa.normVecC, d3)\n v.toArray(vertexPosition as any, offset2)\n offset2 += 3\n }\n addCorner(d1a, d2a, d3a)\n addCorner(d1a, d2a, d3b)\n addCorner(d1a, d2b, d3b)\n addCorner(d1a, d2b, d3a)\n addCorner(d1b, d2b, d3b)\n addCorner(d1b, d2b, d3a)\n addCorner(d1b, d2a, d3a)\n addCorner(d1b, d2a, d3b)\n\n let edgeOffset = offset\n const addEdge = function (a: number, b: number) {\n v.fromArray(vertexPosition as any, offset * 2 + a * 3)\n .toArray(edgePosition1 as any, edgeOffset)\n v.fromArray(vertexPosition as any, offset * 2 + b * 3)\n .toArray(edgePosition2 as any, edgeOffset)\n edgeOffset += 3\n }\n addEdge(0, 1)\n addEdge(0, 3)\n addEdge(0, 6)\n addEdge(1, 2)\n addEdge(1, 7)\n addEdge(2, 3)\n addEdge(2, 4)\n addEdge(3, 5)\n addEdge(4, 5)\n addEdge(4, 7)\n addEdge(5, 6)\n addEdge(6, 7)\n }\n\n const picker = new AxesPicker(pa)\n\n return {\n vertex: {\n position: vertexPosition,\n color: vertexColor,\n radius: vertexRadius,\n picking: picker\n },\n edge: {\n position1: edgePosition1,\n position2: edgePosition2,\n color: edgeColor,\n color2: edgeColor,\n radius: edgeRadius,\n picking: picker\n }\n }\n }\n\n create () {\n const axesData = this.getAxesData(this.structureView)\n\n this.sphereBuffer = new SphereBuffer(\n axesData.vertex as SphereBufferData,\n this.getBufferParams({\n sphereDetail: this.sphereDetail,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n }) as SphereBufferParameters\n )\n\n this.cylinderBuffer = new CylinderBuffer(\n axesData.edge as CylinderBufferData,\n this.getBufferParams({\n openEnded: true,\n radialSegments: this.radialSegments,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n })\n )\n\n this.dataList.push({\n sview: this.structureView,\n bufferList: [ this.sphereBuffer as SphereGeometryBuffer, this.cylinderBuffer as CylinderGeometryBuffer]\n })\n }\n\n createData (sview: StructureView): undefined {\n return\n }\n\n updateData (what: AtomDataFields, data: StructureRepresentationData) {\n const axesData = this.getAxesData(data.sview as StructureView)\n const sphereData = {}\n const cylinderData = {}\n\n if (!what || what.position) {\n Object.assign(sphereData, {\n position: axesData.vertex.position\n })\n Object.assign(cylinderData, {\n position1: axesData.edge.position1,\n position2: axesData.edge.position2\n })\n }\n\n if (!what || what.color) {\n Object.assign(sphereData, {\n color: axesData.vertex.color as Float32Array\n })\n Object.assign(cylinderData, {\n color: axesData.edge.color as Float32Array,\n color2: axesData.edge.color as Float32Array\n })\n }\n\n if (!what || what.radius) {\n Object.assign(sphereData, {\n radius: axesData.vertex.radius as Float32Array\n })\n Object.assign(cylinderData, {\n radius: axesData.edge.radius as Float32Array\n })\n }\n\n (this.sphereBuffer as SphereGeometryBuffer).setAttributes(sphereData);\n (this.cylinderBuffer as CylinderGeometryBuffer).setAttributes(cylinderData)\n }\n}\n\nRepresentationRegistry.add('axes', AxesRepresentation)\n\nexport default AxesRepresentation\n","/**\n * @file Ball And Stick Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport { ExtensionFragDepth, RepresentationRegistry } from '../globals'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport SphereBuffer, { SphereBufferData, SphereBufferParameters } from '../buffer/sphere-buffer'\nimport CylinderBuffer, { CylinderBufferData } from '../buffer/cylinder-buffer'\nimport WideLineBuffer from '../buffer/wideline-buffer'\nimport Viewer from '../viewer/viewer';\n// @ts-ignore: unused import Volume required for declaration only\nimport { Structure, Volume } from '../ngl';\nimport AtomProxy from '../proxy/atom-proxy';\nimport { AtomDataParams, BondDataParams, BondDataFields, AtomDataFields, BondData, AtomData } from '../structure/structure-data';\nimport StructureView from '../structure/structure-view';\nimport CylinderGeometryBuffer from '../buffer/cylindergeometry-buffer';\nimport SphereGeometryBuffer from '../buffer/spheregeometry-buffer';\n// @ts-ignore: unused import Surface required for declaration only\nimport Surface from '../surface/surface';\n\nexport interface BallAndStickRepresentationParameters extends StructureRepresentationParameters {\n sphereDetail: number\n radialSegments: number\n openEnded: boolean\n disableImpostor: boolean\n aspectRatio: number\n lineOnly: boolean\n lineWidth: number\n cylinderOnly: boolean\n multipleBond: 'off' | 'symmetric' | 'offset'\n bondSpacing: number\n bondScale: number\n linewidth: number\n}\n\n/**\n * Ball And Stick representation parameter object. Extends {@link RepresentationParameters} and\n * {@link StructureRepresentationParameters}.\n *\n * @typedef {Object} BallAndStickRepresentationParameters - ball and stick representation parameters\n *\n * @property {Integer} sphereDetail - sphere quality (icosahedron subdivisions)\n * @property {Integer} radialSegments - cylinder quality (number of segments)\n * @property {Boolean} openEnded - capped or not\n * @property {Boolean} disableImpostor - disable use of raycasted impostors for rendering\n * @property {Float} aspectRatio - size difference between atom and bond radii\n * @property {Boolean} lineOnly - render only bonds, and only as lines\n * @property {Integer} linewidth - width of lines\n * @property {Boolean} cylinderOnly - render only bonds (no atoms)\n * @property {String} multipleBond - one off \"off\", \"symmetric\", \"offset\"\n * @property {Float} bondSpacing - spacing for multiple bond rendering\n * @property {Float} bondScale - scale/radius for multiple bond rendering\n */\n\n/**\n * Ball And Stick representation. Show atoms as spheres and bonds as cylinders.\n *\n * __Name:__ _ball+stick_\n *\n * @example\n * stage.loadFile( \"rcsb://1crn\" ).then( function( o ){\n * o.addRepresentation( \"ball+stick\" );\n * o.autoView();\n * } );\n */\nclass BallAndStickRepresentation extends StructureRepresentation {\n protected sphereDetail: number\n protected radialSegments: number\n protected openEnded: boolean\n protected disableImpostor: boolean\n protected aspectRatio: number\n protected lineOnly: boolean\n protected lineWidth: number\n protected cylinderOnly: boolean\n protected multipleBond: 'off' | 'symmetric' | 'offset'\n protected bondSpacing: number\n protected bondScale: number\n protected linewidth: number\n\n protected lineBuffer: WideLineBuffer\n /**\n * Create Ball And Stick representation object\n * @param {Structure} structure - the structure to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {BallAndStickRepresentationParameters} params - ball and stick representation parameters\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'ball+stick'\n\n this.parameters = Object.assign({\n\n sphereDetail: true,\n radialSegments: true,\n openEnded: true,\n disableImpostor: true,\n aspectRatio: {\n type: 'number', precision: 1, max: 10.0, min: 1.0\n },\n lineOnly: {\n type: 'boolean', rebuild: true\n },\n cylinderOnly: {\n type: 'boolean', rebuild: true\n },\n multipleBond: {\n type: 'select',\n rebuild: true,\n options: {\n 'off': 'off',\n 'symmetric': 'symmetric',\n 'offset': 'offset'\n }\n },\n bondScale: {\n type: 'number', precision: 2, max: 1.0, min: 0.01\n },\n bondSpacing: {\n type: 'number', precision: 2, max: 2.0, min: 0.5\n },\n linewidth: {\n type: 'integer', max: 50, min: 1, buffer: true\n }\n\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.radiusType = defaults(p.radiusType, 'size')\n p.radiusSize = defaults(p.radiusSize, 0.15)\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n this.aspectRatio = defaults(p.aspectRatio, 2.0)\n this.lineOnly = defaults(p.lineOnly, false)\n this.cylinderOnly = defaults(p.cylinderOnly, false)\n this.multipleBond = defaults(p.multipleBond, 'off')\n this.bondSpacing = defaults(p.bondSpacing, 1.0)\n this.bondScale = defaults(p.bondScale, 0.4)\n this.linewidth = defaults(p.linewidth, 2)\n\n super.init(p)\n }\n\n getAtomRadius (atom: AtomProxy) {\n return this.aspectRatio * super.getAtomRadius(atom)\n }\n\n getAtomParams (what?: AtomDataFields, params?: Partial) {\n var p = super.getAtomParams(what, params)\n p.radiusParams.scale *= this.aspectRatio\n\n return p\n }\n\n getAtomData (sview: StructureView, what?: AtomDataFields, params?: Partial): AtomData {\n return sview.getAtomData(this.getAtomParams(what, params))\n }\n\n getBondParams (what?: BondDataFields, params?: Partial) {\n params = Object.assign({\n multipleBond: this.multipleBond,\n bondSpacing: this.bondSpacing,\n bondScale: this.bondScale\n }, params)\n\n return super.getBondParams(what, params)\n }\n\n getBondData (sview: StructureView, what?: BondDataFields, params?: Partial): BondData {\n return sview.getBondData(this.getBondParams(what, params))\n }\n\n createData (sview: StructureView) {\n const bufferList: any[] = []\n\n if (this.lineOnly) {\n this.lineBuffer = new WideLineBuffer(\n this.getBondData(sview, { position: true, color: true, picking: true }),\n this.getBufferParams({ linewidth: this.linewidth })\n )\n\n bufferList.push(this.lineBuffer)\n } else {\n const cylinderBuffer = new CylinderBuffer(\n (this.getBondData(sview) as CylinderBufferData),\n this.getBufferParams({\n openEnded: this.openEnded,\n radialSegments: this.radialSegments,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n })\n )\n\n bufferList.push(cylinderBuffer as CylinderGeometryBuffer)\n\n if (!this.cylinderOnly) {\n const sphereBuffer = new SphereBuffer(\n (this.getAtomData(sview) as SphereBufferData),\n (this.getBufferParams({\n sphereDetail: this.sphereDetail,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n }) as SphereBufferParameters)\n )\n\n bufferList.push(sphereBuffer as SphereGeometryBuffer)\n }\n }\n\n return {\n bufferList: bufferList\n }\n }\n\n updateData (what: BondDataFields | AtomDataFields, data: StructureRepresentationData) {\n if (this.multipleBond !== 'off' && what && what.radius) {\n what.position = true\n }\n\n const bondData = this.getBondData(data.sview as StructureView, what)\n\n if (this.lineOnly) {\n const lineData:Partial = {}\n\n if (!what || what.position) {\n Object.assign(lineData, {\n position1: bondData.position1,\n position2: bondData.position2\n })\n }\n\n if (!what || what.color) {\n Object.assign(lineData, {\n color: bondData.color,\n color2: bondData.color2\n })\n }\n\n data.bufferList[ 0 ].setAttributes(lineData)\n } else {\n var cylinderData: Partial = {}\n\n if (!what || what.position) {\n Object.assign(cylinderData, {\n position1: bondData.position1,\n position2: bondData.position2\n })\n }\n\n if (!what || what.color) {\n Object.assign(cylinderData, {\n color: bondData.color,\n color2: bondData.color2\n })\n }\n\n if (!what || what.radius) {\n Object.assign(cylinderData, {\n radius: bondData.radius\n })\n }\n\n data.bufferList[ 0 ].setAttributes(cylinderData)\n\n if (!this.cylinderOnly) {\n var atomData = this.getAtomData(data.sview as StructureView, what)\n\n var sphereData: Partial = {}\n\n if (!what || what.position) {\n Object.assign(sphereData, {\n position: atomData.position\n })\n }\n\n if (!what || what.color) {\n Object.assign(sphereData, {\n color: atomData.color\n })\n }\n\n if (!what || what.radius) {\n Object.assign(sphereData, {\n radius: atomData.radius\n })\n }\n\n data.bufferList[ 1 ].setAttributes(sphereData)\n }\n }\n }\n\n setParameters (params: Partial = {}) {\n let rebuild = false\n const what: AtomDataFields = {}\n\n if (params.aspectRatio || params.bondSpacing || params.bondScale) {\n Object.assign(what, {radius: true})\n if (!ExtensionFragDepth || this.disableImpostor) {\n rebuild = true\n }\n }\n\n super.setParameters(params, what, rebuild)\n\n return this\n }\n}\n\nRepresentationRegistry.add('ball+stick', BallAndStickRepresentation)\n\nexport default BallAndStickRepresentation\n","/**\n * @file Backbone Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport BallAndStickRepresentation, { BallAndStickRepresentationParameters } from './ballandstick-representation'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport AtomProxy from '../proxy/atom-proxy';\nimport StructureView from '../structure/structure-view';\nimport { AtomDataFields, AtomDataParams, BondDataFields, BondDataParams, BondData, AtomData } from '../structure/structure-data';\n\n/**\n * Backbone representation. Show cylinders (or lines) connecting .CA (protein)\n * or .C4'/.C3' (RNA/DNA) of polymers.\n *\n * __Name:__ _backbone_\n *\n * @example\n * stage.loadFile( \"rcsb://1sfi\" ).then( function( o ){\n * o.addRepresentation( \"backbone\" );\n * o.autoView();\n * } );\n */\nclass BackboneRepresentation extends BallAndStickRepresentation {\n /**\n * @param {Structure} structure - the structure object\n * @param {Viewer} viewer - the viewer object\n * @param {BallAndStickRepresentationParameters} params - parameters object\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'backbone'\n\n this.parameters = Object.assign({\n\n }, this.parameters, {\n\n multipleBond: null,\n bondSpacing: null\n\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.aspectRatio = defaults(p.aspectRatio, 1.0)\n p.radiusSize = defaults(p.radiusSize, 0.25)\n\n super.init(p)\n }\n\n getAtomRadius (atom: AtomProxy) {\n return atom.isTrace() ? super.getAtomRadius(atom) : 0\n }\n\n getAtomData (sview: StructureView, what?: AtomDataFields, params?: Partial): AtomData {\n return sview.getBackboneAtomData(this.getAtomParams(what, params))\n }\n\n getBondData (sview: StructureView, what?: BondDataFields, params?: Partial): BondData {\n return sview.getBackboneBondData(this.getBondParams(what, params))\n }\n}\n\nRepresentationRegistry.add('backbone', BackboneRepresentation)\n\nexport default BackboneRepresentation\n","/**\n * @file Base Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport BallAndStickRepresentation, { BallAndStickRepresentationParameters } from './ballandstick-representation'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport { AtomDataFields, AtomDataParams, BondDataFields, BondDataParams, BondData, AtomData } from '../structure/structure-data';\n\n/**\n * Base representation. Show cylinders for RNA/DNA ladders.\n *\n * __Name:__ _base_\n *\n * @example\n * stage.loadFile( \"rcsb://1d66\" ).then( function( o ){\n * o.addRepresentation( \"cartoon\", { sele: \"nucleic\" } );\n * o.addRepresentation( \"base\", { color: \"resname\" } );\n * o.autoView( \"nucleic\" );\n * } );\n */\nclass BaseRepresentation extends BallAndStickRepresentation {\n /**\n * @param {Structure} structure - the structure object\n * @param {Viewer} viewer - the viewer object\n * @param {BallAndStickRepresentationParameters} params - parameters object\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'base'\n\n this.parameters = Object.assign({\n\n }, this.parameters, {\n\n multipleBond: null,\n bondSpacing: null\n\n })\n }\n\n init (params: Partial) {\n let p = params || {}\n p.aspectRatio = defaults(p.aspectRatio, 1.0)\n p.radiusSize = defaults(p.radiusSize, 0.3)\n\n super.init(p)\n }\n\n getAtomData (sview: StructureView, what?: AtomDataFields, params?: AtomDataParams): AtomData {\n return sview.getRungAtomData(this.getAtomParams(what, params))\n }\n\n getBondData (sview: StructureView, what?: BondDataFields, params?: BondDataParams): BondData {\n let p = this.getBondParams(what, params)\n Object.assign(p.colorParams, {rung: true})\n\n return sview.getRungBondData(p)\n }\n}\n\nRepresentationRegistry.add('base', BaseRepresentation)\n\nexport default BaseRepresentation\n","/**\n * @file Spline\n * @author Alexander Rose \n * @private\n */\n\nimport { Vector3 } from 'three'\n\nimport { ColormakerRegistry } from '../globals'\nimport { AtomPicker } from '../utils/picker'\nimport RadiusFactory, { RadiusParams } from '../utils/radius-factory'\nimport { copyArray } from '../math/array-utils'\nimport { spline } from '../math/math-utils'\nimport Polymer from '../proxy/polymer';\nimport AtomProxy from '../proxy/atom-proxy';\nimport { ColormakerParameters } from '../color/colormaker';\nimport { NumberArray } from '../types';\n\nexport class Interpolator {\n \n m: number\n tension: number\n dt: number\n delta: number\n vec1: Vector3\n vec2: Vector3\n vDir: Vector3 \n vTan: Vector3\n vNorm: Vector3\n vBin: Vector3\n m2: number\n\n constructor (m: number, tension: number) {\n this.m = m\n this.tension = tension\n this.dt = 1.0 / this.m\n this.delta = 0.0001\n\n this.vec1 = new Vector3()\n this.vec2 = new Vector3()\n\n this.vDir = new Vector3()\n this.vTan = new Vector3()\n this.vNorm = new Vector3()\n this.vBin = new Vector3()\n \n this.m2 = Math.ceil(this.m / 2)\n }\n\n private interpolateToArr (v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3, t: number, arr: Float32Array, offset: number) {\n arr[ offset + 0 ] = spline(v0.x, v1.x, v2.x, v3.x, t, this.tension)\n arr[ offset + 1 ] = spline(v0.y, v1.y, v2.y, v3.y, t, this.tension)\n arr[ offset + 2 ] = spline(v0.z, v1.z, v2.z, v3.z, t, this.tension)\n }\n\n private interpolateToVec (v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3, t: number, vec: Vector3) {\n vec.x = spline(v0.x, v1.x, v2.x, v3.x, t, this.tension)\n vec.y = spline(v0.y, v1.y, v2.y, v3.y, t, this.tension)\n vec.z = spline(v0.z, v1.z, v2.z, v3.z, t, this.tension)\n }\n\n private interpolatePosition (v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3, pos: Float32Array, offset: number) {\n for (var j = 0; j < this.m; ++j) {\n var l = offset + j * 3\n var d = this.dt * j\n this.interpolateToArr(v0, v1, v2, v3, d, pos, l)\n }\n }\n\n private interpolateTangent (v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3, tan: Float32Array, offset: number) {\n for (var j = 0; j < this.m; ++j) {\n var d = this.dt * j\n var d1 = d - this.delta\n var d2 = d + this.delta\n var l = offset + j * 3\n // capping as a precaution\n if (d1 < 0) d1 = 0\n if (d2 > 1) d2 = 1\n //\n this.interpolateToVec(v0, v1, v2, v3, d1, this.vec1)\n this.interpolateToVec(v0, v1, v2, v3, d2, this.vec2)\n //\n this.vec2.sub(this.vec1).normalize()\n this.vec2.toArray(tan as any, l)\n }\n }\n\n private vectorSubdivide (interpolationFn: (v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3, array: Float32Array, offset: number) => void,\n iterator: AtomIterator, array: Float32Array, offset: number, isCyclic: boolean) {\n let v0: Vector3\n let v1 = iterator.next()\n let v2 = iterator.next()\n let v3 = iterator.next()\n //\n const n = iterator.size\n const n1 = n - 1\n let k = offset || 0\n for (let i = 0; i < n1; ++i) {\n v0 = v1\n v1 = v2\n v2 = v3\n v3 = iterator.next()\n interpolationFn.apply(this, [v0, v1, v2, v3, array, k])\n k += 3 * this.m\n }\n if (isCyclic) {\n v0 = iterator.get(n - 2)\n v1 = iterator.get(n - 1)\n v2 = iterator.get(0)\n v3 = iterator.get(1)\n interpolationFn.apply(this, [v0, v1, v2, v3, array, k])\n k += 3 * this.m\n }\n }\n\n //\n\n public getPosition (iterator: AtomIterator, array: Float32Array, offset: number, isCyclic: boolean) {\n iterator.reset()\n this.vectorSubdivide(this.interpolatePosition, iterator, array, offset, isCyclic)\n var n1 = iterator.size - 1\n var k = n1 * this.m * 3\n if (isCyclic) k += this.m * 3\n var v = iterator.get(isCyclic ? 0 : n1)\n array[ k ] = v.x\n array[ k + 1 ] = v.y\n array[ k + 2 ] = v.z\n }\n\n public getTangent (iterator: AtomIterator, array: Float32Array, offset: number, isCyclic: boolean) {\n iterator.reset()\n this.vectorSubdivide(this.interpolateTangent, iterator, array, offset, isCyclic)\n const n1 = iterator.size - 1\n let k = n1 * this.m * 3\n if (isCyclic) k += this.m * 3\n copyArray(array, array, k - 3, k, 3)\n }\n\n private interpolateNormalDir (u0: Vector3, u1: Vector3, u2: Vector3, u3: Vector3,\n v0: Vector3, v1: Vector3, v2: Vector3, v3: Vector3,\n tan: Float32Array, norm: Float32Array, bin: Float32Array,\n offset: number, shift: boolean) {\n for (let j = 0; j < this.m; ++j) {\n let l = offset + j * 3\n if (shift) l += this.m2 * 3\n const d = this.dt * j\n this.interpolateToVec(u0, u1, u2, u3, d, this.vec1)\n this.interpolateToVec(v0, v1, v2, v3, d, this.vec2)\n this.vDir.subVectors(this.vec2, this.vec1).normalize()\n this.vTan.fromArray(tan as any, l)\n this.vBin.crossVectors(this.vDir, this.vTan).normalize()\n this.vBin.toArray(bin as any, l)\n this.vNorm.crossVectors(this.vTan, this.vBin).normalize()\n this.vNorm.toArray(norm as any, l)\n }\n }\n\n private interpolateNormal (vDir: Vector3, tan: Float32Array, norm: Float32Array, bin: Float32Array, offset: number) {\n for (var j = 0; j < this.m; ++j) {\n var l = offset + j * 3\n vDir.copy(this.vNorm)\n this.vTan.fromArray(tan as any, l)\n this.vBin.crossVectors(vDir, this.vTan).normalize()\n this.vBin.toArray(bin as any, l)\n this.vNorm.crossVectors(this.vTan, this.vBin).normalize()\n this.vNorm.toArray(norm as any, l)\n }\n }\n\n public getNormal (size: number, tan: Float32Array, norm: Float32Array, bin: Float32Array, offset: number, isCyclic: boolean) {\n this.vNorm.set(0, 0, 1)\n const n = size\n const n1 = n - 1\n let k = offset || 0\n for (var i = 0; i < n1; ++i) {\n this.interpolateNormal(this.vDir, tan, norm, bin, k)\n k += 3 * this.m\n }\n if (isCyclic) {\n this.interpolateNormal(this.vDir, tan, norm, bin, k)\n k += 3 * this.m\n }\n this.vBin.toArray(bin as any, k)\n this.vNorm.toArray(norm as any, k)\n }\n\n public getNormalDir (iterDir1: AtomIterator, iterDir2: AtomIterator, tan: Float32Array, norm: Float32Array, bin: Float32Array, offset: number, isCyclic: boolean, shift: boolean) {\n iterDir1.reset()\n iterDir2.reset()\n //\n const vSub1 = new Vector3()\n const vSub2 = new Vector3()\n const vSub3 = new Vector3()\n const vSub4 = new Vector3()\n //\n const d1v1 = new Vector3()\n const d1v2 = new Vector3().copy(iterDir1.next())\n const d1v3 = new Vector3().copy(iterDir1.next())\n const d1v4 = new Vector3().copy(iterDir1.next())\n const d2v1 = new Vector3()\n const d2v2 = new Vector3().copy(iterDir2.next())\n const d2v3 = new Vector3().copy(iterDir2.next())\n const d2v4 = new Vector3().copy(iterDir2.next())\n //\n this.vNorm.set(0, 0, 1)\n let n = iterDir1.size\n let n1 = n - 1\n let k = offset || 0\n for (var i = 0; i < n1; ++i) {\n d1v1.copy(d1v2)\n d1v2.copy(d1v3)\n d1v3.copy(d1v4)\n d1v4.copy(iterDir1.next())\n d2v1.copy(d2v2)\n d2v2.copy(d2v3)\n d2v3.copy(d2v4)\n d2v4.copy(iterDir2.next())\n //\n if (i === 0) {\n vSub1.subVectors(d2v1, d1v1)\n vSub2.subVectors(d2v2, d1v2)\n if (vSub1.dot(vSub2) < 0) {\n vSub2.multiplyScalar(-1)\n d2v2.addVectors(d1v2, vSub2)\n }\n vSub3.subVectors(d2v3, d1v3)\n if (vSub2.dot(vSub3) < 0) {\n vSub3.multiplyScalar(-1)\n d2v3.addVectors(d1v3, vSub3)\n }\n } else {\n vSub3.copy(vSub4)\n }\n vSub4.subVectors(d2v4, d1v4)\n if (vSub3.dot(vSub4) < 0) {\n vSub4.multiplyScalar(-1)\n d2v4.addVectors(d1v4, vSub4)\n }\n this.interpolateNormalDir(\n d1v1, d1v2, d1v3, d1v4,\n d2v1, d2v2, d2v3, d2v4,\n tan, norm, bin, k, shift\n )\n k += 3 * this.m\n }\n if (isCyclic) {\n d1v1.copy(iterDir1.get(n - 2))\n d1v2.copy(iterDir1.get(n - 1))\n d1v3.copy(iterDir1.get(0))\n d1v4.copy(iterDir1.get(1))\n d2v1.copy(iterDir2.get(n - 2))\n d2v2.copy(iterDir2.get(n - 1))\n d2v3.copy(iterDir2.get(0))\n d2v4.copy(iterDir2.get(1))\n //\n vSub3.copy(vSub4)\n vSub4.subVectors(d2v4, d1v4)\n if (vSub3.dot(vSub4) < 0) {\n vSub4.multiplyScalar(-1)\n d2v4.addVectors(d1v4, vSub4)\n }\n this.interpolateNormalDir(\n d1v1, d1v2, d1v3, d1v4,\n d2v1, d2v2, d2v3, d2v4,\n tan, norm, bin, k, shift\n )\n k += 3 * this.m\n }\n if (shift) {\n // FIXME shift requires data from one this.more preceeding residue\n this.vBin.fromArray(bin as any, this.m2 * 3)\n this.vNorm.fromArray(norm as any, this.m2 * 3)\n for (var j = 0; j < this.m2; ++j) {\n this.vBin.toArray(bin as any, j * 3)\n this.vNorm.toArray(norm as any, j * 3)\n }\n } else {\n this.vBin.toArray(bin as any, k)\n this.vNorm.toArray(norm as any, k)\n }\n }\n\n //\n\n private interpolateColor (item1: AtomProxy, item2: AtomProxy, colFn: (...arg: any[]) => void, col: any, offset: number) {\n var j, l\n for (j = 0; j < this.m2; ++j) {\n l = offset + j * 3\n colFn.apply(this, [item1, col, l]) // itemColorToArray\n }\n for (j = this.m2; j < this.m; ++j) {\n l = offset + j * 3\n colFn.apply(this, [item2, col, l]) // itemColorToArray\n }\n }\n\n public getColor (iterator: AtomIterator, colFn: (...arg: any[]) => void, col: any, offset: number, isCyclic: boolean) {\n iterator.reset()\n iterator.next() // first element not needed\n let i0: AtomProxy\n let i1 = iterator.next()\n //\n var n = iterator.size\n var n1 = n - 1\n var k = offset || 0\n for (var i = 0; i < n1; ++i) {\n i0 = i1\n i1 = iterator.next()\n this.interpolateColor(i0, i1, colFn, col, k)\n k += 3 * this.m\n }\n if (isCyclic) {\n i0 = iterator.get(n - 1)\n i1 = iterator.get(0)\n this.interpolateColor(i0, i1, colFn, col, k)\n k += 3 * this.m\n }\n //\n col[ k ] = col[ k - 3 ]\n col[ k + 1 ] = col[ k - 2 ]\n col[ k + 2 ] = col[ k - 1 ]\n }\n\n //\n\n private interpolatePicking (item1: AtomProxy, item2: AtomProxy, pickFn: (item: AtomProxy) => number, pick: Float32Array, offset: number) {\n var j\n for (j = 0; j < this.m2; ++j) {\n pick[ offset + j ] = pickFn.apply(this, [item1])\n }\n for (j = this.m2; j < this.m; ++j) {\n pick[ offset + j ] = pickFn.apply(this, [item2])\n }\n }\n\n public getPicking (iterator: AtomIterator, pickFn: (item: AtomProxy) => number, pick: Float32Array, offset: number, isCyclic: boolean) {\n iterator.reset()\n iterator.next() // first element not needed\n let i0: AtomProxy\n let i1 = iterator.next()\n //\n const n = iterator.size\n const n1 = n - 1\n let k = offset || 0\n for (var i = 0; i < n1; ++i) {\n i0 = i1\n i1 = iterator.next()\n this.interpolatePicking(i0, i1, pickFn, pick, k)\n k += this.m\n }\n if (isCyclic) {\n i0 = iterator.get(n - 1)\n i1 = iterator.get(0)\n this.interpolatePicking(i0, i1, pickFn, pick, k)\n k += this.m\n }\n //\n pick[ k ] = pick[ k - 1 ]\n }\n\n //\n\n private interpolateSize (item1: AtomProxy, item2: AtomProxy, sizeFn: (item: AtomProxy) => number, size: Float32Array, offset: number) {\n const s1: number = sizeFn.apply(this, [item1])\n const s2: number = sizeFn.apply(this, [item2])\n for (let j = 0; j < this.m; ++j) {\n // linear interpolation\n let t = j / this.m\n size[ offset + j ] = (1 - t) * s1 + t * s2\n }\n }\n\n public getSize (iterator: AtomIterator, sizeFn: (item: AtomProxy) => number, size: Float32Array, offset: number, isCyclic: boolean) {\n iterator.reset()\n iterator.next() // first element not needed\n let i0: AtomProxy\n let i1: AtomProxy = iterator.next()\n //\n const n = iterator.size\n const n1 = n - 1\n let k = offset || 0\n for (var i = 0; i < n1; ++i) {\n i0 = i1\n i1 = iterator.next()\n this.interpolateSize(i0, i1, sizeFn, size, k)\n k += this.m\n }\n if (isCyclic) {\n i0 = iterator.get(n - 1)\n i1 = iterator.get(0)\n this.interpolateSize(i0, i1, sizeFn, size, k)\n k += this.m\n }\n //\n size[ k ] = size[ k - 1 ]\n }\n}\n\nexport interface SplineParameters {\n directional?: boolean\n positionIterator?: boolean\n subdiv?: number\n smoothSheet?: boolean\n tension?: number\n}\nexport interface AtomIterator {\n size: number,\n next: () => AtomProxy | Vector3,\n get: (idx: number) => AtomProxy | Vector3,\n reset: () => void\n}\nclass Spline {\n\n polymer: Polymer\n size: number\n directional: boolean\n positionIterator: any\n subdiv: number\n smoothSheet: boolean\n tension: number\n interpolator: Interpolator\n\n constructor (polymer: Polymer, params?: SplineParameters) {\n this.polymer = polymer\n this.size = polymer.residueCount\n\n var p = params || {}\n this.directional = p.directional || false\n this.positionIterator = p.positionIterator || false\n this.subdiv = p.subdiv || 1\n this.smoothSheet = p.smoothSheet || false\n\n if (!p.tension) {\n this.tension = this.polymer.isNucleic() ? 0.5 : 0.9\n } else {\n this.tension = p.tension\n }\n\n this.interpolator = new Interpolator(this.subdiv, this.tension)\n }\n\n getAtomIterator (type: string, smooth?: boolean): AtomIterator {\n const polymer = this.polymer\n const structure = polymer.structure\n const n = polymer.residueCount\n\n let i = 0\n let j = -1\n\n const cache = [\n structure.getAtomProxy(),\n structure.getAtomProxy(),\n structure.getAtomProxy(),\n structure.getAtomProxy()\n ]\n\n const cache2 = [\n new Vector3(),\n new Vector3(),\n new Vector3(),\n new Vector3()\n ]\n\n function next () {\n var atomProxy = get(j)\n j += 1\n return atomProxy\n }\n\n var apPrev = structure.getAtomProxy()\n var apNext = structure.getAtomProxy()\n\n function get (idx: number) {\n var atomProxy = cache[ i % 4 ]\n atomProxy.index = polymer.getAtomIndexByType(idx, type) as number\n if (smooth && idx > 0 && idx < n && atomProxy.sstruc === 'e') {\n var vec = cache2[ i % 4 ]\n apPrev.index = polymer.getAtomIndexByType(idx + 1, type) as number\n apNext.index = polymer.getAtomIndexByType(idx - 1, type) as number\n vec.addVectors(apPrev as any, apNext as any)\n .add(atomProxy as any).add(atomProxy as any)\n .multiplyScalar(0.25)\n i += 1\n return vec\n }\n i += 1\n return atomProxy\n }\n\n function reset () {\n i = 0\n j = -1\n }\n\n return {\n size: n,\n next: next,\n get: get,\n reset: reset\n }\n }\n\n getSubdividedColor (params: {scheme: string, [k: string]: any } & ColormakerParameters) {\n var m = this.subdiv\n var polymer = this.polymer\n var n = polymer.residueCount\n var n1 = n - 1\n var nCol = n1 * m * 3 + 3\n if (polymer.isCyclic) nCol += m * 3\n\n var col = new Float32Array(nCol)\n var iterator = this.getAtomIterator('trace')\n\n var p = params || {}\n p.structure = polymer.structure\n\n var colormaker = ColormakerRegistry.getScheme(p)\n\n function colFn (item: AtomProxy, array: NumberArray, offset: number) {\n colormaker.atomColorToArray(item, array, offset)\n }\n\n this.interpolator.getColor(\n iterator, colFn, col, 0, polymer.isCyclic\n )\n\n return {\n 'color': col\n }\n }\n \n getSubdividedPicking () {\n var m = this.subdiv\n var polymer = this.polymer\n var n = polymer.residueCount\n var n1 = n - 1\n var nCol = n1 * m + 1\n if (polymer.isCyclic) nCol += m\n\n var structure = polymer.structure\n var iterator = this.getAtomIterator('trace')\n var pick = new Float32Array(nCol)\n\n function pickFn (item: AtomProxy) {\n return item.index\n }\n\n this.interpolator.getPicking(\n iterator, pickFn, pick, 0, polymer.isCyclic\n )\n\n return {\n 'picking': new AtomPicker(pick, structure)\n }\n }\n\n getSubdividedPosition () {\n var pos = this.getPosition()\n\n return {\n 'position': pos\n }\n }\n \n getSubdividedOrientation () {\n const tan = this.getTangent()\n const normals = this.getNormals(tan)\n\n return {\n 'tangent': tan,\n 'normal': normals.normal,\n 'binormal': normals.binormal\n }\n }\n\n getSubdividedSize (params: RadiusParams) {\n var m = this.subdiv\n var polymer = this.polymer\n var n = polymer.residueCount\n var n1 = n - 1\n var nSize = n1 * m + 1\n if (polymer.isCyclic) nSize += m\n\n var size = new Float32Array(nSize)\n var iterator = this.getAtomIterator('trace')\n\n var radiusFactory = new RadiusFactory(params)\n\n function sizeFn (item: AtomProxy) {\n return radiusFactory.atomRadius(item)\n }\n\n this.interpolator.getSize(\n iterator, sizeFn, size, 0, polymer.isCyclic\n )\n\n return {\n 'size': size\n }\n }\n\n getPosition () {\n const m = this.subdiv\n const polymer = this.polymer\n const n = polymer.residueCount\n const n1 = n - 1\n let nPos = n1 * m * 3 + 3\n if (polymer.isCyclic) nPos += m * 3\n\n const pos = new Float32Array(nPos)\n const iterator = this.positionIterator || this.getAtomIterator('trace', this.smoothSheet)\n\n this.interpolator.getPosition(iterator, pos, 0, polymer.isCyclic)\n\n return pos\n }\n\n getTangent () {\n const m = this.subdiv\n const polymer = this.polymer\n const n = this.size\n const n1 = n - 1\n let nTan = n1 * m * 3 + 3\n if (polymer.isCyclic) nTan += m * 3\n\n const tan = new Float32Array(nTan)\n const iterator = this.positionIterator || this.getAtomIterator('trace', this.smoothSheet)\n\n this.interpolator.getTangent(iterator, tan, 0, polymer.isCyclic)\n\n return tan\n }\n\n getNormals (tan: Float32Array) {\n const m = this.subdiv\n const polymer = this.polymer\n const isProtein = polymer.isProtein()\n const n = this.size\n const n1 = n - 1\n let nNorm = n1 * m * 3 + 3\n if (polymer.isCyclic) nNorm += m * 3\n\n const norm = new Float32Array(nNorm)\n const bin = new Float32Array(nNorm)\n\n if (this.directional && !this.polymer.isCg()) {\n const iterDir1 = this.getAtomIterator('direction1')\n const iterDir2 = this.getAtomIterator('direction2')\n this.interpolator.getNormalDir(\n iterDir1, iterDir2, tan, norm, bin, 0, polymer.isCyclic, isProtein\n )\n } else {\n this.interpolator.getNormal(\n n, tan, norm, bin, 0, polymer.isCyclic\n )\n }\n\n return {\n 'normal': norm,\n 'binormal': bin\n }\n }\n\n}\n\nexport default Spline\n","/**\n * @file Tube Mesh Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Matrix4 required for declaration only\nimport { Vector3, Matrix4 } from 'three'\n\nimport { defaults, getUintArray } from '../utils'\nimport { serialArray } from '../math/array-utils'\nimport MeshBuffer from './mesh-buffer'\nimport { BufferDefaultParameters, BufferData, BufferParameters } from './buffer'\nimport {Log} from \"../globals\";\n\nconst vTangent = new Vector3()\nconst vMeshNormal = new Vector3()\n\nexport interface TubeMeshBufferData extends BufferData {\n binormal: Float32Array\n tangent: Float32Array\n size: Float32Array\n}\n\nexport const TubeMeshBufferDefaultParameters = Object.assign({\n radialSegments: 4,\n capped: false,\n aspectRatio: 1.0\n}, BufferDefaultParameters)\nexport type TubeMeshBufferParameters = BufferParameters & {\n radialSegments: number,\n capped: boolean,\n aspectRatio: number\n}\n\nfunction getData (data: TubeMeshBufferData, params: Partial = {}) {\n const radialSegments = defaults(params.radialSegments, 4)\n const capped = defaults(params.capped, false)\n\n const capVertices = capped ? radialSegments : 0\n const capTriangles = capped ? radialSegments - 2 : 0\n\n const n = data.position!.length / 3\n const n1 = n - 1\n const x = n * radialSegments * 3 + 2 * capVertices * 3\n const xi = n1 * 2 * radialSegments * 3 + 2 * capTriangles * 3\n\n return {\n position: new Float32Array(x),\n color: new Float32Array(x),\n index: getUintArray(xi, x / 3),\n normal: new Float32Array(x),\n picking: data.picking\n }\n}\n\n/**\n * Tube mesh buffer. Draws a tube.\n */\nclass TubeMeshBuffer extends MeshBuffer {\n get defaultParameters() { return TubeMeshBufferDefaultParameters }\n parameters: TubeMeshBufferParameters\n\n capVertices: number\n capTriangles: number\n size2: number\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.normal - normals\n * @param {Float32Array} data.binormal - binormals\n * @param {Float32Array} data.tangent - tangents\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.size - sizes\n * @param {Picker} data.picking - picking ids\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: TubeMeshBufferData, params: Partial = {}) {\n super(getData(data, params), params)\n\n this.capVertices = this.parameters.capped ? this.parameters.radialSegments : 0\n this.capTriangles = this.parameters.capped ? this.parameters.radialSegments - 2 : 0\n\n this.size2 = data.position!.length / 3\n data.primitiveId = serialArray(this.size2)\n\n this.setAttributes(data)\n this.makeIndex()\n }\n\n setAttributes (data: Partial = {}) {\n const aspectRatio = this.parameters.aspectRatio\n\n const n = this.size2\n const n1 = n - 1\n const radialSegments = this.parameters.radialSegments\n\n const attributes = this.geometry.attributes as any\n\n let position, normal, binormal, tangent, color, size, primitiveId\n let meshPosition, meshColor, meshNormal, meshPrimitiveId\n\n if (data.position) {\n position = data.position\n normal = data.normal\n binormal = data.binormal\n tangent = data.tangent\n size = data.size\n\n meshPosition = attributes.position.array\n meshNormal = attributes.normal.array\n\n attributes.position.needsUpdate = true\n attributes.normal.needsUpdate = true\n }\n\n if (data.color) {\n color = data.color\n meshColor = attributes.color.array\n attributes.color.needsUpdate = true\n }\n\n if (data.primitiveId) {\n primitiveId = data.primitiveId\n meshPrimitiveId = attributes.primitiveId.array\n attributes.primitiveId.needsUpdate = true\n }\n\n let k, l\n let radius = 0\n\n let normX = 0\n let normY = 0\n let normZ = 0\n let biX = 0\n let biY = 0\n let biZ = 0\n let posX = 0\n let posY = 0\n let posZ = 0\n\n const cxArr = []\n const cyArr = []\n const cx1Arr = []\n const cy1Arr = []\n const cx2Arr = []\n const cy2Arr = []\n\n if (position) {\n for (let j = 0; j < radialSegments; ++j) {\n const v = (j / radialSegments) * 2 * Math.PI\n\n cxArr[ j ] = aspectRatio * Math.cos(v)\n cyArr[ j ] = Math.sin(v)\n\n cx1Arr[ j ] = aspectRatio * Math.cos(v - 0.01)\n cy1Arr[ j ] = Math.sin(v - 0.01)\n cx2Arr[ j ] = aspectRatio * Math.cos(v + 0.01)\n cy2Arr[ j ] = Math.sin(v + 0.01)\n }\n }\n\n for (let i = 0; i < n; ++i) {\n k = i * 3\n l = k * radialSegments\n\n if (position && tangent && normal && binormal && size) {\n vTangent.set(\n tangent[ k ], tangent[ k + 1 ], tangent[ k + 2 ]\n )\n\n normX = normal[ k ]\n normY = normal[ k + 1 ]\n normZ = normal[ k + 2 ]\n\n biX = binormal[ k ]\n biY = binormal[ k + 1 ]\n biZ = binormal[ k + 2 ]\n\n posX = position[ k ]\n posY = position[ k + 1 ]\n posZ = position[ k + 2 ]\n\n radius = size[ i ]\n }\n\n for (let j = 0; j < radialSegments; ++j) {\n const s = l + j * 3\n\n if (position) {\n const cx = -radius * cxArr[ j ] // TODO: Hack: Negating it so it faces outside.\n const cy = radius * cyArr[ j ]\n\n const cx1 = -radius * cx1Arr[ j ]\n const cy1 = radius * cy1Arr[ j ]\n const cx2 = -radius * cx2Arr[ j ]\n const cy2 = radius * cy2Arr[ j ]\n\n meshPosition[ s ] = posX + cx * normX + cy * biX\n meshPosition[ s + 1 ] = posY + cx * normY + cy * biY\n meshPosition[ s + 2 ] = posZ + cx * normZ + cy * biZ\n\n // TODO half of these are symmetric\n vMeshNormal.set(\n // ellipse tangent approximated as vector from/to adjacent points\n (cx2 * normX + cy2 * biX) - (cx1 * normX + cy1 * biX),\n (cx2 * normY + cy2 * biY) - (cx1 * normY + cy1 * biY),\n (cx2 * normZ + cy2 * biZ) - (cx1 * normZ + cy1 * biZ)\n ).cross(vTangent)\n\n meshNormal[ s ] = vMeshNormal.x\n meshNormal[ s + 1 ] = vMeshNormal.y\n meshNormal[ s + 2 ] = vMeshNormal.z\n }\n\n if (color) {\n meshColor[ s ] = color[ k ]\n meshColor[ s + 1 ] = color[ k + 1 ]\n meshColor[ s + 2 ] = color[ k + 2 ]\n }\n\n if (primitiveId) {\n meshPrimitiveId[ i * radialSegments + j ] = primitiveId[ i ]\n }\n }\n }\n\n // front cap\n\n k = 0\n l = n * 3 * radialSegments\n\n for (let j = 0; j < radialSegments; ++j) {\n const s = k + j * 3\n const t = l + j * 3\n\n if (position && tangent) {\n meshPosition[ t ] = meshPosition[ s ]\n meshPosition[ t + 1 ] = meshPosition[ s + 1 ]\n meshPosition[ t + 2 ] = meshPosition[ s + 2 ]\n\n meshNormal[ t ] = tangent[ k ]\n meshNormal[ t + 1 ] = tangent[ k + 1 ]\n meshNormal[ t + 2 ] = tangent[ k + 2 ]\n }\n\n if (color) {\n meshColor[ t ] = meshColor[ s ]\n meshColor[ t + 1 ] = meshColor[ s + 1 ]\n meshColor[ t + 2 ] = meshColor[ s + 2 ]\n }\n\n if (primitiveId) {\n meshPrimitiveId[ n * radialSegments + j ] = meshPrimitiveId[ 0 + j ]\n }\n }\n\n // back cap\n\n k = (n - 1) * 3 * radialSegments\n l = (n + 1) * 3 * radialSegments\n\n for (let j = 0; j < radialSegments; ++j) {\n const s = k + j * 3\n const t = l + j * 3\n\n if (position && tangent) {\n meshPosition[ t ] = meshPosition[ s ]\n meshPosition[ t + 1 ] = meshPosition[ s + 1 ]\n meshPosition[ t + 2 ] = meshPosition[ s + 2 ]\n\n meshNormal[ t ] = tangent[ n1 * 3 ]\n meshNormal[ t + 1 ] = tangent[ n1 * 3 + 1 ]\n meshNormal[ t + 2 ] = tangent[ n1 * 3 + 2 ]\n }\n\n if (color) {\n meshColor[ t ] = meshColor[ s ]\n meshColor[ t + 1 ] = meshColor[ s + 1 ]\n meshColor[ t + 2 ] = meshColor[ s + 2 ]\n }\n\n if (primitiveId) {\n meshPrimitiveId[ (n + 1) * radialSegments + j ] = meshPrimitiveId[ (n - 1) * radialSegments + j ]\n }\n }\n }\n\n makeIndex () {\n const index = this.geometry.getIndex()\n if (!index) { Log.error('Index is null'); return; }\n const meshIndex = index.array as Uint32Array|Uint16Array\n\n const n = this.size2\n const n1 = n - 1\n const capTriangles = this.capTriangles\n const radialSegments = this.parameters.radialSegments\n const radialSegments1 = this.parameters.radialSegments + 1\n\n let k, l\n\n for (let i = 0; i < n1; ++i) {\n const k = i * radialSegments * 3 * 2\n\n const irs = i * radialSegments\n const irs1 = (i + 1) * radialSegments\n\n for (let j = 0; j < radialSegments; ++j) {\n l = k + j * 3 * 2\n\n // meshIndex[ l + 0 ] = irs + ( ( j + 0 ) % radialSegments );\n meshIndex[ l ] = irs + j\n meshIndex[ l + 1 ] = irs + ((j + 1) % radialSegments)\n // meshIndex[ l + 2 ] = irs1 + ( ( j + 0 ) % radialSegments );\n meshIndex[ l + 2 ] = irs1 + j\n\n // meshIndex[ l + 3 ] = irs1 + ( ( j + 0 ) % radialSegments );\n meshIndex[ l + 3 ] = irs1 + j\n meshIndex[ l + 4 ] = irs + ((j + 1) % radialSegments)\n meshIndex[ l + 5 ] = irs1 + ((j + 1) % radialSegments)\n }\n }\n\n // capping\n\n const strip = [ 0 ]\n\n for (let j = 1; j < radialSegments1 / 2; ++j) {\n strip.push(j)\n if (radialSegments - j !== j) {\n strip.push(radialSegments - j)\n }\n }\n\n // front cap\n\n l = n1 * radialSegments * 3 * 2\n k = n * radialSegments\n\n for (let j = 0; j < strip.length - 2; ++j) {\n if (j % 2 === 0) {\n meshIndex[ l + j * 3 + 0 ] = k + strip[ j + 0 ]\n meshIndex[ l + j * 3 + 1 ] = k + strip[ j + 1 ]\n meshIndex[ l + j * 3 + 2 ] = k + strip[ j + 2 ]\n } else {\n meshIndex[ l + j * 3 + 0 ] = k + strip[ j + 2 ]\n meshIndex[ l + j * 3 + 1 ] = k + strip[ j + 1 ]\n meshIndex[ l + j * 3 + 2 ] = k + strip[ j + 0 ]\n }\n }\n\n // back cap\n\n l = n1 * radialSegments * 3 * 2 + 3 * capTriangles\n k = n * radialSegments + radialSegments\n\n for (let j = 0; j < strip.length - 2; ++j) {\n if (j % 2 === 0) {\n meshIndex[ l + j * 3 + 0 ] = k + strip[ j + 0 ]\n meshIndex[ l + j * 3 + 1 ] = k + strip[ j + 1 ]\n meshIndex[ l + j * 3 + 2 ] = k + strip[ j + 2 ]\n } else {\n meshIndex[ l + j * 3 + 0 ] = k + strip[ j + 2 ]\n meshIndex[ l + j * 3 + 1 ] = k + strip[ j + 1 ]\n meshIndex[ l + j * 3 + 2 ] = k + strip[ j + 0 ]\n }\n }\n }\n}\n\nexport default TubeMeshBuffer\n","/**\n * @file Cartoon Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport { Debug, Log, RepresentationRegistry } from '../globals'\nimport Spline from '../geometry/spline'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport TubeMeshBuffer from '../buffer/tubemesh-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport Polymer from '../proxy/polymer';\nimport AtomProxy from '../proxy/atom-proxy';\nimport StructureView from '../structure/structure-view';\nimport Buffer from '../buffer/buffer';\n\nexport interface CartoonRepresentationParameters extends StructureRepresentationParameters {\n aspectRatio: number\n subdiv: number\n radialSegments: number\n tension: number\n capped: boolean\n smoothSheet: boolean\n}\n\n/**\n * Cartoon representation. Show a thick ribbon that\n * smoothly connecting backbone atoms in polymers.\n *\n * __Name:__ _cartoon_\n *\n * @example\n * stage.loadFile( \"rcsb://1crn\" ).then( function( o ){\n * o.addRepresentation( \"cartoon\" );\n * o.autoView();\n * } );\n */\nclass CartoonRepresentation extends StructureRepresentation {\n protected aspectRatio: number\n protected tension: number\n protected capped: boolean\n protected smoothSheet: boolean\n protected subdiv: number\n \n /**\n * Create Cartoon representation object\n * @param {Structure} structure - the structure to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {StructureRepresentationParameters} params - representation parameters\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'cartoon'\n\n this.parameters = Object.assign({\n\n aspectRatio: {\n type: 'number', precision: 1, max: 10.0, min: 1.0, rebuild: true\n },\n subdiv: {\n type: 'integer', max: 50, min: 1, rebuild: true\n },\n radialSegments: {\n type: 'integer', max: 50, min: 1, rebuild: true\n },\n tension: {\n type: 'number', precision: 1, max: 1.0, min: 0.1\n },\n capped: {\n type: 'boolean', rebuild: true\n },\n smoothSheet: {\n type: 'boolean', rebuild: true\n }\n\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'chainname')\n p.colorScale = defaults(p.colorScale, 'RdYlBu')\n p.radiusType = defaults(p.radiusType, 'sstruc')\n p.radiusScale = defaults(p.radiusScale, 0.7)\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n this.aspectRatio = defaults(p.aspectRatio, 5.0)\n this.tension = defaults(p.tension, NaN)\n this.capped = defaults(p.capped, true)\n this.smoothSheet = defaults(p.smoothSheet, false)\n\n if (p.quality === 'low') {\n this.subdiv = 3\n this.radialSegments = 6\n } else if (p.quality === 'medium') {\n this.subdiv = 6\n } else if (p.quality === 'high') {\n this.subdiv = 12\n } else {\n this.subdiv = defaults(p.subdiv, 6)\n }\n\n super.init(p)\n }\n\n getSplineParams (params?: Partial) {\n return Object.assign({\n subdiv: this.subdiv,\n tension: this.tension,\n directional: this.aspectRatio !== 1.0,\n smoothSheet: this.smoothSheet\n }, params)\n }\n\n getSpline (polymer: Polymer): Spline {\n return new Spline(polymer, this.getSplineParams())\n }\n\n getAspectRatio (polymer: Polymer): number {\n return polymer.isCg() ? 1.0 : this.aspectRatio\n }\n\n getAtomRadius (atom: AtomProxy): number {\n return atom.isTrace() ? super.getAtomRadius(atom) : 0\n }\n\n createData (sview: StructureView) {\n let bufferList: Buffer[] = []\n let polymerList: Polymer[] = []\n\n this.structure.eachPolymer(polymer => {\n if (polymer.residueCount < 4) return\n polymerList.push(polymer)\n\n const spline = this.getSpline(polymer)\n const aspectRatio = this.getAspectRatio(polymer)\n\n const subPos = spline.getSubdividedPosition()\n const subOri = spline.getSubdividedOrientation()\n const subCol = spline.getSubdividedColor(this.getColorParams())\n const subPick = spline.getSubdividedPicking()\n const subSize = spline.getSubdividedSize(this.getRadiusParams())\n\n bufferList.push(\n new TubeMeshBuffer(\n Object.assign({}, subPos, subOri, subCol, subPick, subSize),\n this.getBufferParams({\n radialSegments: this.radialSegments,\n aspectRatio: aspectRatio,\n capped: this.capped\n })\n )\n )\n }, sview.getSelection())\n\n return {\n bufferList: bufferList,\n polymerList: polymerList\n }\n }\n\n updateData (what: any, data: StructureRepresentationData) {\n if (Debug) Log.time(this.type + ' repr update')\n\n what = what || {}\n\n for (var i = 0, il = data.polymerList!.length; i < il; ++i) {\n var bufferData: {[key: string]: any} = {}\n var polymer = data.polymerList![ i ]\n var spline = this.getSpline(polymer)\n var aspectRatio = this.getAspectRatio(polymer)\n\n Object.assign(data.bufferList[ i ], {aspectRatio: aspectRatio})\n\n if (what.position || what.radius) {\n var subPos = spline.getSubdividedPosition()\n var subOri = spline.getSubdividedOrientation()\n var subSize = spline.getSubdividedSize(this.getRadiusParams(aspectRatio))\n\n bufferData.position = subPos.position\n bufferData.normal = subOri.normal\n bufferData.binormal = subOri.binormal\n bufferData.tangent = subOri.tangent\n bufferData.size = subSize.size\n }\n\n if (what.color) {\n var subCol = spline.getSubdividedColor(this.getColorParams())\n bufferData.color = subCol.color\n }\n\n if (what.picking) {\n var subPick = spline.getSubdividedPicking()\n bufferData.picking = subPick.picking\n }\n\n data.bufferList[ i ].setAttributes(bufferData)\n }\n\n if (Debug) Log.timeEnd(this.type + ' repr update')\n }\n\n setParameters (params: Partial) {\n const rebuild = false\n var what: {[k: string]: any} = {}\n\n if (params && params.aspectRatio) {\n what.radius = true\n }\n\n if (params && params.tension) {\n what.position = true\n }\n\n super.setParameters(params, what, rebuild)\n\n return this\n }\n}\n\nRepresentationRegistry.add('cartoon', CartoonRepresentation)\n\nexport default CartoonRepresentation\n","/**\n * @file Contact Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport { RepresentationRegistry } from '../globals'\nimport StructureRepresentation, { StructureRepresentationParameters } from './structure-representation'\nimport { calculateContacts, getContactData, getLabelData } from '../chemistry/interactions/contact'\nimport CylinderBuffer from '../buffer/cylinder-buffer'\nimport TextBuffer from '../buffer/text-buffer'\nimport { getFixedCountDashData } from '../geometry/dash'\nimport Viewer from '../viewer/viewer';\nimport { Structure } from '../ngl';\nimport StructureView from '../structure/structure-view';\nimport CylinderGeometryBuffer from '../buffer/cylindergeometry-buffer';\nimport CylinderImpostorBuffer from '../buffer/cylinderimpostor-buffer';\n// @ts-ignore: unused import ContactPicker required for declaration only\nimport { ContactPicker } from '../utils/picker';\n\nexport interface ContactRepresentationParameters extends StructureRepresentationParameters {\n hydrogenBond: boolean\n weakHydrogenBond: boolean\n waterHydrogenBond: boolean\n backboneHydrogenBond: boolean\n hydrophobic: boolean\n halogenBond: boolean\n ionicInteraction: boolean\n metalCoordination: boolean\n cationPi: boolean\n piStacking: boolean\n filterSele: string|[string, string]\n maxHydrophobicDist: number\n maxHbondDist: number\n maxHbondSulfurDist: number\n maxHbondAccAngle: number\n maxHbondDonAngle: number\n maxHbondAccPlaneAngle: number\n maxHbondDonPlaneAngle: number\n maxPiStackingDist: number\n maxPiStackingOffset: number\n maxPiStackingAngle: number\n maxCationPiDist: number\n maxCationPiOffset: number\n maxIonicDist: number\n maxHalogenBondDist: number\n maxHalogenBondAngle: number\n maxMetalDist: number\n refineSaltBridges: boolean\n masterModelIndex: number\n lineOfSightDistFactor: number\n}\n\n/**\n * Contact representation.\n */\nclass ContactRepresentation extends StructureRepresentation {\n protected hydrogenBond: boolean\n protected weakHydrogenBond: boolean\n protected waterHydrogenBond: boolean\n protected backboneHydrogenBond: boolean\n protected hydrophobic: boolean\n protected halogenBond: boolean\n protected ionicInteraction: boolean\n protected metalCoordination: boolean\n protected cationPi: boolean\n protected piStacking: boolean\n protected filterSele: string|[string, string]\n protected maxHydrophobicDist: number\n protected maxHbondDist: number\n protected maxHbondSulfurDist: number\n protected maxHbondAccAngle: number\n protected maxHbondDonAngle: number\n protected maxHbondAccPlaneAngle: number\n protected maxHbondDonPlaneAngle: number\n protected maxPiStackingDist: number\n protected maxPiStackingOffset: number\n protected maxPiStackingAngle: number\n protected maxCationPiDist: number\n protected maxCationPiOffset: number\n protected maxIonicDist: number\n protected maxHalogenBondDist: number\n protected maxHalogenBondAngle: number\n protected maxMetalDist: number\n protected refineSaltBridges: boolean\n protected masterModelIndex: number\n protected lineOfSightDistFactor: number\n\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'contact'\n\n this.parameters = Object.assign({\n hydrogenBond: {\n type: 'boolean', rebuild: true\n },\n weakHydrogenBond: {\n type: 'boolean', rebuild: true\n },\n waterHydrogenBond: {\n type: 'boolean', rebuild: true\n },\n backboneHydrogenBond: {\n type: 'boolean', rebuild: true\n },\n hydrophobic: {\n type: 'boolean', rebuild: true\n },\n halogenBond: {\n type: 'boolean', rebuild: true\n },\n ionicInteraction: {\n type: 'boolean', rebuild: true\n },\n metalCoordination: {\n type: 'boolean', rebuild: true\n },\n cationPi: {\n type: 'boolean', rebuild: true\n },\n piStacking: {\n type: 'boolean', rebuild: true\n },\n\n filterSele: {\n type: 'text', rebuild: true\n },\n\n labelVisible: {\n type: 'boolean', rebuild: true\n },\n\n labelFixedSize: {\n type: 'boolean', buffer: 'fixedSize'\n },\n\n labelSize: {\n type: 'number', precision: 3, max: 10.0, min: 0.001, rebuild: true\n },\n\n labelUnit: {\n type: 'select',\n rebuild: true,\n options: { '': '', angstrom: 'angstrom', nm: 'nm' }\n },\n\n maxHydrophobicDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxHbondDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxHbondSulfurDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxHbondAccAngle: {\n type: 'integer', max: 180, min: 0, rebuild: true\n },\n maxHbondDonAngle: {\n type: 'integer', max: 180, min: 0, rebuild: true\n },\n maxHbondAccPlaneAngle: {\n type: 'integer', max: 90, min: 0, rebuild: true\n },\n maxHbondDonPlaneAngle: {\n type: 'integer', max: 90, min: 0, rebuild: true\n },\n maxPiStackingDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxPiStackingOffset: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxPiStackingAngle: {\n type: 'integer', max: 180, min: 0, rebuild: true\n },\n maxCationPiDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxCationPiOffset: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxIonicDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxHalogenBondDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n maxHalogenBondAngle: {\n type: 'integer', max: 180, min: 0, rebuild: true\n },\n maxMetalDist: {\n type: 'number', precision: 1, max: 10, min: 0.1, rebuild: true\n },\n refineSaltBridges: {\n type: 'boolean', rebuild: true\n },\n masterModelIndex: {\n type: 'integer', max: 1000, min: -1, rebuild: true\n },\n lineOfSightDistFactor: {\n type: 'number', precision: 1, max: 10, min: 0.0, rebuild: true\n },\n\n radialSegments: true,\n disableImpostor: true\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.radiusSize = defaults(p.radiusSize, 0.05)\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n this.hydrogenBond = defaults(p.hydrogenBond, true)\n this.weakHydrogenBond = defaults(p.weakHydrogenBond, false)\n this.waterHydrogenBond = defaults(p.waterHydrogenBond, false)\n this.backboneHydrogenBond = defaults(p.backboneHydrogenBond, false)\n this.hydrophobic = defaults(p.hydrophobic, false)\n this.halogenBond = defaults(p.halogenBond, true)\n this.ionicInteraction = defaults(p.ionicInteraction, true)\n this.metalCoordination = defaults(p.metalCoordination, true)\n this.cationPi = defaults(p.cationPi, true)\n this.piStacking = defaults(p.piStacking, true)\n\n this.filterSele = defaults(p.filterSele, '')\n this.labelVisible = defaults(p.labelVisible, false)\n this.labelFixedSize = defaults(p.labelFixedSize, false)\n this.labelSize = defaults(p.labelSize, 2.0)\n this.labelUnit = defaults(p.labelUnit, '')\n\n this.maxHydrophobicDist = defaults(p.maxHydrophobicDist, 4.0)\n this.maxHbondDist = defaults(p.maxHbondDist, 3.5)\n this.maxHbondSulfurDist = defaults(p.maxHbondSulfurDist, 4.1)\n this.maxHbondAccAngle = defaults(p.maxHbondAccAngle, 45)\n this.maxHbondDonAngle = defaults(p.maxHbondDonAngle, 45)\n this.maxHbondAccPlaneAngle = defaults(p.maxHbondAccPlaneAngle, 90)\n this.maxHbondDonPlaneAngle = defaults(p.maxHbondDonPlaneAngle, 30)\n this.maxPiStackingDist = defaults(p.maxPiStackingDist, 5.5)\n this.maxPiStackingOffset = defaults(p.maxPiStackingOffset, 2.0)\n this.maxPiStackingAngle = defaults(p.maxPiStackingAngle, 30)\n this.maxCationPiDist = defaults(p.maxCationPiDist, 6.0)\n this.maxCationPiOffset = defaults(p.maxCationPiOffset, 2.0)\n this.maxIonicDist = defaults(p.maxIonicDist, 5.0)\n this.maxHalogenBondDist = defaults(p.maxHalogenBondDist, 3.5)\n this.maxHalogenBondAngle = defaults(p.maxHalogenBondAngle, 30)\n this.maxMetalDist = defaults(p.maxMetalDist, 3.0)\n this.refineSaltBridges = defaults(p.refineSaltBridges, true)\n this.masterModelIndex = defaults(p.masterModelIndex, -1)\n this.lineOfSightDistFactor = defaults(p.lineOfSightDistFactor, 1.0)\n\n super.init(p)\n }\n\n getAtomRadius () {\n return 0\n }\n\n getContactData (sview: StructureView) {\n const params = {\n maxHydrophobicDist: this.maxHydrophobicDist,\n maxHbondDist: this.maxHbondDist,\n maxHbondSulfurDist: this.maxHbondSulfurDist,\n maxHbondAccAngle: this.maxHbondAccAngle,\n maxHbondDonAngle: this.maxHbondDonAngle,\n maxHbondAccPlaneAngle: this.maxHbondAccPlaneAngle,\n maxHbondDonPlaneAngle: this.maxHbondDonPlaneAngle,\n maxPiStackingDist: this.maxPiStackingDist,\n maxPiStackingOffset: this.maxPiStackingOffset,\n maxPiStackingAngle: this.maxPiStackingAngle,\n maxCationPiDist: this.maxCationPiDist,\n maxCationPiOffset: this.maxCationPiOffset,\n maxIonicDist: this.maxIonicDist,\n maxHalogenBondDist: this.maxHalogenBondDist,\n maxHalogenBondAngle: this.maxHalogenBondAngle,\n maxMetalDist: this.maxMetalDist,\n refineSaltBridges: this.refineSaltBridges,\n masterModelIndex: this.masterModelIndex,\n lineOfSightDistFactor: this.lineOfSightDistFactor\n }\n\n const dataParams = {\n hydrogenBond: this.hydrogenBond,\n weakHydrogenBond: this.weakHydrogenBond,\n waterHydrogenBond: this.waterHydrogenBond,\n backboneHydrogenBond: this.backboneHydrogenBond,\n hydrophobic: this.hydrophobic,\n halogenBond: this.halogenBond,\n ionicInteraction: this.ionicInteraction,\n metalCoordination: this.metalCoordination,\n cationPi: this.cationPi,\n piStacking: this.piStacking,\n radius: this.radiusSize * this.radiusScale,\n filterSele: this.filterSele\n }\n\n const contacts = calculateContacts(sview, params)\n return getContactData(contacts, sview, dataParams)\n }\n\n createData (sview: StructureView) {\n const contactData = this.getContactData(sview)\n\n const bufferList = [\n new CylinderBuffer(\n getFixedCountDashData(contactData),\n this.getBufferParams({\n sphereDetail: 1,\n dullInterior: true,\n disableImpostor: this.disableImpostor\n })\n ) as (CylinderGeometryBuffer | CylinderImpostorBuffer | TextBuffer)\n ]\n\n if (this.labelVisible) {\n const labelParams = {\n size: this.labelSize,\n unit: this.labelUnit\n }\n bufferList.push(new TextBuffer(\n getLabelData(contactData, labelParams),\n this.getBufferParams({fixedSize: this.labelFixedSize})\n ))\n }\n\n return { bufferList }\n }\n}\n\nRepresentationRegistry.add('contact', ContactRepresentation)\n\nexport default ContactRepresentation\n","/**\n * @file Dihedral Representation\n * @author Fred Ludlow \n * @private\n */\nimport { Color } from 'three'\n\nimport { RepresentationRegistry } from '../globals'\nimport MeasurementRepresentation, { calcArcPoint, parseNestedAtoms, MeasurementRepresentationParameters, LabelDataField } from './measurement-representation'\nimport { defaults } from '../utils'\n\nimport MeshBuffer from '../buffer/mesh-buffer'\nimport TextBuffer, { TextBufferData } from '../buffer/text-buffer'\nimport WideLineBuffer from '../buffer/wideline-buffer'\n\nimport { copyArray, uniformArray, uniformArray3 } from '../math/array-utils'\nimport { v3add, v3angle, v3cross, v3dot, v3multiplyScalar, v3fromArray, v3length,\n v3negate, v3new, v3normalize, v3sub, v3toArray } from '../math/vector-utils'\nimport { RAD2DEG } from '../math/math-constants'\nimport { getFixedLengthWrappedDashData } from '../geometry/dash'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport { CylinderBufferData } from '../buffer/cylinder-buffer';\nimport { BufferData } from '../buffer/buffer';\nimport { StructureRepresentationData } from './structure-representation';\n\n/**\n * @typedef {Object} DihedralRepresentationParameters - dihedral representation parameters\n * @mixes RepresentationParameters\n * @mixes StructureRepresentationParameters\n * @mixes MeasurementRepresentationParameters\n *\n * @property {String} atomQuad - list of quadruplets of selection strings\n * or atom indices\n * @property {Boolean} extendLine - Extend lines in planes\n * @property {Number} lineOpacity - Opacity for the line part of the representation\n * @property {Boolean} lineVisible - Display the line part of the representation\n * @property {Number} linewidth - width for line part of representation\n * @property {Boolean} planeVisible - Display the two planes corresponding to dihedral\n * @property {Boolean} sectorVisible - Display the filled arc for each angle\n */\n\nexport interface DihedralRepresentationParameters extends MeasurementRepresentationParameters {\n atomQuad: (number|string)[][]\n extendLine: boolean\n lineOpacity: number\n lineVisible: boolean\n linewidth: number\n planeVisible: boolean\n sectorVisible: boolean\n}\n\n/**\n * Dihedral representation object\n *\n * Reperesentation consists of three parts, visibility can be set for each\n * label - text label indicating dihedral angle\n * line - line indicating four positions that define the dihedral\n * sector - filled arc section\n *\n * @param {Structure} structure - the structure to measure angles in\n * @param {Viewer} viewer - a viewer object\n * @param {AngleRepresentationParameters} params - angle representation parameters\n */\nclass DihedralRepresentation extends MeasurementRepresentation {\n protected atomQuad: (number|string)[][]\n protected extendLine: boolean\n protected lineOpacity: number\n protected lineVisible: boolean\n protected linewidth: number\n protected planeVisible: boolean\n protected sectorVisible: boolean\n\n protected lineLength: number\n protected planeLength: number\n protected sectorLength: number\n\n protected lineBuffer: WideLineBuffer\n protected planeBuffer: MeshBuffer\n protected sectorBuffer: MeshBuffer\n\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'dihedral'\n\n this.parameters = Object.assign({\n atomQuad: {\n type: 'hidden', rebuild: true\n },\n extendLine: {\n type: 'boolean', rebuild: true, default: true\n },\n lineVisible: {\n type: 'boolean', default: true\n },\n planeVisible: {\n type: 'boolean', default: true\n },\n sectorVisible: {\n type: 'boolean', default: true\n }\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.side = defaults(p.side, 'double')\n p.opacity = defaults(p.opacity, 0.5)\n\n this.atomQuad = defaults(p.atomQuad, [])\n this.extendLine = defaults(p.extendLine, true)\n this.lineVisible = defaults(p.lineVisible, true)\n this.planeVisible = defaults(p.planeVisible, true)\n this.sectorVisible = defaults(p.sectorVisible, true)\n\n super.init(p)\n }\n\n createData (sview: StructureView) {\n if (!sview.atomCount || !this.atomQuad.length) return\n\n const atomPosition = parseNestedAtoms(sview, this.atomQuad)\n const dihedralData = getDihedralData(\n atomPosition, {\n extendLine: this.extendLine\n }\n )\n\n const n = this.n = dihedralData.labelText.length\n const labelColor = new Color(this.labelColor)\n\n this.textBuffer = new TextBuffer({\n position: dihedralData.labelPosition,\n size: uniformArray(n, this.labelSize),\n color: uniformArray3(n, labelColor.r, labelColor.g, labelColor.b),\n text: dihedralData.labelText\n } as TextBufferData, this.getLabelBufferParams())\n\n const c = new Color(this.colorValue)\n this.lineLength = dihedralData.linePosition1.length / 3\n const lineColor = uniformArray3(this.lineLength, c.r, c.g, c.b)\n\n this.lineBuffer = new WideLineBuffer(\n getFixedLengthWrappedDashData({\n position1: dihedralData.linePosition1,\n position2: dihedralData.linePosition2,\n color: lineColor,\n color2: lineColor\n } as CylinderBufferData) ,\n this.getBufferParams({\n linewidth: this.linewidth,\n visible: this.lineVisible,\n opacity: this.lineOpacity\n })\n )\n\n this.planeLength = dihedralData.planePosition.length / 3\n this.planeBuffer = new MeshBuffer({\n position: dihedralData.planePosition,\n color: uniformArray3(this.planeLength, c.r, c.g, c.b)\n } as BufferData, this.getBufferParams({\n visible: this.planeVisible\n }))\n\n this.sectorLength = dihedralData.sectorPosition.length / 3\n this.sectorBuffer = new MeshBuffer({\n position: dihedralData.sectorPosition,\n color: uniformArray3(this.sectorLength, c.r, c.g, c.b)\n } as BufferData, this.getBufferParams({\n visible: this.sectorVisible\n }))\n\n return {\n bufferList: [\n this.textBuffer,\n this.lineBuffer,\n this.planeBuffer,\n this.sectorBuffer\n ]\n }\n }\n\n updateData (what: LabelDataField & {color?: boolean}, data: StructureRepresentationData) {\n super.updateData(what, data)\n const lineData = {}\n const planeData = {}\n const sectorData = {}\n\n if (what.color) {\n const c = new Color(this.colorValue)\n Object.assign(lineData, {\n color: uniformArray3(this.lineLength, c.r, c.g, c.b),\n color2: uniformArray3(this.lineLength, c.r, c.g, c.b)\n })\n Object.assign(planeData, {\n color: uniformArray3(this.planeLength, c.r, c.g, c.b)\n })\n Object.assign(sectorData, {\n color: uniformArray3(this.sectorLength, c.r, c.g, c.b)\n })\n }\n\n this.lineBuffer.setAttributes(lineData)\n this.planeBuffer.setAttributes(planeData)\n this.sectorBuffer.setAttributes(sectorData)\n }\n\n setParameters (params: Partial) {\n var rebuild = false\n var what = {}\n\n super.setParameters(params, what, rebuild)\n\n if (params && (\n params.lineVisible !== undefined ||\n params.sectorVisible !== undefined ||\n params.planeVisible !== undefined)) {\n this.setVisibility(this.visible)\n }\n\n if (params && params.lineOpacity) {\n this.lineBuffer.setParameters({ opacity: params.lineOpacity })\n }\n\n if (params && params.opacity !== undefined) {\n this.lineBuffer.setParameters({ opacity: this.lineOpacity })\n }\n\n if (params && params.linewidth) {\n this.lineBuffer.setParameters({ linewidth: params.linewidth })\n }\n\n return this\n }\n\n setVisibility (value: boolean, noRenderRequest?: boolean) {\n super.setVisibility(value, true)\n\n if (this.lineBuffer) {\n this.lineBuffer.setVisibility(this.lineVisible && this.visible)\n }\n\n if (this.planeBuffer) {\n this.planeBuffer.setVisibility(this.planeVisible && this.visible)\n }\n\n if (this.sectorBuffer) {\n this.sectorBuffer.setVisibility(this.sectorVisible && this.visible)\n }\n\n if (!noRenderRequest) this.viewer.requestRender()\n\n return this\n }\n}\n\n/**\n * Build the data required to create {Buffer} objects, given positions\n * @param {Float32Array} atomPosition 3*4*nDihedral array of coordinates\n * @return {Object} Arrays for building buffers\n */\nfunction getDihedralData (position: Float32Array, params: Partial = {}) {\n const angleStep = defaults(params.angleStep, Math.PI / 90)\n const nPos = position.length\n const n = position.length / 12\n const angles = new Float32Array(n)\n const labelPosition = new Float32Array(n * 3)\n const labelText = new Array(n)\n\n // Temporary arrays as don't know output length yet\n const lineTmp1 = new Array(n)\n const lineTmp2 = new Array(n)\n const sectorTmp = new Array(n)\n const planeTmp = new Array(n)\n\n // Eventual sizes of output arrays\n let totalLines = 0\n let totalSegments = 0\n let totalPlanes = 0\n\n const p1 = v3new()\n const p2 = v3new()\n const p3 = v3new()\n const p4 = v3new()\n\n const v21 = v3new()\n const v23 = v3new()\n const v34 = v3new()\n\n const tmp = v3new()\n const mid = v3new()\n const inPlane1 = v3new()\n const inPlane2 = v3new()\n const start = v3new()\n const end = v3new()\n\n const cross = v3new()\n const arcPoint = v3new()\n\n let i = 0 // Actual output index (after skipping inappropriate)\n\n for (var p = 0; p < nPos; p += 12) {\n // Set Positions\n v3fromArray(p1, position, p)\n v3fromArray(p2, position, p + 3)\n v3fromArray(p3, position, p + 6)\n v3fromArray(p4, position, p + 9)\n\n // Vectors between points\n v3sub(v21, p1, p2)\n v3sub(v23, p3, p2)\n if (v3length(v23) === 0.0) {\n continue // Can't define axis\n }\n\n v3sub(v34, p4, p3)\n\n v3multiplyScalar(tmp, v23, 0.5)\n v3add(mid, p2, tmp)\n\n v3normalize(v21, v21)\n v3normalize(v23, v23)\n v3normalize(v34, v34)\n\n // Which side of plane are p1, p4 (are we measuring something that\n // looks more like an improper? e.g. C, CA, CB, N)\n v3sub(tmp, p1, mid)\n const improperStart = v3dot(tmp, v23) > 0.0\n v3sub(tmp, p4, mid)\n const improperEnd = v3dot(tmp, v23) < 0.0\n\n // Calculate vectors perp to v23 (lying in plane (1,2,3) and (2,3,4))\n v3multiplyScalar(tmp, v23, v3dot(v23, v21))\n v3sub(inPlane1, v21, tmp)\n\n v3multiplyScalar(tmp, v23, v3dot(v23, v34))\n v3sub(inPlane2, v34, tmp)\n\n if (v3length(inPlane1) === 0.0 || v3length(inPlane2) === 0.0) {\n continue // Indeterminate angle\n }\n\n v3normalize(inPlane1, inPlane1)\n v3normalize(inPlane2, inPlane2)\n\n const angle = angles[ i ] = v3angle(inPlane1, inPlane2)\n labelText[ i ] = (RAD2DEG * angle).toFixed(1) + String.fromCharCode(0x00B0)\n\n v3cross(cross, inPlane1, v23)\n v3normalize(cross, cross)\n if (v3dot(cross, inPlane2) < 0.0) {\n v3negate(cross, cross) // Ensure cp faces correct way\n }\n\n calcArcPoint(tmp, mid, inPlane1, cross, angle / 2.0)\n v3toArray(tmp, labelPosition, 3 * i)\n\n const nSegments = Math.ceil(angle / angleStep)\n // For extended display mode, 4 straight lines plus arc/segment edge\n // For non-extended, 2 straight lines plus segment edge\n const nLines = nSegments + ((params.extendLine) ? 4 : 2)\n\n // Don't draw planes if not extending lines\n const nPlanes = params.extendLine ? 36 : 0\n\n const line1 = new Float32Array(nLines * 3)\n const line2 = new Float32Array(nLines * 3)\n const sector = new Float32Array(nSegments * 9)\n // 2 planes, 2 triangles each per dihedral (2*2*9)\n const plane = new Float32Array(nPlanes)\n\n lineTmp1[ i ] = line1\n lineTmp2[ i ] = line2\n sectorTmp[ i ] = sector\n planeTmp[ i ] = plane\n\n // Start points for lines/planes, only required\n // if extending lines\n if (params.extendLine) {\n if (improperStart) { // We'll start on the v3->1 line (tmp)\n v3sub(tmp, p1, p3)\n v3normalize(tmp, tmp)\n v3multiplyScalar(start, tmp, 1.0 / v3dot(inPlane1, tmp))\n v3add(start, start, p3)\n } else { // start on the 2->1 line\n v3multiplyScalar(start, v21, 1.0 / v3dot(inPlane1, v21))\n v3add(start, start, p2)\n }\n\n if (improperEnd) { // Finish on 2->4 line\n v3sub(tmp, p4, p2)\n v3normalize(tmp, tmp)\n v3multiplyScalar(end, tmp, 1.0 / v3dot(inPlane2, tmp))\n v3add(end, end, p2)\n } else { // end on the 3->4 line\n v3multiplyScalar(end, v34, 1.0 / v3dot(inPlane2, v34))\n v3add(end, end, p3)\n }\n }\n\n v3add(arcPoint, mid, inPlane1)\n\n // index into line1, line2\n let li = 0\n // If extending lines, there's a bit of stuff to do here\n // figuring out start and end positions\n if (params.extendLine) {\n v3toArray(p1, line1, li)\n v3toArray(start, line2, li)\n li += 3\n v3toArray(start, line1, li)\n v3toArray(arcPoint, line2, li)\n li += 3\n\n // Construct plane at start, if not extening lines\n // this is skipped\n v3toArray(start, plane, 0)\n v3toArray(arcPoint, plane, 3)\n v3toArray(improperStart ? p3 : p2, plane, 6)\n v3toArray(improperStart ? p3 : p2, plane, 9)\n v3toArray(arcPoint, plane, 12)\n v3toArray(mid, plane, 15)\n } else {\n // Not extending lines\n v3toArray(mid, line1, li)\n v3toArray(arcPoint, line2, li)\n li += 3\n }\n\n const appendArcSection = function (a: number, j: number) {\n const si = j * 9\n\n v3toArray(mid, sector, si)\n v3toArray(arcPoint, sector, si + 3)\n v3toArray(arcPoint, line1, li)\n\n calcArcPoint(arcPoint, mid, inPlane1, cross, a)\n\n v3toArray(arcPoint, sector, si + 6)\n v3toArray(arcPoint, line2, li)\n li += 3\n }\n\n let j = 0\n for (let a = angleStep; a < angle; a += angleStep) {\n appendArcSection(a, j++)\n }\n appendArcSection(angle, j++)\n\n if (params.extendLine) {\n v3toArray(arcPoint, line1, (nLines - 2) * 3)\n v3toArray(end, line2, (nLines - 2) * 3)\n v3toArray(end, line1, (nLines - 1) * 3)\n v3toArray(p4, line2, (nLines - 1) * 3)\n\n // Construct plane at end\n v3toArray(end, plane, 18)\n v3toArray(arcPoint, plane, 21)\n v3toArray(improperEnd ? p2 : p3, plane, 24)\n v3toArray(improperEnd ? p2 : p3, plane, 27)\n v3toArray(arcPoint, plane, 30)\n v3toArray(mid, plane, 33)\n } else {\n v3toArray(arcPoint, line1, li)\n v3toArray(mid, line2, li)\n li += 3\n }\n\n totalLines += nLines * 3\n totalSegments += nSegments * 9\n totalPlanes += nPlanes\n i += 1\n }\n\n const nSuccess = i\n\n const linePosition1 = new Float32Array(totalLines)\n const linePosition2 = new Float32Array(totalLines)\n const sectorPosition = new Float32Array(totalSegments)\n const planePosition = new Float32Array(totalPlanes)\n\n let lineOffset = 0\n let sectorOffset = 0\n let planeOffset = 0\n\n for (let i = 0; i < nSuccess; i++) {\n const lp1 = lineTmp1[ i ]\n const lp2 = lineTmp2[ i ]\n const sp = sectorTmp[ i ]\n const pp = planeTmp[ i ]\n\n copyArray(lp1, linePosition1, 0, lineOffset, lp1.length)\n copyArray(lp2, linePosition2, 0, lineOffset, lp2.length)\n copyArray(sp, sectorPosition, 0, sectorOffset, sp.length)\n copyArray(pp, planePosition, 0, planeOffset, pp.length)\n\n lineOffset += lp1.length\n sectorOffset += sp.length\n planeOffset += pp.length\n }\n\n return {\n labelPosition: labelPosition.subarray(0, nSuccess * 3),\n labelText: labelText.slice(0, nSuccess),\n linePosition1,\n linePosition2,\n planePosition,\n sectorPosition\n }\n}\n\nRepresentationRegistry.add('dihedral', DihedralRepresentation)\n\nexport default DihedralRepresentation\n","/**\n * @file Dihedral Histogram Representation\n * @author Rudolfs Petrovs \n * @private\n */\nimport { Color } from 'three'\n\nimport { calcArcPoint, parseNestedAtoms } from './measurement-representation'\nimport StructureRepresentation, { StructureRepresentationParameters } from './structure-representation'\n\nimport { RepresentationRegistry } from '../globals'\nimport { Structure } from '../ngl'\nimport { defaults } from '../utils'\n\nimport { BufferData } from '../buffer/buffer'\nimport MeshBuffer from '../buffer/mesh-buffer'\nimport WideLineBuffer, { WideLineBufferData } from '../buffer/wideline-buffer'\n\nimport { copyArray, uniformArray3, arraySum } from '../math/array-utils'\nimport {\n v3add, v3cross, v3dot, v3multiplyScalar, v3fromArray,\n v3negate, v3new, v3normalize, v3sub, v3toArray, v3length\n} from '../math/vector-utils'\n\nimport StructureView from '../structure/structure-view'\n\nimport Viewer from '../viewer/viewer'\n\n\nconst pointLength = 3 // One Point Length (number of coordinates of one point in 3D)\nconst pointsInTriangle = 3\n\ntype ColorDefinition = Color | string | number | undefined\n\ninterface HistogramColorParameters {\n histogramBinBorderColor: ColorDefinition\n adjacentBondArrowColor: ColorDefinition\n distantBondArrowColor: ColorDefinition\n frontHistogramColor: ColorDefinition\n backHistogramColor: ColorDefinition\n opaqueMiddleDiscColor: ColorDefinition\n}\n\ninterface HistogramInputData extends Partial {\n atomQuad: (number | string)[]\n histogram360: number[]\n}\n\ninterface HistogramData extends HistogramInputData {\n atomPositions: Float32Array\n histogram360Scaled: number[]\n}\n\ninterface WideLineData {\n startPoints: Float32Array\n endPoints: Float32Array\n startColors: Float32Array\n endColors: Float32Array\n}\n\ninterface MeshData {\n triangles: Float32Array\n triangleColors: Float32Array\n}\n\nfunction createUpdatedObject(o: Object, updateSource: Object) {\n function hasKey(obj: O, key: keyof any): key is keyof O {\n return key in obj\n }\n\n const result = { ...o } // Shallow copy\n for (const key in result) {\n if (hasKey(result, key) && hasKey(updateSource, key)) {\n result[key] = defaults(updateSource[key], result[key])\n }\n }\n return result\n}\n\nfunction createColorArray(color: ColorDefinition, arrayLength: number) {\n const colorValue = new Color(color)\n const targetArray = new Float32Array(arrayLength * 3)\n uniformArray3(arrayLength, colorValue.r, colorValue.g, colorValue.b, targetArray)\n return targetArray\n}\n\n/**\n * @typedef {Object} DihedralHistogramRepresentationParameters - dihedral representation parameters\n * @mixes RepresentationParameters\n * @mixes StructureRepresentationParameters\n *\n * @property {HistogramInputData[]} histogramsData\n * List of HistogramInputData objects, which properties specifies each particular\n * histogram, and can contain particular histogram-specific parameters.\n * Obligatory properties are:\n * atomQuad - Quadruplet of selection strings or atom indices\n * histogram360 - List of values, representing histogram from 0 to 360 degrees.\n * @property {Boolean} histogramBinBorderVisible - Display the lines that separate circular histogram bins\n * @property {Boolean} scaleBinToSectorArea - Should sector-based histogram bins'\n * area be proportional to the bins' value\n */\n\nexport interface DihedralHistogramRepresentationParameters extends StructureRepresentationParameters {\n histogramsData: HistogramInputData[]\n\n histogramBinBorderVisible: boolean\n scaleBinToSectorArea: boolean\n}\n\n/**\n * Dihedral Histogram representation object\n *\n * Reperesentation consists of several parts:\n * opaqueMiddleDisc - opaque disc in the middle of the dihedral between front and back histograms\n * frontHistogram - circular histogram from the adjacent bond viewpoint\n * backHistogram - circular histogram from the distant bond viewpoint\n * histogramBinBorder - lines, which separate histogram bins\n * bondArrows - lines, which show the actual angle on the histogram disc\n *\n * @param {Structure} structure - the structure to measure angles in\n * @param {Viewer} viewer - a viewer object\n * @param {DihedralHistogramRepresentationParameters} params - Dihedral histogram representation parameters\n */\nclass DihedralHistogramRepresentation extends StructureRepresentation {\n protected histogramsData: HistogramData[]\n\n protected histogramBinBorderVisible: boolean\n protected histogramBinBorderWidth: number\n protected histogramBinBorderColor: ColorDefinition\n protected histogramBinBorderOpacity: number\n\n protected bondArrowVisible: boolean\n protected bondArrowWidth: number\n protected bondArrowOpacity: number\n\n protected adjacentBondArrowColor: ColorDefinition\n protected distantBondArrowColor: ColorDefinition\n\n protected histogramOpacity: number\n protected frontHistogramColor: ColorDefinition\n protected backHistogramColor: ColorDefinition\n\n protected opaqueMiddleDiscVisible: boolean\n protected opaqueMiddleDiscColor: ColorDefinition\n protected opaqueMiddleDiscOpacity: number\n\n protected scaleBinToSectorArea: boolean\n\n constructor(structure: Structure, viewer: Viewer, params: DihedralHistogramRepresentationParameters) {\n super(structure, viewer, params)\n\n this.type = 'dihedral-histogram'\n\n this.parameters = Object.assign({\n histogramsData: {\n type: 'hidden', rebuild: true\n },\n histogramBinBorderVisible: {\n type: 'boolean', default: true\n },\n scaleBinToSectorArea: {\n type: 'boolean',\n rebuild: true,\n default: false\n }\n }, this.parameters)\n\n this.init(params)\n }\n\n init(params: Partial) {\n const p = params || {}\n\n const defaultColorData = {\n histogramBinBorderColor: 'grey',\n adjacentBondArrowColor: 'black',\n distantBondArrowColor: 'magenta',\n frontHistogramColor: 'green',\n backHistogramColor: 'blue',\n opaqueMiddleDiscColor: 'white'\n }\n\n const colorData = createUpdatedObject(defaultColorData, p)\n Object.assign(this, colorData)\n\n const defaultParameters = {\n histogramsData: [],\n histogramOpacity: 1.0,\n\n opaqueMiddleDiscVisible: true,\n opaqueMiddleDiscOpacity: 1.0,\n\n histogramBinBorderVisible: true,\n histogramBinBorderWidth: 1,\n histogramBinBorderOpacity: 0.5,\n\n bondArrowVisible: true,\n bondArrowWidth: 2,\n bondArrowOpacity: 1.0,\n\n scaleBinToSectorArea: false,\n }\n const parameters = createUpdatedObject(defaultParameters, p)\n Object.assign(this, parameters)\n\n this.histogramsData.forEach(x => {\n const specificColorData = createUpdatedObject(colorData, x)\n Object.assign(x, specificColorData)\n })\n\n p.side = defaults(p.side, 'double')\n p.opacity = defaults(p.opacity, 0.5)\n p.radiusType = defaults(p.radiusType, 'size')\n p.radiusSize = defaults(p.radiusSize, 0.15)\n\n super.init(p)\n }\n\n getHistogramBinBorderBufferParameters() {\n return this.getBufferParams({\n linewidth: this.histogramBinBorderWidth,\n visible: this.histogramBinBorderVisible,\n opacity: this.histogramBinBorderOpacity,\n })\n }\n\n getBondArrowsBufferParameters() {\n return this.getBufferParams({\n linewidth: this.bondArrowWidth,\n visible: this.bondArrowVisible,\n opacity: this.bondArrowOpacity,\n })\n }\n\n getOpaqueMiddleDiscBufferParameters() {\n return this.getBufferParams({\n visible: this.opaqueMiddleDiscVisible,\n opacity: this.opaqueMiddleDiscOpacity\n })\n }\n\n getHistogramBufferParameters() {\n return this.getBufferParams({\n visible: true,\n opacity: this.histogramOpacity,\n side: \"double\"\n })\n }\n\n createData(sview: StructureView) {\n if (!sview.atomCount || !this.histogramsData.length) return\n this.histogramsData.forEach(x => x.atomPositions = parseNestedAtoms(sview, [x.atomQuad]))\n const scaleData = this.scaleBinToSectorArea ? function (y: number) { return Math.sqrt(y) } : function (y: number) { return y }\n this.histogramsData.forEach(x => x.histogram360Scaled = x.histogram360.map(scaleData))\n function Float32Concat(arrays: Float32Array[]) {\n const lengths = arrays.map(x => x.length)\n const result = new Float32Array(arraySum(lengths))\n let accumulatedOffset = 0\n for (let i = 0; i < arrays.length; i++) {\n result.set(arrays[i], accumulatedOffset)\n accumulatedOffset += arrays[i].length\n }\n return result\n }\n\n function createWideLineBuffer(linesList: WideLineData[], params: {}) {\n return new WideLineBuffer(\n {\n position1: Float32Concat(linesList.map(x => x.startPoints)),\n position2: Float32Concat(linesList.map(x => x.endPoints)),\n color: Float32Concat(linesList.map(x => x.startColors)),\n color2: Float32Concat(linesList.map(x => x.endColors)),\n } as WideLineBufferData,\n params)\n }\n\n function createMeshBuffer(mesh: MeshData[], params: {}) {\n return new MeshBuffer(\n {\n position: Float32Concat(mesh.map(x => x.triangles)),\n color: Float32Concat(mesh.map(x => x.triangleColors))\n } as BufferData,\n params)\n }\n\n const dihedralDataArray = []\n\n for (let i = 0; i < this.histogramsData.length; i++) {\n let dihedralData = undefined\n let currentHistogramData = this.histogramsData[i]\n let currentHistogram360 = currentHistogramData.histogram360\n if (currentHistogram360.length >= 3) {\n dihedralData = calculateDihedralHistogram(currentHistogramData)\n }\n if (typeof dihedralData === \"undefined\") continue\n dihedralDataArray.push(dihedralData)\n }\n\n this.frontHistogramBinBordersBuffer = createWideLineBuffer(\n dihedralDataArray.map(x => x.frontHistogramBinBorders),\n this.getHistogramBinBorderBufferParameters()\n )\n\n this.backHistogramBinBordersBuffer = createWideLineBuffer(\n dihedralDataArray.map(x => x.backHistogramBinBorders),\n this.getHistogramBinBorderBufferParameters()\n )\n\n this.adjacentBondArrowsBuffer = createWideLineBuffer(\n dihedralDataArray.map(x => x.adjacentBondArrows),\n this.getBondArrowsBufferParameters()\n )\n\n this.distantBondArrowsBuffer = createWideLineBuffer(\n dihedralDataArray.map(x => x.distantBondArrows),\n this.getBondArrowsBufferParameters()\n )\n\n this.opaqueMiddleDiscBuffer = createMeshBuffer(\n dihedralDataArray.map(x => x.opaqueMiddleDisc),\n this.getOpaqueMiddleDiscBufferParameters()\n )\n\n this.frontHistogramBuffer = createMeshBuffer(\n dihedralDataArray.map(x => x.frontHistogram),\n this.getHistogramBufferParameters()\n )\n\n this.backHistogramBuffer = createMeshBuffer(\n dihedralDataArray.map(x => x.backHistogram),\n this.getHistogramBufferParameters()\n )\n\n return {\n bufferList: [].concat(\n this.frontHistogramBinBordersBuffer,\n this.backHistogramBinBordersBuffer,\n this.adjacentBondArrowsBuffer,\n this.distantBondArrowsBuffer,\n this.opaqueMiddleDiscBuffer,\n this.frontHistogramBuffer,\n this.backHistogramBuffer\n )\n }\n }\n\n setParameters(params: Partial) {\n const rebuild = false\n const what = {}\n super.setParameters(params, what, rebuild)\n\n if (params && (params.histogramBinBorderVisible !== undefined)) {\n this.setVisibility(this.visible)\n }\n return this\n }\n\n setVisibility(value: boolean, noRenderRequest?: boolean) {\n super.setVisibility(value, true)\n if (this.frontHistogramBinBordersBuffer) {\n this.frontHistogramBinBordersBuffer.setVisibility(this.histogramBinBorderVisible)\n }\n if (this.backHistogramBinBordersBuffer) {\n this.backHistogramBinBordersBuffer.setVisibility(this.histogramBinBorderVisible)\n }\n if (!noRenderRequest) this.viewer.requestRender()\n return this\n }\n}\n\n/**\n * Calculates the data required to create {Buffer} objects for one histogram, given positions\n * @param Float32Array positionOfDihedralAtoms 3*4 array of coordinates\n * @param NumberArray histogram array of coordinates\n * @return Arrays for building buffers\n */\nfunction calculateDihedralHistogram(histogramData: HistogramData) {\n const positionOfDihedralAtoms = histogramData.atomPositions\n const histogram = histogramData.histogram360Scaled;\n const totalSectorTrianglesInOpaqueMiddleDisc = histogram.length <= 180 ? 360 : histogram.length * 2\n const frontAndBack = 2\n\n const opaqueMiddleDisc = {\n triangles: new Float32Array(totalSectorTrianglesInOpaqueMiddleDisc * pointsInTriangle * pointLength),\n triangleColors: createColorArray(histogramData.opaqueMiddleDiscColor, totalSectorTrianglesInOpaqueMiddleDisc * pointsInTriangle)\n }\n\n const frontHistogram = {\n triangles: new Float32Array(histogram.length * pointsInTriangle * pointLength),\n triangleColors: createColorArray(histogramData.frontHistogramColor, histogram.length * pointsInTriangle)\n }\n\n const backHistogram = {\n triangles: new Float32Array(histogram.length * pointsInTriangle * pointLength),\n triangleColors: createColorArray(histogramData.backHistogramColor, histogram.length * pointsInTriangle)\n }\n\n const frontHistogramBinBorders = {\n startPoints: new Float32Array(histogram.length * pointLength),\n endPoints: new Float32Array(histogram.length * pointLength),\n startColors: createColorArray(histogramData.histogramBinBorderColor, histogram.length),\n endColors: createColorArray(histogramData.histogramBinBorderColor, histogram.length)\n }\n\n const backHistogramBinBorders = {\n startPoints: new Float32Array(histogram.length * pointLength),\n endPoints: new Float32Array(histogram.length * pointLength),\n startColors: createColorArray(histogramData.histogramBinBorderColor, histogram.length),\n endColors: createColorArray(histogramData.histogramBinBorderColor, histogram.length)\n }\n\n const adjacentBondArrows = {\n startPoints: new Float32Array(frontAndBack * pointLength),\n endPoints: new Float32Array(frontAndBack * pointLength),\n startColors: createColorArray(histogramData.adjacentBondArrowColor, histogram.length),\n endColors: createColorArray(histogramData.adjacentBondArrowColor, histogram.length)\n }\n const distantBondArrows = {\n startPoints: new Float32Array(frontAndBack * pointLength),\n endPoints: new Float32Array(frontAndBack * pointLength),\n startColors: createColorArray(histogramData.distantBondArrowColor, histogram.length),\n endColors: createColorArray(histogramData.distantBondArrowColor, histogram.length)\n }\n\n const p1 = v3new()\n const p2 = v3new()\n const p3 = v3new()\n const p4 = v3new()\n\n const v21 = v3new()\n const v23 = v3new()\n const v32 = v3new()\n const v34 = v3new()\n\n const mid = v3new()\n const inPlane1 = v3new()\n const inPlane2 = v3new()\n\n const cross1 = v3new()\n const cross2 = v3new()\n\n const arcPoint = v3new()\n const tmp = v3new()\n const tmp2 = v3new()\n\n // Set Atom Coordinates\n const dihedralAtomVectors = [p1, p2, p3, p4]\n\n for (let i = 0; i < dihedralAtomVectors.length; i++) {\n v3fromArray(dihedralAtomVectors[i], positionOfDihedralAtoms, i * pointLength)\n }\n\n // Vectors between points\n v3sub(v21, p1, p2)\n v3sub(v23, p3, p2)\n v3sub(v34, p4, p3)\n if (v3length(v23) === 0.0) {\n return // Can't define axis\n }\n\n v3multiplyScalar(tmp, v23, 0.5)\n v3add(mid, p2, tmp)\n\n v3normalize(v21, v21)\n v3normalize(v23, v23)\n v3normalize(v34, v34)\n\n v3negate(v32, v23)\n // Calculate vectors perp to v23 (lying in plane (1,2,3) and (2,3,4))\n v3multiplyScalar(tmp, v32, v3dot(v32, v21))\n v3sub(inPlane1, v21, tmp)\n\n v3multiplyScalar(tmp, v23, v3dot(v23, v34))\n v3sub(inPlane2, v34, tmp)\n\n if (v3length(inPlane1) === 0.0 || v3length(inPlane2) === 0.0) {\n return // Indeterminate angle\n }\n\n v3normalize(inPlane1, inPlane1)\n v3normalize(inPlane2, inPlane2)\n\n // Can use acos as normalized and non-zero\n const absAngle = Math.acos(v3dot(inPlane1, inPlane2))\n\n v3cross(cross1, v32, inPlane1)\n v3cross(cross2, v23, inPlane2)\n v3normalize(cross1, cross1)\n v3normalize(cross2, cross2)\n\n let angle = absAngle\n if (v3dot(cross1, inPlane2) < 0.0) {\n angle = -absAngle\n }\n\n v3add(arcPoint, mid, inPlane1)\n\n // Calculate necessary constants\n const maxHist = Math.max.apply(null, histogram)\n const histBinAngleStep = (Math.PI * 2) / histogram.length\n\n function setHistogramBinCoordinates(out: Float32Array, ind: number, zeroDegreeVector: Float32Array, crossVector: Float32Array, histBinAngleStep: number) {\n const startOffset = ind * pointsInTriangle * pointLength\n v3toArray(mid, out, startOffset)\n const scalingFactor = Number(histogram[ind]) / maxHist\n v3multiplyScalar(tmp, zeroDegreeVector, scalingFactor)\n v3multiplyScalar(tmp2, crossVector, scalingFactor)\n calcArcPoint(arcPoint, mid, tmp, tmp2, ind * histBinAngleStep)\n v3toArray(arcPoint, out, startOffset + 1 * pointLength)\n calcArcPoint(arcPoint, mid, tmp, tmp2, (ind + 1) * histBinAngleStep)\n v3toArray(arcPoint, out, startOffset + 2 * pointLength)\n }\n\n function setOneSideHistogram(discHistogram: MeshData, binBorders: { startPoints: Float32Array, endPoints: Float32Array }, ind: number, zeroDegreeVector: Float32Array, crossVector: Float32Array) {\n // Set Bond Arrows\n\n copyArray(mid, adjacentBondArrows.startPoints, 0, ind * pointLength, mid.length)\n calcArcPoint(tmp, mid, zeroDegreeVector, crossVector, 0 + histBinAngleStep * 0)\n copyArray(tmp, adjacentBondArrows.endPoints, 0, ind * pointLength, mid.length)\n\n copyArray(mid, distantBondArrows.startPoints, 0, ind * pointLength, mid.length)\n calcArcPoint(tmp, mid, zeroDegreeVector, crossVector, angle)\n copyArray(tmp, distantBondArrows.endPoints, 0, ind * pointLength, mid.length)\n\n // Set Histogram Bin Borders\n\n for (let i = 0; i < histogram.length; i++) {\n copyArray(mid, binBorders.startPoints, 0, i * 3, mid.length)\n calcArcPoint(tmp, mid, zeroDegreeVector, crossVector, 0 + histBinAngleStep * i)\n copyArray(tmp, binBorders.endPoints, 0, i * 3, tmp.length)\n }\n\n // Set Histogram Bins\n\n for (let sectionIndex = 0; sectionIndex < histogram.length; sectionIndex++) {\n setHistogramBinCoordinates(discHistogram.triangles, sectionIndex, zeroDegreeVector, crossVector, histBinAngleStep)\n }\n }\n\n // Opaque disc\n const opaqueCircleSectorAngleStep = Math.PI * 2 / totalSectorTrianglesInOpaqueMiddleDisc\n\n for (let sectionIndex = 0; sectionIndex < totalSectorTrianglesInOpaqueMiddleDisc; sectionIndex++) {\n const startOffset = sectionIndex * pointsInTriangle * pointLength\n v3toArray(mid, opaqueMiddleDisc.triangles, startOffset)\n calcArcPoint(arcPoint, mid, inPlane1, cross1, sectionIndex * opaqueCircleSectorAngleStep)\n v3toArray(arcPoint, opaqueMiddleDisc.triangles, startOffset + 1 * pointLength)\n calcArcPoint(arcPoint, mid, inPlane1, cross1, (sectionIndex + 1) * opaqueCircleSectorAngleStep)\n v3toArray(arcPoint, opaqueMiddleDisc.triangles, startOffset + 2 * pointLength)\n }\n\n // Front Histogram\n const distanceToOpaqueDisc = 0.01\n v3multiplyScalar(tmp, v23, -distanceToOpaqueDisc) // Get a vector to move \"mid\" just a bit from opaque disc\n v3add(mid, mid, tmp)\n setOneSideHistogram(frontHistogram, frontHistogramBinBorders, 0, inPlane1, cross1)\n\n // Back Histogram\n v3multiplyScalar(tmp, v23, 2 * distanceToOpaqueDisc) // Get a vector to move \"mid\" back and plus just a bit from opaque disc the other way\n v3add(mid, mid, tmp)\n setOneSideHistogram(backHistogram, backHistogramBinBorders, 1, inPlane2, cross2)\n\n return {\n opaqueMiddleDisc,\n frontHistogram,\n backHistogram,\n frontHistogramBinBorders,\n backHistogramBinBorders,\n adjacentBondArrows,\n distantBondArrows\n }\n}\n\nRepresentationRegistry.add('dihedral-histogram', DihedralHistogramRepresentation)\n\nexport default DihedralHistogramRepresentation\n","/**\n * @file Distance Representation\n * @author Alexander Rose \n * @author Fred Ludlow \n * @private\n */\n\nimport { Color } from 'three'\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { DistancePicker } from '../utils/picker'\nimport { uniformArray, uniformArray3 } from '../math/array-utils'\nimport BitArray from '../utils/bitarray'\nimport MeasurementRepresentation, { MeasurementRepresentationParameters } from './measurement-representation'\nimport Selection from '../selection/selection'\nimport BondStore from '../store/bond-store'\nimport TextBuffer, { TextBufferData, TextBufferParameters } from '../buffer/text-buffer'\nimport WideLineBuffer from '../buffer/wideline-buffer'\nimport CylinderBuffer, { CylinderBufferData } from '../buffer/cylinder-buffer'\nimport { getFixedLengthDashData } from '../geometry/dash'\nimport Viewer from '../viewer/viewer';\nimport { Structure } from '../ngl';\nimport StructureView from '../structure/structure-view';\nimport { BondDataFields, BondDataParams, BondData } from '../structure/structure-data';\nimport { StructureRepresentationData } from './structure-representation';\nimport CylinderGeometryBuffer from '../buffer/cylindergeometry-buffer';\n\n/**\n * Distance representation parameter object.\n * @typedef {Object} DistanceRepresentationParameters - distance representation parameters\n * @mixes RepresentationParameters\n * @mixes StructureRepresentationParameters\n * @mixes MeasurementRepresentationParameters\n *\n * @property {String} labelUnit - distance unit (e.g. \"angstrom\" or \"nm\"). If set, a distance\n * symbol is appended to the label (i.e. 'nm' or '\\u00C5'). In case of 'nm', the\n * distance value is computed in nanometers instead of Angstroms.\n * @property {Array[]} atomPair - list of pairs of selection strings (see {@link Selection})\n * or pairs of atom indices. Using atom indices is much more\n * efficient when the representation is updated often, e.g. by\n * changing the selection or the atom positions, as there\n * are no selection strings to be evaluated.\n */\nexport interface DistanceRepresentationParameters extends MeasurementRepresentationParameters {\n labelUnit: string\n atomPair: AtomPair\n useCylinder: boolean\n}\nexport type AtomPair = (number|string)[][]\n/**\n * Distance representation\n */\nclass DistanceRepresentation extends MeasurementRepresentation {\n protected labelUnit: string\n protected atomPair: AtomPair\n protected useCylinder: boolean\n protected distanceBuffer: WideLineBuffer|CylinderGeometryBuffer\n /**\n * Create Distance representation object\n * @example\n * stage.loadFile( \"rcsb://1crn\" ).then( function( o ){\n * o.addRepresentation( \"cartoon\" );\n * // either give selections (uses first selected atom) ...\n * var atomPair = [ [ \"1.CA\", \"4.CA\" ], [ \"7.CA\", \"13.CA\" ] ];\n * // or atom indices\n * var atomPair = [ [ 8, 28 ], [ 173, 121 ] ];\n * o.addRepresentation( \"distance\", { atomPair: atomPair } );\n * stage.autoView();\n * } );\n * @param {Structure} structure - the structure to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {DistanceRepresentationParameters} params - distance representation parameters\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'distance'\n\n this.parameters = Object.assign({\n radialSegments: true,\n openEnded: true,\n disableImpostor: true,\n labelUnit: {\n type: 'select',\n rebuild: true,\n options: { '': '', angstrom: 'angstrom', nm: 'nm' }\n },\n useCylinder: {\n type: 'boolean', rebuild: true\n },\n atomPair: {\n type: 'hidden', rebuild: true\n }\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.linewidth = defaults(p.linewidth, 5.0)\n p.radiusType = defaults(p.radiusType, 'size')\n p.radiusSize = defaults(p.radiusSize, 0.2)\n\n this.labelUnit = defaults(p.labelUnit, '')\n this.useCylinder = defaults(p.useCylinder, false)\n this.atomPair = defaults(p.atomPair, [])\n\n super.init(p)\n }\n\n getDistanceData (sview: StructureView, atomPair: AtomPair) {\n let n = atomPair.length\n const text = new Array(n)\n let position = new Float32Array(n * 3)\n const sele1 = new Selection()\n const sele2 = new Selection()\n\n const bondStore = new BondStore()\n\n const ap1 = sview.getAtomProxy()\n const ap2 = sview.getAtomProxy()\n\n let j = 0 // Skipped pairs\n const selected = sview.getAtomSet()\n\n atomPair.forEach((pair, i) => {\n let v1 = pair[ 0 ]\n let v2 = pair[ 1 ]\n\n if (typeof(v1) === 'number' && Number.isInteger(v1) && typeof(v2) === 'number' && Number.isInteger(v2)) {\n if (selected.get(v1) && selected.get(v2)) {\n ap1.index = v1\n ap2.index = v2\n } else {\n j += 1\n return\n }\n } else {\n sele1.setString(v1 as string)\n sele2.setString(v2 as string)\n\n var atomIndices1 = sview.getAtomIndices(sele1)\n var atomIndices2 = sview.getAtomIndices(sele2)\n\n if (atomIndices1!.length && atomIndices2!.length) {\n ap1.index = atomIndices1![ 0 ]\n ap2.index = atomIndices2![ 0 ]\n } else {\n j += 1\n return\n }\n }\n\n bondStore.addBond(ap1, ap2, 1)\n\n i -= j\n var d = ap1.distanceTo(ap2)\n switch (this.labelUnit) {\n case 'angstrom':\n text[ i ] = d.toFixed(2) + ' ' + String.fromCharCode(0x212B)\n break\n case 'nm':\n text[ i ] = (d / 10).toFixed(2) + ' nm'\n break\n default:\n text[ i ] = d.toFixed(2)\n break\n }\n\n var i3 = i * 3\n position[ i3 + 0 ] = (ap1.x + ap2.x) / 2\n position[ i3 + 1 ] = (ap1.y + ap2.y) / 2\n position[ i3 + 2 ] = (ap1.z + ap2.z) / 2\n })\n\n if (j > 0) {\n n -= j\n position = position.subarray(0, n * 3)\n }\n\n var bondSet = new BitArray(bondStore.count, true)\n\n return {\n text: text,\n position: position,\n bondSet: bondSet,\n bondStore: bondStore\n }\n }\n\n getBondData (sview: StructureView, what: BondDataFields, params: BondDataParams): BondData {\n const bondData = sview.getBondData(this.getBondParams(what, params))\n if (bondData.picking) {\n bondData.picking = new DistancePicker(\n bondData.picking.array,\n bondData.picking.structure,\n params.bondStore!\n ) as any\n }\n return bondData\n }\n\n createData (sview: StructureView) {\n if (!sview.atomCount || !this.atomPair.length) return\n\n const n = this.atomPair.length\n const c = new Color(this.labelColor)\n const distanceData = this.getDistanceData(sview, this.atomPair)\n\n this.textBuffer = new TextBuffer({\n position: distanceData.position,\n size: uniformArray(n, this.labelSize),\n color: uniformArray3(n, c.r, c.g, c.b),\n text: distanceData.text\n } as TextBufferData, this.getLabelBufferParams() as TextBufferParameters)\n\n const bondParams = {\n bondSet: distanceData.bondSet,\n bondStore: distanceData.bondStore\n }\n\n const bondData = this.getBondData(\n sview,\n { position: true, color: true, picking: true, radius: this.useCylinder },\n bondParams\n )\n\n if (this.useCylinder) {\n this.distanceBuffer = new CylinderBuffer(\n bondData as CylinderBufferData,\n this.getBufferParams({\n openEnded: this.openEnded,\n radialSegments: this.radialSegments,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n }) \n ) as CylinderGeometryBuffer\n } else {\n this.distanceBuffer = new WideLineBuffer(\n getFixedLengthDashData(bondData as CylinderBufferData),\n this.getBufferParams({\n linewidth: this.linewidth,\n visible: this.lineVisible,\n opacity: this.lineOpacity\n })\n )\n }\n\n return {\n bondSet: distanceData.bondSet,\n bondStore: distanceData.bondStore,\n position: distanceData.position,\n bufferList: [ this.textBuffer, this.distanceBuffer ]\n }\n }\n\n updateData (what: BondDataFields, data: StructureRepresentationData) {\n super.updateData(what, data)\n\n const bondParams = {\n bondSet: data.bondSet,\n bondStore: data.bondStore\n }\n\n const bondData = this.getBondData(data.sview as StructureView, what, bondParams)\n const distanceData = {}\n\n if (!what || what.color) {\n Object.assign( distanceData, {\n color: bondData.color,\n color2: bondData.color2\n })\n }\n\n if (!what || what.radius) {\n Object.assign( distanceData, {radius: bondData.radius})\n }\n\n (this.distanceBuffer as CylinderGeometryBuffer).setAttributes(distanceData)\n }\n\n setParameters (params: Partial) {\n let rebuild = false\n const what = {}\n\n super.setParameters(params, what, rebuild)\n\n if (!this.useCylinder) {\n if (params && params.lineOpacity) {\n (this.distanceBuffer as WideLineBuffer).setParameters({ opacity: params.lineOpacity })\n }\n if (params && params.opacity !== undefined) {\n (this.distanceBuffer as WideLineBuffer).setParameters({ opacity: this.lineOpacity })\n }\n if (params && params.linewidth) {\n (this.distanceBuffer as WideLineBuffer).setParameters({ linewidth: params.linewidth })\n }\n }\n\n return this\n }\n}\n\nRepresentationRegistry.add('distance', DistanceRepresentation)\n\nexport default DistanceRepresentation\n","/**\n * @file Vector Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3, Matrix4 required for declaration only\nimport { Color, Matrix4, Vector3 } from 'three'\n\nimport '../shader/Line.vert'\nimport '../shader/Line.frag'\n\nimport { uniformArray3 } from '../math/array-utils'\nimport Buffer, { BufferDefaultParameters, BufferData, BufferParameters } from './buffer'\nimport { GenericColor } from '../types'\n\nfunction getSize(data: BufferData){\n const n = data.position!.length / 3\n return n * 2 * 3\n}\n\nexport interface VectorBufferData extends BufferData {\n vector: Float32Array\n}\n\nexport const VectorBufferDefaultParameters = Object.assign({\n scale: 1,\n color: 'grey'\n}, BufferDefaultParameters)\nexport type VectorBufferParameters = BufferParameters & { scale: number, color: GenericColor }\n\n/**\n * Vector buffer. Draws vectors as lines.\n */\nclass VectorBuffer extends Buffer {\n get defaultParameters() { return VectorBufferDefaultParameters }\n parameters: VectorBufferParameters\n\n isLine = true\n vertexShader = 'Line.vert'\n fragmentShader = 'Line.frag'\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.vector - vectors\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: VectorBufferData, params: Partial = {}) {\n super({\n position: new Float32Array(getSize(data)),\n color: new Float32Array(getSize(data))\n }, params)\n\n const color = new Color(this.parameters.color)\n const attributes = this.geometry.attributes as any // TODO\n uniformArray3(getSize(data) / 3, color.r, color.g, color.b, attributes.color.array)\n\n this.setAttributes(data)\n }\n\n setAttributes (data: Partial = {}) {\n const attributes = this.geometry.attributes as any // TODO\n\n let position, vector\n let aPosition\n\n if (data.position && data.vector) {\n position = data.position\n vector = data.vector\n aPosition = attributes.position.array\n attributes.position.needsUpdate = true\n }\n\n const n = this.size / 2\n const scale = this.parameters.scale\n\n if (position && vector) {\n for (let v = 0; v < n; v++) {\n const i = v * 2 * 3\n const j = v * 3\n\n aPosition[ i + 0 ] = position[ j + 0 ]\n aPosition[ i + 1 ] = position[ j + 1 ]\n aPosition[ i + 2 ] = position[ j + 2 ]\n aPosition[ i + 3 ] = position[ j + 0 ] + vector[ j + 0 ] * scale\n aPosition[ i + 4 ] = position[ j + 1 ] + vector[ j + 1 ] * scale\n aPosition[ i + 5 ] = position[ j + 2 ] + vector[ j + 2 ] * scale\n }\n }\n }\n}\n\nexport default VectorBuffer\n","/**\n * @file Helixorient Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { Debug, Log, RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport Helixorient from '../geometry/helixorient'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport SphereBuffer, { SphereBufferParameters } from '../buffer/sphere-buffer'\nimport VectorBuffer from '../buffer/vector-buffer'\nimport Viewer from '../viewer/viewer';\nimport { Structure } from '../ngl';\nimport StructureView from '../structure/structure-view';\nimport Polymer from '../proxy/polymer';\nimport { AtomDataFields } from '../structure/structure-data';\nimport SphereGeometryBuffer from '../buffer/spheregeometry-buffer';\nimport SphereImpostorBuffer from '../buffer/sphereimpostor-buffer';\nimport { BufferData } from '../buffer/buffer';\n\n/**\n * Helixorient Representation\n */\nclass HelixorientRepresentation extends StructureRepresentation {\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'helixorient'\n\n this.parameters = Object.assign({\n sphereDetail: true,\n disableImpostor: true\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'sstruc')\n p.radiusType = defaults(p.radiusType, 'size')\n p.radiusSize = defaults(p.radiusSize, 0.15)\n p.radiusScale = defaults(p.radiusScale, 1.0)\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n super.init(p)\n }\n\n createData (sview: StructureView) {\n const bufferList: (SphereBuffer|VectorBuffer)[] = []\n const polymerList: Polymer[] = []\n\n this.structure.eachPolymer(polymer => {\n if (polymer.residueCount < 4) return\n polymerList.push(polymer)\n\n const helixorient = new Helixorient(polymer)\n const position = helixorient.getPosition()\n const color = helixorient.getColor(this.getColorParams())\n const size = helixorient.getSize(this.getRadiusParams())\n const picking = helixorient.getPicking()\n\n bufferList.push(\n new SphereBuffer(\n {\n position: position.center,\n color: color.color,\n radius: size.size,\n picking: picking.picking\n },\n this.getBufferParams({\n sphereDetail: this.sphereDetail,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n }) as SphereBufferParameters\n ),\n new VectorBuffer(\n {\n position: position.center,\n vector: position.axis\n },\n this.getBufferParams({\n color: 'skyblue',\n scale: 1\n })\n ),\n new VectorBuffer(\n {\n position: position.center,\n vector: position.resdir\n },\n this.getBufferParams({\n color: 'lightgreen',\n scale: 1\n })\n )\n )\n }, sview.getSelection())\n\n return {\n bufferList: bufferList as (SphereGeometryBuffer|SphereImpostorBuffer|VectorBuffer)[],\n polymerList: polymerList\n }\n }\n\n updateData (what: AtomDataFields, data: StructureRepresentationData) {\n if (Debug) Log.time(this.type + ' repr update')\n\n what = what || {}\n\n for (let i = 0, il = data.polymerList!.length; i < il; ++i) {\n const j = i * 3\n\n const bufferData: Partial = {}\n const polymer = data.polymerList![ i ]\n const helixorient = new Helixorient(polymer)\n\n if (what.position) {\n const position = helixorient.getPosition()\n\n Object.assign(bufferData, {position: position.center})\n\n data.bufferList[ j + 1 ].setAttributes({\n 'position': position.center,\n 'vector': position.axis\n })\n data.bufferList[ j + 2 ].setAttributes({\n 'position': position.center,\n 'vector': position.resdir\n })\n }\n\n data.bufferList[ j ].setAttributes(bufferData)\n }\n\n if (Debug) Log.timeEnd(this.type + ' repr update')\n }\n}\n\nRepresentationRegistry.add('helixorient', HelixorientRepresentation)\n\nexport default HelixorientRepresentation\n","/**\n * @file Licorice Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport BallAndStickRepresentation, { BallAndStickRepresentationParameters } from './ballandstick-representation'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\n\n/**\n * Licorice representation object ({@link BallAndStickRepresentation} with `aspectRatio` fixed at 1.0)\n */\nclass LicoriceRepresentation extends BallAndStickRepresentation {\n /**\n * Create Licorice representation object\n * @param {Structure} structure - the structure to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {BallAndStickRepresentationParameters} params - ball and stick representation parameters\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'licorice'\n\n this.parameters = Object.assign(\n {}, this.parameters, { aspectRatio: null }\n )\n }\n\n init (params: Partial) {\n var p = params || {}\n p.aspectRatio = 1.0\n\n super.init(p)\n }\n}\n\nRepresentationRegistry.add('licorice', LicoriceRepresentation)\n\nexport default LicoriceRepresentation\n","/**\n * @file Mapped Box Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { BufferParameters, BufferData } from './buffer'\nimport MappedBuffer from './mapped-buffer'\n\nconst mapping = new Float32Array([\n -1.0, -1.0, -1.0,\n 1.0, -1.0, -1.0,\n 1.0, -1.0, 1.0,\n -1.0, -1.0, 1.0,\n -1.0, 1.0, -1.0,\n 1.0, 1.0, -1.0,\n 1.0, 1.0, 1.0,\n -1.0, 1.0, 1.0\n])\n\nconst mappingIndices = new Uint16Array([\n 0, 1, 2,\n 0, 2, 3,\n 1, 5, 6,\n 1, 6, 2,\n 4, 6, 5,\n 4, 7, 6,\n 0, 7, 4,\n 0, 3, 7,\n 0, 5, 1,\n 0, 4, 5,\n 3, 2, 6,\n 3, 6, 7\n])\n\n/**\n * Mapped Box buffer. Draws boxes. Used to render general imposters.\n * @interface\n */\nclass MappedBoxBuffer extends MappedBuffer {\n constructor(data: BufferData, params: Partial = {}) {\n super('v3', data, params)\n }\n get mapping () { return mapping }\n get mappingIndices () { return mappingIndices }\n get mappingIndicesSize () { return 36 }\n get mappingSize () { return 8 }\n get mappingItemSize () { return 3 }\n}\n\nexport default MappedBoxBuffer\n","/**\n * @file Hyperball Stick Impostor Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import Vector3 required for declaration only\nimport { Matrix4, Vector3 } from 'three'\n\nimport '../shader/HyperballStickImpostor.vert'\nimport '../shader/HyperballStickImpostor.frag'\n\nimport MappedBoxBuffer from './mappedbox-buffer'\nimport { BufferDefaultParameters, BufferParameterTypes, BufferData, BufferParameters } from './buffer'\n\nexport interface HyperballStickImpostorBufferData extends BufferData {\n position1: Float32Array\n position2: Float32Array\n color2: Float32Array\n radius: Float32Array\n radius2: Float32Array\n}\n\nexport const HyperballStickImpostorBufferDefaultParameters = Object.assign({\n shrink: 0.14\n}, BufferDefaultParameters)\nexport type HyperballStickImpostorBufferParameters = BufferParameters & { shrink: number }\n\nconst HyperballStickImpostorBufferParameterTypes = Object.assign({\n shrink: { uniform: true }\n}, BufferParameterTypes)\n\n/**\n * Hyperball stick impostor buffer.\n *\n * @example\n * var hyperballStickImpostorBuffer = new HyperballStickImpostorBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 2, 2, 2 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * color2: new Float32Array([ 0, 1, 0 ]),\n * radius: new Float32Array([ 1 ]),\n * radius2: new Float32Array([ 2 ])\n * });\n */\nclass HyperballStickImpostorBuffer extends MappedBoxBuffer {\n parameterTypes = HyperballStickImpostorBufferParameterTypes\n get defaultParameters() { return HyperballStickImpostorBufferDefaultParameters }\n parameters: HyperballStickImpostorBufferParameters\n\n isImpostor = true\n vertexShader = 'HyperballStickImpostor.vert'\n fragmentShader = 'HyperballStickImpostor.frag'\n\n constructor (data: HyperballStickImpostorBufferData, params: Partial = {}) {\n super(data, params)\n\n this.addUniforms({\n 'modelViewProjectionMatrix': { value: new Matrix4() },\n 'modelViewProjectionMatrixInverse': { value: new Matrix4() },\n 'modelViewMatrixInverseTranspose': { value: new Matrix4() },\n 'shrink': { value: this.parameters.shrink }\n })\n\n this.addAttributes({\n 'position1': { type: 'v3', value: null },\n 'position2': { type: 'v3', value: null },\n 'color2': { type: 'c', value: null },\n 'radius': { type: 'f', value: null },\n 'radius2': { type: 'f', value: null }\n })\n\n this.setAttributes(data)\n this.makeMapping()\n }\n}\n\nexport default HyperballStickImpostorBuffer\n","/**\n * @file Hyperball Stick Buffer\n * @author Alexander Rose \n * @private\n */\n\n// @ts-ignore: unused import required for declaration only\nimport { Vector3, Matrix4 } from 'three'\nimport { ExtensionFragDepth } from '../globals'\nimport { calculateMinArray } from '../math/array-utils'\nimport CylinderGeometryBuffer, { CylinderGeometryBufferDefaultParameters, CylinderGeometryBufferParameters } from './cylindergeometry-buffer'\nimport HyperballStickImpostorBuffer, { HyperballStickImpostorBufferDefaultParameters, HyperballStickImpostorBufferParameters } from './hyperballstickimpostor-buffer'\nimport { BufferData } from './buffer'\n\nexport interface HyperballStickBufferData extends BufferData {\n position1: Float32Array\n position2: Float32Array\n color2: Float32Array\n radius: Float32Array\n radius2: Float32Array\n}\n\nexport const HyperballStickBufferDefaultParameters = Object.assign({\n disableImpostor: false\n}, CylinderGeometryBufferDefaultParameters, HyperballStickImpostorBufferDefaultParameters)\nexport type HyperballStickBufferParameters = HyperballStickImpostorBufferParameters & CylinderGeometryBufferParameters & { disableImpostor: boolean }\n\nclass HyperballStickBufferImpl {\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position1 - from positions\n * @param {Float32Array} data.position2 - to positions\n * @param {Float32Array} data.color - from colors\n * @param {Float32Array} data.color2 - to colors\n * @param {Float32Array} data.radius - from radii\n * @param {Float32Array} data.radius2 - to radii\n * @param {Float32Array} data.picking - picking ids\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: HyperballStickBufferData, params: Partial = {}) {\n if (!ExtensionFragDepth || (params && params.disableImpostor)) {\n data.radius = calculateMinArray(data.radius, data.radius2)\n return new CylinderGeometryBuffer(data, params)\n } else {\n return new HyperballStickImpostorBuffer(data, params)\n }\n }\n}\n\n/**\n * Hyperball stick buffer. Depending on the value {@link ExtensionFragDepth} and\n * `params.disableImpostor` the constructor returns either a\n * {@link CylinderGeometryBuffer} or a {@link HyperballStickImpostorBuffer}\n * @implements {Buffer}\n *\n * @example\n * var hyperballStickBuffer = new HyperballStickBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 2, 2, 2 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * color2: new Float32Array([ 0, 1, 0 ]),\n * radius: new Float32Array([ 1 ]),\n * radius2: new Float32Array([ 2 ])\n * });\n */\n//@ts-expect-error Incompatible constructor signatures\nconst HyperballStickBuffer: {\n new(data: HyperballStickBufferData, params: Partial): CylinderGeometryBuffer | HyperballStickImpostorBuffer;\n} = HyperballStickBufferImpl;\n\ntype HyperballStickBuffer = CylinderGeometryBuffer | HyperballStickImpostorBuffer;\n\nexport default HyperballStickBuffer\n","/**\n * @file Hyperball Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { calculateCenterArray } from '../math/array-utils'\nimport LicoriceRepresentation from './licorice-representation'\nimport SphereBuffer, { SphereBufferData, SphereBufferParameters } from '../buffer/sphere-buffer'\nimport HyperballStickBuffer, { HyperballStickBufferData } from '../buffer/hyperballstick-buffer'\nimport { BallAndStickRepresentationParameters } from './ballandstick-representation';\n// @ts-ignore: unused import Volume required for declaration only\nimport { Structure, Volume } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport { BondDataParams, BondDataFields, AtomDataFields } from '../structure/structure-data';\nimport StructureView from '../structure/structure-view';\nimport { StructureRepresentationData } from './structure-representation';\nimport SphereGeometryBuffer from '../buffer/spheregeometry-buffer';\n// @ts-ignore: unused import Surface required for declaration only\nimport Surface from '../surface/surface';\n\nexport interface HyperballRepresentationParameters extends BallAndStickRepresentationParameters {\n shrink: number\n}\n\n/**\n * Hyperball Representation\n */\nclass HyperballRepresentation extends LicoriceRepresentation {\n protected shrink: number\n protected __center: Float32Array\n \n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'hyperball'\n\n this.parameters = Object.assign({\n\n shrink: {\n type: 'number', precision: 3, max: 1.0, min: 0.001, buffer: true\n }\n\n }, this.parameters, {\n\n multipleBond: null,\n bondSpacing: null\n\n })\n }\n\n init (params: Partial) {\n var p = params || {}\n p.radiusScale = defaults(p.radiusScale, 0.2)\n p.radiusType = defaults(p.radiusType, 'vdw')\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n this.shrink = defaults(p.shrink, 0.12)\n\n super.init(p)\n }\n\n getBondParams (what?: BondDataFields, params?: BondDataParams) {\n if (!what || what.radius) {\n params = Object.assign({ radius2: true }, params)\n }\n\n return super.getBondParams(what, params)\n }\n\n createData (sview: StructureView) {\n var sphereBuffer = new SphereBuffer(\n (sview.getAtomData(this.getAtomParams()) as SphereBufferData),\n this.getBufferParams({\n sphereDetail: this.sphereDetail,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n }) as SphereBufferParameters\n ) as SphereGeometryBuffer\n\n this.__center = new Float32Array(sview.bondCount * 3)\n\n var stickBuffer = new HyperballStickBuffer(\n sview.getBondData(this.getBondParams()) as HyperballStickBufferData,\n this.getBufferParams({\n shrink: this.shrink,\n radialSegments: this.radialSegments,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n })\n )\n\n return {\n bufferList: [ sphereBuffer, stickBuffer ]\n }\n }\n\n updateData (what: AtomDataFields, data: StructureRepresentationData) {\n var atomData = data.sview!.getAtomData(this.getAtomParams())\n var bondData = data.sview!.getBondData(this.getBondParams())\n var sphereData = {}\n var stickData = {}\n\n if (!what || what.position) {\n Object.assign(sphereData, {position: atomData.position})\n var from = bondData.position1\n var to = bondData.position2\n Object.assign(stickData, {\n position: calculateCenterArray(from!, to!, this.__center),\n position1: from,\n position2: to\n })\n }\n\n if (!what || what.color) {\n Object.assign(sphereData, {color: atomData.color})\n Object.assign(stickData, {\n color: bondData.color,\n color2: bondData.color2\n })\n }\n\n if (!what || what.radius) {\n Object.assign(sphereData, {radius: atomData.radius})\n Object.assign(stickData, {\n radius: bondData.radius,\n radius2: bondData.radius2\n })\n }\n\n data.bufferList[ 0 ].setAttributes(sphereData)\n data.bufferList[ 1 ].setAttributes(stickData)\n }\n}\n\nRepresentationRegistry.add('hyperball', HyperballRepresentation)\n\nexport default HyperballRepresentation\n","/**\n * @file Label Factory\n * @author Alexander Rose \n * @private\n */\n\nimport { AA1 } from '../structure/structure-constants'\nimport AtomProxy from '../proxy/atom-proxy'\nimport { sprintf } from 'sprintf-js'\n\nexport const LabelFactoryTypes = {\n '': '',\n 'atomname': 'atom name',\n 'atomindex': 'atom index',\n 'occupancy': 'occupancy',\n 'bfactor': 'b-factor',\n 'serial': 'serial',\n 'element': 'element',\n 'atom': 'atom name + index',\n 'resname': 'residue name',\n 'resno': 'residue no',\n 'res': 'one letter code + no',\n 'residue': '[residue name] + no + inscode',\n 'text': 'text',\n 'format': 'format',\n 'qualified': 'qualified name'\n}\nexport type LabelType = keyof typeof LabelFactoryTypes\n\nclass LabelFactory {\n\n static types = LabelFactoryTypes\n errorLogged: boolean = false\n\n constructor(readonly type: LabelType, readonly text: { [k: number]: string } = {},\n readonly format: string = '') {}\n\n atomLabel (a: AtomProxy) {\n const type = this.type\n\n let l\n\n switch (type) {\n case 'atomname':\n l = a.atomname\n break\n\n case 'atomindex':\n l = `${a.index}`\n break\n\n case 'occupancy':\n l = a.occupancy.toFixed(2)\n break\n\n case 'bfactor':\n l = a.bfactor.toFixed(2)\n break\n\n case 'serial':\n l = `${a.serial}`\n break\n\n case 'element':\n l = a.element\n break\n\n case 'atom':\n l = `${a.atomname}|${a.index}`\n break\n\n case 'resname':\n l = a.resname\n break\n\n case 'resno':\n l = `${a.resno}`\n break\n\n case 'res':\n l = `${(AA1[ a.resname.toUpperCase() ] || a.resname)}${a.resno}`\n break\n\n case 'residue':\n const aa1 = AA1[ a.resname.toUpperCase() ]\n if (aa1 && !a.inscode) {\n l = `${aa1}${a.resno}`\n } else {\n l = `[${a.resname}]${a.resno}${a.inscode}`\n }\n break\n\n case 'text':\n l = this.text[ a.index ]\n break\n\n case 'format':\n try {\n l = sprintf(this.format, a)\n } catch (e) {\n if (!this.errorLogged) {\n this.errorLogged = true\n console.log(e.message)\n }\n }\n break\n\n // case \"qualified\":\n default:\n l = a.qualifiedName()\n break\n }\n\n return l === undefined ? '' : l\n }\n}\n\nexport default LabelFactory\n","/**\n * @file Label Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry, ColormakerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport LabelFactory, { LabelType } from '../utils/label-factory'\nimport RadiusFactory from '../utils/radius-factory'\nimport StructureRepresentation, { StructureRepresentationData } from './structure-representation'\nimport TextBuffer, { TextBufferData } from '../buffer/text-buffer'\nimport { RepresentationParameters } from './representation';\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport { GenericColor } from '../types'\n\nexport interface TextDataField {\n position?: boolean\n color?: boolean\n radius?: boolean\n text?: boolean\n}\n\n/**\n * Label representation parameter object. Extends {@link RepresentationParameters} and\n * {@link StructureRepresentationParameters}.\n *\n * @typedef {Object} LabelRepresentationParameters - label representation parameters\n *\n * @property {Integer} clipNear - position of camera near/front clipping plane\n * in percent of scene bounding box\n * @property {Float} opacity - translucency: 1 is fully opaque, 0 is fully transparent\n * @property {String} labelType - type of the label, one of:\n * \"atomname\", \"atomindex\", \"occupancy\", \"bfactor\",\n * \"serial\", \"element\", \"atom\", \"resname\", \"resno\",\n * \"res\", \"text\", \"qualified\". When set to \"text\", the\n * `labelText` list is used.\n * @property {String[]} labelText - list of label strings, must set `labelType` to \"text\"\n * to take effect\n * @property {String} labelFormat - sprintf-js format string, any attribute of\n * {@link AtomProxy} can be used\n * @property {String} labelGrouping - grouping of the label, one of:\n * \"atom\", \"residue\".\n * @property {String} fontFamily - font family, one of: \"sans-serif\", \"monospace\", \"serif\"\n * @property {String} fontStyle - font style, \"normal\" or \"italic\"\n * @property {String} fontWeight - font weight, \"normal\" or \"bold\"\n * @property {Float} xOffset - offset in x-direction\n * @property {Float} yOffset - offset in y-direction\n * @property {Float} zOffset - offset in z-direction (i.e. in camera direction)\n * @property {String} attachment - attachment of the label, one of:\n * \"bottom-left\", \"bottom-center\", \"bottom-right\",\n * \"middle-left\", \"middle-center\", \"middle-right\",\n * \"top-left\", \"top-center\", \"top-right\"\n * @property {Boolean} showBorder - show border/outline\n * @property {Color} borderColor - color of the border/outline\n * @property {Float} borderWidth - width of the border/outline\n * @property {Boolean} showBackground - show background rectangle\n * @property {Color} backgroundColor - color of the background\n * @property {Float} backgroundMargin - width of the background\n * @property {Float} backgroundOpacity - opacity of the background\n * @property {Boolean} fixedSize - show text with a fixed pixel size\n */\nexport interface LabelRepresentationParameters extends RepresentationParameters {\n labelType: LabelType\n labelText: string[]\n labelFormat: string\n labelGrouping: 'atom'|'residue'\n fontFamily: 'sans-serif'|'monospace'|'serif'\n fontStyle: 'normal'|'italic'\n fontWeight: 'normal'|'bold'\n xOffset: number\n yOffset: number\n zOffset: number\n attachment: 'bottom-left'|'bottom-center'|'bottom-right'|'middle-left'|'middle-center'|'middle-right'|'top-left'|'top-center'|'top-right'\n showBorder: boolean\n borderColor: GenericColor\n borderWidth: number\n showBackground: boolean\n backgroundColor: GenericColor\n backgroundMargin: number\n backgroundOpacity: number\n fixedSize: boolean\n}\n/**\n * Label representation\n */\nclass LabelRepresentation extends StructureRepresentation {\n\n protected labelType: LabelType\n protected labelText: string[]\n protected labelFormat: string\n protected labelGrouping: 'atom'|'residue'\n protected fontFamily: 'sans-serif'|'monospace'|'serif'\n protected fontStyle: 'normal'|'italic'\n protected fontWeight: 'normal'|'bold'\n protected xOffset: number\n protected yOffset: number\n protected zOffset: number\n protected attachment: 'bottom-left'|'bottom-center'|'bottom-right'|'middle-left'|'middle-center'|'middle-right'|'top-left'|'top-center'|'top-right'\n protected showBorder: boolean\n protected borderColor: GenericColor\n protected borderWidth: number\n protected showBackground: boolean\n protected backgroundColor: GenericColor\n protected backgroundMargin: number\n protected backgroundOpacity: number\n protected fixedSize: boolean\n\n /**\n * Create Label representation object\n * @param {Structure} structure - the structure to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {LabelRepresentationParameters} params - label representation parameters\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'label'\n\n this.parameters = Object.assign({\n\n labelType: {\n type: 'select', options: LabelFactory.types, rebuild: true\n },\n labelText: {\n type: 'hidden', rebuild: true\n },\n labelFormat: {\n type: 'text', rebuild: true\n },\n labelGrouping: {\n type: 'select',\n options: {\n 'atom': 'atom',\n 'residue': 'residue'\n },\n rebuild: true\n },\n fontFamily: {\n type: 'select',\n options: {\n 'sans-serif': 'sans-serif',\n 'monospace': 'monospace',\n 'serif': 'serif'\n },\n buffer: true\n },\n fontStyle: {\n type: 'select',\n options: {\n 'normal': 'normal',\n 'italic': 'italic'\n },\n buffer: true\n },\n fontWeight: {\n type: 'select',\n options: {\n 'normal': 'normal',\n 'bold': 'bold'\n },\n buffer: true\n },\n xOffset: {\n type: 'number', precision: 1, max: 20, min: -20, buffer: true\n },\n yOffset: {\n type: 'number', precision: 1, max: 20, min: -20, buffer: true\n },\n zOffset: {\n type: 'number', precision: 1, max: 20, min: -20, buffer: true\n },\n attachment: {\n type: 'select',\n options: {\n 'bottom-left': 'bottom-left',\n 'bottom-center': 'bottom-center',\n 'bottom-right': 'bottom-right',\n 'middle-left': 'middle-left',\n 'middle-center': 'middle-center',\n 'middle-right': 'middle-right',\n 'top-left': 'top-left',\n 'top-center': 'top-center',\n 'top-right': 'top-right'\n },\n rebuild: true\n },\n showBorder: {\n type: 'boolean', buffer: true\n },\n borderColor: {\n type: 'color', buffer: true\n },\n borderWidth: {\n type: 'number', precision: 2, max: 0.3, min: 0, buffer: true\n },\n showBackground: {\n type: 'boolean', rebuild: true\n },\n backgroundColor: {\n type: 'color', buffer: true\n },\n backgroundMargin: {\n type: 'number', precision: 2, max: 2, min: 0, rebuild: true\n },\n backgroundOpacity: {\n type: 'range', step: 0.01, max: 1, min: 0, buffer: true\n },\n fixedSize: {\n type: 'boolean', buffer: true\n }\n\n }, this.parameters, {\n\n side: null,\n flatShaded: null,\n wireframe: null,\n linewidth: null,\n\n roughness: null,\n metalness: null,\n diffuse: null\n\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n\n this.labelType = defaults(p.labelType, 'res')\n this.labelText = defaults(p.labelText, {})\n this.labelFormat = defaults(p.labelFormat, '')\n this.labelGrouping = defaults(p.labelGrouping, 'atom')\n this.fontFamily = defaults(p.fontFamily, 'sans-serif')\n this.fontStyle = defaults(p.fontStyle, 'normal')\n this.fontWeight = defaults(p.fontWeight, 'bold')\n this.xOffset = defaults(p.xOffset, 0.0)\n this.yOffset = defaults(p.yOffset, 0.0)\n this.zOffset = defaults(p.zOffset, 0.5)\n this.attachment = defaults(p.attachment, 'bottom-left')\n this.showBorder = defaults(p.showBorder, false)\n this.borderColor = defaults(p.borderColor, 'lightgrey')\n this.borderWidth = defaults(p.borderWidth, 0.15)\n this.showBackground = defaults(p.showBackground, false)\n this.backgroundColor = defaults(p.backgroundColor, 'lightgrey')\n this.backgroundMargin = defaults(p.backgroundMargin, 0.5)\n this.backgroundOpacity = defaults(p.backgroundOpacity, 1.0)\n this.fixedSize = defaults(p.fixedSize, false)\n\n super.init(p)\n }\n\n getTextData (sview: StructureView, what?: TextDataField) {\n const p = this.getAtomParams(what)\n const labelFactory = new LabelFactory(this.labelType, this.labelText, this.labelFormat)\n let position: Float32Array, size: Float32Array, color: Float32Array, text: string[],\n positionN: number[], sizeN: number[], colorN: number[]\n if (this.labelGrouping === 'atom') {\n const atomData = sview.getAtomData(p)\n position = atomData.position as Float32Array\n size = atomData.radius as Float32Array\n color = atomData.color as Float32Array\n if (!what || what.text) {\n text = []\n sview.eachAtom(ap => text.push(labelFactory.atomLabel(ap)))\n }\n } else if (this.labelGrouping === 'residue') {\n if (!what || what.position) positionN = []\n if (!what || what.color) colorN = []\n if (!what || what.radius) sizeN = []\n if (!what || what.text) text = []\n if (p.colorParams) p.colorParams.structure = sview.getStructure()\n const colormaker = ColormakerRegistry.getScheme(p.colorParams)\n const radiusFactory = new RadiusFactory(p.radiusParams)\n const ap1 = sview.getAtomProxy()\n\n let i = 0\n sview.eachResidue(rp => {\n const i3 = i * 3\n if (rp.isProtein() || rp.isNucleic()) {\n ap1.index = rp.traceAtomIndex\n if (!what || what.position) {\n ap1.positionToArray(positionN, i3)\n }\n } else {\n ap1.index = rp.atomOffset\n if (!what || what.position) {\n rp.positionToArray(positionN, i3)\n }\n }\n if (!what || what.color) {\n colormaker.atomColorToArray(ap1, colorN, i3)\n }\n if (!what || what.radius) {\n sizeN[ i ] = radiusFactory.atomRadius(ap1)\n }\n if (!what || what.text) {\n text.push(labelFactory.atomLabel(ap1))\n }\n ++i\n })\n\n if (!what || what.position) position = new Float32Array(positionN!)\n if (!what || what.color) color = new Float32Array(colorN!)\n if (!what || what.radius) size = new Float32Array(sizeN!)\n }\n\n return { position: position!, size: size!, color: color!, text: text! }\n }\n\n createData (sview: StructureView) {\n const what: TextDataField = { position: true, color: true, radius: true, text: true }\n\n const textBuffer = new TextBuffer(\n this.getTextData(sview, what) as TextBufferData,\n this.getBufferParams({\n fontFamily: this.fontFamily,\n fontStyle: this.fontStyle,\n fontWeight: this.fontWeight,\n xOffset: this.xOffset,\n yOffset: this.yOffset,\n zOffset: this.zOffset,\n attachment: this.attachment,\n showBorder: this.showBorder,\n borderColor: this.borderColor,\n borderWidth: this.borderWidth,\n showBackground: this.showBackground,\n backgroundColor: this.backgroundColor,\n backgroundMargin: this.backgroundMargin,\n backgroundOpacity: this.backgroundOpacity,\n fixedSize: this.fixedSize\n })\n )\n\n return { bufferList: [ textBuffer ] }\n }\n\n updateData (what: TextDataField, data: StructureRepresentationData) {\n data.bufferList[ 0 ].setAttributes(this.getTextData(data.sview as StructureView, what))\n }\n\n getAtomRadius () {\n return 0\n }\n}\n\nRepresentationRegistry.add('label', LabelRepresentation)\n\nexport default LabelRepresentation\n","/**\n * @file Line Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport { RepresentationRegistry } from '../globals'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport WideLineBuffer from '../buffer/wideline-buffer'\nimport { AtomPicker } from '../utils/picker'\n// @ts-ignore: unused import Volume required for declaration only\nimport { Structure, Volume } from '../ngl';\nimport StructureView from '../structure/structure-view';\nimport Viewer from '../viewer/viewer';\nimport AtomProxy from '../proxy/atom-proxy';\n// @ts-ignore: unused import Surface required for declaration only\nimport Surface from '../surface/surface';\n// @ts-ignore: unused import BondDataFields, BondDataParams required for declaration only\nimport { BondDataFields, BondDataParams } from '../structure/structure-data';\n\n/**\n * Determine which atoms in a Structure[View] form no bonds to any other atoms\n * in that Structure.\n *\n * This differs from setting the selection to \"nonbonded\" as it finds atoms\n * that have no bonds within the current selection.\n * @param {Structure} structure - The Structure or StructureView object\n * @return {AtomSet} AtomSet of lone atoms\n */\nfunction getLoneAtomSet (structure: Structure | StructureView) {\n const atomSet = structure.getAtomSet()\n const bondSet = structure.getBondSet()\n const bp = structure.getBondProxy()\n bondSet.forEach(function (idx) {\n bp.index = idx\n atomSet.clear(bp.atomIndex1)\n atomSet.clear(bp.atomIndex2)\n })\n return atomSet\n}\n\nexport interface LineRepresentationParameters extends StructureRepresentationParameters {\n multipleBond: 'off' | 'symmetric' | 'offset'\n bondSpacing: number\n linewidth: number\n lines: boolean\n crosses: 'off' | 'all' | 'lone'\n crossSize: number\n}\n\nexport interface CrossData {\n position1?: Float32Array\n position2?: Float32Array\n color?: Float32Array\n color2?: Float32Array\n picking?: AtomPicker\n}\n\n/**\n * Line representation\n */\nclass LineRepresentation extends StructureRepresentation {\n protected multipleBond: 'off' | 'symmetric' | 'offset'\n protected bondSpacing: number\n protected linewidth: number\n protected lines: boolean\n protected crosses: 'off' | 'all' | 'lone'\n protected crossSize: number\n /**\n * Create Line representation object\n * @param {Structure} structure - the structure to be represented\n * @param {Viewer} viewer - a viewer object\n * @param {RepresentationParameters} params - representation parameters, plus the properties listed below\n * @property {String} multipleBond - one off \"off\", \"symmetric\", \"offset\"\n * @param {Float} params.bondSpacing - spacing for multiple bond rendering\n * @param {Integer} params.linewidth - width of lines\n * @param {Boolean} params.lines - render bonds as lines\n * @param {String} params.crosses - render atoms as crosses: \"off\", \"all\" or \"lone\" (default)\n * @param {Float} params.crossSize - size of cross\n * @param {null} params.flatShaded - not available\n * @param {null} params.side - not available\n * @param {null} params.wireframe - not available\n * @param {null} params.roughness - not available\n * @param {null} params.metalness - not available\n * @param {null} params.diffuse - not available\n */\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'line'\n\n this.parameters = Object.assign({\n\n multipleBond: {\n type: 'select',\n rebuild: true,\n options: {\n 'off': 'off',\n 'symmetric': 'symmetric',\n 'offset': 'offset'\n }\n },\n bondSpacing: {\n type: 'number', precision: 2, max: 2.0, min: 0.5\n },\n linewidth: {\n type: 'integer', max: 50, min: 1, buffer: true\n },\n lines: {\n type: 'boolean', rebuild: true\n },\n crosses: {\n type: 'select',\n rebuild: true,\n options: {\n 'off': 'off',\n 'lone': 'lone',\n 'all': 'all'\n }\n },\n crossSize: {\n type: 'number', precision: 2, max: 2.0, min: 0.1\n }\n\n }, this.parameters, {\n\n flatShaded: null,\n side: null,\n wireframe: null,\n\n roughness: null,\n metalness: null\n\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n\n this.multipleBond = defaults(p.multipleBond, 'off')\n this.bondSpacing = defaults(p.bondSpacing, 1.0)\n this.linewidth = defaults(p.linewidth, 2)\n this.lines = defaults(p.lines, true)\n this.crosses = defaults(p.crosses, 'lone')\n this.crossSize = defaults(p.crossSize, 0.4)\n\n super.init(p)\n }\n\n getAtomRadius (atom:AtomProxy) {\n return 0.1\n }\n\n getBondParams (what: any, params?: Partial) {\n params = Object.assign({\n multipleBond: this.multipleBond,\n bondSpacing: this.bondSpacing,\n radiusParams: { 'type': 'size', 'size': 0.1, 'scale': 1 }\n }, params)\n\n return super.getBondParams(what, params)\n }\n\n _crossData (what: any, sview: StructureView) {\n if (what) {\n if (!what.position && !what.color) return\n }\n\n const p = {}\n if (this.crosses === 'lone') {\n Object.assign(p, {atomSet : getLoneAtomSet(sview)})\n }\n\n const atomData = sview.getAtomData(this.getAtomParams(what, p))\n const crossData: CrossData = {}\n const position = atomData.position\n const color = atomData.color\n const picking = atomData.picking\n\n const size = (position! || color).length\n const attrSize = size * 3\n\n let cPosition1 = new Float32Array(0)\n let cPosition2 = new Float32Array(0)\n let cColor = new Float32Array(0)\n let cColor2 = new Float32Array(0)\n let cOffset: number = 0\n\n let pickingArray = new Float32Array(0)\n\n if (!what || what.position) {\n cPosition1 = crossData.position1 = new Float32Array(attrSize)\n cPosition2 = crossData.position2 = new Float32Array(attrSize)\n cOffset = this.crossSize / 2\n }\n if (!what || what.color) {\n cColor = crossData.color = new Float32Array(attrSize)\n cColor2 = crossData.color2 = new Float32Array(attrSize)\n }\n if (!what || what.picking) {\n pickingArray = new Float32Array(atomData.picking!.array!.length * 3) // Needs padding??\n }\n\n for (let v = 0; v < size; v++) {\n const j = v * 3\n const i = j * 3\n\n if (!what || what.position) {\n const x = position![ j ]\n const y = position![ j + 1 ]\n const z = position![ j + 2 ]\n\n cPosition1[ i ] = x - cOffset!\n cPosition1[ i + 1 ] = y\n cPosition1[ i + 2 ] = z\n cPosition2[ i ] = x + cOffset\n cPosition2[ i + 1 ] = y\n cPosition2[ i + 2 ] = z\n\n cPosition1[ i + 3 ] = x\n cPosition1[ i + 4 ] = y - cOffset\n cPosition1[ i + 5 ] = z\n cPosition2[ i + 3 ] = x\n cPosition2[ i + 4 ] = y + cOffset\n cPosition2[ i + 5 ] = z\n\n cPosition1[ i + 6 ] = x\n cPosition1[ i + 7 ] = y\n cPosition1[ i + 8 ] = z - cOffset\n cPosition2[ i + 6 ] = x\n cPosition2[ i + 7 ] = y\n cPosition2[ i + 8 ] = z + cOffset\n }\n\n if (!what || what.color) {\n const cimax = i + 9\n for (let ci = i; ci < cimax; ci += 3) {\n cColor[ ci ] = cColor2[ ci ] = color![ j ]\n cColor[ ci + 1 ] = cColor2[ ci + 1 ] = color![ j + 1 ]\n cColor[ ci + 2 ] = cColor2[ ci + 2 ] = color![ j + 2 ]\n }\n }\n\n if (!what || what.picking) {\n pickingArray[ j ] =\n pickingArray[ j + 1 ] =\n pickingArray[ j + 2 ] = picking!.array![ v ]\n }\n }\n\n if (!what || what.picking) {\n crossData.picking = new AtomPicker(\n pickingArray, picking!.structure\n )\n }\n\n return crossData\n }\n\n createData (sview: StructureView) {\n const what = { position: true, color: true, picking: true }\n\n const bufferList = []\n\n if (this.lines) {\n const bondData = sview.getBondData(this.getBondParams(what))\n\n const lineBuffer = new WideLineBuffer(\n bondData, this.getBufferParams({ linewidth: this.linewidth })\n )\n\n bufferList.push(lineBuffer)\n }\n\n if (this.crosses !== 'off') {\n const crossBuffer = new WideLineBuffer(\n (this._crossData(what, sview) as CrossData),\n this.getBufferParams({linewidth: this.linewidth})\n )\n bufferList.push(crossBuffer)\n }\n\n return {\n bufferList: bufferList\n }\n }\n\n updateData (what: any, data: StructureRepresentationData) {\n let bufferIdx = 0\n\n if (this.lines) {\n const bondData = data.sview!.getBondData(this.getBondParams(what))\n const lineAttributes = {}\n\n if (!what || what.position) {\n Object.assign(lineAttributes, {\n position1: bondData.position1,\n position2: bondData.position2\n })\n }\n\n if (!what || what.color) {\n Object.assign(lineAttributes, {\n color: bondData.color,\n color2: bondData.color2\n })\n }\n\n data.bufferList[ bufferIdx++ ].setAttributes(lineAttributes)\n }\n\n if (this.crosses !== 'off') {\n const crossData = this._crossData(what, (data.sview as StructureView))\n const crossAttributes = {}\n\n if (!what || what.position) {\n Object.assign(crossAttributes, {\n position1: crossData!.position1,\n position2: crossData!.position2\n })\n }\n if (!what || what.color) {\n Object.assign(crossAttributes, {\n color: crossData!.color,\n color2: crossData!.color2\n })\n }\n\n data.bufferList[ bufferIdx++ ].setAttributes(crossAttributes)\n }\n }\n\n setParameters (params: Partial) {\n var rebuild = false\n var what = {}\n\n if (params && (params.bondSpacing || params.crossSize)) {\n Object.assign(what, { position: true })\n }\n\n super.setParameters(params, what, rebuild)\n\n return this\n }\n}\n\nRepresentationRegistry.add('line', LineRepresentation)\n\nexport default LineRepresentation\n","import { NumberArray, TypedArray } from \"../types\";\n\n/**\n * @file Grid\n * @author Alexander Rose \n * @private\n */\nexport interface iGrid {\n data: TypedArray\n index: (x: number, y: number, z: number) => number\n set: (x: number, y: number, z: number, ...arg: number[]) => void\n toArray: (x: number, y: number, z: number, array?: NumberArray, offset?: number) => void\n fromArray: (x: number, y: number, z: number, array: NumberArray, offset?: number) => void\n copy: (grid: iGrid) => void\n // clone: () => iGrid\n}\n\nfunction makeGrid (length: number, width: number, height: number, DataCtor: any, elemSize: number) : iGrid {\n DataCtor = DataCtor || Int32Array\n elemSize = elemSize || 1\n\n const data = new DataCtor(length * width * height * elemSize)\n\n function index (x: number, y: number, z: number) {\n return ((((x * width) + y) * height) + z) * elemSize\n }\n\n function set (x: number, y: number, z: number, ...args: number[]) {\n const i = index(x, y, z)\n\n for (let j = 0; j < elemSize; ++j) {\n data[ i + j ] = args[ j ]\n }\n }\n\n function toArray (x: number, y: number, z: number, array: NumberArray = [], offset: number = 0) {\n const i = index(x, y, z)\n\n for (let j = 0; j < elemSize; ++j) {\n array[ offset + j ] = data[ i + j ]\n }\n }\n\n function fromArray(x: number, y: number, z: number, array: NumberArray, offset: number = 0) {\n const i = index(x, y, z)\n\n for (let j = 0; j < elemSize; ++j) {\n data[ i + j ] = array[ offset + j ]\n }\n }\n\n function copy(grid: iGrid) {\n data.set(grid.data)\n }\n\n // function clone() {\n // return makeGrid(\n // length, width, height, DataCtor, elemSize\n // ).copy(this)\n // }\n return { data, index, set, toArray, fromArray, copy }\n}\n\nexport { makeGrid }","/**\n * @file EDT Surface\n * @author Alexander Rose \n * @private\n */\n\nimport { VolumeSurface } from './volume'\nimport { iGrid, makeGrid } from '../geometry/grid'\nimport { computeBoundingBox } from '../math/vector-utils'\nimport { getRadiusDict, getSurfaceGrid } from './surface-utils'\nimport { TypedArray } from '../types';\n\ninterface EDTSurface {\n getVolume: (type: string, probeRadius: number, scaleFactor: number, cutoff: number, setAtomID: boolean) => {\n data: TypedArray\n nx: number\n ny: number\n nz: number\n atomindex: TypedArray\n }\n getSurface: (type: string, probeRadius: number, scaleFactor: number, cutoff: number, setAtomID: boolean, smooth: number, contour: boolean) => any\n}\n\nfunction EDTSurface (this: EDTSurface, coordList: Float32Array, radiusList: Float32Array, indexList: Uint16Array|Uint32Array) {\n // based on D. Xu, Y. Zhang (2009) Generating Triangulated Macromolecular\n // Surfaces by Euclidean Distance Transform. PLoS ONE 4(12): e8140.\n //\n // Permission to use, copy, modify, and distribute this program for\n // any purpose, with or without fee, is hereby granted, provided that\n // the notices on the head, the reference information, and this\n // copyright notice appear in all copies or substantial portions of\n // the Software. It is provided \"as is\" without express or implied\n // warranty.\n //\n // ported to JavaScript by biochem_fan (http://webglmol.sourceforge.jp/)\n // refactored by dkoes (https://github.com/dkoes)\n //\n // adapted to NGL by Alexander Rose\n\n var radiusDict = getRadiusDict(radiusList as any)\n var bbox = computeBoundingBox(coordList)\n if (coordList.length === 0) {\n bbox[ 0 ].set([ 0, 0, 0 ])\n bbox[ 1 ].set([ 0, 0, 0 ])\n }\n var min = bbox[ 0 ]\n var max = bbox[ 1 ]\n\n var probeRadius: number, scaleFactor: number, cutoff: number\n var pLength: number, pWidth: number, pHeight: number\n var matrix: Float32Array, ptran: Float32Array\n var depty: {[k: string]: TypedArray}, widxz: {[k: string]: number}\n var cutRadius: number\n var setAtomID: boolean\n var vpBits: TypedArray, vpDistance: TypedArray, vpAtomID: TypedArray\n\n function init (btype: boolean, _probeRadius: number, _scaleFactor: number, _cutoff: number, _setAtomID: boolean) {\n probeRadius = _probeRadius || 1.4\n scaleFactor = _scaleFactor || 2.0\n setAtomID = _setAtomID || true\n\n var maxRadius = 0\n for (var radius in radiusDict) {\n maxRadius = Math.max(maxRadius, radius as any)\n }\n\n var grid = getSurfaceGrid(\n min, max, maxRadius, scaleFactor, btype ? probeRadius : 0\n )\n\n pLength = grid.dim[0]\n pWidth = grid.dim[1]\n pHeight = grid.dim[2]\n\n matrix = grid.matrix\n ptran = grid.tran\n scaleFactor = grid.scaleFactor\n\n // boundingatom caches\n depty = {}\n widxz = {}\n boundingatom(btype)\n\n cutRadius = probeRadius * scaleFactor\n\n if (_cutoff) {\n cutoff = _cutoff\n } else {\n // cutoff = Math.max( 0.1, -1.2 + scaleFactor * probeRadius );\n cutoff = probeRadius / scaleFactor\n }\n\n vpBits = new Uint8Array(pLength * pWidth * pHeight)\n if (btype) {\n vpDistance = new Float64Array(pLength * pWidth * pHeight)\n }\n if (setAtomID) {\n vpAtomID = new Int32Array(pLength * pWidth * pHeight)\n }\n }\n\n // constants for vpBits bitmasks\n var INOUT = 1\n var ISDONE = 2\n var ISBOUND = 4\n\n var nb = [\n new Int32Array([ 1, 0, 0 ]), new Int32Array([ -1, 0, 0 ]),\n new Int32Array([ 0, 1, 0 ]), new Int32Array([ 0, -1, 0 ]),\n new Int32Array([ 0, 0, 1 ]), new Int32Array([ 0, 0, -1 ]),\n new Int32Array([ 1, 1, 0 ]), new Int32Array([ 1, -1, 0 ]),\n new Int32Array([ -1, 1, 0 ]), new Int32Array([ -1, -1, 0 ]),\n new Int32Array([ 1, 0, 1 ]), new Int32Array([ 1, 0, -1 ]),\n new Int32Array([ -1, 0, 1 ]), new Int32Array([ -1, 0, -1 ]),\n new Int32Array([ 0, 1, 1 ]), new Int32Array([ 0, 1, -1 ]),\n new Int32Array([ 0, -1, 1 ]), new Int32Array([ 0, -1, -1 ]),\n new Int32Array([ 1, 1, 1 ]), new Int32Array([ 1, 1, -1 ]),\n new Int32Array([ 1, -1, 1 ]), new Int32Array([ -1, 1, 1 ]),\n new Int32Array([ 1, -1, -1 ]), new Int32Array([ -1, -1, 1 ]),\n new Int32Array([ -1, 1, -1 ]), new Int32Array([ -1, -1, -1 ])\n ]\n\n //\n\n this.getVolume = function (type: string, probeRadius: number, scaleFactor: number, cutoff: number, setAtomID: boolean) {\n console.time('EDTSurface.getVolume')\n\n var btype = type !== 'vws'\n\n init(btype, probeRadius, scaleFactor, cutoff, setAtomID)\n\n fillvoxels(btype)\n buildboundary()\n\n if (type === 'ms' || type === 'ses') {\n fastdistancemap()\n }\n\n if (type === 'ses') {\n boundingatom(false)\n fillvoxelswaals()\n }\n\n marchingcubeinit(type)\n\n // set atomindex in the volume data\n for (var i = 0, il = vpAtomID.length; i < il; ++i) {\n vpAtomID[ i ] = indexList[ vpAtomID[ i ] ]\n }\n\n console.timeEnd('EDTSurface.getVolume')\n\n return {\n data: vpBits,\n nx: pHeight,\n ny: pWidth,\n nz: pLength,\n atomindex: vpAtomID\n }\n }\n\n this.getSurface = function (type: string, probeRadius: number, scaleFactor: number, cutoff: number, setAtomID: boolean, smooth: number, contour: boolean) {\n var vd = this.getVolume(\n type, probeRadius, scaleFactor, cutoff, setAtomID\n )\n\n var volsurf = new (VolumeSurface as any)(\n vd.data, vd.nx, vd.ny, vd.nz, vd.atomindex\n ) as VolumeSurface\n\n return (volsurf!.getSurface as any)(1, smooth, undefined, matrix, contour)\n }\n\n function boundingatom (btype: boolean) {\n var r\n var j\n var k\n var txz\n var tdept\n var sradius\n var tradius\n var widxzR\n var deptyName\n var indx\n\n for (var name in radiusDict) {\n r = parseFloat(name)\n\n if (depty[ name ]) continue\n\n if (!btype) {\n tradius = r * scaleFactor + 0.5\n } else {\n tradius = (r + probeRadius) * scaleFactor + 0.5\n }\n\n sradius = tradius * tradius\n widxzR = Math.floor(tradius) + 1\n deptyName = new Int32Array(widxzR * widxzR)\n indx = 0\n\n for (j = 0; j < widxzR; ++j) {\n for (k = 0; k < widxzR; ++k) {\n txz = j * j + k * k\n\n if (txz > sradius) {\n deptyName[ indx ] = -1\n } else {\n tdept = Math.sqrt(sradius - txz)\n deptyName[ indx ] = Math.floor(tdept)\n }\n\n ++indx\n }\n }\n\n widxz[ name ] = widxzR\n depty[ name ] = deptyName\n }\n }\n\n function fillatom (idx: number) {\n var ci = idx * 3\n var ri = idx\n\n var cx, cy, cz, ox, oy, oz, mi, mj, mk, i, j, k, si, sj, sk\n var ii, jj, kk\n\n cx = Math.floor(0.5 + scaleFactor * (coordList[ ci ] + ptran[0]))\n cy = Math.floor(0.5 + scaleFactor * (coordList[ ci + 1 ] + ptran[1]))\n cz = Math.floor(0.5 + scaleFactor * (coordList[ ci + 2 ] + ptran[2]))\n\n var at = radiusList[ ri ]\n var deptyAt = depty[ at ]\n var nind = 0\n var pWH = pWidth * pHeight\n var n = widxz[ at ]\n\n var deptyAtNind\n\n for (i = 0; i < n; ++i) {\n for (j = 0; j < n; ++j) {\n deptyAtNind = deptyAt[ nind ]\n\n if (deptyAtNind !== -1) {\n for (ii = -1; ii < 2; ++ii) {\n for (jj = -1; jj < 2; ++jj) {\n for (kk = -1; kk < 2; ++kk) {\n if (ii !== 0 && jj !== 0 && kk !== 0) {\n mi = ii * i\n mk = kk * j\n\n for (k = 0; k <= deptyAtNind; ++k) {\n mj = k * jj\n si = cx + mi\n sj = cy + mj\n sk = cz + mk\n\n if (si < 0 || sj < 0 || sk < 0 ||\n si >= pLength || sj >= pWidth || sk >= pHeight\n ) {\n continue\n }\n\n var index = si * pWH + sj * pHeight + sk\n\n if (!setAtomID) {\n vpBits[ index ] |= INOUT\n } else {\n if (!(vpBits[ index ] & INOUT)) {\n vpBits[ index ] |= INOUT\n vpAtomID[ index ] = idx\n } else if (vpBits[ index ] & INOUT) {\n var ci2 = vpAtomID[ index ]\n\n if (ci2 !== ci) {\n ox = cx + mi - Math.floor(0.5 + scaleFactor * (coordList[ci2] + ptran[0]))\n oy = cy + mj - Math.floor(0.5 + scaleFactor * (coordList[ci2 + 1] + ptran[1]))\n oz = cz + mk - Math.floor(0.5 + scaleFactor * (coordList[ci2 + 2] + ptran[2]))\n\n if (mi * mi + mj * mj + mk * mk < ox * ox + oy * oy + oz * oz) {\n vpAtomID[ index ] = idx\n }\n }\n }\n }\n } // k\n } // if\n } // kk\n } // jj\n } // ii\n } // if\n\n nind++\n } // j\n } // i\n }\n\n function fillvoxels (btype: boolean) {\n console.time('EDTSurface fillvoxels')\n\n var i, il\n\n for (i = 0, il = vpBits.length; i < il; ++i) {\n vpBits[ i ] = 0\n if (btype) vpDistance[ i ] = -1.0\n if (setAtomID) vpAtomID[ i ] = -1\n }\n\n for (i = 0, il = coordList.length / 3; i < il; ++i) {\n fillatom(i)\n }\n\n for (i = 0, il = vpBits.length; i < il; ++i) {\n if (vpBits[ i ] & INOUT) {\n vpBits[ i ] |= ISDONE\n }\n }\n\n console.timeEnd('EDTSurface fillvoxels')\n }\n\n function fillAtomWaals (idx: number) {\n var ci = idx * 3\n var ri = idx\n\n var cx\n var cy\n var cz\n var ox\n var oy\n var oz\n var nind = 0\n\n var mi\n var mj\n var mk\n var si\n var sj\n var sk\n var i\n var j\n var k\n var ii\n var jj\n var kk\n var n\n\n cx = Math.floor(0.5 + scaleFactor * (coordList[ ci ] + ptran[0]))\n cy = Math.floor(0.5 + scaleFactor * (coordList[ ci + 1 ] + ptran[1]))\n cz = Math.floor(0.5 + scaleFactor * (coordList[ ci + 2 ] + ptran[2]))\n\n var at = radiusList[ ri ]\n var pWH = pWidth * pHeight\n\n for (i = 0, n = widxz[at]; i < n; ++i) {\n for (j = 0; j < n; ++j) {\n if (depty[ at ][ nind ] !== -1) {\n for (ii = -1; ii < 2; ++ii) {\n for (jj = -1; jj < 2; ++jj) {\n for (kk = -1; kk < 2; ++kk) {\n if (ii !== 0 && jj !== 0 && kk !== 0) {\n mi = ii * i\n mk = kk * j\n\n for (k = 0; k <= depty[ at ][ nind ]; ++k) {\n mj = k * jj\n si = cx + mi\n sj = cy + mj\n sk = cz + mk\n\n if (si < 0 || sj < 0 || sk < 0 ||\n si >= pLength || sj >= pWidth || sk >= pHeight\n ) {\n continue\n }\n\n var index = si * pWH + sj * pHeight + sk\n\n if (!(vpBits[ index ] & ISDONE)) {\n vpBits[ index ] |= ISDONE\n if (setAtomID) vpAtomID[ index ] = idx\n } else if (setAtomID) {\n var ci2 = vpAtomID[ index ]\n\n ox = Math.floor(0.5 + scaleFactor * (coordList[ ci2 ] + ptran[0]))\n oy = Math.floor(0.5 + scaleFactor * (coordList[ ci2 + 1 ] + ptran[1]))\n oz = Math.floor(0.5 + scaleFactor * (coordList[ ci2 + 2 ] + ptran[2]))\n\n if (mi * mi + mj * mj + mk * mk < ox * ox + oy * oy + oz * oz) {\n vpAtomID[ index ] = idx\n }\n }\n } // k\n } // if\n } // kk\n } // jj\n } // ii\n } // if\n\n nind++\n } // j\n } // i\n }\n\n function fillvoxelswaals () {\n var i, il\n\n for (i = 0, il = vpBits.length; i < il; ++i) {\n vpBits[ i ] &= ~ISDONE // not isdone\n }\n\n for (i = 0, il = coordList.length / 3; i < il; ++i) {\n fillAtomWaals(i)\n }\n }\n\n function buildboundary () {\n var i, j, k\n var pWH = pWidth * pHeight\n\n for (i = 0; i < pLength; ++i) {\n for (j = 0; j < pHeight; ++j) {\n for (k = 0; k < pWidth; ++k) {\n var index = i * pWH + k * pHeight + j\n\n if (vpBits[ index ] & INOUT) {\n // var flagbound = false;\n var ii = 0\n\n // while( !flagbound && ii < 26 ){\n while (ii < 26) {\n var ti = i + nb[ ii ][ 0 ]\n var tj = j + nb[ ii ][ 2 ]\n var tk = k + nb[ ii ][ 1 ]\n\n if (ti > -1 && ti < pLength &&\n tk > -1 && tk < pWidth &&\n tj > -1 && tj < pHeight &&\n !(vpBits[ ti * pWH + tk * pHeight + tj ] & INOUT)\n ) {\n vpBits[ index ] |= ISBOUND\n // flagbound = true;\n break\n } else {\n ii++\n }\n }\n }\n } // k\n } // j\n } // i\n }\n\n function fastdistancemap () {\n console.time('EDTSurface fastdistancemap')\n\n var i, j, k, n\n\n var boundPoint = makeGrid(\n pLength, pWidth, pHeight, Uint16Array, 3\n )\n var pWH = pWidth * pHeight\n var cutRSq = cutRadius * cutRadius\n\n var totalsurfacevox = 0\n // var totalinnervox = 0;\n\n var index\n\n for (i = 0; i < pLength; ++i) {\n for (j = 0; j < pWidth; ++j) {\n for (k = 0; k < pHeight; ++k) {\n index = i * pWH + j * pHeight + k\n\n vpBits[ index ] &= ~ISDONE\n\n if (vpBits[ index ] & INOUT) {\n if (vpBits[ index ] & ISBOUND) {\n boundPoint.set(\n i, j, k,\n i, j, k\n )\n\n vpDistance[ index ] = 0\n vpBits[ index ] |= ISDONE\n\n totalsurfacevox += 1\n }/* else{\n totalinnervox += 1;\n } */\n }\n }\n }\n }\n\n var inarray = new Int32Array(3 * totalsurfacevox)\n var positin = 0\n var outarray = new Int32Array(3 * totalsurfacevox)\n var positout = 0\n\n for (i = 0; i < pLength; ++i) {\n for (j = 0; j < pWidth; ++j) {\n for (k = 0; k < pHeight; ++k) {\n index = i * pWH + j * pHeight + k\n\n if (vpBits[ index ] & ISBOUND) {\n inarray[ positin ] = i\n inarray[ positin + 1 ] = j\n inarray[ positin + 2 ] = k\n positin += 3\n\n vpBits[ index ] &= ~ISBOUND\n }\n }\n }\n }\n\n do {\n positout = fastoneshell(inarray, boundPoint, positin, outarray)\n positin = 0\n\n for (i = 0, n = positout; i < n; i += 3) {\n index = pWH * outarray[ i ] + pHeight * outarray[ i + 1 ] + outarray[ i + 2 ]\n vpBits[ index ] &= ~ISBOUND\n\n if (vpDistance[ index ] <= 1.0404 * cutRSq) {\n // if( vpDistance[ index ] <= 1.02 * cutRadius ){\n\n inarray[ positin ] = outarray[ i ]\n inarray[ positin + 1 ] = outarray[ i + 1 ]\n inarray[ positin + 2 ] = outarray[ i + 2 ]\n positin += 3\n }\n }\n } while (positin > 0)\n\n // var cutsf = Math.max( 0, scaleFactor - 0.5 );\n // cutoff = cutRadius - 0.5 / ( 0.1 + cutsf );\n var cutoffSq = cutoff * cutoff\n\n var index2\n var bp = new Uint16Array(3)\n\n for (i = 0; i < pLength; ++i) {\n for (j = 0; j < pWidth; ++j) {\n for (k = 0; k < pHeight; ++k) {\n index = i * pWH + j * pHeight + k\n vpBits[ index ] &= ~ISBOUND\n\n // ses solid\n\n if (vpBits[ index ] & INOUT) {\n if (!(vpBits[ index ] & ISDONE) ||\n ((vpBits[ index ] & ISDONE) && vpDistance[ index ] >= cutoffSq)\n ) {\n vpBits[ index ] |= ISBOUND\n\n if (setAtomID && (vpBits[ index ] & ISDONE)) {\n boundPoint.toArray(i, j, k, bp)\n index2 = bp[ 0 ] * pWH + bp[ 1 ] * pHeight + bp[ 2 ]\n\n vpAtomID[ index ] = vpAtomID[ index2 ]\n }\n }\n }\n }\n }\n }\n\n console.timeEnd('EDTSurface fastdistancemap')\n }\n\n function fastoneshell (inarray: Int32Array, boundPoint: iGrid, positin: number, outarray: Int32Array) {\n // *allocout,voxel2\n // ***boundPoint, int*\n // outnum, int *elimi)\n var tx, ty, tz\n var dx, dy, dz\n var i, j, n\n var square\n var index\n var nbj\n var bp = new Uint16Array(3)\n var positout = 0\n\n if (positin === 0) {\n return positout\n }\n\n var tnvix = -1\n var tnviy = -1\n var tnviz = -1\n\n var pWH = pWidth * pHeight\n\n for (i = 0, n = positin; i < n; i += 3) {\n tx = inarray[ i ]\n ty = inarray[ i + 1 ]\n tz = inarray[ i + 2 ]\n boundPoint.toArray(tx, ty, tz, bp)\n\n for (j = 0; j < 6; ++j) {\n nbj = nb[ j ]\n tnvix = tx + nbj[ 0 ]\n tnviy = ty + nbj[ 1 ]\n tnviz = tz + nbj[ 2 ]\n\n if (tnvix < pLength && tnvix > -1 &&\n tnviy < pWidth && tnviy > -1 &&\n tnviz < pHeight && tnviz > -1\n ) {\n index = tnvix * pWH + pHeight * tnviy + tnviz\n\n if ((vpBits[ index ] & INOUT) && !(vpBits[ index ] & ISDONE)) {\n boundPoint.fromArray(tnvix, tnviy, tnviz, bp)\n dx = tnvix - bp[ 0 ]\n dy = tnviy - bp[ 1 ]\n dz = tnviz - bp[ 2 ]\n square = dx * dx + dy * dy + dz * dz\n // square = Math.sqrt( square );\n\n vpDistance[ index ] = square\n vpBits[ index ] |= ISDONE\n vpBits[ index ] |= ISBOUND\n\n outarray[ positout ] = tnvix\n outarray[ positout + 1 ] = tnviy\n outarray[ positout + 2 ] = tnviz\n positout += 3\n } else if ((vpBits[ index ] & INOUT) && (vpBits[ index ] & ISDONE)) {\n dx = tnvix - bp[ 0 ]\n dy = tnviy - bp[ 1 ]\n dz = tnviz - bp[ 2 ]\n square = dx * dx + dy * dy + dz * dz\n // square = Math.sqrt( square );\n\n if (square < vpDistance[ index ]) {\n boundPoint.fromArray(tnvix, tnviy, tnviz, bp)\n vpDistance[ index ] = square\n\n if (!(vpBits[ index ] & ISBOUND)) {\n vpBits[ index ] |= ISBOUND\n\n outarray[ positout ] = tnvix\n outarray[ positout + 1 ] = tnviy\n outarray[ positout + 2 ] = tnviz\n positout += 3\n }\n }\n }\n }\n }\n }\n\n for (i = 0, n = positin; i < n; i += 3) {\n tx = inarray[ i ]\n ty = inarray[ i + 1 ]\n tz = inarray[ i + 2 ]\n boundPoint.toArray(tx, ty, tz, bp)\n\n for (j = 6; j < 18; j++) {\n nbj = nb[ j ]\n tnvix = tx + nbj[ 0 ]\n tnviy = ty + nbj[ 1 ]\n tnviz = tz + nbj[ 2 ]\n\n if (tnvix < pLength && tnvix > -1 &&\n tnviy < pWidth && tnviy > -1 &&\n tnviz < pHeight && tnviz > -1\n ) {\n index = tnvix * pWH + pHeight * tnviy + tnviz\n\n if ((vpBits[index] & INOUT) && !(vpBits[index] & ISDONE)) {\n boundPoint.fromArray(tnvix, tnviy, tnviz, bp)\n dx = tnvix - bp[ 0 ]\n dy = tnviy - bp[ 1 ]\n dz = tnviz - bp[ 2 ]\n square = dx * dx + dy * dy + dz * dz\n // square = Math.sqrt( square );\n\n vpDistance[index] = square\n vpBits[index] |= ISDONE\n vpBits[index] |= ISBOUND\n\n outarray[ positout ] = tnvix\n outarray[ positout + 1 ] = tnviy\n outarray[ positout + 2 ] = tnviz\n positout += 3\n } else if ((vpBits[index] & INOUT) && (vpBits[index] & ISDONE)) {\n dx = tnvix - bp[ 0 ]\n dy = tnviy - bp[ 1 ]\n dz = tnviz - bp[ 2 ]\n square = dx * dx + dy * dy + dz * dz\n // square = Math.sqrt( square );\n\n if (square < vpDistance[index]) {\n boundPoint.fromArray(tnvix, tnviy, tnviz, bp)\n vpDistance[index] = square\n\n if (!(vpBits[index] & ISBOUND)) {\n vpBits[index] |= ISBOUND\n\n outarray[ positout ] = tnvix\n outarray[ positout + 1 ] = tnviy\n outarray[ positout + 2 ] = tnviz\n positout += 3\n }\n }\n }\n }\n }\n }\n\n for (i = 0, n = positin; i < n; i += 3) {\n tx = inarray[ i ]\n ty = inarray[ i + 1 ]\n tz = inarray[ i + 2 ]\n boundPoint.toArray(tx, ty, tz, bp)\n\n for (j = 18; j < 26; j++) {\n nbj = nb[ j ]\n tnvix = tx + nbj[ 0 ]\n tnviy = ty + nbj[ 1 ]\n tnviz = tz + nbj[ 2 ]\n\n if (tnvix < pLength && tnvix > -1 &&\n tnviy < pWidth && tnviy > -1 &&\n tnviz < pHeight && tnviz > -1\n ) {\n index = tnvix * pWH + pHeight * tnviy + tnviz\n\n if ((vpBits[index] & INOUT) && !(vpBits[index] & ISDONE)) {\n boundPoint.fromArray(tnvix, tnviy, tnviz, bp)\n dx = tnvix - bp[ 0 ]\n dy = tnviy - bp[ 1 ]\n dz = tnviz - bp[ 2 ]\n square = dx * dx + dy * dy + dz * dz\n // square = Math.sqrt( square );\n\n vpDistance[index] = square\n vpBits[index] |= ISDONE\n vpBits[index] |= ISBOUND\n\n outarray[ positout ] = tnvix\n outarray[ positout + 1 ] = tnviy\n outarray[ positout + 2 ] = tnviz\n positout += 3\n } else if ((vpBits[index] & INOUT) && (vpBits[index] & ISDONE)) {\n dx = tnvix - bp[ 0 ]\n dy = tnviy - bp[ 1 ]\n dz = tnviz - bp[ 2 ]\n square = dx * dx + dy * dy + dz * dz\n // square = Math.sqrt( square );\n\n if (square < vpDistance[index]) {\n boundPoint.fromArray(tnvix, tnviy, tnviz, bp)\n vpDistance[index] = square\n\n if (!(vpBits[index] & ISBOUND)) {\n vpBits[index] |= ISBOUND\n\n outarray[ positout ] = tnvix\n outarray[ positout + 1 ] = tnviy\n outarray[ positout + 2 ] = tnviz\n positout += 3\n }\n }\n }\n }\n }\n }\n\n return positout\n }\n\n function marchingcubeinit (stype: string) {\n var i\n var n = vpBits.length\n\n if (stype === 'vws') {\n for (i = 0; i < n; ++i) {\n vpBits[ i ] &= ~ISBOUND\n vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0\n }\n } else if (stype === 'ms') { // ses without vdw => ms\n for (i = 0; i < n; ++i) {\n vpBits[ i ] &= ~ISDONE\n if (vpBits[ i ] & ISBOUND) {\n vpBits[ i ] |= ISDONE\n }\n vpBits[ i ] &= ~ISBOUND\n vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0\n }\n } else if (stype === 'ses') {\n for (i = 0; i < n; ++i) {\n if ((vpBits[ i ] & ISBOUND) && (vpBits[ i ] & ISDONE)) {\n vpBits[ i ] &= ~ISBOUND\n } else if ((vpBits[ i ] & ISBOUND) && !(vpBits[ i ] & ISDONE)) {\n vpBits[ i ] |= ISDONE\n }\n vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0\n }\n } else if (stype === 'sas') {\n for (i = 0; i < n; ++i) {\n vpBits[ i ] &= ~ISBOUND\n vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0\n }\n }\n }\n}\nObject.assign(EDTSurface, {__deps: [\n getSurfaceGrid, getRadiusDict, VolumeSurface, computeBoundingBox, makeGrid\n]})\n\nexport default EDTSurface\n","/**\n * @file AV Surface\n * @author Fred Ludlow \n * @private\n */\n\nimport { getSurfaceGrid } from './surface-utils'\nimport { VolumeSurface } from './volume'\nimport { uniformArray } from '../math/array-utils'\nimport {\n computeBoundingBox, v3multiplyScalar, v3cross, v3normalize\n} from '../math/vector-utils'\nimport { defaults } from '../utils'\nimport { NumberArray } from '../types';\n\n\n/**\n * Modifed from SpatialHash\n *\n * Main differences are:\n * - Optimized grid size to ensure we only ever need to look +/-1 cell\n * - Aware of atomic radii and will only output atoms within rAtom + rExtra\n * (see withinRadii method)\n *\n * (Uses rounding rather than bitshifting as consequence of arbitrary grid size)\n * @class\n * @param {Float32Array} atomsX - x coordinates\n * @param {Float32Array} atomsY - y coordinates\n * @param {Float32Array} atomsZ - z coordinates\n * @param {Float32Array} atomsR - atom radii\n * @param {Float32Array} min - xyz min coordinates\n * @param {Float32Array} max - xyz max coordinates\n * @param {Float} maxDistance - max distance\n */\nexport interface iAVHash {\n neighbourListLength: number\n withinRadii: (x: number, y: number, z: number, rExtra: number, out: Int32Array) => void\n}\n\n\nfunction makeAVHash (atomsX: Float32Array, atomsY: Float32Array, atomsZ: Float32Array, atomsR: Float32Array, min: Float32Array, max: Float32Array, maxDistance: number): iAVHash {\n maxDistance = Math.max(0.1, maxDistance) // Avoid maxDistance of zero, see #802\n var nAtoms = atomsX.length\n\n var minX = min[ 0 ]\n var minY = min[ 1 ]\n var minZ = min[ 2 ]\n\n var maxX = max[ 0 ]\n var maxY = max[ 1 ]\n var maxZ = max[ 2 ]\n\n function hashFunc (w: number, minW: number) {\n return Math.floor((w - minW) / maxDistance)\n }\n\n var iDim = hashFunc(maxX, minX) + 1\n var jDim = hashFunc(maxY, minY) + 1\n var kDim = hashFunc(maxZ, minZ) + 1\n\n var nCells = iDim * jDim * kDim\n\n var jkDim = jDim * kDim\n\n /* Get cellID for cartesian x,y,z */\n var cellID = function (x: number, y: number, z: number) {\n return (((hashFunc(x, minX) * jDim) + hashFunc(y, minY)) * kDim) + hashFunc(z, minZ)\n }\n\n /* Initial building, could probably be optimized further */\n var preHash = [] // preHash[ cellID ] = [ atomId1, atomId2 ];\n\n for (var i = 0; i < nAtoms; i++) {\n var cid = cellID(atomsX[ i ], atomsY[ i ], atomsZ[ i ])\n\n if (preHash[ cid ] === undefined) {\n preHash[ cid ] = [ i ]\n } else {\n preHash[ cid ].push(i)\n }\n }\n\n var cellOffsets = new Uint32Array(nCells)\n var cellLengths = new Uint16Array(nCells)\n var data = new Uint32Array(nAtoms)\n\n var offset = 0\n var maxCellLength = 0\n\n for (i = 0; i < nCells; i++) {\n var start = cellOffsets[ i ] = offset\n\n var subArray = preHash[ i ]\n\n if (subArray !== undefined) {\n for (var j = 0; j < subArray.length; j++) {\n data[ offset ] = subArray[ j ]\n offset++\n }\n }\n\n var cellLength = offset - start\n cellLengths[ i ] = cellLength\n\n if (cellLength > maxCellLength) { maxCellLength = cellLength }\n }\n\n // Maximum number of neighbours we could ever produce (27 adjacent cells of equal population)\n const neighbourListLength = (27 * maxCellLength) + 1\n\n /**\n * Populate the supplied out array with atom indices that are within rAtom + rExtra\n * of x,y,z\n *\n * -1 in out array indicates the end of the list\n *\n * @param {Float} x - x coordinate\n * @param {Float} y - y coordinate\n * @param {Float} z - z coordinate\n * @param {Float} rExtra - additional radius\n * @param {Float32Array} out - pre-allocated output array\n * @return {undefined}\n */\n const withinRadii = function (x: number, y: number, z: number, rExtra: number, out: Int32Array) {\n var outIdx = 0\n\n var nearI = hashFunc(x, minX)\n var nearJ = hashFunc(y, minY)\n var nearK = hashFunc(z, minZ)\n\n var loI = Math.max(0, nearI - 1)\n var loJ = Math.max(0, nearJ - 1)\n var loK = Math.max(0, nearK - 1)\n\n var hiI = Math.min(iDim, nearI + 2)\n var hiJ = Math.min(jDim, nearJ + 2)\n var hiK = Math.min(kDim, nearK + 2)\n\n for (var i = loI; i < hiI; ++i) {\n var iOffset = i * jkDim\n\n for (var j = loJ; j < hiJ; ++j) {\n var jOffset = j * kDim\n\n for (var k = loK; k < hiK; ++k) {\n var cid = iOffset + jOffset + k\n\n var cellStart = cellOffsets[ cid ]\n var cellEnd = cellStart + cellLengths[ cid ]\n\n for (var dataIndex = cellStart; dataIndex < cellEnd; dataIndex++) {\n var atomIndex = data[ dataIndex ]\n var dx = atomsX[ atomIndex ] - x\n var dy = atomsY[ atomIndex ] - y\n var dz = atomsZ[ atomIndex ] - z\n var rSum = atomsR[ atomIndex ] + rExtra\n\n if ((dx * dx + dy * dy + dz * dz) <= (rSum * rSum)) {\n out[ outIdx++ ] = data[ dataIndex ]\n }\n }\n }\n }\n }\n // Add terminator\n out[ outIdx ] = -1\n }\n return {\n neighbourListLength: neighbourListLength,\n withinRadii: withinRadii\n }\n}\n\ninterface AVSurface {\n getSurface: (type: string, probeRadius: number, scaleFactor: number, cutoff: number, setAtomID: boolean, smooth: number, contour: boolean) => any\n}\nfunction AVSurface (this: AVSurface, coordList: Float32Array, radiusList: Float32Array, indexList: Uint16Array|Uint32Array) {\n // Field generation method adapted from AstexViewer (Mike Hartshorn)\n // by Fred Ludlow.\n // Other parts based heavily on NGL (Alexander Rose) EDT Surface class\n //\n // Should work as a drop-in alternative to EDTSurface (though some of\n // the EDT paramters are not relevant in this method).\n\n const nAtoms = radiusList.length\n\n const x = new Float32Array(nAtoms)\n const y = new Float32Array(nAtoms)\n const z = new Float32Array(nAtoms)\n\n for (let i = 0; i < nAtoms; i++) {\n const ci = 3 * i\n x[ i ] = coordList[ ci ]\n y[ i ] = coordList[ ci + 1 ]\n z[ i ] = coordList[ ci + 2 ]\n }\n\n let bbox = computeBoundingBox(coordList)\n if (coordList.length === 0) {\n bbox[ 0 ].set([ 0, 0, 0 ])\n bbox[ 1 ].set([ 0, 0, 0 ])\n }\n const min = bbox[0]\n const max = bbox[1]\n\n let r: Float32Array, r2: Float32Array // Atom positions, expanded radii (squared)\n let maxRadius: number\n\n // Parameters\n let probeRadius: number, scaleFactor: number, setAtomID: boolean, probePositions: number\n\n // Cache last value for obscured test\n let lastClip = -1\n\n // Grid params\n let dim: Float32Array, matrix: Float32Array, grid: NumberArray, atomIndex: Int32Array\n\n // grid indices -> xyz coords\n let gridx: Float32Array, gridy: Float32Array, gridz: Float32Array\n\n // Lookup tables:\n let sinTable: Float32Array, cosTable: Float32Array\n\n // Spatial Hash\n let hash: iAVHash\n\n // Neighbour array to be filled by hash\n let neighbours: Int32Array\n\n // Vectors for Torus Projection\n const atob = new Float32Array([ 0.0, 0.0, 0.0 ])\n const mid = new Float32Array([ 0.0, 0.0, 0.0 ])\n const n1 = new Float32Array([ 0.0, 0.0, 0.0 ])\n const n2 = new Float32Array([ 0.0, 0.0, 0.0 ])\n\n let ngTorus: number\n\n function init (_probeRadius?: number, _scaleFactor?: number, _setAtomID?: boolean, _probePositions?: number) {\n probeRadius = defaults(_probeRadius, 1.4)\n scaleFactor = defaults(_scaleFactor, 2.0)\n setAtomID = defaults(_setAtomID, true)\n probePositions = defaults(_probePositions, 30)\n\n r = new Float32Array(nAtoms)\n r2 = new Float32Array(nAtoms)\n\n for (let i = 0; i < r.length; ++i) {\n var rExt = radiusList[ i ] + probeRadius\n r[ i ] = rExt\n r2[ i ] = rExt * rExt\n }\n\n maxRadius = 0\n for (let j = 0; j < r.length; ++j) {\n if (r[ j ] > maxRadius) maxRadius = r[ j ]\n }\n\n initializeGrid()\n initializeAngleTables()\n initializeHash()\n\n lastClip = -1\n }\n\n function fillGridDim (a: Float32Array, start: number, step: number) {\n for (let i = 0; i < a.length; i++) {\n a[i] = start + (step * i)\n }\n }\n\n function initializeGrid () {\n const surfGrid = getSurfaceGrid(\n min, max, maxRadius, scaleFactor, 0.0\n )\n\n scaleFactor = surfGrid.scaleFactor\n dim = surfGrid.dim\n matrix = surfGrid.matrix\n\n ngTorus = Math.max(5, 2 + Math.floor(probeRadius * scaleFactor))\n\n grid = uniformArray(dim[0] * dim[1] * dim[2], -1001.0)\n\n atomIndex = new Int32Array(grid.length)\n\n gridx = new Float32Array(dim[0])\n gridy = new Float32Array(dim[1])\n gridz = new Float32Array(dim[2])\n\n fillGridDim(gridx, min[0], 1 / scaleFactor)\n fillGridDim(gridy, min[1], 1 / scaleFactor)\n fillGridDim(gridz, min[2], 1 / scaleFactor)\n }\n\n function initializeAngleTables () {\n var theta = 0.0\n var step = 2 * Math.PI / probePositions\n\n cosTable = new Float32Array(probePositions)\n sinTable = new Float32Array(probePositions)\n for (var i = 0; i < probePositions; i++) {\n cosTable[ i ] = Math.cos(theta)\n sinTable[ i ] = Math.sin(theta)\n theta += step\n }\n }\n\n function initializeHash () {\n hash = makeAVHash(x, y, z, r, min, max, 2.01 * maxRadius)\n neighbours = new Int32Array(hash.neighbourListLength)\n }\n\n function obscured (x: number, y: number, z: number, a: number, b: number) {\n // Is the point at x,y,z obscured by any of the atoms\n // specifeid by indices in neighbours. Ignore indices\n // a and b (these are the relevant atoms in projectPoints/Torii)\n\n // Cache the last clipped atom (as very often the same one in\n // subsequent calls)\n let ai: number\n\n if (lastClip !== -1) {\n ai = lastClip\n if (ai !== a && ai !== b && singleAtomObscures(ai, x, y, z)) {\n return ai\n } else {\n lastClip = -1\n }\n }\n\n var ni = 0\n ai = neighbours[ ni ]\n while (ai >= 0) {\n if (ai !== a && ai !== b && singleAtomObscures(ai, x, y, z)) {\n lastClip = ai\n return ai\n }\n ai = neighbours[ ++ni ]\n }\n\n lastClip = -1\n\n return -1\n }\n\n function singleAtomObscures (ai: number, x: number, y: number, z: number) {\n var ci = 3 * ai\n var ra2 = r2[ ai ]\n var dx = coordList[ ci ] - x\n var dy = coordList[ ci + 1 ] - y\n var dz = coordList[ ci + 2 ] - z\n var d2 = dx * dx + dy * dy + dz * dz\n\n return d2 < ra2\n }\n\n function projectPoints () {\n // For each atom:\n // Iterate over a subsection of the grid, for each point:\n // If current value < 0.0, unvisited, set positive\n //\n // In any case: Project this point onto surface of the atomic sphere\n // If this projected point is not obscured by any other atom\n // Calcualte delta distance and set grid value to minimum of\n // itself and delta\n\n // Should we alias frequently accessed closure variables??\n // Assume JS engine capable of optimizing this\n // anyway...\n\n for (var i = 0; i < nAtoms; i++) {\n var ax = x[ i ]\n var ay = y[ i ]\n var az = z[ i ]\n var ar = r[ i ]\n var ar2 = r2[ i ]\n\n hash.withinRadii(ax, ay, az, ar, neighbours)\n\n // Number of grid points, round this up...\n var ng = Math.ceil(ar * scaleFactor)\n\n // Center of the atom, mapped to grid points (take floor)\n var iax = Math.floor(scaleFactor * (ax - min[ 0 ]))\n var iay = Math.floor(scaleFactor * (ay - min[ 1 ]))\n var iaz = Math.floor(scaleFactor * (az - min[ 2 ]))\n\n // Extents of grid to consider for this atom\n var minx = Math.max(0, iax - ng)\n var miny = Math.max(0, iay - ng)\n var minz = Math.max(0, iaz - ng)\n\n // Add two to these points:\n // - iax are floor'd values so this ensures coverage\n // - these are loop limits (exclusive)\n var maxx = Math.min(dim[ 0 ], iax + ng + 2)\n var maxy = Math.min(dim[ 1 ], iay + ng + 2)\n var maxz = Math.min(dim[ 2 ], iaz + ng + 2)\n\n for (var ix = minx; ix < maxx; ix++) {\n var dx = gridx[ ix ] - ax\n var xoffset = dim[ 1 ] * dim[ 2 ] * ix\n\n for (var iy = miny; iy < maxy; iy++) {\n var dy = gridy[ iy ] - ay\n var dxy2 = dx * dx + dy * dy\n var xyoffset = xoffset + dim[ 2 ] * iy\n\n for (var iz = minz; iz < maxz; iz++) {\n var dz = gridz[ iz ] - az\n var d2 = dxy2 + dz * dz\n\n if (d2 < ar2) {\n var idx = iz + xyoffset\n\n if (grid[idx] < 0.0) {\n // Unvisited, make positive\n grid[ idx ] = -grid[ idx ]\n }\n // Project on to the surface of the sphere\n // sp is the projected point ( dx, dy, dz ) * ( ra / d )\n var d = Math.sqrt(d2)\n var ap = ar / d\n var spx = dx * ap\n var spy = dy * ap\n var spz = dz * ap\n\n spx += ax\n spy += ay\n spz += az\n\n if (obscured(spx, spy, spz, i, -1) === -1) {\n var dd = ar - d\n if (dd < grid[ idx ]) {\n grid[ idx ] = dd\n if (setAtomID) atomIndex[ idx ] = i\n }\n }\n }\n }\n }\n }\n }\n }\n\n function projectTorii () {\n for (var i = 0; i < nAtoms; i++) {\n hash.withinRadii(x[ i ], y[ i ], z[ i ], r[ i ], neighbours)\n var ia = 0\n var ni = neighbours[ ia ]\n while (ni >= 0) {\n if (i < ni) {\n projectTorus(i, ni)\n }\n ni = neighbours[ ++ia ]\n }\n }\n }\n\n function projectTorus (a: number, b: number) {\n var r1 = r[ a ]\n var r2 = r[ b ]\n var dx = atob[ 0 ] = x[ b ] - x[ a ]\n var dy = atob[ 1 ] = y[ b ] - y[ a ]\n var dz = atob[ 2 ] = z[ b ] - z[ a ]\n var d2 = dx * dx + dy * dy + dz * dz\n\n // This check now redundant as already done in AVHash.withinRadii\n // if( d2 > (( r1 + r2 ) * ( r1 + r2 )) ){ return; }\n\n var d = Math.sqrt(d2)\n\n // Find angle between a->b vector and the circle\n // of their intersection by cosine rule\n var cosA = (r1 * r1 + d * d - r2 * r2) / (2.0 * r1 * d)\n\n // distance along a->b at intersection\n var dmp = r1 * cosA\n\n v3normalize(atob, atob)\n\n // Create normal to line\n normalToLine(n1 as any, atob)\n v3normalize(n1, n1)\n\n // Cross together for second normal vector\n v3cross(n2, atob, n1)\n v3normalize(n2, n2)\n\n // r is radius of circle of intersection\n var rInt = Math.sqrt(r1 * r1 - dmp * dmp)\n\n v3multiplyScalar(n1, n1, rInt)\n v3multiplyScalar(n2, n2, rInt)\n v3multiplyScalar(atob, atob, dmp)\n\n mid[ 0 ] = atob[ 0 ] + x[ a ]\n mid[ 1 ] = atob[ 1 ] + y[ a ]\n mid[ 2 ] = atob[ 2 ] + z[ a ]\n\n lastClip = -1\n\n var ng = ngTorus\n\n for (var i = 0; i < probePositions; i++) {\n var cost = cosTable[ i ]\n var sint = sinTable[ i ]\n\n var px = mid[ 0 ] + cost * n1[ 0 ] + sint * n2[ 0 ]\n var py = mid[ 1 ] + cost * n1[ 1 ] + sint * n2[ 1 ]\n var pz = mid[ 2 ] + cost * n1[ 2 ] + sint * n2[ 2 ]\n\n if (obscured(px, py, pz, a, b) === -1) {\n // As above, iterate over our grid...\n // px, py, pz in grid coords\n var iax = Math.floor(scaleFactor * (px - min[ 0 ]))\n var iay = Math.floor(scaleFactor * (py - min[ 1 ]))\n var iaz = Math.floor(scaleFactor * (pz - min[ 2 ]))\n\n var minx = Math.max(0, iax - ng)\n var miny = Math.max(0, iay - ng)\n var minz = Math.max(0, iaz - ng)\n\n var maxx = Math.min(dim[ 0 ], iax + ng + 2)\n var maxy = Math.min(dim[ 1 ], iay + ng + 2)\n var maxz = Math.min(dim[ 2 ], iaz + ng + 2)\n\n for (var ix = minx; ix < maxx; ix++) {\n dx = px - gridx[ ix ]\n var xoffset = dim[ 1 ] * dim[ 2 ] * ix\n\n for (var iy = miny; iy < maxy; iy++) {\n dy = py - gridy[ iy ]\n var dxy2 = dx * dx + dy * dy\n var xyoffset = xoffset + dim[ 2 ] * iy\n\n for (var iz = minz; iz < maxz; iz++) {\n dz = pz - gridz[ iz ]\n d2 = dxy2 + dz * dz\n var idx = iz + xyoffset\n var current = grid[ idx ]\n\n if (current > 0.0 && d2 < (current * current)) {\n grid[ idx ] = Math.sqrt(d2)\n if (setAtomID) {\n // Is this grid point closer to a or b?\n // Take dot product of atob and gridpoint->p (dx, dy, dz)\n const dp = dx * atob[ 0 ] + dy * atob [ 1 ] + dz * atob[ 2 ]\n atomIndex[ idx ] = dp < 0.0 ? b : a\n }\n }\n }\n }\n }\n }\n }\n }\n\n function normalToLine (out: Int32Array, p: Float32Array) {\n out[ 0 ] = out[ 1 ] = out[ 2 ] = 1.0\n if (p[ 0 ] !== 0) {\n out[ 0 ] = (p[ 1 ] + p[ 2 ]) / -p[ 0 ]\n } else if (p[ 1 ] !== 0) {\n out[ 1 ] = (p[ 0 ] + p[ 2 ]) / -p[ 1 ]\n } else if (p[ 2 ] !== 0) {\n out[ 2 ] = (p[ 0 ] + p[ 1 ]) / -p[ 2 ]\n }\n return out\n }\n\n function fixNegatives () {\n for (var i = 0; i < grid.length; i++) {\n if (grid[ i ] < 0) grid[ i ] = 0\n }\n }\n\n function fixAtomIDs () {\n for (var i = 0; i < atomIndex.length; i++) {\n atomIndex[ i ] = indexList[ atomIndex[ i ] ]\n }\n }\n\n function getVolume (probeRadius: number, scaleFactor: number, setAtomID: boolean) {\n // Basic steps are:\n // 1) Initialize\n // 2) Project points\n // 3) Project torii\n\n console.time('AVSurface.getVolume')\n\n console.time('AVSurface.init')\n init(probeRadius, scaleFactor, setAtomID)\n console.timeEnd('AVSurface.init')\n\n console.time('AVSurface.projectPoints')\n projectPoints()\n console.timeEnd('AVSurface.projectPoints')\n\n console.time('AVSurface.projectTorii')\n projectTorii()\n console.timeEnd('AVSurface.projectTorii')\n fixNegatives()\n fixAtomIDs()\n\n console.timeEnd('AVSurface.getVolume')\n }\n\n this.getSurface = function (type: string, probeRadius: number, scaleFactor: number, cutoff: number, setAtomID: boolean, smooth: number, contour: boolean) {\n // type and cutoff left in for compatibility with EDTSurface.getSurface\n // function signature\n\n getVolume(probeRadius, scaleFactor, setAtomID)\n\n var volsurf = new (VolumeSurface as any)(\n grid, dim[ 2 ], dim[ 1 ], dim[ 0 ], atomIndex\n ) as VolumeSurface\n\n return volsurf.getSurface!(probeRadius, false, undefined, matrix, contour)\n }\n}\nObject.assign(AVSurface, {__deps: [\n getSurfaceGrid, VolumeSurface, uniformArray, computeBoundingBox,\n v3multiplyScalar, v3cross, v3normalize,\n makeAVHash,\n defaults\n]})\n\nexport { AVSurface, makeAVHash }\n","/**\n * @file Molecular Surface\n * @author Alexander Rose \n * @private\n */\n\nimport { WorkerRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport Worker from '../worker/worker'\nimport EDTSurface from './edt-surface'\nimport { AVSurface } from './av-surface'\nimport Surface, { SurfaceData } from './surface'\nimport { Structure } from '../ngl';\nimport { AtomData, RadiusParams } from '../structure/structure-data';\n\nWorkerRegistry.add('molsurf', function func (e: any, callback: (data: any, buffers: any[])=> void) {\n const a = e.data.args\n const p = e.data.params\n if (a && p) {\n const SurfClass = (p.type === 'av') ? AVSurface : EDTSurface\n const surf = new (SurfClass as any)(a.coordList, a.radiusList, a.indexList) as AVSurface|EDTSurface\n const sd = surf.getSurface(\n p.type, p.probeRadius, p.scaleFactor, p.cutoff, true, p.smooth, p.contour\n ) as SurfaceData\n const transferList = [ sd.position.buffer, sd.index!.buffer ]\n if (sd.normal) transferList.push(sd.normal.buffer)\n if (sd.atomindex) transferList.push(sd.atomindex.buffer)\n const data = {\n sd: sd,\n p: p\n }\n callback(data, transferList)\n }\n}, [ EDTSurface, AVSurface ])\n\n/**\n * Molecular surface parameter object.\n * @typedef {Object} MolecularSurfaceParameters - stage parameters\n * @property {String} type - \"av\" or \"edt\"\n * @property {Number} probeRadius - probe radius\n * @property {Number} scaleFactor - higher for better quality\n * @property {Integer} smooth - number of smoothing cycles to apply\n * @property {String} name - name for created surface\n */\nexport interface MolecularSurfaceParameters {\n type: 'av'|'edt'\n probeRadius: number\n scaleFactor: number\n smooth: number\n name: string\n cutoff: number\n contour: boolean,\n radiusParams: RadiusParams\n}\n/**\n * Create Molecular surfaces\n */\nclass MolecularSurface {\n structure: Structure\n worker: Worker|undefined\n\n constructor (structure: Structure) {\n this.structure = structure\n }\n\n _getAtomData (params: Partial): AtomData {\n return this.structure.getAtomData({\n what: { position: true, radius: true, index: true },\n radiusParams: defaults(params.radiusParams, {\n type: 'vdw', scale: 1.0\n })\n })\n }\n\n _makeSurface (sd: SurfaceData, p: Partial) {\n var surface = new Surface(p.name!, '', sd)\n\n surface.info.type = p.type\n surface.info.probeRadius = p.probeRadius\n surface.info.scaleFactor = p.scaleFactor\n surface.info.smooth = p.smooth\n surface.info.cutoff = p.cutoff\n\n return surface\n }\n\n /**\n * Get molecular surface\n * @param {MolecularSurfaceParameters} params - parameters for surface creation\n * @return {Surface} the surface\n */\n getSurface (params: Partial) {\n const p = params || {}\n\n const atomData = this._getAtomData(params)\n const coordList = atomData.position\n const radiusList = atomData.radius\n const indexList = atomData.index\n\n const SurfClass = (p.type === 'av') ? AVSurface : EDTSurface\n const surf = new (SurfClass as any)(coordList, radiusList, indexList) as AVSurface|EDTSurface\n const sd = surf.getSurface(\n p.type!, p.probeRadius!, p.scaleFactor!, p.cutoff!, true, p.smooth!, p.contour!\n )\n\n return this._makeSurface(sd, p)\n }\n\n /**\n * Get molecular surface asynchronous\n * @param {MolecularSurfaceParameters} params - parameters for surface creation\n * @param {function(surface: Surface)} callback - function to be called after surface is created\n * @return {undefined}\n */\n getSurfaceWorker (params: MolecularSurfaceParameters, callback: (s: Surface) => void) {\n const p = Object.assign({}, params)\n\n if (window.hasOwnProperty('Worker')) {\n if (this.worker === undefined) {\n this.worker = new Worker('molsurf')\n }\n\n const atomData = this._getAtomData(params)\n const coordList = atomData.position\n const radiusList = atomData.radius\n const indexList = atomData.index\n\n const msg = {\n args: {\n coordList: coordList,\n radiusList: radiusList,\n indexList: indexList\n },\n params: p\n }\n\n const transferList = [\n coordList!.buffer, radiusList!.buffer, indexList!.buffer\n ]\n\n this.worker.post(msg, transferList,\n\n (e: any) => {\n callback(this._makeSurface(e.data.sd, p))\n },\n\n (e: string) => {\n console.warn(\n 'MolecularSurface.getSurfaceWorker error - trying without worker', e\n )\n this.worker!.terminate()\n this.worker = undefined\n const surface = this.getSurface(p)\n callback(surface)\n }\n\n )\n } else {\n const surface = this.getSurface(p)\n callback(surface)\n }\n }\n\n /**\n * Cleanup\n * @return {undefined}\n */\n dispose () {\n if (this.worker) this.worker.terminate()\n }\n}\n\nexport default MolecularSurface\n","/**\n * @file Molecular Surface Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport MolecularSurface, { MolecularSurfaceParameters } from '../surface/molecular-surface'\nimport SurfaceBuffer from '../buffer/surface-buffer'\nimport ContourBuffer from '../buffer/contour-buffer'\nimport DoubleSidedBuffer from '../buffer/doublesided-buffer'\nimport Selection from '../selection/selection'\nimport Viewer from '../viewer/viewer';\n// @ts-ignore: unused import Volume required for declaration only\nimport { Structure, Vector3, Volume } from '../ngl';\nimport StructureView from '../structure/structure-view';\nimport { SurfaceDataFields } from './surface-representation';\nimport Surface, {SurfaceData} from '../surface/surface';\n\nexport interface MolecularSurfaceRepresentationParameters extends StructureRepresentationParameters {\n surfaceType: 'vws'|'sas'|'ms'|'ses'|'av'\n probeRadius: number\n smooth: number\n scaleFactor: number\n cutoff: number\n contour: boolean\n background: boolean\n opaqueBack: boolean\n filterSele: string\n colorVolume: any\n useWorker: boolean\n}\n\nexport interface MolecularSurfaceInfo {\n molsurf?: MolecularSurface\n sele?: string\n surface?: Surface\n}\n\n/**\n * Molecular Surface Representation\n */\nclass MolecularSurfaceRepresentation extends StructureRepresentation {\n protected surfaceType: 'vws'|'sas'|'ms'|'ses'|'av'\n protected probeRadius: number\n protected smooth: number\n protected scaleFactor: number\n protected cutoff: number\n protected contour: boolean\n protected background: boolean\n protected opaqueBack: boolean\n protected filterSele: string\n protected colorVolume: any\n protected useWorker: boolean\n\n protected __infoList: MolecularSurfaceInfo[]\n protected __forceNewMolsurf: boolean\n protected __sele: string\n protected __surfaceParams: string\n\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'surface'\n\n this.parameters = Object.assign({\n\n surfaceType: {\n type: 'select',\n rebuild: true,\n options: {\n 'vws': 'vws',\n 'sas': 'sas',\n 'ms': 'ms',\n 'ses': 'ses',\n 'av': 'av'\n }\n },\n probeRadius: {\n type: 'number',\n precision: 1,\n max: 20,\n min: 0,\n rebuild: true\n },\n smooth: {\n type: 'integer',\n precision: 1,\n max: 10,\n min: 0,\n rebuild: true\n },\n scaleFactor: {\n type: 'number',\n precision: 1,\n max: 5,\n min: 0,\n rebuild: true\n },\n cutoff: {\n type: 'number',\n precision: 2,\n max: 50,\n min: 0,\n rebuild: true\n },\n contour: {\n type: 'boolean', rebuild: true\n },\n background: {\n type: 'boolean', rebuild: true // FIXME\n },\n opaqueBack: {\n type: 'boolean', buffer: true\n },\n filterSele: {\n type: 'text', rebuild: true\n },\n colorVolume: {\n type: 'hidden'\n },\n useWorker: {\n type: 'boolean', rebuild: true\n }\n\n }, this.parameters, {\n\n radius: null,\n scale: null\n\n })\n\n this.__infoList = []\n\n // TODO find a more direct way\n this.structure.signals.refreshed.add(() => {\n this.__forceNewMolsurf = true\n })\n\n this.toBePrepared = true\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'uniform')\n p.colorValue = defaults(p.colorValue, 0xDDDDDD)\n p.disablePicking = defaults(p.disablePicking, true)\n\n this.surfaceType = defaults(p.surfaceType, 'ms')\n this.probeRadius = defaults(p.probeRadius, 1.4)\n this.smooth = defaults(p.smooth, 2)\n this.scaleFactor = defaults(p.scaleFactor, 2.0)\n this.cutoff = defaults(p.cutoff, 0.0)\n this.contour = defaults(p.contour, false)\n this.background = defaults(p.background, false)\n this.opaqueBack = defaults(p.opaqueBack, true)\n this.filterSele = defaults(p.filterSele, '')\n this.colorVolume = defaults(p.colorVolume, undefined)\n this.useWorker = defaults(p.useWorker, true)\n\n super.init(params)\n }\n\n prepareData (sview: StructureView, i: number, callback: (i: number) => void) {\n let info: MolecularSurfaceInfo = this.__infoList[ i ]\n if (!info) {\n info = {}\n this.__infoList[ i ] = info\n }\n\n if (!info.molsurf || info.sele !== sview.selection.string) {\n if (this.filterSele) {\n const sviewFilter = sview.structure.getView(new Selection(this.filterSele))\n const bbSize = sviewFilter.boundingBox.getSize(new Vector3())\n const maxDim = Math.max(bbSize.x, bbSize.y, bbSize.z)\n const asWithin = sview.getAtomSetWithinPoint(sviewFilter.center, (maxDim / 2) + 6.0)\n sview = sview.getView(\n new Selection(sview.getAtomSetWithinSelection(asWithin, 3).toSeleString())\n )\n if (sview.atomCount === 0) {\n callback(i)\n return\n }\n }\n\n info.sele = sview.selection.string\n info.molsurf = new MolecularSurface(sview)\n\n const p = this.getSurfaceParams()\n const onSurfaceFinish = (surface: Surface) => {\n info.surface = surface\n callback(i)\n }\n\n if (this.useWorker) {\n info.molsurf.getSurfaceWorker(p as MolecularSurfaceParameters, onSurfaceFinish)\n } else {\n onSurfaceFinish(info.molsurf.getSurface(p as {name: string, type: 'av'|'edt' } & MolecularSurfaceRepresentationParameters))\n }\n } else {\n callback(i)\n }\n }\n\n prepare (callback: () => void) {\n if (this.__forceNewMolsurf || this.__sele !== this.selection.string ||\n this.__surfaceParams !== JSON.stringify(this.getSurfaceParams())) {\n this.__infoList.forEach((info: MolecularSurfaceInfo) => {\n if (info && info.molsurf) {\n info.molsurf.dispose()\n }\n })\n this.__infoList.length = 0\n }\n\n if (this.structureView.atomCount === 0) {\n callback()\n return\n }\n\n const after = () => {\n this.__sele = this.selection.string\n this.__surfaceParams = JSON.stringify(this.getSurfaceParams())\n this.__forceNewMolsurf = false\n callback()\n }\n\n const name = this.assembly === 'default' ? this.defaultAssembly : this.assembly\n const assembly = this.structure.biomolDict[ name ]\n\n if (assembly) {\n assembly.partList.forEach((part, i) => {\n const sview = part.getView(this.structureView)\n this.prepareData(sview as StructureView, i, (_i) => {\n if (_i === assembly.partList.length - 1) after()\n })\n })\n } else {\n this.prepareData(this.structureView, 0, after)\n }\n }\n\n createData (sview: StructureView, i: number) {\n const info = this.__infoList[ i ]\n const surface = info.surface\n\n if (!surface) {\n // Surface creation bailed (no surface generated for this sview)\n return\n }\n\n const surfaceData = {\n position: surface!.getPosition(),\n color: surface!.getColor(this.getColorParams()),\n index: surface!.getFilteredIndex(this.filterSele, sview)\n }\n\n const bufferList = []\n\n if (surface.contour) {\n const contourBuffer = new ContourBuffer(\n surfaceData,\n this.getBufferParams({\n wireframe: false\n })\n )\n\n bufferList.push(contourBuffer)\n } else {\n Object.assign(surfaceData, {\n normal: surface.getNormal(),\n picking: surface.getPicking(sview.getStructure())\n })\n\n const surfaceBuffer = new SurfaceBuffer(\n surfaceData,\n this.getBufferParams({\n background: this.background,\n opaqueBack: this.opaqueBack,\n dullInterior: false\n })\n )\n\n if (this.getBufferParams().side == 'double') {\n const doubleSidedBuffer = new DoubleSidedBuffer(surfaceBuffer)\n bufferList.push(doubleSidedBuffer)\n }\n else {\n bufferList.push(surfaceBuffer)\n }\n }\n\n return { bufferList, info } as StructureRepresentationData\n }\n\n updateData (what: SurfaceDataFields, data: StructureRepresentationData) {\n const surfaceData: Partial = {}\n\n if (what.position || what.radius) {\n this.__forceNewMolsurf = true\n this.build()\n return\n }\n\n if (what.color) {\n surfaceData.color = data.info.surface.getColor(this.getColorParams())\n }\n\n if (what.index) {\n surfaceData.index = data.info.surface.getFilteredIndex(this.filterSele, data.sview)\n }\n\n data.bufferList[ 0 ].setAttributes(surfaceData)\n }\n\n setParameters (params: Partial, what: Partial = {}, rebuild?: boolean) {\n if (params && params.filterSele) {\n what.index = true\n }\n\n if (params && params.colorVolume !== undefined) {\n what.color = true\n }\n\n // forbid setting wireframe to true when contour is true\n if (params && params.wireframe && (\n params.contour || (params.contour === undefined && this.contour)\n )\n ) {\n params.wireframe = false\n }\n\n super.setParameters(params, what, rebuild)\n\n return this\n }\n\n getSurfaceParams (params: Partial = {}) {\n const p = Object.assign({\n type: this.surfaceType as string,\n probeRadius: this.probeRadius as number,\n scaleFactor: this.scaleFactor as number,\n smooth: this.smooth && !this.contour,\n cutoff: this.cutoff as number,\n contour: this.contour as boolean,\n useWorker: this.useWorker as boolean,\n radiusParams: this.getRadiusParams()\n }, params)\n\n return p\n }\n\n getColorParams () {\n const p = super.getColorParams()\n\n p.volume = this.colorVolume\n\n return p\n }\n\n getAtomRadius () {\n return 0\n }\n\n clear () {\n super.clear()\n }\n\n dispose () {\n this.__infoList.forEach((info: MolecularSurfaceInfo) => {\n if (info && info.molsurf) {\n info.molsurf.dispose()\n }\n })\n this.__infoList.length = 0\n\n super.dispose()\n }\n}\n\nRepresentationRegistry.add('surface', MolecularSurfaceRepresentation)\n\nexport default MolecularSurfaceRepresentation\n","/**\n * @file Point Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport PointBuffer from '../buffer/point-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport { AtomDataFields } from '../structure/structure-data';\n\nexport interface PointRepresentationParameters extends StructureRepresentationParameters {\n pointSize: number\n sizeAttenuation: boolean\n sortParticles: boolean\n useTexture: boolean\n alphaTest: number\n forceTransparent: boolean\n edgeBleach: number\n}\n\n/**\n * Point Representation\n */\nclass PointRepresentation extends StructureRepresentation {\n protected pointSize: number\n protected sizeAttenuation: boolean\n protected sortParticles: boolean\n protected useTexture: boolean\n protected alphaTest: number\n protected forceTransparent: boolean\n protected edgeBleach: number\n\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'point'\n\n this.parameters = Object.assign({\n\n pointSize: {\n type: 'number', precision: 1, max: 100, min: 0, buffer: true\n },\n sizeAttenuation: {\n type: 'boolean', buffer: true\n },\n sortParticles: {\n type: 'boolean', rebuild: true\n },\n useTexture: {\n type: 'boolean', buffer: true\n },\n alphaTest: {\n type: 'range', step: 0.001, max: 1, min: 0, buffer: true\n },\n forceTransparent: {\n type: 'boolean', buffer: true\n },\n edgeBleach: {\n type: 'range', step: 0.001, max: 1, min: 0, buffer: true\n }\n\n }, this.parameters, {\n\n flatShaded: null,\n wireframe: null,\n linewidth: null,\n side: null,\n\n roughness: null,\n metalness: null\n\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n\n this.pointSize = defaults(p.pointSize, 1)\n this.sizeAttenuation = defaults(p.sizeAttenuation, true)\n this.sortParticles = defaults(p.sortParticles, false)\n this.useTexture = defaults(p.useTexture, false)\n this.alphaTest = defaults(p.alphaTest, 0.5)\n this.forceTransparent = defaults(p.forceTransparent, false)\n this.edgeBleach = defaults(p.edgeBleach, 0.0)\n\n super.init(p)\n }\n\n createData (sview: StructureView) {\n var what = { position: true, color: true, picking: true }\n var atomData = sview.getAtomData(this.getAtomParams(what))\n\n var pointBuffer = new PointBuffer(\n atomData,\n this.getBufferParams({\n pointSize: this.pointSize,\n sizeAttenuation: this.sizeAttenuation,\n sortParticles: this.sortParticles,\n useTexture: this.useTexture,\n alphaTest: this.alphaTest,\n forceTransparent: this.forceTransparent,\n edgeBleach: this.edgeBleach\n })\n )\n\n return {\n bufferList: [ pointBuffer ]\n }\n }\n\n updateData (what: AtomDataFields, data: StructureRepresentationData) {\n var atomData = data.sview!.getAtomData(this.getAtomParams(what))\n var pointData = {}\n\n if (!what || what.position) {\n Object.assign(pointData, {position: atomData.position})\n }\n\n if (!what || what.color) {\n Object.assign(pointData, {color: atomData.color})\n }\n\n data.bufferList[ 0 ].setAttributes(pointData)\n }\n\n getAtomRadius () {\n return 0.1\n }\n}\n\nRepresentationRegistry.add('point', PointRepresentation)\n\nexport default PointRepresentation\n","/**\n * @file Ribbon Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport '../shader/Ribbon.vert'\n\nimport { getUintArray } from '../utils'\nimport { serialArray } from '../math/array-utils'\nimport MeshBuffer from './mesh-buffer'\nimport { BufferParameters, BufferData } from './buffer'\nimport {Log} from \"../globals\";\n\nconst quadIndices = new Uint16Array([\n 0, 1, 2,\n 1, 3, 2\n])\n\nexport interface RibbonBufferData extends BufferData {\n normal: Float32Array\n dir: Float32Array\n size: Float32Array\n}\n\nfunction getSize(data: RibbonBufferData){\n const n = (data.position!.length / 3) - 1\n const n4 = n * 4\n const x = n4 * 3\n return x\n}\n\n/**\n * Ribbon buffer. Draws a thin ribbon.\n */\nclass RibbonBuffer extends MeshBuffer {\n vertexShader = 'Ribbon.vert'\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.normal - normals\n * @param {Float32Array} data.dir - binormals\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.size - sizes\n * @param {Picker} data.picking - picking ids\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: RibbonBufferData, params: Partial = {}) {\n super({\n position: new Float32Array(getSize(data)),\n color: new Float32Array(getSize(data)),\n index: getUintArray(getSize(data), getSize(data) / 3),\n normal: new Float32Array(getSize(data)),\n picking: data.picking\n }, params)\n\n const n = (data.position!.length / 3) - 1\n const n4 = n * 4\n const x = n4 * 3\n\n this.addAttributes({\n 'dir': { type: 'v3', value: new Float32Array(x) }\n })\n this.addAttributes({\n 'size': { type: 'f', value: new Float32Array(n4) }\n })\n\n data.primitiveId = serialArray(n)\n this.setAttributes(data)\n\n this.makeIndex()\n }\n\n setAttributes (data: Partial = {}) {\n const n4 = this.size\n const n = n4 / 4\n\n const attributes = this.geometry.attributes as any // TODO\n\n let position, normal, size, dir, color, primitiveId\n let aPosition, aNormal, aSize, aDir, aColor, aPrimitiveId\n\n if (data.position) {\n position = data.position\n aPosition = attributes.position.array\n attributes.position.needsUpdate = true\n }\n\n if (data.normal) {\n normal = data.normal\n aNormal = attributes.normal.array\n attributes.normal.needsUpdate = true\n }\n\n if (data.size) {\n size = data.size\n aSize = attributes.size.array\n attributes.size.needsUpdate = true\n }\n\n if (data.dir) {\n dir = data.dir\n aDir = attributes.dir.array\n attributes.dir.needsUpdate = true\n }\n\n if (data.color) {\n color = data.color\n aColor = attributes.color.array\n attributes.color.needsUpdate = true\n }\n\n if (data.primitiveId) {\n primitiveId = data.primitiveId\n aPrimitiveId = attributes.primitiveId.array\n attributes.primitiveId.needsUpdate = true\n }\n\n let v, i, k, p, l, v3\n let currSize\n let prevSize = size ? size[ 0 ] : null\n\n for (v = 0; v < n; ++v) {\n v3 = v * 3\n k = v * 3 * 4\n l = v * 4\n\n if (position) {\n aPosition[ k ] = aPosition[ k + 3 ] = position[ v3 ]\n aPosition[ k + 1 ] = aPosition[ k + 4 ] = position[ v3 + 1 ]\n aPosition[ k + 2 ] = aPosition[ k + 5 ] = position[ v3 + 2 ]\n\n aPosition[ k + 6 ] = aPosition[ k + 9 ] = position[ v3 + 3 ]\n aPosition[ k + 7 ] = aPosition[ k + 10 ] = position[ v3 + 4 ]\n aPosition[ k + 8 ] = aPosition[ k + 11 ] = position[ v3 + 5 ]\n }\n\n if (normal) {\n aNormal[ k ] = aNormal[ k + 3 ] = -normal[ v3 ]\n aNormal[ k + 1 ] = aNormal[ k + 4 ] = -normal[ v3 + 1 ]\n aNormal[ k + 2 ] = aNormal[ k + 5 ] = -normal[ v3 + 2 ]\n\n aNormal[ k + 6 ] = aNormal[ k + 9 ] = -normal[ v3 + 3 ]\n aNormal[ k + 7 ] = aNormal[ k + 10 ] = -normal[ v3 + 4 ]\n aNormal[ k + 8 ] = aNormal[ k + 11 ] = -normal[ v3 + 5 ]\n }\n\n for (i = 0; i < 4; ++i) {\n p = k + 3 * i\n\n if (color) {\n aColor[ p ] = color[ v3 ]\n aColor[ p + 1 ] = color[ v3 + 1 ]\n aColor[ p + 2 ] = color[ v3 + 2 ]\n }\n\n if (primitiveId) {\n aPrimitiveId[ l + i ] = primitiveId[ v ]\n }\n }\n\n if (size) {\n currSize = size[ v ]\n\n if (prevSize !== size[ v ]) {\n aSize[ l ] = prevSize\n aSize[ l + 1 ] = prevSize\n aSize[ l + 2 ] = currSize\n aSize[ l + 3 ] = currSize\n } else {\n aSize[ l ] = currSize\n aSize[ l + 1 ] = currSize\n aSize[ l + 2 ] = currSize\n aSize[ l + 3 ] = currSize\n }\n\n prevSize = currSize\n }\n\n if (dir) {\n aDir[ k ] = dir[ v3 ]\n aDir[ k + 1 ] = dir[ v3 + 1 ]\n aDir[ k + 2 ] = dir[ v3 + 2 ]\n\n aDir[ k + 3 ] = -dir[ v3 ]\n aDir[ k + 4 ] = -dir[ v3 + 1 ]\n aDir[ k + 5 ] = -dir[ v3 + 2 ]\n\n aDir[ k + 6 ] = dir[ v3 + 3 ]\n aDir[ k + 7 ] = dir[ v3 + 4 ]\n aDir[ k + 8 ] = dir[ v3 + 5 ]\n\n aDir[ k + 9 ] = -dir[ v3 + 3 ]\n aDir[ k + 10 ] = -dir[ v3 + 4 ]\n aDir[ k + 11 ] = -dir[ v3 + 5 ]\n }\n }\n }\n\n makeIndex () {\n const index = this.geometry.getIndex()\n if (!index) { Log.error('Index is null'); return; }\n const meshIndex = index.array as Uint32Array|Uint16Array\n const n = meshIndex.length / 4 / 3\n\n for (let v = 0; v < n; ++v) {\n const ix = v * 6\n const it = v * 4\n\n meshIndex.set(quadIndices, ix)\n for (let s = 0; s < 6; ++s) {\n meshIndex[ ix + s ] += it\n }\n }\n }\n}\n\nexport default RibbonBuffer\n","/**\n * @file Ribbon Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport Spline, { SplineParameters } from '../geometry/spline'\nimport StructureRepresentation, { StructureRepresentationParameters } from './structure-representation'\nimport RibbonBuffer from '../buffer/ribbon-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport AtomProxy from '../proxy/atom-proxy';\nimport StructureView from '../structure/structure-view';\nimport Polymer from '../proxy/polymer';\n\nexport interface RibbonRepresentationParameters extends StructureRepresentationParameters {\n subdiv: number\n tension: number\n smoothSheet: boolean\n}\n\n/**\n * Ribbon Representation\n */\nclass RibbonRepresentation extends StructureRepresentation {\n protected subdiv: number\n protected tension: number\n protected smoothSheet: boolean\n \n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'ribbon'\n\n this.parameters = Object.assign({\n\n subdiv: {\n type: 'integer', max: 50, min: 1, rebuild: true\n },\n tension: {\n type: 'number', precision: 1, max: 1.0, min: 0.1\n },\n smoothSheet: {\n type: 'boolean', rebuild: true\n }\n\n }, this.parameters, {\n\n side: null,\n wireframe: null,\n linewidth: null\n\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'chainname')\n p.colorScale = defaults(p.colorScale, 'RdYlBu')\n p.radiusType = defaults(p.radiusType, 'sstruc')\n p.radiusScale = defaults(p.radiusScale, 4.0)\n\n if (p.quality === 'low') {\n this.subdiv = 3\n } else if (p.quality === 'medium') {\n this.subdiv = 6\n } else if (p.quality === 'high') {\n this.subdiv = 12\n } else {\n this.subdiv = defaults(p.subdiv, 6)\n }\n\n this.tension = defaults(p.tension, NaN)\n this.smoothSheet = defaults(p.smoothSheet, false)\n\n super.init(p)\n }\n\n getSplineParams (params?: Partial) {\n return Object.assign({\n subdiv: this.subdiv,\n tension: this.tension,\n directional: true,\n smoothSheet: this.smoothSheet\n }, params)\n }\n\n getAtomRadius (atom: AtomProxy) {\n return atom.isTrace() ? super.getAtomRadius(atom) : 0\n }\n\n createData (sview: StructureView) {\n var bufferList: RibbonBuffer[] = []\n var polymerList: Polymer[] = []\n\n this.structure.eachPolymer(polymer => {\n if (polymer.residueCount < 4) return\n polymerList.push(polymer)\n\n var spline = new Spline(polymer, this.getSplineParams())\n var subPos = spline.getSubdividedPosition()\n var subOri = spline.getSubdividedOrientation()\n var subCol = spline.getSubdividedColor(this.getColorParams())\n var subPick = spline.getSubdividedPicking()\n var subSize = spline.getSubdividedSize(this.getRadiusParams())\n\n bufferList.push(\n new RibbonBuffer(\n ({\n position: subPos.position,\n normal: subOri.binormal,\n dir: subOri.normal,\n color: subCol.color,\n size: subSize.size,\n picking: subPick.picking\n }),\n this.getBufferParams()\n )\n )\n }, sview.getSelection())\n\n return {\n bufferList: bufferList,\n polymerList: polymerList\n }\n }\n\n updateData (what: {position?: boolean, radius?: boolean, scale?: boolean, color?: boolean}, data: {polymerList: Polymer[], bufferList: RibbonBuffer[]}) {\n what = what || {}\n\n var i = 0\n var n = data.polymerList.length\n\n for (i = 0; i < n; ++i) {\n var bufferData = {}\n var spline = new Spline(data.polymerList[ i ], this.getSplineParams())\n\n if (what.position) {\n var subPos = spline.getSubdividedPosition()\n var subOri = spline.getSubdividedOrientation()\n Object.assign(bufferData, {\n position: subPos.position,\n normal: subOri.binormal,\n dir: subOri.normal\n })\n }\n\n if (what.radius || what.scale) {\n var subSize = spline.getSubdividedSize(this.getRadiusParams())\n Object.assign(bufferData, {size: subSize.size})\n }\n\n if (what.color) {\n var subCol = spline.getSubdividedColor(this.getColorParams())\n Object.assign(bufferData, {color: subCol.color})\n }\n\n data.bufferList[ i ].setAttributes(bufferData)\n }\n }\n\n setParameters (params: Partial) {\n var rebuild = false\n var what = {}\n\n if (params && params.tension) {\n Object.assign(what, {position: true})\n }\n\n super.setParameters(params, what, rebuild)\n\n return this\n }\n}\n\nRepresentationRegistry.add('ribbon', RibbonRepresentation)\n\nexport default RibbonRepresentation\n","/**\n * @file Rocket Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { AtomPicker } from '../utils/picker'\nimport StructureRepresentation, { StructureRepresentationParameters } from './structure-representation'\nimport Helixbundle, { Axis } from '../geometry/helixbundle'\nimport CylinderBuffer from '../buffer/cylinder-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport CylinderGeometryBuffer from '../buffer/cylindergeometry-buffer';\nimport CylinderImpostorBuffer from '../buffer/cylinderimpostor-buffer';\n\nexport interface RocketRepresentationParameters extends StructureRepresentationParameters {\n localAngle: number\n centerDist: number\n ssBorder: boolean\n radialSegments: number\n openEnded: boolean\n disableImpostor: boolean\n}\n\nexport interface AxisData {\n begin: Float32Array\n end: Float32Array\n size: Float32Array\n color: Float32Array\n picking: AtomPicker\n}\n\n/**\n * Rocket Representation\n */\nclass RocketRepresentation extends StructureRepresentation {\n\n protected localAngle: number\n protected centerDist: number\n protected ssBorder: boolean\n protected radialSegments: number\n protected openEnded: boolean\n protected disableImpostor: boolean\n // protected helixbundleList: Helixbundle[]\n\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'rocket'\n\n this.parameters = Object.assign({\n\n localAngle: {\n type: 'integer', max: 180, min: 0, rebuild: true\n },\n centerDist: {\n type: 'number', precision: 1, max: 10, min: 0, rebuild: true\n },\n ssBorder: {\n type: 'boolean', rebuild: true\n },\n radialSegments: true,\n openEnded: true,\n disableImpostor: true\n\n }, this.parameters)\n\n // this.helixbundleList = []\n\n this.init(params)\n }\n\n init (params: Partial) {\n let p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'sstruc')\n p.radiusSize = defaults(p.radiusSize, 1.5)\n p.radiusScale = defaults(p.radiusScale, 1.0)\n p.openEnded = defaults(p.openEnded, false)\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n this.localAngle = defaults(p.localAngle, 30)\n this.centerDist = defaults(p.centerDist, 2.5)\n this.ssBorder = defaults(p.ssBorder, false)\n\n super.init(p)\n }\n\n createData (sview: StructureView) {\n let length = 0\n const axisList:Axis[] = []\n const helixbundleList:Helixbundle[] = []\n\n this.structure.eachPolymer(polymer => {\n if (polymer.residueCount < 4 || polymer.isNucleic()) return\n\n const helixbundle = new Helixbundle(polymer)\n const axis = helixbundle.getAxis(\n this.localAngle, this.centerDist, this.ssBorder,\n this.getColorParams(), this.getRadiusParams()\n )\n\n length += axis.size.length\n axisList.push(axis)\n helixbundleList.push(helixbundle)\n }, sview.getSelection())\n\n const axisData = {\n begin: new Float32Array(length * 3),\n end: new Float32Array(length * 3),\n size: new Float32Array(length),\n color: new Float32Array(length * 3),\n picking: {}\n }\n\n let picking = new Float32Array(length)\n\n let offset = 0\n\n axisList.forEach(function (axis) {\n axisData.begin.set(axis.begin, offset * 3)\n axisData.end.set(axis.end, offset * 3)\n axisData.size.set(axis.size, offset)\n axisData.color.set(axis.color, offset * 3)\n picking.set(axis.picking.array!, offset)\n offset += axis.size.length\n })\n\n if (length) {\n axisData.picking = new AtomPicker(\n picking, sview.getStructure()\n )\n }\n\n const cylinderBuffer = new CylinderBuffer(\n {\n position1: axisData.begin,\n position2: axisData.end,\n color: axisData.color,\n color2: axisData.color,\n radius: axisData.size,\n picking: axisData.picking\n },\n this.getBufferParams({\n openEnded: this.openEnded,\n radialSegments: this.radialSegments,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n })\n )\n\n return {\n bufferList: [ cylinderBuffer as CylinderGeometryBuffer|CylinderImpostorBuffer ],\n axisList: axisList,\n helixbundleList: helixbundleList,\n axisData: axisData\n }\n }\n\n \n updateData (what: any, data: {bufferList: CylinderBuffer[], helixbundleList: Helixbundle[], axisList: Axis[], axisData: AxisData}) {\n what = what || {}\n\n if (what.position) {\n this.build()\n return\n }\n\n var cylinderData = {}\n\n if (what.color || what.radius) {\n var offset = 0\n\n data.helixbundleList.forEach((helixbundle) => {\n var axis = helixbundle.getAxis(\n this.localAngle, this.centerDist, this.ssBorder,\n this.getColorParams(), this.getRadiusParams()\n )\n if (what.color) {\n data.axisData.color.set(axis.color, offset * 3)\n }\n if (what.radius || what.scale) {\n data.axisData.size.set(axis.size, offset)\n }\n offset += axis.size.length\n })\n\n if (what.color) {\n Object.assign(cylinderData, {\n color: data.axisData.color,\n color2: data.axisData.color\n })\n }\n\n if (what.radius || what.scale) {\n Object.assign(cylinderData, {\n radius: data.axisData.size\n })\n }\n }\n\n (data.bufferList[ 0 ] as CylinderGeometryBuffer).setAttributes(cylinderData)\n }\n}\n\nRepresentationRegistry.add('rocket', RocketRepresentation)\n\nexport default RocketRepresentation\n","/**\n * @file Rope Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport CartoonRepresentation, { CartoonRepresentationParameters } from './cartoon-representation'\nimport Helixorient from '../geometry/helixorient'\nimport Spline from '../geometry/spline'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport Polymer from '../proxy/polymer';\n\n/**\n * Rope Representation\n */\nclass RopeRepresentation extends CartoonRepresentation {\n protected smooth: number\n \n constructor (structure: Structure, viewer: Viewer, params: Partial&{smooth: number}) {\n super(structure, viewer, params)\n\n this.type = 'rope'\n\n this.parameters = Object.assign({\n\n smooth: {\n type: 'integer', max: 15, min: 0, rebuild: true\n }\n\n }, this.parameters, {\n aspectRatio: null,\n smoothSheet: null\n })\n }\n\n init (params: Partial) {\n var p = params || {}\n p.aspectRatio = 1.0\n p.tension = defaults(p.tension, 0.5)\n p.radiusScale = defaults(p.radiusScale, 5.0)\n p.smoothSheet = false\n\n this.smooth = defaults(p.smooth, 2)\n\n super.init(p)\n }\n\n getSpline (polymer: Polymer) {\n var helixorient = new Helixorient(polymer)\n\n return new Spline(polymer, this.getSplineParams({\n directional: false,\n positionIterator: helixorient.getCenterIterator(this.smooth)\n }))\n }\n}\n\nRepresentationRegistry.add('rope', RopeRepresentation)\n\nexport default RopeRepresentation\n","/**\n * @file Spacefill Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { defaults } from '../utils'\nimport { RepresentationRegistry } from '../globals'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport SphereBuffer, { SphereBufferData, SphereBufferParameters } from '../buffer/sphere-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport SphereGeometryBuffer from '../buffer/spheregeometry-buffer';\nimport { AtomDataFields } from '../structure/structure-data';\nimport SphereImpostorBuffer from '../buffer/sphereimpostor-buffer';\n\n/**\n * Spacefill Representation\n */\nclass SpacefillRepresentation extends StructureRepresentation {\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'spacefill'\n\n this.parameters = Object.assign({\n sphereDetail: true,\n disableImpostor: true\n }, this.parameters)\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n super.init(p)\n }\n\n createData (sview: StructureView) {\n var sphereBuffer = new SphereBuffer(\n (sview.getAtomData(this.getAtomParams()) as SphereBufferData),\n (this.getBufferParams({\n sphereDetail: this.sphereDetail,\n dullInterior: true,\n disableImpostor: this.disableImpostor\n }) as SphereBufferParameters)\n )\n\n return {\n bufferList: [ sphereBuffer as SphereGeometryBuffer|SphereImpostorBuffer ]\n }\n }\n\n updateData (what: AtomDataFields, data: StructureRepresentationData) {\n var atomData = data.sview!.getAtomData(this.getAtomParams(what))\n var sphereData: Partial = {}\n\n if (!what || what.position) {\n Object.assign(sphereData, {position: atomData.position})\n }\n\n if (!what || what.color) {\n Object.assign(sphereData, {color: atomData.color})\n }\n\n if (!what || what.radius) {\n Object.assign(sphereData, {radius: atomData.radius})\n }\n\n data.bufferList[ 0 ].setAttributes(sphereData)\n }\n}\n\nRepresentationRegistry.add('spacefill', SpacefillRepresentation)\n\nexport default SpacefillRepresentation\n","/**\n * @file Trace Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport '../shader/Line.vert'\nimport '../shader/Line.frag'\n\nimport { Log } from '../globals'\nimport Buffer, { BufferParameters, BufferData } from './buffer'\n\nfunction getSize(data: BufferData){\n const n = data.position!.length / 3\n const n1 = n - 1\n return n1 * 3 * 2\n}\n\n/**\n * Trace buffer. Draws a series of lines.\n */\nclass TraceBuffer extends Buffer {\n isLine = true\n vertexShader = 'Line.vert'\n fragmentShader = 'Line.frag'\n\n /**\n * @param {Object} data - attribute object\n * @param {Float32Array} data.position - positions\n * @param {Float32Array} data.color - colors\n * @param {BufferParameters} params - parameter object\n */\n constructor (data: BufferData, params: Partial = {}) {\n super({\n position: new Float32Array(getSize(data)),\n color: new Float32Array(getSize(data))\n }, params)\n\n this.setAttributes(data)\n }\n\n setAttributes (data: Partial) {\n let position, color\n let linePosition, lineColor\n\n const attributes = this.geometry.attributes as any // TODO\n\n if (data.position) {\n position = data.position\n linePosition = attributes.position.array\n attributes.position.needsUpdate = true\n }\n\n if (data.color) {\n color = data.color\n lineColor = attributes.color.array\n attributes.color.needsUpdate = true\n }\n\n if (!position && !color) {\n Log.warn('TraceBuffer.prototype.setAttributes no data')\n return\n }\n\n let v, v2\n const n = this.size\n const n1 = n - 1\n\n for (let i = 0; i < n1; ++i) {\n v = 3 * i\n v2 = 3 * i * 2\n\n if (position) {\n linePosition[ v2 ] = position[ v ]\n linePosition[ v2 + 1 ] = position[ v + 1 ]\n linePosition[ v2 + 2 ] = position[ v + 2 ]\n\n linePosition[ v2 + 3 ] = position[ v + 3 ]\n linePosition[ v2 + 4 ] = position[ v + 4 ]\n linePosition[ v2 + 5 ] = position[ v + 5 ]\n }\n\n if (color) {\n lineColor[ v2 ] = color[ v ]\n lineColor[ v2 + 1 ] = color[ v + 1 ]\n lineColor[ v2 + 2 ] = color[ v + 2 ]\n\n lineColor[ v2 + 3 ] = color[ v + 3 ]\n lineColor[ v2 + 4 ] = color[ v + 4 ]\n lineColor[ v2 + 5 ] = color[ v + 5 ]\n }\n }\n }\n}\n\nexport default TraceBuffer\n","/**\n * @file Trace Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport Spline from '../geometry/spline'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport TraceBuffer from '../buffer/trace-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport AtomProxy from '../proxy/atom-proxy';\nimport StructureView from '../structure/structure-view';\nimport Polymer from '../proxy/polymer';\n\nexport interface TraceRepresentationParameters extends StructureRepresentationParameters {\n subdiv: number\n tension: number\n smoothSheet: boolean\n}\n/**\n * Trace Representation\n */\nclass TraceRepresentation extends StructureRepresentation {\n protected subdiv: number\n protected tension: number\n protected smoothSheet: boolean\n \n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'trace'\n\n this.parameters = Object.assign({\n\n subdiv: {\n type: 'integer', max: 50, min: 1, rebuild: true\n },\n tension: {\n type: 'number', precision: 1, max: 1.0, min: 0.1\n },\n smoothSheet: {\n type: 'boolean', rebuild: true\n }\n\n }, this.parameters, {\n\n flatShaded: null,\n side: null,\n wireframe: null\n\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n var p = params || {}\n p.colorScheme = defaults(p.colorScheme, 'chainname')\n p.colorScale = defaults(p.colorScale, 'RdYlBu')\n\n if (p.quality === 'low') {\n this.subdiv = 3\n } else if (p.quality === 'medium') {\n this.subdiv = 6\n } else if (p.quality === 'high') {\n this.subdiv = 12\n } else {\n this.subdiv = defaults(p.subdiv, 6)\n }\n\n this.tension = defaults(p.tension, NaN)\n this.smoothSheet = defaults(p.smoothSheet, false)\n\n super.init(p)\n }\n\n getSplineParams (params?: {[k:string]: any}) {\n return Object.assign({\n subdiv: this.subdiv,\n tension: this.tension,\n directional: false,\n smoothSheet: this.smoothSheet\n }, params)\n }\n\n getAtomRadius (atom: AtomProxy) {\n return atom.isTrace() ? 0.1 : 0\n }\n\n createData (sview: StructureView) {\n var bufferList: TraceBuffer[] = []\n var polymerList: Polymer[] = []\n\n this.structure.eachPolymer(polymer => {\n if (polymer.residueCount < 4) return\n polymerList.push(polymer)\n\n var spline = new Spline(polymer, this.getSplineParams())\n var subPos = spline.getSubdividedPosition()\n var subCol = spline.getSubdividedColor(this.getColorParams())\n\n bufferList.push(\n new TraceBuffer(\n Object.assign({}, subPos, subCol),\n this.getBufferParams()\n )\n )\n }, sview.getSelection())\n\n return {\n bufferList: bufferList,\n polymerList: polymerList\n }\n }\n\n updateData (what: any, data: StructureRepresentationData) {\n what = what || {}\n\n var i = 0\n var n = data.polymerList!.length\n\n for (i = 0; i < n; ++i) {\n var bufferData = {}\n var spline = new Spline(data.polymerList![ i ], this.getSplineParams())\n\n if (what.position) {\n var subPos = spline.getSubdividedPosition()\n Object.assign(bufferData, { position: subPos.position })\n }\n\n if (what.color) {\n var subCol = spline.getSubdividedColor(this.getColorParams())\n Object.assign(bufferData, { color: subCol.color })\n }\n\n data.bufferList[ i ].setAttributes(bufferData)\n }\n }\n\n setParameters (params: Partial) {\n var rebuild = false\n var what = {}\n\n if (params && params.tension) {\n Object.assign(what, {position: true})\n }\n\n super.setParameters(params, what, rebuild)\n\n return this\n }\n}\n\nRepresentationRegistry.add('trace', TraceRepresentation)\n\nexport default TraceRepresentation\n","/**\n * @file Tube Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport CartoonRepresentation, {CartoonRepresentationParameters} from './cartoon-representation'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\n\n/**\n * Tube Representation\n */\nclass TubeRepresentation extends CartoonRepresentation {\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'tube'\n\n this.parameters = Object.assign(\n {}, this.parameters, { aspectRatio: null }\n )\n }\n\n init (params: Partial) {\n var p = params || {}\n p.aspectRatio = 1.0\n p.radiusScale = defaults(p.radiusScale, 2.0)\n\n if (p.quality === 'low') {\n this.radialSegments = 5\n }\n\n super.init(p)\n }\n\n getSplineParams (/* params */) {\n return super.getSplineParams({\n directional: false\n })\n }\n}\n\nRepresentationRegistry.add('tube', TubeRepresentation)\n\nexport default TubeRepresentation\n","/**\n * @file Unitcell Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport StructureRepresentation, { StructureRepresentationParameters, StructureRepresentationData } from './structure-representation'\nimport SphereBuffer, { SphereBufferData, SphereBufferParameters } from '../buffer/sphere-buffer'\nimport CylinderBuffer, { CylinderBufferData } from '../buffer/cylinder-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport { AtomDataFields } from '../structure/structure-data';\nimport StructureView from '../structure/structure-view';\nimport SphereGeometryBuffer from '../buffer/spheregeometry-buffer';\nimport CylinderGeometryBuffer from '../buffer/cylindergeometry-buffer';\n// @ts-ignore: unused import UnitcellPicker required for declaration only\nimport { UnitcellPicker } from '../utils/picker';\n\nexport interface UnitcellRepresentationParameters extends StructureRepresentationParameters {\n radiusSize: number\n sphereDetail: number\n radialSegments: number\n disableImpostor: boolean\n}\n\n/**\n * Unitcell Representation\n */\nclass UnitcellRepresentation extends StructureRepresentation {\n sphereBuffer: SphereBuffer\n cylinderBuffer: CylinderBuffer\n\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'unitcell'\n\n this.parameters = Object.assign({\n\n radiusSize: {\n type: 'number', precision: 3, max: 10.0, min: 0.001\n },\n sphereDetail: true,\n radialSegments: true,\n disableImpostor: true\n\n }, this.parameters, {\n assembly: null\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n\n let defaultRadius = 0.5\n if (this.structure.unitcell) {\n defaultRadius = Math.cbrt(this.structure.unitcell.volume) / 200\n }\n\n p.radiusSize = defaults(p.radiusSize, defaultRadius)\n p.colorValue = defaults(p.colorValue, 'orange')\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n super.init(p)\n }\n\n getUnitcellData (structure: Structure) {\n return structure.unitcell!.getData(structure)\n }\n\n create () {\n const structure = this.structureView.getStructure()\n if (!structure.unitcell) return\n const unitcellData = this.getUnitcellData(structure)\n\n this.sphereBuffer = new SphereBuffer(\n unitcellData.vertex as SphereBufferData,\n this.getBufferParams({\n sphereDetail: this.sphereDetail,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n }) as SphereBufferParameters\n )\n\n this.cylinderBuffer = new CylinderBuffer(\n unitcellData.edge as CylinderBufferData,\n this.getBufferParams({\n openEnded: true,\n radialSegments: this.radialSegments,\n disableImpostor: this.disableImpostor,\n dullInterior: true\n })\n )\n\n this.dataList.push({\n sview: this.structureView,\n bufferList: [ this.sphereBuffer as SphereGeometryBuffer, this.cylinderBuffer as CylinderGeometryBuffer ]\n })\n }\n\n createData (sview: StructureView): undefined {\n return\n }\n\n updateData (what: AtomDataFields, data: StructureRepresentationData) {\n const structure = data.sview!.getStructure()\n if (!structure.unitcell) return\n const unitcellData = this.getUnitcellData(structure)\n const sphereData: Partial = {}\n const cylinderData: Partial = {}\n\n if (!what || what.position) {\n Object.assign(sphereData, {position: unitcellData.vertex.position})\n Object.assign(cylinderData, {\n position1: unitcellData.edge.position1,\n position2: unitcellData.edge.position2\n })\n }\n\n if (!what || what.color) {\n Object.assign(sphereData, {color: unitcellData.vertex.color})\n Object.assign(cylinderData, {\n color: unitcellData.edge.color,\n color2: unitcellData.edge.color2\n })\n }\n\n if (!what || what.radius) {\n Object.assign(sphereData, {radius: unitcellData.vertex.radius})\n Object.assign(cylinderData, {radius: unitcellData.edge.radius})\n }\n\n (this.sphereBuffer as SphereGeometryBuffer).setAttributes(sphereData);\n (this.cylinderBuffer as CylinderGeometryBuffer).setAttributes(cylinderData)\n }\n}\n\nRepresentationRegistry.add('unitcell', UnitcellRepresentation)\n\nexport default UnitcellRepresentation\n","/**\n * @file Validation Representation\n * @author Alexander Rose \n * @private\n */\n\nimport { RepresentationRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport StructureRepresentation, { StructureRepresentationParameters } from './structure-representation'\nimport CylinderBuffer from '../buffer/cylinder-buffer'\nimport { Structure } from '../ngl';\nimport Viewer from '../viewer/viewer';\nimport StructureView from '../structure/structure-view';\nimport CylinderGeometryBuffer from '../buffer/cylindergeometry-buffer';\nimport CylinderImpostorBuffer from '../buffer/cylinderimpostor-buffer';\n\n/**\n * Validation representation\n */\nclass ValidationRepresentation extends StructureRepresentation {\n constructor (structure: Structure, viewer: Viewer, params: Partial) {\n super(structure, viewer, params)\n\n this.type = 'validation'\n\n this.parameters = Object.assign({\n\n }, this.parameters, {\n radiusType: null,\n radiusSize: null,\n radiusScale: null\n })\n\n this.init(params)\n }\n\n init (params: Partial) {\n const p = params || {}\n p.colorValue = defaults(p.colorValue, '#f0027f')\n p.useInteriorColor = defaults(p.useInteriorColor, true)\n\n super.init(p)\n }\n\n createData (sview: StructureView) {\n if (!sview.validation) return\n\n const clashData = sview.validation.getClashData({\n structure: sview,\n color: this.colorValue\n })\n\n const cylinderBuffer = new CylinderBuffer(\n clashData, this.getBufferParams({ openEnded: false })\n )\n\n return {\n bufferList: [ cylinderBuffer as CylinderGeometryBuffer|CylinderImpostorBuffer ]\n }\n }\n}\n\nRepresentationRegistry.add('validation', ValidationRepresentation)\n\nexport default ValidationRepresentation\n","/**\n * @file Cone Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4, Vector3, ConeGeometry } from 'three'\n\nimport { BufferRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport { calculateCenterArray } from '../math/array-utils'\nimport GeometryBuffer from './geometry-buffer'\nimport { BufferData, BufferDefaultParameters } from './buffer'\n\nconst scale = new Vector3()\nconst eye = new Vector3()\nconst target = new Vector3()\nconst up = new Vector3(0, 1, 0)\n\nfunction getGeo (params: Partial = {}) {\n const geo = new ConeGeometry(\n 1, // radius\n 1, // height\n defaults(params.radialSegments, 60), // radialSegments\n 1, // heightSegments\n defaults(params.openEnded, false) // openEnded\n )\n geo.applyMatrix4(new Matrix4().makeRotationX(-Math.PI / 2))\n\n return geo\n}\n\nexport interface ConeBufferData extends BufferData {\n position1: Float32Array\n position2: Float32Array\n radius: Float32Array\n}\n\nexport const ConeBufferDefaultParameters = Object.assign({\n radialSegments: 60,\n openEnded: false\n}, BufferDefaultParameters)\nexport type ConeBufferParameters = typeof ConeBufferDefaultParameters\n\n\n/**\n * Cone geometry buffer.\n *\n * @example\n * var coneBuffer = new ConeBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 1, 1, 1 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * color2: new Float32Array([ 0, 1, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n */\nclass ConeBuffer extends GeometryBuffer {\n updateNormals = true\n\n get defaultParameters() { return ConeBufferDefaultParameters }\n parameters: ConeBufferParameters\n\n _position: Float32Array\n _position1: Float32Array\n _position2: Float32Array\n _radius: Float32Array\n\n /**\n * @param {Object} data - buffer data\n * @param {Float32Array} data.position1 - from positions\n * @param {Float32Array} data.position2 - to positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} [params] - parameters object\n */\n constructor (data: ConeBufferData, params: Partial = {}) {\n super({\n position: new Float32Array(data.position1.length),\n color: data.color,\n picking: data.picking\n }, params, getGeo(params))\n\n this._position = new Float32Array(data.position1.length)\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number, i3: number) {\n eye.fromArray(this._position1 as any, i3)\n target.fromArray(this._position2 as any, i3)\n matrix.lookAt(eye, target, up)\n\n const r = this._radius[ i ]\n scale.set(r, r, eye.distanceTo(target))\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n if (data.position1 && data.position2) {\n calculateCenterArray(data.position1, data.position2, this._position)\n this._position1 = data.position1\n this._position2 = data.position2\n data.position = this._position\n }\n if (data.radius) this._radius = data.radius\n\n super.setAttributes(data, initNormals)\n }\n}\n\nBufferRegistry.add('cone', ConeBuffer)\n\nexport default ConeBuffer\n","/**\n * @file Geometry Group\n * @author Alexander Rose \n * @private\n */\n\nimport { Box3, BufferGeometry } from 'three'\n\nclass GeometryGroup {\n geometryList: BufferGeometry[]\n boundingBox: Box3\n\n constructor (geometryList: BufferGeometry[] = []) {\n this.geometryList = geometryList\n }\n\n computeBoundingBox () {\n if (!this.boundingBox) {\n this.boundingBox = new Box3()\n } else {\n this.boundingBox.empty()\n }\n\n this.geometryList.forEach(geo => {\n if (!geo.boundingBox) geo.computeBoundingBox()\n this.boundingBox.union(geo.boundingBox as Box3)\n })\n }\n}\n\nexport default GeometryGroup\n","/**\n * @file Arrow Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { Matrix4, Vector3, Group } from 'three'\n\nimport { BufferRegistry } from '../globals'\nimport { createParams, defaults } from '../utils'\nimport { Picker } from '../utils/picker'\nimport Buffer from './buffer'\nimport CylinderBuffer, { CylinderBufferData } from './cylinder-buffer'\nimport CylinderGeometryBuffer from './cylindergeometry-buffer'\nimport ConeBuffer, { ConeBufferData } from './cone-buffer'\nimport GeometryGroup from '../viewer/geometry-group'\nimport { BufferData, BufferDefaultParameters } from './buffer'\n\nexport interface ArrowBufferData extends BufferData {\n position1: Float32Array\n position2: Float32Array\n radius: Float32Array\n}\n\nexport const ArrowBufferDefaultParameters = Object.assign({\n aspectRatio: 1.5,\n radialSegments: 50,\n openEnded: false,\n disableImpostor: false\n}, BufferDefaultParameters)\nexport type ArrowBufferParameters = typeof ArrowBufferDefaultParameters\n\n/**\n * Arrow buffer. Draws arrows made from a cylinder and a cone.\n * @implements {Buffer}\n *\n * @example\n * var arrowBuffer = new ArrowBuffer({\n * position1: new Float32Array([ 0, 0, 0 ]),\n * position2: new Float32Array([ 10, 1, 1 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * radius: new Float32Array([ 1 ])\n * });\n */\nclass ArrowBuffer {\n parameters: ArrowBufferParameters\n get defaultParameters() { return ArrowBufferDefaultParameters }\n\n cylinderBuffer: CylinderGeometryBuffer\n coneBuffer: ConeBuffer\n\n splitPosition: Float32Array\n cylinderRadius: Float32Array\n\n geometry: GeometryGroup\n picking?: Picker\n\n group = new Group()\n wireframeGroup = new Group()\n pickingGroup = new Group()\n\n visible = true\n\n /**\n * @param {Object} data - buffer data\n * @param {Float32Array} data.position1 - from positions\n * @param {Float32Array} data.position2 - to positions\n * @param {Float32Array} data.color - colors\n * @param {Float32Array} data.radius - radii\n * @param {Picker} [data.picking] - picking ids\n * @param {BufferParameters} [params] - parameters object\n */\n constructor (data: ArrowBufferData, params: Partial = {}) {\n this.parameters = createParams(params, this.defaultParameters)\n\n this.splitPosition = new Float32Array(data.position1.length)\n this.cylinderRadius = new Float32Array(data.radius.length)\n\n const attr = this.makeAttributes(data)\n const bufferParams = {\n radialSegments: this.parameters.radialSegments,\n openEnded: this.parameters.openEnded,\n disableImpostor: this.parameters.disableImpostor\n }\n\n this.cylinderBuffer = new CylinderBuffer(\n attr.cylinder as CylinderBufferData, bufferParams\n ) as CylinderGeometryBuffer\n this.coneBuffer = new ConeBuffer(\n attr.cone as ConeBufferData, bufferParams\n )\n\n this.geometry = new GeometryGroup([\n this.cylinderBuffer.geometry,\n this.coneBuffer.geometry\n ])\n\n // requires Group objects to be present\n this.matrix = defaults(params.matrix, new Matrix4())\n\n this.picking = data.picking\n }\n\n set matrix (m) {\n Buffer.prototype.setMatrix.call(this, m)\n }\n get matrix () {\n return this.group.matrix.clone()\n }\n\n get pickable () {\n return !!this.picking\n }\n\n makeAttributes (data: Partial = {}) {\n const splitPosition = this.splitPosition\n const cylinderRadius = this.cylinderRadius\n\n const aspectRatio = this.parameters.aspectRatio\n\n let i, il\n const cylinder: Partial = {}\n const cone: Partial = {}\n\n if (data.radius) {\n for (i = 0, il = cylinderRadius.length; i < il; ++i) {\n cylinderRadius[ i ] = data.radius[ i ] / aspectRatio\n }\n cylinder.radius = cylinderRadius\n cone.radius = data.radius\n }\n\n if (data.position1 && data.position2) {\n const vFrom = new Vector3()\n const vTo = new Vector3()\n const vDir = new Vector3()\n const vSplit = new Vector3()\n for (i = 0, il = splitPosition.length; i < il; i += 3) {\n vFrom.fromArray(data.position1 as any, i)\n vTo.fromArray(data.position2 as any, i)\n vDir.subVectors(vFrom, vTo)\n const fullLength = vDir.length()\n const coneLength = cylinderRadius[ i / 3 ] * aspectRatio * 2\n const length = Math.min(fullLength, coneLength)\n vDir.setLength(length)\n vSplit.copy(vTo).add(vDir)\n vSplit.toArray(splitPosition as any, i)\n }\n cylinder.position1 = data.position1\n cylinder.position2 = splitPosition\n cone.position1 = splitPosition\n cone.position2 = data.position2\n }\n\n if (data.color) {\n cylinder.color = data.color\n cylinder.color2 = data.color\n cone.color = data.color\n }\n\n return {\n cylinder: cylinder,\n cone: cone\n }\n }\n\n getMesh () {\n return new Group().add(\n this.cylinderBuffer.getMesh(),\n this.coneBuffer.getMesh()\n )\n }\n\n getWireframeMesh () {\n return new Group().add(\n this.cylinderBuffer.getWireframeMesh(),\n this.coneBuffer.getWireframeMesh()\n )\n }\n\n getPickingMesh () {\n return new Group().add(\n this.cylinderBuffer.getPickingMesh(),\n this.coneBuffer.getPickingMesh()\n )\n }\n\n setAttributes (data: Partial = {}) {\n const attr = this.makeAttributes(data)\n\n this.cylinderBuffer.setAttributes(attr.cylinder)\n this.coneBuffer.setAttributes(attr.cone)\n }\n\n /**\n * Set buffer parameters\n * @param {BufferParameters} params - buffer parameters object\n * @return {undefined}\n */\n setParameters (params: Partial = {}) {\n params = Object.assign({}, params)\n\n if (params && params.matrix !== undefined) {\n this.matrix = params.matrix\n }\n delete params.matrix\n\n if (params && params.wireframe !== undefined) {\n this.parameters.wireframe = params.wireframe\n this.setVisibility(this.visible)\n }\n\n this.cylinderBuffer.setParameters(params)\n this.coneBuffer.setParameters(params)\n }\n\n setVisibility (value: boolean) {\n Buffer.prototype.setVisibility.call(this, value)\n }\n\n dispose () {\n this.cylinderBuffer.dispose()\n this.coneBuffer.dispose()\n }\n}\n\nBufferRegistry.add('arrow', ArrowBuffer)\n\nexport default ArrowBuffer\n","/**\n * @file Box Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { BoxGeometry, Vector3, Matrix4 } from 'three'\n\nimport { BufferRegistry } from '../globals'\nimport GeometryBuffer from './geometry-buffer'\nimport { BufferData, BufferParameters } from './buffer'\n\nconst scale = new Vector3()\nconst target = new Vector3()\nconst up = new Vector3()\nconst eye = new Vector3(0, 0, 0)\n\nexport interface BoxBufferData extends BufferData {\n heightAxis: Float32Array\n depthAxis: Float32Array\n size: Float32Array\n}\n\n/**\n * Box buffer. Draws boxes.\n *\n * @example\n * var boxBuffer = new BoxBuffer({\n * position: new Float32Array([ 0, 3, 0, -2, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 1, 0, 1, 0 ]),\n * size: new Float32Array([ 2, 1.5 ]),\n * heightAxis: new Float32Array([ 0, 1, 1, 0, 2, 0 ]),\n * depthAxis: new Float32Array([ 1, 0, 1, 0, 0, 2 ])\n * })\n */\nclass BoxBuffer extends GeometryBuffer {\n updateNormals = true\n\n _heightAxis: Float32Array\n _depthAxis: Float32Array\n _size: Float32Array\n\n constructor (data: BoxBufferData, params: Partial = {}) {\n super(data, params, new BoxGeometry(1, 1, 1))\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number, i3: number) {\n target.fromArray(this._heightAxis as any, i3)\n up.fromArray(this._depthAxis as any, i3)\n matrix.lookAt(eye, target, up)\n\n scale.set(this._size[ i ], up.length(), target.length())\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n if (data.size) this._size = data.size\n if (data.heightAxis) this._heightAxis = data.heightAxis\n if (data.depthAxis) this._depthAxis = data.depthAxis\n\n super.setAttributes(data, initNormals)\n }\n}\n\nBufferRegistry.add('box', BoxBuffer)\n\nexport default BoxBuffer\n","/**\n * @file Ellipsoid Geometry Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { IcosahedronGeometry, Vector3, Matrix4 } from 'three'\n\nimport { BufferRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport GeometryBuffer from './geometry-buffer'\nimport { BufferData, BufferDefaultParameters } from './buffer'\n\nconst scale = new Vector3()\nconst target = new Vector3()\nconst up = new Vector3()\nconst eye = new Vector3(0, 0, 0)\n\nexport interface EllipsoidBufferData extends BufferData {\n majorAxis: Float32Array\n minorAxis: Float32Array\n radius: Float32Array\n}\n\nexport const EllipsoidBufferDefaultParameters = Object.assign({\n sphereDetail: 2,\n}, BufferDefaultParameters)\nexport type EllipsoidBufferParameters = typeof EllipsoidBufferDefaultParameters\n\n/**\n * Ellipsoid buffer. Draws ellipsoids.\n *\n * @example\n * var ellipsoidBuffer = new EllipsoidBuffer({\n * position: new Float32Array([ 0, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * radius: new Float32Array([ 1 ]),\n * majorAxis: new Float32Array([ 1, 1, 0 ]),\n * minorAxis: new Float32Array([ 0.5, 0, 0.5 ]),\n * });\n */\nclass EllipsoidBuffer extends GeometryBuffer {\n updateNormals = true\n\n get defaultParameters() { return EllipsoidBufferDefaultParameters }\n parameters: EllipsoidBufferParameters\n\n _majorAxis: Float32Array\n _minorAxis: Float32Array\n _radius: Float32Array\n\n constructor (data: EllipsoidBufferData, params: Partial = {}) {\n super(data, params, new IcosahedronGeometry(1, defaults(params.sphereDetail, 2)))\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number, i3: number) {\n target.fromArray(this._majorAxis as any, i3)\n up.fromArray(this._minorAxis as any, i3)\n matrix.lookAt(eye, target, up)\n\n scale.set(this._radius[ i ], up.length(), target.length())\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n if (data.radius) this._radius = data.radius\n if (data.majorAxis) this._majorAxis = data.majorAxis\n if (data.minorAxis) this._minorAxis = data.minorAxis\n\n super.setAttributes(data, initNormals)\n }\n}\n\nBufferRegistry.add('ellipsoid', EllipsoidBuffer)\n\nexport default EllipsoidBuffer\n","/**\n * @file Octahedron Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { OctahedronGeometry, Vector3, Matrix4 } from 'three'\nimport { BufferRegistry } from '../globals'\nimport GeometryBuffer from './geometry-buffer'\nimport { BufferData, BufferParameters } from './buffer'\n\nconst scale = new Vector3()\nconst target = new Vector3()\nconst up = new Vector3()\nconst eye = new Vector3(0, 0, 0)\n\nexport interface OctahedronBufferData extends BufferData {\n heightAxis: Float32Array\n depthAxis: Float32Array\n size: Float32Array\n}\n\n/**\n * Octahedron buffer. Draws octahedrons.\n *\n * @example\n * var octahedronBuffer = new OctahedronBuffer({\n * position: new Float32Array([ 0, 3, 0, -2, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 1, 0, 1, 0 ]),\n * size: new Float32Array([ 2, 1.5 ]),\n * heightAxis: new Float32Array([ 0, 1, 1, 0, 2, 0 ]),\n * depthAxis: new Float32Array([ 1, 0, 1, 0, 0, 2 ])\n * })\n */\nclass OctahedronBuffer extends GeometryBuffer {\n updateNormals = true\n\n _heightAxis: Float32Array\n _depthAxis: Float32Array\n _size: Float32Array\n\n constructor (data: OctahedronBufferData, params: Partial = {}) {\n super(data, params, new OctahedronGeometry(1, 0))\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number, i3: number) {\n target.fromArray(this._heightAxis as any, i3)\n up.fromArray(this._depthAxis as any, i3)\n matrix.lookAt(eye, target, up)\n\n scale.set(this._size[ i ], up.length(), target.length())\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n if (data.size) this._size = data.size\n if (data.heightAxis) this._heightAxis = data.heightAxis\n if (data.depthAxis) this._depthAxis = data.depthAxis\n\n super.setAttributes(data, initNormals)\n }\n}\n\nBufferRegistry.add('octahedron', OctahedronBuffer)\n\nexport default OctahedronBuffer\n","/**\n * @file Tetrahedron Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { TetrahedronGeometry, Vector3, Matrix4 } from 'three'\nimport { BufferRegistry } from '../globals'\nimport GeometryBuffer from './geometry-buffer'\nimport { BufferData, BufferParameters } from './buffer'\n\nconst scale = new Vector3()\nconst target = new Vector3()\nconst up = new Vector3()\nconst eye = new Vector3(0, 0, 0)\n\nexport interface TetrahedronBufferData extends BufferData {\n heightAxis: Float32Array\n depthAxis: Float32Array\n size: Float32Array\n}\n\n/**\n * Tetrahedron buffer. Draws tetrahedrons.\n *\n * @example\n * var tetrahedronBuffer = new TetrahedronBuffer({\n * position: new Float32Array([ 0, 3, 0, -2, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 1, 0, 1, 0 ]),\n * size: new Float32Array([ 2, 1.5 ]),\n * heightAxis: new Float32Array([ 0, 1, 1, 0, 2, 0 ]),\n * depthAxis: new Float32Array([ 1, 0, 1, 0, 0, 2 ])\n * })\n */\nclass TetrahedronBuffer extends GeometryBuffer {\n updateNormals = true\n\n _heightAxis: Float32Array\n _depthAxis: Float32Array\n _size: Float32Array\n\n constructor (data: TetrahedronBufferData, params: Partial = {}) {\n super(data, params, new TetrahedronGeometry(1, 0))\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number, i3: number) {\n target.fromArray(this._heightAxis as any, i3)\n up.fromArray(this._depthAxis as any, i3)\n matrix.lookAt(eye, target, up)\n\n scale.set(this._size[ i ], up.length(), target.length())\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n if (data.size) this._size = data.size\n if (data.heightAxis) this._heightAxis = data.heightAxis\n if (data.depthAxis) this._depthAxis = data.depthAxis\n\n super.setAttributes(data, initNormals)\n }\n}\n\nBufferRegistry.add('tetrahedron', TetrahedronBuffer)\n\nexport default TetrahedronBuffer\n","/**\n * @file Tetrahedron Geometry Buffer\n * @author Alexander Rose \n * @private\n */\n\nimport { TorusGeometry, Vector3, Matrix4 } from 'three'\n\nimport { BufferRegistry } from '../globals'\nimport { defaults } from '../utils'\nimport GeometryBuffer from './geometry-buffer'\nimport { BufferDefaultParameters, BufferData } from './buffer'\n\nconst scale = new Vector3()\nconst target = new Vector3()\nconst up = new Vector3()\nconst eye = new Vector3(0, 0, 0)\n\nexport interface TorusBufferData extends BufferData {\n majorAxis: Float32Array\n minorAxis: Float32Array\n radius: Float32Array\n}\n\nexport const TorusBufferDefaultParameters = Object.assign({\n radiusRatio: 0.2,\n radialSegments: 16,\n tubularSegments: 32\n}, BufferDefaultParameters)\nexport type TorusBufferParameters = typeof TorusBufferDefaultParameters\n\n/**\n * Torus geometry buffer. Draws torii.\n *\n * @example\n * var torusBuffer = new TorusBuffer({\n * position: new Float32Array([ 0, 0, 0 ]),\n * color: new Float32Array([ 1, 0, 0 ]),\n * radius: new Float32Array([ 1 ]),\n * majorAxis: new Float32Array([ 1, 1, 0 ]),\n * minorAxis: new Float32Array([ 0.5, 0, 0.5 ]),\n * });\n */\nclass TorusBuffer extends GeometryBuffer {\n updateNormals = true\n\n get defaultParameters() { return TorusBufferDefaultParameters }\n parameters: TorusBufferParameters\n\n _majorAxis: Float32Array\n _minorAxis: Float32Array\n _radius: Float32Array\n\n constructor (data: TorusBufferData, params: Partial = {}) {\n super(data, params, new TorusGeometry(\n 1,\n defaults(params.radiusRatio, 0.2),\n defaults(params.radialSegments, 16),\n defaults(params.tubularSegments, 32)\n ))\n\n this.setAttributes(data, true)\n }\n\n applyPositionTransform (matrix: Matrix4, i: number, i3: number) {\n target.fromArray(this._majorAxis as any, i3)\n up.fromArray(this._minorAxis as any, i3)\n matrix.lookAt(eye, target, up)\n\n const r = this._radius[ i ]\n scale.set(r, r, r)\n matrix.scale(scale)\n }\n\n setAttributes (data: Partial = {}, initNormals?: boolean) {\n if (data.radius) this._radius = data.radius\n if (data.majorAxis) this._majorAxis = data.majorAxis\n if (data.minorAxis) this._minorAxis = data.minorAxis\n\n super.setAttributes(data, initNormals)\n }\n}\n\nBufferRegistry.add('torus', TorusBuffer)\n\nexport default TorusBuffer\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nexport function getArrayBounds(rowCount, params) {\n const start = params && typeof params.start !== 'undefined' ? Math.max(Math.min(params.start, rowCount - 1), 0) : 0;\n const end = params && typeof params.end !== 'undefined' ? Math.min(params.end, rowCount) : rowCount;\n return { start, end };\n}\nexport function createArray(rowCount, params) {\n const c = params && typeof params.array !== 'undefined' ? params.array : Array;\n const { start, end } = getArrayBounds(rowCount, params);\n return { array: new c(end - start), start, end };\n}\nexport function fillArrayValues(value, target, start) {\n for (let i = 0, _e = target.length; i < _e; i++)\n target[i] = value(start + i);\n return target;\n}\nexport function createAndFillArray(rowCount, value, params) {\n const { array, start } = createArray(rowCount, params);\n return fillArrayValues(value, array, start);\n}\nexport function isTypedArray(data) {\n return !!data.buffer && typeof data.byteLength === 'number' && typeof data.BYTES_PER_ELEMENT === 'number';\n}\nexport function typedArrayWindow(data, params) {\n const { constructor, buffer, length, byteOffset, BYTES_PER_ELEMENT } = data;\n const { start, end } = getArrayBounds(length, params);\n if (start === 0 && end === length)\n return data;\n return new constructor(buffer, byteOffset + BYTES_PER_ELEMENT * start, Math.min(length, end - start));\n}\n","/**\n * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\n/*\n * This code has been modified from https://github.com/toji/gl-matrix/,\n * copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n */\nexport const EPSILON = 0.000001;\nexport function equalEps(a, b, eps) {\n return Math.abs(a - b) <= eps;\n}\n","/**\n * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author Alexander Rose \n */\nexport function normalize(value, min, max) {\n return (value - min) / (max - min);\n}\nexport function clamp(value, min, max) {\n return Math.max(min, Math.min(max, value));\n}\nexport function pclamp(value) {\n return clamp(value, 0, 100);\n}\nexport function saturate(value) {\n return clamp(value, 0, 1);\n}\nexport function damp(value, dampingFactor) {\n const dampedValue = value * dampingFactor;\n return Math.abs(dampedValue) < 0.1 ? 0 : dampedValue;\n}\nexport function lerp(start, stop, alpha) {\n return start + (stop - start) * alpha;\n}\n/** Catmul-Rom spline */\nexport function spline(p0, p1, p2, p3, t, tension) {\n const v0 = (p2 - p0) * tension;\n const v1 = (p3 - p1) * tension;\n const t2 = t * t;\n const t3 = t * t2;\n return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;\n}\nexport function quadraticBezier(p0, p1, p2, t) {\n const k = 1 - t;\n return (k * k * p0) + (2 * k * t * p1) + (t * t * p2);\n}\nexport function smoothstep(min, max, x) {\n x = saturate(normalize(x, min, max));\n return x * x * (3 - 2 * x);\n}\nexport function smootherstep(min, max, x) {\n x = saturate(normalize(x, min, max));\n return x * x * x * (x * (x * 6 - 15) + 10);\n}\nexport function smootheststep(min, max, x) {\n x = saturate(normalize(x, min, max));\n return -20 * Math.pow(x, 7) + 70 * Math.pow(x, 6) - 84 * Math.pow(x, 5) + 35 * Math.pow(x, 4);\n}\nexport function almostIdentity(value, start, stop) {\n if (value > start)\n return value;\n const a = 2 * stop - start;\n const b = 2 * start - 3 * stop;\n const t = value / start;\n return (a * t + b) * t * t + stop;\n}\n","/**\n * Copyright (c) 2017-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\n/*\n * This code has been modified from https://github.com/toji/gl-matrix/,\n * copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n */\nimport { Mat4 } from './mat4';\nimport { spline as _spline, quadraticBezier as _quadraticBezier, clamp as _clamp } from '../../interpolate';\nimport { EPSILON } from './common';\nconst _isFinite = isFinite;\nfunction Vec3() {\n return Vec3.zero();\n}\n(function (Vec3) {\n function zero() {\n const out = [0.1, 0.0, 0.0]; // ensure backing array of type double\n out[0] = 0;\n return out;\n }\n Vec3.zero = zero;\n function clone(a) {\n const out = zero();\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n return out;\n }\n Vec3.clone = clone;\n function isFinite(a) {\n return _isFinite(a[0]) && _isFinite(a[1]) && _isFinite(a[2]);\n }\n Vec3.isFinite = isFinite;\n function hasNaN(a) {\n return isNaN(a[0]) || isNaN(a[1]) || isNaN(a[2]);\n }\n Vec3.hasNaN = hasNaN;\n function setNaN(out) {\n out[0] = NaN;\n out[1] = NaN;\n out[2] = NaN;\n return out;\n }\n Vec3.setNaN = setNaN;\n function fromObj(v) {\n return create(v.x, v.y, v.z);\n }\n Vec3.fromObj = fromObj;\n function toObj(v) {\n return { x: v[0], y: v[1], z: v[2] };\n }\n Vec3.toObj = toObj;\n function fromArray(v, array, offset) {\n v[0] = array[offset + 0];\n v[1] = array[offset + 1];\n v[2] = array[offset + 2];\n return v;\n }\n Vec3.fromArray = fromArray;\n function toArray(v, out, offset) {\n out[offset + 0] = v[0];\n out[offset + 1] = v[1];\n out[offset + 2] = v[2];\n return out;\n }\n Vec3.toArray = toArray;\n function create(x, y, z) {\n const out = zero();\n out[0] = x;\n out[1] = y;\n out[2] = z;\n return out;\n }\n Vec3.create = create;\n function ofArray(array) {\n const out = zero();\n out[0] = array[0];\n out[1] = array[1];\n out[2] = array[2];\n return out;\n }\n Vec3.ofArray = ofArray;\n function set(out, x, y, z) {\n out[0] = x;\n out[1] = y;\n out[2] = z;\n return out;\n }\n Vec3.set = set;\n function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n return out;\n }\n Vec3.copy = copy;\n function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n return out;\n }\n Vec3.add = add;\n function sub(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n return out;\n }\n Vec3.sub = sub;\n function mul(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n out[2] = a[2] * b[2];\n return out;\n }\n Vec3.mul = mul;\n function div(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n out[2] = a[2] / b[2];\n return out;\n }\n Vec3.div = div;\n function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n return out;\n }\n Vec3.scale = scale;\n /** Scales b, then adds a and b together */\n function scaleAndAdd(out, a, b, scale) {\n out[0] = a[0] + (b[0] * scale);\n out[1] = a[1] + (b[1] * scale);\n out[2] = a[2] + (b[2] * scale);\n return out;\n }\n Vec3.scaleAndAdd = scaleAndAdd;\n /** Scales b, then subtracts b from a */\n function scaleAndSub(out, a, b, scale) {\n out[0] = a[0] - (b[0] * scale);\n out[1] = a[1] - (b[1] * scale);\n out[2] = a[2] - (b[2] * scale);\n return out;\n }\n Vec3.scaleAndSub = scaleAndSub;\n function addScalar(out, a, b) {\n out[0] = a[0] + b;\n out[1] = a[1] + b;\n out[2] = a[2] + b;\n return out;\n }\n Vec3.addScalar = addScalar;\n function subScalar(out, a, b) {\n out[0] = a[0] - b;\n out[1] = a[1] - b;\n out[2] = a[2] - b;\n return out;\n }\n Vec3.subScalar = subScalar;\n /**\n * Math.round the components of a Vec3\n */\n function round(out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n out[2] = Math.round(a[2]);\n return out;\n }\n Vec3.round = round;\n /**\n * Math.ceil the components of a Vec3\n */\n function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n out[2] = Math.ceil(a[2]);\n return out;\n }\n Vec3.ceil = ceil;\n /**\n * Math.floor the components of a Vec3\n */\n function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n out[2] = Math.floor(a[2]);\n return out;\n }\n Vec3.floor = floor;\n /**\n * Math.trunc the components of a Vec3\n */\n function trunc(out, a) {\n out[0] = Math.trunc(a[0]);\n out[1] = Math.trunc(a[1]);\n out[2] = Math.trunc(a[2]);\n return out;\n }\n Vec3.trunc = trunc;\n /**\n * Math.abs the components of a Vec3\n */\n function abs(out, a) {\n out[0] = Math.abs(a[0]);\n out[1] = Math.abs(a[1]);\n out[2] = Math.abs(a[2]);\n return out;\n }\n Vec3.abs = abs;\n /**\n * Returns the minimum of two Vec3's\n */\n function min(out, a, b) {\n out[0] = Math.min(a[0], b[0]);\n out[1] = Math.min(a[1], b[1]);\n out[2] = Math.min(a[2], b[2]);\n return out;\n }\n Vec3.min = min;\n /**\n * Returns the maximum of two Vec3's\n */\n function max(out, a, b) {\n out[0] = Math.max(a[0], b[0]);\n out[1] = Math.max(a[1], b[1]);\n out[2] = Math.max(a[2], b[2]);\n return out;\n }\n Vec3.max = max;\n /**\n * Assumes min < max, componentwise\n */\n function clamp(out, a, min, max) {\n out[0] = Math.max(min[0], Math.min(max[0], a[0]));\n out[1] = Math.max(min[1], Math.min(max[1], a[1]));\n out[2] = Math.max(min[2], Math.min(max[2], a[2]));\n return out;\n }\n Vec3.clamp = clamp;\n function distance(a, b) {\n const x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2];\n return Math.sqrt(x * x + y * y + z * z);\n }\n Vec3.distance = distance;\n function squaredDistance(a, b) {\n const x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2];\n return x * x + y * y + z * z;\n }\n Vec3.squaredDistance = squaredDistance;\n function magnitude(a) {\n const x = a[0], y = a[1], z = a[2];\n return Math.sqrt(x * x + y * y + z * z);\n }\n Vec3.magnitude = magnitude;\n function squaredMagnitude(a) {\n const x = a[0], y = a[1], z = a[2];\n return x * x + y * y + z * z;\n }\n Vec3.squaredMagnitude = squaredMagnitude;\n function setMagnitude(out, a, l) {\n return scale(out, normalize(out, a), l);\n }\n Vec3.setMagnitude = setMagnitude;\n /**\n * Negates the components of a vec3\n */\n function negate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n return out;\n }\n Vec3.negate = negate;\n /**\n * Returns the inverse of the components of a Vec3\n */\n function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n out[2] = 1.0 / a[2];\n return out;\n }\n Vec3.inverse = inverse;\n function normalize(out, a) {\n const x = a[0], y = a[1], z = a[2];\n let len = x * x + y * y + z * z;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n out[0] = a[0] * len;\n out[1] = a[1] * len;\n out[2] = a[2] * len;\n }\n return out;\n }\n Vec3.normalize = normalize;\n function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n }\n Vec3.dot = dot;\n function cross(out, a, b) {\n const ax = a[0], ay = a[1], az = a[2], bx = b[0], by = b[1], bz = b[2];\n out[0] = ay * bz - az * by;\n out[1] = az * bx - ax * bz;\n out[2] = ax * by - ay * bx;\n return out;\n }\n Vec3.cross = cross;\n /**\n * Performs a linear interpolation between two Vec3's\n */\n function lerp(out, a, b, t) {\n const ax = a[0], ay = a[1], az = a[2];\n out[0] = ax + t * (b[0] - ax);\n out[1] = ay + t * (b[1] - ay);\n out[2] = az + t * (b[2] - az);\n return out;\n }\n Vec3.lerp = lerp;\n const slerpRelVec = zero();\n function slerp(out, a, b, t) {\n const d = _clamp(dot(a, b), -1, 1);\n const theta = Math.acos(d) * t;\n scaleAndAdd(slerpRelVec, b, a, -d);\n normalize(slerpRelVec, slerpRelVec);\n return add(out, scale(out, a, Math.cos(theta)), scale(slerpRelVec, slerpRelVec, Math.sin(theta)));\n }\n Vec3.slerp = slerp;\n /**\n * Performs a hermite interpolation with two control points\n */\n function hermite(out, a, b, c, d, t) {\n const factorTimes2 = t * t;\n const factor1 = factorTimes2 * (2 * t - 3) + 1;\n const factor2 = factorTimes2 * (t - 2) + t;\n const factor3 = factorTimes2 * (t - 1);\n const factor4 = factorTimes2 * (3 - 2 * t);\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\n return out;\n }\n Vec3.hermite = hermite;\n /**\n * Performs a bezier interpolation with two control points\n */\n function bezier(out, a, b, c, d, t) {\n const inverseFactor = 1 - t;\n const inverseFactorTimesTwo = inverseFactor * inverseFactor;\n const factorTimes2 = t * t;\n const factor1 = inverseFactorTimesTwo * inverseFactor;\n const factor2 = 3 * t * inverseFactorTimesTwo;\n const factor3 = 3 * factorTimes2 * inverseFactor;\n const factor4 = factorTimes2 * t;\n out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;\n out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;\n out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;\n return out;\n }\n Vec3.bezier = bezier;\n function quadraticBezier(out, a, b, c, t) {\n out[0] = _quadraticBezier(a[0], b[0], c[0], t);\n out[1] = _quadraticBezier(a[1], b[1], c[1], t);\n out[2] = _quadraticBezier(a[2], b[2], c[2], t);\n return out;\n }\n Vec3.quadraticBezier = quadraticBezier;\n /**\n * Performs a spline interpolation with two control points and a tension parameter\n */\n function spline(out, a, b, c, d, t, tension) {\n out[0] = _spline(a[0], b[0], c[0], d[0], t, tension);\n out[1] = _spline(a[1], b[1], c[1], d[1], t, tension);\n out[2] = _spline(a[2], b[2], c[2], d[2], t, tension);\n return out;\n }\n Vec3.spline = spline;\n /**\n * Generates a random vector with the given scale\n */\n function random(out, scale) {\n const r = Math.random() * 2.0 * Math.PI;\n const z = (Math.random() * 2.0) - 1.0;\n const zScale = Math.sqrt(1.0 - z * z) * scale;\n out[0] = Math.cos(r) * zScale;\n out[1] = Math.sin(r) * zScale;\n out[2] = z * scale;\n return out;\n }\n Vec3.random = random;\n /**\n * Transforms the Vec3 with a Mat4. 4th vector component is implicitly '1'\n */\n function transformMat4(out, a, m) {\n const x = a[0], y = a[1], z = a[2], w = 1 / ((m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0);\n out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) * w;\n out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) * w;\n out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) * w;\n return out;\n }\n Vec3.transformMat4 = transformMat4;\n function transformDirection(out, a, m) {\n const x = a[0], y = a[1], z = a[2];\n out[0] = m[0] * x + m[4] * y + m[8] * z;\n out[1] = m[1] * x + m[5] * y + m[9] * z;\n out[2] = m[2] * x + m[6] * y + m[10] * z;\n return normalize(out, out);\n }\n Vec3.transformDirection = transformDirection;\n /**\n * Like `transformMat4` but with offsets into arrays\n */\n function transformMat4Offset(out, a, m, outO, aO, oM) {\n const x = a[0 + aO], y = a[1 + aO], z = a[2 + aO], w = 1 / ((m[3 + oM] * x + m[7 + oM] * y + m[11 + oM] * z + m[15 + oM]) || 1.0);\n out[0 + outO] = (m[0 + oM] * x + m[4 + oM] * y + m[8 + oM] * z + m[12 + oM]) * w;\n out[1 + outO] = (m[1 + oM] * x + m[5 + oM] * y + m[9 + oM] * z + m[13 + oM]) * w;\n out[2 + outO] = (m[2 + oM] * x + m[6 + oM] * y + m[10 + oM] * z + m[14 + oM]) * w;\n return out;\n }\n Vec3.transformMat4Offset = transformMat4Offset;\n /**\n * Transforms the direction vector with a Mat4. 4th vector component is implicitly '0'\n * This means the translation components of the matrix are ignored.\n * Assumes that m is already the transpose of the inverse matrix suitable for normal transformation.\n */\n function transformDirectionOffset(out, a, m, outO, aO, oM) {\n const x = a[0 + aO], y = a[1 + aO], z = a[2 + aO];\n out[0 + outO] = m[0 + oM] * x + m[4 + oM] * y + m[8 + oM] * z;\n out[1 + outO] = m[1 + oM] * x + m[5 + oM] * y + m[9 + oM] * z;\n out[2 + outO] = m[2 + oM] * x + m[6 + oM] * y + m[10 + oM] * z;\n // Normalize the output vector to handle non-uniform scaling\n const len = Math.hypot(out[0 + outO], out[1 + outO], out[2 + outO]);\n if (len > 0) {\n out[0 + outO] /= len;\n out[1 + outO] /= len;\n out[2 + outO] /= len;\n }\n return out;\n }\n Vec3.transformDirectionOffset = transformDirectionOffset;\n /**\n * Transforms the Vec3 with a Mat3.\n */\n function transformMat3(out, a, m) {\n const x = a[0], y = a[1], z = a[2];\n out[0] = x * m[0] + y * m[3] + z * m[6];\n out[1] = x * m[1] + y * m[4] + z * m[7];\n out[2] = x * m[2] + y * m[5] + z * m[8];\n return out;\n }\n Vec3.transformMat3 = transformMat3;\n /** Transforms the Vec3 with a quat */\n function transformQuat(out, a, q) {\n // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations\n const x = a[0], y = a[1], z = a[2];\n const qx = q[0], qy = q[1], qz = q[2], qw = q[3];\n // calculate quat * vec\n const ix = qw * x + qy * z - qz * y;\n const iy = qw * y + qz * x - qx * z;\n const iz = qw * z + qx * y - qy * x;\n const iw = -qx * x - qy * y - qz * z;\n // calculate result * inverse quat\n out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;\n out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;\n out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;\n return out;\n }\n Vec3.transformQuat = transformQuat;\n /** Computes the angle between 2 vectors, reports in radians. */\n function angle(a, b) {\n const denominator = Math.sqrt(squaredMagnitude(a) * squaredMagnitude(b));\n if (denominator === 0)\n return Math.PI / 2;\n const theta = dot(a, b) / denominator;\n return Math.acos(_clamp(theta, -1, 1)); // clamp to avoid numerical problems\n }\n Vec3.angle = angle;\n const tmp_dh_ab = zero();\n const tmp_dh_cb = zero();\n const tmp_dh_bc = zero();\n const tmp_dh_dc = zero();\n const tmp_dh_abc = zero();\n const tmp_dh_bcd = zero();\n const tmp_dh_cross = zero();\n /**\n * Computes the dihedral angles of 4 points, reports in radians.\n */\n function dihedralAngle(a, b, c, d) {\n sub(tmp_dh_ab, a, b);\n sub(tmp_dh_cb, c, b);\n sub(tmp_dh_bc, b, c);\n sub(tmp_dh_dc, d, c);\n cross(tmp_dh_abc, tmp_dh_ab, tmp_dh_cb);\n cross(tmp_dh_bcd, tmp_dh_bc, tmp_dh_dc);\n const _angle = angle(tmp_dh_abc, tmp_dh_bcd);\n cross(tmp_dh_cross, tmp_dh_abc, tmp_dh_bcd);\n return dot(tmp_dh_cb, tmp_dh_cross) > 0 ? _angle : -_angle;\n }\n Vec3.dihedralAngle = dihedralAngle;\n /**\n * @param inclination in radians [0, PI]\n * @param azimuth in radians [0, 2 * PI]\n * @param radius [0, +Inf]\n */\n function directionFromSpherical(out, inclination, azimuth, radius) {\n return Vec3.set(out, radius * Math.cos(azimuth) * Math.sin(inclination), radius * Math.sin(azimuth) * Math.sin(inclination), radius * Math.cos(inclination));\n }\n Vec3.directionFromSpherical = directionFromSpherical;\n /**\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\n */\n function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];\n }\n Vec3.exactEquals = exactEquals;\n /**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n */\n function equals(a, b) {\n const a0 = a[0], a1 = a[1], a2 = a[2];\n const b0 = b[0], b1 = b[1], b2 = b[2];\n return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));\n }\n Vec3.equals = equals;\n const rotTemp = zero();\n function makeRotation(mat, a, b) {\n const by = angle(a, b);\n if (Math.abs(by) < 0.0001)\n return Mat4.setIdentity(mat);\n if (Math.abs(by - Math.PI) < EPSILON) {\n // here, axis can be [0,0,0] but the rotation is a simple flip\n return Mat4.fromScaling(mat, Vec3.negUnit);\n }\n const axis = cross(rotTemp, a, b);\n return Mat4.fromRotation(mat, by, axis);\n }\n Vec3.makeRotation = makeRotation;\n function isZero(v) {\n return v[0] === 0 && v[1] === 0 && v[2] === 0;\n }\n Vec3.isZero = isZero;\n /** Project `point` onto `vector` starting from `origin` */\n function projectPointOnVector(out, point, vector, origin) {\n sub(out, point, origin);\n const scalar = dot(vector, out) / squaredMagnitude(vector);\n return add(out, scale(out, vector, scalar), origin);\n }\n Vec3.projectPointOnVector = projectPointOnVector;\n const tmpProjectPlane = zero();\n /** Project `point` onto `plane` defined by `normal` starting from `origin` */\n function projectPointOnPlane(out, point, normal, origin) {\n normalize(tmpProjectPlane, normal);\n sub(out, point, origin);\n return sub(out, point, scale(tmpProjectPlane, tmpProjectPlane, dot(out, tmpProjectPlane)));\n }\n Vec3.projectPointOnPlane = projectPointOnPlane;\n function projectOnVector(out, p, vector) {\n const scalar = dot(vector, p) / squaredMagnitude(vector);\n return scale(out, vector, scalar);\n }\n Vec3.projectOnVector = projectOnVector;\n const tmpProject = zero();\n function projectOnPlane(out, p, normal) {\n projectOnVector(tmpProject, p, normal);\n return sub(out, p, tmpProject);\n }\n Vec3.projectOnPlane = projectOnPlane;\n /** Get a vector that is similar to `b` but orthogonal to `a` */\n function orthogonalize(out, a, b) {\n return normalize(out, cross(out, cross(out, a, b), a));\n }\n Vec3.orthogonalize = orthogonalize;\n /**\n * Get a vector like `a` that point into the same general direction as `b`,\n * i.e. where the dot product is > 0\n */\n function matchDirection(out, a, b) {\n if (dot(a, b) > 0)\n copy(out, a);\n else\n negate(out, copy(out, a));\n return out;\n }\n Vec3.matchDirection = matchDirection;\n const triangleNormalTmpAB = zero();\n const triangleNormalTmpAC = zero();\n /** Calculate normal for the triangle defined by `a`, `b` and `c` */\n function triangleNormal(out, a, b, c) {\n sub(triangleNormalTmpAB, b, a);\n sub(triangleNormalTmpAC, c, a);\n return normalize(out, cross(out, triangleNormalTmpAB, triangleNormalTmpAC));\n }\n Vec3.triangleNormal = triangleNormal;\n function toString(a, precision) {\n return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)}]`;\n }\n Vec3.toString = toString;\n Vec3.origin = create(0, 0, 0);\n Vec3.unit = create(1, 1, 1);\n Vec3.negUnit = create(-1, -1, -1);\n Vec3.unitX = create(1, 0, 0);\n Vec3.unitY = create(0, 1, 0);\n Vec3.unitZ = create(0, 0, 1);\n Vec3.negUnitX = create(-1, 0, 0);\n Vec3.negUnitY = create(0, -1, 0);\n Vec3.negUnitZ = create(0, 0, -1);\n})(Vec3 || (Vec3 = {}));\nexport { Vec3 };\n","/**\n * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author Alexander Rose \n */\nexport const halfPI = Math.PI / 2;\nexport const PiDiv180 = Math.PI / 180;\nexport function degToRad(deg) {\n return deg * PiDiv180; // deg * Math.PI / 180\n}\nexport function radToDeg(rad) {\n return rad / PiDiv180; // rad * 180 / Math.PI\n}\nexport function isPowerOfTwo(x) {\n return (x !== 0) && (x & (x - 1)) === 0;\n}\n/** return the value that has the largest absolute value */\nexport function absMax(...values) {\n let max = 0;\n let absMax = 0;\n for (let i = 0, il = values.length; i < il; ++i) {\n const value = values[i];\n const abs = Math.abs(value);\n if (abs > absMax) {\n max = value;\n absMax = abs;\n }\n }\n return max;\n}\n/** Length of an arc with angle in radians */\nexport function arcLength(angle, radius) {\n return angle * radius;\n}\n/** Create an outward spiral of given `radius` on a 2d grid */\nexport function spiral2d(radius) {\n let x = 0;\n let y = 0;\n const delta = [0, -1];\n const size = radius * 2 + 1;\n const halfSize = size / 2;\n const out = [];\n for (let i = Math.pow(size, 2); i > 0; --i) {\n if ((-halfSize < x && x <= halfSize) && (-halfSize < y && y <= halfSize)) {\n out.push([x, y]);\n }\n if (x === y || (x < 0 && x === -y) || (x > 0 && x === 1 - y)) {\n [delta[0], delta[1]] = [-delta[1], delta[0]]; // change direction\n }\n x += delta[0];\n y += delta[1];\n }\n return out;\n}\n","/**\n * Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\n/*\n * This code has been modified from https://github.com/toji/gl-matrix/,\n * copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n */\nimport { EPSILON, equalEps } from './common';\nimport { Vec3 } from './vec3';\nimport { degToRad } from '../../misc';\nfunction Mat4() {\n return Mat4.zero();\n}\n/**\n * Stores a 4x4 matrix in a column major (j * 4 + i indexing) format.\n */\n(function (Mat4) {\n function zero() {\n // force double backing array by 0.1.\n const ret = [0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n ret[0] = 0.0;\n return ret;\n }\n Mat4.zero = zero;\n function identity() {\n const out = zero();\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n }\n Mat4.identity = identity;\n function setIdentity(mat) {\n mat[0] = 1;\n mat[1] = 0;\n mat[2] = 0;\n mat[3] = 0;\n mat[4] = 0;\n mat[5] = 1;\n mat[6] = 0;\n mat[7] = 0;\n mat[8] = 0;\n mat[9] = 0;\n mat[10] = 1;\n mat[11] = 0;\n mat[12] = 0;\n mat[13] = 0;\n mat[14] = 0;\n mat[15] = 1;\n return mat;\n }\n Mat4.setIdentity = setIdentity;\n function setZero(mat) {\n for (let i = 0; i < 16; i++)\n mat[i] = 0;\n return mat;\n }\n Mat4.setZero = setZero;\n function ofRows(rows) {\n const out = zero();\n for (let i = 0; i < 4; i++) {\n const r = rows[i];\n for (let j = 0; j < 4; j++) {\n out[4 * j + i] = r[j];\n }\n }\n return out;\n }\n Mat4.ofRows = ofRows;\n const _id = identity();\n function isIdentity(m, eps) {\n return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON : eps);\n }\n Mat4.isIdentity = isIdentity;\n function hasNaN(m) {\n for (let i = 0; i < 16; i++)\n if (isNaN(m[i]))\n return true;\n return false;\n }\n Mat4.hasNaN = hasNaN;\n function areEqual(a, b, eps) {\n for (let i = 0; i < 16; i++) {\n if (Math.abs(a[i] - b[i]) > eps)\n return false;\n }\n return true;\n }\n Mat4.areEqual = areEqual;\n function setValue(a, i, j, value) {\n a[4 * j + i] = value;\n }\n Mat4.setValue = setValue;\n function getValue(a, i, j) {\n return a[4 * j + i];\n }\n Mat4.getValue = getValue;\n function toArray(a, out, offset) {\n out[offset + 0] = a[0];\n out[offset + 1] = a[1];\n out[offset + 2] = a[2];\n out[offset + 3] = a[3];\n out[offset + 4] = a[4];\n out[offset + 5] = a[5];\n out[offset + 6] = a[6];\n out[offset + 7] = a[7];\n out[offset + 8] = a[8];\n out[offset + 9] = a[9];\n out[offset + 10] = a[10];\n out[offset + 11] = a[11];\n out[offset + 12] = a[12];\n out[offset + 13] = a[13];\n out[offset + 14] = a[14];\n out[offset + 15] = a[15];\n return out;\n }\n Mat4.toArray = toArray;\n function fromArray(a, array, offset) {\n a[0] = array[offset + 0];\n a[1] = array[offset + 1];\n a[2] = array[offset + 2];\n a[3] = array[offset + 3];\n a[4] = array[offset + 4];\n a[5] = array[offset + 5];\n a[6] = array[offset + 6];\n a[7] = array[offset + 7];\n a[8] = array[offset + 8];\n a[9] = array[offset + 9];\n a[10] = array[offset + 10];\n a[11] = array[offset + 11];\n a[12] = array[offset + 12];\n a[13] = array[offset + 13];\n a[14] = array[offset + 14];\n a[15] = array[offset + 15];\n return a;\n }\n Mat4.fromArray = fromArray;\n function fromBasis(a, x, y, z) {\n setZero(a);\n setValue(a, 0, 0, x[0]);\n setValue(a, 1, 0, x[1]);\n setValue(a, 2, 0, x[2]);\n setValue(a, 0, 1, y[0]);\n setValue(a, 1, 1, y[1]);\n setValue(a, 2, 1, y[2]);\n setValue(a, 0, 2, z[0]);\n setValue(a, 1, 2, z[1]);\n setValue(a, 2, 2, z[2]);\n setValue(a, 3, 3, 1);\n return a;\n }\n Mat4.fromBasis = fromBasis;\n function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n out[9] = a[9];\n out[10] = a[10];\n out[11] = a[11];\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n }\n Mat4.copy = copy;\n function clone(a) {\n return copy(zero(), a);\n }\n Mat4.clone = clone;\n /**\n * Returns the translation vector component of a transformation matrix.\n */\n function getTranslation(out, mat) {\n out[0] = mat[12];\n out[1] = mat[13];\n out[2] = mat[14];\n return out;\n }\n Mat4.getTranslation = getTranslation;\n /**\n * Returns the scaling factor component of a transformation matrix.\n */\n function getScaling(out, mat) {\n const m11 = mat[0];\n const m12 = mat[1];\n const m13 = mat[2];\n const m21 = mat[4];\n const m22 = mat[5];\n const m23 = mat[6];\n const m31 = mat[8];\n const m32 = mat[9];\n const m33 = mat[10];\n out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);\n out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);\n out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);\n return out;\n }\n Mat4.getScaling = getScaling;\n /**\n * Returns a quaternion representing the rotational component of a transformation matrix.\n */\n function getRotation(out, mat) {\n // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\n const trace = mat[0] + mat[5] + mat[10];\n let S = 0;\n if (trace > 0) {\n S = Math.sqrt(trace + 1.0) * 2;\n out[3] = 0.25 * S;\n out[0] = (mat[6] - mat[9]) / S;\n out[1] = (mat[8] - mat[2]) / S;\n out[2] = (mat[1] - mat[4]) / S;\n }\n else if ((mat[0] > mat[5]) && (mat[0] > mat[10])) {\n S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;\n out[3] = (mat[6] - mat[9]) / S;\n out[0] = 0.25 * S;\n out[1] = (mat[1] + mat[4]) / S;\n out[2] = (mat[8] + mat[2]) / S;\n }\n else if (mat[5] > mat[10]) {\n S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;\n out[3] = (mat[8] - mat[2]) / S;\n out[0] = (mat[1] + mat[4]) / S;\n out[1] = 0.25 * S;\n out[2] = (mat[6] + mat[9]) / S;\n }\n else {\n S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;\n out[3] = (mat[1] - mat[4]) / S;\n out[0] = (mat[8] + mat[2]) / S;\n out[1] = (mat[6] + mat[9]) / S;\n out[2] = 0.25 * S;\n }\n return out;\n }\n Mat4.getRotation = getRotation;\n function extractRotation(out, mat) {\n const scaleX = 1 / Math.sqrt(mat[0] * mat[0] + mat[1] * mat[1] + mat[2] * mat[2]);\n const scaleY = 1 / Math.sqrt(mat[4] * mat[4] + mat[5] * mat[5] + mat[6] * mat[6]);\n const scaleZ = 1 / Math.sqrt(mat[8] * mat[8] + mat[9] * mat[9] + mat[10] * mat[10]);\n out[0] = mat[0] * scaleX;\n out[1] = mat[1] * scaleX;\n out[2] = mat[2] * scaleX;\n out[3] = 0;\n out[4] = mat[4] * scaleY;\n out[5] = mat[5] * scaleY;\n out[6] = mat[6] * scaleY;\n out[7] = 0;\n out[8] = mat[8] * scaleZ;\n out[9] = mat[9] * scaleZ;\n out[10] = mat[10] * scaleZ;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n }\n Mat4.extractRotation = extractRotation;\n function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache some values\n if (out === a) {\n const a01 = a[1], a02 = a[2], a03 = a[3];\n const a12 = a[6], a13 = a[7];\n const a23 = a[11];\n out[1] = a[4];\n out[2] = a[8];\n out[3] = a[12];\n out[4] = a01;\n out[6] = a[9];\n out[7] = a[13];\n out[8] = a02;\n out[9] = a12;\n out[11] = a[14];\n out[12] = a03;\n out[13] = a13;\n out[14] = a23;\n }\n else {\n out[0] = a[0];\n out[1] = a[4];\n out[2] = a[8];\n out[3] = a[12];\n out[4] = a[1];\n out[5] = a[5];\n out[6] = a[9];\n out[7] = a[13];\n out[8] = a[2];\n out[9] = a[6];\n out[10] = a[10];\n out[11] = a[14];\n out[12] = a[3];\n out[13] = a[7];\n out[14] = a[11];\n out[15] = a[15];\n }\n return out;\n }\n Mat4.transpose = transpose;\n function tryInvert(out, a) {\n const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10, b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12, b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30, b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32;\n // Calculate the determinant\n let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n if (!det) {\n return false;\n }\n det = 1.0 / det;\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\n out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\n out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\n out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;\n out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\n out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\n out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\n out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;\n out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\n out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\n out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\n out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;\n out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;\n out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;\n out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;\n out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;\n return true;\n }\n Mat4.tryInvert = tryInvert;\n function invert(out, a) {\n if (!tryInvert(out, a)) {\n console.warn('non-invertible matrix.', a);\n }\n return out;\n }\n Mat4.invert = invert;\n function mul(out, a, b) {\n const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];\n // Cache only the current line of the second matrix\n let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n b0 = b[4];\n b1 = b[5];\n b2 = b[6];\n b3 = b[7];\n out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n b0 = b[8];\n b1 = b[9];\n b2 = b[10];\n b3 = b[11];\n out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n b0 = b[12];\n b1 = b[13];\n b2 = b[14];\n b3 = b[15];\n out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n return out;\n }\n Mat4.mul = mul;\n /**\n * Like `mul` but with offsets into arrays\n */\n function mulOffset(out, a, b, oOut, oA, oB) {\n const a00 = a[0 + oA], a01 = a[1 + oA], a02 = a[2 + oA], a03 = a[3 + oA], a10 = a[4 + oA], a11 = a[5 + oA], a12 = a[6 + oA], a13 = a[7 + oA], a20 = a[8 + oA], a21 = a[9 + oA], a22 = a[10 + oA], a23 = a[11 + oA], a30 = a[12 + oA], a31 = a[13 + oA], a32 = a[14 + oA], a33 = a[15 + oA];\n // Cache only the current line of the second matrix\n let b0 = b[0 + oB], b1 = b[1 + oB], b2 = b[2 + oB], b3 = b[3 + oB];\n out[0 + oOut] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[1 + oOut] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[2 + oOut] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[3 + oOut] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n b0 = b[4 + oB];\n b1 = b[5 + oB];\n b2 = b[6 + oB];\n b3 = b[7 + oB];\n out[4 + oOut] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[5 + oOut] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[6 + oOut] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[7 + oOut] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n b0 = b[8 + oB];\n b1 = b[9 + oB];\n b2 = b[10 + oB];\n b3 = b[11 + oB];\n out[8 + oOut] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[9 + oOut] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[10 + oOut] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[11 + oOut] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n b0 = b[12 + oB];\n b1 = b[13 + oB];\n b2 = b[14 + oB];\n b3 = b[15 + oB];\n out[12 + oOut] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;\n out[13 + oOut] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;\n out[14 + oOut] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;\n out[15 + oOut] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;\n return out;\n }\n Mat4.mulOffset = mulOffset;\n function mul3(out, a, b, c) {\n return mul(out, mul(out, a, b), c);\n }\n Mat4.mul3 = mul3;\n /** Translate a Mat4 by the given Vec3 */\n function translate(out, a, v) {\n const x = v[0], y = v[1], z = v[2];\n let a00, a01, a02, a03, a10, a11, a12, a13, a20, a21, a22, a23;\n if (a === out) {\n out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];\n out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];\n out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];\n out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];\n }\n else {\n a00 = a[0];\n a01 = a[1];\n a02 = a[2];\n a03 = a[3];\n a10 = a[4];\n a11 = a[5];\n a12 = a[6];\n a13 = a[7];\n a20 = a[8];\n a21 = a[9];\n a22 = a[10];\n a23 = a[11];\n out[0] = a00;\n out[1] = a01;\n out[2] = a02;\n out[3] = a03;\n out[4] = a10;\n out[5] = a11;\n out[6] = a12;\n out[7] = a13;\n out[8] = a20;\n out[9] = a21;\n out[10] = a22;\n out[11] = a23;\n out[12] = a00 * x + a10 * y + a20 * z + a[12];\n out[13] = a01 * x + a11 * y + a21 * z + a[13];\n out[14] = a02 * x + a12 * y + a22 * z + a[14];\n out[15] = a03 * x + a13 * y + a23 * z + a[15];\n }\n return out;\n }\n Mat4.translate = translate;\n function fromTranslation(out, v) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = 1;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 1;\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n return out;\n }\n Mat4.fromTranslation = fromTranslation;\n function setTranslation(out, v) {\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n return out;\n }\n Mat4.setTranslation = setTranslation;\n /**\n * Sets the specified quaternion with values corresponding to the given\n * axes. Each axis is a vec3 and is expected to be unit length and\n * perpendicular to all other specified axes.\n */\n function setAxes(out, view, right, up) {\n out[0] = right[0];\n out[4] = right[1];\n out[8] = right[2];\n out[1] = up[0];\n out[5] = up[1];\n out[9] = up[2];\n out[2] = view[0];\n out[6] = view[1];\n out[10] = view[2];\n return out;\n }\n Mat4.setAxes = setAxes;\n function rotate(out, a, rad, axis) {\n let x = axis[0], y = axis[1], z = axis[2];\n let len = Math.sqrt(x * x + y * y + z * z);\n if (Math.abs(len) < EPSILON) {\n return identity();\n }\n len = 1 / len;\n x *= len;\n y *= len;\n z *= len;\n const s = Math.sin(rad);\n const c = Math.cos(rad);\n const t = 1 - c;\n const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];\n const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];\n const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];\n // Construct the elements of the rotation matrix\n const b00 = x * x * t + c, b01 = y * x * t + z * s, b02 = z * x * t - y * s;\n const b10 = x * y * t - z * s, b11 = y * y * t + c, b12 = z * y * t + x * s;\n const b20 = x * z * t + y * s, b21 = y * z * t - x * s, b22 = z * z * t + c;\n // Perform rotation-specific matrix multiplication\n out[0] = a00 * b00 + a10 * b01 + a20 * b02;\n out[1] = a01 * b00 + a11 * b01 + a21 * b02;\n out[2] = a02 * b00 + a12 * b01 + a22 * b02;\n out[3] = a03 * b00 + a13 * b01 + a23 * b02;\n out[4] = a00 * b10 + a10 * b11 + a20 * b12;\n out[5] = a01 * b10 + a11 * b11 + a21 * b12;\n out[6] = a02 * b10 + a12 * b11 + a22 * b12;\n out[7] = a03 * b10 + a13 * b11 + a23 * b12;\n out[8] = a00 * b20 + a10 * b21 + a20 * b22;\n out[9] = a01 * b20 + a11 * b21 + a21 * b22;\n out[10] = a02 * b20 + a12 * b21 + a22 * b22;\n out[11] = a03 * b20 + a13 * b21 + a23 * b22;\n if (a !== out) { // If the source and destination differ, copy the unchanged last row\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n }\n return out;\n }\n Mat4.rotate = rotate;\n function fromRotation(out, rad, axis) {\n let x = axis[0], y = axis[1], z = axis[2];\n let len = Math.sqrt(x * x + y * y + z * z);\n if (Math.abs(len) < EPSILON) {\n return setIdentity(out);\n }\n len = 1 / len;\n x *= len;\n y *= len;\n z *= len;\n const s = Math.sin(rad);\n const c = Math.cos(rad);\n const t = 1 - c;\n // Perform rotation-specific matrix multiplication\n out[0] = x * x * t + c;\n out[1] = y * x * t + z * s;\n out[2] = z * x * t - y * s;\n out[3] = 0;\n out[4] = x * y * t - z * s;\n out[5] = y * y * t + c;\n out[6] = z * y * t + x * s;\n out[7] = 0;\n out[8] = x * z * t + y * s;\n out[9] = y * z * t - x * s;\n out[10] = z * z * t + c;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n }\n Mat4.fromRotation = fromRotation;\n function scale(out, a, v) {\n const x = v[0], y = v[1], z = v[2];\n out[0] = a[0] * x;\n out[1] = a[1] * x;\n out[2] = a[2] * x;\n out[3] = a[3] * x;\n out[4] = a[4] * y;\n out[5] = a[5] * y;\n out[6] = a[6] * y;\n out[7] = a[7] * y;\n out[8] = a[8] * z;\n out[9] = a[9] * z;\n out[10] = a[10] * z;\n out[11] = a[11] * z;\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n }\n Mat4.scale = scale;\n function scaleUniformly(out, a, scale) {\n out[0] = a[0] * scale;\n out[1] = a[1] * scale;\n out[2] = a[2] * scale;\n out[3] = a[3] * scale;\n out[4] = a[4] * scale;\n out[5] = a[5] * scale;\n out[6] = a[6] * scale;\n out[7] = a[7] * scale;\n out[8] = a[8] * scale;\n out[9] = a[9] * scale;\n out[10] = a[10] * scale;\n out[11] = a[11] * scale;\n out[12] = a[12];\n out[13] = a[13];\n out[14] = a[14];\n out[15] = a[15];\n return out;\n }\n Mat4.scaleUniformly = scaleUniformly;\n function fromScaling(out, v) {\n out[0] = v[0];\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = v[1];\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = v[2];\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n }\n Mat4.fromScaling = fromScaling;\n function fromUniformScaling(out, scale) {\n out[0] = scale;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = scale;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = scale;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n }\n Mat4.fromUniformScaling = fromUniformScaling;\n /**\n * Copies the mat3 into upper-left 3x3 values.\n */\n function fromMat3(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[4] = a[3];\n out[5] = a[4];\n out[6] = a[5];\n out[8] = a[6];\n out[9] = a[7];\n out[10] = a[8];\n return out;\n }\n Mat4.fromMat3 = fromMat3;\n function compose(out, position, quaternion, scale) {\n const [x, y, z, w] = quaternion;\n const x2 = x + x, y2 = y + y, z2 = z + z;\n const xx = x * x2, xy = x * y2, xz = x * z2;\n const yy = y * y2, yz = y * z2, zz = z * z2;\n const wx = w * x2, wy = w * y2, wz = w * z2;\n const [sx, sy, sz] = scale;\n out[0] = (1 - (yy + zz)) * sx;\n out[1] = (xy + wz) * sx;\n out[2] = (xz - wy) * sx;\n out[3] = 0;\n out[4] = (xy - wz) * sy;\n out[5] = (1 - (xx + zz)) * sy;\n out[6] = (yz + wx) * sy;\n out[7] = 0;\n out[8] = (xz + wy) * sz;\n out[9] = (yz - wx) * sz;\n out[10] = (1 - (xx + yy)) * sz;\n out[11] = 0;\n out[12] = position[0];\n out[13] = position[1];\n out[14] = position[2];\n out[15] = 1;\n return out;\n }\n Mat4.compose = compose;\n const _v3 = [0, 0, 0];\n const _m4 = zero();\n function decompose(m, position, quaternion, scale) {\n let sx = Vec3.magnitude(Vec3.set(_v3, m[0], m[1], m[2]));\n const sy = Vec3.magnitude(Vec3.set(_v3, m[4], m[5], m[6]));\n const sz = Vec3.magnitude(Vec3.set(_v3, m[8], m[9], m[10]));\n // if determine is negative, we need to invert one scale\n const det = determinant(m);\n if (det < 0)\n sx = -sx;\n position[0] = m[12];\n position[1] = m[13];\n position[2] = m[14];\n // scale the rotation part\n copy(_m4, m);\n const invSX = 1 / sx;\n const invSY = 1 / sy;\n const invSZ = 1 / sz;\n _m4[0] *= invSX;\n _m4[1] *= invSX;\n _m4[2] *= invSX;\n _m4[4] *= invSY;\n _m4[5] *= invSY;\n _m4[6] *= invSY;\n _m4[8] *= invSZ;\n _m4[9] *= invSZ;\n _m4[10] *= invSZ;\n getRotation(quaternion, _m4);\n scale[0] = sx;\n scale[1] = sy;\n scale[2] = sz;\n return m;\n }\n Mat4.decompose = decompose;\n function makeTable(m) {\n let ret = '';\n for (let i = 0; i < 4; i++) {\n for (let j = 0; j < 4; j++) {\n ret += m[4 * j + i].toString();\n if (j < 3)\n ret += ' ';\n }\n if (i < 3)\n ret += '\\n';\n }\n return ret;\n }\n Mat4.makeTable = makeTable;\n function determinant(a) {\n const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10, b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12, b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30, b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32;\n // Calculate the determinant\n return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n }\n Mat4.determinant = determinant;\n /**\n * Check if the matrix has the form\n * [ Rotation Translation ]\n * [ 0 1 ]\n *\n * Allows for improper rotations\n */\n function isRotationAndTranslation(a, eps) {\n return _isRotationAndTranslation(a, typeof eps !== 'undefined' ? eps : EPSILON);\n }\n Mat4.isRotationAndTranslation = isRotationAndTranslation;\n function _isRotationAndTranslation(a, eps) {\n const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], a33 = a[15];\n if (!equalEps(a33, 1, eps) || !equalEps(a03, 0, eps) || !equalEps(a13, 0, eps) || !equalEps(a23, 0, eps)) {\n return false;\n }\n // use `abs` to allow for improper rotations\n const det3x3 = Math.abs(a00 * (a11 * a22 - a12 * a21) - a01 * (a10 * a22 - a12 * a20) + a02 * (a10 * a21 - a11 * a20));\n if (!equalEps(det3x3, 1, eps)) {\n return false;\n }\n return true;\n }\n /**\n * Check if the matrix has only translation and uniform scaling\n * [ S 0 0 X ]\n * [ 0 S 0 Y ]\n * [ 0 0 S Z ]\n * [ 0 0 0 1 ]\n */\n function isTranslationAndUniformScaling(a, eps) {\n return _isTranslationAndUniformScaling(a, typeof eps !== 'undefined' ? eps : EPSILON);\n }\n Mat4.isTranslationAndUniformScaling = isTranslationAndUniformScaling;\n function _isTranslationAndUniformScaling(a, eps) {\n const a00 = a[0];\n return (\n // 0 base scaling\n equalEps(a[1], 0, eps) &&\n equalEps(a[2], 0, eps) &&\n equalEps(a[3], 0, eps) &&\n equalEps(a[4], 0, eps) &&\n equalEps(a[5], a00, eps) &&\n equalEps(a[6], 0, eps) &&\n equalEps(a[7], 0, eps) &&\n equalEps(a[8], 0, eps) &&\n equalEps(a[9], 0, eps) &&\n equalEps(a[10], a00, eps) &&\n equalEps(a[11], 0, eps) &&\n // 12, 13, 14 translation can be anything\n equalEps(a[15], 1, eps));\n }\n function fromQuat(out, q) {\n const x = q[0], y = q[1], z = q[2], w = q[3];\n const x2 = x + x;\n const y2 = y + y;\n const z2 = z + z;\n const xx = x * x2;\n const yx = y * x2;\n const yy = y * y2;\n const zx = z * x2;\n const zy = z * y2;\n const zz = z * z2;\n const wx = w * x2;\n const wy = w * y2;\n const wz = w * z2;\n out[0] = 1 - yy - zz;\n out[1] = yx + wz;\n out[2] = zx - wy;\n out[3] = 0;\n out[4] = yx - wz;\n out[5] = 1 - xx - zz;\n out[6] = zy + wx;\n out[7] = 0;\n out[8] = zx + wy;\n out[9] = zy - wx;\n out[10] = 1 - xx - yy;\n out[11] = 0;\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n }\n Mat4.fromQuat = fromQuat;\n function fromEuler(out, euler, order) {\n const x = euler[0], y = euler[1], z = euler[2];\n const a = Math.cos(x), b = Math.sin(x);\n const c = Math.cos(y), d = Math.sin(y);\n const e = Math.cos(z), f = Math.sin(z);\n if (order === 'XYZ') {\n const ae = a * e, af = a * f, be = b * e, bf = b * f;\n out[0] = c * e;\n out[4] = -c * f;\n out[8] = d;\n out[1] = af + be * d;\n out[5] = ae - bf * d;\n out[9] = -b * c;\n out[2] = bf - ae * d;\n out[6] = be + af * d;\n out[10] = a * c;\n }\n else if (order === 'YXZ') {\n const ce = c * e, cf = c * f, de = d * e, df = d * f;\n out[0] = ce + df * b;\n out[4] = de * b - cf;\n out[8] = a * d;\n out[1] = a * f;\n out[5] = a * e;\n out[9] = -b;\n out[2] = cf * b - de;\n out[6] = df + ce * b;\n out[10] = a * c;\n }\n else if (order === 'ZXY') {\n const ce = c * e, cf = c * f, de = d * e, df = d * f;\n out[0] = ce - df * b;\n out[4] = -a * f;\n out[8] = de + cf * b;\n out[1] = cf + de * b;\n out[5] = a * e;\n out[9] = df - ce * b;\n out[2] = -a * d;\n out[6] = b;\n out[10] = a * c;\n }\n else if (order === 'ZYX') {\n const ae = a * e, af = a * f, be = b * e, bf = b * f;\n out[0] = c * e;\n out[4] = be * d - af;\n out[8] = ae * d + bf;\n out[1] = c * f;\n out[5] = bf * d + ae;\n out[9] = af * d - be;\n out[2] = -d;\n out[6] = b * c;\n out[10] = a * c;\n }\n else if (order === 'YZX') {\n const ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n out[0] = c * e;\n out[4] = bd - ac * f;\n out[8] = bc * f + ad;\n out[1] = f;\n out[5] = a * e;\n out[9] = -b * e;\n out[2] = -d * e;\n out[6] = ad * f + bc;\n out[10] = ac - bd * f;\n }\n else if (order === 'XZY') {\n const ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n out[0] = c * e;\n out[4] = -f;\n out[8] = d * e;\n out[1] = ac * f + bd;\n out[5] = a * e;\n out[9] = ad * f - bc;\n out[2] = bc * f - ad;\n out[6] = b * e;\n out[10] = bd * f + ac;\n }\n // bottom row\n out[3] = 0;\n out[7] = 0;\n out[11] = 0;\n // last column\n out[12] = 0;\n out[13] = 0;\n out[14] = 0;\n out[15] = 1;\n return out;\n }\n Mat4.fromEuler = fromEuler;\n /**\n * Generates a perspective projection (frustum) matrix with the given bounds\n */\n function perspective(out, left, right, top, bottom, near, far) {\n const x = 2 * near / (right - left);\n const y = 2 * near / (top - bottom);\n const a = (right + left) / (right - left);\n const b = (top + bottom) / (top - bottom);\n const c = -(far + near) / (far - near);\n const d = -2 * far * near / (far - near);\n out[0] = x;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = y;\n out[6] = 0;\n out[7] = 0;\n out[8] = a;\n out[9] = b;\n out[10] = c;\n out[11] = -1;\n out[12] = 0;\n out[13] = 0;\n out[14] = d;\n out[15] = 0;\n return out;\n }\n Mat4.perspective = perspective;\n /**\n * Generates a orthogonal projection matrix with the given bounds\n */\n function ortho(out, left, right, top, bottom, near, far) {\n const w = 1.0 / (right - left);\n const h = 1.0 / (top - bottom);\n const p = 1.0 / (far - near);\n const x = (right + left) * w;\n const y = (top + bottom) * h;\n const z = (far + near) * p;\n out[0] = 2 * w;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = 2 * h;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = -2 * p;\n out[11] = 0;\n out[12] = -x;\n out[13] = -y;\n out[14] = -z;\n out[15] = 1;\n return out;\n }\n Mat4.ortho = ortho;\n /**\n * Generates a look-at matrix with the given eye position, focal point, and up axis\n */\n function lookAt(out, eye, center, up) {\n let x0, x1, x2, y0, y1, y2, z0, z1, z2, len;\n const eyex = eye[0];\n const eyey = eye[1];\n const eyez = eye[2];\n const upx = up[0];\n const upy = up[1];\n const upz = up[2];\n const centerx = center[0];\n const centery = center[1];\n const centerz = center[2];\n if (Math.abs(eyex - centerx) < EPSILON &&\n Math.abs(eyey - centery) < EPSILON &&\n Math.abs(eyez - centerz) < EPSILON) {\n return setIdentity(out);\n }\n z0 = eyex - centerx;\n z1 = eyey - centery;\n z2 = eyez - centerz;\n len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);\n z0 *= len;\n z1 *= len;\n z2 *= len;\n x0 = upy * z2 - upz * z1;\n x1 = upz * z0 - upx * z2;\n x2 = upx * z1 - upy * z0;\n len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);\n if (!len) {\n x0 = 0;\n x1 = 0;\n x2 = 0;\n }\n else {\n len = 1 / len;\n x0 *= len;\n x1 *= len;\n x2 *= len;\n }\n y0 = z1 * x2 - z2 * x1;\n y1 = z2 * x0 - z0 * x2;\n y2 = z0 * x1 - z1 * x0;\n len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);\n if (!len) {\n y0 = 0;\n y1 = 0;\n y2 = 0;\n }\n else {\n len = 1 / len;\n y0 *= len;\n y1 *= len;\n y2 *= len;\n }\n out[0] = x0;\n out[1] = y0;\n out[2] = z0;\n out[3] = 0;\n out[4] = x1;\n out[5] = y1;\n out[6] = z1;\n out[7] = 0;\n out[8] = x2;\n out[9] = y2;\n out[10] = z2;\n out[11] = 0;\n out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);\n out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);\n out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);\n out[15] = 1;\n return out;\n }\n Mat4.lookAt = lookAt;\n /**\n * Generates a matrix that makes something look at something else.\n */\n function targetTo(out, eye, target, up) {\n const eyex = eye[0], eyey = eye[1], eyez = eye[2], upx = up[0], upy = up[1], upz = up[2];\n let z0 = eyex - target[0], z1 = eyey - target[1], z2 = eyez - target[2];\n let len = z0 * z0 + z1 * z1 + z2 * z2;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n z0 *= len;\n z1 *= len;\n z2 *= len;\n }\n let x0 = upy * z2 - upz * z1, x1 = upz * z0 - upx * z2, x2 = upx * z1 - upy * z0;\n len = x0 * x0 + x1 * x1 + x2 * x2;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n x0 *= len;\n x1 *= len;\n x2 *= len;\n }\n out[0] = x0;\n out[1] = x1;\n out[2] = x2;\n out[3] = 0;\n out[4] = z1 * x2 - z2 * x1;\n out[5] = z2 * x0 - z0 * x2;\n out[6] = z0 * x1 - z1 * x0;\n out[7] = 0;\n out[8] = z0;\n out[9] = z1;\n out[10] = z2;\n out[11] = 0;\n out[12] = eyex;\n out[13] = eyey;\n out[14] = eyez;\n out[15] = 1;\n return out;\n }\n Mat4.targetTo = targetTo;\n /**\n * Perm is 0-indexed permutation\n */\n function fromPermutation(out, perm) {\n setZero(out);\n for (let i = 0; i < 4; i++) {\n const p = perm[i];\n setValue(out, i, p, 1);\n }\n return out;\n }\n Mat4.fromPermutation = fromPermutation;\n function getMaxScaleOnAxis(m) {\n const scaleXSq = m[0] * m[0] + m[1] * m[1] + m[2] * m[2];\n const scaleYSq = m[4] * m[4] + m[5] * m[5] + m[6] * m[6];\n const scaleZSq = m[8] * m[8] + m[9] * m[9] + m[10] * m[10];\n return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq));\n }\n Mat4.getMaxScaleOnAxis = getMaxScaleOnAxis;\n const xAxis = [1, 0, 0];\n const yAxis = [0, 1, 0];\n const zAxis = [0, 0, 1];\n /** Rotation matrix for 90deg around x-axis */\n Mat4.rotX90 = fromRotation(zero(), degToRad(90), xAxis);\n /** Rotation matrix for 180deg around x-axis */\n Mat4.rotX180 = fromRotation(zero(), degToRad(180), xAxis);\n /** Rotation matrix for 90deg around y-axis */\n Mat4.rotY90 = fromRotation(zero(), degToRad(90), yAxis);\n /** Rotation matrix for 180deg around y-axis */\n Mat4.rotY180 = fromRotation(zero(), degToRad(180), yAxis);\n /** Rotation matrix for 270deg around y-axis */\n Mat4.rotY270 = fromRotation(zero(), degToRad(270), yAxis);\n /** Rotation matrix for 90deg around z-axis */\n Mat4.rotZ90 = fromRotation(zero(), degToRad(90), zAxis);\n /** Rotation matrix for 180deg around z-axis */\n Mat4.rotZ180 = fromRotation(zero(), degToRad(180), zAxis);\n /** Rotation matrix for 90deg around first x-axis and then y-axis */\n Mat4.rotXY90 = mul(zero(), Mat4.rotX90, Mat4.rotY90);\n /** Rotation matrix for 90deg around first z-axis and then y-axis */\n Mat4.rotZY90 = mul(zero(), Mat4.rotZ90, Mat4.rotY90);\n /** Rotation matrix for 90deg around first z-axis and then y-axis and then z-axis */\n Mat4.rotZYZ90 = mul(zero(), Mat4.rotZY90, Mat4.rotZ90);\n /** Rotation matrix for 90deg around first z-axis and then 180deg around x-axis */\n Mat4.rotZ90X180 = mul(zero(), Mat4.rotZ90, Mat4.rotX180);\n /** Rotation matrix for 90deg around first y-axis and then 180deg around z-axis */\n Mat4.rotY90Z180 = mul(zero(), Mat4.rotY90, Mat4.rotZ180);\n /** Identity matrix */\n Mat4.id = identity();\n})(Mat4 || (Mat4 = {}));\nexport { Mat4 };\n","/**\n * Copyright (c) 2017-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport { EPSILON } from './common';\nimport { Mat4 } from './mat4';\nimport { Vec3 } from './vec3';\nfunction Mat3() {\n return Mat3.zero();\n}\n(function (Mat3) {\n function zero() {\n // force double backing array by 0.1.\n const ret = [0.1, 0, 0, 0, 0, 0, 0, 0, 0];\n ret[0] = 0.0;\n return ret;\n }\n Mat3.zero = zero;\n function identity() {\n const out = zero();\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 1;\n out[5] = 0;\n out[6] = 0;\n out[7] = 0;\n out[8] = 1;\n return out;\n }\n Mat3.identity = identity;\n function setIdentity(mat) {\n mat[0] = 1;\n mat[1] = 0;\n mat[2] = 0;\n mat[3] = 0;\n mat[4] = 1;\n mat[5] = 0;\n mat[6] = 0;\n mat[7] = 0;\n mat[8] = 1;\n return mat;\n }\n Mat3.setIdentity = setIdentity;\n function toArray(a, out, offset) {\n out[offset + 0] = a[0];\n out[offset + 1] = a[1];\n out[offset + 2] = a[2];\n out[offset + 3] = a[3];\n out[offset + 4] = a[4];\n out[offset + 5] = a[5];\n out[offset + 6] = a[6];\n out[offset + 7] = a[7];\n out[offset + 8] = a[8];\n return out;\n }\n Mat3.toArray = toArray;\n function fromArray(a, array, offset) {\n a[0] = array[offset + 0];\n a[1] = array[offset + 1];\n a[2] = array[offset + 2];\n a[3] = array[offset + 3];\n a[4] = array[offset + 4];\n a[5] = array[offset + 5];\n a[6] = array[offset + 6];\n a[7] = array[offset + 7];\n a[8] = array[offset + 8];\n return a;\n }\n Mat3.fromArray = fromArray;\n function fromColumns(out, left, middle, right) {\n out[0] = left[0];\n out[1] = left[1];\n out[2] = left[2];\n out[3] = middle[0];\n out[4] = middle[1];\n out[5] = middle[2];\n out[6] = right[0];\n out[7] = right[1];\n out[8] = right[2];\n return out;\n }\n Mat3.fromColumns = fromColumns;\n /**\n * Copies the upper-left 3x3 values into the given mat3.\n */\n function fromMat4(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[4];\n out[4] = a[5];\n out[5] = a[6];\n out[6] = a[8];\n out[7] = a[9];\n out[8] = a[10];\n return out;\n }\n Mat3.fromMat4 = fromMat4;\n const _m4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n function fromEuler(out, euler, order) {\n Mat4.fromEuler(_m4, euler, order);\n return fromMat4(out, _m4);\n }\n Mat3.fromEuler = fromEuler;\n function create(a00, a01, a02, a10, a11, a12, a20, a21, a22) {\n const out = zero();\n out[0] = a00;\n out[1] = a01;\n out[2] = a02;\n out[3] = a10;\n out[4] = a11;\n out[5] = a12;\n out[6] = a20;\n out[7] = a21;\n out[8] = a22;\n return out;\n }\n Mat3.create = create;\n const _id = identity();\n function isIdentity(m, eps) {\n return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON : eps);\n }\n Mat3.isIdentity = isIdentity;\n function hasNaN(m) {\n for (let i = 0; i < 9; i++)\n if (isNaN(m[i]))\n return true;\n return false;\n }\n Mat3.hasNaN = hasNaN;\n /**\n * Creates a new Mat3 initialized with values from an existing matrix\n */\n function clone(a) {\n return copy(zero(), a);\n }\n Mat3.clone = clone;\n function areEqual(a, b, eps) {\n for (let i = 0; i < 9; i++) {\n if (Math.abs(a[i] - b[i]) > eps)\n return false;\n }\n return true;\n }\n Mat3.areEqual = areEqual;\n function setValue(a, i, j, value) {\n a[3 * j + i] = value;\n }\n Mat3.setValue = setValue;\n function getValue(a, i, j) {\n return a[3 * j + i];\n }\n Mat3.getValue = getValue;\n /**\n * Copy the values from one Mat3 to another\n */\n function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n return out;\n }\n Mat3.copy = copy;\n /**\n * Transpose the values of a Mat3\n */\n function transpose(out, a) {\n // If we are transposing ourselves we can skip a few steps but have to cache some values\n if (out === a) {\n const a01 = a[1], a02 = a[2], a12 = a[5];\n out[1] = a[3];\n out[2] = a[6];\n out[3] = a01;\n out[5] = a[7];\n out[6] = a02;\n out[7] = a12;\n }\n else {\n out[0] = a[0];\n out[1] = a[3];\n out[2] = a[6];\n out[3] = a[1];\n out[4] = a[4];\n out[5] = a[7];\n out[6] = a[2];\n out[7] = a[5];\n out[8] = a[8];\n }\n return out;\n }\n Mat3.transpose = transpose;\n /**\n * Inverts a Mat3\n */\n function invert(out, a) {\n const a00 = a[0], a01 = a[1], a02 = a[2];\n const a10 = a[3], a11 = a[4], a12 = a[5];\n const a20 = a[6], a21 = a[7], a22 = a[8];\n const b01 = a22 * a11 - a12 * a21;\n const b11 = -a22 * a10 + a12 * a20;\n const b21 = a21 * a10 - a11 * a20;\n // Calculate the determinant\n let det = a00 * b01 + a01 * b11 + a02 * b21;\n if (!det) {\n console.warn('non-invertible matrix.', a);\n return out;\n }\n det = 1.0 / det;\n out[0] = b01 * det;\n out[1] = (-a22 * a01 + a02 * a21) * det;\n out[2] = (a12 * a01 - a02 * a11) * det;\n out[3] = b11 * det;\n out[4] = (a22 * a00 - a02 * a20) * det;\n out[5] = (-a12 * a00 + a02 * a10) * det;\n out[6] = b21 * det;\n out[7] = (-a21 * a00 + a01 * a20) * det;\n out[8] = (a11 * a00 - a01 * a10) * det;\n return out;\n }\n Mat3.invert = invert;\n function symmtricFromUpper(out, a) {\n if (out === a) {\n out[3] = a[1];\n out[6] = a[2];\n out[7] = a[5];\n }\n else {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[1];\n out[4] = a[4];\n out[5] = a[5];\n out[6] = a[2];\n out[7] = a[5];\n out[8] = a[8];\n }\n return out;\n }\n Mat3.symmtricFromUpper = symmtricFromUpper;\n function symmtricFromLower(out, a) {\n if (out === a) {\n out[1] = a[3];\n out[2] = a[6];\n out[5] = a[7];\n }\n else {\n out[0] = a[0];\n out[1] = a[3];\n out[2] = a[6];\n out[3] = a[3];\n out[4] = a[4];\n out[5] = a[7];\n out[6] = a[6];\n out[7] = a[7];\n out[8] = a[8];\n }\n return out;\n }\n Mat3.symmtricFromLower = symmtricFromLower;\n function determinant(a) {\n const a00 = a[0], a01 = a[1], a02 = a[2];\n const a10 = a[3], a11 = a[4], a12 = a[5];\n const a20 = a[6], a21 = a[7], a22 = a[8];\n const b01 = a22 * a11 - a12 * a21;\n const b11 = -a22 * a10 + a12 * a20;\n const b21 = a21 * a10 - a11 * a20;\n // Calculate the determinant\n return a00 * b01 + a01 * b11 + a02 * b21;\n }\n Mat3.determinant = determinant;\n function trace(a) {\n return a[0] + a[4] + a[8];\n }\n Mat3.trace = trace;\n function sub(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n out[2] = a[2] - b[2];\n out[3] = a[3] - b[3];\n out[4] = a[4] - b[4];\n out[5] = a[5] - b[5];\n out[6] = a[6] - b[6];\n out[7] = a[7] - b[7];\n out[8] = a[8] - b[8];\n return out;\n }\n Mat3.sub = sub;\n function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n out[4] = a[4] + b[4];\n out[5] = a[5] + b[5];\n out[6] = a[6] + b[6];\n out[7] = a[7] + b[7];\n out[8] = a[8] + b[8];\n return out;\n }\n Mat3.add = add;\n function mul(out, a, b) {\n const a00 = a[0], a01 = a[1], a02 = a[2], a10 = a[3], a11 = a[4], a12 = a[5], a20 = a[6], a21 = a[7], a22 = a[8];\n const b00 = b[0], b01 = b[1], b02 = b[2], b10 = b[3], b11 = b[4], b12 = b[5], b20 = b[6], b21 = b[7], b22 = b[8];\n out[0] = b00 * a00 + b01 * a10 + b02 * a20;\n out[1] = b00 * a01 + b01 * a11 + b02 * a21;\n out[2] = b00 * a02 + b01 * a12 + b02 * a22;\n out[3] = b10 * a00 + b11 * a10 + b12 * a20;\n out[4] = b10 * a01 + b11 * a11 + b12 * a21;\n out[5] = b10 * a02 + b11 * a12 + b12 * a22;\n out[6] = b20 * a00 + b21 * a10 + b22 * a20;\n out[7] = b20 * a01 + b21 * a11 + b22 * a21;\n out[8] = b20 * a02 + b21 * a12 + b22 * a22;\n return out;\n }\n Mat3.mul = mul;\n function subScalar(out, a, s) {\n out[0] = a[0] - s;\n out[1] = a[1] - s;\n out[2] = a[2] - s;\n out[3] = a[3] - s;\n out[4] = a[4] - s;\n out[5] = a[5] - s;\n out[6] = a[6] - s;\n out[7] = a[7] - s;\n out[8] = a[8] - s;\n return out;\n }\n Mat3.subScalar = subScalar;\n function addScalar(out, a, s) {\n out[0] = a[0] + s;\n out[1] = a[1] + s;\n out[2] = a[2] + s;\n out[3] = a[3] + s;\n out[4] = a[4] + s;\n out[5] = a[5] + s;\n out[6] = a[6] + s;\n out[7] = a[7] + s;\n out[8] = a[8] + s;\n return out;\n }\n Mat3.addScalar = addScalar;\n function mulScalar(out, a, s) {\n out[0] = a[0] * s;\n out[1] = a[1] * s;\n out[2] = a[2] * s;\n out[3] = a[3] * s;\n out[4] = a[4] * s;\n out[5] = a[5] * s;\n out[6] = a[6] * s;\n out[7] = a[7] * s;\n out[8] = a[8] * s;\n return out;\n }\n Mat3.mulScalar = mulScalar;\n const piThird = Math.PI / 3;\n const tmpB = zero();\n /**\n * Given a real symmetric 3x3 matrix A, compute the eigenvalues\n *\n * From https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3.C3.973_matrices\n */\n function symmetricEigenvalues(out, a) {\n const p1 = a[1] * a[1] + a[2] * a[2] + a[5] * a[5];\n if (p1 === 0) {\n out[0] = a[0];\n out[1] = a[4];\n out[2] = a[8];\n }\n else {\n const q = trace(a) / 3;\n const a1 = a[0] - q;\n const a2 = a[4] - q;\n const a3 = a[8] - q;\n const p2 = a1 * a1 + a2 * a2 + a3 * a3 + 2 * p1;\n const p = Math.sqrt(p2 / 6);\n mulScalar(tmpB, Mat3.Identity, q);\n sub(tmpB, a, tmpB);\n mulScalar(tmpB, tmpB, (1 / p));\n const r = determinant(tmpB) / 2;\n // In exact arithmetic for a symmetric matrix -1 <= r <= 1\n // but computation error can leave it slightly outside this range.\n const phi = r <= -1 ? piThird : r >= 1 ?\n 0 : Math.acos(r) / 3;\n // the eigenvalues satisfy eig3 <= eig2 <= eig1\n out[0] = q + 2 * p * Math.cos(phi);\n out[2] = q + 2 * p * Math.cos(phi + (2 * piThird));\n out[1] = 3 * q - out[0] - out[2]; // since trace(A) = eig1 + eig2 + eig3\n }\n return out;\n }\n Mat3.symmetricEigenvalues = symmetricEigenvalues;\n const tmpR0 = [0.1, 0.0, 0.0];\n const tmpR1 = [0.1, 0.0, 0.0];\n const tmpR2 = [0.1, 0.0, 0.0];\n const tmpR0xR1 = [0.1, 0.0, 0.0];\n const tmpR0xR2 = [0.1, 0.0, 0.0];\n const tmpR1xR2 = [0.1, 0.0, 0.0];\n /**\n * Calculates the eigenvector for the given eigenvalue `e` of matrix `a`\n */\n function eigenvector(out, a, e) {\n Vec3.set(tmpR0, a[0] - e, a[1], a[2]);\n Vec3.set(tmpR1, a[1], a[4] - e, a[5]);\n Vec3.set(tmpR2, a[2], a[5], a[8] - e);\n Vec3.cross(tmpR0xR1, tmpR0, tmpR1);\n Vec3.cross(tmpR0xR2, tmpR0, tmpR2);\n Vec3.cross(tmpR1xR2, tmpR1, tmpR2);\n const d0 = Vec3.dot(tmpR0xR1, tmpR0xR1);\n const d1 = Vec3.dot(tmpR0xR2, tmpR0xR2);\n const d2 = Vec3.dot(tmpR1xR2, tmpR1xR2);\n let dmax = d0;\n let imax = 0;\n if (d1 > dmax) {\n dmax = d1;\n imax = 1;\n }\n if (d2 > dmax)\n imax = 2;\n if (imax === 0) {\n Vec3.scale(out, tmpR0xR1, 1 / Math.sqrt(d0));\n }\n else if (imax === 1) {\n Vec3.scale(out, tmpR0xR2, 1 / Math.sqrt(d1));\n }\n else {\n Vec3.scale(out, tmpR1xR2, 1 / Math.sqrt(d2));\n }\n return out;\n }\n Mat3.eigenvector = eigenvector;\n /**\n * Get matrix to transform directions, e.g. normals\n */\n function directionTransform(out, t) {\n fromMat4(out, t);\n invert(out, out);\n transpose(out, out);\n return out;\n }\n Mat3.directionTransform = directionTransform;\n Mat3.Identity = identity();\n /** Return the Frobenius inner product of two matrices (= dot product of the flattened matrices).\n * Can be used as a measure of similarity between two rotation matrices. */\n function innerProduct(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n + a[3] * b[3] + a[4] * b[4] + a[5] * b[5]\n + a[6] * b[6] + a[7] * b[7] + a[8] * b[8];\n }\n Mat3.innerProduct = innerProduct;\n})(Mat3 || (Mat3 = {}));\nexport { Mat3 };\n","/**\n * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author Alexander Rose \n */\nfunction Vec2() {\n return Vec2.zero();\n}\n(function (Vec2) {\n function zero() {\n // force double backing array by 0.1.\n const ret = [0.1, 0];\n ret[0] = 0.0;\n return ret;\n }\n Vec2.zero = zero;\n function clone(a) {\n const out = zero();\n out[0] = a[0];\n out[1] = a[1];\n return out;\n }\n Vec2.clone = clone;\n function create(x, y) {\n const out = zero();\n out[0] = x;\n out[1] = y;\n return out;\n }\n Vec2.create = create;\n function hasNaN(a) {\n return isNaN(a[0]) || isNaN(a[1]);\n }\n Vec2.hasNaN = hasNaN;\n function toArray(a, out, offset) {\n out[offset + 0] = a[0];\n out[offset + 1] = a[1];\n return out;\n }\n Vec2.toArray = toArray;\n function fromArray(a, array, offset) {\n a[0] = array[offset + 0];\n a[1] = array[offset + 1];\n return a;\n }\n Vec2.fromArray = fromArray;\n function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n return out;\n }\n Vec2.copy = copy;\n function set(out, x, y) {\n out[0] = x;\n out[1] = y;\n return out;\n }\n Vec2.set = set;\n function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n return out;\n }\n Vec2.add = add;\n function sub(out, a, b) {\n out[0] = a[0] - b[0];\n out[1] = a[1] - b[1];\n return out;\n }\n Vec2.sub = sub;\n function mul(out, a, b) {\n out[0] = a[0] * b[0];\n out[1] = a[1] * b[1];\n return out;\n }\n Vec2.mul = mul;\n function div(out, a, b) {\n out[0] = a[0] / b[0];\n out[1] = a[1] / b[1];\n return out;\n }\n Vec2.div = div;\n function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n return out;\n }\n Vec2.scale = scale;\n /**\n * Math.round the components of a Vec2\n */\n function round(out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n return out;\n }\n Vec2.round = round;\n /**\n * Math.ceil the components of a Vec2\n */\n function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n return out;\n }\n Vec2.ceil = ceil;\n /**\n * Math.floor the components of a Vec2\n */\n function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n return out;\n }\n Vec2.floor = floor;\n function distance(a, b) {\n const x = b[0] - a[0], y = b[1] - a[1];\n return Math.sqrt(x * x + y * y);\n }\n Vec2.distance = distance;\n function squaredDistance(a, b) {\n const x = b[0] - a[0], y = b[1] - a[1];\n return x * x + y * y;\n }\n Vec2.squaredDistance = squaredDistance;\n function magnitude(a) {\n const x = a[0], y = a[1];\n return Math.sqrt(x * x + y * y);\n }\n Vec2.magnitude = magnitude;\n function squaredMagnitude(a) {\n const x = a[0], y = a[1];\n return x * x + y * y;\n }\n Vec2.squaredMagnitude = squaredMagnitude;\n /**\n * Returns the inverse of the components of a Vec2\n */\n function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n return out;\n }\n Vec2.inverse = inverse;\n function areEqual(a, b) {\n return a[0] === b[0] && a[1] === b[1];\n }\n Vec2.areEqual = areEqual;\n function toString(a, precision) {\n return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)}}]`;\n }\n Vec2.toString = toString;\n})(Vec2 || (Vec2 = {}));\nexport { Vec2 };\n","/**\n * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport { EPSILON } from './common';\nfunction Vec4() {\n return Vec4.zero();\n}\n(function (Vec4) {\n function zero() {\n // force double backing array by 0.1.\n const ret = [0.1, 0, 0, 0];\n ret[0] = 0.0;\n return ret;\n }\n Vec4.zero = zero;\n function clone(a) {\n const out = zero();\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n }\n Vec4.clone = clone;\n function create(x, y, z, w) {\n const out = zero();\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n }\n Vec4.create = create;\n function fromSphere(out, sphere) {\n out[0] = sphere.center[0];\n out[1] = sphere.center[1];\n out[2] = sphere.center[2];\n out[3] = sphere.radius;\n return out;\n }\n Vec4.fromSphere = fromSphere;\n function ofSphere(sphere) {\n return fromSphere(zero(), sphere);\n }\n Vec4.ofSphere = ofSphere;\n function hasNaN(a) {\n return isNaN(a[0]) || isNaN(a[1]) || isNaN(a[2]) || isNaN(a[3]);\n }\n Vec4.hasNaN = hasNaN;\n function toArray(a, out, offset) {\n out[offset + 0] = a[0];\n out[offset + 1] = a[1];\n out[offset + 2] = a[2];\n out[offset + 3] = a[3];\n return out;\n }\n Vec4.toArray = toArray;\n function fromArray(a, array, offset) {\n a[0] = array[offset + 0];\n a[1] = array[offset + 1];\n a[2] = array[offset + 2];\n a[3] = array[offset + 3];\n return a;\n }\n Vec4.fromArray = fromArray;\n function toVec3Array(a, out, offset) {\n out[offset + 0] = a[0];\n out[offset + 1] = a[1];\n out[offset + 2] = a[2];\n }\n Vec4.toVec3Array = toVec3Array;\n function fromVec3Array(a, array, offset) {\n a[0] = array[offset + 0];\n a[1] = array[offset + 1];\n a[2] = array[offset + 2];\n a[3] = 0;\n return a;\n }\n Vec4.fromVec3Array = fromVec3Array;\n function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n }\n Vec4.copy = copy;\n function set(out, x, y, z, w) {\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n }\n Vec4.set = set;\n function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n return out;\n }\n Vec4.add = add;\n function distance(a, b) {\n const x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2], w = b[3] - a[3];\n return Math.sqrt(x * x + y * y + z * z + w * w);\n }\n Vec4.distance = distance;\n function scale(out, a, b) {\n out[0] = a[0] * b;\n out[1] = a[1] * b;\n out[2] = a[2] * b;\n out[4] = a[4] * b;\n return out;\n }\n Vec4.scale = scale;\n /**\n * Math.round the components of a Vec4\n */\n function round(out, a) {\n out[0] = Math.round(a[0]);\n out[1] = Math.round(a[1]);\n out[2] = Math.round(a[2]);\n out[3] = Math.round(a[3]);\n return out;\n }\n Vec4.round = round;\n /**\n * Math.ceil the components of a Vec4\n */\n function ceil(out, a) {\n out[0] = Math.ceil(a[0]);\n out[1] = Math.ceil(a[1]);\n out[2] = Math.ceil(a[2]);\n out[3] = Math.ceil(a[3]);\n return out;\n }\n Vec4.ceil = ceil;\n /**\n * Math.floor the components of a Vec3\n */\n function floor(out, a) {\n out[0] = Math.floor(a[0]);\n out[1] = Math.floor(a[1]);\n out[2] = Math.floor(a[2]);\n out[3] = Math.floor(a[3]);\n return out;\n }\n Vec4.floor = floor;\n function squaredDistance(a, b) {\n const x = b[0] - a[0], y = b[1] - a[1], z = b[2] - a[2], w = b[3] - a[3];\n return x * x + y * y + z * z + w * w;\n }\n Vec4.squaredDistance = squaredDistance;\n function norm(a) {\n const x = a[0], y = a[1], z = a[2], w = a[3];\n return Math.sqrt(x * x + y * y + z * z + w * w);\n }\n Vec4.norm = norm;\n function squaredNorm(a) {\n const x = a[0], y = a[1], z = a[2], w = a[3];\n return x * x + y * y + z * z + w * w;\n }\n Vec4.squaredNorm = squaredNorm;\n function transformMat4(out, a, m) {\n const x = a[0], y = a[1], z = a[2], w = a[3];\n out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;\n out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;\n out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;\n out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;\n return out;\n }\n Vec4.transformMat4 = transformMat4;\n function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];\n }\n Vec4.dot = dot;\n /**\n * Returns the inverse of the components of a Vec4\n */\n function inverse(out, a) {\n out[0] = 1.0 / a[0];\n out[1] = 1.0 / a[1];\n out[2] = 1.0 / a[2];\n out[3] = 1.0 / a[3];\n return out;\n }\n Vec4.inverse = inverse;\n /**\n * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)\n */\n function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\n }\n Vec4.exactEquals = exactEquals;\n /**\n * Returns whether or not the vectors have approximately the same elements in the same position.\n */\n function equals(a, b) {\n const a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n const b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));\n }\n Vec4.equals = equals;\n function toString(a, precision) {\n return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)} ${a[3].toPrecision(precision)}]`;\n }\n Vec4.toString = toString;\n})(Vec4 || (Vec4 = {}));\nexport { Vec4 };\n","/**\n * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author Alexander Rose \n * @author David Sehnal \n */\nexport function ObjectKeys(o) {\n return Object.keys(o);\n}\n;\nexport function assertUnreachable(x) {\n throw new Error('unreachable');\n}\nexport function isPromiseLike(x) {\n return typeof (x === null || x === void 0 ? void 0 : x.then) === 'function';\n}\n","/**\n * Copyright (c) 2017-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport { Vec3 } from './vec3';\nimport { EPSILON } from './common';\nimport { assertUnreachable } from '../../../mol-util/type-helpers';\nfunction Quat() {\n return Quat.zero();\n}\n(function (Quat) {\n function zero() {\n // force double backing array by 0.1.\n const ret = [0.1, 0, 0, 0];\n ret[0] = 0.0;\n return ret;\n }\n Quat.zero = zero;\n function identity() {\n const out = zero();\n out[3] = 1;\n return out;\n }\n Quat.identity = identity;\n function setIdentity(out) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n }\n Quat.setIdentity = setIdentity;\n function hasNaN(q) {\n return isNaN(q[0]) || isNaN(q[1]) || isNaN(q[2]) || isNaN(q[3]);\n }\n Quat.hasNaN = hasNaN;\n function create(x, y, z, w) {\n const out = identity();\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n }\n Quat.create = create;\n function setAxisAngle(out, axis, rad) {\n rad = rad * 0.5;\n const s = Math.sin(rad);\n out[0] = s * axis[0];\n out[1] = s * axis[1];\n out[2] = s * axis[2];\n out[3] = Math.cos(rad);\n return out;\n }\n Quat.setAxisAngle = setAxisAngle;\n /**\n * Gets the rotation axis and angle for a given\n * quaternion. If a quaternion is created with\n * setAxisAngle, this method will return the same\n * values as providied in the original parameter list\n * OR functionally equivalent values.\n * Example: The quaternion formed by axis [0, 0, 1] and\n * angle -90 is the same as the quaternion formed by\n * [0, 0, 1] and 270. This method favors the latter.\n */\n function getAxisAngle(out_axis, q) {\n const rad = Math.acos(q[3]) * 2.0;\n const s = Math.sin(rad / 2.0);\n if (s !== 0.0) {\n out_axis[0] = q[0] / s;\n out_axis[1] = q[1] / s;\n out_axis[2] = q[2] / s;\n }\n else {\n // If s is zero, return any axis (no rotation - axis does not matter)\n out_axis[0] = 1;\n out_axis[1] = 0;\n out_axis[2] = 0;\n }\n return rad;\n }\n Quat.getAxisAngle = getAxisAngle;\n function multiply(out, a, b) {\n const ax = a[0], ay = a[1], az = a[2], aw = a[3];\n const bx = b[0], by = b[1], bz = b[2], bw = b[3];\n out[0] = ax * bw + aw * bx + ay * bz - az * by;\n out[1] = ay * bw + aw * by + az * bx - ax * bz;\n out[2] = az * bw + aw * bz + ax * by - ay * bx;\n out[3] = aw * bw - ax * bx - ay * by - az * bz;\n return out;\n }\n Quat.multiply = multiply;\n function rotateX(out, a, rad) {\n rad *= 0.5;\n const ax = a[0], ay = a[1], az = a[2], aw = a[3];\n const bx = Math.sin(rad), bw = Math.cos(rad);\n out[0] = ax * bw + aw * bx;\n out[1] = ay * bw + az * bx;\n out[2] = az * bw - ay * bx;\n out[3] = aw * bw - ax * bx;\n return out;\n }\n Quat.rotateX = rotateX;\n function rotateY(out, a, rad) {\n rad *= 0.5;\n const ax = a[0], ay = a[1], az = a[2], aw = a[3];\n const by = Math.sin(rad), bw = Math.cos(rad);\n out[0] = ax * bw - az * by;\n out[1] = ay * bw + aw * by;\n out[2] = az * bw + ax * by;\n out[3] = aw * bw - ay * by;\n return out;\n }\n Quat.rotateY = rotateY;\n function rotateZ(out, a, rad) {\n rad *= 0.5;\n const ax = a[0], ay = a[1], az = a[2], aw = a[3];\n const bz = Math.sin(rad), bw = Math.cos(rad);\n out[0] = ax * bw + ay * bz;\n out[1] = ay * bw - ax * bz;\n out[2] = az * bw + aw * bz;\n out[3] = aw * bw - az * bz;\n return out;\n }\n Quat.rotateZ = rotateZ;\n /**\n * Calculates the W component of a quat from the X, Y, and Z components.\n * Assumes that quaternion is 1 unit in length.\n * Any existing W component will be ignored.\n */\n function calculateW(out, a) {\n const x = a[0], y = a[1], z = a[2];\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));\n return out;\n }\n Quat.calculateW = calculateW;\n /**\n * Performs a spherical linear interpolation between two quat\n */\n function slerp(out, a, b, t) {\n // benchmarks:\n // http://jsperf.com/quaternion-slerp-implementations\n const ax = a[0], ay = a[1], az = a[2], aw = a[3];\n let bx = b[0], by = b[1], bz = b[2], bw = b[3];\n let omega, cosom, sinom, scale0, scale1;\n // calc cosine\n cosom = ax * bx + ay * by + az * bz + aw * bw;\n // adjust signs (if necessary)\n if (cosom < 0.0) {\n cosom = -cosom;\n bx = -bx;\n by = -by;\n bz = -bz;\n bw = -bw;\n }\n // calculate coefficients\n if ((1.0 - cosom) > 0.000001) {\n // standard case (slerp)\n omega = Math.acos(cosom);\n sinom = Math.sin(omega);\n scale0 = Math.sin((1.0 - t) * omega) / sinom;\n scale1 = Math.sin(t * omega) / sinom;\n }\n else {\n // \"from\" and \"to\" quaternions are very close\n // ... so we can do a linear interpolation\n scale0 = 1.0 - t;\n scale1 = t;\n }\n // calculate final values\n out[0] = scale0 * ax + scale1 * bx;\n out[1] = scale0 * ay + scale1 * by;\n out[2] = scale0 * az + scale1 * bz;\n out[3] = scale0 * aw + scale1 * bw;\n return out;\n }\n Quat.slerp = slerp;\n function invert(out, a) {\n const a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n const dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;\n const invDot = dot ? 1.0 / dot : 0;\n // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0\n out[0] = -a0 * invDot;\n out[1] = -a1 * invDot;\n out[2] = -a2 * invDot;\n out[3] = a3 * invDot;\n return out;\n }\n Quat.invert = invert;\n /**\n * Calculates the conjugate of a quat\n * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.\n */\n function conjugate(out, a) {\n out[0] = -a[0];\n out[1] = -a[1];\n out[2] = -a[2];\n out[3] = a[3];\n return out;\n }\n Quat.conjugate = conjugate;\n function dot(a, b) {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];\n }\n Quat.dot = dot;\n /**\n * Creates a quaternion from the given 3x3 rotation matrix.\n *\n * NOTE: The resultant quaternion is not normalized, so you should be sure\n * to renormalize the quaternion yourself where necessary.\n */\n function fromMat3(out, m) {\n // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes\n // article \"Quaternion Calculus and Fast Animation\".\n const fTrace = m[0] + m[4] + m[8];\n let fRoot;\n if (fTrace > 0.0) {\n // |w| > 1/2, may as well choose w > 1/2\n fRoot = Math.sqrt(fTrace + 1.0); // 2w\n out[3] = 0.5 * fRoot;\n fRoot = 0.5 / fRoot; // 1/(4w)\n out[0] = (m[5] - m[7]) * fRoot;\n out[1] = (m[6] - m[2]) * fRoot;\n out[2] = (m[1] - m[3]) * fRoot;\n }\n else {\n // |w| <= 1/2\n let i = 0;\n if (m[4] > m[0])\n i = 1;\n if (m[8] > m[i * 3 + i])\n i = 2;\n const j = (i + 1) % 3;\n const k = (i + 2) % 3;\n fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);\n out[i] = 0.5 * fRoot;\n fRoot = 0.5 / fRoot;\n out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;\n out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;\n out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;\n }\n return out;\n }\n Quat.fromMat3 = fromMat3;\n function fromEuler(out, euler, order) {\n const [x, y, z] = euler;\n // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m\n const c1 = Math.cos(x / 2);\n const c2 = Math.cos(y / 2);\n const c3 = Math.cos(z / 2);\n const s1 = Math.sin(x / 2);\n const s2 = Math.sin(y / 2);\n const s3 = Math.sin(z / 2);\n switch (order) {\n case 'XYZ':\n out[0] = s1 * c2 * c3 + c1 * s2 * s3;\n out[1] = c1 * s2 * c3 - s1 * c2 * s3;\n out[2] = c1 * c2 * s3 + s1 * s2 * c3;\n out[3] = c1 * c2 * c3 - s1 * s2 * s3;\n break;\n case 'YXZ':\n out[0] = s1 * c2 * c3 + c1 * s2 * s3;\n out[1] = c1 * s2 * c3 - s1 * c2 * s3;\n out[2] = c1 * c2 * s3 - s1 * s2 * c3;\n out[3] = c1 * c2 * c3 + s1 * s2 * s3;\n break;\n case 'ZXY':\n out[0] = s1 * c2 * c3 - c1 * s2 * s3;\n out[1] = c1 * s2 * c3 + s1 * c2 * s3;\n out[2] = c1 * c2 * s3 + s1 * s2 * c3;\n out[3] = c1 * c2 * c3 - s1 * s2 * s3;\n break;\n case 'ZYX':\n out[0] = s1 * c2 * c3 - c1 * s2 * s3;\n out[1] = c1 * s2 * c3 + s1 * c2 * s3;\n out[2] = c1 * c2 * s3 - s1 * s2 * c3;\n out[3] = c1 * c2 * c3 + s1 * s2 * s3;\n break;\n case 'YZX':\n out[0] = s1 * c2 * c3 + c1 * s2 * s3;\n out[1] = c1 * s2 * c3 + s1 * c2 * s3;\n out[2] = c1 * c2 * s3 - s1 * s2 * c3;\n out[3] = c1 * c2 * c3 - s1 * s2 * s3;\n break;\n case 'XZY':\n out[0] = s1 * c2 * c3 - c1 * s2 * s3;\n out[1] = c1 * s2 * c3 - s1 * c2 * s3;\n out[2] = c1 * c2 * s3 + s1 * s2 * c3;\n out[3] = c1 * c2 * c3 + s1 * s2 * s3;\n break;\n default:\n assertUnreachable(order);\n }\n return out;\n }\n Quat.fromEuler = fromEuler;\n const fromUnitVec3Temp = [0, 0, 0];\n /** Quaternion from two normalized unit vectors. */\n function fromUnitVec3(out, a, b) {\n // assumes a and b are normalized\n let r = Vec3.dot(a, b) + 1;\n if (r < EPSILON) {\n // If u and v are exactly opposite, rotate 180 degrees\n // around an arbitrary orthogonal axis. Axis normalisation\n // can happen later, when we normalise the quaternion.\n r = 0;\n if (Math.abs(a[0]) > Math.abs(a[2])) {\n Vec3.set(fromUnitVec3Temp, -a[1], a[0], 0);\n }\n else {\n Vec3.set(fromUnitVec3Temp, 0, -a[2], a[1]);\n }\n }\n else {\n // Otherwise, build quaternion the standard way.\n Vec3.cross(fromUnitVec3Temp, a, b);\n }\n out[0] = fromUnitVec3Temp[0];\n out[1] = fromUnitVec3Temp[1];\n out[2] = fromUnitVec3Temp[2];\n out[3] = r;\n normalize(out, out);\n return out;\n }\n Quat.fromUnitVec3 = fromUnitVec3;\n function clone(a) {\n const out = zero();\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n }\n Quat.clone = clone;\n function toArray(a, out, offset) {\n out[offset + 0] = a[0];\n out[offset + 1] = a[1];\n out[offset + 2] = a[2];\n out[offset + 3] = a[3];\n return out;\n }\n Quat.toArray = toArray;\n function fromArray(a, array, offset) {\n a[0] = array[offset + 0];\n a[1] = array[offset + 1];\n a[2] = array[offset + 2];\n a[3] = array[offset + 3];\n return a;\n }\n Quat.fromArray = fromArray;\n function copy(out, a) {\n out[0] = a[0];\n out[1] = a[1];\n out[2] = a[2];\n out[3] = a[3];\n return out;\n }\n Quat.copy = copy;\n function set(out, x, y, z, w) {\n out[0] = x;\n out[1] = y;\n out[2] = z;\n out[3] = w;\n return out;\n }\n Quat.set = set;\n /**\n * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)\n */\n function exactEquals(a, b) {\n return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];\n }\n Quat.exactEquals = exactEquals;\n /**\n * Returns whether or not the quaternions have approximately the same elements in the same position.\n */\n function equals(a, b) {\n const a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];\n const b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];\n return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&\n Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&\n Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&\n Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));\n }\n Quat.equals = equals;\n function add(out, a, b) {\n out[0] = a[0] + b[0];\n out[1] = a[1] + b[1];\n out[2] = a[2] + b[2];\n out[3] = a[3] + b[3];\n return out;\n }\n Quat.add = add;\n function normalize(out, a) {\n const x = a[0];\n const y = a[1];\n const z = a[2];\n const w = a[3];\n let len = x * x + y * y + z * z + w * w;\n if (len > 0) {\n len = 1 / Math.sqrt(len);\n out[0] = x * len;\n out[1] = y * len;\n out[2] = z * len;\n out[3] = w * len;\n }\n return out;\n }\n Quat.normalize = normalize;\n /**\n * Sets a quaternion to represent the shortest rotation from one\n * vector to another.\n *\n * Both vectors are assumed to be unit length.\n */\n const rotTmpVec3 = [0, 0, 0];\n const rotTmpVec3UnitX = [1, 0, 0];\n const rotTmpVec3UnitY = [0, 1, 0];\n function rotationTo(out, a, b) {\n const dot = Vec3.dot(a, b);\n if (dot < -0.999999) {\n Vec3.cross(rotTmpVec3, rotTmpVec3UnitX, a);\n if (Vec3.magnitude(rotTmpVec3) < 0.000001)\n Vec3.cross(rotTmpVec3, rotTmpVec3UnitY, a);\n Vec3.normalize(rotTmpVec3, rotTmpVec3);\n setAxisAngle(out, rotTmpVec3, Math.PI);\n return out;\n }\n else if (dot > 0.999999) {\n out[0] = 0;\n out[1] = 0;\n out[2] = 0;\n out[3] = 1;\n return out;\n }\n else {\n Vec3.cross(rotTmpVec3, a, b);\n out[0] = rotTmpVec3[0];\n out[1] = rotTmpVec3[1];\n out[2] = rotTmpVec3[2];\n out[3] = 1 + dot;\n return normalize(out, out);\n }\n }\n Quat.rotationTo = rotationTo;\n /**\n * Performs a spherical linear interpolation with two control points\n */\n const sqlerpTemp1 = zero();\n const sqlerpTemp2 = zero();\n function sqlerp(out, a, b, c, d, t) {\n slerp(sqlerpTemp1, a, d, t);\n slerp(sqlerpTemp2, b, c, t);\n slerp(out, sqlerpTemp1, sqlerpTemp2, 2 * t * (1 - t));\n return out;\n }\n Quat.sqlerp = sqlerp;\n /**\n * Sets the specified quaternion with values corresponding to the given\n * axes. Each axis is a vec3 and is expected to be unit length and\n * perpendicular to all other specified axes.\n */\n const axesTmpMat = [0, 0, 0, 0, 0, 0, 0, 0, 0];\n function setAxes(out, view, right, up) {\n axesTmpMat[0] = right[0];\n axesTmpMat[3] = right[1];\n axesTmpMat[6] = right[2];\n axesTmpMat[1] = up[0];\n axesTmpMat[4] = up[1];\n axesTmpMat[7] = up[2];\n axesTmpMat[2] = -view[0];\n axesTmpMat[5] = -view[1];\n axesTmpMat[8] = -view[2];\n return normalize(out, fromMat3(out, axesTmpMat));\n }\n Quat.setAxes = setAxes;\n function toString(a, precision) {\n return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)} ${a[3].toPrecision(precision)}]`;\n }\n Quat.toString = toString;\n Quat.Identity = identity();\n})(Quat || (Quat = {}));\nexport { Quat };\n","import { Mat3 } from './3d/mat3';\n/**\n * Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport { Mat4 } from './3d/mat4';\nexport var Tensor;\n(function (Tensor) {\n function Layout(dimensions, axisOrderSlowToFast, ctor) {\n // need to reverse the axis order for better access.\n const axisOrderFastToSlow = [];\n for (let i = 0; i < axisOrderSlowToFast.length; i++)\n axisOrderFastToSlow[i] = axisOrderSlowToFast[axisOrderSlowToFast.length - i - 1];\n const accessDimensions = [1];\n for (let i = 1; i < dimensions.length; i++)\n accessDimensions[i] = dimensions[axisOrderFastToSlow[i - 1]];\n return { dimensions, axisOrderFastToSlow, axisOrderSlowToFast, accessDimensions, defaultCtor: ctor || Float64Array };\n }\n function create(space, data) { return { space, data }; }\n Tensor.create = create;\n function Space(dimensions, axisOrderSlowToFast, ctor) {\n const layout = Layout(dimensions, axisOrderSlowToFast, ctor);\n const { get, set, add, dataOffset, getCoords } = accessors(layout);\n return { rank: dimensions.length, dimensions, axisOrderSlowToFast, create: creator(layout), get, set, add, dataOffset, getCoords };\n }\n Tensor.Space = Space;\n function Data1(values) { return values; }\n Tensor.Data1 = Data1;\n function Vector(d, ctor) { return Space([d], [0], ctor); }\n Tensor.Vector = Vector;\n function ColumnMajorMatrix(rows, cols, ctor) { return Space([rows, cols], [1, 0], ctor); }\n Tensor.ColumnMajorMatrix = ColumnMajorMatrix;\n function RowMajorMatrix(rows, cols, ctor) { return Space([rows, cols], [0, 1], ctor); }\n Tensor.RowMajorMatrix = RowMajorMatrix;\n function toMat4(out, space, data) {\n if (space.rank !== 2)\n throw new Error('Invalid tensor rank');\n const d0 = Math.min(4, space.dimensions[0]), d1 = Math.min(4, space.dimensions[1]);\n for (let i = 0; i < d0; i++) {\n for (let j = 0; j < d1; j++)\n Mat4.setValue(out, i, j, space.get(data, i, j));\n }\n return out;\n }\n Tensor.toMat4 = toMat4;\n function toMat3(out, space, data) {\n if (space.rank !== 2)\n throw new Error('Invalid tensor rank');\n const d0 = Math.min(3, space.dimensions[0]), d1 = Math.min(3, space.dimensions[1]);\n for (let i = 0; i < d0; i++) {\n for (let j = 0; j < d1; j++)\n Mat3.setValue(out, i, j, space.get(data, i, j));\n }\n return out;\n }\n Tensor.toMat3 = toMat3;\n function toVec3(out, space, data) {\n if (space.rank !== 1)\n throw new Error('Invalid tensor rank');\n const d0 = Math.min(3, space.dimensions[0]);\n for (let i = 0; i < d0; i++)\n out[i] = data[i];\n return out;\n }\n Tensor.toVec3 = toVec3;\n function toVec4(out, space, data) {\n if (space.rank !== 1)\n throw new Error('Invalid tensor rank');\n const d0 = Math.min(4, space.dimensions[0]);\n for (let i = 0; i < d0; i++)\n out[i] = data[i];\n return out;\n }\n Tensor.toVec4 = toVec4;\n function areEqualExact(a, b) {\n const len = a.length;\n if (len !== b.length)\n return false;\n for (let i = 0; i < len; i++)\n if (a[i] !== b[i])\n return false;\n return true;\n }\n Tensor.areEqualExact = areEqualExact;\n function accessors(layout) {\n const { dimensions, axisOrderFastToSlow: ao } = layout;\n switch (dimensions.length) {\n case 1: return {\n get: (t, d) => t[d],\n set: (t, d, x) => t[d] = x,\n add: (t, d, x) => t[d] += x,\n dataOffset: (d) => d,\n getCoords: (o, c) => {\n c[0] = o;\n return c;\n }\n };\n case 2: {\n // column major\n if (ao[0] === 0 && ao[1] === 1) {\n const rows = dimensions[0];\n return {\n get: (t, i, j) => t[j * rows + i],\n set: (t, i, j, x) => t[j * rows + i] = x,\n add: (t, i, j, x) => t[j * rows + i] += x,\n dataOffset: (i, j) => j * rows + i,\n getCoords: (o, c) => {\n c[0] = o % rows;\n c[1] = Math.floor(o / rows);\n return c;\n }\n };\n }\n if (ao[0] === 1 && ao[1] === 0) {\n const cols = dimensions[1];\n return {\n get: (t, i, j) => t[i * cols + j],\n set: (t, i, j, x) => t[i * cols + j] = x,\n add: (t, i, j, x) => t[i * cols + j] += x,\n dataOffset: (i, j) => i * cols + j,\n getCoords: (o, c) => {\n c[0] = Math.floor(o / cols);\n c[1] = o % cols;\n return c;\n }\n };\n }\n throw new Error('bad axis order');\n }\n case 3: {\n if (ao[0] === 0 && ao[1] === 1 && ao[2] === 2) { // 012 ijk\n const u = dimensions[0], v = dimensions[1], uv = u * v;\n return {\n get: (t, i, j, k) => t[i + j * u + k * uv],\n set: (t, i, j, k, x) => t[i + j * u + k * uv] = x,\n add: (t, i, j, k, x) => t[i + j * u + k * uv] += x,\n dataOffset: (i, j, k) => i + j * u + k * uv,\n getCoords: (o, c) => {\n const p = Math.floor(o / u);\n c[0] = o % u;\n c[1] = p % v;\n c[2] = Math.floor(p / v);\n return c;\n }\n };\n }\n if (ao[0] === 0 && ao[1] === 2 && ao[2] === 1) { // 021 ikj\n const u = dimensions[0], v = dimensions[2], uv = u * v;\n return {\n get: (t, i, j, k) => t[i + k * u + j * uv],\n set: (t, i, j, k, x) => t[i + k * u + j * uv] = x,\n add: (t, i, j, k, x) => t[i + k * u + j * uv] += x,\n dataOffset: (i, j, k) => i + k * u + j * uv,\n getCoords: (o, c) => {\n const p = Math.floor(o / u);\n c[0] = o % u;\n c[1] = Math.floor(p / v);\n c[2] = p % v;\n return c;\n }\n };\n }\n if (ao[0] === 1 && ao[1] === 0 && ao[2] === 2) { // 102 jik\n const u = dimensions[1], v = dimensions[0], uv = u * v;\n return {\n get: (t, i, j, k) => t[j + i * u + k * uv],\n set: (t, i, j, k, x) => t[j + i * u + k * uv] = x,\n add: (t, i, j, k, x) => t[j + i * u + k * uv] += x,\n dataOffset: (i, j, k) => j + i * u + k * uv,\n getCoords: (o, c) => {\n const p = Math.floor(o / u);\n c[0] = p % v;\n c[1] = o % u;\n c[2] = Math.floor(p / v);\n return c;\n }\n };\n }\n if (ao[0] === 1 && ao[1] === 2 && ao[2] === 0) { // 120 jki\n const u = dimensions[1], v = dimensions[2], uv = u * v;\n return {\n get: (t, i, j, k) => t[j + k * u + i * uv],\n set: (t, i, j, k, x) => t[j + k * u + i * uv] = x,\n add: (t, i, j, k, x) => t[j + k * u + i * uv] += x,\n dataOffset: (i, j, k) => j + k * u + i * uv,\n getCoords: (o, c) => {\n const p = Math.floor(o / u);\n c[0] = Math.floor(p / v);\n c[1] = o % u;\n c[2] = p % v;\n return c;\n }\n };\n }\n if (ao[0] === 2 && ao[1] === 0 && ao[2] === 1) { // 201 kij\n const u = dimensions[2], v = dimensions[0], uv = u * v;\n return {\n get: (t, i, j, k) => t[k + i * u + j * uv],\n set: (t, i, j, k, x) => t[k + i * u + j * uv] = x,\n add: (t, i, j, k, x) => t[k + i * u + j * uv] += x,\n dataOffset: (i, j, k) => k + i * u + j * uv,\n getCoords: (o, c) => {\n const p = Math.floor(o / u);\n c[0] = p % v;\n c[1] = Math.floor(p / v);\n c[2] = o % u;\n return c;\n }\n };\n }\n if (ao[0] === 2 && ao[1] === 1 && ao[2] === 0) { // 210 kji\n const u = dimensions[2], v = dimensions[1], uv = u * v;\n return {\n get: (t, i, j, k) => t[k + j * u + i * uv],\n set: (t, i, j, k, x) => t[k + j * u + i * uv] = x,\n add: (t, i, j, k, x) => t[k + j * u + i * uv] += x,\n dataOffset: (i, j, k) => k + j * u + i * uv,\n getCoords: (o, c) => {\n const p = Math.floor(o / u);\n c[0] = Math.floor(p / v);\n c[1] = p % v;\n c[2] = o % u;\n return c;\n }\n };\n }\n throw new Error('bad axis order');\n }\n default: return {\n get: (t, ...c) => t[dataOffset(layout, c)],\n set: (t, ...c) => t[dataOffset(layout, c)] = c[c.length - 1],\n add: (t, ...c) => t[dataOffset(layout, c)] += c[c.length - 1],\n dataOffset: (...c) => dataOffset(layout, c),\n getCoords: (o, c) => getCoords(layout, o, c),\n };\n }\n }\n function creator(layout) {\n const { dimensions: ds } = layout;\n let size = 1;\n for (let i = 0, _i = ds.length; i < _i; i++)\n size *= ds[i];\n return ctor => new (ctor || layout.defaultCtor)(size);\n }\n function dataOffset(layout, coord) {\n const { accessDimensions: acc, axisOrderFastToSlow: ao } = layout;\n const d = acc.length - 1;\n let o = acc[d] * coord[ao[d]];\n for (let i = d - 1; i >= 0; i--) {\n o = (o + coord[ao[i]]) * acc[i];\n }\n return o;\n }\n function getCoords(layout, o, coords) {\n const { dimensions: dim, axisOrderFastToSlow: ao } = layout;\n const d = dim.length;\n let c = o;\n for (let i = 0; i < d; i++) {\n const d = dim[ao[i]];\n coords[ao[i]] = c % d;\n c = Math.floor(c / d);\n }\n coords[ao[d + 1]] = c;\n return coords;\n }\n // Convers \"slow to fast\" axis order to \"fast to slow\" and vice versa.\n function invertAxisOrder(v) {\n const ret = [];\n for (let i = 0; i < v.length; i++) {\n ret[i] = v[v.length - i - 1];\n }\n return ret;\n }\n Tensor.invertAxisOrder = invertAxisOrder;\n function reorder(xs, indices) {\n const ret = [];\n for (let i = 0; i < xs.length; i++)\n ret[i] = xs[indices[i]];\n return ret;\n }\n function convertToCanonicalAxisIndicesFastToSlow(order) {\n const indices = new Int32Array(order.length);\n for (let i = 0; i < order.length; i++)\n indices[order[i]] = i;\n return (xs) => reorder(xs, indices);\n }\n Tensor.convertToCanonicalAxisIndicesFastToSlow = convertToCanonicalAxisIndicesFastToSlow;\n function convertToCanonicalAxisIndicesSlowToFast(order) {\n const indices = new Int32Array(order.length);\n for (let i = 0; i < order.length; i++)\n indices[order[order.length - i - 1]] = i;\n return (xs) => reorder(xs, indices);\n }\n Tensor.convertToCanonicalAxisIndicesSlowToFast = convertToCanonicalAxisIndicesSlowToFast;\n})(Tensor || (Tensor = {}));\n","/**\n * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport * as ColumnHelpers from './column-helpers';\nimport { Tensor as Tensors } from '../../mol-math/linear-algebra';\nimport { parseInt as fastParseInt, parseFloat as fastParseFloat } from '../../mol-io/reader/common/text/number-parser';\nvar Column;\n(function (Column) {\n let Schema;\n (function (Schema) {\n // T also serves as a default value for undefined columns\n Schema.str = { '@type': 'str', T: '', valueType: 'str' };\n Schema.ustr = { '@type': 'str', T: '', valueType: 'str', transform: 'uppercase' };\n Schema.lstr = { '@type': 'str', T: '', valueType: 'str', transform: 'lowercase' };\n Schema.int = { '@type': 'int', T: 0, valueType: 'int' };\n Schema.coord = { '@type': 'coord', T: 0, valueType: 'float' };\n Schema.float = { '@type': 'float', T: 0, valueType: 'float' };\n function Str(options) { var _a; return { '@type': 'str', T: (_a = options === null || options === void 0 ? void 0 : options.defaultValue) !== null && _a !== void 0 ? _a : '', transform: options === null || options === void 0 ? void 0 : options.transform, valueType: 'str' }; }\n Schema.Str = Str;\n ;\n function Int(defaultValue = 0) { return { '@type': 'int', T: defaultValue, valueType: 'int' }; }\n Schema.Int = Int;\n ;\n function Float(defaultValue = 0) { return { '@type': 'float', T: defaultValue, valueType: 'float' }; }\n Schema.Float = Float;\n ;\n function Tensor(space, baseType = Schema.float) { return { '@type': 'tensor', T: space.create(), space, valueType: 'tensor', baseType }; }\n Schema.Tensor = Tensor;\n function Vector(dim, baseType = Schema.float) { return Tensor(Tensors.Vector(dim, baseType['@type'] === 'int' ? Int32Array : Float64Array), baseType); }\n Schema.Vector = Vector;\n function Matrix(rows, cols, baseType = Schema.float) { return Tensor(Tensors.ColumnMajorMatrix(rows, cols, baseType['@type'] === 'int' ? Int32Array : Float64Array), baseType); }\n Schema.Matrix = Matrix;\n function Aliased(t) {\n return t;\n }\n Schema.Aliased = Aliased;\n function List(separator, itemParse, defaultValue = []) {\n return { '@type': 'list', T: defaultValue, separator, itemParse, valueType: 'list' };\n }\n Schema.List = List;\n })(Schema = Column.Schema || (Column.Schema = {}));\n function is(v) {\n return !!v && !!v.schema && !!v.value;\n }\n Column.is = is;\n Column.ValueKind = {\n /** Defined value (= 0) */\n Present: 0 /* ValueKinds.Present */,\n /** Expressed in CIF as `.` (= 1) */\n NotPresent: 1 /* ValueKinds.NotPresent */,\n /** Expressed in CIF as `?` (= 2) */\n Unknown: 2 /* ValueKinds.Unknown */\n };\n function Undefined(rowCount, schema) {\n return constColumn(schema['T'], rowCount, schema, 1 /* ValueKinds.NotPresent */);\n }\n Column.Undefined = Undefined;\n function ofConst(v, rowCount, type) {\n return constColumn(v, rowCount, type, 0 /* ValueKinds.Present */);\n }\n Column.ofConst = ofConst;\n function ofLambda(spec) {\n return lambdaColumn(spec);\n }\n Column.ofLambda = ofLambda;\n /** values [min, max] (i.e. include both values) */\n function range(min, max) {\n return ofLambda({\n value: i => i + min,\n rowCount: Math.max(max - min + 1, 0),\n schema: Schema.int\n });\n }\n Column.range = range;\n function ofArray(spec) {\n return arrayColumn(spec);\n }\n Column.ofArray = ofArray;\n function ofIntArray(array) {\n return arrayColumn({ array, schema: Schema.int });\n }\n Column.ofIntArray = ofIntArray;\n function ofFloatArray(array) {\n return arrayColumn({ array, schema: Schema.float });\n }\n Column.ofFloatArray = ofFloatArray;\n function ofStringArray(array) {\n return arrayColumn({ array, schema: Schema.str });\n }\n Column.ofStringArray = ofStringArray;\n function ofStringAliasArray(array) {\n return arrayColumn({ array, schema: Schema.Aliased(Schema.str) });\n }\n Column.ofStringAliasArray = ofStringAliasArray;\n function ofStringListArray(array, separator = ',') {\n return arrayColumn({ array, schema: Schema.List(separator, x => x) });\n }\n Column.ofStringListArray = ofStringListArray;\n function ofIntTokens(tokens) {\n const { count, data, indices } = tokens;\n return lambdaColumn({\n value: (row) => fastParseInt(data, indices[2 * row], indices[2 * row + 1]) || 0,\n rowCount: count,\n schema: Schema.int,\n });\n }\n Column.ofIntTokens = ofIntTokens;\n function ofFloatTokens(tokens) {\n const { count, data, indices } = tokens;\n return lambdaColumn({\n value: (row) => fastParseFloat(data, indices[2 * row], indices[2 * row + 1]) || 0,\n rowCount: count,\n schema: Schema.float,\n });\n }\n Column.ofFloatTokens = ofFloatTokens;\n function ofStringTokens(tokens) {\n const { count, data, indices } = tokens;\n return lambdaColumn({\n value: (row) => {\n const ret = data.substring(indices[2 * row], indices[2 * row + 1]);\n if (ret === '.' || ret === '?')\n return '';\n return ret;\n },\n rowCount: count,\n schema: Schema.str,\n });\n }\n Column.ofStringTokens = ofStringTokens;\n function window(column, start, end) {\n return windowColumn(column, start, end);\n }\n Column.window = window;\n function view(column, indices, checkIndentity = true) {\n return columnView(column, indices, checkIndentity);\n }\n Column.view = view;\n /** A map of the 1st occurence of each value. */\n function createFirstIndexMap(column) {\n return createFirstIndexMapOfColumn(column);\n }\n Column.createFirstIndexMap = createFirstIndexMap;\n function createIndexer(column) {\n return createIndexerOfColumn(column);\n }\n Column.createIndexer = createIndexer;\n function mapToArray(column, f, ctor) {\n return mapToArrayImpl(column, f, ctor || Array);\n }\n Column.mapToArray = mapToArray;\n function areEqual(a, b) {\n return areColumnsEqual(a, b);\n }\n Column.areEqual = areEqual;\n function indicesOf(c, test) {\n return columnIndicesOf(c, test);\n }\n Column.indicesOf = indicesOf;\n /** Makes the column backed by an array. Useful for columns that are accessed often. */\n function asArrayColumn(c, array) {\n if (c.__array)\n return c;\n if (!c.isDefined)\n return Undefined(c.rowCount, c.schema);\n return arrayColumn({ array: c.toArray({ array }), schema: c.schema, valueKind: c.valueKind });\n }\n Column.asArrayColumn = asArrayColumn;\n function copyToArray(c, array, offset = 0) {\n if (!c.isDefined)\n return;\n const cArray = c.__array;\n if (cArray) {\n for (let i = 0, _i = cArray.length; i < _i; i++)\n array[offset + i] = cArray[i];\n }\n else {\n for (let i = 0, _i = c.rowCount; i < _i; i++)\n array[offset + i] = c.value(i);\n }\n }\n Column.copyToArray = copyToArray;\n function isIdentity(c) {\n for (let i = 0, _i = c.rowCount; i < _i; i++) {\n if (i !== c.value(i))\n return false;\n }\n return true;\n }\n Column.isIdentity = isIdentity;\n})(Column || (Column = {}));\nexport { Column };\nfunction createFirstIndexMapOfColumn(c) {\n const map = new Map();\n for (let i = 0, _i = c.rowCount; i < _i; i++) {\n const v = c.value(i);\n if (!map.has(v))\n map.set(c.value(i), i);\n }\n return map;\n}\nfunction createIndexerOfColumn(c) {\n const map = new Map();\n for (let i = 0, _i = c.rowCount; i < _i; i++) {\n const v = c.value(i);\n if (!map.has(v))\n map.set(c.value(i), i);\n }\n return v => map.has(v) ? map.get(v) : -1;\n}\nfunction constColumn(v, rowCount, schema, valueKind) {\n const value = row => v;\n return {\n schema: schema,\n __array: void 0,\n isDefined: valueKind === 0 /* Column.ValueKinds.Present */,\n rowCount,\n value,\n valueKind: row => valueKind,\n toArray: params => {\n const { array } = ColumnHelpers.createArray(rowCount, params);\n for (let i = 0, _i = array.length; i < _i; i++)\n array[i] = v;\n return array;\n },\n areValuesEqual: (rowA, rowB) => true\n };\n}\nfunction lambdaColumn({ value, valueKind, areValuesEqual, rowCount, schema }) {\n return {\n schema: schema,\n __array: void 0,\n isDefined: true,\n rowCount,\n value,\n valueKind: valueKind ? valueKind : row => 0 /* Column.ValueKinds.Present */,\n toArray: params => {\n const { array, start } = ColumnHelpers.createArray(rowCount, params);\n for (let i = 0, _i = array.length; i < _i; i++)\n array[i] = value(i + start);\n return array;\n },\n areValuesEqual: areValuesEqual ? areValuesEqual : (rowA, rowB) => value(rowA) === value(rowB)\n };\n}\nfunction arrayColumn({ array, schema, valueKind }) {\n const rowCount = array.length;\n const defaultValue = schema.T;\n const value = schema.valueType === 'str'\n ? schema.transform === 'lowercase'\n ? row => { const v = array[row]; return typeof v === 'string' ? v.toLowerCase() : `${v !== null && v !== void 0 ? v : defaultValue}`.toLowerCase(); }\n : schema.transform === 'uppercase'\n ? row => { const v = array[row]; return typeof v === 'string' ? v.toUpperCase() : `${v !== null && v !== void 0 ? v : defaultValue}`.toUpperCase(); }\n : row => { const v = array[row]; return typeof v === 'string' ? v : `${v !== null && v !== void 0 ? v : defaultValue}`; }\n : row => array[row];\n const isTyped = ColumnHelpers.isTypedArray(array);\n return {\n schema: schema,\n __array: array,\n isDefined: true,\n rowCount,\n value,\n valueKind: valueKind ? valueKind : row => 0 /* Column.ValueKinds.Present */,\n toArray: schema.valueType === 'str'\n ? schema.transform === 'lowercase'\n ? params => {\n const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);\n const ret = new (params && typeof params.array !== 'undefined' ? params.array : array.constructor)(end - start);\n for (let i = 0, _i = end - start; i < _i; i++) {\n const v = array[start + i];\n ret[i] = typeof v === 'string' ? v.toLowerCase() : `${v !== null && v !== void 0 ? v : defaultValue}`.toLowerCase();\n }\n return ret;\n }\n : schema.transform === 'uppercase'\n ? params => {\n const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);\n const ret = new (params && typeof params.array !== 'undefined' ? params.array : array.constructor)(end - start);\n for (let i = 0, _i = end - start; i < _i; i++) {\n const v = array[start + i];\n ret[i] = typeof v === 'string' ? v.toUpperCase() : `${v !== null && v !== void 0 ? v : defaultValue}`.toUpperCase();\n }\n return ret;\n }\n : params => {\n const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);\n const ret = new (params && typeof params.array !== 'undefined' ? params.array : array.constructor)(end - start);\n for (let i = 0, _i = end - start; i < _i; i++) {\n const v = array[start + i];\n ret[i] = typeof v === 'string' ? v : `${v !== null && v !== void 0 ? v : defaultValue}`;\n }\n return ret;\n }\n : isTyped\n ? params => ColumnHelpers.typedArrayWindow(array, params)\n : params => {\n const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);\n if (start === 0 && end === array.length)\n return array;\n const ret = new (params && typeof params.array !== 'undefined' ? params.array : array.constructor)(end - start);\n for (let i = 0, _i = end - start; i < _i; i++)\n ret[i] = array[start + i];\n return ret;\n },\n areValuesEqual: (rowA, rowB) => array[rowA] === array[rowB]\n };\n}\nfunction windowColumn(column, start, end) {\n if (!column.isDefined)\n return Column.Undefined(end - start, column.schema);\n if (start === 0 && end === column.rowCount)\n return column;\n if (!!column.__array && ColumnHelpers.isTypedArray(column.__array))\n return windowTyped(column, start, end);\n return windowFull(column, start, end);\n}\nfunction windowTyped(c, start, end) {\n const array = ColumnHelpers.typedArrayWindow(c.__array, { start, end });\n const vk = c.valueKind;\n return arrayColumn({ array, schema: c.schema, valueKind: row => vk(start + row) });\n}\nfunction windowFull(c, start, end) {\n const v = c.value, vk = c.valueKind, ave = c.areValuesEqual;\n const value = start === 0 ? v : row => v(row + start);\n const rowCount = end - start;\n return {\n schema: c.schema,\n __array: void 0,\n isDefined: c.isDefined,\n rowCount,\n value,\n valueKind: start === 0 ? vk : row => vk(row + start),\n toArray: params => {\n const { array } = ColumnHelpers.createArray(rowCount, params);\n for (let i = 0, _i = array.length; i < _i; i++)\n array[i] = v(i + start);\n return array;\n },\n areValuesEqual: start === 0 ? ave : (rowA, rowB) => ave(rowA + start, rowB + start)\n };\n}\nfunction isIdentity(map, rowCount) {\n if (map.length !== rowCount)\n return false;\n for (let i = 0, _i = map.length; i < _i; i++) {\n if (map[i] !== i)\n return false;\n }\n return true;\n}\nfunction columnView(c, map, checkIdentity) {\n if (c.rowCount === 0)\n return c;\n if (checkIdentity && isIdentity(map, c.rowCount))\n return c;\n if (!!c.__array && typeof c.value(0) === typeof c.__array[0])\n return arrayView(c, map);\n return viewFull(c, map);\n}\nfunction arrayView(c, map) {\n const array = c.__array;\n const ret = new array.constructor(map.length);\n for (let i = 0, _i = map.length; i < _i; i++)\n ret[i] = array[map[i]];\n const vk = c.valueKind;\n return arrayColumn({ array: ret, schema: c.schema, valueKind: row => vk(map[row]) });\n}\nfunction viewFull(c, map) {\n const v = c.value, vk = c.valueKind, ave = c.areValuesEqual;\n const value = row => v(map[row]);\n const rowCount = map.length;\n return {\n schema: c.schema,\n __array: void 0,\n isDefined: c.isDefined,\n rowCount,\n value,\n valueKind: row => vk(map[row]),\n toArray: params => {\n const { array } = ColumnHelpers.createArray(rowCount, params);\n for (let i = 0, _i = array.length; i < _i; i++)\n array[i] = v(map[i]);\n return array;\n },\n areValuesEqual: (rowA, rowB) => ave(map[rowA], map[rowB])\n };\n}\nfunction mapToArrayImpl(c, f, ctor) {\n const ret = new ctor(c.rowCount);\n for (let i = 0, _i = c.rowCount; i < _i; i++)\n ret[i] = f(c.value(i));\n return ret;\n}\nfunction areColumnsEqual(a, b) {\n if (a === b)\n return true;\n if (a.rowCount !== b.rowCount || a.isDefined !== b.isDefined || a.schema.valueType !== b.schema.valueType)\n return false;\n if (!!a.__array && !!b.__array)\n return areArraysEqual(a, b);\n return areValuesEqual(a, b);\n}\nfunction areArraysEqual(a, b) {\n const xs = a.__array, ys = b.__array;\n for (let i = 0, _i = a.rowCount; i < _i; i++) {\n if (xs[i] !== ys[i])\n return false;\n }\n return true;\n}\nfunction areValuesEqual(a, b) {\n const va = a.value, vb = b.value;\n for (let i = 0, _i = a.rowCount; i < _i; i++) {\n if (va(i) !== vb(i))\n return false;\n }\n return true;\n}\nfunction columnIndicesOf(c, test) {\n const ret = [], v = c.value;\n for (let i = 0, _i = c.rowCount; i < _i; i++) {\n if (test(v(i)))\n ret[ret.length] = i;\n }\n return ret;\n}\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nvar BitFlags;\n(function (BitFlags) {\n function create(flags) { return flags; }\n BitFlags.create = create;\n function has(flags, flag) { return (flags & flag) !== 0; }\n BitFlags.has = has;\n /** toCheck must be non-zero */\n function hasAll(flags, toCheck) { return !!toCheck && (flags & toCheck) === toCheck; }\n BitFlags.hasAll = hasAll;\n})(BitFlags || (BitFlags = {}));\nexport { BitFlags };\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * Adapted from CIFTools.js (https://github.com/dsehnal/CIFTools.js)\n *\n * @author David Sehnal \n */\nvar StringBuilder;\n(function (StringBuilder) {\n function create(chunkCapacity = 512) {\n return {\n current: [],\n offset: 0,\n capacity: chunkCapacity,\n chunks: []\n };\n }\n StringBuilder.create = create;\n function getString(builder) {\n if (!builder.chunks.length) {\n if (builder.current.length === builder.offset)\n return builder.current.join('');\n return builder.current.splice(0, builder.offset).join('');\n }\n if (builder.offset > 0) {\n builder.chunks[builder.chunks.length] = builder.current.length === builder.offset\n ? builder.current.join('')\n : builder.current.slice(0, builder.offset).join('');\n }\n return builder.chunks.join('');\n }\n StringBuilder.getString = getString;\n function getSize(builder) {\n let size = 0;\n for (const c of builder.chunks)\n size += c.length;\n for (let i = 0; i < builder.offset; i++)\n size += builder.current[i].length;\n return size;\n }\n StringBuilder.getSize = getSize;\n function getChunks(builder) {\n if (builder.offset > 0) {\n if (builder.current.length === builder.offset)\n builder.chunks[builder.chunks.length] = builder.current.join('');\n else\n builder.chunks[builder.chunks.length] = builder.current.slice(0, builder.offset).join('');\n builder.offset = 0;\n }\n return builder.chunks;\n }\n StringBuilder.getChunks = getChunks;\n const __paddingSpaces = [];\n (function () {\n let s = '';\n for (let i = 0; i < 512 /* PaddingSpaces.Count */; i++) {\n __paddingSpaces[i] = s;\n s = s + ' ';\n }\n })();\n function newline(builder) {\n writeSafe(builder, '\\n');\n }\n StringBuilder.newline = newline;\n function whitespace(builder, len) {\n if (len > 0)\n writeSafe(builder, __paddingSpaces[len]);\n }\n StringBuilder.whitespace = whitespace;\n function whitespace1(builder) {\n writeSafe(builder, ' ');\n }\n StringBuilder.whitespace1 = whitespace1;\n function write(builder, val) {\n if (!val)\n return;\n if (builder.offset === builder.capacity) {\n builder.chunks[builder.chunks.length] = builder.current.join('');\n builder.offset = 0;\n }\n builder.current[builder.offset++] = val;\n }\n StringBuilder.write = write;\n /** Write without check. */\n function writeSafe(builder, val) {\n if (builder.offset === builder.capacity) {\n builder.chunks[builder.chunks.length] = builder.current.join('');\n builder.offset = 0;\n }\n builder.current[builder.offset++] = val;\n }\n StringBuilder.writeSafe = writeSafe;\n function writePadLeft(builder, val, totalWidth) {\n if (!val) {\n whitespace(builder, totalWidth);\n return;\n }\n const padding = totalWidth - val.length;\n whitespace(builder, padding);\n writeSafe(builder, val);\n }\n StringBuilder.writePadLeft = writePadLeft;\n function writePadRight(builder, val, totalWidth) {\n if (!val) {\n whitespace(builder, totalWidth);\n return;\n }\n const padding = totalWidth - val.length;\n writeSafe(builder, val);\n whitespace(builder, padding);\n }\n StringBuilder.writePadRight = writePadRight;\n function writeInteger(builder, val) {\n writeSafe(builder, '' + val);\n }\n StringBuilder.writeInteger = writeInteger;\n function writeIntegerAndSpace(builder, val) {\n writeSafe(builder, '' + val + ' ');\n }\n StringBuilder.writeIntegerAndSpace = writeIntegerAndSpace;\n function writeIntegerPadLeft(builder, val, totalWidth) {\n const s = '' + val;\n const padding = totalWidth - s.length;\n whitespace(builder, padding);\n writeSafe(builder, s);\n }\n StringBuilder.writeIntegerPadLeft = writeIntegerPadLeft;\n function writeIntegerPadRight(builder, val, totalWidth) {\n const s = '' + val;\n const padding = totalWidth - s.length;\n writeSafe(builder, s);\n whitespace(builder, padding);\n }\n StringBuilder.writeIntegerPadRight = writeIntegerPadRight;\n /**\n * @example writeFloat(123.2123, 100) -- 2 decim\n */\n function writeFloat(builder, val, precisionMultiplier) {\n writeSafe(builder, '' + Math.round(precisionMultiplier * val) / precisionMultiplier);\n }\n StringBuilder.writeFloat = writeFloat;\n function writeFloatPadLeft(builder, val, precisionMultiplier, totalWidth) {\n const s = '' + Math.round(precisionMultiplier * val) / precisionMultiplier;\n const padding = totalWidth - s.length;\n whitespace(builder, padding);\n writeSafe(builder, s);\n }\n StringBuilder.writeFloatPadLeft = writeFloatPadLeft;\n function writeFloatPadRight(builder, val, precisionMultiplier, totalWidth) {\n const s = '' + Math.round(precisionMultiplier * val) / precisionMultiplier;\n const padding = totalWidth - s.length;\n writeSafe(builder, s);\n whitespace(builder, padding);\n }\n StringBuilder.writeFloatPadRight = writeFloatPadRight;\n})(StringBuilder || (StringBuilder = {}));\nexport { StringBuilder };\n","/**\n * Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n *\n * based in part on https://github.com/dsehnal/CIFTools.js\n */\n/**\n * Efficient integer and float parsers.\n *\n * For the purposes of parsing numbers from the mmCIF data representations,\n * up to 4 times faster than JS parseInt/parseFloat.\n */\nexport function parseIntSkipLeadingWhitespace(str, start, end) {\n while (start < end && str.charCodeAt(start) === 32)\n start++;\n return parseInt(str, start, end);\n}\nexport function parseInt(str, start, end) {\n let _start = start, ret = 0, neg = 1;\n if (str.charCodeAt(_start) === 45 /* - */) {\n neg = -1;\n ++_start;\n }\n else if (str.charCodeAt(_start) === 43 /* + */) {\n ++_start;\n }\n for (; _start < end; _start++) {\n const c = str.charCodeAt(_start) - 48;\n if (c > 9 || c < 0)\n return (neg * ret) | 0;\n else\n ret = (10 * ret + c) | 0;\n }\n return neg * ret;\n}\nfunction parseScientific(main, str, start, end) {\n // handle + in '1e+1' separately.\n if (str.charCodeAt(start) === 43 /* + */)\n start++;\n return main * Math.pow(10.0, parseInt(str, start, end));\n}\nexport function parseFloatSkipLeadingWhitespace(str, start, end) {\n while (start < end && str.charCodeAt(start) === 32)\n start++;\n return parseFloat(str, start, end);\n}\nexport function parseFloat(str, start, end) {\n let _start = start, neg = 1.0, ret = 0.0, point = 0.0, div = 1.0;\n if (str.charCodeAt(_start) === 45 /* - */) {\n neg = -1;\n ++_start;\n }\n else if (str.charCodeAt(_start) === 43 /* + */) {\n ++_start;\n }\n while (_start < end) {\n let c = str.charCodeAt(_start) - 48;\n if (c >= 0 && c < 10) {\n ret = ret * 10 + c;\n ++_start;\n }\n else if (c === -2) { // .\n ++_start;\n while (_start < end) {\n c = str.charCodeAt(_start) - 48;\n if (c >= 0 && c < 10) {\n point = 10.0 * point + c;\n div = 10.0 * div;\n ++_start;\n }\n else if (c === 53 || c === 21) { // 'e'/'E'\n return parseScientific(neg * (ret + point / div), str, _start + 1, end);\n }\n else {\n return neg * (ret + point / div);\n }\n }\n return neg * (ret + point / div);\n }\n else if (c === 53 || c === 21) { // 'e'/'E'\n return parseScientific(neg * ret, str, _start + 1, end);\n }\n else {\n break;\n }\n }\n return neg * ret;\n}\nexport const NumberType = {\n Int: 0 /* NumberTypes.Int */,\n Float: 1 /* NumberTypes.Float */,\n Scientific: 2 /* NumberTypes.Scientific */,\n NaN: 3 /* NumberTypes.NaN */\n};\nfunction isInt(str, start, end) {\n if (str.charCodeAt(start) === 45 /* - */) {\n start++;\n }\n for (; start < end; start++) {\n const c = str.charCodeAt(start) - 48;\n if (c > 9 || c < 0)\n return false;\n }\n return true;\n}\n// TODO: check for \"scientific integers?\"\nfunction getNumberTypeScientific(str, start, end) {\n // handle + in '1e+1' separately.\n if (str.charCodeAt(start) === 43 /* + */)\n start++;\n return isInt(str, start, end) ? 2 /* NumberTypes.Scientific */ : 3 /* NumberTypes.NaN */;\n}\n/** The whole range must match, otherwise returns NaN */\nexport function getNumberType(str) {\n let start = 0;\n const end = str.length;\n if (str.charCodeAt(start) === 45) { // -\n ++start;\n }\n // string is . or -.\n if (str.charCodeAt(start) === 46 && end - start === 1) {\n return 3 /* NumberTypes.NaN */;\n }\n while (start < end) {\n let c = str.charCodeAt(start) - 48;\n if (c >= 0 && c < 10) {\n ++start;\n }\n else if (c === -2) { // .\n ++start;\n let hasDigit = false;\n while (start < end) {\n c = str.charCodeAt(start) - 48;\n if (c >= 0 && c < 10) {\n hasDigit = true;\n ++start;\n }\n else if (c === 53 || c === 21) { // 'e'/'E'\n return getNumberTypeScientific(str, start + 1, end);\n }\n else {\n return 3 /* NumberTypes.NaN */;\n }\n }\n return hasDigit ? 1 /* NumberTypes.Float */ : 0 /* NumberTypes.Int */;\n }\n else if (c === 53 || c === 21) { // 'e'/'E'\n if (start === 0 || start === 1 && str.charCodeAt(0) === 45) {\n return 3 /* NumberTypes.NaN */; // string starts with e/E or -e/-E\n }\n return getNumberTypeScientific(str, start + 1, end);\n }\n else {\n break;\n }\n }\n return start === end ? 0 /* NumberTypes.Int */ : 3 /* NumberTypes.NaN */;\n}\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nexport function arrayLess(arr, i, j) {\n return arr[i] - arr[j];\n}\nexport function arraySwap(arr, i, j) {\n const temp = arr[i];\n arr[i] = arr[j];\n arr[j] = temp;\n}\nfunction medianPivotIndex(data, cmp, l, r) {\n const m = (l + r) >> 1;\n if (cmp(data, l, r) > 0)\n return cmp(data, l, m) > 0 ? cmp(data, m, r) > 0 ? m : r : l;\n else\n return cmp(data, r, m) > 0 ? cmp(data, m, l) > 0 ? m : l : r;\n}\nfunction partition(ctx, l, r) {\n const { cmp, swap, data, parts } = ctx;\n let equals = l + 1, tail = r;\n // move the median to the 1st spot\n swap(data, l, medianPivotIndex(data, cmp, l, r));\n while (cmp(data, tail, l) > 0) {\n --tail;\n }\n for (let i = l + 1; i <= tail; i++) {\n const c = cmp(data, i, l);\n if (c > 0) {\n swap(data, i, tail);\n --tail;\n while (cmp(data, tail, l) > 0) {\n --tail;\n }\n i--;\n }\n else if (c === 0) {\n swap(data, i, equals);\n equals++;\n }\n }\n // move the medians to the correct spots\n for (let i = l; i < equals; i++) {\n swap(data, i, l + tail - i);\n }\n parts[0] = tail - equals + l + 1;\n parts[1] = tail;\n}\nfunction insertionSort({ data, cmp, swap }, start, end) {\n for (let i = start + 1; i <= end; i++) {\n let j = i - 1;\n while (j >= start && cmp(data, j, j + 1) > 0) {\n swap(data, j, j + 1);\n j = j - 1;\n }\n }\n}\nfunction quickSort(ctx, low, high) {\n const { parts } = ctx;\n while (low < high) {\n if (high - low < 16) {\n insertionSort(ctx, low, high);\n return;\n }\n partition(ctx, low, high);\n const li = parts[0], ri = parts[1];\n if (li - low < high - ri) {\n quickSort(ctx, low, li - 1);\n low = ri + 1;\n }\n else {\n quickSort(ctx, ri + 1, high);\n high = li - 1;\n }\n }\n}\nfunction partitionArrayAsc(data, parts, l, r) {\n let equals = l + 1, tail = r;\n // move the median to the 1st spot\n arraySwap(data, l, medianPivotIndex(data, arrayLess, l, r));\n const pivot = data[l];\n while (data[tail] > pivot) {\n --tail;\n }\n for (let i = l + 1; i <= tail; i++) {\n const v = data[i];\n if (v > pivot) {\n arraySwap(data, i, tail);\n --tail;\n while (data[tail] > pivot) {\n --tail;\n }\n i--;\n }\n else if (v === pivot) {\n arraySwap(data, i, equals);\n ++equals;\n }\n }\n // move all medians to the correct spots\n for (let i = l; i < equals; i++) {\n arraySwap(data, i, l + tail - i);\n }\n parts[0] = tail - equals + l + 1;\n parts[1] = tail;\n}\nfunction insertionSortArrayAsc(data, start, end) {\n for (let i = start + 1; i <= end; i++) {\n const key = data[i];\n let j = i - 1;\n while (j >= start && data[j] > key) {\n data[j + 1] = data[j];\n j = j - 1;\n }\n data[j + 1] = key;\n }\n}\nfunction quickSortArrayAsc(data, parts, low, high) {\n while (low < high) {\n if (high - low < 16) {\n insertionSortArrayAsc(data, low, high);\n return;\n }\n partitionArrayAsc(data, parts, low, high);\n const li = parts[0], ri = parts[1];\n if (li - low < high - ri) {\n quickSortArrayAsc(data, parts, low, li - 1);\n low = ri + 1;\n }\n else {\n quickSortArrayAsc(data, parts, ri + 1, high);\n high = li - 1;\n }\n }\n}\nexport function sortArray(data, cmp = arrayLess) {\n return sortArrayRange(data, 0, data.length, cmp);\n}\nexport function sortArrayRange(data, start, end, cmp = arrayLess) {\n if (cmp === arrayLess)\n quickSortArrayAsc(data, [0, 0], start, end - 1);\n else\n quickSort({ data, cmp, swap: arraySwap, parts: [0, 0] }, start, end - 1);\n return data;\n}\nexport function sort(data, start, end, cmp, swap) {\n const ctx = { data, cmp, swap, parts: [0, 0] };\n quickSort(ctx, start, end - 1);\n return data;\n}\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nconst now = (function () {\n if (typeof window !== 'undefined' && window.performance) {\n const perf = window.performance;\n return () => perf.now();\n }\n else if (typeof process !== 'undefined' && process.hrtime !== 'undefined' && typeof process.hrtime === 'function') {\n return () => {\n const t = process.hrtime();\n return t[0] * 1000 + t[1] / 1000000;\n };\n }\n else if (Date.now) {\n return () => Date.now();\n }\n else {\n return () => +new Date();\n }\n}());\nfunction formatTimespan(t, includeMsZeroes = true) {\n if (isNaN(t))\n return 'n/a';\n const h = Math.floor(t / (60 * 60 * 1000)), m = Math.floor(t / (60 * 1000) % 60), s = Math.floor(t / 1000 % 60);\n let ms = Math.floor(t % 1000).toString();\n while (ms.length < 3)\n ms = '0' + ms;\n while (!includeMsZeroes && ms.length > 1 && ms[ms.length - 1] === '0')\n ms = ms.substr(0, ms.length - 1);\n if (h > 0)\n return `${h}h${m}m${s}.${ms}s`;\n if (m > 0)\n return `${m}m${s}.${ms}s`;\n if (s > 0)\n return `${s}.${ms}s`;\n return `${t.toFixed(0)}ms`;\n}\nexport { now, formatTimespan };\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nimport { now } from '../mol-util/now';\nvar UUID;\n(function (UUID) {\n const _btoa = typeof btoa !== 'undefined' ? btoa : (s) => Buffer.from(s).toString('base64');\n const chars = [];\n /** Creates a 22 characters 'base64' encoded UUID */\n function create22() {\n let d = (+new Date()) + now();\n for (let i = 0; i < 16; i++) {\n chars[i] = String.fromCharCode((d + Math.random() * 0xff) % 0xff | 0);\n d = Math.floor(d / 0xff);\n }\n return _btoa(chars.join('')).replace(/\\+/g, '-').replace(/\\//g, '_').substr(0, 22);\n }\n UUID.create22 = create22;\n function createv4() {\n let d = (+new Date()) + now();\n const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n const r = (d + Math.random() * 16) % 16 | 0;\n d = Math.floor(d / 16);\n return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);\n });\n return uuid;\n }\n UUID.createv4 = createv4;\n function is(x) {\n return typeof x === 'string';\n }\n UUID.is = is;\n})(UUID || (UUID = {}));\nexport { UUID };\n","/**\n * Copyright (c) 2017 Mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\n// TODO check if the removal of FastSet and the removal of the context object for forEach\n// have any performance implications\nfunction _ascSort(a, b) {\n return a - b;\n}\nexport function sortAsc(array) {\n Array.prototype.sort.call(array, _ascSort);\n return array;\n}\nvar Mask;\n(function (Mask) {\n class EmptyMask {\n has(i) { return false; }\n forEach(f, ctx) { return ctx; }\n constructor() {\n this.size = 0;\n }\n }\n class SingletonMask {\n has(i) { return i === this.idx; }\n forEach(f, ctx) { f(this.idx, ctx); return ctx; }\n constructor(idx) {\n this.idx = idx;\n this.size = 1;\n }\n }\n class BitMask {\n has(i) { return i < this.length && !!this.mask[i]; }\n _forEach(f, ctx) {\n for (let i = 0; i < this.length; i++) {\n if (this.mask[i])\n f(i, ctx);\n }\n }\n forEach(f, ctx) {\n this._forEach(f, ctx);\n return ctx;\n }\n constructor(mask, size) {\n this.mask = mask;\n this.size = size;\n this.length = mask.length;\n }\n }\n class AllMask {\n has(i) { return true; }\n _forEach(f, ctx) {\n for (let i = 0; i < this.size; i++) {\n f(i, ctx);\n }\n }\n forEach(f, ctx) {\n this._forEach(f, ctx);\n return ctx;\n }\n constructor(size) {\n this.size = size;\n }\n }\n class SetMask {\n has(i) { return this.set.has(i); }\n _forEach(f, ctx) {\n for (const idx of this.flatten()) {\n f(idx, ctx);\n }\n }\n flatten() {\n if (this._flat)\n return this._flat;\n const indices = new Int32Array(this.size);\n let offset = 0;\n this.set.forEach(i => indices[offset++] = i);\n sortAsc(indices);\n this._flat = indices;\n return this._flat;\n }\n forEach(f, ctx) {\n this._forEach(f, ctx);\n return ctx;\n }\n constructor(set) {\n this.set = set;\n this._flat = void 0;\n this.size = set.size;\n }\n }\n function always(size) { return new AllMask(size); }\n Mask.always = always;\n Mask.never = new EmptyMask();\n function ofSet(set) {\n return new SetMask(set);\n }\n Mask.ofSet = ofSet;\n function singleton(i) {\n return new SingletonMask(i);\n }\n Mask.singleton = singleton;\n function ofUniqueIndices(indices) {\n const len = indices.length;\n if (len === 0)\n return new EmptyMask();\n if (len === 1)\n return new SingletonMask(indices[0]);\n let max = 0;\n for (const i of indices) {\n if (i > max)\n max = i;\n }\n if (len === max)\n return new AllMask(len);\n const f = len / max;\n if (f < 1 / 12) {\n const set = new Set();\n for (const i of indices)\n set.add(i);\n return new SetMask(set);\n }\n const mask = new Int8Array(max + 1);\n for (const i of indices) {\n mask[i] = 1;\n }\n return new BitMask(mask, indices.length);\n }\n Mask.ofUniqueIndices = ofUniqueIndices;\n function ofMask(mask, size) {\n return new BitMask(mask, size);\n }\n Mask.ofMask = ofMask;\n function hasAny(mask, xs) {\n for (const x of xs) {\n if (mask.has(x))\n return true;\n }\n return false;\n }\n Mask.hasAny = hasAny;\n function complement(mask, against) {\n let count = 0;\n let max = 0;\n against.forEach(i => {\n if (!mask.has(i)) {\n count++;\n if (i > max)\n max = i;\n }\n });\n if (count / max < 1 / 12) {\n // set based\n const set = new Set();\n against.forEach(i => {\n if (!mask.has(i)) {\n set.add(i);\n }\n });\n return ofSet(set);\n }\n else {\n // mask based\n const target = new Uint8Array(max + 1);\n against.forEach(i => {\n if (!mask.has(i)) {\n target[i] = 1;\n }\n });\n return ofMask(target, count);\n }\n }\n Mask.complement = complement;\n})(Mask || (Mask = {}));\nexport { Mask };\n","/**\n * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport { idFactory } from './id-factory';\nvar ValueRef;\n(function (ValueRef) {\n function create(ref) { return { ref }; }\n ValueRef.create = create;\n function set(ref, value) { ref.ref = value; return ref; }\n ValueRef.set = set;\n})(ValueRef || (ValueRef = {}));\nconst getNextId = idFactory(0, 0x7FFFFFFF);\nvar ValueBox;\n(function (ValueBox) {\n function create(value, metadata) {\n return { id: getNextId(), version: 0, value, metadata: metadata };\n }\n ValueBox.create = create;\n /** The box.metadata is carried over from the old box */\n function withValue(box, value) {\n return { id: box.id, version: box.version + 1, value, metadata: box.metadata };\n }\n ValueBox.withValue = withValue;\n})(ValueBox || (ValueBox = {}));\nvar ValueCell;\n(function (ValueCell) {\n function create(value, metadata) {\n return ValueRef.create(ValueBox.create(value, metadata));\n }\n ValueCell.create = create;\n /** The box.metadata is carried over from the old box */\n function update(cell, value) {\n return ValueRef.set(cell, ValueBox.withValue(cell.ref, value));\n }\n ValueCell.update = update;\n function set(cell, box) {\n return ValueRef.set(cell, box);\n }\n ValueCell.set = set;\n /** Updates the cell if the value is has changed, comparing by reference */\n function updateIfChanged(cell, value) {\n return cell.ref.value !== value ? update(cell, value) : cell;\n }\n ValueCell.updateIfChanged = updateIfChanged;\n})(ValueCell || (ValueCell = {}));\nexport { ValueRef, ValueBox, ValueCell };\n","/**\n * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author Alexander Rose \n */\n/** Builds id function returning ids within [firstId, maxId) */\nexport function idFactory(firstId = 0, maxId = Number.MAX_SAFE_INTEGER) {\n let _nextId = firstId;\n return () => {\n const ret = _nextId;\n _nextId = (_nextId + 1) % maxId;\n return ret;\n };\n}\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nimport { Column } from './column';\nimport { sortArray } from '../util/sort';\nimport { StringBuilder } from '../../mol-util';\n/** An immutable table */\nvar Table;\n(function (Table) {\n function is(t) {\n return t && typeof t._rowCount === 'number' && !!t._columns && !!t._schema;\n }\n Table.is = is;\n function pickColumns(schema, table, guard = {}) {\n const ret = Object.create(null);\n const keys = Object.keys(schema);\n ret._rowCount = table._rowCount;\n ret._columns = keys;\n ret._schema = schema;\n for (const k of keys) {\n if (!!table[k])\n ret[k] = table[k];\n else if (!!guard[k])\n ret[k] = guard[k];\n else\n throw Error(`Cannot find column '${k}'.`);\n }\n return ret;\n }\n Table.pickColumns = pickColumns;\n function ofColumns(schema, columns) {\n const _columns = Object.keys(columns);\n const _rowCount = columns[_columns[0]].rowCount;\n return { _rowCount, _columns, _schema: schema, ...columns };\n }\n Table.ofColumns = ofColumns;\n function ofPartialColumns(schema, partialColumns, rowCount) {\n const ret = Object.create(null);\n const columns = Object.keys(schema);\n ret._rowCount = rowCount;\n ret._columns = columns;\n ret._schema = schema;\n for (const k of columns) {\n if (k in partialColumns)\n ret[k] = partialColumns[k];\n else\n ret[k] = Column.Undefined(rowCount, schema[k]);\n }\n return ret;\n }\n Table.ofPartialColumns = ofPartialColumns;\n function ofUndefinedColumns(schema, rowCount) {\n const ret = Object.create(null);\n const columns = Object.keys(schema);\n ret._rowCount = rowCount;\n ret._columns = columns;\n ret._schema = schema;\n for (const k of columns) {\n ret[k] = Column.Undefined(rowCount, schema[k]);\n }\n return ret;\n }\n Table.ofUndefinedColumns = ofUndefinedColumns;\n function ofRows(schema, rows) {\n const ret = Object.create(null);\n const rowCount = rows.length;\n const columns = Object.keys(schema);\n ret._rowCount = rowCount;\n ret._columns = columns;\n ret._schema = schema;\n for (const k of columns) {\n ret[k] = Column.ofLambda({\n rowCount,\n schema: schema[k],\n value: r => rows[r][k],\n valueKind: r => typeof rows[r][k] === 'undefined' ? 1 /* Column.ValueKinds.NotPresent */ : 0 /* Column.ValueKinds.Present */\n });\n }\n return ret;\n }\n Table.ofRows = ofRows;\n function ofArrays(schema, arrays) {\n var _a;\n const ret = Object.create(null);\n const columns = Object.keys(schema);\n ret._rowCount = 0;\n ret._columns = columns;\n ret._schema = schema;\n for (const k of columns) {\n if (typeof arrays[k] !== 'undefined') {\n ret[k] = Column.ofArray({ array: arrays[k], schema: schema[k] });\n ret._rowCount = (_a = arrays[k]) === null || _a === void 0 ? void 0 : _a.length;\n }\n else {\n ret[k] = Column.Undefined(ret._rowCount, schema[k]);\n }\n }\n return ret;\n }\n Table.ofArrays = ofArrays;\n function view(table, schema, view) {\n const ret = Object.create(null);\n const columns = Object.keys(schema);\n ret._rowCount = view.length;\n ret._columns = columns;\n ret._schema = schema;\n for (const k of columns) {\n ret[k] = Column.view(table[k], view);\n }\n return ret;\n }\n Table.view = view;\n function pick(table, schema, test) {\n const _view = [];\n for (let i = 0, il = table._rowCount; i < il; ++i) {\n if (test(i))\n _view.push(i);\n }\n return view(table, schema, _view);\n }\n Table.pick = pick;\n function window(table, schema, start, end) {\n if (start === 0 && end === table._rowCount)\n return table;\n const ret = Object.create(null);\n const columns = Object.keys(schema);\n ret._rowCount = end - start;\n ret._columns = columns;\n ret._schema = schema;\n for (const k of columns) {\n ret[k] = Column.window(table[k], start, end);\n }\n return ret;\n }\n Table.window = window;\n function concat(tables, schema) {\n const ret = Object.create(null);\n const columns = Object.keys(schema);\n ret._rowCount = 0;\n for (const table of tables) {\n ret._rowCount += table._rowCount;\n }\n const arrays = {};\n for (const column of columns) {\n arrays[column] = new Array(ret._rowCount);\n }\n ret._columns = columns;\n ret._schema = schema;\n let offset = 0;\n for (const table of tables) {\n for (const k of columns) {\n Column.copyToArray(table[k], arrays[k], offset);\n }\n offset += table._rowCount;\n }\n for (const k of columns) {\n ret[k] = Column.ofArray({ array: arrays[k], schema: schema[k] });\n }\n return ret;\n }\n Table.concat = concat;\n function columnToArray(table, name, array) {\n table[name] = Column.asArrayColumn(table[name], array);\n }\n Table.columnToArray = columnToArray;\n /** Sort and return a new table */\n function sort(table, cmp) {\n const indices = new Int32Array(table._rowCount);\n for (let i = 0, _i = indices.length; i < _i; i++)\n indices[i] = i;\n sortArray(indices, (_, i, j) => cmp(i, j));\n let isIdentity = true;\n for (let i = 0, _i = indices.length; i < _i; i++) {\n if (indices[i] !== i) {\n isIdentity = false;\n break;\n }\n }\n if (isIdentity)\n return table;\n const ret = Object.create(null);\n ret._rowCount = table._rowCount;\n ret._columns = table._columns;\n ret._schema = table._schema;\n for (const c of table._columns) {\n ret[c] = Column.view(table[c], indices, false);\n }\n return ret;\n }\n Table.sort = sort;\n function areEqual(a, b) {\n if (a._rowCount !== b._rowCount)\n return false;\n if (a._columns.length !== b._columns.length)\n return false;\n for (const c of a._columns) {\n if (!b[c])\n return false;\n }\n for (const c of a._columns) {\n if (!Column.areEqual(a[c], b[c]))\n return false;\n }\n return true;\n }\n Table.areEqual = areEqual;\n /** Allocate a new object with the given row values. */\n function getRow(table, index) {\n const row = Object.create(null);\n const { _columns: cols } = table;\n for (let i = 0; i < cols.length; i++) {\n const c = cols[i];\n row[c] = table[c].value(index);\n }\n return row;\n }\n Table.getRow = getRow;\n /** Pick the first row for which `test` evaluates to true */\n function pickRow(table, test) {\n for (let i = 0, il = table._rowCount; i < il; ++i) {\n if (test(i))\n return getRow(table, i);\n }\n }\n Table.pickRow = pickRow;\n function getRows(table) {\n const ret = [];\n const { _rowCount: c } = table;\n for (let i = 0; i < c; i++) {\n ret[i] = getRow(table, i);\n }\n return ret;\n }\n Table.getRows = getRows;\n function toArrays(table) {\n const arrays = {};\n const { _columns } = table;\n for (let i = 0; i < _columns.length; i++) {\n const c = _columns[i];\n arrays[c] = table[c].toArray();\n }\n return arrays;\n }\n Table.toArrays = toArrays;\n function formatToString(table) {\n const sb = StringBuilder.create();\n const { _columns: cols, _rowCount } = table;\n let headerLength = 1;\n StringBuilder.write(sb, '|');\n for (let i = 0; i < cols.length; i++) {\n StringBuilder.write(sb, cols[i]);\n StringBuilder.write(sb, '|');\n headerLength += cols[i].length + 1;\n }\n StringBuilder.newline(sb);\n StringBuilder.write(sb, new Array(headerLength + 1).join('-'));\n StringBuilder.newline(sb);\n for (let r = 0; r < _rowCount; r++) {\n StringBuilder.write(sb, '|');\n for (let i = 0; i < cols.length; i++) {\n const c = table[cols[i]];\n if (c.valueKind(r) === 0 /* Column.ValueKinds.Present */) {\n StringBuilder.write(sb, c.value(r));\n StringBuilder.write(sb, '|');\n }\n else {\n StringBuilder.write(sb, '.|');\n }\n }\n StringBuilder.newline(sb);\n }\n return StringBuilder.getString(sb);\n }\n Table.formatToString = formatToString;\n})(Table || (Table = {}));\nexport { Table };\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nimport { Table } from './table';\nvar Database;\n(function (Database) {\n function ofTables(name, schema, tables) {\n const keys = Object.keys(tables);\n const ret = Object.create(null);\n const tableNames = [];\n ret._name = name;\n ret._tableNames = tableNames;\n ret._schema = schema;\n for (const k of keys) {\n if (!Table.is(tables[k]))\n continue;\n ret[k] = tables[k];\n tableNames[tableNames.length] = k;\n }\n return ret;\n }\n Database.ofTables = ofTables;\n function getTablesAsRows(database) {\n const ret = {};\n for (const k of database._tableNames) {\n ret[k] = Table.getRows(database[k]);\n }\n return ret;\n }\n Database.getTablesAsRows = getTablesAsRows;\n})(Database || (Database = {}));\nexport { Database };\n","/**\n * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport { Column, ColumnHelpers } from '../../../mol-data/db';\nimport { getNumberType, parseInt as fastParseInt, parseFloat as fastParseFloat } from '../common/text/number-parser';\nimport { areValuesEqualProvider } from '../common/text/column/token';\nexport function CifFile(blocks, name) {\n return { name, blocks: blocks };\n}\nexport function CifBlock(categoryNames, categories, header, saveFrames = []) {\n return {\n categoryNames, header, categories, saveFrames,\n getField(name) {\n const [category, field] = name.split('.');\n return categories[category].getField(field || '');\n }\n };\n}\nexport function CifSaveFrame(categoryNames, categories, header) {\n return { categoryNames, header, categories };\n}\nexport function CifCategory(name, rowCount, fieldNames, fields) {\n return { rowCount, name, fieldNames: [...fieldNames], getField(name) { return fields[name]; } };\n}\n(function (CifCategory) {\n function empty(name) {\n return { rowCount: 0, name, fieldNames: [], getField(name) { return void 0; } };\n }\n CifCategory.empty = empty;\n ;\n function ofFields(name, fields) {\n const fieldNames = Object.keys(fields);\n return {\n rowCount: fieldNames.length > 0 ? fields[fieldNames[0]].rowCount : 0,\n name,\n fieldNames,\n getField(name) { return fields[name]; }\n };\n }\n CifCategory.ofFields = ofFields;\n function ofTable(name, table) {\n const fields = {};\n for (const name of table._columns) {\n fields[name] = CifField.ofColumn(table[name]);\n }\n return ofFields(name, fields);\n }\n CifCategory.ofTable = ofTable;\n})(CifCategory || (CifCategory = {}));\nexport var CifField;\n(function (CifField) {\n function ofString(value) {\n return ofStrings([value]);\n }\n CifField.ofString = ofString;\n function ofStrings(values) {\n const rowCount = values.length;\n const str = row => { const ret = values[row]; if (!ret || ret === '.' || ret === '?')\n return ''; return ret; };\n const int = row => { const v = values[row]; return fastParseInt(v, 0, v.length) || 0; };\n const float = row => { const v = values[row]; return fastParseFloat(v, 0, v.length) || 0; };\n const valueKind = row => {\n const v = values[row], l = v.length;\n if (l > 1)\n return 0 /* Column.ValueKinds.Present */;\n if (l === 0)\n return 1 /* Column.ValueKinds.NotPresent */;\n const c = v.charCodeAt(0);\n if (c === 46 /* . */)\n return 1 /* Column.ValueKinds.NotPresent */;\n if (c === 63 /* ? */)\n return 2 /* Column.ValueKinds.Unknown */;\n return 0 /* Column.ValueKinds.Present */;\n };\n return {\n __array: void 0,\n binaryEncoding: void 0,\n isDefined: true,\n rowCount,\n str,\n int,\n float,\n valueKind,\n areValuesEqual: (rowA, rowB) => values[rowA] === values[rowB],\n toStringArray: params => params ? ColumnHelpers.createAndFillArray(rowCount, str, params) : values,\n toIntArray: params => ColumnHelpers.createAndFillArray(rowCount, int, params),\n toFloatArray: params => ColumnHelpers.createAndFillArray(rowCount, float, params)\n };\n }\n CifField.ofStrings = ofStrings;\n function ofNumbers(values) {\n const rowCount = values.length;\n const str = row => { return '' + values[row]; };\n const float = row => values[row];\n const valueKind = row => 0 /* Column.ValueKinds.Present */;\n const toFloatArray = (params) => {\n if (!params || params.array && values instanceof params.array) {\n return values;\n }\n else {\n return ColumnHelpers.createAndFillArray(rowCount, float, params);\n }\n };\n return {\n __array: void 0,\n binaryEncoding: void 0,\n isDefined: true,\n rowCount,\n str,\n int: float,\n float,\n valueKind,\n areValuesEqual: (rowA, rowB) => values[rowA] === values[rowB],\n toStringArray: params => ColumnHelpers.createAndFillArray(rowCount, str, params),\n toIntArray: toFloatArray,\n toFloatArray\n };\n }\n CifField.ofNumbers = ofNumbers;\n function ofTokens(tokens) {\n const { data, indices, count: rowCount } = tokens;\n const str = row => {\n const ret = data.substring(indices[2 * row], indices[2 * row + 1]);\n if (ret === '.' || ret === '?')\n return '';\n return ret;\n };\n const int = row => {\n return fastParseInt(data, indices[2 * row], indices[2 * row + 1]) || 0;\n };\n const float = row => {\n return fastParseFloat(data, indices[2 * row], indices[2 * row + 1]) || 0;\n };\n const valueKind = row => {\n const s = indices[2 * row], l = indices[2 * row + 1] - s;\n if (l > 1)\n return 0 /* Column.ValueKinds.Present */;\n if (l === 0)\n return 1 /* Column.ValueKinds.NotPresent */;\n const v = data.charCodeAt(s);\n if (v === 46 /* . */)\n return 1 /* Column.ValueKinds.NotPresent */;\n if (v === 63 /* ? */)\n return 2 /* Column.ValueKinds.Unknown */;\n return 0 /* Column.ValueKinds.Present */;\n };\n return {\n __array: void 0,\n binaryEncoding: void 0,\n isDefined: true,\n rowCount,\n str,\n int,\n float,\n valueKind,\n areValuesEqual: areValuesEqualProvider(tokens),\n toStringArray: params => ColumnHelpers.createAndFillArray(rowCount, str, params),\n toIntArray: params => ColumnHelpers.createAndFillArray(rowCount, int, params),\n toFloatArray: params => ColumnHelpers.createAndFillArray(rowCount, float, params)\n };\n }\n CifField.ofTokens = ofTokens;\n function ofColumn(column) {\n const { rowCount, valueKind, areValuesEqual, isDefined } = column;\n let str;\n let int;\n let float;\n switch (column.schema.valueType) {\n case 'float':\n case 'int':\n str = row => { return '' + column.value(row); };\n int = column.value;\n float = column.value;\n break;\n case 'str':\n str = column.value;\n int = row => { const v = column.value(row); return fastParseInt(v, 0, v.length) || 0; };\n float = row => { const v = column.value(row); return fastParseFloat(v, 0, v.length) || 0; };\n break;\n case 'list':\n const { separator } = column.schema;\n str = row => column.value(row).join(separator);\n int = row => NaN;\n float = row => NaN;\n break;\n default:\n throw new Error(`unsupported valueType '${column.schema.valueType}'`);\n }\n return {\n __array: void 0,\n binaryEncoding: void 0,\n isDefined,\n rowCount,\n str,\n int,\n float,\n valueKind,\n areValuesEqual,\n toStringArray: params => ColumnHelpers.createAndFillArray(rowCount, str, params),\n toIntArray: params => ColumnHelpers.createAndFillArray(rowCount, int, params),\n toFloatArray: params => ColumnHelpers.createAndFillArray(rowCount, float, params)\n };\n }\n CifField.ofColumn = ofColumn;\n function ofUndefined(rowCount, schema) {\n return ofColumn(Column.Undefined(rowCount, schema));\n }\n CifField.ofUndefined = ofUndefined;\n})(CifField || (CifField = {}));\nexport function tensorFieldNameGetter(field, rank, zeroIndexed, namingVariant) {\n const offset = zeroIndexed ? 0 : 1;\n switch (rank) {\n case 1:\n return namingVariant === 'brackets'\n ? (i) => `${field}[${i + offset}]`\n : (i) => `${field}_${i + offset}`;\n case 2:\n return namingVariant === 'brackets'\n ? (i, j) => `${field}[${i + offset}][${j + offset}]`\n : (i, j) => `${field}_${i + offset}${j + offset}`;\n case 3:\n return namingVariant === 'brackets'\n ? (i, j, k) => `${field}[${i + offset}][${j + offset}][${k + offset}]`\n : (i, j, k) => `${field}_${i + offset}${j + offset}${k + offset}`;\n default:\n throw new Error('Tensors with rank > 3 or rank 0 are currently not supported.');\n }\n}\nexport function getTensor(category, space, row, getName) {\n const ret = space.create();\n if (space.rank === 1) {\n const rows = space.dimensions[0];\n for (let i = 0; i < rows; i++) {\n const f = category.getField(getName(i));\n space.set(ret, i, !!f ? f.float(row) : 0.0);\n }\n }\n else if (space.rank === 2) {\n const rows = space.dimensions[0], cols = space.dimensions[1];\n for (let i = 0; i < rows; i++) {\n for (let j = 0; j < cols; j++) {\n const f = category.getField(getName(i, j));\n space.set(ret, i, j, !!f ? f.float(row) : 0.0);\n }\n }\n }\n else if (space.rank === 3) {\n const d0 = space.dimensions[0], d1 = space.dimensions[1], d2 = space.dimensions[2];\n for (let i = 0; i < d0; i++) {\n for (let j = 0; j < d1; j++) {\n for (let k = 0; k < d2; k++) {\n const f = category.getField(getName(i, j, k));\n space.set(ret, i, j, k, !!f ? f.float(row) : 0.0);\n }\n }\n }\n }\n else {\n throw new Error('Tensors with rank > 3 or rank 0 are currently not supported.');\n }\n return ret;\n}\nexport function getCifFieldType(field) {\n let floatCount = 0, hasStringOrScientific = false, undefinedCount = 0;\n for (let i = 0, _i = field.rowCount; i < _i; i++) {\n const k = field.valueKind(i);\n if (k !== 0 /* Column.ValueKinds.Present */) {\n undefinedCount++;\n continue;\n }\n const type = getNumberType(field.str(i));\n if (type === 0 /* NumberTypes.Int */)\n continue;\n else if (type === 1 /* NumberTypes.Float */)\n floatCount++;\n else {\n hasStringOrScientific = true;\n break;\n }\n }\n // numbers in scientific notation and plain text are not distinguishable\n if (hasStringOrScientific || undefinedCount === field.rowCount)\n return Column.Schema.str;\n if (floatCount > 0)\n return Column.Schema.float;\n return Column.Schema.int;\n}\n","/**\n * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n * @author Alexander Rose \n */\nimport { ColumnHelpers } from '../../../../../mol-data/db';\nimport { parseInt as fastParseInt, parseFloat as fastParseFloat } from '../number-parser';\nexport function TokenColumnProvider(tokens) {\n return function (type) {\n return TokenColumn(tokens, type);\n };\n}\nexport function TokenColumn(tokens, schema) {\n const { data, indices, count: rowCount } = tokens;\n const { valueType: type } = schema;\n const value = type === 'str'\n ? row => data.substring(indices[2 * row], indices[2 * row + 1])\n : type === 'int'\n ? row => fastParseInt(data, indices[2 * row], indices[2 * row + 1]) || 0\n : row => fastParseFloat(data, indices[2 * row], indices[2 * row + 1]) || 0;\n return {\n schema: schema,\n __array: void 0,\n isDefined: true,\n rowCount,\n value,\n valueKind: row => 0 /* Column.ValueKinds.Present */,\n toArray: params => ColumnHelpers.createAndFillArray(rowCount, value, params),\n areValuesEqual: areValuesEqualProvider(tokens)\n };\n}\nexport function areValuesEqualProvider(tokens) {\n const { data, indices } = tokens;\n return function (rowA, rowB) {\n const aS = indices[2 * rowA], bS = indices[2 * rowB];\n const len = indices[2 * rowA + 1] - aS;\n if (len !== indices[2 * rowB + 1] - bS)\n return false;\n for (let i = 0; i < len; i++) {\n if (data.charCodeAt(i + aS) !== data.charCodeAt(i + bS)) {\n return false;\n }\n }\n return true;\n };\n}\nexport function areTokensEmpty(tokens) {\n const { count, indices } = tokens;\n for (let i = 0; i < count; ++i) {\n if (indices[2 * i] !== indices[2 * i + 1])\n return false;\n }\n return true;\n}\n","/**\n * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.\n *\n * @author David Sehnal \n */\nfunction createImmediateActions() {\n const thisGlobal = (function () {\n const _window = typeof window !== 'undefined' && window;\n const _self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && self;\n const _global = typeof global !== 'undefined' && global;\n return _window || _global || _self;\n })();\n const tasksByHandle = {};\n const doc = typeof document !== 'undefined' ? document : void 0;\n let nextHandle = 1; // Spec says greater than zero\n let registerImmediate;\n function setImmediate(callback, ...args) {\n // Callback can either be a function or a string\n if (typeof callback !== 'function') {\n callback = new Function('' + callback);\n }\n // Store and register the task\n const task = { callback: callback, args: args };\n tasksByHandle[nextHandle] = task;\n registerImmediate(nextHandle);\n return nextHandle++;\n }\n function clearImmediate(handle) {\n delete tasksByHandle[handle];\n }\n function run(task) {\n const callback = task.callback;\n const args = task.args;\n switch (args.length) {\n case 0:\n callback();\n break;\n case 1:\n callback(args[0]);\n break;\n case 2:\n callback(args[0], args[1]);\n break;\n case 3:\n callback(args[0], args[1], args[2]);\n break;\n default:\n callback.apply(undefined, args);\n break;\n }\n }\n function runIfPresent(handle) {\n const task = tasksByHandle[handle];\n clearImmediate(handle);\n run(task);\n }\n function installNextTickImplementation() {\n registerImmediate = function (handle) {\n process.nextTick(function () { runIfPresent(handle); });\n };\n }\n function canUsePostMessage() {\n if (thisGlobal && thisGlobal.postMessage && !thisGlobal.importScripts) {\n let postMessageIsAsynchronous = true;\n const oldOnMessage = thisGlobal.onmessage;\n thisGlobal.onmessage = function () {\n postMessageIsAsynchronous = false;\n };\n thisGlobal.postMessage('', '*');\n thisGlobal.onmessage = oldOnMessage;\n return postMessageIsAsynchronous;\n }\n }\n function installPostMessageImplementation() {\n // Installs an event handler on `global` for the `message` event: see\n // * https://developer.mozilla.org/en/DOM/window.postMessage\n // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages\n const messagePrefix = 'setImmediate$' + Math.random() + '$';\n const onGlobalMessage = function (event) {\n if (event.source === thisGlobal &&\n typeof event.data === 'string' &&\n event.data.indexOf(messagePrefix) === 0) {\n runIfPresent(+event.data.slice(messagePrefix.length));\n }\n };\n if (window.addEventListener) {\n window.addEventListener('message', onGlobalMessage, false);\n }\n else {\n window.attachEvent('onmessage', onGlobalMessage);\n }\n registerImmediate = function (handle) {\n window.postMessage(messagePrefix + handle, '*');\n };\n }\n function installMessageChannelImplementation() {\n const channel = new MessageChannel();\n channel.port1.onmessage = function (event) {\n const handle = event.data;\n runIfPresent(handle);\n };\n registerImmediate = function (handle) {\n channel.port2.postMessage(handle);\n };\n }\n function installReadyStateChangeImplementation() {\n const html = doc.documentElement;\n registerImmediate = function (handle) {\n // Create a