util.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /**
  2. * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Michal Malý <michal.maly@ibt.cas.cz>
  5. * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
  6. */
  7. import { NtCTubeTypes as NTT } from './types';
  8. import { NtCTubeProvider } from './property';
  9. import { DnatcoUtil } from '../util';
  10. import { Segmentation, SortedArray } from '../../../mol-data/int';
  11. import { Vec3 } from '../../../mol-math/linear-algebra';
  12. import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, Unit } from '../../../mol-model/structure';
  13. function getAtomPosition(vec: Vec3, loc: StructureElement.Location, residue: DnatcoUtil.Residue, names: string[], altId: string, insCode: string) {
  14. const eI = DnatcoUtil.getAtomIndex(loc, residue, names, altId, insCode);
  15. if (eI !== -1) {
  16. loc.unit.conformation.invariantPosition(eI, vec);
  17. return true;
  18. }
  19. return false; // Atom not found
  20. }
  21. const p_1 = Vec3();
  22. const p0 = Vec3();
  23. const p1 = Vec3();
  24. const p2 = Vec3();
  25. const p3 = Vec3();
  26. const p4 = Vec3();
  27. const pP = Vec3();
  28. const C5PrimeNames = ['C5\'', 'C5*'];
  29. const O3PrimeNames = ['O3\'', 'O3*'];
  30. const O5PrimeNames = ['O5\'', 'O5*'];
  31. const PNames = ['P'];
  32. function getPoints(
  33. loc: StructureElement.Location,
  34. r0: DnatcoUtil.Residue | undefined, r1: DnatcoUtil.Residue, r2: DnatcoUtil.Residue,
  35. altId0: string, altId1: string, altId2: string,
  36. insCode0: string, insCode1: string, insCode2: string,
  37. ) {
  38. if (r0) {
  39. if (!getAtomPosition(p_1, loc, r0, C5PrimeNames, altId0, insCode0))
  40. return void 0;
  41. if (!getAtomPosition(p0, loc, r0, O3PrimeNames, altId0, insCode0))
  42. return void 0;
  43. } else {
  44. if (!getAtomPosition(p0, loc, r1, O5PrimeNames, altId1, insCode1))
  45. return void 0;
  46. }
  47. if (!getAtomPosition(p1, loc, r1, C5PrimeNames, altId1, insCode1))
  48. return void 0;
  49. if (!getAtomPosition(p2, loc, r1, O3PrimeNames, altId1, insCode1))
  50. return void 0;
  51. if (!getAtomPosition(p3, loc, r2, C5PrimeNames, altId2, insCode2))
  52. return void 0;
  53. if (!getAtomPosition(p4, loc, r2, O3PrimeNames, altId2, insCode2))
  54. return void 0;
  55. if (!getAtomPosition(pP, loc, r2, PNames, altId2, insCode2))
  56. return void 0;
  57. return { p_1, p0, p1, p2, p3, p4, pP };
  58. }
  59. function hasGapElements(r: DnatcoUtil.Residue, unit: Unit) {
  60. for (let xI = r.start; xI < r.end; xI++) {
  61. const eI = unit.elements[xI];
  62. if (SortedArray.has(unit.gapElements, eI)) {
  63. return true;
  64. }
  65. }
  66. return false;
  67. }
  68. export type NtCTubeSegment = {
  69. p_1: Vec3,
  70. p0: Vec3,
  71. p1: Vec3,
  72. p2: Vec3,
  73. p3: Vec3,
  74. p4: Vec3,
  75. pP: Vec3,
  76. stepIdx: number,
  77. followsGap: boolean,
  78. firstInChain: boolean,
  79. capEnd: boolean,
  80. }
  81. export class NtCTubeSegmentsIterator {
  82. private chainIt: Segmentation.SegmentIterator<ChainIndex>;
  83. private residueIt: Segmentation.SegmentIterator<ResidueIndex>;
  84. /* Second residue of the previous step, may be undefined
  85. * if we are at the beginning of a chain or right after a discontinuity */
  86. private residuePrev?: DnatcoUtil.Residue;
  87. /* First residue of the current step */
  88. private residueOne?: DnatcoUtil.Residue;
  89. /* Second residue of the current step */
  90. private residueTwo: DnatcoUtil.Residue;
  91. /* First residue of the next step, may be undefined
  92. * if we are at the end of a chain.
  93. * Undefined value indicates that the iterator has reached the end.*/
  94. private residueNext?: DnatcoUtil.Residue;
  95. private data?: NTT.Data;
  96. private altIdOne = '';
  97. private insCodeOne = '';
  98. private loc: StructureElement.Location;
  99. private moveStep() {
  100. if (!this.residueNext)
  101. return void 0;
  102. /* Assume discontinuity of the ResidueIndex of the residue that would become residue one (= first residue of the corresponding step)
  103. * does not equal to ResidueIndex of what would be residue two (= second residue of the corresponding step). */
  104. if (this.residueTwo.index + 1 === this.residueNext.index) {
  105. this.residuePrev = DnatcoUtil.copyResidue(this.residueOne);
  106. this.residueOne = DnatcoUtil.copyResidue(this.residueTwo);
  107. this.residueTwo = DnatcoUtil.copyResidue(this.residueNext)!;
  108. this.residueNext = this.residueIt.hasNext ? DnatcoUtil.copyResidue(this.residueIt.move())! : void 0;
  109. } else {
  110. if (!this.residueIt.hasNext) {
  111. this.residueNext = void 0;
  112. return void 0;
  113. }
  114. // There is discontinuity, act as if we were at the beginning of a chain
  115. this.residuePrev = void 0;
  116. this.residueOne = DnatcoUtil.copyResidue(this.residueNext);
  117. this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!;
  118. this.residueNext = this.residueIt.hasNext ? DnatcoUtil.copyResidue(this.residueIt.move())! : void 0;
  119. }
  120. return this.toSegment(this.residuePrev, this.residueOne!, this.residueTwo, this.residueNext);
  121. }
  122. private prime() {
  123. if (this.residueIt.hasNext)
  124. this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!;
  125. if (this.residueIt.hasNext)
  126. this.residueNext = this.residueIt.move();
  127. }
  128. private toSegment(r0: DnatcoUtil.Residue | undefined, r1: DnatcoUtil.Residue, r2: DnatcoUtil.Residue, r3: DnatcoUtil.Residue | undefined): NtCTubeSegment | undefined {
  129. const indices = DnatcoUtil.getStepIndices(this.data!.data, this.loc, r1);
  130. if (indices.length === 0)
  131. return void 0;
  132. const stepIdx = indices[0];
  133. const step = this.data!.data.steps[stepIdx];
  134. const altIdPrev = this.altIdOne;
  135. const insCodePrev = this.insCodeOne;
  136. this.altIdOne = step.label_alt_id_1;
  137. this.insCodeOne = step.PDB_ins_code_1;
  138. const altIdTwo = step.label_alt_id_2;
  139. const insCodeTwo = step.PDB_ins_code_2;
  140. const followsGap = !!r0 && hasGapElements(r0, this.loc.unit) && hasGapElements(r1, this.loc.unit);
  141. const precedesDiscontinuity = r3 ? r3.index !== r2.index + 1 : false;
  142. const points = getPoints(this.loc, r0, r1, r2, altIdPrev, this.altIdOne, altIdTwo, insCodePrev, this.insCodeOne, insCodeTwo);
  143. if (!points)
  144. return void 0;
  145. return {
  146. ...points,
  147. stepIdx,
  148. followsGap,
  149. firstInChain: !r0,
  150. capEnd: !this.residueNext || precedesDiscontinuity || hasGapElements(r2, this.loc.unit),
  151. };
  152. }
  153. constructor(structure: Structure, unit: Unit.Atomic) {
  154. this.chainIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, unit.elements);
  155. this.residueIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements);
  156. const prop = NtCTubeProvider.get(unit.model).value;
  157. this.data = prop?.data;
  158. if (this.chainIt.hasNext) {
  159. this.residueIt.setSegment(this.chainIt.move());
  160. this.prime();
  161. }
  162. this.loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
  163. }
  164. get hasNext() {
  165. if (!this.data)
  166. return false;
  167. return !!this.residueNext
  168. ? true
  169. : this.chainIt.hasNext;
  170. }
  171. move() {
  172. if (!!this.residueNext) {
  173. return this.moveStep();
  174. } else {
  175. this.residuePrev = void 0; // Assume discontinuity when we switch chains
  176. this.residueNext = void 0;
  177. this.residueIt.setSegment(this.chainIt.move());
  178. this.prime();
  179. return this.moveStep();
  180. }
  181. }
  182. }