mirror of
https://github.com/molstar/molstar.git
synced 2026-06-06 06:34:23 +08:00
Compare commits
47 Commits
v3.0.0-dev
...
v3.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddc4d8e867 | ||
|
|
7cded03598 | ||
|
|
744b04edc6 | ||
|
|
f2119b1d0b | ||
|
|
b4783909d7 | ||
|
|
fe5f841ab8 | ||
|
|
2c3f0dbc97 | ||
|
|
224fd1733f | ||
|
|
1f262ee422 | ||
|
|
df3bcdd05a | ||
|
|
d5d08542ed | ||
|
|
564a360c8f | ||
|
|
fe0d4dc11e | ||
|
|
812eb0efa9 | ||
|
|
10d0bf293a | ||
|
|
ce2544b9f3 | ||
|
|
1964de1e44 | ||
|
|
20c9d2cc41 | ||
|
|
3b1513adc0 | ||
|
|
eaa60fc5cd | ||
|
|
ce1e3960a2 | ||
|
|
176f80ea9b | ||
|
|
28c9dc8286 | ||
|
|
2135f76441 | ||
|
|
5637a23153 | ||
|
|
2818389741 | ||
|
|
805f772696 | ||
|
|
308bbc1ea0 | ||
|
|
4a248b5591 | ||
|
|
704a9a111d | ||
|
|
a6befc5509 | ||
|
|
9e7aa4226d | ||
|
|
7a25699c23 | ||
|
|
901ae7f6d6 | ||
|
|
694261c19c | ||
|
|
58ce1f6498 | ||
|
|
47c4353eb9 | ||
|
|
d82cd3a8fe | ||
|
|
8f06b603e6 | ||
|
|
0865c1b7fb | ||
|
|
c8c32b89c1 | ||
|
|
658c789906 | ||
|
|
c9ad7fce5b | ||
|
|
720a8a440f | ||
|
|
84fe2d2502 | ||
|
|
6f159c592f | ||
|
|
beff1ecb3e |
2
.github/workflows/node.yml
vendored
2
.github/workflows/node.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
node-version: 17
|
||||
- run: npm ci
|
||||
- run: sudo apt-get install xvfb
|
||||
- name: Lint
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -7,6 +7,8 @@
|
||||
"*.gql.ts": "graphql"
|
||||
},
|
||||
"eslint.options": {
|
||||
"ignorePattern": ["webpack.config.js", "scripts/*"],
|
||||
"overrideConfig": {
|
||||
"ignorePatterns": ["webpack.config.js", "scripts/*"],
|
||||
},
|
||||
}
|
||||
}
|
||||
34
CHANGELOG.md
34
CHANGELOG.md
@@ -6,6 +6,38 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.0.0-dev.6] - 2021-12-19
|
||||
|
||||
- Enable temporal multi-sampling by default
|
||||
- Fix flickering during marking with camera at rest
|
||||
- Enable ``aromaticBonds`` in structure representations by default
|
||||
- Add ``PluginConfig.Structure.DefaultRepresentationPreset``
|
||||
- Add ModelArchive support
|
||||
- schema extensions (e.g., AlphaFold uses it for the pLDDT score)
|
||||
- ModelArchive option in DownloadStructure action
|
||||
- ``model-archive`` GET parameter for Viewer app
|
||||
- ``Viewer.loadModelArchive`` method
|
||||
- Improve support for loading AlphaFold structures
|
||||
- Automatic coloring by pLDDT
|
||||
- AlphaFold DB option in DownloadStructure action
|
||||
- ``afdb`` GET parameter for Viewer app
|
||||
- ``Viewer.loadAlphaFoldDb`` method
|
||||
- Add QualityAssessment extension (using data from ma_qa_metric_local mmcif category)
|
||||
- pLDDT & qmean score: coloring, repr presets, molql symbol, loci labels (including avg for mutli-residue selections)
|
||||
- pLDDT: selection query
|
||||
- Warn about erroneous symmetry operator matrix (instead of throwing an error)
|
||||
- Added ``createPluginUI`` to ``mol-plugin-ui``
|
||||
- Support ``onBeforeUIRender`` to make sure initial UI works with custom presets and similar features.
|
||||
- [Breaking] Removed ``createPlugin`` and ``createPluginAsync`` from ``mol-plugin-ui``
|
||||
- Please use ``createPluginUI`` instead
|
||||
- Improve aromatic bonds handling
|
||||
- Don't detect aromatic bonds for rings < 5 atoms based on planarity
|
||||
- Prefer atoms in aromatic rings as bond reference positions
|
||||
|
||||
## [v3.0.0-dev.5] - 2021-12-16
|
||||
|
||||
- Fix initial camera reset not triggering for some entries.
|
||||
|
||||
## [v3.0.0-dev.4] - 2021-12-14
|
||||
|
||||
- Add ``bumpiness`` (per-object and per-group), ``bumpFrequency`` & ``bumpAmplitude`` (per-object) render parameters (#299)
|
||||
@@ -30,7 +62,7 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
- Add multiple lights support (with color, intensity, and direction parameters)
|
||||
- [Breaking] Add per-object material rendering properties
|
||||
- ``SimpleSettingsParams.lighting.renderStyle`` and ``RendererParams.style`` were removed
|
||||
- ``SimpleSettingsParams.lighting.renderStyle`` and ``RendererParams.style`` were removed
|
||||
- Add substance theme with per-group material rendering properties
|
||||
- ``StructureComponentManager.Options`` state saving support
|
||||
- ``ParamDefinition.Group.presets`` support
|
||||
|
||||
@@ -246,6 +246,14 @@ citation_author.ordinal
|
||||
exptl.entry_id
|
||||
exptl.method
|
||||
|
||||
software.classification
|
||||
software.date
|
||||
software.description
|
||||
software.name
|
||||
software.pdbx_ordinal
|
||||
software.type
|
||||
software.version
|
||||
|
||||
struct.entry_id
|
||||
struct.title
|
||||
struct.pdbx_descriptor
|
||||
@@ -802,4 +810,58 @@ ihm_multi_state_modeling.population_fraction_sd
|
||||
ihm_multi_state_modeling.state_type
|
||||
ihm_multi_state_modeling.state_name
|
||||
ihm_multi_state_modeling.experiment_type
|
||||
ihm_multi_state_modeling.details
|
||||
ihm_multi_state_modeling.details
|
||||
|
||||
ma_data.content_type
|
||||
ma_data.content_type_other_details
|
||||
ma_data.id
|
||||
ma_data.name
|
||||
|
||||
ma_model_list.data_id
|
||||
ma_model_list.model_group_id
|
||||
ma_model_list.model_group_name
|
||||
ma_model_list.model_id
|
||||
ma_model_list.model_name
|
||||
ma_model_list.model_type
|
||||
ma_model_list.ordinal_id
|
||||
|
||||
ma_qa_metric.id
|
||||
ma_qa_metric.mode
|
||||
ma_qa_metric.name
|
||||
ma_qa_metric.software_group_id
|
||||
ma_qa_metric.type
|
||||
|
||||
ma_qa_metric_global.metric_id
|
||||
ma_qa_metric_global.metric_value
|
||||
ma_qa_metric_global.model_id
|
||||
ma_qa_metric_global.ordinal_id
|
||||
|
||||
ma_qa_metric_local.label_asym_id
|
||||
ma_qa_metric_local.label_comp_id
|
||||
ma_qa_metric_local.label_seq_id
|
||||
ma_qa_metric_local.metric_id
|
||||
ma_qa_metric_local.metric_value
|
||||
ma_qa_metric_local.model_id
|
||||
ma_qa_metric_local.ordinal_id
|
||||
|
||||
ma_software_group.group_id
|
||||
ma_software_group.ordinal_id
|
||||
ma_software_group.software_id
|
||||
|
||||
ma_target_entity.data_id
|
||||
ma_target_entity.entity_id
|
||||
ma_target_entity.origin
|
||||
|
||||
ma_target_entity_instance.asym_id
|
||||
ma_target_entity_instance.details
|
||||
ma_target_entity_instance.entity_id
|
||||
|
||||
ma_target_ref_db_details.db_accession
|
||||
ma_target_ref_db_details.db_code
|
||||
ma_target_ref_db_details.db_name
|
||||
ma_target_ref_db_details.ncbi_taxonomy_id
|
||||
ma_target_ref_db_details.organism_scientific
|
||||
ma_target_ref_db_details.seq_db_align_begin
|
||||
ma_target_ref_db_details.seq_db_align_end
|
||||
ma_target_ref_db_details.seq_db_isoform
|
||||
ma_target_ref_db_details.target_entity_id
|
||||
|
@@ -29,6 +29,11 @@
|
||||
* Long linear sugar chain (4HG6)
|
||||
* Anisotropic B-factors/Ellipsoids (1EJG)
|
||||
* NOS bridges (LYS-CSO in 7B0L, 6ZWJ, 6ZWH)
|
||||
* Non-polymer components in polymer entities
|
||||
* PN2 in 1F80
|
||||
* ACE (many, e.g. 5AGU, 1E1X)
|
||||
* ACY in 7ABY
|
||||
* NH2 (many, e.g. 6Y13)
|
||||
|
||||
Assembly symmetries
|
||||
* 5M30 (Assembly 1, C3 local and pseudo)
|
||||
|
||||
86
examples/ace2-hit.mol2
Normal file
86
examples/ace2-hit.mol2
Normal file
@@ -0,0 +1,86 @@
|
||||
@<TRIPOS>MOLECULE
|
||||
ace2_r_r2.top2000.poses.plain/3_Z1137565832_1_T2.pdb
|
||||
37 41 0 0 0
|
||||
SMALL
|
||||
GASTEIGER
|
||||
|
||||
@<TRIPOS>ATOM
|
||||
1 C 64.7720 85.9180 38.1090 C.3 1 LIG1 0.0799
|
||||
2 C 64.6440 84.6900 37.1570 C.3 1 LIG1 0.0306
|
||||
3 C 65.2660 83.4260 37.8080 C.3 1 LIG1 0.0927
|
||||
4 N 66.6560 83.6710 38.1790 N.pl3 1 LIG1 -0.2919
|
||||
5 C 67.7080 82.9280 37.6260 C.ar 1 LIG1 0.1520
|
||||
6 C 69.0970 83.1860 37.8250 C.ar 1 LIG1 0.0393
|
||||
7 C 70.0830 82.4100 37.1810 C.ar 1 LIG1 0.0436
|
||||
8 C 69.6450 81.3740 36.3510 C.ar 1 LIG1 0.1867
|
||||
9 N 70.3370 80.5030 35.6050 N.ar 1 LIG1 -0.1270
|
||||
10 N 69.4700 79.7480 35.0040 N.ar 1 LIG1 -0.1228
|
||||
11 C 68.2200 80.1120 35.3570 C.ar 1 LIG1 0.2583
|
||||
12 N 68.3350 81.1470 36.2040 N.ar 1 LIG1 -0.1866
|
||||
13 N 67.4230 81.8700 36.8030 N.ar 1 LIG1 -0.1473
|
||||
14 C 66.8190 84.7600 39.1350 C.3 1 LIG1 0.0927
|
||||
15 C 66.2560 86.0870 38.5570 C.3 1 LIG1 0.0306
|
||||
16 N 64.4520 87.4670 36.2150 N.am 1 LIG1 -0.2979
|
||||
17 H 64.9740 86.7650 35.7110 H 1 LIG1 0.1498
|
||||
18 C 64.2290 87.1720 37.5220 C.2 1 LIG1 0.2224
|
||||
19 O 63.5690 87.9550 38.2480 O.2 1 LIG1 -0.2751
|
||||
20 C 64.0160 88.6470 35.5420 C.3 1 LIG1 0.1559
|
||||
21 C 65.9650 88.2170 32.5700 C.ar 1 LIG1 0.1629
|
||||
22 N 65.8040 88.0390 33.8860 N.ar 1 LIG1 -0.3232
|
||||
23 H 66.4190 87.5270 34.5040 H 1 LIG1 0.1686
|
||||
24 C 64.6770 88.6690 34.2330 C.ar 1 LIG1 0.1601
|
||||
25 N 64.1890 89.2810 33.1430 N.ar 1 LIG1 -0.1318
|
||||
26 N 64.9640 89.0070 32.1450 N.ar 1 LIG1 -0.1293
|
||||
27 F 69.9260 86.0280 29.3520 F 1 LIG1 -0.2042
|
||||
28 C 68.9880 86.5420 30.0990 C.ar 1 LIG1 0.1401
|
||||
29 C 67.6590 86.0900 29.9830 C.ar 1 LIG1 0.0297
|
||||
30 C 66.6500 86.6450 30.7950 C.ar 1 LIG1 0.0053
|
||||
31 C 66.9590 87.6470 31.7450 C.ar 1 LIG1 0.0359
|
||||
32 C 68.2970 88.0990 31.8400 C.ar 1 LIG1 0.0053
|
||||
33 C 69.3030 87.5560 31.0230 C.ar 1 LIG1 0.0297
|
||||
34 C 66.9850 79.4910 34.8440 C.3 1 LIG1 0.4541
|
||||
35 F 67.3150 78.4110 34.0640 F 1 LIG1 -0.1631
|
||||
36 F 66.2460 80.3690 34.0910 F 1 LIG1 -0.1631
|
||||
37 F 66.1920 79.0650 35.8800 F 1 LIG1 -0.1631
|
||||
@<TRIPOS>BOND
|
||||
1 1 2 1
|
||||
2 1 18 1
|
||||
3 1 15 1
|
||||
4 2 3 1
|
||||
5 3 4 1
|
||||
6 4 5 1
|
||||
7 4 14 1
|
||||
8 5 13 ar
|
||||
9 5 6 ar
|
||||
10 6 7 ar
|
||||
11 7 8 ar
|
||||
12 8 9 ar
|
||||
13 8 12 ar
|
||||
14 9 10 ar
|
||||
15 10 11 ar
|
||||
16 11 34 1
|
||||
17 11 12 ar
|
||||
18 12 13 ar
|
||||
19 14 15 1
|
||||
20 16 20 1
|
||||
21 16 17 1
|
||||
22 16 18 am
|
||||
23 18 19 2
|
||||
24 20 24 1
|
||||
25 21 31 1
|
||||
26 21 26 ar
|
||||
27 21 22 ar
|
||||
28 22 24 ar
|
||||
29 22 23 1
|
||||
30 24 25 ar
|
||||
31 25 26 ar
|
||||
32 27 28 1
|
||||
33 28 29 ar
|
||||
34 28 33 ar
|
||||
35 29 30 ar
|
||||
36 30 31 ar
|
||||
37 31 32 ar
|
||||
38 32 33 ar
|
||||
39 34 35 1
|
||||
40 34 36 1
|
||||
41 34 37 1
|
||||
7628
examples/ace2.pdbqt
Normal file
7628
examples/ace2.pdbqt
Normal file
File diff suppressed because it is too large
Load Diff
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.0.0-dev.4",
|
||||
"version": "3.0.0-dev.6",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "molstar",
|
||||
"version": "3.0.0-dev.4",
|
||||
"version": "3.0.0-dev.6",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.10",
|
||||
@@ -12527,9 +12527,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-ui-dist": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.1.tgz",
|
||||
"integrity": "sha512-xvPMEpOCbd5S9Z1pJT/L/K/C2yAX89ZWJDxEECkVW1dENsKFLbu7sRY7b6UBqLXuTUfdM5owlgPrpwr24CRonA=="
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz",
|
||||
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
||||
},
|
||||
"node_modules/swap-case": {
|
||||
"version": "2.0.2",
|
||||
@@ -23561,9 +23561,9 @@
|
||||
}
|
||||
},
|
||||
"swagger-ui-dist": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.1.tgz",
|
||||
"integrity": "sha512-xvPMEpOCbd5S9Z1pJT/L/K/C2yAX89ZWJDxEECkVW1dENsKFLbu7sRY7b6UBqLXuTUfdM5owlgPrpwr24CRonA=="
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz",
|
||||
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
||||
},
|
||||
"swap-case": {
|
||||
"version": "2.0.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.0.0-dev.4",
|
||||
"version": "3.0.0-dev.6",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -39,6 +39,24 @@ function copyViewer() {
|
||||
addAnalytics(path.resolve(viewerDeployPath, 'index.html'));
|
||||
}
|
||||
|
||||
function copyDemos() {
|
||||
console.log('\n###', 'copy demos files');
|
||||
const lightingBuildPath = path.resolve(buildDir, '../build/examples/lighting/');
|
||||
const lightingDeployPath = path.resolve(localPath, 'demos/lighting/');
|
||||
fse.copySync(lightingBuildPath, lightingDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(lightingDeployPath, 'index.html'));
|
||||
|
||||
const orbitalsBuildPath = path.resolve(buildDir, '../build/examples/alpha-orbitals/');
|
||||
const orbitalsDeployPath = path.resolve(localPath, 'demos/alpha-orbitals/');
|
||||
fse.copySync(orbitalsBuildPath, orbitalsDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(orbitalsDeployPath, 'index.html'));
|
||||
}
|
||||
|
||||
function copyFiles() {
|
||||
copyViewer();
|
||||
copyDemos();
|
||||
}
|
||||
|
||||
if (!fs.existsSync(localPath)) {
|
||||
console.log('\n###', 'create localPath');
|
||||
fs.mkdirSync(localPath, { recursive: true });
|
||||
@@ -52,9 +70,9 @@ if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
|
||||
.outputHandler(log)
|
||||
.clone(remoteUrl, localPath)
|
||||
.fetch(['--all'])
|
||||
.exec(copyViewer)
|
||||
.exec(copyFiles)
|
||||
.add(['-A'])
|
||||
.commit('updated viewer')
|
||||
.commit('updated viewer & demos')
|
||||
.push();
|
||||
} else {
|
||||
console.log('\n###', 'update repository');
|
||||
@@ -62,8 +80,8 @@ if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
|
||||
.outputHandler(log)
|
||||
.fetch(['--all'])
|
||||
.reset(['--hard', 'origin/master'])
|
||||
.exec(copyViewer)
|
||||
.exec(copyFiles)
|
||||
.add(['-A'])
|
||||
.commit('updated viewer')
|
||||
.commit('updated viewer & demos')
|
||||
.push();
|
||||
}
|
||||
@@ -19,19 +19,19 @@
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="./molstar.js"></script>
|
||||
<script type="text/javascript">
|
||||
var viewer = new DockingViewer('app', [0x33DD22, 0x1133EE], true);
|
||||
|
||||
function getParam(name, regex) {
|
||||
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
|
||||
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
|
||||
}
|
||||
var pdbqt = getParam('pdbqt', '[^&]+').trim();
|
||||
var mol2 = getParam('mol2', '[^&]+').trim();
|
||||
var pdbqt = getParam('pdbqt', '[^&]+').trim() || '../../examples/ace2.pdbqt';
|
||||
var mol2 = getParam('mol2', '[^&]+').trim() || '../../examples/ace2-hit.mol2';
|
||||
|
||||
viewer.loadStructuresFromUrlsAndMerge([
|
||||
{ url: pdbqt, format: 'pdbqt' },
|
||||
{ url: mol2, format: 'mol2' }
|
||||
]);
|
||||
DockingViewer.create('app', [0x33DD22, 0x1133EE], true).then(viewer => {
|
||||
viewer.loadStructuresFromUrlsAndMerge([
|
||||
{ url: pdbqt, format: 'pdbqt' },
|
||||
{ url: mol2, format: 'mol2' }
|
||||
]);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,7 +8,7 @@
|
||||
import { Structure } from '../../mol-model/structure';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { PluginStateObject as PSO, PluginStateTransform } from '../../mol-plugin-state/objects';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
|
||||
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
@@ -54,9 +54,10 @@ const DefaultViewerOptions = {
|
||||
};
|
||||
|
||||
class Viewer {
|
||||
plugin: PluginUIContext
|
||||
constructor(public plugin: PluginUIContext) {
|
||||
}
|
||||
|
||||
constructor(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
|
||||
static async create(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
|
||||
const o = { ...DefaultViewerOptions, ...{
|
||||
layoutIsExpanded: false,
|
||||
layoutShowControls: false,
|
||||
@@ -125,29 +126,31 @@ class Viewer {
|
||||
? document.getElementById(elementOrId)
|
||||
: elementOrId;
|
||||
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
|
||||
this.plugin = createPlugin(element, spec);
|
||||
const plugin = await createPluginUI(element, spec);
|
||||
|
||||
(this.plugin.customState as any) = {
|
||||
(plugin.customState as any) = {
|
||||
colorPalette: {
|
||||
name: 'colors',
|
||||
params: { list: { colors } }
|
||||
}
|
||||
};
|
||||
|
||||
this.plugin.behaviors.canvas3d.initialized.subscribe(v => {
|
||||
plugin.behaviors.canvas3d.initialized.subscribe(v => {
|
||||
if (v) {
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
|
||||
PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
|
||||
renderer: {
|
||||
...this.plugin.canvas3d!.props.renderer,
|
||||
...plugin.canvas3d!.props.renderer,
|
||||
backgroundColor: ColorNames.white,
|
||||
},
|
||||
camera: {
|
||||
...this.plugin.canvas3d!.props.camera,
|
||||
...plugin.canvas3d!.props.camera,
|
||||
helper: { axes: { name: 'off', params: {} } }
|
||||
}
|
||||
} });
|
||||
}
|
||||
});
|
||||
|
||||
return new Viewer(plugin);
|
||||
}
|
||||
|
||||
async loadStructuresFromUrlsAndMerge(sources: { url: string, format: BuiltInTrajectoryFormat, isBinary?: boolean }[]) {
|
||||
|
||||
@@ -230,7 +230,7 @@ export class ViewportComponent extends PluginUIComponent {
|
||||
|
||||
set = async (preset: StructureRepresentationPresetProvider) => {
|
||||
await this._set(this.plugin.managers.structure.hierarchy.selection.structures, preset);
|
||||
}
|
||||
};
|
||||
|
||||
structurePreset = () => this.set(StructurePreset);
|
||||
illustrativePreset = () => this.set(IllustrativePreset);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="./molstar.js"></script>
|
||||
<script type="text/javascript">
|
||||
var viewer = new molstar.Viewer('app', {
|
||||
molstar.Viewer.create('app', {
|
||||
layoutIsExpanded: true,
|
||||
layoutShowControls: false,
|
||||
layoutShowRemoteState: false,
|
||||
@@ -34,11 +34,11 @@
|
||||
|
||||
pdbProvider: 'rcsb',
|
||||
emdbProvider: 'rcsb',
|
||||
}).then(viewer => {
|
||||
viewer.loadPdb('7bv2');
|
||||
viewer.loadEmdb('EMD-30210', { detail: 6 });
|
||||
// viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } })
|
||||
});
|
||||
viewer.loadPdb('7bv2');
|
||||
viewer.loadEmdb('EMD-30210', { detail: 6 });
|
||||
|
||||
// viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -56,7 +56,8 @@
|
||||
var pixelScale = getParam('pixel-scale', '[^&]+').trim();
|
||||
var pickScale = getParam('pick-scale', '[^&]+').trim();
|
||||
var pickPadding = getParam('pick-padding', '[^&]+').trim();
|
||||
var viewer = new molstar.Viewer('app', {
|
||||
|
||||
molstar.Viewer.create('app', {
|
||||
layoutShowControls: !hideControls,
|
||||
viewportShowExpand: false,
|
||||
collapseLeftPanel: collapseLeftPanel,
|
||||
@@ -68,28 +69,34 @@
|
||||
pixelScale: parseFloat(pixelScale) || 1,
|
||||
pickScale: parseFloat(pickScale) || 0.25,
|
||||
pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
|
||||
}).then(viewer => {
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
|
||||
|
||||
var snapshotUrl = getParam('snapshot-url', '[^&]+').trim();
|
||||
var snapshotUrlType = getParam('snapshot-url-type', '[^&]+').toLowerCase().trim() || 'molj';
|
||||
if (snapshotUrl && snapshotUrlType) viewer.loadSnapshotFromUrl(snapshotUrl, snapshotUrlType);
|
||||
|
||||
var structureUrl = getParam('structure-url', '[^&]+').trim();
|
||||
var structureUrlFormat = getParam('structure-url-format', '[a-z]+').toLowerCase().trim();
|
||||
var structureUrlIsBinary = getParam('structure-url-is-binary', '[^&]+').trim() === '1';
|
||||
if (structureUrl) viewer.loadStructureFromUrl(structureUrl, structureUrlFormat, structureUrlIsBinary);
|
||||
|
||||
var pdb = getParam('pdb', '[^&]+').trim();
|
||||
if (pdb) viewer.loadPdb(pdb);
|
||||
|
||||
var pdbDev = getParam('pdb-dev', '[^&]+').trim();
|
||||
if (pdbDev) viewer.loadPdbDev(pdbDev);
|
||||
|
||||
var emdb = getParam('emdb', '[^&]+').trim();
|
||||
if (emdb) viewer.loadEmdb(emdb);
|
||||
|
||||
var afdb = getParam('afdb', '[^&]+').trim();
|
||||
if (afdb) viewer.loadAlphaFoldDb(afdb);
|
||||
|
||||
var modelArchive = getParam('model-archive', '[^&]+').trim();
|
||||
if (modelArchive) viewer.loadModelArchive(modelArchive);
|
||||
});
|
||||
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
|
||||
|
||||
var snapshotUrl = getParam('snapshot-url', '[^&]+').trim();
|
||||
var snapshotUrlType = getParam('snapshot-url-type', '[^&]+').toLowerCase().trim() || 'molj';
|
||||
if (snapshotUrl && snapshotUrlType) viewer.loadSnapshotFromUrl(snapshotUrl, snapshotUrlType);
|
||||
|
||||
var structureUrl = getParam('structure-url', '[^&]+').trim();
|
||||
var structureUrlFormat = getParam('structure-url-format', '[a-z]+').toLowerCase().trim();
|
||||
var structureUrlIsBinary = getParam('structure-url-is-binary', '[^&]+').trim() === '1';
|
||||
if (structureUrl) viewer.loadStructureFromUrl(structureUrl, structureUrlFormat, structureUrlIsBinary);
|
||||
|
||||
var pdb = getParam('pdb', '[^&]+').trim();
|
||||
if (pdb) viewer.loadPdb(pdb);
|
||||
|
||||
var pdbDev = getParam('pdb-dev', '[^&]+').trim();
|
||||
if (pdbDev) viewer.loadPdbDev(pdbDev);
|
||||
|
||||
var emdb = getParam('emdb', '[^&]+').trim();
|
||||
if (emdb) viewer.loadEmdb(emdb);
|
||||
</script>
|
||||
<!-- __MOLSTAR_ANALYTICS__ -->
|
||||
</body>
|
||||
|
||||
@@ -10,13 +10,16 @@ import { CellPack } from '../../extensions/cellpack';
|
||||
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
|
||||
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
|
||||
import { GeometryExport } from '../../extensions/geo-export';
|
||||
import { MAQualityAssessment } from '../../extensions/model-archive/quality-assessment/behavior';
|
||||
import { QualityAssessmentPLDDTPreset, QualityAssessmentQmeanPreset } from '../../extensions/model-archive/quality-assessment/behavior';
|
||||
import { QualityAssessment } from '../../extensions/model-archive/quality-assessment/prop';
|
||||
import { Mp4Export } from '../../extensions/mp4-export';
|
||||
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
|
||||
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
|
||||
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
|
||||
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
|
||||
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
|
||||
import { StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
|
||||
import { BuildInStructureFormat } from '../../mol-plugin-state/formats/structure';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
@@ -25,7 +28,7 @@ import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
@@ -33,7 +36,7 @@ import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
|
||||
import { PluginSpec } from '../../mol-plugin/spec';
|
||||
import { PluginState } from '../../mol-plugin/state';
|
||||
import { StateObjectSelector } from '../../mol-state';
|
||||
import { StateObjectRef, StateObjectSelector } from '../../mol-state';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import '../../mol-util/polyfill';
|
||||
@@ -60,7 +63,8 @@ const Extensions = {
|
||||
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
|
||||
'g3d': PluginSpec.Behavior(G3DFormat),
|
||||
'mp4-export': PluginSpec.Behavior(Mp4Export),
|
||||
'geo-export': PluginSpec.Behavior(GeometryExport)
|
||||
'geo-export': PluginSpec.Behavior(GeometryExport),
|
||||
'ma-quality-assessment': PluginSpec.Behavior(MAQualityAssessment),
|
||||
};
|
||||
|
||||
const DefaultViewerOptions = {
|
||||
@@ -95,9 +99,10 @@ const DefaultViewerOptions = {
|
||||
type ViewerOptions = typeof DefaultViewerOptions;
|
||||
|
||||
export class Viewer {
|
||||
plugin: PluginUIContext
|
||||
constructor(public plugin: PluginUIContext) {
|
||||
}
|
||||
|
||||
constructor(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
|
||||
static async create(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
|
||||
const o = { ...DefaultViewerOptions, ...options };
|
||||
const defaultSpec = DefaultPluginUISpec();
|
||||
|
||||
@@ -149,7 +154,8 @@ export class Viewer {
|
||||
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
|
||||
[PluginConfig.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
|
||||
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
|
||||
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider]
|
||||
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
|
||||
[PluginConfig.Structure.DefaultRepresentationPreset, ViewerAutoPreset.id],
|
||||
]
|
||||
};
|
||||
|
||||
@@ -157,7 +163,14 @@ export class Viewer {
|
||||
? document.getElementById(elementOrId)
|
||||
: elementOrId;
|
||||
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
|
||||
this.plugin = createPlugin(element, spec);
|
||||
const plugin = await createPluginUI(element, spec, {
|
||||
onBeforeUIRender: plugin => {
|
||||
// the preset needs to be added before the UI renders otherwise
|
||||
// "Download Structure" wont be able to pick it up
|
||||
plugin.builders.structure.representation.registerPreset(ViewerAutoPreset);
|
||||
}
|
||||
});
|
||||
return new Viewer(plugin);
|
||||
}
|
||||
|
||||
setRemoteSnapshot(id: string) {
|
||||
@@ -251,6 +264,35 @@ export class Viewer {
|
||||
}));
|
||||
}
|
||||
|
||||
loadAlphaFoldDb(afdb: string) {
|
||||
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
name: 'alphafolddb' as const,
|
||||
params: {
|
||||
id: afdb,
|
||||
options: {
|
||||
...params.source.params.options,
|
||||
representation: 'preset-structure-representation-ma-quality-assessment-plddt'
|
||||
},
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
loadModelArchive(id: string) {
|
||||
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
name: 'modelarchive' as const,
|
||||
params: {
|
||||
id,
|
||||
options: params.source.params.options,
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @example Load X-ray density from volume server
|
||||
viewer.loadVolumeFromUrl({
|
||||
@@ -409,4 +451,32 @@ export interface LoadTrajectoryParams {
|
||||
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
|
||||
coordinatesLabel?: string,
|
||||
preset?: keyof PresetTrajectoryHierarchy
|
||||
}
|
||||
}
|
||||
|
||||
export const ViewerAutoPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-structure-representation-viewer-auto',
|
||||
display: {
|
||||
name: 'Automatic (w/ Annotation)', group: 'Annotation',
|
||||
description: 'Show standard automatic representation but colored by quality assessment (if available in the model).'
|
||||
},
|
||||
isApplicable(a) {
|
||||
return (
|
||||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')) ||
|
||||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))
|
||||
);
|
||||
},
|
||||
params: () => StructureRepresentationPresetProvider.CommonParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'))) {
|
||||
return await QualityAssessmentPLDDTPreset.apply(ref, params, plugin);
|
||||
} else if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))) {
|
||||
return await QualityAssessmentQmeanPreset.apply(ref, params, plugin);
|
||||
} else {
|
||||
return await PresetStructureRepresentations.auto.apply(ref, params, plugin);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -35,20 +35,16 @@ async function runGenerateSchemaMmcif(name: string, fieldNamesPath: string, type
|
||||
const ihmDic = await parseCifText(fs.readFileSync(IHM_DIC_PATH, 'utf8')).run();
|
||||
if (ihmDic.isError) throw ihmDic;
|
||||
|
||||
await ensureCarbBranchDicAvailable();
|
||||
const carbBranchDic = await parseCifText(fs.readFileSync(CARB_BRANCH_DIC_PATH, 'utf8')).run();
|
||||
if (carbBranchDic.isError) throw carbBranchDic;
|
||||
|
||||
await ensureCarbCompDicAvailable();
|
||||
const carbCompDic = await parseCifText(fs.readFileSync(CARB_COMP_DIC_PATH, 'utf8')).run();
|
||||
if (carbCompDic.isError) throw carbCompDic;
|
||||
await ensureMaDicAvailable();
|
||||
const maDic = await parseCifText(fs.readFileSync(MA_DIC_PATH, 'utf8')).run();
|
||||
if (maDic.isError) throw maDic;
|
||||
|
||||
const mmcifDicVersion = getDicVersion(mmcifDic.result.blocks[0]);
|
||||
const ihmDicVersion = getDicVersion(ihmDic.result.blocks[0]);
|
||||
const carbDicVersion = 'draft';
|
||||
const version = `Dictionary versions: mmCIF ${mmcifDicVersion}, IHM ${ihmDicVersion}, CARB ${carbDicVersion}.`;
|
||||
const maDicVersion = getDicVersion(maDic.result.blocks[0]);
|
||||
const version = `Dictionary versions: mmCIF ${mmcifDicVersion}, IHM ${ihmDicVersion}, MA ${maDicVersion}.`;
|
||||
|
||||
const frames: CifFrame[] = [...mmcifDic.result.blocks[0].saveFrames, ...ihmDic.result.blocks[0].saveFrames, ...carbBranchDic.result.blocks[0].saveFrames, ...carbCompDic.result.blocks[0].saveFrames];
|
||||
const frames: CifFrame[] = [...mmcifDic.result.blocks[0].saveFrames, ...ihmDic.result.blocks[0].saveFrames, ...maDic.result.blocks[0].saveFrames];
|
||||
const schema = generateSchema(frames);
|
||||
|
||||
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
|
||||
@@ -139,8 +135,7 @@ async function getFieldNamesFilter(fieldNamesPath: string): Promise<Filter> {
|
||||
|
||||
async function ensureMmcifDicAvailable() { await ensureDicAvailable(MMCIF_DIC_PATH, MMCIF_DIC_URL); }
|
||||
async function ensureIhmDicAvailable() { await ensureDicAvailable(IHM_DIC_PATH, IHM_DIC_URL); }
|
||||
async function ensureCarbBranchDicAvailable() { await ensureDicAvailable(CARB_BRANCH_DIC_PATH, CARB_BRANCH_DIC_URL); }
|
||||
async function ensureCarbCompDicAvailable() { await ensureDicAvailable(CARB_COMP_DIC_PATH, CARB_COMP_DIC_URL); }
|
||||
async function ensureMaDicAvailable() { await ensureDicAvailable(MA_DIC_PATH, MA_DIC_URL); }
|
||||
async function ensureCifCoreDicAvailable() {
|
||||
await ensureDicAvailable(CIF_CORE_DIC_PATH, CIF_CORE_DIC_URL);
|
||||
await ensureDicAvailable(CIF_CORE_ENUM_PATH, CIF_CORE_ENUM_URL);
|
||||
@@ -165,10 +160,8 @@ const MMCIF_DIC_PATH = `${DIC_DIR}/mmcif_pdbx_v50.dic`;
|
||||
const MMCIF_DIC_URL = 'http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic';
|
||||
const IHM_DIC_PATH = `${DIC_DIR}/ihm-extension.dic`;
|
||||
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHM-dictionary/master/ihm-extension.dic';
|
||||
const CARB_BRANCH_DIC_PATH = `${DIC_DIR}/entity_branch-extension.dic`;
|
||||
const CARB_BRANCH_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/entity_branch-extension.dic';
|
||||
const CARB_COMP_DIC_PATH = `${DIC_DIR}/chem_comp-extension.dic`;
|
||||
const CARB_COMP_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/chem_comp-extension.dic';
|
||||
const MA_DIC_PATH = `${DIC_DIR}/ma-extension.dic`;
|
||||
const MA_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/MA-dictionary/master/mmcif_ma.dic';
|
||||
|
||||
const CIF_CORE_DIC_PATH = `${DIC_DIR}/cif_core.dic`;
|
||||
const CIF_CORE_DIC_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/cif_core.dic';
|
||||
|
||||
@@ -57,5 +57,6 @@
|
||||
<script>
|
||||
AlphaOrbitalsExample.init('app')
|
||||
</script>
|
||||
<!-- __MOLSTAR_ANALYTICS__ -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,7 +11,7 @@ import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/spherical-f
|
||||
import { BasisAndOrbitals, CreateOrbitalDensityVolume, CreateOrbitalRepresentation3D, CreateOrbitalVolume, StaticBasisAndOrbitals } from '../../extensions/alpha-orbitals/transforms';
|
||||
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { createPluginAsync } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
@@ -54,7 +54,7 @@ export class AlphaOrbitalsExample {
|
||||
|
||||
async init(target: string | HTMLElement) {
|
||||
const defaultSpec = DefaultPluginUISpec();
|
||||
this.plugin = await createPluginAsync(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...defaultSpec,
|
||||
layout: {
|
||||
initial: {
|
||||
@@ -67,7 +67,7 @@ export class AlphaOrbitalsExample {
|
||||
},
|
||||
canvas3d: {
|
||||
camera: {
|
||||
helper: { axes: { name: 'off', params: { } } }
|
||||
helper: { axes: { name: 'off', params: {} } }
|
||||
}
|
||||
},
|
||||
config: [
|
||||
@@ -170,12 +170,11 @@ export class AlphaOrbitalsExample {
|
||||
return {
|
||||
alpha: 0.85,
|
||||
color,
|
||||
directVolume: this.state.value.gpuSurface,
|
||||
kind,
|
||||
relativeIsovalue: this.state.value.isoValue,
|
||||
pickable: false,
|
||||
xrayShaded: true,
|
||||
tryUseGpu: false
|
||||
tryUseGpu: true
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,9 @@
|
||||
$('format').value = format;
|
||||
$('format').onchange = function (e) { format = e.target.value; }
|
||||
|
||||
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
|
||||
BasicMolStarWrapper.setBackground(0xffffff);
|
||||
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */).then(() => {
|
||||
BasicMolStarWrapper.setBackground(0xffffff);
|
||||
});
|
||||
|
||||
addControl('Load Asym Unit', () => BasicMolStarWrapper.load({ url: url, format: format }));
|
||||
addControl('Load Assembly', () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId }));
|
||||
|
||||
@@ -9,7 +9,7 @@ import { EmptyLoci } from '../../mol-model/loci';
|
||||
import { StructureSelection } from '../../mol-model/structure';
|
||||
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
@@ -28,8 +28,8 @@ type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: bo
|
||||
class BasicWrapper {
|
||||
plugin: PluginUIContext;
|
||||
|
||||
init(target: string | HTMLElement) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
async init(target: string | HTMLElement) {
|
||||
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginUISpec(),
|
||||
layout: {
|
||||
initial: {
|
||||
@@ -60,7 +60,7 @@ class BasicWrapper {
|
||||
params: { id: assemblyId }
|
||||
} : {
|
||||
name: 'model',
|
||||
params: { }
|
||||
params: {}
|
||||
},
|
||||
showUnitcell: false,
|
||||
representationPreset: 'auto'
|
||||
@@ -95,7 +95,7 @@ class BasicWrapper {
|
||||
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: { direction: 'forward' } } }); },
|
||||
stop: () => this.plugin.managers.animation.stop()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
coloring = {
|
||||
applyStripes: async () => {
|
||||
@@ -119,7 +119,7 @@ class BasicWrapper {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
interactivity = {
|
||||
highlightOn: () => {
|
||||
@@ -137,7 +137,7 @@ class BasicWrapper {
|
||||
clearHighlight: () => {
|
||||
this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tests = {
|
||||
staticSuperposition: async () => {
|
||||
@@ -168,7 +168,7 @@ class BasicWrapper {
|
||||
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-1' });
|
||||
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-2' });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
(window as any).BasicMolStarWrapper = new BasicWrapper();
|
||||
@@ -45,8 +45,9 @@
|
||||
<div id='controls'></div>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
LightingDemo.init('app')
|
||||
LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3)
|
||||
LightingDemo.init('app').then(() => {
|
||||
LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3);
|
||||
});
|
||||
|
||||
addHeader('Example PDB IDs');
|
||||
addControl('4KTC', () => LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3));
|
||||
@@ -83,5 +84,6 @@
|
||||
$('controls').appendChild(h);
|
||||
}
|
||||
</script>
|
||||
<!-- __MOLSTAR_ANALYTICS__ -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Canvas3DProps } from '../../mol-canvas3d/canvas3d';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
@@ -17,44 +17,46 @@ require('mol-plugin-ui/skin/light.scss');
|
||||
|
||||
type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: boolean, assemblyId?: string }
|
||||
|
||||
type _Preset = Pick<Canvas3DProps, 'multiSample' | 'postprocessing' | 'renderer'>
|
||||
type _Preset = Pick<Canvas3DProps, 'postprocessing' | 'renderer'>
|
||||
type Preset = { [K in keyof _Preset]: Partial<_Preset[K]> }
|
||||
|
||||
const Canvas3DPresets = {
|
||||
illustrative: <Preset> {
|
||||
multiSample: {
|
||||
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.1, color: Color(0x000000) } }
|
||||
},
|
||||
renderer: {
|
||||
style: { name: 'flat', params: {} }
|
||||
illustrative: {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000) } }
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 1.0,
|
||||
light: []
|
||||
}
|
||||
}
|
||||
},
|
||||
occlusion: <Preset> {
|
||||
multiSample: {
|
||||
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'off', params: { } }
|
||||
},
|
||||
renderer: {
|
||||
style: { name: 'matte', params: {} }
|
||||
occlusion: {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
|
||||
outline: { name: 'off', params: {} }
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
light: [{ inclination: 180, azimuth: 0, color: Color.fromNormalizedRgb(1.0, 1.0, 1.0),
|
||||
intensity: 0.6 }]
|
||||
}
|
||||
}
|
||||
},
|
||||
standard: <Preset> {
|
||||
multiSample: {
|
||||
mode: 'off' as Canvas3DProps['multiSample']['mode']
|
||||
},
|
||||
postprocessing: {
|
||||
occlusion: { name: 'off', params: { } },
|
||||
outline: { name: 'off', params: { } }
|
||||
},
|
||||
renderer: {
|
||||
style: { name: 'matte', params: {} }
|
||||
standard: {
|
||||
canvas3d: <Preset>{
|
||||
postprocessing: {
|
||||
occlusion: { name: 'off', params: {} },
|
||||
outline: { name: 'off', params: {} }
|
||||
},
|
||||
renderer: {
|
||||
ambientIntensity: 0.4,
|
||||
light: [{ inclination: 180, azimuth: 0, color: Color.fromNormalizedRgb(1.0, 1.0, 1.0),
|
||||
intensity: 0.6 }]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -69,8 +71,8 @@ class LightingDemo {
|
||||
private bias = 1.1;
|
||||
private preset: Canvas3DPreset = 'illustrative';
|
||||
|
||||
init(target: string | HTMLElement) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
async init(target: string | HTMLElement) {
|
||||
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginUISpec(),
|
||||
layout: {
|
||||
initial: {
|
||||
@@ -88,25 +90,23 @@ class LightingDemo {
|
||||
|
||||
setPreset(preset: Canvas3DPreset) {
|
||||
const props = Canvas3DPresets[preset];
|
||||
if (props.postprocessing.occlusion?.name === 'on') {
|
||||
props.postprocessing.occlusion.params.radius = this.radius;
|
||||
props.postprocessing.occlusion.params.bias = this.bias;
|
||||
if (props.canvas3d.postprocessing.occlusion?.name === 'on') {
|
||||
props.canvas3d.postprocessing.occlusion.params.radius = this.radius;
|
||||
props.canvas3d.postprocessing.occlusion.params.bias = this.bias;
|
||||
}
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
|
||||
...props,
|
||||
multiSample: {
|
||||
...this.plugin.canvas3d!.props.multiSample,
|
||||
...props.multiSample
|
||||
},
|
||||
renderer: {
|
||||
...this.plugin.canvas3d!.props.renderer,
|
||||
...props.renderer
|
||||
},
|
||||
postprocessing: {
|
||||
...this.plugin.canvas3d!.props.postprocessing,
|
||||
...props.postprocessing
|
||||
},
|
||||
} });
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, {
|
||||
settings: {
|
||||
...props,
|
||||
renderer: {
|
||||
...this.plugin.canvas3d!.props.renderer,
|
||||
...props.canvas3d.renderer
|
||||
},
|
||||
postprocessing: {
|
||||
...this.plugin.canvas3d!.props.postprocessing,
|
||||
...props.canvas3d.postprocessing
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async load({ url, format = 'mmcif', isBinary = true, assemblyId = '' }: LoadParams, radius: number, bias: number) {
|
||||
@@ -115,7 +115,7 @@ class LightingDemo {
|
||||
const data = await this.plugin.builders.data.download({ url: Asset.Url(url), isBinary }, { state: { isGhost: true } });
|
||||
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
|
||||
const model = await this.plugin.builders.structure.createModel(trajectory);
|
||||
const structure = await this.plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : { name: 'model', params: { } });
|
||||
const structure = await this.plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : { name: 'model', params: {} });
|
||||
|
||||
const polymer = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'polymer');
|
||||
if (polymer) await this.plugin.builders.structure.representation.addRepresentation(polymer, { type: 'spacefill', color: 'illustrative' });
|
||||
|
||||
@@ -103,10 +103,11 @@
|
||||
|
||||
PluginWrapper.init('app' /** or document.getElementById('app') */, {
|
||||
customColorList: CustomColors
|
||||
}).then(() => {
|
||||
PluginWrapper.setBackground(0xffffff);
|
||||
loadAndSnapshot({ url: url, format: format, isBinary: isBinary, assemblyId: assemblyId, representationStyle: representationStyle });
|
||||
PluginWrapper.toggleSpin();
|
||||
});
|
||||
PluginWrapper.setBackground(0xffffff);
|
||||
loadAndSnapshot({ url: url, format: format, isBinary: isBinary, assemblyId: assemblyId, representationStyle: representationStyle });
|
||||
PluginWrapper.toggleSpin();
|
||||
|
||||
PluginWrapper.events.modelInfo.subscribe(function (info) {
|
||||
console.log('Model Info', info);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/mod
|
||||
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
|
||||
import { PluginStateObject, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { createPlugin } from '../../mol-plugin-ui';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { CreateVolumeStreamingInfo, InitVolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
|
||||
@@ -43,10 +43,10 @@ class MolStarProteopediaWrapper {
|
||||
|
||||
plugin: PluginUIContext;
|
||||
|
||||
init(target: string | HTMLElement, options?: {
|
||||
async init(target: string | HTMLElement, options?: {
|
||||
customColorList?: number[]
|
||||
}) {
|
||||
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
|
||||
...DefaultPluginUISpec(),
|
||||
animations: [
|
||||
AnimateModelIndex
|
||||
@@ -95,7 +95,7 @@ class MolStarProteopediaWrapper {
|
||||
params: { id: assemblyId }
|
||||
} : {
|
||||
name: 'model' as const,
|
||||
params: { }
|
||||
params: {}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,7 +113,7 @@ class MolStarProteopediaWrapper {
|
||||
const structure = this.getObj<PluginStateObject.Molecule.Structure>(StateElements.Assembly);
|
||||
if (!structure) return;
|
||||
|
||||
const style = _style || { };
|
||||
const style = _style || {};
|
||||
|
||||
const update = this.state.build();
|
||||
|
||||
@@ -229,7 +229,7 @@ class MolStarProteopediaWrapper {
|
||||
params: { id: asmId }
|
||||
} : {
|
||||
name: 'model' as const,
|
||||
params: { }
|
||||
params: {}
|
||||
}
|
||||
};
|
||||
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));
|
||||
@@ -269,8 +269,8 @@ class MolStarProteopediaWrapper {
|
||||
|
||||
camera = {
|
||||
toggleSpin: () => this.toggleSpin(),
|
||||
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, { })
|
||||
}
|
||||
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, {})
|
||||
};
|
||||
|
||||
private animateModelIndexTargetFps() {
|
||||
return Math.max(1, this.animate.modelIndex.targetFps | 0);
|
||||
@@ -285,7 +285,7 @@ class MolStarProteopediaWrapper {
|
||||
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: { direction: 'forward' } } }); },
|
||||
stop: () => this.plugin.managers.animation.stop()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
coloring = {
|
||||
evolutionaryConservation: async (params?: { sequence?: boolean, het?: boolean, keepStyle?: boolean }) => {
|
||||
@@ -306,7 +306,7 @@ class MolStarProteopediaWrapper {
|
||||
|
||||
await PluginCommands.State.Update(this.plugin, { state, tree });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private experimentalDataElement?: Element = void 0;
|
||||
experimentalData = {
|
||||
@@ -330,17 +330,17 @@ class MolStarProteopediaWrapper {
|
||||
this.experimentalDataElement = void 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
hetGroups = {
|
||||
reset: () => {
|
||||
const update = this.state.build().delete(StateElements.HetGroupFocusGroup);
|
||||
PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
|
||||
PluginCommands.Camera.Reset(this.plugin, { });
|
||||
PluginCommands.Camera.Reset(this.plugin, {});
|
||||
},
|
||||
focusFirst: async (compId: string, options?: { hideLabels: boolean, doNotLabelWaters: boolean }) => {
|
||||
if (!this.state.transforms.has(StateElements.Assembly)) return;
|
||||
await PluginCommands.Camera.Reset(this.plugin, { });
|
||||
await PluginCommands.Camera.Reset(this.plugin, {});
|
||||
|
||||
const update = this.state.build();
|
||||
|
||||
@@ -397,7 +397,7 @@ class MolStarProteopediaWrapper {
|
||||
const snapshot = this.plugin.canvas3d!.camera.getFocus(sphere.center, radius);
|
||||
PluginCommands.Camera.SetSnapshot(this.plugin, { snapshot, durationMs: 250 });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
snapshot = {
|
||||
get: (params?: PluginState.SnapshotParams) => {
|
||||
@@ -420,7 +420,7 @@ class MolStarProteopediaWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
(window as any).MolStarProteopediaWrapper = MolStarProteopediaWrapper;
|
||||
@@ -166,7 +166,6 @@ export const CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
|
||||
from: PluginStateObject.Volume.Data,
|
||||
to: PluginStateObject.Volume.Representation3D,
|
||||
params: {
|
||||
directVolume: PD.Boolean(false),
|
||||
relativeIsovalue: PD.Numeric(1, { min: 0.01, max: 5, step: 0.01 }),
|
||||
kind: PD.Select<'positive' | 'negative'>('positive', [['positive', 'Positive'], ['negative', 'Negative']]),
|
||||
color: PD.Color(ColorNames.blue),
|
||||
@@ -217,19 +216,7 @@ function volumeParams(plugin: PluginContext, volume: PluginStateObject.Volume.Da
|
||||
|
||||
const value = isovalues[params.kind];
|
||||
|
||||
return createVolumeRepresentationParams(plugin, volume.data, params.directVolume ? {
|
||||
type: 'direct-volume',
|
||||
typeParams: {
|
||||
alpha: params.alpha,
|
||||
renderMode: {
|
||||
name: 'isosurface',
|
||||
params: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, singleLayer: false }
|
||||
},
|
||||
xrayShaded: params.xrayShaded
|
||||
},
|
||||
color: 'uniform',
|
||||
colorParams: { value: params.color }
|
||||
} : {
|
||||
return createVolumeRepresentationParams(plugin, volume.data, {
|
||||
type: 'isosurface',
|
||||
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded, tryUseGpu: params.tryUseGpu },
|
||||
color: 'uniform',
|
||||
|
||||
@@ -30,7 +30,7 @@ export const ANVILMembraneOrientation = PluginBehavior.create<{ autoAttach: bool
|
||||
description: 'Data calculated with ANVIL algorithm.'
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
|
||||
private provider = MembraneOrientationProvider
|
||||
private provider = MembraneOrientationProvider;
|
||||
|
||||
register(): void {
|
||||
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
|
||||
|
||||
@@ -66,7 +66,7 @@ export const DnatcoConfalPyramids = PluginBehavior.create<{ autoAttach: boolean,
|
||||
/* TODO: Implement this */
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
register(): void {
|
||||
this.ctx.customModelProperties.register(this.provider, this.params.autoAttach);
|
||||
|
||||
@@ -114,7 +114,7 @@ export namespace ConfalPyramidsUtil {
|
||||
this.modelNum = unit.model.modelNum;
|
||||
}
|
||||
|
||||
protected readonly data: CPT.PyramidsData
|
||||
protected readonly data: CPT.PyramidsData;
|
||||
protected readonly hasMultipleModels: boolean;
|
||||
protected readonly entryId: string;
|
||||
protected readonly modelNum: number;
|
||||
|
||||
@@ -29,7 +29,7 @@ export const GeometryParams = {
|
||||
export class GeometryControls extends PluginComponent {
|
||||
readonly behaviors = {
|
||||
params: this.ev.behavior<PD.Values<typeof GeometryParams>>(PD.getDefaultValues(GeometryParams))
|
||||
}
|
||||
};
|
||||
|
||||
private getFilename() {
|
||||
const models = this.plugin.state.data.select(StateSelection.Generators.rootsOfType(PluginStateObject.Molecule.Model)).map(s => s.obj!.data);
|
||||
|
||||
@@ -85,7 +85,7 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
|
||||
} finally {
|
||||
this.setState({ busy: false });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
viewInAR = async () => {
|
||||
try {
|
||||
@@ -104,5 +104,5 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
|
||||
} finally {
|
||||
this.setState({ busy: false });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
212
src/extensions/model-archive/quality-assessment/behavior.ts
Normal file
212
src/extensions/model-archive/quality-assessment/behavior.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { PluginBehavior } from '../../../mol-plugin/behavior/behavior';
|
||||
import { Loci } from '../../../mol-model/loci';
|
||||
import { DefaultQueryRuntimeTable } from '../../../mol-script/runtime/query/compiler';
|
||||
import { PLDDTConfidenceColorThemeProvider } from './color/plddt';
|
||||
import { QualityAssessment, QualityAssessmentProvider } from './prop';
|
||||
import { StructureSelectionCategory, StructureSelectionQuery } from '../../../mol-plugin-state/helpers/structure-selection-query';
|
||||
import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
|
||||
import { OrderedSet } from '../../../mol-data/int';
|
||||
import { cantorPairing } from '../../../mol-data/util';
|
||||
import { QmeanScoreColorThemeProvider } from './color/qmean';
|
||||
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { StateObjectRef } from '../../../mol-state';
|
||||
|
||||
export const MAQualityAssessment = PluginBehavior.create<{ autoAttach: boolean, showTooltip: boolean }>({
|
||||
name: 'ma-quality-assessment-prop',
|
||||
category: 'custom-props',
|
||||
display: {
|
||||
name: 'Quality Assessment',
|
||||
description: 'Data included in Model Archive files.'
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
|
||||
private provider = QualityAssessmentProvider
|
||||
|
||||
private labelProvider = {
|
||||
label: (loci: Loci): string | undefined => {
|
||||
if (!this.params.showTooltip) return;
|
||||
return [
|
||||
plddtLabel(loci),
|
||||
qmeanLabel(loci),
|
||||
].filter(l => !!l).join('</br>');
|
||||
}
|
||||
}
|
||||
|
||||
register(): void {
|
||||
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
|
||||
|
||||
this.ctx.customModelProperties.register(this.provider, this.params.autoAttach);
|
||||
|
||||
this.ctx.managers.lociLabels.addProvider(this.labelProvider);
|
||||
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.add(PLDDTConfidenceColorThemeProvider);
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.add(QmeanScoreColorThemeProvider);
|
||||
|
||||
this.ctx.query.structure.registry.add(confidentPLDDT);
|
||||
|
||||
this.ctx.builders.structure.representation.registerPreset(QualityAssessmentPLDDTPreset);
|
||||
this.ctx.builders.structure.representation.registerPreset(QualityAssessmentQmeanPreset);
|
||||
}
|
||||
|
||||
update(p: { autoAttach: boolean, showTooltip: boolean }) {
|
||||
const updated = this.params.autoAttach !== p.autoAttach;
|
||||
this.params.autoAttach = p.autoAttach;
|
||||
this.params.showTooltip = p.showTooltip;
|
||||
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
|
||||
return updated;
|
||||
}
|
||||
|
||||
unregister() {
|
||||
DefaultQueryRuntimeTable.removeCustomProp(this.provider.descriptor);
|
||||
|
||||
this.ctx.customStructureProperties.unregister(this.provider.descriptor.name);
|
||||
|
||||
this.ctx.managers.lociLabels.removeProvider(this.labelProvider);
|
||||
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.remove(PLDDTConfidenceColorThemeProvider);
|
||||
this.ctx.representation.structure.themes.colorThemeRegistry.remove(QmeanScoreColorThemeProvider);
|
||||
|
||||
this.ctx.query.structure.registry.remove(confidentPLDDT);
|
||||
|
||||
this.ctx.builders.structure.representation.unregisterPreset(QualityAssessmentPLDDTPreset);
|
||||
this.ctx.builders.structure.representation.unregisterPreset(QualityAssessmentQmeanPreset);
|
||||
}
|
||||
},
|
||||
params: () => ({
|
||||
autoAttach: PD.Boolean(false),
|
||||
showTooltip: PD.Boolean(true),
|
||||
})
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
function plddtCategory(score: number) {
|
||||
if (score > 50 && score <= 70) return 'Low';
|
||||
if (score > 70 && score <= 90) return 'Confident';
|
||||
if (score > 90) return 'Very high';
|
||||
return 'Very low';
|
||||
}
|
||||
|
||||
function plddtLabel(loci: Loci): string | undefined {
|
||||
return metricLabel(loci, 'pLDDT', (scoreAvg: number, countInfo: string) => `pLDDT Score ${countInfo}: ${scoreAvg.toFixed(2)} <small>(${plddtCategory(scoreAvg)})</small>`);
|
||||
}
|
||||
|
||||
function qmeanLabel(loci: Loci): string | undefined {
|
||||
return metricLabel(loci, 'qmean', (scoreAvg: number, countInfo: string) => `QMEAN Score ${countInfo}: ${scoreAvg.toFixed(2)}`);
|
||||
}
|
||||
|
||||
function metricLabel(loci: Loci, name: 'qmean' | 'pLDDT', label: (scoreAvg: number, countInfo: string) => string): string | undefined {
|
||||
if (loci.kind === 'element-loci') {
|
||||
if (loci.elements.length === 0) return;
|
||||
|
||||
const seen = new Set<number>();
|
||||
const scoreSeen = new Set<number>();
|
||||
let scoreSum = 0;
|
||||
|
||||
for (const { indices, unit } of loci.elements) {
|
||||
const metric = QualityAssessmentProvider.get(unit.model).value?.[name];
|
||||
if (!metric) continue;
|
||||
|
||||
const residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index;
|
||||
const { elements } = unit;
|
||||
|
||||
OrderedSet.forEach(indices, idx => {
|
||||
const eI = elements[idx];
|
||||
const rI = residueIndex[eI];
|
||||
|
||||
const residueKey = cantorPairing(rI, unit.id);
|
||||
if (!seen.has(residueKey)) {
|
||||
const score = metric.get(residueIndex[eI]) ?? -1;
|
||||
if (score !== -1) {
|
||||
scoreSum += score;
|
||||
scoreSeen.add(residueKey);
|
||||
}
|
||||
seen.add(residueKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (seen.size === 0) return;
|
||||
|
||||
const summary: string[] = [];
|
||||
|
||||
if (scoreSeen.size) {
|
||||
const countInfo = `<small>(${scoreSeen.size} ${scoreSeen.size > 1 ? 'Residues avg.' : 'Residue'})</small>`;
|
||||
const scoreAvg = scoreSum / scoreSeen.size;
|
||||
summary.push(label(scoreAvg, countInfo));
|
||||
}
|
||||
|
||||
if (summary.length) {
|
||||
return summary.join('</br>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const confidentPLDDT = StructureSelectionQuery('Confident pLDDT (> 70)', MS.struct.modifier.union([
|
||||
MS.struct.modifier.wholeResidues([
|
||||
MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'residue-test': MS.core.rel.gr([QualityAssessment.symbols.pLDDT.symbol(), 70]),
|
||||
})
|
||||
])
|
||||
])
|
||||
]), {
|
||||
description: 'Select residues with a pLDDT > 70 (confident).',
|
||||
category: StructureSelectionCategory.Validation,
|
||||
ensureCustomProperties: async (ctx, structure) => {
|
||||
for (const m of structure.models) {
|
||||
await QualityAssessmentProvider.attach(ctx, m, void 0, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
export const QualityAssessmentPLDDTPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-structure-representation-ma-quality-assessment-plddt',
|
||||
display: {
|
||||
name: 'Quality Assessment (pLDDT)', group: 'Annotation',
|
||||
description: 'Color structure based on pLDDT Confidence.'
|
||||
},
|
||||
isApplicable(a) {
|
||||
return !!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'));
|
||||
},
|
||||
params: () => StructureRepresentationPresetProvider.CommonParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
const colorTheme = PLDDTConfidenceColorThemeProvider.name as any;
|
||||
return await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
|
||||
}
|
||||
});
|
||||
|
||||
export const QualityAssessmentQmeanPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-structure-representation-ma-quality-assessment-qmean',
|
||||
display: {
|
||||
name: 'Quality Assessment (QMEAN)', group: 'Annotation',
|
||||
description: 'Color structure based on QMEAN Score.'
|
||||
},
|
||||
isApplicable(a) {
|
||||
return !!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'));
|
||||
},
|
||||
params: () => StructureRepresentationPresetProvider.CommonParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
const colorTheme = QmeanScoreColorThemeProvider.name as any;
|
||||
return await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
|
||||
}
|
||||
});
|
||||
106
src/extensions/model-archive/quality-assessment/color/plddt.ts
Normal file
106
src/extensions/model-archive/quality-assessment/color/plddt.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Mandar Deshpande <mandar@ebi.ac.uk>
|
||||
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { QualityAssessment, QualityAssessmentProvider } from '../prop';
|
||||
import { Location } from '../../../../mol-model/location';
|
||||
import { Bond, StructureElement, Unit } from '../../../../mol-model/structure';
|
||||
import { ColorTheme, LocationColor } from '../../../../mol-theme/color';
|
||||
import { ThemeDataContext } from '../../../../mol-theme/theme';
|
||||
import { Color } from '../../../../mol-util/color';
|
||||
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
|
||||
import { CustomProperty } from '../../../../mol-model-props/common/custom-property';
|
||||
import { TableLegend } from '../../../../mol-util/legend';
|
||||
|
||||
const DefaultColor = Color(0xaaaaaa);
|
||||
const ConfidenceColors = {
|
||||
'No Score': DefaultColor,
|
||||
'Very Low': Color(0xff7d45),
|
||||
'Low': Color(0xffdb13),
|
||||
'Confident': Color(0x65cbf3),
|
||||
'Very High': Color(0x0053d6)
|
||||
};
|
||||
|
||||
const ConfidenceColorLegend = TableLegend(Object.entries(ConfidenceColors));
|
||||
|
||||
export function getPLDDTConfidenceColorThemeParams(ctx: ThemeDataContext) {
|
||||
return {};
|
||||
}
|
||||
export type PLDDTConfidenceColorThemeParams = ReturnType<typeof getPLDDTConfidenceColorThemeParams>
|
||||
|
||||
export function PLDDTConfidenceColorTheme(ctx: ThemeDataContext, props: PD.Values<PLDDTConfidenceColorThemeParams>): ColorTheme<PLDDTConfidenceColorThemeParams> {
|
||||
let color: LocationColor = () => DefaultColor;
|
||||
|
||||
if (ctx.structure) {
|
||||
const l = StructureElement.Location.create(ctx.structure.root);
|
||||
|
||||
const getColor = (location: StructureElement.Location): Color => {
|
||||
const { unit, element } = location;
|
||||
if (!Unit.isAtomic(unit)) return DefaultColor;
|
||||
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
|
||||
const score = qualityAssessment?.pLDDT?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
|
||||
if (score < 0) {
|
||||
return DefaultColor;
|
||||
} else if (score <= 50) {
|
||||
return Color(0xff7d45);
|
||||
} else if (score <= 70) {
|
||||
return Color(0xffdb13);
|
||||
} else if (score <= 90) {
|
||||
return Color(0x65cbf3);
|
||||
} else {
|
||||
return Color(0x0053d6);
|
||||
}
|
||||
};
|
||||
|
||||
color = (location: Location) => {
|
||||
if (StructureElement.Location.is(location)) {
|
||||
return getColor(location);
|
||||
} else if (Bond.isLocation(location)) {
|
||||
l.unit = location.aUnit;
|
||||
l.element = location.aUnit.elements[location.aIndex];
|
||||
return getColor(l);
|
||||
}
|
||||
return DefaultColor;
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
factory: PLDDTConfidenceColorTheme,
|
||||
granularity: 'group',
|
||||
preferSmoothing: true,
|
||||
color,
|
||||
props,
|
||||
description: 'Assigns residue colors according to the pLDDT Confidence score.',
|
||||
legend: ConfidenceColorLegend
|
||||
};
|
||||
}
|
||||
|
||||
export const PLDDTConfidenceColorThemeProvider: ColorTheme.Provider<PLDDTConfidenceColorThemeParams, 'plddt-confidence'> = {
|
||||
name: 'plddt-confidence',
|
||||
label: 'pLDDT Confidence',
|
||||
category: ColorTheme.Category.Validation,
|
||||
factory: PLDDTConfidenceColorTheme,
|
||||
getParams: getPLDDTConfidenceColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(getPLDDTConfidenceColorThemeParams({})),
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure?.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')),
|
||||
ensureCustomProperties: {
|
||||
attach: async (ctx: CustomProperty.Context, data: ThemeDataContext) => {
|
||||
if (data.structure) {
|
||||
for (const m of data.structure.models) {
|
||||
await QualityAssessmentProvider.attach(ctx, m, void 0, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
detach: async (data: ThemeDataContext) => {
|
||||
if (data.structure) {
|
||||
for (const m of data.structure.models) {
|
||||
QualityAssessmentProvider.ref(m, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { QualityAssessment, QualityAssessmentProvider } from '../prop';
|
||||
import { Location } from '../../../../mol-model/location';
|
||||
import { Bond, StructureElement, Unit } from '../../../../mol-model/structure';
|
||||
import { ColorTheme, LocationColor } from '../../../../mol-theme/color';
|
||||
import { ThemeDataContext } from '../../../../mol-theme/theme';
|
||||
import { Color, ColorScale } from '../../../../mol-util/color';
|
||||
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
|
||||
import { CustomProperty } from '../../../../mol-model-props/common/custom-property';
|
||||
|
||||
const DefaultColor = Color(0xaaaaaa);
|
||||
|
||||
export function getQmeanScoreColorThemeParams(ctx: ThemeDataContext) {
|
||||
return {};
|
||||
}
|
||||
export type QmeanScoreColorThemeParams = ReturnType<typeof getQmeanScoreColorThemeParams>
|
||||
|
||||
export function QmeanScoreColorTheme(ctx: ThemeDataContext, props: PD.Values<QmeanScoreColorThemeParams>): ColorTheme<QmeanScoreColorThemeParams> {
|
||||
let color: LocationColor = () => DefaultColor;
|
||||
|
||||
const scale = ColorScale.create({
|
||||
domain: [0, 1],
|
||||
listOrName: [
|
||||
[Color(0xFF5000), 0.5], [Color(0x025AFD), 1.0]
|
||||
]
|
||||
});
|
||||
|
||||
if (ctx.structure) {
|
||||
const l = StructureElement.Location.create(ctx.structure.root);
|
||||
|
||||
const getColor = (location: StructureElement.Location): Color => {
|
||||
const { unit, element } = location;
|
||||
if (!Unit.isAtomic(unit)) return DefaultColor;
|
||||
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
|
||||
const score = qualityAssessment?.qmean?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
|
||||
if (score < 0) {
|
||||
return DefaultColor;
|
||||
} else {
|
||||
return scale.color(score);
|
||||
}
|
||||
};
|
||||
|
||||
color = (location: Location) => {
|
||||
if (StructureElement.Location.is(location)) {
|
||||
return getColor(location);
|
||||
} else if (Bond.isLocation(location)) {
|
||||
l.unit = location.aUnit;
|
||||
l.element = location.aUnit.elements[location.aIndex];
|
||||
return getColor(l);
|
||||
}
|
||||
return DefaultColor;
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
factory: QmeanScoreColorTheme,
|
||||
granularity: 'group',
|
||||
preferSmoothing: true,
|
||||
color,
|
||||
props,
|
||||
description: 'Assigns residue colors according to the QMEAN score.',
|
||||
legend: scale.legend
|
||||
};
|
||||
}
|
||||
|
||||
export const QmeanScoreColorThemeProvider: ColorTheme.Provider<QmeanScoreColorThemeParams, 'qmean-score'> = {
|
||||
name: 'qmean-score',
|
||||
label: 'QMEAN Score',
|
||||
category: ColorTheme.Category.Validation,
|
||||
factory: QmeanScoreColorTheme,
|
||||
getParams: getQmeanScoreColorThemeParams,
|
||||
defaultValues: PD.getDefaultValues(getQmeanScoreColorThemeParams({})),
|
||||
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure?.models.some(m => QualityAssessment.isApplicable(m, 'qmean')),
|
||||
ensureCustomProperties: {
|
||||
attach: async (ctx: CustomProperty.Context, data: ThemeDataContext) => {
|
||||
if (data.structure) {
|
||||
for (const m of data.structure.models) {
|
||||
await QualityAssessmentProvider.attach(ctx, m, void 0, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
detach: async (data: ThemeDataContext) => {
|
||||
if (data.structure) {
|
||||
for (const m of data.structure.models) {
|
||||
QualityAssessmentProvider.ref(m, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
131
src/extensions/model-archive/quality-assessment/prop.ts
Normal file
131
src/extensions/model-archive/quality-assessment/prop.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { Unit } from '../../../mol-model/structure';
|
||||
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
|
||||
import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
|
||||
import { Model, ResidueIndex } from '../../../mol-model/structure/model';
|
||||
import { QuerySymbolRuntime } from '../../../mol-script/runtime/query/compiler';
|
||||
import { CustomPropSymbol } from '../../../mol-script/language/symbol';
|
||||
import { Type } from '../../../mol-script/language/type';
|
||||
import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
|
||||
import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
|
||||
|
||||
export { QualityAssessment };
|
||||
|
||||
interface QualityAssessment {
|
||||
localMetrics: Map<string, Map<ResidueIndex, number>>
|
||||
pLDDT?: Map<ResidueIndex, number>
|
||||
qmean?: Map<ResidueIndex, number>
|
||||
}
|
||||
|
||||
namespace QualityAssessment {
|
||||
const Empty = {
|
||||
value: {
|
||||
localMetrics: new Map()
|
||||
}
|
||||
};
|
||||
|
||||
export function isApplicable(model?: Model, localMetricName?: 'pLDDT' | 'qmean'): boolean {
|
||||
if (!model || !MmcifFormat.is(model.sourceData)) return false;
|
||||
const { db } = model.sourceData.data;
|
||||
const hasLocalMetric = (
|
||||
db.ma_qa_metric.id.isDefined &&
|
||||
db.ma_qa_metric_local.ordinal_id.isDefined
|
||||
);
|
||||
if (localMetricName && hasLocalMetric) {
|
||||
for (let i = 0, il = db.ma_qa_metric._rowCount; i < il; i++) {
|
||||
if (db.ma_qa_metric.mode.value(i) !== 'local') continue;
|
||||
if (localMetricName === db.ma_qa_metric.name.value(i)) return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return hasLocalMetric;
|
||||
}
|
||||
}
|
||||
|
||||
export async function obtain(ctx: CustomProperty.Context, model: Model, props: QualityAssessmentProps): Promise<CustomProperty.Data<QualityAssessment>> {
|
||||
if (!model || !MmcifFormat.is(model.sourceData)) return Empty;
|
||||
const { ma_qa_metric, ma_qa_metric_local } = model.sourceData.data.db;
|
||||
const { model_id, label_asym_id, label_seq_id, metric_id, metric_value } = ma_qa_metric_local;
|
||||
const { index } = model.atomicHierarchy;
|
||||
|
||||
// for simplicity we assume names in ma_qa_metric for mode 'local' are unique
|
||||
const localMetrics = new Map<string, Map<ResidueIndex, number>>();
|
||||
const localNames = new Map<number, string>();
|
||||
|
||||
for (let i = 0, il = ma_qa_metric._rowCount; i < il; i++) {
|
||||
if (ma_qa_metric.mode.value(i) !== 'local') continue;
|
||||
|
||||
const name = ma_qa_metric.name.value(i);
|
||||
if (localMetrics.has(name)) {
|
||||
console.warn(`local ma_qa_metric with name '${name}' already added`);
|
||||
continue;
|
||||
}
|
||||
|
||||
localMetrics.set(name, new Map());
|
||||
localNames.set(ma_qa_metric.id.value(i), name);
|
||||
}
|
||||
|
||||
for (let i = 0, il = ma_qa_metric_local._rowCount; i < il; i++) {
|
||||
if (model_id.value(i) !== model.modelNum) continue;
|
||||
|
||||
const labelAsymId = label_asym_id.value(i);
|
||||
const entityIndex = index.findEntity(labelAsymId);
|
||||
const rI = index.findResidue(model.entities.data.id.value(entityIndex), labelAsymId, label_seq_id.value(i));
|
||||
const name = localNames.get(metric_id.value(i))!;
|
||||
localMetrics.get(name)!.set(rI, metric_value.value(i));
|
||||
}
|
||||
|
||||
return {
|
||||
value: {
|
||||
localMetrics,
|
||||
pLDDT: localMetrics.get('pLDDT'),
|
||||
qmean: localMetrics.get('qmean'),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const symbols = {
|
||||
pLDDT: QuerySymbolRuntime.Dynamic(CustomPropSymbol('ma', 'quality-assessment.pLDDT', Type.Num),
|
||||
ctx => {
|
||||
const { unit, element } = ctx.element;
|
||||
if (!Unit.isAtomic(unit)) return -1;
|
||||
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
|
||||
return qualityAssessment?.pLDDT?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
|
||||
}
|
||||
),
|
||||
qmean: QuerySymbolRuntime.Dynamic(CustomPropSymbol('ma', 'quality-assessment.qmean', Type.Num),
|
||||
ctx => {
|
||||
const { unit, element } = ctx.element;
|
||||
if (!Unit.isAtomic(unit)) return -1;
|
||||
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
|
||||
return qualityAssessment?.qmean?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
|
||||
}
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export const QualityAssessmentParams = { };
|
||||
export type QualityAssessmentParams = typeof QualityAssessmentParams
|
||||
export type QualityAssessmentProps = PD.Values<QualityAssessmentParams>
|
||||
|
||||
export const QualityAssessmentProvider: CustomModelProperty.Provider<QualityAssessmentParams, QualityAssessment> = CustomModelProperty.createProvider({
|
||||
label: 'QualityAssessment',
|
||||
descriptor: CustomPropertyDescriptor({
|
||||
name: 'ma_quality_assessment',
|
||||
symbols: QualityAssessment.symbols
|
||||
}),
|
||||
type: 'static',
|
||||
defaultParams: QualityAssessmentParams,
|
||||
getParams: (data: Model) => QualityAssessmentParams,
|
||||
isApplicable: (data: Model) => QualityAssessment.isApplicable(data),
|
||||
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<QualityAssessmentProps>) => {
|
||||
const p = { ...PD.getDefaultValues(QualityAssessmentParams), ...props };
|
||||
return await QualityAssessment.obtain(ctx, data, p);
|
||||
}
|
||||
});
|
||||
@@ -31,7 +31,7 @@ export class Mp4Controls extends PluginComponent {
|
||||
canApply: this.ev.behavior<PluginStateAnimation.CanApply>({ canApply: false }),
|
||||
info: this.ev.behavior<Mp4AnimationInfo>({ width: 0, height: 0 }),
|
||||
params: this.ev.behavior<PD.Values<typeof Mp4AnimationParams>>(PD.getDefaultValues(Mp4AnimationParams))
|
||||
}
|
||||
};
|
||||
|
||||
setCurrent(name?: string) {
|
||||
const anim = this.animations.find(a => a.name === name);
|
||||
@@ -125,17 +125,20 @@ export class Mp4Controls extends PluginComponent {
|
||||
this.subscribe(this.plugin.canvas3d?.resized!, () => this.syncInfo());
|
||||
this.subscribe(this.plugin.helpers.viewportScreenshot?.events.previewed!, () => this.syncInfo());
|
||||
|
||||
this.subscribe(this.plugin.behaviors.state.isBusy, b => {
|
||||
const anim = this.current;
|
||||
if (!b && anim) {
|
||||
this.behaviors.canApply.next(anim.anim.canApply?.(this.plugin) ?? { canApply: true });
|
||||
}
|
||||
});
|
||||
this.subscribe(this.plugin.behaviors.state.isBusy, b => this.updateCanApply(b));
|
||||
this.subscribe(this.plugin.managers.snapshot.events.changed, b => this.updateCanApply(b));
|
||||
|
||||
this.sync();
|
||||
this.syncInfo();
|
||||
}
|
||||
|
||||
private updateCanApply(b?: any) {
|
||||
const anim = this.current;
|
||||
if (!b && anim) {
|
||||
this.behaviors.canApply.next(anim.anim.canApply?.(this.plugin) ?? { canApply: true });
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private plugin: PluginContext) {
|
||||
super();
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ export class Mp4EncoderUI extends CollapsableControls<{}, State> {
|
||||
|
||||
save = () => {
|
||||
download(new Blob([this.state.data!.movie]), this.state.data!.filename);
|
||||
}
|
||||
};
|
||||
|
||||
generate = async () => {
|
||||
try {
|
||||
@@ -119,5 +119,5 @@ export class Mp4EncoderUI extends CollapsableControls<{}, State> {
|
||||
console.error(e);
|
||||
this.setState({ busy: false });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
|
||||
|
||||
private provider = StructureQualityReportProvider
|
||||
private provider = StructureQualityReportProvider;
|
||||
|
||||
private labelPDBeValidation = {
|
||||
label: (loci: Loci): string | undefined => {
|
||||
@@ -42,7 +42,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
|
||||
default: return void 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
register(): void {
|
||||
this.ctx.customModelProperties.register(this.provider, this.params.autoAttach);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace StructureQualityReport {
|
||||
}
|
||||
|
||||
export function isApplicable(model?: Model): boolean {
|
||||
return !!model && Model.isFromPdbArchive(model);
|
||||
return !!model && Model.hasPdbId(model);
|
||||
}
|
||||
|
||||
export const Schema = {
|
||||
|
||||
@@ -27,7 +27,7 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean
|
||||
description: 'Assembly Symmetry data calculated with BioJava, obtained via RCSB PDB.'
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
|
||||
private provider = AssemblySymmetryProvider
|
||||
private provider = AssemblySymmetryProvider;
|
||||
|
||||
register(): void {
|
||||
this.ctx.state.data.actions.add(InitAssemblySymmetry3D);
|
||||
|
||||
@@ -53,7 +53,7 @@ export namespace AssemblySymmetry {
|
||||
export function isApplicable(structure?: Structure): boolean {
|
||||
return (
|
||||
!!structure && structure.models.length === 1 &&
|
||||
Model.isFromPdbArchive(structure.models[0]) &&
|
||||
Model.hasPdbId(structure.models[0]) &&
|
||||
isBiologicalAssembly(structure)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ export class AssemblySymmetryControls extends CollapsableControls<{}, AssemblySy
|
||||
|
||||
paramsOnChange = (options: AssemblySymmetryProps) => {
|
||||
this.updateAssemblySymmetry(options);
|
||||
}
|
||||
};
|
||||
|
||||
get hasAssemblySymmetry3D() {
|
||||
return !this.pivot.cell.parent || !!StateSelection.findTagInSubtree(this.pivot.cell.parent.tree, this.pivot.cell.transform.ref, AssemblySymmetry.Tag.Representation);
|
||||
|
||||
@@ -30,7 +30,7 @@ export const RCSBValidationReport = PluginBehavior.create<{ autoAttach: boolean,
|
||||
description: 'Data from wwPDB Validation Report, obtained via RCSB PDB.'
|
||||
},
|
||||
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
|
||||
private provider = ValidationReportProvider
|
||||
private provider = ValidationReportProvider;
|
||||
|
||||
private labelProvider = {
|
||||
label: (loci: Loci): string | undefined => {
|
||||
@@ -41,7 +41,7 @@ export const RCSBValidationReport = PluginBehavior.create<{ autoAttach: boolean,
|
||||
randomCoilIndexLabel(loci)
|
||||
].filter(l => !!l).join('</br>');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
register(): void {
|
||||
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace ValidationReport {
|
||||
}
|
||||
|
||||
export function isApplicable(model?: Model): boolean {
|
||||
return !!model && Model.isFromPdbArchive(model);
|
||||
return !!model && Model.hasPdbId(model);
|
||||
}
|
||||
|
||||
export function fromXml(xml: XMLDocument, model: Model): ValidationReport {
|
||||
|
||||
@@ -37,7 +37,7 @@ class Camera implements ICamera {
|
||||
readonly projectionView: Mat4 = Mat4.identity();
|
||||
readonly inverseProjectionView: Mat4 = Mat4.identity();
|
||||
|
||||
private pixelScale: number
|
||||
private pixelScale: number;
|
||||
get pixelRatio() {
|
||||
const dpr = (typeof window !== 'undefined') ? window.devicePixelRatio : 1;
|
||||
return dpr * this.pixelScale;
|
||||
@@ -47,11 +47,11 @@ class Camera implements ICamera {
|
||||
readonly state: Readonly<Camera.Snapshot> = Camera.createDefaultSnapshot();
|
||||
readonly viewOffset = Camera.ViewOffset();
|
||||
|
||||
near = 1
|
||||
far = 10000
|
||||
fogNear = 5000
|
||||
fogFar = 10000
|
||||
zoom = 1
|
||||
near = 1;
|
||||
far = 10000;
|
||||
fogNear = 5000;
|
||||
fogFar = 10000;
|
||||
zoom = 1;
|
||||
|
||||
readonly transition: CameraTransitionManager = new CameraTransitionManager(this);
|
||||
readonly stateChanged = new BehaviorSubject<Partial<Camera.Snapshot>>(this.state);
|
||||
|
||||
@@ -33,7 +33,7 @@ class StereoCamera {
|
||||
return this.parent.viewOffset;
|
||||
}
|
||||
|
||||
private props: StereoCameraProps
|
||||
private props: StereoCameraProps;
|
||||
|
||||
constructor(private parent: Camera, props: Partial<StereoCameraProps> = {}) {
|
||||
this.props = { ...DefaultStereoCameraProps, ...props };
|
||||
|
||||
@@ -395,7 +395,11 @@ namespace Canvas3D {
|
||||
}
|
||||
|
||||
if (MultiSamplePass.isEnabled(p.multiSample)) {
|
||||
multiSampleHelper.render(renderer, cam, scene, helper, true, p.transparentBackground, p);
|
||||
if (!cameraChanged) {
|
||||
while (!multiSampleHelper.render(renderer, cam, scene, helper, true, p.transparentBackground, p));
|
||||
} else {
|
||||
multiSampleHelper.render(renderer, cam, scene, helper, true, p.transparentBackground, p);
|
||||
}
|
||||
} else {
|
||||
passes.draw.render(renderer, cam, scene, helper, true, p.transparentBackground, p.postprocessing, p.marking);
|
||||
}
|
||||
@@ -514,7 +518,7 @@ namespace Canvas3D {
|
||||
|
||||
if (camera.transition.inTransition || nextCameraResetSnapshot) return false;
|
||||
|
||||
let cameraSphereOverlapsNone = true;
|
||||
let cameraSphereOverlapsNone = true, isEmpty = true;
|
||||
Sphere3D.set(cameraSphere, camera.state.target, camera.state.radius);
|
||||
|
||||
// check if any renderable has moved outside of the old bounding sphere
|
||||
@@ -525,12 +529,13 @@ namespace Canvas3D {
|
||||
const b = r.values.boundingSphere.ref.value;
|
||||
if (!b.radius) continue;
|
||||
|
||||
isEmpty = false;
|
||||
const cameraDist = Vec3.distance(cameraSphere.center, b.center);
|
||||
if ((cameraDist > cameraSphere.radius || cameraDist > b.radius || b.radius > camera.state.radiusMax) && !Sphere3D.includes(oldBoundingSphereVisible, b)) return true;
|
||||
if (Sphere3D.overlaps(cameraSphere, b)) cameraSphereOverlapsNone = false;
|
||||
}
|
||||
|
||||
return cameraSphereOverlapsNone;
|
||||
return cameraSphereOverlapsNone || (!isEmpty && cameraSphere.radius <= 0.1);
|
||||
}
|
||||
|
||||
const sceneCommitTimeoutMs = 250;
|
||||
|
||||
@@ -31,14 +31,14 @@ export type DebugHelperProps = PD.Values<DebugHelperParams>
|
||||
type BoundingSphereData = { boundingSphere: Sphere3D, renderObject: GraphicsRenderObject, mesh: Mesh }
|
||||
|
||||
export class BoundingSphereHelper {
|
||||
readonly scene: Scene
|
||||
readonly scene: Scene;
|
||||
|
||||
private readonly parent: Scene
|
||||
private _props: DebugHelperProps
|
||||
private objectsData = new Map<GraphicsRenderObject, BoundingSphereData>()
|
||||
private instancesData = new Map<GraphicsRenderObject, BoundingSphereData>()
|
||||
private sceneData: BoundingSphereData | undefined
|
||||
private visibleSceneData: BoundingSphereData | undefined
|
||||
private readonly parent: Scene;
|
||||
private _props: DebugHelperProps;
|
||||
private objectsData = new Map<GraphicsRenderObject, BoundingSphereData>();
|
||||
private instancesData = new Map<GraphicsRenderObject, BoundingSphereData>();
|
||||
private sceneData: BoundingSphereData | undefined;
|
||||
private visibleSceneData: BoundingSphereData | undefined;
|
||||
|
||||
constructor(ctx: WebGLContext, parent: Scene, props: Partial<DebugHelperProps>) {
|
||||
this.scene = Scene.create(ctx);
|
||||
|
||||
@@ -49,13 +49,13 @@ export type CameraHelperParams = typeof CameraHelperParams
|
||||
export type CameraHelperProps = PD.Values<CameraHelperParams>
|
||||
|
||||
export class CameraHelper {
|
||||
scene: Scene
|
||||
camera: Camera
|
||||
scene: Scene;
|
||||
camera: Camera;
|
||||
props: CameraHelperProps = {
|
||||
axes: { name: 'off', params: {} }
|
||||
}
|
||||
};
|
||||
|
||||
private renderObject: GraphicsRenderObject | undefined
|
||||
private renderObject: GraphicsRenderObject | undefined;
|
||||
|
||||
constructor(private webgl: WebGLContext, props: Partial<CameraHelperProps> = {}) {
|
||||
this.scene = Scene.create(webgl);
|
||||
@@ -109,7 +109,7 @@ export class CameraHelper {
|
||||
if (apply(Interval.ofSingleton(idx))) changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
};
|
||||
|
||||
mark(loci: Loci, action: MarkerAction) {
|
||||
if (!MarkerActions.is(MarkerActions.Highlighting, action)) return false;
|
||||
|
||||
@@ -47,12 +47,12 @@ export type HandleHelperParams = typeof HandleHelperParams
|
||||
export type HandleHelperProps = PD.Values<HandleHelperParams>
|
||||
|
||||
export class HandleHelper {
|
||||
scene: Scene
|
||||
scene: Scene;
|
||||
props: HandleHelperProps = {
|
||||
handle: { name: 'off', params: {} }
|
||||
}
|
||||
};
|
||||
|
||||
private renderObject: GraphicsRenderObject | undefined
|
||||
private renderObject: GraphicsRenderObject | undefined;
|
||||
|
||||
private _transform = Mat4();
|
||||
getBoundingSphere(out: Sphere3D, instanceId: number) {
|
||||
@@ -117,7 +117,7 @@ export class HandleHelper {
|
||||
if (apply(Interval.ofSingleton(idx))) changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
};
|
||||
|
||||
mark(loci: Loci, action: MarkerAction) {
|
||||
if (!MarkerActions.is(MarkerActions.Highlighting, action)) return false;
|
||||
|
||||
@@ -23,9 +23,9 @@ export type HelperProps = PD.Values<typeof HelperParams>
|
||||
|
||||
|
||||
export class Helper {
|
||||
readonly debug: BoundingSphereHelper
|
||||
readonly camera: CameraHelper
|
||||
readonly handle: HandleHelper
|
||||
readonly debug: BoundingSphereHelper;
|
||||
readonly camera: CameraHelper;
|
||||
readonly handle: HandleHelper;
|
||||
|
||||
constructor(webgl: WebGLContext, scene: Scene, props: Partial<HelperProps> = {}) {
|
||||
const p = { ...DefaultHelperProps, ...props };
|
||||
|
||||
@@ -54,27 +54,27 @@ function getDepthMergeRenderable(ctx: WebGLContext, depthTexturePrimitives: Text
|
||||
}
|
||||
|
||||
export class DrawPass {
|
||||
private readonly drawTarget: RenderTarget
|
||||
private readonly drawTarget: RenderTarget;
|
||||
|
||||
readonly colorTarget: RenderTarget
|
||||
readonly depthTexture: Texture
|
||||
readonly depthTexturePrimitives: Texture
|
||||
readonly colorTarget: RenderTarget;
|
||||
readonly depthTexture: Texture;
|
||||
readonly depthTexturePrimitives: Texture;
|
||||
|
||||
readonly packedDepth: boolean
|
||||
readonly packedDepth: boolean;
|
||||
|
||||
private depthTarget: RenderTarget
|
||||
private depthTargetPrimitives: RenderTarget | null
|
||||
private depthTargetVolumes: RenderTarget | null
|
||||
private depthTextureVolumes: Texture
|
||||
private depthMerge: DepthMergeRenderable
|
||||
private depthTarget: RenderTarget;
|
||||
private depthTargetPrimitives: RenderTarget | null;
|
||||
private depthTargetVolumes: RenderTarget | null;
|
||||
private depthTextureVolumes: Texture;
|
||||
private depthMerge: DepthMergeRenderable;
|
||||
|
||||
private copyFboTarget: CopyRenderable
|
||||
private copyFboPostprocessing: CopyRenderable
|
||||
private copyFboTarget: CopyRenderable;
|
||||
private copyFboPostprocessing: CopyRenderable;
|
||||
|
||||
private wboit: WboitPass | undefined
|
||||
private readonly marking: MarkingPass
|
||||
readonly postprocessing: PostprocessingPass
|
||||
private readonly antialiasing: AntialiasingPass
|
||||
private wboit: WboitPass | undefined;
|
||||
private readonly marking: MarkingPass;
|
||||
readonly postprocessing: PostprocessingPass;
|
||||
private readonly antialiasing: AntialiasingPass;
|
||||
|
||||
get wboitEnabled() {
|
||||
return !!this.wboit?.supported;
|
||||
|
||||
@@ -28,7 +28,7 @@ export const FxaaParams = {
|
||||
export type FxaaProps = PD.Values<typeof FxaaParams>
|
||||
|
||||
export class FxaaPass {
|
||||
private readonly renderable: FxaaRenderable
|
||||
private readonly renderable: FxaaRenderable;
|
||||
|
||||
constructor(private webgl: WebGLContext, input: Texture) {
|
||||
this.renderable = getFxaaRenderable(webgl, input);
|
||||
|
||||
@@ -30,19 +30,19 @@ export const ImageParams = {
|
||||
export type ImageProps = PD.Values<typeof ImageParams>
|
||||
|
||||
export class ImagePass {
|
||||
private _width = 0
|
||||
private _height = 0
|
||||
private _camera = new Camera()
|
||||
private _width = 0;
|
||||
private _height = 0;
|
||||
private _camera = new Camera();
|
||||
|
||||
readonly props: ImageProps
|
||||
readonly props: ImageProps;
|
||||
|
||||
private _colorTarget: RenderTarget
|
||||
private _colorTarget: RenderTarget;
|
||||
get colorTarget() { return this._colorTarget; }
|
||||
|
||||
private readonly drawPass: DrawPass
|
||||
private readonly multiSamplePass: MultiSamplePass
|
||||
private readonly multiSampleHelper: MultiSampleHelper
|
||||
private readonly helper: Helper
|
||||
private readonly drawPass: DrawPass;
|
||||
private readonly multiSamplePass: MultiSamplePass;
|
||||
private readonly multiSampleHelper: MultiSampleHelper;
|
||||
private readonly helper: Helper;
|
||||
|
||||
get width() { return this._width; }
|
||||
get height() { return this._height; }
|
||||
|
||||
@@ -36,12 +36,12 @@ export class MarkingPass {
|
||||
return props.enabled;
|
||||
}
|
||||
|
||||
readonly depthTarget: RenderTarget
|
||||
readonly maskTarget: RenderTarget
|
||||
private readonly edgesTarget: RenderTarget
|
||||
readonly depthTarget: RenderTarget;
|
||||
readonly maskTarget: RenderTarget;
|
||||
private readonly edgesTarget: RenderTarget;
|
||||
|
||||
private readonly edge: EdgeRenderable
|
||||
private readonly overlay: OverlayRenderable
|
||||
private readonly edge: EdgeRenderable;
|
||||
private readonly overlay: OverlayRenderable;
|
||||
|
||||
constructor(private webgl: WebGLContext, width: number, height: number) {
|
||||
this.depthTarget = webgl.createRenderTarget(width, height);
|
||||
|
||||
@@ -50,8 +50,8 @@ function getComposeRenderable(ctx: WebGLContext, colorTexture: Texture): Compose
|
||||
}
|
||||
|
||||
export const MultiSampleParams = {
|
||||
mode: PD.Select('off', [['off', 'Off'], ['on', 'On'], ['temporal', 'Temporal']]),
|
||||
sampleLevel: PD.Numeric(2, { min: 0, max: 5, step: 1 }),
|
||||
mode: PD.Select('temporal', [['off', 'Off'], ['on', 'On'], ['temporal', 'Temporal']]),
|
||||
sampleLevel: PD.Numeric(2, { min: 0, max: 5, step: 1 }, { description: 'Take level^2 samples.' }),
|
||||
};
|
||||
export type MultiSampleProps = PD.Values<typeof MultiSampleParams>
|
||||
|
||||
@@ -66,11 +66,11 @@ export class MultiSamplePass {
|
||||
return props.mode !== 'off';
|
||||
}
|
||||
|
||||
colorTarget: RenderTarget
|
||||
colorTarget: RenderTarget;
|
||||
|
||||
private composeTarget: RenderTarget
|
||||
private holdTarget: RenderTarget
|
||||
private compose: ComposeRenderable
|
||||
private composeTarget: RenderTarget;
|
||||
private holdTarget: RenderTarget;
|
||||
private compose: ComposeRenderable;
|
||||
|
||||
constructor(private webgl: WebGLContext, private drawPass: DrawPass) {
|
||||
const { colorBufferFloat, textureFloat, colorBufferHalfFloat, textureHalfFloat } = webgl.extensions;
|
||||
@@ -317,15 +317,17 @@ JitterVectors.forEach(offsetList => {
|
||||
});
|
||||
|
||||
export class MultiSampleHelper {
|
||||
private sampleIndex = -2
|
||||
private sampleIndex = -2;
|
||||
|
||||
update(changed: boolean, props: MultiSampleProps) {
|
||||
if (changed) this.sampleIndex = -1;
|
||||
return props.mode === 'temporal' ? this.sampleIndex !== -2 : false;
|
||||
}
|
||||
|
||||
/** Return `true` while more samples are needed */
|
||||
render(renderer: Renderer, camera: Camera | StereoCamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, transparentBackground: boolean, props: Props) {
|
||||
this.sampleIndex = this.multiSamplePass.render(this.sampleIndex, renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, props);
|
||||
return this.sampleIndex < 0;
|
||||
}
|
||||
|
||||
constructor(private multiSamplePass: MultiSamplePass) {
|
||||
|
||||
@@ -10,9 +10,9 @@ import { MultiSamplePass } from './multi-sample';
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
|
||||
export class Passes {
|
||||
readonly draw: DrawPass
|
||||
readonly pick: PickPass
|
||||
readonly multiSample: MultiSamplePass
|
||||
readonly draw: DrawPass;
|
||||
readonly pick: PickPass;
|
||||
readonly multiSample: MultiSamplePass;
|
||||
|
||||
constructor(private webgl: WebGLContext, attribs: Partial<{ pickScale: number, enableWboit: boolean }> = {}) {
|
||||
const { gl } = webgl;
|
||||
|
||||
@@ -25,13 +25,13 @@ const NullId = Math.pow(2, 24) - 2;
|
||||
export type PickData = { id: PickingId, position: Vec3 }
|
||||
|
||||
export class PickPass {
|
||||
readonly objectPickTarget: RenderTarget
|
||||
readonly instancePickTarget: RenderTarget
|
||||
readonly groupPickTarget: RenderTarget
|
||||
readonly depthPickTarget: RenderTarget
|
||||
readonly objectPickTarget: RenderTarget;
|
||||
readonly instancePickTarget: RenderTarget;
|
||||
readonly groupPickTarget: RenderTarget;
|
||||
readonly depthPickTarget: RenderTarget;
|
||||
|
||||
private pickWidth: number
|
||||
private pickHeight: number
|
||||
private pickWidth: number;
|
||||
private pickHeight: number;
|
||||
|
||||
constructor(private webgl: WebGLContext, private drawPass: DrawPass, readonly pickBaseScale: number) {
|
||||
const pickScale = pickBaseScale / webgl.pixelRatio;
|
||||
@@ -97,23 +97,23 @@ export class PickPass {
|
||||
}
|
||||
|
||||
export class PickHelper {
|
||||
dirty = true
|
||||
dirty = true;
|
||||
|
||||
private objectBuffer: Uint8Array
|
||||
private instanceBuffer: Uint8Array
|
||||
private groupBuffer: Uint8Array
|
||||
private depthBuffer: Uint8Array
|
||||
private objectBuffer: Uint8Array;
|
||||
private instanceBuffer: Uint8Array;
|
||||
private groupBuffer: Uint8Array;
|
||||
private depthBuffer: Uint8Array;
|
||||
|
||||
private viewport = Viewport()
|
||||
private viewport = Viewport();
|
||||
|
||||
private pickScale: number
|
||||
private pickX: number
|
||||
private pickY: number
|
||||
private pickWidth: number
|
||||
private pickHeight: number
|
||||
private halfPickWidth: number
|
||||
private pickScale: number;
|
||||
private pickX: number;
|
||||
private pickY: number;
|
||||
private pickWidth: number;
|
||||
private pickHeight: number;
|
||||
private halfPickWidth: number;
|
||||
|
||||
private spiral: [number, number][]
|
||||
private spiral: [number, number][];
|
||||
|
||||
private setupBuffers() {
|
||||
const bufferSize = this.pickWidth * this.pickHeight * 4;
|
||||
|
||||
@@ -271,29 +271,29 @@ export class PostprocessingPass {
|
||||
return props.occlusion.name === 'on' || props.outline.name === 'on';
|
||||
}
|
||||
|
||||
readonly target: RenderTarget
|
||||
readonly target: RenderTarget;
|
||||
|
||||
private readonly outlinesTarget: RenderTarget
|
||||
private readonly outlinesRenderable: OutlinesRenderable
|
||||
private readonly outlinesTarget: RenderTarget;
|
||||
private readonly outlinesRenderable: OutlinesRenderable;
|
||||
|
||||
private readonly randomHemisphereVector: Vec3[]
|
||||
private readonly ssaoFramebuffer: Framebuffer
|
||||
private readonly ssaoBlurFirstPassFramebuffer: Framebuffer
|
||||
private readonly ssaoBlurSecondPassFramebuffer: Framebuffer
|
||||
private readonly randomHemisphereVector: Vec3[];
|
||||
private readonly ssaoFramebuffer: Framebuffer;
|
||||
private readonly ssaoBlurFirstPassFramebuffer: Framebuffer;
|
||||
private readonly ssaoBlurSecondPassFramebuffer: Framebuffer;
|
||||
|
||||
private readonly ssaoDepthTexture: Texture
|
||||
private readonly ssaoDepthBlurProxyTexture: Texture
|
||||
private readonly ssaoDepthTexture: Texture;
|
||||
private readonly ssaoDepthBlurProxyTexture: Texture;
|
||||
|
||||
private readonly ssaoRenderable: SsaoRenderable
|
||||
private readonly ssaoBlurFirstPassRenderable: SsaoBlurRenderable
|
||||
private readonly ssaoBlurSecondPassRenderable: SsaoBlurRenderable
|
||||
private readonly ssaoRenderable: SsaoRenderable;
|
||||
private readonly ssaoBlurFirstPassRenderable: SsaoBlurRenderable;
|
||||
private readonly ssaoBlurSecondPassRenderable: SsaoBlurRenderable;
|
||||
|
||||
private nSamples: number
|
||||
private blurKernelSize: number
|
||||
private nSamples: number;
|
||||
private blurKernelSize: number;
|
||||
|
||||
private readonly renderable: PostprocessingRenderable
|
||||
private readonly renderable: PostprocessingRenderable;
|
||||
|
||||
private ssaoScale: number
|
||||
private ssaoScale: number;
|
||||
private calcSsaoScale() {
|
||||
// downscale ssao for high pixel-ratios
|
||||
return Math.min(1, 1 / this.webgl.pixelRatio);
|
||||
@@ -543,9 +543,9 @@ export class AntialiasingPass {
|
||||
return props.antialiasing.name !== 'off';
|
||||
}
|
||||
|
||||
readonly target: RenderTarget
|
||||
private readonly fxaa: FxaaPass
|
||||
private readonly smaa: SmaaPass
|
||||
readonly target: RenderTarget;
|
||||
private readonly fxaa: FxaaPass;
|
||||
private readonly smaa: SmaaPass;
|
||||
|
||||
constructor(webgl: WebGLContext, private drawPass: DrawPass) {
|
||||
const { colorTarget } = drawPass;
|
||||
|
||||
@@ -31,12 +31,12 @@ export const SmaaParams = {
|
||||
export type SmaaProps = PD.Values<typeof SmaaParams>
|
||||
|
||||
export class SmaaPass {
|
||||
private readonly edgesTarget: RenderTarget
|
||||
private readonly weightsTarget: RenderTarget
|
||||
private readonly edgesTarget: RenderTarget;
|
||||
private readonly weightsTarget: RenderTarget;
|
||||
|
||||
private readonly edgesRenderable: EdgesRenderable
|
||||
private readonly weightsRenderable: WeightsRenderable
|
||||
private readonly blendRenderable: BlendRenderable
|
||||
private readonly edgesRenderable: EdgesRenderable;
|
||||
private readonly weightsRenderable: WeightsRenderable;
|
||||
private readonly blendRenderable: BlendRenderable;
|
||||
|
||||
private _supported = false;
|
||||
get supported() {
|
||||
|
||||
@@ -45,11 +45,11 @@ function getEvaluateWboitRenderable(ctx: WebGLContext, wboitATexture: Texture, w
|
||||
//
|
||||
|
||||
export class WboitPass {
|
||||
private readonly renderable: EvaluateWboitRenderable
|
||||
private readonly renderable: EvaluateWboitRenderable;
|
||||
|
||||
private readonly framebuffer: Framebuffer
|
||||
private readonly textureA: Texture
|
||||
private readonly textureB: Texture
|
||||
private readonly framebuffer: Framebuffer;
|
||||
private readonly textureA: Texture;
|
||||
private readonly textureB: Texture;
|
||||
|
||||
private _supported = false;
|
||||
get supported() {
|
||||
|
||||
@@ -87,9 +87,9 @@ namespace SortedRanges {
|
||||
}
|
||||
|
||||
export class Iterator<T extends number = number, I extends number = number> implements _Iterator<Segmentation.Segment<I>> {
|
||||
private value: Segmentation.Segment<I> = { index: 0 as I, start: 0 as T, end: 0 as T }
|
||||
private value: Segmentation.Segment<I> = { index: 0 as I, start: 0 as T, end: 0 as T };
|
||||
|
||||
private curIndex = 0
|
||||
private curIndex = 0;
|
||||
|
||||
hasNext: boolean = false;
|
||||
|
||||
|
||||
@@ -28,11 +28,11 @@ function nextIndex(n: number) {
|
||||
};
|
||||
|
||||
export class CombinationIterator<T> implements Iterator<ReadonlyArray<T>> {
|
||||
private value: T[]
|
||||
private index: number
|
||||
private maxIndex: number
|
||||
private value: T[];
|
||||
private index: number;
|
||||
private maxIndex: number;
|
||||
|
||||
size: number
|
||||
size: number;
|
||||
hasNext: boolean = false;
|
||||
|
||||
move() {
|
||||
|
||||
@@ -9,10 +9,10 @@ import { OrderedSet, Interval, Segmentation } from '../int';
|
||||
|
||||
/** Emits a segment of length one for each element in the interval that is also in the set */
|
||||
export class IntervalIterator<I extends number = number> implements Iterator<Segmentation.Segment<I>> {
|
||||
private value: Segmentation.Segment<I> = { index: 0 as I, start: 0, end: 0 }
|
||||
private value: Segmentation.Segment<I> = { index: 0 as I, start: 0, end: 0 };
|
||||
|
||||
private curIndex = 0
|
||||
private maxIndex = 0
|
||||
private curIndex = 0;
|
||||
private maxIndex = 0;
|
||||
|
||||
hasNext: boolean = false;
|
||||
|
||||
|
||||
@@ -39,35 +39,35 @@ export type FontAtlasMap = {
|
||||
}
|
||||
|
||||
export class FontAtlas {
|
||||
readonly props: Readonly<FontAtlasProps>
|
||||
readonly mapped: { [k: string]: FontAtlasMap } = {}
|
||||
readonly placeholder: FontAtlasMap
|
||||
readonly texture: TextureImage<Uint8Array>
|
||||
readonly props: Readonly<FontAtlasProps>;
|
||||
readonly mapped: { [k: string]: FontAtlasMap } = {};
|
||||
readonly placeholder: FontAtlasMap;
|
||||
readonly texture: TextureImage<Uint8Array>;
|
||||
|
||||
private scratchW = 0
|
||||
private scratchH = 0
|
||||
private currentX = 0
|
||||
private currentY = 0
|
||||
private readonly scratchData: Uint8Array
|
||||
private scratchW = 0;
|
||||
private scratchH = 0;
|
||||
private currentX = 0;
|
||||
private currentY = 0;
|
||||
private readonly scratchData: Uint8Array;
|
||||
|
||||
private readonly cutoff = 0.5
|
||||
readonly buffer: number
|
||||
private readonly radius: number
|
||||
private readonly cutoff = 0.5;
|
||||
readonly buffer: number;
|
||||
private readonly radius: number;
|
||||
|
||||
private gridOuter: Float64Array
|
||||
private gridInner: Float64Array
|
||||
private f: Float64Array
|
||||
private d: Float64Array
|
||||
private z: Float64Array
|
||||
private v: Int16Array
|
||||
private gridOuter: Float64Array;
|
||||
private gridInner: Float64Array;
|
||||
private f: Float64Array;
|
||||
private d: Float64Array;
|
||||
private z: Float64Array;
|
||||
private v: Int16Array;
|
||||
|
||||
private scratchCanvas: HTMLCanvasElement
|
||||
private scratchContext: CanvasRenderingContext2D
|
||||
private scratchCanvas: HTMLCanvasElement;
|
||||
private scratchContext: CanvasRenderingContext2D;
|
||||
|
||||
readonly lineHeight: number
|
||||
readonly lineHeight: number;
|
||||
|
||||
private readonly maxWidth: number
|
||||
private readonly middle: number
|
||||
private readonly maxWidth: number;
|
||||
private readonly middle: number;
|
||||
|
||||
constructor(props: Partial<FontAtlasProps> = {}) {
|
||||
const p = { ...PD.getDefaultValues(FontAtlasParams), ...props };
|
||||
|
||||
@@ -47,7 +47,7 @@ export interface TextureMesh {
|
||||
export namespace TextureMesh {
|
||||
export class DoubleBuffer {
|
||||
private index = 0;
|
||||
private textures: ({ vertex: Texture, group: Texture, normal: Texture } | undefined)[] = []
|
||||
private textures: ({ vertex: Texture, group: Texture, normal: Texture } | undefined)[] = [];
|
||||
|
||||
get() {
|
||||
return this.textures[this.index];
|
||||
|
||||
@@ -72,7 +72,7 @@ export function computeMarchingCubesLines(params: MarchingCubesParams, lines?: L
|
||||
class MarchingCubesComputation {
|
||||
private size: number;
|
||||
private sliceSize: number;
|
||||
private edgeFilter: number
|
||||
private edgeFilter: number;
|
||||
|
||||
private minX = 0; private minY = 0; private minZ = 0;
|
||||
private maxX = 0; private maxY = 0; private maxZ = 0;
|
||||
|
||||
@@ -74,6 +74,7 @@ uniform vec3 uFogColor;
|
||||
uniform float uAlpha;
|
||||
uniform float uPickingAlphaThreshold;
|
||||
uniform bool uTransparentBackground;
|
||||
uniform float uXrayEdgeFalloff;
|
||||
|
||||
uniform float uInteriorDarkening;
|
||||
uniform bool uInteriorColorFlag;
|
||||
|
||||
@@ -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.352, IHM 1.17, CARB draft.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.353, IHM 1.17, MA 1.3.3.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
@@ -942,6 +942,48 @@ export const mmCIF_Schema = {
|
||||
*/
|
||||
method: Aliased<'X-RAY DIFFRACTION' | 'NEUTRON DIFFRACTION' | 'FIBER DIFFRACTION' | 'ELECTRON CRYSTALLOGRAPHY' | 'ELECTRON MICROSCOPY' | 'SOLUTION NMR' | 'SOLID-STATE NMR' | 'SOLUTION SCATTERING' | 'POWDER DIFFRACTION' | 'INFRARED SPECTROSCOPY' | 'EPR' | 'FLUORESCENCE TRANSFER' | 'THEORETICAL MODEL'>(str),
|
||||
},
|
||||
/**
|
||||
* Data items in the SOFTWARE category record details about
|
||||
* the software used in the structure analysis, which implies
|
||||
* any software used in the generation of any data items
|
||||
* associated with the structure determination and
|
||||
* structure representation.
|
||||
*
|
||||
* These data items allow computer programs to be referenced
|
||||
* in more detail than data items in the COMPUTING category do.
|
||||
*/
|
||||
software: {
|
||||
/**
|
||||
* The classification of the program according to its
|
||||
* major function.
|
||||
*/
|
||||
classification: str,
|
||||
/**
|
||||
* The date the software was released.
|
||||
*/
|
||||
date: str,
|
||||
/**
|
||||
* Description of the software.
|
||||
*/
|
||||
description: str,
|
||||
/**
|
||||
* The name of the software.
|
||||
*/
|
||||
name: str,
|
||||
/**
|
||||
* The classification of the software according to the most
|
||||
* common types.
|
||||
*/
|
||||
type: Aliased<'program' | 'library' | 'package' | 'filter' | 'jiffy' | 'other'>(str),
|
||||
/**
|
||||
* The version of the software.
|
||||
*/
|
||||
version: str,
|
||||
/**
|
||||
* An ordinal index for this category
|
||||
*/
|
||||
pdbx_ordinal: int,
|
||||
},
|
||||
/**
|
||||
* Data items in the STRUCT category record details about the
|
||||
* description of the crystallographic structure.
|
||||
@@ -4717,6 +4759,289 @@ export const mmCIF_Schema = {
|
||||
*/
|
||||
dataset_list_id: int,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_MODEL_LIST category record the
|
||||
* details of the models being deposited.
|
||||
*/
|
||||
ma_model_list: {
|
||||
/**
|
||||
* A unique identifier for the model / model group combination.
|
||||
*/
|
||||
ordinal_id: int,
|
||||
/**
|
||||
* A unique identifier for the structural model being deposited.
|
||||
*/
|
||||
model_id: int,
|
||||
/**
|
||||
* An identifier to group structural models into collections or sets.
|
||||
* A cluster of models and its representative can either be grouped together
|
||||
* or can be separate groups in the ma_model_list table. The choice between
|
||||
* the two options should be decided based on how the modeling was carried out
|
||||
* and how the representative was chosen. If the representative is a member of
|
||||
* the ensemble (i.e., best scoring model), then it is recommended that the
|
||||
* representative and the ensemble belong to the same model group. If the
|
||||
* representative is calculated from the ensemble (i.e., centroid), then it is
|
||||
* recommended that the representative be separated into a different group.
|
||||
* If the models do not need to be grouped into collections, then the
|
||||
* _ma_model_list.model_group_id is the same as _ma_model_list.model_id.
|
||||
*/
|
||||
model_group_id: int,
|
||||
/**
|
||||
* A decsriptive name for the model.
|
||||
*/
|
||||
model_name: str,
|
||||
/**
|
||||
* A decsriptive name for the model group.
|
||||
*/
|
||||
model_group_name: str,
|
||||
/**
|
||||
* The type of model.
|
||||
*/
|
||||
model_type: Aliased<'Homology model' | 'Ab initio model' | 'Other'>(str),
|
||||
/**
|
||||
* The data_id identifier. This data item is a pointer to
|
||||
* _ma_data.id in the MA_DATA category.
|
||||
*/
|
||||
data_id: int,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_TARGET_ENTITY category record details about
|
||||
* the target entities. The details are provided for each entity
|
||||
* being modeled.
|
||||
*/
|
||||
ma_target_entity: {
|
||||
/**
|
||||
* A unique identifier for the distinct molecular entity of the target.
|
||||
* This data item is a pointer to _entity.id in the ENTITY category.
|
||||
*/
|
||||
entity_id: str,
|
||||
/**
|
||||
* The data_id identifier. This data item is a pointer to
|
||||
* _ma_data.id in the MA_DATA category.
|
||||
*/
|
||||
data_id: int,
|
||||
/**
|
||||
* The origin of the target entity.
|
||||
*/
|
||||
origin: Aliased<'reference database' | 'designed'>(str),
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_TARGET_ENTITY_INSTANCE category record details about
|
||||
* the instances of target entities modeled.
|
||||
*/
|
||||
ma_target_entity_instance: {
|
||||
/**
|
||||
* A unique identifier for the instance of the entity.
|
||||
*/
|
||||
asym_id: str,
|
||||
/**
|
||||
* A unique identifier for the distinct molecular entity of the target.
|
||||
* This data item is a pointer to _ma_target_entity.entity_id in the
|
||||
* MA_TARGET_ENTITY category.
|
||||
*/
|
||||
entity_id: str,
|
||||
/**
|
||||
* Additional details about the entity instance.
|
||||
*/
|
||||
details: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_TARGET_REF_DB_DETAILS category record details about
|
||||
* the reference databases for the target sequences.
|
||||
*/
|
||||
ma_target_ref_db_details: {
|
||||
/**
|
||||
* An identifier for the target entity.
|
||||
*/
|
||||
target_entity_id: str,
|
||||
/**
|
||||
* The name of the database containing reference information about
|
||||
* this entity or biological unit.
|
||||
*/
|
||||
db_name: Aliased<'UNP' | 'GB' | 'OrthoDB' | 'NCBI' | 'JGI' | 'Other'>(str),
|
||||
/**
|
||||
* The code for this entity or biological unit or for a closely
|
||||
* related entity or biological unit in the named database.
|
||||
* This can include the version number.
|
||||
*/
|
||||
db_code: str,
|
||||
/**
|
||||
* Accession code assigned by the reference database.
|
||||
*/
|
||||
db_accession: str,
|
||||
/**
|
||||
* Database code assigned by the reference database for a sequence isoform. An isoform sequence is an
|
||||
* alternative protein sequence that can be generated from the same gene by a single or by a combination of
|
||||
* biological events such as: alternative promoter usage, alternative splicing, alternative initiation
|
||||
* and ribosomal frameshifting.
|
||||
*/
|
||||
seq_db_isoform: str,
|
||||
/**
|
||||
* Beginning index in the chemical sequence from the
|
||||
* reference database.
|
||||
*/
|
||||
seq_db_align_begin: str,
|
||||
/**
|
||||
* Ending index in the chemical sequence from the
|
||||
* reference database.
|
||||
*/
|
||||
seq_db_align_end: str,
|
||||
/**
|
||||
* Taxonomy identifier provided by NCBI.
|
||||
*/
|
||||
ncbi_taxonomy_id: str,
|
||||
/**
|
||||
* Scientific name of the organism.
|
||||
*/
|
||||
organism_scientific: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_DATA category capture the different kinds of
|
||||
* data used in the modeling. These can be multiple sequence
|
||||
* alignments, spatial restraints, template structures etc.
|
||||
*/
|
||||
ma_data: {
|
||||
/**
|
||||
* A unique identifier for the data.
|
||||
*/
|
||||
id: int,
|
||||
/**
|
||||
* The type of data held in the dataset.
|
||||
*/
|
||||
content_type: Aliased<'target' | 'template structure' | 'polymeric template library' | 'spatial restraints' | 'target-template alignment' | 'coevolution MSA' | 'model coordinates' | 'other'>(str),
|
||||
/**
|
||||
* Details for other content types.
|
||||
*/
|
||||
content_type_other_details: str,
|
||||
/**
|
||||
* An author-given name for the content held in the dataset.
|
||||
*/
|
||||
name: str,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_SOFTWARE_GROUP category describes the
|
||||
* collection of software into groups so that they can be used
|
||||
* efficiently in the MA_PROTOCOL_STEP category.
|
||||
*/
|
||||
ma_software_group: {
|
||||
/**
|
||||
* A unique identifier for the category.
|
||||
*/
|
||||
ordinal_id: int,
|
||||
/**
|
||||
* An identifier for the group entry.
|
||||
* If data does not need to be grouped, then _ma_software_group.group_id
|
||||
* is the same as _ma_software_group.software_id.
|
||||
*/
|
||||
group_id: int,
|
||||
/**
|
||||
* The identifier for the software.
|
||||
* This data item is a pointer to _software.pdbx_ordinal
|
||||
* in the SOFTWARE category.
|
||||
*/
|
||||
software_id: int,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_QA_METRIC category record the
|
||||
* details of the metrics use to assess model quality.
|
||||
*/
|
||||
ma_qa_metric: {
|
||||
/**
|
||||
* An identifier for the QA metric.
|
||||
*/
|
||||
id: int,
|
||||
/**
|
||||
* Name of the QA metric.
|
||||
*/
|
||||
name: str,
|
||||
/**
|
||||
* The type of QA metric.
|
||||
*/
|
||||
type: Aliased<'zscore' | 'energy' | 'distance' | 'normalized score' | 'pLDDT' | 'PAE' | 'contact probability' | 'other'>(str),
|
||||
/**
|
||||
* The mode of calculation of the QA metric.
|
||||
*/
|
||||
mode: Aliased<'local' | 'global' | 'local-pairwise'>(str),
|
||||
/**
|
||||
* Identifier to the set of software used to calculate the QA metric.
|
||||
* This data item is a pointer to the _ma_software_group.group_id in the
|
||||
* MA_SOFTWARE_GROUP category.
|
||||
*/
|
||||
software_group_id: int,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_QA_METRIC_GLOBAL category captures the
|
||||
* details of the global QA metrics, calculated at the model-level.
|
||||
*/
|
||||
ma_qa_metric_global: {
|
||||
/**
|
||||
* A unique identifier for the category.
|
||||
*/
|
||||
ordinal_id: int,
|
||||
/**
|
||||
* The identifier for the structural model, for which global QA metric is provided.
|
||||
* This data item is a pointer to _ma_model_list.model_id
|
||||
* in the MA_MODEL_LIST category.
|
||||
*/
|
||||
model_id: int,
|
||||
/**
|
||||
* The identifier for the QA metric.
|
||||
* This data item is a pointer to _ma_qa_metric.id in the
|
||||
* MA_QA_METRIC category.
|
||||
*/
|
||||
metric_id: int,
|
||||
/**
|
||||
* The value of the global QA metric.
|
||||
*/
|
||||
metric_value: float,
|
||||
},
|
||||
/**
|
||||
* Data items in the MA_QA_METRIC_LOCAL category captures the
|
||||
* details of the local QA metrics, calculated at the residue-level.
|
||||
*/
|
||||
ma_qa_metric_local: {
|
||||
/**
|
||||
* A unique identifier for the category.
|
||||
*/
|
||||
ordinal_id: int,
|
||||
/**
|
||||
* The identifier for the structural model, for which local QA metric is provided.
|
||||
* This data item is a pointer to _ma_model_list.model_id
|
||||
* in the MA_MODEL_LIST category.
|
||||
*/
|
||||
model_id: int,
|
||||
/**
|
||||
* The identifier for the asym id of the residue in the
|
||||
* structural model, for which local QA metric is provided.
|
||||
* This data item is a pointer to _atom_site.label_asym_id
|
||||
* in the ATOM_SITE category.
|
||||
*/
|
||||
label_asym_id: str,
|
||||
/**
|
||||
* The identifier for the sequence index of the residue
|
||||
* in the structural model, for which local QA metric is provided.
|
||||
* This data item is a pointer to _atom_site.label_seq_id
|
||||
* in the ATOM_SITE category.
|
||||
*/
|
||||
label_seq_id: int,
|
||||
/**
|
||||
* The component identifier for the residue in the
|
||||
* structural model, for which local QA metric is provided.
|
||||
* This data item is a pointer to _atom_site.label_comp_id
|
||||
* in the ATOM_SITE category.
|
||||
*/
|
||||
label_comp_id: str,
|
||||
/**
|
||||
* The identifier for the QA metric.
|
||||
* This data item is a pointer to _ma_qa_metric.id in the
|
||||
* MA_QA_METRIC category.
|
||||
*/
|
||||
metric_id: int,
|
||||
/**
|
||||
* The value of the local QA metric.
|
||||
*/
|
||||
metric_value: float,
|
||||
},
|
||||
};
|
||||
|
||||
export type mmCIF_Schema = typeof mmCIF_Schema;
|
||||
|
||||
@@ -12,12 +12,12 @@ import { Box3D } from './primitives/box3d';
|
||||
// implementing http://www.ep.liu.se/ecp/034/009/ecp083409.pdf
|
||||
|
||||
export class BoundaryHelper {
|
||||
private dir: Vec3[]
|
||||
private dir: Vec3[];
|
||||
|
||||
private minDist: number[] = []
|
||||
private maxDist: number[] = []
|
||||
private extrema: Vec3[] = []
|
||||
centroidHelper = new CentroidHelper()
|
||||
private minDist: number[] = [];
|
||||
private maxDist: number[] = [];
|
||||
private extrema: Vec3[] = [];
|
||||
centroidHelper = new CentroidHelper();
|
||||
|
||||
private computeExtrema(i: number, p: Vec3) {
|
||||
const d = Vec3.dot(this.dir[i], p);
|
||||
|
||||
@@ -27,7 +27,7 @@ class GridLookup3DImpl<T extends number = number> implements GridLookup3D<T> {
|
||||
private ctx: QueryContext;
|
||||
boundary: Lookup3D['boundary'];
|
||||
buckets: GridLookup3D['buckets'];
|
||||
result: Result<T>
|
||||
result: Result<T>;
|
||||
|
||||
find(x: number, y: number, z: number, radius: number, result?: Result<T>): Result<T> {
|
||||
this.ctx.x = x;
|
||||
|
||||
@@ -59,7 +59,9 @@ namespace SymmetryOperator {
|
||||
ncsId = ncsId || -1;
|
||||
const suffix = getSuffix(info);
|
||||
if (Mat4.isIdentity(matrix)) return { name, assembly, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl, spgrOp, ncsId, suffix };
|
||||
if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) throw new Error(`Symmetry operator (${name}) must be a composition of rotation and translation.`);
|
||||
if (!Mat4.isRotationAndTranslation(matrix, RotationTranslationEpsilon)) {
|
||||
console.warn(`Symmetry operator (${name}) should be a composition of rotation and translation.`);
|
||||
}
|
||||
return { name, assembly, matrix, inverse: Mat4.invert(Mat4(), matrix), isIdentity: false, hkl: _hkl, spgrOp, ncsId, suffix };
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ export { InterUnitGraph };
|
||||
|
||||
class InterUnitGraph<UnitId extends number, VertexIndex extends number, EdgeProps extends InterUnitGraph.EdgePropsBase = {}> {
|
||||
/** Number of inter-unit edges */
|
||||
readonly edgeCount: number
|
||||
readonly edgeCount: number;
|
||||
/** Array of inter-unit edges */
|
||||
readonly edges: ReadonlyArray<InterUnitGraph.Edge<UnitId, VertexIndex, EdgeProps>>
|
||||
private readonly edgeKeyIndex: Map<string, number>
|
||||
private readonly vertexKeyIndex: Map<string, number[]>
|
||||
readonly edges: ReadonlyArray<InterUnitGraph.Edge<UnitId, VertexIndex, EdgeProps>>;
|
||||
private readonly edgeKeyIndex: Map<string, number>;
|
||||
private readonly vertexKeyIndex: Map<string, number[]>;
|
||||
|
||||
/** Get an array of unit-pair-edges that are connected to the given unit */
|
||||
getConnectedUnits(unit: UnitId): ReadonlyArray<InterUnitGraph.UnitPairEdges<UnitId, VertexIndex, EdgeProps>> {
|
||||
@@ -134,13 +134,13 @@ namespace InterUnitGraph {
|
||||
|
||||
|
||||
export class Builder<UnitId extends number, VertexIndex extends number, EdgeProps extends InterUnitGraph.EdgePropsBase = {}> {
|
||||
private uA: UnitId
|
||||
private uB: UnitId
|
||||
private mapAB: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>
|
||||
private mapBA: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>
|
||||
private linkedA: UniqueArray<VertexIndex, VertexIndex>
|
||||
private linkedB: UniqueArray<VertexIndex, VertexIndex>
|
||||
private linkCount: number
|
||||
private uA: UnitId;
|
||||
private uB: UnitId;
|
||||
private mapAB: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>;
|
||||
private mapBA: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>;
|
||||
private linkedA: UniqueArray<VertexIndex, VertexIndex>;
|
||||
private linkedB: UniqueArray<VertexIndex, VertexIndex>;
|
||||
private linkCount: number;
|
||||
|
||||
private map = new Map<number, UnitPairEdges<UnitId, VertexIndex, EdgeProps>[]>();
|
||||
|
||||
|
||||
@@ -98,12 +98,12 @@ const CharmmIonComponents = (function () {
|
||||
})();
|
||||
|
||||
export class ComponentBuilder {
|
||||
private namesMap = new Map<string, string>()
|
||||
private comps = new Map<string, Component>()
|
||||
private ids: string[] = []
|
||||
private names: string[] = []
|
||||
private types: mmCIF_chemComp_schema['type']['T'][] = []
|
||||
private mon_nstd_flags: mmCIF_chemComp_schema['mon_nstd_flag']['T'][] = []
|
||||
private namesMap = new Map<string, string>();
|
||||
private comps = new Map<string, Component>();
|
||||
private ids: string[] = [];
|
||||
private names: string[] = [];
|
||||
private types: mmCIF_chemComp_schema['type']['T'][] = [];
|
||||
private mon_nstd_flags: mmCIF_chemComp_schema['mon_nstd_flag']['T'][] = [];
|
||||
|
||||
private set(c: Component) {
|
||||
this.comps.set(c.id, c);
|
||||
|
||||
@@ -14,16 +14,16 @@ export type EntityCompound = { chains: string[], description: string }
|
||||
type EntityType = 'water' | 'polymer' | 'non-polymer'
|
||||
|
||||
export class EntityBuilder {
|
||||
private count = 0
|
||||
private ids: string[] = []
|
||||
private types: EntityType[] = []
|
||||
private descriptions: string[][] = []
|
||||
private count = 0;
|
||||
private ids: string[] = [];
|
||||
private types: EntityType[] = [];
|
||||
private descriptions: string[][] = [];
|
||||
|
||||
private compoundsMap = new Map<string, string>()
|
||||
private namesMap = new Map<string, string>()
|
||||
private heteroMap = new Map<string, string>()
|
||||
private chainMap = new Map<string, string>()
|
||||
private waterId?: string
|
||||
private compoundsMap = new Map<string, string>();
|
||||
private namesMap = new Map<string, string>();
|
||||
private heteroMap = new Map<string, string>();
|
||||
private chainMap = new Map<string, string>();
|
||||
private waterId?: string;
|
||||
|
||||
private set(type: EntityType, description: string) {
|
||||
this.count += 1;
|
||||
|
||||
@@ -9,8 +9,8 @@ import { ModelFormat } from '../../format';
|
||||
import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
|
||||
|
||||
class FormatRegistry<T> {
|
||||
private map = new Map<ModelFormat['kind'], (model: Model) => T | undefined>()
|
||||
private applicable = new Map<ModelFormat['kind'], (model: Model) => boolean>()
|
||||
private map = new Map<ModelFormat['kind'], (model: Model) => T | undefined>();
|
||||
private applicable = new Map<ModelFormat['kind'], (model: Model) => boolean>();
|
||||
|
||||
add(kind: ModelFormat['kind'], obtain: (model: Model) => T | undefined, applicable?: (model: Model) => boolean) {
|
||||
this.map.set(kind, obtain);
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace CustomProperty {
|
||||
}
|
||||
|
||||
export class Registry<Data> {
|
||||
private providers = OrderedMap<string, Provider<Data, any, any>>().asMutable()
|
||||
private defaultAutoAttachValues = new Map<string, boolean>()
|
||||
private providers = OrderedMap<string, Provider<Data, any, any>>().asMutable();
|
||||
private defaultAutoAttachValues = new Map<string, boolean>();
|
||||
|
||||
/** Get params for all applicable property providers */
|
||||
getParams(data?: Data) {
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace InteractionsIntraContacts {
|
||||
|
||||
export { InteractionsInterContacts };
|
||||
class InteractionsInterContacts extends InterUnitGraph<number, Features.FeatureIndex, InteractionsInterContacts.Props> {
|
||||
private readonly elementKeyIndex: Map<string, number[]>
|
||||
private readonly elementKeyIndex: Map<string, number[]>;
|
||||
|
||||
getContactIndicesForElement(index: StructureElement.UnitIndex, unit: Unit): ReadonlyArray<number> {
|
||||
return this.elementKeyIndex.get(this.getElementKey(index, unit.id)) || [];
|
||||
|
||||
@@ -20,8 +20,8 @@ function getPairKey(indexA: StructureElement.UnitIndex, unitA: Unit, indexB: Str
|
||||
}
|
||||
|
||||
export class PairRestraints<T extends PairRestraint> {
|
||||
readonly count: number
|
||||
private readonly pairKeyIndices: Map<string, number[]>
|
||||
readonly count: number;
|
||||
private readonly pairKeyIndices: Map<string, number[]>;
|
||||
|
||||
/** Indices into this.pairs */
|
||||
getPairIndices(indexA: StructureElement.UnitIndex, unitA: Unit, indexB: StructureElement.UnitIndex, unitB: Unit): ReadonlyArray<number> {
|
||||
|
||||
@@ -21,11 +21,11 @@ export function align(seqA: ArrayLike<string>, seqB: ArrayLike<string>, options:
|
||||
}
|
||||
|
||||
class Alignment {
|
||||
readonly gapPenalty: number; readonly gapExtensionPenalty: number
|
||||
readonly substMatrix: SubstitutionMatrixData | undefined
|
||||
readonly gapPenalty: number; readonly gapExtensionPenalty: number;
|
||||
readonly substMatrix: SubstitutionMatrixData | undefined;
|
||||
|
||||
readonly n: number; readonly m: number
|
||||
readonly S: number[][] = []; readonly V: number[][] = []; readonly H: number[][] = []
|
||||
readonly n: number; readonly m: number;
|
||||
readonly S: number[][] = []; readonly V: number[][] = []; readonly H: number[][] = [];
|
||||
|
||||
constructor(readonly seqA: ArrayLike<string>, readonly seqB: ArrayLike<string>, options: AlignmentOptions) {
|
||||
this.gapPenalty = options.gapPenalty;
|
||||
|
||||
@@ -86,14 +86,14 @@ namespace Sequence {
|
||||
}
|
||||
|
||||
class ResidueNamesImpl<K extends Kind, Alphabet extends string> implements Base<K, Alphabet> {
|
||||
public length: number
|
||||
public code: Column<Alphabet>
|
||||
public label: Column<string>
|
||||
public seqId: Column<number>
|
||||
public compId: Column<string>
|
||||
public microHet: ReadonlyMap<number, string[]> = new Map()
|
||||
public length: number;
|
||||
public code: Column<Alphabet>;
|
||||
public label: Column<string>;
|
||||
public seqId: Column<number>;
|
||||
public compId: Column<string>;
|
||||
public microHet: ReadonlyMap<number, string[]> = new Map();
|
||||
|
||||
private indexMap: Map<number, number>
|
||||
private indexMap: Map<number, number>;
|
||||
index(seqId: number) {
|
||||
return this.indexMap.get(seqId)!;
|
||||
}
|
||||
@@ -158,14 +158,14 @@ namespace Sequence {
|
||||
}
|
||||
|
||||
class SequenceRangesImpl<K extends Kind, Alphabet extends string> implements Base<K, Alphabet> {
|
||||
public length: number
|
||||
public code: Column<Alphabet>
|
||||
public label: Column<string>
|
||||
public seqId: Column<number>
|
||||
public compId: Column<string>
|
||||
public microHet: ReadonlyMap<number, string[]> = new Map()
|
||||
public length: number;
|
||||
public code: Column<Alphabet>;
|
||||
public label: Column<string>;
|
||||
public seqId: Column<number>;
|
||||
public compId: Column<string>;
|
||||
public microHet: ReadonlyMap<number, string[]> = new Map();
|
||||
|
||||
private minSeqId: number
|
||||
private minSeqId: number;
|
||||
index(seqId: number) {
|
||||
return seqId - this.minSeqId;
|
||||
}
|
||||
|
||||
@@ -286,6 +286,11 @@ export namespace Model {
|
||||
for (let i = 0, il = db.database_2.database_id.rowCount; i < il; ++i) {
|
||||
if (db.database_2.database_id.value(i) === 'PDB') return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasPdbId(model: Model): boolean {
|
||||
if (!MmcifFormat.is(model.sourceData)) return false;
|
||||
return (
|
||||
// 4 character PDB id
|
||||
model.entryId.match(/^[1-9][a-z0-9]{3,3}$/i) !== null ||
|
||||
@@ -381,7 +386,7 @@ export namespace Model {
|
||||
const { db } = model.sourceData.data;
|
||||
return hasDensityMap(model) || (
|
||||
// check if from pdb archive but missing relevant meta data
|
||||
isFromPdbArchive(model) && (
|
||||
hasPdbId(model) && (
|
||||
!db.exptl.method.isDefined ||
|
||||
(isFromXray(model) && (
|
||||
!db.pdbx_database_status.status_code_sf.isDefined ||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2021 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>
|
||||
@@ -206,6 +206,12 @@ export interface AtomicIndex {
|
||||
*/
|
||||
findAtomsOnResidue(residueIndex: ResidueIndex, label_atom_ids: Set<string>): ElementIndex
|
||||
|
||||
/**
|
||||
* Find element index of an atom on a given residue.
|
||||
* @returns index or -1 if the atom is not present.
|
||||
*/
|
||||
findElementOnResidue(residueIndex: ResidueIndex, type_symbol: ElementSymbol): ElementIndex
|
||||
|
||||
// TODO: add indices that support comp_id?
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -7,7 +7,7 @@
|
||||
import { AtomicData, AtomNumber } from '../atomic';
|
||||
import { AtomicIndex, AtomicDerivedData, AtomicSegments } from '../atomic/hierarchy';
|
||||
import { ElementIndex, ResidueIndex } from '../../indexing';
|
||||
import { MoleculeType, getMoleculeType, getComponentType, PolymerType, getPolymerType } from '../../types';
|
||||
import { MoleculeType, getMoleculeType, getComponentType, PolymerType, getPolymerType, isPolymer, ElementSymbol } from '../../types';
|
||||
import { getAtomIdForAtomRole } from '../../../../../mol-model/structure/util';
|
||||
import { ChemicalComponentMap } from '../common';
|
||||
import { isProductionMode } from '../../../../../mol-util/debug';
|
||||
@@ -63,6 +63,9 @@ export function getAtomicDerivedData(data: AtomicData, segments: AtomicSegments,
|
||||
if (traceIndex === -1) {
|
||||
const coarseAtomId = getAtomIdForAtomRole(polyType, 'coarseBackbone');
|
||||
traceIndex = index.findAtomsOnResidue(i, coarseAtomId);
|
||||
if (traceIndex === -1 && isPolymer(molType)) {
|
||||
traceIndex = index.findElementOnResidue(i, ElementSymbol('C'));
|
||||
}
|
||||
}
|
||||
traceElementIndex[i] = traceIndex;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2021 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>
|
||||
@@ -12,6 +12,7 @@ import { ChainIndex, ResidueIndex, EntityIndex, ElementIndex } from '../../index
|
||||
import { AtomicIndex, AtomicHierarchy } from '../atomic/hierarchy';
|
||||
import { cantorPairing } from '../../../../../mol-data/util';
|
||||
import { Column } from '../../../../../mol-data/db';
|
||||
import { ElementSymbol } from '../../types';
|
||||
|
||||
function getResidueId(seq_id: number, ins_code: string) {
|
||||
if (!ins_code) return seq_id;
|
||||
@@ -43,6 +44,7 @@ interface Mapping {
|
||||
label_atom_id: Column<string>,
|
||||
auth_atom_id: Column<string>,
|
||||
label_alt_id: Column<string>,
|
||||
type_symbol: Column<ElementSymbol>,
|
||||
segments: AtomicSegments,
|
||||
|
||||
chain_index_entity_index: EntityIndex[],
|
||||
@@ -64,6 +66,7 @@ function createMapping(entities: Entities, data: AtomicData, segments: AtomicSeg
|
||||
label_atom_id: data.atoms.label_atom_id,
|
||||
auth_atom_id: data.atoms.auth_atom_id,
|
||||
label_alt_id: data.atoms.label_alt_id,
|
||||
type_symbol: data.atoms.type_symbol,
|
||||
chain_index_entity_index: new Int32Array(data.chains._rowCount) as any,
|
||||
entity_index_label_asym_id: new Map(),
|
||||
chain_index_label_seq_id: new Map(),
|
||||
@@ -173,6 +176,10 @@ class Index implements AtomicIndex {
|
||||
return findAtomByNames(this.residueOffsets[rI], this.residueOffsets[rI + 1], this.map.label_atom_id, label_atom_ids);
|
||||
}
|
||||
|
||||
findElementOnResidue(rI: ResidueIndex, type_symbol: ElementSymbol) {
|
||||
return findAtomByElement(this.residueOffsets[rI], this.residueOffsets[rI + 1], this.map.type_symbol, type_symbol);
|
||||
}
|
||||
|
||||
constructor(private map: Mapping) {
|
||||
this.entityIndex = map.entities.getEntityIndex;
|
||||
this.residueOffsets = this.map.segments.residueAtomSegments.offsets;
|
||||
@@ -201,6 +208,13 @@ function findAtomByNameAndAltLoc(start: ElementIndex, end: ElementIndex, nameDat
|
||||
return -1 as ElementIndex;
|
||||
}
|
||||
|
||||
function findAtomByElement(start: ElementIndex, end: ElementIndex, data: Column<ElementSymbol>, typeSymbol: ElementSymbol): ElementIndex {
|
||||
for (let i = start; i < end; i++) {
|
||||
if (data.value(i) === typeSymbol) return i;
|
||||
}
|
||||
return -1 as ElementIndex;
|
||||
}
|
||||
|
||||
export function getAtomicIndex(data: AtomicData, entities: Entities, segments: AtomicSegments): AtomicIndex {
|
||||
const map = createMapping(entities, data, segments);
|
||||
|
||||
|
||||
@@ -321,6 +321,12 @@ export function getMoleculeType(compType: string, compId: string): MoleculeType
|
||||
if (SaccharideCompIdMap.has(compId)) {
|
||||
// trust our saccharide table more than given 'non-polymer' or 'other' component type
|
||||
return MoleculeType.Saccharide;
|
||||
} else if (AminoAcidNames.has(compId)) {
|
||||
return MoleculeType.Protein;
|
||||
} else if (RnaBaseNames.has(compId)) {
|
||||
return MoleculeType.RNA;
|
||||
} else if (DnaBaseNames.has(compId)) {
|
||||
return MoleculeType.DNA;
|
||||
} else {
|
||||
return MoleculeType.Other;
|
||||
}
|
||||
|
||||
@@ -938,7 +938,7 @@ namespace Structure {
|
||||
|
||||
export class StructureBuilder {
|
||||
private units: Unit[] = [];
|
||||
private invariantId = idFactory()
|
||||
private invariantId = idFactory();
|
||||
|
||||
private chainGroupId = -1;
|
||||
private inChainGroup = false;
|
||||
|
||||
@@ -180,18 +180,18 @@ namespace Bond {
|
||||
}
|
||||
|
||||
export class ElementBondIterator implements Iterator<ElementBondData> {
|
||||
private current: ElementBondData = {} as any
|
||||
private current: ElementBondData = {} as any;
|
||||
|
||||
private structure: Structure
|
||||
private unit: Unit.Atomic
|
||||
private index: StructureElement.UnitIndex
|
||||
private structure: Structure;
|
||||
private unit: Unit.Atomic;
|
||||
private index: StructureElement.UnitIndex;
|
||||
|
||||
private interBondIndices: ReadonlyArray<number>
|
||||
private interBondCount: number
|
||||
private interBondIndex: number
|
||||
private interBondIndices: ReadonlyArray<number>;
|
||||
private interBondCount: number;
|
||||
private interBondIndex: number;
|
||||
|
||||
private intraBondEnd: number
|
||||
private intraBondIndex: number
|
||||
private intraBondEnd: number;
|
||||
private intraBondIndex: number;
|
||||
|
||||
hasNext: boolean;
|
||||
move(): ElementBondData {
|
||||
|
||||
@@ -29,7 +29,7 @@ class UnitRings {
|
||||
readonly ringComponentIndex: ReadonlyArray<UnitRings.ComponentIndex>,
|
||||
readonly ringComponents: ReadonlyArray<ReadonlyArray<UnitRings.Index>>
|
||||
};
|
||||
private _aromaticRings?: ReadonlyArray<UnitRings.Index>
|
||||
private _aromaticRings?: ReadonlyArray<UnitRings.Index>;
|
||||
|
||||
private get index() {
|
||||
if (this._index) return this._index;
|
||||
@@ -122,6 +122,7 @@ namespace UnitRing {
|
||||
}
|
||||
if (aromaticBondCount === 2 * ring.length) return true;
|
||||
if (!hasAromaticRingElement) return false;
|
||||
if (ring.length < 5) return false;
|
||||
|
||||
const ma = PrincipalAxes.calculateMomentsAxes(getPositions(unit, ring));
|
||||
return Vec3.magnitude(ma.dirC) < AromaticRingPlanarityThreshold;
|
||||
|
||||
@@ -12,8 +12,8 @@ import { fillIdentityTransform } from '../../../../mol-geo/geometry/transform-da
|
||||
const tmpMat = Mat4();
|
||||
|
||||
export class StructureUnitTransforms {
|
||||
private unitTransforms: Float32Array
|
||||
private groupUnitTransforms: Float32Array[] = []
|
||||
private unitTransforms: Float32Array;
|
||||
private groupUnitTransforms: Float32Array[] = [];
|
||||
/** maps unit.id to offset of transform in unitTransforms */
|
||||
private unitOffsetMap = IntMap.Mutable<number>();
|
||||
private groupIndexMap = IntMap.Mutable<number>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 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>
|
||||
@@ -18,19 +18,23 @@ import { Download } from '../transforms/data';
|
||||
import { CustomModelProperties, CustomStructureProperties, TrajectoryFromModelAndCoordinates } from '../transforms/model';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { getFileInfo } from '../../mol-util/file-info';
|
||||
|
||||
const DownloadModelRepresentationOptions = (plugin: PluginContext) => PD.Group({
|
||||
type: RootStructureDefinition.getParams(void 0, 'auto').type,
|
||||
representation: PD.Select(PresetStructureRepresentations.auto.id,
|
||||
plugin.builders.structure.representation.getPresets().map(p => [p.id, p.display.name, p.display.group] as any),
|
||||
{ description: 'Which representation preset to use.' }),
|
||||
representationParams: PD.Group(StructureRepresentationPresetProvider.CommonParams, { isHidden: true }),
|
||||
asTrajectory: PD.Optional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' }))
|
||||
}, { isExpanded: false });
|
||||
const DownloadModelRepresentationOptions = (plugin: PluginContext) => {
|
||||
const representationDefault = plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
||||
return PD.Group({
|
||||
type: RootStructureDefinition.getParams(void 0, 'auto').type,
|
||||
representation: PD.Select(representationDefault,
|
||||
plugin.builders.structure.representation.getPresets().map(p => [p.id, p.display.name, p.display.group] as any),
|
||||
{ description: 'Which representation preset to use.' }),
|
||||
representationParams: PD.Group(StructureRepresentationPresetProvider.CommonParams, { isHidden: true }),
|
||||
asTrajectory: PD.Optional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' }))
|
||||
}, { isExpanded: false });
|
||||
};
|
||||
|
||||
export const PdbDownloadProvider = {
|
||||
'rcsb': PD.Group({
|
||||
encoding: PD.Select('bcif', [['cif', 'cif'], ['bcif', 'bcif']] as ['cif' | 'bcif', string][]),
|
||||
encoding: PD.Select('bcif', PD.arrayToOptions(['cif', 'bcif'] as const)),
|
||||
}, { label: 'RCSB PDB', isFlat: true }),
|
||||
'pdbe': PD.Group({
|
||||
variant: PD.Select('updated-bcif', [['updated-bcif', 'Updated (bcif)'], ['updated', 'Updated'], ['archival', 'Archival']] as ['updated' | 'updtaed-bcif' | 'archival', string][]),
|
||||
@@ -58,7 +62,7 @@ const DownloadStructure = StateAction.build({
|
||||
'pdb-dev': PD.Group({
|
||||
provider: PD.Group({
|
||||
id: PD.Text('PDBDEV_00000001', { label: 'PDBDev Id(s)', description: 'One or more comma/space separated ids.' }),
|
||||
encoding: PD.Select('bcif', [['cif', 'cif'], ['bcif', 'bcif']] as ['cif' | 'bcif', string][]),
|
||||
encoding: PD.Select('bcif', PD.arrayToOptions(['cif', 'bcif'] as const)),
|
||||
}, { pivot: 'id' }),
|
||||
options
|
||||
}, { isFlat: true, label: 'PDBDEV' }),
|
||||
@@ -66,6 +70,14 @@ const DownloadStructure = StateAction.build({
|
||||
id: PD.Text('Q9Y2I8', { label: 'UniProtKB AC(s)', description: 'One or more comma/space separated ACs.' }),
|
||||
options
|
||||
}, { isFlat: true, label: 'SWISS-MODEL', description: 'Loads the best homology model or experimental structure' }),
|
||||
'alphafolddb': PD.Group({
|
||||
id: PD.Text('Q8W3K0', { label: 'UniProtKB AC(s)', description: 'One or more comma/space separated ACs.' }),
|
||||
options
|
||||
}, { isFlat: true, label: 'AlphaFold DB', description: 'Loads the predicted model if available' }),
|
||||
'modelarchive': PD.Group({
|
||||
id: PD.Text('ma-bak-cepc-0003', { label: 'Accession Code(s)', description: 'One or more comma/space separated ACs.' }),
|
||||
options
|
||||
}, { isFlat: true, label: 'Model Archive' }),
|
||||
'pubchem': PD.Group({
|
||||
id: PD.Text('2244,2245', { label: 'PubChem ID', description: 'One or more comma/space separated IDs.' }),
|
||||
options
|
||||
@@ -84,7 +96,7 @@ const DownloadStructure = StateAction.build({
|
||||
|
||||
const src = params.source;
|
||||
let downloadParams: StateTransformer.Params<Download>[];
|
||||
let asTrajectory = false, format: BuiltInTrajectoryFormat = 'mmcif';
|
||||
let asTrajectory = false, format: BuiltInTrajectoryFormat | 'auto' = 'mmcif';
|
||||
|
||||
switch (src.name) {
|
||||
case 'url':
|
||||
@@ -92,7 +104,7 @@ const DownloadStructure = StateAction.build({
|
||||
format = src.params.format;
|
||||
break;
|
||||
case 'pdb':
|
||||
downloadParams = src.params.provider.server.name === 'pdbe'
|
||||
downloadParams = await (src.params.provider.server.name === 'pdbe'
|
||||
? src.params.provider.server.params.variant === 'updated'
|
||||
? getDownloadParams(src.params.provider.id, id => `https://www.ebi.ac.uk/pdbe/static/entry/${id.toLowerCase()}_updated.cif`, id => `PDBe: ${id} (updated cif)`, false)
|
||||
: src.params.provider.server.params.variant === 'updated-bcif'
|
||||
@@ -100,11 +112,12 @@ const DownloadStructure = StateAction.build({
|
||||
: getDownloadParams(src.params.provider.id, id => `https://www.ebi.ac.uk/pdbe/static/entry/${id.toLowerCase()}.cif`, id => `PDBe: ${id} (cif)`, false)
|
||||
: src.params.provider.server.params.encoding === 'cif'
|
||||
? getDownloadParams(src.params.provider.id, id => `https://files.rcsb.org/download/${id.toUpperCase()}.cif`, id => `RCSB: ${id} (cif)`, false)
|
||||
: getDownloadParams(src.params.provider.id, id => `https://models.rcsb.org/${id.toUpperCase()}.bcif`, id => `RCSB: ${id} (bcif)`, true);
|
||||
: getDownloadParams(src.params.provider.id, id => `https://models.rcsb.org/${id.toUpperCase()}.bcif`, id => `RCSB: ${id} (bcif)`, true)
|
||||
);
|
||||
asTrajectory = !!src.params.options.asTrajectory;
|
||||
break;
|
||||
case 'pdb-dev':
|
||||
downloadParams = getDownloadParams(src.params.provider.id,
|
||||
downloadParams = await getDownloadParams(src.params.provider.id,
|
||||
id => {
|
||||
const nId = id.toUpperCase().startsWith('PDBDEV_') ? id : `PDBDEV_${id.padStart(8, '0')}`;
|
||||
return src.params.provider.encoding === 'bcif'
|
||||
@@ -117,19 +130,34 @@ const DownloadStructure = StateAction.build({
|
||||
asTrajectory = !!src.params.options.asTrajectory;
|
||||
break;
|
||||
case 'swissmodel':
|
||||
downloadParams = getDownloadParams(src.params.id, id => `https://swissmodel.expasy.org/repository/uniprot/${id.toUpperCase()}.pdb`, id => `SWISS-MODEL: ${id}`, false);
|
||||
downloadParams = await getDownloadParams(src.params.id, id => `https://swissmodel.expasy.org/repository/uniprot/${id.toUpperCase()}.pdb`, id => `SWISS-MODEL: ${id}`, false);
|
||||
asTrajectory = !!src.params.options.asTrajectory;
|
||||
format = 'pdb';
|
||||
break;
|
||||
case 'alphafolddb':
|
||||
downloadParams = await getDownloadParams(src.params.id, async id => {
|
||||
const url = `https://www.alphafold.ebi.ac.uk/api/prediction/${id.toUpperCase()}`;
|
||||
const info = await plugin.runTask(plugin.fetch({ url, type: 'json' }));
|
||||
if (Array.isArray(info) && info.length > 0) return info[0].cifUrl;
|
||||
throw new Error(`No AlphaFold DB entry for '${id}'`);
|
||||
}, id => `AlphaFold DB: ${id}`, false);
|
||||
asTrajectory = !!src.params.options.asTrajectory;
|
||||
format = 'mmcif';
|
||||
break;
|
||||
case 'modelarchive':
|
||||
downloadParams = await getDownloadParams(src.params.id, id => `https://www.modelarchive.org/doi/10.5452/${id.toLowerCase()}.cif`, id => `Model Archive: ${id}`, false);
|
||||
asTrajectory = !!src.params.options.asTrajectory;
|
||||
format = 'mmcif';
|
||||
break;
|
||||
case 'pubchem':
|
||||
downloadParams = getDownloadParams(src.params.id, id => `https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/CID/${id.trim()}/record/SDF/?record_type=3d`, id => `PubChem: ${id}`, false);
|
||||
downloadParams = await getDownloadParams(src.params.id, id => `https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/CID/${id.trim()}/record/SDF/?record_type=3d`, id => `PubChem: ${id}`, false);
|
||||
asTrajectory = !!src.params.options.asTrajectory;
|
||||
format = 'mol';
|
||||
break;
|
||||
default: throw new Error(`${(src as any).name} not supported.`);
|
||||
}
|
||||
|
||||
const representationPreset: any = params.source.params.options.representation || PresetStructureRepresentations.auto.id;
|
||||
const representationPreset: any = params.source.params.options.representation || plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
||||
const showUnitcell = representationPreset !== PresetStructureRepresentations.empty.id;
|
||||
|
||||
const structure = src.params.options.type.name === 'auto' ? void 0 : src.params.options.type;
|
||||
@@ -151,7 +179,11 @@ const DownloadStructure = StateAction.build({
|
||||
} else {
|
||||
for (const download of downloadParams) {
|
||||
const data = await plugin.builders.data.download(download, { state: { isGhost: true } });
|
||||
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
|
||||
const provider = format === 'auto'
|
||||
? plugin.dataFormats.auto(getFileInfo(Asset.getUrl(download.url)), data.cell?.obj!)
|
||||
: plugin.dataFormats.get(format);
|
||||
if (!provider) throw new Error('unknown file format');
|
||||
const trajectory = await plugin.builders.structure.parseTrajectory(data, provider);
|
||||
|
||||
await plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default', {
|
||||
structure,
|
||||
@@ -164,11 +196,11 @@ const DownloadStructure = StateAction.build({
|
||||
}).runInContext(ctx);
|
||||
}));
|
||||
|
||||
function getDownloadParams(src: string, url: (id: string) => string, label: (id: string) => string, isBinary: boolean): StateTransformer.Params<Download>[] {
|
||||
async function getDownloadParams(src: string, url: (id: string) => string | Promise<string>, label: (id: string) => string, isBinary: boolean): Promise<StateTransformer.Params<Download>[]> {
|
||||
const ids = src.split(/[,\s]/).map(id => id.trim()).filter(id => !!id && (id.length >= 4 || /^[1-9][0-9]*$/.test(id)));
|
||||
const ret: StateTransformer.Params<Download>[] = [];
|
||||
for (const id of ids) {
|
||||
ret.push({ url: Asset.Url(url(id)), isBinary, label: label(id) });
|
||||
ret.push({ url: Asset.Url(await url(id)), isBinary, label: label(id) });
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -176,7 +208,7 @@ function getDownloadParams(src: string, url: (id: string) => string, label: (id:
|
||||
export const UpdateTrajectory = StateAction.build({
|
||||
display: { name: 'Update Trajectory' },
|
||||
params: {
|
||||
action: PD.Select<'advance' | 'reset'>('advance', [['advance', 'Advance'], ['reset', 'Reset']]),
|
||||
action: PD.Select('advance', PD.arrayToOptions(['advance', 'reset'] as const)),
|
||||
by: PD.Optional(PD.Numeric(1, { min: -1, max: 1, step: 1 }))
|
||||
}
|
||||
})(({ params, state }) => {
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { Model } from '../../../mol-model/structure';
|
||||
import { getStructureQuality } from '../../../mol-repr/util';
|
||||
import { OperatorNameColorThemeProvider } from '../../../mol-theme/color/operator-name';
|
||||
import { PluginConfig } from '../../../mol-plugin/config';
|
||||
|
||||
export interface TrajectoryHierarchyPresetProvider<P = any, S = {}> extends PresetProvider<PluginStateObject.Molecule.Trajectory, P, S> { }
|
||||
export function TrajectoryHierarchyPresetProvider<P, S>(preset: TrajectoryHierarchyPresetProvider<P, S>) { return preset; }
|
||||
@@ -61,7 +62,8 @@ const defaultPreset = TrajectoryHierarchyPresetProvider({
|
||||
const structureProperties = await builder.insertStructureProperties(structure, params.structureProperties);
|
||||
|
||||
const unitcell = params.showUnitcell === void 0 || !!params.showUnitcell ? await builder.tryCreateUnitcell(modelProperties, undefined, { isHidden: true }) : void 0;
|
||||
const representation = await plugin.builders.structure.representation.applyPreset(structureProperties, params.representationPreset || 'auto', params.representationPresetParams);
|
||||
const representationPreset = params.representationPreset || plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
||||
const representation = await plugin.builders.structure.representation.applyPreset(structureProperties, representationPreset, params.representationPresetParams);
|
||||
|
||||
return {
|
||||
model,
|
||||
@@ -112,7 +114,8 @@ const allModels = TrajectoryHierarchyPresetProvider({
|
||||
structures.push(structure);
|
||||
|
||||
const quality = structure.obj ? getStructureQuality(structure.obj.data, { elementCountFactor: tr.frameCount }) : 'medium';
|
||||
await builder.representation.applyPreset(structureProperties, params.representationPreset || 'auto', { theme: { globalName: 'model-index' }, quality });
|
||||
const representationPreset = params.representationPreset || plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
||||
await builder.representation.applyPreset(structureProperties, representationPreset, { theme: { globalName: 'model-index' }, quality });
|
||||
}
|
||||
|
||||
return { models, structures };
|
||||
@@ -137,7 +140,8 @@ async function applyCrystalSymmetry(props: { ijkMin: Vec3, ijkMax: Vec3, theme?:
|
||||
const structureProperties = await builder.insertStructureProperties(structure, params.structureProperties);
|
||||
|
||||
const unitcell = await builder.tryCreateUnitcell(modelProperties, undefined, { isHidden: false });
|
||||
const representation = await plugin.builders.structure.representation.applyPreset(structureProperties, params.representationPreset || 'auto', { theme: { globalName: props.theme } });
|
||||
const representationPreset = params.representationPreset || plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
||||
const representation = await plugin.builders.structure.representation.applyPreset(structureProperties, representationPreset, { theme: { globalName: props.theme } });
|
||||
|
||||
return {
|
||||
model,
|
||||
@@ -207,7 +211,8 @@ const crystalContacts = TrajectoryHierarchyPresetProvider({
|
||||
const structureProperties = await builder.insertStructureProperties(structure, params.structureProperties);
|
||||
|
||||
const unitcell = await builder.tryCreateUnitcell(modelProperties, undefined, { isHidden: true });
|
||||
const representation = await plugin.builders.structure.representation.applyPreset(structureProperties, params.representationPreset || 'auto', { theme: { globalName: 'operator-name', carbonColor: 'operator-name', focus: { name: 'element-symbol', params: { carbonColor: { name: 'operator-name', params: OperatorNameColorThemeProvider.defaultValues } } } } });
|
||||
const representationPreset = params.representationPreset || plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
||||
const representation = await plugin.builders.structure.representation.applyPreset(structureProperties, representationPreset, { theme: { globalName: 'operator-name', carbonColor: 'operator-name', focus: { name: 'element-symbol', params: { carbonColor: { name: 'operator-name', params: OperatorNameColorThemeProvider.defaultValues } } } } });
|
||||
|
||||
return {
|
||||
model,
|
||||
|
||||
@@ -14,11 +14,11 @@ import { BuiltInShapeFormats } from './shape';
|
||||
import { BuiltInStructureFormats } from './structure';
|
||||
|
||||
export class DataFormatRegistry {
|
||||
private _list: { name: string, provider: DataFormatProvider }[] = []
|
||||
private _map = new Map<string, DataFormatProvider>()
|
||||
private _extensions: Set<string> | undefined = undefined
|
||||
private _binaryExtensions: Set<string> | undefined = undefined
|
||||
private _options: [string, string, string][] | undefined = undefined
|
||||
private _list: { name: string, provider: DataFormatProvider }[] = [];
|
||||
private _map = new Map<string, DataFormatProvider>();
|
||||
private _extensions: Set<string> | undefined = undefined;
|
||||
private _binaryExtensions: Set<string> | undefined = undefined;
|
||||
private _options: [string, string, string][] | undefined = undefined;
|
||||
|
||||
get types(): [string, string][] {
|
||||
return this._list.map(e => [e.name, e.provider.label] as [string, string]);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { CustomProperty } from '../../mol-model-props/common/custom-property';
|
||||
import { QueryContext, Structure, StructureQuery, StructureSelection, StructureProperties, StructureElement } from '../../mol-model/structure';
|
||||
import { BondType, NucleicBackboneAtoms, ProteinBackboneAtoms, SecondaryStructureType, AminoAcidNamesL, RnaBaseNames, DnaBaseNames, WaterNames, ElementSymbol } from '../../mol-model/structure/model/types';
|
||||
import { BondType, NucleicBackboneAtoms, ProteinBackboneAtoms, SecondaryStructureType, AminoAcidNamesL, RnaBaseNames, DnaBaseNames, WaterNames, ElementSymbol, PolymerNames } from '../../mol-model/structure/model/types';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
|
||||
import { Expression } from '../../mol-script/language/expression';
|
||||
@@ -320,33 +320,46 @@ const branchedConnectedOnly = StructureSelectionQuery('Connected to Carbohydrate
|
||||
]), { category: StructureSelectionCategory.Internal, isHidden: true });
|
||||
|
||||
const ligand = StructureSelectionQuery('Ligand', MS.struct.modifier.union([
|
||||
MS.struct.combinator.merge([
|
||||
MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
'entity-test': MS.core.logic.and([
|
||||
MS.core.logic.or([
|
||||
MS.core.rel.eq([MS.ammp('entityType'), 'non-polymer']),
|
||||
MS.core.rel.neq([MS.ammp('entityPrdId'), ''])
|
||||
]),
|
||||
MS.core.logic.not([MS.core.str.match([
|
||||
MS.re('(oligosaccharide|lipid|ion)', 'i'),
|
||||
MS.ammp('entitySubtype')
|
||||
])])
|
||||
MS.struct.modifier.exceptBy({
|
||||
0: MS.struct.modifier.union([
|
||||
MS.struct.combinator.merge([
|
||||
MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
'entity-test': MS.core.logic.and([
|
||||
MS.core.logic.or([
|
||||
MS.core.rel.eq([MS.ammp('entityType'), 'non-polymer']),
|
||||
MS.core.rel.neq([MS.ammp('entityPrdId'), ''])
|
||||
]),
|
||||
MS.core.logic.not([MS.core.str.match([
|
||||
MS.re('(oligosaccharide|lipid|ion)', 'i'),
|
||||
MS.ammp('entitySubtype')
|
||||
])])
|
||||
]),
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'residue-test': MS.core.logic.not([
|
||||
MS.core.str.match([MS.re('saccharide', 'i'), MS.ammp('chemCompType')])
|
||||
])
|
||||
})
|
||||
]),
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'residue-test': MS.core.logic.not([
|
||||
MS.core.str.match([MS.re('saccharide', 'i'), MS.ammp('chemCompType')])
|
||||
MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'residue-test': _nonPolymerResidueTest
|
||||
})
|
||||
])
|
||||
})
|
||||
]),
|
||||
]),
|
||||
MS.struct.modifier.union([
|
||||
by: MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']),
|
||||
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
|
||||
'residue-test': _nonPolymerResidueTest
|
||||
'residue-test': MS.core.set.has([
|
||||
MS.set(...SetUtils.toArray(PolymerNames)), MS.ammp('label_comp_id')
|
||||
])
|
||||
})
|
||||
])
|
||||
]),
|
||||
})
|
||||
]), { category: StructureSelectionCategory.Type });
|
||||
|
||||
// don't include branched entities as they have their own link representation
|
||||
@@ -729,9 +742,9 @@ export const StructureSelectionQueries = {
|
||||
};
|
||||
|
||||
export class StructureSelectionQueryRegistry {
|
||||
list: StructureSelectionQuery[] = []
|
||||
options: [StructureSelectionQuery, string, string][] = []
|
||||
version = 1
|
||||
list: StructureSelectionQuery[] = [];
|
||||
options: [StructureSelectionQuery, string, string][] = [];
|
||||
version = 1;
|
||||
|
||||
add(q: StructureSelectionQuery) {
|
||||
this.list.push(q);
|
||||
|
||||
@@ -36,7 +36,7 @@ class InteractivityManager extends StatefulPluginComponent<InteractivityManagerS
|
||||
readonly lociSelects: InteractivityManager.LociSelectManager;
|
||||
readonly lociHighlights: InteractivityManager.LociHighlightManager;
|
||||
|
||||
private _props = PD.getDefaultValues(InteractivityManager.Params)
|
||||
private _props = PD.getDefaultValues(InteractivityManager.Params);
|
||||
|
||||
readonly events = {
|
||||
propsUpdated: this.ev()
|
||||
@@ -84,9 +84,9 @@ namespace InteractivityManager {
|
||||
|
||||
export abstract class LociMarkManager {
|
||||
protected providers: LociMarkProvider[] = [];
|
||||
protected sel: StructureSelectionManager
|
||||
protected sel: StructureSelectionManager;
|
||||
|
||||
readonly props: Readonly<Props> = PD.getDefaultValues(Params)
|
||||
readonly props: Readonly<Props> = PD.getDefaultValues(Params);
|
||||
|
||||
setProps(props: Partial<Props>) {
|
||||
Object.assign(this.props, props);
|
||||
@@ -141,7 +141,7 @@ namespace InteractivityManager {
|
||||
this.mark(p, MarkerAction.RemoveHighlight, noRender);
|
||||
}
|
||||
this.prev.length = 0;
|
||||
}
|
||||
};
|
||||
|
||||
highlight(current: Representation.Loci, applyGranularity = true) {
|
||||
const normalized = this.normalizedLoci(current, applyGranularity);
|
||||
|
||||
@@ -41,7 +41,7 @@ export class LociLabelManager {
|
||||
this.showLabels();
|
||||
}
|
||||
|
||||
private locis: Representation.Loci[] = []
|
||||
private locis: Representation.Loci[] = [];
|
||||
|
||||
private mark(loci: Representation.Loci, action: MarkerAction) {
|
||||
const idx = this.locis.findIndex(l => Representation.Loci.areEqual(loci, l));
|
||||
@@ -54,9 +54,9 @@ export class LociLabelManager {
|
||||
}
|
||||
}
|
||||
|
||||
private isDirty = false
|
||||
private labels: LociLabel[] = []
|
||||
private groupedLabels = new Map<string, LociLabel[]>()
|
||||
private isDirty = false;
|
||||
private labels: LociLabel[] = [];
|
||||
private groupedLabels = new Map<string, LociLabel[]>();
|
||||
|
||||
private showLabels() {
|
||||
this.ctx.behaviors.labels.highlight.next({ labels: this.getLabels() });
|
||||
|
||||
@@ -14,7 +14,7 @@ import { StateBuilder, StateObjectRef, StateTransformer } from '../../../mol-sta
|
||||
import { Task } from '../../../mol-task';
|
||||
import { ColorTheme } from '../../../mol-theme/color';
|
||||
import { SizeTheme } from '../../../mol-theme/size';
|
||||
import { UUID } from '../../../mol-util';
|
||||
import { shallowEqual, UUID } from '../../../mol-util';
|
||||
import { ColorNames } from '../../../mol-util/color/names';
|
||||
import { objectForEach } from '../../../mol-util/object';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
@@ -42,7 +42,7 @@ interface StructureComponentManagerState {
|
||||
class StructureComponentManager extends StatefulPluginComponent<StructureComponentManagerState> {
|
||||
readonly events = {
|
||||
optionsUpdated: this.ev<undefined>()
|
||||
}
|
||||
};
|
||||
|
||||
get currentStructures() {
|
||||
return this.plugin.managers.structure.hierarchy.selection.structures;
|
||||
@@ -82,7 +82,7 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone
|
||||
if (r.cell.transform.transformer !== StructureRepresentation3D) continue;
|
||||
|
||||
const params = r.cell.transform.params as StateTransformer.Params<StructureRepresentation3D>;
|
||||
if (!!params.type.params.ignoreHydrogens !== ignoreHydrogens || params.type.params.quality !== quality || params.type.params.material !== material) {
|
||||
if (!!params.type.params.ignoreHydrogens !== ignoreHydrogens || params.type.params.quality !== quality || !shallowEqual(params.type.params.material, material)) {
|
||||
update.to(r.cell).update(old => {
|
||||
old.type.params.ignoreHydrogens = ignoreHydrogens;
|
||||
old.type.params.quality = quality;
|
||||
|
||||
@@ -41,7 +41,7 @@ const HISTORY_CAPACITY = 8;
|
||||
export class StructureFocusManager extends StatefulPluginComponent<StructureFocusManagerState> {
|
||||
readonly events = {
|
||||
historyUpdated: this.ev<undefined>()
|
||||
}
|
||||
};
|
||||
|
||||
readonly behaviors = {
|
||||
current: this.ev.behavior<FocusEntry | undefined>(void 0)
|
||||
|
||||
@@ -25,7 +25,7 @@ export class StructureHierarchyManager extends PluginComponent {
|
||||
models: [] as ReadonlyArray<ModelRef>,
|
||||
structures: [] as ReadonlyArray<StructureRef>
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
readonly behaviors = {
|
||||
selection: this.ev.behavior({
|
||||
@@ -34,7 +34,7 @@ export class StructureHierarchyManager extends PluginComponent {
|
||||
models: this.selection.models,
|
||||
structures: this.selection.structures
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
private get dataState() {
|
||||
return this.plugin.state.data;
|
||||
|
||||
@@ -45,9 +45,9 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
|
||||
remove: this.ev<StructureElement.Loci>(),
|
||||
clear: this.ev<undefined>()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private referenceLoci: StructureElement.Loci | undefined
|
||||
private referenceLoci: StructureElement.Loci | undefined;
|
||||
|
||||
get entries() { return this.state.entries; }
|
||||
get additionsHistory() { return this.state.additionsHistory; }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user