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.js CHANGED
@@ -6893,7 +6893,10 @@ class UtilsCls {
6893
6893
  let nOtherAtoms = 0;
6894
6894
  for(let i in atomlist) {
6895
6895
  if(index < testLength) {
6896
- let atomName = atomlist[i].name.trim();
6896
+ let atomName = atomlist[i].name;
6897
+ if(!atomName) continue;
6898
+ atomName = atomName.trim();
6899
+
6897
6900
  if(atomName !== "CA" && atomName !== "P" && atomName !== "O3'" && atomName !== "O3*") {
6898
6901
  //bOtherAtoms = true;
6899
6902
  //break;
@@ -9046,7 +9049,7 @@ class ClickMenu {
9046
9049
  });
9047
9050
 
9048
9051
  me.myEventCls.onIds("#" + me.pre + "mn1_cid", "click", function(e) { me.icn3d; //e.preventDefault();
9049
- me.htmlCls.dialogCls.openDlg('dl_cid', 'Please input PubChem CID');
9052
+ me.htmlCls.dialogCls.openDlg('dl_cid', 'Please input PubChem Compound');
9050
9053
  });
9051
9054
 
9052
9055
  me.myEventCls.onIds("#" + me.pre + "mn1_pngimage", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -10670,13 +10673,21 @@ class ClickMenu {
10670
10673
  });
10671
10674
 
10672
10675
  me.myEventCls.onIds("#" + me.pre + "mn6_distManySets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
10673
- me.htmlCls.dialogCls.openDlg('dl_distmanysets', 'Measure the pairwise distance among many sets');
10676
+ me.htmlCls.dialogCls.openDlg('dl_distmanysets', 'Measure the pairwise distances among many sets');
10674
10677
 
10675
10678
  thisClass.setSetsMenus('atomsCustomDistTable');
10676
10679
 
10677
10680
  ic.bMeasureDistance = true;
10678
10681
  });
10679
10682
 
10683
+ me.myEventCls.onIds("#" + me.pre + "mn6_angleManySets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
10684
+ me.htmlCls.dialogCls.openDlg('dl_anglemanysets', 'Measure the pairwise angles among many sets');
10685
+
10686
+ thisClass.setSetsMenus('atomsCustomAngleTable');
10687
+
10688
+ ic.bMeasureAngle = true;
10689
+ });
10690
+
10680
10691
  me.myEventCls.onIds("#" + me.pre + "mn6_distanceNo", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
10681
10692
  ic.pickpair = false;
10682
10693
  let select = "set lines off";
@@ -10761,6 +10772,10 @@ class ClickMenu {
10761
10772
  me.htmlCls.dialogCls.openDlg('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
10762
10773
  });
10763
10774
 
10775
+ $(document).on("click", "#" + me.pre + "mn6_angleTwoSets", function(e) { me.icn3d; //e.preventDefault();
10776
+ me.htmlCls.dialogCls.openDlg('dl_angle', 'Measure the angle between two vectors');
10777
+ });
10778
+
10764
10779
  $(document).on("click", "#" + me.pre + "mn2_matrix", function(e) { me.icn3d; //e.preventDefault();
10765
10780
  me.htmlCls.dialogCls.openDlg('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
10766
10781
  });
@@ -11681,7 +11696,7 @@ class SetMenu {
11681
11696
  html += this.getLink('mn1_mmcifid', 'RCSB mmCIF ID ' + me.htmlCls.wifiStr, undefined, 2);
11682
11697
  //html += this.getLink('mn1_gi', 'NCBI gi ' + me.htmlCls.wifiStr, undefined, 2);
11683
11698
 
11684
- html += this.getLink('mn1_cid', 'PubChem CID ' + me.htmlCls.wifiStr, 1, 2);
11699
+ html += this.getLink('mn1_cid', 'PubChem CID/Name/InchI ' + me.htmlCls.wifiStr, 1, 2);
11685
11700
 
11686
11701
  html += "</ul>";
11687
11702
  html += "</li>";
@@ -12782,11 +12797,18 @@ class SetMenu {
12782
12797
  html += "<ul>";
12783
12798
  html += this.getRadio('mn6_distance', 'mn6_distanceYes', 'between Two Atoms', undefined, 1, 2);
12784
12799
  html += this.getRadio('mn6_distance', 'mn6_distTwoSets', 'between Two Sets', undefined, undefined, 2);
12785
- html += this.getRadio('mn6_distance', 'mn6_distManySets', 'Among Many Sets', undefined, undefined, 2);
12800
+ html += this.getRadio('mn6_distance', 'mn6_distManySets', 'among Many Sets', undefined, undefined, 2);
12786
12801
  html += this.getRadio('mn6_distance', 'mn6_distanceNo', 'Hide', true, 1, 2);
12787
12802
  html += "</ul>";
12788
12803
  html += "</li>";
12789
12804
 
12805
+ html += this.getMenuText('mn6_anglewrap', 'Angle', undefined, 1, 1);
12806
+ html += "<ul>";
12807
+ html += this.getRadio('mn6_angle', 'mn6_angleManySets', 'among Many Sets', undefined, 1, 2);
12808
+ html += this.getRadio('mn6_angle', 'mn6_angleTwoSets', 'b/w Two Vectors', undefined, undefined, 2);
12809
+ html += "</ul>";
12810
+ html += "</li>";
12811
+
12790
12812
  html += this.getLink('mn6_area', 'Surface Area', 1, 1);
12791
12813
 
12792
12814
  html += this.getMenuText('mn6_addlabelwrap', 'Label', undefined, 1, 1);
@@ -14102,8 +14124,8 @@ class SetDialog {
14102
14124
  html += "</div>";
14103
14125
 
14104
14126
  html += me.htmlCls.divStr + "dl_cid' class='" + dialogClass + "'>";
14105
- html += this.addNotebookTitle('dl_cid', 'Please input a PubChem CID');
14106
- html += "PubChem CID: " + me.htmlCls.inputTextStr + "id='" + me.pre + "cid' value='2244' size=8> ";
14127
+ html += this.addNotebookTitle('dl_cid', 'Please input a PubChem Compound');
14128
+ html += "PubChem CID/Name/InchI: " + me.htmlCls.inputTextStr + "id='" + me.pre + "cid' value='2244' size=8> ";
14107
14129
  html += me.htmlCls.buttonStr + "reload_cid'>Load</button>";
14108
14130
  html += "</div>";
14109
14131
 
@@ -14734,6 +14756,28 @@ class SetDialog {
14734
14756
  html += me.htmlCls.spanNowrapStr + "2. " + me.htmlCls.buttonStr + "applydisttable'>Distances in Table</button></span>";
14735
14757
  html += "</div>";
14736
14758
 
14759
+
14760
+ html += me.htmlCls.divStr + "dl_anglemanysets' class='" + dialogClass + "'>";
14761
+ html += this.addNotebookTitle('dl_anglemanysets', 'Measure angles among many sets');
14762
+ html += me.htmlCls.spanNowrapStr + "1. Select sets for pairwise angles</span><br/>";
14763
+ html += "<table border=0 width=400 cellspacing=10><tr><td>";
14764
+
14765
+ html += me.htmlCls.divNowrapStr + "First sets:</div>";
14766
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "atomsCustomAngleTable2' multiple size='5' style='min-width:130px;'>";
14767
+ html += "</select></div>";
14768
+
14769
+ html += "</td><td>";
14770
+
14771
+ html += me.htmlCls.divNowrapStr + "Second sets:</div>";
14772
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "atomsCustomAngleTable' multiple size='5' style='min-width:130px;'>";
14773
+ html += "</select></div>";
14774
+
14775
+ html += "</td></tr></table>";
14776
+
14777
+ html += me.htmlCls.spanNowrapStr + "2. " + me.htmlCls.buttonStr + "applyangletable'>Angles in Table</button></span>";
14778
+ html += "</div>";
14779
+
14780
+
14737
14781
  html += me.htmlCls.divStr + "dl_stabilizer_rm' class='" + dialogClass + "'>";
14738
14782
  html += this.addNotebookTitle('dl_stabilizer_rm', 'Remove a stabilizer');
14739
14783
  if(me.utilsCls.isMobile()) {
@@ -15013,6 +15057,11 @@ class SetDialog {
15013
15057
  html += this.addNotebookTitle('dl_disttable', 'Distance Table', true);
15014
15058
  html += "</div>";
15015
15059
 
15060
+
15061
+ html += me.htmlCls.divStr + "dl_angletable' class='" + dialogClass + "'>";
15062
+ html += this.addNotebookTitle('dl_angletable', 'Angle Table', true);
15063
+ html += "</div>";
15064
+
15016
15065
  html += me.htmlCls.divStr + "dl_translate' class='" + dialogClass + "'>";
15017
15066
  html += this.addNotebookTitle('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
15018
15067
  html += "X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "translateX' value='' size=4> ";
@@ -15021,6 +15070,20 @@ class SetDialog {
15021
15070
  html += me.htmlCls.buttonStr + "translate_pdb'>Translate</button>";
15022
15071
  html += "</div>";
15023
15072
 
15073
+ html += me.htmlCls.divStr + "dl_angle' class='" + dialogClass + "'>";
15074
+ html += this.addNotebookTitle('dl_angle', 'Measure the angle between two vectors');
15075
+ html += "<b>Vector 1</b>, X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1X' value='' size=6> ";
15076
+ html += "Y: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1Y' value='' size=6> ";
15077
+ html += "Z: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1Z' value='' size=6><br>";
15078
+ html += "<b>Vector 2</b>, X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2X' value='' size=6> ";
15079
+ html += "Y: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2Y' value='' size=6> ";
15080
+ html += "Z: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2Z' value='' size=6><br>";
15081
+ html += "<br>";
15082
+
15083
+ html += me.htmlCls.buttonStr + "measure_angle'>Measure Angle</button>";
15084
+ html += "The angle is: " + me.htmlCls.inputTextStr + "id='" + me.pre + "angle_value' value='' size=6> degree.";
15085
+ html += "</div>";
15086
+
15024
15087
  html += me.htmlCls.divStr + "dl_matrix' class='" + dialogClass + "'>";
15025
15088
  html += this.addNotebookTitle('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
15026
15089
  html += "0: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix0' value='1' size=2> ";
@@ -15864,6 +15927,27 @@ class Events {
15864
15927
  thisClass.setLogCmd("translate pdb " + dx + " " + dy + " " + dz, true);
15865
15928
  });
15866
15929
 
15930
+ me.myEventCls.onIds("#" + me.pre + "measure_angle", "click", function(e) { me.icn3d;
15931
+ e.preventDefault();
15932
+ if(!me.cfg.notebook) dialog.dialog( "close" );
15933
+ let v1X = $("#" + me.pre + "v1X").val();
15934
+ let v1Y = $("#" + me.pre + "v1Y").val();
15935
+ let v1Z= $("#" + me.pre + "v1Z").val();
15936
+
15937
+ let v2X = $("#" + me.pre + "v2X").val();
15938
+ let v2Y = $("#" + me.pre + "v2Y").val();
15939
+ let v2Z = $("#" + me.pre + "v2Z").val();
15940
+
15941
+ let angleRad = new THREE.Vector3(parseFloat(v1X), parseFloat(v1Y), parseFloat(v1Z)).angleTo(new THREE.Vector3(parseFloat(v2X), parseFloat(v2Y), parseFloat(v2Z)));
15942
+ let angle = angleRad / 3.1416 * 180;
15943
+ angle = Math.abs(angle).toFixed(0);
15944
+ if(angle > 180) angle -= 180;
15945
+ if(angle > 90) angle = 180 - angle;
15946
+
15947
+ thisClass.setLogCmd("The angle is " + angle + " degree", false);
15948
+ $("#" + me.pre + "angle_value").val(angle);
15949
+ });
15950
+
15867
15951
  me.myEventCls.onIds("#" + me.pre + "matrix_pdb", "click", function(e) { let ic = me.icn3d;
15868
15952
  e.preventDefault();
15869
15953
  if(!me.cfg.notebook) dialog.dialog( "close" );
@@ -17520,6 +17604,20 @@ class Events {
17520
17604
  thisClass.setLogCmd("disttable | " + nameArray2 + " " + nameArray, true);
17521
17605
  });
17522
17606
 
17607
+ me.myEventCls.onIds("#" + me.pre + "applyangletable", "click", function(e) { let ic = me.icn3d;
17608
+ e.preventDefault();
17609
+ if(!me.cfg.notebook) dialog.dialog( "close" );
17610
+ ic.bMeasureAngle = false;
17611
+
17612
+ let nameArray = $("#" + me.pre + "atomsCustomAngleTable").val();
17613
+ let nameArray2 = $("#" + me.pre + "atomsCustomAngleTable2").val();
17614
+
17615
+ ic.analysisCls.measureAngleManySets(nameArray, nameArray2);
17616
+ me.htmlCls.dialogCls.openDlg('dl_angletable', 'Angles among the sets');
17617
+
17618
+ thisClass.setLogCmd("angletable | " + nameArray2 + " " + nameArray, true);
17619
+ });
17620
+
17523
17621
  me.myEventCls.onIds("#" + me.pre + "applylinebtwsets", "click", function(e) { let ic = me.icn3d;
17524
17622
  e.preventDefault();
17525
17623
 
@@ -28109,18 +28207,17 @@ class Strand {
28109
28207
 
28110
28208
  let bRibbon = fill ? true: false;
28111
28209
 
28112
- // when highlight, the input atoms may only include part of sheet or helix
28113
- // include the whole sheet or helix when highlighting
28210
+ // when highlight, the input atoms may only include one rediue.
28211
+ // add one extra residue to show the strand
28114
28212
  let atomsAdjust = {};
28115
28213
 
28116
- // if( Object.keys(atoms).length < Object.keys(ic.atoms).length) {
28117
- // atomsAdjust = this.getSSExpandedAtoms(atoms);
28118
- // }
28119
- // else {
28120
- // atomsAdjust = atoms;
28121
- // }
28122
-
28123
- atomsAdjust = atoms;
28214
+ let residueHashTmp = ic.firstAtomObjCls.getResiduesFromAtoms(atoms);
28215
+ if( Object.keys(residueHashTmp).length == 1) {
28216
+ atomsAdjust = this.getOneExtraResidue(residueHashTmp);
28217
+ }
28218
+ else {
28219
+ atomsAdjust = atoms;
28220
+ }
28124
28221
 
28125
28222
  if(bHighlight === 2) {
28126
28223
  if(fill) {
@@ -28155,22 +28252,24 @@ class Strand {
28155
28252
  let currentChain, currentResi, currentCA = null, currentO = null, currentColor = null, prevCoorCA = null, prevCoorO = null, prevColor = null;
28156
28253
  let prevCO = null, ss = null, ssend = false, atomid = null, prevAtomid = null, prevAtomSelected = null, prevResi = null, calphaid = null, prevCalphaid = null;
28157
28254
  let strandWidth, bSheetSegment = false, bHelixSegment = false;
28158
- let atom, tubeAtoms = {};
28159
28255
 
28160
- // test the first 30 atoms to see whether only C-alpha is available
28161
- ic.bCalphaOnly = me.utilsCls.isCalphaPhosOnly(atomsAdjust); //, 'CA');
28256
+ // For each chain, test the first 30 atoms to see whether only C-alpha is available
28257
+ let bCalphaOnlyHash = {};
28258
+ for(let chainid in ic.chains) {
28259
+ let atoms = me.hashUtilsCls.hash2Atoms(ic.chains[chainid], ic.atoms);
28260
+ let bCalphaOnly = me.utilsCls.isCalphaPhosOnly(atoms); //, 'CA');
28261
+ bCalphaOnlyHash[chainid] = bCalphaOnly;
28262
+ }
28162
28263
 
28163
28264
  // when highlight, draw whole beta sheet and use bShowArray to show the highlight part
28164
28265
  let residueHash = {};
28165
28266
  for(let i in atomsAdjust) {
28166
- let atom = atomsAdjust[i];
28267
+ let atom = ic.atoms[i];
28167
28268
 
28168
28269
  let residueid = atom.structure + '_' + atom.chain + '_' + atom.resi;
28169
28270
  residueHash[residueid] = 1;
28170
28271
  }
28171
- let totalResidueCount = Object.keys(residueHash).length;
28172
-
28173
- let drawnResidueCount = 0;
28272
+ Object.keys(residueHash).length;
28174
28273
 
28175
28274
  let bFullAtom = (Object.keys(ic.hAtoms).length == Object.keys(ic.atoms).length) ? true : false;
28176
28275
 
@@ -28179,22 +28278,20 @@ class Strand {
28179
28278
  let maxDist = 6.0;
28180
28279
 
28181
28280
  //get the last residue
28182
- let atomArray = Object.keys(atoms);
28281
+ let atomArray = Object.keys(atomsAdjust);
28183
28282
  let lastAtomSerial = atomArray[atomArray.length - 1];
28184
- let lastAtom = atoms[lastAtomSerial];
28283
+ let lastAtom = ic.atoms[lastAtomSerial];
28185
28284
  let lastResid = lastAtom.structure + '_' + lastAtom.chain + '_' + lastAtom.resi;
28186
28285
 
28187
28286
  for (let i in atomsAdjust) {
28188
- atom = atomsAdjust[i];
28287
+ let atom = ic.atoms[i];
28189
28288
  let chainid = atom.structure + '_' + atom.chain;
28190
28289
  let resid = atom.structure + '_' + atom.chain + '_' + atom.resi;
28191
28290
  if ((atom.name === 'O' || atom.name === 'CA') && !atom.het) {
28192
28291
  // "CA" has to appear before "O"
28193
28292
 
28194
28293
  if (atom.name === 'CA') {
28195
- if ( atoms.hasOwnProperty(i) && ((atom.ss !== 'helix' && atom.ss !== 'sheet') || atom.ssend || atom.ssbegin) ) {
28196
- tubeAtoms[i] = atom;
28197
- }
28294
+ if ( atoms.hasOwnProperty(i) && ((atom.ss !== 'helix' && atom.ss !== 'sheet') || atom.ssend || atom.ssbegin) ) ;
28198
28295
 
28199
28296
  currentCA = atom.coord;
28200
28297
  currentColor = atom.color;
@@ -28203,7 +28300,7 @@ class Strand {
28203
28300
  caArray.push(atom.serial);
28204
28301
  }
28205
28302
 
28206
- if (atom.name === 'O' || (ic.bCalphaOnly && atom.name === 'CA')) {
28303
+ if (atom.name === 'O' || (bCalphaOnlyHash[chainid] && atom.name === 'CA')) {
28207
28304
  if(currentCA === null || currentCA === undefined) {
28208
28305
  currentCA = atom.coord;
28209
28306
  currentColor = atom.color;
@@ -28266,7 +28363,7 @@ class Strand {
28266
28363
  }
28267
28364
  }
28268
28365
  }
28269
- else if(ic.bCalphaOnly && atom.name === 'CA') {
28366
+ else if(bCalphaOnlyHash[chainid] && atom.name === 'CA') {
28270
28367
  if(caArray.length > resSpan + 1) { // use the calpha and the previous 4th c-alpha to calculate the helix direction
28271
28368
  O = prevCoorCA.clone();
28272
28369
  oldCA = ic.atoms[caArray[caArray.length - 1 - resSpan - 1]].coord.clone();
@@ -28301,8 +28398,6 @@ class Strand {
28301
28398
  bShowArray.push(0);
28302
28399
  calphaIdArray.push(0);
28303
28400
  }
28304
-
28305
- ++drawnResidueCount;
28306
28401
  }
28307
28402
 
28308
28403
  //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);
@@ -28331,7 +28426,9 @@ class Strand {
28331
28426
  // }
28332
28427
 
28333
28428
  //if ((atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs) && pnts[0].length > 0 && bSameChain) {
28334
- if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs || resid == lastResid) && pnts[0].length > 0) {
28429
+ // 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
28430
+
28431
+ if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || bBrokenSs || (resid == lastResid && atom.ss != 'coil')) && pnts[0].length > 0) {
28335
28432
  let atomName = 'CA';
28336
28433
 
28337
28434
  let prevone = [], nexttwo = [];
@@ -28388,7 +28485,7 @@ class Strand {
28388
28485
  O = currentO.clone();
28389
28486
  O.sub(currentCA);
28390
28487
  }
28391
- else if(ic.bCalphaOnly && atom.name === 'CA') {
28488
+ else if(bCalphaOnlyHash[chainid] && atom.name === 'CA') {
28392
28489
  if(caArray.length > resSpan) { // use the calpha and the previous 4th c-alpha to calculate the helix direction
28393
28490
  O = currentCA.clone();
28394
28491
  oldCA = ic.atoms[caArray[caArray.length - 1 - resSpan]].coord.clone();
@@ -28477,7 +28574,9 @@ class Strand {
28477
28574
  // end of a chain, or end of selection
28478
28575
  if ((currentChain !== atom.chain
28479
28576
  || ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + currentChain, currentResi) + 1 !== ic.ParserUtilsCls.getResiNCBI(chainid, atom.resi)
28480
- || resid == lastResid
28577
+ // || (drawnResidueCount === totalResidueCount - 1)
28578
+ // || bBrokenSs
28579
+ || (resid == lastResid && atom.ss != 'coil')
28481
28580
  ) && pnts[0].length > 0) {
28482
28581
  //if ((currentChain !== atom.chain) && pnts[0].length > 0) {
28483
28582
 
@@ -28545,18 +28644,42 @@ class Strand {
28545
28644
  prevCoorCA = currentCA;
28546
28645
  prevCoorO = atom.coord;
28547
28646
  prevColor = currentColor;
28548
- } // end if (atom.name === 'O' || (ic.bCalphaOnly && atom.name === 'CA') ) {
28647
+ } // end if (atom.name === 'O' || (bCalphaOnlyHash[chainid] && atom.name === 'CA') ) {
28549
28648
  } // end if ((atom.name === 'O' || atom.name === 'CA') && !atom.het) {
28550
28649
  } // end for
28551
28650
 
28552
28651
  caArray = [];
28553
28652
 
28554
- ic.tubeCls.createTube(tubeAtoms, 'CA', coilWidth, bHighlight);
28555
-
28556
- tubeAtoms = {};
28653
+ // ic.tubeCls.createTube(tubeAtoms, 'CA', coilWidth, bHighlight);
28654
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
28655
+ ic.tubeCls.createTube(atomsAdjust, 'CA', coilWidth, bHighlight);
28557
28656
  pnts = {};
28558
28657
  }
28559
28658
 
28659
+ getOneExtraResidue(residueHash) { let ic = this.icn3d, me = ic.icn3dui;
28660
+ let atomsAdjust = {};
28661
+
28662
+ for(let resid in residueHash) {
28663
+ atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, ic.residues[resid]);
28664
+
28665
+ let residNcbi = ic.resid2ncbi[resid];
28666
+ let resiNcbi = residNcbi.substr(residNcbi.lastIndexOf('_') + 1);
28667
+
28668
+ let nextResidNcbi = residNcbi.substr(0, residNcbi.lastIndexOf('_')) + '_' + (parseInt(resiNcbi) + 1);
28669
+ let nextResid = ic.ncbi2resid[nextResidNcbi];
28670
+
28671
+ if(!nextResid) {
28672
+ nextResidNcbi = residNcbi.substr(0, residNcbi.lastIndexOf('_')) + '_' + (parseInt(resiNcbi) - 1);
28673
+ nextResid = ic.ncbi2resid[nextResidNcbi];
28674
+ }
28675
+
28676
+ if(nextResid) atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, ic.residues[nextResid]);
28677
+ }
28678
+
28679
+ return atomsAdjust;
28680
+ }
28681
+
28682
+ /*
28560
28683
  getSSExpandedAtoms(atoms, bHighlight) { let ic = this.icn3d, me = ic.icn3dui;
28561
28684
  let currChain, currResi, currAtom, prevChain, prevResi, prevAtom;
28562
28685
  let firstAtom, lastAtom;
@@ -28663,6 +28786,7 @@ class Strand {
28663
28786
 
28664
28787
  return atomsAdjust;
28665
28788
  }
28789
+ */
28666
28790
  }
28667
28791
 
28668
28792
  /**
@@ -28682,7 +28806,8 @@ class Strip {
28682
28806
  if (p0.length < 2) return;
28683
28807
  div = div || ic.axisDIV;
28684
28808
 
28685
- if(pntsCA && ic.bDoublecolor && !ic.bCalphaOnly) {
28809
+ // if(pntsCA && ic.bDoublecolor && !ic.bCalphaOnly) {
28810
+ if(pntsCA && ic.bDoublecolor) {
28686
28811
  let bExtendLastRes = false; //true;
28687
28812
 
28688
28813
  let pnts_clrs = me.subdivideCls.subdivide(pntsCA, colors, div, bShowArray, bHighlight, prevone, nexttwo, bExtendLastRes);
@@ -29010,7 +29135,7 @@ class Tube {
29010
29135
  //Create tubes for "atoms" with certain "atomName". "radius" is the radius of the tubes.
29011
29136
  //"bHighlight" is an option to draw the highlight for these atoms. The highlight could be
29012
29137
  //outlines with bHighlight=1 and 3D objects with bHighlight=2.
29013
- createTube(atoms, atomName, radius, bHighlight, bCustom, bRadiusArray) { let ic = this.icn3d, me = ic.icn3dui;
29138
+ createTube(atoms, atomName, radius, bHighlight, bCustom, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
29014
29139
  if(me.bNode) return;
29015
29140
 
29016
29141
  let pnts = [], colors = [], radii = [], prevone = [], nexttwo = [];
@@ -29122,6 +29247,9 @@ class Tube {
29122
29247
  else {
29123
29248
  radiusFinal = this.getRadius(radius, atom);
29124
29249
  }
29250
+
29251
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
29252
+ if(!bNonCoil && atom.ss != 'coil' && !atom.ssbegin && !atom.ssend ) radiusFinal = 0;
29125
29253
 
29126
29254
  //radii.push(radius || (atom.b > 0 ? atom.b * 0.01 : ic.coilWidth));
29127
29255
  radii.push(radiusFinal);
@@ -29195,183 +29323,247 @@ class Tube {
29195
29323
  let prevone = pnts_colors_radii_prevone_nexttwo[i].prevone;
29196
29324
  let nexttwo = pnts_colors_radii_prevone_nexttwo[i].nexttwo;
29197
29325
 
29198
- this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bRadiusArray);
29326
+ this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil);
29199
29327
  }
29200
29328
 
29201
- pnts_colors_radii_prevone_nexttwo = [];
29329
+ pnts_colors_radii_prevone_nexttwo = [];
29202
29330
  }
29203
29331
 
29204
- getCustomtubesize(resid) { let ic = this.icn3d; ic.icn3dui;
29205
- let pos = resid.lastIndexOf('_');
29206
- let resi = resid.substr(pos + 1);
29207
- let chainid = resid.substr(0, pos);
29332
+ /*
29333
+ createTube(atoms, atomName, radius, bHighlight, bCustom, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
29334
+ if(me.bNode) return;
29208
29335
 
29209
- let radiusFinal = (ic.queryresi2score[chainid] && ic.queryresi2score[chainid].hasOwnProperty(resi)) ? ic.queryresi2score[chainid][resi] * 0.01 : ic.coilWidth;
29336
+ let pnts = [], colors = [], radii = [], prevone = [], nexttwo = [];
29337
+ let currentChain, currentResi;
29338
+ let index = 0;
29339
+ let maxDist = 6.0;
29340
+ let maxDist2 = 3.0; // avoid tube between the residues in 3 residue helix
29210
29341
 
29211
- return radiusFinal;
29212
- };
29342
+ let pnts_colors_radii_prevone_nexttwo = [];
29343
+ let firstAtom, atom, prevAtom;
29213
29344
 
29214
- // modified from iview (http://istar.cse.cuhk.edu.hk/iview/)
29215
- createTubeSub(_pnts, colors, radii, bHighlight, prevone, nexttwo, bRadiusArray) { let ic = this.icn3d, me = ic.icn3dui;
29216
- if(me.bNode) return;
29345
+ for (let i in atoms) {
29346
+ atom = atoms[i];
29347
+ if ((atom.name === atomName) && !atom.het) {
29348
+ if(index == 0) {
29349
+ firstAtom = atom;
29350
+ }
29217
29351
 
29218
- if (_pnts.length < 2) return;
29352
+ 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
29353
+ || (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))
29354
+ ) ) {
29355
+ if(bHighlight !== 2) {
29356
+ if(!isNaN(firstAtom.resi) && !isNaN(prevAtom.resi)) {
29357
+ let prevoneResid = firstAtom.structure + '_' + firstAtom.chain + '_' + (parseInt(firstAtom.resi) - 1).toString();
29358
+ let prevoneCoord = ic.firstAtomObjCls.getAtomCoordFromResi(prevoneResid, atomName);
29359
+ prevone = (prevoneCoord !== undefined) ? [prevoneCoord] : [];
29219
29360
 
29220
- // if(bRadiusArray) {
29221
- let circleDiv = ic.tubeDIV, axisDiv = ic.axisDIV;
29222
- let circleDivInv = 1 / circleDiv, axisDivInv = 1 / axisDiv;
29223
- //var geo = new THREE.Geometry();
29224
- let geo = new THREE.BufferGeometry();
29225
- let verticeArray = [], colorArray = [],indexArray = [], color;
29226
- let offset = 0, offset2 = 0, offset3 = 0;
29361
+ let nextoneResid = prevAtom.structure + '_' + prevAtom.chain + '_' + (parseInt(prevAtom.resi) + 1).toString();
29227
29362
 
29228
- let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
29363
+ // add one more residue if only one residue is available
29364
+ if(pnts.length == 1 && ic.residues.hasOwnProperty(nextoneResid)) {
29365
+ let nextAtom = ic.firstAtomObjCls.getAtomFromResi(nextoneResid, atomName);
29229
29366
 
29230
- let pnts = pnts_clrs[0];
29231
- colors = pnts_clrs[2];
29367
+ if(nextAtom) {
29368
+ pnts.push(nextAtom.coord);
29369
+ colors.push(nextAtom.color);
29232
29370
 
29233
- let prevAxis1 = new THREE.Vector3(), prevAxis2;
29234
- for (let i = 0, lim = pnts.length; i < lim; ++i) {
29235
- let r, idx = (i - 1) * axisDivInv;
29236
- if (i === 0) r = radii[0];
29237
- else {
29238
- if (idx % 1 === 0) r = radii[idx];
29239
- else {
29240
- let floored = Math.floor(idx);
29241
- let tmp = idx - floored;
29242
- r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp);
29371
+ let radiusFinal = this.getRadius(radius, atom);
29372
+ radii.push(radiusFinal);
29373
+ }
29374
+ }
29375
+
29376
+ }
29377
+
29378
+ pnts_colors_radii_prevone_nexttwo.push({'pnts':pnts, 'colors':colors, 'radii':radii, 'prevone':prevone, 'nexttwo':nexttwo});
29243
29379
  }
29380
+ pnts = []; colors = []; radii = []; prevone = []; nexttwo = [];
29381
+ firstAtom = atom;
29382
+ index = 0;
29244
29383
  }
29245
- let delta, axis1, axis2;
29246
- if (i < lim - 1) {
29247
- delta = pnts[i].clone().sub(pnts[i + 1]);
29248
- axis1 = new THREE.Vector3(0, -delta.z, delta.y).normalize().multiplyScalar(r);
29249
- axis2 = delta.clone().cross(axis1).normalize().multiplyScalar(r);
29250
- // let dir = 1, offset = 0;
29251
- if (prevAxis1.dot(axis1) < 0) {
29252
- axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv;
29253
- }
29254
- prevAxis1 = axis1; prevAxis2 = axis2;
29255
- } else {
29256
- axis1 = prevAxis1; axis2 = prevAxis2;
29384
+
29385
+ pnts.push(atom.coord);
29386
+
29387
+ let radiusFinal;
29388
+ if(bCustom) {
29389
+ radiusFinal = this.getCustomtubesize(atom.structure + '_' + atom.chain + '_' + atom.resi);
29390
+ }
29391
+ else {
29392
+ radiusFinal = this.getRadius(radius, atom);
29257
29393
  }
29258
- for (let j = 0; j < circleDiv; ++j) {
29259
- let angle = 2 * Math.PI * circleDivInv * j; //* dir + offset;
29260
- let point = pnts[i].clone().add(axis1.clone().multiplyScalar(Math.cos(angle))).add(axis2.clone().multiplyScalar(Math.sin(angle)));
29261
- verticeArray[offset++] = point.x;
29262
- verticeArray[offset++] = point.y;
29263
- verticeArray[offset++] = point.z;
29264
29394
 
29265
- color = (i == colors.length - 1 && colors.length > 1) ? me.parasCls.thr(colors[colors.length - 2]) : me.parasCls.thr(colors[i]);
29266
- colorArray[offset2++] = color.r;
29267
- colorArray[offset2++] = color.g;
29268
- colorArray[offset2++] = color.b;
29395
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
29396
+ if(!bNonCoil && atom.ss != 'coil' && !atom.ssbegin && !atom.ssend ) radiusFinal = 0;
29397
+
29398
+ //radii.push(radius || (atom.b > 0 ? atom.b * 0.01 : ic.coilWidth));
29399
+ radii.push(radiusFinal);
29400
+
29401
+ colors.push(atom.color);
29402
+ // the starting residue of a coil uses the color from the next residue to avoid using the color of the last helix/sheet residue
29403
+ if(index === 1) colors[colors.length - 2] = atom.color;
29404
+
29405
+ currentChain = atom.chain;
29406
+ currentResi = atom.resi;
29407
+
29408
+ let scale = 1.2;
29409
+ if(bHighlight === 2 && !atom.ssbegin) {
29410
+ ic.boxCls.createBox(atom, undefined, undefined, scale, undefined, bHighlight);
29269
29411
  }
29412
+
29413
+ ++index;
29414
+
29415
+ prevAtom = atom;
29270
29416
  }
29271
- let offsetTmp = 0, nComp = 3;
29272
- for (let i = 0, lim = pnts.length - 1; i < lim; ++i) {
29273
- let reg = 0;
29274
- //var r1 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv]).lengthSq();
29275
- //var r2 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv + 1]).lengthSq();
29276
- let pos = offsetTmp * nComp;
29277
- let point1 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
29278
- pos = (offsetTmp + circleDiv) * nComp;
29279
- let point2 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
29280
- pos = (offsetTmp + circleDiv + 1) * nComp;
29281
- let point3 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
29282
-
29283
- let r1 = point1.clone().sub(point2).lengthSq();
29284
- let r2 = point1.clone().sub(point3).lengthSq();
29285
- if (r1 > r2) { r1 = r2; reg = 1; } for (let j = 0; j < circleDiv; ++j) {
29286
- //geo.faces.push(new THREE.Face3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv, undefined, c));
29287
- //geo.faces.push(new THREE.Face3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv, undefined, c));
29288
- //indexArray = indexArray.concat([offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv]);
29289
- indexArray[offset3++] = offsetTmp + j;
29290
- indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
29291
- indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
29292
-
29293
- //indexArray = indexArray.concat([offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv]);
29294
- indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
29295
- indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
29296
- indexArray[offset3++] = offsetTmp + (j + reg + 1) % circleDiv + circleDiv;
29297
- }
29298
- offsetTmp += circleDiv;
29299
- }
29417
+ }
29300
29418
 
29301
- geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticeArray), nComp));
29302
- geo.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colorArray), nComp));
29419
+ if(bHighlight !== 2) {
29420
+ pnts_colors_radii_prevone_nexttwo.push({'pnts':pnts, 'colors':colors, 'radii':radii, 'prevone':prevone, 'nexttwo':nexttwo});
29421
+ }
29303
29422
 
29304
- geo.setIndex(new THREE.BufferAttribute(new Uint32Array(indexArray), 1));
29305
- //geo.setIndex(indexArray);
29423
+ for(let i = 0, il = pnts_colors_radii_prevone_nexttwo.length; i < il; ++i) {
29424
+ let pnts = pnts_colors_radii_prevone_nexttwo[i].pnts;
29425
+ let colors = pnts_colors_radii_prevone_nexttwo[i].colors;
29426
+ let radii = pnts_colors_radii_prevone_nexttwo[i].radii;
29427
+ let prevone = []; // = pnts_colors_radii_prevone_nexttwo[i].prevone;
29428
+ let nexttwo = []; // = pnts_colors_radii_prevone_nexttwo[i].nexttwo;
29306
29429
 
29307
- //geo.computeFaceNormals();
29308
- //geo.computeVertexNormals(false);
29309
- geo.computeVertexNormals();
29310
- /*
29430
+ this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil);
29311
29431
  }
29312
- else {
29313
- let axisDiv = ic.axisDIV;
29314
29432
 
29315
- let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
29316
- // extend one residue
29317
- //var pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo, true);
29433
+ pnts_colors_radii_prevone_nexttwo = [];
29434
+ }
29435
+ */
29318
29436
 
29319
- _pnts = pnts_clrs[0];
29320
- colors = pnts_clrs[2];
29437
+ getCustomtubesize(resid) { let ic = this.icn3d; ic.icn3dui;
29438
+ let pos = resid.lastIndexOf('_');
29439
+ let resi = resid.substr(pos + 1);
29440
+ let chainid = resid.substr(0, pos);
29321
29441
 
29322
- let radius = ic.coilWidth;
29323
- segments = _pnts.length;
29324
- //radiusSegments = 8;
29325
- radiusSegments = 4; // save memory
29326
- let closed = false;
29442
+ let radiusFinal = (ic.queryresi2score[chainid] && ic.queryresi2score[chainid].hasOwnProperty(resi)) ? ic.queryresi2score[chainid][resi] * 0.01 : ic.coilWidth;
29327
29443
 
29328
- // when using radiusArray with modified three.js, the tube didn't work in picking
29329
- let geo = new THREE.TubeGeometry(
29330
- new THREE.CatmullRomCurve3(_pnts), // path
29331
- segments,
29332
- radius, //radiusArray, //radius,
29333
- radiusSegments,
29334
- closed
29335
- );
29444
+ return radiusFinal;
29445
+ };
29336
29446
 
29337
- //https://stemkoski.github.io/Three.js/Graphulus-Curve.html
29338
- let color, face, numberOfSides, vertexIndex;
29339
- // faces are indexed using characters
29340
- let faceIndices = [ 'a', 'b', 'c', 'd' ];
29447
+ // modified from iview (http://istar.cse.cuhk.edu.hk/iview/)
29448
+ createTubeSub(_pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
29449
+ if(me.bNode) return;
29341
29450
 
29342
- // first, assign colors to vertices as desired
29343
- let prevColor, geoColors = {};
29344
- for ( let s = 0; s <= segments; s++ ) {
29345
- for ( let r = 0; r < radiusSegments; r++ )
29346
- {
29347
- vertexIndex = r + s * radiusSegments;
29348
- color = colors[s];
29349
- if(!color) color = prevColor;
29451
+ if (_pnts.length < 2) return;
29350
29452
 
29351
- geoColors[vertexIndex] = color; // use this array for convenience
29453
+ let circleDiv = ic.tubeDIV, axisDiv = ic.axisDIV;
29454
+ let circleDivInv = 1 / circleDiv, axisDivInv = 1 / axisDiv;
29455
+ //var geo = new THREE.Geometry();
29456
+ let geo = new THREE.BufferGeometry();
29457
+ let verticeArray = [], colorArray = [],indexArray = [], color;
29458
+ let offset = 0, offset2 = 0, offset3 = 0;
29352
29459
 
29353
- prevColor = color;
29354
- }
29355
- }
29460
+ let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
29356
29461
 
29357
- // copy the colors as necessary to the face's vertexColors array.
29358
- // after version r125, geo.faces is undefined for TubeGeometry
29359
- for ( let i = 0; geo.faces && i < geo.faces.length; i++ )
29360
- {
29361
- face = geo.faces[ i ];
29462
+ let pnts = pnts_clrs[0];
29463
+ colors = pnts_clrs[2];
29464
+
29465
+ let constRadiius;
29466
+ // a threshold to stop drawing the tube if it's less than this ratio of radius
29467
+ let thresholdRatio = 1; //0.9;
29468
+
29469
+ let prevAxis1 = new THREE.Vector3(), prevAxis2;
29470
+ for (let i = 0, lim = pnts.length; i < lim; ++i) {
29471
+ let r, idx = (i - 1) * axisDivInv;
29362
29472
 
29363
- numberOfSides = ( face instanceof THREE.Face3 ) ? 3 : 4;
29364
- for( let j = 0; j < numberOfSides; j++ )
29365
- {
29366
- vertexIndex = face[ faceIndices[ j ] ];
29367
- face.vertexColors[ j ] = geoColors[ vertexIndex ];
29473
+ if (i === 0) {
29474
+ r = radii[0];
29475
+ if(r > 0) constRadiius = r;
29476
+ }
29477
+ else {
29478
+ if (idx % 1 === 0) {
29479
+ r = radii[idx];
29480
+ if(r > 0) constRadiius = r;
29481
+ }
29482
+ else {
29483
+ let floored = Math.floor(idx);
29484
+ let tmp = idx - floored;
29485
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
29486
+ // r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp);
29487
+ r = radii[floored] * (1 - tmp) + radii[floored + 1] * tmp;
29488
+
29489
+ // a threshold to stop drawing the tube if it's less than this ratio of radius.
29490
+ // The extra bit of tube connects coil with strands or helices
29491
+ if(!bNonCoil) {
29492
+ if(r < thresholdRatio * constRadiius) {
29493
+ r = 0;
29494
+ }
29495
+ // else if(r < constRadiius) {
29496
+ // r *= 0.5; // use small radius for the connection between coild and sheets/helices
29497
+ // }
29498
+ }
29368
29499
  }
29369
29500
  }
29370
-
29371
- geo.computeFaceNormals();
29372
- geo.computeVertexNormals(false);
29501
+ let delta, axis1, axis2;
29502
+ if (i < lim - 1) {
29503
+ delta = pnts[i].clone().sub(pnts[i + 1]);
29504
+ axis1 = new THREE.Vector3(0, -delta.z, delta.y).normalize().multiplyScalar(r);
29505
+ axis2 = delta.clone().cross(axis1).normalize().multiplyScalar(r);
29506
+ // let dir = 1, offset = 0;
29507
+ if (prevAxis1.dot(axis1) < 0) {
29508
+ axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv;
29509
+ }
29510
+ prevAxis1 = axis1; prevAxis2 = axis2;
29511
+ } else {
29512
+ axis1 = prevAxis1; axis2 = prevAxis2;
29513
+ }
29514
+ for (let j = 0; j < circleDiv; ++j) {
29515
+ let angle = 2 * Math.PI * circleDivInv * j; //* dir + offset;
29516
+ let point = pnts[i].clone().add(axis1.clone().multiplyScalar(Math.cos(angle))).add(axis2.clone().multiplyScalar(Math.sin(angle)));
29517
+ verticeArray[offset++] = point.x;
29518
+ verticeArray[offset++] = point.y;
29519
+ verticeArray[offset++] = point.z;
29520
+
29521
+ color = (i == colors.length - 1 && colors.length > 1) ? me.parasCls.thr(colors[colors.length - 2]) : me.parasCls.thr(colors[i]);
29522
+ colorArray[offset2++] = color.r;
29523
+ colorArray[offset2++] = color.g;
29524
+ colorArray[offset2++] = color.b;
29525
+ }
29526
+ }
29527
+ let offsetTmp = 0, nComp = 3;
29528
+ for (let i = 0, lim = pnts.length - 1; i < lim; ++i) {
29529
+ let reg = 0;
29530
+ //var r1 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv]).lengthSq();
29531
+ //var r2 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv + 1]).lengthSq();
29532
+ let pos = offsetTmp * nComp;
29533
+ let point1 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
29534
+ pos = (offsetTmp + circleDiv) * nComp;
29535
+ let point2 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
29536
+ pos = (offsetTmp + circleDiv + 1) * nComp;
29537
+ let point3 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
29538
+
29539
+ let r1 = point1.clone().sub(point2).lengthSq();
29540
+ let r2 = point1.clone().sub(point3).lengthSq();
29541
+ if (r1 > r2) { r1 = r2; reg = 1; } for (let j = 0; j < circleDiv; ++j) {
29542
+ //geo.faces.push(new THREE.Face3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv, undefined, c));
29543
+ //geo.faces.push(new THREE.Face3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv, undefined, c));
29544
+ //indexArray = indexArray.concat([offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv]);
29545
+ indexArray[offset3++] = offsetTmp + j;
29546
+ indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
29547
+ indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
29548
+
29549
+ //indexArray = indexArray.concat([offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv]);
29550
+ indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
29551
+ indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
29552
+ indexArray[offset3++] = offsetTmp + (j + reg + 1) % circleDiv + circleDiv;
29553
+ }
29554
+ offsetTmp += circleDiv;
29373
29555
  }
29374
- */
29556
+
29557
+ geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticeArray), nComp));
29558
+ geo.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colorArray), nComp));
29559
+
29560
+ geo.setIndex(new THREE.BufferAttribute(new Uint32Array(indexArray), 1));
29561
+ //geo.setIndex(indexArray);
29562
+
29563
+ //geo.computeFaceNormals();
29564
+ //geo.computeVertexNormals(false);
29565
+ geo.computeVertexNormals();
29566
+
29375
29567
  let mesh;
29376
29568
  if(bHighlight === 2) {
29377
29569
  //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 }));
@@ -29954,7 +30146,7 @@ class Axes {
29954
30146
  return cone;
29955
30147
  }
29956
30148
 
29957
- setPc1Axes() { let ic = this.icn3d, me = ic.icn3dui;
30149
+ setPc1Axes(bXAxis) { let ic = this.icn3d, me = ic.icn3dui;
29958
30150
  if(me.bNode) return;
29959
30151
 
29960
30152
  let atomHash = me.hashUtilsCls.intHash(ic.hAtoms, ic.dAtoms);
@@ -30035,6 +30227,11 @@ class Axes {
30035
30227
 
30036
30228
  let positionX = center.clone().add(vecX.normalize().multiplyScalar(maxD * 0.4));
30037
30229
 
30230
+ let prinXaxis = vecX.normalize();
30231
+ me.htmlCls.clickMenuCls.setLogCmd('Principle X-Axis: ' + prinXaxis.x.toFixed(3) + " " + prinXaxis.y.toFixed(3) + " " + prinXaxis.z.toFixed(3), false);
30232
+
30233
+ if(bXAxis) return prinXaxis;
30234
+
30038
30235
  let vecY = new THREE.Vector3(eigenRet.h2[0], eigenRet.h2[1], eigenRet.h2[2]);
30039
30236
  let positionY = center.clone().add(vecY.normalize().multiplyScalar(maxD * 0.3));
30040
30237
 
@@ -34253,6 +34450,9 @@ class ApplySymd {
34253
34450
 
34254
34451
  ic.cylinderCls.createCylinder(start, end, axisRadius, colorAxis, 0);
34255
34452
 
34453
+ let SymAxis = end.clone().sub(start).normalize();
34454
+ me.htmlCls.clickMenuCls.setLogCmd('Symmetry Axis: ' + SymAxis.x.toFixed(3) + " " + SymAxis.y.toFixed(3) + " " + SymAxis.z.toFixed(3), false);
34455
+
34256
34456
  if(ic.bAxisOnly) continue;
34257
34457
 
34258
34458
  if(symmetryType == 'C' || (symmetryType == 'D' && order == nSide) ) {
@@ -34409,87 +34609,87 @@ class ApplySymd {
34409
34609
  pointArray.push(end);
34410
34610
  }
34411
34611
  else ;
34412
- }
34413
34612
 
34414
- if(symmetryType == 'T') {
34415
- let pos1 = pointArray[0]; // pointArray: start, end, start, end, ...
34416
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
34613
+ if(symmetryType == 'T') {
34614
+ let pos1 = pointArray[0]; // pointArray: start, end, start, end, ...
34615
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
34417
34616
 
34418
- let dist2 = pos1.distanceTo(pointArray[2]);
34419
- let dist3 = pos1.distanceTo(pointArray[3]);
34617
+ let dist2 = pos1.distanceTo(pointArray[2]);
34618
+ let dist3 = pos1.distanceTo(pointArray[3]);
34420
34619
 
34421
- let distSmall, posSel;
34422
- if(dist2 < dist3) {
34423
- distSmall = dist2;
34424
- posSel = pointArray[3];
34425
- }
34426
- else {
34427
- distSmall = dist3;
34428
- posSel = pointArray[2];
34429
- }
34620
+ let distSmall, posSel;
34621
+ if(dist2 < dist3) {
34622
+ distSmall = dist2;
34623
+ posSel = pointArray[3];
34624
+ }
34625
+ else {
34626
+ distSmall = dist3;
34627
+ posSel = pointArray[2];
34628
+ }
34430
34629
 
34431
- ic.sphereCls.createSphereBase(posSel, colorPolygon, polygonRadius, 1.0, 0);
34432
- ic.cylinderCls.createCylinder(pos1, posSel, polygonRadius, colorPolygon, 0);
34630
+ ic.sphereCls.createSphereBase(posSel, colorPolygon, polygonRadius, 1.0, 0);
34631
+ ic.cylinderCls.createCylinder(pos1, posSel, polygonRadius, colorPolygon, 0);
34433
34632
 
34434
- let iPrev;
34435
- for(let i = 4, il = pointArray.length; i < il; ++i) {
34436
- let pos2 = pointArray[i];
34633
+ let iPrev;
34634
+ for(let i = 4, il = pointArray.length; i < il; ++i) {
34635
+ let pos2 = pointArray[i];
34437
34636
 
34438
- let dist = pos1.distanceTo(pos2);
34439
- if(dist > distSmall) {
34440
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
34441
- ic.cylinderCls.createCylinder(pos1, pos2, polygonRadius, colorPolygon, 0);
34637
+ let dist = pos1.distanceTo(pos2);
34638
+ if(dist > distSmall) {
34639
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
34640
+ ic.cylinderCls.createCylinder(pos1, pos2, polygonRadius, colorPolygon, 0);
34442
34641
 
34443
- ic.cylinderCls.createCylinder(posSel, pos2, polygonRadius, colorPolygon, 0);
34444
- if(iPrev !== undefined) {
34445
- ic.cylinderCls.createCylinder(pointArray[iPrev], pos2, polygonRadius, colorPolygon, 0);
34446
- }
34642
+ ic.cylinderCls.createCylinder(posSel, pos2, polygonRadius, colorPolygon, 0);
34643
+ if(iPrev !== undefined) {
34644
+ ic.cylinderCls.createCylinder(pointArray[iPrev], pos2, polygonRadius, colorPolygon, 0);
34645
+ }
34447
34646
 
34448
- iPrev = i;
34647
+ iPrev = i;
34648
+ }
34449
34649
  }
34450
34650
  }
34451
- }
34452
- else if(symmetryType == 'O') {
34453
- for(let i = 0, il = pointArray.length; i < il; i += 2) {
34454
- let pos1 = pointArray[i];
34455
- let pos2 = pointArray[i+1];
34456
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
34457
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
34458
- for(let j = i + 2, jl = pointArray.length; j < jl; ++j) {
34459
- let pos3 = pointArray[j];
34460
- ic.sphereCls.createSphereBase(pos3, colorPolygon, polygonRadius, 1.0, 0);
34461
- ic.cylinderCls.createCylinder(pos1, pos3, polygonRadius, colorPolygon, 0);
34462
- ic.cylinderCls.createCylinder(pos2, pos3, polygonRadius, colorPolygon, 0);
34651
+ else if(symmetryType == 'O') {
34652
+ for(let i = 0, il = pointArray.length; i < il; i += 2) {
34653
+ let pos1 = pointArray[i];
34654
+ let pos2 = pointArray[i+1];
34655
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
34656
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
34657
+ for(let j = i + 2, jl = pointArray.length; j < jl; ++j) {
34658
+ let pos3 = pointArray[j];
34659
+ ic.sphereCls.createSphereBase(pos3, colorPolygon, polygonRadius, 1.0, 0);
34660
+ ic.cylinderCls.createCylinder(pos1, pos3, polygonRadius, colorPolygon, 0);
34661
+ ic.cylinderCls.createCylinder(pos2, pos3, polygonRadius, colorPolygon, 0);
34662
+ }
34463
34663
  }
34464
34664
  }
34465
- }
34466
- else if(symmetryType == 'I') {
34467
- for(let i = 0, il = pointArray.length; i < il; i += 2) {
34468
- let pos1 = pointArray[i];
34469
- let pos2 = pointArray[i+1];
34470
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
34471
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
34472
- for(let j = i + 2, jl = pointArray.length; j < jl; j += 2) {
34473
- let pos3 = pointArray[j];
34474
- let pos4 = pointArray[j+1];
34665
+ else if(symmetryType == 'I') {
34666
+ for(let i = 0, il = pointArray.length; i < il; i += 2) {
34667
+ let pos1 = pointArray[i];
34668
+ let pos2 = pointArray[i+1];
34669
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
34670
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
34671
+ for(let j = i + 2, jl = pointArray.length; j < jl; j += 2) {
34672
+ let pos3 = pointArray[j];
34673
+ let pos4 = pointArray[j+1];
34475
34674
 
34476
- let dist3 = pos1.distanceTo(pos3);
34477
- let dist4 = pos1.distanceTo(pos4);
34675
+ let dist3 = pos1.distanceTo(pos3);
34676
+ let dist4 = pos1.distanceTo(pos4);
34478
34677
 
34479
- let pos1Sel, pos2Sel;
34480
- if(dist3 < dist4) {
34481
- pos1Sel = pos3;
34482
- pos2Sel = pos4;
34483
- }
34484
- else {
34485
- pos1Sel = pos4;
34486
- pos2Sel = pos3;
34487
- }
34678
+ let pos1Sel, pos2Sel;
34679
+ if(dist3 < dist4) {
34680
+ pos1Sel = pos3;
34681
+ pos2Sel = pos4;
34682
+ }
34683
+ else {
34684
+ pos1Sel = pos4;
34685
+ pos2Sel = pos3;
34686
+ }
34488
34687
 
34489
- ic.sphereCls.createSphereBase(pos1Sel, colorPolygon, polygonRadius, 1.0, 0);
34490
- ic.sphereCls.createSphereBase(pos2Sel, colorPolygon, polygonRadius, 1.0, 0);
34491
- ic.cylinderCls.createCylinder(pos1, pos1Sel, polygonRadius, colorPolygon, 0);
34492
- ic.cylinderCls.createCylinder(pos2, pos2Sel, polygonRadius, colorPolygon, 0);
34688
+ ic.sphereCls.createSphereBase(pos1Sel, colorPolygon, polygonRadius, 1.0, 0);
34689
+ ic.sphereCls.createSphereBase(pos2Sel, colorPolygon, polygonRadius, 1.0, 0);
34690
+ ic.cylinderCls.createCylinder(pos1, pos1Sel, polygonRadius, colorPolygon, 0);
34691
+ ic.cylinderCls.createCylinder(pos2, pos2Sel, polygonRadius, colorPolygon, 0);
34692
+ }
34493
34693
  }
34494
34694
  }
34495
34695
  }
@@ -44667,7 +44867,6 @@ class AddTrack {
44667
44867
  }
44668
44868
 
44669
44869
  getExonHtml(exonIndex, colorGradient, from, to, genomeRange, chainid, simpTitle) { let ic = this.icn3d; ic.icn3dui;
44670
- // 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>';
44671
44870
  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>';
44672
44871
  }
44673
44872
 
@@ -45409,7 +45608,7 @@ class AddTrack {
45409
45608
  let targetId = 'genomeRes';
45410
45609
 
45411
45610
  let acc2index = {};
45412
-
45611
+
45413
45612
  for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
45414
45613
  let acc = accArray[index];
45415
45614
 
@@ -45494,22 +45693,24 @@ class AddTrack {
45494
45693
  trackSeqArrayFinal[i] = '';
45495
45694
  }
45496
45695
 
45497
- for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
45498
- let seq = trackSeqArray[maxIndex][j];
45696
+ if(trackSeqArray[maxIndex]) {
45697
+ for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
45698
+ let seq = trackSeqArray[maxIndex][j];
45499
45699
 
45500
- let bExon = (seq != '-') ? true : false;
45501
- if(!bExon) {
45502
- for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
45503
- if(trackSeqArray[i][j] != '-') {
45504
- bExon = true;
45505
- break;
45700
+ let bExon = (seq != '-') ? true : false;
45701
+ if(!bExon) {
45702
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
45703
+ if(trackSeqArray[i][j] != '-') {
45704
+ bExon = true;
45705
+ break;
45706
+ }
45506
45707
  }
45507
45708
  }
45508
- }
45509
-
45510
- if(bExon) {
45511
- for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
45512
- trackSeqArrayFinal[i] += trackSeqArray[i][j];
45709
+
45710
+ if(bExon) {
45711
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
45712
+ trackSeqArrayFinal[i] += trackSeqArray[i][j];
45713
+ }
45513
45714
  }
45514
45715
  }
45515
45716
  }
@@ -45580,7 +45781,9 @@ class AddTrack {
45580
45781
  ic.maxAnnoLength = ic.maxAnnoLengthOri + ic.seqStartLen[chainid] + ic.seqEndLen[chainid];
45581
45782
  }
45582
45783
 
45583
- await ic.annotationCls.resetAnnoAll();
45784
+ // do not remove other tracks
45785
+ // await ic.annotationCls.resetAnnoAll();
45786
+ await ic.showAnnoCls.processSeqData(ic.chainid_seq);
45584
45787
 
45585
45788
  let targetGapHashStr = '';
45586
45789
  let cntTmp = 0;
@@ -45747,7 +45950,7 @@ class AddTrack {
45747
45950
 
45748
45951
  let type = 'identity';
45749
45952
 
45750
- await thisClass.addExonTracks(chainid, geneid, startpos, type);
45953
+ await this.addExonTracks(chainid, geneid, startpos, type);
45751
45954
  }
45752
45955
 
45753
45956
  async addExonTracks(chainid, geneid, startpos, type) { let ic = this.icn3d, me = ic.icn3dui;
@@ -45782,13 +45985,12 @@ class AddTrack {
45782
45985
  let cnt = (j == jl - 1) ? itemArray[2] - 3 : itemArray[2]; // The last one is stop codeon
45783
45986
  cntTotal += cnt;
45784
45987
 
45785
- let resStart = parseInt(prevCntTotal/3.0 + 0.5); // 0-based
45786
- let resEnd = parseInt(cntTotal/3.0 + 0.5) - 1; // 0-based
45988
+ let resStart = parseInt((prevCntTotal+2)/3.0); // 0-based
45989
+ let resEnd = parseInt((cntTotal+2)/3.0) - 1; // 0-based
45787
45990
 
45788
- let genResStart = parseInt(itemArray[0] / 3.0 + 0.5);
45789
-
45790
- //let genResEnd = parseInt(itemArray[1] / 3.0 + 0.5); // some difference due to round
45791
- let genResEnd = genResStart + ic.exonOrder * (resEnd - resStart);
45991
+ let genResEnd = parseInt((itemArray[1]+2) / 3.0);
45992
+ // let genResStart = parseInt((itemArray[0]+2) / 3.0); // some difference due to round
45993
+ let genResStart = genResEnd - ic.exonOrder * (resEnd - resStart);
45792
45994
 
45793
45995
  rangeArray.push({genomeRange: genomeRange, genResStart: genResStart, genResEnd: genResEnd, resStart: resStart, resEnd: resEnd});
45794
45996
 
@@ -45842,7 +46044,7 @@ class AddTrack {
45842
46044
 
45843
46045
  let ALen = trackSeqArray.length;
45844
46046
 
45845
- while (i < A.length && j < B.length) {
46047
+ while (A && B && i < A.length && j < B.length) {
45846
46048
  if(A[i] != B[j]) {
45847
46049
  if(A[i] == '-') {
45848
46050
  // insert "-" in B
@@ -57651,13 +57853,7 @@ class RealignParser {
57651
57853
 
57652
57854
  let allPromise = Promise.allSettled(ajaxArray);
57653
57855
  // try {
57654
- // let dataArray = await allPromise;
57655
-
57656
- let startDate = new Date();
57657
57856
  let dataArray = await allPromise;
57658
- let endDate = new Date();
57659
- let miliseconds = (endDate.getTime() - startDate.getTime());
57660
- console.log("vastdyn time: " + miliseconds + " miliseconds");
57661
57857
 
57662
57858
  ic.qt_start_end = []; // reset the alignment
57663
57859
  await ic.chainalignParserCls.downloadChainalignmentPart2bRealign(dataArray, chainidPairArray, bReverse);
@@ -57749,6 +57945,8 @@ class RealignParser {
57749
57945
  async realignChainOnSeqAlign(chainresiCalphaHash2, chainidArray, bRealign, bPredefined) { let ic = this.icn3d, me = ic.icn3dui;
57750
57946
  let thisClass = this;
57751
57947
 
57948
+ me.cfg.aligntool = 'seqalign';
57949
+
57752
57950
  //bRealign: realign based on seq alignment
57753
57951
  //bPredefined: chain alignment with predefined matching residues
57754
57952
 
@@ -59946,9 +60144,11 @@ class LoadAtomData {
59946
60144
  serial2structure[j] = pdbidTmp.toString();
59947
60145
  mmdbid2pdbid[mmdbidTmp] = pdbidTmp;
59948
60146
  }
59949
-
60147
+
59950
60148
  for(let j = 0, jl = structure.molecules.length; j < jl; ++j) {
59951
60149
  let chain = structure.molecules[j].chain;
60150
+ chain = chain.replace(/_/g, ''); // change "A_1" to "A1"
60151
+
59952
60152
  let kind = structure.molecules[j].kind;
59953
60153
  let title = structure.molecules[j].name;
59954
60154
  //var seq = structure.molecules[j].sequence;
@@ -60941,7 +61141,9 @@ class SetSeqAlign {
60941
61141
 
60942
61142
  let resid = chainid + '_' + resi;
60943
61143
  let resn = ic.residueId2Name[resid];
60944
- if(!resn) resn = '?';
61144
+ if(!resn) {
61145
+ resn = '?';
61146
+ }
60945
61147
 
60946
61148
  return resn;
60947
61149
  }
@@ -65653,7 +65855,21 @@ class ApplyCommand {
65653
65855
  let nameArray2 = setNameArray[1].split(',');
65654
65856
 
65655
65857
  ic.analysisCls.measureDistManySets(nameArray, nameArray2);
65656
- me.htmlCls.dialogCls.openDlg('dl_disttable', 'Distance among the sets');
65858
+ me.htmlCls.dialogCls.openDlg('dl_disttable', 'Distances among the sets');
65859
+ }
65860
+ }
65861
+ }
65862
+ else if(commandOri.indexOf('angletable') == 0) {
65863
+ let paraArray = commandOri.split(' | ');
65864
+ if(paraArray.length == 2) {
65865
+ let setNameArray = paraArray[1].split(' ');
65866
+
65867
+ if(setNameArray.length == 2) {
65868
+ let nameArray = setNameArray[0].split(',');
65869
+ let nameArray2 = setNameArray[1].split(',');
65870
+
65871
+ ic.analysisCls.measureAngleManySets(nameArray, nameArray2);
65872
+ me.htmlCls.dialogCls.openDlg('dl_angletable', 'Angles among the sets');
65657
65873
  }
65658
65874
  }
65659
65875
  }
@@ -67261,9 +67477,9 @@ class SelectCollections {
67261
67477
  'chemicals': {},
67262
67478
  'ions': {},
67263
67479
  'water': {},
67264
- 'structures': {}, // getSSExpandedAtoms
67480
+ 'structures': {},
67265
67481
  'ssbondpnts': {},
67266
- 'residues': {}, // getSSExpandedAtoms
67482
+ 'residues': {},
67267
67483
  'chains': {},
67268
67484
  'chainsSeq': {}, //Sequences and Annotation
67269
67485
  'defNames2Atoms': {},
@@ -67312,9 +67528,9 @@ class SelectCollections {
67312
67528
  'chemicals': ic.chemicals,
67313
67529
  'ions': ic.ions,
67314
67530
  'water': ic.water,
67315
- 'structures': ic.structures, // getSSExpandedAtoms
67531
+ 'structures': ic.structures,
67316
67532
  'ssbondpnts': ic.ssbondpnts,
67317
- 'residues': ic.residues, // getSSExpandedAtoms
67533
+ 'residues': ic.residues,
67318
67534
  'chains': ic.chains,
67319
67535
  'chainsSeq': ic.chainsSeq, //Sequences and Annotation
67320
67536
  'defNames2Atoms': ic.defNames2Atoms,
@@ -67328,9 +67544,9 @@ class SelectCollections {
67328
67544
  'chemicals': thisClass.dictionaryDifference(ic.allData['prev']['chemicals'], ic.chemicals),
67329
67545
  'ions': thisClass.dictionaryDifference(ic.allData['prev']['ions'], ic.ions),
67330
67546
  'water': thisClass.dictionaryDifference(ic.allData['prev']['water'], ic.water),
67331
- 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures), // getSSExpandedAtoms
67547
+ 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures),
67332
67548
  'ssbondpnts': thisClass.dictionaryDifference(ic.allData['prev']['ssbondpnts'], ic.ssbondpnts),
67333
- 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues), // getSSExpandedAtoms
67549
+ 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues),
67334
67550
  'chains': thisClass.dictionaryDifference(ic.allData['prev']['chains'], ic.chains),
67335
67551
  'chainsSeq': thisClass.dictionaryDifference(ic.allData['prev']['chainsSeq'], ic.chainsSeq), //Sequences and Annotation
67336
67552
  'defNames2Atoms': thisClass.dictionaryDifference(ic.allData['prev']['defNames2Atoms'], ic.defNames2Atoms),
@@ -74145,7 +74361,73 @@ class Analysis {
74145
74361
 
74146
74362
  $("#" + me.pre + "dl_disttable_html").html(tableHtml);
74147
74363
  }
74148
- }
74364
+ }
74365
+
74366
+ measureAngleManySets(nameArray, nameArray2) {var ic = this.icn3d, me = ic.icn3dui;
74367
+ if(nameArray.length == 0 || nameArray2.length == 0) {
74368
+ var aaa = 1; //alert("Please select sets for angleance calculation...");
74369
+ }
74370
+ else {
74371
+ let angleHash = {};
74372
+
74373
+ for(let i = 0, il = nameArray.length; i < il; ++i) {
74374
+ let set1 = nameArray[i];
74375
+ let array1 = [set1];
74376
+ angleHash[set1] = {};
74377
+
74378
+ ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(array1);
74379
+ let axis1 = ic.axesCls.setPc1Axes(true);
74380
+
74381
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
74382
+ let set2 = nameArray2[j];
74383
+ let array2 = [set2];
74384
+
74385
+ if(set1 == set2) continue;
74386
+
74387
+ ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(array2);
74388
+ let axis2 = ic.axesCls.setPc1Axes(true);
74389
+
74390
+ 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)));
74391
+
74392
+ let angle = angleRad / 3.1416 * 180;
74393
+ angle = Math.abs(angle).toFixed(0);
74394
+ if(angle > 180) angle -= 180;
74395
+ if(angle > 90) angle = 180 - angle;
74396
+
74397
+ angleHash[set1][set2] = angle;
74398
+ }
74399
+ }
74400
+
74401
+ let tableHtml = '<table align=center border=1 cellpadding=10 cellspacing=0><tr><th></th>';
74402
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
74403
+ let set2 = nameArray2[j];
74404
+ tableHtml += '<th><b>' + set2 + '</b> (&deg;)</th>';
74405
+ }
74406
+ tableHtml += '</tr>';
74407
+
74408
+ for(let i = 0, il = nameArray.length; i < il; ++i) {
74409
+ let set1 = nameArray[i];
74410
+ tableHtml += '<tr><th><b>' + set1 + '</b> (&deg;)</th>';
74411
+
74412
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
74413
+ let set2 = nameArray2[j];
74414
+
74415
+ if(angleHash[set1] && angleHash[set1][set2]) {
74416
+ tableHtml += '<td><span>' + angleHash[set1][set2] + '</span></td>';
74417
+ }
74418
+ else {
74419
+ tableHtml += '<td>0</td>';
74420
+ }
74421
+ }
74422
+
74423
+ tableHtml += '</tr>';
74424
+ }
74425
+
74426
+ tableHtml += '</table><br><br>';
74427
+
74428
+ $("#" + me.pre + "dl_angletable_html").html(tableHtml);
74429
+ }
74430
+ }
74149
74431
 
74150
74432
  //Add a line between the position (x1, y1, z1) and the position (x2, y2, z2) with the input "color".
74151
74433
  //The line can be dashed if "dashed" is set true.
@@ -77988,7 +78270,8 @@ class ShareLink {
77988
78270
  }
77989
78271
  else {
77990
78272
  text += "\nStart of type file======\n";
77991
- text += ic.InputfileType + "\n";
78273
+ // text += ic.InputfileType + "\n";
78274
+ text += "pdb\n";
77992
78275
  text += "End of type file======\n";
77993
78276
 
77994
78277
  text += "Start of data file======\n";
@@ -80853,7 +81136,7 @@ class iCn3DUI {
80853
81136
  //even when multiple iCn3D viewers are shown together.
80854
81137
  this.pre = this.cfg.divid + "_";
80855
81138
 
80856
- this.REVISION = '3.33.0';
81139
+ this.REVISION = '3.33.2';
80857
81140
 
80858
81141
  // In nodejs, iCn3D defines "window = {navigator: {}}"
80859
81142
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -80997,7 +81280,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
80997
81280
  ic.setStyleCls.handleContextLost();
80998
81281
  ic.applyCenterCls.setWidthHeight(width, height);
80999
81282
  ic.ori_chemicalbinding = ic.opts['chemicalbinding'];
81000
- if(me.cfg.bCalphaOnly !== undefined) ic.bCalphaOnly = me.cfg.bCalphaOnly;
81283
+ // if(me.cfg.bCalphaOnly !== undefined) ic.bCalphaOnly = me.cfg.bCalphaOnly;
81001
81284
  ic.opts = me.hashUtilsCls.cloneHash(ic.opts);
81002
81285
  ic.STATENUMBER = ic.commands.length;
81003
81286
  // If previously crashed, recover it
@@ -81025,7 +81308,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81025
81308
  ic.bInputfile = true;
81026
81309
  ic.InputfileType = 'pdb';
81027
81310
  ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + pdbStr : pdbStr;
81028
-
81311
+
81029
81312
  await ic.pdbParserCls.loadPdbData(pdbStr);
81030
81313
 
81031
81314
  if(me.cfg.resdef !== undefined && me.cfg.chains !== undefined) {
@@ -81036,9 +81319,9 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81036
81319
  for(let i = 0, il = structureArray.length; i < il; ++i) {
81037
81320
  chainidArray.push(structureArray[i] + '_' + chainArray[i]);
81038
81321
  }
81039
-
81322
+
81040
81323
  chainidArray = ic.chainalignParserCls.addPostfixForChainids(chainidArray);
81041
-
81324
+
81042
81325
  let bRealign = true, bPredefined = true;
81043
81326
  await ic.realignParserCls.realignChainOnSeqAlign(undefined, chainidArray, bRealign, bPredefined);
81044
81327
  }
@@ -81059,7 +81342,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81059
81342
  chainidArray.push(domainidArray[i]);
81060
81343
  }
81061
81344
  }
81062
-
81345
+
81063
81346
  // get the matched structures, do not include the template
81064
81347
  let mmdbafid = '';
81065
81348
  for(let i = 0, il = chainidArray.length; i < il; ++i) {
@@ -81070,7 +81353,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81070
81353
  // realign, include the template
81071
81354
  ic.chainidArray = [chain_t].concat(chainidArray);
81072
81355
  ic.chainidArray = ic.chainalignParserCls.addPostfixForChainids(ic.chainidArray);
81073
-
81356
+
81074
81357
  me.htmlCls.clickMenuCls.setLogCmd('resdef ' + me.cfg.resdef, true);
81075
81358
 
81076
81359
  ic.loadCmd = 'vast_search_chainid ' + ic.chainidArray;
@@ -81147,7 +81430,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81147
81430
  }
81148
81431
  else if(me.cfg.refseqid !== undefined) {
81149
81432
  ic.inputid = me.cfg.refseqid;
81150
-
81433
+
81151
81434
  // ic.bNCBI = true;
81152
81435
  ic.loadCmd = 'load refseq ' + me.cfg.refseqid;
81153
81436
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
@@ -81155,7 +81438,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81155
81438
  }
81156
81439
  else if(me.cfg.protein !== undefined) {
81157
81440
  ic.inputid = me.cfg.protein;
81158
-
81441
+
81159
81442
  // ic.bNCBI = true;
81160
81443
  ic.loadCmd = 'load protein ' + me.cfg.protein;
81161
81444
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
@@ -81164,7 +81447,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81164
81447
  else if(me.cfg.blast_rep_id !== undefined) {
81165
81448
  // ic.bNCBI = true;
81166
81449
  ic.inputid = me.cfg.query_id + ',' + me.cfg.blast_rep_id;
81167
-
81450
+
81168
81451
  me.cfg.oriQuery_id = me.cfg.query_id;
81169
81452
  me.cfg.oriBlast_rep_id = me.cfg.blast_rep_id;
81170
81453
 
@@ -81188,7 +81471,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81188
81471
  ic.bSmithwm = false;
81189
81472
  ic.bLocalSmithwm = false;
81190
81473
  }
81191
-
81474
+
81192
81475
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
81193
81476
  await ic.mmdbParserCls.downloadBlast_rep_id(me.cfg.query_id + ',' + me.cfg.blast_rep_id);
81194
81477
  }
@@ -81197,7 +81480,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81197
81480
  let data = await me.getAjaxPromise(url, 'json', false, 'The RID ' + me.cfg.rid + ' may have expired...');
81198
81481
 
81199
81482
  for(let q = 0, ql = data.BlastOutput2.length; q < ql; ++q) {
81200
-
81483
+
81201
81484
  let hitArray;
81202
81485
  if(data.BlastOutput2[q].report.results.iterations) { // psi-blast may have "iterations". Use the last iteration.
81203
81486
  let nIterations = data.BlastOutput2[q].report.results.iterations.length;
@@ -81208,7 +81491,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81208
81491
  if(data.BlastOutput2[q].report.results.search.query_id != me.cfg.query_id) continue;
81209
81492
  hitArray = data.BlastOutput2[q].report.results.search.hits;
81210
81493
  }
81211
-
81494
+
81212
81495
  let qseq = undefined;
81213
81496
  for(let i = 0, il = hitArray.length; i < il; ++i) {
81214
81497
  let hit = hitArray[i];
@@ -81240,6 +81523,18 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81240
81523
  }
81241
81524
  }
81242
81525
  else if(me.cfg.cid !== undefined) {
81526
+ if(isNaN(me.cfg.cid)) {
81527
+ let urlCid = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?compound2cid=" + me.cfg.cid;
81528
+ let cidJson = await me.getAjaxPromise(urlCid, 'jsonp');
81529
+ if(cidJson.cid && cidJson.cid[0]) {
81530
+ me.cfg.cid = cidJson.cid[0];
81531
+ }
81532
+ else {
81533
+ var aaa = 1; //alert("Please input an valid PubChem CID...");
81534
+ return;
81535
+ }
81536
+ }
81537
+
81243
81538
  ic.inputid = me.cfg.cid;
81244
81539
 
81245
81540
  let url = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/" + ic.inputid + "/description/jsonp";
@@ -81304,7 +81599,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81304
81599
  }
81305
81600
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
81306
81601
 
81307
- await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
81602
+ await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
81308
81603
  //await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
81309
81604
  }
81310
81605
  else if(me.cfg.command !== undefined && me.cfg.command !== '') {
@@ -81318,7 +81613,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81318
81613
 
81319
81614
  return;
81320
81615
  }
81321
-
81616
+
81322
81617
  await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
81323
81618
  // });
81324
81619
  // return me.deferred.promise();
@@ -81386,7 +81681,7 @@ iCn3DUI.prototype.getXMLHttpRqstPromise = function(url, dataType, responseType,
81386
81681
  let oReq = new XMLHttpRequest();
81387
81682
  oReq.open(dataType, url, true);
81388
81683
  oReq.responseType = responseType;
81389
-
81684
+
81390
81685
  oReq.onreadystatechange = function() {
81391
81686
  if (this.readyState == 4) {
81392
81687
  if(this.status == 200) {
@@ -81438,7 +81733,7 @@ iCn3DUI.prototype.getAjaxPromise = function(url, dataType, beforeSend, alertMess
81438
81733
  error : function() {
81439
81734
  if(alertMess) var aaa = 1; //alert(alertMess);
81440
81735
  if(logMess) console.log(logMess);
81441
-
81736
+
81442
81737
  reject('error');
81443
81738
  }
81444
81739
  });
@@ -81481,7 +81776,7 @@ iCn3DUI.prototype.getAjaxPostPromise = async function(url, data, beforeSend, ale
81481
81776
  //if(alertMess) var aaa = 1; //alert(alertMess);
81482
81777
  if(!me.bNode && alertMess) console.log(alertMess);
81483
81778
  if(!me.bNode && logMess) console.log(logMess);
81484
-
81779
+
81485
81780
  // reject('error');
81486
81781
  // keep running the program
81487
81782
  resolve('error');