diff --git a/src/apps/rednatco/api-impl.ts b/src/apps/rednatco/api-impl.ts index a24cca51f7eac4adada621010200c0def83689e6..4121bb9e96b85482fda0c8bd1672926ba0433ae9 100644 --- a/src/apps/rednatco/api-impl.ts +++ b/src/apps/rednatco/api-impl.ts @@ -34,9 +34,9 @@ export class ReDNATCOMspApiImpl implements ReDNATCOMspApi.Object { return !!this.target; } - loadStructure(data: string, type: 'cif'|'pdb') { + loadStructure(coords: { data: string, type: 'cif'|'pdb' }, densityMap: { data: Uint8Array, type: 'ccp4'|'dsn6' }|null) { this.check(); - this.target!.loadStructure(data, type); + this.target!.loadStructure(coords, densityMap); } query<T extends ReDNATCOMspApi.Queries.Type>(type: T): ReDNATCOMspApi.ResponseTypes[T] { diff --git a/src/apps/rednatco/api.ts b/src/apps/rednatco/api.ts index dcf9854ac7630a1591c66926816d903c27f1f05a..549b8a44885a463c9e4ce8eb44f919b014715307 100644 --- a/src/apps/rednatco/api.ts +++ b/src/apps/rednatco/api.ts @@ -126,7 +126,7 @@ export namespace ReDNATCOMspApi { event: (evt: Event) => void; init: (elemId: string, onEvent?: (evt: Event) => void) => void; isReady: () => boolean; - loadStructure: (data: string, type: 'cif'|'pdb') => void; + loadStructure: (coords: { data: string, type: 'cif'|'pdb'}, densityMap: { data: Uint8Array, type: 'ccp4'|'dsn6' }|null) => void; query: <T extends Queries.Type>(type: T) => ResponseTypes[T]; } } diff --git a/src/apps/rednatco/idents.ts b/src/apps/rednatco/idents.ts index 96a74d6be640412d0533843432c52e52edaf023a..91b5b4c91d599df50d24dd472a644c1cd9770b2d 100644 --- a/src/apps/rednatco/idents.ts +++ b/src/apps/rednatco/idents.ts @@ -8,6 +8,7 @@ export type ID = 'structure' | /* Possibly filtered structure as PSO - this is what shall be used to create visuals from */ 'visual' | /* Visual PSO - the thing that is actually drawn on the screen */ 'pyramids'|'superposition'; /* Additional identifiers for DNATCO-specific objects */ + export type Substructure = 'nucleic'|'protein'|'water'|'selected-slice'|'remainder-slice'; export function ID(id: ID, sub: Substructure|'', ref: string) { @@ -16,6 +17,12 @@ export function ID(id: ID, sub: Substructure|'', ref: string) { return `${ref}_${sub}_${id}`; } +export type DensityID = 'data'|'volume'|'visual'; + +export function DensityID(id: DensityID, ref: string) { + return `${ref}_density-map_${id}`; +} + export function isVisual(ident: string) { return ident.endsWith('_visual'); } diff --git a/src/apps/rednatco/index.tsx b/src/apps/rednatco/index.tsx index ae047f25ba34a73aaf53a2cf483549bc7d65e228..e5a86b0aec8797fff1391b05bc594f2ba5b9d0a7 100644 --- a/src/apps/rednatco/index.tsx +++ b/src/apps/rednatco/index.tsx @@ -204,9 +204,9 @@ export class ReDNATCOMsp extends React.Component<ReDNATCOMsp.Props, State> { } } - loadStructure(data: string, type: 'pdb'|'cif') { + loadStructure(coords: { data: string, type: 'pdb'|'cif' }, densityMap: { data: Uint8Array, type: 'ccp4'|'dsn6' }|null) { if (this.viewer) { - this.viewer.loadStructure(data, type, this.state.display).then(() => { + this.viewer.loadStructure(coords, densityMap, this.state.display).then(() => { this.presentConformers = this.viewer!.getPresentConformers(); this.forceUpdate(); ReDNATCOMspApi.event(Api.Events.StructureLoaded()); diff --git a/src/apps/rednatco/viewer.ts b/src/apps/rednatco/viewer.ts index 06195b5dfe445a7551bc912b79c4d9f65ce8727a..8c609374fee3ae872e6fbffe55983d5f0b12afa3 100644 --- a/src/apps/rednatco/viewer.ts +++ b/src/apps/rednatco/viewer.ts @@ -16,6 +16,7 @@ import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper'; import { Vec3 } from '../../mol-math/linear-algebra/3d'; import { EmptyLoci, Loci } from '../../mol-model/loci'; import { ElementIndex, Model, StructureElement, StructureProperties, StructureSelection, Trajectory } from '../../mol-model/structure'; +// import { Volume } from '../../mol-model/volume'; import { structureUnion, structureSubtract } from '../../mol-model/structure/query/utils/structure-set'; import { Location } from '../../mol-model/structure/structure/element/location'; import { MmcifFormat } from '../../mol-model-formats/structure/mmcif'; @@ -799,16 +800,20 @@ export class ReDNATCOMspViewer { return this.has('structure', '', BaseRef); } - async loadStructure(data: string, type: 'pdb'|'cif', display: Display) { + async loadStructure( + coords: { data: string, type: 'pdb'|'cif' }, + densityMap: { data: Uint8Array, type: 'ccp4'|'dsn6' }|null, + display: Display + ) { // TODO: Remove the currently loaded structure const chainColor = Color(display.chainColor); const waterColor = Color(display.waterColor); - const b = (t => type === 'pdb' + const b = (t => coords.type === 'pdb' ? t.apply(StateTransforms.Model.TrajectoryFromPDB, {}, { ref: IDs.ID('trajectory', '', BaseRef) }) : t.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif, {}, { ref: IDs.ID('trajectory', '', BaseRef) }) - )(this.plugin.state.data.build().toRoot().apply(RawData, { data }, { ref: IDs.ID('data', '', BaseRef) })) + )(this.plugin.state.data.build().toRoot().apply(RawData, { data: coords.data }, { ref: IDs.ID('data', '', BaseRef) })) .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: display.modelNumber ? display.modelNumber - 1 : 0 }, { ref: IDs.ID('model', '', BaseRef) }) .apply(StateTransforms.Model.StructureFromModel, {}, { ref: IDs.ID('entire-structure', '', BaseRef) }) // Extract substructures @@ -885,6 +890,38 @@ export class ReDNATCOMspViewer { await b3.commit(); + // Load density map, if any + if (densityMap) { + const [ParseTransform, VolumeTransform] = densityMap.type === 'ccp4' + ? [StateTransforms.Data.ParseCcp4, StateTransforms.Volume.VolumeFromCcp4] + : [StateTransforms.Data.ParseDsn6, StateTransforms.Volume.VolumeFromDsn6]; + const b4 = this.plugin.state.data.build(); + b4.toRoot() + .apply(RawData, { data: densityMap.data }, { ref: IDs.DensityID('data', BaseRef) }) + .apply(ParseTransform) + .apply(VolumeTransform, {}, { ref: IDs.DensityID('volume', BaseRef) }) + .apply( + StateTransforms.Representation.VolumeRepresentation3D, + { + type: { + name: 'isosurface', + params: { + alpha: 0.5, + visuals: ['wireframe'], + sizeFactor: 0.75, + } + }, + colorTheme: { + name: 'uniform', + params: { value: Color(0x000000) }, + }, + }, + { ref: IDs.DensityID('visual', BaseRef) } + ); + + await b4.commit(); + } + this.haveMultipleModels = this.getModelCount() > 1; const ntcInfo = this.gatherStepInfo();