structure.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { arrayFind } from '../../mol-data/util';
  7. import { Structure } from '../../mol-model/structure';
  8. import { StateTransform, StateTree, StateSelection } from '../../mol-state';
  9. import { Task } from '../../mol-task';
  10. import { isProductionMode } from '../../mol-util/debug';
  11. import { objectForEach } from '../../mol-util/object';
  12. import { ParamDefinition as PD } from '../../mol-util/param-definition';
  13. import { PluginContext } from '../../mol-plugin/context';
  14. import { PresetStructureReprentations } from './structure/preset';
  15. import { StructureRepresentationProvider, RepresentationProviderTags } from './structure/provider';
  16. import { UniqueArray } from '../../mol-data/generic';
  17. // TODO: support quality
  18. // TODO: support ignore hydrogens
  19. export class StructureRepresentationManager {
  20. private providers: StructureRepresentationProvider[] = [];
  21. private providerMap: Map<string, StructureRepresentationProvider> = new Map();
  22. readonly defaultProvider = PresetStructureReprentations.auto;
  23. hasProvider(s: Structure) {
  24. for (const p of this.providers) {
  25. if (!p.isApplicable || p.isApplicable(s, this.plugin)) return true;
  26. }
  27. return false;
  28. }
  29. getOptions(s: Structure) {
  30. const options: [string, string][] = [];
  31. const map: { [K in string]: PD.Any } = Object.create(null);
  32. for (const p of this.providers) {
  33. if (p.isApplicable && !p.isApplicable(s, this.plugin)) continue;
  34. options.push([p.id, p.display.name]);
  35. map[p.id] = p.params ? PD.Group(p.params(s, this.plugin)) : PD.EmptyGroup()
  36. }
  37. if (options.length === 0) return PD.MappedStatic('', { '': PD.EmptyGroup() });
  38. return PD.MappedStatic(options[0][0], map, { options });
  39. }
  40. hasManagedRepresentation(ref: StateTransform.Ref) {
  41. const tree = this.plugin.state.dataState.tree;
  42. // TODO: make this state selection function?
  43. return StateTree.doPreOrder(tree, tree.transforms.get(ref), { found: false, map: this.providerMap }, (n, _, s) => {
  44. if (!n.tags) return;
  45. for (const t of n.tags) {
  46. if (s.map.has(t)) {
  47. s.found = true;
  48. return false;
  49. }
  50. }
  51. }).found;
  52. }
  53. getManagedRepresentations(ref: StateTransform.Ref) {
  54. // TODO: check if Structure etc.
  55. const tree = this.plugin.state.dataState.tree;
  56. return StateTree.doPreOrder(tree, tree.transforms.get(ref), { found: UniqueArray.create<string, StructureRepresentationProvider>(), map: this.providerMap }, (n, _, s) => {
  57. if (!n.tags) return;
  58. for (const t of n.tags) {
  59. if (s.map.has(t)) UniqueArray.add(s.found, t, s.map.get(t)!);
  60. }
  61. }).found.array;
  62. }
  63. register(provider: StructureRepresentationProvider) {
  64. if (this.providerMap.has(provider.id)) {
  65. throw new Error(`Repr. provider with id '${provider.id}' already registered.`);
  66. }
  67. // TODO: sort by group
  68. this.providers.push(provider);
  69. this.providerMap.set(provider.id, provider);
  70. }
  71. remove(providerOrId: StructureRepresentationProvider | string, structureRoot?: StateTransform.Ref) {
  72. const root = structureRoot || StateTransform.RootRef;
  73. const id = typeof providerOrId === 'string' ? providerOrId : providerOrId.id;
  74. const state = this.plugin.state.dataState;
  75. const reprs = StateSelection.findWithAllTags(state.tree, root, new Set([id, RepresentationProviderTags.Representation]));
  76. const builder = state.build();
  77. for (const r of reprs) {
  78. builder.delete(r.ref);
  79. }
  80. const tree = builder.currentTree;
  81. const selections = StateSelection.findWithAllTags(tree, root, new Set([RepresentationProviderTags.Selection]));
  82. for (const s of selections) {
  83. if (!tree.children.has(s.ref) || tree.children.get(s.ref).size === 0) builder.delete(s.ref);
  84. }
  85. if (builder.editInfo.count === 0) return;
  86. return this.plugin.runTask(state.updateTree(builder));
  87. }
  88. apply<P = any, S = {}>(ref: StateTransform.Ref, providerOrId: StructureRepresentationProvider<P, S> | string, params?: P) {
  89. const provider = typeof providerOrId === 'string'
  90. ? arrayFind(this.providers, p => p.id === providerOrId)
  91. : providerOrId;
  92. if (!provider) return;
  93. const state = this.plugin.state.dataState;
  94. const cell = state.cells.get(ref);
  95. if (!cell || !cell.obj || cell.status !== 'ok') {
  96. if (!isProductionMode) console.warn(`Applying structure repr. provider to bad cell.`);
  97. return;
  98. }
  99. const prms = params || (provider.params
  100. ? PD.getDefaultValues(provider.params(cell.obj.data, this.plugin))
  101. : {})
  102. const task = Task.create<S>(`${provider.display.name}`, ctx => provider.apply(ctx, state, cell, prms, this.plugin) as Promise<S>);
  103. return this.plugin.runTask(task);
  104. }
  105. // init() {
  106. // objectForEach(PresetStructureReprentations, r => this.register(r));
  107. // }
  108. constructor(public plugin: PluginContext) {
  109. objectForEach(PresetStructureReprentations, r => this.register(r));
  110. }
  111. }