structure-overpaint-helper.ts 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  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 { PluginStateObject } from '../../mol-plugin/state/objects';
  7. import { StateTransforms } from '../../mol-plugin/state/transforms';
  8. import { StateSelection, StateObjectCell, StateTransform, StateBuilder } from '../../mol-state';
  9. import { Structure, StructureElement } from '../../mol-model/structure';
  10. import { PluginContext } from '../context';
  11. import { Color } from '../../mol-util/color';
  12. import { Overpaint } from '../../mol-theme/overpaint';
  13. type OverpaintEachReprCallback = (update: StateBuilder.Root, repr: StateObjectCell<PluginStateObject.Molecule.Structure.Representation3D, StateTransform<typeof StateTransforms.Representation.StructureRepresentation3D>>, overpaint?: StateObjectCell<any, StateTransform<typeof StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle>>) => void
  14. const OverpaintManagerTag = 'overpaint-controls'
  15. export class StructureOverpaintHelper {
  16. private async eachRepr(callback: OverpaintEachReprCallback) {
  17. const state = this.plugin.state.dataState;
  18. const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D));
  19. const update = state.build();
  20. for (const r of reprs) {
  21. const overpaint = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle, r.transform.ref).withTag(OverpaintManagerTag))
  22. callback(update, r, overpaint[0])
  23. }
  24. await this.plugin.runTask(state.updateTree(update, { doNotUpdateCurrent: true }));
  25. }
  26. async set(color: Color | -1, lociGetter: (structure: Structure) => StructureElement.Loci, types?: string[]) {
  27. await this.eachRepr((update, repr, overpaintCell) => {
  28. if (types && !types.includes(repr.params!.values.type.name)) return
  29. const structure = repr.obj!.data.source.data
  30. // always use the root structure to get the loci so the overpaint
  31. // stays applicable as long as the root structure does not change
  32. const loci = lociGetter(structure.root)
  33. if (StructureElement.Loci.isEmpty(loci)) return
  34. const layer = {
  35. bundle: StructureElement.Bundle.fromLoci(loci),
  36. color: color === -1 ? Color(0) : color,
  37. clear: color === -1
  38. }
  39. if (overpaintCell) {
  40. const bundleLayers = [ ...overpaintCell.params!.values.layers, layer ]
  41. const filtered = getFilteredBundle(bundleLayers, structure)
  42. update.to(overpaintCell).update(Overpaint.toBundle(filtered, 1))
  43. } else {
  44. const filtered = getFilteredBundle([ layer ], structure)
  45. update.to(repr.transform.ref)
  46. .apply(StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle, Overpaint.toBundle(filtered, 1), { tags: OverpaintManagerTag });
  47. }
  48. })
  49. }
  50. constructor(private plugin: PluginContext) {
  51. }
  52. }
  53. /** filter overpaint layers for given structure */
  54. function getFilteredBundle(layers: Overpaint.BundleLayer[], structure: Structure) {
  55. const overpaint = Overpaint.ofBundle(layers, 1, structure.root)
  56. const merged = Overpaint.merge(overpaint)
  57. return Overpaint.filter(merged, structure)
  58. }