diff --git a/CHANGELOG.md b/CHANGELOG.md index dd6600dfda724293d007181cfd210cd9244d8e06..2a1d89ceb48816b9fba33df24af66d4570bb3c61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,9 @@ Note that since we don't clearly distinguish between a public and private interf - [Breaking] Rename the ``model-index`` color theme to ``trajectory-index`` - Add a new ``model-index`` color theme that uniquely colors each loaded model -- Add the new ``model-index`` color theme as an option for the carbon color in the ``element-symbol`` and ``ilustrative`` color themes -- Add nearest method to lookup3d +- Add the new ``model-index`` and ``structure-index`` color themes as an option for the carbon color in the ``element-symbol`` and ``ilustrative`` color themes +- Add ``structure-index`` color theme that uniquely colors each root structure +- Add ``nearest`` method to ``Lookup3D`` - Add mipmap-based blur for skybox backgrounds ## [v3.19.0] - 2022-10-01 diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 3c2dfdc6322d5895bf82dbd5c6689c78b58d4bae..afcec12747ba27d40354809ab07bb8cc603366b1 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -1357,6 +1357,9 @@ namespace Structure { export type Index = number; export const Index = CustomStructureProperty.createSimple<Index>('index', 'root'); + export type MaxIndex = number; + export const MaxIndex = CustomStructureProperty.createSimple<MaxIndex>('max_index', 'root'); + const PrincipalAxesProp = '__PrincipalAxes__'; export function getPrincipalAxes(structure: Structure): PrincipalAxes { if (structure.currentPropertyData[PrincipalAxesProp]) return structure.currentPropertyData[PrincipalAxesProp]; diff --git a/src/mol-plugin/behavior/dynamic/custom-props/structure-info.ts b/src/mol-plugin/behavior/dynamic/custom-props/structure-info.ts index f144a40cf4b83e608ba4e9c15ae18f5a4731e547..e2484b9ce1c95f8cb62b071636425f4ffa9ed1f1 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/structure-info.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/structure-info.ts @@ -65,6 +65,19 @@ export const StructureInfo = PluginBehavior.create({ } } + private setStructureMaxIndex() { + const value = this.maxModelIndex; + const cells = this.ctx.state.data.select(StateSelection.Generators.rootsOfType(PluginStateObject.Molecule.Structure)); + for (const c of cells) { + const s = c.obj?.data; + if (s) { + if (Structure.MaxIndex.get(s).value !== value) { + Structure.MaxIndex.set(s, { value }, value); + } + } + } + } + private handleModel(model: Model, oldModel?: Model) { if (Model.Index.get(model).value === undefined) { const oldIndex = oldModel && Model.Index.get(oldModel).value; @@ -107,10 +120,12 @@ export const StructureInfo = PluginBehavior.create({ this.ctx.customModelProperties.register(Model.Index, true); this.ctx.customModelProperties.register(Model.MaxIndex, true); this.ctx.customStructureProperties.register(Structure.Index, true); + this.ctx.customStructureProperties.register(Structure.MaxIndex, true); this.subscribeObservable(this.ctx.state.data.events.object.created, o => { this.handle(o.ref, o.obj); this.setModelMaxIndex(); + this.setStructureMaxIndex(); }); this.subscribeObservable(this.ctx.state.data.events.object.updated, o => { @@ -123,6 +138,7 @@ export const StructureInfo = PluginBehavior.create({ this.ctx.customModelProperties.unregister(Model.Index.descriptor.name); this.ctx.customModelProperties.unregister(Model.MaxIndex.descriptor.name); this.ctx.customStructureProperties.unregister(Structure.Index.descriptor.name); + this.ctx.customStructureProperties.unregister(Structure.MaxIndex.descriptor.name); } } }); \ No newline at end of file diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts index 2415d421bb860482d00cf6353efcd78e19a3c6bb..84af7dad2d2a34f23cfcb4f270fc068dda79f949 100644 --- a/src/mol-theme/color.ts +++ b/src/mol-theme/color.ts @@ -39,6 +39,7 @@ import { Texture, TextureFilter } from '../mol-gl/webgl/texture'; import { VolumeValueColorThemeProvider } from './color/volume-value'; import { Vec3, Vec4 } from '../mol-math/linear-algebra'; import { ModelIndexColorThemeProvider } from './color/model-index'; +import { StructureIndexColorThemeProvider } from './color/structure-index'; export type LocationColor = (location: Location, isSecondary: boolean) => Color @@ -145,6 +146,7 @@ namespace ColorTheme { 'secondary-structure': SecondaryStructureColorThemeProvider, 'sequence-id': SequenceIdColorThemeProvider, 'shape-group': ShapeGroupColorThemeProvider, + 'structure-index': StructureIndexColorThemeProvider, 'trajectory-index': TrajectoryIndexColorThemeProvider, 'uncertainty': UncertaintyColorThemeProvider, 'unit-index': UnitIndexColorThemeProvider, diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts index db1589b3559fed8c1d91584fd784075ad0de9580..a466848df48e6d5b9b41e5ffc1d4a6e30954eed2 100644 --- a/src/mol-theme/color/element-symbol.ts +++ b/src/mol-theme/color/element-symbol.ts @@ -20,6 +20,7 @@ import { EntityIdColorTheme, EntityIdColorThemeParams } from './entity-id'; import { assertUnreachable } from '../../mol-util/type-helpers'; import { EntitySourceColorTheme, EntitySourceColorThemeParams } from './entity-source'; import { ModelIndexColorTheme, ModelIndexColorThemeParams } from './model-index'; +import { StructureIndexColorTheme, StructureIndexColorThemeParams } from './structure-index'; // from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF) export const ElementSymbolColors = ColorMap({ @@ -37,6 +38,7 @@ export const ElementSymbolColorThemeParams = { 'entity-source': PD.Group(EntitySourceColorThemeParams), 'operator-name': PD.Group(OperatorNameColorThemeParams), 'model-index': PD.Group(ModelIndexColorThemeParams), + 'structure-index': PD.Group(StructureIndexColorThemeParams), 'element-symbol': PD.EmptyGroup() }, { description: 'Use chain-id coloring for carbon atoms.' }), saturation: PD.Numeric(0, { min: -6, max: 6, step: 0.1 }), @@ -66,8 +68,9 @@ export function ElementSymbolColorTheme(ctx: ThemeDataContext, props: PD.Values< pcc.name === 'entity-source' ? EntitySourceColorTheme(ctx, pcc.params).color : pcc.name === 'operator-name' ? OperatorNameColorTheme(ctx, pcc.params).color : pcc.name === 'model-index' ? ModelIndexColorTheme(ctx, pcc.params).color : - pcc.name === 'element-symbol' ? undefined : - assertUnreachable(pcc); + pcc.name === 'structure-index' ? StructureIndexColorTheme(ctx, pcc.params).color : + pcc.name === 'element-symbol' ? undefined : + assertUnreachable(pcc); function elementColor(element: ElementSymbol, location: Location) { return (carbonColor && element === 'C') diff --git a/src/mol-theme/color/illustrative.ts b/src/mol-theme/color/illustrative.ts index 89f21e2b5ace8749855ea68f37714bbbf809c3f7..18510ef68fdb85d0aa57c6d49ae08eefeae2009c 100644 --- a/src/mol-theme/color/illustrative.ts +++ b/src/mol-theme/color/illustrative.ts @@ -18,6 +18,7 @@ import { EntityIdColorTheme, EntityIdColorThemeParams } from './entity-id'; import { MoleculeTypeColorTheme, MoleculeTypeColorThemeParams } from './molecule-type'; import { EntitySourceColorTheme, EntitySourceColorThemeParams } from './entity-source'; import { ModelIndexColorTheme, ModelIndexColorThemeParams } from './model-index'; +import { StructureIndexColorTheme, StructureIndexColorThemeParams } from './structure-index'; const DefaultIllustrativeColor = Color(0xEEEEEE); const Description = `Assigns an illustrative color that gives every chain a color based on the chosen style but with lighter carbons (inspired by David Goodsell's Molecule of the Month style).`; @@ -30,6 +31,7 @@ export const IllustrativeColorThemeParams = { 'entity-source': PD.Group(EntitySourceColorThemeParams), 'molecule-type': PD.Group(MoleculeTypeColorThemeParams), 'model-index': PD.Group(ModelIndexColorThemeParams), + 'structure-index': PD.Group(StructureIndexColorThemeParams), }), carbonLightness: PD.Numeric(0.8, { min: -6, max: 6, step: 0.1 }) }; @@ -47,7 +49,8 @@ export function IllustrativeColorTheme(ctx: ThemeDataContext, props: PD.Values<I props.style.name === 'entity-source' ? EntitySourceColorTheme(ctx, props.style.params) : props.style.name === 'molecule-type' ? MoleculeTypeColorTheme(ctx, props.style.params) : props.style.name === 'model-index' ? ModelIndexColorTheme(ctx, props.style.params) : - assertUnreachable(props.style); + props.style.name === 'structure-index' ? StructureIndexColorTheme(ctx, props.style.params) : + assertUnreachable(props.style); function illustrativeColor(location: Location, typeSymbol: ElementSymbol) { const baseColor = styleColor(location, false); diff --git a/src/mol-theme/color/structure-index.ts b/src/mol-theme/color/structure-index.ts new file mode 100644 index 0000000000000000000000000000000000000000..28dda92802ae4db29fd67dc7f807fc3ec1988583 --- /dev/null +++ b/src/mol-theme/color/structure-index.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Color } from '../../mol-util/color'; +import { Location } from '../../mol-model/location'; +import { StructureElement, Bond, Structure } from '../../mol-model/structure'; +import { ColorTheme, LocationColor } from '../color'; +import { ParamDefinition as PD } from '../../mol-util/param-definition'; +import { ThemeDataContext } from '../../mol-theme/theme'; +import { getPaletteParams, getPalette } from '../../mol-util/color/palette'; +import { TableLegend, ScaleLegend } from '../../mol-util/legend'; + +const DefaultColor = Color(0xCCCCCC); +const Description = 'Gives every structure a unique color based on its index.'; + +export const StructureIndexColorThemeParams = { + ...getPaletteParams({ type: 'colors', colorList: 'many-distinct' }), +}; +export type StructureIndexColorThemeParams = typeof StructureIndexColorThemeParams +export function getStructureIndexColorThemeParams(ctx: ThemeDataContext) { + return PD.clone(StructureIndexColorThemeParams); +} + +export function StructureIndexColorTheme(ctx: ThemeDataContext, props: PD.Values<StructureIndexColorThemeParams>): ColorTheme<StructureIndexColorThemeParams> { + let color: LocationColor; + let legend: ScaleLegend | TableLegend | undefined; + + if (ctx.structure) { + const size = (Structure.MaxIndex.get(ctx.structure).value ?? -1) + 1; + + const palette = getPalette(size, props); + legend = palette.legend; + + color = (location: Location): Color => { + if (StructureElement.Location.is(location)) { + return palette.color(Structure.Index.get(location.structure).value || 0)!; + } else if (Bond.isLocation(location)) { + return palette.color(Structure.Index.get(location.aStructure).value || 0)!; + } + return DefaultColor; + }; + } else { + color = () => DefaultColor; + } + + return { + factory: StructureIndexColorTheme, + granularity: 'instance', + color, + props, + description: Description, + legend + }; +} + +export const StructureIndexColorThemeProvider: ColorTheme.Provider<StructureIndexColorThemeParams, 'structure-index'> = { + name: 'structure-index', + label: 'Structure Index', + category: ColorTheme.Category.Chain, + factory: StructureIndexColorTheme, + getParams: getStructureIndexColorThemeParams, + defaultValues: PD.getDefaultValues(StructureIndexColorThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.elementCount > 0 +}; \ No newline at end of file