Compare commits

...

1212 Commits

Author SHA1 Message Date
dsehnal
ae2285599f 3.31.3 2023-02-22 20:44:32 +01:00
dsehnal
104ab757d2 Update fs import in data-source.ts 2023-02-22 20:37:34 +01:00
Alexander Rose
de84a8c8c5 tweak minNear param max 2023-02-18 11:42:45 -08:00
Alexander Rose
4fa135daf0 fix near clipping avoidance in impostor shaders 2023-02-18 11:33:36 -08:00
midlik
9870cb4082 Fixed degenerate case (1-point) in PCA (#725)
* Fixed degenerate case (1-point) in PCA - now correctly returns identity matrix

* Changelog
2023-02-17 20:08:21 +01:00
Alexander Rose
b2924761ab update impostor bond visuals on sizeFactor changes 2023-02-12 22:06:18 -08:00
Alexander Rose
9c5f451878 3.31.2 2023-02-12 09:19:17 -08:00
Alexander Rose
6a5fb85c5a changelog 2023-02-12 09:13:40 -08:00
Alexander Rose
2aef5fb3e5 fix use of WEBGL_provoking_vertex 2023-02-12 09:12:24 -08:00
Jose Manuel Duarte
63a9aef5eb Fixing exit code for volume packer (#714)
* Fixing exit code for pack.ts

* Changelog

---------

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2023-02-12 14:37:02 +01:00
Alexander Rose
e36fe8c707 fix polymer trace update logic 2023-02-11 21:26:03 -08:00
Alexander Rose
0585f7b9ca timer, mark ssao 2023-02-11 10:53:47 -08:00
Alexander Rose
25ab0d7799 fix outline artefact with opaque behind transparent 2023-02-11 10:49:43 -08:00
Alexander Rose
ea313a442c remove pca transform from components ui focus
- too distracting
2023-02-11 10:45:09 -08:00
Alexander Rose
57a63e0381 3.31.1 2023-02-05 16:35:19 -08:00
Alexander Rose
c525812aee changelog 2023-02-05 16:30:41 -08:00
Alexander Rose
e602705e6d 3.31.0 2023-02-05 16:19:17 -08:00
Alexander Rose
b7d126b39b package updates 2023-02-05 16:13:46 -08:00
Alexander Rose
80b2864da8 remove unused travis file 2023-02-05 16:13:36 -08:00
Alexander Rose
36ba6f035a increase max intensity in light/ambient params 2023-02-05 15:45:39 -08:00
Alexander Rose
b84bbdace2 refactor PCA focus some more 2023-02-05 15:08:17 -08:00
Alexander Rose
750b2f69fc Merge pull request #710 from molstar/console-stats-timing
add consoleStats, improve timer
2023-02-05 14:00:51 -08:00
Alexander Rose
6ffe051a8e Merge branch 'master' of https://github.com/molstar/molstar 2023-02-05 13:43:36 -08:00
Alexander Rose
bc3640b264 add asymIds to OperatorGroup 2023-02-05 13:43:27 -08:00
Alexander Rose
8746b6e2f4 Observable canvas commit 2023-02-05 13:41:42 -08:00
dsehnal
445977d99b Fix data-source node workaround 2023-02-05 22:34:38 +01:00
Alexander Rose
0f0185e18c add fast boundary helper and unit trait 2023-02-05 13:34:33 -08:00
dsehnal
a748b1581e refactor PCA focus 2023-02-05 22:24:40 +01:00
Ke Ma
af1e06203b Dev focus pca (#624)
* viewer camera change based on Pca

* minor code refactor

* update author

* Update src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>

* Update src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>

* Update src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>

* Update src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>

* Update src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>

* Update src/mol-plugin-ui/structure/components.tsx

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>

* Update src/mol-plugin-state/manager/focus-camera/focus-first-residue.ts

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>

* revise

* deepclone

* chunked-array

---------

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2023-02-05 20:27:25 +01:00
Alexander Rose
356cf008ce add consoleStats, improve timer 2023-02-04 19:25:08 -08:00
Alexander Rose
07284e7e3d handle null-texture in calcTextureMeshColorSmoothing 2023-02-04 13:58:02 -08:00
Alexander Rose
72055442b7 add Color.contrast/.luminance 2023-02-04 10:30:14 -08:00
Alexander Rose
5fa7d84c23 axes camera-helper tweaks 2023-02-03 07:59:26 -08:00
midlik
de46f08bf4 Minor changes regarding HeadlessPluginContext (#708)
* Minor changes regarding HeadlessPluginContext

* Tweaks
2023-02-03 12:31:39 +01:00
Alexander Rose
fde395e2fa Merge pull request #705 from molstar/camera-helper-params
add axes camera-helper customization options
2023-02-01 08:10:47 -08:00
midlik
da1e55250e Added HeadlessPluginContext, Canvas3DRenderer, image-renderer example (#700)
* Added HeadlessPluginContext, Canvas3DRenderer, image-renderer example

* Fixed dependencies in package.json

* Removed gl from deps

* Removed gl, pngjs, jpeg-js from dependencies, importing via LazyImports

* Updated docs in src/examples/image-renderer/index.ts

* Added gl, pngjs, jpeg-js to optionalDependencies

* Canvas3DRenderer: default cameraResetDurationMs: 0 (necessary when changing camera between renderings)

---------

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2023-02-01 16:56:38 +01:00
Alexander Rose
a4ab117d14 support WEBGL_provoking_vertex 2023-01-31 19:56:03 -08:00
Alexander Rose
4cd7088eb8 add axes camera-helper customization options 2023-01-31 19:41:14 -08:00
Alexander Rose
8e1876fc25 update camera/handle helper on pixelRatio changes 2023-01-31 19:35:09 -08:00
Alexander Rose
29693ebe8c fix text zOffset with orthographic projection 2023-01-31 19:09:36 -08:00
Alexander Rose
a8ee7bfcbe fix uModelView construction 2023-01-31 19:04:46 -08:00
Alexander Rose
2037dad03d 3.30.0 2023-01-29 16:28:11 -08:00
Alexander Rose
0a9fb603f6 changelog 2023-01-29 16:22:25 -08:00
Alexander Rose
0b7dadd345 package updates 2023-01-29 16:21:56 -08:00
Alexander Rose
a3645f5acc use single channel for downsampled depth when possible 2023-01-29 16:08:58 -08:00
Alexander Rose
92f409d6fc fix downsampled ssao 2023-01-29 16:08:18 -08:00
Alexander Rose
c28dd8135c perf tweaks
- reuse vec3 in getMatrices
- fast path in createElementSphereImpostor
2023-01-28 23:08:39 -08:00
Alexander Rose
3baa03ccdc adjust outlines based on view distance 2023-01-22 14:21:37 -08:00
Alexander Rose
659e96d93c Merge pull request #699 from MadCatX/ntc_tube_discontinuity
Fix NtC tube and Confal pyramids mesh when there are discontinuous chains
2023-01-22 14:14:51 -08:00
Alexander Rose
365d7d46fd fix SSAO artefacts with high bias values 2023-01-22 11:47:17 -08:00
Alexander Rose
f8284508e1 Merge pull request #695 from molstar/state-images
state snapshot images
2023-01-22 11:45:16 -08:00
Alexander Rose
e9c36c2375 fix boundary-helper regression 2023-01-19 21:43:57 -08:00
Michal Malý
5d269fd77c Check for discontinuities when buiilding Confal pyramids mesh 2023-01-17 17:30:30 +01:00
Michal Malý
0064293e01 Unregister ConfalPyramids 2023-01-17 17:30:30 +01:00
Michal Malý
ba4b6f70d3 Draw gaps in NtC tube if there are discontinuities in a chain 2023-01-17 17:30:28 +01:00
Alexander Rose
9d056a85ec state snapshot images 2023-01-15 22:59:33 -08:00
Alexander Rose
3ed17fce6b update gh workflow gl version 2023-01-15 22:53:34 -08:00
Alexander Rose
d656dd0d18 improve boundary calculation performance 2023-01-15 22:49:07 -08:00
Alexander Rose
27c92085c7 changelog 2023-01-15 14:06:53 -08:00
Alexander Rose
94e9462af8 Merge pull request #526 from MadCatX/ntc_tube_2
Add NtC Tube representation
2023-01-15 14:05:29 -08:00
Michal Malý
2e52ccf5d8 Add NtC Tube representation 2023-01-15 22:18:13 +01:00
Michal Malý
b15196a284 Reset ConfalPyramidsIterator internal state correctly when switching
chains
2023-01-15 22:08:45 +01:00
Michal Malý
d29cc85439 Factor out common Dnatco code 2023-01-15 22:08:41 +01:00
Alexander Rose
30367cf239 lint spacing 2023-01-15 11:10:16 -08:00
Alexander Rose
dcf9d1c3bb 3.29.0 2023-01-15 10:06:42 -08:00
Alexander Rose
c0c2e4ce4a changelog 2023-01-15 10:01:35 -08:00
Alexander Rose
3557f4e738 schema updates 2023-01-15 10:00:38 -08:00
Alexander Rose
6595c00cff package updates 2023-01-15 09:58:20 -08:00
Alexander Rose
c612018ba8 Merge pull request #693 from molstar/dim-unmarked
support dim unmarked groups & marker edge strength
2023-01-15 09:04:35 -08:00
Alexander Rose
ec06ef2dfb fix missing uniforms 2023-01-14 13:14:16 -08:00
Alexander Rose
2febf45700 support dim unmarked groups & marker edge strength 2023-01-14 12:46:26 -08:00
Alexander Rose
3e6066a1a1 add .getCenter and .center to Camera 2023-01-14 12:41:41 -08:00
Alexander Rose
b61e5c76db add default to ParamDefinition.Values type 2023-01-14 12:40:13 -08:00
Alexander Rose
bdee4859f2 generic loci support for overpaint, substance, clipping 2023-01-14 12:39:25 -08:00
Alexander Rose
b5e45aae95 Merge pull request #692 from molstar/misc2
Misc2
2023-01-09 20:18:01 -08:00
Alexander Rose
7fd12c5622 tweaks/fixes 2023-01-09 20:16:33 -08:00
Alexander Rose
47442be989 changelog 2023-01-08 21:30:41 -08:00
Alexander Rose
3a484dc41a make SymmetryOperator.createMapping monomorphic 2023-01-08 21:25:23 -08:00
Alexander Rose
9a2dfd7e57 improve calculateInvariantBoundingSphere 2023-01-08 21:25:07 -08:00
Alexander Rose
c9a168a138 improve checks in UnitsRepresentation setVisualState 2023-01-08 21:24:35 -08:00
Alexander Rose
3726f28eeb defer calculation of more scene properties 2023-01-08 21:24:21 -08:00
Alexander Rose
ead25d6a9c tweak BoundaryHelper performance 2023-01-08 21:24:14 -08:00
Alexander Rose
55f4abb6be add repr/theme registry .clear method 2023-01-08 21:24:04 -08:00
dsehnal
2e013fafc8 Add StructureElement.Loci.forEachLocation 2023-01-05 13:07:21 +01:00
dsehnal
0809379f91 update build badge 2023-01-02 14:23:36 +01:00
dsehnal
0d4a95f5af workflow name 2023-01-02 14:21:30 +01:00
David Sehnal
2e9129a71c Fix some cyclic imports & reduce const enum usage (#680)
* fix mol-theme/color

* fix mol-theme/size

* remove unnecessary const enums

* remove Column.ValueType const enum

* NumberTypes

* ValueKindConst => ValueKinds

* more const enum fixes

* more const enums

* readme

* update filename

* typing

* FeatureTypes
2022-12-31 11:22:18 +01:00
David Sehnal
7384bebf4e Fix some cyclic imports & reduce const enum usage (#680)
* fix mol-theme/color

* fix mol-theme/size

* remove unnecessary const enums

* remove Column.ValueType const enum

* NumberTypes

* ValueKindConst => ValueKinds

* more const enum fixes

* more const enums

* readme

* update filename

* typing

* FeatureTypes
2022-12-31 11:22:05 +01:00
Alexander Rose
0e197b1885 Merge pull request #683 from molstar/misc
Misc tweaks
2022-12-30 20:45:46 -08:00
Alexander Rose
54697ae0d5 changelog 2022-12-30 10:16:30 -08:00
Alexander Rose
7b6eb9337e add input-color picker 2022-12-29 21:51:42 -08:00
Alexander Rose
a94fb84052 add isDisabled to ParameterMappingControl 2022-12-29 21:51:27 -08:00
Alexander Rose
528aeb1873 only update clip defines if changed 2022-12-29 21:51:18 -08:00
Alexander Rose
e7b35daf45 improve structure/unit areEqual methods
- always equal when objects are identical
2022-12-29 21:51:06 -08:00
Alexander Rose
7d10971617 avoid cloning of structure repr params 2022-12-29 21:50:49 -08:00
dsehnal
3d83211503 fix dropFiles bug 2022-12-24 12:51:09 +01:00
dsehnal
cd8c8fa020 Merge branch 'master' of https://github.com/molstar/molstar 2022-12-23 14:28:16 +01:00
David Sehnal
4c03009357 Volume Quick Color Select Control (#677)
* changelog

* volume quick select control

* tweak
2022-12-22 08:53:27 +01:00
Alexander Rose
047f547863 support tags in StructureBuilder.createStructure 2022-12-21 20:25:03 -08:00
Alexander Rose
83c62c614b Merge branch 'master' of https://github.com/molstar/molstar 2022-12-21 20:24:22 -08:00
Alexander Rose
c39b3569de add escapeRegExp util 2022-12-21 20:24:06 -08:00
dsehnal
7fea62aa46 changelog 2022-12-20 14:28:07 +01:00
midlik
d816f510ea Volseg more tweaks 2 (#675)
* Volseg: Fixed not loading volume section from state

* Volseg: Double-sided meshes (still ugly)

* Mesh extension: Detection (and correction) of inverted meshes

* Meshes extension: Fixed transparent backfaces, tidy up

* Removed duplicated classes in Meshes and Volseg extensions

* Changelog
2022-12-20 14:24:31 +01:00
dsehnal
c2064aa318 3.28.0 2022-12-20 00:37:33 +01:00
dsehnal
109709ce8b Merge branch 'master' of https://github.com/molstar/molstar 2022-12-20 00:34:53 +01:00
midlik
b200725762 Volseg more tweaks (#674)
* Volseg: Fixed not loading volume section from state

* Volseg: Double-sided meshes (still ugly)

* Mesh extension: Detection (and correction) of inverted meshes
2022-12-20 00:34:40 +01:00
dsehnal
9cf34bf987 changelog 2022-12-20 00:27:00 +01:00
Alexander Rose
be3a91bb14 package updates 2022-12-19 15:21:10 -08:00
Alexander Rose
fc948d8b27 fix gpu mc use of float16 2022-12-19 14:41:12 -08:00
midlik
8774658f4e Volseg: Fixed not loading volume section from state (#672)
* Volseg: Fixed not loading volume section from state

* Volseg: Double-sided meshes (still ugly)
2022-12-19 23:19:53 +01:00
David Sehnal
0bf32148af Viewer setting for volumes and segmentations (#673) 2022-12-19 23:10:40 +01:00
David Sehnal
97d158b615 Volseg extenison tweaks (#671)
* improve currentVolume behavior

* use different iso-value if 1sigma isnt present in the data
2022-12-19 22:16:09 +01:00
Alexander Rose
b772dea188 tweak ignoreHydrogens non-polar handling (#669) 2022-12-19 21:59:55 +01:00
Alexander Rose
5c8f0b35ec changelog 2022-12-19 10:33:36 -08:00
dsehnal
1b382653f2 add volume controls to Volseg extension 2022-12-19 16:49:30 +01:00
midlik
c7cee63c97 Volumes & Segmentations extension (#668)
* Created CellStar state action

* CellStar: download metadata

* Right panel - CellStar UI

* CellStar: Lattice segmenatation and fitted PDB models

* CellStar: Support for source-database entry ID from metadata

* CellStar: Mesh segmentation

* CellStar: Switching between multiple entries

* CellStar: Changed default API URL

* UI updates

* CellStar: Clicking on meshes shows annotations...

* support info in Converted param

* support color/size in VolumeRepresentation3DHelpers.getDefaultParams

* support multi-visual volume representations

- repr can provide list of keys
- create visual for each key

* add volume segmentation support

- segmentation property
- segment loci & location

* add volume-segment color theme

* add volume segment representation

* use optional chaining

* add support for volume segmentation cif

* improve isosurface bounding-sphere

* fix segcif schema type

* CellStar: Highlighting segments on hover in the right panel

* CellStar: Using new Mol*-native segment visualization

* lint

* Segmentation volume can have custom segment labels

* CellStar: Segment labels for Mol*-native segments

* CellStar: Removed old implementation of segments

* CellStar: Rename CellStarLatticeSegmentationData2 -> CellStarLatticeSegmentationData

* CellStar: Default volume server is https://cellstar.ncbr.muni.cz

* CellStar: debugging

* CellStar: Fixed bug in LatticeSegmentation (scaling)

* CellStar: Partially savable state

* CellStar: WaitingSlider

* CellStar: Opacity changed via params

* Savable state for opacity

* CellStar: Changing UI in animations

* CellStar: Savable state for whole current UI

* CellStar: Savable state for segment labels

* CellStar: Source can be 'idr', CellStarVolumeServerConfig.DefaultServer

* CellStar: Select segment for lattice segmentation

* CellStar: Select segment, complete

* CellStar: Changes visible labels to "Volume & Segmentation"

* CellStar: Drop list with available entries

* CellStar: Volume type switching (partial)

* CellStar: Trying to set direct-volume control points

* CellStar: Volume visual switching

* Mesh extension: removed molstar-lib-imports

* CellStar: Global options

* CellStar: Updated file headers and `CHANGELOG.md`

* CellStar: UI controls disabled while executing change

* CellStar: Hidden state nodes, fixed bug with removed global state

* CellStar: Volume opacity slider

* CellStar extension renamed to Volseg

* UI tweaks

Co-authored-by: Alexander Rose <alexander.rose@weirdbyte.de>
2022-12-19 16:15:23 +01:00
Alexander Rose
ba9474fa62 add stencil related webgl state and format 2022-12-16 21:47:05 -08:00
Alexander Rose
b7ec7ea686 Merge pull request #665 from molstar/solid-impostor
Solid impostors
2022-12-16 21:41:14 -08:00
Alexander Rose
74560adb08 changelog 2022-12-16 21:20:52 -08:00
Alexander Rose
e6a303bdda Merge branch 'master' of https://github.com/molstar/molstar into solid-impostor 2022-12-16 21:19:19 -08:00
David Sehnal
7afcf0bb68 Show histogram in direct volume control point settings (#666) 2022-12-16 20:02:46 +01:00
Alexander Rose
7aae2d0616 fix impostor sphere near clipping 2022-12-15 22:06:06 -08:00
dsehnal
9255505a3b 3.27.0 2022-12-15 13:02:37 +01:00
dsehnal
6c0dfd338d changelog 2022-12-15 12:59:45 +01:00
David Sehnal
c306e988c8 Ability to show only polar hydrogens (#663) 2022-12-15 12:26:34 +01:00
Alexander Rose
86f7a8b273 add impostor solidInterior param 2022-12-14 22:50:15 -08:00
David Sehnal
2428a8efab Merge pull request #660 from molstar/struct-conn-ions-fix
Fix struct_conn bond assignment for ions
2022-12-14 10:20:22 +01:00
Alexander Rose
cba12e487f wip, solid impostor flag 2022-12-13 23:59:08 -08:00
dsehnal
e98d7931ca Fix import 2022-12-13 18:01:59 +01:00
dsehnal
f8e2d2e3d0 tweak hasStructConnRecord 2022-12-13 17:57:31 +01:00
dsehnal
4455bab6ac Fix struct_conn bond assignment for ions 2022-12-13 16:06:19 +01:00
David Sehnal
b21fb27041 Merge pull request #658 from molstar/action-params
ApplyActionControl param handling
2022-12-13 15:20:31 +01:00
dsehnal
5402ee0019 ApplyActionControl param handling 2022-12-13 15:16:19 +01:00
David Sehnal
02654ea57b Merge pull request #657 from molstar/fix-qa-assignment
Fix QualityAssessment assignment
2022-12-13 09:33:13 +01:00
dsehnal
9cd4aeabaa Merge branch 'master' of https://github.com/molstar/molstar into fix-qa-assignment 2022-12-13 09:32:42 +01:00
dsehnal
d788511a83 header 2022-12-13 09:32:20 +01:00
Alexander Rose
378b5b8096 Merge pull request #643 from arussell123/master
Add include transparent parameter for outlines
2022-12-12 21:58:49 -08:00
Alexander Rose
e26eb2f751 Merge branch 'master' into master 2022-12-12 21:58:25 -08:00
Alexander Rose
26264b15f7 tweaks 2022-12-12 21:56:34 -08:00
Alexander Rose
309e3dd981 impostor per-pixel object clipping 2022-12-12 21:51:39 -08:00
Alexander Rose
4ff5ed3b5d fix cylinder imposter cap normals 2022-12-12 21:18:37 -08:00
dsehnal
270a757756 changelog 2022-12-12 18:39:41 +01:00
dsehnal
79e4030ab4 fix qa assignment 2022-12-12 18:35:52 +01:00
David Sehnal
fd86927e04 Merge pull request #655 from MKampfrath/access-modifiers
change access modifiers
2022-12-12 16:36:38 +01:00
MKampfrath
df3a7e5037 change access modifiers 2022-12-12 16:30:40 +01:00
Alice Russell
fefc6f14c9 Change is outline enabled to is transparant outline enabled 2022-12-12 10:43:14 +00:00
Alexander Rose
923fbef0e4 remove superfluous check 2022-12-11 20:45:26 -08:00
Alexander Rose
601bd5ba7a improve impostor shaders
- fix sphere near-clipping with orthographic projection
- fix cylinder near-clipping
- add interior cylinder caps
2022-12-10 21:47:16 -08:00
Alexander Rose
5798f20c41 lint fix 2022-12-10 21:41:25 -08:00
David Sehnal
f2e26f91a8 Merge pull request #647 from dwilliams-nobias/animation-once-stops
Animation "once" fails to stop for many frames under certain conditions
2022-12-08 16:53:27 +01:00
David Sehnal
e2cdc45be6 Merge branch 'master' into animation-once-stops 2022-12-08 16:53:15 +01:00
Alice Russell
96493bc75e Fix linting 2022-12-07 14:26:48 +00:00
Alice Russell
d78ad4a78e Merge remote-tracking branch 'upstream/master' 2022-12-07 12:25:22 +00:00
Alice Russell
0c54b0dd6e Add option to toogle transparent outline 2022-12-07 12:21:31 +00:00
Alexander Rose
65310e52de guard against issue with bumpiness in impostors 2022-12-06 22:48:22 -08:00
David Williams
285d3cd9b8 Requested changes for pull request 2022-12-06 17:36:48 -08:00
David Williams
10486abb64 Add example molecule with 1,000 animation frames 2022-12-06 17:32:44 -08:00
David Williams
8c1a9fc988 Correctly check for duration "once" for fixed or computed duration 2022-12-06 16:57:27 -08:00
Alexander Rose
7bdd0b470b 3.26.0 2022-12-04 12:18:09 -08:00
Alexander Rose
b7a51f12bf changelog 2022-12-04 12:12:22 -08:00
Alexander Rose
e002ac5474 Merge pull request #644 from molstar/power-pref
support power-preference webgl attribute
2022-12-04 12:09:46 -08:00
Alexander Rose
211d339ce0 Merge branch 'master' into power-pref 2022-12-04 12:09:39 -08:00
Alexander Rose
509fb14473 Merge pull request #645 from molstar/structure-mol-surf
add structure molecular surface visual
2022-12-04 12:09:14 -08:00
Alexander Rose
ef838a1b83 Merge branch 'master' into structure-mol-surf 2022-12-04 12:09:05 -08:00
Alexander Rose
f84b5b633d improve Representation typing 2022-12-04 09:45:12 -08:00
Alexander Rose
8ec8c1170d comment 2022-12-04 09:32:02 -08:00
David Sehnal
920b98e4d1 Merge pull request #604 from molstar/volume-theme
by-volume-value theme
2022-12-04 09:18:32 +01:00
dsehnal
c80f52d4bc Merge branch 'master' of https://github.com/molstar/molstar into volume-theme 2022-12-04 09:14:41 +01:00
dsehnal
0b6aa42daf tweaks 2022-12-04 09:14:06 +01:00
Alexander Rose
04dc6427ef update SaccharideNames 2022-12-03 22:00:24 -08:00
Alexander Rose
77e366b484 schema updates 2022-12-03 21:58:04 -08:00
Alexander Rose
add7cfa0f2 package updates 2022-12-03 21:53:00 -08:00
Alexander Rose
14d4fa142c changelog 2022-12-03 21:46:55 -08:00
Alexander Rose
7fe1617f25 shadow param tweaks 2022-12-03 21:46:30 -08:00
Alexander Rose
cbe4cb521c add structure molecular surface visual 2022-12-03 21:32:54 -08:00
Alexander Rose
7c394525c1 Merge pull request #637 from molstar/sss
Screen-space shadows
2022-12-03 10:59:05 -08:00
Alexander Rose
12ed051fea Merge pull request #606 from jpattle/remove-caps-from-ligand-query
Remove common protein caps from ligand query
2022-12-03 10:41:00 -08:00
Alexander Rose
014913c635 support power-preference webgl attribute 2022-12-03 10:17:57 -08:00
Alexander Rose
369e45c282 handle bounds in shadow screen fade 2022-12-03 10:02:14 -08:00
Alice Russell
2892caec0c Update changelog 2022-12-02 12:31:56 +00:00
Alice Russell
eb609e918a linting fixes 2022-12-02 12:28:51 +00:00
Alice Russell
9217e58845 Add option to set minimum alpha value for outlines to be shown 2022-12-02 12:12:22 +00:00
Alexander Rose
26b633618a tweak cellpack shadow params 2022-11-27 22:22:29 -08:00
Alexander Rose
e3054d6ee1 shadows bonds check 2022-11-27 22:07:23 -08:00
Alexander Rose
0b6294f4ec check for shadow in PostprocessingPass.isEnabled 2022-11-26 22:33:11 -08:00
Alexander Rose
7b130dc0f3 cleanup 2022-11-26 22:09:24 -08:00
Alexander Rose
d93c128c25 cleanup 2022-11-26 22:04:41 -08:00
Alexander Rose
e1dd74775e refactor sss
- only sss, remove other ao implementations
- tweak params
- make sss a separate renderable
2022-11-26 21:47:08 -08:00
Alexander Rose
e61e706607 Merge branch 'master' of https://github.com/molstar/molstar into fake_shadow 2022-11-25 21:13:35 -08:00
jpattle
a57d46deaa Merge branch 'master' into remove-caps-from-ligand-query 2022-11-21 08:58:41 +00:00
Alexander Rose
60efdc0071 3.25.1 2022-11-20 10:43:31 -08:00
Alexander Rose
4dc1155a9e changelog 2022-11-20 10:38:07 -08:00
Alexander Rose
5cabe6fb42 fix auto structure-quality for coarse models 2022-11-20 10:37:30 -08:00
Alexander Rose
42239c305f better handle single-element units in Structure.eachUnitPair 2022-11-20 10:25:26 -08:00
ludovic autin
fd3c763349 All parameters exposed to try to find best parameters for different representation. 2022-11-18 09:13:42 -08:00
ludovic autin
daa9bbf2c9 fix trailing space 2022-11-17 09:31:21 -08:00
ludovic autin
c7dad00908 fake screen space shadow, second pass ssao 2022-11-17 09:28:00 -08:00
ludovic autin
24317717e8 Merge remote-tracking branch 'upstream/master' into forkdev 2022-11-16 14:01:04 -08:00
dsehnal
dd3eac6db6 3.25.0 2022-11-16 00:15:41 +01:00
dsehnal
1606f8517f changelog 2022-11-16 00:12:57 +01:00
David Sehnal
3a98401ada Merge pull request #623 from JonStargaryen/master
Fix Handling of Gzipped Assets by Reverting #615
2022-11-16 00:11:02 +01:00
Alexander Rose
4764251241 operator key tweaks 2022-11-14 21:48:44 -08:00
Sebastian Bittrich
3de04b7b9d CHANGELOG 2022-11-14 13:17:15 -08:00
Sebastian Bittrich
04908495e9 Revert "keep asset url to detect compression"
This reverts commit 2bc45c25fe.
2022-11-14 13:13:06 -08:00
Alexander Rose
3c835c848e 3.24.0 2022-11-13 20:56:58 -08:00
Alexander Rose
0f1788f122 changelog 2022-11-13 20:51:24 -08:00
Alexander Rose
3d72e700a4 package updates 2022-11-13 20:48:33 -08:00
Alexander Rose
a5cf41e65f fix viewport color for transparent background (#617) 2022-11-13 20:47:30 -08:00
Alexander Rose
7029bc41d7 Merge pull request #621 from molstar/theme-strength
add theme strength to 3d repr state
2022-11-13 20:22:14 -08:00
Alexander Rose
b87d40c844 changelog 2022-11-13 20:21:41 -08:00
Alexander Rose
9e154376d3 Merge branch 'master' of https://github.com/molstar/molstar into theme-strength 2022-11-13 20:18:56 -08:00
Alexander Rose
4a9fdbce57 Merge pull request #619 from molstar/opkey
add key to symmetry operator
2022-11-13 20:18:12 -08:00
Alexander Rose
775e335292 remove cantor-pair use 2022-11-13 20:11:42 -08:00
Alexander Rose
e553bf4deb add theme strength to 3d repr state 2022-11-12 21:58:13 -08:00
Alexander Rose
db0e09ec6e add more webgl extensions
- draw_buffers_indexed
- parallel_shader_compile
- fbo_render_mipmap
2022-11-12 20:34:18 -08:00
Alexander Rose
ba50760f92 add key to symmetry operator
- molql operatorKey
- index-pair operator prop
2022-11-12 20:30:33 -08:00
David Sehnal
524e6d4f81 Merge pull request #615 from JonStargaryen/master
keep asset url to detect compression
2022-11-11 07:47:44 +01:00
ludovic autin
db93a669ab Merge branch 'molstar:master' into forkdev 2022-11-10 13:59:26 -08:00
Sebastian Bittrich
423f5b0502 CHANGELOG 2022-11-10 13:16:27 -08:00
Sebastian Bittrich
2bc45c25fe keep asset url to detect compression 2022-11-10 13:13:49 -08:00
Jason Pattle
d341463f67 Removed unneccessary wholeResidues query from new ligand selection query as the atomGroups residue-test already covers this functionality 2022-11-07 08:37:16 +00:00
Alexander Rose
19d1ecb36a add (slow) texture-mesh position iterator 2022-11-06 23:27:17 -08:00
Alexander Rose
ffe4047f97 fix vertex color/overpaint in direct-volume shader 2022-11-06 22:24:36 -08:00
Alexander Rose
15a3c29e7a adjust external-volume theme file name 2022-11-06 22:23:15 -08:00
Alexander Rose
6a32f85e60 Merge pull request #603 from giagitom/transparent-bg-fixes 2022-11-06 16:42:27 -08:00
Jason Pattle
42ff593004 Added missing semicolon; linting 2022-11-02 10:06:26 +00:00
Jason Pattle
5140af4e6f Added myself as a contributor to package.json 2022-11-02 09:56:07 +00:00
Jason Pattle
0f5b4c00a9 Updated changelog 2022-11-02 09:54:57 +00:00
Jason Pattle
feb69f4987 Excluded whole residues which match any common protein caps from the ligand selection query 2022-11-02 09:49:44 +00:00
Jason Pattle
84eb9a58ca Added names for common protein caps 2022-11-02 09:49:07 +00:00
dsehnal
fbd96f473a External Volume theme features 2022-11-01 11:54:27 +01:00
dsehnal
69228157dc fix typo 2022-10-31 15:42:13 +01:00
dsehnal
6808f32b8d by-volume-value theme 2022-10-31 15:41:10 +01:00
giagitom
f29c62ec33 Transparent bg fix 2022-10-30 12:06:32 +01:00
Alexander Rose
d77981230b mmcif schema update 2022-10-29 12:15:29 -07:00
dsehnal
e2b92c15f0 PluginContext.initContainer options 2022-10-27 08:41:01 +02:00
dsehnal
14614f4803 3.23.0 2022-10-19 13:11:47 +02:00
dsehnal
37d3489b07 changelog 2022-10-19 13:09:02 +02:00
David Sehnal
f81225cc0d Merge pull request #592 from molstar/volume/defaults-for-em
Change EM Volume Streaming default Auto
2022-10-19 13:08:17 +02:00
dsehnal
eb47f43940 Change EM Volume Streaming default Auto 2022-10-19 13:05:16 +02:00
dsehnal
7618a5e2c9 pr template 2022-10-19 12:41:24 +02:00
David Sehnal
ab3ff842b2 Merge pull request #590 from molstar/reusable-canvas
Built-in support for mouting/unmounting PluginContext
2022-10-19 09:55:31 +02:00
dsehnal
82f0f92c15 remove unused code 2022-10-18 15:20:48 +02:00
dsehnal
545d9434d8 Add PluginContext.initContainer/canvas3dInitialized and their usage 2022-10-18 09:16:08 +02:00
dsehnal
bbc43d5113 Add PluginContext.mount/unmount 2022-10-18 08:41:29 +02:00
dsehnal
a6709acf65 3.22.0 2022-10-17 20:44:13 +02:00
dsehnal
509a027742 changelog 2022-10-17 20:41:35 +02:00
David Sehnal
7244023233 Merge pull request #589 from molstar/picking-granuality-v2
Volume.PickingGranuality custom property
2022-10-17 20:39:47 +02:00
dsehnal
c5f987d8b2 getSliceLoci tweak 2022-10-17 20:36:39 +02:00
dsehnal
793696d4c0 Volume slice granuality 2022-10-17 20:34:11 +02:00
dsehnal
305ca05f04 tweaks 2022-10-17 20:24:48 +02:00
dsehnal
f4d7d1920a typos 2022-10-17 20:12:19 +02:00
dsehnal
458aad0161 Volume.PickingGranuality custom property 2022-10-17 20:05:56 +02:00
dsehnal
9e3132461f 3.21.0 2022-10-17 17:32:57 +02:00
dsehnal
8301291215 changelog 2022-10-17 17:29:52 +02:00
David Sehnal
daed14e228 Merge pull request #588 from midlik/picking-whole-isosurfaces
New volume isosurface param pickingGranularity: voxels|surfaces
2022-10-17 17:27:34 +02:00
David Sehnal
7db82c5ba5 Merge pull request #584 from arussell123/master
Prevent component controls collapsing when option is selected
2022-10-17 16:43:01 +02:00
Alexander Rose
91d03c22c2 3.20.0 2022-10-16 21:42:39 -07:00
Alexander Rose
bc188f0d2b changelog 2022-10-16 21:37:18 -07:00
Alexander Rose
3981225824 package updates 2022-10-16 21:34:59 -07:00
Alexander Rose
1886d9d72f add structure-index color theme 2022-10-16 21:28:06 -07:00
Alexander Rose
2a7dec8892 Merge pull request #583 from jpattle/model-index-carbon-color
Model index updates & carbon color
2022-10-16 19:43:23 -07:00
Alexander Rose
35d4a5b297 Merge branch 'master' into model-index-carbon-color 2022-10-16 19:39:22 -07:00
Alexander Rose
26345bfa50 tweak 2022-10-16 17:42:43 -07:00
Alexander Rose
8c9b8676dd handle 'not enough samples' in distinctColors 2022-10-16 16:43:50 -07:00
Alexander Rose
5593c7a75f add Model.MaxIndex and use in model-index theme 2022-10-16 16:37:09 -07:00
Alexander Rose
5b70c14ffe tweak theme descriptions 2022-10-16 16:35:51 -07:00
Alexander Rose
5e4d611044 tweak changelog 2022-10-16 16:33:52 -07:00
David Sehnal
7ab9d57156 Merge pull request #545 from giagitom/lookup3d
adding nearest and distance to point methods to lookup3d
2022-10-14 21:46:33 +02:00
Adam Midlik
9ea6f51126 New volume isosurface param pickingGranularity: voxels|surfaces 2022-10-13 00:57:39 +02:00
giagitom
649fe4f4f0 Lint fix 2022-10-12 16:57:56 +02:00
giagitom
53df86c585 Avoid using unnecessary extractMinimum from heap if k=1 on nearest search, add nearest method as unreleased. 2022-10-12 16:14:51 +02:00
Alice Russell
87c708e3c1 Remove action state from being set to undefined when action selected to stop options from minimising on selection 2022-10-12 10:58:30 +01:00
Jason Pattle
ba927b0490 returned clone of theme params for model and trajectory index themes, added contributor name 2022-10-12 08:30:52 +01:00
Jason Pattle
2a09725c98 added the new model-index color theme as an option in the illustrative color-theme 2022-10-12 08:30:10 +01:00
Jason Pattle
9fa0d17933 removed carbon color adjustment option 2022-10-12 08:29:45 +01:00
Jason Pattle
8d9f8a996a Updated change log with changes to model-index and element-symbol 2022-10-12 08:29:17 +01:00
giagitom
8814b60d0b Increased performances of lookup3d nearest search. 2022-10-11 18:12:27 +02:00
Jason Pattle
541c07c53a Added a parameter to make adjusting the carbon color by the same saturation and lightness carbon colors optional 2022-10-11 16:19:17 +01:00
Jason Pattle
6cbed80815 updated the default color palette and removed the redundant model color map 2022-10-11 16:07:44 +01:00
Jason Pattle
a3c1fdc0f4 Added the model index theme provider as an option for the carbon color when selecting the element-symbol color theme 2022-10-11 15:53:05 +01:00
Jason Pattle
ddf789b01c added a new model-index color theme based off the trajectory index theme but instead using the Model.Index structure property 2022-10-11 15:50:23 +01:00
Jason Pattle
ab86cc0bf3 Renamed the model-index color theme file to trajectory-index 2022-10-11 15:37:04 +01:00
Jason Pattle
dc8fab5820 [BREAKING CHANGE] renamed the model-index color theme and its usages to trajectory-index to better reflect the functionality of the color theme 2022-10-11 15:35:29 +01:00
giagitom
813c4f845a Merge branch 'master' into lookup3d 2022-10-09 15:10:37 +02:00
Alexander Rose
6ed42e9521 add mipmap-based blur for skybox backgrounds 2022-10-08 14:54:29 -07:00
Alexander Rose
fb01ba60ec use resources object to get textures for smaa pass 2022-10-08 14:08:07 -07:00
Alexander Rose
ea4210ded5 add willReadFrequently option to sdf text 2d context 2022-10-08 14:06:25 -07:00
Alexander Rose
75e5cf54d6 remove deprecated vscode extension from recommendations 2022-10-08 14:05:12 -07:00
Jason Pattle
7cebc85a95 fixed linting warnings 2022-10-06 13:02:15 +01:00
Jason Pattle
c00faafa6d Returned a clone of the element symbol params instead of the original const, removing a todo comment 2022-10-06 11:42:53 +01:00
Jason Pattle
c9b14f0742 Updated the element symbol color theme so that the carbon color is also adjusted by saturation and brightness props 2022-10-06 09:13:33 +01:00
Alexander Rose
9624137c0d 3.19.0 2022-10-01 17:26:48 -07:00
Alexander Rose
3eb433368f changelog 2022-10-01 17:21:18 -07:00
Alexander Rose
58691f4f5f package updates 2022-10-01 17:19:59 -07:00
Alexander Rose
5e9295abd5 changelog 2022-10-01 15:45:17 -07:00
Alexander Rose
6ed0ae55b2 fix black artifacts
- on specular highlights with transparent background
2022-10-01 15:34:54 -07:00
Alexander Rose
84448d0aa1 Merge branch 'master' of https://github.com/molstar/molstar 2022-10-01 13:51:58 -07:00
Alexander Rose
31ced24966 Merge pull request #573 from molstar/optimize-binary-packing
Optimize BinaryCIF integer packing
2022-10-01 13:51:21 -07:00
Alexander Rose
24681840af debug tweaks 2022-10-01 13:34:50 -07:00
Alexander Rose
5d28aa4f2e add cameraClipping.minNear param 2022-10-01 13:32:09 -07:00
Alexander Rose
7dabdf3085 dpoit fixes
- when post-processing is off
- when rendering direct-volumes
2022-10-01 13:26:10 -07:00
giagitom
d7cbd5570c Implement lookup & grid nearest search using fibonacci heap 2022-09-30 15:44:10 +02:00
dsehnal
80011d4aea optimize BinaryCIF integer packing 2022-09-29 17:30:26 +02:00
David Sehnal
c6fe440a01 Merge pull request #569 from russellp17/fix-empty-texture-error-on-empty-canvas
Fix "empty textures" error on empty canvas
2022-09-27 16:52:28 +02:00
Russell Parker
ba8d6dc3fa Fix "empty textures" error on empty canvas 2022-09-27 10:24:55 -04:00
giagitom
378f4f8304 Merge branch 'master' into lookup3d 2022-09-19 10:22:43 +02:00
Alexander Rose
aa414485a5 3.18.0 2022-09-17 11:55:04 -07:00
Alexander Rose
3a35a5d66a changelog 2022-09-17 11:49:08 -07:00
Alexander Rose
43b0a72b09 package updates 2022-09-17 11:49:01 -07:00
Alexander Rose
521ac2d13f stereo camera improvements
- fix param updates not applied
- better param ranges and description
- add timer.mark for left/right camera
2022-09-17 11:43:18 -07:00
Alexander Rose
30520c50c2 fix changelog 2022-09-17 11:39:40 -07:00
Alexander Rose
819f07eba3 Merge pull request #533 from giagitom/dpoit
Integration of Dual depth peeling - OIT method
2022-09-17 11:36:56 -07:00
Alexander Rose
d8d6aa7136 wboit, tweak timer.mark 2022-09-17 11:34:48 -07:00
giagitom
0bdcfea276 Merge branch 'master' into lookup3d 2022-09-16 17:45:20 +02:00
giagitom
718f76313f Adding nearest method to lookup3d at unit and structure level. 2022-09-16 17:32:07 +02:00
Alexander Rose
ed75a365d8 dpoit, cleanup 2022-09-12 22:38:49 -07:00
Alexander Rose
f5ff13ffe4 dpoit, fix transparent background 2022-09-12 22:38:26 -07:00
Alexander Rose
44c69b1716 dpoit, fix depthMask not off 2022-09-12 22:27:03 -07:00
Alexander Rose
559ca7ffb8 Merge branch 'master' of https://github.com/molstar/molstar into pr/giagitom/533 2022-09-12 22:22:55 -07:00
Alexander Rose
524f34e8c1 3.17.0 2022-09-11 14:38:51 -07:00
Alexander Rose
d749be11f0 type fixes 2022-09-11 14:34:21 -07:00
Alexander Rose
13dc9ff3cb package updates 2022-09-11 14:12:57 -07:00
Alexander Rose
24b4fce326 improve RG texture format handling 2022-09-10 17:21:20 -07:00
Alexander Rose
f506210bf8 dpoit, fix webgl1 support
- in webgl1 drawbuffers must be in the same format for some reason
2022-09-10 17:12:59 -07:00
Alexander Rose
cb0cbd06ce Merge branch 'master' of https://github.com/molstar/molstar into pr/giagitom/533 2022-09-10 16:02:43 -07:00
Alexander Rose
3356239089 fix click event triggered after move 2022-09-10 15:57:07 -07:00
Alexander Rose
9a5b2edc08 cleanup unused variable 2022-09-10 15:39:07 -07:00
Alexander Rose
2d41b4bd83 dpoit, use half float for color textures when available 2022-09-10 15:36:54 -07:00
Alexander Rose
58f7758ee1 add note to MAX_DPOIT_DEPTH constant 2022-09-10 15:30:28 -07:00
Alexander Rose
9dbb642883 more blend back handling cleanup 2022-09-10 15:26:49 -07:00
Alexander Rose
c5222e4d1d Merge branch 'master' of https://github.com/molstar/molstar into pr/giagitom/533 2022-09-10 14:54:57 -07:00
Alexander Rose
a5a695a17c Merge pull request #514 from yakomaxa/molql_integration_PR
Integration of pymol/vmd/jmol transpilers from MolQL project (WIP rasmol transpiler)
2022-09-10 14:51:53 -07:00
Alexander Rose
7d1dc86cfb Merge branch 'master' into molql_integration_PR 2022-09-10 14:50:27 -07:00
Alexander Rose
03224f914a transpiler helper cleanup 2022-09-10 14:49:03 -07:00
Alexander Rose
1cf1f07232 Merge pull request #552 from molstar/perf-caveat
add support for failIfMajorPerformanceCaveat
2022-09-10 13:43:37 -07:00
Alexander Rose
838d36a74e Merge branch 'master' into perf-caveat 2022-09-10 13:43:24 -07:00
Alexander Rose
6c9300d01b fix useBehavior handling 2022-09-10 13:42:52 -07:00
Alexander Rose
3059f7efef Merge pull request #553 from molstar/pdb-ter
fix handling of PDB TER records
2022-09-10 12:51:08 -07:00
Alexander Rose
fbce7d9afa Merge branch 'master' into pdb-ter 2022-09-10 12:50:59 -07:00
Alexander Rose
1c9f3ed9fa simplify ter record check 2022-09-10 12:50:22 -07:00
Alexander Rose
8c47d2d400 Merge pull request #554 from molstar/repr-getAllLoci
add repr.getAllLoci
2022-09-10 12:46:13 -07:00
Alexander Rose
8a18f25b5d Merge branch 'master' into repr-getAllLoci 2022-09-10 12:46:05 -07:00
Alexander Rose
e7ae0058ed Merge pull request #555 from molstar/bond-key-prop
add key property to intra- and inter-bonds
2022-09-10 12:45:39 -07:00
Alexander Rose
98bf3a3e33 tweak per-group transparency cutoff 2022-09-09 23:45:02 -07:00
Alexander Rose
379fcd4494 dpoit, render volumes with standard blending 2022-09-09 23:13:15 -07:00
Alexander Rose
8589777bac Merge branch 'master' of https://github.com/molstar/molstar into pr/giagitom/533 2022-09-09 22:27:45 -07:00
Alexander Rose
c10a21ecbd add key property to intra- and inter-bonds 2022-09-09 22:19:57 -07:00
Alexander Rose
eddc616b14 add repr.getAllLoci 2022-09-09 19:23:46 -07:00
Alexander Rose
70fc1a9579 support residue ranges in jmol atom expressions 2022-09-09 15:59:14 -07:00
Alexander Rose
f27ec4d6a4 formatting 2022-09-09 15:36:08 -07:00
Alexander Rose
1e6e956e2d improve pymol keywords
- rename polymer.protein and polymer.nucleic
- fix guide "C4'"
2022-09-09 15:35:46 -07:00
Alexander Rose
0a2a3530d1 fix handling of PDB TER records 2022-09-09 13:20:15 -07:00
Alexander Rose
9e4c820e26 add support for failIfMajorPerformanceCaveat 2022-09-09 12:31:40 -07:00
Alexander Rose
05290bfe9e update renderer spec resource counts 2022-09-08 18:40:43 -07:00
Alexander Rose
607f4ce353 dpoit: fix drawbuffer setup and blend to target 2022-09-08 18:10:31 -07:00
Alexander Rose
4b819ead1d formating 2022-09-08 18:08:53 -07:00
Alexander Rose
d07d9d3f31 add missing dpoitIterations param 2022-09-08 18:08:16 -07:00
Alexander Rose
d08776bf19 Merge branch 'master' of https://github.com/molstar/molstar into pr/yakomaxa/514 2022-09-07 18:37:37 -07:00
Alexander Rose
7a61fd44fd remove rasmol transpiler
- functionallity integrated into jmol transpiler
2022-09-07 18:32:43 -07:00
Alexander Rose
151da1487c formatting 2022-09-07 18:28:45 -07:00
Alexander Rose
e3f6dfad5b improve jmol transpiler
- add basic within function
- add basic backbone and protein keyword
- allow withspace in parans
2022-09-07 18:06:15 -07:00
Alexander Rose
32080ce918 improve jmol transpiler
- add resno ranges
- add bracketed resnames
- allow comma as OR
2022-09-07 15:16:28 -07:00
Alexander Rose
aedb2138c8 Merge pull request #548 from molstar/interactions-parent-display
add parentDisplay param to interactions repr
2022-09-06 12:19:25 -07:00
Alexander Rose
90e6938f1c Merge branch 'master' into interactions-parent-display 2022-09-06 11:57:02 -07:00
David Sehnal
eadff35250 Merge pull request #547 from molstar/sifts-alignment/residue-test
alignAndSuperposeWithSIFTSMapping includeResidueTest option
2022-09-05 15:11:53 +02:00
Alexander Rose
487450ec64 show only 'between' interaction in docking-viewer 2022-09-04 22:41:35 -07:00
Alexander Rose
f2f730bab5 fix parentDisplay 'between' logic 2022-09-04 22:41:06 -07:00
Alexander Rose
ceecee37a7 add parentDisplay param to interactions repr 2022-09-02 22:19:45 -07:00
dsehnal
394377bea9 alignAndSuperposeWithSIFTSMapping update 2022-09-02 15:50:58 +02:00
dsehnal
2b47818deb alignAndSuperposeWithSIFTSMapping includeResidueTest option 2022-09-02 15:38:06 +02:00
giagitom
9f72465052 remove unnecessary 2022-09-02 10:21:56 +02:00
giagitom
ac33b4a322 Adding distanceToVec in sphere3d namespace 2022-09-02 10:20:51 +02:00
giagitom
911c844e54 Remove logs and unused variables 2022-09-01 18:09:04 +02:00
giagitom
12b9655565 adding nearest and distance to point methods to lookup3d 2022-09-01 17:41:09 +02:00
dsehnal
2935717a06 Canvas3DParams fix 2022-08-29 16:49:30 +02:00
dsehnal
2c8d2cfa21 3.16.0 2022-08-25 17:55:54 +02:00
dsehnal
d67c0eb757 ViewportHelpContent fix 2022-08-25 17:53:10 +02:00
giagitom
7bcbcd5a7f Exposed dpoitIterations parameter 2022-08-25 16:07:36 +02:00
giagitom
1c06e7f36e Merge branch 'master' into dpoit 2022-08-24 18:44:30 +02:00
giagitom
407297adc0 added dpoit-enable query string 2022-08-24 18:21:34 +02:00
giagitom
b082b31562 Remove logs, changelog, set wboit as default option 2022-08-24 18:19:59 +02:00
giagitom
fcbeb0f82f Add defines for direct-volume 2022-08-24 17:42:08 +02:00
dsehnal
7094f8f265 Improve Viewer theming & label customization 2022-08-24 15:26:24 +02:00
giagitom
48aaa13420 Fix missing texture format 2022-08-24 15:24:30 +02:00
giagitom
d2434cf91f Merge branch 'master' into dpoit 2022-08-24 15:09:13 +02:00
giagitom
8dbe0d2793 Lint-fix 2022-08-24 14:37:33 +02:00
giagitom
7b308cf984 Keep wboit as default OIT method 2022-08-24 14:34:44 +02:00
giagitom
520af504aa Throw an error if wboit and dpoit are both enabled 2022-08-24 14:29:40 +02:00
giagitom
4bee130599 Added credits and contributions + lint-fix 2022-08-24 14:12:12 +02:00
dsehnal
19a9ed3e19 3.15.0 2022-08-23 19:00:36 +02:00
dsehnal
0dac1b93ae changelog 2022-08-23 18:57:45 +02:00
dsehnal
e824863de1 lint 2022-08-23 18:56:07 +02:00
David Sehnal
9ff8becd62 Merge pull request #530 from midlik/volume-streaming-camera-target
Volume streaming camera target (without caching)
2022-08-23 18:53:11 +02:00
Adam Midlik
fcaa1bcfa8 Merge branch 'master' into volume-streaming-camera-target 2022-08-23 18:39:37 +02:00
giagitom
39f51bcc4f Integration of Dual depth peeling - OIT method 2022-08-23 17:09:53 +02:00
Adam Midlik
1b904ee2c9 Addressed PR comments 2022-08-23 17:03:32 +02:00
yakomaxa
e2baafc426 lint 2022-08-23 18:13:14 +09:00
yakomaxa
6dabe73002 Update pymol keywords and properties 2022-08-23 17:16:10 +09:00
David Sehnal
d9b2b99c86 Merge pull request #531 from molstar/safari-wboit
add missing depth renderbuffer to wboit pass
2022-08-23 09:40:27 +02:00
Alexander Rose
bdf23a7c4e add missing depth renderbuffer to wboit pass
- fix wboit in Safari >=15
2022-08-22 23:39:50 -07:00
yakomaxa
c1723e0806 lint 2022-08-21 21:59:10 +09:00
yakomaxa
93590bd482 Remove comment line in vmd keyword 2022-08-21 21:54:38 +09:00
yakomaxa
fbaa9d9e58 Finally enabled selection by negative-valued residue index in RasMol 2022-08-21 21:48:47 +09:00
yakomaxa
ba78a8558c Finally enabled selection by negative-valued residue index 2022-08-21 21:39:20 +09:00
yakomaxa
513be04352 lint PyMOL 2022-08-21 21:38:43 +09:00
yakomaxa
15317aa11b give pymol the ability to deal with negatively indexed residue numbering 2022-08-21 19:37:20 +09:00
yakomaxa
93e107f333 give pymol the ability to deal with negatively indexed residue numbering 2022-08-21 19:32:45 +09:00
yakomaxa
655b334b0a Updated rasmol parser and spec 2022-08-21 17:14:29 +09:00
yakomaxa
95cc1c58a6 remove comment and unused character and functions 2022-08-21 16:56:20 +09:00
yakomaxa
0511d3e599 Unparenthesized residue range enabled in RasMol and parenthesized was un-activated 2022-08-21 16:51:38 +09:00
yakomaxa
92a41b5c46 Unparenthesized residue range enabled in RasMol, which should be ported to Jmol 2022-08-21 16:48:41 +09:00
yakomaxa
be16837c8c Remove unused lines 2022-08-21 15:51:41 +09:00
yakomaxa
bf5f26cb12 Remove comment-out lines. Moved un-bracketed residue name to the supported feature 2022-08-21 15:44:09 +09:00
yakomaxa
ccbcef7eff lint 2022-08-21 15:33:49 +09:00
yakomaxa
d02a97b7f0 un-bracketed residue-name and un-parenthesized residue number is enabeled in RasMol 2022-08-21 15:31:48 +09:00
yakomaxa
e0ca413c54 Remove needless substitutions to a temporary variable x 2022-08-21 10:42:32 +09:00
yakomaxa
a272fc1c05 Remove comment-out lines 2022-08-21 10:39:44 +09:00
yakomaxa
2c3f74d4ea Remove a comment-out line 2022-08-21 10:38:40 +09:00
yakomaxa
c65b2fc0fd Remove a comment-out line 2022-08-21 10:37:25 +09:00
yakomaxa
fd725adf27 Added TODO comment for comment-out functions 2022-08-21 10:36:47 +09:00
yakomaxa
ceba6da91f Remove comment-out lines 2022-08-21 10:27:57 +09:00
yakomaxa
064e7d42ee Remove a comment-out import 2022-08-21 10:26:56 +09:00
yakomaxa
cfdbf0c614 Remove comment-out lines 2022-08-21 10:25:33 +09:00
yakomaxa
436777fe34 Remove a comment-out import and a comment-out piece of code 2022-08-21 10:22:45 +09:00
yakomaxa
f08aa46222 Remove two comment-out import 2022-08-21 10:20:58 +09:00
yakomaxa
e099ac514a Remove three comment-out console.log 2022-08-21 10:19:56 +09:00
yakomaxa
873755f619 Remove comment-out unused import 2022-08-21 10:18:49 +09:00
yakomaxa
2094b7cf83 Update changelog mentioning this feature 2022-08-21 10:16:49 +09:00
yakomaxa
6ffdd81bb1 remove commented console.log 2022-08-21 10:14:32 +09:00
yakomaxa
a69cb17602 remove default paramerter and added whitespace before } 2022-08-21 10:12:56 +09:00
yakomaxa
7c82a9fd6e update transpile.ts 2022-08-21 10:11:59 +09:00
yakomaxa
10d9a6c83d removed console.log in try and replaced it by console.error in catch 2022-08-21 10:01:56 +09:00
Alexander Rose
e474e9b090 3.14.0 2022-08-20 16:43:16 -07:00
Alexander Rose
837f9a6c74 changelog 2022-08-20 16:37:46 -07:00
Alexander Rose
c357aed7bb schema updates 2022-08-20 16:36:48 -07:00
Alexander Rose
59ffddfd8d update packages 2022-08-20 16:33:17 -07:00
Alexander Rose
fb3accaa36 Merge pull request #528 from molstar/safari-surf-fix
wrap gl_VertexID in int()
2022-08-20 15:45:14 -07:00
Alexander Rose
b3e79544ad Merge branch 'master' into safari-surf-fix 2022-08-20 15:44:30 -07:00
Alexander Rose
2ee0f3bf97 Merge pull request #515 from molstar/background-pass
Background pass
2022-08-20 15:41:32 -07:00
Alexander Rose
a56b5edc4e cleanup 2022-08-20 15:32:01 -07:00
Alexander Rose
f2d71b6551 Merge branch 'master' into background-pass 2022-08-20 15:25:20 -07:00
Alexander Rose
ef560ddc03 Merge pull request #529 from molstar/webgl-state
Webgl state
2022-08-20 15:22:04 -07:00
Alexander Rose
2e30ffe1bc Merge branch 'master' into webgl-state 2022-08-20 15:21:54 -07:00
Alexander Rose
325b5e9297 Merge pull request #527 from molstar/custom-prop-fix
fix CustomElementProperty coloring
2022-08-20 15:21:01 -07:00
Alexander Rose
ae9e04b8d4 reduce number of webgl state changes
- add viewport and scissor to state object
- add hasOpaque to scene object
2022-08-20 12:04:51 -07:00
Alexander Rose
ab0010122b handle renderable rendering edge cases
- fix text background rendering for opaque text
- fix helper scenes not shown when rendering directly to draw target
2022-08-20 12:04:04 -07:00
Alexander Rose
08d736ecdc image loading error handling and other tweaks 2022-08-20 11:54:51 -07:00
Alexander Rose
9c362c8ffd Merge branch 'master' of https://github.com/molstar/molstar into background-pass 2022-08-20 11:07:57 -07:00
Alexander Rose
62c8778560 Merge pull request #513 from molstar/inter-bonds-props
expose inter-bonds props & improve performance
2022-08-20 11:06:04 -07:00
Alexander Rose
2fe0665e12 simplify box3d functions 2022-08-20 10:57:40 -07:00
Alexander Rose
14a957f517 Merge branch 'master' of https://github.com/molstar/molstar into inter-bonds-props 2022-08-20 10:56:14 -07:00
Alexander Rose
087010d0a1 Merge pull request #525 from molstar/pairBonds-maxDistance
set some IndexPairBonds maxDistance to Infinity
2022-08-20 10:54:12 -07:00
Alexander Rose
f92657310a Merge branch 'master' into pairBonds-maxDistance 2022-08-20 10:54:03 -07:00
Alexander Rose
19e91400b5 fix CustomElementProperty coloring
- can't check data availabilty in isApplicable because it is obtained on demand
2022-08-20 10:14:21 -07:00
Alexander Rose
7885fb7b4f wrap gl_VertexID in int()
-fix GPU surfaces rendering in Safari with WebGL2
2022-08-20 10:12:51 -07:00
Alexander Rose
331bec11ee cleanup comment 2022-08-20 10:08:47 -07:00
Adam Midlik
f6ed650ef6 Refactoring, cleaning 2022-08-19 15:17:50 +02:00
Adam Midlik
df9ce6add9 Volume Streaming Around Camera - parameter Radius is relative to FOV 2022-08-19 12:42:10 +02:00
Adam Midlik
28ee47d501 Volume Streaming Around Camera - avoid chain-reaction updates 2022-08-19 11:29:52 +02:00
Adam Midlik
df2da479ad Volume Streaming - corrected help text for Detail Level (range is 1-7) 2022-08-19 10:23:00 +02:00
Adam Midlik
46eb9d8baf Volume Streaming - correct init value of Selection Detail and Dynamic Detail when View type changes 2022-08-19 10:21:08 +02:00
Adam Midlik
b6be871a21 Volume Streaming all types use MonoQueue 2022-08-18 23:28:11 +02:00
Adam Midlik
ce2367fc0a Volume streaming Around Focus uses MonoQueue (i.e. never queuing more than 1 update) 2022-08-18 19:27:53 +02:00
dsehnal
f219cd6c8b prefer webgl1 in Safari 16 2022-08-18 17:39:18 +02:00
yakomaxa
7789e8cfea deleted package-lock.json 2022-08-18 19:58:30 +09:00
Alexander Rose
e697624064 prefer WebGL1 for more Safari versions
-avoid broken GPU surfaces rendering
2022-08-17 22:08:17 -07:00
Alexander Rose
92ffdeb5bf don't include glycam names in default saccharides 2022-08-17 21:57:55 -07:00
Alexander Rose
ddefe7e542 package updates 2022-08-17 21:50:54 -07:00
Alexander Rose
fb4019c041 changelog 2022-08-17 21:39:14 -07:00
Alexander Rose
46026e047e set some IndexPairBonds maxDistance to Infinity
- for MOL/SDF and MOL2 (without symmetry) models
- avoid filtering by element-based rules
2022-08-17 21:38:06 -07:00
yakomaxa
51a9effcaa Added a sentence on transpilers in CHANGELOG.md 2022-08-17 12:07:12 +09:00
yakomaxa
fc3b953a8e Added whitespace remover to prefixRemoveKet in helper.ts and update rasmol.spec.ts 2022-08-17 11:55:45 +09:00
yakomaxa
a2ded3cecc Small update for RasMol parser 2022-08-17 10:28:39 +09:00
yakomaxa
ffb1390b51 added conditional evalation to inComplement 2022-08-17 10:15:18 +09:00
yakomaxa
3b92591c05 added conditional evaluation to disjunct and invert 2022-08-17 10:08:15 +09:00
yakomaxa
f173ddcf00 removed comment-out lines from rasmol parser.ts 2022-08-16 22:50:35 +09:00
yakomaxa
f78306f624 removed unused abbr. from rasmol operators.ts 2022-08-16 22:41:18 +09:00
yakomaxa
9852c9301e Changed list name in respective examples.ts and now examples.spec.ts runs without error 2022-08-16 20:07:44 +09:00
yakomaxa
2e4f3de604 debugging example.spec.ts 2022-08-16 19:47:11 +09:00
yakomaxa
300dd97353 Added spec, debugged Jmol parser, removed unused definition from RasMol properties/operators 2022-08-16 19:34:13 +09:00
yakomaxa
8e29ade83a minor change of language name: Rasmol -> RasMol 2022-08-16 16:52:34 +09:00
Alexander Rose
971c770f6a add experimental warning for transpiled scripts 2022-08-15 22:03:24 -07:00
Alexander Rose
0dfad5a757 imporve labels of skybox params 2022-08-15 20:55:45 -07:00
Alexander Rose
a0495f8aae fix SSAO renderable initialization 2022-08-15 20:55:27 -07:00
yakomaxa
7d31a06ae4 Updated atom-set.ts according to suggestion by dsehnal 2022-08-16 12:50:02 +09:00
KoyaS
c5319ad7b1 Update package.json
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:38:31 +09:00
KoyaS
f8bdb28ea6 Update package.json
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:38:18 +09:00
KoyaS
2f8806d7c2 Update src/mol-script/runtime/query/table.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:37:55 +09:00
KoyaS
7d0a181c12 Update src/mol-model/structure/query/queries/atom-set.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:37:46 +09:00
KoyaS
27cb7e53ed Update src/mol-script/runtime/query/table.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:37:36 +09:00
KoyaS
ee5154b510 Update src/mol-script/runtime/query/table.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:37:20 +09:00
KoyaS
080837201a Update src/mol-script/runtime/query/table.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:36:44 +09:00
KoyaS
656e6c0d94 Update src/mol-script/runtime/query/table.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:36:17 +09:00
KoyaS
b018f61bab Update src/mol-script/runtime/query/table.ts
conditional evaluation

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-08-16 12:35:37 +09:00
yakomaxa
b03b306848 Enabling some numerical properties and cleaning by lint 2022-08-16 06:17:58 +09:00
yakomaxa
19bf5c2b3e [SER]3:A.CA type of selection enabled 2022-08-16 05:27:30 +09:00
yakomaxa
c22a716cf9 Update helper.ts for RasMol 2022-08-16 04:35:26 +09:00
yakomaxa
220c65da92 Parentheses re-enabled in RasMol 2022-08-16 04:27:17 +09:00
yakomaxa
675f4b86f8 Minor update of RasMol mode 2022-08-16 04:18:00 +09:00
yakomaxa
d31b3522b2 Added myself as author in package.json. Thanks. 2022-08-15 21:12:22 +09:00
yakomaxa
4ed2bab1d7 cleaning by lint 2022-08-15 20:56:20 +09:00
yakomaxa
a572872806 Updated author information and removed notes 2022-08-15 20:53:47 +09:00
yakomaxa
e3ca23db0b Remove needless setting of class members and added revised author information 2022-08-15 20:24:23 +09:00
KoyaS
67eb16a53f Merge pull request #18 from yakomaxa/rasmol
Merge from RasMol branch and begin answering the reviewers
2022-08-15 20:12:23 +09:00
yakomaxa
d7421cd1a3 Removed unwanted file 2022-08-15 20:00:48 +09:00
yakomaxa
c2e68ced66 cleaning by lint 2022-08-15 19:39:54 +09:00
yakomaxa
10cf0db050 Within operator was implemented in RasMol 2022-08-15 19:38:14 +09:00
yakomaxa
08f1a1dcfe Added experimental within to rasmol 2022-08-15 18:03:16 +09:00
yakomaxa
11bf352295 Added experimental within to rasmol 2022-08-15 15:39:57 +09:00
yakomaxa
5fd560b30a Added experimental within to rasmol 2022-08-15 15:38:38 +09:00
KoyaS
e6d01ca246 Merge pull request #17 from yakomaxa/molql_integration_PR
Molql integration pr
2022-08-15 13:03:55 +09:00
Alexander Rose
1610f05b83 Merge branch 'master' of https://github.com/molstar/molstar into inter-bonds-props 2022-08-14 16:28:21 -07:00
Alexander Rose
8202b75cda Merge branch 'master' of https://github.com/molstar/molstar into background-pass 2022-08-14 16:26:47 -07:00
Alexander Rose
4904bae5a6 background pass improvements
- add PluginConfig.Background.Styles
- file support, asset management
- opacity, saturation, lightness controls for skybox/image
- coverage controls for image/gradient
- add backgrounds extension with examples
- image handling for build/watch (webpack, cpx)
2022-08-14 16:24:28 -07:00
Alexander Rose
04c06db02c Merge pull request #519 from MadCatX/gzip_files
Allow download of Gzipped files
2022-08-14 14:52:10 -07:00
Alexander Rose
0ddf2fa00d typing tweaks 2022-08-14 14:37:30 -07:00
Alexander Rose
8776143ec2 revert to mol-script in StructureSelectionFromScript 2022-08-14 14:07:39 -07:00
Alexander Rose
080c8e7af3 add basic scipt language selector 2022-08-14 14:06:12 -07:00
Michal Malý
a96f94b676 Allow download of Gzipped files 2022-08-14 17:11:35 +02:00
yakomaxa
64998e762b cleaning by lint and adding comments 2022-08-14 11:15:50 +09:00
yakomaxa
b508da5ccc cleaning by lint 2022-08-14 11:06:24 +09:00
KoyaS
84a492655a Merge pull request #16 from yakomaxa/molql_integration_PR
Molql integration pr
2022-08-14 10:57:07 +09:00
yakomaxa
9b9cfe4138 rasmol -> pymol 2022-08-14 10:55:11 +09:00
yakomaxa
f362a7086a rasmol update 2022-08-14 10:54:31 +09:00
KoyaS
9e9ec57a5f Merge pull request #14 from yakomaxa/rasmol
merge from rasmol branch
2022-08-14 04:09:15 +09:00
yakomaxa
da6a153985 Construction of rasmol selection command has nearly finished 2022-08-14 04:03:48 +09:00
yakomaxa
b4bde3f510 Rasmol parser WIP 5 2022-08-14 03:31:08 +09:00
yakomaxa
8a5cebd635 Rasmol parser WIP 4 2022-08-14 03:23:54 +09:00
Alexander Rose
ebdfc694c2 Merge pull request #520 from MadCatX/clean_up_pyramids
Change the lookup logic of NtC steps from residues
2022-08-13 11:19:30 -07:00
yakomaxa
ddf2733d3c Rasmol parser WIP 3 2022-08-14 00:36:37 +09:00
yakomaxa
cf65bfbcd0 Rasmol parser WIP 2 2022-08-13 23:03:26 +09:00
yakomaxa
03cce830bc Rasmol parser WIP 2022-08-13 21:43:05 +09:00
yakomaxa
913cf4c3e9 developing rasmol residue-range selector WIP 2022-08-13 12:44:14 +09:00
yakomaxa
2ccce0beaf developing rasmol residue-range selector WIP 2022-08-13 12:43:07 +09:00
yakomaxa
52239f71cd refined rasmol keywords 2022-08-13 11:20:41 +09:00
KoyaS
d9265af2e8 Merge pull request #13 from yakomaxa/molql_integration_PR
Added transpilers/_spec and checked that they pass the test
2022-08-13 08:57:48 +09:00
yakomaxa
5877f6a627 Added transpilers/_spec and checked that they pass the test 2022-08-13 02:43:54 +09:00
Michal Malý
7f29340797 Change the lookup logic of NtC steps from residues 2022-08-12 15:29:26 +02:00
KoyaS
e3e982c051 Merge pull request #11 from yakomaxa/molql_integration_PR
merge from molql_integration_PR
2022-08-12 18:07:23 +09:00
yakomaxa
17f09ff3de Cleaning and lint 2022-08-12 18:00:45 +09:00
yakomaxa
7a73416c03 Cleaning and lint 2022-08-12 17:44:29 +09:00
yakomaxa
0f799d44ad Found a bug in withSameAtomProperties in filter.ts, where propSet and currentProps are placed inversely in isSuperSet() 2022-08-12 16:08:42 +09:00
yakomaxa
24ebd44f87 remove namedAtomProperty from vmd/parser.ts, removed as any from definition of withSameAtomProperties, un-commented out the continue line in filter.ts 2022-08-12 10:06:44 +09:00
KoyaS
572b10e655 Merge pull request #9 from yakomaxa/molql_integration_PR
merge from molql_integration_pr branch
2022-08-12 07:11:15 +09:00
yakomaxa
60361c176b Updated pick function in filter.ts. This enebles VMD keywords like backbone and many more. 2022-08-12 06:29:13 +09:00
yakomaxa
b232a2c58f Updated atom-set.ts and filter.ts, which leads to correct behavior of inorganic in PyMOL. The bound_to operator was found to behave differently from original PyMOL even in MolQL implementation: it's just mistake in logic. 2022-08-12 06:19:20 +09:00
yakomaxa
2a44ac56fb cleaning by lint 2022-08-12 01:18:56 +09:00
yakomaxa
d0340a3257 The function called by filter.withSameAtomProperties is debugged and almost everything works fine now. 2022-08-11 23:54:57 +09:00
yakomaxa
e708a53ddb atom-set.ts table.ts updates 2022-08-11 22:11:15 +09:00
yakomaxa
23cdd70198 updated atomCount and many problem solved 2022-08-11 21:20:55 +09:00
yakomaxa
ba4bc30a78 remove trash file 2022-08-11 14:28:31 +09:00
yakomaxa
e516ea146d Update for atomCount and countQuery in table.ts 2022-08-11 14:26:10 +09:00
yakomaxa
61af638fe4 Update atom-set 2022-08-11 13:59:56 +09:00
yakomaxa
7a0af4142f Now PyMOL within operator works. The key was to replace xs['max-radius'] -> xs['max-radius'](ctx) in table.ts 2022-08-11 10:52:56 +09:00
yakomaxa
1aa8d596a3 Updates for queryInSelection in src/mol-script/runtime/query/table.ts was reverted (made bug) 2022-08-11 10:30:09 +09:00
yakomaxa
a457810623 queryInSelection in src/mol-script/runtime/query/table.ts was updated 2022-08-11 10:18:16 +09:00
yakomaxa
4bccb7ab84 VMD jmol rasmol parser debugged 2022-08-11 09:46:15 +09:00
yakomaxa
fcd5b2ce0a VMD parser debugged 2022-08-11 09:36:32 +09:00
yakomaxa
57a1184a16 VMD parser updated, now math function to value comparison enabled 2022-08-11 09:22:37 +09:00
Adam Midlik
ef176efed8 Volume streaming 'Around Camera' - prototype 2022-08-11 01:39:22 +02:00
yakomaxa
9943e0317d VMD jmol and rasmol parser updated 2022-08-11 08:39:21 +09:00
yakomaxa
ae11c1c904 VMD keyword update 2022-08-11 03:33:28 +09:00
yakomaxa
f937e069ca Clearning by Lint 2022-08-11 02:41:43 +09:00
yakomaxa
c9326da47b Implemented subset of atomSet: atomCount, queryCount and propertySet, which enables some of PyMOL operators. Implementation should be reviewed as byring is not working, and inorganic working incorrectly 2022-08-11 02:32:45 +09:00
yakomaxa
4698c05f9c re-implementation of VMD's exwithin without using wihtin 2022-08-10 21:41:03 +09:00
yakomaxa
15fd2cd5a0 let transpile.ts show what the query is 2022-08-10 21:27:25 +09:00
yakomaxa
193eb11095 Set some operators that lacks corresponding implementation to isUnsupported : true 2022-08-10 16:34:35 +09:00
yakomaxa
59cc0096cd fixing typo in example of pymol operator: resname CA -> name CA 2022-08-10 16:28:51 +09:00
yakomaxa
6bd7390eb8 Debbuged asAtoms in helper.ts, which enables operation using this function such as byresidue and neighbor. In addition, min-spelling in neighbor operation fixed: neighbour -> neighbor 2022-08-10 16:21:06 +09:00
yakomaxa
eabeb18f34 pymol 2022-08-10 16:11:54 +09:00
yakomaxa
4b6f539ba3 debugging wrapValue in helper.ts : property.head -> property.head.name : This enables secondary structure selection for VMD via valuesTest in helper.ts 2022-08-09 22:22:08 +09:00
yakomaxa
ea55fc5f41 debugging VMD mode 2022-08-09 22:05:04 +09:00
yakomaxa
94787229a4 testLevel in helper.ts was debuged and now comes back in vmd/parser.ts 2022-08-09 19:24:34 +09:00
Alexander Rose
113d0b5141 add background pass
- skybox, image, horizontal/radial gradient
2022-08-07 13:27:06 -07:00
Alexander Rose
163285b0a9 cleanup 2022-08-07 13:20:52 -07:00
Alexander Rose
9f1cf5377a add sceneRadiusFactor param 2022-08-07 13:17:52 -07:00
Alexander Rose
c37636215b expose fov camera param 2022-08-07 13:14:57 -07:00
KoyaS
0cb162022c Merge pull request #6 from yakomaxa/enable_not_and
Enabled NOT operation
2022-08-07 17:45:45 +09:00
yakomaxa
5ff2ca311e structure-query.generator.query-in-selection was implemented: this enables NOT operation. In addition, tranpiler/helper.ts was fixed to use B.struct.generator.all() instead of B.struct.generator.atomGroups(). B.struct.generator.atomGroups() is not working for some reason, which was also met in the keyword 'all' in all of vmd/pymol/jmol parser.ts 2022-08-07 17:42:15 +09:00
KoyaS
44b8d452a8 Merge pull request #5 from yakomaxa/enable_not_and
structure-query.modifier.intersectby was implemented
2022-08-07 15:55:08 +09:00
yakomaxa
82ccb1ab23 structure-query.modifier.intersectBy was implemented: this enables AND operation 2022-08-07 15:51:06 +09:00
yakomaxa
feb8b94e30 modified _spec: I don't understand what these _spec things do 2022-08-07 10:19:03 +09:00
yakomaxa
5adc73e277 removed unsused modules from package.json 2022-08-07 10:18:41 +09:00
KoyaS
c4ac983fc7 Merge pull request #4 from molstar/master
merge from head repository
2022-08-07 08:40:03 +09:00
yakomaxa
5ba7ba3aac Cleaning before PR. Note that many tests fail. 2022-08-07 08:34:22 +09:00
yakomaxa
e879479b3d removed mock-extension for language selector and reverted src/mol-plugin-state/transforms/representation.ts to the original 2022-08-07 07:36:39 +09:00
yakomaxa
7b49463297 NamedAtomProperties was added to vmd parser 2022-08-07 06:16:29 +09:00
Alexander Rose
1f77b19ced changelog 2022-08-06 13:45:29 -07:00
Alexander Rose
9853ebf02f Merge pull request #507 from MadCatX/add_pyramid_labels
Add labels for Confal pyramids
2022-08-06 13:42:02 -07:00
Alexander Rose
6e13aa0bc9 expose inter-bonds props & improve performance 2022-08-06 13:31:10 -07:00
yakomaxa
66600c3373 deleted unused comment lines in monadic-parser.ts 2022-08-07 02:39:22 +09:00
yakomaxa
19401c4bc6 Activated RangeListProperty in vmd/parser.ts with hardcoded 'atom-test' line 2022-08-07 02:38:21 +09:00
yakomaxa
bfc8660c5e replaced structure. -> structure-query. in transpiler directory 2022-08-07 02:21:52 +09:00
yakomaxa
6a83dc56ba reverted vmd parser and properties to original 2022-08-07 02:12:21 +09:00
KoyaS
82df9d8cad Merge pull request #3 from yakomaxa/rasmol
Rasmol transpiler added
2022-08-05 23:47:28 +09:00
yakomaxa
dd30fef078 Added many properties and keywords for PyMOL and rasmol 2022-08-05 23:38:41 +09:00
yakomaxa
79feb5a1cc rasmol branch launched 2022-08-05 20:48:16 +09:00
yakomaxa
0665524b11 refined VMD: RangeListProperty in vmd/parser.ts is not working for unknown reasons, so it was substituted by NamedAtomProperties: This limits the selection like 'residue 10 to 50' and 'residue 10' 2022-08-05 20:36:32 +09:00
yakomaxa
d45367e840 Refining VMD parser and properties 2022-08-05 13:32:46 +09:00
Michal Malý
1b7f0e0f1e Add example mmCIF to allow testing of Confal pyramids 2022-08-04 10:09:50 +02:00
Michal Malý
18cb3360b5 Update changelog 2022-08-04 09:56:28 +02:00
yakomaxa
cb0d988efc Updated language-select/ui, refactored transpile.ts and monadic-parser.ts 2022-08-03 22:52:07 +09:00
yakomaxa
fc0c556967 updated default value for Script and added mock-up for language-selector 2022-08-03 21:31:53 +09:00
yakomaxa
00970164db Debugged all in jmol 2022-08-03 03:24:35 +09:00
yakomaxa
7c3d76e9fe Merge branch 'master' of github:yakomaxa/molstar_my 2022-08-03 02:50:43 +09:00
yakomaxa
190c1f9620 Added pymol, jmol and vmd alongside mol-script: pymol is now enabled 2022-08-03 02:49:52 +09:00
KoyaS
f532325147 Merge pull request #2 from yakomaxa/PyMOL
added all and polymer.protein to keywords of pymol
2022-08-02 13:25:09 +09:00
yakomaxa
278dcb8808 added all and polymer.protein to keywords of pymol 2022-08-02 13:10:42 +09:00
Michal Malý
6fec598b96 Add labels for Confal pyramids 2022-08-01 14:46:35 +02:00
KoyaS
309c25e10b Merge pull request #1 from yakomaxa/jmol
Added Jmol transpiler (not enabled)
2022-07-31 23:05:06 +09:00
yakomaxa
6df728ea3e added jmol transplier (not enabled) 2022-07-31 23:01:11 +09:00
yakomaxa
dcf4ef6d74 added jmol transpiler 2022-07-31 22:49:20 +09:00
yakomaxa
4de1369a5a added jmol transpiler 2022-07-31 22:46:58 +09:00
yakomaxa
2ccfdb1280 added _spec (not tested whether it works) 2022-07-31 21:58:43 +09:00
yakomaxa
9fbf800639 added _spec (not tested whether it works) 2022-07-31 21:58:09 +09:00
yakomaxa
577daf64df PyMOL mode was successfully enabled (though mol-script is disabled...) 2022-07-31 12:27:15 +09:00
yakomaxa
0b1943e9b3 Now it worksgit add src/mol-script/transpile.ts 2022-07-31 12:17:25 +09:00
yakomaxa
30bd2dd876 Compiles but not boot 2022-07-31 12:04:38 +09:00
yakomaxa
cecd4d4179 Compiles but not working again 2022-07-31 11:15:58 +09:00
yakomaxa
364baab18d Added transpile.ts and all.ts 2022-07-31 10:30:37 +09:00
yakomaxa
bb3d4d2171 Added default export 2022-07-31 10:00:36 +09:00
yakomaxa
2355faf899 compiles but not working 2022-07-31 01:54:27 +09:00
yakomaxa
858e0b24ff now with few errors 2022-07-31 00:03:22 +09:00
yakomaxa
f7d0ed3988 Added additional modules 2022-07-30 23:17:21 +09:00
David Sehnal
40096ecdfb Merge pull request #502 from giagitom/master 2022-07-27 10:05:35 +02:00
giagitom
43061b80b8 Deliver defaultAttribs to Passes constructor 2022-07-26 19:24:31 +02:00
Alexander Rose
aa3d657d42 3.13.0 2022-07-24 17:11:08 -07:00
Alexander Rose
b0ef385769 changelog 2022-07-24 17:05:47 -07:00
Alexander Rose
dcf24e6292 Merge pull request #496 from JonStargaryen/master
Download CCD from Configurable URL
2022-07-24 17:04:28 -07:00
Alexander Rose
2fdd77737c Merge pull request #499 from molstar/immediate-isolevel
enable immediateUpdate for iso level
2022-07-24 17:02:55 -07:00
Alexander Rose
31c98ef1ba package updates 2022-07-23 13:40:23 -07:00
Alexander Rose
ceeec2c13a enable immediateUpdate for iso level 2022-07-23 13:36:15 -07:00
Alexander Rose
cc82e0cff8 Merge pull request #498 from molstar/varying-group
Varying group
2022-07-23 13:19:10 -07:00
Alexander Rose
29fc6c59e9 support constant group in gpu mc 2022-07-23 13:18:16 -07:00
Alexander Rose
aa931fab7b add dVaryingGroup to avoid flat qualifier more 2022-07-23 13:06:35 -07:00
Alexander Rose
8e2585a5c0 add material annotation support for textures 2022-07-23 11:26:34 -07:00
Alexander Rose
c115047f74 handle principal axes of points in a plane 2022-07-23 11:06:01 -07:00
Alexander Rose
0ac58cb137 changelog 2022-07-23 11:02:01 -07:00
Alexander Rose
492e0977c3 Merge pull request #494 from giagitom/master
only update camera state if manualReset is off
2022-07-23 10:57:36 -07:00
JonStargaryen
e8a09e81f3 fix short arg names 2022-07-21 14:02:57 -07:00
JonStargaryen
4fcc2c6208 download CCD from configurable URL 2022-07-21 09:50:01 -07:00
giagitom
e3523dc5fe only update camera state if manualReset is off 2022-07-20 18:04:03 +02:00
dsehnal
acf6c31a36 3.12.1 2022-07-20 15:43:33 +02:00
dsehnal
339b2e696c PluginBehavior dispose logic 2022-07-20 15:40:30 +02:00
Alexander Rose
6417fd49d6 3.12.0 2022-07-17 16:28:26 -07:00
Alexander Rose
374fd4db65 changelog 2022-07-17 16:23:08 -07:00
Alexander Rose
0b70dd9e38 Merge pull request #487 from molstar/fix/struct_conn-parsing
struct_conn parsing fix
2022-07-17 16:20:45 -07:00
dsehnal
55b19a7922 changelog 2022-07-17 18:01:28 +02:00
dsehnal
beb1b2655e scan all entities when looking for struct_conn etries
- solves PDB loading issue
2022-07-17 17:58:57 +02:00
Alexander Rose
6a81e48c3a package updates 2022-07-16 13:20:19 -07:00
Alexander Rose
f9841dd3df improve CellPack's adjustStyle option
- disable colorMarker
- set component options
- enable marking w/o ghost
2022-07-16 13:02:04 -07:00
Alexander Rose
b563c773c1 avoid using flat qualifier in shaders
- causing slowdown
2022-07-16 13:01:33 -07:00
Alexander Rose
dcda649d9d add colorMarker option to Renderer
- disables the highlight and select marker at a shader level
- faster rendering of large scenes in some cases.
2022-07-16 12:58:49 -07:00
Alexander Rose
d6cfd23ae5 fix missing material annotation for some uniforms
- causing unnecessary uniform updates
2022-07-16 12:31:38 -07:00
Alexander Rose
b69f62c9a4 remove use of isnan in impostor shaders
- not needed and causing slowdown
2022-07-16 12:28:40 -07:00
Alexander Rose
582ee7d623 bind shared textures only once per pass 2022-07-16 12:27:16 -07:00
ludovic autin
9e69f5dcfa Merge branch 'master' of https://github.com/corredD/molstar-proto into forkdev
# Conflicts:
#	CHANGELOG.md
2022-07-05 08:51:25 -07:00
dsehnal
7c4202186d 3.11.0 2022-07-04 16:30:54 +02:00
dsehnal
7c56e4c09d fix unused import 2022-07-04 16:28:24 +02:00
dsehnal
b10b466c61 changelog 2022-07-04 16:25:23 +02:00
David Sehnal
80d1986c61 Merge pull request #474 from molstar/composable-superposition
coordinate system support for superposition
2022-07-04 16:24:45 +02:00
dsehnal
7f9e413604 coordinate system support for superposition 2022-07-04 16:23:51 +02:00
Alexander Rose
4dfbc3830f Merge pull request #466 from molstar/cellpack-tweaks
Cellpack tweaks
2022-07-03 14:18:26 -07:00
Alexander Rose
46cdefa9ee add adjustStyle option to LoadCellPackModel 2022-07-02 12:48:05 -07:00
Alexander Rose
f857ea6095 fix missing rename
- forceInstanceTheme -> instanceGranularity
2022-07-01 06:34:27 -07:00
Alexander Rose
994920f99f fix shader compilation
- support instance texture params for overpaint, substance, transparency
2022-06-29 22:28:10 -07:00
ludovic autin
409ed9ad67 Merge branch 'forkdev' of https://github.com/corredD/molstar-proto into forkdev
# Conflicts:
#	CHANGELOG.md
2022-06-28 08:11:29 -07:00
Alexander Rose
130d4096d5 Merge branch 'master' of https://github.com/molstar/molstar into cellpack-tweaks 2022-06-26 17:50:14 -07:00
Alexander Rose
d5659529d7 3.10.2 2022-06-26 17:34:46 -07:00
Alexander Rose
f6e06ab16e changelog 2022-06-26 17:29:48 -07:00
Alexander Rose
4245eaf1b2 improve use of gl_VertexID when possible 2022-06-26 17:29:21 -07:00
Alexander Rose
c41bd702e2 remove superfluous shader varying 2022-06-26 17:25:14 -07:00
Alexander Rose
3911145f87 Merge branch 'master' of https://github.com/molstar/molstar into cellpack-tweaks 2022-06-26 14:54:15 -07:00
Alexander Rose
350f5c4266 3.10.1 2022-06-26 14:17:31 -07:00
Alexander Rose
ed4056bc8b changelog 2022-06-26 14:04:20 -07:00
Alexander Rose
0d96fa21b7 schema updates 2022-06-26 14:03:09 -07:00
Alexander Rose
0ee8d33d36 package updates 2022-06-26 13:30:44 -07:00
Alexander Rose
64cedec12b fix groupCount updating TextureMesh-based visuals 2022-06-26 12:42:26 -07:00
Alexander Rose
a16eaca42e finalize instanceGranularity 2022-06-26 12:27:02 -07:00
dsehnal
366b3b1b75 3.10.0 2022-06-24 15:59:45 +02:00
dsehnal
33963c085a ShowTrajectoryControls option 2022-06-24 15:56:39 +02:00
Alexander Rose
f3b18ef518 fix & simplify lociApply for instanceGranularity 2022-06-20 22:33:24 -07:00
Alexander Rose
bca1b45fd4 tweak name
- useInstanceGranularity -> instanceGranularity
2022-06-20 22:00:21 -07:00
Alexander Rose
3448d5ef03 Merge branch 'master' of https://github.com/molstar/molstar into cellpack-tweaks 2022-06-20 21:23:32 -07:00
David Sehnal
0f5a6194ff Merge pull request #455 from molstar/support-glycam-names
Support glycam names
2022-06-20 13:37:16 +02:00
David Sehnal
9266faec59 Merge branch 'master' into support-glycam-names 2022-06-20 13:37:10 +02:00
Alexander Rose
94347c6dde cleanup app.ts (#450) 2022-06-19 19:38:43 -07:00
Alexander Rose
7a07701be0 3.9.1 2022-06-19 19:21:25 -07:00
Alexander Rose
42519a4f75 changelog 2022-06-19 19:16:15 -07:00
Alexander Rose
c898c16430 package updates 2022-06-19 19:15:06 -07:00
Alexander Rose
318863bd18 fix missing aromatic bond display
- simplify code to always show when aromatic
2022-06-19 19:05:58 -07:00
Alexander Rose
ce94760d02 fix missing uGroupCount update for visuals 2022-06-19 18:51:16 -07:00
Alexander Rose
99759b5282 add useInstanceGranularity option
- for marker, transparency, clipping, overpaint, substance data
- saves memory
2022-06-19 18:45:31 -07:00
dsehnal
d9d8562ed9 changelog 2022-06-13 19:52:44 +02:00
dsehnal
dee55ea874 support glycam names 2022-06-13 19:52:14 +02:00
dsehnal
da413cc9e6 added missing super.componentWillUnmount 2022-06-10 14:53:26 +02:00
David Sehnal
c72e93a13d Merge pull request #452 from simeonborko/sborko/screenshot-unmount
DownloadScreenshotControls: componentWillUnmount
2022-06-10 14:46:19 +02:00
Simeon Borko
21f910a3ca DownloadScreenshotControls: componentWillUnmount
This should solve the error:

Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
2022-06-10 10:04:31 +02:00
ludovic autin
06e78e19d0 Merge branch 'forkdev' of https://github.com/corredD/molstar-proto into forkdev 2022-05-31 09:55:03 -07:00
Alexander Rose
2c51edb4c2 changelog 2022-05-30 19:20:41 -07:00
Alexander Rose
da2c893721 Merge branch 'master' of https://github.com/molstar/molstar into cellpack-tweaks 2022-05-30 19:18:49 -07:00
Alexander Rose
e7ce693e50 3.9.0 2022-05-30 11:46:42 -07:00
Alexander Rose
29e8fe7904 fix types 2022-05-30 11:41:40 -07:00
Alexander Rose
baf3a6077e package updates 2022-05-30 11:32:05 -07:00
Alexander Rose
e030e7a32d changelog 2022-05-30 11:29:23 -07:00
Alexander Rose
125566ed75 only call renderBlendedTransparent when needed 2022-05-30 11:27:58 -07:00
Alexander Rose
c51cb67519 Merge pull request #447 from molstar/pick-drawbuffers
use drawbuffers for picking
2022-05-29 23:35:53 -07:00
Alexander Rose
57f086b530 Merge branch 'master' into pick-drawbuffers 2022-05-29 23:32:57 -07:00
Alexander Rose
d1e17785b8 Merge pull request #446 from molstar/webgl-timer
Webgl timing support
2022-05-29 23:32:29 -07:00
Alexander Rose
774328a1d8 Merge branch 'master' into webgl-timer 2022-05-29 23:31:13 -07:00
Alexander Rose
175a0f48fa lint fix 2022-05-29 23:30:36 -07:00
Alexander Rose
60b91ff032 Merge branch 'master' into pick-drawbuffers 2022-05-29 11:11:29 -07:00
David Sehnal
2b003bc5b0 Merge pull request #445 from aliaksei-chareshneu/fix_bad_axis_order
Add check that a data block contains volume data before parsing
2022-05-29 16:00:10 +02:00
David Sehnal
029a2fcab1 Merge branch 'master' into fix_bad_axis_order 2022-05-29 15:59:52 +02:00
Alexander Rose
aa47f7fe4a use instances to create dna/rna curves
- much less memory use (but can't show as single cartoon)
2022-05-28 19:49:56 -07:00
Alexander Rose
a828113d9b use drawbuffers for picking 2022-05-28 13:17:35 -07:00
Alexander Rose
ab4d509eda fix rendering volumes
- when wboit is switched off and postprocessing is enabled
2022-05-28 13:13:35 -07:00
Alexander Rose
1296f32fa8 tweak alpha-orbitals example 2022-05-28 11:54:33 -07:00
Alexander Rose
5aa1ec9876 add timing mode 2022-05-28 11:43:13 -07:00
Alexander Rose
f2cf1ab226 add support for GPU timer queries 2022-05-28 11:20:22 -07:00
Alexander Rose
2d34c2a40b fix Scene.clear not clearing primitives/volumes 2022-05-28 11:07:03 -07:00
Aliaksei
a7181e865c Skipping server data block
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-05-28 08:16:58 +02:00
Aliaksei
0a71b788b3 Apply suggestions from code review
fix bugs and optimizing the code related to iteration over data blocks

Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-05-27 18:22:00 +02:00
aliaksei-chareshneu
1ed3d84043 fix to skip block with header SERVER 2022-05-27 14:26:42 +02:00
aliaksei-chareshneu
f472b75d0d iterate over all blocks as even 0th can contain data 2022-05-27 13:53:08 +02:00
aliaksei-chareshneu
072a9d1ccd add name and email to header; add changelog entry 2022-05-27 12:19:51 +02:00
aliaksei-chareshneu
8e26d1be68 fix bad axis ordering bug 2022-05-27 10:34:48 +02:00
Alexander Rose
c5871e9025 3.8.2 2022-05-22 08:36:50 -07:00
Alexander Rose
f26911b358 changelog 2022-05-22 08:31:57 -07:00
Alexander Rose
3a595b80b5 package updates 2022-05-22 08:30:15 -07:00
Alexander Rose
45760ddd41 fix Scene.opacityAverage not handling xray shaded 2022-05-22 08:22:39 -07:00
Alexander Rose
447d068bf1 3.8.1 2022-05-14 11:59:03 -07:00
Alexander Rose
7e1642a4a3 changelog 2022-05-14 11:53:55 -07:00
Alexander Rose
7781267e78 package updates 2022-05-14 11:53:18 -07:00
Alexander Rose
f824fdcfed improve scene marker/opacity average calculation 2022-05-14 11:43:24 -07:00
Alexander Rose
79dd441967 Merge pull request #436 from JonStargaryen/master
Fix Polymer Chain Instance Coloring
2022-05-09 22:41:33 -07:00
Sebastian Bittrich
9dcf9c0785 CHANGELOG 2022-05-09 15:58:22 -07:00
Sebastian Bittrich
83569462c6 fix instance coloring 2022-05-09 15:53:26 -07:00
Alexander Rose
947e169c3a Merge pull request #434 from JonStargaryen/master
proposed fix for headless-gl issues
2022-05-06 22:29:40 -07:00
Sebastian Bittrich
e6b36c52d1 CHANGELOG 2022-05-06 09:11:40 -07:00
Sebastian Bittrich
7fed3b84fa Merge remote-tracking branch 'upstream/master' 2022-05-06 09:08:53 -07:00
Sebastian Bittrich
cbc941f193 simplify array uniform check 2022-05-06 09:08:22 -07:00
Alexander Rose
a7ef0fb85f add interesting pdb entry 2022-05-05 22:41:16 -07:00
Alexander Rose
d10c36eaf5 fix issues with marking camera/handle helper 2022-05-05 22:40:52 -07:00
Sebastian Bittrich
e4c3a66753 proposed fix for headless-gl issues 2022-05-04 11:50:42 -07:00
Alexander Rose
f58f2cdc90 3.8.0 2022-04-30 16:11:07 -07:00
Alexander Rose
8f2676e91e schema updates 2022-04-30 16:05:30 -07:00
Alexander Rose
89d397898e changelog 2022-04-30 15:24:26 -07:00
Alexander Rose
2dc32be9ee Merge pull request #427 from molstar/transparent-object-outline
Transparent object outline
2022-04-30 15:08:46 -07:00
Alexander Rose
769220bd82 Merge pull request #421 from molstar/color-theme-typing
better color theme typing
2022-04-30 15:06:06 -07:00
Alexander Rose
c75aa5dd52 improve transparency & outlines
- proper per-group transparency with wboit off
- fixed outlines with transparent backgound
2022-04-30 12:53:14 -07:00
Alexander Rose
88f1cfd8c4 fix ignoreLight for direct-volume with webgl1 2022-04-30 09:24:39 -07:00
Alexander Rose
108279c1aa add clearDepth & blendColor to WebGLState 2022-04-30 08:42:01 -07:00
Alexander Rose
8150490aac Merge branch 'master' of https://github.com/molstar/molstar into transparent-object-outline 2022-04-30 08:39:16 -07:00
Alexander Rose
9497aa6362 package updates 2022-04-30 08:38:07 -07:00
Alexander Rose
3769da48a1 handle building GridLookup3D with zero cell size 2022-04-29 20:18:40 -07:00
Alexander Rose
3c21fcd53a fix FormatRegistry.isApplicable
- was returning true for unregistered formats
2022-04-29 20:16:09 -07:00
Alexander Rose
102ef2795d handle outlines for per-group transparency
- fix allowTransparentBackfaces for per-group transparency
2022-04-23 23:02:11 -07:00
Alexander Rose
0befa253c2 add WebGLState.depthFunc 2022-04-23 20:07:41 -07:00
Alexander Rose
87189cee58 support outlines for transparent objects
- cleanup of renderer and draw pass
2022-04-23 15:19:01 -07:00
Alexander Rose
3284f13fc6 fix spec of emptyDepthTexture in Renderer 2022-04-23 15:17:20 -07:00
Alexander Rose
70d219b120 improve Renderer.renderPick typing 2022-04-23 15:13:38 -07:00
Alexander Rose
a5ed3a08ea add Scene.getOpacityAverage 2022-04-23 15:12:16 -07:00
Alexander Rose
3665e7e999 expose RenderTarget.depthRenderbuffer 2022-04-23 15:10:40 -07:00
Alexander Rose
9b583b23ae add Renderbuffer.detachFramebuffer 2022-04-23 15:10:16 -07:00
Alexander Rose
d602415e98 check if WEBGL_depth_texture is supported 2022-04-23 15:09:44 -07:00
Alexander Rose
2c49a423e2 type assertion 2022-04-21 19:47:13 -07:00
Alexander Rose
8a266e70c8 fix handling of struct_conf mmCIF field (#425) 2022-04-21 19:46:50 -07:00
Alexander Rose
0df3bcd65d document supported file formats 2022-04-19 17:43:33 -07:00
dsehnal
f5ecf5648e 3.7.0 2022-04-13 20:04:01 +02:00
dsehnal
821f82fc3f changelog 2022-04-13 20:01:04 +02:00
David Sehnal
92305fe628 Merge pull request #420 from molstar/transparentBackfaces
improve transparentBackfaces handling
2022-04-13 19:57:29 +02:00
David Sehnal
17fe57b8a5 Merge pull request #423 from jpattle/option-to-disable-drag-overlay
Added an option to disable the drag overlay
2022-04-13 16:31:21 +02:00
Jason Pattle
47433a51d3 Added an option to the components spec to allow disabling of the drag-and-drop overlap for Molstar that loads files into the viewer. By default the drag overlay is enabled, just as it was before 2022-04-13 15:00:03 +01:00
Alexander Rose
e090827ced Merge branch 'master' of https://github.com/molstar/molstar into transparentBackfaces 2022-04-10 13:20:22 -07:00
Alexander Rose
856e6a8b74 use ColorTypeLocation as default
- for backwards compatibility
- most used
2022-04-09 19:27:06 -07:00
Alexander Rose
a813b4d40e Merge branch 'master' of https://github.com/molstar/molstar into color-theme-typing 2022-04-09 16:53:17 -07:00
dsehnal
98afc27442 fix react typing 2022-04-09 21:24:14 +02:00
Alexander Rose
9d4f28a395 fix type deps 2022-04-09 11:36:17 -07:00
Alexander Rose
50266d9a56 package updates 2022-04-09 11:20:28 -07:00
Alexander Rose
602a532cf2 better color theme typing 2022-04-09 10:38:03 -07:00
Alexander Rose
b23d610c94 improve transparentBackfaces handling
- off: don't show (default)
- on: show with transparency
- opaque: show fully opaque
2022-04-09 10:17:41 -07:00
Alexander Rose
119c43d527 fix xrayShaded for texture-mesh geometries 2022-04-09 10:04:06 -07:00
Alexander Rose
124feeb790 color theme tweaks
- add optional grid property
- handle dColorType_direct for non direct-volume shaders
2022-04-09 09:57:31 -07:00
dsehnal
2c0e7e84da 3.6.2 2022-04-05 17:59:48 +02:00
dsehnal
0d1e105343 changelog 2022-04-05 17:57:14 +02:00
dsehnal
f040c89ab3 React 18 friendly useBehavior hook 2022-04-05 17:51:13 +02:00
David Sehnal
5e9d8298ef Merge pull request #415 from JonStargaryen/master
ModelServer Ligand Export: Fix Alternate Locations & Mismatching Atoms
2022-04-05 17:49:16 +02:00
Sebastian Bittrich
7766ca2793 CHANGELOG 2022-04-04 11:36:39 -07:00
Sebastian Bittrich
fb2f22f120 Merge remote-tracking branch 'upstream/master' 2022-04-04 11:33:01 -07:00
Sebastian Bittrich
146fed3504 CHANGELOG 2022-04-04 11:32:51 -07:00
Sebastian Bittrich
0b7a6e3375 cleanup 2022-04-04 10:55:44 -07:00
Sebastian Bittrich
f1fbdeaca0 handle missing atoms (ignore hydrogen, fail for heavy) 2022-04-04 10:49:40 -07:00
Sebastian Bittrich
ee7e37f6bc handle deuterated part 2 2022-04-04 09:45:42 -07:00
Sebastian Bittrich
861f665ab3 handle deuterated 2022-04-04 09:17:39 -07:00
dsehnal
456de23ad4 remove console.log 2022-04-03 14:45:41 +02:00
dsehnal
6d3578c17e fix alpha orbitals example 2022-04-03 14:08:31 +02:00
dsehnal
57da7267e2 3.6.1 2022-04-03 13:50:46 +02:00
dsehnal
578b764406 fix react 18 ui: use hooks for overlay components 2022-04-03 13:48:05 +02:00
dsehnal
f65a38a085 TransformControlBase fix 2022-04-03 13:00:09 +02:00
dsehnal
d187757bbc 3.6.0 2022-04-03 11:19:12 +02:00
dsehnal
df83b24cf4 changelog 2022-04-03 11:16:16 +02:00
dsehnal
8e31ce0f5b react 18 support 2022-04-03 11:15:47 +02:00
David Sehnal
4f69eb7963 Merge pull request #414 from molstar/lowercase-str-column
lowercase column schema
2022-04-03 10:53:08 +02:00
Alexander Rose
4b9009216b mmcif schema: use lowercase instead of uppercase 2022-04-02 22:49:57 -07:00
Alexander Rose
895076c837 Merge branch 'master' of https://github.com/molstar/molstar into lowercase-str-column 2022-04-02 16:31:15 -07:00
Alexander Rose
6e398ee64a gh action 2022-04-02 16:13:24 -07:00
Alexander Rose
c2177272b5 gh action 2022-04-02 16:07:32 -07:00
Alexander Rose
4877de5839 re-add gl support to gh action 2022-04-02 15:55:22 -07:00
Alexander Rose
3cb9d10126 fix shader tests & cleanup shader code 2022-04-02 15:52:39 -07:00
Alexander Rose
23c53cd9fb fix disable-wboit Viewer GET param 2022-04-02 15:42:33 -07:00
Alexander Rose
3471743a63 changelog 2022-04-02 15:26:25 -07:00
Alexander Rose
1b0b1809ef handle case-insensitve mmcif fields
- support upper/lower case transforms
- handle case transform for CifField to Column
2022-04-02 15:24:01 -07:00
dsehnal
0833cffead fix undefined value handling and update alised type 2022-04-02 21:48:15 +02:00
Alexander Rose
a0a8ae88b7 Merge branch 'master' of https://github.com/molstar/molstar into lowercase-str-column 2022-04-02 12:27:40 -07:00
David Sehnal
e415cbeca4 Merge pull request #413 from molstar/allowTransparentBackfaces
add allowTransparentBackfaces parameter
2022-04-02 21:00:43 +02:00
dsehnal
4c15c93381 lowercase column schema 2022-04-02 20:54:35 +02:00
Alexander Rose
bd19822112 add allowTransparentBackfaces parameter
- for mesh, spheres, cylinders, texture-mesh geometries
2022-04-01 19:18:24 -07:00
Sebastian Bittrich
b87beb4a6e better msg for UNL 2022-04-01 16:58:32 -07:00
Sebastian Bittrich
62a58facb2 better error msg for unknown components 2022-04-01 15:51:00 -07:00
Sebastian Bittrich
5fa8178df7 fix handling of alternate locations in ligand-encoder#_getAtoms 2022-04-01 11:47:59 -07:00
David Sehnal
d6043e7d1f Merge pull request #411 from JonStargaryen/master
fix volume streaming for entries with multiple contour lists
2022-04-01 13:35:57 +02:00
Sebastian Bittrich
8e432dfbb4 CHANGELOG 2022-03-30 09:27:40 -07:00
Sebastian Bittrich
324ab3744b fix volume streaming for entries with multiple contour lists 2022-03-30 09:19:36 -07:00
Alexander Rose
33ee4d0418 Merge pull request #409 from JonStargaryen/master
Fix unit mapping in bondedAtomicPairs MolScript query
2022-03-29 18:11:59 -07:00
Alexander Rose
cbb104ccba Merge branch 'master' into master 2022-03-29 18:11:37 -07:00
Alexander Rose
0bda5461ae Merge pull request #403 from molstar/pdb-conect
improve pdb parsing
2022-03-29 18:01:56 -07:00
Sebastian Bittrich
4096a03de1 CHANGELOG 2022-03-29 11:40:46 -07:00
Sebastian Bittrich
fbee5f83df fix mapping issues in bondedAtomicPairs 2022-03-29 11:34:53 -07:00
Alexander Rose
84a1b19850 improve Model.hasSecondaryStructure
- check ModelSecondaryStructure.Provider.isApplicable
2022-03-28 18:51:54 -07:00
Alexander Rose
1df5bd6d03 make use of PDB TER record 2022-03-28 18:47:00 -07:00
Alexander Rose
8bd4221a85 improve pdb parsing
- handle non unique atom and chain names
- fixes #156
2022-03-26 11:26:20 -07:00
Alexander Rose
4d97ccdfb3 improve bonds assignment of coarse grained models
- check for IndexPairBonds and exhaustive StructConn
2022-03-26 11:22:04 -07:00
Alexander Rose
ca5e57ddbf fix aromatic rings assignment 2022-03-26 11:17:46 -07:00
Alexander Rose
ed6511799b check model and coordinates element count 2022-03-26 11:15:19 -07:00
Alexander Rose
9b1223ec15 improve webgl error/type handling 2022-03-26 11:12:28 -07:00
Alexander Rose
97210ee67a avoid calculating actionItems for isDisabled check 2022-03-26 11:11:22 -07:00
David Sehnal
308d1003ad Merge pull request #401 from molstar/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-03-25 14:07:50 +01:00
dependabot[bot]
ce9e193958 Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-25 12:50:11 +00:00
dsehnal
2a83afa8c1 3.5.0 2022-03-25 13:49:33 +01:00
dsehnal
8891fa328b cif2bcif BCIF => CIF conversion support 2022-03-25 13:45:00 +01:00
David Sehnal
a23c06c456 Merge pull request #399 from MadCatX/dnatco-changeable-colors
Make Confal pyramids colors changeable
2022-03-22 13:25:32 +01:00
Michal Malý
34e87121e1 Make Confal pyramids colors changeable 2022-03-21 09:07:49 +01:00
Alexander Rose
6e5c20f442 improve surface bounding-sphere
- use exact max radius to expand structure/unit sphere
2022-03-19 12:21:55 -07:00
Alexander Rose
8ac3bec451 improve color-smoothing
- use padded box
2022-03-19 12:20:12 -07:00
Alexander Rose
5128d0f405 improve Sphere3D.expand & Box3D.fromSphere3D
- ensure extrema are within radius
- avoid degenerate box for low number of points
2022-03-19 12:19:39 -07:00
Alexander Rose
6ae2121391 guard against zero window.devicePixelRatio 2022-03-19 11:43:41 -07:00
David Sehnal
749e0c5a47 Merge pull request #396 from MadCatX/dnatco-off-by-one
DNATCO extension: Fix off-by-one error in element lookup
2022-03-17 09:21:11 +01:00
Michal Malý
7b55ef85e1 DNATCO extension: Fix missing Confal pyramids in some structures 2022-03-17 07:47:47 +01:00
Alexander Rose
23ec35d1f9 3.4.0 2022-03-13 13:12:32 -07:00
Alexander Rose
ff089c2b9f changelog 2022-03-13 12:50:44 -07:00
Alexander Rose
1ab088718a package updates 2022-03-13 12:49:03 -07:00
Alexander Rose
0cb2e5857a Merge pull request #393 from molstar/zenodo-import
Zenodo import
2022-03-13 12:19:04 -07:00
Alexander Rose
7c5ae5d7ee tweak guessElementSymbolString 2022-03-13 12:16:12 -07:00
Alexander Rose
6e2665d98d Merge branch 'master' of https://github.com/molstar/molstar into zenodo-import 2022-03-12 18:03:45 -08:00
Alexander Rose
b3b4692237 add top format support 2022-03-12 17:46:29 -08:00
Alexander Rose
55ff1d4999 add nctraj format support 2022-03-12 14:17:58 -08:00
Alexander Rose
511c839237 add prmtop format support 2022-03-12 13:48:10 -08:00
Alexander Rose
384cd6e5d9 add trr format support 2022-03-12 13:02:50 -08:00
Alexander Rose
6fd9dcc72e split structure formats into topology & coordinates 2022-03-12 11:51:03 -08:00
Alexander Rose
12ca06fe91 fix handling of empty symmetry cell data 2022-03-12 11:44:27 -08:00
Alexander Rose
652f6c651b fix wrong element assignment 2022-03-12 10:58:33 -08:00
Alexander Rose
7dd808a772 add custom import controls 2022-03-12 10:52:43 -08:00
Alexander Rose
945e55f8a7 add formated file size 2022-03-07 22:06:22 -08:00
Alexander Rose
866a30abe5 cleanup getFileInfo 2022-03-07 22:05:11 -08:00
Alexander Rose
f0e33e1e4e fix legend of hydrophobicity color theme 2022-03-07 21:44:57 -08:00
Alexander Rose
8723ca38b4 improve saccharide detection 2022-03-07 21:31:33 -08:00
Alexander Rose
efffca0026 zenode import fixes 2022-03-06 21:57:42 -08:00
Alexander Rose
6c5eb3035f remove default record id 2022-03-06 17:55:52 -08:00
Alexander Rose
0bf385f2ca add zip file support to zenodo extension 2022-03-06 17:37:39 -08:00
Alexander Rose
9d5f51f513 improve handling of compressed files
- fix loading of some compressed files within sessions
- ignore some hidden MACOSX files
2022-03-06 17:32:56 -08:00
Alexander Rose
a1448131d8 add Zenodo import extension 2022-03-06 11:12:21 -08:00
Alexander Rose
664cacc7ac add LoadTrajectory action 2022-03-06 11:11:16 -08:00
Alexander Rose
1aec37dd05 fix 2022-03-06 11:09:51 -08:00
Alexander Rose
3ff2c0840e Merge pull request #392 from molstar/assert-unreachable
make use of assertUnreachable
2022-03-06 11:06:04 -08:00
Alexander Rose
5ca3c3ac52 Update src/mol-script/language/parser.ts 2022-03-06 11:04:58 -08:00
Alexander Rose
714ee50965 Update src/mol-script/language/parser.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-03-06 11:03:33 -08:00
Alexander Rose
ae1df3c5aa Update src/mol-script/language/parser.ts
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-03-06 11:03:28 -08:00
Alexander Rose
28afb39550 make use of assertUnreachable 2022-03-05 10:18:40 -08:00
Alexander Rose
3466a8a024 Merge pull request #389 from molstar/cif-check-present
fix handling of mmcif with empty label_asym_id
2022-03-05 09:20:19 -08:00
Alexander Rose
90db3321f5 changelog
Co-authored-by: David Sehnal <dsehnal@users.noreply.github.com>
2022-03-05 09:20:04 -08:00
Alexander Rose
bf4e5ed7c2 normalize mmcif data 2022-03-04 22:47:14 -08:00
Alexander Rose
d3b2c20c26 normalize atom_site early 2022-03-03 18:31:54 -08:00
Alexander Rose
c3afabb4b1 spelling 2022-03-02 19:50:30 -08:00
Alexander Rose
18cc9790d1 fix handling of mmcif with empty label_asym_id 2022-03-02 19:17:31 -08:00
Alexander Rose
d5ed3aa674 3.3.1 2022-02-27 18:45:45 -08:00
Alexander Rose
cfb9c9acfe changelog 2022-02-27 18:40:48 -08:00
Alexander Rose
67feef0b1d add option to ignore ions for inter-unit bonds 2022-02-27 18:40:27 -08:00
Alexander Rose
e0192ab5aa fix issue with unit boundary reuse
- do at visual level instead
2022-02-27 18:03:41 -08:00
Alexander Rose
eae7c11c55 3.3.0 2022-02-27 13:03:01 -08:00
Alexander Rose
b8251e1ade changelog 2022-02-27 12:57:51 -08:00
Alexander Rose
2ff2b9f348 schema updates 2022-02-27 12:50:48 -08:00
Alexander Rose
164e3f3343 package updates 2022-02-27 12:47:45 -08:00
Alexander Rose
4901a1bd87 rename occlusion scaleFactor to resolutionScale 2022-02-27 12:16:37 -08:00
Alexander Rose
cd194cca65 Merge pull request #385 from molstar/traj-anim
Coordinate trajectory related improvements
2022-02-27 12:04:28 -08:00
Alexander Rose
1748efbc18 Merge branch 'master' of https://github.com/molstar/molstar into traj-anim 2022-02-27 12:03:54 -08:00
Alexander Rose
4d60b40403 fix interUnitBonds parent check 2022-02-27 12:02:36 -08:00
Alexander Rose
6e5a41879f Merge pull request #386 from molstar/improve-ao
Improve AO performance
2022-02-27 11:58:50 -08:00
Alexander Rose
c5f9eb54da set default occlusion scaleFactor to 1 2022-02-26 23:51:21 -08:00
Alexander Rose
aebbfeb061 add support for lower resolution AO
- downsample depth for AO
- add scaleFactor param
- full res for image/video
2022-02-26 22:23:52 -08:00
Alexander Rose
a0a5a6b578 add encoder spec
- mostly as example
2022-02-26 17:43:37 -08:00
Alexander Rose
6bdafb85d7 Check if marking passes are needed
- add Scene.getMarkerAverage
2022-02-26 13:30:05 -08:00
Alexander Rose
0dd7debf5d reuse occlusion in multi-sample pass 2022-02-26 13:02:53 -08:00
Alexander Rose
962b9ee7af Merge pull request #378 from molstar/ar-bonds
fix visuals for aromatic/delocalized bonds
2022-02-26 11:34:42 -08:00
Alexander Rose
15bcc5df88 Merge branch 'master' into ar-bonds 2022-02-26 11:26:29 -08:00
Alexander Rose
8495d834c8 add getTripletIndices & triplets to UnitResonance 2022-02-26 11:25:35 -08:00
Alexander Rose
7282399709 fix/improve canRemap handling in IntraUnitBonds 2022-02-26 10:56:32 -08:00
Alexander Rose
780bdd6e7e don't compute InterUnitBonds when parent ones empty 2022-02-26 10:53:54 -08:00
Alexander Rose
ad08e7c67f reuse unit boundary if it has not changed too much 2022-02-26 10:52:26 -08:00
Alexander Rose
ff089964ca improve line visuals in polymerAndLigand preset 2022-02-26 10:50:02 -08:00
Alexander Rose
990191529a reuse Model.CoarseGrained for coordinate trajectories 2022-02-26 10:48:05 -08:00
Alexander Rose
ce1bec12b4 fix mononucleotides detected as polymer components 2022-02-26 10:46:51 -08:00
Alexander Rose
703ea9af53 change line geometry default scaleFactor to 2
- 3 is too big after fixing line rendering
2022-02-26 10:45:51 -08:00
David Sehnal
df0227ae1e Merge pull request #383 from molstar/batch-highlights
Resolve marking in main render loop
2022-02-24 07:46:44 +01:00
dsehnal
486d12b6ac Fix multisample pass "forceOn" 2022-02-24 07:20:03 +01:00
dsehnal
9c18375ab4 typo 2022-02-23 23:34:09 +01:00
dsehnal
e1708aed68 dispose mark buffer 2022-02-23 19:09:40 +01:00
dsehnal
a42d778b84 changelog 2022-02-23 12:04:38 +01:00
dsehnal
7692b59c7c resolve marking in main render loop insread of eagerly 2022-02-23 11:59:29 +01:00
dsehnal
82de9b36b3 addRing check tweak 2022-02-22 16:02:11 +01:00
dsehnal
49b3c8f65f ring computation algorithm fixes 2022-02-22 13:16:32 +01:00
Alexander Rose
90ad32d936 add ring example PDB IDs 2022-02-21 13:48:43 -08:00
David Sehnal
2509e91f1a Merge pull request #381 from russellp17/disable-ts-config-for-sourceMappingURL
Disable ts config that leads to sourceMappingURL comment
2022-02-21 15:20:00 +01:00
David Sehnal
80dc2219e4 Merge pull request #380 from russellp17/allow-react-16-in-peer-dependency
Allow React ^16.14.0 as peer dependency
2022-02-21 15:10:33 +01:00
Russell Parker
931cb0fa7d Disable ts config that leads to sourceMappingURL comment in transpilation 2022-02-21 08:24:09 -05:00
Russell Parker
4383f2ea90 Allow React ^16.14.0 as peer dependency 2022-02-21 08:20:55 -05:00
dsehnal
add79dc242 ring computation algorithm fix 2022-02-21 14:15:13 +01:00
Alexander Rose
b6e142f04c move delocalizedTriplets code to unit.resonance 2022-02-20 16:28:42 -08:00
Alexander Rose
105f6c3041 fix visuals for aromatic/delocalized bonds 2022-02-20 12:50:44 -08:00
Alexander Rose
4babbb65c1 fix spec 2022-02-19 17:22:25 -08:00
Alexander Rose
878159f7ed fix texture warnings (#319)
- bind real texture to tDepth in renderer
- ensure textures are not empty; init as 1x1(x1)
2022-02-19 16:59:03 -08:00
Alexander Rose
c320386019 changelog 2022-02-19 14:23:37 -08:00
Alexander Rose
1e7a0159f0 Merge pull request #377 from JonStargaryen/master
parse contour-level from emdb v3 header files
2022-02-19 14:20:48 -08:00
JonStargaryen
bbf4f1d1d3 break early 2022-02-19 11:02:30 -08:00
Alexander Rose
8cd1c69c76 css tweaks, fixes #376 2022-02-19 10:46:06 -08:00
JonStargaryen
2372a878ac parse contour-level from emdb v3 header files 2022-02-19 09:12:20 -08:00
dsehnal
9bec644997 3.2.0 2022-02-17 19:24:55 +01:00
dsehnal
650d38dff8 Store IndexPairBonds as a dynamic property 2022-02-17 19:21:49 +01:00
David Sehnal
097277e397 Merge pull request #373 from JonStargaryen/master
Add TraceOnly option for Structure Superposition
2022-02-14 19:53:51 +01:00
Sebastian Bittrich
82a4d5eedf cleanup 2022-02-14 10:46:03 -08:00
Sebastian Bittrich
2a00248812 determine trace during buildIndex 2022-02-14 10:41:10 -08:00
Sebastian Bittrich
9841c773cb reset camera after all alignments 2022-02-10 13:55:09 -08:00
Sebastian Bittrich
b21a78ad14 support shuffled atoms when aligning SIFTS trace 2022-02-10 13:49:37 -08:00
Sebastian Bittrich
7329fa597d options obj for alignAndSuperposeWithSIFTSMapping 2022-02-10 11:36:50 -08:00
Sebastian Bittrich
f1d8f0ecb4 auth 2022-02-10 11:32:21 -08:00
Sebastian Bittrich
1d127f2364 changelog 2022-02-10 11:30:55 -08:00
Sebastian Bittrich
b244405cc3 polymer-based query 2022-02-10 10:39:22 -08:00
Sebastian Bittrich
38adfe0ca6 cleanup 2022-02-10 10:29:34 -08:00
Sebastian Bittrich
6f0d798847 optional filtering for trace during alignment 2022-02-10 10:23:31 -08:00
Sebastian Bittrich
6e58bfd2b0 traceOnly param for superpos 2022-02-08 16:03:05 -08:00
David Sehnal
bc2e8d8ac4 Merge pull request #369 from molstar/pdbx_sifts-export
Better support for atom_site.pdbx_sifts_xref
2022-02-08 10:19:02 +01:00
dsehnal
7be654d47f tweak labels 2022-02-08 10:18:01 +01:00
dsehnal
bfe46e3604 pdbx_sifts_xref PR feedback 2022-02-08 10:12:21 +01:00
dsehnal
008b597fc5 changelog 2022-02-07 17:51:13 +01:00
dsehnal
c4b4f2e3b1 rename BestDatabaseSequenceMapping -> SIFTSMapping 2022-02-07 17:49:10 +01:00
dsehnal
76ee97301b atom_site.pdbx_label_index support 2022-02-07 17:44:03 +01:00
dsehnal
289dc09eae add support for atom_site.pdbx_sifts_xref export 2022-02-07 17:33:11 +01:00
Alexander Rose
f23f84f0f3 3.1.0 2022-02-06 15:56:41 -08:00
Alexander Rose
62259f3295 changelog 2022-02-06 15:51:40 -08:00
Alexander Rose
854a430a12 tweak quick-styles order 2022-02-06 15:46:40 -08:00
Alexander Rose
d27cdb5637 schema updates 2022-02-06 15:41:09 -08:00
Alexander Rose
7d12d9ee90 package udpdates 2022-02-06 15:38:09 -08:00
Alexander Rose
d70a4ff347 Merge pull request #366 from molstar/repr-defaults-tweaks
cleaner default representation style
2022-02-06 15:24:27 -08:00
Alexander Rose
49541558d1 Merge branch 'master' into repr-defaults-tweaks 2022-02-06 15:24:16 -08:00
Alexander Rose
7b00a1227c changelog 2022-02-06 15:22:50 -08:00
Alexander Rose
7800603c81 Merge pull request #367 from molstar/quick-styles
Quick styles
2022-02-06 15:16:43 -08:00
Alexander Rose
fca00c8116 variable naming 2022-02-06 15:15:55 -08:00
Alexander Rose
00fa549e44 Merge pull request #368 from JonStargaryen/master
iterate over `structure.unitSymmetryGroups`, fixes #364
2022-02-06 15:13:57 -08:00
Alexander Rose
36181b6b87 tweak quick style names 2022-02-06 15:13:15 -08:00
JonStargaryen
88a95162e9 iterate over structure.unitSymmetryGroups, fixes #364 2022-02-06 10:47:40 -08:00
Alexander Rose
9c1d59a2c8 add Quick Styles panel 2022-02-05 12:58:32 -08:00
Alexander Rose
fdd894956a fix representation preset side effects 2022-02-05 12:56:55 -08:00
Alexander Rose
eb6dc0859d cleaner default representation style 2022-02-05 12:23:28 -08:00
Alexander Rose
b99026bba2 add ignoreLight to component params 2022-02-05 12:10:56 -08:00
Alexander Rose
6fa50eb8d5 fix xrayShader & ignoreLight not working together 2022-02-05 11:57:39 -08:00
David Sehnal
e5046f15a9 Merge pull request #365 from JonStargaryen/master
Volume Streaming Error Message
2022-02-04 17:11:31 +01:00
JonStargaryen
09f1c066a0 logic 2022-02-03 17:11:50 -08:00
Sebastian Bittrich
ed2f0b34c9 volume streaming err msg 2022-02-03 16:11:10 -08:00
Alexander Rose
c7f75861de 3.0.2 2022-01-30 12:24:48 -08:00
Alexander Rose
ccd04dbc9d changelog 2022-01-30 12:19:49 -08:00
Alexander Rose
e71f8d2c10 Merge pull request #360 from molstar/fix/visual-visibility
Fix visual visibility edge case
2022-01-30 12:17:12 -08:00
dsehnal
d9b4c60239 Fix visual visibility edge case 2022-01-30 15:02:46 +01:00
Alexander Rose
103c1fca21 measurement options tweaks
- allow larger text size
- make customText essential
2022-01-29 19:30:03 -08:00
Alexander Rose
49559bf5fb citation tweak 2022-01-29 16:05:17 -08:00
Alexander Rose
26dceabf83 add citation file 2022-01-29 15:56:39 -08:00
Alexander Rose
abe506182e fix multi-instance entity label display
- fix empty elements created in extendToAllInstances
2022-01-29 11:21:48 -08:00
Alexander Rose
582a0e2a38 fix Sphere.expand for highly directional extrema 2022-01-29 11:13:19 -08:00
dsehnal
2784ccf379 3.0.1 2022-01-27 12:15:53 +01:00
dsehnal
0ad1d578fe changelog 2022-01-27 12:13:22 +01:00
David Sehnal
31fd1c9c68 Merge pull request #353 from molstar/drag-tweak
emit drag event whenever started within viewport
2022-01-27 12:12:07 +01:00
David Sehnal
9c961297a2 Merge branch 'master' into drag-tweak 2022-01-27 12:11:59 +01:00
David Sehnal
b920053349 Merge pull request #352 from molstar/var-fixes
Various fixes
2022-01-27 12:09:39 +01:00
David Sehnal
0a5c764e4a Merge pull request #351 from molstar/volume-server-data-fix
Volume server data fix
2022-01-27 11:37:31 +01:00
Alexander Rose
b9a71c83ff emit drag event whenever started within viewport 2022-01-26 21:32:14 -08:00
Alexander Rose
3255f207d0 Merge branch 'master' of https://github.com/molstar/molstar into var-fixes 2022-01-26 20:46:11 -08:00
Alexander Rose
e3b4ca8862 add entity-id and entity-source as carbonColor 2022-01-26 20:42:38 -08:00
Alexander Rose
6810793015 fix marking of InteractionsInterUnitVisual 2022-01-26 20:40:12 -08:00
Alexander Rose
1feb3c2095 fix entity-id coloring broken for non-ihm models 2022-01-26 20:38:46 -08:00
Alexander Rose
f2da6033d0 fix pdbe xray maps url 2022-01-26 20:36:52 -08:00
Alexander Rose
28bc212132 fix marking pass for transparentBackground 2022-01-26 20:35:38 -08:00
dsehnal
1a7c62eec6 remove gl from dependencies & install it on demand instead
- installing gl on M1 Mac was taking several minutes to compile on each update
2022-01-26 23:12:12 +01:00
dsehnal
de67dbacba iso-value adjustment for VolumeServer data in default Viewer 2022-01-26 17:47:23 +01:00
dsehnal
57223a0f9a Fix VolumeServer/query CLI 2022-01-26 16:49:18 +01:00
Alexander Rose
2ad0754b90 3.0.0 2022-01-23 18:12:48 -08:00
Alexander Rose
3ecb3af57b changelog 2022-01-23 18:08:01 -08:00
Alexander Rose
ec4f15f549 improve/fix InteractionsIntraUnitVisual marking 2022-01-23 17:55:51 -08:00
Alexander Rose
2458ea7b92 Merge pull request #349 from molstar/custom-theme-colors
add custom theme colors
2022-01-23 15:13:24 -08:00
Alexander Rose
c5e6bedf11 Merge branch 'master' into custom-theme-colors 2022-01-23 13:54:57 -08:00
dsehnal
8528e5a666 Support/bugfixes for atom_site.pdbx_sifts_xref categories 2022-01-23 20:46:49 +01:00
dsehnal
6ed232b3d9 fix using default values for webgl1/wboit features in the default viewer app 2022-01-23 19:25:09 +01:00
dsehnal
f8aae8cbd1 skip Coarse models in export extension 2022-01-23 16:13:02 +01:00
Alexander Rose
00c2517045 package updates 2022-01-22 14:06:26 -08:00
Alexander Rose
99b043a929 avoid circular dependency 2022-01-22 11:10:41 -08:00
Alexander Rose
5900e27e39 add custom theme colors
- element-symbol
- molecule-type
- residue-name
- secondary-structure
2022-01-22 10:51:41 -08:00
Alexander Rose
1b79d34907 fix marking of carbohydrate visuals 2022-01-22 08:53:47 -08:00
Alexander Rose
fc52e29c92 re-add using _struct_asym cat in getStructAsymMap
- needed for ihm model support
2022-01-22 08:50:29 -08:00
Alexander Rose
df23b3c0fe fix coarse model support in entity-id color theme
- add StructureProperties.coarse.entity_id
2022-01-22 08:48:07 -08:00
David Sehnal
5e25716c98 Merge pull request #334 from molstar/export-extension
Model export extension & related improvements
2022-01-18 13:23:11 +01:00
dsehnal
f70a10bc56 add info about CIF export failure 2022-01-18 13:20:53 +01:00
dsehnal
0ccb045f4e Merge branch 'master' of https://github.com/molstar/molstar into export-extension 2022-01-18 12:30:45 +01:00
Alexander Rose
fa18d0d852 3.0.0-dev.10 2022-01-17 14:08:28 -08:00
Alexander Rose
687c4342fb changelog 2022-01-17 14:03:55 -08:00
Alexander Rose
9459af46b8 Merge pull request #337 from molstar/anim-rock
Add rock animation
2022-01-17 13:38:08 -08:00
Alexander Rose
fc5832747a Merge pull request #345 from molstar/bump-immutable
bump immutable to 4.0
2022-01-17 13:37:19 -08:00
Alexander Rose
01205d244b tweak trackball speed calc 2022-01-17 13:16:19 -08:00
dsehnal
31a555255a bump immutable to 4.0 2022-01-17 17:56:39 +01:00
dsehnal
fbb60c9493 Treat empty string as non-present value in BinaryCIF 2022-01-17 16:21:14 +01:00
dsehnal
9f953ef51c add Model Export overlay 2022-01-17 15:47:56 +01:00
dsehnal
4871f1547c Generate structAsymMap from normalized atomic hierarchy
- Fixes issue with remapped chains
- Requires to parse PRD separately
2022-01-17 14:52:53 +01:00
dsehnal
d6413529f4 PR feedback 2022-01-17 13:58:20 +01:00
dsehnal
724cf5a0da Add integrations section to readme 2022-01-17 12:58:35 +01:00
dsehnal
b6847907ca Add ModelExport to viewer/app.ts 2022-01-17 11:37:49 +01:00
dsehnal
fb54a1aed7 Merge branch 'master' of https://github.com/molstar/molstar into export-extension 2022-01-17 11:37:16 +01:00
Alexander Rose
9815318daf add entity-source option to illustrative coloring 2022-01-16 23:08:43 -08:00
Alexander Rose
bc13b98111 Merge branch 'master' of https://github.com/molstar/molstar into anim-rock 2022-01-16 15:48:33 -08:00
Alexander Rose
238b70c121 simplify rock state/trackball animation
- use sin() instead of smoothstep()
2022-01-16 15:47:25 -08:00
Alexander Rose
dcd23bc0cb improve illustrative style support
- add illustrative representation preset
- add style option to illustrative color theme
2022-01-16 13:13:00 -08:00
Alexander Rose
4694ea85fa support custom colors in molecule-type theme 2022-01-16 13:05:43 -08:00
Alexander Rose
bdb17743d7 update schemas 2022-01-15 19:54:22 -08:00
Alexander Rose
8b76ff2461 update packages 2022-01-15 19:53:04 -08:00
Alexander Rose
ea5421002b add camera rock state animation 2022-01-15 18:59:12 -08:00
Alexander Rose
76ac55917d type, tweaks 2022-01-15 18:45:56 -08:00
Alexander Rose
5cfb2376c4 Merge branch 'master' of https://github.com/molstar/molstar into anim-rock 2022-01-15 15:56:55 -08:00
Alexander Rose
6b9d3fd80e cleaner MembraneOrientationVisuals defaults 2022-01-15 13:52:14 -08:00
dsehnal
a09752b62e changelog and contibutors in package.json 2022-01-14 12:53:51 +01:00
David Sehnal
3134e1d9f9 Merge pull request #341 from molstar/fix-camera-spin-stutter
Pass animation info to state animations
2022-01-14 12:51:51 +01:00
David Sehnal
e94ecf2a0b Merge pull request #314 from ptourlas/feature/formal-charge-labels
Feature/formal charge labels
2022-01-14 12:51:09 +01:00
ptourlas
1bd4d841a1 ADD: Test multiple charge lines in molfiles 2022-01-12 17:01:36 +02:00
ptourlas
8e349f47a5 (author tags) 2022-01-12 16:50:06 +02:00
ptourlas
119c0a4231 ADD: Test formal charge parsing in sdf reader 2022-01-12 16:25:23 +02:00
ptourlas
f009f533e0 TWEAK: Default charges in V3000 sdf files 2022-01-12 15:05:07 +02:00
ptourlas
3ab0c1e509 ADD: Test formal charge parsing in mol reader 2022-01-12 12:42:29 +02:00
dsehnal
e3d264e239 Pass animation info to state animations
+ Fix camera stutter for "camera spin"
2022-01-11 19:38:32 +01:00
dsehnal
9bd60f8e8e Fix getOperatorsForIndex 2022-01-11 17:34:43 +01:00
ptourlas
bcec1d9637 (forgot to cleanup) 2022-01-11 16:41:23 +02:00
ptourlas
1b431b1d20 RFR: Formal charge assignment at model creation 2022-01-11 16:04:46 +02:00
ptourlas
23c2dcdfd4 FIX: Use tokenizer to ensure the loop terminates 2022-01-11 15:01:15 +02:00
ptourlas
dd415bf802 FTR: Support multiple formal charge lines
* Start with two empty arrays for indexes and charges.
* Each `M CHG` line is passed to `handleFormalCharges()` and the
parsed elements are pushed to the arrays.
* The `Column`s are made at the end of this process.
2022-01-11 14:40:57 +02:00
ptourlas
7bc0e9db7c RFR: formalChargeMapper tweaks
* The key is of type number, no need to stringify it.
* Simplified `switch()`.
2022-01-11 00:18:25 +02:00
ptourlas
ca10bb01db Merge branch 'molstar:master' into feature/formal-charge-labels 2022-01-10 23:46:37 +02:00
Alexander Rose
c0f14b7c33 3.0.0-dev.9 2022-01-09 18:24:30 -08:00
Alexander Rose
b096f328fc changelog 2022-01-09 18:19:52 -08:00
Alexander Rose
88dbd43884 re-allow interaction during trackball animation
- was disallowed as a stop-gap measure
- ok after improving temporal multi sampling
2022-01-09 14:39:09 -08:00
Alexander Rose
ade5e4d4b8 re-allow interaction during trackball animation
- was disallowed as a stop-gap measure
- ok after improving temporal multi sampling
2022-01-09 14:30:43 -08:00
ptourlas
cb76b53a1b FTR: Add formal charges during model creation
This implementation takes into account both the property and atom block
cases and makes sure the latter is ignored if the first one is present.
2022-01-10 00:30:25 +02:00
Alexander Rose
b9423f70d4 Merge branch 'master' of https://github.com/molstar/molstar into anim-rock 2022-01-09 14:25:36 -08:00
Alexander Rose
d61e18e6f3 fix mol2 element symbol assignment 2022-01-09 14:04:31 -08:00
Alexander Rose
ca4a725a79 Merge pull request #336 from molstar/bond-dist-id
IndexPairBonds improvements
2022-01-09 13:37:38 -08:00
Alexander Rose
17a18d5fea tweak bond assignment from IndexPairBonds
- fix & clarify logic
2022-01-09 13:25:14 -08:00
Alexander Rose
73be238ac4 rename IndexPairBonds mapping field from id to key 2022-01-09 12:51:26 -08:00
Alexander Rose
796a034fec add rock animation to trackball controls 2022-01-08 17:02:33 -08:00
Alexander Rose
952b320975 Merge branch 'master' of https://github.com/molstar/molstar into bond-dist-id 2022-01-08 13:23:15 -08:00
Alexander Rose
be0f06ff0f fix mol2 crysin support 2022-01-08 13:22:26 -08:00
Alexander Rose
6294ef2db2 fix stats for single element in multi-chain unit
- observe in, e.g., label for water molecule in 3pqr
2022-01-08 12:42:37 -08:00
Alexander Rose
78b5d505bd improve IndexPairBonds
- add id field
- better distance-based assignment
2022-01-08 12:35:40 -08:00
Alexander Rose
22afdffa15 add mol2 symmetry support
- only for spacegroup setting 1
2022-01-08 12:14:14 -08:00
Alexander Rose
d1056eddeb Merge pull request #335 from molstar/standalone-viewer
move Viewer class to separate file
2022-01-08 11:55:53 -08:00
dsehnal
8655f4d85a move viewer app to separate file 2022-01-08 10:31:53 +01:00
ptourlas
f9deb54352 FIX: Found the right tokenizer operations
(at last)
2022-01-08 01:16:59 +02:00
ptourlas
eae3c1b33a FIX: Formal charges are all on the same line
Therefore we have to get the count of charges and iterate based on that.
A handle properties function is added so that new handler can be used based
the property type. Note that this function only returns the charges at
the moment for simplicity. A more general version should return multiple
properties.
2022-01-07 16:14:47 +02:00
ptourlas
5c5f8aa741 FTR:(WIP) Add formal charges during model creation 2022-01-06 16:12:44 +02:00
ptourlas
ba68ac2e32 FTR: Parse formal charges in the atom block 2022-01-06 15:58:49 +02:00
ptourlas
239fef281e Merge branch 'master' into feature/formal-charge-labels 2022-01-06 13:32:05 +02:00
dsehnal
c0880b647f changelog 2022-01-03 13:51:09 +01:00
dsehnal
039dc6a76b changelog 2022-01-03 13:49:59 +01:00
dsehnal
042a7625ad isWithoutOperator tweak 2022-01-03 13:46:13 +01:00
dsehnal
41827c478d open zip files with multiple entries 2022-01-03 13:42:37 +01:00
dsehnal
9a73180c3c support transformed export & structAsymMap parsing fix 2022-01-03 13:15:51 +01:00
dsehnal
333ee85fdb omit suffix for identity assembly operators 2022-01-03 12:52:05 +01:00
dsehnal
fa8ca45b6a do not include assembly categories in export if an operator has been applied 2022-01-03 12:34:37 +01:00
dsehnal
c2bae1aeb7 model export extension 2022-01-03 12:26:36 +01:00
Alexander Rose
ada7a45fe6 add PDBj pdb-provider option 2022-01-01 16:56:23 -08:00
Alexander Rose
2d09df55a9 3.0.0-dev.8 2021-12-31 11:42:09 -08:00
Alexander Rose
ec2554537e changelog 2021-12-31 11:37:40 -08:00
Alexander Rose
f266dfadc6 emulate round function for webgl1 compatibility 2021-12-31 11:37:02 -08:00
Alexander Rose
99048eed61 Merge pull request #323 from molstar/dv-refactor
Direct-volume refactor
2021-12-31 10:43:26 -08:00
Alexander Rose
fe63718b0c Merge branch 'master' into dv-refactor 2021-12-31 10:34:50 -08:00
Alexander Rose
2c1200433c Merge pull request #333 from molstar/surface-size-theme
Use size theme in molecular/gaussian surface & label representations
2021-12-31 10:33:46 -08:00
Alexander Rose
4a3252c929 use size theme in label repr 2021-12-30 18:17:40 -08:00
Alexander Rose
5e052174ee use size theme in molecular/gaussian surface repr 2021-12-30 18:12:53 -08:00
Alexander Rose
cda0966105 filter repr size themes to applicable types 2021-12-30 18:01:02 -08:00
Alexander Rose
c0a9716846 Merge branch 'master' of https://github.com/molstar/molstar into dv-refactor 2021-12-30 17:30:44 -08:00
Alexander Rose
18c7395f9d Merge pull request #326 from molstar/marker-fixes
Marker improvements
2021-12-30 17:29:07 -08:00
Alexander Rose
d3da79f3dd better use of StateSelection API 2021-12-30 17:18:21 -08:00
Alexander Rose
5a215daca4 remove superfluous arg from canvas3d.requestDraw 2021-12-30 17:14:07 -08:00
Alexander Rose
8527a3b3ef change canvas3d draw to use options argument 2021-12-30 17:08:28 -08:00
Alexander Rose
492dc1ba32 Merge branch 'master' of https://github.com/molstar/molstar into marker-fixes 2021-12-30 17:04:17 -08:00
Alexander Rose
305a8ca802 Merge pull request #332 from molstar/fix-331
fix gpu isosurface group id
2021-12-30 17:02:54 -08:00
Alexander Rose
6d2a35494f rename float-packing to number-packing
- more telling name
2021-12-30 17:01:23 -08:00
Alexander Rose
e76a08c73a remove unused en/decodeFloatLog 2021-12-30 16:59:39 -08:00
Alexander Rose
a0fef0c20f rename en/decodeFloatRGB
- since they only work for positive integers
- encodeFloatRGB -> packIntToRGB
- decodeFloatRGB -> unpackRGBToInt
2021-12-30 16:57:50 -08:00
Alexander Rose
605432ddd1 fix glsl decodeFloatRGB 2021-12-30 16:39:06 -08:00
Alexander Rose
0c895071d8 support axis order in direct-volume shader 2021-12-30 15:36:12 -08:00
Alexander Rose
79cd833ae6 cleanup 2021-12-30 14:37:34 -08:00
Alexander Rose
0fee928e37 fix gpu isosurface group id
- was wrong for axis order other than 012
- fixes #331
2021-12-30 13:49:08 -08:00
Alexander Rose
7f698336d7 fix webgl error in volume-streaming behavior
- don't use gpu mc for small volumes
- return empty texture-mesh for volumes of size 1 or 0
2021-12-29 18:51:55 -08:00
Alexander Rose
cef04f192a no picking during camera spinning 2021-12-29 16:54:26 -08:00
Alexander Rose
4087c4c226 changelog 2021-12-29 16:27:43 -08:00
Alexander Rose
87bdcd2372 add prefer-webgl1 & disable-wboit Viewer GET params 2021-12-29 16:03:45 -08:00
Alexander Rose
1dbcc0d7c8 Merge branch 'master' of https://github.com/molstar/molstar into dv-refactor 2021-12-29 15:42:41 -08:00
Alexander Rose
4c93f01c64 improve temporal multi-smaple handling
- add forceOn arg
- instead of letting temporal converge do full sampling
- saves one geometry pass
2021-12-28 20:39:03 -08:00
Alexander Rose
0a18412da0 refactor draw/multiSample .render args 2021-12-28 20:24:16 -08:00
Alexander Rose
b67d16bdc4 enable marking pass by default 2021-12-28 19:47:54 -08:00
Alexander Rose
976542d355 ensure mark changes are rendered (even w/ noDraw)
- schedule using forceNextRender to avoid rendering twice
2021-12-28 19:30:45 -08:00
Alexander Rose
a2e5fda646 improve temporal multi-sample rendering
- don't render all when spinning
- only render all when explicitely requested (new allowMulti arg)
2021-12-28 19:28:36 -08:00
Alexander Rose
41b1b65d5f improve SelectLoci behavior
- only handle direct children of updated objects (no update of same repr multiple times)
2021-12-28 19:25:40 -08:00
Alexander Rose
2ec2d1997f improve StructureSelectionManager.onUpdate
- only process for root structure (processing childs is superfluous)
2021-12-28 19:20:54 -08:00
Alexander Rose
0bc65f3b72 improve visual marking performance
- treat structure-loci as every-loci
2021-12-28 19:17:46 -08:00
Alexander Rose
9ed96b3599 fix getMarkersAverage edge case with small arrays 2021-12-28 19:16:08 -08:00
David Sehnal
b1cf9566f6 Merge pull request #324 from molstar/safari15-wboit
PluginFeatureDetection and disable WBOIT in Safari
2021-12-28 20:46:46 +01:00
ptourlas
13ea97bd98 Merge branch 'master' into feature/formal-charge-labels 2021-12-27 18:18:27 +02:00
ptourlas
009a17a9ca (forgot the author tag) 2021-12-27 17:56:25 +02:00
ptourlas
ca38d9adb1 (WIP) Formal charges handler implementation 2021-12-27 17:44:59 +02:00
ptourlas
4e5a86e3db (WIP) Add the formal charges handler to sdf parser 2021-12-27 17:37:52 +02:00
dsehnal
983ae4f8c2 PluginFeatureDetection and disable WBOIT in Safari 2021-12-24 11:21:15 +01:00
Alexander Rose
7ce3531cc7 direct-volume define cleanup 2021-12-23 15:35:14 -08:00
Alexander Rose
11f1a7fd1c add general dGeometryType
- remove dRenderMode & dGeoTexture
2021-12-23 15:16:14 -08:00
Alexander Rose
47d7dd4d22 move direct-volume coloring into theme
- add 'direct' color type
- remove color from transfer-function (now only alpha)
- add direct-volume color theme support
- add volume-value color theme
2021-12-23 14:47:17 -08:00
Alexander Rose
0d4f6bb5d9 3.0.0-dev.7 2021-12-20 22:42:23 -08:00
Alexander Rose
b3a4e1976d changelog 2021-12-20 22:36:56 -08:00
Alexander Rose
8b3c0fd94e Merge branch 'master' of https://github.com/molstar/molstar into dv-refactor 2021-12-20 17:51:38 -08:00
Alexander Rose
ab4a24d8ab Merge pull request #310 from molstar/clipping
Per Object Clip Objects
2021-12-20 17:38:41 -08:00
Alexander Rose
7c93e9f834 changelog & fix clipping exclude group filtering 2021-12-20 17:22:15 -08:00
Alexander Rose
90ea8cfebd Merge branch 'master' of https://github.com/molstar/molstar into clipping 2021-12-20 16:49:58 -08:00
Alexander Rose
7fc1866dac Merge pull request #320 from molstar/shader-compilation
Shader compilation
2021-12-20 16:46:56 -08:00
Alexander Rose
bb520ff424 fix spec 2021-12-20 16:38:24 -08:00
Alexander Rose
f9d2e20cb9 webgl1 compat 2021-12-20 16:16:22 -08:00
Alexander Rose
6f13b67bf1 combine markingDepth/markingMask shader variants 2021-12-20 16:14:37 -08:00
Alexander Rose
f37026a980 Merge branch 'master' of https://github.com/molstar/molstar into shader-compilation 2021-12-20 14:15:06 -08:00
Alexander Rose
ddc4d8e867 3.0.0-dev.6 2021-12-19 13:15:50 -08:00
Alexander Rose
7cded03598 changelog 2021-12-19 13:11:41 -08:00
Alexander Rose
744b04edc6 add demos to deploy script
- include analytics in deployed demos
2021-12-19 13:06:41 -08:00
Alexander Rose
f2119b1d0b tweak alpha-orbitals example
- remove direct-volume option
- enable tryUseGpu for isosurface repr
2021-12-19 13:05:34 -08:00
Alexander Rose
b4783909d7 fix lighting example
- adjust to new light & material handling
2021-12-19 13:04:05 -08:00
Alexander Rose
fe5f841ab8 improve docking-viewer example
- add example pdbqt & mol2
2021-12-19 13:03:10 -08:00
Alexander Rose
2c3f0dbc97 fix missing uniform in direct-volume shader 2021-12-19 13:02:23 -08:00
Alexander Rose
224fd1733f improve aromatic bonds
- Don't detect aromatic bonds for rings < 5 atoms based on planarity
- Prefer atoms in aromatic rings as bond reference positions
2021-12-19 13:02:02 -08:00
Alexander Rose
1f262ee422 Merge pull request #321 from molstar/update-create-plugin
mol-plugin-ui/createPluginUI
2021-12-19 11:51:44 -08:00
Alexander Rose
df3bcdd05a fix embedded 2021-12-19 11:41:53 -08:00
dsehnal
d5d08542ed tweak 2021-12-19 17:36:32 +01:00
dsehnal
564a360c8f Added createPluginUI, removed createPlugin and createPluginAsync 2021-12-19 17:32:58 +01:00
Alexander Rose
74f123265b correctly set shader define flags
- overpaint, transparency, substance, clipping
2021-12-18 19:53:35 -08:00
Alexander Rose
ccfae65b01 fix tests 2021-12-18 19:29:02 -08:00
Alexander Rose
bcfaef77c9 combined pick shader variant 2021-12-18 18:11:31 -08:00
Alexander Rose
0b6243c0d1 remove log statement 2021-12-18 16:53:48 -08:00
Alexander Rose
472866d8ec support ignoring defines for shader variants 2021-12-18 16:48:56 -08:00
Alexander Rose
471163f3d8 better defaults for postprocessing pass 2021-12-18 16:44:08 -08:00
Alexander Rose
ab6106896d only include vPaletteV for color shaders 2021-12-18 16:43:48 -08:00
Alexander Rose
7ca624d04b remove dMarkerType shader define 2021-12-18 16:42:43 -08:00
Alexander Rose
bd3d18f43f use uniform for double-sided shader param 2021-12-18 16:39:15 -08:00
Alexander Rose
21eb21b6dd support variants for graphics render-itms 2021-12-18 16:32:20 -08:00
Alexander Rose
fe0d4dc11e warn (not throw) about erroneous symmetry matrix
- #303
2021-12-18 15:24:52 -08:00
Alexander Rose
812eb0efa9 Merge pull request #309 from molstar/ma-support
ModelArchive / AlphaFold support
2021-12-18 14:52:55 -08:00
Alexander Rose
10d0bf293a fix wrong method name loadAfdb 2021-12-18 14:41:38 -08:00
Alexander Rose
ce2544b9f3 add model-archive viewer helpers 2021-12-18 14:40:45 -08:00
Alexander Rose
1964de1e44 Merge branch 'master' of https://github.com/molstar/molstar into ma-support 2021-12-18 14:26:00 -08:00
Alexander Rose
20c9d2cc41 enable aromaticBonds by default 2021-12-18 14:22:21 -08:00
Alexander Rose
3b1513adc0 fix eslint warnings 2021-12-18 14:12:58 -08:00
Alexander Rose
eaa60fc5cd fix linting errors and vscode settings 2021-12-18 12:47:41 -08:00
Alexander Rose
ce1e3960a2 avoid standard polymers misqualified as ligands
- overrule erroneous chem comp type in some files
2021-12-18 12:13:36 -08:00
Alexander Rose
176f80ea9b ensure trace element for polymer residues 2021-12-18 12:09:17 -08:00
Alexander Rose
28c9dc8286 refactor Model.isFromPdbArchive
- split into isFromPdbArchive and hasPdbId
- improve when secondary structure is calculated
2021-12-18 10:45:59 -08:00
Alexander Rose
2135f76441 fix temporal multi-sample flicker, enable by default 2021-12-18 10:29:42 -08:00
Alexander Rose
5637a23153 fix unnecessary cartoon geometry recreation 2021-12-18 10:14:55 -08:00
dsehnal
2818389741 update label 2021-12-17 23:33:50 +01:00
ptourlas
a736fe7989 Add formal charge option to atom site 2021-12-15 00:35:34 +02:00
ptourlas
1970b7f249 Spot the formal charge prefix 2021-12-15 00:34:06 +02:00
Alexander Rose
694261c19c add ModelArchive to DownloadStructure action 2021-12-13 19:57:19 -08:00
Alexander Rose
24ad38e260 add clip support to components & focus repr 2021-12-12 18:09:26 -08:00
Alexander Rose
53bac83dff remove renderable.noClip 2021-12-12 17:59:09 -08:00
Alexander Rose
ab1578f667 move clip props to base geometry 2021-12-12 17:56:14 -08:00
Alexander Rose
4e70301b62 cleanup after merge 2021-12-12 17:27:47 -08:00
Alexander Rose
76ed2e9e11 Merge branch 'master' of https://github.com/molstar/molstar into clipping 2021-12-12 17:11:59 -08:00
Alexander Rose
58ce1f6498 Viewer.loadAfdb -> Viewer.loadAlphaFoldDb 2021-12-12 14:56:04 -08:00
Alexander Rose
47c4353eb9 use web api to get alphafold model for uniprot ac 2021-12-12 14:55:09 -08:00
Alexander Rose
d82cd3a8fe fix: do plugin ui render after context init 2021-12-12 14:45:57 -08:00
Alexander Rose
8f06b603e6 add bond location support to qmean & pLDDT color themes 2021-12-11 21:35:56 -08:00
Alexander Rose
0865c1b7fb changelog 2021-12-11 18:04:40 -08:00
Alexander Rose
c8c32b89c1 improve loading of ModelArchive schema structures
- includes AlphaFold mmcif structures
- add Viewer.loadAfdb
- add afdb GET param to Viewer html
- add Viewer default presets showing quality assessment (qmean & pLDDT)
- add alphafolddb option to download structure action
2021-12-11 17:56:26 -08:00
Alexander Rose
658c789906 tweak: use PD.arrayToOptions 2021-12-11 17:47:29 -08:00
Alexander Rose
c9ad7fce5b add PluginConfig.Structure.DefaultRepresentationPreset 2021-12-11 17:46:21 -08:00
Alexander Rose
720a8a440f tweak param comparision
- avoid unneccesary update
2021-12-11 17:42:41 -08:00
Alexander Rose
84fe2d2502 add ModelArchive extension
- QualityAssessment prop (from ma_qa_metric_local mmcif category)
- pLDDT & qmean coloring
- pLDDT & qmean repr presets
- pLDDT & qmean molql symbol
- pLDDT & qmean loci labels (including avg for mutli residue selections)
- pLDDT selection query
2021-12-11 17:40:04 -08:00
Alexander Rose
6f159c592f cleanup mmcif schema generation
- remove BRANCH and CARB extension (nwo included in mmCIF)
2021-12-11 16:57:09 -08:00
Alexander Rose
beff1ecb3e add model-archive cif schema 2021-12-11 16:40:29 -08:00
Alexander Rose
aa1f081664 remove direct-volume isosurface render-mode 2021-12-05 14:24:18 -08:00
ludovic autin
9a1d746170 Merge branch 'master' of https://github.com/molstar/molstar into forkdev 2021-11-17 10:06:49 -08:00
ludovic autin
ef87ce3507 Merge branch 'master' of https://github.com/molstar/molstar into forkdev 2021-11-10 14:35:24 -08:00
ludovic autin
2b9053eac4 Merge branch 'master' of https://github.com/molstar/molstar into forkdev 2021-11-01 10:21:08 -07:00
ludovic autin
116ef719be Merge branch 'master' of https://github.com/molstar/molstar into forkdev 2021-09-20 09:17:09 -07:00
Alexander Rose
504406eb22 move clip variant and objects to repr state 2021-08-01 21:16:44 -07:00
719 changed files with 93696 additions and 31596 deletions

View File

@@ -18,7 +18,7 @@
],
"brace-style": "off",
"comma-spacing": "off",
"space-infix-ops": "error",
"space-infix-ops": "off",
"comma-dangle": "off",
"eqeqeq": [
"error",
@@ -107,6 +107,7 @@
"1tbs", { "allowSingleLine": true }
],
"@typescript-eslint/comma-spacing": "error",
"@typescript-eslint/space-infix-ops": "error",
"@typescript-eslint/space-before-function-paren": ["error", {
"anonymous": "always",
"named": "never",

10
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,10 @@
<!-- Thank you for contributing to Mol* -->
# Description
## Actions
- [ ] Added description of changes to the `[Unreleased]` section of `CHANGELOG.md`
- [ ] Updated headers of modified files
- [ ] Added my name to `package.json`'s `contributors`

View File

@@ -1,3 +1,5 @@
name: Build
on:
push:
pull_request:
@@ -9,12 +11,12 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 17
node-version: 16
- run: npm ci
- run: sudo apt-get install xvfb
- name: Lint
run: npm run lint
- name: Test
run: xvfb-run --auto-servernum npm run jest
run: npm install --no-save "gl@^6.0.2" && xvfb-run --auto-servernum npm run jest
- name: Build
run: npm run build

View File

@@ -1,18 +0,0 @@
language: node_js
os: linux
sudo: required
dist: trusty
before_install:
- sudo apt-get install -y mesa-utils
- sudo apt-get install -y xvfb
- sudo apt-get install -y libgl1-mesa-dri
- sudo apt-get install -y libglapi-mesa
- sudo apt-get install -y libosmesa6
- sudo apt-get install -y gcc-4.9
- sudo apt-get install -y libstdc++6
- sudo apt-get install -y libxi-dev
node_js:
- "12"
- "10"
before_script:
- export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start

View File

@@ -6,7 +6,6 @@
"recommendations": [
"dbaeumer.vscode-eslint",
"firsttris.vscode-jest-runner",
"msjsdiag.debugger-for-chrome",
"slevesque.shader",
"stpn.vscode-graphql",
"wayou.vscode-todo-highlight"

View File

@@ -7,6 +7,8 @@
"*.gql.ts": "graphql"
},
"eslint.options": {
"ignorePattern": ["webpack.config.js", "scripts/*"],
"overrideConfig": {
"ignorePatterns": ["webpack.config.js", "scripts/*"],
},
}
}

View File

@@ -6,6 +6,530 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased]
## [v3.31.3] - 2023-02-22
- Fix impostor bond visuals not correctly updating on `sizeFactor` changes
- Fix degenerate case in PCA
- Fix near clipping avoidance in impostor shaders
- Update `fs` import in `data-source.ts`
## [v3.31.2] - 2023-02-12
- Fix exit code of volume pack executable (pack.ts). Now exits with non-0 status when an error happens
- Remove pca transform from components ui focus (too distracting)
- Fix artefacts with opaque outlines behind transparent objects
- Fix polymer trace visual not updating
- Fix use of `WEBGL_provoking_vertex`
## [v3.31.1] - 2023-02-05
- Improve Component camera focus based on the PCA of the structure and the following rules:
- The first residue should be in first quadrant if there is only one chain
- The average position of the residues of the first chain should be in the first quadrant if there is more than one chain
- Add `HeadlessPluginContext` and `HeadlessScreenshotHelper` to be used in Node.js
- Add example `image-renderer`
- Fix wrong offset when rendering text with orthographic projection
- Update camera/handle helper when `devicePixelRatio` changes
- Add various options to customize the axes camera-helper
- Fix issue with texture-mesh color smoothing when changing themes
- Add fast boundary helper and corresponding unit trait
- Add Observable for Canvas3D commits
## [v3.30.0] - 2023-01-29
- Improve `Dnatco` extension
- Factor out common code in `Dnatco` extension
- Add `NtC tube` visual. Applicable for structures with NtC annotation
- [Breaking] Rename `DnatcoConfalPyramids` to `DnatcoNtCs`
- Improve boundary calculation performance
- Add option to create & include images in state snapshots
- Fix SSAO artefacts with high bias values
- Fix SSAO resolution scale parameter handling
- Improve outlines, visually more stable at different view distances
## [v3.29.0] - 2023-01-15
- `meshes` extension: Fixed a bug in mesh visualization (show backfaces when opacity < 1)
- Add color quick select control to Volume controls
- Fix `dropFiles` bug
- Fix some cyclic imports and reduce the use of const enums. This should make it easier to use the library with the `isolatedModules: true` TS config.
- Fix `dropFiles` bug (#679)
- Add `input type='color'` picker to `CombinedColorControl`
- Set `ParameterMappingControl` disabled when state is updating
- Performance tweaks
- Update clip `defines` only when changed
- Check for identity in structure/unit areEqual methods
- Avoid cloning of structure representation parameters
- Make SymmetryOperator.createMapping monomorphic
- Improve bonding-sphere calculation
- Defer Scene properties calculation (markerAverage, opacityAverage, hasOpaque)
- Improve checks in in UnitsRepresentation setVisualState
- Add StructureElement.Loci.forEachLocation
- Add RepresentationRegistry.clear and ThemeRegistry.clear
- Add generic Loci support for overpaint, substance, clipping themes
- Add `.getCenter` and `.center` to `Camera`
- Add support to dim unmarked groups
- Add support for marker edge strength
## [v3.28.0] - 2022-12-20
- Show histogram in direct volume control point settings
- Add `solidInterior` parameter to sphere/cylinder impostors
- [Breaking] Tweak `ignoreHydrogens` non-polar handling (introduced in 3.27.0)
- Add `meshes` and `volumes-and-segmentations` extensions
- See https://molstarvolseg.ncbr.muni.cz/ for more info
- Fix missing support for info in `ParamDefinition.Converted`
- Add support for multi-visual volume representations
- Improve volume isosurface bounding-sphere
- Add basic volume segmentation support to core
- Add `Volume.Segment` model
- Add `Segmentation` custom volume property
- Add `SegmentRepresentation` representation
- Add `volume-segment` color theme
- Fix GPU marching cubes failing for large meshes with webgl2 (due to use of float16)
## [v3.27.0] - 2022-12-15
- Add an `includeTransparent` parameter to hide/show outlines of components that are transparent
- Fix 'once' for animations of systems with many frames
- Better guard against issue (black fringes) with bumpiness in impostors
- Improve impostor shaders
- Fix sphere near-clipping with orthographic projection
- Fix cylinder near-clipping
- Add interior cylinder caps
- Add per-pixel object clipping
- Fix `QualityAssessment` assignment bug for structures with different auth vs label sequence numbering
- Refresh `ApplyActionControl`'s param definition when toggling expanded state
- Fix `struct_conn` bond assignment for ions
- Ability to show only polar hydrogens
## [v3.26.0] - 2022-12-04
- Support for ``powerPreference`` webgl attribute. Add ``PluginConfig.General.PowerPreference`` and ``power-preference`` Viewer GET param.
- Excluded common protein caps `NME` and `ACE` from the ligand selection query
- Add screen-space shadow post-processing effect
- Add "Structure Molecular Surface" visual
- Add `external-volume` theme (coloring of arbitrary geometries by user-selected volume)
## [v3.25.1] - 2022-11-20
- Fix edge-case in `Structure.eachUnitPair` with single-element units
- Fix 'auto' structure-quality for coarse models
## [v3.25.0] - 2022-11-16
- Fix handling of gzipped assets (reverts #615)
## [v3.24.0] - 2022-11-13
- Make `PluginContext.initContainer` checkered canvas background optional
- Store URL of downloaded assets to detect zip/gzip based on extension (#615)
- Add optional `operator.key`; can be referenced in `IndexPairBonds`
- Add overpaint/transparency/substance theme strength to representations
- Fix viewport color for transparent background
## [v3.23.0] - 2022-10-19
- Add `PluginContext.initContainer/mount/unmount` methods; these should make it easier to reuse a plugin context with both custom and built-in UI
- Add `PluginContext.canvas3dInitialized`
- `createPluginUI` now resolves after the 3d canvas has been initialized
- Change EM Volume Streaming default from `Whole Structure` to `Auto`
## [v3.22.0] - 2022-10-17
- Replace `VolumeIsosurfaceParams.pickingGranularity` param with `Volume.PickingGranuality`
## [v3.21.0] - 2022-10-17
- Add `VolumeIsosurfaceParams.pickingGranularity` param
- Prevent component controls collapsing when option is selected
## [v3.20.0] - 2022-10-16
- [Breaking] Rename the ``model-index`` color theme to ``trajectory-index``
- Add a new ``model-index`` color theme that uniquely colors each loaded model
- Add the new ``model-index`` and ``structure-index`` color themes as an option for the carbon color in the ``element-symbol`` and ``ilustrative`` color themes
- Add ``structure-index`` color theme that uniquely colors each root structure
- Add ``nearest`` method to ``Lookup3D``
- Add mipmap-based blur for skybox backgrounds
## [v3.19.0] - 2022-10-01
- Fix "empty textures" error on empty canvas
- Optimize BinaryCIF integer packing encoder
- Fix dual depth peeling when post-processing is off or when rendering direct-volumes
- Add ``cameraClipping.minNear`` parameter
- Fix black artifacts on specular highlights with transparent background
## [v3.18.0] - 2022-09-17
- Integration of Dual depth peeling - OIT method
- Stereo camera improvements
- Fix param updates not applied
- Better param ranges and description
- Add timer.mark for left/right camera
## [v3.17.0] - 2022-09-11
- [Fix] Clone ``Canvas3DParams`` when creating a ``Canvas3D`` instance to prevent shared state between multiple instances
- Add ``includeResidueTest`` option to ``alignAndSuperposeWithSIFTSMapping``
- Add ``parentDisplay`` param for interactions representation.
- [Experimental] Add support for PyMOL, VMD, and Jmol atom expressions in selection scripts
- Support for ``failIfMajorPerformanceCaveat`` webgl attribute. Add ``PluginConfig.General.AllowMajorPerformanceCaveat`` and ``allow-major-performance-caveat`` Viewer GET param.
- Fix handling of PDB TER records (#549)
- Add support for getting multiple loci from a representation (``.getAllLoci()``)
- Add ``key`` property to intra- and inter-bonds for referencing source data
- Fix click event triggered after move
## [v3.16.0] - 2022-08-25
- Support ``globalColorParams`` and ``globalSymmetryParams`` in common representation params
- Support ``label`` parameter in ``Viewer.loadStructureFromUrl``
- Fix ``ViewportHelpContent`` Mouse Controls section
## [v3.15.0] - 2022-08-23
- Fix wboit in Safari >=15 (add missing depth renderbuffer to wboit pass)
- Add 'Around Camera' option to Volume streaming
- Avoid queuing more than one update in Volume streaming
## [v3.14.0] - 2022-08-20
- Expose inter-bonds compute params in structure
- Improve performance of inter/intra-bonds compute
- Fix defaultAttribs handling in Canvas3DContext.fromCanvas
- Confal pyramids extension improvements
- Add custom labels to Confal pyramids
- Improve naming of some internal types in Confal pyramids extension coordinate
- Add example mmCIF file with categories necessary to display Confal pyramids
- Change the lookup logic of NtC steps from residues
- Add support for download of gzipped files
- Don't filter IndexPairBonds by element-based rules in MOL/SDF and MOL2 (without symmetry) models
- Fix Glycam Saccharide Names used by default
- Fix GPU surfaces rendering in Safari with WebGL2
- Add ``fov`` (Field of View) Canvas3D parameter
- Add ``sceneRadiusFactor`` Canvas3D parameter
- Add background pass (skybox, image, horizontal/radial gradient)
- Set simple-settings presets via ``PluginConfig.Background.Styles``
- Example presets in new backgrounds extension
- Load skybox/image from URL or File (saved in session)
- Opacity, saturation, lightness controls for skybox/image
- Coverage (viewport or canvas) controls for image/gradient
- [Breaking] ``AssetManager`` needs to be passed to various graphics related classes
- Fix SSAO renderable initialization
- Reduce number of webgl state changes
- Add ``viewport`` and ``scissor`` to state object
- Add ``hasOpaque`` to scene object
- Handle edge cases where some renderables would not get (correctly) rendered
- Fix text background rendering for opaque text
- Fix helper scenes not shown when rendering directly to draw target
- Fix ``CustomElementProperty`` coloring not working
## [v3.13.0] - 2022-07-24
- Fix: only update camera state if manualReset is off (#494)
- Improve handling principal axes of points in a plane
- Add 'material' annotation support for textures
- More effort to avoid using ``flat`` qualifier in shaders: add ``dVaryingGroup``
- Enable ``immediateUpdate`` for iso level in isosurface and volume streaming controls
- Add support to download CCD from configurable URL
## [v3.12.1] - 2022-07-20
- Fix plugin behavior dispose logic to correctly unsubscribe observables.
## [v3.12.0] - 2022-07-17
- Add ``colorMarker`` option to Renderer. This disables the highlight and select marker at a shader level for faster rendering of large scenes in some cases.
- Bind shared textures only once per pass, not for each render item
- Fix missing 'material' annotation for some uniforms, causing unnecessary uniform updates
- Remove use of ``isnan`` in impostor shaders, not needed and causing slowdown
- Avoid using ``flat`` qualifier in shaders, causing slowdown
- Improve CellPack's ``adjustStyle`` option (disable ``colorMarker``, set component options, enable marking w/o ghost)
- Scan all entities when looking for ``struct_conn`` entries (fixes issue when the same ``label_asym_id`` is used in more than one entity)
## [v3.11.0] - 2022-07-04
- Add ``instanceGranularity`` option for marker, transparency, clipping, overpaint, substance data to save memory
- CellPack extension tweaks
- Use instancing to create DNA/RNA curves to save memory
- Enable ``instanceGranularity`` by default
- Add ``adjustStyle`` option to LoadCellPackModel action (stylized, no multi-sample, no far clipping, chain picking)
- Structure Superposition now respects pivot's coordinate system
## [v3.10.2] - 2022-06-26
- Fix superfluous shader varying
- Improve use of gl_VertexID when possible
## [v3.10.1] - 2022-06-26
- Fix groupCount when updating TextureMesh-based visuals
## [v3.10.0] - 2022-06-24
- Add support for Glycam saccharide names
- Add ``PluginConfig.Viewport.ShowTrajectoryControls`` config option
## [v3.9.1] - 2022-06-19
- Fix missing ``super.componentWillUnmount()`` calls (@simeonborko)
- Fix missing ``uGroupCount`` update for visuals
- Fix missing aromatic bond display
## [v3.9.0] - 2022-05-30
- Improve picking by using drawbuffers (when available) to reduce number of drawcalls
- GPU timing support
- Add ``timing-mode`` Viewer GET param
- Add support for webgl timer queries
- Add timer marks around GPU render & compute operations
- Volume Server CIF: Add check that a data block contains volume data before parsing
- Fix ``Scene.clear`` not clearing primitives & volumes arrays (@JonStargaryen)
- Fix rendering volumes when wboit is switched off and postprocessing is enabled
## [v3.8.2] - 2022-05-22
- Fix ``Scene.opacityAverage`` not taking xray shaded into account
## [v3.8.1] - 2022-05-14
- Fix issues with marking camera/handle helper (#433)
- Fix issues with array uniforms when running with headless-gl
- Fix Polymer Chain Instance coloring
- Improve performance of scene marker/opacity average calculation
## [v3.8.0] - 2022-04-30
- Add support for outlines around transparent objects
- Improve per-group transparency when wboit is switched off
- Improve ``ColorTheme`` typing with ``ColorType`` generic.
- Defaults to ``ColorTypeLocation``
- Set when using ``ColorTypeDirect`` or ``ColorTypeGrid``
- Fix case handling of ``struct_conf`` mmCIF enumeration field (#425)
- Fix ``allowTransparentBackfaces`` for per-group transparency
- Fix ``FormatRegistry.isApplicable`` returning true for unregistered formats
- Fix: handle building of ``GridLookup3D`` with zero cell size
- Fix ``ignoreLight`` for direct-volume rendering with webgl1
- Fix (non-black) outlines when using transparent background
## [v3.7.0] - 2022-04-13
- Fix ``xrayShaded`` for texture-mesh geometries
- [Breaking] Change ``allowTransparentBackfaces`` to ``transparentBackfaces`` with options ``off``, ``on``, ``opaque``. This was only added in 3.6.0, so allowing a breaking change here.
- ``off``: don't show (default)
- ``on``: show with transparency
- ``opaque``: show fully opaque
- Add option to disable file drop overlay.
## [v3.6.2] - 2022-04-05
- ModelServer ligand queries: fixes for alternate locations, additional atoms & UNL ligand
- React 18 friendly ``useBehavior`` hook.
## [v3.6.1] - 2022-04-03
- Fix React18 related UI regressions.
## [v3.6.0] - 2022-04-03
- Check that model and coordinates have same element count when creating a trajectory
- Fix aromatic rings assignment: do not mix flags and planarity test
- Improve bonds assignment of coarse grained models: check for IndexPairBonds and exhaustive StructConn
- Fix unit mapping in bondedAtomicPairs MolScript query
- Improve pdb parsing: handle non unique atom and chain names (fixes #156)
- Fix volume streaming for entries with multiple contour lists
- Add ``allowTransparentBackfaces`` parameter to support double-sided rendering of transparent geometries
- Fix handling of case insensitive mmCIF enumeration fields (including entity.type)
- Fix ``disable-wboit`` Viewer GET param
- Add support for React 18.
- Used by importing ``createPluginUI`` from ``mol-plugin-ui/react18``;
- In Mol* 4.0, React 18 will become the default option.
## [v3.5.0] - 2022-03-25
- Fix issues with bounding-sphere & color-smoothing (mostly for small geometries)
- Support BCIF => CIF conversion in ``cif2bcif`` CLI tool
## [v3.4.0] - 2022-03-13
- Fix handling of mmcif with empty ``label_*`` fields
- Improve saccharide detection (compare against list from CCD)
- Fix legend label of hydrophobicity color theme
- Add ``LoadTrajectory`` action
- Add ``CustomImportControls`` to left panel
- Add Zenodo import extension (load structures, trajectories, volumes, and zip files)
- Fix loading of some compressed files within sessions
- Fix wrong element assignment for atoms with Charmm ion names
- Fix handling of empty symmetry cell data
- Add support for ``trr`` and ``nctraj`` coordinates files
- Add support for ``prmtop`` and ``top`` topology files
## [v3.3.1] - 2022-02-27
- Fix issue with unit boundary reuse (do at visual level instead)
- Add option to ignore ions for inter-unit bond computation
## [v3.3.0] - 2022-02-27
- Fix parsing contour-level from emdb v3 header files
- Fix invalid CSS (#376)
- Fix "texture not renderable" & "texture not bound" warnings (#319)
- Fix visual for bonds between two aromatic rings
- Fix visual for delocalized bonds (parsed from mmcif and mol2)
- Fix ring computation algorithm
- Add ``UnitResonance`` property with info about delocalized triplets
- Resolve marking in main renderer loop to improve overall performance
- Use ``throttleTime`` instead of ``debounceTime`` in sequence viewer for better responsiveness
- Change line geometry default ``scaleFactor`` to 2 (3 is too big after fixing line rendering)
- Trajectory animation performance improvements
- Reuse ``Model.CoarseGrained`` for coordinate trajectories
- Avoid calculating ``InterUnitBonds`` when ``Structure.parent`` ones are empty
- Reuse unit boundary if sphere has not changed too much
- Don't show 'inter-bond' and 'element-cross' visuals in line representations of polymerAndLigand preset
- Fix additional mononucleotides detected as polymer components
- Fix and improve ``canRemap`` handling in ``IntraUnitBonds``
- Reuse occlusion for secondary passes during multi-sampling
- Check if marking passes are needed before doing them
- Add ``resolutionScale`` parameter to allow trading quality of occlusion for performance
## [v3.2.0] - 2022-02-17
- Rename "best database mapping" to "SIFTS Mapping"
- Add schema and export support for ``atom_site.pdbx_sifts_xref_*`` fields
- Add schema export support for ``atom_site.pdbx_label_index`` field
- Add `traceOnly` parameter to chain/UniProt-based structure alignment
- Store ``IndexPairBonds`` as a dynamic property.
## [v3.1.0] - 2022-02-06
- Fix ``xrayShaded`` & ``ignoreLight`` params not working at the same time
- Add ``ignoreLight`` to component params
- Tweaks for cleaner default representation style
- Cartoon: use ``nucleotide-ring`` instead of ``nucleotide-block``
- Focus: use ``xrayShaded`` instead of opacity; adjust target size; don't show non-covalent interactions twice
- Fix representation preset side effects (changing post-processing parameters, see #363)
- Add Quick Styles panel (default, illustrative, stylized)
- Fix exported structure missing secondary-structure categories (#364)
- Fix volume streaming error message: distinguish between missing data and server error (#364)
## [v3.0.2] - 2022-01-30
- Fix color smoothing of elongated structures (by fixing ``Sphere.expand`` for spheres with highly directional extrema)
- Fix entity label not displayed when multiple instances of the same entity are highlighted
- Fix empty elements created in ``StructureElement.Loci.extendToAllInstances``
- Measurement options tweaks (allow larger ``textSize``; make ``customText`` essential)
- Fix visual visibility sync edge case when changing state snapshots
## [v3.0.1] - 2022-01-27
- Fix marking pass not working with ``transparentBackground``
- Fix pdbe xray maps url not https
- Fix entity-id color theme broken for non-IHM models
- Improve/fix marking of ``InteractionsInterUnitVisual`` (mark when all contact-feature members are given)
- Add missing "entity-id" and "enity-source" options for carbon coloring to "element-symbol" color theme
- Fix VolumeServer/query CLI
- Support automatic iso-value adjustment for VolumeServer data in ``Viewer.loadVolumeFromUrl``
- Emit drag event whenever started within viewport (not only for non-empty loci)
## [v3.0.0] - 2022-01-23
- Assembly handling tweaks:
- Do not include suffix for "identity assembly operators"
- Do not include assembly-related categories to export if the structure was composed from an assembly
- Special case for ``structAsymMap`` if Mol* asym id operator mapping is present
- Support for opening ZIP files with multiple entries
- Add Model Export extension
- Bugfix: Automatically treat empty string as "non-present" value in BinaryCIF writer.
- Fix coarse model support in entity-id color theme
- Fix marking of carbohydrate visuals (whole chain could get marked instead of single residue)
- Add custom colors to "element-symbol", "molecule-type", "residue-name", and "secondary-structure" themes
- Support/bugfixes for ``atom_site.pdbx_sifts_xref`` categories
- Improve/fix marking of ``InteractionsIntraUnitVisual`` (mark when all contact-feature members are given)
## [v3.0.0-dev.10] - 2022-01-17
- Fix ``getOperatorsForIndex``
- Pass animation info (current frame & count) to state animations
- Fix camera stutter for "camera spin" animation
- Add formal charge parsing support for MOL/SDF files (thanks @ptourlas)
- [Breaking] Cleaner looking ``MembraneOrientationVisuals`` defaults
- [Breaking] Add rock animation to trackball controls
- Add ``animate`` to ``TrackballControlsParams``, remove ``spin`` and ``spinSpeed``
- Add ``animate`` to ``SimpleSettingsParams``, remove ``spin``
- Add "camera rock" state animation
- Add support for custom colors to "molecule-type" theme
- [Breaking] Add style parameter to "illustrative" color theme
- Defaults to "entity-id" style instead of "chain-id"
- Add "illustrative" representation preset
## [v3.0.0-dev.9] - 2022-01-09
- Add PDBj as a ``pdb-provider`` option
- Move Viewer APP to a separate file to allow use without importing light theme & index.html
- Add symmetry support for mol2 files (only spacegroup setting 1)
- Fix mol2 files element symbol assignment
- Improve bond assignment from ``IndexPairBonds``
- Add ``key`` field for mapping to source data
- Fix assignment of bonds with unphysical length
- Fix label/stats of single atom selection in multi-chain units
## [v3.0.0-dev.8] - 2021-12-31
- Add ``PluginFeatureDetection`` and disable WBOIT in Safari 15.
- Add ``disable-wboit`` Viewer GET param
- Add ``prefer-webgl1`` Viewer GET param
- [Breaking] Refactor direct-volume rendering
- Remove isosurface render-mode (use GPU MC instead)
- Move coloring into theme (like for other geometries/renderables)
- Add ``direct`` color type
- Remove color from transfer-function (now only alpha)
- Add direct-volume color theme support
- Add volume-value color theme
- [Breaking] Use size theme in molecular/gaussian surface & label representations
- This is breaking because it was hardcoded to ``physical`` internally but the repr size theme default was ``uniform`` (now ``physical``)
## [v3.0.0-dev.7] - 2021-12-20
- Reduce number of created programs/shaders
- Support specifying variants when creating graphics render-items
- Change double-side shader param from define to uniform
- Remove dMarkerType shader define (use uMarker as needed)
- Support to ignore defines depending on the shader variant
- Combine pickObject/pickInstance/pickGroup shader variants into one
- Combine markingDepth/markingMask shader variants into one
- Correctly set shader define flags for overpaint, transparency, substance, clipping
- [Breaking] Add per-object clip rendering properties (variant/objects)
- ``SimpleSettingsParams.clipping.variant/objects`` and ``RendererParams.clip`` were removed
## [v3.0.0-dev.6] - 2021-12-19
- Enable temporal multi-sampling by default
- Fix flickering during marking with camera at rest
- Enable ``aromaticBonds`` in structure representations by default
- Add ``PluginConfig.Structure.DefaultRepresentationPreset``
- Add ModelArchive support
- schema extensions (e.g., AlphaFold uses it for the pLDDT score)
- ModelArchive option in DownloadStructure action
- ``model-archive`` GET parameter for Viewer app
- ``Viewer.loadModelArchive`` method
- Improve support for loading AlphaFold structures
- Automatic coloring by pLDDT
- AlphaFold DB option in DownloadStructure action
- ``afdb`` GET parameter for Viewer app
- ``Viewer.loadAlphaFoldDb`` method
- Add QualityAssessment extension (using data from ma_qa_metric_local mmcif category)
- pLDDT & qmean score: coloring, repr presets, molql symbol, loci labels (including avg for mutli-residue selections)
- pLDDT: selection query
- Warn about erroneous symmetry operator matrix (instead of throwing an error)
- Added ``createPluginUI`` to ``mol-plugin-ui``
- Support ``onBeforeUIRender`` to make sure initial UI works with custom presets and similar features.
- [Breaking] Removed ``createPlugin`` and ``createPluginAsync`` from ``mol-plugin-ui``
- Please use ``createPluginUI`` instead
- Improve aromatic bonds handling
- Don't detect aromatic bonds for rings < 5 atoms based on planarity
- Prefer atoms in aromatic rings as bond reference positions
## [v3.0.0-dev.5] - 2021-12-16
- Fix initial camera reset not triggering for some entries.
@@ -34,7 +558,7 @@ Note that since we don't clearly distinguish between a public and private interf
- Add multiple lights support (with color, intensity, and direction parameters)
- [Breaking] Add per-object material rendering properties
- ``SimpleSettingsParams.lighting.renderStyle`` and ``RendererParams.style`` were removed
- ``SimpleSettingsParams.lighting.renderStyle`` and ``RendererParams.style`` were removed
- Add substance theme with per-group material rendering properties
- ``StructureComponentManager.Options`` state saving support
- ``ParamDefinition.Group.presets`` support

72
CITATION.cff Normal file
View File

@@ -0,0 +1,72 @@
cff-version: 1.2.0
title: >-
Mol* library
message: >-
Please cite this software using the metadata from
'preferred-citation'.
authors:
- given-names: Alexander S
family-names: Rose
orcid: 'https://orcid.org/0000-0002-0893-5551'
- given-names: David
family-names: Sehnal
orcid: 'https://orcid.org/0000-0002-0682-3089'
- given-names: Sebastian
family-names: Bittrich
orcid: 'https://orcid.org/0000-0003-3576-0387'
- given-names: Áron Samuel
family-names: Kovács
- given-names: Ludovic
family-names: Autin
orcid: 'https://orcid.org/0000-0002-2197-191X'
- given-names: Michal
family-names: Malý
- given-names: Jiří
family-names: Černý
- given-names: Panagiotis
family-names: Tourlas
type: software
doi: 10.5281/zenodo.3947306
preferred-citation:
authors:
- given-names: David
family-names: Sehnal
orcid: 'https://orcid.org/0000-0002-0682-3089'
- given-names: Sebastian
family-names: Bittrich
orcid: 'https://orcid.org/0000-0003-3576-0387'
- given-names: Mandar
family-names: Deshpande
orcid: 'https://orcid.org/0000-0002-9043-7665'
- given-names: Radka
family-names: Svobodová
orcid: 'https://orcid.org/0000-0002-3840-8760'
- given-names: Karel
family-names: Berka
orcid: 'https://orcid.org/0000-0001-9472-2589'
- given-names: Václav
family-names: Bazgier
orcid: 'https://orcid.org/0000-0003-3393-3010'
- given-names: Sameer
family-names: Velankar
orcid: 'https://orcid.org/0000-0002-8439-5964'
- given-names: Stephen K
family-names: Burley
orcid: 'https://orcid.org/0000-0002-2487-9713'
- given-names: Jaroslav
family-names: Koča
orcid: 'https://orcid.org/0000-0002-2780-4901'
- given-names: Alexander S
family-names: Rose
orcid: 'https://orcid.org/0000-0002-0893-5551'
title: >-
Mol* Viewer: modern web app for 3D visualization
and analysis of large biomolecular structures
type: article
doi: 10.1093/nar/gkab314
journal: "Nucleic Acids Research"
issue: W1
volume: 49
year: 2021
month: 7
pages: "W431W437"

View File

@@ -1,6 +1,6 @@
[![License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](./LICENSE)
[![npm version](https://badge.fury.io/js/molstar.svg)](https://www.npmjs.com/package/molstar)
[![Build Status](https://travis-ci.org/molstar/molstar.svg?branch=master)](https://travis-ci.org/molstar/molstar)
[![Build](https://github.com/molstar/molstar/actions/workflows/node.yml/badge.svg)](https://github.com/molstar/molstar/actions/workflows/node.yml)
[![Gitter](https://badges.gitter.im/molstar/Lobby.svg)](https://gitter.im/molstar/Lobby)
# Mol*
@@ -11,6 +11,13 @@ When using Mol*, please cite:
David Sehnal, Sebastian Bittrich, Mandar Deshpande, Radka Svobodová, Karel Berka, Václav Bazgier, Sameer Velankar, Stephen K Burley, Jaroslav Koča, Alexander S Rose: [Mol* Viewer: modern web app for 3D visualization and analysis of large biomolecular structures](https://doi.org/10.1093/nar/gkab314), *Nucleic Acids Research*, 2021; https://doi.org/10.1093/nar/gkab314.
### Protein Data Bank Integrations
- The [pdbe-molstar](https://github.com/molstar/pdbe-molstar) library is the Mol* implementation used by EMBL-EBI data resources such as [PDBe](https://pdbe.org/), [PDBe-KB](https://pdbe-kb.org/) and [AlphaFold DB](https://alphafold.ebi.ac.uk/). This implementation can be used as a JS plugin and a Web component and supports property/attribute-based easy customisation. It provides helper methods to facilitate programmatic interactions between the web application and the 3D viewer. It also provides a superposition view for overlaying all the observed ligand molecules on representative protein conformations.
- [rcsb-molstar](https://github.com/molstar/rcsb-molstar) is the Mol* plugin used by [RCSB PDB](https://www.rcsb.org). The project provides additional presets for the visualization of structure alignments and structure motifs such as ligand binding sites. Furthermore, [rcsb-molstar](https://github.com/molstar/rcsb-molstar) allows to interactively add or hide of (parts of) chains, as seen in the [3D Protein Feature View](https://www.rcsb.org/3d-sequence/4hhb).
## Project Structure Overview
The core of Mol* consists of these modules (see under `src/`):
@@ -113,10 +120,13 @@ and navigate to `build/viewer`
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-ions.js src/mol-model/structure/model/types/ions.ts
**Saccharide names**
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-saccharides.js src/mol-model/structure/model/types/saccharides.ts
**GraphQL schemas**
node node_modules//@graphql-codegen/cli/bin -c src/extensions/rcsb/graphql/codegen.yml
node node_modules/@graphql-codegen/cli/cjs/bin -c src/extensions/rcsb/graphql/codegen.yml
### Other scripts
**Create chem comp bond table**
@@ -131,7 +141,7 @@ and navigate to `build/viewer`
export NODE_PATH="lib"; node build/state-docs
**Convert any CIF to BinaryCIF**
**Convert any CIF to BinaryCIF (or vice versa)**
node lib/commonjs/servers/model/preprocess -i file.cif -ob file.bcif
@@ -141,6 +151,11 @@ Or
node lib/commonjs/cli/cif2bcif
E.g.
node lib/commonjs/cli/cif2bcif src.cif out.bcif.gz
node lib/commonjs/cli/cif2bcif src.bcif.gz out.cif
## Development
### Installation

View File

@@ -24,6 +24,11 @@ atom_site.auth_asym_id
atom_site.auth_seq_id
atom_site.pdbx_PDB_model_num
atom_site.ihm_model_id
atom_site.pdbx_label_index
atom_site.pdbx_sifts_xref_db_name
atom_site.pdbx_sifts_xref_db_acc
atom_site.pdbx_sifts_xref_db_num
atom_site.pdbx_sifts_xref_db_res
atom_site_anisotrop.id
atom_site_anisotrop.U
@@ -246,6 +251,14 @@ citation_author.ordinal
exptl.entry_id
exptl.method
software.classification
software.date
software.description
software.name
software.pdbx_ordinal
software.type
software.version
struct.entry_id
struct.title
struct.pdbx_descriptor
@@ -802,4 +815,58 @@ ihm_multi_state_modeling.population_fraction_sd
ihm_multi_state_modeling.state_type
ihm_multi_state_modeling.state_name
ihm_multi_state_modeling.experiment_type
ihm_multi_state_modeling.details
ihm_multi_state_modeling.details
ma_data.content_type
ma_data.content_type_other_details
ma_data.id
ma_data.name
ma_model_list.data_id
ma_model_list.model_group_id
ma_model_list.model_group_name
ma_model_list.model_id
ma_model_list.model_name
ma_model_list.model_type
ma_model_list.ordinal_id
ma_qa_metric.id
ma_qa_metric.mode
ma_qa_metric.name
ma_qa_metric.software_group_id
ma_qa_metric.type
ma_qa_metric_global.metric_id
ma_qa_metric_global.metric_value
ma_qa_metric_global.model_id
ma_qa_metric_global.ordinal_id
ma_qa_metric_local.label_asym_id
ma_qa_metric_local.label_comp_id
ma_qa_metric_local.label_seq_id
ma_qa_metric_local.metric_id
ma_qa_metric_local.metric_value
ma_qa_metric_local.model_id
ma_qa_metric_local.ordinal_id
ma_software_group.group_id
ma_software_group.ordinal_id
ma_software_group.software_id
ma_target_entity.data_id
ma_target_entity.entity_id
ma_target_entity.origin
ma_target_entity_instance.asym_id
ma_target_entity_instance.details
ma_target_entity_instance.entity_id
ma_target_ref_db_details.db_accession
ma_target_ref_db_details.db_code
ma_target_ref_db_details.db_name
ma_target_ref_db_details.ncbi_taxonomy_id
ma_target_ref_db_details.organism_scientific
ma_target_ref_db_details.seq_db_align_begin
ma_target_ref_db_details.seq_db_align_end
ma_target_ref_db_details.seq_db_isoform
ma_target_ref_db_details.target_entity_id
1 atom_sites.entry_id
24 atom_site.pdbx_PDB_model_num
25 atom_site.ihm_model_id
26 atom_site_anisotrop.id atom_site.pdbx_label_index
27 atom_site.pdbx_sifts_xref_db_name
28 atom_site.pdbx_sifts_xref_db_acc
29 atom_site.pdbx_sifts_xref_db_num
30 atom_site.pdbx_sifts_xref_db_res
31 atom_site_anisotrop.id
32 atom_site_anisotrop.U
33 atom_site_anisotrop.U_esd
34 atom_site_anisotrop.pdbx_PDB_ins_code
251 struct_conn.conn_type_id struct_conf.end_auth_comp_id
252 struct_conn.pdbx_PDB_id struct_conf.end_auth_asym_id
253 struct_conn.ptnr1_label_asym_id struct_conf.end_auth_seq_id
254 struct_conf.pdbx_PDB_helix_class
255 struct_conf.details
256 struct_conf.pdbx_PDB_helix_length
257 struct_conn.id
258 struct_conn.conn_type_id
259 struct_conn.pdbx_PDB_id
260 struct_conn.ptnr1_label_asym_id
261 struct_conn.ptnr1_label_comp_id
262 struct_conn.ptnr1_label_comp_id struct_conn.ptnr1_label_seq_id
263 struct_conn.ptnr1_label_seq_id struct_conn.ptnr1_label_atom_id
264 struct_conn.ptnr1_label_atom_id struct_conn.pdbx_ptnr1_label_alt_id
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872

44
docs/file-formats.md Normal file
View File

@@ -0,0 +1,44 @@
Support file formats and their extensions.
## Structure
- MMCIF and CIFCORE (mmCIF and coreCIF schemas): cif, bcif, mmcif, mcif
- GRO: gro
- MOL: mol
- MOL2: mol2
- PDB/PDBQT: pdb, ent, pdbqt
- SDF: sdf, sd
- XYZ: xyz
## Topology
Need to be loaded together with Coordinates.
- PRMTOP: prmtop, parm7
- PSF: psf
- TOP: top
## Coordinates
Need to be loaded together with a Structure or Topology.
- DCD: dcd
- NCTRAJ: nc, nctraj
- TRR: trr
- XTC: xtc
## Volume
- CCP4/MRC/MAP: ccp4, mrc, map
- CUBE (may include a Structure): cub, cube
- DSN6/BRIX: dsn6, brix
- DX and DXBIN: dx, dxbin
- DSCIF (DensityServer CIF schema): cif, bcif
## Shape
- PLY

View File

@@ -13,6 +13,7 @@
* 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)
* Helices of D-amino acids (e.g. 7QDI)
* Mixed (heterogeneous) all-atom/trace-only RNA model (1JGQ)
* Polymers with residues with missing trace atoms (e.g. 2QFJ)
* Modified RNA bases (1y26, 5L4O)
@@ -29,6 +30,19 @@
* Long linear sugar chain (4HG6)
* Anisotropic B-factors/Ellipsoids (1EJG)
* NOS bridges (LYS-CSO in 7B0L, 6ZWJ, 6ZWH)
* Non-polymer components in polymer entities
* PN2 in 1F80
* ACE (many, e.g. 5AGU, 1E1X)
* ACY in 7ABY
* NH2 (many, e.g. 6Y13)
* Ligands with many rings
* STU (e.g. 1U59) - many fused rings
* HT (e.g. 127D) - rings connected by a single bond
* J2C (e.g. 7EFJ) - rings connected by a single atom
* RBF (e.g. 7QF2) - three linearly fused rings
* TA1 (e.g. 1JFF) - many fused rings (incl. a 8-member rings)
* BPA (e.g. 1JDG) - many fused rings
* CLR (e.g. 3GKI) - four fused rings
Assembly symmetries
* 5M30 (Assembly 1, C3 local and pseudo)

File diff suppressed because it is too large Load Diff

86
examples/ace2-hit.mol2 Normal file
View File

@@ -0,0 +1,86 @@
@<TRIPOS>MOLECULE
ace2_r_r2.top2000.poses.plain/3_Z1137565832_1_T2.pdb
37 41 0 0 0
SMALL
GASTEIGER
@<TRIPOS>ATOM
1 C 64.7720 85.9180 38.1090 C.3 1 LIG1 0.0799
2 C 64.6440 84.6900 37.1570 C.3 1 LIG1 0.0306
3 C 65.2660 83.4260 37.8080 C.3 1 LIG1 0.0927
4 N 66.6560 83.6710 38.1790 N.pl3 1 LIG1 -0.2919
5 C 67.7080 82.9280 37.6260 C.ar 1 LIG1 0.1520
6 C 69.0970 83.1860 37.8250 C.ar 1 LIG1 0.0393
7 C 70.0830 82.4100 37.1810 C.ar 1 LIG1 0.0436
8 C 69.6450 81.3740 36.3510 C.ar 1 LIG1 0.1867
9 N 70.3370 80.5030 35.6050 N.ar 1 LIG1 -0.1270
10 N 69.4700 79.7480 35.0040 N.ar 1 LIG1 -0.1228
11 C 68.2200 80.1120 35.3570 C.ar 1 LIG1 0.2583
12 N 68.3350 81.1470 36.2040 N.ar 1 LIG1 -0.1866
13 N 67.4230 81.8700 36.8030 N.ar 1 LIG1 -0.1473
14 C 66.8190 84.7600 39.1350 C.3 1 LIG1 0.0927
15 C 66.2560 86.0870 38.5570 C.3 1 LIG1 0.0306
16 N 64.4520 87.4670 36.2150 N.am 1 LIG1 -0.2979
17 H 64.9740 86.7650 35.7110 H 1 LIG1 0.1498
18 C 64.2290 87.1720 37.5220 C.2 1 LIG1 0.2224
19 O 63.5690 87.9550 38.2480 O.2 1 LIG1 -0.2751
20 C 64.0160 88.6470 35.5420 C.3 1 LIG1 0.1559
21 C 65.9650 88.2170 32.5700 C.ar 1 LIG1 0.1629
22 N 65.8040 88.0390 33.8860 N.ar 1 LIG1 -0.3232
23 H 66.4190 87.5270 34.5040 H 1 LIG1 0.1686
24 C 64.6770 88.6690 34.2330 C.ar 1 LIG1 0.1601
25 N 64.1890 89.2810 33.1430 N.ar 1 LIG1 -0.1318
26 N 64.9640 89.0070 32.1450 N.ar 1 LIG1 -0.1293
27 F 69.9260 86.0280 29.3520 F 1 LIG1 -0.2042
28 C 68.9880 86.5420 30.0990 C.ar 1 LIG1 0.1401
29 C 67.6590 86.0900 29.9830 C.ar 1 LIG1 0.0297
30 C 66.6500 86.6450 30.7950 C.ar 1 LIG1 0.0053
31 C 66.9590 87.6470 31.7450 C.ar 1 LIG1 0.0359
32 C 68.2970 88.0990 31.8400 C.ar 1 LIG1 0.0053
33 C 69.3030 87.5560 31.0230 C.ar 1 LIG1 0.0297
34 C 66.9850 79.4910 34.8440 C.3 1 LIG1 0.4541
35 F 67.3150 78.4110 34.0640 F 1 LIG1 -0.1631
36 F 66.2460 80.3690 34.0910 F 1 LIG1 -0.1631
37 F 66.1920 79.0650 35.8800 F 1 LIG1 -0.1631
@<TRIPOS>BOND
1 1 2 1
2 1 18 1
3 1 15 1
4 2 3 1
5 3 4 1
6 4 5 1
7 4 14 1
8 5 13 ar
9 5 6 ar
10 6 7 ar
11 7 8 ar
12 8 9 ar
13 8 12 ar
14 9 10 ar
15 10 11 ar
16 11 34 1
17 11 12 ar
18 12 13 ar
19 14 15 1
20 16 20 1
21 16 17 1
22 16 18 am
23 18 19 2
24 20 24 1
25 21 31 1
26 21 26 ar
27 21 22 ar
28 22 24 ar
29 22 23 1
30 24 25 ar
31 25 26 ar
32 27 28 1
33 28 29 ar
34 28 33 ar
35 29 30 ar
36 30 31 ar
37 31 32 ar
38 32 33 ar
39 34 35 1
40 34 36 1
41 34 37 1

7628
examples/ace2.pdbqt Normal file

File diff suppressed because it is too large Load Diff

28000
examples/long_animation.sdf Normal file

File diff suppressed because it is too large Load Diff

48535
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "3.0.0-dev.5",
"version": "3.31.3",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -13,14 +13,14 @@
"scripts": {
"lint": "eslint .",
"lint-fix": "eslint . --fix",
"test": "npm run lint && jest",
"test": "npm install --no-save \"gl@^6.0.2\" && npm run lint && jest",
"jest": "jest",
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
"clean": "node ./scripts/clean.js",
"rebuild": "npm run clean && npm run build",
"build-viewer": "npm run build-tsc && npm run build-extra && npm run build-webpack-viewer",
"build-tsc": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\"",
"build-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/",
"build-extra": "cpx \"src/**/*.{scss,html,ico,jpg}\" lib/",
"build-webpack": "webpack --mode production --config ./webpack.config.production.js",
"build-webpack-viewer": "webpack --mode production --config ./webpack.config.viewer.js",
"watch": "concurrently -c \"green,green,gray,gray\" --names \"tsc,srv,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-servers\" \"npm:watch-extra\" \"npm:watch-webpack\"",
@@ -28,7 +28,7 @@
"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.commonjs.json --watch --incremental",
"watch-extra": "cpx \"src/**/*.{scss,html,ico}\" lib/ --watch",
"watch-extra": "cpx \"src/**/*.{scss,html,ico,jpg}\" lib/ --watch",
"watch-webpack": "webpack -w --mode development --stats minimal",
"watch-webpack-viewer": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.js",
"watch-webpack-viewer-debug": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.debug.js",
@@ -75,7 +75,9 @@
"node_modules",
"lib"
],
"testURL": "http://localhost/",
"testEnvironmentOptions": {
"url": "http://localhost/"
},
"testRegex": "\\.spec\\.ts$"
},
"author": "Mol* Contributors",
@@ -86,77 +88,90 @@
"Áron Samuel Kovács <aron.kovacs@mail.muni.cz>",
"Ludovic Autin <autin@scripps.edu>",
"Michal Malý <michal.maly@ibt.cas.cz>",
"Jiří Černý <jiri.cerny@ibt.cas.cz>"
"Jiří Černý <jiri.cerny@ibt.cas.cz>",
"Panagiotis Tourlas <panagiot_tourlov@hotmail.com>",
"Adam Midlik <midlik@gmail.com>",
"Koya Sakuma <koya.sakuma.work@gmail.com>",
"Gianluca Tomasello <giagitom@gmail.com>",
"Ke Ma <mark.ma@rcsb.org>",
"Jason Pattle <jpattle@exscientia.co.uk>",
"David Williams <dwilliams@nobiastx.com>"
],
"license": "MIT",
"devDependencies": {
"@graphql-codegen/add": "^3.1.0",
"@graphql-codegen/cli": "^2.3.0",
"@graphql-codegen/time": "^3.1.0",
"@graphql-codegen/typescript": "^2.4.1",
"@graphql-codegen/typescript-graphql-files-modules": "^2.1.0",
"@graphql-codegen/typescript-graphql-request": "^4.3.1",
"@graphql-codegen/typescript-operations": "^2.2.1",
"@types/cors": "^2.8.12",
"@types/gl": "^4.1.0",
"@types/jest": "^27.0.3",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"@graphql-codegen/add": "^4.0.0",
"@graphql-codegen/cli": "^3.0.0",
"@graphql-codegen/time": "^4.0.0",
"@graphql-codegen/typescript": "^3.0.0",
"@graphql-codegen/typescript-graphql-files-modules": "^2.2.1",
"@graphql-codegen/typescript-graphql-request": "^4.5.8",
"@graphql-codegen/typescript-operations": "^3.0.0",
"@types/cors": "^2.8.13",
"@types/gl": "^6.0.2",
"@types/jpeg-js": "^0.3.7",
"@types/pngjs": "^6.0.1",
"@types/jest": "^29.4.0",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"benchmark": "^2.1.4",
"concurrently": "^6.4.0",
"cpx2": "^4.0.0",
"concurrently": "^7.6.0",
"cpx2": "^4.2.0",
"crypto-browserify": "^3.12.0",
"css-loader": "^6.5.1",
"eslint": "^8.3.0",
"css-loader": "^6.7.3",
"eslint": "^8.33.0",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^6.2.0",
"fs-extra": "^10.0.0",
"graphql": "^15.7.2",
"http-server": "^14.0.0",
"jest": "^27.3.1",
"mini-css-extract-plugin": "^2.4.5",
"fs-extra": "^11.1.0",
"graphql": "^16.6.0",
"http-server": "^14.1.1",
"jest": "^29.4.1",
"mini-css-extract-plugin": "^2.7.2",
"path-browserify": "^1.0.1",
"raw-loader": "^4.0.2",
"sass": "^1.43.5",
"sass-loader": "^12.3.0",
"simple-git": "^2.47.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "^1.58.0",
"sass-loader": "^13.2.0",
"simple-git": "^3.16.0",
"stream-browserify": "^3.0.0",
"style-loader": "^3.3.1",
"ts-jest": "^27.0.7",
"typescript": "^4.5.2",
"webpack": "^5.64.4",
"webpack-cli": "^4.9.1"
"ts-jest": "^29.0.5",
"typescript": "^4.9.5",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
},
"dependencies": {
"@types/argparse": "^2.0.10",
"@types/benchmark": "^2.1.1",
"@types/benchmark": "^2.1.2",
"@types/compression": "1.7.2",
"@types/express": "^4.17.13",
"@types/node": "^16.11.10",
"@types/node-fetch": "^2.5.12",
"@types/react": "^17.0.37",
"@types/react-dom": "^17.0.11",
"@types/express": "^4.17.17",
"@types/node": "^16.18.12",
"@types/node-fetch": "^2.6.2",
"@types/swagger-ui-dist": "3.30.1",
"argparse": "^2.0.1",
"body-parser": "^1.19.0",
"body-parser": "^1.20.1",
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.17.1",
"express": "^4.18.2",
"h264-mp4-encoder": "^1.0.12",
"immer": "^9.0.7",
"immutable": "^3.8.2",
"node-fetch": "^2.6.2",
"rxjs": "^7.4.0",
"swagger-ui-dist": "^4.1.1",
"tslib": "^2.3.1",
"immer": "^9.0.19",
"immutable": "^4.2.3",
"node-fetch": "^2.6.9",
"rxjs": "^7.8.0",
"swagger-ui-dist": "^4.15.5",
"tslib": "^2.5.0",
"util.promisify": "^1.1.1",
"xhr2": "^0.2.1"
},
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react": "^18.1.0 || ^17.0.2 || ^16.14.0",
"react-dom": "^18.1.0 || ^17.0.2 || ^16.14.0"
},
"optionalDependencies": {
"gl": "^4.9.2"
"gl": "^6.0.2",
"jpeg-js": "^0.4.4",
"pngjs": "^6.0.0"
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -39,6 +39,24 @@ function copyViewer() {
addAnalytics(path.resolve(viewerDeployPath, 'index.html'));
}
function copyDemos() {
console.log('\n###', 'copy demos files');
const lightingBuildPath = path.resolve(buildDir, '../build/examples/lighting/');
const lightingDeployPath = path.resolve(localPath, 'demos/lighting/');
fse.copySync(lightingBuildPath, lightingDeployPath, { overwrite: true });
addAnalytics(path.resolve(lightingDeployPath, 'index.html'));
const orbitalsBuildPath = path.resolve(buildDir, '../build/examples/alpha-orbitals/');
const orbitalsDeployPath = path.resolve(localPath, 'demos/alpha-orbitals/');
fse.copySync(orbitalsBuildPath, orbitalsDeployPath, { overwrite: true });
addAnalytics(path.resolve(orbitalsDeployPath, 'index.html'));
}
function copyFiles() {
copyViewer();
copyDemos();
}
if (!fs.existsSync(localPath)) {
console.log('\n###', 'create localPath');
fs.mkdirSync(localPath, { recursive: true });
@@ -52,9 +70,9 @@ if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
.outputHandler(log)
.clone(remoteUrl, localPath)
.fetch(['--all'])
.exec(copyViewer)
.exec(copyFiles)
.add(['-A'])
.commit('updated viewer')
.commit('updated viewer & demos')
.push();
} else {
console.log('\n###', 'update repository');
@@ -62,8 +80,8 @@ if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
.outputHandler(log)
.fetch(['--all'])
.reset(['--hard', 'origin/master'])
.exec(copyViewer)
.exec(copyFiles)
.add(['-A'])
.commit('updated viewer')
.commit('updated viewer & demos')
.push();
}

View File

@@ -19,19 +19,19 @@
<div id="app"></div>
<script type="text/javascript" src="./molstar.js"></script>
<script type="text/javascript">
var viewer = new DockingViewer('app', [0x33DD22, 0x1133EE], true);
function getParam(name, regex) {
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
}
var pdbqt = getParam('pdbqt', '[^&]+').trim();
var mol2 = getParam('mol2', '[^&]+').trim();
var pdbqt = getParam('pdbqt', '[^&]+').trim() || '../../examples/ace2.pdbqt';
var mol2 = getParam('mol2', '[^&]+').trim() || '../../examples/ace2-hit.mol2';
viewer.loadStructuresFromUrlsAndMerge([
{ url: pdbqt, format: 'pdbqt' },
{ url: mol2, format: 'mol2' }
]);
DockingViewer.create('app', [0x33DD22, 0x1133EE], true).then(viewer => {
viewer.loadStructuresFromUrlsAndMerge([
{ url: pdbqt, format: 'pdbqt' },
{ url: mol2, format: 'mol2' }
]);
});
</script>
</body>
</html>

View File

@@ -8,7 +8,7 @@
import { Structure } from '../../mol-model/structure';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { PluginStateObject as PSO, PluginStateTransform } from '../../mol-plugin-state/objects';
import { createPlugin } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
@@ -54,23 +54,26 @@ const DefaultViewerOptions = {
};
class Viewer {
plugin: PluginUIContext
constructor(public plugin: PluginUIContext) {
}
constructor(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
const o = { ...DefaultViewerOptions, ...{
layoutIsExpanded: false,
layoutShowControls: false,
layoutShowRemoteState: false,
layoutShowSequence: true,
layoutShowLog: false,
layoutShowLeftPanel: true,
static async create(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
const o = {
...DefaultViewerOptions, ...{
layoutIsExpanded: false,
layoutShowControls: false,
layoutShowRemoteState: false,
layoutShowSequence: true,
layoutShowLog: false,
layoutShowLeftPanel: true,
viewportShowExpand: true,
viewportShowControls: false,
viewportShowSettings: false,
viewportShowSelectionMode: false,
viewportShowAnimation: false,
} };
viewportShowExpand: true,
viewportShowControls: false,
viewportShowSettings: false,
viewportShowSelectionMode: false,
viewportShowAnimation: false,
}
};
const defaultSpec = DefaultPluginUISpec();
const spec: PluginUISpec = {
@@ -125,29 +128,29 @@ class Viewer {
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
this.plugin = createPlugin(element, spec);
const plugin = await createPluginUI(element, spec);
(this.plugin.customState as any) = {
(plugin.customState as any) = {
colorPalette: {
name: 'colors',
params: { list: { colors } }
}
};
this.plugin.behaviors.canvas3d.initialized.subscribe(v => {
if (v) {
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: {} } }
}
} });
PluginCommands.Canvas3D.SetSettings(plugin, {
settings: {
renderer: {
...plugin.canvas3d!.props.renderer,
backgroundColor: ColorNames.white,
},
camera: {
...plugin.canvas3d!.props.camera,
helper: { axes: { name: 'off', params: {} } }
}
}
});
return new Viewer(plugin);
}
async loadStructuresFromUrlsAndMerge(sources: { url: string, format: BuiltInTrajectoryFormat, isBinary?: boolean }[]) {
@@ -163,7 +166,7 @@ class Viewer {
structures.push({ ref: structureProperties?.ref || structure.ref });
}
// remove current structuresfrom hierarchy as they will be merged
// remove current structures from hierarchy as they will be merged
// TODO only works with using loadStructuresFromUrlsAndMerge once
// need some more API metho to work with the hierarchy
this.plugin.managers.structure.hierarchy.updateCurrent(this.plugin.managers.structure.hierarchy.current.structures, 'remove');

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -31,7 +31,8 @@ function shinyStyle(plugin: PluginContext) {
postprocessing: {
...plugin.canvas3d!.props.postprocessing,
occlusion: { name: 'off', params: {} },
outline: { name: 'off', params: {} }
shadow: { name: 'off', params: {} },
outline: { name: 'off', params: {} },
}
} });
}
@@ -44,16 +45,19 @@ function occlusionStyle(plugin: PluginContext) {
postprocessing: {
...plugin.canvas3d!.props.postprocessing,
occlusion: { name: 'on', params: {
samples: 64,
radius: 8,
bias: 1.0,
blurKernelSize: 13
bias: 0.8,
blurKernelSize: 15,
radius: 5,
samples: 32,
resolutionScale: 1,
} },
outline: { name: 'on', params: {
scale: 1.0,
threshold: 0.33,
color: Color(0x0000),
} }
includeTransparent: true,
} },
shadow: { name: 'off', params: {} },
}
} });
}
@@ -201,14 +205,14 @@ const InteractionsPreset = StructureRepresentationPresetProvider({
const components = {
ligand: await presetStaticComponent(plugin, structureCell, 'ligand'),
surroundings: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandSurroundings, `surroundings`),
interactions: await plugin.builders.structure.tryCreateComponentFromSelection(structureCell, ligandPlusSurroundings, `interactions`)
interactions: await presetStaticComponent(plugin, structureCell, 'ligand'),
};
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
const representations = {
ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, material: CustomMaterial, sizeFactor: 0.3 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }),
ballAndStick: builder.buildRepresentation(update, components.surroundings, { type: 'ball-and-stick', typeParams: { ...typeParams, material: CustomMaterial, sizeFactor: 0.1, sizeAspectRatio: 1 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ball-and-stick' }),
interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams, material: CustomMaterial }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }),
interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams, material: CustomMaterial, includeParent: true, parentDisplay: 'between' }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }),
label: builder.buildRepresentation(update, components.surroundings, { type: 'label', typeParams: { ...typeParams, material: CustomMaterial, background: false, borderWidth: 0.1 }, color: 'uniform', colorParams: { value: Color(0x000000) } }, { tag: 'label' }),
};
@@ -230,7 +234,7 @@ export class ViewportComponent extends PluginUIComponent {
set = async (preset: StructureRepresentationPresetProvider) => {
await this._set(this.plugin.managers.structure.hierarchy.selection.structures, preset);
}
};
structurePreset = () => this.set(StructurePreset);
illustrativePreset = () => this.set(IllustrativePreset);

510
src/apps/viewer/app.ts Normal file
View File

@@ -0,0 +1,510 @@
/**
* Copyright (c) 2018-2023 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 { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
import { CellPack } from '../../extensions/cellpack';
import { DnatcoNtCs } from '../../extensions/dnatco';
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
import { Volseg, VolsegVolumeServerConfig } from '../../extensions/volumes-and-segmentations';
import { GeometryExport } from '../../extensions/geo-export';
import { MAQualityAssessment } from '../../extensions/model-archive/quality-assessment/behavior';
import { QualityAssessmentPLDDTPreset, QualityAssessmentQmeanPreset } from '../../extensions/model-archive/quality-assessment/behavior';
import { QualityAssessment } from '../../extensions/model-archive/quality-assessment/prop';
import { ModelExport } from '../../extensions/model-export';
import { Mp4Export } from '../../extensions/mp4-export';
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
import { ZenodoImport } from '../../extensions/zenodo';
import { Volume } from '../../mol-model/volume';
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
import { BuiltInTopologyFormat } from '../../mol-plugin-state/formats/topology';
import { BuiltInCoordinatesFormat } from '../../mol-plugin-state/formats/coordinates';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginConfig } from '../../mol-plugin/config';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { PluginSpec } from '../../mol-plugin/spec';
import { PluginState } from '../../mol-plugin/state';
import { StateObjectRef, StateObjectSelector } from '../../mol-state';
import { Asset } from '../../mol-util/assets';
import { Color } from '../../mol-util/color';
import '../../mol-util/polyfill';
import { ObjectKeys } from '../../mol-util/type-helpers';
import { SaccharideCompIdMapType } from '../../mol-model/structure/structure/carbohydrates/constants';
import { Backgrounds } from '../../extensions/backgrounds';
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setDebugMode, setProductionMode, setTimingMode, consoleStats } from '../../mol-util/debug';
const CustomFormats = [
['g3d', G3dProvider] as const
];
const Extensions = {
'volseg': PluginSpec.Behavior(Volseg),
'backgrounds': PluginSpec.Behavior(Backgrounds),
'cellpack': PluginSpec.Behavior(CellPack),
'dnatco-ntcs': PluginSpec.Behavior(DnatcoNtCs),
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
'rcsb-assembly-symmetry': PluginSpec.Behavior(RCSBAssemblySymmetry),
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
'g3d': PluginSpec.Behavior(G3DFormat),
'model-export': PluginSpec.Behavior(ModelExport),
'mp4-export': PluginSpec.Behavior(Mp4Export),
'geo-export': PluginSpec.Behavior(GeometryExport),
'ma-quality-assessment': PluginSpec.Behavior(MAQualityAssessment),
'zenodo-import': PluginSpec.Behavior(ZenodoImport),
};
const DefaultViewerOptions = {
customFormats: CustomFormats as [string, DataFormatProvider][],
extensions: ObjectKeys(Extensions),
layoutIsExpanded: true,
layoutShowControls: true,
layoutShowRemoteState: true,
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
layoutShowSequence: true,
layoutShowLog: true,
layoutShowLeftPanel: true,
collapseLeftPanel: false,
collapseRightPanel: false,
disableAntialiasing: PluginConfig.General.DisableAntialiasing.defaultValue,
pixelScale: PluginConfig.General.PixelScale.defaultValue,
pickScale: PluginConfig.General.PickScale.defaultValue,
pickPadding: PluginConfig.General.PickPadding.defaultValue,
enableWboit: PluginConfig.General.EnableWboit.defaultValue,
enableDpoit: PluginConfig.General.EnableDpoit.defaultValue,
preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
allowMajorPerformanceCaveat: PluginConfig.General.AllowMajorPerformanceCaveat.defaultValue,
powerPreference: PluginConfig.General.PowerPreference.defaultValue,
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,
viewportShowTrajectoryControls: PluginConfig.Viewport.ShowTrajectoryControls.defaultValue,
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
saccharideCompIdMapType: 'default' as SaccharideCompIdMapType,
volumesAndSegmentationsDefaultServer: VolsegVolumeServerConfig.DefaultServer.defaultValue,
};
type ViewerOptions = typeof DefaultViewerOptions;
export class Viewer {
constructor(public plugin: PluginUIContext) {
}
static async create(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
const definedOptions = {} as any;
// filter for defined properies only so the default values
// are property applied
for (const p of Object.keys(options) as (keyof ViewerOptions)[]) {
if (options[p] !== void 0) definedOptions[p] = options[p];
}
const o: ViewerOptions = { ...DefaultViewerOptions, ...definedOptions };
const defaultSpec = DefaultPluginUISpec();
const spec: PluginUISpec = {
actions: defaultSpec.actions,
behaviors: [
...defaultSpec.behaviors,
...o.extensions.map(e => Extensions[e]),
],
animations: [...defaultSpec.animations || []],
customParamEditors: defaultSpec.customParamEditors,
customFormats: o?.customFormats,
layout: {
initial: {
isExpanded: o.layoutIsExpanded,
showControls: o.layoutShowControls,
controlsDisplay: o.layoutControlsDisplay,
regionState: {
bottom: 'full',
left: o.collapseLeftPanel ? 'collapsed' : 'full',
right: o.collapseRightPanel ? 'hidden' : 'full',
top: 'full',
}
},
},
components: {
...defaultSpec.components,
controls: {
...defaultSpec.components?.controls,
top: o.layoutShowSequence ? undefined : 'none',
bottom: o.layoutShowLog ? undefined : 'none',
left: o.layoutShowLeftPanel ? undefined : 'none',
},
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
},
config: [
[PluginConfig.General.DisableAntialiasing, o.disableAntialiasing],
[PluginConfig.General.PixelScale, o.pixelScale],
[PluginConfig.General.PickScale, o.pickScale],
[PluginConfig.General.PickPadding, o.pickPadding],
[PluginConfig.General.EnableWboit, o.enableWboit],
[PluginConfig.General.EnableDpoit, o.enableDpoit],
[PluginConfig.General.PreferWebGl1, o.preferWebgl1],
[PluginConfig.General.AllowMajorPerformanceCaveat, o.allowMajorPerformanceCaveat],
[PluginConfig.General.PowerPreference, o.powerPreference],
[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.Viewport.ShowTrajectoryControls, o.viewportShowTrajectoryControls],
[PluginConfig.State.DefaultServer, o.pluginStateServer],
[PluginConfig.State.CurrentServer, o.pluginStateServer],
[PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
[PluginConfig.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
[PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
[PluginConfig.Structure.DefaultRepresentationPreset, ViewerAutoPreset.id],
[PluginConfig.Structure.SaccharideCompIdMapType, o.saccharideCompIdMapType],
[VolsegVolumeServerConfig.DefaultServer, o.volumesAndSegmentationsDefaultServer],
]
};
const element = typeof elementOrId === 'string'
? document.getElementById(elementOrId)
: elementOrId;
if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
const plugin = await createPluginUI(element, spec, {
onBeforeUIRender: plugin => {
// the preset needs to be added before the UI renders otherwise
// "Download Structure" wont be able to pick it up
plugin.builders.structure.representation.registerPreset(ViewerAutoPreset);
}
});
return new Viewer(plugin);
}
setRemoteSnapshot(id: string) {
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, options?: LoadStructureOptions & { label?: 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: 'url',
params: {
url: Asset.Url(url),
format: format as any,
isBinary,
label: options?.label,
options: { ...params.source.params.options, representationParams: options?.representationParams as any },
}
}
}));
}
async loadAllModelsOrAssemblyFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const plugin = this.plugin;
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'all-models', { useDefaultIfSingleModel: true, representationPresetParams: options?.representationParams });
}
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, options?: LoadStructureOptions) {
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, representationParams: options?.representationParams as any },
}
}
}));
}
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, options?: { detail?: number }) {
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: options?.detail ?? 3,
}
}
}));
}
loadAlphaFoldDb(afdb: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'alphafolddb' as const,
params: {
id: afdb,
options: {
...params.source.params.options,
representation: 'preset-structure-representation-ma-quality-assessment-plddt'
},
}
}
}));
}
loadModelArchive(id: string) {
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
source: {
name: 'modelarchive' as const,
params: {
id,
options: params.source.params.options,
}
}
}));
}
/**
* @example Load X-ray density from volume server
viewer.loadVolumeFromUrl({
url: 'https://www.ebi.ac.uk/pdbe/densities/x-ray/1tqn/cell?detail=3',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1.5,
color: 0x3362B2
}, {
type: 'relative',
value: 3,
color: 0x33BB33,
volumeIndex: 1
}, {
type: 'relative',
value: -3,
color: 0xBB3333,
volumeIndex: 1
}], {
entryId: ['2FO-FC', 'FO-FC'],
isLazy: true
});
* *********************
* @example Load EM density from volume server
viewer.loadVolumeFromUrl({
url: 'https://maps.rcsb.org/em/emd-30210/cell?detail=6',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1,
color: 0x3377aa
}], {
entryId: 'EMD-30210',
isLazy: true
});
*/
async loadVolumeFromUrl({ url, format, isBinary }: { url: string, format: BuildInVolumeFormat, isBinary: boolean }, isovalues: VolumeIsovalueInfo[], options?: { entryId?: string | string[], isLazy?: boolean }) {
const plugin = this.plugin;
if (!plugin.dataFormats.get(format)) {
throw new Error(`Unknown density format: ${format}`);
}
if (options?.isLazy) {
const update = this.plugin.build();
update.toRoot().apply(StateTransforms.Data.LazyVolume, {
url,
format,
entryId: options?.entryId,
isBinary,
isovalues: isovalues.map(v => ({ alpha: 1, volumeIndex: 0, ...v }))
});
return update.commit();
}
return plugin.dataTransaction(async () => {
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const parsed = await plugin.dataFormats.get(format)!.parse(plugin, data, { entryId: options?.entryId });
const firstVolume = (parsed.volume || parsed.volumes[0]) as StateObjectSelector<PluginStateObject.Volume.Data>;
if (!firstVolume?.isOk) throw new Error('Failed to parse any volume.');
const repr = plugin.build();
for (const iso of isovalues) {
const volume: StateObjectSelector<PluginStateObject.Volume.Data> = parsed.volumes?.[iso.volumeIndex ?? 0] ?? parsed.volume;
const volumeData = volume.cell!.obj!.data;
repr
.to(volume)
.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, firstVolume.data!, {
type: 'isosurface',
typeParams: { alpha: iso.alpha ?? 1, isoValue: Volume.adjustedIsoValue(volumeData, iso.value, iso.type) },
color: 'uniform',
colorParams: { value: iso.color }
}));
}
await repr.commit();
});
}
/**
* @example
* viewer.loadTrajectory({
* model: { kind: 'model-url', url: 'villin.gro', format: 'gro' },
* coordinates: { kind: 'coordinates-url', url: 'villin.xtc', format: 'xtc', isBinary: true },
* preset: 'all-models' // or 'default'
* });
*/
async loadTrajectory(params: LoadTrajectoryParams) {
const plugin = this.plugin;
let model: StateObjectSelector;
if (params.model.kind === 'model-data' || params.model.kind === 'model-url') {
const data = params.model.kind === 'model-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const trajectory = await plugin.builders.structure.parseTrajectory(data, params.model.format ?? 'mmcif');
model = await plugin.builders.structure.createModel(trajectory);
} else {
const data = params.model.kind === 'topology-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const provider = plugin.dataFormats.get(params.model.format);
model = await provider!.parse(plugin, data);
}
const data = params.coordinates.kind === 'coordinates-data'
? await plugin.builders.data.rawData({ data: params.coordinates.data, label: params.coordinatesLabel })
: await plugin.builders.data.download({ url: params.coordinates.url, isBinary: params.coordinates.isBinary, label: params.coordinatesLabel });
const provider = plugin.dataFormats.get(params.coordinates.format);
const coords = await provider!.parse(plugin, data);
const trajectory = await plugin.build().toRoot()
.apply(TrajectoryFromModelAndCoordinates, {
modelRef: model.ref,
coordinatesRef: coords.ref
}, { dependsOn: [model.ref, coords.ref] })
.commit();
const preset = await plugin.builders.structure.hierarchy.applyPreset(trajectory, params.preset ?? 'default');
return { model, coords, preset };
}
handleResize() {
this.plugin.layout.events.updated.next(void 0);
}
}
export interface LoadStructureOptions {
representationParams?: StructureRepresentationPresetProvider.CommonParams
}
export interface VolumeIsovalueInfo {
type: 'absolute' | 'relative',
value: number,
color: Color,
alpha?: number,
volumeIndex?: number
}
export interface LoadTrajectoryParams {
model: { kind: 'model-url', url: string, format?: BuiltInTrajectoryFormat /* mmcif */, isBinary?: boolean }
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array, format?: BuiltInTrajectoryFormat /* mmcif */ }
| { kind: 'topology-url', url: string, format: BuiltInTopologyFormat, isBinary?: boolean }
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInTopologyFormat },
modelLabel?: string,
coordinates: { kind: 'coordinates-url', url: string, format: BuiltInCoordinatesFormat, isBinary?: boolean }
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInCoordinatesFormat },
coordinatesLabel?: string,
preset?: keyof PresetTrajectoryHierarchy
}
export const ViewerAutoPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-viewer-auto',
display: {
name: 'Automatic (w/ Annotation)', group: 'Annotation',
description: 'Show standard automatic representation but colored by quality assessment (if available in the model).'
},
isApplicable(a) {
return (
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')) ||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))
);
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'))) {
return await QualityAssessmentPLDDTPreset.apply(ref, params, plugin);
} else if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))) {
return await QualityAssessmentQmeanPreset.apply(ref, params, plugin);
} else {
return await PresetStructureRepresentations.auto.apply(ref, params, plugin);
}
}
});

View File

@@ -20,7 +20,7 @@
<div id="app"></div>
<script type="text/javascript" src="./molstar.js"></script>
<script type="text/javascript">
var viewer = new molstar.Viewer('app', {
molstar.Viewer.create('app', {
layoutIsExpanded: true,
layoutShowControls: false,
layoutShowRemoteState: false,
@@ -34,11 +34,20 @@
pdbProvider: 'rcsb',
emdbProvider: 'rcsb',
}).then(viewer => {
viewer.loadPdb('7bv2');
viewer.loadEmdb('EMD-30210', { detail: 6 });
// viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } })
// viewer.loadStructureFromUrl('my url', 'pdb', false, {
// representationParams: {
// theme: {
// globalName: 'uniform',
// globalColorParams: { value: 0xff0000 }
// }
// },
// label: 'my structure'
// });
});
viewer.loadPdb('7bv2');
viewer.loadEmdb('EMD-30210', { detail: 6 });
// viewer.loadAllModelsOrAssemblyFromUrl('https://cs.litemol.org/5ire/full', 'mmcif', false, { representationParams: { theme: { globalName: 'operator-name' } } })
</script>
</body>
</html>

View File

@@ -46,7 +46,10 @@
}
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
if (debugMode) molstar.setDebugMode(debugMode, debugMode);
if (debugMode) molstar.setDebugMode(debugMode);
var timingMode = getParam('timing-mode', '[^&]+').trim() === '1';
if (timingMode) molstar.setTimingMode(timingMode);
var hideControls = getParam('hide-controls', '[^&]+').trim() === '1';
var collapseLeftPanel = getParam('collapse-left-panel', '[^&]+').trim() === '1';
@@ -56,7 +59,13 @@
var pixelScale = getParam('pixel-scale', '[^&]+').trim();
var pickScale = getParam('pick-scale', '[^&]+').trim();
var pickPadding = getParam('pick-padding', '[^&]+').trim();
var viewer = new molstar.Viewer('app', {
var disableWboit = getParam('disable-wboit', '[^&]+').trim() === '1';
var enableDpoit = getParam('enable-dpoit', '[^&]+').trim() === '1';
var preferWebgl1 = getParam('prefer-webgl1', '[^&]+').trim() === '1' || void 0;
var allowMajorPerformanceCaveat = getParam('allow-major-performance-caveat', '[^&]+').trim() === '1';
var powerPreference = getParam('power-preference', '[^&]+').trim().toLowerCase();
molstar.Viewer.create('app', {
layoutShowControls: !hideControls,
viewportShowExpand: false,
collapseLeftPanel: collapseLeftPanel,
@@ -68,28 +77,39 @@
pixelScale: parseFloat(pixelScale) || 1,
pickScale: parseFloat(pickScale) || 0.25,
pickPadding: isNaN(parseFloat(pickPadding)) ? 1 : parseFloat(pickPadding),
enableWboit: (disableWboit || enableDpoit) ? false : void 0, // use default value if disable-wboit is not set
enableDpoit: enableDpoit ? true : void 0,
preferWebgl1: preferWebgl1,
allowMajorPerformanceCaveat: allowMajorPerformanceCaveat,
powerPreference: powerPreference || 'high-performance',
}).then(viewer => {
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
var snapshotUrl = getParam('snapshot-url', '[^&]+').trim();
var snapshotUrlType = getParam('snapshot-url-type', '[^&]+').toLowerCase().trim() || 'molj';
if (snapshotUrl && snapshotUrlType) viewer.loadSnapshotFromUrl(snapshotUrl, snapshotUrlType);
var structureUrl = getParam('structure-url', '[^&]+').trim();
var structureUrlFormat = getParam('structure-url-format', '[a-z]+').toLowerCase().trim();
var structureUrlIsBinary = getParam('structure-url-is-binary', '[^&]+').trim() === '1';
if (structureUrl) viewer.loadStructureFromUrl(structureUrl, structureUrlFormat, structureUrlIsBinary);
var pdb = getParam('pdb', '[^&]+').trim();
if (pdb) viewer.loadPdb(pdb);
var pdbDev = getParam('pdb-dev', '[^&]+').trim();
if (pdbDev) viewer.loadPdbDev(pdbDev);
var emdb = getParam('emdb', '[^&]+').trim();
if (emdb) viewer.loadEmdb(emdb);
var afdb = getParam('afdb', '[^&]+').trim();
if (afdb) viewer.loadAlphaFoldDb(afdb);
var modelArchive = getParam('model-archive', '[^&]+').trim();
if (modelArchive) viewer.loadModelArchive(modelArchive);
});
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
var snapshotUrl = getParam('snapshot-url', '[^&]+').trim();
var snapshotUrlType = getParam('snapshot-url-type', '[^&]+').toLowerCase().trim() || 'molj';
if (snapshotUrl && snapshotUrlType) viewer.loadSnapshotFromUrl(snapshotUrl, snapshotUrlType);
var structureUrl = getParam('structure-url', '[^&]+').trim();
var structureUrlFormat = getParam('structure-url-format', '[a-z]+').toLowerCase().trim();
var structureUrlIsBinary = getParam('structure-url-is-binary', '[^&]+').trim() === '1';
if (structureUrl) viewer.loadStructureFromUrl(structureUrl, structureUrlFormat, structureUrlIsBinary);
var pdb = getParam('pdb', '[^&]+').trim();
if (pdb) viewer.loadPdb(pdb);
var pdbDev = getParam('pdb-dev', '[^&]+').trim();
if (pdbDev) viewer.loadPdbDev(pdbDev);
var emdb = getParam('emdb', '[^&]+').trim();
if (emdb) viewer.loadEmdb(emdb);
</script>
<!-- __MOLSTAR_ANALYTICS__ -->
</body>

View File

@@ -1,412 +1,12 @@
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 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 { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
import { CellPack } from '../../extensions/cellpack';
import { DnatcoConfalPyramids } from '../../extensions/dnatco';
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
import { GeometryExport } from '../../extensions/geo-export';
import { Mp4Export } from '../../extensions/mp4-export';
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
import { RCSBAssemblySymmetry, RCSBValidationReport } from '../../extensions/rcsb';
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
import { StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
import { BuildInStructureFormat } from '../../mol-plugin-state/formats/structure';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
import { createPlugin } from '../../mol-plugin-ui';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
import { PluginConfig } from '../../mol-plugin/config';
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
import { PluginSpec } from '../../mol-plugin/spec';
import { PluginState } from '../../mol-plugin/state';
import { StateObjectSelector } from '../../mol-state';
import { Asset } from '../../mol-util/assets';
import { Color } from '../../mol-util/color';
import '../../mol-util/polyfill';
import { ObjectKeys } from '../../mol-util/type-helpers';
import './embedded.html';
import './favicon.ico';
import './index.html';
require('mol-plugin-ui/skin/light.scss');
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
export { setDebugMode, setProductionMode } from '../../mol-util/debug';
const CustomFormats = [
['g3d', G3dProvider] as const
];
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),
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
'g3d': PluginSpec.Behavior(G3DFormat),
'mp4-export': PluginSpec.Behavior(Mp4Export),
'geo-export': PluginSpec.Behavior(GeometryExport)
};
const DefaultViewerOptions = {
customFormats: CustomFormats as [string, DataFormatProvider][],
extensions: ObjectKeys(Extensions),
layoutIsExpanded: true,
layoutShowControls: true,
layoutShowRemoteState: true,
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
layoutShowSequence: true,
layoutShowLog: true,
layoutShowLeftPanel: true,
collapseLeftPanel: false,
collapseRightPanel: false,
disableAntialiasing: PluginConfig.General.DisableAntialiasing.defaultValue,
pixelScale: PluginConfig.General.PixelScale.defaultValue,
pickScale: PluginConfig.General.PickScale.defaultValue,
pickPadding: PluginConfig.General.PickPadding.defaultValue,
enableWboit: PluginConfig.General.EnableWboit.defaultValue,
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,
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
};
type ViewerOptions = typeof DefaultViewerOptions;
export class Viewer {
plugin: PluginUIContext
constructor(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
const o = { ...DefaultViewerOptions, ...options };
const defaultSpec = DefaultPluginUISpec();
const spec: PluginUISpec = {
actions: defaultSpec.actions,
behaviors: [
...defaultSpec.behaviors,
...o.extensions.map(e => Extensions[e]),
],
animations: [...defaultSpec.animations || []],
customParamEditors: defaultSpec.customParamEditors,
customFormats: o?.customFormats,
layout: {
initial: {
isExpanded: o.layoutIsExpanded,
showControls: o.layoutShowControls,
controlsDisplay: o.layoutControlsDisplay,
regionState: {
bottom: 'full',
left: o.collapseLeftPanel ? 'collapsed' : 'full',
right: o.collapseRightPanel ? 'hidden' : 'full',
top: 'full',
}
},
},
components: {
...defaultSpec.components,
controls: {
...defaultSpec.components?.controls,
top: o.layoutShowSequence ? undefined : 'none',
bottom: o.layoutShowLog ? undefined : 'none',
left: o.layoutShowLeftPanel ? undefined : 'none',
},
remoteState: o.layoutShowRemoteState ? 'default' : 'none',
},
config: [
[PluginConfig.General.DisableAntialiasing, o.disableAntialiasing],
[PluginConfig.General.PixelScale, o.pixelScale],
[PluginConfig.General.PickScale, o.pickScale],
[PluginConfig.General.PickPadding, o.pickPadding],
[PluginConfig.General.EnableWboit, o.enableWboit],
[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.VolumeStreaming.Enabled, !o.volumeStreamingDisabled],
[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);
}
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, options?: LoadStructureOptions) {
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, representationParams: options?.representationParams as any },
}
}
}));
}
async loadAllModelsOrAssemblyFromUrl(url: string, format: BuiltInTrajectoryFormat = 'mmcif', isBinary = false, options?: LoadStructureOptions) {
const plugin = this.plugin;
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, 'all-models', { useDefaultIfSingleModel: true, representationPresetParams: options?.representationParams });
}
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, options?: LoadStructureOptions) {
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, representationParams: options?.representationParams as any },
}
}
}));
}
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, options?: { detail?: number }) {
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: options?.detail ?? 3,
}
}
}));
}
/**
* @example Load X-ray density from volume server
viewer.loadVolumeFromUrl({
url: 'https://www.ebi.ac.uk/pdbe/densities/x-ray/1tqn/cell?detail=3',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1.5,
color: 0x3362B2
}, {
type: 'relative',
value: 3,
color: 0x33BB33,
volumeIndex: 1
}, {
type: 'relative',
value: -3,
color: 0xBB3333,
volumeIndex: 1
}], {
entryId: ['2FO-FC', 'FO-FC'],
isLazy: true
});
* *********************
* @example Load EM density from volume server
viewer.loadVolumeFromUrl({
url: 'https://maps.rcsb.org/em/emd-30210/cell?detail=6',
format: 'dscif',
isBinary: true
}, [{
type: 'relative',
value: 1,
color: 0x3377aa
}], {
entryId: 'EMD-30210',
isLazy: true
});
*/
async loadVolumeFromUrl({ url, format, isBinary }: { url: string, format: BuildInVolumeFormat, isBinary: boolean }, isovalues: VolumeIsovalueInfo[], options?: { entryId?: string | string[], isLazy?: boolean }) {
const plugin = this.plugin;
if (!plugin.dataFormats.get(format)) {
throw new Error(`Unknown density format: ${format}`);
}
if (options?.isLazy) {
const update = this.plugin.build();
update.toRoot().apply(StateTransforms.Data.LazyVolume, {
url,
format,
entryId: options?.entryId,
isBinary,
isovalues: isovalues.map(v => ({ alpha: 1, volumeIndex: 0, ...v }))
});
return update.commit();
}
return plugin.dataTransaction(async () => {
const data = await plugin.builders.data.download({ url, isBinary }, { state: { isGhost: true } });
const parsed = await plugin.dataFormats.get(format)!.parse(plugin, data, { entryId: options?.entryId });
const firstVolume = (parsed.volume || parsed.volumes[0]) as StateObjectSelector<PluginStateObject.Volume.Data>;
if (!firstVolume?.isOk) throw new Error('Failed to parse any volume.');
const repr = plugin.build();
for (const iso of isovalues) {
repr
.to(parsed.volumes?.[iso.volumeIndex ?? 0] ?? parsed.volume)
.apply(StateTransforms.Representation.VolumeRepresentation3D, createVolumeRepresentationParams(this.plugin, firstVolume.data!, {
type: 'isosurface',
typeParams: { alpha: iso.alpha ?? 1, isoValue: iso.type === 'absolute' ? { kind: 'absolute', absoluteValue: iso.value } : { kind: 'relative', relativeValue: iso.value } },
color: 'uniform',
colorParams: { value: iso.color }
}));
}
await repr.commit();
});
}
/**
* @example
* viewer.loadTrajectory({
* model: { kind: 'model-url', url: 'villin.gro', format: 'gro' },
* coordinates: { kind: 'coordinates-url', url: 'villin.xtc', format: 'xtc', isBinary: true },
* preset: 'all-models' // or 'default'
* });
*/
async loadTrajectory(params: LoadTrajectoryParams) {
const plugin = this.plugin;
let model: StateObjectSelector, coords: StateObjectSelector;
if (params.model.kind === 'model-data' || params.model.kind === 'model-url') {
const data = params.model.kind === 'model-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const trajectory = await plugin.builders.structure.parseTrajectory(data, params.model.format ?? 'mmcif');
model = await plugin.builders.structure.createModel(trajectory);
} else {
const data = params.model.kind === 'topology-data'
? await plugin.builders.data.rawData({ data: params.model.data, label: params.modelLabel })
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
const provider = plugin.dataFormats.get(params.model.format);
model = await provider!.parse(plugin, data);
}
{
const data = params.coordinates.kind === 'coordinates-data'
? await plugin.builders.data.rawData({ data: params.coordinates.data, label: params.coordinatesLabel })
: await plugin.builders.data.download({ url: params.coordinates.url, isBinary: params.coordinates.isBinary, label: params.coordinatesLabel });
const provider = plugin.dataFormats.get(params.coordinates.format);
coords = await provider!.parse(plugin, data);
}
const trajectory = await plugin.build().toRoot()
.apply(TrajectoryFromModelAndCoordinates, {
modelRef: model.ref,
coordinatesRef: coords.ref
}, { dependsOn: [model.ref, coords.ref] })
.commit();
const preset = await plugin.builders.structure.hierarchy.applyPreset(trajectory, params.preset ?? 'default');
return { model, coords, preset };
}
handleResize() {
this.plugin.layout.events.updated.next(void 0);
}
}
export interface LoadStructureOptions {
representationParams?: StructureRepresentationPresetProvider.CommonParams
}
export interface VolumeIsovalueInfo {
type: 'absolute' | 'relative',
value: number,
color: Color,
alpha?: number,
volumeIndex?: number
}
export interface LoadTrajectoryParams {
model: { kind: 'model-url', url: string, format?: BuiltInTrajectoryFormat /* mmcif */, isBinary?: boolean }
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array, format?: BuiltInTrajectoryFormat /* mmcif */ }
| { kind: 'topology-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
modelLabel?: string,
coordinates: { kind: 'coordinates-url', url: string, format: BuildInStructureFormat, isBinary?: boolean }
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuildInStructureFormat },
coordinatesLabel?: string,
preset?: keyof PresetTrajectoryHierarchy
}
export * from './app';

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env node
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Josh McMenemy <josh.mcmenemy@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as argparse from 'argparse';
@@ -14,7 +15,7 @@ const writeFile = util.promisify(fs.writeFile);
import { DatabaseCollection } from '../../mol-data/db';
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
import { ensureDataAvailable, readCCD } from './util';
import { DefaultDataOptions, ensureDataAvailable, readCCD } from './util';
function extractIonNames(ccd: DatabaseCollection<CCD_Schema>) {
const ionNames: string[] = [];
@@ -31,11 +32,11 @@ function extractIonNames(ccd: DatabaseCollection<CCD_Schema>) {
function writeIonNamesFile(filePath: string, ionNames: string[]) {
const output = `/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated ion names params file. Names extracted from CCD components.
*
* @author molstar/chem-comp-dict/create-table cli
* @author molstar/chem-comp-dict/create-ions cli
*/
export const IonNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});
@@ -43,8 +44,8 @@ export const IonNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").re
writeFile(filePath, output);
}
async function run(out: string, forceDownload = false) {
await ensureDataAvailable(forceDownload);
async function run(out: string, options = DefaultDataOptions) {
await ensureDataAvailable(options);
const ccd = await readCCD();
const ionNames = extractIonNames(ccd);
if (!fs.existsSync(path.dirname(out))) {
@@ -64,10 +65,15 @@ parser.add_argument('--forceDownload', '-f', {
action: 'store_true',
help: 'Force download of CCD and PVCD.'
});
parser.add_argument('--ccdUrl', '-c', {
help: 'Fetch the CCD from a custom URL. This forces download of the CCD.',
required: false
});
interface Args {
out: string,
forceDownload?: boolean,
ccdUrl?: string
}
const args: Args = parser.parse_args();
run(args.out, args.forceDownload);
run(args.out, { forceDownload: args.forceDownload, ccdUrl: args.ccdUrl });

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env node
/**
* Copyright (c) 2022 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 path from 'path';
import util from 'util';
import fs from 'fs';
require('util.promisify').shim();
const writeFile = util.promisify(fs.writeFile);
import { DatabaseCollection } from '../../mol-data/db';
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
import { DefaultDataOptions, ensureDataAvailable, readCCD } from './util';
function extractSaccharideNames(ccd: DatabaseCollection<CCD_Schema>) {
const saccharideNames: string[] = [];
for (const k in ccd) {
const { chem_comp } = ccd[k];
const type = chem_comp.type.value(0).toUpperCase();
if (type.includes('SACCHARIDE')) {
saccharideNames.push(chem_comp.id.value(0));
}
}
// these are extra saccharides that don't have SACCHARIDE in their type
saccharideNames.push(
'UMQ', // UNDECYL-MALTOSIDE, via GlyFinder
'SQD', // SULFOQUINOVOSYLDIACYLGLYCEROL, via GlyFinder
);
return saccharideNames;
}
function writeSaccharideNamesFile(filePath: string, ionNames: string[]) {
const output = `/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated ion names params file. Names extracted from CCD components.
*
* @author molstar/cli/chem-comp-dict/create-saccharides
*/
export const SaccharideNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});
`;
writeFile(filePath, output);
}
async function run(out: string, options = DefaultDataOptions) {
await ensureDataAvailable(options);
const ccd = await readCCD();
const saccharideNames = extractSaccharideNames(ccd);
if (!fs.existsSync(path.dirname(out))) {
fs.mkdirSync(path.dirname(out));
}
writeSaccharideNamesFile(out, saccharideNames);
}
const parser = new argparse.ArgumentParser({
add_help: true,
description: 'Extract and save SaccharideNames from CCD.'
});
parser.add_argument('out', {
help: 'Generated file output path.'
});
parser.add_argument('--forceDownload', '-f', {
action: 'store_true',
help: 'Force download of CCD and PVCD.'
});
parser.add_argument('--ccdUrl', '-c', {
help: 'Fetch the CCD from a custom URL. This forces download of the CCD.',
required: false
});
interface Args {
out: string,
forceDownload?: boolean,
ccdUrl?: string
}
const args: Args = parser.parse_args();
run(args.out, { forceDownload: args.forceDownload, ccdUrl: args.ccdUrl });

View File

@@ -18,7 +18,7 @@ import { SetUtils } from '../../mol-util/set';
import { DefaultMap } from '../../mol-util/map';
import { mmCIF_chemCompBond_schema } from '../../mol-io/reader/cif/schema/mmcif-extras';
import { ccd_chemCompAtom_schema } from '../../mol-io/reader/cif/schema/ccd-extras';
import { ensureDataAvailable, getEncodedCif, readCCD, readPVCD } from './util';
import { DefaultDataOptions, ensureDataAvailable, getEncodedCif, readCCD, readPVCD } from './util';
type CCB = Table<CCD_Schema['chem_comp_bond']>
type CCA = Table<CCD_Schema['chem_comp_atom']>
@@ -239,8 +239,8 @@ function createAtoms(ccd: DatabaseCollection<CCD_Schema>, pvcd: DatabaseCollecti
);
}
async function run(out: string, binary = false, forceDownload = false, ccaOut?: string) {
await ensureDataAvailable(forceDownload);
async function run(out: string, binary = false, options = DefaultDataOptions, ccaOut?: string) {
await ensureDataAvailable(options);
const ccd = await readCCD();
const pvcd = await readPVCD();
@@ -283,12 +283,22 @@ parser.add_argument('--ccaOut', '-a', {
help: 'Optional generated file output path for chem_comp_atom data.',
required: false
});
parser.add_argument('--ccdUrl', '-c', {
help: 'Fetch the CCD from a custom URL. This forces download of the CCD.',
required: false
});
parser.add_argument('--pvcdUrl', '-p', {
help: 'Fetch the PVCD from a custom URL. This forces download of the PVCD.',
required: false
});
interface Args {
out: string,
forceDownload?: boolean,
binary?: boolean,
ccaOut?: string
ccaOut?: string,
ccdUrl?: string,
pvcdUrl?: string
}
const args: Args = parser.parse_args();
run(args.out, args.binary, args.forceDownload, args.ccaOut);
run(args.out, args.binary, { forceDownload: args.forceDownload, ccdUrl: args.ccdUrl, pvcdUrl: args.pvcdUrl }, args.ccaOut);

View File

@@ -35,9 +35,9 @@ export async function ensureAvailable(path: string, url: string, forceDownload =
}
}
export async function ensureDataAvailable(forceDownload = false) {
await ensureAvailable(CCD_PATH, CCD_URL, forceDownload);
await ensureAvailable(PVCD_PATH, PVCD_URL, forceDownload);
export async function ensureDataAvailable(options: DataOptions) {
await ensureAvailable(CCD_PATH, options.ccdUrl || CCD_URL, !!options.ccdUrl || options.forceDownload);
await ensureAvailable(PVCD_PATH, options.pvcdUrl || PVCD_URL, !!options.pvcdUrl || options.forceDownload);
}
export async function readFileAsCollection<S extends Database.Schema>(path: string, schema: S) {
@@ -68,6 +68,16 @@ export function getEncodedCif(name: string, database: Database<Database.Schema>,
return encoder.getData();
}
export type DataOptions = {
ccdUrl?: string,
pvcdUrl?: string,
forceDownload?: boolean
}
export const DefaultDataOptions: DataOptions = {
forceDownload: false
};
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');

View File

@@ -71,7 +71,7 @@ function classify(name: string, field: CifField): CifWriter.Field {
}
export function convert(path: string, asText = false, hints?: EncodingStrategyHint[], filter?: string) {
return Task.create<Uint8Array>('BinaryCIF', async ctx => {
return Task.create<Uint8Array>('Convert CIF', async ctx => {
const encodingProvider: BinaryEncodingProvider = hints
? CifWriter.createEncodingProviderFromJsonConfig(hints)
: { get: (c, f) => void 0 };

View File

@@ -18,7 +18,7 @@ async function process(srcPath: string, outPath: string, configPath?: string, fi
const config = configPath ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : void 0;
const filter = filterPath ? fs.readFileSync(filterPath, 'utf8') : void 0;
const res = await convert(srcPath, false, config, filter);
const res = await convert(srcPath, srcPath.toLowerCase().indexOf('.bcif') > 0, config, filter);
await write(outPath, res);
}
@@ -38,13 +38,13 @@ function run(args: Args) {
const parser = new argparse.ArgumentParser({
add_help: true,
description: 'Convert any CIF file to a BCIF file'
description: 'Convert any BCIF file to a CIF file or vice versa'
});
parser.add_argument('src', {
help: 'Source CIF path'
help: 'Source file path'
});
parser.add_argument('out', {
help: 'Output BCIF path'
help: 'Output file path'
});
parser.add_argument('-c', '--config', {
help: 'Optional encoding strategy/precision config path',

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node
/**
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -35,20 +35,16 @@ async function runGenerateSchemaMmcif(name: string, fieldNamesPath: string, type
const ihmDic = await parseCifText(fs.readFileSync(IHM_DIC_PATH, 'utf8')).run();
if (ihmDic.isError) throw ihmDic;
await ensureCarbBranchDicAvailable();
const carbBranchDic = await parseCifText(fs.readFileSync(CARB_BRANCH_DIC_PATH, 'utf8')).run();
if (carbBranchDic.isError) throw carbBranchDic;
await ensureCarbCompDicAvailable();
const carbCompDic = await parseCifText(fs.readFileSync(CARB_COMP_DIC_PATH, 'utf8')).run();
if (carbCompDic.isError) throw carbCompDic;
await ensureMaDicAvailable();
const maDic = await parseCifText(fs.readFileSync(MA_DIC_PATH, 'utf8')).run();
if (maDic.isError) throw maDic;
const mmcifDicVersion = getDicVersion(mmcifDic.result.blocks[0]);
const ihmDicVersion = getDicVersion(ihmDic.result.blocks[0]);
const carbDicVersion = 'draft';
const version = `Dictionary versions: mmCIF ${mmcifDicVersion}, IHM ${ihmDicVersion}, CARB ${carbDicVersion}.`;
const maDicVersion = getDicVersion(maDic.result.blocks[0]);
const version = `Dictionary versions: mmCIF ${mmcifDicVersion}, IHM ${ihmDicVersion}, MA ${maDicVersion}.`;
const frames: CifFrame[] = [...mmcifDic.result.blocks[0].saveFrames, ...ihmDic.result.blocks[0].saveFrames, ...carbBranchDic.result.blocks[0].saveFrames, ...carbCompDic.result.blocks[0].saveFrames];
const frames: CifFrame[] = [...mmcifDic.result.blocks[0].saveFrames, ...ihmDic.result.blocks[0].saveFrames, ...maDic.result.blocks[0].saveFrames];
const schema = generateSchema(frames);
await runGenerateSchema(name, version, schema, fieldNamesPath, typescript, out, moldbImportPath, addAliases);
@@ -139,8 +135,7 @@ async function getFieldNamesFilter(fieldNamesPath: string): Promise<Filter> {
async function ensureMmcifDicAvailable() { await ensureDicAvailable(MMCIF_DIC_PATH, MMCIF_DIC_URL); }
async function ensureIhmDicAvailable() { await ensureDicAvailable(IHM_DIC_PATH, IHM_DIC_URL); }
async function ensureCarbBranchDicAvailable() { await ensureDicAvailable(CARB_BRANCH_DIC_PATH, CARB_BRANCH_DIC_URL); }
async function ensureCarbCompDicAvailable() { await ensureDicAvailable(CARB_COMP_DIC_PATH, CARB_COMP_DIC_URL); }
async function ensureMaDicAvailable() { await ensureDicAvailable(MA_DIC_PATH, MA_DIC_URL); }
async function ensureCifCoreDicAvailable() {
await ensureDicAvailable(CIF_CORE_DIC_PATH, CIF_CORE_DIC_URL);
await ensureDicAvailable(CIF_CORE_ENUM_PATH, CIF_CORE_ENUM_URL);
@@ -165,10 +160,8 @@ const MMCIF_DIC_PATH = `${DIC_DIR}/mmcif_pdbx_v50.dic`;
const MMCIF_DIC_URL = 'http://mmcif.wwpdb.org/dictionaries/ascii/mmcif_pdbx_v50.dic';
const IHM_DIC_PATH = `${DIC_DIR}/ihm-extension.dic`;
const IHM_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/IHM-dictionary/master/ihm-extension.dic';
const CARB_BRANCH_DIC_PATH = `${DIC_DIR}/entity_branch-extension.dic`;
const CARB_BRANCH_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/entity_branch-extension.dic';
const CARB_COMP_DIC_PATH = `${DIC_DIR}/chem_comp-extension.dic`;
const CARB_COMP_DIC_URL = 'https://raw.githubusercontent.com/pdbxmmcifwg/carbohydrate-extension/master/dict/chem_comp-extension.dic';
const MA_DIC_PATH = `${DIC_DIR}/ma-extension.dic`;
const MA_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/ModelCIF/master/dist/mmcif_ma.dic';
const CIF_CORE_DIC_PATH = `${DIC_DIR}/cif_core.dic`;
const CIF_CORE_DIC_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/cif_core.dic';

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -13,15 +13,17 @@ export function getFieldType(type: string, description: string, values?: string[
switch (type) {
// mmCIF
case 'code':
case 'ucode':
case 'line':
case 'uline':
case 'text':
case 'char':
case 'uchar3':
case 'uchar1':
case 'boolean':
return values && values.length ? EnumCol(values, 'str', description) : StrCol(description);
case 'ucode':
case 'uline':
case 'uchar3':
case 'uchar1':
// only force lower-case for enums
return values && values.length ? EnumCol(values.map(x => x.toLowerCase()), 'lstr', description) : StrCol(description);
case 'aliasname':
case 'name':
case 'idname':
@@ -49,6 +51,7 @@ export function getFieldType(type: string, description: string, values?: string[
case 'operation_expression':
case 'point_symmetry':
case '4x3_matrix':
case '3x4_matrix':
case '3x4_matrices':
case 'point_group':
case 'point_group_helical':
@@ -68,6 +71,7 @@ export function getFieldType(type: string, description: string, values?: string[
case 'ec-type':
case 'ucode-alphanum-csv':
case 'id_list':
case 'entity_id_list':
return ListCol('str', ',', description);
case 'id_list_spc':
return ListCol('str', ' ', description);
@@ -148,7 +152,7 @@ function getImportFrames(d: Data.CifFrame, imports: Imports) {
}
/** get field from given or linked category */
function getField(category: string, field: string, d: Data.CifFrame, imports: Imports, ctx: FrameData): Data.CifField|undefined {
function getField(category: string, field: string, d: Data.CifFrame, imports: Imports, ctx: FrameData): Data.CifField | undefined {
const { categories, links } = ctx;
const cat = d.categories[category];
if (cat) {

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -10,7 +10,7 @@ import { FieldPath } from '../../../mol-io/reader/cif/schema';
function header(name: string, info: string, moldataImportPath: string) {
return `/**
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated '${name}' schema file. ${info}
*
@@ -35,13 +35,17 @@ function getTypeShorthands(schema: Database, fields?: Filter) {
const { columns } = schema.tables[table];
Object.keys(columns).forEach(columnName => {
if (fields && !fields[table][columnName]) return;
types.add(schema.tables[table].columns[columnName].type);
const col = schema.tables[table].columns[columnName];
if (col.type === 'enum') types.add(col.subType);
types.add(col.type);
});
});
const shorthands: string[] = [];
types.forEach(type => {
switch (type) {
case 'str': shorthands.push('const str = Schema.str;'); break;
case 'ustr': shorthands.push('const ustr = Schema.ustr;'); break;
case 'lstr': shorthands.push('const lstr = Schema.lstr;'); break;
case 'int': shorthands.push('const int = Schema.int;'); break;
case 'float': shorthands.push('const float = Schema.float;'); break;
case 'coord': shorthands.push('const coord = Schema.coord;'); break;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -29,8 +29,8 @@ export function FloatCol(description: string): FloatCol { return { type: 'float'
export type CoordCol = { type: 'coord' } & BaseCol
export function CoordCol(description: string): CoordCol { return { type: 'coord', description }; }
export type EnumCol = { type: 'enum', subType: 'int' | 'str', values: string[] } & BaseCol
export function EnumCol(values: string[], subType: 'int' | 'str', description: string): EnumCol {
export type EnumCol = { type: 'enum', subType: 'int' | 'str' | 'ustr' | 'lstr', values: string[] } & BaseCol
export function EnumCol(values: string[], subType: 'int' | 'str' | 'ustr' | 'lstr', description: string): EnumCol {
return { type: 'enum', description, values, subType };
}

View File

@@ -25,7 +25,7 @@ async function readFile(path: string) {
}
}
async function parseCif(data: string|Uint8Array) {
async function parseCif(data: string | Uint8Array) {
const comp = CIF.parse(data);
const parsed = await comp.run(p => console.log(Progress.format(p)), 250);
if (parsed.isError) throw parsed;

View File

@@ -38,7 +38,7 @@ function print(volume: Volume) {
}
async function doMesh(volume: Volume, filename: string) {
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) })).run();
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, -1, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) })).run();
console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount });
// Export the mesh in OBJ format.

View File

@@ -4,16 +4,16 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
import { AlphaOrbitalsExample } from '.';
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior';
import { PluginContextContainer } from '../../mol-plugin-ui/plugin';
export function mountControls(orbitals: AlphaOrbitalsExample, parent: Element) {
ReactDOM.render(<PluginContextContainer plugin={orbitals.plugin}>
createRoot(parent).render(<PluginContextContainer plugin={orbitals.plugin}>
<Controls orbitals={orbitals} />
</PluginContextContainer>, parent);
</PluginContextContainer>);
}
function Controls({ orbitals }: { orbitals: AlphaOrbitalsExample }) {

View File

@@ -55,7 +55,19 @@
</a>
</div>
<script>
function getParam(name, regex) {
var r = new RegExp(name + '=' + '(' + regex + ')[&]?', 'i');
return decodeURIComponent(((window.location.search || '').match(r) || [])[1] || '');
}
var debugMode = getParam('debug-mode', '[^&]+').trim() === '1';
if (debugMode) AlphaOrbitalsExample.setDebugMode(debugMode);
var timingMode = getParam('timing-mode', '[^&]+').trim() === '1';
if (timingMode) AlphaOrbitalsExample.setTimingMode(timingMode);
AlphaOrbitalsExample.init('app')
</script>
<!-- __MOLSTAR_ANALYTICS__ -->
</body>
</html>

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
@@ -11,7 +11,7 @@ import { SphericalBasisOrder } from '../../extensions/alpha-orbitals/spherical-f
import { BasisAndOrbitals, CreateOrbitalDensityVolume, CreateOrbitalRepresentation3D, CreateOrbitalVolume, StaticBasisAndOrbitals } from '../../extensions/alpha-orbitals/transforms';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { createPluginAsync } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
@@ -25,6 +25,8 @@ import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
import './index.html';
require('mol-plugin-ui/skin/light.scss');
import { setDebugMode, setTimingMode, consoleStats } from '../../mol-util/debug';
interface DemoInput {
moleculeSdf: string,
basis: Basis,
@@ -54,7 +56,7 @@ export class AlphaOrbitalsExample {
async init(target: string | HTMLElement) {
const defaultSpec = DefaultPluginUISpec();
this.plugin = await createPluginAsync(typeof target === 'string' ? document.getElementById(target)! : target, {
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
...defaultSpec,
layout: {
initial: {
@@ -67,7 +69,7 @@ export class AlphaOrbitalsExample {
},
canvas3d: {
camera: {
helper: { axes: { name: 'off', params: { } } }
helper: { axes: { name: 'off', params: {} } }
}
},
config: [
@@ -97,7 +99,7 @@ export class AlphaOrbitalsExample {
}
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);
readonly state = new BehaviorSubject<Params>({ show: { name: 'orbital', params: { index: 32 } }, isoValue: 1, gpuSurface: false });
readonly state = new BehaviorSubject<Params>({ show: { name: 'orbital', params: { index: 32 } }, isoValue: 1, gpuSurface: true });
private selectors?: Selectors = void 0;
private basis?: StateObjectSelector<BasisAndOrbitals> = void 0;
@@ -170,12 +172,11 @@ export class AlphaOrbitalsExample {
return {
alpha: 0.85,
color,
directVolume: this.state.value.gpuSurface,
kind,
relativeIsovalue: this.state.value.isoValue,
pickable: false,
xrayShaded: true,
tryUseGpu: false
tryUseGpu: true
};
}
@@ -219,4 +220,7 @@ export class AlphaOrbitalsExample {
}
}
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
(window as any).AlphaOrbitalsExample = new AlphaOrbitalsExample();
(window as any).AlphaOrbitalsExample.setDebugMode = setDebugMode;
(window as any).AlphaOrbitalsExample.setTimingMode = setTimingMode;
(window as any).AlphaOrbitalsExample.consoleStats = consoleStats;

View File

@@ -69,8 +69,9 @@
$('format').value = format;
$('format').onchange = function (e) { format = e.target.value; }
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
BasicMolStarWrapper.setBackground(0xffffff);
BasicMolStarWrapper.init('app' /** or document.getElementById('app') */).then(() => {
BasicMolStarWrapper.setBackground(0xffffff);
});
addControl('Load Asym Unit', () => BasicMolStarWrapper.load({ url: url, format: format }));
addControl('Load Assembly', () => BasicMolStarWrapper.load({ url: url, format: format, assemblyId: assemblyId }));

View File

@@ -9,7 +9,7 @@ import { EmptyLoci } from '../../mol-model/loci';
import { StructureSelection } from '../../mol-model/structure';
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/model-index';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { createPlugin } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
@@ -28,8 +28,8 @@ type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: bo
class BasicWrapper {
plugin: PluginUIContext;
init(target: string | HTMLElement) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
async init(target: string | HTMLElement) {
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginUISpec(),
layout: {
initial: {
@@ -60,7 +60,7 @@ class BasicWrapper {
params: { id: assemblyId }
} : {
name: 'model',
params: { }
params: {}
},
showUnitcell: false,
representationPreset: 'auto'
@@ -74,12 +74,20 @@ class BasicWrapper {
toggleSpin() {
if (!this.plugin.canvas3d) return;
const trackball = this.plugin.canvas3d.props.trackball;
PluginCommands.Canvas3D.SetSettings(this.plugin, {
settings: props => {
props.trackball.spin = !props.trackball.spin;
settings: {
trackball: {
...trackball,
animate: trackball.animate.name === 'spin'
? { name: 'off', params: {} }
: { name: 'spin', params: { speed: 1 } }
}
}
});
if (!this.plugin.canvas3d.props.trackball.spin) PluginCommands.Camera.Reset(this.plugin, {});
if (this.plugin.canvas3d.props.trackball.animate.name !== 'spin') {
PluginCommands.Camera.Reset(this.plugin, {});
}
}
private animateModelIndexTargetFps() {
@@ -95,7 +103,7 @@ class BasicWrapper {
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: { direction: 'forward' } } }); },
stop: () => this.plugin.managers.animation.stop()
}
}
};
coloring = {
applyStripes: async () => {
@@ -119,7 +127,7 @@ class BasicWrapper {
}
});
}
}
};
interactivity = {
highlightOn: () => {
@@ -137,7 +145,7 @@ class BasicWrapper {
clearHighlight: () => {
this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
}
}
};
tests = {
staticSuperposition: async () => {
@@ -168,7 +176,7 @@ class BasicWrapper {
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-1' });
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-2' });
}
}
};
}
(window as any).BasicMolStarWrapper = new BasicWrapper();

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*
* Example command-line application generating images of PDB structures
* Build: npm install --no-save gl jpeg-js pngjs // these packages are not listed in dependencies for performance reasons
* npm run build
* Run: node lib/commonjs/examples/image-renderer 1cbs ../outputs_1cbs/
*/
import { ArgumentParser } from 'argparse';
import fs from 'fs';
import path from 'path';
import { Download, ParseCif } from '../../mol-plugin-state/transforms/data';
import { ModelFromTrajectory, StructureComponent, StructureFromModel, TrajectoryFromMmCif } from '../../mol-plugin-state/transforms/model';
import { StructureRepresentation3D } from '../../mol-plugin-state/transforms/representation';
import { HeadlessPluginContext } from '../../mol-plugin/headless-plugin-context';
import { DefaultPluginSpec } from '../../mol-plugin/spec';
import { STYLIZED_POSTPROCESSING } from '../../mol-plugin/util/headless-screenshot';
interface Args {
pdbId: string,
outDirectory: string
}
function parseArguments(): Args {
const parser = new ArgumentParser({ description: 'Example command-line application generating images of PDB structures' });
parser.add_argument('pdbId', { help: 'PDB identifier' });
parser.add_argument('outDirectory', { help: 'Directory for outputs' });
const args = parser.parse_args();
return { ...args };
}
async function main() {
const args = parseArguments();
const url = `https://www.ebi.ac.uk/pdbe/entry-files/download/${args.pdbId}.bcif`;
console.log('PDB ID:', args.pdbId);
console.log('Source URL:', url);
console.log('Outputs:', args.outDirectory);
// Create a headless plugin
const plugin = new HeadlessPluginContext(DefaultPluginSpec(), { width: 800, height: 800 });
await plugin.init();
// Download and visualize data in the plugin
const update = plugin.build();
const structure = update.toRoot()
.apply(Download, { url, isBinary: true })
.apply(ParseCif)
.apply(TrajectoryFromMmCif)
.apply(ModelFromTrajectory)
.apply(StructureFromModel);
const polymer = structure.apply(StructureComponent, { type: { name: 'static', params: 'polymer' } });
const ligand = structure.apply(StructureComponent, { type: { name: 'static', params: 'ligand' } });
polymer.apply(StructureRepresentation3D, {
type: { name: 'cartoon', params: { alpha: 1 } },
colorTheme: { name: 'sequence-id', params: {} },
});
ligand.apply(StructureRepresentation3D, {
type: { name: 'ball-and-stick', params: { sizeFactor: 1 } },
colorTheme: { name: 'element-symbol', params: { carbonColor: { name: 'element-symbol', params: {} } } },
sizeTheme: { name: 'physical', params: {} },
});
await update.commit();
// Export images
fs.mkdirSync(args.outDirectory, { recursive: true });
await plugin.saveImage(path.join(args.outDirectory, 'basic.png'));
await plugin.saveImage(path.join(args.outDirectory, 'basic.jpg'));
await plugin.saveImage(path.join(args.outDirectory, 'large.png'), { width: 1600, height: 1200 });
await plugin.saveImage(path.join(args.outDirectory, 'large.jpg'), { width: 1600, height: 1200 });
await plugin.saveImage(path.join(args.outDirectory, 'stylized.png'), undefined, STYLIZED_POSTPROCESSING);
await plugin.saveImage(path.join(args.outDirectory, 'stylized.jpg'), undefined, STYLIZED_POSTPROCESSING);
await plugin.saveImage(path.join(args.outDirectory, 'stylized-compressed-jpg.jpg'), undefined, STYLIZED_POSTPROCESSING, undefined, 10);
// Export state loadable in Mol* Viewer
await plugin.saveStateSnapshot(path.join(args.outDirectory, 'molstar-state.molj'));
// Cleanup
await plugin.clear();
plugin.dispose();
}
main();

View File

@@ -45,8 +45,9 @@
<div id='controls'></div>
<div id="app"></div>
<script>
LightingDemo.init('app')
LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3)
LightingDemo.init('app').then(() => {
LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3);
});
addHeader('Example PDB IDs');
addControl('4KTC', () => LightingDemo.load({ url: 'https://models.rcsb.org/4KTC.bcif', assemblyId: '1' }, 5, 1.3));
@@ -83,5 +84,6 @@
$('controls').appendChild(h);
}
</script>
<!-- __MOLSTAR_ANALYTICS__ -->
</body>
</html>

View File

@@ -1,12 +1,12 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Canvas3DProps } from '../../mol-canvas3d/canvas3d';
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
import { createPlugin } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { PluginCommands } from '../../mol-plugin/commands';
@@ -17,44 +17,49 @@ require('mol-plugin-ui/skin/light.scss');
type LoadParams = { url: string, format?: BuiltInTrajectoryFormat, isBinary?: boolean, assemblyId?: string }
type _Preset = Pick<Canvas3DProps, 'multiSample' | 'postprocessing' | 'renderer'>
type _Preset = Pick<Canvas3DProps, 'postprocessing' | 'renderer'>
type Preset = { [K in keyof _Preset]: Partial<_Preset[K]> }
const Canvas3DPresets = {
illustrative: <Preset> {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
outline: { name: 'on', params: { scale: 1, threshold: 0.1, color: Color(0x000000) } }
},
renderer: {
style: { name: 'flat', params: {} }
illustrative: {
canvas3d: <Preset>{
postprocessing: {
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000), includeTransparent: true, } },
shadow: { name: 'off', params: {} },
},
renderer: {
ambientIntensity: 1.0,
light: []
}
}
},
occlusion: <Preset> {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15 } },
outline: { name: 'off', params: { } }
},
renderer: {
style: { name: 'matte', params: {} }
occlusion: {
canvas3d: <Preset>{
postprocessing: {
occlusion: { name: 'on', params: { samples: 32, radius: 6, bias: 1.4, blurKernelSize: 15, resolutionScale: 1 } },
outline: { name: 'off', params: {} },
shadow: { name: 'off', params: {} },
},
renderer: {
ambientIntensity: 0.4,
light: [{ inclination: 180, azimuth: 0, color: Color.fromNormalizedRgb(1.0, 1.0, 1.0),
intensity: 0.6 }]
}
}
},
standard: <Preset> {
multiSample: {
mode: 'off' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusion: { name: 'off', params: { } },
outline: { name: 'off', params: { } }
},
renderer: {
style: { name: 'matte', params: {} }
standard: {
canvas3d: <Preset>{
postprocessing: {
occlusion: { name: 'off', params: {} },
outline: { name: 'off', params: {} },
shadow: { name: 'off', params: {} },
},
renderer: {
ambientIntensity: 0.4,
light: [{ inclination: 180, azimuth: 0, color: Color.fromNormalizedRgb(1.0, 1.0, 1.0),
intensity: 0.6 }]
}
}
}
};
@@ -69,8 +74,8 @@ class LightingDemo {
private bias = 1.1;
private preset: Canvas3DPreset = 'illustrative';
init(target: string | HTMLElement) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
async init(target: string | HTMLElement) {
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginUISpec(),
layout: {
initial: {
@@ -88,25 +93,23 @@ class LightingDemo {
setPreset(preset: Canvas3DPreset) {
const props = Canvas3DPresets[preset];
if (props.postprocessing.occlusion?.name === 'on') {
props.postprocessing.occlusion.params.radius = this.radius;
props.postprocessing.occlusion.params.bias = this.bias;
if (props.canvas3d.postprocessing.occlusion?.name === 'on') {
props.canvas3d.postprocessing.occlusion.params.radius = this.radius;
props.canvas3d.postprocessing.occlusion.params.bias = this.bias;
}
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
...props,
multiSample: {
...this.plugin.canvas3d!.props.multiSample,
...props.multiSample
},
renderer: {
...this.plugin.canvas3d!.props.renderer,
...props.renderer
},
postprocessing: {
...this.plugin.canvas3d!.props.postprocessing,
...props.postprocessing
},
} });
PluginCommands.Canvas3D.SetSettings(this.plugin, {
settings: {
...props,
renderer: {
...this.plugin.canvas3d!.props.renderer,
...props.canvas3d.renderer
},
postprocessing: {
...this.plugin.canvas3d!.props.postprocessing,
...props.canvas3d.postprocessing
},
}
});
}
async load({ url, format = 'mmcif', isBinary = true, assemblyId = '' }: LoadParams, radius: number, bias: number) {
@@ -115,7 +118,7 @@ class LightingDemo {
const data = await this.plugin.builders.data.download({ url: Asset.Url(url), isBinary }, { state: { isGhost: true } });
const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
const model = await this.plugin.builders.structure.createModel(trajectory);
const structure = await this.plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : { name: 'model', params: { } });
const structure = await this.plugin.builders.structure.createStructure(model, assemblyId ? { name: 'assembly', params: { id: assemblyId } } : { name: 'model', params: {} });
const polymer = await this.plugin.builders.structure.tryCreateComponentStatic(structure, 'polymer');
if (polymer) await this.plugin.builders.structure.representation.addRepresentation(polymer, { type: 'spacefill', color: 'illustrative' });

View File

@@ -103,10 +103,11 @@
PluginWrapper.init('app' /** or document.getElementById('app') */, {
customColorList: CustomColors
}).then(() => {
PluginWrapper.setBackground(0xffffff);
loadAndSnapshot({ url: url, format: format, isBinary: isBinary, assemblyId: assemblyId, representationStyle: representationStyle });
PluginWrapper.toggleSpin();
});
PluginWrapper.setBackground(0xffffff);
loadAndSnapshot({ url: url, format: format, isBinary: isBinary, assemblyId: assemblyId, representationStyle: representationStyle });
PluginWrapper.toggleSpin();
PluginWrapper.events.modelInfo.subscribe(function (info) {
console.log('Model Info', info);

View File

@@ -10,7 +10,7 @@ import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in/mod
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
import { PluginStateObject, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { createPlugin } from '../../mol-plugin-ui';
import { createPluginUI } from '../../mol-plugin-ui/react18';
import { PluginUIContext } from '../../mol-plugin-ui/context';
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
import { CreateVolumeStreamingInfo, InitVolumeStreaming } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
@@ -43,10 +43,10 @@ class MolStarProteopediaWrapper {
plugin: PluginUIContext;
init(target: string | HTMLElement, options?: {
async init(target: string | HTMLElement, options?: {
customColorList?: number[]
}) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
this.plugin = await createPluginUI(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginUISpec(),
animations: [
AnimateModelIndex
@@ -95,7 +95,7 @@ class MolStarProteopediaWrapper {
params: { id: assemblyId }
} : {
name: 'model' as const,
params: { }
params: {}
}
};
@@ -113,7 +113,7 @@ class MolStarProteopediaWrapper {
const structure = this.getObj<PluginStateObject.Molecule.Structure>(StateElements.Assembly);
if (!structure) return;
const style = _style || { };
const style = _style || {};
const update = this.state.build();
@@ -229,7 +229,7 @@ class MolStarProteopediaWrapper {
params: { id: asmId }
} : {
name: 'model' as const,
params: { }
params: {}
}
};
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));
@@ -256,7 +256,16 @@ class MolStarProteopediaWrapper {
toggleSpin() {
if (!this.plugin.canvas3d) return;
const trackball = this.plugin.canvas3d.props.trackball;
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
PluginCommands.Canvas3D.SetSettings(this.plugin, {
settings: {
trackball: {
...trackball,
animate: trackball.animate.name === 'spin'
? { name: 'off', params: {} }
: { name: 'spin', params: { speed: 1 } }
}
}
});
}
viewport = {
@@ -269,8 +278,8 @@ class MolStarProteopediaWrapper {
camera = {
toggleSpin: () => this.toggleSpin(),
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, { })
}
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, {})
};
private animateModelIndexTargetFps() {
return Math.max(1, this.animate.modelIndex.targetFps | 0);
@@ -285,7 +294,7 @@ class MolStarProteopediaWrapper {
loop: () => { this.plugin.managers.animation.play(AnimateModelIndex, { duration: { name: 'computed', params: { targetFps: this.animateModelIndexTargetFps() } }, mode: { name: 'loop', params: { direction: 'forward' } } }); },
stop: () => this.plugin.managers.animation.stop()
}
}
};
coloring = {
evolutionaryConservation: async (params?: { sequence?: boolean, het?: boolean, keepStyle?: boolean }) => {
@@ -306,7 +315,7 @@ class MolStarProteopediaWrapper {
await PluginCommands.State.Update(this.plugin, { state, tree });
}
}
};
private experimentalDataElement?: Element = void 0;
experimentalData = {
@@ -330,17 +339,17 @@ class MolStarProteopediaWrapper {
this.experimentalDataElement = void 0;
}
}
}
};
hetGroups = {
reset: () => {
const update = this.state.build().delete(StateElements.HetGroupFocusGroup);
PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
PluginCommands.Camera.Reset(this.plugin, { });
PluginCommands.Camera.Reset(this.plugin, {});
},
focusFirst: async (compId: string, options?: { hideLabels: boolean, doNotLabelWaters: boolean }) => {
if (!this.state.transforms.has(StateElements.Assembly)) return;
await PluginCommands.Camera.Reset(this.plugin, { });
await PluginCommands.Camera.Reset(this.plugin, {});
const update = this.state.build();
@@ -397,7 +406,7 @@ class MolStarProteopediaWrapper {
const snapshot = this.plugin.canvas3d!.camera.getFocus(sphere.center, radius);
PluginCommands.Camera.SetSnapshot(this.plugin, { snapshot, durationMs: 250 });
}
}
};
snapshot = {
get: (params?: PluginState.SnapshotParams) => {
@@ -420,7 +429,7 @@ class MolStarProteopediaWrapper {
}
}
}
};
}
(window as any).MolStarProteopediaWrapper = MolStarProteopediaWrapper;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
@@ -8,6 +8,7 @@ import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsDensityGridValues } from './gpu/compute';
@@ -19,9 +20,9 @@ export function createSphericalCollocationDensityGrid(
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl!, cubeGrid, orbitals);
// console.timeEnd('gpu');
if (isTimingMode) webgl.timer.mark('createSphericalCollocationDensityGrid');
matrix = await gpuComputeAlphaOrbitalsDensityGridValues(ctx, webgl, cubeGrid, orbitals);
if (isTimingMode) webgl.timer.markEnd('createSphericalCollocationDensityGrid');
} else {
throw new Error('Missing OES_texture_float WebGL extension.');
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Inspired by https://github.com/dgasmith/gau2grid.
*
@@ -10,12 +10,11 @@ import { sortArray } from '../../mol-data/util';
import { canComputeGrid3dOnGPU } from '../../mol-gl/compute/grid3d';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Task } from '../../mol-task';
import { isTimingMode } from '../../mol-util/debug';
import { sphericalCollocation } from './collocation';
import { AlphaOrbital, createGrid, CubeGrid, CubeGridComputationParams, initCubeGrid } from './data-model';
import { gpuComputeAlphaOrbitalsGridValues } from './gpu/compute';
// setDebugMode(true);
export function createSphericalCollocationGrid(
params: CubeGridComputationParams, orbital: AlphaOrbital, webgl?: WebGLContext
): Task<CubeGrid> {
@@ -24,9 +23,9 @@ export function createSphericalCollocationGrid(
let matrix: Float32Array;
if (canComputeGrid3dOnGPU(webgl)) {
// console.time('gpu');
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl!, cubeGrid, orbital);
// console.timeEnd('gpu');
if (isTimingMode) webgl.timer.mark('createSphericalCollocationGrid');
matrix = await gpuComputeAlphaOrbitalsGridValues(ctx, webgl, cubeGrid, orbital);
if (isTimingMode) webgl.timer.markEnd('createSphericalCollocationGrid');
} else {
// console.time('cpu');
matrix = await sphericalCollocation(cubeGrid, orbital, ctx);

View File

@@ -166,7 +166,6 @@ export const CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
from: PluginStateObject.Volume.Data,
to: PluginStateObject.Volume.Representation3D,
params: {
directVolume: PD.Boolean(false),
relativeIsovalue: PD.Numeric(1, { min: 0.01, max: 5, step: 0.01 }),
kind: PD.Select<'positive' | 'negative'>('positive', [['positive', 'Positive'], ['negative', 'Negative']]),
color: PD.Color(ColorNames.blue),
@@ -217,19 +216,7 @@ function volumeParams(plugin: PluginContext, volume: PluginStateObject.Volume.Da
const value = isovalues[params.kind];
return createVolumeRepresentationParams(plugin, volume.data, params.directVolume ? {
type: 'direct-volume',
typeParams: {
alpha: params.alpha,
renderMode: {
name: 'isosurface',
params: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, singleLayer: false }
},
xrayShaded: params.xrayShaded
},
color: 'uniform',
colorParams: { value: params.color }
} : {
return createVolumeRepresentationParams(plugin, volume.data, {
type: 'isosurface',
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value ?? 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded, tryUseGpu: params.tryUseGpu },
color: 'uniform',

View File

@@ -30,7 +30,7 @@ export const ANVILMembraneOrientation = PluginBehavior.create<{ autoAttach: bool
description: 'Data calculated with ANVIL algorithm.'
},
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean }> {
private provider = MembraneOrientationProvider
private provider = MembraneOrientationProvider;
register(): void {
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);

View File

@@ -43,9 +43,9 @@ 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),
lineSizeAttenuation: PD.Boolean(false),
linesSize: PD.Numeric(0.5, { min: 0.01, max: 50, step: 0.01 }),
dashedLines: PD.Boolean(false),
};
export type BilayerRimsParams = typeof BilayerRimsParams
export type BilayerRimsProps = PD.Values<BilayerRimsParams>

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { PluginBehavior } from '../../mol-plugin/behavior/behavior';
import { PluginConfig } from '../../mol-plugin/config';
import { Color } from '../../mol-util/color/color';
// from https://visualsonline.cancer.gov/details.cfm?imageid=2304, public domain
import image_cells from './images/cells.jpg';
// created with http://alexcpeterson.com/spacescape/
import face_nebula_nx from './skyboxes/nebula/nebula_left2.jpg';
import face_nebula_ny from './skyboxes/nebula/nebula_bottom4.jpg';
import face_nebula_nz from './skyboxes/nebula/nebula_back6.jpg';
import face_nebula_px from './skyboxes/nebula/nebula_right1.jpg';
import face_nebula_py from './skyboxes/nebula/nebula_top3.jpg';
import face_nebula_pz from './skyboxes/nebula/nebula_front5.jpg';
export const Backgrounds = PluginBehavior.create<{ }>({
name: 'extension-backgrounds',
category: 'misc',
display: {
name: 'Backgrounds'
},
ctor: class extends PluginBehavior.Handler<{ }> {
register(): void {
this.ctx.config.set(PluginConfig.Background.Styles, [
[{
variant: {
name: 'radialGradient',
params: {
centerColor: Color(0xFFFFFF),
edgeColor: Color(0x808080),
ratio: 0.2,
coverage: 'viewport',
}
}
}, 'Light Radial Gradient'],
[{
variant: {
name: 'image',
params: {
source: {
name: 'url',
params: image_cells
},
lightness: 0,
saturation: 0,
opacity: 1,
coverage: 'viewport',
}
}
}, 'Normal Cells Image'],
[{
variant: {
name: 'skybox',
params: {
faces: {
name: 'urls',
params: {
nx: face_nebula_nx,
ny: face_nebula_ny,
nz: face_nebula_nz,
px: face_nebula_px,
py: face_nebula_py,
pz: face_nebula_pz,
}
},
lightness: 0,
saturation: 0,
opacity: 1,
blur: 0.3,
}
}
}, 'Purple Nebula Skybox'],
]);
}
update() {
return false;
}
unregister() {
this.ctx.config.set(PluginConfig.Background.Styles, []);
}
},
params: () => ({ })
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

10
src/extensions/backgrounds/typings.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
declare module '*.jpg' {
const value: string;
export = value;
}

View File

@@ -52,7 +52,7 @@ export interface Compartment {
}
// Primitives discribing a compartment
export const enum CompartmentPrimitiveType {
export enum CompartmentPrimitiveType {
MetaBall = 0,
Sphere = 1,
Cube = 2,

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Ludovic Autin <ludovic.autin@gmail.com>
@@ -12,7 +12,7 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Ingredient, CellPacking, CompartmentPrimitives } from './data';
import { getFromPdb, getFromCellPackDB, IngredientFiles, parseCif, parsePDBfile, getStructureMean, getFromOPM } from './util';
import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext, Unit, Trajectory } from '../../mol-model/structure';
import { trajectoryFromMmCIF, MmcifFormat } from '../../mol-model-formats/structure/mmcif';
import { trajectoryFromMmCIF } from '../../mol-model-formats/structure/mmcif';
import { trajectoryFromPDB } from '../../mol-model-formats/structure/pdb';
import { Mat4, Vec3, Quat } from '../../mol-math/linear-algebra';
import { SymmetryOperator } from '../../mol-math/geometry';
@@ -22,10 +22,6 @@ import { ParseCellPack, StructureFromCellpack, DefaultCellPackBaseUrl, Structure
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { getMatFromResamplePoints } from './curve';
import { compile } from '../../mol-script/runtime/query/compiler';
import { CifCategory, CifField } from '../../mol-io/reader/cif';
import { mmCIF_Schema } from '../../mol-io/reader/cif/schema/mmcif';
import { Column } from '../../mol-data/db';
import { createModels } from '../../mol-model-formats/structure/basic/parser';
import { CellpackPackingPreset, CellpackMembranePreset } from './preset';
import { Asset } from '../../mol-util/assets';
import { Color } from '../../mol-util/color';
@@ -141,7 +137,7 @@ async function getStructure(plugin: PluginContext, model: Model, source: Ingredi
function getTransformLegacy(trans: Vec3, rot: Quat) {
const q: Quat = Quat.create(-rot[3], rot[0], rot[1], rot[2]);
const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q);
const m: Mat4 = Mat4.fromQuat(Mat4(), q);
Mat4.transpose(m, m);
Mat4.scale(m, m, Vec3.create(-1.0, 1.0, -1.0));
Mat4.setTranslation(m, trans);
@@ -150,7 +146,7 @@ function getTransformLegacy(trans: Vec3, rot: Quat) {
function getTransform(trans: Vec3, rot: Quat) {
const q: Quat = Quat.create(-rot[0], rot[1], rot[2], -rot[3]);
const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q);
const m: Mat4 = Mat4.fromQuat(Mat4(), q);
const p: Vec3 = Vec3.create(-trans[0], trans[1], trans[2]);
Mat4.setTranslation(m, p);
return m;
@@ -213,110 +209,10 @@ function getAssembly(name: string, transforms: Mat4[], structure: Structure) {
return builder.getStructure();
}
function getCifCurve(name: string, transforms: Mat4[], model: Model) {
if (!MmcifFormat.is(model.sourceData)) throw new Error('mmcif source data needed');
const { db } = model.sourceData.data;
const d = db.atom_site;
const n = d._rowCount;
const rowCount = n * transforms.length;
const { offsets, count } = model.atomicHierarchy.chainAtomSegments;
const x = d.Cartn_x.toArray();
const y = d.Cartn_y.toArray();
const z = d.Cartn_z.toArray();
const Cartn_x = new Float32Array(rowCount);
const Cartn_y = new Float32Array(rowCount);
const Cartn_z = new Float32Array(rowCount);
const map = new Uint32Array(rowCount);
const seq = new Int32Array(rowCount);
let offset = 0;
for (let c = 0; c < count; ++c) {
const cStart = offsets[c];
const cEnd = offsets[c + 1];
const cLength = cEnd - cStart;
for (let t = 0, tl = transforms.length; t < tl; ++t) {
const m = transforms[t];
for (let j = cStart; j < cEnd; ++j) {
const i = offset + j - cStart;
const xj = x[j], yj = y[j], zj = z[j];
Cartn_x[i] = m[0] * xj + m[4] * yj + m[8] * zj + m[12];
Cartn_y[i] = m[1] * xj + m[5] * yj + m[9] * zj + m[13];
Cartn_z[i] = m[2] * xj + m[6] * yj + m[10] * zj + m[14];
map[i] = j;
seq[i] = t + 1;
}
offset += cLength;
}
}
function multColumn<T>(column: Column<T>) {
const array = column.toArray();
return Column.ofLambda({
value: row => array[map[row]],
areValuesEqual: (rowA, rowB) => map[rowA] === map[rowB] || array[map[rowA]] === array[map[rowB]],
rowCount, schema: column.schema
});
}
const _atom_site: CifCategory.SomeFields<mmCIF_Schema['atom_site']> = {
auth_asym_id: CifField.ofColumn(multColumn(d.auth_asym_id)),
auth_atom_id: CifField.ofColumn(multColumn(d.auth_atom_id)),
auth_comp_id: CifField.ofColumn(multColumn(d.auth_comp_id)),
auth_seq_id: CifField.ofNumbers(seq),
B_iso_or_equiv: CifField.ofColumn(Column.ofConst(0, rowCount, Column.Schema.float)),
Cartn_x: CifField.ofNumbers(Cartn_x),
Cartn_y: CifField.ofNumbers(Cartn_y),
Cartn_z: CifField.ofNumbers(Cartn_z),
group_PDB: CifField.ofColumn(Column.ofConst('ATOM', rowCount, Column.Schema.str)),
id: CifField.ofColumn(Column.ofLambda({
value: row => row,
areValuesEqual: (rowA, rowB) => rowA === rowB,
rowCount, schema: d.id.schema,
})),
label_alt_id: CifField.ofColumn(multColumn(d.label_alt_id)),
label_asym_id: CifField.ofColumn(multColumn(d.label_asym_id)),
label_atom_id: CifField.ofColumn(multColumn(d.label_atom_id)),
label_comp_id: CifField.ofColumn(multColumn(d.label_comp_id)),
label_seq_id: CifField.ofNumbers(seq),
label_entity_id: CifField.ofColumn(Column.ofConst('1', rowCount, Column.Schema.str)),
occupancy: CifField.ofColumn(Column.ofConst(1, rowCount, Column.Schema.float)),
type_symbol: CifField.ofColumn(multColumn(d.type_symbol)),
pdbx_PDB_ins_code: CifField.ofColumn(Column.ofConst('', rowCount, Column.Schema.str)),
pdbx_PDB_model_num: CifField.ofColumn(Column.ofConst(1, rowCount, Column.Schema.int)),
};
const categories = {
entity: CifCategory.ofTable('entity', db.entity),
chem_comp: CifCategory.ofTable('chem_comp', db.chem_comp),
atom_site: CifCategory.ofFields('atom_site', _atom_site)
};
return {
header: name,
categoryNames: Object.keys(categories),
categories
};
}
async function getCurve(plugin: PluginContext, name: string, ingredient: Ingredient, transforms: Mat4[], model: Model) {
const cif = getCifCurve(name, transforms, model);
const curveModelTask = Task.create('Curve Model', async ctx => {
const format = MmcifFormat.fromFrame(cif);
const models = await createModels(format.data.db, format, ctx);
return models.representative;
});
const curveModel = await plugin.runTask(curveModelTask);
// ingredient.source.selection = undefined;
return getStructure(plugin, curveModel, ingredient);
async function getCurve(name: string, transforms: Mat4[], model: Model) {
const structure = Structure.ofModel(model);
const assembly = getAssembly(name, transforms, structure);
return assembly;
}
async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredient, baseUrl: string, ingredientFiles: IngredientFiles, trajCache: TrajectoryCache, location: 'surface' | 'interior' | 'cytoplasme') {
@@ -337,10 +233,10 @@ async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredi
if (!model) return;
let structure: Structure;
if (nbCurve) {
structure = await getCurve(plugin, name, ingredient, getCurveTransforms(ingredient), model);
structure = await getCurve(name, getCurveTransforms(ingredient), model);
} else {
if ((!results || results.length === 0)) return;
let bu: string|undefined = source.bu ? source.bu : undefined;
let bu: string | undefined = source.bu ? source.bu : undefined;
if (bu) {
if (bu === 'AU') {
bu = undefined;
@@ -361,7 +257,7 @@ async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredi
structure = Structure.transform(structure, m1);
if (ingredient.offset) {
const o: Vec3 = Vec3.create(ingredient.offset[0], ingredient.offset[1], ingredient.offset[2]);
if (!Vec3.exactEquals(o, Vec3.zero())) { // -1, 1, 4e-16 ??
if (!Vec3.exactEquals(o, Vec3())) { // -1, 1, 4e-16 ??
if (location !== 'surface') {
Vec3.negate(o, o);
}
@@ -375,7 +271,7 @@ async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredi
if (!Vec3.exactEquals(p, Vec3.unitZ)) {
const q: Quat = Quat.identity();
Quat.rotationTo(q, p, Vec3.unitZ);
const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q);
const m: Mat4 = Mat4.fromQuat(Mat4(), q);
structure = Structure.transform(structure, m);
}
}
@@ -519,6 +415,7 @@ async function loadMembrane(plugin: PluginContext, name: string, state: State, p
.apply(StructureFromAssemblies, undefined, { state: { isGhost: true } })
.commit({ revertOnError: true });
const membraneParams = {
ignoreLight: params.preset.adjustStyle,
representation: params.preset.representation,
};
await CellpackMembranePreset.apply(membrane, membraneParams, plugin);
@@ -535,6 +432,7 @@ async function loadMembrane(plugin: PluginContext, name: string, state: State, p
.apply(StateTransforms.Model.StructureFromModel, props, { state: { isGhost: true } })
.commit({ revertOnError: true });
const membraneParams = {
ignoreLight: params.preset.adjustStyle,
representation: params.preset.representation,
};
await CellpackMembranePreset.apply(membrane, membraneParams, plugin);
@@ -618,6 +516,7 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat
const packingParams = {
traceOnly: params.preset.traceOnly,
ignoreLight: params.preset.adjustStyle,
representation: params.preset.representation,
};
await CellpackPackingPreset.apply(packing, packingParams, plugin);
@@ -669,7 +568,8 @@ const LoadCellPackModelParams = {
ingredients: PD.FileList({ accept: '.cif,.bcif,.pdb', label: 'Ingredient files' }),
preset: PD.Group({
traceOnly: PD.Boolean(false),
representation: PD.Select('gaussian-surface', PD.arrayToOptions(['spacefill', 'gaussian-surface', 'point', 'orientation']))
adjustStyle: PD.Boolean(true),
representation: PD.Select('gaussian-surface', PD.arrayToOptions(['spacefill', 'gaussian-surface', 'point', 'orientation'] as const))
}, { isExpanded: true })
};
type LoadCellPackModelParams = PD.Values<typeof LoadCellPackModelParams>
@@ -679,5 +579,53 @@ export const LoadCellPackModel = StateAction.build({
params: LoadCellPackModelParams,
from: PSO.Root
})(({ state, params }, ctx: PluginContext) => Task.create('CellPack Loader', async taskCtx => {
if (params.preset.adjustStyle) {
ctx.managers.interactivity.setProps({ granularity: 'chain' });
ctx.managers.structure.component.setOptions({
... ctx.managers.structure.component.state.options,
visualQuality: 'custom',
ignoreLight: true,
hydrogens: 'hide-all',
});
ctx.canvas3d?.setProps({
multiSample: { mode: 'off' },
cameraClipping: { far: false },
renderer: { colorMarker: false },
marking: {
enabled: true,
ghostEdgeStrength: 1,
},
postprocessing: {
occlusion: {
name: 'on',
params: {
samples: 32,
radius: 8,
bias: 1,
blurKernelSize: 15,
resolutionScale: 1,
}
},
shadow: {
name: 'on',
params: {
bias: 0.6,
maxDistance: 80,
steps: 3,
tolerance: 1.0,
}
},
outline: {
name: 'on',
params: {
scale: 1,
threshold: 0.33,
color: ColorNames.black,
includeTransparent: true,
}
}
}
});
}
await loadPackings(ctx, taskCtx, state, params);
}));

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author Ludovic Autin <ludovic.autin@gmail.com>
@@ -13,7 +13,8 @@ import { CellPackGenerateColorThemeProvider } from './color/generate';
export const CellpackPackingPresetParams = {
traceOnly: PD.Boolean(true),
representation: PD.Select('gaussian-surface', PD.arrayToOptions(['gaussian-surface', 'spacefill', 'point', 'orientation'])),
ignoreLight: PD.Boolean(false),
representation: PD.Select('gaussian-surface', PD.arrayToOptions(['gaussian-surface', 'spacefill', 'point', 'orientation'] as const)),
};
export type CellpackPackingPresetParams = PD.ValuesFor<typeof CellpackPackingPresetParams>
@@ -27,7 +28,9 @@ export const CellpackPackingPreset = StructureRepresentationPresetProvider({
const reprProps = {
ignoreHydrogens: true,
traceOnly: params.traceOnly
traceOnly: params.traceOnly,
instanceGranularity: true,
ignoreLight: params.ignoreLight,
};
const components = {
polymer: await presetStaticComponent(plugin, structureCell, 'polymer')
@@ -37,8 +40,8 @@ export const CellpackPackingPreset = StructureRepresentationPresetProvider({
Object.assign(reprProps, {
quality: 'custom', resolution: 10, radiusOffset: 2, doubleSided: false
});
} else if (params.representation === 'spacefill' && params.traceOnly) {
Object.assign(reprProps, { sizeFactor: 2 });
} else if (params.representation === 'spacefill') {
Object.assign(reprProps, { sizeFactor: params.traceOnly ? 2 : 1 });
}
// default is generated
@@ -57,7 +60,8 @@ export const CellpackPackingPreset = StructureRepresentationPresetProvider({
//
export const CellpackMembranePresetParams = {
representation: PD.Select('gaussian-surface', PD.arrayToOptions(['gaussian-surface', 'spacefill', 'point', 'orientation'])),
ignoreLight: PD.Boolean(false),
representation: PD.Select('gaussian-surface', PD.arrayToOptions(['gaussian-surface', 'spacefill', 'point', 'orientation'] as const)),
};
export type CellpackMembranePresetParams = PD.ValuesFor<typeof CellpackMembranePresetParams>
@@ -71,6 +75,8 @@ export const CellpackMembranePreset = StructureRepresentationPresetProvider({
const reprProps = {
ignoreHydrogens: true,
instanceGranularity: true,
ignoreLight: params.ignoreLight,
};
const components = {
membrane: await presetStaticComponent(plugin, structureCell, 'all', { label: 'Membrane' })
@@ -84,7 +90,7 @@ export const CellpackMembranePreset = StructureRepresentationPresetProvider({
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, {});
const representations = {
membrane: builder.buildRepresentation(update, components.membrane, { type: 'gaussian-surface', typeParams: { ...typeParams, ...reprProps }, color: 'uniform', colorParams: { value: ColorNames.lightgrey } }, { tag: 'all' })
membrane: builder.buildRepresentation(update, components.membrane, { type: params.representation, typeParams: { ...typeParams, ...reprProps }, color: 'uniform', colorParams: { value: ColorNames.lightgrey } }, { tag: 'all' })
};
await update.commit({ revertOnError: true });

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2018-2022 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 { PluginBehavior } from '../../mol-plugin/behavior/behavior';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { ConfalPyramidsPreset } from './confal-pyramids/behavior';
import { ConfalPyramidsColorThemeProvider } from './confal-pyramids/color';
import { ConfalPyramidsProvider } from './confal-pyramids/property';
import { ConfalPyramidsRepresentationProvider } from './confal-pyramids/representation';
import { NtCTubePreset } from './ntc-tube/behavior';
import { NtCTubeColorThemeProvider } from './ntc-tube/color';
import { NtCTubeProvider } from './ntc-tube/property';
import { NtCTubeRepresentationProvider } from './ntc-tube/representation';
export const DnatcoNtCs = PluginBehavior.create<{ autoAttach: boolean, showToolTip: boolean }>({
name: 'dnatco-ntcs',
category: 'custom-props',
display: {
name: 'DNATCO NtC Annotations',
description: 'DNATCO NtC Annotations',
},
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showToolTip: boolean }> {
register(): void {
this.ctx.customModelProperties.register(ConfalPyramidsProvider, this.params.autoAttach);
this.ctx.customModelProperties.register(NtCTubeProvider, this.params.autoAttach);
this.ctx.representation.structure.themes.colorThemeRegistry.add(ConfalPyramidsColorThemeProvider);
this.ctx.representation.structure.registry.add(ConfalPyramidsRepresentationProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.add(NtCTubeColorThemeProvider);
this.ctx.representation.structure.registry.add(NtCTubeRepresentationProvider);
this.ctx.builders.structure.representation.registerPreset(ConfalPyramidsPreset);
this.ctx.builders.structure.representation.registerPreset(NtCTubePreset);
}
unregister() {
this.ctx.customModelProperties.unregister(ConfalPyramidsProvider.descriptor.name);
this.ctx.customModelProperties.unregister(NtCTubeProvider.descriptor.name);
this.ctx.representation.structure.registry.remove(ConfalPyramidsRepresentationProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(ConfalPyramidsColorThemeProvider);
this.ctx.representation.structure.registry.remove(NtCTubeRepresentationProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(NtCTubeColorThemeProvider);
this.ctx.builders.structure.representation.unregisterPreset(ConfalPyramidsPreset);
this.ctx.builders.structure.representation.unregisterPreset(NtCTubePreset);
}
},
params: () => ({
autoAttach: PD.Boolean(true),
showToolTip: PD.Boolean(true)
})
});

View File

@@ -0,0 +1,219 @@
/**
* Copyright (c) 2018-2022 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 { Color, ColorMap } from '../../mol-util/color';
export const DefaultNtCClassColors = {
A: 0xFFC1C1,
B: 0xC8CFFF,
BII: 0x0059DA,
miB: 0x3BE8FB,
Z: 0x01F60E,
IC: 0xFA5CFB,
OPN: 0xE90000,
SYN: 0xFFFF01,
N: 0xF2F2F2,
};
export const ErrorColor = Color(0xFFA10A);
export const NtCColors = ColorMap({
NANT_Upr: DefaultNtCClassColors.N,
NANT_Lwr: DefaultNtCClassColors.N,
AA00_Upr: DefaultNtCClassColors.A,
AA00_Lwr: DefaultNtCClassColors.A,
AA02_Upr: DefaultNtCClassColors.A,
AA02_Lwr: DefaultNtCClassColors.A,
AA03_Upr: DefaultNtCClassColors.A,
AA03_Lwr: DefaultNtCClassColors.A,
AA04_Upr: DefaultNtCClassColors.A,
AA04_Lwr: DefaultNtCClassColors.A,
AA08_Upr: DefaultNtCClassColors.A,
AA08_Lwr: DefaultNtCClassColors.A,
AA09_Upr: DefaultNtCClassColors.A,
AA09_Lwr: DefaultNtCClassColors.A,
AA01_Upr: DefaultNtCClassColors.A,
AA01_Lwr: DefaultNtCClassColors.A,
AA05_Upr: DefaultNtCClassColors.A,
AA05_Lwr: DefaultNtCClassColors.A,
AA06_Upr: DefaultNtCClassColors.A,
AA06_Lwr: DefaultNtCClassColors.A,
AA10_Upr: DefaultNtCClassColors.A,
AA10_Lwr: DefaultNtCClassColors.A,
AA11_Upr: DefaultNtCClassColors.A,
AA11_Lwr: DefaultNtCClassColors.A,
AA07_Upr: DefaultNtCClassColors.A,
AA07_Lwr: DefaultNtCClassColors.A,
AA12_Upr: DefaultNtCClassColors.A,
AA12_Lwr: DefaultNtCClassColors.A,
AA13_Upr: DefaultNtCClassColors.A,
AA13_Lwr: DefaultNtCClassColors.A,
AB01_Upr: DefaultNtCClassColors.A,
AB01_Lwr: DefaultNtCClassColors.B,
AB02_Upr: DefaultNtCClassColors.A,
AB02_Lwr: DefaultNtCClassColors.B,
AB03_Upr: DefaultNtCClassColors.A,
AB03_Lwr: DefaultNtCClassColors.B,
AB04_Upr: DefaultNtCClassColors.A,
AB04_Lwr: DefaultNtCClassColors.B,
AB05_Upr: DefaultNtCClassColors.A,
AB05_Lwr: DefaultNtCClassColors.B,
BA01_Upr: DefaultNtCClassColors.B,
BA01_Lwr: DefaultNtCClassColors.A,
BA05_Upr: DefaultNtCClassColors.B,
BA05_Lwr: DefaultNtCClassColors.A,
BA09_Upr: DefaultNtCClassColors.B,
BA09_Lwr: DefaultNtCClassColors.A,
BA08_Upr: DefaultNtCClassColors.BII,
BA08_Lwr: DefaultNtCClassColors.A,
BA10_Upr: DefaultNtCClassColors.B,
BA10_Lwr: DefaultNtCClassColors.A,
BA13_Upr: DefaultNtCClassColors.BII,
BA13_Lwr: DefaultNtCClassColors.A,
BA16_Upr: DefaultNtCClassColors.BII,
BA16_Lwr: DefaultNtCClassColors.A,
BA17_Upr: DefaultNtCClassColors.BII,
BA17_Lwr: DefaultNtCClassColors.A,
BB00_Upr: DefaultNtCClassColors.B,
BB00_Lwr: DefaultNtCClassColors.B,
BB01_Upr: DefaultNtCClassColors.B,
BB01_Lwr: DefaultNtCClassColors.B,
BB17_Upr: DefaultNtCClassColors.B,
BB17_Lwr: DefaultNtCClassColors.B,
BB02_Upr: DefaultNtCClassColors.B,
BB02_Lwr: DefaultNtCClassColors.B,
BB03_Upr: DefaultNtCClassColors.B,
BB03_Lwr: DefaultNtCClassColors.B,
BB11_Upr: DefaultNtCClassColors.B,
BB11_Lwr: DefaultNtCClassColors.B,
BB16_Upr: DefaultNtCClassColors.B,
BB16_Lwr: DefaultNtCClassColors.B,
BB04_Upr: DefaultNtCClassColors.B,
BB04_Lwr: DefaultNtCClassColors.BII,
BB05_Upr: DefaultNtCClassColors.B,
BB05_Lwr: DefaultNtCClassColors.BII,
BB07_Upr: DefaultNtCClassColors.BII,
BB07_Lwr: DefaultNtCClassColors.BII,
BB08_Upr: DefaultNtCClassColors.BII,
BB08_Lwr: DefaultNtCClassColors.BII,
BB10_Upr: DefaultNtCClassColors.miB,
BB10_Lwr: DefaultNtCClassColors.miB,
BB12_Upr: DefaultNtCClassColors.miB,
BB12_Lwr: DefaultNtCClassColors.miB,
BB13_Upr: DefaultNtCClassColors.miB,
BB13_Lwr: DefaultNtCClassColors.miB,
BB14_Upr: DefaultNtCClassColors.miB,
BB14_Lwr: DefaultNtCClassColors.miB,
BB15_Upr: DefaultNtCClassColors.miB,
BB15_Lwr: DefaultNtCClassColors.miB,
BB20_Upr: DefaultNtCClassColors.miB,
BB20_Lwr: DefaultNtCClassColors.miB,
IC01_Upr: DefaultNtCClassColors.IC,
IC01_Lwr: DefaultNtCClassColors.IC,
IC02_Upr: DefaultNtCClassColors.IC,
IC02_Lwr: DefaultNtCClassColors.IC,
IC03_Upr: DefaultNtCClassColors.IC,
IC03_Lwr: DefaultNtCClassColors.IC,
IC04_Upr: DefaultNtCClassColors.IC,
IC04_Lwr: DefaultNtCClassColors.IC,
IC05_Upr: DefaultNtCClassColors.IC,
IC05_Lwr: DefaultNtCClassColors.IC,
IC06_Upr: DefaultNtCClassColors.IC,
IC06_Lwr: DefaultNtCClassColors.IC,
IC07_Upr: DefaultNtCClassColors.IC,
IC07_Lwr: DefaultNtCClassColors.IC,
OP01_Upr: DefaultNtCClassColors.OPN,
OP01_Lwr: DefaultNtCClassColors.OPN,
OP02_Upr: DefaultNtCClassColors.OPN,
OP02_Lwr: DefaultNtCClassColors.OPN,
OP03_Upr: DefaultNtCClassColors.OPN,
OP03_Lwr: DefaultNtCClassColors.OPN,
OP04_Upr: DefaultNtCClassColors.OPN,
OP04_Lwr: DefaultNtCClassColors.OPN,
OP05_Upr: DefaultNtCClassColors.OPN,
OP05_Lwr: DefaultNtCClassColors.OPN,
OP06_Upr: DefaultNtCClassColors.OPN,
OP06_Lwr: DefaultNtCClassColors.OPN,
OP07_Upr: DefaultNtCClassColors.OPN,
OP07_Lwr: DefaultNtCClassColors.OPN,
OP08_Upr: DefaultNtCClassColors.OPN,
OP08_Lwr: DefaultNtCClassColors.OPN,
OP09_Upr: DefaultNtCClassColors.OPN,
OP09_Lwr: DefaultNtCClassColors.OPN,
OP10_Upr: DefaultNtCClassColors.OPN,
OP10_Lwr: DefaultNtCClassColors.OPN,
OP11_Upr: DefaultNtCClassColors.OPN,
OP11_Lwr: DefaultNtCClassColors.OPN,
OP12_Upr: DefaultNtCClassColors.OPN,
OP12_Lwr: DefaultNtCClassColors.OPN,
OP13_Upr: DefaultNtCClassColors.OPN,
OP13_Lwr: DefaultNtCClassColors.OPN,
OP14_Upr: DefaultNtCClassColors.OPN,
OP14_Lwr: DefaultNtCClassColors.OPN,
OP15_Upr: DefaultNtCClassColors.OPN,
OP15_Lwr: DefaultNtCClassColors.OPN,
OP16_Upr: DefaultNtCClassColors.OPN,
OP16_Lwr: DefaultNtCClassColors.OPN,
OP17_Upr: DefaultNtCClassColors.OPN,
OP17_Lwr: DefaultNtCClassColors.OPN,
OP18_Upr: DefaultNtCClassColors.OPN,
OP18_Lwr: DefaultNtCClassColors.OPN,
OP19_Upr: DefaultNtCClassColors.OPN,
OP19_Lwr: DefaultNtCClassColors.OPN,
OP20_Upr: DefaultNtCClassColors.OPN,
OP20_Lwr: DefaultNtCClassColors.OPN,
OP21_Upr: DefaultNtCClassColors.OPN,
OP21_Lwr: DefaultNtCClassColors.OPN,
OP22_Upr: DefaultNtCClassColors.OPN,
OP22_Lwr: DefaultNtCClassColors.OPN,
OP23_Upr: DefaultNtCClassColors.OPN,
OP23_Lwr: DefaultNtCClassColors.OPN,
OP24_Upr: DefaultNtCClassColors.OPN,
OP24_Lwr: DefaultNtCClassColors.OPN,
OP25_Upr: DefaultNtCClassColors.OPN,
OP25_Lwr: DefaultNtCClassColors.OPN,
OP26_Upr: DefaultNtCClassColors.OPN,
OP26_Lwr: DefaultNtCClassColors.OPN,
OP27_Upr: DefaultNtCClassColors.OPN,
OP27_Lwr: DefaultNtCClassColors.OPN,
OP28_Upr: DefaultNtCClassColors.OPN,
OP28_Lwr: DefaultNtCClassColors.OPN,
OP29_Upr: DefaultNtCClassColors.OPN,
OP29_Lwr: DefaultNtCClassColors.OPN,
OP30_Upr: DefaultNtCClassColors.OPN,
OP30_Lwr: DefaultNtCClassColors.OPN,
OP31_Upr: DefaultNtCClassColors.OPN,
OP31_Lwr: DefaultNtCClassColors.OPN,
OPS1_Upr: DefaultNtCClassColors.OPN,
OPS1_Lwr: DefaultNtCClassColors.OPN,
OP1S_Upr: DefaultNtCClassColors.OPN,
OP1S_Lwr: DefaultNtCClassColors.SYN,
AAS1_Upr: DefaultNtCClassColors.SYN,
AAS1_Lwr: DefaultNtCClassColors.A,
AB1S_Upr: DefaultNtCClassColors.A,
AB1S_Lwr: DefaultNtCClassColors.SYN,
AB2S_Upr: DefaultNtCClassColors.A,
AB2S_Lwr: DefaultNtCClassColors.SYN,
BB1S_Upr: DefaultNtCClassColors.B,
BB1S_Lwr: DefaultNtCClassColors.SYN,
BB2S_Upr: DefaultNtCClassColors.B,
BB2S_Lwr: DefaultNtCClassColors.SYN,
BBS1_Upr: DefaultNtCClassColors.SYN,
BBS1_Lwr: DefaultNtCClassColors.B,
ZZ01_Upr: DefaultNtCClassColors.Z,
ZZ01_Lwr: DefaultNtCClassColors.Z,
ZZ02_Upr: DefaultNtCClassColors.Z,
ZZ02_Lwr: DefaultNtCClassColors.Z,
ZZ1S_Upr: DefaultNtCClassColors.Z,
ZZ1S_Lwr: DefaultNtCClassColors.SYN,
ZZ2S_Upr: DefaultNtCClassColors.Z,
ZZ2S_Lwr: DefaultNtCClassColors.SYN,
ZZS1_Upr: DefaultNtCClassColors.SYN,
ZZS1_Lwr: DefaultNtCClassColors.Z,
ZZS2_Upr: DefaultNtCClassColors.SYN,
ZZS2_Lwr: DefaultNtCClassColors.Z,
});

View File

@@ -6,23 +6,22 @@
*/
import { ConfalPyramidsColorThemeProvider } from './color';
import { ConfalPyramids, ConfalPyramidsProvider } from './property';
import { ConfalPyramidsProvider } from './property';
import { ConfalPyramidsRepresentationProvider } from './representation';
import { Loci } from '../../../mol-model/loci';
import { PluginBehavior } from '../../../mol-plugin/behavior/behavior';
import { Dnatco } from '../property';
import { DnatcoTypes } from '../types';
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({
export const ConfalPyramidsPreset = 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));
return a.data.models.length >= 1 && a.data.models.some(m => Dnatco.isApplicable(m));
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
@@ -48,56 +47,11 @@ export const DnatcoConfalPyramidsPreset = StructureRepresentationPresetProvider(
}
});
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)
})
});
export function confalPyramidLabel(step: DnatcoTypes.Step) {
return `
<b>${step.auth_asym_id_1}</b> |
<b>${step.label_comp_id_1} ${step.auth_seq_id_1}${step.PDB_ins_code_1}${step.label_alt_id_1.length > 0 ? ` (alt ${step.label_alt_id_1})` : ''}
${step.label_comp_id_2} ${step.auth_seq_id_2}${step.PDB_ins_code_2}${step.label_alt_id_2.length > 0 ? ` (alt ${step.label_alt_id_2})` : ''} </b><br />
<i>NtC:</i> ${step.NtC} | <i>Confal score:</i> ${step.confal_score} | <i>RMSD:</i> ${step.rmsd.toFixed(2)}
`;
}

View File

@@ -5,155 +5,48 @@
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { ConfalPyramids, ConfalPyramidsProvider } from './property';
import { ErrorColor, NtCColors } from '../color';
import { ConfalPyramidsProvider } from './property';
import { ConfalPyramidsTypes as CPT } from './types';
import { Dnatco } from '../property';
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 { Color, ColorMap } from '../../../mol-util/color';
import { getColorMapParams } from '../../../mol-util/color/params';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { TableLegend } from '../../../mol-util/legend';
import { iterableToArray } from '../../../mol-data/util';
import { ObjectKeys } from '../../../mol-util/type-helpers';
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 PyramidsColors = ColorMap({ ...NtCColors });
type PyramidsColors = typeof PyramidsColors;
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)],
]);
export const ConfalPyramidsColorThemeParams = {
colors: PD.MappedStatic('default', {
'default': PD.EmptyGroup(),
'custom': PD.Group(getColorMapParams(PyramidsColors))
}),
};
export type ConfalPyramidsColorThemeParams = typeof ConfalPyramidsColorThemeParams;
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
return PD.clone(ConfalPyramidsColorThemeParams);
}
export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values<ConfalPyramidsColorThemeParams>): ColorTheme<ConfalPyramidsColorThemeParams> {
const colorMap = props.colors.name === 'default' ? PyramidsColors : props.colors.params;
function color(location: Location, isSecondary: boolean): Color {
if (CPT.isLocation(location)) {
const { pyramid, isLower } = location.data;
return getConformerColor(pyramid.NtC, isLower);
const { step, isLower } = location.data;
const key = step.NtC + `_${isLower ? 'Lwr' : 'Upr'}` as keyof PyramidsColors;
return colorMap[key] ?? ErrorColor;
}
return DefaultColor;
return ErrorColor;
}
return {
@@ -162,12 +55,7 @@ export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values
color,
props,
description: Description,
legend: TableLegend(iterableToArray(ColorMapping.entries()).map(([conformer, color]) => {
return [conformer, color] as [string, Color];
}).concat([
['Error', ErrorColor],
['Unknown', DefaultColor]
]))
legend: TableLegend(ObjectKeys(colorMap).map(k => [k.replace('_', ' '), colorMap[k]] as [string, Color]).concat([['Error', ErrorColor]])),
};
}
@@ -178,7 +66,7 @@ export const ConfalPyramidsColorThemeProvider: ColorTheme.Provider<ConfalPyramid
factory: ConfalPyramidsColorTheme,
getParams: getConfalPyramidsColorThemeParams,
defaultValues: PD.getDefaultValues(ConfalPyramidsColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models.some(m => ConfalPyramids.isApplicable(m)),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models.some(m => Dnatco.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 && ConfalPyramidsProvider.ref(data.structure.models[0], false)

View File

@@ -5,90 +5,18 @@
* @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 { Dnatco, DnatcoParams, DnatcoSteps } from '../property';
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 const ConfalPyramidsParams = { ...DnatcoParams };
export type ConfalPyramidsParams = typeof ConfalPyramidsParams;
export type ConfalPyramidsProps = PD.Values<ConfalPyramidsParams>;
export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramidsParams, ConfalPyramids> = CustomModelProperty.createProvider({
export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramidsParams, DnatcoSteps> = CustomModelProperty.createProvider({
label: 'Confal Pyramids',
descriptor: CustomPropertyDescriptor({
name: 'confal_pyramids',
@@ -96,77 +24,9 @@ export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramids
type: 'static',
defaultParams: ConfalPyramidsParams,
getParams: (data: Model) => ConfalPyramidsParams,
isApplicable: (data: Model) => ConfalPyramids.isApplicable(data),
isApplicable: (data: Model) => Dnatco.isApplicable(data),
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<ConfalPyramidsProps>) => {
const p = { ...PD.getDefaultValues(ConfalPyramidsParams), ...props };
return ConfalPyramids.fromCif(ctx, data, p);
return Dnatco.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

@@ -5,9 +5,10 @@
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { ConfalPyramids, ConfalPyramidsProvider } from './property';
import { ConfalPyramidsUtil } from './util';
import { ConfalPyramidsProvider } from './property';
import { ConfalPyramidsIterator } from './util';
import { ConfalPyramidsTypes as CPT } from './types';
import { Dnatco } from '../property';
import { Interval } from '../../../mol-data/int';
import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
@@ -16,14 +17,14 @@ 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 { Structure, 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 { UnitsMeshParams, UnitsMeshVisual, UnitsVisual } from '../../../mol-repr/structure/units-visual';
import { VisualUpdateState } from '../../../mol-repr/util';
import { VisualContext } from '../../../mol-repr/visual';
import { getAltResidueLociFromId, StructureGroup } from '../../../mol-repr/structure/visual/util/common';
import { StructureGroup } 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';
@@ -32,6 +33,12 @@ const t = Mat4.identity();
const w = Vec3.zero();
const mp = Vec3.zero();
const posO3 = Vec3();
const posP = Vec3();
const posOP1 = Vec3();
const posOP2 = Vec3();
const posO5 = Vec3();
function calcMidpoint(mp: Vec3, v: Vec3, w: Vec3) {
Vec3.sub(mp, v, w);
Vec3.scale(mp, mp, 0.5);
@@ -53,64 +60,78 @@ function createConfalPyramidsIterator(structureGroup: StructureGroup): LocationI
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, 1, () => NullLocation);
}
const data = ConfalPyramidsProvider.get(structure.model)?.value?.data;
if (!data) return LocationIterator(0, 1, 1, () => NullLocation);
const { locations } = prop.data;
const halfPyramidsCount = data.steps.length * 2;
const getLocation = (groupIndex: number, instanceIndex: number) => {
if (locations.length <= groupIndex) return NullLocation;
return locations[groupIndex];
if (halfPyramidsCount <= groupIndex) return NullLocation;
const idx = Math.floor(groupIndex / 2); // Map groupIndex to a step, see createConfalPyramidsMesh() for full explanation
return CPT.Location(data.steps[idx], groupIndex % 2 === 1);
};
return LocationIterator(locations.length, instanceCount, 1, getLocation);
return LocationIterator(halfPyramidsCount, instanceCount, 1, 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 data = ConfalPyramidsProvider.get(structure.model)?.value?.data;
if (!data) return Mesh.createEmpty(mesh);
const { pyramids } = prop.data;
if (pyramids.length === 0) return Mesh.createEmpty(mesh);
const { steps, mapping } = data;
if (steps.length === 0) return Mesh.createEmpty(mesh);
const vertexCount = (6 * steps.length) / mapping.length;
const mb = MeshBuilder.createState(512, 512, mesh);
const mb = MeshBuilder.createState(vertexCount, vertexCount / 10, 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 it = new ConfalPyramidsIterator(structure, unit);
while (it.hasNext) {
const allPoints = it.move();
if (!allPoints)
continue;
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;
for (const points of allPoints) {
const { O3, P, OP1, OP2, O5, confalScore } = points;
const scale = (confalScore - 20.0) / 100.0;
// Steps can be drawn in a different order than they are stored.
// To make sure that we can get from the drawn pyramid back to the step in represents,
// we need to use an appropriate groupId. The stepIdx passed from the iterator
// is an index into the array of all steps in the structure.
// Since a step is drawn as two "half-pyramids" we need two ids to map to a single step.
// To do that, we just multiply the index by 2. idx*2 marks the "upper" half-pyramid,
// (idx*2)+1 the "lower" half-pyramid.
const groupIdx = points.stepIdx * 2;
shiftVertex(O3, P, scale);
shiftVertex(OP1, P, scale);
shiftVertex(OP2, P, scale);
shiftVertex(O5, P, scale);
calcMidpoint(mp, O3, O5);
unit.conformation.invariantPosition(O3, posO3);
unit.conformation.invariantPosition(P, posP);
unit.conformation.invariantPosition(OP1, posOP1);
unit.conformation.invariantPosition(OP2, posOP2);
unit.conformation.invariantPosition(O5, posO5);
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());
shiftVertex(posO3, posP, scale);
shiftVertex(posOP1, posP, scale);
shiftVertex(posOP2, posP, scale);
shiftVertex(posO5, posP, scale);
calcMidpoint(mp, posO3, posO5);
/* 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());
};
mb.currentGroup = groupIdx;
let pb = PrimitiveBuilder(3);
/* Upper part (for first residue in step) */
pb.add(posO3, posOP1, posOP2);
pb.add(posO3, mp, posOP1);
pb.add(posO3, posOP2, mp);
MeshBuilder.addPrimitive(mb, t, pb.getPrimitive());
const walker = new ConfalPyramidsUtil.UnitWalker(structure, unit, handler);
walker.walk();
/* Lower part (for second residue in step) */
mb.currentGroup = groupIdx + 1;
pb = PrimitiveBuilder(3);
pb.add(mp, posO5, posOP1);
pb.add(mp, posOP2, posO5);
pb.add(posO5, posOP2, posOP1);
MeshBuilder.addPrimitive(mb, t, pb.getPrimitive());
}
}
return MeshBuilder.getMesh(mb);
}
@@ -124,16 +145,15 @@ function getConfalPyramidLoci(pickingId: PickingId, structureGroup: StructureGro
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 data = ConfalPyramidsProvider.get(structure.model)?.value?.data;
if (!data) return EmptyLoci;
const { locations } = prop.data;
const halfPyramidsCount = data.steps.length * 2;
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];
if (halfPyramidsCount <= groupId) return EmptyLoci;
return getAltResidueLociFromId(structure, unit, rI, altId);
const idx = Math.floor(groupId / 2); // Map groupIndex to a step, see createConfalPyramidsMesh() for full explanation
return CPT.Loci(data.steps, [idx]);
}
function eachConfalPyramid(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
@@ -178,7 +198,7 @@ export const ConfalPyramidsRepresentationProvider = StructureRepresentationProvi
defaultValues: PD.getDefaultValues(ConfalPyramidsParams),
defaultColorTheme: { name: 'confal-pyramids' },
defaultSizeTheme: { name: 'uniform' },
isApplicable: (structure: Structure) => structure.models.some(m => ConfalPyramids.isApplicable(m)),
isApplicable: (structure: Structure) => structure.models.some(m => Dnatco.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

@@ -5,56 +5,29 @@
* @author Jiří Černý <jiri.cerny@ibt.cas.cz>
*/
import { DnatcoTypes } from '../types';
import { DataLocation } from '../../../mol-model/location';
import { ElementIndex, Structure, StructureElement, Unit } from '../../../mol-model/structure';
import { DataLoci } from '../../../mol-model/loci';
import { confalPyramidLabel } from './behavior';
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 Location extends DataLocation<DnatcoTypes.HalfStep, {}> {}
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 Location(step: DnatcoTypes.Step, isLower: boolean) {
return DataLocation(DnatcoTypes.DataTag, { step, isLower }, {});
}
export function isLocation(x: any): x is Location {
return !!x && x.kind === 'data-location' && x.tag === 'pyramid';
return !!x && x.kind === 'data-location' && x.tag === DnatcoTypes.DataTag;
}
export function toElementLocation(location: Location) {
return StructureElement.Location.create(location.element.structure, location.element.unit, location.element.element);
export interface Loci extends DataLoci<DnatcoTypes.Step[], number> {}
export function Loci(data: DnatcoTypes.Step[], elements: ReadonlyArray<number>): Loci {
return DataLoci(DnatcoTypes.DataTag, data, elements, undefined, () => elements[0] !== undefined ? confalPyramidLabel(data[elements[0]]) : '');
}
export function isLoci(x: any): x is Loci {
return !!x && x.kind === 'data-loci' && x.tag === DnatcoTypes.DataTag;
}
}

View File

@@ -1,299 +1,104 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2023 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';
import { DnatcoTypes } from '../types';
import { DnatcoUtil } from '../util';
import { Segmentation } from '../../../mol-data/int';
import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, Unit } from '../../../mol-model/structure';
export namespace ConfalPyramidsUtil {
type Residue = Segmentation.Segment<ResidueIndex>;
export type Pyramid = {
O3: ElementIndex,
P: ElementIndex,
OP1: ElementIndex,
OP2: ElementIndex,
O5: ElementIndex,
confalScore: number,
stepIdx: number,
};
export type AtomInfo = {
pos: Vec3,
index: ElementIndex,
fakeAltId: string,
};
function getPyramid(
loc: StructureElement.Location,
one: DnatcoUtil.Residue, two: DnatcoUtil.Residue,
altIdOne: string, altIdTwo: string,
insCodeOne: string, insCodeTwo: string,
confalScore: number, stepIdx: number): Pyramid {
const O3 = DnatcoUtil.getAtomIndex(loc, one, ['O3\'', 'O3*'], altIdOne, insCodeOne);
const P = DnatcoUtil.getAtomIndex(loc, two, ['P'], altIdTwo, insCodeTwo);
const OP1 = DnatcoUtil.getAtomIndex(loc, two, ['OP1'], altIdTwo, insCodeTwo);
const OP2 = DnatcoUtil.getAtomIndex(loc, two, ['OP2'], altIdTwo, insCodeTwo);
const O5 = DnatcoUtil.getAtomIndex(loc, two, ['O5\'', 'O5*'], altIdTwo, insCodeTwo);
export type FirstResidueAtoms = {
O3: AtomInfo,
};
return { O3, P, OP1, OP2, O5, confalScore, stepIdx };
}
export type SecondResidueAtoms = {
OP1: AtomInfo,
OP2: AtomInfo,
O5: AtomInfo,
P: AtomInfo,
};
export class ConfalPyramidsIterator {
private chainIt: Segmentation.SegmentIterator<ChainIndex>;
private residueIt: Segmentation.SegmentIterator<ResidueIndex>;
private residueOne?: DnatcoUtil.Residue;
private residueTwo: DnatcoUtil.Residue;
private data?: DnatcoTypes.Steps;
private loc: StructureElement.Location;
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,
};
private moveStep() {
this.residueOne = DnatcoUtil.copyResidue(this.residueTwo);
this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!;
export type Handler = (pyramid: CPT.Pyramid, first: FirstResidueAtoms, second: SecondResidueAtoms, firstLocIndex: number, secondLocIndex: number) => void;
// Check for discontinuity
if (this.residueTwo.index !== (this.residueOne!.index + 1))
return void 0;
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)
};
return this.toPyramids(this.residueOne!, this.residueTwo);
}
export function hasMultipleModels(unit: Unit.Atomic): boolean {
private toPyramids(one: DnatcoUtil.Residue, two: DnatcoUtil.Residue) {
const indices = DnatcoUtil.getStepIndices(this.data!, this.loc, one);
const points = [];
for (const idx of indices) {
const step = this.data!.steps[idx];
points.push(getPyramid(this.loc, one, two, step.label_alt_id_1, step.label_alt_id_2, step.PDB_ins_code_1, step.PDB_ins_code_2, step.confal_score, idx));
}
return points;
}
constructor(structure: Structure, unit: Unit) {
this.chainIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, unit.elements);
this.residueIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements);
const prop = ConfalPyramidsProvider.get(unit.model).value;
if (prop === undefined || prop.data === undefined) throw new Error('No custom properties data');
return prop.data.hasMultipleModels;
this.data = prop?.data;
if (this.chainIt.hasNext) {
this.residueIt.setSegment(this.chainIt.move());
if (this.residueIt.hasNext)
this.residueTwo = this.residueIt.move();
}
this.loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
}
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;
get hasNext() {
if (!this.data)
return false;
return this.residueIt.hasNext
? true
: this.chainIt.hasNext;
}
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 };
move() {
if (this.residueIt.hasNext) {
return this.moveStep();
} else {
this.residueIt.setSegment(this.chainIt.move());
if (this.residueIt.hasNext)
this.residueTwo = this.residueIt.move();
return this.moveStep();
}
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

@@ -1,8 +1,8 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2022 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';
export { DnatcoNtCs } from './behavior';

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2018-2022 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 { NtCTubeColorThemeProvider } from './color';
import { NtCTubeProvider } from './property';
import { NtCTubeRepresentationProvider } from './representation';
import { DnatcoTypes } from '../types';
import { Dnatco } from '../property';
import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../../mol-plugin-state/builder/structure/representation-preset';
import { StateObjectRef } from '../../../mol-state';
import { Task } from '../../../mol-task';
export const NtCTubePreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-ntc-tube',
display: {
name: 'NtC Tube', group: 'Annotation',
description: 'NtC Tube',
},
isApplicable(a) {
return a.data.models.length >= 1 && a.data.models.some(m => Dnatco.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('NtC tube', async runtime => {
await NtCTubeProvider.attach({ runtime, assetManager: plugin.managers.asset }, model);
}));
const { components, representations } = await PresetStructureRepresentations.auto.apply(ref, { ...params }, plugin);
const tube = await plugin.builders.structure.tryCreateComponentStatic(structureCell, 'nucleic', { label: 'NtC Tube' });
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params);
let tubeRepr;
if (representations)
tubeRepr = builder.buildRepresentation(update, tube, { type: NtCTubeRepresentationProvider, typeParams, color: NtCTubeColorThemeProvider }, { tag: 'ntc-tube' });
await update.commit({ revertOnError: true });
return { components: { ...components, tube }, representations: { ...representations, tubeRepr } };
}
});
export function NtCTubeSegmentLabel(step: DnatcoTypes.Step) {
return `
<b>${step.auth_asym_id_1}</b> |
<b>${step.label_comp_id_1} ${step.auth_seq_id_1}${step.PDB_ins_code_1}${step.label_alt_id_1.length > 0 ? ` (alt ${step.label_alt_id_1})` : ''}
${step.label_comp_id_2} ${step.auth_seq_id_2}${step.PDB_ins_code_2}${step.label_alt_id_2.length > 0 ? ` (alt ${step.label_alt_id_2})` : ''} </b><br />
<i>NtC:</i> ${step.NtC} | <i>Confal score:</i> ${step.confal_score} | <i>RMSD:</i> ${step.rmsd.toFixed(2)}
`;
}

View File

@@ -0,0 +1,90 @@
/**
* Copyright (c) 2018-2022 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 { ErrorColor, NtCColors } from '../color';
import { NtCTubeProvider } from './property';
import { NtCTubeTypes as NTT } from './types';
import { Dnatco } from '../property';
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, ColorMap } from '../../../mol-util/color';
import { getColorMapParams } from '../../../mol-util/color/params';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { TableLegend } from '../../../mol-util/legend';
import { ObjectKeys } from '../../../mol-util/type-helpers';
const Description = 'Assigns colors to NtC Tube segments';
const NtCTubeColors = ColorMap({
...NtCColors,
residueMarker: Color(0x222222),
stepBoundaryMarker: Color(0x656565),
});
type NtCTubeColors = typeof NtCTubeColors;
export const NtCTubeColorThemeParams = {
colors: PD.MappedStatic('default', {
'default': PD.EmptyGroup(),
'custom': PD.Group(getColorMapParams(NtCTubeColors))
}),
markResidueBoundaries: PD.Boolean(true),
markSegmentBoundaries: PD.Boolean(true),
};
export type NtCTubeColorThemeParams = typeof NtCTubeColorThemeParams;
export function getNtCTubeColorThemeParams(ctx: ThemeDataContext) {
return PD.clone(NtCTubeColorThemeParams);
}
export function NtCTubeColorTheme(ctx: ThemeDataContext, props: PD.Values<NtCTubeColorThemeParams>): ColorTheme<NtCTubeColorThemeParams> {
const colorMap = props.colors.name === 'default' ? NtCTubeColors : props.colors.params;
function color(location: Location, isSecondary: boolean): Color {
if (NTT.isLocation(location)) {
const { data } = location;
const { step, kind } = data;
let key;
if (kind === 'upper')
key = step.NtC + '_Upr' as keyof NtCTubeColors;
else if (kind === 'lower')
key = step.NtC + '_Lwr' as keyof NtCTubeColors;
else if (kind === 'residue-boundary')
key = (!props.markResidueBoundaries ? step.NtC + '_Lwr' : 'residueMarker') as keyof NtCTubeColors;
else /* segment-boundary */
key = (!props.markSegmentBoundaries ? step.NtC + '_Lwr' : 'stepBoundaryMarker') as keyof NtCTubeColors;
return colorMap[key] ?? ErrorColor;
}
return ErrorColor;
}
return {
factory: NtCTubeColorTheme,
granularity: 'group',
color,
props,
description: Description,
legend: TableLegend(ObjectKeys(colorMap).map(k => [k.replace('_', ' '), colorMap[k]] as [string, Color]).concat([['Error', ErrorColor]])),
};
}
export const NtCTubeColorThemeProvider: ColorTheme.Provider<NtCTubeColorThemeParams, 'ntc-tube'> = {
name: 'ntc-tube',
label: 'NtC Tube',
category: ColorTheme.Category.Residue,
factory: NtCTubeColorTheme,
getParams: getNtCTubeColorThemeParams,
defaultValues: PD.getDefaultValues(NtCTubeColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models.some(m => Dnatco.isApplicable(m)),
ensureCustomProperties: {
attach: (ctx: CustomProperty.Context, data: ThemeDataContext) => data.structure ? NtCTubeProvider.attach(ctx, data.structure.models[0], void 0, true) : Promise.resolve(),
detach: (data) => data.structure && NtCTubeProvider.ref(data.structure.models[0], false)
}
};

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2018-2022 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 { NtCTubeTypes as NTT } from './types';
import { Dnatco, DnatcoParams } from '../property';
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';
export const NtCTubeParams = { ...DnatcoParams };
export type NtCTubeParams = typeof NtCTubeParams;
export type NtCTubeProps = PD.Values<NtCTubeParams>;
export type NtCTubeData = PropertyWrapper<NTT.Data | undefined>;
async function fromCif(ctx: CustomProperty.Context, model: Model, props: NtCTubeProps): Promise<CustomProperty.Data<NtCTubeData>> {
const info = PropertyWrapper.createInfo();
const data = Dnatco.getCifData(model);
if (data === undefined) return { value: { info, data: undefined } };
const steps = Dnatco.getStepsFromCif(model, data.steps, data.stepsSummary);
return { value: { info, data: { data: steps } } };
}
export const NtCTubeProvider: CustomModelProperty.Provider<NtCTubeParams, NtCTubeData> = CustomModelProperty.createProvider({
label: 'NtC Tube',
descriptor: CustomPropertyDescriptor({
name: 'ntc-tube',
}),
type: 'static',
defaultParams: NtCTubeParams,
getParams: (data: Model) => NtCTubeParams,
isApplicable: (data: Model) => Dnatco.isApplicable(data),
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<NtCTubeProps>) => {
const p = { ...PD.getDefaultValues(NtCTubeParams), ...props };
return fromCif(ctx, data, p);
}
});

View File

@@ -0,0 +1,454 @@
/**
* Copyright (c) 2018-2022 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 { NtCTubeProvider } from './property';
import { NtCTubeSegmentsIterator } from './util';
import { NtCTubeTypes as NTT } from './types';
import { Dnatco } from '../property';
import { DnatcoTypes } from '../types';
import { DnatcoUtil } from '../util';
import { Interval } from '../../../mol-data/int';
import { BaseGeometry, VisualQuality } from '../../../mol-geo/geometry/base';
import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
import { addFixedCountDashedCylinder } from '../../../mol-geo/geometry/mesh/builder/cylinder';
import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
import { addTube } from '../../../mol-geo/geometry/mesh/builder/tube';
import { PickingId } from '../../../mol-geo/geometry/picking';
import { CylinderProps } from '../../../mol-geo/primitive/cylinder';
import { LocationIterator } from '../../../mol-geo/util/location-iterator';
import { Sphere3D } from '../../../mol-math/geometry/primitives/sphere3d';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { smoothstep } from '../../../mol-math/interpolate';
import { NullLocation } from '../../../mol-model/location';
import { EmptyLoci, Loci } from '../../../mol-model/loci';
import { Structure, StructureElement, Unit } from '../../../mol-model/structure';
import { structureUnion } from '../../../mol-model/structure/query/utils/structure-set';
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 { UnitsMeshParams, UnitsMeshVisual, UnitsVisual } from '../../../mol-repr/structure/units-visual';
import { createCurveSegmentState, CurveSegmentState } from '../../../mol-repr/structure/visual/util/polymer';
import { getStructureQuality, VisualUpdateState } from '../../../mol-repr/util';
import { VisualContext } from '../../../mol-repr/visual';
import { StructureGroup } from '../../../mol-repr/structure/visual/util/common';
import { Theme, ThemeRegistryContext } from '../../../mol-theme/theme';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
const v3add = Vec3.add;
const v3copy = Vec3.copy;
const v3cross = Vec3.cross;
const v3fromArray = Vec3.fromArray;
const v3matchDirection = Vec3.matchDirection;
const v3normalize = Vec3.normalize;
const v3orthogonalize = Vec3.orthogonalize;
const v3scale = Vec3.scale;
const v3slerp = Vec3.slerp;
const v3spline = Vec3.spline;
const v3sub = Vec3.sub;
const v3toArray = Vec3.toArray;
const NtCTubeMeshParams = {
...UnitsMeshParams,
linearSegments: PD.Numeric(4, { min: 2, max: 8, step: 1 }, BaseGeometry.CustomQualityParamInfo),
radialSegments: PD.Numeric(22, { min: 4, max: 56, step: 2 }, BaseGeometry.CustomQualityParamInfo),
residueMarkerWidth: PD.Numeric(0.05, { min: 0.01, max: 0.25, step: 0.01 }),
segmentBoundaryWidth: PD.Numeric(0.05, { min: 0.01, max: 0.25, step: 0.01 }),
};
type NtCTubeMeshParams = typeof NtCTubeMeshParams;
type QualityOptions = Exclude<VisualQuality, 'auto' | 'custom'>;
const LinearSegmentCount: Record<QualityOptions, number> = {
highest: 6,
higher: 6,
high: 4,
medium: 4,
low: 3,
lower: 3,
lowest: 2,
};
const RadialSegmentCount: Record<QualityOptions, number> = {
highest: 32,
higher: 26,
high: 22,
medium: 18,
low: 14,
lower: 10,
lowest: 6,
};
const _curvePoint = Vec3();
const _tanA = Vec3();
const _tanB = Vec3();
const _firstTangentVec = Vec3();
const _lastTangentVec = Vec3();
const _firstNormalVec = Vec3();
const _lastNormalVec = Vec3();
const _tmpNormal = Vec3();
const _tangentVec = Vec3();
const _normalVec = Vec3();
const _binormalVec = Vec3();
const _prevNormal = Vec3();
const _nextNormal = Vec3();
function interpolatePointsAndTangents(state: CurveSegmentState, p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, tRange: number[]) {
const { curvePoints, tangentVectors, linearSegments } = state;
const tension = 0.5;
const r = tRange[1] - tRange[0];
for (let j = 0; j <= linearSegments; ++j) {
const t = j * r / linearSegments + tRange[0];
v3spline(_curvePoint, p0, p1, p2, p3, t, tension);
v3spline(_tanA, p0, p1, p2, p3, t - 0.01, tension);
v3spline(_tanB, p0, p1, p2, p3, t + 0.01, tension);
v3toArray(_curvePoint, curvePoints, j * 3);
v3normalize(_tangentVec, v3sub(_tangentVec, _tanA, _tanB));
v3toArray(_tangentVec, tangentVectors, j * 3);
}
}
function interpolateNormals(state: CurveSegmentState, firstDirection: Vec3, lastDirection: Vec3) {
const { curvePoints, tangentVectors, normalVectors, binormalVectors } = state;
const n = curvePoints.length / 3;
v3fromArray(_firstTangentVec, tangentVectors, 0);
v3fromArray(_lastTangentVec, tangentVectors, (n - 1) * 3);
v3orthogonalize(_firstNormalVec, _firstTangentVec, firstDirection);
v3orthogonalize(_lastNormalVec, _lastTangentVec, lastDirection);
v3matchDirection(_lastNormalVec, _lastNormalVec, _firstNormalVec);
v3copy(_prevNormal, _firstNormalVec);
const n1 = n - 1;
for (let i = 0; i < n; ++i) {
const j = smoothstep(0, n1, i) * n1;
const t = i === 0 ? 0 : 1 / (n - j);
v3fromArray(_tangentVec, tangentVectors, i * 3);
v3orthogonalize(_normalVec, _tangentVec, v3slerp(_tmpNormal, _prevNormal, _lastNormalVec, t));
v3toArray(_normalVec, normalVectors, i * 3);
v3copy(_prevNormal, _normalVec);
v3normalize(_binormalVec, v3cross(_binormalVec, _tangentVec, _normalVec));
v3toArray(_binormalVec, binormalVectors, i * 3);
}
for (let i = 1; i < n1; ++i) {
v3fromArray(_prevNormal, normalVectors, (i - 1) * 3);
v3fromArray(_normalVec, normalVectors, i * 3);
v3fromArray(_nextNormal, normalVectors, (i + 1) * 3);
v3scale(_normalVec, v3add(_normalVec, _prevNormal, v3add(_normalVec, _nextNormal, _normalVec)), 1 / 3);
v3toArray(_normalVec, normalVectors, i * 3);
v3fromArray(_tangentVec, tangentVectors, i * 3);
v3normalize(_binormalVec, v3cross(_binormalVec, _tangentVec, _normalVec));
v3toArray(_binormalVec, binormalVectors, i * 3);
}
}
function interpolate(state: CurveSegmentState, p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, firstDir: Vec3, lastDir: Vec3, tRange = [0, 1]) {
interpolatePointsAndTangents(state, p0, p1, p2, p3, tRange);
interpolateNormals(state, firstDir, lastDir);
}
function createNtCTubeSegmentsIterator(structureGroup: StructureGroup): LocationIterator {
const { structure, group } = structureGroup;
const instanceCount = group.units.length;
const data = NtCTubeProvider.get(structure.model)?.value?.data;
if (!data) return LocationIterator(0, 1, 1, () => NullLocation);
const numBlocks = data.data.steps.length * 4;
const getLocation = (groupId: number, instanceId: number) => {
if (groupId > numBlocks) return NullLocation;
const stepIdx = Math.floor(groupId / 4);
const step = data.data.steps[stepIdx];
const r = groupId % 4;
const kind =
r === 0 ? 'upper' :
r === 1 ? 'lower' :
r === 2 ? 'residue-boundary' : 'segment-boundary';
return NTT.Location({ step, kind });
};
return LocationIterator(totalMeshGroupsCount(data.data.steps) + 1, instanceCount, 1, getLocation);
}
function segmentCount(structure: Structure, props: PD.Values<NtCTubeMeshParams>): { linear: number, radial: number } {
const quality = props.quality;
if (quality === 'custom')
return { linear: props.linearSegments, radial: props.radialSegments };
else if (quality === 'auto') {
const autoQuality = getStructureQuality(structure) as QualityOptions;
return { linear: LinearSegmentCount[autoQuality], radial: RadialSegmentCount[autoQuality] };
} else
return { linear: LinearSegmentCount[quality], radial: RadialSegmentCount[quality] };
}
function stepBoundingSphere(step: DnatcoTypes.Step, struLoci: StructureElement.Loci): Sphere3D | undefined {
const one = DnatcoUtil.residueToLoci(step.auth_asym_id_1, step.auth_seq_id_1, step.label_alt_id_1, step.PDB_ins_code_1, struLoci, 'auth');
const two = DnatcoUtil.residueToLoci(step.auth_asym_id_2, step.auth_seq_id_2, step.label_alt_id_2, step.PDB_ins_code_2, struLoci, 'auth');
if (StructureElement.Loci.is(one) && StructureElement.Loci.is(two)) {
const union = structureUnion(struLoci.structure, [StructureElement.Loci.toStructure(one), StructureElement.Loci.toStructure(two)]);
return union.boundary.sphere;
}
return void 0;
}
function totalMeshGroupsCount(steps: DnatcoTypes.Step[]) {
// Each segment has two blocks, Residue Boundary marker and a Segment Boundary marker
return steps.length * 4 - 1; // Subtract one because the last Segment Boundary marker is not drawn
}
function createNtCTubeMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<NtCTubeMeshParams>, mesh?: Mesh) {
if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh);
const prop = NtCTubeProvider.get(structure.model).value;
if (prop === undefined || prop.data === undefined) return Mesh.createEmpty(mesh);
const { data } = prop.data;
if (data.steps.length === 0) return Mesh.createEmpty(mesh);
const MarkerLinearSegmentCount = 2;
const segCount = segmentCount(structure, props);
const vertexCount = Math.floor((segCount.linear * 4 * data.steps.length / structure.model.atomicHierarchy.chains._rowCount) * segCount.radial);
const chunkSize = Math.floor(vertexCount / 3);
const diameter = 1.0 * theme.size.props.value;
const mb = MeshBuilder.createState(vertexCount, chunkSize, mesh);
const state = createCurveSegmentState(segCount.linear);
const { curvePoints, normalVectors, binormalVectors, widthValues, heightValues } = state;
for (let idx = 0; idx <= segCount.linear; idx++) {
widthValues[idx] = diameter;
heightValues[idx] = diameter;
}
const [normals, binormals] = [binormalVectors, normalVectors]; // Needed so that the tube is not drawn from inside out
const markerState = createCurveSegmentState(MarkerLinearSegmentCount);
const { curvePoints: mCurvePoints, normalVectors: mNormalVectors, binormalVectors: mBinormalVectors, widthValues: mWidthValues, heightValues: mHeightValues } = markerState;
for (let idx = 0; idx <= MarkerLinearSegmentCount; idx++) {
mWidthValues[idx] = diameter;
mHeightValues[idx] = diameter;
}
const [mNormals, mBinormals] = [mBinormalVectors, mNormalVectors];
const firstDir = Vec3();
const lastDir = Vec3();
const markerDir = Vec3();
const residueMarkerWidth = props.residueMarkerWidth / 2;
const it = new NtCTubeSegmentsIterator(structure, unit);
while (it.hasNext) {
const segment = it.move();
if (!segment)
continue;
const { p_1, p0, p1, p2, p3, p4, pP } = segment;
const FirstBlockId = segment.stepIdx * 4;
const SecondBlockId = FirstBlockId + 1;
const ResidueMarkerId = FirstBlockId + 2;
const SegmentBoundaryMarkerId = FirstBlockId + 3;
const { rmShift, rmPos } = calcResidueMarkerShift(p2, p3, pP);
if (segment.firstInChain) {
v3normalize(firstDir, v3sub(firstDir, p2, p1));
v3normalize(lastDir, v3sub(lastDir, rmPos, p2));
} else {
v3copy(firstDir, lastDir);
v3normalize(lastDir, v3sub(lastDir, rmPos, p2));
}
// C5' -> O3' block
interpolate(state, p0, p1, p2, p3, firstDir, lastDir);
mb.currentGroup = FirstBlockId;
addTube(mb, curvePoints, normals, binormals, segCount.linear, segCount.radial, widthValues, heightValues, segment.firstInChain || segment.followsGap, false, 'rounded');
// O3' -> C5' block
v3copy(firstDir, lastDir);
v3normalize(markerDir, v3sub(markerDir, p3, rmPos));
v3normalize(lastDir, v3sub(lastDir, p4, p3));
// From O3' to the residue marker
interpolate(state, p1, p2, p3, p4, firstDir, markerDir, [0, rmShift - residueMarkerWidth]);
mb.currentGroup = SecondBlockId;
addTube(mb, curvePoints, normals, binormals, segCount.linear, segCount.radial, widthValues, heightValues, false, false, 'rounded');
// Residue marker
interpolate(markerState, p1, p2, p3, p4, markerDir, markerDir, [rmShift - residueMarkerWidth, rmShift + residueMarkerWidth]);
mb.currentGroup = ResidueMarkerId;
addTube(mb, mCurvePoints, mNormals, mBinormals, MarkerLinearSegmentCount, segCount.radial, mWidthValues, mHeightValues, false, false, 'rounded');
if (segment.capEnd) {
// From the residue marker to C5' of the end
interpolate(state, p1, p2, p3, p4, markerDir, lastDir, [rmShift + residueMarkerWidth, 1]);
mb.currentGroup = SecondBlockId;
addTube(mb, curvePoints, normals, binormals, segCount.linear, segCount.radial, widthValues, heightValues, false, true, 'rounded');
} else {
// From the residue marker to C5' of the step boundary marker
interpolate(state, p1, p2, p3, p4, markerDir, lastDir, [rmShift + residueMarkerWidth, 1 - props.segmentBoundaryWidth]);
mb.currentGroup = SecondBlockId;
addTube(mb, curvePoints, normals, binormals, segCount.linear, segCount.radial, widthValues, heightValues, false, false, 'rounded');
// Step boundary marker
interpolate(markerState, p1, p2, p3, p4, lastDir, lastDir, [1 - props.segmentBoundaryWidth, 1]);
mb.currentGroup = SegmentBoundaryMarkerId;
addTube(mb, mCurvePoints, mNormals, mBinormals, MarkerLinearSegmentCount, segCount.radial, mWidthValues, mHeightValues, false, false, 'rounded');
}
if (segment.followsGap) {
const cylinderProps: CylinderProps = {
radiusTop: diameter / 2, radiusBottom: diameter / 2, topCap: true, bottomCap: true, radialSegments: segCount.radial,
};
mb.currentGroup = FirstBlockId;
addFixedCountDashedCylinder(mb, p_1, p1, 1, 2 * segCount.linear, cylinderProps);
}
}
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, 1.05);
const m = MeshBuilder.getMesh(mb);
m.setBoundingSphere(boundingSphere);
return m;
}
const _rmvCO = Vec3();
const _rmvPO = Vec3();
const _rmPos = Vec3();
const _HalfPi = Math.PI / 2;
function calcResidueMarkerShift(pO: Vec3, pC: Vec3, pP: Vec3): { rmShift: number, rmPos: Vec3 } {
v3sub(_rmvCO, pC, pO);
v3sub(_rmvPO, pP, pO);
// Project position of P atom on the O3' -> C5' vector
const beta = Vec3.angle(_rmvPO, _rmvCO);
const alpha = _HalfPi - Math.abs(beta);
const lengthMO = Math.cos(alpha) * Vec3.magnitude(_rmvPO);
const shift = lengthMO / Vec3.magnitude(_rmvCO);
v3scale(_rmvCO, _rmvCO, shift);
v3add(_rmPos, _rmvCO, pO);
return { rmShift: shift, rmPos: _rmPos };
}
function getNtCTubeSegmentLoci(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 data = NtCTubeProvider.get(structure.model)?.value?.data ?? undefined;
if (!data) return EmptyLoci;
const MeshGroupsCount = totalMeshGroupsCount(data.data.steps);
if (groupId > MeshGroupsCount) return EmptyLoci;
const stepIdx = Math.floor(groupId / 4);
const bs = stepBoundingSphere(data.data.steps[stepIdx], Structure.toStructureElementLoci(structure));
/*
* NOTE 1) Each step is drawn with 4 mesh groups. We need to divide/multiply by 4 to convert between steps and mesh groups.
* NOTE 2) Molstar will create a mesh only for the asymmetric unit. When the entire biological assembly
* is displayed, Molstar just copies and transforms the mesh. This means that even though the mesh
* might be displayed multiple times, groupIds of the individual blocks in the mesh will be the same.
* If there are multiple copies of a mesh, Molstar needs to be able to tell which block belongs to which copy of the mesh.
* To do that, Molstar adds an offset to groupIds of the copied meshes. Offset is calculated as follows:
*
* offset = NumberOfBlocks * UnitIndex
*
* "NumberOfBlocks" is the number of valid Location objects got from LocationIterator *or* the greatest groupId set by
* the mesh generator - whichever is smaller.
*
* UnitIndex is the index of the Unit the mesh belongs to, starting from 0. (See "unitMap" in the Structure object).
* We can also get this index from the value "instanceId" of the "pickingId" object.
*
* If this offset is not applied, picking a piece of one of the copied meshes would actually pick that piece in the original mesh.
* This is particularly apparent with highlighting - hovering over items in a copied mesh incorrectly highlights those items in the source mesh.
*
* Molstar can take advantage of the fact that ElementLoci has a reference to the Unit object attached to it. Since we cannot attach ElementLoci
* to a step, we need to calculate the offseted groupId here and pass it as part of the DataLoci.
*/
const offsetGroupId = stepIdx * 4 + (MeshGroupsCount + 1) * instanceId;
return NTT.Loci(data.data.steps, [stepIdx], [offsetGroupId], bs);
}
function eachNtCTubeSegment(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
if (NTT.isLoci(loci)) {
const offsetGroupId = loci.elements[0];
return apply(Interval.ofBounds(offsetGroupId, offsetGroupId + 4));
}
return false;
}
function NtCTubeVisual(materialId: number): UnitsVisual<NtCTubeMeshParams> {
return UnitsMeshVisual<NtCTubeMeshParams>({
defaultProps: PD.getDefaultValues(NtCTubeMeshParams),
createGeometry: createNtCTubeMesh,
createLocationIterator: createNtCTubeSegmentsIterator,
getLoci: getNtCTubeSegmentLoci,
eachLocation: eachNtCTubeSegment,
setUpdateState: (state: VisualUpdateState, newProps: PD.Values<NtCTubeMeshParams>, currentProps: PD.Values<NtCTubeMeshParams>) => {
state.createGeometry = (
newProps.quality !== currentProps.quality ||
newProps.residueMarkerWidth !== currentProps.residueMarkerWidth ||
newProps.segmentBoundaryWidth !== currentProps.segmentBoundaryWidth ||
newProps.doubleSided !== currentProps.doubleSided ||
newProps.alpha !== currentProps.alpha ||
newProps.linearSegments !== currentProps.linearSegments ||
newProps.radialSegments !== currentProps.radialSegments
);
}
}, materialId);
}
const NtCTubeVisuals = {
'ntc-tube-symbol': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, NtCTubeMeshParams>) => UnitsRepresentation('NtC Tube Mesh', ctx, getParams, NtCTubeVisual),
};
export const NtCTubeParams = {
...NtCTubeMeshParams
};
export type NtCTubeParams = typeof NtCTubeParams;
export function getNtCTubeParams(ctx: ThemeRegistryContext, structure: Structure) {
return PD.clone(NtCTubeParams);
}
export type NtCTubeRepresentation = StructureRepresentation<NtCTubeParams>;
export function NtCTubeRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, NtCTubeParams>): NtCTubeRepresentation {
return Representation.createMulti('NtC Tube', ctx, getParams, StructureRepresentationStateBuilder, NtCTubeVisuals as unknown as Representation.Def<Structure, NtCTubeParams>);
}
export const NtCTubeRepresentationProvider = StructureRepresentationProvider({
name: 'ntc-tube',
label: 'NtC Tube',
description: 'Displays schematic representation of NtC conformers',
factory: NtCTubeRepresentation,
getParams: getNtCTubeParams,
defaultValues: PD.getDefaultValues(NtCTubeParams),
defaultColorTheme: { name: 'ntc-tube' },
defaultSizeTheme: { name: 'uniform', props: { value: 2.0 } },
isApplicable: (structure: Structure) => structure.models.every(m => Dnatco.isApplicable(m)),
ensureCustomProperties: {
attach: async (ctx: CustomProperty.Context, structure: Structure) => structure.models.forEach(m => NtCTubeProvider.attach(ctx, m, void 0, true)),
detach: (data) => data.models.forEach(m => NtCTubeProvider.ref(m, false)),
},
});

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) 2018-2022 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 { NtCTubeSegmentLabel } from './behavior';
import { DnatcoTypes } from '../types';
import { Sphere3D } from '../../../mol-math/geometry/primitives/sphere3d';
import { DataLocation } from '../../../mol-model/location';
import { DataLoci } from '../../../mol-model/loci';
export namespace NtCTubeTypes {
const DataTag = 'dnatco-tube-segment-data';
const DummyTag = 'dnatco-tube-dummy';
export type Data = {
data: DnatcoTypes.Steps,
}
export type TubeBlock = {
step: DnatcoTypes.Step,
kind: 'upper' | 'lower' | 'residue-boundary' | 'segment-boundary';
}
export interface Location extends DataLocation<TubeBlock> {}
export function Location(payload: TubeBlock) {
return DataLocation(DataTag, payload, {});
}
export function isLocation(x: any): x is Location {
return !!x && x.kind === 'data-location' && x.tag === DataTag;
}
export interface Loci extends DataLoci<DnatcoTypes.Step[], number> {}
export interface DummyLoci extends DataLoci<{}, number> {}
export function Loci(data: DnatcoTypes.Step[], stepIndices: number[], elements: number[], boundingSphere?: Sphere3D): Loci {
return DataLoci(DataTag, data, elements, boundingSphere ? () => boundingSphere : undefined, () => stepIndices[0] !== undefined ? NtCTubeSegmentLabel(data[stepIndices[0]]) : '');
}
export function DummyLoci(): DummyLoci {
return DataLoci(DummyTag, {}, [], undefined, () => '');
}
export function isLoci(x: any): x is Loci {
return !!x && x.kind === 'data-loci' && x.tag === DataTag;
}
}

View File

@@ -0,0 +1,191 @@
/**
* Copyright (c) 2018-2022 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 { NtCTubeTypes as NTT } from './types';
import { NtCTubeProvider } from './property';
import { DnatcoUtil } from '../util';
import { Segmentation, SortedArray } from '../../../mol-data/int';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, Unit } from '../../../mol-model/structure';
function getAtomPosition(vec: Vec3, loc: StructureElement.Location, residue: DnatcoUtil.Residue, names: string[], altId: string, insCode: string) {
const eI = DnatcoUtil.getAtomIndex(loc, residue, names, altId, insCode);
if (eI !== -1)
loc.unit.conformation.invariantPosition(eI, vec);
else {
vec[0] = 0; vec[1] = 0; vec[2] = 0;
}
}
const p_1 = Vec3();
const p0 = Vec3();
const p1 = Vec3();
const p2 = Vec3();
const p3 = Vec3();
const p4 = Vec3();
const pP = Vec3();
function getPoints(
loc: StructureElement.Location,
r0: DnatcoUtil.Residue | undefined, r1: DnatcoUtil.Residue, r2: DnatcoUtil.Residue,
altId0: string, altId1: string, altId2: string,
insCode0: string, insCode1: string, insCode2: string,
) {
if (r0) getAtomPosition(p_1, loc, r0, ['C5\'', 'C5*'], altId0, insCode0);
r0 ? getAtomPosition(p0, loc, r0, ['O3\'', 'O3*'], altId0, insCode0) : getAtomPosition(p0, loc, r1, ['O5\'', 'O5*'], altId1, insCode1);
getAtomPosition(p1, loc, r1, ['C5\'', 'C5*'], altId1, insCode1);
getAtomPosition(p2, loc, r1, ['O3\'', 'O3*'], altId1, insCode1);
getAtomPosition(p3, loc, r2, ['C5\'', 'C5*'], altId2, insCode2);
getAtomPosition(p4, loc, r2, ['O3\'', 'O3*'], altId2, insCode2);
getAtomPosition(pP, loc, r2, ['P'], altId2, insCode2);
return { p_1, p0, p1, p2, p3, p4, pP };
}
function hasGapElements(r: DnatcoUtil.Residue, unit: Unit) {
for (let xI = r.start; xI < r.end; xI++) {
const eI = unit.elements[xI];
if (SortedArray.has(unit.gapElements, eI)) {
return true;
}
}
return false;
}
export type NtCTubeSegment = {
p_1: Vec3,
p0: Vec3,
p1: Vec3,
p2: Vec3,
p3: Vec3,
p4: Vec3,
pP: Vec3,
stepIdx: number,
followsGap: boolean,
firstInChain: boolean,
capEnd: boolean,
}
export class NtCTubeSegmentsIterator {
private chainIt: Segmentation.SegmentIterator<ChainIndex>;
private residueIt: Segmentation.SegmentIterator<ResidueIndex>;
/* Second residue of the previous step, may be undefined
* if we are at the beginning of a chain or right after a discontinuity */
private residuePrev?: DnatcoUtil.Residue;
/* First residue of the current step */
private residueOne?: DnatcoUtil.Residue;
/* Second residue of the current step */
private residueTwo: DnatcoUtil.Residue;
/* First residue of the next step, may be undefined
* if we are at the end of a chain.
* Undefined value indicates that the iterator has reached the end.*/
private residueNext?: DnatcoUtil.Residue;
private data?: NTT.Data;
private altIdOne = '';
private insCodeOne = '';
private loc: StructureElement.Location;
private moveStep() {
if (!this.residueNext)
return void 0;
/* Assume discontinuity of the ResidueIndex of the residue that would become residue one (= first residue of the corresponding step)
* does not equal to ResidueIndex of what would be residue two (= second residue of the corresponding step). */
if (this.residueTwo.index + 1 === this.residueNext.index) {
this.residuePrev = DnatcoUtil.copyResidue(this.residueOne);
this.residueOne = DnatcoUtil.copyResidue(this.residueTwo);
this.residueTwo = DnatcoUtil.copyResidue(this.residueNext)!;
this.residueNext = this.residueIt.hasNext ? DnatcoUtil.copyResidue(this.residueIt.move())! : void 0;
} else {
if (!this.residueIt.hasNext) {
this.residueNext = void 0;
return void 0;
}
// There is discontinuity, act as if we were at the beginning of a chain
this.residuePrev = void 0;
this.residueOne = DnatcoUtil.copyResidue(this.residueNext);
this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!;
this.residueNext = this.residueIt.hasNext ? DnatcoUtil.copyResidue(this.residueIt.move())! : void 0;
}
return this.toSegment(this.residuePrev, this.residueOne!, this.residueTwo, this.residueNext);
}
private prime() {
if (this.residueIt.hasNext)
this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!;
if (this.residueIt.hasNext)
this.residueNext = this.residueIt.move();
}
private toSegment(r0: DnatcoUtil.Residue | undefined, r1: DnatcoUtil.Residue, r2: DnatcoUtil.Residue, r3: DnatcoUtil.Residue | undefined): NtCTubeSegment | undefined {
const indices = DnatcoUtil.getStepIndices(this.data!.data, this.loc, r1);
if (indices.length === 0)
return void 0;
const stepIdx = indices[0];
const step = this.data!.data.steps[stepIdx];
const altIdPrev = this.altIdOne;
const insCodePrev = this.insCodeOne;
this.altIdOne = step.label_alt_id_1;
this.insCodeOne = step.PDB_ins_code_1;
const altIdTwo = step.label_alt_id_2;
const insCodeTwo = step.PDB_ins_code_2;
const followsGap = !!r0 && hasGapElements(r0, this.loc.unit) && hasGapElements(r1, this.loc.unit);
const precedesDiscontinuity = r3 ? r3.index !== r2.index + 1 : false;
return {
...getPoints(this.loc, r0, r1, r2, altIdPrev, this.altIdOne, altIdTwo, insCodePrev, this.insCodeOne, insCodeTwo),
stepIdx,
followsGap,
firstInChain: !r0,
capEnd: !this.residueNext || precedesDiscontinuity || hasGapElements(r2, this.loc.unit),
};
}
constructor(structure: Structure, unit: Unit.Atomic) {
this.chainIt = Segmentation.transientSegments(unit.model.atomicHierarchy.chainAtomSegments, unit.elements);
this.residueIt = Segmentation.transientSegments(unit.model.atomicHierarchy.residueAtomSegments, unit.elements);
const prop = NtCTubeProvider.get(unit.model).value;
this.data = prop?.data;
if (this.chainIt.hasNext) {
this.residueIt.setSegment(this.chainIt.move());
this.prime();
}
this.loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex);
}
get hasNext() {
if (!this.data)
return false;
return !!this.residueNext
? true
: this.chainIt.hasNext;
}
move() {
if (!!this.residueNext) {
return this.moveStep();
} else {
this.residuePrev = void 0; // Assume discontinuity when we switch chains
this.residueNext = void 0;
this.residueIt.setSegment(this.chainIt.move());
this.prime();
return this.moveStep();
}
}
}

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 { DnatcoTypes } from './types';
import { Column, Table } from '../../mol-data/db';
import { toTable } from '../../mol-io/reader/cif/schema';
import { Model } from '../../mol-model/structure';
import { CustomProperty } from '../../mol-model-props/common/custom-property';
import { PropertyWrapper } from '../../mol-model-props/common/wrapper';
import { MmcifFormat } from '../../mol-model-formats/structure/mmcif';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
export type DnatcoSteps = PropertyWrapper<DnatcoTypes.Steps | undefined>;
export const DnatcoParams = {};
export type DnatcoParams = typeof DnatcoParams;
export type DnatcoProps = PD.Values<DnatcoParams>;
export namespace Dnatco {
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 function getStepsFromCif(
model: Model,
cifSteps: Table<typeof Dnatco.Schema.ndb_struct_ntc_step>,
stepsSummary: StepsSummaryTable
): DnatcoTypes.Steps {
const steps = new Array<DnatcoTypes.Step>();
const mapping = new Array<DnatcoTypes.MappedChains>();
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
} = cifSteps;
if (_rowCount !== stepsSummary._rowCount) throw new Error('Inconsistent mmCIF data');
for (let i = 0; i < _rowCount; i++) {
const {
NtC,
confal_score,
rmsd
} = getSummaryData(id.value(i), i, stepsSummary);
const modelNum = PDB_model_number.value(i);
const chainId = auth_asym_id_1.value(i);
const seqId = auth_seq_id_1.value(i);
const modelIdx = modelNum - 1;
if (mapping.length <= modelIdx || !mapping[modelIdx])
mapping[modelIdx] = new Map<string, DnatcoTypes.MappedResidues>();
const step = {
PDB_model_number: modelNum,
name: name.value(i),
auth_asym_id_1: chainId,
auth_seq_id_1: seqId,
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,
NtC,
rmsd,
};
steps.push(step);
const mappedChains = mapping[modelIdx];
const residuesOnChain = mappedChains.get(chainId) ?? new Map<number, number[]>();
const stepsForResidue = residuesOnChain.get(seqId) ?? [];
stepsForResidue.push(steps.length - 1);
residuesOnChain.set(seqId, stepsForResidue);
mappedChains.set(chainId, residuesOnChain);
mapping[modelIdx] = mappedChains;
}
return { steps, mapping };
}
export async function fromCif(ctx: CustomProperty.Context, model: Model, props: DnatcoProps): Promise<CustomProperty.Data<DnatcoSteps>> {
const info = PropertyWrapper.createInfo();
const data = getCifData(model);
if (data === undefined) return { value: { info, data: undefined } };
const fromCif = getStepsFromCif(model, data.steps, data.stepsSummary);
return { value: { info, data: fromCif } };
}
export 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);
}
}
type StepsSummaryTable = Table<typeof Dnatco.Schema.ndb_struct_ntc_step_summary>;
function getSummaryData(id: number, i: number, stepsSummary: StepsSummaryTable) {
const {
step_id,
confal_score,
assigned_NtC,
cartesian_rmsd_closest_NtC_representative,
} = 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), rmsd: cartesian_rmsd_closest_NtC_representative.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), rmsd: cartesian_rmsd_closest_NtC_representative.value(j) };
}
throw new Error('Inconsistent mmCIF data');
}

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2018-2022 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 namespace DnatcoTypes {
export const DataTag = 'dnatco-confal-half-step';
export type Step = {
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,
rmsd: number,
}
export type MappedChains = Map<string, MappedResidues>;
export type MappedResidues = Map<number, number[]>;
export interface Steps {
steps: Array<Step>,
mapping: MappedChains[],
}
export interface HalfStep {
step: Step,
isLower: boolean,
}
}

View File

@@ -0,0 +1,117 @@
/**
* Copyright (c) 2018-2022 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 { DnatcoTypes } from './types';
import { OrderedSet, Segmentation } from '../../mol-data/int';
import { EmptyLoci } from '../../mol-model/loci';
import { ElementIndex, ResidueIndex, Structure, StructureElement, StructureProperties, Unit } from '../../mol-model/structure';
const EmptyStepIndices = new Array<number>();
export namespace DnatcoUtil {
export type Residue = Segmentation.Segment<ResidueIndex>;
export function copyResidue(r?: Residue) {
return r ? { index: r.index, start: r.start, end: r.end } : void 0;
}
export function getAtomIndex(loc: StructureElement.Location, residue: Residue, names: string[], altId: string, insCode: string): ElementIndex {
for (let eI = residue.start; eI < residue.end; eI++) {
loc.element = loc.unit.elements[eI];
const elName = StructureProperties.atom.label_atom_id(loc);
const elAltId = StructureProperties.atom.label_alt_id(loc);
const elInsCode = StructureProperties.residue.pdbx_PDB_ins_code(loc);
if (names.includes(elName) && (elAltId === altId || elAltId.length === 0) && (elInsCode === insCode))
return loc.element;
}
return -1 as ElementIndex;
}
export function getStepIndices(data: DnatcoTypes.Steps, loc: StructureElement.Location, r: DnatcoUtil.Residue) {
loc.element = loc.unit.elements[r.start];
const modelIdx = StructureProperties.unit.model_num(loc) - 1;
const chainId = StructureProperties.chain.auth_asym_id(loc);
const seqId = StructureProperties.residue.auth_seq_id(loc);
const insCode = StructureProperties.residue.pdbx_PDB_ins_code(loc);
const chains = data.mapping[modelIdx];
if (!chains) return EmptyStepIndices;
const residues = chains.get(chainId);
if (!residues) return EmptyStepIndices;
const indices = residues.get(seqId);
if (!indices) return EmptyStepIndices;
return insCode !== '' ? indices.filter(idx => data.steps[idx].PDB_ins_code_1 === insCode) : indices;
}
export function residueAltIds(structure: Structure, unit: Unit, residue: Residue) {
const altIds = new Array<string>();
const loc = StructureElement.Location.create(structure, unit);
for (let eI = residue.start; eI < residue.end; eI++) {
loc.element = OrderedSet.getAt(unit.elements, eI);
const altId = StructureProperties.atom.label_alt_id(loc);
if (altId !== '' && !altIds.includes(altId))
altIds.push(altId);
}
return altIds;
}
const _loc = StructureElement.Location.create();
export function residueToLoci(asymId: string, seqId: number, altId: string | undefined, insCode: string, loci: StructureElement.Loci, source: 'label' | 'auth') {
_loc.structure = loci.structure;
for (const e of loci.elements) {
_loc.unit = e.unit;
const getAsymId = source === 'label' ? StructureProperties.chain.label_asym_id : StructureProperties.chain.auth_asym_id;
const getSeqId = source === 'label' ? StructureProperties.residue.label_seq_id : StructureProperties.residue.auth_seq_id;
// Walk the entire unit and look for the requested residue
const chainIt = Segmentation.transientSegments(e.unit.model.atomicHierarchy.chainAtomSegments, e.unit.elements);
const residueIt = Segmentation.transientSegments(e.unit.model.atomicHierarchy.residueAtomSegments, e.unit.elements);
const elemIndex = (idx: number) => OrderedSet.getAt(e.unit.elements, idx);
while (chainIt.hasNext) {
const chain = chainIt.move();
_loc.element = elemIndex(chain.start);
const _asymId = getAsymId(_loc);
if (_asymId !== asymId)
continue; // Wrong chain, skip it
residueIt.setSegment(chain);
while (residueIt.hasNext) {
const residue = residueIt.move();
_loc.element = elemIndex(residue.start);
const _seqId = getSeqId(_loc);
if (_seqId === seqId) {
const _insCode = StructureProperties.residue.pdbx_PDB_ins_code(_loc);
if (_insCode !== insCode)
continue;
if (altId) {
const _altIds = residueAltIds(loci.structure, e.unit, residue);
if (!_altIds.includes(altId))
continue;
}
const start = residue.start as StructureElement.UnitIndex;
const end = residue.end as StructureElement.UnitIndex;
return StructureElement.Loci(
loci.structure,
[{ unit: e.unit, indices: OrderedSet.ofBounds(start, end) }]
);
}
}
}
}
return EmptyLoci;
}
}

View File

@@ -29,7 +29,7 @@ export const GeometryParams = {
export class GeometryControls extends PluginComponent {
readonly behaviors = {
params: this.ev.behavior<PD.Values<typeof GeometryParams>>(PD.getDefaultValues(GeometryParams))
}
};
private getFilename() {
const models = this.plugin.state.data.select(StateSelection.Generators.rootsOfType(PluginStateObject.Molecule.Model)).map(s => s.obj!.data);

View File

@@ -25,7 +25,7 @@ import { sizeDataFactor } from '../../mol-geo/geometry/size-data';
import { Vec3 } from '../../mol-math/linear-algebra';
import { RuntimeContext } from '../../mol-task';
import { Color } from '../../mol-util/color/color';
import { decodeFloatRGB } from '../../mol-util/float-packing';
import { unpackRGBToInt } from '../../mol-util/number-packing';
import { RenderObjectExporter, RenderObjectExportData } from './render-object-exporter';
import { readAlphaTexture, readTexture } from '../../mol-gl/compute/util';
@@ -65,7 +65,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements
const r = tSize.array[i * 3];
const g = tSize.array[i * 3 + 1];
const b = tSize.array[i * 3 + 2];
return decodeFloatRGB(r, g, b) / sizeDataFactor;
return unpackRGBToInt(r, g, b) / sizeDataFactor;
}
private static getSize(values: BaseValues & SizeValues, instanceIndex: number, group: number): number {
@@ -95,9 +95,9 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements
const g = groups[i4 + 1];
const b = groups[i4 + 2];
if (groups instanceof Float32Array) {
return decodeFloatRGB(r * 255 + 0.5, g * 255 + 0.5, b * 255 + 0.5);
return unpackRGBToInt(r * 255 + 0.5, g * 255 + 0.5, b * 255 + 0.5);
}
return decodeFloatRGB(r, g, b);
return unpackRGBToInt(r, g, b);
}
protected static getInterpolatedColors(webgl: WebGLContext, input: { vertices: Float32Array, vertexCount: number, values: BaseValues, stride: 3 | 4, colorType: 'volume' | 'volumeInstance' }) {

View File

@@ -60,6 +60,8 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
}
componentDidMount() {
if (!this.plugin.canvas3d) return;
const merged = merge(
this.controls.behaviors.params,
this.plugin.canvas3d!.reprCount
@@ -71,6 +73,7 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
}
componentWillUnmount() {
super.componentWillUnmount();
this._controls?.dispose();
this._controls = void 0;
}
@@ -85,7 +88,7 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
} finally {
this.setState({ busy: false });
}
}
};
viewInAR = async () => {
try {
@@ -104,5 +107,5 @@ export class GeometryExporterUI extends CollapsableControls<{}, State> {
} finally {
this.setState({ busy: false });
}
}
};
}

View File

@@ -0,0 +1,187 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
/** Testing examples for using mesh-extension.ts. */
import { CIF } from '../../mol-io/reader/cif';
import { Volume } from '../../mol-model/volume';
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { PluginContext } from '../../mol-plugin/context';
import { StateObjectSelector } from '../../mol-state';
import { Asset } from '../../mol-util/assets';
import { Color } from '../../mol-util/color';
import { ParamDefinition } from '../../mol-util/param-definition';
import { createMeshFromUrl } from './mesh-extension';
import { MeshServerInfo } from './mesh-streaming/server-info';
import { InitMeshStreaming } from './mesh-streaming/transformers';
import * as MeshUtils from './mesh-utils';
export const DB_URL = '/db'; // local
export async function runMeshExtensionExamples(plugin: PluginContext, db_url: string = DB_URL) {
console.time('TIME MESH EXAMPLES');
// await runIsosurfaceExample(plugin, db_url);
// await runMolsurfaceExample(plugin);
// Focused Ion Beam-Scanning Electron Microscopy of mitochondrial reticulum in murine skeletal muscle: https://www.ebi.ac.uk/empiar/EMPIAR-10070/
// await runMeshExample(plugin, 'all', db_url);
// await runMeshExample(plugin, 'fg', db_url);
// await runMultimeshExample(plugin, 'fg', 'worst', db_url);
// await runCifMeshExample(plugin);
// await runMeshExample2(plugin, 'fg');
await runMeshStreamingExample(plugin);
console.timeEnd('TIME MESH EXAMPLES');
}
/** Example for downloading multiple separate segments, each containing 1 mesh. */
export async function runMeshExample(plugin: PluginContext, segments: 'fg' | 'all', db_url: string = DB_URL) {
const detail = 2;
const segmentIds = (segments === 'all') ?
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17] // segment-16 has no detail-2
: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 17]; // segment-13 and segment-15 are quasi background
for (const segmentId of segmentIds) {
await createMeshFromUrl(plugin, `${db_url}/empiar-10070-mesh-rounded/segment-${segmentId}/detail-${detail}`, segmentId, detail, true, undefined);
}
}
/** Example for downloading multiple separate segments, each containing 1 mesh. */
export async function runMeshExample2(plugin: PluginContext, segments: 'one' | 'few' | 'fg' | 'all') {
const detail = 1;
const segmentIds = (segments === 'one') ? [15]
: (segments === 'few') ? [1, 4, 7, 10, 16]
: (segments === 'all') ? [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17] // segment-16 has no detail-2
: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 17]; // segment-13 and segment-15 are quasi background
for (const segmentId of segmentIds) {
await createMeshFromUrl(plugin, `http://localhost:9000/v2/empiar/empiar-10070/mesh_bcif/${segmentId}/${detail}`, segmentId, detail, false, undefined);
}
}
/** Example for downloading a single segment containing multiple meshes. */
export async function runMultimeshExample(plugin: PluginContext, segments: 'fg' | 'all', detailChoice: 'best' | 'worst', db_url: string = DB_URL) {
const urlDetail = (detailChoice === 'best') ? '2' : 'worst';
const numDetail = (detailChoice === 'best') ? 2 : 1000;
await createMeshFromUrl(plugin, `${db_url}/empiar-10070-multimesh-rounded/segments-${segments}/detail-${urlDetail}`, 0, numDetail, false, undefined);
}
export async function runMeshStreamingExample(plugin: PluginContext, source: MeshServerInfo.MeshSource = 'empiar', entryId: string = 'empiar-10070', serverUrl?: string, parent?: StateObjectSelector) {
const params = ParamDefinition.getDefaultValues(MeshServerInfo.Params);
if (serverUrl) params.serverUrl = serverUrl;
params.source = source;
params.entryId = entryId;
await plugin.runTask(plugin.state.data.applyAction(InitMeshStreaming, params, parent?.ref), { useOverlay: false });
}
/** Example for downloading a protein structure and visualizing molecular surface. */
export async function runMolsurfaceExample(plugin: PluginContext) {
const entryId = 'pdb-7etq';
// Node "https://www.ebi.ac.uk/pdbe/entry-files/download/7etq.bcif" ("transformer": "ms-plugin.download") -> var data
const data = await plugin.builders.data.download({ url: 'https://www.ebi.ac.uk/pdbe/entry-files/download/7etq.bcif', isBinary: true }, { state: { isGhost: false } });
console.log('formats:', plugin.dataFormats.list);
// Node "CIF File" ("transformer": "ms-plugin.parse-cif")
// Node "7ETQ 1 model" ("transformer": "ms-plugin.trajectory-from-mmcif") -> var trajectory
const parsed = await plugin.dataFormats.get('mmcif')!.parse(plugin, data, { entryId });
const trajectory: StateObjectSelector<PluginStateObject.Molecule.Trajectory> = parsed.trajectory;
console.log('parsed', parsed);
console.log('trajectory', trajectory);
// Node "Model 1" ("transformer": "ms-plugin.model-from-trajectory") -> var model
const model = await plugin.build().to(trajectory).apply(StateTransforms.Model.ModelFromTrajectory).commit();
console.log('model:', model);
// Node "Model 91 elements" ("transformer": "ms-plugin.structure-from-model") -> var structure
const structure = await plugin.build().to(model).apply(StateTransforms.Model.StructureFromModel,).commit();
console.log('structure:', structure);
// Node "Molecular Surface" ("transformer": "ms-plugin.structure-representation-3d") -> var repr
const reprParams = createStructureRepresentationParams(plugin, undefined, { type: 'molecular-surface' });
const repr = await plugin.build().to(structure).apply(StateTransforms.Representation.StructureRepresentation3D, reprParams).commit();
console.log('repr:', repr);
}
/** Example for downloading an EMDB density data and visualizing isosurface. */
export async function runIsosurfaceExample(plugin: PluginContext, db_url: string = DB_URL) {
const entryId = 'emd-1832';
const isoLevel = 2.73;
let root = await plugin.build();
const data = await plugin.builders.data.download({ url: `${db_url}/emd-1832-box`, isBinary: true }, { state: { isGhost: false } });
const parsed = await plugin.dataFormats.get('dscif')!.parse(plugin, data, { entryId });
const volume: StateObjectSelector<PluginStateObject.Volume.Data> = parsed.volumes?.[0] ?? parsed.volume;
const volumeData = volume.cell!.obj!.data;
console.log('data:', data);
console.log('parsed:', parsed);
console.log('volume:', volume);
console.log('volumeData:', volumeData);
root = await plugin.build();
console.log('root:', root);
console.log('to:', root.to(volume));
console.log('toRoot:', root.toRoot());
let volumeParams;
volumeParams = createVolumeRepresentationParams(plugin, volumeData, {
type: 'isosurface',
typeParams: {
alpha: 0.5,
isoValue: Volume.adjustedIsoValue(volumeData, isoLevel, 'relative'),
visuals: ['solid'],
sizeFactor: 1,
},
color: 'uniform',
colorParams: { value: Color(0x00aaaa) },
});
root.to(volume).apply(StateTransforms.Representation.VolumeRepresentation3D, volumeParams);
volumeParams = createVolumeRepresentationParams(plugin, volumeData, {
type: 'isosurface',
typeParams: {
alpha: 1.0,
isoValue: Volume.adjustedIsoValue(volumeData, isoLevel, 'relative'),
visuals: ['wireframe'],
sizeFactor: 1,
},
color: 'uniform',
colorParams: { value: Color(0x8800aa) },
});
root.to(volume).apply(StateTransforms.Representation.VolumeRepresentation3D, volumeParams);
await root.commit();
}
export async function runCifMeshExample(plugin: PluginContext, api: string = 'http://localhost:9000/v2',
source: MeshServerInfo.MeshSource = 'empiar', entryId: string = 'empiar-10070',
segmentId: number = 1, detail: number = 10,
) {
const url = `${api}/${source}/${entryId}/mesh_bcif/${segmentId}/${detail}`;
getMeshFromBcif(plugin, url);
}
async function getMeshFromBcif(plugin: PluginContext, url: string) {
const urlAsset = Asset.getUrlAsset(plugin.managers.asset, url);
const asset = await plugin.runTask(plugin.managers.asset.resolve(urlAsset, 'binary'));
const parsed = await plugin.runTask(CIF.parseBinary(asset.data));
if (parsed.isError) {
plugin.log.error('VolumeStreaming, parsing CIF: ' + parsed.toString());
return;
}
console.log('blocks:', parsed.result.blocks);
const mesh = await MeshUtils.meshFromCif(parsed.result);
console.log(mesh);
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
import { Column, Database } from '../../mol-data/db';
import { CifFrame } from '../../mol-io/reader/cif';
import { toDatabase } from '../../mol-io/reader/cif/schema';
const int = Column.Schema.int;
const float = Column.Schema.float;
// TODO in future, move to molstar/src/mol-io/reader/cif/schema/mesh.ts
export const Mesh_Data_Schema = {
mesh: {
id: int,
},
mesh_vertex: {
mesh_id: int,
vertex_id: int,
x: float,
y: float,
z: float,
},
/** Table of triangles, 3 rows per triangle */
mesh_triangle: {
mesh_id: int,
/** Indices of vertices within mesh */
vertex_id: int,
}
};
export type Mesh_Data_Schema = typeof Mesh_Data_Schema;
export interface Mesh_Data_Database extends Database<Mesh_Data_Schema> {}
// TODO in future, move to molstar/src/mol-io/reader/cif.ts: CIF.schema.mesh
export const CIF_schema_mesh = (frame: CifFrame) => toDatabase<Mesh_Data_Schema, Mesh_Data_Database>(Mesh_Data_Schema, frame);

View File

@@ -0,0 +1,223 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
/** Defines new types of State tree transformers for dealing with mesh data. */
import { BaseGeometry, VisualQuality, VisualQualityOptions } from '../../mol-geo/geometry/base';
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
import { CifFile } from '../../mol-io/reader/cif';
import { Box3D } from '../../mol-math/geometry';
import { Vec3 } from '../../mol-math/linear-algebra';
import { Shape } from '../../mol-model/shape';
import { ShapeProvider } from '../../mol-model/shape/provider';
import { PluginStateObject } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { Download } from '../../mol-plugin-state/transforms/data';
import { ShapeRepresentation3D } from '../../mol-plugin-state/transforms/representation';
import { PluginContext } from '../../mol-plugin/context';
import { StateObjectRef, StateObjectSelector, StateTransformer } from '../../mol-state';
import { Task } from '../../mol-task';
import { Color } from '../../mol-util/color';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import * as MeshUtils from './mesh-utils';
export const BACKGROUND_OPACITY = 0.2;
export const FOREROUND_OPACITY = 1;
export const VolsegTransform: StateTransformer.Builder.Root = StateTransformer.builderFactory('volseg');
// // // // // // // // // // // // // // // // // // // // // // // //
// Parsed data
/** Data type for `MeshlistStateObject` - list of meshes */
export interface MeshlistData {
segmentId: number,
segmentName: string,
detail: number,
meshIds: number[],
mesh: Mesh,
/** Reference to the object which created this meshlist (e.g. `MeshStreaming.Behavior`) */
ownerId?: string,
}
export namespace MeshlistData {
export function empty(): MeshlistData {
return {
segmentId: 0,
segmentName: 'Empty',
detail: 0,
meshIds: [],
mesh: Mesh.createEmpty(),
};
};
export async function fromCIF(data: CifFile, segmentId: number, segmentName: string, detail: number): Promise<MeshlistData> {
const { mesh, meshIds } = await MeshUtils.meshFromCif(data);
return {
segmentId,
segmentName,
detail,
meshIds,
mesh,
};
}
export function stats(meshListData: MeshlistData): string {
return `Meshlist "${meshListData.segmentName}" (detail ${meshListData.detail}): ${meshListData.meshIds.length} meshes, ${meshListData.mesh.vertexCount} vertices, ${meshListData.mesh.triangleCount} triangles`;
}
export function getShape(data: MeshlistData, color: Color): Shape<Mesh> {
const mesh = data.mesh;
const meshShape: Shape<Mesh> = Shape.create(data.segmentName, data, mesh,
() => color,
() => 1,
// group => `${data.segmentName} | Segment ${data.segmentId} | Detail ${data.detail} | Mesh ${group}`,
group => data.segmentName,
);
return meshShape;
}
export function combineBBoxes(boxes: (Box3D | null)[]): Box3D | null {
let result = null;
for (const box of boxes) {
if (!box) continue;
if (result) {
Vec3.min(result.min, result.min, box.min);
Vec3.max(result.max, result.max, box.max);
} else {
result = Box3D.zero();
Box3D.copy(result, box);
}
}
return result;
}
export function bbox(data: MeshlistData): Box3D | null {
return MeshUtils.bbox(data.mesh);
}
export function allVerticesUsed(data: MeshlistData): boolean {
const unusedVertices = new Set();
for (let i = 0; i < data.mesh.vertexCount; i++) {
unusedVertices.add(i);
}
for (let i = 0; i < 3 * data.mesh.triangleCount; i++) {
const v = data.mesh.vertexBuffer.ref.value[i];
unusedVertices.delete(v);
}
return unusedVertices.size === 0;
}
}
// // // // // // // // // // // // // // // // // // // // // // // //
// Raw Data -> Parsed data
export class MeshlistStateObject extends PluginStateObject.Create<MeshlistData>({ name: 'Parsed Meshlist', typeClass: 'Object' }) { }
export const ParseMeshlistTransformer = VolsegTransform({
name: 'meshlist-from-string',
from: PluginStateObject.Format.Cif,
to: MeshlistStateObject,
params: {
label: PD.Text(MeshlistStateObject.type.name, { isHidden: true }),
segmentId: PD.Numeric(1, {}, { isHidden: true }),
segmentName: PD.Text('Segment'),
detail: PD.Numeric(1, {}, { isHidden: true }),
/** Reference to the object which manages this meshlist (e.g. `MeshStreaming.Behavior`) */
ownerId: PD.Text('', { isHidden: true }),
}
})({
apply({ a, params }, globalCtx) { // `a` is the parent node, params are 2nd argument to To.apply(), `globalCtx` is the plugin
return Task.create('Create Parsed Meshlist', async ctx => {
const meshlistData = await MeshlistData.fromCIF(a.data, params.segmentId, params.segmentName, params.detail);
meshlistData.ownerId = params.ownerId;
const es = meshlistData.meshIds.length === 1 ? '' : 'es';
return new MeshlistStateObject(meshlistData, { label: params.label, description: `${meshlistData.segmentName} (${meshlistData.meshIds.length} mesh${es})` });
});
}
});
// // // // // // // // // // // // // // // // // // // // // // // //
// Parsed data -> Shape
/** Data type for PluginStateObject.Shape.Provider */
type MeshShapeProvider = ShapeProvider<MeshlistData, Mesh, Mesh.Params>;
namespace MeshShapeProvider {
export function fromMeshlistData(meshlist: MeshlistData, color?: Color): MeshShapeProvider {
const theColor = color ?? MeshUtils.ColorGenerator.next().value;
return {
label: 'Mesh',
data: meshlist,
params: meshShapeProviderParams,
geometryUtils: Mesh.Utils,
getShape: (ctx, data: MeshlistData) => MeshlistData.getShape(data, theColor),
};
}
}
const meshShapeProviderParams: Mesh.Params = {
...Mesh.Params,
quality: PD.Select<VisualQuality>('custom', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }), // use 'custom' when wanting to apply doubleSided
doubleSided: PD.Boolean(true, BaseGeometry.CustomQualityParamInfo),
// set `flatShaded`: true to see the real mesh vertices and triangles
transparentBackfaces: PD.Select('on', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory), // 'on' means: show backfaces with correct opacity, even when opacity < 1 (requires doubleSided) ¯\_(ツ)_/¯
};
export const MeshShapeTransformer = VolsegTransform({
name: 'shape-from-meshlist',
display: { name: 'Shape from Meshlist', description: 'Create Shape from Meshlist data' },
from: MeshlistStateObject,
to: PluginStateObject.Shape.Provider,
params: {
color: PD.Value<Color | undefined>(undefined), // undefined means random color
},
})({
apply({ a, params }) {
const shapeProvider = MeshShapeProvider.fromMeshlistData(a.data, params.color);
return new PluginStateObject.Shape.Provider(shapeProvider, { label: PluginStateObject.Shape.Provider.type.name, description: a.description });
}
});
// // // // // // // // // // // // // // // // // // // // // // // //
/** Download data and create state tree hierarchy down to visual representation. */
export async function createMeshFromUrl(plugin: PluginContext, meshDataUrl: string, segmentId: number, detail: number,
collapseTree: boolean, color?: Color, parent?: StateObjectSelector | StateObjectRef, transparentIfBboxAbove?: number,
name?: string, ownerId?: string) {
const update = parent ? plugin.build().to(parent) : plugin.build().toRoot();
const rawDataNodeRef = update.apply(Download,
{ url: meshDataUrl, isBinary: true, label: `Downloaded Data ${segmentId}` },
{ state: { isCollapsed: collapseTree } }
).ref;
const parsedDataNode = await update.to(rawDataNodeRef)
.apply(StateTransforms.Data.ParseCif)
.apply(ParseMeshlistTransformer,
{ label: undefined, segmentId: segmentId, segmentName: name ?? `Segment ${segmentId}`, detail: detail, ownerId: ownerId },
{}
)
.commit();
let transparent = false;
if (transparentIfBboxAbove !== undefined && parsedDataNode.data) {
const bbox = MeshlistData.bbox(parsedDataNode.data) || Box3D.zero();
transparent = Box3D.volume(bbox) > transparentIfBboxAbove;
}
await plugin.build().to(parsedDataNode)
.apply(MeshShapeTransformer, { color: color },)
.apply(ShapeRepresentation3D,
{ alpha: transparent ? BACKGROUND_OPACITY : FOREROUND_OPACITY },
{ tags: ['mesh-segment-visual', `segment-${segmentId}`] }
)
.commit();
return rawDataNodeRef;
}

View File

@@ -0,0 +1,332 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
import { distinctUntilChanged, map } from 'rxjs';
import { CIF } from '../../../mol-io/reader/cif';
import { Box3D } from '../../../mol-math/geometry';
import { PluginStateObject } from '../../../mol-plugin-state/objects';
import { PluginBehavior } from '../../../mol-plugin/behavior';
import { PluginCommand } from '../../../mol-plugin/command';
import { PluginCommands } from '../../../mol-plugin/commands';
import { PluginContext } from '../../../mol-plugin/context';
import { UUID } from '../../../mol-util';
import { Asset } from '../../../mol-util/assets';
import { Color } from '../../../mol-util/color';
import { ColorNames } from '../../../mol-util/color/names';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Choice } from '../../volumes-and-segmentations/helpers';
import { MetadataWrapper } from '../../volumes-and-segmentations/volseg-api/utils';
import { MeshlistData } from '../mesh-extension';
import { MeshServerInfo } from './server-info';
const DEFAULT_SEGMENT_NAME = 'Untitled segment';
const DEFAULT_SEGMENT_COLOR = ColorNames.lightgray;
export const NO_SEGMENT = -1;
/** Maximum (worst) detail level available in GUI (TODO set actual maximum possible value) */
const MAX_DETAIL = 10;
const DEFAULT_DETAIL = 7; // TODO decide a reasonable default
/** Segments whose bounding box volume is above this value (relative to the overall bounding box) are considered as background segments */
export const BACKGROUND_SEGMENT_VOLUME_THRESHOLD = 0.5;
export class MeshStreaming extends PluginStateObject.CreateBehavior<MeshStreaming.Behavior>({ name: 'Mesh Streaming' }) { }
export namespace MeshStreaming {
export namespace Params {
export const ViewTypeChoice = new Choice({ off: 'Off', select: 'Select', all: 'All' }, 'select'); // TODO add camera target?
export type ViewType = Choice.Values<typeof ViewTypeChoice>;
export function create(options: MeshServerInfo.Data) {
return {
view: PD.MappedStatic('select', {
'off': PD.Group({}),
'select': PD.Group({
baseDetail: PD.Numeric(DEFAULT_DETAIL, { min: 1, max: MAX_DETAIL, step: 1 }, { description: 'Detail level for the non-selected segments (lower number = better)' }),
focusDetail: PD.Numeric(1, { min: 1, max: MAX_DETAIL, step: 1 }, { description: 'Detail level for the selected segment (lower number = better)' }),
selectedSegment: PD.Numeric(NO_SEGMENT, {}, { isHidden: true }),
}, { isFlat: true }),
'all': PD.Group({
detail: PD.Numeric(DEFAULT_DETAIL, { min: 1, max: MAX_DETAIL, step: 1 }, { description: 'Detail level for all segments (lower number = better)' })
}, { isFlat: true }),
}, { description: '"Off" hides all segments. \n"Select" shows all segments in lower detail, clicked segment in better detail. "All" shows all segment in the same level.' }),
};
}
export type Definition = ReturnType<typeof create>
export type Values = PD.Values<Definition>
export function copyValues(params: Values): Values {
return {
view: {
name: params.view.name,
params: { ...params.view.params } as any,
}
};
}
export function valuesEqual(p: Values, q: Values): boolean {
if (p.view.name !== q.view.name) return false;
for (const key in p.view.params) {
if ((p.view.params as any)[key] !== (q.view.params as any)[key]) return false;
}
return true;
}
export function detailsEqual(p: Values, q: Values): boolean {
switch (p.view.name) {
case 'off':
return q.view.name === 'off';
case 'select':
return q.view.name === 'select' && p.view.params.baseDetail === q.view.params.baseDetail && p.view.params.focusDetail === q.view.params.focusDetail;
case 'all':
return q.view.name === 'all' && p.view.params.detail === q.view.params.detail;
default:
throw new Error('Not implemented');
}
}
}
export interface VisualInfo {
tag: string, // e.g. high-2, low-1 // ? remove if can be omitted
segmentId: number, // ? remove if unused
segmentName: string, // ? remove if unused
detailType: VisualInfo.DetailType, // ? remove if unused
detail: number, // ? remove if unused
color: Color, // move to MeshlistData?
visible: boolean,
data?: MeshlistData,
}
export namespace VisualInfo {
export type DetailType = 'low' | 'high';
export const DetailTypes: DetailType[] = ['low', 'high'];
export function tagFor(segmentId: number, detail: DetailType) {
return `${detail}-${segmentId}`;
}
}
export class Behavior extends PluginBehavior.WithSubscribers<Params.Values> {
private id: string;
private ref: string = '';
public parentData: MeshServerInfo.Data;
private metadata?: MetadataWrapper;
public visuals?: { [tag: string]: VisualInfo };
public backgroundSegments: { [segmentId: number]: boolean } = {};
private focusObservable = this.plugin.behaviors.interaction.click.pipe( // QUESTION is this OK way to get focused segment?
map(evt => evt.current.loci),
map(loci => (loci.kind === 'group-loci') ? loci.shape.sourceData as MeshlistData : null),
map(data => (data?.ownerId === this.id) ? data : null), // do not process shapes created by others
distinctUntilChanged((old, current) => old?.segmentId === current?.segmentId),
);
private focusSubscription?: PluginCommand.Subscription = undefined;
private backgroundSegmentsInitialized = false;
constructor(plugin: PluginContext, data: MeshServerInfo.Data, params: Params.Values) {
super(plugin, params);
this.id = UUID.create22();
this.parentData = data;
}
register(ref: string): void {
this.ref = ref;
}
unregister(): void {
if (this.focusSubscription) {
this.focusSubscription.unsubscribe();
this.focusSubscription = undefined;
}
// TODO empty cache here (if used)
}
selectSegment(segmentId: number) {
if (this.params.view.name === 'select') {
if (this.params.view.params.selectedSegment === segmentId) return;
const newParams = Params.copyValues(this.params);
if (newParams.view.name === 'select') {
newParams.view.params.selectedSegment = segmentId;
}
const state = this.plugin.state.data;
const update = state.build().to(this.ref).update(newParams);
PluginCommands.State.Update(this.plugin, { state, tree: update, options: { doNotUpdateCurrent: true } });
}
}
async update(params: Params.Values) {
const oldParams = this.params;
this.params = params;
if (!this.metadata) {
const response = await fetch(this.getMetadataUrl());
const rawMetadata = await response.json();
this.metadata = new MetadataWrapper(rawMetadata);
}
if (!this.visuals) {
this.initVisualInfos();
} else if (!Params.detailsEqual(this.params, oldParams)) {
this.updateVisualInfoDetails();
}
switch (params.view.name) {
case 'off':
await this.disableVisuals();
break;
case 'select':
await this.enableVisuals(params.view.params.selectedSegment);
break;
case 'all':
await this.enableVisuals();
break;
default:
throw new Error('Not implemented');
}
if (params.view.name !== 'off' && !this.backgroundSegmentsInitialized) {
this.guessBackgroundSegments();
this.backgroundSegmentsInitialized = true;
}
if (params.view.name === 'select' && !this.focusSubscription) {
this.focusSubscription = this.subscribeObservable(this.focusObservable, data => { this.selectSegment(data?.segmentId ?? NO_SEGMENT); });
} else if (params.view.name !== 'select' && this.focusSubscription) {
this.focusSubscription.unsubscribe();
this.focusSubscription = undefined;
}
return true;
}
private getMetadataUrl() {
return `${this.parentData.serverUrl}/${this.parentData.source}/${this.parentData.entryId}/metadata`;
}
private getMeshUrl(segment: number, detail: number) {
return `${this.parentData.serverUrl}/${this.parentData.source}/${this.parentData.entryId}/mesh_bcif/${segment}/${detail}`;
}
private initVisualInfos() {
const visuals: { [tag: string]: VisualInfo } = {};
for (const segid of this.metadata!.meshSegmentIds) {
const name = this.metadata?.getSegment(segid)?.biological_annotation.name ?? DEFAULT_SEGMENT_NAME;
const color = this.metadata?.getSegmentColor(segid) ?? DEFAULT_SEGMENT_COLOR;
for (const detailType of VisualInfo.DetailTypes) {
const visual: VisualInfo = {
tag: VisualInfo.tagFor(segid, detailType),
segmentId: segid,
segmentName: name,
detailType: detailType,
detail: -1, // to be set at the end
color: color,
visible: false,
data: undefined,
};
visuals[visual.tag] = visual;
}
}
this.visuals = visuals;
this.updateVisualInfoDetails();
}
private updateVisualInfoDetails() {
let highDetail: number | undefined;
let lowDetail: number | undefined;
switch (this.params.view.name) {
case 'off':
lowDetail = undefined;
highDetail = undefined;
break;
case 'select':
lowDetail = this.params.view.params.baseDetail;
highDetail = this.params.view.params.focusDetail;
break;
case 'all':
lowDetail = this.params.view.params.detail;
highDetail = undefined;
break;
}
for (const tag in this.visuals) {
const visual = this.visuals[tag];
const preferredDetail = (visual.detailType === 'high') ? highDetail : lowDetail;
if (preferredDetail !== undefined) {
visual.detail = this.metadata!.getSufficientMeshDetail(visual.segmentId, preferredDetail);
}
}
}
private async enableVisuals(highDetailSegment?: number) {
for (const tag in this.visuals) {
const visual = this.visuals[tag];
const requiredDetailType = visual.segmentId === highDetailSegment ? 'high' : 'low';
if (visual.detailType === requiredDetailType) {
visual.data = await this.getMeshData(visual);
visual.visible = true;
} else {
visual.visible = false;
}
}
}
private async disableVisuals() {
for (const tag in this.visuals) {
const visual = this.visuals[tag];
visual.visible = false;
}
}
/** Fetch data in current `visual.detail`, or return already fetched data (if available in the correct detail). */
private async getMeshData(visual: VisualInfo): Promise<MeshlistData> {
if (visual.data && visual.data.detail === visual.detail) {
// Do not recreate
return visual.data;
}
// TODO cache
const url = this.getMeshUrl(visual.segmentId, visual.detail);
const urlAsset = Asset.getUrlAsset(this.plugin.managers.asset, url);
const asset = await this.plugin.runTask(this.plugin.managers.asset.resolve(urlAsset, 'binary'));
const parsed = await this.plugin.runTask(CIF.parseBinary(asset.data));
if (parsed.isError) {
throw new Error(`Failed parsing CIF file from ${url}`);
}
const meshlistData = await MeshlistData.fromCIF(parsed.result, visual.segmentId, visual.segmentName, visual.detail);
meshlistData.ownerId = this.id;
// const bbox = MeshlistData.bbox(meshlistData);
// const bboxVolume = bbox ? MS.Box3D.volume(bbox) : 0.0;
// console.log(`BBox ${visual.segmentId}: ${Math.round(bboxVolume! / 1e6)} M`, bbox); // DEBUG
return meshlistData;
}
private async guessBackgroundSegments() {
const bboxes: { [segid: number]: Box3D } = {};
for (const tag in this.visuals) {
const visual = this.visuals[tag];
if (visual.detailType === 'low' && visual.data) {
const bbox = MeshlistData.bbox(visual.data);
if (bbox) {
bboxes[visual.segmentId] = bbox;
}
}
}
const totalBbox = MeshlistData.combineBBoxes(Object.values(bboxes));
const totalVolume = totalBbox ? Box3D.volume(totalBbox) : 0.0;
// console.log(`BBox total: ${Math.round(totalVolume! / 1e6)} M`, totalBbox); // DEBUG
const isBgSegment: { [segid: number]: boolean } = {};
for (const segid in bboxes) {
const bbox = bboxes[segid];
const bboxVolume = Box3D.volume(bbox);
isBgSegment[segid] = (bboxVolume > totalVolume * BACKGROUND_SEGMENT_VOLUME_THRESHOLD);
// console.log(`BBox ${segid}: ${Math.round(bboxVolume! / 1e6)} M, ${bboxVolume / totalVolume}`, bbox); // DEBUG
}
this.backgroundSegments = isBgSegment;
}
getDescription() {
return Params.ViewTypeChoice.prettyName(this.params.view.name);
}
}
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
import { PluginStateObject } from '../../../mol-plugin-state/objects';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Choice } from '../../volumes-and-segmentations/helpers';
export const DEFAULT_MESH_SERVER = 'http://localhost:9000/v2';
export class MeshServerInfo extends PluginStateObject.Create<MeshServerInfo.Data>({ name: 'Volume Server', typeClass: 'Object' }) { }
export namespace MeshServerInfo {
export const MeshSourceChoice = new Choice({ empiar: 'EMPIAR', emdb: 'EMDB' }, 'empiar');
export type MeshSource = Choice.Values<typeof MeshSourceChoice>;
export const Params = {
serverUrl: PD.Text(DEFAULT_MESH_SERVER),
source: MeshSourceChoice.PDSelect(),
entryId: PD.Text(''),
};
export type Data = PD.Values<typeof Params>;
}

View File

@@ -0,0 +1,214 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
import { PluginStateObject } from '../../../mol-plugin-state/objects';
import { PluginContext } from '../../../mol-plugin/context';
import { ShapeRepresentation } from '../../../mol-repr/shape/representation';
import { StateAction, StateTransformer } from '../../../mol-state';
import { Task } from '../../../mol-task';
import { shallowEqualObjects } from '../../../mol-util';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { BACKGROUND_OPACITY, FOREROUND_OPACITY, MeshlistData, VolsegTransform } from '../mesh-extension';
import { MeshStreaming, NO_SEGMENT } from './behavior';
import { MeshServerInfo } from './server-info';
// // // // // // // // // // // // // // // // // // // // // // // //
export const MeshServerTransformer = VolsegTransform({
name: 'mesh-server-info',
from: PluginStateObject.Root,
to: MeshServerInfo,
params: MeshServerInfo.Params,
})({
apply({ a, params }, plugin: PluginContext) { // `a` is the parent node, `params` are 2nd argument to To.apply()
params.serverUrl = params.serverUrl.replace(/\/*$/, ''); // trim trailing slash
const description: string = params.entryId;
return new MeshServerInfo({ ...params }, { label: 'Mesh Server', description: description });
}
});
// // // // // // // // // // // // // // // // // // // // // // // //
export const MeshStreamingTransformer = VolsegTransform({
name: 'mesh-streaming-from-server-info',
display: { name: 'Mesh Streaming' },
from: MeshServerInfo,
to: MeshStreaming,
params: a => MeshStreaming.Params.create(a!.data),
})({
canAutoUpdate() { return true; },
apply({ a, params }, plugin: PluginContext) {
return Task.create('Mesh Streaming', async ctx => {
const behavior = new MeshStreaming.Behavior(plugin, a.data, params);
await behavior.update(params);
return new MeshStreaming(behavior, { label: 'Mesh Streaming', description: behavior.getDescription() });
});
},
update({ a, b, oldParams, newParams }) {
return Task.create('Update Mesh Streaming', async ctx => {
if (a.data.source !== b.data.parentData.source || a.data.entryId !== b.data.parentData.entryId) {
return StateTransformer.UpdateResult.Recreate;
}
b.data.parentData = a.data;
await b.data.update(newParams);
b.description = b.data.getDescription();
return StateTransformer.UpdateResult.Updated;
});
}
});
// // // // // // // // // // // // // // // // // // // // // // // //
interface MeshVisualGroupData {
opacity: number,
}
// export type MeshVisualGroupTransformer = typeof MeshVisualGroupTransformer;
export const MeshVisualGroupTransformer = VolsegTransform({
name: 'mesh-visual-group-from-streaming',
display: { name: 'Mesh Visuals for a Segment' },
from: MeshStreaming,
to: PluginStateObject.Group,
params: {
/** Shown on the node in GUI */
label: PD.Text('', { isHidden: true }),
/** Shown on the node in GUI (gray letters) */
description: PD.Text(''),
segmentId: PD.Numeric(NO_SEGMENT, {}, { isHidden: true }),
opacity: PD.Numeric(-1, { min: 0, max: 1, step: 0.01 }),
}
})({
apply({ a, params }, plugin) {
trySetAutoOpacity(params, a);
return new PluginStateObject.Group({ opacity: params.opacity }, params);
},
update({ a, b, oldParams, newParams }, plugin) {
if (shallowEqualObjects(oldParams, newParams)) {
return StateTransformer.UpdateResult.Unchanged;
}
newParams.label ||= oldParams.label; // Protect against resetting params to invalid defaults
if (newParams.segmentId === NO_SEGMENT) newParams.segmentId = oldParams.segmentId; // Protect against resetting params to invalid defaults
trySetAutoOpacity(newParams, a);
b.label = newParams.label;
b.description = newParams.description;
(b.data as MeshVisualGroupData).opacity = newParams.opacity;
return StateTransformer.UpdateResult.Updated;
},
canAutoUpdate({ oldParams, newParams }, plugin) {
return newParams.description === oldParams.description;
},
});
function trySetAutoOpacity(params: StateTransformer.Params<typeof MeshVisualGroupTransformer>, parent: MeshStreaming) {
if (params.opacity === -1) {
const isBgSegment = parent.data.backgroundSegments[params.segmentId];
if (isBgSegment !== undefined) {
params.opacity = isBgSegment ? BACKGROUND_OPACITY : FOREROUND_OPACITY;
}
}
}
// // // // // // // // // // // // // // // // // // // // // // // //
export const MeshVisualTransformer = VolsegTransform({
name: 'mesh-visual-from-streaming',
display: { name: 'Mesh Visual from Streaming' },
from: MeshStreaming,
to: PluginStateObject.Shape.Representation3D,
params: {
/** Must be set to PluginStateObject reference to self */
ref: PD.Text('', { isHidden: true, isEssential: true }), // QUESTION what is isEssential
/** Identification of the mesh visual, e.g. 'low-2' */
tag: PD.Text('', { isHidden: true, isEssential: true }),
/** Opacity of the visual (not to be set directly, but controlled by the opacity of the parent Group, and by VisualInfo.visible) */
opacity: PD.Numeric(-1, { min: 0, max: 1, step: 0.01 }, { isHidden: true }),
}
})({
apply({ a, params, spine }, plugin: PluginContext) {
return Task.create('Mesh Visual', async ctx => {
const visualInfo: MeshStreaming.VisualInfo = a.data.visuals![params.tag];
if (!visualInfo) throw new Error(`VisualInfo with tag '${params.tag}' is missing.`);
const groupData = spine.getAncestorOfType(PluginStateObject.Group)?.data as MeshVisualGroupData | undefined;
params.opacity = visualInfo.visible ? (groupData?.opacity ?? FOREROUND_OPACITY) : 0.0;
const props = PD.getDefaultValues(Mesh.Params);
props.flatShaded = true; // `flatShaded: true` is to see the real mesh vertices and triangles (default: false)
props.alpha = params.opacity;
const repr = ShapeRepresentation((ctx, meshlist: MeshlistData) => MeshlistData.getShape(meshlist, visualInfo.color), Mesh.Utils);
await repr.createOrUpdate(props, visualInfo.data ?? MeshlistData.empty()).runInContext(ctx);
return new PluginStateObject.Shape.Representation3D({ repr, sourceData: visualInfo.data }, { label: 'Mesh Visual', description: params.tag });
});
},
update({ a, b, oldParams, newParams, spine }, plugin: PluginContext) {
return Task.create('Update Mesh Visual', async ctx => {
newParams.ref ||= oldParams.ref; // Protect against resetting params to invalid defaults
newParams.tag ||= oldParams.tag; // Protect against resetting params to invalid defaults
const visualInfo: MeshStreaming.VisualInfo = a.data.visuals![newParams.tag];
if (!visualInfo) throw new Error(`VisualInfo with tag '${newParams.tag}' is missing.`);
const oldData = b.data.sourceData as MeshlistData | undefined;
if (visualInfo.data?.detail !== oldData?.detail) {
return StateTransformer.UpdateResult.Recreate;
}
const groupData = spine.getAncestorOfType(PluginStateObject.Group)?.data as MeshVisualGroupData | undefined;
const newOpacity = visualInfo.visible ? (groupData?.opacity ?? FOREROUND_OPACITY) : 0.0; // do not store to newParams directly, because oldParams and newParams might point to the same object!
if (newOpacity !== oldParams.opacity) {
newParams.opacity = newOpacity;
await b.data.repr.createOrUpdate({ alpha: newParams.opacity }).runInContext(ctx);
return StateTransformer.UpdateResult.Updated;
} else {
return StateTransformer.UpdateResult.Unchanged;
}
});
},
canAutoUpdate(params, globalCtx) {
return true;
},
dispose({ b, params }, plugin) {
b?.data.repr.destroy(); // QUESTION is this correct?
},
});
// // // // // // // // // // // // // // // // // // // // // // // //
export const InitMeshStreaming = StateAction.build({
display: { name: 'Mesh Streaming' },
from: PluginStateObject.Root,
params: MeshServerInfo.Params,
isApplicable: (a, _, plugin: PluginContext) => true
})(function (p, plugin: PluginContext) {
return Task.create('Mesh Streaming', async ctx => {
const { params } = p;
// p.ref
const serverNode = await plugin.build().to(p.ref).apply(MeshServerTransformer, params).commit();
// const serverNode = await plugin.build().toRoot().apply(MeshServerTransformer, params).commit();
const streamingNode = await plugin.build().to(serverNode).apply(MeshStreamingTransformer, {}).commit();
const visuals = streamingNode.data?.visuals ?? {};
const bgSegments = streamingNode.data?.backgroundSegments ?? {};
const segmentGroups: { [segid: number]: string } = {};
for (const tag in visuals) {
const segid = visuals[tag].segmentId;
if (!segmentGroups[segid]) {
let description = visuals[tag].segmentName;
if (bgSegments[segid]) description += ' (background)';
const group = await plugin.build().to(streamingNode).apply(MeshVisualGroupTransformer, { label: `Segment ${segid}`, description: description, segmentId: segid }, { state: { isCollapsed: true } }).commit();
segmentGroups[segid] = group.ref;
}
}
const visualsUpdate = plugin.build();
for (const tag in visuals) {
const ref = `${streamingNode.ref}-${tag}`;
const segid = visuals[tag].segmentId;
visualsUpdate.to(segmentGroups[segid]).apply(MeshVisualTransformer, { ref: ref, tag: tag }, { ref: ref }); // ref - hack to allow the node make itself invisible
}
await plugin.state.data.updateTree(visualsUpdate).runInContext(ctx); // QUESTION what is really the difference between this and `visualsUpdate.commit()`?
});
});
// TODO make available in GUI, in left panel or in right panel like Volume Streaming in src/mol-plugin-ui/structure/volume.tsx?

View File

@@ -0,0 +1,340 @@
/**
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Adam Midlik <midlik@gmail.com>
*/
/** Helper functions for manipulation with mesh data. */
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
import { CIF, CifFile } from '../../mol-io/reader/cif';
import { Box3D } from '../../mol-math/geometry';
import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
import { volumeFromDensityServerData } from '../../mol-model-formats/volume/density-server';
import { Grid } from '../../mol-model/volume';
import { ColorNames } from '../../mol-util/color/names';
import { TypedArray } from '../../mol-util/type-helpers';
import { CIF_schema_mesh } from './mesh-cif-schema';
type MeshModificationParams = {
scale?: [number, number, number],
shift?: [number, number, number],
matrix?: Mat4,
group?: number,
invertSides?: boolean
};
/** Modify mesh in-place */
export function modify(m: Mesh, params: MeshModificationParams) {
if (params.scale !== undefined) {
const [qx, qy, qz] = params.scale;
const vertices = m.vertexBuffer.ref.value;
for (let i = 0; i < vertices.length; i += 3) {
vertices[i] *= qx;
vertices[i + 1] *= qy;
vertices[i + 2] *= qz;
}
}
if (params.shift !== undefined) {
const [dx, dy, dz] = params.shift;
const vertices = m.vertexBuffer.ref.value;
for (let i = 0; i < vertices.length; i += 3) {
vertices[i] += dx;
vertices[i + 1] += dy;
vertices[i + 2] += dz;
}
}
if (params.matrix !== undefined) {
const r = m.vertexBuffer.ref.value;
const matrix = params.matrix;
const size = 3 * m.vertexCount;
for (let i = 0; i < size; i += 3) {
Vec3.transformMat4Offset(r, r, matrix, i, i, 0);
}
}
if (params.group !== undefined) {
const groups = m.groupBuffer.ref.value;
for (let i = 0; i < groups.length; i++) {
groups[i] = params.group;
}
}
if (params.invertSides) {
const indices = m.indexBuffer.ref.value;
let tmp;
for (let i = 0; i < indices.length; i += 3) {
tmp = indices[i];
indices[i] = indices[i + 1];
indices[i + 1] = tmp;
}
const normals = m.normalBuffer.ref.value;
for (let i = 0; i < normals.length; i++) {
normals[i] *= -1;
}
}
}
/** Create a copy a mesh, possibly modified */
export function copy(m: Mesh, modification?: MeshModificationParams): Mesh {
const nVertices = m.vertexCount;
const nTriangles = m.triangleCount;
const vertices = new Float32Array(m.vertexBuffer.ref.value);
const indices = new Uint32Array(m.indexBuffer.ref.value);
const normals = new Float32Array(m.normalBuffer.ref.value);
const groups = new Float32Array(m.groupBuffer.ref.value);
const result = Mesh.create(vertices, indices, normals, groups, nVertices, nTriangles);
if (modification) {
modify(result, modification);
}
return result;
}
/** Join more meshes into one */
export function concat(...meshes: Mesh[]): Mesh {
const nVertices = sum(meshes.map(m => m.vertexCount));
const nTriangles = sum(meshes.map(m => m.triangleCount));
const vertices = concatArrays(Float32Array, meshes.map(m => m.vertexBuffer.ref.value));
const normals = concatArrays(Float32Array, meshes.map(m => m.normalBuffer.ref.value));
const groups = concatArrays(Float32Array, meshes.map(m => m.groupBuffer.ref.value));
const newIndices = [];
let offset = 0;
for (const m of meshes) {
newIndices.push(m.indexBuffer.ref.value.map(i => i + offset));
offset += m.vertexCount;
}
const indices = concatArrays(Uint32Array, newIndices);
return Mesh.create(vertices, indices, normals, groups, nVertices, nTriangles);
}
/** Return Mesh from CIF data and mesh IDs (group IDs).
* Assume the CIF contains coords in grid space,
* transform the output mesh to `space` */
export async function meshFromCif(data: CifFile, invertSides: boolean | undefined = undefined, outSpace: 'grid' | 'fractional' | 'cartesian' = 'cartesian'): Promise<{ mesh: Mesh, meshIds: number[] }> {
const volumeInfoBlock = data.blocks.find(b => b.header === 'VOLUME_INFO');
const meshesBlock = data.blocks.find(b => b.header === 'MESHES');
if (!volumeInfoBlock || !meshesBlock) throw new Error('Missing VOLUME_INFO or MESHES block in mesh CIF file');
const volumeInfoCif = CIF.schema.densityServer(volumeInfoBlock);
const meshCif = CIF_schema_mesh(meshesBlock);
const nVertices = meshCif.mesh_vertex._rowCount;
const nTriangles = Math.floor(meshCif.mesh_triangle._rowCount / 3);
const mesh_id = meshCif.mesh.id.toArray();
const vertex_meshId = meshCif.mesh_vertex.mesh_id.toArray();
const x = meshCif.mesh_vertex.x.toArray();
const y = meshCif.mesh_vertex.y.toArray();
const z = meshCif.mesh_vertex.z.toArray();
const triangle_meshId = meshCif.mesh_triangle.mesh_id.toArray();
const triangle_vertexId = meshCif.mesh_triangle.vertex_id.toArray();
// Shift indices from within-mesh indices to overall indices
const indices = new Uint32Array(3 * nTriangles);
const offsets = offsetMap(vertex_meshId);
for (let i = 0; i < 3 * nTriangles; i++) {
const offset = offsets.get(triangle_meshId[i])!;
indices[i] = offset + triangle_vertexId[i];
}
const vertices = flattenCoords(x, y, z);
const normals = new Float32Array(3 * nVertices);
const groups = new Float32Array(vertex_meshId);
const mesh = Mesh.create(vertices, indices, normals, groups, nVertices, nTriangles);
invertSides ??= isInverted(mesh);
if (invertSides) {
modify(mesh, { invertSides: true }); // Vertex orientation convention is opposite in Volseg API and in MolStar
}
if (outSpace === 'cartesian') {
const volume = await volumeFromDensityServerData(volumeInfoCif).run();
const gridToCartesian = Grid.getGridToCartesianTransform(volume.grid);
modify(mesh, { matrix: gridToCartesian });
} else if (outSpace === 'fractional') {
const gridSize = volumeInfoCif.volume_data_3d_info.sample_count.value(0);
const originFract = volumeInfoCif.volume_data_3d_info.origin.value(0);
const dimensionFract = volumeInfoCif.volume_data_3d_info.dimensions.value(0);
if (dimensionFract[0] !== 1 || dimensionFract[1] !== 1 || dimensionFract[2] !== 1) throw new Error(`Asserted the fractional dimensions are [1,1,1], but are actually [${dimensionFract}]`);
const scale: [number, number, number] = [1 / gridSize[0], 1 / gridSize[1], 1 / gridSize[2]];
modify(mesh, { scale: scale, shift: Array.from(originFract) as any });
}
Mesh.computeNormals(mesh); // normals only necessary if flatShaded==false
// const boxMesh = makeMeshFromBox([[0,0,0], [1,1,1]], 1);
// const gridSize = volumeInfoCif.volume_data_3d_info.sample_count.value(0); const boxMesh = makeMeshFromBox([[0,0,0], Array.from(gridSize)] as any, 1);
// const cellSize = volumeInfoCif.volume_data_3d_info.spacegroup_cell_size.value(0); const boxMesh = makeMeshFromBox([[0, 0, 0], Array.from(cellSize)] as any, 1);
// mesh = concat(mesh, boxMesh); // debug
return { mesh: mesh, meshIds: Array.from(mesh_id) };
}
function isInverted(mesh: Mesh): boolean {
const vertices = mesh.vertexBuffer.ref.value;
const indices = mesh.indexBuffer.ref.value;
const center = meshCenter(mesh);
const center3 = Vec3.create(3 * center[0], 3 * center[1], 3 * center[2]);
let dirMetric = 0.0;
const [a, b, c, u, v, normal, radius] = [Vec3(), Vec3(), Vec3(), Vec3(), Vec3(), Vec3(), Vec3()];
for (let i = 0; i < indices.length; i += 3) {
Vec3.fromArray(a, vertices, 3 * indices[i]);
Vec3.fromArray(b, vertices, 3 * indices[i + 1]);
Vec3.fromArray(c, vertices, 3 * indices[i + 2]);
Vec3.sub(u, b, a);
Vec3.sub(v, c, b);
Vec3.cross(normal, u, v); // direction of the surface
Vec3.add(radius, a, b);
Vec3.add(radius, radius, c);
Vec3.sub(radius, radius, center3); // direction center -> this triangle
dirMetric += Vec3.dot(radius, normal);
}
return dirMetric < 0;
}
function meshCenter(mesh: Mesh) {
const vertices = mesh.vertexBuffer.ref.value;
const n = vertices.length;
let x = 0.0;
let y = 0.0;
let z = 0.0;
for (let i = 0; i < vertices.length; i += 3) {
x += vertices[i];
y += vertices[i + 1];
z += vertices[i + 2];
}
return Vec3.create(x / n, y / n, z / n);
}
function flattenCoords(x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number>): Float32Array {
const n = x.length;
const out = new Float32Array(3 * n);
for (let i = 0; i < n; i++) {
out[3 * i] = x[i];
out[3 * i + 1] = y[i];
out[3 * i + 2] = z[i];
}
return out;
}
/** Get mapping of unique values to the position of their first occurrence */
function offsetMap(values: ArrayLike<number>) {
const result = new Map<number, number>();
for (let i = 0; i < values.length; i++) {
if (!result.has(values[i])) {
result.set(values[i], i);
}
}
return result;
}
/** Return bounding box */
export function bbox(mesh: Mesh): Box3D | null { // Is there no function for this?
const nVertices = mesh.vertexCount;
const coords = mesh.vertexBuffer.ref.value;
if (nVertices === 0) {
return null;
}
let minX = coords[0], minY = coords[1], minZ = coords[2];
let maxX = minX, maxY = minY, maxZ = minZ;
for (let i = 0; i < 3 * nVertices; i += 3) {
const x = coords[i], y = coords[i + 1], z = coords[i + 2];
if (x < minX) minX = x;
if (y < minY) minY = y;
if (z < minZ) minZ = z;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
if (z > maxZ) maxZ = z;
}
return Box3D.create(Vec3.create(minX, minY, minZ), Vec3.create(maxX, maxY, maxZ));
}
/** Example mesh - 1 triangle */
export function fakeFakeMesh1(): Mesh {
const nVertices = 3;
const nTriangles = 1;
const vertices = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]);
const indices = new Uint32Array([0, 1, 2]);
const normals = new Float32Array([0, 0, 1]);
const groups = new Float32Array([0]);
return Mesh.create(vertices, indices, normals, groups, nVertices, nTriangles);
}
/** Example mesh - irregular tetrahedron */
export function fakeMesh4(): Mesh {
const nVertices = 4;
const nTriangles = 4;
const vertices = new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]);
const indices = new Uint32Array([0, 2, 1, 0, 1, 3, 1, 2, 3, 2, 0, 3]);
const normals = new Float32Array([-1, -1, -1, 1, 0, 0, 0, 1, 0, 0, 0, 1]);
const groups = new Float32Array([0, 1, 2, 3]);
return Mesh.create(vertices, indices, normals, groups, nVertices, nTriangles);
}
/** Return a box-shaped mesh */
export function meshFromBox(box: [[number, number, number], [number, number, number]], group: number = 0) {
const [[x0, y0, z0], [x1, y1, z1]] = box;
const vertices = new Float32Array([
x0, y0, z0,
x1, y0, z0,
x0, y1, z0,
x1, y1, z0,
x0, y0, z1,
x1, y0, z1,
x0, y1, z1,
x1, y1, z1,
]);
const indices = new Uint32Array([
2, 1, 0, 1, 2, 3,
1, 4, 0, 4, 1, 5,
3, 5, 1, 5, 3, 7,
2, 7, 3, 7, 2, 6,
0, 6, 2, 6, 0, 4,
4, 7, 6, 7, 4, 5,
]);
const groups = new Float32Array([group, group, group, group, group, group, group, group]);
const normals = new Float32Array(8);
const mesh = Mesh.create(vertices, indices, normals, groups, 8, 12);
Mesh.computeNormals(mesh); // normals only necessary if flatShaded==false
return mesh;
}
function sum(array: number[]): number {
return array.reduce((a, b) => a + b, 0);
}
function concatArrays<T extends TypedArray>(t: new (len: number) => T, arrays: T[]): T {
const totalLength = arrays.map(a => a.length).reduce((a, b) => a + b, 0);
const result: T = new t(totalLength);
let offset = 0;
for (const array of arrays) {
result.set(array, offset);
offset += array.length;
}
return result;
}
/** Generate random colors (in a cycle) */
export const ColorGenerator = function* () {
const colors = shuffleArray(Object.values(ColorNames));
let i = 0;
while (true) {
yield colors[i];
i++;
if (i >= colors.length) i = 0;
}
}();
function shuffleArray<T>(array: T[]): T[] {
// Stealed from https://www.w3docs.com/snippets/javascript/how-to-randomize-shuffle-a-javascript-array.html
let curId = array.length;
// There remain elements to shuffle
while (0 !== curId) {
// Pick a remaining element
const randId = Math.floor(Math.random() * curId);
curId -= 1;
// Swap it with the current element.
const tmp = array[curId];
array[curId] = array[randId];
array[randId] = tmp;
}
return array;
}

View File

@@ -0,0 +1,212 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { PluginBehavior } from '../../../mol-plugin/behavior/behavior';
import { Loci } from '../../../mol-model/loci';
import { DefaultQueryRuntimeTable } from '../../../mol-script/runtime/query/compiler';
import { PLDDTConfidenceColorThemeProvider } from './color/plddt';
import { QualityAssessment, QualityAssessmentProvider } from './prop';
import { StructureSelectionCategory, StructureSelectionQuery } from '../../../mol-plugin-state/helpers/structure-selection-query';
import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
import { OrderedSet } from '../../../mol-data/int';
import { cantorPairing } from '../../../mol-data/util';
import { QmeanScoreColorThemeProvider } from './color/qmean';
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../../mol-plugin-state/builder/structure/representation-preset';
import { StateObjectRef } from '../../../mol-state';
export const MAQualityAssessment = PluginBehavior.create<{ autoAttach: boolean, showTooltip: boolean }>({
name: 'ma-quality-assessment-prop',
category: 'custom-props',
display: {
name: 'Quality Assessment',
description: 'Data included in Model Archive files.'
},
ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
private provider = QualityAssessmentProvider;
private labelProvider = {
label: (loci: Loci): string | undefined => {
if (!this.params.showTooltip) return;
return [
plddtLabel(loci),
qmeanLabel(loci),
].filter(l => !!l).join('</br>');
}
};
register(): void {
DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
this.ctx.customModelProperties.register(this.provider, this.params.autoAttach);
this.ctx.managers.lociLabels.addProvider(this.labelProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.add(PLDDTConfidenceColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.add(QmeanScoreColorThemeProvider);
this.ctx.query.structure.registry.add(confidentPLDDT);
this.ctx.builders.structure.representation.registerPreset(QualityAssessmentPLDDTPreset);
this.ctx.builders.structure.representation.registerPreset(QualityAssessmentQmeanPreset);
}
update(p: { autoAttach: boolean, showTooltip: boolean }) {
const updated = this.params.autoAttach !== p.autoAttach;
this.params.autoAttach = p.autoAttach;
this.params.showTooltip = p.showTooltip;
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
return updated;
}
unregister() {
DefaultQueryRuntimeTable.removeCustomProp(this.provider.descriptor);
this.ctx.customStructureProperties.unregister(this.provider.descriptor.name);
this.ctx.managers.lociLabels.removeProvider(this.labelProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(PLDDTConfidenceColorThemeProvider);
this.ctx.representation.structure.themes.colorThemeRegistry.remove(QmeanScoreColorThemeProvider);
this.ctx.query.structure.registry.remove(confidentPLDDT);
this.ctx.builders.structure.representation.unregisterPreset(QualityAssessmentPLDDTPreset);
this.ctx.builders.structure.representation.unregisterPreset(QualityAssessmentQmeanPreset);
}
},
params: () => ({
autoAttach: PD.Boolean(false),
showTooltip: PD.Boolean(true),
})
});
//
function plddtCategory(score: number) {
if (score > 50 && score <= 70) return 'Low';
if (score > 70 && score <= 90) return 'Confident';
if (score > 90) return 'Very high';
return 'Very low';
}
function plddtLabel(loci: Loci): string | undefined {
return metricLabel(loci, 'pLDDT', (scoreAvg: number, countInfo: string) => `pLDDT Score ${countInfo}: ${scoreAvg.toFixed(2)} <small>(${plddtCategory(scoreAvg)})</small>`);
}
function qmeanLabel(loci: Loci): string | undefined {
return metricLabel(loci, 'qmean', (scoreAvg: number, countInfo: string) => `QMEAN Score ${countInfo}: ${scoreAvg.toFixed(2)}`);
}
function metricLabel(loci: Loci, name: 'qmean' | 'pLDDT', label: (scoreAvg: number, countInfo: string) => string): string | undefined {
if (loci.kind === 'element-loci') {
if (loci.elements.length === 0) return;
const seen = new Set<number>();
const scoreSeen = new Set<number>();
let scoreSum = 0;
for (const { indices, unit } of loci.elements) {
const metric = QualityAssessmentProvider.get(unit.model).value?.[name];
if (!metric) continue;
const residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index;
const { elements } = unit;
OrderedSet.forEach(indices, idx => {
const eI = elements[idx];
const rI = residueIndex[eI];
const residueKey = cantorPairing(rI, unit.id);
if (!seen.has(residueKey)) {
const score = metric.get(residueIndex[eI]) ?? -1;
if (score !== -1) {
scoreSum += score;
scoreSeen.add(residueKey);
}
seen.add(residueKey);
}
});
}
if (seen.size === 0) return;
const summary: string[] = [];
if (scoreSeen.size) {
const countInfo = `<small>(${scoreSeen.size} ${scoreSeen.size > 1 ? 'Residues avg.' : 'Residue'})</small>`;
const scoreAvg = scoreSum / scoreSeen.size;
summary.push(label(scoreAvg, countInfo));
}
if (summary.length) {
return summary.join('</br>');
}
}
}
//
const confidentPLDDT = StructureSelectionQuery('Confident pLDDT (> 70)', MS.struct.modifier.union([
MS.struct.modifier.wholeResidues([
MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
'residue-test': MS.core.rel.gr([QualityAssessment.symbols.pLDDT.symbol(), 70]),
})
])
])
]), {
description: 'Select residues with a pLDDT > 70 (confident).',
category: StructureSelectionCategory.Validation,
ensureCustomProperties: async (ctx, structure) => {
for (const m of structure.models) {
await QualityAssessmentProvider.attach(ctx, m, void 0, true);
}
}
});
//
export const QualityAssessmentPLDDTPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-ma-quality-assessment-plddt',
display: {
name: 'Quality Assessment (pLDDT)', group: 'Annotation',
description: 'Color structure based on pLDDT Confidence.'
},
isApplicable(a) {
return !!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'));
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
const colorTheme = PLDDTConfidenceColorThemeProvider.name as any;
return await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
}
});
export const QualityAssessmentQmeanPreset = StructureRepresentationPresetProvider({
id: 'preset-structure-representation-ma-quality-assessment-qmean',
display: {
name: 'Quality Assessment (QMEAN)', group: 'Annotation',
description: 'Color structure based on QMEAN Score.'
},
isApplicable(a) {
return !!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'));
},
params: () => StructureRepresentationPresetProvider.CommonParams,
async apply(ref, params, plugin) {
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
const structure = structureCell?.obj?.data;
if (!structureCell || !structure) return {};
const colorTheme = QmeanScoreColorThemeProvider.name as any;
return await PresetStructureRepresentations.auto.apply(ref, { ...params, theme: { globalName: colorTheme, focus: { name: colorTheme } } }, plugin);
}
});

View File

@@ -0,0 +1,106 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Mandar Deshpande <mandar@ebi.ac.uk>
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { QualityAssessment, QualityAssessmentProvider } from '../prop';
import { Location } from '../../../../mol-model/location';
import { Bond, StructureElement, Unit } from '../../../../mol-model/structure';
import { ColorTheme, LocationColor } from '../../../../mol-theme/color';
import { ThemeDataContext } from '../../../../mol-theme/theme';
import { Color } from '../../../../mol-util/color';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { CustomProperty } from '../../../../mol-model-props/common/custom-property';
import { TableLegend } from '../../../../mol-util/legend';
const DefaultColor = Color(0xaaaaaa);
const ConfidenceColors = {
'No Score': DefaultColor,
'Very Low': Color(0xff7d45),
'Low': Color(0xffdb13),
'Confident': Color(0x65cbf3),
'Very High': Color(0x0053d6)
};
const ConfidenceColorLegend = TableLegend(Object.entries(ConfidenceColors));
export function getPLDDTConfidenceColorThemeParams(ctx: ThemeDataContext) {
return {};
}
export type PLDDTConfidenceColorThemeParams = ReturnType<typeof getPLDDTConfidenceColorThemeParams>
export function PLDDTConfidenceColorTheme(ctx: ThemeDataContext, props: PD.Values<PLDDTConfidenceColorThemeParams>): ColorTheme<PLDDTConfidenceColorThemeParams> {
let color: LocationColor = () => DefaultColor;
if (ctx.structure) {
const l = StructureElement.Location.create(ctx.structure.root);
const getColor = (location: StructureElement.Location): Color => {
const { unit, element } = location;
if (!Unit.isAtomic(unit)) return DefaultColor;
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
const score = qualityAssessment?.pLDDT?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
if (score < 0) {
return DefaultColor;
} else if (score <= 50) {
return Color(0xff7d45);
} else if (score <= 70) {
return Color(0xffdb13);
} else if (score <= 90) {
return Color(0x65cbf3);
} else {
return Color(0x0053d6);
}
};
color = (location: Location) => {
if (StructureElement.Location.is(location)) {
return getColor(location);
} else if (Bond.isLocation(location)) {
l.unit = location.aUnit;
l.element = location.aUnit.elements[location.aIndex];
return getColor(l);
}
return DefaultColor;
};
}
return {
factory: PLDDTConfidenceColorTheme,
granularity: 'group',
preferSmoothing: true,
color,
props,
description: 'Assigns residue colors according to the pLDDT Confidence score.',
legend: ConfidenceColorLegend
};
}
export const PLDDTConfidenceColorThemeProvider: ColorTheme.Provider<PLDDTConfidenceColorThemeParams, 'plddt-confidence'> = {
name: 'plddt-confidence',
label: 'pLDDT Confidence',
category: ColorTheme.Category.Validation,
factory: PLDDTConfidenceColorTheme,
getParams: getPLDDTConfidenceColorThemeParams,
defaultValues: PD.getDefaultValues(getPLDDTConfidenceColorThemeParams({})),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure?.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')),
ensureCustomProperties: {
attach: async (ctx: CustomProperty.Context, data: ThemeDataContext) => {
if (data.structure) {
for (const m of data.structure.models) {
await QualityAssessmentProvider.attach(ctx, m, void 0, true);
}
}
},
detach: async (data: ThemeDataContext) => {
if (data.structure) {
for (const m of data.structure.models) {
QualityAssessmentProvider.ref(m, false);
}
}
}
}
};

View File

@@ -0,0 +1,95 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { QualityAssessment, QualityAssessmentProvider } from '../prop';
import { Location } from '../../../../mol-model/location';
import { Bond, StructureElement, Unit } from '../../../../mol-model/structure';
import { ColorTheme, LocationColor } from '../../../../mol-theme/color';
import { ThemeDataContext } from '../../../../mol-theme/theme';
import { Color, ColorScale } from '../../../../mol-util/color';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { CustomProperty } from '../../../../mol-model-props/common/custom-property';
const DefaultColor = Color(0xaaaaaa);
export function getQmeanScoreColorThemeParams(ctx: ThemeDataContext) {
return {};
}
export type QmeanScoreColorThemeParams = ReturnType<typeof getQmeanScoreColorThemeParams>
export function QmeanScoreColorTheme(ctx: ThemeDataContext, props: PD.Values<QmeanScoreColorThemeParams>): ColorTheme<QmeanScoreColorThemeParams> {
let color: LocationColor = () => DefaultColor;
const scale = ColorScale.create({
domain: [0, 1],
listOrName: [
[Color(0xFF5000), 0.5], [Color(0x025AFD), 1.0]
]
});
if (ctx.structure) {
const l = StructureElement.Location.create(ctx.structure.root);
const getColor = (location: StructureElement.Location): Color => {
const { unit, element } = location;
if (!Unit.isAtomic(unit)) return DefaultColor;
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
const score = qualityAssessment?.qmean?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
if (score < 0) {
return DefaultColor;
} else {
return scale.color(score);
}
};
color = (location: Location) => {
if (StructureElement.Location.is(location)) {
return getColor(location);
} else if (Bond.isLocation(location)) {
l.unit = location.aUnit;
l.element = location.aUnit.elements[location.aIndex];
return getColor(l);
}
return DefaultColor;
};
}
return {
factory: QmeanScoreColorTheme,
granularity: 'group',
preferSmoothing: true,
color,
props,
description: 'Assigns residue colors according to the QMEAN score.',
legend: scale.legend
};
}
export const QmeanScoreColorThemeProvider: ColorTheme.Provider<QmeanScoreColorThemeParams, 'qmean-score'> = {
name: 'qmean-score',
label: 'QMEAN Score',
category: ColorTheme.Category.Validation,
factory: QmeanScoreColorTheme,
getParams: getQmeanScoreColorThemeParams,
defaultValues: PD.getDefaultValues(getQmeanScoreColorThemeParams({})),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure?.models.some(m => QualityAssessment.isApplicable(m, 'qmean')),
ensureCustomProperties: {
attach: async (ctx: CustomProperty.Context, data: ThemeDataContext) => {
if (data.structure) {
for (const m of data.structure.models) {
await QualityAssessmentProvider.attach(ctx, m, void 0, true);
}
}
},
detach: async (data: ThemeDataContext) => {
if (data.structure) {
for (const m of data.structure.models) {
QualityAssessmentProvider.ref(m, false);
}
}
}
}
};

View File

@@ -0,0 +1,147 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Unit } from '../../../mol-model/structure';
import { CustomProperty } from '../../../mol-model-props/common/custom-property';
import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
import { Model, ResidueIndex } from '../../../mol-model/structure/model';
import { QuerySymbolRuntime } from '../../../mol-script/runtime/query/compiler';
import { CustomPropSymbol } from '../../../mol-script/language/symbol';
import { Type } from '../../../mol-script/language/type';
import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
import { AtomicIndex } from '../../../mol-model/structure/model/properties/atomic';
export { QualityAssessment };
interface QualityAssessment {
localMetrics: Map<string, Map<ResidueIndex, number>>
pLDDT?: Map<ResidueIndex, number>
qmean?: Map<ResidueIndex, number>
}
namespace QualityAssessment {
const Empty = {
value: {
localMetrics: new Map()
}
};
export function isApplicable(model?: Model, localMetricName?: 'pLDDT' | 'qmean'): boolean {
if (!model || !MmcifFormat.is(model.sourceData)) return false;
const { db } = model.sourceData.data;
const hasLocalMetric = (
db.ma_qa_metric.id.isDefined &&
db.ma_qa_metric_local.ordinal_id.isDefined
);
if (localMetricName && hasLocalMetric) {
for (let i = 0, il = db.ma_qa_metric._rowCount; i < il; i++) {
if (db.ma_qa_metric.mode.value(i) !== 'local') continue;
if (localMetricName === db.ma_qa_metric.name.value(i)) return true;
}
return false;
} else {
return hasLocalMetric;
}
}
export async function obtain(ctx: CustomProperty.Context, model: Model, props: QualityAssessmentProps): Promise<CustomProperty.Data<QualityAssessment>> {
if (!model || !MmcifFormat.is(model.sourceData)) return Empty;
const { ma_qa_metric, ma_qa_metric_local } = model.sourceData.data.db;
const { model_id, label_asym_id, label_seq_id, metric_id, metric_value } = ma_qa_metric_local;
const { index } = model.atomicHierarchy;
// for simplicity we assume names in ma_qa_metric for mode 'local' are unique
const localMetrics = new Map<string, Map<ResidueIndex, number>>();
const localNames = new Map<number, string>();
for (let i = 0, il = ma_qa_metric._rowCount; i < il; i++) {
if (ma_qa_metric.mode.value(i) !== 'local') continue;
const name = ma_qa_metric.name.value(i);
if (localMetrics.has(name)) {
console.warn(`local ma_qa_metric with name '${name}' already added`);
continue;
}
localMetrics.set(name, new Map());
localNames.set(ma_qa_metric.id.value(i), name);
}
const residueKey: AtomicIndex.ResidueLabelKey = {
label_entity_id: '',
label_asym_id: '',
label_seq_id: 0,
pdbx_PDB_ins_code: undefined,
};
for (let i = 0, il = ma_qa_metric_local._rowCount; i < il; i++) {
if (model_id.value(i) !== model.modelNum) continue;
const labelAsymId = label_asym_id.value(i);
const entityIndex = index.findEntity(labelAsymId);
residueKey.label_entity_id = model.entities.data.id.value(entityIndex);
residueKey.label_asym_id = labelAsymId;
residueKey.label_seq_id = label_seq_id.value(i);
const rI = index.findResidueLabel(residueKey);
if (rI >= 0) {
const name = localNames.get(metric_id.value(i))!;
localMetrics.get(name)!.set(rI, metric_value.value(i));
}
}
return {
value: {
localMetrics,
pLDDT: localMetrics.get('pLDDT'),
qmean: localMetrics.get('qmean'),
}
};
}
export const symbols = {
pLDDT: QuerySymbolRuntime.Dynamic(CustomPropSymbol('ma', 'quality-assessment.pLDDT', Type.Num),
ctx => {
const { unit, element } = ctx.element;
if (!Unit.isAtomic(unit)) return -1;
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
return qualityAssessment?.pLDDT?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
}
),
qmean: QuerySymbolRuntime.Dynamic(CustomPropSymbol('ma', 'quality-assessment.qmean', Type.Num),
ctx => {
const { unit, element } = ctx.element;
if (!Unit.isAtomic(unit)) return -1;
const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
return qualityAssessment?.qmean?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
}
),
};
}
export const QualityAssessmentParams = { };
export type QualityAssessmentParams = typeof QualityAssessmentParams
export type QualityAssessmentProps = PD.Values<QualityAssessmentParams>
export const QualityAssessmentProvider: CustomModelProperty.Provider<QualityAssessmentParams, QualityAssessment> = CustomModelProperty.createProvider({
label: 'QualityAssessment',
descriptor: CustomPropertyDescriptor({
name: 'ma_quality_assessment',
symbols: QualityAssessment.symbols
}),
type: 'static',
defaultParams: QualityAssessmentParams,
getParams: (data: Model) => QualityAssessmentParams,
isApplicable: (data: Model) => QualityAssessment.isApplicable(data),
obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<QualityAssessmentProps>) => {
const p = { ...PD.getDefaultValues(QualityAssessmentParams), ...props };
return await QualityAssessment.obtain(ctx, data, p);
}
});

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { utf8ByteCount, utf8Write } from '../../mol-io/common/utf8';
import { to_mmCIF, Unit } from '../../mol-model/structure';
import { PluginContext } from '../../mol-plugin/context';
import { Task } from '../../mol-task';
import { getFormattedTime } from '../../mol-util/date';
import { download } from '../../mol-util/download';
import { zip } from '../../mol-util/zip/zip';
export async function exportHierarchy(plugin: PluginContext, options?: { format?: 'cif' | 'bcif' }) {
try {
await plugin.runTask(_exportHierarchy(plugin, options), { useOverlay: true });
} catch (e) {
console.error(e);
plugin.log.error(`Model export failed. See console for details.`);
}
}
function _exportHierarchy(plugin: PluginContext, options?: { format?: 'cif' | 'bcif' }) {
return Task.create('Export', async ctx => {
await ctx.update({ message: 'Exporting...', isIndeterminate: true, canAbort: false });
const format = options?.format ?? 'cif';
const { structures } = plugin.managers.structure.hierarchy.current;
const files: [name: string, data: string | Uint8Array][] = [];
const entryMap = new Map<string, number>();
for (const _s of structures) {
const s = _s.transform?.cell.obj?.data ?? _s.cell.obj?.data;
if (!s) continue;
if (s.models.length > 1) {
plugin.log.warn(`[Export] Skipping ${_s.cell.obj?.label}: Multimodel exports not supported.`);
continue;
}
if (s.units.some(u => !Unit.isAtomic(u))) {
plugin.log.warn(`[Export] Skipping ${_s.cell.obj?.label}: Non-atomic model exports not supported.`);
continue;
}
const name = entryMap.has(s.model.entryId)
? `${s.model.entryId}_${entryMap.get(s.model.entryId)! + 1}.${format}`
: `${s.model.entryId}.${format}`;
entryMap.set(s.model.entryId, (entryMap.get(s.model.entryId) ?? 0) + 1);
await ctx.update({ message: `Exporting ${s.model.entryId}...`, isIndeterminate: true, canAbort: false });
if (s.elementCount > 100000) {
// Give UI chance to update, only needed for larger structures.
await new Promise(res => setTimeout(res, 50));
}
try {
files.push([name, to_mmCIF(s.model.entryId, s, format === 'bcif', { copyAllCategories: true })]);
} catch (e) {
if (format === 'cif' && s.elementCount > 2000000) {
plugin.log.warn(`[Export] The structure might be too big to be exported as Text CIF, consider using the BinaryCIF format instead.`);
}
throw e;
}
}
if (files.length === 1) {
download(new Blob([files[0][1]]), files[0][0]);
} else if (files.length > 1) {
const zipData: Record<string, Uint8Array> = {};
for (const [fn, data] of files) {
if (data instanceof Uint8Array) {
zipData[fn] = data;
} else {
const bytes = new Uint8Array(utf8ByteCount(data));
utf8Write(bytes, 0, data);
zipData[fn] = bytes;
}
}
await ctx.update({ message: `Compressing Data...`, isIndeterminate: true, canAbort: false });
const buffer = await zip(ctx, zipData);
download(new Blob([new Uint8Array(buffer, 0, buffer.byteLength)]), `structures_${getFormattedTime()}.zip`);
}
plugin.log.info(`[Export] Done.`);
});
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { PluginBehavior } from '../../mol-plugin/behavior/behavior';
import { ModelExportUI } from './ui';
export const ModelExport = PluginBehavior.create<{}>({
name: 'extension-model-export',
category: 'misc',
display: {
name: 'Model Export'
},
ctor: class extends PluginBehavior.Handler<{}> {
register(): void {
this.ctx.customStructureControls.set('model-export', ModelExportUI as any);
}
update() {
return false;
}
unregister() {
this.ctx.customStructureControls.delete('model-export');
}
},
params: () => ({})
});

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { useState } from 'react';
import { CollapsableControls, CollapsableState } from '../../mol-plugin-ui/base';
import { Button } from '../../mol-plugin-ui/controls/common';
import { GetAppSvg } from '../../mol-plugin-ui/controls/icons';
import { ParameterControls } from '../../mol-plugin-ui/controls/parameters';
import { useBehavior } from '../../mol-plugin-ui/hooks/use-behavior';
import { PluginContext } from '../../mol-plugin/context';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { exportHierarchy } from './export';
export class ModelExportUI extends CollapsableControls<{}, {}> {
protected defaultState(): CollapsableState {
return {
header: 'Export Models',
isCollapsed: true,
brand: { accent: 'cyan', svg: GetAppSvg }
};
}
protected renderControls(): JSX.Element | null {
return <ExportControls plugin={this.plugin} />;
}
}
const Params = {
format: PD.Select<'cif' | 'bcif'>('cif', [['cif', 'mmCIF'], ['bcif', 'Binary mmCIF']])
};
const DefaultParams = PD.getDefaultValues(Params);
function ExportControls({ plugin }: { plugin: PluginContext }) {
const [params, setParams] = useState(DefaultParams);
const [exporting, setExporting] = useState(false);
useBehavior(plugin.managers.structure.hierarchy.behaviors.selection); // triggers UI update
const isBusy = useBehavior(plugin.behaviors.state.isBusy);
const hierarchy = plugin.managers.structure.hierarchy.current;
let label: string = 'Nothing to Export';
if (hierarchy.structures.length === 1) {
label = 'Export';
} if (hierarchy.structures.length > 1) {
label = 'Export (as ZIP)';
}
const onExport = async () => {
setExporting(true);
try {
await exportHierarchy(plugin, { format: params.format });
} finally {
setExporting(false);
}
};
return <>
<ParameterControls params={Params} values={params} onChangeValues={setParams} isDisabled={isBusy || exporting} />
<Button
onClick={onExport}
style={{ marginTop: 1 }}
disabled={isBusy || hierarchy.structures.length === 0 || exporting}
commit={hierarchy.structures.length ? 'on' : 'off'}
>
{label}
</Button>
</>;
}

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