structure-overpaint.ts 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. /**
  2. * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. * @author David Sehnal <david.sehnal@gmail.com>
  6. */
  7. import { Structure, StructureElement } from '../../mol-model/structure';
  8. import { PluginStateObject } from '../../mol-plugin-state/objects';
  9. import { StateTransforms } from '../../mol-plugin-state/transforms';
  10. import { PluginContext } from '../../mol-plugin/context';
  11. import { StateBuilder, StateObjectCell, StateSelection, StateTransform } from '../../mol-state';
  12. import { Overpaint } from '../../mol-theme/overpaint';
  13. import { Color } from '../../mol-util/color';
  14. import { StructureComponentRef } from '../manager/structure/hierarchy-state';
  15. import { EmptyLoci, Loci } from '../../mol-model/loci';
  16. 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
  17. const OverpaintManagerTag = 'overpaint-controls'
  18. export async function setStructureOverpaint(plugin: PluginContext, components: StructureComponentRef[], color: Color | -1, lociGetter: (structure: Structure) => StructureElement.Loci | EmptyLoci, types?: string[], alpha = 1) {
  19. await eachRepr(plugin, components, (update, repr, overpaintCell) => {
  20. if (types && types.length > 0 && !types.includes(repr.params!.values.type.name)) return
  21. const structure = repr.obj!.data.source.data
  22. // always use the root structure to get the loci so the overpaint
  23. // stays applicable as long as the root structure does not change
  24. const loci = lociGetter(structure.root)
  25. if (Loci.isEmpty(loci)) return
  26. const layer = {
  27. bundle: StructureElement.Bundle.fromLoci(loci),
  28. color: color === -1 ? Color(0) : color,
  29. clear: color === -1
  30. }
  31. if (overpaintCell) {
  32. const bundleLayers = [...overpaintCell.params!.values.layers, layer]
  33. const filtered = getFilteredBundle(bundleLayers, structure)
  34. update.to(overpaintCell).update(Overpaint.toBundle(filtered, alpha))
  35. } else {
  36. const filtered = getFilteredBundle([layer], structure)
  37. update.to(repr.transform.ref)
  38. .apply(StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle, Overpaint.toBundle(filtered, alpha), { tags: OverpaintManagerTag });
  39. }
  40. })
  41. }
  42. export async function clearStructureOverpaint(plugin: PluginContext, components: StructureComponentRef[], types?: string[]) {
  43. await eachRepr(plugin, components, (update, repr, overpaintCell) => {
  44. if (types && types.length > 0 && !types.includes(repr.params!.values.type.name)) return;
  45. if (overpaintCell) {
  46. update.delete(overpaintCell.transform.ref);
  47. }
  48. });
  49. }
  50. function eachRepr(plugin: PluginContext, components: StructureComponentRef[], callback: OverpaintEachReprCallback) {
  51. const state = plugin.state.data;
  52. const update = state.build();
  53. for (const c of components) {
  54. for (const r of c.representations) {
  55. const overpaint = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle, r.cell.transform.ref).withTag(OverpaintManagerTag))
  56. callback(update, r.cell, overpaint[0])
  57. }
  58. }
  59. return update.commit({ doNotUpdateCurrent: true });
  60. }
  61. /** filter overpaint layers for given structure */
  62. function getFilteredBundle(layers: Overpaint.BundleLayer[], structure: Structure) {
  63. const overpaint = Overpaint.ofBundle(layers, 1, structure.root)
  64. const merged = Overpaint.merge(overpaint)
  65. return Overpaint.filter(merged, structure)
  66. }