Compare commits

...

1172 Commits

Author SHA1 Message Date
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
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
Alexander Rose
944d370c14 0.3.2 2019-10-09 16:59:24 -07:00
Alexander Rose
74f9aa6af6 package updates 2019-10-09 16:55:44 -07:00
Alexander Rose
c20c9c9917 fixed setting CollapsableControls default state 2019-10-09 16:54:15 -07:00
Alexander Rose
4801435d72 add controls to create image 2019-10-09 16:10:36 -07:00
Alexander Rose
33fd105ef7 add ImagePass 2019-10-09 16:09:43 -07:00
Alexander Rose
3ea3fb8984 support rendering with transparent background 2019-10-09 16:08:48 -07:00
Alexander Rose
b4bbc544ca 0.3.1 2019-10-07 17:27:35 -07:00
Alexander Rose
5f880e920b add focus button to StructureSelectionControls 2019-10-07 17:26:16 -07:00
Alexander Rose
bcce801dd7 ensure sequence markers are up-to-date 2019-10-07 16:10:21 -07:00
Alexander Rose
00f9dcee4a added StructureSymmetryMatesFromModel transform, fixes for findMatesRadius 2019-10-07 15:31:54 -07:00
Alexander Rose
505af2bc96 fix help for scrollFocus 2019-10-07 12:04:20 -07:00
Alexander Rose
c217aab5fc reduced default unicell cage thickness 2019-10-07 11:23:50 -07:00
Alexander Rose
5d5fd0028f added operator name & hkl color themes 2019-10-07 11:20:10 -07:00
Alexander Rose
c88693dfdd improved color theme legend with labels from data 2019-10-07 11:18:08 -07:00
David Sehnal
0a16ec1bd2 mol-plugin: added TextInput wrapper and RGB color input 2019-10-05 14:52:00 +02:00
Alexander Rose
6f36a3c724 0.3.0 2019-10-04 17:21:16 -07:00
Alexander Rose
71496bd1ef package updates 2019-10-04 17:20:38 -07:00
Alexander Rose
c5a99a7c12 improved lociApply for whole structures 2019-10-04 17:07:08 -07:00
Alexander Rose
cfaf33d696 also look for 4 and 7 member sugar rings 2019-10-04 15:55:47 -07:00
Alexander Rose
e24c76d2bf update modifierkeys on mouse input 2019-10-04 15:40:14 -07:00
Alexander Rose
b6273205a2 removed duplicate type 2019-10-04 15:18:33 -07:00
Alexander Rose
b38193aa19 for unknown carbs draw polygonal prisms 2019-10-04 15:13:00 -07:00
Alexander Rose
f9cfacae23 sequence widget, bind onMouseLeave 2019-10-04 12:26:05 -07:00
Alexander Rose
ac46317dc6 fix lighting for orthographic projection close to camera 2019-10-04 11:53:38 -07:00
Alexander Rose
2b492a5a61 lighter monospace font 2019-10-04 10:44:08 -07:00
Alexander Rose
a2133657f0 chnaged label Unit->Chain in sequence widget 2019-10-04 10:42:07 -07:00
David Sehnal
e8de45789f mol-plugin: optimized sequence control 2019-10-04 16:52:36 +02:00
David Sehnal
3d2bd167ca mol-plugin: use monospace font for sequence 2019-10-04 15:34:59 +02:00
David Sehnal
504c8626dc mol-plugin: fixed PluginCommands.State.Highlight (wip) 2019-10-04 15:22:26 +02:00
Alexander Rose
f4b29dc7e0 ui, offset expanded color param 2019-10-03 17:24:24 -07:00
Alexander Rose
b34c5c743b tweaked ligandPlusConnected selection 2019-10-03 16:40:44 -07:00
Alexander Rose
c57311d6c0 carbohydrate improvements, updated carb table 2019-10-03 16:04:32 -07:00
Alexander Rose
4d786dc697 fix missing awaits in StructureRepresentationHelper.preset 2019-10-03 11:50:18 -07:00
Alexander Rose
062e3e055a show full compId for modified residues in sequence widget 2019-10-03 10:05:31 -07:00
Alexander Rose
1465174a45 Merge branch 'master' of https://github.com/molstar/molstar 2019-10-02 17:57:38 -07:00
Alexander Rose
cc00ada5a3 add model Unitcell representation 2019-10-02 17:57:19 -07:00
Alexander Rose
cbf312b62d calculate symmetry operators for transform around deposited coordinates 2019-10-02 17:56:41 -07:00
Alexander Rose
2be3144086 add .volume to SpacegroupCell 2019-10-02 17:55:03 -07:00
Alexander Rose
da3acd9d19 calculate model center as dynamic prop 2019-10-02 17:53:51 -07:00
Alexander Rose
34b048479b added arrayMinMax util 2019-10-02 17:53:03 -07:00
Alexander Rose
ca92931bf2 mol-geo improvements for mesh, cage and primitive 2019-10-02 17:52:48 -07:00
David Sehnal
0d3daeb823 mol-plugin: semi-transparent viewport controls background 2019-10-02 13:11:50 +02:00
David Sehnal
58b1d7e0eb mol-model & formats: added fallback when chem_comp category is missing 2019-10-02 12:46:23 +02:00
Alexander Rose
c5997ed056 reset buttons and modifier keys state when browser window looses focus 2019-10-01 14:11:01 -07:00
Alexander Rose
da1deee7f3 switched off marker interpolation for webgl2 2019-10-01 10:58:26 -07:00
Alexander Rose
a4eaff3175 add background to canvas icons for legibility with different render background colors 2019-10-01 10:30:44 -07:00
Alexander Rose
211cfc0bd3 fix highlight persisting after rotation 2019-10-01 09:52:18 -07:00
David Sehnal
c0f85b691d mol-plugin: reverted msp-layout-region background !important, because it broke the visual style 2019-10-01 17:42:42 +02:00
David Sehnal
6b93d58ea6 mol-plugin: updated color select control 2019-10-01 17:33:49 +02:00
Alexander Rose
5bce423b49 fully mark carbohydrate terminal links from StructureElement.Loci 2019-09-30 17:38:05 -07:00
Alexander Rose
01b0dde503 set plugin Context.customState: unknown 2019-09-30 16:38:55 -07:00
Alexander Rose
ed1bc8cb7d ensure single element loci have some volume in volume interaction behavior 2019-09-30 15:52:55 -07:00
Alexander Rose
abe559261b show insertion code in labels 2019-09-30 14:36:42 -07:00
Alexander Rose
b0cdf22cb8 various interaction behaviors improvements 2019-09-30 14:26:59 -07:00
Alexander Rose
a61ba71f1e handle mixed sizes in link visuals 2019-09-30 12:11:07 -07:00
Alexander Rose
7061d57559 tweak some bond distance thresholds 2019-09-30 11:06:49 -07:00
Alexander Rose
83a1e6c87c improved entity subtype assignment (use chem comp type) 2019-09-30 11:06:19 -07:00
Alexander Rose
c18888b8de 0.2.15 2019-09-27 17:19:57 -07:00
Alexander Rose
2d80935e00 ignore non-identity 'given' NCS operators 2019-09-27 17:18:14 -07:00
Alexander Rose
4287d158b6 add Mat3.isIdentity 2019-09-27 17:18:06 -07:00
Alexander Rose
4e9b569178 show logo in empty viewer 2019-09-27 16:48:10 -07:00
Alexander Rose
5d626d291b added viewer favicon 2019-09-27 16:48:00 -07:00
Alexander Rose
afa4a01c44 package updates 2019-09-27 16:41:53 -07:00
Alexander Rose
3c4a23c5a3 ensure msp-layout-region background 2019-09-27 15:22:27 -07:00
Alexander Rose
8d92c976d9 css 'select' tweaks 2019-09-27 13:19:01 -07:00
Alexander Rose
1a9adfad29 0.2.14 2019-09-27 11:17:53 -07:00
Alexander Rose
a9e9a5974d fix volumeserver cmd arg types 2019-09-27 11:10:11 -07:00
Alexander Rose
27160aa8fe fix stale array use 2019-09-26 15:33:52 -07:00
David Sehnal
6a71af00cf mol-plugin: Toast support 2019-09-26 16:18:57 +02:00
David Sehnal
6c0938db50 mol-plugin: added InitVolumeStreaming binding param 2019-09-26 15:11:13 +02:00
Alexander Rose
b76173c82f 0.2.13 2019-09-25 17:25:25 -07:00
Alexander Rose
0bcf2b1ff4 fix wrong style.overflow assignment 2019-09-25 16:07:25 -07:00
Alexander Rose
d074415a26 added more param docs 2019-09-25 11:55:00 -07:00
Alexander Rose
42f3e38026 0.2.12 2019-09-24 14:21:58 -07:00
Alexander Rose
74c16ee7ba package updates 2019-09-24 14:19:44 -07:00
Alexander Rose
f6ef22b917 added link cylinder to ellopsoids repr 2019-09-24 14:16:19 -07:00
Alexander Rose
c3f3d7efda check if atomistic before query modified 2019-09-24 12:20:38 -07:00
Alexander Rose
61d44efdc4 fix typo 2019-09-24 12:12:19 -07:00
Alexander Rose
ad200c86ec Merge branch 'master' of https://github.com/molstar/molstar 2019-09-24 12:10:54 -07:00
Alexander Rose
4aecf4e0b4 added ElementSequenceWrapper & ChainSequenceWrapper 2019-09-24 12:09:54 -07:00
Alexander Rose
d81f37c78b added AtomicUnit.residueCount 2019-09-24 12:07:26 -07:00
Alexander Rose
c2979ce5ab StructureSequence, handle empty coarse hierarchies 2019-09-24 12:06:55 -07:00
Alexander Rose
09c7edce88 smaller terminal links and dashed terminal links to metals 2019-09-24 10:11:42 -07:00
David Sehnal
beefb79258 mol-plugin: better default Structure Complex, extended StructureComplexElement transform 2019-09-24 15:17:05 +02:00
David Sehnal
529c6ac81c mol-plugin: fix SelectionFromScript & volume streaming bugs 2019-09-24 14:07:42 +02:00
Alexander Rose
84b988ea96 fix csv parser choking on newline at end of file 2019-09-23 16:46:35 -07:00
Alexander Rose
35e978efc9 added Table.toArrays 2019-09-23 16:45:58 -07:00
David Sehnal
19559d01f7 mol-state: call canAutoUpdate with correct parameters 2019-09-23 16:53:31 +02:00
David Sehnal
56cec343e2 Proteopedia wrapper fix 2019-09-23 16:12:40 +02:00
David Sehnal
20c9bd0130 mol-plugin: CSS fix 2019-09-23 15:56:48 +02:00
David Sehnal
1336997c58 mol-plugin: volume streaming support for LinkLoci, update "current box" when switching to surroundings, init behavior fix 2019-09-23 15:47:55 +02:00
David Sehnal
b178fdefdc mol-plugin: Camera focus duration default value fix 2019-09-23 14:59:44 +02:00
Alexander Rose
453d60060a ui, print length of sequences that are too long 2019-09-22 19:48:59 -07:00
Alexander Rose
901fac97a0 basic support for .3dg files 2019-09-22 19:44:37 -07:00
Alexander Rose
29b6a88343 check for Performance object capabilities 2019-09-22 19:43:13 -07:00
Alexander Rose
a2217c7fc6 fix csv parser chunking 2019-09-22 19:42:31 -07:00
Alexander Rose
3eec30aa42 sequence improvements, create sequence from coarse elements 2019-09-22 18:29:46 -07:00
Alexander Rose
f352e19e90 config for debugging 2019-09-22 09:32:19 -07:00
Alexander Rose
be65ef89bc 0.2.11 2019-09-20 17:23:25 -07:00
Alexander Rose
cfc46073c0 package updates 2019-09-20 17:22:39 -07:00
Alexander Rose
1819a2bbda add wwpdb provider for emdb contourLevel 2019-09-20 17:14:53 -07:00
Alexander Rose
aa3a42f94e added simple xml parser 2019-09-20 17:13:13 -07:00
Alexander Rose
4bff55b612 improve theme applicability checks 2019-09-20 15:08:55 -07:00
Alexander Rose
dbc4e09909 add 'disorder' to uncertainty theme label/description 2019-09-20 14:46:46 -07:00
Alexander Rose
0a074c8a66 add modelNum to location labels 2019-09-20 11:10:40 -07:00
Alexander Rose
8b314ebb75 add border to .msp-layout-standard 2019-09-20 10:20:12 -07:00
Alexander Rose
4dc0791aeb tweaked slider rail/handle color 2019-09-20 10:06:59 -07:00
Alexander Rose
e3483f11b1 adjusted maxCovalentHydrogenBondingLength 2019-09-20 09:32:45 -07:00
Alexander Rose
244a678ab7 fix Props.residue.label_comp_id for micro het 2019-09-19 19:11:57 -07:00
Alexander Rose
8e1d44fabc fixes, seq wrapper mark every loci, binding docs & cleanup 2019-09-19 18:33:44 -07:00
Alexander Rose
954a5b58e0 tweaked structure and volume surroundings behaviors 2019-09-19 18:10:07 -07:00
Alexander Rose
53223bc72b support EveryLoci in StructureRepresentation.mark 2019-09-19 17:10:28 -07:00
Alexander Rose
a11a1fa07e formating 2019-09-19 17:09:26 -07:00
Alexander Rose
9ab4001544 get Behavior defaultParams from transformer params 2019-09-19 17:09:15 -07:00
Alexander Rose
3e3b71d230 added Interval.ofLength 2019-09-19 17:08:36 -07:00
Alexander Rose
186929269b refactored bindings and interactivity 2019-09-19 17:08:20 -07:00
Alexander Rose
afa7a04af0 various ui tweaks, added CollapsableControls 2019-09-19 17:03:06 -07:00
Alexander Rose
2861d12f04 inline help for params, color theme legend ui 2019-09-16 16:47:58 -07:00
Alexander Rose
65e1212b2f wip, focusZoom action 2019-09-13 16:30:55 -07:00
Alexander Rose
47136c8b71 wip, focus input bindings 2019-09-13 12:57:46 -07:00
Alexander Rose
375b829562 wip, simplified camera class 2019-09-13 10:53:56 -07:00
Alexander Rose
2718d42b01 wip, input bindings, radius-based clipping 2019-09-12 16:47:19 -07:00
Alexander Rose
93d4118c0a Merge branch 'master' of https://github.com/molstar/molstar 2019-09-12 09:37:31 -07:00
David Sehnal
3a2a47af12 removed unused comments 2019-09-12 16:09:47 +02:00
David Sehnal
0eacdfca85 added transition duration effect to camera focus 2019-09-12 16:07:48 +02:00
David Sehnal
a7388be25f mol-canvas3d: fixed camera focus 2019-09-12 15:34:27 +02:00
Alexander Rose
5fcdcb1275 webpack.config cleanup, package updates 2019-09-11 17:57:54 -07:00
Alexander Rose
4635bdffb0 0.2.10 2019-09-11 16:11:33 -07:00
Alexander Rose
72b1c36111 basic microheterogeneity support 2019-09-11 15:50:57 -07:00
Alexander Rose
fc5ff601a8 typed generic (Column<T>) return of windowColumn 2019-09-11 15:49:13 -07:00
Alexander Rose
8dd142fc9f fixed ellipsoids with three identical eigenvalues (render sphere) 2019-09-11 10:35:14 -07:00
Alexander Rose
97f24293e2 0.2.9 2019-09-10 16:52:30 -07:00
Alexander Rose
f4beba5215 pdb-parser, aniso records 2019-09-10 16:49:10 -07:00
Alexander Rose
e2abe0f52a pdb-parser, atom-site fixes 2019-09-10 16:48:36 -07:00
Alexander Rose
5d18643374 pdb-parser, move atom-site methods to separate file 2019-09-10 15:50:04 -07:00
Alexander Rose
769f2a30c2 package updates 2019-09-10 15:43:00 -07:00
Alexander Rose
0e040d7744 added occupancy color theme 2019-09-10 15:31:57 -07:00
Alexander Rose
7600d0a44e add ellipsoid repr showing mmcif thermal displacement 2019-09-10 15:10:58 -07:00
Alexander Rose
9113d6d189 only show applicable repr types in ui 2019-09-10 15:10:13 -07:00
Alexander Rose
fd9dac86b9 combined duplicate chem_comp_bond props 2019-09-10 15:09:33 -07:00
Alexander Rose
fe1f3bd4bb use structure.uniqueResidues, removed duplicated code 2019-09-10 11:12:00 -07:00
Alexander Rose
d950718110 linalg: return out array for .toArray, create symmetric mat3 2019-09-10 10:50:34 -07:00
Alexander Rose
4be903b9d5 added atom_site_anisotrop to mmcif schema 2019-09-09 17:35:16 -07:00
Alexander Rose
8050644869 mat3 symmetricEigenvalues and eigenvectors 2019-09-09 17:32:45 -07:00
Alexander Rose
347c1986df require output object for Tensor.to* methods 2019-09-09 17:32:02 -07:00
David Sehnal
eac4a8988b mol-model: added Model.entryId; mol-plugin: toggle validation tooltip; fixed using correct entryId for various custom properties 2019-09-05 16:09:05 +02:00
Alexander Rose
25137f29d2 typescript 3.6 compat fixes 2019-09-04 17:26:42 -07:00
Alexander Rose
4601fe74bb packaage updates 2019-09-04 17:26:21 -07:00
Alexander Rose
f0b54e9cbf 0.2.8 2019-09-04 12:18:43 -07:00
Alexander Rose
fdb45c3624 improved canvas3d.clear 2019-09-04 12:17:22 -07:00
Alexander Rose
f3b1ec0ed8 Merge branch 'master' of https://github.com/molstar/molstar 2019-09-04 12:05:42 -07:00
Alexander Rose
79510614b9 add .uniqueElementCount and .polymerUnitCount to Structure 2019-09-04 12:04:58 -07:00
Alexander Rose
f8c9bc6812 add volume-server npm start script 2019-09-04 12:03:44 -07:00
Alexander Rose
85d35aab90 handle special CCP4 spacegroup numbers 2019-09-04 12:03:14 -07:00
David Sehnal
f5b09dbd10 mol-plugin: added customState to PluginContext 2019-09-03 14:42:59 +02:00
Alexander Rose
57ea322fd6 cellpack loader tweak 2019-08-30 19:09:53 -07:00
Alexander Rose
c31aab5594 wip, cellpack loader 2019-08-30 18:56:30 -07:00
Alexander Rose
a5556e8c41 imroved sequence widget entity dropdown 2019-08-30 18:55:46 -07:00
Alexander Rose
0ce2966c47 lazy calculation of Structure.polymerResidueCount 2019-08-30 18:54:54 -07:00
Alexander Rose
f2c04a13af adjust grid-cell-count in partitionAtomicUnitByResidue 2019-08-30 17:28:33 -07:00
Alexander Rose
60ba0de219 CifField creation optimizations 2019-08-30 17:27:58 -07:00
Alexander Rose
99e515604e skip identical positions in spheres and lines bounding sphere calculation 2019-08-30 17:26:52 -07:00
Alexander Rose
84dfa60fc2 added CifCategory.ofTable and 'list' valueType support for CifField.ofColumn 2019-08-29 17:42:30 -07:00
Alexander Rose
a753095f92 added ImportString and ImportJson transforms 2019-08-29 17:31:44 -07:00
David Sehnal
ce0ff2fed8 mol-model: optionally compute centroid based bounding sphere (disabled for now) 2019-08-29 15:46:47 +02:00
Alexander Rose
1c1deb5ee7 0.2.7 2019-08-28 17:48:22 -07:00
Alexander Rose
e28749b794 overpaint improvements, merge and filter 2019-08-28 17:34:41 -07:00
Alexander Rose
7566cc89ca added transperancy-from-bundle, improved overpaint 2019-08-28 15:29:17 -07:00
Alexander Rose
8b76c09559 added Script namespace with helpers 2019-08-28 15:28:35 -07:00
Alexander Rose
c60d7d3faf removed console statements 2019-08-28 12:49:33 -07:00
Alexander Rose
3eb3d1e27e re-apply select-mark to all representation of an updated structure 2019-08-28 12:43:23 -07:00
Alexander Rose
3083c7d9e0 overpaint improvements 2019-08-28 12:04:47 -07:00
Alexander Rose
9184219976 StructureElement loci & bundle fixes 2019-08-28 12:03:26 -07:00
Alexander Rose
90a3d302f3 loci helper methods, isEmpty 2019-08-28 12:00:39 -07:00
Alexander Rose
02dd5f9d11 fix, set new source in StructureRepresentation3D.update 2019-08-27 17:05:10 -07:00
Alexander Rose
3685c92b52 add missing info in ObjectList param 2019-08-27 17:04:23 -07:00
Alexander Rose
e1a04c8b0b renamed StructureSelection-related transforms 2019-08-27 14:51:10 -07:00
Alexander Rose
5a704b7974 renamed StructureElement.Query to StructureElement.Bundle 2019-08-27 14:29:10 -07:00
Alexander Rose
2376d0a9c6 split up StructureElement 2019-08-27 13:54:00 -07:00
Alexander Rose
87e0c05ec0 tweaked cellpack loader: baseUrl, binary membrane file 2019-08-27 09:54:27 -07:00
Alexander Rose
8140b75086 fixed polymer/chain-id color theme for coarse models 2019-08-27 09:53:38 -07:00
Alexander Rose
1f32d5469e ignoreHydrogens in cellpack presets 2019-08-26 17:30:53 -07:00
Alexander Rose
b09549439f added StructureElement.Stats and improved loci-labels 2019-08-26 17:14:32 -07:00
Alexander Rose
e1b7a5b267 wip, structure tools, repr presets 2019-08-26 17:13:28 -07:00
Alexander Rose
1ed420aeb7 added entity.subtype based on _entity_poly.type and _pdbx_entity_branch.type 2019-08-26 17:10:12 -07:00
Alexander Rose
301a23b1e0 refactored cellpack curve to resuse Vec3 objects 2019-08-25 21:42:07 -07:00
Alexander Rose
e53bb51f15 removed superfluous gl.viewport call 2019-08-25 21:05:18 -07:00
Alexander Rose
4e6e8fed82 add rna in hiv cellpack models 2019-08-25 21:04:40 -07:00
Alexander Rose
b2809ad631 handle curves/fibers in mesoscale models 2019-08-24 16:32:49 -07:00
Alexander Rose
37648b41ea added uInteriorDarkening factor to renderer 2019-08-23 22:28:27 -07:00
Alexander Rose
fac183c2ee allow partial reprParams in StructureRepresentation3DHelpers.createParams 2019-08-23 22:27:20 -07:00
Alexander Rose
b113448e01 added 'serve' npm script 2019-08-23 22:26:25 -07:00
Alexander Rose
c585ba7791 color theme and list tweaks, added turbo 2019-08-23 12:23:56 -07:00
Alexander Rose
afb6c65c48 fix sequence widget update on state changes 2019-08-23 12:23:15 -07:00
Alexander Rose
527e91c9eb fix Structure.unitIndexMap creation when units are unsorted 2019-08-23 12:22:15 -07:00
Alexander Rose
9e2ef87611 don't use Mesh.uniformTriangleGroup when WebGL2 is available 2019-08-22 16:17:22 -07:00
Alexander Rose
f2342c3273 added structure gaussian surface complex-visual 2019-08-22 12:07:07 -07:00
Alexander Rose
347981792e added Structure.serialMapping 2019-08-22 12:04:05 -07:00
Alexander Rose
032d2f2784 removed fillUniform, use Array.fill 2019-08-22 08:44:32 -07:00
Alexander Rose
ddc1119a80 0.2.6 2019-08-21 13:38:22 -07:00
Alexander Rose
0fe6774f04 fixed comparison and typo 2019-08-21 13:37:04 -07:00
Alexander Rose
2a71e44ae8 updated packages 2019-08-21 13:36:37 -07:00
Alexander Rose
1257f1ce85 label tweak 2019-08-21 12:17:05 -07:00
Alexander Rose
07cd9f4b16 css fix 2019-08-21 12:09:19 -07:00
Alexander Rose
ed5ff1c9ce slider ui tweaks 2019-08-21 10:13:42 -07:00
Alexander Rose
7ffc2db76e fix trackball controls dropping inputs 2019-08-21 09:42:30 -07:00
Alexander Rose
03067ca6d6 wip, structure tools quality option 2019-08-20 16:39:32 -07:00
Alexander Rose
a69f1337d7 color refactoring 2019-08-20 12:51:27 -07:00
Alexander Rose
5e83c3350a added Structure.root 2019-08-20 12:51:16 -07:00
Alexander Rose
f051d2d01e use model.entry in volume-streaming 2019-08-20 12:48:59 -07:00
Alexander Rose
257340283b wip, color list refactoring 2019-08-20 09:53:34 -07:00
Alexander Rose
e769d77ec8 wip, color theme refactoring 2019-08-19 18:50:46 -07:00
Alexander Rose
1923535918 limit max number of generated colors 2019-08-19 12:44:34 -07:00
Alexander Rose
dd3fc5620b label fix 2019-08-19 12:43:52 -07:00
Alexander Rose
7165258431 sequence widget fixes 2019-08-19 12:43:31 -07:00
Alexander Rose
df9b367e0b tweaked structure labeling 2019-08-19 12:43:08 -07:00
Alexander Rose
ed1ae71f71 optimized repr loci iteration, marking and extendToWholeChains 2019-08-18 13:01:31 -07:00
Alexander Rose
1c58bca454 fix wrong props object in Structure creation 2019-08-18 12:58:01 -07:00
Alexander Rose
c01be0644e improved handling of polymer trace termini 2019-08-16 20:01:20 -07:00
Alexander Rose
66b9f6104c improved low-poly geo (cylinder, sheet, tube, ribbon) 2019-08-16 17:14:57 -07:00
Alexander Rose
af4d2c4003 Merge branch 'master' of https://github.com/molstar/molstar 2019-08-15 17:18:02 -07:00
Alexander Rose
3b1a2f19a4 wip, structure tools, repr presets 2019-08-15 17:15:50 -07:00
Alexander Rose
6b874786a8 only extract CrossLinkRestraints when needed 2019-08-15 16:07:58 -07:00
Alexander Rose
f9d2560468 fixed symmetry operator when NCS operators are present 2019-08-15 16:07:18 -07:00
David Sehnal
961034584a model-server: config can be (partially) provided as a separate JSON file 2019-08-15 17:22:23 +02:00
David Sehnal
f6d11a59a3 model-server: wip config refactoring 2019-08-15 17:11:55 +02:00
Alexander Rose
53ee758378 wip, sequence widget 2019-08-14 17:21:53 -07:00
Alexander Rose
c80c630810 param control tweaks 2019-08-14 17:21:40 -07:00
Alexander Rose
13cd6e82ba added StructureFromTrajectory, improved multi-model structures 2019-08-14 17:20:40 -07:00
David Sehnal
f2966032d9 model-server: rest api, swagger ui, response schemas, bug fixes 2019-08-14 15:04:07 +02:00
David Sehnal
76503b52f5 wip model-server 2019-08-14 14:21:13 +02:00
Alexander Rose
aa24be8e9b type fixes 2019-08-13 16:44:19 -07:00
Alexander Rose
5d7bb894d4 wip, structure tools 2019-08-13 16:18:44 -07:00
Alexander Rose
fcf559fa6b toggle hydrogens in structure view tools 2019-08-13 15:55:32 -07:00
Alexander Rose
27963b5aed added option to ignore hydrogens in structure representations 2019-08-13 14:54:38 -07:00
Alexander Rose
40d539c4aa viewport ui improvements: mouse handling, config 2019-08-13 11:42:42 -07:00
David Sehnal
d1433aaf7b mol-state: added StateTree.subtreeHasRef 2019-08-13 17:19:36 +02:00
Alexander Rose
8f4bf9a314 added outsideControls to PluginLayoutStateParams 2019-08-12 17:30:27 -07:00
Alexander Rose
cca0f407f6 improved StructureRepresentationHelper 2019-08-12 16:47:09 -07:00
Alexander Rose
1e9e41754a added isApplicable support to representation provider & registry 2019-08-12 16:46:48 -07:00
David Sehnal
38dc2d6e26 mol-script: macro support 2019-08-12 16:00:53 +02:00
David Sehnal
ea46b1c8c8 mol-script: bond* => link*; make link tests "covalent" by default; wip link tests 2019-08-12 15:29:50 +02:00
Alexander Rose
5846d7c4b4 wip, structure view tools 2019-08-09 18:40:07 -07:00
Alexander Rose
214176ce2e handle incompatibility of StructureElement.Query and Structure 2019-08-09 18:18:32 -07:00
Alexander Rose
ee4cb214e1 updated cif schemas 2019-08-09 18:16:58 -07:00
Alexander Rose
01cca9e8a6 use .componentDidUpdate in SliderBase 2019-08-09 11:08:53 -07:00
Alexander Rose
7a23493e19 package updates 2019-08-09 10:26:41 -07:00
Alexander Rose
e109f069a8 wip, structure ui tools 2019-08-08 17:46:23 -07:00
Alexander Rose
82e667e402 added chemCompType and other mol-script improvements 2019-08-08 17:16:47 -07:00
Alexander Rose
c28feb2d1c added objectPrimitive to unit and mol-script 2019-08-08 13:56:21 -07:00
Alexander Rose
8447a2d4f2 add missing alias for cbrt 2019-08-08 13:54:20 -07:00
Alexander Rose
f9ebf1c399 better renderer defaults (occlusian radius, cmaera dist clipping) 2019-08-08 13:53:49 -07:00
Alexander Rose
286b27720a StructureElement fixes 2019-08-07 17:04:10 -07:00
Alexander Rose
dc0e54c275 Merge branch 'master' of https://github.com/molstar/molstar 2019-08-07 08:37:26 -07:00
David Sehnal
b710291d5e mol-plugin: animation controls tweak 2019-08-07 12:15:36 +02:00
David Sehnal
d84d5f38f5 mol-model: implemented includeConnected query 2019-08-07 12:10:24 +02:00
Alexander Rose
9bea13438f improved picking pass 2019-08-06 12:50:45 -07:00
Alexander Rose
2fc28f6005 improved StructureElement.Query 2019-08-06 11:16:50 -07:00
Alexander Rose
bb07d6ec56 imroved download helper and state download 2019-08-06 10:02:49 -07:00
Alexander Rose
3cdfd04048 improved element loci remap, added SortedArray.indexOfInRange 2019-08-06 08:38:36 -07:00
Alexander Rose
2120a258f9 remap loci per repr not per visual 2019-08-06 08:30:21 -07:00
Alexander Rose
2b5e49d215 use LociStructureSelection in plugin structure tools 2019-08-05 15:09:16 -07:00
Alexander Rose
b88bf9bdf2 LociStructureSelection based on StructureElement.Query 2019-08-05 15:08:43 -07:00
Alexander Rose
df0f15d132 added StructureElement.Query for Loci serialization 2019-08-05 15:08:36 -07:00
Alexander Rose
a6319bfb3d tweakes to avoid cyclic import issues 2019-08-05 12:32:01 -07:00
Alexander Rose
d6278cb3eb sorted-ranges, .areEqual and .forEach 2019-08-05 12:30:53 -07:00
Alexander Rose
560da38687 fixed exceptBy and structureSubtract 2019-08-03 14:55:55 -07:00
Alexander Rose
83ba9d8776 avoid .apply for long arg lists 2019-08-02 21:53:59 -07:00
Alexander Rose
ee776e6e3e wip, structure tools 2019-08-02 17:18:07 -07:00
Alexander Rose
3e52496b4e sequence widget, chain -> unit 2019-08-02 17:17:21 -07:00
Alexander Rose
2659b96008 added math.cbrt to mol-script 2019-08-02 17:16:47 -07:00
Alexander Rose
a8be84701b improved screendoor transparency with multi-sample 2019-08-02 10:23:16 -07:00
Alexander Rose
0c79aa1709 show number of selected elements and structures 2019-08-01 16:09:33 -07:00
Alexander Rose
e57a19857f improved pdb reader, entity 2019-08-01 12:36:10 -07:00
Alexander Rose
469dd05cd9 added Column.ofIntTokens, .ofFloatTokens, .ofStringTokens 2019-08-01 12:34:47 -07:00
Alexander Rose
fb72db61bd code simplification 2019-08-01 12:34:01 -07:00
Alexander Rose
c285e30ee0 improved gro format reading 2019-08-01 10:09:20 -07:00
Alexander Rose
789a327322 improved large chain partitioning 2019-08-01 10:06:50 -07:00
Alexander Rose
b8d2021599 partition very large atomic chains per residue 2019-07-30 16:28:00 -07:00
Alexander Rose
36eae744af ensure that "single atom chains" units have same entity id 2019-07-30 16:24:54 -07:00
Alexander Rose
00df6ae52a don't show sequences > 10000 in widget 2019-07-30 16:23:05 -07:00
Alexander Rose
023b65572e viewer, option to load files without adding visuals 2019-07-30 16:22:34 -07:00
Alexander Rose
904e9b869c wip, cellpack loader improvements 2019-07-30 12:03:26 -07:00
Alexander Rose
6f204b960d Merge branch 'master' into meso 2019-07-30 09:12:08 -07:00
Alexander Rose
6217a51fa5 optimized toScriptExpression 2019-07-29 11:32:02 -07:00
Alexander Rose
f1edb05c5c fixed sorted-ranges spec 2019-07-29 10:03:54 -07:00
Alexander Rose
55bd27bb97 wip, structure selection tools 2019-07-26 17:32:51 -07:00
Alexander Rose
e2c9b601a6 wip, structure tools refactoring 2019-07-26 16:36:27 -07:00
Alexander Rose
238191660e Fixed StructureElement.Loci.toScriptExpression 2019-07-26 16:12:03 -07:00
Alexander Rose
0b175acc25 wip, structure tool controls 2019-07-26 15:50:26 -07:00
Alexander Rose
02865cbece trace-iterator to work with unit subsets 2019-07-26 12:44:40 -07:00
Alexander Rose
a3e14bf579 improved sorted-ranges and docs 2019-07-26 12:44:08 -07:00
Alexander Rose
1d502cbb54 loci remapping 2019-07-25 13:49:04 -07:00
Alexander Rose
4894b110b9 fixes, SortedRanges and AtomicPolymerTraceIterator 2019-07-25 10:58:42 -07:00
Alexander Rose
cefd0440a0 docs 2019-07-25 10:57:26 -07:00
David Sehnal
296bfb343e mol-plugin: updated 'select animation' icon 2019-07-24 07:45:41 +02:00
David Sehnal
bc91f0d3ff Support multiple models in StructureElement.Loci.toScriptExpression 2019-07-24 07:35:03 +02:00
David Sehnal
aaa8215a6d Fixed StructureElement.Loci.toScriptExpression 2019-07-24 07:11:38 +02:00
Alexander Rose
bf0b37895d handle modified base rings (DP, DZ) 2019-07-23 15:51:17 -07:00
Alexander Rose
0810ed411d nucleotide cartoon, detect Purin/Pyrimidin from geometry 2019-07-23 15:16:22 -07:00
Alexander Rose
ff8fec542c wip, overpaint controls, overpaint clearing 2019-07-23 12:04:02 -07:00
Alexander Rose
8fb7308572 wip, OverpaintControls 2019-07-22 17:35:17 -07:00
Alexander Rose
c9b7049532 fixed ExplodeStructureRepresentation3D 2019-07-22 17:34:46 -07:00
Alexander Rose
da71332de1 add 'sel.atom.all' macro 2019-07-22 17:34:30 -07:00
Alexander Rose
a0de8dd9f9 fixed seq widget update on object change 2019-07-22 12:14:03 -07:00
Alexander Rose
e226f27041 fixed wrong property use in seq widget 2019-07-22 12:04:27 -07:00
Alexander Rose
804a04d9f8 fixed coarse trace-iterator direction vectors 2019-07-22 11:52:00 -07:00
Alexander Rose
3be06bb3b6 wip, cellpack loader 2019-07-21 18:28:45 -07:00
Alexander Rose
c7b618c246 lighting demo 2019-07-21 18:13:10 -07:00
Alexander Rose
55d990962f better entity handling for pdb files 2019-07-20 15:58:22 -07:00
Alexander Rose
53e0a36539 improved readme deploy section 2019-07-19 18:38:13 -07:00
Alexander Rose
ed7a5219bf 0.2.5 2019-07-19 17:43:32 -07:00
Alexander Rose
8b49ccdc08 tweaked bottom and top height 2019-07-19 17:41:40 -07:00
Alexander Rose
04fd3ade5f improved canvas3d.resetCamera 2019-07-19 14:52:20 -07:00
Alexander Rose
48985cd49d improved scene commit handling for canvas3d and debug-helper 2019-07-19 14:40:45 -07:00
Alexander Rose
dd0707a8a5 fix renderer.spec test 2019-07-19 10:12:22 -07:00
Alexander Rose
b41ebcbbc8 Merge branch 'master' of https://github.com/molstar/molstar
# Conflicts:
#	src/mol-canvas3d/camera.ts
#	src/mol-canvas3d/canvas3d.ts
2019-07-19 09:50:03 -07:00
Alexander Rose
991d2e3a57 async gl repr object handling 2019-07-19 09:46:27 -07:00
Alexander Rose
7f4ac6782f camera tweaks 2019-07-19 09:45:26 -07:00
Alexander Rose
7e7e30a82e fix: removed useless z-sort 2019-07-19 09:44:11 -07:00
Alexander Rose
08e92f12d3 improved MolecularSurface calc: projectToriiRange 2019-07-19 09:42:09 -07:00
Alexander Rose
d713ea6a76 ModelIndex color theme 2019-07-19 09:41:06 -07:00
Alexander Rose
0924020f24 updated packages 2019-07-19 09:11:53 -07:00
David Sehnal
9f10af3ba6 proteopedia-wrapper: clipping commands; mol-canvas3d: camera.getFocus optional direction 2019-06-26 13:41:53 +02:00
Alexander Rose
f754026cc5 better entity placeholder 2019-06-22 12:26:28 -07:00
Alexander Rose
321d98f4c1 hetero sequence wrapper 2019-06-22 11:35:11 -07:00
Alexander Rose
58a49a8512 fix handling of structure loci selection 2019-06-22 08:12:07 -07:00
Alexander Rose
98bb9575b6 simplified polymer sequence wrapper 2019-06-22 07:45:04 -07:00
Alexander Rose
f10a135dea sequence view, better handling of missing residues, full structure loci 2019-06-22 07:34:20 -07:00
Alexander Rose
f300e524d1 updated packages 2019-06-21 17:36:38 -07:00
Alexander Rose
87028c0a0b 0.2.4 2019-06-21 17:21:59 -07:00
Alexander Rose
8ea23e6965 Merge branch 'master' into seq 2019-06-21 17:19:26 -07:00
Alexander Rose
f9d8942814 basic support for missing residues 2019-06-21 16:55:28 -07:00
Alexander Rose
b40df2f1e3 sequence, on state tree change improvments 2019-06-21 16:55:12 -07:00
Alexander Rose
884cb0d9a4 sequence widget refactoring 2019-06-21 12:54:22 -07:00
Alexander Rose
ef1ccd4286 cif schema updates 2019-06-21 12:44:28 -07:00
Alexander Rose
898abda373 sequence & interactivity tweaks 2019-06-21 11:06:49 -07:00
Alexander Rose
e42c664a8c fixes: StructureElement.Loci.union, Structure.parent 2019-06-21 10:56:06 -07:00
Alexander Rose
987bf47827 save interactivity props in state 2019-06-21 09:29:03 -07:00
Alexander Rose
6201dd1d74 improved xtal symmetry support for props & sequence 2019-06-21 09:11:38 -07:00
David Sehnal
5ed17ce4e5 proteopedia-wrapper: evolutionary coloring on current representation 2019-06-21 12:47:14 +02:00
Alexander Rose
e301eca9c2 wip, sequence view, select options 2019-06-20 15:50:31 -07:00
Alexander Rose
8a4ef015a2 added StructureElement.set 2019-06-20 15:42:45 -07:00
Alexander Rose
67f3f3fdbb improved AtomsQueryParams.unitTest and StructureProperties.unit 2019-06-20 15:42:23 -07:00
Alexander Rose
adc5b559cd various tweaks 2019-06-20 15:35:55 -07:00
Alexander Rose
bbaa637118 wip, sequence selector 2019-06-19 17:45:50 -07:00
Alexander Rose
a3094b4d19 wip, per-chain sequence widget 2019-06-19 17:03:20 -07:00
Alexander Rose
c3f937e113 sequence widget refactoring 2019-06-19 14:17:49 -07:00
Alexander Rose
04df327939 renamed lociExpansion to granularity 2019-06-19 12:30:19 -07:00
Alexander Rose
b1a0f46ade improved link loci handling for interactivity 2019-06-19 12:18:53 -07:00
Alexander Rose
389e249862 use PurePluginUIComponent for Residue 2019-06-19 11:48:36 -07:00
Alexander Rose
cfcf9f6818 wip, plugin interactivity 2019-06-18 17:28:57 -07:00
Alexander Rose
bcb8419f37 init repr3d and seq view marker with global selection 2019-06-18 14:31:22 -07:00
Alexander Rose
7d24bcf1dc tweaked resolution quality settings 2019-06-18 14:24:47 -07:00
Alexander Rose
8d0f7a2dc7 factored-out marker-action 2019-06-18 11:48:59 -07:00
Alexander Rose
a7cb7beaa8 Merge branch 'master' into seq 2019-06-18 09:04:33 -07:00
David Sehnal
3c9b82dc04 proteopedia-plugin: Load asym unit fix 2019-06-18 15:42:29 +02:00
David Sehnal
9dba6d5371 proteopedia-wrapper: tweak 2019-06-18 13:53:04 +02:00
David Sehnal
a65bba0969 proteopedia-wrapper: better HET group focusing 2019-06-18 13:39:23 +02:00
David Sehnal
175e009152 proteopedia-wrapper: fix assembly loading 2019-06-18 13:01:38 +02:00
Alexander Rose
f6b2c0b2ba wip, sequence view 2019-06-17 16:44:38 -07:00
Alexander Rose
ea419c68ae removed old unused ui code 2019-06-17 15:41:03 -07:00
Alexander Rose
40cf348d40 simple (entity) sequence view 2019-06-17 15:40:51 -07:00
Alexander Rose
93ea759a71 StateTreeSpine.current tweaks 2019-06-17 15:39:12 -07:00
Alexander Rose
3e50377eb8 use as const to quickly make class props readonly 2019-06-17 15:29:37 -07:00
Alexander Rose
3fbd1f8dc4 StructureElementSelectionManager.tryGetRange in both directions 2019-06-17 15:27:22 -07:00
Alexander Rose
f03ce68513 plugin interaction helpers refactoring 2019-06-17 14:37:24 -07:00
Alexander Rose
50e2d542df add getModifiers input helper 2019-06-17 14:33:32 -07:00
Alexander Rose
e53e739d18 ignore non StructureElement loci in StructureElementSelectionManager 2019-06-17 14:32:47 -07:00
Alexander Rose
dfb7f7811f support coarse elements in atomGroups generator 2019-06-14 18:59:37 -07:00
896 changed files with 66462 additions and 24209 deletions

65
.eslintrc.json Normal file
View File

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

View File

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

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

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

View File

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

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
@@ -85,12 +92,13 @@ and navigate to `build/viewer`
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/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**
@@ -142,6 +150,8 @@ To get syntax highlighting for shader and graphql files add the following to Vis
npm publish
## Deploy
npm run test
npm run build
node ./scripts/deploy.js # currently updates the viewer on molstar.org/viewer
## Contributing

View File

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

View File

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

View File

@@ -0,0 +1,12 @@
schema: https://data-beta.rcsb.org/graphql
documents: './src/mol-model-props/rcsb/graphql/symmetry.gql.ts'
generates:
'./src/mol-model-props/rcsb/graphql/types.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 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 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

16890
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "0.2.3",
"version": "0.6.0-dev.3",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {
@@ -11,18 +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-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html}\" lib/",
"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-extra": "cpx \"src/**/*.{scss,woff,woff2,ttf,otf,eot,svg,html}\" lib/ --watch",
"watch-webpack": "webpack -w --mode development --display minimal",
"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 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-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"
@@ -30,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",
@@ -61,55 +74,67 @@
],
"license": "MIT",
"devDependencies": {
"@graphql-codegen/add": "^1.13.0",
"@graphql-codegen/cli": "^1.13.0",
"@graphql-codegen/time": "^1.13.0",
"@graphql-codegen/typescript": "^1.13.0",
"@graphql-codegen/typescript-graphql-files-modules": "^1.13.0",
"@graphql-codegen/typescript-graphql-request": "^1.13.0",
"@graphql-codegen/typescript-operations": "^1.13.0",
"@types/cors": "^2.8.6",
"@typescript-eslint/eslint-plugin": "^2.23.0",
"@typescript-eslint/parser": "^2.23.0",
"benchmark": "^2.1.4",
"circular-dependency-plugin": "^5.0.2",
"concurrently": "^4.1.0",
"cpx": "^1.5.0",
"css-loader": "^3.0.0",
"circular-dependency-plugin": "^5.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.0.0",
"fs-extra": "^8.0.1",
"graphql-code-generator": "^0.18.2",
"graphql-codegen-time": "^0.18.2",
"graphql-codegen-typescript-template": "^0.18.2",
"jest": "^24.8.0",
"file-loader": "^5.1.0",
"fs-extra": "^8.1.0",
"http-server": "^0.12.1",
"jest": "^25.1.0",
"jest-raw-loader": "^1.0.1",
"mini-css-extract-plugin": "^0.7.0",
"node-sass": "^4.12.0",
"raw-loader": "^3.0.0",
"resolve-url-loader": "^3.1.0",
"sass-loader": "^7.1.0",
"simple-git": "^1.113.0",
"style-loader": "^0.23.1",
"ts-jest": "^24.0.2",
"tslint": "^5.17.0",
"typescript": "^3.5.1",
"webpack": "^4.33.0",
"webpack-cli": "^3.3.4"
"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": "0.0.36",
"@types/express": "^4.17.0",
"@types/jest": "^24.0.13",
"@types/node": "^12.0.8",
"@types/node-fetch": "^2.3.5",
"@types/react": "^16.8.19",
"@types/react-dom": "^16.8.4",
"@types/swagger-ui-dist": "3.0.0",
"@types/webgl2": "0.0.4",
"@types/compression": "1.7.0",
"@types/express": "^4.17.3",
"@types/jest": "^25.1.4",
"@types/node": "^13.9.0",
"@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.3.1",
"graphql": "^14.6.0",
"immer": "^6.0.1",
"immutable": "^3.8.2",
"node-fetch": "^2.6.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"rxjs": "^6.5.2",
"swagger-ui-dist": "^3.22.3",
"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 {
@@ -19,4 +19,12 @@ export class BasicWrapperControls extends PluginUIComponent {
<TransformUpdaterControl nodeRef='ihm-visual' header={{ name: 'I/HM Visual' }} initiallyCollapsed={true} />
</div>;
}
}
export class CustomToastMessage extends PluginUIComponent {
render() {
return <>
Custom <i>Toast</i> content. No timeout.
</>;
}
}

View File

@@ -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,22 +29,22 @@ 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) {
const query = MS.struct.generator.atomGroups({
const expression = MS.struct.generator.atomGroups({
'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), auth_asym_id])
})
return b.apply(StateTransforms.Model.StructureSelection, { query, label: `Chain ${auth_asym_id}` });
return b.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: `Chain ${auth_asym_id}` });
}
export function select(b: StateBuilder.To<PSO.Molecule.Structure>, query: Expression) {
return b.apply(StateTransforms.Model.StructureSelection, { query });
export function select(b: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression) {
return b.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression });
}
export function selectSurroundingsOfFirstResidue(b: StateBuilder.To<PSO.Molecule.Structure>, comp_id: string, radius: number) {
const query = MS.struct.modifier.includeSurroundings({
const expression = MS.struct.modifier.includeSurroundings({
0: MS.struct.filter.first([
MS.struct.generator.atomGroups({
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), comp_id]),
@@ -53,7 +53,7 @@ export namespace StateHelper {
]),
radius
})
return b.apply(StateTransforms.Model.StructureSelection, { query, label: `Surr. ${comp_id} (${radius} ang)` });
return b.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: `Surr. ${comp_id} (${radius} ang)` });
}
export function identityTransform(b: StateBuilder.To<PSO.Molecule.Structure>, m: Mat4) {
@@ -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>, query: Expression, coloring?: BuiltInColorThemeName) {
export function ballsAndSticks(ctx: PluginContext, visualRoot: StateBuilder.To<PSO.Molecule.Structure>, expression: Expression, color?: ColorTheme.BuiltIn) {
visualRoot
.apply(StateTransforms.Model.StructureSelection, { query })
.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,10 +105,18 @@
addControl('Apply Stripes', () => BasicMolStarWrapper.coloring.applyStripes());
addHeader('Interactivity');
addControl('Highlight seq_id=7', () => BasicMolStarWrapper.interactivity.highlightOn());
addControl('Clear Highlight', () => BasicMolStarWrapper.interactivity.clearHighlight());
addHeader('Tests');
addControl('Static Superposition', () => BasicMolStarWrapper.tests.staticSuperposition());
addControl('Dynamic Superposition', () => BasicMolStarWrapper.tests.dynamicSuperposition());
addControl('Validation Tooltip', () => BasicMolStarWrapper.tests.toggleValidationTooltip());
addControl('Show Toasts', () => BasicMolStarWrapper.tests.showToasts());
addControl('Hide Toasts', () => BasicMolStarWrapper.tests.hideToasts());
////////////////////////////////////////////////////////

View File

@@ -7,17 +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';
require('mol-plugin/skin/light.scss')
import { PDBeStructureQualityReport } from '../../mol-plugin/behavior/dynamic/custom-props';
import { CustomToastMessage } from './controls';
import { EmptyLoci } from '../../mol-model/loci';
import { StructureSelection } from '../../mol-model/structure';
import { Script } from '../../mol-script/script';
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 }
@@ -37,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) {
@@ -54,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;
}
@@ -80,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';
@@ -90,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 = {
@@ -128,30 +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.behaviors;
const tree = state.build().to(PDBeStructureQualityReport.id).update(PDBeStructureQualityReport, p => ({ ...p, showTooltip: !p.showTooltip }));
await PluginCommands.State.Update(this.plugin, { state, tree });
},
showToasts: () => {
PluginCommands.Toast.Show(this.plugin, {
title: 'Toast 1',
message: 'This is an example text, timeout 3s',
key: 'toast-1',
timeoutMs: 3000
});
PluginCommands.Toast.Show(this.plugin, {
title: 'Toast 2',
message: CustomToastMessage,
key: 'toast-2'
});
},
hideToasts: () => {
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

@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<title>Mol* Lighting Demo</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#app {
position: absolute;
left: 160px;
top: 100px;
width: 600px;
height: 600px;
border: 1px solid #ccc;
}
#controls {
position: absolute;
width: 150px;
top: 100px;
left: 780px;
}
#controls > button {
display: block;
width: 100%;
text-align: left;
margin: 5px 0px;
}
#controls > input, #controls > select {
width: 100%;
display: block;
}
</style>
<link rel="stylesheet" type="text/css" href="app.css" />
<script type="text/javascript" src="./index.js"></script>
</head>
<body>
<div id='controls'></div>
<div id="app"></div>
<script>
LightingDemo.init('app')
LightingDemo.load({ url: 'https://files.rcsb.org/download/1M07.cif', assemblyId: '1' })
addHeader('Example PDB IDs');
addControl('1M07', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/1M07.cif', assemblyId: '1' }));
addControl('6HY0', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/6HY0.cif', assemblyId: '1' }));
addControl('6QVK', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/6QVK.cif', assemblyId: '1' }));
addControl('1RB8', () => LightingDemo.load({ url: 'https://files.rcsb.org/download/1RB8.cif', assemblyId: '1' }));
addSeparator()
addHeader('Lighting Presets');
addControl('Illustrative', () => LightingDemo.setPreset('illustrative'));
addControl('Standard', () => LightingDemo.setPreset('standard'));
addControl('Ambient Occlusion', () => LightingDemo.setPreset('occlusion'));
////////////////////////////////////////////////////////
function $(id) { return document.getElementById(id); }
function addControl(label, action) {
var btn = document.createElement('button');
btn.onclick = action;
btn.innerText = label;
$('controls').appendChild(btn);
}
function addSeparator() {
var hr = document.createElement('br');
$('controls').appendChild(hr);
}
function addHeader(header) {
var h = document.createElement('h3');
h.innerText = header;
$('controls').appendChild(h);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,178 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { createPlugin, DefaultPluginSpec } from '../../../mol-plugin';
import './index.html'
import { PluginContext } from '../../../mol-plugin/context';
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';
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 }
const Canvas3DPresets = {
illustrative: {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusionEnable: true,
occlusionBias: 0.8,
occlusionKernelSize: 6,
outlineEnable: true,
},
renderer: {
ambientIntensity: 1,
lightIntensity: 0,
}
},
occlusion: {
multiSample: {
mode: 'temporal' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusionEnable: true,
occlusionBias: 0.8,
occlusionKernelSize: 6,
outlineEnable: false,
},
renderer: {
ambientIntensity: 0.4,
lightIntensity: 0.6,
}
},
standard: {
multiSample: {
mode: 'off' as Canvas3DProps['multiSample']['mode']
},
postprocessing: {
occlusionEnable: false,
outlineEnable: false,
},
renderer: {
ambientIntensity: 0.4,
lightIntensity: 0.6,
}
}
}
type Canvas3DPreset = keyof typeof Canvas3DPresets
function getPreset(preset: Canvas3DPreset) {
switch (preset) {
case 'illustrative': return Canvas3DPresets['illustrative']
case 'standard': return Canvas3DPresets['standard']
case 'occlusion': return Canvas3DPresets['occlusion']
}
}
class LightingDemo {
plugin: PluginContext;
init(target: string | HTMLElement) {
this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
...DefaultPluginSpec,
layout: {
initial: {
isExpanded: false,
showControls: false
},
controls: { left: 'none', right: 'none', top: 'none', bottom: 'none' }
}
});
this.setPreset('illustrative');
}
setPreset(preset: Canvas3DPreset) {
const props = getPreset(preset)
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
...props,
multiSample: {
...this.plugin.canvas3d!.props.multiSample,
...props.multiSample
},
renderer: {
...this.plugin.canvas3d!.props.renderer,
...props.renderer
},
postprocessing: {
...this.plugin.canvas3d!.props.postprocessing,
...props.postprocessing
},
}});
}
private download(b: StateBuilder.To<PSO.Root>, url: string) {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
}
private parse(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
const parsed = format === 'cif'
? 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.StructureFromModel, props, { ref: 'asm' });
}
private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(this.plugin, void 0, { type: 'spacefill', color: 'illustrative' }), { ref: 'seq-visual' });
visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(this.plugin, void 0, { type: 'ball-and-stick' }), { ref: 'het-visual' });
return visualRoot;
}
private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
let loadType: 'full' | 'update' = 'full';
const state = this.plugin.state.data;
if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
loadType = 'full';
} else if (this.loadedParams.url === url) {
if (state.select('asm').length > 0) loadType = 'update';
}
let tree: StateBuilder.Root;
if (loadType === 'full') {
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.StructureFromModel, p => ({ ...p, ...props }));
}
await PluginCommands.State.Update(this.plugin, { state: this.plugin.state.data, tree });
this.loadedParams = { url, format, assemblyId };
PluginCommands.Camera.Reset(this.plugin, { });
}
}
(window as any).LightingDemo = new LightingDemo();

View File

@@ -112,7 +112,7 @@ const state: State = {
function formatParams(def: QueryDefinition) {
const prms = Object.create(null);
for (const p of def.params) {
for (const p of def.jsonParams) {
prms[p.name] = p.exampleValues ? p.exampleValues[0] : void 0;
}
return JSON.stringify(prms, void 0, 2);

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

@@ -19,9 +19,10 @@ function paramInfo(param: PD.Any, offset: number): string {
case 'conditioned': return getParams(param.conditionParams, offset);
case 'multi-select': return `Array of ${oToS(param.options)}`;
case 'color': return 'Color as 0xrrggbb';
case 'color-scale': return `One of ${oToS(param.options)}`;
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]`;
@@ -30,7 +31,7 @@ function paramInfo(param: PD.Any, offset: number): string {
case 'line-graph': return `A list of 2d vectors [xi, yi][]`;
case 'object-list': return `Array of\n${paramInfo(PD.Group(param.element), offset + 2)}`;
// TODO: support more languages
case 'script-expression': return `An expression in the specified language { language: 'mol-script', expressiong: string }`;
case 'script': return `An expression in the specified language { language: 'mol-script', expressiong: string }`;
default:
const _: never = param;
console.warn(`${_} has no associated UI component`);
@@ -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

@@ -15,6 +15,9 @@ import { OrderedSet } from '../../mol-data/int';
import { openCif, downloadCif } from './helpers';
import { Vec3 } from '../../mol-math/linear-algebra';
import { trajectoryFromMmCIF } from '../../mol-model-formats/structure/mmcif';
import { Sequence } from '../../mol-model/sequence';
import { ModelSecondaryStructure } from '../../mol-model-formats/structure/property/secondary-structure';
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
async function downloadFromPdb(pdb: string) {
@@ -49,8 +52,10 @@ export function residueLabel(model: Model, rI: number) {
export function printSecStructure(model: Model) {
console.log('\nSecondary Structure\n=============');
const { residues } = model.atomicHierarchy;
const { key, elements } = model.properties.secondaryStructure;
const secondaryStructure = ModelSecondaryStructure.Provider.get(model);
if (!secondaryStructure) return
const { key, elements } = secondaryStructure
const count = residues._rowCount;
let rI = 0;
while (rI < count) {
@@ -64,14 +69,14 @@ export function printSecStructure(model: Model) {
}
}
export function printLinks(structure: Structure, showIntra: boolean, showInter: boolean) {
export function printBonds(structure: Structure, showIntra: boolean, showInter: boolean) {
if (showIntra) {
console.log('\nIntra Unit Links\n=============');
console.log('\nIntra Unit Bonds\n=============');
for (const unit of structure.units) {
if (!Unit.isAtomic(unit)) continue;
const elements = unit.elements;
const { a, b, edgeCount } = unit.links;
const { a, b, edgeCount } = unit.bonds;
const { model } = unit;
if (!edgeCount) continue;
@@ -85,20 +90,20 @@ export function printLinks(structure: Structure, showIntra: boolean, showInter:
}
if (showInter) {
console.log('\nInter Unit Links\n=============');
const links = structure.links;
console.log('\nInter Unit Bonds\n=============');
const bonds = structure.interUnitBonds;
for (const unit of structure.units) {
if (!Unit.isAtomic(unit)) continue;
for (const pairLinks of links.getLinkedUnits(unit)) {
if (!pairLinks.areUnitsOrdered || pairLinks.bondCount === 0) continue;
for (const pairBonds of bonds.getConnectedUnits(unit)) {
if (!pairBonds.areUnitsOrdered || pairBonds.edgeCount === 0) continue;
const { unitA, unitB } = pairLinks;
console.log(`${pairLinks.unitA.id} - ${pairLinks.unitB.id}: ${pairLinks.bondCount} bond(s)`);
const { unitA, unitB } = pairBonds;
console.log(`${pairBonds.unitA.id} - ${pairBonds.unitB.id}: ${pairBonds.edgeCount} bond(s)`);
for (const aI of pairLinks.linkedElementIndices) {
for (const link of pairLinks.getBonds(aI)) {
console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[link.indexB])}`);
for (const aI of pairBonds.connectedIndices) {
for (const bond of pairBonds.getEdges(aI)) {
console.log(`${atomLabel(unitA.model, unitA.elements[aI])} -- ${atomLabel(unitB.model, unitB.elements[bond.indexB])}`);
}
}
}
@@ -110,21 +115,10 @@ export function printSequence(model: Model) {
console.log('\nSequence\n=============');
const { byEntityKey } = model.sequence;
for (const key of Object.keys(byEntityKey)) {
const seq = byEntityKey[+key];
console.log(`${seq.entityId} (${seq.sequence.kind} ${seq.num.value(0)} (offset ${seq.sequence.offset}), ${seq.num.value(seq.num.rowCount - 1)}) (${seq.compId.value(0)}, ${seq.compId.value(seq.compId.rowCount - 1)})`);
console.log(`${seq.sequence.sequence}`);
}
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}`);
const { sequence, entityId } = byEntityKey[+key];
const { seqId, compId } = sequence
console.log(`${entityId} (${sequence.kind} ${seqId.value(0)} (offset ${sequence.offset}), ${seqId.value(seqId.rowCount - 1)}) (${compId.value(0)}, ${compId.value(compId.rowCount - 1)})`);
console.log(`${Sequence.getSequenceString(sequence)}`);
}
console.log();
}
@@ -146,7 +140,7 @@ export function printRings(structure: Structure) {
export function printUnits(structure: Structure) {
console.log('\nUnits\n=============');
const l = StructureElement.create();
const l = StructureElement.Location.create(structure);
for (const unit of structure.units) {
l.unit = unit;
@@ -159,14 +153,14 @@ export function printUnits(structure: Structure) {
console.log(`Coarse unit ${unit.id} ${unit.conformation.operator.name} (${Unit.isSpheres(l.unit) ? 'spheres' : 'gaussians'}): ${size} elements.`);
const props = StructureProperties.coarse;
const seq = l.unit.model.sequence;
const modelSeq = l.unit.model.sequence;
for (let j = 0, _j = Math.min(size, 3); j < _j; j++) {
l.element = OrderedSet.getAt(elements, j);
const residues: string[] = [];
const start = props.seq_id_begin(l), end = props.seq_id_end(l);
const compId = seq.byEntityKey[props.entityKey(l)].compId.value;
const compId = modelSeq.byEntityKey[props.entityKey(l)].sequence.compId.value;
for (let e = start; e <= end; e++) residues.push(compId(e));
console.log(`${props.asym_id(l)}:${start}-${end} (${residues.join('-')}) ${props.asym_id(l)} [${props.x(l).toFixed(2)}, ${props.y(l).toFixed(2)}, ${props.z(l).toFixed(2)}]`);
}
@@ -177,7 +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(', ')}`);
@@ -212,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]);
}
@@ -240,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 {
@@ -254,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

@@ -0,0 +1,228 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Ludovic Autin <autin@scripps.edu>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Quat, Mat4 } from '../../../../mol-math/linear-algebra';
import { NumberArray } from '../../../../mol-util/type-helpers';
interface Frame {
t: Vec3,
r: Vec3,
s: Vec3,
}
const a0Tmp = Vec3()
const a1Tmp = Vec3()
const a2Tmp = Vec3()
const a3Tmp = Vec3()
function CubicInterpolate(out: Vec3, y0: Vec3, y1: Vec3, y2: Vec3, y3: Vec3, mu: number): Vec3 {
const mu2 = mu * mu;
Vec3.sub(a0Tmp, y3, y2)
Vec3.sub(a0Tmp, a0Tmp, y0)
Vec3.add(a0Tmp, a0Tmp, y1)
Vec3.sub(a1Tmp, y0, y1)
Vec3.sub(a1Tmp, a1Tmp, a0Tmp)
Vec3.sub(a2Tmp, y2, y0)
Vec3.copy(a3Tmp, y1)
out[0] = a0Tmp[0] * mu * mu2 + a1Tmp[0] * mu2 + a2Tmp[0] * mu + a3Tmp[0]
out[1] = a0Tmp[1] * mu * mu2 + a1Tmp[1] * mu2 + a2Tmp[1] * mu + a3Tmp[1]
out[2] = a0Tmp[2] * mu * mu2 + a1Tmp[2] * mu2 + a2Tmp[2] * mu + a3Tmp[2]
return out
}
const cp0 = Vec3()
const cp1 = Vec3()
const cp2 = Vec3()
const cp3 = Vec3()
const currentPosition = Vec3()
function ResampleControlPoints(points: NumberArray, segmentLength: number) {
const nP = points.length / 3
// insert a point at the end and at the begining
// controlPoints.Insert(0, controlPoints[0] + (controlPoints[0] - controlPoints[1]) / 2.0f);
// controlPoints.Add(controlPoints[nP - 1] + (controlPoints[nP - 1] - controlPoints[nP - 2]) / 2.0f);
let resampledControlPoints: Vec3[] = []
// resampledControlPoints.Add(controlPoints[0]);
// resampledControlPoints.Add(controlPoints[1]);
let idx = 1
// const currentPosition = Vec3.create(points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2])
Vec3.fromArray(currentPosition, points, idx * 3)
let lerpValue = 0.0
// Normalize the distance between control points
while (true) {
if (idx + 2 >= nP) break
Vec3.fromArray(cp0, points, (idx - 1) * 3)
Vec3.fromArray(cp1, points, idx * 3)
Vec3.fromArray(cp2, points, (idx + 1) * 3)
Vec3.fromArray(cp3, points, (idx + 2) * 3)
// const cp0 = Vec3.create(points[(idx-1)*3], points[(idx-1)*3+1], points[(idx-1)*3+2]) // controlPoints[currentPointId - 1];
// const cp1 = Vec3.create(points[idx*3], points[idx*3+1], points[idx*3+2]) // controlPoints[currentPointId];
// const cp2 = Vec3.create(points[(idx+1)*3], points[(idx+1)*3+1], points[(idx+1)*3+2]) // controlPoints[currentPointId + 1];
// const cp3 = Vec3.create(points[(idx+2)*3], points[(idx+2)*3+1], points[(idx+2)*3+2]); // controlPoints[currentPointId + 2];
let found = false
for (; lerpValue <= 1; lerpValue += 0.01) {
// lerp?slerp
// let candidate:Vec3 = Vec3.lerp(Vec3.zero(), cp0, cp1, lerpValue);
// const candidate:Vec3 = Vec3.bezier(Vec3.zero(), cp0, cp1, cp2, cp3, lerpValue);
const candidate = CubicInterpolate(Vec3(), cp0, cp1, cp2, cp3, lerpValue)
const d = Vec3.distance(currentPosition, candidate);
if (d > segmentLength) {
resampledControlPoints.push(candidate)
Vec3.copy(currentPosition, candidate)
found = true
break
}
}
if (!found) {
lerpValue = 0
idx += 1
}
}
return resampledControlPoints
}
const prevV = Vec3()
const tmpV1 = Vec3()
const tmpV2 = Vec3()
const tmpV3 = Vec3()
// easier to align to theses normals
function GetSmoothNormals(points: Vec3[]) {
const nP: number = points.length;
const smoothNormals: Vec3[] = []
if (points.length < 3) {
for (let i = 0; i < points.length; ++i)
smoothNormals.push(Vec3.normalize(Vec3(), points[i]))
return smoothNormals;
}
let p0 = points[0]
let p1 = points[1]
let p2 = points[2]
const p21 = Vec3.sub(tmpV1, p2, p1)
const p01 = Vec3.sub(tmpV2, p0, p1)
const p0121 = Vec3.cross(tmpV3, p01, p21)
Vec3.normalize(prevV, p0121)
smoothNormals.push(Vec3.clone(prevV))
for (let i = 1; i < points.length - 1; ++i) {
p0 = points[i - 1]
p1 = points[i]
p2 = points[i + 1]
const t = Vec3.normalize(tmpV1, Vec3.sub(tmpV1, p2 , p0))
const b = Vec3.normalize(tmpV2, Vec3.cross(tmpV2, t, prevV))
const n = Vec3.normalize(Vec3(), Vec3.cross(tmpV3, t, b))
Vec3.negate(n, n)
Vec3.copy(prevV, n)
smoothNormals.push(n)
}
const last = Vec3()
Vec3.normalize(last, Vec3.cross(last,
Vec3.sub(tmpV1, points[nP - 3], points[nP-2]),
Vec3.sub(tmpV2, points[nP-2] , points[nP-1]))
)
smoothNormals.push(last)
return smoothNormals;
}
const frameTmpV1 = Vec3()
const frameTmpV2 = Vec3()
const frameTmpV3 = Vec3()
function getFrame(reference: Vec3, tangent: Vec3) {
const t = Vec3.normalize(Vec3(), tangent);
// make reference vector orthogonal to tangent
const proj_r_to_t = Vec3.scale(
frameTmpV1, tangent, Vec3.dot(reference, tangent) / Vec3.dot(tangent, tangent)
)
const r = Vec3.normalize(Vec3(), Vec3.sub(frameTmpV2, reference, proj_r_to_t))
// make bitangent vector orthogonal to the others
const s = Vec3.normalize(Vec3(), Vec3.cross(frameTmpV3, t, r))
return { t, r, s }
}
const mfTmpV1 = Vec3()
const mfTmpV2 = Vec3()
const mfTmpV3 = Vec3()
const mfTmpV4 = Vec3()
const mfTmpV5 = Vec3()
const mfTmpV6 = Vec3()
const mfTmpV7 = Vec3()
const mfTmpV8 = Vec3()
const mfTmpV9 = Vec3()
// easier to align to theses normals
// https://github.com/bzamecnik/gpg/blob/master/rotation-minimizing-frame/rmf.py
function GetMiniFrame(points: Vec3[], normals: Vec3[]) {
const frames: Frame[] = [];
const t0 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[1], points[0]))
frames.push(getFrame(normals[0], t0))
for (let i = 0; i< points.length-2; ++i) {
const t2 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[i+2], points[i+1]))
const v1 = Vec3.sub(mfTmpV2, points[i + 1], points[i]) // this is tangeant
const c1 = Vec3.dot(v1, v1)
// compute r_i^L = R_1 * r_i
const v1r = Vec3.scale(mfTmpV3, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].r))
const ref_L_i = Vec3.sub(mfTmpV4, frames[i].r, v1r)
// compute t_i^L = R_1 * t_i
const v1t = Vec3.scale(mfTmpV5, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].t))
const tan_L_i = Vec3.sub(mfTmpV6, frames[i].t, v1t)
// # compute reflection vector of R_2
const v2 = Vec3.sub(mfTmpV7, t2 , tan_L_i)
const c2 = Vec3.dot(v2, v2)
// compute r_(i+1) = R_2 * r_i^L
const v2l = Vec3.scale(mfTmpV8, v1, (2.0/c2) * Vec3.dot(v2, ref_L_i))
const ref_next = Vec3.sub(mfTmpV9, ref_L_i, v2l) // ref_L_i - (2 / c2) * v2.dot(ref_L_i) * v2
frames.push(getFrame(ref_next, t2)) // frames.append(Frame(ref_next, tangents[i+1]))
}
return frames;
}
const rpTmpVec1 = Vec3()
export function getMatFromResamplePoints(points: NumberArray) {
const segmentLength = 3.4
const new_points = ResampleControlPoints(points, 3.4)
const npoints = new_points.length
const new_normal = GetSmoothNormals(new_points)
const frames = GetMiniFrame(new_points, new_normal)
const limit = npoints
const transforms: Mat4[] = []
const pti = Vec3.copy(rpTmpVec1, new_points[0]);
// console.log(new_points.length)
// console.log(points.length/3)
// console.log(limit)
// console.log(segmentLength)
for (let i = 0; i<npoints-2; ++i) {
const pti1: Vec3 = new_points[i+1] // Vec3.create(points[(i+1)*3],points[(i+1)*3+1],points[(i+1)*3+2]);
const d = Vec3.distance(pti, pti1)
if (d >= segmentLength) {
// use twist or random?
const quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t) // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal
const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random()*3.60 ) // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();//
const m = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)) // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat));
// let pos:Vec3 = Vec3.add(Vec3.zero(),pti1,pti)
// pos = Vec3.scale(pos,pos,1.0/2.0);
// Vec3.makeRotation(Mat4.zero(),Vec3.create(0,0,1),frames[i].t);//
Mat4.setTranslation(m, pti1)
// let m2:Mat4 = GetTubePropertiesMatrix(pti,pti1);
// let q:Quat = Quat.rotationTo(Quat.zero(), Vec3.create(0,1,0),Vec3.create(0,0,1))
// m2=Mat4.mul(Mat4.identity(),Mat4.fromQuat(Mat4.zero(),q),m2);
transforms.push(m)
Vec3.copy(pti, pti1)
}
if (transforms.length >= limit) break
}
return transforms
}

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Vec3, Quat } from '../../../../mol-math/linear-algebra';
export interface CellPack {
cell: Cell
packings: CellPacking[]
}
export interface CellPacking {
name: string,
location: 'surface' | 'interior' | 'cytoplasme',
ingredients: Packing['ingredients']
}
//
export interface Cell {
recipe: Recipe
cytoplasme?: Packing
compartments?: { [key: string]: Compartment }
}
export interface Recipe {
setupfile: string
/** First entry is name, secound is path: [name: string, path: string][] */
paths: [string, string][]
version: string
name: string
}
export interface Compartment {
surface?: Packing
interior?: Packing
}
export interface Packing {
ingredients: { [key: string]: Ingredient }
}
export interface Ingredient {
source: IngredientSource
results: [Vec3, Quat][]
name: string
positions?: [Vec3[]] // why wrapped in an extra array?
radii?: [number[]] // why wrapped in an extra array?
/** Number of `curveX` properties in the object where `X` is a 0-indexed number */
nbCurve?: number
/** Curve properties are Vec3[] but that is not expressable in TypeScript */
[curveX: string]: unknown
}
export interface IngredientSource {
pdb: string
transform: { center: boolean, translate?: Vec3 }
biomt?: boolean
}

View File

@@ -0,0 +1,469 @@
/**
* 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 { 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, 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 { 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';
import { ParseCellPack, StructureFromCellpack, DefaultCellPackBaseUrl } from './state';
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 { 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}`
}
async function getModel(id: string, baseUrl: string) {
let model: Model;
if (id.match(/^[1-9][a-zA-Z0-9]{3,3}$/i)) {
// return
const cif = await getFromPdb(id)
model = (await trajectoryFromMmCIF(cif).run())[0]
} else {
const pdb = await getFromCellPackDB(id, baseUrl)
model = (await trajectoryFromPDB(pdb).run())[0]
}
return model
}
async function getStructure(model: Model, props: { assembly?: string } = {}) {
let structure = Structure.ofModel(model)
const { assembly } = props
if (assembly) {
structure = await StructureSymmetry.buildAssembly(structure, assembly).run()
}
const query = MS.struct.modifier.union([
MS.struct.generator.atomGroups({
'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer'])
})
])
const compiled = compile<StructureSelection>(query)
const result = compiled(new QueryContext(structure))
structure = StructureSelection.unionStructure(result)
return structure
}
function getTransform(trans: Vec3, rot: Quat) {
const q: Quat = Quat.create(-rot[3], rot[0], rot[1], rot[2])
const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q)
Mat4.transpose(m, m)
Mat4.scale(m, m, Vec3.create(-1.0, 1.0, -1.0))
Mat4.setTranslation(m, trans)
return m
}
function getResultTransforms(results: Ingredient['results']) {
return results.map((r: Ingredient['results'][0]) => getTransform(r[0], r[1]))
}
function getCurveTransforms(ingredient: Ingredient) {
const n = ingredient.nbCurve || 0
const instances: Mat4[] = []
for (let i = 0; i < n; ++i) {
const cname = `curve${i}`
if (!(cname in ingredient)) {
// console.warn(`Expected '${cname}' in ingredient`)
continue
}
const _points = ingredient[cname] as Vec3[]
if (_points.length <= 2) {
// TODO handle curve with 2 or less points
continue
}
const points = new Float32Array(_points.length * 3)
for (let i = 0, il = _points.length; i < il; ++i) Vec3.toArray(_points[i], points, i * 3)
const newInstances = getMatFromResamplePoints(points)
instances.push(...newInstances)
}
return instances
}
function getAssembly(transforms: Mat4[], structure: Structure) {
const builder = Structure.Builder()
const { units } = structure;
for (let i = 0, il = transforms.length; i < il; ++i) {
const id = `${i + 1}`
const op = SymmetryOperator.create(id, transforms[i], { id, operList: [ id ] })
for (const unit of units) {
builder.addWithOperator(unit, op)
}
}
return builder.getStructure();
}
function getCifCurve(name: string, transforms: Mat4[], model: Model) {
if (!MmcifFormat.is(model.sourceData)) throw new Error('mmcif source data needed')
const { db } = model.sourceData.data
const d = db.atom_site
const n = d._rowCount
const rowCount = n * transforms.length
const { offsets, count } = model.atomicHierarchy.chainAtomSegments
const x = d.Cartn_x.toArray()
const y = d.Cartn_y.toArray()
const z = d.Cartn_z.toArray()
const Cartn_x = new Float32Array(rowCount)
const Cartn_y = new Float32Array(rowCount)
const Cartn_z = new Float32Array(rowCount)
const map = new Uint32Array(rowCount)
const seq = new Int32Array(rowCount)
let offset = 0
for (let c = 0; c < count; ++c) {
const cStart = offsets[c]
const cEnd = offsets[c + 1]
const cLength = cEnd - cStart
for (let t = 0, tl = transforms.length; t < tl; ++t) {
const m = transforms[t]
for (let j = cStart; j < cEnd; ++j) {
const i = offset + j - cStart
const xj = x[j], yj = y[j], zj = z[j]
Cartn_x[i] = m[0] * xj + m[4] * yj + m[8] * zj + m[12]
Cartn_y[i] = m[1] * xj + m[5] * yj + m[9] * zj + m[13]
Cartn_z[i] = m[2] * xj + m[6] * yj + m[10] * zj + m[14]
map[i] = j
seq[i] = t + 1
}
offset += cLength
}
}
function multColumn<T>(column: Column<T>) {
const array = column.toArray()
return Column.ofLambda({
value: row => array[map[row]],
areValuesEqual: (rowA, rowB) => map[rowA] === map[rowB] || array[map[rowA]] === array[map[rowB]],
rowCount, schema: column.schema
})
}
const _atom_site: CifCategory.SomeFields<mmCIF_Schema['atom_site']> = {
auth_asym_id: CifField.ofColumn(multColumn(d.auth_asym_id)),
auth_atom_id: CifField.ofColumn(multColumn(d.auth_atom_id)),
auth_comp_id: CifField.ofColumn(multColumn(d.auth_comp_id)),
auth_seq_id: CifField.ofNumbers(seq),
B_iso_or_equiv: CifField.ofColumn(Column.ofConst(0, rowCount, Column.Schema.float)),
Cartn_x: CifField.ofNumbers(Cartn_x),
Cartn_y: CifField.ofNumbers(Cartn_y),
Cartn_z: CifField.ofNumbers(Cartn_z),
group_PDB: CifField.ofColumn(Column.ofConst('ATOM', rowCount, Column.Schema.str)),
id: CifField.ofColumn(Column.ofLambda({
value: row => row,
areValuesEqual: (rowA, rowB) => rowA === rowB,
rowCount, schema: d.id.schema,
})),
label_alt_id: CifField.ofColumn(multColumn(d.label_alt_id)),
label_asym_id: CifField.ofColumn(multColumn(d.label_asym_id)),
label_atom_id: CifField.ofColumn(multColumn(d.label_atom_id)),
label_comp_id: CifField.ofColumn(multColumn(d.label_comp_id)),
label_seq_id: CifField.ofNumbers(seq),
label_entity_id: CifField.ofColumn(Column.ofConst('1', rowCount, Column.Schema.str)),
occupancy: CifField.ofColumn(Column.ofConst(1, rowCount, Column.Schema.float)),
type_symbol: CifField.ofColumn(multColumn(d.type_symbol)),
pdbx_PDB_ins_code: CifField.ofColumn(Column.ofConst('', rowCount, Column.Schema.str)),
pdbx_PDB_model_num: CifField.ofColumn(Column.ofConst(1, rowCount, Column.Schema.int)),
}
const categories = {
entity: CifCategory.ofTable('entity', db.entity),
chem_comp: CifCategory.ofTable('chem_comp', db.chem_comp),
atom_site: CifCategory.ofFields('atom_site', _atom_site)
}
return {
header: name,
categoryNames: Object.keys(categories),
categories
};
}
async function getCurve(name: string, transforms: Mat4[], model: Model) {
const cif = getCifCurve(name, transforms, model)
const curveModelTask = Task.create('Curve Model', async ctx => {
const format = MmcifFormat.fromFrame(cif)
const models = await createModels(format.data.db, format, ctx)
return models[0]
})
const curveModel = await curveModelTask.run()
return getStructure(curveModel)
}
async function getIngredientStructure(ingredient: Ingredient, baseUrl: string) {
const { name, source, results, nbCurve } = ingredient
// TODO can these be added to the library?
if (name === 'HIV1_CAhex_0_1_0') return
if (name === 'HIV1_CAhexCyclophilA_0_1_0') return
if (name === 'iLDL') return
if (name === 'peptides') return
if (name === 'lypoglycane') return
if (source.pdb === 'None') return
const model = await getModel(source.pdb || name, baseUrl)
if (!model) return
if (nbCurve) {
return getCurve(name, getCurveTransforms(ingredient), model)
} else {
const structure = await getStructure(model, { assembly: source.biomt ? '1' : undefined })
return getAssembly(getResultTransforms(results), structure)
}
}
export function createStructureFromCellPack(packing: CellPacking, baseUrl: string) {
return Task.create('Create Packing Structure', async ctx => {
const { ingredients, name } = packing
const structures: Structure[] = []
for (const iName in ingredients) {
if (ctx.shouldUpdate) await ctx.update(iName)
const s = await getIngredientStructure(ingredients[iName], baseUrl)
if (s) structures.push(s)
}
if (ctx.shouldUpdate) await ctx.update(`${name} - units`)
const builder = Structure.Builder({ label: name })
let offsetInvariantId = 0
for (const s of structures) {
if (ctx.shouldUpdate) await ctx.update(`${s.label}`)
let maxInvariantId = 0
for (const u of s.units) {
const invariantId = u.invariantId + offsetInvariantId
if (u.invariantId > maxInvariantId) maxInvariantId = u.invariantId
builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, Unit.Trait.None, invariantId)
}
offsetInvariantId += maxInvariantId
}
if (ctx.shouldUpdate) await ctx.update(`${name} - structure`)
const s = builder.getStructure()
return s
})
}
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: {
id: PD.Select('influenza_model1.json', [
['blood_hiv_immature_inside.json', 'blood_hiv_immature_inside'],
['BloodHIV1.0_mixed_fixed_nc1.cpr', 'BloodHIV1.0_mixed_fixed_nc1'],
['HIV-1_0.1.6-8_mixed_radii_pdb.cpr', 'HIV-1_0.1.6-8_mixed_radii_pdb'],
['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', RepresentationOptions)
}, { isExpanded: true })
},
from: PSO.Root
})(({ state, params }, ctx: PluginContext) => Task.create('CellPack Loader', async taskCtx => {
const url = getCellPackModelUrl(params.id, params.baseUrl)
const root = state.build().toRoot();
let cellPackBuilder: any
if (params.id === 'curveTest') {
const url = `${params.baseUrl}/extras/rna_allpoints.json`
const data = await ctx.fetch({ url, type: 'string' }).runInContext(taskCtx);
const { points } = await (new Response(data)).json() as { points: number[] }
const curve0: Vec3[] = []
for (let j = 0, jl = Math.min(points.length, 3 * 100); j < jl; j += 3) {
curve0.push(Vec3.fromArray(Vec3(), points, j))
}
const cell: Cell = {
recipe: { setupfile: '', paths: [], version: '', name: 'Curve Test' },
compartments: {
'CurveCompartment': {
interior: {
ingredients: {
'CurveIngredient': {
source: { pdb: 'RNA_U_Base.pdb', transform: { center: false } },
results: [],
name: 'RNA',
nbCurve: 1,
curve0
}
}
}
}
}
}
cellPackBuilder = root
.apply(StateTransforms.Data.ImportJson, { data: cell }, { state: { isGhost: true } })
.apply(ParseCellPack)
} else {
cellPackBuilder = root
.apply(StateTransforms.Data.Download, { url, isBinary: false, label: params.id }, { state: { isGhost: true } })
.apply(StateTransforms.Data.ParseJson, undefined, { state: { isGhost: true } })
.apply(ParseCellPack)
}
const cellPackObject = await state.updateTree(cellPackBuilder).runInContext(taskCtx)
const { packings } = cellPackObject.data
const tree = state.build().to(cellPackBuilder.ref);
const isHiv = (
params.id === 'BloodHIV1.0_mixed_fixed_nc1.cpr' ||
params.id === 'HIV-1_0.1.6-8_mixed_radii_pdb.cpr'
)
if (isHiv) {
for (let i = 0, il = packings.length; i < il; ++i) {
if (packings[i].name === 'HIV1_capsid_3j3q_PackInner_0_1_0') {
const url = `${params.baseUrl}/extras/rna_allpoints.json`
const data = await ctx.fetch({ url, type: 'string' }).runInContext(taskCtx);
const { points } = await (new Response(data)).json() as { points: number[] }
const curve0: Vec3[] = []
for (let j = 0, jl = points.length; j < jl; j += 3) {
curve0.push(Vec3.fromArray(Vec3(), points, j))
}
packings[i].ingredients['RNA'] = {
source: { pdb: 'RNA_U_Base.pdb', transform: { center: false } },
results: [],
name: 'RNA',
nbCurve: 1,
curve0
}
}
}
}
const colors = distinctColors(packings.length)
for (let i = 0, il = packings.length; i < il; ++i) {
const hcl = Hcl.fromColor(Hcl(), colors[i])
const hue = [Math.max(0, hcl[0] - 35), Math.min(360, hcl[0] + 35)] as [number, number]
const p = { packing: i, baseUrl: params.baseUrl }
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'])
])
})
cellpackTree = cellpackTree.apply(StateTransforms.Model.StructureSelectionFromExpression, { expression }, { state: { isGhost: true } }) as any
}
cellpackTree
.apply(StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(ctx, Structure.Empty, {
...getReprParams(ctx, params.preset),
...getColorParams(hue)
})
)
}
if (isHiv) {
const url = `${params.baseUrl}/membranes/hiv_lipids.bcif`
tree.apply(StateTransforms.Data.Download, { label: 'hiv_lipids', url, isBinary: true }, { state: { isGhost: true } })
.apply(StateTransforms.Data.ParseCif, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Model.TrajectoryFromMmCif, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Model.ModelFromTrajectory, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Model.StructureFromModel, undefined, { state: { isGhost: true } })
.apply(StateTransforms.Misc.CreateGroup, { label: 'HIV1_envelope_Membrane' })
.apply(StateTransforms.Representation.StructureRepresentation3D,
createStructureRepresentationParams(ctx, Structure.Empty, {
...getReprParams(ctx, params.preset),
color: UniformColorThemeProvider
})
)
}
console.time('cellpack')
await state.updateTree(tree).runInContext(taskCtx);
console.timeEnd('cellpack')
}));
function getReprParams(ctx: PluginContext, params: { representation: RepresentationName, traceOnly: boolean }) {
const { representation, traceOnly } = params
switch (representation) {
case 'spacefill':
return traceOnly
? {
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 {
type: ctx.representation.structure.registry.get('gaussian-surface'),
typeParams: {
quality: 'custom', resolution: 10, radiusOffset: 2,
alpha: 1.0, flatShaded: false, doubleSided: false,
ignoreHydrogens: true
}
}
case 'point':
return { type: ctx.representation.structure.registry.get('point') }
case 'ellipsoid':
return { type: ctx.representation.structure.registry.get('orientation') }
}
}
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
}
}
}
}
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
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';
import { createStructureFromCellPack } from './model';
// export const DefaultCellPackBaseUrl = 'https://cdn.jsdelivr.net/gh/mesoscope/cellPACK_data@master/cellPACK_database_1.1.0/'
export const DefaultCellPackBaseUrl = 'https://mgldev.scripps.edu/projects/autoPACK/web/cellpackproject/'
export class CellPack extends PSO.Create<_CellPack>({ name: 'CellPack', typeClass: 'Object' }) { }
export { ParseCellPack }
type ParseCellPack = typeof ParseCellPack
const ParseCellPack = PluginStateTransform.BuiltIn({
name: 'parse-cellpack',
display: { name: 'Parse CellPack', description: 'Parse CellPack from JSON data' },
from: PSO.Format.Json,
to: CellPack
})({
apply({ a }) {
return Task.create('Parse CellPack', async ctx => {
const cell = a.data as Cell
const packings: CellPacking[] = []
const { compartments, cytoplasme } = cell
if (compartments) {
for (const name in compartments) {
const { surface, interior } = compartments[name]
if (surface) packings.push({ name, location: 'surface', ingredients: surface.ingredients })
if (interior) packings.push({ name, location: 'interior', ingredients: interior.ingredients })
}
}
if (cytoplasme) packings.push({ name: 'Cytoplasme', location: 'cytoplasme', ingredients: cytoplasme.ingredients })
return new CellPack({ cell, packings });
});
}
});
export { StructureFromCellpack }
type StructureFromCellpack = typeof ParseCellPack
const StructureFromCellpack = PluginStateTransform.BuiltIn({
name: 'structure-from-cellpack',
display: { name: 'Structure from CellPack', description: 'Create Structure from CellPack Packing' },
from: CellPack,
to: PSO.Molecule.Structure,
params: a => {
if (!a) {
return {
packing: PD.Numeric(0, {}, { description: 'Packing Index' }),
baseUrl: PD.Text(DefaultCellPackBaseUrl)
};
}
const options = a.data.packings.map((d, i) => [i, d.name] as [number, string])
return {
packing: PD.Select(0, options),
baseUrl: PD.Text(DefaultCellPackBaseUrl)
}
}
})({
apply({ a, params }) {
return Task.create('Structure from CellPack', async ctx => {
const packing = a.data.packings[params.packing]
const structure = await createStructureFromCellPack(packing, params.baseUrl).runInContext(ctx)
return new PSO.Molecule.Structure(structure, { label: packing.name })
});
}
});

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { CIF } from '../../../../mol-io/reader/cif'
import { parsePDB } from '../../../../mol-io/reader/pdb/parser';
async function parseCif(data: string|Uint8Array) {
const comp = CIF.parse(data);
const parsed = await comp.run();
if (parsed.isError) throw parsed;
return parsed.result;
}
async function parsePDBfile(data: string, id: string) {
const comp = parsePDB(data, id);
const parsed = await comp.run();
if (parsed.isError) throw parsed;
return parsed.result;
}
async function downloadCif(url: string, isBinary: boolean) {
const data = await fetch(url);
return parseCif(isBinary ? new Uint8Array(await data.arrayBuffer()) : await data.text());
}
async function downloadPDB(url: string, id: string) {
const data = await fetch(url);
return parsePDBfile(await data.text(), id);
}
export async function getFromPdb(id: string) {
const parsed = await downloadCif(`https://files.rcsb.org/download/${id}.cif`, false);
return parsed.blocks[0];
}
function getCellPackDataUrl(id: string, baseUrl: string) {
const url = `${baseUrl}/other/${id}`
return url.endsWith('.pdb') ? url : `${url}.pdb`
}
export async function getFromCellPackDB(id: string, baseUrl: string) {
const name = id.endsWith('.pdb') ? id.substring(0, id.length - 4) : id
const parsed = await downloadPDB(getCellPackDataUrl(id, baseUrl), name);
return parsed;
}

View File

@@ -1,171 +1,168 @@
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
// /**
// * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
// *
// * @author David Sehnal <david.sehnal@gmail.com>
// */
import { StateTree, StateBuilder, StateAction, State } from '../../../mol-state';
import { StateTransforms } from '../../../mol-plugin/state/transforms';
import { createModelTree, complexRepresentation } from '../../../mol-plugin/state/actions/structure';
import { PluginContext } from '../../../mol-plugin/context';
import { PluginStateObject } from '../../../mol-plugin/state/objects';
import { ParamDefinition } from '../../../mol-util/param-definition';
import { PluginCommands } from '../../../mol-plugin/command';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { PluginStateSnapshotManager } from '../../../mol-plugin/state/snapshots';
import { MolScriptBuilder as MS } from '../../../mol-script/language/builder';
import { Text } from '../../../mol-geo/geometry/text/text';
import { UUID } from '../../../mol-util';
import { ColorNames } from '../../../mol-util/color/tables';
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 query = createQuery([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.StructureSelection, { query, 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.StructureSelection, { query: MS.struct.modifier.wholeResidues([query]), 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.StructureSelection, { query: createQuery(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.StructureSelection, { query: createQuery([l.i_atom1, l.i_atom2]), label: `Distance ${++i}` })
// .apply(StateTransforms.Representation.StructureLabels3D, {
// target: { name: 'static-text', params: { value: l. || '' } },
// options: labelOptions
// });
// }
return PluginStateSnapshotManager.Entry({
id: UUID.create22(),
data: { tree: StateTree.toJSON(b.getTree()) },
camera: {
current: getCameraSnapshot(params.e.camera),
transitionStyle: 'animate',
transitionDurationInMs: 350
}
}, {
name: params.e.text
});
}
// group
// .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression, label: 'Atom' })
// .apply(StateTransforms.Representation.StructureLabels3D, {
// target: { name: 'static-text', params: { value: l.text || '' } },
// options: labelOptions
// });
function getCameraSnapshot(e: JoleculeSnapshot['camera']): Camera.Snapshot {
const direction = Vec3.sub(Vec3.zero(), e.pos, e.in);
Vec3.normalize(direction, direction);
const up = Vec3.sub(Vec3.zero(), e.pos, e.up);
Vec3.normalize(up, up);
// group
// .apply(StateTransforms.Model.StructureSelectionFromExpression, { expression: MS.struct.modifier.wholeResidues([ expression ]), label: 'Residue' })
// .apply(StateTransforms.Representation.StructureRepresentation3D,
// 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',
position: Vec3.scaleAndAdd(Vec3.zero(), e.pos, direction, e.slab.zoom),
target: e.pos,
direction,
up,
near: e.slab.zoom + e.slab.z_front,
far: e.slab.zoom + e.slab.z_back,
fogNear: e.slab.zoom + e.slab.z_front,
fogFar: e.slab.zoom + e.slab.z_back,
fov: Math.PI / 4,
zoom: 1
};
return s;
}
// function getCameraSnapshot(e: JoleculeSnapshot['camera']): Camera.Snapshot {
// const direction = Vec3.sub(Vec3(), e.pos, e.in);
// Vec3.normalize(direction, direction);
// const up = Vec3.sub(Vec3(), e.pos, e.up);
// Vec3.normalize(up, up);
function createQuery(atomIndices: number[]) {
if (atomIndices.length === 0) return MS.struct.generator.empty();
// const s: Camera.Snapshot = {
// mode: 'perspective',
// fov: Math.PI / 4,
// position: Vec3.scaleAndAdd(Vec3(), e.pos, direction, e.slab.zoom),
// target: e.pos,
// radius: (e.slab.z_back - e.slab.z_front) / 2,
// fog: 50,
// up,
// };
// return s;
// }
return MS.struct.generator.atomGroups({
'atom-test': atomIndices.length === 1
? MS.core.rel.eq([MS.struct.atomProperty.core.sourceIndex(), atomIndices[0]])
: MS.core.set.has([MS.set.apply(null, atomIndices), MS.struct.atomProperty.core.sourceIndex()]),
'group-by': 0
});
}
// function createExpression(atomIndices: number[]) {
// if (atomIndices.length === 0) return MS.struct.generator.empty();
// return MS.struct.generator.atomGroups({
// 'atom-test': atomIndices.length === 1
// ? MS.core.rel.eq([MS.struct.atomProperty.core.sourceIndex(), atomIndices[0]])
// : MS.core.set.has([MS.set.apply(null, atomIndices), MS.struct.atomProperty.core.sourceIndex()]),
// 'group-by': 0
// });
// }

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

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

View File

@@ -2,15 +2,20 @@
* Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import '../../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';
require('mol-plugin/skin/light.scss')
import { LoadCellPackModel } from './extensions/cellpack/model';
import { StructureFromCellpack } from './extensions/cellpack/state';
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');
@@ -21,7 +26,12 @@ const hideControls = getParam('hide-controls', `[^&]+`) === '1';
function init() {
const spec: PluginSpec = {
actions: [...DefaultPluginSpec.actions, PluginSpec.Action(CreateJoleculeState)],
actions: [
...DefaultPluginSpec.actions,
// PluginSpec.Action(CreateJoleculeState),
PluginSpec.Action(LoadCellPackModel),
PluginSpec.Action(StructureFromCellpack),
],
behaviors: [...DefaultPluginSpec.behaviors],
animations: [...DefaultPluginSpec.animations || []],
customParamEditors: DefaultPluginSpec.customParamEditors,
@@ -33,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) {
@@ -48,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) {
const id = model.label.toLowerCase();
const req = await fetch(`https://proteopedia.org/cgi-bin/cnsrf?${id}`);
const json = await req.json();
label: 'Evolutionary Conservation',
type: 'static',
async getData(model: Model, ctx: CustomProperty.Context) {
const id = model.entryId.toLowerCase();
const url = `https://proteopedia.org/cgi-bin/cnsrf?${id}`
const json = await ctx.fetch({ url, type: 'json' }).runInContext(ctx.runtime)
const annotations = (json && json.residueAnnotations) || [];
const conservationMap = new Map<string, number>();
@@ -65,7 +67,7 @@ export const EvolutionaryConservation = CustomElementProperty.create<number>({
},
defaultColor: EvolutionaryConservationDefaultColor
},
format(e) {
getLabel(e) {
if (e === 10) return `Evolutionary Conservation: InsufficientData`;
return e ? `Evolutionary Conservation: ${e}` : void 0;
}

View File

@@ -1,3 +1,18 @@
== v3.4 ==
* Fixed HET group reset.
* Updated core.
* Removed Camera Cliping.
== v3.3 ==
* Camera Clipping.
== v3.2 ==
* Fixed assembly loading.
* Better HET group focus.
== v3.0 ==
* Fixed initial camera zoom.

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.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) {
@@ -67,11 +67,11 @@ export function createProteopediaCustomTheme(colors: number[]) {
}
color = (location: Location): Color => {
if (StructureElement.isLocation(location)) {
if (StructureElement.Location.is(location)) {
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[] }[],
@@ -18,9 +19,9 @@ export interface ModelInfo {
export namespace ModelInfo {
async function getPreferredAssembly(ctx: PluginContext, model: Model) {
if (model.label.length <= 3) return void 0;
if (model.entryId.length <= 3) return void 0;
try {
const id = model.label.toLowerCase();
const id = model.entryId.toLowerCase();
const src = await ctx.runTask(ctx.fetch({ url: `https://www.ebi.ac.uk/pdbe/api/pdb/entry/summary/${id}` })) as string;
const json = JSON.parse(src);
const data = json && json[id];
@@ -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 {
@@ -115,5 +116,6 @@ export enum StateElements {
Water = 'water',
WaterVisual = 'water-visual',
HetGroupFocus = 'het-group-focus'
HetGroupFocus = 'het-group-focus',
HetGroupFocusGroup = 'het-group-focus-group'
}

View File

@@ -130,7 +130,11 @@
addSeparator();
addHeader('Camera');
addControl('Toggle Spin', () => PluginWrapper.toggleSpin());
addControl('Reset Position', () => PluginWrapper.camera.resetPosition());
addControl('Toggle Spin', () => PluginWrapper.camera.toggleSpin());
// Same as "wheel icon" and Viewport options
// addControl('Clip', () => PluginWrapper.viewport.setSettings({ clip: [33, 66] }));
// addControl('Reset Clip', () => PluginWrapper.viewport.setSettings({ clip: [1, 100] }));
addSeparator();
@@ -149,7 +153,8 @@
addSeparator();
addHeader('Misc');
addControl('Apply Evo Cons', () => PluginWrapper.coloring.evolutionaryConservation());
addControl('Apply Evo Cons Style', () => PluginWrapper.coloring.evolutionaryConservation());
addControl('Apply Evo Cons Colors', () => PluginWrapper.coloring.evolutionaryConservation({ sequence: true, het: false, keepStyle: true }));
addControl('Default Visuals', () => PluginWrapper.updateStyle());
addSeparator();

View File

@@ -8,35 +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/tables';
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 = 1;
static VERSION_MAJOR = 4;
static VERSION_MINOR = 0;
private _ev = RxEventHelper.create();
@@ -58,30 +55,30 @@ 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) {
return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
}
private model(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
private model(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats) {
const parsed = format === 'cif'
? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
: b.apply(StateTransforms.Model.TrajectoryFromPDB);
@@ -92,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 });
@@ -118,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'
}));
}
}
@@ -133,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
}));
}
}
}
@@ -149,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' }));
}
}
}
@@ -160,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
}));
}
}
@@ -186,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 = '', representationStyle }: LoadParams) {
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';
@@ -202,40 +209,83 @@ class MolStarProteopediaWrapper {
}
if (loadType === 'full') {
await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
const modelTree = this.model(this.download(state.build().toRoot(), url), format, assemblyId);
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);
const structureTree = this.structure((assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId);
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
const structureTree = this.structure(asmId);
await this.applyState(structureTree);
} else {
const tree = state.build();
tree.to(StateElements.Assembly).update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
const info = await this.doInfo(true);
const asmId = (assemblyId === 'preferred' && info && info.preferredAssemblyId) || assemblyId;
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(this.plugin, {
settings: settings || DefaultCanvas3DParams
});
}
};
camera = {
toggleSpin: () => this.toggleSpin(),
resetPosition: () => PluginCommands.Camera.Reset(this.plugin, { }),
// setClip: (options?: { distance?: number, near?: number, far?: number }) => {
// if (!options) {
// PluginCommands.Canvas3D.SetSettings(this.plugin, {
// settings: {
// cameraClipDistance: DefaultCanvas3DParams.cameraClipDistance,
// clip: DefaultCanvas3DParams.clip
// }
// });
// return;
// }
// options = options || { };
// 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(this.plugin, {
// settings: { cameraClipDistance: options.distance, clip: [clipNear, clipFar] }
// });
// }
}
animate = {
@@ -250,20 +300,28 @@ class MolStarProteopediaWrapper {
}
coloring = {
evolutionaryConservation: async () => {
await this.updateStyle({ sequence: { kind: 'spacefill' } }, true);
evolutionaryConservation: async (params?: { sequence?: boolean, het?: boolean, keepStyle?: boolean }) => {
if (!params || !params.keepStyle) {
await this.updateStyle({ sequence: { kind: 'spacefill' } }, true);
}
const state = this.state;
// const visuals = state.selectQ(q => q.ofType(PluginStateObject.Molecule.Structure.Representation3D).filter(c => c.transform.transformer === StateTransforms.Representation.StructureRepresentation3D));
const tree = state.build();
const colorTheme = { name: EvolutionaryConservation.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(EvolutionaryConservation.Descriptor.name).defaultValues };
tree.to(StateElements.SequenceVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
// for (const v of visuals) {
// }
await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
const tree = state.build();
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 }));
}
if (params && !!params.het) {
tree.to(StateElements.HetVisual).update(StateTransforms.Representation.StructureRepresentation3D, old => ({ ...old, colorTheme }));
}
await PluginCommands.State.Update(this.plugin, { state, tree });
}
}
@@ -271,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);
@@ -281,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;
@@ -291,34 +351,34 @@ class MolStarProteopediaWrapper {
hetGroups = {
reset: () => {
const update = this.state.build().delete(StateElements.HetGroupFocus);
PluginCommands.State.Update.dispatch(this.plugin, { state: this.state, tree: update });
PluginCommands.Camera.Reset.dispatch(this.plugin, { });
const update = this.state.build().delete(StateElements.HetGroupFocusGroup);
PluginCommands.State.Update(this.plugin, { state: this.state, tree: update });
PluginCommands.Camera.Reset(this.plugin, { });
},
focusFirst: async (resn: string) => {
focusFirst: async (compId: string) => {
if (!this.state.transforms.has(StateElements.Assembly)) return;
await PluginCommands.Camera.Reset(this.plugin, { });
// const asm = (this.state.select(StateElements.Assembly)[0].obj as PluginStateObject.Molecule.Structure).data;
const update = this.state.build();
update.delete(StateElements.HetGroupFocus);
update.delete(StateElements.HetGroupFocusGroup);
const surroundings = MS.struct.modifier.includeSurroundings({
0: MS.struct.filter.first([
MS.struct.generator.atomGroups({
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), resn]),
'group-by': MS.struct.atomProperty.macromolecular.residueKey()
})
]),
radius: 5,
'as-whole-residues': true
});
const core = MS.struct.filter.first([
MS.struct.generator.atomGroups({
'residue-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_comp_id(), compId]),
'group-by': MS.core.str.concat([MS.struct.atomProperty.core.operatorName(), MS.struct.atomProperty.macromolecular.residueKey()])
})
]);
const surroundings = MS.struct.modifier.includeSurroundings({ 0: core, radius: 5, 'as-whole-residues': true });
const sel = update.to(StateElements.Assembly)
.apply(StateTransforms.Model.StructureSelection, { label: resn, query: surroundings }, { ref: StateElements.HetGroupFocus });
const group = update.to(StateElements.Assembly).group(StateTransforms.Misc.CreateGroup, { label: compId }, { ref: StateElements.HetGroupFocusGroup });
sel.apply(StateTransforms.Representation.StructureRepresentation3D, this.createSurVisualParams());
group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Core', expression: core }, { ref: StateElements.HetGroupFocus })
.apply(StateTransforms.Representation.StructureRepresentation3D, this.createCoreVisualParams());
group.apply(StateTransforms.Model.StructureSelectionFromExpression, { label: 'Surroundings', expression: surroundings })
.apply(StateTransforms.Representation.StructureRepresentation3D, this.createSurVisualParams());
// sel.apply(StateTransforms.Representation.StructureLabels3D, {
// target: { name: 'residues', params: { } },
// options: {
@@ -330,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;
@@ -338,17 +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, 0.75 * sphere.radius);
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 createStructureRepresentationParams(this.plugin, asm.data, {
type: 'ball-and-stick'
});
}
@@ -361,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

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

View File

@@ -1,39 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
export interface BooleanParamComponentProps {
label: string
param: PD.BooleanParam
value: boolean
onChange(v: boolean): void
}
export interface BooleanParamComponentState {
value: boolean
}
export class BooleanParamComponent extends React.Component<BooleanParamComponentProps, BooleanParamComponentState> {
state = {
value: this.props.value
}
onChange(value: boolean) {
this.setState({ value })
this.props.onChange(value)
}
render() {
return <div>
<span>{this.props.label} </span>
<button onClick={e => this.onChange(!this.state.value) }>
{this.state.value ? 'Off' : 'On'}
</button>
</div>;
}
}

View File

@@ -1,43 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { ColorNames } from '../../../mol-util/color/tables';
import { Color } from '../../../mol-util/color';
export interface ColorParamComponentProps {
label: string
param: PD.Color
value: Color
onChange(v: Color): void
}
export interface ColorParamComponentState {
value: Color
}
export class ColorParamComponent extends React.Component<ColorParamComponentProps, ColorParamComponentState> {
state = {
value: this.props.value
}
onChange(value: Color) {
this.setState({ value })
this.props.onChange(value)
}
render() {
return <div>
<span>{this.props.label} </span>
<select value={this.state.value} onChange={e => this.onChange(Color(parseInt(e.target.value))) }>
{Object.keys(ColorNames).map(name => {
return <option key={name} value={(ColorNames as { [k: string]: Color})[name]}>{name}</option>
})}
</select>
</div>;
}
}

View File

@@ -1,45 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
export interface MultiSelectParamComponentProps<T extends string> {
label: string
param: PD.MultiSelect<T>
value: T[]
onChange(v: T[]): void
}
export interface MultiSelectParamComponentState<T extends string> {
value: T[]
}
export class MultiSelectParamComponent<T extends string> extends React.Component<MultiSelectParamComponentProps<T>, MultiSelectParamComponentState<T>> {
state = {
value: this.props.value
}
onChange(value: T[]) {
this.setState({ value })
this.props.onChange(value)
}
render() {
return <div>
<span>{this.props.label} </span>
<select multiple value={this.state.value} onChange={e => {
const value = Array.from(e.target.options).filter(option => option.selected).map(option => option.value)
this.onChange(value as T[])
}}>
{this.props.param.options.map(v => {
const [value, label] = v
return <option key={label} value={value}>{label}</option>
})}
</select>
</div>;
}
}

View File

@@ -1,45 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
export interface NumberParamComponentProps {
label: string
param: PD.Numeric
value: number
onChange(v: number): void
}
export interface NumberParamComponentState {
value: number
}
export class NumberParamComponent extends React.Component<NumberParamComponentProps, NumberParamComponentState> {
state = {
value: this.props.value
}
onChange(valueStr: string) {
const value = this.props.param.step && Number.isInteger(this.props.param.step) ? parseInt(valueStr) : parseFloat(valueStr)
this.setState({ value })
this.props.onChange(value)
}
render() {
return <div>
<span>{this.props.label} </span>
<input type='range'
value={this.state.value}
min={this.props.param.min}
max={this.props.param.max}
step={this.props.param.step}
onChange={e => this.onChange(e.currentTarget.value)}
>
</input>
</div>;
}
}

View File

@@ -1,42 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
export interface SelectParamComponentProps<T extends string> {
label: string
param: PD.Select<T>
value: T
onChange(v: T): void
}
export interface SelectParamComponentState<T extends string> {
value: T
}
export class SelectParamComponent<T extends string> extends React.Component<SelectParamComponentProps<T>, SelectParamComponentState<T>> {
state = {
value: this.props.value
}
onChange(value: T) {
this.setState({ value })
this.props.onChange(value)
}
render() {
return <div>
<span>{this.props.label} </span>
<select value={this.state.value} onChange={e => this.onChange(e.target.value as T) }>
{this.props.param.options.map(v => {
const [value, label] = v
return <option key={label} value={value}>{label}</option>
})}
</select>
</div>;
}
}

View File

@@ -1,41 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
export interface TextParamComponentProps {
label: string
param: PD.Text
value: string
onChange(v: string): void
}
export interface TextParamComponentState {
value: string
}
export class TextParamComponent extends React.Component<TextParamComponentProps, TextParamComponentState> {
state = {
value: this.props.value
}
onChange(value: string) {
this.setState({ value })
this.props.onChange(value)
}
render() {
return <div>
<span>{this.props.label} </span>
<input type='text'
value={this.state.value}
onChange={e => this.onChange(e.currentTarget.value)}
>
</input>
</div>;
}
}

View File

@@ -1,64 +0,0 @@
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import * as React from 'react'
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { BooleanParamComponent } from './parameter/boolean';
import { NumberParamComponent } from './parameter/number';
import { SelectParamComponent } from './parameter/select';
import { MultiSelectParamComponent } from './parameter/multi-select';
import { TextParamComponent } from './parameter/text';
import { ColorParamComponent } from './parameter/color';
import { camelCaseToWords } from '../../mol-util/string';
interface ParametersProps<P extends PD.Params> {
params: P
values: { [k in keyof P]: P[k]['defaultValue'] }
onChange<K extends keyof P>(k: K, v: P[K]['defaultValue']): void
}
type ParametersState = {}
function getParamComponent<P extends PD.Any>(label: string, param: PD.Any, value: P['defaultValue'], onChange: (v: P['defaultValue']) => void) {
switch (param.type) {
case 'boolean':
return <BooleanParamComponent label={label} param={param} value={value} onChange={onChange} />
case 'number':
return <NumberParamComponent label={label} param={param} value={value} onChange={onChange} />
case 'select':
return <SelectParamComponent label={label} param={param} value={value} onChange={onChange} />
case 'multi-select':
return <MultiSelectParamComponent label={label} param={param} value={value} onChange={onChange} />
case 'text':
return <TextParamComponent label={label} param={param} value={value} onChange={onChange} />
case 'color':
return <ColorParamComponent label={label} param={param} value={value} onChange={onChange} />
}
return ''
}
function getLabel(name: string, param: PD.Base<any>) {
return param.label === undefined ? camelCaseToWords(name) : param.label
}
export class ParametersComponent<P extends PD.Params> extends React.Component<ParametersProps<P>, ParametersState> {
onChange(k: string, value: any) {
this.props.onChange(k, value)
}
render() {
return <div style={{ width: '100%' }}>
{ Object.keys(this.props.params).map(k => {
const param = this.props.params[k]
const value = this.props.values[k]
const label = getLabel(k, param)
return <div key={k}>
{getParamComponent(label, param, value, v => this.onChange(k, v))}
</div>
})}
</div>;
}
}

View File

@@ -1,81 +0,0 @@
// /**
// * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
// *
// * @author David Sehnal <david.sehnal@gmail.com>
// */
// import * as React from 'react'
// import { Structure, StructureSequence, Queries, StructureSelection, StructureProperties, StructureQuery } from 'mol-model/structure';
// import { EmptyLoci } from 'mol-model/loci';
// export class SequenceView extends View<SequenceViewController, {}, {}> {
// render() {
// const s = this.controller.latestState.structure;
// if (!s) return <div className='molstar-sequence-view-wrap'>No structure available.</div>;
// const seqs = s.models[0].sequence.sequences;
// return <div className='molstar-sequence-view-wrap'>
// {seqs.map((seq, i) => <EntitySequence key={i} ctx={this.controller.context} seq={seq} structure={s} /> )}
// </div>;
// }
// }
// function createQuery(entityId: string, label_seq_id: number) {
// return Queries.generators.atoms({
// entityTest: ctx => StructureProperties.entity.id(ctx.element) === entityId,
// residueTest: ctx => StructureProperties.residue.label_seq_id(ctx.element) === label_seq_id
// });
// }
// // TODO: this is really ineffective and should be done using a canvas.
// class EntitySequence extends React.Component<{ ctx: Context, seq: StructureSequence.Entity, structure: Structure }> {
// raiseInteractityEvent(seqId?: number) {
// if (typeof seqId === 'undefined') {
// InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, EmptyLoci);
// return;
// }
// const query = createQuery(this.props.seq.entityId, seqId);
// const loci = StructureSelection.toLoci(StructureQuery.run(query, this.props.structure));
// if (loci.elements.length === 0) InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, EmptyLoci);
// else InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, loci);
// }
// render() {
// const { ctx, seq } = this.props;
// const { offset, sequence } = seq.sequence;
// const elems: JSX.Element[] = [];
// for (let i = 0, _i = sequence.length; i < _i; i++) {
// elems[elems.length] = <ResidueView ctx={ctx} seqId={offset + i} letter={sequence[i]} parent={this} key={i} />;
// }
// return <div style={{ wordWrap: 'break-word' }}>
// <span style={{ fontWeight: 'bold' }}>{this.props.seq.entityId}:{offset}&nbsp;</span>
// {elems}
// </div>;
// }
// }
// class ResidueView extends React.Component<{ ctx: Context, seqId: number, letter: string, parent: EntitySequence }, { isHighlighted: boolean }> {
// state = { isHighlighted: false }
// mouseEnter = () => {
// this.setState({ isHighlighted: true });
// this.props.parent.raiseInteractityEvent(this.props.seqId);
// }
// mouseLeave = () => {
// this.setState({ isHighlighted: false });
// this.props.parent.raiseInteractityEvent();
// }
// render() {
// return <span onMouseEnter={this.mouseEnter} onMouseLeave={this.mouseLeave}
// style={{ cursor: 'pointer', backgroundColor: this.state.isHighlighted ? 'yellow' : void 0 }}>
// {this.props.letter}
// </span>;
// }
// }

View File

@@ -7,17 +7,12 @@
import { Mat4, Vec3, Vec4, EPSILON } from '../mol-math/linear-algebra'
import { Viewport, cameraProject, cameraUnproject } from './camera/util';
import { Object3D } from '../mol-gl/object3d';
import { BehaviorSubject } from 'rxjs';
import { CameraTransitionManager } from './camera/transition';
import { BehaviorSubject } from 'rxjs';
export { Camera }
// TODO: slab controls that modify near/far planes?
class Camera implements Object3D {
readonly updatedViewProjection = new BehaviorSubject<Camera>(this);
class Camera {
readonly view: Mat4 = Mat4.identity();
readonly projection: Mat4 = Mat4.identity();
readonly projectionView: Mat4 = Mat4.identity();
@@ -32,14 +27,18 @@ class Camera implements Object3D {
width: 1, height: 1
}
near = 1
far = 10000
fogNear = 5000
fogFar = 10000
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); }
get direction() { return this.state.direction; }
set direction(v: Vec3) { Vec3.copy(this.state.direction, v); }
get up() { return this.state.up; }
set up(v: Vec3) { Vec3.copy(this.state.up, v); }
@@ -51,10 +50,12 @@ class Camera implements Object3D {
private deltaDirection = Vec3.zero();
private newPosition = Vec3.zero();
updateMatrices() {
update() {
const snapshot = this.state as Camera.Snapshot;
const height = 2 * Math.tan(snapshot.fov / 2) * Vec3.distance(snapshot.position, snapshot.target);
snapshot.zoom = this.viewport.height / height;
this.zoom = this.viewport.height / height;
updateClip(this);
switch (this.state.mode) {
case 'orthographic': updateOrtho(this); break;
@@ -62,11 +63,7 @@ class Camera implements Object3D {
default: throw new Error('unknown camera mode');
}
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON.Value) || !Mat4.areEqual(this.view, this.prevView, EPSILON.Value);
Mat4.mul(this.projectionView, this.projection, this.view)
Mat4.invert(this.inverseProjectionView, this.projectionView)
const changed = !Mat4.areEqual(this.projection, this.prevProjection, EPSILON) || !Mat4.areEqual(this.view, this.prevView, EPSILON);
if (changed) {
Mat4.mul(this.projectionView, this.projection, this.view)
@@ -74,52 +71,48 @@ class Camera implements Object3D {
Mat4.copy(this.prevView, this.view);
Mat4.copy(this.prevProjection, this.projection);
this.updatedViewProjection.next(this);
}
return changed;
}
setState(snapshot: Partial<Camera.Snapshot>) {
this.transition.apply(snapshot);
setState(snapshot: Partial<Camera.Snapshot>, durationMs?: number) {
this.transition.apply(snapshot, durationMs);
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 currentDistance = Vec3.distance(this.state.position, target)
const targetDistance = Math.abs((radius / aspectFactor) / Math.sin(fov / 2))
const deltaDistance = Math.abs(currentDistance - targetDistance)
const targetDistance = Math.abs((r / aspectFactor) / Math.sin(fov / 2))
Vec3.sub(this.deltaDirection, this.state.position, target)
Vec3.setMagnitude(this.deltaDirection, this.state.direction, deltaDistance)
if (currentDistance < targetDistance) Vec3.negate(this.deltaDirection, this.deltaDirection)
Vec3.add(this.newPosition, this.state.position, this.deltaDirection)
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)
return { target, position: Vec3.clone(this.newPosition) };
const state = Camera.copySnapshot(Camera.createDefaultSnapshot(), this.state)
state.target = Vec3.clone(target)
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) {
this.setState(this.getFocus(target, radius));
focus(target: Vec3, radius: number, durationMs?: number, up?: Vec3, dir?: Vec3) {
if (radius > 0) {
this.setState(this.getFocus(target, radius, up, dir), durationMs);
}
}
// lookAt(target: Vec3) {
// cameraLookAt(this.position, this.up, this.direction, target);
// }
// translate(v: Vec3) {
// Vec3.add(this.position, this.position, v);
// cameraLookAt(this.position, this.up, this.direction, this.target);
// }
project(out: Vec4, point: Vec3) {
return cameraProject(out, point, this.viewport, this.projectionView)
}
@@ -128,10 +121,6 @@ class Camera implements Object3D {
return cameraUnproject(out, point, this.viewport, this.inverseProjectionView)
}
dispose() {
this.updatedViewProjection.complete();
}
constructor(state?: Partial<Camera.Snapshot>, viewport = Viewport.create(-1, -1, 1, 1)) {
this.viewport = viewport;
Camera.copySnapshot(this.state, state);
@@ -142,13 +131,6 @@ class Camera implements Object3D {
namespace Camera {
export type Mode = 'perspective' | 'orthographic'
export interface ClippingInfo {
near: number,
far: number,
fogNear: number,
fogFar: number
}
/**
* Sets an offseted view in a larger frustum. This is useful for
* - multi-window or multi-monitor/multi-machine setups
@@ -176,64 +158,54 @@ namespace Camera {
export function createDefaultSnapshot(): Snapshot {
return {
mode: 'perspective',
fov: Math.PI / 4,
position: Vec3.zero(),
direction: Vec3.create(0, 0, -1),
position: Vec3.create(0, 0, 100),
up: Vec3.create(0, 1, 0),
target: Vec3.create(0, 0, 0),
near: 1,
far: 10000,
fogNear: 1,
fogFar: 10000,
fov: Math.PI / 4,
zoom: 1,
radius: 10,
radiusMax: 10,
fog: 50,
clipFar: true
};
}
export interface Snapshot {
mode: Mode,
mode: Mode
fov: number
position: Vec3,
// Normalized camera direction
direction: Vec3,
up: Vec3,
target: Vec3,
position: Vec3
up: Vec3
target: Vec3
near: number,
far: number,
fogNear: number,
fogFar: number,
fov: number,
zoom: number,
radius: number
radiusMax: number
fog: number
clipFar: boolean
}
export function copySnapshot(out: Snapshot, source?: Partial<Snapshot>) {
if (!source) return;
if (!source) return out;
if (typeof source.mode !== 'undefined') out.mode = source.mode;
if (typeof source.fov !== 'undefined') out.fov = source.fov;
if (typeof source.position !== 'undefined') Vec3.copy(out.position, source.position);
if (typeof source.direction !== 'undefined') Vec3.copy(out.direction, source.direction);
if (typeof source.up !== 'undefined') Vec3.copy(out.up, source.up);
if (typeof source.target !== 'undefined') Vec3.copy(out.target, source.target);
if (typeof source.near !== 'undefined') out.near = source.near;
if (typeof source.far !== 'undefined') out.far = source.far;
if (typeof source.fogNear !== 'undefined') out.fogNear = source.fogNear;
if (typeof source.fogFar !== 'undefined') out.fogFar = source.fogFar;
if (typeof source.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;
if (typeof source.fov !== 'undefined') out.fov = source.fov;
if (typeof source.zoom !== 'undefined') out.zoom = source.zoom;
return out;
}
}
const _center = Vec3.zero();
function updateOrtho(camera: Camera) {
const { viewport, state: { zoom, near, far }, viewOffset } = camera
const { viewport, zoom, near, far, viewOffset } = camera
const fullLeft = -(viewport.width - viewport.x) / 2
const fullRight = (viewport.width - viewport.x) / 2
@@ -250,7 +222,7 @@ function updateOrtho(camera: Camera) {
let top = cy + dy
let bottom = cy - dy
if (viewOffset && viewOffset.enabled) {
if (viewOffset.enabled) {
const zoomW = zoom / (viewOffset.width / viewOffset.fullWidth)
const zoomH = zoom / (viewOffset.height / viewOffset.fullHeight)
const scaleW = (fullRight - fullLeft) / viewOffset.width
@@ -265,21 +237,20 @@ function updateOrtho(camera: Camera) {
Mat4.ortho(camera.projection, left, right, top, bottom, near, far)
// build view matrix
Vec3.add(_center, camera.position, camera.direction)
Mat4.lookAt(camera.view, camera.position, _center, camera.up)
Mat4.lookAt(camera.view, camera.position, camera.target, camera.up)
}
function updatePers(camera: Camera) {
const aspect = camera.viewport.width / camera.viewport.height
const { state: { fov, near, far }, viewOffset } = camera
const { near, far, viewOffset } = camera
let top = near * Math.tan(0.5 * fov)
let top = near * Math.tan(0.5 * camera.state.fov)
let height = 2 * top
let width = aspect * height
let left = -0.5 * width
if (viewOffset && viewOffset.enabled) {
if (viewOffset.enabled) {
left += viewOffset.offsetX * width / viewOffset.fullWidth
top -= viewOffset.offsetY * height / viewOffset.fullHeight
width *= viewOffset.width / viewOffset.fullWidth
@@ -290,6 +261,33 @@ function updatePers(camera: Camera) {
Mat4.perspective(camera.projection, left, left + width, top, top - height, near, far)
// build view matrix
Vec3.add(_center, camera.position, camera.direction)
Mat4.lookAt(camera.view, camera.position, _center, camera.up)
Mat4.lookAt(camera.view, camera.position, camera.target, camera.up)
}
function updateClip(camera: Camera) {
let { radius, radiusMax, mode, fog, clipFar } = camera.state
if (radius < 0.01) radius = 0.01
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 = cameraDistance - (normalizedFar * fogNearFactor)
let fogFar = far
if (mode === 'perspective') {
// set at least to 5 to avoid slow sphere impostor rendering
near = Math.max(5, near)
far = Math.max(5, far)
} else {
near = Math.max(0, near)
far = Math.max(0, far)
}
camera.near = near;
camera.far = far;
camera.fogNear = fogNear;
camera.fogFar = fogFar;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2019 Mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
@@ -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 || 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) {
@@ -68,33 +75,23 @@ class CameraTransitionManager {
namespace CameraTransitionManager {
export type TransitionFunc = (out: Camera.Snapshot, t: number, source: Camera.Snapshot, target: Camera.Snapshot) => void
const _rot = Quat.identity();
export function defaultTransition(out: Camera.Snapshot, t: number, source: Camera.Snapshot, target: Camera.Snapshot): void {
Camera.copySnapshot(out, target);
// Rotate direction
const rot = Quat.identity();
Quat.slerp(rot, rot, Quat.rotationTo(Quat.zero(), source.direction, target.direction), t);
Vec3.transformQuat(out.direction, source.direction, rot);
// Rotate up
Quat.setIdentity(rot);
Quat.slerp(rot, rot, Quat.rotationTo(Quat.zero(), source.up, target.up), t);
Vec3.transformQuat(out.up, source.up, rot);
Quat.slerp(_rot, Quat.Identity, Quat.rotationTo(_rot, source.up, target.up), t);
Vec3.transformQuat(out.up, source.up, _rot);
// Lerp target
// Lerp target, position & radius
Vec3.lerp(out.target, source.target, target.target, t);
Vec3.lerp(out.position, source.position, target.position, t);
out.radius = lerp(source.radius, target.radius, t);
// TODO take change of `clipFar` into account
out.radiusMax = lerp(source.radiusMax, target.radiusMax, t);
// Update position
const dist = -lerp(Vec3.distance(source.position, source.target), Vec3.distance(target.position, target.target), t);
Vec3.scale(out.position, out.direction, dist);
Vec3.add(out.position, out.position, out.target);
// Lerp other props
out.zoom = lerp(source.zoom, target.zoom, t);
// Lerp fov & fog
out.fov = lerp(source.fov, target.fov, t);
out.near = lerp(source.near, target.near, t);
out.far = lerp(source.far, target.far, t);
out.fogNear = lerp(source.fogNear, target.fogNear, t);
out.fogFar = lerp(source.fogFar, target.fogFar, t);
out.fog = lerp(source.fog, target.fog, t);
}
}

View File

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

View File

@@ -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';
@@ -17,7 +18,7 @@ import { Representation } from '../mol-repr/representation';
import Scene from '../mol-gl/scene';
import { GraphicsRenderVariant } from '../mol-gl/webgl/render-item';
import { PickingId } from '../mol-geo/geometry/picking';
import { MarkerAction } from '../mol-geo/geometry/marker-data';
import { MarkerAction } from '../mol-util/marker-action';
import { Loci, EmptyLoci, isEmptyLoci } from '../mol-model/loci';
import { Camera } from './camera';
import { ParamDefinition as PD } from '../mol-util/param-definition';
@@ -26,19 +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 = {
// TODO: FPS cap?
// maxFps: PD.Numeric(30),
cameraMode: PD.Select('perspective', [['perspective', 'Perspective'], ['orthographic', 'Orthographic']]),
cameraClipDistance: PD.Numeric(0, { min: 0.0, max: 50.0, step: 0.1 }, { description: 'The distance between camera and scene at which to clip regardless of near clipping plane.' }),
clip: PD.Interval([1, 100], { min: 1, max: 100, step: 1 }),
fog: PD.Interval([50, 100], { min: 1, max: 100, step: 1 }),
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),
@@ -46,6 +58,7 @@ export const Canvas3DParams = {
trackball: PD.Group(TrackballControlsParams),
debug: PD.Group(DebugHelperParams)
}
export const DefaultCanvas3DParams = PD.getDefaultValues(Canvas3DParams);
export type Canvas3DProps = PD.Values<typeof Canvas3DParams>
export { Canvas3D }
@@ -53,27 +66,33 @@ export { Canvas3D }
interface Canvas3D {
readonly webgl: WebGLContext,
add: (repr: Representation.Any) => void
remove: (repr: Representation.Any) => void
update: (repr?: Representation.Any, keepBoundingSphere?: boolean) => void
clear: () => void
add(repr: Representation.Any): void
remove(repr: Representation.Any): void
/**
* This function must be called if animate() is not set up so that add/remove actions take place.
*/
commit(isSynchronous?: boolean): void
update(repr?: Representation.Any, keepBoundingSphere?: boolean): void
clear(): void
// draw: (force?: boolean) => void
requestDraw: (force?: boolean) => void
animate: () => void
identify: (x: number, y: number) => PickingId | undefined
mark: (loci: Representation.Loci, action: MarkerAction) => void
getLoci: (pickingId: PickingId) => Representation.Loci
requestDraw(force?: boolean): void
animate(): void
identify(x: number, y: number): PickingId | undefined
mark(loci: Representation.Loci, action: MarkerAction): void
getLoci(pickingId: PickingId): Representation.Loci
readonly didDraw: BehaviorSubject<now.Timestamp>
readonly reprCount: BehaviorSubject<number>
handleResize: () => void
handleResize(): void
/** Focuses camera on scene's bounding sphere, centered and zoomed. */
resetCamera: () => void
requestCameraReset(options?: { durationMs?: number, snapshot?: Partial<Camera.Snapshot> }): void
readonly camera: Camera
downloadScreenshot: () => void
getPixelData: (variant: GraphicsRenderVariant) => PixelData
setProps: (props: Partial<Canvas3DProps>) => void
readonly boundingSphere: Readonly<Sphere3D>
downloadScreenshot(): void
getPixelData(variant: GraphicsRenderVariant): PixelData
setProps(props: Partial<Canvas3DProps>): void
getImagePass(): ImagePass
/** Returns a copy of the current Canvas3D instance props */
readonly props: Readonly<Canvas3DProps>
@@ -81,29 +100,66 @@ interface Canvas3D {
readonly stats: RendererStats
readonly interaction: Canvas3dInteractionHelper['events']
dispose: () => void
dispose(): void
}
const requestAnimationFrame = typeof window !== 'undefined' ? window.requestAnimationFrame : (f: (time: number) => void) => setImmediate(()=>f(Date.now()))
const DefaultRunTask = (task: Task<unknown>) => task.run()
namespace Canvas3D {
export interface HighlightEvent { current: Representation.Loci, modifiers?: ModifiersKeys }
export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, modifiers: ModifiersKeys }
export interface HoverEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
export interface ClickEvent { current: Representation.Loci, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys }
export function fromCanvas(canvas: HTMLCanvasElement, props: Partial<Canvas3DProps> = {}) {
export function fromCanvas(canvas: HTMLCanvasElement, props: Partial<Canvas3DProps> = {}, runTask = DefaultRunTask) {
const gl = getGLContext(canvas, {
alpha: false,
alpha: true,
antialias: true,
depth: true,
preserveDrawingBuffer: true
preserveDrawingBuffer: true,
premultipliedAlpha: false,
})
if (gl === null) throw new Error('Could not create a WebGL rendering context')
const input = InputObserver.fromElement(canvas)
return Canvas3D.create(gl, input, props)
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> = {}): Canvas3D {
const p = { ...PD.getDefaultValues(Canvas3DParams), ...props }
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>>()
const reprUpdatedSubscriptions = new Map<Representation.Any, Subscription>()
@@ -112,31 +168,39 @@ namespace Canvas3D {
const startTime = now()
const didDraw = new BehaviorSubject<now.Timestamp>(0 as now.Timestamp)
const camera = new Camera({
near: 0.1,
far: 10000,
position: Vec3.create(0, 0, 10),
mode: p.cameraMode
})
const webgl = createContext(gl)
const { gl, contextRestored } = webgl
let width = gl.drawingBufferWidth
let height = gl.drawingBufferHeight
const scene = Scene.create(webgl)
const camera = new Camera({
position: Vec3.create(0, 0, 100),
mode: p.cameraMode,
fog: p.cameraFog.name === 'on' ? p.cameraFog.params.intensity : 0,
clipFar: p.cameraClipping.far
})
const controls = TrackballControls.create(input, camera, p.trackball)
const renderer = Renderer.create(webgl, camera, p.renderer)
const renderer = Renderer.create(webgl, p.renderer)
const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug);
const interactionHelper = new Canvas3dInteractionHelper(identify, getLoci, input);
const drawPass = new DrawPass(webgl, renderer, scene, debugHelper)
const pickPass = new PickPass(webgl, renderer, scene, 0.5)
const drawPass = new DrawPass(webgl, renderer, scene, camera, debugHelper)
const pickPass = new PickPass(webgl, renderer, scene, camera, 0.5)
const postprocessing = new PostprocessingPass(webgl, camera, drawPass, p.postprocessing)
const multiSample = new MultiSamplePass(webgl, camera, drawPass, postprocessing, p.multiSample)
let isUpdating = false
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
@@ -144,7 +208,9 @@ namespace Canvas3D {
reprRenderObjects.forEach((_, _repr) => {
const _loci = _repr.getLoci(pickingId)
if (!isEmptyLoci(_loci)) {
if (!isEmptyLoci(loci)) console.warn('found another loci')
if (!isEmptyLoci(loci)) {
console.warn('found another loci, this should not happen')
}
loci = _loci
repr = _repr
}
@@ -168,75 +234,35 @@ namespace Canvas3D {
}
}
let currentNear = -1, currentFar = -1, currentFogNear = -1, currentFogFar = -1
function setClipping() {
const cDist = Vec3.distance(camera.state.position, camera.state.target)
const bRadius = Math.max(10, scene.boundingSphere.radius)
const nearFactor = (50 - p.clip[0]) / 50
const farFactor = -(50 - p.clip[1]) / 50
let near = cDist - (bRadius * nearFactor)
let far = cDist + (bRadius * farFactor)
const fogNearFactor = (50 - p.fog[0]) / 50
const fogFarFactor = -(50 - p.fog[1]) / 50
let fogNear = cDist - (bRadius * fogNearFactor)
let fogFar = cDist + (bRadius * fogFarFactor)
if (camera.state.mode === 'perspective') {
near = Math.max(1, p.cameraClipDistance, near)
far = Math.max(1, far)
fogNear = Math.max(1, fogNear)
fogFar = Math.max(1, fogFar)
} else if (camera.state.mode === 'orthographic') {
if (p.cameraClipDistance > 0) {
near = Math.max(p.cameraClipDistance, near)
}
}
if (near !== currentNear || far !== currentFar || fogNear !== currentFogNear || fogFar !== currentFogFar) {
camera.setState({ near, far, fogNear, fogFar })
currentNear = near, currentFar = far, currentFogNear = fogNear, currentFogFar = fogFar
}
}
function render(variant: 'pick' | 'draw', force: boolean) {
if (isUpdating) return false
function render(force: boolean) {
if (webgl.isContextLost) return false
let didRender = false
controls.update(currentTime);
// TODO: is this a good fix? Also, setClipping does not work if the user has manually set a clipping plane.
if (!camera.transition.inTransition) setClipping();
const cameraChanged = camera.updateMatrices();
controls.update(currentTime)
Viewport.set(camera.viewport, 0, 0, width, height)
const cameraChanged = camera.update()
multiSample.update(force || cameraChanged, currentTime)
if (force || cameraChanged || multiSample.enabled) {
switch (variant) {
case 'pick':
pickPass.render()
break;
case 'draw':
renderer.setViewport(0, 0, width, height);
if (multiSample.enabled) {
multiSample.render()
} else {
drawPass.render(!postprocessing.enabled)
if (postprocessing.enabled) postprocessing.render(true)
}
pickPass.pickDirty = true
break;
renderer.setViewport(0, 0, width, height)
if (multiSample.enabled) {
multiSample.render(true, p.transparentBackground)
} else {
drawPass.render(!postprocessing.enabled, p.transparentBackground)
if (postprocessing.enabled) postprocessing.render(true)
}
pickPass.pickDirty = true
didRender = true
}
return didRender && cameraChanged;
return didRender;
}
let forceNextDraw = false;
let currentTime = 0;
function draw(force?: boolean) {
if (render('draw', !!force || forceNextDraw)) {
if (render(!!force || forceNextDraw)) {
didDraw.next(now() - startTime as now.Timestamp)
}
forceNextDraw = false;
@@ -251,36 +277,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(isSynchronous: boolean = false) {
const allCommited = commitScene(isSynchronous);
// Only reset the camera after the full scene has been commited.
if (allCommited) resolveCameraReset();
}
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) {
isUpdating = true
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)
scene.update(repr.renderObjects, false)
if (debugHelper.isEnabled) debugHelper.update()
isUpdating = false
requestDraw(true)
reprCount.next(reprRenderObjects.size)
}
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()
@@ -288,29 +377,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) {
isUpdating = true
renderObjects.forEach(o => scene.remove(o))
reprRenderObjects.delete(repr)
scene.update(void 0, false)
if (debugHelper.isEnabled) debugHelper.update()
isUpdating = false
requestDraw(true)
reprCount.next(reprRenderObjects.size)
}
},
add,
remove,
commit,
update: (repr, keepSphere) => {
if (repr) {
if (!reprRenderObjects.has(repr)) return;
@@ -320,9 +389,13 @@ namespace Canvas3D {
}
},
clear: () => {
reprUpdatedSubscriptions.forEach(v => v.unsubscribe())
reprUpdatedSubscriptions.clear()
reprRenderObjects.clear()
scene.clear()
debugHelper.clear()
requestDraw(true)
reprCount.next(reprRenderObjects.size)
},
// draw,
@@ -333,11 +406,13 @@ namespace Canvas3D {
getLoci,
handleResize,
resetCamera: () => {
camera.focus(scene.boundingSphere.center, scene.boundingSphere.radius)
requestDraw(true);
requestCameraReset: options => {
nextCameraResetDuration = options?.durationMs;
nextCameraResetSnapshot = options?.snapshot;
cameraResetRequested = true;
},
camera,
boundingSphere: scene.boundingSphere,
downloadScreenshot: () => {
// TODO
},
@@ -351,28 +426,58 @@ 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.cameraClipDistance !== undefined) p.cameraClipDistance = props.cameraClipDistance
if (props.clip !== undefined) p.clip = [props.clip[0], props.clip[1]]
if (props.fog !== undefined) p.fog = [props.fog[0], props.fog[1]]
if (props.cameraFog !== undefined) {
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> = {}) => {
return new ImagePass(webgl, renderer, scene, camera, debugHelper, props)
},
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,
cameraClipDistance: p.cameraClipDistance,
clip: p.clip,
fog: p.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 },
@@ -391,12 +496,13 @@ namespace Canvas3D {
return interactionHelper.events
},
dispose: () => {
contextRestoredSub.unsubscribe()
scene.clear()
debugHelper.clear()
input.dispose()
controls.dispose()
renderer.dispose()
camera.dispose()
interactionHelper.dispose()
}
}

View File

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

View File

@@ -13,7 +13,7 @@ import Scene from '../../mol-gl/scene';
import { WebGLContext } from '../../mol-gl/webgl/context';
import { Sphere3D } from '../../mol-math/geometry';
import { Color } from '../../mol-util/color';
import { ColorNames } from '../../mol-util/color/tables';
import { ColorNames } from '../../mol-util/color/names';
import { TransformData } from '../../mol-geo/geometry/transform-data';
import { sphereVertexCount } from '../../mol-geo/primitive/sphere';
import { ValueCell } from '../../mol-util';
@@ -53,19 +53,17 @@ export class BoundingSphereHelper {
const newObjectData = updateBoundingSphereData(this.scene, r.values.boundingSphere.ref.value, objectData, ColorNames.tomato)
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, {
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) => {
@@ -81,7 +79,8 @@ export class BoundingSphereHelper {
}
})
this.scene.update(void 0, false);
this.scene.update(void 0, false)
this.scene.commit()
}
syncVisibility() {
@@ -132,7 +131,11 @@ 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) {
for (const b of Sphere3D.getList(boundingSphere)) {
addSphere(builderState, b.center, b.radius, detail)
}
}
return MeshBuilder.getMesh(builderState)
}

View File

@@ -11,13 +11,15 @@ import InputObserver, { ModifiersKeys, ButtonsType } from '../../mol-util/input/
import { RxEventHelper } from '../../mol-util/rx-event-helper';
type Canvas3D = import('../canvas3d').Canvas3D
type HoverEvent = import('../canvas3d').Canvas3D.HoverEvent
type ClickEvent = import('../canvas3d').Canvas3D.ClickEvent
export class Canvas3dInteractionHelper {
private ev = RxEventHelper.create();
readonly events = {
highlight: this.ev<import('../canvas3d').Canvas3D.HighlightEvent>(),
click: this.ev<import('../canvas3d').Canvas3D.ClickEvent>(),
hover: this.ev<HoverEvent>(),
click: this.ev<ClickEvent>(),
};
private cX = -1;
@@ -36,6 +38,7 @@ export class Canvas3dInteractionHelper {
private inside = false;
private buttons: ButtonsType = ButtonsType.create(0);
private button: ButtonsType.Flag = ButtonsType.create(0);
private modifiers: ModifiersKeys = ModifiersKeys.None;
private identify(isClick: boolean, t: number) {
@@ -48,18 +51,18 @@ export class Canvas3dInteractionHelper {
if (!this.id) return;
if (isClick) {
this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, modifiers: this.modifiers });
this.events.click.next({ current: this.getLoci(this.id), buttons: this.buttons, button: this.button, modifiers: this.modifiers });
return;
}
// only highlight the latest
if (!this.inside || this.currentIdentifyT !== t) {
return;
}
const loci = this.getLoci(this.id);
// only broadcast the latest hover
if (!Representation.Loci.areEqual(this.prevLoci, loci)) {
this.events.highlight.next({ current: loci, modifiers: this.modifiers });
this.events.hover.next({ current: loci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
this.prevLoci = loci;
}
}
@@ -76,21 +79,24 @@ export class Canvas3dInteractionHelper {
this.inside = false;
if (this.prevLoci.loci !== EmptyLoci) {
this.prevLoci = Representation.Loci.Empty;
this.events.highlight.next({ current: this.prevLoci });
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
}
}
move(x: number, y: number, modifiers: ModifiersKeys) {
move(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
this.inside = true;
this.buttons = buttons;
this.button = button;
this.modifiers = modifiers;
this.cX = x;
this.cY = y;
}
select(x: number, y: number, buttons: ButtonsType, modifiers: ModifiersKeys) {
select(x: number, y: number, buttons: ButtonsType, button: ButtonsType.Flag, modifiers: ModifiersKeys) {
this.cX = x;
this.cY = y;
this.buttons = buttons;
this.button = button;
this.modifiers = modifiers;
this.identify(true, 0);
}
@@ -98,7 +104,7 @@ export class Canvas3dInteractionHelper {
modify(modifiers: ModifiersKeys) {
if (this.prevLoci.loci === EmptyLoci || ModifiersKeys.areEqual(modifiers, this.modifiers)) return;
this.modifiers = modifiers;
this.events.highlight.next({ current: this.prevLoci, modifiers: this.modifiers });
this.events.hover.next({ current: this.prevLoci, buttons: this.buttons, button: this.button, modifiers: this.modifiers });
}
dispose() {
@@ -106,17 +112,17 @@ export class Canvas3dInteractionHelper {
}
constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], input: InputObserver, private maxFps: number = 15) {
input.move.subscribe(({x, y, inside, buttons, modifiers }) => {
if (!inside || buttons) { return; }
this.move(x, y, modifiers);
input.move.subscribe(({x, y, inside, buttons, button, modifiers }) => {
if (!inside) return;
this.move(x, y, buttons, button, modifiers);
});
input.leave.subscribe(() => {
this.leave();
});
input.click.subscribe(({x, y, buttons, modifiers }) => {
this.select(x, y, buttons, modifiers);
input.click.subscribe(({x, y, buttons, button, modifiers }) => {
this.select(x, y, buttons, button, modifiers);
});
input.modifiers.subscribe(modifiers => this.modify(modifiers));

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ import { ShaderCode } from '../../mol-gl/shader-code';
import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
import { createComputeRenderable, ComputeRenderable } from '../../mol-gl/renderable';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { RenderTarget, createRenderTarget } from '../../mol-gl/webgl/render-target';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import { Camera } from '../../mol-canvas3d/camera';
import { PostprocessingPass } from './postprocessing';
import { DrawPass } from './draw';
@@ -35,7 +35,7 @@ function getComposeRenderable(ctx: WebGLContext, colorTexture: Texture): Compose
const values: Values<typeof ComposeSchema> = {
...QuadValues,
tColor: ValueCell.create(colorTexture),
uTexSize: ValueCell.create(Vec2.create(colorTexture.width, colorTexture.height)),
uTexSize: ValueCell.create(Vec2.create(colorTexture.getWidth(), colorTexture.getHeight())),
uWeight: ValueCell.create(1.0),
}
@@ -54,6 +54,7 @@ export type MultiSampleProps = PD.Values<typeof MultiSampleParams>
export class MultiSamplePass {
props: MultiSampleProps
colorTarget: RenderTarget
private composeTarget: RenderTarget
private holdTarget: RenderTarget
@@ -65,8 +66,9 @@ export class MultiSamplePass {
constructor(private webgl: WebGLContext, private camera: Camera, private drawPass: DrawPass, private postprocessing: PostprocessingPass, props: Partial<MultiSampleProps>) {
const { gl } = webgl
this.composeTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.holdTarget = createRenderTarget(webgl, gl.drawingBufferWidth, gl.drawingBufferHeight)
this.colorTarget = webgl.createRenderTarget(gl.drawingBufferWidth, gl.drawingBufferHeight)
this.composeTarget = webgl.createRenderTarget(gl.drawingBufferWidth, gl.drawingBufferHeight)
this.holdTarget = webgl.createRenderTarget(gl.drawingBufferWidth, gl.drawingBufferHeight)
this.compose = getComposeRenderable(webgl, drawPass.colorTarget.texture)
this.props = { ...PD.getDefaultValues(MultiSampleParams), ...props }
}
@@ -92,6 +94,7 @@ export class MultiSamplePass {
}
setSize(width: number, height: number) {
this.colorTarget.setSize(width, height)
this.composeTarget.setSize(width, height)
this.holdTarget.setSize(width, height)
ValueCell.update(this.compose.values.uTexSize, Vec2.set(this.compose.values.uTexSize.ref.value, width, height))
@@ -102,15 +105,15 @@ export class MultiSamplePass {
if (props.sampleLevel !== undefined) this.props.sampleLevel = props.sampleLevel
}
render() {
render(toDrawingBuffer: boolean, transparentBackground: boolean) {
if (this.props.mode === 'temporal') {
this.renderTemporalMultiSample()
this.renderTemporalMultiSample(toDrawingBuffer, transparentBackground)
} else {
this.renderMultiSample()
this.renderMultiSample(toDrawingBuffer, transparentBackground)
}
}
private renderMultiSample() {
private renderMultiSample(toDrawingBuffer: boolean, transparentBackground: boolean) {
const { camera, compose, composeTarget, drawPass, postprocessing, webgl } = this
const { gl, state } = webgl
@@ -128,14 +131,15 @@ export class MultiSamplePass {
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawPass.colorTarget.texture)
compose.update()
const { width, height } = drawPass.colorTarget
const width = drawPass.colorTarget.getWidth()
const height = drawPass.colorTarget.getHeight()
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
for (let i = 0; i < offsetList.length; ++i) {
const offset = offsetList[i]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
camera.update()
// the theory is that equal weights for each sample lead to an accumulation of rounding
// errors. The following equation varies the sampleWeight per sample so that it is uniformly
@@ -145,7 +149,7 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, sampleWeight)
// render scene and optionally postprocess
drawPass.render(false)
drawPass.render(false, transparentBackground)
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
@@ -168,16 +172,20 @@ export class MultiSamplePass {
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
this.colorTarget.bind()
}
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
camera.viewOffset.enabled = false
camera.updateMatrices()
camera.update()
}
private renderTemporalMultiSample() {
private renderTemporalMultiSample(toDrawingBuffer: boolean, transparentBackground: boolean) {
const { camera, compose, composeTarget, holdTarget, postprocessing, drawPass, webgl } = this
const { gl, state } = webgl
@@ -197,7 +205,7 @@ export class MultiSamplePass {
const i = this.sampleIndex
if (i === 0) {
drawPass.render(false)
drawPass.render(false, transparentBackground)
if (postprocessing.enabled) postprocessing.render(false)
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, postprocessing.enabled ? postprocessing.target.texture : drawPass.colorTarget.texture)
@@ -215,7 +223,8 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, sampleWeight)
compose.update()
const { width, height } = drawPass.colorTarget
const width = drawPass.colorTarget.getWidth()
const height = drawPass.colorTarget.getHeight()
// render the scene multiple times, each slightly jitter offset
// from the last and accumulate the results.
@@ -223,10 +232,10 @@ export class MultiSamplePass {
for (let i = 0; i < numSamplesPerFrame; ++i) {
const offset = offsetList[this.sampleIndex]
Camera.setViewOffset(camera.viewOffset, width, height, offset[0], offset[1], width, height)
camera.updateMatrices()
camera.update()
// render scene and optionally postprocess
drawPass.render(false)
drawPass.render(false, transparentBackground)
if (postprocessing.enabled) postprocessing.render(false)
// compose rendered scene with compose target
@@ -252,7 +261,11 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, 1.0)
ValueCell.update(compose.values.tColor, composeTarget.texture)
compose.update()
webgl.unbindFramebuffer()
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
this.colorTarget.bind()
}
gl.viewport(0, 0, width, height)
state.disable(gl.BLEND)
compose.render()
@@ -261,7 +274,11 @@ export class MultiSamplePass {
ValueCell.update(compose.values.uWeight, 1.0 - accumulationWeight)
ValueCell.update(compose.values.tColor, holdTarget.texture)
compose.update()
webgl.unbindFramebuffer()
if (toDrawingBuffer) {
webgl.unbindFramebuffer()
} else {
this.colorTarget.bind()
}
gl.viewport(0, 0, width, height)
if (accumulationWeight === 0) state.disable(gl.BLEND)
else state.enable(gl.BLEND)
@@ -269,7 +286,7 @@ export class MultiSamplePass {
}
camera.viewOffset.enabled = false
camera.updateMatrices()
camera.update()
if (this.sampleIndex >= offsetList.length) this.sampleIndex = -1
}
}

View File

@@ -5,25 +5,29 @@
*/
import { WebGLContext } from '../../mol-gl/webgl/context';
import { createRenderTarget, RenderTarget } from '../../mol-gl/webgl/render-target';
import { RenderTarget } from '../../mol-gl/webgl/render-target';
import Renderer from '../../mol-gl/renderer';
import Scene from '../../mol-gl/scene';
import { PickingId } from '../../mol-geo/geometry/picking';
import { decodeFloatRGB } from '../../mol-util/float-packing';
const readBuffer = new Uint8Array(4)
import { Camera } from '../camera';
export class PickPass {
pickDirty = true
objectPickTarget: RenderTarget
instancePickTarget: RenderTarget
groupPickTarget: RenderTarget
private objectBuffer: Uint8Array
private instanceBuffer: Uint8Array
private groupBuffer: Uint8Array
private pickScale: number
private pickWidth: number
private pickHeight: number
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private pickBaseScale: number) {
constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private pickBaseScale: number) {
const { gl } = webgl
const width = gl.drawingBufferWidth
const height = gl.drawingBufferHeight
@@ -31,35 +35,75 @@ export class PickPass {
this.pickScale = pickBaseScale / webgl.pixelRatio
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()
}
private setupBuffers() {
const bufferSize = this.pickWidth * this.pickHeight * 4
if (!this.objectBuffer || this.objectBuffer.length !== bufferSize) {
this.objectBuffer = new Uint8Array(bufferSize)
this.instanceBuffer = new Uint8Array(bufferSize)
this.groupBuffer = new Uint8Array(bufferSize)
}
}
setSize(width: number, height: number) {
this.pickScale = this.pickBaseScale / this.webgl.pixelRatio
this.pickWidth = Math.round(width * this.pickScale)
this.pickHeight = Math.round(height * this.pickScale)
this.objectPickTarget.setSize(this.pickWidth, this.pickHeight)
this.instancePickTarget.setSize(this.pickWidth, this.pickHeight)
this.groupPickTarget.setSize(this.pickWidth, this.pickHeight)
this.setupBuffers()
}
render() {
const { renderer, scene } = this
const { renderer, scene, camera } = this
renderer.setViewport(0, 0, this.pickWidth, this.pickHeight);
this.objectPickTarget.bind();
renderer.render(scene, 'pickObject', true);
renderer.render(scene, camera, 'pickObject', true, false);
this.instancePickTarget.bind();
renderer.render(scene, 'pickInstance', true);
renderer.render(scene, camera, 'pickInstance', true, false);
this.groupPickTarget.bind();
renderer.render(scene, 'pickGroup', true);
renderer.render(scene, camera, 'pickGroup', true, false);
this.pickDirty = false
}
private syncBuffers() {
const { webgl } = this
this.objectPickTarget.bind()
webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.objectBuffer)
this.instancePickTarget.bind()
webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.instanceBuffer)
this.groupPickTarget.bind()
webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.groupBuffer)
}
private getId(x: number, y: number, buffer: Uint8Array) {
const idx = (y * this.pickWidth + x) * 4
return decodeFloatRGB(buffer[idx], buffer[idx + 1], buffer[idx + 2])
}
identify(x: number, y: number): PickingId | undefined {
const { webgl, pickScale } = this
if (webgl.isContextLost) return
const { gl } = webgl
if (this.pickDirty) this.render()
if (this.pickDirty) {
this.render()
this.syncBuffers()
}
x *= webgl.pixelRatio
y *= webgl.pixelRatio
@@ -68,19 +112,13 @@ export class PickPass {
const xp = Math.round(x * pickScale)
const yp = Math.round(y * pickScale)
this.objectPickTarget.bind()
webgl.readPixels(xp, yp, 1, 1, readBuffer)
const objectId = decodeFloatRGB(readBuffer[0], readBuffer[1], readBuffer[2])
const objectId = this.getId(xp, yp, this.objectBuffer)
if (objectId === -1) return
this.instancePickTarget.bind()
webgl.readPixels(xp, yp, 1, 1, readBuffer)
const instanceId = decodeFloatRGB(readBuffer[0], readBuffer[1], readBuffer[2])
const instanceId = this.getId(xp, yp, this.instanceBuffer)
if (instanceId === -1) return
this.groupPickTarget.bind()
webgl.readPixels(xp, yp, 1, 1, readBuffer)
const groupId = decodeFloatRGB(readBuffer[0], readBuffer[1], readBuffer[2])
const groupId = this.getId(xp, yp, this.groupBuffer)
if (groupId === -1) return
return { objectId, instanceId, groupId }

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(64, { 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,49 +125,37 @@ 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()
}
render(toDrawingBuffer: boolean) {
ValueCell.update(this.renderable.values.uFar, this.camera.state.far)
ValueCell.update(this.renderable.values.uNear, this.camera.state.near)
ValueCell.update(this.renderable.values.uFogFar, this.camera.state.fogFar)
ValueCell.update(this.renderable.values.uFogNear, this.camera.state.fogNear)
ValueCell.update(this.renderable.values.uFar, this.camera.far)
ValueCell.update(this.renderable.values.uNear, this.camera.near)
ValueCell.update(this.renderable.values.uFogFar, this.camera.fogFar)
ValueCell.update(this.renderable.values.uFogNear, this.camera.fogNear)
ValueCell.update(this.renderable.values.dOrthographic, this.camera.state.mode === 'orthographic' ? 1 : 0)
const { gl, state } = this.webgl

View File

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

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -7,6 +7,8 @@
import * as ColumnHelpers from './column-helpers'
import { Tensor as Tensors } from '../../mol-math/linear-algebra'
import { Tokens } from '../../mol-io/reader/common/text/tokenizer';
import { parseInt as fastParseInt, parseFloat as fastParseFloat } from '../../mol-io/reader/common/text/number-parser';
interface Column<T> {
readonly schema: Column.Schema,
@@ -35,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' };
@@ -71,6 +73,7 @@ namespace Column {
rowCount: number,
schema: T,
valueKind?: (row: number) => ValueKind,
areValuesEqual?: (rowA: number, rowB: number) => boolean
}
export interface ArraySpec<T extends Schema> {
@@ -89,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);
@@ -128,6 +137,45 @@ 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({
value: (row: number) => fastParseInt(data, indices[2 * row], indices[2 * row + 1]) || 0,
rowCount: count,
schema: Schema.int,
});
}
export function ofFloatTokens(tokens: Tokens) {
const { count, data, indices } = tokens
return lambdaColumn({
value: (row: number) => fastParseFloat(data, indices[2 * row], indices[2 * row + 1]) || 0,
rowCount: count,
schema: Schema.float,
});
}
export function ofStringTokens(tokens: Tokens) {
const { count, data, indices } = tokens
return lambdaColumn({
value: (row: number) => {
const ret = data.substring(indices[2 * row], indices[2 * row + 1]);
if (ret === '.' || ret === '?') return '';
return ret;
},
rowCount: count,
schema: Schema.str,
});
}
export function window<T>(column: Column<T>, start: number, end: number) {
return windowColumn(column, start, end);
}
@@ -214,7 +262,7 @@ function constColumn<T extends Column.Schema>(v: T['T'], rowCount: number, schem
}
}
function lambdaColumn<T extends Column.Schema>({ value, valueKind, rowCount, schema }: Column.LambdaSpec<T>): Column<T['T']> {
function lambdaColumn<T extends Column.Schema>({ value, valueKind, areValuesEqual, rowCount, schema }: Column.LambdaSpec<T>): Column<T['T']> {
return {
schema: schema,
__array: void 0,
@@ -227,7 +275,7 @@ function lambdaColumn<T extends Column.Schema>({ value, valueKind, rowCount, sch
for (let i = 0, _i = array.length; i < _i; i++) array[i] = value(i + start);
return array;
},
areValuesEqual: (rowA, rowB) => value(rowA) === value(rowB)
areValuesEqual: areValuesEqual ? areValuesEqual : (rowA, rowB) => value(rowA) === value(rowB)
}
}
@@ -256,19 +304,19 @@ 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]
}
}
function windowColumn<T>(column: Column<T>, start: number, end: number) {
function windowColumn<T>(column: Column<T>, start: number, end: number): Column<T> {
if (!column.isDefined) return Column.Undefined(end - start, column.schema);
if (start === 0 && end === column.rowCount) return column;
if (!!column.__array && ColumnHelpers.isTypedArray(column.__array)) return windowTyped(column, start, end);
@@ -277,7 +325,8 @@ function windowColumn<T>(column: Column<T>, start: number, end: number) {
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> {
@@ -309,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);
}
@@ -319,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) {
@@ -218,6 +237,16 @@ namespace Table {
return ret;
}
export function toArrays<S extends Schema>(table: Table<S>) {
const arrays: { [k: string]: ArrayLike<any> } = {}
const { _columns } = table;
for (let i = 0; i < _columns.length; i++) {
const c = _columns[i]
arrays[c] = table[c].toArray();
}
return arrays as { [k in keyof S]: ArrayLike<S[k]['T']> }
}
export function formatToString<S extends Schema>(table: Table<S>) {
const sb = StringBuilder.create();

View File

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

View File

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

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import OrderedSet from '../ordered-set'
import Interval from '../interval'
import SortedArray from '../sorted-array';
describe('ordered set', () => {
function ordSetToArray(set: OrderedSet) {
@@ -81,6 +82,13 @@ describe('ordered set', () => {
expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([12, 13, 16]))).toBe(false);
});
it('isSubsetIS', () => {
expect(OrderedSet.isSubset(
Interval.ofRange(1271, 1295),
OrderedSet.ofSortedArray([1271, 1272, 1274, 1275, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294])
)).toBe(true);
});
it('access/membership', () => {
expect(OrderedSet.has(empty, 10)).toBe(false);
expect(OrderedSet.indexOf(empty, 10)).toBe(-1);
@@ -156,6 +164,15 @@ describe('ordered set', () => {
testEq('intersect AA', OrderedSet.intersect(arr136, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [3, 6]);
it('intersect AA1', () => expect(OrderedSet.union(arr136, OrderedSet.ofSortedArray([1, 3, 6]))).toBe(arr136));
testEq('idxIntersect 1', OrderedSet.indexedIntersect(
OrderedSet.ofSortedArray([1, 2, 4]),
SortedArray.ofSortedArray([1, 2, 3, 4, 5, 6]),
SortedArray.ofSortedArray([2, 4, 5, 8])), [0, 2]);
testEq('idxIntersect 2', OrderedSet.indexedIntersect(
OrderedSet.ofSortedArray([0, 1]),
SortedArray.ofSortedArray([1, 2]),
SortedArray.ofSortedArray([1, 2])), [0, 1]);
testEq('subtract ES', OrderedSet.subtract(empty, singleton10), []);
testEq('subtract ER', OrderedSet.subtract(empty, range1_4), []);
testEq('subtract EA', OrderedSet.subtract(empty, arr136), []);

View File

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

View File

@@ -17,7 +17,7 @@ describe('rangesArray', () => {
it(`iterator, ${name}`, () => {
const rangesIt = SortedRanges.transientSegments(ranges, set)
const { index, start, end } = expectedValues
let i = 0
while (rangesIt.hasNext) {
const segment = rangesIt.move()
@@ -41,7 +41,7 @@ describe('rangesArray', () => {
testIterator('two ranges',
SortedRanges.ofSortedRanges([1, 2, 3, 4]),
OrderedSet.ofBounds(1, 4),
OrderedSet.ofBounds(1, 5),
{ index: [0, 1], start: [0, 2], end: [2, 4] }
)
testIterator('first range',
@@ -62,7 +62,7 @@ describe('rangesArray', () => {
testIterator('set in second range and beyond',
SortedRanges.ofSortedRanges([1, 2, 3, 4]),
SortedArray.ofSortedArray([3, 10]),
{ index: [1], start: [0], end: [2] }
{ index: [1], start: [0], end: [1] }
)
testIterator('length 1 range',
SortedRanges.ofSortedRanges([1, 1, 3, 4]),

View File

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

View File

@@ -126,7 +126,7 @@ function isSubsetIS(a: I, b: S) {
const minA = I.min(a), maxA = I.max(a);
if (maxA - minA + 1 === 0) return false;
const minB = S.min(b), maxB = S.max(b);
return minB >= minA && maxA <= maxB;
return minB >= minA && maxB <= maxA;
}
function areRangesIntersecting(a: OrderedSetImpl, b: OrderedSetImpl) {
@@ -286,4 +286,69 @@ export function forEach(set: OrderedSetImpl, f: (value: number, i: number, ctx:
}
}
return ctx;
}
export function forEachSegment(set: OrderedSetImpl, segment: (v: number) => number, f: (value: number, segIndex: number, ctx: any) => void, ctx: any) {
if (I.is(set)) {
let sI = 0;
for (let i = I.min(set), _i = I.max(set); i <= _i; i++) {
const s = segment(i);
let endI = i + 1;
while (endI < _i && segment(endI) === s) endI++;
i = endI - 1;
f(s, sI, ctx);
sI++;
}
} else {
let sI = 0;
for (let i = 0, _i = set.length; i < _i; i++) {
const s = segment(set[i]);
let endI = i + 1;
while (endI < _i && segment(set[endI]) === s) endI++;
i = endI - 1;
f(s, sI, ctx);
sI++;
}
}
return ctx;
}
export function indexedIntersect(idxA: OrderedSetImpl, a: S, b: S): OrderedSetImpl {
if (a === b) return idxA;
const lenI = size(idxA), lenA = a.length, lenB = b.length;
if (lenI === 0 || lenA === 0 || lenB === 0) return Empty;
const startJ = S.findPredecessorIndex(b, a[min(idxA)]);
const endJ = S.findPredecessorIndex(b, a[max(idxA)] + 1);
let commonCount = 0;
let offset = 0;
let O = 0;
let j = startJ;
while (O < lenI && j < endJ) {
const x = a[getAt(idxA, O)], y = b[j];
if (x < y) { O++; }
else if (x > y) { j++; }
else { commonCount++; O++; j++; }
}
// no common elements
if (commonCount === 0) return Empty;
// A === B
if (commonCount === lenA && commonCount === lenB) return idxA;
const indices = new Int32Array(commonCount);
offset = 0;
O = 0;
j = startJ;
while (O < lenI && j < endJ) {
const x = a[getAt(idxA, O)], y = b[j];
if (x < y) { O++; }
else if (x > y) { j++; }
else { indices[offset++] = j; O++; j++; }
}
return ofSortedArray(indices);
}

View File

@@ -47,8 +47,10 @@ export function indexOf(xs: Nums, v: number) {
return l === 0 ? -1 : xs[0] <= v && v <= xs[l - 1] ? binarySearchRange(xs, v, 0, l) : -1;
}
export function indexOfInInterval(xs: Nums, v: number, bounds: Interval) {
return indexOfInRange(xs, v, Interval.start(bounds), Interval.end(bounds))
}
export function indexOfInRange(xs: Nums, v: number, s: number, e: number) {
const l = xs.length;
const s = Interval.start(bounds), e = Interval.end(bounds);
return l === 0 || e <= s ? -1 : xs[s] <= v && v <= xs[e - 1] ? binarySearchRange(xs, v, s, e) : -1;
}
export function has(xs: Nums, v: number) { return indexOf(xs, v) >= 0; }
@@ -65,6 +67,11 @@ export function areEqual(a: Nums, b: Nums) {
return true;
}
/**
* Returns 0 if `v` is smaller or equal the first element of `xs`
* Returns length of `xs` if `v` is bigger than the last element of `xs`
* Otherwise returns the first index where the value of `xs` is equal or bigger than `v`
*/
export function findPredecessorIndex(xs: Nums, v: number) {
const len = xs.length;
if (v <= xs[0]) return 0;
@@ -164,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++; }
@@ -193,6 +202,10 @@ export function union(a: Nums, b: Nums) {
else { indices[offset++] = x; i++; j++; }
}
// insert the remaining common part
for (; i < endI; i++) indices[offset++] = a[i];
for (; j < endJ; j++) indices[offset++] = b[j];
// insert the "tail"
for (; i < lenA; i++) indices[offset++] = a[i];
for (; j < lenB; j++) indices[offset++] = b[j];

View File

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

View File

@@ -21,12 +21,14 @@ namespace OrderedSet {
export const has: <T extends number = number>(set: OrderedSet<T>, x: T) => boolean = Base.has as any;
/** Returns the index of `x` in `set` or -1 if not found. */
export const indexOf: <T extends number = number>(set: OrderedSet<T>, x: T) => number = Base.indexOf as any;
/** Returns the value in `set` at index `i`. */
export const getAt: <T extends number = number>(set: OrderedSet<T>, i: number) => T = Base.getAt as any;
export const min: <T extends number = number>(set: OrderedSet<T>) => T = Base.min as any;
export const max: <T extends number = number>(set: OrderedSet<T>) => T = Base.max as any;
export const start: <T extends number = number>(set: OrderedSet<T>) => T = Base.start as any;
export const end: <T extends number = number>(set: OrderedSet<T>) => T = Base.end as any;
/** Number of elements in the OrderedSet */
export const size: <T extends number = number>(set: OrderedSet<T>) => number = Base.size as any;
export const hashCode: <T extends number = number>(set: OrderedSet<T>) => number = Base.hashCode as any;
@@ -37,8 +39,15 @@ 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;
/**
* Returns 0 if `x` is smaller or equal the first element of `set`
* Returns length of `set` if `x` is bigger than the last element of `set`
* Otherwise returns the first index where the value of `set` is equal or bigger than `x`
*/
export const findPredecessorIndex: <T extends number = number>(set: OrderedSet<T>, x: number) => number = Base.findPredecessorIndex as any;
export const findPredecessorIndexInInterval: <T extends number = number>(set: OrderedSet<T>, x: T, range: Interval) => number = Base.findPredecessorIndexInInterval as any;
export const findRange: <T extends number = number>(set: OrderedSet<T>, min: T, max: T) => Interval = Base.findRange as any;
@@ -48,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

@@ -18,7 +18,7 @@ namespace Segmentation {
export const getSegment: <T extends number = number, I extends number = number>(segs: Segmentation<T, I>, value: T) => number = Impl.getSegment as any;
export const projectValue: <T extends number = number, I extends number = number>(segs: Segmentation<T, I>, set: OrderedSet<T>, value: T) => Interval = Impl.projectValue as any;
// Segment iterator that mutates a single segment object to mark all the segments.
/** Segment iterator that mutates a single segment object to mark all the segments. */
export const transientSegments: <T extends number = number, I extends number = number>(segs: Segmentation<T, I>, set: OrderedSet<T>, segment?: Segment) => Impl.SegmentIterator<I> = Impl.segments as any;
export type SegmentIterator<I extends number = number> = Impl.SegmentIterator<I>

View File

@@ -12,9 +12,9 @@ namespace SortedArray {
export const ofUnsortedArray: <T extends number = number>(xs: ArrayLike<number>) => SortedArray<T> = Impl.ofUnsortedArray as any;
export const ofSingleton: <T extends number = number>(v: number) => SortedArray<T> = Impl.ofSingleton as any;
export const ofSortedArray: <T extends number = number>(xs: ArrayLike<number>) => SortedArray<T> = Impl.ofSortedArray as any;
// create sorted array [min, max] (it DOES contain the max value)
/** create sorted array [min, max] (it DOES contain the max value) */
export const ofRange: <T extends number = number>(min: T, max: T) => SortedArray<T> = Impl.ofRange as any;
// create sorted array [min, max) (it does NOT contain the max value)
/** create sorted array [min, max) (it does NOT contain the max value) */
export const ofBounds: <T extends number = number>(min: T, max: T) => SortedArray<T> = (min, max) => Impl.ofRange(min, max - 1) as any;
export const is: <T extends number = number>(v: any) => v is SortedArray<T> = Impl.is as any;
@@ -22,10 +22,11 @@ namespace SortedArray {
/** Returns the index of `x` in `set` or -1 if not found. */
export const indexOf: <T extends number = number>(array: SortedArray<T>, x: T) => number = Impl.indexOf as any;
export const indexOfInInterval: <T extends number = number>(array: SortedArray<T>, x: number, bounds: Interval) => number = Impl.indexOfInInterval as any;
export const indexOfInRange: <T extends number = number>(array: SortedArray<T>, x: number, start: number, end: number) => number = Impl.indexOfInRange as any;
// array[0]
/** Returns `array[0]` */
export const start: <T extends number = number>(array: SortedArray<T>) => T = Impl.start as any;
// array[array.length - 1] + 1
/** Returns `array[array.length - 1] + 1` */
export const end: <T extends number = number>(array: SortedArray<T>) => T = Impl.end as any;
export const min: <T extends number = number>(array: SortedArray<T>) => T = Impl.min as any;
export const max: <T extends number = number>(array: SortedArray<T>) => T = Impl.max as any;

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>
*/
@@ -23,6 +23,64 @@ namespace SortedRanges {
}
return size
}
export function count<T extends number = number>(ranges: SortedRanges<T>) { return ranges.length / 2 }
export function startAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
return ranges[index * 2]
}
export function endAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
return ranges[index * 2 + 1] + 1
}
export function minAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
return ranges[index * 2]
}
export function maxAt<T extends number = number>(ranges: SortedRanges<T>, index: number) {
return ranges[index * 2 + 1]
}
export function areEqual<T extends number = number>(a: SortedRanges<T>, b: SortedRanges<T>) {
if (a.length !== b.length) return false
for (let i = 0, il = a.length; i < il; ++i) {
if (a[i] !== b[i]) return false
}
return true
}
export function forEach<T extends number = number>(ranges: SortedRanges<T>, f: (value: T, i: number) => void) {
let k = 0
for (let i = 0, il = ranges.length; i < il; i += 2) {
for (let j = ranges[i], jl = ranges[i + 1]; j <= jl; ++j) {
f(j, k);
++k
}
}
}
/** Returns if a value of `set` is included in `ranges` */
export function has<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>) {
return firstIntersectionIndex(ranges, set) !== -1
}
/** Returns if a value of `set` is included in `ranges` from given index */
export function hasFrom<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>, from: number) {
return firstIntersectionIndexFrom(ranges, set, from) !== -1
}
export function firstIntersectionIndex<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>): number {
return firstIntersectionIndexFrom(ranges, set, 0)
}
export function firstIntersectionIndexFrom<T extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>, from: number): number {
if (minAt(ranges, from) > OrderedSet.max(set) || max(ranges) < OrderedSet.min(set)) return -1
for (let i = from, il = count(ranges); i < il; ++i) {
const interval = Interval.ofRange(minAt(ranges, i), maxAt(ranges, i))
if (OrderedSet.areIntersecting(interval, set)) return i
}
return -1
}
export function transientSegments<T extends number = number, I extends number = number>(ranges: SortedRanges<T>, set: OrderedSet<T>) {
return new Iterator<T, I>(ranges, set)
@@ -32,53 +90,27 @@ namespace SortedRanges {
private value: Segmentation.Segment<I> = { index: 0 as I, start: 0 as T, end: 0 as T }
private curIndex = 0
private maxIndex = 0
private interval: Interval<T>
private curMin: T = 0 as T
hasNext: boolean = false;
updateInterval() {
this.interval = Interval.ofRange(this.ranges[this.curIndex], this.ranges[this.curIndex + 1])
}
updateValue() {
this.value.index = this.curIndex / 2 as I
this.value.start = OrderedSet.findPredecessorIndex(this.set, this.ranges[this.curIndex])
this.value.end = OrderedSet.findPredecessorIndex(this.set, this.ranges[this.curIndex + 1]) + 1
private updateValue() {
this.value.index = this.curIndex as I
this.value.start = OrderedSet.findPredecessorIndex(this.set, startAt(this.ranges, this.curIndex))
this.value.end = OrderedSet.findPredecessorIndex(this.set, endAt(this.ranges, this.curIndex))
}
move() {
if (this.hasNext) {
this.updateValue()
while (this.curIndex <= this.maxIndex) {
this.curIndex += 2
this.curMin = Interval.end(this.interval)
this.updateInterval()
if (Interval.min(this.interval) >= this.curMin && OrderedSet.areIntersecting(this.interval, this.set)) break
}
this.hasNext = this.curIndex <= this.maxIndex
this.curIndex = firstIntersectionIndexFrom(this.ranges, this.set, this.curIndex + 1)
this.hasNext = this.curIndex !== -1
}
return this.value;
}
getRangeIndex(value: number) {
const index = SortedArray.findPredecessorIndex(this.ranges, value)
return (index % 2 === 1) ? index - 1 : index
}
constructor(private ranges: SortedRanges<T>, private set: OrderedSet<T>) {
// TODO cleanup, refactor to make it clearer
const min = SortedArray.findPredecessorIndex(this.ranges, OrderedSet.min(set))
const max = SortedArray.findPredecessorIndex(this.ranges, OrderedSet.max(set) + 1)
if (ranges.length && min !== max) {
this.curIndex = this.getRangeIndex(OrderedSet.min(set))
this.maxIndex = Math.min(ranges.length - 2, this.getRangeIndex(OrderedSet.max(set)))
this.curMin = this.ranges[this.curIndex]
this.updateInterval()
}
this.hasNext = ranges.length > 0 && min !== max && this.curIndex <= this.maxIndex
this.curIndex = firstIntersectionIndex(ranges, set)
this.hasNext = this.curIndex !== -1
}
}
}

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

@@ -73,7 +73,7 @@ export function sortedCantorPairing(a: number, b: number) {
/**
* 32 bit FNV-1a hash, see http://isthe.com/chongo/tech/comp/fnv/
*/
export function hashFnv32a(array: number[]) {
export function hashFnv32a(array: ArrayLike<number>) {
let hval = 0x811c9dc5;
for (let i = 0, il = array.length; i < il; ++i) {
hval ^= array[i];

View File

@@ -9,11 +9,9 @@ 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/tables';
import { ColorNames } from '../../mol-util/color/names';
import { NullLocation } from '../../mol-model/location';
import { UniformColorTheme } from '../../mol-theme/color/uniform';
import { UniformSizeTheme } from '../../mol-theme/size/uniform';
@@ -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,20 +18,22 @@ 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/scale';
import { ColorListOptions, ColorListName } from '../../../mol-util/color/lists';
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 {
@@ -81,7 +117,7 @@ export namespace DirectVolume {
Vec2.create(0.19, 0.0), Vec2.create(0.2, 0.05), Vec2.create(0.25, 0.05), Vec2.create(0.26, 0.0),
Vec2.create(0.79, 0.0), Vec2.create(0.8, 0.05), Vec2.create(0.85, 0.05), Vec2.create(0.86, 0.0),
]),
list: PD.ColorScale<ColorListName>('RedYellowBlue', ColorListOptions),
list: PD.ColorList<ColorListName>('red-yellow-blue', ColorListOptions),
}
export type Params = typeof Params
@@ -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

@@ -9,7 +9,7 @@ import { spline } from '../../../mol-math/interpolate';
import { ColorScale, Color } from '../../../mol-util/color';
import { ValueCell } from '../../../mol-util';
import { Vec2 } from '../../../mol-math/linear-algebra';
import { ColorListName } from '../../../mol-util/color/scale';
import { ColorListName } from '../../../mol-util/color/lists';
export interface ControlPoint { x: number, alpha: number }

View File

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

View File

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

View File

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

View File

@@ -13,57 +13,6 @@ export type MarkerData = {
uMarkerTexDim: ValueCell<Vec2>
}
export enum MarkerAction {
Highlight,
RemoveHighlight,
Select,
Deselect,
Toggle,
Clear
}
export function applyMarkerAction(array: Uint8Array, start: number, end: number, action: MarkerAction) {
let changed = false
for (let i = start; i < end; ++i) {
let v = array[i]
switch (action) {
case MarkerAction.Highlight:
if (v % 2 === 0) {
v += 1
}
break
case MarkerAction.RemoveHighlight:
if (v % 2 !== 0) {
v -= 1
}
break
case MarkerAction.Select:
if (v < 2) v += 2
// v += 2
break
case MarkerAction.Deselect:
// if (v >= 2) {
// v -= 2
// }
v = v % 2
break
case MarkerAction.Toggle:
if (v >= 2) {
v -= 2
} else {
v += 2
}
break
case MarkerAction.Clear:
v = 0
break
}
changed = array[i] !== v || changed
array[i] = v
}
return changed
}
export function createMarkers(count: number, markerData?: MarkerData): MarkerData {
const markers = createTextureImage(Math.max(1, count), 1, Uint8Array, markerData && markerData.tMarker.ref.value.array)
if (markerData) {

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

@@ -1,13 +1,15 @@
/**
* 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, Mat4 } from '../../../../mol-math/linear-algebra';
import { MeshBuilder } from '../mesh-builder';
import { Primitive } from '../../../primitive/primitive';
import { Primitive, transformPrimitive } from '../../../primitive/primitive';
import { Cylinder, CylinderProps } from '../../../primitive/cylinder';
import { Prism } from '../../../primitive/prism';
import { polygon } from '../../../primitive/polygon';
const cylinderMap = new Map<string, Primitive>()
const up = Vec3.create(0, 1, 0)
@@ -24,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)
}
@@ -34,7 +35,12 @@ function getCylinder(props: CylinderProps) {
const key = JSON.stringify(props)
let cylinder = cylinderMap.get(key)
if (cylinder === undefined) {
cylinder = Cylinder(props)
if (props.radialSegments && props.radialSegments <= 4) {
const box = Prism(polygon(4, true, props.radiusTop), props)
cylinder = transformPrimitive(box, Mat4.rotX90)
} else {
cylinder = Cylinder(props)
}
cylinderMap.set(key, cylinder)
}
return cylinder

View File

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

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2018-2019 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 { Vec3 } from '../../../../mol-math/linear-algebra';
import { ChunkedArray } from '../../../../mol-data/util';
import { MeshBuilder } from '../mesh-builder';
const tA = Vec3.zero()
const tB = Vec3.zero()
const tV = Vec3.zero()
const horizontalVector = Vec3.zero()
const verticalVector = Vec3.zero()
const normalOffset = Vec3.zero()
const positionVector = Vec3.zero()
const normalVector = Vec3.zero()
const torsionVector = Vec3.zero()
/** set arrowHeight = 0 for no arrow */
export function addRibbon(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, widthValues: ArrayLike<number>, heightValues: ArrayLike<number>, arrowHeight: number) {
const { currentGroup, vertices, normals, indices, groups } = state
let vertexCount = vertices.elementCount
let offsetLength = 0
if (arrowHeight > 0) {
Vec3.fromArray(tA, controlPoints, 0)
Vec3.fromArray(tB, controlPoints, linearSegments * 3)
offsetLength = arrowHeight / Vec3.magnitude(Vec3.sub(tV, tB, tA))
}
for (let i = 0; i <= linearSegments; ++i) {
const width = widthValues[i]
const height = heightValues[i]
const actualHeight = arrowHeight === 0 ? height : arrowHeight * (1 - i / linearSegments);
const i3 = i * 3
Vec3.fromArray(verticalVector, normalVectors, i3)
Vec3.scale(verticalVector, verticalVector, actualHeight);
Vec3.fromArray(horizontalVector, binormalVectors, i3)
Vec3.scale(horizontalVector, horizontalVector, width);
if (arrowHeight > 0) {
Vec3.fromArray(tA, normalVectors, i3)
Vec3.fromArray(tB, binormalVectors, i3)
Vec3.scale(normalOffset, Vec3.cross(normalOffset, tA, tB), offsetLength)
}
Vec3.fromArray(positionVector, controlPoints, i3)
Vec3.fromArray(normalVector, normalVectors, i3)
Vec3.fromArray(torsionVector, binormalVectors, i3)
Vec3.add(tA, positionVector, verticalVector)
Vec3.negate(tB, torsionVector)
ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
Vec3.sub(tA, positionVector, verticalVector)
ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
Vec3.add(tA, positionVector, verticalVector)
Vec3.copy(tB, torsionVector)
ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
Vec3.sub(tA, positionVector, verticalVector)
ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
}
for (let i = 0; i < linearSegments; ++i) {
ChunkedArray.add3(
indices,
vertexCount + i * 4,
vertexCount + (i + 1) * 4 + 1,
vertexCount + i * 4 + 1
);
ChunkedArray.add3(
indices,
vertexCount + i * 4,
vertexCount + (i + 1) * 4,
vertexCount + (i + 1) * 4 + 1
);
ChunkedArray.add3(
indices,
vertexCount + i * 4 + 2 + 1,
vertexCount + (i + 1) * 4 + 2 + 1,
vertexCount + i * 4 + 2
);
ChunkedArray.add3(
indices,
vertexCount + i * 4 + 2,
vertexCount + (i + 1) * 4 + 2 + 1,
vertexCount + (i + 1) * 4 + 2
);
}
const addedVertexCount = (linearSegments + 1) * 4
for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup)
}

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>
* @author David Sehnal <david.sehnal@gmail.com>
@@ -71,7 +71,7 @@ function addCap(offset: number, state: MeshBuilder.State, controlPoints: ArrayLi
}
/** set arrowHeight = 0 for no arrow */
export function addSheet(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean) {
export function addSheet(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, widthValues: ArrayLike<number>, heightValues: ArrayLike<number>, arrowHeight: number, startCap: boolean, endCap: boolean) {
const { currentGroup, vertices, normals, indices, groups } = state
let vertexCount = vertices.elementCount
@@ -84,6 +84,9 @@ export function addSheet(state: MeshBuilder.State, controlPoints: ArrayLike<numb
}
for (let i = 0; i <= linearSegments; ++i) {
const width = widthValues[i]
const height = heightValues[i]
const actualHeight = arrowHeight === 0 ? height : arrowHeight * (1 - i / linearSegments);
const i3 = i * 3
@@ -141,32 +144,55 @@ export function addSheet(state: MeshBuilder.State, controlPoints: ArrayLike<numb
}
for (let i = 0; i < linearSegments; ++i) {
for (let j = 0; j < 4; j++) {
// the triangles are arranged such that opposing triangles of the sheet align
// which prevents triangle intersection within tight curves
for (let j = 0; j < 2; j++) {
ChunkedArray.add3(
indices,
vertexCount + i * 8 + 2 * j,
vertexCount + (i + 1) * 8 + 2 * j + 1,
vertexCount + i * 8 + 2 * j + 1
vertexCount + i * 8 + 2 * j, // a
vertexCount + (i + 1) * 8 + 2 * j + 1, // c
vertexCount + i * 8 + 2 * j + 1 // b
);
ChunkedArray.add3(
indices,
vertexCount + i * 8 + 2 * j,
vertexCount + (i + 1) * 8 + 2 * j,
vertexCount + (i + 1) * 8 + 2 * j + 1
vertexCount + i * 8 + 2 * j, // a
vertexCount + (i + 1) * 8 + 2 * j, // d
vertexCount + (i + 1) * 8 + 2 * j + 1 // c
);
}
for (let j = 2; j < 4; j++) {
ChunkedArray.add3(
indices,
vertexCount + i * 8 + 2 * j, // a
vertexCount + (i + 1) * 8 + 2 * j, // d
vertexCount + i * 8 + 2 * j + 1, // b
);
ChunkedArray.add3(
indices,
vertexCount + (i + 1) * 8 + 2 * j, // d
vertexCount + (i + 1) * 8 + 2 * j + 1, // c
vertexCount + i * 8 + 2 * j + 1, // b
);
}
}
if (startCap) {
const width = widthValues[0]
const height = heightValues[0]
const h = arrowHeight === 0 ? height : arrowHeight
addCap(0, state, controlPoints, normalVectors, binormalVectors, width, h, h)
} else if (arrowHeight > 0) {
const width = widthValues[0]
const height = heightValues[0]
addCap(0, state, controlPoints, normalVectors, binormalVectors, width, arrowHeight, -height)
addCap(0, state, controlPoints, normalVectors, binormalVectors, width, -arrowHeight, height)
}
if (endCap && arrowHeight === 0) {
addCap(linearSegments * 3, state, controlPoints, normalVectors, binormalVectors, width, height, height)
const width = widthValues[linearSegments]
const height = heightValues[linearSegments]
// use negative height to flip the direction the cap's triangles are facing
addCap(linearSegments * 3, state, controlPoints, normalVectors, binormalVectors, width, -height, -height)
}
const addedVertexCount = (linearSegments + 1) * 8 +

View File

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

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