فهرست منبع

mol-plugin-state: StructureCoordinateSystem decorator (wip)
+ SymmetryOperator.assembly now optional

David Sehnal 5 سال پیش
والد
کامیت
7311e6f484

+ 4 - 2
src/apps/basic-wrapper/helpers.ts

@@ -58,12 +58,14 @@ export namespace StateHelper {
 
     export function identityTransform(b: StateBuilder.To<PSO.Molecule.Structure>, m: Mat4) {
         return b.apply(StateTransforms.Model.TransformStructureConformation,
-            { axis: Vec3.create(1, 0, 0), angle: 0, translation: Vec3.zero() },
+            { transform: { name: 'components', params: { axis: Vec3.create(1, 0, 0), angle: 0, translation: Vec3.zero() } } },
             { tags: 'transform' });
     }
 
     export function transform(b: StateBuilder.To<PSO.Molecule.Structure>, matrix: Mat4) {
-        return b.apply(StateTransforms.Model.TransformStructureConformationByMatrix, { matrix }, { tags: 'transform' });
+        return b.apply(StateTransforms.Model.TransformStructureConformation, { 
+            transform: { name: 'matrix', params: matrix }
+        }, { tags: 'transform' });
     }
 
     export function assemble(b: StateBuilder.To<PSO.Molecule.Model>, id?: string) {

+ 3 - 3
src/mol-math/geometry/symmetry-operator.ts

@@ -11,7 +11,7 @@ import { defaults } from '../../mol-util';
 interface SymmetryOperator {
     readonly name: string,
 
-    readonly assembly: {
+    readonly assembly?: {
         /** pointer to `pdbx_struct_assembly.id` or empty string */
         readonly id: string
         /** pointers to `pdbx_struct_oper_list.id` or empty list */
@@ -34,11 +34,11 @@ interface SymmetryOperator {
 
 namespace SymmetryOperator {
     export const DefaultName = '1_555'
-    export const Default: SymmetryOperator = create(DefaultName, Mat4.identity(), { id: '', operList: [] });
+    export const Default: SymmetryOperator = create(DefaultName, Mat4.identity());
 
     export const RotationTranslationEpsilon = 0.005;
 
-    export function create(name: string, matrix: Mat4, assembly: SymmetryOperator['assembly'], ncsId?: string, hkl?: Vec3, spgrOp?: number): SymmetryOperator {
+    export function create(name: string, matrix: Mat4, assembly?: SymmetryOperator['assembly'], ncsId?: string, hkl?: Vec3, spgrOp?: number): SymmetryOperator {
         const _hkl = hkl ? Vec3.clone(hkl) : Vec3.zero();
         spgrOp = defaults(spgrOp, -1)
         ncsId = ncsId || ''

+ 2 - 2
src/mol-model-props/rcsb/assembly-symmetry.ts

@@ -42,7 +42,7 @@ export namespace AssemblySymmetry {
         // check if assembly is 'biological'
         const mmcif = structure.models[0].sourceData.data.db
         if (!mmcif.pdbx_struct_assembly.details.isDefined) return false
-        const id = structure.units[0].conformation.operator.assembly.id
+        const id = structure.units[0].conformation.operator.assembly?.id || ''
         if (id === '' || id === 'deposited') return true
         const indices = Column.indicesOf(mmcif.pdbx_struct_assembly.id, e => e === id)
         if (indices.length !== 1) return false
@@ -55,7 +55,7 @@ export namespace AssemblySymmetry {
 
         const client = new GraphQLClient(props.serverUrl, ctx.fetch)
         const variables: AssemblySymmetryQueryVariables = {
-            assembly_id: structure.units[0].conformation.operator.assembly.id || 'deposited',
+            assembly_id: structure.units[0].conformation.operator.assembly?.id || 'deposited',
             entry_id: structure.units[0].model.entryId
         }
         const result = await client.request<AssemblySymmetryQuery>(ctx.runtime, query, variables)

+ 1 - 1
src/mol-model-props/rcsb/representations/assembly-symmetry.ts

@@ -87,7 +87,7 @@ export type AssemblySymmetryProps = PD.Values<AssemblySymmetryParams>
 //
 
 function getAssemblyName(s: Structure) {
-    const { id } = s.units[0].conformation.operator.assembly
+    const id = s.units[0].conformation.operator.assembly?.id || ''
     return isInteger(id) ? `Assembly ${id}` : id
 }
 

+ 2 - 1
src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts

@@ -69,11 +69,12 @@ export function AssemblySymmetryClusterColorTheme(ctx: ThemeDataContext, props:
         const palette = getPalette(clusters.length, props)
         legend = palette.legend
 
+        const _emptyList: any[] = [];
         color = (location: Location): Color => {
             if (StructureElement.Location.is(location)) {
                 const { assembly } = location.unit.conformation.operator
                 const asymId = getAsymId(location.unit)(location)
-                const cluster = clusterByMember.get(clusterMemberKey(asymId, assembly.operList))
+                const cluster = clusterByMember.get(clusterMemberKey(asymId, assembly?.operList || _emptyList))
                 return cluster !== undefined ? palette.color(cluster) : DefaultColor
             }
             return DefaultColor

+ 4 - 2
src/mol-model/structure/structure/properties.ts

@@ -10,6 +10,7 @@ import Unit from './unit'
 import { VdwRadius } from '../model/properties/atomic';
 import { SecondaryStructureType } from '../model/types';
 import { SecondaryStructureProvider } from '../../../mol-model-props/computed/secondary-structure';
+import { SymmetryOperator } from '../../../mol-math/geometry';
 
 function p<T>(p: StructureElement.Property<T>) { return p; }
 
@@ -167,6 +168,7 @@ const entity = {
     pdbx_ec: p(l => l.unit.model.entities.data.pdbx_ec.value(eK(l)))
 }
 
+const _emptyList: any[] = [];
 const unit = {
     id: p(l => l.unit.id),
     chainGroupId: p(l => l.unit.chainGroupId),
@@ -180,8 +182,8 @@ const unit = {
     spgrOp: p(l => l.unit.conformation.operator.spgrOp),
 
     model_num: p(l => l.unit.model.modelNum),
-    pdbx_struct_assembly_id: p(l => l.unit.conformation.operator.assembly.id),
-    pdbx_struct_oper_list_ids: p(l => l.unit.conformation.operator.assembly.operList),
+    pdbx_struct_assembly_id: p(l => l.unit.conformation.operator.assembly?.id || SymmetryOperator.DefaultName),
+    pdbx_struct_oper_list_ids: p(l => l.unit.conformation.operator.assembly?.operList || _emptyList),
     struct_ncs_oper_id: p(l => l.unit.conformation.operator.ncsId),
 }
 

+ 7 - 1
src/mol-model/structure/structure/structure.ts

@@ -205,7 +205,13 @@ class Structure {
     }
 
     get coordinateSystem() {
-        return this._props.coordinateSystem;
+        // TODO: do not use SymmetryOperator for this?
+        // TODO: figure out a good way to compose this
+        return this.parent?.coordinateSystem || this._props.coordinateSystem;
+    }
+
+    set coordinateSystem(op: SymmetryOperator) {
+        this._props.coordinateSystem = op;
     }
 
     get label() {

+ 0 - 9
src/mol-plugin-state/actions/structure.ts

@@ -356,15 +356,6 @@ export const EnableStructureCustomProps = StateAction.build({
     }
 })(({ ref, params }, ctx: PluginContext) => ctx.builders.structure.insertStructureProperties(ref, params));
 
-export const TransformStructureConformation = StateAction.build({
-    display: { name: 'Transform Conformation' },
-    from: PluginStateObject.Molecule.Structure,
-    params: StateTransforms.Model.TransformStructureConformation.definition.params,
-})(({ ref, params, state }) => {
-    const root = state.build().to(ref).insert(StateTransforms.Model.TransformStructureConformation, params as any);
-    return state.updateTree(root);
-});
-
 export const AddTrajectory = StateAction.build({
     display: { name: 'Add Trajectory', description: 'Add trajectory from existing model/topology and coordinates.' },
     from: PluginStateObject.Root,

+ 1 - 1
src/mol-plugin-state/helpers/structure-component.ts

@@ -115,7 +115,7 @@ export function updateStructureComponent(a: Structure, b: SO.Molecule.Structure,
                 return StateTransformer.UpdateResult.Recreate;
             }
 
-            if (a === cache.source) return StateTransformer.UpdateResult.Unchanged;
+            if (a === cache.source) break;
 
             const entry = (cache as { entry: StructureQueryHelper.CacheEntry }).entry;
 

+ 94 - 60
src/mol-plugin-state/transforms/model.ts

@@ -5,33 +5,33 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
+import { parse3DG } from '../../mol-io/reader/3dg/parser';
+import { parseDcd } from '../../mol-io/reader/dcd/parser';
+import { parseGRO } from '../../mol-io/reader/gro/parser';
 import { parsePDB } from '../../mol-io/reader/pdb/parser';
-import { Vec3, Mat4, Quat } from '../../mol-math/linear-algebra';
+import { SymmetryOperator } from '../../mol-math/geometry';
+import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
+import { shapeFromPly } from '../../mol-model-formats/shape/ply';
+import { trajectoryFrom3DG } from '../../mol-model-formats/structure/3dg';
+import { coordinatesFromDcd } from '../../mol-model-formats/structure/dcd';
+import { trajectoryFromGRO } from '../../mol-model-formats/structure/gro';
 import { trajectoryFromMmCIF } from '../../mol-model-formats/structure/mmcif';
 import { trajectoryFromPDB } from '../../mol-model-formats/structure/pdb';
-import { Model, Queries, QueryContext, Structure, StructureQuery, StructureSelection as Sel, StructureElement, Coordinates, Topology } from '../../mol-model/structure';
+import { topologyFromPsf } from '../../mol-model-formats/structure/psf';
+import { Coordinates, Model, Queries, QueryContext, Structure, StructureElement, StructureQuery, StructureSelection as Sel, Topology } from '../../mol-model/structure';
 import { PluginContext } from '../../mol-plugin/context';
 import { MolScriptBuilder } from '../../mol-script/language/builder';
 import Expression from '../../mol-script/language/expression';
+import { Script } from '../../mol-script/script';
 import { StateObject, StateTransformer } from '../../mol-state';
 import { RuntimeContext, Task } from '../../mol-task';
+import { deepEqual } from '../../mol-util';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
-import { PluginStateObject as SO, PluginStateTransform } from '../objects';
-import { trajectoryFromGRO } from '../../mol-model-formats/structure/gro';
-import { parseGRO } from '../../mol-io/reader/gro/parser';
-import { shapeFromPly } from '../../mol-model-formats/shape/ply';
-import { SymmetryOperator } from '../../mol-math/geometry';
-import { Script } from '../../mol-script/script';
-import { parse3DG } from '../../mol-io/reader/3dg/parser';
-import { trajectoryFrom3DG } from '../../mol-model-formats/structure/3dg';
-import { StructureSelectionQueries } from '../helpers/structure-selection-query';
-import { StructureQueryHelper } from '../helpers/structure-query';
 import { RootStructureDefinition } from '../helpers/root-structure';
-import { parseDcd } from '../../mol-io/reader/dcd/parser';
-import { coordinatesFromDcd } from '../../mol-model-formats/structure/dcd';
-import { topologyFromPsf } from '../../mol-model-formats/structure/psf';
-import { deepEqual } from '../../mol-util';
-import { StructureComponentParams, createStructureComponent, updateStructureComponent } from '../helpers/structure-component';
+import { createStructureComponent, StructureComponentParams, updateStructureComponent } from '../helpers/structure-component';
+import { StructureQueryHelper } from '../helpers/structure-query';
+import { StructureSelectionQueries } from '../helpers/structure-selection-query';
+import { PluginStateObject as SO, PluginStateTransform } from '../objects';
 
 export { CoordinatesFromDcd };
 export { TopologyFromPsf };
@@ -44,16 +44,17 @@ export { TrajectoryFrom3DG };
 export { ModelFromTrajectory };
 export { StructureFromTrajectory };
 export { StructureFromModel };
+export { StructureCoordinateSystem };
 export { TransformStructureConformation };
-export { TransformStructureConformationByMatrix };
 export { StructureSelectionFromExpression };
-export { MultiStructureSelectionFromExpression }
+export { MultiStructureSelectionFromExpression };
 export { StructureSelectionFromScript };
 export { StructureSelectionFromBundle };
 export { StructureComplexElement };
-export { StructureComponent }
+export { StructureComponent };
 export { CustomModelProperties };
 export { CustomStructureProperties };
+export { ShapeFromPly };
 
 type CoordinatesFromDcd = typeof CoordinatesFromDcd
 const CoordinatesFromDcd = PluginStateTransform.BuiltIn({
@@ -291,69 +292,103 @@ const StructureFromModel = PluginStateTransform.BuiltIn({
 });
 
 const _translation = Vec3(), _m = Mat4(), _n = Mat4();
-type TransformStructureConformation = typeof TransformStructureConformation
-const TransformStructureConformation = PluginStateTransform.BuiltIn({
-    name: 'transform-structure-conformation',
-    display: { name: 'Transform Conformation' },
+
+type StructureCoordinateSystem = typeof StructureCoordinateSystem
+const StructureCoordinateSystem = PluginStateTransform.BuiltIn({
+    name: 'structure-coordinate-system',
+    display: { name: 'Coordinate System' },
+    isDecorator: true,
     from: SO.Molecule.Structure,
     to: SO.Molecule.Structure,
     params: {
-        axis: PD.Vec3(Vec3.create(1, 0, 0)),
-        angle: PD.Numeric(0, { min: -180, max: 180, step: 0.1 }),
-        translation: PD.Vec3(Vec3.create(0, 0, 0)),
+        transform: PD.MappedStatic('components', {
+            components: PD.Group({
+                axis: PD.Vec3(Vec3.create(1, 0, 0)),
+                angle: PD.Numeric(0, { min: -180, max: 180, step: 0.1 }),
+                translation: PD.Vec3(Vec3.create(0, 0, 0)),
+            }, { isFlat: true }),
+            matrix: PD.Value(Mat4.identity(), { isHidden: true })
+        }, { label: 'Kind' })
     }
 })({
-    canAutoUpdate() {
-        return true;
+    canAutoUpdate({ newParams }) {
+        return newParams.transform.name === 'components';
     },
     apply({ a, params }) {
         // TODO: optimze
 
-        const center = a.data.boundary.sphere.center;
-        Mat4.fromTranslation(_m, Vec3.negate(_translation, center));
-        Mat4.fromTranslation(_n, Vec3.add(_translation, center, params.translation));
-        const rot = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * params.angle, Vec3.normalize(Vec3.zero(), params.axis));
+        const transform = Mat4.zero();
 
-        const m = Mat4.zero();
-        Mat4.mul3(m, _n, rot, _m);
+        if (params.transform.name === 'components') {
+            const { axis, angle, translation } = params.transform.params;
+            const center = a.data.boundary.sphere.center;
+            Mat4.fromTranslation(_m, Vec3.negate(_translation, center));
+            Mat4.fromTranslation(_n, Vec3.add(_translation, center, translation));
+            const rot = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * angle, Vec3.normalize(Vec3.zero(), axis));
+            Mat4.mul3(transform, _n, rot, _m);
+        } else {
+            Mat4.copy(transform, params.transform.params);
+        }
 
-        const s = Structure.transform(a.data, m);
-        const props = { label: `${a.label}`, description: 'Transformed' };
-        return new SO.Molecule.Structure(s, props);
-    },
-    interpolate(src, tar, t) {
-        // TODO: optimize
-        const u = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * src.angle, Vec3.normalize(Vec3(), src.axis));
-        Mat4.setTranslation(u, src.translation);
-        const v = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * tar.angle, Vec3.normalize(Vec3(), tar.axis));
-        Mat4.setTranslation(v, tar.translation);
-        const m = SymmetryOperator.slerp(Mat4.zero(), u, v, t);
-        const rot = Mat4.getRotation(Quat.zero(), m);
-        const axis = Vec3.zero();
-        const angle = Quat.getAxisAngle(axis, rot);
-        const translation = Mat4.getTranslation(Vec3.zero(), m);
-        return { axis, angle, translation };
+        // TODO: compose with parent's coordinate system
+        a.data.coordinateSystem = SymmetryOperator.create('CS', transform);
+        return new SO.Molecule.Structure(a.data, { label: a.label, description: `${a.description} [Transformed]` });
     }
 });
 
-type TransformStructureConformationByMatrix = typeof TransformStructureConformation
-const TransformStructureConformationByMatrix = PluginStateTransform.BuiltIn({
-    name: 'transform-structure-conformation-by-matrix',
+type TransformStructureConformation = typeof TransformStructureConformation
+const TransformStructureConformation = PluginStateTransform.BuiltIn({
+    name: 'transform-structure-conformation',
     display: { name: 'Transform Conformation' },
+    isDecorator: true,
     from: SO.Molecule.Structure,
     to: SO.Molecule.Structure,
     params: {
-        matrix: PD.Value<Mat4>(Mat4.identity(), { isHidden: true })
+        transform: PD.MappedStatic('components', {
+            components: PD.Group({
+                axis: PD.Vec3(Vec3.create(1, 0, 0)),
+                angle: PD.Numeric(0, { min: -180, max: 180, step: 0.1 }),
+                translation: PD.Vec3(Vec3.create(0, 0, 0)),
+            }, { isFlat: true }),
+            matrix: PD.Value(Mat4.identity(), { isHidden: true })
+        }, { label: 'Kind' })
     }
 })({
     canAutoUpdate() {
         return true;
     },
     apply({ a, params }) {
-        const s = Structure.transform(a.data, params.matrix);
-        const props = { label: `${a.label}`, description: 'Transformed' };
-        return new SO.Molecule.Structure(s, props);
-    }
+        // TODO: optimze
+
+        const transform = Mat4.zero();
+
+        if (params.transform.name === 'components') {
+            const { axis, angle, translation } = params.transform.params;
+            const center = a.data.boundary.sphere.center;
+            Mat4.fromTranslation(_m, Vec3.negate(_translation, center));
+            Mat4.fromTranslation(_n, Vec3.add(_translation, center, translation));
+            const rot = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * angle, Vec3.normalize(Vec3.zero(), axis));
+            Mat4.mul3(transform, _n, rot, _m);
+        } else {
+            Mat4.copy(transform, params.transform.params);
+        }
+
+        const s = Structure.transform(a.data, transform);
+        return new SO.Molecule.Structure(s, { label: a.label, description: `${a.description} [Transformed]` });
+    }
+    // interpolate(src, tar, t) {
+    //     // TODO: optimize
+    //     const u = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * src.angle, Vec3.normalize(Vec3(), src.axis));
+    //     Mat4.setTranslation(u, src.translation);
+    //     const v = Mat4.fromRotation(Mat4.zero(), Math.PI / 180 * tar.angle, Vec3.normalize(Vec3(), tar.axis));
+    //     Mat4.setTranslation(v, tar.translation);
+    //     const m = SymmetryOperator.slerp(Mat4.zero(), u, v, t);
+    //     const rot = Mat4.getRotation(Quat.zero(), m);
+    //     const axis = Vec3.zero();
+    //     const angle = Quat.getAxisAngle(axis, rot);
+    //     const translation = Mat4.getTranslation(Vec3.zero(), m);
+    //     return { axis, angle, translation };
+    // }
 });
 
 type StructureSelectionFromExpression = typeof StructureSelectionFromExpression
@@ -781,7 +816,6 @@ async function attachStructureProps(structure: Structure, ctx: PluginContext, ta
     }
 }
 
-export { ShapeFromPly }
 type ShapeFromPly = typeof ShapeFromPly
 const ShapeFromPly = PluginStateTransform.BuiltIn({
     name: 'shape-from-ply',

+ 16 - 2
src/mol-plugin-state/transforms/representation.ts

@@ -118,7 +118,7 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
             oldParams.type.name === newParams.type.name && newParams.type.params.quality !== 'custom'
         );
     },
-    apply({ a, params }, plugin: PluginContext) {
+    apply({ a, params, cache }, plugin: PluginContext) {
         return Task.create('Structure Representation', async ctx => {
             const propertyCtx = { runtime: ctx, fetch: plugin.fetch }
             const provider = plugin.representation.structure.registry.get(params.type.name)
@@ -127,12 +127,19 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
             const repr = provider.factory({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, provider.getParams)
             await Theme.ensureDependencies(propertyCtx, plugin.representation.structure.themes, { structure: a.data }, params)
             repr.setTheme(Theme.create(plugin.representation.structure.themes, { structure: a.data }, params))
+
+            // TODO: build this into representation?
+            if (!a.data.coordinateSystem.isIdentity) {
+                (cache as any)['transform'] = a.data.coordinateSystem;
+                repr.setState({ transform: a.data.coordinateSystem.matrix });
+            }
+
             // TODO set initial state, repr.setState({})
             await repr.createOrUpdate(props, a.data).runInContext(ctx);
             return new SO.Molecule.Structure.Representation3D({ repr, source: a } , { label: provider.label });
         });
     },
-    update({ a, b, oldParams, newParams }, plugin: PluginContext) {
+    update({ a, b, oldParams, newParams, cache }, plugin: PluginContext) {
         return Task.create('Structure Representation', async ctx => {
             const oldProvider = plugin.representation.structure.registry.get(oldParams.type.name);
             const propertyCtx = { runtime: ctx, fetch: plugin.fetch }
@@ -145,6 +152,13 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
             const props = { ...b.data.repr.props, ...newParams.type.params }
             await Theme.ensureDependencies(propertyCtx, plugin.representation.structure.themes, { structure: a.data }, newParams)
             b.data.repr.setTheme(Theme.create(plugin.representation.structure.themes, { structure: a.data }, newParams));
+
+            // TODO: build this into representation?
+            if ((cache as any)['transform'] !== a.data.coordinateSystem) {
+                (cache as any)['transform'] = a.data.coordinateSystem;
+                b.data.repr.setState({ transform: a.data.coordinateSystem.matrix });
+            }
+
             await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
             b.data.source = a
             return StateTransformer.UpdateResult.Updated;

+ 9 - 9
src/mol-plugin/index.ts

@@ -5,20 +5,19 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { PluginContext } from './context';
-import { Plugin } from '../mol-plugin-ui/plugin'
 import * as React from 'react';
 import * as ReactDOM from 'react-dom';
-import { PluginSpec } from './spec';
+import { StateActions } from '../mol-plugin-state/actions';
+import { AnimateAssemblyUnwind, AnimateModelIndex, AnimateStateInterpolation, AnimateUnitsExplode } from '../mol-plugin-state/animation/built-in';
 import { StateTransforms } from '../mol-plugin-state/transforms';
+import { VolumeStreamingCustomControls } from '../mol-plugin-ui/custom/volume';
+import { Plugin } from '../mol-plugin-ui/plugin';
 import { PluginBehaviors } from './behavior';
-import { AnimateModelIndex, AnimateAssemblyUnwind, AnimateUnitsExplode, AnimateStateInterpolation } from '../mol-plugin-state/animation/built-in';
-import { StateActions } from '../mol-plugin-state/actions';
-import { InitVolumeStreaming, BoxifyVolumeStreaming, CreateVolumeStreamingBehavior } from './behavior/dynamic/volume-streaming/transformers';
 import { StructureRepresentationInteraction } from './behavior/dynamic/selection/structure-representation-interaction';
-import { TransformStructureConformation } from '../mol-plugin-state/actions/structure';
-import { VolumeStreamingCustomControls } from '../mol-plugin-ui/custom/volume';
+import { BoxifyVolumeStreaming, CreateVolumeStreamingBehavior, InitVolumeStreaming } from './behavior/dynamic/volume-streaming/transformers';
 import { PluginConfig } from './config';
+import { PluginContext } from './context';
+import { PluginSpec } from './spec';
 
 export const DefaultPluginSpec: PluginSpec = {
     actions: [
@@ -42,7 +41,8 @@ export const DefaultPluginSpec: PluginSpec = {
 
         PluginSpec.Action(StateTransforms.Model.TrajectoryFromMmCif),
         PluginSpec.Action(StateTransforms.Model.TrajectoryFromPDB),
-        PluginSpec.Action(TransformStructureConformation),
+        PluginSpec.Action(StateTransforms.Model.TransformStructureConformation),
+        PluginSpec.Action(StateTransforms.Model.StructureCoordinateSystem),
         PluginSpec.Action(StateTransforms.Model.StructureFromModel),
         PluginSpec.Action(StateTransforms.Model.StructureFromTrajectory),
         PluginSpec.Action(StateTransforms.Model.ModelFromTrajectory),