Compare commits

...

239 Commits

Author SHA1 Message Date
David Sehnal
c81166d04b 1.1.2 2020-07-02 23:09:15 +02:00
David Sehnal
3384a8630b Merge pull request #71 from JonStargaryen/sdf
SDF/MOL/MOL2 export by ModelServer
2020-07-02 23:03:00 +02:00
JonStargaryen
e39c7c4e98 move encoders to mol-io 2020-07-02 09:41:41 -07:00
JonStargaryen
38e838a352 remove label 2020-07-02 09:19:14 -07:00
JonStargaryen
cea22c0ea1 use spread 2020-07-02 09:18:52 -07:00
David Sehnal
6b73361963 mol-plugin-ui: added ViewportCanvas component 2020-07-02 14:00:26 +02:00
David Sehnal
096a4ee63e mol-plugin: volume streaming 'auto' view mode 2020-07-02 13:46:58 +02:00
JonStargaryen
28c8d6bef9 description 2020-07-01 13:28:19 -07:00
JonStargaryen
37fdbfe12a omit redundant code 2020-07-01 10:35:13 -07:00
David Sehnal
295cb84cc8 Fix docking-viewer presets 2020-07-01 12:50:24 +02:00
Alexander Rose
b5252516e3 added docking-viewer example
- expects a pdbqt and a mol2 file in the url get params
2020-06-30 21:57:25 -07:00
Alexander Rose
8e2c0327d6 added Viewport.ShowControls/Settings options to plugin config 2020-06-30 21:28:53 -07:00
Alexander Rose
eaa92b75a3 tweak, use const instead of let 2020-06-30 21:18:34 -07:00
Alexander Rose
ab81c89a9a bool param for mark repr in Highlight/SelectLoci behaviors 2020-06-30 21:18:02 -07:00
Alexander Rose
e49af151c1 use mol2 mol_name for entity name when available 2020-06-30 21:16:11 -07:00
Alexander Rose
78ca5cbb43 use chain-id coloring as base for illiustrative coloring 2020-06-30 21:15:26 -07:00
Alexander Rose
48c242d59d fix chain-id coloring for multi-model structures 2020-06-30 21:14:41 -07:00
JonStargaryen
8b4603d5a1 semicolon 2020-06-30 10:05:42 -07:00
JonStargaryen
cc6dce8845 numModels param for first model 2020-06-30 09:37:35 -07:00
JonStargaryen
b2eac8092c cleanup 2020-06-29 15:33:36 -07:00
JonStargaryen
a22362bac8 hydrogen flag 2020-06-29 15:32:37 -07:00
JonStargaryen
298b283686 revert config 2020-06-29 15:24:01 -07:00
JonStargaryen
14f4de2e3f revert config 2020-06-29 15:23:02 -07:00
JonStargaryen
9bde4c40b0 enforce first model 2020-06-29 11:22:35 -07:00
JonStargaryen
61390cb64f group by query 2020-06-29 10:00:26 -07:00
Alexander Rose
1b67bc41f5 explicit pdbqt provider
- instead of trying to deduce it during parsing
2020-06-26 22:04:27 -07:00
Alexander Rose
5b698b816e basic partial charge and pdbt support
- AtomPartialCharge format property provider
- add from PDBQT and MOL2
- color theme
2020-06-26 00:36:21 -07:00
Alexander Rose
bf9303ea80 number parser fix, handle prefixed plus sign 2020-06-26 00:33:47 -07:00
JonStargaryen
017676c148 path TODO 2020-06-25 16:31:53 -07:00
JonStargaryen
526f7700b2 cleanup 2020-06-25 16:05:43 -07:00
JonStargaryen
220e01106f lint 2020-06-25 10:35:25 -07:00
JonStargaryen
240de5b24d cleanup 2020-06-25 10:30:30 -07:00
JonStargaryen
17a001427b spelling 2020-06-25 09:57:48 -07:00
JonStargaryen
a423970b9c basic ligand writing 2020-06-25 09:53:22 -07:00
JonStargaryen
56f4c8775f cleanup 2020-06-24 16:17:31 -07:00
JonStargaryen
5ed4aa0fae SdfFile tweaks 2020-06-24 14:08:25 -07:00
JonStargaryen
4f4245b895 sdf def, reader, spec 2020-06-24 12:23:31 -07:00
JonStargaryen
bc6d2112e2 refactoring 2020-06-23 16:41:38 -07:00
JonStargaryen
3b2b87d264 tweaks to sdf output 2020-06-23 09:01:15 -07:00
Alexander Rose
181646f052 membrane orientation tweaks
- registered custom repr so it shows up in components
- some renames to make it more in line with the other extensions
- fix shapes to reuse existing geometries (fails to update on prop changes otherwise)
- added label to repr visuals on hover/highlight
- ignore light forbilayer planes mesh
- TODO: layer spheres seem to be broken (e.g. 3pqr)
2020-06-23 01:08:58 -07:00
Alexander Rose
ea5a945810 Merge pull request #47 from JonStargaryen/anvil
ANVIL / Membrane placement prediction implementation
2020-06-22 23:09:59 -07:00
JonStargaryen
7cfdc8ab1b lint 2020-06-22 14:58:03 -07:00
JonStargaryen
52e011ade9 wip query mode 2020-06-22 14:53:34 -07:00
JonStargaryen
895e2ede2d mol2 stub 2020-06-22 09:49:23 -07:00
JonStargaryen
3a25769a94 style 2020-06-22 09:26:38 -07:00
JonStargaryen
5db4b48a86 putative check for compatible encoding 2020-06-22 09:25:41 -07:00
Alexander Rose
aa2899bfbd fix sequence label for non-standard residues, #70 2020-06-21 18:54:10 -07:00
JonStargaryen
40bbd87c4e unique group check 2020-06-19 20:12:30 -07:00
JonStargaryen
fb7dd66600 cleanup 2020-06-19 17:45:00 -07:00
JonStargaryen
e12dc2b089 tweak mapping 2020-06-19 17:37:40 -07:00
JonStargaryen
78242b18c3 hydrogen handling 2020-06-19 15:28:51 -07:00
JonStargaryen
9043e4c8e1 propagate atoms only if present 2020-06-19 12:05:16 -07:00
JonStargaryen
54b5e3a0cc hydrogen option 2020-06-19 10:19:23 -07:00
JonStargaryen
b6719a2f57 always write error category 2020-06-19 09:57:23 -07:00
JonStargaryen
087d5fbb68 stub for sdf writing 2020-06-18 21:12:06 -07:00
JonStargaryen
4f60c91256 impl is-transmembrane symbol correctly 2020-06-17 15:49:33 -07:00
JonStargaryen
99415ef290 reintroduce custom prop 2020-06-17 15:02:15 -07:00
JonStargaryen
d446a2d047 fix serialmapping 2020-06-17 13:07:22 -07:00
JonStargaryen
b476f738bc style of symbol description 2020-06-17 13:05:54 -07:00
JonStargaryen
4c0d1383b2 fix label_comp_id retrieval for color themes 2020-06-16 15:24:44 -07:00
JonStargaryen
6a924bf732 ui label 2020-06-16 11:18:20 -07:00
JonStargaryen
5e1f1220af cleanup 2020-06-16 11:09:42 -07:00
JonStargaryen
d13ee0a2cc ui integration 2020-06-16 10:54:55 -07:00
JonStargaryen
826127672a move symbol 2020-06-15 17:26:25 -07:00
JonStargaryen
df8dd7278a label_comp_id move 2020-06-15 16:38:34 -07:00
JonStargaryen
cbdc4a3e9d drop DefaultQueryRuntimeTable, wip moving 2020-06-15 16:11:07 -07:00
JonStargaryen
75266ad257 merge 2020-06-15 13:30:27 -07:00
JonStargaryen
0e93374b2d add to extensions 2020-06-15 13:25:52 -07:00
JonStargaryen
8e350617f2 wip sdf 2020-06-15 12:18:10 -07:00
Alexander Rose
f6acf0a60a 1.1.1 2020-06-14 20:21:24 -07:00
Alexander Rose
7982f25a45 ignoreHydrogens option for StructureFocusRepresentation
- also updated by StructureComponentManager
2020-06-13 17:03:25 -07:00
Alexander Rose
ddafa7aac1 added todo for gro parser regarding reusing static model parts 2020-06-13 17:01:22 -07:00
Alexander Rose
65946c3045 support for multi-model gro files 2020-06-13 13:24:42 -07:00
Alexander Rose
63d699d620 lower threshold for coarse boundary helper 2020-06-13 12:39:25 -07:00
Alexander Rose
e1170c0552 fix debug helper update missing 2020-06-13 12:30:55 -07:00
Alexander Rose
97612bf044 dcd nd coordinates fixes/tweaks
- cell optional
- elementCount only on frame
2020-06-13 11:58:34 -07:00
Alexander Rose
012ac33bd5 ignore water units for inter-unit bond calculation by default 2020-06-13 11:56:54 -07:00
Alexander Rose
272e208fd4 add ion & lipid as chem_comp type, charmm ion names 2020-06-12 20:11:29 -07:00
Alexander Rose
714f0623bb tweaked repr preset to better handle md systems 2020-06-12 20:10:33 -07:00
Alexander Rose
5327962409 support ignoreHydrogens & traceOnly for points visual 2020-06-11 20:28:22 -07:00
Alexander Rose
7c3529ae30 wip testing: don't partition
- partitioning does'nt agree with trajectories of water/lipid molecules...
2020-06-10 19:53:37 -07:00
Alexander Rose
61c63df9e9 ignore H-H index-pair bonds 2020-06-10 19:52:00 -07:00
Alexander Rose
9b6fcaeb79 lines fixes and tweaks 2020-06-10 19:51:35 -07:00
Alexander Rose
ef3f035f27 allow int for ply vertex property 2020-06-10 17:46:27 -07:00
Alexander Rose
e9bc67fbf4 add .visuals to PlyProvider 2020-06-10 17:46:12 -07:00
Alexander Rose
745f2aecf8 fix props destructuring in ShapeRepresentation3D 2020-06-10 17:45:55 -07:00
Alexander Rose
eff80ad5ff line representation 2020-06-09 18:57:48 -07:00
Alexander Rose
27ef44b833 throwing in hasNdbStructNtcCategories breaks non-mmcif files 2020-06-09 17:29:29 -07:00
JonStargaryen
9d0190c11c color 2020-06-09 11:53:39 -07:00
JonStargaryen
0069687233 simplify params 2020-06-09 10:49:47 -07:00
David Sehnal
478033d405 mol-plugin: added excludeTargetFromSurroundings to Focus behavior 2020-06-09 19:27:56 +02:00
JonStargaryen
58f57d5ad2 typo 2020-06-09 09:24:24 -07:00
JonStargaryen
3f80230f4f membrane orientation behavior 2020-06-09 09:14:11 -07:00
JonStargaryen
da35f0ea16 additional membrane layer scaling param 2020-06-05 11:28:26 -07:00
JonStargaryen
72bdd5bc05 asaCutoff param 2020-06-05 11:20:16 -07:00
JonStargaryen
255cc620a5 dashedLines param 2020-06-05 11:16:07 -07:00
Alexander Rose
4753271a6d 1.1.0 2020-06-04 18:02:00 -07:00
Alexander Rose
11c7024edd tweaks for dnatco confal pyramids
- added Michal and Jiří as contributors
- add preset to annotation group
- legend for color theme
- add as extension to viewer
2020-06-02 17:49:50 -07:00
Alexander Rose
47ba54199f Merge pull request #39 from MadCatX/confal_v2
Confal v2
2020-06-02 17:29:42 -07:00
JonStargaryen
cd7643e79b params 2020-06-02 09:22:02 -07:00
Michal Malý
9a797e39e5 Add README for DNATCO extensions 2020-06-02 09:42:43 +02:00
Michal Malý
7898840003 Add a preset for DNATCO Confal Pyramids representation 2020-06-02 09:01:34 +02:00
Michal Malý
8e91cb6d54 Implement Loci getter in DNATCO Confal Pyramids representation 2020-06-02 09:01:32 +02:00
Michal Malý
893401f7c4 Implement DNATCO Confal Pyramids color theme 2020-06-02 09:00:29 +02:00
Michal Malý
021e6ffeb5 Implement DNATCO Confal Pyramids location iterator 2020-06-02 09:00:27 +02:00
Michal Malý
4080c1e005 Add DNATCO Confal Pyramids representation provider 2020-06-02 08:55:24 +02:00
Michal Malý
5063e99761 Implement basic structure of DNATCO Confal Pyramids extension 2020-06-02 08:50:38 +02:00
Alexander Rose
a59f6546c5 more comp_id fixes 2020-06-01 18:13:10 -07:00
Alexander Rose
3a737099ad add micro het todos and example pdb id 2020-06-01 17:49:47 -07:00
Alexander Rose
d1f76fd48e check all micro het comp ids for isNonStandard prop 2020-06-01 17:44:22 -07:00
Alexander Rose
437d52e484 fix comp_id issues from making it a atom prop, #66 2020-06-01 17:34:57 -07:00
JonStargaryen
610977cc08 params 2020-06-01 15:36:51 -07:00
JonStargaryen
6c78adb353 adds visuals 2020-06-01 10:25:57 -07:00
Alexander Rose
abef75bfa2 fixed sequence label regression
- show comp id only when non-standard, i.e. code is X
2020-05-30 14:47:51 -07:00
Alexander Rose
8137d4acdb fix spelling of isNonStandardCrystalFrame 2020-05-30 13:38:35 -07:00
Alexander Rose
899a186808 take micoheterogeneity into account in getUniqueResidueNames 2020-05-30 13:36:42 -07:00
Alexander Rose
bb7d3e075c change comp_id to be atom property to support micro heterogeneity 2020-05-30 13:32:49 -07:00
David Sehnal
78ba9df263 tweak 2020-05-28 19:15:21 +02:00
David Sehnal
9126416389 mol-plugin: structure repr preset updates
- added "theme" object to params
- added carbonByChainId option
- added Structure.DefaultRepresentationPresetParams plugin config option
2020-05-28 18:58:05 +02:00
David Sehnal
eef944b617 StructureFocusRepresentationParams fix 2020-05-28 14:12:08 +02:00
Alexander Rose
208cc2e48e schema updates and cli path fixes 2020-05-27 17:46:11 -07:00
David Sehnal
1522bf4ae4 package.json cli fix 2020-05-27 22:07:50 +02:00
David Sehnal
422f4567f1 full commonjs build for servers and cli tools 2020-05-27 20:37:12 +02:00
David Sehnal
6c8ae32ff9 mol-plugin: do not update focus theme if not set 2020-05-27 19:46:03 +02:00
David Sehnal
e67c610b84 mol-plugin: fix Volume streaming when clearing state 2020-05-27 19:40:00 +02:00
David Sehnal
96aa003702 mol-plugin: focusTheme params for presets 2020-05-27 19:35:53 +02:00
JonStargaryen
f6262f4be5 remove density param 2020-05-27 10:28:51 -07:00
JonStargaryen
efc5bf6a45 use set 2020-05-27 09:41:11 -07:00
JonStargaryen
cbc9801477 cleanup 2020-05-27 09:40:01 -07:00
Alexander Rose
94e21e8a3a min resolution in repr quality 2020-05-26 17:35:17 -07:00
JonStargaryen
2ed118604c cleanup 2020-05-26 15:38:15 -07:00
JonStargaryen
219d4f4d33 more generic options 2020-05-26 11:16:51 -07:00
Alexander Rose
a937e3c57d lipid query and component 2020-05-25 14:24:10 -07:00
Alexander Rose
9fe16e321e add script to generate martini lipid names 2020-05-25 14:23:55 -07:00
Alexander Rose
697e9986b4 can't ignore atoms with zero occupancy
- is too often the case when just not set
2020-05-25 14:10:40 -07:00
Alexander Rose
613cdc3145 fix building of cli tools 2020-05-25 13:46:46 -07:00
David Sehnal
a2bf489017 fix bond ordering when creating structure from Topology 2020-05-25 03:52:35 +02:00
David Sehnal
aca49b9ba5 PSF parser fix, correct topology/coordinates ordering (wip) 2020-05-25 03:12:14 +02:00
David Sehnal
11d5e301f3 xtc format support
+ build tweaks
2020-05-24 17:44:29 +02:00
Alexander Rose
2797b451fb add interesting pdb entries info 2020-05-22 17:10:03 -07:00
JonStargaryen
e82918db6a membrane orientation representation 2020-05-22 13:53:18 -07:00
Alexander Rose
e0b98f70f0 1.0.5 2020-05-22 10:30:11 -07:00
Alexander Rose
297b9bd3ff update focus color in repr presets 2020-05-22 10:27:31 -07:00
Alexander Rose
013a59857d updated packages
- set "@typescript-eslint/ban-types": "off" (TODO investigate)
- remove node 8 in travis
2020-05-22 09:34:56 -07:00
David Sehnal
0b14381255 mol-io: XTC parser 2020-05-22 16:32:32 +02:00
Alexander Rose
e1e0b0f2da 1.0.4 2020-05-21 16:20:31 -07:00
Alexander Rose
2142290300 add prd_id as entity property, treat prd as ligand 2020-05-21 16:12:09 -07:00
Alexander Rose
aeb7c7033d 0.7.1-dev.13 2020-05-21 11:15:11 -07:00
Alexander Rose
0f8540e7fc trace iterator fixes 2020-05-21 11:08:25 -07:00
Alexander Rose
f14b57fe30 don't split small single atom polymer chains 2020-05-21 11:08:04 -07:00
Alexander Rose
abfb1d5992 ensure sec struct for putty repr 2020-05-21 10:16:51 -07:00
Alexander Rose
35c53b27fe 0.7.1-dev.12 2020-05-21 00:33:50 -07:00
Alexander Rose
a7f144e810 Merge branch 'master' of https://github.com/molstar/molstar 2020-05-21 00:31:40 -07:00
Alexander Rose
f4cb3aeed7 default coloring improvments
- changed chain-id theme to assign distinct color accros the whole scene
- made chain-id the default
- added 'many-distinct' color list
- changed element-symbol theme to use cahin-id theme for carbon coloring
- indicate focus repr with translucent halo
2020-05-21 00:31:29 -07:00
Alexander Rose
bceb044552 add structure-info behavior and plugin-wide properties
- Model.AsymIdOffset
- Model.Index
- Structure.Index
2020-05-21 00:26:44 -07:00
Alexander Rose
5e41e959f8 custom property improvements
- isHidden (always attached)
- getParams uses current props as defaultValues
- add .createSimple to model & structure property provider
2020-05-21 00:23:59 -07:00
Alexander Rose
c95d54f9cd param-definition: fix areEqual, add setDefaultValues 2020-05-21 00:21:30 -07:00
Alexander Rose
8149a25ad4 fix unit cell spelling 2020-05-20 14:13:26 -07:00
Alexander Rose
d500393501 added Model.TrajectoryInfo
- replaces model.trajectoryInfo
2020-05-20 13:07:34 -07:00
David Sehnal
9d2fa3e749 mol-plugin: StructureFocus component customization 2020-05-20 20:32:59 +02:00
JonStargaryen
ee886244fc begin separating calc and representation 2020-05-20 10:45:57 -07:00
JonStargaryen
f2557fe80a refactor membrane orientation 2020-05-20 10:01:51 -07:00
JonStargaryen
bf904a5b32 OPM stub 2020-05-20 09:53:25 -07:00
Alexander Rose
76a5ce8f14 Merge branch 'master' of https://github.com/molstar/molstar 2020-05-20 09:34:25 -07:00
JonStargaryen
1ff83d9648 parameters 2020-05-20 09:26:09 -07:00
Alexander Rose
d121ed8b6c always calculate stats when all stats related values are zero, fixes #48 2020-05-20 01:52:23 -07:00
JonStargaryen
6c27deed74 unused import 2020-05-19 16:53:48 -07:00
JonStargaryen
7e2d15f329 unused import 2020-05-19 16:52:58 -07:00
JonStargaryen
10bd7853f3 move ASA request 2020-05-19 16:52:17 -07:00
JonStargaryen
4a7bfe953c package-lock 2020-05-19 16:34:47 -07:00
JonStargaryen
3598d13a3d package-lock 2020-05-19 16:33:51 -07:00
JonStargaryen
96ac561279 merge 2020-05-19 16:30:39 -07:00
JonStargaryen
2c81267ca7 avoid overlap 2020-05-19 16:26:21 -07:00
JonStargaryen
395fa5dad1 less sphere points 2020-05-19 16:10:39 -07:00
JonStargaryen
d15340e62e typo 2020-05-19 16:04:05 -07:00
JonStargaryen
eab4c08836 reintroduce ASA calc 2020-05-19 15:59:37 -07:00
JonStargaryen
69c5bf0094 lint 2020-05-19 15:54:55 -07:00
JonStargaryen
6c112f83e8 cleanup 2020-05-19 15:50:12 -07:00
JonStargaryen
f49c34c551 cleanup 2020-05-19 15:41:52 -07:00
Alexander Rose
3ab4458cb2 add OT1 and OT2 to protein backbone atoms- commonly used 2020-05-19 15:34:40 -07:00
JonStargaryen
ad3c07c634 use correct score 2020-05-19 14:49:47 -07:00
JonStargaryen
68525c2109 fix bugs 2020-05-19 12:07:02 -07:00
JonStargaryen
9e9851472d debugging 2020-05-19 10:31:42 -07:00
JonStargaryen
c0edb27323 circumvent repr provider for now 2020-05-18 17:30:16 -07:00
JonStargaryen
0a70783b5e draft for ANVIL impl 2020-05-18 17:29:09 -07:00
Alexander Rose
a3d101cdf9 0.7.1-dev.11 2020-05-18 17:18:46 -07:00
Alexander Rose
7255e08ecf tweak combined color ui
- use short label
2020-05-18 17:16:51 -07:00
Alexander Rose
b1bdb8e66b fix partial polymer trace curve calculation 2020-05-18 16:20:50 -07:00
Alexander Rose
49c8c7f396 focus manager: only union loci when from same structure 2020-05-18 15:21:24 -07:00
Alexander Rose
d3b4280589 ensure transformed structure is used in camera.focusLoci 2020-05-18 14:51:36 -07:00
Alexander Rose
bb9acaaa9c fix intra-interactions visual doubly transformed 2020-05-18 14:13:40 -07:00
Alexander Rose
fc10b9bf7b ensure rendering after scene changes
- add/remove/update representations
2020-05-18 11:55:15 -07:00
JonStargaryen
5fcb495d24 centroid and extent calculation 2020-05-18 11:40:27 -07:00
Alexander Rose
b2fdcba674 mouse control tweak
- always do camera center/focus on right click
2020-05-18 11:14:07 -07:00
Alexander Rose
0d01948ba9 0.7.1-dev.10 2020-05-18 08:59:56 -07:00
Alexander Rose
c4370670cb changed nucleic trace atom to O3' 2020-05-16 22:21:10 -07:00
Alexander Rose
1b19136c18 remove alpha/opacity from overpaint params
- does not play well with layers and freely assigning colors as it is per representation
2020-05-16 11:52:27 -07:00
Alexander Rose
217e983da8 add transparency to component theme 2020-05-16 11:37:54 -07:00
Alexander Rose
57338bdad1 ui, always delete full component
- one click less, undo to get back
2020-05-15 19:44:46 -07:00
Alexander Rose
0e84bf9513 component ui related tweaks and fixes
- theme reset should only act on selection
- on-screen ui act similar to controls-ui
- stick to component as name consistently
2020-05-15 19:07:05 -07:00
Alexander Rose
0be28cacdf support change of component label 2020-05-15 19:05:05 -07:00
Alexander Rose
017c608439 simplified cmara/focus binding defaults 2020-05-15 16:53:35 -07:00
Alexander Rose
20ee9496e3 add lighten/darken buttons to CombinedColorControl 2020-05-15 16:52:52 -07:00
Alexander Rose
6fd81d0961 0.7.1-dev.9 2020-05-15 12:08:03 -07:00
Alexander Rose
823a68f9bf package updates 2020-05-15 12:05:50 -07:00
Alexander Rose
deab18e805 only apply structure focus for appropriate granularity 2020-05-15 11:53:37 -07:00
Alexander Rose
19016b6730 seperated camera and repr focus more; always do camera focus with primary-alt 2020-05-15 11:39:21 -07:00
Alexander Rose
4319ae251c 0.7.1-dev.8 2020-05-15 10:25:29 -07:00
Alexander Rose
e5920e29b4 improved presets for coarse-grained structures 2020-05-15 09:58:57 -07:00
Alexander Rose
c376ddfc9d Merge branch 'master' of https://github.com/molstar/molstar 2020-05-14 22:59:46 -07:00
Alexander Rose
8fe2d3f724 Merge branch 'master' of https://github.com/molstar/molstar 2020-05-14 22:58:32 -07:00
Alexander Rose
4d7a128528 clip object support for non mesh geometries
- spheres
- lines
- points
- text
2020-05-14 22:57:57 -07:00
Alexander Rose
663ec9695e fixes for structure focus & selection 2020-05-14 17:18:20 -07:00
JonStargaryen
5e6eb7ed49 tmp vis of asa 2020-05-14 16:38:20 -07:00
Alexander Rose
dfaa4dacdb 0.7.1-dev.7 2020-05-14 16:26:27 -07:00
Alexander Rose
f7adb8b589 fix icon typo 2020-05-14 16:24:50 -07:00
Alexander Rose
cb6b1bf19d 0.7.1-dev.6 2020-05-14 16:09:37 -07:00
Alexander Rose
27a4e1d7d9 icon tweaks 2020-05-14 16:06:38 -07:00
Alexander Rose
0cba88ad8c 0.7.1-dev.5 2020-05-14 15:50:50 -07:00
Alexander Rose
e535c4efa8 fix expected texture resource count 2020-05-14 15:49:08 -07:00
Alexander Rose
31f58ee110 export LocalStateSnapshots ui classes 2020-05-14 15:44:36 -07:00
JonStargaryen
2a9f6c88a0 modify structure-test 2020-05-14 15:25:11 -07:00
Alexander Rose
feb167dcf8 fix case of DDmanHep and LDmanHep 2020-05-14 11:19:38 -07:00
Alexander Rose
1b53ea846b added 6 more common saccharide names 2020-05-14 10:56:58 -07:00
Alexander Rose
88b9be5fd1 Merge branch 'master' of https://github.com/molstar/molstar 2020-05-14 00:11:52 -07:00
Alexander Rose
89486ea9e2 clip objects & per group clipping
- variants: instance, pixel
2020-05-14 00:08:51 -07:00
Alexander Rose
86c09ead98 added Model helpers
- .hasCarbohydrate
- .hasProtein
- .hasNucleic
2020-05-13 16:40:22 -07:00
Alexander Rose
1f60d887a8 add gap even for consecutive residues if they are not connected 2020-05-13 14:18:24 -07:00
Alexander Rose
a672115505 Merge branch 'master' of https://github.com/molstar/molstar 2020-05-12 19:25:46 -07:00
Alexander Rose
8f54ea137d small tweaks 2020-05-12 19:24:53 -07:00
David Sehnal
4171008c3f apps/Viewer: removed unused async 2020-05-13 02:00:17 +02:00
David Sehnal
3a9c3780ac apps/viewer tweaks
- added loadStructureFromData
- fixed loadStructureFromUrl format param
2020-05-13 01:58:42 +02:00
David Sehnal
fe55f33bd1 mol-plugin-ui: make SVG icons "static" 2020-05-13 01:37:13 +02:00
Alexander Rose
71bc88c041 0.7.1-dev.4 2020-05-12 11:35:31 -07:00
Alexander Rose
a5aadfef0e removed material-ui dependency
- included used icons as svg
2020-05-12 11:29:42 -07:00
Alexander Rose
0b368ef804 removed bcif-static option from structure download action 2020-05-12 09:34:21 -07:00
Alexander Rose
f398993d33 0.7.1-dev.3 2020-05-11 12:21:46 -07:00
Alexander Rose
b6f59ca9c3 package updates
- updated all
- removed unused jest-raw-loader
- removed unused circular-dependency-plugin
- removed unused resolve-url-loader
2020-05-11 12:18:45 -07:00
Alexander Rose
c857c17bb4 removed custom name 'deposited' for structures from model
- use 'model' instead
2020-05-11 11:24:01 -07:00
298 changed files with 20183 additions and 7404 deletions

View File

@@ -5,14 +5,14 @@
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["tsconfig.json", "tsconfig.servers.json"],
"project": ["tsconfig.json", "tsconfig.commonjs.json"],
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/ban-types": "warn",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/class-name-casing": "off",
"indent": "off",
"@typescript-eslint/indent": [

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@ node_modules/
debug.log
npm-debug.log
tsconfig.tsbuildinfo
tsconfig.commonjs.tsbuildinfo
*.sublime-workspace
.idea

View File

@@ -1 +1 @@
tsconfig.servers.buildinfo
tsconfig.commonjs.buildinfo

View File

@@ -14,6 +14,5 @@ before_install:
node_js:
- "12"
- "10"
- "8"
before_script:
- export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start

View File

@@ -41,7 +41,7 @@ Moreover, the project contains the implementation of `servers`, including
- `servers/volume` A tool for accessing volumetric experimental data related to molecular structures.
- `servers/plugin-state` A basic server to store Mol* Plugin states.
The project also contains performance tests (`perf-tests`), `examples`, and basic proof of concept `apps` (CIF to BinaryCIF converter and JSON domain annotation to CIF converter).
The project also contains performance tests (`perf-tests`), `examples`, and basic proof of concept `cli` apps (CIF to BinaryCIF converter and JSON domain annotation to CIF converter).
## Previous Work
This project builds on experience from previous solutions:
@@ -90,19 +90,23 @@ and navigate to `build/viewer`
### Code generation
**CIF schemas**
node ./lib/apps/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/mmcif.ts -p mmCIF
node ./lib/apps/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/ccd.ts -p CCD
node ./lib/apps/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/bird.ts -p BIRD
node ./lib/apps/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/cif-core.ts -p CifCore -aa
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/mmcif.ts -p mmCIF
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/ccd.ts -p CCD
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/bird.ts -p BIRD
node ./lib/commonjs/cli/cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/cif-core.ts -p CifCore -aa
**Lipid names**
node lib/commonjs/cli/lipid-params -o src/mol-model/structure/model/types/lipids.ts
**GraphQL schemas**
./node_modules/.bin/graphql-codegen -c ./src/extensions/rcsb/graphql/codegen.yml
node node_modules//@graphql-codegen/cli/bin -c src/extensions/rcsb/graphql/codegen.yml
### Other scripts
**Create chem comp bond table**
node --max-old-space-size=4096 lib/apps/chem-comp-bond/create-table.js build/data/ccb.bcif -b
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-bond/create-table.js build/data/ccb.bcif -b
**Test model server**
@@ -120,7 +124,7 @@ To see all available commands, use ``node lib/servers/model/preprocess -h``.
Or
node ./lib/apps/cif2bcif
node lib/commonjs/cli/cif2bcif
## Development

View File

@@ -0,0 +1,27 @@
* Cyclic polymers (1sfi, 6dny, 1HVZ)
* B-DNA (1bna)
* Missing carbonyl oxygen (1gfl)
* Mono-saccharides with alt locs (1B5F)
* Microheterogeneity
* Protein (1EJG, 3NIR)
* DNA (3VOK)
* PNA: peptide nucleic acid (5eme, 1xj9)
* Peptide derived residues
* GFP chromophores (5Z6Y)
* Nucleotides that dont have a parent base set, i.e. detect purine/pyrimidine from geometry (THX in 1AUL, OMC in e.g. 5D3G)
* Bases with modified ring atoms
* DZ has C1 instead of N1 (e.g. 6I4N)
* DP has N5 instead of C5 and C7 instead of N7 (e.g. 6I4N)
* Beta & Gamma peptides (e.g. 1GAC, 6PQF)
* Mixed (heterogeneous) all-atom/trace-only RNA model (1JGQ)
* Polymers with residues with missing trace atoms (e.g. 2QFJ)
* Modified RNA bases (1y26, 5L4O)
* Discontinuous chains, i.e. gaps in the sequence (3sn6)
* Lots of sheets (1cbs)
* DNA (2np2, 1d66)
* C-alpha only (2rcj)
* Not cyclic, but termini are backbone-only and within distance but seqIds are not compatible (6SW3)
* Close backbone atoms but not linked (e.g. 4HIV)
* Non-standard residues
* Protein (1BRR, 5Z6Y)
* DNA (5D3G)

View File

@@ -54,12 +54,12 @@ Sometimes nodejs might run into problems with memory. This is usually resolved b
## Preprocessor
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. ``node lib/servers/servers/model/preprocess`` or ``model-server-preprocess`` binary from the NPM package.
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. ``node lib/commonjs/servers/model/preprocess`` or ``model-server-preprocess`` binary from the NPM package.
## Local Mode
The server can be run in local/file based mode using ``node lib/servers/servers/model/query`` (``model-server-query`` binary from the NPM package).
The server can be run in local/file based mode using ``node lib/commonjs/servers/model/query`` (``model-server-query`` binary from the NPM package).
Custom Properties
=================

View File

@@ -28,7 +28,7 @@ npm run build-tsc
and run the server by
```
node lib/servers/servers/volume/server
node lib/commonjs/servers/volume/server
```
## From NPM
@@ -60,11 +60,11 @@ Sometimes nodejs might run into problems with memory. This is usually resolved b
## Preparing the Data
For the server to work, CCP4/MAP (models 0, 1, 2 are supported) input data need to be converted into a custom block format.
To achieve this, use the ``pack`` application (``node lib/servers/servers/volume/pack`` or ``volume-server-pack`` binary from the NPM package).
To achieve this, use the ``pack`` application (``node lib/commonjs/servers/volume/pack`` or ``volume-server-pack`` binary from the NPM package).
## Local Mode
The program ``lib/servers/servers/volume/pack`` (``volume-server-query`` in NPM package) can be used to query the data without running a http server.
The program ``lib/commonjs/servers/volume/pack`` (``volume-server-query`` in NPM package) can be used to query the data without running a http server.
## Navigating the Source Code

4820
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "0.7.1-dev.2",
"version": "1.1.2",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -16,7 +16,7 @@
"test": "npm run lint && jest",
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
"build-viewer": "npm run build-tsc && npm run build-extra && npm run build-webpack-viewer",
"build-tsc": "tsc --incremental && tsc --build tsconfig.servers.json --incremental",
"build-tsc": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\"",
"build-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/",
"build-webpack": "webpack --mode production --config ./webpack.config.production.js",
"build-webpack-viewer": "webpack --mode production --config ./webpack.config.viewer.js",
@@ -24,16 +24,16 @@
"watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"",
"watch-viewer-debug": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer-debug\"",
"watch-tsc": "tsc --watch --incremental",
"watch-servers": "tsc --build tsconfig.servers.json --watch --incremental",
"watch-servers": "tsc --build tsconfig.commonjs.json --watch --incremental",
"watch-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/ --watch",
"watch-webpack": "webpack -w --mode development --display minimal",
"watch-webpack-viewer": "webpack -w --mode development --display errors-only --info-verbosity verbose --config ./webpack.config.viewer.js",
"watch-webpack-viewer-debug": "webpack -w --mode development --display errors-only --info-verbosity verbose --config ./webpack.config.viewer.debug.js",
"serve": "http-server -p 1338",
"model-server": "node lib/servers/servers/model/server.js",
"model-server-watch": "nodemon --watch lib lib/servers/servers/model/server.js",
"volume-server-test": "node lib/servers/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
"plugin-state": "node lib/servers/servers/plugin-state/index.js",
"model-server": "node lib/commonjs/servers/model/server.js",
"model-server-watch": "nodemon --watch lib lib/commonjs/servers/model/server.js",
"volume-server-test": "node lib/commonjs/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
"plugin-state": "node lib/commonjs/servers/plugin-state/index.js",
"preversion": "npm run test",
"version": "npm run build",
"postversion": "git push && git push --tags"
@@ -43,14 +43,14 @@
"build/viewer/"
],
"bin": {
"cif2bcif": "lib/apps/cif2bcif/index.js",
"cifschema": "lib/apps/cifschema/index.js",
"model-server": "lib/servers/servers/model/server.js",
"model-server-query": "lib/servers/servers/model/query.js",
"model-server-preprocess": "lib/servers/servers/model/preprocess.js",
"volume-server": "lib/servers/servers/volume/server.js",
"volume-server-query": "lib/servers/servers/volume/query.js",
"volume-server-pack": "lib/servers/servers/volume/pack.js"
"cif2bcif": "lib/commonjs/cli/cif2bcif/index.js",
"cifschema": "lib/commonjs/cli/cifschema/index.js",
"model-server": "lib/commonjs/servers/model/server.js",
"model-server-query": "lib/commonjs/servers/model/query.js",
"model-server-preprocess": "lib/commonjs/servers/model/preprocess.js",
"volume-server": "lib/commonjs/servers/volume/server.js",
"volume-server-query": "lib/commonjs/servers/volume/query.js",
"volume-server-pack": "lib/commonjs/servers/volume/pack.js"
},
"nodemonConfig": {
"ignoreRoot": [
@@ -79,72 +79,70 @@
"contributors": [
"Alexander Rose <alexander.rose@weirdbyte.de>",
"David Sehnal <david.sehnal@gmail.com>",
"Sebastian Bittrich <sebastian.bittrich@rcsb.org>"
"Sebastian Bittrich <sebastian.bittrich@rcsb.org>",
"Ludovic Autin <autin@scripps.edu>",
"Michal Malý <michal.maly@ibt.cas.cz>",
"Jiří Černý <jiri.cerny@ibt.cas.cz>"
],
"license": "MIT",
"devDependencies": {
"@graphql-codegen/add": "^1.13.3",
"@graphql-codegen/cli": "^1.13.3",
"@graphql-codegen/time": "^1.13.3",
"@graphql-codegen/typescript": "^1.13.3",
"@graphql-codegen/typescript-graphql-files-modules": "^1.13.3",
"@graphql-codegen/typescript-graphql-request": "^1.13.3",
"@graphql-codegen/typescript-operations": "^1.13.3",
"@graphql-codegen/add": "^1.14.0",
"@graphql-codegen/cli": "^1.14.0",
"@graphql-codegen/time": "^1.14.0",
"@graphql-codegen/typescript": "^1.14.0",
"@graphql-codegen/typescript-graphql-files-modules": "^1.14.0",
"@graphql-codegen/typescript-graphql-request": "^1.14.0",
"@graphql-codegen/typescript-operations": "^1.14.0",
"@types/cors": "^2.8.6",
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"@typescript-eslint/eslint-plugin": "^3.0.0",
"@typescript-eslint/parser": "^3.0.0",
"benchmark": "^2.1.4",
"circular-dependency-plugin": "^5.2.0",
"concurrently": "^5.1.0",
"concurrently": "^5.2.0",
"cpx2": "^2.0.0",
"css-loader": "^3.5.3",
"eslint": "^6.8.0",
"eslint": "^7.0.0",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^6.0.0",
"fs-extra": "^9.0.0",
"graphql": "^15.0.0",
"http-server": "^0.12.1",
"jest": "^25.4.0",
"jest-raw-loader": "^1.0.1",
"http-server": "^0.12.3",
"jest": "^26.0.1",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.14.0",
"node-sass": "^4.14.1",
"raw-loader": "^4.0.1",
"resolve-url-loader": "^3.1.1",
"sass-loader": "^8.0.2",
"simple-git": "^1.132.0",
"style-loader": "^1.2.0",
"ts-jest": "^25.4.0",
"typescript": "^3.8.3",
"simple-git": "^2.5.0",
"style-loader": "^1.2.1",
"ts-jest": "^26.0.0",
"typescript": "^3.9.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-version-file-plugin": "^0.4.0"
},
"dependencies": {
"@material-ui/core": "^4.9.11",
"@material-ui/icons": "^4.9.1",
"@types/argparse": "^1.0.38",
"@types/benchmark": "^1.0.31",
"@types/benchmark": "^1.0.33",
"@types/compression": "1.7.0",
"@types/express": "^4.17.6",
"@types/jest": "^25.2.1",
"@types/node": "^13.13.2",
"@types/jest": "^25.2.3",
"@types/node": "^14.0.5",
"@types/node-fetch": "^2.5.7",
"@types/react": "^16.9.34",
"@types/react-dom": "^16.9.6",
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
"@types/swagger-ui-dist": "3.0.5",
"argparse": "^1.0.10",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.17.1",
"immer": "^6.0.3",
"immer": "^6.0.6",
"immutable": "^3.8.2",
"node-fetch": "^2.6.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"rxjs": "^6.5.5",
"swagger-ui-dist": "^3.25.0",
"tslib": "^1.11.1",
"swagger-ui-dist": "^3.25.4",
"tslib": "^2.0.0",
"util.promisify": "^1.0.1",
"xhr2": "^0.2.0"
}

View File

@@ -23,6 +23,9 @@ import { ObjectKeys } from '../../mol-util/type-helpers';
import { PluginState } from '../../mol-plugin/state';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
require('mol-plugin-ui/skin/light.scss');
@@ -31,9 +34,11 @@ export { setProductionMode, setDebugMode } from '../../mol-util/debug';
const Extensions = {
'cellpack': PluginSpec.Behavior(CellPack),
'dnatco-confal-pyramids': PluginSpec.Behavior(DnatcoConfalPyramids),
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
'rcsb-assembly-symmetry': PluginSpec.Behavior(RCSBAssemblySymmetry),
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport)
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation)
};
const DefaultViewerOptions = {
@@ -47,6 +52,8 @@ const DefaultViewerOptions = {
layoutShowLeftPanel: true,
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
@@ -59,7 +66,7 @@ type ViewerOptions = typeof DefaultViewerOptions;
export class Viewer {
plugin: PluginContext
constructor(elementId: string, options: Partial<ViewerOptions> = {}) {
constructor(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
const o = { ...DefaultViewerOptions, ...options };
const spec: PluginSpec = {
@@ -89,6 +96,8 @@ export class Viewer {
},
config: [
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
[PluginConfig.State.DefaultServer, o.pluginStateServer],
@@ -99,21 +108,23 @@ export class Viewer {
]
};
const element = document.getElementById(elementId);
if (!element) throw new Error(`Could not get element with id '${elementId}'`);
const element = typeof elementOrId === 'string'
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
this.plugin = createPlugin(element, spec);
}
async setRemoteSnapshot(id: string) {
setRemoteSnapshot(id: string) {
const url = `${this.plugin.config.get(PluginConfig.State.CurrentServer)}/get/${id}`;
await PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
return PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
}
async loadSnapshotFromUrl(url: string, type: PluginState.SnapshotType) {
await PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
loadSnapshotFromUrl(url: string, type: PluginState.SnapshotType) {
return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
}
async loadStructureFromUrl(url: string, format = 'cif', isBinary = false) {
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
@@ -128,7 +139,13 @@ export class Viewer {
}));
}
async loadPdb(pdb: string) {
async loadStructureFromData(data: string | number[], format: BuiltInTrajectoryFormat, options?: { dataLabel?: string }) {
const _data = await this.plugin.builders.data.rawData({ data, label: options?.dataLabel });
const trajectory = await this.plugin.builders.structure.parseTrajectory(_data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default');
}
loadPdb(pdb: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
const provider = this.plugin.config.get(PluginConfig.Download.DefaultPdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
@@ -148,7 +165,7 @@ export class Viewer {
}));
}
async loadPdbDev(pdbDev: string) {
loadPdbDev(pdbDev: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
@@ -164,7 +181,7 @@ export class Viewer {
}));
}
async loadEmdb(emdb: string) {
loadEmdb(emdb: string) {
const provider = this.plugin.config.get(PluginConfig.Download.DefaultEmdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
source: {

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
@@ -219,7 +220,7 @@ async function run(out: string, binary = false) {
const TABLE_NAME = 'CHEM_COMP_BONDS';
const DATA_DIR = path.join(__dirname, '..', '..', '..', 'build/data');
const DATA_DIR = path.join(__dirname, '..', '..', '..', '..', 'build/data');
const CCD_PATH = path.join(DATA_DIR, 'components.cif');
const PVCD_PATH = path.join(DATA_DIR, 'aa-variants-v1.cif');
const CCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif';

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env node
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env node
/**
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
@@ -159,7 +160,7 @@ async function ensureDicAvailable(dicPath: string, dicUrl: string) {
}
}
const DIC_DIR = path.resolve(__dirname, '../../../build/dics/');
const DIC_DIR = path.resolve(__dirname, '../../../../build/dics/');
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`;
@@ -237,22 +238,22 @@ switch (args.preset) {
case 'mmCIF':
args.name = 'mmCIF';
args.dic = 'mmCIF';
args.fieldNamesPath = path.resolve(__dirname, '../../../data/cif-field-names/mmcif-field-names.csv');
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/mmcif-field-names.csv');
break;
case 'CCD':
args.name = 'CCD';
args.dic = 'mmCIF';
args.fieldNamesPath = path.resolve(__dirname, '../../../data/cif-field-names/ccd-field-names.csv');
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/ccd-field-names.csv');
break;
case 'BIRD':
args.name = 'BIRD';
args.dic = 'mmCIF';
args.fieldNamesPath = path.resolve(__dirname, '../../../data/cif-field-names/bird-field-names.csv');
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/bird-field-names.csv');
break;
case 'CifCore':
args.name = 'CifCore';
args.dic = 'CifCore';
args.fieldNamesPath = path.resolve(__dirname, '../../../data/cif-field-names/cif-core-field-names.csv');
args.fieldNamesPath = path.resolve(__dirname, '../../../../data/cif-field-names/cif-core-field-names.csv');
break;
}

View File

@@ -17,15 +17,15 @@ function header (name: string, info: string, moldataImportPath: string) {
* @author molstar/ciftools package
*/
import { Database, Column } from '${moldataImportPath}/db'
import { Database, Column } from '${moldataImportPath}/db';
import Schema = Column.Schema`;
import Schema = Column.Schema;`;
}
function footer (name: string) {
return `
export type ${name}_Schema = typeof ${name}_Schema;
export interface ${name}_Database extends Database<${name}_Schema> {}`;
export interface ${name}_Database extends Database<${name}_Schema> {};`;
}
function getTypeShorthands(schema: Database, fields?: Filter) {
@@ -122,7 +122,7 @@ export function generate (name: string, info: string, schema: Database, fields:
});
codeLines.push(' },');
});
codeLines.push('}');
codeLines.push('};');
if (addAliases) {
codeLines.push('');
@@ -144,7 +144,7 @@ export function generate (name: string, info: string, schema: Database, fields:
});
codeLines.push(' ],');
});
codeLines.push('}');
codeLines.push('};');
}
return `${header(name, info, moldataImportPath)}\n\n${getTypeShorthands(schema, fields)}\n\n${codeLines.join('\n')}\n${footer(name)}`;

View File

@@ -0,0 +1,88 @@
#!/usr/bin/env node
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
import * as fs from 'fs';
import * as path from 'path';
import fetch from 'node-fetch';
import { UniqueArray } from '../../mol-data/generic';
const LIPIDS_DIR = path.resolve(__dirname, '../../../../build/lipids/');
const MARTINI_LIPIDS_PATH = path.resolve(LIPIDS_DIR, 'martini_lipids.itp');
const MARTINI_LIPIDS_URL = 'http://www.cgmartini.nl/images/parameters/lipids/Collections/martini_v2.0_lipids_all_201506.itp';
async function ensureAvailable(path: string, url: string) {
if (FORCE_DOWNLOAD || !fs.existsSync(path)) {
const name = url.substr(url.lastIndexOf('/') + 1);
console.log(`downloading ${name}...`);
const data = await fetch(url);
if (!fs.existsSync(LIPIDS_DIR)) {
fs.mkdirSync(LIPIDS_DIR);
}
fs.writeFileSync(path, await data.text());
console.log(`done downloading ${name}`);
}
}
async function ensureLipidsAvailable() { await ensureAvailable(MARTINI_LIPIDS_PATH, MARTINI_LIPIDS_URL); }
async function run(out: string) {
await ensureLipidsAvailable();
const lipidsItpStr = fs.readFileSync(MARTINI_LIPIDS_PATH, 'utf8');
const lipids = UniqueArray.create<string>();
const reLipid = /\[moleculetype\]\n; molname nrexcl\n +([a-zA-Z]{3,5})/g;
let m: RegExpExecArray | null;
while ((m = reLipid.exec(lipidsItpStr)) !== null) {
const v = m[0].substr(m[0].lastIndexOf(' ') + 1);
UniqueArray.add(lipids, v, v);
}
const lipidNames = JSON.stringify(lipids.array);
if (out) {
const output = `/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated lipid params file. Names extracted from Martini FF lipids itp.
*
* @author molstar/lipid-params cli
*/
export const LipidNames = new Set(${lipidNames.replace(/"/g, "'").replace(/,/g, ', ')});
`;
fs.writeFileSync(out, output);
} else {
console.log(lipidNames);
}
}
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Create lipid params (from martini lipids itp)'
});
parser.addArgument([ '--out', '-o' ], {
help: 'Generated lipid params output path, if not given printed to stdout'
});
parser.addArgument([ '--forceDownload', '-f' ], {
action: 'storeTrue',
help: 'Force download of martini lipids itp'
});
interface Args {
out: string
forceDownload: boolean
}
const args: Args = parser.parseArgs();
const FORCE_DOWNLOAD = args.forceDownload;
run(args.out || '').catch(e => {
console.error(e);
});

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
@@ -33,20 +34,22 @@ export async function readCifFile(path: string) {
export function atomLabel(model: Model, aI: number) {
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy;
const { label_atom_id } = atoms;
const { label_comp_id, label_seq_id } = residues;
const { label_atom_id, label_comp_id } = atoms;
const { label_seq_id } = residues;
const { label_asym_id } = chains;
const rI = residueAtomSegments.index[aI];
const cI = chainAtomSegments.index[aI];
return `${label_asym_id.value(cI)} ${label_comp_id.value(rI)} ${label_seq_id.value(rI)} ${label_atom_id.value(aI)}`;
return `${label_asym_id.value(cI)} ${label_comp_id.value(aI)} ${label_seq_id.value(rI)} ${label_atom_id.value(aI)}`;
}
export function residueLabel(model: Model, rI: number) {
const { residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy;
const { label_comp_id, label_seq_id } = residues;
const { atoms, residues, chains, residueAtomSegments, chainAtomSegments } = model.atomicHierarchy;
const { label_comp_id } = atoms;
const { label_seq_id } = residues;
const { label_asym_id } = chains;
const cI = chainAtomSegments.index[residueAtomSegments.offsets[rI]];
return `${label_asym_id.value(cI)} ${label_comp_id.value(rI)} ${label_seq_id.value(rI)}`;
const aI = residueAtomSegments.offsets[rI];
const cI = chainAtomSegments.index[aI];
return `${label_asym_id.value(cI)} ${label_comp_id.value(aI)} ${label_seq_id.value(rI)}`;
}
export function printSecStructure(model: Model) {

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env node
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*

View File

@@ -69,15 +69,8 @@
$('format').value = format;
$('format').onchange = function (e) { format = e.target.value; }
// var url = 'https://www.ebi.ac.uk/pdbe/entry-files/pdb' + pdbId + '.ent';
// var format = 'pdb';
// var assemblyId = 'deposited';
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
BasicMolStarWrapper.setBackground(0xffffff);
// BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId });
// BasicMolStarWrapper.toggleSpin();
addControl('Load Asym Unit', () => BasicMolStarWrapper.load({ url: url, format: format }));
addControl('Load Assembly', () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId }));

View File

@@ -56,7 +56,13 @@ class BasicWrapper {
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default', {
structure: assemblyId ? { name: 'assembly', params: { id: assemblyId } } : { name: 'deposited', params: { } },
structure: assemblyId ? {
name: 'assembly',
params: { id: assemblyId }
} : {
name: 'model',
params: { }
},
showUnitcell: false,
representationPreset: 'auto'
});

View File

@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<title>Mol* Docking Viewer</title>
<style>
#app {
position: absolute;
left: 100px;
top: 100px;
width: 800px;
height: 600px;
}
</style>
<link rel="stylesheet" type="text/css" href="molstar.css" />
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="./index.js"></script>
<script type="text/javascript">
var viewer = new DockingViewer('app', {
layoutIsExpanded: false,
layoutShowControls: false,
layoutShowRemoteState: false,
layoutShowSequence: true,
layoutShowLog: false,
layoutShowLeftPanel: true,
viewportShowExpand: true,
viewportShowControls: false,
viewportShowSettings: false,
viewportShowSelectionMode: false,
viewportShowAnimation: false,
});
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();
viewer.loadStructuresFromUrlsAndMerge([
{ url: pdbqt, format: 'pdbqt' },
{ url: mol2, format: 'mol2' }
]);
</script>
</body>
</html>

View File

@@ -0,0 +1,263 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import '../../mol-util/polyfill';
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
import './index.html';
import { PluginContext } from '../../mol-plugin/context';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginSpec } from '../../mol-plugin/spec';
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
import { PluginConfig } from '../../mol-plugin/config';
import { Asset } from '../../mol-util/assets';
import { ObjectKeys } from '../../mol-util/type-helpers';
import { PluginState } from '../../mol-plugin/state';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { Structure } from '../../mol-model/structure';
import { PluginStateTransform, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Task } from '../../mol-task';
import { StateObject } from '../../mol-state';
import { ViewportComponent, StructurePreset } from './viewport';
import { PluginBehaviors } from '../../mol-plugin/behavior';
import { ColorNames } from '../../mol-util/color/names';
require('mol-plugin-ui/skin/light.scss');
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setProductionMode, setDebugMode } from '../../mol-util/debug';
const DefaultViewerOptions = {
extensions: ObjectKeys({}),
layoutIsExpanded: true,
layoutShowControls: true,
layoutShowRemoteState: true,
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
layoutShowSequence: true,
layoutShowLog: true,
layoutShowLeftPanel: true,
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
};
type ViewerOptions = typeof DefaultViewerOptions;
class Viewer {
plugin: PluginContext
constructor(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
const o = { ...DefaultViewerOptions, ...options };
const spec: PluginSpec = {
actions: [...DefaultPluginSpec.actions],
behaviors: [
PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci, { mark: false }),
PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci),
PluginSpec.Behavior(PluginBehaviors.CustomProps.StructureInfo),
PluginSpec.Behavior(PluginBehaviors.CustomProps.Interactions),
PluginSpec.Behavior(PluginBehaviors.CustomProps.SecondaryStructure),
],
animations: [...DefaultPluginSpec.animations || []],
customParamEditors: DefaultPluginSpec.customParamEditors,
layout: {
initial: {
isExpanded: o.layoutIsExpanded,
showControls: o.layoutShowControls,
controlsDisplay: o.layoutControlsDisplay,
},
controls: {
...DefaultPluginSpec.layout && DefaultPluginSpec.layout.controls,
top: o.layoutShowSequence ? undefined : 'none',
bottom: o.layoutShowLog ? undefined : 'none',
left: o.layoutShowLeftPanel ? undefined : 'none',
}
},
components: {
...DefaultPluginSpec.components,
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
viewport: {
view: ViewportComponent
}
},
config: [
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
[PluginConfig.State.DefaultServer, o.pluginStateServer],
[PluginConfig.State.CurrentServer, o.pluginStateServer],
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider]
]
};
const element = typeof elementOrId === 'string'
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
this.plugin = createPlugin(element, spec);
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
renderer: {
...this.plugin.canvas3d!.props.renderer,
backgroundColor: ColorNames.white,
},
camera: {
...this.plugin.canvas3d!.props.camera,
helper: { axes: { name: 'off', params: {} } }
}
} });
}
setRemoteSnapshot(id: string) {
const url = `${this.plugin.config.get(PluginConfig.State.CurrentServer)}/get/${id}`;
return PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
}
loadSnapshotFromUrl(url: string, type: PluginState.SnapshotType) {
return PluginCommands.State.Snapshots.OpenUrl(this.plugin, { url, type });
}
loadStructureFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'url',
params: {
url: Asset.Url(url),
format: format as any,
isBinary,
options: params.source.params.options,
}
}
}));
}
async loadStructuresFromUrlsAndMerge(sources: { url: string, format: BuiltInTrajectoryFormat, isBinary?: boolean }[]) {
const structures: { ref: string }[] = [];
for (const { url, format, isBinary } of sources) {
const data = await this.plugin.builders.data.download({ url, isBinary });
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
const model = await this.plugin.builders.structure.createModel(trajectory);
const modelProperties = await this.plugin.builders.structure.insertModelProperties(model);
const structure = await this.plugin.builders.structure.createStructure(modelProperties || model);
const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
structures.push({ ref: structureProperties?.ref || structure.ref });
}
const dependsOn = structures.map(({ ref }) => ref);
const data = this.plugin.state.data.build().toRoot().apply(MergeStructures, { structures }, { dependsOn });
const structure = await data.commit();
const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
await this.plugin.builders.structure.representation.applyPreset(structureProperties || structure, StructurePreset);
}
async loadStructureFromData(data: string | number[], format: BuiltInTrajectoryFormat, options?: { dataLabel?: string }) {
const _data = await this.plugin.builders.data.rawData({ data, label: options?.dataLabel });
const trajectory = await this.plugin.builders.structure.parseTrajectory(_data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default');
}
loadPdb(pdb: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
const provider = this.plugin.config.get(PluginConfig.Download.DefaultPdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'pdb' as const,
params: {
provider: {
id: pdb,
server: {
name: provider,
params: PdbDownloadProvider[provider].defaultValue as any
}
},
options: params.source.params.options,
}
}
}));
}
loadPdbDev(pdbDev: 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: 'pdb-dev' as const,
params: {
provider: {
id: pdbDev,
encoding: 'bcif',
},
options: params.source.params.options,
}
}
}));
}
loadEmdb(emdb: string) {
const provider = this.plugin.config.get(PluginConfig.Download.DefaultEmdbProvider)!;
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadDensity, {
source: {
name: 'pdb-emd-ds' as const,
params: {
provider: {
id: emdb,
server: provider,
},
detail: 3,
}
}
}));
}
}
type MergeStructures = typeof MergeStructures
const MergeStructures = PluginStateTransform.BuiltIn({
name: 'merge-structures',
display: { name: 'Merge Structures', description: 'Merge Structure' },
from: PSO.Root,
to: PSO.Molecule.Structure,
params: {
structures: PD.ObjectList({
ref: PD.Text('')
}, ({ ref }) => ref, { isHidden: true })
}
})({
apply({ params, dependencies }) {
return Task.create('Merge Structures', async ctx => {
if (params.structures.length === 0) return StateObject.Null;
const first = dependencies![params.structures[0].ref].data as Structure;
const builder = Structure.Builder({ masterModel: first.models[0] });
for (const { ref } of params.structures) {
const s = dependencies![ref].data as Structure;
for (const unit of s.units) {
// TODO invariantId
builder.addUnit(unit.kind, unit.model, unit.conformation.operator, unit.elements, unit.traits);
}
}
const structure = builder.getStructure();
return new PSO.Molecule.Structure(structure, { label: 'Merged Structure' });
});
}
});
(window as any).DockingViewer = Viewer;

View File

@@ -0,0 +1,254 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react';
import { PluginUIComponent } from '../../mol-plugin-ui/base';
import { Viewport, ViewportControls } from '../../mol-plugin-ui/viewport';
import { BackgroundTaskProgress } from '../../mol-plugin-ui/task';
import { LociLabels } from '../../mol-plugin-ui/controls';
import { Toasts } from '../../mol-plugin-ui/toast';
import { Button } from '../../mol-plugin-ui/controls/common';
import { StructureRepresentationPresetProvider, presetStaticComponent } from '../../mol-plugin-state/builder/structure/representation-preset';
import { StateObjectRef } from '../../mol-state';
import { StructureSelectionQueries, StructureSelectionQuery } from '../../mol-plugin-state/helpers/structure-selection-query';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { InteractionsRepresentationProvider } from '../../mol-model-props/computed/representations/interactions';
import { InteractionTypeColorThemeProvider } from '../../mol-model-props/computed/themes/interaction-type';
import { compile } from '../../mol-script/runtime/query/compiler';
import { StructureSelection, QueryContext, Structure } from '../../mol-model/structure';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginContext } from '../../mol-plugin/context';
function shinyStyle(plugin: PluginContext) {
return PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
renderer: {
...plugin.canvas3d!.props.renderer,
style: { name: 'plastic', params: {} },
},
postprocessing: {
...plugin.canvas3d!.props.postprocessing,
occlusion: { name: 'off', params: {} },
outline: { name: 'off', params: {} }
}
} });
}
function occlusionStyle(plugin: PluginContext) {
return PluginCommands.Canvas3D.SetSettings(plugin, { settings: {
renderer: {
...plugin.canvas3d!.props.renderer,
style: { name: 'flat', params: {} }
},
postprocessing: {
...plugin.canvas3d!.props.postprocessing,
occlusion: { name: 'on', params: {
kernelSize: 8,
bias: 0.8,
radius: 64
} },
outline: { name: 'on', params: {
scale: 1.0,
threshold: 0.8
} }
}
} });
}
const ligandPlusSurroundings = StructureSelectionQuery('Surrounding Residues (5 \u212B) of Ligand plus Ligand itself', MS.struct.modifier.union([
MS.struct.modifier.includeSurroundings({
0: StructureSelectionQueries.ligand.expression,
radius: 5,
'as-whole-residues': true
})
]));
const ligandSurroundings = StructureSelectionQuery('Surrounding Residues (5 \u212B) of Ligand', MS.struct.modifier.union([
MS.struct.modifier.exceptBy({
0: ligandPlusSurroundings.expression,
by: StructureSelectionQueries.ligand.expression
})
]));
const PresetParams = {
...StructureRepresentationPresetProvider.CommonParams,
};
export const StructurePreset = StructureRepresentationPresetProvider({
id: 'preset-structure',
display: { name: 'Structure' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
if (!structureCell) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
polymer: await presetStaticComponent(plugin, structureCell, 'polymer'),
};
const { update, builder, typeParams, color } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.26 }, color }, { tag: 'ligand' }),
polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams }, color }, { tag: 'polymer' }),
};
await update.commit({ revertOnError: true });
await shinyStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'residue' });
return { components, representations };
}
});
export const IllustrativePreset = StructureRepresentationPresetProvider({
id: 'preset-illustrative',
display: { name: 'Illustrative' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
if (!structureCell) return {};
const components = {
all: await presetStaticComponent(plugin, structureCell, 'all')
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
all: builder.buildRepresentation(update, components.all, { type: 'spacefill', typeParams: { ...typeParams }, color: 'illustrative' }, { tag: 'all' }),
};
await update.commit({ revertOnError: true });
await occlusionStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'residue' });
return { components, representations };
}
});
const PocketPreset = StructureRepresentationPresetProvider({
id: 'preset-pocket',
display: { name: 'Pocket' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
surroundings: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandSurroundings, `surroundings`),
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.26 }, color: 'partial-charge' }, { tag: 'ligand' }),
surroundings: builder.buildRepresentation(update, components.surroundings, { type: 'molecular-surface', typeParams: { ...typeParams, includeParent: true, quality: 'custom', resolution: 0.2, doubleSided: true }, color: 'partial-charge' }, { tag: 'surroundings' }),
};
await update.commit({ revertOnError: true });
await shinyStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'element' });
const compiled = compile<StructureSelection>(StructureSelectionQueries.ligand.expression);
const result = compiled(new QueryContext(structure));
const selection = StructureSelection.unionStructure(result);
plugin.managers.camera.focusLoci(Structure.toStructureElementLoci(selection));
return { components, representations };
}
});
const InteractionsPreset = StructureRepresentationPresetProvider({
id: 'preset-interactions',
display: { name: 'Interactions' },
params: () => PresetParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
selection: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandPlusSurroundings, `selection`)
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.26 }, color: 'partial-charge' }, { tag: 'ligand' }),
ballAndStick: builder.buildRepresentation(update, components.selection, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.1, sizeAspectRatio: 1 }, color: 'partial-charge' }, { tag: 'ball-and-stick' }),
interactions: builder.buildRepresentation(update, components.selection, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }),
};
await update.commit({ revertOnError: true });
await shinyStyle(plugin);
plugin.managers.interactivity.setProps({ granularity: 'element' });
const compiled = compile<StructureSelection>(StructureSelectionQueries.ligand.expression);
const result = compiled(new QueryContext(structure));
const selection = StructureSelection.unionStructure(result);
plugin.managers.camera.focusLoci(Structure.toStructureElementLoci(selection));
return { components, representations };
}
});
export class ViewportComponent extends PluginUIComponent {
structurePreset = () => {
this.plugin.managers.structure.component.applyPreset(
this.plugin.managers.structure.hierarchy.selection.structures,
StructurePreset
);
}
illustrativePreset = () => {
this.plugin.managers.structure.component.applyPreset(
this.plugin.managers.structure.hierarchy.selection.structures,
IllustrativePreset
);
}
pocketPreset = () => {
this.plugin.managers.structure.component.applyPreset(
this.plugin.managers.structure.hierarchy.selection.structures,
PocketPreset
);
}
interactionsPreset = () => {
this.plugin.managers.structure.component.applyPreset(
this.plugin.managers.structure.hierarchy.selection.structures,
InteractionsPreset
);
}
render() {
const VPControls = this.plugin.spec.components?.viewport?.controls || ViewportControls;
return <>
<Viewport />
<div className='msp-viewport-top-left-controls'>
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.structurePreset} >Structure</Button>
</div>
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.illustrativePreset}>Illustrative</Button>
</div>
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.pocketPreset}>Pocket</Button>
</div>
<div style={{ marginBottom: '4px' }}>
<Button onClick={this.interactionsPreset}>Interactions</Button>
</div>
</div>
<VPControls />
<BackgroundTaskProgress />
<div className='msp-highlight-toast-wrapper'>
<LociLabels />
<Toasts />
</div>
</>;
}
}

View File

@@ -105,7 +105,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: 'deposited', 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' });

View File

@@ -58,7 +58,7 @@ export namespace ModelInfo {
const entityType = model.entities.data.type.value(eI);
if (entityType !== 'non-polymer' && entityType !== 'branched') continue;
const comp_id = model.atomicHierarchy.residues.label_comp_id.value(rI);
const comp_id = model.atomicHierarchy.atoms.label_comp_id.value(residueOffsets[rI]);
let lig = hetMap.get(comp_id);
if (!lig) {

View File

@@ -88,10 +88,6 @@
$('isBinary').checked = isBinary;
$('isBinary').onchange = function (e) { isBinary = !!e.target.checked; };
// var url = 'https://www.ebi.ac.uk/pdbe/entry-files/pdb' + pdbId + '.ent';
// var format = 'pdb';
// var assemblyId = 'deposited';
function loadAndSnapshot(params) {
PluginWrapper.load(params).then(() => {
setTimeout(() => snapshot = PluginWrapper.plugin.state.getSnapshot({ canvas3d: false /* do not save spinning state */ }), 500);

View File

@@ -89,9 +89,12 @@ class MolStarProteopediaWrapper {
private structure(assemblyId: string) {
const model = this.state.build().to(StateElements.Model);
const props = {
type: {
type: assemblyId ? {
name: 'assembly' as const,
params: { id: assemblyId || 'deposited' }
params: { id: assemblyId }
} : {
name: 'model' as const,
params: { }
}
};
@@ -196,7 +199,7 @@ class MolStarProteopediaWrapper {
private emptyLoadedParams: LoadParams = { url: '', format: 'cif', isBinary: false, assemblyId: '' };
private loadedParams: LoadParams = { url: '', format: 'cif', isBinary: false, assemblyId: '' };
async load({ url, format = 'cif', assemblyId = 'deposited', isBinary = false, representationStyle }: LoadParams) {
async load({ url, format = 'cif', assemblyId = '', isBinary = false, representationStyle }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.data;
@@ -220,9 +223,12 @@ class MolStarProteopediaWrapper {
const info = await this.doInfo(true);
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
const props = {
type: {
type: assemblyId ? {
name: 'assembly' as const,
params: { id: asmId || 'deposited' }
params: { id: asmId }
} : {
name: 'model' as const,
params: { }
}
};
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));

View File

@@ -0,0 +1,369 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Structure, StructureElement, StructureProperties } from '../../mol-model/structure';
import { Task, RuntimeContext } from '../../mol-task';
import { CentroidHelper } from '../../mol-math/geometry/centroid-helper';
import { AccessibleSurfaceAreaProvider } from '../../mol-model-props/computed/accessible-surface-area';
import { Vec3 } from '../../mol-math/linear-algebra';
import { getElementMoleculeType } from '../../mol-model/structure/util';
import { MoleculeType } from '../../mol-model/structure/model/types';
import { AccessibleSurfaceArea } from '../../mol-model-props/computed/accessible-surface-area/shrake-rupley';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { MembraneOrientation } from './prop';
interface ANVILContext {
structure: Structure,
numberOfSpherePoints: number,
stepSize: number,
minThickness: number,
maxThickness: number,
asaCutoff: number,
offsets: ArrayLike<number>,
exposed: ArrayLike<boolean>,
centroid: Vec3,
extent: number
};
export const ANVILParams = {
numberOfSpherePoints: PD.Numeric(120, { min: 35, max: 700, step: 1 }, { description: 'Number of spheres/directions to test for membrane placement. Original value is 350.' }),
stepSize: PD.Numeric(1, { min: 0.25, max: 4, step: 0.25 }, { description: 'Thickness of membrane slices that will be tested' }),
minThickness: PD.Numeric(20, { min: 10, max: 30, step: 1}, { description: 'Minimum membrane thickness used during refinement' }),
maxThickness: PD.Numeric(40, { min: 30, max: 50, step: 1}, { description: 'Maximum membrane thickness used during refinement' }),
asaCutoff: PD.Numeric(40, { min: 10, max: 100, step: 1 }, { description: 'Absolute ASA cutoff above which residues will be considered' })
};
export type ANVILParams = typeof ANVILParams
export type ANVILProps = PD.Values<ANVILParams>
/**
* Implements:
* Membrane positioning for high- and low-resolution protein structures through a binary classification approach
* Guillaume Postic, Yassine Ghouzam, Vincent Guiraud, and Jean-Christophe Gelly
* Protein Engineering, Design & Selection, 2015, 15
* doi: 10.1093/protein/gzv063
*/
export function computeANVIL(structure: Structure, props: ANVILProps) {
return Task.create('Compute Membrane Orientation', async runtime => {
return await calculate(runtime, structure, props);
});
}
const l = StructureElement.Location.create(void 0);
const centroidHelper = new CentroidHelper();
function initialize(structure: Structure, props: ANVILProps): ANVILContext {
const { label_atom_id, x, y, z } = StructureProperties.atom;
const elementCount = structure.polymerResidueCount;
centroidHelper.reset();
l.structure = structure;
let offsets = new Int32Array(elementCount);
let exposed = new Array<boolean>(elementCount);
const accessibleSurfaceArea = structure && AccessibleSurfaceAreaProvider.get(structure);
const asa = accessibleSurfaceArea.value!;
const vec = Vec3();
let m = 0;
for (let i = 0, il = structure.units.length; i < il; ++i) {
const unit = structure.units[i];
const { elements } = unit;
l.unit = unit;
for (let j = 0, jl = elements.length; j < jl; ++j) {
const eI = elements[j];
l.element = eI;
// consider only amino acids
if (getElementMoleculeType(unit, eI) !== MoleculeType.Protein) {
continue;
}
// only CA is considered for downstream operations
if (label_atom_id(l) !== 'CA') {
continue;
}
// while iterating use first pass to compute centroid
Vec3.set(vec, x(l), y(l), z(l));
centroidHelper.includeStep(vec);
// keep track of offsets and exposed state to reuse
offsets[m] = structure.serialMapping.getSerialIndex(l.unit, l.element);
exposed[m] = AccessibleSurfaceArea.getValue(l, asa) > props.asaCutoff;
m++;
}
}
// omit potentially empty tail1
offsets = offsets.slice(0, m);
exposed = exposed.slice(0, m);
// calculate centroid and extent
centroidHelper.finishedIncludeStep();
const centroid = centroidHelper.center;
for (let k = 0, kl = offsets.length; k < kl; k++) {
setLocation(l, structure, offsets[k]);
Vec3.set(vec, x(l), y(l), z(l));
centroidHelper.radiusStep(vec);
}
const extent = 1.2 * Math.sqrt(centroidHelper.radiusSq);
return {
...props,
structure: structure,
offsets: offsets,
exposed: exposed,
centroid: centroid,
extent: extent
};
}
export async function calculate(runtime: RuntimeContext, structure: Structure, params: ANVILProps): Promise<MembraneOrientation> {
const { label_comp_id } = StructureProperties.atom;
const ctx = initialize(structure, params);
const initialHphobHphil = HphobHphil.filtered(ctx, label_comp_id);
const initialMembrane = findMembrane(ctx, generateSpherePoints(ctx, ctx.numberOfSpherePoints), initialHphobHphil, label_comp_id);
const alternativeMembrane = findMembrane(ctx, findProximateAxes(ctx, initialMembrane), initialHphobHphil, label_comp_id);
const membrane = initialMembrane.qmax! > alternativeMembrane.qmax! ? initialMembrane : alternativeMembrane;
return {
planePoint1: membrane.planePoint1,
planePoint2: membrane.planePoint2,
normalVector: membrane.normalVector!,
radius: ctx.extent,
centroid: ctx.centroid
};
}
interface MembraneCandidate {
planePoint1: Vec3,
planePoint2: Vec3,
stats: HphobHphil,
normalVector?: Vec3,
spherePoint?: Vec3,
qmax?: number
}
namespace MembraneCandidate {
export function initial(c1: Vec3, c2: Vec3, stats: HphobHphil): MembraneCandidate {
return {
planePoint1: c1,
planePoint2: c2,
stats: stats
};
}
export function scored(spherePoint: Vec3, c1: Vec3, c2: Vec3, stats: HphobHphil, qmax: number, centroid: Vec3): MembraneCandidate {
const diam_vect = Vec3();
Vec3.sub(diam_vect, centroid, spherePoint);
return {
planePoint1: c1,
planePoint2: c2,
stats: stats,
normalVector: diam_vect,
spherePoint: spherePoint,
qmax: qmax
};
}
}
function findMembrane(ctx: ANVILContext, spherePoints: Vec3[], initialStats: HphobHphil, label_comp_id: StructureElement.Property<string>): MembraneCandidate {
const { centroid, stepSize, minThickness, maxThickness } = ctx;
// best performing membrane
let membrane: MembraneCandidate;
// score of the best performing membrane
let qmax = 0;
// construct slices of thickness 1.0 along the axis connecting the centroid and the spherePoint
const diam = Vec3();
for (let i = 0, il = spherePoints.length; i < il; i++) {
const spherePoint = spherePoints[i];
Vec3.sub(diam, centroid, spherePoint);
Vec3.scale(diam, diam, 2);
const diamNorm = Vec3.magnitude(diam);
const qvartemp = [];
for (let i = 0, il = diamNorm - stepSize; i < il; i += stepSize) {
const c1 = Vec3();
const c2 = Vec3();
Vec3.scaleAndAdd(c1, spherePoint, diam, i / diamNorm);
Vec3.scaleAndAdd(c2, spherePoint, diam, (i + stepSize) / diamNorm);
// evaluate how well this membrane slice embeddeds the peculiar residues
const stats = HphobHphil.filtered(ctx, label_comp_id, (testPoint: Vec3) => isInMembranePlane(testPoint, diam, c1, c2));
qvartemp.push(MembraneCandidate.initial(c1, c2, stats));
}
let jmax = (minThickness / stepSize) - 1;
for (let width = 0, widthl = maxThickness; width < widthl;) {
const imax = qvartemp.length - 1 - jmax;
for (let i = 0, il = imax; i < il; i++) {
const c1 = qvartemp[i].planePoint1;
const c2 = qvartemp[i + jmax].planePoint2;
let hphob = 0;
let hphil = 0;
let total = 0;
for (let j = 0; j < jmax; j++) {
const ij = qvartemp[i + j];
if (j === 0 || j === jmax - 1) {
hphob += 0.5 * ij.stats.hphob;
hphil += 0.5 * ij.stats.hphil;
} else {
hphob += ij.stats.hphob;
hphil += ij.stats.hphil;
}
total += ij.stats.total;
}
const stats = HphobHphil.of(hphob, hphil, total);
if (hphob !== 0) {
const qvaltest = qValue(stats, initialStats);
if (qvaltest > qmax) {
qmax = qvaltest;
membrane = MembraneCandidate.scored(spherePoint, c1, c2, HphobHphil.of(hphob, hphil, total), qmax, centroid);
}
}
}
jmax++;
width = (jmax + 1) * stepSize;
}
}
return membrane!;
}
function qValue(currentStats: HphobHphil, initialStats: HphobHphil): number {
if(initialStats.hphob < 1) {
initialStats.hphob = 0.1;
}
if(initialStats.hphil < 1) {
initialStats.hphil += 1;
}
const part_tot = currentStats.hphob + currentStats.hphil;
return (currentStats.hphob * (initialStats.hphil - currentStats.hphil) - currentStats.hphil * (initialStats.hphob - currentStats.hphob)) /
Math.sqrt(part_tot * initialStats.hphob * initialStats.hphil * (initialStats.hphob + initialStats.hphil - part_tot));
}
export function isInMembranePlane(testPoint: Vec3, normalVector: Vec3, planePoint1: Vec3, planePoint2: Vec3): boolean {
const d1 = -Vec3.dot(normalVector, planePoint1);
const d2 = -Vec3.dot(normalVector, planePoint2);
const d = -Vec3.dot(normalVector, testPoint);
return d > Math.min(d1, d2) && d < Math.max(d1, d2);
}
// generates a defined number of points on a sphere with radius = extent around the specified centroid
function generateSpherePoints(ctx: ANVILContext, numberOfSpherePoints: number): Vec3[] {
const { centroid, extent } = ctx;
const points = [];
let oldPhi = 0, h, theta, phi;
for(let k = 1, kl = numberOfSpherePoints + 1; k < kl; k++) {
h = -1 + 2 * (k - 1) / (numberOfSpherePoints - 1);
theta = Math.acos(h);
phi = (k === 1 || k === numberOfSpherePoints) ? 0 : (oldPhi + 3.6 / Math.sqrt(numberOfSpherePoints * (1 - h * h))) % (2 * Math.PI);
const point = Vec3.create(
extent * Math.sin(phi) * Math.sin(theta) + centroid[0],
extent * Math.cos(theta) + centroid[1],
extent * Math.cos(phi) * Math.sin(theta) + centroid[2]
);
points[k - 1] = point;
oldPhi = phi;
}
return points;
}
// generates sphere points close to that of the initial membrane
function findProximateAxes(ctx: ANVILContext, membrane: MembraneCandidate): Vec3[] {
const { numberOfSpherePoints, extent } = ctx;
const points = generateSpherePoints(ctx, 30000);
let j = 4;
let sphere_pts2: Vec3[] = [];
while (sphere_pts2.length < numberOfSpherePoints) {
const d = 2 * extent / numberOfSpherePoints + j;
const dsq = d * d;
sphere_pts2 = [];
for (let i = 0, il = points.length; i < il; i++) {
if (Vec3.squaredDistance(points[i], membrane.spherePoint!) < dsq) {
sphere_pts2.push(points[i]);
}
}
j += 0.2;
}
return sphere_pts2;
}
interface HphobHphil {
hphob: number,
hphil: number,
total: number
}
namespace HphobHphil {
export function of(hphob: number, hphil: number, total?: number) {
return {
hphob: hphob,
hphil: hphil,
total: !!total ? total : hphob + hphil
};
}
const testPoint = Vec3();
export function filtered(ctx: ANVILContext, label_comp_id: StructureElement.Property<string>, filter?: (test: Vec3) => boolean): HphobHphil {
const { offsets, exposed, structure } = ctx;
const { x, y, z } = StructureProperties.atom;
let hphob = 0;
let hphil = 0;
for (let k = 0, kl = offsets.length; k < kl; k++) {
// ignore buried residues
if (!exposed[k]) {
continue;
}
setLocation(l, structure, offsets[k]);
Vec3.set(testPoint, x(l), y(l), z(l));
// testPoints have to be in putative membrane layer
if (filter && !filter(testPoint)) {
continue;
}
if (isHydrophobic(label_comp_id(l))) {
hphob++;
} else {
hphil++;
}
}
return of(hphob, hphil);
}
}
// ANVIL-specific (not general) definition of membrane-favoring amino acids
const HYDROPHOBIC_AMINO_ACIDS = new Set(['ALA', 'CYS', 'GLY', 'HIS', 'ILE', 'LEU', 'MET', 'PHE', 'SER', 'THR', 'VAL']);
export function isHydrophobic(label_comp_id: string): boolean {
return HYDROPHOBIC_AMINO_ACIDS.has(label_comp_id);
}
function setLocation(l: StructureElement.Location, structure: Structure, serialIndex: number) {
l.structure = structure;
l.unit = structure.units[structure.serialMapping.unitIndices[serialIndex]];
l.element = structure.serialMapping.elementIndices[serialIndex];
return l;
}

View File

@@ -0,0 +1,174 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../mol-plugin-state/builder/structure/representation-preset';
import { MembraneOrientationProvider, MembraneOrientation } from './prop';
import { StateObjectRef, StateTransformer, StateTransform } from '../../mol-state';
import { Task } from '../../mol-task';
import { PluginBehavior } from '../../mol-plugin/behavior';
import { MembraneOrientationRepresentationProvider, MembraneOrientationParams, MembraneOrientationRepresentation } from './representation';
import { HydrophobicityColorThemeProvider } from '../../mol-theme/color/hydrophobicity';
import { PluginStateObject, PluginStateTransform } from '../../mol-plugin-state/objects';
import { PluginContext } from '../../mol-plugin/context';
import { DefaultQueryRuntimeTable } from '../../mol-script/runtime/query/compiler';
import { StructureSelectionQuery, StructureSelectionCategory } from '../../mol-plugin-state/helpers/structure-selection-query';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { GenericRepresentationRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
const Tag = MembraneOrientation.Tag;
export const ANVILMembraneOrientation = PluginBehavior.create<{ autoAttach: boolean }>({
name: 'anvil-membrane-orientation-prop',
category: 'custom-props',
display: {
name: 'Membrane Orientation',
description: 'Data calculated with ANVIL algorithm.'
},
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
private provider = MembraneOrientationProvider
register(): void {
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
this.ctx.customStructureProperties.register(this.provider, this.params.autoAttach);
this.ctx.representation.structure.registry.add(MembraneOrientationRepresentationProvider);
this.ctx.query.structure.registry.add(isTransmembrane);
this.ctx.genericRepresentationControls.set(Tag.Representation, selection => {
const refs: GenericRepresentationRef[] = [];
selection.structures.forEach(structure => {
const memRepr = structure.genericRepresentations?.filter(r => r.cell.transform.transformer.id === MembraneOrientation3D.id)[0];
if (memRepr) refs.push(memRepr);
});
return [refs, 'Membrane Orientation'];
});
this.ctx.builders.structure.representation.registerPreset(MembraneOrientationPreset);
}
update(p: { autoAttach: boolean }) {
let updated = this.params.autoAttach !== p.autoAttach;
this.params.autoAttach = p.autoAttach;
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.representation.structure.registry.remove(MembraneOrientationRepresentationProvider);
this.ctx.query.structure.registry.remove(isTransmembrane);
this.ctx.genericRepresentationControls.delete(Tag.Representation);
this.ctx.builders.structure.representation.unregisterPreset(MembraneOrientationPreset);
}
},
params: () => ({
autoAttach: PD.Boolean(false)
})
});
//
export const isTransmembrane = StructureSelectionQuery('Residues Embedded in Membrane', 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']),
'atom-test': MembraneOrientation.symbols.isTransmembrane.symbol(),
})
])
])
]), {
description: 'Select residues that are embedded between the membrane layers.',
category: StructureSelectionCategory.Residue,
ensureCustomProperties: (ctx, structure) => {
return MembraneOrientationProvider.attach(ctx, structure);
}
});
//
export { MembraneOrientation3D };
type MembraneOrientation3D = typeof MembraneOrientation3D
const MembraneOrientation3D = PluginStateTransform.BuiltIn({
name: 'membrane-orientation-3d',
display: {
name: 'Membrane Orientation',
description: 'Membrane Orientation planes and rims. Data calculated with ANVIL algorithm.'
},
from: PluginStateObject.Molecule.Structure,
to: PluginStateObject.Shape.Representation3D,
params: (a) => {
return {
...MembraneOrientationParams,
};
}
})({
canAutoUpdate({ oldParams, newParams }) {
return true;
},
apply({ a, params }, plugin: PluginContext) {
return Task.create('Membrane Orientation', async ctx => {
await MembraneOrientationProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, a.data);
const repr = MembraneOrientationRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => MembraneOrientationParams);
await repr.createOrUpdate(params, a.data).runInContext(ctx);
return new PluginStateObject.Shape.Representation3D({ repr, source: a }, { label: 'Membrane Orientation' });
});
},
update({ a, b, newParams }, plugin: PluginContext) {
return Task.create('Membrane Orientation', async ctx => {
await MembraneOrientationProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, a.data);
const props = { ...b.data.repr.props, ...newParams };
await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
return StateTransformer.UpdateResult.Updated;
});
},
isApplicable(a) {
return MembraneOrientationProvider.isApplicable(a.data);
}
});
export const MembraneOrientationPreset = StructureRepresentationPresetProvider({
id: 'preset-membrane-orientation',
display: {
name: 'Membrane Orientation', group: 'Annotation',
description: 'Shows orientation of membrane layers. Data calculated with ANVIL algorithm.' // TODO add ' or obtained via RCSB PDB'
},
isApplicable(a) {
return MembraneOrientationProvider.isApplicable(a.data);
},
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 (!MembraneOrientationProvider.get(structure).value) {
await plugin.runTask(Task.create('Membrane Orientation', async runtime => {
await MembraneOrientationProvider.attach({ runtime, assetManager: plugin.managers.asset }, structure);
}));
}
const membraneOrientation = await tryCreateMembraneOrientation(plugin, structureCell);
const colorTheme = HydrophobicityColorThemeProvider.name as any;
const preset = await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
return { components: preset.components, representations: { ...preset.representations, membraneOrientation } };
}
});
export function tryCreateMembraneOrientation(plugin: PluginContext, structure: StateObjectRef<PluginStateObject.Molecule.Structure>, params?: StateTransformer.Params<MembraneOrientation3D>, initialState?: Partial<StateTransform.State>) {
const state = plugin.state.data;
const membraneOrientation = state.build().to(structure)
.applyOrUpdateTagged('membrane-orientation-3d', MembraneOrientation3D, params, { state: initialState });
return membraneOrientation.commit({ revertOnError: true });
}

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Structure, StructureProperties, Unit } from '../../mol-model/structure';
import { CustomPropertyDescriptor } from '../../mol-model/custom-property';
import { ANVILParams, ANVILProps, computeANVIL, isInMembranePlane } from './algorithm';
import { CustomStructureProperty } from '../../mol-model-props/common/custom-structure-property';
import { CustomProperty } from '../../mol-model-props/common/custom-property';
import { AccessibleSurfaceAreaProvider } from '../../mol-model-props/computed/accessible-surface-area';
import { Vec3 } from '../../mol-math/linear-algebra';
import { QuerySymbolRuntime } from '../../mol-script/runtime/query/base';
import { CustomPropSymbol } from '../../mol-script/language/symbol';
import Type from '../../mol-script/language/type';
export const MembraneOrientationParams = {
...ANVILParams
};
export type MembraneOrientationParams = typeof MembraneOrientationParams
export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
export { MembraneOrientation };
interface MembraneOrientation {
// point in membrane boundary
readonly planePoint1: Vec3,
// point in opposite side of membrane boundary
readonly planePoint2: Vec3,
// normal vector of membrane layer
readonly normalVector: Vec3,
// the radius of the membrane layer
readonly radius: number,
readonly centroid: Vec3
}
namespace MembraneOrientation {
export enum Tag {
Representation = 'membrane-orientation-3d'
}
const pos = Vec3();
export const symbols = {
isTransmembrane: QuerySymbolRuntime.Dynamic(CustomPropSymbol('computed', 'membrane-orientation.is-transmembrane', Type.Bool),
ctx => {
const { unit, structure } = ctx.element;
const { x, y, z } = StructureProperties.atom;
if (!Unit.isAtomic(unit)) return 0;
const membraneOrientation = MembraneOrientationProvider.get(structure).value;
if (!membraneOrientation) return 0;
Vec3.set(pos, x(ctx.element), y(ctx.element), z(ctx.element));
const { normalVector, planePoint1, planePoint2 } = membraneOrientation!;
return isInMembranePlane(pos, normalVector, planePoint1, planePoint2);
})
};
}
export const MembraneOrientationProvider: CustomStructureProperty.Provider<MembraneOrientationParams, MembraneOrientation> = CustomStructureProperty.createProvider({
label: 'Membrane Orientation',
descriptor: CustomPropertyDescriptor({
name: 'anvil_computed_membrane_orientation',
symbols: MembraneOrientation.symbols,
// TODO `cifExport`
}),
type: 'root',
defaultParams: MembraneOrientationParams,
getParams: (data: Structure) => MembraneOrientationParams,
isApplicable: (data: Structure) => true,
obtain: async (ctx: CustomProperty.Context, data: Structure, props: Partial<MembraneOrientationProps>) => {
const p = { ...PD.getDefaultValues(MembraneOrientationParams), ...props };
return { value: await computeAnvil(ctx, data, p) };
}
});
async function computeAnvil(ctx: CustomProperty.Context, data: Structure, props: Partial<ANVILProps>): Promise<MembraneOrientation> {
await AccessibleSurfaceAreaProvider.attach(ctx, data);
const p = { ...PD.getDefaultValues(ANVILParams), ...props };
return await computeANVIL(data, p).runInContext(ctx.runtime);
}

View File

@@ -0,0 +1,178 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
*/
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../mol-repr/representation';
import { Structure } from '../../mol-model/structure';
import { Spheres } from '../../mol-geo/geometry/spheres/spheres';
import { SpheresBuilder } from '../../mol-geo/geometry/spheres/spheres-builder';
import { StructureRepresentationProvider, StructureRepresentation, StructureRepresentationStateBuilder } from '../../mol-repr/structure/representation';
import { MembraneOrientation } from './prop';
import { ThemeRegistryContext } from '../../mol-theme/theme';
import { ShapeRepresentation } from '../../mol-repr/shape/representation';
import { Shape } from '../../mol-model/shape';
import { RuntimeContext } from '../../mol-task';
import { Lines } from '../../mol-geo/geometry/lines/lines';
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
import { LinesBuilder } from '../../mol-geo/geometry/lines/lines-builder';
import { Circle } from '../../mol-geo/primitive/circle';
import { transformPrimitive } from '../../mol-geo/primitive/primitive';
import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
import { MembraneOrientationProvider } from './prop';
import { MarkerActions } from '../../mol-util/marker-action';
import { lociLabel } from '../../mol-theme/label';
import { ColorNames } from '../../mol-util/color/names';
const SharedParams = {
color: PD.Color(ColorNames.lightgrey),
radiusFactor: PD.Numeric(0.8333, { min: 0.1, max: 3.0, step: 0.01 }, { description: 'Scale the radius of the membrane layer' })
};
const BilayerSpheresParams = {
...Spheres.Params,
...SharedParams,
sphereSize: PD.Numeric(1, { min: 0.1, max: 10, step: 0.1 }, { description: 'Size of spheres that represent membrane planes' }),
density: PD.Numeric(1, { min: 0.25, max: 10, step: 0.25 }, { description: 'Distance between spheres'})
};
export type BilayerSpheresParams = typeof BilayerSpheresParams
export type BilayerSpheresProps = PD.Values<BilayerSpheresParams>
const BilayerPlanesParams = {
...Mesh.Params,
...SharedParams,
sectorOpacity: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
};
export type BilayerPlanesParams = typeof BilayerPlanesParams
export type BilayerPlanesProps = PD.Values<BilayerPlanesParams>
const BilayerRimsParams = {
...Lines.Params,
...SharedParams,
lineSizeAttenuation: PD.Boolean(true),
linesSize: PD.Numeric(0.3, { min: 0.01, max: 50, step: 0.01 }),
dashedLines: PD.Boolean(true),
};
export type BilayerRimsParams = typeof BilayerRimsParams
export type BilayerRimsProps = PD.Values<BilayerRimsParams>
const MembraneOrientationVisuals = {
'bilayer-spheres': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerSpheresParams>) => ShapeRepresentation(getBilayerSpheres, Spheres.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }) }),
'bilayer-planes': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerPlanesParams>) => ShapeRepresentation(getBilayerPlanes, Mesh.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }), modifyProps: p => ({ ...p, alpha: p.sectorOpacity, ignoreLight: true, doubleSided: false }) }),
'bilayer-rims': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerRimsParams>) => ShapeRepresentation(getBilayerRims, Lines.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }) })
};
export const MembraneOrientationParams = {
...BilayerSpheresParams,
...BilayerPlanesParams,
...BilayerRimsParams,
visuals: PD.MultiSelect(['bilayer-planes', 'bilayer-rims'], PD.objectToOptions(MembraneOrientationVisuals)),
};
export type MembraneOrientationParams = typeof MembraneOrientationParams
export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
export function getMembraneOrientationParams(ctx: ThemeRegistryContext, structure: Structure) {
return PD.clone(MembraneOrientationParams);
}
export type MembraneOrientationRepresentation = StructureRepresentation<MembraneOrientationParams>
export function MembraneOrientationRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MembraneOrientationParams>): MembraneOrientationRepresentation {
return Representation.createMulti('Membrane Orientation', ctx, getParams, StructureRepresentationStateBuilder, MembraneOrientationVisuals as unknown as Representation.Def<Structure, MembraneOrientationParams>);
}
export const MembraneOrientationRepresentationProvider = StructureRepresentationProvider({
name: 'membrane-orientation',
label: 'Membrane Orientation',
description: 'Displays a grid of points representing membrane layers.',
factory: MembraneOrientationRepresentation,
getParams: getMembraneOrientationParams,
defaultValues: PD.getDefaultValues(MembraneOrientationParams),
defaultColorTheme: { name: 'uniform' },
defaultSizeTheme: { name: 'uniform' },
isApplicable: (structure: Structure) => structure.elementCount > 0
});
function membraneLabel(data: Structure) {
return `${lociLabel(Structure.Loci(data))} | Membrane Orientation`;
}
function getBilayerRims(ctx: RuntimeContext, data: Structure, props: BilayerRimsProps, shape?: Shape<Lines>): Shape<Lines> {
const { planePoint1: p1, planePoint2: p2, centroid, normalVector: normal, radius } = MembraneOrientationProvider.get(data).value!;
const scaledRadius = props.radiusFactor * radius;
const builder = LinesBuilder.create(128, 64, shape?.geometry);
getLayerCircle(builder, p1, centroid, normal, scaledRadius, props);
getLayerCircle(builder, p2, centroid, normal, scaledRadius, props);
return Shape.create(name, data, builder.getLines(), () => props.color, () => props.linesSize, () => membraneLabel(data));
}
function getLayerCircle(builder: LinesBuilder, p: Vec3, centroid: Vec3, normal: Vec3, radius: number, props: BilayerRimsProps, shape?: Shape<Lines>) {
const circle = getCircle(p, centroid, normal, radius);
const { indices, vertices } = circle;
for (let j = 0, jl = indices.length; j < jl; j += 3) {
if (props.dashedLines && j % 2 === 1) continue; // draw every other segment to get dashes
const start = indices[j] * 3;
const end = indices[j + 1] * 3;
const startX = vertices[start];
const startY = vertices[start + 1];
const startZ = vertices[start + 2];
const endX = vertices[end];
const endY = vertices[end + 1];
const endZ = vertices[end + 2];
builder.add(startX, startY, startZ, endX, endY, endZ, 0);
}
}
const tmpMat = Mat4();
function getCircle(p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
Mat4.targetTo(tmpMat, p, centroid, normal);
Mat4.setTranslation(tmpMat, p);
Mat4.mul(tmpMat, tmpMat, Mat4.rotX90);
const circle = Circle({ radius, segments: 64 });
return transformPrimitive(circle, tmpMat);
}
function getBilayerPlanes(ctx: RuntimeContext, data: Structure, props: BilayerPlanesProps, shape?: Shape<Mesh>): Shape<Mesh> {
const { planePoint1: p1, planePoint2: p2, centroid, normalVector: normal, radius } = MembraneOrientationProvider.get(data).value!;
const state = MeshBuilder.createState(128, 64, shape && shape.geometry);
const scaledRadius = props.radiusFactor * radius;
getLayerPlane(state, p1, centroid, normal, scaledRadius);
getLayerPlane(state, p2, centroid, normal, scaledRadius);
return Shape.create(name, data, MeshBuilder.getMesh(state), () => props.color, () => 1, () => membraneLabel(data));
}
function getLayerPlane(state: MeshBuilder.State, p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
const circle = getCircle(p, centroid, normal, radius);
state.currentGroup = 0;
MeshBuilder.addPrimitive(state, Mat4.id, circle);
MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle);
}
function getBilayerSpheres(ctx: RuntimeContext, data: Structure, props: BilayerSpheresProps, shape?: Shape<Spheres>): Shape<Spheres> {
const { density } = props;
const { radius, planePoint1, planePoint2, normalVector } = MembraneOrientationProvider.get(data).value!;
const scaledRadius = (props.radiusFactor * radius) * (props.radiusFactor * radius);
const spheresBuilder = SpheresBuilder.create(256, 128, shape?.geometry);
getLayerSpheres(spheresBuilder, planePoint1, normalVector, density, scaledRadius);
getLayerSpheres(spheresBuilder, planePoint2, normalVector, density, scaledRadius);
return Shape.create(name, data, spheresBuilder.getSpheres(), () => props.color, () => props.sphereSize, () => membraneLabel(data));
}
function getLayerSpheres(spheresBuilder: SpheresBuilder, point: Vec3, normalVector: Vec3, density: number, sqRadius: number) {
Vec3.normalize(normalVector, normalVector);
const d = -Vec3.dot(normalVector, point);
const rep = Vec3();
for (let i = -1000, il = 1000; i < il; i += density) {
for (let j = -1000, jl = 1000; j < jl; j += density) {
Vec3.set(rep, i, j, normalVector[2] === 0 ? 0 : -(d + i * normalVector[0] + j * normalVector[1]) / normalVector[2]);
if (Vec3.squaredDistance(rep, point) < sqRadius) {
spheresBuilder.add(rep[0], rep[1], rep[2], 0);
}
}
}
}

View File

@@ -10,7 +10,7 @@ import { Color } from '../../../mol-util/color';
import { getPalette } from '../../../mol-util/color/palette';
import { ColorTheme, LocationColor } from '../../../mol-theme/color';
import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
import { StructureElement, Bond } from '../../../mol-model/structure';
import { StructureElement, Bond, Model } from '../../../mol-model/structure';
import { Location } from '../../../mol-model/location';
import { CellPackInfoProvider } from '../property';
import { distinctColors } from '../../../mol-util/color/distinct';
@@ -40,7 +40,7 @@ export function CellPackGenerateColorTheme(ctx: ThemeDataContext, props: PD.Valu
const { models } = ctx.structure.root;
let size = 0;
for (const m of models) size = Math.max(size, m.trajectoryInfo.size);
for (const m of models) size = Math.max(size, Model.TrajectoryInfo.get(m).size);
const palette = getPalette(size, { palette: {
name: 'generate',
@@ -53,15 +53,15 @@ export function CellPackGenerateColorTheme(ctx: ThemeDataContext, props: PD.Valu
legend = palette.legend;
const modelColor = new Map<number, Color>();
for (let i = 0, il = models.length; i < il; ++i) {
const idx = models[i].trajectoryInfo.index;
modelColor.set(models[i].trajectoryInfo.index, palette.color(idx));
const idx = Model.TrajectoryInfo.get(models[i]).index;
modelColor.set(Model.TrajectoryInfo.get(models[i]).index, palette.color(idx));
}
color = (location: Location): Color => {
if (StructureElement.Location.is(location)) {
return modelColor.get(location.unit.model.trajectoryInfo.index)!;
return modelColor.get(Model.TrajectoryInfo.get(location.unit.model).index)!;
} else if (Bond.isLocation(location)) {
return modelColor.get(location.aUnit.model.trajectoryInfo.index)!;
return modelColor.get(Model.TrajectoryInfo.get(location.aUnit.model).index)!;
}
return DefaultColor;
};
@@ -89,7 +89,7 @@ export const CellPackGenerateColorThemeProvider: ColorTheme.Provider<CellPackGen
isApplicable: (ctx: ThemeDataContext) => {
return (
!!ctx.structure && ctx.structure.elementCount > 0 &&
ctx.structure.models[0].trajectoryInfo.size > 1 &&
Model.TrajectoryInfo.get(ctx.structure.models[0]).size > 1 &&
!!CellPackInfoProvider.get(ctx.structure).value
);
}

View File

@@ -9,7 +9,7 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Color } from '../../../mol-util/color';
import { ColorTheme, LocationColor } from '../../../mol-theme/color';
import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
import { StructureElement } from '../../../mol-model/structure';
import { StructureElement, Model } from '../../../mol-model/structure';
import { Location } from '../../../mol-model/location';
import { CellPackInfoProvider } from '../property';
@@ -32,13 +32,13 @@ export function CellPackProvidedColorTheme(ctx: ThemeDataContext, props: PD.Valu
const { models } = ctx.structure.root;
const modelColor = new Map<number, Color>();
for (let i = 0, il = models.length; i < il; ++i) {
const idx = models[i].trajectoryInfo.index;
modelColor.set(models[i].trajectoryInfo.index, info.colors[idx]);
const idx = Model.TrajectoryInfo.get(models[i]).index;
modelColor.set(Model.TrajectoryInfo.get(models[i]).index, info.colors[idx]);
}
color = (location: Location): Color => {
return StructureElement.Location.is(location)
? modelColor.get(location.unit.model.trajectoryInfo.index)!
? modelColor.get(Model.TrajectoryInfo.get(location.unit.model).index)!
: DefaultColor;
};
} else {
@@ -65,7 +65,7 @@ export const CellPackProvidedColorThemeProvider: ColorTheme.Provider<CellPackPro
isApplicable: (ctx: ThemeDataContext) => {
return (
!!ctx.structure && ctx.structure.elementCount > 0 &&
ctx.structure.models[0].trajectoryInfo.size > 1 &&
Model.TrajectoryInfo.get(ctx.structure.models[0]).size > 1 &&
!!CellPackInfoProvider.get(ctx.structure).value?.colors
);
}

View File

@@ -412,9 +412,7 @@ export function createStructureFromCellPack(plugin: PluginContext, packing: Cell
if (ctx.shouldUpdate) await ctx.update(`${name} - structure`);
const structure = builder.getStructure();
for( let i = 0, il = structure.models.length; i < il; ++i) {
const { trajectoryInfo } = structure.models[i];
trajectoryInfo.size = il;
trajectoryInfo.index = i;
Model.TrajectoryInfo.set(structure.models[i], { size: il, index: i });
}
return { structure, assets, colors: skipColors ? undefined : colors };
});

View File

@@ -13,7 +13,7 @@ import { IngredientFiles } from './util';
import { Asset } from '../../mol-util/assets';
import { PluginContext } from '../../mol-plugin/context';
import { CellPackInfoProvider } from './property';
import { Structure, StructureSymmetry, Unit } from '../../mol-model/structure';
import { Structure, StructureSymmetry, Unit, Model } from '../../mol-model/structure';
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
export const DefaultCellPackBaseUrl = 'https://mesoscope.scripps.edu/data/cellPACK_data/cellPACK_database_1.1.0/';
@@ -138,9 +138,7 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({
}
structure = builder.getStructure();
for( let i = 0, il = structure.models.length; i < il; ++i) {
const { trajectoryInfo } = structure.models[i];
trajectoryInfo.size = il;
trajectoryInfo.index = i;
Model.TrajectoryInfo.set(structure.models[i], { size: il, index: i });
}
}
return new PSO.Molecule.Structure(structure, { label: a.label, description: `${a.description}` });
@@ -150,55 +148,3 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({
b?.data.customPropertyDescriptors.dispose();
}
});
// export { GetAllAssamblyinOneStructure };
// type GetAllAssamblyinOneStructure = typeof GetAllAssamblyinOneStructure
// const GetAllAssamblyinOneStructure = PluginStateTransform.BuiltIn({
// name: 'get assambly from structure',
// display: { name: 'get assambly from structure' },
// isDecorator: true,
// from: PSO.Molecule.Structure,
// to: PSO.Molecule.Structure,
// params(a) {
// return { };
// }
// })({
// apply({ a, params }) {
// return Task.create('Build Structure Assemblies', async ctx => {
// // TODO: optimze
// // TODO: think of ways how to fast-track changes to this for animations
// const initial_structure = a.data;
// const structures: Structure[] = [];
// let structure: Structure = initial_structure;
// // the list of asambly *?
// const symmetry = ModelSymmetry.Provider.get(initial_structure.model);
// if (symmetry){
// if (symmetry.assemblies.length !== 0) {
// for (const a of symmetry.assemblies) {
// const s = await StructureSymmetry.buildAssembly(initial_structure, a.id!).runInContext(ctx);
// structures.push(s);
// }
// const builder = Structure.Builder({ label: name });
// let offsetInvariantId = 0;
// for (const s of structures) {
// let maxInvariantId = 0;
// for (const u of s.units) {
// const invariantId = u.invariantId + offsetInvariantId;
// if (u.invariantId > maxInvariantId) maxInvariantId = u.invariantId;
// builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, Unit.Trait.None, invariantId);
// }
// offsetInvariantId += maxInvariantId + 1;
// }
// structure = builder.getStructure();
// for( let i = 0, il = structure.models.length; i < il; ++i) {
// const { trajectoryInfo } = structure.models[i];
// trajectoryInfo.size = il;
// trajectoryInfo.index = i;
// }
// }
// }
// return new PSO.Molecule.Structure(structure, { label: a.label, description: `${a.description}` });
// });
// }
// });

View File

@@ -0,0 +1,10 @@
## DNATCO Extensions
### Confal Pyramids
The Confal Pyramids extensions displays tetrahedron-like pyramids. These pyramids are a simple visual representation of nucleotide conformer classes that can be assigned to individual steps in nucleic acid structures.
For more information, see:
* [Černý et al., Nucleic Acids Research, 44, W284 (2016)](http://dx.doi.org/10.1093/nar/gkw381)
* [Schneider et al., Acta Cryst D, 74, 52-64 (2018)](http://dx.doi.org/10.1107/S2059798318000050)
* [Schneider et al., Genes, 8(10), 278, (2017)](http://dx.doi.org/10.3390/genes8100278)

View File

@@ -0,0 +1,103 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Michal Malý <michal.maly@ibt.cas.cz>
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { ConfalPyramidsColorThemeProvider } from './color';
import { ConfalPyramids, ConfalPyramidsProvider } from './property';
import { ConfalPyramidsRepresentationProvider } from './representation';
import { Loci } from '../../../mol-model/loci';
import { PluginBehavior } from '../../../mol-plugin/behavior/behavior';
import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../../mol-plugin-state/builder/structure/representation-preset';
import { StateObjectRef } from '../../../mol-state';
import { Task } from '../../../mol-task';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
export const DnatcoConfalPyramidsPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-confal-pyramids',
display: {
name: 'Confal Pyramids', group: 'Annotation',
description: 'Schematic depiction of conformer class and confal value.',
},
isApplicable(a) {
return a.data.models.length >= 1 && a.data.models.some(m => ConfalPyramids.isApplicable(m));
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const model = structureCell?.obj?.data.model;
if (!structureCell || !model) return {};
await plugin.runTask(Task.create('Confal Pyramids', async runtime => {
await ConfalPyramidsProvider.attach({ runtime, assetManager: plugin.managers.asset }, model);
}));
const { components, representations } = await PresetStructureRepresentations.auto.apply(ref, { ...params }, plugin);
const pyramids = await plugin.builders.structure.tryCreateComponentStatic(structureCell, 'nucleic', { label: 'Confal Pyramids' });
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
let pyramidsRepr;
if (representations)
pyramidsRepr = builder.buildRepresentation(update, pyramids, { type: ConfalPyramidsRepresentationProvider, typeParams, color: ConfalPyramidsColorThemeProvider }, { tag: 'confal-pyramdis' } );
await update.commit({ revertOnError: true });
return { components: { ...components, pyramids }, representations: { ...representations, pyramidsRepr } };
}
});
export const DnatcoConfalPyramids = PluginBehavior.create<{ autoAttach: boolean, showToolTip: boolean }>({
name: 'dnatco-confal-pyramids-prop',
category: 'custom-props',
display: {
name: 'Confal Pyramids',
description: 'Schematic depiction of conformer class and confal value.',
},
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showToolTip: boolean }> {
private provider = ConfalPyramidsProvider;
private labelConfalPyramids = {
label: (loci: Loci): string | undefined => {
if (!this.params.showToolTip) return void 0;
/* TODO: Implement this */
return void 0;
}
}
register(): void {
this.ctx.customModelProperties.register(this.provider, this.params.autoAttach);
this.ctx.managers.lociLabels.addProvider(this.labelConfalPyramids);
this.ctx.representation.structure.themes.colorThemeRegistry.add(ConfalPyramidsColorThemeProvider);
this.ctx.representation.structure.registry.add(ConfalPyramidsRepresentationProvider);
this.ctx.builders.structure.representation.registerPreset(DnatcoConfalPyramidsPreset);
}
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.customModelProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
return updated;
}
unregister() {
this.ctx.customModelProperties.unregister(ConfalPyramidsProvider.descriptor.name);
this.ctx.managers.lociLabels.removeProvider(this.labelConfalPyramids);
this.ctx.representation.structure.registry.remove(ConfalPyramidsRepresentationProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(ConfalPyramidsColorThemeProvider);
this.ctx.builders.structure.representation.unregisterPreset(DnatcoConfalPyramidsPreset);
}
},
params: () => ({
autoAttach: PD.Boolean(true),
showToolTip: PD.Boolean(true)
})
});

View File

@@ -0,0 +1,186 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Michal Malý <michal.maly@ibt.cas.cz>
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { ConfalPyramids, ConfalPyramidsProvider } from './property';
import { ConfalPyramidsTypes as CPT } from './types';
import { Location } from '../../../mol-model/location';
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
import { ColorTheme } 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 { TableLegend } from '../../../mol-util/legend';
import { iterableToArray } from '../../../mol-data/util';
const DefaultColor = Color(0xCCCCCC);
const Description = 'Assigns colors to confal pyramids';
const ErrorColor = Color(0xFFA10A);
type ConformerClasses = 'A' | 'B' | 'BII' | 'miB' | 'Z' | 'IC' | 'OPN' | 'SYN' | 'N';
const ColorMapping: ReadonlyMap<ConformerClasses, Color> = new Map([
['A', Color(0xFFC1C1)],
['B', Color(0xC8CFFF)],
['BII', Color(0x0059DA)],
['miB', Color(0x3BE8FB)],
['Z', Color(0x01F60E)],
['IC', Color(0xFA5CFB)],
['OPN', Color(0xE90000)],
['SYN', Color(0xFFFF01)],
['N', Color(0xF2F2F2)],
]);
const NtCToClasses: ReadonlyMap<string, [ConformerClasses, ConformerClasses]> = new Map([
['NANT', ['N', 'N']],
['AA00', ['A', 'A']],
['AA02', ['A', 'A']],
['AA03', ['A', 'A']],
['AA04', ['A', 'A']],
['AA08', ['A', 'A']],
['AA09', ['A', 'A']],
['AA01', ['A', 'A']],
['AA05', ['A', 'A']],
['AA06', ['A', 'A']],
['AA10', ['A', 'A']],
['AA11', ['A', 'A']],
['AA07', ['A', 'A']],
['AA12', ['A', 'A']],
['AA13', ['A', 'A']],
['AB01', ['A', 'B']],
['AB02', ['A', 'B']],
['AB03', ['A', 'B']],
['AB04', ['A', 'B']],
['AB05', ['A', 'B']],
['BA01', ['B', 'A']],
['BA05', ['B', 'A']],
['BA09', ['B', 'A']],
['BA08', ['BII', 'A']],
['BA10', ['B', 'A']],
['BA13', ['BII', 'A']],
['BA16', ['BII', 'A']],
['BA17', ['BII', 'A']],
['BB00', ['B', 'B']],
['BB01', ['B', 'B']],
['BB17', ['B', 'B']],
['BB02', ['B', 'B']],
['BB03', ['B', 'B']],
['BB11', ['B', 'B']],
['BB16', ['B', 'B']],
['BB04', ['B', 'BII']],
['BB05', ['B', 'BII']],
['BB07', ['BII', 'BII']],
['BB08', ['BII', 'BII']],
['BB10', ['miB', 'miB']],
['BB12', ['miB', 'miB']],
['BB13', ['miB', 'miB']],
['BB14', ['miB', 'miB']],
['BB15', ['miB', 'miB']],
['BB20', ['miB', 'miB']],
['IC01', ['IC', 'IC']],
['IC02', ['IC', 'IC']],
['IC03', ['IC', 'IC']],
['IC04', ['IC', 'IC']],
['IC05', ['IC', 'IC']],
['IC06', ['IC', 'IC']],
['IC07', ['IC', 'IC']],
['OP01', ['OPN', 'OPN']],
['OP02', ['OPN', 'OPN']],
['OP03', ['OPN', 'OPN']],
['OP04', ['OPN', 'OPN']],
['OP05', ['OPN', 'OPN']],
['OP06', ['OPN', 'OPN']],
['OP07', ['OPN', 'OPN']],
['OP08', ['OPN', 'OPN']],
['OP09', ['OPN', 'OPN']],
['OP10', ['OPN', 'OPN']],
['OP11', ['OPN', 'OPN']],
['OP12', ['OPN', 'OPN']],
['OP13', ['OPN', 'OPN']],
['OP14', ['OPN', 'OPN']],
['OP15', ['OPN', 'OPN']],
['OP16', ['OPN', 'OPN']],
['OP17', ['OPN', 'OPN']],
['OP18', ['OPN', 'OPN']],
['OP19', ['OPN', 'OPN']],
['OP20', ['OPN', 'OPN']],
['OP21', ['OPN', 'OPN']],
['OP22', ['OPN', 'OPN']],
['OP23', ['OPN', 'OPN']],
['OP24', ['OPN', 'OPN']],
['OP25', ['OPN', 'OPN']],
['OP26', ['OPN', 'OPN']],
['OP27', ['OPN', 'OPN']],
['OP28', ['OPN', 'OPN']],
['OP29', ['OPN', 'OPN']],
['OP30', ['OPN', 'OPN']],
['OP31', ['OPN', 'OPN']],
['OPS1', ['OPN', 'OPN']],
['OP1S', ['OPN', 'SYN']],
['AAS1', ['SYN', 'A']],
['AB1S', ['A', 'SYN']],
['AB2S', ['A', 'SYN']],
['BB1S', ['B', 'SYN']],
['BB2S', ['B', 'SYN']],
['BBS1', ['SYN', 'B']],
['ZZ01', ['Z', 'Z']],
['ZZ02', ['Z', 'Z']],
['ZZ1S', ['Z', 'SYN']],
['ZZ2S', ['Z', 'SYN']],
['ZZS1', ['SYN', 'Z']],
['ZZS2', ['SYN', 'Z']],
]);
function getConformerColor(ntc: string, useLower: boolean): Color {
const item = NtCToClasses.get(ntc);
if (!item) return ErrorColor;
return ColorMapping.get(useLower ? item[1] : item[0]) ?? ErrorColor;
}
export const ConfalPyramidsColorThemeParams = {};
export type ConfalPyramidsColorThemeParams = typeof ConfalPyramidsColorThemeParams
export function getConfalPyramidsColorThemeParams(ctx: ThemeDataContext) {
return ConfalPyramidsColorThemeParams; // TODO return copy
}
export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values<ConfalPyramidsColorThemeParams>): ColorTheme<ConfalPyramidsColorThemeParams> {
function color(location: Location, isSecondary: boolean): Color {
if (CPT.isLocation(location)) {
const { pyramid, isLower } = location.data;
return getConformerColor(pyramid.NtC, isLower);
}
return DefaultColor;
}
return {
factory: ConfalPyramidsColorTheme,
granularity: 'group',
color,
props,
description: Description,
legend: TableLegend(iterableToArray(ColorMapping.entries()).map(([conformer, color]) => {
return [conformer, color] as [string, Color];
}).concat([
[ 'Error', ErrorColor ],
[ 'Unknown', DefaultColor ]
]))
};
}
export const ConfalPyramidsColorThemeProvider: ColorTheme.Provider<ConfalPyramidsColorThemeParams, 'confal-pyramids'> = {
name: 'confal-pyramids',
label: 'Confal Pyramids',
category: ColorTheme.Category.Residue,
factory: ConfalPyramidsColorTheme,
getParams: getConfalPyramidsColorThemeParams,
defaultValues: PD.getDefaultValues(ConfalPyramidsColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models.some(m => ConfalPyramids.isApplicable(m)),
ensureCustomProperties: {
attach: (ctx: CustomProperty.Context, data: ThemeDataContext) => data.structure ? ConfalPyramidsProvider.attach(ctx, data.structure.models[0], void 0, true) : Promise.resolve(),
detach: (data) => data.structure && data.structure.models[0].customProperties.reference(ConfalPyramidsProvider.descriptor, false)
}
};

View File

@@ -0,0 +1,172 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Michal Malý <michal.maly@ibt.cas.cz>
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { ConfalPyramidsTypes as CPT } from './types';
import { Column, Table } from '../../../mol-data/db';
import { toTable } from '../../../mol-io/reader/cif/schema';
import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
import { Model } from '../../../mol-model/structure';
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
import { PropertyWrapper } from '../../../mol-model-props/common/wrapper';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
export type ConfalPyramids = PropertyWrapper<CPT.PyramidsData | undefined >;
export namespace ConfalPyramids {
export const Schema = {
ndb_struct_ntc_step: {
id: Column.Schema.int,
name: Column.Schema.str,
PDB_model_number: Column.Schema.int,
label_entity_id_1: Column.Schema.int,
label_asym_id_1: Column.Schema.str,
label_seq_id_1: Column.Schema.int,
label_comp_id_1: Column.Schema.str,
label_alt_id_1: Column.Schema.str,
label_entity_id_2: Column.Schema.int,
label_asym_id_2: Column.Schema.str,
label_seq_id_2: Column.Schema.int,
label_comp_id_2: Column.Schema.str,
label_alt_id_2: Column.Schema.str,
auth_asym_id_1: Column.Schema.str,
auth_seq_id_1: Column.Schema.int,
auth_asym_id_2: Column.Schema.str,
auth_seq_id_2: Column.Schema.int,
PDB_ins_code_1: Column.Schema.str,
PDB_ins_code_2: Column.Schema.str,
},
ndb_struct_ntc_step_summary: {
step_id: Column.Schema.int,
assigned_CANA: Column.Schema.str,
assigned_NtC: Column.Schema.str,
confal_score: Column.Schema.int,
euclidean_distance_NtC_ideal: Column.Schema.float,
cartesian_rmsd_closest_NtC_representative: Column.Schema.float,
closest_CANA: Column.Schema.str,
closest_NtC: Column.Schema.str,
closest_step_golden: Column.Schema.str
}
};
export type Schema = typeof Schema;
export async function fromCif(ctx: CustomProperty.Context, model: Model, props: ConfalPyramidsProps): Promise<CustomProperty.Data<ConfalPyramids>> {
const info = PropertyWrapper.createInfo();
const data = getCifData(model);
if (data === undefined) return { value: { info, data: undefined } };
const fromCif = createPyramidsFromCif(model, data.steps, data.stepsSummary);
return { value: { info, data: fromCif } };
}
function getCifData(model: Model) {
if (!MmcifFormat.is(model.sourceData)) throw new Error('Data format must be mmCIF');
if (!hasNdbStructNtcCategories(model)) return undefined;
return {
steps: toTable(Schema.ndb_struct_ntc_step, model.sourceData.data.frame.categories.ndb_struct_ntc_step),
stepsSummary: toTable(Schema.ndb_struct_ntc_step_summary, model.sourceData.data.frame.categories.ndb_struct_ntc_step_summary)
};
}
function hasNdbStructNtcCategories(model: Model): boolean {
if (!MmcifFormat.is(model.sourceData)) return false;
const names = (model.sourceData).data.frame.categoryNames;
return names.includes('ndb_struct_ntc_step') && names.includes('ndb_struct_ntc_step_summary');
}
export function isApplicable(model?: Model): boolean {
return !!model && hasNdbStructNtcCategories(model);
}
}
export const ConfalPyramidsParams = {};
export type ConfalPyramidsParams = typeof ConfalPyramidsParams;
export type ConfalPyramidsProps = PD.Values<ConfalPyramidsParams>;
export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramidsParams, ConfalPyramids> = CustomModelProperty.createProvider({
label: 'Confal Pyramids',
descriptor: CustomPropertyDescriptor({
name: 'confal_pyramids',
}),
type: 'static',
defaultParams: ConfalPyramidsParams,
getParams: (data: Model) => ConfalPyramidsParams,
isApplicable: (data: Model) => ConfalPyramids.isApplicable(data),
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<ConfalPyramidsProps>) => {
const p = { ...PD.getDefaultValues(ConfalPyramidsParams), ...props };
return ConfalPyramids.fromCif(ctx, data, p);
}
});
type StepsSummaryTable = Table<typeof ConfalPyramids.Schema.ndb_struct_ntc_step_summary>;
function createPyramidsFromCif(model: Model,
steps: Table<typeof ConfalPyramids.Schema.ndb_struct_ntc_step>,
stepsSummary: StepsSummaryTable): CPT.PyramidsData {
const pyramids = new Array<CPT.Pyramid>();
const names = new Map<string, number>();
const locations = new Array<CPT.Location>();
let hasMultipleModels = false;
const {
id, PDB_model_number, name,
auth_asym_id_1, auth_seq_id_1, label_comp_id_1, label_alt_id_1, PDB_ins_code_1,
auth_asym_id_2, auth_seq_id_2, label_comp_id_2, label_alt_id_2, PDB_ins_code_2,
_rowCount } = steps;
if (_rowCount !== stepsSummary._rowCount) throw new Error('Inconsistent mmCIF data');
for (let i = 0; i < _rowCount; i++) {
const model_num = PDB_model_number.value(i);
if (model_num !== model.modelNum) {
hasMultipleModels = true;
continue; // We are only interested in data for the current model
}
const { _NtC, _confal_score } = getNtCAndConfalScore(id.value(i), i, stepsSummary);
const pyramid = {
PDB_model_number: model_num,
name: name.value(i),
auth_asym_id_1: auth_asym_id_1.value(i),
auth_seq_id_1: auth_seq_id_1.value(i),
label_comp_id_1: label_comp_id_1.value(i),
label_alt_id_1: label_alt_id_1.value(i),
PDB_ins_code_1: PDB_ins_code_1.value(i),
auth_asym_id_2: auth_asym_id_2.value(i),
auth_seq_id_2: auth_seq_id_2.value(i),
label_comp_id_2: label_comp_id_2.value(i),
label_alt_id_2: label_alt_id_2.value(i),
PDB_ins_code_2: PDB_ins_code_2.value(i),
confal_score: _confal_score,
NtC: _NtC
};
pyramids.push(pyramid);
names.set(pyramid.name, pyramids.length - 1);
locations.push(CPT.Location(pyramid, false));
locations.push(CPT.Location(pyramid, true));
}
return { pyramids, names, locations, hasMultipleModels };
}
function getNtCAndConfalScore(id: number, i: number, stepsSummary: StepsSummaryTable) {
const { step_id, confal_score, assigned_NtC } = stepsSummary;
// Assume that step_ids in ntc_step_summary are in the same order as steps in ntc_step
for (let j = i; j < stepsSummary._rowCount; j++) {
if (id === step_id.value(j)) return { _NtC: assigned_NtC.value(j), _confal_score: confal_score.value(j) };
}
// Safety net for cases where the previous assumption is not met
for (let j = 0; j < i; j++) {
if (id === step_id.value(j)) return { _NtC: assigned_NtC.value(j), _confal_score: confal_score.value(j) };
}
throw new Error('Inconsistent mmCIF data');
}

View File

@@ -0,0 +1,186 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Michal Malý <michal.maly@ibt.cas.cz>
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { ConfalPyramids, ConfalPyramidsProvider } from './property';
import { ConfalPyramidsUtil } from './util';
import { ConfalPyramidsTypes as CPT } from './types';
import { Interval } from '../../../mol-data/int';
import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
import { PickingId } from '../../../mol-geo/geometry/picking';
import { PrimitiveBuilder } from '../../../mol-geo/primitive/primitive';
import { LocationIterator } from '../../../mol-geo/util/location-iterator';
import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
import { EmptyLoci, Loci } from '../../../mol-model/loci';
import { Structure, StructureProperties, Unit } from '../../../mol-model/structure';
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../../mol-repr/representation';
import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder, UnitsRepresentation } from '../../../mol-repr/structure/representation';
import { StructureGroup, UnitsMeshParams, UnitsMeshVisual, UnitsVisual } from '../../../mol-repr/structure/units-visual';
import { VisualUpdateState } from '../../../mol-repr/util';
import { VisualContext } from '../../../mol-repr/visual';
import { getAltResidueLociFromId } from '../../../mol-repr/structure/visual/util/common';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Theme, ThemeRegistryContext } from '../../../mol-theme/theme';
import { NullLocation } from '../../../mol-model/location';
const t = Mat4.identity();
const w = Vec3.zero();
const mp = Vec3.zero();
function calcMidpoint(mp: Vec3, v: Vec3, w: Vec3) {
Vec3.sub(mp, v, w);
Vec3.scale(mp, mp, 0.5);
Vec3.add(mp, mp, w);
}
function shiftVertex(vec: Vec3, ref: Vec3, scale: number) {
Vec3.sub(w, vec, ref);
Vec3.scale(w, w, scale);
Vec3.add(vec, vec, w);
}
const ConfalPyramidsMeshParams = {
...UnitsMeshParams
};
type ConfalPyramidsMeshParams = typeof ConfalPyramidsMeshParams;
function createConfalPyramidsIterator(structureGroup: StructureGroup): LocationIterator {
const { structure, group } = structureGroup;
const instanceCount = group.units.length;
const prop = ConfalPyramidsProvider.get(structure.model).value;
if (prop === undefined || prop.data === undefined) {
return LocationIterator(0, 1, () => NullLocation);
}
const { locations } = prop.data;
const getLocation = (groupIndex: number, instanceIndex: number) => {
if (locations.length <= groupIndex) return NullLocation;
return locations[groupIndex];
};
return LocationIterator(locations.length, instanceCount, getLocation);
}
function createConfalPyramidsMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<ConfalPyramidsMeshParams>, mesh?: Mesh) {
if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh);
const prop = ConfalPyramidsProvider.get(structure.model).value;
if (prop === undefined || prop.data === undefined) return Mesh.createEmpty(mesh);
const { pyramids } = prop.data;
if (pyramids.length === 0) return Mesh.createEmpty(mesh);
const mb = MeshBuilder.createState(512, 512, mesh);
const handler = (pyramid: CPT.Pyramid, first: ConfalPyramidsUtil.FirstResidueAtoms, second: ConfalPyramidsUtil.SecondResidueAtoms, firsLocIndex: number, secondLocIndex: number) => {
if (firsLocIndex === -1 || secondLocIndex === -1)
throw new Error('Invalid location index');
const scale = (pyramid.confal_score - 20.0) / 100.0;
const O3 = first.O3.pos;
const OP1 = second.OP1.pos; const OP2 = second.OP2.pos; const O5 = second.O5.pos; const P = second.P.pos;
shiftVertex(O3, P, scale);
shiftVertex(OP1, P, scale);
shiftVertex(OP2, P, scale);
shiftVertex(O5, P, scale);
calcMidpoint(mp, O3, O5);
mb.currentGroup = firsLocIndex;
let pb = PrimitiveBuilder(3);
/* Upper part (for first residue in step) */
pb.add(O3, OP1, OP2);
pb.add(O3, mp, OP1);
pb.add(O3, OP2, mp);
MeshBuilder.addPrimitive(mb, t, pb.getPrimitive());
/* Lower part (for second residue in step */
mb.currentGroup = secondLocIndex;
pb = PrimitiveBuilder(3);
pb.add(mp, O5, OP1);
pb.add(mp, OP2, O5);
pb.add(O5, OP2, OP1);
MeshBuilder.addPrimitive(mb, t, pb.getPrimitive());
};
const walker = new ConfalPyramidsUtil.UnitWalker(structure, unit, handler);
walker.walk();
return MeshBuilder.getMesh(mb);
}
function getConfalPyramidLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) {
const { groupId, objectId, instanceId } = pickingId;
if (objectId !== id) return EmptyLoci;
const { structure } = structureGroup;
const unit = structureGroup.group.units[instanceId];
if (!Unit.isAtomic(unit)) return EmptyLoci;
const prop = ConfalPyramidsProvider.get(structure.model).value;
if (prop === undefined || prop.data === undefined) return EmptyLoci;
const { locations } = prop.data;
if (locations.length <= groupId) return EmptyLoci;
const altId = StructureProperties.atom.label_alt_id(CPT.toElementLocation(locations[groupId]));
const rI = unit.residueIndex[locations[groupId].element.element];
return getAltResidueLociFromId(structure, unit, rI, altId);
}
function eachConfalPyramid(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
return false; // TODO: Implement me
}
function ConfalPyramidsVisual(materialId: number): UnitsVisual<ConfalPyramidsMeshParams> {
return UnitsMeshVisual<ConfalPyramidsMeshParams>({
defaultProps: PD.getDefaultValues(ConfalPyramidsMeshParams),
createGeometry: createConfalPyramidsMesh,
createLocationIterator: createConfalPyramidsIterator,
getLoci: getConfalPyramidLoci,
eachLocation: eachConfalPyramid,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ConfalPyramidsMeshParams>, currentProps: PD.Values<ConfalPyramidsMeshParams>) => {
}
}, materialId);
}
const ConfalPyramidsVisuals = {
'confal-pyramids-symbol': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, UnitsMeshParams>) => UnitsRepresentation('Confal Pyramids Symbol Mesh', ctx, getParams, ConfalPyramidsVisual),
};
export const ConfalPyramidsParams = {
...UnitsMeshParams
};
export type ConfalPyramidsParams = typeof ConfalPyramidsParams;
export function getConfalPyramidsParams(ctx: ThemeRegistryContext, structure: Structure) {
return PD.clone(ConfalPyramidsParams);
}
export type ConfalPyramidsRepresentation = StructureRepresentation<ConfalPyramidsParams>;
export function ConfalPyramidsRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ConfalPyramidsParams>): ConfalPyramidsRepresentation {
const repr = Representation.createMulti('Confal Pyramids', ctx, getParams, StructureRepresentationStateBuilder, ConfalPyramidsVisuals as unknown as Representation.Def<Structure, ConfalPyramidsParams>);
return repr;
}
export const ConfalPyramidsRepresentationProvider = StructureRepresentationProvider({
name: 'confal-pyramids',
label: 'Confal Pyramids',
description: 'Displays schematic depiction of conformer classes and confal values',
factory: ConfalPyramidsRepresentation,
getParams: getConfalPyramidsParams,
defaultValues: PD.getDefaultValues(ConfalPyramidsParams),
defaultColorTheme: { name: 'confal-pyramids' },
defaultSizeTheme: { name: 'uniform' },
isApplicable: (structure: Structure) => structure.models.some(m => ConfalPyramids.isApplicable(m)),
ensureCustomProperties: {
attach: (ctx: CustomProperty.Context, structure: Structure) => ConfalPyramidsProvider.attach(ctx, structure.model, void 0, true),
detach: (data) => ConfalPyramidsProvider.ref(data.model, false),
}
});

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Michal Malý <michal.maly@ibt.cas.cz>
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { DataLocation } from '../../../mol-model/location';
import { ElementIndex, Structure, StructureElement, Unit } from '../../../mol-model/structure';
export namespace ConfalPyramidsTypes {
export type Pyramid = {
PDB_model_number: number,
name: string,
auth_asym_id_1: string,
auth_seq_id_1: number,
label_comp_id_1: string,
label_alt_id_1: string,
PDB_ins_code_1: string,
auth_asym_id_2: string,
auth_seq_id_2: number,
label_comp_id_2: string,
label_alt_id_2: string,
PDB_ins_code_2: string,
confal_score: number,
NtC: string
}
export interface PyramidsData {
pyramids: Array<Pyramid>,
names: Map<string, number>,
locations: Array<Location>,
hasMultipleModels: boolean
}
export interface LocationData {
readonly pyramid: Pyramid
readonly isLower: boolean;
}
export interface Element {
structure: Structure;
unit: Unit.Atomic;
element: ElementIndex;
}
export interface Location extends DataLocation<LocationData, Element> {}
export function Location(pyramid: Pyramid, isLower: boolean, structure?: Structure, unit?: Unit.Atomic, element?: ElementIndex) {
return DataLocation('pyramid', { pyramid, isLower }, { structure: structure as any, unit: unit as any, element: element as any });
}
export function isLocation(x: any): x is Location {
return !!x && x.kind === 'data-location' && x.tag === 'pyramid';
}
export function toElementLocation(location: Location) {
return StructureElement.Location.create(location.element.structure, location.element.unit, location.element.element);
}
}

View File

@@ -0,0 +1,299 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Michal Malý <michal.maly@ibt.cas.cz>
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { ConfalPyramidsProvider } from './property';
import { ConfalPyramidsTypes as CPT } from './types';
import { OrderedSet, Segmentation } from '../../../mol-data/int';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, StructureProperties, Unit } from '../../../mol-model/structure';
export namespace ConfalPyramidsUtil {
type Residue = Segmentation.Segment<ResidueIndex>;
export type AtomInfo = {
pos: Vec3,
index: ElementIndex,
fakeAltId: string,
};
export type FirstResidueAtoms = {
O3: AtomInfo,
};
export type SecondResidueAtoms = {
OP1: AtomInfo,
OP2: AtomInfo,
O5: AtomInfo,
P: AtomInfo,
};
type ResidueInfo = {
PDB_model_num: number,
asym_id: string,
auth_asym_id: string,
seq_id: number,
auth_seq_id: number,
comp_id: string,
alt_id: string,
ins_code: string,
};
export type Handler = (pyramid: CPT.Pyramid, first: FirstResidueAtoms, second: SecondResidueAtoms, firstLocIndex: number, secondLocIndex: number) => void;
function residueInfoFromLocation(loc: StructureElement.Location): ResidueInfo {
return {
PDB_model_num: StructureProperties.unit.model_num(loc),
asym_id: StructureProperties.chain.label_asym_id(loc),
auth_asym_id: StructureProperties.chain.auth_asym_id(loc),
seq_id: StructureProperties.residue.label_seq_id(loc),
auth_seq_id: StructureProperties.residue.auth_seq_id(loc),
comp_id: StructureProperties.atom.label_comp_id(loc),
alt_id: StructureProperties.atom.label_alt_id(loc),
ins_code: StructureProperties.residue.pdbx_PDB_ins_code(loc)
};
}
export function hasMultipleModels(unit: Unit.Atomic): boolean {
const prop = ConfalPyramidsProvider.get(unit.model).value;
if (prop === undefined || prop.data === undefined) throw new Error('No custom properties data');
return prop.data.hasMultipleModels;
}
function getPossibleAltIdsIndices(eIFirst: ElementIndex, eILast: ElementIndex, structure: Structure, unit: Unit.Atomic): string[] {
const loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
const uIFirst = OrderedSet.indexOf(unit.elements, eIFirst);
const uILast = OrderedSet.indexOf(unit.elements, eILast);
const possibleAltIds: string[] = [];
for (let uI = uIFirst; uI <= uILast; uI++) {
loc.element = unit.elements[uI];
const altId = StructureProperties.atom.label_alt_id(loc);
if (altId !== '' && !possibleAltIds.includes(altId)) possibleAltIds.push(altId);
}
return possibleAltIds;
}
function getPossibleAltIdsResidue(residue: Residue, structure: Structure, unit: Unit.Atomic): string[] {
return getPossibleAltIdsIndices(unit.elements[residue.start], unit.elements[residue.end - 1], structure, unit);
}
class Utility {
protected getPyramidByName(name: string): { pyramid: CPT.Pyramid | undefined, index: number } {
const index = this.data.names.get(name);
if (index === undefined) return { pyramid: undefined, index: -1 };
return { pyramid: this.data.pyramids[index], index };
}
protected stepToName(entry_id: string, modelNum: number, locFirst: StructureElement.Location, locSecond: StructureElement.Location, fakeAltId_1: string, fakeAltId_2: string) {
const first = residueInfoFromLocation(locFirst);
const second = residueInfoFromLocation(locSecond);
const model_id = this.hasMultipleModels ? `-m${modelNum}` : '';
const alt_id_1 = fakeAltId_1 !== '' ? `.${fakeAltId_1}` : (first.alt_id.length ? `.${first.alt_id}` : '');
const alt_id_2 = fakeAltId_2 !== '' ? `.${fakeAltId_2}` : (second.alt_id.length ? `.${second.alt_id}` : '');
const ins_code_1 = first.ins_code.length ? `.${first.ins_code}` : '';
const ins_code_2 = second.ins_code.length ? `.${second.ins_code}` : '';
return `${entry_id}${model_id}_${first.auth_asym_id}_${first.comp_id}${alt_id_1}_${first.auth_seq_id}${ins_code_1}_${second.comp_id}${alt_id_2}_${second.auth_seq_id}${ins_code_2}`;
}
constructor(unit: Unit.Atomic) {
const prop = ConfalPyramidsProvider.get(unit.model).value;
if (prop === undefined || prop.data === undefined) throw new Error('No custom properties data');
this.data = prop.data;
this.hasMultipleModels = hasMultipleModels(unit);
this.entryId = unit.model.entryId.toLowerCase();
this.modelNum = unit.model.modelNum;
}
protected readonly data: CPT.PyramidsData
protected readonly hasMultipleModels: boolean;
protected readonly entryId: string;
protected readonly modelNum: number;
}
export class UnitWalker extends Utility {
private getAtomIndices(names: string[], residue: Residue): ElementIndex[] {
let rI = residue.start;
const rILast = residue.end - 1;
const indices: ElementIndex[] = [];
for (; rI !== rILast; rI++) {
const eI = this.unit.elements[rI];
const loc = StructureElement.Location.create(this.structure, this.unit, eI);
const thisName = StructureProperties.atom.label_atom_id(loc);
if (names.includes(thisName)) indices.push(eI);
}
if (indices.length === 0)
throw new Error(`Element ${name} not found on residue ${residue.index}`);
return indices;
}
private getAtomPositions(indices: ElementIndex[]): Vec3[] {
const pos = this.unit.conformation.invariantPosition;
const positions: Vec3[] = [];
for (const eI of indices) {
const v = Vec3.zero();
pos(eI, v);
positions.push(v);
}
return positions;
}
private handleStep(firstAtoms: FirstResidueAtoms[], secondAtoms: SecondResidueAtoms[]) {
const modelNum = this.hasMultipleModels ? this.modelNum : -1;
let ok = false;
const firstLoc = StructureElement.Location.create(this.structure, this.unit, -1 as ElementIndex);
const secondLoc = StructureElement.Location.create(this.structure, this.unit, -1 as ElementIndex);
for (let i = 0; i < firstAtoms.length; i++) {
const first = firstAtoms[i];
for (let j = 0; j < secondAtoms.length; j++) {
const second = secondAtoms[j];
firstLoc.element = first.O3.index;
secondLoc.element = second.OP1.index;
const name = this.stepToName(this.entryId, modelNum, firstLoc, secondLoc, first.O3.fakeAltId, second.OP1.fakeAltId);
const { pyramid, index } = this.getPyramidByName(name);
if (pyramid !== undefined) {
const setLoc = (loc: CPT.Location, eI: ElementIndex) => {
loc.element.structure = this.structure;
loc.element.unit = this.unit;
loc.element.element = eI;
};
const locIndex = index * 2;
setLoc(this.data.locations[locIndex], firstLoc.element);
setLoc(this.data.locations[locIndex + 1], secondLoc.element);
this.handler(pyramid, first, second, locIndex, locIndex + 1);
ok = true;
}
}
}
if (!ok) throw new Error('Bogus step');
}
private processFirstResidue(residue: Residue, possibleAltIds: string[]) {
const indO3 = this.getAtomIndices(['O3\'', 'O3*'], residue);
const posO3 = this.getAtomPositions(indO3);
const altPos: FirstResidueAtoms[] = [
{ O3: { pos: posO3[0], index: indO3[0], fakeAltId: '' } }
];
for (let i = 1; i < indO3.length; i++) {
altPos.push({ O3: { pos: posO3[i], index: indO3[i], fakeAltId: '' } });
}
if (altPos.length === 1 && possibleAltIds.length > 1) {
/* We have some alternate positions on the residue but O3 does not have any - fake them */
altPos[0].O3.fakeAltId = possibleAltIds[0];
for (let i = 1; i < possibleAltIds.length; i++)
altPos.push({ O3: { pos: posO3[0], index: indO3[0], fakeAltId: possibleAltIds[i] } });
}
return altPos;
}
private processSecondResidue(residue: Residue, possibleAltIds: string[]) {
const indOP1 = this.getAtomIndices(['OP1'], residue);
const indOP2 = this.getAtomIndices(['OP2'], residue);
const indO5 = this.getAtomIndices(['O5\'', 'O5*'], residue);
const indP = this.getAtomIndices(['P'], residue);
const posOP1 = this.getAtomPositions(indOP1);
const posOP2 = this.getAtomPositions(indOP2);
const posO5 = this.getAtomPositions(indO5);
const posP = this.getAtomPositions(indP);
const infoOP1: AtomInfo[] = [];
/* We use OP1 as "pivotal" atom. There is no specific reason
* to pick OP1, it is as good a choice as any other atom
*/
if (indOP1.length === 1 && possibleAltIds.length > 1) {
/* No altIds on OP1, fake them */
for (const altId of possibleAltIds)
infoOP1.push({ pos: posOP1[0], index: indOP1[0], fakeAltId: altId });
} else {
for (let i = 0; i < indOP1.length; i++)
infoOP1.push({ pos: posOP1[i], index: indOP1[i], fakeAltId: '' });
}
const mkInfo = (i: number, indices: ElementIndex[], positions: Vec3[], altId: string) => {
if (i >= indices.length) {
const last = indices.length - 1;
return { pos: positions[last], index: indices[last], fakeAltId: altId };
}
return { pos: positions[i], index: indices[i], fakeAltId: altId };
};
const altPos: SecondResidueAtoms[] = [];
for (let i = 0; i < infoOP1.length; i++) {
const altId = infoOP1[i].fakeAltId;
const OP2 = mkInfo(i, indOP2, posOP2, altId);
const O5 = mkInfo(i, indO5, posO5, altId);
const P = mkInfo(i, indP, posP, altId);
altPos.push({ OP1: infoOP1[i], OP2, O5, P });
}
return altPos;
}
private step(residue: Residue): { firstAtoms: FirstResidueAtoms[], secondAtoms: SecondResidueAtoms[] } {
const firstPossibleAltIds = getPossibleAltIdsResidue(residue, this.structure, this.unit);
const firstAtoms = this.processFirstResidue(residue, firstPossibleAltIds);
residue = this.residueIt.move();
const secondPossibleAltIds = getPossibleAltIdsResidue(residue, this.structure, this.unit);
const secondAtoms = this.processSecondResidue(residue, secondPossibleAltIds);
return { firstAtoms, secondAtoms };
}
walk() {
while (this.chainIt.hasNext) {
this.residueIt.setSegment(this.chainIt.move());
let residue = this.residueIt.move();
while (this.residueIt.hasNext) {
try {
const { firstAtoms, secondAtoms } = this.step(residue);
this.handleStep(firstAtoms, secondAtoms);
} catch (error) {
/* Skip and move along */
residue = this.residueIt.move();
}
}
}
}
constructor(private structure: Structure, private unit: Unit.Atomic, private handler: Handler) {
super(unit);
this.chainIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, unit.elements);
this.residueIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements);
}
private chainIt: Segmentation.SegmentIterator<ChainIndex>;
private residueIt: Segmentation.SegmentIterator<ResidueIndex>;
}
}

View File

@@ -0,0 +1,8 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Michal Malý <michal.maly@ibt.cas.cz>
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
export { DnatcoConfalPyramids } from './confal-pyramids/behavior';

View File

@@ -181,8 +181,8 @@ export const AssemblySymmetryPreset = StructureRepresentationPresetProvider({
}
const assemblySymmetry = await tryCreateAssemblySymmetry(plugin, structureCell);
const globalThemeName = assemblySymmetry.isOk ? Tag.Cluster as any : undefined;
const preset = await PresetStructureRepresentations.auto.apply(ref, { ...params, globalThemeName }, plugin);
const colorTheme = assemblySymmetry.isOk ? Tag.Cluster as any : undefined;
const preset = await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
return { components: preset.components, representations: { ...preset.representations, assemblySymmetry } };
}

View File

@@ -35,7 +35,7 @@ export function isBiologicalAssembly(structure: Structure): boolean {
const mmcif = structure.models[0].sourceData.data.db;
if (!mmcif.pdbx_struct_assembly.details.isDefined) return false;
const id = structure.units[0].conformation.operator.assembly?.id || '';
if (id === '' || id === 'deposited') return true;
if (id === '') return true;
const indices = Column.indicesOf(mmcif.pdbx_struct_assembly.id, e => e === id);
if (indices.length !== 1) return false;
const details = mmcif.pdbx_struct_assembly.details.value(indices[0]);
@@ -63,7 +63,7 @@ export namespace AssemblySymmetry {
const client = new GraphQLClient(props.serverUrl, ctx.assetManager);
const variables: AssemblySymmetryQueryVariables = {
assembly_id: structure.units[0].conformation.operator.assembly?.id || 'deposited',
assembly_id: structure.units[0].conformation.operator.assembly?.id || '',
entry_id: structure.units[0].model.entryId
};
const result = await client.request(ctx.runtime, query, variables);

View File

@@ -16,8 +16,7 @@ import { StateAction, StateSelection } from '../../../mol-state';
import { PluginStateObject } from '../../../mol-plugin-state/objects';
import { PluginContext } from '../../../mol-plugin/context';
import { Task } from '../../../mol-task';
import Check from '@material-ui/icons/Check';
import Extension from '@material-ui/icons/Extension';
import { ExtensionSvg, CheckSvg } from '../../../mol-plugin-ui/controls/icons';
interface AssemblySymmetryControlState extends CollapsableState {
isBusy: boolean
@@ -30,7 +29,7 @@ export class AssemblySymmetryControls extends CollapsableControls<{}, AssemblySy
isCollapsed: false,
isBusy: false,
isHidden: true,
brand: { accent: 'cyan', svg: Extension }
brand: { accent: 'cyan', svg: ExtensionSvg }
};
}
@@ -62,7 +61,7 @@ export class AssemblySymmetryControls extends CollapsableControls<{}, AssemblySy
renderEnable() {
const pivot = this.pivot;
if (!pivot.cell.parent) return null;
return <ApplyActionControl state={pivot.cell.parent} action={EnableAssemblySymmetry3D} initiallyCollapsed={true} nodeRef={pivot.cell.transform.ref} simpleApply={{ header: 'Enable', icon: Check }} />;
return <ApplyActionControl state={pivot.cell.parent} action={EnableAssemblySymmetry3D} initiallyCollapsed={true} nodeRef={pivot.cell.transform.ref} simpleApply={{ header: 'Enable', icon: CheckSvg }} />;
}
renderNoSymmetries() {

File diff suppressed because it is too large Load Diff

View File

@@ -309,27 +309,28 @@ export const ValidationReportGeometryQualityPreset = StructureRepresentationPres
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const model = structureCell?.obj?.data.model;
if (!structureCell || !model) return {};
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
await plugin.runTask(Task.create('Validation Report', async runtime => {
await ValidationReportProvider.attach({ runtime, assetManager: plugin.managers.asset }, model);
await ValidationReportProvider.attach({ runtime, assetManager: plugin.managers.asset }, structure.models[0]);
}));
const colorTheme = GeometryQualityColorThemeProvider.name as any;
const { components, representations } = await PresetStructureRepresentations.auto.apply(ref, { ...params, globalThemeName: colorTheme }, plugin);
const { components, representations } = await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
const clashes = await plugin.builders.structure.tryCreateComponentFromExpression(structureCell, hasClash.expression, 'clashes', { label: 'Clashes' });
const { update, builder, typeParams, color } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
let clashesBallAndStick, clashesSnfg3d;
let clashesBallAndStick, clashesRepr;
if (representations) {
clashesBallAndStick = builder.buildRepresentation(update, clashes, { type: 'ball-and-stick', typeParams, color: colorTheme }, { tag: 'clashes-ball-and-stick' });
clashesSnfg3d = builder.buildRepresentation<any>(update, clashes, { type: ClashesRepresentationProvider.name, typeParams, color }, { tag: 'clashes-snfg-3d' });
clashesRepr = builder.buildRepresentation<any>(update, clashes, { type: ClashesRepresentationProvider.name, typeParams, color }, { tag: 'clashes-repr' });
}
await update.commit({ revertOnError: true });
return { components: { ...components, clashes }, representations: { ...representations, clashesBallAndStick, clashesSnfg3d } };
return { components: { ...components, clashes }, representations: { ...representations, clashesBallAndStick, clashesRepr } };
}
});
@@ -345,15 +346,15 @@ export const ValidationReportDensityFitPreset = StructureRepresentationPresetPro
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const model = structureCell?.obj?.data.model;
if (!structureCell || !model) return {};
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
await plugin.runTask(Task.create('Validation Report', async runtime => {
await ValidationReportProvider.attach({ runtime, assetManager: plugin.managers.asset }, model);
await ValidationReportProvider.attach({ runtime, assetManager: plugin.managers.asset }, structure.models[0]);
}));
const colorTheme = DensityFitColorThemeProvider.name as any;
return await PresetStructureRepresentations.auto.apply(ref, { ...params, globalThemeName: colorTheme }, plugin);
return await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
}
});
@@ -369,14 +370,14 @@ export const ValidationReportRandomCoilIndexPreset = StructureRepresentationPres
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const model = structureCell?.obj?.data.model;
if (!structureCell || !model) return {};
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
await plugin.runTask(Task.create('Validation Report', async runtime => {
await ValidationReportProvider.attach({ runtime, assetManager: plugin.managers.asset }, model);
await ValidationReportProvider.attach({ runtime, assetManager: plugin.managers.asset }, structure.models[0]);
}));
const colorTheme = RandomCoilIndexColorThemeProvider.name as any;
return await PresetStructureRepresentations.auto.apply(ref, { ...params, globalThemeName: colorTheme }, plugin);
return await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
}
});

View File

@@ -15,7 +15,7 @@ import { Interval } from '../../../mol-data/int';
import { RepresentationContext, RepresentationParamsGetter, Representation } from '../../../mol-repr/representation';
import { UnitsRepresentation, StructureRepresentation, StructureRepresentationStateBuilder, StructureRepresentationProvider, ComplexRepresentation } from '../../../mol-repr/structure/representation';
import { VisualContext } from '../../../mol-repr/visual';
import { createLinkCylinderMesh, LinkCylinderParams, LinkCylinderStyle } from '../../../mol-repr/structure/visual/util/link';
import { createLinkCylinderMesh, LinkCylinderParams, LinkStyle } from '../../../mol-repr/structure/visual/util/link';
import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual, StructureGroup } from '../../../mol-repr/structure/units-visual';
import { VisualUpdateState } from '../../../mol-repr/util';
import { LocationIterator } from '../../../mol-geo/util/location-iterator';
@@ -50,7 +50,7 @@ function createIntraUnitClashCylinderMesh(ctx: VisualContext, unit: Unit, struct
pos(elements[a[edgeIndex]], posA);
pos(elements[b[edgeIndex]], posB);
},
style: (edgeIndex: number) => LinkCylinderStyle.Disk,
style: (edgeIndex: number) => LinkStyle.Disk,
radius: (edgeIndex: number) => magnitude[edgeIndex] * sizeFactor,
};
@@ -163,7 +163,7 @@ function createInterUnitClashCylinderMesh(ctx: VisualContext, structure: Structu
uA.conformation.position(uA.elements[b.indexA], posA);
uB.conformation.position(uB.elements[b.indexB], posB);
},
style: (edgeIndex: number) => LinkCylinderStyle.Disk,
style: (edgeIndex: number) => LinkStyle.Disk,
radius: (edgeIndex: number) => edges[edgeIndex].props.magnitude * sizeFactor
};

View File

@@ -265,6 +265,7 @@ namespace Canvas3D {
}
let forceNextDraw = false;
let forceDrawAfterAllCommited = false;
let currentTime = 0;
function draw(force?: boolean) {
@@ -300,7 +301,14 @@ namespace Canvas3D {
function commit(isSynchronous: boolean = false) {
const allCommited = commitScene(isSynchronous);
// Only reset the camera after the full scene has been commited.
if (allCommited) resolveCameraReset();
if (allCommited) {
resolveCameraReset();
if (forceDrawAfterAllCommited) {
if (debugHelper.isEnabled) debugHelper.update();
draw(true);
forceDrawAfterAllCommited = false;
}
}
}
function resolveCameraReset() {
@@ -393,6 +401,7 @@ namespace Canvas3D {
reprRenderObjects.set(repr, newRO);
scene.update(repr.renderObjects, false);
forceDrawAfterAllCommited = true;
if (isDebugMode) consoleStats();
}
@@ -404,6 +413,7 @@ namespace Canvas3D {
renderObjects.forEach(o => scene.remove(o));
reprRenderObjects.delete(repr);
scene.update(repr.renderObjects, false, true);
forceDrawAfterAllCommited = true;
if (isDebugMode) consoleStats();
}
}
@@ -470,6 +480,7 @@ namespace Canvas3D {
} else {
scene.update(void 0, !!keepSphere);
}
forceDrawAfterAllCommited = true;
},
clear: () => {
reprUpdatedSubscriptions.forEach(v => v.unsubscribe());
@@ -489,6 +500,7 @@ namespace Canvas3D {
if (scene.syncVisibility()) {
if (debugHelper.isEnabled) debugHelper.update();
}
requestDraw(true);
},
// draw,

View File

@@ -220,7 +220,13 @@ namespace Column {
} else {
for (let i = 0, _i = c.rowCount; i < _i; i++) array[offset + i] = c.value(i);
}
}
export function isIdentity<T extends number>(c: Column<T>) {
for (let i = 0, _i = c.rowCount; i < _i; i++) {
if (i !== c.value(i)) return false;
}
return true;
}
}

View File

@@ -0,0 +1,67 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../mol-util/value-cell';
import { Vec2 } from '../../mol-math/linear-algebra';
import { TextureImage, createTextureImage } from '../../mol-gl/renderable/util';
import { Clipping } from '../../mol-theme/clipping';
export type ClippingData = {
dClipObjectCount: ValueCell<number>,
dClipVariant: ValueCell<string>,
tClipping: ValueCell<TextureImage<Uint8Array>>
uClippingTexDim: ValueCell<Vec2>
dClipping: ValueCell<boolean>,
}
export function applyClippingGroups(array: Uint8Array, start: number, end: number, groups: Clipping.Groups) {
for (let i = start; i < end; ++i) {
array[i] = groups;
}
return true;
}
export function clearClipping(array: Uint8Array, start: number, end: number) {
array.fill(0, start, end);
}
export function createClipping(count: number, clippingData?: ClippingData): ClippingData {
const clipping = createTextureImage(Math.max(1, count), 1, Uint8Array, clippingData && clippingData.tClipping.ref.value.array);
if (clippingData) {
ValueCell.update(clippingData.tClipping, clipping);
ValueCell.update(clippingData.uClippingTexDim, Vec2.create(clipping.width, clipping.height));
ValueCell.update(clippingData.dClipping, count > 0);
return clippingData;
} else {
return {
dClipObjectCount: ValueCell.create(0),
dClipVariant: ValueCell.create('instance'),
tClipping: ValueCell.create(clipping),
uClippingTexDim: ValueCell.create(Vec2.create(clipping.width, clipping.height)),
dClipping: ValueCell.create(count > 0),
};
}
}
const emptyClippingTexture = { array: new Uint8Array(1), width: 1, height: 1 };
export function createEmptyClipping(clippingData?: ClippingData): ClippingData {
if (clippingData) {
ValueCell.update(clippingData.tClipping, emptyClippingTexture);
ValueCell.update(clippingData.uClippingTexDim, Vec2.create(1, 1));
return clippingData;
} else {
return {
dClipObjectCount: ValueCell.create(0),
dClipVariant: ValueCell.create('instance'),
tClipping: ValueCell.create(emptyClippingTexture),
uClippingTexDim: ValueCell.create(Vec2.create(1, 1)),
dClipping: ValueCell.create(false),
};
}
}

View File

@@ -12,7 +12,7 @@ import { DirectVolumeValues } from '../../../mol-gl/renderable/direct-volume';
import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { Texture } from '../../../mol-gl/webgl/texture';
import { Box3D, Sphere3D } from '../../../mol-math/geometry';
import { Mat4, Vec2, Vec3 } from '../../../mol-math/linear-algebra';
import { Mat4, Vec2, Vec3, Vec4 } from '../../../mol-math/linear-algebra';
import { Theme } from '../../../mol-theme/theme';
import { ValueCell } from '../../../mol-util';
import { Color } from '../../../mol-util/color';
@@ -26,6 +26,7 @@ import { createEmptyOverpaint } from '../overpaint-data';
import { TransformData } from '../transform-data';
import { createEmptyTransparency } from '../transparency-data';
import { createTransferFunctionTexture, getControlPointsFromVec2Array } from './transfer-function';
import { createEmptyClipping } from '../clipping-data';
const VolumeBox = Box();
const RenderModeOptions = [['isosurface', 'Isosurface'], ['volume', 'Volume']] as [string, string][];
@@ -140,6 +141,7 @@ export namespace DirectVolume {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: VolumeBox.indices.length, groupCount, instanceCount };
@@ -156,6 +158,7 @@ export namespace DirectVolume {
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
...BaseGeometry.createValues(props, counts),
@@ -163,6 +166,7 @@ export namespace DirectVolume {
elements: ValueCell.create(VolumeBox.indices as Uint32Array),
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere)),
uIsoValue: ValueCell.create(props.isoValueNorm),
uBboxMin: bboxMin,
@@ -204,6 +208,7 @@ export namespace DirectVolume {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
}

View File

@@ -9,7 +9,7 @@ import { LocationIterator } from '../../../mol-geo/util/location-iterator';
import { RenderableState } from '../../../mol-gl/renderable';
import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere, TextureImage } from '../../../mol-gl/renderable/util';
import { Sphere3D } from '../../../mol-math/geometry';
import { Vec2 } from '../../../mol-math/linear-algebra';
import { Vec2, Vec4 } from '../../../mol-math/linear-algebra';
import { Theme } from '../../../mol-theme/theme';
import { ValueCell } from '../../../mol-util';
import { Color } from '../../../mol-util/color';
@@ -23,6 +23,7 @@ import { TransformData } from '../transform-data';
import { createEmptyTransparency } from '../transparency-data';
import { ImageValues } from '../../../mol-gl/renderable/image';
import { fillSerial } from '../../../mol-util/array';
import { createEmptyClipping } from '../clipping-data';
const QuadIndices = new Uint32Array([
0, 1, 2,
@@ -137,6 +138,7 @@ namespace Image {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: QuadIndices.length, groupCount, instanceCount };
@@ -148,6 +150,7 @@ namespace Image {
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
...BaseGeometry.createValues(props, counts),
@@ -159,6 +162,7 @@ namespace Image {
aGroup: ValueCell.create(fillSerial(new Float32Array(4))),
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere)),
dInterpolation: ValueCell.create(props.interpolation),
@@ -188,6 +192,7 @@ namespace Image {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
}

View File

@@ -83,7 +83,7 @@ export namespace LinesBuilder {
const gb = ChunkedArray.compact(groups, true) as Float32Array;
const sb = ChunkedArray.compact(starts, true) as Float32Array;
const eb = ChunkedArray.compact(ends, true) as Float32Array;
return Lines.create(mb, ib, gb, sb, eb, indices.elementCount / 2);
return Lines.create(mb, ib, gb, sb, eb, indices.elementCount / 2, lines);
}
};
}

View File

@@ -5,7 +5,7 @@
*/
import { ValueCell } from '../../../mol-util';
import { Mat4 } from '../../../mol-math/linear-algebra';
import { Mat4, Vec4 } from '../../../mol-math/linear-algebra';
import { transformPositionArray, GroupMapping, createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
import { createColors } from '../color-data';
@@ -25,6 +25,7 @@ import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
import { createEmptyClipping } from '../clipping-data';
/** Wide line */
export interface Lines {
@@ -184,6 +185,7 @@ export namespace Lines {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: lines.lineCount * 2 * 3, groupCount, instanceCount };
@@ -198,11 +200,13 @@ export namespace Lines {
elements: lines.indexBuffer,
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere)),
...color,
...size,
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
...BaseGeometry.createValues(props, counts),
@@ -234,6 +238,7 @@ export namespace Lines {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
}
}

View File

@@ -6,7 +6,7 @@
*/
import { ValueCell } from '../../../mol-util';
import { Vec3, Mat4, Mat3 } from '../../../mol-math/linear-algebra';
import { Vec3, Mat4, Mat3, Vec4 } from '../../../mol-math/linear-algebra';
import { Sphere3D } from '../../../mol-math/geometry';
import { transformPositionArray, transformDirectionArray, computeIndexedVertexNormals, GroupMapping, createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
@@ -23,6 +23,7 @@ import { Color } from '../../../mol-util/color';
import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { createEmptyClipping } from '../clipping-data';
export interface Mesh {
readonly kind: 'mesh',
@@ -355,6 +356,7 @@ export namespace Mesh {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount };
@@ -368,10 +370,12 @@ export namespace Mesh {
elements: mesh.indexBuffer,
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere)),
...color,
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
...BaseGeometry.createValues(props, counts),
@@ -405,6 +409,7 @@ export namespace Mesh {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
}
}

View File

@@ -15,10 +15,10 @@ export type OverpaintData = {
dOverpaint: ValueCell<boolean>,
}
export function applyOverpaintColor(array: Uint8Array, start: number, end: number, color: Color, alpha: number) {
export function applyOverpaintColor(array: Uint8Array, start: number, end: number, color: Color) {
for (let i = start; i < end; ++i) {
Color.toArray(color, array, i * 4);
array[i * 4 + 3] = alpha * 255;
array[i * 4 + 3] = 255;
}
return true;
}

View File

@@ -5,7 +5,7 @@
*/
import { ValueCell } from '../../../mol-util';
import { Mat4 } from '../../../mol-math/linear-algebra';
import { Mat4, Vec4 } from '../../../mol-math/linear-algebra';
import { transformPositionArray, GroupMapping, createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
import { createColors } from '../color-data';
@@ -24,6 +24,7 @@ import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
import { createEmptyClipping } from '../clipping-data';
/** Point cloud */
export interface Points {
@@ -143,6 +144,7 @@ export namespace Points {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: points.pointCount, groupCount, instanceCount };
@@ -154,11 +156,13 @@ export namespace Points {
aGroup: points.groupBuffer,
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere)),
...color,
...size,
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
...BaseGeometry.createValues(props, counts),
@@ -192,6 +196,7 @@ export namespace Points {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
}

View File

@@ -22,6 +22,8 @@ import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
import { GroupMapping, createGroupMapping } from '../../util';
import { createEmptyClipping } from '../clipping-data';
import { Vec4 } from '../../../mol-math/linear-algebra';
export interface Spheres {
readonly kind: 'spheres',
@@ -147,6 +149,7 @@ export namespace Spheres {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: spheres.sphereCount * 2 * 3, groupCount, instanceCount };
@@ -161,11 +164,13 @@ export namespace Spheres {
elements: spheres.indexBuffer,
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere)),
...color,
...size,
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
padding: ValueCell.create(padding),
@@ -200,6 +205,7 @@ export namespace Spheres {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
ValueCell.update(values.padding, padding);
}

View File

@@ -18,7 +18,7 @@ import { Sphere3D } from '../../../mol-math/geometry';
import { TextureImage, createTextureImage, calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { TextValues } from '../../../mol-gl/renderable/text';
import { Color } from '../../../mol-util/color';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { Vec3, Vec4 } from '../../../mol-math/linear-algebra';
import { FontAtlasParams } from './font-atlas';
import { RenderableState } from '../../../mol-gl/renderable';
import { clamp } from '../../../mol-math/interpolate';
@@ -28,6 +28,7 @@ import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
import { GroupMapping, createGroupMapping } from '../../util';
import { createEmptyClipping } from '../clipping-data';
type TextAttachment = (
'bottom-left' | 'bottom-center' | 'bottom-right' |
@@ -195,6 +196,7 @@ export namespace Text {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: text.charCount * 2 * 3, groupCount, instanceCount };
@@ -210,11 +212,13 @@ export namespace Text {
elements: text.indexBuffer,
boundingSphere: ValueCell.create(boundingSphere),
invariantBoundingSphere: ValueCell.create(invariantBoundingSphere),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere)),
...color,
...size,
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
aTexCoord: text.tcoordBuffer,
@@ -269,6 +273,7 @@ export namespace Text {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
ValueCell.update(values.padding, padding);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -20,8 +20,9 @@ import { createEmptyTransparency } from '../transparency-data';
import { TextureMeshValues } from '../../../mol-gl/renderable/texture-mesh';
import { calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { Texture } from '../../../mol-gl/webgl/texture';
import { Vec2 } from '../../../mol-math/linear-algebra';
import { Vec2, Vec4 } from '../../../mol-math/linear-algebra';
import { fillSerial } from '../../../mol-util/array';
import { createEmptyClipping } from '../clipping-data';
export interface TextureMesh {
readonly kind: 'texture-mesh',
@@ -93,6 +94,7 @@ export namespace TextureMesh {
const marker = createMarkers(instanceCount * groupCount);
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const counts = { drawCount: textureMesh.vertexCount, groupCount, instanceCount };
@@ -107,11 +109,13 @@ export namespace TextureMesh {
aGroup: ValueCell.create(fillSerial(new Float32Array(textureMesh.vertexCount))),
boundingSphere: ValueCell.create(transformBoundingSphere),
invariantBoundingSphere: ValueCell.create(Sphere3D.clone(textureMesh.boundingSphere)),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(textureMesh.boundingSphere)),
...color,
...marker,
...overpaint,
...transparency,
...clipping,
...transform,
...BaseGeometry.createValues(props, counts),
@@ -149,6 +153,7 @@ export namespace TextureMesh {
}
if (!Sphere3D.equals(invariantBoundingSphere, values.invariantBoundingSphere.ref.value)) {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere);
ValueCell.update(values.uInvariantBoundingSphere, Vec4.fromSphere(values.uInvariantBoundingSphere.ref.value, invariantBoundingSphere));
}
}
}

View File

@@ -7,7 +7,6 @@
import { ValueCell } from '../../mol-util/value-cell';
import { Vec2 } from '../../mol-math/linear-algebra';
import { TextureImage, createTextureImage } from '../../mol-gl/renderable/util';
import { Transparency } from '../../mol-theme/transparency';
export type TransparencyData = {
tTransparency: ValueCell<TextureImage<Uint8Array>>
@@ -27,20 +26,19 @@ export function clearTransparency(array: Uint8Array, start: number, end: number)
array.fill(0, start, end);
}
export function createTransparency(count: number, variant: Transparency.Variant, transparencyData?: TransparencyData): TransparencyData {
export function createTransparency(count: number, transparencyData?: TransparencyData): TransparencyData {
const transparency = createTextureImage(Math.max(1, count), 1, Uint8Array, transparencyData && transparencyData.tTransparency.ref.value.array);
if (transparencyData) {
ValueCell.update(transparencyData.tTransparency, transparency);
ValueCell.update(transparencyData.uTransparencyTexDim, Vec2.create(transparency.width, transparency.height));
ValueCell.update(transparencyData.dTransparency, count > 0);
ValueCell.update(transparencyData.dTransparencyVariant, variant);
return transparencyData;
} else {
return {
tTransparency: ValueCell.create(transparency),
uTransparencyTexDim: ValueCell.create(Vec2.create(transparency.width, transparency.height)),
dTransparency: ValueCell.create(count > 0),
dTransparencyVariant: ValueCell.create(variant),
dTransparencyVariant: ValueCell.create('single'),
};
}
}

View File

@@ -7,7 +7,7 @@
import { createGl } from './gl.shim';
import { Camera } from '../../mol-canvas3d/camera';
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
import { Vec3, Mat4, Vec4 } from '../../mol-math/linear-algebra';
import { ValueCell } from '../../mol-util';
import Renderer from '../renderer';
@@ -24,6 +24,7 @@ import { Color } from '../../mol-util/color';
import { Sphere3D } from '../../mol-math/geometry';
import { createEmptyOverpaint } from '../../mol-geo/geometry/overpaint-data';
import { createEmptyTransparency } from '../../mol-geo/geometry/transparency-data';
import { createEmptyClipping } from '../../mol-geo/geometry/clipping-data';
function createRenderer(gl: WebGLRenderingContext) {
const ctx = createContext(gl);
@@ -43,6 +44,7 @@ function createPoints() {
const marker = createEmptyMarkers();
const overpaint = createEmptyOverpaint();
const transparency = createEmptyTransparency();
const clipping = createEmptyClipping();
const aTransform = ValueCell.create(new Float32Array(16));
const m4 = Mat4.identity();
@@ -63,10 +65,12 @@ function createPoints() {
...size,
...overpaint,
...transparency,
...clipping,
uAlpha: ValueCell.create(1.0),
uInstanceCount: ValueCell.create(1),
uGroupCount: ValueCell.create(3),
uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere.ref.value)),
alpha: ValueCell.create(1.0),
drawCount: ValueCell.create(3),
@@ -124,7 +128,7 @@ describe('renderer', () => {
scene.add(points);
scene.commit();
expect(ctx.stats.resourceCounts.attribute).toBe(4);
expect(ctx.stats.resourceCounts.texture).toBe(5);
expect(ctx.stats.resourceCounts.texture).toBe(6);
expect(ctx.stats.resourceCounts.vertexArray).toBe(5);
expect(ctx.stats.resourceCounts.program).toBe(5);
expect(ctx.stats.resourceCounts.shader).toBe(10);

View File

@@ -29,8 +29,15 @@ export const DirectVolumeSchema = {
dTransparency: DefineSpec('boolean'),
dTransparencyVariant: DefineSpec('string', ['single', 'multi']),
dClipObjectCount: DefineSpec('number'),
dClipVariant: DefineSpec('string', ['instance', 'pixel']),
uClippingTexDim: UniformSpec('v2'),
tClipping: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'),
dClipping: DefineSpec('boolean'),
uInstanceCount: UniformSpec('i'),
uGroupCount: UniformSpec('i'),
uInvariantBoundingSphere: UniformSpec('v4'),
aInstance: AttributeSpec('float32', 1, 1),
aTransform: AttributeSpec('float32', 16, 1),

View File

@@ -1,22 +1,21 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../mol-util';
import { AttributeItemSize, ElementsKind, AttributeValues, AttributeKind } from '../webgl/buffer';
import { UniformKind, UniformValues } from '../webgl/uniform';
import { AttributeItemSize, ElementsKind, AttributeValues, AttributeKind, DataTypeArrayType } from '../webgl/buffer';
import { UniformKind, UniformValues, UniformKindValue } from '../webgl/uniform';
import { DefineKind, DefineValues } from '../shader-code';
import { Vec2, Vec3, Vec4, Mat3, Mat4 } from '../../mol-math/linear-algebra';
import { TextureImage, TextureVolume } from './util';
import { TextureValues, TextureType, TextureFormat, TextureFilter, TextureKind, Texture } from '../webgl/texture';
import { Mat4 } from '../../mol-math/linear-algebra';
import { TextureValues, TextureType, TextureFormat, TextureFilter, TextureKind, TextureKindValue } from '../webgl/texture';
import { Sphere3D } from '../../mol-math/geometry';
export type ValueKindType = {
'number': number
'string': string
'boolean': string
'boolean': boolean
'any': any
'm4': Mat4,
@@ -27,40 +26,7 @@ export type ValueKind = keyof ValueKindType
//
export type KindValue = {
'f': number
'i': number
'v2': Vec2
'v3': Vec3
'v4': Vec4
'm3': Mat3
'm4': Mat4
't': number
'uint8': Uint8Array
'int8': Int8Array
'uint16': Uint16Array
'int16': Int16Array
'uint32': Uint32Array
'int32': Int32Array
'float32': Float32Array
'image-uint8': TextureImage<Uint8Array>
'image-float32': TextureImage<Float32Array>
'image-depth': TextureImage<Uint8Array> // TODO should be Uint32Array
'volume-uint8': TextureVolume<Uint8Array>
'volume-float32': TextureVolume<Float32Array>
'texture': Texture
'texture2d': Texture
'texture3d': Texture
'number': number
'string': string
'boolean': boolean
'any': any
'sphere': Sphere3D
}
export type KindValue = UniformKindValue & DataTypeArrayType & TextureKindValue & ValueKindType
export type Values<S extends RenderableSchema> = { readonly [k in keyof S]: ValueCell<KindValue[S[k]['kind']]> }
@@ -163,6 +129,11 @@ export const GlobalUniformSchema = {
uTransparentBackground: UniformSpec('i'),
uClipObjectType: UniformSpec('i[]'),
uClipObjectPosition: UniformSpec('v3[]'),
uClipObjectRotation: UniformSpec('v4[]'),
uClipObjectScale: UniformSpec('v3[]'),
// all the following could in principle be per object
// as a kind of 'material' parameter set
// would need to test performance implications
@@ -228,21 +199,31 @@ export type OverpaintSchema = typeof OverpaintSchema
export type OverpaintValues = Values<OverpaintSchema>
export const TransparencySchema = {
// aTransparency: AttributeSpec('float32', 1, 0), // TODO
uTransparencyTexDim: UniformSpec('v2'),
tTransparency: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'),
dTransparency: DefineSpec('boolean'),
// dTransparencyType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'group', 'group_instance']), // TODO
dTransparencyVariant: DefineSpec('string', ['single', 'multi']),
} as const;
export type TransparencySchema = typeof TransparencySchema
export type TransparencyValues = Values<TransparencySchema>
export const ClippingSchema = {
dClipObjectCount: DefineSpec('number'),
dClipVariant: DefineSpec('string', ['instance', 'pixel']),
uClippingTexDim: UniformSpec('v2'),
tClipping: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'),
dClipping: DefineSpec('boolean'),
} as const;
export type ClippingSchema = typeof ClippingSchema
export type ClippingValues = Values<ClippingSchema>
export const BaseSchema = {
...ColorSchema,
...MarkerSchema,
...OverpaintSchema,
...TransparencySchema,
...ClippingSchema,
aInstance: AttributeSpec('float32', 1, 1),
aGroup: AttributeSpec('float32', 1, 0),
@@ -258,6 +239,7 @@ export const BaseSchema = {
uAlpha: UniformSpec('f', true),
uInstanceCount: UniformSpec('i'),
uGroupCount: UniformSpec('i'),
uInvariantBoundingSphere: UniformSpec('v4'),
drawCount: ValueSpec('number'),
instanceCount: ValueSpec('number'),
@@ -272,7 +254,7 @@ export const BaseSchema = {
/** additional per-instance transform, see aTransform */
extraTransform: ValueSpec('float32'),
/** bounding sphere taking aTransform into account */
/** bounding sphere taking aTransform into account and encompases all instances */
boundingSphere: ValueSpec('sphere'),
/** bounding sphere NOT taking aTransform into account */
invariantBoundingSphere: ValueSpec('sphere'),

View File

@@ -9,13 +9,16 @@ import { Camera } from '../mol-canvas3d/camera';
import Scene from './scene';
import { WebGLContext } from './webgl/context';
import { Mat4, Vec3, Vec4, Vec2 } from '../mol-math/linear-algebra';
import { Mat4, Vec3, Vec4, Vec2, Quat } from '../mol-math/linear-algebra';
import { Renderable } from './renderable';
import { Color } from '../mol-util/color';
import { ValueCell } from '../mol-util';
import { ValueCell, deepEqual } from '../mol-util';
import { RenderableValues, GlobalUniformValues, BaseValues } from './renderable/schema';
import { GraphicsRenderVariant } from './webgl/render-item';
import { ParamDefinition as PD } from '../mol-util/param-definition';
import { Clipping } from '../mol-theme/clipping';
import { stringToWords } from '../mol-util/string';
import { Transparency } from '../mol-theme/transparency';
export interface RendererStats {
programCount: number
@@ -49,6 +52,7 @@ export const RendererParams = {
// the following are general 'material' parameters
pickingAlphaThreshold: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }, { description: 'The minimum opacity value needed for an object to be pickable.' }),
transparencyVariant: PD.Select('single', PD.arrayToOptions<Transparency.Variant>(['single', 'multi'])),
interiorDarkening: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
interiorColorFlag: PD.Boolean(true, { label: 'Use Interior Color' }),
@@ -71,6 +75,19 @@ export const RendererParams = {
metallic: PD.Group({}),
plastic: PD.Group({}),
}, { label: 'Lighting', description: 'Style in which the 3D scene is rendered/lighted' }),
clip: PD.Group({
variant: PD.Select('instance', PD.arrayToOptions<Clipping.Variant>(['instance', 'pixel'])),
objects: PD.ObjectList({
type: PD.Select('plane', PD.objectToOptions(Clipping.Type, t => stringToWords(t))),
position: PD.Vec3(Vec3()),
rotation: PD.Group({
axis: PD.Vec3(Vec3.create(1, 0, 0)),
angle: PD.Numeric(0, { min: -180, max: 180, step: 0.1 }),
}, { isExpanded: true }),
scale: PD.Vec3(Vec3.create(1, 1, 1)),
}, o => stringToWords(o.type))
})
};
export type RendererProps = PD.Values<typeof RendererParams>
@@ -106,11 +123,44 @@ function getStyle(props: RendererProps['style']) {
}
}
type Clip = {
variant: Clipping.Variant
objects: {
count: number
type: number[]
position: number[]
rotation: number[]
scale: number[]
}
}
const tmpQuat = Quat();
function getClip(props: RendererProps['clip'], clip?: Clip): Clip {
const { type, position, rotation, scale } = clip?.objects || {
type: (new Array(5)).fill(1),
position: (new Array(5 * 3)).fill(0),
rotation: (new Array(5 * 4)).fill(0),
scale: (new Array(5 * 3)).fill(1),
};
for (let i = 0, il = props.objects.length; i < il; ++i) {
const p = props.objects[i];
type[i] = Clipping.Type[p.type];
Vec3.toArray(p.position, position, i * 3);
Quat.toArray(Quat.setAxisAngle(tmpQuat, p.rotation.axis, p.rotation.angle), rotation, i * 4);
Vec3.toArray(p.scale, scale, i * 3);
}
return {
variant: props.variant,
objects: { count: props.objects.length, type, position, rotation, scale }
};
}
namespace Renderer {
export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer {
const { gl, state, stats } = ctx;
const p = PD.merge(RendererParams, PD.getDefaultValues(RendererParams), props);
const style = getStyle(p.style);
const clip = getClip(p.clip);
const viewport = Viewport();
const bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor);
@@ -151,6 +201,11 @@ namespace Renderer {
uFogColor: ValueCell.create(bgColor),
uTransparentBackground: ValueCell.create(0),
uClipObjectType: ValueCell.create(clip.objects.type),
uClipObjectPosition: ValueCell.create(clip.objects.position),
uClipObjectRotation: ValueCell.create(clip.objects.rotation),
uClipObjectScale: ValueCell.create(clip.objects.scale),
// the following are general 'material' uniforms
uLightIntensity: ValueCell.create(style.lightIntensity),
uAmbientIntensity: ValueCell.create(style.ambientIntensity),
@@ -177,6 +232,21 @@ namespace Renderer {
return;
}
let definesNeedUpdate = false;
if (r.values.dClipObjectCount.ref.value !== clip.objects.count) {
ValueCell.update(r.values.dClipObjectCount, clip.objects.count);
definesNeedUpdate = true;
}
if (r.values.dClipVariant.ref.value !== clip.variant) {
ValueCell.update(r.values.dClipVariant, clip.variant);
definesNeedUpdate = true;
}
if (r.values.dTransparencyVariant.ref.value !== p.transparencyVariant) {
ValueCell.update(r.values.dTransparencyVariant, p.transparencyVariant);
definesNeedUpdate = true;
}
if (definesNeedUpdate) r.update();
const program = r.getProgram(variant);
if (state.currentProgramId !== program.id) {
// console.log('new program')
@@ -309,6 +379,9 @@ namespace Renderer {
p.pickingAlphaThreshold = props.pickingAlphaThreshold;
ValueCell.update(globalUniforms.uPickingAlphaThreshold, p.pickingAlphaThreshold);
}
if (props.transparencyVariant !== undefined && props.transparencyVariant !== p.transparencyVariant) {
p.transparencyVariant = props.transparencyVariant;
}
if (props.interiorDarkening !== undefined && props.interiorDarkening !== p.interiorDarkening) {
p.interiorDarkening = props.interiorDarkening;
@@ -341,6 +414,15 @@ namespace Renderer {
ValueCell.updateIfChanged(globalUniforms.uRoughness, style.roughness);
ValueCell.updateIfChanged(globalUniforms.uReflectivity, style.reflectivity);
}
if (props.clip !== undefined && !deepEqual(props.clip, p.clip)) {
p.clip = props.clip;
Object.assign(clip, getClip(props.clip, clip));
ValueCell.update(globalUniforms.uClipObjectPosition, clip.objects.position);
ValueCell.update(globalUniforms.uClipObjectRotation, clip.objects.rotation);
ValueCell.update(globalUniforms.uClipObjectScale, clip.objects.scale);
ValueCell.update(globalUniforms.uClipObjectType, clip.objects.type);
}
},
setViewport: (x: number, y: number, width: number, height: number) => {
gl.viewport(x, y, width, height);

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -34,6 +34,7 @@ import apply_fog from './shader/chunks/apply-fog.glsl';
import apply_interior_color from './shader/chunks/apply-interior-color.glsl';
import apply_light_color from './shader/chunks/apply-light-color.glsl';
import apply_marker_color from './shader/chunks/apply-marker-color.glsl';
import assign_clipping_varying from './shader/chunks/assign-clipping-varying.glsl';
import assign_color_varying from './shader/chunks/assign-color-varying.glsl';
import assign_group from './shader/chunks/assign-group.glsl';
import assign_marker_varying from './shader/chunks/assign-marker-varying.glsl';
@@ -41,8 +42,11 @@ import assign_material_color from './shader/chunks/assign-material-color.glsl';
import assign_position from './shader/chunks/assign-position.glsl';
import assign_size from './shader/chunks/assign-size.glsl';
import check_picking_alpha from './shader/chunks/check-picking-alpha.glsl';
import clip_instance from './shader/chunks/clip-instance.glsl';
import clip_pixel from './shader/chunks/clip-pixel.glsl';
import color_frag_params from './shader/chunks/color-frag-params.glsl';
import color_vert_params from './shader/chunks/color-vert-params.glsl';
import common_clip from './shader/chunks/common-clip.glsl';
import common_frag_params from './shader/chunks/common-frag-params.glsl';
import common_vert_params from './shader/chunks/common-vert-params.glsl';
import common from './shader/chunks/common.glsl';
@@ -59,6 +63,7 @@ const ShaderChunks: { [k: string]: string } = {
apply_interior_color,
apply_light_color,
apply_marker_color,
assign_clipping_varying,
assign_color_varying,
assign_group,
assign_marker_varying,
@@ -66,8 +71,11 @@ const ShaderChunks: { [k: string]: string } = {
assign_position,
assign_size,
check_picking_alpha,
clip_instance,
clip_pixel,
color_frag_params,
color_vert_params,
common_clip,
common_frag_params,
common_vert_params,
common,

View File

@@ -0,0 +1,5 @@
export default `
#if dClipObjectCount != 0 && defined(dClipping)
vClipping = readFromTexture(tClipping, aInstance * float(uGroupCount) + group, uClippingTexDim).a;
#endif
`;

View File

@@ -1,11 +1,14 @@
export default `
mat4 modelView = uView * uModel * aTransform;
mat4 model = uModel * aTransform;
mat4 modelView = uView * model;
#ifdef dGeoTexture
vec3 position = readFromTexture(tPositionGroup, aGroup, uGeoTexDim).xyz;
#else
vec3 position = aPosition;
#endif
vec4 mvPosition = modelView * vec4(position, 1.0);
vec4 position4 = vec4(position, 1.0);
vModelPosition = (model * position4).xyz; // for clipping in frag shader
vec4 mvPosition = modelView * position4;
vViewPosition = mvPosition.xyz;
gl_Position = uProjection * mvPosition;
`;

View File

@@ -0,0 +1,13 @@
export default `
#if defined(dClipVariant_instance) && dClipObjectCount != 0
int flag = 0;
#if defined(dClipping)
flag = int(floor(vClipping * 255.0 + 0.5));
#endif
vec4 mCenter = uModel * aTransform * vec4(uInvariantBoundingSphere.xyz, 1.0);
if (clipTest(vec4(mCenter.xyz, uInvariantBoundingSphere.w), flag))
// move out of [ -w, +w ] to 'discard' in vert shader
gl_Position.z = 2.0 * gl_Position.w;
#endif
`;

View File

@@ -0,0 +1,12 @@
export default `
#if defined(dClipVariant_pixel) && dClipObjectCount != 0
#if defined(dClipping)
int clippingFlag = int(floor(vClipping * 255.0 + 0.5));
#else
int clippingFlag = 0;
#endif
if (clipTest(vec4(vModelPosition, 0.0), clippingFlag))
discard;
#endif
`;

View File

@@ -0,0 +1,102 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Ludovic Autin <autin@scripps.edu>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export default `
#if dClipObjectCount != 0
vec3 quaternionTransform(vec4 q, vec3 v) {
vec3 t = 2.0 * cross(q.xyz, v);
return v + q.w * t + cross(q.xyz, t);
}
vec4 computePlane(vec3 normal, vec3 inPoint) {
return vec4(normalize(normal), -dot(normal, inPoint));
}
float planeSD(vec4 plane, vec3 center) {
return -dot(plane.xyz, center - plane.xyz * -plane.w);
}
float sphereSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
return (
length(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position) / size) - 1.0
) * min(min(size.x, size.y), size.z);
}
float cubeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
vec3 d = abs(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position)) - size;
return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0));
}
float cylinderSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position);
vec2 d = abs(vec2(length(t.xz), t.y)) - size.xy;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}
float infiniteConeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) {
vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position);
float q = length(t.xy);
return dot(size.xy, vec2(q, t.z));
}
float getSignedDistance(vec3 center, int type, vec3 position, vec4 rotation, vec3 scale) {
if (type == 1) {
vec3 normal = quaternionTransform(rotation, vec3(0.0, 1.0, 0.0));
vec4 plane = computePlane(normal, position);
return planeSD(plane, center);
} else if (type == 2) {
return sphereSD(position, rotation, scale * 0.5, center);
} else if (type == 3) {
return cubeSD(position, rotation, scale * 0.5, center);
} else if (type == 4) {
return cylinderSD(position, rotation, scale * 0.5, center);
} else if (type == 5) {
return infiniteConeSD(position, rotation, scale * 0.5, center);
} else {
return 0.1;
}
}
#if __VERSION__ != 300
// 8-bit
int bitwiseAnd(int a, int b) {
int d = 128;
int result = 0;
for (int i = 0; i < 8; ++i) {
if (d <= 0) break;
if (a >= d && b >= d) result += d;
if (a >= d) a -= d;
if (b >= d) b -= d;
d /= 2;
}
return result;
}
bool hasBit(int mask, int bit) {
return bitwiseAnd(mask, bit) == 0;
}
#else
bool hasBit(int mask, int bit) {
return (mask & bit) == 0;
}
#endif
// flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0)
bool clipTest(vec4 sphere, int flag) {
for (int i = 0; i < dClipObjectCount; ++i) {
if (flag == 0 || hasBit(flag, i + 1)) {
// TODO take sphere radius into account?
if (getSignedDistance(sphere.xyz, uClipObjectType[i], uClipObjectPosition[i], uClipObjectRotation[i], uClipObjectScale[i]) <= 0.0)
return true;
}
}
return false;
}
#endif
`;

View File

@@ -3,6 +3,21 @@ uniform int uObjectId;
uniform int uInstanceCount;
uniform int uGroupCount;
#if dClipObjectCount != 0
uniform int uClipObjectType[dClipObjectCount];
uniform vec3 uClipObjectPosition[dClipObjectCount];
uniform vec4 uClipObjectRotation[dClipObjectCount];
uniform vec3 uClipObjectScale[dClipObjectCount];
#if defined(dClipping)
#if __VERSION__ != 300
varying float vClipping;
#else
flat in float vClipping;
#endif
#endif
#endif
uniform vec3 uHighlightColor;
uniform vec3 uSelectColor;
#if __VERSION__ != 300
@@ -11,6 +26,7 @@ uniform vec3 uSelectColor;
flat in float vMarker;
#endif
varying vec3 vModelPosition;
varying vec3 vViewPosition;
uniform vec2 uViewOffset;

View File

@@ -5,6 +5,24 @@ uniform vec3 uCameraPosition;
uniform int uObjectId;
uniform int uInstanceCount;
uniform int uGroupCount;
uniform vec4 uInvariantBoundingSphere;
#if dClipObjectCount != 0
uniform int uClipObjectType[dClipObjectCount];
uniform vec3 uClipObjectPosition[dClipObjectCount];
uniform vec4 uClipObjectRotation[dClipObjectCount];
uniform vec3 uClipObjectScale[dClipObjectCount];
#if defined(dClipping)
uniform vec2 uClippingTexDim;
uniform sampler2D tClipping;
#if __VERSION__ != 300
varying float vClipping;
#else
flat out float vClipping;
#endif
#endif
#endif
uniform vec2 uMarkerTexDim;
uniform sampler2D tMarker;
@@ -14,5 +32,6 @@ uniform sampler2D tMarker;
flat out float vMarker;
#endif
varying vec3 vModelPosition;
varying vec3 vViewPosition;
`;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -11,8 +11,10 @@ precision highp int;
#include common
#include common_frag_params
#include color_frag_params
#include common_clip
void main(){
#include clip_pixel
#include assign_material_color
#if defined(dRenderVariant_pick)

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*
@@ -15,6 +15,7 @@ precision highp int;
#include common_vert_params
#include color_vert_params
#include size_vert_params
#include common_clip
uniform float uPixelRatio;
uniform float uViewportHeight;
@@ -42,6 +43,7 @@ void main(){
#include assign_group
#include assign_color_varying
#include assign_marker_varying
#include assign_clipping_varying
#include assign_size
mat4 modelView = uView * uModel * aTransform;
@@ -51,10 +53,12 @@ void main(){
vec4 end = modelView * vec4(aEnd, 1.0);
// assign position
vec3 position = (aMapping.y < 0.5) ? aStart : aEnd;
vec4 mvPosition = modelView * vec4(position, 1.0);
vec4 position4 = vec4((aMapping.y < 0.5) ? aStart : aEnd, 1.0);
vec4 mvPosition = modelView * position4;
vViewPosition = mvPosition.xyz;
vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
// special case for perspective projection, and segments that terminate either in, or behind, the camera plane
// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
// but we need to perform ndc-space calculations in the shader, so we must address this issue directly
@@ -114,5 +118,7 @@ void main(){
offset *= clip.w;
clip.xy += offset;
gl_Position = clip;
#include clip_instance
}
`;

View File

@@ -13,8 +13,11 @@ precision highp int;
#include color_frag_params
#include light_frag_params
#include normal_frag_params
#include common_clip
void main() {
#include clip_pixel
// Workaround for buggy gl_FrontFacing (e.g. on some integrated Intel GPUs)
#if defined(enabledStandardDerivatives)
vec3 fdx = dFdx(vViewPosition);

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -12,6 +12,7 @@ precision highp int;
#include read_from_texture
#include common_vert_params
#include color_vert_params
#include common_clip
#ifdef dGeoTexture
uniform vec2 uGeoTexDim;
@@ -34,7 +35,9 @@ void main(){
#include assign_group
#include assign_color_varying
#include assign_marker_varying
#include assign_clipping_varying
#include assign_position
#include clip_instance
#ifdef dGeoTexture
vec3 normal = readFromTexture(tNormal, aGroup, uGeoTexDim).xyz;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -11,6 +11,7 @@ precision highp int;
#include common
#include common_frag_params
#include color_frag_params
#include common_clip
#ifdef dPointFilledCircle
uniform float uPointEdgeBleach;
@@ -20,6 +21,7 @@ const vec2 center = vec2(0.5);
const float radius = 0.5;
void main(){
#include clip_pixel
#include assign_material_color
#if defined(dRenderVariant_pick)

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -13,6 +13,7 @@ precision highp int;
#include common_vert_params
#include color_vert_params
#include size_vert_params
#include common_clip
uniform float uPixelRatio;
uniform float uViewportHeight;
@@ -26,6 +27,7 @@ void main(){
#include assign_group
#include assign_color_varying
#include assign_marker_varying
#include assign_clipping_varying
#include assign_position
#include assign_size
@@ -36,5 +38,7 @@ void main(){
#endif
gl_Position = uProjection * mvPosition;
#include clip_instance
}
`;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -12,6 +12,7 @@ precision highp int;
#include common_frag_params
#include color_frag_params
#include light_frag_params
#include common_clip
uniform mat4 uProjection;
@@ -73,6 +74,8 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
}
void main(void){
#include clip_pixel
bool flag = Impostor(cameraPos, cameraNormal);
#ifndef dDoubleSided
if (interior)

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -13,6 +13,7 @@ precision highp int;
#include common_vert_params
#include color_vert_params
#include size_vert_params
#include common_clip
uniform mat4 uModelView;
uniform mat4 uInvProjection;
@@ -77,11 +78,13 @@ void main(void){
#include assign_group
#include assign_color_varying
#include assign_marker_varying
#include assign_clipping_varying
#include assign_size
vRadius = size * matrixScale(uModelView);
vec4 mvPosition = uModelView * aTransform * vec4(aPosition, 1.0);
vec4 position4 = vec4(aPosition, 1.0);
vec4 mvPosition = uModelView * aTransform * position4;
mvPosition.z -= vRadius; // avoid clipping, added again in fragment shader
gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
@@ -91,5 +94,9 @@ void main(void){
vec4 vPoint4 = uInvProjection * gl_Position;
vPoint = vPoint4.xyz / vPoint4.w;
vPointViewPosition = -mvPosition.xyz / mvPosition.w;
vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
#include clip_instance
}
`;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -11,6 +11,7 @@ precision highp int;
#include common
#include common_frag_params
#include color_frag_params
#include common_clip
uniform sampler2D tFont;
@@ -29,6 +30,7 @@ void main2(){
}
void main(){
#include clip_pixel
#include assign_material_color
if (vTexCoord.x > 1.0) {

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -13,6 +13,7 @@ precision highp int;
#include common_vert_params
#include color_vert_params
#include size_vert_params
#include common_clip
uniform mat4 uModelView;
@@ -40,6 +41,7 @@ void main(void){
#include assign_group
#include assign_color_varying
#include assign_marker_varying
#include assign_clipping_varying
#include assign_size
vTexCoord = aTexCoord;
@@ -50,7 +52,10 @@ void main(void){
float offsetY = uOffsetY * scale;
float offsetZ = (uOffsetZ + aDepth * 0.95) * scale;
vec4 mvPosition = uModelView * aTransform * vec4(aPosition, 1.0);
vec4 position4 = vec4(aPosition, 1.0);
vec4 mvPosition = uModelView * aTransform * position4;
vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
// TODO
// #ifdef FIXED_SIZE
@@ -64,7 +69,7 @@ void main(void){
vec4 mvCorner = vec4(mvPosition.xyz, 1.0);
if (vTexCoord.x == 10.0) { // indicates background plane
// move a bit to the back, tkaing ditsnace to camera into account to avoid z-fighting
// move a bit to the back, taking distance to camera into account to avoid z-fighting
offsetZ -= 0.001 * distance(uCameraPosition, (uProjection * mvCorner).xyz);
}
@@ -83,5 +88,7 @@ void main(void){
gl_Position = uProjection * mvCorner;
vViewPosition = -mvCorner.xyz;
#include clip_instance
}
`;

View File

@@ -86,7 +86,8 @@ function checkActiveUniforms(gl: GLRenderingContext, program: WebGLProgram, sche
// name assigned by `gl.shim.ts`, ignore for checks
continue;
}
const spec = schema[name];
const baseName = name.replace(/[[0-9]+\]$/, ''); // 'array' uniforms
const spec = schema[baseName];
if (spec === undefined) {
throw new Error(`missing 'uniform' or 'texture' with name '${name}' in schema`);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -8,45 +8,33 @@ import { Mat3, Mat4, Vec2, Vec3, Vec4 } from '../../mol-math/linear-algebra';
import { ValueCell } from '../../mol-util';
import { GLRenderingContext } from './compat';
import { RenderableSchema } from '../../mol-gl/renderable/schema';
import { ValueOf } from '../../mol-util/type-helpers';
export type UniformKindValue = {
'f': number
'i': number
'v2': Vec2
'v3': Vec3
'v4': Vec4
'm3': Mat3
'm4': Mat4
't': number
'f': number; 'f[]': number[]
'i': number; 'i[]': number[]
'v2': Vec2; 'v2[]': number[]
'v3': Vec3; 'v3[]': number[]
'v4': Vec4; 'v4[]': number[]
'm3': Mat3; 'm3[]': number[]
'm4': Mat4; 'm4[]': number[]
't': number; 't[]': number[]
}
export type UniformKind = keyof UniformKindValue
export type UniformType = number | Vec2 | Vec3 | Vec4 | Mat3 | Mat4
export type UniformType = ValueOf<UniformKindValue>
export type UniformValues = { [k: string]: ValueCell<UniformType> }
export type UniformsList = [string, ValueCell<UniformType>][]
export function getUniformType(gl: GLRenderingContext, kind: UniformKind) {
switch (kind) {
case 'f': return gl.FLOAT;
case 'i': return gl.INT;
case 'v2': return gl.FLOAT_VEC2;
case 'v3': return gl.FLOAT_VEC3;
case 'v4': return gl.FLOAT_VEC4;
case 'm3': return gl.FLOAT_MAT3;
case 'm4': return gl.FLOAT_MAT4;
default: console.error(`unknown uniform kind '${kind}'`);
}
}
export function setUniform(gl: GLRenderingContext, location: WebGLUniformLocation | null, kind: UniformKind, value: any) {
switch (kind) {
case 'f': gl.uniform1f(location, value); break;
case 'i': case 't': gl.uniform1i(location, value); break;
case 'v2': gl.uniform2fv(location, value); break;
case 'v3': gl.uniform3fv(location, value); break;
case 'v4': gl.uniform4fv(location, value); break;
case 'm3': gl.uniformMatrix3fv(location, false, value); break;
case 'm4': gl.uniformMatrix4fv(location, false, value); break;
case 'f': case 'f[]': return gl.FLOAT;
case 'i': case 'i[]': return gl.INT;
case 'v2': case 'v2[]': return gl.FLOAT_VEC2;
case 'v3': case 'v3[]': return gl.FLOAT_VEC3;
case 'v4': case 'v4[]': return gl.FLOAT_VEC4;
case 'm3': case 'm3[]': return gl.FLOAT_MAT3;
case 'm4': case 'm4[]': return gl.FLOAT_MAT4;
default: console.error(`unknown uniform kind '${kind}'`);
}
}
@@ -55,24 +43,27 @@ export type UniformSetter = (gl: GLRenderingContext, location: number, value: an
export type UniformSetters = { [k: string]: UniformSetter }
function uniform1f (gl: GLRenderingContext, location: number, value: any) { gl.uniform1f(location, value); }
function uniform1fv (gl: GLRenderingContext, location: number, value: any) { gl.uniform1fv(location, value); }
function uniform1i (gl: GLRenderingContext, location: number, value: any) { gl.uniform1i(location, value); }
function uniform1iv (gl: GLRenderingContext, location: number, value: any) { gl.uniform1iv(location, value); }
function uniform2fv (gl: GLRenderingContext, location: number, value: any) { gl.uniform2fv(location, value); }
function uniform3fv (gl: GLRenderingContext, location: number, value: any) { gl.uniform3fv(location, value); }
function uniform4fv (gl: GLRenderingContext, location: number, value: any) { gl.uniform4fv(location, value); }
function uniformMatrix3fv (gl: GLRenderingContext, location: number, value: any) { gl.uniformMatrix3fv(location, false, value); }
function uniformMatrix4fv (gl: GLRenderingContext, location: number, value: any) { gl.uniformMatrix4fv(location, false, value); }
function getUniformSetter(kind: UniformKind) {
function getUniformSetter(kind: UniformKind): UniformSetter {
switch (kind) {
case 'f': return uniform1f;
case 'f[]': return uniform1fv;
case 'i': case 't': return uniform1i;
case 'v2': return uniform2fv;
case 'v3': return uniform3fv;
case 'v4': return uniform4fv;
case 'm3': return uniformMatrix3fv;
case 'm4': return uniformMatrix4fv;
case 'i[]': case 't[]': return uniform1iv;
case 'v2': case 'v2[]': return uniform2fv;
case 'v3': case 'v3[]': return uniform3fv;
case 'v4': case 'v4[]': return uniform4fv;
case 'm3': case 'm3[]': return uniformMatrix3fv;
case 'm4': case 'm4[]': return uniformMatrix4fv;
}
throw new Error(`unknown uniform kind '${kind}'`);
}
export function getUniformSetters(schema: RenderableSchema) {

View File

@@ -12,11 +12,15 @@ describe('common', () => {
expect(fastParseFloat('11.0829(23)', 0, 11)).toBe(11.0829);
// scientific with no space between consecutive values
expect(fastParseFloat('-5.1E-01-6.1E-01', 0, 11)).toBe(-0.51);
// ignore plus sign
expect(fastParseFloat('+0.149', 0, 6)).toBe(0.149);
});
it('number-parser fastParseInt', () => {
// ignore suffix numbers in parentheses
expect(fastParseInt('11(23)', 0, 11)).toBe(11);
// ignore plus sign
expect(fastParseFloat('+10149', 0, 6)).toBe(10149);
});
it('number-parser getNumberType', () => {

View File

@@ -0,0 +1,149 @@
import { parseSdf } from '../sdf/parser';
const SdfString = `
Mrv1718007121815122D
5 4 0 0 0 0 999 V2000
0.0000 0.8250 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
-0.8250 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
0.0000 -0.8250 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
0.0000 0.0000 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0
0.8250 0.0000 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0
4 1 1 0 0 0 0
4 2 2 0 0 0 0
4 3 1 0 0 0 0
4 5 1 0 0 0 0
M CHG 3 1 -1 3 -1 5 -1
M END
> <DATABASE_ID>
DB14523
> <DATABASE_NAME>
drugbank
> <SMILES>
[O-]P([O-])([O-])=O
> <INCHI_IDENTIFIER>
InChI=1S/H3O4P/c1-5(2,3)4/h(H3,1,2,3,4)/p-3
> <INCHI_KEY>
NBIIXXVUZAFLBC-UHFFFAOYSA-K
> <FORMULA>
O4P
> <MOLECULAR_WEIGHT>
94.9714
> <EXACT_MASS>
94.95342
> <JCHEM_ACCEPTOR_COUNT>
4
> <JCHEM_ATOM_COUNT>
5
> <JCHEM_AVERAGE_POLARIZABILITY>
4.932162910070488
> <JCHEM_BIOAVAILABILITY>
1
> <JCHEM_DONOR_COUNT>
0
> <JCHEM_FORMAL_CHARGE>
-3
> <JCHEM_GHOSE_FILTER>
0
> <JCHEM_IUPAC>
phosphate
> <JCHEM_LOGP>
-1.0201038226666665
> <JCHEM_MDDR_LIKE_RULE>
0
> <JCHEM_NUMBER_OF_RINGS>
0
> <JCHEM_PHYSIOLOGICAL_CHARGE>
-2
> <JCHEM_PKA>
6.951626889535468
> <JCHEM_PKA_STRONGEST_ACIDIC>
1.7961261340181292
> <JCHEM_POLAR_SURFACE_AREA>
86.25
> <JCHEM_REFRACTIVITY>
11.2868
> <JCHEM_ROTATABLE_BOND_COUNT>
0
> <JCHEM_RULE_OF_FIVE>
1
> <JCHEM_TRADITIONAL_IUPAC>
phosphate
> <JCHEM_VEBER_RULE>
0
> <DRUGBANK_ID>
DB14523
> <DRUG_GROUPS>
experimental
> <GENERIC_NAME>
Phosphate ion
> <SYNONYMS>
Orthophosphate; Phosphate
$$$$`;
describe('sdf reader', () => {
it('basic', async () => {
const parsed = await parseSdf(SdfString).run();
if (parsed.isError) {
throw new Error(parsed.message);
}
const compound = parsed.result.compounds[0];
const { molFile, dataItems } = compound;
const { atoms, bonds } = molFile;
// number of structures
expect(atoms.count).toBe(5);
expect(bonds.count).toBe(4);
expect(atoms.x.value(0)).toBeCloseTo(0, 0.001);
expect(atoms.y.value(0)).toBeCloseTo(0.8250, 0.0001);
expect(atoms.z.value(0)).toBeCloseTo(0, 0.0001);
expect(atoms.type_symbol.value(0)).toBe('O');
expect(bonds.atomIdxA.value(3)).toBe(4);
expect(bonds.atomIdxB.value(3)).toBe(5);
expect(bonds.order.value(3)).toBe(1);
expect(dataItems.dataHeader.value(0)).toBe('DATABASE_ID');
expect(dataItems.data.value(0)).toBe('DB14523');
expect(dataItems.dataHeader.value(1)).toBe('DATABASE_NAME');
expect(dataItems.data.value(1)).toBe('drugbank');
expect(dataItems.dataHeader.value(31)).toBe('SYNONYMS');
expect(dataItems.data.value(31)).toBe('Orthophosphate; Phosphate');
});
});

View File

@@ -1,14 +1,14 @@
/**
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.324, IHM 1.09, CARB draft.
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.326, IHM 1.09, CARB draft.
*
* @author molstar/ciftools package
*/
import { Database, Column } from '../../../../mol-data/db';
import Schema = Column.Schema
import Schema = Column.Schema;
const str = Schema.str;
const float = Schema.float;
@@ -66,7 +66,7 @@ export const BIRD_Schema = {
/**
* Broadly defines the function of the entity.
*/
class: Aliased<'Antagonist' | 'Antibiotic' | 'Anticancer' | 'Anticoagulant' | 'Antifungal' | 'Antiinflammatory' | 'Antimicrobial' | 'Antineoplastic' | 'Antiparasitic' | 'Antiretroviral' | 'Anthelmintic' | 'Antithrombotic' | 'Antitumor' | 'Antiviral' | 'CASPASE inhibitor' | 'Chaperone binding' | 'Enzyme inhibitor' | 'Growth factor' | 'Immunosuppressant' | 'Inhibitor' | 'Lantibiotic' | 'Metabolism' | 'Metal transport' | 'Oxidation-reduction' | 'Receptor' | 'Thrombin inhibitor' | 'Trypsin inhibitor' | 'Toxin' | 'Unknown' | 'Anticoagulant, Antithrombotic' | 'Antibiotic, Antimicrobial' | 'Antibiotic, Anthelmintic' | 'Antibiotic, Antineoplastic' | 'Antimicrobial, Antiretroviral' | 'Antimicrobial, Antitumor' | 'Antimicrobial, Antiparasitic, Antibiotic' | 'Thrombin inhibitor, Trypsin inhibitor'>(str),
class: Aliased<'Antagonist' | 'Antibiotic' | 'Anticancer' | 'Anticoagulant' | 'Antifungal' | 'Antigen' | 'Antiinflammatory' | 'Antimicrobial' | 'Antineoplastic' | 'Antiparasitic' | 'Antiretroviral' | 'Anthelmintic' | 'Antithrombotic' | 'Antitumor' | 'Antiviral' | 'CASPASE inhibitor' | 'Chaperone binding' | 'Enzyme inhibitor' | 'Drug delivery' | 'Glycan component' | 'Growth factor' | 'Immunosuppressant' | 'Inducer' | 'Inhibitor' | 'Lantibiotic' | 'Metabolism' | 'Metal transport' | 'Nutrient' | 'Oxidation-reduction' | 'Protein binding' | 'Receptor' | 'Substrate analog' | 'Thrombin inhibitor' | 'Trypsin inhibitor' | 'Toxin' | 'Unknown' | 'Water retention' | 'Anticoagulant, Antithrombotic' | 'Antibiotic, Antimicrobial' | 'Antibiotic, Anthelmintic' | 'Antibiotic, Antineoplastic' | 'Antimicrobial, Antiretroviral' | 'Antimicrobial, Antitumor' | 'Antimicrobial, Antiparasitic, Antibiotic' | 'Thrombin inhibitor, Trypsin inhibitor'>(str),
/**
* Evidence for the assignment of _pdbx_reference_molecule.class
*/
@@ -356,7 +356,7 @@ export const BIRD_Schema = {
/**
* The type of the polymer.
*/
type: Aliased<'peptide-like' | 'nucleic-acid-like' | 'polysaccharide-like'>(str),
type: Aliased<'peptide-like' | 'nucleic-acid-like' | 'polysaccharide-like' | 'oligosaccharide'>(str),
/**
* The database code for this source information
*/
@@ -496,4 +496,4 @@ export const BIRD_Schema = {
};
export type BIRD_Schema = typeof BIRD_Schema;
export interface BIRD_Database extends Database<BIRD_Schema> {}
export interface BIRD_Database extends Database<BIRD_Schema> {};

View File

@@ -1,14 +1,14 @@
/**
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.324, IHM 1.09, CARB draft.
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.326, IHM 1.09, CARB draft.
*
* @author molstar/ciftools package
*/
import { Database, Column } from '../../../../mol-data/db';
import Schema = Column.Schema
import Schema = Column.Schema;
const str = Schema.str;
const float = Schema.float;
@@ -397,4 +397,4 @@ export const CCD_Schema = {
};
export type CCD_Schema = typeof CCD_Schema;
export interface CCD_Database extends Database<CCD_Schema> {}
export interface CCD_Database extends Database<CCD_Schema> {};

View File

@@ -8,7 +8,7 @@
import { Database, Column } from '../../../../mol-data/db';
import Schema = Column.Schema
import Schema = Column.Schema;
const int = Schema.int;
const float = Schema.float;
@@ -792,4 +792,4 @@ export const CifCore_Aliases = {
};
export type CifCore_Schema = typeof CifCore_Schema;
export interface CifCore_Database extends Database<CifCore_Schema> {}
export interface CifCore_Database extends Database<CifCore_Schema> {};

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -23,4 +23,11 @@ export const mmCIF_chemCompBond_schema = {
...mmCIF_Schema.chem_comp_bond,
/** Indicates if the bond entry was taken from the protonation variant dictionary */
molstar_protonation_variant: Column.Schema.Str()
};
};
/** Has `type` extended with 'Ion' and 'Lipid' */
export const mmCIF_chemComp_schema = {
...mmCIF_Schema.chem_comp,
type: Column.Schema.Aliased<mmCIF_Schema['chem_comp']['type']['T'] | 'Ion' | 'Lipid'>(Column.Schema.str)
};
export type mmCIF_chemComp_schema = typeof mmCIF_chemComp_schema;

Some files were not shown because too many files have changed in this diff Show More