hetero.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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, Unit } 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/names';
  11. import { MarkerAction, applyMarkerAction } from '../../mol-util/marker-action';
  12. export class HeteroSequenceWrapper extends SequenceWrapper<StructureUnit> {
  13. private readonly unitMap: Map<number, Unit>
  14. private readonly sequence: string[]
  15. private readonly sequenceIndices: Map<ResidueIndex, number>
  16. private readonly residueIndices: Map<number, ResidueIndex>
  17. private readonly seqToUnit: Map<number, Unit>
  18. residueLabel(seqIdx: number) {
  19. return this.sequence[seqIdx];
  20. }
  21. residueColor(seqIdx: number) {
  22. return ColorNames.black;
  23. }
  24. residueClass(seqIdx: number) {
  25. return 'msp-sequence-present';
  26. }
  27. mark(loci: Loci, action: MarkerAction) {
  28. let changed = false;
  29. const { structure } = this.data;
  30. if (StructureElement.Loci.is(loci)) {
  31. if (!Structure.areRootsEquivalent(loci.structure, structure)) return false;
  32. loci = StructureElement.Loci.remap(loci, structure);
  33. for (const e of loci.elements) {
  34. const unit = this.unitMap.get(e.unit.id);
  35. if (unit) {
  36. const { index: residueIndex } = e.unit.model.atomicHierarchy.residueAtomSegments;
  37. OrderedSet.forEach(e.indices, v => {
  38. const seqIdx = this.sequenceIndices.get(residueIndex[unit.elements[v]]);
  39. if (seqIdx !== undefined && applyMarkerAction(this.markerArray, Interval.ofSingleton(seqIdx), action)) changed = true;
  40. });
  41. }
  42. }
  43. } else if (Structure.isLoci(loci)) {
  44. if (!Structure.areRootsEquivalent(loci.structure, structure)) return false;
  45. if (applyMarkerAction(this.markerArray, Interval.ofBounds(0, this.length), action)) changed = true;
  46. }
  47. return changed;
  48. }
  49. getLoci(seqIdx: number) {
  50. const elements: StructureElement.Loci['elements'][0][] = [];
  51. const rI = this.residueIndices.get(seqIdx);
  52. if (rI !== undefined) {
  53. const unit = this.seqToUnit.get(seqIdx)!;
  54. const { offsets } = unit.model.atomicHierarchy.residueAtomSegments;
  55. const start = SortedArray.findPredecessorIndex(unit.elements, offsets[rI]);
  56. const end = SortedArray.findPredecessorIndex(unit.elements, offsets[rI + 1]);
  57. elements.push({ unit, indices: Interval.ofBounds(start, end) });
  58. }
  59. return StructureElement.Loci(this.data.structure, elements);
  60. }
  61. constructor(data: StructureUnit) {
  62. const sequence: string[] = [];
  63. const sequenceIndices = new Map<ResidueIndex, number>();
  64. const residueIndices = new Map<number, ResidueIndex>();
  65. const seqToUnit = new Map<number, Unit>();
  66. for (let i = 0, il = data.units.length; i < il; ++i) {
  67. const unit = data.units[i];
  68. const { residueAtomSegments, atoms } = unit.model.atomicHierarchy;
  69. const residueIt = Segmentation.transientSegments(residueAtomSegments, unit.elements);
  70. while (residueIt.hasNext) {
  71. const { index } = residueIt.move();
  72. sequenceIndices.set(index, sequence.length);
  73. residueIndices.set(sequence.length, index);
  74. seqToUnit.set(sequence.length, unit);
  75. sequence.push(atoms.label_comp_id.value(residueAtomSegments.offsets[index]));
  76. }
  77. }
  78. const length = sequence.length;
  79. const markerArray = new Uint8Array(length);
  80. super(data, markerArray, length);
  81. this.unitMap = new Map();
  82. for (const unit of data.units) this.unitMap.set(unit.id, unit);
  83. this.sequence = sequence;
  84. this.sequenceIndices = sequenceIndices;
  85. this.residueIndices = residueIndices;
  86. this.seqToUnit = seqToUnit;
  87. }
  88. }