icn3d 3.29.4 → 3.29.6

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
@@ -7611,6 +7611,13 @@ class ClickMenu {
7611
7611
  //}
7612
7612
  });
7613
7613
 
7614
+ $(document).on("click", "#" + me.pre + "mn2_translate", function(e) { me.icn3d; //e.preventDefault();
7615
+ me.htmlCls.dialogCls.openDlg('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
7616
+ });
7617
+
7618
+ $(document).on("click", "#" + me.pre + "mn2_matrix", function(e) { me.icn3d; //e.preventDefault();
7619
+ me.htmlCls.dialogCls.openDlg('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
7620
+ });
7614
7621
 
7615
7622
  $(document).on("click", "." + me.pre + "mn6_rotate", function(e) { let ic = me.icn3d; //e.preventDefault();
7616
7623
  let value = $(this).attr('v').toLowerCase();
@@ -8667,14 +8674,14 @@ class SetMenu {
8667
8674
  }
8668
8675
 
8669
8676
  //!!!
8670
- /*
8677
+
8671
8678
  html += this.getMenuText('m1_exportrefnum', 'Reference Numbers', undefined, undefined, 2);
8672
8679
  html += "<ul>";
8673
8680
  html += this.getLink('mn1_exportIgstrand', 'Ig Strand', undefined, 3);
8674
8681
  html += this.getLink('mn1_exportKabat', 'Kabat', undefined, 3);
8675
8682
  html += this.getLink('mn1_exportImgt', 'IMGT', undefined, 3);
8676
8683
  html += "</ul>";
8677
- */
8684
+
8678
8685
 
8679
8686
  html += "<li><br/></li>";
8680
8687
 
@@ -8894,6 +8901,9 @@ class SetMenu {
8894
8901
  html += "</ul>";
8895
8902
  html += "</li>";
8896
8903
 
8904
+ html += this.getLink('mn2_translate', 'Translate XYZ', undefined, 1);
8905
+ html += this.getLink('mn2_matrix', 'Apply Matrix', undefined, 1);
8906
+
8897
8907
  html += this.getMenuText('mn2_camera', 'Camera', undefined, undefined, 1);
8898
8908
  html += "<ul>";
8899
8909
  html += this.getRadio('mn6_camera', 'mn6_cameraPers', 'Perspective', true, undefined, 2);
@@ -9515,8 +9525,8 @@ class SetMenu {
9515
9525
  //}
9516
9526
 
9517
9527
  //!!!
9518
- //html += this.getRadio('mn4_clr', 'mn4_clrIgstrand', 'Ig Strand', undefined, undefined, 2);
9519
- //html += this.getRadio('mn4_clr', 'mn4_clrIgproto', 'Ig Protodomain', undefined, undefined, 2);
9528
+ html += this.getRadio('mn4_clr', 'mn4_clrIgstrand', 'Ig Strand', undefined, undefined, 2);
9529
+ html += this.getRadio('mn4_clr', 'mn4_clrIgproto', 'Ig Protodomain', undefined, undefined, 2);
9520
9530
  }
9521
9531
  else {
9522
9532
  //if(!me.cfg.hidelicense) html += this.getRadio('mn4_clr', 'mn1_delphi2', 'DelPhi<br><span style="padding-left:1.5em;">Potential ' + me.htmlCls.licenseStr + '</span>');
@@ -9647,7 +9657,7 @@ class SetMenu {
9647
9657
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelResidues', 'per Residue', undefined, 1, 2);
9648
9658
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelResnum', 'per Residue & Number', undefined, 1, 2);
9649
9659
  //!!!
9650
- //html += this.getRadio('mn6_addlabel', 'mn6_addlabelRefnum', 'per Reference Number', undefined, 1, 2);
9660
+ html += this.getRadio('mn6_addlabel', 'mn6_addlabelRefnum', 'per Reference Number', undefined, 1, 2);
9651
9661
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelChains', 'per Chain', undefined, undefined, 2);
9652
9662
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelTermini', 'N- & C-Termini', undefined, 1, 2);
9653
9663
  }
@@ -9739,13 +9749,13 @@ class SetMenu {
9739
9749
 
9740
9750
  html += "<ul>";
9741
9751
  //!!!
9742
- /*
9752
+
9743
9753
  html += this.getLink('mn6_igrefYes', 'Show Ig Ref. Number', undefined, 2);
9744
9754
  html += this.getLink('mn6_igrefTpl', 'Ig w/ Specified Template', undefined, 2);
9745
9755
  html += this.getLink('mn6_igrefNo', 'Hide Ig Ref. Number', undefined, 2);
9746
9756
 
9747
9757
  html += this.getMenuSep();
9748
- */
9758
+
9749
9759
  html += this.getLink('mn6_customref', 'Custom Ref. Number', undefined, 2);
9750
9760
  html += "</ul>";
9751
9761
  html += "</li>";
@@ -11855,6 +11865,39 @@ class SetDialog {
11855
11865
  html += this.addNotebookTitle('dl_disttable', 'Distance Table', true);
11856
11866
  html += "</div>";
11857
11867
 
11868
+ html += me.htmlCls.divStr + "dl_translate' class='" + dialogClass + "'>";
11869
+ html += this.addNotebookTitle('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
11870
+ html += "X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "translateX' value='' size=4> ";
11871
+ html += "Y: " + me.htmlCls.inputTextStr + "id='" + me.pre + "translateY' value='' size=4> ";
11872
+ html += "Z: " + me.htmlCls.inputTextStr + "id='" + me.pre + "translateZ' value='' size=4> ";
11873
+ html += me.htmlCls.buttonStr + "translate_pdb'>Translate</button>";
11874
+ html += "</div>";
11875
+
11876
+ html += me.htmlCls.divStr + "dl_matrix' class='" + dialogClass + "'>";
11877
+ html += this.addNotebookTitle('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
11878
+ html += "0: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix0' value='1' size=2> ";
11879
+ html += "4: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix4' value='0' size=2> ";
11880
+ html += "8: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix8' value='0' size=2> ";
11881
+ html += "12: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix12' value='0' size=2><br>";
11882
+
11883
+ html += "1: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix1' value='0' size=2> ";
11884
+ html += "5: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix5' value='1' size=2> ";
11885
+ html += "9: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix9' value='0' size=2> ";
11886
+ html += "13: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix13' value='0' size=2><br>";
11887
+
11888
+ html += "2: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix2' value='0' size=2> ";
11889
+ html += "6: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix6' value='0' size=2> ";
11890
+ html += "10: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix10' value='1' size=2> ";
11891
+ html += "14: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix14' value='0' size=2><br>";
11892
+
11893
+ html += "3: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix3' value='0' size=2> ";
11894
+ html += "7: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix7' value='0' size=2> ";
11895
+ html += "11: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix11' value='0' size=2> ";
11896
+ html += "15: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix15' value='1' size=2><br>";
11897
+
11898
+ html += me.htmlCls.buttonStr + "matrix_pdb'>Apply Matrix</button>";
11899
+ html += "</div>";
11900
+
11858
11901
  html += me.htmlCls.divStr + "dl_igrefTpl' class='" + dialogClass + "'>";
11859
11902
  html += this.addNotebookTitle('dl_igrefTpl', 'Choose an Ig template');
11860
11903
  html += "<span style='white-space:nowrap;font-weight:bold;'>Choose an Ig template for selected residues:</span> <br><br><select id='" + me.pre + "igrefTpl'>";
@@ -12580,6 +12623,33 @@ class Events {
12580
12623
  window.open(hostUrl + '?pdbid=' + $("#" + me.pre + "pdbid").val(), urlTarget);
12581
12624
  });
12582
12625
 
12626
+ me.myEventCls.onIds("#" + me.pre + "translate_pdb", "click", function(e) { let ic = me.icn3d;
12627
+ e.preventDefault();
12628
+ if(!me.cfg.notebook) dialog.dialog( "close" );
12629
+ let dx = $("#" + me.pre + "translateX").val();
12630
+ let dy = $("#" + me.pre + "translateY").val();
12631
+ let dz = $("#" + me.pre + "translateZ").val();
12632
+
12633
+ ic.transformCls.translateCoord(ic.hAtoms, parseFloat(dx), parseFloat(dy), parseFloat(dz));
12634
+ ic.drawCls.draw();
12635
+
12636
+ thisClass.setLogCmd("translate pdb " + dx + " " + dy + " " + dz, true);
12637
+ });
12638
+
12639
+ me.myEventCls.onIds("#" + me.pre + "matrix_pdb", "click", function(e) { let ic = me.icn3d;
12640
+ e.preventDefault();
12641
+ if(!me.cfg.notebook) dialog.dialog( "close" );
12642
+ let mArray = [];
12643
+ for(let i = 0; i< 16; ++i) {
12644
+ mArray.push(parseFloat($("#" + me.pre + "matrix" + i).val()));
12645
+ }
12646
+
12647
+ ic.transformCls.rotateCoord(ic.hAtoms, mArray);
12648
+ ic.drawCls.draw();
12649
+
12650
+ thisClass.setLogCmd("rotate pdb " + mArray, true);
12651
+ });
12652
+
12583
12653
  me.myEventCls.onIds("#" + me.pre + "pdbid", "keyup", function(e) { let ic = me.icn3d;
12584
12654
  if (e.keyCode === 13) {
12585
12655
  e.preventDefault();
@@ -39260,6 +39330,7 @@ class Domain3d {
39260
39330
  substructItem.z2 = atom.coord.z;
39261
39331
 
39262
39332
  substructItem.Sheet = (atom.ss == 'sheet') ? true : false;
39333
+
39263
39334
  substruct.push(substructItem);
39264
39335
  substructItem = {};
39265
39336
  }
@@ -42985,8 +43056,8 @@ class ShowSeq {
42985
43056
  }
42986
43057
  giSeq = giSeqTmp;
42987
43058
 
42988
- //let divLength = me.htmlCls.RESIDUE_WIDTH * ic.giSeq[chnid].length + 200;
42989
- let divLength = me.htmlCls.RESIDUE_WIDTH * (ic.giSeq[chnid].length + ic.nTotalGap) + 200;
43059
+ //let divLength = me.htmlCls.RESIDUE_WIDTH * (ic.giSeq[chnid].length + ic.nTotalGap) + 200;
43060
+ let divLength = me.htmlCls.RESIDUE_WIDTH * (giSeq.length + ic.nTotalGap) + 200;
42990
43061
 
42991
43062
  // let seqLength = ic.giSeq[chnid].length
42992
43063
  // if(seqLength > ic.maxAnnoLength) {
@@ -43006,7 +43077,7 @@ class ShowSeq {
43006
43077
  // html to display protein positions(10, 20, etc)
43007
43078
  //if(Object.keys(ic.chains[chnid]).length > 10) {
43008
43079
 
43009
- if(ic.giSeq[chnid].length > 10) {
43080
+ if(giSeq.length > 10) {
43010
43081
  htmlTmp = '<div class="icn3d-residueLine" style="white-space:nowrap;">';
43011
43082
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
43012
43083
  //if(ic.baseResi[chnid] != 0 &&(me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined || me.cfg.align !== undefined)) {
@@ -43368,7 +43439,7 @@ class ShowSeq {
43368
43439
  html3 += '</div>';
43369
43440
 
43370
43441
  //if(Object.keys(ic.chains[chnid]).length > 10) {
43371
- if(ic.giSeq[chnid].length > 10) {
43442
+ if(giSeq.length > 10) {
43372
43443
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
43373
43444
  //if(ic.baseResi[chnid] != 0 &&(me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined || me.cfg.align !== undefined)) {
43374
43445
  if((me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined || me.cfg.blast_rep_id !== undefined || me.cfg.align !== undefined || me.cfg.chainalign !== undefined || me.cfg.mmdbafid !== undefined) && atom.resi_ori !== undefined && atom.resi_ori != atom.resi && chnid.indexOf('Misc') == -1 ) {
@@ -43555,12 +43626,12 @@ class ShowSeq {
43555
43626
  // reset ic.residIgLoop for the current selection, which could be the second round of ref num assignment
43556
43627
  // just current chain
43557
43628
  let atomHash = me.hashUtilsCls.intHash(ic.chains[chnid], ic.hAtoms);
43558
- let residHash = ic.firstAtomObjCls.getResiduesFromAtoms(atomHash);
43629
+ ic.firstAtomObjCls.getResiduesFromAtoms(atomHash);
43559
43630
 
43560
- for(let resid in residHash) {
43561
- // not in loop any more if you assign ref numbers multiple times
43562
- delete ic.residIgLoop[resid];
43563
- }
43631
+ // for(let resid in residHash) {
43632
+ // // not in loop any more if you assign ref numbers multiple times
43633
+ // delete ic.residIgLoop[resid];
43634
+ // }
43564
43635
  }
43565
43636
 
43566
43637
  // 1. get the range of each strand excluding loops
@@ -43690,6 +43761,76 @@ class ShowSeq {
43690
43761
  }
43691
43762
  }
43692
43763
 
43764
+ // 2b. extend the strand to end of sheet
43765
+ let maxExtend = 8;
43766
+ for(let i = 0, il = strandArray.length; i < il; ++i) {
43767
+ let startAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[chnid + '_' + strandArray[i].startResi]);
43768
+ let endAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[chnid + '_' + strandArray[i].endResi]);
43769
+
43770
+ let startPos = ic.setSeqAlignCls.getPosFromResi(chnid, strandArray[i].startResi);
43771
+ let endPos = ic.setSeqAlignCls.getPosFromResi(chnid, strandArray[i].endResi);
43772
+
43773
+ if(startAtom.ss == 'sheet' && !startAtom.ssbegin) {
43774
+ for(let j = 1; j <= maxExtend; ++j) {
43775
+ let currPos = startPos - j;
43776
+ let currResi = ic.ParserUtilsCls.getResi(chnid, currPos);
43777
+ if(i > 0 && parseInt(currResi) <= parseInt(strandArray[i-1].endResi)) break;
43778
+
43779
+ let currResid = chnid + '_' + currResi;
43780
+ let currAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[currResid]);
43781
+ if(currAtom.ssbegin) { // find the start of the sheet
43782
+ // update the following: startResi,startRefnum,endResi,endRefnum,loopResCnt,resCntBfAnchor,resCntAtAnchor
43783
+ strandArray[i].startResi = currResi;
43784
+ strandArray[i].startRefnum -= j;
43785
+ strandArray[i].loopResCnt -= j;
43786
+ if(strandArray[i].loopResCnt < 0) strandArray[i].loopResCnt = 0;
43787
+ strandArray[i].resCntBfAnchor += j;
43788
+
43789
+ // update ic.resid2refnum
43790
+ for(let k = 1; k <= j; ++k) {
43791
+ currPos = startPos - k;
43792
+ currResi = ic.ParserUtilsCls.getResi(chnid, currPos);
43793
+ let currResid = chnid + '_' + currResi;
43794
+ delete ic.residIgLoop[currResid];
43795
+ }
43796
+
43797
+ break;
43798
+ }
43799
+ }
43800
+ }
43801
+
43802
+ if(endAtom.ss == 'sheet' && !endAtom.ssend) {
43803
+ for(let j = 1; j <= maxExtend; ++j) {
43804
+ let currPos = endPos + j;
43805
+ let currResi = ic.ParserUtilsCls.getResi(chnid, currPos);
43806
+ if(i < il - 1 && parseInt(currResi) >= parseInt(strandArray[i+1].startResi)) break;
43807
+
43808
+ let currResid = chnid + '_' + currResi;
43809
+ let currAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[currResid]);
43810
+ if(currAtom.ssend) { // find the end of the sheet
43811
+ // update the following: startResi,startRefnum,endResi,endRefnum,loopResCnt,resCntBfAnchor,resCntAtAnchor
43812
+ strandArray[i].endResi = currResi;
43813
+ strandArray[i].endRefnum += j;
43814
+ if(i < il - 1) {
43815
+ strandArray[i + 1].loopResCnt -= j;
43816
+ if(strandArray[i + 1].loopResCnt < 0) strandArray[i + 1].loopResCnt = 0;
43817
+ }
43818
+ strandArray[i].resCntAtAnchor += j;
43819
+
43820
+ // update ic.residIgLoop[resid];
43821
+ for(let k = 1; k <= j; ++k) {
43822
+ currPos = endPos + k;
43823
+ currResi = ic.ParserUtilsCls.getResi(chnid, currPos);
43824
+ let currResid = chnid + '_' + currResi;
43825
+ delete ic.residIgLoop[currResid];
43826
+ }
43827
+
43828
+ break;
43829
+ }
43830
+ }
43831
+ }
43832
+ }
43833
+
43693
43834
  // 3. assign refnumLabel for each resid
43694
43835
  strandCnt = 0;
43695
43836
  let loopCnt = 0;
@@ -45872,7 +46013,15 @@ class LineGraph {
45872
46013
 
45873
46014
  ic.pdbDataArray = await this.promiseWithFixedJobs(pdbAjaxArray);
45874
46015
 
45875
- await thisClass.parseRefPdbData(ic.pdbDataArray, template);
46016
+ let bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template);
46017
+ let numRound = 0;
46018
+
46019
+ //while(!bNoMoreIg) {
46020
+ while(!bNoMoreIg && numRound < 10) {
46021
+ let bRerun = true;
46022
+ bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template, bRerun);
46023
+ ++numRound;
46024
+ }
45876
46025
  }
45877
46026
  else {
45878
46027
  await thisClass.parseRefPdbData(undefined, template);
@@ -45884,7 +46033,7 @@ class LineGraph {
45884
46033
  // }
45885
46034
  }
45886
46035
 
45887
- async parseRefPdbData(dataArray, template) { let ic = this.icn3d, me = ic.icn3dui;
46036
+ async parseRefPdbData(dataArray, template, bRerun) { let ic = this.icn3d, me = ic.icn3dui;
45888
46037
  let thisClass = this;
45889
46038
 
45890
46039
  let struArray = Object.keys(ic.structures);
@@ -45899,6 +46048,7 @@ class LineGraph {
45899
46048
  //ic.resid2domainid = {};
45900
46049
  ic.domainid2pdb = {};
45901
46050
 
46051
+ let bNoMoreIg = true;
45902
46052
  for(let i = 0, il = struArray.length; i < il; ++i) {
45903
46053
  let struct = struArray[i];
45904
46054
  let chainidArray = ic.structures[struct];
@@ -45906,12 +46056,14 @@ class LineGraph {
45906
46056
  for(let j = 0, jl = chainidArray.length; j < jl; ++j) {
45907
46057
  let chainid = chainidArray[j];
45908
46058
 
45909
- let domainAtomsArray = this.getDomainAtomsArray(chainid);
45910
-
46059
+ let domainAtomsArray = this.getDomainAtomsArray(chainid, bRerun);
46060
+
45911
46061
  if(!ic.domainid2refpdbname) ic.domainid2refpdbname = {};
45912
46062
  if(!ic.domainid2score) ic.domainid2score = {};
45913
46063
 
45914
46064
  for(let k = 0, kl = domainAtomsArray.length; k < kl; ++k) {
46065
+ bNoMoreIg = false;
46066
+
45915
46067
  let pdb_target = ic.saveFileCls.getAtomPDB(domainAtomsArray[k], undefined, undefined, undefined, undefined, struct);
45916
46068
  //let bForceOneDomain = true;
45917
46069
  //let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(domainAtomsArray[k], bForceOneDomain);
@@ -46012,6 +46164,8 @@ class LineGraph {
46012
46164
 
46013
46165
  await thisClass.parseAlignData(dataArray3, domainidpairArray3);
46014
46166
  }
46167
+
46168
+ return bNoMoreIg;
46015
46169
  /*
46016
46170
  }
46017
46171
  catch(err) {
@@ -46028,10 +46182,12 @@ class LineGraph {
46028
46182
  */
46029
46183
  }
46030
46184
 
46031
- getDomainAtomsArray(chainid) { let ic = this.icn3d, me = ic.icn3dui;
46185
+ getDomainAtomsArray(chainid, bRerunDomain) { let ic = this.icn3d, me = ic.icn3dui;
46032
46186
  let domainAtomsArray = [];
46033
46187
 
46034
- let minResidues = 20;
46188
+ let minResidues = 20, minAtoms = 200;
46189
+
46190
+ if(!ic.chainid2atomsLeft) ic.chainid2atomsLeft = {};
46035
46191
 
46036
46192
  if(!ic.proteins.hasOwnProperty(ic.firstAtomObjCls.getFirstAtomObj(ic.chains[chainid]).serial)
46037
46193
  && !ic.proteins.hasOwnProperty(ic.firstAtomObjCls.getMiddleAtomObj(ic.chains[chainid]).serial)) return domainAtomsArray;
@@ -46040,18 +46196,37 @@ class LineGraph {
46040
46196
  let currAtoms = me.hashUtilsCls.intHash(ic.chains[chainid], ic.hAtoms);
46041
46197
  if(Object.keys(currAtoms).length == 0) return domainAtomsArray;
46042
46198
 
46199
+ if(bRerunDomain) {
46200
+ let atomsAssigned = {};
46201
+ // for(let resid in ic.resid2refnum_ori) {
46202
+ // atomsAssigned = me.hashUtilsCls.unionHash(atomsAssigned, ic.residues[resid]);
46203
+ // }
46204
+ for(let resid in ic.resid2refnum) {
46205
+ if(ic.resid2refnum[resid]) atomsAssigned = me.hashUtilsCls.unionHash(atomsAssigned, ic.residues[resid]);
46206
+ }
46207
+
46208
+ currAtoms = me.hashUtilsCls.exclHash(currAtoms, atomsAssigned);
46209
+
46210
+ // no need to rerun the rest residues any more
46211
+ if(ic.chainid2atomsLeft[chainid] == Object.keys(currAtoms).length) {
46212
+ return domainAtomsArray;
46213
+ }
46214
+
46215
+ ic.chainid2atomsLeft[chainid] = Object.keys(currAtoms).length;
46216
+
46217
+ if(Object.keys(currAtoms).length < minAtoms) return domainAtomsArray;
46218
+ }
46219
+
46043
46220
  // align each 3D domain with reference structure
46044
46221
  //let result = ic.domain3dCls.c2b_NewSplitChain(ic.chains[chainid]);
46045
46222
  // assign ref numbers to selected residues
46046
- let result = ic.domain3dCls.c2b_NewSplitChain(currAtoms);
46223
+ let result = ic.domain3dCls.c2b_NewSplitChain(currAtoms, undefined);
46047
46224
  let subdomains = result.subdomains;
46048
46225
  let pos2resi = result.pos2resi;
46049
46226
 
46050
46227
  if(subdomains.length <= 1) {
46051
- //domainAtomsArray.push(ic.chains[chainid]);
46052
- domainAtomsArray.push(currAtoms);
46053
-
46054
46228
  let residueArray = ic.resid2specCls.atoms2residues(Object.keys(currAtoms));
46229
+ if(residueArray.length < minResidues) return domainAtomsArray;
46055
46230
 
46056
46231
  let atomFirst = ic.firstAtomObjCls.getFirstAtomObj(currAtoms);
46057
46232
  let atomLast = ic.firstAtomObjCls.getLastAtomObj(currAtoms);
@@ -46062,31 +46237,41 @@ class LineGraph {
46062
46237
  ic.resid2domainid[resid] = chainid + '-0' + '_' + resiSum;
46063
46238
 
46064
46239
  // clear previous refnum assignment if any
46065
- if(ic.resid2refnum && ic.resid2refnum[resid]) {
46240
+ // if(!bRerunDomain && ic.resid2refnum && ic.resid2refnum[resid]) {
46241
+ // if(ic.resid2refnum && ic.resid2refnum[resid]) {
46066
46242
  delete ic.resid2refnum[resid];
46067
- }
46243
+ delete ic.residIgLoop[resid];
46244
+ // }
46068
46245
  }
46246
+
46247
+ domainAtomsArray.push(currAtoms);
46069
46248
  }
46070
46249
  else {
46071
46250
  for(let k = 0, kl = subdomains.length; k < kl; ++k) {
46072
46251
  let domainAtoms = {};
46073
46252
  let segArray = subdomains[k];
46074
46253
 
46254
+ let resCnt = 0;
46075
46255
  for(let m = 0, ml = segArray.length; m < ml; m += 2) {
46076
46256
  let startResi = segArray[m];
46077
46257
  let endResi = segArray[m+1];
46078
46258
  for(let n = parseInt(startResi); n <= parseInt(endResi); ++n) {
46079
46259
  let resid = chainid + '_' + pos2resi[n];
46260
+ ++resCnt;
46080
46261
  domainAtoms = me.hashUtilsCls.unionHash(domainAtoms, ic.residues[resid]);
46081
46262
  //ic.resid2domainid[resid] = chainid + '-' + k;
46082
46263
 
46083
46264
  // clear previous refnum assignment if any
46084
- if(ic.resid2refnum && ic.resid2refnum[resid]) {
46265
+ // if(!bRerunDomain && ic.resid2refnum && ic.resid2refnum[resid]) {
46266
+ // if(ic.resid2refnum && ic.resid2refnum[resid]) {
46085
46267
  delete ic.resid2refnum[resid];
46086
- }
46268
+ delete ic.residIgLoop[resid];
46269
+ // }
46087
46270
  }
46088
46271
  }
46089
46272
 
46273
+ if(resCnt < minResidues) continue;
46274
+
46090
46275
  domainAtomsArray.push(domainAtoms);
46091
46276
 
46092
46277
  let atomFirst = ic.firstAtomObjCls.getFirstAtomObj(domainAtoms);
@@ -46209,31 +46394,45 @@ class LineGraph {
46209
46394
 
46210
46395
  // Ig-like domains: B (2150, 2150a, 2150b), C (3150, 3250), E (7150, 7250), F (8150, 8250) strands
46211
46396
  // Ig domain may require G (7050). But we'll leave that out for now.
46212
- if(!bRound1) {
46397
+ if(!bRound1 && queryData[0].segs) {
46213
46398
  let bBstrand = false, bCstrand = false, bEstrand = false, bFstrand = false;
46214
- for(let i = 0, il = queryData[0].segs.length; i < il; ++i) {
46215
- let seg = queryData[0].segs[i];
46399
+ let bBSheet = true, bCSheet = true, bESheet = true, bFSheet = true;
46400
+ let chainid = domainid.split(',')[0];
46401
+
46402
+ for(let j = 0, jl = queryData[0].segs.length; j < jl; ++j) {
46403
+ let seg = queryData[0].segs[j];
46404
+ let resi = seg.t_start;
46405
+ let resid = chainid + '_' + resi;
46216
46406
 
46217
46407
  if(seg.q_start.indexOf('2550') != -1) {
46218
46408
  bBstrand = true;
46409
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46410
+ bBSheet = (atom.ss == 'sheet');
46219
46411
  }
46220
46412
  else if(seg.q_start.indexOf('3550') != -1) {
46221
46413
  bCstrand = true;
46414
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46415
+ bBSheet = (atom.ss == 'sheet');
46222
46416
  }
46223
46417
  else if(seg.q_start.indexOf('7550') != -1) {
46224
46418
  bEstrand = true;
46419
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46420
+ bBSheet = (atom.ss == 'sheet');
46225
46421
  }
46226
46422
  else if(seg.q_start.indexOf('8550') != -1) {
46227
46423
  bFstrand = true;
46424
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46425
+ bBSheet = (atom.ss == 'sheet');
46228
46426
  }
46229
46427
 
46230
46428
  //if(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand) break;
46231
46429
  if(bBstrand && bCstrand && bEstrand && bFstrand) break;
46232
46430
  }
46233
46431
 
46234
- //if(!(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand)) continue;
46235
- if(!(bBstrand && bCstrand && bEstrand && bFstrand)) {
46236
- if(!me.bNode) console.log("Some of the Ig strands B, C, E, F are missing in the domain " + domainid + "...");
46432
+ if(!(bBstrand && bCstrand && bEstrand && bFstrand) || !(bBSheet && bCSheet && bESheet && bFSheet)) {
46433
+ //if(!(bBstrand && bCstrand && bEstrand && bFstrand)) {
46434
+ if(!me.bNode && !(bBstrand && bCstrand && bEstrand && bFstrand)) console.log("Some of the Ig strands B, C, E, F are missing in the domain " + domainid + "...");
46435
+ if(!me.bNode && !(bBSheet && bCSheet && bESheet && bFSheet)) console.log("Some of the Ig strands B, C, E, F are not beta sheets...");
46237
46436
  if(ic.domainid2refpdbname[domainid] == refpdbname) {
46238
46437
  delete ic.domainid2refpdbname[domainid];
46239
46438
  delete ic.domainid2score[domainid];
@@ -46370,11 +46569,12 @@ class LineGraph {
46370
46569
 
46371
46570
  // assign ic.resid2refnum, ic.refnum2residArray, ic.chainsMapping
46372
46571
  if(!ic.resid2refnum) ic.resid2refnum = {};
46572
+ // if(!ic.resid2refnum_ori) ic.resid2refnum_ori = {};
46373
46573
  if(!ic.refnum2residArray) ic.refnum2residArray = {};
46374
46574
  if(!ic.chainsMapping) ic.chainsMapping = {};
46375
46575
 
46376
46576
  if(!ic.refPdbList) ic.refPdbList = [];
46377
-
46577
+
46378
46578
  for(let chainid in chainid2segs) {
46379
46579
  let segArray = chainid2segs[chainid];
46380
46580
 
@@ -46393,10 +46593,66 @@ class LineGraph {
46393
46593
  }
46394
46594
  ic.refPdbList.push(message);
46395
46595
 
46596
+ // adjust C' and D strands ======start
46597
+ let bCstrand = false, bCpstrand = false, bCppstrand = false, bDstrand = false, bEstrand = false;
46598
+ let CAtom, CpAtom, DAtom, EAtom;
46599
+ //let chainid = domainid.split(',')[0];
46600
+
46601
+ let cntBtCE = 0;
46602
+ for(let i = 0, il = segArray.length; i < il; ++i) {
46603
+ let seg = segArray[i];
46604
+ if(!seg) continue;
46605
+
46606
+ let resi = seg.t_start;
46607
+ let resid = chainid + '_' + resi;
46608
+
46609
+ if(seg.q_start.indexOf('3550') != -1) {
46610
+ bCstrand = true;
46611
+ CAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46612
+ }
46613
+ else if(seg.q_start.indexOf('4550') != -1) {
46614
+ bCpstrand = true;
46615
+ CpAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46616
+ ++cntBtCE;
46617
+ }
46618
+ // else if(seg.q_start.indexOf('5550') != -1) {
46619
+ // bCppstrand = true;
46620
+ // CppAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46621
+ // ++cntBtCE;
46622
+ // }
46623
+ else if(seg.q_start.indexOf('6550') != -1) {
46624
+ bDstrand = true;
46625
+ DAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46626
+ ++cntBtCE;
46627
+ }
46628
+ else if(seg.q_start.indexOf('7550') != -1) {
46629
+ bEstrand = true;
46630
+ EAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
46631
+ }
46632
+
46633
+ if(bCstrand && bCpstrand && bCppstrand && bDstrand && bEstrand) break;
46634
+ }
46635
+
46636
+ let CpToDResi, DToCpResi;
46637
+ if(cntBtCE == 1) {
46638
+ let distToC = (bCpstrand) ? CpAtom.coord.distanceTo(CAtom.coord) : DAtom.coord.distanceTo(CAtom.coord);
46639
+ let distToE = (bCpstrand) ? CpAtom.coord.distanceTo(EAtom.coord) : DAtom.coord.distanceTo(EAtom.coord);
46640
+
46641
+ if(bCpstrand && distToC > distToE) { // rename C' to D
46642
+ CpToDResi = CAtom.resi;
46643
+ }
46644
+ else if(bDstrand && distToC < distToE) { // rename D to C'
46645
+ DToCpResi = DAtom.resi;
46646
+ }
46647
+ }
46648
+ // adjust C' and D strands ======end
46649
+
46396
46650
  let prevStrand;
46397
46651
  let bCd19 = refpdbnameArray.length == 1 && refpdbnameArray[0] == 'CD19_6al5A_human_C2orV-n1';
46398
46652
  for(let i = 0, il = segArray.length; i < il; ++i) {
46399
46653
  let seg = segArray[i];
46654
+ if(!seg) continue;
46655
+
46400
46656
  let qStart = seg.q_start;
46401
46657
  parseInt(seg.q_start);
46402
46658
  if(isNaN(seg.q_start)) seg.q_start.substr(seg.q_start.length - 1, 1);
@@ -46413,10 +46669,21 @@ class LineGraph {
46413
46669
  //let refnum = qStart + postfix;
46414
46670
  let refnum = qStart;
46415
46671
 
46416
- let refnumLabel = this.getLabelFromRefnum(refnum, prevStrand, bCd19);
46672
+ let prevStrandFinal = prevStrand;
46673
+ if(prevStrand == "C'" && CpToDResi && parseInt(seg.t_start) < parseInt(CpToDResi) + 10
46674
+ && parseInt(seg.t_start) > parseInt(CpToDResi) - 10 ) {
46675
+ prevStrandFinal = "D";
46676
+ }
46677
+ else if(prevStrand == "D" && DToCpResi && parseInt(seg.t_start) < parseInt(DToCpResi) + 10
46678
+ && parseInt(seg.t_start) > parseInt(DToCpResi) - 10 ) {
46679
+ prevStrandFinal = "C'";
46680
+ }
46681
+
46682
+ let refnumLabel = this.getLabelFromRefnum(refnum, prevStrandFinal, bCd19);
46417
46683
  prevStrand = (refnumLabel) ? refnumLabel.replace(new RegExp(refnum,'g'), '') : undefined;
46418
46684
 
46419
46685
  ic.resid2refnum[resid] = refnumLabel;
46686
+ // ic.resid2refnum_ori[resid] = refnumLabel;
46420
46687
 
46421
46688
  // final reference numbers will be assign in ic.showSeqCls.showRefNum()
46422
46689
 
@@ -47893,7 +48160,7 @@ class ViewInterPairs {
47893
48160
  // last ss
47894
48161
  if(Object.keys(ssAtoms).length > 0) ssAtomsArray.push(ssAtoms);
47895
48162
  let len = ssAtomsArray.length;
47896
- select = "interactions " + threshold + " | sets " + nameArray2 + " " + nameArray + " | true";
48163
+ let select = "interactions " + threshold + " | sets " + nameArray2 + " " + nameArray + " | true";
47897
48164
  ic.opts['contact'] = "yes";
47898
48165
 
47899
48166
  for(let i = 0; i < len; ++i) {
@@ -50642,7 +50909,7 @@ class Dsn6Parser {
50642
50909
  return sigma;
50643
50910
  }
50644
50911
 
50645
- loadDsn6Data(dsn6data, type, sigma, location, bInputSigma) { let ic = this.icn3d; ic.icn3dui;
50912
+ loadDsn6Data(dsn6data, type, sigma, location, bInputSigma) { let ic = this.icn3d, me = ic.icn3dui;
50646
50913
  // DSN6 http://www.uoxray.uoregon.edu/tnt/manual/node104.html
50647
50914
  // BRIX http://svn.cgl.ucsf.edu/svn/chimera/trunk/libs/VolumeData/dsn6/brix-1.html
50648
50915
 
@@ -50719,6 +50986,8 @@ class Dsn6Parser {
50719
50986
  summand = intView[ 16 ];
50720
50987
  }
50721
50988
 
50989
+ if(!me.bNode) console.log("header: " + JSON.stringify(header));
50990
+
50722
50991
  let data = new Float32Array(
50723
50992
  header.xExtent * header.yExtent * header.zExtent
50724
50993
  );
@@ -51917,7 +52186,9 @@ class MmcifParser {
51917
52186
 
51918
52187
  async downloadMmcifSymmetry(mmcifid, type) { let ic = this.icn3d, me = ic.icn3dui;
51919
52188
  // https://files.rcsb.org/header/ is not accessible in Node.js and Mac
51920
- let url = (me.bNode || me.utilsCls.isMac()) ? "https://files.rcsb.org/view/" + mmcifid + ".cif" : "https://files.rcsb.org/header/" + mmcifid + ".cif";
52189
+ // Some header files are in the wrong format. So we use the full mmCIF file
52190
+ //let url = (me.bNode || me.utilsCls.isMac()) ? "https://files.rcsb.org/view/" + mmcifid + ".cif" : "https://files.rcsb.org/header/" + mmcifid + ".cif";
52191
+ let url = "https://files.rcsb.org/view/" + mmcifid + ".cif";
51921
52192
 
51922
52193
  //ic.bCid = undefined;
51923
52194
  let data1 = await me.getAjaxPromise(url, 'text', false, "The structure " + mmcifid + " was not found...");
@@ -58800,6 +59071,8 @@ class LoadPDB {
58800
59071
 
58801
59072
  let bHeader = false, bFirstAtom = true;
58802
59073
 
59074
+ let segId, prevSegId;
59075
+
58803
59076
  for (let i in lines) {
58804
59077
  let line = lines[i];
58805
59078
  let record = line.substr(0, 6);
@@ -58959,11 +59232,36 @@ class LoadPDB {
58959
59232
  ic.pmid = line.substr(19).trim();
58960
59233
  }
58961
59234
  } else if (record === 'ATOM ' || record === 'HETATM') {
59235
+ //73 - 76 LString(4) segID Segment identifier, left-justified.
59236
+ // deal with PDBs from MD trajectories
59237
+ segId = line.substr(72, 4).trim();
59238
+
58962
59239
  if(bFirstAtom) {
58963
59240
  structure = this.getStructureId(id, moleculeNum, bMutation);
58964
59241
 
58965
59242
  bFirstAtom = false;
58966
59243
  }
59244
+ else if(segId != prevSegId) {
59245
+ ++moleculeNum;
59246
+ id = ic.defaultPdbId;
59247
+
59248
+ structure = this.getStructureId(id, moleculeNum, bMutation);
59249
+
59250
+ //helices = [];
59251
+ //sheets = [];
59252
+ if(!bNMR) {
59253
+ sheetArray = [];
59254
+ sheetStart = [];
59255
+ sheetEnd = [];
59256
+ helixArray = [];
59257
+ helixStart = [];
59258
+ helixEnd = [];
59259
+ }
59260
+
59261
+ bHeader = false; // reinitialize to read structure name from the header
59262
+ }
59263
+
59264
+ prevSegId = segId;
58967
59265
 
58968
59266
  let alt = line.substr(16, 1);
58969
59267
  //if (alt !== " " && alt !== "A") continue;
@@ -61733,6 +62031,22 @@ class ApplyCommand {
61733
62031
  else if(command.indexOf('hide ref number') == 0) {
61734
62032
  ic.bShownRefnum = false;
61735
62033
  }
62034
+ else if(command.indexOf('translate pdb') == 0) {
62035
+ let xyz = command.substr(14 + 1).split(' ');
62036
+
62037
+ ic.transformCls.translateCoord(ic.hAtoms, parseFloat(xyz[0]), parseFloat(xyz[1]), parseFloat(xyz[2]));
62038
+ ic.drawCls.draw();
62039
+ }
62040
+ else if(command.indexOf('rotate pdb') == 0) {
62041
+ let mArray = command.substr(10 + 1).split(',');
62042
+ let mArrayFloat = [];
62043
+ for(let i = 0, il = mArray.length; i < il; ++i) {
62044
+ mArrayFloat.push(parseFloat(mArray[i]));
62045
+ }
62046
+
62047
+ ic.transformCls.rotateCoord(ic.hAtoms, mArrayFloat);
62048
+ ic.drawCls.draw();
62049
+ }
61736
62050
 
61737
62051
  // special, select ==========
61738
62052
 
@@ -62913,6 +63227,14 @@ class SelectCollections {
62913
63227
  ic.transformCls.zoominSelection();
62914
63228
  ic.definedSetsCls.showSets();
62915
63229
 
63230
+ ic.bResetAnno = true;
63231
+ if(ic.bAnnoShown) {
63232
+ await ic.showAnnoCls.showAnnotations();
63233
+
63234
+ ic.hlUpdateCls.updateHlAll(nameArray);
63235
+ // show selected chains in annotation window
63236
+ ic.annotationCls.showAnnoSelectedChains();
63237
+ }
62916
63238
 
62917
63239
  await ic.drawCls.draw();
62918
63240
  ic.saveFileCls.showTitle();
@@ -69861,7 +70183,7 @@ class ResizeCanvas {
69861
70183
  //let itemArray = ['dl_selectannotations', 'dl_alignment', 'dl_2ddgm', 'dl_definedsets', 'dl_graph',
69862
70184
  // 'dl_linegraph', 'dl_scatterplot', 'dl_contactmap', 'dl_allinteraction', 'dl_copyurl',
69863
70185
  // 'dl_symmetry', 'dl_symd', 'dl_rmsd', 'dl_legend', 'dl_disttable'];
69864
- let itemArray = ['dl_2ddgm', 'dl_2dctn', 'dl_alignment', 'dl_sequence2', 'dl_definedsets', 'dl_setsmenu', 'dl_command', 'dl_setoperations', 'dl_vast', 'dl_foldseek', 'dl_mmtfid', 'dl_pdbid', 'dl_afid', 'dl_opmid', 'dl_pdbfile', 'dl_pdbfile_app', 'dl_rescolorfile', 'dl_customcolor', 'dl_align', 'dl_alignaf', 'dl_chainalign', 'dl_chainalign2', 'dl_chainalign3', 'dl_mutation', 'dl_mol2file', 'dl_sdffile', 'dl_xyzfile', 'dl_afmapfile', 'dl_urlfile', 'dl_mmciffile', 'dl_mmcifid', 'dl_mmdbid', 'dl_mmdbafid', 'dl_blast_rep_id', 'dl_yournote', 'dl_proteinname', 'dl_refseqid', 'dl_cid', 'dl_pngimage', 'dl_state', 'dl_fixedversion', 'dl_selection', 'dl_dsn6', 'dl_dsn6url', 'dl_clr', 'dl_symmetry', 'dl_symd', 'dl_contact', 'dl_hbonds', 'dl_realign', 'dl_realignbystruct', 'dl_allinteracton', 'dl_interactionsorted', 'dl_linegraph', 'dl_linegraphcolor', 'dl_scatterplot', 'dl_scatterploitcolor', 'dl_contactmap', 'dl_alignerrormap', 'dl_elecmap2fofc', 'dl_elecmapfofc', 'dl_emmap', 'dl_aroundsphere', 'dl_adjustmem', 'dl_selectplane', 'dl_addlabel', 'dl_addlabelselection', 'dl_labelColor', 'dl_distance', 'dl_stabilizer', 'dl_disttwosets', 'dl_distmanysets', 'dl_stabilizer_rm', 'dl_thickness', 'dl_thickness2', 'dl_addtrack', 'dl_addtrack_tabs', 'dl_saveselection', 'dl_copyurl', 'dl_selectannotations', 'dl_annotations_tabs', 'dl_anno_view_tabs', 'dl_annotations', 'dl_graph', 'dl_svgcolor', 'dl_area', 'dl_colorbyarea', 'dl_rmsd', 'dl_buriedarea', 'dl_propbypercentout', 'dl_propbybfactor', 'dl_legend', 'dl_disttable'];
70186
+ let itemArray = ['dl_2ddgm', 'dl_2dctn', 'dl_alignment', 'dl_sequence2', 'dl_definedsets', 'dl_setsmenu', 'dl_command', 'dl_setoperations', 'dl_vast', 'dl_foldseek', 'dl_mmtfid', 'dl_pdbid', 'dl_afid', 'dl_opmid', 'dl_pdbfile', 'dl_pdbfile_app', 'dl_rescolorfile', 'dl_customcolor', 'dl_align', 'dl_alignaf', 'dl_chainalign', 'dl_chainalign2', 'dl_chainalign3', 'dl_mutation', 'dl_mol2file', 'dl_sdffile', 'dl_xyzfile', 'dl_afmapfile', 'dl_urlfile', 'dl_mmciffile', 'dl_mmcifid', 'dl_mmdbid', 'dl_mmdbafid', 'dl_blast_rep_id', 'dl_yournote', 'dl_proteinname', 'dl_refseqid', 'dl_cid', 'dl_pngimage', 'dl_state', 'dl_fixedversion', 'dl_selection', 'dl_dsn6', 'dl_dsn6url', 'dl_clr', 'dl_symmetry', 'dl_symd', 'dl_contact', 'dl_hbonds', 'dl_realign', 'dl_realignbystruct', 'dl_allinteracton', 'dl_interactionsorted', 'dl_linegraph', 'dl_linegraphcolor', 'dl_scatterplot', 'dl_scatterploitcolor', 'dl_contactmap', 'dl_alignerrormap', 'dl_elecmap2fofc', 'dl_elecmapfofc', 'dl_emmap', 'dl_aroundsphere', 'dl_adjustmem', 'dl_selectplane', 'dl_addlabel', 'dl_addlabelselection', 'dl_labelColor', 'dl_distance', 'dl_stabilizer', 'dl_disttwosets', 'dl_distmanysets', 'dl_stabilizer_rm', 'dl_thickness', 'dl_thickness2', 'dl_addtrack', 'dl_addtrack_tabs', 'dl_saveselection', 'dl_copyurl', 'dl_selectannotations', 'dl_annotations_tabs', 'dl_anno_view_tabs', 'dl_annotations', 'dl_graph', 'dl_svgcolor', 'dl_area', 'dl_colorbyarea', 'dl_rmsd', 'dl_buriedarea', 'dl_propbypercentout', 'dl_propbybfactor', 'dl_legend', 'dl_disttable', 'dl_translate'];
69865
70187
 
69866
70188
  for(let i in itemArray) {
69867
70189
  let item = itemArray[i];
@@ -70025,6 +70347,8 @@ class Transform {
70025
70347
  }
70026
70348
 
70027
70349
  setRotation(axis, angle) { let ic = this.icn3d, me = ic.icn3dui;
70350
+ if(!axis) return;
70351
+
70028
70352
  if(ic.bControlGl && !me.bNode && window.cam) {
70029
70353
  axis.applyQuaternion( window.cam.quaternion ).normalize();
70030
70354
  }
@@ -70089,6 +70413,25 @@ class Transform {
70089
70413
  if(ic.bRender) ic.drawCls.render();
70090
70414
  }
70091
70415
 
70416
+ translateCoord(atoms, dx, dy, dz) { let ic = this.icn3d; ic.icn3dui;
70417
+ for(let i in atoms) {
70418
+ let atom = ic.atoms[i];
70419
+ atom.coord.x += dx;
70420
+ atom.coord.y += dy;
70421
+ atom.coord.z += dz;
70422
+ }
70423
+ }
70424
+
70425
+ rotateCoord(atoms, mArray) { let ic = this.icn3d; ic.icn3dui;
70426
+ const m = new THREE.Matrix4();
70427
+ m.elements = mArray;
70428
+
70429
+ for(let i in atoms) {
70430
+ let atom = ic.atoms[i];
70431
+ atom.coord = atom.coord.applyMatrix4(m);
70432
+ }
70433
+ }
70434
+
70092
70435
  //Center on the selected atoms and zoom in.
70093
70436
  zoominSelection(atoms) { let ic = this.icn3d, me = ic.icn3dui;
70094
70437
  let para = {};
@@ -70646,7 +70989,7 @@ class SaveFile {
70646
70989
  // }
70647
70990
 
70648
70991
  // export assembly symmetry matrix "BIOMT"
70649
- if(ic.biomtMatrices) {
70992
+ if(ic.biomtMatrices && Object.keys(atomHash).length == Object.keys(ic.atoms).length) {
70650
70993
  let stru = Object.keys(ic.structures)[0];
70651
70994
  for(let m = 0, ml = ic.biomtMatrices.length; m < ml; ++m) {
70652
70995
  let mNum = m + 1;
@@ -74416,7 +74759,7 @@ class iCn3DUI {
74416
74759
  //even when multiple iCn3D viewers are shown together.
74417
74760
  this.pre = this.cfg.divid + "_";
74418
74761
 
74419
- this.REVISION = '3.29.2';
74762
+ this.REVISION = '3.29.3';
74420
74763
 
74421
74764
  // In nodejs, iCn3D defines "window = {navigator: {}}"
74422
74765
  this.bNode = (Object.keys(window).length < 2) ? true : false;