diff --git a/src/apps/structure-info/volume.ts b/src/apps/structure-info/volume.ts index ef38fcb190d1a90a8855321319ea18063188198c..cfedb46e9e4a7d520469ca3b1206d1992a0d5522 100644 --- a/src/apps/structure-info/volume.ts +++ b/src/apps/structure-info/volume.ts @@ -8,38 +8,36 @@ import * as fs from 'fs'; import * as argparse from 'argparse'; import * as util from 'util'; -import { VolumeData, VolumeIsoValue } from '../../mol-model/volume'; +import { Volume } from '../../mol-model/volume'; import { downloadCif } from './helpers'; import { CIF } from '../../mol-io/reader/cif'; -import { DensityServer_Data_Database } from '../../mol-io/reader/cif/schema/density-server'; import { Table } from '../../mol-data/db'; import { StringBuilder } from '../../mol-util'; import { Task } from '../../mol-task'; import { createVolumeIsosurfaceMesh } from '../../mol-repr/volume/isosurface'; import { Theme } from '../../mol-theme/theme'; -import { volumeFromDensityServerData } from '../../mol-model-formats/volume/density-server'; +import { volumeFromDensityServerData, DscifFormat } from '../../mol-model-formats/volume/density-server'; require('util.promisify').shim(); const writeFileAsync = util.promisify(fs.writeFile); -type Volume = { source: DensityServer_Data_Database, volume: VolumeData } - async function getVolume(url: string): Promise<Volume> { const cif = await downloadCif(url, true); const data = CIF.schema.densityServer(cif.blocks[1]); - return { source: data, volume: await volumeFromDensityServerData(data).run() }; + return await volumeFromDensityServerData(data).run(); } -function print(data: Volume) { - const { volume_data_3d_info } = data.source; +function print(volume: Volume) { + if (!DscifFormat.is(volume.sourceData)) return; + const { volume_data_3d_info } = volume.sourceData.data; const row = Table.getRow(volume_data_3d_info, 0); console.log(row); - if (data.volume.transform) console.log(data.volume.transform); - console.log(data.volume.dataStats); + console.log(volume.grid.transform); + console.log(volume.grid.stats); } -async function doMesh(data: Volume, filename: string) { - const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, data.volume, Theme.createEmpty(), { isoValue: VolumeIsoValue.absolute(1.5) } )).run(); +async function doMesh(volume: Volume, filename: string) { + const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) } )).run(); console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount }); // Export the mesh in OBJ format. diff --git a/src/extensions/cellpack/property.ts b/src/extensions/cellpack/property.ts index 700776fea1689c23bb2d4c3c0b76b28a0b03ee07..56e58cfb26c21b719ac79c5344c0effbfc909c33 100644 --- a/src/extensions/cellpack/property.ts +++ b/src/extensions/cellpack/property.ts @@ -5,9 +5,10 @@ */ import { CustomStructureProperty } from '../../mol-model-props/common/custom-structure-property'; -import { Structure, CustomPropertyDescriptor } from '../../mol-model/structure'; +import { Structure } from '../../mol-model/structure'; import { CustomProperty } from '../../mol-model-props/common/custom-property'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export type CellPackInfoValue = { packingsCount: number diff --git a/src/extensions/pdbe/preferred-assembly.ts b/src/extensions/pdbe/preferred-assembly.ts index 52a2d3c3218cb7e82f803bce135ed94f1ceb5da7..f4a11f08bdd103c1d969d8f5403653cc85b5198c 100644 --- a/src/extensions/pdbe/preferred-assembly.ts +++ b/src/extensions/pdbe/preferred-assembly.ts @@ -7,9 +7,10 @@ import { Column, Table } from '../../mol-data/db'; import { toTable } from '../../mol-io/reader/cif/schema'; import { CifWriter } from '../../mol-io/writer/cif'; -import { Model, CustomPropertyDescriptor } from '../../mol-model/structure'; +import { Model } from '../../mol-model/structure'; import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry'; import { MmcifFormat } from '../../mol-model-formats/structure/mmcif'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export namespace PDBePreferredAssembly { export type Property = string diff --git a/src/extensions/pdbe/struct-ref-domain.ts b/src/extensions/pdbe/struct-ref-domain.ts index 4b025f55230860d427b7c6be975b672e134d3881..c92a385b4984c10f73ed9e166ccf62a765238294 100644 --- a/src/extensions/pdbe/struct-ref-domain.ts +++ b/src/extensions/pdbe/struct-ref-domain.ts @@ -7,9 +7,10 @@ import { Column, Table } from '../../mol-data/db'; import { toTable } from '../../mol-io/reader/cif/schema'; import { CifWriter } from '../../mol-io/writer/cif'; -import { Model, CustomPropertyDescriptor } from '../../mol-model/structure'; +import { Model } from '../../mol-model/structure'; import { PropertyWrapper } from '../../mol-model-props/common/wrapper'; import { MmcifFormat } from '../../mol-model-formats/structure/mmcif'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export namespace PDBeStructRefDomain { export type Property = PropertyWrapper<Table<Schema['pdbe_struct_ref_domain']> | undefined> diff --git a/src/extensions/pdbe/structure-quality-report/prop.ts b/src/extensions/pdbe/structure-quality-report/prop.ts index e51f875867f89598a96b3e1dd063f0429c36b1ea..e1342d51b9abfe07a347bd4afcb9258b04ba0ac0 100644 --- a/src/extensions/pdbe/structure-quality-report/prop.ts +++ b/src/extensions/pdbe/structure-quality-report/prop.ts @@ -9,7 +9,7 @@ import { Column, Table } from '../../../mol-data/db'; import { toTable } from '../../../mol-io/reader/cif/schema'; import { mmCIF_residueId_schema } from '../../../mol-io/reader/cif/schema/mmcif-extras'; import { CifWriter } from '../../../mol-io/writer/cif'; -import { Model, CustomPropertyDescriptor, ResidueIndex, Unit, IndexedCustomProperty } from '../../../mol-model/structure'; +import { Model, ResidueIndex, Unit, IndexedCustomProperty } from '../../../mol-model/structure'; import { residueIdFields } from '../../../mol-model/structure/export/categories/atom_site'; import { StructureElement, CifExportContext, Structure } from '../../../mol-model/structure/structure'; import { CustomPropSymbol } from '../../../mol-script/language/symbol'; @@ -22,6 +22,7 @@ import { PropertyWrapper } from '../../../mol-model-props/common/wrapper'; import { CustomProperty } from '../../../mol-model-props/common/custom-property'; import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property'; import { Asset } from '../../../mol-util/assets'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; export { StructureQualityReport }; diff --git a/src/extensions/rcsb/assembly-symmetry/prop.ts b/src/extensions/rcsb/assembly-symmetry/prop.ts index 7bd1286448a08726257d2a3604adea9b8cc6f43f..c88daa19ab72297f9f86685d8263a7187beb2eed 100644 --- a/src/extensions/rcsb/assembly-symmetry/prop.ts +++ b/src/extensions/rcsb/assembly-symmetry/prop.ts @@ -8,7 +8,7 @@ import { AssemblySymmetryQuery, AssemblySymmetryQueryVariables } from '../graphq import query from '../graphql/symmetry.gql'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { CustomPropertyDescriptor, Structure, Model, StructureSelection, QueryContext } from '../../../mol-model/structure'; +import { Structure, Model, StructureSelection, QueryContext } from '../../../mol-model/structure'; import { Database as _Database, Column } from '../../../mol-data/db'; import { GraphQLClient } from '../../../mol-util/graphql-client'; import { CustomProperty } from '../../../mol-model-props/common/custom-property'; @@ -19,6 +19,7 @@ import { ReadonlyVec3 } from '../../../mol-math/linear-algebra/3d/vec3'; import { SetUtils } from '../../../mol-util/set'; import { MolScriptBuilder as MS } from '../../../mol-script/language/builder'; import { compile } from '../../../mol-script/runtime/query/compiler'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; const BiologicalAssemblyNames = new Set([ 'author_and_software_defined_assembly', diff --git a/src/extensions/rcsb/validation-report/prop.ts b/src/extensions/rcsb/validation-report/prop.ts index a17bc6fd1feeab3b336e8057bbc93af2a1f8f825..aec4ea9a2956f4f6e1d3fa84129c788faeb1a840 100644 --- a/src/extensions/rcsb/validation-report/prop.ts +++ b/src/extensions/rcsb/validation-report/prop.ts @@ -5,7 +5,7 @@ */ import { ParamDefinition as PD } from '../../../mol-util/param-definition'; -import { CustomPropertyDescriptor, Structure, Unit } from '../../../mol-model/structure'; +import { Structure, Unit } from '../../../mol-model/structure'; import { CustomProperty } from '../../../mol-model-props/common/custom-property'; import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property'; import { Model, ElementIndex, ResidueIndex } from '../../../mol-model/structure/model'; @@ -21,6 +21,7 @@ import { QuerySymbolRuntime } from '../../../mol-script/runtime/query/compiler'; import { CustomPropSymbol } from '../../../mol-script/language/symbol'; import Type from '../../../mol-script/language/type'; import { Asset } from '../../../mol-util/assets'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; export { ValidationReport }; diff --git a/src/mol-model-formats/structure/basic/parser.ts b/src/mol-model-formats/structure/basic/parser.ts index bf7129e2a08e21145a50020e227c1f8e6aac6ee2..8773e4e2a7d776c3f39e5630fb443942d8434424 100644 --- a/src/mol-model-formats/structure/basic/parser.ts +++ b/src/mol-model-formats/structure/basic/parser.ts @@ -10,7 +10,7 @@ import { RuntimeContext } from '../../../mol-task'; import UUID from '../../../mol-util/uuid'; import { Model } from '../../../mol-model/structure/model/model'; import { Entities } from '../../../mol-model/structure/model/properties/common'; -import { CustomProperties } from '../../../mol-model/structure'; +import { CustomProperties } from '../../../mol-model/custom-property'; import { getAtomicHierarchyAndConformation } from './atomic'; import { getCoarse, EmptyCoarse, CoarseData } from './coarse'; import { getSequence } from './sequence'; diff --git a/src/mol-model-formats/structure/common/property.ts b/src/mol-model-formats/structure/common/property.ts index cbc1718f8a99beb821d9f81e0b947f05f982341a..63709daac1bbcfe8fb01c35602cc4fcc39fb09ae 100644 --- a/src/mol-model-formats/structure/common/property.ts +++ b/src/mol-model-formats/structure/common/property.ts @@ -4,8 +4,9 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CustomPropertyDescriptor, Model } from '../../../mol-model/structure'; +import { Model } from '../../../mol-model/structure'; import { ModelFormat } from '../../format'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; class FormatRegistry<T> { private map = new Map<ModelFormat['kind'], (model: Model) => T | undefined>() diff --git a/src/mol-model-formats/structure/property/anisotropic.ts b/src/mol-model-formats/structure/property/anisotropic.ts index 16cb3591e646ef9084ae255d4deeecc989bf3e5e..f6cc407d15d2c51ffd9319b82755f0fc50a2e0e6 100644 --- a/src/mol-model-formats/structure/property/anisotropic.ts +++ b/src/mol-model-formats/structure/property/anisotropic.ts @@ -5,7 +5,7 @@ */ import { Table, Column } from '../../../mol-data/db'; -import { CustomPropertyDescriptor } from '../../../mol-model/structure'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; import { mmCIF_Schema } from '../../../mol-io/reader/cif/schema/mmcif'; import { CifWriter } from '../../../mol-io/writer/cif'; import { FormatPropertyProvider } from '../common/property'; diff --git a/src/mol-model-formats/structure/property/bonds/comp.ts b/src/mol-model-formats/structure/property/bonds/comp.ts index ed510b10fa01f68e7efaf73a43e6720ef16dd331..b30e9dac92f4e5c62ec908ca22af7dc5a3485d3b 100644 --- a/src/mol-model-formats/structure/property/bonds/comp.ts +++ b/src/mol-model-formats/structure/property/bonds/comp.ts @@ -7,7 +7,7 @@ import { Model } from '../../../../mol-model/structure/model/model'; import { BondType } from '../../../../mol-model/structure/model/types'; -import { CustomPropertyDescriptor } from '../../../../mol-model/structure'; +import { CustomPropertyDescriptor } from '../../../../mol-model/custom-property'; import { mmCIF_Schema } from '../../../../mol-io/reader/cif/schema/mmcif'; import { CifWriter } from '../../../../mol-io/writer/cif'; import { Table } from '../../../../mol-data/db'; diff --git a/src/mol-model-formats/structure/property/bonds/index-pair.ts b/src/mol-model-formats/structure/property/bonds/index-pair.ts index 7a09535eb37b4026a4055d0c7b7c7a91080528e1..485fe8d737818499cc809bdf4c5eb8a957da7dca 100644 --- a/src/mol-model-formats/structure/property/bonds/index-pair.ts +++ b/src/mol-model-formats/structure/property/bonds/index-pair.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CustomPropertyDescriptor } from '../../../../mol-model/structure'; +import { CustomPropertyDescriptor } from '../../../../mol-model/custom-property'; import { IntAdjacencyGraph } from '../../../../mol-math/graph'; import { Column } from '../../../../mol-data/db'; import { FormatPropertyProvider } from '../../common/property'; diff --git a/src/mol-model-formats/structure/property/bonds/struct_conn.ts b/src/mol-model-formats/structure/property/bonds/struct_conn.ts index 494ac4d2b6c0c62c28847de18753189b9730bbcf..ae48045cdadc8a6a6f9f4c1bf3708857e6d3697c 100644 --- a/src/mol-model-formats/structure/property/bonds/struct_conn.ts +++ b/src/mol-model-formats/structure/property/bonds/struct_conn.ts @@ -9,7 +9,7 @@ import { Model } from '../../../../mol-model/structure/model/model'; import { Structure } from '../../../../mol-model/structure'; import { BondType } from '../../../../mol-model/structure/model/types'; import { Column, Table } from '../../../../mol-data/db'; -import { CustomPropertyDescriptor } from '../../../../mol-model/structure'; +import { CustomPropertyDescriptor } from '../../../../mol-model/custom-property'; import { mmCIF_Schema } from '../../../../mol-io/reader/cif/schema/mmcif'; import { SortedArray } from '../../../../mol-data/int'; import { CifWriter } from '../../../../mol-io/writer/cif'; diff --git a/src/mol-model-formats/structure/property/secondary-structure.ts b/src/mol-model-formats/structure/property/secondary-structure.ts index e79e9a321900da33f4def2872497d8a7b0d2b9f0..616cd18bf2a6fbbf5eabe1a7475b6f1914537467 100644 --- a/src/mol-model-formats/structure/property/secondary-structure.ts +++ b/src/mol-model-formats/structure/property/secondary-structure.ts @@ -13,7 +13,7 @@ import { SecondaryStructure } from '../../../mol-model/structure/model/propertie import { Column, Table } from '../../../mol-data/db'; import { ChainIndex, ResidueIndex } from '../../../mol-model/structure/model/indexing'; import { FormatPropertyProvider } from '../common/property'; -import { CustomPropertyDescriptor } from '../../../mol-model/structure'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; export { ModelSecondaryStructure }; diff --git a/src/mol-model-formats/structure/property/symmetry.ts b/src/mol-model-formats/structure/property/symmetry.ts index 75330f6f657469b770f2345054864d98642d2f65..22f610e86430653c9cca30c4fc34305ee1b62e7a 100644 --- a/src/mol-model-formats/structure/property/symmetry.ts +++ b/src/mol-model-formats/structure/property/symmetry.ts @@ -10,7 +10,7 @@ import { Spacegroup, SpacegroupCell, SymmetryOperator } from '../../../mol-math/ import { Tensor, Vec3, Mat3 } from '../../../mol-math/linear-algebra'; import { Symmetry } from '../../../mol-model/structure/model/properties/symmetry'; import { createAssemblies } from './assembly'; -import { CustomPropertyDescriptor } from '../../../mol-model/structure'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; import { FormatPropertyProvider } from '../common/property'; import { Table } from '../../../mol-data/db'; diff --git a/src/mol-model-formats/volume/ccp4.ts b/src/mol-model-formats/volume/ccp4.ts index 8ccf5ad7aa02d9261492d427211a96a534a8a489..2a05fce5e6762e56abaa1fa7c446ff80f70325c3 100644 --- a/src/mol-model-formats/volume/ccp4.ts +++ b/src/mol-model-formats/volume/ccp4.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { VolumeData } from '../../mol-model/volume/data'; +import { Volume } from '../../mol-model/volume'; import { Task } from '../../mol-task'; import { SpacegroupCell, Box3D } from '../../mol-math/geometry'; import { Tensor, Vec3 } from '../../mol-math/linear-algebra'; @@ -14,6 +14,7 @@ import { getCcp4ValueType } from '../../mol-io/reader/ccp4/parser'; import { TypedArrayValueType } from '../../mol-io/common/typed-array'; import { arrayMin, arrayRms, arrayMean, arrayMax } from '../../mol-util/array'; import { ModelFormat } from '../format'; +import { CustomProperties } from '../../mol-model/custom-property'; /** When available (e.g. in MRC files) use ORIGIN records instead of N[CRS]START */ export function getCcp4Origin(header: Ccp4Header): Vec3 { @@ -39,8 +40,8 @@ function getTypedArrayCtor(header: Ccp4Header) { throw Error(`${valueType} is not a supported value format.`); } -export function volumeFromCcp4(source: Ccp4File, params?: { voxelSize?: Vec3, offset?: Vec3, label?: string }): Task<VolumeData> { - return Task.create<VolumeData>('Create Volume Data', async ctx => { +export function volumeFromCcp4(source: Ccp4File, params?: { voxelSize?: Vec3, offset?: Vec3, label?: string }): Task<Volume> { + return Task.create<Volume>('Create Volume', async ctx => { const { header, values } = source; const size = Vec3.create(header.xLength, header.yLength, header.zLength); if (params && params.voxelSize) Vec3.mul(size, size, params.voxelSize); @@ -69,15 +70,19 @@ export function volumeFromCcp4(source: Ccp4File, params?: { voxelSize?: Vec3, of return { label: params?.label, - transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) }, - data, - dataStats: { - min: isNaN(header.AMIN) ? arrayMin(values) : header.AMIN, - max: isNaN(header.AMAX) ? arrayMax(values) : header.AMAX, - mean: isNaN(header.AMEAN) ? arrayMean(values) : header.AMEAN, - sigma: (isNaN(header.ARMS) || header.ARMS === 0) ? arrayRms(values) : header.ARMS + grid: { + transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) }, + cells: data, + stats: { + min: isNaN(header.AMIN) ? arrayMin(values) : header.AMIN, + max: isNaN(header.AMAX) ? arrayMax(values) : header.AMAX, + mean: isNaN(header.AMEAN) ? arrayMean(values) : header.AMEAN, + sigma: (isNaN(header.ARMS) || header.ARMS === 0) ? arrayRms(values) : header.ARMS + }, }, - sourceData: Ccp4Format.create(source) + sourceData: Ccp4Format.create(source), + customProperties: new CustomProperties(), + _propertyData: Object.create(null), }; }); } diff --git a/src/mol-model-formats/volume/cube.ts b/src/mol-model-formats/volume/cube.ts index 416944d77a6e44ff6ef4d399b5f5fd23ef672f58..4db35bee33106fb05e7f2eabc1bc7e83b3b65056 100644 --- a/src/mol-model-formats/volume/cube.ts +++ b/src/mol-model-formats/volume/cube.ts @@ -6,13 +6,14 @@ import { CubeFile } from '../../mol-io/reader/cube/parser'; import { Mat4, Tensor } from '../../mol-math/linear-algebra'; -import { VolumeData } from '../../mol-model/volume/data'; +import { Volume } from '../../mol-model/volume'; import { Task } from '../../mol-task'; import { arrayMax, arrayMean, arrayMin, arrayRms } from '../../mol-util/array'; import { ModelFormat } from '../format'; +import { CustomProperties } from '../../mol-model/custom-property'; -export function volumeFromCube(source: CubeFile, params?: { dataIndex?: number, label?: string }): Task<VolumeData> { - return Task.create<VolumeData>('Create Volume Data', async () => { +export function volumeFromCube(source: CubeFile, params?: { dataIndex?: number, label?: string }): Task<Volume> { + return Task.create<Volume>('Create Volume', async () => { const { header, values: sourceValues } = source; const space = Tensor.Space(header.dim, [0, 1, 2], Float64Array); @@ -45,15 +46,19 @@ export function volumeFromCube(source: CubeFile, params?: { dataIndex?: number, return { label: params?.label, - transform: { kind: 'matrix', matrix }, - data, - dataStats: { - min: arrayMin(values), - max: arrayMax(values), - mean: arrayMean(values), - sigma: arrayRms(values) + grid: { + transform: { kind: 'matrix', matrix }, + cells: data, + stats: { + min: arrayMin(values), + max: arrayMax(values), + mean: arrayMean(values), + sigma: arrayRms(values) + }, }, - sourceData: CubeFormat.create(source) + sourceData: CubeFormat.create(source), + customProperties: new CustomProperties(), + _propertyData: Object.create(null), }; }); } diff --git a/src/mol-model-formats/volume/density-server.ts b/src/mol-model-formats/volume/density-server.ts index bb35f01408b9032a3c4bf3c8cf96fe8bdd809809..ad2a5ccd649f480d375cb88538cc937e72bfce30 100644 --- a/src/mol-model-formats/volume/density-server.ts +++ b/src/mol-model-formats/volume/density-server.ts @@ -5,14 +5,15 @@ */ import { DensityServer_Data_Database } from '../../mol-io/reader/cif/schema/density-server'; -import { VolumeData } from '../../mol-model/volume/data'; +import { Volume } from '../../mol-model/volume'; import { Task } from '../../mol-task'; import { SpacegroupCell, Box3D } from '../../mol-math/geometry'; import { Tensor, Vec3 } from '../../mol-math/linear-algebra'; import { ModelFormat } from '../format'; +import { CustomProperties } from '../../mol-model/custom-property'; -export function volumeFromDensityServerData(source: DensityServer_Data_Database): Task<VolumeData> { - return Task.create<VolumeData>('Create Volume Data', async ctx => { +export function volumeFromDensityServerData(source: DensityServer_Data_Database): Task<Volume> { + return Task.create<Volume>('Create Volume', async ctx => { const { volume_data_3d_info: info, volume_data_3d: values } = source; const cell = SpacegroupCell.create( info.spacegroup_number.value(0), @@ -35,15 +36,19 @@ export function volumeFromDensityServerData(source: DensityServer_Data_Database) const dimensions = Vec3.ofArray(normalizeOrder(info.dimensions.value(0))); return { - transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin, Vec3.add(Vec3.zero(), origin, dimensions)) }, - data, - dataStats: { - min: info.min_sampled.value(0), - max: info.max_sampled.value(0), - mean: info.mean_sampled.value(0), - sigma: info.sigma_sampled.value(0) + grid: { + transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin, Vec3.add(Vec3.zero(), origin, dimensions)) }, + cells: data, + stats: { + min: info.min_sampled.value(0), + max: info.max_sampled.value(0), + mean: info.mean_sampled.value(0), + sigma: info.sigma_sampled.value(0) + }, }, - sourceData: DscifFormat.create(source) + sourceData: DscifFormat.create(source), + customProperties: new CustomProperties(), + _propertyData: Object.create(null), }; }); } diff --git a/src/mol-model-formats/volume/dsn6.ts b/src/mol-model-formats/volume/dsn6.ts index f6ef76cd6da544664d58060905409f22b83a47f4..b49ed46f10e2a1c0011225373d3b2d4ff464a19d 100644 --- a/src/mol-model-formats/volume/dsn6.ts +++ b/src/mol-model-formats/volume/dsn6.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { VolumeData } from '../../mol-model/volume/data'; +import { Volume } from '../../mol-model/volume'; import { Task } from '../../mol-task'; import { SpacegroupCell, Box3D } from '../../mol-math/geometry'; import { Tensor, Vec3 } from '../../mol-math/linear-algebra'; @@ -12,9 +12,10 @@ import { degToRad } from '../../mol-math/misc'; import { Dsn6File } from '../../mol-io/reader/dsn6/schema'; import { arrayMin, arrayMax, arrayMean, arrayRms } from '../../mol-util/array'; import { ModelFormat } from '../format'; +import { CustomProperties } from '../../mol-model/custom-property'; -export function volumeFromDsn6(source: Dsn6File, params?: { voxelSize?: Vec3, label?: string }): Task<VolumeData> { - return Task.create<VolumeData>('Create Volume Data', async ctx => { +export function volumeFromDsn6(source: Dsn6File, params?: { voxelSize?: Vec3, label?: string }): Task<Volume> { + return Task.create<Volume>('Create Volume', async ctx => { const { header, values } = source; const size = Vec3.create(header.xlen, header.ylen, header.zlen); if (params && params.voxelSize) Vec3.mul(size, size, params.voxelSize); @@ -34,15 +35,19 @@ export function volumeFromDsn6(source: Dsn6File, params?: { voxelSize?: Vec3, la return { label: params?.label, - transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) }, - data, - dataStats: { - min: arrayMin(values), - max: arrayMax(values), - mean: arrayMean(values), - sigma: header.sigma !== undefined ? header.sigma : arrayRms(values) + grid: { + transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) }, + cells: data, + stats: { + min: arrayMin(values), + max: arrayMax(values), + mean: arrayMean(values), + sigma: header.sigma !== undefined ? header.sigma : arrayRms(values) + }, }, - sourceData: Dsn6Format.create(source) + sourceData: Dsn6Format.create(source), + customProperties: new CustomProperties(), + _propertyData: Object.create(null), }; }); } diff --git a/src/mol-model-formats/volume/dx.ts b/src/mol-model-formats/volume/dx.ts index 2ec9007ca7b601639f74db0d8486f65816c524ef..08424a9232d83211778827a6942c0064560ce916 100644 --- a/src/mol-model-formats/volume/dx.ts +++ b/src/mol-model-formats/volume/dx.ts @@ -6,13 +6,14 @@ import { DxFile } from '../../mol-io/reader/dx/parser'; import { Mat4, Tensor } from '../../mol-math/linear-algebra'; -import { VolumeData } from '../../mol-model/volume/data'; +import { Volume } from '../../mol-model/volume'; import { Task } from '../../mol-task'; import { arrayMax, arrayMean, arrayMin, arrayRms } from '../../mol-util/array'; import { ModelFormat } from '../format'; +import { CustomProperties } from '../../mol-model/custom-property'; -export function volumeFromDx(source: DxFile, params?: { label?: string }): Task<VolumeData> { - return Task.create<VolumeData>('Create Volume Data', async () => { +export function volumeFromDx(source: DxFile, params?: { label?: string }): Task<Volume> { + return Task.create<Volume>('Create Volume', async () => { const { header, values } = source; const space = Tensor.Space(header.dim, [0, 1, 2], Float64Array); const data = Tensor.create(space, Tensor.Data1(values)); @@ -22,15 +23,19 @@ export function volumeFromDx(source: DxFile, params?: { label?: string }): Task< return { label: params?.label, - transform: { kind: 'matrix', matrix }, - data, - dataStats: { - min: arrayMin(values), - max: arrayMax(values), - mean: arrayMean(values), - sigma: arrayRms(values) + grid: { + transform: { kind: 'matrix', matrix }, + cells: data, + stats: { + min: arrayMin(values), + max: arrayMax(values), + mean: arrayMean(values), + sigma: arrayRms(values) + }, }, - sourceData: DxFormat.create(source) + sourceData: DxFormat.create(source), + customProperties: new CustomProperties(), + _propertyData: Object.create(null), }; }); } diff --git a/src/mol-model-props/common/custom-element-property.ts b/src/mol-model-props/common/custom-element-property.ts index a54b47798f5b1773653c19d9da4e8ba588d20eb8..afd22d801489a3736e89fb447052c17947750ded 100644 --- a/src/mol-model-props/common/custom-element-property.ts +++ b/src/mol-model-props/common/custom-element-property.ts @@ -5,7 +5,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ElementIndex, Model, CustomPropertyDescriptor } from '../../mol-model/structure'; +import { ElementIndex, Model } from '../../mol-model/structure'; import { StructureElement } from '../../mol-model/structure/structure'; import { Location } from '../../mol-model/location'; import { ThemeDataContext } from '../../mol-theme/theme'; @@ -16,6 +16,7 @@ import { OrderedSet } from '../../mol-data/int'; import { CustomModelProperty } from './custom-model-property'; import { CustomProperty } from './custom-property'; import { LociLabelProvider } from '../../mol-plugin-state/manager/loci-label'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export { CustomElementProperty }; diff --git a/src/mol-model-props/common/custom-model-property.ts b/src/mol-model-props/common/custom-model-property.ts index 2e8f14f4c99e5369659b4a5cc9318259c3366e8c..75ce00d8f16a4179e830507728aa5935577b5017 100644 --- a/src/mol-model-props/common/custom-model-property.ts +++ b/src/mol-model-props/common/custom-model-property.ts @@ -4,10 +4,11 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CustomPropertyDescriptor, Model } from '../../mol-model/structure'; +import { Model } from '../../mol-model/structure'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ValueBox } from '../../mol-util'; import { CustomProperty } from './custom-property'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export { CustomModelProperty }; diff --git a/src/mol-model-props/common/custom-property.ts b/src/mol-model-props/common/custom-property.ts index 5aafd392f155b620a318513e7777eb3ba869f042..22fdaf35310f3811aca8830a3114fc12f66a446a 100644 --- a/src/mol-model-props/common/custom-property.ts +++ b/src/mol-model-props/common/custom-property.ts @@ -5,7 +5,7 @@ */ import { RuntimeContext } from '../../mol-task'; -import { CustomPropertyDescriptor } from '../../mol-model/structure'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ValueBox } from '../../mol-util'; import { OrderedMap } from 'immutable'; diff --git a/src/mol-model-props/common/custom-structure-property.ts b/src/mol-model-props/common/custom-structure-property.ts index fefa5f174fe1fe826aa2323ed62668323af76788..8f7a758b5a55ecb129a334b60f7aebb77ed4d569 100644 --- a/src/mol-model-props/common/custom-structure-property.ts +++ b/src/mol-model-props/common/custom-structure-property.ts @@ -4,10 +4,11 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CustomPropertyDescriptor, Structure } from '../../mol-model/structure'; +import { Structure } from '../../mol-model/structure'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ValueBox } from '../../mol-util'; import { CustomProperty } from './custom-property'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export { CustomStructureProperty }; diff --git a/src/mol-model-props/computed/accessible-surface-area.ts b/src/mol-model-props/computed/accessible-surface-area.ts index a12020eb6128a0bcd40cd260b1018c5593a60753..009754df87eaf2c956712d7d49757c02a5b93d16 100644 --- a/src/mol-model-props/computed/accessible-surface-area.ts +++ b/src/mol-model-props/computed/accessible-surface-area.ts @@ -7,12 +7,13 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ShrakeRupleyComputationParams, AccessibleSurfaceArea } from './accessible-surface-area/shrake-rupley'; -import { Structure, CustomPropertyDescriptor, Unit } from '../../mol-model/structure'; +import { Structure, Unit } from '../../mol-model/structure'; import { CustomStructureProperty } from '../common/custom-structure-property'; import { CustomProperty } from '../common/custom-property'; import { QuerySymbolRuntime } from '../../mol-script/runtime/query/compiler'; import { CustomPropSymbol } from '../../mol-script/language/symbol'; import Type from '../../mol-script/language/type'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export const AccessibleSurfaceAreaParams = { ...ShrakeRupleyComputationParams diff --git a/src/mol-model-props/computed/interactions.ts b/src/mol-model-props/computed/interactions.ts index bba29c192a3b0b46046c3b0102024df6afddc26a..e299e9f9692be384874a0ae63e85ef999b5cd9ba 100644 --- a/src/mol-model-props/computed/interactions.ts +++ b/src/mol-model-props/computed/interactions.ts @@ -4,11 +4,12 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CustomPropertyDescriptor, Structure } from '../../mol-model/structure'; +import { Structure } from '../../mol-model/structure'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { computeInteractions, Interactions, InteractionsParams as _InteractionsParams } from './interactions/interactions'; import { CustomStructureProperty } from '../common/custom-structure-property'; import { CustomProperty } from '../common/custom-property'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export const InteractionsParams = { ..._InteractionsParams diff --git a/src/mol-model-props/computed/secondary-structure.ts b/src/mol-model-props/computed/secondary-structure.ts index 383703dfb011bab15855f8824a2cd9728d8997c6..68b790452b9eebdb9311d9a74598af90266ec6ed 100644 --- a/src/mol-model-props/computed/secondary-structure.ts +++ b/src/mol-model-props/computed/secondary-structure.ts @@ -12,7 +12,7 @@ import { Unit } from '../../mol-model/structure/structure'; import { CustomStructureProperty } from '../common/custom-structure-property'; import { CustomProperty } from '../common/custom-property'; import { ModelSecondaryStructure } from '../../mol-model-formats/structure/property/secondary-structure'; -import { CustomPropertyDescriptor } from '../../mol-model/structure/common/custom-property'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; import { Model } from '../../mol-model/structure/model'; function getSecondaryStructureParams(data?: Structure) { diff --git a/src/mol-model-props/computed/valence-model.ts b/src/mol-model-props/computed/valence-model.ts index 8fa1d24ba17bb44fa3ca30e39d4b6aa70fc638ec..b1fb1959fd25949d4458e01297d58e285ef2e293 100644 --- a/src/mol-model-props/computed/valence-model.ts +++ b/src/mol-model-props/computed/valence-model.ts @@ -4,11 +4,12 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CustomPropertyDescriptor, Structure } from '../../mol-model/structure'; +import { Structure } from '../../mol-model/structure'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { calcValenceModel, ValenceModel, ValenceModelParams as _ValenceModelParams } from './chemistry/valence-model'; import { CustomStructureProperty } from '../common/custom-structure-property'; import { CustomProperty } from '../common/custom-property'; +import { CustomPropertyDescriptor } from '../../mol-model/custom-property'; export const ValenceModelParams = { ..._ValenceModelParams diff --git a/src/mol-model-props/integrative/cross-link-restraint/format.ts b/src/mol-model-props/integrative/cross-link-restraint/format.ts index b4e2704e3323abd4f22744d14fb5e3ae1f9eba08..3d65c86b6f1cff33ee6606b9f5995a574b148847 100644 --- a/src/mol-model-props/integrative/cross-link-restraint/format.ts +++ b/src/mol-model-props/integrative/cross-link-restraint/format.ts @@ -7,9 +7,10 @@ import { Model } from '../../../mol-model/structure/model/model'; import { Table } from '../../../mol-data/db'; import { mmCIF_Schema } from '../../../mol-io/reader/cif/schema/mmcif'; -import { Unit, CustomPropertyDescriptor } from '../../../mol-model/structure'; +import { Unit } from '../../../mol-model/structure'; import { ElementIndex } from '../../../mol-model/structure/model/indexing'; import { FormatPropertyProvider } from '../../../mol-model-formats/structure/common/property'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; export { ModelCrossLinkRestraint }; diff --git a/src/mol-model-props/integrative/cross-link-restraint/property.ts b/src/mol-model-props/integrative/cross-link-restraint/property.ts index 8b7f07ee495dda32725b3f724c4b51295cded89a..1b2059173832cdb448fbf30be45d67558a62a09b 100644 --- a/src/mol-model-props/integrative/cross-link-restraint/property.ts +++ b/src/mol-model-props/integrative/cross-link-restraint/property.ts @@ -5,7 +5,7 @@ */ import { ModelCrossLinkRestraint } from './format'; -import { Unit, StructureElement, Structure, CustomPropertyDescriptor, Bond} from '../../../mol-model/structure'; +import { Unit, StructureElement, Structure, Bond} from '../../../mol-model/structure'; import { PairRestraints, PairRestraint } from '../pair-restraints'; import { CustomStructureProperty } from '../../common/custom-structure-property'; import { CustomProperty } from '../../common/custom-property'; @@ -15,6 +15,7 @@ import { Sphere3D } from '../../../mol-math/geometry'; import { CentroidHelper } from '../../../mol-math/geometry/centroid-helper'; import { bondLabel } from '../../../mol-theme/label'; import { Vec3 } from '../../../mol-math/linear-algebra'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; export type CrossLinkRestraintValue = PairRestraints<CrossLinkRestraint> diff --git a/src/mol-model/structure/common/custom-property.ts b/src/mol-model/custom-property.ts similarity index 90% rename from src/mol-model/structure/common/custom-property.ts rename to src/mol-model/custom-property.ts index 3c6723d768a82570d86941c5135ab6519c134c90..0bf52fa2cfc7a015742774d7cd857562ae19dee2 100644 --- a/src/mol-model/structure/common/custom-property.ts +++ b/src/mol-model/custom-property.ts @@ -5,11 +5,11 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CifWriter } from '../../../mol-io/writer/cif'; -import { CifExportContext } from '../export/mmcif'; -import { QuerySymbolRuntime } from '../../../mol-script/runtime/query/compiler'; -import { UUID } from '../../../mol-util'; -import { Asset } from '../../../mol-util/assets'; +import { CifWriter } from '../mol-io/writer/cif'; +import { CifExportContext } from './structure/export/mmcif'; +import { QuerySymbolRuntime } from '../mol-script/runtime/query/compiler'; +import { UUID } from '../mol-util'; +import { Asset } from '../mol-util/assets'; export { CustomPropertyDescriptor, CustomProperties }; diff --git a/src/mol-model/structure.ts b/src/mol-model/structure.ts index 1069f684fafcdee5f86a16dc8877d2f8d3350083..d8ab4a1a8c79065037c93708cc2864720beda46d 100644 --- a/src/mol-model/structure.ts +++ b/src/mol-model/structure.ts @@ -9,5 +9,4 @@ export * from './structure/coordinates'; export * from './structure/topology'; export * from './structure/model'; export * from './structure/structure'; -export * from './structure/query'; -export * from './structure/common/custom-property'; \ No newline at end of file +export * from './structure/query'; \ No newline at end of file diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index cbbbb2582947178d4cc2b1ae6fe44523b35ae98c..fffe06a4c05e0e8df131e053669fc36779f0424b 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -15,7 +15,7 @@ import { _chem_comp, _pdbx_chem_comp_identifier, _pdbx_nonpoly_scheme } from './ import { Model } from '../model'; import { getUniqueEntityIndicesFromStructures, copy_mmCif_category, copy_source_mmCifCategory } from './categories/utils'; import { _struct_asym, _entity_poly, _entity_poly_seq } from './categories/sequence'; -import { CustomPropertyDescriptor } from '../common/custom-property'; +import { CustomPropertyDescriptor } from '../../custom-property'; import { atom_site_operator_mapping } from './categories/atom_site_operator_mapping'; import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif'; diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts index 00e90d1c9c18ee29abea6000147e029a2054d306..8fe22966d28ef7ad0659a584dd3b254979051109 100644 --- a/src/mol-model/structure/model/model.ts +++ b/src/mol-model/structure/model/model.ts @@ -10,7 +10,7 @@ import StructureSequence from './properties/sequence'; import { AtomicHierarchy, AtomicConformation, AtomicRanges } from './properties/atomic'; import { CoarseHierarchy, CoarseConformation } from './properties/coarse'; import { Entities, ChemicalComponentMap, MissingResidues, StructAsymMap } from './properties/common'; -import { CustomProperties } from '../common/custom-property'; +import { CustomProperties } from '../../custom-property'; import { SaccharideComponentMap } from '../structure/carbohydrates/constants'; import { ModelFormat } from '../../../mol-model-formats/format'; import { calcModelCenter } from './util'; diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 05bee252c46352762c0364f5b24ed6098ae57e86..4e40ad996444d318bb3bc051ab59b6207d13053e 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -25,7 +25,7 @@ import { Vec3, Mat4 } from '../../../mol-math/linear-algebra'; import { idFactory } from '../../../mol-util/id-factory'; import { GridLookup3D } from '../../../mol-math/geometry'; import { UUID } from '../../../mol-util'; -import { CustomProperties } from '../common/custom-property'; +import { CustomProperties } from '../../custom-property'; import { AtomicHierarchy } from '../model/properties/atomic'; import { StructureSelection } from '../query/selection'; import { getBoundary } from '../../../mol-math/geometry/boundary'; diff --git a/src/mol-model/volume.ts b/src/mol-model/volume.ts index 70aad4db3d39bd24f02fb1cede4b3ec389d69824..f566b4be1baa69113884780c3b18758ab4289b74 100644 --- a/src/mol-model/volume.ts +++ b/src/mol-model/volume.ts @@ -1,7 +1,9 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2020 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> */ -export * from './volume/data'; \ No newline at end of file +export * from './volume/volume'; +export * from './volume/grid'; \ No newline at end of file diff --git a/src/mol-model/volume/data.ts b/src/mol-model/volume/data.ts deleted file mode 100644 index 2ab5681126a681ba73062b93fed4b485c2695fb1..0000000000000000000000000000000000000000 --- a/src/mol-model/volume/data.ts +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2018-2020 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> - */ - -import { SpacegroupCell, Box3D } from '../../mol-math/geometry'; -import { Tensor, Mat4, Vec3 } from '../../mol-math/linear-algebra'; -import { equalEps } from '../../mol-math/linear-algebra/3d/common'; -import { ModelFormat } from '../../mol-model-formats/format'; - -/** The basic unit cell that contains the data. */ -interface VolumeDataBase { - readonly label?: string, - readonly transform: { kind: 'spacegroup', cell: SpacegroupCell, fractionalBox: Box3D } | { kind: 'matrix', matrix: Mat4 }, - readonly data: Tensor, - readonly dataStats: Readonly<{ - min: number, - max: number, - mean: number, - sigma: number - }> - readonly sourceData: ModelFormat, -} - -interface VolumeData extends VolumeDataBase { - readonly colorVolume?: VolumeDataBase -} - -namespace VolumeData { - export const One: VolumeData = { - transform: { kind: 'matrix', matrix: Mat4.identity() }, - data: Tensor.create(Tensor.Space([1, 1, 1], [0, 1, 2]), Tensor.Data1([0])), - dataStats: { min: 0, max: 0, mean: 0, sigma: 0 }, - sourceData: { kind: '', data: '', name: '' } - }; - - const _scale = Mat4.zero(), _translate = Mat4.zero(); - export function getGridToCartesianTransform(volume: VolumeData) { - if (volume.transform.kind === 'matrix') { - return Mat4.copy(Mat4(), volume.transform.matrix); - } - - if (volume.transform.kind === 'spacegroup') { - const { data: { space } } = volume; - const scale = Mat4.fromScaling(_scale, Vec3.div(Vec3.zero(), Box3D.size(Vec3.zero(), volume.transform.fractionalBox), Vec3.ofArray(space.dimensions))); - const translate = Mat4.fromTranslation(_translate, volume.transform.fractionalBox.min); - return Mat4.mul3(Mat4.zero(), volume.transform.cell.fromFractional, translate, scale); - } - - return Mat4.identity(); - } - - export function areEquivalent(volA: VolumeData, volB: VolumeData) { - return volA === volB; - } -} - -type VolumeIsoValue = VolumeIsoValue.Absolute | VolumeIsoValue.Relative - -namespace VolumeIsoValue { - export type Relative = Readonly<{ kind: 'relative', relativeValue: number }> - export type Absolute = Readonly<{ kind: 'absolute', absoluteValue: number }> - - export function areSame(a: VolumeIsoValue, b: VolumeIsoValue, stats: VolumeData['dataStats']) { - return equalEps(toAbsolute(a, stats).absoluteValue, toAbsolute(b, stats).absoluteValue, stats.sigma / 100); - } - - export function absolute(value: number): Absolute { return { kind: 'absolute', absoluteValue: value }; } - export function relative(value: number): Relative { return { kind: 'relative', relativeValue: value }; } - - export function calcAbsolute(stats: VolumeData['dataStats'], relativeValue: number): number { - return relativeValue * stats.sigma + stats.mean; - } - - export function calcRelative(stats: VolumeData['dataStats'], absoluteValue: number): number { - return stats.sigma === 0 ? 0 : ((absoluteValue - stats.mean) / stats.sigma); - } - - export function toAbsolute(value: VolumeIsoValue, stats: VolumeData['dataStats']): Absolute { - return value.kind === 'absolute' ? value : { kind: 'absolute', absoluteValue: VolumeIsoValue.calcAbsolute(stats, value.relativeValue) }; - } - - export function toRelative(value: VolumeIsoValue, stats: VolumeData['dataStats']): Relative { - return value.kind === 'relative' ? value : { kind: 'relative', relativeValue: VolumeIsoValue.calcRelative(stats, value.absoluteValue) }; - } - - export function toString(value: VolumeIsoValue) { - return value.kind === 'relative' - ? `${value.relativeValue.toFixed(2)} σ` - : `${value.absoluteValue.toPrecision(4)}`; - } -} - -export { VolumeData, VolumeIsoValue }; \ No newline at end of file diff --git a/src/mol-model/volume/grid.ts b/src/mol-model/volume/grid.ts new file mode 100644 index 0000000000000000000000000000000000000000..53ec19a96f216f04087c77b9a3b76d3995f72deb --- /dev/null +++ b/src/mol-model/volume/grid.ts @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2018-2020 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> + */ + +import { SpacegroupCell, Box3D } from '../../mol-math/geometry'; +import { Tensor, Mat4, Vec3 } from '../../mol-math/linear-algebra'; + +/** The basic unit cell that contains the grid data. */ +interface Grid { + readonly transform: Grid.Transform, + readonly cells: Tensor, + readonly stats: Readonly<{ + min: number, + max: number, + mean: number, + sigma: number + }> +} + +namespace Grid { + export const One: Grid = { + transform: { kind: 'matrix', matrix: Mat4.identity() }, + cells: Tensor.create(Tensor.Space([1, 1, 1], [0, 1, 2]), Tensor.Data1([0])), + stats: { min: 0, max: 0, mean: 0, sigma: 0 }, + }; + + export type Transform = { kind: 'spacegroup', cell: SpacegroupCell, fractionalBox: Box3D } | { kind: 'matrix', matrix: Mat4 } + + const _scale = Mat4.zero(), _translate = Mat4.zero(); + export function getGridToCartesianTransform(grid: Grid) { + if (grid.transform.kind === 'matrix') { + return Mat4.copy(Mat4(), grid.transform.matrix); + } + + if (grid.transform.kind === 'spacegroup') { + const { cells: { space } } = grid; + const scale = Mat4.fromScaling(_scale, Vec3.div(Vec3.zero(), Box3D.size(Vec3.zero(), grid.transform.fractionalBox), Vec3.ofArray(space.dimensions))); + const translate = Mat4.fromTranslation(_translate, grid.transform.fractionalBox.min); + return Mat4.mul3(Mat4.zero(), grid.transform.cell.fromFractional, translate, scale); + } + + return Mat4.identity(); + } + + export function areEquivalent(gridA: Grid, gridB: Grid) { + return gridA === gridB; + } + + export function isEmpty(grid: Grid) { + return grid.cells.data.length === 0; + } +} + +export { Grid }; \ No newline at end of file diff --git a/src/mol-model/volume/volume.ts b/src/mol-model/volume/volume.ts index f61fed8e84ee6c8feacd8fdc86c5b38b5b9c3678..69afd4a966816b2fda54c68c82832eca8fd01981 100644 --- a/src/mol-model/volume/volume.ts +++ b/src/mol-model/volume/volume.ts @@ -4,32 +4,105 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { VolumeData, VolumeIsoValue } from './data'; +import { Grid } from './grid'; import { OrderedSet } from '../../mol-data/int'; import { Sphere3D } from '../../mol-math/geometry'; import { Vec3, Mat4 } from '../../mol-math/linear-algebra'; import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper'; import { CubeFormat } from '../../mol-model-formats/volume/cube'; +import { equalEps } from '../../mol-math/linear-algebra/3d/common'; +import { ModelFormat } from '../../mol-model-formats/format'; +import { CustomProperties } from '../custom-property'; + +export interface Volume { + readonly label?: string + readonly grid: Grid + readonly sourceData: ModelFormat + + // TODO use... + customProperties: CustomProperties + + /** + * Not to be accessed directly, each custom property descriptor + * defines property accessors that use this field to store the data. + */ + _propertyData: { [name: string]: any } + + // TODO add as customProperty? + readonly colorVolume?: Volume +} export namespace Volume { export type CellIndex = { readonly '@type': 'cell-index' } & number - export function isOrbitals(volume: VolumeData) { + export type IsoValue = IsoValue.Absolute | IsoValue.Relative + + export namespace IsoValue { + export type Relative = Readonly<{ kind: 'relative', relativeValue: number }> + export type Absolute = Readonly<{ kind: 'absolute', absoluteValue: number }> + + export function areSame(a: IsoValue, b: IsoValue, stats: Grid['stats']) { + return equalEps(toAbsolute(a, stats).absoluteValue, toAbsolute(b, stats).absoluteValue, stats.sigma / 100); + } + + export function absolute(value: number): Absolute { return { kind: 'absolute', absoluteValue: value }; } + export function relative(value: number): Relative { return { kind: 'relative', relativeValue: value }; } + + export function calcAbsolute(stats: Grid['stats'], relativeValue: number): number { + return relativeValue * stats.sigma + stats.mean; + } + + export function calcRelative(stats: Grid['stats'], absoluteValue: number): number { + return stats.sigma === 0 ? 0 : ((absoluteValue - stats.mean) / stats.sigma); + } + + export function toAbsolute(value: IsoValue, stats: Grid['stats']): Absolute { + return value.kind === 'absolute' ? value : { kind: 'absolute', absoluteValue: IsoValue.calcAbsolute(stats, value.relativeValue) }; + } + + export function toRelative(value: IsoValue, stats: Grid['stats']): Relative { + return value.kind === 'relative' ? value : { kind: 'relative', relativeValue: IsoValue.calcRelative(stats, value.absoluteValue) }; + } + + export function toString(value: IsoValue) { + return value.kind === 'relative' + ? `${value.relativeValue.toFixed(2)} σ` + : `${value.absoluteValue.toPrecision(4)}`; + } + } + + export const One: Volume = { + label: '', + grid: Grid.One, + sourceData: { kind: '', name: '', data: {} }, + customProperties: new CustomProperties(), + _propertyData: Object.create(null), + }; + + export function areEquivalent(volA: Volume, volB: Volume) { + return Grid.areEquivalent(volA.grid, volB.grid); + } + + export function isEmpty(vol: Volume) { + return Grid.isEmpty(vol.grid); + } + + export function isOrbitals(volume: Volume) { if (!CubeFormat.is(volume.sourceData)) return false; return volume.sourceData.data.header.orbitals; } - export interface Loci { readonly kind: 'volume-loci', readonly volume: VolumeData } - export function Loci(volume: VolumeData): Loci { return { kind: 'volume-loci', volume }; } + export interface Loci { readonly kind: 'volume-loci', readonly volume: Volume } + export function Loci(volume: Volume): Loci { return { kind: 'volume-loci', volume }; } export function isLoci(x: any): x is Loci { return !!x && x.kind === 'volume-loci'; } export function areLociEqual(a: Loci, b: Loci) { return a.volume === b.volume; } - export function isLociEmpty(loci: Loci) { return loci.volume.data.data.length === 0; } + export function isLociEmpty(loci: Loci) { return Grid.isEmpty(loci.volume.grid); } - export function getBoundingSphere(volume: VolumeData, boundingSphere?: Sphere3D) { + export function getBoundingSphere(volume: Volume, boundingSphere?: Sphere3D) { if (!boundingSphere) boundingSphere = Sphere3D(); - const transform = VolumeData.getGridToCartesianTransform(volume); - const [x, y, z] = volume.data.space.dimensions; + const transform = Grid.getGridToCartesianTransform(volume.grid); + const [x, y, z] = volume.grid.cells.space.dimensions; const cpA = Vec3.create(0, 0, 0); Vec3.transformMat4(cpA, cpA, transform); const cpB = Vec3.create(x, y, z); Vec3.transformMat4(cpB, cpB, transform); @@ -52,31 +125,31 @@ export namespace Volume { } export namespace Isosurface { - export interface Loci { readonly kind: 'isosurface-loci', readonly volume: VolumeData, readonly isoValue: VolumeIsoValue } - export function Loci(volume: VolumeData, isoValue: VolumeIsoValue): Loci { return { kind: 'isosurface-loci', volume, isoValue }; } + export interface Loci { readonly kind: 'isosurface-loci', readonly volume: Volume, readonly isoValue: Volume.IsoValue } + export function Loci(volume: Volume, isoValue: Volume.IsoValue): Loci { return { kind: 'isosurface-loci', volume, isoValue }; } export function isLoci(x: any): x is Loci { return !!x && x.kind === 'isosurface-loci'; } - export function areLociEqual(a: Loci, b: Loci) { return a.volume === b.volume && VolumeIsoValue.areSame(a.isoValue, b.isoValue, a.volume.dataStats); } - export function isLociEmpty(loci: Loci) { return loci.volume.data.data.length === 0; } + export function areLociEqual(a: Loci, b: Loci) { return a.volume === b.volume && Volume.IsoValue.areSame(a.isoValue, b.isoValue, a.volume.grid.stats); } + export function isLociEmpty(loci: Loci) { return loci.volume.grid.cells.data.length === 0; } - export function getBoundingSphere(volume: VolumeData, isoValue: VolumeIsoValue, boundingSphere?: Sphere3D) { + export function getBoundingSphere(volume: Volume, isoValue: Volume.IsoValue, boundingSphere?: Sphere3D) { // TODO get bounding sphere for subgrid with values >= isoValue return Volume.getBoundingSphere(volume, boundingSphere); } } export namespace Cell { - export interface Loci { readonly kind: 'cell-loci', readonly volume: VolumeData, readonly indices: OrderedSet<CellIndex> } - export function Loci(volume: VolumeData, indices: OrderedSet<CellIndex>): Loci { return { kind: 'cell-loci', volume, indices }; } + export interface Loci { readonly kind: 'cell-loci', readonly volume: Volume, readonly indices: OrderedSet<CellIndex> } + export function Loci(volume: Volume, indices: OrderedSet<CellIndex>): Loci { return { kind: 'cell-loci', volume, indices }; } export function isLoci(x: any): x is Loci { return !!x && x.kind === 'cell-loci'; } export function areLociEqual(a: Loci, b: Loci) { return a.volume === b.volume && OrderedSet.areEqual(a.indices, b.indices); } export function isLociEmpty(loci: Loci) { return OrderedSet.size(loci.indices) === 0; } const boundaryHelper = new BoundaryHelper('98'); const tmpBoundaryPos = Vec3(); - export function getBoundingSphere(volume: VolumeData, indices: OrderedSet<CellIndex>, boundingSphere?: Sphere3D) { + export function getBoundingSphere(volume: Volume, indices: OrderedSet<CellIndex>, boundingSphere?: Sphere3D) { boundaryHelper.reset(); - const transform = VolumeData.getGridToCartesianTransform(volume); - const { getCoords } = volume.data.space; + const transform = Grid.getGridToCartesianTransform(volume.grid); + const { getCoords } = volume.grid.cells.space; for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) { const o = OrderedSet.getAt(indices, i); diff --git a/src/mol-plugin-state/formats/volume.ts b/src/mol-plugin-state/formats/volume.ts index b39e288e1e3ab02b87f22b5c307b160c8f3fb55a..853c32bd70a1359eaf85e0687b9564301a44c410 100644 --- a/src/mol-plugin-state/formats/volume.ts +++ b/src/mol-plugin-state/formats/volume.ts @@ -12,10 +12,9 @@ import { StateObjectSelector } from '../../mol-state'; import { PluginStateObject } from '../objects'; import { VolumeRepresentation3DHelpers } from '../transforms/representation'; import { ColorNames } from '../../mol-util/color/names'; -import { VolumeIsoValue } from '../../mol-model/volume'; +import { Volume } from '../../mol-model/volume'; import { createVolumeRepresentationParams } from '../helpers/volume-representation-params'; import { objectForEach } from '../../mol-util/object'; -import { Volume } from '../../mol-model/volume/volume'; const Category = 'Volume'; @@ -110,13 +109,13 @@ export const CubeProvider = DataFormatProvider({ if (volumeData && Volume.isOrbitals(volumeData)) { const volumePos = surfaces.to(data.volume).apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(plugin, volumeData, { type: 'isosurface', - typeParams: { isoValue: VolumeIsoValue.relative(1), alpha: 0.4 }, + typeParams: { isoValue: Volume.IsoValue.relative(1), alpha: 0.4 }, color: 'uniform', colorParams: { value: ColorNames.blue } })); const volumeNeg = surfaces.to(data.volume).apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(plugin, volumeData, { type: 'isosurface', - typeParams: { isoValue: VolumeIsoValue.relative(-1), alpha: 0.4 }, + typeParams: { isoValue: Volume.IsoValue.relative(-1), alpha: 0.4 }, color: 'uniform', colorParams: { value: ColorNames.red } })); @@ -124,7 +123,7 @@ export const CubeProvider = DataFormatProvider({ } else { const volume = surfaces.to(data.volume).apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(plugin, volumeData, { type: 'isosurface', - typeParams: { isoValue: VolumeIsoValue.relative(2), alpha: 0.4 }, + typeParams: { isoValue: Volume.IsoValue.relative(2), alpha: 0.4 }, color: 'uniform', colorParams: { value: ColorNames.grey } })); @@ -176,13 +175,13 @@ export const DscifProvider = DataFormatProvider({ if (volumes.length > 0) { visuals[0] = tree .to(volumes[0]) - .apply(StateTransforms.Representation.VolumeRepresentation3D, VolumeRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'isosurface', { isoValue: VolumeIsoValue.relative(1.5), alpha: 1 }, 'uniform', { value: ColorNames.teal })) + .apply(StateTransforms.Representation.VolumeRepresentation3D, VolumeRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'isosurface', { isoValue: Volume.IsoValue.relative(1.5), alpha: 1 }, 'uniform', { value: ColorNames.teal })) .selector; } if (volumes.length > 1) { - const posParams = VolumeRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'isosurface', { isoValue: VolumeIsoValue.relative(3), alpha: 0.3 }, 'uniform', { value: ColorNames.green }); - const negParams = VolumeRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'isosurface', { isoValue: VolumeIsoValue.relative(-3), alpha: 0.3 }, 'uniform', { value: ColorNames.red }); + const posParams = VolumeRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'isosurface', { isoValue: Volume.IsoValue.relative(3), alpha: 0.3 }, 'uniform', { value: ColorNames.green }); + const negParams = VolumeRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'isosurface', { isoValue: Volume.IsoValue.relative(-3), alpha: 0.3 }, 'uniform', { value: ColorNames.red }); visuals[visuals.length] = tree.to(volumes[1]).apply(StateTransforms.Representation.VolumeRepresentation3D, posParams).selector; visuals[visuals.length] = tree.to(volumes[1]).apply(StateTransforms.Representation.VolumeRepresentation3D, negParams).selector; } diff --git a/src/mol-plugin-state/helpers/volume-representation-params.ts b/src/mol-plugin-state/helpers/volume-representation-params.ts index 3dae058f303eb03f87c8241432b44833533d3e83..55d9ab3bd2ffe0f71b03a101e8809825337c8f1b 100644 --- a/src/mol-plugin-state/helpers/volume-representation-params.ts +++ b/src/mol-plugin-state/helpers/volume-representation-params.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { VolumeData } from '../../mol-model/volume'; +import { Volume } from '../../mol-model/volume'; import { PluginContext } from '../../mol-plugin/context'; import { RepresentationProvider } from '../../mol-repr/representation'; import { VolumeRepresentationRegistry } from '../../mol-repr/volume/registry'; @@ -30,7 +30,7 @@ export interface VolumeRepresentationBuiltInProps< } export interface VolumeRepresentationProps< - R extends RepresentationProvider<VolumeData> = RepresentationProvider<VolumeData>, + R extends RepresentationProvider<Volume> = RepresentationProvider<Volume>, C extends ColorTheme.Provider = ColorTheme.Provider, S extends SizeTheme.Provider = SizeTheme.Provider> { type?: R, @@ -41,43 +41,43 @@ export interface VolumeRepresentationProps< sizeParams?: Partial<SizeTheme.ParamValues<S>> } -export function createVolumeRepresentationParams<R extends VolumeRepresentationRegistry.BuiltIn, C extends ColorTheme.BuiltIn, S extends SizeTheme.BuiltIn>(ctx: PluginContext, volume?: VolumeData, props?: VolumeRepresentationBuiltInProps<R, C, S>): StateTransformer.Params<VolumeRepresentation3D> -export function createVolumeRepresentationParams<R extends RepresentationProvider<VolumeData>, C extends ColorTheme.Provider, S extends SizeTheme.Provider>(ctx: PluginContext, volume?: VolumeData, props?: VolumeRepresentationProps<R, C, S>): StateTransformer.Params<VolumeRepresentation3D> -export function createVolumeRepresentationParams(ctx: PluginContext, volume?: VolumeData, props: any = {}): StateTransformer.Params<VolumeRepresentation3D> { +export function createVolumeRepresentationParams<R extends VolumeRepresentationRegistry.BuiltIn, C extends ColorTheme.BuiltIn, S extends SizeTheme.BuiltIn>(ctx: PluginContext, volume?: Volume, props?: VolumeRepresentationBuiltInProps<R, C, S>): StateTransformer.Params<VolumeRepresentation3D> +export function createVolumeRepresentationParams<R extends RepresentationProvider<Volume>, C extends ColorTheme.Provider, S extends SizeTheme.Provider>(ctx: PluginContext, volume?: Volume, props?: VolumeRepresentationProps<R, C, S>): StateTransformer.Params<VolumeRepresentation3D> +export function createVolumeRepresentationParams(ctx: PluginContext, volume?: Volume, props: any = {}): StateTransformer.Params<VolumeRepresentation3D> { const p = props as VolumeRepresentationBuiltInProps; - if (typeof p.type === 'string' || typeof p.color === 'string' || typeof p.size === 'string') return createParamsByName(ctx, volume || VolumeData.One, props); - return createParamsProvider(ctx, volume || VolumeData.One, props); + if (typeof p.type === 'string' || typeof p.color === 'string' || typeof p.size === 'string') return createParamsByName(ctx, volume || Volume.One, props); + return createParamsProvider(ctx, volume || Volume.One, props); } -export function getVolumeThemeTypes(ctx: PluginContext, volume?: VolumeData) { +export function getVolumeThemeTypes(ctx: PluginContext, volume?: Volume) { const { themes: themeCtx } = ctx.representation.volume; if (!volume) return themeCtx.colorThemeRegistry.types; return themeCtx.colorThemeRegistry.getApplicableTypes({ volume }); } -export function createVolumeColorThemeParams<T extends ColorTheme.BuiltIn>(ctx: PluginContext, volume: VolumeData | undefined, typeName: string | undefined, themeName: T, params?: ColorTheme.BuiltInParams<T>): StateTransformer.Params<VolumeRepresentation3D>['colorTheme'] -export function createVolumeColorThemeParams(ctx: PluginContext, volume: VolumeData | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['colorTheme'] -export function createVolumeColorThemeParams(ctx: PluginContext, volume: VolumeData | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['colorTheme'] { +export function createVolumeColorThemeParams<T extends ColorTheme.BuiltIn>(ctx: PluginContext, volume: Volume | undefined, typeName: string | undefined, themeName: T, params?: ColorTheme.BuiltInParams<T>): StateTransformer.Params<VolumeRepresentation3D>['colorTheme'] +export function createVolumeColorThemeParams(ctx: PluginContext, volume: Volume | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['colorTheme'] +export function createVolumeColorThemeParams(ctx: PluginContext, volume: Volume | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['colorTheme'] { const { registry, themes } = ctx.representation.volume; const repr = registry.get(typeName || registry.default.name); const color = themes.colorThemeRegistry.get(themeName || repr.defaultColorTheme.name); - const colorDefaultParams = PD.getDefaultValues(color.getParams({ volume: volume || VolumeData.One })); + const colorDefaultParams = PD.getDefaultValues(color.getParams({ volume: volume || Volume.One })); if (color.name === repr.defaultColorTheme.name) Object.assign(colorDefaultParams, repr.defaultColorTheme.props); return { name: color.name, params: Object.assign(colorDefaultParams, params) }; } -export function createVolumeSizeThemeParams<T extends SizeTheme.BuiltIn>(ctx: PluginContext, volume: VolumeData | undefined, typeName: string | undefined, themeName: T, params?: SizeTheme.BuiltInParams<T>): StateTransformer.Params<VolumeRepresentation3D>['sizeTheme'] -export function createVolumeSizeThemeParams(ctx: PluginContext, volume: VolumeData | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['sizeTheme'] -export function createVolumeSizeThemeParams(ctx: PluginContext, volume: VolumeData | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['sizeTheme'] { +export function createVolumeSizeThemeParams<T extends SizeTheme.BuiltIn>(ctx: PluginContext, volume: Volume | undefined, typeName: string | undefined, themeName: T, params?: SizeTheme.BuiltInParams<T>): StateTransformer.Params<VolumeRepresentation3D>['sizeTheme'] +export function createVolumeSizeThemeParams(ctx: PluginContext, volume: Volume | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['sizeTheme'] +export function createVolumeSizeThemeParams(ctx: PluginContext, volume: Volume | undefined, typeName: string | undefined, themeName?: string, params?: any): StateTransformer.Params<VolumeRepresentation3D>['sizeTheme'] { const { registry, themes } = ctx.representation.volume; const repr = registry.get(typeName || registry.default.name); const size = themes.sizeThemeRegistry.get(themeName || repr.defaultSizeTheme.name); - const sizeDefaultParams = PD.getDefaultValues(size.getParams({ volume: volume || VolumeData.One })); + const sizeDefaultParams = PD.getDefaultValues(size.getParams({ volume: volume || Volume.One })); if (size.name === repr.defaultSizeTheme.name) Object.assign(sizeDefaultParams, repr.defaultSizeTheme.props); return { name: size.name, params: Object.assign(sizeDefaultParams, params) }; } -function createParamsByName(ctx: PluginContext, volume: VolumeData, props: VolumeRepresentationBuiltInProps): StateTransformer.Params<VolumeRepresentation3D> { +function createParamsByName(ctx: PluginContext, volume: Volume, props: VolumeRepresentationBuiltInProps): StateTransformer.Params<VolumeRepresentation3D> { const typeProvider = (props.type && ctx.representation.volume.registry.get(props.type)) || ctx.representation.volume.registry.default.provider; const colorProvider = (props.color && ctx.representation.volume.themes.colorThemeRegistry.get(props.color)) @@ -95,7 +95,7 @@ function createParamsByName(ctx: PluginContext, volume: VolumeData, props: Volum }); } -function createParamsProvider(ctx: PluginContext, volume: VolumeData, props: VolumeRepresentationProps = {}): StateTransformer.Params<VolumeRepresentation3D> { +function createParamsProvider(ctx: PluginContext, volume: Volume, props: VolumeRepresentationProps = {}): StateTransformer.Params<VolumeRepresentation3D> { const { themes: themeCtx } = ctx.representation.volume; const themeDataCtx = { volume }; diff --git a/src/mol-plugin-state/objects.ts b/src/mol-plugin-state/objects.ts index 96d3488f4cf6034bfc6399e8f2533babc2bc680a..a9b18d77da426094dc91deb5d34415de6973afe6 100644 --- a/src/mol-plugin-state/objects.ts +++ b/src/mol-plugin-state/objects.ts @@ -14,7 +14,7 @@ import { PlyFile } from '../mol-io/reader/ply/schema'; import { PsfFile } from '../mol-io/reader/psf/parser'; import { ShapeProvider } from '../mol-model/shape/provider'; import { Coordinates as _Coordinates, Model as _Model, Structure as _Structure, StructureElement, Topology as _Topology } from '../mol-model/structure'; -import { VolumeData } from '../mol-model/volume'; +import { Volume as _Volume } from '../mol-model/volume'; import { PluginBehavior } from '../mol-plugin/behavior/behavior'; import { Representation } from '../mol-repr/representation'; import { ShapeRepresentation } from '../mol-repr/shape/representation'; @@ -121,7 +121,7 @@ export namespace PluginStateObject { } export namespace Volume { - export class Data extends Create<VolumeData>({ name: 'Volume Data', typeClass: 'Object' }) { } + export class Data extends Create<_Volume>({ name: 'Volume', typeClass: 'Object' }) { } export class Representation3D extends CreateRepresentation3D<VolumeRepresentation<any>>({ name: 'Volume 3D' }) { } } diff --git a/src/mol-plugin-state/transforms/representation.ts b/src/mol-plugin-state/transforms/representation.ts index 0aee3349c202b7517cfec32d605203178b652b44..bcb1f8560550c73feba8220fa5b5cd7ac932c95b 100644 --- a/src/mol-plugin-state/transforms/representation.ts +++ b/src/mol-plugin-state/transforms/representation.ts @@ -6,7 +6,7 @@ */ import { Structure, StructureElement } from '../../mol-model/structure'; -import { VolumeData, VolumeIsoValue } from '../../mol-model/volume'; +import { Volume } from '../../mol-model/volume'; import { PluginContext } from '../../mol-plugin/context'; import { VolumeRepresentationRegistry } from '../../mol-repr/volume/registry'; import { VolumeParams } from '../../mol-repr/volume/representation'; @@ -441,7 +441,7 @@ const TransparencyStructureRepresentation3DFromBundle = PluginStateTransform.Bui // export namespace VolumeRepresentation3DHelpers { - export function getDefaultParams(ctx: PluginContext, name: VolumeRepresentationRegistry.BuiltIn, volume: VolumeData, volumeParams?: Partial<PD.Values<VolumeParams>>): StateTransformer.Params<VolumeRepresentation3D> { + export function getDefaultParams(ctx: PluginContext, name: VolumeRepresentationRegistry.BuiltIn, volume: Volume, volumeParams?: Partial<PD.Values<VolumeParams>>): StateTransformer.Params<VolumeRepresentation3D> { const type = ctx.representation.volume.registry.get(name); const themeDataCtx = { volume }; @@ -467,7 +467,7 @@ export namespace VolumeRepresentation3DHelpers { } export function getDescription(props: any) { - return props.isoValue && VolumeIsoValue.toString(props.isoValue); + return props.isoValue && Volume.IsoValue.toString(props.isoValue); } } type VolumeRepresentation3D = typeof VolumeRepresentation3D @@ -485,16 +485,16 @@ const VolumeRepresentation3D = PluginStateTransform.BuiltIn({ type: PD.Mapped<any>( registry.default.name, registry.types, - name => PD.Group<any>(registry.get(name).getParams(themeCtx, VolumeData.One))), + name => PD.Group<any>(registry.get(name).getParams(themeCtx, Volume.One))), colorTheme: PD.Mapped<any>( type.defaultColorTheme.name, themeCtx.colorThemeRegistry.types, - name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams({ volume: VolumeData.One })) + name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams({ volume: Volume.One })) ), sizeTheme: PD.Mapped<any>( type.defaultSizeTheme.name, themeCtx.sizeThemeRegistry.types, - name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams({ volume: VolumeData.One })) + name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams({ volume: Volume.One })) ) }; } diff --git a/src/mol-plugin-state/transforms/volume.ts b/src/mol-plugin-state/transforms/volume.ts index 1e85fb0bdcf91d5ddfcab18b9ba9340e8fb2df47..e9cee9706606348e5ba87c144b9af2485ae478c4 100644 --- a/src/mol-plugin-state/transforms/volume.ts +++ b/src/mol-plugin-state/transforms/volume.ts @@ -15,7 +15,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { PluginStateObject as SO, PluginStateTransform } from '../objects'; import { volumeFromCube } from '../../mol-model-formats/volume/cube'; import { volumeFromDx } from '../../mol-model-formats/volume/dx'; -import { VolumeData } from '../../mol-model/volume'; +import { Volume } from '../../mol-model/volume'; import { PluginContext } from '../../mol-plugin/context'; import { StateSelection } from '../../mol-state'; @@ -160,8 +160,8 @@ const AssignColorVolume = PluginStateTransform.BuiltIn({ if (!dependencies || !dependencies[params.ref]) { throw new Error('Dependency not available.'); } - const colorVolume = dependencies[params.ref].data as VolumeData; - const volume: VolumeData = { + const colorVolume = dependencies[params.ref].data as Volume; + const volume: Volume = { ...a.data, colorVolume }; diff --git a/src/mol-plugin-ui/custom/volume.tsx b/src/mol-plugin-ui/custom/volume.tsx index 261ede7e7b7709ebb99daf70db2b906da2dfba0e..b0beddb56e50e12f5523f5cab83d913d595b5622 100644 --- a/src/mol-plugin-ui/custom/volume.tsx +++ b/src/mol-plugin-ui/custom/volume.tsx @@ -12,7 +12,7 @@ import { ExpandableControlRow, IconButton } from '../controls/common'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ParameterControls, ParamOnChange } from '../controls/parameters'; import { Slider } from '../controls/slider'; -import { VolumeIsoValue, VolumeData } from '../../mol-model/volume'; +import { Volume, Grid } from '../../mol-model/volume'; import { Vec3 } from '../../mol-math/linear-algebra'; import { ColorNames } from '../../mol-util/color/names'; import { toPrecision } from '../../mol-util/number'; @@ -34,7 +34,7 @@ class Channel extends PluginUIComponent<{ channels: { [k: string]: VolumeStreaming.ChannelParams }, isRelative: boolean, params: StateTransformParameters.Props, - stats: VolumeData['dataStats'], + stats: Grid['stats'], changeIso: (name: string, value: number, isRelative: boolean) => void, changeParams: (name: string, param: string, value: any) => void, bCell: StateObjectCell, @@ -111,7 +111,7 @@ export class VolumeStreamingCustomControls extends PluginUIComponent<StateTransf ...old.entry.params.channels, [name]: { ...(old.entry.params.channels as any)[name], - isoValue: isRelative ? VolumeIsoValue.relative(value) : VolumeIsoValue.absolute(value) + isoValue: isRelative ? Volume.IsoValue.relative(value) : Volume.IsoValue.absolute(value) } } } @@ -139,11 +139,11 @@ export class VolumeStreamingCustomControls extends PluginUIComponent<StateTransf }); }; - convert(channel: any, stats: VolumeData['dataStats'], isRelative: boolean) { + convert(channel: any, stats: Grid['stats'], isRelative: boolean) { return { ...channel, isoValue: isRelative - ? VolumeIsoValue.toRelative(channel.isoValue, stats) - : VolumeIsoValue.toAbsolute(channel.isoValue, stats) + ? Volume.IsoValue.toRelative(channel.isoValue, stats) + : Volume.IsoValue.toAbsolute(channel.isoValue, stats) }; } @@ -215,7 +215,7 @@ export class VolumeStreamingCustomControls extends PluginUIComponent<StateTransf const params = this.props.params as VolumeStreaming.Params; const detailLevel = ((this.props.info.params as VolumeStreaming.ParamDefinition) .entry.map(params.entry.name) as PD.Group<VolumeStreaming.EntryParamDefinition>).params.detailLevel; - const isRelative = ((params.entry.params.channels as any)[pivot].isoValue as VolumeIsoValue).kind === 'relative'; + const isRelative = ((params.entry.params.channels as any)[pivot].isoValue as Volume.IsoValue).kind === 'relative'; const sampling = b.info.header.sampling[0]; diff --git a/src/mol-plugin-ui/structure/volume.tsx b/src/mol-plugin-ui/structure/volume.tsx index 4c1eb90d848eae0574e854656fae41f7d9832924..3291975cbdb9101f1c0c008dd73fab3725b62d32 100644 --- a/src/mol-plugin-ui/structure/volume.tsx +++ b/src/mol-plugin-ui/structure/volume.tsx @@ -137,7 +137,7 @@ export class VolumeSourceControls extends CollapsableControls<{}, VolumeSourceCo private item = (ref: VolumeRef) => { const selected = this.plugin.managers.volume.hierarchy.selection; - const label = ref.cell.obj?.data.label || 'Volume'; + const label = ref.cell.obj?.label || 'Volume'; const item: ActionMenu.Item = { kind: 'item', label: label || ref.kind, selected: selected === ref, value: ref }; return item; } @@ -172,7 +172,7 @@ export class VolumeSourceControls extends CollapsableControls<{}, VolumeSourceCo get label() { const selected = this.plugin.managers.volume.hierarchy.selection; if (!selected) return 'Nothing Selected'; - return selected?.cell.obj?.data.label || 'Volume'; + return selected?.cell.obj?.label || 'Volume'; } selectCurrent: ActionMenu.OnSelect = (item) => { diff --git a/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts b/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts index 20648b515f4e77e492d700226377a722e288a3ba..b0d271f709c1fed8e6e610d01ee2842a53f71b6c 100644 --- a/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts +++ b/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts @@ -7,7 +7,7 @@ import { ParamDefinition as PD } from '../../../../mol-util/param-definition'; import { PluginStateObject } from '../../../../mol-plugin-state/objects'; -import { VolumeIsoValue, VolumeData } from '../../../../mol-model/volume'; +import { Volume, Grid } from '../../../../mol-model/volume'; import { createIsoValueParam } from '../../../../mol-repr/volume/isosurface'; import { VolumeServerHeader, VolumeServerInfo } from './model'; import { Box3D } from '../../../../mol-math/geometry'; @@ -31,13 +31,13 @@ export namespace VolumeStreaming { export const RootTag = 'volume-streaming-info'; export interface ChannelParams { - isoValue: VolumeIsoValue, + isoValue: Volume.IsoValue, color: Color, wireframe: boolean, opacity: number } - function channelParam(label: string, color: Color, defaultValue: VolumeIsoValue, stats: VolumeData['dataStats'], defaults: Partial<ChannelParams> = {}) { + function channelParam(label: string, color: Color, defaultValue: Volume.IsoValue, stats: Grid['stats'], defaults: Partial<ChannelParams> = {}) { return PD.Group<ChannelParams>({ isoValue: createIsoValueParam(typeof defaults.isoValue !== 'undefined' ? defaults.isoValue : defaultValue, stats), color: PD.Color(typeof defaults.color !== 'undefined' ? defaults.color : color), @@ -71,7 +71,7 @@ export namespace VolumeStreaming { const { entryData, defaultView, structure, channelParams = { } } = options; // fake the info - const info = entryData || { kind: 'em', header: { sampling: [fakeSampling], availablePrecisions: [{ precision: 0, maxVoxels: 0 }] }, emDefaultContourLevel: VolumeIsoValue.relative(0) }; + const info = entryData || { kind: 'em', header: { sampling: [fakeSampling], availablePrecisions: [{ precision: 0, maxVoxels: 0 }] }, emDefaultContourLevel: Volume.IsoValue.relative(0) }; const box = (structure && structure.boundary.box) || Box3D.empty(); return { @@ -93,12 +93,12 @@ export namespace VolumeStreaming { info.header.availablePrecisions.map((p, i) => [i, `${i + 1} [ ${Math.pow(p.maxVoxels, 1 / 3) | 0}^3 cells ]`] as [number, string]), { description: 'Determines the maximum number of voxels. Depending on the size of the volume options are in the range from 0 (0.52M voxels) to 6 (25.17M voxels).' }), channels: info.kind === 'em' ? PD.Group({ - 'em': channelParam('EM', Color(0x638F8F), info.emDefaultContourLevel || VolumeIsoValue.relative(1), info.header.sampling[0].valuesInfo[0], channelParams['em']) + 'em': channelParam('EM', Color(0x638F8F), info.emDefaultContourLevel || Volume.IsoValue.relative(1), info.header.sampling[0].valuesInfo[0], channelParams['em']) }, { isFlat: true }) : PD.Group({ - '2fo-fc': channelParam('2Fo-Fc', Color(0x3362B2), VolumeIsoValue.relative(1.5), info.header.sampling[0].valuesInfo[0], channelParams['2fo-fc']), - 'fo-fc(+ve)': channelParam('Fo-Fc(+ve)', Color(0x33BB33), VolumeIsoValue.relative(3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(+ve)']), - 'fo-fc(-ve)': channelParam('Fo-Fc(-ve)', Color(0xBB3333), VolumeIsoValue.relative(-3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(-ve)']), + '2fo-fc': channelParam('2Fo-Fc', Color(0x3362B2), Volume.IsoValue.relative(1.5), info.header.sampling[0].valuesInfo[0], channelParams['2fo-fc']), + 'fo-fc(+ve)': channelParam('Fo-Fc(+ve)', Color(0x33BB33), Volume.IsoValue.relative(3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(+ve)']), + 'fo-fc(-ve)': channelParam('Fo-Fc(-ve)', Color(0xBB3333), Volume.IsoValue.relative(-3), info.header.sampling[0].valuesInfo[1], channelParams['fo-fc(-ve)']), }, { isFlat: true }), }; } @@ -110,16 +110,16 @@ export namespace VolumeStreaming { export type ParamDefinition = typeof createParams extends (...args: any[]) => (infer T) ? T : never export type Params = ParamDefinition extends PD.Params ? PD.Values<ParamDefinition> : {} - type ChannelsInfo = { [name in ChannelType]?: { isoValue: VolumeIsoValue, color: Color, wireframe: boolean, opacity: number } } - type ChannelsData = { [name in 'EM' | '2FO-FC' | 'FO-FC']?: VolumeData } + type ChannelsInfo = { [name in ChannelType]?: { isoValue: Volume.IsoValue, color: Color, wireframe: boolean, opacity: number } } + type ChannelsData = { [name in 'EM' | '2FO-FC' | 'FO-FC']?: Volume } export type ChannelType = 'em' | '2fo-fc' | 'fo-fc(+ve)' | 'fo-fc(-ve)' export const ChannelTypeOptions: [ChannelType, string][] = [['em', 'em'], ['2fo-fc', '2fo-fc'], ['fo-fc(+ve)', 'fo-fc(+ve)'], ['fo-fc(-ve)', 'fo-fc(-ve)']]; export interface ChannelInfo { - data: VolumeData, + data: Volume, color: Color, wireframe: boolean, - isoValue: VolumeIsoValue.Relative, + isoValue: Volume.IsoValue.Relative, opacity: number } export type Channels = { [name in ChannelType]?: ChannelInfo } @@ -329,24 +329,24 @@ export namespace VolumeStreaming { const info = params.entry.params.channels as ChannelsInfo; if (this.info.kind === 'x-ray') { - this.channels['2fo-fc'] = this.createChannel(data['2FO-FC'] || VolumeData.One, info['2fo-fc'], this.info.header.sampling[0].valuesInfo[0]); - this.channels['fo-fc(+ve)'] = this.createChannel(data['FO-FC'] || VolumeData.One, info['fo-fc(+ve)'], this.info.header.sampling[0].valuesInfo[1]); - this.channels['fo-fc(-ve)'] = this.createChannel(data['FO-FC'] || VolumeData.One, info['fo-fc(-ve)'], this.info.header.sampling[0].valuesInfo[1]); + this.channels['2fo-fc'] = this.createChannel(data['2FO-FC'] || Volume.One, info['2fo-fc'], this.info.header.sampling[0].valuesInfo[0]); + this.channels['fo-fc(+ve)'] = this.createChannel(data['FO-FC'] || Volume.One, info['fo-fc(+ve)'], this.info.header.sampling[0].valuesInfo[1]); + this.channels['fo-fc(-ve)'] = this.createChannel(data['FO-FC'] || Volume.One, info['fo-fc(-ve)'], this.info.header.sampling[0].valuesInfo[1]); } else { - this.channels['em'] = this.createChannel(data['EM'] || VolumeData.One, info['em'], this.info.header.sampling[0].valuesInfo[0]); + this.channels['em'] = this.createChannel(data['EM'] || Volume.One, info['em'], this.info.header.sampling[0].valuesInfo[0]); } return true; } - private createChannel(data: VolumeData, info: ChannelsInfo['em'], stats: VolumeData['dataStats']): ChannelInfo { + private createChannel(data: Volume, info: ChannelsInfo['em'], stats: Grid['stats']): ChannelInfo { const i = info!; return { data, color: i.color, wireframe: i.wireframe, opacity: i.opacity, - isoValue: i.isoValue.kind === 'relative' ? i.isoValue : VolumeIsoValue.toRelative(i.isoValue, stats) + isoValue: i.isoValue.kind === 'relative' ? i.isoValue : Volume.IsoValue.toRelative(i.isoValue, stats) }; } diff --git a/src/mol-plugin/behavior/dynamic/volume-streaming/model.ts b/src/mol-plugin/behavior/dynamic/volume-streaming/model.ts index 59f47b1534cc99394ea252a5a9f3f629992cf13f..13138d154e3fbac6335004781e055d723260f434 100644 --- a/src/mol-plugin/behavior/dynamic/volume-streaming/model.ts +++ b/src/mol-plugin/behavior/dynamic/volume-streaming/model.ts @@ -1,12 +1,12 @@ /** - * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2020 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> */ import { PluginStateObject } from '../../../../mol-plugin-state/objects'; -import { VolumeIsoValue } from '../../../../mol-model/volume'; +import { Volume } from '../../../../mol-model/volume'; import { Structure } from '../../../../mol-model/structure'; export class VolumeServerInfo extends PluginStateObject.Create<VolumeServerInfo.Data>({ name: 'Volume Streaming', typeClass: 'Object' }) { } @@ -18,7 +18,7 @@ export namespace VolumeServerInfo { // for em, the EMDB access code, for x-ray, the PDB id dataId: string, header: VolumeServerHeader, - emDefaultContourLevel?: VolumeIsoValue, + emDefaultContourLevel?: Volume.IsoValue, } export interface Data { serverUrl: string, diff --git a/src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts b/src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts index d5d27521c32d13fdea57853ccc59b1e9efb30486..fdbf2f7ec8a2dd9de276586fe013268b80b007a5 100644 --- a/src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts +++ b/src/mol-plugin/behavior/dynamic/volume-streaming/transformers.ts @@ -12,7 +12,7 @@ import { Task } from '../../../../mol-task'; import { PluginContext } from '../../../../mol-plugin/context'; import { urlCombine } from '../../../../mol-util/url'; import { createIsoValueParam } from '../../../../mol-repr/volume/isosurface'; -import { VolumeIsoValue } from '../../../../mol-model/volume'; +import { Volume } from '../../../../mol-model/volume'; import { StateAction, StateObject, StateTransformer } from '../../../../mol-state'; import { getStreamingMethod, getIds, getContourLevel, getEmdbIds } from './util'; import { VolumeStreaming } from './behavior'; @@ -27,7 +27,7 @@ import { Model } from '../../../../mol-model/structure'; function addEntry(entries: InfoEntryProps[], method: VolumeServerInfo.Kind, dataId: string, emDefaultContourLevel: number) { entries.push({ source: method === 'em' - ? { name: 'em', params: { isoValue: VolumeIsoValue.absolute(emDefaultContourLevel || 0) } } + ? { name: 'em', params: { isoValue: Volume.IsoValue.absolute(emDefaultContourLevel || 0) } } : { name: 'x-ray', params: { } }, dataId }); @@ -157,7 +157,7 @@ const InfoEntryParams = { dataId: PD.Text(''), source: PD.MappedStatic('x-ray', { 'em': PD.Group({ - isoValue: createIsoValueParam(VolumeIsoValue.relative(1)) + isoValue: createIsoValueParam(Volume.IsoValue.relative(1)) }), 'x-ray': PD.Group({ }) }) @@ -185,7 +185,7 @@ const CreateVolumeStreamingInfo = PluginStateTransform.BuiltIn({ for (let i = 0, il = params.entries.length; i < il; ++i) { const e = params.entries[i]; const dataId = e.dataId; - const emDefaultContourLevel = e.source.name === 'em' ? e.source.params.isoValue : VolumeIsoValue.relative(1); + const emDefaultContourLevel = e.source.name === 'em' ? e.source.params.isoValue : Volume.IsoValue.relative(1); await taskCtx.update('Getting server header...'); const header = await plugin.fetch({ url: urlCombine(params.serverUrl, `${e.source.name}/${dataId.toLocaleLowerCase()}`), type: 'json' }).runInContext(taskCtx) as VolumeServerHeader; entries.push({ diff --git a/src/mol-repr/volume/direct-volume.ts b/src/mol-repr/volume/direct-volume.ts index f896bdbc1bb1b95b3b464495a89fc28bf4cb1dd2..da3cc458a499e22939392ddf591e305bad038113 100644 --- a/src/mol-repr/volume/direct-volume.ts +++ b/src/mol-repr/volume/direct-volume.ts @@ -7,7 +7,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { Vec3, Mat4 } from '../../mol-math/linear-algebra'; import { Box3D } from '../../mol-math/geometry'; -import { VolumeData } from '../../mol-model/volume'; +import { Grid, Volume } from '../../mol-model/volume'; import { RuntimeContext } from '../../mol-task'; import { WebGLContext } from '../../mol-gl/webgl/context'; import { DirectVolume } from '../../mol-geo/geometry/direct-volume/direct-volume'; @@ -20,7 +20,6 @@ import { NullLocation } from '../../mol-model/location'; import { EmptyLoci } from '../../mol-model/loci'; import { VisualUpdateState } from '../util'; import { RepresentationContext, RepresentationParamsGetter } from '../representation'; -import { Volume } from '../../mol-model/volume/volume'; function getBoundingBox(gridDimension: Vec3, transform: Mat4) { const bbox = Box3D.empty(); @@ -49,9 +48,8 @@ function getVolumeTexture2dLayout(dim: Vec3, maxTextureSize: number) { return { width, height, columns, rows }; } -function createVolumeTexture2d(volume: VolumeData, maxTextureSize: number) { - const { data: tensor, dataStats: stats } = volume; - const { space, data } = tensor; +function createVolumeTexture2d(volume: Volume, maxTextureSize: number) { + const { cells: { space, data }, stats } = volume.grid; const dim = space.dimensions as Vec3; const { get } = space; const { width, height, columns, rows } = getVolumeTexture2dLayout(dim, maxTextureSize); @@ -85,11 +83,11 @@ function createVolumeTexture2d(volume: VolumeData, maxTextureSize: number) { return textureImage; } -export function createDirectVolume2d(ctx: RuntimeContext, webgl: WebGLContext, volume: VolumeData, directVolume?: DirectVolume) { - const gridDimension = volume.data.space.dimensions as Vec3; +export function createDirectVolume2d(ctx: RuntimeContext, webgl: WebGLContext, volume: Volume, directVolume?: DirectVolume) { + const gridDimension = volume.grid.cells.space.dimensions as Vec3; const textureImage = createVolumeTexture2d(volume, webgl.maxTextureSize); // debugTexture(createImageData(textureImage.array, textureImage.width, textureImage.height), 1/3) - const transform = VolumeData.getGridToCartesianTransform(volume); + const transform = Grid.getGridToCartesianTransform(volume.grid); const bbox = getBoundingBox(gridDimension, transform); const dim = Vec3.create(gridDimension[0], gridDimension[1], gridDimension[2]); dim[0] += 1; // horizontal padding @@ -103,9 +101,8 @@ export function createDirectVolume2d(ctx: RuntimeContext, webgl: WebGLContext, v // 3d volume texture -function createVolumeTexture3d(volume: VolumeData) { - const { data: tensor, dataStats: stats } = volume; - const { space, data } = tensor; +function createVolumeTexture3d(volume: Volume) { + const { cells: { space, data }, stats } = volume.grid; const [ width, height, depth ] = space.dimensions as Vec3; const { get } = space; @@ -128,10 +125,10 @@ function createVolumeTexture3d(volume: VolumeData) { return textureVolume; } -export function createDirectVolume3d(ctx: RuntimeContext, webgl: WebGLContext, volume: VolumeData, directVolume?: DirectVolume) { - const gridDimension = volume.data.space.dimensions as Vec3; +export function createDirectVolume3d(ctx: RuntimeContext, webgl: WebGLContext, volume: Volume, directVolume?: DirectVolume) { + const gridDimension = volume.grid.cells.space.dimensions as Vec3; const textureVolume = createVolumeTexture3d(volume); - const transform = VolumeData.getGridToCartesianTransform(volume); + const transform = Grid.getGridToCartesianTransform(volume.grid); // Mat4.invert(transform, transform) const bbox = getBoundingBox(gridDimension, transform); @@ -143,7 +140,7 @@ export function createDirectVolume3d(ctx: RuntimeContext, webgl: WebGLContext, v // -export async function createDirectVolume(ctx: VisualContext, volume: VolumeData, theme: Theme, props: PD.Values<DirectVolumeParams>, directVolume?: DirectVolume) { +export async function createDirectVolume(ctx: VisualContext, volume: Volume, theme: Theme, props: PD.Values<DirectVolumeParams>, directVolume?: DirectVolume) { const { runtime, webgl } = ctx; if (webgl === undefined) throw new Error('DirectVolumeVisual requires `webgl` in props'); @@ -152,7 +149,7 @@ export async function createDirectVolume(ctx: VisualContext, volume: VolumeData, createDirectVolume2d(runtime, webgl, volume, directVolume); } -function getLoci(volume: VolumeData, props: PD.Values<DirectVolumeParams>) { +function getLoci(volume: Volume, props: PD.Values<DirectVolumeParams>) { return Volume.Loci(volume); } @@ -163,7 +160,7 @@ export const DirectVolumeParams = { ...DirectVolume.Params }; export type DirectVolumeParams = typeof DirectVolumeParams -export function getDirectVolumeParams(ctx: ThemeRegistryContext, volume: VolumeData) { +export function getDirectVolumeParams(ctx: ThemeRegistryContext, volume: Volume) { return PD.clone(DirectVolumeParams); } @@ -171,16 +168,16 @@ export function DirectVolumeVisual(materialId: number): VolumeVisual<DirectVolum return VolumeVisual<DirectVolume, DirectVolumeParams>({ defaultProps: PD.getDefaultValues(DirectVolumeParams), createGeometry: createDirectVolume, - createLocationIterator: (volume: VolumeData) => LocationIterator(1, 1, () => NullLocation), + createLocationIterator: (volume: Volume) => LocationIterator(1, 1, () => NullLocation), getLoci: () => EmptyLoci, eachLocation: () => false, - setUpdateState: (state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<DirectVolumeParams>, currentProps: PD.Values<DirectVolumeParams>) => { + setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<DirectVolumeParams>, currentProps: PD.Values<DirectVolumeParams>) => { }, geometryUtils: DirectVolume.Utils }, materialId); } -export function DirectVolumeRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, DirectVolumeParams>): VolumeRepresentation<DirectVolumeParams> { +export function DirectVolumeRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, DirectVolumeParams>): VolumeRepresentation<DirectVolumeParams> { return VolumeRepresentation('Direct Volume', ctx, getParams, DirectVolumeVisual, getLoci); } @@ -193,5 +190,5 @@ export const DirectVolumeRepresentationProvider = VolumeRepresentationProvider({ defaultValues: PD.getDefaultValues(DirectVolumeParams), defaultColorTheme: { name: 'uniform' }, defaultSizeTheme: { name: 'uniform' }, - isApplicable: (volume: VolumeData) => volume.data.data.length > 0 + isApplicable: (volume: Volume) => !Volume.isEmpty(volume) }); \ No newline at end of file diff --git a/src/mol-repr/volume/isosurface.ts b/src/mol-repr/volume/isosurface.ts index 6e6ddb7f9245cddb287032b96d41026e6abdc6b6..65d5bac070e5846e30c6c331a3455d7e988b88e5 100644 --- a/src/mol-repr/volume/isosurface.ts +++ b/src/mol-repr/volume/isosurface.ts @@ -6,7 +6,7 @@ */ import { ParamDefinition as PD } from '../../mol-util/param-definition'; -import { VolumeData, VolumeIsoValue } from '../../mol-model/volume'; +import { Grid, Volume } from '../../mol-model/volume'; import { VisualContext } from '../visual'; import { Theme, ThemeRegistryContext } from '../../mol-theme/theme'; import { Mesh } from '../../mol-geo/geometry/mesh/mesh'; @@ -18,15 +18,14 @@ import { VisualUpdateState } from '../util'; import { Lines } from '../../mol-geo/geometry/lines/lines'; import { RepresentationContext, RepresentationParamsGetter, Representation } from '../representation'; import { toPrecision } from '../../mol-util/number'; -import { Volume } from '../../mol-model/volume/volume'; import { PickingId } from '../../mol-geo/geometry/picking'; import { EmptyLoci, Loci } from '../../mol-model/loci'; import { Interval, OrderedSet } from '../../mol-data/int'; import { Tensor } from '../../mol-math/linear-algebra'; import { fillSerial } from '../../mol-util/array'; -const defaultStats: VolumeData['dataStats'] = { min: -1, max: 1, mean: 0, sigma: 0.1 }; -export function createIsoValueParam(defaultValue: VolumeIsoValue, stats?: VolumeData['dataStats']) { +const defaultStats: Grid['stats'] = { min: -1, max: 1, mean: 0, sigma: 0.1 }; +export function createIsoValueParam(defaultValue: Volume.IsoValue, stats?: Grid['stats']) { const sts = stats || defaultStats; const { min, max, mean, sigma } = sts; @@ -36,34 +35,34 @@ export function createIsoValueParam(defaultValue: VolumeIsoValue, stats?: Volume let def = defaultValue; if (defaultValue.kind === 'absolute') { - if (defaultValue.absoluteValue < min) def = VolumeIsoValue.absolute(min); - else if (defaultValue.absoluteValue > max) def = VolumeIsoValue.absolute(max); + if (defaultValue.absoluteValue < min) def = Volume.IsoValue.absolute(min); + else if (defaultValue.absoluteValue > max) def = Volume.IsoValue.absolute(max); } else { - if (defaultValue.relativeValue < relMin) def = VolumeIsoValue.relative(relMin); - else if (defaultValue.relativeValue > relMax) def = VolumeIsoValue.relative(relMax); + if (defaultValue.relativeValue < relMin) def = Volume.IsoValue.relative(relMin); + else if (defaultValue.relativeValue > relMax) def = Volume.IsoValue.relative(relMax); } return PD.Conditioned( def, { 'absolute': PD.Converted( - (v: VolumeIsoValue) => VolumeIsoValue.toAbsolute(v, VolumeData.One.dataStats).absoluteValue, - (v: number) => VolumeIsoValue.absolute(v), + (v: Volume.IsoValue) => Volume.IsoValue.toAbsolute(v, Grid.One.stats).absoluteValue, + (v: number) => Volume.IsoValue.absolute(v), PD.Numeric(mean, { min, max, step: toPrecision(sigma / 100, 2) }) ), 'relative': PD.Converted( - (v: VolumeIsoValue) => VolumeIsoValue.toRelative(v, VolumeData.One.dataStats).relativeValue, - (v: number) => VolumeIsoValue.relative(v), + (v: Volume.IsoValue) => Volume.IsoValue.toRelative(v, Grid.One.stats).relativeValue, + (v: number) => Volume.IsoValue.relative(v), PD.Numeric(Math.min(1, relMax), { min: relMin, max: relMax, step: toPrecision(Math.round(((max - min) / sigma)) / 100, 2) }) ) }, - (v: VolumeIsoValue) => v.kind === 'absolute' ? 'absolute' : 'relative', - (v: VolumeIsoValue, c: 'absolute' | 'relative') => c === 'absolute' ? VolumeIsoValue.toAbsolute(v, sts) : VolumeIsoValue.toRelative(v, sts), + (v: Volume.IsoValue) => v.kind === 'absolute' ? 'absolute' : 'relative', + (v: Volume.IsoValue, c: 'absolute' | 'relative') => c === 'absolute' ? Volume.IsoValue.toAbsolute(v, sts) : Volume.IsoValue.toRelative(v, sts), { isEssential: true } ); } -export const IsoValueParam = createIsoValueParam(VolumeIsoValue.relative(2)); +export const IsoValueParam = createIsoValueParam(Volume.IsoValue.relative(2)); type IsoValueParam = typeof IsoValueParam export const VolumeIsosurfaceParams = { @@ -72,11 +71,11 @@ export const VolumeIsosurfaceParams = { export type VolumeIsosurfaceParams = typeof VolumeIsosurfaceParams export type VolumeIsosurfaceProps = PD.Values<VolumeIsosurfaceParams> -function getLoci(volume: VolumeData, props: VolumeIsosurfaceProps) { +function getLoci(volume: Volume, props: VolumeIsosurfaceProps) { return Volume.Isosurface.Loci(volume, props.isoValue); } -function getIsosurfaceLoci(pickingId: PickingId, volume: VolumeData, props: VolumeIsosurfaceProps, id: number) { +function getIsosurfaceLoci(pickingId: PickingId, volume: Volume, props: VolumeIsosurfaceProps, id: number) { const { objectId, groupId } = pickingId; if (id === objectId) { return Volume.Cell.Loci(volume, Interval.ofSingleton(groupId as Volume.CellIndex)); @@ -84,17 +83,17 @@ function getIsosurfaceLoci(pickingId: PickingId, volume: VolumeData, props: Volu return EmptyLoci; } -function eachIsosurface(loci: Loci, volume: VolumeData, props: VolumeIsosurfaceProps, apply: (interval: Interval) => boolean) { +function eachIsosurface(loci: Loci, volume: Volume, props: VolumeIsosurfaceProps, apply: (interval: Interval) => boolean) { let changed = false; if (Volume.isLoci(loci)) { - if (!VolumeData.areEquivalent(loci.volume, volume)) return false; - if (apply(Interval.ofLength(volume.data.data.length))) changed = true; + if (!Volume.areEquivalent(loci.volume, volume)) return false; + if (apply(Interval.ofLength(volume.grid.cells.data.length))) changed = true; } else if (Volume.Isosurface.isLoci(loci)) { - if (!VolumeData.areEquivalent(loci.volume, volume)) return false; - if (!VolumeIsoValue.areSame(loci.isoValue, props.isoValue, volume.dataStats)) return false; - if (apply(Interval.ofLength(volume.data.data.length))) changed = true; + if (!Volume.areEquivalent(loci.volume, volume)) return false; + if (!Volume.IsoValue.areSame(loci.isoValue, props.isoValue, volume.grid.stats)) return false; + if (apply(Interval.ofLength(volume.grid.cells.data.length))) changed = true; } else if (Volume.Cell.isLoci(loci)) { - if (!VolumeData.areEquivalent(loci.volume, volume)) return false; + if (!Volume.areEquivalent(loci.volume, volume)) return false; if (Interval.is(loci.indices)) { if (apply(loci.indices)) changed = true; } else { @@ -108,18 +107,18 @@ function eachIsosurface(loci: Loci, volume: VolumeData, props: VolumeIsosurfaceP // -export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: VolumeData, theme: Theme, props: VolumeIsosurfaceProps, mesh?: Mesh) { +export async function createVolumeIsosurfaceMesh(ctx: VisualContext, volume: Volume, theme: Theme, props: VolumeIsosurfaceProps, mesh?: Mesh) { ctx.runtime.update({ message: 'Marching cubes...' }); - const ids = fillSerial(new Int32Array(volume.data.data.length)); + const ids = fillSerial(new Int32Array(volume.grid.cells.data.length)); const surface = await computeMarchingCubesMesh({ - isoLevel: VolumeIsoValue.toAbsolute(props.isoValue, volume.dataStats).absoluteValue, - scalarField: volume.data, - idField: Tensor.create(volume.data.space, Tensor.Data1(ids)) + isoLevel: Volume.IsoValue.toAbsolute(props.isoValue, volume.grid.stats).absoluteValue, + scalarField: volume.grid.cells, + idField: Tensor.create(volume.grid.cells.space, Tensor.Data1(ids)) }, mesh).runAsChild(ctx.runtime); - const transform = VolumeData.getGridToCartesianTransform(volume); + const transform = Grid.getGridToCartesianTransform(volume.grid); ctx.runtime.update({ message: 'Transforming mesh...' }); Mesh.transform(surface, transform); return surface; @@ -136,11 +135,11 @@ export function IsosurfaceMeshVisual(materialId: number): VolumeVisual<Isosurfac return VolumeVisual<Mesh, IsosurfaceMeshParams>({ defaultProps: PD.getDefaultValues(IsosurfaceMeshParams), createGeometry: createVolumeIsosurfaceMesh, - createLocationIterator: (volume: VolumeData) => LocationIterator(volume.data.data.length, 1, () => NullLocation), + createLocationIterator: (volume: Volume) => LocationIterator(volume.grid.cells.data.length, 1, () => NullLocation), getLoci: getIsosurfaceLoci, eachLocation: eachIsosurface, - setUpdateState: (state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<IsosurfaceMeshParams>, currentProps: PD.Values<IsosurfaceMeshParams>) => { - if (!VolumeIsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.dataStats)) state.createGeometry = true; + setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<IsosurfaceMeshParams>, currentProps: PD.Values<IsosurfaceMeshParams>) => { + if (!Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true; }, geometryUtils: Mesh.Utils }, materialId); @@ -148,18 +147,18 @@ export function IsosurfaceMeshVisual(materialId: number): VolumeVisual<Isosurfac // -export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume: VolumeData, theme: Theme, props: VolumeIsosurfaceProps, lines?: Lines) { +export async function createVolumeIsosurfaceWireframe(ctx: VisualContext, volume: Volume, theme: Theme, props: VolumeIsosurfaceProps, lines?: Lines) { ctx.runtime.update({ message: 'Marching cubes...' }); - const ids = fillSerial(new Int32Array(volume.data.data.length)); + const ids = fillSerial(new Int32Array(volume.grid.cells.data.length)); const wireframe = await computeMarchingCubesLines({ - isoLevel: VolumeIsoValue.toAbsolute(props.isoValue, volume.dataStats).absoluteValue, - scalarField: volume.data, - idField: Tensor.create(volume.data.space, Tensor.Data1(ids)) + isoLevel: Volume.IsoValue.toAbsolute(props.isoValue, volume.grid.stats).absoluteValue, + scalarField: volume.grid.cells, + idField: Tensor.create(volume.grid.cells.space, Tensor.Data1(ids)) }, lines).runAsChild(ctx.runtime); - const transform = VolumeData.getGridToCartesianTransform(volume); + const transform = Grid.getGridToCartesianTransform(volume.grid); Lines.transform(wireframe, transform); return wireframe; @@ -177,11 +176,11 @@ export function IsosurfaceWireframeVisual(materialId: number): VolumeVisual<Isos return VolumeVisual<Lines, IsosurfaceWireframeParams>({ defaultProps: PD.getDefaultValues(IsosurfaceWireframeParams), createGeometry: createVolumeIsosurfaceWireframe, - createLocationIterator: (volume: VolumeData) => LocationIterator(volume.data.data.length, 1, () => NullLocation), + createLocationIterator: (volume: Volume) => LocationIterator(volume.grid.cells.data.length, 1, () => NullLocation), getLoci: getIsosurfaceLoci, eachLocation: eachIsosurface, - setUpdateState: (state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<IsosurfaceWireframeParams>, currentProps: PD.Values<IsosurfaceWireframeParams>) => { - if (!VolumeIsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.dataStats)) state.createGeometry = true; + setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<IsosurfaceWireframeParams>, currentProps: PD.Values<IsosurfaceWireframeParams>) => { + if (!Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats)) state.createGeometry = true; }, geometryUtils: Lines.Utils }, materialId); @@ -190,8 +189,8 @@ export function IsosurfaceWireframeVisual(materialId: number): VolumeVisual<Isos // const IsosurfaceVisuals = { - 'solid': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, IsosurfaceMeshParams>) => VolumeRepresentation('Isosurface mesh', ctx, getParams, IsosurfaceMeshVisual, getLoci), - 'wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, IsosurfaceWireframeParams>) => VolumeRepresentation('Isosurface wireframe', ctx, getParams, IsosurfaceWireframeVisual, getLoci), + 'solid': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceMeshParams>) => VolumeRepresentation('Isosurface mesh', ctx, getParams, IsosurfaceMeshVisual, getLoci), + 'wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceWireframeParams>) => VolumeRepresentation('Isosurface wireframe', ctx, getParams, IsosurfaceWireframeVisual, getLoci), }; export const IsosurfaceParams = { @@ -200,15 +199,15 @@ export const IsosurfaceParams = { visuals: PD.MultiSelect(['solid'], PD.objectToOptions(IsosurfaceVisuals)), }; export type IsosurfaceParams = typeof IsosurfaceParams -export function getIsosurfaceParams(ctx: ThemeRegistryContext, volume: VolumeData) { +export function getIsosurfaceParams(ctx: ThemeRegistryContext, volume: Volume) { const p = PD.clone(IsosurfaceParams); - p.isoValue = createIsoValueParam(VolumeIsoValue.relative(2), volume.dataStats); + p.isoValue = createIsoValueParam(Volume.IsoValue.relative(2), volume.grid.stats); return p; } export type IsosurfaceRepresentation = VolumeRepresentation<IsosurfaceParams> -export function IsosurfaceRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, IsosurfaceParams>): IsosurfaceRepresentation { - return Representation.createMulti('Isosurface', ctx, getParams, Representation.StateBuilder, IsosurfaceVisuals as unknown as Representation.Def<VolumeData, IsosurfaceParams>); +export function IsosurfaceRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, IsosurfaceParams>): IsosurfaceRepresentation { + return Representation.createMulti('Isosurface', ctx, getParams, Representation.StateBuilder, IsosurfaceVisuals as unknown as Representation.Def<Volume, IsosurfaceParams>); } export const IsosurfaceRepresentationProvider = VolumeRepresentationProvider({ @@ -220,5 +219,5 @@ export const IsosurfaceRepresentationProvider = VolumeRepresentationProvider({ defaultValues: PD.getDefaultValues(IsosurfaceParams), defaultColorTheme: { name: 'uniform' }, defaultSizeTheme: { name: 'uniform' }, - isApplicable: (volume: VolumeData) => volume.data.data.length > 0 + isApplicable: (volume: Volume) => !Volume.isEmpty(volume) }); \ No newline at end of file diff --git a/src/mol-repr/volume/registry.ts b/src/mol-repr/volume/registry.ts index ee7b0050c6540ddd10f408711e5a8c6d3fa5dbf7..8f952a20cc4733a20eb405b810e7a46a481039bb 100644 --- a/src/mol-repr/volume/registry.ts +++ b/src/mol-repr/volume/registry.ts @@ -5,12 +5,12 @@ */ import { RepresentationRegistry, Representation, RepresentationProvider } from '../representation'; -import { VolumeData } from '../../mol-model/volume'; +import { Volume } from '../../mol-model/volume'; import { IsosurfaceRepresentationProvider } from './isosurface'; import { objectForEach } from '../../mol-util/object'; import { SliceRepresentationProvider } from './slice'; -export class VolumeRepresentationRegistry extends RepresentationRegistry<VolumeData, Representation.State> { +export class VolumeRepresentationRegistry extends RepresentationRegistry<Volume, Representation.State> { constructor() { super(); objectForEach(VolumeRepresentationRegistry.BuiltIn, (p, k) => { diff --git a/src/mol-repr/volume/representation.ts b/src/mol-repr/volume/representation.ts index e5f2a7685e357a01ad85289243e99a6c65ba11d2..7e97b98365fcfd42ef3bc2c14e1f711b65b1dc4c 100644 --- a/src/mol-repr/volume/representation.ts +++ b/src/mol-repr/volume/representation.ts @@ -6,7 +6,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { Visual, VisualContext } from '../visual'; -import { VolumeData } from '../../mol-model/volume'; +import { Volume } from '../../mol-model/volume'; import { Geometry, GeometryUtils } from '../../mol-geo/geometry/geometry'; import { LocationIterator } from '../../mol-geo/util/location-iterator'; import { Theme } from '../../mol-theme/theme'; @@ -30,9 +30,9 @@ import { Subject } from 'rxjs'; import { Task } from '../../mol-task'; import { SizeValues } from '../../mol-gl/renderable/schema'; -export interface VolumeVisual<P extends VolumeParams> extends Visual<VolumeData, P> { } +export interface VolumeVisual<P extends VolumeParams> extends Visual<Volume, P> { } -function createVolumeRenderObject<G extends Geometry>(volume: VolumeData, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>, materialId: number) { +function createVolumeRenderObject<G extends Geometry>(volume: Volume, geometry: G, locationIt: LocationIterator, theme: Theme, props: PD.Values<Geometry.Params<G>>, materialId: number) { const { createValues, createRenderableState } = Geometry.getUtils(geometry); const transform = createIdentityTransform(); const values = createValues(geometry, transform, locationIt, theme, props); @@ -42,11 +42,11 @@ function createVolumeRenderObject<G extends Geometry>(volume: VolumeData, geomet interface VolumeVisualBuilder<P extends VolumeParams, G extends Geometry> { defaultProps: PD.Values<P> - createGeometry(ctx: VisualContext, volume: VolumeData, theme: Theme, props: PD.Values<P>, geometry?: G): Promise<G> | G - createLocationIterator(volume: VolumeData): LocationIterator - getLoci(pickingId: PickingId, volume: VolumeData, props: PD.Values<P>, id: number): Loci - eachLocation(loci: Loci, volume: VolumeData, props: PD.Values<P>, apply: (interval: Interval) => boolean): boolean - setUpdateState(state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme): void + createGeometry(ctx: VisualContext, volume: Volume, theme: Theme, props: PD.Values<P>, geometry?: G): Promise<G> | G + createLocationIterator(volume: Volume): LocationIterator + getLoci(pickingId: PickingId, volume: Volume, props: PD.Values<P>, id: number): Loci + eachLocation(loci: Loci, volume: Volume, props: PD.Values<P>, apply: (interval: Interval) => boolean): boolean + setUpdateState(state: VisualUpdateState, volume: Volume, newProps: PD.Values<P>, currentProps: PD.Values<P>, newTheme: Theme, currentTheme: Theme): void } interface VolumeVisualGeometryBuilder<P extends VolumeParams, G extends Geometry> extends VolumeVisualBuilder<P, G> { @@ -62,16 +62,16 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet let newProps: PD.Values<P>; let newTheme: Theme; - let newVolume: VolumeData; + let newVolume: Volume; let currentProps: PD.Values<P> = Object.assign({}, defaultProps); let currentTheme: Theme = Theme.createEmpty(); - let currentVolume: VolumeData; + let currentVolume: Volume; let geometry: G; let locationIt: LocationIterator; - function prepareUpdate(theme: Theme, props: Partial<PD.Values<P>>, volume: VolumeData) { + function prepareUpdate(theme: Theme, props: Partial<PD.Values<P>>, volume: Volume) { if (!volume && !currentVolume) { throw new Error('missing volume'); } @@ -84,7 +84,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet if (!renderObject) { updateState.createNew = true; - } else if (!currentVolume || !VolumeData.areEquivalent(newVolume, currentVolume)) { + } else if (!currentVolume || !Volume.areEquivalent(newVolume, currentVolume)) { updateState.createNew = true; } @@ -158,7 +158,7 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet return { get groupCount() { return locationIt ? locationIt.count : 0; }, get renderObject () { return renderObject; }, - async createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<PD.Values<P>> = {}, volume?: VolumeData) { + async createOrUpdate(ctx: VisualContext, theme: Theme, props: Partial<PD.Values<P>> = {}, volume?: Volume) { prepareUpdate(theme, props, volume || currentVolume); if (updateState.createGeometry) { const newGeometry = createGeometry(ctx, newVolume, newTheme, newProps, geometry); @@ -198,9 +198,9 @@ export function VolumeVisual<G extends Geometry, P extends VolumeParams & Geomet }; } -export interface VolumeRepresentation<P extends VolumeParams> extends Representation<VolumeData, P> { } +export interface VolumeRepresentation<P extends VolumeParams> extends Representation<Volume, P> { } -export type VolumeRepresentationProvider<P extends VolumeParams, Id extends string = string> = RepresentationProvider<VolumeData, P, Representation.State, Id> +export type VolumeRepresentationProvider<P extends VolumeParams, Id extends string = string> = RepresentationProvider<Volume, P, Representation.State, Id> export function VolumeRepresentationProvider<P extends VolumeParams, Id extends string>(p: VolumeRepresentationProvider<P, Id>): VolumeRepresentationProvider<P, Id> { return p; } // @@ -210,7 +210,7 @@ export const VolumeParams = { }; export type VolumeParams = typeof VolumeParams -export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, P>, visualCtor: (materialId: number) => VolumeVisual<P>, getLoci: (volume: VolumeData, props: PD.Values<P>) => Loci): VolumeRepresentation<P> { +export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, P>, visualCtor: (materialId: number) => VolumeVisual<P>, getLoci: (volume: Volume, props: PD.Values<P>) => Loci): VolumeRepresentation<P> { let version = 0; const updated = new Subject<number>(); const materialId = getNextMaterialId(); @@ -218,12 +218,12 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: const _state = Representation.createState(); let visual: VolumeVisual<P> | undefined; - let _volume: VolumeData; + let _volume: Volume; let _params: P; let _props: PD.Values<P>; let _theme = Theme.createEmpty(); - function createOrUpdate(props: Partial<PD.Values<P>> = {}, volume?: VolumeData) { + function createOrUpdate(props: Partial<PD.Values<P>> = {}, volume?: Volume) { if (volume && volume !== _volume) { _params = getParams(ctx, volume); _volume = volume; diff --git a/src/mol-repr/volume/slice.ts b/src/mol-repr/volume/slice.ts index 3b9314597846f81a9abcdf1979eda652059ae50f..485d17d8464e815ea5bf8425d5aacdd4043a6ebd 100644 --- a/src/mol-repr/volume/slice.ts +++ b/src/mol-repr/volume/slice.ts @@ -7,14 +7,13 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { Image } from '../../mol-geo/geometry/image/image'; import { ThemeRegistryContext, Theme } from '../../mol-theme/theme'; -import { VolumeData, VolumeIsoValue } from '../../mol-model/volume'; +import { Grid, Volume } from '../../mol-model/volume'; import { VolumeVisual, VolumeRepresentation, VolumeRepresentationProvider } from './representation'; import { LocationIterator } from '../../mol-geo/util/location-iterator'; import { VisualUpdateState } from '../util'; import { NullLocation } from '../../mol-model/location'; import { RepresentationContext, RepresentationParamsGetter } from '../representation'; import { VisualContext } from '../visual'; -import { Volume } from '../../mol-model/volume/volume'; import { PickingId } from '../../mol-geo/geometry/picking'; import { EmptyLoci, Loci } from '../../mol-model/loci'; import { Interval, OrderedSet, SortedArray } from '../../mol-data/int'; @@ -25,12 +24,12 @@ import { createIsoValueParam, IsoValueParam } from './isosurface'; import { Color } from '../../mol-util/color'; import { ColorTheme } from '../../mol-theme/color'; -export async function createImage(ctx: VisualContext, volume: VolumeData, theme: Theme, props: PD.Values<SliceParams>, image?: Image) { +export async function createImage(ctx: VisualContext, volume: Volume, theme: Theme, props: PD.Values<SliceParams>, image?: Image) { const { dimension: { name: dim }, isoValue } = props; - const { space, data: data } = volume.data; - const { min, max } = volume.dataStats; - const isoVal = VolumeIsoValue.toAbsolute(isoValue, volume.dataStats).absoluteValue; + const { space, data } = volume.grid.cells; + const { min, max } = volume.grid.stats; + const isoVal = Volume.IsoValue.toAbsolute(isoValue, volume.grid.stats).absoluteValue; // TODO more color themes const color = theme.color.color(NullLocation, false); @@ -41,7 +40,7 @@ export async function createImage(ctx: VisualContext, volume: VolumeData, theme: x, y, z, x0, y0, z0, nx, ny, nz - } = getSliceInfo(volume, props); + } = getSliceInfo(volume.grid, props); const corners = new Float32Array( dim === 'x' ? [x, 0, 0, x, y, 0, x, 0, z, x, y, z] : @@ -50,7 +49,7 @@ export async function createImage(ctx: VisualContext, volume: VolumeData, theme: ); const imageArray = new Float32Array(width * height * 4); - const groupArray = getGroupArray(volume, props); + const groupArray = getGroupArray(volume.grid, props); let i = 0; for (let iy = y0; iy < ny; ++iy) { @@ -72,15 +71,15 @@ export async function createImage(ctx: VisualContext, volume: VolumeData, theme: const imageTexture = { width, height, array: imageArray, flipY: true }; const groupTexture = { width, height, array: groupArray, flipY: true }; - const transform = VolumeData.getGridToCartesianTransform(volume); + const transform = Grid.getGridToCartesianTransform(volume.grid); transformPositionArray(transform, corners, 0, 4); return Image.create(imageTexture, corners, groupTexture, image); } -function getSliceInfo(volume: VolumeData, props: PD.Values<SliceParams>) { +function getSliceInfo(grid: Grid, props: PD.Values<SliceParams>) { const { dimension: { name: dim, params: index } } = props; - const { space } = volume.data; + const { space } = grid.cells; let width, height; let x, y, z; @@ -108,9 +107,9 @@ function getSliceInfo(volume: VolumeData, props: PD.Values<SliceParams>) { }; } -function getGroupArray(volume: VolumeData, props: PD.Values<SliceParams>) { - const { space } = volume.data; - const { width, height, x0, y0, z0, nx, ny, nz } = getSliceInfo(volume, props); +function getGroupArray(grid: Grid, props: PD.Values<SliceParams>) { + const { space } = grid.cells; + const { width, height, x0, y0, z0, nx, ny, nz } = getSliceInfo(grid, props); const groupArray = new Float32Array(width * height); let j = 0; @@ -125,13 +124,13 @@ function getGroupArray(volume: VolumeData, props: PD.Values<SliceParams>) { return groupArray; } -function getLoci(volume: VolumeData, props: PD.Values<SliceParams>) { +function getLoci(volume: Volume, props: PD.Values<SliceParams>) { // TODO cache somehow? - const groupArray = getGroupArray(volume, props); + const groupArray = getGroupArray(volume.grid, props); return Volume.Cell.Loci(volume, SortedArray.ofUnsortedArray(groupArray)); } -function getSliceLoci(pickingId: PickingId, volume: VolumeData, props: PD.Values<SliceParams>, id: number) { +function getSliceLoci(pickingId: PickingId, volume: Volume, props: PD.Values<SliceParams>, id: number) { const { objectId, groupId } = pickingId; if (id === objectId) { return Volume.Cell.Loci(volume, Interval.ofSingleton(groupId as Volume.CellIndex)); @@ -139,24 +138,24 @@ function getSliceLoci(pickingId: PickingId, volume: VolumeData, props: PD.Values return EmptyLoci; } -function eachSlice(loci: Loci, volume: VolumeData, props: PD.Values<SliceParams>, apply: (interval: Interval) => boolean) { +function eachSlice(loci: Loci, volume: Volume, props: PD.Values<SliceParams>, apply: (interval: Interval) => boolean) { let changed = false; if (Volume.isLoci(loci)) { - if (!VolumeData.areEquivalent(loci.volume, volume)) return false; - if (apply(Interval.ofLength(volume.data.data.length))) changed = true; + if (!Volume.areEquivalent(loci.volume, volume)) return false; + if (apply(Interval.ofLength(volume.grid.cells.data.length))) changed = true; } else if (Volume.Isosurface.isLoci(loci)) { - if (!VolumeData.areEquivalent(loci.volume, volume)) return false; + if (!Volume.areEquivalent(loci.volume, volume)) return false; // TODO find a cheaper way? - const { dataStats, data: { data } } = volume; - const eps = dataStats.sigma; - const v = VolumeIsoValue.toAbsolute(loci.isoValue, dataStats).absoluteValue; + const { stats, cells: { data } } = volume.grid; + const eps = stats.sigma; + const v = Volume.IsoValue.toAbsolute(loci.isoValue, stats).absoluteValue; for (let i = 0, il = data.length; i < il; ++i) { if (equalEps(v, data[i], eps)) { if (apply(Interval.ofSingleton(i))) changed = true; } } } else if (Volume.Cell.isLoci(loci)) { - if (!VolumeData.areEquivalent(loci.volume, volume)) return false; + if (!Volume.areEquivalent(loci.volume, volume)) return false; if (Interval.is(loci.indices)) { if (apply(loci.indices)) changed = true; } else { @@ -181,15 +180,15 @@ export const SliceParams = { isoValue: IsoValueParam, }; export type SliceParams = typeof SliceParams -export function getSliceParams(ctx: ThemeRegistryContext, volume: VolumeData) { +export function getSliceParams(ctx: ThemeRegistryContext, volume: Volume) { const p = PD.clone(SliceParams); - const dim = volume.data.space.dimensions; + const dim = volume.grid.cells.space.dimensions; p.dimension = PD.MappedStatic('x', { x: PD.Numeric(0, { min: 0, max: dim[0] - 1, step: 1 }), y: PD.Numeric(0, { min: 0, max: dim[1] - 1, step: 1 }), z: PD.Numeric(0, { min: 0, max: dim[2] - 1, step: 1 }), }, { isEssential: true }); - p.isoValue = createIsoValueParam(VolumeIsoValue.absolute(volume.dataStats.min), volume.dataStats); + p.isoValue = createIsoValueParam(Volume.IsoValue.absolute(volume.grid.stats.min), volume.grid.stats); return p; } @@ -197,14 +196,14 @@ export function SliceVisual(materialId: number): VolumeVisual<SliceParams> { return VolumeVisual<Image, SliceParams>({ defaultProps: PD.getDefaultValues(SliceParams), createGeometry: createImage, - createLocationIterator: (volume: VolumeData) => LocationIterator(volume.data.data.length, 1, () => NullLocation), + createLocationIterator: (volume: Volume) => LocationIterator(volume.grid.cells.data.length, 1, () => NullLocation), getLoci: getSliceLoci, eachLocation: eachSlice, - setUpdateState: (state: VisualUpdateState, volume: VolumeData, newProps: PD.Values<SliceParams>, currentProps: PD.Values<SliceParams>, newTheme: Theme, currentTheme: Theme) => { + setUpdateState: (state: VisualUpdateState, volume: Volume, newProps: PD.Values<SliceParams>, currentProps: PD.Values<SliceParams>, newTheme: Theme, currentTheme: Theme) => { state.createGeometry = ( newProps.dimension.name !== currentProps.dimension.name || newProps.dimension.params !== currentProps.dimension.params || - !VolumeIsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.dataStats) || + !Volume.IsoValue.areSame(newProps.isoValue, currentProps.isoValue, volume.grid.stats) || !ColorTheme.areEqual(newTheme.color, currentTheme.color) ); }, @@ -226,7 +225,7 @@ function updateRenderableState(state: RenderableState, props: PD.Values<SlicePar state.writeDepth = true; } -export function SliceRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<VolumeData, SliceParams>): VolumeRepresentation<SliceParams> { +export function SliceRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Volume, SliceParams>): VolumeRepresentation<SliceParams> { return VolumeRepresentation('Slice', ctx, getParams, SliceVisual, getLoci); } @@ -239,5 +238,5 @@ export const SliceRepresentationProvider = VolumeRepresentationProvider({ defaultValues: PD.getDefaultValues(SliceParams), defaultColorTheme: { name: 'uniform' }, defaultSizeTheme: { name: 'uniform' }, - isApplicable: (volume: VolumeData) => volume.data.data.length > 0 + isApplicable: (volume: Volume) => !Volume.isEmpty(volume) }); \ No newline at end of file diff --git a/src/mol-script/runtime/query/base.ts b/src/mol-script/runtime/query/base.ts index dabc80ad3deb1efa464997beb2d6dc91ab8e8a92..8f77598a0da57c2e87293fa3eb69121f2bf6a0db 100644 --- a/src/mol-script/runtime/query/base.ts +++ b/src/mol-script/runtime/query/base.ts @@ -5,8 +5,9 @@ */ import Expression from '../../language/expression'; -import { QueryContext, QueryFn, Structure, CustomPropertyDescriptor } from '../../../mol-model/structure'; +import { QueryContext, QueryFn, Structure } from '../../../mol-model/structure'; import { MSymbol } from '../../language/symbol'; +import { CustomPropertyDescriptor } from '../../../mol-model/custom-property'; export class QueryRuntimeTable { private map = new Map<string, QuerySymbolRuntime>(); diff --git a/src/mol-theme/label.ts b/src/mol-theme/label.ts index b1d530d8ce4cc6c53abed9961950e646675585dc..2d8cc64cf64a792419d8cad06d67f7c88f655c4b 100644 --- a/src/mol-theme/label.ts +++ b/src/mol-theme/label.ts @@ -12,7 +12,7 @@ import { capitalize, stripTags } from '../mol-util/string'; import { Column } from '../mol-data/db'; import { Vec3 } from '../mol-math/linear-algebra'; import { radToDeg } from '../mol-math/misc'; -import { VolumeIsoValue } from '../mol-model/volume'; +import { Volume } from '../mol-model/volume'; export type LabelGranularity = 'element' | 'conformation' | 'residue' | 'chain' | 'structure' @@ -51,19 +51,19 @@ export function lociLabel(loci: Loci, options: Partial<LabelOptions> = {}): stri case 'isosurface-loci': return [ `${loci.volume.label || 'Volume'}`, - `Isosurface at ${VolumeIsoValue.toString(loci.isoValue)}` + `Isosurface at ${Volume.IsoValue.toString(loci.isoValue)}` ].join(' | '); case 'cell-loci': const size = OrderedSet.size(loci.indices); const start = OrderedSet.start(loci.indices); - const absVal = VolumeIsoValue.absolute(loci.volume.data.data[start]); - const relVal = VolumeIsoValue.toRelative(absVal, loci.volume.dataStats); + const absVal = Volume.IsoValue.absolute(loci.volume.grid.cells.data[start]); + const relVal = Volume.IsoValue.toRelative(absVal, loci.volume.grid.stats); const label = [ `${loci.volume.label || 'Volume'}`, `${size === 1 ? `Cell #${start}` : `${size} Cells`}` ]; if (size === 1) { - label.push(`${VolumeIsoValue.toString(absVal)} (${VolumeIsoValue.toString(relVal)})`); + label.push(`${Volume.IsoValue.toString(absVal)} (${Volume.IsoValue.toString(relVal)})`); } return label.join(' | '); } diff --git a/src/mol-theme/theme.ts b/src/mol-theme/theme.ts index 83c4fe8bdf1826bab80d79a07853f6460171a738..2bd1543cdda981926c974bbacda80cc5340ee406 100644 --- a/src/mol-theme/theme.ts +++ b/src/mol-theme/theme.ts @@ -7,7 +7,7 @@ import { ColorTheme } from './color'; import { SizeTheme } from './size'; import { Structure } from '../mol-model/structure'; -import { VolumeData } from '../mol-model/volume'; +import { Volume } from '../mol-model/volume'; import { ParamDefinition as PD } from '../mol-util/param-definition'; import { Shape } from '../mol-model/shape'; import { CustomProperty } from '../mol-model-props/common/custom-property'; @@ -21,7 +21,7 @@ export interface ThemeRegistryContext { export interface ThemeDataContext { [k: string]: any structure?: Structure - volume?: VolumeData + volume?: Volume shape?: Shape } diff --git a/src/perf-tests/mol-script.ts b/src/perf-tests/mol-script.ts index eb40e8848ed8c442534e3e89802f263ebb888325..3b4fc50308bd02c3add42349b52764e91e292dff 100644 --- a/src/perf-tests/mol-script.ts +++ b/src/perf-tests/mol-script.ts @@ -1,6 +1,6 @@ import { MolScriptBuilder } from '../mol-script/language/builder'; import { compile, QuerySymbolRuntime, DefaultQueryRuntimeTable } from '../mol-script/runtime/query/compiler'; -import { QueryContext, Structure, StructureQuery, CustomPropertyDescriptor } from '../mol-model/structure'; +import { QueryContext, Structure, StructureQuery } from '../mol-model/structure'; import { readCifFile, getModelsAndStructure } from '../apps/structure-info/model'; import { CustomPropSymbol } from '../mol-script/language/symbol'; import Type from '../mol-script/language/type'; @@ -10,6 +10,7 @@ import { transpileMolScript } from '../mol-script/script/mol-script/symbols'; import { formatMolScript } from '../mol-script/language/expression-formatter'; import { StructureQualityReport, StructureQualityReportProvider } from '../extensions/pdbe/structure-quality-report/prop'; import fetch from 'node-fetch'; +import { CustomPropertyDescriptor } from '../mol-model/custom-property'; // import Examples from 'mol-script/script/mol-script/examples' // import { parseMolScript } from 'mol-script/script/mol-script/parser'