hetero.ts 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Structure, StructureElement, ResidueIndex } from '../../../mol-model/structure';
  7. import { SequenceWrapper, StructureUnit } from './wrapper';
  8. import { OrderedSet, Segmentation, Interval, SortedArray } from '../../../mol-data/int';
  9. import { Loci } from '../../../mol-model/loci';
  10. import { ColorNames } from '../../../mol-util/color/tables';
  11. export class HeteroSequenceWrapper extends SequenceWrapper<StructureUnit> {
  12. private readonly sequence: string[]
  13. private readonly sequenceIndices: Map<ResidueIndex, number>
  14. private readonly residueIndices: Map<number, ResidueIndex>
  15. residueLabel(seqIdx: number) {
  16. return this.sequence[seqIdx]
  17. }
  18. residueColor(seqIdx: number) {
  19. return ColorNames.black
  20. }
  21. eachResidue(loci: Loci, apply: (set: OrderedSet) => boolean) {
  22. let changed = false
  23. const { structure, unit } = this.data
  24. if (StructureElement.isLoci(loci)) {
  25. if (!Structure.areParentsEqual(loci.structure, structure)) return false
  26. for (const e of loci.elements) {
  27. if (e.unit.id === unit.id) {
  28. const { index: residueIndex } = e.unit.model.atomicHierarchy.residueAtomSegments
  29. OrderedSet.forEach(e.indices, v => {
  30. const seqIdx = this.sequenceIndices.get(residueIndex[unit.elements[v]])
  31. if (seqIdx !== undefined && apply(Interval.ofSingleton(seqIdx))) changed = true
  32. })
  33. }
  34. }
  35. } else if (Structure.isLoci(loci)) {
  36. if (!Structure.areParentsEqual(loci.structure, structure)) return false
  37. if (apply(Interval.ofBounds(0, this.length))) changed = true
  38. }
  39. return changed
  40. }
  41. getLoci(seqIdx: number) {
  42. const elements: StructureElement.Loci['elements'][0][] = []
  43. const rI = this.residueIndices.get(seqIdx)
  44. if (rI !== undefined) {
  45. const { unit } = this.data
  46. const { offsets } = unit.model.atomicHierarchy.residueAtomSegments
  47. const start = SortedArray.findPredecessorIndex(unit.elements, offsets[rI])
  48. const end = SortedArray.findPredecessorIndex(unit.elements, offsets[rI + 1])
  49. elements.push({ unit, indices: Interval.ofBounds(start, end) })
  50. }
  51. return StructureElement.Loci(this.data.structure, elements)
  52. }
  53. constructor(data: StructureUnit) {
  54. const sequence: string[] = []
  55. const sequenceIndices = new Map<ResidueIndex, number>()
  56. const residueIndices = new Map<number, ResidueIndex>()
  57. const residueIt = Segmentation.transientSegments(data.unit.model.atomicHierarchy.residueAtomSegments, data.unit.elements)
  58. while (residueIt.hasNext) {
  59. const { index } = residueIt.move()
  60. sequenceIndices.set(index, sequence.length)
  61. residueIndices.set(sequence.length, index)
  62. sequence.push(data.unit.model.atomicHierarchy.residues.label_comp_id.value(index))
  63. }
  64. const length = sequence.length
  65. const markerArray = new Uint8Array(length)
  66. super(data, markerArray, length)
  67. this.sequence = sequence
  68. this.sequenceIndices = sequenceIndices
  69. this.residueIndices = residueIndices
  70. }
  71. }