Bläddra i källkod

added Spacegroup.getOperatorXyz

Alexander Rose 5 år sedan
förälder
incheckning
3681f01fad

+ 36 - 0
src/mol-math/geometry/_spec/spacegroup.spec.ts

@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Spacegroup, SpacegroupCell } from '../spacegroup/construction';
+import { Vec3 } from '../../linear-algebra';
+
+function getSpacegroup(name: string) {
+    const size = Vec3.create(1, 1, 1)
+    const anglesInRadians = Vec3.create(Math.PI / 2, Math.PI / 2, Math.PI / 2)
+    const cell = SpacegroupCell.create(name, size, anglesInRadians)
+    return Spacegroup.create(cell)
+}
+
+function checkOperatorsXyz(name: string, expected: string[]) {
+    const spacegroup = getSpacegroup(name)
+    for (let i = 0, il = spacegroup.operators.length; i < il; ++i) {
+        const op = spacegroup.operators[i]
+        const actual = Spacegroup.getOperatorXyz(op)
+        expect(actual).toBe(expected[i])
+    }
+}
+
+describe('Spacegroup', () => {
+    it('operators xyz', () => {
+        checkOperatorsXyz('P 1', ['X,Y,Z'])
+        checkOperatorsXyz('P -1', ['X,Y,Z', '-X,-Y,-Z'])
+        checkOperatorsXyz('P 1 21 1', ['X,Y,Z', '-X,1/2+Y,-Z'])
+        checkOperatorsXyz('P 1 21/m 1', ['X,Y,Z', '-X,1/2+Y,-Z', '-X,-Y,-Z', 'X,1/2-Y,Z'])
+        checkOperatorsXyz('P 41', ['X,Y,Z', '-X,-Y,1/2+Z', '-Y,X,1/4+Z', 'Y,-X,3/4+Z'])
+        checkOperatorsXyz('P 41 21 2', ['X,Y,Z', '-X,-Y,1/2+Z', '1/2-Y,1/2+X,1/4+Z', '1/2+Y,1/2-X,3/4+Z', '1/2-X,1/2+Y,1/4-Z', '1/2+X,1/2-Y,3/4-Z', 'Y,X,-Z', '-Y,-X,1/2-Z'])
+        checkOperatorsXyz('P 3', ['X,Y,Z', '-Y,X-Y,Z', 'Y-X,-X,Z'])
+    });
+})

+ 49 - 1
src/mol-math/geometry/spacegroup/construction.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -145,6 +145,54 @@ namespace Spacegroup {
         const r3 = TransformData[ids[2]];
         return Mat4.ofRows([r1, r2, r3, [0, 0, 0, 1]]);
     }
+
+    export function getOperatorXyz(op: Mat4) {
+        return [
+            formatElement(getRotation(op[0], op[4], op[8]), getShift(op[12])),
+            formatElement(getRotation(op[1], op[5], op[9]), getShift(op[13])),
+            formatElement(getRotation(op[2], op[6], op[10]), getShift(op[14]))
+        ].join(',')
+    }
+
+    function getRotation(x: number, y: number, z: number) {
+        let r: string[] = []
+        if (x > 0) r.push('+X')
+        else if (x < 0) r.push('-X')
+        if (y > 0) r.push('+Y')
+        else if (y < 0) r.push('-Y')
+        if (z > 0) r.push('+Z')
+        else if (z < 0) r.push('-Z')
+
+        if (r.length === 1) {
+            return r[0].charAt(0) === '+' ? r[0].substr(1) : r[0]
+        }
+        if (r.length === 2) {
+            const s0 = r[0].charAt(0)
+            const s1 = r[1].charAt(0)
+            if (s0 === '+') return `${r[0].substr(1)}${r[1]}`
+            if (s1 === '+') return `${r[1].substr(1)}${r[0]}`
+        }
+        throw new Error(`unknown rotation '${r}', ${x} ${y} ${z}`)
+    }
+
+    function getShift(s: number) {
+        switch (s) {
+            case 1/2: return '1/2'
+            case 1/4: return '1/4'
+            case 3/4: return '3/4'
+            case 1/3: return '1/3'
+            case 2/3: return '2/3'
+            case 1/6: return '1/6'
+            case 5/6: return '5/6'
+        }
+        return ''
+    }
+
+    function formatElement(rotation: string, shift: string) {
+        if (shift === '') return rotation
+        if (rotation.length > 2) return `${rotation}+${shift}`
+        return rotation.charAt(0) === '-' ? `${shift}${rotation}` : `${shift}+${rotation}`
+    }
 }
 
 export { Spacegroup, SpacegroupCell }