Compare commits

...

37 Commits

Author SHA1 Message Date
Alexander Rose
d29bf2eec2 3.45.0 2024-02-03 10:02:48 -08:00
Alexander Rose
5db60c2882 changelog 2024-02-03 10:00:17 -08:00
Alexander Rose
737846e093 schema updates 2024-02-03 09:59:52 -08:00
Alexander Rose
2ad551bdc7 package updates 2024-02-03 09:52:14 -08:00
Alexander Rose
46fa581f07 Merge pull request #1036 from russellp17/master
Move most headless context deps to optional peer dependencies and remove `@types/jpeg-js`
2024-02-03 09:43:27 -08:00
Alexander Rose
17dbe4b60e make jpeg-js a dev and optional peer dependency 2024-02-03 09:35:20 -08:00
Russell Parker
aeaf2e799a update changelog 2024-01-30 11:18:08 -05:00
Russell Parker
ef16b718c4 Move most headless context deps to optional peer deps and remove @types/jpeg-js 2024-01-30 11:17:54 -05:00
Alexander Rose
ab4130d42d Merge pull request #1032 from molstar/interactive-snapshots
Interative labels & related changes
2024-01-29 22:52:05 -08:00
dsehnal
9e73de89fb changelog 2024-01-28 05:32:17 +01:00
dsehnal
02cec6f8e6 support multiline PD.text and use markdown to render multi-line tooltips 2024-01-28 05:26:46 +01:00
dsehnal
e97a02473f label snapshot key & tooltip support 2024-01-28 04:35:01 +01:00
Alexander Rose
22e5c9d65b Merge pull request #800 from giagitom/2-colors-cylinders
Implementing 2 colors interpolation on impostor cylinders
2024-01-15 09:06:15 -08:00
Alexander Rose
10d9120d37 hide colorMode for cartoon repr 2024-01-13 11:38:45 -08:00
Alexander Rose
e6c20d35bd Merge branch 'master' into 2-colors-cylinders 2024-01-13 10:19:54 -08:00
Alexander Rose
27bf66038d location-iterator tweaks
- consolidate BondIterator.fromGroup/.fromStructure
- use options argument in PolymerLocationIterator.fromGroup
- remove 'any' type
2024-01-13 10:16:28 -08:00
Alexander Rose
3ce6d89521 color-mode docs 2024-01-13 10:14:06 -08:00
Alexander Rose
24608ac355 stricter param types 2024-01-13 10:13:11 -08:00
Alexander Rose
da034d9502 move cylinder color mixing to vertex shader 2024-01-13 10:11:13 -08:00
Alexander Rose
581673fb9b Merge pull request #1022 from midlik/is-mvs-model-prop
check applicability of mvs repr/color 2
2024-01-10 22:11:37 -08:00
Adam Midlik
29cf97e6cf Revert package-lock.json 2024-01-10 11:04:07 +00:00
Adam Midlik
f65773d654 MVS extension: MolViewSpec components are applicable only when the model has been loaded from MolViewSpec 2024-01-09 11:50:57 +00:00
giagitom
d11c8c166a Fix 2024-01-07 19:55:06 +01:00
giagitom
ae6bd743a8 Fix nucleotide atomic bonds 2024-01-07 19:34:09 +01:00
giagitom
c1654574d0 Merge branch 'master' into 2-colors-cylinders 2024-01-07 19:09:36 +01:00
giagitom
6f506351cd Merge branch 'master' of https://github.com/molstar/molstar 2024-01-07 19:06:01 +01:00
giagitom
db83b97ff9 Use only when necessary 2024-01-07 18:41:06 +01:00
giagitom
302e1c659f Merge branch 'master' into 2-colors-cylinders 2023-12-26 16:43:09 +01:00
giagitom
8b4d987f94 Merge branch 'master' of https://github.com/molstar/molstar 2023-12-26 16:38:35 +01:00
giagitom
3fe80fe61a Merge branch 'master' of https://github.com/molstar/molstar 2023-12-22 00:24:16 +01:00
giagitom
3e6d0c8c62 Merge branch 'master' of https://github.com/molstar/molstar 2023-11-26 21:38:09 +01:00
giagitom
c6210ae1a0 Merge branch 'master' of https://github.com/molstar/molstar 2023-11-06 07:36:00 +01:00
giagitom
36cf2853b2 Merge branch 'master' of https://github.com/molstar/molstar 2023-10-22 15:15:38 +02:00
giagitom
70ebdc6b80 Merge branch 'fix-pdb-insCode-labelSeq' of https://github.com/molstar/molstar 2023-10-09 11:37:28 +02:00
giagitom
5934f355c2 Fixes and added changelog entry 2023-05-22 17:02:25 +02:00
giagitom
225d051dd6 Merge branch 'master' into 2-colors-cylinders 2023-05-22 16:50:59 +02:00
giagitom
c59ae908b8 Implement 2 colors interpolation on impostor cylinders 2023-04-26 15:24:15 +02:00
57 changed files with 1264 additions and 547 deletions

View File

@@ -6,6 +6,20 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased]
## [v3.45.0] - 2023-02-03
- Add color interpolation to impostor cylinders
- MolViewSpec components are applicable only when the model has been loaded from MolViewSpec
- Add `snapshotKey` and `tooltip` params to loci `LabelRepresentation`
- Update `FocusLoci` behavior to support `snapshotKey` param
- Clicking a visual with `snapshotKey` will trigger that snapshot
- Render multiline loci label tooltips as Markdown
- `ParamDefinition.Text` updates:
- Support `multiline` inputs
- Support `placeholder` parameter
- Support `disableInteractiveUpdates` to only trigger updates once the control loses focus
- Move dependencies related to the headless context from optional deps to optional peer deps
## [v3.44.0] - 2023-01-06
- Add new `cartoon` visuals to support atomic nucleotide base with sugar

953
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "3.44.0",
"version": "3.45.0",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -113,22 +113,21 @@
"@graphql-codegen/time": "^5.0.0",
"@graphql-codegen/typescript": "^4.0.1",
"@graphql-codegen/typescript-graphql-files-modules": "^3.0.0",
"@graphql-codegen/typescript-graphql-request": "^6.1.0",
"@graphql-codegen/typescript-graphql-request": "^6.2.0",
"@graphql-codegen/typescript-operations": "^4.0.1",
"@types/cors": "^2.8.17",
"@types/gl": "^6.0.5",
"@types/jpeg-js": "^0.3.7",
"@types/pngjs": "^6.0.4",
"@types/jest": "^29.5.11",
"@types/react": "^18.2.47",
"@types/jest": "^29.5.12",
"@types/react": "^18.2.52",
"@types/react-dom": "^18.2.18",
"@typescript-eslint/eslint-plugin": "^6.18.0",
"@typescript-eslint/parser": "^6.18.0",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"benchmark": "^2.1.4",
"concurrently": "^8.2.2",
"cpx2": "^6.0.1",
"crypto-browserify": "^3.12.0",
"css-loader": "^6.8.1",
"css-loader": "^6.10.0",
"eslint": "^8.56.0",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^6.2.0",
@@ -136,19 +135,20 @@
"graphql": "^16.8.1",
"http-server": "^14.1.1",
"jest": "^29.7.0",
"mini-css-extract-plugin": "^2.7.6",
"jpeg-js": "^0.4.4",
"mini-css-extract-plugin": "^2.8.0",
"path-browserify": "^1.0.1",
"raw-loader": "^4.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.69.7",
"sass-loader": "^13.3.3",
"sass": "^1.70.0",
"sass-loader": "^14.1.0",
"simple-git": "^3.22.0",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.3",
"ts-jest": "^29.1.1",
"style-loader": "^3.3.4",
"ts-jest": "^29.1.2",
"typescript": "^5.3.3",
"webpack": "^5.89.0",
"webpack": "^5.90.1",
"webpack-cli": "^5.1.4"
},
"dependencies": {
@@ -157,7 +157,7 @@
"@types/compression": "1.7.5",
"@types/express": "^4.17.21",
"@types/node": "^16.18.69",
"@types/node-fetch": "^2.6.10",
"@types/node-fetch": "^2.6.11",
"@types/swagger-ui-dist": "3.30.4",
"argparse": "^2.0.1",
"body-parser": "^1.20.2",
@@ -171,19 +171,31 @@
"node-fetch": "^2.7.0",
"react-markdown": "^9.0.1",
"rxjs": "^7.8.1",
"swagger-ui-dist": "^5.10.5",
"swagger-ui-dist": "^5.11.2",
"tslib": "^2.6.2",
"util.promisify": "^1.1.2",
"xhr2": "^0.2.1"
},
"peerDependencies": {
"react": "^18.1.0 || ^17.0.2 || ^16.14.0",
"react-dom": "^18.1.0 || ^17.0.2 || ^16.14.0"
},
"optionalDependencies": {
"canvas": "^2.11.2",
"gl": "^6.0.2",
"jpeg-js": "^0.4.4",
"pngjs": "^6.0.0"
"pngjs": "^6.0.0",
"react": "^18.1.0 || ^17.0.2 || ^16.14.0",
"react-dom": "^18.1.0 || ^17.0.2 || ^16.14.0"
},
"peerDependenciesMeta": {
"canvas": {
"optional": true
},
"gl": {
"optional": true
},
"jpeg-js": {
"optional": true
},
"pngjs": {
"optional": true
}
}
}

View File

@@ -158,8 +158,8 @@ async function ensureDicAvailable(dicPath: string, dicUrl: string) {
const DIC_DIR = path.resolve(__dirname, '../../../../build/dics/');
const MMCIF_DIC_PATH = `${DIC_DIR}/mmcif_pdbx_v50.dic`;
const MMCIF_DIC_URL = 'http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic';
const IHM_DIC_PATH = `${DIC_DIR}/ihm-extension.dic`;
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHM-dictionary/master/ihm-extension.dic';
const IHM_DIC_PATH = `${DIC_DIR}/mmcif_ihm_ext.dic`;
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHMCIF/master/dist/mmcif_ihm_ext.dic';
const MA_DIC_PATH = `${DIC_DIR}/ma-extension.dic`;
const MA_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/ModelCIF/master/dist/mmcif_ma.dic';

View File

@@ -164,7 +164,7 @@ const meshShapeProviderParams: Mesh.Params = {
quality: PD.Select<VisualQuality>('custom', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }), // use 'custom' when wanting to apply doubleSided
doubleSided: PD.Boolean(true, BaseGeometry.CustomQualityParamInfo),
// set `flatShaded`: true to see the real mesh vertices and triangles
transparentBackfaces: PD.Select('on', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory), // 'on' means: show backfaces with correct opacity, even when opacity < 1 (requires doubleSided) ¯\_(ツ)_/¯
transparentBackfaces: PD.Select('on', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory), // 'on' means: show backfaces with correct opacity, even when opacity < 1 (requires doubleSided) ¯\_(ツ)_/¯
};

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -22,6 +22,7 @@ import { MVSAnnotationTooltipsLabelProvider, MVSAnnotationTooltipsProvider } fro
import { CustomLabelRepresentationProvider } from './components/custom-label/representation';
import { CustomTooltipsLabelProvider, CustomTooltipsProvider } from './components/custom-tooltips-prop';
import { LoadMvsData, MVSJFormatProvider } from './components/formats';
import { IsMVSModelProvider } from './components/is-mvs-model-prop';
import { makeMultilayerColorThemeProvider } from './components/multilayer-color-theme';
import { loadMVS } from './load';
import { MVSData } from './mvs-data';
@@ -51,6 +52,7 @@ export const MolViewSpec = PluginBehavior.create<{ autoAttach: boolean }>({
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
private readonly registrables: Registrables = {
customModelProperties: [
IsMVSModelProvider,
MVSAnnotationsProvider,
],
customStructureProperties: [

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -12,6 +12,7 @@ import { ColorNames } from '../../../mol-util/color/names';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { decodeColor } from '../helpers/utils';
import { getMVSAnnotationForStructure } from './annotation-prop';
import { isMVSStructure } from './is-mvs-model-prop';
/** Parameter definition for color theme "MVS Annotation" */
@@ -76,5 +77,5 @@ export const MVSAnnotationColorThemeProvider: ColorTheme.Provider<MVSAnnotationC
factory: MVSAnnotationColorTheme,
getParams: ctx => MVSAnnotationColorThemeParams,
defaultValues: PD.getDefaultValues(MVSAnnotationColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => true,
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && isMVSStructure(ctx.structure),
};

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -9,6 +9,7 @@ import { Representation, RepresentationContext, RepresentationParamsGetter } fro
import { ComplexRepresentation, StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../../../../mol-repr/structure/representation';
import { MarkerAction } from '../../../../mol-util/marker-action';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { isMVSStructure } from '../is-mvs-model-prop';
import { MVSAnnotationLabelTextParams, MVSAnnotationLabelTextVisual } from './visual';
@@ -45,5 +46,5 @@ export const MVSAnnotationLabelRepresentationProvider = StructureRepresentationP
defaultValues: PD.getDefaultValues(MVSAnnotationLabelParams),
defaultColorTheme: { name: 'uniform' }, // this ain't workin
defaultSizeTheme: { name: 'physical' },
isApplicable: (structure: Structure) => structure.elementCount > 0,
isApplicable: (structure: Structure) => structure.elementCount > 0 && isMVSStructure(structure),
});

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -75,7 +75,7 @@ type MVSAnnotationData = { format: 'json', data: Jsonable } | { format: 'cif', d
/** Provider for custom model property "Annotations" */
export const MVSAnnotationsProvider: CustomModelProperty.Provider<MVSAnnotationsParams, MVSAnnotations> = CustomModelProperty.createProvider({
label: 'Annotations',
label: 'MVS Annotations',
descriptor: CustomPropertyDescriptor({
name: 'mvs-annotations',
}),

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -9,6 +9,7 @@ import { Representation, RepresentationContext, RepresentationParamsGetter } fro
import { ComplexRepresentation, StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../../../../mol-repr/structure/representation';
import { MarkerAction } from '../../../../mol-util/marker-action';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { isMVSStructure } from '../is-mvs-model-prop';
import { CustomLabelTextParams, CustomLabelTextVisual } from './visual';
@@ -38,12 +39,12 @@ export function CustomLabelRepresentation(ctx: RepresentationContext, getParams:
/** A thingy that is needed to register representation type "Custom Label", allowing user-defined labels at at user-defined positions */
export const CustomLabelRepresentationProvider = StructureRepresentationProvider({
name: 'mvs-custom-label',
label: 'Custom Label',
label: 'MVS Custom Label',
description: 'Displays labels with custom text',
factory: CustomLabelRepresentation,
getParams: () => CustomLabelParams,
defaultValues: PD.getDefaultValues(CustomLabelParams),
defaultColorTheme: { name: 'uniform' },
defaultSizeTheme: { name: 'physical' },
isApplicable: (structure: Structure) => structure.elementCount > 0
isApplicable: (structure: Structure) => structure.elementCount > 0 && isMVSStructure(structure),
});

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -36,7 +36,7 @@ export type CustomTooltipsData = { selector: Selector, text: string, elementSet?
/** Provider for custom structure property "CustomTooltips" */
export const CustomTooltipsProvider: CustomStructureProperty.Provider<CustomTooltipsParams, CustomTooltipsData> = CustomStructureProperty.createProvider({
label: 'Custom Tooltips',
label: 'MVS Custom Tooltips',
descriptor: CustomPropertyDescriptor<any, any>({
name: 'mvs-custom-tooltips',
}),

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
import { Model, Structure } from '../../../mol-model/structure';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
/** Parameter definition for custom model property "Is MVS" */
export type IsMVSModelParams = typeof IsMVSModelParams
export const IsMVSModelParams = {
isMvs: PD.Boolean(false, { description: 'Flag this model as managed by MolViewSpec and enable MolViewSpec features' }),
};
/** Parameter values for custom model property "Is MVS" */
export type IsMVSModelProps = PD.Values<IsMVSModelParams>
/** Provider for custom model property "Is MVS" */
export const IsMVSModelProvider: CustomModelProperty.Provider<IsMVSModelParams, {}> = CustomModelProperty.createProvider({
label: 'MVS',
descriptor: CustomPropertyDescriptor({
name: 'mvs-is-mvs-model',
}),
type: 'static',
defaultParams: IsMVSModelParams,
getParams: (data: Model) => IsMVSModelParams,
isApplicable: (data: Model) => true,
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<IsMVSModelProps>) => ({ value: {} }),
});
/** Decide if the model is flagged as managed by MolViewSpec */
export function isMVSModel(model: Model): boolean {
return !!IsMVSModelProvider.props(model)?.isMvs;
}
/** Decide if the structure is flagged as managed by MolViewSpec */
export function isMVSStructure(structure: Structure): boolean {
return structure.models.some(isMVSModel);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -12,6 +12,7 @@ import { Color } from '../../../mol-util/color';
import { ColorNames } from '../../../mol-util/color/names';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { stringToWords } from '../../../mol-util/string';
import { isMVSStructure } from './is-mvs-model-prop';
import { ElementSet, SelectorParams, isSelectorAll } from './selector';
@@ -137,11 +138,11 @@ export const MultilayerColorThemeName = 'mvs-multilayer';
export function makeMultilayerColorThemeProvider(colorThemeRegistry: ColorTheme.Registry): ColorTheme.Provider<MultilayerColorThemeParams, typeof MultilayerColorThemeName> {
return {
name: MultilayerColorThemeName,
label: 'Multi-layer',
label: 'MVS Multi-layer',
category: ColorTheme.Category.Misc,
factory: (ctx, props) => makeMultilayerColorTheme(ctx, props, colorThemeRegistry),
getParams: (ctx: ThemeDataContext) => makeMultilayerColorThemeParams(colorThemeRegistry, ctx),
defaultValues: DefaultMultilayerColorThemeProps,
isApplicable: (ctx: ThemeDataContext) => true,
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && isMVSStructure(ctx.structure),
};
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
@@ -16,6 +16,7 @@ import { MVSAnnotationStructureComponent } from './components/annotation-structu
import { MVSAnnotationTooltipsProvider } from './components/annotation-tooltips-prop';
import { CustomLabelProps, CustomLabelRepresentationProvider } from './components/custom-label/representation';
import { CustomTooltipsProvider } from './components/custom-tooltips-prop';
import { IsMVSModelProps, IsMVSModelProvider } from './components/is-mvs-model-prop';
import { AnnotationFromSourceKind, AnnotationFromUriKind, LoadingActions, UpdateTarget, collectAnnotationReferences, collectAnnotationTooltips, collectInlineLabels, collectInlineTooltips, colorThemeForNode, componentFromXProps, componentPropsFromSelector, isPhantomComponent, labelFromXProps, loadTree, makeNearestReprMap, prettyNameFromSelector, representationProps, structureProps, transformProps } from './load-helpers';
import { MVSData } from './mvs-data';
import { ParamsOfKind, SubTreeOfKind, validateTree } from './tree/generic/tree-schema';
@@ -119,10 +120,12 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
});
UpdateTarget.apply(model, CustomModelProperties, {
properties: {
[MVSAnnotationsProvider.descriptor.name]: { annotations }
[IsMVSModelProvider.descriptor.name]: { isMvs: true } satisfies IsMVSModelProps,
[MVSAnnotationsProvider.descriptor.name]: { annotations },
},
autoAttach: [
MVSAnnotationsProvider.descriptor.name
IsMVSModelProvider.descriptor.name,
MVSAnnotationsProvider.descriptor.name,
],
});
return model;

View File

@@ -6,7 +6,7 @@ export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?:
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
// Generated on 2023-12-02T13:19:10-08:00
// Generated on 2024-02-03T09:57:34-08:00
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
@@ -496,7 +496,9 @@ export type CoreAssembly = {
readonly pdbx_struct_oper_list?: Maybe<ReadonlyArray<Maybe<PdbxStructOperList>>>;
/** Get a list of polymer entity instances (chains) that constitute this assembly. */
readonly polymer_entity_instances?: Maybe<ReadonlyArray<Maybe<CorePolymerEntityInstance>>>;
readonly rcsb_assembly_annotation?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyAnnotation>>>;
readonly rcsb_assembly_container_identifiers: RcsbAssemblyContainerIdentifiers;
readonly rcsb_assembly_feature?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyFeature>>>;
readonly rcsb_assembly_info?: Maybe<RcsbAssemblyInfo>;
/**
* A unique identifier for each object in this assembly container formed by
@@ -1223,8 +1225,15 @@ export type DrugbankInfo = {
readonly description?: Maybe<Scalars['String']['output']>;
/** The DrugBank drug categories. */
readonly drug_categories?: Maybe<ReadonlyArray<Maybe<Scalars['String']['output']>>>;
/** The DrugBank drug drug groups. */
/**
* The DrugBank drug groups determine their drug development status.
*
* Allowable values:
* approved, experimental, illicit, investigational, nutraceutical, vet_approved, withdrawn
*
*/
readonly drug_groups?: Maybe<ReadonlyArray<Maybe<Scalars['String']['output']>>>;
readonly drug_products?: Maybe<ReadonlyArray<Maybe<DrugbankInfoDrugProducts>>>;
/** The DrugBank accession code */
readonly drugbank_id: Scalars['String']['output'];
/**
@@ -1257,6 +1266,57 @@ export type DrugbankInfo = {
readonly synonyms?: Maybe<ReadonlyArray<Maybe<Scalars['String']['output']>>>;
};
export type DrugbankInfoDrugProducts = {
/**
* Indicates whether this drug has been approved by the regulating government.
*
* Allowable values:
* N, Y
*
*/
readonly approved?: Maybe<Scalars['String']['output']>;
/**
* The country where this commercially available drug has been approved.
*
* Allowable values:
* Canada, EU, US
*
*/
readonly country?: Maybe<Scalars['String']['output']>;
/**
* The ending date for market approval.
*
* Examples:
* 2003-07-30
*
*/
readonly ended_marketing_on?: Maybe<Scalars['Date']['output']>;
/**
* The proprietary name(s) provided by the manufacturer for any commercially available products containing this drug.
*
* Examples:
* Hivid Tab 0.375mg
*
*/
readonly name?: Maybe<Scalars['String']['output']>;
/**
* Source of this product information. For example, a value of DPD indicates this information was retrieved from the Canadian Drug Product Database.
*
* Allowable values:
* DPD, EMA, FDA NDC
*
*/
readonly source?: Maybe<Scalars['String']['output']>;
/**
* The starting date for market approval.
*
* Examples:
* 1992-12-31
*
*/
readonly started_marketing_on?: Maybe<Scalars['Date']['output']>;
};
export type DrugbankTarget = {
/** The type of target interaction. */
readonly interaction_type?: Maybe<Scalars['String']['output']>;
@@ -6591,6 +6651,48 @@ export type RcsbAccessionInfo = {
readonly status_code?: Maybe<Scalars['String']['output']>;
};
export type RcsbAssemblyAnnotation = {
readonly additional_properties?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyAnnotationAdditionalProperties>>>;
/** An identifier for the annotation. */
readonly annotation_id?: Maybe<Scalars['String']['output']>;
/** Identifies the version of the annotation assignment. */
readonly assignment_version?: Maybe<Scalars['String']['output']>;
/** A description for the annotation. */
readonly description?: Maybe<Scalars['String']['output']>;
/** A name for the annotation. */
readonly name?: Maybe<Scalars['String']['output']>;
/**
* Code identifying the individual, organization or program that
* assigned the annotation.
*
* Examples:
* MCSA
*
*/
readonly provenance_source?: Maybe<Scalars['String']['output']>;
/**
* A type or category of the annotation.
*
* Allowable values:
* MCSA
*
*/
readonly type?: Maybe<Scalars['String']['output']>;
};
export type RcsbAssemblyAnnotationAdditionalProperties = {
/**
* The additional property name.
*
* Allowable values:
* MCSA_MOTIF_COMPATIBILITY
*
*/
readonly name?: Maybe<Scalars['String']['output']>;
/** The value(s) of the additional property. */
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['ObjectScalar']['output']>>>;
};
export type RcsbAssemblyContainerIdentifiers = {
/**
* Assembly identifier for the container.
@@ -6615,6 +6717,69 @@ export type RcsbAssemblyContainerIdentifiers = {
readonly rcsb_id?: Maybe<Scalars['String']['output']>;
};
export type RcsbAssemblyFeature = {
readonly additional_properties?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyFeatureAdditionalProperties>>>;
/** Identifies the version of the feature assignment. */
readonly assignment_version?: Maybe<Scalars['String']['output']>;
/** A description for the feature. */
readonly description?: Maybe<Scalars['String']['output']>;
/** An identifier for the feature. */
readonly feature_id?: Maybe<Scalars['String']['output']>;
/** This container groups together chain-level identifiers of the assigned features. */
readonly feature_positions?: Maybe<ReadonlyArray<Maybe<RcsbAssemblyFeatureFeaturePositions>>>;
/** A name for the feature. */
readonly name?: Maybe<Scalars['String']['output']>;
/**
* Code identifying the individual, organization or program that
* assigned the feature.
*
* Examples:
* MCSA
*
*/
readonly provenance_source?: Maybe<Scalars['String']['output']>;
/**
* A type or category of the feature.
*
* Allowable values:
* MCSA
*
*/
readonly type?: Maybe<Scalars['String']['output']>;
};
export type RcsbAssemblyFeatureAdditionalProperties = {
/**
* The additional property name.
*
* Allowable values:
* MCSA_MOTIF_COMPATIBILITY
*
*/
readonly name?: Maybe<Scalars['String']['output']>;
/** The value(s) of the additional property. */
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['ObjectScalar']['output']>>>;
};
export type RcsbAssemblyFeatureFeaturePositions = {
/**
* An identifier of polymer chain (label_asym_id) corresponding to the feature assignment.
*
* Examples:
* A, B
*
*/
readonly asym_id: Scalars['String']['output'];
/** An identifier for the monomer at which this segment of the feature begins. */
readonly beg_seq_id: Scalars['Int']['output'];
/** An identifier for the monomer at which this segment of the feature ends. */
readonly end_seq_id?: Maybe<Scalars['Int']['output']>;
/** Identifies the list of operations from the category pdbx_struct_oper_list. One item in array per operator applied. The order follows how operators are applied. */
readonly struct_oper_list: ReadonlyArray<Maybe<Scalars['String']['output']>>;
/** The value(s) of the feature over the monomer segment. */
readonly values?: Maybe<ReadonlyArray<Maybe<Scalars['Float']['output']>>>;
};
export type RcsbAssemblyInfo = {
/** Entity identifier for the container. */
readonly assembly_id?: Maybe<Scalars['String']['output']>;

View File

@@ -3,6 +3,7 @@
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { ValueCell } from '../../mol-util';
@@ -155,25 +156,29 @@ function createInstanceColor(locationIt: LocationIterator, color: LocationColor,
/** Creates color texture with color for each group (i.e. shared across instances) */
function createGroupColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
const { groupCount } = locationIt;
const colors = createTextureImage(Math.max(1, groupCount), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
const { groupCount, hasLocation2 } = locationIt;
const colors = createTextureImage(Math.max(1, groupCount * (hasLocation2 ? 2 : 1)), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
locationIt.reset();
const indexMultiplier = hasLocation2 ? 6 : 3;
while (locationIt.hasNext && !locationIt.isNextNewInstance) {
const { location, isSecondary, groupIndex } = locationIt.move();
Color.toArray(color(location, isSecondary), colors.array, groupIndex * 3);
const { location, location2, isSecondary, groupIndex } = locationIt.move();
Color.toArray(color(location, isSecondary), colors.array, groupIndex * indexMultiplier);
if (hasLocation2) Color.toArray(color(location2, isSecondary), colors.array, groupIndex * indexMultiplier + 3);
}
return createTextureColor(colors, 'group', colorData);
}
/** Creates color texture with color for each group in each instance */
function createGroupInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
const { groupCount, instanceCount } = locationIt;
const count = instanceCount * groupCount;
const { groupCount, instanceCount, hasLocation2 } = locationIt;
const count = instanceCount * groupCount * (hasLocation2 ? 2 : 1);
const colors = createTextureImage(Math.max(1, count), 3, Uint8Array, colorData && colorData.tColor.ref.value.array);
locationIt.reset();
const indexMultiplier = hasLocation2 ? 6 : 3;
while (locationIt.hasNext) {
const { location, isSecondary, index } = locationIt.move();
Color.toArray(color(location, isSecondary), colors.array, index * 3);
const { location, location2, isSecondary, index } = locationIt.move();
Color.toArray(color(location, isSecondary), colors.array, index * indexMultiplier);
if (hasLocation2) Color.toArray(color(location2, isSecondary), colors.array, index * indexMultiplier + 3);
}
return createTextureColor(colors, 'groupInstance', colorData);
}
@@ -258,4 +263,4 @@ function createDirectColor(colorData?: ColorData): ColorData {
dUsePalette: ValueCell.create(false),
};
}
}
}

View File

@@ -10,9 +10,15 @@ import { Cylinders } from './cylinders';
import { Vec3 } from '../../../mol-math/linear-algebra';
export interface CylindersBuilder {
add(startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number): void
addFixedCountDashes(start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, group: number): void
addFixedLengthDashes(start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number): void
/**
* @param colorMode - controls if and how theme colors are interpolated
* - for colorMode between 0 and 1 use colorMode to interpolate
* - for colorMode == 2 do nothing, i.e., use given theme color
* - for colorMode == 3 use position on cylinder axis to interpolate
*/
add(startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, colorMode: number, group: number): void
addFixedCountDashes(start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, interpolate: boolean, group: number): void
addFixedLengthDashes(start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, interpolate: boolean, group: number): void
getCylinders(): Cylinders
}
@@ -31,22 +37,25 @@ export namespace CylindersBuilder {
const ends = ChunkedArray.create(Float32Array, 3, chunkSize, cylinders ? cylinders.endBuffer.ref.value : initialCount);
const scales = ChunkedArray.create(Float32Array, 1, chunkSize, cylinders ? cylinders.scaleBuffer.ref.value : initialCount);
const caps = ChunkedArray.create(Float32Array, 1, chunkSize, cylinders ? cylinders.capBuffer.ref.value : initialCount);
const colorModes = ChunkedArray.create(Float32Array, 1, chunkSize, cylinders ? cylinders.colorModeBuffer.ref.value : initialCount);
const add = (startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number) => {
const add = (startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, radiusScale: number, topCap: boolean, bottomCap: boolean, colorMode: number, group: number) => {
for (let i = 0; i < 6; ++i) {
caAdd3(starts, startX, startY, startZ);
caAdd3(ends, endX, endY, endZ);
caAdd(groups, group);
caAdd(scales, radiusScale);
caAdd(caps, (topCap ? 1 : 0) + (bottomCap ? 2 : 0));
caAdd(colorModes, colorMode);
}
};
const addFixedCountDashes = (start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, group: number) => {
const addFixedCountDashes = (start: Vec3, end: Vec3, segmentCount: number, radiusScale: number, topCap: boolean, bottomCap: boolean, stubCap: boolean, interpolate: boolean, group: number) => {
const d = Vec3.distance(start, end);
const isOdd = segmentCount % 2 !== 0;
const s = Math.floor((segmentCount + 1) / 2);
const step = d / (segmentCount + 0.5);
let colorMode = 2.0;
Vec3.setMagnitude(tmpDir, Vec3.sub(tmpDir, end, start), step);
Vec3.copy(tmpVecA, start);
@@ -58,7 +67,10 @@ export namespace CylindersBuilder {
} else {
Vec3.add(tmpVecB, tmpVecA, tmpDir);
}
add(tmpVecA[0], tmpVecA[1], tmpVecA[2], tmpVecB[0], tmpVecB[1], tmpVecB[2], radiusScale, topCap, bottomCap, group);
if (interpolate) {
colorMode = Vec3.distance(start, tmpVecB) / (d * 2);
}
add(tmpVecA[0], tmpVecA[1], tmpVecA[2], tmpVecB[0], tmpVecB[1], tmpVecB[2], radiusScale, topCap, bottomCap, colorMode, group);
Vec3.add(tmpVecA, tmpVecA, tmpDir);
}
};
@@ -66,9 +78,9 @@ export namespace CylindersBuilder {
return {
add,
addFixedCountDashes,
addFixedLengthDashes: (start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, group: number) => {
addFixedLengthDashes: (start: Vec3, end: Vec3, segmentLength: number, radiusScale: number, topCap: boolean, bottomCap: boolean, interpolate: boolean, group: number) => {
const d = Vec3.distance(start, end);
addFixedCountDashes(start, end, d / segmentLength, radiusScale, topCap, bottomCap, true, group);
addFixedCountDashes(start, end, d / segmentLength, radiusScale, topCap, bottomCap, true, interpolate, group);
},
getCylinders: () => {
const cylinderCount = groups.elementCount / 6;
@@ -77,10 +89,11 @@ export namespace CylindersBuilder {
const eb = ChunkedArray.compact(ends, true) as Float32Array;
const ab = ChunkedArray.compact(scales, true) as Float32Array;
const cb = ChunkedArray.compact(caps, true) as Float32Array;
const cmb = ChunkedArray.compact(colorModes, true) as Float32Array;
const mb = cylinders && cylinderCount <= cylinders.cylinderCount ? cylinders.mappingBuffer.ref.value : new Float32Array(cylinderCount * 18);
const ib = cylinders && cylinderCount <= cylinders.cylinderCount ? cylinders.indexBuffer.ref.value : new Uint32Array(cylinderCount * 12);
if (!cylinders || cylinderCount > cylinders.cylinderCount) fillMappingAndIndices(cylinderCount, mb, ib);
return Cylinders.create(mb, ib, gb, sb, eb, ab, cb, cylinderCount, cylinders);
return Cylinders.create(mb, ib, gb, sb, eb, ab, cb, cmb, cylinderCount, cylinders);
}
};
}

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { ValueCell } from '../../../mol-util';
@@ -47,6 +48,13 @@ export interface Cylinders {
readonly scaleBuffer: ValueCell<Float32Array>,
/** Cylinder cap buffer as array of cap flags wrapped in a value cell */
readonly capBuffer: ValueCell<Float32Array>,
/**
* Cylinder colorMode buffer as array of coloring modes flags wrapped in a value cell
* - for colorMode between 0 and 1 use colorMode to interpolate
* - for colorMode == 2 do nothing, i.e., use given theme color
* - for colorMode == 3 use position on cylinder axis to interpolate
*/
readonly colorModeBuffer: ValueCell<Float32Array>,
/** Bounding sphere of the cylinders */
readonly boundingSphere: Sphere3D
@@ -57,10 +65,10 @@ export interface Cylinders {
}
export namespace Cylinders {
export function create(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, cylinderCount: number, cylinders?: Cylinders): Cylinders {
export function create(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, colorModes: Float32Array, cylinderCount: number, cylinders?: Cylinders): Cylinders {
return cylinders ?
update(mappings, indices, groups, starts, ends, scales, caps, cylinderCount, cylinders) :
fromArrays(mappings, indices, groups, starts, ends, scales, caps, cylinderCount);
update(mappings, indices, groups, starts, ends, scales, caps, colorModes, cylinderCount, cylinders) :
fromArrays(mappings, indices, groups, starts, ends, scales, caps, colorModes, cylinderCount);
}
export function createEmpty(cylinders?: Cylinders): Cylinders {
@@ -71,17 +79,18 @@ export namespace Cylinders {
const eb = cylinders ? cylinders.endBuffer.ref.value : new Float32Array(0);
const ab = cylinders ? cylinders.scaleBuffer.ref.value : new Float32Array(0);
const cb = cylinders ? cylinders.capBuffer.ref.value : new Float32Array(0);
return create(mb, ib, gb, sb, eb, ab, cb, 0, cylinders);
const cmb = cylinders ? cylinders.colorModeBuffer.ref.value : new Float32Array(0);
return create(mb, ib, gb, sb, eb, ab, cb, cmb, 0, cylinders);
}
function hashCode(cylinders: Cylinders) {
return hashFnv32a([
cylinders.cylinderCount, cylinders.mappingBuffer.ref.version, cylinders.indexBuffer.ref.version,
cylinders.groupBuffer.ref.version, cylinders.startBuffer.ref.version, cylinders.endBuffer.ref.version, cylinders.scaleBuffer.ref.version, cylinders.capBuffer.ref.version
cylinders.groupBuffer.ref.version, cylinders.startBuffer.ref.version, cylinders.endBuffer.ref.version, cylinders.scaleBuffer.ref.version, cylinders.capBuffer.ref.version, cylinders.colorModeBuffer.ref.version
]);
}
function fromArrays(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, cylinderCount: number): Cylinders {
function fromArrays(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, colorModes: Float32Array, cylinderCount: number): Cylinders {
const boundingSphere = Sphere3D();
let groupMapping: GroupMapping;
@@ -99,6 +108,7 @@ export namespace Cylinders {
endBuffer: ValueCell.create(ends),
scaleBuffer: ValueCell.create(scales),
capBuffer: ValueCell.create(caps),
colorModeBuffer: ValueCell.create(colorModes),
get boundingSphere() {
const newHash = hashCode(cylinders);
if (newHash !== currentHash) {
@@ -125,7 +135,7 @@ export namespace Cylinders {
return cylinders;
}
function update(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, cylinderCount: number, cylinders: Cylinders) {
function update(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, scales: Float32Array, caps: Float32Array, colorModes: Float32Array, cylinderCount: number, cylinders: Cylinders) {
if (cylinderCount > cylinders.cylinderCount) {
ValueCell.update(cylinders.mappingBuffer, mappings);
ValueCell.update(cylinders.indexBuffer, indices);
@@ -136,6 +146,7 @@ export namespace Cylinders {
ValueCell.update(cylinders.endBuffer, ends);
ValueCell.update(cylinders.scaleBuffer, scales);
ValueCell.update(cylinders.capBuffer, caps);
ValueCell.update(cylinders.colorModeBuffer, colorModes);
return cylinders;
}
@@ -157,10 +168,11 @@ export namespace Cylinders {
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
solidInterior: PD.Boolean(true, BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), BaseGeometry.ShadingCategory)
};
export type Params = typeof Params
@@ -215,7 +227,6 @@ export namespace Cylinders {
const padding = getMaxSize(size) * props.sizeFactor;
const invariantBoundingSphere = Sphere3D.clone(cylinders.boundingSphere);
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount, 0);
return {
dGeometryType: ValueCell.create('cylinders'),
@@ -225,6 +236,7 @@ export namespace Cylinders {
aEnd: cylinders.endBuffer,
aScale: cylinders.scaleBuffer,
aCap: cylinders.capBuffer,
aColorMode: cylinders.colorModeBuffer,
elements: cylinders.indexBuffer,
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
@@ -249,6 +261,7 @@ export namespace Cylinders {
dSolidInterior: ValueCell.create(props.solidInterior),
uBumpFrequency: ValueCell.create(props.bumpFrequency),
uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
dDualColor: ValueCell.create(props.colorMode === 'interpolate'),
};
}
@@ -268,6 +281,7 @@ export namespace Cylinders {
ValueCell.updateIfChanged(values.dSolidInterior, props.solidInterior);
ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
ValueCell.updateIfChanged(values.dDualColor, props.colorMode === 'interpolate');
}
function updateBoundingSphere(values: CylindersValues, cylinders: Cylinders) {
@@ -294,4 +308,4 @@ export namespace Cylinders {
state.opaque = state.opaque && !props.xrayShaded;
state.writeDepth = state.opaque;
}
}
}

View File

@@ -628,7 +628,7 @@ export namespace Mesh {
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
};

View File

@@ -148,7 +148,7 @@ export namespace Spheres {
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
solidInterior: PD.Boolean(true, BaseGeometry.ShadingCategory),
clipPrimitive: PD.Boolean(false, { ...BaseGeometry.ShadingCategory, description: 'Clip whole sphere instead of cutting it.' }),
approximate: PD.Boolean(false, { ...BaseGeometry.ShadingCategory, description: 'Faster rendering, but has artifacts.' }),

View File

@@ -120,7 +120,7 @@ export namespace TextureMesh {
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque'] as const), BaseGeometry.ShadingCategory),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
};

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { Iterator } from '../../mol-data';
@@ -10,6 +11,7 @@ import { NullLocation, Location } from '../../mol-model/location';
export interface LocationValue {
location: Location
location2: Location
index: number
groupIndex: number
instanceIndex: number
@@ -24,6 +26,7 @@ export interface LocationIterator extends Iterator<LocationValue> {
readonly count: number
readonly stride: number
readonly nonInstanceable: boolean
readonly hasLocation2: boolean
move(): LocationValue
reset(): void
skipInstance(): void
@@ -33,13 +36,14 @@ export interface LocationIterator extends Iterator<LocationValue> {
type LocationGetter = (groupIndex: number, instanceIndex: number) => Location
type IsSecondaryGetter = (groupIndex: number, instanceIndex: number) => boolean
export function LocationIterator(groupCount: number, instanceCount: number, stride: number, getLocation: LocationGetter, nonInstanceable = false, isSecondary: IsSecondaryGetter = () => false): LocationIterator {
export function LocationIterator(groupCount: number, instanceCount: number, stride: number, getLocation: LocationGetter, nonInstanceable = false, isSecondary: IsSecondaryGetter = () => false, getLocation2?: LocationGetter): LocationIterator {
if (groupCount % stride !== 0) {
throw new Error('incompatible groupCount and stride');
}
const value: LocationValue = {
location: NullLocation as Location,
location2: NullLocation as Location,
index: 0,
groupIndex: 0,
instanceIndex: 0,
@@ -52,6 +56,8 @@ export function LocationIterator(groupCount: number, instanceCount: number, stri
let instanceIndex = 0;
let voidInstances = false;
const hasLocation2 = !!getLocation2;
return {
get hasNext() { return hasNext; },
get isNextNewInstance() { return isNextNewInstance; },
@@ -60,12 +66,14 @@ export function LocationIterator(groupCount: number, instanceCount: number, stri
count: groupCount * instanceCount,
stride,
nonInstanceable,
hasLocation2,
move() {
if (hasNext) {
value.groupIndex = groupIndex;
value.instanceIndex = instanceIndex;
value.index = instanceIndex * groupCount + groupIndex;
value.location = getLocation(groupIndex, voidInstances ? -1 : instanceIndex);
if (hasLocation2) value.location2 = getLocation2(groupIndex, voidInstances ? -1 : instanceIndex);
value.isSecondary = isSecondary(groupIndex, voidInstances ? -1 : instanceIndex);
groupIndex += stride;
if (groupIndex === groupCount) {
@@ -81,6 +89,7 @@ export function LocationIterator(groupCount: number, instanceCount: number, stri
},
reset() {
value.location = NullLocation;
value.location2 = NullLocation;
value.index = 0;
value.groupIndex = 0;
value.instanceIndex = 0;

View File

@@ -20,6 +20,7 @@ export const CylindersSchema = {
aMapping: AttributeSpec('float32', 3, 0),
aScale: AttributeSpec('float32', 1, 0),
aCap: AttributeSpec('float32', 1, 0),
aColorMode: AttributeSpec('float32', 1, 0),
elements: ElementsSpec('uint32'),
padding: ValueSpec('number'),
@@ -30,6 +31,7 @@ export const CylindersSchema = {
dSolidInterior: DefineSpec('boolean'),
uBumpFrequency: UniformSpec('f', 'material'),
uBumpAmplitude: UniformSpec('f', 'material'),
dDualColor: DefineSpec('boolean'),
};
export type CylindersSchema = typeof CylindersSchema
export type CylindersValues = Values<CylindersSchema>

View File

@@ -5,9 +5,29 @@ export const assign_color_varying = `
#elif defined(dColorType_instance)
vColor.rgb = readFromTexture(tColor, aInstance, uColorTexDim).rgb;
#elif defined(dColorType_group)
vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
#if defined(dDualColor)
vec4 color2;
if (aColorMode == 2.0) {
vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
} else {
vColor.rgb = readFromTexture(tColor, group * 2.0, uColorTexDim).rgb;
color2.rgb = readFromTexture(tColor, group * 2.0 + 1.0, uColorTexDim).rgb;
}
#else
vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
#endif
#elif defined(dColorType_groupInstance)
vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
#if defined(dDualColor)
vec4 color2;
if (aColorMode == 2.0) {
vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
} else {
vColor.rgb = readFromTexture(tColor, (aInstance * float(uGroupCount) + group) * 2.0, uColorTexDim).rgb;
color2.rgb = readFromTexture(tColor, (aInstance * float(uGroupCount) + group) * 2.0 + 1.0, uColorTexDim).rgb;
}
#else
vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
#endif
#elif defined(dColorType_vertex)
vColor.rgb = readFromTexture(tColor, VertexID, uColorTexDim).rgb;
#elif defined(dColorType_vertexInstance)
@@ -90,4 +110,4 @@ export const assign_color_varying = `
#endif
vTransparency *= uTransparencyStrength;
#endif
`;
`;

View File

@@ -121,4 +121,4 @@ export const assign_material_color = `
#endif
#endif
#endif
`;
`;

View File

@@ -49,4 +49,4 @@ uniform float uBumpiness;
#ifdef dTransparency
varying float vTransparency;
#endif
`;
`;

View File

@@ -90,4 +90,4 @@ uniform float uBumpiness;
#endif
uniform float uTransparencyStrength;
#endif
`;
`;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -26,6 +26,7 @@ attribute vec3 aStart;
attribute vec3 aEnd;
attribute float aScale;
attribute float aCap;
attribute float aColorMode;
varying mat4 vTransform;
varying vec3 vStart;
@@ -54,9 +55,11 @@ void main() {
vModelPosition = (vStart + vEnd) * 0.5;
vec3 camDir = -mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
vec3 dir = vEnd - vStart;
float f = aMapping.x > 0.0 ? 1.0 : 0.0;
// ensure cylinder 'dir' is pointing towards the camera
if(dot(camDir, dir) < 0.0) {
dir = -dir;
f = 1.0 - f;
}
vec3 left = cross(camDir, dir);
@@ -76,6 +79,18 @@ void main() {
gl_Position.z = (uProjection * mvPosition).z;
}
#if defined(dDualColor) && defined(dRenderVariant_color) && (defined(dColorType_group) || defined(dColorType_groupInstance))
// dual-color mixing
// - for aColorMode between 0 and 1 use aColorMode to interpolate
// - for aColorMode == 2 do nothing, i.e., use vColor
// - for aColorMode == 3 use position on cylinder axis to interpolate
if (aColorMode <= 1.0){
vColor.rgb = mix(vColor.rgb, color2.rgb, aColorMode);
} else if (aColorMode == 3.0) {
vColor.rgb = mix(vColor.rgb, color2.rgb, mix(-0.25, 1.25, f / 1.5));
}
#endif
#include clip_instance
}
`;
`;

View File

@@ -1,7 +1,7 @@
/**
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.382, IHM 1.24, MA 1.4.5.
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.386, IHM 1.25, MA 1.4.6.
*
* @author molstar/ciftools package
*/

View File

@@ -1,7 +1,7 @@
/**
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.382, IHM 1.24, MA 1.4.5.
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.386, IHM 1.25, MA 1.4.6.
*
* @author molstar/ciftools package
*/

View File

@@ -1,7 +1,7 @@
/**
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.382, IHM 1.24, MA 1.4.5.
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.386, IHM 1.25, MA 1.4.6.
*
* @author molstar/ciftools package
*/
@@ -1966,7 +1966,7 @@ export const mmCIF_Schema = {
/**
* The identifying content type of the related entry.
*/
content_type: Aliased<'minimized average structure' | 'representative structure' | 'ensemble' | 'derivative structure' | 'native structure' | 'associated EM volume' | 'other EM volume' | 'associated NMR restraints' | 'associated structure factors' | 'associated SAS data' | 'protein target sequence and/or protocol data' | 'split' | 're-refinement' | 'complete structure' | 'unspecified' | 'other'>(str),
content_type: Aliased<'minimized average structure' | 'representative structure' | 'ensemble' | 'derivative structure' | 'native structure' | 'associated EM volume' | 'other EM volume' | 'focused EM volume' | 'consensus EM volume' | 'associated NMR restraints' | 'associated structure factors' | 'associated SAS data' | 'protein target sequence and/or protocol data' | 'split' | 're-refinement' | 'complete structure' | 'unspecified' | 'other'>(str),
},
/**
* The PDBX_ENTITY_NONPOLY category provides a mapping between

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2024 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>
@@ -43,6 +43,7 @@ import { PlaneParams, PlaneRepresentation } from '../../mol-repr/shape/loci/plan
import { Substance } from '../../mol-theme/substance';
import { Material } from '../../mol-util/material';
import { lerp } from '../../mol-math/interpolate';
import { MarkerAction, MarkerActions } from '../../mol-util/marker-action';
export { StructureRepresentation3D };
export { ExplodeStructureRepresentation3D };
@@ -1143,6 +1144,11 @@ const StructureSelectionsLabel3D = PluginStateTransform.BuiltIn({
const data = getLabelDataFromStructureSelections(a.data);
const repr = LabelRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => LabelParams);
await repr.createOrUpdate(params, data).runInContext(ctx);
// Support interactivity when needed
const pickable = !!(params.snapshotKey?.trim() || params.tooltip?.trim());
repr.setState({ pickable, markerActions: pickable ? MarkerActions.Highlighting : MarkerAction.None });
return new SO.Shape.Representation3D({ repr, sourceData: data }, { label: `Label` });
});
},
@@ -1152,6 +1158,11 @@ const StructureSelectionsLabel3D = PluginStateTransform.BuiltIn({
const data = getLabelDataFromStructureSelections(a.data);
await b.data.repr.createOrUpdate(props, data).runInContext(ctx);
b.data.sourceData = data;
// Update interactivity
const pickable = !!(newParams.snapshotKey?.trim() || newParams.tooltip?.trim());
b.data.repr.setState({ pickable, markerActions: pickable ? MarkerActions.Highlighting : MarkerAction.None });
return StateTransformer.UpdateResult.Updated;
});
},

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2024 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>
@@ -286,7 +286,7 @@ export class SelectionViewportControls extends PluginUIComponent {
}
export class LociLabels extends PluginUIComponent<{}, { labels: ReadonlyArray<LociLabel> }> {
state = { labels: [] };
state = { labels: [] as string[] };
componentDidMount() {
this.subscribe(this.plugin.behaviors.labels.highlight, e => this.setState({ labels: e.labels }));
@@ -298,7 +298,15 @@ export class LociLabels extends PluginUIComponent<{}, { labels: ReadonlyArray<Lo
}
return <div className='msp-highlight-info'>
{this.state.labels.map((e, i) => <div key={'' + i} dangerouslySetInnerHTML={{ __html: e }} />)}
{this.state.labels.map((e, i) => {
if (e.indexOf('\n') > 0) {
return <div className='msp-highlight-markdown-row' key={'' + i}>
<Markdown skipHtml>{e}</Markdown>
</div>;
}
return <div className='msp-highlight-simple-row' key={'' + i} dangerouslySetInnerHTML={{ __html: e }} />;
})}
</div>;
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2024 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>
@@ -244,6 +244,7 @@ function renderSimple(options: { props: ParamProps<any>, state: { showHelp: bool
const _className = [];
if (props.param.shortLabel) _className.push('msp-control-label-short');
if (props.param.twoColumns) _className.push('msp-control-col-2');
if (props.param.multiline) _className.push('msp-control-twoline');
const className = _className.join(' ');
const label = props.param.label || camelCaseToWords(props.name);
@@ -403,32 +404,71 @@ export class NumberRangeControl extends SimpleParam<PD.Numeric> {
}
export class TextControl extends SimpleParam<PD.Text> {
onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
updateValue = (value: string) => {
if (value !== this.props.value) {
this.update(value);
}
};
onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
if ((e.keyCode === 13 || e.charCode === 13 || e.key === 'Enter')) {
if (this.props.onEnter) this.props.onEnter();
}
e.stopPropagation();
};
renderControl() {
const placeholder = this.props.param.label || camelCaseToWords(this.props.name);
return <input type='text'
value={this.props.value || ''}
placeholder={placeholder}
onChange={this.onChange}
onKeyPress={this.props.onEnter ? this.onKeyPress : void 0}
disabled={this.props.isDisabled}
/>;
const placeholder = this.props.param.placeholder || this.props.param.label || camelCaseToWords(this.props.name);
return <TextCtrl props={this.props} placeholder={placeholder} update={this.updateValue} />;
}
}
function TextCtrl({ props, placeholder, update }: { props: ParamProps<PD.Text>, placeholder: string, update: (v: string) => any }) {
const [value, setValue] = React.useState(props.value);
React.useEffect(() => setValue(props.value), [props.value]);
if (props.param.multiline) {
return <div className='msp-control-text-area-wrapper'>
<textarea
value={props.param.disableInteractiveUpdates ? (value || '') : props.value}
placeholder={placeholder}
onChange={e => {
if (props.param.disableInteractiveUpdates) setValue(e.target.value);
else update(e.target.value);
}}
onBlur={e => {
if (props.param.disableInteractiveUpdates) update(e.target.value);
}}
onKeyDown={e => {
if (e.key === 'Enter' && (e.shiftKey || e.ctrlKey || e.metaKey)) {
e.currentTarget.blur();
}
}}
disabled={props.isDisabled}
/>
</div>;
}
return <input
type='text'
value={props.param.disableInteractiveUpdates ? (value || '') : props.value}
placeholder={placeholder}
onChange={e => {
if (props.param.disableInteractiveUpdates) setValue(e.target.value);
else update(e.target.value);
}}
onBlur={e => {
if (props.param.disableInteractiveUpdates) update(e.target.value);
}}
disabled={props.isDisabled}
onKeyDown={e => {
if (e.key !== 'Enter') return;
if (props.onEnter) {
e.stopPropagation();
props.onEnter();
} else if (e.key === 'Enter' && (e.shiftKey || e.ctrlKey || e.metaKey)) {
e.currentTarget.blur();
} else if (props.param.disableInteractiveUpdates) {
update(value);
}
}}
/>;
}
export class PureSelectControl extends React.PureComponent<ParamProps<PD.Select<string | number>> & { title?: string }> {
protected update(value: string | number) {
this.props.onChange({ param: this.props.param, name: this.props.name, value });

View File

@@ -71,6 +71,10 @@
width: 50%;
}
.msp-control-twoline {
height: 2 * $row-height !important;
}
.msp-control-group {
position: relative;
}
@@ -418,9 +422,8 @@
}
}
.msp-text-area-wrapper {
.msp-control-text-area-wrapper, .msp-text-area-wrapper {
position: relative;
height: 3 * $row-height !important;
textarea {
border: none;
width: 100%;
@@ -431,4 +434,12 @@
font-size: 12px;
line-height: 16px;
}
}
}
.msp-control-text-area-wrapper {
height: 2 * $row-height !important;
}
.msp-text-area-wrapper {
height: 3 * $row-height !important;
}

View File

@@ -142,13 +142,19 @@
padding: $info-vertical-padding $control-spacing;
background: $default-background; //$highlight-info-background;
opacity: 90%;
// min-height: $row-height;
text-align: right;
max-width: 400px;
@include non-selectable;
}
.msp-highlight-markdown-row {
padding-left: $control-spacing;
}
.msp-highlight-simple-row {
text-align: right;
}
.msp-highlight-info-hr {
margin-inline: 0px;
margin-block: 3px;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2024 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>
@@ -264,12 +264,20 @@ export const FocusLoci = PluginBehavior.create<FocusLociProps>({
this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, button, modifiers }) => {
const { clickFocus, clickFocusAdd, clickFocusSelectMode, clickFocusAddSelectMode } = this.params.bindings;
const binding = this.ctx.selectionMode ? clickFocusSelectMode : clickFocus;
const matched = Binding.match(binding, button, modifiers);
// Support snapshot key property, in which case ignore the focus functionality
const snapshotKey = current.repr?.props?.snapshotKey?.trim() ?? '';
if (!this.ctx.selectionMode && matched && snapshotKey) {
this.ctx.managers.snapshot.applyKey(snapshotKey);
return;
}
// only apply structure focus for appropriate granularity
const { granularity } = this.ctx.managers.interactivity.props;
if (granularity !== 'residue' && granularity !== 'element') return;
const binding = this.ctx.selectionMode ? clickFocusSelectMode : clickFocus;
const matched = Binding.match(binding, button, modifiers);
const bindingAdd = this.ctx.selectionMode ? clickFocusAddSelectMode : clickFocusAdd;
const matchedAdd = Binding.match(bindingAdd, button, modifiers);
if (!matched && !matchedAdd) return;

View File

@@ -1,7 +1,8 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-24 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Loci } from '../../../mol-model/loci';
@@ -26,13 +27,15 @@ const TextParams = {
type TextParams = typeof TextParams
const LabelVisuals = {
'text': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<LabelData, TextParams>) => ShapeRepresentation(getTextShape, Text.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
'text': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<LabelData, TextParams>) => ShapeRepresentation(getTextShape, Text.Utils),
};
export const LabelParams = {
...TextParams,
scaleByRadius: PD.Boolean(true),
visuals: PD.MultiSelect(['text'], PD.objectToOptions(LabelVisuals)),
snapshotKey: PD.Text('', { isEssential: true, disableInteractiveUpdates: true, description: 'Activate the snapshot with the provided key when clicking on the label' }),
tooltip: PD.Text('', { isEssential: true, multiline: true, disableInteractiveUpdates: true, placeholder: 'Tooltip', description: 'Tooltip text to be displayed when hovering over the label' }),
};
export type LabelParams = typeof LabelParams
@@ -69,13 +72,18 @@ function buildText(data: LabelData, props: LabelProps, text?: Text): Text {
function getTextShape(ctx: RuntimeContext, data: LabelData, props: LabelProps, shape?: Shape<Text>) {
const text = buildText(data, props, shape && shape.geometry);
const name = getLabelName(data);
const tooltip = props.tooltip?.trim() ?? '';
const customLabel = props.customText.trim();
const getLabel = customLabel
? function (groupId: number) {
return customLabel;
} : function (groupId: number) {
return label(data.infos[groupId]);
};
let getLabel: (groupId: number) => any;
if (tooltip) {
getLabel = (_: number) => tooltip;
} else if (customLabel) {
getLabel = (_: number) => customLabel;
} else {
getLabel = (groupId: number) => label(data.infos[groupId]);
}
return Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel);
}

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
@@ -52,7 +53,7 @@ function createComplexRenderObject<G extends Geometry>(structure: Structure, geo
interface ComplexVisualBuilder<P extends StructureParams, G extends Geometry> {
defaultProps: PD.Values<P>
createGeometry(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<P>, geometry?: G): Promise<G> | G
createLocationIterator(structure: Structure): LocationIterator
createLocationIterator(structure: Structure, props: PD.Values<P>): LocationIterator
getLoci(pickingId: PickingId, structure: Structure, id: number): Loci
eachLocation(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean, isMarking: boolean): boolean,
setUpdateState(state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure): void
@@ -143,7 +144,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
function update(newGeometry?: G) {
if (updateState.createNew) {
locationIt = createLocationIterator(newStructure);
locationIt = createLocationIterator(newStructure, newProps);
if (newGeometry) {
renderObject = createComplexRenderObject(newStructure, newGeometry, locationIt, newTheme, newProps, materialId);
positionIt = createPositionIterator(newGeometry, renderObject.values);
@@ -157,7 +158,7 @@ export function ComplexVisual<G extends Geometry, P extends StructureParams & Ge
if (updateState.updateTransform) {
// console.log('update transform')
locationIt = createLocationIterator(newStructure);
locationIt = createLocationIterator(newStructure, newProps);
const { instanceCount, groupCount } = locationIt;
if (newProps.instanceGranularity) {
createMarkers(instanceCount, 'instance', renderObject.values);

View File

@@ -28,6 +28,7 @@ export const BackboneParams = {
sizeAspectRatio: PD.Numeric(1, { min: 0.1, max: 3, step: 0.1 }),
visuals: PD.MultiSelect(['polymer-backbone-cylinder', 'polymer-backbone-sphere', 'polymer-gap'], PD.objectToOptions(BackboneVisuals)),
bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), { ...BaseGeometry.ShadingCategory, isHidden: true }),
};
export type BackboneParams = typeof BackboneParams
export function getBackboneParams(ctx: ThemeRegistryContext, structure: Structure) {

View File

@@ -47,6 +47,7 @@ export const CartoonParams = {
sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
visuals: PD.MultiSelect(['polymer-trace', 'polymer-gap', 'nucleotide-ring', 'nucleotide-atomic-ring-fill', 'nucleotide-atomic-bond', 'nucleotide-atomic-element'], PD.objectToOptions(CartoonVisuals)),
bumpFrequency: PD.Numeric(2, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), { ...BaseGeometry.ShadingCategory, isHidden: true }),
};
export type CartoonParams = typeof CartoonParams

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
@@ -55,7 +56,7 @@ function createUnitsRenderObject<G extends Geometry>(structureGroup: StructureGr
interface UnitsVisualBuilder<P extends StructureParams, G extends Geometry> {
defaultProps: PD.Values<P>
createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<P>, geometry?: G): Promise<G> | G
createLocationIterator(structureGroup: StructureGroup): LocationIterator
createLocationIterator(structureGroup: StructureGroup, props: PD.Values<P>): LocationIterator
getLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number): Loci
eachLocation(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean, isMarking: boolean): boolean
setUpdateState(state: VisualUpdateState, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup): void
@@ -182,7 +183,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
function update(newGeometry?: G) {
if (updateState.createNew) {
locationIt = createLocationIterator(newStructureGroup);
locationIt = createLocationIterator(newStructureGroup, newProps);
if (newGeometry) {
renderObject = createUnitsRenderObject(newStructureGroup, newGeometry, locationIt, newTheme, newProps, materialId);
positionIt = createPositionIterator(newGeometry, renderObject.values);
@@ -196,7 +197,7 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom
if (updateState.updateTransform) {
// console.log('update transform');
locationIt = createLocationIterator(newStructureGroup);
locationIt = createLocationIterator(newStructureGroup, newProps);
const { instanceCount, groupCount } = locationIt;
if (newProps.instanceGranularity) {
createMarkers(instanceCount, 'instance', renderObject.values);

View File

@@ -2,6 +2,7 @@
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
@@ -213,7 +214,7 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
return ComplexCylindersVisual<InterUnitBondCylinderParams>({
defaultProps: PD.getDefaultValues(InterUnitBondCylinderParams),
createGeometry: createInterUnitBondCylinderImpostors,
createLocationIterator: BondIterator.fromStructure,
createLocationIterator: (structure: Structure, props: PD.Values<InterUnitBondCylinderParams>) => BondIterator.fromStructure(structure, { includeLocation2: props.colorMode === 'interpolate' }),
getLoci: getInterBondLoci,
eachLocation: eachInterBond,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<InterUnitBondCylinderParams>, currentProps: PD.Values<InterUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure) => {
@@ -238,6 +239,12 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
newProps.multipleBonds !== currentProps.multipleBonds
);
if (newProps.colorMode !== currentProps.colorMode) {
state.createGeometry = true;
state.updateTransform = true;
state.updateColor = true;
}
if (newStructure.interUnitBonds !== currentStructure.interUnitBonds) {
state.createGeometry = true;
state.updateTransform = true;
@@ -255,7 +262,7 @@ export function InterUnitBondCylinderMeshVisual(materialId: number): ComplexVisu
return ComplexMeshVisual<InterUnitBondCylinderParams>({
defaultProps: PD.getDefaultValues(InterUnitBondCylinderParams),
createGeometry: createInterUnitBondCylinderMesh,
createLocationIterator: BondIterator.fromStructure,
createLocationIterator: (structure: Structure) => BondIterator.fromStructure(structure),
getLoci: getInterBondLoci,
eachLocation: eachInterBond,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<InterUnitBondCylinderParams>, currentProps: PD.Values<InterUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure) => {

View File

@@ -127,7 +127,7 @@ export function InterUnitBondLineVisual(materialId: number): ComplexVisual<Inter
return ComplexLinesVisual<InterUnitBondLineParams>({
defaultProps: PD.getDefaultValues(InterUnitBondLineParams),
createGeometry: createInterUnitBondLines,
createLocationIterator: BondIterator.fromStructure,
createLocationIterator: (structure: Structure) => BondIterator.fromStructure(structure),
getLoci: getInterBondLoci,
eachLocation: eachInterBond,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<InterUnitBondLineParams>, currentProps: PD.Values<InterUnitBondLineParams>, newTheme: Theme, currentTheme: Theme, newStructure: Structure, currentStructure: Structure) => {

View File

@@ -3,6 +3,7 @@
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
@@ -230,7 +231,7 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
return UnitsCylindersVisual<IntraUnitBondCylinderParams>({
defaultProps: PD.getDefaultValues(IntraUnitBondCylinderParams),
createGeometry: createIntraUnitBondCylinderImpostors,
createLocationIterator: BondIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup, props) => BondIterator.fromGroup(structureGroup, { includeLocation2: props.colorMode === 'interpolate' }),
getLoci: getIntraBondLoci,
eachLocation: eachIntraBond,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitBondCylinderParams>, currentProps: PD.Values<IntraUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {
@@ -256,6 +257,12 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
newProps.multipleBonds !== currentProps.multipleBonds
);
if (newProps.colorMode !== currentProps.colorMode) {
state.createGeometry = true;
state.updateTransform = true;
state.updateColor = true;
}
const newUnit = newStructureGroup.group.units[0];
const currentUnit = currentStructureGroup.group.units[0];
if (Unit.isAtomic(newUnit) && Unit.isAtomic(currentUnit)) {
@@ -277,7 +284,7 @@ export function IntraUnitBondCylinderMeshVisual(materialId: number): UnitsVisual
return UnitsMeshVisual<IntraUnitBondCylinderParams>({
defaultProps: PD.getDefaultValues(IntraUnitBondCylinderParams),
createGeometry: createIntraUnitBondCylinderMesh,
createLocationIterator: BondIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup) => BondIterator.fromGroup(structureGroup),
getLoci: getIntraBondLoci,
eachLocation: eachIntraBond,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitBondCylinderParams>, currentProps: PD.Values<IntraUnitBondCylinderParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {

View File

@@ -153,7 +153,7 @@ export function IntraUnitBondLineVisual(materialId: number): UnitsVisual<IntraUn
return UnitsLinesVisual<IntraUnitBondLineParams>({
defaultProps: PD.getDefaultValues(IntraUnitBondLineParams),
createGeometry: createIntraUnitBondLines,
createLocationIterator: BondIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup) => BondIterator.fromGroup(structureGroup),
getLoci: getIntraBondLoci,
eachLocation: eachIntraBond,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitBondLineParams>, currentProps: PD.Values<IntraUnitBondLineParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {

View File

@@ -83,6 +83,7 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
const residueIt = Segmentation.transientSegments(residueAtomSegments, elements);
let i = 0;
const colorModeFlag = 2.0;
while (chainIt.hasNext) {
residueIt.setSegment(chainIt.move());
@@ -99,14 +100,14 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
// trace cylinder
pos(idx.trace, pTrace);
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, i);
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, colorModeFlag, i);
// sugar ring
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pC4_1[0], pC4_1[1], pC4_1[2], 1, true, true, i);
builder.add(pC4_1[0], pC4_1[1], pC4_1[2], pO4_1[0], pO4_1[1], pO4_1[2], 1, true, true, i);
builder.add(pO4_1[0], pO4_1[1], pO4_1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, i);
builder.add(pC1_1[0], pC1_1[1], pC1_1[2], pC2_1[0], pC2_1[1], pC2_1[2], 1, true, true, i);
builder.add(pC2_1[0], pC2_1[1], pC2_1[2], pC3_1[0], pC3_1[1], pC3_1[2], 1, true, true, i);
builder.add(pC3_1[0], pC3_1[1], pC3_1[2], pC4_1[0], pC4_1[1], pC4_1[2], 1, true, true, colorModeFlag, i);
builder.add(pC4_1[0], pC4_1[1], pC4_1[2], pO4_1[0], pO4_1[1], pO4_1[2], 1, true, true, colorModeFlag, i);
builder.add(pO4_1[0], pO4_1[1], pO4_1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, colorModeFlag, i);
builder.add(pC1_1[0], pC1_1[1], pC1_1[2], pC2_1[0], pC2_1[1], pC2_1[2], 1, true, true, colorModeFlag, i);
builder.add(pC2_1[0], pC2_1[1], pC2_1[2], pC3_1[0], pC3_1[1], pC3_1[2], 1, true, true, colorModeFlag, i);
}
const { isPurine, isPyrimidine } = getNucleotideBaseType(unit, residueIndex);
@@ -116,26 +117,26 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
if (idx.C1_1 !== -1 && idx.N9 !== -1) {
pos(idx.C1_1, pC1_1); pos(idx.N9, pN9);
builder.add(pN9[0], pN9[1], pN9[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, i);
builder.add(pN9[0], pN9[1], pN9[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, colorModeFlag, i);
} else if (idx.N9 !== -1 && idx.trace !== -1) {
pos(idx.N9, pN9); pos(idx.trace, pTrace);
builder.add(pN9[0], pN9[1], pN9[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, i);
builder.add(pN9[0], pN9[1], pN9[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, colorModeFlag, i);
}
if (hasPurinIndices(idx)) {
pos(idx.N1, pN1); pos(idx.C2, pC2); pos(idx.N3, pN3); pos(idx.C4, pC4); pos(idx.C5, pC5); pos(idx.C6, pC6); pos(idx.N7, pN7); pos(idx.C8, pC8); pos(idx.N9, pN9);
// base ring
builder.add(pN9[0], pN9[1], pN9[2], pC8[0], pC8[1], pC8[2], 1, true, true, i);
builder.add(pC8[0], pC8[1], pC8[2], pN7[0], pN7[1], pN7[2], 1, true, true, i);
builder.add(pN7[0], pN7[1], pN7[2], pC5[0], pC5[1], pC5[2], 1, true, true, i);
builder.add(pC5[0], pC5[1], pC5[2], pC6[0], pC6[1], pC6[2], 1, true, true, i);
builder.add(pC6[0], pC6[1], pC6[2], pN1[0], pN1[1], pN1[2], 1, true, true, i);
builder.add(pN1[0], pN1[1], pN1[2], pC2[0], pC2[1], pC2[2], 1, true, true, i);
builder.add(pC2[0], pC2[1], pC2[2], pN3[0], pN3[1], pN3[2], 1, true, true, i);
builder.add(pN3[0], pN3[1], pN3[2], pC4[0], pC4[1], pC4[2], 1, true, true, i);
builder.add(pC4[0], pC4[1], pC4[2], pC5[0], pC5[1], pC5[2], 1, true, true, i);
builder.add(pC4[0], pC4[1], pC4[2], pN9[0], pN9[1], pN9[2], 1, true, true, i);
builder.add(pN9[0], pN9[1], pN9[2], pC8[0], pC8[1], pC8[2], 1, true, true, colorModeFlag, i);
builder.add(pC8[0], pC8[1], pC8[2], pN7[0], pN7[1], pN7[2], 1, true, true, colorModeFlag, i);
builder.add(pN7[0], pN7[1], pN7[2], pC5[0], pC5[1], pC5[2], 1, true, true, colorModeFlag, i);
builder.add(pC5[0], pC5[1], pC5[2], pC6[0], pC6[1], pC6[2], 1, true, true, colorModeFlag, i);
builder.add(pC6[0], pC6[1], pC6[2], pN1[0], pN1[1], pN1[2], 1, true, true, colorModeFlag, i);
builder.add(pN1[0], pN1[1], pN1[2], pC2[0], pC2[1], pC2[2], 1, true, true, colorModeFlag, i);
builder.add(pC2[0], pC2[1], pC2[2], pN3[0], pN3[1], pN3[2], 1, true, true, colorModeFlag, i);
builder.add(pN3[0], pN3[1], pN3[2], pC4[0], pC4[1], pC4[2], 1, true, true, colorModeFlag, i);
builder.add(pC4[0], pC4[1], pC4[2], pC5[0], pC5[1], pC5[2], 1, true, true, colorModeFlag, i);
builder.add(pC4[0], pC4[1], pC4[2], pN9[0], pN9[1], pN9[2], 1, true, true, colorModeFlag, i);
}
} else if (isPyrimidine) {
@@ -143,22 +144,22 @@ function createNucleotideAtomicBondImpostor(ctx: VisualContext, unit: Unit, stru
if (idx.C1_1 !== -1 && idx.N1 !== -1) {
pos(idx.N1, pN1); pos(idx.C1_1, pC1_1);
builder.add(pN1[0], pN1[1], pN1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, i);
builder.add(pN1[0], pN1[1], pN1[2], pC1_1[0], pC1_1[1], pC1_1[2], 1, true, true, colorModeFlag, i);
} else if (idx.N1 !== -1 && idx.trace !== -1) {
pos(idx.N1, pN1); pos(idx.trace, pTrace);
builder.add(pN1[0], pN1[1], pN1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, i);
builder.add(pN1[0], pN1[1], pN1[2], pTrace[0], pTrace[1], pTrace[2], 1, true, true, colorModeFlag, i);
}
if (hasPyrimidineIndices(idx)) {
pos(idx.N1, pN1); pos(idx.C2, pC2); pos(idx.N3, pN3); pos(idx.C4, pC4); pos(idx.C5, pC5); pos(idx.C6, pC6);
// base ring
builder.add(pN1[0], pN1[1], pN1[2], pC6[0], pC6[1], pC6[2], 1, true, true, i);
builder.add(pC6[0], pC6[1], pC6[2], pC5[0], pC5[1], pC5[2], 1, true, true, i);
builder.add(pC5[0], pC5[1], pC5[2], pC4[0], pC4[1], pC4[2], 1, true, true, i);
builder.add(pC4[0], pC4[1], pC4[2], pN3[0], pN3[1], pN3[2], 1, true, true, i);
builder.add(pN3[0], pN3[1], pN3[2], pC2[0], pC2[1], pC2[2], 1, true, true, i);
builder.add(pC2[0], pC2[1], pC2[2], pN1[0], pN1[1], pN1[2], 1, true, true, i);
builder.add(pN1[0], pN1[1], pN1[2], pC6[0], pC6[1], pC6[2], 1, true, true, colorModeFlag, i);
builder.add(pC6[0], pC6[1], pC6[2], pC5[0], pC5[1], pC5[2], 1, true, true, colorModeFlag, i);
builder.add(pC5[0], pC5[1], pC5[2], pC4[0], pC4[1], pC4[2], 1, true, true, colorModeFlag, i);
builder.add(pC4[0], pC4[1], pC4[2], pN3[0], pN3[1], pN3[2], 1, true, true, colorModeFlag, i);
builder.add(pN3[0], pN3[1], pN3[2], pC2[0], pC2[1], pC2[2], 1, true, true, colorModeFlag, i);
builder.add(pC2[0], pC2[1], pC2[2], pN1[0], pN1[1], pN1[2], 1, true, true, colorModeFlag, i);
}
}

View File

@@ -70,8 +70,8 @@ function createPolymerBackboneCylinderImpostor(ctx: VisualContext, unit: Unit, s
const shift = isNucleicType ? NucleicShift : StandardShift;
v3add(pM, pA, v3scale(pM, v3sub(pM, pB, pA), shift));
builder.add(pA[0], pA[1], pA[2], pM[0], pM[1], pM[2], 1, false, false, groupA);
builder.add(pM[0], pM[1], pM[2], pB[0], pB[1], pB[2], 1, false, false, groupB);
builder.add(pA[0], pA[1], pA[2], pM[0], pM[1], pM[2], 1, false, false, 2, groupA);
builder.add(pM[0], pM[1], pM[2], pB[0], pB[1], pB[2], 1, false, false, 2, groupB);
};
eachPolymerBackboneLink(unit, add);
@@ -88,7 +88,7 @@ export function PolymerBackboneCylinderImpostorVisual(materialId: number): Units
return UnitsCylindersVisual<PolymerBackboneCylinderParams>({
defaultProps: PD.getDefaultValues(PolymerBackboneCylinderParams),
createGeometry: createPolymerBackboneCylinderImpostor,
createLocationIterator: PolymerLocationIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
getLoci: getPolymerElementLoci,
eachLocation: eachPolymerElement,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneCylinderParams>, currentProps: PD.Values<PolymerBackboneCylinderParams>) => { },
@@ -148,7 +148,7 @@ export function PolymerBackboneCylinderMeshVisual(materialId: number): UnitsVisu
return UnitsMeshVisual<PolymerBackboneCylinderParams>({
defaultProps: PD.getDefaultValues(PolymerBackboneCylinderParams),
createGeometry: createPolymerBackboneCylinderMesh,
createLocationIterator: PolymerLocationIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
getLoci: getPolymerElementLoci,
eachLocation: eachPolymerElement,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneCylinderParams>, currentProps: PD.Values<PolymerBackboneCylinderParams>) => {
@@ -161,4 +161,4 @@ export function PolymerBackboneCylinderMeshVisual(materialId: number): UnitsVisu
return props.tryUseImpostor && !!webgl;
}
}, materialId);
}
}

View File

@@ -72,7 +72,7 @@ export function PolymerBackboneSphereImpostorVisual(materialId: number): UnitsVi
return UnitsSpheresVisual<PolymerBackboneSphereParams>({
defaultProps: PD.getDefaultValues(PolymerBackboneSphereParams),
createGeometry: createPolymerBackboneSphereImpostor,
createLocationIterator: PolymerLocationIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
getLoci: getPolymerElementLoci,
eachLocation: eachPolymerElement,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneSphereParams>, currentProps: PD.Values<PolymerBackboneSphereParams>) => { },
@@ -116,7 +116,7 @@ export function PolymerBackboneSphereMeshVisual(materialId: number): UnitsVisual
return UnitsMeshVisual<PolymerBackboneSphereParams>({
defaultProps: PD.getDefaultValues(PolymerBackboneSphereParams),
createGeometry: createPolymerBackboneSphereMesh,
createLocationIterator: PolymerLocationIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
getLoci: getPolymerElementLoci,
eachLocation: eachPolymerElement,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneSphereParams>, currentProps: PD.Values<PolymerBackboneSphereParams>) => {

View File

@@ -17,6 +17,7 @@ import { isNucleic, SecondaryStructureType } from '../../../mol-model/structure/
import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual } from '../units-visual';
import { VisualUpdateState } from '../../util';
import { Sphere3D } from '../../../mol-math/geometry';
import { StructureGroup } from './util/common';
const t = Mat4.identity();
const sVec = Vec3.zero();
@@ -101,7 +102,7 @@ export function PolymerDirectionVisual(materialId: number): UnitsVisual<PolymerD
return UnitsMeshVisual<PolymerDirectionParams>({
defaultProps: PD.getDefaultValues(PolymerDirectionParams),
createGeometry: createPolymerDirectionWedgeMesh,
createLocationIterator: PolymerLocationIterator.fromGroup,
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup),
getLoci: getPolymerElementLoci,
eachLocation: eachPolymerElement,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerDirectionParams>, currentProps: PD.Values<PolymerDirectionParams>) => {

View File

@@ -187,7 +187,7 @@ export function PolymerTraceVisual(materialId: number): UnitsVisual<PolymerTrace
return UnitsMeshVisual<PolymerTraceParams>({
defaultProps: PD.getDefaultValues(PolymerTraceParams),
createGeometry: createPolymerTraceMesh,
createLocationIterator: sg => PolymerLocationIterator.fromGroup(sg, true),
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup, { asSecondary: true }),
getLoci: getPolymerElementLoci,
eachLocation: eachPolymerElement,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerTraceParams>, currentProps: PD.Values<PolymerTraceParams>, newTheme: Theme, currentTheme: Theme, newStructureGroup: StructureGroup, currentStructureGroup: StructureGroup) => {

View File

@@ -21,6 +21,7 @@ import { Vec3 } from '../../../mol-math/linear-algebra';
import { addSphere } from '../../../mol-geo/geometry/mesh/builder/sphere';
import { BaseGeometry } from '../../../mol-geo/geometry/base';
import { Sphere3D } from '../../../mol-math/geometry';
import { StructureGroup } from './util/common';
export const PolymerTubeMeshParams = {
sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
@@ -117,7 +118,7 @@ export function PolymerTubeVisual(materialId: number): UnitsVisual<PolymerTubePa
return UnitsMeshVisual<PolymerTubeParams>({
defaultProps: PD.getDefaultValues(PolymerTubeParams),
createGeometry: createPolymerTubeMesh,
createLocationIterator: sg => PolymerLocationIterator.fromGroup(sg, true),
createLocationIterator: (structureGroup: StructureGroup) => PolymerLocationIterator.fromGroup(structureGroup, { asSecondary: true }),
getLoci: getPolymerElementLoci,
eachLocation: eachPolymerElement,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerTubeParams>, currentProps: PD.Values<PolymerTubeParams>) => {

View File

@@ -3,6 +3,7 @@
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
* @author Gianluca Tomasello <giagitom@gmail.com>
*/
import { BondType } from '../../../../mol-model/structure/model/types';
@@ -125,7 +126,7 @@ export function makeInterBondIgnoreTest(structure: Structure, props: BondProps):
}
export namespace BondIterator {
export function fromGroup(structureGroup: StructureGroup): LocationIterator {
export function fromGroup(structureGroup: StructureGroup, props?: { includeLocation2?: boolean }): LocationIterator {
const { group, structure } = structureGroup;
const unit = group.units[0] as Unit.Atomic;
const groupCount = Unit.isAtomic(unit) ? unit.bonds.edgeCount * 2 : 0;
@@ -139,10 +140,22 @@ export namespace BondIterator {
location.bIndex = unit.bonds.b[groupIndex];
return location;
};
if (props?.includeLocation2) {
const location2 = Bond.Location(structure, undefined, undefined, structure, undefined, undefined);
const getLocation2 = (groupIndex: number, instanceIndex: number) => { // swapping A and B
const unit = group.units[instanceIndex] as Unit.Atomic;
location2.aUnit = unit;
location2.bUnit = unit;
location2.aIndex = unit.bonds.b[groupIndex];
location2.bIndex = unit.bonds.a[groupIndex];
return location2;
};
return LocationIterator(groupCount, instanceCount, 1, getLocation, false, () => false, getLocation2);
}
return LocationIterator(groupCount, instanceCount, 1, getLocation);
}
export function fromStructure(structure: Structure): LocationIterator {
export function fromStructure(structure: Structure, props?: { includeLocation2?: boolean }): LocationIterator {
const groupCount = structure.interUnitBonds.edgeCount;
const instanceCount = 1;
const location = Bond.Location(structure, undefined, undefined, structure, undefined, undefined);
@@ -154,6 +167,18 @@ export namespace BondIterator {
location.bIndex = bond.indexB;
return location;
};
if (props?.includeLocation2) {
const location2 = Bond.Location(structure, undefined, undefined, structure, undefined, undefined);
const getLocation2 = (groupIndex: number) => { // swapping A and B
const bond = structure.interUnitBonds.edges[groupIndex];
location2.aUnit = structure.unitMap.get(bond.unitB);
location2.aIndex = bond.indexB;
location2.bUnit = structure.unitMap.get(bond.unitA);
location2.bIndex = bond.indexA;
return location2;
};
return LocationIterator(groupCount, instanceCount, 1, getLocation, true, () => false, getLocation2);
};
return LocationIterator(groupCount, instanceCount, 1, getLocation, true);
}
}

View File

@@ -33,6 +33,7 @@ export const LinkCylinderParams = {
dashCap: PD.Boolean(true),
stubCap: PD.Boolean(true),
radialSegments: PD.Numeric(16, { min: 2, max: 56, step: 2 }, BaseGeometry.CustomQualityParamInfo),
colorMode: PD.Select('default', PD.arrayToOptions(['default', 'interpolate'] as const), BaseGeometry.ShadingCategory)
};
export const DefaultLinkCylinderProps = PD.getDefaultValues(LinkCylinderParams);
export type LinkCylinderProps = typeof DefaultLinkCylinderProps
@@ -264,7 +265,9 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
if (!linkCount) return { cylinders: Cylinders.createEmpty(cylinders) };
const { linkScale, linkSpacing, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props;
const { linkScale, linkSpacing, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap, colorMode } = props;
const interpolate = colorMode === 'interpolate';
const colorModeFlag = interpolate === true ? 3 : 2;
const cylindersCountEstimate = linkCount * 2;
const builder = CylindersBuilder.create(cylindersCountEstimate, cylindersCountEstimate / 4, cylinders);
@@ -292,10 +295,10 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
if (linkStyle === LinkStyle.Solid) {
v3scale(vm, v3add(vm, va, vb), 0.5);
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
} else if (linkStyle === LinkStyle.Dashed) {
v3scale(vm, v3add(vm, va, vb), 0.5);
builder.addFixedCountDashes(va, vm, dashCount, dashScale, dashCap, dashCap, linkStub, edgeIndex);
builder.addFixedCountDashes(va, vm, dashCount, dashScale, dashCap, dashCap, linkStub, interpolate, edgeIndex);
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
(linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
@@ -306,7 +309,7 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
calculateShiftDir(vShift, va, vb, referencePosition ? referencePosition(edgeIndex) : null);
if (linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
const aromaticOffset = linkRadius + aromaticScale * linkRadius + aromaticScale * linkRadius * aromaticSpacing;
@@ -316,38 +319,38 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
v3setMagnitude(vShift, vShift, aromaticOffset);
v3sub(va, va, vShift);
v3sub(vm, vm, vShift);
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, edgeIndex);
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, interpolate, edgeIndex);
if (linkStyle === LinkStyle.MirroredAromatic) {
v3setMagnitude(vShift, vShift, aromaticOffset * 2);
v3add(va, va, vShift);
v3add(vm, vm, vShift);
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, edgeIndex);
builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, interpolate, edgeIndex);
}
} else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
const multipleOffset = linkRadius + multiScale * linkRadius + linkScale * linkRadius * linkSpacing;
v3setMagnitude(vShift, vShift, multipleOffset);
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
v3setMagnitude(tmpV12, v3sub(tmpV12, va, vm), linkRadius / 1.5);
v3sub(va, va, tmpV12);
if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex);
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, dashCap, linkStub, edgeIndex);
if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, dashCap, linkStub, colorModeFlag, edgeIndex);
} else {
v3setMagnitude(vShift, vShift, absOffset);
if (order === 3) builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], multiScale, linkCap, linkStub, edgeIndex);
builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex);
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, linkCap, linkStub, edgeIndex);
if (order === 3) builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, linkCap, linkStub, colorModeFlag, edgeIndex);
}
} else if (linkStyle === LinkStyle.Disk) {
v3scale(tmpV12, v3sub(tmpV12, vm, va), 0.475);
v3add(va, va, tmpV12);
v3sub(vm, vm, tmpV12);
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, colorModeFlag, edgeIndex);
}
}

View File

@@ -41,7 +41,7 @@ export function getGapRanges(unit: Unit): SortedRanges<ElementIndex> {
}
export namespace PolymerLocationIterator {
export function fromGroup(structureGroup: StructureGroup, asSecondary = false): LocationIterator {
export function fromGroup(structureGroup: StructureGroup, options?: { asSecondary?: boolean }): LocationIterator {
const { group, structure } = structureGroup;
const polymerElements = group.units[0].polymerElements;
const groupCount = polymerElements.length;
@@ -53,6 +53,7 @@ export namespace PolymerLocationIterator {
location.element = polymerElements[groupIndex];
return location;
};
const asSecondary = !!options?.asSecondary;
function isSecondary(elementIndex: number, instanceIndex: number) {
return asSecondary;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -104,10 +104,13 @@ export namespace ParamDefinition {
}
export interface Text<T extends string = string> extends Base<T> {
type: 'text'
type: 'text',
multiline?: boolean,
placeholder?: string,
disableInteractiveUpdates?: boolean
}
export function Text<T extends string = string>(defaultValue: string = '', info?: Info): Text<T> {
return setInfo<Text<T>>({ type: 'text', defaultValue: defaultValue as any }, info);
export function Text<T extends string = string>(defaultValue: string = '', info?: Info & { multiline?: boolean, placeholder?: string, disableInteractiveUpdates?: boolean }): Text<T> {
return setInfo<Text<T>>({ type: 'text', defaultValue: defaultValue as any, multiline: info?.multiline, placeholder: info?.placeholder, disableInteractiveUpdates: info?.disableInteractiveUpdates }, info);
}
export interface Color extends Base<ColorData> {