Compare commits

...

826 Commits

Author SHA1 Message Date
Alexander Rose
8f2085d8b4 0.6.0-dev.4 2020-03-18 20:59:42 -07:00
Alexander Rose
b5a48ad201 package updates 2020-03-18 20:59:01 -07:00
Alexander Rose
14b900791f wip, unitcell ref 2020-03-18 20:49:30 -07:00
Alexander Rose
de80799e68 allow any Loci in CameraManager.focusLoci 2020-03-18 20:44:54 -07:00
Alexander Rose
53eca387fc take renderable visibility into account for scene bounding-sphere 2020-03-18 20:35:14 -07:00
Alexander Rose
fc3005f271 ui tweaks 2020-03-18 16:47:57 -07:00
Alexander Rose
c95fdff00c tweaked StructureSelectionCategorys 2020-03-18 16:04:09 -07:00
Alexander Rose
3cd9042c72 added helpers to Model, better InitVolumeStreaming.isApplicable check 2020-03-18 15:47:58 -07:00
Alexander Rose
4d3914426e improved LociLabelManager to handle multiple loci 2020-03-18 15:46:29 -07:00
Alexander Rose
5c77eec184 bounding-sphere fixes
- fixed renderable.spec
- simplify extrema for calculateInvariantBoundingSphere when possible
- fixed Sphere3D.expand
2020-03-17 23:19:26 -07:00
Alexander Rose
a931ed7c01 Merge branch 'master' into objects 2020-03-17 21:46:22 -07:00
Alexander Rose
94cd2b618c wip 2020-03-17 20:17:41 -07:00
Alexander Rose
9c97fc258d better box3d calculation in boundary-helper 2020-03-17 16:35:57 -07:00
Alexander Rose
0ac1cfe555 improved bounding sphere- drop hierarchy in favor of extrema points 2020-03-17 16:28:34 -07:00
Alexander Rose
3942f1bc33 added PickRequired type helper 2020-03-17 15:21:06 -07:00
Alexander Rose
a66e38a901 use unit/structure bounding-sphere in visuals geometry 2020-03-17 12:15:39 -07:00
Alexander Rose
f65f4f4aeb seperate grid and boundary calculation 2020-03-17 12:14:36 -07:00
Alexander Rose
f28b13bf87 shader: fixed broken flat-shaded & flip-sided 2020-03-17 09:48:28 -07:00
David Sehnal
8f211a0785 servers readme tweak 2020-03-17 15:50:05 +01:00
David Sehnal
ba1dfb2851 remove preprocess app from webpack config 2020-03-17 15:35:06 +01:00
David Sehnal
964d56752e 0.6.0-dev.3 2020-03-17 15:32:11 +01:00
David Sehnal
cb6a66eba5 0.6.0-dev.2 2020-03-17 15:25:18 +01:00
David Sehnal
94adf7259d model and volume server configuration and docs 2020-03-17 14:46:28 +01:00
David Sehnal
3c831b549a volume-server JSON config 2020-03-17 12:34:32 +01:00
Alexander Rose
7ccf36a0fa moved unitcell representation to mol-repr/shape 2020-03-16 22:38:46 -07:00
Alexander Rose
b0ee640c12 calc bespoke boundingSphere for unitcell 2020-03-16 22:18:09 -07:00
Alexander Rose
cd6d41a035 allow direct setting of geo bounding sphere
- support mesh, lines, text, spheres, points
2020-03-16 21:20:07 -07:00
Alexander Rose
9c8f1f3e11 wip 2020-03-16 17:20:20 -07:00
Alexander Rose
7c50a5a456 HierarchyHelper: check if the split spheres actually result in a smaller radius 2020-03-16 16:12:13 -07:00
David Sehnal
f3b6703fd4 mol-plugin-ui unsubscribe events 2020-03-16 20:05:06 +01:00
Alexander Rose
60f2716b5a fix missing camera reset from scene with only empty objects 2020-03-16 11:42:11 -07:00
David Sehnal
d7007ef99d CSS oveflow: hidden related fixes 2020-03-16 19:22:01 +01:00
David Sehnal
4aca41cdbb Controls Help in volume streaming controls 2020-03-16 15:54:47 +01:00
David Sehnal
7e31fac99a StructureHierarchy.childRoot for structure/model
- to correctly support decorators like custom props
2020-03-16 15:44:25 +01:00
David Sehnal
3bcf1cb6b5 VolumeStreaming manager & UI 2020-03-16 15:14:56 +01:00
David Sehnal
a29cc74304 StructureSourceControls tweak 2020-03-16 12:00:44 +01:00
David Sehnal
95c43d0864 fix camera.radius = 0 (leads to NaNs) 2020-03-16 11:59:32 +01:00
David Sehnal
369b958335 Refactor Bindings and show them in "Simple settings" 2020-03-16 11:51:05 +01:00
David Sehnal
9a17da8f65 Component UI improvements 2020-03-16 10:59:22 +01:00
Alexander Rose
0c4ba20d6e Merge branch 'master' of https://github.com/molstar/molstar 2020-03-15 23:46:55 -07:00
Alexander Rose
22936ff6c9 canvas3d settings improvements
- added clipping params
- show clipping radius
- ranmed render-style to lighting
2020-03-15 23:46:27 -07:00
David Sehnal
3369ad0bdc Change ParameterControls property name 2020-03-15 23:31:40 +01:00
David Sehnal
20853ef60b StructureSource: hide "actions button" when empty 2020-03-15 23:29:10 +01:00
David Sehnal
da0c66bd8e disable "Selected" button when empty 2020-03-15 23:25:08 +01:00
David Sehnal
44664917ff StateTree: always show remove all button 2020-03-15 23:22:36 +01:00
David Sehnal
ce26e002c7 StructureSource UI 2020-03-15 23:20:00 +01:00
David Sehnal
345b9f546c inline actions and updates in StateTree
mol-plugin code cleanup
2020-03-15 19:50:39 +01:00
David Sehnal
f4ed5e301d mol-plugin: code cleanup 2020-03-15 17:37:54 +01:00
David Sehnal
4818f851b3 measurements ui improvements 2020-03-15 16:54:25 +01:00
David Sehnal
6f2c47c0ca spinSpeed param update 2020-03-15 16:00:53 +01:00
David Sehnal
5e6bc0f0df ui tweaks 2020-03-15 15:47:30 +01:00
David Sehnal
083daa0b76 state undo label 2020-03-15 15:40:29 +01:00
David Sehnal
139a10ba8c do not freeze immer objects 2020-03-15 15:29:50 +01:00
David Sehnal
0b512487f5 add PD.Group.pivot, simplified viewport settings 2020-03-15 15:11:55 +01:00
David Sehnal
a85adfdf1f refactored Repr/Color/Size registry & built-ins
updated component UI
2020-03-15 14:32:04 +01:00
David Sehnal
0171b785af optimized Slider control 2020-03-15 01:37:47 +01:00
David Sehnal
4c1c484af9 PurePluginUIComponent fix 2020-03-15 00:25:53 +01:00
David Sehnal
db7585b6b6 CameraManager 2020-03-15 00:16:25 +01:00
David Sehnal
d263f6d929 allow to undo more than 1 step 2020-03-14 23:17:53 +01:00
David Sehnal
034c28e487 selection history updates
updated measurements ui
added focusLoci/Sphere
Loci stats label fixes
2020-03-14 22:44:36 +01:00
David Sehnal
9a88f57ce6 Unify PluginCommands.Highlight and HighlighAll
Select newly created models and structure for create all models
2020-03-14 20:40:40 +01:00
David Sehnal
28415646a2 StructureComponentManager.updateRepresentations tweak 2020-03-14 17:18:04 +01:00
David Sehnal
b03295ef81 undo button tweak 2020-03-14 16:49:13 +01:00
David Sehnal
7d3e849ff3 undo tweak 2020-03-14 15:24:03 +01:00
David Sehnal
926f20a6a4 mol-state: undo support 2020-03-14 15:21:45 +01:00
David Sehnal
c12d577ce6 Add intersect to Component modify options 2020-03-14 14:17:27 +01:00
David Sehnal
aa8d3a9841 tweak non-convalent interactions size factor 2020-03-14 13:41:59 +01:00
David Sehnal
f11e03eb85 Component UI: show modify operations only if available 2020-03-14 13:36:25 +01:00
David Sehnal
ab996b5189 Selection UI improvements 2020-03-14 13:19:03 +01:00
Alexander Rose
4c91e730a2 various params tweaks
- added more descriptions
- cleaned-up structure related params
- added missing quality categorisation
- clearer picking/granularity param
2020-03-13 23:39:35 -07:00
Alexander Rose
5ca5f44c61 tweaked set svg icons 2020-03-13 18:26:01 -07:00
Alexander Rose
f8a89b1c0d add HighlightMany plugin command 2020-03-13 18:12:30 -07:00
Alexander Rose
99dacef747 check structure equality for StructureElement.Loci 2020-03-13 18:10:20 -07:00
Alexander Rose
24fc37105e revert eslint indent rule (conflicts with switch statement) 2020-03-13 17:16:11 -07:00
Alexander Rose
cbd493d834 use sequential list as default for model-index color theme 2020-03-13 16:59:31 -07:00
Alexander Rose
53dbd1aedf ignore type params in eslint indent rule 2020-03-13 16:27:17 -07:00
Alexander Rose
6ab1af54aa added svg icon shapes for set operations 2020-03-13 15:59:47 -07:00
Alexander Rose
615d9758bb Merge branch 'master' of https://github.com/molstar/molstar 2020-03-13 10:17:20 -07:00
David Sehnal
341f9f8c91 repr/theme/size providers now contain unique name 2020-03-13 17:23:12 +01:00
David Sehnal
ba7d4a5215 customize current interaction, wip refactroring repr registries 2020-03-13 16:33:12 +01:00
David Sehnal
428187ad81 refactoring and tweaks 2020-03-13 13:47:20 +01:00
David Sehnal
fe96172fcd wip structure tools 2020-03-13 13:21:02 +01:00
David Sehnal
8b13be698c mol-plugin-state: StructureHierarchy tweaks 2020-03-13 12:23:04 +01:00
David Sehnal
5edc924e4f unify structure representation params creation 2020-03-13 11:55:06 +01:00
David Sehnal
78c50a4339 build config 2020-03-13 09:49:01 +01:00
Alexander Rose
607284585c intersect modifier for ui selections 2020-03-12 17:46:08 -07:00
Alexander Rose
f7af352f03 package updates 2020-03-12 17:45:10 -07:00
David Sehnal
008ec2c88c use tslib to provide helper functions (saves a lot of code) 2020-03-12 22:53:12 +01:00
David Sehnal
c91074ad91 add watch-viewer npm task for faster build times 2020-03-12 22:19:43 +01:00
David Sehnal
51fbb619e5 UI customization via spec & tweaks 2020-03-12 21:14:20 +01:00
David Sehnal
062c4b335b fix typo 2020-03-12 20:39:46 +01:00
David Sehnal
d4107e273d Merge branch 'master' of https://github.com/molstar/molstar 2020-03-12 20:33:14 +01:00
David Sehnal
4dad67fc2e improved Representation params 2020-03-12 20:33:02 +01:00
David Sehnal
64b0713742 represention preset common props 2020-03-12 20:19:24 +01:00
Alexander Rose
22c45e788e improved renderer and postprocessing params 2020-03-12 11:20:06 -07:00
David Sehnal
75de544669 wip source controls 2020-03-12 18:38:29 +01:00
David Sehnal
768ec10809 removed LociHighligh command extend 2020-03-12 17:29:16 +01:00
David Sehnal
4d5d9be399 wip: source structure manager 2020-03-12 17:26:51 +01:00
David Sehnal
7f4afc111e StructureHierarchyManager.currentTrajectories 2020-03-12 15:06:43 +01:00
David Sehnal
0365f883dd mol-plugin: customuze UI layout in viewport params 2020-03-12 14:04:42 +01:00
David Sehnal
6f98549f31 mol-state: doNotUpdateCurrent false as default 2020-03-12 13:23:49 +01:00
David Sehnal
77920818d9 icon tweak 2020-03-12 13:19:49 +01:00
David Sehnal
0682d54ee2 ActionMenu.Item.disabled 2020-03-12 13:17:11 +01:00
David Sehnal
fbcc3b2fa2 Measurement UI, updated "more options" icon in MappedParam 2020-03-12 12:46:26 +01:00
David Sehnal
c3f47b2ecb mol-plugin-state: component representation update 2020-03-12 12:16:34 +01:00
David Sehnal
8b9f59ac5a mol-plugin: component/selection managers/UI 2020-03-12 12:01:31 +01:00
David Sehnal
362dcabe5c PD.Color.isExpanded property 2020-03-12 07:49:33 +01:00
Alexander Rose
6e205661bd tweak 2020-03-11 23:02:52 -07:00
Alexander Rose
c1a8627702 fix BoundaryHelper edge cases & naming tweaks 2020-03-11 23:00:25 -07:00
Alexander Rose
2c5253943c lint and test fixes 2020-03-11 18:22:16 -07:00
Alexander Rose
03668216fa use EPOS-based boundary-helper throughout 2020-03-11 17:56:04 -07:00
Alexander Rose
37ef234803 wip, improved bounding sphere calculation
- Sphere3D.Hierarchy (one level)
- use hierarchy when merging spheres
- split sphere into two when data unevenly spread
2020-03-11 16:58:21 -07:00
David Sehnal
d25aa97fca ui tweaks 2020-03-11 23:29:36 +01:00
David Sehnal
17dc973305 mol-plugin-state: update label/desc for in custom props transform 2020-03-11 22:08:42 +01:00
David Sehnal
eed4e4a134 tweak 2020-03-11 21:03:21 +01:00
David Sehnal
5fd28c6cad mol-plugin-state: do not update interaction params if they didnt change 2020-03-11 21:00:50 +01:00
David Sehnal
0f69ea197d fix custom property transforms, isBusy behavior, other tweaks 2020-03-11 20:46:57 +01:00
David Sehnal
e1a214e1a8 fix component merging 2020-03-11 18:55:51 +01:00
David Sehnal
e7e14750cb Merge branch 'master' of https://github.com/molstar/molstar 2020-03-11 18:49:46 +01:00
David Sehnal
cb83013967 component ui tweak 2020-03-11 18:49:33 +01:00
Alexander Rose
0a84e1bb7b wip, bounding sphere of spheres calculation improvements 2020-03-11 10:22:51 -07:00
David Sehnal
aee7f4988a removed overpaint and repr helpers 2020-03-11 18:18:42 +01:00
David Sehnal
e762c402fa mol-plugin: component manager options 2020-03-11 18:17:06 +01:00
David Sehnal
4375cae70d structure builder tweaks 2020-03-11 17:26:12 +01:00
David Sehnal
90268a9041 Bundle.fromSubStructure 2020-03-11 16:46:52 +01:00
David Sehnal
a3ebc4df45 mol-plugin: modify component manager/ui 2020-03-11 16:42:59 +01:00
David Sehnal
b2743c76e0 wip mol-plugin managers 2020-03-11 12:58:53 +01:00
Alexander Rose
969a70d571 wip, use EPOS for boundary calculation 2020-03-10 18:50:29 -07:00
Alexander Rose
e6a538dbd7 Merge branch 'master' of https://github.com/molstar/molstar 2020-03-10 17:38:18 -07:00
Alexander Rose
9cffce55c9 added EPOS for bounding sphere calculation 2020-03-10 17:37:57 -07:00
David Sehnal
7bc91d7e99 mol-plugin-state: StructureHierarchy fix 2020-03-10 22:50:41 +01:00
David Sehnal
943f5feb59 mol-plugin-state: TrajectoryFormatProvider 2020-03-10 22:12:41 +01:00
David Sehnal
dc72dbbc97 mol-plugin: PluginContext refactoring 2020-03-10 20:16:41 +01:00
David Sehnal
1513a1e2d2 mol-plugin: code cleanup and refactoring 2020-03-10 19:41:56 +01:00
David Sehnal
82989cae57 mol-plugin-ui: Selection/measurement UI updates 2020-03-10 18:27:20 +01:00
David Sehnal
74f8a5053e refactored StructureSelectionManager 2020-03-10 17:43:32 +01:00
David Sehnal
79f7ea209a wip StructureSelectionManager 2020-03-10 17:14:00 +01:00
David Sehnal
ba65e35c51 refactoring 2020-03-10 15:24:27 +01:00
David Sehnal
5bc4e3ce3b css tweaks 2020-03-10 15:13:43 +01:00
David Sehnal
1c7ac60c11 mol-plugin: state.isBusy behavior 2020-03-10 15:01:24 +01:00
David Sehnal
00cd54b69c mol-state: nested transactions 2020-03-10 14:53:05 +01:00
David Sehnal
90e3a3f0c7 ActionMenu tweak 2020-03-10 13:27:27 +01:00
David Sehnal
5eef3fc42a mol-plugin: Structure components UI 2020-03-10 13:10:47 +01:00
David Sehnal
83a8474731 mol-state: accept partial params for transforms; refactored measurements 2020-03-10 12:15:42 +01:00
Alexander Rose
a5e13c5152 wip, measurements controls improvements 2020-03-09 19:03:15 -07:00
Alexander Rose
b19f53d380 added distanceLabel, angleLabel, dihedralLabel 2020-03-09 19:02:30 -07:00
Alexander Rose
abadef1d2e moved FiniteArray to type helpers 2020-03-09 19:01:17 -07:00
Alexander Rose
a3d976c5b8 consistency fix, Vec3.dihedralAngle now returns radians 2020-03-09 19:00:56 -07:00
Alexander Rose
414b20f06d added Sphere3D.fromSphere3Ds and Loci.getBundleBoundingSphere 2020-03-09 19:00:07 -07:00
David Sehnal
d03a442b6c StructureHierarchyManager tweak 2020-03-09 18:46:00 +01:00
David Sehnal
e5acce03e5 mol-plugin-ui: StructureComponentControls 2020-03-09 18:42:27 +01:00
David Sehnal
fe714d4515 wip: StructureHierarchyManager 2020-03-09 17:27:59 +01:00
David Sehnal
7959344bca Current Interaction -> Focus, Fix StructureSelectionFromBundle 2020-03-08 17:12:40 +01:00
David Sehnal
b9582f171d rename 2020-03-08 15:41:03 +01:00
David Sehnal
410123d933 plugin/state: helpers & fixes 2020-03-08 15:34:15 +01:00
David Sehnal
ae484443d8 decorator transforms 2020-03-08 14:40:23 +01:00
David Sehnal
9d97e56f03 mol-state: StateObjectSelector.update 2020-03-08 13:39:18 +01:00
David Sehnal
01269ec1ef mol-state: use produce in "old params" update 2020-03-08 13:28:34 +01:00
David Sehnal
a204264bcc label fix 2020-03-07 15:53:06 +01:00
David Sehnal
eb0a048926 mol-plugin-ui: strongly typed icons & icons preview HTML 2020-03-07 14:43:57 +01:00
Alexander Rose
ba1509b37a wip, measurements ui 2020-03-06 18:02:47 -08:00
Alexander Rose
ad379e7a32 improved Interactions params 2020-03-06 16:12:46 -08:00
Alexander Rose
9d45beea3b ui: add option to cycle through select options on click 2020-03-06 16:12:16 -08:00
Alexander Rose
b2d134aeb4 added ObjectKeys type helper function 2020-03-06 15:07:20 -08:00
Alexander Rose
d500b8ea19 Merge branch 'master' of https://github.com/molstar/molstar 2020-03-06 13:07:24 -08:00
Alexander Rose
8b3df4b373 plugin-state: preset improvements 2020-03-06 13:07:04 -08:00
David Sehnal
f01fc7c8ba mol-state: log error in transaction 2020-03-06 20:35:57 +01:00
David Sehnal
0e6da0bffa Merge branch 'master' of https://github.com/molstar/molstar 2020-03-06 19:10:58 +01:00
David Sehnal
eab8b1c2bf mol-plugin-state: fix in repr presets 2020-03-06 18:46:41 +01:00
Alexander Rose
8b42a0fede Merge branch 'master' of https://github.com/molstar/molstar 2020-03-06 08:49:13 -08:00
David Sehnal
4bbe078230 custom property reference counting 2020-03-06 17:03:19 +01:00
David Sehnal
aabb931d27 wip Custom Property references 2020-03-06 16:53:24 +01:00
David Sehnal
b1c1b21975 mol-plugin-state: representation components/presets 2020-03-06 14:57:31 +01:00
David Sehnal
7b5dc3ef96 PD.ValuesFor 2020-03-06 14:12:33 +01:00
David Sehnal
1f831f90e0 mol-plugin-state: StructureBuilder 2020-03-06 13:54:14 +01:00
Alexander Rose
ef2c1b51e9 tweaked geometry param info categories 2020-03-05 16:40:19 -08:00
David Sehnal
ace73c041b fix CustomElementProperty color theme 2020-03-05 10:44:55 +01:00
David Sehnal
3c70fe5303 support hiding remote state 2020-03-05 10:03:51 +01:00
Alexander Rose
137e23c025 wip, interactions options for representation panel 2020-03-04 18:18:56 -08:00
Alexander Rose
969a19d515 added defaultParams to CustomProperty.Provider 2020-03-04 18:18:05 -08:00
Alexander Rose
7536abe96c workaround for buggy gl_FrontFacing
- e.g. on some integrated Intel GPUs
2020-03-04 16:27:11 -08:00
Alexander Rose
8e20e163f9 Merge branch 'master' of https://github.com/molstar/molstar 2020-03-04 15:09:16 -08:00
Alexander Rose
adbe8e1f67 take parent structure into account for surface calculations
- new option `includeParent`
2020-03-04 15:08:46 -08:00
David Sehnal
5db134f34f mol-plugin-state: StructureComponent 2020-03-04 19:20:52 +01:00
David Sehnal
80cf7c1dd2 wip state builders 2020-03-04 15:01:46 +01:00
David Sehnal
9e5cc184ed State transactions, better error message for failed downloads 2020-03-04 13:44:38 +01:00
David Sehnal
a5185b456c mol-plugin-state: DataBuilder 2020-03-04 12:56:17 +01:00
Alexander Rose
0615198ad2 0.5.6 2020-03-03 15:13:50 -08:00
Alexander Rose
6cd422f5b3 package updates 2020-03-03 15:13:16 -08:00
Alexander Rose
4416178d6f fix error handling in readData 2020-03-03 14:52:11 -08:00
David Sehnal
b8cef99dc1 ParameterControls fix 2020-03-03 23:04:56 +01:00
David Sehnal
4dcb68af33 ParamDefinition category and hideIf support 2020-03-03 22:45:20 +01:00
David Sehnal
b4c70ab14a fix camera reset when loading stored state 2020-03-03 17:29:51 +01:00
David Sehnal
8436e17af9 removed PD.categories, added PD.isEssential & UI support 2020-03-03 16:05:56 +01:00
David Sehnal
bda04cbdc7 ParamDefinition categories (wip) 2020-03-03 15:27:10 +01:00
David Sehnal
7287947a55 added mol-plugin-state, refactored PluginCommand 2020-03-03 13:46:34 +01:00
David Sehnal
fb5eb1e19c Merge branch 'master' into plugin 2020-03-03 13:11:51 +01:00
David Sehnal
d735dcdc3e mol-plugin-ui: ActionMenu helpers 2020-03-03 13:09:51 +01:00
Alexander Rose
83d8a61400 0.5.5 2020-03-02 17:22:34 -08:00
Alexander Rose
b72f57c040 assembly symmetry tweaks 2020-03-02 17:21:07 -08:00
Alexander Rose
8a7ef1c704 added StructureOverpaintHelper.setFromExpression and alpha prop 2020-03-02 16:28:10 -08:00
Alexander Rose
8731bc13d1 StructureElement.Loci helpers
- firstElement
- firstResidue
- firstChain
2020-03-02 16:27:37 -08:00
Alexander Rose
d103cda0c8 StructureSelectionQuery improvements
- added categories
- StructureSelectionQueryList with standard residues
2020-03-02 14:04:27 -08:00
Alexander Rose
ca4e864e46 StructureRepresentationHelper.getRepresentationParams tweaks 2020-03-02 13:02:27 -08:00
Alexander Rose
0e25950d51 don't remove C! assembly symmetry 2020-03-02 13:01:35 -08:00
David Sehnal
2c29a90b5e fix 2020-03-02 15:32:24 +01:00
David Sehnal
2900836208 mol-canvas3d: requestCameraReset options 2020-03-02 15:28:20 +01:00
Alexander Rose
928a1df525 handle nullish values in SelectControl 2020-02-29 22:09:13 -08:00
Alexander Rose
16e0dff551 molecule types improvements 2020-02-29 22:08:29 -08:00
David Sehnal
7e443d5c9b mol-plugin-ui: simplified ActionMenu, fixed residue/amk selection 2020-02-29 18:15:39 +01:00
David Sehnal
172ae17966 mol-plugin-ui: SelectControl label fix 2020-02-29 15:40:28 +01:00
David Sehnal
8cbf7b5d0a mol-plugin-ui: Controls improvements 2020-02-29 15:27:21 +01:00
Alexander Rose
2c40b85880 0.5.4 2020-02-28 18:29:15 -08:00
Alexander Rose
ad388f23ae package updates 2020-02-28 18:28:39 -08:00
Alexander Rose
27b559a2d8 tweaked color-theme categories 2020-02-28 18:08:33 -08:00
Alexander Rose
c6d19e14c5 improved naming of PDBe and RCSB PDB provided properties 2020-02-28 17:46:10 -08:00
Alexander Rose
b807dca2d8 wip, StructureRepresentationHelper tweaks 2020-02-28 17:13:00 -08:00
Alexander Rose
2cae6e3f59 pass correct themeDataCtx in StructureRepresentation3DHelpers.createParams 2020-02-28 17:12:09 -08:00
Alexander Rose
69c73f3dcd StructureSelectionQuery improvements
- delayed query compilation to work with CustomPropSymbol
- optional async ensureCustomProperties method
- added hasClash, isBuried, isAccessible built-ins
- integrate .ensureCustomProperties with StructureSelectionHelper
2020-02-28 17:11:06 -08:00
Alexander Rose
4456ab2cd5 whitespace 2020-02-28 17:06:13 -08:00
Alexander Rose
bdda18de23 added mol-script symbol to ValidationReport 2020-02-28 17:05:22 -08:00
Alexander Rose
1b2c2f3d41 added Tag enum with common strings to AssemblySymmetry 2020-02-28 17:04:55 -08:00
Alexander Rose
fd19d29ef6 accessible surface area improvements
- added mol-script symbols
- helpers to get normalized value and flag
2020-02-28 17:04:03 -08:00
David Sehnal
1f0c0fd756 mol-geo: VisualQuality label fix 2020-02-27 16:56:28 +01:00
David Sehnal
83698cc52d mol-plugin-ui: ActionMenu fixes 2020-02-27 16:53:11 +01:00
David Sehnal
70b94deb20 tweak 2020-02-27 16:19:46 +01:00
David Sehnal
2da3df6e4d ParamDefinition.Select grouping & used in theme definitions 2020-02-27 16:17:23 +01:00
David Sehnal
509e633a69 mol-plugin-ui: use ActionMenu in SelectControl 2020-02-27 15:09:47 +01:00
David Sehnal
17fac2b82a mol-plugin-ui: ActionMenu refactoring 2020-02-27 14:36:48 +01:00
Alexander Rose
c543c4e10a 0.5.3 2020-02-26 17:20:24 -08:00
Alexander Rose
10073800dc added amino acids and nucleic bases queries 2020-02-26 17:14:40 -08:00
Alexander Rose
04c38250b4 tweaked action-menu offset 2020-02-26 17:14:08 -08:00
Alexander Rose
5ccb329af1 added SetUtils.toArray 2020-02-26 17:13:34 -08:00
Alexander Rose
3cecb53bc5 added model.properties.structAsymMap 2020-02-26 15:04:48 -08:00
Alexander Rose
0daf431d68 added and use cross-link loci/location 2020-02-26 14:23:51 -08:00
Alexander Rose
3e0c4242ad simplified interactions loci/location 2020-02-26 14:23:03 -08:00
Alexander Rose
17b775c377 areDataLociEqual, use shallowEqual to compare data objects 2020-02-26 14:22:05 -08:00
Alexander Rose
4525b98288 SecondaryStructure improvements
- use SecondaryStructureProvider in StructureProperties
- renamed mmCIF source to model
2020-02-26 11:43:15 -08:00
Alexander Rose
755699d479 fix structure/model props attachment 2020-02-26 11:37:57 -08:00
Alexander Rose
a84309b800 add mon_nstd_flag when deriving chemComp 2020-02-26 10:37:36 -08:00
Alexander Rose
16863535b8 cleanup, removed comment 2020-02-26 10:36:37 -08:00
Alexander Rose
dd9773d72e fix pdb parser: need cif-category not table 2020-02-26 10:36:12 -08:00
Alexander Rose
ec45f6c0ee removed 'modified residues'
- use non-standard flag in polymers residues instead to show interesting residues
- 'modified residues' is of limited value to get parent, better rely on chem_comp.type
2020-02-26 09:51:54 -08:00
David Sehnal
59235630bb mol-plugin-ui: ActionMenu, use in selection manager to test 2020-02-26 18:43:56 +01:00
David Sehnal
11ed0ca89b added draft of ParamMapping interface and control 2020-02-26 16:39:24 +01:00
Alexander Rose
188ea6e8e2 skin: fix select button hidden issue in FF 2020-02-25 22:06:52 -08:00
Alexander Rose
293b464d9f moved cross-link-restraint to props 2020-02-25 17:40:08 -08:00
Alexander Rose
0e91aa521e added IntervalControl, use 'step' for precision, allow 'range' in Vec3 2020-02-25 17:39:34 -08:00
Alexander Rose
5272593cc3 ermoved deprecated StructureAssemblyFromModel 2020-02-25 15:10:12 -08:00
Alexander Rose
c5f336b0e4 fix Assembly Symmetry Cluster coloring for deposited model 2020-02-25 14:53:37 -08:00
Alexander Rose
b1a6fa3ffc package updates, remove tslint related package 2020-02-25 14:52:55 -08:00
Alexander Rose
fe47134934 0.5.2 2020-02-25 12:00:59 -08:00
Alexander Rose
131cc606f0 added support to build custom assembly from symmetry operations and asym ids 2020-02-25 11:57:58 -08:00
Alexander Rose
3681f01fad added Spacegroup.getOperatorXyz 2020-02-25 11:56:48 -08:00
Alexander Rose
e966c112ab assymbly-symmetry: filter C1, export AssemblySymmetry3D 2020-02-24 17:25:49 -08:00
David Sehnal
d7b232b00b Merge branch 'master' into plugin 2020-02-24 10:12:35 +01:00
Alexander Rose
7986509ad3 0.5.1 2020-02-21 16:54:42 -08:00
Alexander Rose
73dcf970f3 fix fog handling so fog can be fully switched off 2020-02-21 16:26:14 -08:00
Alexander Rose
9377aa2d05 renamed renderstyle 'toon' to 'flat'
- reflects what the options is actually doing
2020-02-21 16:05:35 -08:00
Alexander Rose
686fa5a5ed package updates 2020-02-21 16:05:01 -08:00
Alexander Rose
c946ae6eab updated schemas, emmit .ts instead of .d.ts 2020-02-21 16:01:41 -08:00
David Sehnal
9b2f1d9415 updated to TypeScript 3.8 2020-02-21 17:13:10 +01:00
Alexander Rose
f6c28aa8e2 0.5.0 2020-02-20 16:25:38 -08:00
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
David Sehnal
2c327cfdf6 vscode tasks 2020-02-12 12:06:52 +01:00
David Sehnal
307f2efc97 Merge branch 'master' into plugin 2020-02-12 12:02:51 +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
64c51f0d94 Merge branch 'master' into plugin 2020-02-10 11:51:29 +01: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
David Sehnal
7a0b4c4d23 Viewer: load from URL 2019-12-24 11:37:43 +01:00
David Sehnal
f45edbc4f0 mol-theme: truncate too long entry names 2019-12-24 11:27:47 +01:00
David Sehnal
65d3355b18 mol-plugin: DataManager [wip] 2019-12-23 17:19:38 +01: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
827 changed files with 55013 additions and 23627 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,8 +4,8 @@
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"dbaeumer.vscode-eslint",
"firsttris.vscode-jest-runner",
"ms-vscode.vscode-typescript-tslint-plugin",
"msjsdiag.debugger-for-chrome",
"slevesque.shader",
"stpn.vscode-graphql",

View File

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

14
.vscode/tasks.json vendored
View File

@@ -9,6 +9,20 @@
"problemMatcher": [
"$tsc"
]
},
{
"type": "npm",
"script": "build-tsc",
"problemMatcher": [
"$tsc"
]
},
{
"type": "npm",
"script": "watch",
"problemMatcher": [
"$tsc"
]
}
]
}

View File

@@ -31,12 +31,15 @@ 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-state` State transformations, builders, and managers.
- `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).
@@ -59,9 +62,13 @@ This project builds on experience from previous solutions:
### Build automatically on file save:
npm run watch
If working on just the viewer, ``npm run watch-viewer`` will provide shorter compile times.
### 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 +94,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**

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.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)
}
];
};

View File

@@ -6,133 +6,64 @@ Model Server is a tool for preprocessing and querying macromolecular structure d
Installing and Running
=====================
Getting the code (use node 8+):
Requires nodejs 8+.
## From GitHub
```
git clone https://github.com/molstar/molstar
npm install
```
Customize configuration at ``src/server/model/config.ts`` to point to your data and which custom properties to include (see the [Custom Properties](#custom-properties) section). Alternatively, the config can be edited in the compiled version in ``build/node_modules/servers/model/config.js``.
Afterwards, build the project:
Afterwards, build the project source:
```
npm run build
npm run build-tsc
```
(or run watch mode for automatic rebuilds: ``npm run watch``)
and run the server by
Running the server locally for testing:
```
npm run model-server
```
or
```
node build/node_modules/servers/model/server
node lib/servers/model/server/server
```
In production it is a good idea to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
## From NPM
```
npm install --production molstar
./model-server
```
(or ``node node_modules\.bin\model-server`` in Windows).
The NPM package contains all the tools mentioned here as "binaries":
- ``model-server``
- ``model-server-query``
- ``model-server-preprocess``
## Memory issues
### Production use
In production it is required to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
### Memory issues
Sometimes nodejs might run into problems with memory. This is usually resolved by adding the ``--max-old-space-size=8192`` parameter.
Preprocessor
============
## Preprocessor
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. See the [Custom Properties](#custom-properties) section for providing custom properties.
The preprocessor application allows to add custom data to CIF files and/or convert CIF to BinaryCIF. ``node lib/servers/model/preprocess`` or ``model-server-preprocess`` binary from the NPM package.
## Usage
The app works in two modes: single files and folders.
## Local Mode
Single files:
```
node build\node_modules\servers\model\preprocess -i input.cif [-oc output.cif] [-ob output.bcif] [--cfg config.json]
```
Folder:
```
node build\node_modules\servers\model\preprocess -fin input_folder [-foc output_cif_folder] [-fob output_bcif_folder] [--cfg config.json]
```
## Config
The config speficies the maximum number of processes to use (in case of folder processing) and defines sources and parameters for custom properties.
Example:
```json
{
"numProcesses": 4,
"customProperties": {
"sources": [
"./properties/pdbe"
],
"params": {
"PDBe": {
"UseFileSource": false,
"API": {
"residuewise_outlier_summary": "https://www.ebi.ac.uk/pdbe/api/validation/residuewise_outlier_summary/entry",
"preferred_assembly": "https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary",
"struct_ref_domain": "https://www.ebi.ac.uk/pdbe/api/mappings/sequence_domains"
}
}
}
}
}
```
The server can be run in local/file based mode using ``node lib/servers/model/query`` (``model-server-query`` binary from the NPM package).
Custom Properties
=================
It is possible to provide property descriptors that transform data to internal representation and define how it should be exported into one or mode CIF categories. Examples of this are located in the ``mol-model-props`` module and are linked to the server in the config and ``servers/model/properties``.
This feature is still in development.
Local Mode
==========
The server can be run in local/file based mode:
```
node build/node_modules/servers/model/server jobs.json
```
where ``jobs.json`` is an array of
```ts
type LocalInput = {
input: string,
output: string,
query: QueryName,
modelNums?: number[],
params?: any,
binary?: boolean
}[]
```
For example
```json
[
{
"input": "c:/test/quick/1tqn.cif",
"output": "c:/test/quick/localapi/1tqn_full.cif",
"query": "full"
},
{
"input": "c:/test/quick/1tqn.cif",
"output": "c:/test/quick/localapi/1tqn_full.bcif",
"query": "full",
"params": {}
},
{
"input": "c:/test/quick/1cbs_updated.cif",
"output": "c:/test/quick/localapi/1cbs_ligint.cif",
"query": "residueInteraction",
"params": {
"atom_site": { "label_comp_id": "REA" }
}
}
]
```
It is possible to provide property descriptors that transform data to internal representation and define how it should be exported into one or mode CIF categories. Examples of this are located in the ``mol-model-props`` module and are linked to the server in the config and ``servers/model/properties``.

View File

@@ -7,107 +7,64 @@ It uses the text based CIF and BinaryCIF formats to deliver the data to the clie
For quick info about the benefits of using the server, check out the [examples](examples.md).
Installing the Server
Installing and Running
=====================
- Install [Node.js](https://nodejs.org/en/) (tested on Node 6.* and 7.*; x64 version is strongly preferred).
- Get the code.
- Prepare the data.
- Run the server.
Requires nodejs 8+.
Preparing the Data
------------------
## From GitHub
```
git clone https://github.com/molstar/molstar
npm install
```
Afterwards, build the project source:
```
npm run build-tsc
```
and run the server by
```
node lib/servers/volume/server
```
## From NPM
```
npm install --production molstar
./volume-server
```
(or ``node node_modules\.bin\volume-server`` in Windows).
The NPM package contains all the tools mentioned here as "binaries":
- ``volume-server``
- ``volume-server-pack``
- ``volume-server-query``
### Production use
In production it is required to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
### Memory issues
Sometimes nodejs might run into problems with memory. This is usually resolved by adding the ``--max-old-space-size=8192`` parameter.
## Preparing the Data
For the server to work, CCP4/MAP (models 0, 1, 2 are supported) input data need to be converted into a custom block format.
To achieve this, use the ``pack`` application.
To achieve this, use the ``pack`` application (``node lib/servers/volume/pack`` or ``volume-server-pack`` binary from the NPM package).
- To prepare data from x-ray based methods, use:
## Local Mode
```
node pack -xray main.ccp4 diff.ccp4 out.mdb
```
- For EM data, use:
```
node pack -em em.map out.mdb
```
Running the Server
------------------
- Install production dependencies:
```
npm install --only=production
```
- Update ``server-config.js`` to link to your data and optionally tweak the other parameters.
- Run it:
```
node server
```
In production it is a good idea to use a service that will keep the server running, such as [forever.js](https://github.com/foreverjs/forever).
### Local Mode
The program ``local`` in the build folder can be used to query the data without running a http server.
- ``node local`` prints the program usage.
- ``node local jobs.json`` takes a list of jobs to execute in JSON format. A job entry is defined by this interface:
```TypeScript
interface JobEntry {
source: {
filename: string,
name: string,
id: string
},
query: {
kind: 'box' | 'cell',
space?: 'fractional' | 'cartesian',
bottomLeft?: number[],
topRight?: number[],
}
params: {
/** Determines the detail level as specified in server-config */
detail?: number,
/**
* Determines the sampling level:
* 1: Original data
* 2: Downsampled by factor 1/2
* ...
* N: downsampled 1/2^(N-1)
*/
forcedSamplingLevel?: number,
asBinary: boolean,
},
outputFolder: string
}
```
Example ``jobs.json`` file content:
```TypeScript
[{
source: {
filename: `g:/test/mdb/emd-8116.mdb`,
name: 'em',
id: '8116',
},
query: {
kind: 'cell'
},
params: {
detail: 4,
asBinary: true
},
outputFolder: 'g:/test/local-test'
}]
```
The program ``lib/servers/volume/pack`` (``volume-server-query`` in NPM package) can be used to query the data without running a http server.
## Navigating the Source Code
@@ -122,8 +79,8 @@ The source code is split into 2 mains parts: ``pack`` and ``server``:
Consuming the Data
==================
The data can be consumed in any (modern) browser using the [CIFTools.js library](https://github.com/dsehnal/CIFTools.js) (or any other piece of code that can read text or binary CIF).
The data can be consumed in any (modern) browser using the [ciftools library](https://github.com/molstar/ciftools) (or any other piece of code that can read text or binary CIF).
The [Data Format](DataFormat.md) document gives a detailed description of the server response format.
As a reference/example of the server usage, please see the implementation in [LiteMol](https://github.com/dsehnal/LiteMol) ([CIF.ts + Data.ts](https://github.com/dsehnal/LiteMol/tree/master/src/lib/Core/Formats/Density), [UI](https://github.com/dsehnal/LiteMol/tree/master/src/Viewer/Extensions/DensityStreaming)) or in Mol*.
As a reference/example of the server usage is available in Mol* ``mol-plugin`` module.

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

16438
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "0.3.2",
"version": "0.6.0-dev.4",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -11,20 +11,23 @@
"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-tsc": "tsc --incremental",
"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": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack\"",
"watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"",
"watch-tsc": "tsc --watch --incremental",
"watch-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html,ico}\" lib/ --watch",
"watch-webpack": "webpack -w --mode development --display minimal",
"watch-webpack": "webpack -w --mode development --display errors-only --info-verbosity verbose",
"watch-webpack-viewer": "webpack -w --mode development --display errors-only --info-verbosity verbose --config ./webpack.config.viewer.js",
"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-test": "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"
@@ -32,6 +35,14 @@
"files": [
"lib/"
],
"bin": {
"model-server": "lib/servers/model/server.js",
"model-server-query": "lib/servers/model/local.js",
"model-server-preprocess": "lib/servers/model/preprocess.js",
"volume-server": "lib/servers/volume/server.js",
"volume-server-query": "lib/servers/volume/query.js",
"volume-server-pack": "lib/servers/volume/pack.js"
},
"nodemonConfig": {
"ignoreRoot": [
"./node_modules",
@@ -63,56 +74,67 @@
],
"license": "MIT",
"devDependencies": {
"@graphql-codegen/add": "^1.13.1",
"@graphql-codegen/cli": "^1.13.1",
"@graphql-codegen/time": "^1.13.1",
"@graphql-codegen/typescript": "^1.13.1",
"@graphql-codegen/typescript-graphql-files-modules": "^1.13.1",
"@graphql-codegen/typescript-graphql-request": "^1.13.1",
"@graphql-codegen/typescript-operations": "^1.13.1",
"@types/cors": "^2.8.6",
"@typescript-eslint/eslint-plugin": "^2.24.0",
"@typescript-eslint/parser": "^2.24.0",
"benchmark": "^2.1.4",
"circular-dependency-plugin": "^5.2.0",
"concurrently": "^5.0.0",
"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": "^6.0.0",
"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.1.0",
"tslint": "^5.20.0",
"typescript": "^3.6.4",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9"
"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.132.0",
"style-loader": "^1.1.3",
"ts-jest": "^25.2.1",
"typescript": "^3.8.3",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
},
"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.12",
"@types/node-fetch": "^2.5.2",
"@types/react": "^16.9.5",
"@types/react-dom": "^16.9.1",
"@types/swagger-ui-dist": "3.0.3",
"@types/webgl2": "0.0.5",
"@types/compression": "1.7.0",
"@types/express": "^4.17.3",
"@types/jest": "^25.1.4",
"@types/node": "^13.9.2",
"@types/node-fetch": "^2.5.5",
"@types/react": "^16.9.23",
"@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.8",
"graphql": "^14.6.0",
"immer": "^6.0.2",
"immutable": "^3.8.2",
"node-fetch": "^2.6.0",
"react": "^16.10.2",
"react-dom": "^16.10.2",
"rxjs": "^6.5.3",
"swagger-ui-dist": "^3.23.11",
"util.promisify": "^1.0.0",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"rxjs": "^6.5.4",
"swagger-ui-dist": "^3.25.0",
"tslib": "^1.11.1",
"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 {

View File

@@ -6,13 +6,13 @@
import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
import { PluginContext } from '../../mol-plugin/context';
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
import { StateTransforms } from '../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
import { PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { StateBuilder } from '../../mol-state';
import Expression from '../../mol-script/language/expression';
import { BuiltInColorThemeName } from '../../mol-theme/color';
import { ColorTheme } from '../../mol-theme/color';
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
type SupportedFormats = 'cif' | 'pdb'
export namespace StateHelper {
@@ -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) {
@@ -67,27 +67,30 @@ export namespace StateHelper {
}
export function assemble(b: StateBuilder.To<PSO.Molecule.Model>, id?: string) {
return b.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: id || 'deposited' }, { tags: 'asm' })
const props = {
type: {
name: 'assembly' as const,
params: { id: id || 'deposited' }
}
}
return b.apply(StateTransforms.Model.StructureFromModel, props, { tags: 'asm' })
}
export function visual(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'cartoon'), { tags: 'seq-visual' });
createStructureRepresentationParams(ctx, void 0, { type: 'cartoon' }), { tags: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick'), { tags: 'het-visual' });
// visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
// .apply(StateTransforms.Representation.StructureRepresentation3D,
// StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', { alpha: 0.51 }), { tags: 'water-visual' });
createStructureRepresentationParams(ctx, void 0, { type: 'ball-and-stick' }), { tags: 'het-visual' });
return visualRoot;
}
export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression, coloring?: BuiltInColorThemeName) {
export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression, color?: ColorTheme.BuiltIn) {
visualRoot
.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'ball-and-stick', void 0, coloring), { tags: 'het-visual' });
createStructureRepresentationParams(ctx, void 0, { type: 'ball-and-stick', color }), { tags: 'het-visual' });
return visualRoot;
}

View File

@@ -105,6 +105,10 @@
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());

View File

@@ -7,19 +7,21 @@
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
import './index.html'
import { PluginContext } from '../../mol-plugin/context';
import { PluginCommands } from '../../mol-plugin/command';
import { StateTransforms } from '../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
import { PluginCommands } from '../../mol-plugin/commands';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { Color } from '../../mol-util/color';
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
import { AnimateModelIndex } from '../../mol-plugin/state/animation/built-in';
import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin-state/objects';
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in';
import { StateBuilder, StateTransform } from '../../mol-state';
import { StripedResidues } from './coloring';
// import { BasicWrapperControls } from './controls';
import { StaticSuperpositionTestData, buildStaticSuperposition, dynamicSuperpositionTest } from './superposition';
import { PDBeStructureQualityReport } from '../../mol-plugin/behavior/dynamic/custom-props';
import { CustomToastMessage } from './controls';
require('mol-plugin/skin/light.scss')
import { EmptyLoci } from '../../mol-model/loci';
import { StructureSelection } from '../../mol-model/structure';
import { Script } from '../../mol-script/script';
import { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
require('mol-plugin-ui/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb'
type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
@@ -39,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.representation.structure.themes.colorThemeRegistry.add(StripedResidues.colorThemeProvider!);
this.plugin.managers.lociLabels.addProvider(StripedResidues.labelProvider!);
this.plugin.customModelProperties.register(StripedResidues.propertyProvider, true);
}
private download(b: StateBuilder.To<PSO.Root>, url: string) {
@@ -56,25 +61,31 @@ class BasicWrapper {
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
const props = {
type: {
name: 'assembly' as const,
params: { id: assemblyId || 'deposited' }
}
}
return parsed
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
.apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.Descriptor.name] }, { ref: 'props', state: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
.apply(StateTransforms.Model.CustomModelProperties, { autoAttach: [StripedResidues.propertyProvider.descriptor.name], properties: {} }, { ref: 'props', state: { isGhost: false } })
.apply(StateTransforms.Model.StructureFromModel, props, { 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' });
createStructureRepresentationParams(this.plugin, void 0, { type: 'cartoon' }), { ref: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'), { ref: 'het-visual' });
createStructureRepresentationParams(this.plugin, void 0, { type: 'ball-and-stick' }), { ref: 'het-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick', { alpha: 0.51 }), { ref: 'water-visual' });
createStructureRepresentationParams(this.plugin, void 0, { type: 'ball-and-stick', typeParams: { alpha: 0.51 } }), { ref: 'water-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill'), { ref: 'ihm-visual' });
createStructureRepresentationParams(this.plugin, void 0, { type: 'spacefill' }), { ref: 'ihm-visual' });
return visualRoot;
}
@@ -82,7 +93,7 @@ class BasicWrapper {
async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.dataState;
const state = this.plugin.state.data;
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
loadType = 'full';
@@ -92,29 +103,38 @@ class BasicWrapper {
let tree: StateBuilder.Root;
if (loadType === 'full') {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
await PluginCommands.State.RemoveObject(this.plugin, { state, ref: state.tree.root.ref });
tree = state.build();
this.visual(this.parse(this.download(tree.toRoot(), url), format, assemblyId));
} else {
const props = {
type: {
name: 'assembly' as const,
params: { id: assemblyId || 'deposited' }
}
}
tree = state.build();
tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
tree.to('asm').update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
await PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
this.loadedParams = { url, format, assemblyId };
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
PluginCommands.Camera.Reset(this.plugin, { });
}
setBackground(color: number) {
const renderer = this.plugin.canvas3d.props.renderer;
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
const renderer = this.plugin.canvas3d!.props.renderer;
PluginCommands.Canvas3D.SetSettings(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 } } });
if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
if (!spinning) PluginCommands.Camera.Reset(this.plugin, { });
}
animate = {
@@ -130,52 +150,68 @@ class BasicWrapper {
coloring = {
applyStripes: async () => {
const state = this.plugin.state.dataState;
const state = this.plugin.state.data;
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.representation.structure.themes.colorThemeRegistry.get(StripedResidues.propertyProvider.descriptor.name).defaultValues };
for (const v of visuals) {
tree.to(v).update(old => ({ ...old, colorTheme }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
await PluginCommands.State.Update(this.plugin, { state, tree });
}
}
interactivity = {
highlightOn: () => {
const seq_id = 7;
const data = (this.plugin.state.data.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.managers.interactivity.lociHighlights.highlightOnly({ loci });
},
clearHighlight: () => {
this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci: EmptyLoci });
}
}
tests = {
staticSuperposition: async () => {
const state = this.plugin.state.dataState;
const state = this.plugin.state.data;
const tree = buildStaticSuperposition(this.plugin, StaticSuperpositionTestData);
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: StateTransform.RootRef });
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
await PluginCommands.State.RemoveObject(this.plugin, { state, ref: StateTransform.RootRef });
await PluginCommands.State.Update(this.plugin, { state, tree });
},
dynamicSuperposition: async () => {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.plugin.state.dataState, ref: StateTransform.RootRef });
await PluginCommands.State.RemoveObject(this.plugin, { state: this.plugin.state.data, ref: StateTransform.RootRef });
await dynamicSuperpositionTest(this.plugin, ['1tqn', '2hhb', '4hhb'], 'HEM');
},
toggleValidationTooltip: async () => {
const state = this.plugin.state.behaviorState;
const state = this.plugin.state.behaviors;
const tree = state.build().to(PDBeStructureQualityReport.id).update(PDBeStructureQualityReport, p => ({ ...p, showTooltip: !p.showTooltip }));
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
await PluginCommands.State.Update(this.plugin, { state, tree });
},
showToasts: () => {
PluginCommands.Toast.Show.dispatch(this.plugin, {
PluginCommands.Toast.Show(this.plugin, {
title: 'Toast 1',
message: 'This is an example text, timeout 3s',
key: 'toast-1',
timeoutMs: 3000
});
PluginCommands.Toast.Show.dispatch(this.plugin, {
PluginCommands.Toast.Show(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' });
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-1' });
PluginCommands.Toast.Hide(this.plugin, { key: 'toast-2' });
}
}
}

View File

@@ -9,9 +9,9 @@
import { PluginContext } from '../../mol-plugin/context';
import { Mat4 } from '../../mol-math/linear-algebra';
import { StateHelper } from './helpers';
import { PluginCommands } from '../../mol-plugin/command';
import { PluginCommands } from '../../mol-plugin/commands';
import { StateSelection, StateBuilder } from '../../mol-state';
import { PluginStateObject as PSO } from '../../mol-plugin/state/objects';
import { PluginStateObject as PSO } from '../../mol-plugin-state/objects';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { compile } from '../../mol-script/runtime/query/compiler';
import { StructureSelection, QueryContext } from '../../mol-model/structure';
@@ -32,7 +32,7 @@ export type SuperpositionTestInput = {
// }
export function buildStaticSuperposition(ctx: PluginContext, src: SuperpositionTestInput) {
const b = ctx.state.dataState.build().toRoot();
const b = ctx.state.data.build().toRoot();
for (const s of src) {
StateHelper.visual(ctx,
StateHelper.transform(
@@ -50,20 +50,20 @@ 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) {
const state = ctx.state.dataState;
const state = ctx.state.data;
const structures = state.build().toRoot();
for (const s of src) {
@@ -71,7 +71,7 @@ export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[]
StateHelper.getModel(StateHelper.download(structures, `https://www.ebi.ac.uk/pdbe/static/entry/${s}_updated.cif`), 'cif'));
}
await PluginCommands.State.Update.dispatch(ctx, { state, tree: structures });
await PluginCommands.State.Update(ctx, { state, tree: structures });
const pivot = MS.struct.filter.first([
MS.struct.generator.atomGroups({
@@ -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();
@@ -99,7 +99,7 @@ export async function dynamicSuperpositionTest(ctx: PluginContext, src: string[]
pivot, rest);
}
await PluginCommands.State.Update.dispatch(ctx, { state, tree: visuals });
await PluginCommands.State.Update(ctx, { state, tree: visuals });
}
function siteVisual(ctx: PluginContext, b: StateBuilder.To<PSO.Molecule.Structure>, pivot: Expression, rest: Expression) {

View File

@@ -144,9 +144,9 @@ async function createBonds() {
const comp_id: string[] = []
const atom_id_1: string[] = []
const atom_id_2: string[] = []
const value_order: string[] = []
const pdbx_aromatic_flag: string[] = []
const pdbx_stereo_config: string[] = []
const value_order: typeof mmCIF_chemCompBond_schema['value_order']['T'][] = []
const pdbx_aromatic_flag: typeof mmCIF_chemCompBond_schema['pdbx_aromatic_flag']['T'][] = []
const pdbx_stereo_config: typeof mmCIF_chemCompBond_schema['pdbx_stereo_config']['T'][] = []
const molstar_protonation_variant: string[] = []
function addBonds(compId: string, ccb: CCB, protonationVariant: boolean) {
@@ -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

@@ -7,13 +7,13 @@
import { createPlugin, DefaultPluginSpec } from '../../../mol-plugin';
import './index.html'
import { PluginContext } from '../../../mol-plugin/context';
import { PluginCommands } from '../../../mol-plugin/command';
import { StateTransforms } from '../../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../../mol-plugin/state/transforms/representation';
import { PluginStateObject as PSO } from '../../../mol-plugin/state/objects';
import { PluginCommands } from '../../../mol-plugin/commands';
import { StateTransforms } from '../../../mol-plugin-state/transforms';
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')
import { createStructureRepresentationParams } from '../../../mol-plugin-state/helpers/structure-representation-params';
require('mol-plugin-ui/skin/light.scss')
type SupportedFormats = 'cif' | 'pdb'
type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
@@ -94,18 +94,18 @@ class LightingDemo {
setPreset(preset: Canvas3DPreset) {
const props = getPreset(preset)
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: {
PluginCommands.Canvas3D.SetSettings(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
},
}});
@@ -120,18 +120,24 @@ class LightingDemo {
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
const props = {
type: {
name: 'assembly' as const,
params: { id: assemblyId || 'deposited' }
}
}
return parsed
.apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
.apply(StateTransforms.Model.StructureFromModel, props, { ref: 'asm' });
}
private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill', {}, 'illustrative'), { ref: 'seq-visual' });
createStructureRepresentationParams(this.plugin, void 0, { type: 'spacefill', color: 'illustrative' }), { ref: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'), { ref: 'het-visual' });
createStructureRepresentationParams(this.plugin, void 0, { type: 'ball-and-stick' }), { ref: 'het-visual' });
return visualRoot;
}
@@ -139,7 +145,7 @@ class LightingDemo {
async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.dataState;
const state = this.plugin.state.data;
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
loadType = 'full';
@@ -149,17 +155,23 @@ class LightingDemo {
let tree: StateBuilder.Root;
if (loadType === 'full') {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
await PluginCommands.State.RemoveObject(this.plugin, { state, ref: state.tree.root.ref });
tree = state.build();
this.visual(this.parse(this.download(tree.toRoot(), url), format, assemblyId));
} else {
const props = {
type: {
name: 'assembly' as const,
params: { id: assemblyId || 'deposited' }
}
}
tree = state.build();
tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
tree.to('asm').update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
await PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
this.loadedParams = { url, format, assemblyId };
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
PluginCommands.Camera.Reset(this.plugin, { });
}
}

View File

@@ -4,7 +4,7 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as _ from '../../mol-plugin/state/transforms'
import * as _ from '../../mol-plugin-state/transforms'
import { StateTransformer, StateObject } from '../../mol-state';
import { StringBuilder } from '../../mol-util';
import * as fs from 'fs';

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] | readonly [string, string, string])[]) {
return options.map(o => `'${o[0]}'`).join(', ');
}

View File

@@ -16,6 +16,8 @@ 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) {
@@ -50,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) {
@@ -65,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;
@@ -86,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])}`);
}
}
}
@@ -119,18 +123,6 @@ export function printSequence(model: Model) {
console.log();
}
export function printModRes(model: Model) {
console.log('\nModified Residues\n=============');
const map = model.properties.modifiedResidues.parentId;
const { label_comp_id, _rowCount } = model.atomicHierarchy.residues;
for (let i = 0; i < _rowCount; i++) {
const comp_id = label_comp_id.value(i);
if (!map.has(comp_id)) continue;
console.log(`[${i}] ${map.get(comp_id)} -> ${comp_id}`);
}
console.log();
}
export function printRings(structure: Structure) {
console.log('\nRings\n=============');
for (const unit of structure.units) {
@@ -148,7 +140,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;
@@ -179,7 +171,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(', ')}`);
@@ -214,9 +207,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.mod) printModRes(models[0]);
if (args.intraBonds) printBonds(structure, true, false);
if (args.interBonds) printBonds(structure, false, true);
if (args.sec) printSecStructure(models[0]);
}
@@ -242,8 +234,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 {
@@ -256,8 +248,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,23 +1,22 @@
/**
* 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 { StateAction } from '../../../../mol-state';
import { PluginContext } from '../../../../mol-plugin/context';
import { PluginStateObject as PSO } from '../../../../mol-plugin/state/objects';
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';
import { Task } from '../../../../mol-task';
import { StructureRepresentation3DHelpers } from '../../../../mol-plugin/state/transforms/representation';
import { StateTransforms } from '../../../../mol-plugin/state/transforms';
import { StateTransforms } from '../../../../mol-plugin-state/transforms';
import { distinctColors } from '../../../../mol-util/color/distinct';
import { ModelIndexColorThemeProvider } from '../../../../mol-theme/color/model-index';
import { Hcl } from '../../../../mol-util/color/spaces/hcl';
@@ -26,13 +25,11 @@ import { MolScriptBuilder as MS } from '../../../../mol-script/language/builder'
import { getMatFromResamplePoints } from './curve';
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';
import { createStructureRepresentationParams } from '../../../../mol-plugin-state/helpers/structure-representation-params';
function getCellPackModelUrl(fileName: string, baseUrl: string) {
return `${baseUrl}/results/${fileName}`
@@ -124,7 +121,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 +201,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 +217,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 +268,7 @@ export function createStructureFromCellPack(packing: CellPacking, baseUrl: strin
for (const u of s.units) {
const invariantId = u.invariantId + offsetInvariantId
if (u.invariantId > maxInvariantId) maxInvariantId = u.invariantId
builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, invariantId)
builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, Unit.Trait.None, invariantId)
}
offsetInvariantId += maxInvariantId
}
@@ -279,6 +279,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 +292,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,21 +384,21 @@ 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),
color: getColorParams(hue)
createStructureRepresentationParams(ctx, Structure.Empty, {
...getReprParams(ctx, params.preset),
...getColorParams(hue)
})
)
}
@@ -413,8 +412,8 @@ export const LoadCellPackModel = StateAction.build({
.apply(StateTransforms.Model.StructureFromModel, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Misc.CreateGroup, { label: 'HIV1_envelope_Membrane' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.createParams(ctx, Structure.Empty, {
repr: getReprParams(ctx, params.preset),
createStructureRepresentationParams(ctx, Structure.Empty, {
...getReprParams(ctx, params.preset),
color: UniformColorThemeProvider
})
)
@@ -425,50 +424,46 @@ 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':
return traceOnly
? [
ctx.structureRepresentation.registry.get('spacefill'),
() => ({ sizeFactor: 2, ignoreHydrogens: true })
] as [any, any]
: [
ctx.structureRepresentation.registry.get('spacefill'),
() => ({ ignoreHydrogens: true })
] as [any, any]
? {
type: ctx.representation.structure.registry.get('spacefill'),
typeParams: { sizeFactor: 2, ignoreHydrogens: true }
} : {
type: ctx.representation.structure.registry.get('spacefill'),
typeParams: { ignoreHydrogens: true }
}
case 'gaussian-surface':
return [
ctx.structureRepresentation.registry.get('gaussian-surface'),
() => ({
return {
type: ctx.representation.structure.registry.get('gaussian-surface'),
typeParams: {
quality: 'custom', resolution: 10, radiusOffset: 2,
alpha: 1.0, flatShaded: false, doubleSided: false,
ignoreHydrogens: true
})
] as [any, any]
}
}
case 'point':
return [
ctx.structureRepresentation.registry.get('point'),
() => ({ ignoreHydrogens: true })
] as [any, any]
return { type: ctx.representation.structure.registry.get('point') }
case 'ellipsoid':
return { type: ctx.representation.structure.registry.get('orientation') }
}
}
function getColorParams(hue: [number, number]) {
return [
ModelIndexColorThemeProvider,
(c: ColorTheme.Provider<any>, ctx: ThemeRegistryContext) => {
return {
palette: {
name: 'generate',
params: {
hue, chroma: [30, 80], luminance: [15, 85],
clusteringStepCount: 50, minSampleCount: 800,
maxCount: 75
}
function getColorParams(hue: [number, number]): any {
return {
color: ModelIndexColorThemeProvider,
colorParams: {
palette: {
name: 'generate',
params: {
hue, chroma: [30, 80], luminance: [15, 85],
clusteringStepCount: 50, minSampleCount: 800,
maxCount: 75
}
}
}
] as [any, any]
}
}

View File

@@ -4,7 +4,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { PluginStateObject as PSO, PluginStateTransform } from '../../../../mol-plugin/state/objects';
import { PluginStateObject as PSO, PluginStateTransform } from '../../../../mol-plugin-state/objects';
import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
import { Task } from '../../../../mol-task';
import { CellPack as _CellPack, Cell, CellPacking } from './data';

View File

@@ -1,167 +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 { createStructureRepresentation3dParamss } 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(), e.pos, e.in);
Vec3.normalize(direction, direction);
const up = Vec3.sub(Vec3(), 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,
// createStructureRepresentation3dParamss.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,
// createStructureRepresentation3dParamss.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',
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;
}
// 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
// });
// }

View File

@@ -5,16 +5,17 @@
* @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 { PluginCommands } from '../../mol-plugin/commands';
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')
import { DownloadStructure } from '../../mol-plugin-state/actions/structure';
require('mol-plugin-ui/skin/light.scss')
function getParam(name: string, regex: string): string {
let r = new RegExp(`${name}=(${regex})[&]?`, 'i');
@@ -27,7 +28,7 @@ function init() {
const spec: PluginSpec = {
actions: [
...DefaultPluginSpec.actions,
PluginSpec.Action(CreateJoleculeState),
// PluginSpec.Action(CreateJoleculeState),
PluginSpec.Action(LoadCellPackModel),
PluginSpec.Action(StructureFromCellpack),
],
@@ -42,10 +43,12 @@ function init() {
controls: {
...DefaultPluginSpec.layout && DefaultPluginSpec.layout.controls
}
}
},
config: DefaultPluginSpec.config
};
const plugin = createPlugin(document.getElementById('app')!, spec);
trySetSnapshot(plugin);
tryLoadFromUrl(plugin);
}
async function trySetSnapshot(ctx: PluginContext) {
@@ -57,11 +60,42 @@ async function trySetSnapshot(ctx: PluginContext) {
const url = snapshotId
? `https://webchem.ncbr.muni.cz/molstar-state/get/${snapshotId}`
: snapshotUrl;
await PluginCommands.State.Snapshots.Fetch.dispatch(ctx, { url })
await PluginCommands.State.Snapshots.Fetch(ctx, { url })
} catch (e) {
ctx.log.error('Failed to load snapshot.');
console.warn('Failed to load snapshot', e);
}
}
async function tryLoadFromUrl(ctx: PluginContext) {
const url = getParam('loadFromURL', '[^&]+').trim();
try {
if (!url) return;
let format = 'cif', isBinary = false;
switch (getParam('loadFromURLFormat', '[a-z]+').toLocaleLowerCase().trim()) {
case 'pdb': format = 'pdb'; break;
case 'mmbcif': isBinary = true; break;
}
const params = DownloadStructure.createDefaultParams(void 0 as any, ctx);
return ctx.runTask(ctx.state.data.applyAction(DownloadStructure, {
source: {
name: 'url',
params: {
url,
format: format as any,
isBinary,
options: params.source.params.options,
structure: params.source.params.structure,
}
}
}));
} catch (e) {
ctx.log.error(`Failed to load from URL (${url})`);
console.warn(`Failed to load from URL (${url})`, e);
}
}
init();

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

@@ -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]
@@ -94,13 +94,13 @@ export function createProteopediaCustomTheme(colors: number[]) {
}
}
const ProteopediaCustomColorThemeProvider: ColorTheme.Provider<ProteopediaCustomColorThemeParams> = {
return {
name: 'proteopedia-custom',
label: 'Proteopedia Custom',
category: 'Custom',
factory: ProteopediaCustomColorTheme,
getParams: getChainIdColorThemeParams,
defaultValues: PD.getDefaultValues(ProteopediaCustomColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
}
return ProteopediaCustomColorThemeProvider;
}

View File

@@ -5,10 +5,11 @@
*/
import { ResidueIndex, Model } from '../../mol-model/structure';
import { BuiltInStructureRepresentationsName } from '../../mol-repr/structure/registry';
import { BuiltInColorThemeName } from '../../mol-theme/color';
import { AminoAcidNames } from '../../mol-model/structure/model/types';
import { StructureRepresentationRegistry } from '../../mol-repr/structure/registry';
import { ColorTheme } from '../../mol-theme/color';
import { PolymerType } 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[] }[],
@@ -53,15 +54,14 @@ export namespace ModelInfo {
const hetMap = new Map<string, ModelInfo['hetResidues'][0]>();
for (let rI = 0 as ResidueIndex; rI < residueCount; rI++) {
const comp_id = model.atomicHierarchy.residues.label_comp_id.value(rI);
if (AminoAcidNames.has(comp_id)) continue;
const mod_parent = model.properties.modifiedResidues.parentId.get(comp_id);
if (mod_parent && AminoAcidNames.has(mod_parent)) continue;
if (model.atomicHierarchy.derived.residue.polymerType[rI] !== PolymerType.NA) continue;
const cI = chainIndex[residueOffsets[rI]];
const eI = model.atomicHierarchy.index.getEntityFromChain(cI);
if (model.entities.data.type.value(eI) === 'water') continue;
const comp_id = model.atomicHierarchy.residues.label_comp_id.value(rI);
let lig = hetMap.get(comp_id);
if (!lig) {
lig = { name: comp_id, indices: [] };
@@ -72,10 +72,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
};
}
@@ -97,7 +98,7 @@ export interface RepresentationStyle {
}
export namespace RepresentationStyle {
export type Entry = { hide?: boolean, kind?: BuiltInStructureRepresentationsName, coloring?: BuiltInColorThemeName }
export type Entry = { hide?: boolean, kind?: StructureRepresentationRegistry.BuiltIn, coloring?: ColorTheme.BuiltIn }
}
export enum StateElements {

View File

@@ -8,36 +8,32 @@ import * as ReactDOM from 'react-dom';
import { createPlugin, DefaultPluginSpec } from '../../mol-plugin';
import './index.html'
import { PluginContext } from '../../mol-plugin/context';
import { PluginCommands } from '../../mol-plugin/command';
import { StateTransforms } from '../../mol-plugin/state/transforms';
import { StructureRepresentation3DHelpers } from '../../mol-plugin/state/transforms/representation';
import { PluginCommands } from '../../mol-plugin/commands';
import { StateTransforms } from '../../mol-plugin-state/transforms';
import { Color } from '../../mol-util/color';
import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin/state/objects';
import { AnimateModelIndex } from '../../mol-plugin/state/animation/built-in';
import { PluginStateObject as PSO, PluginStateObject } from '../../mol-plugin-state/objects';
import { AnimateModelIndex } from '../../mol-plugin-state/animation/built-in';
import { StateBuilder, StateObject, StateSelection } from '../../mol-state';
import { EvolutionaryConservation } from './annotation';
import { LoadParams, SupportedFormats, RepresentationStyle, ModelInfo, StateElements } from './helpers';
import { RxEventHelper } from '../../mol-util/rx-event-helper';
import { ControlsWrapper, volumeStreamingControls } from './ui/controls';
import { volumeStreamingControls } from './ui/controls';
import { PluginState } from '../../mol-plugin/state';
import { Scheduler } from '../../mol-task';
import { createProteopediaCustomTheme } from './coloring';
import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
import { BuiltInStructureRepresentations } from '../../mol-repr/structure/registry';
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 { createStructureRepresentationParams } from '../../mol-plugin-state/helpers/structure-representation-params';
// 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 = 4;
static VERSION_MAJOR = 4;
static VERSION_MINOR = 0;
private _ev = RxEventHelper.create();
@@ -59,23 +55,23 @@ class MolStarProteopediaWrapper {
initial: {
isExpanded: false,
showControls: false
},
controls: {
right: ControlsWrapper
}
},
components: {
remoteState: 'none'
}
});
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.representation.structure.themes.colorThemeRegistry.add(customColoring);
this.plugin.representation.structure.themes.colorThemeRegistry.add(EvolutionaryConservation.colorThemeProvider!);
this.plugin.managers.lociLabels.addProvider(EvolutionaryConservation.labelProvider!);
this.plugin.customModelProperties.register(EvolutionaryConservation.propertyProvider, true);
}
get state() {
return this.plugin.state.dataState;
return this.plugin.state.data;
}
private download(b: StateBuilder.To<PSO.Root>, url: string) {
@@ -93,10 +89,16 @@ class MolStarProteopediaWrapper {
private structure(assemblyId: string) {
const model = this.state.build().to(StateElements.Model);
const props = {
type: {
name: 'assembly' as const,
params: { id: assemblyId || 'deposited' }
}
}
const s = model
.apply(StateTransforms.Model.CustomModelProperties, { properties: [EvolutionaryConservation.Descriptor.name] }, { ref: StateElements.ModelProps, state: { isGhost: false } })
.apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: StateElements.Assembly });
.apply(StateTransforms.Model.CustomModelProperties, { autoAttach: [EvolutionaryConservation.propertyProvider.descriptor.name], properties: {} }, { ref: StateElements.ModelProps, state: { isGhost: false } })
.apply(StateTransforms.Model.StructureFromModel, props, { ref: StateElements.Assembly });
s.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' }, { ref: StateElements.Sequence });
s.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' }, { ref: StateElements.Het });
@@ -119,9 +121,10 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.SequenceVisual);
} else {
root.applyOrUpdate(StateElements.SequenceVisual, StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
(style.sequence && style.sequence.kind) || 'cartoon',
(style.sequence && style.sequence.coloring) || 'unit-index', structure));
createStructureRepresentationParams(this.plugin, structure, {
type: (style.sequence && style.sequence.kind) || 'cartoon',
color: (style.sequence && style.sequence.coloring) || 'unit-index'
}));
}
}
@@ -134,9 +137,10 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.HetVisual);
} else {
root.applyOrUpdate(StateElements.HetVisual, StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin,
(style.hetGroups && style.hetGroups.kind) || 'ball-and-stick',
(style.hetGroups && style.hetGroups.coloring), structure));
createStructureRepresentationParams(this.plugin, structure, {
type: (style.hetGroups && style.hetGroups.kind) || 'ball-and-stick',
color: style.hetGroups && style.hetGroups.coloring
}));
}
}
}
@@ -150,7 +154,7 @@ class MolStarProteopediaWrapper {
root.delete(StateElements.Het3DSNFG);
} else {
root.applyOrUpdate(StateElements.Het3DSNFG, StateTransforms.Representation.StructureRepresentation3D,
StructureRepresentation3DHelpers.getDefaultParamsWithTheme(this.plugin, 'carbohydrate', void 0, structure));
createStructureRepresentationParams(this.plugin, structure, { type: 'carbohydrate' }));
}
}
}
@@ -161,9 +165,11 @@ 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 }));
createStructureRepresentationParams(this.plugin, structure, {
type: (style.water && style.water.kind) || 'ball-and-stick',
typeParams: { alpha: 0.51 },
color: style.water && style.water.coloring
}));
}
}
@@ -187,14 +193,14 @@ class MolStarProteopediaWrapper {
}
private applyState(tree: StateBuilder) {
return PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
return PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
}
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
async load({ url, format = 'cif', assemblyId = 'deposited', representationStyle }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.dataState;
const state = this.plugin.state.data;
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
loadType = 'full';
@@ -203,7 +209,7 @@ class MolStarProteopediaWrapper {
}
if (loadType === 'full') {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
await PluginCommands.State.RemoveObject(this.plugin, { state, ref: state.tree.root.ref });
const modelTree = this.model(this.download(state.build().toRoot(), url), format);
await this.applyState(modelTree);
const info = await this.doInfo(true);
@@ -214,37 +220,45 @@ class MolStarProteopediaWrapper {
const tree = state.build();
const info = await this.doInfo(true);
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: asmId }));
const props = {
type: {
name: 'assembly' as const,
params: { id: asmId || 'deposited' }
}
}
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureFromModel, p => ({ ...p, ...props }));
await this.applyState(tree);
}
await this.updateStyle(representationStyle);
this.loadedParams = { url, format, assemblyId };
Scheduler.setImmediate(() => PluginCommands.Camera.Reset.dispatch(this.plugin, { }));
Scheduler.setImmediate(() => PluginCommands.Camera.Reset(this.plugin, { }));
}
async updateStyle(style?: RepresentationStyle, partial?: boolean) {
const tree = this.visual(style, partial);
if (!tree) return;
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
await PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
}
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) } } });
PluginCommands.Canvas3D.SetSettings(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 } } });
if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
if (!spinning) PluginCommands.Camera.Reset(this.plugin, { });
}
viewport = {
setSettings: (settings?: Canvas3DProps) => {
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, {
PluginCommands.Canvas3D.SetSettings(this.plugin, {
settings: settings || DefaultCanvas3DParams
});
}
@@ -252,10 +266,10 @@ class MolStarProteopediaWrapper {
camera = {
toggleSpin: () => this.toggleSpin(),
resetPosition: () => PluginCommands.Camera.Reset.dispatch(this.plugin, { }),
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, { }),
// setClip: (options?: { distance?: number, near?: number, far?: number }) => {
// if (!options) {
// PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, {
// PluginCommands.Canvas3D.SetSettings(this.plugin, {
// settings: {
// cameraClipDistance: DefaultCanvas3DParams.cameraClipDistance,
// clip: DefaultCanvas3DParams.clip
@@ -268,7 +282,7 @@ class MolStarProteopediaWrapper {
// const props = this.plugin.canvas3d.props;
// const clipNear = typeof options.near === 'undefined' ? props.clip[0] : options.near;
// const clipFar = typeof options.far === 'undefined' ? props.clip[1] : options.far;
// PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, {
// PluginCommands.Canvas3D.SetSettings(this.plugin, {
// settings: { cameraClipDistance: options.distance, clip: [clipNear, clipFar] }
// });
// }
@@ -298,7 +312,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.representation.structure.themes.colorThemeRegistry.get(EvolutionaryConservation.propertyProvider.descriptor.name).defaultValues };
if (!params || !!params.sequence) {
tree.to(StateElements.SequenceVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
@@ -307,7 +321,7 @@ class MolStarProteopediaWrapper {
tree.to(StateElements.HetVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
}
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
await PluginCommands.State.Update(this.plugin, { state, tree });
}
}
@@ -315,9 +329,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);
@@ -325,7 +341,7 @@ class MolStarProteopediaWrapper {
remove: () => {
const r = this.state.select(StateSelection.Generators.ofTransformer(CreateVolumeStreamingInfo))[0];
if (!r) return;
PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.state, ref: r.transform.ref });
PluginCommands.State.RemoveObject(this.plugin, { state: this.state, ref: r.transform.ref });
if (this.experimentalDataElement) {
ReactDOM.unmountComponentAtNode(this.experimentalDataElement);
this.experimentalDataElement = void 0;
@@ -336,12 +352,12 @@ class MolStarProteopediaWrapper {
hetGroups = {
reset: () => {
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, { });
PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
PluginCommands.Camera.Reset(this.plugin, { });
},
focusFirst: async (compId: string) => {
if (!this.state.transforms.has(StateElements.Assembly)) return;
await PluginCommands.Camera.Reset.dispatch(this.plugin, { });
await PluginCommands.Camera.Reset(this.plugin, { });
// const asm = (this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure).data;
@@ -374,7 +390,7 @@ class MolStarProteopediaWrapper {
// }
// });
await PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
await PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
const focus = (this.state.select(StateElements.HetGroupFocus)[0].obj as PluginStateObject.Molecule.Structure).data;
const sphere = focus.boundary.sphere;
@@ -382,26 +398,25 @@ 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));
PluginCommands.Camera.SetSnapshot.dispatch(this.plugin, { snapshot, durationMs: 250 });
const radius = Math.max(sphere.radius, 5)
const snapshot = this.plugin.canvas3d!.camera.getFocus(sphere.center, radius);
PluginCommands.Camera.SetSnapshot(this.plugin, { snapshot, durationMs: 250 });
}
}
private createSurVisualParams() {
const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, {
repr: BuiltInStructureRepresentations['ball-and-stick'],
color: [BuiltInColorThemes.uniform, () => ({ value: ColorNames.gray })],
size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )]
return createStructureRepresentationParams(this.plugin, asm.data, {
type: 'ball-and-stick',
color: 'uniform', colorParams: { value: ColorNames.gray },
size: 'uniform', sizeParams: { value: 0.33 }
});
}
private createCoreVisualParams() {
const asm = this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure;
return StructureRepresentation3DHelpers.createParams(this.plugin, asm.data, {
repr: BuiltInStructureRepresentations['ball-and-stick'],
// color: [BuiltInColorThemes.uniform, () => ({ value: ColorNames.gray })],
// size: [BuiltInSizeThemes.uniform, () => ({ value: 0.33 } )]
return createStructureRepresentationParams(this.plugin, asm.data, {
type: 'ball-and-stick'
});
}
@@ -414,8 +429,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,24 +6,11 @@
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 { PluginContextContainer } from '../../../mol-plugin-ui/plugin';
import { TransformUpdaterControl } from '../../../mol-plugin-ui/state/update-transform';
import { PluginContext } from '../../../mol-plugin/context';
import { TransformUpdaterControl } from '../../../mol-plugin/ui/state/update-transform';
import { StateElements } from '../helpers';
export class ControlsWrapper extends PluginUIComponent {
render() {
return <div className='msp-scrollable-container msp-right-controls'>
<CurrentObject />
<AnimationControls />
<CameraSnapshots />
</div>;
}
}
export function volumeStreamingControls(plugin: PluginContext, parent: Element) {
ReactDOM.render(<PluginContextContainer plugin={plugin}>
<TransformUpdaterControl nodeRef={StateElements.VolumeStreaming} />

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

@@ -8,6 +8,7 @@
import { Mat4, Vec3, Vec4, EPSILON } from '../mol-math/linear-algebra'
import { Viewport, cameraProject, cameraUnproject } from './camera/util';
import { CameraTransitionManager } from './camera/transition';
import { BehaviorSubject } from 'rxjs';
export { Camera }
@@ -33,6 +34,7 @@ class Camera {
zoom = 1
readonly transition: CameraTransitionManager = new CameraTransitionManager(this);
readonly stateChanged = new BehaviorSubject<Partial<Camera.Snapshot>>(this.state);
get position() { return this.state.position; }
set position(v: Vec3) { Vec3.copy(this.state.position, v); }
@@ -76,35 +78,39 @@ class Camera {
setState(snapshot: Partial<Camera.Snapshot>, durationMs?: number) {
this.transition.apply(snapshot, durationMs);
this.stateChanged.next(snapshot);
}
getSnapshot() {
const ret = Camera.createDefaultSnapshot();
Camera.copySnapshot(ret, this.state);
return ret;
return Camera.copySnapshot(Camera.createDefaultSnapshot(), this.state);
}
getFocus(target: Vec3, radius: number): Partial<Camera.Snapshot> {
const fov = this.state.fov
getFocus(target: Vec3, radius: number, up?: Vec3, dir?: Vec3): Partial<Camera.Snapshot> {
const r = Math.max(radius, 0.01)
const { fov } = this.state
const { width, height } = this.viewport
const aspect = width / height
const aspectFactor = (height < width ? 1 : aspect)
const targetDistance = Math.abs((radius / aspectFactor) / Math.sin(fov / 2))
const targetDistance = Math.abs((r / aspectFactor) / Math.sin(fov / 2))
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)
const state = Camera.copySnapshot(Camera.createDefaultSnapshot(), this.state)
state.target = Vec3.clone(target)
state.radius = radius
state.radius = r
state.position = Vec3.clone(this.newPosition)
if (up) Vec3.matchDirection(state.up, up, state.up)
return state
}
focus(target: Vec3, radius: number, durationMs?: number) {
if (radius > 0) this.setState(this.getFocus(target, radius), durationMs);
focus(target: Vec3, radius: number, durationMs?: number, up?: Vec3, dir?: Vec3) {
if (radius > 0) {
this.setState(this.getFocus(target, radius, up, dir), durationMs);
}
}
project(out: Vec4, point: Vec3) {
@@ -159,7 +165,9 @@ namespace Camera {
target: Vec3.create(0, 0, 0),
radius: 10,
radiusMax: 10,
fog: 50,
clipFar: true
};
}
@@ -172,7 +180,9 @@ namespace Camera {
target: Vec3
radius: number
radiusMax: number
fog: number
clipFar: boolean
}
export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) {
@@ -186,7 +196,9 @@ namespace Camera {
if (typeof source.target !== 'undefined') Vec3.copy(out.target, source.target);
if (typeof source.radius !== 'undefined') out.radius = source.radius;
if (typeof source.radiusMax !== 'undefined') out.radiusMax = source.radiusMax;
if (typeof source.fog !== 'undefined') out.fog = source.fog;
if (typeof source.clipFar !== 'undefined') out.clipFar = source.clipFar;
return out;
}
@@ -253,17 +265,17 @@ function updatePers(camera: Camera) {
}
function updateClip(camera: Camera) {
const { radius, mode, fog } = camera.state
let { radius, radiusMax, mode, fog, clipFar } = camera.state
if (radius < 0.01) radius = 0.01
const cDist = Vec3.distance(camera.position, camera.target)
const bRadius = Math.max(1, radius)
let near = cDist - bRadius
let far = cDist + bRadius
const normalizedFar = clipFar ? radius : radiusMax
const cameraDistance = Vec3.distance(camera.position, camera.target)
let near = cameraDistance - radius
let far = cameraDistance + normalizedFar
const fogNearFactor = -(50 - fog) / 50
let fogNear = cDist - (bRadius * fogNearFactor)
let fogFar = cDist + bRadius
let fogNear = cameraDistance - (normalizedFar * fogNearFactor)
let fogFar = far
if (mode === 'perspective') {
// set at least to 5 to avoid slow sphere impostor rendering

View File

@@ -17,19 +17,26 @@ class CameraTransitionManager {
private start = 0;
inTransition = false;
private durationMs = 0;
private source: Camera.Snapshot = Camera.createDefaultSnapshot();
private target: Camera.Snapshot = Camera.createDefaultSnapshot();
private current = Camera.createDefaultSnapshot();
private _source: Camera.Snapshot = Camera.createDefaultSnapshot();
private _target: Camera.Snapshot = Camera.createDefaultSnapshot();
private _current = Camera.createDefaultSnapshot();
get source(): Readonly<Camera.Snapshot> { return this._source }
get target(): Readonly<Camera.Snapshot> { return this._target }
apply(to: Partial<Camera.Snapshot>, durationMs: number = 0, transition?: CameraTransitionManager.TransitionFunc) {
if (durationMs <= 0 || (typeof to.mode !== 'undefined' && to.mode !== this.camera.state.mode)) {
this.finish(to);
return;
Camera.copySnapshot(this._source, this.camera.state);
Camera.copySnapshot(this._target, this.camera.state);
Camera.copySnapshot(this._target, to);
if (this._target.radius > this._target.radiusMax) {
this._target.radius = this._target.radiusMax
}
Camera.copySnapshot(this.source, this.camera.state);
Camera.copySnapshot(this.target, this.camera.state);
Camera.copySnapshot(this.target, to);
if (durationMs <= 0 || (typeof to.mode !== 'undefined' && to.mode !== this.camera.state.mode)) {
this.finish(this._target);
return;
}
this.inTransition = true;
this.func = transition || CameraTransitionManager.defaultTransition;
@@ -52,12 +59,12 @@ class CameraTransitionManager {
const normalized = Math.min((this.t - this.start) / this.durationMs, 1);
if (normalized === 1) {
this.finish(this.target!);
this.finish(this._target!);
return;
}
this.func(this.current, normalized, this.source, this.target);
Camera.copySnapshot(this.camera.state, this.current);
this.func(this._current, normalized, this._source, this._target);
Camera.copySnapshot(this.camera.state, this._current);
}
constructor(private camera: Camera) {
@@ -80,6 +87,8 @@ namespace CameraTransitionManager {
Vec3.lerp(out.target, source.target, target.target, t);
Vec3.lerp(out.position, source.position, target.position, t);
out.radius = lerp(source.radius, target.radius, t);
// TODO take change of `clipFar` into account
out.radiusMax = lerp(source.radiusMax, target.radiusMax, t);
// Lerp fov & fog
out.fov = lerp(source.fov, target.fov, t);

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,18 +27,30 @@ 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 = {
cameraMode: PD.Select('perspective', [['perspective', 'Perspective'], ['orthographic', 'Orthographic']]),
cameraFog: PD.Numeric(50, { min: 1, max: 100, step: 1 }),
cameraMode: PD.Select('perspective', [['perspective', 'Perspective'], ['orthographic', 'Orthographic']] as const),
cameraFog: PD.MappedStatic('on', {
on: PD.Group({
intensity: PD.Numeric(50, { min: 1, max: 100, step: 1 }),
}),
off: PD.Group({})
}, { cycle: true, description: 'Show fog in the distance' }),
cameraClipping: PD.Group({
radius: PD.Numeric(100, { min: 0, max: 99, step: 1 }, { label: 'Clipping', description: 'How much of the scene to show.' }),
far: PD.Boolean(true, { description: 'Hide scene in the distance' }),
}, { pivot: 'radius' }),
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),
@@ -53,29 +66,34 @@ 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
syncVisibility(): 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(options?: { durationMs?: number, snapshot?: Partial<Camera.Snapshot> }): void
readonly camera: Camera
downloadScreenshot: () => void
getPixelData: (variant: GraphicsRenderVariant) => PixelData
setProps: (props: Partial<Canvas3DProps>) => void
getImagePass: () => ImagePass
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>
@@ -83,15 +101,15 @@ 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 HoverEvent { current: Representation.Loci, buttons: ButtonsType, 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, {
@@ -103,10 +121,45 @@ namespace Canvas3D {
})
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,7 +169,7 @@ namespace Canvas3D {
const startTime = now()
const didDraw = new BehaviorSubject<now.Timestamp>(0 as now.Timestamp)
const webgl = createContext(gl)
const { gl, contextRestored } = webgl
let width = gl.drawingBufferWidth
let height = gl.drawingBufferHeight
@@ -126,7 +179,8 @@ namespace Canvas3D {
const camera = new Camera({
position: Vec3.create(0, 0, 100),
mode: p.cameraMode,
fog: p.cameraFog
fog: p.cameraFog.name === 'on' ? p.cameraFog.params.intensity : 0,
clipFar: p.cameraClipping.far
})
const controls = TrackballControls.create(input, camera, p.trackball)
@@ -139,8 +193,15 @@ namespace Canvas3D {
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 = false
let nextCameraResetDuration: number | undefined = void 0
let nextCameraResetSnapshot: Partial<Camera.Snapshot> | undefined = void 0
function getLoci(pickingId: PickingId) {
let loci: Loci = EmptyLoci
@@ -174,8 +235,8 @@ namespace Canvas3D {
}
}
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)
@@ -184,32 +245,25 @@ namespace Canvas3D {
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(true)
} 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;
@@ -224,45 +278,99 @@ 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) {
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius)
cameraResetRequested = false
}
if (debugHelper.isEnabled) debugHelper.update()
requestDraw(true)
reprCount.next(reprRenderObjects.size)
})
function resolveCameraReset() {
if (!cameraResetRequested) return;
const { center, radius } = scene.boundingSphere;
if (radius > 0) {
const duration = nextCameraResetDuration === undefined ? p.cameraResetDurationMs : nextCameraResetDuration
const focus = camera.getFocus(center, radius);
const snapshot = nextCameraResetSnapshot ? { ...focus, ...nextCameraResetSnapshot } : focus;
camera.setState(snapshot, duration);
}
nextCameraResetDuration = void 0;
nextCameraResetSnapshot = 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();
if (reprCount.value === 0 || camera.state.radiusMax === 0) cameraResetRequested = true;
camera.setState({ radiusMax: scene.boundingSphere.radius })
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()
@@ -270,24 +378,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;
@@ -297,12 +390,19 @@ namespace Canvas3D {
}
},
clear: () => {
reprUpdatedSubscriptions.forEach(v => v.unsubscribe())
reprUpdatedSubscriptions.clear()
reprRenderObjects.clear()
scene.clear()
debugHelper.clear()
requestDraw(true)
reprCount.next(reprRenderObjects.size)
},
syncVisibility: () => {
if (scene.syncVisibility()) {
camera.setState({ radiusMax: scene.boundingSphere.radius })
}
},
// draw,
requestDraw,
@@ -312,15 +412,13 @@ namespace Canvas3D {
getLoci,
handleResize,
resetCamera: () => {
if (scene.isCommiting) {
cameraResetRequested = true
} else {
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius, p.cameraResetDurationMs)
requestDraw(true);
}
requestCameraReset: options => {
nextCameraResetDuration = options?.durationMs;
nextCameraResetSnapshot = options?.snapshot;
cameraResetRequested = true;
},
camera,
boundingSphere: scene.boundingSphere,
downloadScreenshot: () => {
// TODO
},
@@ -336,19 +434,37 @@ namespace Canvas3D {
didDraw,
reprCount,
setProps: (props: Partial<Canvas3DProps>) => {
const cameraState: Partial<Camera.Snapshot> = Object.create(null)
if (props.cameraMode !== undefined && props.cameraMode !== camera.state.mode) {
camera.setState({ mode: props.cameraMode })
cameraState.mode = props.cameraMode
}
if (props.cameraFog !== undefined && props.cameraFog !== camera.state.fog) {
camera.setState({ fog: props.cameraFog })
if (props.cameraFog !== undefined) {
const newFog = props.cameraFog.name === 'on' ? props.cameraFog.params.intensity : 0
if (newFog !== camera.state.fog) cameraState.fog = newFog
}
if (props.cameraClipping !== undefined) {
if (props.cameraClipping.far !== undefined && props.cameraClipping.far !== camera.state.clipFar) {
cameraState.clipFar = props.cameraClipping.far
}
if (props.cameraClipping.radius !== undefined) {
const radius = (scene.boundingSphere.radius / 100) * (100 - props.cameraClipping.radius)
if (radius > 0 && radius !== cameraState.radius) {
// if radius = 0, NaNs happen
cameraState.radius = Math.max(radius, 0.01)
}
}
}
if (Object.keys(cameraState).length > 0) camera.setState(cameraState)
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)
if (props.renderer) renderer.setProps(props.renderer)
if (props.trackball) controls.setProps(props.trackball)
if (props.debug) debugHelper.setProps(props.debug)
requestDraw(true)
},
getImagePass: (props: Partial<ImageProps> = {}) => {
@@ -356,10 +472,18 @@ namespace Canvas3D {
},
get props() {
const radius = scene.boundingSphere.radius > 0
? 100 - Math.round((camera.transition.target.radius / scene.boundingSphere.radius) * 100)
: 0
return {
cameraMode: camera.state.mode,
cameraFog: camera.state.fog,
cameraFog: camera.state.fog > 0
? { name: 'on' as const, params: { intensity: camera.state.fog } }
: { name: 'off' as const, params: {} },
cameraClipping: { far: camera.state.clipFar, radius },
cameraResetDurationMs: p.cameraResetDurationMs,
transparentBackground: p.transparentBackground,
postprocessing: { ...postprocessing.props },
multiSample: { ...multiSample.props },
@@ -378,6 +502,8 @@ namespace Canvas3D {
return interactionHelper.events
},
dispose: () => {
contextRestoredSub.unsubscribe()
scene.clear()
debugHelper.clear()
input.dispose()

View File

@@ -21,15 +21,15 @@ 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 ${trigger}'),
dragRotateZ: Binding(Trigger(B.Flag.Primary, M.create({ shift: true })), 'Rotate the 3D scene around the z-axis by dragging using ${trigger}'),
dragPan: Binding(Trigger(B.Flag.Secondary, M.create()), 'Pan the 3D scene by dragging using ${trigger}'),
dragRotate: Binding([Trigger(B.Flag.Primary, M.create())], 'Rotate', 'Drag using ${triggers}'),
dragRotateZ: Binding([Trigger(B.Flag.Primary, M.create({ shift: true }))], 'Rotate around z-axis', 'Drag using ${triggers}'),
dragPan: Binding([Trigger(B.Flag.Secondary, M.create()), Trigger(B.Flag.Primary, M.create({ control: true }))], 'Pan', 'Drag using ${triggers}'),
dragZoom: Binding.Empty,
dragFocus: Binding(Trigger(B.Flag.Forth, M.create()), 'Focus the 3D scene by dragging using ${trigger}'),
dragFocusZoom: Binding(Trigger(B.Flag.Auxilary, M.create()), 'Focus and zoom the 3D scene by dragging using ${trigger}'),
dragFocus: Binding([Trigger(B.Flag.Forth, M.create())], 'Focus', 'Drag using ${triggers}'),
dragFocusZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Focus and zoom', 'Drag using ${triggers}'),
scrollZoom: Binding(Trigger(B.Flag.Auxilary, M.create()), 'Zoom the 3D scene by scrolling using ${trigger}'),
scrollFocus: Binding(Trigger(B.Flag.Auxilary, M.create({ shift: true })), 'Focus the 3D scene by scrolling using ${trigger}'),
scrollZoom: Binding([Trigger(B.Flag.Auxilary, M.create())], 'Zoom', 'Scroll using ${triggers}'),
scrollFocus: Binding([Trigger(B.Flag.Auxilary, M.create({ shift: true }))], 'Clip', 'Scroll using ${triggers}'),
scrollFocusZoom: Binding.Empty,
}
@@ -41,7 +41,7 @@ export const TrackballControlsParams = {
panSpeed: PD.Numeric(0.8, { min: 0.1, max: 5, step: 0.1 }),
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 }),
spinSpeed: PD.Numeric(1, { min: -20, max: 20, step: 1 }),
staticMoving: PD.Boolean(true, { isHidden: true }),
dynamicDampingFactor: PD.Numeric(0.2, {}, { isHidden: true }),

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>
*/
@@ -45,27 +45,25 @@ export class BoundingSphereHelper {
}
update() {
const newSceneData = updateBoundingSphereData(this.scene, this.parent.boundingSphere, this.sceneData, ColorNames.grey)
const newSceneData = updateBoundingSphereData(this.scene, this.parent.boundingSphere, this.sceneData, ColorNames.grey, sceneMaterialId)
if (newSceneData) this.sceneData = newSceneData
this.parent.forEach((r, ro) => {
const objectData = this.objectsData.get(ro)
const newObjectData = updateBoundingSphereData(this.scene, r.values.boundingSphere.ref.value, objectData, ColorNames.tomato)
const newObjectData = updateBoundingSphereData(this.scene, r.values.boundingSphere.ref.value, objectData, ColorNames.tomato, objectMaterialId)
if (newObjectData) this.objectsData.set(ro, newObjectData)
if (ro.type === 'mesh' || ro.type === 'lines' || ro.type === 'points') {
const instanceData = this.instancesData.get(ro)
const newInstanceData = updateBoundingSphereData(this.scene, r.values.invariantBoundingSphere.ref.value, instanceData, ColorNames.skyblue, {
aTransform: ro.values.aTransform,
matrix: ro.values.matrix,
transform: ro.values.transform,
extraTransform: ro.values.extraTransform,
uInstanceCount: ro.values.uInstanceCount,
instanceCount: ro.values.instanceCount,
aInstance: ro.values.aInstance,
})
if (newInstanceData) this.instancesData.set(ro, newInstanceData)
}
const instanceData = this.instancesData.get(ro)
const newInstanceData = updateBoundingSphereData(this.scene, r.values.invariantBoundingSphere.ref.value, instanceData, ColorNames.skyblue, instanceMaterialId, {
aTransform: ro.values.aTransform,
matrix: ro.values.matrix,
transform: ro.values.transform,
extraTransform: ro.values.extraTransform,
uInstanceCount: ro.values.uInstanceCount,
instanceCount: ro.values.instanceCount,
aInstance: ro.values.aInstance,
})
if (newInstanceData) this.instancesData.set(ro, newInstanceData)
})
this.objectsData.forEach((objectData, ro) => {
@@ -82,7 +80,7 @@ export class BoundingSphereHelper {
})
this.scene.update(void 0, false)
this.scene.syncCommit()
this.scene.commit()
}
syncVisibility() {
@@ -116,10 +114,10 @@ export class BoundingSphereHelper {
}
}
function updateBoundingSphereData(scene: Scene, boundingSphere: Sphere3D, data: BoundingSphereData | undefined, color: Color, transform?: TransformData) {
function updateBoundingSphereData(scene: Scene, boundingSphere: Sphere3D, data: BoundingSphereData | undefined, color: Color, materialId: number, transform?: TransformData) {
if (!data || !Sphere3D.equals(data.boundingSphere, boundingSphere)) {
const mesh = createBoundingSphereMesh(boundingSphere, data && data.mesh)
const renderObject = data ? data.renderObject : createBoundingSphereRenderObject(mesh, color, transform)
const renderObject = data ? data.renderObject : createBoundingSphereRenderObject(mesh, color, materialId, transform)
if (data) {
ValueCell.update(renderObject.values.drawCount, Geometry.getDrawCount(mesh))
} else {
@@ -133,12 +131,20 @@ function createBoundingSphereMesh(boundingSphere: Sphere3D, mesh?: Mesh) {
const detail = 2
const vertexCount = sphereVertexCount(detail)
const builderState = MeshBuilder.createState(vertexCount, vertexCount / 2, mesh)
if (boundingSphere.radius) addSphere(builderState, boundingSphere.center, boundingSphere.radius, detail)
if (boundingSphere.radius) {
addSphere(builderState, boundingSphere.center, boundingSphere.radius, detail)
if (Sphere3D.hasExtrema(boundingSphere)) {
for (const e of boundingSphere.extrema) addSphere(builderState, e, 1.0, 0)
}
}
return MeshBuilder.getMesh(builderState)
}
const boundingSphereHelberMaterialId = getNextMaterialId()
function createBoundingSphereRenderObject(mesh: Mesh, color: Color, transform?: TransformData) {
const sceneMaterialId = getNextMaterialId()
const objectMaterialId = getNextMaterialId()
const instanceMaterialId = getNextMaterialId()
function createBoundingSphereRenderObject(mesh: Mesh, color: Color, materialId: number, transform?: TransformData) {
const values = Mesh.Utils.createValuesSimple(mesh, { alpha: 0.1, doubleSided: false }, color, 1, transform)
return createRenderObject('mesh', values, { visible: true, alphaFactor: 1, pickable: false, opaque: false }, boundingSphereHelberMaterialId)
return createRenderObject('mesh', values, { visible: true, alphaFactor: 1, pickable: false, opaque: false }, materialId)
}

View File

@@ -38,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) {
@@ -50,7 +51,7 @@ 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;
}
@@ -61,7 +62,7 @@ export class Canvas3dInteractionHelper {
const loci = this.getLoci(this.id);
// only broadcast the latest hover
if (!Representation.Loci.areEqual(this.prevLoci, loci)) {
this.events.hover.next({ current: loci, buttons: this.buttons, modifiers: this.modifiers });
this.events.hover.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
this.prevLoci = loci;
}
}
@@ -78,22 +79,24 @@ export class Canvas3dInteractionHelper {
this.inside = false;
if (this.prevLoci.loci !== EmptyLoci) {
this.prevLoci = Representation.Loci.Empty;
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, modifiers: this.modifiers });
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
}
}
move(x: number, y: number, buttons: ButtonsType, 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);
}
@@ -101,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.hover.next({ current: this.prevLoci, buttons: this.buttons, modifiers: this.modifiers });
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
}
dispose() {
@@ -109,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 }) => {
input.move.subscribe(({x, y, inside, buttons, button, modifiers }) => {
if (!inside) return;
this.move(x, y, buttons, modifiers);
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,11 @@
*/
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 {
@@ -20,13 +20,13 @@ export class DrawPass {
private depthTarget: RenderTarget | null
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private debugHelper: BoundingSphereHelper) {
const { gl, extensions } = webgl
const { gl, extensions, resources } = webgl
const width = gl.drawingBufferWidth
const height = gl.drawingBufferHeight
this.colorTarget = createRenderTarget(webgl, width, height)
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')
@@ -42,29 +42,33 @@ export class DrawPass {
}
}
render(toDrawingBuffer: boolean) {
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, colorTarget.width, colorTarget.height)
renderer.render(scene, camera, '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, camera, '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, camera, 'depth', true)
renderer.render(scene, camera, 'depth', true, transparentBackground)
if (debugHelper.isEnabled) {
debugHelper.syncVisibility()
renderer.render(debugHelper.scene, camera, 'depth', false)
renderer.render(debugHelper.scene, camera, 'depth', false, transparentBackground)
}
}
}

View File

@@ -17,6 +17,7 @@ import { Camera } from '../camera';
import { Viewport } from '../camera/util';
export const ImageParams = {
transparentBackground: PD.Boolean(false),
multiSample: PD.Group(MultiSampleParams),
postprocessing: PD.Group(PostprocessingParams),
}
@@ -26,6 +27,7 @@ export class ImagePass {
private _width = 1024
private _height = 768
private _camera = new Camera()
private _transparentBackground = false
private _colorTarget: RenderTarget
get colorTarget() { return this._colorTarget }
@@ -40,6 +42,8 @@ export class ImagePass {
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)
@@ -48,6 +52,8 @@ export class ImagePass {
}
setSize(width: number, height: number) {
if (width === this._width && height === this._height) return
this._width = width
this._height = height
@@ -57,6 +63,7 @@ export class ImagePass {
}
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)
}
@@ -69,10 +76,10 @@ export class ImagePass {
this.renderer.setViewport(0, 0, this._width, this._height);
if (this.multiSample.enabled) {
this.multiSample.render(false)
this.multiSample.render(false, this._transparentBackground)
this._colorTarget = this.multiSample.colorTarget
} else {
this.drawPass.render(false)
this.drawPass.render(false, this._transparentBackground)
if (this.postprocessing.enabled) {
this.postprocessing.render(false)
this._colorTarget = this.postprocessing.target

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),
}
@@ -66,9 +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.colorTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
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 }
}
@@ -105,15 +105,15 @@ export class MultiSamplePass {
if (props.sampleLevel !== undefined) this.props.sampleLevel = props.sampleLevel
}
render(toDrawingBuffer: boolean) {
render(toDrawingBuffer: boolean, transparentBackground: boolean) {
if (this.props.mode === 'temporal') {
this.renderTemporalMultiSample(toDrawingBuffer)
this.renderTemporalMultiSample(toDrawingBuffer, transparentBackground)
} else {
this.renderMultiSample(toDrawingBuffer)
this.renderMultiSample(toDrawingBuffer, transparentBackground)
}
}
private renderMultiSample(toDrawingBuffer: boolean) {
private renderMultiSample(toDrawingBuffer: boolean, transparentBackground: boolean) {
const { camera, compose, composeTarget, drawPass, postprocessing, webgl } = this
const { gl, state } = webgl
@@ -131,7 +131,8 @@ 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.
@@ -148,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
@@ -184,7 +185,7 @@ export class MultiSamplePass {
camera.update()
}
private renderTemporalMultiSample(toDrawingBuffer: boolean) {
private renderTemporalMultiSample(toDrawingBuffer: boolean, transparentBackground: boolean) {
const { camera, compose, composeTarget, holdTarget, postprocessing, drawPass, webgl } = this
const { gl, state } = webgl
@@ -204,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)
@@ -222,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.
@@ -233,7 +235,7 @@ export class MultiSamplePass {
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

View File

@@ -5,7 +5,7 @@
*/
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';
@@ -36,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()
}
@@ -68,11 +68,11 @@ export class PickPass {
const { renderer, scene, camera } = this
renderer.setViewport(0, 0, this.pickWidth, this.pickHeight);
this.objectPickTarget.bind();
renderer.render(scene, camera, 'pickObject', true);
renderer.render(scene, camera, 'pickObject', true, false);
this.instancePickTarget.bind();
renderer.render(scene, camera, 'pickInstance', true);
renderer.render(scene, camera, 'pickInstance', true, false);
this.groupPickTarget.bind();
renderer.render(scene, camera, 'pickGroup', true);
renderer.render(scene, camera, 'pickGroup', true, false);
this.pickDirty = false
}
@@ -97,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

@@ -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>
*/
@@ -14,9 +14,10 @@ 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';
import { produce } from 'immer';
import quad_vert from '../../mol-gl/shader/quad.vert'
import postprocessing_frag from '../../mol-gl/shader/postprocessing.frag'
@@ -27,7 +28,6 @@ const PostprocessingSchema = {
tDepth: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
uTexSize: UniformSpec('v2'),
dUseFog: DefineSpec('boolean'),
dOrthographic: DefineSpec('number'),
uNear: UniformSpec('f'),
uFar: UniformSpec('f'),
@@ -48,16 +48,21 @@ const PostprocessingSchema = {
}
export const PostprocessingParams = {
occlusionEnable: PD.Boolean(false),
occlusionKernelSize: PD.Numeric(4, { min: 1, max: 32, step: 1 }),
occlusionBias: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
occlusionRadius: PD.Numeric(32, { min: 0, max: 256, step: 1 }),
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),
occlusion: PD.MappedStatic('off', {
on: PD.Group({
kernelSize: PD.Numeric(4, { min: 1, max: 32, step: 1 }),
bias: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
radius: PD.Numeric(64, { min: 0, max: 256, step: 1 }),
}),
off: PD.Group({})
}, { cycle: true, description: 'Darken occluded crevices with the ambient occlusion effect' }),
outline: PD.MappedStatic('off', {
on: PD.Group({
scale: PD.Numeric(1, { min: 0, max: 10, step: 1 }),
threshold: PD.Numeric(0.8, { min: 0, max: 1, step: 0.01 }),
}),
off: PD.Group({})
}, { cycle: true, description: 'Draw outline around 3D objects' })
}
export type PostprocessingProps = PD.Values<typeof PostprocessingParams>
@@ -69,9 +74,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),
@@ -79,14 +83,14 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
uFogFar: ValueCell.create(10000),
uFogColor: ValueCell.create(Vec3.create(1, 1, 1)),
dOcclusionEnable: ValueCell.create(p.occlusionEnable),
dOcclusionKernelSize: ValueCell.create(p.occlusionKernelSize),
uOcclusionBias: ValueCell.create(p.occlusionBias),
uOcclusionRadius: ValueCell.create(p.occlusionRadius),
dOcclusionEnable: ValueCell.create(p.occlusion.name === 'on'),
dOcclusionKernelSize: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.kernelSize : 4),
uOcclusionBias: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.bias : 0.5),
uOcclusionRadius: ValueCell.create(p.occlusion.name === 'on' ? p.occlusion.params.radius : 64),
dOutlineEnable: ValueCell.create(p.outlineEnable),
uOutlineScale: ValueCell.create(p.outlineScale * ctx.pixelRatio),
uOutlineThreshold: ValueCell.create(p.outlineThreshold),
dOutlineEnable: ValueCell.create(p.outline.name === 'on'),
uOutlineScale: ValueCell.create((p.outline.name === 'on' ? p.outline.params.scale : 1) * ctx.pixelRatio),
uOutlineThreshold: ValueCell.create(p.outline.name === 'on' ? p.outline.params.threshold : 0.8),
dPackedDepth: ValueCell.create(packedDepth),
}
@@ -105,14 +109,14 @@ 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)
}
get enabled() {
return this.props.occlusionEnable || this.props.outlineEnable
return this.props.occlusion.name === 'on' || this.props.outline.name === 'on'
}
setSize(width: number, height: number) {
@@ -121,40 +125,28 @@ export class PostprocessingPass {
}
setProps(props: Partial<PostprocessingProps>) {
if (props.occlusionEnable !== undefined) {
this.props.occlusionEnable = props.occlusionEnable
ValueCell.update(this.renderable.values.dOcclusionEnable, props.occlusionEnable)
}
if (props.occlusionKernelSize !== undefined) {
this.props.occlusionKernelSize = props.occlusionKernelSize
ValueCell.update(this.renderable.values.dOcclusionKernelSize, props.occlusionKernelSize)
}
if (props.occlusionBias !== undefined) {
this.props.occlusionBias = props.occlusionBias
ValueCell.update(this.renderable.values.uOcclusionBias, props.occlusionBias)
}
if (props.occlusionRadius !== undefined) {
this.props.occlusionRadius = props.occlusionRadius
ValueCell.update(this.renderable.values.uOcclusionRadius, props.occlusionRadius)
}
this.props = produce(this.props, p => {
if (props.occlusion !== undefined) {
p.occlusion.name = props.occlusion.name
ValueCell.updateIfChanged(this.renderable.values.dOcclusionEnable, props.occlusion.name === 'on')
if (props.occlusion.name === 'on') {
p.occlusion.params = { ...props.occlusion.params }
ValueCell.updateIfChanged(this.renderable.values.dOcclusionKernelSize, props.occlusion.params.kernelSize)
ValueCell.updateIfChanged(this.renderable.values.uOcclusionBias, props.occlusion.params.bias)
ValueCell.updateIfChanged(this.renderable.values.uOcclusionRadius, props.occlusion.params.radius)
}
}
if (props.outlineEnable !== undefined) {
this.props.outlineEnable = props.outlineEnable
ValueCell.update(this.renderable.values.dOutlineEnable, props.outlineEnable)
}
if (props.outlineScale !== undefined) {
this.props.outlineScale = props.outlineScale
ValueCell.update(this.renderable.values.uOutlineScale, props.outlineScale * this.webgl.pixelRatio)
}
if (props.outlineThreshold !== undefined) {
this.props.outlineThreshold = props.outlineThreshold
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)
}
if (props.outline !== undefined) {
p.outline.name = props.outline.name
ValueCell.updateIfChanged(this.renderable.values.dOutlineEnable, props.outline.name === 'on')
if (props.outline.name === 'on') {
p.outline.params = { ...props.outline.params }
ValueCell.updateIfChanged(this.renderable.values.uOutlineScale, props.outline.params.scale)
ValueCell.updateIfChanged(this.renderable.values.uOutlineThreshold, props.outline.params.threshold)
}
}
})
this.renderable.update()
}

View File

@@ -6,8 +6,8 @@
/** Set canvas size taking `devicePixelRatio` into account */
export function setCanvasSize(canvas: HTMLCanvasElement, width: number, height: number) {
canvas.width = window.devicePixelRatio * width
canvas.height = window.devicePixelRatio * height
canvas.width = Math.round(window.devicePixelRatio * width)
canvas.height = Math.round(window.devicePixelRatio * height)
Object.assign(canvas.style, { width: `${width}px`, height: `${height}px` })
}
@@ -28,7 +28,7 @@ function _canvasToBlob(canvas: HTMLCanvasElement, callback: BlobCallback, type?:
const len = bin.length
const len32 = len >> 2
const a8 = new Uint8Array(len)
const a32 = new Uint32Array( a8.buffer, 0, len32 )
const a32 = new Uint32Array(a8.buffer, 0, len32)
let j = 0
for (let i = 0; i < len32; ++i) {

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

@@ -9,7 +9,7 @@ import { sortArray } from '../util/sort'
import { StringBuilder } from '../../mol-util';
/** A collection of columns */
type Table<Schema extends Table.Schema> = {
type Table<Schema extends Table.Schema = any> = {
readonly _rowCount: number,
readonly _columns: ReadonlyArray<string>,
readonly _schema: Schema
@@ -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);
@@ -59,7 +73,7 @@ namespace Table {
return ret;
}
export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, rows: ArrayLike<Partial<Row<S>>>): R {
export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: S, rows: ArrayLike<Partial<Row<S>>>): R {
const ret = Object.create(null);
const rowCount = rows.length;
const columns = Object.keys(schema);
@@ -77,14 +91,19 @@ namespace Table {
return ret as R;
}
export function ofArrays<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, arrays: Arrays<S>): R {
export function ofArrays<S extends Schema, R extends Table<S> = Table<S>>(schema: S, arrays: Partial<Arrays<S>>): R {
const ret = Object.create(null);
const columns = Object.keys(schema);
ret._rowCount = arrays[columns[0]].length;
ret._rowCount = 0;
ret._columns = columns;
ret._schema = schema;
for (const k of columns) {
(ret as any)[k] = typeof arrays[k] !== 'undefined' ? Column.ofArray({ array: arrays[k], schema: schema[k] }) : Column.Undefined(ret._rowCount, schema[k]);
if (typeof arrays[k] !== 'undefined') {
(ret as any)[k] = Column.ofArray({ array: arrays[k]!, schema: schema[k] });
ret._rowCount = arrays[k]?.length;
} else {
(ret as any)[k] = Column.Undefined(ret._rowCount, schema[k]);
}
}
return ret as R;
}
@@ -153,7 +172,7 @@ namespace Table {
}
/** Sort and return a new table */
export function sort<T extends Table<S>, S extends Schema>(table: T, cmp: (i: number, j: number) => number) {
export function sort<T extends Table>(table: T, cmp: (i: number, j: number) => number) {
const indices = new Int32Array(table._rowCount);
for (let i = 0, _i = indices.length; i < _i; i++) indices[i] = i;
sortArray(indices, (_, i, j) => cmp(i, j));
@@ -177,7 +196,7 @@ namespace Table {
return ret;
}
export function areEqual<T extends Table<Schema>>(a: T, b: T) {
export function areEqual<T extends Table<any>>(a: T, b: T) {
if (a._rowCount !== b._rowCount) return false;
if (a._columns.length !== b._columns.length) return false;
for (const c of a._columns) {

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

@@ -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

@@ -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';
@@ -30,22 +28,24 @@ export const VisualQualityInfo = {
'lowest': {},
}
export type VisualQuality = keyof typeof VisualQualityInfo
export const VisualQualityNames = Object.keys(VisualQualityInfo)
export const VisualQualityOptions = VisualQualityNames.map(n => [n, n] as [VisualQuality, string])
export const VisualQualityNames = Object.keys(VisualQualityInfo) as VisualQuality[]
export const VisualQualityOptions = PD.arrayToOptions(VisualQualityNames)
//
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),
alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', isEssential: true, description: 'How opaque/transparent the representation is rendered.' }),
quality: PD.Select<VisualQuality>('auto', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }),
}
export type Params = typeof Params
export const ShadingCategory: PD.Info = { category: 'Shading' };
export const CustomQualityParamInfo: PD.Info = {
category: 'Custom Quality',
hideIf: (params: PD.Values<Params>) => typeof params.quality !== 'undefined' && params.quality !== 'custom'
};
export type Counts = { drawCount: number, groupCount: number, instanceCount: number }
export function createSimple(colorValue = ColorNames.grey, sizeValue = 1, transform?: TransformData) {
@@ -62,24 +62,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,12 @@
/**
* 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, GroupMapping, createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
import { createColors } from '../color-data';
import { createMarkers } from '../marker-data';
@@ -17,19 +17,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 +43,29 @@ 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
setBoundingSphere(boundingSphere: Sphere3D): void
}
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,71 @@ 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
},
setBoundingSphere(sphere: Sphere3D) {
Sphere3D.copy(boundingSphere, sphere)
currentHash = hashCode(lines)
}
}
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 +187,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 +226,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 +236,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,6 +99,27 @@ export namespace MeshBuilder {
}
}
/** 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, radialSegments }
@@ -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,102 @@ 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
setBoundingSphere(boundingSphere: Sphere3D): void
}
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
},
setBoundingSphere(sphere: Sphere3D) {
Sphere3D.copy(boundingSphere, sphere)
currentHash = hashCode(mesh)
}
}
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 +146,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 +161,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 +197,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)
@@ -358,9 +327,10 @@ export namespace Mesh {
export const Params = {
...BaseGeometry.Params,
doubleSided: PD.Boolean(false),
flipSided: PD.Boolean(false),
flatShaded: PD.Boolean(false),
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
flipSided: PD.Boolean(false, BaseGeometry.ShadingCategory),
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
}
export type Params = typeof Params
@@ -388,10 +358,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 +378,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 +393,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 +408,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,12 @@
/**
* 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, GroupMapping, createGroupMapping} from '../../util';
import { GeometryUtils } from '../geometry';
import { createColors } from '../color-data';
import { createMarkers } from '../marker-data';
@@ -14,7 +14,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 +23,94 @@ 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
setBoundingSphere(boundingSphere: Sphere3D): void
}
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
},
setBoundingSphere(sphere: Sphere3D) {
Sphere3D.copy(boundingSphere, sphere)
currentHash = hashCode(points)
}
}
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 +146,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 +184,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,91 @@ 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
setBoundingSphere(boundingSphere: Sphere3D): void
}
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
},
setBoundingSphere(sphere: Sphere3D) {
Sphere3D.copy(boundingSphere, sphere)
currentHash = hashCode(spheres)
}
}
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),
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
ignoreLight: PD.Boolean(false, BaseGeometry.ShadingCategory),
}
export type Params = typeof Params
@@ -87,10 +151,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 +173,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 +187,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,22 @@ 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
setBoundingSphere(boundingSphere: Sphere3D): void
}
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 +81,70 @@ 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
},
setBoundingSphere(sphere: Sphere3D) {
Sphere3D.copy(boundingSphere, sphere)
currentHash = hashCode(text)
}
}
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 +199,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 +261,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 +281,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),
}
}
}
@@ -69,9 +70,9 @@ export namespace TextureMesh {
export const Params = {
...BaseGeometry.Params,
doubleSided: PD.Boolean(false),
flipSided: PD.Boolean(false),
flatShaded: PD.Boolean(false),
doubleSided: PD.Boolean(false, BaseGeometry.CustomQualityParamInfo),
flipSided: PD.Boolean(false, BaseGeometry.ShadingCategory),
flatShaded: PD.Boolean(false, BaseGeometry.ShadingCategory),
}
export type Params = typeof Params
@@ -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

@@ -16,7 +16,7 @@ export function createCage(vertices: ArrayLike<number>, edges: ArrayLike<number>
return { vertices, edges }
}
export function copyCage(cage: Cage): Cage {
export function cloneCage(cage: Cage): Cage {
return {
vertices: new Float32Array(cage.vertices),
edges: new Uint32Array(cage.edges)

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 {
@@ -74,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

@@ -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-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -166,6 +166,19 @@ class MarchingCubesState {
const v1 = sfg(sf, hi, hj, hk);
const t = (this.isoLevel - v0) / (v0 - v1);
if (this.idField) {
const u = this.idFieldGet!(this.idField, li, lj, lk);
const v = this.idFieldGet!(this.idField, hi, hj, hk)
let a = t < 0.5 ? u : v;
// -1 means 'no id', check if the other cell has an id
if (a === -1) a = t < 0.5 ? v : u;
// -2 means 'ignore this cell'
if (a === -2) return -1
this.builder.addGroup(a);
} else {
this.builder.addGroup(0);
}
const id = this.builder.addVertex(
li + t * (li - hi),
lj + t * (lj - hj),
@@ -189,16 +202,6 @@ class MarchingCubesState {
n0z + t * (n0z - n1z)
)
if (this.idField) {
const u = this.idFieldGet!(this.idField, li, lj, lk);
const v = this.idFieldGet!(this.idField, hi, hj, hk)
let a = t < 0.5 ? u : v;
if (a < 0) a = t < 0.5 ? v : u;
this.builder.addGroup(a);
} else {
this.builder.addGroup(0);
}
return id;
}

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
@@ -44,25 +44,20 @@ export function MarchinCubesMeshBuilder(vertexChunkSize: number, mesh?: Mesh): M
ChunkedArray.add(groups, group);
},
addTriangle: (vertList: number[], a: number, b: number, c: number) => {
++triangleCount
ChunkedArray.add3(indices, vertList[a], vertList[b], vertList[c]);
const i = vertList[a], j = vertList[b], k = vertList[c]
// vertex indices <0 mean that the vertex was ignored and is not available
// and hence we don't add a triangle when this occurs
if (i >= 0 && j >= 0 && k >= 0) {
++triangleCount
ChunkedArray.add3(indices, i, j, k)
}
},
get: () => {
const vb = ChunkedArray.compact(vertices, true) as Float32Array;
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)
}
}
}
@@ -83,17 +78,22 @@ export function MarchinCubesLinesBuilder(vertexChunkSize: number, lines?: Lines)
ChunkedArray.add(groups, group);
},
addTriangle: (vertList: number[], a: number, b: number, c: number, edgeFilter: number) => {
if (AllowedContours[a][b] & edgeFilter) {
++linesCount
ChunkedArray.add2(indices, vertList[a], vertList[b])
}
if (AllowedContours[b][c] & edgeFilter) {
++linesCount
ChunkedArray.add2(indices, vertList[b], vertList[c])
}
if (AllowedContours[a][c] & edgeFilter) {
++linesCount
ChunkedArray.add2(indices, vertList[a], vertList[c])
const i = vertList[a], j = vertList[b], k = vertList[c]
// vertex indices <0 mean that the vertex was ignored and is not available
// and hence we don't add a triangle when this occurs
if (i >= 0 && j >= 0 && k >= 0) {
if (AllowedContours[a][b] & edgeFilter) {
++linesCount
ChunkedArray.add2(indices, vertList[a], vertList[b])
}
if (AllowedContours[b][c] & edgeFilter) {
++linesCount
ChunkedArray.add2(indices, vertList[b], vertList[c])
}
if (AllowedContours[a][c] & edgeFilter) {
++linesCount
ChunkedArray.add2(indices, vertList[a], vertList[c])
}
}
},
get: () => {

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>
*/
@@ -10,7 +10,8 @@ describe('renderable', () => {
it('calculateBoundingSphere', () => {
const position = new Float32Array([
0, 0, 0,
1, 0, 0
1, 0, 0,
-1, 0, 0,
])
const transform = new Float32Array([
1, 0, 0, 0,
@@ -26,15 +27,18 @@ describe('renderable', () => {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
2, 0, 0, 0
-1, 0, 0, 0
])
const { boundingSphere } = calculateBoundingSphere(
const { boundingSphere, invariantBoundingSphere } = calculateBoundingSphere(
position, position.length / 3,
transform, transform.length / 16
)
expect(boundingSphere.radius).toBe(1.5)
expect(boundingSphere.center).toEqual([1.5, 0.0, 0.0])
expect(invariantBoundingSphere.extrema).toEqual([[0, 0, 0], [1, 0, 0], [-1, 0, 0]])
expect(invariantBoundingSphere.radius).toBe(1)
expect(invariantBoundingSphere.center).toEqual([0, 0, 0])
expect(boundingSphere.radius).toBe(2)
expect(boundingSphere.center).toEqual([0, 0, 0])
})
})

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>
*/
@@ -65,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),
@@ -83,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,
@@ -104,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)
@@ -124,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()

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -13,7 +13,7 @@ import { Vec2 } from '../../mol-math/linear-algebra';
import { GLRenderingContext } from '../../mol-gl/webgl/compat';
export const QuadPositions = new Float32Array([
1.0, 1.0, -1.0, 1.0, -1.0, -1.0, // First triangle
1.0, 1.0, -1.0, 1.0, -1.0, -1.0, // First triangle
-1.0, -1.0, 1.0, -1.0, 1.0, 1.0 // Second triangle
])
@@ -42,11 +42,11 @@ function getArrayForTexture(gl: GLRenderingContext, texture: Texture, size: numb
}
export function readTexture(ctx: WebGLContext, texture: Texture, width?: number, height?: number) {
const { gl, framebufferCache } = ctx
width = defaults(width, texture.width)
height = defaults(height, texture.height)
const { gl, resources } = ctx
width = defaults(width, texture.getWidth())
height = defaults(height, texture.getHeight())
const size = width * height * 4
const framebuffer = framebufferCache.get('read-texture').value
const framebuffer = resources.framebuffer()
const array = getArrayForTexture(gl, texture, size)
framebuffer.bind()
texture.attachFramebuffer(framebuffer, 0)

View File

@@ -1,11 +1,10 @@
/**
* 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 { RenderableState, Renderable } from './renderable'
import { RenderableValues } from './renderable/schema';
import { idFactory } from '../mol-util/id-factory';
import { WebGLContext } from './webgl/context';
import { DirectVolumeValues, DirectVolumeRenderable } from './renderable/direct-volume';
@@ -20,53 +19,40 @@ const getNextId = idFactory(0, 0x7FFFFFFF)
export const getNextMaterialId = idFactory(0, 0x7FFFFFFF)
export interface BaseRenderObject<T extends RenderableValues> { id: number, type: string, values: T, state: RenderableState, materialId: number }
export interface MeshRenderObject extends BaseRenderObject<MeshValues> { type: 'mesh' }
export interface PointsRenderObject extends BaseRenderObject<PointsValues> { type: 'points' }
export interface SpheresRenderObject extends BaseRenderObject<SpheresValues> { type: 'spheres' }
export interface TextRenderObject extends BaseRenderObject<TextValues> { type: 'text' }
export interface LinesRenderObject extends BaseRenderObject<LinesValues> { type: 'lines' }
export interface DirectVolumeRenderObject extends BaseRenderObject<DirectVolumeValues> { type: 'direct-volume' }
export interface TextureMeshRenderObject extends BaseRenderObject<TextureMeshValues> { type: 'texture-mesh' }
export interface GraphicsRenderObject<T extends RenderObjectType = RenderObjectType> {
readonly id: number,
readonly type: T,
readonly values: RenderObjectValues<T>,
readonly state: RenderableState,
readonly materialId: number
}
export type RenderObjectType = 'mesh' | 'points' | 'spheres' | 'text' | 'lines' | 'direct-volume' | 'texture-mesh'
export type RenderObjectValues<T extends RenderObjectType> =
T extends 'mesh' ? MeshValues :
T extends 'points' ? PointsValues :
T extends 'spheres' ? SpheresValues :
T extends 'text' ? TextValues :
T extends 'lines' ? LinesValues :
T extends 'direct-volume' ? DirectVolumeValues :
T extends 'texture-mesh' ? TextureMeshValues : never
//
export type GraphicsRenderObject = MeshRenderObject | PointsRenderObject | SpheresRenderObject | TextRenderObject | LinesRenderObject | DirectVolumeRenderObject | TextureMeshRenderObject
export type RenderObjectKindType = {
'mesh': MeshRenderObject
'points': PointsRenderObject
'spheres': SpheresRenderObject
'text': TextRenderObject
'lines': LinesRenderObject
'direct-volume': DirectVolumeRenderObject
'texture-mesh': TextureMeshRenderObject
}
export type RenderObjectValuesType = {
'mesh': MeshValues
'points': PointsValues
'spheres': SpheresValues
'text': TextValues
'lines': LinesValues
'direct-volume': DirectVolumeValues
'texture-mesh': TextureMeshValues
}
export type RenderObjectType = keyof RenderObjectKindType
//
export function createRenderObject<T extends RenderObjectType>(type: T, values: RenderObjectValuesType[T], state: RenderableState, materialId: number): RenderObjectKindType[T] {
return { id: getNextId(), type, values, state, materialId } as RenderObjectKindType[T]
export function createRenderObject<T extends RenderObjectType>(type: T, values: RenderObjectValues<T>, state: RenderableState, materialId: number): GraphicsRenderObject<T> {
return { id: getNextId(), type, values, state, materialId } as GraphicsRenderObject<T>
}
export function createRenderable(ctx: WebGLContext, o: GraphicsRenderObject): Renderable<any> {
export function createRenderable<T extends RenderObjectType>(ctx: WebGLContext, o: GraphicsRenderObject<T>): Renderable<any> {
switch (o.type) {
case 'mesh': return MeshRenderable(ctx, o.id, o.values, o.state, o.materialId)
case 'points': return PointsRenderable(ctx, o.id, o.values, o.state, o.materialId)
case 'spheres': return SpheresRenderable(ctx, o.id, o.values, o.state, o.materialId)
case 'text': return TextRenderable(ctx, o.id, o.values, o.state, o.materialId)
case 'lines': return LinesRenderable(ctx, o.id, o.values, o.state, o.materialId)
case 'direct-volume': return DirectVolumeRenderable(ctx, o.id, o.values, o.state, o.materialId)
case 'texture-mesh': return TextureMeshRenderable(ctx, o.id, o.values, o.state, o.materialId)
case 'mesh': return MeshRenderable(ctx, o.id, o.values as MeshValues, o.state, o.materialId)
case 'points': return PointsRenderable(ctx, o.id, o.values as PointsValues, o.state, o.materialId)
case 'spheres': return SpheresRenderable(ctx, o.id, o.values as SpheresValues, o.state, o.materialId)
case 'text': return TextRenderable(ctx, o.id, o.values as TextValues, o.state, o.materialId)
case 'lines': return LinesRenderable(ctx, o.id, o.values as LinesValues, o.state, o.materialId)
case 'direct-volume': return DirectVolumeRenderable(ctx, o.id, o.values as DirectVolumeValues, o.state, o.materialId)
case 'texture-mesh': return TextureMeshRenderable(ctx, o.id, o.values as TextureMeshValues, o.state, o.materialId)
}
}
throw new Error('unsupported type')
}

View File

@@ -51,9 +51,6 @@ export const DirectVolumeSchema = {
elements: ElementsSpec('uint32'),
uAlpha: UniformSpec('f'),
uHighlightColor: UniformSpec('v3'),
uSelectColor: UniformSpec('v3'),
dUseFog: DefineSpec('boolean'),
uIsoValue: UniformSpec('f'),
uBboxMin: UniformSpec('v3'),

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