Compare commits

...

684 Commits

Author SHA1 Message Date
Alexander Rose
64c72aa6f5 0.5.0-dev.3 2020-02-20 10:56:21 -08:00
Alexander Rose
0a22917773 add unknown/any DNA/RNA base names N/DN 2020-02-20 10:23:39 -08:00
David Sehnal
3c4888e52b mol-canvas3d: tweak commit and camera reset 2020-02-20 12:55:21 +01:00
Alexander Rose
9d31f1ba07 0.5.0-dev.2 2020-02-19 16:13:55 -08:00
David Sehnal
d722d17a02 mol-gl: partial scene commit support 2020-02-19 22:19:17 +01:00
Alexander Rose
522d929f5a handle UNK as amino acid 2020-02-19 10:32:03 -08:00
David Sehnal
42037074cb fix unitTransforms visual state updating 2020-02-19 16:49:14 +01:00
David Sehnal
1e3f17efdf disable selection/highlight when animating/updating 2020-02-19 16:10:19 +01:00
David Sehnal
7389e0075d mol-canvas/gl: refactored scene add/remove object sync 2020-02-19 15:20:38 +01:00
David Sehnal
a080114690 added Structure property to StructureElement and Bond locations 2020-02-19 13:31:42 +01:00
Alexander Rose
1293848d9b refactored ModelFormat
- convert to mmCIF only when needed
- added gro, psf, 3dg formats
2020-02-18 17:11:31 -08:00
Alexander Rose
16b2d9e873 add .ofStringAliasArray and .ofStringListArray to Column 2020-02-18 17:08:03 -08:00
Alexander Rose
7a64334261 split mmcif parser into basic part and properties
- basic part is for hierarchy and conformation
- properties is for any additional info

first commit of refactoring with the aim to make the format parsing more modular and be clear about what data is actually needed for the basic part and for properties
2020-02-18 14:20:47 -08:00
Alexander Rose
009b20c95a uuid docs 2020-02-18 14:17:17 -08:00
Alexander Rose
296bea1b88 added AtomicIndex.findEntity 2020-02-18 14:16:46 -08:00
Alexander Rose
e0775607cc added Table.ofPartialColumns 2020-02-18 14:05:36 -08:00
Alexander Rose
a1fb4b8bf3 support loading multiple files at once
- OpenFiles state action
- file-list param definition
2020-02-14 10:47:05 -08:00
Alexander Rose
29ae78c193 assembly symmetry: use https 2020-02-14 09:34:50 -08:00
Alexander Rose
46cfb42cce seperated autoAttach from property params in custom property transform 2020-02-13 15:09:35 -08:00
Alexander Rose
94ef9f4dbe struct_conn refactoring
- explicitely between two partners
- use symmetry in intra-unit compute (important, before there where wrong hbonds in e.g. 1XJ9)
2020-02-13 11:03:42 -08:00
David Sehnal
b864e992ef mol-io: CIF triple quote support 2020-02-13 16:31:11 +01:00
Alexander Rose
57ed9a4226 updated cif schemas 2020-02-12 18:50:52 -08:00
Alexander Rose
b2c93cbeda add option to ignore issues types in geo quality coloring 2020-02-12 12:29:44 -08:00
Alexander Rose
60540dadee SetUtils: added intersectionSize & differenceSize 2020-02-12 12:28:34 -08:00
David Sehnal
c0236650f0 mol-model: struct conn bonds fix 2020-02-12 19:58:13 +01:00
David Sehnal
fb3017cfff mol-model-props: support outlier type coloring in RCSB validation theme 2020-02-12 16:06:48 +01:00
Alexander Rose
929c91a48c fixed & improved carbohydrate handling
- marking behavior like for polymer visual (single atom triggers full marking)
- fixed carbohydrate links induced by intra-unit bonds
- carbohydrate element is now defined by an altId ring index (instead of the anomeric carbon element index)
2020-02-11 19:09:03 -08:00
Alexander Rose
bfd9595c1c avoid adding bonds multiple times 2020-02-11 19:01:50 -08:00
Alexander Rose
c091f9a8ae typo 2020-02-11 19:00:49 -08:00
David Sehnal
d5b71b302b mol-model: check alt loc in carb fused rings 2020-02-11 14:54:53 +01:00
David Sehnal
67103232be mol-data: fixed valueKind for typed array based Column views 2020-02-11 14:02:46 +01:00
David Sehnal
f471fc3d2b mol-model: support alt loc in ring computation 2020-02-11 13:39:14 +01:00
David Sehnal
2a0783d005 fix residue label; CIF export tweak 2020-02-11 12:11:10 +01:00
Alexander Rose
7234ad261b linting and unit test fixes 2020-02-10 18:54:30 -08:00
Alexander Rose
001d1fb8d3 updated packages 2020-02-10 18:02:00 -08:00
Alexander Rose
35a56bf37c Merge branch 'master' of https://github.com/molstar/molstar 2020-02-10 17:55:40 -08:00
Alexander Rose
9715ff061e ccp4/mrc handling improvements
- read mode 6 (uint16)
- correctly normalize mrc origin offset
- use heuristic to determine endianess if not given
- handle erroneous spacegroup
- calculate data stats if not available
- add offset param
2020-02-10 17:55:24 -08:00
Alexander Rose
9866db9ced remove label on mouseleave in state tree 2020-02-10 14:43:57 -08:00
Alexander Rose
fc2288a583 label tweaks 2020-02-10 14:21:47 -08:00
Alexander Rose
11d1bbe222 cleanup, removed console.log 2020-02-10 14:18:56 -08:00
Alexander Rose
bc07256d8e improved shallowEqual
- old shallowEqual is now shallowEqualObjects
- new shallowEqual supports objects, primitives and arrays
2020-02-10 14:17:54 -08:00
Alexander Rose
3826bdb0c3 validation-report: support symm-clashes 2020-02-10 14:16:41 -08:00
Alexander Rose
9609dddd47 assembly symmetry: improved error and transform handling 2020-02-10 10:32:44 -08:00
David Sehnal
ad7b318da0 mol-plugin: state saving tweak 2020-02-09 18:01:58 +01:00
David Sehnal
66c76ea6b5 mol-plugin: remember state server URL 2020-02-09 17:45:56 +01:00
David Sehnal
29e47c1e90 plugin-state server swagger ui 2020-02-09 17:39:58 +01:00
David Sehnal
e08a074a1c mol-plugin: config 2020-02-08 17:02:44 +01:00
David Sehnal
d7ebb30e05 servers/plugin-state 2020-02-08 16:26:29 +01:00
Alexander Rose
8330068434 assembly symmetry: cage support and improved labels 2020-02-07 18:20:29 -08:00
Alexander Rose
42dea4a2eb renamed copyCage to cloneCage 2020-02-07 18:19:30 -08:00
Alexander Rose
4de0ae6628 fix tetrahedron primitive to be a one... 2020-02-07 18:18:54 -08:00
Alexander Rose
5a714af309 use skipTypename for rcsb graphql codegen 2020-02-07 18:18:17 -08:00
Alexander Rose
20f73fdae7 assembly symmetry: add axes order symbols and coloring 2020-02-06 13:07:15 -08:00
Alexander Rose
aca91cf18f added bundleLabel, improved measurement labels 2020-02-06 10:54:41 -08:00
Alexander Rose
974a7d7520 shape loci bounding sphere for points and text geo 2020-02-06 09:29:07 -08:00
Alexander Rose
f9d7545f7d add avg./sum indication to labels 2020-02-06 09:14:36 -08:00
Alexander Rose
0e135c4645 label improvements for various properties
- asa
- rci
- geometry quality
- desnity fit
- interactions
2020-02-05 18:27:04 -08:00
Alexander Rose
961f847765 updated rcsb graphql schema and url 2020-02-05 14:22:16 -08:00
Alexander Rose
b83fed4701 refactored DataLoci, DataLocation and improved props
- moved nci theme & repr to props
- better validaiton clash loci handling
2020-02-05 12:30:13 -08:00
Alexander Rose
651fd2aca7 fix validation report clashes between unrelated units 2020-02-05 12:27:29 -08:00
Alexander Rose
2dd863e711 add CentroidHelper utils .fromProvider and .fromPairProvider 2020-02-05 12:26:55 -08:00
Alexander Rose
bac5ea7ea6 better asa label, moved asa theme to props 2020-02-04 17:48:29 -08:00
Alexander Rose
312db7eec3 added Bond.getBoundingSphere (moved from model/loci) 2020-02-04 16:51:34 -08:00
Alexander Rose
31850b3a71 Shape.Loci improvements including bounding-sphere calculation 2020-02-04 16:31:09 -08:00
Alexander Rose
ee35e39611 fix .expandBySphere and .expand in Sphere3D 2020-02-04 16:28:58 -08:00
Alexander Rose
872130d65c added GroupMapping to mesh, lines, spheres geometries 2020-02-04 16:28:34 -08:00
Alexander Rose
b903554f52 geo util cleanup and consilidation 2020-02-04 14:21:20 -08:00
Alexander Rose
c3fba20780 ply improvements: use vertex group field name in label, fix parser and spec 2020-02-04 11:28:30 -08:00
Alexander Rose
870d2da8ed wip, geometry refactoring
- create helper function
- bounding-sphere handling
- cleanup
2020-02-03 19:34:28 -08:00
Alexander Rose
22d17f6c8e ply parser: handle list elements with appended properties 2020-02-03 19:31:36 -08:00
Alexander Rose
6bbf12a660 repr marker and label fixes 2020-02-03 18:14:53 -08:00
Alexander Rose
ab4ae742db add Mat4.isRotationAndTranslation 2020-02-03 17:46:46 -08:00
Alexander Rose
7725071ae2 repr state handling fixes and support for allowed marker actions 2020-02-03 17:45:33 -08:00
Alexander Rose
c7ab6ebec7 wip, rcsb validation report clashes 2020-02-03 09:35:32 -08:00
Alexander Rose
d56abadf4c support props in default theme of repr provider 2020-02-03 09:34:29 -08:00
David Sehnal
7eb2952ec5 mol-state: StateActionManager.remove 2020-02-03 15:41:45 +01:00
Alexander Rose
21cf2d5437 wip, rcsb validation report 2020-01-31 18:53:31 -08:00
Alexander Rose
5af0c448c6 generic data Location 2020-01-31 18:33:07 -08:00
Alexander Rose
2ca9392c5a Column.ValueKind docs 2020-01-31 18:30:07 -08:00
Alexander Rose
a5a6f2dcc4 emit StructureElement.Location in BondIterator.fromStructure
- simpler to handle in themes
2020-01-31 18:29:53 -08:00
Alexander Rose
91f5207d68 formating 2020-01-31 17:30:59 -08:00
Alexander Rose
c89848dec0 fix AtomicIndex.findChainAuth
- needs to consider that auth_asym_id can map to multiple label_asym_ids
2020-01-31 17:29:48 -08:00
Alexander Rose
116d3ec319 added InterUnitGraph.Builder 2020-01-31 15:56:36 -08:00
Alexander Rose
20266a229b added Structure.eachUnitPair 2020-01-31 12:06:38 -08:00
Alexander Rose
0a26e84f8f added LinkCylinderStyle.Disk 2020-01-30 19:33:02 -08:00
Alexander Rose
93bfa7a575 refactored link/bond utils for visuals 2020-01-30 18:35:20 -08:00
Alexander Rose
c09991573c refactored custom-model-property
- analogous to custom-structure-property
2020-01-29 18:55:08 -08:00
Alexander Rose
556b7b26d4 handle update in StructureFromModel 2020-01-29 18:53:33 -08:00
Alexander Rose
a011600766 handle more edge cases in getNumberType 2020-01-29 18:51:28 -08:00
Alexander Rose
2e5439c385 treat scientific numbers as string in getFieldType 2020-01-29 10:22:36 -08:00
Alexander Rose
3d6ae08437 wip, custom property refactoring 2020-01-28 17:16:01 -08:00
Alexander Rose
03228f7952 renamed CustomStructureProperty.getValue to .get 2020-01-28 16:23:49 -08:00
Alexander Rose
e46a8c4369 better handle scientific number type in getCifFieldType 2020-01-28 16:13:51 -08:00
Alexander Rose
01ef92a795 cleanup assembly-symmetry 2020-01-28 13:04:59 -08:00
Alexander Rose
61a5d18be6 async zip/gzip decoding 2020-01-28 11:47:26 -08:00
Alexander Rose
9c2c48bd59 use TextDecoder when available 2020-01-28 11:44:09 -08:00
Alexander Rose
df6d49b2ac zip utils cleanup 2020-01-27 22:41:03 -08:00
Alexander Rose
2476bf76b5 Merge branch 'master' of https://github.com/molstar/molstar 2020-01-27 22:33:00 -08:00
Alexander Rose
1c4a397249 support loading of zip and gz files
- only zip files with a single entry
2020-01-27 22:32:40 -08:00
Alexander Rose
4930018a55 added lightweight zip utils
- deflate/inflate
- zip files
- gz files
2020-01-27 22:30:48 -08:00
Alexander Rose
205f4c31d6 tweaked geometry and render-object types 2020-01-27 14:41:24 -08:00
Alexander Rose
89d3c87919 refactored data-source to leverage built-in json/xml parsing 2020-01-27 14:40:45 -08:00
Alexander Rose
d0a861d39c take aromatic rings into account for hydrogen bond calculation 2020-01-27 11:13:35 -08:00
Alexander Rose
9f7b96c727 fix use of invariant positions when calculation interactions 2020-01-25 14:29:48 -08:00
Alexander Rose
e1d2a8b41d ignore non-src files in vscode eslint plugin 2020-01-25 13:20:43 -08:00
Alexander Rose
e71bf9c288 use cpx2 instead of unmaintained cpx package 2020-01-24 18:30:31 -08:00
Alexander Rose
693ea3a40e refactored CustomStructureProperties & updated RCSB assembly symmetry
- CustomStructureProperties.attach recieves runtime and fetch context
- RCSBAsseblySymmetry uses updated data API
2020-01-24 18:23:20 -08:00
Alexander Rose
921d23e73f add NonNullableArray type helper 2020-01-24 18:13:20 -08:00
Alexander Rose
709944c859 typed DataLoci 2020-01-24 18:12:43 -08:00
Alexander Rose
9341c19bd5 updated graphql codegen script 2020-01-24 18:12:10 -08:00
Alexander Rose
1cee84d9af fix formating 2020-01-23 10:14:03 -08:00
Alexander Rose
bea5fe5474 updated packages 2020-01-23 10:13:53 -08:00
Alexander Rose
c473f2b284 Merge branch 'master' of https://github.com/molstar/molstar 2020-01-23 09:31:20 -08:00
Alexander Rose
d5c163ac48 handle context loss, add webgl resources 2020-01-23 09:31:05 -08:00
Alexander Rose
85dcef1b2e more browser backwards compat, polyfills 2020-01-23 08:57:53 -08:00
Alexander Rose
8c1acc6758 fix floatLogFactor in shader code 2020-01-22 17:55:18 -08:00
Alexander Rose
fbb7f0a6a1 fix glsl300 frag shader prefix 2020-01-22 17:54:56 -08:00
David Sehnal
3b7c8963df mol-theme: include <1 occupancy in default label 2020-01-21 12:51:34 +01:00
David Sehnal
d58f4a73b6 mol-model: fix for links with <1 occupancy atoms 2020-01-21 12:42:44 +01:00
Alexander Rose
09cfd85603 tweaked shader const 2020-01-16 11:38:09 -05:00
Alexander Rose
846a301122 added polyfills 2020-01-16 11:37:18 -05:00
Alexander Rose
6a29925733 fix if statements in WebGLState 2020-01-15 15:21:41 -05:00
Alexander Rose
5633350b63 formating tweaks 2020-01-15 15:12:55 -05:00
Alexander Rose
5d5ffcdb36 trajectory from topology and coordinates 2020-01-15 15:00:26 -05:00
Alexander Rose
a819835984 add AtomicConformation.xyzDefined & improve getAtomicRanges 2020-01-15 14:58:03 -05:00
Alexander Rose
227721bfd3 fix sequence creation from hierarchy 2020-01-15 14:14:37 -05:00
Alexander Rose
31e2cc5f07 add index-pair bond provider 2020-01-15 14:14:02 -05:00
Alexander Rose
3f02cf0561 take .isDefined into account in CifField.ofColumn 2020-01-15 13:51:54 -05:00
Alexander Rose
a57a9f0386 fix psf parser 2020-01-15 13:50:13 -05:00
Alexander Rose
11a6df6e19 add basic psf reader 2020-01-13 16:32:42 -05:00
Alexander Rose
8d5e1feac9 updated packages 2020-01-13 09:12:59 -05:00
Alexander Rose
e19e3d7380 use eslint instead of tslint 2020-01-13 09:02:47 -05:00
Alexander Rose
78c7664be3 very basic ccp4 spec test 2020-01-12 13:38:06 -08:00
Alexander Rose
39b29fe0ea formating & code style 2020-01-12 13:23:37 -08:00
Alexander Rose
5636edc1d1 plugin, trajectory from model and coordinates 2020-01-12 13:22:50 -08:00
Alexander Rose
7dbdc75cad added dcd format parser 2020-01-12 13:20:55 -08:00
Alexander Rose
fd92c916b7 added coordinates support to model 2020-01-12 13:01:41 -08:00
Alexander Rose
f5e880839e force cast from unknown for state dependencies 2020-01-12 11:56:07 -08:00
Alexander Rose
6e70172c45 fixed addUnitPositiveCharges 2020-01-10 17:46:27 -08:00
Alexander Rose
22563bf671 consider overlapping secondary structure elements from mmCIF 2020-01-10 17:33:28 -08:00
Alexander Rose
cad95403aa added option to toggle far clipping 2020-01-10 17:03:08 -08:00
Alexander Rose
d375595e08 support interactions loci in getBoundingSphere 2020-01-10 16:08:25 -08:00
Alexander Rose
b16d13cc35 interactions, links to contacts renaming 2020-01-10 16:07:52 -08:00
Alexander Rose
f03471ee39 tweaked interaction params 2020-01-10 15:33:58 -08:00
Alexander Rose
6f1f65487d string, kebab case 2020-01-10 15:33:31 -08:00
Alexander Rose
b863aaedb3 general support for aromatic rings
- containing annotated aromatic bonds
- being flat with certain elements
2020-01-10 15:33:06 -08:00
Alexander Rose
b77994d01f improved bond handling
- filter (include/exclude) type in repr
- cleaned-up bond types and names
2020-01-10 15:30:29 -08:00
Alexander Rose
30e01c07f7 add interactions repr to surroundings behavior 2020-01-09 17:34:29 -08:00
Alexander Rose
1e018b82df interactions repr: use size theme 2020-01-09 17:33:58 -08:00
Alexander Rose
49e6966037 fixe & improved interaction refiners 2020-01-09 17:04:23 -08:00
Alexander Rose
85b1df46cd improved checkLineOfSight 2020-01-09 17:03:43 -08:00
Alexander Rose
6908a2cd2b copy structure.lookup.findUnitIndices results
needed so structure.lookup.find can be safely called within
2020-01-09 17:02:52 -08:00
Alexander Rose
4379d818ab fix interactions/valence-model label behavior 2020-01-09 17:00:35 -08:00
Alexander Rose
4434dfb79a fix .firstChainLoc assignment in handleUnitChainsSimple 2020-01-09 16:59:49 -08:00
Alexander Rose
9621f67e84 helper to copy lookup results 2020-01-09 16:59:12 -08:00
Alexander Rose
21a0684353 wip, interactions refiners
- saltBridgeRefiner
- piStackingRefiner
- metalCoordinationRefiner
2020-01-08 17:54:10 -08:00
Alexander Rose
3601955433 wip, interactions, various fixes
- limit bond-related calculations to covalent bonds
- wrong charge feature assignment
2020-01-08 17:53:12 -08:00
Alexander Rose
d91483c485 implemented areFeaturesWithinDistanceSq 2020-01-07 16:57:44 -08:00
Alexander Rose
8b3d07906f wip, refactored refineInteractions, added weakHydrogenBondsRefiner 2020-01-07 16:46:21 -08:00
Alexander Rose
5f8a4b6be4 better types for IntAdjacencyGraph and GridLookup3D 2020-01-07 16:45:21 -08:00
Alexander Rose
f8ff919787 wip, interactions, fix hydrogen bond distance test 2020-01-06 17:55:40 -08:00
Alexander Rose
6dfe975fc7 wip, interactions refinement
- more links to contacts renaming
- line-of-sight check
- hydrophobic contact refinement
2020-01-06 17:40:55 -08:00
Alexander Rose
2650f8d3dd wip, renamed links to contacts for interactions 2020-01-06 10:06:57 -08:00
Alexander Rose
f172b6ceaa wip, interactions
- improved performance by searching for links in only the subset of relevant Features
2020-01-03 17:22:52 -08:00
Alexander Rose
8086af1bf7 impoved SetUtils
- use ReadonlySet when possible
- added .add
2020-01-03 17:21:18 -08:00
Alexander Rose
5813840e17 wip, interactions
- metal coordination
- Features.Provider() ctor
- Features.Provider, multiple types
2020-01-03 15:34:02 -08:00
Alexander Rose
e2d595394a wip, interactions
- hydrophobic
- allow computing of a subset of types
2020-01-03 12:53:27 -08:00
Alexander Rose
9b24e6fb1f add rings selection to UI 2020-01-02 14:57:51 -08:00
Alexander Rose
0f33144935 wip, various nci fixes and tweaks 2020-01-02 14:57:29 -08:00
Alexander Rose
6d384166d5 fix, rings must have at least three elements 2020-01-02 14:55:06 -08:00
Alexander Rose
8b766dc242 tweak, use Box3D.size 2020-01-02 14:54:47 -08:00
Alexander Rose
1fa64c836c wip, charged interactions 2019-12-20 17:30:10 -08:00
Alexander Rose
af700c1481 wip, refactored interaction computation 2019-12-20 11:33:29 -08:00
Alexander Rose
7dcf16cd97 wip, interactions, halogen bonds 2019-12-19 17:30:24 -08:00
Alexander Rose
f86b46076c wip, interactions & valence-model label providers 2019-12-19 16:29:55 -08:00
Alexander Rose
6fe58d7b73 wip, various interactions computation fixes 2019-12-19 14:53:20 -08:00
Alexander Rose
8c2a4b5cae fix unitTransforms reset with complex representation 2019-12-18 16:50:32 -08:00
Alexander Rose
b2c31f5166 fix unit instance marking 2019-12-18 16:14:50 -08:00
Alexander Rose
0f4d0ff986 wip, interactions, features in invariant space 2019-12-18 15:56:04 -08:00
Alexander Rose
2b73f9cafd improved hbond param handling 2019-12-18 15:55:07 -08:00
Alexander Rose
a86438a265 wip, interactions & hydrogen bonds 2019-12-18 14:40:22 -08:00
Alexander Rose
c0b5102d31 bonds tweaks 2019-12-18 14:39:48 -08:00
Alexander Rose
feab3a38f9 add unit kind helpers to Structure 2019-12-18 14:38:01 -08:00
Alexander Rose
b1fb9c5c47 renamed 'structure-element-index' to 'unit-element-index' 2019-12-17 10:17:42 -08:00
Alexander Rose
9fb65f46a1 wip, bond compute todos 2019-12-16 17:20:08 -08:00
Alexander Rose
7a2e85b856 always use root topology for valence model 2019-12-16 17:19:40 -08:00
Alexander Rose
f85e3e76fd add CustomStructureProperty.type determining inheritance 2019-12-16 15:48:24 -08:00
Alexander Rose
c6ef02d0a6 factored out Unit BaseProperties 2019-12-16 15:45:00 -08:00
Alexander Rose
81a6e3cf4e package updates 2019-12-16 11:46:05 -08:00
Alexander Rose
48a75927f6 renamed 'link' to 'bond' as appropriate 2019-12-16 11:38:46 -08:00
Alexander Rose
067a85ef88 avoid console.log when not in debug-mode 2019-12-16 10:23:52 -08:00
Alexander Rose
c4757313e6 fix typo 2019-12-16 10:23:24 -08:00
Alexander Rose
88d8998bd2 generalized InterUnitBonds to InterUnitGraph 2019-12-13 18:31:32 -08:00
Alexander Rose
97e6884487 wip, fix interactions marking 2019-12-13 18:13:50 -08:00
Alexander Rose
8fd56dbc38 wip, interactions 2019-12-13 16:59:47 -08:00
Alexander Rose
f9c97ad5cb fix regression, only calc dssp for non-archival files by default 2019-12-13 16:58:41 -08:00
Alexander Rose
f893aba522 make custom structure properties auto-attachable 2019-12-13 11:49:31 -08:00
Alexander Rose
f2740aaee2 secondary structure query/selection improvements
- secondaryStructureFlag names for query
- helix and beta selection query helper
2019-12-13 09:22:39 -08:00
Alexander Rose
fb15cc135a wip, handle custom custom structure props as on-demand dependencies 2019-12-12 18:26:15 -08:00
Alexander Rose
d9579914b4 improved accessible-surface-area computation 2019-12-11 15:56:33 -08:00
Alexander Rose
5a98bfd8ef added StructureElement.Location.areEqual 2019-12-11 15:22:49 -08:00
Alexander Rose
149e6ebf84 cleanup 2019-12-11 15:22:26 -08:00
Alexander Rose
74c8e512a7 add Structure.atomicResidueCount & SerialMapping.getSerialIndex 2019-12-11 15:22:08 -08:00
Alexander Rose
52bf9b87fa Merge branch 'master' of https://github.com/molstar/molstar 2019-12-11 08:55:22 -08:00
David Sehnal
ac8d71215e mol-server: print out current config 2019-12-11 15:15:10 +01:00
David Sehnal
c7cfedb874 model-server: support post params 2019-12-11 15:01:51 +01:00
Alexander Rose
faae40c9e8 better naming in SerialMapping 2019-12-10 13:37:52 -08:00
Alexander Rose
288912ccea add Task.empty 2019-12-10 13:35:16 -08:00
Alexander Rose
26e47c3e33 Theme namespace fixes 2019-12-10 13:35:02 -08:00
Alexander Rose
15a8ea6598 Merge branch 'master' of https://github.com/molstar/molstar 2019-12-10 08:33:32 -08:00
Alexander Rose
aeda6d3312 Theme namespace 2019-12-10 08:33:05 -08:00
David Sehnal
79f430efb3 added PD.array/objectToOptions 2019-12-10 12:51:49 +01:00
Alexander Rose
4fe70de2ff InterUnitLink improvements 2019-12-09 17:15:35 -08:00
Alexander Rose
56fd6d6a5b add InterUnitBonds.hasBond 2019-12-09 17:14:25 -08:00
Sebastian Bittrich
b5076edc8d accessible surface area calculation improvements 2019-12-09 17:12:09 -08:00
Alexander Rose
4fbb9e232c removed unused code 2019-12-09 17:08:12 -08:00
Alexander Rose
b6324d9cee bond-order table for standard residues 2019-12-09 17:07:54 -08:00
Alexander Rose
f668f725e8 improved CombinationIterator 2019-12-09 17:06:47 -08:00
Alexander Rose
e45041f2f2 simplified Vec3.angle 2019-12-09 17:06:33 -08:00
Alexander Rose
d285076acb Structure.bondCount 2019-12-09 17:06:12 -08:00
Alexander Rose
9047aae87c Link.ElementLinkIterator 2019-12-09 17:05:33 -08:00
Alexander Rose
44b00edcb6 StructureGroup as first argument for UnitsVisualBuilder.createLocationIterator 2019-12-09 17:04:57 -08:00
Alexander Rose
a476c2a167 rename Structure.links to .interUnitBonds 2019-12-09 17:02:32 -08:00
Alexander Rose
1b2b168624 add orientation ellipsoid to load cellpack presets 2019-12-09 09:11:18 -08:00
Alexander Rose
ce238bcd1d fix, removed unused property 2019-12-09 09:06:31 -08:00
Alexander Rose
c119a82d83 simplified fog shader handling 2019-12-08 23:06:36 -08:00
Alexander Rose
4b97686a26 consolidated some shader uniforms as global 2019-12-08 22:56:12 -08:00
Alexander Rose
c13350b098 set transparent background per render call & screenshot improvements 2019-12-08 18:41:47 -08:00
Alexander Rose
c9c6df4861 Merge branch 'master' of https://github.com/molstar/molstar 2019-12-08 17:33:01 -08:00
David Sehnal
2e73681aae Merge branch 'master' of https://github.com/molstar/molstar 2019-12-08 14:55:42 +01:00
David Sehnal
42b4c25ca3 mol-plugin: screenshot UI improvements 2019-12-08 14:55:34 +01:00
Alexander Rose
5a5939408f support for interior-color (mesh, spheres) 2019-12-08 00:23:18 -08:00
Alexander Rose
7041bac8ca add ignore-light support to spheres shader 2019-12-08 00:22:29 -08:00
Alexander Rose
f8ab02fdab add doubleSided to quality props 2019-12-07 19:43:05 -08:00
David Sehnal
b75ba4b4aa mol-plugin: screenshot controls 2019-12-07 16:42:47 +01:00
David Sehnal
baa80d08dd mol-plugin: remove passRepresentation from Highlight command 2019-12-07 12:47:05 +01:00
David Sehnal
144d40cd38 moved skin to mol-plugin-ui 2019-12-07 12:40:06 +01:00
David Sehnal
c6b4610adf mol-plugin: fix highlight label style 2019-12-07 12:32:13 +01:00
Alexander Rose
f2c5cd978b removed superseded label transfroms and representations 2019-12-06 16:58:29 -08:00
Alexander Rose
63823698c7 take fog into account for picking visibility 2019-12-06 16:55:18 -08:00
Alexander Rose
f6ca679a57 improved highlighting
- highlight SO.Molecule.Structure.Selections
- cleaned-up LociHighlightManager
2019-12-06 16:12:00 -08:00
Alexander Rose
142c46c127 improved measurement representation labels 2019-12-06 15:18:53 -08:00
Alexander Rose
1bd59523b2 Representation.getLoci() returns 'whole' loci for repr 2019-12-06 15:18:26 -08:00
David Sehnal
ef67925858 added mol-plugin-ui 2019-12-06 23:25:26 +01:00
David Sehnal
5dae376bcb mol-plugin: fix non-structure visual highlighting 2019-12-06 22:55:30 +01:00
David Sehnal
14ed325579 removed console.log 2019-12-06 22:31:48 +01:00
David Sehnal
b007409521 Merge branch 'master' of https://github.com/molstar/molstar 2019-12-06 22:17:07 +01:00
David Sehnal
5830252df7 mol-plugin: optimized sequence marking 2019-12-06 22:16:23 +01:00
David Sehnal
02ad9587fc mol-repr: optimized highlight marking for structure visuals 2019-12-06 21:16:36 +01:00
Alexander Rose
4596336c13 mmcif schema updates, mostly regarding carbohydrates 2019-12-06 12:14:45 -08:00
Alexander Rose
2a413256ed added element/residue/chain instances loci granularity and helpers 2019-12-06 11:46:54 -08:00
David Sehnal
8b9178249d mol-plugin: added Structure.Selections groupId 2019-12-06 19:30:42 +01:00
David Sehnal
1d0ba36d7c mol-repr: show residue/nucleotide segments selected when intersecting, not just subset 2019-12-06 18:02:58 +01:00
David Sehnal
3a8211937f mol-plugin: better current object handling 2019-12-06 17:44:21 +01:00
David Sehnal
0d576f7011 mol-plugin: state tree label use button instead of link 2019-12-06 15:28:31 +01:00
David Sehnal
d90e81b0e5 mol-plugin: wip state manager 2019-12-06 14:54:51 +01:00
David Sehnal
89be1767e9 Merge branch 'master' of https://github.com/molstar/molstar 2019-12-06 13:58:36 +01:00
Alexander Rose
aee6921140 added entity & model loci granularity and helpers 2019-12-05 16:49:21 -08:00
Alexander Rose
a55572d52f show structure orientation ellipsoid for more applicable units 2019-12-05 16:00:33 -08:00
Alexander Rose
525deafd83 added ellipsoid visual to orientation shape-repr 2019-12-05 15:37:53 -08:00
Alexander Rose
8064b969be added structure label-representation 2019-12-05 15:12:50 -08:00
Alexander Rose
6d6e12bbd0 added scale argument to TextBuilder.add 2019-12-05 15:12:19 -08:00
Alexander Rose
825ae48000 added Text geo support for structure repr/visual 2019-12-05 15:11:30 -08:00
Alexander Rose
764aef3181 added backbone helper-selection 2019-12-05 10:44:09 -08:00
Alexander Rose
d226abadc1 no text picking by default 2019-12-05 10:40:04 -08:00
Alexander Rose
ccd1fa3a0f better renderer depthMask handling 2019-12-05 10:38:22 -08:00
Alexander Rose
65a692e3bf OrientationEllipsoidMeshVisual.eachUnit 2019-12-04 11:28:25 -08:00
David Sehnal
2daac955f4 mol-model: Loci.Bundle 2019-12-04 20:10:54 +01:00
Alexander Rose
162797e43a fix ModelStructureRepresentation.getParams for structures without assebmlies 2019-12-04 11:09:56 -08:00
Alexander Rose
784b29805a added structure OrientationRepresentation 2019-12-04 11:00:57 -08:00
Alexander Rose
67b60cff60 added Unit.principalAxes 2019-12-04 11:00:12 -08:00
Alexander Rose
28443de11f mesh-builder: addAxes, addOrientedBox 2019-12-04 10:58:44 -08:00
Alexander Rose
59cf60c2ba removed StructureOrientation3D
- use StructureSelectionsOrientation3D
2019-12-04 09:39:52 -08:00
Alexander Rose
8e14a1e2ec updated packages 2019-12-03 17:47:00 -08:00
Alexander Rose
7dd2e5ec98 bind label & orientation to ui button 2019-12-03 17:07:13 -08:00
Alexander Rose
bd3e052130 assign position in lines shader so fog works 2019-12-03 16:46:27 -08:00
Alexander Rose
6fbe7efcab added ignoreLight param for mesh geo 2019-12-03 16:31:08 -08:00
Alexander Rose
572a574bf3 improved measurements repr, including added dihedral repr 2019-12-03 16:30:42 -08:00
Alexander Rose
347a0a43ea Loci.Pair./Triple/.Quad type 2019-12-03 16:14:44 -08:00
Alexander Rose
28abd00a6e wip, ShapeBuilder argument for ShapeRepresentation 2019-12-03 16:14:14 -08:00
Alexander Rose
06354d6d1d math lib tweaks 2019-12-03 16:13:24 -08:00
Alexander Rose
2b31d54e18 always trigger highlight on hover
no matter what keys are pressed
2019-12-02 10:20:31 -08:00
Alexander Rose
58644b3d5c wip, measurements representations 2019-12-02 08:18:54 -08:00
Alexander Rose
4c732b3b2d added Loci.getPrincipalAxes 2019-12-02 08:17:44 -08:00
Alexander Rose
36d3a0728c added MeshBuilder.addPrimitiveFlipped 2019-12-02 08:17:28 -08:00
Alexander Rose
b0c696e401 wip, add dashed in lines builder 2019-12-02 08:16:58 -08:00
Alexander Rose
2a28b5421f wip, circle primitive 2019-12-02 08:16:16 -08:00
Alexander Rose
269176e0a6 lociLabel options 2019-12-02 08:15:36 -08:00
Alexander Rose
cd23a68268 moved toUpperCase to string.ts 2019-12-02 08:13:49 -08:00
David Sehnal
48e81c8b10 packages 2019-11-30 22:07:44 +01:00
David Sehnal
649c294929 mol-plugin: fixes 2019-11-29 18:55:49 +01:00
David Sehnal
ab0dcb0de9 mol-state: builder fixes, StateObjectSelector 2019-11-29 18:18:25 +01:00
David Sehnal
cb2fc8f95b mol-state: StateObjectSelector 2019-11-29 17:42:07 +01:00
David Sehnal
5deec4391d mol-plugin: fix state action list being mutated by accident 2019-11-28 23:39:28 +01:00
David Sehnal
1873e506e0 mol-plugin: state tree button tweaks 2019-11-28 23:33:00 +01:00
David Sehnal
11e660a81a mol-plugin: indicate unobserved changed in state tree, better home screen 2019-11-28 23:27:48 +01:00
David Sehnal
635ba2a7e3 mol-plugin: fix collapsed left panel when controls are hidden 2019-11-28 22:55:42 +01:00
David Sehnal
1a2fb55d03 mol-plugin: add remote state list to the "home" panel 2019-11-28 22:54:17 +01:00
David Sehnal
a5785e526e mol-plugin: basic background settings change 2019-11-28 19:08:34 +01:00
David Sehnal
af9d50f5ec mol-plugin: make Log take less space 2019-11-28 18:58:19 +01:00
David Sehnal
ac06b9c018 mol-plugin: configure remote states in plugin spec (wip) 2019-11-28 18:05:36 +01:00
David Sehnal
36d8df1442 mol-plugin: UI tweaks 2019-11-28 18:01:03 +01:00
David Sehnal
a312c4ef1d mol-plugin: collapse left panel 2019-11-28 17:41:37 +01:00
David Sehnal
0c6b80d370 mol-plugin: UI improvements (wip) 2019-11-28 16:58:43 +01:00
David Sehnal
16f9129acc mol-plugin: only show transform back button where appropriate 2019-11-28 15:27:40 +01:00
David Sehnal
1af9554cc7 mol-plugin: sequence view tweak 2019-11-28 14:50:04 +01:00
David Sehnal
cc8999cbc9 mol-plugin: only expand DownloadStructure for root actions 2019-11-28 14:40:43 +01:00
David Sehnal
c7b4099758 mol-plugin: viewport controls tweaks 2019-11-28 14:33:29 +01:00
David Sehnal
f060fc228f mol-plugin: Help panel 2019-11-28 14:12:44 +01:00
David Sehnal
8d3c091d2e mol-plugin: simple settings 2019-11-28 13:45:57 +01:00
David Sehnal
cabf7c1613 mol-plugin: Automatic default 3d representation 2019-11-27 19:08:17 +01:00
David Sehnal
b44149bbaf mol-plugin: wip StructureRepresentationManager 2019-11-27 18:32:25 +01:00
David Sehnal
18befade7f mol-plugin: Transform and Action tweaks 2019-11-27 16:36:45 +01:00
David Sehnal
8fd8eb703b mol-plugin: CreateComplex -> Create3DRepresentationPreset 2019-11-27 16:08:09 +01:00
David Sehnal
fa0c29c1d1 mol-plugin: DownloadStructure now uses StructureFromModel 2019-11-27 13:52:19 +01:00
David Sehnal
65ed5c98bf mol-plugin: refactor StructureFromModel 2019-11-27 13:38:21 +01:00
David Sehnal
f0ecf74aad mol-script: bind rings generator 2019-11-27 12:32:15 +01:00
Alexander Rose
c56ed0af28 0.5.0-dev.1 2019-11-26 16:15:18 -08:00
Alexander Rose
ddb8231c00 focus tweaks, export structure boundary functions 2019-11-26 16:09:45 -08:00
Alexander Rose
bc24e8f236 fix query name 2019-11-26 16:08:44 -08:00
Alexander Rose
2edb31e7ea fix structure orientation translation-matrix 2019-11-26 16:06:12 -08:00
Alexander Rose
ad619d9b8d mouse binding fixes 2019-11-26 11:19:02 -08:00
Alexander Rose
61f738ce3d Merge branch 'master' of https://github.com/molstar/molstar 2019-11-26 10:59:03 -08:00
Alexander Rose
73ae95ed06 improved selection of residue ranges
- support brushing in sequence widget
- introduce reference-loci in selection manager
2019-11-26 10:48:59 -08:00
Alexander Rose
6d4c1aa3ea better names for LociSelectManager methods 2019-11-26 10:47:44 -08:00
Alexander Rose
34f230a882 reverted SelectLoci bindings 2019-11-26 10:47:22 -08:00
Alexander Rose
a68d81e495 wip, add button to input observer 2019-11-26 10:46:49 -08:00
David Sehnal
9687c38e06 mol-plugin: CSS fix active control hover 2019-11-26 16:32:08 +01:00
David Sehnal
f69670c368 mol-plugin: action select control 2019-11-26 16:19:17 +01:00
David Sehnal
a0b537ef64 mol-plugin: cleaner object update UI 2019-11-26 15:04:33 +01:00
David Sehnal
e8663b5bfc mol-plugin: fix plugin crash when WebGL is not available 2019-11-26 13:31:42 +01:00
David Sehnal
9f12fbde70 mol-plugin: param help tweaks 2019-11-26 13:07:04 +01:00
David Sehnal
940b16ebd2 mol-plugin: DownloadStructure param tweaks 2019-11-26 13:01:06 +01:00
David Sehnal
dc5aa0c30d mol-util: Fix invalid default options in ParamDefinition 2019-11-26 12:50:44 +01:00
Alexander Rose
b70b9c44fc fix ajaxGet: handle case where download had finished before callback were registered 2019-11-25 16:26:21 -08:00
David Sehnal
88a4cf1aa4 mol-plugin: SequenceView tweaks 2019-11-25 13:21:06 +01:00
David Sehnal
49eefa131f tweaks 2019-11-25 13:14:13 +01:00
David Sehnal
9f4a60572f mol-plugin: improved SequenceView 2019-11-25 13:03:01 +01:00
David Sehnal
8f9579bcaf mol-plugin: interactivity binding tweaks 2019-11-25 00:15:08 +01:00
David Sehnal
845dd4115d mol-model: changed assembly operator naming 2019-11-24 23:57:47 +01:00
David Sehnal
3e2a1227ce mol-plugin: improved range selection 2019-11-24 23:46:29 +01:00
David Sehnal
dcfec014a5 mol-plugin: Fix interactivity bindings so that only one action is triggered. 2019-11-24 23:19:32 +01:00
David Sehnal
f5598ba93e tweak 2019-11-24 22:31:43 +01:00
David Sehnal
a5fadb6e8a mol-model: remap uses OrderedSet.indexedIntersect 2019-11-24 22:26:23 +01:00
David Sehnal
738ba2d6fd mol-data: OrderedSet.indexedIntersect 2019-11-24 22:20:14 +01:00
David Sehnal
ebcc45d1fd mol-plugin: added Download Screenshot icon 2019-11-24 16:04:37 +01:00
David Sehnal
272a911d35 mol-plugin: refactored selection transforms 2019-11-24 15:36:52 +01:00
Alexander Rose
a725e577be refactored principal-axes calculation 2019-11-22 18:28:16 -08:00
Alexander Rose
a36ead9ef1 add Axes3D 2019-11-22 18:27:30 -08:00
Alexander Rose
f516072d12 extract getStructureQuality helper 2019-11-22 18:26:36 -08:00
Alexander Rose
a54b36b057 add Mat3.directionTransform 2019-11-22 18:26:05 -08:00
Alexander Rose
a18484a5dd fix memory leak, reprUpdatedSubscriptions not removed 2019-11-22 18:24:32 -08:00
David Sehnal
e685c0a342 revert name change 2019-11-22 18:27:38 +01:00
David Sehnal
a3b1d11bb3 mol-plugin: measurement tweak and todo 2019-11-22 18:25:28 +01:00
David Sehnal
7a7643c6bc mol-plugin: css fix 2019-11-22 17:56:16 +01:00
David Sehnal
3643bd04f1 mol-state: fix dependent transform delete 2019-11-22 17:49:14 +01:00
David Sehnal
65c2faaced [wip] mol-plugin: measurements 2019-11-22 17:28:21 +01:00
David Sehnal
32a91ca98c mol-plugin: wip measurements 2019-11-22 16:40:20 +01:00
David Sehnal
9f6e98a5d0 mol-plugin: support latest loci in selection manager 2019-11-22 16:17:27 +01:00
David Sehnal
0964a9fd50 mol-plugin: fix selectToggle, bind unselect to secondary button 2019-11-22 15:05:17 +01:00
David Sehnal
a0b865cd07 mol-state: dependent transforms 2019-11-22 14:36:20 +01:00
David Sehnal
a5f73b5c20 [wip] mol-state: dependent transforms 2019-11-22 13:39:15 +01:00
Alexander Rose
d10be352be 0.4.4 2019-11-21 16:23:10 -08:00
Alexander Rose
6f3d8ddd96 fix computeInterUnitBonds 2019-11-21 16:22:14 -08:00
Alexander Rose
1a14e65dcf 0.4.3 2019-11-21 15:26:23 -08:00
Alexander Rose
2757dfdb75 add sleep util 2019-11-21 15:23:34 -08:00
Alexander Rose
1b5526235e make Canvas3D.add/.remove awaitable 2019-11-21 15:23:21 -08:00
David Sehnal
d4836c5fde Merge pull request #21 from molstar/fix-bond-compute
fix struct_conn use for bond computation
2019-11-21 18:29:06 +01:00
Alexander Rose
530810e366 fix struct_conn use for bond computation 2019-11-20 15:35:11 -08:00
Alexander Rose
9f2a4828f4 improve default color-list handling 2019-11-20 15:13:45 -08:00
Alexander Rose
70cc3a612e stats: count single element unit as unit not element 2019-11-20 14:33:03 -08:00
Alexander Rose
6917ba6230 don't treat peptide terminus components as polymers
they don't neccesarily have the right atoms to draw a polymer cartoon
2019-11-20 14:18:35 -08:00
Alexander Rose
710c06672e fix, selection mark not applyed correctly on structure change 2019-11-20 09:05:46 -08:00
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
772 changed files with 47724 additions and 18276 deletions

65
.eslintrc.json Normal file
View File

@@ -0,0 +1,65 @@
{
"env": {
"browser": true,
"node": true
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/ban-types": "warn",
"@typescript-eslint/class-name-casing": "off",
"@typescript-eslint/indent": [
"warn",
4
],
"@typescript-eslint/member-delimiter-style": [
"off",
{
"multiline": {
"delimiter": "none",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/quotes": [
"warn",
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"@typescript-eslint/semi": [
"off",
null
],
"@typescript-eslint/type-annotation-spacing": "warn",
"arrow-parens": [
"off",
"as-needed"
],
"comma-dangle": "off",
"eqeqeq": [
"warn",
"smart"
],
"import/order": "off",
"no-eval": "warn",
"no-new-wrappers": "warn",
"no-trailing-spaces": "warn",
"no-unsafe-finally": "warn",
"no-var": "warn",
"spaced-comment": "warn"
}
}

View File

@@ -4,7 +4,9 @@
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-vscode.vscode-typescript-tslint-plugin",
"dbaeumer.vscode-eslint",
"firsttris.vscode-jest-runner",
"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

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

View File

@@ -31,12 +31,14 @@ The core of Mol* currently consists of these modules (see under `src/`):
- `mol-state` State representation tree with state saving and automatic updates.
- `mol-app` Components for builduing UIs.
- `mol-plugin` Allow to define modular Mol* plugin instances utilizing `mol-state` and `mol-canvas3d`.
- `mol-plugin-ui` React based user interface for the Mol* plugin. Some components of the UI are usable outside the main plugin and can be integrated to 3rd party solutions.
- `mol-util` Useful things that do not fit elsewhere.
Moreover, the project contains the imlementation of `servers`, including
- `servers/model` A tool for accessing coordinate and annotation data of molecular structures.
- `servers/volume` A tool for accessing volumetric experimental data related to molecular structures.
- `servers/plugin-state` A basic server to store Mol* Plugin states.
The project also contains performance tests (`perf-tests`), `examples`, and basic proof of concept `apps` (CIF to BinaryCIF converter and JSON domain annotation to CIF converter).
@@ -62,6 +64,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
@@ -87,10 +91,11 @@ Install CIFTools `npm install ciftools -g`
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/mmcif.ts -p mmCIF
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/ccd.ts -p CCD
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/bird.ts -p BIRD
cifschema -mip ../../../../mol-data -o src/mol-io/reader/cif/schema/cif-core.ts -p CifCore -aa
**GraphQL schemas**
node data/rcsb-graphql/codegen.js
./node_modules/.bin/graphql-codegen -c ./data/rcsb-graphql/codegen.yml
### Other scripts
**Create chem comp bond table**
@@ -143,7 +148,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

View File

@@ -1,22 +0,0 @@
const { generate } = require('graphql-code-generator')
const path = require('path')
const basePath = path.join(__dirname, '..', '..', 'src', 'mol-model-props', 'rcsb', 'graphql')
generate({
schema: 'http://rest-staging.rcsb.org/graphql',
documents: {
[path.join(basePath, 'symmetry.gql.ts')]: {
loader: path.join(__dirname, 'loader.js')
},
},
generates: {
[path.join(basePath, 'types.ts')]: {
plugins: ['time', 'typescript-common', 'typescript-client']
}
},
overwrite: true,
config: path.join(__dirname, 'codegen.json')
}, true).then(
() => console.log('done')
).catch(e => console.error(e))

View File

@@ -1,6 +0,0 @@
{
"flattenTypes": true,
"generatorConfig": {
"immutableTypes": true
}
}

View File

@@ -0,0 +1,12 @@
schema: https://data-beta.rcsb.org/graphql
documents: './src/mol-model-props/rcsb/graphql/symmetry.gql.ts'
generates:
'./src/mol-model-props/rcsb/graphql/types.d.ts':
plugins:
- add: '/* eslint-disable */'
- time
- typescript
- typescript-operations
config:
immutableTypes: true
skipTypename: true

View File

@@ -1,14 +0,0 @@
const { parse } = require('graphql');
const { readFileSync } = require('fs');
module.exports = function(docString, config) {
const str = readFileSync(docString, { encoding: 'utf-8' }).trim()
.replace(/^export default `/, '')
.replace(/`$/, '')
return [
{
filePath: docString,
content: parse(str)
}
];
};

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

15801
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.10",
"version": "0.5.0-dev.3",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -11,20 +11,21 @@
"url": "https://github.com/molstar/molstar/issues"
},
"scripts": {
"lint": "tslint src/**/*.ts",
"lint": "eslint src/**/*.ts",
"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",
"model-server-watch": "nodemon --watch lib lib/servers/model/server.js",
"volume-server": "node lib/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
"volume-server": "node lib/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
"plugin-state": "node lib/servers/plugin-state/index.js",
"preversion": "npm run test",
"postversion": "git push && git push --tags",
"prepublishOnly": "npm run test && npm run build"
@@ -63,56 +64,66 @@
],
"license": "MIT",
"devDependencies": {
"@graphql-codegen/add": "^1.12.2",
"@graphql-codegen/cli": "^1.12.2",
"@graphql-codegen/time": "^1.12.2",
"@graphql-codegen/typescript": "^1.12.2",
"@graphql-codegen/typescript-graphql-files-modules": "^1.12.2",
"@graphql-codegen/typescript-graphql-request": "^1.12.2",
"@graphql-codegen/typescript-operations": "^1.12.2",
"@types/cors": "^2.8.6",
"@typescript-eslint/eslint-plugin": "^2.19.2",
"@typescript-eslint/eslint-plugin-tslint": "^2.19.2",
"@typescript-eslint/parser": "^2.19.2",
"benchmark": "^2.1.4",
"circular-dependency-plugin": "^5.2.0",
"concurrently": "^4.1.2",
"cpx": "^1.5.0",
"css-loader": "^3.2.0",
"concurrently": "^5.1.0",
"cpx2": "^2.0.0",
"css-loader": "^3.4.2",
"eslint": "^6.8.0",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^4.2.0",
"file-loader": "^5.0.2",
"fs-extra": "^8.1.0",
"graphql-code-generator": "^0.18.2",
"graphql-codegen-time": "^0.18.2",
"graphql-codegen-typescript-template": "^0.18.2",
"http-server": "^0.11.1",
"jest": "^24.9.0",
"http-server": "^0.12.1",
"jest": "^25.1.0",
"jest-raw-loader": "^1.0.1",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.12.0",
"raw-loader": "^3.1.0",
"resolve-url-loader": "^3.1.0",
"sass-loader": "^8.0.0",
"simple-git": "^1.126.0",
"style-loader": "^1.0.0",
"ts-jest": "^24.0.2",
"tslint": "^5.20.0",
"typescript": "^3.6.3",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.8"
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.13.1",
"pascal-case": "^3.1.1",
"raw-loader": "^4.0.0",
"resolve-url-loader": "^3.1.1",
"sass-loader": "^8.0.2",
"simple-git": "^1.131.0",
"style-loader": "^1.1.3",
"ts-jest": "^25.2.0",
"typescript": "^3.7.5",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10"
},
"dependencies": {
"@types/argparse": "^1.0.36",
"@types/argparse": "^1.0.38",
"@types/benchmark": "^1.0.31",
"@types/compression": "1.0.1",
"@types/express": "^4.17.1",
"@types/jest": "^24.0.18",
"@types/node": "^12.7.4",
"@types/node-fetch": "^2.5.0",
"@types/react": "^16.9.2",
"@types/react-dom": "^16.9.0",
"@types/swagger-ui-dist": "3.0.3",
"@types/webgl2": "0.0.5",
"@types/compression": "1.7.0",
"@types/express": "^4.17.2",
"@types/jest": "^25.1.2",
"@types/node": "^13.7.0",
"@types/node-fetch": "^2.5.4",
"@types/react": "^16.9.19",
"@types/react-dom": "^16.9.5",
"@types/swagger-ui-dist": "3.0.5",
"argparse": "^1.0.10",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
"express": "^4.17.1",
"graphql": "^14.5.4",
"graphql": "^14.6.0",
"immutable": "^3.8.2",
"node-fetch": "^2.6.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"rxjs": "^6.5.3",
"swagger-ui-dist": "^3.23.9",
"util.promisify": "^1.0.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"rxjs": "^6.5.4",
"swagger-ui-dist": "^3.25.0",
"util.promisify": "^1.0.1",
"xhr2": "^0.2.0"
}
}

View File

@@ -1,7 +1,8 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { CustomElementProperty } from '../../mol-model-props/common/custom-element-property';
@@ -9,9 +10,8 @@ import { Model, ElementIndex } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
export const StripedResidues = CustomElementProperty.create<number>({
isStatic: true,
label: 'Residue Stripes',
name: 'basic-wrapper-residue-striping',
display: 'Residue Stripes',
getData(model: Model) {
const map = new Map<ElementIndex, number>();
const residueIndex = model.atomicHierarchy.residueAtomSegments.index;
@@ -24,7 +24,7 @@ export const StripedResidues = CustomElementProperty.create<number>({
getColor(e) { return e === 0 ? Color(0xff0000) : Color(0x0000ff) },
defaultColor: Color(0x777777)
},
format(e) {
getLabel(e) {
return e === 0 ? 'Odd stripe' : 'Even stripe'
}
})

View File

@@ -4,9 +4,9 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { PluginUIComponent } from '../../mol-plugin/ui/base';
import { PluginUIComponent } from '../../mol-plugin-ui/base';
import * as React from 'react';
import { TransformUpdaterControl } from '../../mol-plugin/ui/state/update-transform';
import { TransformUpdaterControl } from '../../mol-plugin-ui/state/update-transform';
export class BasicWrapperControls extends PluginUIComponent {
@@ -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

@@ -29,7 +29,7 @@ export namespace StateHelper {
}
export function structure(b: StateBuilder.To<PSO.Molecule.Model>) {
return b.apply(StateTransforms.Model.StructureFromModel, { tags: 'structure' })
return b.apply(StateTransforms.Model.StructureFromModel, void 0, { tags: 'structure' })
};
export function selectChain(b: StateBuilder.To<PSO.Molecule.Structure>, auth_asym_id: string) {

View File

@@ -105,11 +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,14 +11,17 @@ 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';
require('mol-plugin/skin/light.scss')
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-ui/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb'
type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
@@ -38,12 +41,15 @@ class BasicWrapper {
// left: 'none',
// right: BasicWrapperControls
}
},
components: {
remoteState: 'none'
}
});
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.Descriptor.name, StripedResidues.colorTheme!);
this.plugin.lociLabels.addProvider(StripedResidues.labelProvider);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider);
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.propertyProvider.descriptor.name, StripedResidues.colorThemeProvider!);
this.plugin.lociLabels.addProvider(StripedResidues.labelProvider!);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider, true);
}
private download(b: StateBuilder.To<PSO.Root>, url: string) {
@@ -57,12 +63,12 @@ class BasicWrapper {
return parsed
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
.apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.Descriptor.name] }, { ref: 'props', state: { isGhost: false } })
.apply(StateTransforms.Model.CustomModelProperties, { autoAttach: [StripedResidues.propertyProvider.descriptor.name], properties: {} }, { ref: 'props', state: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
}
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' })
@@ -105,11 +111,13 @@ class BasicWrapper {
}
setBackground(color: number) {
const renderer = this.plugin.canvas3d.props.renderer;
const renderer = this.plugin.canvas3d!.props.renderer;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
}
toggleSpin() {
if (!this.plugin.canvas3d) return;
const trackball = this.plugin.canvas3d.props.trackball;
const spinning = trackball.spin;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
@@ -133,7 +141,7 @@ class BasicWrapper {
const visuals = state.selectQ(q => q.ofTransformer(StateTransforms.Representation.StructureRepresentation3D));
const tree = state.build();
const colorTheme = { name: StripedResidues.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(StripedResidues.Descriptor.name).defaultValues };
const colorTheme = { name: StripedResidues.propertyProvider.descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(StripedResidues.propertyProvider.descriptor.name).defaultValues };
for (const v of visuals) {
tree.to(v).update(old => ({ ...old, colorTheme }));
@@ -143,6 +151,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;
@@ -158,6 +182,23 @@ class BasicWrapper {
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

@@ -50,16 +50,16 @@ export function buildStaticSuperposition(ctx: PluginContext, src: SuperpositionT
export const StaticSuperpositionTestData: SuperpositionTestInput = [
{ pdbId: '1aj5', auth_asym_id: 'A', matrix: Mat4.identity() },
{ pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows(
[[0.406, 0.879, 0.248, -200.633],
[0.693, -0.473, 0.544, 73.403],
[0.596, -0.049, -0.802, -14.209],
[0, 0, 0, 1]] )},
{ pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows(
[[-0.053, -0.077, 0.996, -45.633],
[-0.312, 0.949, 0.057, -12.255],
[-0.949, -0.307, -0.074, 53.562],
[0, 0, 0, 1]] )}
{ pdbId: '1df0', auth_asym_id: 'B', matrix: Mat4.ofRows([
[0.406, 0.879, 0.248, -200.633],
[0.693, -0.473, 0.544, 73.403],
[0.596, -0.049, -0.802, -14.209],
[0, 0, 0, 1]] )},
{ pdbId: '1dvi', auth_asym_id: 'A', matrix: Mat4.ofRows([
[-0.053, -0.077, 0.996, -45.633],
[-0.312, 0.949, 0.057, -12.255],
[-0.949, -0.307, -0.074, 53.562],
[0, 0, 0, 1]] )}
];
export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[], comp_id: string) {
@@ -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

@@ -226,8 +226,8 @@ const CCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif'
const PVCD_URL = 'http://ftp.wwpdb.org/pub/pdb/data/monomers/aa-variants-v1.cif'
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Create a cif file with one big table of all chem_comp_bond entries from the CCD and PVCD.'
addHelp: true,
description: 'Create a cif file with one big table of all chem_comp_bond entries from the CCD and PVCD.'
});
parser.addArgument('out', {
help: 'Generated file output path.'

View File

@@ -13,7 +13,7 @@ import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/tran
import { PluginStateObject as PSO } from '../../../mol-plugin/state/objects';
import { StateBuilder } from '../../../mol-state';
import { Canvas3DProps } from '../../../mol-canvas3d/canvas3d';
require('mol-plugin/skin/light.scss')
require('mol-plugin-ui/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb'
type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
@@ -97,15 +97,15 @@ class LightingDemo {
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: {
...props,
multiSample: {
...this.plugin.canvas3d.props.multiSample,
...this.plugin.canvas3d!.props.multiSample,
...props.multiSample
},
renderer: {
...this.plugin.canvas3d.props.renderer,
...this.plugin.canvas3d!.props.renderer,
...props.renderer
},
postprocessing: {
...this.plugin.canvas3d.props.postprocessing,
...this.plugin.canvas3d!.props.postprocessing,
...props.postprocessing
},
}});

View File

@@ -22,6 +22,7 @@ function paramInfo(param: PD.Any, offset: number): string {
case 'color-list': return `One of ${oToS(param.options)}`;
case 'vec3': return `3D vector [x, y, z]`;
case 'file': return `JavaScript File Handle`;
case 'file-list': return `JavaScript FileList Handle`;
case 'select': return `One of ${oToS(param.options)}`;
case 'text': return 'String';
case 'interval': return `Interval [min, max]`;
@@ -38,7 +39,7 @@ function paramInfo(param: PD.Any, offset: number): string {
}
}
function oToS(options: [string, string][]) {
function oToS(options: readonly (readonly [string, string])[]) {
return options.map(o => `'${o[0]}'`).join(', ');
}

View File

@@ -15,6 +15,9 @@ 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';
import { ModelSecondaryStructure } from '../../mol-model-formats/structure/property/secondary-structure';
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
async function downloadFromPdb(pdb: string) {
@@ -49,8 +52,10 @@ export function residueLabel(model: Model, rI: number) {
export function printSecStructure(model: Model) {
console.log('\nSecondary Structure\n=============');
const { residues } = model.atomicHierarchy;
const { key, elements } = model.properties.secondaryStructure;
const secondaryStructure = ModelSecondaryStructure.Provider.get(model);
if (!secondaryStructure) return
const { key, elements } = secondaryStructure
const count = residues._rowCount;
let rI = 0;
while (rI < count) {
@@ -64,14 +69,14 @@ export function printSecStructure(model: Model) {
}
}
export function printLinks(structure: Structure, showIntra: boolean, showInter: boolean) {
export function printBonds(structure: Structure, showIntra: boolean, showInter: boolean) {
if (showIntra) {
console.log('\nIntra Unit Links\n=============');
console.log('\nIntra Unit Bonds\n=============');
for (const unit of structure.units) {
if (!Unit.isAtomic(unit)) continue;
const elements = unit.elements;
const { a, b, edgeCount } = unit.links;
const { a, b, edgeCount } = unit.bonds;
const { model } = unit;
if (!edgeCount) continue;
@@ -85,20 +90,20 @@ export function printLinks(structure: Structure, showIntra: boolean, showInter:
}
if (showInter) {
console.log('\nInter Unit Links\n=============');
const links = structure.links;
console.log('\nInter Unit Bonds\n=============');
const bonds = structure.interUnitBonds;
for (const unit of structure.units) {
if (!Unit.isAtomic(unit)) continue;
for (const pairLinks of links.getLinkedUnits(unit)) {
if (!pairLinks.areUnitsOrdered || pairLinks.bondCount === 0) continue;
for (const pairBonds of bonds.getConnectedUnits(unit)) {
if (!pairBonds.areUnitsOrdered || pairBonds.edgeCount === 0) continue;
const { unitA, unitB } = pairLinks;
console.log(`${pairLinks.unitA.id} - ${pairLinks.unitB.id}: ${pairLinks.bondCount} bond(s)`);
const { unitA, unitB } = pairBonds;
console.log(`${pairBonds.unitA.id} - ${pairBonds.unitB.id}: ${pairBonds.edgeCount} bond(s)`);
for (const aI of pairLinks.linkedElementIndices) {
for (const link of pairLinks.getBonds(aI)) {
console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[link.indexB])}`);
for (const aI of pairBonds.connectedIndices) {
for (const bond of pairBonds.getEdges(aI)) {
console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[bond.indexB])}`);
}
}
}
@@ -110,9 +115,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();
}
@@ -146,7 +152,7 @@ export function printRings(structure: Structure) {
export function printUnits(structure: Structure) {
console.log('\nUnits\n=============');
const l = StructureElement.Location.create();
const l = StructureElement.Location.create(structure);
for (const unit of structure.units) {
l.unit = unit;
@@ -159,14 +165,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)}]`);
}
@@ -177,7 +183,8 @@ export function printUnits(structure: Structure) {
export function printSymmetryInfo(model: Model) {
console.log('\nSymmetry Info\n=============');
const { symmetry } = model;
const symmetry = ModelSymmetry.Provider.get(model)
if (!symmetry) return
const { size, anglesInRadians } = symmetry.spacegroup.cell;
console.log(`Spacegroup: ${symmetry.spacegroup.name} size: ${Vec3.toString(size)} angles: ${Vec3.toString(anglesInRadians)}`);
console.log(`Assembly names: ${symmetry.assemblies.map(a => a.id).join(', ')}`);
@@ -212,8 +219,8 @@ async function run(frame: CifFrame, args: Args) {
if (args.units) printUnits(structure);
if (args.sym) printSymmetryInfo(models[0]);
if (args.rings) printRings(structure);
if (args.intraLinks) printLinks(structure, true, false);
if (args.interLinks) printLinks(structure, false, true);
if (args.intraBonds) printBonds(structure, true, false);
if (args.interBonds) printBonds(structure, false, true);
if (args.mod) printModRes(models[0]);
if (args.sec) printSecStructure(models[0]);
}
@@ -240,8 +247,8 @@ parser.addArgument(['--seq'], { help: 'print sequence', action: 'storeTrue' });
parser.addArgument(['--units'], { help: 'print units', action: 'storeTrue' });
parser.addArgument(['--sym'], { help: 'print symmetry', action: 'storeTrue' });
parser.addArgument(['--rings'], { help: 'print rings', action: 'storeTrue' });
parser.addArgument(['--intraLinks'], { help: 'print intra unit links', action: 'storeTrue' });
parser.addArgument(['--interLinks'], { help: 'print inter unit links', action: 'storeTrue' });
parser.addArgument(['--intraBonds'], { help: 'print intra unit bonds', action: 'storeTrue' });
parser.addArgument(['--interBonds'], { help: 'print inter unit bonds', action: 'storeTrue' });
parser.addArgument(['--mod'], { help: 'print modified residues', action: 'storeTrue' });
parser.addArgument(['--sec'], { help: 'print secoundary structure', action: 'storeTrue' });
interface Args {
@@ -254,8 +261,8 @@ interface Args {
units?: boolean,
sym?: boolean,
rings?: boolean,
intraLinks?: boolean,
interLinks?: boolean,
intraBonds?: boolean,
interBonds?: boolean,
mod?: boolean,
sec?: boolean,
}

View File

@@ -16,7 +16,7 @@ import { Table } from '../../mol-data/db';
import { StringBuilder } from '../../mol-util';
import { Task } from '../../mol-task';
import { createVolumeIsosurfaceMesh } from '../../mol-repr/volume/isosurface';
import { createEmptyTheme } from '../../mol-theme/theme';
import { Theme } from '../../mol-theme/theme';
import { volumeFromDensityServerData } from '../../mol-model-formats/volume/density-server';
require('util.promisify').shim();
@@ -40,7 +40,7 @@ function print(data: Volume) {
}
async function doMesh(data: Volume, filename: string) {
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, data.volume, createEmptyTheme(), { isoValue: VolumeIsoValue.absolute(1.5) } )).run();
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, data.volume, Theme.createEmpty(), { isoValue: VolumeIsoValue.absolute(1.5) } )).run();
console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount });
// Export the mesh in OBJ format.
@@ -77,8 +77,8 @@ async function run(url: string, meshFilename: string) {
}
const parser = new argparse.ArgumentParser({
addHelp: true,
description: 'Info about VolumeData from mol-model module'
addHelp: true,
description: 'Info about VolumeData from mol-model module'
});
parser.addArgument([ '--emdb', '-e' ], {
help: 'EMDB id, for example 8116',

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -10,8 +10,8 @@ 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 { trajectoryFromMmCIF } from '../../../../mol-model-formats/structure/mmcif';
import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext, Unit } from '../../../../mol-model/structure';
import { trajectoryFromMmCIF, MmcifFormat } from '../../../../mol-model-formats/structure/mmcif';
import { trajectoryFromPDB } from '../../../../mol-model-formats/structure/pdb';
import { Mat4, Vec3, Quat } from '../../../../mol-math/linear-algebra';
import { SymmetryOperator } from '../../../../mol-math/geometry';
@@ -28,11 +28,10 @@ import { compile } from '../../../../mol-script/runtime/query/compiler';
import { UniformColorThemeProvider } from '../../../../mol-theme/color/uniform';
import { ThemeRegistryContext } from '../../../../mol-theme/theme';
import { ColorTheme } from '../../../../mol-theme/color';
import { _parse_mmCif } from '../../../../mol-model-formats/structure/mmcif/parser';
import { ModelFormat } from '../../../../mol-model-formats/structure/format';
import { CifCategory, CifField } from '../../../../mol-io/reader/cif';
import { mmCIF_Schema } from '../../../../mol-io/reader/cif/schema/mmcif';
import { Column } from '../../../../mol-data/db';
import { createModels } from '../../../../mol-model-formats/structure/basic/parser';
function getCellPackModelUrl(fileName: string, baseUrl: string) {
return `${baseUrl}/results/${fileName}`
@@ -124,7 +123,10 @@ function getAssembly(transforms: Mat4[], structure: Structure) {
}
function getCifCurve(name: string, transforms: Mat4[], model: Model) {
const d = model.sourceData.data.atom_site
if (!MmcifFormat.is(model.sourceData)) throw new Error('mmcif source data needed')
const { db } = model.sourceData.data
const d = db.atom_site
const n = d._rowCount
const rowCount = n * transforms.length
@@ -201,8 +203,8 @@ function getCifCurve(name: string, transforms: Mat4[], model: Model) {
}
const categories = {
entity: CifCategory.ofTable('entity', model.sourceData.data.entity),
chem_comp: CifCategory.ofTable('chem_comp', model.sourceData.data.chem_comp),
entity: CifCategory.ofTable('entity', db.entity),
chem_comp: CifCategory.ofTable('chem_comp', db.chem_comp),
atom_site: CifCategory.ofFields('atom_site', _atom_site)
}
@@ -217,8 +219,8 @@ async function getCurve(name: string, transforms: Mat4[], model: Model) {
const cif = getCifCurve(name, transforms, model)
const curveModelTask = Task.create('Curve Model', async ctx => {
const format = ModelFormat.mmCIF(cif)
const models = await _parse_mmCif(format, ctx)
const format = MmcifFormat.fromFrame(cif)
const models = await createModels(format.data.db, format, ctx)
return models[0]
})
@@ -268,7 +270,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
}
@@ -279,6 +281,9 @@ export function createStructureFromCellPack(packing: CellPacking, baseUrl: strin
})
}
const RepresentationOptions = PD.arrayToOptions(['spacefill', 'gaussian-surface', 'point', 'ellipsoid'] as const)
type RepresentationName = (typeof RepresentationOptions)[0][0]
export const LoadCellPackModel = StateAction.build({
display: { name: 'Load CellPack Model' },
params: {
@@ -289,15 +294,11 @@ export const LoadCellPackModel = StateAction.build({
['influenza_model1.json', 'influenza_model1'],
['Mycoplasma1.5_mixed_pdb_fixed.cpr', 'Mycoplasma1.5_mixed_pdb_fixed'],
['curveTest', 'Curve Test'],
]),
] as const),
baseUrl: PD.Text(DefaultCellPackBaseUrl),
preset: PD.Group({
traceOnly: PD.Boolean(false),
representation: PD.Select('spacefill', [
['spacefill', 'Spacefill'],
['gaussian-surface', 'Gaussian Surface'],
['point', 'Point'],
] as ['spacefill' | 'gaussian-surface' | 'point', string][])
representation: PD.Select('spacefill', RepresentationOptions)
}, { isExpanded: true })
},
from: PSO.Root
@@ -385,17 +386,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 } }) as any
}
cellpackTree
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.createParams(ctx, Structure.Empty, {
repr: getReprParams(ctx, params.preset),
@@ -425,7 +426,7 @@ export const LoadCellPackModel = StateAction.build({
console.timeEnd('cellpack')
}));
function getReprParams(ctx: PluginContext, params: { representation: 'spacefill' | 'gaussian-surface' | 'point', traceOnly: boolean }) {
function getReprParams(ctx: PluginContext, params: { representation: RepresentationName, traceOnly: boolean }) {
const { representation, traceOnly } = params
switch (representation) {
case 'spacefill':
@@ -452,6 +453,11 @@ function getReprParams(ctx: PluginContext, params: { representation: 'spacefill'
ctx.structureRepresentation.registry.get('point'),
() => ({ ignoreHydrogens: true })
] as [any, any]
case 'ellipsoid':
return [
ctx.structureRepresentation.registry.get('orientation'),
() => ({})
] as [any, any]
}
}

View File

@@ -1,171 +1,168 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
// /**
// * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
// *
// * @author David Sehnal <david.sehnal@gmail.com>
// */
import { StateTree, StateBuilder, StateAction, State } from '../../../mol-state';
import { StateTransforms } from '../../../mol-plugin/state/transforms';
import { createModelTree, complexRepresentation } from '../../../mol-plugin/state/actions/structure';
import { PluginContext } from '../../../mol-plugin/context';
import { PluginStateObject } from '../../../mol-plugin/state/objects';
import { ParamDefinition } from '../../../mol-util/param-definition';
import { PluginCommands } from '../../../mol-plugin/command';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { PluginStateSnapshotManager } from '../../../mol-plugin/state/snapshots';
import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
import { Text } from '../../../mol-geo/geometry/text/text';
import { UUID } from '../../../mol-util';
import { ColorNames } from '../../../mol-util/color/names';
import { Camera } from '../../../mol-canvas3d/camera';
import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/transforms/representation';
// import { StateTree, StateBuilder, StateAction, State } from '../../../mol-state';
// import { StateTransforms } from '../../../mol-plugin/state/transforms';
// import { createModelTree } from '../../../mol-plugin/state/actions/structure';
// import { PluginContext } from '../../../mol-plugin/context';
// import { PluginStateObject } from '../../../mol-plugin/state/objects';
// import { ParamDefinition } from '../../../mol-util/param-definition';
// import { PluginCommands } from '../../../mol-plugin/command';
// import { Vec3 } from '../../../mol-math/linear-algebra';
// import { PluginStateSnapshotManager } from '../../../mol-plugin/state/snapshots';
// import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
// import { Text } from '../../../mol-geo/geometry/text/text';
// import { UUID } from '../../../mol-util';
// import { ColorNames } from '../../../mol-util/color/names';
// import { Camera } from '../../../mol-canvas3d/camera';
// import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/transforms/representation';
// import { createDefaultStructureComplex } from '../../../mol-plugin/util/structure-complex-helper';
export const CreateJoleculeState = StateAction.build({
display: { name: 'Jolecule State Import' },
params: { id: ParamDefinition.Text('1mbo') },
from: PluginStateObject.Root
})(async ({ ref, state, params }, plugin: PluginContext) => {
try {
const id = params.id.trim().toLowerCase();
const data = await plugin.runTask(plugin.fetch({ url: `https://jolecule.appspot.com/pdb/${id}.views.json`, type: 'json' })) as JoleculeSnapshot[];
// export const CreateJoleculeState = StateAction.build({
// display: { name: 'Jolecule State Import' },
// params: { id: ParamDefinition.Text('1mbo') },
// from: PluginStateObject.Root
// })(async ({ ref, state, params }, plugin: PluginContext) => {
// try {
// const id = params.id.trim().toLowerCase();
// const data = await plugin.runTask(plugin.fetch({ url: `https://jolecule.appspot.com/pdb/${id}.views.json`, type: 'json' })) as JoleculeSnapshot[];
data.sort((a, b) => a.order - b.order);
// data.sort((a, b) => a.order - b.order);
await PluginCommands.State.RemoveObject.dispatch(plugin, { state, ref });
plugin.state.snapshots.clear();
// await PluginCommands.State.RemoveObject.dispatch(plugin, { state, ref });
// plugin.state.snapshots.clear();
const template = createTemplate(plugin, state, id);
const snapshots = data.map((e, idx) => buildSnapshot(plugin, template, { e, idx, len: data.length }));
for (const s of snapshots) {
plugin.state.snapshots.add(s);
}
// const template = createTemplate(plugin, state, id);
// const snapshots = data.map((e, idx) => buildSnapshot(plugin, template, { e, idx, len: data.length }));
// for (const s of snapshots) {
// plugin.state.snapshots.add(s);
// }
PluginCommands.State.Snapshots.Apply.dispatch(plugin, { id: snapshots[0].snapshot.id });
} catch (e) {
plugin.log.error(`Jolecule Failed: ${e}`);
}
});
// PluginCommands.State.Snapshots.Apply.dispatch(plugin, { id: snapshots[0].snapshot.id });
// } catch (e) {
// plugin.log.error(`Jolecule Failed: ${e}`);
// }
// });
interface JoleculeSnapshot {
order: number,
distances: { i_atom1: number, i_atom2: number }[],
labels: { i_atom: number, text: string }[],
camera: { up: Vec3, pos: Vec3, in: Vec3, slab: { z_front: number, z_back: number, zoom: number } },
selected: number[],
text: string
}
// interface JoleculeSnapshot {
// order: number,
// distances: { i_atom1: number, i_atom2: number }[],
// labels: { i_atom: number, text: string }[],
// camera: { up: Vec3, pos: Vec3, in: Vec3, slab: { z_front: number, z_back: number, zoom: number } },
// selected: number[],
// text: string
// }
function createTemplate(plugin: PluginContext, state: State, id: string) {
const b = new StateBuilder.Root(state.tree);
const data = b.toRoot().apply(StateTransforms.Data.Download, { url: `https://www.ebi.ac.uk/pdbe/static/entry/${id}_updated.cif` }, { state: { isGhost: true }});
const model = createModelTree(data, 'cif');
const structure = model.apply(StateTransforms.Model.StructureFromModel, {});
complexRepresentation(plugin, structure, { hideWater: true });
return { tree: b.getTree(), structure: structure.ref };
}
// function createTemplate(plugin: PluginContext, state: State, id: string) {
// const b = new StateBuilder.Root(state.tree);
// const data = b.toRoot().apply(StateTransforms.Data.Download, { url: `https://www.ebi.ac.uk/pdbe/static/entry/${id}_updated.cif` }, { state: { isGhost: true }});
// const model = createModelTree(data, 'cif');
// const structure = model.apply(StateTransforms.Model.StructureFromModel);
// createDefaultStructureComplex(plugin, structure);
// return { tree: b.getTree(), structure: structure.ref };
// }
const labelOptions: ParamDefinition.Values<Text.Params> = {
...ParamDefinition.getDefaultValues(Text.Params),
tether: true,
sizeFactor: 1.3,
attachment: 'bottom-right',
offsetZ: 10,
background: true,
backgroundMargin: 0.2,
backgroundColor: ColorNames.skyblue,
backgroundOpacity: 0.9
}
// const distanceLabelOptions = {
// const labelOptions: ParamDefinition.Values<Text.Params> = {
// ...ParamDefinition.getDefaultValues(Text.Params),
// sizeFactor: 1,
// offsetX: 0,
// offsetY: 0,
// tether: true,
// sizeFactor: 1.3,
// attachment: 'bottom-right',
// offsetZ: 10,
// background: true,
// backgroundMargin: 0.2,
// backgroundColor: ColorNames.snow,
// backgroundColor: ColorNames.skyblue,
// backgroundOpacity: 0.9
// }
function buildSnapshot(plugin: PluginContext, template: { tree: StateTree, structure: string }, params: { e: JoleculeSnapshot, idx: number, len: number }): PluginStateSnapshotManager.Entry {
const b = new StateBuilder.Root(template.tree);
// // const distanceLabelOptions = {
// // ...ParamDefinition.getDefaultValues(Text.Params),
// // sizeFactor: 1,
// // offsetX: 0,
// // offsetY: 0,
// // offsetZ: 10,
// // background: true,
// // backgroundMargin: 0.2,
// // backgroundColor: ColorNames.snow,
// // backgroundOpacity: 0.9
// // }
let i = 0;
for (const l of params.e.labels) {
const expression = createExpression([l.i_atom]);
const group = b.to(template.structure)
.group(StateTransforms.Misc.CreateGroup, { label: `Label ${++i}` });
// function buildSnapshot(plugin: PluginContext, template: { tree: StateTree, structure: string }, params: { e: JoleculeSnapshot, idx: number, len: number }): PluginStateSnapshotManager.Entry {
// const b = new StateBuilder.Root(template.tree);
group
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: 'Atom' })
.apply(StateTransforms.Representation.StructureLabels3D, {
target: { name: 'static-text', params: { value: l.text || '' } },
options: labelOptions
});
// let i = 0;
// for (const l of params.e.labels) {
// const expression = createExpression([l.i_atom]);
// const group = b.to(template.structure)
// .group(StateTransforms.Misc.CreateGroup, { label: `Label ${++i}` });
group
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: MS.struct.modifier.wholeResidues([ expression ]), label: 'Residue' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick', { }));
}
if (params.e.selected && params.e.selected.length > 0) {
b.to(template.structure)
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: createExpression(params.e.selected), label: `Selected` })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick'));
}
// TODO
// for (const l of params.e.distances) {
// b.to('structure')
// .apply(StateTransforms.Model.StructureSelectionFromExpression, { query: createQuery([l.i_atom1, l.i_atom2]), label: `Distance ${++i}` })
// .apply(StateTransforms.Representation.StructureLabels3D, {
// target: { name: 'static-text', params: { value: l. || '' } },
// options: labelOptions
// });
// }
return PluginStateSnapshotManager.Entry({
id: UUID.create22(),
data: { tree: StateTree.toJSON(b.getTree()) },
camera: {
current: getCameraSnapshot(params.e.camera),
transitionStyle: 'animate',
transitionDurationInMs: 350
}
}, {
name: params.e.text
});
}
// group
// .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: 'Atom' })
// .apply(StateTransforms.Representation.StructureLabels3D, {
// target: { name: 'static-text', params: { value: l.text || '' } },
// options: labelOptions
// });
function getCameraSnapshot(e: JoleculeSnapshot['camera']): Camera.Snapshot {
const direction = Vec3.sub(Vec3.zero(), e.pos, e.in);
Vec3.normalize(direction, direction);
const up = Vec3.sub(Vec3.zero(), e.pos, e.up);
Vec3.normalize(up, up);
// group
// .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: MS.struct.modifier.wholeResidues([ expression ]), label: 'Residue' })
// .apply(StateTransforms.Representation.StructureRepresentation3D,
// StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick', { }));
// }
// if (params.e.selected && params.e.selected.length > 0) {
// b.to(template.structure)
// .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: createExpression(params.e.selected), label: `Selected` })
// .apply(StateTransforms.Representation.StructureRepresentation3D,
// StructureRepresentation3DHelpers.getDefaultParamsStatic(plugin, 'ball-and-stick'));
// }
// // TODO
// // for (const l of params.e.distances) {
// // b.to('structure')
// // .apply(StateTransforms.Model.StructureSelectionFromExpression, { query: createQuery([l.i_atom1, l.i_atom2]), label: `Distance ${++i}` })
// // .apply(StateTransforms.Representation.StructureLabels3D, {
// // target: { name: 'static-text', params: { value: l. || '' } },
// // options: labelOptions
// // });
// // }
// return PluginStateSnapshotManager.Entry({
// id: UUID.create22(),
// data: { tree: StateTree.toJSON(b.getTree()) },
// camera: {
// current: getCameraSnapshot(params.e.camera),
// transitionStyle: 'animate',
// transitionDurationInMs: 350
// }
// }, {
// name: params.e.text
// });
// }
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
};
return s;
}
// function getCameraSnapshot(e: JoleculeSnapshot['camera']): Camera.Snapshot {
// const direction = Vec3.sub(Vec3(), e.pos, e.in);
// Vec3.normalize(direction, direction);
// const up = Vec3.sub(Vec3(), e.pos, e.up);
// Vec3.normalize(up, up);
function createExpression(atomIndices: number[]) {
if (atomIndices.length === 0) return MS.struct.generator.empty();
// const s: Camera.Snapshot = {
// mode: 'perspective',
// fov: Math.PI / 4,
// 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;
// }
return MS.struct.generator.atomGroups({
'atom-test': atomIndices.length === 1
? MS.core.rel.eq([MS.struct.atomProperty.core.sourceIndex(), atomIndices[0]])
: MS.core.set.has([MS.set.apply(null, atomIndices), MS.struct.atomProperty.core.sourceIndex()]),
'group-by': 0
});
}
// function createExpression(atomIndices: number[]) {
// if (atomIndices.length === 0) return MS.struct.generator.empty();
// return MS.struct.generator.atomGroups({
// 'atom-test': atomIndices.length === 1
// ? MS.core.rel.eq([MS.struct.atomProperty.core.sourceIndex(), atomIndices[0]])
// : MS.core.set.has([MS.set.apply(null, atomIndices), MS.struct.atomProperty.core.sourceIndex()]),
// 'group-by': 0
// });
// }

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

@@ -5,15 +5,16 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import '../../mol-util/polyfill';
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';
import { CreateJoleculeState } from './extensions/jolecule';
import { LoadCellPackModel } from './extensions/cellpack/model';
import { StructureFromCellpack } from './extensions/cellpack/state';
require('mol-plugin/skin/light.scss')
require('mol-plugin-ui/skin/light.scss')
function getParam(name: string, regex: string): string {
let r = new RegExp(`${name}=(${regex})[&]?`, 'i');
@@ -26,7 +27,7 @@ function init() {
const spec: PluginSpec = {
actions: [
...DefaultPluginSpec.actions,
PluginSpec.Action(CreateJoleculeState),
// PluginSpec.Action(CreateJoleculeState),
PluginSpec.Action(LoadCellPackModel),
PluginSpec.Action(StructureFromCellpack),
],
@@ -41,7 +42,8 @@ function init() {
controls: {
...DefaultPluginSpec.layout && DefaultPluginSpec.layout.controls
}
}
},
config: DefaultPluginSpec.config
};
const plugin = createPlugin(document.getElementById('app')!, spec);
trySetSnapshot(plugin);

View File

@@ -1,12 +1,14 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { CustomElementProperty } from '../../mol-model-props/common/custom-element-property';
import { Model, ElementIndex, ResidueIndex } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
import { CustomProperty } from '../../mol-model-props/common/custom-property';
const EvolutionaryConservationPalette: Color[] = [
[255, 255, 129], // insufficient
@@ -23,13 +25,13 @@ const EvolutionaryConservationPalette: Color[] = [
const EvolutionaryConservationDefaultColor = Color(0x999999);
export const EvolutionaryConservation = CustomElementProperty.create<number>({
isStatic: true,
name: 'proteopedia-wrapper-evolutionary-conservation',
display: 'Evolutionary Conservation',
async getData(model: Model) {
label: 'Evolutionary Conservation',
type: 'static',
async getData(model: Model, ctx: CustomProperty.Context) {
const id = model.entryId.toLowerCase();
const req = await fetch(`https://proteopedia.org/cgi-bin/cnsrf?${id}`);
const json = await req.json();
const url = `https://proteopedia.org/cgi-bin/cnsrf?${id}`
const json = await ctx.fetch({ url, type: 'json' }).runInContext(ctx.runtime)
const annotations = (json && json.residueAnnotations) || [];
const conservationMap = new Map<string, number>();
@@ -65,7 +67,7 @@ export const EvolutionaryConservation = CustomElementProperty.create<number>({
},
defaultColor: EvolutionaryConservationDefaultColor
},
format(e) {
getLabel(e) {
if (e === 10) return `Evolutionary Conservation: InsufficientData`;
return e ? `Evolutionary Conservation: ${e}` : void 0;
}

View File

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

View File

@@ -6,7 +6,7 @@
*/
import { Unit, StructureProperties, StructureElement, Link } from '../../mol-model/structure';
import { Unit, StructureProperties, StructureElement, Bond } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
import { Location } from '../../mol-model/location';
@@ -54,7 +54,7 @@ export function createProteopediaCustomTheme(colors: number[]) {
const colors = props.colors, colorCount = colors.length, defaultColor = colors[0].color;
if (ctx.structure) {
const l = StructureElement.Location.create()
const l = StructureElement.Location.create(ctx.structure)
const { models } = ctx.structure
const asymIdSerialMap = new Map<string, number>()
for (let i = 0, il = models.length; i < il; ++i) {
@@ -71,7 +71,7 @@ export function createProteopediaCustomTheme(colors: number[]) {
const asym_id = getAsymId(location.unit);
const o = asymIdSerialMap.get(asym_id(location)) || 0;
return colors[o % colorCount].color;
} else if (Link.isLocation(location)) {
} else if (Bond.isLocation(location)) {
const asym_id = getAsymId(location.aUnit)
l.unit = location.aUnit
l.element = location.aUnit.elements[location.aIndex]

View File

@@ -9,6 +9,7 @@ import { BuiltInStructureRepresentationsName } from '../../mol-repr/structure/re
import { BuiltInColorThemeName } from '../../mol-theme/color';
import { AminoAcidNames } from '../../mol-model/structure/model/types';
import { PluginContext } from '../../mol-plugin/context';
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
export interface ModelInfo {
hetResidues: { name: string, indices: ResidueIndex[] }[],
@@ -72,10 +73,11 @@ export namespace ModelInfo {
}
const preferredAssemblyId = await pref;
const symmetry = ModelSymmetry.Provider.get(model)
return {
hetResidues: hetResidues,
assemblies: model.symmetry.assemblies.map(a => ({ id: a.id, details: a.details, isPreferred: a.id === preferredAssemblyId })),
assemblies: symmetry ? symmetry.assemblies.map(a => ({ id: a.id, details: a.details, isPreferred: a.id === preferredAssemblyId })) : [],
preferredAssemblyId
};
}

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,16 +28,15 @@ 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';
// import { Text } from 'mol-geo/geometry/text/text';
require('../../mol-plugin/skin/light.scss')
require('../../mol-plugin-ui/skin/light.scss')
class MolStarProteopediaWrapper {
static VERSION_MAJOR = 3;
static VERSION_MINOR = 3;
static VERSION_MINOR = 4;
private _ev = RxEventHelper.create();
@@ -69,9 +68,9 @@ class MolStarProteopediaWrapper {
const customColoring = createProteopediaCustomTheme((options && options.customColorList) || []);
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add('proteopedia-custom', customColoring);
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(EvolutionaryConservation.Descriptor.name, EvolutionaryConservation.colorTheme!);
this.plugin.lociLabels.addProvider(EvolutionaryConservation.labelProvider);
this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider);
this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(EvolutionaryConservation.propertyProvider.descriptor.name, EvolutionaryConservation.colorThemeProvider!);
this.plugin.lociLabels.addProvider(EvolutionaryConservation.labelProvider!);
this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider, true);
}
get state() {
@@ -95,7 +94,7 @@ class MolStarProteopediaWrapper {
const model = this.state.build().to(StateElements.Model);
const s = model
.apply(StateTransforms.Model.CustomModelProperties, { properties: [EvolutionaryConservation.Descriptor.name] }, { ref: StateElements.ModelProps, state: { isGhost: false } })
.apply(StateTransforms.Model.CustomModelProperties, { autoAttach: [EvolutionaryConservation.propertyProvider.descriptor.name], properties: {} }, { ref: StateElements.ModelProps, state: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: StateElements.Assembly });
s.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: StateElements.Sequence });
@@ -161,9 +160,9 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.WaterVisual);
} else {
root.applyOrUpdate(StateElements.WaterVisual, StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
(style.water && style.water.kind) || 'ball-and-stick',
(style.water && style.water.coloring), structure, { alpha: 0.51 }));
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
(style.water && style.water.kind) || 'ball-and-stick',
(style.water && style.water.coloring), structure, { alpha: 0.51 }));
}
}
@@ -231,11 +230,13 @@ class MolStarProteopediaWrapper {
}
setBackground(color: number) {
if (!this.plugin.canvas3d) return;
const renderer = this.plugin.canvas3d.props.renderer;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
}
toggleSpin() {
if (!this.plugin.canvas3d) return;
const trackball = this.plugin.canvas3d.props.trackball;
const spinning = trackball.spin;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
@@ -298,7 +299,7 @@ class MolStarProteopediaWrapper {
// }
const tree = state.build();
const colorTheme = { name: EvolutionaryConservation.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(EvolutionaryConservation.Descriptor.name).defaultValues };
const colorTheme = { name: EvolutionaryConservation.propertyProvider.descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(EvolutionaryConservation.propertyProvider.descriptor.name).defaultValues };
if (!params || !!params.sequence) {
tree.to(StateElements.SequenceVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
@@ -315,9 +316,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 +338,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, { });
},
@@ -382,7 +385,8 @@ class MolStarProteopediaWrapper {
// const position = Vec3.sub(Vec3.zero(), sphere.center, asmCenter);
// Vec3.normalize(position, position);
// Vec3.scaleAndAdd(position, sphere.center, position, sphere.radius);
const snapshot = this.plugin.canvas3d.camera.getFocus(sphere.center, Math.max(sphere.radius, 5));
const radius = Math.max(sphere.radius, 5)
const snapshot = this.plugin.canvas3d!.camera.getFocus(sphere.center, radius, radius);
PluginCommands.Camera.SetSnapshot.dispatch(this.plugin, { snapshot, durationMs: 250 });
}
}
@@ -414,8 +418,7 @@ class MolStarProteopediaWrapper {
},
download: async (url: string) => {
try {
const data = await this.plugin.runTask(this.plugin.fetch({ url }));
const snapshot = JSON.parse(data);
const snapshot = await this.plugin.runTask(this.plugin.fetch({ url, type: 'json' }));
await this.plugin.state.setSnapshot(snapshot);
} catch (e) {
console.log(e);

View File

@@ -6,12 +6,12 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { PluginUIComponent } from '../../../mol-plugin/ui/base';
import { CurrentObject, PluginContextContainer } from '../../../mol-plugin/ui/plugin';
import { AnimationControls } from '../../../mol-plugin/ui/state/animation';
import { CameraSnapshots } from '../../../mol-plugin/ui/camera';
import { PluginUIComponent } from '../../../mol-plugin-ui/base';
import { CurrentObject, PluginContextContainer } from '../../../mol-plugin-ui/plugin';
import { AnimationControls } from '../../../mol-plugin-ui/state/animation';
import { CameraSnapshots } from '../../../mol-plugin-ui/camera';
import { PluginContext } from '../../../mol-plugin/context';
import { TransformUpdaterControl } from '../../../mol-plugin/ui/state/update-transform';
import { TransformUpdaterControl } from '../../../mol-plugin-ui/state/update-transform';
import { StateElements } from '../helpers';
export class ControlsWrapper extends PluginUIComponent {

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;
@@ -64,67 +63,53 @@ class Camera implements Object3D {
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON) || !Mat4.areEqual(this.view, this.prevView, EPSILON);
Mat4.mul(this.projectionView, this.projection, this.view)
Mat4.invert(this.inverseProjectionView, this.projectionView)
if (changed) {
Mat4.mul(this.projectionView, this.projection, this.view)
Mat4.invert(this.inverseProjectionView, this.projectionView)
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, radiusNear: number, radiusFar: 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 targetDistance = Math.abs((radiusNear / 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.radiusNear = radiusNear
state.radiusFar = radiusFar
state.position = Vec3.clone(this.newPosition)
if (up) Vec3.matchDirection(state.up, up, state.up)
return state
}
focus(target: Vec3, radiusNear: number, radiusFar: number, durationMs?: number, up?: Vec3, dir?: Vec3) {
if (radiusNear > 0 && radiusFar > 0) {
this.setState(this.getFocus(target, radiusNear, radiusFar, up, dir), durationMs);
}
return { target, position: Vec3.clone(this.newPosition) };
}
focus(target: Vec3, radius: number, dir?: Vec3) {
if (radius > 0) this.setState(this.getFocus(target, radius, dir));
}
// 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 +118,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 +128,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 +155,54 @@ 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,
radiusNear: 10,
radiusFar: 10,
fog: 50,
clipFar: true
};
}
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,
radiusNear: number
radiusFar: number
fog: number
clipFar: boolean
}
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.radiusNear !== 'undefined') out.radiusNear = source.radiusNear;
if (typeof source.radiusFar !== 'undefined') out.radiusFar = source.radiusFar;
if (typeof source.fog !== 'undefined') out.fog = source.fog;
if (typeof source.clipFar !== 'undefined') out.clipFar = source.clipFar;
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 +234,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 +258,31 @@ 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 { radiusNear, radiusFar, mode, fog, clipFar } = camera.state
const cDist = Vec3.distance(camera.position, camera.target)
let near = cDist - radiusNear
let far = cDist + (clipFar ? radiusNear : radiusFar)
const fogNearFactor = -(50 - fog) / 50
let fogNear = cDist - (radiusNear * fogNearFactor)
let fogFar = far
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,23 @@ 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.radiusNear = lerp(source.radiusNear, target.radiusNear, t);
// TODO take change of `clipFar` into account
out.radiusFar = lerp(source.radiusFar, target.radiusFar, 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) { // parallel
Vec3.scale(up, direction, -1)
} else if (Math.abs(d + 1) < EPSILON) { // 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

@@ -1,7 +1,8 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { BehaviorSubject, Subscription } from 'rxjs';
@@ -26,20 +27,21 @@ import { SetUtils } from '../mol-util/set';
import { Canvas3dInteractionHelper } from './helper/interaction-events';
import { PostprocessingParams, PostprocessingPass } from './passes/postprocessing';
import { MultiSampleParams, MultiSamplePass } from './passes/multi-sample';
import { GLRenderingContext } from '../mol-gl/webgl/compat';
import { PixelData } from '../mol-util/image';
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';
import { Sphere3D } from '../mol-math/geometry';
import { isDebugMode } from '../mol-util/debug';
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 }),
cameraClipFar: PD.Boolean(true),
cameraResetDurationMs: PD.Numeric(250, { min: 0, max: 1000, step: 1 }, { description: 'The time it takes to reset the camera.' }),
transparentBackground: PD.Boolean(false),
multiSample: PD.Group(MultiSampleParams),
postprocessing: PD.Group(PostprocessingParams),
@@ -55,28 +57,33 @@ export { Canvas3D }
interface Canvas3D {
readonly webgl: WebGLContext,
add: (repr: Representation.Any) => void
remove: (repr: Representation.Any) => void
update: (repr?: Representation.Any, keepBoundingSphere?: boolean) => void
clear: () => void
add(repr: Representation.Any): void
remove(repr: Representation.Any): void
/**
* This function must be called if animate() is not set up so that add/remove actions take place.
*/
commit(isSynchronous?: boolean): void
update(repr?: Representation.Any, keepBoundingSphere?: boolean): void
clear(): void
// draw: (force?: boolean) => void
requestDraw: (force?: boolean) => void
animate: () => void
identify: (x: number, y: number) => PickingId | undefined
mark: (loci: Representation.Loci, action: MarkerAction) => void
getLoci: (pickingId: PickingId) => Representation.Loci
requestDraw(force?: boolean): void
animate(): void
identify(x: number, y: number): PickingId | undefined
mark(loci: Representation.Loci, action: MarkerAction): void
getLoci(pickingId: PickingId): Representation.Loci
readonly didDraw: BehaviorSubject<now.Timestamp>
readonly reprCount: BehaviorSubject<number>
handleResize: () => void
handleResize(): void
/** Focuses camera on scene's bounding sphere, centered and zoomed. */
resetCamera: () => void
requestCameraReset(durationMs?: number): void
readonly camera: Camera
downloadScreenshot: () => void
getPixelData: (variant: GraphicsRenderVariant) => PixelData
setProps: (props: Partial<Canvas3DProps>) => void
readonly boundingSphere: Readonly<Sphere3D>
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>
@@ -84,29 +91,65 @@ interface Canvas3D {
readonly stats: RendererStats
readonly interaction: Canvas3dInteractionHelper['events']
dispose: () => void
dispose(): void
}
const requestAnimationFrame = typeof window !== 'undefined' ? window.requestAnimationFrame : (f: (time: number) => void) => setImmediate(()=>f(Date.now()))
const DefaultRunTask = (task: Task<unknown>) => task.run()
namespace Canvas3D {
export interface HighlightEvent { current: Representation.Loci, modifiers?: ModifiersKeys }
export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, 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)
return Canvas3D.create(gl, input, props, runTask)
const webgl = createContext(gl)
if (isDebugMode) {
const loseContextExt = gl.getExtension('WEBGL_lose_context')
if (loseContextExt) {
canvas.addEventListener('mousedown', e => {
if (webgl.isContextLost) return
if (!e.shiftKey || !e.ctrlKey || !e.altKey) return
console.log('lose context')
loseContextExt.loseContext()
setTimeout(() => {
if (!webgl.isContextLost) return
console.log('restore context')
loseContextExt.restoreContext()
}, 1000)
}, false)
}
}
// https://www.khronos.org/webgl/wiki/HandlingContextLost
canvas.addEventListener('webglcontextlost', e => {
webgl.setContextLost()
e.preventDefault()
if (isDebugMode) console.log('context lost')
}, false)
canvas.addEventListener('webglcontextrestored', () => {
if (!webgl.isContextLost) return
webgl.handleContextRestored()
if (isDebugMode) console.log('context restored')
}, false)
return Canvas3D.create(webgl, input, props, runTask)
}
export function create(gl: GLRenderingContext, input: InputObserver, props: Partial<Canvas3DProps> = {}, runTask = DefaultRunTask): Canvas3D {
export function create(webgl: WebGLContext, input: InputObserver, props: Partial<Canvas3DProps> = {}, runTask = DefaultRunTask): Canvas3D {
const p = { ...DefaultCanvas3DParams, ...props }
const reprRenderObjects = new Map<Representation.Any, Set<GraphicsRenderObject>>()
@@ -116,31 +159,38 @@ 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)
const { gl, contextRestored } = webgl
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,
clipFar: p.cameraClipFar
})
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)
const contextRestoredSub = contextRestored.subscribe(() => {
pickPass.pickDirty = true
draw(true)
})
let drawPending = false
let cameraResetRequested: boolean | Vec3 = false
let cameraResetRequested = false
let nextCameraResetDuration: number | undefined = void 0
function getLoci(pickingId: PickingId) {
let loci: Loci = EmptyLoci
@@ -148,7 +198,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,76 +224,35 @@ 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
function render(force: boolean) {
if (webgl.isContextLost) 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) {
switch (variant) {
case 'pick':
pickPass.render()
break;
case 'draw':
renderer.setViewport(0, 0, width, height);
if (multiSample.enabled) {
multiSample.render()
} else {
drawPass.render(!postprocessing.enabled)
if (postprocessing.enabled) postprocessing.render(true)
}
pickPass.pickDirty = true
break;
renderer.setViewport(0, 0, width, height)
if (multiSample.enabled) {
multiSample.render(true, p.transparentBackground)
} else {
drawPass.render(!postprocessing.enabled, p.transparentBackground)
if (postprocessing.enabled) postprocessing.render(true)
}
pickPass.pickDirty = true
didRender = true
}
return didRender && cameraChanged;
return didRender;
}
let forceNextDraw = false;
let currentTime = 0;
function draw(force?: boolean) {
if (render('draw', !!force || forceNextDraw)) {
if (render(!!force || forceNextDraw)) {
didDraw.next(now() - startTime as now.Timestamp)
}
forceNextDraw = false;
@@ -256,46 +267,93 @@ namespace Canvas3D {
function animate() {
currentTime = now();
commit();
camera.transition.tick(currentTime);
draw(false);
if (!camera.transition.inTransition) interactionHelper.tick(currentTime);
if (!camera.transition.inTransition && !webgl.isContextLost) {
interactionHelper.tick(currentTime);
}
requestAnimationFrame(animate)
}
function identify(x: number, y: number): PickingId | undefined {
return pickPass.identify(x, y)
return webgl.isContextLost ? undefined : pickPass.identify(x, y)
}
function commit(renderObjects?: readonly GraphicsRenderObject[]) {
scene.update(renderObjects, false)
function commit(isSynchronous: boolean = false) {
const allCommited = commitScene(isSynchronous);
// Only reset the camera after the full scene has been commited.
if (allCommited) resolveCameraReset();
}
runTask(scene.commit()).then(() => {
if (cameraResetRequested && !scene.isCommiting) {
const dir = typeof cameraResetRequested === 'boolean' ? undefined : cameraResetRequested
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius, dir)
cameraResetRequested = false
}
if (debugHelper.isEnabled) debugHelper.update()
requestDraw(true)
reprCount.next(reprRenderObjects.size)
})
function resolveCameraReset() {
if (!cameraResetRequested) return;
const { center, radius } = scene.boundingSphere;
camera.focus(center, radius, radius,
typeof nextCameraResetDuration === 'undefined' ? p.cameraResetDurationMs : nextCameraResetDuration);
nextCameraResetDuration = void 0;
cameraResetRequested = false;
}
const sceneCommitTimeoutMs = 250;
function commitScene(isSynchronous: boolean) {
if (!scene.needsCommit) return true;
if (!scene.commit(isSynchronous ? void 0 : sceneCommitTimeoutMs)) return false;
if (debugHelper.isEnabled) debugHelper.update();
reprCount.next(reprRenderObjects.size);
return true;
}
function add(repr: Representation.Any) {
registerAutoUpdate(repr);
const oldRO = reprRenderObjects.get(repr)
const newRO = new Set<GraphicsRenderObject>()
repr.renderObjects.forEach(o => newRO.add(o))
if (oldRO) {
if (!SetUtils.areEqual(newRO, oldRO)) {
for (const o of Array.from(newRO)) { if (!oldRO.has(o)) scene.add(o); }
for (const o of Array.from(oldRO)) { if (!newRO.has(o)) scene.remove(o) }
newRO.forEach(o => { if (!oldRO.has(o)) scene.add(o) })
oldRO.forEach(o => { if (!newRO.has(o)) scene.remove(o) })
}
} else {
repr.renderObjects.forEach(o => scene.add(o))
}
reprRenderObjects.set(repr, newRO)
commit(repr.renderObjects)
scene.update(repr.renderObjects, false)
}
function remove(repr: Representation.Any) {
unregisterAutoUpdate(repr);
const renderObjects = reprRenderObjects.get(repr)
if (renderObjects) {
renderObjects.forEach(o => scene.remove(o))
reprRenderObjects.delete(repr)
scene.update(repr.renderObjects, false, true)
}
}
function registerAutoUpdate(repr: Representation.Any) {
if (reprUpdatedSubscriptions.has(repr)) return;
reprUpdatedSubscriptions.set(repr, repr.updated.subscribe(_ => {
if (!repr.state.syncManually) add(repr);
}))
}
function unregisterAutoUpdate(repr: Representation.Any) {
const updatedSubscription = reprUpdatedSubscriptions.get(repr);
if (updatedSubscription) {
updatedSubscription.unsubscribe();
reprUpdatedSubscriptions.delete(repr);
}
}
handleResize()
@@ -303,24 +361,9 @@ namespace Canvas3D {
return {
webgl,
add: (repr: Representation.Any) => {
add(repr)
reprUpdatedSubscriptions.set(repr, repr.updated.subscribe(_ => {
if (!repr.state.syncManually) add(repr)
}))
},
remove: (repr: Representation.Any) => {
const updatedSubscription = reprUpdatedSubscriptions.get(repr)
if (updatedSubscription) {
updatedSubscription.unsubscribe()
}
const renderObjects = reprRenderObjects.get(repr)
if (renderObjects) {
renderObjects.forEach(o => scene.remove(o))
reprRenderObjects.delete(repr)
commit()
}
},
add,
remove,
commit,
update: (repr, keepSphere) => {
if (repr) {
if (!reprRenderObjects.has(repr)) return;
@@ -330,6 +373,8 @@ namespace Canvas3D {
}
},
clear: () => {
reprUpdatedSubscriptions.forEach(v => v.unsubscribe())
reprUpdatedSubscriptions.clear()
reprRenderObjects.clear()
scene.clear()
debugHelper.clear()
@@ -345,15 +390,12 @@ namespace Canvas3D {
getLoci,
handleResize,
resetCamera: (dir?: Vec3) => {
if (scene.isCommiting) {
cameraResetRequested = dir || true
} else {
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius, dir)
requestDraw(true);
}
requestCameraReset: (durationMs) => {
nextCameraResetDuration = durationMs;
cameraResetRequested = true;
},
camera,
boundingSphere: scene.boundingSphere,
downloadScreenshot: () => {
// TODO
},
@@ -372,9 +414,14 @@ 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.cameraClipFar !== undefined && props.cameraClipFar !== camera.state.clipFar) {
camera.setState({ clipFar: props.cameraClipFar })
}
if (props.cameraResetDurationMs !== undefined) p.cameraResetDurationMs = props.cameraResetDurationMs
if (props.transparentBackground !== undefined) p.transparentBackground = props.transparentBackground
if (props.postprocessing) postprocessing.setProps(props.postprocessing)
if (props.multiSample) multiSample.setProps(props.multiSample)
@@ -383,13 +430,17 @@ 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,
cameraClipFar: camera.state.clipFar,
cameraResetDurationMs: p.cameraResetDurationMs,
transparentBackground: p.transparentBackground,
postprocessing: { ...postprocessing.props },
multiSample: { ...multiSample.props },
@@ -408,12 +459,13 @@ namespace Canvas3D {
return interactionHelper.events
},
dispose: () => {
contextRestoredSub.unsubscribe()
scene.clear()
debugHelper.clear()
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 radiusNear = Math.max(1, camera.state.radiusNear + 10 * factor)
camera.setState({ radiusNear })
}
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) {
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({ radiusNear: 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

@@ -82,7 +82,7 @@ export class BoundingSphereHelper {
})
this.scene.update(void 0, false)
this.scene.syncCommit()
this.scene.commit()
}
syncVisibility() {

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;
@@ -36,6 +38,7 @@ export class Canvas3dInteractionHelper {
private inside = false;
private buttons: ButtonsType = ButtonsType.create(0);
private button: ButtonsType.Flag = ButtonsType.create(0);
private modifiers: ModifiersKeys = ModifiersKeys.None;
private identify(isClick: boolean, t: number) {
@@ -48,18 +51,18 @@ export class Canvas3dInteractionHelper {
if (!this.id) return;
if (isClick) {
this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, modifiers: this.modifiers });
this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, button: this.button, modifiers: this.modifiers });
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, button: this.button, modifiers: this.modifiers });
this.prevLoci = loci;
}
}
@@ -76,21 +79,24 @@ 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, button: this.button, modifiers: this.modifiers });
}
}
move(x: number, y: number, modifiers: ModifiersKeys) {
move(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
this.inside = true;
this.buttons = buttons;
this.button = button;
this.modifiers = modifiers;
this.cX = x;
this.cY = y;
}
select(x: number, y: number, buttons: ButtonsType, modifiers: ModifiersKeys) {
select(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
this.cX = x;
this.cY = y;
this.buttons = buttons;
this.button = button;
this.modifiers = modifiers;
this.identify(true, 0);
}
@@ -98,7 +104,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, button: this.button, modifiers: this.modifiers });
}
dispose() {
@@ -106,17 +112,17 @@ 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);
input.move.subscribe(({x, y, inside, buttons, button, modifiers }) => {
if (!inside) return;
this.move(x, y, buttons, button, modifiers);
});
input.leave.subscribe(() => {
this.leave();
});
input.click.subscribe(({x, y, buttons, modifiers }) => {
this.select(x, y, buttons, modifiers);
input.click.subscribe(({x, y, buttons, button, modifiers }) => {
this.select(x, y, buttons, button, modifiers);
});
input.modifiers.subscribe(modifiers => this.modify(modifiers));

View File

@@ -5,11 +5,12 @@
*/
import { WebGLContext } from '../../mol-gl/webgl/context';
import { createRenderTarget, RenderTarget } from '../../mol-gl/webgl/render-target';
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 { createTexture, Texture } from '../../mol-gl/webgl/texture';
import { Texture } from '../../mol-gl/webgl/texture';
import { Camera } from '../camera';
export class DrawPass {
colorTarget: RenderTarget
@@ -18,14 +19,14 @@ export class DrawPass {
private depthTarget: RenderTarget | null
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private debugHelper: BoundingSphereHelper) {
const { gl, extensions } = webgl
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private debugHelper: BoundingSphereHelper) {
const { gl, extensions, resources } = webgl
const width = gl.drawingBufferWidth
const height = gl.drawingBufferHeight
this.colorTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.colorTarget = webgl.createRenderTarget(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')
this.depthTarget = this.packedDepth ? webgl.createRenderTarget(width, height) : null
this.depthTexture = this.depthTarget ? this.depthTarget.texture : resources.texture('image-depth', 'depth', 'ushort', 'nearest')
if (!this.packedDepth) {
this.depthTexture.define(width, height)
this.depthTexture.attachFramebuffer(this.colorTarget.framebuffer, 'depth')
@@ -41,29 +42,33 @@ export class DrawPass {
}
}
render(toDrawingBuffer: boolean) {
const { webgl, renderer, scene, debugHelper, colorTarget, depthTarget } = this
const { gl } = webgl
render(toDrawingBuffer: boolean, transparentBackground: boolean) {
const { webgl, renderer, scene, camera, debugHelper, colorTarget, depthTarget } = this
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
colorTarget.bind()
if (!this.packedDepth) {
// TODO unlcear why it is not enough to call `attachFramebuffer` in `Texture.reset`
this.depthTexture.attachFramebuffer(this.colorTarget.framebuffer, 'depth')
}
}
renderer.setViewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)
renderer.render(scene, 'color', true)
renderer.setViewport(0, 0, colorTarget.getWidth(), colorTarget.getHeight())
renderer.render(scene, camera, 'color', true, transparentBackground)
if (debugHelper.isEnabled) {
debugHelper.syncVisibility()
renderer.render(debugHelper.scene, 'color', false)
renderer.render(debugHelper.scene, camera, 'color', false, transparentBackground)
}
// 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, transparentBackground)
if (debugHelper.isEnabled) {
debugHelper.syncVisibility()
renderer.render(debugHelper.scene, 'depth', false)
renderer.render(debugHelper.scene, camera, 'depth', false, transparentBackground)
}
}
}

View File

@@ -0,0 +1,98 @@
/**
* 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 = {
transparentBackground: PD.Boolean(false),
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 _transparentBackground = false
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._transparentBackground = p.transparentBackground
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) {
if (width === this._width && height === this._height) return
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.transparentBackground !== undefined) this._transparentBackground = props.transparentBackground
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._transparentBackground)
this._colorTarget = this.multiSample.colorTarget
} else {
this.drawPass.render(false, this._transparentBackground)
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

@@ -14,7 +14,7 @@ import { ShaderCode } from '../../mol-gl/shader-code';
import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
import { createComputeRenderable, ComputeRenderable } from '../../mol-gl/renderable';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { RenderTarget, createRenderTarget } from '../../mol-gl/webgl/render-target';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { Camera } from '../../mol-canvas3d/camera';
import { PostprocessingPass } from './postprocessing';
import { DrawPass } from './draw';
@@ -35,7 +35,7 @@ function getComposeRenderable(ctx: WebGLContext, colorTexture: Texture): Compose
const values: Values<typeof ComposeSchema> = {
...QuadValues,
tColor: ValueCell.create(colorTexture),
uTexSize: ValueCell.create(Vec2.create(colorTexture.width, colorTexture.height)),
uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())),
uWeight: ValueCell.create(1.0),
}
@@ -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,8 +66,9 @@ export class MultiSamplePass {
constructor(private webgl: WebGLContext, private camera: Camera, private drawPass: DrawPass, private postprocessing: PostprocessingPass, props: Partial<MultiSampleProps>) {
const { gl } = webgl
this.composeTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.holdTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.colorTarget = webgl.createRenderTarget(gl.drawingBufferWidth, gl.drawingBufferHeight)
this.composeTarget = webgl.createRenderTarget(gl.drawingBufferWidth, gl.drawingBufferHeight)
this.holdTarget = webgl.createRenderTarget(gl.drawingBufferWidth, gl.drawingBufferHeight)
this.compose = getComposeRenderable(webgl, drawPass.colorTarget.texture)
this.props = { ...PD.getDefaultValues(MultiSampleParams), ...props }
}
@@ -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, transparentBackground: boolean) {
if (this.props.mode === 'temporal') {
this.renderTemporalMultiSample()
this.renderTemporalMultiSample(toDrawingBuffer, transparentBackground)
} else {
this.renderMultiSample()
this.renderMultiSample(toDrawingBuffer, transparentBackground)
}
}
private renderMultiSample() {
private renderMultiSample(toDrawingBuffer: boolean, transparentBackground: boolean) {
const { camera, compose, composeTarget, drawPass, postprocessing, webgl } = this
const { gl, state } = webgl
@@ -128,14 +131,15 @@ export class MultiSamplePass {
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawPass.colorTarget.texture)
compose.update()
const { width, height } = drawPass.colorTarget
const width = drawPass.colorTarget.getWidth()
const height = drawPass.colorTarget.getHeight()
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
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
@@ -145,7 +149,7 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, sampleWeight)
// render scene and optionally postprocess
drawPass.render(false)
drawPass.render(false, transparentBackground)
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
@@ -168,16 +172,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, transparentBackground: boolean) {
const { camera, compose, composeTarget, holdTarget, postprocessing, drawPass, webgl } = this
const { gl, state } = webgl
@@ -197,7 +205,7 @@ export class MultiSamplePass {
const i = this.sampleIndex
if (i === 0) {
drawPass.render(false)
drawPass.render(false, transparentBackground)
if (postprocessing.enabled) postprocessing.render(false)
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawPass.colorTarget.texture)
@@ -215,7 +223,8 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, sampleWeight)
compose.update()
const { width, height } = drawPass.colorTarget
const width = drawPass.colorTarget.getWidth()
const height = drawPass.colorTarget.getHeight()
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
@@ -223,10 +232,10 @@ 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)
drawPass.render(false, transparentBackground)
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
@@ -252,7 +261,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 +274,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 +286,7 @@ export class MultiSamplePass {
}
camera.viewOffset.enabled = false
camera.updateMatrices()
camera.update()
if (this.sampleIndex >= offsetList.length) this.sampleIndex = -1
}
}

View File

@@ -5,11 +5,12 @@
*/
import { WebGLContext } from '../../mol-gl/webgl/context';
import { createRenderTarget, RenderTarget } from '../../mol-gl/webgl/render-target';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
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
@@ -35,9 +36,9 @@ export class PickPass {
this.pickWidth = Math.round(width * this.pickScale)
this.pickHeight = Math.round(height * this.pickScale)
this.objectPickTarget = createRenderTarget(webgl, this.pickWidth, this.pickHeight)
this.instancePickTarget = createRenderTarget(webgl, this.pickWidth, this.pickHeight)
this.groupPickTarget = createRenderTarget(webgl, this.pickWidth, this.pickHeight)
this.objectPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight)
this.instancePickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight)
this.groupPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight)
this.setupBuffers()
}
@@ -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, false);
this.instancePickTarget.bind();
renderer.render(scene, 'pickInstance', true);
renderer.render(scene, camera, 'pickInstance', true, false);
this.groupPickTarget.bind();
renderer.render(scene, 'pickGroup', true);
renderer.render(scene, camera, 'pickGroup', true, false);
this.pickDirty = false
}
@@ -96,6 +97,8 @@ export class PickPass {
identify(x: number, y: number): PickingId | undefined {
const { webgl, pickScale } = this
if (webgl.isContextLost) return
const { gl } = webgl
if (this.pickDirty) {
this.render()

View File

@@ -14,7 +14,7 @@ import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
import { createComputeRenderable, ComputeRenderable } from '../../mol-gl/renderable';
import { Vec2, Vec3 } from '../../mol-math/linear-algebra';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { createRenderTarget, RenderTarget } from '../../mol-gl/webgl/render-target';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { DrawPass } from './draw';
import { Camera } from '../../mol-canvas3d/camera';
@@ -27,7 +27,6 @@ const PostprocessingSchema = {
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
uTexSize: UniformSpec('v2'),
dUseFog: DefineSpec('boolean'),
dOrthographic: DefineSpec('number'),
uNear: UniformSpec('f'),
uFar: UniformSpec('f'),
@@ -56,8 +55,6 @@ export const PostprocessingParams = {
outlineEnable: PD.Boolean(false),
outlineScale: PD.Numeric(1, { min: 0, max: 10, step: 1 }),
outlineThreshold: PD.Numeric(0.8, { min: 0, max: 1, step: 0.01 }),
useFog: PD.Boolean(true),
}
export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
@@ -69,9 +66,8 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
...QuadValues,
tColor: ValueCell.create(colorTexture),
tDepth: ValueCell.create(depthTexture),
uTexSize: ValueCell.create(Vec2.create(colorTexture.width, colorTexture.height)),
uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())),
dUseFog: ValueCell.create(p.useFog),
dOrthographic: ValueCell.create(0),
uNear: ValueCell.create(1),
uFar: ValueCell.create(10000),
@@ -105,7 +101,7 @@ export class PostprocessingPass {
constructor(private webgl: WebGLContext, private camera: Camera, drawPass: DrawPass, props: Partial<PostprocessingProps>) {
const { gl } = webgl
this.target = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.target = webgl.createRenderTarget(gl.drawingBufferWidth, gl.drawingBufferHeight)
this.props = { ...PD.getDefaultValues(PostprocessingParams), ...props }
const { colorTarget, depthTexture, packedDepth } = drawPass
this.renderable = getPostprocessingRenderable(webgl, colorTarget.texture, depthTexture, packedDepth, this.props)
@@ -151,19 +147,14 @@ export class PostprocessingPass {
ValueCell.update(this.renderable.values.uOutlineThreshold, props.outlineThreshold)
}
if (props.useFog !== undefined) {
this.props.useFog = props.useFog
ValueCell.update(this.renderable.values.dUseFog, props.useFog)
}
this.renderable.update()
}
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

@@ -37,7 +37,7 @@ namespace Column {
export type Coordinate = { '@type': 'coord', T: number } & Base<'float'>
export type Tensor = { '@type': 'tensor', T: Tensors.Data, space: Tensors.Space, baseType: Int | Float } & Base<'tensor'>
export type Aliased<T> = { '@type': 'aliased', T: T } & Base<'str' | 'int'>
export type Aliased<T> = { '@type': 'aliased', T: T } & Base<T extends string ? 'str' : 'int'>
export type List<T extends number|string> = { '@type': 'list', T: T[], separator: string, itemParse: (x: string) => T } & Base<'list'>
export const str: Str = { '@type': 'str', T: '', valueType: 'str' };
@@ -92,7 +92,13 @@ namespace Column {
return !!v && !!(v as Column<any>).schema && !!(v as Column<any>).value;
}
export const enum ValueKind { Present = 0, NotPresent = 1, Unknown = 2 }
export const enum ValueKind {
Present = 0,
/** Expressed in CIF as `.` */
NotPresent = 1,
/** Expressed in CIF as `?` */
Unknown = 2
}
export function Undefined<T extends Schema>(rowCount: number, schema: T): Column<T['T']> {
return constColumn(schema['T'], rowCount, schema, ValueKind.NotPresent);
@@ -131,6 +137,14 @@ namespace Column {
return arrayColumn({ array, schema: Schema.str });
}
export function ofStringAliasArray<T extends string>(array: ArrayLike<T>) {
return arrayColumn<Schema.Aliased<T>>({ array, schema: Schema.Aliased(Schema.str) });
}
export function ofStringListArray<T extends string>(array: ArrayLike<T[]>, separator = ',') {
return arrayColumn<Schema.List<T>>({ array, schema: Schema.List<T>(separator, x => x as T) });
}
export function ofIntTokens(tokens: Tokens) {
const { count, data, indices } = tokens
return lambdaColumn({
@@ -290,14 +304,14 @@ function arrayColumn<T extends Column.Schema>({ array, schema, valueKind }: Colu
return ret;
}
: isTyped
? params => ColumnHelpers.typedArrayWindow(array, params) as any as ReadonlyArray<T>
: params => {
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
if (start === 0 && end === array.length) return array as ReadonlyArray<T['T']>;
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
for (let i = 0, _i = end - start; i < _i; i++) ret[i] = array[start + i];
return ret;
},
? params => ColumnHelpers.typedArrayWindow(array, params) as any as ReadonlyArray<T>
: params => {
const { start, end } = ColumnHelpers.getArrayBounds(rowCount, params);
if (start === 0 && end === array.length) return array as ReadonlyArray<T['T']>;
const ret = new (params && typeof params.array !== 'undefined' ? params.array : (array as any).constructor)(end - start) as any;
for (let i = 0, _i = end - start; i < _i; i++) ret[i] = array[start + i];
return ret;
},
areValuesEqual: (rowA, rowB) => array[rowA] === array[rowB]
}
}
@@ -311,7 +325,8 @@ function windowColumn<T>(column: Column<T>, start: number, end: number): Column<
function windowTyped<T>(c: Column<T>, start: number, end: number): Column<T> {
const array = ColumnHelpers.typedArrayWindow(c.__array, { start, end });
return arrayColumn({ array, schema: c.schema, valueKind: c.valueKind }) as any;
const vk = c.valueKind;
return arrayColumn({ array, schema: c.schema, valueKind: row => vk(start + row) }) as any;
}
function windowFull<T>(c: Column<T>, start: number, end: number): Column<T> {
@@ -343,9 +358,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);
}
@@ -353,7 +368,8 @@ function arrayView<T>(c: Column<T>, map: ArrayLike<number>): Column<T> {
const array = c.__array!;
const ret = new (array as any).constructor(map.length);
for (let i = 0, _i = map.length; i < _i; i++) ret[i] = array[map[i]];
return arrayColumn({ array: ret, schema: c.schema, valueKind: c.valueKind });
const vk = c.valueKind;
return arrayColumn({ array: ret, schema: c.schema, valueKind: row => vk(map[row]) });
}
function viewFull<T>(c: Column<T>, map: ArrayLike<number>): Column<T> {

View File

@@ -21,7 +21,8 @@ namespace Table {
export type Columns<S extends Schema> = { [C in keyof S]: Column<S[C]['T']> }
export type Row<S extends Schema> = { [C in keyof S]: S[C]['T'] }
export type Arrays<S extends Schema> = { [C in keyof S]: ArrayLike<S[C]['T']> }
export type PartialTable<S extends Table.Schema> = { readonly _rowCount: number, readonly _columns: ReadonlyArray<string> } & { [C in keyof S]?: Column<S[C]['T']> }
export type PartialColumns<S extends Schema> = { [C in keyof S]?: Column<S[C]['T']> }
export type PartialTable<S extends Table.Schema> = { readonly _rowCount: number, readonly _columns: ReadonlyArray<string> } & PartialColumns<S>
export function is(t: any): t is Table<any> {
return t && typeof t._rowCount === 'number' && !!t._columns && !!t._schema;
@@ -47,6 +48,19 @@ namespace Table {
return { _rowCount, _columns, _schema: schema, ...(columns as any) };
}
export function ofPartialColumns<S extends Schema, R extends Table<S> = Table<S>>(schema: S, partialColumns: PartialColumns<S>, rowCount: number): R {
const ret = Object.create(null);
const columns = Object.keys(schema);
ret._rowCount = rowCount;
ret._columns = columns;
ret._schema = schema;
for (const k of columns) {
if (k in partialColumns) ret[k] = partialColumns[k]
else ret[k] = Column.Undefined(rowCount, schema[k])
}
return ret;
}
export function ofUndefinedColumns<S extends Schema, R extends Table<S> = Table<S>>(schema: S, rowCount: number): R {
const ret = Object.create(null);
const columns = Object.keys(schema);
@@ -218,6 +232,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

@@ -90,14 +90,14 @@ class LinkedListImpl<T> implements LinkedList<T> {
if (node.previous !== null) {
node.previous.next = node.next;
}
else if (/*first == item*/ node.previous === null) {
else if (/* first == item*/ node.previous === null) {
this.first = node.next;
}
if (node.next !== null) {
node.next.previous = node.previous;
}
else if (/*last == item*/ node.next === null) {
else if (/* last == item*/ node.next === null) {
this.last = node.previous;
}

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,11 +1,12 @@
/**
* 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>
*/
import OrderedSet from '../ordered-set'
import Interval from '../interval'
import SortedArray from '../sorted-array';
describe('ordered set', () => {
function ordSetToArray(set: OrderedSet) {
@@ -81,6 +82,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);
@@ -156,6 +164,15 @@ describe('ordered set', () => {
testEq('intersect AA', OrderedSet.intersect(arr136, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [3, 6]);
it('intersect AA1', () => expect(OrderedSet.union(arr136, OrderedSet.ofSortedArray([1, 3, 6]))).toBe(arr136));
testEq('idxIntersect 1', OrderedSet.indexedIntersect(
OrderedSet.ofSortedArray([1, 2, 4]),
SortedArray.ofSortedArray([1, 2, 3, 4, 5, 6]),
SortedArray.ofSortedArray([2, 4, 5, 8])), [0, 2]);
testEq('idxIntersect 2', OrderedSet.indexedIntersect(
OrderedSet.ofSortedArray([0, 1]),
SortedArray.ofSortedArray([1, 2]),
SortedArray.ofSortedArray([1, 2])), [0, 1]);
testEq('subtract ES', OrderedSet.subtract(empty, singleton10), []);
testEq('subtract ER', OrderedSet.subtract(empty, range1_4), []);
testEq('subtract EA', OrderedSet.subtract(empty, arr136), []);

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>
*/
@@ -63,8 +63,102 @@ describe('sortedArray', () => {
compareArrays(SortedArray.indicesOf(SortedArray.ofSortedArray([10, 11, 12]), SortedArray.ofSortedArray([10, 12, 14])), [0, 2]);
})
it('indicesOf 2', () => {
compareArrays(
SortedArray.indicesOf(
SortedArray.ofSortedArray([0, 1, 2, 3, 4, 8, 9, 10]),
SortedArray.ofSortedArray([1, 3, 4, 9, 10])
),
[1, 3, 4, 6, 7]
);
})
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) {
@@ -286,4 +286,69 @@ export function forEach(set: OrderedSetImpl, f: (value: number, i: number, ctx:
}
}
return ctx;
}
export function forEachSegment(set: OrderedSetImpl, segment: (v: number) => number, f: (value: number, segIndex: number, ctx: any) => void, ctx: any) {
if (I.is(set)) {
let sI = 0;
for (let i = I.min(set), _i = I.max(set); i <= _i; i++) {
const s = segment(i);
let endI = i + 1;
while (endI < _i && segment(endI) === s) endI++;
i = endI - 1;
f(s, sI, ctx);
sI++;
}
} else {
let sI = 0;
for (let i = 0, _i = set.length; i < _i; i++) {
const s = segment(set[i]);
let endI = i + 1;
while (endI < _i && segment(set[endI]) === s) endI++;
i = endI - 1;
f(s, sI, ctx);
sI++;
}
}
return ctx;
}
export function indexedIntersect(idxA: OrderedSetImpl, a: S, b: S): OrderedSetImpl {
if (a === b) return idxA;
const lenI = size(idxA), lenA = a.length, lenB = b.length;
if (lenI === 0 || lenA === 0 || lenB === 0) return Empty;
const startJ = S.findPredecessorIndex(b, a[min(idxA)]);
const endJ = S.findPredecessorIndex(b, a[max(idxA)] + 1);
let commonCount = 0;
let offset = 0;
let O = 0;
let j = startJ;
while (O < lenI && j < endJ) {
const x = a[getAt(idxA, O)], y = b[j];
if (x < y) { O++; }
else if (x > y) { j++; }
else { commonCount++; O++; j++; }
}
// no common elements
if (commonCount === 0) return Empty;
// A === B
if (commonCount === lenA && commonCount === lenB) return idxA;
const indices = new Int32Array(commonCount);
offset = 0;
O = 0;
j = startJ;
while (O < lenI && j < endJ) {
const x = a[getAt(idxA, O)], y = b[j];
if (x < y) { O++; }
else if (x > y) { j++; }
else { indices[offset++] = j; O++; j++; }
}
return ofSortedArray(indices);
}

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

@@ -39,6 +39,7 @@ namespace OrderedSet {
export const union: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => OrderedSet<T> = Base.union as any;
export const intersect: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => OrderedSet<T> = Base.intersect as any;
export const indexedIntersect: <T extends number = number, S extends number = number>(idxA: OrderedSet<T>, a: SortedArray<S>, b: SortedArray<S>) => OrderedSet<T> = Base.indexedIntersect as any;
/** Returns elements of `a` that are not in `b`, i.e `a` - `b` */
export const subtract: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => OrderedSet<T> = Base.subtract as any;
@@ -56,6 +57,10 @@ namespace OrderedSet {
return Base.forEach(set as any, f as any, ctx);
}
export function forEachSegment<T extends number, S extends number, Ctx>(set: OrderedSet<T>, segment: (v: T) => S, f: (v: S, sI: number, ctx: Ctx) => void, ctx?: Ctx): Ctx {
return Base.forEachSegment(set as any, segment as any, f as any, ctx);
}
export function isInterval<T extends number = number>(set: OrderedSet<T>): set is Interval<T> {
return Interval.is(set);
}

View File

@@ -7,12 +7,12 @@
import { Interval, OrderedSet, SortedArray } from '../../int';
import { IntervalIterator } from '../interval-iterator';
describe('interval', () => {
describe('interval', () => {
function testIterator(name: string, interval: Interval, set: OrderedSet, expectedValues: { index: number[], start: number[], end: number[]}) {
it(`iterator, ${name}`, () => {
const intervalIt = new IntervalIterator(interval, set)
const { index, start, end } = expectedValues
let i = 0
while (intervalIt.hasNext) {
const segment = intervalIt.move()

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 Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -27,7 +27,7 @@ function nextIndex(n: number) {
return ripple | ones
};
export class CombinationIterator<T> implements Iterator<T[]> {
export class CombinationIterator<T> implements Iterator<ReadonlyArray<T>> {
private value: T[]
private index: number
private maxIndex: number

View File

@@ -9,8 +9,6 @@ import { ValueCell } from '../../mol-util';
import { BaseValues } from '../../mol-gl/renderable/schema';
import { LocationIterator } from '../util/location-iterator';
import { ParamDefinition as PD } from '../../mol-util/param-definition'
import { Color } from '../../mol-util/color';
import { Vec3 } from '../../mol-math/linear-algebra';
import { TransformData, createIdentityTransform } from './transform-data';
import { Theme } from '../../mol-theme/theme';
import { ColorNames } from '../../mol-util/color/names';
@@ -38,10 +36,6 @@ export const VisualQualityOptions = VisualQualityNames.map(n => [n, n] as [Visua
export namespace BaseGeometry {
export const Params = {
alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity' }),
useFog: PD.Boolean(true),
highlightColor: PD.Color(Color.fromNormalizedRgb(1.0, 0.4, 0.6)),
selectColor: PD.Color(Color.fromNormalizedRgb(0.2, 1.0, 0.1)),
quality: PD.Select<VisualQuality>('auto', VisualQualityOptions),
}
export type Params = typeof Params
@@ -62,24 +56,13 @@ export namespace BaseGeometry {
return {
alpha: ValueCell.create(props.alpha),
uAlpha: ValueCell.create(props.alpha),
uHighlightColor: ValueCell.create(Color.toArrayNormalized(props.highlightColor, Vec3.zero(), 0)),
uSelectColor: ValueCell.create(Color.toArrayNormalized(props.selectColor, Vec3.zero(), 0)),
dUseFog: ValueCell.create(props.useFog),
uGroupCount: ValueCell.create(counts.groupCount),
drawCount: ValueCell.create(counts.drawCount),
}
}
export function updateValues(values: BaseValues, props: PD.Values<Params>) {
if (Color.fromNormalizedArray(values.uHighlightColor.ref.value, 0) !== props.highlightColor) {
ValueCell.update(values.uHighlightColor, Color.toArrayNormalized(props.highlightColor, values.uHighlightColor.ref.value, 0))
}
if (Color.fromNormalizedArray(values.uSelectColor.ref.value, 0) !== props.selectColor) {
ValueCell.update(values.uSelectColor, Color.toArrayNormalized(props.selectColor, values.uSelectColor.ref.value, 0))
}
ValueCell.updateIfChanged(values.alpha, props.alpha) // `uAlpha` is set in renderable.render
ValueCell.updateIfChanged(values.dUseFog, props.useFog)
}
export function createRenderableState(props: Partial<PD.Values<Params>> = {}): RenderableState {

View File

@@ -18,7 +18,7 @@ import { createColors } from '../color-data';
import { createMarkers } from '../marker-data';
import { GeometryUtils } from '../geometry';
import { transformPositionArray } from '../../../mol-geo/util';
import { calculateBoundingSphere } from '../../../mol-gl/renderable/util';
import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { Theme } from '../../../mol-theme/theme';
import { RenderableState } from '../../../mol-gl/renderable';
import { ColorListOptions, ColorListName } from '../../../mol-util/color/lists';
@@ -26,12 +26,14 @@ import { Color } from '../../../mol-util/color';
import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
const VolumeBox = Box()
const RenderModeOptions = [['isosurface', 'Isosurface'], ['volume', 'Volume']] as [string, string][]
export interface DirectVolume {
readonly kind: 'direct-volume',
readonly gridTexture: ValueCell<Texture>,
readonly gridTextureDim: ValueCell<Vec3>,
readonly gridDimension: ValueCell<Vec3>,
@@ -41,32 +43,66 @@ export interface DirectVolume {
readonly transform: ValueCell<Mat4>
/** Bounding sphere of the volume */
boundingSphere?: Sphere3D
boundingSphere: Sphere3D
}
export namespace DirectVolume {
export function create(bbox: Box3D, gridDimension: Vec3, transform: Mat4, texture: Texture, directVolume?: DirectVolume): DirectVolume {
const { width, height, depth } = texture
if (directVolume) {
ValueCell.update(directVolume.gridDimension, gridDimension)
ValueCell.update(directVolume.gridTextureDim, Vec3.set(directVolume.gridTextureDim.ref.value, width, height, depth))
ValueCell.update(directVolume.bboxMin, bbox.min)
ValueCell.update(directVolume.bboxMax, bbox.max)
ValueCell.update(directVolume.bboxSize, Vec3.sub(directVolume.bboxSize.ref.value, bbox.max, bbox.min))
ValueCell.update(directVolume.transform, transform)
return directVolume
} else {
return {
kind: 'direct-volume',
gridDimension: ValueCell.create(gridDimension),
gridTexture: ValueCell.create(texture),
gridTextureDim: ValueCell.create(Vec3.create(width, height, depth)),
bboxMin: ValueCell.create(bbox.min),
bboxMax: ValueCell.create(bbox.max),
bboxSize: ValueCell.create(Vec3.sub(Vec3.zero(), bbox.max, bbox.min)),
transform: ValueCell.create(transform),
}
return directVolume ?
update(bbox, gridDimension, transform, texture, directVolume) :
fromData(bbox, gridDimension, transform, texture)
}
function hashCode(directVolume: DirectVolume) {
return hashFnv32a([
directVolume.bboxSize.ref.version, directVolume.gridDimension.ref.version,
directVolume.gridTexture.ref.version, directVolume.transform.ref.version,
])
}
function fromData(bbox: Box3D, gridDimension: Vec3, transform: Mat4, texture: Texture): DirectVolume {
const boundingSphere = Sphere3D()
let currentHash = -1
const width = texture.getWidth()
const height = texture.getHeight()
const depth = texture.getDepth()
const directVolume = {
kind: 'direct-volume' as const,
gridDimension: ValueCell.create(gridDimension),
gridTexture: ValueCell.create(texture),
gridTextureDim: ValueCell.create(Vec3.create(width, height, depth)),
bboxMin: ValueCell.create(bbox.min),
bboxMax: ValueCell.create(bbox.max),
bboxSize: ValueCell.create(Vec3.sub(Vec3.zero(), bbox.max, bbox.min)),
transform: ValueCell.create(transform),
get boundingSphere() {
const newHash = hashCode(directVolume)
if (newHash !== currentHash) {
const b = getBoundingSphere(directVolume.gridDimension.ref.value, directVolume.transform.ref.value)
Sphere3D.copy(boundingSphere, b)
currentHash = newHash
}
return boundingSphere
},
}
return directVolume
}
function update(bbox: Box3D, gridDimension: Vec3, transform: Mat4, texture: Texture, directVolume: DirectVolume): DirectVolume {
const width = texture.getWidth()
const height = texture.getHeight()
const depth = texture.getDepth()
ValueCell.update(directVolume.gridDimension, gridDimension)
ValueCell.update(directVolume.gridTexture, texture)
ValueCell.update(directVolume.gridTextureDim, Vec3.set(directVolume.gridTextureDim.ref.value, width, height, depth))
ValueCell.update(directVolume.bboxMin, bbox.min)
ValueCell.update(directVolume.bboxMax, bbox.max)
ValueCell.update(directVolume.bboxSize, Vec3.sub(directVolume.bboxSize.ref.value, bbox.max, bbox.min))
ValueCell.update(directVolume.transform, transform)
return directVolume
}
export function createEmpty(directVolume?: DirectVolume): DirectVolume {
@@ -108,7 +144,8 @@ export namespace DirectVolume {
const counts = { drawCount: VolumeBox.indices.length, groupCount, instanceCount }
const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(gridDimension.ref.value, gridTransform.ref.value, transform.aTransform.ref.value, transform.instanceCount.ref.value)
const invariantBoundingSphere = Sphere3D.clone(directVolume.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount)
const controlPoints = getControlPointsFromVec2Array(props.controlPoints)
const transferTex = createTransferFunctionTexture(controlPoints, props.list)
@@ -138,7 +175,7 @@ export namespace DirectVolume {
dRenderMode: ValueCell.create(props.renderMode),
tTransferTex: transferTex,
dGridTexType: ValueCell.create(gridTexture.ref.value.depth > 0 ? '3d' : '2d'),
dGridTexType: ValueCell.create(gridTexture.ref.value.getDepth() > 0 ? '3d' : '2d'),
uGridTexDim: gridTextureDim,
tGridTex: gridTexture,
}
@@ -153,7 +190,6 @@ export namespace DirectVolume {
function updateValues(values: DirectVolumeValues, props: PD.Values<Params>) {
ValueCell.updateIfChanged(values.uIsoValue, props.isoValueNorm)
ValueCell.updateIfChanged(values.uAlpha, props.alpha)
ValueCell.updateIfChanged(values.dUseFog, props.useFog)
ValueCell.updateIfChanged(values.dRenderMode, props.renderMode)
const controlPoints = getControlPointsFromVec2Array(props.controlPoints)
@@ -161,7 +197,9 @@ export namespace DirectVolume {
}
function updateBoundingSphere(values: DirectVolumeValues, directVolume: DirectVolume) {
const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(values.uGridDim.ref.value, values.uTransform.ref.value, values.aTransform.ref.value, values.instanceCount.ref.value)
const invariantBoundingSphere = Sphere3D.clone(directVolume.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)
}
@@ -188,11 +226,12 @@ const mTmp = Mat4.identity()
const mTmp2 = Mat4.identity()
const vHalfUnit = Vec3.create(0.5, 0.5, 0.5)
const tmpVertices = new Float32Array(VolumeBox.vertices.length)
function getBoundingSphere(gridDimension: Vec3, gridTransform: Mat4, transform: Float32Array, transformCount: number) {
function getBoundingSphere(gridDimension: Vec3, gridTransform: Mat4) {
tmpVertices.set(VolumeBox.vertices)
Mat4.fromTranslation(mTmp, vHalfUnit)
Mat4.mul(mTmp, Mat4.fromScaling(mTmp2, gridDimension), mTmp)
Mat4.mul(mTmp, gridTransform, mTmp)
transformPositionArray(mTmp, tmpVertices, 0, tmpVertices.length / 3)
return calculateBoundingSphere(tmpVertices, tmpVertices.length / 3, transform, transformCount)
return calculateInvariantBoundingSphere(tmpVertices, tmpVertices.length / 3, 1)
// return calculateBoundingSphere(tmpVertices, tmpVertices.length / 3, transform, transformCount)
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -19,32 +19,30 @@ import { Spheres } from './spheres/spheres';
import { arrayMax } from '../../mol-util/array';
import { TransformData } from './transform-data';
import { Theme } from '../../mol-theme/theme';
import { RenderObjectValuesType } from '../../mol-gl/render-object';
import { ValueOf } from '../../mol-util/type-helpers';
import { RenderObjectValues } from '../../mol-gl/render-object';
import { TextureMesh } from './texture-mesh/texture-mesh';
export type GeometryKindType = {
'mesh': Mesh,
'points': Points,
'spheres': Spheres,
'text': Text,
'lines': Lines,
'direct-volume': DirectVolume,
'texture-mesh': TextureMesh,
}
export type GeometryKindParams = {
'mesh': Mesh.Params,
'points': Points.Params,
'spheres': Spheres.Params,
'text': Text.Params,
'lines': Lines.Params,
'direct-volume': DirectVolume.Params,
'texture-mesh': TextureMesh.Params,
}
export type GeometryKind = keyof GeometryKindType
export type Geometry = ValueOf<GeometryKindType>
export type GeometryKind = 'mesh' | 'points' | 'spheres' | 'text' | 'lines' | 'direct-volume' | 'texture-mesh'
export interface GeometryUtils<G extends Geometry, P extends PD.Params = GeometryKindParams[G['kind']], V = RenderObjectValuesType[G['kind']]> {
export type Geometry<T extends GeometryKind = GeometryKind> =
T extends 'mesh' ? Mesh :
T extends 'points' ? Points :
T extends 'spheres' ? Spheres :
T extends 'text' ? Text :
T extends 'lines' ? Lines :
T extends 'direct-volume' ? DirectVolume :
T extends 'texture-mesh' ? TextureMesh : never
type GeometryParams<T extends GeometryKind> =
T extends 'mesh' ? Mesh.Params :
T extends 'points' ? Points.Params :
T extends 'spheres' ? Spheres.Params :
T extends 'text' ? Text.Params :
T extends 'lines' ? Lines.Params :
T extends 'direct-volume' ? DirectVolume.Params :
T extends 'texture-mesh' ? TextureMesh.Params : never
export interface GeometryUtils<G extends Geometry, P extends PD.Params = GeometryParams<G['kind']>, V = RenderObjectValues<G['kind']>> {
Params: P
createEmpty(geometry?: G): G
createValues(geometry: G, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: PD.Values<P>): V
@@ -56,7 +54,7 @@ export interface GeometryUtils<G extends Geometry, P extends PD.Params = Geometr
}
export namespace Geometry {
export type Params<G extends Geometry> = GeometryKindParams[G['kind']]
export type Params<G extends Geometry> = GeometryParams<G['kind']>
export function getDrawCount(geometry: Geometry): number {
switch (geometry.kind) {
@@ -66,7 +64,7 @@ export namespace Geometry {
case 'text': return geometry.charCount * 2 * 3
case 'lines': return geometry.lineCount * 2 * 3
case 'direct-volume': return 12 * 3
case 'texture-mesh': return geometry.vertexCount.ref.value
case 'texture-mesh': return geometry.vertexCount
}
}
@@ -81,7 +79,7 @@ export namespace Geometry {
case 'direct-volume':
return 1
case 'texture-mesh':
return geometry.groupCount.ref.value
return geometry.groupCount
}
}
@@ -96,7 +94,6 @@ export namespace Geometry {
case 'direct-volume': return DirectVolume.Utils as any
case 'texture-mesh': return TextureMesh.Utils as any
}
throw new Error('unknown geometry kind')
}
export function getGranularity(locationIt: LocationIterator, granularity: ColorType | SizeType) {

View File

@@ -1,10 +1,9 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../../mol-util/value-cell'
import { ChunkedArray } from '../../../mol-data/util';
import { Lines } from './lines';
import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
@@ -12,12 +11,15 @@ import { Cage } from '../../../mol-geo/primitive/cage';
export interface LinesBuilder {
add(startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, group: number): void
addFixedCountDashes(start: Vec3, end: Vec3, segmentCount: number, group: number): void
addFixedLengthDashes(start: Vec3, end: Vec3, segmentLength: number, group: number): void
addCage(t: Mat4, cage: Cage, group: number): void
getLines(): Lines
}
const tmpVecA = Vec3.zero()
const tmpVecB = Vec3.zero()
const tmpVecA = Vec3()
const tmpVecB = Vec3()
const tmpDir = Vec3()
export namespace LinesBuilder {
export function create(initialCount = 2048, chunkSize = 1024, lines?: Lines): LinesBuilder {
@@ -42,8 +44,29 @@ export namespace LinesBuilder {
ChunkedArray.add3(indices, offset + 1, offset + 3, offset + 2);
}
const addFixedCountDashes = (start: Vec3, end: Vec3, segmentCount: number, group: number) => {
const d = Vec3.distance(start, end)
const s = Math.floor(segmentCount / 2)
const step = 1 / segmentCount
Vec3.sub(tmpDir, end, start)
for (let j = 0; j < s; ++j) {
const f = step * (j * 2 + 1)
Vec3.setMagnitude(tmpDir, tmpDir, d * f)
Vec3.add(tmpVecA, start, tmpDir)
Vec3.setMagnitude(tmpDir, tmpDir, d * step * ((j + 1) * 2))
Vec3.add(tmpVecB, start, tmpDir)
add(tmpVecA[0], tmpVecA[1], tmpVecA[2], tmpVecB[0], tmpVecB[1], tmpVecB[2], group)
}
}
return {
add,
addFixedCountDashes,
addFixedLengthDashes: (start: Vec3, end: Vec3, segmentLength: number, group: number) => {
const d = Vec3.distance(start, end)
addFixedCountDashes(start, end, d / segmentLength, group)
},
addCage: (t: Mat4, cage: Cage, group: number) => {
const { vertices, edges } = cage
for (let i = 0, il = edges.length; i < il; i += 2) {
@@ -60,15 +83,7 @@ export namespace LinesBuilder {
const gb = ChunkedArray.compact(groups, true) as Float32Array
const sb = ChunkedArray.compact(starts, true) as Float32Array
const eb = ChunkedArray.compact(ends, true) as Float32Array
return {
kind: 'lines',
lineCount: indices.elementCount / 2,
mappingBuffer: lines ? ValueCell.update(lines.mappingBuffer, mb) : ValueCell.create(mb),
indexBuffer: lines ? ValueCell.update(lines.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: lines ? ValueCell.update(lines.groupBuffer, gb) : ValueCell.create(gb),
startBuffer: lines ? ValueCell.update(lines.startBuffer, sb) : ValueCell.create(sb),
endBuffer: lines ? ValueCell.update(lines.endBuffer, eb) : ValueCell.create(eb),
}
return Lines.create(mb, ib, gb, sb, eb, indices.elementCount / 2)
}
}
}

View File

@@ -1,12 +1,14 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../../mol-util'
import { Mat4 } from '../../../mol-math/linear-algebra'
import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
import { transformPositionArray,/* , transformDirectionArray, getNormalMatrix */
GroupMapping,
createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
import { createColors } from '../color-data';
import { createMarkers } from '../marker-data';
@@ -17,19 +19,22 @@ import { LinesValues } from '../../../mol-gl/renderable/lines';
import { Mesh } from '../mesh/mesh';
import { LinesBuilder } from './lines-builder';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { calculateBoundingSphere } from '../../../mol-gl/renderable/util';
import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { Sphere3D } from '../../../mol-math/geometry';
import { Theme } from '../../../mol-theme/theme';
import { Color } from '../../../mol-util/color';
import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
/** Wide line */
export interface Lines {
readonly kind: 'lines',
/** Number of lines */
lineCount: number,
/** Mapping buffer as array of xy values wrapped in a value cell */
readonly mappingBuffer: ValueCell<Float32Array>,
/** Index buffer as array of vertex index triplets wrapped in a value cell */
@@ -40,24 +45,27 @@ export interface Lines {
readonly startBuffer: ValueCell<Float32Array>,
/** Line end buffer as array of xyz values wrapped in a value cell */
readonly endBuffer: ValueCell<Float32Array>,
/** Bounding sphere of the lines */
readonly boundingSphere: Sphere3D
/** Maps group ids to line indices */
readonly groupMapping: GroupMapping
}
export namespace Lines {
export function create(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, lineCount: number, lines?: Lines): Lines {
return lines ?
update(mappings, indices, groups, starts, ends, lineCount, lines) :
fromArrays(mappings, indices, groups, starts, ends, lineCount)
}
export function createEmpty(lines?: Lines): Lines {
const mb = lines ? lines.mappingBuffer.ref.value : new Float32Array(0)
const ib = lines ? lines.indexBuffer.ref.value : new Uint32Array(0)
const gb = lines ? lines.groupBuffer.ref.value : new Float32Array(0)
const sb = lines ? lines.startBuffer.ref.value : new Float32Array(0)
const eb = lines ? lines.endBuffer.ref.value : new Float32Array(0)
return {
kind: 'lines',
lineCount: 0,
mappingBuffer: lines ? ValueCell.update(lines.mappingBuffer, mb) : ValueCell.create(mb),
indexBuffer: lines ? ValueCell.update(lines.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: lines ? ValueCell.update(lines.groupBuffer, gb) : ValueCell.create(gb),
startBuffer: lines ? ValueCell.update(lines.startBuffer, sb) : ValueCell.create(sb),
endBuffer: lines ? ValueCell.update(lines.endBuffer, eb) : ValueCell.create(eb),
}
return create(mb, ib, gb, sb, eb, 0, lines)
}
export function fromMesh(mesh: Mesh, lines?: Lines) {
@@ -81,16 +89,67 @@ export namespace Lines {
return builder.getLines();
}
export function transformImmediate(line: Lines, t: Mat4) {
transformRangeImmediate(line, t, 0, line.lineCount)
function hashCode(lines: Lines) {
return hashFnv32a([
lines.lineCount, lines.mappingBuffer.ref.version, lines.indexBuffer.ref.version,
lines.groupBuffer.ref.version, lines.startBuffer.ref.version, lines.startBuffer.ref.version
])
}
export function transformRangeImmediate(lines: Lines, t: Mat4, offset: number, count: number) {
function fromArrays(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, lineCount: number): Lines {
const boundingSphere = Sphere3D()
let groupMapping: GroupMapping
let currentHash = -1
let currentGroup = -1
const lines = {
kind: 'lines' as const,
lineCount,
mappingBuffer: ValueCell.create(mappings),
indexBuffer: ValueCell.create(indices),
groupBuffer: ValueCell.create(groups),
startBuffer: ValueCell.create(starts),
endBuffer: ValueCell.create(ends),
get boundingSphere() {
const newHash = hashCode(lines)
if (newHash !== currentHash) {
const s = calculateInvariantBoundingSphere(lines.startBuffer.ref.value, lines.lineCount * 4, 4)
const e = calculateInvariantBoundingSphere(lines.endBuffer.ref.value, lines.lineCount * 4, 4)
Sphere3D.expandBySphere(boundingSphere, s, e)
currentHash = newHash
}
return boundingSphere
},
get groupMapping() {
if (lines.groupBuffer.ref.version !== currentGroup) {
groupMapping = createGroupMapping(lines.groupBuffer.ref.value, lines.lineCount, 4)
currentGroup = lines.groupBuffer.ref.version
}
return groupMapping
}
}
return lines
}
function update(mappings: Float32Array, indices: Uint32Array, groups: Float32Array, starts: Float32Array, ends: Float32Array, lineCount: number, lines: Lines) {
lines.lineCount = lineCount
ValueCell.update(lines.mappingBuffer, mappings)
ValueCell.update(lines.indexBuffer, indices)
ValueCell.update(lines.groupBuffer, groups)
ValueCell.update(lines.startBuffer, starts)
ValueCell.update(lines.endBuffer, ends)
return lines
}
export function transform(lines: Lines, t: Mat4) {
const start = lines.startBuffer.ref.value
transformPositionArray(t, start, offset, count * 4)
transformPositionArray(t, start, 0, lines.lineCount * 4)
ValueCell.update(lines.startBuffer, start);
const end = lines.endBuffer.ref.value
transformPositionArray(t, end, offset, count * 4)
transformPositionArray(t, end, 0, lines.lineCount * 4)
ValueCell.update(lines.endBuffer, end);
}
@@ -124,8 +183,8 @@ export namespace Lines {
const counts = { drawCount: lines.lineCount * 2 * 3, groupCount, instanceCount }
const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(lines.startBuffer.ref.value, lines.endBuffer.ref.value, lines.lineCount,
transform.aTransform.ref.value, transform.instanceCount.ref.value)
const invariantBoundingSphere = Sphere3D.clone(lines.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount)
return {
aMapping: lines.mappingBuffer,
@@ -163,10 +222,9 @@ export namespace Lines {
}
function updateBoundingSphere(values: LinesValues, lines: Lines) {
const { boundingSphere, invariantBoundingSphere } = getBoundingSphere(
values.aStart.ref.value, values.aEnd.ref.value, lines.lineCount,
values.aTransform.ref.value, values.instanceCount.ref.value
)
const invariantBoundingSphere = Sphere3D.clone(lines.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)
}
@@ -174,13 +232,4 @@ export namespace Lines {
ValueCell.update(values.invariantBoundingSphere, invariantBoundingSphere)
}
}
}
function getBoundingSphere(lineStart: Float32Array, lineEnd: Float32Array, lineCount: number, transform: Float32Array, transformCount: number) {
const start = calculateBoundingSphere(lineStart, lineCount * 4, transform, transformCount, 0, 4)
const end = calculateBoundingSphere(lineEnd, lineCount * 4, transform, transformCount, 0, 4)
return {
boundingSphere: Sphere3D.expandBySphere(start.boundingSphere, end.boundingSphere),
invariantBoundingSphere: Sphere3D.expandBySphere(start.invariantBoundingSphere, end.invariantBoundingSphere)
}
}

View File

@@ -0,0 +1,34 @@
/**
* 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 { Axes3D } from '../../../../mol-math/geometry';
import { createCage } from '../../../primitive/cage';
const tmpVec = Vec3()
const tmpMatrix = Mat4.identity()
const tmpVertices = new Float32Array(6 * 3)
const tmpEdges = new Uint8Array([0, 1, 2, 3, 4, 5])
export function addAxes(state: MeshBuilder.State, axes: Axes3D, radiusScale: number, detail: number, radialSegments: number) {
const { origin, dirA, dirB, dirC } = axes
Vec3.add(tmpVec, origin, dirA)
Vec3.toArray(Vec3.add(tmpVec, origin, dirA), tmpVertices, 0)
Vec3.toArray(Vec3.sub(tmpVec, origin, dirA), tmpVertices, 3)
Vec3.toArray(Vec3.add(tmpVec, origin, dirB), tmpVertices, 6)
Vec3.toArray(Vec3.sub(tmpVec, origin, dirB), tmpVertices, 9)
Vec3.toArray(Vec3.add(tmpVec, origin, dirC), tmpVertices, 12)
Vec3.toArray(Vec3.sub(tmpVec, origin, dirC), tmpVertices, 15)
const cage = createCage(tmpVertices, tmpEdges)
const volume = Axes3D.volume(axes)
const radius = (Math.cbrt(volume) / 300) * radiusScale
MeshBuilder.addCage(state, tmpMatrix, cage, radius, detail, radialSegments)
}

View File

@@ -1,15 +1,16 @@
/**
* 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 { Vec3 } from '../../../../mol-math/linear-algebra';
import { Box3D } from '../../../../mol-math/geometry';
import { Vec3, Mat4 } from '../../../../mol-math/linear-algebra';
import { Box3D, Axes3D } from '../../../../mol-math/geometry';
import { MeshBuilder } from '../mesh-builder';
import { CylinderProps } from '../../../primitive/cylinder';
import { addCylinder } from './cylinder';
import { addSphere } from './sphere';
import { createCage } from '../../../primitive/cage';
const tmpStart = Vec3.zero()
const tmpEnd = Vec3.zero()
@@ -62,4 +63,49 @@ export function addBoundingBox(state: MeshBuilder.State, box: Box3D, radius: num
Vec3.set(tmpEnd, min[0], max[1], max[2])
addSphere(state, tmpEnd, radius, detail)
addCylinder(state, tmpStart, tmpEnd, 1, cylinderProps)
}
//
const tmpBoxVecCorner = Vec3()
const tmpBoxVecA = Vec3()
const tmpBoxVecB = Vec3()
const tmpBoxVecC = Vec3()
const tmpMatrix = Mat4.identity()
const tmpVertices = new Float32Array(8 * 3)
const tmpEdges = new Uint8Array([
0, 1, 0, 3, 0, 6, 1, 2, 1, 7, 2, 3,
2, 4, 3, 5, 4, 5, 4, 7, 5, 6, 6, 7
])
export function addOrientedBox(state: MeshBuilder.State, axes: Axes3D, radiusScale: number, detail: number, radialSegments: number) {
const { origin, dirA, dirB, dirC } = axes
const negDirA = Vec3.negate(tmpBoxVecA, dirA)
const negDirB = Vec3.negate(tmpBoxVecB, dirB)
const negDirC = Vec3.negate(tmpBoxVecC, dirC)
let offset = 0
const addCornerHelper = function (v1: Vec3, v2: Vec3, v3: Vec3) {
Vec3.copy(tmpBoxVecCorner, origin)
Vec3.add(tmpBoxVecCorner, tmpBoxVecCorner, v1)
Vec3.add(tmpBoxVecCorner, tmpBoxVecCorner, v2)
Vec3.add(tmpBoxVecCorner, tmpBoxVecCorner, v3)
Vec3.toArray(tmpBoxVecCorner, tmpVertices, offset)
offset += 3
}
addCornerHelper(dirA, dirB, dirC)
addCornerHelper(dirA, dirB, negDirC)
addCornerHelper(dirA, negDirB, negDirC)
addCornerHelper(dirA, negDirB, dirC)
addCornerHelper(negDirA, negDirB, negDirC)
addCornerHelper(negDirA, negDirB, dirC)
addCornerHelper(negDirA, dirB, dirC)
addCornerHelper(negDirA, dirB, negDirC)
const cage = createCage(tmpVertices, tmpEdges)
const volume = Axes3D.volume(axes)
const radius = (Math.cbrt(volume) / 300) * radiusScale
MeshBuilder.addCage(state, tmpMatrix, cage, radius, detail, radialSegments)
}

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,90 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
// TODO
// function addVertex(src: Float32Array, i: number, dst: Float32Array, j: number) {
// dst[3 * j] += src[3 * i];
// dst[3 * j + 1] += src[3 * i + 1];
// dst[3 * j + 2] += src[3 * i + 2];
// }
// function laplacianSmoothIter(surface: Surface, vertexCounts: Int32Array, vs: Float32Array, vertexWeight: number) {
// const triCount = surface.triangleIndices.length,
// src = surface.vertices;
// const triangleIndices = surface.triangleIndices;
// for (let i = 0; i < triCount; i += 3) {
// const a = triangleIndices[i],
// b = triangleIndices[i + 1],
// c = triangleIndices[i + 2];
// addVertex(src, b, vs, a);
// addVertex(src, c, vs, a);
// addVertex(src, a, vs, b);
// addVertex(src, c, vs, b);
// addVertex(src, a, vs, c);
// addVertex(src, b, vs, c);
// }
// const vw = 2 * vertexWeight;
// for (let i = 0, _b = surface.vertexCount; i < _b; i++) {
// const n = vertexCounts[i] + vw;
// vs[3 * i] = (vs[3 * i] + vw * src[3 * i]) / n;
// vs[3 * i + 1] = (vs[3 * i + 1] + vw * src[3 * i + 1]) / n;
// vs[3 * i + 2] = (vs[3 * i + 2] + vw * src[3 * i + 2]) / n;
// }
// }
// async function laplacianSmoothComputation(ctx: Computation.Context, surface: Surface, iterCount: number, vertexWeight: number) {
// await ctx.updateProgress('Smoothing surface...', true);
// const vertexCounts = new Int32Array(surface.vertexCount),
// triCount = surface.triangleIndices.length;
// const tris = surface.triangleIndices;
// for (let i = 0; i < triCount; i++) {
// // in a triangle 2 edges touch each vertex, hence the constant.
// vertexCounts[tris[i]] += 2;
// }
// let vs = new Float32Array(surface.vertices.length);
// let started = Utils.PerformanceMonitor.currentTime();
// await ctx.updateProgress('Smoothing surface...', true);
// for (let i = 0; i < iterCount; i++) {
// if (i > 0) {
// for (let j = 0, _b = vs.length; j < _b; j++) vs[j] = 0;
// }
// surface.normals = void 0;
// laplacianSmoothIter(surface, vertexCounts, vs, vertexWeight);
// const t = surface.vertices;
// surface.vertices = <any>vs;
// vs = <any>t;
// const time = Utils.PerformanceMonitor.currentTime();
// if (time - started > Computation.UpdateProgressDelta) {
// started = time;
// await ctx.updateProgress('Smoothing surface...', true, i + 1, iterCount);
// }
// }
// return surface;
// }
// /*
// * Smooths the vertices by averaging the neighborhood.
// *
// * Resets normals. Might replace vertex array.
// */
// export function laplacianSmooth(surface: Surface, iterCount: number = 1, vertexWeight: number = 1): Computation<Surface> {
// if (iterCount < 1) iterCount = 0;
// if (iterCount === 0) return Computation.resolve(surface);
// return computation(async ctx => await laplacianSmoothComputation(ctx, surface, iterCount, (1.1 * vertexWeight) / 1.1));
// }

View File

@@ -1,14 +1,12 @@
/**
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../../mol-util/value-cell'
import { Vec3, Mat4, Mat3 } from '../../../mol-math/linear-algebra';
import { ChunkedArray } from '../../../mol-data/util';
import { Mesh } from './mesh';
import { getNormalMatrix } from '../../util';
import { Primitive } from '../../primitive/primitive';
import { Cage } from '../../../mol-geo/primitive/cage';
import { addSphere } from './builder/sphere';
@@ -85,7 +83,7 @@ export namespace MeshBuilder {
const { vertices: va, normals: na, indices: ia } = primitive
const { vertices, normals, indices, groups, currentGroup } = state
const offset = vertices.elementCount
const n = getNormalMatrix(tmpMat3, t)
const n = Mat3.directionTransform(tmpMat3, t)
for (let i = 0, il = va.length; i < il; i += 3) {
// position
Vec3.transformMat4(tmpV, Vec3.fromArray(tmpV, va, i), t)
@@ -101,9 +99,30 @@ export namespace MeshBuilder {
}
}
export function addCage(state: State, t: Mat4, cage: Cage, radius: number, detail: number) {
/** Flips triangle normals and winding order */
export function addPrimitiveFlipped(state: State, t: Mat4, primitive: Primitive) {
const { vertices: va, normals: na, indices: ia } = primitive
const { vertices, normals, indices, groups, currentGroup } = state
const offset = vertices.elementCount
const n = Mat3.directionTransform(tmpMat3, t)
for (let i = 0, il = va.length; i < il; i += 3) {
// position
Vec3.transformMat4(tmpV, Vec3.fromArray(tmpV, va, i), t)
ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]);
// normal
Vec3.transformMat3(tmpV, Vec3.fromArray(tmpV, na, i), n)
ChunkedArray.add3(normals, -tmpV[0], -tmpV[1], -tmpV[2]);
// group
ChunkedArray.add(groups, currentGroup);
}
for (let i = 0, il = ia.length; i < il; i += 3) {
ChunkedArray.add3(indices, ia[i + 2] + offset, ia[i + 1] + offset, ia[i] + offset);
}
}
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)
@@ -121,15 +140,6 @@ export namespace MeshBuilder {
const ib = ChunkedArray.compact(indices, true) as Uint32Array
const nb = ChunkedArray.compact(normals, true) as Float32Array
const gb = ChunkedArray.compact(groups, true) as Float32Array
return {
kind: 'mesh',
vertexCount: state.vertices.elementCount,
triangleCount: state.indices.elementCount,
vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb),
indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib),
normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb),
groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, gb) : ValueCell.create(gb),
normalsComputed: true,
}
return Mesh.create(vb, ib, nb, gb, state.vertices.elementCount, state.indices.elementCount, mesh)
}
}

View File

@@ -1,22 +1,22 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Task } from '../../../mol-task'
import { ValueCell } from '../../../mol-util'
import { Vec3, Mat4 } from '../../../mol-math/linear-algebra'
import { Vec3, Mat4, Mat3 } from '../../../mol-math/linear-algebra'
import { Sphere3D } from '../../../mol-math/geometry'
import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
import { transformPositionArray, transformDirectionArray, computeIndexedVertexNormals, GroupMapping, createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
import { createMarkers } from '../marker-data';
import { TransformData } from '../transform-data';
import { LocationIterator } from '../../util/location-iterator';
import { createColors } from '../color-data';
import { ChunkedArray } from '../../../mol-data/util';
import { ChunkedArray, hashFnv32a } from '../../../mol-data/util';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { calculateBoundingSphere } from '../../../mol-gl/renderable/util';
import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { Theme } from '../../../mol-theme/theme';
import { MeshValues } from '../../../mol-gl/renderable/mesh';
import { Color } from '../../../mol-util/color';
@@ -41,85 +41,96 @@ export interface Mesh {
/** Group buffer as array of group ids for each vertex wrapped in a value cell */
readonly groupBuffer: ValueCell<Float32Array>,
/** Flag indicating if normals are computed for the current set of vertices */
normalsComputed: boolean,
/** Bounding sphere of the mesh */
boundingSphere?: Sphere3D
readonly boundingSphere: Sphere3D
/** Maps group ids to vertex indices */
readonly groupMapping: GroupMapping
}
export namespace Mesh {
export function create(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number, mesh?: Mesh): Mesh {
return mesh ?
update(vertices, indices, normals, groups, vertexCount, triangleCount, mesh) :
fromArrays(vertices, indices, normals, groups, vertexCount, triangleCount)
}
export function createEmpty(mesh?: Mesh): Mesh {
const vb = mesh ? mesh.vertexBuffer.ref.value : new Float32Array(0)
const ib = mesh ? mesh.indexBuffer.ref.value : new Uint32Array(0)
const nb = mesh ? mesh.normalBuffer.ref.value : new Float32Array(0)
const gb = mesh ? mesh.groupBuffer.ref.value : new Float32Array(0)
return {
kind: 'mesh',
vertexCount: 0,
triangleCount: 0,
vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb),
indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib),
normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb),
groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, gb) : ValueCell.create(gb),
normalsComputed: true,
}
return create(vb, ib, nb, gb, 0, 0, mesh)
}
export function fromArrays(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number, normalsComputed: boolean): Mesh {
return {
kind: 'mesh',
function hashCode(mesh: Mesh) {
return hashFnv32a([
mesh.vertexCount, mesh.triangleCount,
mesh.vertexBuffer.ref.version, mesh.indexBuffer.ref.version,
mesh.normalBuffer.ref.version, mesh.groupBuffer.ref.version
])
}
function fromArrays(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number): Mesh {
const boundingSphere = Sphere3D()
let groupMapping: GroupMapping
let currentHash = -1
let currentGroup = -1
const mesh = {
kind: 'mesh' as const,
vertexCount,
triangleCount,
vertexBuffer: ValueCell.create(vertices),
indexBuffer: ValueCell.create(indices),
normalBuffer: ValueCell.create(normals),
groupBuffer: ValueCell.create(groups),
normalsComputed,
}
}
export function computeNormalsImmediate(mesh: Mesh) {
if (mesh.normalsComputed) return;
const normals = mesh.normalBuffer.ref.value.length >= mesh.vertexCount * 3
? mesh.normalBuffer.ref.value : new Float32Array(mesh.vertexBuffer.ref.value.length);
const v = mesh.vertexBuffer.ref.value, triangles = mesh.indexBuffer.ref.value;
if (normals === mesh.normalBuffer.ref.value) {
for (let i = 0, ii = 3 * mesh.vertexCount; i < ii; i += 3) {
normals[i] = 0; normals[i + 1] = 0; normals[i + 2] = 0;
get boundingSphere() {
const newHash = hashCode(mesh)
if (newHash !== currentHash) {
const b = calculateInvariantBoundingSphere(mesh.vertexBuffer.ref.value, mesh.vertexCount, 1)
Sphere3D.copy(boundingSphere, b)
currentHash = newHash
}
return boundingSphere
},
get groupMapping() {
if (mesh.groupBuffer.ref.version !== currentGroup) {
groupMapping = createGroupMapping(mesh.groupBuffer.ref.value, mesh.vertexCount)
currentGroup = mesh.groupBuffer.ref.version
}
return groupMapping
}
}
return mesh
}
const x = Vec3.zero(), y = Vec3.zero(), z = Vec3.zero(), d1 = Vec3.zero(), d2 = Vec3.zero(), n = Vec3.zero();
for (let i = 0, ii = 3 * mesh.triangleCount; i < ii; i += 3) {
const a = 3 * triangles[i], b = 3 * triangles[i + 1], c = 3 * triangles[i + 2];
function update(vertices: Float32Array, indices: Uint32Array, normals: Float32Array, groups: Float32Array, vertexCount: number, triangleCount: number, mesh: Mesh) {
mesh.vertexCount = vertexCount
mesh.triangleCount = triangleCount
ValueCell.update(mesh.vertexBuffer, vertices)
ValueCell.update(mesh.indexBuffer, indices)
ValueCell.update(mesh.normalBuffer, normals)
ValueCell.update(mesh.groupBuffer, groups)
return mesh
}
Vec3.fromArray(x, v, a);
Vec3.fromArray(y, v, b);
Vec3.fromArray(z, v, c);
Vec3.sub(d1, z, y);
Vec3.sub(d2, x, y);
Vec3.cross(n, d1, d2);
export function computeNormals(mesh: Mesh) {
const { vertexCount, triangleCount } = mesh
const vertices = mesh.vertexBuffer.ref.value
const indices = mesh.indexBuffer.ref.value
normals[a] += n[0]; normals[a + 1] += n[1]; normals[a + 2] += n[2];
normals[b] += n[0]; normals[b + 1] += n[1]; normals[b + 2] += n[2];
normals[c] += n[0]; normals[c + 1] += n[1]; normals[c + 2] += n[2];
const normals = mesh.normalBuffer.ref.value.length >= vertexCount * 3
? mesh.normalBuffer.ref.value
: new Float32Array(vertexCount * 3);
if (normals === mesh.normalBuffer.ref.value) {
normals.fill(0, 0, vertexCount * 3)
}
for (let i = 0, ii = 3 * mesh.vertexCount; i < ii; i += 3) {
const nx = normals[i];
const ny = normals[i + 1];
const nz = normals[i + 2];
const f = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz);
normals[i] *= f; normals[i + 1] *= f; normals[i + 2] *= f;
// console.log([normals[i], normals[i + 1], normals[i + 2]], [v[i], v[i + 1], v[i + 2]])
}
computeIndexedVertexNormals(vertices, indices, normals, vertexCount, triangleCount)
ValueCell.update(mesh.normalBuffer, normals);
mesh.normalsComputed = true;
}
export function checkForDuplicateVertices(mesh: Mesh, fractionDigits = 3) {
@@ -129,7 +140,7 @@ export namespace Mesh {
const hash = (v: Vec3, d: number) => `${v[0].toFixed(d)}|${v[1].toFixed(d)}|${v[2].toFixed(d)}`
let duplicates = 0
const a = Vec3.zero()
const a = Vec3()
for (let i = 0, il = mesh.vertexCount; i < il; ++i) {
Vec3.fromArray(a, v, i * 3)
const k = hash(a, fractionDigits)
@@ -144,63 +155,15 @@ export namespace Mesh {
return duplicates
}
export function computeNormals(surface: Mesh): Task<Mesh> {
return Task.create<Mesh>('Surface (Compute Normals)', async ctx => {
if (surface.normalsComputed) return surface;
await ctx.update('Computing normals...');
computeNormalsImmediate(surface);
return surface;
});
}
export function transformImmediate(mesh: Mesh, t: Mat4) {
transformRangeImmediate(mesh, t, 0, mesh.vertexCount)
}
export function transformRangeImmediate(mesh: Mesh, t: Mat4, offset: number, count: number) {
const tmpMat3 = Mat3()
export function transform(mesh: Mesh, t: Mat4) {
const v = mesh.vertexBuffer.ref.value
transformPositionArray(t, v, offset, count)
// TODO normals transformation does not work for an unknown reason, ASR
// if (mesh.normalBuffer.ref.value) {
// const n = getNormalMatrix(Mat3.zero(), t)
// transformDirectionArray(n, mesh.normalBuffer.ref.value, offset, count)
// mesh.normalsComputed = true;
// }
transformPositionArray(t, v, 0, mesh.vertexCount)
if (!Mat4.isTranslationAndUniformScaling(t)) {
const n = Mat3.directionTransform(tmpMat3, t)
transformDirectionArray(n, mesh.normalBuffer.ref.value, 0, mesh.vertexCount)
}
ValueCell.update(mesh.vertexBuffer, v);
mesh.normalsComputed = false;
}
export function computeBoundingSphere(mesh: Mesh): Task<Mesh> {
return Task.create<Mesh>('Mesh (Compute Bounding Sphere)', async ctx => {
if (mesh.boundingSphere) {
return mesh;
}
await ctx.update('Computing bounding sphere...');
const vertices = mesh.vertexBuffer.ref.value;
let x = 0, y = 0, z = 0;
for (let i = 0, _c = vertices.length; i < _c; i += 3) {
x += vertices[i];
y += vertices[i + 1];
z += vertices[i + 2];
}
x /= mesh.vertexCount;
y /= mesh.vertexCount;
z /= mesh.vertexCount;
let r = 0;
for (let i = 0, _c = vertices.length; i < _c; i += 3) {
const dx = x - vertices[i];
const dy = y - vertices[i + 1];
const dz = z - vertices[i + 2];
r = Math.max(r, dx * dx + dy * dy + dz * dz);
}
mesh.boundingSphere = {
center: Vec3.create(x, y, z),
radius: Math.sqrt(r)
}
return mesh;
});
}
/**
@@ -228,12 +191,12 @@ export namespace Mesh {
group.currentIndex = vertexCount
group.elementCount = vertexCount
const vi = Vec3.zero()
const vj = Vec3.zero()
const vk = Vec3.zero()
const ni = Vec3.zero()
const nj = Vec3.zero()
const nk = Vec3.zero()
const vi = Vec3()
const vj = Vec3()
const vk = Vec3()
const ni = Vec3()
const nj = Vec3()
const nk = Vec3()
function add(i: number) {
Vec3.fromArray(vi, vb, i * 3)
@@ -361,6 +324,7 @@ export namespace Mesh {
doubleSided: PD.Boolean(false),
flipSided: PD.Boolean(false),
flatShaded: PD.Boolean(false),
ignoreLight: PD.Boolean(false),
}
export type Params = typeof Params
@@ -388,10 +352,8 @@ export namespace Mesh {
const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount }
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
mesh.vertexBuffer.ref.value, mesh.vertexCount,
transform.aTransform.ref.value, instanceCount
)
const invariantBoundingSphere = Sphere3D.clone(mesh.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount)
return {
aPosition: mesh.vertexBuffer,
@@ -410,6 +372,7 @@ export namespace Mesh {
dDoubleSided: ValueCell.create(props.doubleSided),
dFlatShaded: ValueCell.create(props.flatShaded),
dFlipSided: ValueCell.create(props.flipSided),
dIgnoreLight: ValueCell.create(props.ignoreLight),
}
}
@@ -424,13 +387,13 @@ export namespace Mesh {
ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided)
ValueCell.updateIfChanged(values.dFlatShaded, props.flatShaded)
ValueCell.updateIfChanged(values.dFlipSided, props.flipSided)
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight)
}
function updateBoundingSphere(values: MeshValues, mesh: Mesh) {
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
values.aPosition.ref.value, mesh.vertexCount,
values.aTransform.ref.value, values.instanceCount.ref.value
)
const invariantBoundingSphere = Sphere3D.clone(mesh.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)
}
@@ -439,86 +402,3 @@ export namespace Mesh {
}
}
}
// function addVertex(src: Float32Array, i: number, dst: Float32Array, j: number) {
// dst[3 * j] += src[3 * i];
// dst[3 * j + 1] += src[3 * i + 1];
// dst[3 * j + 2] += src[3 * i + 2];
// }
// function laplacianSmoothIter(surface: Surface, vertexCounts: Int32Array, vs: Float32Array, vertexWeight: number) {
// const triCount = surface.triangleIndices.length,
// src = surface.vertices;
// const triangleIndices = surface.triangleIndices;
// for (let i = 0; i < triCount; i += 3) {
// const a = triangleIndices[i],
// b = triangleIndices[i + 1],
// c = triangleIndices[i + 2];
// addVertex(src, b, vs, a);
// addVertex(src, c, vs, a);
// addVertex(src, a, vs, b);
// addVertex(src, c, vs, b);
// addVertex(src, a, vs, c);
// addVertex(src, b, vs, c);
// }
// const vw = 2 * vertexWeight;
// for (let i = 0, _b = surface.vertexCount; i < _b; i++) {
// const n = vertexCounts[i] + vw;
// vs[3 * i] = (vs[3 * i] + vw * src[3 * i]) / n;
// vs[3 * i + 1] = (vs[3 * i + 1] + vw * src[3 * i + 1]) / n;
// vs[3 * i + 2] = (vs[3 * i + 2] + vw * src[3 * i + 2]) / n;
// }
// }
// async function laplacianSmoothComputation(ctx: Computation.Context, surface: Surface, iterCount: number, vertexWeight: number) {
// await ctx.updateProgress('Smoothing surface...', true);
// const vertexCounts = new Int32Array(surface.vertexCount),
// triCount = surface.triangleIndices.length;
// const tris = surface.triangleIndices;
// for (let i = 0; i < triCount; i++) {
// // in a triangle 2 edges touch each vertex, hence the constant.
// vertexCounts[tris[i]] += 2;
// }
// let vs = new Float32Array(surface.vertices.length);
// let started = Utils.PerformanceMonitor.currentTime();
// await ctx.updateProgress('Smoothing surface...', true);
// for (let i = 0; i < iterCount; i++) {
// if (i > 0) {
// for (let j = 0, _b = vs.length; j < _b; j++) vs[j] = 0;
// }
// surface.normals = void 0;
// laplacianSmoothIter(surface, vertexCounts, vs, vertexWeight);
// const t = surface.vertices;
// surface.vertices = <any>vs;
// vs = <any>t;
// const time = Utils.PerformanceMonitor.currentTime();
// if (time - started > Computation.UpdateProgressDelta) {
// started = time;
// await ctx.updateProgress('Smoothing surface...', true, i + 1, iterCount);
// }
// }
// return surface;
// }
// /*
// * Smooths the vertices by averaging the neighborhood.
// *
// * Resets normals. Might replace vertex array.
// */
// export function laplacianSmooth(surface: Surface, iterCount: number = 1, vertexWeight: number = 1): Computation<Surface> {
// if (iterCount < 1) iterCount = 0;
// if (iterCount === 0) return Computation.resolve(surface);
// return computation(async ctx => await laplacianSmoothComputation(ctx, surface, iterCount, (1.1 * vertexWeight) / 1.1));
// }

View File

@@ -1,10 +1,9 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../../mol-util/value-cell'
import { ChunkedArray } from '../../../mol-data/util';
import { Points } from './points';
@@ -26,12 +25,7 @@ export namespace PointsBuilder {
getPoints: () => {
const cb = ChunkedArray.compact(centers, true) as Float32Array
const gb = ChunkedArray.compact(groups, true) as Float32Array
return {
kind: 'points',
pointCount: centers.elementCount,
centerBuffer: points ? ValueCell.update(points.centerBuffer, cb) : ValueCell.create(cb),
groupBuffer: points ? ValueCell.update(points.groupBuffer, gb) : ValueCell.create(gb),
}
return Points.create(cb, gb, centers.elementCount, points)
}
}
}

View File

@@ -1,12 +1,14 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../../mol-util'
import { Mat4 } from '../../../mol-math/linear-algebra'
import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
import { transformPositionArray,/* , transformDirectionArray, getNormalMatrix */
GroupMapping,
createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
import { createColors } from '../color-data';
import { createMarkers } from '../marker-data';
@@ -14,7 +16,7 @@ import { createSizes } from '../size-data';
import { TransformData } from '../transform-data';
import { LocationIterator } from '../../util/location-iterator';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { calculateBoundingSphere } from '../../../mol-gl/renderable/util';
import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { Sphere3D } from '../../../mol-math/geometry';
import { Theme } from '../../../mol-theme/theme';
import { PointsValues } from '../../../mol-gl/renderable/points';
@@ -23,37 +25,88 @@ import { Color } from '../../../mol-util/color';
import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
/** Point cloud */
export interface Points {
readonly kind: 'points',
/** Number of vertices in the point cloud */
pointCount: number,
/** Center buffer as array of xyz values wrapped in a value cell */
readonly centerBuffer: ValueCell<Float32Array>,
/** Group buffer as array of group ids for each vertex wrapped in a value cell */
readonly groupBuffer: ValueCell<Float32Array>,
/** Bounding sphere of the points */
readonly boundingSphere: Sphere3D
/** Maps group ids to point indices */
readonly groupMapping: GroupMapping
}
export namespace Points {
export function create(centers: Float32Array, groups: Float32Array, pointCount: number, points?: Points): Points {
return points ?
update(centers, groups, pointCount, points) :
fromArrays(centers, groups, pointCount)
}
export function createEmpty(points?: Points): Points {
const cb = points ? points.centerBuffer.ref.value : new Float32Array(0)
const gb = points ? points.groupBuffer.ref.value : new Float32Array(0)
return {
kind: 'points',
pointCount: 0,
centerBuffer: points ? ValueCell.update(points.centerBuffer, cb) : ValueCell.create(cb),
groupBuffer: points ? ValueCell.update(points.groupBuffer, gb) : ValueCell.create(gb),
return create(cb, gb, 0, points)
}
function hashCode(points: Points) {
return hashFnv32a([
points.pointCount, points.centerBuffer.ref.version, points.groupBuffer.ref.version,
])
}
function fromArrays(centers: Float32Array, groups: Float32Array, pointCount: number): Points {
const boundingSphere = Sphere3D()
let groupMapping: GroupMapping
let currentHash = -1
let currentGroup = -1
const points = {
kind: 'points' as const,
pointCount,
centerBuffer: ValueCell.create(centers),
groupBuffer: ValueCell.create(groups),
get boundingSphere() {
const newHash = hashCode(points)
if (newHash !== currentHash) {
const b = calculateInvariantBoundingSphere(points.centerBuffer.ref.value, points.pointCount, 1)
Sphere3D.copy(boundingSphere, b)
currentHash = newHash
}
return boundingSphere
},
get groupMapping() {
if (points.groupBuffer.ref.version !== currentGroup) {
groupMapping = createGroupMapping(points.groupBuffer.ref.value, points.pointCount)
currentGroup = points.groupBuffer.ref.version
}
return groupMapping
}
}
return points
}
export function transformImmediate(points: Points, t: Mat4) {
transformRangeImmediate(points, t, 0, points.pointCount)
function update(centers: Float32Array, groups: Float32Array, pointCount: number, points: Points) {
points.pointCount = pointCount
ValueCell.update(points.centerBuffer, centers)
ValueCell.update(points.groupBuffer, groups)
return points
}
export function transformRangeImmediate(points: Points, t: Mat4, offset: number, count: number) {
export function transform(points: Points, t: Mat4) {
const c = points.centerBuffer.ref.value
transformPositionArray(t, c, offset, count)
transformPositionArray(t, c, 0, points.pointCount)
ValueCell.update(points.centerBuffer, c);
}
@@ -89,10 +142,8 @@ export namespace Points {
const counts = { drawCount: points.pointCount, groupCount, instanceCount }
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
points.centerBuffer.ref.value, points.pointCount,
transform.aTransform.ref.value, transform.instanceCount.ref.value
)
const invariantBoundingSphere = Sphere3D.clone(points.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount)
return {
aPosition: points.centerBuffer,
@@ -129,10 +180,9 @@ export namespace Points {
}
function updateBoundingSphere(values: PointsValues, points: Points) {
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
values.aPosition.ref.value, points.pointCount,
values.aTransform.ref.value, values.instanceCount.ref.value
)
const invariantBoundingSphere = Sphere3D.clone(points.boundingSphere)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)
}

View File

@@ -1,10 +1,9 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from '../../../mol-util/value-cell'
import { ChunkedArray } from '../../../mol-data/util';
import { Spheres } from './spheres';
@@ -50,14 +49,7 @@ export namespace SpheresBuilder {
const mb = ChunkedArray.compact(mappings, true) as Float32Array
const ib = ChunkedArray.compact(indices, true) as Uint32Array
const gb = ChunkedArray.compact(groups, true) as Float32Array
return {
kind: 'spheres',
sphereCount: centers.elementCount / 4,
centerBuffer: spheres ? ValueCell.update(spheres.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: spheres ? ValueCell.update(spheres.mappingBuffer, mb) : ValueCell.create(mb),
indexBuffer: spheres ? ValueCell.update(spheres.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: spheres ? ValueCell.update(spheres.groupBuffer, gb) : ValueCell.create(gb),
}
return Spheres.create(cb, mb, ib, gb, centers.elementCount / 4, spheres)
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -13,15 +13,16 @@ import { Theme } from '../../../mol-theme/theme';
import { SpheresValues } from '../../../mol-gl/renderable/spheres';
import { createColors } from '../color-data';
import { createMarkers } from '../marker-data';
import { calculateBoundingSphere } from '../../../mol-gl/renderable/util';
import { calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { Sphere3D } from '../../../mol-math/geometry';
import { createSizes, getMaxSize } from '../size-data';
import { Color } from '../../../mol-util/color';
import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
import { GroupMapping, createGroupMapping } from '../../util';
/** Spheres */
export interface Spheres {
readonly kind: 'spheres',
@@ -36,28 +37,85 @@ export interface Spheres {
readonly indexBuffer: ValueCell<Uint32Array>,
/** Group buffer as array of group ids for each vertex wrapped in a value cell */
readonly groupBuffer: ValueCell<Float32Array>,
/** Bounding sphere of the spheres */
readonly boundingSphere: Sphere3D
/** Maps group ids to sphere indices */
readonly groupMapping: GroupMapping
}
export namespace Spheres {
export function create(centers: Float32Array, mappings: Float32Array, indices: Uint32Array, groups: Float32Array, sphereCount: number, spheres?: Spheres): Spheres {
return spheres ?
update(centers, mappings, indices, groups, sphereCount, spheres) :
fromArrays(centers, mappings, indices, groups, sphereCount)
}
export function createEmpty(spheres?: Spheres): Spheres {
const cb = spheres ? spheres.centerBuffer.ref.value : new Float32Array(0)
const mb = spheres ? spheres.mappingBuffer.ref.value : new Float32Array(0)
const ib = spheres ? spheres.indexBuffer.ref.value : new Uint32Array(0)
const gb = spheres ? spheres.groupBuffer.ref.value : new Float32Array(0)
return {
kind: 'spheres',
sphereCount: 0,
centerBuffer: spheres ? ValueCell.update(spheres.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: spheres ? ValueCell.update(spheres.mappingBuffer, mb) : ValueCell.create(mb),
indexBuffer: spheres ? ValueCell.update(spheres.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: spheres ? ValueCell.update(spheres.groupBuffer, gb) : ValueCell.create(gb)
return create(cb, mb, ib, gb, 0, spheres)
}
function hashCode(spheres: Spheres) {
return hashFnv32a([
spheres.sphereCount,
spheres.centerBuffer.ref.version, spheres.mappingBuffer.ref.version,
spheres.indexBuffer.ref.version, spheres.groupBuffer.ref.version
])
}
function fromArrays(centers: Float32Array, mappings: Float32Array, indices: Uint32Array, groups: Float32Array, sphereCount: number): Spheres {
const boundingSphere = Sphere3D()
let groupMapping: GroupMapping
let currentHash = -1
let currentGroup = -1
const spheres = {
kind: 'spheres' as const,
sphereCount,
centerBuffer: ValueCell.create(centers),
mappingBuffer: ValueCell.create(mappings),
indexBuffer: ValueCell.create(indices),
groupBuffer: ValueCell.create(groups),
get boundingSphere() {
const newHash = hashCode(spheres)
if (newHash !== currentHash) {
const b = calculateInvariantBoundingSphere(spheres.centerBuffer.ref.value, spheres.sphereCount * 4, 4)
Sphere3D.copy(boundingSphere, b)
currentHash = newHash
}
return boundingSphere
},
get groupMapping() {
if (spheres.groupBuffer.ref.version !== currentGroup) {
groupMapping = createGroupMapping(spheres.groupBuffer.ref.value, spheres.sphereCount, 4)
currentGroup = spheres.groupBuffer.ref.version
}
return groupMapping
}
}
return spheres
}
function update(centers: Float32Array, mappings: Float32Array, indices: Uint32Array, groups: Float32Array, sphereCount: number, spheres: Spheres) {
spheres.sphereCount = sphereCount
ValueCell.update(spheres.centerBuffer, centers)
ValueCell.update(spheres.mappingBuffer, mappings)
ValueCell.update(spheres.indexBuffer, indices)
ValueCell.update(spheres.groupBuffer, groups)
return spheres
}
export const Params = {
...BaseGeometry.Params,
sizeFactor: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }),
doubleSided: PD.Boolean(false),
ignoreLight: PD.Boolean(false),
}
export type Params = typeof Params
@@ -87,10 +145,8 @@ export namespace Spheres {
const counts = { drawCount: spheres.sphereCount * 2 * 3, groupCount, instanceCount }
const padding = getMaxSize(size)
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
spheres.centerBuffer.ref.value, spheres.sphereCount * 4,
transform.aTransform.ref.value, instanceCount, padding, 4
)
const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), spheres.boundingSphere, padding)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount)
return {
aPosition: spheres.centerBuffer,
@@ -111,6 +167,7 @@ export namespace Spheres {
...BaseGeometry.createValues(props, counts),
uSizeFactor: ValueCell.create(props.sizeFactor),
dDoubleSided: ValueCell.create(props.doubleSided),
dIgnoreLight: ValueCell.create(props.ignoreLight),
}
}
@@ -124,14 +181,14 @@ export namespace Spheres {
BaseGeometry.updateValues(values, props)
ValueCell.updateIfChanged(values.uSizeFactor, props.sizeFactor)
ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided)
ValueCell.updateIfChanged(values.dIgnoreLight, props.ignoreLight)
}
function updateBoundingSphere(values: SpheresValues, spheres: Spheres) {
const padding = getMaxSize(values)
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
values.aPosition.ref.value, spheres.sphereCount * 4,
values.aTransform.ref.value, values.instanceCount.ref.value, padding, 4
)
const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), spheres.boundingSphere, padding)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)
}

View File

@@ -24,11 +24,11 @@ export type FontVariant = 'normal' | 'small-caps'
export type FontWeight = 'normal' | 'bold'
export const FontAtlasParams = {
fontFamily: PD.Select('sans-serif', [['sans-serif', 'Sans Serif'], ['monospace', 'Monospace'], ['serif', 'Serif'], ['cursive', 'Cursive']] as [FontFamily, string][]),
fontQuality: PD.Select(3, [[0, 'lower'], [1, 'low'], [2, 'medium'], [3, 'high'], [4, 'higher']]),
fontStyle: PD.Select('normal', [['normal', 'Normal'], ['italic', 'Italic'], ['oblique', 'Oblique']] as [FontStyle, string][]),
fontVariant: PD.Select('normal', [['normal', 'Normal'], ['small-caps', 'Small Caps']] as [FontVariant, string][]),
fontWeight: PD.Select('normal', [['normal', 'Normal'], ['bold', 'Bold']] as [FontWeight, string][]),
fontFamily: PD.Select('sans-serif', [['sans-serif', 'Sans Serif'], ['monospace', 'Monospace'], ['serif', 'Serif'], ['cursive', 'Cursive']] as [FontFamily, string][]),
fontQuality: PD.Select(3, [[0, 'lower'], [1, 'low'], [2, 'medium'], [3, 'high'], [4, 'higher']]),
fontStyle: PD.Select('normal', [['normal', 'Normal'], ['italic', 'Italic'], ['oblique', 'Oblique']] as [FontStyle, string][]),
fontVariant: PD.Select('normal', [['normal', 'Normal'], ['small-caps', 'Small Caps']] as [FontVariant, string][]),
fontWeight: PD.Select('normal', [['normal', 'Normal'], ['bold', 'Bold']] as [FontWeight, string][]),
}
export type FontAtlasParams = typeof FontAtlasParams
export type FontAtlasProps = PD.Values<FontAtlasParams>

View File

@@ -1,11 +1,10 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { ValueCell } from '../../../mol-util/value-cell'
import { ChunkedArray } from '../../../mol-data/util';
import { Text } from './text';
import { getFontAtlas } from './font-atlas';
@@ -16,7 +15,7 @@ const quadIndices = new Uint16Array([
])
export interface TextBuilder {
add(str: string, x: number, y: number, z: number, depth: number, group: number): void
add(str: string, x: number, y: number, z: number, depth: number, scale: number, group: number): void
getText(): Text
}
@@ -45,7 +44,7 @@ export namespace TextBuilder {
}
return {
add: (str: string, x: number, y: number, z: number, depth: number, group: number) => {
add: (str: string, x: number, y: number, z: number, depth: number, scale: number, group: number) => {
let bWidth = 0
const nChar = str.length
@@ -111,10 +110,10 @@ export namespace TextBuilder {
}
}
const xLeft = -xShift - margin - 0.1
const xRight = bWidth - xShift + margin + 0.1
const yTop = bHeight - yShift + margin
const yBottom = -yShift - margin
const xLeft = (-xShift - margin - 0.1) * scale
const xRight = (bWidth - xShift + margin + 0.1) * scale
const yTop = (bHeight - yShift + margin) * scale
const yBottom = (-yShift - margin) * scale
// background
if (background) {
@@ -137,45 +136,49 @@ export namespace TextBuilder {
let xBaseA: number, yBaseA: number
let xBaseB: number, yBaseB: number
let xBaseCenter: number, yBaseCenter: number
const scaledTetherLength = tetherLength * scale
const scaledTetherBaseWidth = tetherBaseWidth * scale
switch (attachment) {
case 'bottom-left':
xTip = xLeft - tetherLength / 2
xBaseA = xLeft + tetherBaseWidth / 2
xTip = xLeft - scaledTetherLength / 2
xBaseA = xLeft + scaledTetherBaseWidth / 2
xBaseB = xLeft
xBaseCenter = xLeft
yTip = yBottom - tetherLength / 2
yTip = yBottom - scaledTetherLength / 2
yBaseA = yBottom
yBaseB = yBottom + tetherBaseWidth / 2
yBaseB = yBottom + scaledTetherBaseWidth / 2
yBaseCenter = yBottom
break
case 'bottom-center':
xTip = 0
xBaseA = tetherBaseWidth / 2
xBaseB = -tetherBaseWidth / 2
xBaseA = scaledTetherBaseWidth / 2
xBaseB = -scaledTetherBaseWidth / 2
xBaseCenter = 0
yTip = yBottom - tetherLength
yTip = yBottom - scaledTetherLength
yBaseA = yBottom
yBaseB = yBottom
yBaseCenter = yBottom
break
case 'bottom-right':
xTip = xRight + tetherLength / 2
xTip = xRight + scaledTetherLength / 2
xBaseA = xRight
xBaseB = xRight - tetherBaseWidth / 2
xBaseB = xRight - scaledTetherBaseWidth / 2
xBaseCenter = xRight
yTip = yBottom - tetherLength / 2
yBaseA = yBottom + tetherBaseWidth / 2
yTip = yBottom - scaledTetherLength / 2
yBaseA = yBottom + scaledTetherBaseWidth / 2
yBaseB = yBottom
yBaseCenter = yBottom
break
case 'middle-left':
xTip = xLeft - tetherLength
xTip = xLeft - scaledTetherLength
xBaseA = xLeft
xBaseB = xLeft
xBaseCenter = xLeft
yTip = 0
yBaseA = -tetherBaseWidth / 2
yBaseB = tetherBaseWidth / 2
yBaseA = -scaledTetherBaseWidth / 2
yBaseB = scaledTetherBaseWidth / 2
yBaseCenter = 0
break
case 'middle-center':
@@ -189,42 +192,42 @@ export namespace TextBuilder {
yBaseCenter = 0
break
case 'middle-right':
xTip = xRight + tetherLength
xTip = xRight + scaledTetherLength
xBaseA = xRight
xBaseB = xRight
xBaseCenter = xRight
yTip = 0
yBaseA = tetherBaseWidth / 2
yBaseB = -tetherBaseWidth / 2
yBaseA = scaledTetherBaseWidth / 2
yBaseB = -scaledTetherBaseWidth / 2
yBaseCenter = 0
break
case 'top-left':
xTip = xLeft - tetherLength / 2
xBaseA = xLeft + tetherBaseWidth / 2
xTip = xLeft - scaledTetherLength / 2
xBaseA = xLeft + scaledTetherBaseWidth / 2
xBaseB = xLeft
xBaseCenter = xLeft
yTip = yTop + tetherLength / 2
yTip = yTop + scaledTetherLength / 2
yBaseA = yTop
yBaseB = yTop - tetherBaseWidth / 2
yBaseB = yTop - scaledTetherBaseWidth / 2
yBaseCenter = yTop
break
case 'top-center':
xTip = 0
xBaseA = tetherBaseWidth / 2
xBaseB = -tetherBaseWidth / 2
xBaseA = scaledTetherBaseWidth / 2
xBaseB = -scaledTetherBaseWidth / 2
xBaseCenter = 0
yTip = yTop + tetherLength
yTip = yTop + scaledTetherLength
yBaseA = yTop
yBaseB = yTop
yBaseCenter = yTop
break
case 'top-right':
xTip = xRight + tetherLength / 2
xTip = xRight + scaledTetherLength / 2
xBaseA = xRight
xBaseB = xRight - tetherBaseWidth / 2
xBaseB = xRight - scaledTetherBaseWidth / 2
xBaseCenter = xRight
yTip = yTop + tetherLength / 2
yBaseA = yTop - tetherBaseWidth / 2
yTip = yTop + scaledTetherLength / 2
yBaseA = yTop - scaledTetherBaseWidth / 2
yBaseB = yTop
yBaseCenter = yTop
break
@@ -252,10 +255,15 @@ export namespace TextBuilder {
for (let iChar = 0; iChar < nChar; ++iChar) {
const c = fontAtlas.get(str[iChar])
ChunkedArray.add2(mappings, xadvance - xShift, c.nh - yShift) // top left
ChunkedArray.add2(mappings, xadvance - xShift, -yShift) // bottom left
ChunkedArray.add2(mappings, xadvance + c.nw - xShift, c.nh - yShift) // top right
ChunkedArray.add2(mappings, xadvance + c.nw - xShift, -yShift) // bottom right
const left = (xadvance - xShift) * scale
const right = (xadvance + c.nw - xShift) * scale
const top = (c.nh - yShift) * scale
const bottom = (-yShift) * scale
ChunkedArray.add2(mappings, left, top)
ChunkedArray.add2(mappings, left, bottom)
ChunkedArray.add2(mappings, right, top)
ChunkedArray.add2(mappings, right, bottom)
const texWidth = fontAtlas.texture.width
const texHeight = fontAtlas.texture.height
@@ -281,17 +289,7 @@ export namespace TextBuilder {
const ib = ChunkedArray.compact(indices, true) as Uint32Array
const gb = ChunkedArray.compact(groups, true) as Float32Array
const tb = ChunkedArray.compact(tcoords, true) as Float32Array
return {
kind: 'text',
charCount: indices.elementCount / 2,
fontTexture: text ? ValueCell.update(text.fontTexture, ft) : ValueCell.create(ft),
centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb),
depthBuffer: text ? ValueCell.update(text.depthBuffer, db) : ValueCell.create(db),
indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: text ? ValueCell.update(text.groupBuffer, gb) : ValueCell.create(gb),
tcoordBuffer: text ? ValueCell.update(text.tcoordBuffer, tb) : ValueCell.create(tb),
}
return Text.create(ft, cb,mb, db, ib, gb, tb, indices.elementCount / 2, text)
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -15,7 +15,7 @@ import { createSizes, getMaxSize } from '../size-data';
import { createMarkers } from '../marker-data';
import { ColorNames } from '../../../mol-util/color/names';
import { Sphere3D } from '../../../mol-math/geometry';
import { calculateBoundingSphere, TextureImage, createTextureImage } from '../../../mol-gl/renderable/util';
import { TextureImage, createTextureImage, calculateInvariantBoundingSphere, calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
import { TextValues } from '../../../mol-gl/renderable/text';
import { Color } from '../../../mol-util/color';
import { Vec3 } from '../../../mol-math/linear-algebra';
@@ -26,6 +26,8 @@ import { createRenderObject as _createRenderObject } from '../../../mol-gl/rende
import { BaseGeometry } from '../base';
import { createEmptyOverpaint } from '../overpaint-data';
import { createEmptyTransparency } from '../transparency-data';
import { hashFnv32a } from '../../../mol-data/util';
import { GroupMapping, createGroupMapping } from '../../util';
type TextAttachment = (
'bottom-left' | 'bottom-center' | 'bottom-right' |
@@ -38,7 +40,8 @@ export interface Text {
readonly kind: 'text',
/** Number of characters in the text */
readonly charCount: number,
charCount: number,
/** Font Atlas */
readonly fontTexture: ValueCell<TextureImage<Uint8Array>>,
@@ -54,9 +57,20 @@ export interface Text {
readonly groupBuffer: ValueCell<Float32Array>,
/** Texture coordinates buffer as array of uv values wrapped in a value cell */
readonly tcoordBuffer: ValueCell<Float32Array>,
/** Bounding sphere of the text */
readonly boundingSphere: Sphere3D
/** Maps group ids to text indices */
readonly groupMapping: GroupMapping
}
export namespace Text {
export function create(fontTexture: TextureImage<Uint8Array>, centers: Float32Array, mappings: Float32Array, depths: Float32Array, indices: Uint32Array, groups: Float32Array, tcoords: Float32Array, charCount: number, text?: Text): Text {
return text ?
update(fontTexture, centers, mappings, depths, indices, groups, tcoords, charCount, text) :
fromData(fontTexture, centers, mappings, depths, indices, groups, tcoords, charCount)
}
export function createEmpty(text?: Text): Text {
const ft = text ? text.fontTexture.ref.value : createTextureImage(0, 1, Uint8Array)
const cb = text ? text.centerBuffer.ref.value : new Float32Array(0)
@@ -65,17 +79,66 @@ export namespace Text {
const ib = text ? text.indexBuffer.ref.value : new Uint32Array(0)
const gb = text ? text.groupBuffer.ref.value : new Float32Array(0)
const tb = text ? text.tcoordBuffer.ref.value : new Float32Array(0)
return {
kind: 'text',
charCount: 0,
fontTexture: text ? ValueCell.update(text.fontTexture, ft) : ValueCell.create(ft),
centerBuffer: text ? ValueCell.update(text.centerBuffer, cb) : ValueCell.create(cb),
mappingBuffer: text ? ValueCell.update(text.mappingBuffer, mb) : ValueCell.create(mb),
depthBuffer: text ? ValueCell.update(text.depthBuffer, db) : ValueCell.create(db),
indexBuffer: text ? ValueCell.update(text.indexBuffer, ib) : ValueCell.create(ib),
groupBuffer: text ? ValueCell.update(text.groupBuffer, gb) : ValueCell.create(gb),
tcoordBuffer: text ? ValueCell.update(text.tcoordBuffer, tb) : ValueCell.create(tb)
return create(ft, cb, mb, db, ib, gb, tb, 0, text)
}
function hashCode(text: Text) {
return hashFnv32a([
text.charCount, text.fontTexture.ref.version,
text.centerBuffer.ref.version, text.mappingBuffer.ref.version,
text.depthBuffer.ref.version, text.indexBuffer.ref.version,
text.groupBuffer.ref.version, text.tcoordBuffer.ref.version
])
}
function fromData(fontTexture: TextureImage<Uint8Array>, centers: Float32Array, mappings: Float32Array, depths: Float32Array, indices: Uint32Array, groups: Float32Array, tcoords: Float32Array, charCount: number): Text {
const boundingSphere = Sphere3D()
let groupMapping: GroupMapping
let currentHash = -1
let currentGroup = -1
const text = {
kind: 'text' as const,
charCount,
fontTexture: ValueCell.create(fontTexture),
centerBuffer: ValueCell.create(centers),
mappingBuffer: ValueCell.create(mappings),
depthBuffer: ValueCell.create(depths),
indexBuffer: ValueCell.create(indices),
groupBuffer: ValueCell.create(groups),
tcoordBuffer: ValueCell.create(tcoords),
get boundingSphere() {
const newHash = hashCode(text)
if (newHash !== currentHash) {
const b = calculateInvariantBoundingSphere(text.centerBuffer.ref.value, text.charCount * 4, 4)
Sphere3D.copy(boundingSphere, b)
currentHash = newHash
}
return boundingSphere
},
get groupMapping() {
if (text.groupBuffer.ref.version !== currentGroup) {
groupMapping = createGroupMapping(text.groupBuffer.ref.value, text.charCount, 4)
currentGroup = text.groupBuffer.ref.version
}
return groupMapping
}
}
return text
}
function update(fontTexture: TextureImage<Uint8Array>, centers: Float32Array, mappings: Float32Array, depths: Float32Array, indices: Uint32Array, groups: Float32Array, tcoords: Float32Array, charCount: number, text: Text) {
text.charCount = charCount
ValueCell.update(text.fontTexture, fontTexture)
ValueCell.update(text.centerBuffer, centers)
ValueCell.update(text.mappingBuffer, mappings)
ValueCell.update(text.depthBuffer, depths)
ValueCell.update(text.indexBuffer, indices)
ValueCell.update(text.groupBuffer, groups)
ValueCell.update(text.tcoordBuffer, tcoords)
return text
}
export const Params = {
@@ -130,10 +193,8 @@ export namespace Text {
const counts = { drawCount: text.charCount * 2 * 3, groupCount, instanceCount }
const padding = getPadding(text.mappingBuffer.ref.value, text.depthBuffer.ref.value, text.charCount, getMaxSize(size))
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
text.centerBuffer.ref.value, text.charCount * 4,
transform.aTransform.ref.value, instanceCount, padding
)
const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), text.boundingSphere, padding)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform.aTransform.ref.value, instanceCount)
return {
aPosition: text.centerBuffer,
@@ -194,10 +255,9 @@ export namespace Text {
function updateBoundingSphere(values: TextValues, text: Text) {
const padding = getPadding(values.aMapping.ref.value, values.aDepth.ref.value, text.charCount, getMaxSize(values))
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
values.aPosition.ref.value, text.charCount * 4,
values.aTransform.ref.value, values.instanceCount.ref.value, padding
)
const invariantBoundingSphere = Sphere3D.expand(Sphere3D(), text.boundingSphere, padding)
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)
}
@@ -215,6 +275,7 @@ export namespace Text {
function updateRenderableState(state: RenderableState, props: PD.Values<Params>) {
BaseGeometry.updateRenderableState(state, props)
state.pickable = false
state.opaque = false
}
}

View File

@@ -27,38 +27,39 @@ export interface TextureMesh {
readonly kind: 'texture-mesh',
/** Number of vertices in the texture-mesh */
readonly vertexCount: ValueCell<number>,
vertexCount: number,
/** Number of groups in the texture-mesh */
readonly groupCount: ValueCell<number>,
groupCount: number,
readonly geoTextureDim: ValueCell<Vec2>,
/** texture has vertex positions in XYZ and group id in W */
readonly vertexGroupTexture: ValueCell<Texture>,
readonly normalTexture: ValueCell<Texture>,
readonly boundingSphere: ValueCell<Sphere3D>,
readonly boundingSphere: Sphere3D
}
export namespace TextureMesh {
export function create(vertexCount: number, groupCount: number, vertexGroupTexture: Texture, normalTexture: Texture, boundingSphere: Sphere3D, textureMesh?: TextureMesh): TextureMesh {
const { width, height } = vertexGroupTexture
const width = vertexGroupTexture.getWidth()
const height = vertexGroupTexture.getHeight()
if (textureMesh) {
ValueCell.update(textureMesh.vertexCount, vertexCount)
ValueCell.update(textureMesh.groupCount, groupCount)
textureMesh.vertexCount = vertexCount
textureMesh.groupCount = groupCount
ValueCell.update(textureMesh.geoTextureDim, Vec2.set(textureMesh.geoTextureDim.ref.value, width, height))
ValueCell.update(textureMesh.vertexGroupTexture, vertexGroupTexture)
ValueCell.update(textureMesh.normalTexture, normalTexture)
ValueCell.update(textureMesh.boundingSphere, boundingSphere)
Sphere3D.copy(textureMesh.boundingSphere, boundingSphere)
return textureMesh
} else {
return {
kind: 'texture-mesh',
vertexCount: ValueCell.create(vertexCount),
groupCount: ValueCell.create(groupCount),
vertexCount,
groupCount,
geoTextureDim: ValueCell.create(Vec2.create(width, height)),
vertexGroupTexture: ValueCell.create(vertexGroupTexture),
normalTexture: ValueCell.create(normalTexture),
boundingSphere: ValueCell.create(boundingSphere),
boundingSphere: Sphere3D.clone(boundingSphere),
}
}
}
@@ -93,9 +94,9 @@ export namespace TextureMesh {
const overpaint = createEmptyOverpaint()
const transparency = createEmptyTransparency()
const counts = { drawCount: textureMesh.vertexCount.ref.value, groupCount, instanceCount }
const counts = { drawCount: textureMesh.vertexCount, groupCount, instanceCount }
const transformBoundingSphere = calculateTransformBoundingSphere(textureMesh.boundingSphere.ref.value, transform.aTransform.ref.value, transform.instanceCount.ref.value)
const transformBoundingSphere = calculateTransformBoundingSphere(textureMesh.boundingSphere, transform.aTransform.ref.value, transform.instanceCount.ref.value)
return {
uGeoTexDim: textureMesh.geoTextureDim,
@@ -103,9 +104,9 @@ export namespace TextureMesh {
tNormal: textureMesh.normalTexture,
// aGroup is used as a vertex index here and the group id is retirieved from tPositionGroup
aGroup: ValueCell.create(fillSerial(new Float32Array(textureMesh.vertexCount.ref.value))),
aGroup: ValueCell.create(fillSerial(new Float32Array(textureMesh.vertexCount))),
boundingSphere: ValueCell.create(transformBoundingSphere),
invariantBoundingSphere: textureMesh.boundingSphere,
invariantBoundingSphere: ValueCell.create(Sphere3D.clone(textureMesh.boundingSphere)),
...color,
...marker,
@@ -128,14 +129,7 @@ export namespace TextureMesh {
}
function updateValues(values: TextureMeshValues, props: PD.Values<Params>) {
if (Color.fromNormalizedArray(values.uHighlightColor.ref.value, 0) !== props.highlightColor) {
ValueCell.update(values.uHighlightColor, Color.toArrayNormalized(props.highlightColor, values.uHighlightColor.ref.value, 0))
}
if (Color.fromNormalizedArray(values.uSelectColor.ref.value, 0) !== props.selectColor) {
ValueCell.update(values.uSelectColor, Color.toArrayNormalized(props.selectColor, values.uSelectColor.ref.value, 0))
}
ValueCell.updateIfChanged(values.alpha, props.alpha) // `uAlpha` is set in renderable.render
ValueCell.updateIfChanged(values.dUseFog, props.useFog)
ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided)
ValueCell.updateIfChanged(values.dFlatShaded, props.flatShaded)
@@ -148,7 +142,7 @@ export namespace TextureMesh {
}
function updateBoundingSphere(values: TextureMeshValues, textureMesh: TextureMesh) {
const invariantBoundingSphere = textureMesh.boundingSphere.ref.value
const invariantBoundingSphere = textureMesh.boundingSphere
const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, values.aTransform.ref.value, values.instanceCount.ref.value)
if (!Sphere3D.equals(boundingSphere, values.boundingSphere.ref.value)) {
ValueCell.update(values.boundingSphere, boundingSphere)

View File

@@ -61,23 +61,20 @@ export function PerforatedBox() {
let boxCage: Cage
export function BoxCage() {
if (!boxCage) {
boxCage = createCage(
[
0.5, 0.5, -0.5, // bottom
-0.5, 0.5, -0.5,
-0.5, -0.5, -0.5,
0.5, -0.5, -0.5,
0.5, 0.5, 0.5, // top
-0.5, 0.5, 0.5,
-0.5, -0.5, 0.5,
0.5, -0.5, 0.5
],
[
0, 4, 1, 5, 2, 6, 3, 7, // sides
0, 1, 1, 2, 2, 3, 3, 0, // bottom base
4, 5, 5, 6, 6, 7, 7, 4 // top base
]
)
boxCage = createCage([
0.5, 0.5, -0.5, // bottom
-0.5, 0.5, -0.5,
-0.5, -0.5, -0.5,
0.5, -0.5, -0.5,
0.5, 0.5, 0.5, // top
-0.5, 0.5, 0.5,
-0.5, -0.5, 0.5,
0.5, -0.5, 0.5
], [
0, 4, 1, 5, 2, 6, 3, 7, // sides
0, 1, 1, 2, 2, 3, 3, 0, // bottom base
4, 5, 5, 6, 6, 7, 7, 4 // top base
])
}
return boxCage
}

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 cloneCage(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

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Primitive } from './primitive';
export const DefaultCircleProps = {
radius: 1,
segments: 36,
thetaStart: 0,
thetaLength: Math.PI * 2
}
export type CirclerProps = Partial<typeof DefaultCircleProps>
export function Circle(props?: CirclerProps): Primitive {
const { radius, segments, thetaStart, thetaLength } = { ...DefaultCircleProps, ...props }
const isFull = thetaLength === Math.PI * 2
const count = isFull ? segments + 1 : segments + 2
const vertices = new Float32Array(count * 3)
const normals = new Float32Array(count * 3)
const indices = new Uint32Array(segments * 3)
// center
vertices[0] = 0; vertices[1] = 0; vertices[2] = 0;
normals[0] = 0; normals[1] = 1; normals[2] = 0;
// vertices & normals
for (let s = 0, i = 3; s < segments; ++s, i += 3) {
const segment = thetaStart + s / segments * thetaLength;
vertices[i] = radius * Math.sin(segment)
vertices[i + 1] = 0
vertices[i + 2] = radius * Math.cos(segment)
normals[i] = 0; normals[i + 1] = 1; normals[i + 2] = 0;
}
// indices
for (let s = 1, i = 0; s < segments; ++s, i += 3) {
indices[i] = s; indices[i + 1] = s + 1; indices[i + 2] = 0;
}
if (isFull) {
const j = (segments - 1) * 3
indices[j] = segments
indices[j + 1] = 1
indices[j + 2] = 0
} else {
const segment = thetaStart + thetaLength;
const i = (segments + 1) * 3
vertices[i] = radius * Math.sin(segment)
vertices[i + 1] = 0
vertices[i + 2] = radius * Math.cos(segment)
normals[i] = 0; normals[i + 1] = 1; normals[i + 2] = 0;
const j = (segments - 1) * 3
indices[j] = segments
indices[j + 1] = segments + 1
indices[j + 2] = 0
}
return { vertices, normals, indices }
}

View File

@@ -14,46 +14,46 @@ const b = 1 / t;
const c = 2 - t;
export const dodecahedronVertices: ReadonlyArray<number> = [
c, 0, a, -c, 0, a, -b, b, b, 0, a, c, b, b, b,
b, -b, b, 0, -a, c, -b, -b, b, c, 0, -a, -c, 0, -a,
c, 0, a, -c, 0, a, -b, b, b, 0, a, c, b, b, b,
b, -b, b, 0, -a, c, -b, -b, b, c, 0, -a, -c, 0, -a,
-b, -b, -b, 0, -a, -c, b, -b, -b, b, b, -b, 0, a, -c,
-b, b, -b, a, c, 0, -a, c, 0, -a, -c, 0, a, -c, 0
];
/** indices of pentagonal faces, groups of five */
export const dodecahedronFaces: ReadonlyArray<number> = [
4, 3, 2, 1, 0,
7, 6, 5, 0, 1,
4, 3, 2, 1, 0,
7, 6, 5, 0, 1,
12, 11, 10, 9, 8,
15, 14, 13, 8, 9,
14, 3, 4, 16, 13,
3, 14, 15, 17, 2,
3, 14, 15, 17, 2,
11, 6, 7, 18, 10,
6, 11, 12, 19, 5,
4, 0, 5, 19, 16,
6, 11, 12, 19, 5,
4, 0, 5, 19, 16,
12, 8, 13, 16, 19,
15, 9, 10, 18, 17,
7, 1, 2, 17, 18
7, 1, 2, 17, 18
];
const dodecahedronIndices: ReadonlyArray<number> = [ // pentagonal faces
4, 3, 2, 2, 1, 0, 4, 2, 0, // 4, 3, 2, 1, 0
7, 6, 5, 5, 0, 1, 7, 5, 1, // 7, 6, 5, 0, 1
4, 3, 2, 2, 1, 0, 4, 2, 0, // 4, 3, 2, 1, 0
7, 6, 5, 5, 0, 1, 7, 5, 1, // 7, 6, 5, 0, 1
12, 11, 10, 10, 9, 8, 12, 10, 8, // 12, 11, 10, 9, 8
15, 14, 13, 13, 8, 9, 15, 13, 9, // 15, 14, 13, 8, 9
14, 3, 4, 4, 16, 13, 14, 4, 13, // 14, 3, 4, 16, 13
3, 14, 15, 15, 17, 2, 3, 15, 2, // 3, 14, 15, 17, 2
3, 14, 15, 15, 17, 2, 3, 15, 2, // 3, 14, 15, 17, 2
11, 6, 7, 7, 18, 10, 11, 7, 10, // 11, 6, 7, 18, 10
6, 11, 12, 12, 19, 5, 6, 12, 5, // 6, 11, 12, 19, 5
4, 0, 5, 5, 19, 16, 4, 5, 16, // 4, 0, 5, 19, 16
6, 11, 12, 12, 19, 5, 6, 12, 5, // 6, 11, 12, 19, 5
4, 0, 5, 5, 19, 16, 4, 5, 16, // 4, 0, 5, 19, 16
12, 8, 13, 13, 16, 19, 12, 13, 19, // 12, 8, 13, 16, 19
15, 9, 10, 10, 18, 17, 15, 10, 17, // 15, 9, 10, 18, 17
7, 1, 2, 2, 17, 18, 7, 2, 18, // 7, 1, 2, 17, 18
7, 1, 2, 2, 17, 18, 7, 2, 18, // 7, 1, 2, 17, 18
];
const dodecahedronEdges: ReadonlyArray<number> = [
0, 1, 0, 4, 0, 5, 1, 2, 1, 7, 2, 3, 2, 17, 3, 4, 3, 14, 4, 16,
5, 6, 5, 19, 6, 7, 6, 11, 7, 18, 8, 9, 8, 12, 8, 13, 9, 10, 9, 15,
0, 1, 0, 4, 0, 5, 1, 2, 1, 7, 2, 3, 2, 17, 3, 4, 3, 14, 4, 16,
5, 6, 5, 19, 6, 7, 6, 11, 7, 18, 8, 9, 8, 12, 8, 13, 9, 10, 9, 15,
10, 11, 10, 18, 11, 12, 12, 19, 13, 14, 13, 16, 14, 15, 15, 17, 16, 19, 17, 18,
]

View File

@@ -11,8 +11,8 @@ const t = (1 + Math.sqrt(5)) / 2;
const icosahedronVertices: ReadonlyArray<number> = [
-1, t, 0, 1, t, 0, -1, -t, 0, 1, -t, 0,
0, -1, t, 0, 1, t, 0, -1, -t, 0, 1, -t,
t, 0, -1, t, 0, 1, -t, 0, -1, -t, 0, 1
0, -1, t, 0, 1, t, 0, -1, -t, 0, 1, -t,
t, 0, -1, t, 0, 1, -t, 0, -1, -t, 0, 1
];
const icosahedronIndices: ReadonlyArray<number> = [

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -28,7 +28,7 @@ export function Polyhedron(_vertices: ArrayLike<number>, _indices: ArrayLike<num
appplyRadius(vertices, radius);
const normals = new Float32Array(vertices.length);
computeIndexedVertexNormals(vertices, indices, normals)
computeIndexedVertexNormals(vertices, indices, normals, vertices.length / 3, indices.length / 3)
return {
vertices: new Float32Array(vertices),
@@ -39,9 +39,9 @@ export function Polyhedron(_vertices: ArrayLike<number>, _indices: ArrayLike<num
// helper functions
function subdivide(detail: number) {
const a = Vec3.zero()
const b = Vec3.zero()
const c = Vec3.zero()
const a = Vec3()
const b = Vec3()
const c = Vec3()
// iterate over all faces and apply a subdivison with the given detail value
for (let i = 0; i < _indices.length; i += 3) {
@@ -66,10 +66,10 @@ export function Polyhedron(_vertices: ArrayLike<number>, _indices: ArrayLike<num
for (let i = 0; i <= cols; ++i) {
v[i] = []
const aj = Vec3.zero()
const aj = Vec3()
Vec3.lerp(aj, a, c, i / cols)
const bj = Vec3.zero()
const bj = Vec3()
Vec3.lerp(bj, b, c, i / cols)
const rows = cols - i
@@ -77,7 +77,7 @@ export function Polyhedron(_vertices: ArrayLike<number>, _indices: ArrayLike<num
if (j === 0 && i === cols) {
v[i][j] = aj
} else {
const abj = Vec3.zero()
const abj = Vec3()
Vec3.lerp(abj, aj, bj, j / rows)
v[i][j] = abj
@@ -90,7 +90,6 @@ export function Polyhedron(_vertices: ArrayLike<number>, _indices: ArrayLike<num
for (let j = 0; j < 2 * (cols - i) - 1; ++j) {
const k = Math.floor(j / 2)
if (j % 2 === 0) {
builder.add
builder.add(v[i][k + 1], v[i + 1][k], v[i][k])
} else {
builder.add(v[i][k + 1], v[i + 1][k + 1], v[i + 1][k])

View File

@@ -5,7 +5,6 @@
*/
import { Vec3, Mat4, Mat3 } from '../../mol-math/linear-algebra';
import { getNormalMatrix } from '../util';
import { NumberArray } from '../../mol-util/type-helpers';
export interface Primitive {
@@ -30,6 +29,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
@@ -66,7 +73,7 @@ const tmpMat3 = Mat3.zero()
/** Transform primitive in-place */
export function transformPrimitive(primitive: Primitive, t: Mat4) {
const { vertices, normals } = primitive
const n = getNormalMatrix(tmpMat3, t)
const n = Mat3.directionTransform(tmpMat3, t)
for (let i = 0, il = vertices.length; i < il; i += 3) {
// position
Vec3.transformMat4(tmpV, Vec3.fromArray(tmpV, vertices, i), t)

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

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -8,20 +8,16 @@ import { createPrimitive, Primitive } from './primitive';
import { createCage, Cage } from './cage';
export const tetrahedronVertices: ReadonlyArray<number> = [
0.7071, 0, 0, -0.3535, 0.6123, 0, -0.3535, -0.6123, 0,
0, 0, 0.7071, 0, 0, -0.7071
0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5
];
export const tetrahedronIndices: ReadonlyArray<number> = [
4, 1, 0, 4, 2, 1, 4, 0, 2,
0, 1, 3, 1, 2, 3, 2, 0, 3,
2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
];
const tetrahedronEdges: ReadonlyArray<number> = [
0, 1, 1, 2, 2, 0,
0, 3, 1, 3, 2, 3,
0, 4, 1, 4, 2, 4,
]
let tetrahedron: Primitive

View File

@@ -1,30 +1,24 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Mat4, Mat3 } from '../mol-math/linear-algebra'
import { NumberArray } from '../mol-util/type-helpers';
import { arrayMax } from '../mol-util/array';
export function normalizeVec3Array<T extends NumberArray> (a: T) {
const n = a.length
for (let i = 0; i < n; i += 3) {
const x = a[ i ]
const y = a[ i + 1 ]
const z = a[ i + 2 ]
export function normalizeVec3Array<T extends NumberArray> (a: T, count: number) {
for (let i = 0, il = count * 3; i < il; i += 3) {
const x = a[i]
const y = a[i + 1]
const z = a[i + 2]
const s = 1 / Math.sqrt(x * x + y * y + z * z)
a[ i ] = x * s
a[ i + 1 ] = y * s
a[ i + 2 ] = z * s
a[i] = x * s
a[i + 1] = y * s
a[i + 2] = z * s
}
}
export function getNormalMatrix(out: Mat3, t: Mat4) {
Mat3.fromMat4(out, t)
Mat3.invert(out, out)
Mat3.transpose(out, out)
return out
return a
}
const tmpV3 = Vec3.zero()
@@ -45,38 +39,33 @@ export function transformDirectionArray (n: Mat3, array: NumberArray, offset: nu
}
}
export function setArrayZero(array: NumberArray) {
const n = array.length
for (let i = 0; i < n; ++i) array[i] = 0
}
/** iterate over the entire buffer and apply the radius to each vertex */
/** iterate over the entire array and apply the radius to each vertex */
export function appplyRadius(vertices: NumberArray, radius: number) {
const v = Vec3.zero()
const n = vertices.length
for (let i = 0; i < n; i += 3) {
Vec3.fromArray(v, vertices, i)
Vec3.normalize(v, v)
Vec3.scale(v, v, radius)
Vec3.toArray(v, vertices, i)
for (let i = 0, il = vertices.length; i < il; i += 3) {
Vec3.fromArray(tmpV3, vertices, i)
Vec3.normalize(tmpV3, tmpV3)
Vec3.scale(tmpV3, tmpV3, radius)
Vec3.toArray(tmpV3, vertices, i)
}
}
/**
* indexed vertex normals weighted by triangle areas http://www.iquilezles.org/www/articles/normals/normals.htm
* normal array must contain only zeros
*/
export function computeIndexedVertexNormals<T extends NumberArray> (vertices: NumberArray, indices: NumberArray, normals: T) {
const a = Vec3.zero()
const b = Vec3.zero()
const c = Vec3.zero()
const cb = Vec3.zero()
const ab = Vec3.zero()
const a = Vec3()
const b = Vec3()
const c = Vec3()
const cb = Vec3()
const ab = Vec3()
for (let i = 0, il = indices.length; i < il; i += 3) {
const ai = indices[ i ] * 3
const bi = indices[ i + 1 ] * 3
const ci = indices[ i + 2 ] * 3
/**
* indexed vertex normals weighted by triangle areas
* http://www.iquilezles.org/www/articles/normals/normals.htm
* - normals array must contain only zeros
*/
export function computeIndexedVertexNormals<T extends NumberArray> (vertices: NumberArray, indices: NumberArray, normals: T, vertexCount: number, triangleCount: number) {
for (let i = 0, il = triangleCount * 3; i < il; i += 3) {
const ai = indices[i] * 3
const bi = indices[i + 1] * 3
const ci = indices[i + 2] * 3
Vec3.fromArray(a, vertices, ai)
Vec3.fromArray(b, vertices, bi)
@@ -86,34 +75,28 @@ export function computeIndexedVertexNormals<T extends NumberArray> (vertices: Nu
Vec3.sub(ab, a, b)
Vec3.cross(cb, cb, ab)
normals[ ai ] += cb[ 0 ]
normals[ ai + 1 ] += cb[ 1 ]
normals[ ai + 2 ] += cb[ 2 ]
normals[ai] += cb[0]
normals[ai + 1] += cb[1]
normals[ai + 2] += cb[2]
normals[ bi ] += cb[ 0 ]
normals[ bi + 1 ] += cb[ 1 ]
normals[ bi + 2 ] += cb[ 2 ]
normals[bi] += cb[0]
normals[bi + 1] += cb[1]
normals[bi + 2] += cb[2]
normals[ ci ] += cb[ 0 ]
normals[ ci + 1 ] += cb[ 1 ]
normals[ ci + 2 ] += cb[ 2 ]
normals[ci] += cb[0]
normals[ci + 1] += cb[1]
normals[ci + 2] += cb[2]
}
normalizeVec3Array(normals)
return normals
return normalizeVec3Array(normals, vertexCount)
}
/** vertex normals for unindexed triangle soup, normal array must contain only zeros */
export function computeVertexNormals<T extends NumberArray> (vertices: NumberArray, normals: T) {
setArrayZero(normals)
const a = Vec3.zero()
const b = Vec3.zero()
const c = Vec3.zero()
const cb = Vec3.zero()
const ab = Vec3.zero()
for (let i = 0, il = vertices.length; i < il; i += 9) {
/**
* vertex normals for unindexed triangle soup
* - normals array must contain only zeros
*/
export function computeVertexNormals<T extends NumberArray> (vertices: NumberArray, normals: T, vertexCount: number) {
for (let i = 0, il = vertexCount * 3; i < il; i += 9) {
Vec3.fromArray(a, vertices, i)
Vec3.fromArray(b, vertices, i + 3)
Vec3.fromArray(c, vertices, i + 6)
@@ -122,19 +105,58 @@ export function computeVertexNormals<T extends NumberArray> (vertices: NumberArr
Vec3.sub(ab, a, b)
Vec3.cross(cb, cb, ab)
normals[ i ] = cb[ 0 ]
normals[ i + 1 ] = cb[ 1 ]
normals[ i + 2 ] = cb[ 2 ]
normals[i] = cb[0]
normals[i + 1] = cb[1]
normals[i + 2] = cb[2]
normals[ i + 3 ] = cb[ 0 ]
normals[ i + 4 ] = cb[ 1 ]
normals[ i + 5 ] = cb[ 2 ]
normals[i + 3] = cb[0]
normals[i + 4] = cb[1]
normals[i + 5] = cb[2]
normals[ i + 6 ] = cb[ 0 ]
normals[ i + 7 ] = cb[ 1 ]
normals[ i + 8 ] = cb[ 2 ]
normals[i + 6] = cb[0]
normals[i + 7] = cb[1]
normals[i + 8] = cb[2]
}
normalizeVec3Array(normals)
return normals
}
return normalizeVec3Array(normals, vertexCount)
}
/**
* Maps groups to data, range for group i is offsets[i] to offsets[i + 1]
*/
export type GroupMapping = {
/** data indices */
readonly indices: ArrayLike<number>
/** range for group i is offsets[i] to offsets[i + 1] */
readonly offsets: ArrayLike<number>
}
/**
* The `step` parameter allows to skip over repeated values in `groups`
*/
export function createGroupMapping(groups: ArrayLike<number>, dataCount: number, step = 1): GroupMapping {
const maxId = arrayMax(groups)
const offsets = new Int32Array(maxId + 2)
const bucketFill = new Int32Array(dataCount)
const bucketSizes = new Int32Array(dataCount)
for (let i = 0, il = dataCount * step; i < il; i += step) ++bucketSizes[groups[i]]
let offset = 0
for (let i = 0; i < dataCount; i++) {
offsets[i] = offset
offset += bucketSizes[i]
}
offsets[dataCount] = offset
const indices = new Int32Array(offset)
for (let i = 0, il = dataCount * step; i < il; i += step) {
const g = groups[i]
const og = offsets[g] + bucketFill[g]
indices[og] = i
++bucketFill[g]
}
return { indices, offsets }
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -7,13 +7,13 @@
*/
import { ChunkedArray } from '../../../mol-data/util';
import { ValueCell, noop } from '../../../mol-util';
import { noop } from '../../../mol-util';
import { Mesh } from '../../geometry/mesh/mesh';
import { AllowedContours } from './tables';
import { LinesBuilder } from '../../geometry/lines/lines-builder';
import { Lines } from '../../geometry/lines/lines';
export interface MarchinCubesBuilder<T> {
export interface MarchinCubesBuilder<T> {
addVertex(x: number, y: number, z: number): number
addNormal(x: number, y: number, z: number): void
addGroup(group: number): void
@@ -52,17 +52,7 @@ export function MarchinCubesMeshBuilder(vertexChunkSize: number, mesh?: Mesh): M
const nb = ChunkedArray.compact(normals, true) as Float32Array;
const ib = ChunkedArray.compact(indices, true) as Uint32Array;
const gb = ChunkedArray.compact(groups, true) as Float32Array;
return {
kind: 'mesh',
vertexCount,
triangleCount,
vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb),
groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, gb) : ValueCell.create(gb),
indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib),
normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb),
normalsComputed: true
}
return Mesh.create(vb, ib, nb, gb, vertexCount, triangleCount, mesh)
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -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 }
}
@@ -67,8 +65,6 @@ function createPoints() {
...transparency,
uAlpha: ValueCell.create(1.0),
uHighlightColor: ValueCell.create(Vec3.create(1.0, 0.4, 0.6)),
uSelectColor: ValueCell.create(Vec3.create(0.2, 1.0, 0.1)),
uInstanceCount: ValueCell.create(1),
uGroupCount: ValueCell.create(3),
@@ -85,7 +81,6 @@ function createPoints() {
dPointSizeAttenuation: ValueCell.create(true),
dPointFilledCircle: ValueCell.create(false),
uPointEdgeBleach: ValueCell.create(0.5),
dUseFog: ValueCell.create(true),
}
const state: RenderableState = {
visible: true,
@@ -106,11 +101,11 @@ describe('renderer', () => {
expect(ctx.gl.canvas.width).toBe(32)
expect(ctx.gl.canvas.height).toBe(32)
expect(ctx.stats.bufferCount).toBe(0);
expect(ctx.stats.textureCount).toBe(0);
expect(ctx.stats.vaoCount).toBe(0);
expect(ctx.programCache.count).toBe(0);
expect(ctx.shaderCache.count).toBe(0);
expect(ctx.stats.resourceCounts.attribute).toBe(0);
expect(ctx.stats.resourceCounts.texture).toBe(0);
expect(ctx.stats.resourceCounts.vertexArray).toBe(0);
expect(ctx.stats.resourceCounts.program).toBe(0);
expect(ctx.stats.resourceCounts.shader).toBe(0);
renderer.setViewport(0, 0, 64, 48)
expect(ctx.gl.getParameter(ctx.gl.VIEWPORT)[2]).toBe(64)
@@ -126,25 +121,23 @@ describe('renderer', () => {
const points = createPoints()
scene.add(points)
await scene.commit().run()
expect(ctx.stats.bufferCount).toBe(4);
expect(ctx.stats.textureCount).toBe(5);
expect(ctx.stats.vaoCount).toBe(5);
expect(ctx.programCache.count).toBe(5);
expect(ctx.shaderCache.count).toBe(10);
scene.commit()
expect(ctx.stats.resourceCounts.attribute).toBe(4);
expect(ctx.stats.resourceCounts.texture).toBe(5);
expect(ctx.stats.resourceCounts.vertexArray).toBe(5);
expect(ctx.stats.resourceCounts.program).toBe(5);
expect(ctx.stats.resourceCounts.shader).toBe(10);
scene.remove(points)
await scene.commit().run()
expect(ctx.stats.bufferCount).toBe(0);
expect(ctx.stats.textureCount).toBe(0);
expect(ctx.stats.vaoCount).toBe(0);
expect(ctx.programCache.count).toBe(5);
expect(ctx.shaderCache.count).toBe(10);
scene.commit()
expect(ctx.stats.resourceCounts.attribute).toBe(0);
expect(ctx.stats.resourceCounts.texture).toBe(0);
expect(ctx.stats.resourceCounts.vertexArray).toBe(0);
expect(ctx.stats.resourceCounts.program).toBe(5);
expect(ctx.stats.resourceCounts.shader).toBe(10);
ctx.programCache.dispose()
expect(ctx.programCache.count).toBe(0);
ctx.shaderCache.clear()
expect(ctx.shaderCache.count).toBe(0);
ctx.resources.destroy()
expect(ctx.stats.resourceCounts.program).toBe(0);
expect(ctx.stats.resourceCounts.shader).toBe(0);
})
})

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { LinkedList } from '../mol-data/generic'
import { GraphicsRenderObject } from './render-object'
type N = LinkedList.Node<GraphicsRenderObject>
export class CommitQueue {
private removeList = LinkedList<GraphicsRenderObject>();
private removeMap = new Map<GraphicsRenderObject, N>();
private addList = LinkedList<GraphicsRenderObject>();
private addMap = new Map<GraphicsRenderObject, N>();
get isEmpty() {
return this.removeList.count === 0 && this.addList.count === 0;
}
add(o: GraphicsRenderObject) {
if (this.removeMap.has(o)) {
const a = this.removeMap.get(o)!;
this.removeMap.delete(o);
this.removeList.remove(a);
}
if (this.addMap.has(o)) return;
const b = this.addList.addLast(o);
this.addMap.set(o, b);
}
remove(o: GraphicsRenderObject) {
if (this.addMap.has(o)) {
const a = this.addMap.get(o)!;
this.addMap.delete(o);
this.addList.remove(a);
}
if (this.removeMap.has(o)) return;
const b = this.removeList.addLast(o);
this.removeMap.set(o, b);
}
tryGetRemove() {
const o = this.removeList.removeFirst();
if (o) this.removeMap.delete(o);
return o;
}
tryGetAdd() {
const o = this.addList.removeFirst();
if (o) this.addMap.delete(o);
return o;
}
}

View File

@@ -8,13 +8,13 @@ import { createComputeRenderable, ComputeRenderable } from '../../renderable'
import { WebGLContext } from '../../webgl/context';
import { createComputeRenderItem } from '../../webgl/render-item';
import { Values, TextureSpec, UniformSpec } from '../../renderable/schema';
import { Texture, createTexture } from '../../../mol-gl/webgl/texture';
import { Texture } from '../../../mol-gl/webgl/texture';
import { ShaderCode } from '../../../mol-gl/shader-code';
import { ValueCell } from '../../../mol-util';
import { QuadSchema, QuadValues } from '../util';
import { Vec2 } from '../../../mol-math/linear-algebra';
import { getHistopyramidSum } from './sum';
import { Framebuffer, createFramebuffer } from '../../../mol-gl/webgl/framebuffer';
import { Framebuffer } from '../../../mol-gl/webgl/framebuffer';
import { isPowerOfTwo } from '../../../mol-math/misc';
import quad_vert from '../../../mol-gl/shader/quad.vert'
import reduction_frag from '../../../mol-gl/shader/histogram-pyramid/reduction.frag'
@@ -55,8 +55,8 @@ function getLevelTextureFramebuffer(ctx: WebGLContext, level: number) {
let textureFramebuffer = LevelTexturesFramebuffers[level]
const size = Math.pow(2, level)
if (textureFramebuffer === undefined) {
const texture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
const framebuffer = createFramebuffer(ctx.gl, ctx.stats)
const texture = ctx.resources.texture('image-float32', 'rgba', 'float', 'nearest')
const framebuffer = ctx.resources.framebuffer()
texture.attachFramebuffer(framebuffer, 0)
textureFramebuffer = { texture, framebuffer }
textureFramebuffer.texture.define(size, size)
@@ -85,22 +85,22 @@ export interface HistogramPyramid {
}
export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture, scale: Vec2): HistogramPyramid {
const { gl, framebufferCache } = ctx
const { gl, resources } = ctx
// printTexture(ctx, inputTexture, 2)
if (inputTexture.width !== inputTexture.height || !isPowerOfTwo(inputTexture.width)) {
if (inputTexture.getWidth() !== inputTexture.getHeight() || !isPowerOfTwo(inputTexture.getWidth())) {
throw new Error('inputTexture must be of square power-of-two size')
}
// This part set the levels
const levels = Math.ceil(Math.log(inputTexture.width) / Math.log(2))
const levels = Math.ceil(Math.log(inputTexture.getWidth()) / Math.log(2))
const maxSize = Math.pow(2, levels)
// console.log('levels', levels, 'maxSize', maxSize)
const pyramidTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
const pyramidTexture = resources.texture('image-float32', 'rgba', 'float', 'nearest')
pyramidTexture.define(maxSize, maxSize)
const framebuffer = framebufferCache.get('reduction').value
const framebuffer = resources.framebuffer()
pyramidTexture.attachFramebuffer(framebuffer, 0)
gl.clear(gl.COLOR_BUFFER_BIT)

View File

@@ -8,7 +8,7 @@ import { createComputeRenderable, ComputeRenderable } from '../../renderable'
import { WebGLContext } from '../../webgl/context';
import { createComputeRenderItem } from '../../webgl/render-item';
import { Values, TextureSpec } from '../../renderable/schema';
import { Texture, createTexture } from '../../../mol-gl/webgl/texture';
import { Texture } from '../../../mol-gl/webgl/texture';
import { ShaderCode } from '../../../mol-gl/shader-code';
import { ValueCell } from '../../../mol-util';
import { decodeFloatRGB } from '../../../mol-util/float-packing';
@@ -45,14 +45,11 @@ function getHistopyramidSumRenderable(ctx: WebGLContext, texture: Texture) {
let SumTexture: Texture
function getSumTexture(ctx: WebGLContext) {
if (SumTexture) return SumTexture
SumTexture = createTexture(ctx, 'image-uint8', 'rgba', 'ubyte', 'nearest')
SumTexture = ctx.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest')
SumTexture.define(1, 1)
return SumTexture
}
/** name for shared framebuffer used for histogram-pyramid operations */
const FramebufferName = 'histogram-pyramid-sum'
function setRenderingDefaults(ctx: WebGLContext) {
const { gl, state } = ctx
state.disable(gl.CULL_FACE)
@@ -66,12 +63,12 @@ function setRenderingDefaults(ctx: WebGLContext) {
const sumArray = new Uint8Array(4)
export function getHistopyramidSum(ctx: WebGLContext, pyramidTopTexture: Texture) {
const { gl, framebufferCache } = ctx
const { gl, resources } = ctx
const renderable = getHistopyramidSumRenderable(ctx, pyramidTopTexture)
ctx.state.currentRenderItemId = -1
const framebuffer = framebufferCache.get(FramebufferName).value
const framebuffer = resources.framebuffer()
const sumTexture = getSumTexture(ctx)
sumTexture.attachFramebuffer(framebuffer, 0)

View File

@@ -8,7 +8,7 @@ import { createComputeRenderable } from '../../renderable'
import { WebGLContext } from '../../webgl/context';
import { createComputeRenderItem } from '../../webgl/render-item';
import { Values, TextureSpec, UniformSpec } from '../../renderable/schema';
import { Texture, createTexture } from '../../../mol-gl/webgl/texture';
import { Texture } from '../../../mol-gl/webgl/texture';
import { ShaderCode } from '../../../mol-gl/shader-code';
import { ValueCell } from '../../../mol-util';
import { Vec3, Vec2 } from '../../../mol-math/linear-algebra';
@@ -17,9 +17,6 @@ import { getTriCount } from './tables';
import quad_vert from '../../../mol-gl/shader/quad.vert'
import active_voxels_frag from '../../../mol-gl/shader/marching-cubes/active-voxels.frag'
/** name for shared framebuffer used for gpu marching cubes operations */
const FramebufferName = 'marching-cubes-active-voxels'
const ActiveVoxelsSchema = {
...QuadSchema,
@@ -67,13 +64,14 @@ function setRenderingDefaults(ctx: WebGLContext) {
}
export function calcActiveVoxels(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, isoValue: number, gridScale: Vec2) {
const { gl, framebufferCache } = ctx
const { width, height } = volumeData
const { gl, resources } = ctx
const width = volumeData.getWidth()
const height = volumeData.getHeight()
const framebuffer = framebufferCache.get(FramebufferName).value
const framebuffer = resources.framebuffer()
framebuffer.bind()
const activeVoxelsTex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
const activeVoxelsTex = resources.texture('image-float32', 'rgba', 'float', 'nearest')
activeVoxelsTex.define(width, height)
const renderable = getActiveVoxelsRenderable(ctx, volumeData, gridDim, gridTexDim, isoValue, gridScale)

View File

@@ -8,7 +8,7 @@ import { createComputeRenderable } from '../../renderable'
import { WebGLContext } from '../../webgl/context';
import { createComputeRenderItem } from '../../webgl/render-item';
import { Values, TextureSpec, UniformSpec } from '../../renderable/schema';
import { Texture, createTexture } from '../../../mol-gl/webgl/texture';
import { Texture } from '../../../mol-gl/webgl/texture';
import { ShaderCode } from '../../../mol-gl/shader-code';
import { ValueCell } from '../../../mol-util';
import { Vec3, Vec2, Mat4 } from '../../../mol-math/linear-algebra';
@@ -18,9 +18,6 @@ import { getTriIndices } from './tables';
import quad_vert from '../../../mol-gl/shader/quad.vert'
import isosurface_frag from '../../../mol-gl/shader/marching-cubes/isosurface.frag'
/** name for shared framebuffer used for gpu marching cubes operations */
const FramebufferName = 'marching-cubes-isosurface'
const IsosurfaceSchema = {
...QuadSchema,
@@ -83,30 +80,30 @@ function setRenderingDefaults(ctx: WebGLContext) {
}
export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, vertexGroupTexture?: Texture, normalTexture?: Texture) {
const { gl, framebufferCache } = ctx
const { gl, resources } = ctx
const { pyramidTex, height, levels, scale, count } = histogramPyramid
// console.log('iso', 'gridDim', gridDim, 'scale', scale, 'gridTexDim', gridTexDim)
// console.log('iso volumeData', volumeData)
const framebuffer = framebufferCache.get(FramebufferName).value
const framebuffer = resources.framebuffer()
let needsClear = false
if (!vertexGroupTexture) {
vertexGroupTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
vertexGroupTexture.define(pyramidTex.width, pyramidTex.height)
} else if (vertexGroupTexture.width !== pyramidTex.width || vertexGroupTexture.height !== pyramidTex.height) {
vertexGroupTexture.define(pyramidTex.width, pyramidTex.height)
vertexGroupTexture = resources.texture('image-float32', 'rgba', 'float', 'nearest')
vertexGroupTexture.define(pyramidTex.getWidth(), pyramidTex.getHeight())
} else if (vertexGroupTexture.getWidth() !== pyramidTex.getWidth() || vertexGroupTexture.getHeight() !== pyramidTex.getHeight()) {
vertexGroupTexture.define(pyramidTex.getWidth(), pyramidTex.getHeight())
} else {
needsClear = true
}
if (!normalTexture) {
normalTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
normalTexture.define(pyramidTex.width, pyramidTex.height)
} else if (normalTexture.width !== pyramidTex.width || normalTexture.height !== pyramidTex.height) {
normalTexture.define(pyramidTex.width, pyramidTex.height)
normalTexture = resources.texture('image-float32', 'rgba', 'float', 'nearest')
normalTexture.define(pyramidTex.getWidth(), pyramidTex.getHeight())
} else if (normalTexture.getWidth() !== pyramidTex.getWidth() || normalTexture.getHeight() !== pyramidTex.getHeight()) {
normalTexture.define(pyramidTex.getWidth(), pyramidTex.getHeight())
} else {
needsClear = true
}
@@ -150,7 +147,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
])
setRenderingDefaults(ctx)
gl.viewport(0, 0, pyramidTex.width, pyramidTex.height)
gl.viewport(0, 0, pyramidTex.getWidth(), pyramidTex.getHeight())
if (needsClear) gl.clear(gl.COLOR_BUFFER_BIT)
renderable.render()

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