Browse Source

add model Unitcell representation

Alexander Rose 5 years ago
parent
commit
cc00ada5a3

+ 1 - 0
src/mol-plugin/index.ts

@@ -49,6 +49,7 @@ export const DefaultPluginSpec: PluginSpec = {
         PluginSpec.Action(StateTransforms.Model.StructureSelectionFromScript),
         PluginSpec.Action(StateTransforms.Representation.StructureRepresentation3D),
         PluginSpec.Action(StateTransforms.Representation.StructureLabels3D),
+        PluginSpec.Action(StateTransforms.Representation.ModelUnitcell3D),
         PluginSpec.Action(StateTransforms.Representation.ExplodeStructureRepresentation3D),
         PluginSpec.Action(StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D),
         PluginSpec.Action(StateTransforms.Representation.OverpaintStructureRepresentation3DFromScript),

+ 29 - 0
src/mol-plugin/state/transforms/representation.ts

@@ -31,6 +31,7 @@ import { Overpaint } from '../../../mol-theme/overpaint';
 import { Transparency } from '../../../mol-theme/transparency';
 import { BaseGeometry } from '../../../mol-geo/geometry/base';
 import { Script } from '../../../mol-script/script';
+import { getUnitcellRepresentation, UnitcellParams } from '../../util/model-unitcell';
 
 export { StructureRepresentation3D }
 export { StructureRepresentation3DHelpers }
@@ -667,4 +668,32 @@ const ShapeRepresentation3D = PluginStateTransform.BuiltIn({
             return StateTransformer.UpdateResult.Updated;
         });
     }
+});
+
+export { ModelUnitcell3D }
+type ModelUnitcell3D = typeof ModelUnitcell3D
+const ModelUnitcell3D = PluginStateTransform.BuiltIn({
+    name: 'model-unitcell-3d',
+    display: 'Model Unitcell',
+    from: SO.Molecule.Model,
+    to: SO.Shape.Representation3D,
+    params: {
+        ...UnitcellParams,
+    }
+})({
+    canAutoUpdate({ oldParams, newParams }) {
+        return true;
+    },
+    apply({ a, params }) {
+        return Task.create('Model Unitcell', async ctx => {
+            const repr = await getUnitcellRepresentation(ctx, a.data, params);
+            return new SO.Shape.Representation3D({ repr, source: a }, { label: `Unitcell`, description: a.data.symmetry.spacegroup.name });
+        });
+    },
+    update({ a, b, newParams }) {
+        return Task.create('Model Unitcell', async ctx => {
+            await getUnitcellRepresentation(ctx, a.data, newParams, b.data.repr as ShapeRepresentation<any, any, any>);
+            return StateTransformer.UpdateResult.Updated;
+        });
+    }
 });

+ 91 - 0
src/mol-plugin/util/model-unitcell.ts

@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Model, ModelSymmetry } from '../../mol-model/structure';
+import { StateTransformer } from '../../mol-state';
+import { ModelUnitcell3D } from '../state/transforms/representation';
+import { ShapeRepresentation } from '../../mol-repr/shape/representation';
+import { Text } from '../../mol-geo/geometry/text/text';
+import { Shape } from '../../mol-model/shape';
+import { ColorNames } from '../../mol-util/color/names';
+import { RuntimeContext } from '../../mol-task';
+import { ParamDefinition as PD } from '../../mol-util/param-definition';
+import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
+import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
+import { BoxCage } from '../../mol-geo/primitive/box';
+import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
+import { transformCage, copyCage } from '../../mol-geo/primitive/cage';
+import { radToDeg } from '../../mol-math/misc';
+
+const translate05 = Mat4.fromTranslation(Mat4(), Vec3.create(0.5, 0.5, 0.5))
+const unitCage = transformCage(copyCage(BoxCage()), translate05)
+
+const tmpRef = Vec3()
+const tmpTranslate = Mat4()
+
+interface UnitcellData {
+    symmetry: ModelSymmetry
+    ref: Vec3
+}
+
+export const UnitcellParams = {
+    ...Mesh.Params,
+    cellColor: PD.Color(ColorNames.orange),
+    cellScale: PD.Numeric(2, { min: 0.1, max: 5, step: 0.1 })
+}
+export type UnitcellParams = typeof UnitcellParams
+export type UnitcellProps = PD.Values<UnitcellParams>
+
+function getUnitcellMesh(data: UnitcellData, props: UnitcellProps, mesh?: Mesh) {
+    const state = MeshBuilder.createState(256, 128, mesh)
+
+    const { fromFractional } = data.symmetry.spacegroup.cell
+
+    Vec3.floor(tmpRef, data.ref)
+    Mat4.fromTranslation(tmpTranslate, tmpRef)
+    const cellCage = transformCage(copyCage(unitCage), tmpTranslate)
+
+    const radius = (Math.cbrt(data.symmetry.spacegroup.cell.volume) / 100) * props.cellScale
+    state.currentGroup = 1
+    MeshBuilder.addCage(state, fromFractional, cellCage, radius, 2, 20)
+
+    return MeshBuilder.getMesh(state)
+}
+
+export async function getUnitcellRepresentation(ctx: RuntimeContext, model: Model, params: StateTransformer.Params<ModelUnitcell3D>, prev?: ShapeRepresentation<UnitcellData, Text, Text.Params>) {
+    const repr = prev || ShapeRepresentation(getUnitcellShape, Mesh.Utils);
+    const data = {
+        symmetry: model.symmetry,
+        ref: Vec3.transformMat4(Vec3(), Model.getCenter(model), model.symmetry.spacegroup.cell.toFractional)
+    }
+    await repr.createOrUpdate(params, data).runInContext(ctx);
+    return repr;
+}
+
+function getUnitcellLabel(data: UnitcellData) {
+    const { cell, name } = data.symmetry.spacegroup
+    const { index, size, anglesInRadians } = cell
+    const a = size[0].toFixed(2)
+    const b = size[1].toFixed(2)
+    const c = size[2].toFixed(2)
+    const alpha = radToDeg(anglesInRadians[0]).toFixed(2)
+    const beta = radToDeg(anglesInRadians[1]).toFixed(2)
+    const gamma = radToDeg(anglesInRadians[2]).toFixed(2)
+    const label: string[] = []
+    // name
+    label.push(`${name} #${index + 1}`)
+    // sizes
+    label.push(`${a}\u00D7${b}\u00D7${c} \u212B`)
+    // angles
+    label.push(`\u03b1=${alpha}\u00B0 \u03b2=${beta}\u00B0 \u03b3=${gamma}\u00B0`)
+    return label.join(' | ')
+}
+
+function getUnitcellShape(ctx: RuntimeContext, data: UnitcellData, props: UnitcellProps, shape?: Shape<Mesh>) {
+    const geo = getUnitcellMesh(data, props, shape && shape.geometry);
+    const label = getUnitcellLabel(data)
+    return Shape.create('Unitcell', data, geo, () => props.cellColor, () => 1, () => label)
+}