Browse Source

wip, structure orientation representation

Alexander Rose 5 years ago
parent
commit
911a7e3636

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

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

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

@@ -32,6 +32,7 @@ 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';
+import { getStructureOrientationRepresentation, OrientationParams } from '../../util/structure-orientation';
 
 export { StructureRepresentation3D }
 export { StructureRepresentation3DHelpers }
@@ -698,4 +699,32 @@ const ModelUnitcell3D = PluginStateTransform.BuiltIn({
             return StateTransformer.UpdateResult.Updated;
         });
     }
+});
+
+export { StructureOrientation3D }
+type StructureOrientation3D = typeof StructureOrientation3D
+const StructureOrientation3D = PluginStateTransform.BuiltIn({
+    name: 'structure-orientation-3d',
+    display: 'Structure Orientation',
+    from: SO.Molecule.Structure,
+    to: SO.Shape.Representation3D,
+    params: {
+        ...OrientationParams,
+    }
+})({
+    canAutoUpdate({ oldParams, newParams }) {
+        return true;
+    },
+    apply({ a, params }) {
+        return Task.create('Structure Orientation', async ctx => {
+            const repr = await getStructureOrientationRepresentation(ctx, a.data, params);
+            return new SO.Shape.Representation3D({ repr, source: a }, { label: `Orientation` });
+        });
+    },
+    update({ a, b, newParams }) {
+        return Task.create('Structure Orientation', async ctx => {
+            await getStructureOrientationRepresentation(ctx, a.data, newParams, b.data.repr as ShapeRepresentation<any, any, any>);
+            return StateTransformer.UpdateResult.Updated;
+        });
+    }
 });

+ 108 - 0
src/mol-plugin/util/structure-orientation.ts

@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Structure } from '../../mol-model/structure';
+import { ShapeRepresentation } from '../../mol-repr/shape/representation';
+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 { Vec3, Mat4 } from '../../mol-math/linear-algebra';
+import Matrix from '../../mol-math/linear-algebra/matrix/matrix';
+import { PrincipalAxes } from '../../mol-math/linear-algebra/matrix/principal-axes';
+import { createCage } from '../../mol-geo/primitive/cage';
+import { stringToWords } from '../../mol-util/string';
+
+const tmpMatrixPos = Vec3.zero()
+export function getPositionMatrix(structure: Structure) {
+    const mat = Matrix.create(3, structure.elementCount)
+    for (let i = 0, m = 0, il = structure.units.length; i < il; ++i) {
+        const unit = structure.units[i]
+        const { elements } = unit
+        const pos = unit.conformation.position
+        for (let j = 0, jl = elements.length; j < jl; ++j) {
+            pos(elements[j], tmpMatrixPos)
+            Vec3.toArray(tmpMatrixPos, mat.data, m + j * 3)
+        }
+        m += elements.length * 3
+    }
+    return mat
+}
+
+interface OrientationData {
+    principalAxes: PrincipalAxes
+}
+
+const OrientationVisuals = { 'principal-axes': '', 'oriented-box': '' }
+type OrientationVisualName = keyof typeof OrientationVisuals
+const OrientationVisualOptions = Object.keys(OrientationVisuals).map(name => [name, stringToWords(name)] as [OrientationVisualName, string])
+
+export const OrientationParams = {
+    ...Mesh.Params,
+    visuals: PD.MultiSelect<OrientationVisualName>(['principal-axes'], OrientationVisualOptions),
+    orientationColor: PD.Color(ColorNames.orange),
+    orientationScale: PD.Numeric(2, { min: 0.1, max: 5, step: 0.1 })
+}
+export type OrientationParams = typeof OrientationParams
+export type OrientationProps = PD.Values<OrientationParams>
+
+enum VisualGroup {
+    PrincipalAxes = 1,
+    OrientedBox = 2
+}
+
+function buildPrincipalAxes(state: MeshBuilder.State, data: OrientationData, props: OrientationProps) {
+    const vertices = new Float32Array(6 * 3)
+    const edges = new Uint8Array([0, 1, 2, 3, 4, 5])
+    Vec3.toArray(data.principalAxes.begA, vertices, 0)
+    Vec3.toArray(data.principalAxes.endA, vertices, 3)
+    Vec3.toArray(data.principalAxes.begB, vertices, 6)
+    Vec3.toArray(data.principalAxes.endB, vertices, 9)
+    Vec3.toArray(data.principalAxes.begC, vertices, 12)
+    Vec3.toArray(data.principalAxes.endC, vertices, 15)
+
+    const matrix = Mat4.fromTranslation(Mat4(), Vec3.inverse(Vec3(), data.principalAxes.center))
+
+    const cage = createCage(vertices, edges)
+    const radius = 0.3 * props.orientationScale
+    state.currentGroup = VisualGroup.PrincipalAxes
+    MeshBuilder.addCage(state, matrix, cage, radius, 2, 20)
+}
+
+function getOrientationMesh(data: OrientationData, props: OrientationProps, mesh?: Mesh) {
+    const state = MeshBuilder.createState(256, 128, mesh)
+
+    if (props.visuals.includes('principal-axes')) buildPrincipalAxes(state, data, props)
+
+    return MeshBuilder.getMesh(state)
+}
+
+export async function getStructureOrientationRepresentation(ctx: RuntimeContext, structure: Structure, params: OrientationProps, prev?: ShapeRepresentation<OrientationData, Mesh, Mesh.Params>) {
+    const repr = prev || ShapeRepresentation(getOrientationShape, Mesh.Utils);
+    const data = {
+        principalAxes: PrincipalAxes.fromPoints(getPositionMatrix(structure))
+    }
+    await repr.createOrUpdate(params, data).runInContext(ctx);
+    return repr;
+}
+
+function getOrientationLabel(data: OrientationData, groupId: number): string {
+    switch (groupId) {
+        case VisualGroup.PrincipalAxes: return 'Principal Axes'
+        case VisualGroup.OrientedBox: return 'Oriented Box'
+    }
+    return 'Unknown Orientation Visual'
+}
+
+function getOrientationShape(ctx: RuntimeContext, data: OrientationData, props: OrientationProps, shape?: Shape<Mesh>) {
+    const geo = getOrientationMesh(data, props, shape && shape.geometry);
+    const getLabel = function (groupId: number ) {
+        return getOrientationLabel(data, groupId)
+    }
+    return Shape.create('Principal Axes', data, geo, () => props.orientationColor, () => 1, getLabel)
+}