icn3d 3.33.0 → 3.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/icn3d.module.js CHANGED
@@ -7794,7 +7794,10 @@ class UtilsCls {
7794
7794
  let nOtherAtoms = 0;
7795
7795
  for(let i in atomlist) {
7796
7796
  if(index < testLength) {
7797
- let atomName = atomlist[i].name.trim();
7797
+ let atomName = atomlist[i].name;
7798
+ if(!atomName) continue;
7799
+ atomName = atomName.trim();
7800
+
7798
7801
  if(atomName !== "CA" && atomName !== "P" && atomName !== "O3'" && atomName !== "O3*") {
7799
7802
  //bOtherAtoms = true;
7800
7803
  //break;
@@ -9947,7 +9950,7 @@ class ClickMenu {
9947
9950
  });
9948
9951
 
9949
9952
  me.myEventCls.onIds("#" + me.pre + "mn1_cid", "click", function(e) { me.icn3d; //e.preventDefault();
9950
- me.htmlCls.dialogCls.openDlg('dl_cid', 'Please input PubChem CID');
9953
+ me.htmlCls.dialogCls.openDlg('dl_cid', 'Please input PubChem Compound');
9951
9954
  });
9952
9955
 
9953
9956
  me.myEventCls.onIds("#" + me.pre + "mn1_pngimage", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -11571,13 +11574,21 @@ class ClickMenu {
11571
11574
  });
11572
11575
 
11573
11576
  me.myEventCls.onIds("#" + me.pre + "mn6_distManySets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11574
- me.htmlCls.dialogCls.openDlg('dl_distmanysets', 'Measure the pairwise distance among many sets');
11577
+ me.htmlCls.dialogCls.openDlg('dl_distmanysets', 'Measure the pairwise distances among many sets');
11575
11578
 
11576
11579
  thisClass.setSetsMenus('atomsCustomDistTable');
11577
11580
 
11578
11581
  ic.bMeasureDistance = true;
11579
11582
  });
11580
11583
 
11584
+ me.myEventCls.onIds("#" + me.pre + "mn6_angleManySets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11585
+ me.htmlCls.dialogCls.openDlg('dl_anglemanysets', 'Measure the pairwise angles among many sets');
11586
+
11587
+ thisClass.setSetsMenus('atomsCustomAngleTable');
11588
+
11589
+ ic.bMeasureAngle = true;
11590
+ });
11591
+
11581
11592
  me.myEventCls.onIds("#" + me.pre + "mn6_distanceNo", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11582
11593
  ic.pickpair = false;
11583
11594
  let select = "set lines off";
@@ -11662,6 +11673,10 @@ class ClickMenu {
11662
11673
  me.htmlCls.dialogCls.openDlg('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
11663
11674
  });
11664
11675
 
11676
+ $(document).on("click", "#" + me.pre + "mn6_angleTwoSets", function(e) { me.icn3d; //e.preventDefault();
11677
+ me.htmlCls.dialogCls.openDlg('dl_angle', 'Measure the angle between two vectors');
11678
+ });
11679
+
11665
11680
  $(document).on("click", "#" + me.pre + "mn2_matrix", function(e) { me.icn3d; //e.preventDefault();
11666
11681
  me.htmlCls.dialogCls.openDlg('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
11667
11682
  });
@@ -12582,7 +12597,7 @@ class SetMenu {
12582
12597
  html += this.getLink('mn1_mmcifid', 'RCSB mmCIF ID ' + me.htmlCls.wifiStr, undefined, 2);
12583
12598
  //html += this.getLink('mn1_gi', 'NCBI gi ' + me.htmlCls.wifiStr, undefined, 2);
12584
12599
 
12585
- html += this.getLink('mn1_cid', 'PubChem CID ' + me.htmlCls.wifiStr, 1, 2);
12600
+ html += this.getLink('mn1_cid', 'PubChem CID/Name/InchI ' + me.htmlCls.wifiStr, 1, 2);
12586
12601
 
12587
12602
  html += "</ul>";
12588
12603
  html += "</li>";
@@ -13683,11 +13698,18 @@ class SetMenu {
13683
13698
  html += "<ul>";
13684
13699
  html += this.getRadio('mn6_distance', 'mn6_distanceYes', 'between Two Atoms', undefined, 1, 2);
13685
13700
  html += this.getRadio('mn6_distance', 'mn6_distTwoSets', 'between Two Sets', undefined, undefined, 2);
13686
- html += this.getRadio('mn6_distance', 'mn6_distManySets', 'Among Many Sets', undefined, undefined, 2);
13701
+ html += this.getRadio('mn6_distance', 'mn6_distManySets', 'among Many Sets', undefined, undefined, 2);
13687
13702
  html += this.getRadio('mn6_distance', 'mn6_distanceNo', 'Hide', true, 1, 2);
13688
13703
  html += "</ul>";
13689
13704
  html += "</li>";
13690
13705
 
13706
+ html += this.getMenuText('mn6_anglewrap', 'Angle', undefined, 1, 1);
13707
+ html += "<ul>";
13708
+ html += this.getRadio('mn6_angle', 'mn6_angleManySets', 'among Many Sets', undefined, 1, 2);
13709
+ html += this.getRadio('mn6_angle', 'mn6_angleTwoSets', 'b/w Two Vectors', undefined, undefined, 2);
13710
+ html += "</ul>";
13711
+ html += "</li>";
13712
+
13691
13713
  html += this.getLink('mn6_area', 'Surface Area', 1, 1);
13692
13714
 
13693
13715
  html += this.getMenuText('mn6_addlabelwrap', 'Label', undefined, 1, 1);
@@ -15003,8 +15025,8 @@ class SetDialog {
15003
15025
  html += "</div>";
15004
15026
 
15005
15027
  html += me.htmlCls.divStr + "dl_cid' class='" + dialogClass + "'>";
15006
- html += this.addNotebookTitle('dl_cid', 'Please input a PubChem CID');
15007
- html += "PubChem CID: " + me.htmlCls.inputTextStr + "id='" + me.pre + "cid' value='2244' size=8> ";
15028
+ html += this.addNotebookTitle('dl_cid', 'Please input a PubChem Compound');
15029
+ html += "PubChem CID/Name/InchI: " + me.htmlCls.inputTextStr + "id='" + me.pre + "cid' value='2244' size=8> ";
15008
15030
  html += me.htmlCls.buttonStr + "reload_cid'>Load</button>";
15009
15031
  html += "</div>";
15010
15032
 
@@ -15635,6 +15657,28 @@ class SetDialog {
15635
15657
  html += me.htmlCls.spanNowrapStr + "2. " + me.htmlCls.buttonStr + "applydisttable'>Distances in Table</button></span>";
15636
15658
  html += "</div>";
15637
15659
 
15660
+
15661
+ html += me.htmlCls.divStr + "dl_anglemanysets' class='" + dialogClass + "'>";
15662
+ html += this.addNotebookTitle('dl_anglemanysets', 'Measure angles among many sets');
15663
+ html += me.htmlCls.spanNowrapStr + "1. Select sets for pairwise angles</span><br/>";
15664
+ html += "<table border=0 width=400 cellspacing=10><tr><td>";
15665
+
15666
+ html += me.htmlCls.divNowrapStr + "First sets:</div>";
15667
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "atomsCustomAngleTable2' multiple size='5' style='min-width:130px;'>";
15668
+ html += "</select></div>";
15669
+
15670
+ html += "</td><td>";
15671
+
15672
+ html += me.htmlCls.divNowrapStr + "Second sets:</div>";
15673
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "atomsCustomAngleTable' multiple size='5' style='min-width:130px;'>";
15674
+ html += "</select></div>";
15675
+
15676
+ html += "</td></tr></table>";
15677
+
15678
+ html += me.htmlCls.spanNowrapStr + "2. " + me.htmlCls.buttonStr + "applyangletable'>Angles in Table</button></span>";
15679
+ html += "</div>";
15680
+
15681
+
15638
15682
  html += me.htmlCls.divStr + "dl_stabilizer_rm' class='" + dialogClass + "'>";
15639
15683
  html += this.addNotebookTitle('dl_stabilizer_rm', 'Remove a stabilizer');
15640
15684
  if(me.utilsCls.isMobile()) {
@@ -15914,6 +15958,11 @@ class SetDialog {
15914
15958
  html += this.addNotebookTitle('dl_disttable', 'Distance Table', true);
15915
15959
  html += "</div>";
15916
15960
 
15961
+
15962
+ html += me.htmlCls.divStr + "dl_angletable' class='" + dialogClass + "'>";
15963
+ html += this.addNotebookTitle('dl_angletable', 'Angle Table', true);
15964
+ html += "</div>";
15965
+
15917
15966
  html += me.htmlCls.divStr + "dl_translate' class='" + dialogClass + "'>";
15918
15967
  html += this.addNotebookTitle('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
15919
15968
  html += "X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "translateX' value='' size=4> ";
@@ -15922,6 +15971,20 @@ class SetDialog {
15922
15971
  html += me.htmlCls.buttonStr + "translate_pdb'>Translate</button>";
15923
15972
  html += "</div>";
15924
15973
 
15974
+ html += me.htmlCls.divStr + "dl_angle' class='" + dialogClass + "'>";
15975
+ html += this.addNotebookTitle('dl_angle', 'Measure the angle between two vectors');
15976
+ html += "<b>Vector 1</b>, X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1X' value='' size=6> ";
15977
+ html += "Y: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1Y' value='' size=6> ";
15978
+ html += "Z: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1Z' value='' size=6><br>";
15979
+ html += "<b>Vector 2</b>, X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2X' value='' size=6> ";
15980
+ html += "Y: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2Y' value='' size=6> ";
15981
+ html += "Z: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2Z' value='' size=6><br>";
15982
+ html += "<br>";
15983
+
15984
+ html += me.htmlCls.buttonStr + "measure_angle'>Measure Angle</button>";
15985
+ html += "The angle is: " + me.htmlCls.inputTextStr + "id='" + me.pre + "angle_value' value='' size=6> degree.";
15986
+ html += "</div>";
15987
+
15925
15988
  html += me.htmlCls.divStr + "dl_matrix' class='" + dialogClass + "'>";
15926
15989
  html += this.addNotebookTitle('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
15927
15990
  html += "0: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix0' value='1' size=2> ";
@@ -16765,6 +16828,27 @@ class Events {
16765
16828
  thisClass.setLogCmd("translate pdb " + dx + " " + dy + " " + dz, true);
16766
16829
  });
16767
16830
 
16831
+ me.myEventCls.onIds("#" + me.pre + "measure_angle", "click", function(e) { me.icn3d;
16832
+ e.preventDefault();
16833
+ if(!me.cfg.notebook) dialog.dialog( "close" );
16834
+ let v1X = $("#" + me.pre + "v1X").val();
16835
+ let v1Y = $("#" + me.pre + "v1Y").val();
16836
+ let v1Z= $("#" + me.pre + "v1Z").val();
16837
+
16838
+ let v2X = $("#" + me.pre + "v2X").val();
16839
+ let v2Y = $("#" + me.pre + "v2Y").val();
16840
+ let v2Z = $("#" + me.pre + "v2Z").val();
16841
+
16842
+ let angleRad = new THREE.Vector3(parseFloat(v1X), parseFloat(v1Y), parseFloat(v1Z)).angleTo(new THREE.Vector3(parseFloat(v2X), parseFloat(v2Y), parseFloat(v2Z)));
16843
+ let angle = angleRad / 3.1416 * 180;
16844
+ angle = Math.abs(angle).toFixed(0);
16845
+ if(angle > 180) angle -= 180;
16846
+ if(angle > 90) angle = 180 - angle;
16847
+
16848
+ thisClass.setLogCmd("The angle is " + angle + " degree", false);
16849
+ $("#" + me.pre + "angle_value").val(angle);
16850
+ });
16851
+
16768
16852
  me.myEventCls.onIds("#" + me.pre + "matrix_pdb", "click", function(e) { let ic = me.icn3d;
16769
16853
  e.preventDefault();
16770
16854
  if(!me.cfg.notebook) dialog.dialog( "close" );
@@ -18421,6 +18505,20 @@ class Events {
18421
18505
  thisClass.setLogCmd("disttable | " + nameArray2 + " " + nameArray, true);
18422
18506
  });
18423
18507
 
18508
+ me.myEventCls.onIds("#" + me.pre + "applyangletable", "click", function(e) { let ic = me.icn3d;
18509
+ e.preventDefault();
18510
+ if(!me.cfg.notebook) dialog.dialog( "close" );
18511
+ ic.bMeasureAngle = false;
18512
+
18513
+ let nameArray = $("#" + me.pre + "atomsCustomAngleTable").val();
18514
+ let nameArray2 = $("#" + me.pre + "atomsCustomAngleTable2").val();
18515
+
18516
+ ic.analysisCls.measureAngleManySets(nameArray, nameArray2);
18517
+ me.htmlCls.dialogCls.openDlg('dl_angletable', 'Angles among the sets');
18518
+
18519
+ thisClass.setLogCmd("angletable | " + nameArray2 + " " + nameArray, true);
18520
+ });
18521
+
18424
18522
  me.myEventCls.onIds("#" + me.pre + "applylinebtwsets", "click", function(e) { let ic = me.icn3d;
18425
18523
  e.preventDefault();
18426
18524
 
@@ -29010,18 +29108,17 @@ class Strand {
29010
29108
 
29011
29109
  let bRibbon = fill ? true: false;
29012
29110
 
29013
- // when highlight, the input atoms may only include part of sheet or helix
29014
- // include the whole sheet or helix when highlighting
29111
+ // when highlight, the input atoms may only include one rediue.
29112
+ // add one extra residue to show the strand
29015
29113
  let atomsAdjust = {};
29016
29114
 
29017
- // if( Object.keys(atoms).length < Object.keys(ic.atoms).length) {
29018
- // atomsAdjust = this.getSSExpandedAtoms(atoms);
29019
- // }
29020
- // else {
29021
- // atomsAdjust = atoms;
29022
- // }
29023
-
29024
- atomsAdjust = atoms;
29115
+ let residueHashTmp = ic.firstAtomObjCls.getResiduesFromAtoms(atoms);
29116
+ if( Object.keys(residueHashTmp).length == 1) {
29117
+ atomsAdjust = this.getOneExtraResidue(residueHashTmp);
29118
+ }
29119
+ else {
29120
+ atomsAdjust = atoms;
29121
+ }
29025
29122
 
29026
29123
  if(bHighlight === 2) {
29027
29124
  if(fill) {
@@ -29056,22 +29153,24 @@ class Strand {
29056
29153
  let currentChain, currentResi, currentCA = null, currentO = null, currentColor = null, prevCoorCA = null, prevCoorO = null, prevColor = null;
29057
29154
  let prevCO = null, ss = null, ssend = false, atomid = null, prevAtomid = null, prevAtomSelected = null, prevResi = null, calphaid = null, prevCalphaid = null;
29058
29155
  let strandWidth, bSheetSegment = false, bHelixSegment = false;
29059
- let atom, tubeAtoms = {};
29060
29156
 
29061
- // test the first 30 atoms to see whether only C-alpha is available
29062
- ic.bCalphaOnly = me.utilsCls.isCalphaPhosOnly(atomsAdjust); //, 'CA');
29157
+ // For each chain, test the first 30 atoms to see whether only C-alpha is available
29158
+ let bCalphaOnlyHash = {};
29159
+ for(let chainid in ic.chains) {
29160
+ let atoms = me.hashUtilsCls.hash2Atoms(ic.chains[chainid], ic.atoms);
29161
+ let bCalphaOnly = me.utilsCls.isCalphaPhosOnly(atoms); //, 'CA');
29162
+ bCalphaOnlyHash[chainid] = bCalphaOnly;
29163
+ }
29063
29164
 
29064
29165
  // when highlight, draw whole beta sheet and use bShowArray to show the highlight part
29065
29166
  let residueHash = {};
29066
29167
  for(let i in atomsAdjust) {
29067
- let atom = atomsAdjust[i];
29168
+ let atom = ic.atoms[i];
29068
29169
 
29069
29170
  let residueid = atom.structure + '_' + atom.chain + '_' + atom.resi;
29070
29171
  residueHash[residueid] = 1;
29071
29172
  }
29072
- let totalResidueCount = Object.keys(residueHash).length;
29073
-
29074
- let drawnResidueCount = 0;
29173
+ Object.keys(residueHash).length;
29075
29174
 
29076
29175
  let bFullAtom = (Object.keys(ic.hAtoms).length == Object.keys(ic.atoms).length) ? true : false;
29077
29176
 
@@ -29080,22 +29179,20 @@ class Strand {
29080
29179
  let maxDist = 6.0;
29081
29180
 
29082
29181
  //get the last residue
29083
- let atomArray = Object.keys(atoms);
29182
+ let atomArray = Object.keys(atomsAdjust);
29084
29183
  let lastAtomSerial = atomArray[atomArray.length - 1];
29085
- let lastAtom = atoms[lastAtomSerial];
29184
+ let lastAtom = ic.atoms[lastAtomSerial];
29086
29185
  let lastResid = lastAtom.structure + '_' + lastAtom.chain + '_' + lastAtom.resi;
29087
29186
 
29088
29187
  for (let i in atomsAdjust) {
29089
- atom = atomsAdjust[i];
29188
+ let atom = ic.atoms[i];
29090
29189
  let chainid = atom.structure + '_' + atom.chain;
29091
29190
  let resid = atom.structure + '_' + atom.chain + '_' + atom.resi;
29092
29191
  if ((atom.name === 'O' || atom.name === 'CA') && !atom.het) {
29093
29192
  // "CA" has to appear before "O"
29094
29193
 
29095
29194
  if (atom.name === 'CA') {
29096
- if ( atoms.hasOwnProperty(i) && ((atom.ss !== 'helix' && atom.ss !== 'sheet') || atom.ssend || atom.ssbegin) ) {
29097
- tubeAtoms[i] = atom;
29098
- }
29195
+ if ( atoms.hasOwnProperty(i) && ((atom.ss !== 'helix' && atom.ss !== 'sheet') || atom.ssend || atom.ssbegin) ) ;
29099
29196
 
29100
29197
  currentCA = atom.coord;
29101
29198
  currentColor = atom.color;
@@ -29104,7 +29201,7 @@ class Strand {
29104
29201
  caArray.push(atom.serial);
29105
29202
  }
29106
29203
 
29107
- if (atom.name === 'O' || (ic.bCalphaOnly && atom.name === 'CA')) {
29204
+ if (atom.name === 'O' || (bCalphaOnlyHash[chainid] && atom.name === 'CA')) {
29108
29205
  if(currentCA === null || currentCA === undefined) {
29109
29206
  currentCA = atom.coord;
29110
29207
  currentColor = atom.color;
@@ -29167,7 +29264,7 @@ class Strand {
29167
29264
  }
29168
29265
  }
29169
29266
  }
29170
- else if(ic.bCalphaOnly && atom.name === 'CA') {
29267
+ else if(bCalphaOnlyHash[chainid] && atom.name === 'CA') {
29171
29268
  if(caArray.length > resSpan + 1) { // use the calpha and the previous 4th c-alpha to calculate the helix direction
29172
29269
  O = prevCoorCA.clone();
29173
29270
  oldCA = ic.atoms[caArray[caArray.length - 1 - resSpan - 1]].coord.clone();
@@ -29202,8 +29299,6 @@ class Strand {
29202
29299
  bShowArray.push(0);
29203
29300
  calphaIdArray.push(0);
29204
29301
  }
29205
-
29206
- ++drawnResidueCount;
29207
29302
  }
29208
29303
 
29209
29304
  //let bBrokenSs = ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + currentChain, currentResi) + 1 !== ic.ParserUtilsCls.getResiNCBI(chainid, atom.resi) || (prevCoorCA && Math.abs(currentCA.x - prevCoorCA.x) > maxDist) || (prevCoorCA && Math.abs(currentCA.y - prevCoorCA.y) > maxDist) || (prevCoorCA && Math.abs(currentCA.z - prevCoorCA.z) > maxDist);
@@ -29232,7 +29327,9 @@ class Strand {
29232
29327
  // }
29233
29328
 
29234
29329
  //if ((atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs) && pnts[0].length > 0 && bSameChain) {
29235
- if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs || resid == lastResid) && pnts[0].length > 0) {
29330
+ // if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs || resid == lastResid) && pnts[0].length > 0) { // last coil was not drawn correctly, e.g., in 1TOP
29331
+
29332
+ if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || bBrokenSs || (resid == lastResid && atom.ss != 'coil')) && pnts[0].length > 0) {
29236
29333
  let atomName = 'CA';
29237
29334
 
29238
29335
  let prevone = [], nexttwo = [];
@@ -29289,7 +29386,7 @@ class Strand {
29289
29386
  O = currentO.clone();
29290
29387
  O.sub(currentCA);
29291
29388
  }
29292
- else if(ic.bCalphaOnly && atom.name === 'CA') {
29389
+ else if(bCalphaOnlyHash[chainid] && atom.name === 'CA') {
29293
29390
  if(caArray.length > resSpan) { // use the calpha and the previous 4th c-alpha to calculate the helix direction
29294
29391
  O = currentCA.clone();
29295
29392
  oldCA = ic.atoms[caArray[caArray.length - 1 - resSpan]].coord.clone();
@@ -29378,7 +29475,9 @@ class Strand {
29378
29475
  // end of a chain, or end of selection
29379
29476
  if ((currentChain !== atom.chain
29380
29477
  || ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + currentChain, currentResi) + 1 !== ic.ParserUtilsCls.getResiNCBI(chainid, atom.resi)
29381
- || resid == lastResid
29478
+ // || (drawnResidueCount === totalResidueCount - 1)
29479
+ // || bBrokenSs
29480
+ || (resid == lastResid && atom.ss != 'coil')
29382
29481
  ) && pnts[0].length > 0) {
29383
29482
  //if ((currentChain !== atom.chain) && pnts[0].length > 0) {
29384
29483
 
@@ -29446,18 +29545,42 @@ class Strand {
29446
29545
  prevCoorCA = currentCA;
29447
29546
  prevCoorO = atom.coord;
29448
29547
  prevColor = currentColor;
29449
- } // end if (atom.name === 'O' || (ic.bCalphaOnly && atom.name === 'CA') ) {
29548
+ } // end if (atom.name === 'O' || (bCalphaOnlyHash[chainid] && atom.name === 'CA') ) {
29450
29549
  } // end if ((atom.name === 'O' || atom.name === 'CA') && !atom.het) {
29451
29550
  } // end for
29452
29551
 
29453
29552
  caArray = [];
29454
29553
 
29455
- ic.tubeCls.createTube(tubeAtoms, 'CA', coilWidth, bHighlight);
29456
-
29457
- tubeAtoms = {};
29554
+ // ic.tubeCls.createTube(tubeAtoms, 'CA', coilWidth, bHighlight);
29555
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
29556
+ ic.tubeCls.createTube(atomsAdjust, 'CA', coilWidth, bHighlight);
29458
29557
  pnts = {};
29459
29558
  }
29460
29559
 
29560
+ getOneExtraResidue(residueHash) { let ic = this.icn3d, me = ic.icn3dui;
29561
+ let atomsAdjust = {};
29562
+
29563
+ for(let resid in residueHash) {
29564
+ atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, ic.residues[resid]);
29565
+
29566
+ let residNcbi = ic.resid2ncbi[resid];
29567
+ let resiNcbi = residNcbi.substr(residNcbi.lastIndexOf('_') + 1);
29568
+
29569
+ let nextResidNcbi = residNcbi.substr(0, residNcbi.lastIndexOf('_')) + '_' + (parseInt(resiNcbi) + 1);
29570
+ let nextResid = ic.ncbi2resid[nextResidNcbi];
29571
+
29572
+ if(!nextResid) {
29573
+ nextResidNcbi = residNcbi.substr(0, residNcbi.lastIndexOf('_')) + '_' + (parseInt(resiNcbi) - 1);
29574
+ nextResid = ic.ncbi2resid[nextResidNcbi];
29575
+ }
29576
+
29577
+ if(nextResid) atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, ic.residues[nextResid]);
29578
+ }
29579
+
29580
+ return atomsAdjust;
29581
+ }
29582
+
29583
+ /*
29461
29584
  getSSExpandedAtoms(atoms, bHighlight) { let ic = this.icn3d, me = ic.icn3dui;
29462
29585
  let currChain, currResi, currAtom, prevChain, prevResi, prevAtom;
29463
29586
  let firstAtom, lastAtom;
@@ -29564,6 +29687,7 @@ class Strand {
29564
29687
 
29565
29688
  return atomsAdjust;
29566
29689
  }
29690
+ */
29567
29691
  }
29568
29692
 
29569
29693
  /**
@@ -29583,7 +29707,8 @@ class Strip {
29583
29707
  if (p0.length < 2) return;
29584
29708
  div = div || ic.axisDIV;
29585
29709
 
29586
- if(pntsCA && ic.bDoublecolor && !ic.bCalphaOnly) {
29710
+ // if(pntsCA && ic.bDoublecolor && !ic.bCalphaOnly) {
29711
+ if(pntsCA && ic.bDoublecolor) {
29587
29712
  let bExtendLastRes = false; //true;
29588
29713
 
29589
29714
  let pnts_clrs = me.subdivideCls.subdivide(pntsCA, colors, div, bShowArray, bHighlight, prevone, nexttwo, bExtendLastRes);
@@ -29911,7 +30036,7 @@ class Tube {
29911
30036
  //Create tubes for "atoms" with certain "atomName". "radius" is the radius of the tubes.
29912
30037
  //"bHighlight" is an option to draw the highlight for these atoms. The highlight could be
29913
30038
  //outlines with bHighlight=1 and 3D objects with bHighlight=2.
29914
- createTube(atoms, atomName, radius, bHighlight, bCustom, bRadiusArray) { let ic = this.icn3d, me = ic.icn3dui;
30039
+ createTube(atoms, atomName, radius, bHighlight, bCustom, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
29915
30040
  if(me.bNode) return;
29916
30041
 
29917
30042
  let pnts = [], colors = [], radii = [], prevone = [], nexttwo = [];
@@ -30023,6 +30148,9 @@ class Tube {
30023
30148
  else {
30024
30149
  radiusFinal = this.getRadius(radius, atom);
30025
30150
  }
30151
+
30152
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
30153
+ if(!bNonCoil && atom.ss != 'coil' && !atom.ssbegin && !atom.ssend ) radiusFinal = 0;
30026
30154
 
30027
30155
  //radii.push(radius || (atom.b > 0 ? atom.b * 0.01 : ic.coilWidth));
30028
30156
  radii.push(radiusFinal);
@@ -30096,183 +30224,247 @@ class Tube {
30096
30224
  let prevone = pnts_colors_radii_prevone_nexttwo[i].prevone;
30097
30225
  let nexttwo = pnts_colors_radii_prevone_nexttwo[i].nexttwo;
30098
30226
 
30099
- this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bRadiusArray);
30227
+ this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil);
30100
30228
  }
30101
30229
 
30102
- pnts_colors_radii_prevone_nexttwo = [];
30230
+ pnts_colors_radii_prevone_nexttwo = [];
30103
30231
  }
30104
30232
 
30105
- getCustomtubesize(resid) { let ic = this.icn3d; ic.icn3dui;
30106
- let pos = resid.lastIndexOf('_');
30107
- let resi = resid.substr(pos + 1);
30108
- let chainid = resid.substr(0, pos);
30233
+ /*
30234
+ createTube(atoms, atomName, radius, bHighlight, bCustom, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
30235
+ if(me.bNode) return;
30109
30236
 
30110
- let radiusFinal = (ic.queryresi2score[chainid] && ic.queryresi2score[chainid].hasOwnProperty(resi)) ? ic.queryresi2score[chainid][resi] * 0.01 : ic.coilWidth;
30237
+ let pnts = [], colors = [], radii = [], prevone = [], nexttwo = [];
30238
+ let currentChain, currentResi;
30239
+ let index = 0;
30240
+ let maxDist = 6.0;
30241
+ let maxDist2 = 3.0; // avoid tube between the residues in 3 residue helix
30111
30242
 
30112
- return radiusFinal;
30113
- };
30243
+ let pnts_colors_radii_prevone_nexttwo = [];
30244
+ let firstAtom, atom, prevAtom;
30114
30245
 
30115
- // modified from iview (http://istar.cse.cuhk.edu.hk/iview/)
30116
- createTubeSub(_pnts, colors, radii, bHighlight, prevone, nexttwo, bRadiusArray) { let ic = this.icn3d, me = ic.icn3dui;
30117
- if(me.bNode) return;
30246
+ for (let i in atoms) {
30247
+ atom = atoms[i];
30248
+ if ((atom.name === atomName) && !atom.het) {
30249
+ if(index == 0) {
30250
+ firstAtom = atom;
30251
+ }
30118
30252
 
30119
- if (_pnts.length < 2) return;
30253
+ if (index > 0 && (currentChain !== atom.chain || Math.abs(atom.coord.x - prevAtom.coord.x) > maxDist || Math.abs(atom.coord.y - prevAtom.coord.y) > maxDist || Math.abs(atom.coord.z - prevAtom.coord.z) > maxDist
30254
+ || (ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + currentChain, currentResi) + 1 < ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + atom.chain, atom.resi) && (Math.abs(atom.coord.x - prevAtom.coord.x) > maxDist2 || Math.abs(atom.coord.y - prevAtom.coord.y) > maxDist2 || Math.abs(atom.coord.z - prevAtom.coord.z) > maxDist2))
30255
+ ) ) {
30256
+ if(bHighlight !== 2) {
30257
+ if(!isNaN(firstAtom.resi) && !isNaN(prevAtom.resi)) {
30258
+ let prevoneResid = firstAtom.structure + '_' + firstAtom.chain + '_' + (parseInt(firstAtom.resi) - 1).toString();
30259
+ let prevoneCoord = ic.firstAtomObjCls.getAtomCoordFromResi(prevoneResid, atomName);
30260
+ prevone = (prevoneCoord !== undefined) ? [prevoneCoord] : [];
30120
30261
 
30121
- // if(bRadiusArray) {
30122
- let circleDiv = ic.tubeDIV, axisDiv = ic.axisDIV;
30123
- let circleDivInv = 1 / circleDiv, axisDivInv = 1 / axisDiv;
30124
- //var geo = new THREE.Geometry();
30125
- let geo = new THREE.BufferGeometry();
30126
- let verticeArray = [], colorArray = [],indexArray = [], color;
30127
- let offset = 0, offset2 = 0, offset3 = 0;
30262
+ let nextoneResid = prevAtom.structure + '_' + prevAtom.chain + '_' + (parseInt(prevAtom.resi) + 1).toString();
30128
30263
 
30129
- let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
30264
+ // add one more residue if only one residue is available
30265
+ if(pnts.length == 1 && ic.residues.hasOwnProperty(nextoneResid)) {
30266
+ let nextAtom = ic.firstAtomObjCls.getAtomFromResi(nextoneResid, atomName);
30130
30267
 
30131
- let pnts = pnts_clrs[0];
30132
- colors = pnts_clrs[2];
30268
+ if(nextAtom) {
30269
+ pnts.push(nextAtom.coord);
30270
+ colors.push(nextAtom.color);
30133
30271
 
30134
- let prevAxis1 = new THREE.Vector3(), prevAxis2;
30135
- for (let i = 0, lim = pnts.length; i < lim; ++i) {
30136
- let r, idx = (i - 1) * axisDivInv;
30137
- if (i === 0) r = radii[0];
30138
- else {
30139
- if (idx % 1 === 0) r = radii[idx];
30140
- else {
30141
- let floored = Math.floor(idx);
30142
- let tmp = idx - floored;
30143
- r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp);
30272
+ let radiusFinal = this.getRadius(radius, atom);
30273
+ radii.push(radiusFinal);
30274
+ }
30275
+ }
30276
+
30277
+ }
30278
+
30279
+ pnts_colors_radii_prevone_nexttwo.push({'pnts':pnts, 'colors':colors, 'radii':radii, 'prevone':prevone, 'nexttwo':nexttwo});
30144
30280
  }
30281
+ pnts = []; colors = []; radii = []; prevone = []; nexttwo = [];
30282
+ firstAtom = atom;
30283
+ index = 0;
30145
30284
  }
30146
- let delta, axis1, axis2;
30147
- if (i < lim - 1) {
30148
- delta = pnts[i].clone().sub(pnts[i + 1]);
30149
- axis1 = new THREE.Vector3(0, -delta.z, delta.y).normalize().multiplyScalar(r);
30150
- axis2 = delta.clone().cross(axis1).normalize().multiplyScalar(r);
30151
- // let dir = 1, offset = 0;
30152
- if (prevAxis1.dot(axis1) < 0) {
30153
- axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv;
30154
- }
30155
- prevAxis1 = axis1; prevAxis2 = axis2;
30156
- } else {
30157
- axis1 = prevAxis1; axis2 = prevAxis2;
30285
+
30286
+ pnts.push(atom.coord);
30287
+
30288
+ let radiusFinal;
30289
+ if(bCustom) {
30290
+ radiusFinal = this.getCustomtubesize(atom.structure + '_' + atom.chain + '_' + atom.resi);
30291
+ }
30292
+ else {
30293
+ radiusFinal = this.getRadius(radius, atom);
30158
30294
  }
30159
- for (let j = 0; j < circleDiv; ++j) {
30160
- let angle = 2 * Math.PI * circleDivInv * j; //* dir + offset;
30161
- let point = pnts[i].clone().add(axis1.clone().multiplyScalar(Math.cos(angle))).add(axis2.clone().multiplyScalar(Math.sin(angle)));
30162
- verticeArray[offset++] = point.x;
30163
- verticeArray[offset++] = point.y;
30164
- verticeArray[offset++] = point.z;
30165
30295
 
30166
- color = (i == colors.length - 1 && colors.length > 1) ? me.parasCls.thr(colors[colors.length - 2]) : me.parasCls.thr(colors[i]);
30167
- colorArray[offset2++] = color.r;
30168
- colorArray[offset2++] = color.g;
30169
- colorArray[offset2++] = color.b;
30296
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
30297
+ if(!bNonCoil && atom.ss != 'coil' && !atom.ssbegin && !atom.ssend ) radiusFinal = 0;
30298
+
30299
+ //radii.push(radius || (atom.b > 0 ? atom.b * 0.01 : ic.coilWidth));
30300
+ radii.push(radiusFinal);
30301
+
30302
+ colors.push(atom.color);
30303
+ // the starting residue of a coil uses the color from the next residue to avoid using the color of the last helix/sheet residue
30304
+ if(index === 1) colors[colors.length - 2] = atom.color;
30305
+
30306
+ currentChain = atom.chain;
30307
+ currentResi = atom.resi;
30308
+
30309
+ let scale = 1.2;
30310
+ if(bHighlight === 2 && !atom.ssbegin) {
30311
+ ic.boxCls.createBox(atom, undefined, undefined, scale, undefined, bHighlight);
30170
30312
  }
30313
+
30314
+ ++index;
30315
+
30316
+ prevAtom = atom;
30171
30317
  }
30172
- let offsetTmp = 0, nComp = 3;
30173
- for (let i = 0, lim = pnts.length - 1; i < lim; ++i) {
30174
- let reg = 0;
30175
- //var r1 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv]).lengthSq();
30176
- //var r2 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv + 1]).lengthSq();
30177
- let pos = offsetTmp * nComp;
30178
- let point1 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30179
- pos = (offsetTmp + circleDiv) * nComp;
30180
- let point2 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30181
- pos = (offsetTmp + circleDiv + 1) * nComp;
30182
- let point3 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30183
-
30184
- let r1 = point1.clone().sub(point2).lengthSq();
30185
- let r2 = point1.clone().sub(point3).lengthSq();
30186
- if (r1 > r2) { r1 = r2; reg = 1; } for (let j = 0; j < circleDiv; ++j) {
30187
- //geo.faces.push(new THREE.Face3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv, undefined, c));
30188
- //geo.faces.push(new THREE.Face3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv, undefined, c));
30189
- //indexArray = indexArray.concat([offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv]);
30190
- indexArray[offset3++] = offsetTmp + j;
30191
- indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30192
- indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30193
-
30194
- //indexArray = indexArray.concat([offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv]);
30195
- indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30196
- indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30197
- indexArray[offset3++] = offsetTmp + (j + reg + 1) % circleDiv + circleDiv;
30198
- }
30199
- offsetTmp += circleDiv;
30200
- }
30318
+ }
30201
30319
 
30202
- geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticeArray), nComp));
30203
- geo.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colorArray), nComp));
30320
+ if(bHighlight !== 2) {
30321
+ pnts_colors_radii_prevone_nexttwo.push({'pnts':pnts, 'colors':colors, 'radii':radii, 'prevone':prevone, 'nexttwo':nexttwo});
30322
+ }
30204
30323
 
30205
- geo.setIndex(new THREE.BufferAttribute(new Uint32Array(indexArray), 1));
30206
- //geo.setIndex(indexArray);
30324
+ for(let i = 0, il = pnts_colors_radii_prevone_nexttwo.length; i < il; ++i) {
30325
+ let pnts = pnts_colors_radii_prevone_nexttwo[i].pnts;
30326
+ let colors = pnts_colors_radii_prevone_nexttwo[i].colors;
30327
+ let radii = pnts_colors_radii_prevone_nexttwo[i].radii;
30328
+ let prevone = []; // = pnts_colors_radii_prevone_nexttwo[i].prevone;
30329
+ let nexttwo = []; // = pnts_colors_radii_prevone_nexttwo[i].nexttwo;
30207
30330
 
30208
- //geo.computeFaceNormals();
30209
- //geo.computeVertexNormals(false);
30210
- geo.computeVertexNormals();
30211
- /*
30331
+ this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil);
30212
30332
  }
30213
- else {
30214
- let axisDiv = ic.axisDIV;
30215
30333
 
30216
- let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
30217
- // extend one residue
30218
- //var pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo, true);
30334
+ pnts_colors_radii_prevone_nexttwo = [];
30335
+ }
30336
+ */
30219
30337
 
30220
- _pnts = pnts_clrs[0];
30221
- colors = pnts_clrs[2];
30338
+ getCustomtubesize(resid) { let ic = this.icn3d; ic.icn3dui;
30339
+ let pos = resid.lastIndexOf('_');
30340
+ let resi = resid.substr(pos + 1);
30341
+ let chainid = resid.substr(0, pos);
30222
30342
 
30223
- let radius = ic.coilWidth;
30224
- segments = _pnts.length;
30225
- //radiusSegments = 8;
30226
- radiusSegments = 4; // save memory
30227
- let closed = false;
30343
+ let radiusFinal = (ic.queryresi2score[chainid] && ic.queryresi2score[chainid].hasOwnProperty(resi)) ? ic.queryresi2score[chainid][resi] * 0.01 : ic.coilWidth;
30228
30344
 
30229
- // when using radiusArray with modified three.js, the tube didn't work in picking
30230
- let geo = new THREE.TubeGeometry(
30231
- new THREE.CatmullRomCurve3(_pnts), // path
30232
- segments,
30233
- radius, //radiusArray, //radius,
30234
- radiusSegments,
30235
- closed
30236
- );
30345
+ return radiusFinal;
30346
+ };
30237
30347
 
30238
- //https://stemkoski.github.io/Three.js/Graphulus-Curve.html
30239
- let color, face, numberOfSides, vertexIndex;
30240
- // faces are indexed using characters
30241
- let faceIndices = [ 'a', 'b', 'c', 'd' ];
30348
+ // modified from iview (http://istar.cse.cuhk.edu.hk/iview/)
30349
+ createTubeSub(_pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
30350
+ if(me.bNode) return;
30242
30351
 
30243
- // first, assign colors to vertices as desired
30244
- let prevColor, geoColors = {};
30245
- for ( let s = 0; s <= segments; s++ ) {
30246
- for ( let r = 0; r < radiusSegments; r++ )
30247
- {
30248
- vertexIndex = r + s * radiusSegments;
30249
- color = colors[s];
30250
- if(!color) color = prevColor;
30352
+ if (_pnts.length < 2) return;
30251
30353
 
30252
- geoColors[vertexIndex] = color; // use this array for convenience
30354
+ let circleDiv = ic.tubeDIV, axisDiv = ic.axisDIV;
30355
+ let circleDivInv = 1 / circleDiv, axisDivInv = 1 / axisDiv;
30356
+ //var geo = new THREE.Geometry();
30357
+ let geo = new THREE.BufferGeometry();
30358
+ let verticeArray = [], colorArray = [],indexArray = [], color;
30359
+ let offset = 0, offset2 = 0, offset3 = 0;
30253
30360
 
30254
- prevColor = color;
30255
- }
30256
- }
30361
+ let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
30257
30362
 
30258
- // copy the colors as necessary to the face's vertexColors array.
30259
- // after version r125, geo.faces is undefined for TubeGeometry
30260
- for ( let i = 0; geo.faces && i < geo.faces.length; i++ )
30261
- {
30262
- face = geo.faces[ i ];
30363
+ let pnts = pnts_clrs[0];
30364
+ colors = pnts_clrs[2];
30365
+
30366
+ let constRadiius;
30367
+ // a threshold to stop drawing the tube if it's less than this ratio of radius
30368
+ let thresholdRatio = 1; //0.9;
30369
+
30370
+ let prevAxis1 = new THREE.Vector3(), prevAxis2;
30371
+ for (let i = 0, lim = pnts.length; i < lim; ++i) {
30372
+ let r, idx = (i - 1) * axisDivInv;
30263
30373
 
30264
- numberOfSides = ( face instanceof THREE.Face3 ) ? 3 : 4;
30265
- for( let j = 0; j < numberOfSides; j++ )
30266
- {
30267
- vertexIndex = face[ faceIndices[ j ] ];
30268
- face.vertexColors[ j ] = geoColors[ vertexIndex ];
30374
+ if (i === 0) {
30375
+ r = radii[0];
30376
+ if(r > 0) constRadiius = r;
30377
+ }
30378
+ else {
30379
+ if (idx % 1 === 0) {
30380
+ r = radii[idx];
30381
+ if(r > 0) constRadiius = r;
30382
+ }
30383
+ else {
30384
+ let floored = Math.floor(idx);
30385
+ let tmp = idx - floored;
30386
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
30387
+ // r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp);
30388
+ r = radii[floored] * (1 - tmp) + radii[floored + 1] * tmp;
30389
+
30390
+ // a threshold to stop drawing the tube if it's less than this ratio of radius.
30391
+ // The extra bit of tube connects coil with strands or helices
30392
+ if(!bNonCoil) {
30393
+ if(r < thresholdRatio * constRadiius) {
30394
+ r = 0;
30395
+ }
30396
+ // else if(r < constRadiius) {
30397
+ // r *= 0.5; // use small radius for the connection between coild and sheets/helices
30398
+ // }
30399
+ }
30269
30400
  }
30270
30401
  }
30271
-
30272
- geo.computeFaceNormals();
30273
- geo.computeVertexNormals(false);
30402
+ let delta, axis1, axis2;
30403
+ if (i < lim - 1) {
30404
+ delta = pnts[i].clone().sub(pnts[i + 1]);
30405
+ axis1 = new THREE.Vector3(0, -delta.z, delta.y).normalize().multiplyScalar(r);
30406
+ axis2 = delta.clone().cross(axis1).normalize().multiplyScalar(r);
30407
+ // let dir = 1, offset = 0;
30408
+ if (prevAxis1.dot(axis1) < 0) {
30409
+ axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv;
30410
+ }
30411
+ prevAxis1 = axis1; prevAxis2 = axis2;
30412
+ } else {
30413
+ axis1 = prevAxis1; axis2 = prevAxis2;
30414
+ }
30415
+ for (let j = 0; j < circleDiv; ++j) {
30416
+ let angle = 2 * Math.PI * circleDivInv * j; //* dir + offset;
30417
+ let point = pnts[i].clone().add(axis1.clone().multiplyScalar(Math.cos(angle))).add(axis2.clone().multiplyScalar(Math.sin(angle)));
30418
+ verticeArray[offset++] = point.x;
30419
+ verticeArray[offset++] = point.y;
30420
+ verticeArray[offset++] = point.z;
30421
+
30422
+ color = (i == colors.length - 1 && colors.length > 1) ? me.parasCls.thr(colors[colors.length - 2]) : me.parasCls.thr(colors[i]);
30423
+ colorArray[offset2++] = color.r;
30424
+ colorArray[offset2++] = color.g;
30425
+ colorArray[offset2++] = color.b;
30426
+ }
30427
+ }
30428
+ let offsetTmp = 0, nComp = 3;
30429
+ for (let i = 0, lim = pnts.length - 1; i < lim; ++i) {
30430
+ let reg = 0;
30431
+ //var r1 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv]).lengthSq();
30432
+ //var r2 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv + 1]).lengthSq();
30433
+ let pos = offsetTmp * nComp;
30434
+ let point1 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30435
+ pos = (offsetTmp + circleDiv) * nComp;
30436
+ let point2 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30437
+ pos = (offsetTmp + circleDiv + 1) * nComp;
30438
+ let point3 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30439
+
30440
+ let r1 = point1.clone().sub(point2).lengthSq();
30441
+ let r2 = point1.clone().sub(point3).lengthSq();
30442
+ if (r1 > r2) { r1 = r2; reg = 1; } for (let j = 0; j < circleDiv; ++j) {
30443
+ //geo.faces.push(new THREE.Face3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv, undefined, c));
30444
+ //geo.faces.push(new THREE.Face3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv, undefined, c));
30445
+ //indexArray = indexArray.concat([offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv]);
30446
+ indexArray[offset3++] = offsetTmp + j;
30447
+ indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30448
+ indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30449
+
30450
+ //indexArray = indexArray.concat([offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv]);
30451
+ indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30452
+ indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30453
+ indexArray[offset3++] = offsetTmp + (j + reg + 1) % circleDiv + circleDiv;
30454
+ }
30455
+ offsetTmp += circleDiv;
30274
30456
  }
30275
- */
30457
+
30458
+ geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticeArray), nComp));
30459
+ geo.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colorArray), nComp));
30460
+
30461
+ geo.setIndex(new THREE.BufferAttribute(new Uint32Array(indexArray), 1));
30462
+ //geo.setIndex(indexArray);
30463
+
30464
+ //geo.computeFaceNormals();
30465
+ //geo.computeVertexNormals(false);
30466
+ geo.computeVertexNormals();
30467
+
30276
30468
  let mesh;
30277
30469
  if(bHighlight === 2) {
30278
30470
  //mesh = new THREE.Mesh(geo, new THREE.MeshPhongMaterial({ transparent: true, opacity: 0.5, specular: ic.frac, shininess: ic.shininess, emissive: ic.emissive, vertexColors: THREE.FaceColors, side: THREE.DoubleSide }));
@@ -30855,7 +31047,7 @@ class Axes {
30855
31047
  return cone;
30856
31048
  }
30857
31049
 
30858
- setPc1Axes() { let ic = this.icn3d, me = ic.icn3dui;
31050
+ setPc1Axes(bXAxis) { let ic = this.icn3d, me = ic.icn3dui;
30859
31051
  if(me.bNode) return;
30860
31052
 
30861
31053
  let atomHash = me.hashUtilsCls.intHash(ic.hAtoms, ic.dAtoms);
@@ -30936,6 +31128,11 @@ class Axes {
30936
31128
 
30937
31129
  let positionX = center.clone().add(vecX.normalize().multiplyScalar(maxD * 0.4));
30938
31130
 
31131
+ let prinXaxis = vecX.normalize();
31132
+ me.htmlCls.clickMenuCls.setLogCmd('Principle X-Axis: ' + prinXaxis.x.toFixed(3) + " " + prinXaxis.y.toFixed(3) + " " + prinXaxis.z.toFixed(3), false);
31133
+
31134
+ if(bXAxis) return prinXaxis;
31135
+
30939
31136
  let vecY = new THREE.Vector3(eigenRet.h2[0], eigenRet.h2[1], eigenRet.h2[2]);
30940
31137
  let positionY = center.clone().add(vecY.normalize().multiplyScalar(maxD * 0.3));
30941
31138
 
@@ -35154,6 +35351,9 @@ class ApplySymd {
35154
35351
 
35155
35352
  ic.cylinderCls.createCylinder(start, end, axisRadius, colorAxis, 0);
35156
35353
 
35354
+ let SymAxis = end.clone().sub(start).normalize();
35355
+ me.htmlCls.clickMenuCls.setLogCmd('Symmetry Axis: ' + SymAxis.x.toFixed(3) + " " + SymAxis.y.toFixed(3) + " " + SymAxis.z.toFixed(3), false);
35356
+
35157
35357
  if(ic.bAxisOnly) continue;
35158
35358
 
35159
35359
  if(symmetryType == 'C' || (symmetryType == 'D' && order == nSide) ) {
@@ -35310,87 +35510,87 @@ class ApplySymd {
35310
35510
  pointArray.push(end);
35311
35511
  }
35312
35512
  else ;
35313
- }
35314
35513
 
35315
- if(symmetryType == 'T') {
35316
- let pos1 = pointArray[0]; // pointArray: start, end, start, end, ...
35317
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35514
+ if(symmetryType == 'T') {
35515
+ let pos1 = pointArray[0]; // pointArray: start, end, start, end, ...
35516
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35318
35517
 
35319
- let dist2 = pos1.distanceTo(pointArray[2]);
35320
- let dist3 = pos1.distanceTo(pointArray[3]);
35518
+ let dist2 = pos1.distanceTo(pointArray[2]);
35519
+ let dist3 = pos1.distanceTo(pointArray[3]);
35321
35520
 
35322
- let distSmall, posSel;
35323
- if(dist2 < dist3) {
35324
- distSmall = dist2;
35325
- posSel = pointArray[3];
35326
- }
35327
- else {
35328
- distSmall = dist3;
35329
- posSel = pointArray[2];
35330
- }
35521
+ let distSmall, posSel;
35522
+ if(dist2 < dist3) {
35523
+ distSmall = dist2;
35524
+ posSel = pointArray[3];
35525
+ }
35526
+ else {
35527
+ distSmall = dist3;
35528
+ posSel = pointArray[2];
35529
+ }
35331
35530
 
35332
- ic.sphereCls.createSphereBase(posSel, colorPolygon, polygonRadius, 1.0, 0);
35333
- ic.cylinderCls.createCylinder(pos1, posSel, polygonRadius, colorPolygon, 0);
35531
+ ic.sphereCls.createSphereBase(posSel, colorPolygon, polygonRadius, 1.0, 0);
35532
+ ic.cylinderCls.createCylinder(pos1, posSel, polygonRadius, colorPolygon, 0);
35334
35533
 
35335
- let iPrev;
35336
- for(let i = 4, il = pointArray.length; i < il; ++i) {
35337
- let pos2 = pointArray[i];
35534
+ let iPrev;
35535
+ for(let i = 4, il = pointArray.length; i < il; ++i) {
35536
+ let pos2 = pointArray[i];
35338
35537
 
35339
- let dist = pos1.distanceTo(pos2);
35340
- if(dist > distSmall) {
35341
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35342
- ic.cylinderCls.createCylinder(pos1, pos2, polygonRadius, colorPolygon, 0);
35538
+ let dist = pos1.distanceTo(pos2);
35539
+ if(dist > distSmall) {
35540
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35541
+ ic.cylinderCls.createCylinder(pos1, pos2, polygonRadius, colorPolygon, 0);
35343
35542
 
35344
- ic.cylinderCls.createCylinder(posSel, pos2, polygonRadius, colorPolygon, 0);
35345
- if(iPrev !== undefined) {
35346
- ic.cylinderCls.createCylinder(pointArray[iPrev], pos2, polygonRadius, colorPolygon, 0);
35347
- }
35543
+ ic.cylinderCls.createCylinder(posSel, pos2, polygonRadius, colorPolygon, 0);
35544
+ if(iPrev !== undefined) {
35545
+ ic.cylinderCls.createCylinder(pointArray[iPrev], pos2, polygonRadius, colorPolygon, 0);
35546
+ }
35348
35547
 
35349
- iPrev = i;
35548
+ iPrev = i;
35549
+ }
35350
35550
  }
35351
35551
  }
35352
- }
35353
- else if(symmetryType == 'O') {
35354
- for(let i = 0, il = pointArray.length; i < il; i += 2) {
35355
- let pos1 = pointArray[i];
35356
- let pos2 = pointArray[i+1];
35357
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35358
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35359
- for(let j = i + 2, jl = pointArray.length; j < jl; ++j) {
35360
- let pos3 = pointArray[j];
35361
- ic.sphereCls.createSphereBase(pos3, colorPolygon, polygonRadius, 1.0, 0);
35362
- ic.cylinderCls.createCylinder(pos1, pos3, polygonRadius, colorPolygon, 0);
35363
- ic.cylinderCls.createCylinder(pos2, pos3, polygonRadius, colorPolygon, 0);
35552
+ else if(symmetryType == 'O') {
35553
+ for(let i = 0, il = pointArray.length; i < il; i += 2) {
35554
+ let pos1 = pointArray[i];
35555
+ let pos2 = pointArray[i+1];
35556
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35557
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35558
+ for(let j = i + 2, jl = pointArray.length; j < jl; ++j) {
35559
+ let pos3 = pointArray[j];
35560
+ ic.sphereCls.createSphereBase(pos3, colorPolygon, polygonRadius, 1.0, 0);
35561
+ ic.cylinderCls.createCylinder(pos1, pos3, polygonRadius, colorPolygon, 0);
35562
+ ic.cylinderCls.createCylinder(pos2, pos3, polygonRadius, colorPolygon, 0);
35563
+ }
35364
35564
  }
35365
35565
  }
35366
- }
35367
- else if(symmetryType == 'I') {
35368
- for(let i = 0, il = pointArray.length; i < il; i += 2) {
35369
- let pos1 = pointArray[i];
35370
- let pos2 = pointArray[i+1];
35371
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35372
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35373
- for(let j = i + 2, jl = pointArray.length; j < jl; j += 2) {
35374
- let pos3 = pointArray[j];
35375
- let pos4 = pointArray[j+1];
35566
+ else if(symmetryType == 'I') {
35567
+ for(let i = 0, il = pointArray.length; i < il; i += 2) {
35568
+ let pos1 = pointArray[i];
35569
+ let pos2 = pointArray[i+1];
35570
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35571
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35572
+ for(let j = i + 2, jl = pointArray.length; j < jl; j += 2) {
35573
+ let pos3 = pointArray[j];
35574
+ let pos4 = pointArray[j+1];
35376
35575
 
35377
- let dist3 = pos1.distanceTo(pos3);
35378
- let dist4 = pos1.distanceTo(pos4);
35576
+ let dist3 = pos1.distanceTo(pos3);
35577
+ let dist4 = pos1.distanceTo(pos4);
35379
35578
 
35380
- let pos1Sel, pos2Sel;
35381
- if(dist3 < dist4) {
35382
- pos1Sel = pos3;
35383
- pos2Sel = pos4;
35384
- }
35385
- else {
35386
- pos1Sel = pos4;
35387
- pos2Sel = pos3;
35388
- }
35579
+ let pos1Sel, pos2Sel;
35580
+ if(dist3 < dist4) {
35581
+ pos1Sel = pos3;
35582
+ pos2Sel = pos4;
35583
+ }
35584
+ else {
35585
+ pos1Sel = pos4;
35586
+ pos2Sel = pos3;
35587
+ }
35389
35588
 
35390
- ic.sphereCls.createSphereBase(pos1Sel, colorPolygon, polygonRadius, 1.0, 0);
35391
- ic.sphereCls.createSphereBase(pos2Sel, colorPolygon, polygonRadius, 1.0, 0);
35392
- ic.cylinderCls.createCylinder(pos1, pos1Sel, polygonRadius, colorPolygon, 0);
35393
- ic.cylinderCls.createCylinder(pos2, pos2Sel, polygonRadius, colorPolygon, 0);
35589
+ ic.sphereCls.createSphereBase(pos1Sel, colorPolygon, polygonRadius, 1.0, 0);
35590
+ ic.sphereCls.createSphereBase(pos2Sel, colorPolygon, polygonRadius, 1.0, 0);
35591
+ ic.cylinderCls.createCylinder(pos1, pos1Sel, polygonRadius, colorPolygon, 0);
35592
+ ic.cylinderCls.createCylinder(pos2, pos2Sel, polygonRadius, colorPolygon, 0);
35593
+ }
35394
35594
  }
35395
35595
  }
35396
35596
  }
@@ -45568,7 +45768,6 @@ class AddTrack {
45568
45768
  }
45569
45769
 
45570
45770
  getExonHtml(exonIndex, colorGradient, from, to, genomeRange, chainid, simpTitle) { let ic = this.icn3d; ic.icn3dui;
45571
- // return '<div style="display:inline-block; color:white!important; width:' + Math.round(ic.seqAnnWidth *(to - from + 1) /(ic.maxAnnoLength + ic.nTotalGap)) + 'px;" class="icn3d-seqTitle icn3d-link icn3d-blue" domain="' + (exonIndex + 1) + '" from="' + from + '" to="' + to + '" setname="' + simpTitle + ', Exon ' + (exonIndex + 1) + '" title="Exon ' + (exonIndex + 1) + ': ' + genomeRange + ' genomic interval" anno="sequence" chain="' + chainid + '"><div style="height: 12px; border: 1px solid #000; background: linear-gradient(to right, ' + colorGradient + ');"></div></div>';
45572
45771
  return '<div style="display:inline-block; color:white!important; width:' + Math.round(ic.seqAnnWidth *(to - from + 1) /(ic.maxAnnoLength + ic.nTotalGap)) + 'px;" class="icn3d-seqTitle icn3d-link icn3d-blue" domain="' + (exonIndex + 1) + '" from="' + from + '" to="' + to + '" setname="' + simpTitle + ', ' + (exonIndex + 1) + '" title="Exon: ' + genomeRange + ' genomic interval" anno="sequence" chain="' + chainid + '"><div style="height: 12px; border: 1px solid #000; background: linear-gradient(to right, ' + colorGradient + ');"></div></div>';
45573
45772
  }
45574
45773
 
@@ -46310,7 +46509,7 @@ class AddTrack {
46310
46509
  let targetId = 'genomeRes';
46311
46510
 
46312
46511
  let acc2index = {};
46313
-
46512
+
46314
46513
  for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
46315
46514
  let acc = accArray[index];
46316
46515
 
@@ -46395,22 +46594,24 @@ class AddTrack {
46395
46594
  trackSeqArrayFinal[i] = '';
46396
46595
  }
46397
46596
 
46398
- for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
46399
- let seq = trackSeqArray[maxIndex][j];
46597
+ if(trackSeqArray[maxIndex]) {
46598
+ for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
46599
+ let seq = trackSeqArray[maxIndex][j];
46400
46600
 
46401
- let bExon = (seq != '-') ? true : false;
46402
- if(!bExon) {
46403
- for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46404
- if(trackSeqArray[i][j] != '-') {
46405
- bExon = true;
46406
- break;
46601
+ let bExon = (seq != '-') ? true : false;
46602
+ if(!bExon) {
46603
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46604
+ if(trackSeqArray[i][j] != '-') {
46605
+ bExon = true;
46606
+ break;
46607
+ }
46407
46608
  }
46408
46609
  }
46409
- }
46410
-
46411
- if(bExon) {
46412
- for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46413
- trackSeqArrayFinal[i] += trackSeqArray[i][j];
46610
+
46611
+ if(bExon) {
46612
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46613
+ trackSeqArrayFinal[i] += trackSeqArray[i][j];
46614
+ }
46414
46615
  }
46415
46616
  }
46416
46617
  }
@@ -46481,7 +46682,9 @@ class AddTrack {
46481
46682
  ic.maxAnnoLength = ic.maxAnnoLengthOri + ic.seqStartLen[chainid] + ic.seqEndLen[chainid];
46482
46683
  }
46483
46684
 
46484
- await ic.annotationCls.resetAnnoAll();
46685
+ // do not remove other tracks
46686
+ // await ic.annotationCls.resetAnnoAll();
46687
+ await ic.showAnnoCls.processSeqData(ic.chainid_seq);
46485
46688
 
46486
46689
  let targetGapHashStr = '';
46487
46690
  let cntTmp = 0;
@@ -46648,7 +46851,7 @@ class AddTrack {
46648
46851
 
46649
46852
  let type = 'identity';
46650
46853
 
46651
- await thisClass.addExonTracks(chainid, geneid, startpos, type);
46854
+ await this.addExonTracks(chainid, geneid, startpos, type);
46652
46855
  }
46653
46856
 
46654
46857
  async addExonTracks(chainid, geneid, startpos, type) { let ic = this.icn3d, me = ic.icn3dui;
@@ -46683,13 +46886,12 @@ class AddTrack {
46683
46886
  let cnt = (j == jl - 1) ? itemArray[2] - 3 : itemArray[2]; // The last one is stop codeon
46684
46887
  cntTotal += cnt;
46685
46888
 
46686
- let resStart = parseInt(prevCntTotal/3.0 + 0.5); // 0-based
46687
- let resEnd = parseInt(cntTotal/3.0 + 0.5) - 1; // 0-based
46889
+ let resStart = parseInt((prevCntTotal+2)/3.0); // 0-based
46890
+ let resEnd = parseInt((cntTotal+2)/3.0) - 1; // 0-based
46688
46891
 
46689
- let genResStart = parseInt(itemArray[0] / 3.0 + 0.5);
46690
-
46691
- //let genResEnd = parseInt(itemArray[1] / 3.0 + 0.5); // some difference due to round
46692
- let genResEnd = genResStart + ic.exonOrder * (resEnd - resStart);
46892
+ let genResEnd = parseInt((itemArray[1]+2) / 3.0);
46893
+ // let genResStart = parseInt((itemArray[0]+2) / 3.0); // some difference due to round
46894
+ let genResStart = genResEnd - ic.exonOrder * (resEnd - resStart);
46693
46895
 
46694
46896
  rangeArray.push({genomeRange: genomeRange, genResStart: genResStart, genResEnd: genResEnd, resStart: resStart, resEnd: resEnd});
46695
46897
 
@@ -46743,7 +46945,7 @@ class AddTrack {
46743
46945
 
46744
46946
  let ALen = trackSeqArray.length;
46745
46947
 
46746
- while (i < A.length && j < B.length) {
46948
+ while (A && B && i < A.length && j < B.length) {
46747
46949
  if(A[i] != B[j]) {
46748
46950
  if(A[i] == '-') {
46749
46951
  // insert "-" in B
@@ -58552,13 +58754,7 @@ class RealignParser {
58552
58754
 
58553
58755
  let allPromise = Promise.allSettled(ajaxArray);
58554
58756
  // try {
58555
- // let dataArray = await allPromise;
58556
-
58557
- let startDate = new Date();
58558
58757
  let dataArray = await allPromise;
58559
- let endDate = new Date();
58560
- let miliseconds = (endDate.getTime() - startDate.getTime());
58561
- console.log("vastdyn time: " + miliseconds + " miliseconds");
58562
58758
 
58563
58759
  ic.qt_start_end = []; // reset the alignment
58564
58760
  await ic.chainalignParserCls.downloadChainalignmentPart2bRealign(dataArray, chainidPairArray, bReverse);
@@ -58650,6 +58846,8 @@ class RealignParser {
58650
58846
  async realignChainOnSeqAlign(chainresiCalphaHash2, chainidArray, bRealign, bPredefined) { let ic = this.icn3d, me = ic.icn3dui;
58651
58847
  let thisClass = this;
58652
58848
 
58849
+ me.cfg.aligntool = 'seqalign';
58850
+
58653
58851
  //bRealign: realign based on seq alignment
58654
58852
  //bPredefined: chain alignment with predefined matching residues
58655
58853
 
@@ -60847,9 +61045,11 @@ class LoadAtomData {
60847
61045
  serial2structure[j] = pdbidTmp.toString();
60848
61046
  mmdbid2pdbid[mmdbidTmp] = pdbidTmp;
60849
61047
  }
60850
-
61048
+
60851
61049
  for(let j = 0, jl = structure.molecules.length; j < jl; ++j) {
60852
61050
  let chain = structure.molecules[j].chain;
61051
+ chain = chain.replace(/_/g, ''); // change "A_1" to "A1"
61052
+
60853
61053
  let kind = structure.molecules[j].kind;
60854
61054
  let title = structure.molecules[j].name;
60855
61055
  //var seq = structure.molecules[j].sequence;
@@ -61842,7 +62042,9 @@ class SetSeqAlign {
61842
62042
 
61843
62043
  let resid = chainid + '_' + resi;
61844
62044
  let resn = ic.residueId2Name[resid];
61845
- if(!resn) resn = '?';
62045
+ if(!resn) {
62046
+ resn = '?';
62047
+ }
61846
62048
 
61847
62049
  return resn;
61848
62050
  }
@@ -66554,7 +66756,21 @@ class ApplyCommand {
66554
66756
  let nameArray2 = setNameArray[1].split(',');
66555
66757
 
66556
66758
  ic.analysisCls.measureDistManySets(nameArray, nameArray2);
66557
- me.htmlCls.dialogCls.openDlg('dl_disttable', 'Distance among the sets');
66759
+ me.htmlCls.dialogCls.openDlg('dl_disttable', 'Distances among the sets');
66760
+ }
66761
+ }
66762
+ }
66763
+ else if(commandOri.indexOf('angletable') == 0) {
66764
+ let paraArray = commandOri.split(' | ');
66765
+ if(paraArray.length == 2) {
66766
+ let setNameArray = paraArray[1].split(' ');
66767
+
66768
+ if(setNameArray.length == 2) {
66769
+ let nameArray = setNameArray[0].split(',');
66770
+ let nameArray2 = setNameArray[1].split(',');
66771
+
66772
+ ic.analysisCls.measureAngleManySets(nameArray, nameArray2);
66773
+ me.htmlCls.dialogCls.openDlg('dl_angletable', 'Angles among the sets');
66558
66774
  }
66559
66775
  }
66560
66776
  }
@@ -68162,9 +68378,9 @@ class SelectCollections {
68162
68378
  'chemicals': {},
68163
68379
  'ions': {},
68164
68380
  'water': {},
68165
- 'structures': {}, // getSSExpandedAtoms
68381
+ 'structures': {},
68166
68382
  'ssbondpnts': {},
68167
- 'residues': {}, // getSSExpandedAtoms
68383
+ 'residues': {},
68168
68384
  'chains': {},
68169
68385
  'chainsSeq': {}, //Sequences and Annotation
68170
68386
  'defNames2Atoms': {},
@@ -68213,9 +68429,9 @@ class SelectCollections {
68213
68429
  'chemicals': ic.chemicals,
68214
68430
  'ions': ic.ions,
68215
68431
  'water': ic.water,
68216
- 'structures': ic.structures, // getSSExpandedAtoms
68432
+ 'structures': ic.structures,
68217
68433
  'ssbondpnts': ic.ssbondpnts,
68218
- 'residues': ic.residues, // getSSExpandedAtoms
68434
+ 'residues': ic.residues,
68219
68435
  'chains': ic.chains,
68220
68436
  'chainsSeq': ic.chainsSeq, //Sequences and Annotation
68221
68437
  'defNames2Atoms': ic.defNames2Atoms,
@@ -68229,9 +68445,9 @@ class SelectCollections {
68229
68445
  'chemicals': thisClass.dictionaryDifference(ic.allData['prev']['chemicals'], ic.chemicals),
68230
68446
  'ions': thisClass.dictionaryDifference(ic.allData['prev']['ions'], ic.ions),
68231
68447
  'water': thisClass.dictionaryDifference(ic.allData['prev']['water'], ic.water),
68232
- 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures), // getSSExpandedAtoms
68448
+ 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures),
68233
68449
  'ssbondpnts': thisClass.dictionaryDifference(ic.allData['prev']['ssbondpnts'], ic.ssbondpnts),
68234
- 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues), // getSSExpandedAtoms
68450
+ 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues),
68235
68451
  'chains': thisClass.dictionaryDifference(ic.allData['prev']['chains'], ic.chains),
68236
68452
  'chainsSeq': thisClass.dictionaryDifference(ic.allData['prev']['chainsSeq'], ic.chainsSeq), //Sequences and Annotation
68237
68453
  'defNames2Atoms': thisClass.dictionaryDifference(ic.allData['prev']['defNames2Atoms'], ic.defNames2Atoms),
@@ -75046,7 +75262,73 @@ class Analysis {
75046
75262
 
75047
75263
  $("#" + me.pre + "dl_disttable_html").html(tableHtml);
75048
75264
  }
75049
- }
75265
+ }
75266
+
75267
+ measureAngleManySets(nameArray, nameArray2) {var ic = this.icn3d, me = ic.icn3dui;
75268
+ if(nameArray.length == 0 || nameArray2.length == 0) {
75269
+ alert("Please select sets for angleance calculation...");
75270
+ }
75271
+ else {
75272
+ let angleHash = {};
75273
+
75274
+ for(let i = 0, il = nameArray.length; i < il; ++i) {
75275
+ let set1 = nameArray[i];
75276
+ let array1 = [set1];
75277
+ angleHash[set1] = {};
75278
+
75279
+ ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(array1);
75280
+ let axis1 = ic.axesCls.setPc1Axes(true);
75281
+
75282
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
75283
+ let set2 = nameArray2[j];
75284
+ let array2 = [set2];
75285
+
75286
+ if(set1 == set2) continue;
75287
+
75288
+ ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(array2);
75289
+ let axis2 = ic.axesCls.setPc1Axes(true);
75290
+
75291
+ let angleRad = new THREE.Vector3(parseFloat(axis1.x), parseFloat(axis1.y), parseFloat(axis1.z)).angleTo(new THREE.Vector3(parseFloat(axis2.x), parseFloat(axis2.y), parseFloat(axis2.z)));
75292
+
75293
+ let angle = angleRad / 3.1416 * 180;
75294
+ angle = Math.abs(angle).toFixed(0);
75295
+ if(angle > 180) angle -= 180;
75296
+ if(angle > 90) angle = 180 - angle;
75297
+
75298
+ angleHash[set1][set2] = angle;
75299
+ }
75300
+ }
75301
+
75302
+ let tableHtml = '<table align=center border=1 cellpadding=10 cellspacing=0><tr><th></th>';
75303
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
75304
+ let set2 = nameArray2[j];
75305
+ tableHtml += '<th><b>' + set2 + '</b> (&deg;)</th>';
75306
+ }
75307
+ tableHtml += '</tr>';
75308
+
75309
+ for(let i = 0, il = nameArray.length; i < il; ++i) {
75310
+ let set1 = nameArray[i];
75311
+ tableHtml += '<tr><th><b>' + set1 + '</b> (&deg;)</th>';
75312
+
75313
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
75314
+ let set2 = nameArray2[j];
75315
+
75316
+ if(angleHash[set1] && angleHash[set1][set2]) {
75317
+ tableHtml += '<td><span>' + angleHash[set1][set2] + '</span></td>';
75318
+ }
75319
+ else {
75320
+ tableHtml += '<td>0</td>';
75321
+ }
75322
+ }
75323
+
75324
+ tableHtml += '</tr>';
75325
+ }
75326
+
75327
+ tableHtml += '</table><br><br>';
75328
+
75329
+ $("#" + me.pre + "dl_angletable_html").html(tableHtml);
75330
+ }
75331
+ }
75050
75332
 
75051
75333
  //Add a line between the position (x1, y1, z1) and the position (x2, y2, z2) with the input "color".
75052
75334
  //The line can be dashed if "dashed" is set true.
@@ -78889,7 +79171,8 @@ class ShareLink {
78889
79171
  }
78890
79172
  else {
78891
79173
  text += "\nStart of type file======\n";
78892
- text += ic.InputfileType + "\n";
79174
+ // text += ic.InputfileType + "\n";
79175
+ text += "pdb\n";
78893
79176
  text += "End of type file======\n";
78894
79177
 
78895
79178
  text += "Start of data file======\n";
@@ -81754,7 +82037,7 @@ class iCn3DUI {
81754
82037
  //even when multiple iCn3D viewers are shown together.
81755
82038
  this.pre = this.cfg.divid + "_";
81756
82039
 
81757
- this.REVISION = '3.33.0';
82040
+ this.REVISION = '3.33.2';
81758
82041
 
81759
82042
  // In nodejs, iCn3D defines "window = {navigator: {}}"
81760
82043
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -81898,7 +82181,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81898
82181
  ic.setStyleCls.handleContextLost();
81899
82182
  ic.applyCenterCls.setWidthHeight(width, height);
81900
82183
  ic.ori_chemicalbinding = ic.opts['chemicalbinding'];
81901
- if(me.cfg.bCalphaOnly !== undefined) ic.bCalphaOnly = me.cfg.bCalphaOnly;
82184
+ // if(me.cfg.bCalphaOnly !== undefined) ic.bCalphaOnly = me.cfg.bCalphaOnly;
81902
82185
  ic.opts = me.hashUtilsCls.cloneHash(ic.opts);
81903
82186
  ic.STATENUMBER = ic.commands.length;
81904
82187
  // If previously crashed, recover it
@@ -81926,7 +82209,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81926
82209
  ic.bInputfile = true;
81927
82210
  ic.InputfileType = 'pdb';
81928
82211
  ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + pdbStr : pdbStr;
81929
-
82212
+
81930
82213
  await ic.pdbParserCls.loadPdbData(pdbStr);
81931
82214
 
81932
82215
  if(me.cfg.resdef !== undefined && me.cfg.chains !== undefined) {
@@ -81937,9 +82220,9 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81937
82220
  for(let i = 0, il = structureArray.length; i < il; ++i) {
81938
82221
  chainidArray.push(structureArray[i] + '_' + chainArray[i]);
81939
82222
  }
81940
-
82223
+
81941
82224
  chainidArray = ic.chainalignParserCls.addPostfixForChainids(chainidArray);
81942
-
82225
+
81943
82226
  let bRealign = true, bPredefined = true;
81944
82227
  await ic.realignParserCls.realignChainOnSeqAlign(undefined, chainidArray, bRealign, bPredefined);
81945
82228
  }
@@ -81960,7 +82243,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81960
82243
  chainidArray.push(domainidArray[i]);
81961
82244
  }
81962
82245
  }
81963
-
82246
+
81964
82247
  // get the matched structures, do not include the template
81965
82248
  let mmdbafid = '';
81966
82249
  for(let i = 0, il = chainidArray.length; i < il; ++i) {
@@ -81971,7 +82254,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81971
82254
  // realign, include the template
81972
82255
  ic.chainidArray = [chain_t].concat(chainidArray);
81973
82256
  ic.chainidArray = ic.chainalignParserCls.addPostfixForChainids(ic.chainidArray);
81974
-
82257
+
81975
82258
  me.htmlCls.clickMenuCls.setLogCmd('resdef ' + me.cfg.resdef, true);
81976
82259
 
81977
82260
  ic.loadCmd = 'vast_search_chainid ' + ic.chainidArray;
@@ -82048,7 +82331,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82048
82331
  }
82049
82332
  else if(me.cfg.refseqid !== undefined) {
82050
82333
  ic.inputid = me.cfg.refseqid;
82051
-
82334
+
82052
82335
  // ic.bNCBI = true;
82053
82336
  ic.loadCmd = 'load refseq ' + me.cfg.refseqid;
82054
82337
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
@@ -82056,7 +82339,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82056
82339
  }
82057
82340
  else if(me.cfg.protein !== undefined) {
82058
82341
  ic.inputid = me.cfg.protein;
82059
-
82342
+
82060
82343
  // ic.bNCBI = true;
82061
82344
  ic.loadCmd = 'load protein ' + me.cfg.protein;
82062
82345
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
@@ -82065,7 +82348,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82065
82348
  else if(me.cfg.blast_rep_id !== undefined) {
82066
82349
  // ic.bNCBI = true;
82067
82350
  ic.inputid = me.cfg.query_id + ',' + me.cfg.blast_rep_id;
82068
-
82351
+
82069
82352
  me.cfg.oriQuery_id = me.cfg.query_id;
82070
82353
  me.cfg.oriBlast_rep_id = me.cfg.blast_rep_id;
82071
82354
 
@@ -82089,7 +82372,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82089
82372
  ic.bSmithwm = false;
82090
82373
  ic.bLocalSmithwm = false;
82091
82374
  }
82092
-
82375
+
82093
82376
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
82094
82377
  await ic.mmdbParserCls.downloadBlast_rep_id(me.cfg.query_id + ',' + me.cfg.blast_rep_id);
82095
82378
  }
@@ -82098,7 +82381,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82098
82381
  let data = await me.getAjaxPromise(url, 'json', false, 'The RID ' + me.cfg.rid + ' may have expired...');
82099
82382
 
82100
82383
  for(let q = 0, ql = data.BlastOutput2.length; q < ql; ++q) {
82101
-
82384
+
82102
82385
  let hitArray;
82103
82386
  if(data.BlastOutput2[q].report.results.iterations) { // psi-blast may have "iterations". Use the last iteration.
82104
82387
  let nIterations = data.BlastOutput2[q].report.results.iterations.length;
@@ -82109,7 +82392,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82109
82392
  if(data.BlastOutput2[q].report.results.search.query_id != me.cfg.query_id) continue;
82110
82393
  hitArray = data.BlastOutput2[q].report.results.search.hits;
82111
82394
  }
82112
-
82395
+
82113
82396
  let qseq = undefined;
82114
82397
  for(let i = 0, il = hitArray.length; i < il; ++i) {
82115
82398
  let hit = hitArray[i];
@@ -82141,6 +82424,18 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82141
82424
  }
82142
82425
  }
82143
82426
  else if(me.cfg.cid !== undefined) {
82427
+ if(isNaN(me.cfg.cid)) {
82428
+ let urlCid = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?compound2cid=" + me.cfg.cid;
82429
+ let cidJson = await me.getAjaxPromise(urlCid, 'jsonp');
82430
+ if(cidJson.cid && cidJson.cid[0]) {
82431
+ me.cfg.cid = cidJson.cid[0];
82432
+ }
82433
+ else {
82434
+ alert("Please input an valid PubChem CID...");
82435
+ return;
82436
+ }
82437
+ }
82438
+
82144
82439
  ic.inputid = me.cfg.cid;
82145
82440
 
82146
82441
  let url = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/" + ic.inputid + "/description/jsonp";
@@ -82205,7 +82500,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82205
82500
  }
82206
82501
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
82207
82502
 
82208
- await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
82503
+ await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
82209
82504
  //await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
82210
82505
  }
82211
82506
  else if(me.cfg.command !== undefined && me.cfg.command !== '') {
@@ -82219,7 +82514,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82219
82514
 
82220
82515
  return;
82221
82516
  }
82222
-
82517
+
82223
82518
  await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
82224
82519
  // });
82225
82520
  // return me.deferred.promise();
@@ -82287,7 +82582,7 @@ iCn3DUI.prototype.getXMLHttpRqstPromise = function(url, dataType, responseType,
82287
82582
  let oReq = new XMLHttpRequest();
82288
82583
  oReq.open(dataType, url, true);
82289
82584
  oReq.responseType = responseType;
82290
-
82585
+
82291
82586
  oReq.onreadystatechange = function() {
82292
82587
  if (this.readyState == 4) {
82293
82588
  if(this.status == 200) {
@@ -82339,7 +82634,7 @@ iCn3DUI.prototype.getAjaxPromise = function(url, dataType, beforeSend, alertMess
82339
82634
  error : function() {
82340
82635
  if(alertMess) alert(alertMess);
82341
82636
  if(logMess) console.log(logMess);
82342
-
82637
+
82343
82638
  reject('error');
82344
82639
  }
82345
82640
  });
@@ -82382,7 +82677,7 @@ iCn3DUI.prototype.getAjaxPostPromise = async function(url, data, beforeSend, ale
82382
82677
  //if(alertMess) alert(alertMess);
82383
82678
  if(!me.bNode && alertMess) console.log(alertMess);
82384
82679
  if(!me.bNode && logMess) console.log(logMess);
82385
-
82680
+
82386
82681
  // reject('error');
82387
82682
  // keep running the program
82388
82683
  resolve('error');