diff --git a/src/mol-model-props/rcsb/representations/assembly-symmetry-axes.ts b/src/mol-model-props/rcsb/representations/assembly-symmetry-axes.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6f46fa74dcdf464380791f3f80b5bc0b4121e0f --- /dev/null +++ b/src/mol-model-props/rcsb/representations/assembly-symmetry-axes.ts @@ -0,0 +1,136 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { RepresentationParamsGetter, RepresentationContext, VisualContext } from 'mol-repr/representation'; +import { ThemeRegistryContext, Theme } from 'mol-theme/theme'; +import { Structure } from 'mol-model/structure'; +import { StructureRepresentationProvider, StructureRepresentation, ComplexRepresentation, ComplexVisual } from 'mol-repr/structure/representation'; +import { AssemblySymmetry } from '../assembly-symmetry'; +import { Table } from 'mol-data/db'; +import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; +import { Tensor } from 'mol-math/linear-algebra'; +import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; +import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; +import { VisualUpdateState } from 'mol-repr/util'; +import { ComplexMeshVisual, ComplexMeshParams } from 'mol-repr/structure/complex-visual'; +import { Mesh } from 'mol-geo/geometry/mesh/mesh'; +import { EmptyLoci } from 'mol-model/loci'; +import { LocationIterator } from 'mol-geo/util/location-iterator'; +import { NullLocation } from 'mol-model/location'; + +export const AssemblySymmetryAxesParams = { + ...ComplexMeshParams, + sizeFactor: PD.Numeric(0.4, { min: 0, max: 3, step: 0.01 }), + radialSegments: PD.Numeric(16, { min: 3, max: 56, step: 1 }), + detail: PD.Numeric(0, { min: 0, max: 3, step: 1 }), + symmetryId: PD.Select<number>(-1, []), +} +export type AssemblySymmetryAxesParams = typeof AssemblySymmetryAxesParams +export function getAssemblySymmetryAxesParams(ctx: ThemeRegistryContext, structure: Structure) { + const params = PD.clone(AssemblySymmetryAxesParams) + + if (structure.models[0].customProperties.has(AssemblySymmetry.Descriptor)) { + const assemblySymmetry = AssemblySymmetry.get(structure.models[0])! + const assemblyName = structure.assemblyName + const s = assemblySymmetry.db.rcsb_assembly_symmetry + if (s._rowCount) { + params.symmetryId.options = [] + for (let i = 0, il = s._rowCount; i < il; ++i) { + if (s.assembly_id.value(i) === assemblyName) { + params.symmetryId.options.push([ + s.id.value(i), `${s.symbol.value(i)} ${s.kind.value(i)}` + ]) + } + } + params.symmetryId.defaultValue = params.symmetryId.options[0][0] + } + } + + return params +} + +export type AssemblySymmetryAxesRepresentation = StructureRepresentation<AssemblySymmetryAxesParams> +export function AssemblySymmetryAxesRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, AssemblySymmetryAxesParams>): AssemblySymmetryAxesRepresentation { + return ComplexRepresentation('RCSB Assembly Symmetry Axes', ctx, getParams, AssemblySymmetryAxesVisual) +} + +export const AssemblySymmetryAxesRepresentationProvider: StructureRepresentationProvider<AssemblySymmetryAxesParams> = { + label: 'RCSB Assembly Symmetry Axes', + description: 'Displays assembly symmetry axes.', + factory: AssemblySymmetryAxesRepresentation, + getParams: getAssemblySymmetryAxesParams, + defaultValues: PD.getDefaultValues(AssemblySymmetryAxesParams), + defaultColorTheme: 'uniform', + defaultSizeTheme: 'uniform' +} + +// + +export function AssemblySymmetryAxesVisual(): ComplexVisual<AssemblySymmetryAxesParams> { + return ComplexMeshVisual<AssemblySymmetryAxesParams>({ + defaultProps: PD.getDefaultValues(AssemblySymmetryAxesParams), + createGeometry: createAssemblySymmetryAxesMesh, + createLocationIterator, + getLoci: () => EmptyLoci, + mark: () => false, + setUpdateState: (state: VisualUpdateState, newProps: PD.Values<AssemblySymmetryAxesParams>, currentProps: PD.Values<AssemblySymmetryAxesParams>) => { + state.createGeometry = ( + newProps.sizeFactor !== currentProps.sizeFactor || + newProps.detail !== currentProps.detail || + newProps.symmetryId !== currentProps.symmetryId + ) + } + }) +} + +function createLocationIterator(structure: Structure) { + let groupCount = 0 + + const assemblySymmetry = AssemblySymmetry.get(structure.models[0]) + if (assemblySymmetry) { + const axis = assemblySymmetry.db.rcsb_assembly_symmetry_axis + groupCount = axis._rowCount + } + + return LocationIterator(groupCount, 1, () => NullLocation) +} + +export function createAssemblySymmetryAxesMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<AssemblySymmetryAxesParams>, mesh?: Mesh) { + + const { symmetryId, sizeFactor } = props + + const assemblySymmetry = AssemblySymmetry.get(structure.models[0]) + if (!assemblySymmetry) return Mesh.createEmpty(mesh) + + const s = assemblySymmetry.db.rcsb_assembly_symmetry + const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId) + if (!symmetry) return Mesh.createEmpty(mesh) + + // symmetry.assembly_id not available for structure.assemblyName + if (symmetry.assembly_id !== structure.assemblyName) return Mesh.createEmpty(mesh) + + const axes = assemblySymmetry.getAxes(symmetryId) + if (!axes._rowCount) return Mesh.createEmpty(mesh) + + const vectorSpace = AssemblySymmetry.Schema.rcsb_assembly_symmetry_axis.start.space; + // const colors: Color[] = [] + // const labels: string[] = [] + const radius = 1 * sizeFactor + const cylinderProps = { radiusTop: radius, radiusBottom: radius } + const builderState = MeshBuilder.createState(256, 128, mesh) + for (let i = 0, il = axes._rowCount; i < il; ++i) { + const start = Tensor.toVec3(vectorSpace, axes.start.value(i)) + const end = Tensor.toVec3(vectorSpace, axes.end.value(i)) + builderState.currentGroup = i + addSphere(builderState, start, radius, 2) + addSphere(builderState, end, radius, 2) + addCylinder(builderState, start, end, 1, cylinderProps) + // colors.push(Color(0xCCEE11)) + // labels.push(`Axis ${i + 1} for ${symmetry.kind} ${symmetry.type.toLowerCase()} symmetry`) + } + return MeshBuilder.getMesh(builderState) +} \ No newline at end of file diff --git a/src/mol-model-props/rcsb/themes/assembly-symmetry.ts b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts similarity index 97% rename from src/mol-model-props/rcsb/themes/assembly-symmetry.ts rename to src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts index 41f03e6135f94e22fd83cd9cc9d41b67012b1961..7bfbff51a3c7105a2d45bef7cfd76d8a7db90c50 100644 --- a/src/mol-model-props/rcsb/themes/assembly-symmetry.ts +++ b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts @@ -32,7 +32,7 @@ function clusterMemberKey (asym_id: string, oper_list_ids: string[]) { export const AssemblySymmetryClusterColorThemeParams = { list: PD.Select<ColorListName>('Viridis', ColorListOptions), - symmetryId: PD.Select<number>(0, []), + symmetryId: PD.Select<number>(-1, []), } export type AssemblySymmetryClusterColorThemeParams = typeof AssemblySymmetryClusterColorThemeParams export function getAssemblySymmetryClusterColorThemeParams(ctx: ThemeDataContext) { @@ -51,7 +51,7 @@ export function getAssemblySymmetryClusterColorThemeParams(ctx: ThemeDataContext ]) } } - params.symmetryId.defaultValue = s.id.value(0) + params.symmetryId.defaultValue = params.symmetryId.options[0][0] } } diff --git a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts index 3337e6b60d49058f6b4b8a917c92d434735eec49..fba6dbf620a7db014cd11dabbd7fa51ae9a0119a 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts @@ -8,7 +8,8 @@ import { PluginBehavior } from 'mol-plugin/behavior'; import { ParamDefinition as PD } from 'mol-util/param-definition' import { AssemblySymmetry } from 'mol-model-props/rcsb/assembly-symmetry'; import { CustomPropertyRegistry } from 'mol-plugin/util/custom-prop-registry'; -import { AssemblySymmetryClusterColorThemeProvider } from 'mol-model-props/rcsb/themes/assembly-symmetry'; +import { AssemblySymmetryClusterColorThemeProvider } from 'mol-model-props/rcsb/themes/assembly-symmetry-cluster'; +import { AssemblySymmetryAxesRepresentationProvider } from 'mol-model-props/rcsb/representations/assembly-symmetry-axes'; export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean }>({ name: 'rcsb-assembly-symmetry-prop', @@ -27,9 +28,10 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean register(): void { this.ctx.customModelProperties.register(this.provider); - // TODO: support filtering of themes based on the input structure + // TODO: support filtering of themes and representations based on the input structure // in this case, it would check structure.models[0].customProperties.has(AssemblySymmetry.Descriptor) this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.add('rcsb-assembly-symmetry-cluster', AssemblySymmetryClusterColorThemeProvider) + this.ctx.structureRepresentation.registry.add('rcsb-assembly-symmetry-axes', AssemblySymmetryAxesRepresentationProvider) } update(p: { autoAttach: boolean }) { @@ -42,6 +44,7 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean unregister() { this.ctx.customModelProperties.unregister(AssemblySymmetry.Descriptor.name); this.ctx.structureRepresentation.themeCtx.colorThemeRegistry.remove('rcsb-assembly-symmetry-cluster') + this.ctx.structureRepresentation.registry.remove('rcsb-assembly-symmetry-axes') } }, params: () => ({ diff --git a/src/mol-repr/structure/representation/ball-and-stick.ts b/src/mol-repr/structure/representation/ball-and-stick.ts index be1559e103775e99f44074a6cce91dfa045f9d39..a12848cb64368590662015cc2477b950460c1ff4 100644 --- a/src/mol-repr/structure/representation/ball-and-stick.ts +++ b/src/mol-repr/structure/representation/ball-and-stick.ts @@ -43,7 +43,7 @@ export function BallAndStickRepresentation(ctx: RepresentationContext, getParams return Representation.createMulti('Ball & Stick', ctx, getParams, BallAndStickVisuals as unknown as Representation.Def<Structure, BallAndStickParams>) } -export const BallAndStickRepresentationProvider: StructureRepresentationProvider<typeof BallAndStickParams> = { +export const BallAndStickRepresentationProvider: StructureRepresentationProvider<BallAndStickParams> = { label: 'Ball & Stick', description: 'Displays atoms as spheres and bonds as cylinders.', factory: BallAndStickRepresentation, diff --git a/src/mol-repr/structure/representation/distance-restraint.ts b/src/mol-repr/structure/representation/distance-restraint.ts index cb79889cc9850147567bb1a6e0c3aed793698126..ca1c8a8819531d2fef7b73b8c6073620787a3d6e 100644 --- a/src/mol-repr/structure/representation/distance-restraint.ts +++ b/src/mol-repr/structure/representation/distance-restraint.ts @@ -31,7 +31,7 @@ export function DistanceRestraintRepresentation(ctx: RepresentationContext, getP return Representation.createMulti('DistanceRestraint', ctx, getParams, DistanceRestraintVisuals as unknown as Representation.Def<Structure, DistanceRestraintParams>) } -export const DistanceRestraintRepresentationProvider: StructureRepresentationProvider<typeof DistanceRestraintParams> = { +export const DistanceRestraintRepresentationProvider: StructureRepresentationProvider<DistanceRestraintParams> = { label: 'Distance Restraint', description: 'Displays cross-link distance restraints.', factory: DistanceRestraintRepresentation, diff --git a/src/mol-repr/structure/representation/spacefill.ts b/src/mol-repr/structure/representation/spacefill.ts index 985f7ef36d29de4f07e5ce2f2057b43b7942d39b..b4de348557884d50be444846dce1e69f07c3f5db 100644 --- a/src/mol-repr/structure/representation/spacefill.ts +++ b/src/mol-repr/structure/representation/spacefill.ts @@ -31,7 +31,7 @@ export function SpacefillRepresentation(ctx: RepresentationContext, getParams: R return Representation.createMulti('Spacefill', ctx, getParams, SpacefillVisuals as unknown as Representation.Def<Structure, SpacefillParams>) } -export const SpacefillRepresentationProvider: StructureRepresentationProvider<typeof SpacefillParams> = { +export const SpacefillRepresentationProvider: StructureRepresentationProvider<SpacefillParams> = { label: 'Spacefill', description: 'Displays atoms as spheres.', factory: SpacefillRepresentation,