selector.ts 4.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /**
  2. * Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Adam Midlik <midlik@gmail.com>
  5. */
  6. import { SortedArray } from '../../../mol-data/int';
  7. import { ElementIndex, Structure, StructureElement } from '../../../mol-model/structure';
  8. import { StaticStructureComponentTypes, createStructureComponent } from '../../../mol-plugin-state/helpers/structure-component';
  9. import { PluginStateObject } from '../../../mol-plugin-state/objects';
  10. import { MolScriptBuilder } from '../../../mol-script/language/builder';
  11. import { Expression } from '../../../mol-script/language/expression';
  12. import { UUID } from '../../../mol-util';
  13. import { arrayExtend, sortIfNeeded } from '../../../mol-util/array';
  14. import { mapArrayToObject, pickObjectKeys } from '../../../mol-util/object';
  15. import { Choice } from '../../../mol-util/param-choice';
  16. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  17. import { capitalize } from '../../../mol-util/string';
  18. import { MVSAnnotationStructureComponentParams, createMVSAnnotationStructureComponent } from './annotation-structure-component';
  19. /** Allowed values for a static selector */
  20. export const StaticSelectorChoice = new Choice(mapArrayToObject(StaticStructureComponentTypes, t => capitalize(t)), 'all');
  21. export type StaticSelectorChoice = Choice.Values<typeof StaticSelectorChoice>
  22. /** Parameter definition for specifying a part of structure (kinda extension of `StructureComponentParams` from mol-plugin-state/helpers/structure-component) */
  23. export const SelectorParams = PD.MappedStatic('static', {
  24. static: StaticSelectorChoice.PDSelect(),
  25. expression: PD.Value<Expression>(MolScriptBuilder.struct.generator.all),
  26. bundle: PD.Value<StructureElement.Bundle>(StructureElement.Bundle.Empty),
  27. script: PD.Script({ language: 'mol-script', expression: '(sel.atom.all)' }),
  28. annotation: PD.Group(pickObjectKeys(MVSAnnotationStructureComponentParams, ['annotationId', 'fieldName', 'fieldValues'])),
  29. }, { description: 'Define a part of the structure where this layer applies (use Static:all to apply to the whole structure)' }
  30. );
  31. /** Parameter values for specifying a part of structure */
  32. export type Selector = PD.Values<{ selector: typeof SelectorParams }>['selector']
  33. /** `Selector` for selecting the whole structure */
  34. export const SelectorAll = { name: 'static', params: 'all' } satisfies Selector;
  35. /** Decide whether a selector is `SelectorAll` */
  36. export function isSelectorAll(props: Selector): props is typeof SelectorAll {
  37. return props.name === 'static' && props.params === 'all';
  38. }
  39. /** Data structure for fast lookup of a structure element location in a substructure */
  40. export type ElementSet = { [modelId: UUID]: SortedArray<ElementIndex> }
  41. export const ElementSet = {
  42. /** Create an `ElementSet` from the substructure of `structure` defined by `selector` */
  43. fromSelector(structure: Structure | undefined, selector: Selector): ElementSet {
  44. if (!structure) return {};
  45. const arrays: { [modelId: UUID]: ElementIndex[] } = {};
  46. const selection = substructureFromSelector(structure, selector); // using `getAtomRangesForRow` might (might not) be faster here
  47. for (const unit of selection.units) {
  48. arrayExtend(arrays[unit.model.id] ??= [], unit.elements);
  49. }
  50. const result: { [modelId: UUID]: SortedArray<ElementIndex> } = {};
  51. for (const modelId in arrays) {
  52. const array = arrays[modelId as UUID];
  53. sortIfNeeded(array, (a, b) => a - b);
  54. result[modelId as UUID] = SortedArray.ofSortedArray(array);
  55. }
  56. return result;
  57. },
  58. /** Decide if the element set `set` contains structure element location `location` */
  59. has(set: ElementSet, location: StructureElement.Location): boolean {
  60. const array = set[location.unit.model.id];
  61. return array ? SortedArray.has(array, location.element) : false;
  62. },
  63. };
  64. /** Return a substructure of `structure` defined by `selector` */
  65. export function substructureFromSelector(structure: Structure, selector: Selector): Structure {
  66. const pso = (selector.name === 'annotation') ?
  67. createMVSAnnotationStructureComponent(structure, { ...selector.params, label: '', nullIfEmpty: false })
  68. : createStructureComponent(structure, { type: selector, label: '', nullIfEmpty: false }, { source: structure });
  69. return PluginStateObject.Molecule.Structure.is(pso) ? pso.data : Structure.Empty;
  70. }