selection.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /**
  2. * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import Iterator from '../../../mol-base/collections/iterator'
  7. import HashSet from '../../../mol-base/collections/hash-set'
  8. import { Structure, Atom, AtomSet } from '../structure'
  9. type Selection =
  10. | Structure // each atom is interpreted as a singleton structure
  11. | Structure[]
  12. namespace Selection {
  13. export const Empty: Selection = [];
  14. function isStructure(x: Selection): x is Structure { return !!(x as Structure).units && !!(x as Structure).atoms; }
  15. export function structureCount(sel: Selection) {
  16. if (isStructure(sel)) return AtomSet.atomCount(sel.atoms);
  17. return sel.length;
  18. }
  19. export function union(sel: Selection): Structure {
  20. if (isStructure(sel)) return sel;
  21. if (!sel.length) return Structure.Empty;
  22. const sets = [];
  23. for (let i = 0, _i = sel.length; i < _i; i++) sets[sets.length] = sel[i].atoms;
  24. return { units: unionUnits(sel), atoms: AtomSet.unionMany(sets) };
  25. }
  26. export function structures(sel: Selection): Iterator<Structure> {
  27. if (isStructure(sel)) {
  28. const units = sel.units;
  29. return Iterator.map<Atom, Structure>(AtomSet.atoms(sel.atoms), atoms => ({ units, atoms }));
  30. }
  31. return Iterator.Array(sel);
  32. }
  33. export function getAt(sel: Selection, i: number): Structure {
  34. if (isStructure(sel)) {
  35. return { units: sel.units, atoms: AtomSet.atomGetAt(sel.atoms, i) };
  36. }
  37. return sel[i];
  38. }
  39. export interface Builder {
  40. add(s: Structure): void,
  41. getSelection(): Selection
  42. }
  43. class LinearBuilderImpl implements Builder {
  44. private structures: Structure[] = [];
  45. private allSingletons = true;
  46. add(s: Structure) {
  47. const atomCount = AtomSet.atomCount(s.atoms);
  48. if (atomCount === 0) return;
  49. this.structures[this.structures.length] = s;
  50. if (atomCount !== 1) this.allSingletons = false;
  51. }
  52. getSelection() {
  53. const len = this.structures.length;
  54. if (len === 0) return Empty;
  55. if (len === 1) return this.structures[0];
  56. if (this.allSingletons) return union(this.structures);
  57. return this.structures;
  58. }
  59. constructor() { }
  60. }
  61. class HashBuilderImpl implements Builder {
  62. private structures: Structure[] = [];
  63. private allSingletons = true;
  64. private sets = HashSet(AtomSet.hashCode, AtomSet.areEqual);
  65. add(s: Structure) {
  66. const atomCount = AtomSet.atomCount(s.atoms);
  67. if (atomCount === 0 || !this.sets.add(s.atoms)) return;
  68. this.structures[this.structures.length] = s;
  69. if (atomCount !== 1) this.allSingletons = false;
  70. }
  71. getSelection() {
  72. const len = this.structures.length;
  73. if (len === 0) return Empty;
  74. if (len === 1) return this.structures[0];
  75. if (this.allSingletons) return union(this.structures);
  76. return this.structures;
  77. }
  78. constructor() { }
  79. }
  80. export function LinearBuilder(): Builder { return new LinearBuilderImpl(); }
  81. export function UniqueBuilder(): Builder { return new HashBuilderImpl(); }
  82. // TODO: spatial lookup
  83. }
  84. export default Selection
  85. function unionUnits(xs: Structure[]): Structure['units'] {
  86. let prev = xs[0].units;
  87. let sameModel = true;
  88. for (let i = 1, _i = xs.length; i < _i; i++) {
  89. if (xs[i].units !== prev) sameModel = false;
  90. }
  91. if (sameModel) return prev;
  92. let ret: any = { ...prev };
  93. for (let i = 1, _i = xs.length; i < _i; i++) {
  94. const units = xs[i].units;
  95. if (units !== prev) {
  96. const keys = Object.keys(units);
  97. for (let j = 0; j < keys.length; j++) ret[keys[j]] = (units as any)[keys[j]];
  98. }
  99. prev = xs[i];
  100. }
  101. return ret;
  102. }