Bladeren bron

VolumeData.transform

David Sehnal 5 jaren geleden
bovenliggende
commit
ad521948b6

+ 1 - 2
src/apps/structure-info/volume.ts

@@ -34,9 +34,8 @@ function print(data: Volume) {
     const { volume_data_3d_info } = data.source;
     const row = Table.getRow(volume_data_3d_info, 0);
     console.log(row);
-    console.log(data.volume.cell);
+    if (data.volume.transform) console.log(data.volume.transform);
     console.log(data.volume.dataStats);
-    console.log(data.volume.fractionalBox);
 }
 
 async function doMesh(data: Volume, filename: string) {

+ 15 - 0
src/mol-math/linear-algebra/3d/mat4.ts

@@ -164,6 +164,21 @@ namespace Mat4 {
         return a;
     }
 
+    export function fromBasis(a: Mat4, x: Vec3, y: Vec3, z: Vec3) {
+        Mat4.setZero(a);
+        Mat4.setValue(a, 0, 0, x[0]);
+        Mat4.setValue(a, 1, 0, x[1]);
+        Mat4.setValue(a, 2, 0, x[2]);
+        Mat4.setValue(a, 0, 1, y[0]);
+        Mat4.setValue(a, 1, 1, y[1]);
+        Mat4.setValue(a, 2, 1, y[2]);
+        Mat4.setValue(a, 0, 2, z[0]);
+        Mat4.setValue(a, 1, 2, z[1]);
+        Mat4.setValue(a, 2, 2, z[2]);
+        Mat4.setValue(a, 3, 3, 1);
+        return a;
+    }
+
     export function copy(out: Mat4, a: Mat4) {
         out[0] = a[0];
         out[1] = a[1];

+ 1 - 2
src/mol-model-formats/volume/ccp4.ts

@@ -67,8 +67,7 @@ export function volumeFromCcp4(source: Ccp4File, params?: { voxelSize?: Vec3, of
         // These, however, calculate sigma, so no data on that.
 
         return {
-            cell,
-            fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)),
+            transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) },
             data,
             dataStats: {
                 min: isNaN(header.AMIN) ? arrayMin(values) : header.AMIN,

+ 8 - 21
src/mol-model-formats/volume/cube.ts

@@ -4,31 +4,15 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
+import { CubeFile } from '../../mol-io/reader/cube/parser';
+import { Mat4, Tensor } from '../../mol-math/linear-algebra';
 import { VolumeData } from '../../mol-model/volume/data';
 import { Task } from '../../mol-task';
-import { SpacegroupCell, Box3D } from '../../mol-math/geometry';
-import { Tensor, Vec3 } from '../../mol-math/linear-algebra';
-import { arrayMin, arrayMax, arrayMean, arrayRms } from '../../mol-util/array';
-import { CubeFile } from '../../mol-io/reader/cube/parser';
+import { arrayMax, arrayMean, arrayMin, arrayRms } from '../../mol-util/array';
 
 export function volumeFromCube(source: CubeFile, params?: { dataIndex?: number }): Task<VolumeData> {
     return Task.create<VolumeData>('Create Volume Data', async () => {
-        // TODO: support non-orthogonal axes
-
         const { header, values: sourceValues } = source;
-        const angles = SpacegroupCell.Zero.anglesInRadians;
-        const size = Vec3.create(header.basisX[0] * header.dim[0], header.basisY[1] * header.dim[1], header.basisZ[2] * header.dim[2]);
-        const cell = SpacegroupCell.create('P 1', size, angles);
-
-        if (header.basisX[1] !== 0 || header.basisX[2] !== 0
-            || header.basisY[0] !== 0 || header.basisY[2] !== 0
-            || header.basisZ[0] !== 0 || header.basisZ[1] !== 0) {
-            throw new Error('Non-orthogonal bases not supported. (TODO)');
-        }
-
-        const origin_frac = Vec3.div(Vec3(), header.origin, size);
-        const dimensions_frac = Vec3.add(Vec3(), origin_frac, Vec3.create(1, 1, 1));
-
         const space = Tensor.Space(header.dim, [0, 1, 2], Float64Array);
 
         let values: Float64Array;
@@ -54,9 +38,12 @@ export function volumeFromCube(source: CubeFile, params?: { dataIndex?: number }
 
         const data = Tensor.create(space, Tensor.Data1(values));
 
+        const matrix = Mat4.fromTranslation(Mat4(), header.origin);
+        const basis = Mat4.fromBasis(Mat4(), header.basisX, header.basisY, header.basisZ);
+        Mat4.mul(matrix, matrix, basis);
+
         return {
-            cell,
-            fractionalBox: Box3D.create(origin_frac, dimensions_frac),
+            transform: { kind: 'matrix', matrix },
             data,
             dataStats: {
                 min: arrayMin(values),

+ 1 - 2
src/mol-model-formats/volume/density-server.ts

@@ -34,8 +34,7 @@ function volumeFromDensityServerData(source: DensityServer_Data_Database): Task<
         const dimensions = Vec3.ofArray(normalizeOrder(info.dimensions.value(0)));
 
         return {
-            cell,
-            fractionalBox: Box3D.create(origin, Vec3.add(Vec3.zero(), origin, dimensions)),
+            transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin, Vec3.add(Vec3.zero(), origin, dimensions)) },
             data,
             dataStats: {
                 min: info.min_sampled.value(0),

+ 1 - 2
src/mol-model-formats/volume/dsn6.ts

@@ -32,8 +32,7 @@ function volumeFromDsn6(source: Dsn6File, params?: { voxelSize?: Vec3 }): Task<V
         const data = Tensor.create(space, Tensor.Data1(values));
 
         return {
-            cell,
-            fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)),
+            transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) },
             data,
             dataStats: {
                 min: arrayMin(values),

+ 14 - 8
src/mol-model/volume/data.ts

@@ -12,8 +12,7 @@ import { equalEps } from '../../mol-math/linear-algebra/3d/common';
 /** The basic unit cell that contains the data. */
 interface VolumeData {
     readonly label?: string,
-    readonly cell: SpacegroupCell,
-    readonly fractionalBox: Box3D,
+    readonly transform: { kind: 'spacegroup', cell: SpacegroupCell, fractionalBox: Box3D } | { kind: 'matrix', matrix: Mat4 },
     readonly data: Tensor,
     readonly dataStats: Readonly<{
         min: number,
@@ -25,18 +24,25 @@ interface VolumeData {
 
 namespace VolumeData {
     export const One: VolumeData = {
-        cell: SpacegroupCell.Zero,
-        fractionalBox: Box3D.empty(),
+        transform: { kind: 'matrix', matrix: Mat4() },
         data: Tensor.create(Tensor.Space([1, 1, 1], [0, 1, 2]), Tensor.Data1([0])),
         dataStats: { min: 0, max: 0, mean: 0, sigma: 0 }
     };
 
     const _scale = Mat4.zero(), _translate = Mat4.zero();
     export function getGridToCartesianTransform(volume: VolumeData) {
-        const { data: { space } } = volume;
-        const scale = Mat4.fromScaling(_scale, Vec3.div(Vec3.zero(), Box3D.size(Vec3.zero(), volume.fractionalBox), Vec3.ofArray(space.dimensions)));
-        const translate = Mat4.fromTranslation(_translate, volume.fractionalBox.min);
-        return Mat4.mul3(Mat4.zero(), volume.cell.fromFractional, translate, scale);
+        if (volume.transform.kind === 'matrix') {
+            return Mat4.copy(Mat4(), volume.transform.matrix);
+        }
+
+        if (volume.transform.kind === 'spacegroup') {
+            const { data: { space } } = volume;
+            const scale = Mat4.fromScaling(_scale, Vec3.div(Vec3.zero(), Box3D.size(Vec3.zero(), volume.transform.fractionalBox), Vec3.ofArray(space.dimensions)));
+            const translate = Mat4.fromTranslation(_translate, volume.transform.fractionalBox.min);
+            return Mat4.mul3(Mat4.zero(), volume.transform.cell.fromFractional, translate, scale);
+        }
+
+        return Mat4.identity();
     }
 
     export function areEquivalent(volA: VolumeData, volB: VolumeData) {