Bladeren bron

improve illustrative style support

- add illustrative representation preset
- add style option to illustrative color theme
Alexander Rose 3 jaren geleden
bovenliggende
commit
dcd23bc0cb

+ 3 - 0
CHANGELOG.md

@@ -12,6 +12,9 @@ Note that since we don't clearly distinguish between a public and private interf
 - Add partial charge parsing support for MOL/SDF files (thanks @ptourlas)
 - [Breaking] Cleaner looking ``MembraneOrientationVisuals`` defaults
 - Add support for custom colors to "molecule-type" theme
+- [Breaking] Add style parameter to "illustrative" color theme
+    - Defaults to "entity-id" style instad of "chain-id"
+- Add "illustrative" representation preset
 
 ## [v3.0.0-dev.9] - 2022-01-09
 

+ 73 - 2
src/mol-plugin-state/builder/structure/representation-preset.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -24,6 +24,8 @@ import { IndexPairBonds } from '../../../mol-model-formats/structure/property/bo
 import { StructConn } from '../../../mol-model-formats/structure/property/bonds/struct_conn';
 import { StructureRepresentationRegistry } from '../../../mol-repr/structure/registry';
 import { assertUnreachable } from '../../../mol-util/type-helpers';
+import { Color } from '../../../mol-util/color';
+import { PostprocessingParams } from '../../../mol-canvas3d/passes/postprocessing';
 
 export interface StructureRepresentationPresetProvider<P = any, S extends _Result = _Result> extends PresetProvider<PluginStateObject.Molecule.Structure, P, S> { }
 export function StructureRepresentationPresetProvider<P, S extends _Result>(repr: StructureRepresentationPresetProvider<P, S>) { return repr; }
@@ -98,6 +100,15 @@ type CommonParams = StructureRepresentationPresetProvider.CommonParams
 const reprBuilder = StructureRepresentationPresetProvider.reprBuilder;
 const updateFocusRepr = StructureRepresentationPresetProvider.updateFocusRepr;
 
+function resetPostprocessingProps(plugin: PluginContext) {
+    if (plugin.canvas3d) {
+        const p = PD.getDefaultValues(PostprocessingParams);
+        plugin.canvas3d.setProps({
+            postprocessing: { outline: p.outline, occlusion: p.occlusion }
+        });
+    }
+}
+
 const auto = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-auto',
     display: {
@@ -137,6 +148,7 @@ const empty = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-empty',
     display: { name: 'Empty', description: 'Removes all existing representations.' },
     async apply(ref, params, plugin) {
+        resetPostprocessingProps(plugin);
         return { };
     }
 });
@@ -191,6 +203,8 @@ const polymerAndLigand = StructureRepresentationPresetProvider({
         await update.commit({ revertOnError: false });
         await updateFocusRepr(plugin, structure, params.theme?.focus?.name, params.theme?.focus?.params);
 
+        resetPostprocessingProps(plugin);
+
         return { components, representations };
     }
 });
@@ -230,6 +244,8 @@ const proteinAndNucleic = StructureRepresentationPresetProvider({
         await update.commit({ revertOnError: true });
         await updateFocusRepr(plugin, structure, params.theme?.focus?.name, params.theme?.focus?.params);
 
+        resetPostprocessingProps(plugin);
+
         return { components, representations };
     }
 });
@@ -282,6 +298,8 @@ const coarseSurface = StructureRepresentationPresetProvider({
         await update.commit({ revertOnError: true });
         await updateFocusRepr(plugin, structure, params.theme?.focus?.name, params.theme?.focus?.params);
 
+        resetPostprocessingProps(plugin);
+
         return { components, representations };
     }
 });
@@ -315,6 +333,8 @@ const polymerCartoon = StructureRepresentationPresetProvider({
         await update.commit({ revertOnError: true });
         await updateFocusRepr(plugin, structure, params.theme?.focus?.name, params.theme?.focus?.params);
 
+        resetPostprocessingProps(plugin);
+
         return { components, representations };
     }
 });
@@ -381,6 +401,56 @@ const atomicDetail = StructureRepresentationPresetProvider({
         await update.commit({ revertOnError: true });
         await updateFocusRepr(plugin, structure, params.theme?.focus?.name ?? color, params.theme?.focus?.params ?? colorParams);
 
+        resetPostprocessingProps(plugin);
+
+        return { components, representations };
+    }
+});
+
+const illustrative = StructureRepresentationPresetProvider({
+    id: 'preset-structure-representation-illustrative',
+    display: {
+        name: 'Illustrative', group: 'Miscellaneous',
+        description: '...'
+    },
+    params: () => ({
+        ...CommonParams,
+        showCarbohydrateSymbol: PD.Boolean(false)
+    }),
+    async apply(ref, params, plugin) {
+        const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
+        if (!structureCell) return {};
+
+        const components = {
+            all: await presetStaticComponent(plugin, structureCell, 'all'),
+            branched: undefined
+        };
+
+        const structure = structureCell.obj!.data;
+
+        const { update, builder, typeParams, color } = reprBuilder(plugin, params, structure);
+
+        const representations = {
+            all: builder.buildRepresentation(update, components.all, { type: 'spacefill', typeParams: { ...typeParams, ignoreLight: true }, color: 'illustrative' }, { tag: 'all' }),
+        };
+        await update.commit({ revertOnError: true });
+        await updateFocusRepr(plugin, structure, params.theme?.focus?.name ?? color, params.theme?.focus?.params);
+
+        if (plugin.canvas3d) {
+            plugin.canvas3d.setProps({
+                postprocessing: {
+                    outline: {
+                        name: 'on',
+                        params: { scale: 1, color: Color(0x000000), threshold: 0.25 }
+                    },
+                    occlusion: {
+                        name: 'on',
+                        params: { bias: 0.9, blurKernelSize: 15, radius: 5, samples: 32 }
+                    },
+                }
+            });
+        }
+
         return { components, representations };
     }
 });
@@ -400,6 +470,7 @@ export const PresetStructureRepresentations = {
     'polymer-cartoon': polymerCartoon,
     'polymer-and-ligand': polymerAndLigand,
     'protein-and-nucleic': proteinAndNucleic,
-    'coarse-surface': coarseSurface
+    'coarse-surface': coarseSurface,
+    'illustrative': illustrative,
 };
 export type PresetStructureRepresentations = typeof PresetStructureRepresentations;

+ 21 - 6
src/mol-theme/color/illustrative.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -12,24 +12,39 @@ import { ColorTheme } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { ThemeDataContext } from '../theme';
 import { ChainIdColorTheme, ChainIdColorThemeParams } from './chain-id';
+import { UniformColorTheme, UniformColorThemeParams } from './uniform';
+import { assertUnreachable } from '../../mol-util/type-helpers';
+import { EntityIdColorTheme, EntityIdColorThemeParams } from './entity-id';
+import { MoleculeTypeColorTheme, MoleculeTypeColorThemeParams } from './molecule-type';
 
 const DefaultIllustrativeColor = Color(0xEEEEEE);
-const Description = `Assigns an illustrative color that gives every chain a unique color with lighter carbons (inspired by David Goodsell's Molecule of the Month style).`;
+const Description = `Assigns an illustrative color that gives every chain a color based on the choosen style but with lighter carbons (inspired by David Goodsell's Molecule of the Month style).`;
 
 export const IllustrativeColorThemeParams = {
-    ...ChainIdColorThemeParams,
+    style: PD.MappedStatic('entity-id', {
+        uniform: PD.Group(UniformColorThemeParams),
+        'chain-id': PD.Group(ChainIdColorThemeParams),
+        'entity-id': PD.Group(EntityIdColorThemeParams),
+        'molecule-type': PD.Group(MoleculeTypeColorThemeParams),
+    }),
     carbonLightness: PD.Numeric(0.8, { min: -6, max: 6, step: 0.1 })
 };
 export type IllustrativeColorThemeParams = typeof IllustrativeColorThemeParams
 export function getIllustrativeColorThemeParams(ctx: ThemeDataContext) {
-    return IllustrativeColorThemeParams; // TODO return copy
+    const params = PD.clone(IllustrativeColorThemeParams);
+    return params;
 }
 
 export function IllustrativeColorTheme(ctx: ThemeDataContext, props: PD.Values<IllustrativeColorThemeParams>): ColorTheme<IllustrativeColorThemeParams> {
-    const { color: chainIdColor, legend } = ChainIdColorTheme(ctx, props);
+    const { color: styleColor, legend } =
+        props.style.name === 'uniform' ? UniformColorTheme(ctx, props.style.params) :
+            props.style.name === 'chain-id' ? ChainIdColorTheme(ctx, props.style.params) :
+                props.style.name === 'entity-id' ? EntityIdColorTheme(ctx, props.style.params) :
+                    props.style.name === 'molecule-type' ? MoleculeTypeColorTheme(ctx, props.style.params) :
+                        assertUnreachable(props.style);
 
     function illustrativeColor(location: Location, typeSymbol: ElementSymbol) {
-        const baseColor = chainIdColor(location, false);
+        const baseColor = styleColor(location, false);
         return typeSymbol === 'C' ? Color.lighten(baseColor, props.carbonLightness) : baseColor;
     }