From 35baaaf59442a6602b8f7ca8b6f1cc76df48e429 Mon Sep 17 00:00:00 2001 From: ludovic autin <autin@scripps.edu> Date: Mon, 13 Sep 2021 11:46:27 -0700 Subject: [PATCH] support for compartment PLY file. --- src/extensions/cellpack/data.ts | 30 +++++--- src/extensions/cellpack/model.ts | 48 +++++++----- src/extensions/cellpack/representation.ts | 16 ---- src/extensions/cellpack/state.ts | 16 ++-- src/extensions/cellpack/util.ts | 89 +---------------------- 5 files changed, 62 insertions(+), 137 deletions(-) diff --git a/src/extensions/cellpack/data.ts b/src/extensions/cellpack/data.ts index 51ad02365..f415040fc 100644 --- a/src/extensions/cellpack/data.ts +++ b/src/extensions/cellpack/data.ts @@ -13,11 +13,11 @@ export interface CellPack { export interface CellPacking { name: string, - location: 'surface' | 'interior' | 'cytoplasme', + location: 'surface' | 'interior' | 'cytoplasme' ingredients: Packing['ingredients'] - geom?: string - geom_type?: string - mb?: Membrane + filename?: string + geom_type?: 'raw' | 'file' | 'sphere' | 'mb' | 'None' + primitives?: Primitives } // @@ -44,17 +44,29 @@ export interface Recipe { export interface Compartment { surface?: Packing interior?: Packing - geom?: string - geom_type?: string - mb?: Membrane + geom?: unknown + geom_type?: 'raw' | 'file' | 'sphere' | 'mb' | 'None' + mb?: Primitives } -export interface Membrane{ +// Primitives discribing a compartment +export const enum PrimitiveType { + MetaBall = 0, + Sphere = 1, + Cube = 2, + Cylinder = 3, + Cone = 4, + Plane = 5, + None = 6 +} + +export interface Primitives{ positions?: number[]; radii?: number[]; - source?: string; + types?: PrimitiveType[]; } + export interface Packing { ingredients: { [key: string]: Ingredient } } diff --git a/src/extensions/cellpack/model.ts b/src/extensions/cellpack/model.ts index 8b5dbe904..1a55ed03f 100644 --- a/src/extensions/cellpack/model.ts +++ b/src/extensions/cellpack/model.ts @@ -9,7 +9,7 @@ import { StateAction, StateBuilder, StateTransformer, State } from '../../mol-st import { PluginContext } from '../../mol-plugin/context'; import { PluginStateObject as PSO } from '../../mol-plugin-state/objects'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; -import { Ingredient, CellPacking, Membrane } from './data'; +import { Ingredient, CellPacking, Primitives } from './data'; import { getFromPdb, getFromCellPackDB, IngredientFiles, parseCif, parsePDBfile, getStructureMean, getFromOPM } from './util'; import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext, Unit, Trajectory } from '../../mol-model/structure'; import { trajectoryFromMmCIF, MmcifFormat } from '../../mol-model-formats/structure/mmcif'; @@ -18,7 +18,7 @@ import { Mat4, Vec3, Quat } from '../../mol-math/linear-algebra'; import { SymmetryOperator } from '../../mol-math/geometry'; import { Task, RuntimeContext } from '../../mol-task'; import { StateTransforms } from '../../mol-plugin-state/transforms'; -import { ParseCellPack, StructureFromCellpack, DefaultCellPackBaseUrl, StructureFromAssemblies, CreateSphere } from './state'; +import { ParseCellPack, StructureFromCellpack, DefaultCellPackBaseUrl, StructureFromAssemblies, CreateCompartmentSphere } from './state'; import { MolScriptBuilder as MS } from '../../mol-script/language/builder'; import { getMatFromResamplePoints } from './curve'; import { compile } from '../../mol-script/runtime/query/compiler'; @@ -186,7 +186,7 @@ function getCurveTransforms(ingredient: Ingredient) { // test for resampling const distance: number = Vec3.distance(_points[0], _points[1]); if (distance >= segmentLength + 2.0) { - console.info(distance); + // console.info(distance); resampling = true; } const points = new Float32Array(_points.length * 3); @@ -479,6 +479,7 @@ async function loadMembrane(plugin: PluginContext, name: string, state: State, p } } let legacy_membrane: boolean = false; // temporary variable until all membrane are converted to the new correct cif format + let geometry_membrane: boolean = false; // membrane can be a mesh geometry let b = state.build().toRoot(); if (file) { if (file.name.endsWith('.cif')) { @@ -493,6 +494,10 @@ async function loadMembrane(plugin: PluginContext, name: string, state: State, p } else if (name.toLowerCase().endsWith('.cif')) { const url = Asset.getUrlAsset(plugin.managers.asset, `${params.baseUrl}/membranes/${name}`); b = b.apply(StateTransforms.Data.Download, { url, isBinary: false, label: name }, { state: { isGhost: true } }); + } else if (name.toLowerCase().endsWith('.ply')) { + const url = Asset.getUrlAsset(plugin.managers.asset, `${params.baseUrl}/geometries/${name}`); + b = b.apply(StateTransforms.Data.Download, { url, isBinary: false, label: name }, { state: { isGhost: true } }); + geometry_membrane = true; } else { const url = Asset.getUrlAsset(plugin.managers.asset, `${params.baseUrl}/membranes/${name}.bcif`); b = b.apply(StateTransforms.Data.Download, { url, isBinary: true, label: name }, { state: { isGhost: true } }); @@ -516,6 +521,11 @@ async function loadMembrane(plugin: PluginContext, name: string, state: State, p representation: params.preset.representation, }; await CellpackMembranePreset.apply(membrane, membraneParams, plugin); + } else if (geometry_membrane) { + await b.apply(StateTransforms.Data.ParsePly, undefined, { state: { isGhost: true } }) + .apply(StateTransforms.Model.ShapeFromPly) + .apply(StateTransforms.Representation.ShapeRepresentation3D) + .commit({ revertOnError: true }); } else { const membrane = await b.apply(StateTransforms.Data.ParseCif, undefined, { state: { isGhost: true } }) .apply(StateTransforms.Model.TrajectoryFromMmCif, undefined, { state: { isGhost: true } }) @@ -529,19 +539,20 @@ async function loadMembrane(plugin: PluginContext, name: string, state: State, p } } -async function handleMembraneSpheres(state: State, mb: Membrane) { - const nSpheres = mb.positions!.length / 3; - console.log('ok mb ', nSpheres); +async function handleMembraneSpheres(state: State, primitives: Primitives) { + const nSpheres = primitives.positions!.length / 3; + // console.log('ok mb ', nSpheres); + // TODO : take in account the type of the primitives. for (let j = 0; j < nSpheres; j++) { await state.build() .toRoot() - .apply(CreateSphere, { + .apply(CreateCompartmentSphere, { center: Vec3.create( - mb.positions![j * 3 + 0], - mb.positions![j * 3 + 1], - mb.positions![j * 3 + 2] + primitives.positions![j * 3 + 0], + primitives.positions![j * 3 + 1], + primitives.positions![j * 3 + 2] ), - radius: mb!.radii![j] + radius: primitives!.radii![j] }) .commit(); } @@ -609,14 +620,15 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat }; await CellpackPackingPreset.apply(packing, packingParams, plugin); if (packings[i].location === 'surface') { - console.log('ok surface ' + params.membrane); + // console.log('ok surface ' + params.membrane); if (params.membrane === 'lipids') { - console.log('ok packings[i].geom_type ' + packings[i].geom_type); + // console.log('ok packings[i].geom_type ' + packings[i].geom_type); if (packings[i].geom_type) { if (packings[i].geom_type === 'file') { - await loadMembrane(plugin, packings[i].geom!, state, params); - } else if (packings[i].mb) { - await handleMembraneSpheres(state, packings[i].mb!); + // TODO: load mesh files or vertex,faces data + await loadMembrane(plugin, packings[i].filename!, state, params); + } else if (packings[i].primitives) { + await handleMembraneSpheres(state, packings[i].primitives!); } } else { // try loading membrane from repo as a bcif file or from the given list of files. @@ -625,8 +637,8 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat } } } else if (params.membrane === 'spheres') { - if (packings[i].mb) { - await handleMembraneSpheres(state, packings[i].mb!); + if (packings[i].primitives) { + await handleMembraneSpheres(state, packings[i].primitives!); } } } diff --git a/src/extensions/cellpack/representation.ts b/src/extensions/cellpack/representation.ts index 64dcbf096..261e3a3c4 100644 --- a/src/extensions/cellpack/representation.ts +++ b/src/extensions/cellpack/representation.ts @@ -49,11 +49,6 @@ export type UnitcellProps = PD.Values<MBParams> function getMBMesh(data: MembraneSphereData, props: UnitcellProps, mesh?: Mesh) { const state = MeshBuilder.createState(256, 128, mesh); const radius = props.radius; - // const p = DefaultPolyhedronProps; - // p.detail = 3; - // p.radius = radius; - // const { vertices, indices } = Icosahedron(); - // const asphere = Polyhedron(vertices, indices, p); const asphere = Sphere(3); const trans: Mat4 = Mat4.identity(); Mat4.fromScaling(trans, Vec3.create(radius, radius, radius)); @@ -69,17 +64,6 @@ function getMBShape(ctx: RuntimeContext, data: MembraneSphereData, props: Unitce return Shape.create(label, data, geo, () => props.cellColor, () => 1, () => label); } -// -/* -export function getMBData(model: Model, symmetry: Symmetry, props: UnitcellProps) { - const ref = Vec3(); - if (props.ref === 'model') { - Vec3.transformMat4(ref, Model.getCenter(model), symmetry.spacegroup.cell.toFractional); - } - return { symmetry, ref }; -} -*/ - export type MBRepresentation = Representation<MembraneSphereData, MBParams> export function MBRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneSphereData, MBParams>): MBRepresentation { return Representation.createMulti('MB', ctx, getParams, Representation.StateBuilder, MembraneSphereVisuals as unknown as Representation.Def<MembraneSphereData, MBParams>); diff --git a/src/extensions/cellpack/state.ts b/src/extensions/cellpack/state.ts index 7e6374156..948f0e0cb 100644 --- a/src/extensions/cellpack/state.ts +++ b/src/extensions/cellpack/state.ts @@ -67,7 +67,11 @@ const ParseCellPack = PluginStateTransform.BuiltIn({ for (const name in compartments) { const { surface, interior } = compartments[name]; if (surface) { - packings.push({ name, location: 'surface', ingredients: surface.ingredients, geom: compartments[name].geom, geom_type: compartments[name].geom_type, mb: compartments[name].mb }); + let filename = ''; + if (compartments[name].geom_type === 'file') { + filename = (compartments[name].geom) ? compartments[name].geom as string : ''; + } + packings.push({ name, location: 'surface', ingredients: surface.ingredients, filename: filename, geom_type: compartments[name].geom_type, primitives: compartments[name].mb }); for (const iName in surface.ingredients) { if (surface.ingredients[iName].ingtype === 'fiber') { cell.mapping_ids[-(fiber_counter_id + 1)] = [comp_counter, iName]; @@ -295,9 +299,9 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({ }); const CreateTransformer = StateTransformer.builderFactory('cellPACK'); -export const CreateSphere = CreateTransformer({ - name: 'create-sphere', - display: 'Sphere', +export const CreateCompartmentSphere = CreateTransformer({ + name: 'create-compartment-sphere', + display: 'CompartmentSphere', from: PSO.Root, // or whatever data source to: PSO.Shape.Representation3D, params: { @@ -309,11 +313,11 @@ export const CreateSphere = CreateTransformer({ return true; }, apply({ a, params }, plugin: PluginContext) { - return Task.create('Custom Sphere', async ctx => { + return Task.create('Compartment Sphere', async ctx => { const data = params; const repr = MBRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => (MBParams)); await repr.createOrUpdate({ ...params, quality: 'custom', doubleSided: true }, data).runInContext(ctx); - return new PSO.Shape.Representation3D({ repr, sourceData: a }, { label: `My Sphere` }); + return new PSO.Shape.Representation3D({ repr, sourceData: a }, { label: `Compartment Sphere` }); }); } }); \ No newline at end of file diff --git a/src/extensions/cellpack/util.ts b/src/extensions/cellpack/util.ts index 452b4c4b5..b7c8aea30 100644 --- a/src/extensions/cellpack/util.ts +++ b/src/extensions/cellpack/util.ts @@ -38,7 +38,6 @@ async function downloadPDB(plugin: PluginContext, url: string, id: string, asset } export async function getFromPdb(plugin: PluginContext, pdbId: string, assetManager: AssetManager) { - // ${pdbId.toUpperCase()} const { cif, asset } = await downloadCif(plugin, `https://models.rcsb.org/${pdbId}.bcif`, true, assetManager); return { mmcif: cif.blocks[0], asset }; } @@ -107,90 +106,4 @@ export function getFloatValue(value: DataView, offset: number) { } return mantissa * Math.pow(10, exponent); -} - -/* -async function loadPackingResultsBinary(plugin: PluginContext, runtime: RuntimeContext, file: Asset.File, packing: CellPack){ - const model_data = await readFromFile(file.file!, 'binary').runInContext(runtime);// async ? - let buffer = model_data.buffer; - let {cell, packings } = packing; - if (!IsNativeEndianLittle) { - // flip the byte order - buffer = flipByteOrder(model_data, 4); - } - const numbers = new DataView(buffer); - const ninst = getFloatValue(numbers, 0); - const npoints = getFloatValue(numbers, 4); - const ncurve = getFloatValue(numbers, 8); - - let pos = new Float32Array(); - let quat = new Float32Array(); - let ctr_pos = new Float32Array(); - let ctr_info = new Float32Array(); - let curve_ids = new Float32Array(); - - let offset = 12; - if (ninst !== 0){ - pos = new Float32Array(buffer, offset, ninst * 4);offset += ninst * 4 * 4; - quat = new Float32Array(buffer, offset, ninst * 4);offset += ninst * 4 * 4; - } - if ( npoints !== 0 ) { - ctr_pos = new Float32Array(buffer, offset, npoints * 4);offset += npoints * 4 * 4; - offset += npoints * 4 * 4; - ctr_info = new Float32Array(buffer, offset, npoints * 4);offset += npoints * 4 * 4; - curve_ids = new Float32Array(buffer, offset, ncurve * 4);offset += ncurve * 4 * 4; - } - - for (let i = 0; i < ninst; i++) { - const x: number = pos[i * 4 + 0]; - const y: number = pos[i * 4 + 1]; - const z: number = pos[i * 4 + 2]; - const ingr_id = pos[i * 4 + 3] as number; - const pid = cell.mapping_ids![ingr_id]; - if (!packings[pid[0]].ingredients[pid[1]].results) { - packings[pid[0]].ingredients[pid[1]].results = []; - } - packings[pid[0]].ingredients[pid[1]].results.push([Vec3.create(x, y, z), - Quat.create(quat[i * 4 + 0], quat[i * 4 + 1], quat[i * 4 + 2], quat[i * 4 + 3])]); - } - let counter = 0; - let ctr_points: Vec3[] = []; - let prev_ctype = 0; - let prev_cid = 0; - - for (let i = 0; i < npoints; i++) { - const x: number = -ctr_pos[i * 4 + 0]; - const y: number = ctr_pos[i * 4 + 1]; - const z: number = ctr_pos[i * 4 + 2]; - const cid: number = ctr_info[i * 4 + 0];// curve id - const ctype: number = curve_ids[cid * 4 + 0];// curve type - // cid 148 165 -1 0 - // console.log("cid ",cid,ctype,prev_cid,prev_ctype);//165,148 - if (prev_ctype !== ctype){ - const pid = cell.mapping_ids![-prev_ctype - 1]; - const cname = `curve${counter}`; - packings[pid[0]].ingredients[pid[1]].nbCurve = counter + 1; - packings[pid[0]].ingredients[pid[1]][cname] = ctr_points; - ctr_points = []; - counter = 0; - } else if (prev_cid !== cid){ - ctr_points = []; - const pid = cell.mapping_ids![-prev_ctype - 1]; - const cname = `curve${counter}`; - packings[pid[0]].ingredients[pid[1]][cname] = ctr_points; - counter += 1; - } - ctr_points.push(Vec3.create(x, y, z)); - prev_ctype = ctype; - prev_cid = cid; - } - // do the last one - if ( npoints !== 0 ) { - const pid = cell.mapping_ids![-prev_ctype - 1]; - const cname = `curve${counter}`; - packings[pid[0]].ingredients[pid[1]].nbCurve = counter + 1; - packings[pid[0]].ingredients[pid[1]][cname] = ctr_points; - } - return packings; -} -*/ \ No newline at end of file +} \ No newline at end of file -- GitLab