Browse Source

support for compartment PLY file.

ludovic autin 3 years ago
parent
commit
35baaaf594

+ 21 - 9
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 }
 }

+ 30 - 18
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!);
                 }
             }
         }

+ 0 - 16
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>);

+ 10 - 6
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` });
         });
     }
 });

+ 1 - 88
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;
-}
-*/
+}