modifiers.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Segmentation } from 'mol-data/int';
  7. import { Structure, Unit } from '../../structure';
  8. import { StructureQuery } from '../query';
  9. import { StructureSelection } from '../selection';
  10. import { UniqueStructuresBuilder } from '../utils/builders';
  11. import { StructureUniqueSubsetBuilder } from '../../structure/util/unique-subset-builder';
  12. import { QueryContext } from '../context';
  13. import { structureIntersect, structureSubtract } from '../utils/structure-set';
  14. function getWholeResidues(ctx: QueryContext, source: Structure, structure: Structure) {
  15. const builder = source.subsetBuilder(true);
  16. for (const unit of structure.units) {
  17. if (unit.kind !== Unit.Kind.Atomic) {
  18. // just copy non-atomic units.
  19. builder.setUnit(unit.id, unit.elements);
  20. continue;
  21. }
  22. const { residueAtomSegments } = unit.model.atomicHierarchy;
  23. const elements = unit.elements;
  24. builder.beginUnit(unit.id);
  25. const residuesIt = Segmentation.transientSegments(residueAtomSegments, elements);
  26. while (residuesIt.hasNext) {
  27. const rI = residuesIt.move().index;
  28. for (let j = residueAtomSegments.offsets[rI], _j = residueAtomSegments.offsets[rI + 1]; j < _j; j++) {
  29. builder.addElement(j);
  30. }
  31. }
  32. builder.commitUnit();
  33. ctx.throwIfTimedOut();
  34. }
  35. return builder.getStructure();
  36. }
  37. export function wholeResidues(query: StructureQuery): StructureQuery {
  38. return ctx => {
  39. const inner = query(ctx);
  40. if (StructureSelection.isSingleton(inner)) {
  41. return StructureSelection.Singletons(ctx.inputStructure, getWholeResidues(ctx, ctx.inputStructure, inner.structure));
  42. } else {
  43. const builder = new UniqueStructuresBuilder(ctx.inputStructure);
  44. for (const s of inner.structures) {
  45. builder.add(getWholeResidues(ctx, ctx.inputStructure, s));
  46. }
  47. return builder.getSelection();
  48. }
  49. };
  50. }
  51. export interface IncludeSurroundingsParams {
  52. radius: number,
  53. // TODO
  54. // atomRadius?: Element.Property<number>,
  55. wholeResidues?: boolean
  56. }
  57. function getIncludeSurroundings(ctx: QueryContext, source: Structure, structure: Structure, params: IncludeSurroundingsParams) {
  58. const builder = new StructureUniqueSubsetBuilder(source);
  59. const lookup = source.lookup3d;
  60. const r = params.radius;
  61. for (const unit of structure.units) {
  62. const { x, y, z } = unit.conformation;
  63. const elements = unit.elements;
  64. for (let i = 0, _i = elements.length; i < _i; i++) {
  65. const e = elements[i];
  66. lookup.findIntoBuilder(x(e), y(e), z(e), r, builder);
  67. }
  68. ctx.throwIfTimedOut();
  69. }
  70. return !!params.wholeResidues ? getWholeResidues(ctx, source, builder.getStructure()) : builder.getStructure();
  71. }
  72. export function includeSurroundings(query: StructureQuery, params: IncludeSurroundingsParams): StructureQuery {
  73. return ctx => {
  74. const inner = query(ctx);
  75. if (StructureSelection.isSingleton(inner)) {
  76. const surr = getIncludeSurroundings(ctx, ctx.inputStructure, inner.structure, params);
  77. const ret = StructureSelection.Singletons(ctx.inputStructure, surr);
  78. return ret;
  79. } else {
  80. const builder = new UniqueStructuresBuilder(ctx.inputStructure);
  81. for (const s of inner.structures) {
  82. builder.add(getIncludeSurroundings(ctx, ctx.inputStructure, s, params));
  83. }
  84. return builder.getSelection();
  85. }
  86. };
  87. }
  88. export function querySelection(selection: StructureQuery, query: StructureQuery): StructureQuery {
  89. return ctx => {
  90. const targetSel = selection(ctx);
  91. if (StructureSelection.structureCount(targetSel) === 0) return targetSel;
  92. const ret = StructureSelection.UniqueBuilder(ctx.inputStructure);
  93. const add = (s: Structure) => ret.add(s);
  94. StructureSelection.forEach(targetSel, (s, sI) => {
  95. ctx.pushInputStructure(s);
  96. StructureSelection.forEach(query(ctx), add);
  97. ctx.popInputStructure();
  98. if (sI % 10 === 0) ctx.throwIfTimedOut();
  99. });
  100. return ret.getSelection();
  101. }
  102. }
  103. export function intersectBy(query: StructureQuery, by: StructureQuery): StructureQuery {
  104. return ctx => {
  105. const selection = query(ctx);
  106. if (StructureSelection.structureCount(selection) === 0) return selection;
  107. const bySel = by(ctx);
  108. if (StructureSelection.structureCount(bySel) === 0) return StructureSelection.Empty(ctx.inputStructure);
  109. const unionBy = StructureSelection.unionStructure(bySel);
  110. const ret = StructureSelection.UniqueBuilder(ctx.inputStructure);
  111. StructureSelection.forEach(selection, (s, sI) => {
  112. const ii = structureIntersect(unionBy, s);
  113. if (ii.elementCount !== 0) ret.add(ii);
  114. });
  115. return ret.getSelection();
  116. };
  117. }
  118. export function exceptBy(query: StructureQuery, by: StructureQuery): StructureQuery {
  119. return ctx => {
  120. const selection = query(ctx);
  121. if (StructureSelection.structureCount(selection) === 0) return selection;
  122. const bySel = by(ctx);
  123. if (StructureSelection.structureCount(bySel) === 0) return StructureSelection.Empty(ctx.inputStructure);
  124. const subtractBy = StructureSelection.unionStructure(bySel);
  125. const ret = StructureSelection.UniqueBuilder(ctx.inputStructure);
  126. StructureSelection.forEach(selection, (s, sI) => {
  127. const diff = structureSubtract(s, subtractBy);
  128. if (diff.elementCount !== 0) ret.add(diff);
  129. });
  130. return ret.getSelection();
  131. };
  132. }
  133. export function union(query: StructureQuery): StructureQuery {
  134. return ctx => {
  135. const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
  136. ret.add(StructureSelection.unionStructure(query(ctx)));
  137. return ret.getSelection();
  138. };
  139. }
  140. // TODO: unionBy (skip this one?), cluster, includeConnected, includeSurroundings with "radii", expandProperty