Compare commits

...

332 Commits

Author SHA1 Message Date
Alexander Rose
5d9e14aad1 0.4.2 2019-11-19 15:29:19 -08:00
Alexander Rose
9963cb3770 prevent browser scrolling with middle click (FF on win) 2019-11-19 09:02:20 -08:00
Alexander Rose
5731ef20b3 0.4.1 2019-11-18 16:14:41 -08:00
Alexander Rose
ab89d34440 package updates 2019-11-18 16:13:43 -08:00
Alexander Rose
d9bac2916c fix polymer sequence widget .getLoci
was not taking operator.name into account
2019-11-18 15:21:42 -08:00
Alexander Rose
edaa9610f6 camera focus takes granularity into account 2019-11-18 14:39:32 -08:00
Alexander Rose
90255b1a1b moved loci normalization/granularity to model/loci 2019-11-18 14:38:55 -08:00
Alexander Rose
639f137ad2 fix PrincipalAxes 2019-11-18 12:08:53 -08:00
Alexander Rose
29609e04c2 improved structure docs and sequence description 2019-11-18 11:43:51 -08:00
Alexander Rose
736aaf4433 matrix and axes improvements 2019-11-18 11:43:10 -08:00
Alexander Rose
2d7248962f add oriented-box visual to structure-orientation 2019-11-17 19:02:44 -08:00
Alexander Rose
a13c98c36c fix StructureElementSelectionManager.getPrincipalAxes for multiple entries 2019-11-17 17:32:37 -08:00
Alexander Rose
e298499326 improved handling of Structure.Loci, added whole structure support to Stats 2019-11-17 17:27:57 -08:00
Alexander Rose
6e1e463e1d fix whole structure selection/highlighting 2019-11-17 16:45:16 -08:00
Alexander Rose
2a2261beaf principal axes for loci and orientation for Camera.focus 2019-11-17 16:10:28 -08:00
Alexander Rose
14623f5df2 vec3 improvements, .matchDirection & readonly .negUnit 2019-11-17 16:03:48 -08:00
Alexander Rose
32889779a2 ModelUnitcell cleanup 2019-11-16 19:22:06 -08:00
Alexander Rose
911a7e3636 wip, structure orientation representation 2019-11-16 19:21:37 -08:00
Alexander Rose
bcf8ae2734 wip, principal component refactoring 2019-11-16 19:20:40 -08:00
Alexander Rose
92df3b1f42 console.log 2019-11-16 16:11:53 -08:00
Alexander Rose
5bbed1f9a3 remove console.log statement 2019-11-16 16:10:46 -08:00
Alexander Rose
0a391760b8 fix stats.firstResidueLoc assignment 2019-11-16 15:42:12 -08:00
Alexander Rose
e7eeb8cb55 center/focus with left+alt 2019-11-16 14:46:06 -08:00
Alexander Rose
bee4f38209 0.4.0 2019-11-15 16:35:56 -08:00
Alexander Rose
ff4dcfc220 package updates 2019-11-15 16:34:13 -08:00
Alexander Rose
ad726a97e4 filter display list of select queries, add bonded query 2019-11-15 16:12:49 -08:00
Alexander Rose
b533542792 check if pointer actually moved 2019-11-15 15:15:09 -08:00
Alexander Rose
dbe33cc046 twekaed mouse bindings
left: toggle selection
middle: center
right: show surrounding
2019-11-15 15:06:59 -08:00
Alexander Rose
3ddf5f4bec tweaked StructureRepresentationInteraction visual
make look less like ball+stick default
2019-11-15 15:04:46 -08:00
Alexander Rose
f02d49f181 typo 2019-11-15 15:01:57 -08:00
Alexander Rose
4df68697f2 update CommonSaccharideNames 2019-11-15 15:01:36 -08:00
Alexander Rose
eeb09d9184 allow partial params in .createParams helper 2019-11-15 15:01:17 -08:00
David Sehnal
d8509a145b mol-model: fixed Loci stats 2019-11-15 21:01:38 +01:00
David Sehnal
e3cb799638 mol-model: fix Loci.extentTo* 2019-11-15 20:49:59 +01:00
David Sehnal
ce9469c85b mol-model: Fixed Loci.isSubset 2019-11-15 20:33:08 +01:00
David Sehnal
e62b166805 mol-model: fix Loci Stats.add 2019-11-15 20:12:47 +01:00
David Sehnal
a1f283c641 Merge branch 'master' of https://github.com/molstar/molstar 2019-11-15 20:05:49 +01:00
David Sehnal
2b14c398a8 mol-model: optimized Loci.extendToResidues/Chains 2019-11-15 20:05:44 +01:00
Alexander Rose
d8480d058b don't apply granularity for State Highlight 2019-11-15 09:51:51 -08:00
David Sehnal
b1ac1a36d4 mol-model: extendToWholeChains now works on partitioned chains 2019-11-15 16:27:58 +01:00
David Sehnal
3c2d014ad3 mol-model: count chains in Loci stats 2019-11-15 14:39:17 +01:00
David Sehnal
d940d26312 mol-model: added Unit.Traits (replaces multiChain prop) 2019-11-15 13:23:01 +01:00
Alexander Rose
99028b5c99 use unit.chainGroupId in sequence widget 2019-11-14 18:03:26 -08:00
Alexander Rose
ac94f0659d add unit.multiChain; tweaks to unit.chainGroupId 2019-11-14 18:03:03 -08:00
Alexander Rose
bd85a5a153 sequence widget help icon 2019-11-14 14:57:21 -08:00
Alexander Rose
9aa375a45f handle conformations in selections, marking, labels 2019-11-14 14:16:26 -08:00
David Sehnal
999cb99eb8 mol-data: fixed bug in isSubsetIS 2019-11-14 06:09:30 +01:00
Alexander Rose
12b53bc4bb added failing unittest for isSubsetIS 2019-11-13 18:21:20 -08:00
Alexander Rose
952f3c451f package updates, removed now superfluous @types/webgl2 2019-11-13 13:49:50 -08:00
David Sehnal
ce06375a92 mol-plugin: sequence view remove scrollTo behavior 2019-11-13 16:19:59 +01:00
Alexander Rose
c0f60d48bb tweaked label/description for custom volume param.isRelative 2019-11-12 17:12:54 -08:00
Alexander Rose
e40f08d467 update packages 2019-11-12 17:00:44 -08:00
Alexander Rose
9c977bf90f add ColorSwatch and use instead of ColorNames for color dropdown 2019-11-12 17:00:30 -08:00
Alexander Rose
525f32feab use elementLabel() for sequence widget dropdown 2019-11-12 16:04:13 -08:00
Alexander Rose
cdb698f0d1 added stripTags string helper 2019-11-12 16:03:38 -08:00
Alexander Rose
c65d09f4a8 use previous SequenceView.state when structure hasn't changed 2019-11-12 15:13:13 -08:00
Alexander Rose
7d4e48431c add e.stopPropagation(); to onKeyPress methods in controls 2019-11-12 14:42:36 -08:00
Alexander Rose
6a7268a9c9 improved sequenceNumberPeriod for short sequences 2019-11-12 12:03:30 -08:00
Alexander Rose
eea1137abc prefer EMDB map for 'ELECTRON CRYSTALLOGRAPHY' entries 2019-11-12 11:44:46 -08:00
Alexander Rose
a130121698 fix extra layout(location = X) definitions in shaders 2019-11-12 10:39:46 -08:00
Alexander Rose
153f039ee6 added number-parser spec 2019-11-08 21:23:02 -05:00
Alexander Rose
b7216d28f4 wip, cif-core support 2019-11-08 21:12:01 -05:00
David Sehnal
ee34139094 added setMolStarDebugMode 2019-11-07 17:23:42 +01:00
David Sehnal
9addea79b7 updated packages 2019-11-07 16:56:58 +01:00
Alexander Rose
2c88ace91c added number precision helpers, improved isovalue step calculation 2019-11-05 06:14:35 +03:00
David Sehnal
6eae95f964 mol-plugin: scroll first highlighted/selected element into view 2019-11-02 15:48:20 +01:00
David Sehnal
b44ed7c45a mol-theme: lociLabel tweaks 2019-11-02 15:33:14 +01:00
David Sehnal
b2d2546e39 mol-model: added chainGroupId 2019-11-02 14:58:29 +01:00
David Sehnal
4dbabdf350 mol-plugin: fix SubstructureParentHelper 2019-11-02 13:13:31 +01:00
David Sehnal
df63d8fe0f mol-plugin: support HTML tags in labels, tweaks to default label provider 2019-11-02 12:15:17 +01:00
David Sehnal
c9116575fa mol-model: support isConnectedTo query disjunct and invert 2019-11-02 11:34:46 +01:00
David Sehnal
6707673c7f mol-model: fixes to link related queries 2019-11-02 11:30:02 +01:00
Alexander Rose
1f82446843 0.3.12 2019-11-01 13:43:17 -07:00
Alexander Rose
9942b0e389 avoid extra selection in cellpack loader 2019-11-01 13:41:39 -07:00
Alexander Rose
f57e8501c4 fix order in LociMarkManager.normalizedLoci 2019-11-01 13:25:14 -07:00
Alexander Rose
1e9fa003db don't apply granularity in StructureSelectionControls 2019-11-01 11:29:58 -07:00
Alexander Rose
7868b22918 added disulfide-bridges StructureSelectionQuery 2019-11-01 11:15:40 -07:00
Alexander Rose
e2c80956dc structureElementStatsLabel tweaks 2019-11-01 11:12:48 -07:00
David Sehnal
5d5af58bdf mol-model: removed QueryContextLinkInfo.swap 2019-11-01 16:47:23 +01:00
David Sehnal
8f78106816 mol-data: fix SortedArray.union & mol-model: fix includeConnected 2019-11-01 15:43:04 +01:00
David Sehnal
1923289c51 mol-plugin: better element loci highlight label 2019-11-01 14:55:37 +01:00
David Sehnal
14c22147d5 mol-script: added linkedAtomicPairs generator + fixed assembly-symmetry-axes isApplicable for empty structures 2019-11-01 14:39:15 +01:00
David Sehnal
6d39bc4a20 mol-script: added more link props, support different element reference for atomic props 2019-11-01 13:46:40 +01:00
Alexander Rose
cfaecb590d fix StructureRepresentationInteractionBehavior bundle handling 2019-10-31 19:05:51 -07:00
Alexander Rose
2894c18ba1 0.3.11 2019-10-31 17:13:11 -07:00
Alexander Rose
e6633c2fc6 optimized Bundle.toStructure 2019-10-31 17:10:47 -07:00
Alexander Rose
fe341f0851 fix Bundle.toStructure, #19 2019-10-31 16:55:04 -07:00
Alexander Rose
34a387d4bd optimize StructureRepresentationInteractionBehavior by using bundle 2019-10-31 12:35:49 -07:00
Alexander Rose
f975d9c8dc add names anon molql functions for debugging/profiling 2019-10-31 12:31:25 -07:00
Alexander Rose
563ff98c83 fix MolScript.internal.generator.bundle binding 2019-10-31 12:29:02 -07:00
Alexander Rose
0b9ecb76b9 tweaked ball&stick default size 2019-10-31 10:27:24 -07:00
Alexander Rose
b8de1de3a8 don't calc sec-struc for archival files 2019-10-31 10:22:05 -07:00
Alexander Rose
ac2f48684e updated cif schemas with more meta data fields 2019-10-31 10:18:43 -07:00
Alexander Rose
9928b17a76 fix, carb preset missing connected 2019-10-31 09:44:06 -07:00
Alexander Rose
723a6a1fbd gracefully handle errors when getting em map info 2019-10-30 18:05:44 -07:00
Alexander Rose
51ac75943d query preset tweaks 2019-10-30 17:37:10 -07:00
Alexander Rose
6bcb5eac71 adjust 'auto' quality 2019-10-30 16:30:36 -07:00
Alexander Rose
f2f1e355c2 molql, fix expandConnected 2019-10-30 16:30:08 -07:00
Alexander Rose
4cc0754f11 add isNonStandard atom prop, use polymer repr preset 2019-10-30 15:35:18 -07:00
Alexander Rose
cd30caa12d better align negative sequence numbers in ui 2019-10-30 10:48:19 -07:00
Alexander Rose
41bc74e543 add support for Beta and Gamma peptides 2019-10-30 10:26:35 -07:00
David Sehnal
96a908698d mol-data: fix Column.view if underlying __array is of different type than value 2019-10-30 12:21:29 +01:00
Alexander Rose
77a561024f removed unneccessary z-index 2019-10-29 16:24:47 -07:00
Alexander Rose
5d0176e686 use landscape for reactive layout when width > 1000 2019-10-29 15:41:23 -07:00
David Sehnal
3a6013145e mol-task: fixed subtask cancellation 2019-10-29 21:42:26 +01:00
David Sehnal
c5e2471f34 mol-state/task: use console.error only when not in production mode 2019-10-29 20:37:29 +01:00
Alexander Rose
e9802f2191 0.3.10 2019-10-29 12:07:55 -07:00
Alexander Rose
2d0097fddc package updates 2019-10-29 12:07:02 -07:00
Alexander Rose
1a245db4c9 tweaked bindings formating 2019-10-29 11:56:38 -07:00
Alexander Rose
6a694f9298 wip, tweak tasks css 2019-10-28 17:25:11 -07:00
Alexander Rose
acd1f43018 0.3.9 2019-10-28 16:57:41 -07:00
Alexander Rose
71ed9a2db9 fix extractCrossLinkRestraints 2019-10-28 16:51:21 -07:00
David Sehnal
2b5d9bd213 Merge branch 'master' of https://github.com/molstar/molstar 2019-10-28 22:13:30 +01:00
David Sehnal
32c8664829 mol-plugin: fix transform update UI when error happens 2019-10-28 22:13:10 +01:00
David Sehnal
26e6e0ab72 Task cancellation fix 2019-10-28 22:03:10 +01:00
Alexander Rose
6d9c9bd884 use model.entryId(s) for image filename when possible 2019-10-28 12:07:30 -07:00
David Sehnal
2a74d5eb94 mol-state: added revertible update (and used it in DownloadStrucutre action) 2019-10-28 16:23:41 +01:00
David Sehnal
04d39e0e8d support Task cancellation in plugin UI 2019-10-28 16:01:13 +01:00
David Sehnal
c5e64b39db mol-model-formats: mmCIF substitute undefined atom_site.label_* with auth_* columns (and vice versa) 2019-10-27 11:53:37 +01:00
Alexander Rose
4911585a85 fix seq number in sequence widget for atomic models without auth_seq_id 2019-10-25 18:26:08 -07:00
Alexander Rose
590c00114f 0.3.8 2019-10-25 15:48:20 -07:00
Alexander Rose
111eded34a disable some ui elements when state tree is busy 2019-10-25 12:18:46 -07:00
Alexander Rose
d767900fb1 fix, canvas.render not always returning true when it did render 2019-10-25 12:06:14 -07:00
Alexander Rose
9074d5390a add support for sequence numbers in coarse units 2019-10-24 16:28:06 -07:00
Alexander Rose
91027459ca typos 2019-10-24 15:02:23 -07:00
Alexander Rose
a2eda6c5af added controls display options: outside, portrait, landscape, reactive 2019-10-24 11:32:00 -07:00
Alexander Rose
338489febd 0.3.7 2019-10-24 07:54:31 -07:00
David Sehnal
94e7820baf mol-data: SortedArray fix 2019-10-24 07:40:35 +02:00
Alexander Rose
a47df57709 more SortedArray.union tests (one failing) 2019-10-23 19:32:41 -07:00
Alexander Rose
f73d64f732 0.3.6 2019-10-23 18:15:46 -07:00
Alexander Rose
cfaef4c567 added more volume param docs 2019-10-23 18:14:16 -07:00
Alexander Rose
3ec2c6ded4 ui layout tweaks 2019-10-23 17:18:16 -07:00
Alexander Rose
2afaa35170 increased default wireframe thickness from 1 to 1.5 2019-10-23 17:17:34 -07:00
Alexander Rose
efcf4a77c6 add molecular surface wireframe visual 2019-10-23 17:16:40 -07:00
Alexander Rose
221e1de4e7 improved entity-source color theme 2019-10-23 12:25:59 -07:00
Alexander Rose
f2de2983c8 added isInteger helper 2019-10-23 12:25:38 -07:00
Alexander Rose
82c8499789 updated cif schemas 2019-10-23 11:43:19 -07:00
David Sehnal
d66ccdb255 mol-plugin: sequence view tweaks 2019-10-23 09:27:59 +02:00
David Sehnal
8d13c514b0 mol-data: SortedArray fix 2019-10-23 09:17:25 +02:00
Alexander Rose
f57aafba19 improved sequence numbers in sequence widget UI 2019-10-22 17:25:57 -07:00
Alexander Rose
0a7406db15 added more SortedArray.union tests, one failing 2019-10-22 15:17:18 -07:00
Alexander Rose
2f97e8b329 overset residue numbers in sequence ui 2019-10-22 12:24:53 -07:00
David Sehnal
22a8758852 mol-data: fixed SortedArray.union 2019-10-22 20:48:16 +02:00
Alexander Rose
bc6bc1d57a fix StructureElement.Stats 2019-10-22 10:22:02 -07:00
Alexander Rose
4a692b9a88 ensure applicable repr types are up-to-date 2019-10-22 10:20:55 -07:00
Alexander Rose
0094f800dc fixed entity-source color theme labels 2019-10-21 18:18:26 -07:00
Alexander Rose
9bd616f36f ensure file extension for image download 2019-10-21 17:59:09 -07:00
David Sehnal
4acc36628d mol-plugin: show sequence offsets in UI (wip) 2019-10-21 15:06:58 +02:00
David Sehnal
e550413778 mol-state: added createDefaultParams to StateAction and StateTransformer 2019-10-21 13:45:18 +02:00
David Sehnal
ccdc894979 ability to set default params for volume streaming 2019-10-21 13:39:05 +02:00
David Sehnal
322bc71d52 changed default color list to dark-2 to avoid a clash with EM volume map colors 2019-10-21 12:49:04 +02:00
Alexander Rose
7c55e4d234 0.3.5 2019-10-18 17:02:14 -07:00
Alexander Rose
8c8058290c fixed spacegroup index/number handling 2019-10-18 16:58:53 -07:00
David Sehnal
9d413bf0eb mol-util: palette fix missing valueLabel function 2019-10-18 15:29:45 +02:00
Alexander Rose
8fde5dd1bf 0.3.4 2019-10-17 11:47:10 -07:00
Alexander Rose
2f9ecb9396 package updates 2019-10-17 11:46:26 -07:00
Alexander Rose
85092279fa better handle unsupported extensions 2019-10-17 11:40:32 -07:00
Alexander Rose
d0189523e4 fix Loci stats for partial residue selections 2019-10-17 11:10:10 -07:00
Alexander Rose
a26d03205a tweak bindings to work better with one-button mouse 2019-10-16 18:26:22 -07:00
Alexander Rose
862eda6dd4 better min size limit in image ui 2019-10-16 17:54:46 -07:00
Alexander Rose
4a7f0fc206 hide non-applicable repr types in repr ui 2019-10-16 17:46:27 -07:00
Alexander Rose
6bbee58d39 guard against undefined values in ParameterControls 2019-10-16 16:42:14 -07:00
Alexander Rose
989faed410 added StructureSelectionQuery wrapping expr & query 2019-10-16 16:30:38 -07:00
Alexander Rose
198e2f2043 support for currentSelection in StructureSelectionHelper and surroundings query 2019-10-16 15:48:39 -07:00
Alexander Rose
6ae3d4110d added StructureElement.Loci.toStructure 2019-10-16 15:47:57 -07:00
David Sehnal
c34e1be43b Merge branch 'master' of https://github.com/molstar/molstar 2019-10-16 20:46:40 +02:00
David Sehnal
17a440ad9c moved StructureQuery.runExpr to Script.getStructureSelection to fix cyclic dep 2019-10-16 20:46:25 +02:00
Alexander Rose
04dcfc7adb check seqId compatibility for cyclic peptides 2019-10-16 11:01:07 -07:00
David Sehnal
ca66e334c1 mol-model: added StructureQuery.runExpr 2019-10-16 13:47:06 +02:00
David Sehnal
54bba4c92f mol-script: added internal.generator.current symbol 2019-10-16 13:38:58 +02:00
David Sehnal
9c046b808c mol-script: added Bundle support 2019-10-16 13:26:05 +02:00
David Sehnal
ca5d1865cc mol-model: Loci fixes 2019-10-16 12:48:21 +02:00
Alexander Rose
d8f1aa5bc9 support for streaming multiple em volumes, limit to associate maps 2019-10-15 17:38:42 -07:00
David Sehnal
6ac790e083 mol-model: renamed StructureSelection.toLoci* 2019-10-15 08:49:06 +02:00
David Sehnal
d0870e4bbb added highlight example to basic wrapper, better empty loci handling 2019-10-15 08:44:50 +02:00
Alexander Rose
5138595f36 added more StructureSelectionQueries 2019-10-14 16:26:54 -07:00
Alexander Rose
d9aa5684a9 show non-polymer residues of polymer entities as ball&stick 2019-10-14 14:09:34 -07:00
Alexander Rose
8e2521a7a9 consider coarse/non-coarse backbone when checking distance for backbone links 2019-10-14 14:09:12 -07:00
Alexander Rose
7dd7a117cb wip, terminal gaps 2019-10-11 16:55:39 -07:00
Alexander Rose
defbadf4d7 handle polymer ends in visuals properly 2019-10-11 16:55:22 -07:00
Alexander Rose
131e88080a 0.3.3 2019-10-10 10:43:52 -07:00
Alexander Rose
fb78b886c1 collapse link labels to hide repeated ids 2019-10-10 10:41:56 -07:00
Alexander Rose
aed0b87b16 fix fractional canvas/image dimensions 2019-10-10 10:35:44 -07:00
Alexander Rose
1316cc6a40 fix StructureSelectionControls.focus for single element 2019-10-09 17:52:59 -07:00
Alexander Rose
944d370c14 0.3.2 2019-10-09 16:59:24 -07:00
Alexander Rose
74f9aa6af6 package updates 2019-10-09 16:55:44 -07:00
Alexander Rose
c20c9c9917 fixed setting CollapsableControls default state 2019-10-09 16:54:15 -07:00
Alexander Rose
4801435d72 add controls to create image 2019-10-09 16:10:36 -07:00
Alexander Rose
33fd105ef7 add ImagePass 2019-10-09 16:09:43 -07:00
Alexander Rose
3ea3fb8984 support rendering with transparent background 2019-10-09 16:08:48 -07:00
Alexander Rose
b4bbc544ca 0.3.1 2019-10-07 17:27:35 -07:00
Alexander Rose
5f880e920b add focus button to StructureSelectionControls 2019-10-07 17:26:16 -07:00
Alexander Rose
bcce801dd7 ensure sequence markers are up-to-date 2019-10-07 16:10:21 -07:00
Alexander Rose
00f9dcee4a added StructureSymmetryMatesFromModel transform, fixes for findMatesRadius 2019-10-07 15:31:54 -07:00
Alexander Rose
505af2bc96 fix help for scrollFocus 2019-10-07 12:04:20 -07:00
Alexander Rose
c217aab5fc reduced default unicell cage thickness 2019-10-07 11:23:50 -07:00
Alexander Rose
5d5fd0028f added operator name & hkl color themes 2019-10-07 11:20:10 -07:00
Alexander Rose
c88693dfdd improved color theme legend with labels from data 2019-10-07 11:18:08 -07:00
David Sehnal
0a16ec1bd2 mol-plugin: added TextInput wrapper and RGB color input 2019-10-05 14:52:00 +02:00
Alexander Rose
6f36a3c724 0.3.0 2019-10-04 17:21:16 -07:00
Alexander Rose
71496bd1ef package updates 2019-10-04 17:20:38 -07:00
Alexander Rose
c5a99a7c12 improved lociApply for whole structures 2019-10-04 17:07:08 -07:00
Alexander Rose
cfaf33d696 also look for 4 and 7 member sugar rings 2019-10-04 15:55:47 -07:00
Alexander Rose
e24c76d2bf update modifierkeys on mouse input 2019-10-04 15:40:14 -07:00
Alexander Rose
b6273205a2 removed duplicate type 2019-10-04 15:18:33 -07:00
Alexander Rose
b38193aa19 for unknown carbs draw polygonal prisms 2019-10-04 15:13:00 -07:00
Alexander Rose
f9cfacae23 sequence widget, bind onMouseLeave 2019-10-04 12:26:05 -07:00
Alexander Rose
ac46317dc6 fix lighting for orthographic projection close to camera 2019-10-04 11:53:38 -07:00
Alexander Rose
2b492a5a61 lighter monospace font 2019-10-04 10:44:08 -07:00
Alexander Rose
a2133657f0 chnaged label Unit->Chain in sequence widget 2019-10-04 10:42:07 -07:00
David Sehnal
e8de45789f mol-plugin: optimized sequence control 2019-10-04 16:52:36 +02:00
David Sehnal
3d2bd167ca mol-plugin: use monospace font for sequence 2019-10-04 15:34:59 +02:00
David Sehnal
504c8626dc mol-plugin: fixed PluginCommands.State.Highlight (wip) 2019-10-04 15:22:26 +02:00
Alexander Rose
f4b29dc7e0 ui, offset expanded color param 2019-10-03 17:24:24 -07:00
Alexander Rose
b34c5c743b tweaked ligandPlusConnected selection 2019-10-03 16:40:44 -07:00
Alexander Rose
c57311d6c0 carbohydrate improvements, updated carb table 2019-10-03 16:04:32 -07:00
Alexander Rose
4d786dc697 fix missing awaits in StructureRepresentationHelper.preset 2019-10-03 11:50:18 -07:00
Alexander Rose
062e3e055a show full compId for modified residues in sequence widget 2019-10-03 10:05:31 -07:00
Alexander Rose
1465174a45 Merge branch 'master' of https://github.com/molstar/molstar 2019-10-02 17:57:38 -07:00
Alexander Rose
cc00ada5a3 add model Unitcell representation 2019-10-02 17:57:19 -07:00
Alexander Rose
cbf312b62d calculate symmetry operators for transform around deposited coordinates 2019-10-02 17:56:41 -07:00
Alexander Rose
2be3144086 add .volume to SpacegroupCell 2019-10-02 17:55:03 -07:00
Alexander Rose
da3acd9d19 calculate model center as dynamic prop 2019-10-02 17:53:51 -07:00
Alexander Rose
34b048479b added arrayMinMax util 2019-10-02 17:53:03 -07:00
Alexander Rose
ca92931bf2 mol-geo improvements for mesh, cage and primitive 2019-10-02 17:52:48 -07:00
David Sehnal
0d3daeb823 mol-plugin: semi-transparent viewport controls background 2019-10-02 13:11:50 +02:00
David Sehnal
58b1d7e0eb mol-model & formats: added fallback when chem_comp category is missing 2019-10-02 12:46:23 +02:00
Alexander Rose
c5997ed056 reset buttons and modifier keys state when browser window looses focus 2019-10-01 14:11:01 -07:00
Alexander Rose
da1deee7f3 switched off marker interpolation for webgl2 2019-10-01 10:58:26 -07:00
Alexander Rose
a4eaff3175 add background to canvas icons for legibility with different render background colors 2019-10-01 10:30:44 -07:00
Alexander Rose
211cfc0bd3 fix highlight persisting after rotation 2019-10-01 09:52:18 -07:00
David Sehnal
c0f85b691d mol-plugin: reverted msp-layout-region background !important, because it broke the visual style 2019-10-01 17:42:42 +02:00
David Sehnal
6b93d58ea6 mol-plugin: updated color select control 2019-10-01 17:33:49 +02:00
Alexander Rose
5bce423b49 fully mark carbohydrate terminal links from StructureElement.Loci 2019-09-30 17:38:05 -07:00
Alexander Rose
01b0dde503 set plugin Context.customState: unknown 2019-09-30 16:38:55 -07:00
Alexander Rose
ed1bc8cb7d ensure single element loci have some volume in volume interaction behavior 2019-09-30 15:52:55 -07:00
Alexander Rose
abe559261b show insertion code in labels 2019-09-30 14:36:42 -07:00
Alexander Rose
b0cdf22cb8 various interaction behaviors improvements 2019-09-30 14:26:59 -07:00
Alexander Rose
a61ba71f1e handle mixed sizes in link visuals 2019-09-30 12:11:07 -07:00
Alexander Rose
7061d57559 tweak some bond distance thresholds 2019-09-30 11:06:49 -07:00
Alexander Rose
83a1e6c87c improved entity subtype assignment (use chem comp type) 2019-09-30 11:06:19 -07:00
Alexander Rose
c18888b8de 0.2.15 2019-09-27 17:19:57 -07:00
Alexander Rose
2d80935e00 ignore non-identity 'given' NCS operators 2019-09-27 17:18:14 -07:00
Alexander Rose
4287d158b6 add Mat3.isIdentity 2019-09-27 17:18:06 -07:00
Alexander Rose
4e9b569178 show logo in empty viewer 2019-09-27 16:48:10 -07:00
Alexander Rose
5d626d291b added viewer favicon 2019-09-27 16:48:00 -07:00
Alexander Rose
afa4a01c44 package updates 2019-09-27 16:41:53 -07:00
Alexander Rose
3c4a23c5a3 ensure msp-layout-region background 2019-09-27 15:22:27 -07:00
Alexander Rose
8d92c976d9 css 'select' tweaks 2019-09-27 13:19:01 -07:00
Alexander Rose
1a9adfad29 0.2.14 2019-09-27 11:17:53 -07:00
Alexander Rose
a9e9a5974d fix volumeserver cmd arg types 2019-09-27 11:10:11 -07:00
Alexander Rose
27160aa8fe fix stale array use 2019-09-26 15:33:52 -07:00
David Sehnal
6a71af00cf mol-plugin: Toast support 2019-09-26 16:18:57 +02:00
David Sehnal
6c0938db50 mol-plugin: added InitVolumeStreaming binding param 2019-09-26 15:11:13 +02:00
Alexander Rose
b76173c82f 0.2.13 2019-09-25 17:25:25 -07:00
Alexander Rose
0bcf2b1ff4 fix wrong style.overflow assignment 2019-09-25 16:07:25 -07:00
Alexander Rose
d074415a26 added more param docs 2019-09-25 11:55:00 -07:00
Alexander Rose
42f3e38026 0.2.12 2019-09-24 14:21:58 -07:00
Alexander Rose
74c16ee7ba package updates 2019-09-24 14:19:44 -07:00
Alexander Rose
f6ef22b917 added link cylinder to ellopsoids repr 2019-09-24 14:16:19 -07:00
Alexander Rose
c3f3d7efda check if atomistic before query modified 2019-09-24 12:20:38 -07:00
Alexander Rose
61d44efdc4 fix typo 2019-09-24 12:12:19 -07:00
Alexander Rose
ad200c86ec Merge branch 'master' of https://github.com/molstar/molstar 2019-09-24 12:10:54 -07:00
Alexander Rose
4aecf4e0b4 added ElementSequenceWrapper & ChainSequenceWrapper 2019-09-24 12:09:54 -07:00
Alexander Rose
d81f37c78b added AtomicUnit.residueCount 2019-09-24 12:07:26 -07:00
Alexander Rose
c2979ce5ab StructureSequence, handle empty coarse hierarchies 2019-09-24 12:06:55 -07:00
Alexander Rose
09c7edce88 smaller terminal links and dashed terminal links to metals 2019-09-24 10:11:42 -07:00
David Sehnal
beefb79258 mol-plugin: better default Structure Complex, extended StructureComplexElement transform 2019-09-24 15:17:05 +02:00
David Sehnal
529c6ac81c mol-plugin: fix SelectionFromScript & volume streaming bugs 2019-09-24 14:07:42 +02:00
Alexander Rose
84b988ea96 fix csv parser choking on newline at end of file 2019-09-23 16:46:35 -07:00
Alexander Rose
35e978efc9 added Table.toArrays 2019-09-23 16:45:58 -07:00
David Sehnal
19559d01f7 mol-state: call canAutoUpdate with correct parameters 2019-09-23 16:53:31 +02:00
David Sehnal
56cec343e2 Proteopedia wrapper fix 2019-09-23 16:12:40 +02:00
David Sehnal
20c9bd0130 mol-plugin: CSS fix 2019-09-23 15:56:48 +02:00
David Sehnal
1336997c58 mol-plugin: volume streaming support for LinkLoci, update "current box" when switching to surroundings, init behavior fix 2019-09-23 15:47:55 +02:00
David Sehnal
b178fdefdc mol-plugin: Camera focus duration default value fix 2019-09-23 14:59:44 +02:00
Alexander Rose
453d60060a ui, print length of sequences that are too long 2019-09-22 19:48:59 -07:00
Alexander Rose
901fac97a0 basic support for .3dg files 2019-09-22 19:44:37 -07:00
Alexander Rose
29b6a88343 check for Performance object capabilities 2019-09-22 19:43:13 -07:00
Alexander Rose
a2217c7fc6 fix csv parser chunking 2019-09-22 19:42:31 -07:00
Alexander Rose
3eec30aa42 sequence improvements, create sequence from coarse elements 2019-09-22 18:29:46 -07:00
Alexander Rose
f352e19e90 config for debugging 2019-09-22 09:32:19 -07:00
Alexander Rose
be65ef89bc 0.2.11 2019-09-20 17:23:25 -07:00
Alexander Rose
cfc46073c0 package updates 2019-09-20 17:22:39 -07:00
Alexander Rose
1819a2bbda add wwpdb provider for emdb contourLevel 2019-09-20 17:14:53 -07:00
Alexander Rose
aa3a42f94e added simple xml parser 2019-09-20 17:13:13 -07:00
Alexander Rose
4bff55b612 improve theme applicability checks 2019-09-20 15:08:55 -07:00
Alexander Rose
dbc4e09909 add 'disorder' to uncertainty theme label/description 2019-09-20 14:46:46 -07:00
Alexander Rose
0a074c8a66 add modelNum to location labels 2019-09-20 11:10:40 -07:00
Alexander Rose
8b314ebb75 add border to .msp-layout-standard 2019-09-20 10:20:12 -07:00
Alexander Rose
4dc0791aeb tweaked slider rail/handle color 2019-09-20 10:06:59 -07:00
Alexander Rose
e3483f11b1 adjusted maxCovalentHydrogenBondingLength 2019-09-20 09:32:45 -07:00
Alexander Rose
244a678ab7 fix Props.residue.label_comp_id for micro het 2019-09-19 19:11:57 -07:00
Alexander Rose
8e1d44fabc fixes, seq wrapper mark every loci, binding docs & cleanup 2019-09-19 18:33:44 -07:00
Alexander Rose
954a5b58e0 tweaked structure and volume surroundings behaviors 2019-09-19 18:10:07 -07:00
Alexander Rose
53223bc72b support EveryLoci in StructureRepresentation.mark 2019-09-19 17:10:28 -07:00
Alexander Rose
a11a1fa07e formating 2019-09-19 17:09:26 -07:00
Alexander Rose
9ab4001544 get Behavior defaultParams from transformer params 2019-09-19 17:09:15 -07:00
Alexander Rose
3e3b71d230 added Interval.ofLength 2019-09-19 17:08:36 -07:00
Alexander Rose
186929269b refactored bindings and interactivity 2019-09-19 17:08:20 -07:00
Alexander Rose
afa7a04af0 various ui tweaks, added CollapsableControls 2019-09-19 17:03:06 -07:00
Alexander Rose
2861d12f04 inline help for params, color theme legend ui 2019-09-16 16:47:58 -07:00
Alexander Rose
65e1212b2f wip, focusZoom action 2019-09-13 16:30:55 -07:00
Alexander Rose
47136c8b71 wip, focus input bindings 2019-09-13 12:57:46 -07:00
Alexander Rose
375b829562 wip, simplified camera class 2019-09-13 10:53:56 -07:00
Alexander Rose
2718d42b01 wip, input bindings, radius-based clipping 2019-09-12 16:47:19 -07:00
Alexander Rose
93d4118c0a Merge branch 'master' of https://github.com/molstar/molstar 2019-09-12 09:37:31 -07:00
David Sehnal
3a2a47af12 removed unused comments 2019-09-12 16:09:47 +02:00
David Sehnal
0eacdfca85 added transition duration effect to camera focus 2019-09-12 16:07:48 +02:00
David Sehnal
a7388be25f mol-canvas3d: fixed camera focus 2019-09-12 15:34:27 +02:00
Alexander Rose
5fcdcb1275 webpack.config cleanup, package updates 2019-09-11 17:57:54 -07:00
Alexander Rose
4635bdffb0 0.2.10 2019-09-11 16:11:33 -07:00
Alexander Rose
72b1c36111 basic microheterogeneity support 2019-09-11 15:50:57 -07:00
Alexander Rose
fc5ff601a8 typed generic (Column<T>) return of windowColumn 2019-09-11 15:49:13 -07:00
Alexander Rose
8dd142fc9f fixed ellipsoids with three identical eigenvalues (render sphere) 2019-09-11 10:35:14 -07:00
Alexander Rose
97f24293e2 0.2.9 2019-09-10 16:52:30 -07:00
Alexander Rose
f4beba5215 pdb-parser, aniso records 2019-09-10 16:49:10 -07:00
Alexander Rose
e2abe0f52a pdb-parser, atom-site fixes 2019-09-10 16:48:36 -07:00
Alexander Rose
5d18643374 pdb-parser, move atom-site methods to separate file 2019-09-10 15:50:04 -07:00
Alexander Rose
769f2a30c2 package updates 2019-09-10 15:43:00 -07:00
Alexander Rose
0e040d7744 added occupancy color theme 2019-09-10 15:31:57 -07:00
Alexander Rose
7600d0a44e add ellipsoid repr showing mmcif thermal displacement 2019-09-10 15:10:58 -07:00
Alexander Rose
9113d6d189 only show applicable repr types in ui 2019-09-10 15:10:13 -07:00
Alexander Rose
fd9dac86b9 combined duplicate chem_comp_bond props 2019-09-10 15:09:33 -07:00
Alexander Rose
fe1f3bd4bb use structure.uniqueResidues, removed duplicated code 2019-09-10 11:12:00 -07:00
Alexander Rose
d950718110 linalg: return out array for .toArray, create symmetric mat3 2019-09-10 10:50:34 -07:00
Alexander Rose
4be903b9d5 added atom_site_anisotrop to mmcif schema 2019-09-09 17:35:16 -07:00
Alexander Rose
8050644869 mat3 symmetricEigenvalues and eigenvectors 2019-09-09 17:32:45 -07:00
Alexander Rose
347c1986df require output object for Tensor.to* methods 2019-09-09 17:32:02 -07:00
David Sehnal
eac4a8988b mol-model: added Model.entryId; mol-plugin: toggle validation tooltip; fixed using correct entryId for various custom properties 2019-09-05 16:09:05 +02:00
Alexander Rose
25137f29d2 typescript 3.6 compat fixes 2019-09-04 17:26:42 -07:00
Alexander Rose
4601fe74bb packaage updates 2019-09-04 17:26:21 -07:00
322 changed files with 12099 additions and 3604 deletions

View File

@@ -4,7 +4,9 @@
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"firsttris.vscode-jest-runner",
"ms-vscode.vscode-typescript-tslint-plugin",
"msjsdiag.debugger-for-chrome",
"slevesque.shader",
"stpn.vscode-graphql",
"wayou.vscode-todo-highlight"

16
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Mol* Viewer",
"url": "http://localhost:1338/build/viewer/index.html",
"sourceMaps": true,
"webRoot": "${workspaceFolder}"
}
]
}

View File

@@ -62,6 +62,8 @@ This project builds on experience from previous solutions:
### Build with debug mode enabled:
DEBUG=molstar npm run watch
Debug/production mode in browsers can be turned on/off during runtime by calling ``setMolStarDebugMode(true/false, true/false)`` from the dev console.
### Build for production:
NODE_ENV=production npm run build
@@ -143,7 +145,7 @@ To get syntax highlighting for shader and graphql files add the following to Vis
## Deploy
npm run test
NODE_ENV=production npm run build
npm run build
node ./scripts/deploy.js # currently updates the viewer on molstar.org/viewer
## Contributing

60
data/cif-core.csv Normal file
View File

@@ -0,0 +1,60 @@
audit.block_doi
database_code.depnum_ccdc_archive
chemical.name_systematic
chemical.name_common
chemical.melting_point
chemical_formula.moiety
chemical_formula.sum
chemical_formula.weight
atom_type.symbol
atom_type.description
atom_type_scat.dispersion_real
atom_type_scat.dispersion_imag
atom_type_scat.source
space_group.crystal_system
space_group.name_H-M_full
space_group_symop.operation_xyz
cell.length_a
cell.length_b
cell.length_c
cell.angle_alpha
cell.angle_beta
cell.angle_gamma
cell.volume
cell.formula_units_Z
atom_site.label
atom_site.type_symbol
atom_site.fract_x
atom_site.fract_y
atom_site.fract_z
atom_site.U_iso_or_equiv
atom_site.adp_type
atom_site.occupancy
atom_site.calc_flag
atom_site.refinement_flags
atom_site.disorder_assembly
atom_site.disorder_group
atom_site.site_symmetry_multiplicity
atom_site_aniso.label
atom_site_aniso.U_11
atom_site_aniso.U_22
atom_site_aniso.U_33
atom_site_aniso.U_23
atom_site_aniso.U_13
atom_site_aniso.U_12
geom_bond.atom_site_label_1
geom_bond.atom_site_label_2
geom_bond.distance
geom_bond.site_symmetry_2
geom_bond.publ_flag
1 audit.block_doi
2 database_code.depnum_ccdc_archive
3 chemical.name_systematic
4 chemical.name_common
5 chemical.melting_point
6 chemical_formula.moiety
7 chemical_formula.sum
8 chemical_formula.weight
9 atom_type.symbol
10 atom_type.description
11 atom_type_scat.dispersion_real
12 atom_type_scat.dispersion_imag
13 atom_type_scat.source
14 space_group.crystal_system
15 space_group.name_H-M_full
16 space_group_symop.operation_xyz
17 cell.length_a
18 cell.length_b
19 cell.length_c
20 cell.angle_alpha
21 cell.angle_beta
22 cell.angle_gamma
23 cell.volume
24 cell.formula_units_Z
25 atom_site.label
26 atom_site.type_symbol
27 atom_site.fract_x
28 atom_site.fract_y
29 atom_site.fract_z
30 atom_site.U_iso_or_equiv
31 atom_site.adp_type
32 atom_site.occupancy
33 atom_site.calc_flag
34 atom_site.refinement_flags
35 atom_site.disorder_assembly
36 atom_site.disorder_group
37 atom_site.site_symmetry_multiplicity
38 atom_site_aniso.label
39 atom_site_aniso.U_11
40 atom_site_aniso.U_22
41 atom_site_aniso.U_33
42 atom_site_aniso.U_23
43 atom_site_aniso.U_13
44 atom_site_aniso.U_12
45 geom_bond.atom_site_label_1
46 geom_bond.atom_site_label_2
47 geom_bond.distance
48 geom_bond.site_symmetry_2
49 geom_bond.publ_flag

884
examples/867861-core.cif Normal file
View File

@@ -0,0 +1,884 @@
#######################################################################
#
# This file contains crystal structure data downloaded from the
# Cambridge Structural Database (CSD) hosted by the Cambridge
# Crystallographic Data Centre (CCDC).
#
# Full information about CCDC data access policies and citation
# guidelines are available at http://www.ccdc.cam.ac.uk/access/V1
#
# Audit and citation data items may have been added by the CCDC.
# Please retain this information to preserve the provenance of
# this file and to allow appropriate attribution of the data.
#
#######################################################################
data_n1379
_audit_block_doi 10.5517/ccy42jn
_database_code_depnum_ccdc_archive 'CCDC 867861'
loop_
_citation_id
_citation_doi
_citation_year
1 10.1002/chem.201202070 2012
_audit_update_record
;
2012-02-20 deposited with the CCDC.
2016-10-08 downloaded from the CCDC.
;
_audit_creation_method SHELXL-97
_chemical_name_systematic
;
?
;
_chemical_name_common ?
_chemical_melting_point ?
_chemical_formula_moiety 'C76 H90 N10 O14 4(C2 F3 O2) 4(C2 H3 N)'
_chemical_formula_sum 'C92 H102 F12 N14 O22'
_chemical_formula_weight 1983.88
loop_
_atom_type_symbol
_atom_type_description
_atom_type_scat_dispersion_real
_atom_type_scat_dispersion_imag
_atom_type_scat_source
C C 0.0181 0.0091 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
H H 0.0000 0.0000 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
N N 0.0311 0.0180 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
O O 0.0492 0.0322 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
F F 0.0727 0.0534 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
_symmetry_cell_setting Triclinic
_symmetry_space_group_name_H-M P-1
loop_
_symmetry_equiv_pos_as_xyz
'x, y, z'
'-x, -y, -z'
_cell_length_a 11.0829(8)
_cell_length_b 14.6829(10)
_cell_length_c 16.8532(17)
_cell_angle_alpha 105.728(6)
_cell_angle_beta 100.310(6)
_cell_angle_gamma 110.620(4)
_cell_volume 2353.3(3)
_cell_formula_units_Z 1
_cell_measurement_temperature 100(2)
_cell_measurement_reflns_used 5934
_cell_measurement_theta_min 2.86
_cell_measurement_theta_max 64.30
_exptl_crystal_description plate
_exptl_crystal_colour violet
_exptl_crystal_size_max 0.57
_exptl_crystal_size_mid 0.18
_exptl_crystal_size_min 0.05
_exptl_crystal_density_meas ?
_exptl_crystal_density_diffrn 1.400
_exptl_crystal_density_method ?
_exptl_crystal_F_000 1036
_exptl_absorpt_coefficient_mu 0.995
_exptl_absorpt_correction_type integration
_exptl_absorpt_correction_T_min 0.6022
_exptl_absorpt_correction_T_max 0.9482
_exptl_absorpt_process_details 'XPREP, face-indexed'
_exptl_special_details
;
?
;
_diffrn_ambient_temperature 100(2)
_diffrn_radiation_wavelength 1.54178
_diffrn_radiation_type CuK\a
_diffrn_radiation_source microsource
_diffrn_radiation_monochromator 'Quazar optics'
_diffrn_measurement_device_type 'Bruker APEX-II CCD'
_diffrn_measurement_method '\f and \w scans'
_diffrn_detector_area_resol_mean ?
_diffrn_reflns_number 16613
_diffrn_reflns_av_R_equivalents 0.1477
_diffrn_reflns_av_sigmaI/netI 0.1112
_diffrn_reflns_limit_h_min -12
_diffrn_reflns_limit_h_max 8
_diffrn_reflns_limit_k_min -17
_diffrn_reflns_limit_k_max 17
_diffrn_reflns_limit_l_min -19
_diffrn_reflns_limit_l_max 19
_diffrn_reflns_theta_min 2.86
_diffrn_reflns_theta_max 64.94
_reflns_number_total 7680
_reflns_number_gt 5560
_reflns_threshold_expression >2sigma(I)
_computing_data_collection 'Bruker APEX2'
_computing_cell_refinement 'Bruker SAINT'
_computing_data_reduction 'Bruker SAINT'
_computing_structure_solution 'SHELXS-97 (Sheldrick, 2008)'
_computing_structure_refinement 'SHELXL-97 (Sheldrick, 2008)'
_computing_molecular_graphics 'Bruker SHELXTL'
_computing_publication_material 'Bruker SHELXTL'
_refine_special_details
;
Refinement of F^2^ against ALL reflections. The weighted R-factor wR and
goodness of fit S are based on F^2^, conventional R-factors R are based
on F, with F set to zero for negative F^2^. The threshold expression of
F^2^ > 2sigma(F^2^) is used only for calculating R-factors(gt) etc. and is
not relevant to the choice of reflections for refinement. R-factors based
on F^2^ are statistically about twice as large as those based on F, and R-
factors based on ALL data will be even larger.
Rigid bond restraints (esd 0.002) were imposed on the displacement parameters,
as well as restraints on similar amplitudes (esd 0.002) separated by less
than 1.7 Ang. on C27, C29, and N102.
Distance restraints were refined on the bond between C28 and C29.
;
_refine_ls_structure_factor_coef Fsqd
_refine_ls_matrix_type full
_refine_ls_weighting_scheme calc
_refine_ls_weighting_details
'calc w=1/[\s^2^(Fo^2^)+(0.1912P)^2^+4.8134P] where P=(Fo^2^+2Fc^2^)/3'
_atom_sites_solution_primary direct
_atom_sites_solution_secondary difmap
_atom_sites_solution_hydrogens geom
_refine_ls_hydrogen_treatment mixed
_refine_ls_extinction_method none
_refine_ls_extinction_coef ?
_refine_ls_number_reflns 7680
_refine_ls_number_parameters 633
_refine_ls_number_restraints 1
_refine_ls_R_factor_all 0.1349
_refine_ls_R_factor_gt 0.1101
_refine_ls_wR_factor_ref 0.3402
_refine_ls_wR_factor_gt 0.3102
_refine_ls_goodness_of_fit_ref 1.089
_refine_ls_restrained_S_all 1.096
_refine_ls_shift/su_max 0.000
_refine_ls_shift/su_mean 0.000
loop_
_atom_site_label
_atom_site_type_symbol
_atom_site_fract_x
_atom_site_fract_y
_atom_site_fract_z
_atom_site_U_iso_or_equiv
_atom_site_adp_type
_atom_site_occupancy
_atom_site_symmetry_multiplicity
_atom_site_calc_flag
_atom_site_refinement_flags
_atom_site_disorder_assembly
_atom_site_disorder_group
C1 C -0.3373(4) -0.2086(3) -0.2547(3) 0.0229(10) Uani 1 1 d . . .
H1 H -0.3820 -0.2827 -0.2795 0.027 Uiso 1 1 calc R . .
C2 C -0.1956(4) -0.0511(3) -0.2602(3) 0.0215(10) Uani 1 1 d . . .
H2 H -0.1401 -0.0147 -0.2886 0.026 Uiso 1 1 calc R . .
C3 C -0.3583(4) -0.1574(3) -0.1814(3) 0.0213(9) Uani 1 1 d . . .
H3 H -0.4168 -0.1960 -0.1558 0.026 Uiso 1 1 calc R . .
C4 C -0.2146(4) 0.0039(3) -0.1873(3) 0.0180(9) Uani 1 1 d . . .
H4 H -0.1736 0.0780 -0.1660 0.022 Uiso 1 1 calc R . .
C5 C -0.2943(4) -0.0488(3) -0.1440(3) 0.0163(9) Uani 1 1 d . . .
C6 C -0.3053(4) 0.0091(3) -0.0600(3) 0.0170(9) Uani 1 1 d . . .
C7 C -0.3538(4) -0.0444(3) -0.0071(3) 0.0193(9) Uani 1 1 d . . .
H7 H -0.3850 -0.1181 -0.0264 0.023 Uiso 1 1 calc R . .
C8 C -0.2620(4) 0.1168(3) -0.0291(3) 0.0194(9) Uani 1 1 d . . .
H8 H -0.2304 0.1553 -0.0640 0.023 Uiso 1 1 calc R . .
C9 C -0.3563(4) 0.0094(3) 0.0725(3) 0.0218(10) Uani 1 1 d . . .
H9 H -0.3904 -0.0276 0.1077 0.026 Uiso 1 1 calc R . .
C10 C -0.2648(4) 0.1679(3) 0.0515(3) 0.0190(9) Uani 1 1 d . . .
H10 H -0.2340 0.2416 0.0724 0.023 Uiso 1 1 calc R . .
C11 C -0.3024(4) 0.1707(4) 0.1919(3) 0.0227(10) Uani 1 1 d . . .
H11A H -0.3772 0.1277 0.2088 0.027 Uiso 1 1 calc R . .
H11B H -0.3094 0.2371 0.1964 0.027 Uiso 1 1 calc R . .
C12 C -0.1670(4) 0.1920(3) 0.2509(2) 0.0184(9) Uani 1 1 d . . .
C13 C -0.1547(5) 0.1179(4) 0.2849(3) 0.0223(10) Uani 1 1 d . . .
H13 H -0.2328 0.0589 0.2788 0.027 Uiso 1 1 calc R . .
C14 C -0.0541(4) 0.2821(3) 0.2667(2) 0.0204(9) Uani 1 1 d . . .
H14 H -0.0631 0.3352 0.2475 0.024 Uiso 1 1 calc R . .
C15 C -0.0272(5) 0.1313(4) 0.3277(3) 0.0231(10) Uani 1 1 d . . .
H15 H -0.0192 0.0806 0.3506 0.028 Uiso 1 1 calc R . .
C16 C 0.0731(4) 0.2946(3) 0.3110(2) 0.0195(9) Uani 1 1 d . . .
C17 C 0.0890(4) 0.2163(3) 0.3381(2) 0.0204(10) Uani 1 1 d . . .
C18 C 0.2252(5) 0.2149(4) 0.3687(3) 0.0273(11) Uani 1 1 d . . .
H18A H 0.2965 0.2872 0.3968 0.033 Uiso 1 1 calc R . .
H18B H 0.2237 0.1802 0.4116 0.033 Uiso 1 1 calc R . .
C19 C 0.2862(4) 0.4582(4) 0.3974(3) 0.0247(10) Uani 1 1 d . . .
H19 H 0.3032 0.4532 0.4530 0.030 Uiso 1 1 calc R . .
C20 C 0.3577(5) 0.5371(4) 0.3739(3) 0.0279(11) Uani 1 1 d . . .
C21 C 0.4805(5) 0.6358(4) 0.4267(3) 0.0333(12) Uani 1 1 d . . .
H21A H 0.4882 0.6869 0.3975 0.040 Uiso 1 1 calc R . .
H21B H 0.4699 0.6656 0.4837 0.040 Uiso 1 1 calc R . .
C22 C 0.6303(6) 0.5857(4) 0.3599(3) 0.0374(12) Uani 1 1 d . . .
H22A H 0.6523 0.6416 0.3355 0.045 Uiso 1 1 calc R . .
H22B H 0.5494 0.5242 0.3176 0.045 Uiso 1 1 calc R . .
C23 C 0.7460(6) 0.5575(5) 0.3762(4) 0.0413(13) Uani 1 1 d . . .
H23A H 0.7730 0.5406 0.3231 0.050 Uiso 1 1 calc R . .
H23B H 0.8246 0.6169 0.4226 0.050 Uiso 1 1 calc R . .
C24 C 0.7952(6) 0.4206(5) 0.3967(4) 0.0496(16) Uani 1 1 d . . .
H24A H 0.8893 0.4743 0.4264 0.060 Uiso 1 1 calc R . .
H24B H 0.7870 0.3874 0.3353 0.060 Uiso 1 1 calc R . .
C25 C 0.7663(11) 0.3428(7) 0.4361(4) 0.074(3) Uani 1 1 d . . .
H25A H 0.8372 0.3165 0.4378 0.089 Uiso 1 1 calc R . .
H25B H 0.7691 0.3754 0.4965 0.089 Uiso 1 1 calc R . .
C26 C 0.6441(8) 0.1838(7) 0.4342(5) 0.071(2) Uani 1 1 d . . .
H26A H 0.7153 0.1600 0.4249 0.085 Uiso 1 1 calc R . .
H26B H 0.6577 0.2137 0.4970 0.085 Uiso 1 1 calc R . .
C27 C 0.5204(10) 0.1080(8) 0.3921(7) 0.125(5) Uani 1 1 d . . .
H27A H 0.5220 0.0408 0.3913 0.150 Uiso 1 1 calc R . .
H27B H 0.4964 0.1039 0.3313 0.150 Uiso 1 1 calc R . .
C28 C 0.3730(9) 0.0886(7) 0.4988(5) 0.097(4) Uani 1 1 d D . .
H28A H 0.4284 0.0506 0.5097 0.116 Uiso 1 1 calc R . .
H28B H 0.4078 0.1526 0.5510 0.116 Uiso 1 1 calc R . .
C29 C 0.2559(11) 0.033(2) 0.4964(8) 0.281(16) Uani 1 1 d D . .
H29A H 0.2452 0.0690 0.5518 0.337 Uiso 1 1 calc R . .
H29B H 0.2589 -0.0322 0.5000 0.337 Uiso 1 1 calc R . .
C30 C 0.0569(12) -0.1026(9) 0.4169(5) 0.089(3) Uani 1 1 d . . .
H30A H 0.0442 -0.1134 0.4708 0.107 Uiso 1 1 calc R . .
H30B H 0.1035 -0.1448 0.3928 0.107 Uiso 1 1 calc R . .
C31 C -0.0702(10) -0.1360(6) 0.3569(6) 0.083(3) Uani 1 1 d . . .
H31A H -0.1307 -0.2064 0.3530 0.100 Uiso 1 1 calc R . .
H31B H -0.1113 -0.0878 0.3776 0.100 Uiso 1 1 calc R . .
C32 C -0.1964(9) -0.1774(5) 0.2168(5) 0.067(2) Uani 1 1 d . . .
H32A H -0.2564 -0.2441 0.2195 0.080 Uiso 1 1 calc R . .
H32B H -0.2342 -0.1258 0.2343 0.080 Uiso 1 1 calc R . .
C33 C -0.1881(7) -0.1926(5) 0.1297(4) 0.0593(19) Uani 1 1 d . . .
H33A H -0.2803 -0.2327 0.0880 0.071 Uiso 1 1 calc R . .
H33B H -0.1354 -0.2340 0.1169 0.071 Uiso 1 1 calc R . .
C34 C -0.0909(4) -0.0989(4) 0.0440(3) 0.0231(10) Uani 1 1 d . . .
C35 C -0.1178(5) -0.1907(4) -0.0206(3) 0.0290(11) Uani 1 1 d . . .
H35 H -0.1660 -0.2560 -0.0162 0.035 Uiso 1 1 calc R . .
C36 C -0.0214(4) -0.0005(3) 0.0371(3) 0.0182(9) Uani 1 1 d . . .
C37 C 0.0055(4) 0.0950(3) 0.1019(3) 0.0212(10) Uani 1 1 d . . .
H37 H -0.0240 0.0948 0.1515 0.025 Uiso 1 1 calc R . .
C38 C 0.0734(4) 0.1868(4) 0.0931(3) 0.0249(10) Uani 1 1 d . . .
H38 H 0.0914 0.2503 0.1372 0.030 Uiso 1 1 calc R . .
N1 N -0.2553(3) -0.1567(3) -0.2921(2) 0.0202(8) Uani 1 1 d . . .
N2 N -0.3112(3) 0.1137(3) 0.1013(2) 0.0181(8) Uani 1 1 d . . .
N3 N 0.1854(4) 0.3880(3) 0.3242(2) 0.0221(8) Uani 1 1 d . . .
N4 N 0.1947(4) 0.4236(3) 0.2574(2) 0.0281(9) Uani 1 1 d . . .
N5 N 0.2991(4) 0.5136(3) 0.2881(3) 0.0315(10) Uani 1 1 d . . .
O1 O 0.6028(3) 0.6210(3) 0.4395(2) 0.0301(8) Uani 1 1 d . . .
O2 O 0.7045(4) 0.4689(3) 0.4018(2) 0.0429(10) Uani 1 1 d . . .
O3 O 0.6381(7) 0.2580(4) 0.3907(4) 0.0743(17) Uani 1 1 d . . .
O4 O 0.4041(4) 0.1218(3) 0.4321(2) 0.0412(10) Uani 1 1 d . . .
O5 O 0.1363(5) 0.0023(6) 0.4355(3) 0.0786(19) Uani 1 1 d . . .
O6 O -0.0597(6) -0.1394(4) 0.2749(3) 0.0757(17) Uani 1 1 d . . .
O7 O -0.1244(3) -0.0939(3) 0.1185(2) 0.0320(8) Uani 1 1 d . . .
C101 C 0.6294(5) 0.3676(4) 0.1211(3) 0.0286(11) Uani 1 1 d . . .
C102 C 0.5798(8) 0.4458(5) 0.1022(5) 0.066(2) Uani 1 1 d . . .
C103 C 0.5077(5) 0.8961(4) 0.2466(3) 0.0342(12) Uani 1 1 d . . .
C104 C 0.3819(8) 0.8078(6) 0.2433(5) 0.077(3) Uani 1 1 d . . .
C105 C 0.0707(7) 0.4215(5) 0.0313(4) 0.0516(16) Uani 1 1 d . . .
C106 C 0.2104(7) 0.4969(6) 0.0645(5) 0.066(2) Uani 1 1 d . . .
H10A H 0.2627 0.4718 0.0303 0.099 Uiso 1 1 calc R . .
H10B H 0.2471 0.5066 0.1251 0.099 Uiso 1 1 calc R . .
H10C H 0.2161 0.5637 0.0606 0.099 Uiso 1 1 calc R . .
C107 C 0.0569(7) 0.6249(7) 0.2999(5) 0.071(2) Uani 1 1 d . . .
C108 C 0.0316(8) 0.5978(7) 0.2128(5) 0.077(2) Uani 1 1 d . . .
H10D H 0.0994 0.5753 0.1954 0.115 Uiso 1 1 calc R . .
H10E H 0.0360 0.6581 0.1969 0.115 Uiso 1 1 calc R . .
H10F H -0.0588 0.5404 0.1833 0.115 Uiso 1 1 calc R . .
O101 O 0.5421(4) 0.2774(3) 0.0882(3) 0.0463(10) Uani 1 1 d . . .
O102 O 0.7472(4) 0.4014(3) 0.1666(3) 0.0485(11) Uani 1 1 d . . .
O103 O 0.4882(4) 0.9389(3) 0.1955(2) 0.0356(9) Uani 1 1 d . . .
O104 O 0.6107(4) 0.9176(3) 0.3029(3) 0.0517(11) Uani 1 1 d . . .
F101 F 0.4877(8) 0.4530(7) 0.1408(4) 0.148(3) Uani 1 1 d . . .
F102 F 0.5188(6) 0.4177(4) 0.0191(3) 0.105(2) Uani 1 1 d . . .
F103 F 0.6733(8) 0.5407(3) 0.1298(5) 0.160(4) Uani 1 1 d . . .
F104 F 0.2811(5) 0.7655(4) 0.1734(3) 0.098(2) Uani 1 1 d . . .
F105 F 0.3328(8) 0.8406(9) 0.3070(4) 0.233(7) Uani 1 1 d . . .
F106 F 0.4002(9) 0.7351(6) 0.2617(7) 0.224(6) Uani 1 1 d . . .
N101 N -0.0392(7) 0.3613(5) 0.0045(4) 0.0715(19) Uani 1 1 d . . .
N102 N 0.0774(10) 0.6479(13) 0.3716(6) 0.185(7) Uani 1 1 d . . .
loop_
_atom_site_aniso_label
_atom_site_aniso_U_11
_atom_site_aniso_U_22
_atom_site_aniso_U_33
_atom_site_aniso_U_23
_atom_site_aniso_U_13
_atom_site_aniso_U_12
C1 0.015(2) 0.023(2) 0.022(2) -0.0003(18) -0.0032(18) 0.0097(17)
C2 0.021(2) 0.032(2) 0.012(2) 0.0047(17) -0.0022(17) 0.0168(19)
C3 0.0099(19) 0.030(2) 0.021(2) 0.0059(18) -0.0007(17) 0.0104(17)
C4 0.017(2) 0.027(2) 0.0111(19) 0.0045(16) -0.0012(16) 0.0157(18)
C5 0.0087(18) 0.025(2) 0.0134(19) 0.0028(16) -0.0032(15) 0.0121(16)
C6 0.0075(18) 0.031(2) 0.014(2) 0.0067(17) -0.0017(15) 0.0130(17)
C7 0.0074(18) 0.029(2) 0.019(2) 0.0047(17) 0.0003(16) 0.0093(17)
C8 0.0135(19) 0.028(2) 0.013(2) 0.0039(17) -0.0035(16) 0.0120(17)
C9 0.013(2) 0.031(2) 0.020(2) 0.0072(18) 0.0012(17) 0.0105(18)
C10 0.0112(19) 0.029(2) 0.018(2) 0.0066(17) 0.0025(16) 0.0122(17)
C11 0.019(2) 0.038(2) 0.014(2) 0.0056(18) 0.0059(17) 0.0178(19)
C12 0.019(2) 0.029(2) 0.0068(18) -0.0007(16) 0.0013(16) 0.0169(18)
C13 0.024(2) 0.030(2) 0.013(2) 0.0023(17) 0.0047(18) 0.0159(19)
C14 0.027(2) 0.027(2) 0.0079(19) -0.0015(16) 0.0012(17) 0.0200(19)
C15 0.030(2) 0.034(2) 0.012(2) 0.0056(17) 0.0059(18) 0.023(2)
C16 0.023(2) 0.028(2) 0.0057(18) -0.0018(16) 0.0027(16) 0.0154(19)
C17 0.024(2) 0.032(2) 0.0063(18) -0.0012(16) 0.0008(16) 0.0209(19)
C18 0.028(2) 0.040(3) 0.010(2) -0.0024(18) -0.0038(18) 0.025(2)
C19 0.023(2) 0.034(2) 0.012(2) -0.0015(18) -0.0024(17) 0.017(2)
C20 0.024(2) 0.031(2) 0.019(2) 0.0008(19) -0.0030(19) 0.011(2)
C21 0.027(3) 0.034(3) 0.028(3) -0.001(2) 0.001(2) 0.014(2)
C22 0.038(3) 0.046(3) 0.027(3) 0.011(2) 0.010(2) 0.018(2)
C23 0.039(3) 0.054(3) 0.033(3) 0.012(3) 0.015(2) 0.022(3)
C24 0.051(3) 0.061(4) 0.034(3) -0.002(3) 0.006(3) 0.038(3)
C25 0.145(8) 0.082(5) 0.039(4) 0.023(4) 0.042(5) 0.090(6)
C26 0.068(5) 0.096(6) 0.055(4) 0.020(4) 0.007(4) 0.053(5)
C27 0.105(7) 0.115(7) 0.120(8) -0.033(6) -0.051(6) 0.106(7)
C28 0.082(6) 0.105(6) 0.049(4) 0.052(4) -0.036(4) -0.012(5)
C29 0.074(7) 0.62(4) 0.114(10) 0.252(18) 0.001(7) 0.029(14)
C30 0.149(9) 0.141(9) 0.054(5) 0.065(5) 0.057(6) 0.113(8)
C31 0.110(7) 0.062(5) 0.082(6) 0.050(4) 0.030(5) 0.021(5)
C32 0.094(6) 0.046(4) 0.061(4) 0.021(3) 0.040(4) 0.021(4)
C33 0.056(4) 0.048(4) 0.046(4) 0.013(3) 0.018(3) -0.007(3)
C34 0.014(2) 0.035(2) 0.014(2) 0.0059(18) -0.0019(17) 0.0096(18)
C35 0.025(2) 0.032(2) 0.021(2) 0.0050(19) -0.0033(19) 0.010(2)
C36 0.0082(18) 0.030(2) 0.0130(19) 0.0013(17) -0.0030(15) 0.0125(17)
C37 0.017(2) 0.032(2) 0.013(2) -0.0004(17) -0.0039(16) 0.0181(19)
C38 0.024(2) 0.029(2) 0.016(2) -0.0031(18) -0.0035(18) 0.017(2)
N1 0.0187(18) 0.032(2) 0.0087(16) -0.0003(14) -0.0050(14) 0.0193(16)
N2 0.0109(16) 0.033(2) 0.0095(16) 0.0031(14) -0.0003(13) 0.0141(15)
N3 0.0216(18) 0.030(2) 0.0120(17) -0.0001(15) -0.0016(14) 0.0163(16)
N4 0.029(2) 0.029(2) 0.0150(18) 0.0034(16) -0.0032(16) 0.0089(17)
N5 0.033(2) 0.032(2) 0.021(2) 0.0036(17) -0.0041(17) 0.0140(18)
O1 0.0235(17) 0.0363(18) 0.0205(16) 0.0026(14) 0.0003(13) 0.0105(14)
O2 0.054(2) 0.060(2) 0.031(2) 0.0152(18) 0.0199(18) 0.040(2)
O3 0.137(5) 0.064(3) 0.083(4) 0.044(3) 0.084(4) 0.073(4)
O4 0.0309(19) 0.049(2) 0.043(2) 0.0191(18) -0.0025(16) 0.0215(17)
O5 0.045(3) 0.155(6) 0.048(3) 0.062(3) 0.024(2) 0.031(3)
O6 0.093(4) 0.048(3) 0.058(3) 0.026(2) -0.016(3) 0.012(3)
O7 0.0255(17) 0.045(2) 0.0179(16) 0.0091(14) 0.0051(14) 0.0090(15)
C101 0.033(3) 0.030(3) 0.021(2) 0.0047(19) 0.011(2) 0.014(2)
C102 0.082(5) 0.053(4) 0.047(4) 0.000(3) -0.010(4) 0.039(4)
C103 0.041(3) 0.035(3) 0.021(2) 0.008(2) -0.002(2) 0.017(2)
C104 0.073(5) 0.069(5) 0.048(4) 0.042(4) -0.023(4) -0.012(4)
C105 0.055(4) 0.045(3) 0.055(4) 0.018(3) 0.001(3) 0.028(3)
C106 0.057(4) 0.060(4) 0.070(5) 0.018(4) 0.001(4) 0.026(4)
C107 0.041(4) 0.113(7) 0.059(5) 0.035(4) 0.016(3) 0.028(4)
C108 0.057(4) 0.081(5) 0.061(5) 0.019(4) 0.011(4) 0.003(4)
O101 0.033(2) 0.038(2) 0.060(3) 0.0192(19) 0.0048(19) 0.0098(17)
O102 0.041(2) 0.038(2) 0.053(2) 0.0099(18) -0.0001(19) 0.0125(18)
O103 0.038(2) 0.043(2) 0.0269(18) 0.0176(16) 0.0086(15) 0.0154(17)
O104 0.043(2) 0.055(2) 0.045(2) 0.023(2) -0.0085(19) 0.0130(19)
F101 0.159(6) 0.220(8) 0.099(4) 0.007(5) 0.016(4) 0.166(7)
F102 0.148(5) 0.067(3) 0.074(3) 0.030(2) -0.031(3) 0.045(3)
F103 0.177(7) 0.030(2) 0.180(6) 0.007(3) -0.087(5) 0.030(3)
F104 0.073(3) 0.084(3) 0.072(3) 0.054(2) -0.037(2) -0.028(2)
F105 0.132(6) 0.291(12) 0.076(4) 0.035(6) 0.034(4) -0.108(8)
F106 0.161(7) 0.104(5) 0.286(11) 0.146(7) -0.127(7) -0.041(5)
N101 0.063(4) 0.050(3) 0.082(4) 0.025(3) -0.013(3) 0.018(3)
N102 0.077(6) 0.35(2) 0.072(6) 0.079(9) 0.015(5) 0.027(9)
_geom_special_details
;
All esds (except the esd in the dihedral angle between two l.s. planes)
are estimated using the full covariance matrix. The cell esds are taken
into account individually in the estimation of esds in distances, angles
and torsion angles; correlations between esds in cell parameters are only
used when they are defined by crystal symmetry. An approximate (isotropic)
treatment of cell esds is used for estimating esds involving l.s. planes.
;
loop_
_geom_bond_atom_site_label_1
_geom_bond_atom_site_label_2
_geom_bond_distance
_geom_bond_site_symmetry_2
_geom_bond_publ_flag
C1 N1 1.334(6) . ?
C1 C3 1.367(6) . ?
C1 H1 0.9500 . ?
C2 N1 1.353(6) . ?
C2 C4 1.371(6) . ?
C2 H2 0.9500 . ?
C3 C5 1.394(6) . ?
C3 H3 0.9500 . ?
C4 C5 1.403(6) . ?
C4 H4 0.9500 . ?
C5 C6 1.490(6) . ?
C6 C8 1.390(6) . ?
C6 C7 1.397(6) . ?
C7 C9 1.371(6) . ?
C7 H7 0.9500 . ?
C8 C10 1.375(6) . ?
C8 H8 0.9500 . ?
C9 N2 1.342(6) . ?
C9 H9 0.9500 . ?
C10 N2 1.352(6) . ?
C10 H10 0.9500 . ?
C11 N2 1.497(5) . ?
C11 C12 1.517(6) . ?
C11 H11A 0.9900 . ?
C11 H11B 0.9900 . ?
C12 C14 1.382(6) . ?
C12 C13 1.396(6) . ?
C13 C15 1.384(6) . ?
C13 H13 0.9500 . ?
C14 C16 1.395(6) . ?
C14 H14 0.9500 . ?
C15 C17 1.383(7) . ?
C15 H15 0.9500 . ?
C16 C17 1.400(6) . ?
C16 N3 1.418(6) . ?
C17 C18 1.515(6) . ?
C18 N1 1.505(5) 2 ?
C18 H18A 0.9900 . ?
C18 H18B 0.9900 . ?
C19 N3 1.356(5) . ?
C19 C20 1.357(7) . ?
C19 H19 0.9500 . ?
C20 N5 1.366(6) . ?
C20 C21 1.491(6) . ?
C21 O1 1.435(6) . ?
C21 H21A 0.9900 . ?
C21 H21B 0.9900 . ?
C22 O1 1.429(6) . ?
C22 C23 1.484(8) . ?
C22 H22A 0.9900 . ?
C22 H22B 0.9900 . ?
C23 O2 1.431(7) . ?
C23 H23A 0.9900 . ?
C23 H23B 0.9900 . ?
C24 O2 1.420(7) . ?
C24 C25 1.442(11) . ?
C24 H24A 0.9900 . ?
C24 H24B 0.9900 . ?
C25 O3 1.416(11) . ?
C25 H25A 0.9900 . ?
C25 H25B 0.9900 . ?
C26 C27 1.331(12) . ?
C26 O3 1.481(9) . ?
C26 H26A 0.9900 . ?
C26 H26B 0.9900 . ?
C27 O4 1.605(11) . ?
C27 H27A 0.9900 . ?
C27 H27B 0.9900 . ?
C28 C29 1.252(12) . ?
C28 O4 1.391(8) . ?
C28 H28A 0.9900 . ?
C28 H28B 0.9900 . ?
C29 O5 1.361(11) . ?
C29 H29A 0.9900 . ?
C29 H29B 0.9900 . ?
C30 O5 1.388(12) . ?
C30 C31 1.407(13) . ?
C30 H30A 0.9900 . ?
C30 H30B 0.9900 . ?
C31 O6 1.396(10) . ?
C31 H31A 0.9900 . ?
C31 H31B 0.9900 . ?
C32 C33 1.449(9) . ?
C32 O6 1.464(10) . ?
C32 H32A 0.9900 . ?
C32 H32B 0.9900 . ?
C33 O7 1.453(7) . ?
C33 H33A 0.9900 . ?
C33 H33B 0.9900 . ?
C34 O7 1.362(5) . ?
C34 C35 1.377(7) . ?
C34 C36 1.425(7) . ?
C35 C38 1.404(7) 2 ?
C35 H35 0.9500 . ?
C36 C36 1.417(9) 2 ?
C36 C37 1.417(6) . ?
C37 C38 1.356(7) . ?
C37 H37 0.9500 . ?
C38 C35 1.404(7) 2 ?
C38 H38 0.9500 . ?
N1 C18 1.505(5) 2 ?
N3 N4 1.370(5) . ?
N4 N5 1.300(6) . ?
C101 O101 1.227(6) . ?
C101 O102 1.232(6) . ?
C101 C102 1.518(9) . ?
C102 F103 1.301(9) . ?
C102 F102 1.318(8) . ?
C102 F101 1.324(11) . ?
C103 O104 1.224(6) . ?
C103 O103 1.227(6) . ?
C103 C104 1.512(9) . ?
C104 F106 1.260(10) . ?
C104 F104 1.290(7) . ?
C104 F105 1.341(14) . ?
C105 N101 1.139(9) . ?
C105 C106 1.443(10) . ?
C106 H10A 0.9800 . ?
C106 H10B 0.9800 . ?
C106 H10C 0.9800 . ?
C107 N102 1.118(11) . ?
C107 C108 1.360(11) . ?
C108 H10D 0.9800 . ?
C108 H10E 0.9800 . ?
C108 H10F 0.9800 . ?
loop_
_geom_angle_atom_site_label_1
_geom_angle_atom_site_label_2
_geom_angle_atom_site_label_3
_geom_angle
_geom_angle_site_symmetry_1
_geom_angle_site_symmetry_3
_geom_angle_publ_flag
N1 C1 C3 121.3(4) . . ?
N1 C1 H1 119.3 . . ?
C3 C1 H1 119.3 . . ?
N1 C2 C4 120.4(4) . . ?
N1 C2 H2 119.8 . . ?
C4 C2 H2 119.8 . . ?
C1 C3 C5 120.4(4) . . ?
C1 C3 H3 119.8 . . ?
C5 C3 H3 119.8 . . ?
C2 C4 C5 120.4(4) . . ?
C2 C4 H4 119.8 . . ?
C5 C4 H4 119.8 . . ?
C3 C5 C4 116.9(4) . . ?
C3 C5 C6 121.8(4) . . ?
C4 C5 C6 121.2(4) . . ?
C8 C6 C7 117.6(4) . . ?
C8 C6 C5 122.4(4) . . ?
C7 C6 C5 119.9(4) . . ?
C9 C7 C6 120.1(4) . . ?
C9 C7 H7 120.0 . . ?
C6 C7 H7 120.0 . . ?
C10 C8 C6 120.4(4) . . ?
C10 C8 H8 119.8 . . ?
C6 C8 H8 119.8 . . ?
N2 C9 C7 120.9(4) . . ?
N2 C9 H9 119.5 . . ?
C7 C9 H9 119.5 . . ?
N2 C10 C8 120.3(4) . . ?
N2 C10 H10 119.8 . . ?
C8 C10 H10 119.8 . . ?
N2 C11 C12 107.7(3) . . ?
N2 C11 H11A 110.2 . . ?
C12 C11 H11A 110.2 . . ?
N2 C11 H11B 110.2 . . ?
C12 C11 H11B 110.2 . . ?
H11A C11 H11B 108.5 . . ?
C14 C12 C13 119.9(4) . . ?
C14 C12 C11 120.0(4) . . ?
C13 C12 C11 120.0(4) . . ?
C15 C13 C12 119.2(4) . . ?
C15 C13 H13 120.4 . . ?
C12 C13 H13 120.4 . . ?
C12 C14 C16 119.7(4) . . ?
C12 C14 H14 120.2 . . ?
C16 C14 H14 120.2 . . ?
C17 C15 C13 122.1(4) . . ?
C17 C15 H15 118.9 . . ?
C13 C15 H15 118.9 . . ?
C14 C16 C17 121.1(4) . . ?
C14 C16 N3 117.0(4) . . ?
C17 C16 N3 121.8(4) . . ?
C15 C17 C16 117.5(4) . . ?
C15 C17 C18 119.0(4) . . ?
C16 C17 C18 123.2(4) . . ?
N1 C18 C17 109.0(3) 2 . ?
N1 C18 H18A 109.9 2 . ?
C17 C18 H18A 109.9 . . ?
N1 C18 H18B 109.9 2 . ?
C17 C18 H18B 109.9 . . ?
H18A C18 H18B 108.3 . . ?
N3 C19 C20 105.0(4) . . ?
N3 C19 H19 127.5 . . ?
C20 C19 H19 127.5 . . ?
C19 C20 N5 108.7(4) . . ?
C19 C20 C21 129.7(4) . . ?
N5 C20 C21 121.6(5) . . ?
O1 C21 C20 113.0(4) . . ?
O1 C21 H21A 109.0 . . ?
C20 C21 H21A 109.0 . . ?
O1 C21 H21B 109.0 . . ?
C20 C21 H21B 109.0 . . ?
H21A C21 H21B 107.8 . . ?
O1 C22 C23 109.1(4) . . ?
O1 C22 H22A 109.9 . . ?
C23 C22 H22A 109.9 . . ?
O1 C22 H22B 109.9 . . ?
C23 C22 H22B 109.9 . . ?
H22A C22 H22B 108.3 . . ?
O2 C23 C22 108.0(5) . . ?
O2 C23 H23A 110.1 . . ?
C22 C23 H23A 110.1 . . ?
O2 C23 H23B 110.1 . . ?
C22 C23 H23B 110.1 . . ?
H23A C23 H23B 108.4 . . ?
O2 C24 C25 110.9(6) . . ?
O2 C24 H24A 109.5 . . ?
C25 C24 H24A 109.5 . . ?
O2 C24 H24B 109.5 . . ?
C25 C24 H24B 109.5 . . ?
H24A C24 H24B 108.0 . . ?
O3 C25 C24 112.1(6) . . ?
O3 C25 H25A 109.2 . . ?
C24 C25 H25A 109.2 . . ?
O3 C25 H25B 109.2 . . ?
C24 C25 H25B 109.2 . . ?
H25A C25 H25B 107.9 . . ?
C27 C26 O3 98.8(7) . . ?
C27 C26 H26A 112.0 . . ?
O3 C26 H26A 112.0 . . ?
C27 C26 H26B 112.0 . . ?
O3 C26 H26B 112.0 . . ?
H26A C26 H26B 109.7 . . ?
C26 C27 O4 114.9(7) . . ?
C26 C27 H27A 108.5 . . ?
O4 C27 H27A 108.5 . . ?
C26 C27 H27B 108.5 . . ?
O4 C27 H27B 108.5 . . ?
H27A C27 H27B 107.5 . . ?
C29 C28 O4 124.1(6) . . ?
C29 C28 H28A 106.3 . . ?
O4 C28 H28A 106.3 . . ?
C29 C28 H28B 106.3 . . ?
O4 C28 H28B 106.3 . . ?
H28A C28 H28B 106.4 . . ?
C28 C29 O5 128.7(9) . . ?
C28 C29 H29A 105.1 . . ?
O5 C29 H29A 105.1 . . ?
C28 C29 H29B 105.1 . . ?
O5 C29 H29B 105.1 . . ?
H29A C29 H29B 105.9 . . ?
O5 C30 C31 110.9(6) . . ?
O5 C30 H30A 109.5 . . ?
C31 C30 H30A 109.5 . . ?
O5 C30 H30B 109.5 . . ?
C31 C30 H30B 109.5 . . ?
H30A C30 H30B 108.1 . . ?
O6 C31 C30 111.7(8) . . ?
O6 C31 H31A 109.3 . . ?
C30 C31 H31A 109.3 . . ?
O6 C31 H31B 109.3 . . ?
C30 C31 H31B 109.3 . . ?
H31A C31 H31B 107.9 . . ?
C33 C32 O6 108.1(6) . . ?
C33 C32 H32A 110.1 . . ?
O6 C32 H32A 110.1 . . ?
C33 C32 H32B 110.1 . . ?
O6 C32 H32B 110.1 . . ?
H32A C32 H32B 108.4 . . ?
C32 C33 O7 111.8(5) . . ?
C32 C33 H33A 109.3 . . ?
O7 C33 H33A 109.3 . . ?
C32 C33 H33B 109.3 . . ?
O7 C33 H33B 109.3 . . ?
H33A C33 H33B 107.9 . . ?
O7 C34 C35 124.0(4) . . ?
O7 C34 C36 115.2(4) . . ?
C35 C34 C36 120.8(4) . . ?
C34 C35 C38 119.3(5) . 2 ?
C34 C35 H35 120.4 . . ?
C38 C35 H35 120.4 2 . ?
C36 C36 C37 119.6(5) 2 . ?
C36 C36 C34 118.4(5) 2 . ?
C37 C36 C34 121.9(4) . . ?
C38 C37 C36 119.9(4) . . ?
C38 C37 H37 120.1 . . ?
C36 C37 H37 120.1 . . ?
C37 C38 C35 122.0(4) . 2 ?
C37 C38 H38 119.0 . . ?
C35 C38 H38 119.0 2 . ?
C1 N1 C2 120.4(4) . . ?
C1 N1 C18 120.5(4) . 2 ?
C2 N1 C18 119.1(4) . 2 ?
C9 N2 C10 120.6(4) . . ?
C9 N2 C11 119.3(4) . . ?
C10 N2 C11 119.9(4) . . ?
C19 N3 N4 110.0(4) . . ?
C19 N3 C16 130.4(4) . . ?
N4 N3 C16 119.3(3) . . ?
N5 N4 N3 107.0(3) . . ?
N4 N5 C20 109.4(4) . . ?
C22 O1 C21 112.0(4) . . ?
C24 O2 C23 111.2(5) . . ?
C25 O3 C26 101.1(6) . . ?
C28 O4 C27 123.6(7) . . ?
C29 O5 C30 109.4(11) . . ?
C31 O6 C32 107.8(7) . . ?
C34 O7 C33 116.5(4) . . ?
O101 C101 O102 129.2(5) . . ?
O101 C101 C102 113.1(5) . . ?
O102 C101 C102 117.7(5) . . ?
F103 C102 F102 108.6(7) . . ?
F103 C102 F101 104.9(7) . . ?
F102 C102 F101 105.0(7) . . ?
F103 C102 C101 114.3(6) . . ?
F102 C102 C101 112.4(5) . . ?
F101 C102 C101 111.0(7) . . ?
O104 C103 O103 130.2(5) . . ?
O104 C103 C104 115.4(5) . . ?
O103 C103 C104 114.3(5) . . ?
F106 C104 F104 107.4(7) . . ?
F106 C104 F105 99.1(9) . . ?
F104 C104 F105 105.1(9) . . ?
F106 C104 C103 115.6(8) . . ?
F104 C104 C103 117.1(5) . . ?
F105 C104 C103 110.5(7) . . ?
N101 C105 C106 179.3(9) . . ?
C105 C106 H10A 109.5 . . ?
C105 C106 H10B 109.5 . . ?
H10A C106 H10B 109.5 . . ?
C105 C106 H10C 109.5 . . ?
H10A C106 H10C 109.5 . . ?
H10B C106 H10C 109.5 . . ?
N102 C107 C108 179.3(14) . . ?
C107 C108 H10D 109.5 . . ?
C107 C108 H10E 109.5 . . ?
H10D C108 H10E 109.5 . . ?
C107 C108 H10F 109.5 . . ?
H10D C108 H10F 109.5 . . ?
H10E C108 H10F 109.5 . . ?
loop_
_geom_torsion_atom_site_label_1
_geom_torsion_atom_site_label_2
_geom_torsion_atom_site_label_3
_geom_torsion_atom_site_label_4
_geom_torsion
_geom_torsion_site_symmetry_1
_geom_torsion_site_symmetry_2
_geom_torsion_site_symmetry_3
_geom_torsion_site_symmetry_4
_geom_torsion_publ_flag
N1 C1 C3 C5 0.3(6) . . . . ?
N1 C2 C4 C5 1.1(6) . . . . ?
C1 C3 C5 C4 3.1(6) . . . . ?
C1 C3 C5 C6 -174.6(4) . . . . ?
C2 C4 C5 C3 -3.8(5) . . . . ?
C2 C4 C5 C6 173.9(3) . . . . ?
C3 C5 C6 C8 -168.8(4) . . . . ?
C4 C5 C6 C8 13.6(5) . . . . ?
C3 C5 C6 C7 14.7(5) . . . . ?
C4 C5 C6 C7 -162.9(4) . . . . ?
C8 C6 C7 C9 -0.6(5) . . . . ?
C5 C6 C7 C9 176.0(3) . . . . ?
C7 C6 C8 C10 1.4(5) . . . . ?
C5 C6 C8 C10 -175.2(3) . . . . ?
C6 C7 C9 N2 -0.7(6) . . . . ?
C6 C8 C10 N2 -0.8(6) . . . . ?
N2 C11 C12 C14 88.4(5) . . . . ?
N2 C11 C12 C13 -87.7(5) . . . . ?
C14 C12 C13 C15 -5.7(6) . . . . ?
C11 C12 C13 C15 170.4(4) . . . . ?
C13 C12 C14 C16 4.9(6) . . . . ?
C11 C12 C14 C16 -171.2(4) . . . . ?
C12 C13 C15 C17 0.2(6) . . . . ?
C12 C14 C16 C17 1.4(6) . . . . ?
C12 C14 C16 N3 179.1(3) . . . . ?
C13 C15 C17 C16 5.9(6) . . . . ?
C13 C15 C17 C18 -167.5(4) . . . . ?
C14 C16 C17 C15 -6.7(6) . . . . ?
N3 C16 C17 C15 175.7(4) . . . . ?
C14 C16 C17 C18 166.4(4) . . . . ?
N3 C16 C17 C18 -11.2(6) . . . . ?
C15 C17 C18 N1 83.8(5) . . . 2 ?
C16 C17 C18 N1 -89.3(5) . . . 2 ?
N3 C19 C20 N5 0.2(5) . . . . ?
N3 C19 C20 C21 -179.5(5) . . . . ?
C19 C20 C21 O1 78.8(7) . . . . ?
N5 C20 C21 O1 -100.9(6) . . . . ?
O1 C22 C23 O2 66.1(5) . . . . ?
O2 C24 C25 O3 65.4(6) . . . . ?
O3 C26 C27 O4 -86.2(9) . . . . ?
O4 C28 C29 O5 -7(4) . . . . ?
O5 C30 C31 O6 69.5(9) . . . . ?
O6 C32 C33 O7 -71.5(8) . . . . ?
O7 C34 C35 C38 -177.1(4) . . . 2 ?
C36 C34 C35 C38 1.4(6) . . . 2 ?
O7 C34 C36 C36 177.6(4) . . . 2 ?
C35 C34 C36 C36 -1.1(7) . . . 2 ?
O7 C34 C36 C37 -2.5(6) . . . . ?
C35 C34 C36 C37 178.9(4) . . . . ?
C36 C36 C37 C38 -0.8(7) 2 . . . ?
C34 C36 C37 C38 179.2(4) . . . . ?
C36 C37 C38 C35 0.5(6) . . . 2 ?
C3 C1 N1 C2 -3.1(6) . . . . ?
C3 C1 N1 C18 175.3(4) . . . 2 ?
C4 C2 N1 C1 2.4(6) . . . . ?
C4 C2 N1 C18 -176.0(3) . . . 2 ?
C7 C9 N2 C10 1.4(6) . . . . ?
C7 C9 N2 C11 -173.8(3) . . . . ?
C8 C10 N2 C9 -0.6(6) . . . . ?
C8 C10 N2 C11 174.5(3) . . . . ?
C12 C11 N2 C9 85.7(4) . . . . ?
C12 C11 N2 C10 -89.6(4) . . . . ?
C20 C19 N3 N4 -0.2(5) . . . . ?
C20 C19 N3 C16 -174.0(4) . . . . ?
C14 C16 N3 C19 129.4(5) . . . . ?
C17 C16 N3 C19 -52.9(6) . . . . ?
C14 C16 N3 N4 -43.9(5) . . . . ?
C17 C16 N3 N4 133.8(4) . . . . ?
C19 N3 N4 N5 0.2(5) . . . . ?
C16 N3 N4 N5 174.8(4) . . . . ?
N3 N4 N5 C20 -0.1(5) . . . . ?
C19 C20 N5 N4 -0.1(6) . . . . ?
C21 C20 N5 N4 179.7(4) . . . . ?
C23 C22 O1 C21 -171.9(4) . . . . ?
C20 C21 O1 C22 63.3(6) . . . . ?
C25 C24 O2 C23 170.3(5) . . . . ?
C22 C23 O2 C24 164.7(4) . . . . ?
C24 C25 O3 C26 170.9(5) . . . . ?
C27 C26 O3 C25 177.5(7) . . . . ?
C29 C28 O4 C27 -129(2) . . . . ?
C26 C27 O4 C28 -85.6(11) . . . . ?
C28 C29 O5 C30 136(3) . . . . ?
C31 C30 O5 C29 177.4(11) . . . . ?
C30 C31 O6 C32 178.6(7) . . . . ?
C33 C32 O6 C31 -173.5(6) . . . . ?
C35 C34 O7 C33 2.2(7) . . . . ?
C36 C34 O7 C33 -176.4(5) . . . . ?
C32 C33 O7 C34 169.3(6) . . . . ?
O101 C101 C102 F103 -174.2(7) . . . . ?
O102 C101 C102 F103 6.5(10) . . . . ?
O101 C101 C102 F102 -49.8(9) . . . . ?
O102 C101 C102 F102 130.9(7) . . . . ?
O101 C101 C102 F101 67.5(7) . . . . ?
O102 C101 C102 F101 -111.9(7) . . . . ?
O104 C103 C104 F106 -34.8(12) . . . . ?
O103 C103 C104 F106 149.3(9) . . . . ?
O104 C103 C104 F104 -163.1(8) . . . . ?
O103 C103 C104 F104 21.0(11) . . . . ?
O104 C103 C104 F105 76.7(10) . . . . ?
O103 C103 C104 F105 -99.2(8) . . . . ?
_diffrn_measured_fraction_theta_max 0.961
_diffrn_reflns_theta_full 64.94
_diffrn_measured_fraction_theta_full 0.961
_refine_diff_density_max 1.693
_refine_diff_density_min -0.992
_refine_diff_density_rms 0.109
# start Validation Reply Form
_vrf_PLAT213_I
;
PROBLEM: Atom C5 has ADP max/min Ratio ..... 5.1 oblat
RESPONSE: The atoms of the glycol chain and of the CBPQT4+ ring showed elongated
displacement parameters. Attempts to model this disorder did not significantly
improve the refinement.
;
_vrf_PLAT222_I
;
PROBLEM: Large Non-Solvent H Uiso(max)/Uiso(min) .. 10.0 Ratio
RESPONSE: Hydrogen atoms were refined as riding models with their isotropic
displacement parameters linked to their parent atoms.
In this case the parent atom exhibits disorder with an elongated
displacement parameter and therefore the riding hydrogen atom is also large.
;
_vrf_PLAT241_I
;
PROBLEM: Check High Ueq as Compared to Neighbors for C27
RESPONSE: C27 and C29 are part of the disordered glycol chain, however they
are bonded to C26 and O5 which are relatively well-ordered parts of the
structure.
;
# end Validation Reply Form

806
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "0.2.8",
"version": "0.4.2",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -15,11 +15,11 @@
"test": "npm run lint && jest",
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
"build-tsc": "tsc",
"build-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html}\" lib/",
"build-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/",
"build-webpack": "webpack --mode production",
"watch": "concurrently --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack\"",
"watch-tsc": "tsc -watch",
"watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html}\" lib/ --watch",
"watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/ --watch",
"watch-webpack": "webpack -w --mode development --display minimal",
"serve": "http-server -p 1338",
"model-server": "node lib/servers/model/server.js",
@@ -65,7 +65,7 @@
"devDependencies": {
"benchmark": "^2.1.4",
"circular-dependency-plugin": "^5.2.0",
"concurrently": "^4.1.2",
"concurrently": "^5.0.0",
"cpx": "^1.5.0",
"css-loader": "^3.2.0",
"extra-watch-webpack-plugin": "^1.0.3",
@@ -78,40 +78,39 @@
"jest": "^24.9.0",
"jest-raw-loader": "^1.0.1",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.12.0",
"node-sass": "^4.13.0",
"raw-loader": "^3.1.0",
"resolve-url-loader": "^3.1.0",
"sass-loader": "^7.3.1",
"simple-git": "^1.124.0",
"resolve-url-loader": "^3.1.1",
"sass-loader": "^8.0.0",
"simple-git": "^1.126.0",
"style-loader": "^1.0.0",
"ts-jest": "^24.0.2",
"tslint": "^5.19.0",
"typescript": "^3.5.3",
"webpack": "^4.39.2",
"webpack-cli": "^3.3.7"
"ts-jest": "^24.1.0",
"tslint": "^5.20.1",
"typescript": "^3.7.2",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
},
"dependencies": {
"@types/argparse": "^1.0.36",
"@types/benchmark": "^1.0.31",
"@types/compression": "1.0.1",
"@types/express": "^4.17.1",
"@types/jest": "^24.0.18",
"@types/node": "^12.7.2",
"@types/node-fetch": "^2.5.0",
"@types/react": "^16.9.2",
"@types/react-dom": "^16.9.0",
"@types/express": "^4.17.2",
"@types/jest": "^24.0.23",
"@types/node": "^12.12.9",
"@types/node-fetch": "^2.5.3",
"@types/react": "^16.9.11",
"@types/react-dom": "^16.9.4",
"@types/swagger-ui-dist": "3.0.3",
"@types/webgl2": "0.0.5",
"argparse": "^1.0.10",
"compression": "^1.7.4",
"express": "^4.17.1",
"graphql": "^14.4.2",
"graphql": "^14.5.8",
"immutable": "^3.8.2",
"node-fetch": "^2.6.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"rxjs": "^6.5.2",
"swagger-ui-dist": "^3.23.5",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"rxjs": "^6.5.3",
"swagger-ui-dist": "^3.24.3",
"util.promisify": "^1.0.0",
"xhr2": "^0.2.0"
}

View File

@@ -19,4 +19,12 @@ export class BasicWrapperControls extends PluginUIComponent {
<TransformUpdaterControl nodeRef='ihm-visual' header={{ name: 'I/HM Visual' }} initiallyCollapsed={true} />
</div>;
}
}
export class CustomToastMessage extends PluginUIComponent {
render() {
return <>
Custom <i>Toast</i> content. No timeout.
</>;
}
}

View File

@@ -105,10 +105,18 @@
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
addHeader('Interactivity');
addControl('Highlight seq_id=7', () => BasicMolStarWrapper.interactivity.highlightOn());
addControl('Clear Highlight', () => BasicMolStarWrapper.interactivity.clearHighlight());
addHeader('Tests');
addControl('Static Superposition', () => BasicMolStarWrapper.tests.staticSuperposition());
addControl('Dynamic Superposition', () => BasicMolStarWrapper.tests.dynamicSuperposition());
addControl('Validation Tooltip', () => BasicMolStarWrapper.tests.toggleValidationTooltip());
addControl('Show Toasts', () => BasicMolStarWrapper.tests.showToasts());
addControl('Hide Toasts', () => BasicMolStarWrapper.tests.hideToasts());
////////////////////////////////////////////////////////

View File

@@ -11,12 +11,16 @@ import { PluginCommands } from '../../mol-plugin/command';
import { StateTransforms } from '../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
import { Color } from '../../mol-util/color';
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin/state/objects';
import { AnimateModelIndex } from '../../mol-plugin/state/animation/built-in';
import { StateBuilder, StateTransform } from '../../mol-state';
import { StripedResidues } from './coloring';
// import { BasicWrapperControls } from './controls';
import { StaticSuperpositionTestData, buildStaticSuperposition, dynamicSuperpositionTest } from './superposition';
import { PDBeStructureQualityReport } from '../../mol-plugin/behavior/dynamic/custom-props';
import { CustomToastMessage } from './controls';
import { EmptyLoci } from '../../mol-model/loci';
import { StructureSelection } from '../../mol-model/structure';
import { Script } from '../../mol-script/script';
require('mol-plugin/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb'
@@ -61,7 +65,7 @@ class BasicWrapper {
}
private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: 'seq' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'), { ref: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
@@ -142,6 +146,22 @@ class BasicWrapper {
}
}
interactivity = {
highlightOn: () => {
const seq_id = 7;
const data = (this.plugin.state.dataState.select('asm')[0].obj as PluginStateObject.Molecule.Structure).data;
const sel = Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
'residue-test': Q.core.rel.eq([Q.struct.atomProperty.macromolecular.label_seq_id(), seq_id]),
'group-by': Q.struct.atomProperty.macromolecular.residueKey()
}), data);
const loci = StructureSelection.toLociWithSourceUnits(sel);
this.plugin.interactivity.lociHighlights.highlightOnly({ loci });
},
clearHighlight: () => {
this.plugin.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
}
}
tests = {
staticSuperposition: async () => {
const state = this.plugin.state.dataState;
@@ -152,6 +172,28 @@ class BasicWrapper {
dynamicSuperposition: async () => {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.plugin.state.dataState, ref: StateTransform.RootRef });
await dynamicSuperpositionTest(this.plugin, ['1tqn', '2hhb', '4hhb'], 'HEM');
},
toggleValidationTooltip: async () => {
const state = this.plugin.state.behaviorState;
const tree = state.build().to(PDBeStructureQualityReport.id).update(PDBeStructureQualityReport, p => ({ ...p, showTooltip: !p.showTooltip }));
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
},
showToasts: () => {
PluginCommands.Toast.Show.dispatch(this.plugin, {
title: 'Toast 1',
message: 'This is an example text, timeout 3s',
key: 'toast-1',
timeoutMs: 3000
});
PluginCommands.Toast.Show.dispatch(this.plugin, {
title: 'Toast 2',
message: CustomToastMessage,
key: 'toast-2'
});
},
hideToasts: () => {
PluginCommands.Toast.Hide.dispatch(this.plugin, { key: 'toast-1' });
PluginCommands.Toast.Hide.dispatch(this.plugin, { key: 'toast-2' });
}
}
}

View File

@@ -86,7 +86,7 @@ export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[]
const query = compile<StructureSelection>(pivot);
const xs = state.select(StateSelection.Generators.rootsOfType(PSO.Molecule.Structure));
const selections = xs.map(s => StructureSelection.toLoci(query(new QueryContext(s.obj!.data))));
const selections = xs.map(s => StructureSelection.toLociWithCurrentUnits(query(new QueryContext(s.obj!.data))));
const transforms = superposeStructures(selections);
const visuals = state.build();

View File

@@ -15,6 +15,7 @@ import { OrderedSet } from '../../mol-data/int';
import { openCif, downloadCif } from './helpers';
import { Vec3 } from '../../mol-math/linear-algebra';
import { trajectoryFromMmCIF } from '../../mol-model-formats/structure/mmcif';
import { Sequence } from '../../mol-model/sequence';
async function downloadFromPdb(pdb: string) {
@@ -110,9 +111,10 @@ export function printSequence(model: Model) {
console.log('\nSequence\n=============');
const { byEntityKey } = model.sequence;
for (const key of Object.keys(byEntityKey)) {
const seq = byEntityKey[+key];
console.log(`${seq.entityId} (${seq.sequence.kind} ${seq.num.value(0)} (offset ${seq.sequence.offset}), ${seq.num.value(seq.num.rowCount - 1)}) (${seq.compId.value(0)}, ${seq.compId.value(seq.compId.rowCount - 1)})`);
console.log(`${seq.sequence.sequence}`);
const { sequence, entityId } = byEntityKey[+key];
const { seqId, compId } = sequence
console.log(`${entityId} (${sequence.kind} ${seqId.value(0)} (offset ${sequence.offset}), ${seqId.value(seqId.rowCount - 1)}) (${compId.value(0)}, ${compId.value(compId.rowCount - 1)})`);
console.log(`${Sequence.getSequenceString(sequence)}`);
}
console.log();
}
@@ -159,14 +161,14 @@ export function printUnits(structure: Structure) {
console.log(`Coarse unit ${unit.id} ${unit.conformation.operator.name} (${Unit.isSpheres(l.unit) ? 'spheres' : 'gaussians'}): ${size} elements.`);
const props = StructureProperties.coarse;
const seq = l.unit.model.sequence;
const modelSeq = l.unit.model.sequence;
for (let j = 0, _j = Math.min(size, 3); j < _j; j++) {
l.element = OrderedSet.getAt(elements, j);
const residues: string[] = [];
const start = props.seq_id_begin(l), end = props.seq_id_end(l);
const compId = seq.byEntityKey[props.entityKey(l)].compId.value;
const compId = modelSeq.byEntityKey[props.entityKey(l)].sequence.compId.value;
for (let e = start; e <= end; e++) residues.push(compId(e));
console.log(`${props.asym_id(l)}:${start}-${end} (${residues.join('-')}) ${props.asym_id(l)} [${props.x(l).toFixed(2)}, ${props.y(l).toFixed(2)}, ${props.z(l).toFixed(2)}]`);
}

View File

@@ -10,7 +10,7 @@ import { PluginStateObject as PSO } from '../../../../mol-plugin/state/objects';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { Ingredient, CellPacking, Cell } from './data';
import { getFromPdb, getFromCellPackDB } from './util';
import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext } from '../../../../mol-model/structure';
import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext, Unit } from '../../../../mol-model/structure';
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';
@@ -268,7 +268,7 @@ export function createStructureFromCellPack(packing: CellPacking, baseUrl: strin
for (const u of s.units) {
const invariantId = u.invariantId + offsetInvariantId
if (u.invariantId > maxInvariantId) maxInvariantId = u.invariantId
builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, invariantId)
builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, Unit.Trait.None, invariantId)
}
offsetInvariantId += maxInvariantId
}
@@ -297,7 +297,7 @@ export const LoadCellPackModel = StateAction.build({
['spacefill', 'Spacefill'],
['gaussian-surface', 'Gaussian Surface'],
['point', 'Point'],
])
] as ['spacefill' | 'gaussian-surface' | 'point', string][])
}, { isExpanded: true })
},
from: PSO.Root
@@ -385,17 +385,17 @@ export const LoadCellPackModel = StateAction.build({
const hue = [Math.max(0, hcl[0] - 35), Math.min(360, hcl[0] + 35)] as [number, number]
const p = { packing: i, baseUrl: params.baseUrl }
const expression = params.preset.traceOnly
? MS.struct.generator.atomGroups({
let cellpackTree = tree.apply(StructureFromCellpack, p)
if (params.preset.traceOnly) {
const expression = MS.struct.generator.atomGroups({
'atom-test': MS.core.logic.or([
MS.core.rel.eq([MS.ammp('label_atom_id'), 'CA']),
MS.core.rel.eq([MS.ammp('label_atom_id'), 'P'])
])
})
: MS.struct.generator.all()
tree.apply(StructureFromCellpack, p)
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression }, { state: { isGhost: true } })
cellpackTree = cellpackTree.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression }, { state: { isGhost: true } })
}
cellpackTree
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.createParams(ctx, Structure.Empty, {
repr: getReprParams(ctx, params.preset),

View File

@@ -138,23 +138,19 @@ function buildSnapshot(plugin: PluginContext, template: { tree: StateTree, struc
}
function getCameraSnapshot(e: JoleculeSnapshot['camera']): Camera.Snapshot {
const direction = Vec3.sub(Vec3.zero(), e.pos, e.in);
const direction = Vec3.sub(Vec3(), e.pos, e.in);
Vec3.normalize(direction, direction);
const up = Vec3.sub(Vec3.zero(), e.pos, e.up);
const up = Vec3.sub(Vec3(), e.pos, e.up);
Vec3.normalize(up, up);
const s: Camera.Snapshot = {
mode: 'perspective',
position: Vec3.scaleAndAdd(Vec3.zero(), e.pos, direction, e.slab.zoom),
target: e.pos,
direction,
up,
near: e.slab.zoom + e.slab.z_front,
far: e.slab.zoom + e.slab.z_back,
fogNear: e.slab.zoom + e.slab.z_front,
fogFar: e.slab.zoom + e.slab.z_back,
fov: Math.PI / 4,
zoom: 1
position: Vec3.scaleAndAdd(Vec3(), e.pos, direction, e.slab.zoom),
target: e.pos,
radius: (e.slab.z_back - e.slab.z_front) / 2,
fog: 50,
up,
};
return s;
}

BIN
src/apps/viewer/favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="icon" href="./favicon.ico" type="image/x-icon">
<title>Mol* Viewer</title>
<style>
* {

View File

@@ -7,6 +7,7 @@
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
import './index.html'
import './favicon.ico'
import { PluginContext } from '../../mol-plugin/context';
import { PluginCommands } from '../../mol-plugin/command';
import { PluginSpec } from '../../mol-plugin/spec';

View File

@@ -27,7 +27,7 @@ export const EvolutionaryConservation = CustomElementProperty.create<number>({
name: 'proteopedia-wrapper-evolutionary-conservation',
display: 'Evolutionary Conservation',
async getData(model: Model) {
const id = model.label.toLowerCase();
const id = model.entryId.toLowerCase();
const req = await fetch(`https://proteopedia.org/cgi-bin/cnsrf?${id}`);
const json = await req.json();
const annotations = (json && json.residueAnnotations) || [];

View File

@@ -1,3 +1,9 @@
== v3.4 ==
* Fixed HET group reset.
* Updated core.
* Removed Camera Cliping.
== v3.3 ==
* Camera Clipping.

View File

@@ -18,9 +18,9 @@ export interface ModelInfo {
export namespace ModelInfo {
async function getPreferredAssembly(ctx: PluginContext, model: Model) {
if (model.label.length <= 3) return void 0;
if (model.entryId.length <= 3) return void 0;
try {
const id = model.label.toLowerCase();
const id = model.entryId.toLowerCase();
const src = await ctx.runTask(ctx.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/${id}` })) as string;
const json = JSON.parse(src);
const data = json && json[id];

View File

@@ -133,8 +133,8 @@
addControl('Reset Position', () => PluginWrapper.camera.resetPosition());
addControl('Toggle Spin', () => PluginWrapper.camera.toggleSpin());
// Same as "wheel icon" and Viewport options
addControl('Clip', () => PluginWrapper.viewport.setSettings({ clip: [33, 66] }));
addControl('Reset Clip', () => PluginWrapper.viewport.setSettings({ clip: [1, 100] }));
// addControl('Clip', () => PluginWrapper.viewport.setSettings({ clip: [33, 66] }));
// addControl('Reset Clip', () => PluginWrapper.viewport.setSettings({ clip: [1, 100] }));
addSeparator();

View File

@@ -28,7 +28,6 @@ import { BuiltInColorThemes } from '../../mol-theme/color';
import { BuiltInSizeThemes } from '../../mol-theme/size';
import { ColorNames } from '../../mol-util/color/names';
import { InitVolumeStreaming, CreateVolumeStreamingInfo } from '../../mol-plugin/behavior/dynamic/volume-streaming/transformers';
import { ParamDefinition } from '../../mol-util/param-definition';
import { DefaultCanvas3DParams, Canvas3DProps } from '../../mol-canvas3d/canvas3d';
// import { Vec3 } from 'mol-math/linear-algebra';
// import { ParamDefinition } from 'mol-util/param-definition';
@@ -37,7 +36,7 @@ require('../../mol-plugin/skin/light.scss')
class MolStarProteopediaWrapper {
static VERSION_MAJOR = 3;
static VERSION_MINOR = 3;
static VERSION_MINOR = 4;
private _ev = RxEventHelper.create();
@@ -315,9 +314,11 @@ class MolStarProteopediaWrapper {
experimentalData = {
init: async (parent: Element) => {
const asm = this.state.select(StateElements.Assembly)[0].obj!;
const params = ParamDefinition.getDefaultValues(InitVolumeStreaming.definition.params!(asm, this.plugin));
params.behaviorRef = StateElements.VolumeStreaming;
const params = InitVolumeStreaming.createDefaultParams(asm, this.plugin);
params.options.behaviorRef = StateElements.VolumeStreaming;
params.defaultView = 'box';
params.options.channelParams['fo-fc(+ve)'] = { wireframe: true };
params.options.channelParams['fo-fc(-ve)'] = { wireframe: true };
await this.plugin.runTask(this.state.applyAction(InitVolumeStreaming, params, StateElements.Assembly));
this.experimentalDataElement = parent;
volumeStreamingControls(this.plugin, parent);
@@ -335,7 +336,7 @@ class MolStarProteopediaWrapper {
hetGroups = {
reset: () => {
const update = this.state.build().delete(StateElements.HetGroupFocus);
const update = this.state.build().delete(StateElements.HetGroupFocusGroup);
PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
},

View File

@@ -28,9 +28,9 @@ function messageTree(root: Progress.Node, prefix = ''): string {
function createTask<T>(delayMs: number, r: T): Task<T> {
return Task.create('delayed value ' + r, async ctx => {
ctx.update('Processing delayed... ' + r, true);
ctx.update(`Processing delayed ${r} after ${delayMs}ms`, true);
await Scheduler.delay(delayMs);
if (ctx.shouldUpdate) await ctx.update({ message: 'hello from delayed... ' });
if (ctx.shouldUpdate) await ctx.update({ message: `hello from delayed ${r} ${delayMs}` });
return r;
}, () => console.log('On abort called ' + r));
}
@@ -63,7 +63,7 @@ export function testTree() {
const r = await c1 + await c2 + await c3;
if (ctx.shouldUpdate) await ctx.update({ message: 'Almost done...' });
return r + 1;
});
}, () => console.log('On abort O'));
}
export type ChunkedState = { i: number, current: number, total: number }
@@ -115,7 +115,7 @@ async function test() {
// const r = await Run(testTree(), abortingObserver, 250);
// console.log(r);
const m = await ms({ i: 10 }).run(logP);
const m = await testTree().run(abortingObserver, 50);
console.log(m);
} catch (e) {
console.error(e);

View File

@@ -1,56 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ColorTheme } from '../../mol-theme/color';
import { Color } from '../../mol-util/color';
export interface ColorThemeComponentProps {
colorTheme: ColorTheme<any>
}
export interface ColorThemeComponentState {
}
export class ColorThemeComponent extends React.Component<ColorThemeComponentProps, ColorThemeComponentState> {
state = {
}
render() {
const ct = this.props.colorTheme
return <div>
<span>Color Theme Info </span>
{ct.description ? <div><i>{ct.description}</i></div> : ''}
{
ct.legend && ct.legend.kind === 'scale-legend'
? <div
style={{
width: '100%',
height: '30px',
background: `linear-gradient(to right, ${ct.legend.colors.map(c => Color.toStyle(c)).join(', ')})`
}}
>
<span style={{float: 'left', padding: '6px', color: 'white', fontWeight: 'bold', backgroundColor: 'rgba(0, 0, 0, 0.2)'}}>{ct.legend.minLabel}</span>
<span style={{float: 'right', padding: '6px', color: 'white', fontWeight: 'bold', backgroundColor: 'rgba(0, 0, 0, 0.2)'}}>{ct.legend.maxLabel}</span>
</div>
: ct.legend && ct.legend.kind === 'table-legend'
? <div>
{ct.legend.table.map((value, i) => {
const [name, color] = value
return <div key={i} style={{minWidth: '60px', marginRight: '5px', display: 'inline-block'}}>
<div style={{width: '30px', height: '20px', backgroundColor: Color.toStyle(color), display: 'inline-block'}}></div>
{name}
</div>
})}
</div>
: ''
}
</div>;
}
}

View File

@@ -7,17 +7,11 @@
import { Mat4, Vec3, Vec4, EPSILON } from '../mol-math/linear-algebra'
import { Viewport, cameraProject, cameraUnproject } from './camera/util';
import { Object3D } from '../mol-gl/object3d';
import { BehaviorSubject } from 'rxjs';
import { CameraTransitionManager } from './camera/transition';
export { Camera }
// TODO: slab controls that modify near/far planes?
class Camera implements Object3D {
readonly updatedViewProjection = new BehaviorSubject<Camera>(this);
class Camera {
readonly view: Mat4 = Mat4.identity();
readonly projection: Mat4 = Mat4.identity();
readonly projectionView: Mat4 = Mat4.identity();
@@ -32,14 +26,17 @@ class Camera implements Object3D {
width: 1, height: 1
}
near = 1
far = 10000
fogNear = 5000
fogFar = 10000
zoom = 1
readonly transition: CameraTransitionManager = new CameraTransitionManager(this);
get position() { return this.state.position; }
set position(v: Vec3) { Vec3.copy(this.state.position, v); }
get direction() { return this.state.direction; }
set direction(v: Vec3) { Vec3.copy(this.state.direction, v); }
get up() { return this.state.up; }
set up(v: Vec3) { Vec3.copy(this.state.up, v); }
@@ -51,10 +48,12 @@ class Camera implements Object3D {
private deltaDirection = Vec3.zero();
private newPosition = Vec3.zero();
updateMatrices() {
update() {
const snapshot = this.state as Camera.Snapshot;
const height = 2 * Math.tan(snapshot.fov / 2) * Vec3.distance(snapshot.position, snapshot.target);
snapshot.zoom = this.viewport.height / height;
this.zoom = this.viewport.height / height;
updateClip(this);
switch (this.state.mode) {
case 'orthographic': updateOrtho(this); break;
@@ -62,11 +61,7 @@ class Camera implements Object3D {
default: throw new Error('unknown camera mode');
}
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON.Value) || !Mat4.areEqual(this.view, this.prevView, EPSILON.Value);
Mat4.mul(this.projectionView, this.projection, this.view)
Mat4.invert(this.inverseProjectionView, this.projectionView)
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON) || !Mat4.areEqual(this.view, this.prevView, EPSILON);
if (changed) {
Mat4.mul(this.projectionView, this.projection, this.view)
@@ -74,57 +69,44 @@ class Camera implements Object3D {
Mat4.copy(this.prevView, this.view);
Mat4.copy(this.prevProjection, this.projection);
this.updatedViewProjection.next(this);
}
return changed;
}
setState(snapshot: Partial<Camera.Snapshot>) {
this.transition.apply(snapshot);
setState(snapshot: Partial<Camera.Snapshot>, durationMs?: number) {
this.transition.apply(snapshot, durationMs);
}
getSnapshot() {
const ret = Camera.createDefaultSnapshot();
Camera.copySnapshot(ret, this.state);
return ret;
return Camera.copySnapshot(Camera.createDefaultSnapshot(), this.state);
}
getFocus(target: Vec3, radius: number, dir?: Vec3): Partial<Camera.Snapshot> {
getFocus(target: Vec3, radius: number, up?: Vec3, dir?: Vec3): Partial<Camera.Snapshot> {
const fov = this.state.fov
const { width, height } = this.viewport
const aspect = width / height
const aspectFactor = (height < width ? 1 : aspect)
const currentDistance = Vec3.distance(this.state.position, target)
const targetDistance = Math.abs((radius / aspectFactor) / Math.sin(fov / 2))
const deltaDistance = Math.abs(currentDistance - targetDistance)
Vec3.sub(this.deltaDirection, this.target, this.position)
if (dir) Vec3.matchDirection(this.deltaDirection, dir, this.deltaDirection)
Vec3.setMagnitude(this.deltaDirection, this.deltaDirection, targetDistance)
Vec3.sub(this.newPosition, target, this.deltaDirection)
if (dir) {
Vec3.setMagnitude(this.deltaDirection, dir, targetDistance)
Vec3.add(this.newPosition, target, this.deltaDirection)
} else {
Vec3.setMagnitude(this.deltaDirection, this.state.direction, deltaDistance)
if (currentDistance < targetDistance) Vec3.negate(this.deltaDirection, this.deltaDirection)
Vec3.add(this.newPosition, this.state.position, this.deltaDirection)
}
const state = Camera.copySnapshot(Camera.createDefaultSnapshot(), this.state)
state.target = Vec3.clone(target)
state.radius = radius
state.position = Vec3.clone(this.newPosition)
if (up) Vec3.matchDirection(state.up, up, state.up)
return { target, position: Vec3.clone(this.newPosition) };
return state
}
focus(target: Vec3, radius: number, dir?: Vec3) {
if (radius > 0) this.setState(this.getFocus(target, radius, dir));
focus(target: Vec3, radius: number, durationMs?: number, up?: Vec3, dir?: Vec3) {
if (radius > 0) this.setState(this.getFocus(target, radius, up, dir), durationMs);
}
// lookAt(target: Vec3) {
// cameraLookAt(this.position, this.up, this.direction, target);
// }
// translate(v: Vec3) {
// Vec3.add(this.position, this.position, v);
// cameraLookAt(this.position, this.up, this.direction, this.target);
// }
project(out: Vec4, point: Vec3) {
return cameraProject(out, point, this.viewport, this.projectionView)
}
@@ -133,10 +115,6 @@ class Camera implements Object3D {
return cameraUnproject(out, point, this.viewport, this.inverseProjectionView)
}
dispose() {
this.updatedViewProjection.complete();
}
constructor(state?: Partial<Camera.Snapshot>, viewport = Viewport.create(-1, -1, 1, 1)) {
this.viewport = viewport;
Camera.copySnapshot(this.state, state);
@@ -147,13 +125,6 @@ class Camera implements Object3D {
namespace Camera {
export type Mode = 'perspective' | 'orthographic'
export interface ClippingInfo {
near: number,
far: number,
fogNear: number,
fogFar: number
}
/**
* Sets an offseted view in a larger frustum. This is useful for
* - multi-window or multi-monitor/multi-machine setups
@@ -181,64 +152,48 @@ namespace Camera {
export function createDefaultSnapshot(): Snapshot {
return {
mode: 'perspective',
fov: Math.PI / 4,
position: Vec3.create(0, 0, 100),
direction: Vec3.create(0, 0, 1),
up: Vec3.create(0, 1, 0),
target: Vec3.create(0, 0, 0),
near: 1,
far: 10000,
fogNear: 1,
fogFar: 10000,
fov: Math.PI / 4,
zoom: 1,
radius: 10,
fog: 50,
};
}
export interface Snapshot {
mode: Mode,
mode: Mode
fov: number
position: Vec3,
// Normalized camera direction
direction: Vec3,
up: Vec3,
target: Vec3,
position: Vec3
up: Vec3
target: Vec3
near: number,
far: number,
fogNear: number,
fogFar: number,
fov: number,
zoom: number,
radius: number
fog: number
}
export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) {
if (!source) return;
if (!source) return out;
if (typeof source.mode !== 'undefined') out.mode = source.mode;
if (typeof source.fov !== 'undefined') out.fov = source.fov;
if (typeof source.position !== 'undefined') Vec3.copy(out.position, source.position);
if (typeof source.direction !== 'undefined') Vec3.copy(out.direction, source.direction);
if (typeof source.up !== 'undefined') Vec3.copy(out.up, source.up);
if (typeof source.target !== 'undefined') Vec3.copy(out.target, source.target);
if (typeof source.near !== 'undefined') out.near = source.near;
if (typeof source.far !== 'undefined') out.far = source.far;
if (typeof source.fogNear !== 'undefined') out.fogNear = source.fogNear;
if (typeof source.fogFar !== 'undefined') out.fogFar = source.fogFar;
if (typeof source.radius !== 'undefined') out.radius = source.radius;
if (typeof source.fog !== 'undefined') out.fog = source.fog;
if (typeof source.fov !== 'undefined') out.fov = source.fov;
if (typeof source.zoom !== 'undefined') out.zoom = source.zoom;
return out;
}
}
const _center = Vec3.zero();
function updateOrtho(camera: Camera) {
const { viewport, state: { zoom, near, far }, viewOffset } = camera
const { viewport, zoom, near, far, viewOffset } = camera
const fullLeft = -(viewport.width - viewport.x) / 2
const fullRight = (viewport.width - viewport.x) / 2
@@ -270,16 +225,15 @@ function updateOrtho(camera: Camera) {
Mat4.ortho(camera.projection, left, right, top, bottom, near, far)
// build view matrix
Vec3.add(_center, camera.position, camera.direction)
Mat4.lookAt(camera.view, camera.position, _center, camera.up)
Mat4.lookAt(camera.view, camera.position, camera.target, camera.up)
}
function updatePers(camera: Camera) {
const aspect = camera.viewport.width / camera.viewport.height
const { state: { fov, near, far }, viewOffset } = camera
const { near, far, viewOffset } = camera
let top = near * Math.tan(0.5 * fov)
let top = near * Math.tan(0.5 * camera.state.fov)
let height = 2 * top
let width = aspect * height
let left = -0.5 * width
@@ -295,6 +249,33 @@ function updatePers(camera: Camera) {
Mat4.perspective(camera.projection, left, left + width, top, top - height, near, far)
// build view matrix
Vec3.add(_center, camera.position, camera.direction)
Mat4.lookAt(camera.view, camera.position, _center, camera.up)
Mat4.lookAt(camera.view, camera.position, camera.target, camera.up)
}
function updateClip(camera: Camera) {
const { radius, mode, fog } = camera.state
const cDist = Vec3.distance(camera.position, camera.target)
const bRadius = Math.max(1, radius)
let near = cDist - bRadius
let far = cDist + bRadius
const fogNearFactor = -(50 - fog) / 50
let fogNear = cDist - (bRadius * fogNearFactor)
let fogFar = cDist + bRadius
if (mode === 'perspective') {
// set at least to 5 to avoid slow sphere impostor rendering
near = Math.max(5, near)
far = Math.max(5, far)
} else {
near = Math.max(0, near)
far = Math.max(0, far)
}
camera.near = near;
camera.far = far;
camera.fogNear = fogNear;
camera.fogFar = fogFar;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 Mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
@@ -22,7 +22,7 @@ class CameraTransitionManager {
private current = Camera.createDefaultSnapshot();
apply(to: Partial<Camera.Snapshot>, durationMs: number = 0, transition?: CameraTransitionManager.TransitionFunc) {
if (durationMs <= 0 || to.mode !== this.camera.state.mode) {
if (durationMs <= 0 || (typeof to.mode !== 'undefined' && to.mode !== this.camera.state.mode)) {
this.finish(to);
return;
}
@@ -68,33 +68,21 @@ class CameraTransitionManager {
namespace CameraTransitionManager {
export type TransitionFunc = (out: Camera.Snapshot, t: number, source: Camera.Snapshot, target: Camera.Snapshot) => void
const _rot = Quat.identity();
export function defaultTransition(out: Camera.Snapshot, t: number, source: Camera.Snapshot, target: Camera.Snapshot): void {
Camera.copySnapshot(out, target);
// Rotate direction
const rot = Quat.identity();
Quat.slerp(rot, rot, Quat.rotationTo(Quat.zero(), source.direction, target.direction), t);
Vec3.transformQuat(out.direction, source.direction, rot);
// Rotate up
Quat.setIdentity(rot);
Quat.slerp(rot, rot, Quat.rotationTo(Quat.zero(), source.up, target.up), t);
Vec3.transformQuat(out.up, source.up, rot);
Quat.slerp(_rot, Quat.Identity, Quat.rotationTo(_rot, source.up, target.up), t);
Vec3.transformQuat(out.up, source.up, _rot);
// Lerp target
// Lerp target, position & radius
Vec3.lerp(out.target, source.target, target.target, t);
Vec3.lerp(out.position, source.position, target.position, t);
out.radius = lerp(source.radius, target.radius, t);
// Update position
const dist = -lerp(Vec3.distance(source.position, source.target), Vec3.distance(target.position, target.target), t);
Vec3.scale(out.position, out.direction, dist);
Vec3.add(out.position, out.position, out.target);
// Lerp other props
out.zoom = lerp(source.zoom, target.zoom, t);
// Lerp fov & fog
out.fov = lerp(source.fov, target.fov, t);
out.near = lerp(source.near, target.near, t);
out.far = lerp(source.far, target.far, t);
out.fogNear = lerp(source.fogNear, target.fogNear, t);
out.fogFar = lerp(source.fogFar, target.fogFar, t);
out.fog = lerp(source.fog, target.fog, t);
}
}

View File

@@ -4,7 +4,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Mat4, Vec3, Vec4, EPSILON } from '../../mol-math/linear-algebra'
import { Mat4, Vec3, Vec4 } from '../../mol-math/linear-algebra'
export { Viewport }
@@ -55,31 +55,6 @@ namespace Viewport {
//
const tmpVec3 = Vec3()
/** Modifies the direction & up vectors in place, both are normalized */
export function cameraLookAt(position: Vec3, up: Vec3, direction: Vec3, target: Vec3) {
Vec3.sub(tmpVec3, target, position)
Vec3.normalize(tmpVec3, tmpVec3)
if (!Vec3.isZero(tmpVec3)) {
// change direction vector to look at target
const d = Vec3.dot(tmpVec3, up)
if (Math.abs(d - 1) < EPSILON.Value) { // parallel
Vec3.scale(up, direction, -1)
} else if (Math.abs(d + 1) < EPSILON.Value) { // anti parallel
Vec3.copy(up, direction)
}
Vec3.copy(direction, tmpVec3)
// normalize up vector
Vec3.cross(tmpVec3, direction, up)
Vec3.normalize(tmpVec3, tmpVec3)
Vec3.cross(up, tmpVec3, direction)
Vec3.normalize(up, up)
}
}
const NEAR_RANGE = 0
const FAR_RANGE = 1

View File

@@ -32,14 +32,12 @@ import { readTexture } from '../mol-gl/compute/util';
import { DrawPass } from './passes/draw';
import { PickPass } from './passes/pick';
import { Task } from '../mol-task';
import { ImagePass, ImageProps } from './passes/image';
export const Canvas3DParams = {
// TODO: FPS cap?
// maxFps: PD.Numeric(30),
cameraMode: PD.Select('perspective', [['perspective', 'Perspective'], ['orthographic', 'Orthographic']]),
cameraClipDistance: PD.Numeric(0, { min: 0.0, max: 50.0, step: 0.1 }, { description: 'The distance between camera and scene at which to clip regardless of near clipping plane.' }),
clip: PD.Interval([1, 100], { min: 1, max: 100, step: 1 }),
fog: PD.Interval([50, 100], { min: 1, max: 100, step: 1 }),
cameraFog: PD.Numeric(50, { min: 1, max: 100, step: 1 }),
cameraResetDurationMs: PD.Numeric(250, { min: 0, max: 1000, step: 1 }, { description: 'The time it takes to reset the camera.' }),
multiSample: PD.Group(MultiSampleParams),
postprocessing: PD.Group(PostprocessingParams),
@@ -77,6 +75,7 @@ interface Canvas3D {
downloadScreenshot: () => void
getPixelData: (variant: GraphicsRenderVariant) => PixelData
setProps: (props: Partial<Canvas3DProps>) => void
getImagePass: () => ImagePass
/** Returns a copy of the current Canvas3D instance props */
readonly props: Readonly<Canvas3DProps>
@@ -91,15 +90,16 @@ const requestAnimationFrame = typeof window !== 'undefined' ? window.requestAnim
const DefaultRunTask = (task: Task<unknown>) => task.run()
namespace Canvas3D {
export interface HighlightEvent { current: Representation.Loci, modifiers?: ModifiersKeys }
export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
export function fromCanvas(canvas: HTMLCanvasElement, props: Partial<Canvas3DProps> = {}, runTask = DefaultRunTask) {
const gl = getGLContext(canvas, {
alpha: false,
alpha: true,
antialias: true,
depth: true,
preserveDrawingBuffer: true
preserveDrawingBuffer: true,
premultipliedAlpha: false,
})
if (gl === null) throw new Error('Could not create a WebGL rendering context')
const input = InputObserver.fromElement(canvas)
@@ -116,31 +116,31 @@ namespace Canvas3D {
const startTime = now()
const didDraw = new BehaviorSubject<now.Timestamp>(0 as now.Timestamp)
const camera = new Camera({
near: 0.1,
far: 10000,
position: Vec3.create(0, 0, 100),
mode: p.cameraMode
})
const webgl = createContext(gl)
let width = gl.drawingBufferWidth
let height = gl.drawingBufferHeight
const scene = Scene.create(webgl)
const camera = new Camera({
position: Vec3.create(0, 0, 100),
mode: p.cameraMode,
fog: p.cameraFog
})
const controls = TrackballControls.create(input, camera, p.trackball)
const renderer = Renderer.create(webgl, camera, p.renderer)
const renderer = Renderer.create(webgl, p.renderer)
const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug);
const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input);
const drawPass = new DrawPass(webgl, renderer, scene, debugHelper)
const pickPass = new PickPass(webgl, renderer, scene, 0.5)
const drawPass = new DrawPass(webgl, renderer, scene, camera, debugHelper)
const pickPass = new PickPass(webgl, renderer, scene, camera, 0.5)
const postprocessing = new PostprocessingPass(webgl, camera, drawPass, p.postprocessing)
const multiSample = new MultiSamplePass(webgl, camera, drawPass, postprocessing, p.multiSample)
let drawPending = false
let cameraResetRequested: boolean | Vec3 = false
let cameraResetRequested = false
function getLoci(pickingId: PickingId) {
let loci: Loci = EmptyLoci
@@ -148,7 +148,9 @@ namespace Canvas3D {
reprRenderObjects.forEach((_, _repr) => {
const _loci = _repr.getLoci(pickingId)
if (!isEmptyLoci(_loci)) {
if (!isEmptyLoci(loci)) console.warn('found another loci')
if (!isEmptyLoci(loci)) {
console.warn('found another loci, this should not happen')
}
loci = _loci
repr = _repr
}
@@ -172,47 +174,13 @@ namespace Canvas3D {
}
}
let currentNear = -1, currentFar = -1, currentFogNear = -1, currentFogFar = -1
function setClipping() {
const cDist = Vec3.distance(camera.state.position, camera.state.target)
const bRadius = Math.max(10, scene.boundingSphere.radius)
const nearFactor = (50 - p.clip[0]) / 50
const farFactor = -(50 - p.clip[1]) / 50
let near = cDist - (bRadius * nearFactor)
let far = cDist + (bRadius * farFactor)
const fogNearFactor = (50 - p.fog[0]) / 50
const fogFarFactor = -(50 - p.fog[1]) / 50
let fogNear = cDist - (bRadius * fogNearFactor)
let fogFar = cDist + (bRadius * fogFarFactor)
if (camera.state.mode === 'perspective') {
// set at least to 5 to avoid slow sphere impostor rendering
near = Math.max(5, p.cameraClipDistance, near)
far = Math.max(5, far)
fogNear = Math.max(5, fogNear)
fogFar = Math.max(5, fogFar)
} else if (camera.state.mode === 'orthographic') {
if (p.cameraClipDistance > 0) {
near = Math.max(p.cameraClipDistance, near)
}
}
if (near !== currentNear || far !== currentFar || fogNear !== currentFogNear || fogFar !== currentFogFar) {
camera.setState({ near, far, fogNear, fogFar })
currentNear = near, currentFar = far, currentFogNear = fogNear, currentFogFar = fogFar
}
}
function render(variant: 'pick' | 'draw', force: boolean) {
if (scene.isCommiting) return false
let didRender = false
controls.update(currentTime);
// TODO: is this a good fix? Also, setClipping does not work if the user has manually set a clipping plane.
if (!camera.transition.inTransition) setClipping();
const cameraChanged = camera.updateMatrices();
controls.update(currentTime)
Viewport.set(camera.viewport, 0, 0, width, height)
const cameraChanged = camera.update()
multiSample.update(force || cameraChanged, currentTime)
if (force || cameraChanged || multiSample.enabled) {
@@ -221,9 +189,9 @@ namespace Canvas3D {
pickPass.render()
break;
case 'draw':
renderer.setViewport(0, 0, width, height);
renderer.setViewport(0, 0, width, height)
if (multiSample.enabled) {
multiSample.render()
multiSample.render(true)
} else {
drawPass.render(!postprocessing.enabled)
if (postprocessing.enabled) postprocessing.render(true)
@@ -234,7 +202,7 @@ namespace Canvas3D {
didRender = true
}
return didRender && cameraChanged;
return didRender;
}
let forceNextDraw = false;
@@ -271,8 +239,7 @@ namespace Canvas3D {
runTask(scene.commit()).then(() => {
if (cameraResetRequested && !scene.isCommiting) {
const dir = typeof cameraResetRequested === 'boolean' ? undefined : cameraResetRequested
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius, dir)
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius)
cameraResetRequested = false
}
if (debugHelper.isEnabled) debugHelper.update()
@@ -345,11 +312,11 @@ namespace Canvas3D {
getLoci,
handleResize,
resetCamera: (dir?: Vec3) => {
resetCamera: () => {
if (scene.isCommiting) {
cameraResetRequested = dir || true
cameraResetRequested = true
} else {
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius, dir)
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius, p.cameraResetDurationMs)
requestDraw(true);
}
},
@@ -372,9 +339,10 @@ namespace Canvas3D {
if (props.cameraMode !== undefined && props.cameraMode !== camera.state.mode) {
camera.setState({ mode: props.cameraMode })
}
if (props.cameraClipDistance !== undefined) p.cameraClipDistance = props.cameraClipDistance
if (props.clip !== undefined) p.clip = [props.clip[0], props.clip[1]]
if (props.fog !== undefined) p.fog = [props.fog[0], props.fog[1]]
if (props.cameraFog !== undefined && props.cameraFog !== camera.state.fog) {
camera.setState({ fog: props.cameraFog })
}
if (props.cameraResetDurationMs !== undefined) p.cameraResetDurationMs = props.cameraResetDurationMs
if (props.postprocessing) postprocessing.setProps(props.postprocessing)
if (props.multiSample) multiSample.setProps(props.multiSample)
@@ -383,13 +351,15 @@ namespace Canvas3D {
if (props.debug) debugHelper.setProps(props.debug)
requestDraw(true)
},
getImagePass: (props: Partial<ImageProps> = {}) => {
return new ImagePass(webgl, renderer, scene, camera, debugHelper, props)
},
get props() {
return {
cameraMode: camera.state.mode,
cameraClipDistance: p.cameraClipDistance,
clip: p.clip,
fog: p.fog,
cameraFog: camera.state.fog,
cameraResetDurationMs: p.cameraResetDurationMs,
postprocessing: { ...postprocessing.props },
multiSample: { ...multiSample.props },
@@ -413,7 +383,6 @@ namespace Canvas3D {
input.dispose()
controls.dispose()
renderer.dispose()
camera.dispose()
interactionHelper.dispose()
}
}

View File

@@ -9,10 +9,29 @@
*/
import { Quat, Vec2, Vec3, EPSILON } from '../../mol-math/linear-algebra';
import { cameraLookAt, Viewport } from '../camera/util';
import InputObserver, { DragInput, WheelInput, ButtonsType, PinchInput } from '../../mol-util/input/input-observer';
import { Object3D } from '../../mol-gl/object3d';
import { Viewport } from '../camera/util';
import InputObserver, { DragInput, WheelInput, PinchInput, ButtonsType, ModifiersKeys } from '../../mol-util/input/input-observer';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Camera } from '../camera';
import { absMax } from '../../mol-math/misc';
import { Binding } from '../../mol-util/binding';
const B = ButtonsType
const M = ModifiersKeys
const Trigger = Binding.Trigger
export const DefaultTrackballBindings = {
dragRotate: Binding([Trigger(B.Flag.Primary, M.create())], 'Rotate the 3D scene by dragging using ${triggers}'),
dragRotateZ: Binding([Trigger(B.Flag.Primary, M.create({ shift: true }))], 'Rotate the 3D scene around the z-axis by dragging using ${triggers}'),
dragPan: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Pan the 3D scene by dragging using ${triggers}'),
dragZoom: Binding.Empty,
dragFocus: Binding([Trigger(B.Flag.Forth, M.create())], 'Focus the 3D scene by dragging using ${triggers}'),
dragFocusZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Focus and zoom the 3D scene by dragging using ${triggers}'),
scrollZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Zoom the 3D scene by scrolling using ${triggers}'),
scrollFocus: Binding([Trigger(B.Flag.Auxilary, M.create({ shift: true }))], 'Focus the 3D scene by scrolling using ${triggers}'),
scrollFocusZoom: Binding.Empty,
}
export const TrackballControlsParams = {
noScroll: PD.Boolean(true, { isHidden: true }),
@@ -21,14 +40,16 @@ export const TrackballControlsParams = {
zoomSpeed: PD.Numeric(6.0, { min: 0.1, max: 10, step: 0.1 }),
panSpeed: PD.Numeric(0.8, { min: 0.1, max: 5, step: 0.1 }),
spin: PD.Boolean(false),
spin: PD.Boolean(false, { description: 'Spin the 3D scene around the x-axis in view space' }),
spinSpeed: PD.Numeric(1, { min: -100, max: 100, step: 1 }),
staticMoving: PD.Boolean(true, { isHidden: true }),
dynamicDampingFactor: PD.Numeric(0.2, {}, { isHidden: true }),
minDistance: PD.Numeric(0.01, {}, { isHidden: true }),
maxDistance: PD.Numeric(1e150, {}, { isHidden: true })
maxDistance: PD.Numeric(1e150, {}, { isHidden: true }),
bindings: PD.Value(DefaultTrackballBindings, { isHidden: true })
}
export type TrackballControlsProps = PD.Values<typeof TrackballControlsParams>
@@ -44,11 +65,10 @@ interface TrackballControls {
dispose: () => void
}
namespace TrackballControls {
export function create(input: InputObserver, object: Object3D & { target: Vec3 }, props: Partial<TrackballControlsProps> = {}): TrackballControls {
export function create(input: InputObserver, camera: Camera, props: Partial<TrackballControlsProps> = {}): TrackballControls {
const p = { ...PD.getDefaultValues(TrackballControlsParams), ...props }
const viewport: Viewport = { x: 0, y: 0, width: 0, height: 0 }
const target: Vec3 = object.target
const viewport = Viewport()
let disposed = false
@@ -60,91 +80,116 @@ namespace TrackballControls {
let _isInteracting = false;
// For internal use
const lastPosition = Vec3.zero()
const lastPosition = Vec3()
const _eye = Vec3.zero()
const _eye = Vec3()
const _movePrev = Vec2.zero()
const _moveCurr = Vec2.zero()
const _rotPrev = Vec2()
const _rotCurr = Vec2()
const _rotLastAxis = Vec3()
let _rotLastAngle = 0
const _lastAxis = Vec3.zero()
let _lastAngle = 0
const _zRotPrev = Vec2()
const _zRotCurr = Vec2()
let _zRotLastAngle = 0
const _zoomStart = Vec2.zero()
const _zoomEnd = Vec2.zero()
const _zoomStart = Vec2()
const _zoomEnd = Vec2()
const _panStart = Vec2.zero()
const _panEnd = Vec2.zero()
const _focusStart = Vec2()
const _focusEnd = Vec2()
const _panStart = Vec2()
const _panEnd = Vec2()
// Initial values for reseting
const target0 = Vec3.clone(target)
const position0 = Vec3.clone(object.position)
const up0 = Vec3.clone(object.up)
const target0 = Vec3.clone(camera.target)
const position0 = Vec3.clone(camera.position)
const up0 = Vec3.clone(camera.up)
const mouseOnScreenVec2 = Vec2.zero()
const mouseOnScreenVec2 = Vec2()
function getMouseOnScreen(pageX: number, pageY: number) {
Vec2.set(
return Vec2.set(
mouseOnScreenVec2,
(pageX - viewport.x) / viewport.width,
(pageY - viewport.y) / viewport.height
);
return mouseOnScreenVec2;
}
const mouseOnCircleVec2 = Vec2.zero()
const mouseOnCircleVec2 = Vec2()
function getMouseOnCircle(pageX: number, pageY: number) {
Vec2.set(
return Vec2.set(
mouseOnCircleVec2,
((pageX - viewport.width * 0.5 - viewport.x) / (viewport.width * 0.5)),
((viewport.height + 2 * (viewport.y - pageY)) / viewport.width) // screen.width intentional
(pageX - viewport.width * 0.5 - viewport.x) / (viewport.width * 0.5),
(viewport.height + 2 * (viewport.y - pageY)) / viewport.width // screen.width intentional
);
return mouseOnCircleVec2;
}
const rotAxis = Vec3.zero()
const rotQuat = Quat.zero()
const rotEyeDir = Vec3.zero()
const rotObjUpDir = Vec3.zero()
const rotObjSideDir = Vec3.zero()
const rotMoveDir = Vec3.zero()
const rotAxis = Vec3()
const rotQuat = Quat()
const rotEyeDir = Vec3()
const rotObjUpDir = Vec3()
const rotObjSideDir = Vec3()
const rotMoveDir = Vec3()
function rotateCamera() {
Vec3.set(rotMoveDir, _moveCurr[0] - _movePrev[0], _moveCurr[1] - _movePrev[1], 0);
let angle = Vec3.magnitude(rotMoveDir);
const dx = _rotCurr[0] - _rotPrev[0]
const dy = _rotCurr[1] - _rotPrev[1]
Vec3.set(rotMoveDir, dx, dy, 0);
const angle = Vec3.magnitude(rotMoveDir) * p.rotateSpeed;
if (angle) {
Vec3.copy(_eye, object.position)
Vec3.sub(_eye, _eye, target)
Vec3.sub(_eye, camera.position, camera.target)
Vec3.normalize(rotEyeDir, Vec3.copy(rotEyeDir, _eye))
Vec3.normalize(rotObjUpDir, Vec3.copy(rotObjUpDir, object.up))
Vec3.normalize(rotEyeDir, _eye)
Vec3.normalize(rotObjUpDir, camera.up)
Vec3.normalize(rotObjSideDir, Vec3.cross(rotObjSideDir, rotObjUpDir, rotEyeDir))
Vec3.setMagnitude(rotObjUpDir, rotObjUpDir, _moveCurr[1] - _movePrev[1])
Vec3.setMagnitude(rotObjSideDir, rotObjSideDir, _moveCurr[0] - _movePrev[0])
Vec3.add(rotMoveDir, Vec3.copy(rotMoveDir, rotObjUpDir), rotObjSideDir)
Vec3.setMagnitude(rotObjUpDir, rotObjUpDir, dy)
Vec3.setMagnitude(rotObjSideDir, rotObjSideDir, dx)
Vec3.add(rotMoveDir, rotObjUpDir, rotObjSideDir)
Vec3.normalize(rotAxis, Vec3.cross(rotAxis, rotMoveDir, _eye))
angle *= p.rotateSpeed;
Quat.setAxisAngle(rotQuat, rotAxis, angle)
Vec3.transformQuat(_eye, _eye, rotQuat)
Vec3.transformQuat(object.up, object.up, rotQuat)
Vec3.transformQuat(camera.up, camera.up, rotQuat)
Vec3.copy(_lastAxis, rotAxis)
_lastAngle = angle;
} else if (!p.staticMoving && _lastAngle) {
_lastAngle *= Math.sqrt(1.0 - p.dynamicDampingFactor);
Vec3.sub(_eye, Vec3.copy(_eye, object.position), target)
Quat.setAxisAngle(rotQuat, _lastAxis, _lastAngle)
Vec3.copy(_rotLastAxis, rotAxis)
_rotLastAngle = angle;
} else if (!p.staticMoving && _rotLastAngle) {
_rotLastAngle *= Math.sqrt(1.0 - p.dynamicDampingFactor);
Vec3.sub(_eye, camera.position, camera.target)
Quat.setAxisAngle(rotQuat, _rotLastAxis, _rotLastAngle)
Vec3.transformQuat(_eye, _eye, rotQuat)
Vec3.transformQuat(object.up, object.up, rotQuat)
Vec3.transformQuat(camera.up, camera.up, rotQuat)
}
Vec2.copy(_movePrev, _moveCurr)
Vec2.copy(_rotPrev, _rotCurr)
}
const zRotQuat = Quat()
function zRotateCamera() {
const dx = _zRotCurr[0] - _zRotPrev[0]
const dy = _zRotCurr[1] - _zRotPrev[1]
const angle = p.rotateSpeed * (-dx + dy) * -0.05
if (angle) {
Vec3.sub(_eye, camera.position, camera.target)
Quat.setAxisAngle(zRotQuat, _eye, angle)
Vec3.transformQuat(camera.up, camera.up, zRotQuat)
_zRotLastAngle = angle;
} else if (!p.staticMoving && _zRotLastAngle) {
_zRotLastAngle *= Math.sqrt(1.0 - p.dynamicDampingFactor);
Vec3.sub(_eye, camera.position, camera.target)
Quat.setAxisAngle(zRotQuat, _eye, _zRotLastAngle)
Vec3.transformQuat(camera.up, camera.up, zRotQuat)
}
Vec2.copy(_zRotPrev, _zRotCurr)
}
function zoomCamera() {
@@ -160,9 +205,23 @@ namespace TrackballControls {
}
}
const panMouseChange = Vec2.zero()
const panObjUp = Vec3.zero()
const panOffset = Vec3.zero()
function focusCamera() {
const factor = (_focusEnd[1] - _focusStart[1]) * p.zoomSpeed
if (factor !== 0.0) {
const radius = Math.max(1, camera.state.radius + 10 * factor)
camera.setState({ radius })
}
if (p.staticMoving) {
Vec2.copy(_focusStart, _focusEnd)
} else {
_focusStart[1] += (_focusEnd[1] - _focusStart[1]) * p.dynamicDampingFactor
}
}
const panMouseChange = Vec2()
const panObjUp = Vec3()
const panOffset = Vec3()
function panCamera() {
Vec2.sub(panMouseChange, Vec2.copy(panMouseChange, _panEnd), _panStart)
@@ -170,14 +229,14 @@ namespace TrackballControls {
if (Vec2.squaredMagnitude(panMouseChange)) {
Vec2.scale(panMouseChange, panMouseChange, Vec3.magnitude(_eye) * p.panSpeed)
Vec3.cross(panOffset, Vec3.copy(panOffset, _eye), object.up)
Vec3.cross(panOffset, Vec3.copy(panOffset, _eye), camera.up)
Vec3.setMagnitude(panOffset, panOffset, panMouseChange[0])
Vec3.setMagnitude(panObjUp, object.up, panMouseChange[1])
Vec3.setMagnitude(panObjUp, camera.up, panMouseChange[1])
Vec3.add(panOffset, panOffset, panObjUp)
Vec3.add(object.position, object.position, panOffset)
Vec3.add(target, target, panOffset)
Vec3.add(camera.position, camera.position, panOffset)
Vec3.add(camera.target, camera.target, panOffset)
if (p.staticMoving) {
Vec2.copy(_panStart, _panEnd)
@@ -193,14 +252,16 @@ namespace TrackballControls {
function checkDistances() {
if (Vec3.squaredMagnitude(_eye) > p.maxDistance * p.maxDistance) {
Vec3.setMagnitude(_eye, _eye, p.maxDistance)
Vec3.add(object.position, target, _eye)
Vec3.add(camera.position, camera.target, _eye)
Vec2.copy(_zoomStart, _zoomEnd)
Vec2.copy(_focusStart, _focusEnd)
}
if (Vec3.squaredMagnitude(_eye) < p.minDistance * p.minDistance) {
Vec3.setMagnitude(_eye, _eye, p.minDistance)
Vec3.add(object.position, target, _eye)
Vec3.add(camera.position, camera.target, _eye)
Vec2.copy(_zoomStart, _zoomEnd)
Vec2.copy(_focusStart, _focusEnd)
}
}
@@ -210,18 +271,19 @@ namespace TrackballControls {
if (lastUpdated === t) return;
if (p.spin) spin(t - lastUpdated);
Vec3.sub(_eye, object.position, target)
Vec3.sub(_eye, camera.position, camera.target)
rotateCamera()
zRotateCamera()
zoomCamera()
focusCamera()
panCamera()
Vec3.add(object.position, target, _eye)
Vec3.add(camera.position, camera.target, _eye)
checkDistances()
cameraLookAt(object.position, object.up, object.direction, target)
if (Vec3.squaredDistance(lastPosition, object.position) > EPSILON.Value) {
Vec3.copy(lastPosition, object.position)
if (Vec3.squaredDistance(lastPosition, camera.position) > EPSILON) {
Vec3.copy(lastPosition, camera.position)
}
lastUpdated = t;
@@ -229,53 +291,82 @@ namespace TrackballControls {
/** Reset object's vectors and the target vector to their initial values */
function reset() {
Vec3.copy(target, target0)
Vec3.copy(object.position, position0)
Vec3.copy(object.up, up0)
Vec3.copy(camera.target, target0)
Vec3.copy(camera.position, position0)
Vec3.copy(camera.up, up0)
Vec3.sub(_eye, object.position, target)
cameraLookAt(object.position, object.up, object.direction, target)
Vec3.copy(lastPosition, object.position)
Vec3.sub(_eye, camera.position, camera.target)
Vec3.copy(lastPosition, camera.position)
}
// listeners
function onDrag({ pageX, pageY, buttons, isStart }: DragInput) {
function onDrag({ pageX, pageY, buttons, modifiers, isStart }: DragInput) {
_isInteracting = true;
const dragRotate = Binding.match(p.bindings.dragRotate, buttons, modifiers)
const dragRotateZ = Binding.match(p.bindings.dragRotateZ, buttons, modifiers)
const dragPan = Binding.match(p.bindings.dragPan, buttons, modifiers)
const dragZoom = Binding.match(p.bindings.dragZoom, buttons, modifiers)
const dragFocus = Binding.match(p.bindings.dragFocus, buttons, modifiers)
const dragFocusZoom = Binding.match(p.bindings.dragFocusZoom, buttons, modifiers)
getMouseOnCircle(pageX, pageY)
getMouseOnScreen(pageX, pageY)
if (isStart) {
if (buttons === ButtonsType.Flag.Primary) {
Vec2.copy(_moveCurr, getMouseOnCircle(pageX, pageY))
Vec2.copy(_movePrev, _moveCurr)
} else if (buttons === ButtonsType.Flag.Auxilary) {
Vec2.copy(_zoomStart, getMouseOnScreen(pageX, pageY))
if (dragRotate) {
Vec2.copy(_rotCurr, mouseOnCircleVec2)
Vec2.copy(_rotPrev, _rotCurr)
}
if (dragRotateZ) {
Vec2.copy(_zRotCurr, mouseOnCircleVec2)
Vec2.copy(_zRotPrev, _zRotCurr)
}
if (dragZoom || dragFocusZoom) {
Vec2.copy(_zoomStart, mouseOnScreenVec2)
Vec2.copy(_zoomEnd, _zoomStart)
} else if (buttons === ButtonsType.Flag.Secondary) {
Vec2.copy(_panStart, getMouseOnScreen(pageX, pageY))
}
if (dragFocus) {
Vec2.copy(_focusStart, mouseOnScreenVec2)
Vec2.copy(_focusEnd, _focusStart)
}
if (dragPan) {
Vec2.copy(_panStart, mouseOnScreenVec2)
Vec2.copy(_panEnd, _panStart)
}
}
if (buttons === ButtonsType.Flag.Primary) {
Vec2.copy(_moveCurr, getMouseOnCircle(pageX, pageY))
} else if (buttons === ButtonsType.Flag.Auxilary) {
Vec2.copy(_zoomEnd, getMouseOnScreen(pageX, pageY))
} else if (buttons === ButtonsType.Flag.Secondary) {
Vec2.copy(_panEnd, getMouseOnScreen(pageX, pageY))
if (dragRotate) Vec2.copy(_rotCurr, mouseOnCircleVec2)
if (dragRotateZ) Vec2.copy(_zRotCurr, mouseOnCircleVec2)
if (dragZoom || dragFocusZoom) Vec2.copy(_zoomEnd, mouseOnScreenVec2)
if (dragFocus) Vec2.copy(_focusEnd, mouseOnScreenVec2)
if (dragFocusZoom) {
const dist = Vec3.distance(camera.state.position, camera.state.target);
camera.setState({ radius: dist / 5 })
}
if (dragPan) Vec2.copy(_panEnd, mouseOnScreenVec2)
}
function onInteractionEnd() {
_isInteracting = false;
}
function onWheel({ dy }: WheelInput) {
_zoomEnd[1] += dy * 0.0001
function onWheel({ dx, dy, dz, buttons, modifiers }: WheelInput) {
const delta = absMax(dx, dy, dz)
if (Binding.match(p.bindings.scrollZoom, buttons, modifiers)) {
_zoomEnd[1] += delta * 0.0001
}
if (Binding.match(p.bindings.scrollFocus, buttons, modifiers)) {
_focusEnd[1] += delta * 0.0001
}
}
function onPinch({ fraction }: PinchInput) {
_isInteracting = true;
_zoomEnd[1] += (fraction - 1) * 0.1
function onPinch({ fraction, buttons, modifiers }: PinchInput) {
if (Binding.match(p.bindings.scrollZoom, buttons, modifiers)) {
_isInteracting = true;
_zoomEnd[1] += (fraction - 1) * 0.1
}
}
function dispose() {
@@ -292,7 +383,7 @@ namespace TrackballControls {
function spin(deltaT: number) {
const frameSpeed = (p.spinSpeed || 0) / 1000;
_spinSpeed[0] = 60 * Math.min(Math.abs(deltaT), 1000 / 8) / 1000 * frameSpeed;
if (!_isInteracting) Vec2.add(_moveCurr, _movePrev, _spinSpeed);
if (!_isInteracting) Vec2.add(_rotCurr, _rotPrev, _spinSpeed);
}
// force an update at start

View File

@@ -11,13 +11,15 @@ import InputObserver, { ModifiersKeys, ButtonsType } from '../../mol-util/input/
import { RxEventHelper } from '../../mol-util/rx-event-helper';
type Canvas3D = import('../canvas3d').Canvas3D
type HoverEvent = import('../canvas3d').Canvas3D.HoverEvent
type ClickEvent = import('../canvas3d').Canvas3D.ClickEvent
export class Canvas3dInteractionHelper {
private ev = RxEventHelper.create();
readonly events = {
highlight: this.ev<import('../canvas3d').Canvas3D.HighlightEvent>(),
click: this.ev<import('../canvas3d').Canvas3D.ClickEvent>(),
hover: this.ev<HoverEvent>(),
click: this.ev<ClickEvent>(),
};
private cX = -1;
@@ -52,14 +54,14 @@ export class Canvas3dInteractionHelper {
return;
}
// only highlight the latest
if (!this.inside || this.currentIdentifyT !== t) {
return;
}
const loci = this.getLoci(this.id);
// only broadcast the latest hover
if (!Representation.Loci.areEqual(this.prevLoci, loci)) {
this.events.highlight.next({ current: loci, modifiers: this.modifiers });
this.events.hover.next({ current: loci, buttons: this.buttons, modifiers: this.modifiers });
this.prevLoci = loci;
}
}
@@ -76,12 +78,13 @@ export class Canvas3dInteractionHelper {
this.inside = false;
if (this.prevLoci.loci !== EmptyLoci) {
this.prevLoci = Representation.Loci.Empty;
this.events.highlight.next({ current: this.prevLoci });
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, modifiers: this.modifiers });
}
}
move(x: number, y: number, modifiers: ModifiersKeys) {
move(x: number, y: number, buttons: ButtonsType, modifiers: ModifiersKeys) {
this.inside = true;
this.buttons = buttons;
this.modifiers = modifiers;
this.cX = x;
this.cY = y;
@@ -98,7 +101,7 @@ export class Canvas3dInteractionHelper {
modify(modifiers: ModifiersKeys) {
if (this.prevLoci.loci === EmptyLoci || ModifiersKeys.areEqual(modifiers, this.modifiers)) return;
this.modifiers = modifiers;
this.events.highlight.next({ current: this.prevLoci, modifiers: this.modifiers });
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, modifiers: this.modifiers });
}
dispose() {
@@ -107,8 +110,8 @@ export class Canvas3dInteractionHelper {
constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], input: InputObserver, private maxFps: number = 15) {
input.move.subscribe(({x, y, inside, buttons, modifiers }) => {
if (!inside || buttons) { return; }
this.move(x, y, modifiers);
if (!inside) return;
this.move(x, y, buttons, modifiers);
});
input.leave.subscribe(() => {

View File

@@ -10,6 +10,7 @@ import Renderer from '../../mol-gl/renderer';
import Scene from '../../mol-gl/scene';
import { BoundingSphereHelper } from '../helper/bounding-sphere-helper';
import { createTexture, Texture } from '../../mol-gl/webgl/texture';
import { Camera } from '../camera';
export class DrawPass {
colorTarget: RenderTarget
@@ -18,11 +19,11 @@ export class DrawPass {
private depthTarget: RenderTarget | null
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private debugHelper: BoundingSphereHelper) {
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private debugHelper: BoundingSphereHelper) {
const { gl, extensions } = webgl
const width = gl.drawingBufferWidth
const height = gl.drawingBufferHeight
this.colorTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.colorTarget = createRenderTarget(webgl, width, height)
this.packedDepth = !extensions.depthTexture
this.depthTarget = this.packedDepth ? createRenderTarget(webgl, width, height) : null
this.depthTexture = this.depthTarget ? this.depthTarget.texture : createTexture(webgl, 'image-depth', 'depth', 'ushort', 'nearest')
@@ -42,28 +43,28 @@ export class DrawPass {
}
render(toDrawingBuffer: boolean) {
const { webgl, renderer, scene, debugHelper, colorTarget, depthTarget } = this
const { gl } = webgl
const { webgl, renderer, scene, camera, debugHelper, colorTarget, depthTarget } = this
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
colorTarget.bind()
}
renderer.setViewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)
renderer.render(scene, 'color', true)
renderer.setViewport(0, 0, colorTarget.width, colorTarget.height)
renderer.render(scene, camera, 'color', true)
if (debugHelper.isEnabled) {
debugHelper.syncVisibility()
renderer.render(debugHelper.scene, 'color', false)
renderer.render(debugHelper.scene, camera, 'color', false)
}
// do a depth pass if not rendering to drawing buffer and
// extensions.depthTexture is unsupported (i.e. depthTarget is set)
if (!toDrawingBuffer && depthTarget) {
depthTarget.bind()
renderer.render(scene, 'depth', true)
renderer.render(scene, camera, 'depth', true)
if (debugHelper.isEnabled) {
debugHelper.syncVisibility()
renderer.render(debugHelper.scene, 'depth', false)
renderer.render(debugHelper.scene, camera, 'depth', false)
}
}
}

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { WebGLContext } from '../../mol-gl/webgl/context';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import Renderer from '../../mol-gl/renderer';
import Scene from '../../mol-gl/scene';
import { BoundingSphereHelper } from '../helper/bounding-sphere-helper';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { DrawPass } from './draw'
import { PostprocessingPass, PostprocessingParams } from './postprocessing'
import { MultiSamplePass, MultiSampleParams } from './multi-sample'
import { Camera } from '../camera';
import { Viewport } from '../camera/util';
export const ImageParams = {
multiSample: PD.Group(MultiSampleParams),
postprocessing: PD.Group(PostprocessingParams),
}
export type ImageProps = PD.Values<typeof ImageParams>
export class ImagePass {
private _width = 1024
private _height = 768
private _camera = new Camera()
private _colorTarget: RenderTarget
get colorTarget() { return this._colorTarget }
readonly drawPass: DrawPass
private readonly postprocessing: PostprocessingPass
private readonly multiSample: MultiSamplePass
get width() { return this._width }
get height() { return this._height }
constructor(webgl: WebGLContext, private renderer: Renderer, scene: Scene, private camera: Camera, debugHelper: BoundingSphereHelper, props: Partial<ImageProps>) {
const p = { ...PD.getDefaultValues(ImageParams), ...props }
this.drawPass = new DrawPass(webgl, renderer, scene, this._camera, debugHelper)
this.postprocessing = new PostprocessingPass(webgl, this._camera, this.drawPass, p.postprocessing)
this.multiSample = new MultiSamplePass(webgl, this._camera, this.drawPass, this.postprocessing, p.multiSample)
this.setSize(this._width, this._height)
}
setSize(width: number, height: number) {
this._width = width
this._height = height
this.drawPass.setSize(width, height)
this.postprocessing.setSize(width, height)
this.multiSample.setSize(width, height)
}
setProps(props: Partial<ImageProps> = {}) {
if (props.postprocessing) this.postprocessing.setProps(props.postprocessing)
if (props.multiSample) this.multiSample.setProps(props.multiSample)
}
render() {
Camera.copySnapshot(this._camera.state, this.camera.state)
Viewport.set(this._camera.viewport, 0, 0, this._width, this._height)
this._camera.update()
this.renderer.setViewport(0, 0, this._width, this._height);
if (this.multiSample.enabled) {
this.multiSample.render(false)
this._colorTarget = this.multiSample.colorTarget
} else {
this.drawPass.render(false)
if (this.postprocessing.enabled) {
this.postprocessing.render(false)
this._colorTarget = this.postprocessing.target
} else {
this._colorTarget = this.drawPass.colorTarget
}
}
}
getImageData(width: number, height: number) {
this.setSize(width, height)
this.render()
const pd = this.colorTarget.getPixelData()
return new ImageData(new Uint8ClampedArray(pd.array), pd.width, pd.height)
}
}

View File

@@ -54,6 +54,7 @@ export type MultiSampleProps = PD.Values<typeof MultiSampleParams>
export class MultiSamplePass {
props: MultiSampleProps
colorTarget: RenderTarget
private composeTarget: RenderTarget
private holdTarget: RenderTarget
@@ -65,6 +66,7 @@ export class MultiSamplePass {
constructor(private webgl: WebGLContext, private camera: Camera, private drawPass: DrawPass, private postprocessing: PostprocessingPass, props: Partial<MultiSampleProps>) {
const { gl } = webgl
this.colorTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.composeTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.holdTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.compose = getComposeRenderable(webgl, drawPass.colorTarget.texture)
@@ -92,6 +94,7 @@ export class MultiSamplePass {
}
setSize(width: number, height: number) {
this.colorTarget.setSize(width, height)
this.composeTarget.setSize(width, height)
this.holdTarget.setSize(width, height)
ValueCell.update(this.compose.values.uTexSize, Vec2.set(this.compose.values.uTexSize.ref.value, width, height))
@@ -102,15 +105,15 @@ export class MultiSamplePass {
if (props.sampleLevel !== undefined) this.props.sampleLevel = props.sampleLevel
}
render() {
render(toDrawingBuffer: boolean) {
if (this.props.mode === 'temporal') {
this.renderTemporalMultiSample()
this.renderTemporalMultiSample(toDrawingBuffer)
} else {
this.renderMultiSample()
this.renderMultiSample(toDrawingBuffer)
}
}
private renderMultiSample() {
private renderMultiSample(toDrawingBuffer: boolean) {
const { camera, compose, composeTarget, drawPass, postprocessing, webgl } = this
const { gl, state } = webgl
@@ -135,7 +138,7 @@ export class MultiSamplePass {
for (let i = 0; i < offsetList.length; ++i) {
const offset = offsetList[i]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
camera.update()
// the theory is that equal weights for each sample lead to an accumulation of rounding
// errors. The following equation varies the sampleWeight per sample so that it is uniformly
@@ -168,16 +171,20 @@ export class MultiSamplePass {
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
this.colorTarget.bind()
}
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
camera.viewOffset.enabled = false
camera.updateMatrices()
camera.update()
}
private renderTemporalMultiSample() {
private renderTemporalMultiSample(toDrawingBuffer: boolean) {
const { camera, compose, composeTarget, holdTarget, postprocessing, drawPass, webgl } = this
const { gl, state } = webgl
@@ -223,7 +230,7 @@ export class MultiSamplePass {
for (let i = 0; i < numSamplesPerFrame; ++i) {
const offset = offsetList[this.sampleIndex]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
camera.update()
// render scene and optionally postprocess
drawPass.render(false)
@@ -252,7 +259,11 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
this.colorTarget.bind()
}
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
@@ -261,7 +272,11 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, 1.0 - accumulationWeight)
ValueCell.update(compose.values.tColor, holdTarget.texture)
compose.update()
webgl.unbindFramebuffer()
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
this.colorTarget.bind()
}
gl.viewport(0, 0, width, height)
if (accumulationWeight === 0) state.disable(gl.BLEND)
else state.enable(gl.BLEND)
@@ -269,7 +284,7 @@ export class MultiSamplePass {
}
camera.viewOffset.enabled = false
camera.updateMatrices()
camera.update()
if (this.sampleIndex >= offsetList.length) this.sampleIndex = -1
}
}

View File

@@ -10,6 +10,7 @@ import Renderer from '../../mol-gl/renderer';
import Scene from '../../mol-gl/scene';
import { PickingId } from '../../mol-geo/geometry/picking';
import { decodeFloatRGB } from '../../mol-util/float-packing';
import { Camera } from '../camera';
export class PickPass {
pickDirty = true
@@ -26,7 +27,7 @@ export class PickPass {
private pickWidth: number
private pickHeight: number
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private pickBaseScale: number) {
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private pickBaseScale: number) {
const { gl } = webgl
const width = gl.drawingBufferWidth
const height = gl.drawingBufferHeight
@@ -64,14 +65,14 @@ export class PickPass {
}
render() {
const { renderer, scene } = this
const { renderer, scene, camera } = this
renderer.setViewport(0, 0, this.pickWidth, this.pickHeight);
this.objectPickTarget.bind();
renderer.render(scene, 'pickObject', true);
renderer.render(scene, camera, 'pickObject', true);
this.instancePickTarget.bind();
renderer.render(scene, 'pickInstance', true);
renderer.render(scene, camera, 'pickInstance', true);
this.groupPickTarget.bind();
renderer.render(scene, 'pickGroup', true);
renderer.render(scene, camera, 'pickGroup', true);
this.pickDirty = false
}

View File

@@ -160,10 +160,10 @@ export class PostprocessingPass {
}
render(toDrawingBuffer: boolean) {
ValueCell.update(this.renderable.values.uFar, this.camera.state.far)
ValueCell.update(this.renderable.values.uNear, this.camera.state.near)
ValueCell.update(this.renderable.values.uFogFar, this.camera.state.fogFar)
ValueCell.update(this.renderable.values.uFogNear, this.camera.state.fogNear)
ValueCell.update(this.renderable.values.uFar, this.camera.far)
ValueCell.update(this.renderable.values.uNear, this.camera.near)
ValueCell.update(this.renderable.values.uFogFar, this.camera.fogFar)
ValueCell.update(this.renderable.values.uFogNear, this.camera.fogNear)
ValueCell.update(this.renderable.values.dOrthographic, this.camera.state.mode === 'orthographic' ? 1 : 0)
const { gl, state } = this.webgl

View File

@@ -4,16 +4,57 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
/** resize canvas to container element */
/** Set canvas size taking `devicePixelRatio` into account */
export function setCanvasSize(canvas: HTMLCanvasElement, width: number, height: number) {
canvas.width = Math.round(window.devicePixelRatio * width)
canvas.height = Math.round(window.devicePixelRatio * height)
Object.assign(canvas.style, { width: `${width}px`, height: `${height}px` })
}
/** Resize canvas to container element taking `devicePixelRatio` into account */
export function resizeCanvas (canvas: HTMLCanvasElement, container: Element) {
let w = window.innerWidth
let h = window.innerHeight
let width = window.innerWidth
let height = window.innerHeight
if (container !== document.body) {
let bounds = container.getBoundingClientRect()
w = bounds.right - bounds.left
h = bounds.bottom - bounds.top
width = bounds.right - bounds.left
height = bounds.bottom - bounds.top
}
canvas.width = window.devicePixelRatio * w
canvas.height = window.devicePixelRatio * h
Object.assign(canvas.style, { width: `${w}px`, height: `${h}px` })
setCanvasSize(canvas, width, height)
}
function _canvasToBlob(canvas: HTMLCanvasElement, callback: BlobCallback, type?: string, quality?: any) {
const bin = atob(canvas.toDataURL(type, quality).split(',')[1])
const len = bin.length
const len32 = len >> 2
const a8 = new Uint8Array(len)
const a32 = new Uint32Array(a8.buffer, 0, len32)
let j = 0
for (let i = 0; i < len32; ++i) {
a32[i] = bin.charCodeAt(j++) |
bin.charCodeAt(j++) << 8 |
bin.charCodeAt(j++) << 16 |
bin.charCodeAt(j++) << 24
}
let tailLength = len & 3;
while (tailLength--) a8[j] = bin.charCodeAt(j++)
callback(new Blob([a8], { type: type || 'image/png' }));
}
export async function canvasToBlob(canvas: HTMLCanvasElement, type?: string, quality?: any): Promise<Blob> {
return new Promise((resolve, reject) => {
const callback = (blob: Blob | null) => {
if (blob) resolve(blob)
else reject('no blob returned')
}
if (!HTMLCanvasElement.prototype.toBlob) {
_canvasToBlob(canvas, callback, type, quality)
} else {
canvas.toBlob(callback, type, quality)
}
})
}

View File

@@ -302,7 +302,7 @@ function arrayColumn<T extends Column.Schema>({ array, schema, valueKind }: Colu
}
}
function windowColumn<T>(column: Column<T>, start: number, end: number) {
function windowColumn<T>(column: Column<T>, start: number, end: number): Column<T> {
if (!column.isDefined) return Column.Undefined(end - start, column.schema);
if (start === 0 && end === column.rowCount) return column;
if (!!column.__array && ColumnHelpers.isTypedArray(column.__array)) return windowTyped(column, start, end);
@@ -343,9 +343,9 @@ function isIdentity(map: ArrayLike<number>, rowCount: number) {
}
function columnView<T>(c: Column<T>, map: ArrayLike<number>, checkIdentity: boolean): Column<T> {
if (!c.isDefined) return c;
if (!c.isDefined || c.rowCount === 0) return c;
if (checkIdentity && isIdentity(map, c.rowCount)) return c;
if (!!c.__array) return arrayView(c, map);
if (!!c.__array && typeof c.value(0) === typeof c.__array[0]) return arrayView(c, map);
return viewFull(c, map);
}

View File

@@ -218,6 +218,16 @@ namespace Table {
return ret;
}
export function toArrays<S extends Schema>(table: Table<S>) {
const arrays: { [k: string]: ArrayLike<any> } = {}
const { _columns } = table;
for (let i = 0; i < _columns.length; i++) {
const c = _columns[i]
arrays[c] = table[c].toArray();
}
return arrays as { [k in keyof S]: ArrayLike<S[k]['T']> }
}
export function formatToString<S extends Schema>(table: Table<S>) {
const sb = StringBuilder.create();

View File

@@ -20,6 +20,10 @@ namespace UniqueArray {
array[array.length] = value;
return true;
}
export function has<K, T>({ keys }: UniqueArray<K, T>, key: K) {
return keys.has(key);
}
}
export { UniqueArray }

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
@@ -81,6 +81,13 @@ describe('ordered set', () => {
expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([12, 13, 16]))).toBe(false);
});
it('isSubsetIS', () => {
expect(OrderedSet.isSubset(
Interval.ofRange(1271, 1295),
OrderedSet.ofSortedArray([1271, 1272, 1274, 1275, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294])
)).toBe(true);
});
it('access/membership', () => {
expect(OrderedSet.has(empty, 10)).toBe(false);
expect(OrderedSet.indexOf(empty, 10)).toBe(-1);

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
@@ -65,6 +65,90 @@ describe('sortedArray', () => {
test('intersectionSize', SortedArray.intersectionSize(a1234, a2468), 2);
// console.log(Interval.findPredecessorIndexInInterval(Interval.ofBounds(0, 3), 2, Interval.ofBounds(0, 3)))
// console.log(SortedArray.findPredecessorIndexInInterval(SortedArray.ofSortedArray([0, 1, 2]), 2, Interval.ofBounds(0, 3)))
it('union1', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 836, 837, 838, 839, 840, 841, 842, 843]),
SortedArray.ofSortedArray([835])
),
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843])
)
})
it('union2', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([830, 832, 833]),
SortedArray.ofSortedArray([831])
),
SortedArray.ofSortedArray([830, 831, 832, 833])
)
})
it('union3ab', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835]),
SortedArray.ofSortedArray([836, 837, 838, 839, 840, 841, 842, 843])
),
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843])
)
})
it('union3ba', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([836, 837, 838, 839, 840, 841, 842, 843]),
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835])
),
SortedArray.ofSortedArray([830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843])
)
})
it('union4', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([1, 3, 5, 7, 9]),
SortedArray.ofSortedArray([2, 4, 6, 8])
),
SortedArray.ofSortedArray([1, 2, 3, 4, 5, 6, 7, 8, 9])
)
})
it('union5', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([2, 3, 4, 20, 21, 22]),
SortedArray.ofSortedArray([10, 11, 12])
),
SortedArray.ofSortedArray([2, 3, 4, 10, 11, 12, 20, 21, 22])
)
})
it('union6', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([768, 769, 770, 771, 772, 773, 774, 775, 776, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819]),
SortedArray.ofSortedArray([1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758])
),
SortedArray.ofSortedArray([768, 769, 770, 771, 772, 773, 774, 775, 776, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819])
)
})
it('union7', () => {
compareArrays(
SortedArray.union(
SortedArray.ofSortedArray([3766, 3767, 3768, 3770, 3773, 3780, 3783, 3787, 3797]),
SortedArray.ofSortedArray([3769, 3790, 3794])
),
SortedArray.ofSortedArray([3766, 3767, 3768, 3769, 3770, 3773, 3780, 3783, 3787, 3790, 3794, 3797])
)
})
it('isSubset', () => {
expect(SortedArray.isSubset(
SortedArray.ofSortedArray([1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295]),
SortedArray.ofSortedArray([1271, 1272, 1274, 1275, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294])
)).toBe(true);
})
});

View File

@@ -9,6 +9,7 @@ import Tuple from '../tuple'
export const Empty = Tuple.Zero;
export function ofRange(min: number, max: number) { return max < min ? Tuple.create(min, min) : Tuple.create(min, max + 1); }
export function ofBounds(start: number, end: number) { return end <= start ? Tuple.create(start, start) : Tuple.create(start, end); }
export function ofLength(length: number) { return length < 0 ? Tuple.create(0, 0) : Tuple.create(0, length); }
export const is = Tuple.is;
export const start = Tuple.fst;

View File

@@ -126,7 +126,7 @@ function isSubsetIS(a: I, b: S) {
const minA = I.min(a), maxA = I.max(a);
if (maxA - minA + 1 === 0) return false;
const minB = S.min(b), maxB = S.max(b);
return minB >= minA && maxA <= maxB;
return minB >= minA && maxB <= maxA;
}
function areRangesIntersecting(a: OrderedSetImpl, b: OrderedSetImpl) {

View File

@@ -171,28 +171,30 @@ export function isSubset(a: Nums, b: Nums) {
return equal === lenB;
}
export function union(a: Nums, b: Nums) {
export function union(a: Nums, b: Nums): Nums {
if (a === b) return a;
const lenA = a.length, lenB = b.length;
if (lenA === 0) return b;
if (lenB === 0) return a;
if (a[0] > b[0]) return union(b, a);
const { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b);
const commonCount = getCommonCount(a, b, startI, startJ, endI, endJ);
const lenA = a.length, lenB = b.length;
// A === B || B is subset of A ==> A
if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return a;
// A is subset of B ===> B
if (commonCount === lenA) return b;
const indices = new Int32Array(lenA + lenB - commonCount);
let offset = 0;
let i = 0, j = 0, offset = 0;
// insert the "prefixes"
for (let k = 0; k < startI; k++) indices[offset++] = a[k];
for (let k = 0; k < startJ; k++) indices[offset++] = b[k];
for (i = 0; i < startI; i++) indices[offset++] = a[i];
while (j < endJ && a[startI] > b[j]) indices[offset++] = b[j++];
// insert the common part
let i = startI;
let j = startJ;
while (i < endI && j < endJ) {
const x = a[i], y = b[j];
if (x < y) { indices[offset++] = x; i++; }
@@ -200,6 +202,10 @@ export function union(a: Nums, b: Nums) {
else { indices[offset++] = x; i++; j++; }
}
// insert the remaining common part
for (; i < endI; i++) indices[offset++] = a[i];
for (; j < endJ; j++) indices[offset++] = b[j];
// insert the "tail"
for (; i < lenA; i++) indices[offset++] = a[i];
for (; j < lenB; j++) indices[offset++] = b[j];

View File

@@ -14,6 +14,8 @@ namespace Interval {
export const ofRange: <T extends number = number>(min: T, max: T) => Interval<T> = Impl.ofRange as any;
/** Create interval from bounds [start, end), i.e. [start, end - 1] */
export const ofBounds: <T extends number = number>(start: T, end: T) => Interval<T> = Impl.ofBounds as any;
/** Create interval from length [0, length), i.e. [0, length - 1] */
export const ofLength: <T extends number = number>(length: T) => Interval<T> = Impl.ofLength as any;
export const is: <T extends number = number>(v: any) => v is Interval<T> = Impl.is as any;
/** Test if a value is within the bounds of the interval */

View File

@@ -26,8 +26,7 @@ function setCylinderMat(m: Mat4, start: Vec3, dir: Vec3, length: number) {
Vec3.add(tmpCylinderCenter, start, tmpCylinderMatDir)
// ensure the direction used to create the rotation is always pointing in the same
// direction so the triangles of adjacent cylinder will line up
Vec3.copy(tmpUp, up)
if (Vec3.dot(tmpCylinderMatDir, tmpUp) < 0) Vec3.scale(tmpUp, tmpUp, -1)
Vec3.matchDirection(tmpUp, up, tmpCylinderMatDir)
Vec3.makeRotation(m, tmpUp, tmpCylinderMatDir)
return Mat4.setTranslation(m, tmpCylinderCenter)
}

View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Mat4 } from '../../../../mol-math/linear-algebra';
import { MeshBuilder } from '../mesh-builder';
import { getSphere } from './sphere';
const tmpEllipsoidMat = Mat4.identity()
const tmpVec = Vec3()
function setEllipsoidMat(m: Mat4, center: Vec3, dirMajor: Vec3, dirMinor: Vec3, radiusScale: Vec3) {
Vec3.add(tmpVec, center, dirMajor)
Mat4.targetTo(m, center, tmpVec, dirMinor)
Mat4.setTranslation(m, center)
return Mat4.scale(m, m, radiusScale)
}
export function addEllipsoid(state: MeshBuilder.State, center: Vec3, dirMajor: Vec3, dirMinor: Vec3, radiusScale: Vec3, detail: number) {
MeshBuilder.addPrimitive(state, setEllipsoidMat(tmpEllipsoidMat, center, dirMajor, dirMinor, radiusScale), getSphere(detail))
}

View File

@@ -16,7 +16,7 @@ function setSphereMat(m: Mat4, center: Vec3, radius: number) {
return Mat4.scaleUniformly(m, Mat4.fromTranslation(m, center), radius)
}
function getSphere(detail: number) {
export function getSphere(detail: number) {
let sphere = sphereMap.get(detail)
if (sphere === undefined) {
sphere = Sphere(detail)

View File

@@ -101,9 +101,9 @@ export namespace MeshBuilder {
}
}
export function addCage(state: State, t: Mat4, cage: Cage, radius: number, detail: number) {
export function addCage(state: State, t: Mat4, cage: Cage, radius: number, detail: number, radialSegments: number) {
const { vertices: va, edges: ea } = cage
const cylinderProps = { radiusTop: radius, radiusBottom: radius }
const cylinderProps = { radiusTop: radius, radiusBottom: radius, radialSegments }
for (let i = 0, il = ea.length; i < il; i += 2) {
Vec3.fromArray(tmpVecA, va, ea[i] * 3)
Vec3.fromArray(tmpVecB, va, ea[i + 1] * 3)

View File

@@ -4,6 +4,9 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Mat4, Vec3 } from '../../mol-math/linear-algebra'
import { NumberArray } from '../../mol-util/type-helpers'
export interface Cage {
readonly vertices: ArrayLike<number>
readonly edges: ArrayLike<number>
@@ -11,4 +14,24 @@ export interface Cage {
export function createCage(vertices: ArrayLike<number>, edges: ArrayLike<number>): Cage {
return { vertices, edges }
}
export function copyCage(cage: Cage): Cage {
return {
vertices: new Float32Array(cage.vertices),
edges: new Uint32Array(cage.edges)
}
}
const tmpV = Vec3.zero()
/** Transform primitive in-place */
export function transformCage(cage: Cage, t: Mat4) {
const { vertices } = cage
for (let i = 0, il = vertices.length; i < il; i += 3) {
// position
Vec3.transformMat4(tmpV, Vec3.fromArray(tmpV, vertices, i), t)
Vec3.toArray(tmpV, vertices as NumberArray, i)
}
return cage
}

View File

@@ -30,6 +30,14 @@ export function createPrimitive(vertices: ArrayLike<number>, indices: ArrayLike<
return builder.getPrimitive()
}
export function copyPrimitive(primitive: Primitive): Primitive {
return {
vertices: new Float32Array(primitive.vertices),
normals: new Float32Array(primitive.normals),
indices: new Uint32Array(primitive.indices)
}
}
export interface PrimitiveBuilder {
add(a: Vec3, b: Vec3, c: Vec3): void
getPrimitive(): Primitive

View File

@@ -78,10 +78,22 @@ export function PentagonalPrism() {
let hexagonalPrism: Primitive
export function HexagonalPrism() {
if (!hexagonalPrism) hexagonalPrism = Prism(polygon(6, true))
if (!hexagonalPrism) hexagonalPrism = Prism(polygon(6, false))
return hexagonalPrism
}
let shiftedHexagonalPrism: Primitive
export function ShiftedHexagonalPrism() {
if (!shiftedHexagonalPrism) shiftedHexagonalPrism = Prism(polygon(6, true))
return shiftedHexagonalPrism
}
let heptagonalPrism: Primitive
export function HeptagonalPrism() {
if (!heptagonalPrism) heptagonalPrism = Prism(polygon(7, false))
return heptagonalPrism
}
//
/**
@@ -133,6 +145,6 @@ export function PentagonalPrismCage() {
let hexagonalPrismCage: Cage
export function HexagonalPrismCage() {
if (!hexagonalPrismCage) hexagonalPrismCage = PrismCage(polygon(6, true))
if (!hexagonalPrismCage) hexagonalPrismCage = PrismCage(polygon(6, false))
return hexagonalPrismCage
}

View File

@@ -54,6 +54,12 @@ export function Pyramid(points: ArrayLike<number>): Primitive {
return builder.getPrimitive()
}
let triangularPyramid: Primitive
export function TriangularPyramid() {
if (!triangularPyramid) triangularPyramid = Pyramid(polygon(3, true))
return triangularPyramid
}
let octagonalPyramid: Primitive
export function OctagonalPyramid() {
if (!octagonalPyramid) octagonalPyramid = Pyramid(polygon(8, true))

View File

@@ -28,11 +28,9 @@ import { createEmptyTransparency } from '../../mol-geo/geometry/transparency-dat
function createRenderer(gl: WebGLRenderingContext) {
const ctx = createContext(gl)
const camera = new Camera({
near: 0.01,
far: 10000,
position: Vec3.create(0, 0, 50)
})
const renderer = Renderer.create(ctx, camera)
const renderer = Renderer.create(ctx)
return { ctx, camera, renderer }
}

View File

@@ -168,6 +168,7 @@ export const GlobalUniformSchema = {
uFogFar: UniformSpec('f'),
uFogColor: UniformSpec('v3'),
uTransparentBackground: UniformSpec('i'),
uPickingAlphaThreshold: UniformSpec('f'),
uInteriorDarkening: UniformSpec('f'),
}

View File

@@ -38,14 +38,15 @@ interface Renderer {
readonly props: Readonly<RendererProps>
clear: () => void
render: (scene: Scene, variant: GraphicsRenderVariant, clear: boolean) => void
render: (scene: Scene, camera: Camera, variant: GraphicsRenderVariant, clear: boolean) => void
setProps: (props: Partial<RendererProps>) => void
setViewport: (x: number, y: number, width: number, height: number) => void
dispose: () => void
}
export const RendererParams = {
backgroundColor: PD.Color(Color(0x000000)),
backgroundColor: PD.Color(Color(0x000000), { description: 'Background color of the 3D canvas' }),
transparentBackground: PD.Boolean(false, { description: 'Background opacity of the 3D canvas' }),
pickingAlphaThreshold: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }, { description: 'The minimum opacity value needed for an object to be pickable.' }),
interiorDarkening: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
@@ -59,39 +60,40 @@ export const RendererParams = {
export type RendererProps = PD.Values<typeof RendererParams>
namespace Renderer {
export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer {
export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer {
const { gl, state, stats } = ctx
const p = deepClone({ ...PD.getDefaultValues(RendererParams), ...props })
const viewport = Viewport()
const bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor)
const view = Mat4.clone(camera.view)
const invView = Mat4.invert(Mat4.identity(), view)
const modelView = Mat4.clone(camera.view)
const invModelView = Mat4.invert(Mat4.identity(), modelView)
const invProjection = Mat4.invert(Mat4.identity(), camera.projection)
const modelViewProjection = Mat4.mul(Mat4.identity(), modelView, camera.projection)
const invModelViewProjection = Mat4.invert(Mat4.identity(), modelViewProjection)
const view = Mat4()
const invView = Mat4()
const modelView = Mat4()
const invModelView = Mat4()
const invProjection = Mat4()
const modelViewProjection = Mat4()
const invModelViewProjection = Mat4()
const viewOffset = camera.viewOffset.enabled ? Vec2.create(camera.viewOffset.offsetX * 16, camera.viewOffset.offsetY * 16) : Vec2()
const viewOffset = Vec2()
const globalUniforms: GlobalUniformValues = {
uModel: ValueCell.create(Mat4.identity()),
uView: ValueCell.create(camera.view),
uView: ValueCell.create(view),
uInvView: ValueCell.create(invView),
uModelView: ValueCell.create(modelView),
uInvModelView: ValueCell.create(invModelView),
uInvProjection: ValueCell.create(invProjection),
uProjection: ValueCell.create(Mat4.clone(camera.projection)),
uProjection: ValueCell.create(Mat4()),
uModelViewProjection: ValueCell.create(modelViewProjection),
uInvModelViewProjection: ValueCell.create(invModelViewProjection),
uIsOrtho: ValueCell.create(camera.state.mode === 'orthographic' ? 1 : 0),
uIsOrtho: ValueCell.create(1),
uViewOffset: ValueCell.create(viewOffset),
uPixelRatio: ValueCell.create(ctx.pixelRatio),
uViewportHeight: ValueCell.create(viewport.height),
uViewport: ValueCell.create(Viewport.toVec4(Vec4(), viewport)),
uViewOffset: ValueCell.create(viewOffset),
uLightIntensity: ValueCell.create(p.lightIntensity),
uAmbientIntensity: ValueCell.create(p.ambientIntensity),
@@ -100,13 +102,14 @@ namespace Renderer {
uRoughness: ValueCell.create(p.roughness),
uReflectivity: ValueCell.create(p.reflectivity),
uCameraPosition: ValueCell.create(Vec3.clone(camera.state.position)),
uNear: ValueCell.create(camera.state.near),
uFar: ValueCell.create(camera.state.far),
uFogNear: ValueCell.create(camera.state.fogNear),
uFogFar: ValueCell.create(camera.state.fogFar),
uCameraPosition: ValueCell.create(Vec3()),
uNear: ValueCell.create(1),
uFar: ValueCell.create(10000),
uFogNear: ValueCell.create(1),
uFogFar: ValueCell.create(10000),
uFogColor: ValueCell.create(bgColor),
uTransparentBackground: ValueCell.create(p.transparentBackground ? 1 : 0),
uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold),
uInteriorDarkening: ValueCell.create(p.interiorDarkening),
}
@@ -158,7 +161,7 @@ namespace Renderer {
}
}
const render = (scene: Scene, variant: GraphicsRenderVariant, clear: boolean) => {
const render = (scene: Scene, camera: Camera, variant: GraphicsRenderVariant, clear: boolean) => {
ValueCell.update(globalUniforms.uModel, scene.view)
ValueCell.update(globalUniforms.uView, camera.view)
ValueCell.update(globalUniforms.uInvView, Mat4.invert(invView, camera.view))
@@ -173,10 +176,10 @@ namespace Renderer {
ValueCell.update(globalUniforms.uViewOffset, camera.viewOffset.enabled ? Vec2.set(viewOffset, camera.viewOffset.offsetX * 16, camera.viewOffset.offsetY * 16) : Vec2.set(viewOffset, 0, 0))
ValueCell.update(globalUniforms.uCameraPosition, camera.state.position)
ValueCell.update(globalUniforms.uFar, camera.state.far)
ValueCell.update(globalUniforms.uNear, camera.state.near)
ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
ValueCell.update(globalUniforms.uFar, camera.far)
ValueCell.update(globalUniforms.uNear, camera.near)
ValueCell.update(globalUniforms.uFogFar, camera.fogFar)
ValueCell.update(globalUniforms.uFogNear, camera.fogNear)
globalUniformsNeedUpdate = true
state.currentRenderItemId = -1
@@ -191,7 +194,7 @@ namespace Renderer {
if (clear) {
if (variant === 'color') {
state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1.0)
state.clearColor(bgColor[0], bgColor[1], bgColor[2], p.transparentBackground ? 0 : 1)
} else {
state.clearColor(1, 1, 1, 1)
}
@@ -204,7 +207,7 @@ namespace Renderer {
if (r.state.opaque) renderObject(r, variant)
}
state.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE)
state.enable(gl.BLEND)
for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i]
@@ -224,7 +227,7 @@ namespace Renderer {
clear: () => {
state.depthMask(true)
state.colorMask(true, true, true, true)
state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1.0)
state.clearColor(bgColor[0], bgColor[1], bgColor[2], p.transparentBackground ? 0 : 1)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
},
render,
@@ -243,6 +246,10 @@ namespace Renderer {
Color.toVec3Normalized(bgColor, p.backgroundColor)
ValueCell.update(globalUniforms.uFogColor, Vec3.copy(globalUniforms.uFogColor.ref.value, bgColor))
}
if (props.transparentBackground !== undefined && props.transparentBackground !== p.transparentBackground) {
p.transparentBackground = props.transparentBackground
ValueCell.update(globalUniforms.uTransparentBackground, p.transparentBackground ? 1 : 0)
}
if (props.lightIntensity !== undefined && props.lightIntensity !== p.lightIntensity) {
p.lightIntensity = props.lightIntensity
ValueCell.update(globalUniforms.uLightIntensity, p.lightIntensity)

View File

@@ -189,16 +189,7 @@ const glsl300VertPrefix = `#version 300 es
#define texture2D texture
`
const glsl300FragPrefix = `#version 300 es
layout(location = 0) out highp vec4 out_FragData0;
layout(location = 1) out highp vec4 out_FragData1;
layout(location = 2) out highp vec4 out_FragData2;
layout(location = 3) out highp vec4 out_FragData3;
layout(location = 4) out highp vec4 out_FragData4;
layout(location = 5) out highp vec4 out_FragData5;
layout(location = 6) out highp vec4 out_FragData6;
layout(location = 7) out highp vec4 out_FragData7;
const glsl300FragPrefixCommon = `
#define varying in
#define texture2D texture
#define texture2DLodEXT textureLod
@@ -211,16 +202,29 @@ layout(location = 7) out highp vec4 out_FragData7;
#define requiredDrawBuffers
`
function getGlsl300FragPrefix(gl: WebGL2RenderingContext, extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) {
const prefix = [ '#version 300 es' ]
if (extensions.drawBuffers) {
const maxDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS) as number
for (let i = 0, il = maxDrawBuffers; i < il; ++i) {
prefix.push(`layout(location = ${i}) out highp vec4 out_FragData${i};`)
}
}
prefix.push(glsl300FragPrefixCommon)
return prefix.join('\n') + '\n'
}
function transformGlsl300Frag(frag: string) {
return frag.replace(/gl_FragData\[([0-7])\]/g, 'out_FragData$1')
return frag.replace(/gl_FragData\[([0-9]+)\]/g, 'out_FragData$1')
}
export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode {
const webgl2 = isWebGL2(gl)
const header = getDefinesCode(defines)
const vertPrefix = webgl2 ? glsl300VertPrefix : ''
const fragPrefix = webgl2 ? glsl300FragPrefix : getGlsl100FragPrefix(extensions, shaders.extensions)
const frag = webgl2 ? transformGlsl300Frag(shaders.frag) : shaders.frag
const vertPrefix = isWebGL2(gl) ? glsl300VertPrefix : ''
const fragPrefix = isWebGL2(gl)
? getGlsl300FragPrefix(gl, extensions, shaders.extensions)
: getGlsl100FragPrefix(extensions, shaders.extensions)
const frag = isWebGL2(gl) ? transformGlsl300Frag(shaders.frag) : shaders.frag
return {
id: shaderCodeId(),
vert: `${vertPrefix}${header}${shaders.vert}`,

View File

@@ -2,10 +2,11 @@ export default `
#ifdef dUseFog
float depth = length(vViewPosition);
float fogFactor = smoothstep(uFogNear, uFogFar, depth);
gl_FragColor.rgb = mix(gl_FragColor.rgb, uFogColor, fogFactor);
float fogAlpha = (1.0 - fogFactor) * gl_FragColor.a;
if (fogAlpha < 0.01)
discard;
gl_FragColor = vec4(gl_FragColor.rgb, fogAlpha);
if (uTransparentBackground == 0) {
gl_FragColor.rgb = mix(gl_FragColor.rgb, uFogColor, fogFactor);
} else {
float fogAlpha = (1.0 - fogFactor) * gl_FragColor.a;
gl_FragColor.a = fogAlpha;
}
#endif
`

View File

@@ -36,7 +36,7 @@ geometry.normal = normal;
geometry.viewDir = normalize(vViewPosition);
IncidentLight directLight;
directLight.direction = geometry.viewDir;
directLight.direction = vec3(0.0, 0.0, -1.0);
directLight.color = vec3(uLightIntensity);
RE_Direct_Physical(directLight, geometry, physicalMaterial, reflectedLight);

View File

@@ -5,7 +5,11 @@ uniform int uGroupCount;
uniform vec3 uHighlightColor;
uniform vec3 uSelectColor;
varying float vMarker;
#if __VERSION__ != 300
varying float vMarker;
#else
flat in float vMarker;
#endif
varying vec3 vViewPosition;
@@ -18,6 +22,7 @@ uniform vec3 uFogColor;
uniform float uAlpha;
uniform float uPickingAlphaThreshold;
uniform int uPickable;
uniform int uTransparentBackground;
uniform float uInteriorDarkening;
`

View File

@@ -8,7 +8,11 @@ uniform int uGroupCount;
uniform vec2 uMarkerTexDim;
uniform sampler2D tMarker;
varying float vMarker;
#if __VERSION__ != 300
varying float vMarker;
#else
flat out float vMarker;
#endif
varying vec3 vViewPosition;
`

View File

@@ -23,7 +23,7 @@ attribute mat4 aTransform;
attribute float aInstance;
attribute float aGroup;
#ifndef dFlatShaded
#if !defined(dFlatShaded) || !defined(enabledStandardDerivatives)
#ifdef dGeoTexture
uniform sampler2D tNormal;
#else
@@ -38,7 +38,7 @@ void main(){
#include assign_marker_varying
#include assign_position
#ifndef dFlatShaded
#if !defined(dFlatShaded) || !defined(enabledStandardDerivatives)
#ifdef dGeoTexture
vec3 normal = readFromTexture(tNormal, aGroup, uGeoTexDim).xyz;
#else

View File

@@ -124,8 +124,8 @@ void main(void){
#elif defined(dColorType_depth)
gl_FragColor = material;
#else
vec3 normal = cameraNormal;
vec3 vViewPosition = -cameraPos;
vec3 normal = -cameraNormal;
vec3 vViewPosition = cameraPos;
#include apply_light_color
if (interior) {

View File

@@ -190,6 +190,7 @@ export interface WebGLContext {
readonly framebufferCache: FramebufferCache
readonly maxTextureSize: number
readonly maxRenderbufferSize: number
readonly maxDrawBuffers: number
unbindFramebuffer: () => void
@@ -212,6 +213,7 @@ export function createContext(gl: GLRenderingContext): WebGLContext {
const parameters = {
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE) as number,
maxRenderbufferSize: gl.getParameter(gl.MAX_RENDERBUFFER_SIZE) as number,
maxDrawBuffers: isWebGL2(gl) ? gl.getParameter(gl.MAX_DRAW_BUFFERS) as number : 0,
maxVertexTextureImageUnits: gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) as number,
}
@@ -274,6 +276,7 @@ export function createContext(gl: GLRenderingContext): WebGLContext {
framebufferCache,
get maxTextureSize () { return parameters.maxTextureSize },
get maxRenderbufferSize () { return parameters.maxRenderbufferSize },
get maxDrawBuffers () { return parameters.maxDrawBuffers },
unbindFramebuffer: () => unbindFramebuffer(gl),

View File

@@ -5,6 +5,7 @@
*/
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax, getFragDepth, COMPAT_frag_depth, COMPAT_color_buffer_float, getColorBufferFloat, COMPAT_draw_buffers, getDrawBuffers, getShaderTextureLod, COMPAT_shader_texture_lod, getDepthTexture, COMPAT_depth_texture } from './compat';
import { isDebugMode } from '../../mol-util/debug';
export type WebGLExtensions = {
instancedArrays: COMPAT_instanced_arrays
@@ -37,43 +38,45 @@ export function createExtensions(gl: GLRenderingContext): WebGLExtensions {
}
const standardDerivatives = getStandardDerivatives(gl)
if (standardDerivatives === null) {
// TODO handle non-support downstream (e.g. no flat shading)
// throw new Error('Could not find support for "standard_derivatives"')
if (isDebugMode && standardDerivatives === null) {
// - non-support handled downstream (flat shading option is ignored)
// - can't be a required extension because it is not supported by `headless-gl`
console.log('Could not find support for "standard_derivatives"')
}
const textureFloatLinear = getTextureFloatLinear(gl)
if (textureFloatLinear === null) {
if (isDebugMode && textureFloatLinear === null) {
// TODO handle non-support downstream (no gpu gaussian calc, no gpu mc???)
// throw new Error('Could not find support for "texture_float_linear"')
// - can't be a required extension because it is not supported by `headless-gl`
console.log('Could not find support for "texture_float_linear"')
}
const depthTexture = getDepthTexture(gl)
if (depthTexture === null) {
if (isDebugMode && depthTexture === null) {
console.log('Could not find support for "depth_texture"')
}
const blendMinMax = getBlendMinMax(gl)
if (blendMinMax === null) {
if (isDebugMode && blendMinMax === null) {
// TODO handle non-support downstream (e.g. no gpu gaussian calc)
// - can't be a required extension because it is not supported by `headless-gl`
console.log('Could not find support for "blend_minmax"')
}
const vertexArrayObject = getVertexArrayObject(gl)
if (vertexArrayObject === null) {
if (isDebugMode && vertexArrayObject === null) {
console.log('Could not find support for "vertex_array_object"')
}
const fragDepth = getFragDepth(gl)
if (fragDepth === null) {
if (isDebugMode && fragDepth === null) {
console.log('Could not find support for "frag_depth"')
}
const colorBufferFloat = getColorBufferFloat(gl)
if (colorBufferFloat === null) {
if (isDebugMode && colorBufferFloat === null) {
console.log('Could not find support for "color_buffer_float"')
}
const drawBuffers = getDrawBuffers(gl)
if (drawBuffers === null) {
if (isDebugMode && drawBuffers === null) {
console.log('Could not find support for "draw_buffers"')
}
const shaderTextureLod = getShaderTextureLod(gl)
if (shaderTextureLod === null) {
if (isDebugMode && shaderTextureLod === null) {
console.log('Could not find support for "shader_texture_lod"')
}

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ReaderResult as Result } from '../result'
import { Task } from '../../../mol-task'
import { parseCsv } from '../csv/parser';
import { Column, Table } from '../../../mol-data/db';
import { toTable } from '../cif/schema';
import Schema = Column.Schema
import { CsvTable } from '../csv/data-model';
export const Schema3DG = {
/** Chromosome name */
chromosome: Schema.str,
/** Base position */
position: Schema.int,
/** X coordinate */
x: Schema.float,
/** Y coordinate */
y: Schema.float,
/** Z coordinate */
z: Schema.float,
}
export type Schema3DG = typeof Schema3DG
export interface File3DG {
table: Table<Schema3DG>
}
const FieldNames = [ 'chromosome', 'position', 'x', 'y', 'z' ]
function categoryFromTable(name: string, table: CsvTable) {
return {
name,
rowCount: table.rowCount,
fieldNames: FieldNames,
getField: (name: string) => {
return table.getColumn(FieldNames.indexOf(name).toString())
}
}
}
export function parse3DG(data: string) {
return Task.create<Result<File3DG>>('Parse 3DG', async ctx => {
const opts = { quote: '', comment: '#', delimiter: '\t', noColumnNames: true }
const csvFile = await parseCsv(data, opts).runInContext(ctx)
if (csvFile.isError) return Result.error(csvFile.message, csvFile.line)
const category = categoryFromTable('3dg', csvFile.result.table)
const table = toTable(Schema3DG, category)
return Result.success({ table })
});
}

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { parse3DG } from '../3dg/parser';
const basic3dgString = `1(mat) 1420000 0.791377837067 10.9947291355 -13.1882897693
1(mat) 1440000 -0.268241283699 10.5200875887 -13.0896257278
1(mat) 1460000 -1.3853075236 10.5513787498 -13.1440142173
1(mat) 1480000 -1.55984101733 11.4340829129 -13.6026301209
1(mat) 1500000 -0.770991778399 11.4758488546 -14.5881137222
1(mat) 1520000 -0.0848245107875 12.2624690808 -14.354289628
1(mat) 1540000 -0.458643807046 12.5985791771 -13.4701149287
1(mat) 1560000 -0.810322906201 12.2461643989 -12.3172933413
1(mat) 1580000 -2.08211172035 12.8886838656 -12.8742007778
1(mat) 1600000 -3.52093948201 13.1850935438 -12.4118684428`
describe('3dg reader', () => {
it('basic', async () => {
const parsed = await parse3DG(basic3dgString).run();
expect(parsed.isError).toBe(false)
if (parsed.isError) return;
const { chromosome, position, x, y, z } = parsed.result.table;
expect(chromosome.value(0)).toBe('1(mat)')
expect(position.value(1)).toBe(1440000)
expect(x.value(5)).toBe(-0.0848245107875)
expect(y.value(5)).toBe(12.2624690808)
expect(z.value(5)).toBe(-14.354289628)
});
});

View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { parseFloat as fastParseFloat, parseInt as fastParseInt } from '../../../mol-io/reader/common/text/number-parser';
describe('common', () => {
it('number-parser fastParseFloat', () => {
expect(fastParseFloat('11.0829(23)', 0, 11)).toBe(11.0829)
});
it('number-parser fastParseInt', () => {
expect(fastParseInt('11(23)', 0, 11)).toBe(11)
});
});

View File

@@ -14,6 +14,7 @@ import { CCD_Schema, CCD_Database } from './cif/schema/ccd'
import { BIRD_Schema, BIRD_Database } from './cif/schema/bird'
import { dic_Schema, dic_Database } from './cif/schema/dic'
import { DensityServer_Data_Schema, DensityServer_Data_Database } from './cif/schema/density-server'
import { cifCore_Database, cifCore_Schema, cifCore_Aliases } from './cif/schema/cif-core'
export const CIF = {
parse: (data: string|Uint8Array) => typeof data === 'string' ? parseText(data) : parseBinary(data),
@@ -26,7 +27,8 @@ export const CIF = {
CCD: (frame: CifFrame) => toDatabase<CCD_Schema, CCD_Database>(CCD_Schema, frame),
BIRD: (frame: CifFrame) => toDatabase<BIRD_Schema, BIRD_Database>(BIRD_Schema, frame),
dic: (frame: CifFrame) => toDatabase<dic_Schema, dic_Database>(dic_Schema, frame),
densityServer: (frame: CifFrame) => toDatabase<DensityServer_Data_Schema, DensityServer_Data_Database>(DensityServer_Data_Schema, frame)
cifCore: (frame: CifFrame) => toDatabase<cifCore_Schema, cifCore_Database>(cifCore_Schema, frame, cifCore_Aliases),
densityServer: (frame: CifFrame) => toDatabase<DensityServer_Data_Schema, DensityServer_Data_Database>(DensityServer_Data_Schema, frame),
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -23,23 +23,31 @@ export function CifFile(blocks: ArrayLike<CifBlock>, name?: string): CifFile {
export interface CifFrame {
readonly header: string,
// Category names stored separately so that the ordering can be preserved.
/** Category names, stored separately so that the ordering can be preserved. */
readonly categoryNames: ReadonlyArray<string>,
readonly categories: CifCategories
}
export interface CifBlock extends CifFrame {
readonly saveFrames: CifFrame[]
getField(name: string): CifField | undefined
}
export function CifBlock(categoryNames: string[], categories: CifCategories, header: string, saveFrames: CifFrame[] = []): CifBlock {
return { categoryNames, header, categories, saveFrames };
return {
categoryNames, header, categories, saveFrames,
getField(name: string) {
const [ category, field ] = name.split('.')
return categories[category].getField(field || '')
}
};
}
export function CifSafeFrame(categoryNames: string[], categories: CifCategories, header: string): CifFrame {
export function CifSaveFrame(categoryNames: string[], categories: CifCategories, header: string): CifFrame {
return { categoryNames, header, categories };
}
export type CifAliases = { readonly [name: string]: string[] }
export type CifCategories = { readonly [name: string]: CifCategory }
export interface CifCategory {

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 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>
@@ -10,16 +10,31 @@ import { Tensor } from '../../../mol-math/linear-algebra'
import { arrayEqual } from '../../../mol-util'
import * as Data from './data-model'
export function toDatabaseCollection<Schema extends Database.Schema>(schema: Schema, file: Data.CifFile): DatabaseCollection<Schema> {
export namespace FieldPath {
export function canonical(path: string) {
return path.replace('.', '_').replace(/\[/, '_').replace(/(\[|\])/g, '')
}
export function equal(pathA: string, pathB: string) {
return canonical(pathA) === canonical(pathB)
}
export function create(category: string, field: string, asCanonical = false) {
const p = `${category}${field ? `.${field}` : ''}`
return asCanonical ? canonical(p) : p
}
}
export function toDatabaseCollection<Schema extends Database.Schema>(schema: Schema, file: Data.CifFile, aliases?: Data.CifAliases): DatabaseCollection<Schema> {
const dbc: DatabaseCollection<Schema> = {}
for (const data of file.blocks) {
dbc[data.header] = toDatabase(schema, data)
dbc[data.header] = toDatabase(schema, data, aliases)
}
return dbc;
}
export function toDatabase<Schema extends Database.Schema, Frame extends Database<Schema> = Database<Schema>>(schema: Schema, frame: Data.CifFrame): Frame {
return createDatabase(schema, frame) as Frame;
export function toDatabase<Schema extends Database.Schema, Frame extends Database<Schema> = Database<Schema>>(schema: Schema, frame: Data.CifFrame, aliases?: Data.CifAliases): Frame {
return createDatabase(schema, frame, aliases) as Frame;
}
export function toTable<Schema extends Table.Schema, R extends Table<Schema> = Table<Schema>>(schema: Schema, category: Data.CifCategory): R {
@@ -51,7 +66,7 @@ function createColumn<T>(schema: Column.Schema, field: Data.CifField, value: (ro
};
}
function createListColumn<T extends number|string>(schema: Column.Schema.List<T>, category: Data.CifCategory, key: string): Column<(number|string)[]> {
function createListColumn<T extends number | string>(schema: Column.Schema.List<T>, category: Data.CifCategory, key: string): Column<(number | string)[]> {
const separator = schema.separator;
const itemParse = schema.itemParse;
@@ -134,15 +149,62 @@ class CategoryTable implements Table<any> { // tslint:disable-line:class-name
}
}
function createDatabase(schema: Database.Schema, frame: Data.CifFrame): Database<any> {
function createDatabase(schema: Database.Schema, frame: Data.CifFrame, aliases?: Data.CifAliases): Database<any> {
const tables = Object.create(null);
for (const k of Object.keys(schema)) {
tables[k] = createTable(k, (schema as any)[k], frame);
tables[k] = createTable(k, schema[k], frame, aliases);
}
return Database.ofTables(frame.header, schema, tables);
}
function createTable(key: string, schema: Table.Schema, frame: Data.CifFrame) {
const cat = frame.categories[key];
type FlatFrame = { [k: string]: Data.CifField }
function flattenFrame(frame: Data.CifFrame): FlatFrame {
const flatFrame = Object.create(null)
for (const c of Object.keys(frame.categories)) {
for (const f of frame.categories[c].fieldNames) {
const p = FieldPath.create(c, f, true)
flatFrame[p] = frame.categories[c].getField(f)
}
}
return flatFrame
}
function getField(field: string, category: string, flatFrame: FlatFrame, aliases?: Data.CifAliases) {
const path = FieldPath.create(category, field)
const canonicalPath = FieldPath.canonical(path)
if (canonicalPath in flatFrame) return flatFrame[canonicalPath]
if (aliases && path in aliases) {
for (const aliased of aliases[path]) {
const canonicalAliased = FieldPath.canonical(aliased)
if (canonicalAliased in flatFrame) return flatFrame[canonicalAliased]
}
}
}
function createTable(key: string, schema: Table.Schema, frame: Data.CifFrame, aliases?: Data.CifAliases) {
let cat = frame.categories[key];
if (aliases) {
const flatFrame = flattenFrame(frame)
const fields: { [k: string]: Data.CifField } = Object.create(null)
const fieldNames: string[] = []
let rowCount = 0
for (const k of Object.keys(schema)) {
const field = getField(k, key, flatFrame, aliases)
if (field) {
fields[k] = field
fieldNames.push(k)
rowCount = field.rowCount
}
}
cat = {
rowCount,
name: key,
fieldNames: [...fieldNames],
getField(name: string) {
return fields[name];
}
}
}
return new CategoryTable(cat || Data.CifCategory.empty(key), schema, !!cat);
}

View File

@@ -1,7 +1,7 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.313, IHM 1.01, CARB draft.
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.318, IHM 1.04, CARB draft.
*
* @author molstar/ciftools package
*/

View File

@@ -1,7 +1,7 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.313, IHM 1.01, CARB draft.
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.318, IHM 1.04, CARB draft.
*
* @author molstar/ciftools package
*/

View File

@@ -0,0 +1,637 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'cifCore' schema file. Dictionary versions: CifCore 3.0.11.
*
* @author molstar/ciftools package
*/
import { Database, Column } from '../../../../mol-data/db'
import Schema = Column.Schema
const int = Schema.int;
const float = Schema.float;
const str = Schema.str;
export const cifCore_Schema = {
/**
* The CATEGORY of data items used to describe the parameters of
* the crystal unit cell and their measurement.
*/
cell: {
/**
* The number of the formula units in the unit cell as specified
* by _chemical_formula.structural, _chemical_formula.moiety or
* _chemical_formula.sum.
*/
formula_units_Z: int,
/**
* Volume of the crystal unit cell.
*/
volume: float,
/**
* The angle between the bounding cell axes.
*/
angle_alpha: float,
/**
* The angle between the bounding cell axes.
*/
angle_beta: float,
/**
* The angle between the bounding cell axes.
*/
angle_gamma: float,
/**
* The length of each cell axis.
*/
length_a: float,
/**
* The length of each cell axis.
*/
length_b: float,
/**
* The length of each cell axis.
*/
length_c: float,
},
/**
* The CATEGORY of data items which describe the composition and
* chemical properties of the compound under study. The formula data
* items must be consistent with the density, unit-cell and Z values.
*/
chemical: {
/**
* The temperature at which a crystalline solid changes to a liquid.
*/
melting_point: float,
/**
* Trivial name by which the compound is commonly known.
*/
name_common: str,
/**
* IUPAC or Chemical Abstracts full name of compound.
*/
name_systematic: str,
},
/**
* The CATEGORY of data items which specify the composition and chemical
* properties of the compound. The formula data items must agree
* with those that specify the density, unit-cell and Z values.
*
* The following rules apply to the construction of the data items
* _chemical_formula.analytical, *.structural and *.sum. For the
* data item *.moiety the formula construction is broken up into
* residues or moieties, i.e. groups of atoms that form a molecular
* unit or molecular ion. The rules given below apply within each
* moiety but different requirements apply to the way that moieties
* are connected (see _chemical_formula.moiety).
*
* 1. Only recognized element symbols may be used.
*
* 2. Each element symbol is followed by a 'count' number. A count of
* '1' may be omitted.
*
* 3. A space or parenthesis must separate each cluster of (element
* symbol + count).
*
* 4. Where a group of elements is enclosed in parentheses, the
* multiplier for the group must follow the closing parentheses.
* That is, all element and group multipliers are assumed to be
* printed as subscripted numbers. [An exception to this rule
* exists for *.moiety formulae where pre- and post-multipliers
* are permitted for molecular units].
*
* 5. Unless the elements are ordered in a manner that corresponds to
* their chemical structure, as in _chemical_formula.structural,
* the order of the elements within any group or moiety
* depends on whether or not carbon is present. If carbon is
* present, the order should be: C, then H, then the other
* elements in alphabetical order of their symbol. If carbon is
* not present, the elements are listed purely in alphabetic order
* of their symbol. This is the 'Hill' system used by Chemical
* Abstracts. This ordering is used in _chemical_formula.moiety
* and _chemical_formula.sum.
*
* _chemical_formula.iupac '[Mo (C O)4 (C18 H33 P)2]'
* _chemical_formula.moiety 'C40 H66 Mo O4 P2'
* _chemical_formula.structural '((C O)4 (P (C6 H11)3)2)Mo'
* _chemical_formula.sum 'C40 H66 Mo O4 P2'
* _chemical_formula.weight 768.81
*/
chemical_formula: {
/**
* Formula with each discrete bonded residue or ion shown as a
* separate moiety. See above CHEMICAL_FORMULA for rules
* for writing chemical formulae. In addition to the general
* formulae requirements, the following rules apply:
* 1. Moieties are separated by commas ','.
* 2. The order of elements within a moiety follows general rule
* 5 in CHEMICAL_FORMULA.
* 3. Parentheses are not used within moieties but may surround
* a moiety. Parentheses may not be nested.
* 4. Charges should be placed at the end of the moiety. The
* Singlege '+' or '-' may be preceded by a numerical multiplier
* and should be separated from the last (element symbol +
* count) by a space. Pre- or post-multipliers may be used for
* individual moieties.
*/
moiety: str,
/**
* Chemical formulae in which all discrete bonded residues and ions are
* summed over the constituent elements, following the ordering given
* in rule 5 of the CATEGORY description. Parentheses normally not used.
*/
sum: str,
/**
* Mass corresponding to the formulae _chemical_formula.structural,
* *_iupac, *_moiety or *_sum and, together with the Z value and cell
* parameters yield the density given as _exptl_crystal.density_diffrn.
*/
weight: float,
},
/**
* The CATEGORY of data items used to specify space group
* information about the crystal used in the diffraction measurements.
*
* Space-group types are identified by their number as listed in
* International Tables for Crystallography Volume A, or by their
* Schoenflies symbol. Specific settings of the space groups can
* be identified by their Hall symbol, by specifying their
* symmetry operations or generators, or by giving the
* transformation that relates the specific setting to the
* reference setting based on International Tables Volume A and
* stored in this dictionary.
*
* The commonly used Hermann-Mauguin symbol determines the
* space-group type uniquely but several different Hermann-Mauguin
* symbols may refer to the same space-group type. A
* Hermann-Mauguin symbol contains information on the choice of
* the basis, but not on the choice of origin.
*
* Ref: International Tables for Crystallography (2002). Volume A,
* Space-group symmetry, edited by Th. Hahn, 5th ed.
* Dordrecht: Kluwer Academic Publishers.
*/
space_group: {
/**
* The name of the system of geometric crystal classes of space
* groups (crystal system) to which the space group belongs.
* Note that rhombohedral space groups belong to the
* trigonal system.
*/
crystal_system: str,
/**
* The full international Hermann-Mauguin space-group symbol as
* defined in Section 2.2.3 and given as the second item of the
* second line of each of the space-group tables of Part 7 of
* International Tables for Crystallography Volume A (2002).
*
* Each component of the space-group name is separated by a
* space or an underscore character. The use of a space is
* strongly recommended. The underscore is only retained
* because it was used in old CIFs. It should not be used in
* new CIFs.
*
* Subscripts should appear without special symbols. Bars should
* be given as negative signs before the numbers to which they
* apply. The commonly used Hermann-Mauguin symbol determines the
* space-group type uniquely but a given space-group type may
* be described by more than one Hermann-Mauguin symbol. The
* space-group type is best described using
* _space_group.IT_number or _space_group.name_Schoenflies. The
* full international Hermann-Mauguin symbol contains information
* about the choice of basis for monoclinic and orthorhombic
* space groups but does not give information about the choice
* of origin. To define the setting uniquely use
* _space_group.name_Hall, or list the symmetry operations
* or generators.
*
* Ref: International Tables for Crystallography (2002). Volume A,
* Space-group symmetry, edited by Th. Hahn, 5th ed.
* Dordrecht: Kluwer Academic Publishers.
*/
'name_H-M_full': str,
},
/**
* The CATEGORY of data items used to describe symmetry equivalent sites
* in the crystal unit cell.
*/
space_group_symop: {
/**
* A parsable string giving one of the symmetry operations of the
* space group in algebraic form. If W is a matrix representation
* of the rotational part of the symmetry operation defined by the
* positions and signs of x, y and z, and w is a column of
* translations defined by fractions, an equivalent position
* X' is generated from a given position X by the equation
*
* X' = WX + w
*
* (Note: X is used to represent bold_italics_x in International
* Tables for Crystallography Vol. A, Part 5)
*
* When a list of symmetry operations is given, it must contain
* a complete set of coordinate representatives which generates
* all the operations of the space group by the addition of
* all primitive translations of the space group. Such
* representatives are to be found as the coordinates of
* the general-equivalent position in International Tables for
* Crystallography Vol. A (2002), to which it is necessary to
* add any centring translations shown above the
* general-equivalent position.
*
* That is to say, it is necessary to list explicitly all the
* symmetry operations required to generate all the atoms in
* the unit cell defined by the setting used.
*/
operation_xyz: str,
},
/**
* The CATEGORY of data items used to specify the geometry bonds in the
* structural model as derived from the atomic sites.
*/
geom_bond: {
/**
* This label is a unique identifier for a particular site in the
* asymmetric unit of the crystal unit cell.
*/
atom_site_label_1: str,
/**
* This label is a unique identifier for a particular site in the
* asymmetric unit of the crystal unit cell.
*/
atom_site_label_2: str,
/**
* Intramolecular bond distance between the sites identified
* by _geom_bond.id
*/
distance: float,
/**
* This code signals whether the angle is referred to in a
* publication or should be placed in a table of significant angles.
*/
publ_flag: str,
/**
* The set of data items which specify the symmetry operation codes
* which must be applied to the atom sites involved in the geometry angle.
*
* The symmetry code of each atom site as the symmetry-equivalent position
* number 'n' and the cell translation number 'pqr'. These numbers are
* combined to form the code 'n pqr' or n_pqr.
*
* The character string n_pqr is composed as follows:
*
* n refers to the symmetry operation that is applied to the
* coordinates stored in _atom_site.fract_xyz. It must match a
* number given in _symmetry_equiv.pos_site_id.
*
* p, q and r refer to the translations that are subsequently
* applied to the symmetry transformed coordinates to generate
* the atom used in calculating the angle. These translations
* (x,y,z) are related to (p,q,r) by the relations
* p = 5 + x
* q = 5 + y
* r = 5 + z
*/
site_symmetry_2: str,
},
/**
* The CATEGORY of data items used to record details about the
* creation and subsequent updating of the data block.
*/
audit: {
/**
* The digital object identifier (DOI) registered to identify
* the data set publication represented by the current
* datablock. This can be used as a unique identifier for
* the datablock so long as the code used is a valid DOI
* (i.e. begins with a valid publisher prefix assigned by a
* Registration Agency and a suffix guaranteed to be unique
* by the publisher) and has had its metadata deposited
* with a DOI Registration Agency.
*
* A DOI is a unique character string identifying any
* object of intellectual property. It provides a
* persistent identifier for an object on a digital network
* and permits the association of related current data in a
* structured extensible way. A DOI is an implementation
* of the Internet concepts of Uniform Resource Name and
* Universal Resource Locator managed according to the
* specifications of the International DOI Foundation (see
* http://www.doi.org).
*/
block_doi: str,
},
/**
* The CATEGORY of data items recording database deposition. These data items
* are assigned by database managers and should only appear in a CIF if they
* originate from that source.
*/
database_code: {
/**
* Deposition numbers assigned by the Cambridge Crystallographic
* Data Centre (CCDC) to files containing structural information
* archived by the CCDC.
*/
depnum_ccdc_archive: str,
},
/**
* The CATEGORY of data items used to describe atom site information
* used in crystallographic structure studies.
*/
atom_site: {
/**
* Code for type of atomic displacement parameters used for the site.
*/
adp_type: str,
/**
* A standard code to signal if the site coordinates have been
* determined from the intensities or calculated from the geometry
* of surrounding sites, or have been assigned dummy coordinates.
*/
calc_flag: str,
/**
* A code which identifies a cluster of atoms that show long range
* positional disorder but are locally ordered. Within each such
* cluster of atoms, _atom_site.disorder_group is used to identify
* the sites that are simultaneously occupied. This field is only
* needed if there is more than one cluster of disordered atoms
* showing independent local order.
*/
disorder_assembly: str,
/**
* A code that identifies a group of positionally disordered atom
* sites that are locally simultaneously occupied. Atoms that are
* positionally disordered over two or more sites (e.g. the H
* atoms of a methyl group that exists in two orientations) can
* be assigned to two or more groups. Sites belonging to the same
* group are simultaneously occupied, but those belonging to
* different groups are not. A minus prefix (e.g. "-1") is used to
* indicate sites disordered about a special position.
*/
disorder_group: str,
/**
* Atom site coordinates as fractions of the cell length values.
*/
fract_x: float,
/**
* Atom site coordinates as fractions of the cell length values.
*/
fract_y: float,
/**
* Atom site coordinates as fractions of the cell length values.
*/
fract_z: float,
/**
* This label is a unique identifier for a particular site in the
* asymmetric unit of the crystal unit cell. It is made up of
* components, _atom_site.label_component_0 to *_6, which may be
* specified as separate data items. Component 0 usually matches one
* of the specified _atom_type.symbol codes. This is not mandatory
* if an _atom_site.type_symbol item is included in the atom site
* list. The _atom_site.type_symbol always takes precedence over
* an _atom_site.label in the identification of the atom type. The
* label components 1 to 6 are optional, and normally only
* components 0 and 1 are used. Note that components 0 and 1 are
* concatenated, while all other components, if specified, are
* separated by an underline character. Underline separators are
* only used if higher-order components exist. If an intermediate
* component is not used it may be omitted provided the underline
* separators are inserted. For example the label 'C233__ggg' is
* acceptable and represents the components C, 233, '', and ggg.
* Each label may have a different number of components.
*/
label: str,
/**
* The fraction of the atom type present at this site.
* The sum of the occupancies of all the atom types at this site
* may not significantly exceed 1.0 unless it is a dummy site. The
* value must lie in the 99.97% Gaussian confidence interval
* -3u =< x =< 1 + 3u. The _enumeration.range of 0.0:1.0 is thus
* correctly interpreted as meaning (0.0 - 3u) =< x =< (1.0 + 3u).
*/
occupancy: float,
/**
* A concatenated series of single-letter codes which indicate the
* refinement restraints or constraints applied to this site. This
* item should not be used. It has been replaced by
* _atom_site.refinement_flags_posn, _adp and _occupancy. It is
* retained in this dictionary only to provide compatibility with
* legacy CIFs.
*/
refinement_flags: str,
/**
* The number of different sites that are generated by the
* application of the space-group symmetry to the coordinates
* given for this site. It is equal to the multiplicity given
* for this Wyckoff site in International Tables for Cryst.
* Vol. A (2002). It is equal to the multiplicity of the general
* position divided by the order of the site symmetry given in
* _atom_site.site_symmetry_order.
*/
site_symmetry_multiplicity: int,
/**
* A code to identify the atom specie(s) occupying this site.
* This code must match a corresponding _atom_type.symbol. The
* specification of this code is optional if component_0 of the
* _atom_site.label is used for this purpose. See _atom_type.symbol.
*/
type_symbol: str,
/**
* Isotropic atomic displacement parameter, or equivalent isotropic
* atomic displacement parameter, U(equiv), in angstroms squared,
* calculated from anisotropic atomic displacement parameters.
*
* U(equiv) = (1/3) sum~i~[sum~j~(U^ij^ a*~i~ a*~j~ a~i~ a~j~)]
*
* a = the real-space cell lengths
* a* = the reciprocal-space cell lengths
* Ref: Fischer, R. X. & Tillmanns, E. (1988). Acta Cryst. C44, 775-776.
*/
U_iso_or_equiv: float,
},
/**
* The CATEGORY of data items used to describe the anisotropic
* thermal parameters of the atomic sites in a crystal structure.
*/
atom_site_aniso: {
/**
* Anisotropic atomic displacement parameters are usually looped in
* a separate list. If this is the case, this code must match the
* _atom_site.label of the associated atom in the atom coordinate
* list and conform with the same rules described in _atom_site.label.
*/
label: str,
/**
* These are the standard anisotropic atomic displacement
* components in angstroms squared which appear in the
* structure factor term:
*
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
*
* h = the Miller indices
* a* = the reciprocal-space cell lengths
*
* The unique elements of the real symmetric matrix are entered by row.
*/
U_11: float,
/**
* These are the standard anisotropic atomic displacement
* components in angstroms squared which appear in the
* structure factor term:
*
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
*
* h = the Miller indices
* a* = the reciprocal-space cell lengths
*
* The unique elements of the real symmetric matrix are entered by row.
*/
U_12: float,
/**
* These are the standard anisotropic atomic displacement
* components in angstroms squared which appear in the
* structure factor term:
*
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
*
* h = the Miller indices
* a* = the reciprocal-space cell lengths
*
* The unique elements of the real symmetric matrix are entered by row.
*/
U_13: float,
/**
* These are the standard anisotropic atomic displacement
* components in angstroms squared which appear in the
* structure factor term:
*
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
*
* h = the Miller indices
* a* = the reciprocal-space cell lengths
*
* The unique elements of the real symmetric matrix are entered by row.
*/
U_22: float,
/**
* These are the standard anisotropic atomic displacement
* components in angstroms squared which appear in the
* structure factor term:
*
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
*
* h = the Miller indices
* a* = the reciprocal-space cell lengths
*
* The unique elements of the real symmetric matrix are entered by row.
*/
U_23: float,
/**
* These are the standard anisotropic atomic displacement
* components in angstroms squared which appear in the
* structure factor term:
*
* T = exp{-2pi^2^ sum~i~ [sum~j~ (U^ij^ h~i~ h~j~ a*~i~ a*~j~) ] }
*
* h = the Miller indices
* a* = the reciprocal-space cell lengths
*
* The unique elements of the real symmetric matrix are entered by row.
*/
U_33: float,
},
/**
* The CATEGORY of data items used to describe atomic type information
* used in crystallographic structure studies.
*/
atom_type: {
/**
* A description of the atom(s) designated by this atom type. In
* most cases this will be the element name and oxidation state of
* a single atom species. For disordered or nonstoichiometric
* structures it will describe a combination of atom species.
*/
description: str,
/**
* The identity of the atom specie(s) representing this atom type.
* Normally this code is the element symbol followed by the charge
* if there is one. The symbol may be composed of any character except
* an underline or a blank, with the proviso that digits designate an
* oxidation state and must be followed by a + or - character.
*/
symbol: str,
},
/**
* The CATEGORY of data items used to describe atomic scattering
* information used in crystallographic structure studies.
*/
atom_type_scat: {
/**
* The imaginary component of the anomalous dispersion scattering factors
* for this atom type and radiation by _diffrn_radiation_wavelength.value
*/
dispersion_imag: float,
/**
* The real component of the anomalous dispersion scattering factors
* for this atom type and radiation by _diffrn_radiation_wavelength.value
*/
dispersion_real: float,
/**
* Reference to source of scattering factors used for this atom type.
*/
source: str,
},
}
export const cifCore_Aliases = {
'space_group.name_H-M_full': [
'symmetry_space_group_name_H-M',
],
'space_group_symop.operation_xyz': [
'symmetry_equiv_pos_as_xyz',
],
'geom_bond.atom_site_label_1': [
'geom_bond_atom_site_id_1',
],
'geom_bond.atom_site_label_2': [
'geom_bond_atom_site_id_2',
],
'geom_bond.distance': [
'geom_bond_dist',
],
'atom_site.adp_type': [
'atom_site_thermal_displace_type',
],
'atom_site.label': [
'atom_site_id',
],
'atom_site.site_symmetry_multiplicity': [
'atom_site_symmetry_multiplicity',
],
'atom_site_aniso.label': [
'atom_site_anisotrop_id',
],
'atom_site_aniso.U_11': [
'atom_site_anisotrop_U_11',
],
'atom_site_aniso.U_12': [
'atom_site_anisotrop_U_12',
],
'atom_site_aniso.U_13': [
'atom_site_anisotrop_U_13',
],
'atom_site_aniso.U_22': [
'atom_site_anisotrop_U_22',
],
'atom_site_aniso.U_23': [
'atom_site_anisotrop_U_23',
],
'atom_site_aniso.U_33': [
'atom_site_anisotrop_U_33',
],
}
export type cifCore_Schema = typeof cifCore_Schema;
export interface cifCore_Database extends Database<cifCore_Schema> {}

View File

@@ -1,7 +1,7 @@
/**
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.313, IHM 1.01, CARB draft.
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.318, IHM 1.04, CARB draft.
*
* @author molstar/ciftools package
*/
@@ -142,12 +142,12 @@ export const mmCIF_Schema = {
*/
id: int,
/**
* A component of the identifier for this atom site.
* For further details, see the definition of the ATOM_SITE_ALT
* category.
*
* This data item is a pointer to _atom_sites_alt.id in the
* ATOM_SITES_ALT category.
* A place holder to indicate alternate conformation. The alternate conformation
* can be an entire polymer chain, or several residues or
* partial residue (several atoms within one residue). If
* an atom is provided in more than one position, then a
* non-blank alternate location indicator must be used for
* each of the atomic positions.
*/
label_alt_id: str,
/**
@@ -213,6 +213,89 @@ export const mmCIF_Schema = {
*/
ihm_model_id: int,
},
/**
* Data items in the ATOM_SITE_ANISOTROP category record details
* about anisotropic displacement parameters.
* If the ATOM_SITE_ANISOTROP category is used for storing these
* data, the corresponding ATOM_SITE data items are not used.
*/
atom_site_anisotrop: {
/**
* This data item is a pointer to _atom_site.id in the ATOM_SITE
* category.
*/
id: int,
/**
* This data item is a pointer to _atom_type.symbol in the
* ATOM_TYPE category.
*/
type_symbol: str,
/**
* The elements of the standard anisotropic atomic
* displacement matrix U, which appears in the structure-factor
* term as:
*
* T = exp{-2 pi^2^ sum~i~[sum~j~(U^ij^ h~i~ h~j~ a*~i~ a*~j~)]}
*
* h = the Miller indices
* a* = the reciprocal space cell lengths
*
* These matrix elements may appear with atomic coordinates
* in the ATOM_SITE category, or they may appear in the separate
* ATOM_SITE_ANISOTROP category, but they may not appear in both
* places. Similarly, anisotropic displacements may appear as
* either B's or U's, but not as both.
*
* The unique elements of the real symmetric matrix are
* entered by row.
*/
U: Matrix(3, 3),
/**
* The standard uncertainty (estimated standard deviation)
* of _atom_site_anisotrop.U.
*/
U_esd: Matrix(3, 3),
/**
* Pointer to _atom_site.auth_seq_id
*/
pdbx_auth_seq_id: str,
/**
* Pointer to _atom_site.auth_asym_id
*/
pdbx_auth_asym_id: str,
/**
* Pointer to _atom_site.auth_atom_id
*/
pdbx_auth_atom_id: str,
/**
* Pointer to _atom_site.auth_comp_id
*/
pdbx_auth_comp_id: str,
/**
* Pointer to _atom_site.label_seq_id
*/
pdbx_label_seq_id: int,
/**
* Pointer to _atom_site.label_alt_id.
*/
pdbx_label_alt_id: str,
/**
* Pointer to _atom_site.label_asym_id
*/
pdbx_label_asym_id: str,
/**
* Pointer to _atom_site.label_atom_id
*/
pdbx_label_atom_id: str,
/**
* Pointer to _atom_site.label_comp_id
*/
pdbx_label_comp_id: str,
/**
* Pointer to _atom_site.pdbx_PDB_ins_code
*/
pdbx_PDB_ins_code: str,
},
/**
* Data items in the ATOM_SITES category record details about
* the crystallographic cell and cell transformations, which are
@@ -250,6 +333,50 @@ export const mmCIF_Schema = {
*/
fract_transf_vector: Vector(3),
},
/**
* Data items in the AUDIT_AUTHOR category record details about
* the author(s) of the data block.
*/
audit_author: {
/**
* The name of an author of this data block. If there are multiple
* authors, _audit_author.name is looped with _audit_author.address.
* The family name(s), followed by a comma and including any
* dynastic components, precedes the first name(s) or initial(s).
*/
name: str,
/**
* This data item defines the order of the author's name in the
* list of audit authors.
*/
pdbx_ordinal: int,
/**
* The Open Researcher and Contributor ID (ORCID).
*/
identifier_ORCID: str,
},
/**
* Data items in the AUDIT_CONFORM category describe the
* dictionary versions against which the data names appearing in
* the current data block are conformant.
*/
audit_conform: {
/**
* A file name or uniform resource locator (URL) for the
* dictionary to which the current data block conforms.
*/
dict_location: str,
/**
* The string identifying the highest-level dictionary defining
* data names used in this file.
*/
dict_name: str,
/**
* The version number of the dictionary to which the current
* data block conforms.
*/
dict_version: str,
},
/**
* Data items in the CELL category record details about the
* crystallographic cell parameters.
@@ -416,6 +543,143 @@ export const mmCIF_Schema = {
*/
pdbx_aromatic_flag: Aliased<'Y' | 'N'>(str),
},
/**
* Data items in the CITATION category record details about the
* literature cited as being relevant to the contents of the data
* block.
*/
citation: {
/**
* The name of the publisher of the citation; relevant
* for books or book chapters.
*/
book_publisher: str,
/**
* The country/region of publication; relevant for books
* and book chapters.
*/
country: str,
/**
* The value of _citation.id must uniquely identify a record in the
* CITATION list.
*
* The _citation.id 'primary' should be used to indicate the
* citation that the author(s) consider to be the most pertinent to
* the contents of the data block.
*
* Note that this item need not be a number; it can be any unique
* identifier.
*/
id: str,
/**
* Abbreviated name of the cited journal as given in the
* Chemical Abstracts Service Source Index.
*/
journal_abbrev: str,
/**
* The American Society for Testing and Materials (ASTM) code
* assigned to the journal cited (also referred to as the CODEN
* designator of the Chemical Abstracts Service); relevant for
* journal articles.
*/
journal_id_ASTM: str,
/**
* The Cambridge Structural Database (CSD) code assigned to the
* journal cited; relevant for journal articles. This is also the
* system used at the Protein Data Bank (PDB).
*/
journal_id_CSD: str,
/**
* The International Standard Serial Number (ISSN) code assigned to
* the journal cited; relevant for journal articles.
*/
journal_id_ISSN: str,
/**
* Volume number of the journal cited; relevant for journal
* articles.
*/
journal_volume: str,
/**
* The first page of the citation; relevant for journal
* articles, books and book chapters.
*/
page_first: str,
/**
* The last page of the citation; relevant for journal
* articles, books and book chapters.
*/
page_last: str,
/**
* The title of the citation; relevant for journal articles, books
* and book chapters.
*/
title: str,
/**
* The year of the citation; relevant for journal articles, books
* and book chapters.
*/
year: int,
/**
* Document Object Identifier used by doi.org to uniquely
* specify bibliographic entry.
*/
pdbx_database_id_DOI: str,
/**
* Ascession number used by PubMed to categorize a specific
* bibliographic entry.
*/
pdbx_database_id_PubMed: int,
},
/**
* Data items in the CITATION_AUTHOR category record details
* about the authors associated with the citations in the
* CITATION list.
*/
citation_author: {
/**
* This data item is a pointer to _citation.id in the CITATION
* category.
*/
citation_id: str,
/**
* Name of an author of the citation; relevant for journal
* articles, books and book chapters.
*
* The family name(s), followed by a comma and including any
* dynastic components, precedes the first name(s) or initial(s).
*/
name: str,
/**
* This data item defines the order of the author's name in the
* list of authors of a citation.
*/
ordinal: int,
},
/**
* Data items in the DATABASE_2 category record details about the
* database identifiers of the data block.
*
* These data items are assigned by database managers and should
* only appear in a data block if they originate from that source.
*
* The name of this category, DATABASE_2, arose because the
* category name DATABASE was already in use in the core CIF
* dictionary, but was used differently from the way it needed
* to be used in the mmCIF dictionary. Since CIF data names
* cannot be changed once they have been adopted, a new category
* had to be created.
*/
database_2: {
/**
* An abbreviation that identifies the database.
*/
database_id: Aliased<'CAS' | 'CSD' | 'EMDB' | 'ICSD' | 'MDF' | 'NDB' | 'NBS' | 'PDB' | 'PDF' | 'RCSB' | 'EBI' | 'PDBE' | 'BMRB' | 'WWPDB' | 'PDB_ACC'>(str),
/**
* The code assigned by the database identified in
* _database_2.database_id.
*/
database_code: str,
},
/**
* Data items in the ENTITY category record details (such as
* chemical composition, name and source) about the molecular
@@ -658,6 +922,11 @@ export const mmCIF_Schema = {
* and to distinguish this structural result from others.
*/
title: str,
/**
* An automatically generated descriptor for an NDB structure or
* the unstructured content of the PDB COMPND record.
*/
pdbx_descriptor: str,
},
/**
* Data items in the STRUCT_ASYM category record details about the
@@ -1597,6 +1866,20 @@ export const mmCIF_Schema = {
*/
content_type: Aliased<'minimized average structure' | 'representative structure' | 'ensemble' | 'derivative structure' | 'native structure' | 'associated EM volume' | 'other EM volume' | 'associated NMR restraints' | 'associated structure factors' | 'associated SAS data' | 'protein target sequence and/or protocol data' | 'split' | 're-refinement' | 'complete structure' | 'unspecified' | 'other'>(str),
},
pdbx_entity_nonpoly: {
/**
* This data item is a pointer to _entity.id in the ENTITY category.
*/
entity_id: str,
/**
* This data item is a pointer to _chem_comp.id in the CHEM_COMP category.
*/
comp_id: str,
/**
* A name for the non-polymer entity
*/
name: str,
},
/**
* Data items in the CHEM_COMP_IDENTIFIER category provide
* identifiers for chemical components.
@@ -2132,15 +2415,18 @@ export const mmCIF_Schema = {
* This data item is a pointer to _entity.id in the ENTITY category.
*/
entity_id: str,
/**
* Scientific name of the organism of the natural source.
*/
pdbx_organism_scientific: str,
/**
* The plasmid containing the gene.
*/
pdbx_plasmid_name: str,
/**
* This data item is an ordinal identifier for entity_src_nat data records.
*/
pdbx_src_id: int,
/**
* This data item identifies cases in which an alternative source
* modeled.
*/
pdbx_alt_source_flag: Aliased<'sample' | 'model'>(str),
/**
* The beginning polymer sequence position for the polymer section corresponding
* to this source.
@@ -2174,19 +2460,22 @@ export const mmCIF_Schema = {
* Identifies the gene.
*/
pdbx_gene_src_gene: List(',', x => x),
/**
* Scientific name of the organism.
*/
pdbx_gene_src_scientific_name: str,
/**
* The name of the plasmid that produced the entity in the host
* organism. Where full details of the protein production are available
* it would be expected that this item would be derived from
* _pdbx_construct.name of the construct pointed to from
* _entity_src_gen_express.plasmid_id.
*/
plasmid_name: str,
/**
* This data item is an ordinal identifier for entity_src_gen data records.
*/
pdbx_src_id: int,
/**
* This data item identifies cases in which an alternative source
* modeled.
*/
pdbx_alt_source_flag: Aliased<'sample' | 'model'>(str),
/**
* This data item povides additional information about the sequence type.
*/
pdbx_seq_type: Aliased<'N-terminal tag' | 'C-terminal tag' | 'Biological sequence' | 'Linker'>(str),
/**
* The beginning polymer sequence position for the polymer section corresponding
* to this source.
@@ -2207,6 +2496,11 @@ export const mmCIF_Schema = {
* about chemically synthesized molecules.
*/
pdbx_entity_src_syn: {
/**
* The scientific name of the organism from which the sequence of
* the synthetic entity was derived.
*/
organism_scientific: str,
/**
* This data item is a pointer to _entity.id in the ENTITY category.
*/
@@ -2215,11 +2509,6 @@ export const mmCIF_Schema = {
* This data item is an ordinal identifier for pdbx_entity_src_syn data records.
*/
pdbx_src_id: int,
/**
* This data item identifies cases in which an alternative source
* modeled.
*/
pdbx_alt_source_flag: Aliased<'sample' | 'model'>(str),
/**
* The beginning polymer sequence position for the polymer section corresponding
* to this source.
@@ -2967,7 +3256,7 @@ export const mmCIF_Schema = {
/**
* The type of data held in the dataset.
*/
data_type: Aliased<'NMR data' | '3DEM volume' | '2DEM class average' | 'EM raw micrographs' | 'SAS data' | 'CX-MS data' | 'Mass Spectrometry data' | 'EPR data' | 'H/D exchange data' | 'Single molecule FRET data' | 'Experimental model' | 'Comparative model' | 'Integrative model' | 'De Novo model' | 'Predicted contacts' | 'Mutagenesis data' | 'DNA footprinting data' | 'Hydroxyl radical footprinting data' | 'Yeast two-hybrid screening data' | 'Other'>(str),
data_type: Aliased<'NMR data' | '3DEM volume' | '2DEM class average' | 'EM raw micrographs' | 'SAS data' | 'CX-MS data' | 'Mass Spectrometry data' | 'EPR data' | 'H/D exchange data' | 'Single molecule FRET data' | 'Experimental model' | 'Comparative model' | 'Integrative model' | 'De Novo model' | 'Predicted contacts' | 'Mutagenesis data' | 'DNA footprinting data' | 'Hydroxyl radical footprinting data' | 'Yeast two-hybrid screening data' | 'Quantitative measurements of genetic interactions' | 'Other'>(str),
/**
* A flag that indicates whether the dataset is archived in
* an IHM related database or elsewhere.
@@ -3142,7 +3431,7 @@ export const mmCIF_Schema = {
*/
file_size_bytes: float,
/**
* Textual description of what the external file is.
* Additional textual details regarding the external file.
*/
details: str,
},
@@ -3376,7 +3665,7 @@ export const mmCIF_Schema = {
/**
* The type of crosslinker used.
*/
linker_type: Aliased<'EDC' | 'DSS' | 'EGS' | 'BS3' | 'BS2G' | 'DST' | 'sulfo-SDA' | 'sulfo-SMCC' | 'DSSO' | 'Other'>(str),
linker_type: Aliased<'EDC' | 'DSS' | 'EGS' | 'BS3' | 'BS2G' | 'DST' | 'sulfo-SDA' | 'sulfo-SMCC' | 'DSSO' | 'DSG' | 'BSP' | 'Other'>(str),
/**
* Identifier to the crosslinking dataset.
* This data item is a pointer to the _ihm_dataset_list.id in the

View File

@@ -1,7 +1,8 @@
/**
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
/**
@@ -23,7 +24,7 @@
*/
import * as Data from '../data-model'
import { Tokens, TokenBuilder } from '../../common/text/tokenizer'
import { Tokens, TokenBuilder, Tokenizer } from '../../common/text/tokenizer'
import { ReaderResult as Result } from '../../result'
import { Task, RuntimeContext, chunkedSubtask } from '../../../../mol-task'
@@ -46,6 +47,8 @@ interface TokenizerState {
position: number,
length: number,
isEscaped: boolean,
isImportGet: boolean,
inSaveFrame: boolean,
lineNumber: number,
tokenType: CifTokenType,
@@ -168,6 +171,23 @@ function eatMultiline(state: TokenizerState) {
return prev;
}
function eatImportGet(state: TokenizerState) {
// _import.get [{'save':orient_matrix 'file':templ_attr.cif}]
// skipWhitespace(state)
while (state.position < state.length) {
switch (state.data.charCodeAt(state.position)) {
case 93: // ]
++state.position;
state.tokenEnd = state.position;
state.isImportGet = false
return;
default:
++state.position;
break;
}
}
}
/**
* Skips until \n or \r occurs -- therefore the newlines get handled by the "skipWhitespace" function.
*/
@@ -274,6 +294,25 @@ function isLoop(state: TokenizerState): boolean {
return true;
}
function isImportGet(state: TokenizerState): boolean {
// _import.get [{'save':orient_matrix 'file':templ_attr.cif}]
if (state.tokenEnd - state.tokenStart !== 11) return false;
if (state.data.charCodeAt(state.tokenStart + 1) !== 105) return false; // i
if (state.data.charCodeAt(state.tokenStart + 2) !== 109) return false; // m
if (state.data.charCodeAt(state.tokenStart + 3) !== 112) return false; // p
if (state.data.charCodeAt(state.tokenStart + 4) !== 111) return false; // o
if (state.data.charCodeAt(state.tokenStart + 5) !== 114) return false; // r
if (state.data.charCodeAt(state.tokenStart + 6) !== 116) return false; // t
if (state.data.charCodeAt(state.tokenStart + 7) !== 46) return false; // .
if (state.data.charCodeAt(state.tokenStart + 8) !== 103) return false; // g
if (state.data.charCodeAt(state.tokenStart + 9) !== 101) return false; // e
if (state.data.charCodeAt(state.tokenStart + 10) !== 116) return false; // t
return true;
}
/**
* Checks if the current token shares the namespace with string at <start,end).
*/
@@ -315,6 +354,17 @@ function getNamespace(state: TokenizerState, endIndex: number) {
return state.data.substring(state.tokenStart, endIndex);
}
/**
* Returns true if the current token contain no '.', otherwise returns false.
*/
function isFlatNamespace(state: TokenizerState): boolean {
let i: number;
for (i = state.tokenStart; i < state.tokenEnd; ++i) {
if (state.data.charCodeAt(i) === 46) return false;
}
return true;
}
/**
* String representation of the current token.
*/
@@ -336,6 +386,7 @@ function moveNextInternal(state: TokenizerState) {
state.tokenStart = state.position;
state.tokenEnd = state.position;
state.isEscaped = false;
let c = state.data.charCodeAt(state.position);
switch (c) {
case 35: // #, comment
@@ -357,20 +408,28 @@ function moveNextInternal(state: TokenizerState) {
state.tokenType = CifTokenType.Value;
break;
default:
eatValue(state);
if (state.isImportGet) {
eatImportGet(state);
} else {
eatValue(state);
}
// escaped is always Value
if (state.isEscaped) {
state.tokenType = CifTokenType.Value;
// _ always means column name
// _ means column name, including _import.get
} else if (state.data.charCodeAt(state.tokenStart) === 95) { // _
if (state.inSaveFrame && isImportGet(state)) {
state.isImportGet = true
}
state.tokenType = CifTokenType.ColumnName;
// 5th char needs to be _ for data_ or loop_
// 5th char needs to be _ for data_, save_ or loop_
} else if (state.tokenEnd - state.tokenStart >= 5 && state.data.charCodeAt(state.tokenStart + 4) === 95) {
if (isData(state)) state.tokenType = CifTokenType.Data;
else if (isSave(state)) state.tokenType = CifTokenType.Save;
else if (isLoop(state)) state.tokenType = CifTokenType.Loop;
else state.tokenType = CifTokenType.Value;
// all other tests failed, we are at Value token.
// all other tests failed, we are at Value token.
} else {
state.tokenType = CifTokenType.Value;
}
@@ -396,6 +455,8 @@ function createTokenizer(data: string, runtimeCtx: RuntimeContext): TokenizerSta
tokenType: CifTokenType.End,
lineNumber: 1,
isEscaped: false,
isImportGet: false,
inSaveFrame: false,
runtimeCtx
};
@@ -410,13 +471,48 @@ interface CifCategoryResult {
errorMessage: string;
}
interface CifCategoryData {
name: string,
rowCount: number,
fieldNames: string[],
fields: { [name: string]: Data.CifField }
}
type FrameContext = {
categoryNames: string[],
categories: { [name: string]: Data.CifCategory }
categoryData: { [name: string]: CifCategoryData }
}
function FrameContext(): FrameContext {
return { categoryNames: [], categories: Object.create(null) };
return { categoryNames: [], categoryData: Object.create(null) };
}
function CifCategories(categoryNames: string[], categoryData: { [name: string]: CifCategoryData }): { [name: string]: Data.CifCategory } {
const categories = Object.create(null)
for (const name of categoryNames) {
const d = categoryData[name]
categories[name] = Data.CifCategory(d.name, d.rowCount, d.fieldNames, d.fields)
}
return categories
}
function CifBlock(ctx: FrameContext, header: string, saveFrames?: Data.CifFrame[]): Data.CifBlock {
return Data.CifBlock(ctx.categoryNames, CifCategories(ctx.categoryNames, ctx.categoryData), header, saveFrames)
}
function CifSaveFrame(ctx: FrameContext, header: string): Data.CifBlock {
return Data.CifBlock(ctx.categoryNames, CifCategories(ctx.categoryNames, ctx.categoryData), header)
}
function addFields(ctx: FrameContext, name: string, rowCount: number, fieldNames: string[], fields: { [k: string]: Data.CifField }) {
if (name in ctx.categoryData) {
const cat = ctx.categoryData[name]
cat.fieldNames.push(...fieldNames)
Object.assign(cat.fields, fields)
} else {
ctx.categoryData[name] = { name, rowCount, fieldNames, fields };
ctx.categoryNames.push(name);
}
}
/**
@@ -449,9 +545,7 @@ function handleSingle(tokenizer: TokenizerState, ctx: FrameContext): CifCategory
moveNext(tokenizer);
}
const catName = name.substr(1);
ctx.categories[catName] = Data.CifCategory(catName, 1, fieldNames, fields);
ctx.categoryNames.push(catName);
addFields(ctx, name.substr(1), 1, fieldNames, fields)
return {
hasError: false,
@@ -496,10 +590,13 @@ async function handleLoop(tokenizer: TokenizerState, ctx: FrameContext): Promise
moveNext(tokenizer);
const name = getNamespace(tokenizer, getNamespaceEnd(tokenizer));
const isFlat = isFlatNamespace(tokenizer);
const fieldNames: string[] = [];
while (tokenizer.tokenType === CifTokenType.ColumnName) {
fieldNames[fieldNames.length] = getTokenString(tokenizer).substring(name.length + 1);
fieldNames[fieldNames.length] = isFlat
? getTokenString(tokenizer)
: getTokenString(tokenizer).substring(name.length + 1);
moveNext(tokenizer);
}
@@ -526,14 +623,19 @@ async function handleLoop(tokenizer: TokenizerState, ctx: FrameContext): Promise
}
const rowCount = (state.tokenCount / fieldCount) | 0;
const fields = Object.create(null);
for (let i = 0; i < fieldCount; i++) {
fields[fieldNames[i]] = Data.CifField.ofTokens(tokens[i]);
}
if (isFlat) {
for (let i = 0; i < fieldCount; i++) {
const fields = { '': Data.CifField.ofTokens(tokens[i]) };
addFields(ctx, fieldNames[i].substr(1), rowCount, [''], fields)
}
} else {
const fields = Object.create(null);
for (let i = 0; i < fieldCount; i++) {
fields[fieldNames[i]] = Data.CifField.ofTokens(tokens[i]);
}
const catName = name.substr(1);
ctx.categories[catName] = Data.CifCategory(catName, rowCount, fieldNames, fields);
ctx.categoryNames.push(catName);
addFields(ctx, name.substr(1), rowCount, fieldNames, fields)
}
return {
hasError: false,
@@ -568,12 +670,14 @@ async function parseInternal(data: string, runtimeCtx: RuntimeContext) {
let blockCtx = FrameContext();
let inSaveFrame = false;
// the next three initial values are never used in valid files
let saveFrames: Data.CifFrame[] = [];
let saveCtx = FrameContext();
let saveFrame: Data.CifFrame = Data.CifSafeFrame(saveCtx.categoryNames, saveCtx.categories, '');
let saveFrame: Data.CifFrame = Data.CifSaveFrame(
saveCtx.categoryNames, CifCategories(saveCtx.categoryNames, saveCtx.categoryData), ''
);
let saveHeader = ''
runtimeCtx.update({ message: 'Parsing...', current: 0, max: data.length });
@@ -583,11 +687,11 @@ async function parseInternal(data: string, runtimeCtx: RuntimeContext) {
// Data block
if (token === CifTokenType.Data) {
if (inSaveFrame) {
if (tokenizer.inSaveFrame) {
return error(tokenizer.lineNumber, 'Unexpected data block inside a save frame.');
}
if (blockCtx.categoryNames.length > 0) {
dataBlocks.push(Data.CifBlock(blockCtx.categoryNames, blockCtx.categories, blockHeader, saveFrames));
dataBlocks.push(CifBlock(blockCtx, blockHeader, saveFrames));
}
blockHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
blockCtx = FrameContext();
@@ -595,47 +699,47 @@ async function parseInternal(data: string, runtimeCtx: RuntimeContext) {
moveNext(tokenizer);
// Save frame
} else if (token === CifTokenType.Save) {
const saveHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
if (saveHeader.length === 0) {
if (tokenizer.tokenEnd - tokenizer.tokenStart === 5) { // end of save frame
if (saveCtx.categoryNames.length > 0) {
saveFrames[saveFrames.length] = saveFrame;
saveFrames[saveFrames.length] = CifSaveFrame(saveCtx, saveHeader);
}
inSaveFrame = false;
} else {
if (inSaveFrame) {
tokenizer.inSaveFrame = false;
} else { // start of save frame
if (tokenizer.inSaveFrame) {
return error(tokenizer.lineNumber, 'Save frames cannot be nested.');
}
inSaveFrame = true;
const safeHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
tokenizer.inSaveFrame = true;
saveHeader = data.substring(tokenizer.tokenStart + 5, tokenizer.tokenEnd);
saveCtx = FrameContext();
saveFrame = Data.CifSafeFrame(saveCtx.categoryNames, saveCtx.categories, safeHeader);
// saveFrame = CifSaveFrame(saveCtx, saveHeader);
}
moveNext(tokenizer);
// Loop
} else if (token === CifTokenType.Loop) {
const cat = await handleLoop(tokenizer, inSaveFrame ? saveCtx : blockCtx);
const cat = await handleLoop(tokenizer, tokenizer.inSaveFrame ? saveCtx : blockCtx);
if (cat.hasError) {
return error(cat.errorLine, cat.errorMessage);
}
// Single row
} else if (token === CifTokenType.ColumnName) {
const cat = handleSingle(tokenizer, inSaveFrame ? saveCtx : blockCtx);
const cat = handleSingle(tokenizer, tokenizer.inSaveFrame ? saveCtx : blockCtx);
if (cat.hasError) {
return error(cat.errorLine, cat.errorMessage);
}
// Out of options
} else {
console.log(tokenizer.tokenType, Tokenizer.getTokenString(tokenizer))
return error(tokenizer.lineNumber, 'Unexpected token. Expected data_, loop_, or data name.');
}
}
// Check if the latest save frame was closed.
if (inSaveFrame) {
if (tokenizer.inSaveFrame) {
return error(tokenizer.lineNumber, `Unfinished save frame (${saveFrame.header}).`);
}
if (blockCtx.categoryNames.length > 0 || saveFrames.length > 0) {
dataBlocks.push(Data.CifBlock(blockCtx.categoryNames, blockCtx.categories, blockHeader, saveFrames));
dataBlocks.push(CifBlock(blockCtx, blockHeader, saveFrames));
}
return result(Data.CifFile(dataBlocks));

View File

@@ -174,7 +174,7 @@ function moveNextInternal(state: State) {
if (tokenizer.position >= tokenizer.length) {
state.tokenType = CsvTokenType.End;
return true;
return false;
}
tokenizer.tokenStart = tokenizer.position;
@@ -209,22 +209,26 @@ function moveNext(state: State) {
function readRecordsChunk(chunkSize: number, state: State) {
if (state.tokenType === CsvTokenType.End) return 0
let newRecord = moveNext(state);
if (newRecord) ++state.recordCount
let counter = 0;
let newRecord: boolean | undefined
const { tokens, tokenizer } = state;
let counter = 0;
while (state.tokenType === CsvTokenType.Value && counter < chunkSize) {
TokenBuilder.add(tokens[state.fieldCount % state.columnCount], tokenizer.tokenStart, tokenizer.tokenEnd);
++state.fieldCount
newRecord = moveNext(state);
if (newRecord) ++state.recordCount
++counter;
if (newRecord) {
++state.recordCount
++counter;
}
}
return counter;
}
function readRecordsChunks(state: State) {
let newRecord = moveNext(state);
if (newRecord) ++state.recordCount
return chunkedSubtask(state.runtimeCtx, 100000, state, readRecordsChunk,
(ctx, state) => ctx.update({ message: 'Parsing...', current: state.tokenizer.position, max: state.data.length }));
}

View File

@@ -124,7 +124,7 @@ namespace Sphere3D {
export function equals(a: Sphere3D, b: Sphere3D) {
const ar = a.radius;
const br = b.radius;
return (Math.abs(ar - br) <= EPSILON.Value * Math.max(1.0, Math.abs(ar), Math.abs(br)) &&
return (Math.abs(ar - br) <= EPSILON * Math.max(1.0, Math.abs(ar), Math.abs(br)) &&
Vec3.equals(a.center, b.center));
}
}

View File

@@ -1,17 +1,19 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 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 { Vec3, Mat4 } from '../../linear-algebra'
import { SpacegroupName, TransformData, GroupData, getSpacegroupIndex, OperatorData, SpacegroupNames } from './tables'
import { SpacegroupName, TransformData, GroupData, getSpacegroupIndex, OperatorData, SpacegroupNumber } from './tables'
import { SymmetryOperator } from '../../geometry';
interface SpacegroupCell {
// zero based spacegroup number
/** Index into spacegroup data table */
readonly index: number,
readonly size: Vec3,
readonly volume: number,
readonly anglesInRadians: Vec3,
/** Transfrom cartesian -> fractional coordinates within the cell */
readonly toFractional: Mat4,
@@ -20,7 +22,10 @@ interface SpacegroupCell {
}
interface Spacegroup {
/** Hermann-Mauguin spacegroup name */
readonly name: string,
/** Spacegroup number from International Tables for Crystallography */
readonly num: number,
readonly cell: SpacegroupCell,
readonly operators: ReadonlyArray<Mat4>
}
@@ -34,7 +39,7 @@ namespace SpacegroupCell {
return cell.index === 0 && cell.size[0] === 1 && cell.size[1] === 1 && cell.size[1] === 1;
}
// returns Zero cell if the spacegroup does not exist
/** Returns Zero cell if the spacegroup does not exist */
export function create(nameOrNumber: number | string | SpacegroupName, size: Vec3, anglesInRadians: Vec3): SpacegroupCell {
const index = getSpacegroupIndex(nameOrNumber);
if (index < 0) {
@@ -42,6 +47,8 @@ namespace SpacegroupCell {
return Zero;
}
const volume = size[0] * size[1] * size[2]
const alpha = anglesInRadians[0];
const beta = anglesInRadians[1];
const gamma = anglesInRadians[2];
@@ -64,32 +71,71 @@ namespace SpacegroupCell {
]);
const toFractional = Mat4.invert(Mat4.zero(), fromFractional)!;
return { index, size, anglesInRadians, toFractional, fromFractional };
return { index, size, volume, anglesInRadians, toFractional, fromFractional };
}
}
namespace Spacegroup {
// P1 with [1, 1, 1] cell.
/** P1 with [1, 1, 1] cell */
export const ZeroP1 = create(SpacegroupCell.Zero);
export function create(cell: SpacegroupCell): Spacegroup {
const operators = GroupData[cell.index].map(i => getOperatorMatrix(OperatorData[i]));
return { name: SpacegroupNames[cell.index], cell, operators };
const name = SpacegroupName[cell.index]
const num = SpacegroupNumber[cell.index]
return { name, num, cell, operators };
}
const _tempVec = Vec3.zero(), _tempMat = Mat4.zero();
export function updateOperatorMatrix(spacegroup: Spacegroup, index: number, i: number, j: number, k: number, target: Mat4) {
_tempVec[0] = i;
_tempVec[1] = j;
_tempVec[2] = k;
const _ijkVec = Vec3();
const _tempMat = Mat4();
export function setOperatorMatrix(spacegroup: Spacegroup, index: number, i: number, j: number, k: number, target: Mat4) {
Vec3.set(_ijkVec, i, j, k);
Mat4.fromTranslation(_tempMat, _tempVec);
return Mat4.mul(target, Mat4.mul(target, Mat4.mul(target, spacegroup.cell.fromFractional, _tempMat), spacegroup.operators[index]), spacegroup.cell.toFractional);
Mat4.fromTranslation(_tempMat, _ijkVec);
return Mat4.mul(
target,
Mat4.mul(
target,
Mat4.mul(target, spacegroup.cell.fromFractional, _tempMat),
spacegroup.operators[index]
),
spacegroup.cell.toFractional
);
}
export function getSymmetryOperator(spacegroup: Spacegroup, index: number, i: number, j: number, k: number): SymmetryOperator {
const operator = updateOperatorMatrix(spacegroup, index, i, j, k, Mat4.zero());
const operator = setOperatorMatrix(spacegroup, index, i, j, k, Mat4.zero());
return SymmetryOperator.create(`${index + 1}_${5 + i}${5 + j}${5 + k}`, operator, { id: '', operList: [] }, '', Vec3.create(i, j, k), index);
}
const _translationRef = Vec3()
const _translationRefSymop = Vec3()
const _translationSymop = Vec3()
export function setOperatorMatrixRef(spacegroup: Spacegroup, index: number, i: number, j: number, k: number, ref: Vec3, target: Mat4) {
Vec3.set(_ijkVec, i, j, k);
Vec3.floor(_translationRef, ref)
Mat4.copy(target, spacegroup.operators[index])
Vec3.floor(_translationRefSymop, Vec3.transformMat4(_translationRefSymop, ref, target))
Mat4.getTranslation(_translationSymop, target)
Vec3.sub(_translationSymop, _translationSymop, _translationRefSymop)
Vec3.add(_translationSymop, _translationSymop, _translationRef)
Vec3.add(_translationSymop, _translationSymop, _ijkVec)
Mat4.setTranslation(target, _translationSymop)
Mat4.mul(target, spacegroup.cell.fromFractional, target)
Mat4.mul(target, target, spacegroup.cell.toFractional)
return target
}
/**
* Get Symmetry operator for transformation around the given
* reference point `ref` in fractional coordinates
*/
export function getSymmetryOperatorRef(spacegroup: Spacegroup, index: number, i: number, j: number, k: number, ref: Vec3) {
const operator = setOperatorMatrixRef(spacegroup, index, i, j, k, ref, Mat4.zero());
return SymmetryOperator.create(`${index + 1}_${5 + i}${5 + j}${5 + k}`, operator, { id: '', operList: [] }, '', Vec3.create(i, j, k), index);
}

View File

@@ -1,7 +1,8 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 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>
*/
export const TransformData = [
@@ -31,26 +32,26 @@ export const TransformData = [
[0.0, 0.0, -1.0, 0.75],
[1.0, -1.0, 0.0, 0.0],
[-1.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.333333333333333],
[0.0, 0.0, 1.0, 0.666666666666667],
[1.0, 0.0, 0.0, 0.666666666666667],
[0.0, 1.0, 0.0, 0.333333333333333],
[0.0, -1.0, 0.0, 0.666666666666667],
[1.0, -1.0, 0.0, 0.333333333333333],
[-1.0, 1.0, 0.0, 0.666666666666667],
[-1.0, 0.0, 0.0, 0.333333333333333],
[1.0, 0.0, 0.0, 0.333333333333333],
[0.0, 1.0, 0.0, 0.666666666666667],
[0.0, -1.0, 0.0, 0.333333333333333],
[1.0, -1.0, 0.0, 0.666666666666667],
[-1.0, 1.0, 0.0, 0.333333333333333],
[-1.0, 0.0, 0.0, 0.666666666666667],
[0.0, 0.0, -1.0, 0.333333333333333],
[0.0, 0.0, -1.0, 0.666666666666667],
[0.0, 0.0, 1.0, 0.833333333333333],
[0.0, 0.0, 1.0, 0.166666666666667],
[0.0, 0.0, -1.0, 0.833333333333333],
[0.0, 0.0, -1.0, 0.166666666666667],
[0.0, 0.0, 1.0, 1/3],
[0.0, 0.0, 1.0, 2/3],
[1.0, 0.0, 0.0, 2/3],
[0.0, 1.0, 0.0, 1/3],
[0.0, -1.0, 0.0, 2/3],
[1.0, -1.0, 0.0, 1/3],
[-1.0, 1.0, 0.0, 2/3],
[-1.0, 0.0, 0.0, 1/3],
[1.0, 0.0, 0.0, 1/3],
[0.0, 1.0, 0.0, 2/3],
[0.0, -1.0, 0.0, 1/3],
[1.0, -1.0, 0.0, 2/3],
[-1.0, 1.0, 0.0, 1/3],
[-1.0, 0.0, 0.0, 2/3],
[0.0, 0.0, -1.0, 1/3],
[0.0, 0.0, -1.0, 2/3],
[0.0, 0.0, 1.0, 5/6],
[0.0, 0.0, 1.0, 1/6],
[0.0, 0.0, -1.0, 5/6],
[0.0, 0.0, -1.0, 1/6],
];
export const OperatorData = [
@@ -970,6 +971,16 @@ export const GroupData = [
[0, 52, 16, 1, 26, 59, 20, 65],
[0, 31, 1, 63],
[0, 1, 24, 62],
[0, 15, 1, 9], // 'P 1 21/n 1'
// X,Y,Z
// -X+1/2,Y+1/2,-Z+1/2
// -X,-Y,-Z
// X+1/2,-Y+1/2,Z+1/2
[0, 5, 1, 8], // 'P 1 21/a 1'
// X,Y,Z
// -X+1/2,Y+1/2,-Z
// -X,-Y,-Z
// X+1/2,-Y+1/2,Z
[0, 31, 1, 63, 26, 21, 65, 54],
[0, 2, 57, 56],
[0, 60, 3, 16],
@@ -985,7 +996,7 @@ export const GroupData = [
[0, 22, 57, 3, 159, 279, 654, 655, 158, 274, 656, 657, 29, 18, 25, 27, 284, 658, 262, 269, 280, 659, 257, 267],
];
export const ZeroBasedSpacegroupNumbers = {
export const SpacegroupNameToIndexMap = {
'P 1': 0,
'P -1': 1,
'P 1 2 1': 2,
@@ -1318,44 +1329,164 @@ export const ZeroBasedSpacegroupNumbers = {
'B 1 1 2/m': 250,
'P 1 1 2/b': 251,
'P 1 1 21/b': 252,
'B 1 1 2/b': 253,
'P 21 2 2': 254,
'P 2 21 2': 255,
'P 21 21 2 (a)': 256,
'P 21 2 21': 257,
'P 2 21 21': 258,
'C 2 2 21a)': 259,
'C 2 2 2a': 260,
'F 2 2 2a': 261,
'I 2 2 2a': 262,
'P 21/m 21/m 2/n a': 263,
'P 42 21 2a': 264,
'I 2 3a': 265,
'P 1 21/n 1': 253,
'P 1 21/a 1': 254,
'B 1 1 2/b': 255,
'P 21 2 2': 256,
'P 2 21 2': 257,
'P 21 21 2 (a)': 258,
'P 21 2 21': 259,
'P 2 21 21': 260,
'C 2 2 21a)': 261,
'C 2 2 2a': 262,
'F 2 2 2a': 263,
'I 2 2 2a': 264,
'P 21/m 21/m 2/n a': 265,
'P 42 21 2a': 266,
'I 2 3a': 267,
};
export type SpacegroupName = keyof typeof ZeroBasedSpacegroupNumbers
export function getSpacegroupIndexFromNumber(num: number) {
// 38 spacegroup variants as given CCP4s symop.lib
switch (num) {
case 1146: return 146
case 1148: return 149
case 1155: return 157
case 1160: return 163
case 1161: return 165
case 1166: return 171
case 1167: return 173
export const SpacegroupNames: { [num: number]: SpacegroupName } = (function () {
case 1003: return 237 // 'P 1 1 2' !(dyad along z)
case 1004: return 238 // 'P 1 1 21' !(unique axis c)
case 1005: return 239 // 'B 1 1 2' 'B 2'
case 2005: return 240 // 'A 1 2 1'
case 3005: return 241 // 'C 1 21 1' ! (Origin on screw at 1/4X)
case 4005: return 242 // 'I 1 2 1' 'I 2' !!! GJK @ 2003-06-02
case 5005: return 243 // 'I 1 21 1'
case 1006: return 244 // 'P 1 1 m'
case 1007: return 245 // 'P 1 1 b'
case 1008: return 246 // 'B 1 1 m'
case 1009: return 247 // 'B 1 1 b'
case 1010: return 248 // 'P 1 1 2/m'
case 1011: return 249 // 'P 1 1 21/m'
case 1012: return 250 // 'B 1 1 2/m'
case 1013: return 251 // 'P 1 1 2/b'
case 1014: return 252 // 'P 1 1 21/b'
case 2014: return 253 // 'P 1 21/n 1'
case 3014: return 254 // 'P 1 21/a 1'
case 1015: return 255 // 'B 1 1 2/b'
case 1017: return 256 // 'P 21 2 2' !(unique axis a)
case 2017: return 257 // 'P 2 21 2' !(unique axis b)
case 1018: return 258 // 'P 21 21 2 (a)' ! origin on 21 21, shift (1/4,1/4,0)
case 2018: return 259 // 'P 21 2 21' !(unique axis b)
case 3018: return 260 // 'P 2 21 21' !(unique axis a)
case 1020: return 261 // 'C 2 2 21a)' ! P212121 with C centring, shift(1/4,0,0)
case 1021: return 262 // 'C 2 2 2a' ! C21212a origin on 21 21
case 1022: return 263 // 'F 2 2 2a' ! same as 1018 with face centring shift (1/4,0,0)
case 1023: return 264 // 'I 2 2 2a' ! as 1018 with origin shift (1/4,1/4,1/4)
case 1059: return 265 // 'P 21/m 21/m 2/n a'
case 1094: return 266 // 'P 42 21 2a' ! (as P21212a) origin on 21 21 ie Shift 1/4,1/4,1/4
case 1197: return 267 // 'I 2 3a' ! Expansion of 1023 which is an expansion of 1018
}
let offset = 0
if (num > 146) ++offset
if (num > 148) ++offset
if (num > 155) ++offset
if (num > 160) ++offset
if (num > 161) ++offset
if (num > 166) ++offset
if (num > 167) ++offset
return num - 1 + offset
}
export function getSpacegroupNumberFromIndex(idx: number) {
if (idx < 146) return idx + 1
if (idx === 146) return 1146
if (idx < 149) return idx + 1 - 1
if (idx === 149) return 1148
if (idx < 157) return idx + 1 - 2
if (idx === 157) return 1155
if (idx < 163) return idx + 1 - 3
if (idx === 163) return 1160
if (idx < 165) return idx + 1 - 4
if (idx === 165) return 1161
if (idx < 171) return idx + 1 - 5
if (idx === 171) return 1166
if (idx < 173) return idx + 1 - 6
if (idx === 173) return 1167
if (idx < 237) return idx + 1 - 7
if (idx === 237) return 1003
if (idx === 238) return 1004
if (idx === 239) return 1005
if (idx === 240) return 2005
if (idx === 241) return 3005
if (idx === 242) return 4005
if (idx === 243) return 5005
if (idx === 244) return 1006
if (idx === 245) return 1007
if (idx === 246) return 1008
if (idx === 247) return 1009
if (idx === 248) return 1010
if (idx === 249) return 1011
if (idx === 250) return 1012
if (idx === 251) return 1013
if (idx === 252) return 1014
if (idx === 253) return 2014
if (idx === 254) return 3014
if (idx === 255) return 1015
if (idx === 256) return 1017
if (idx === 257) return 2017
if (idx === 258) return 1018
if (idx === 259) return 2018
if (idx === 260) return 3018
if (idx === 261) return 1020
if (idx === 262) return 1021
if (idx === 263) return 1022
if (idx === 264) return 1023
if (idx === 265) return 1059
if (idx === 266) return 1094
if (idx === 267) return 1197
throw new Error(`unknown spacegroup index '${idx}'`)
}
export type SpacegroupName = keyof typeof SpacegroupNameToIndexMap
/** Maps spacegroup index to Hermann-Mauguin spacegroup name */
export const SpacegroupName: { [idx: number]: SpacegroupName } = (function () {
const names = Object.create(null);
for (const n of Object.keys(ZeroBasedSpacegroupNumbers)) {
names[(ZeroBasedSpacegroupNumbers as any)[n]] = n;
for (const n of Object.keys(SpacegroupNameToIndexMap)) {
names[(SpacegroupNameToIndexMap as any)[n]] = n;
}
return names;
}());
// return -1 if the spacegroup does not exist.
export function getSpacegroupIndex(nameOrNumber: number | string | SpacegroupName): number {
let index: number
if (typeof nameOrNumber === 'number') {
// used by CCP4, see http://www.ccp4.ac.uk/html/pointless.html#setting
if (nameOrNumber === 1017) index = 254
else if (nameOrNumber === 2017) index = 255
else if (nameOrNumber === 2018) index = 257
else if (nameOrNumber === 3018) index = 258
else index = nameOrNumber - 1
} else {
index = ZeroBasedSpacegroupNumbers[nameOrNumber as SpacegroupName];
/** Maps spacegroup index to spacegroup number from International Tables for Crystallography */
export const SpacegroupNumber: { [idx: number]: number } = (function () {
const numbers = Object.create(null);
for (const n of Object.keys(SpacegroupNameToIndexMap)) {
const idx = (SpacegroupNameToIndexMap as any)[n]
numbers[idx] = getSpacegroupNumberFromIndex(idx);
}
if (typeof index === 'undefined' || typeof SpacegroupNames[index] === 'undefined') return -1;
return numbers;
}());
/** return -1 if the spacegroup does not exist */
export function getSpacegroupIndex(nameOrNumber: number | string | SpacegroupName): number {
const index = typeof nameOrNumber === 'number'
? getSpacegroupIndexFromNumber(nameOrNumber)
: SpacegroupNameToIndexMap[nameOrNumber as SpacegroupName];
if (typeof index === 'undefined' || typeof SpacegroupName[index] === 'undefined') return -1;
return index;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 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>
@@ -25,4 +25,10 @@ import Vec4 from './3d/vec4'
import Quat from './3d/quat'
import { EPSILON } from './3d/common'
export { Mat4, Mat3, Vec2, Vec3, Vec4, Quat, EPSILON }
export { Mat4, Mat3, Vec2, Vec3, Vec4, Quat, EPSILON }
export type Vec<T> =
T extends 4 ? Vec4 :
T extends 3 ? Vec3 :
T extends 2 ? Vec2 :
number[]

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 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>
@@ -17,7 +17,7 @@
* furnished to do so, subject to the following conditions:
*/
export const enum EPSILON { Value = 0.000001 }
export const EPSILON = 0.000001;
export function equalEps(a: number, b: number, eps: number) {
return Math.abs(a - b) <= eps;

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 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>
@@ -17,10 +17,11 @@
* furnished to do so, subject to the following conditions:
*/
import { Mat4 } from '../3d'
import { Mat4, Vec3, EPSILON } from '../3d'
import { NumberArray } from '../../../mol-util/type-helpers';
interface Mat3 extends Array<number> { [d: number]: number, '@type': 'mat3', length: 9 }
interface ReadonlyMat3 extends Array<number> { readonly [d: number]: number, '@type': 'mat3', length: 9 }
function Mat3() {
return Mat3.zero();
@@ -71,6 +72,7 @@ namespace Mat3 {
out[offset + 6] = a[6];
out[offset + 7] = a[7];
out[offset + 8] = a[8];
return out;
}
export function fromArray(a: Mat3, array: NumberArray, offset: number) {
@@ -102,6 +104,25 @@ namespace Mat3 {
return out;
}
export function create(a00: number, a01: number, a02: number, a10: number, a11: number, a12: number, a20: number, a21: number, a22: number): Mat3 {
const out = zero();
out[0] = a00
out[1] = a01
out[2] = a02
out[3] = a10
out[4] = a11
out[5] = a12
out[6] = a20
out[7] = a21
out[8] = a22
return out;
}
const _id = identity();
export function isIdentity(m: Mat3, eps?: number) {
return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON : eps);
}
export function hasNaN(m: Mat3) {
for (let i = 0; i < 9; i++) if (isNaN(m[i])) return true
return false
@@ -114,6 +135,13 @@ namespace Mat3 {
return Mat3.copy(Mat3.zero(), a);
}
export function areEqual(a: Mat3, b: Mat3, eps: number) {
for (let i = 0; i < 9; i++) {
if (Math.abs(a[i] - b[i]) > eps) return false;
}
return true;
}
export function setValue(a: Mat3, i: number, j: number, value: number) {
a[3 * j + i] = value;
}
@@ -198,6 +226,44 @@ namespace Mat3 {
return out;
}
export function symmtricFromUpper(out: Mat3, a: Mat3) {
if (out === a) {
out[3] = a[1];
out[6] = a[2];
out[7] = a[5];
} else {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[1];
out[4] = a[4];
out[5] = a[5];
out[6] = a[2];
out[7] = a[5];
out[8] = a[8];
}
return out;
}
export function symmtricFromLower(out: Mat3, a: Mat3) {
if (out === a) {
out[1] = a[3];
out[2] = a[6];
out[5] = a[7];
} else {
out[0] = a[0];
out[1] = a[3];
out[2] = a[6];
out[3] = a[3];
out[4] = a[4];
out[5] = a[7];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
}
return out;
}
export function determinant(a: Mat3) {
const a00 = a[0], a01 = a[1], a02 = a[2];
const a10 = a[3], a11 = a[4], a12 = a[5];
@@ -210,6 +276,172 @@ namespace Mat3 {
// Calculate the determinant
return a00 * b01 + a01 * b11 + a02 * b21;
}
export function trace(a: Mat3) {
return a[0] + a[4] + a[8]
}
export function sub(out: Mat3, a: Mat3, b: Mat3) {
out[0] = a[0] - b[0]
out[1] = a[1] - b[1]
out[2] = a[2] - b[2]
out[3] = a[3] - b[3]
out[4] = a[4] - b[4]
out[5] = a[5] - b[5]
out[6] = a[6] - b[6]
out[7] = a[7] - b[7]
out[8] = a[8] - b[8]
return out
}
export function add(out: Mat3, a: Mat3, b: Mat3) {
out[0] = a[0] + b[0]
out[1] = a[1] + b[1]
out[2] = a[2] + b[2]
out[3] = a[3] + b[3]
out[4] = a[4] + b[4]
out[5] = a[5] + b[5]
out[6] = a[6] + b[6]
out[7] = a[7] + b[7]
out[8] = a[8] + b[8]
return out
}
export function mul(out: Mat3, a: Mat3, b: Mat3) {
const a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8];
const b00 = b[0], b01 = b[1], b02 = b[2],
b10 = b[3], b11 = b[4], b12 = b[5],
b20 = b[6], b21 = b[7], b22 = b[8];
out[0] = b00 * a00 + b01 * a10 + b02 * a20;
out[1] = b00 * a01 + b01 * a11 + b02 * a21;
out[2] = b00 * a02 + b01 * a12 + b02 * a22;
out[3] = b10 * a00 + b11 * a10 + b12 * a20;
out[4] = b10 * a01 + b11 * a11 + b12 * a21;
out[5] = b10 * a02 + b11 * a12 + b12 * a22;
out[6] = b20 * a00 + b21 * a10 + b22 * a20;
out[7] = b20 * a01 + b21 * a11 + b22 * a21;
out[8] = b20 * a02 + b21 * a12 + b22 * a22;
return out;
}
export function subScalar(out: Mat3, a: Mat3, s: number) {
out[0] = a[0] - s
out[1] = a[1] - s
out[2] = a[2] - s
out[3] = a[3] - s
out[4] = a[4] - s
out[5] = a[5] - s
out[6] = a[6] - s
out[7] = a[7] - s
out[8] = a[8] - s
return out
}
export function addScalar(out: Mat3, a: Mat3, s: number) {
out[0] = a[0] + s
out[1] = a[1] + s
out[2] = a[2] + s
out[3] = a[3] + s
out[4] = a[4] + s
out[5] = a[5] + s
out[6] = a[6] + s
out[7] = a[7] + s
out[8] = a[8] + s
return out
}
export function mulScalar(out: Mat3, a: Mat3, s: number) {
out[0] = a[0] * s
out[1] = a[1] * s
out[2] = a[2] * s
out[3] = a[3] * s
out[4] = a[4] * s
out[5] = a[5] * s
out[6] = a[6] * s
out[7] = a[7] * s
out[8] = a[8] * s
return out
}
const piThird = Math.PI / 3
const tmpB = Mat3()
/**
* Given a real symmetric 3x3 matrix A, compute the eigenvalues
*
* From https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3.C3.973_matrices
*/
export function symmetricEigenvalues(out: Vec3, a: Mat3) {
const p1 = a[1] * a[1] + a[2] * a[2] + a[5] * a[5]
if (p1 === 0) {
out[0] = a[0]
out[1] = a[4]
out[2] = a[8]
} else {
const q = trace(a) / 3
const a1 = a[0] - q
const a2 = a[4] - q
const a3 = a[8] - q
const p2 = a1 * a1 + a2 * a2 + a3 * a3 + 2 * p1
const p = Math.sqrt(p2 / 6)
mulScalar(tmpB, Identity, q)
sub(tmpB, a, tmpB)
mulScalar(tmpB, tmpB, (1 / p))
const r = determinant(tmpB) / 2
// In exact arithmetic for a symmetric matrix -1 <= r <= 1
// but computation error can leave it slightly outside this range.
const phi = r <= -1 ? piThird : r >= 1 ?
0 : Math.acos(r) / 3
// the eigenvalues satisfy eig3 <= eig2 <= eig1
out[0] = q + 2 * p * Math.cos(phi)
out[2] = q + 2 * p * Math.cos(phi + (2 * piThird))
out[1] = 3 * q - out[0] - out[2] // since trace(A) = eig1 + eig2 + eig3
}
return out
}
const tmpR0 = [0.1, 0.0, 0.0] as Vec3
const tmpR1 = [0.1, 0.0, 0.0] as Vec3
const tmpR2 = [0.1, 0.0, 0.0] as Vec3
const tmpR0xR1 = [0.1, 0.0, 0.0] as Vec3
const tmpR0xR2 = [0.1, 0.0, 0.0] as Vec3
const tmpR1xR2 = [0.1, 0.0, 0.0] as Vec3
/**
* Calculates the eigenvector for the given eigenvalue `e` of matrix `a`
*/
export function eigenvector(out: Vec3, a: Mat3, e: number) {
Vec3.set(tmpR0, a[0] - e, a[1], a[2])
Vec3.set(tmpR1, a[1], a[4] - e, a[5])
Vec3.set(tmpR2, a[2], a[5], a[8] - e)
Vec3.cross(tmpR0xR1, tmpR0, tmpR1)
Vec3.cross(tmpR0xR2, tmpR0, tmpR2)
Vec3.cross(tmpR1xR2, tmpR1, tmpR2)
const d0 = Vec3.dot(tmpR0xR1, tmpR0xR1)
const d1 = Vec3.dot(tmpR0xR2, tmpR0xR2)
const d2 = Vec3.dot(tmpR1xR2, tmpR1xR2)
let dmax = d0
let imax = 0
if (d1 > dmax) {
dmax = d1
imax = 1
}
if (d2 > dmax) imax = 2
if (imax === 0) {
Vec3.scale(out, tmpR0xR1, 1 / Math.sqrt(d0))
} else if (imax === 1) {
Vec3.scale(out, tmpR0xR2, 1 / Math.sqrt(d1))
} else {
Vec3.scale(out, tmpR1xR2, 1 / Math.sqrt(d2))
}
return out
}
export const Identity: ReadonlyMat3 = identity()
}
export default Mat3

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 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>
@@ -101,7 +101,7 @@ namespace Mat4 {
const _id = identity();
export function isIdentity(m: Mat4, eps?: number) {
return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON.Value : eps);
return areEqual(m, _id, typeof eps === 'undefined' ? EPSILON : eps);
}
export function hasNaN(m: Mat4) {
@@ -141,6 +141,7 @@ namespace Mat4 {
out[offset + 13] = a[13];
out[offset + 14] = a[14];
out[offset + 15] = a[15];
return out;
}
export function fromArray(a: Mat4, array: NumberArray, offset: number) {
@@ -499,7 +500,7 @@ namespace Mat4 {
b10, b11, b12,
b20, b21, b22;
if (Math.abs(len) < EPSILON.Value) {
if (Math.abs(len) < EPSILON) {
return Mat4.identity();
}
@@ -549,7 +550,7 @@ namespace Mat4 {
len = Math.sqrt(x * x + y * y + z * z),
s, c, t;
if (Math.abs(len) < EPSILON.Value) { return setIdentity(out); }
if (Math.abs(len) < EPSILON) { return setIdentity(out); }
len = 1 / len;
x *= len;
@@ -719,7 +720,7 @@ namespace Mat4 {
* [ 0 1 ]
*/
export function isRotationAndTranslation(a: Mat4, eps?: number) {
return _isRotationAndTranslation(a, typeof eps !== 'undefined' ? eps : EPSILON.Value)
return _isRotationAndTranslation(a, typeof eps !== 'undefined' ? eps : EPSILON)
}
function _isRotationAndTranslation(a: Mat4, eps: number) {
@@ -854,9 +855,9 @@ namespace Mat4 {
const centery = center[1];
const centerz = center[2];
if (Math.abs(eyex - centerx) < EPSILON.Value &&
Math.abs(eyey - centery) < EPSILON.Value &&
Math.abs(eyez - centerz) < EPSILON.Value
if (Math.abs(eyex - centerx) < EPSILON &&
Math.abs(eyey - centery) < EPSILON &&
Math.abs(eyez - centerz) < EPSILON
) {
return setIdentity(out);
}

View File

@@ -28,6 +28,7 @@ import { EPSILON } from './common';
import { NumberArray } from '../../../mol-util/type-helpers';
interface Quat extends Array<number> { [d: number]: number, '@type': 'quat', length: 4 }
interface ReadonlyQuat extends Array<number> { readonly [d: number]: number, '@type': 'quat', length: 4 }
function Quat() {
return Quat.zero();
@@ -281,7 +282,7 @@ namespace Quat {
export function fromUnitVec3 (out: Quat, a: Vec3, b: Vec3) {
// assumes a and b are normalized
let r = Vec3.dot(a, b) + 1
if (r < EPSILON.Value) {
if (r < EPSILON) {
// If u and v are exactly opposite, rotate 180 degrees
// around an arbitrary orthogonal axis. Axis normalisation
// can happen later, when we normalise the quaternion.
@@ -318,6 +319,7 @@ namespace Quat {
out[offset + 1] = a[1];
out[offset + 2] = a[2];
out[offset + 3] = a[3];
return out;
}
export function fromArray(a: Quat, array: NumberArray, offset: number) {
@@ -439,6 +441,8 @@ namespace Quat {
export function toString(a: Quat, precision?: number) {
return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)} ${a[3].toPrecision(precision)}]`;
}
export const Identity: ReadonlyQuat = identity()
}
export default Quat

View File

@@ -53,6 +53,7 @@ namespace Vec2 {
export function toArray(a: Vec2, out: NumberArray, offset: number) {
out[offset + 0] = a[0];
out[offset + 1] = a[1];
return out;
}
export function fromArray(a: Vec2, array: NumberArray, offset: number) {

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -23,6 +23,7 @@ import { spline as _spline, quadraticBezier as _quadraticBezier, clamp } from '.
import { NumberArray } from '../../../mol-util/type-helpers';
interface Vec3 extends Array<number> { [d: number]: number, '@type': 'vec3', length: 3 }
interface ReadonlyVec3 extends Array<number> { readonly [d: number]: number, '@type': 'vec3', length: 3 }
function Vec3() {
return Vec3.zero();
@@ -73,6 +74,7 @@ namespace Vec3 {
out[offset + 0] = v[0]
out[offset + 1] = v[1]
out[offset + 2] = v[2]
return out
}
export function create(x: number, y: number, z: number): Vec3 {
@@ -490,19 +492,18 @@ namespace Vec3 {
export function equals(a: Vec3, b: Vec3) {
const a0 = a[0], a1 = a[1], a2 = a[2];
const b0 = b[0], b1 = b[1], b2 = b[2];
return (Math.abs(a0 - b0) <= EPSILON.Value * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= EPSILON.Value * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= EPSILON.Value * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
}
const rotTemp = zero();
const flipScaling = create(-1, -1, -1);
export function makeRotation(mat: Mat4, a: Vec3, b: Vec3): Mat4 {
const by = angle(a, b);
if (Math.abs(by) < 0.0001) return Mat4.setIdentity(mat);
if (Math.abs(by - Math.PI) < EPSILON.Value) {
if (Math.abs(by - Math.PI) < EPSILON) {
// here, axis can be [0,0,0] but the rotation is a simple flip
return Mat4.fromScaling(mat, flipScaling);
return Mat4.fromScaling(mat, negUnit);
}
const axis = cross(rotTemp, a, b);
return Mat4.fromRotation(mat, by, axis);
@@ -524,6 +525,16 @@ namespace Vec3 {
return normalize(out, cross(out, cross(out, a, b), a));
}
/**
* Get a vector like `a` that point into the same general direction as `b`,
* i.e. where the dot product is > 0
*/
export function matchDirection(out: Vec3, a: Vec3, b: Vec3) {
if (Vec3.dot(a, b) > 0) Vec3.copy(out, a)
else Vec3.negate(out, Vec3.copy(out, a))
return out
}
const triangleNormalTmpAB = zero();
const triangleNormalTmpAC = zero();
/** Calculate normal for the triangle defined by `a`, `b` and `c` */
@@ -536,6 +547,9 @@ namespace Vec3 {
export function toString(a: Vec3, precision?: number) {
return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)}]`;
}
export const unit: ReadonlyVec3 = Vec3.create(1, 1, 1)
export const negUnit: ReadonlyVec3 = Vec3.create(-1, -1, -1)
}
export default Vec3

View File

@@ -62,6 +62,7 @@ namespace Vec4 {
out[offset + 1] = a[1];
out[offset + 2] = a[2];
out[offset + 3] = a[3];
return out;
}
export function fromArray(a: Vec4, array: NumberArray, offset: number) {
@@ -220,10 +221,10 @@ namespace Vec4 {
export function equals(a: Vec4, b: Vec4) {
const a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
const b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
return (Math.abs(a0 - b0) <= EPSILON.Value * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= EPSILON.Value * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= EPSILON.Value * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= EPSILON.Value * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)));
}
export function toString(a: Vec4, precision?: number) {

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Mat3, Vec3 } from '../3d'
describe('Mat3', () => {
it('symmetricEigenvalues', () => {
const m = Mat3.create(
0.1945, -0.0219, -0.0416,
-0.0219, 0.1995, -0.0119,
-0.0416, -0.0119, 0.3673
)
const e = Vec3.create(0.377052701425898, 0.21713981522725134, 0.1671074833468507)
expect(Vec3.equals(e, Mat3.symmetricEigenvalues(Vec3(), m))).toBe(true);
});
it('eigenvectors', () => {
const m = Mat3.create(
0.1945, -0.0219, -0.0416,
-0.0219, 0.1995, -0.0119,
-0.0416, -0.0119, 0.3673
)
const e = Vec3.create(0.377052701425898, 0.21713981522725134, 0.1671074833468507)
const v0 = Vec3.create(-0.2176231019882068, -0.038522620041966125, 0.9752723687391808)
const v1 = Vec3.create(-0.5905636938047126, 0.8007524989198634, -0.10014968314142503)
const v2 = Vec3.create(0.7770937582036648, 0.5977553372576602, 0.19701230352667118)
expect(Vec3.equals(v0, Mat3.eigenvector(Vec3(), m, e[0]))).toBe(true);
expect(Vec3.equals(v1, Mat3.eigenvector(Vec3(), m, e[1]))).toBe(true);
expect(Vec3.equals(v2, Mat3.eigenvector(Vec3(), m, e[2]))).toBe(true);
});
});

View File

@@ -1,47 +1,74 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { NumberArray } from '../../../mol-util/type-helpers';
import { Vec } from '../3d';
interface Matrix { data: NumberArray, size: number, cols: number, rows: number }
interface Matrix<N extends number = number, M extends number = number> {
data: NumberArray,
size: number,
cols: N,
rows: M
}
namespace Matrix {
export function create(cols: number, rows: number, ctor: { new (size: number): NumberArray } = Float32Array): Matrix {
export function create<N extends number, M extends number>(cols: N, rows: M, ctor: { new (size: number): NumberArray } = Float32Array): Matrix<N, M> {
const size = cols * rows
return { data: new ctor(size), size, cols, rows }
}
/** Get element assuming data are stored in column-major order */
export function get(m: Matrix, i: number, j: number) { return m.data[m.rows * j + i]; }
/** Set element assuming data are stored in column-major order */
export function set(m: Matrix, i: number, j: number, value: number) { m.data[m.rows * j + i] = value; }
/** Add to element assuming data are stored in column-major order */
export function add(m: Matrix, i: number, j: number, value: number) { m.data[m.rows * j + i] += value; }
/** Zero out the matrix */
export function makeZero(m: Matrix) {
for (let i = 0, _l = m.data.length; i < _l; i++) m.data[i] = 0.0;
export function get(m: Matrix, i: number, j: number) {
return m.data[m.rows * j + i];
}
export function fromArray(data: NumberArray, cols: number, rows: number): Matrix {
/** Set element assuming data are stored in column-major order */
export function set<N extends number, M extends number>(m: Matrix<N, M>, i: number, j: number, value: number) {
m.data[m.rows * j + i] = value;
return m
}
/** Add to element assuming data are stored in column-major order */
export function add<N extends number, M extends number>(m: Matrix<N, M>, i: number, j: number, value: number) {
m.data[m.rows * j + i] += value;
return m
}
/** Zero out the matrix */
export function makeZero<N extends number, M extends number>(m: Matrix<N, M>) {
m.data.fill(0.0)
return m
}
export function clone<N extends number, M extends number>(m: Matrix<N, M>): Matrix<N, M> {
return { data: m.data.slice(), size: m.size, cols: m.cols, rows: m.rows }
}
export function fromArray<N extends number, M extends number>(data: NumberArray, cols: N, rows: M): Matrix<N, M> {
return { data, size: cols * rows, cols, rows }
}
export function transpose(out: Matrix, mat: Matrix): Matrix {
export function transpose<N extends number, M extends number>(out: Matrix<M, N>, mat: Matrix<N, M>): Matrix<M, N> {
if (out.cols !== mat.rows || out.rows !== mat.cols) {
throw new Error('transpose: matrix dimensions incompatible')
}
if (out.data === mat.data) {
throw new Error('transpose: matrices share memory')
}
const nrows = mat.rows, ncols = mat.cols
const md = mat.data, mtd = out.data
for (let i = 0, mi = 0, mti = 0; i < nrows; mti += 1, mi += ncols, ++i) {
let ri = mti
for (let j = 0; j < ncols; ri += nrows, j++) mtd[ri] = md[mi + j]
}
return mat
return out
}
/** out = matA * matB' */
export function multiplyABt (out: Matrix, matA: Matrix, matB: Matrix) {
export function multiplyABt<NA extends number, NB extends number, M extends number>(out: Matrix<M, M>, matA: Matrix<NA, M>, matB: Matrix<NB, M>): Matrix<M, M> {
const ncols = matA.cols, nrows = matA.rows, mrows = matB.rows
const ad = matA.data, bd = matB.data, cd = out.data
@@ -59,10 +86,10 @@ namespace Matrix {
}
/** Get the mean of rows in `mat` */
export function meanRows (mat: Matrix) {
export function meanRows<N extends number, M extends number, V extends Vec<N>>(mat: Matrix<N, M>): V {
const nrows = mat.rows, ncols = mat.cols
const md = mat.data
const mean = new Array(ncols)
const mean = new Array(ncols) as V
for (let j = 0; j < ncols; ++j) mean[ j ] = 0.0
for (let i = 0, p = 0; i < nrows; ++i) {
@@ -74,7 +101,7 @@ namespace Matrix {
}
/** Subtract `row` from all rows in `mat` */
export function subRows (mat: Matrix, row: NumberArray) {
export function subRows<N extends number, M extends number>(mat: Matrix<N, M>, row: NumberArray) {
const nrows = mat.rows, ncols = mat.cols
const md = mat.data

View File

@@ -1,21 +1,17 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import Matrix from './matrix';
import { Vec3 } from '../3d';
// import { Vec3, Mat4 } from '../3d.js';
import { Vec3, Mat4 } from '../3d';
import { svd } from './svd';
import { NumberArray } from '../../../mol-util/type-helpers';
// const negateVector = Vec3.create(-1, -1, -1)
// const tmpMatrix = Mat4.identity()
export { PrincipalAxes }
/**
* Principal axes
*/
class PrincipalAxes {
interface PrincipalAxes {
begA: Vec3
endA: Vec3
begB: Vec3
@@ -32,14 +28,15 @@ class PrincipalAxes {
normVecA: Vec3
normVecB: Vec3
normVecC: Vec3
}
namespace PrincipalAxes {
/**
* points is a 3xN matrix
* @param points 3xN matrix
*/
constructor(points: Matrix) {
export function ofPoints(points: Matrix<3, number>): PrincipalAxes {
const n = points.rows
const n3 = n / 3
const pointsT = Matrix.create(n, 3)
const A = Matrix.create(3, 3)
const W = Matrix.create(1, 3)
const U = Matrix.create(3, 3)
@@ -47,145 +44,102 @@ class PrincipalAxes {
// calculate
const mean = Matrix.meanRows(points)
Matrix.subRows(points, mean)
Matrix.transpose(pointsT, points)
const pointsM = Matrix.subRows(Matrix.clone(points), mean)
const pointsT = Matrix.transpose(Matrix.create(n, 3), pointsM)
Matrix.multiplyABt(A, pointsT, pointsT)
svd(A, W, U, V)
// center
const vm = Vec3.create(mean[0], mean[1], mean[2])
const center = Vec3.create(mean[0], mean[1], mean[2])
// normalized
const van = Vec3.create(U.data[0], U.data[3], U.data[6])
const vbn = Vec3.create(U.data[1], U.data[4], U.data[7])
const vcn = Vec3.create(U.data[2], U.data[5], U.data[8])
const normVecA = Vec3.create(U.data[0], U.data[3], U.data[6])
const normVecB = Vec3.create(U.data[1], U.data[4], U.data[7])
const normVecC = Vec3.create(U.data[2], U.data[5], U.data[8])
// scaled
const va = Vec3.scale(Vec3.zero(), van, Math.sqrt(W.data[0] / n3))
const vb = Vec3.scale(Vec3.zero(), vbn, Math.sqrt(W.data[1] / n3))
const vc = Vec3.scale(Vec3.zero(), vcn, Math.sqrt(W.data[2] / n3))
// const va = van.clone().multiplyScalar(Math.sqrt(W.data[0] / n3))
// const vb = vbn.clone().multiplyScalar(Math.sqrt(W.data[1] / n3))
// const vc = vcn.clone().multiplyScalar(Math.sqrt(W.data[2] / n3))
const vecA = Vec3.scale(Vec3(), normVecA, Math.sqrt(W.data[0] / n3))
const vecB = Vec3.scale(Vec3(), normVecB, Math.sqrt(W.data[1] / n3))
const vecC = Vec3.scale(Vec3(), normVecC, Math.sqrt(W.data[2] / n3))
// points
this.begA = Vec3.sub(Vec3.clone(vm), vm, va)
this.endA = Vec3.add(Vec3.clone(vm), vm, va)
this.begB = Vec3.sub(Vec3.clone(vm), vm, vb)
this.endB = Vec3.add(Vec3.clone(vm), vm, vb)
this.begC = Vec3.sub(Vec3.clone(vm), vm, vc)
this.endC = Vec3.add(Vec3.clone(vm), vm, vc)
// this.begA = vm.clone().sub(va)
// this.endA = vm.clone().add(va)
// this.begB = vm.clone().sub(vb)
// this.endB = vm.clone().add(vb)
// this.begC = vm.clone().sub(vc)
// this.endC = vm.clone().add(vc)
const begA = Vec3.sub(Vec3.clone(center), center, vecA)
const endA = Vec3.add(Vec3.clone(center), center, vecA)
const begB = Vec3.sub(Vec3.clone(center), center, vecB)
const endB = Vec3.add(Vec3.clone(center), center, vecB)
const begC = Vec3.sub(Vec3.clone(center), center, vecC)
const endC = Vec3.add(Vec3.clone(center), center, vecC)
//
this.center = vm
this.vecA = va
this.vecB = vb
this.vecC = vc
this.normVecA = van
this.normVecB = vbn
this.normVecC = vcn
return {
begA, endA, begB, endB, begC, endC,
center,
vecA, vecB, vecC,
normVecA, normVecB, normVecC
}
}
// TODO
// /**
// * Get the basis matrix descriping the axes
// * @param {Matrix4} [optionalTarget] - target object
// * @return {Matrix4} the basis
// */
// getBasisMatrix(optionalTarget = new Matrix4()) {
// const basis = optionalTarget
/**
* Set basis matrix for given axes
*/
export function setBasisMatrix(out: Mat4, principalAxes: PrincipalAxes) {
Mat4.setAxes(out, principalAxes.normVecB, principalAxes.normVecA, principalAxes.normVecC)
if (Mat4.determinant(out) < 0) Mat4.scaleUniformly(out, out, -1)
return out
}
// basis.makeBasis(this.normVecB, this.normVecA, this.normVecC)
// if (basis.determinant() < 0) {
// basis.scale(negateVector)
// }
/**
* Get the scale/length for each dimension for a box around the axes
* to enclose the given positions
*/
export function getProjectedScale(positions: NumberArray, principalAxes: PrincipalAxes) {
let d1a = -Infinity
let d1b = -Infinity
let d2a = -Infinity
let d2b = -Infinity
let d3a = -Infinity
let d3b = -Infinity
// return basis
// }
const p = Vec3()
const t = Vec3()
// TODO
// /**
// * Get a quaternion descriping the axes rotation
// * @param {Quaternion} [optionalTarget] - target object
// * @return {Quaternion} the rotation
// */
// getRotationQuaternion(optionalTarget = new Quaternion()) {
// const q = optionalTarget
// q.setFromRotationMatrix(this.getBasisMatrix(tmpMatrix))
const { center, normVecA, normVecB, normVecC } = principalAxes
// return q.inverse()
// }
for (let i = 0, il = positions.length; i < il; i += 3) {
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecA, center)
const dp1 = Vec3.dot(normVecA, Vec3.normalize(t, Vec3.sub(t, p, center)))
const dt1 = Vec3.distance(p, center)
if (dp1 > 0) {
if (dt1 > d1a) d1a = dt1
} else {
if (dt1 > d1b) d1b = dt1
}
// TODO
// /**
// * Get the scale/length for each dimension for a box around the axes
// * to enclose the atoms of a structure
// * @param {Structure|StructureView} structure - the structure
// * @return {{d1a: Number, d2a: Number, d3a: Number, d1b: Number, d2b: Number, d3b: Number}} scale
// */
// getProjectedScaleForAtoms(structure: Structure) {
// let d1a = -Infinity
// let d1b = -Infinity
// let d2a = -Infinity
// let d2b = -Infinity
// let d3a = -Infinity
// let d3b = -Infinity
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecB, center)
const dp2 = Vec3.dot(normVecB, Vec3.normalize(t, Vec3.sub(t, p, center)))
const dt2 = Vec3.distance(p, center)
if (dp2 > 0) {
if (dt2 > d2a) d2a = dt2
} else {
if (dt2 > d2b) d2b = dt2
}
// const p = new Vector3()
// const t = new Vector3()
Vec3.projectPointOnVector(p, Vec3.fromArray(p, positions, i), normVecC, center)
const dp3 = Vec3.dot(normVecC, Vec3.normalize(t, Vec3.sub(t, p, center)))
const dt3 = Vec3.distance(p, center)
if (dp3 > 0) {
if (dt3 > d3a) d3a = dt3
} else {
if (dt3 > d3b) d3b = dt3
}
}
// const center = this.center
// const ax1 = this.normVecA
// const ax2 = this.normVecB
// const ax3 = this.normVecC
// structure.eachAtom(function (ap: AtomProxy) {
// projectPointOnVector(p.copy(ap as any), ax1, center) // TODO
// const dp1 = t.subVectors(p, center).normalize().dot(ax1)
// const dt1 = p.distanceTo(center)
// if (dp1 > 0) {
// if (dt1 > d1a) d1a = dt1
// } else {
// if (dt1 > d1b) d1b = dt1
// }
// projectPointOnVector(p.copy(ap as any), ax2, center)
// const dp2 = t.subVectors(p, center).normalize().dot(ax2)
// const dt2 = p.distanceTo(center)
// if (dp2 > 0) {
// if (dt2 > d2a) d2a = dt2
// } else {
// if (dt2 > d2b) d2b = dt2
// }
// projectPointOnVector(p.copy(ap as any), ax3, center)
// const dp3 = t.subVectors(p, center).normalize().dot(ax3)
// const dt3 = p.distanceTo(center)
// if (dp3 > 0) {
// if (dt3 > d3a) d3a = dt3
// } else {
// if (dt3 > d3b) d3b = dt3
// }
// })
// return {
// d1a: d1a,
// d2a: d2a,
// d3a: d3a,
// d1b: -d1b,
// d2b: -d2b,
// d3b: -d3b
// }
// }
}
export default PrincipalAxes
return {
d1a: d1a,
d2a: d2a,
d3a: d3a,
d1b: -d1b,
d2b: -d2b,
d3b: -d3b
}
}
}

View File

@@ -56,40 +56,36 @@ export namespace Tensor {
export function ColumnMajorMatrix(rows: number, cols: number, ctor?: ArrayCtor) { return Space([rows, cols], [1, 0], ctor); }
export function RowMajorMatrix(rows: number, cols: number, ctor?: ArrayCtor) { return Space([rows, cols], [0, 1], ctor); }
export function toMat4(space: Space, data: Tensor.Data): Mat4 {
export function toMat4(out: Mat4, space: Space, data: Tensor.Data): Mat4 {
if (space.rank !== 2) throw new Error('Invalid tensor rank');
const mat = Mat4.zero();
const d0 = Math.min(4, space.dimensions[0]), d1 = Math.min(4, space.dimensions[1]);
for (let i = 0; i < d0; i++) {
for (let j = 0; j < d1; j++) Mat4.setValue(mat, i, j, space.get(data, i, j));
for (let j = 0; j < d1; j++) Mat4.setValue(out, i, j, space.get(data, i, j));
}
return mat;
return out;
}
export function toMat3(space: Space, data: Tensor.Data): Mat3 {
export function toMat3(out: Mat3, space: Space, data: Tensor.Data): Mat3 {
if (space.rank !== 2) throw new Error('Invalid tensor rank');
const mat = Mat3.zero();
const d0 = Math.min(3, space.dimensions[0]), d1 = Math.min(3, space.dimensions[1]);
for (let i = 0; i < d0; i++) {
for (let j = 0; j < d1; j++) Mat3.setValue(mat, i, j, space.get(data, i, j));
for (let j = 0; j < d1; j++) Mat3.setValue(out, i, j, space.get(data, i, j));
}
return mat;
return out;
}
export function toVec3(space: Space, data: Tensor.Data): Vec3 {
export function toVec3(out: Vec3, space: Space, data: Tensor.Data): Vec3 {
if (space.rank !== 1) throw new Error('Invalid tensor rank');
const vec = Vec3.zero();
const d0 = Math.min(3, space.dimensions[0]);
for (let i = 0; i < d0; i++) vec[i] = data[i];
return vec;
for (let i = 0; i < d0; i++) out[i] = data[i];
return out;
}
export function toVec4(space: Space, data: Tensor.Data): Vec4 {
export function toVec4(out: Vec4, space: Space, data: Tensor.Data): Vec4 {
if (space.rank !== 1) throw new Error('Invalid tensor rank');
const vec = Vec4.zero();
const d0 = Math.min(4, space.dimensions[0]);
for (let i = 0; i < d0; i++) vec[i] = data[i];
return vec;
for (let i = 0; i < d0; i++) out[i] = data[i];
return out;
}
export function areEqualExact(a: Tensor.Data, b: Tensor.Data) {

View File

@@ -14,4 +14,19 @@ export function radToDeg (rad: number) {
export function isPowerOfTwo (x: number) {
return (x !== 0) && (x & (x - 1)) === 0
}
/** return the value that has the largest absolute value */
export function absMax(...values: number[]) {
let max = 0
let absMax = 0
for (let i = 0, il = values.length; i < il; ++i) {
const value = values[i]
const abs = Math.abs(value)
if (abs > absMax) {
max = value
absMax = abs
}
}
return max
}

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Model } from '../../mol-model/structure/model';
import { Task } from '../../mol-task';
import { ModelFormat } from './format';
import { _parse_mmCif } from './mmcif/parser';
import { CifCategory, CifField } from '../../mol-io/reader/cif';
import { Column } from '../../mol-data/db';
import { mmCIF_Schema } from '../../mol-io/reader/cif/schema/mmcif';
import { EntityBuilder } from './common/entity';
import { File3DG } from '../../mol-io/reader/3dg/parser';
import { fillSerial } from '../../mol-util/array';
import { MoleculeType } from '../../mol-model/structure/model/types';
function getCategories(table: File3DG['table']) {
const entityIds = new Array<string>(table._rowCount)
const entityBuilder = new EntityBuilder()
const seqIdStarts = table.position.toArray({ array: Uint32Array })
const seqIdEnds = new Uint32Array(table._rowCount)
const stride = seqIdStarts[1] - seqIdStarts[0]
const objectRadius = stride / 3500
for (let i = 0, il = table._rowCount; i < il; ++i) {
const chr = table.chromosome.value(i)
const entityId = entityBuilder.getEntityId(chr, MoleculeType.DNA, chr)
entityIds[i] = entityId
seqIdEnds[i] = seqIdStarts[i] + stride - 1
}
const ihm_sphere_obj_site: CifCategory.SomeFields<mmCIF_Schema['ihm_sphere_obj_site']> = {
id: CifField.ofNumbers(fillSerial(new Uint32Array(table._rowCount))),
entity_id: CifField.ofStrings(entityIds),
seq_id_begin: CifField.ofNumbers(seqIdStarts),
seq_id_end: CifField.ofNumbers(seqIdEnds),
asym_id: CifField.ofColumn(table.chromosome),
Cartn_x: CifField.ofNumbers(Column.mapToArray(table.x, x => x * 10, Float32Array)),
Cartn_y: CifField.ofNumbers(Column.mapToArray(table.y, y => y * 10, Float32Array)),
Cartn_z: CifField.ofNumbers(Column.mapToArray(table.z, z => z * 10, Float32Array)),
object_radius: CifField.ofColumn(Column.ofConst(objectRadius, table._rowCount, Column.Schema.float)),
rmsf: CifField.ofColumn(Column.ofConst(0, table._rowCount, Column.Schema.float)),
model_id: CifField.ofColumn(Column.ofConst(1, table._rowCount, Column.Schema.int)),
}
return {
entity: entityBuilder.getEntityCategory(),
ihm_model_list: CifCategory.ofFields('ihm_model_list', {
model_id: CifField.ofNumbers([1]),
model_name: CifField.ofStrings(['3DG Model']),
}),
ihm_sphere_obj_site: CifCategory.ofFields('ihm_sphere_obj_site', ihm_sphere_obj_site)
}
}
async function mmCifFrom3dg(file3dg: File3DG) {
const categories = getCategories(file3dg.table)
return {
header: '3DG',
categoryNames: Object.keys(categories),
categories
};
}
export function trajectoryFrom3DG(file3dg: File3DG): Task<Model.Trajectory> {
return Task.create('Parse 3DG', async ctx => {
await ctx.update('Converting to mmCIF');
const cif = await mmCifFrom3dg(file3dg);
const format = ModelFormat.mmCIF(cif);
return _parse_mmCif(format, ctx);
})
}

View File

@@ -0,0 +1,70 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { CIF } from '../../../mol-io/reader/cif';
const cifCoreString = `data_n1379
_audit_block_doi 10.5517/ccy42jn
_database_code_depnum_ccdc_archive 'CCDC 867861'
loop_
_citation_id
_citation_doi
_citation_year
1 10.1002/chem.201202070 2012
_audit_update_record
;
2012-02-20 deposited with the CCDC.
2016-10-08 downloaded from the CCDC.
;
loop_
_atom_type_symbol
_atom_type_description
_atom_type_scat_dispersion_real
_atom_type_scat_dispersion_imag
_atom_type_scat_source
C C 0.0181 0.0091 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
H H 0.0000 0.0000 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
N N 0.0311 0.0180 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
O O 0.0492 0.0322 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
F F 0.0727 0.0534 'International Tables Vol C Tables 4.2.6.8 and 6.1.1.4'
_cell_length_a 11.0829(8)
_cell_length_b 14.6829(10)
_cell_length_c 16.8532(17)
_cell_angle_alpha 105.728(6)
_cell_angle_beta 100.310(6)
_cell_angle_gamma 110.620(4)
_cell_volume 2353.3(3)
_cell_formula_units_Z 1
_cell_measurement_temperature 100(2)
_cell_measurement_reflns_used 5934
_cell_measurement_theta_min 2.86
_cell_measurement_theta_max 64.30
`
describe('cif-core read', () => {
it('frame', async () => {
const parsed = await CIF.parseText(cifCoreString).run()
if (parsed.isError) return
const cifFile = parsed.result
const block = cifFile.blocks[0]
expect(block.getField('cell_length_a')!.float(0)).toBe(11.0829)
expect.assertions(1)
});
it('schema', async () => {
const parsed = await CIF.parseText(cifCoreString).run()
if (parsed.isError) return
const cifFile = parsed.result
const block = cifFile.blocks[0]
const cifCore = CIF.schema.cifCore(block)
expect(cifCore.cell.length_a.value(0)).toBe(11.0829)
expect.assertions(1)
});
});

View File

@@ -30,7 +30,7 @@ export class EntityBuilder {
}
getEntityId(compId: string, moleculeType: MoleculeType, chainId: string): string {
if (moleculeType === MoleculeType.water) {
if (moleculeType === MoleculeType.Water) {
if (this.waterId === undefined) {
this.set('water', 'Water')
this.waterId = `${this.count}`

View File

@@ -36,7 +36,7 @@ function getCategories(atoms: GroAtoms) {
let currentAsymIndex = 0
let currentAsymId = ''
let currentSeqId = 0
let prevMoleculeType = MoleculeType.unknown
let prevMoleculeType = MoleculeType.Unknown
let prevResidueNumber = -1
for (let i = 0, il = atoms.count; i < il; ++i) {

View File

@@ -0,0 +1,89 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Table } from '../../../mol-data/db';
import { Model, CustomPropertyDescriptor } from '../../../mol-model/structure';
import { mmCIF_Schema } from '../../../mol-io/reader/cif/schema/mmcif';
import { CifWriter } from '../../../mol-io/writer/cif';
export interface AtomSiteAnisotrop {
data: Table<AtomSiteAnisotrop.Schema['atom_site_anisotrop']>
/** maps atom_site-index to atom_site_anisotrop-index */
elementToAnsiotrop: Int32Array
}
export namespace AtomSiteAnisotrop {
export function getAtomSiteAnisotrop(model: Model) {
if (model.sourceData.kind !== 'mmCIF') return void 0;
const { atom_site_anisotrop } = model.sourceData.data
return Table.ofColumns(Schema.atom_site_anisotrop, atom_site_anisotrop);
}
export const PropName = '__AtomSiteAnisotrop__';
export function get(model: Model): AtomSiteAnisotrop | undefined {
if (model._staticPropertyData[PropName]) return model._staticPropertyData[PropName]
if (!model.customProperties.has(Descriptor)) return void 0;
const data = getAtomSiteAnisotrop(model);
if (!data) return void 0;
const prop = { data, elementToAnsiotrop: getElementToAnsiotrop(model, data) }
set(model, prop)
return prop;
}
function set(model: Model, prop: AtomSiteAnisotrop) {
(model._staticPropertyData[PropName] as AtomSiteAnisotrop) = prop;
}
export const Schema = { atom_site_anisotrop: mmCIF_Schema['atom_site_anisotrop'] };
export type Schema = typeof Schema
export const Descriptor: CustomPropertyDescriptor = {
isStatic: true,
name: 'atom_site_anisotrop',
cifExport: {
prefix: '',
categories: [{
name: 'atom_site_anisotrop',
instance(ctx) {
const atom_site_anisotrop = getAtomSiteAnisotrop(ctx.firstModel);
if (!atom_site_anisotrop) return CifWriter.Category.Empty;
return CifWriter.Category.ofTable(atom_site_anisotrop);
}
}]
}
};
function getElementToAnsiotrop(model: Model, data: Table<Schema['atom_site_anisotrop']>) {
const { atomId } = model.atomicConformation
const atomIdToElement = new Int32Array(atomId.rowCount)
atomIdToElement.fill(-1)
for (let i = 0, il = atomId.rowCount; i < il; i++) {
atomIdToElement[atomId.value(i)] = i
}
const { id } = data
const elementToAnsiotrop = new Int32Array(atomId.rowCount)
elementToAnsiotrop.fill(-1)
for (let i = 0, il = id.rowCount; i < il; ++i) {
const ei = atomIdToElement[id.value(i)]
if (ei !== -1) elementToAnsiotrop[ei] = i
}
return elementToAnsiotrop
}
export async function attachFromMmCif(model: Model) {
if (model.customProperties.has(Descriptor)) return true;
if (model.sourceData.kind !== 'mmCIF') return false;
const atomSiteAnisotrop = getAtomSiteAnisotrop(model);
if (!atomSiteAnisotrop || atomSiteAnisotrop._rowCount === 0) return false;
model.customProperties.add(Descriptor);
return true;
}
}

View File

@@ -4,7 +4,7 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Mat4, Tensor } from '../../../mol-math/linear-algebra'
import { Mat4, Tensor, Vec3 } from '../../../mol-math/linear-algebra'
import { SymmetryOperator } from '../../../mol-math/geometry/symmetry-operator'
import { Assembly, OperatorGroup, OperatorGroups } from '../../../mol-model/structure/model/properties/symmetry'
import { Queries as Q } from '../../../mol-model/structure'
@@ -76,8 +76,8 @@ function getMatrices({ data }: mmCIF_Format): Matrices {
const matrices = new Map<string, Mat4>();
for (let i = 0, _i = pdbx_struct_oper_list._rowCount; i < _i; i++) {
const m = Tensor.toMat4(_schema.matrix.space, matrix.value(i));
const t = Tensor.toVec3(_schema.vector.space, vector.value(i));
const m = Tensor.toMat4(Mat4(), _schema.matrix.space, matrix.value(i));
const t = Tensor.toVec3(Vec3(), _schema.vector.space, vector.value(i));
Mat4.setTranslation(m, t);
Mat4.setValue(m, 3, 3, 1);
matrices.set(id.value(i), m);

View File

@@ -1,7 +1,8 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 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 { Column, Table } from '../../../mol-data/db';
@@ -14,7 +15,6 @@ import { AtomicConformation, AtomicData, AtomicHierarchy, AtomicSegments, AtomsS
import { getAtomicIndex } from '../../../mol-model/structure/model/properties/utils/atomic-index';
import { ElementSymbol } from '../../../mol-model/structure/model/types';
import { Entities } from '../../../mol-model/structure/model/properties/common';
import { getAtomicRanges } from '../../../mol-model/structure/model/properties/utils/atomic-ranges';
import { getAtomicDerivedData } from '../../../mol-model/structure/model/properties/utils/atomic-derived';
import { FormatData } from './parser';
@@ -26,15 +26,15 @@ function findHierarchyOffsets(atom_site: AtomSite) {
const start = 0, end = atom_site._rowCount;
const residues = [start as ElementIndex], chains = [start as ElementIndex];
const { label_entity_id, label_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code, label_comp_id } = atom_site;
const { label_entity_id, label_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code } = atom_site;
for (let i = start + 1 as ElementIndex; i < end; i++) {
const newChain = !label_entity_id.areValuesEqual(i - 1, i) || !label_asym_id.areValuesEqual(i - 1, i);
const newResidue = newChain
|| !label_seq_id.areValuesEqual(i - 1, i)
|| !auth_seq_id.areValuesEqual(i - 1, i)
|| !pdbx_PDB_ins_code.areValuesEqual(i - 1, i)
|| !label_comp_id.areValuesEqual(i - 1, i);
|| !pdbx_PDB_ins_code.areValuesEqual(i - 1, i);
// not checking label_comp_id to allow for MICROHETEROGENEITY
if (newResidue) residues[residues.length] = i as ElementIndex;
if (newChain) chains[chains.length] = i as ElementIndex;
@@ -42,6 +42,15 @@ function findHierarchyOffsets(atom_site: AtomSite) {
return { residues, chains };
}
function substUndefinedColumn<T extends Table<any>>(table: T, a: keyof T, b: keyof T) {
if (!(table as any)[a].isDefined) {
(table as any)[a] = (table as any)[b];
}
if (!(table as any)[b].isDefined) {
(table as any)[b] = (table as any)[a];
}
}
function createHierarchyData(atom_site: AtomSite, sourceIndex: Column<number>, offsets: { residues: ArrayLike<number>, chains: ArrayLike<number> }): AtomicData {
const atoms = Table.ofColumns(AtomsSchema, {
type_symbol: Column.ofArray({ array: Column.mapToArray(atom_site.type_symbol, ElementSymbol), schema: Column.Schema.Aliased<ElementSymbol>(Column.Schema.str) }),
@@ -51,11 +60,20 @@ function createHierarchyData(atom_site: AtomSite, sourceIndex: Column<number>, o
pdbx_formal_charge: atom_site.pdbx_formal_charge,
sourceIndex
});
const residues = Table.view(atom_site, ResiduesSchema, offsets.residues);
// Optimize the numeric columns
Table.columnToArray(residues, 'label_seq_id', Int32Array);
Table.columnToArray(residues, 'auth_seq_id', Int32Array);
const chains = Table.view(atom_site, ChainsSchema, offsets.chains);
// Fix possibly missing auth_/label_ columns
substUndefinedColumn(residues, 'label_seq_id', 'auth_seq_id');
substUndefinedColumn(atoms, 'label_atom_id', 'auth_atom_id');
substUndefinedColumn(residues, 'label_comp_id', 'auth_comp_id');
substUndefinedColumn(chains, 'label_asym_id', 'auth_asym_id');
return { atoms, residues, chains };
}
@@ -99,7 +117,6 @@ export function getAtomicHierarchyAndConformation(atom_site: AtomSite, sourceInd
const index = getAtomicIndex(hierarchyData, entities, hierarchySegments);
const derived = getAtomicDerivedData(hierarchyData, index, formatData.chemicalComponentMap);
const hierarchyRanges = getAtomicRanges(hierarchyData, hierarchySegments, conformation, index, derived.residue.moleculeType);
const hierarchy: AtomicHierarchy = { ...hierarchyData, ...hierarchySegments, ...hierarchyRanges, index, derived };
const hierarchy: AtomicHierarchy = { ...hierarchyData, ...hierarchySegments, index, derived };
return { sameAsPrevious: false, hierarchy, conformation };
}

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