mirror of
https://github.com/molstar/molstar.git
synced 2026-06-07 15:14:22 +08:00
Compare commits
14 Commits
v0.5.0-dev
...
v0.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe47134934 | ||
|
|
131cc606f0 | ||
|
|
3681f01fad | ||
|
|
e966c112ab | ||
|
|
7986509ad3 | ||
|
|
73dcf970f3 | ||
|
|
9377aa2d05 | ||
|
|
686fa5a5ed | ||
|
|
c946ae6eab | ||
|
|
9b2f1d9415 | ||
|
|
f6c28aa8e2 | ||
|
|
64c72aa6f5 | ||
|
|
0a22917773 | ||
|
|
3c4888e52b |
@@ -1,7 +1,7 @@
|
||||
schema: https://data-beta.rcsb.org/graphql
|
||||
documents: './src/mol-model-props/rcsb/graphql/symmetry.gql.ts'
|
||||
generates:
|
||||
'./src/mol-model-props/rcsb/graphql/types.d.ts':
|
||||
'./src/mol-model-props/rcsb/graphql/types.ts':
|
||||
plugins:
|
||||
- add: '/* eslint-disable */'
|
||||
- time
|
||||
|
||||
1086
package-lock.json
generated
1086
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "0.5.0-dev.2",
|
||||
"version": "0.5.2",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -72,9 +72,9 @@
|
||||
"@graphql-codegen/typescript-graphql-request": "^1.12.2",
|
||||
"@graphql-codegen/typescript-operations": "^1.12.2",
|
||||
"@types/cors": "^2.8.6",
|
||||
"@typescript-eslint/eslint-plugin": "^2.19.2",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "^2.19.2",
|
||||
"@typescript-eslint/parser": "^2.19.2",
|
||||
"@typescript-eslint/eslint-plugin": "^2.20.0",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "^2.20.0",
|
||||
"@typescript-eslint/parser": "^2.20.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"circular-dependency-plugin": "^5.2.0",
|
||||
"concurrently": "^5.1.0",
|
||||
@@ -82,7 +82,7 @@
|
||||
"css-loader": "^3.4.2",
|
||||
"eslint": "^6.8.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^5.0.2",
|
||||
"file-loader": "^5.1.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"http-server": "^0.12.1",
|
||||
"jest": "^25.1.0",
|
||||
@@ -95,20 +95,20 @@
|
||||
"sass-loader": "^8.0.2",
|
||||
"simple-git": "^1.131.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"ts-jest": "^25.2.0",
|
||||
"typescript": "^3.7.5",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "^3.3.10"
|
||||
"ts-jest": "^25.2.1",
|
||||
"typescript": "^3.8.2",
|
||||
"webpack": "^4.41.6",
|
||||
"webpack-cli": "^3.3.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^1.0.38",
|
||||
"@types/benchmark": "^1.0.31",
|
||||
"@types/compression": "1.7.0",
|
||||
"@types/express": "^4.17.2",
|
||||
"@types/jest": "^25.1.2",
|
||||
"@types/node": "^13.7.0",
|
||||
"@types/jest": "^25.1.3",
|
||||
"@types/node": "^13.7.4",
|
||||
"@types/node-fetch": "^2.5.4",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react": "^16.9.22",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/swagger-ui-dist": "3.0.5",
|
||||
"argparse": "^1.0.10",
|
||||
|
||||
@@ -144,9 +144,9 @@ async function createBonds() {
|
||||
const comp_id: string[] = []
|
||||
const atom_id_1: string[] = []
|
||||
const atom_id_2: string[] = []
|
||||
const value_order: string[] = []
|
||||
const pdbx_aromatic_flag: string[] = []
|
||||
const pdbx_stereo_config: string[] = []
|
||||
const value_order: typeof mmCIF_chemCompBond_schema['value_order']['T'][] = []
|
||||
const pdbx_aromatic_flag: typeof mmCIF_chemCompBond_schema['pdbx_aromatic_flag']['T'][] = []
|
||||
const pdbx_stereo_config: typeof mmCIF_chemCompBond_schema['pdbx_stereo_config']['T'][] = []
|
||||
const molstar_protonation_variant: string[] = []
|
||||
|
||||
function addBonds(compId: string, ccb: CCB, protonationVariant: boolean) {
|
||||
|
||||
@@ -264,12 +264,13 @@ function updatePers(camera: Camera) {
|
||||
function updateClip(camera: Camera) {
|
||||
const { radiusNear, radiusFar, mode, fog, clipFar } = camera.state
|
||||
|
||||
const cDist = Vec3.distance(camera.position, camera.target)
|
||||
let near = cDist - radiusNear
|
||||
let far = cDist + (clipFar ? radiusNear : radiusFar)
|
||||
const normalizedFar = clipFar ? radiusNear : radiusFar
|
||||
const cameraDistance = Vec3.distance(camera.position, camera.target)
|
||||
let near = cameraDistance - radiusNear
|
||||
let far = cameraDistance + normalizedFar
|
||||
|
||||
const fogNearFactor = -(50 - fog) / 50
|
||||
let fogNear = cDist - (radiusNear * fogNearFactor)
|
||||
let fogNear = cameraDistance - (normalizedFar * fogNearFactor)
|
||||
let fogFar = far
|
||||
|
||||
if (mode === 'perspective') {
|
||||
|
||||
@@ -38,7 +38,7 @@ import { isDebugMode } from '../mol-util/debug';
|
||||
|
||||
export const Canvas3DParams = {
|
||||
cameraMode: PD.Select('perspective', [['perspective', 'Perspective'], ['orthographic', 'Orthographic']]),
|
||||
cameraFog: PD.Numeric(50, { min: 1, max: 100, step: 1 }),
|
||||
cameraFog: PD.Numeric(50, { min: 0, max: 100, step: 1 }),
|
||||
cameraClipFar: PD.Boolean(true),
|
||||
cameraResetDurationMs: PD.Numeric(250, { min: 0, max: 1000, step: 1 }, { description: 'The time it takes to reset the camera.' }),
|
||||
transparentBackground: PD.Boolean(false),
|
||||
@@ -62,7 +62,7 @@ interface Canvas3D {
|
||||
/**
|
||||
* This function must be called if animate() is not set up so that add/remove actions take place.
|
||||
*/
|
||||
commit(): void
|
||||
commit(isSynchronous?: boolean): void
|
||||
update(repr?: Representation.Any, keepBoundingSphere?: boolean): void
|
||||
clear(): void
|
||||
|
||||
@@ -77,7 +77,7 @@ interface Canvas3D {
|
||||
|
||||
handleResize(): void
|
||||
/** Focuses camera on scene's bounding sphere, centered and zoomed. */
|
||||
requestCameraReset(): void
|
||||
requestCameraReset(durationMs?: number): void
|
||||
readonly camera: Camera
|
||||
readonly boundingSphere: Readonly<Sphere3D>
|
||||
downloadScreenshot(): void
|
||||
@@ -190,6 +190,7 @@ namespace Canvas3D {
|
||||
|
||||
let drawPending = false
|
||||
let cameraResetRequested = false
|
||||
let nextCameraResetDuration: number | undefined = void 0
|
||||
|
||||
function getLoci(pickingId: PickingId) {
|
||||
let loci: Loci = EmptyLoci
|
||||
@@ -266,9 +267,7 @@ namespace Canvas3D {
|
||||
|
||||
function animate() {
|
||||
currentTime = now();
|
||||
|
||||
commit();
|
||||
|
||||
camera.transition.tick(currentTime);
|
||||
|
||||
draw(false);
|
||||
@@ -282,25 +281,30 @@ namespace Canvas3D {
|
||||
return webgl.isContextLost ? undefined : pickPass.identify(x, y)
|
||||
}
|
||||
|
||||
function commit() {
|
||||
commitScene();
|
||||
resolveCameraReset();
|
||||
function commit(isSynchronous: boolean = false) {
|
||||
const allCommited = commitScene(isSynchronous);
|
||||
// Only reset the camera after the full scene has been commited.
|
||||
if (allCommited) resolveCameraReset();
|
||||
}
|
||||
|
||||
function resolveCameraReset() {
|
||||
if (!cameraResetRequested) return;
|
||||
const { center, radius } = scene.boundingSphere;
|
||||
camera.focus(center, radius, radius, p.cameraResetDurationMs);
|
||||
const duration = nextCameraResetDuration === undefined ? p.cameraResetDurationMs : nextCameraResetDuration
|
||||
camera.focus(center, radius, radius, duration);
|
||||
nextCameraResetDuration = void 0;
|
||||
cameraResetRequested = false;
|
||||
}
|
||||
|
||||
const sceneCommitTimeoutMs = 250;
|
||||
function commitScene() {
|
||||
if (!scene.needsCommit) return;
|
||||
function commitScene(isSynchronous: boolean) {
|
||||
if (!scene.needsCommit) return true;
|
||||
|
||||
if (!scene.commit(isSynchronous ? void 0 : sceneCommitTimeoutMs)) return false;
|
||||
|
||||
const allCommited = scene.commit(sceneCommitTimeoutMs);
|
||||
if (debugHelper.isEnabled) debugHelper.update();
|
||||
if (allCommited) reprCount.next(reprRenderObjects.size);
|
||||
reprCount.next(reprRenderObjects.size);
|
||||
return true;
|
||||
}
|
||||
|
||||
function add(repr: Representation.Any) {
|
||||
@@ -384,7 +388,8 @@ namespace Canvas3D {
|
||||
getLoci,
|
||||
|
||||
handleResize,
|
||||
requestCameraReset: () => {
|
||||
requestCameraReset: (durationMs) => {
|
||||
nextCameraResetDuration = durationMs;
|
||||
cameraResetRequested = true;
|
||||
},
|
||||
camera,
|
||||
|
||||
@@ -9,7 +9,7 @@ import { sortArray } from '../util/sort'
|
||||
import { StringBuilder } from '../../mol-util';
|
||||
|
||||
/** A collection of columns */
|
||||
type Table<Schema extends Table.Schema> = {
|
||||
type Table<Schema extends Table.Schema = any> = {
|
||||
readonly _rowCount: number,
|
||||
readonly _columns: ReadonlyArray<string>,
|
||||
readonly _schema: Schema
|
||||
@@ -73,7 +73,7 @@ namespace Table {
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, rows: ArrayLike<Partial<Row<S>>>): R {
|
||||
export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: S, rows: ArrayLike<Partial<Row<S>>>): R {
|
||||
const ret = Object.create(null);
|
||||
const rowCount = rows.length;
|
||||
const columns = Object.keys(schema);
|
||||
@@ -91,14 +91,19 @@ namespace Table {
|
||||
return ret as R;
|
||||
}
|
||||
|
||||
export function ofArrays<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, arrays: Arrays<S>): R {
|
||||
export function ofArrays<S extends Schema, R extends Table<S> = Table<S>>(schema: S, arrays: Partial<Arrays<S>>): R {
|
||||
const ret = Object.create(null);
|
||||
const columns = Object.keys(schema);
|
||||
ret._rowCount = arrays[columns[0]].length;
|
||||
ret._rowCount = 0;
|
||||
ret._columns = columns;
|
||||
ret._schema = schema;
|
||||
for (const k of columns) {
|
||||
(ret as any)[k] = typeof arrays[k] !== 'undefined' ? Column.ofArray({ array: arrays[k], schema: schema[k] }) : Column.Undefined(ret._rowCount, schema[k]);
|
||||
if (typeof arrays[k] !== 'undefined') {
|
||||
(ret as any)[k] = Column.ofArray({ array: arrays[k]!, schema: schema[k] });
|
||||
ret._rowCount = arrays[k]?.length;
|
||||
} else {
|
||||
(ret as any)[k] = Column.Undefined(ret._rowCount, schema[k]);
|
||||
}
|
||||
}
|
||||
return ret as R;
|
||||
}
|
||||
@@ -167,7 +172,7 @@ namespace Table {
|
||||
}
|
||||
|
||||
/** Sort and return a new table */
|
||||
export function sort<T extends Table<S>, S extends Schema>(table: T, cmp: (i: number, j: number) => number) {
|
||||
export function sort<T extends Table>(table: T, cmp: (i: number, j: number) => number) {
|
||||
const indices = new Int32Array(table._rowCount);
|
||||
for (let i = 0, _i = indices.length; i < _i; i++) indices[i] = i;
|
||||
sortArray(indices, (_, i, j) => cmp(i, j));
|
||||
@@ -191,7 +196,7 @@ namespace Table {
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function areEqual<T extends Table<Schema>>(a: T, b: T) {
|
||||
export function areEqual<T extends Table<any>>(a: T, b: T) {
|
||||
if (a._rowCount !== b._rowCount) return false;
|
||||
if (a._columns.length !== b._columns.length) return false;
|
||||
for (const c of a._columns) {
|
||||
|
||||
@@ -126,8 +126,6 @@ namespace Scene {
|
||||
return true;
|
||||
}
|
||||
|
||||
// const toAdd: GraphicsRenderObject[] = []
|
||||
// const toRemove: GraphicsRenderObject[] = []
|
||||
const commitQueue = new CommitQueue();
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.323, IHM 1.07, CARB draft.
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.323, IHM 1.08, CARB draft.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.323, IHM 1.07, CARB draft.
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.323, IHM 1.08, CARB draft.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.323, IHM 1.07, CARB draft.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.323, IHM 1.08, CARB draft.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -199,7 +199,7 @@ export namespace Category {
|
||||
getFormat(cat, field) { return void 0; }
|
||||
}
|
||||
|
||||
export function ofTable(table: Table<Table.Schema>, indices?: ArrayLike<number>): Category.Instance {
|
||||
export function ofTable(table: Table, indices?: ArrayLike<number>): Category.Instance {
|
||||
if (indices) {
|
||||
return {
|
||||
fields: cifFieldsFromTableSchema(table._schema),
|
||||
|
||||
36
src/mol-math/geometry/_spec/spacegroup.spec.ts
Normal file
36
src/mol-math/geometry/_spec/spacegroup.spec.ts
Normal file
@@ -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'])
|
||||
});
|
||||
})
|
||||
@@ -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 }
|
||||
@@ -90,9 +90,9 @@ function getConformation(atom_site: AtomSite): AtomicConformation {
|
||||
|
||||
function isHierarchyDataEqual(a: AtomicData, b: AtomicData) {
|
||||
// TODO need to cast because of how TS handles type resolution for interfaces https://github.com/Microsoft/TypeScript/issues/15300
|
||||
return Table.areEqual(a.chains as Table<ChainsSchema>, b.chains as Table<ChainsSchema>)
|
||||
&& Table.areEqual(a.residues as Table<ResiduesSchema>, b.residues as Table<ResiduesSchema>)
|
||||
&& Table.areEqual(a.atoms as Table<AtomsSchema>, b.atoms as Table<AtomsSchema>)
|
||||
return Table.areEqual(a.chains, b.chains)
|
||||
&& Table.areEqual(a.residues, b.residues)
|
||||
&& Table.areEqual(a.atoms, b.atoms)
|
||||
}
|
||||
|
||||
function getAtomicHierarchy(atom_site: AtomSite, sourceIndex: Column<number>, entities: Entities, chemicalComponentMap: Model['properties']['chemicalComponentMap'], previous?: Model) {
|
||||
|
||||
@@ -37,6 +37,7 @@ export namespace AssemblySymmetry {
|
||||
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
|
||||
if (id === '' || id === 'deposited') return true
|
||||
const indices = Column.indicesOf(mmcif.pdbx_struct_assembly.id, e => e === id)
|
||||
if (indices.length !== 1) return false
|
||||
const details = mmcif.pdbx_struct_assembly.details.value(indices[0])
|
||||
@@ -48,7 +49,7 @@ export namespace AssemblySymmetry {
|
||||
|
||||
const client = new GraphQLClient(props.serverUrl, ctx.fetch)
|
||||
const variables: AssemblySymmetryQueryVariables = {
|
||||
assembly_id: structure.units[0].conformation.operator.assembly.id,
|
||||
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)
|
||||
@@ -56,7 +57,8 @@ export namespace AssemblySymmetry {
|
||||
if (!result.assembly?.rcsb_struct_symmetry) {
|
||||
throw new Error('missing fields')
|
||||
}
|
||||
return result.assembly.rcsb_struct_symmetry as AssemblySymmetryValue
|
||||
const symmetry = result.assembly.rcsb_struct_symmetry as AssemblySymmetryValue
|
||||
return symmetry.filter(s => s.symbol !== 'C1')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable */
|
||||
export type Maybe<T> = T | null;
|
||||
|
||||
// Generated in 2020-02-07T10:59:45-08:00
|
||||
// Generated in 2020-02-21T15:58:06-08:00
|
||||
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
@@ -14,7 +14,6 @@ export type Scalars = {
|
||||
UNREPRESENTABLE: any,
|
||||
};
|
||||
|
||||
|
||||
export type AuditAuthor = {
|
||||
readonly identifier_ORCID?: Maybe<Scalars['String']>,
|
||||
readonly name?: Maybe<Scalars['String']>,
|
||||
@@ -1750,6 +1749,7 @@ export type RcsbEntryContainerIdentifiers = {
|
||||
readonly emdb_ids?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>,
|
||||
readonly entity_ids?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>,
|
||||
readonly entry_id: Scalars['String'],
|
||||
readonly model_ids?: Maybe<ReadonlyArray<Maybe<Scalars['Int']>>>,
|
||||
readonly non_polymer_entity_ids?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>,
|
||||
readonly polymer_entity_ids?: Maybe<ReadonlyArray<Maybe<Scalars['String']>>>,
|
||||
readonly pubmed_id?: Maybe<Scalars['Int']>,
|
||||
@@ -1921,7 +1921,6 @@ export type RcsbNonpolymerInstanceAnnotationAnnotationLineage = {
|
||||
|
||||
export type RcsbNonpolymerInstanceFeature = {
|
||||
readonly assignment_version?: Maybe<Scalars['String']>,
|
||||
readonly auth_seq_id?: Maybe<Scalars['String']>,
|
||||
readonly comp_id?: Maybe<Scalars['String']>,
|
||||
readonly description?: Maybe<Scalars['String']>,
|
||||
readonly feature_id?: Maybe<Scalars['String']>,
|
||||
@@ -1942,6 +1941,7 @@ export type RcsbNonpolymerInstanceFeatureFeatureValue = {
|
||||
};
|
||||
|
||||
export type RcsbNonpolymerInstanceFeatureSummary = {
|
||||
readonly comp_id?: Maybe<Scalars['String']>,
|
||||
readonly count?: Maybe<Scalars['Int']>,
|
||||
readonly maximum_length?: Maybe<Scalars['Int']>,
|
||||
readonly maximum_value?: Maybe<Scalars['Float']>,
|
||||
@@ -50,7 +50,7 @@ export const AtomsSchema = {
|
||||
};
|
||||
|
||||
export type AtomsSchema = typeof AtomsSchema
|
||||
export interface Atoms extends Table<AtomsSchema> { }
|
||||
export type Atoms = Table<AtomsSchema>
|
||||
|
||||
export const ResiduesSchema = {
|
||||
/**
|
||||
@@ -83,7 +83,7 @@ export const ResiduesSchema = {
|
||||
pdbx_PDB_ins_code: mmCIF.atom_site.pdbx_PDB_ins_code,
|
||||
};
|
||||
export type ResiduesSchema = typeof ResiduesSchema
|
||||
export interface Residues extends Table<ResiduesSchema> { }
|
||||
export type Residues = Table<ResiduesSchema>
|
||||
|
||||
export const ChainsSchema = {
|
||||
/**
|
||||
@@ -102,7 +102,7 @@ export const ChainsSchema = {
|
||||
label_entity_id: mmCIF.atom_site.label_entity_id
|
||||
}
|
||||
export type ChainsSchema = typeof ChainsSchema
|
||||
export interface Chains extends Table<ChainsSchema> { }
|
||||
export type Chains = Table<ChainsSchema>
|
||||
|
||||
export interface AtomicData {
|
||||
atoms: Atoms,
|
||||
|
||||
@@ -221,7 +221,6 @@ export const WaterNames = new Set([
|
||||
export const AminoAcidNamesL = new Set([
|
||||
'HIS', 'ARG', 'LYS', 'ILE', 'PHE', 'LEU', 'TRP', 'ALA', 'MET', 'PRO', 'CYS',
|
||||
'ASN', 'VAL', 'GLY', 'SER', 'GLN', 'TYR', 'ASP', 'GLU', 'THR', 'SEC', 'PYL',
|
||||
|
||||
'UNK' // unknown amino acid from CCD
|
||||
])
|
||||
export const AminoAcidNamesD = new Set([
|
||||
@@ -249,8 +248,14 @@ export const AminoAcidNamesD = new Set([
|
||||
])
|
||||
export const AminoAcidNames = SetUtils.unionMany(AminoAcidNamesL, AminoAcidNamesD)
|
||||
|
||||
export const RnaBaseNames = new Set([ 'A', 'C', 'T', 'G', 'I', 'U' ])
|
||||
export const DnaBaseNames = new Set([ 'DA', 'DC', 'DT', 'DG', 'DI', 'DU' ])
|
||||
export const RnaBaseNames = new Set([
|
||||
'A', 'C', 'T', 'G', 'I', 'U',
|
||||
'N' // unknown RNA base from CCD
|
||||
])
|
||||
export const DnaBaseNames = new Set([
|
||||
'DA', 'DC', 'DT', 'DG', 'DI', 'DU',
|
||||
'DN' // unknown DNA base from CCD
|
||||
])
|
||||
export const PeptideBaseNames = new Set([ 'APN', 'CPN', 'TPN', 'GPN' ])
|
||||
export const PurineBaseNames = new Set([ 'A', 'G', 'DA', 'DG', 'DI', 'APN', 'GPN' ])
|
||||
export const PyrimidineBaseNames = new Set([ 'C', 'T', 'U', 'DC', 'DT', 'DU', 'CPN', 'TPN' ])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-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>
|
||||
@@ -11,10 +11,11 @@ import { Spacegroup, SpacegroupCell, SymmetryOperator } from '../../../mol-math/
|
||||
import { Vec3, Mat4 } from '../../../mol-math/linear-algebra';
|
||||
import { RuntimeContext, Task } from '../../../mol-task';
|
||||
import { Symmetry, Model } from '../model';
|
||||
import { QueryContext, StructureSelection } from '../query';
|
||||
import { QueryContext, StructureSelection, Queries as Q } from '../query';
|
||||
import Structure from './structure';
|
||||
import Unit from './unit';
|
||||
import { ModelSymmetry } from '../../../mol-model-formats/structure/property/symmetry';
|
||||
import StructureProperties from './properties';
|
||||
|
||||
namespace StructureSymmetry {
|
||||
export function buildAssembly(structure: Structure, asmName: string) {
|
||||
@@ -48,6 +49,40 @@ namespace StructureSymmetry {
|
||||
});
|
||||
}
|
||||
|
||||
export type Generators = { operators: { index: number, shift: Vec3 }[], asymIds: string[] }[]
|
||||
|
||||
export function buildSymmetryAssembly(structure: Structure, generators: Generators, symmetry: Symmetry) {
|
||||
return Task.create('Build Symmetry Assembly', async ctx => {
|
||||
const models = structure.models;
|
||||
if (models.length !== 1) throw new Error('Can only build symmetry assemblies from structures based on 1 model.');
|
||||
|
||||
const modelCenter = Vec3() // Model.getCenter(models[0])
|
||||
const assembler = Structure.Builder({ label: structure.label });
|
||||
|
||||
const queryCtx = new QueryContext(structure);
|
||||
|
||||
for (const g of generators) {
|
||||
const selector = getSelector(g.asymIds);
|
||||
const selection = selector(queryCtx);
|
||||
if (StructureSelection.structureCount(selection) === 0) {
|
||||
continue;
|
||||
}
|
||||
const { units } = StructureSelection.unionStructure(selection);
|
||||
|
||||
for (const { index, shift: [i, j, k] } of g.operators) {
|
||||
const operators = getOperatorsForIndex(symmetry, index, i, j, k, modelCenter)
|
||||
for (const unit of units) {
|
||||
for (const op of operators) {
|
||||
assembler.addWithOperator(unit, op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return assembler.getStructure();
|
||||
});
|
||||
}
|
||||
|
||||
export function builderSymmetryMates(structure: Structure, radius: number) {
|
||||
return Task.create('Find Symmetry Mates', ctx => findMatesRadius(ctx, structure, radius));
|
||||
}
|
||||
@@ -96,7 +131,35 @@ namespace StructureSymmetry {
|
||||
}
|
||||
}
|
||||
|
||||
function getOperators(symmetry: Symmetry, ijkMin: Vec3, ijkMax: Vec3, modelCenter: Vec3) {
|
||||
function getSelector(asymIds: string[]) {
|
||||
return Q.generators.atoms({ chainTest: Q.pred.and(
|
||||
Q.pred.eq(ctx => StructureProperties.unit.operator_name(ctx.element), SymmetryOperator.DefaultName),
|
||||
Q.pred.inSet(ctx => StructureProperties.chain.label_asym_id(ctx.element), asymIds)
|
||||
)});
|
||||
}
|
||||
|
||||
function getOperatorsForIndex(symmetry: Symmetry, index: number, i: number, j: number, k: number, modelCenter: Vec3) {
|
||||
const { spacegroup, ncsOperators } = symmetry;
|
||||
const operators: SymmetryOperator[] = []
|
||||
|
||||
const { toFractional } = spacegroup.cell
|
||||
const ref = Vec3.transformMat4(Vec3(), modelCenter, toFractional)
|
||||
|
||||
const symOp = Spacegroup.getSymmetryOperatorRef(spacegroup, index, i, j, k, ref)
|
||||
if (ncsOperators && ncsOperators.length) {
|
||||
for (let u = 0, ul = ncsOperators.length; u < ul; ++u) {
|
||||
const ncsOp = ncsOperators![u]
|
||||
const matrix = Mat4.mul(Mat4(), symOp.matrix, ncsOp.matrix)
|
||||
const operator = SymmetryOperator.create(`${symOp.name} ${ncsOp.name}`, matrix, symOp.assembly, ncsOp.ncsId, symOp.hkl, symOp.spgrOp);
|
||||
operators.push(operator)
|
||||
}
|
||||
} else {
|
||||
operators.push(symOp)
|
||||
}
|
||||
return operators
|
||||
}
|
||||
|
||||
function getOperatorsForRange(symmetry: Symmetry, ijkMin: Vec3, ijkMax: Vec3, modelCenter: Vec3) {
|
||||
const { spacegroup, ncsOperators } = symmetry;
|
||||
const ncsCount = (ncsOperators && ncsOperators.length) || 0
|
||||
const operators: SymmetryOperator[] = [];
|
||||
@@ -117,18 +180,7 @@ function getOperators(symmetry: Symmetry, ijkMin: Vec3, ijkMax: Vec3, modelCente
|
||||
for (let k = ijkMin[2]; k <= ijkMax[2]; k++) {
|
||||
// check if we have added identity as the 1st operator.
|
||||
if (!ncsCount && op === 0 && i === 0 && j === 0 && k === 0) continue;
|
||||
|
||||
const symOp = Spacegroup.getSymmetryOperatorRef(spacegroup, op, i, j, k, ref)
|
||||
if (ncsCount) {
|
||||
for (let u = 0; u < ncsCount; ++u) {
|
||||
const ncsOp = ncsOperators![u]
|
||||
const matrix = Mat4.mul(Mat4.zero(), symOp.matrix, ncsOp.matrix)
|
||||
const operator = SymmetryOperator.create(`${symOp.name} ${ncsOp.name}`, matrix, symOp.assembly, ncsOp.ncsId, symOp.hkl, symOp.spgrOp);
|
||||
operators[operators.length] = operator;
|
||||
}
|
||||
} else {
|
||||
operators[operators.length] = symOp;
|
||||
}
|
||||
operators.push(...getOperatorsForIndex(symmetry, op, i, j, k, ref))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +194,7 @@ function getOperatorsCached333(symmetry: Symmetry, ref: Vec3) {
|
||||
}
|
||||
symmetry._operators_333 = {
|
||||
ref: Vec3.clone(ref),
|
||||
operators: getOperators(symmetry, Vec3.create(-3, -3, -3), Vec3.create(3, 3, 3), ref)
|
||||
operators: getOperatorsForRange(symmetry, Vec3.create(-3, -3, -3), Vec3.create(3, 3, 3), ref)
|
||||
};
|
||||
return symmetry._operators_333.operators;
|
||||
}
|
||||
@@ -181,7 +233,7 @@ async function findSymmetryRange(ctx: RuntimeContext, structure: Structure, ijkM
|
||||
if (SpacegroupCell.isZero(spacegroup.cell)) return structure;
|
||||
|
||||
const modelCenter = Model.getCenter(models[0])
|
||||
const operators = getOperators(symmetry, ijkMin, ijkMax, modelCenter);
|
||||
const operators = getOperatorsForRange(symmetry, ijkMin, ijkMax, modelCenter);
|
||||
return assembleOperators(structure, operators);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ const SimpleSettingsParams = {
|
||||
'transparent': PD.EmptyGroup(),
|
||||
'opaque': PD.Group({ color: PD.Color(Color(0xFCFBF9), { description: 'Custom background color' }) }, { isFlat: true })
|
||||
}, { description: 'Background of the 3D canvas' }),
|
||||
renderStyle: PD.Select('glossy', [['toon', 'Toon'], ['matte', 'Matte'], ['glossy', 'Glossy'], ['metallic', 'Metallic']], { description: 'Style in which the 3D scene is rendered' }),
|
||||
renderStyle: PD.Select('glossy', [['flat', 'Flat'], ['matte', 'Matte'], ['glossy', 'Glossy'], ['metallic', 'Metallic']], { description: 'Style in which the 3D scene is rendered' }),
|
||||
occlusion: PD.Boolean(false, { description: 'Darken occluded crevices with the ambient occlusion effect' }),
|
||||
outline: PD.Boolean(false, { description: 'Draw outline around 3D objects' }),
|
||||
fog: PD.Boolean(false, { description: 'Show fog in the distance' }),
|
||||
@@ -49,7 +49,7 @@ export class SimpleSettingsControl extends PluginUIComponent {
|
||||
if (!this.plugin.canvas3d) return;
|
||||
|
||||
const renderer = this.plugin.canvas3d.props.renderer;
|
||||
if (p.value === 'toon') {
|
||||
if (p.value === 'flat') {
|
||||
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: {
|
||||
renderer: { ...renderer, lightIntensity: 0, ambientIntensity: 1, roughness: 0.4, metalness: 0 }
|
||||
} });
|
||||
@@ -80,7 +80,7 @@ export class SimpleSettingsControl extends PluginUIComponent {
|
||||
} });
|
||||
} else if (p.name === 'fog') {;
|
||||
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: {
|
||||
cameraFog: p.value ? 50 : 1,
|
||||
cameraFog: p.value ? 50 : 0,
|
||||
} });
|
||||
} else if (p.name === 'clipFar') {;
|
||||
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: {
|
||||
@@ -97,7 +97,7 @@ export class SimpleSettingsControl extends PluginUIComponent {
|
||||
|
||||
if (renderer) {
|
||||
if (renderer.lightIntensity === 0 && renderer.ambientIntensity === 1 && renderer.roughness === 0.4 && renderer.metalness === 0) {
|
||||
renderStyle = 'toon'
|
||||
renderStyle = 'flat'
|
||||
} else if (renderer.lightIntensity === 0.6 && renderer.ambientIntensity === 0.4) {
|
||||
if (renderer.roughness === 1 && renderer.metalness === 0) {
|
||||
renderStyle = 'matte'
|
||||
|
||||
@@ -61,6 +61,8 @@ const InitAssemblySymmetry3D = StateAction.build({
|
||||
await state.updateTree(tree).runInContext(ctx);
|
||||
}));
|
||||
|
||||
export { AssemblySymmetry3D }
|
||||
|
||||
type AssemblySymmetry3D = typeof AssemblySymmetry3D
|
||||
const AssemblySymmetry3D = PluginStateTransform.BuiltIn({
|
||||
name: 'rcsb-assembly-symmetry-3d',
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-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>
|
||||
*/
|
||||
|
||||
import { Model, Structure, StructureSymmetry } from '../../../mol-model/structure';
|
||||
import { stringToWords } from '../../../mol-util/string';
|
||||
import { SpacegroupCell } from '../../../mol-math/geometry';
|
||||
import { SpacegroupCell, Spacegroup } from '../../../mol-math/geometry';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { RuntimeContext } from '../../../mol-task';
|
||||
@@ -14,14 +15,33 @@ import { PluginContext } from '../../context';
|
||||
import { Assembly, Symmetry } from '../../../mol-model/structure/model/properties/symmetry';
|
||||
import { PluginStateObject as SO } from '../objects';
|
||||
import { ModelSymmetry } from '../../../mol-model-formats/structure/property/symmetry';
|
||||
import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
|
||||
|
||||
export namespace ModelStructureRepresentation {
|
||||
export function getParams(model?: Model, defaultValue?: 'deposited' | 'assembly' | 'symmetry' | 'symmetry-mates') {
|
||||
export function getParams(model?: Model, defaultValue?: 'deposited' | 'assembly' | 'symmetry' | 'symmetry-mates' | 'symmetry-assembly') {
|
||||
const symmetry = model && ModelSymmetry.Provider.get(model)
|
||||
|
||||
const assemblyIds = symmetry ? symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]) : [];
|
||||
const showSymm = !symmetry ? true : !SpacegroupCell.isZero(symmetry.spacegroup.cell);
|
||||
|
||||
const operatorOptions: [number, string][] = []
|
||||
if (symmetry) {
|
||||
const { operators } = symmetry.spacegroup
|
||||
for (let i = 0, il = operators.length; i < il; i++) {
|
||||
operatorOptions.push([i, `${i + 1}: ${Spacegroup.getOperatorXyz(operators[i])}`])
|
||||
}
|
||||
}
|
||||
|
||||
const asymIdsOptions: [string, string][] = []
|
||||
if (model && MmcifFormat.is(model?.sourceData)) {
|
||||
// TODO make generally available for models, also include auth_asym_id
|
||||
const { struct_asym } = model.sourceData.data.db
|
||||
for (let i = 0, il = struct_asym._rowCount; i < il; ++i) {
|
||||
const id = struct_asym.id.value(i)
|
||||
asymIdsOptions.push([id, id])
|
||||
}
|
||||
}
|
||||
|
||||
const modes = {
|
||||
deposited: PD.EmptyGroup(),
|
||||
assembly: PD.Group({
|
||||
@@ -35,6 +55,19 @@ export namespace ModelStructureRepresentation {
|
||||
'symmetry': PD.Group({
|
||||
ijkMin: PD.Vec3(Vec3.create(-1, -1, -1), { label: 'Min IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } }),
|
||||
ijkMax: PD.Vec3(Vec3.create(1, 1, 1), { label: 'Max IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
|
||||
}, { isFlat: true }),
|
||||
'symmetry-assembly': PD.Group({
|
||||
generators: PD.ObjectList({
|
||||
operators: PD.ObjectList({
|
||||
index: PD.Select(0, operatorOptions),
|
||||
shift: PD.Vec3(Vec3(), { label: 'IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
|
||||
}, e => `${e.index + 1}_${e.shift.map(a => a + 5).join('')}`, {
|
||||
defaultValue: [] as { index: number, shift: Vec3 }[]
|
||||
}),
|
||||
asymIds: PD.MultiSelect([] as string[], asymIdsOptions)
|
||||
}, e => `${e.asymIds.length} asym ids, ${e.operators.length} operators`, {
|
||||
defaultValue: [] as { operators: { index: number, shift: Vec3 }[], asymIds: string[] }[]
|
||||
})
|
||||
}, { isFlat: true })
|
||||
};
|
||||
|
||||
@@ -49,6 +82,7 @@ export namespace ModelStructureRepresentation {
|
||||
if (showSymm) {
|
||||
options.push(['symmetry-mates', 'Symmetry Mates']);
|
||||
options.push(['symmetry', 'Symmetry (indices)']);
|
||||
options.push(['symmetry-assembly', 'Symmetry (assembly)']);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -105,8 +139,16 @@ export namespace ModelStructureRepresentation {
|
||||
return new SO.Molecule.Structure(s, props);
|
||||
}
|
||||
|
||||
async function buildSymmetryAssembly(ctx: RuntimeContext, model: Model, generators: StructureSymmetry.Generators, symmetry: Symmetry) {
|
||||
const base = Structure.ofModel(model);
|
||||
const s = await StructureSymmetry.buildSymmetryAssembly(base, generators, symmetry).runInContext(ctx);
|
||||
const props = { label: `Symmetry Assembly`, description: Structure.elementDescription(s) };
|
||||
return new SO.Molecule.Structure(s, props);
|
||||
}
|
||||
|
||||
export async function create(plugin: PluginContext, ctx: RuntimeContext, model: Model, params?: Params): Promise<SO.Molecule.Structure> {
|
||||
if (!params || params.name === 'deposited') {
|
||||
const symmetry = ModelSymmetry.Provider.get(model)
|
||||
if (!symmetry || !params || params.name === 'deposited') {
|
||||
const s = Structure.ofModel(model);
|
||||
return new SO.Molecule.Structure(s, { label: 'Deposited', description: Structure.elementDescription(s) });
|
||||
}
|
||||
@@ -119,6 +161,9 @@ export namespace ModelStructureRepresentation {
|
||||
if (params.name === 'symmetry-mates') {
|
||||
return buildSymmetryMates(ctx, model, params.params.radius)
|
||||
}
|
||||
if (params.name === 'symmetry-assembly') {
|
||||
return buildSymmetryAssembly(ctx, model, params.params.generators, symmetry)
|
||||
}
|
||||
|
||||
throw new Error(`Unknown represetation type: ${(params as any).name}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user