backbone-iterator.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Unit, StructureElement, ElementIndex, ResidueIndex } from '../../../../../mol-model/structure';
  7. import { Segmentation } from '../../../../../mol-data/int';
  8. import Iterator from '../../../../../mol-data/iterator';
  9. import SortedRanges from '../../../../../mol-data/int/sorted-ranges';
  10. import { getPolymerRanges } from '../polymer';
  11. /** Iterates over consecutive pairs of residues/coarse elements in polymers */
  12. export function PolymerBackboneIterator(unit: Unit): Iterator<PolymerBackbonePair> {
  13. switch (unit.kind) {
  14. case Unit.Kind.Atomic: return new AtomicPolymerBackboneIterator(unit)
  15. case Unit.Kind.Spheres:
  16. case Unit.Kind.Gaussians:
  17. return new CoarsePolymerBackboneIterator(unit)
  18. }
  19. }
  20. interface PolymerBackbonePair {
  21. centerA: StructureElement.Location
  22. centerB: StructureElement.Location
  23. }
  24. function createPolymerBackbonePair (unit: Unit) {
  25. return {
  26. centerA: StructureElement.Location.create(unit),
  27. centerB: StructureElement.Location.create(unit),
  28. }
  29. }
  30. const enum AtomicPolymerBackboneIteratorState { nextPolymer, firstResidue, nextResidue, cycle }
  31. export class AtomicPolymerBackboneIterator implements Iterator<PolymerBackbonePair> {
  32. private traceElementIndex: ArrayLike<ElementIndex>
  33. private value: PolymerBackbonePair
  34. private polymerIt: SortedRanges.Iterator<ElementIndex, ResidueIndex>
  35. private residueIt: Segmentation.SegmentIterator<ResidueIndex>
  36. private state: AtomicPolymerBackboneIteratorState = AtomicPolymerBackboneIteratorState.nextPolymer
  37. private residueSegment: Segmentation.Segment<ResidueIndex>
  38. hasNext: boolean = false;
  39. move() {
  40. if (this.state === AtomicPolymerBackboneIteratorState.nextPolymer) {
  41. while (this.polymerIt.hasNext) {
  42. this.residueIt.setSegment(this.polymerIt.move());
  43. if (this.residueIt.hasNext) {
  44. this.residueSegment = this.residueIt.move()
  45. this.value.centerB.element = this.traceElementIndex[this.residueSegment.index]
  46. this.state = AtomicPolymerBackboneIteratorState.nextResidue
  47. break
  48. }
  49. }
  50. }
  51. if (this.state === AtomicPolymerBackboneIteratorState.nextResidue) {
  52. this.residueSegment = this.residueIt.move()
  53. this.value.centerA.element = this.value.centerB.element
  54. this.value.centerB.element = this.traceElementIndex[this.residueSegment.index]
  55. if (!this.residueIt.hasNext) {
  56. if (this.unit.model.atomicRanges.cyclicPolymerMap.has(this.residueSegment.index)) {
  57. this.state = AtomicPolymerBackboneIteratorState.cycle
  58. } else {
  59. // TODO need to advance to a polymer that has two or more residues (can't assume it has)
  60. this.state = AtomicPolymerBackboneIteratorState.nextPolymer
  61. }
  62. }
  63. } else if (this.state === AtomicPolymerBackboneIteratorState.cycle) {
  64. const { cyclicPolymerMap } = this.unit.model.atomicRanges
  65. this.value.centerA.element = this.value.centerB.element
  66. this.value.centerB.element = this.traceElementIndex[cyclicPolymerMap.get(this.residueSegment.index)!]
  67. // TODO need to advance to a polymer that has two or more residues (can't assume it has)
  68. this.state = AtomicPolymerBackboneIteratorState.nextPolymer
  69. }
  70. this.hasNext = this.residueIt.hasNext || this.polymerIt.hasNext || this.state === AtomicPolymerBackboneIteratorState.cycle
  71. return this.value;
  72. }
  73. constructor(private unit: Unit.Atomic) {
  74. this.traceElementIndex = unit.model.atomicHierarchy.derived.residue.traceElementIndex as ArrayLike<ElementIndex> // can assume it won't be -1 for polymer residues
  75. this.polymerIt = SortedRanges.transientSegments(getPolymerRanges(unit), unit.elements)
  76. this.residueIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements)
  77. this.value = createPolymerBackbonePair(unit)
  78. this.hasNext = this.residueIt.hasNext && this.polymerIt.hasNext
  79. }
  80. }
  81. const enum CoarsePolymerBackboneIteratorState { nextPolymer, nextElement }
  82. export class CoarsePolymerBackboneIterator implements Iterator<PolymerBackbonePair> {
  83. private value: PolymerBackbonePair
  84. private polymerIt: SortedRanges.Iterator<ElementIndex, ResidueIndex>
  85. private polymerSegment: Segmentation.Segment<ResidueIndex>
  86. private state: CoarsePolymerBackboneIteratorState = CoarsePolymerBackboneIteratorState.nextPolymer
  87. private elementIndex: number
  88. hasNext: boolean = false;
  89. move() {
  90. if (this.state === CoarsePolymerBackboneIteratorState.nextPolymer) {
  91. if (this.polymerIt.hasNext) {
  92. this.polymerSegment = this.polymerIt.move();
  93. this.elementIndex = this.polymerSegment.start
  94. if (this.elementIndex + 1 < this.polymerSegment.end) {
  95. this.value.centerB.element = this.unit.elements[this.elementIndex]
  96. this.state = CoarsePolymerBackboneIteratorState.nextElement
  97. } else {
  98. this.state = CoarsePolymerBackboneIteratorState.nextPolymer
  99. }
  100. }
  101. }
  102. if (this.state === CoarsePolymerBackboneIteratorState.nextElement) {
  103. this.elementIndex += 1
  104. this.value.centerA.element = this.value.centerB.element
  105. this.value.centerB.element = this.unit.elements[this.elementIndex]
  106. if (this.elementIndex + 1 >= this.polymerSegment.end) {
  107. this.state = CoarsePolymerBackboneIteratorState.nextPolymer
  108. }
  109. }
  110. this.hasNext = this.elementIndex + 1 < this.polymerSegment.end || this.polymerIt.hasNext
  111. return this.value;
  112. }
  113. constructor(private unit: Unit.Spheres | Unit.Gaussians) {
  114. this.polymerIt = SortedRanges.transientSegments(getPolymerRanges(unit), unit.elements);
  115. this.value = createPolymerBackbonePair(unit)
  116. this.hasNext = this.polymerIt.hasNext
  117. }
  118. }