mirror of
https://github.com/molstar/molstar.git
synced 2026-06-07 07:04:22 +08:00
Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e843c20cc | ||
|
|
ecaf19c5fb | ||
|
|
f024aeef2c | ||
|
|
9d9985f117 | ||
|
|
a0f7349ef6 | ||
|
|
01407427d2 | ||
|
|
3dee03d9b6 | ||
|
|
737f6593be | ||
|
|
068e10dd40 | ||
|
|
c1ba5248b0 | ||
|
|
4af0f22ac0 | ||
|
|
25a67e1176 | ||
|
|
a8fcd501d6 | ||
|
|
573ee92889 | ||
|
|
2558d6fada | ||
|
|
2cf3f8d62b | ||
|
|
589d89b0d5 | ||
|
|
7cc7b77460 | ||
|
|
e8a9995bef | ||
|
|
74ff283e00 | ||
|
|
1ecb960b82 | ||
|
|
387d59f97b | ||
|
|
d993082f24 | ||
|
|
5eaa73d56d | ||
|
|
b9428fd3cd | ||
|
|
97d180b79d | ||
|
|
25bd915ea5 | ||
|
|
f8fdffdc44 | ||
|
|
d11aa6ea77 | ||
|
|
fc3c7997ea | ||
|
|
b3aecf8de4 | ||
|
|
f3581e62ef | ||
|
|
88e7fe508f | ||
|
|
98049ed02d | ||
|
|
194092ed67 | ||
|
|
e96157c890 | ||
|
|
a028c1ef42 | ||
|
|
ad2b5e687d | ||
|
|
8ba19f0be4 | ||
|
|
bccc68f6df | ||
|
|
026a05d03d | ||
|
|
2b4741c8ee | ||
|
|
7960ee06d4 | ||
|
|
f73f5af131 | ||
|
|
3123110aa4 | ||
|
|
154063638d | ||
|
|
a720b98365 | ||
|
|
d4a2937e0b | ||
|
|
b0ca7ffbb7 | ||
|
|
c42b738abe | ||
|
|
ab0d0fec53 | ||
|
|
8d96131962 | ||
|
|
95bbcd8b24 | ||
|
|
a21f5c2c23 | ||
|
|
94b7b1281c | ||
|
|
16dba586df | ||
|
|
72b761f959 | ||
|
|
943d81cbf9 | ||
|
|
2ecdc0eafa | ||
|
|
dccfd35c7a | ||
|
|
9e81a4f7a6 | ||
|
|
6f6cc73ce9 | ||
|
|
c248ae11bf | ||
|
|
742be03901 | ||
|
|
00009ef198 | ||
|
|
1cb617524d | ||
|
|
e2e348240b | ||
|
|
b54908492c | ||
|
|
33172862bd | ||
|
|
c5f2767efc | ||
|
|
66f5a81a5d | ||
|
|
9e90e11bfc | ||
|
|
ab372a89d6 | ||
|
|
ea612c3acb | ||
|
|
a1308645e5 | ||
|
|
c6506d515f | ||
|
|
794b705184 | ||
|
|
66264abe50 | ||
|
|
7d0f84ff72 | ||
|
|
31495ab02a | ||
|
|
853ad5c916 | ||
|
|
51fc525215 | ||
|
|
6f9fed180d | ||
|
|
5ecd176f20 |
50
CHANGELOG.md
50
CHANGELOG.md
@@ -5,7 +5,53 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v5.1.0] - 2025-10-25
|
||||
## [v5.4.2] - 2025-12-07
|
||||
- Fix postprocessing issues with SSAO and outlines for large structures (#1387)
|
||||
- Reduce automatic quality on standalone HMD devices
|
||||
|
||||
## [v5.4.1] - 2025-11-16
|
||||
- Fix ugly camera clipping in snapshot transitions
|
||||
- Add viewport button to toggle illumination mode
|
||||
- Fix bounding sphere computation for 3D text
|
||||
- Structure bounding sphere includes atom VDW radii / coarse sphere radii
|
||||
- Relax camera limits to allow focusing any selection with >1 atom
|
||||
- MolViewSpec
|
||||
- Fix `appendSnapshots` when loading MVSX
|
||||
- Fix all-selector color not applying on substructure
|
||||
- Fix primitives in root not being transformed with reference structure
|
||||
- Color themes do not prefer smoothing (improves performance in animations)
|
||||
- Allow canvas background interpolation
|
||||
- Fix `direct-volume` not drawn in illumination mode
|
||||
- Fix default trackball animated spin speed
|
||||
- Use `PluginCommands` to set canvas3d props in camera behavior
|
||||
- Volume improvements
|
||||
- Add `Volume.periodicity`
|
||||
- Wrap isosurfaces for periodic volumes
|
||||
- Fix dimensions for slices
|
||||
- Add support for Input Method Editor (IME) to text params input
|
||||
- Update `guessCifVariant` to detect density files not generated by the VolumeServer
|
||||
|
||||
## [v5.3.0] - 2025-11-05
|
||||
- Update loading message in MVS Stories Viewer
|
||||
- Add `Canvas3D.setAttribs`
|
||||
- Fix `normalizeWheel` "spin" calculation fallback
|
||||
- MolViewSpec
|
||||
- Add support for "topology" formats (TOP, PRMTOP, PSF)
|
||||
- Add support for additional "coordiates" formats (NCTRAJ, DCD, TRR)
|
||||
- Fix coarse structure selection
|
||||
- Fix missing default param values in `primitives_from_uri`
|
||||
|
||||
## [v5.2.0] - 2025-10-31
|
||||
- Handle transparency updates on ImagePass
|
||||
- Fix CIF parser edge case when the last token is escaped
|
||||
- MolViewSpec
|
||||
- Fix tooltips persisting across snapshots
|
||||
- Fix CIF annotations with no selector columns being ignored
|
||||
- Fix trackpad lock when camera up parallel to direction
|
||||
- Add clipping support for primitives
|
||||
- Support near camera distance
|
||||
|
||||
## [v5.1.2] - 2025-10-25
|
||||
- Fix createColorScaleByType when offsets are available
|
||||
- Get bond orders from non-standard CONECT records in PDB files
|
||||
- Remove outdated `gl_FrontFacing` workaround for buggy drivers
|
||||
@@ -13,7 +59,7 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
- Support "magic window" style AR (via WebXR)
|
||||
- Fix `PluginState.getStateTransitionFrameIndex`
|
||||
- Update `GlycamSaccharideNames` and `Monosaccharides` in `carbohydrates/constants.ts`
|
||||
- Support custom ref resolvers in `State`
|
||||
- Support custom ref resolvers in `State`
|
||||
- Add full-screen mode support to layout manager
|
||||
- Add `show-toggle-fullscreen` URL param option to Viewer app
|
||||
- MolViewSpec
|
||||
|
||||
BIN
examples/trajectory/protein.dcd
Normal file
BIN
examples/trajectory/protein.dcd
Normal file
Binary file not shown.
BIN
examples/trajectory/protein.nc
Normal file
BIN
examples/trajectory/protein.nc
Normal file
Binary file not shown.
264
examples/trajectory/protein.parm7
Normal file
264
examples/trajectory/protein.parm7
Normal file
@@ -0,0 +1,264 @@
|
||||
%VERSION VERSION_STAMP = V0001.000 DATE = 11/04/25 11:55:47
|
||||
%FLAG TITLE
|
||||
%FORMAT(20a4)
|
||||
alanine-dipeptide.solvated.pdb
|
||||
%FLAG POINTERS
|
||||
%FORMAT(10I8)
|
||||
22 7 12 9 25 11 39 19 0 0
|
||||
99 3 9 11 19 7 11 20 0 0
|
||||
0 0 0 0 0 0 0 1 10 0
|
||||
0 1
|
||||
%FLAG ATOM_NAME
|
||||
%FORMAT(20a4)
|
||||
H1 CH3 H2 H3 C O N H CA HA CB HB1 HB2 HB3 C O N H C H1
|
||||
H2 H3
|
||||
%FLAG ATOMIC_NUMBER
|
||||
%FORMAT(10I8)
|
||||
1 6 1 1 6 8 7 1 6 1
|
||||
6 1 1 1 6 8 7 1 6 1
|
||||
1 1
|
||||
%FLAG RESIDUE_LABEL
|
||||
%FORMAT(20a4)
|
||||
ACE ALA NME
|
||||
%FLAG RESIDUE_POINTER
|
||||
%FORMAT(10I8)
|
||||
1 7 17
|
||||
%FLAG RESIDUE_NUMBER
|
||||
%FORMAT(20I4)
|
||||
1 2 3
|
||||
%FLAG RESIDUE_ICODE
|
||||
%FORMAT(20a4)
|
||||
|
||||
%FLAG RESIDUE_CHAINID
|
||||
%FORMAT(20a4)
|
||||
B B B
|
||||
%FLAG SOLVENT_POINTERS
|
||||
%FORMAT(3I8)
|
||||
0 1 0
|
||||
%FLAG ATOMS_PER_MOLECULE
|
||||
%FORMAT(10I8)
|
||||
22
|
||||
%FLAG MASS
|
||||
%FORMAT(5E16.8)
|
||||
3.02400000E+00 5.96200000E+00 3.02400000E+00 3.02400000E+00 1.20100000E+01
|
||||
1.60000000E+01 1.19940000E+01 3.02400000E+00 9.99400000E+00 3.02400000E+00
|
||||
5.96200000E+00 3.02400000E+00 3.02400000E+00 3.02400000E+00 1.20100000E+01
|
||||
1.60000000E+01 1.19940000E+01 3.02400000E+00 5.96200000E+00 3.02400000E+00
|
||||
3.02400000E+00 3.02400000E+00
|
||||
%FLAG CHARGE
|
||||
%FORMAT(5E16.8)
|
||||
2.04636429E+00 -6.67300626E+00 2.04636429E+00 2.04636429E+00 1.08823576E+01
|
||||
-1.03484442E+01 -7.57501011E+00 4.95464337E+00 6.14091510E-01 1.49969529E+00
|
||||
-3.32556975E+00 1.09880469E+00 1.09880469E+00 1.09880469E+00 1.08841798E+01
|
||||
-1.03484442E+01 -7.57501011E+00 4.95464337E+00 -2.71512270E+00 1.77849648E+00
|
||||
1.77849648E+00 1.77849648E+00
|
||||
%FLAG AMBER_ATOM_TYPE
|
||||
%FORMAT(20a4)
|
||||
a0 a1 a0 a0 a2 a3 a4 a5 a1 a6 a1 a0 a0 a0 a2 a3 a4 a5 a1 a6
|
||||
a6 a6
|
||||
%FLAG ATOM_TYPE_INDEX
|
||||
%FORMAT(10I8)
|
||||
1 2 1 1 3 4 5 6 2 7
|
||||
2 1 1 1 3 4 5 6 2 7
|
||||
7 7
|
||||
%FLAG NONBONDED_PARM_INDEX
|
||||
%FORMAT(10I8)
|
||||
1 2 4 7 11 16 22 2 3 5
|
||||
8 12 17 23 4 5 6 9 13 18
|
||||
24 7 8 9 10 14 19 25 11 12
|
||||
13 14 15 20 26 16 17 18 19 20
|
||||
21 27 22 23 24 25 26 27 28
|
||||
%FLAG LENNARD_JONES_ACOEF
|
||||
%FORMAT(5E16.8)
|
||||
7.51607703E+03 9.71708117E+04 1.04308023E+06 8.61541883E+04 9.24822269E+05
|
||||
8.19971662E+05 5.44261042E+04 6.47841732E+05 5.74393458E+05 3.79876399E+05
|
||||
8.96776989E+04 9.95480466E+05 8.82619071E+05 6.06829343E+05 9.44293233E+05
|
||||
1.07193645E+02 2.56678134E+03 2.27577560E+03 1.02595236E+03 2.12601181E+03
|
||||
1.39982777E-01 4.98586847E+03 6.78771368E+04 6.01816484E+04 3.69471530E+04
|
||||
6.20665998E+04 5.94667299E+01 3.25969625E+03
|
||||
%FLAG LENNARD_JONES_BCOEF
|
||||
%FORMAT(5E16.8)
|
||||
2.17257828E+01 1.26919150E+02 6.75612247E+02 1.12529845E+02 5.99015525E+02
|
||||
5.31102864E+02 1.11805549E+02 6.26720080E+02 5.55666449E+02 5.64885984E+02
|
||||
1.36131731E+02 7.36907417E+02 6.53361429E+02 6.77220874E+02 8.01323529E+02
|
||||
2.59456373E+00 2.06278363E+01 1.82891803E+01 1.53505284E+01 2.09604198E+01
|
||||
9.37598976E-02 1.76949863E+01 1.06076943E+02 9.40505981E+01 9.21192137E+01
|
||||
1.13252062E+02 1.93248820E+00 1.43076527E+01
|
||||
%FLAG NUMBER_EXCLUDED_ATOMS
|
||||
%FORMAT(10I8)
|
||||
6 7 4 3 7 3 10 4 10 7
|
||||
6 3 2 1 7 3 5 4 3 2
|
||||
1 1
|
||||
%FLAG EXCLUDED_ATOMS_LIST
|
||||
%FORMAT(10I8)
|
||||
2 3 4 5 6 7 3 4 5 6
|
||||
7 8 9 4 5 6 7 5 6 7
|
||||
6 7 8 9 10 11 15 7 8 9
|
||||
8 9 10 11 12 13 14 15 16 17
|
||||
9 10 11 15 10 11 12 13 14 15
|
||||
16 17 18 19 11 12 13 14 15 16
|
||||
17 12 13 14 15 16 17 13 14 15
|
||||
14 15 15 16 17 18 19 20 21 22
|
||||
17 18 19 18 19 20 21 22 19 20
|
||||
21 22 20 21 22 21 22 22 0
|
||||
%FLAG BOND_FORCE_CONSTANT
|
||||
%FORMAT(5E16.8)
|
||||
3.40000000E+02 4.34000000E+02 3.17000000E+02 5.70000000E+02 4.90000000E+02
|
||||
3.37000000E+02 3.10000000E+02
|
||||
%FLAG BOND_EQUIL_VALUE
|
||||
%FORMAT(5E16.8)
|
||||
1.09000000E+00 1.01000000E+00 1.52200000E+00 1.22900000E+00 1.33500000E+00
|
||||
1.44900000E+00 1.52600000E+00
|
||||
%FLAG BONDS_INC_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
0 3 1 3 6 1 3 9 1 18
|
||||
21 2 24 27 1 30 33 1 30 36
|
||||
1 30 39 1 48 51 2 54 57 1
|
||||
54 60 1 54 63 1
|
||||
%FLAG BONDS_WITHOUT_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
3 12 3 12 15 4 12 18 5 18
|
||||
24 6 24 42 3 24 30 7 42 48
|
||||
5 42 45 4 48 54 6
|
||||
%FLAG ANGLE_FORCE_CONSTANT
|
||||
%FORMAT(5E16.8)
|
||||
3.50000000E+01 5.00000000E+01 5.00000000E+01 5.00000000E+01 8.00000000E+01
|
||||
7.00000000E+01 5.00000000E+01 8.00000000E+01 8.00000000E+01 6.30000000E+01
|
||||
6.30000000E+01
|
||||
%FLAG ANGLE_EQUIL_VALUE
|
||||
%FORMAT(5E16.8)
|
||||
1.91113553E+00 1.91113553E+00 2.09439510E+00 2.06018665E+00 2.10137642E+00
|
||||
2.03505391E+00 2.12755636E+00 2.14500965E+00 1.91462619E+00 1.92160751E+00
|
||||
1.93906080E+00
|
||||
%FLAG ANGLES_INC_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
0 3 6 1 0 3 9 1 0 3
|
||||
12 2 6 3 9 1 6 3 12 2
|
||||
9 3 12 2 12 18 21 3 18 24
|
||||
27 2 21 18 24 4 24 30 33 2
|
||||
24 30 36 2 24 30 39 2 27 24
|
||||
30 2 27 24 42 2 33 30 36 1
|
||||
33 30 39 1 36 30 39 1 42 48
|
||||
51 3 48 54 57 2 48 54 60 2
|
||||
48 54 63 2 51 48 54 4 57 54
|
||||
60 1 57 54 63 1 60 54 63 1
|
||||
%FLAG ANGLES_WITHOUT_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
3 12 15 5 3 12 18 6 12 18
|
||||
24 7 15 12 18 8 18 24 30 9
|
||||
18 24 42 10 24 42 45 5 24 42
|
||||
48 6 30 24 42 11 42 48 54 7
|
||||
45 42 48 8
|
||||
%FLAG DIHEDRAL_FORCE_CONSTANT
|
||||
%FORMAT(5E16.8)
|
||||
8.00000000E-01 8.00000000E-02 2.50000000E+00 2.50000000E+00 2.00000000E+00
|
||||
1.55555556E-01 1.10000000E+00 0.00000000E+00 0.00000000E+00 8.00000000E-01
|
||||
1.80000000E+00 4.20000000E-01 2.70000000E-01 5.50000000E-01 1.58000000E+00
|
||||
4.50000000E-01 4.00000000E-01 2.00000000E-01 2.00000000E-01 1.05000000E+01
|
||||
%FLAG DIHEDRAL_PERIODICITY
|
||||
%FORMAT(5E16.8)
|
||||
1.00000000E+00 3.00000000E+00 2.00000000E+00 2.00000000E+00 1.00000000E+00
|
||||
3.00000000E+00 2.00000000E+00 1.00000000E+00 1.00000000E+00 3.00000000E+00
|
||||
2.00000000E+00 3.00000000E+00 2.00000000E+00 3.00000000E+00 2.00000000E+00
|
||||
1.00000000E+00 3.00000000E+00 2.00000000E+00 1.00000000E+00 2.00000000E+00
|
||||
%FLAG DIHEDRAL_PHASE
|
||||
%FORMAT(5E16.8)
|
||||
0.00000000E+00 3.14159265E+00 3.14159265E+00 3.14159265E+00 0.00000000E+00
|
||||
0.00000000E+00 3.14159265E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 3.14159265E+00 3.14159265E+00
|
||||
3.14159265E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 3.14159265E+00
|
||||
%FLAG SCEE_SCALE_FACTOR
|
||||
%FORMAT(5E16.8)
|
||||
1.20000000E+00 0.00000000E+00 1.20000000E+00 1.20000000E+00 0.00000000E+00
|
||||
1.20000000E+00 0.00000000E+00 1.20000000E+00 1.20000000E+00 1.20000000E+00
|
||||
0.00000000E+00 1.20000000E+00 0.00000000E+00 1.20000000E+00 0.00000000E+00
|
||||
0.00000000E+00 1.20000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
%FLAG SCNB_SCALE_FACTOR
|
||||
%FORMAT(5E16.8)
|
||||
2.00000000E+00 0.00000000E+00 2.00000000E+00 2.00000000E+00 0.00000000E+00
|
||||
2.00000000E+00 0.00000000E+00 2.00000000E+00 2.00000000E+00 2.00000000E+00
|
||||
0.00000000E+00 2.00000000E+00 0.00000000E+00 2.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 2.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
%FLAG DIHEDRALS_INC_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
0 3 12 15 1 0 3 -12 15 2
|
||||
3 12 18 21 3 6 3 12 15 1
|
||||
6 3 -12 15 2 9 3 12 15 1
|
||||
9 3 -12 15 2 15 12 18 21 4
|
||||
15 12 -18 21 5 18 24 30 33 6
|
||||
18 24 30 36 6 18 24 30 39 6
|
||||
24 42 48 51 3 27 24 30 33 6
|
||||
27 24 30 36 6 27 24 30 39 6
|
||||
27 24 42 45 1 27 24 -42 45 2
|
||||
42 24 30 33 6 42 24 30 36 6
|
||||
42 24 30 39 6 45 42 48 51 4
|
||||
45 42 -48 51 5 21 18 -24 -12 7
|
||||
51 48 -54 -42 7 51 48 54 60 8
|
||||
21 18 24 30 8 42 48 54 57 8
|
||||
6 3 12 18 9 42 48 54 63 8
|
||||
51 48 54 57 8 21 18 24 42 8
|
||||
0 3 12 18 9 42 48 54 60 8
|
||||
27 24 42 48 8 21 18 24 27 8
|
||||
51 48 54 63 8 9 3 12 18 9
|
||||
12 18 24 27 8
|
||||
%FLAG DIHEDRALS_WITHOUT_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
3 12 18 24 3 12 18 24 30 10
|
||||
12 18 -24 30 11 12 18 -24 30 5
|
||||
12 18 24 42 12 12 18 -24 42 13
|
||||
15 12 18 24 3 18 24 42 48 14
|
||||
18 24 -42 48 15 18 24 -42 48 16
|
||||
24 42 48 54 3 30 24 42 48 17
|
||||
30 24 -42 48 18 30 24 -42 48 19
|
||||
45 42 48 54 3 15 12 -18 -3 20
|
||||
45 42 -48 -24 20 18 24 42 45 8
|
||||
30 24 42 45 8
|
||||
%FLAG SOLTY
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG HBOND_ACOEF
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG HBOND_BCOEF
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG HBCUT
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG TREE_CHAIN_CLASSIFICATION
|
||||
%FORMAT(20a4)
|
||||
BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA
|
||||
BLA BLA
|
||||
%FLAG JOIN_ARRAY
|
||||
%FORMAT(10I8)
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0
|
||||
%FLAG IROTAT
|
||||
%FORMAT(10I8)
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0
|
||||
%FLAG BOX_DIMENSIONS
|
||||
%FORMAT(5E16.8)
|
||||
9.00000000E+01 3.00000000E+01 3.00000000E+01 3.00000000E+01
|
||||
%FLAG RADIUS_SET
|
||||
%FORMAT(1a80)
|
||||
0
|
||||
%FLAG RADII
|
||||
%FORMAT(5E16.8)
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00
|
||||
%FLAG SCREEN
|
||||
%FORMAT(5E16.8)
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00
|
||||
%FLAG IPOL
|
||||
%FORMAT(1I8)
|
||||
0
|
||||
26
examples/trajectory/protein.pdb
Normal file
26
examples/trajectory/protein.pdb
Normal file
@@ -0,0 +1,26 @@
|
||||
CRYST1 30.000 30.000 30.000 90.00 90.00 90.00 P 1 1
|
||||
ATOM 1 H1 ACE A 1 2.000 1.000 -0.000 0.00 0.00 H
|
||||
ATOM 2 CH3 ACE A 1 2.000 2.090 0.000 0.00 0.00 C
|
||||
ATOM 3 H2 ACE A 1 1.486 2.454 0.890 0.00 0.00 H
|
||||
ATOM 4 H3 ACE A 1 1.486 2.454 -0.890 0.00 0.00 H
|
||||
ATOM 5 C ACE A 1 3.427 2.641 -0.000 0.00 0.00 C
|
||||
ATOM 6 O ACE A 1 4.391 1.877 -0.000 0.00 0.00 O
|
||||
ATOM 7 N ALA A 2 3.555 3.970 -0.000 0.00 0.00 N
|
||||
ATOM 8 H ALA A 2 2.733 4.556 -0.000 0.00 0.00 H
|
||||
ATOM 9 CA ALA A 2 4.853 4.614 -0.000 0.00 0.00 C
|
||||
ATOM 10 HA ALA A 2 5.408 4.316 0.890 0.00 0.00 H
|
||||
ATOM 11 CB ALA A 2 5.661 4.221 -1.232 0.00 0.00 C
|
||||
ATOM 12 HB1 ALA A 2 5.123 4.521 -2.131 0.00 0.00 H
|
||||
ATOM 13 HB2 ALA A 2 6.630 4.719 -1.206 0.00 0.00 H
|
||||
ATOM 14 HB3 ALA A 2 5.809 3.141 -1.241 0.00 0.00 H
|
||||
ATOM 15 C ALA A 2 4.713 6.129 0.000 0.00 0.00 C
|
||||
ATOM 16 O ALA A 2 3.601 6.653 0.000 0.00 0.00 O
|
||||
ATOM 17 N NME A 3 5.846 6.835 0.000 0.00 0.00 N
|
||||
ATOM 18 H NME A 3 6.737 6.359 -0.000 0.00 0.00 H
|
||||
ATOM 19 C NME A 3 5.846 8.284 0.000 0.00 0.00 C
|
||||
ATOM 20 H1 NME A 3 4.819 8.648 0.000 0.00 0.00 H
|
||||
ATOM 21 H2 NME A 3 6.360 8.648 0.890 0.00 0.00 H
|
||||
ATOM 22 H3 NME A 3 6.360 8.648 -0.890 0.00 0.00 H
|
||||
TER 23 NME A 3
|
||||
CONECT 5 7
|
||||
CONECT 15 17
|
||||
14
examples/trajectory/protein.rst7
Normal file
14
examples/trajectory/protein.rst7
Normal file
@@ -0,0 +1,14 @@
|
||||
alanine-dipeptide.solvated.pdb
|
||||
22
|
||||
0.7494821 1.2436848 0.8743532 1.0856344 2.2423820 0.5955986
|
||||
0.4304414 2.9747953 1.0671825 1.0497815 2.3544810 -0.4880289
|
||||
2.5015950 2.4471725 1.0820421 3.1003812 1.5343071 1.6479120
|
||||
3.0220696 3.6519467 0.8741013 2.4411554 4.3533213 0.4373955
|
||||
4.3920715 4.0500473 1.2160543 4.7674596 3.4172266 2.0202454
|
||||
5.2805058 3.8202998 -0.0180103 4.9565949 4.4537317 -0.8438106
|
||||
6.3180425 4.0583459 0.2164072 5.2327259 2.7740601 -0.3200050
|
||||
4.4431625 5.5106563 1.7135265 3.4307644 6.2198007 1.6891606
|
||||
5.6170320 5.9613562 2.1744082 6.3997462 5.3231585 2.1616313
|
||||
5.8784762 7.3296314 2.6320299 5.1056278 8.0184146 2.2908769
|
||||
5.9253575 7.3544224 3.7207393 6.8360338 7.6745804 2.2419090
|
||||
30.0000000 30.0000000 30.0000000 90.0000000 90.0000000 90.0000000
|
||||
6393
package-lock.json
generated
6393
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "5.1.2",
|
||||
"version": "5.4.2",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -131,51 +131,51 @@
|
||||
"@types/gl": "^6.0.5",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@types/react": "^18.3.24",
|
||||
"@types/react": "^18.3.26",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"@types/webxr": "^0.5.23",
|
||||
"@typescript-eslint/eslint-plugin": "^8.44.1",
|
||||
"@typescript-eslint/parser": "^8.44.1",
|
||||
"@types/webxr": "^0.5.24",
|
||||
"@typescript-eslint/eslint-plugin": "^8.48.1",
|
||||
"@typescript-eslint/parser": "^8.48.1",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^9.2.1",
|
||||
"cpx2": "^8.0.0",
|
||||
"css-loader": "^7.1.2",
|
||||
"esbuild": "^0.25.10",
|
||||
"esbuild": "^0.27.1",
|
||||
"esbuild-jest-transform": "^2.0.1",
|
||||
"esbuild-sass-plugin": "^3.3.1",
|
||||
"eslint": "^9.36.0",
|
||||
"eslint": "^9.39.1",
|
||||
"fs-extra": "^11.3.2",
|
||||
"http-server": "^14.1.1",
|
||||
"jest": "^30.2.0",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"sass": "^1.93.2",
|
||||
"simple-git": "^3.28.0",
|
||||
"sass": "^1.94.2",
|
||||
"simple-git": "^3.30.0",
|
||||
"tsc-alias": "^1.8.16",
|
||||
"typescript": "^5.9.2"
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.17",
|
||||
"@types/benchmark": "^2.1.5",
|
||||
"@types/compression": "1.8.1",
|
||||
"@types/express": "^5.0.3",
|
||||
"@types/node": "^20.19.17",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/node": "^20.19.25",
|
||||
"@types/node-fetch": "^2.6.13",
|
||||
"@types/swagger-ui-dist": "3.30.6",
|
||||
"argparse": "^2.0.1",
|
||||
"compression": "^1.8.1",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0",
|
||||
"express": "^5.2.1",
|
||||
"h264-mp4-encoder": "^1.0.12",
|
||||
"immutable": "^5.1.3",
|
||||
"immutable": "^5.1.4",
|
||||
"io-ts": "^2.2.22",
|
||||
"mutative": "^1.3.0",
|
||||
"node-fetch": "^2.7.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"rxjs": "^7.8.2",
|
||||
"swagger-ui-dist": "^5.29.0",
|
||||
"swagger-ui-dist": "^5.30.3",
|
||||
"tslib": "^2.8.1",
|
||||
"util.promisify": "^1.1.3"
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useBehavior } from '../../../mol-plugin-ui/hooks/use-behavior';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { PluginStateSnapshotManager } from '../../../mol-plugin-state/manager/snapshots';
|
||||
import { PluginReactContext } from '../../../mol-plugin-ui/base';
|
||||
import { CSSProperties } from 'react';
|
||||
import { CSSProperties, useEffect, useState } from 'react';
|
||||
import { Markdown } from '../../../mol-plugin-ui/controls/markdown';
|
||||
|
||||
export class MVSStoriesSnapshotMarkdownModel extends PluginComponent {
|
||||
@@ -70,6 +70,28 @@ export class MVSStoriesSnapshotMarkdownModel extends PluginComponent {
|
||||
}
|
||||
}
|
||||
|
||||
function Loading() {
|
||||
return <div>
|
||||
<div style={{ marginBottom: 16 }}><i>Loading times may vary depending on the story size, your internet connection, and device performance</i></div>
|
||||
<div>Fetching data<Dots /></div>
|
||||
<div>Generating animations<Dots /></div>
|
||||
<div>Preparing visuals<Dots /></div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function Dots() {
|
||||
const [dots, setDots] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setDots(d => (d + 1) % 4);
|
||||
}, Math.random() * 500 + 300);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return <span>{'.'.repeat(dots)}</span>;
|
||||
}
|
||||
|
||||
export function MVSStoriesSnapshotMarkdownUI({ model }: { model: MVSStoriesSnapshotMarkdownModel }) {
|
||||
const state = useBehavior(model.state);
|
||||
const isLoading = useBehavior(model.context.state.isLoading);
|
||||
@@ -79,7 +101,8 @@ export function MVSStoriesSnapshotMarkdownUI({ model }: { model: MVSStoriesSnaps
|
||||
|
||||
if (isLoading) {
|
||||
return <div style={style} className={className}>
|
||||
<i>Loading...</i>
|
||||
<h3>The story will be ready momentarily</h3>
|
||||
<Loading />
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,8 +94,8 @@
|
||||
</div>
|
||||
|
||||
<div id="links">
|
||||
<span id="open-in-stories"><a href="#" id="open-in-stories-link" target="_blank" rel="noopener noreferrer" title="Open and edit the story in the MolViewStories app">Edit in MolViewStories</a> <span class="sep">•</span></span>
|
||||
<span id="open-in-molstar"><a href="#" id="open-in-molstar-link" target="_blank" rel="noopener noreferrer" title="Open the story in the Mol* Viewer app. Enables exporting an animation.">Open in Mol* Viewer</a> <span class="sep">•</span></span>
|
||||
<span id="open-in-stories" style="display: none;"><a href="#" id="open-in-stories-link" target="_blank" rel="noopener noreferrer" title="Open and edit the story in the MolViewStories app">Edit in MolViewStories</a> <span class="sep">•</span></span>
|
||||
<span id="open-in-molstar" style="display: none;"><a href="#" id="open-in-molstar-link" target="_blank" rel="noopener noreferrer" title="Open the story in the Mol* Viewer app. Enables exporting an animation.">Open in Mol* Viewer</a> <span class="sep">•</span></span>
|
||||
<a href="#" id="mvs-data" title="MolViewSpec State for this story. Can be opened in the Mol* app.">Download MVS</a> <span class="sep">•</span> <a href="https://github.com/molstar/molstar/tree/master/src/apps/mvs-stories" id="mvs-data" target="_blank" rel="noopener noreferrer">Source Code</a>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@ export class Viewer {
|
||||
} else if (format === 'mvsx') {
|
||||
const data = await this.plugin.runTask(this.plugin.fetch({ url, type: 'binary' }));
|
||||
await this.plugin.runTask(Task.create('Load MVSX file', async ctx => {
|
||||
const parsed = await loadMVSX(this.plugin, ctx, data);
|
||||
const parsed = await loadMVSX(this.plugin, ctx, data, { doNotClearAssets: options?.appendSnapshots });
|
||||
await loadMVS(this.plugin, parsed.mvsData, { sanityChecks: true, sourceUrl: parsed.sourceUrl, ...options });
|
||||
}));
|
||||
} else {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2025 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 * as fs from 'fs';
|
||||
@@ -38,7 +39,7 @@ function print(volume: Volume) {
|
||||
}
|
||||
|
||||
async function doMesh(volume: Volume, filename: string) {
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, -1, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) })).run();
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, -1, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5), wrap: 'auto' })).run();
|
||||
console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount });
|
||||
|
||||
// Export the mesh in OBJ format.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
@@ -33,7 +33,7 @@ import { MVSTreeSchema } from './tree/mvs/mvs-tree';
|
||||
|
||||
|
||||
const DefaultFocusOptions = {
|
||||
minRadius: 5,
|
||||
minRadius: 1,
|
||||
extraRadius: 0,
|
||||
};
|
||||
const DefaultCanvasBackgroundColor = ColorNames.white;
|
||||
@@ -62,7 +62,15 @@ export function cameraParamsToCameraSnapshot(plugin: PluginContext, params: Mols
|
||||
if (plugin.canvas3d) position = fovAdjustedPosition(target, position, plugin.canvas3d.camera.state.mode, plugin.canvas3d.camera.state.fov);
|
||||
const up = Vec3.create(...params.up);
|
||||
Vec3.orthogonalize(up, Vec3.sub(_tmpVec, target, position), up);
|
||||
const snapshot: Partial<Camera.Snapshot> = { target, position, up, radius, radiusMax: radius };
|
||||
|
||||
const snapshot: Partial<Camera.Snapshot> = {
|
||||
target,
|
||||
position,
|
||||
up,
|
||||
radius,
|
||||
radiusMax: radius,
|
||||
minNear: params.near ?? undefined,
|
||||
};
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ export function MVSAnnotationColorTheme(ctx: ThemeDataContext, props: MVSAnnotat
|
||||
return {
|
||||
factory: MVSAnnotationColorTheme,
|
||||
granularity: 'groupInstance',
|
||||
preferSmoothing: true,
|
||||
preferSmoothing: false,
|
||||
color: color,
|
||||
props: props,
|
||||
description: 'Assigns colors based on custom MolViewSpec annotation data.',
|
||||
|
||||
@@ -377,6 +377,7 @@ function getRowsFromCif(data: CifCategory, schema: MVSAnnotationSchema, fieldRem
|
||||
const columnArray = getArrayFromCifCategory(data, srcKey, cifSchema[key]); // Avoiding `column.toArray` as it replaces . and ? fields by 0 or ''
|
||||
if (columnArray) columns[key] = columnArray;
|
||||
}
|
||||
if (Object.keys(columns).length === 0) return new Array(data.rowCount).fill({});
|
||||
return objectOfArraysToArrayOfObjects(columns);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,11 +112,18 @@ export const MVSXFormatProvider: DataFormatProvider<{}, StateObjectRef<Mvs>, any
|
||||
* add all contained files to `plugin`'s asset manager,
|
||||
* and parse the main file in the archive as MVSJ.
|
||||
* Return parsed MVS data and `sourceUrl` for resolution of relative URIs. */
|
||||
export async function loadMVSX(plugin: PluginContext, runtimeCtx: RuntimeContext, data: Uint8Array<ArrayBuffer>, mainFilePath: string = 'index.mvsj'): Promise<{ mvsData: MVSData, sourceUrl: string }> {
|
||||
export async function loadMVSX(plugin: PluginContext, runtimeCtx: RuntimeContext, data: Uint8Array<ArrayBuffer>, mainFilePathOrOptions?: string | { mainFilePath?: string, doNotClearAssets?: boolean }): Promise<{ mvsData: MVSData, sourceUrl: string }> {
|
||||
// TODO: on next major version, streamline mainFilePathOrOptions
|
||||
if (typeof mainFilePathOrOptions === 'string') {
|
||||
mainFilePathOrOptions = { mainFilePath: mainFilePathOrOptions };
|
||||
}
|
||||
const mainFilePath = mainFilePathOrOptions?.mainFilePath ?? 'index.mvsj';
|
||||
const doNotClearAssets = mainFilePathOrOptions?.doNotClearAssets ?? false;
|
||||
|
||||
// Ensure at most one generation of MVSX file assets exists in the asset manager.
|
||||
// Hopefully, this is a reasonable compromise to ensure MVSX files work in multi-snapshot
|
||||
// states.
|
||||
clearMVSXFileAssets(plugin);
|
||||
if (!doNotClearAssets) clearMVSXFileAssets(plugin);
|
||||
|
||||
const archiveId = `ni,MurmurHash3_128;${murmurHash3_128_fromBytes(data, 42)}`;
|
||||
let files: { [path: string]: Uint8Array<ArrayBuffer> };
|
||||
@@ -160,7 +167,7 @@ export async function loadMVSData(plugin: PluginContext, data: MVSData | StringL
|
||||
throw new Error("loadMvsData: if `format` is 'mvsx', then `data` must be a Uint8Array or a base64-encoded string prefixed with 'base64,'.");
|
||||
}
|
||||
await plugin.runTask(Task.create('Load MVSX file', async ctx => {
|
||||
const parsed = await loadMVSX(plugin, ctx, data as Uint8Array<ArrayBuffer>);
|
||||
const parsed = await loadMVSX(plugin, ctx, data as Uint8Array<ArrayBuffer>, { doNotClearAssets: options?.appendSnapshots });
|
||||
await loadMVS(plugin, parsed.mvsData, { sanityChecks: true, ...options, sourceUrl: parsed.sourceUrl });
|
||||
}));
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
@@ -72,7 +72,7 @@ export const DefaultMultilayerColorThemeProps: MultilayerColorThemeProps = { lay
|
||||
* If a nested theme provider has `ensureCustomProperties` methods, these will not be called automatically
|
||||
* (the caller must ensure that any required custom properties be attached). */
|
||||
function makeMultilayerColorTheme(ctx: ThemeDataContext, props: MultilayerColorThemeProps, colorThemeRegistry: ColorTheme.Registry): ColorTheme<MultilayerColorThemeParams> {
|
||||
const { colorLayers, granularity } = makeLayers(ctx, props, colorThemeRegistry);
|
||||
const { colorLayers, granularity, preferSmoothing } = makeLayers(ctx, props, colorThemeRegistry);
|
||||
|
||||
function structureElementColor(loc: StructureElement.Location, isSecondary: boolean): Color {
|
||||
for (const layer of colorLayers) {
|
||||
@@ -101,7 +101,7 @@ function makeMultilayerColorTheme(ctx: ThemeDataContext, props: MultilayerColorT
|
||||
return {
|
||||
factory: (ctx_, props_) => makeMultilayerColorTheme(ctx_, props_, colorThemeRegistry),
|
||||
granularity,
|
||||
preferSmoothing: true,
|
||||
preferSmoothing,
|
||||
color: color,
|
||||
props: props,
|
||||
description: 'Combines colors from multiple color themes.',
|
||||
@@ -136,6 +136,7 @@ interface ColorLayer {
|
||||
function makeLayers(ctx: ThemeDataContext, props: MultilayerColorThemeProps, colorThemeRegistry: ColorTheme.Registry) {
|
||||
const colorLayers: ColorLayer[] = [];
|
||||
let granularityFlags = 0;
|
||||
let preferSmoothing = false;
|
||||
for (let i = props.layers.length - 1; i >= 0; i--) { // iterate from the end to get top layer first, bottom layer last
|
||||
const layer = props.layers[i];
|
||||
const themeProvider = colorThemeRegistry.get(layer.theme.name);
|
||||
@@ -175,8 +176,9 @@ function makeLayers(ctx: ThemeDataContext, props: MultilayerColorThemeProps, col
|
||||
default:
|
||||
console.warn(`Skipping color theme '${layer.theme.name}', cannot process granularity '${theme.granularity}'`);
|
||||
}
|
||||
if (theme.preferSmoothing) preferSmoothing = true;
|
||||
}
|
||||
return { colorLayers, granularity: granularityNameFromFlags(granularityFlags) };
|
||||
return { colorLayers, granularity: granularityNameFromFlags(granularityFlags), preferSmoothing };
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import { Task } from '../../../mol-task';
|
||||
import { round } from '../../../mol-util';
|
||||
import { range } from '../../../mol-util/array';
|
||||
import { Asset } from '../../../mol-util/assets';
|
||||
import { Clip } from '../../../mol-util/clip';
|
||||
import { Color } from '../../../mol-util/color';
|
||||
import { MarkerActions } from '../../../mol-util/marker-action';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
@@ -40,6 +41,7 @@ import { capitalize } from '../../../mol-util/string';
|
||||
import { rowsToExpression, rowToExpression } from '../helpers/selections';
|
||||
import { collectMVSReferences, decodeColor, isDefined } from '../helpers/utils';
|
||||
import { addParamDefaults } from '../tree/generic/params-schema';
|
||||
import { treeValidationIssues } from '../tree/generic/tree-validation';
|
||||
import { MolstarNode, MolstarNodeParams, MolstarSubtree } from '../tree/molstar/molstar-tree';
|
||||
import { MVSNode, MVSTreeSchema } from '../tree/mvs/mvs-tree';
|
||||
import { isComponentExpression, isPrimitiveComponentExpressions, isVector3, PrimitivePositionT } from '../tree/mvs/param-types';
|
||||
@@ -81,15 +83,35 @@ export const MVSDownloadPrimitiveData = MVSTransform({
|
||||
const url = Asset.getUrlAsset(plugin.managers.asset, params.uri);
|
||||
const asset = await plugin.managers.asset.resolve(url, 'string').runInContext(ctx);
|
||||
const node = JSON.parse(StringLike.toString(asset.data)) as MolstarSubtree<'primitives'>;
|
||||
const validationIssues = treeValidationIssues(MVSTreeSchema, node, { anyRoot: true });
|
||||
if (validationIssues) {
|
||||
throw new Error(`Invalid primitive data from ${params.uri}:\n${validationIssues.join('\n')}`);
|
||||
}
|
||||
if (node.kind !== 'primitives') {
|
||||
throw new Error(`Expected primitives node from ${params.uri}, got ${node.kind}`);
|
||||
}
|
||||
const nodeWithDefaults: MolstarSubtree<'primitives'> = {
|
||||
...node,
|
||||
params: addParamDefaults(MVSTreeSchema.nodes.primitives.params, node.params || {}),
|
||||
children: node.children?.map((child: any) => {
|
||||
if (child.kind === 'primitive') {
|
||||
return {
|
||||
...child,
|
||||
params: addParamDefaults(MVSTreeSchema.nodes.primitive.params, child.params || {})
|
||||
};
|
||||
}
|
||||
return child;
|
||||
})
|
||||
};
|
||||
(cache as any).asset = asset;
|
||||
return new MVSPrimitivesData({
|
||||
node,
|
||||
node: nodeWithDefaults,
|
||||
defaultStructure: SO.Molecule.Structure.is(a) ? a.data : undefined,
|
||||
structureRefs: {},
|
||||
primitives: getPrimitives(node),
|
||||
options: { ...node.params },
|
||||
primitives: getPrimitives(nodeWithDefaults),
|
||||
options: { ...nodeWithDefaults.params },
|
||||
positionCache: new Map(),
|
||||
instances: getInstances(node.params),
|
||||
instances: getInstances(nodeWithDefaults.params),
|
||||
}, { label: 'Primitive Data' });
|
||||
});
|
||||
},
|
||||
@@ -141,7 +163,8 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
from: MVSPrimitivesData,
|
||||
to: SO.Shape.Provider,
|
||||
params: {
|
||||
kind: PD.Text<'mesh' | 'labels' | 'lines'>('mesh')
|
||||
kind: PD.Text<'mesh' | 'labels' | 'lines'>('mesh'),
|
||||
clip: PD.Value<Clip.Props | undefined>(undefined, { isHidden: true })
|
||||
}
|
||||
})({
|
||||
apply({ a, params, dependencies }) {
|
||||
@@ -160,7 +183,7 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
label,
|
||||
data: context,
|
||||
params: {
|
||||
...PD.withDefaults(Mesh.Params, { alpha: a.data.options?.opacity ?? 1, ...customMeshParams }),
|
||||
...PD.withDefaults(Mesh.Params, { alpha: a.data.options?.opacity ?? 1, clip: params.clip, ...customMeshParams }),
|
||||
...snapshotKey,
|
||||
...markdownCommands,
|
||||
},
|
||||
@@ -184,6 +207,7 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
tetherLength: options?.label_tether_length ?? 1,
|
||||
background: isDefined(bgColor),
|
||||
backgroundColor: isDefined(bgColor) ? decodeColor(bgColor) : undefined,
|
||||
clip: params.clip,
|
||||
...customLabelParams,
|
||||
}),
|
||||
...snapshotKey,
|
||||
@@ -200,7 +224,7 @@ export const MVSBuildPrimitiveShape = MVSTransform({
|
||||
label,
|
||||
data: context,
|
||||
params: {
|
||||
...PD.withDefaults(Lines.Params, { alpha: a.data.options?.opacity ?? 1, ...customLineParams }),
|
||||
...PD.withDefaults(Lines.Params, { alpha: a.data.options?.opacity ?? 1, clip: params.clip, ...customLineParams }),
|
||||
...snapshotKey,
|
||||
...markdownCommands,
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ import { MVSTransform } from './annotation-structure-component';
|
||||
export const MVSTrajectoryWithCoordinates = MVSTransform({
|
||||
name: 'trajectory-with-coordinates',
|
||||
display: { name: 'Trajectory with Coordinates', description: 'Create a trajectory from existing model and the provided coordinates.' },
|
||||
from: PluginStateObject.Molecule.Model,
|
||||
from: [PluginStateObject.Molecule.Model, PluginStateObject.Molecule.Topology],
|
||||
to: PluginStateObject.Molecule.Trajectory,
|
||||
params: {
|
||||
coordinatesRef: ParamDefinition.Text('', { isHidden: true }),
|
||||
|
||||
@@ -208,6 +208,7 @@ function getQualifyingResidues(model: Model, row: MVSAnnotationRow, indices: Ato
|
||||
}
|
||||
arrayExtend(result, residuesHere);
|
||||
}
|
||||
sortIfNeeded(result, (a, b) => a - b);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -419,7 +420,7 @@ function getQualifyingCoarseElements(coarseElements: CoarseElements, row: MVSAnn
|
||||
// This implementation can yield some elements even when queryStart>queryEnd (e.g. { beg_label_seq_id: 70, end_label_seq_id: 58, label_seq_id: 60 } -> sphere 51-100 qualifies ).
|
||||
// This is on purpose, to have the same behavior as MolScript.
|
||||
}
|
||||
sortIfNeeded(result, iElem => iElem);
|
||||
sortIfNeeded(result, (a, b) => a - b);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import { hashString } from '../../../mol-data/util';
|
||||
import { StateObject } from '../../../mol-state';
|
||||
import { Color } from '../../../mol-util/color';
|
||||
import { ColorNames } from '../../../mol-util/color/names';
|
||||
import { decodeColor as _decodeColor } from '../../../mol-util/color/utils';
|
||||
|
||||
|
||||
@@ -107,29 +106,6 @@ export function decodeColor(colorString: string | number | undefined | null): Co
|
||||
return _decodeColor(colorString);
|
||||
}
|
||||
|
||||
/** Regular expression matching a hexadecimal color string, e.g. '#FF1100' or '#f10' */
|
||||
const hexColorRegex = /^#([0-9A-F]{3}){1,2}$/i;
|
||||
|
||||
/** Hexadecimal color string, e.g. '#FF1100' (the type matches more than just valid HexColor strings) */
|
||||
export type HexColor = `#${string}`
|
||||
|
||||
export const HexColor = {
|
||||
/** Decide if a string is a valid hexadecimal color string (6-digit or 3-digit, e.g. '#FF1100' or '#f10') */
|
||||
is(str: any): str is HexColor {
|
||||
return typeof str === 'string' && hexColorRegex.test(str);
|
||||
},
|
||||
};
|
||||
|
||||
/** Named color string, e.g. 'red' */
|
||||
export type ColorName = keyof ColorNames
|
||||
|
||||
export const ColorName = {
|
||||
/** Decide if a string is a valid named color string */
|
||||
is(str: any): str is ColorName {
|
||||
return str in ColorNames;
|
||||
},
|
||||
};
|
||||
|
||||
export function collectMVSReferences<T extends StateObject.Ctor>(type: T[], dependencies: Record<string, StateObject>): Record<string, StateObject.From<T>['data']> {
|
||||
const ret: any = {};
|
||||
|
||||
|
||||
8
src/extensions/mvs/index.ts
Normal file
8
src/extensions/mvs/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
export * from './mvs-data';
|
||||
export * from './load';
|
||||
@@ -479,7 +479,7 @@ function getClipObject(node: MolstarNode<'clip'>): Clip.Props['objects'][number]
|
||||
}
|
||||
}
|
||||
|
||||
export function clippingForNode(node: MolstarSubtree<'representation' | 'volume_representation'>): Clip.Props | undefined {
|
||||
export function clippingForNode(node: MolstarSubtree<'representation' | 'volume_representation' | 'primitives' | 'primitives_from_uri'>): Clip.Props | undefined {
|
||||
const children = getChildren(node).filter(c => c.kind === 'clip');
|
||||
if (!children.length) return;
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
import { PluginStateSnapshotManager } from '../../mol-plugin-state/manager/snapshots';
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { Download, ParseCif, ParseCcp4, ParseDx } from '../../mol-plugin-state/transforms/data';
|
||||
import { CoordinatesFromLammpstraj, CoordinatesFromXtc, CustomModelProperties, CustomStructureProperties, ModelFromTrajectory, StructureComponent, StructureFromModel, TrajectoryFromGRO, TrajectoryFromLammpsTrajData, TrajectoryFromMmCif, TrajectoryFromMOL, TrajectoryFromMOL2, TrajectoryFromPDB, TrajectoryFromSDF, TrajectoryFromXYZ } from '../../mol-plugin-state/transforms/model';
|
||||
import { Download, ParseCcp4, ParseCif, ParseDx, ParsePrmtop, ParsePsf, ParseTop } from '../../mol-plugin-state/transforms/data';
|
||||
import { CoordinatesFromDcd, CoordinatesFromLammpstraj, CoordinatesFromNctraj, CoordinatesFromTrr, CoordinatesFromXtc, CustomModelProperties, CustomStructureProperties, ModelFromTrajectory, StructureComponent, StructureFromModel, TopologyFromPrmtop, TopologyFromPsf, TopologyFromTop, TrajectoryFromGRO, TrajectoryFromLammpsTrajData, TrajectoryFromMmCif, TrajectoryFromMOL, TrajectoryFromMOL2, TrajectoryFromPDB, TrajectoryFromSDF, TrajectoryFromXYZ } from '../../mol-plugin-state/transforms/model';
|
||||
import { StructureRepresentation3D, VolumeRepresentation3D } from '../../mol-plugin-state/transforms/representation';
|
||||
import { VolumeFromCcp4, VolumeFromDensityServerCif, VolumeFromDx } from '../../mol-plugin-state/transforms/volume';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
@@ -17,6 +17,7 @@ import { PluginContext } from '../../mol-plugin/context';
|
||||
import { PluginState } from '../../mol-plugin/state';
|
||||
import { StateObjectSelector, StateTree } from '../../mol-state';
|
||||
import { RuntimeContext, Task } from '../../mol-task';
|
||||
import { Clip } from '../../mol-util/clip';
|
||||
import { MolViewSpec } from './behavior';
|
||||
import { createPluginStateSnapshotCamera, modifyCanvasProps, resetCanvasProps } from './camera';
|
||||
import { MVSAnnotationsProvider } from './components/annotation-prop';
|
||||
@@ -31,7 +32,7 @@ import { generateStateTransition } from './helpers/animation';
|
||||
import { IsHiddenCustomStateExtension } from './load-extensions/is-hidden-custom-state';
|
||||
import { NonCovalentInteractionsExtension } from './load-extensions/non-covalent-interactions';
|
||||
import { LoadingActions, LoadingExtension, loadTreeVirtual, UpdateTarget } from './load-generic';
|
||||
import { AnnotationFromSourceKind, AnnotationFromUriKind, collectAnnotationReferences, collectAnnotationTooltips, collectInlineLabels, collectInlineTooltips, colorThemeForNode, componentFromXProps, componentPropsFromSelector, isPhantomComponent, labelFromXProps, makeNearestReprMap, prettyNameFromSelector, representationProps, structureProps, transformAndInstantiateStructure, transformAndInstantiateVolume, volumeColorThemeForNode, volumeRepresentationProps } from './load-helpers';
|
||||
import { AnnotationFromSourceKind, AnnotationFromUriKind, clippingForNode, collectAnnotationReferences, collectAnnotationTooltips, collectInlineLabels, collectInlineTooltips, colorThemeForNode, componentFromXProps, componentPropsFromSelector, isPhantomComponent, labelFromXProps, makeNearestReprMap, prettyNameFromSelector, representationProps, structureProps, transformAndInstantiateStructure, transformAndInstantiateVolume, volumeColorThemeForNode, volumeRepresentationProps } from './load-helpers';
|
||||
import { MVSData, MVSData_States, Snapshot, SnapshotMetadata } from './mvs-data';
|
||||
import { MVSAnimationNode, MVSAnimationSchema } from './tree/animation/animation-tree';
|
||||
import { validateTree } from './tree/generic/tree-validation';
|
||||
@@ -245,7 +246,16 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
|
||||
case 'mol2':
|
||||
case 'xtc':
|
||||
case 'lammpstrj':
|
||||
case 'dcd':
|
||||
case 'nctraj':
|
||||
case 'trr':
|
||||
return updateParent;
|
||||
case 'psf':
|
||||
return UpdateTarget.apply(updateParent, ParsePsf, {});
|
||||
case 'prmtop':
|
||||
return UpdateTarget.apply(updateParent, ParsePrmtop, {});
|
||||
case 'top':
|
||||
return UpdateTarget.apply(updateParent, ParseTop, {});
|
||||
case 'map':
|
||||
return UpdateTarget.apply(updateParent, ParseCcp4, {});
|
||||
case 'dx':
|
||||
@@ -259,6 +269,12 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
|
||||
coordinates(updateParent: UpdateTarget, node: MolstarNode<'coordinates'>): UpdateTarget | undefined {
|
||||
const format = node.params.format;
|
||||
switch (format) {
|
||||
case 'nctraj':
|
||||
return UpdateTarget.apply(updateParent, CoordinatesFromNctraj);
|
||||
case 'dcd':
|
||||
return UpdateTarget.apply(updateParent, CoordinatesFromDcd);
|
||||
case 'trr':
|
||||
return UpdateTarget.apply(updateParent, CoordinatesFromTrr);
|
||||
case 'xtc':
|
||||
return UpdateTarget.apply(updateParent, CoordinatesFromXtc);
|
||||
case 'lammpstrj':
|
||||
@@ -302,6 +318,28 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
|
||||
});
|
||||
return UpdateTarget.setMvsDependencies(result, [node.params.coordinates_ref]);
|
||||
},
|
||||
topology_with_coordinates(updateParent: UpdateTarget, node: MolstarNode<'topology_with_coordinates'>): UpdateTarget | undefined {
|
||||
let parsed: UpdateTarget;
|
||||
const format = node.params.format;
|
||||
switch (format) {
|
||||
case 'psf':
|
||||
parsed = UpdateTarget.apply(updateParent, TopologyFromPsf, {});
|
||||
break;
|
||||
case 'prmtop':
|
||||
parsed = UpdateTarget.apply(updateParent, TopologyFromPrmtop, {});
|
||||
break;
|
||||
case 'top':
|
||||
parsed = UpdateTarget.apply(updateParent, TopologyFromTop, {});
|
||||
break;
|
||||
default:
|
||||
console.error(`Unknown format in "topology_with_coordinates" node: "${format}"`);
|
||||
return undefined;
|
||||
}
|
||||
const result = UpdateTarget.apply(parsed, MVSTrajectoryWithCoordinates, {
|
||||
coordinatesRef: node.params.coordinates_ref,
|
||||
});
|
||||
return UpdateTarget.setMvsDependencies(result, [node.params.coordinates_ref]);
|
||||
},
|
||||
model(updateParent: UpdateTarget, node: MolstarSubtree<'model'>, context: MolstarLoadingContext): UpdateTarget {
|
||||
const annotations = collectAnnotationReferences(node, context);
|
||||
const model = UpdateTarget.apply(updateParent, ModelFromTrajectory, {
|
||||
@@ -325,18 +363,16 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
|
||||
const transformed = transformAndInstantiateStructure(struct, node);
|
||||
const annotationTooltips = collectAnnotationTooltips(node, context);
|
||||
const inlineTooltips = collectInlineTooltips(node, context);
|
||||
if (annotationTooltips.length + inlineTooltips.length > 0) {
|
||||
UpdateTarget.apply(struct, CustomStructureProperties, {
|
||||
properties: {
|
||||
[MVSAnnotationTooltipsProvider.descriptor.name]: { tooltips: annotationTooltips },
|
||||
[CustomTooltipsProvider.descriptor.name]: { tooltips: inlineTooltips },
|
||||
},
|
||||
autoAttach: [
|
||||
MVSAnnotationTooltipsProvider.descriptor.name,
|
||||
CustomTooltipsProvider.descriptor.name,
|
||||
],
|
||||
});
|
||||
}
|
||||
UpdateTarget.apply(struct, CustomStructureProperties, {
|
||||
properties: {
|
||||
[MVSAnnotationTooltipsProvider.descriptor.name]: { tooltips: annotationTooltips },
|
||||
[CustomTooltipsProvider.descriptor.name]: { tooltips: inlineTooltips },
|
||||
},
|
||||
autoAttach: [
|
||||
MVSAnnotationTooltipsProvider.descriptor.name,
|
||||
CustomTooltipsProvider.descriptor.name,
|
||||
],
|
||||
}); // CustomStructureProperties must be applied even when `annotationTooltips` and `inlineTooltips` are empty, otherwise tooltips would persists across MVS snapshots
|
||||
const inlineLabels = collectInlineLabels(node, context);
|
||||
if (inlineLabels.length > 0) {
|
||||
const nearestReprNode = context.nearestReprMap?.get(node);
|
||||
@@ -426,21 +462,26 @@ const MolstarLoadingActions: LoadingActions<MolstarTree, MolstarLoadingContext>
|
||||
},
|
||||
primitives(updateParent: UpdateTarget, tree: MolstarSubtree<'primitives'>, context: MolstarLoadingContext): UpdateTarget {
|
||||
const refs = getPrimitiveStructureRefs(tree);
|
||||
const clip = clippingForNode(tree);
|
||||
const data = UpdateTarget.apply(updateParent, MVSInlinePrimitiveData, { node: tree as any });
|
||||
return applyPrimitiveVisuals(data, refs);
|
||||
UpdateTarget.setMvsDependencies(data, refs); // MVSInlinePrimitiveData must depend on `refs` because it caches positions
|
||||
return applyPrimitiveVisuals(data, refs, clip);
|
||||
},
|
||||
primitives_from_uri(updateParent: UpdateTarget, tree: MolstarNode<'primitives_from_uri'>, context: MolstarLoadingContext): UpdateTarget {
|
||||
const refs = new Set(tree.params.references);
|
||||
const clip = clippingForNode(tree);
|
||||
const data = UpdateTarget.apply(updateParent, MVSDownloadPrimitiveData, { uri: tree.params.uri, format: tree.params.format });
|
||||
return applyPrimitiveVisuals(data, new Set(tree.params.references));
|
||||
UpdateTarget.setMvsDependencies(data, refs); // MVSInlinePrimitiveData must depend on `refs` because it caches positions
|
||||
return applyPrimitiveVisuals(data, refs, clip);
|
||||
},
|
||||
};
|
||||
|
||||
function applyPrimitiveVisuals(data: UpdateTarget, refs: Set<string>) {
|
||||
const mesh = UpdateTarget.setMvsDependencies(UpdateTarget.apply(data, MVSBuildPrimitiveShape, { kind: 'mesh' }, { state: { isGhost: true } }), refs);
|
||||
function applyPrimitiveVisuals(data: UpdateTarget, refs: Set<string>, clip: Clip.Props | undefined) {
|
||||
const mesh = UpdateTarget.setMvsDependencies(UpdateTarget.apply(data, MVSBuildPrimitiveShape, { kind: 'mesh', clip }, { state: { isGhost: true } }), refs);
|
||||
UpdateTarget.apply(mesh, MVSShapeRepresentation3D);
|
||||
const labels = UpdateTarget.setMvsDependencies(UpdateTarget.apply(data, MVSBuildPrimitiveShape, { kind: 'labels' }, { state: { isGhost: true } }), refs);
|
||||
const labels = UpdateTarget.setMvsDependencies(UpdateTarget.apply(data, MVSBuildPrimitiveShape, { kind: 'labels', clip }, { state: { isGhost: true } }), refs);
|
||||
UpdateTarget.apply(labels, MVSShapeRepresentation3D);
|
||||
const lines = UpdateTarget.setMvsDependencies(UpdateTarget.apply(data, MVSBuildPrimitiveShape, { kind: 'lines' }, { state: { isGhost: true } }), refs);
|
||||
const lines = UpdateTarget.setMvsDependencies(UpdateTarget.apply(data, MVSBuildPrimitiveShape, { kind: 'lines', clip }, { state: { isGhost: true } }), refs);
|
||||
UpdateTarget.apply(lines, MVSShapeRepresentation3D);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,15 @@ import { SimpleParamsSchema, UnionParamsSchema } from '../generic/params-schema'
|
||||
import { NodeFor, ParamsOfKind, SubtreeOfKind, TreeFor, TreeSchema } from '../generic/tree-schema';
|
||||
import { ColorT, ContinuousPalette, DiscretePalette, Matrix, Vector3 } from '../mvs/param-types';
|
||||
|
||||
const Easing = literal(
|
||||
type Easing =
|
||||
| 'linear'
|
||||
| 'bounce-in' | 'bounce-out' | 'bounce-in-out'
|
||||
| 'circle-in' | 'circle-out' | 'circle-in-out'
|
||||
| 'cubic-in' | 'cubic-out' | 'cubic-in-out'
|
||||
| 'exp-in' | 'exp-out' | 'exp-in-out'
|
||||
| 'quad-in' | 'quad-out' | 'quad-in-out'
|
||||
| 'sin-in' | 'sin-out' | 'sin-in-out'
|
||||
const Easing = literal<Easing>(
|
||||
'linear',
|
||||
'bounce-in', 'bounce-out', 'bounce-in-out',
|
||||
'circle-in', 'circle-out', 'circle-in-out',
|
||||
@@ -22,23 +30,31 @@ const Easing = literal(
|
||||
export type MVSAnimationEasing = ValueFor<typeof Easing>;
|
||||
|
||||
const _Noise = {
|
||||
/** Magnitude of the noise to apply to the interpolated value. */
|
||||
noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the interpolated value.')
|
||||
// support cummulative noise?
|
||||
};
|
||||
|
||||
const _Common = {
|
||||
/** Reference to the node. */
|
||||
target_ref: RequiredField(str, 'Reference to the node.'),
|
||||
/** Value accessor. */
|
||||
property: RequiredField(union(str, list(union(str, int))), 'Value accessor.'),
|
||||
/** Start time of the transition in milliseconds. */
|
||||
start_ms: OptionalField(float, 0, 'Start time of the transition in milliseconds.'),
|
||||
/** Duration of the transition in milliseconds. */
|
||||
duration_ms: RequiredField(float, 'Duration of the transition in milliseconds.'),
|
||||
};
|
||||
|
||||
const _Frequency = {
|
||||
/** Determines how many times the interpolation loops. Current T = frequency * t mod 1. */
|
||||
frequency: OptionalField(int, 1, 'Determines how many times the interpolation loops. Current T = frequency * t mod 1.'),
|
||||
/** Whether to alternate the direction of the interpolation for frequency > 1. */
|
||||
alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
|
||||
};
|
||||
|
||||
const _Easing = {
|
||||
/** Easing function to use for the transition. */
|
||||
easing: OptionalField(Easing, 'linear', 'Easing function to use for the transition.'),
|
||||
};
|
||||
|
||||
@@ -46,8 +62,11 @@ const ScalarInterpolation = {
|
||||
..._Common,
|
||||
..._Frequency,
|
||||
..._Easing,
|
||||
/** Start value. If a list of values is provided, each element will be interpolated separately. If unset, parent state value is used. */
|
||||
start: OptionalField(nullable(union(float, list(float))), null, 'Start value. If a list of values is provided, each element will be interpolated separately. If unset, parent state value is used.'),
|
||||
/** End value. If a list of values is provided, each element will be interpolated separately. If unset, only noise is applied. */
|
||||
end: OptionalField(nullable(union(float, list(float))), null, 'End value. If a list of values is provided, each element will be interpolated separately. If unset, only noise is applied.'),
|
||||
/** Whether to round the values to the closest integer. Useful for example for trajectory animation. */
|
||||
discrete: OptionalField(bool, false, 'Whether to round the values to the closest integer. Useful for example for trajectory animation.'),
|
||||
..._Noise,
|
||||
};
|
||||
@@ -56,8 +75,11 @@ const Vec3Interpolation = {
|
||||
..._Common,
|
||||
..._Frequency,
|
||||
..._Easing,
|
||||
/** Start value. If unset, parent state value is used. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...). */
|
||||
start: OptionalField(nullable(list(float)), null, 'Start value. If unset, parent state value is used. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...).'),
|
||||
/** End value. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...). If unset, only noise is applied. */
|
||||
end: OptionalField(nullable(list(float)), null, 'End value. Must be array of length 3N (x1, y1, z1, x2, y2, z2, ...). If unset, only noise is applied.'),
|
||||
/** Whether to use spherical interpolation. */
|
||||
spherical: OptionalField(bool, false, 'Whether to use spherical interpolation.'),
|
||||
..._Noise,
|
||||
};
|
||||
@@ -66,7 +88,9 @@ const RotationMatrixInterpolation = {
|
||||
..._Common,
|
||||
..._Frequency,
|
||||
..._Easing,
|
||||
/** Start value. If unset, parent state value is used. */
|
||||
start: OptionalField(nullable(Matrix), null, 'Start value. If unset, parent state value is used.'),
|
||||
/** End value. If unset, only noise is applied. */
|
||||
end: OptionalField(nullable(Matrix), null, 'End value. If unset, only noise is applied.'),
|
||||
..._Noise,
|
||||
};
|
||||
@@ -75,31 +99,53 @@ const ColorInterpolation = {
|
||||
..._Common,
|
||||
..._Frequency,
|
||||
..._Easing,
|
||||
/** Start value. If unset, parent state value is used. */
|
||||
start: OptionalField(union(nullable(ColorT), dict(union(int, str), ColorT)), null, 'Start value. If unset, parent state value is used.'),
|
||||
/** End value. */
|
||||
end: OptionalField(union(nullable(ColorT), dict(union(int, str), ColorT)), null, 'End value.'),
|
||||
/** Palette to sample colors from. Overrides start and end values. */
|
||||
palette: OptionalField(nullable(union(DiscretePalette, ContinuousPalette)), null, 'Palette to sample colors from. Overrides start and end values.'),
|
||||
};
|
||||
|
||||
const TransformationMatrixInterpolation = {
|
||||
..._Common,
|
||||
/** Pivot point for rotation and scale. */
|
||||
pivot: OptionalField(nullable(Vector3), null, 'Pivot point for rotation and scale.'),
|
||||
/** Start rotation value. If unset, parent state value is used. */
|
||||
rotation_start: OptionalField(nullable(Matrix), null, 'Start rotation value. If unset, parent state value is used.'),
|
||||
/** End rotation value. If unset, only noise is applied */
|
||||
rotation_end: OptionalField(nullable(Matrix), null, 'End rotation value. If unset, only noise is applied.'),
|
||||
/** Magnitude of the noise to apply to the rotation. */
|
||||
rotation_noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the rotation.'),
|
||||
/** Easing function to use for the rotation. */
|
||||
rotation_easing: OptionalField(Easing, 'linear', 'Easing function to use for the rotation.'),
|
||||
/** Determines how many times the rotation interpolation loops. Current T = frequency * t mod 1. */
|
||||
rotation_frequency: OptionalField(int, 1, 'Determines how many times the rotation interpolation loops. Current T = frequency * t mod 1.'),
|
||||
/** Whether to alternate the direction of the interpolation for frequency > 1. */
|
||||
rotation_alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
|
||||
/** Start translation value. If unset, parent state value is used. */
|
||||
translation_start: OptionalField(nullable(Vector3), null, 'Start translation value. If unset, parent state value is used.'),
|
||||
/** End translation value. If unset, only noise is applied. */
|
||||
translation_end: OptionalField(nullable(Vector3), null, 'End translation value. If unset, only noise is applied.'),
|
||||
/** Magnitude of the noise to apply to the translation. */
|
||||
translation_noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the translation.'),
|
||||
/** Easing function to use for the translation. */
|
||||
translation_easing: OptionalField(Easing, 'linear', 'Easing function to use for the translation.'),
|
||||
/** Determines how many times the translation interpolation loops. Current T = frequency * t mod 1. */
|
||||
translation_frequency: OptionalField(int, 1, 'Determines how many times the translation interpolation loops. Current T = frequency * t mod 1.'),
|
||||
/** Whether to alternate the direction of the interpolation for frequency > 1. */
|
||||
translation_alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
|
||||
/** Start scale value. If unset, parent state value is used. */
|
||||
scale_start: OptionalField(nullable(Vector3), null, 'Start scale value. If unset, parent state value is used.'),
|
||||
/** End scale value. If unset, only noise is applied. */
|
||||
scale_end: OptionalField(nullable(Vector3), null, 'End scale value. If unset, only noise is applied.'),
|
||||
/** Magnitude of the noise to apply to the scale. */
|
||||
scale_noise_magnitude: OptionalField(float, 0, 'Magnitude of the noise to apply to the scale.'),
|
||||
/** Easing function to use for the scale. */
|
||||
scale_easing: OptionalField(Easing, 'linear', 'Easing function to use for the scale.'),
|
||||
/** Determines how many times the scale interpolation loops. Current T = frequency * t mod 1. */
|
||||
scale_frequency: OptionalField(int, 1, 'Determines how many times the scale interpolation loops. Current T = frequency * t mod 1.'),
|
||||
/** Whether to alternate the direction of the interpolation for frequency > 1. */
|
||||
scale_alternate_direction: OptionalField(bool, false, 'Whether to alternate the direction of the interpolation for frequency > 1.'),
|
||||
};
|
||||
|
||||
@@ -110,12 +156,18 @@ export const MVSAnimationSchema = TreeSchema({
|
||||
description: 'Animation root node',
|
||||
parent: [],
|
||||
params: SimpleParamsSchema({
|
||||
frame_time_ms: OptionalField(float, 1000 / 60, 'Frame time in milliseconds'),
|
||||
/** Frame time in milliseconds. */
|
||||
frame_time_ms: OptionalField(float, 1000 / 60, 'Frame time in milliseconds.'),
|
||||
/** Total duration of the animation. If not specified, computed as maximum of all transitions. */
|
||||
duration_ms: OptionalField(nullable(float), null, 'Total duration of the animation. If not specified, computed as maximum of all transitions.'),
|
||||
autoplay: OptionalField(bool, true, 'Determines whether the animation should autoplay when a snapshot is loaded'),
|
||||
loop: OptionalField(bool, false, 'Determines whether the animation should loop when it reaches the end'),
|
||||
include_camera: OptionalField(bool, false, 'Determines whether the camera state should be included in the animation'),
|
||||
include_canvas: OptionalField(bool, false, 'Determines whether the canvas state should be included in the animation'),
|
||||
/** Determines whether the animation should autoplay when a snapshot is loaded */
|
||||
autoplay: OptionalField(bool, true, 'Determines whether the animation should autoplay when a snapshot is loaded.'),
|
||||
/** Determines whether the animation should loop when it reaches the end. */
|
||||
loop: OptionalField(bool, false, 'Determines whether the animation should loop when it reaches the end.'),
|
||||
/** Determines whether the camera state should be included in the animation. */
|
||||
include_camera: OptionalField(bool, false, 'Determines whether the camera state should be included in the animation.'),
|
||||
/** Determines whether the canvas state should be included in the animation. */
|
||||
include_canvas: OptionalField(bool, false, 'Determines whether the canvas state should be included in the animation.'),
|
||||
}),
|
||||
},
|
||||
interpolate: {
|
||||
|
||||
@@ -78,7 +78,16 @@ export function nullable<V>(type: iots.Type<V>): iots.Type<V | null> {
|
||||
return union(type, iots.null);
|
||||
}
|
||||
|
||||
/** Type definition for literal types, e.g. `literal('red', 'green', 'blue')` means 'red' or 'green' or 'blue' */
|
||||
/** Type definition for literal types, e.g. `literal('red', 'green', 'blue')` means 'red' or 'green' or 'blue'.
|
||||
*
|
||||
* Example usage:
|
||||
* ```
|
||||
* export type MyColor = 'red' | 'green' | 'blue';
|
||||
* export const MyColor = literal<MyColor>('red', 'green', 'blue');
|
||||
* ```
|
||||
*
|
||||
* (it looks stupid to repeat the list of values but it will result in nicer type bundle (for MolViewStories))
|
||||
*/
|
||||
export function literal<V extends string | number | boolean>(...values: V[]) {
|
||||
if (values.length === 0) {
|
||||
throw new Error(`literal type must have at least one value`);
|
||||
|
||||
@@ -28,12 +28,22 @@ export const ParseFormatMvsToMolstar = {
|
||||
lammpstrj: { format: 'lammpstrj', is_binary: false },
|
||||
// coordinates
|
||||
xtc: { format: 'xtc', is_binary: true },
|
||||
nctraj: { format: 'nctraj', is_binary: true },
|
||||
dcd: { format: 'dcd', is_binary: true },
|
||||
trr: { format: 'trr', is_binary: true },
|
||||
// topology
|
||||
psf: { format: 'psf', is_binary: false },
|
||||
prmtop: { format: 'prmtop', is_binary: false },
|
||||
top: { format: 'top', is_binary: false },
|
||||
// maps
|
||||
map: { format: 'map', is_binary: true },
|
||||
dx: { format: 'dx', is_binary: false },
|
||||
dxbin: { format: 'dxbin', is_binary: true },
|
||||
} satisfies { [p in ParseFormatT]: { format: MolstarParseFormatT, is_binary: boolean } };
|
||||
|
||||
|
||||
const TopologyFormats = new Set<ParseFormatT>(['psf', 'prmtop', 'top']);
|
||||
|
||||
/** Conversion rules for conversion from `MVSTree` (with all parameter values) to `MolstarTree` */
|
||||
const mvsToMolstarConversionRules: ConversionRules<FullMVSTree, MolstarTree> = {
|
||||
'download': node => ({ subtree: [] }),
|
||||
@@ -68,7 +78,18 @@ const mvsToMolstarConversionRules: ConversionRules<FullMVSTree, MolstarTree> = {
|
||||
if (parent?.kind !== 'parse') throw new Error(`Parent of "structure" must be "parse", not "${parent?.kind}".`);
|
||||
const { format } = ParseFormatMvsToMolstar[parent.params.format];
|
||||
|
||||
if (node.params.coordinates_ref) {
|
||||
if (TopologyFormats.has(parent.params.format)) {
|
||||
if (!node.params.coordinates_ref) {
|
||||
throw new Error(`"structure" node with topology format "${parent.params.format}" must have "coordinates_ref" parameter.`);
|
||||
}
|
||||
return {
|
||||
subtree: [
|
||||
{ kind: 'topology_with_coordinates', params: { format, coordinates_ref: node.params.coordinates_ref } },
|
||||
{ kind: 'model', params: pickObjectKeys(node.params, ['model_index']) },
|
||||
{ kind: 'structure', params: omitObjectKeys(node.params, ['block_header', 'block_index', 'model_index', 'coordinates_ref']), custom: node.custom, ref: node.ref },
|
||||
] satisfies MolstarNode[]
|
||||
};
|
||||
} else if (node.params.coordinates_ref) {
|
||||
return {
|
||||
subtree: [
|
||||
{ kind: 'trajectory', params: { format, ...pickObjectKeys(node.params, ['block_header', 'block_index']) } },
|
||||
@@ -124,6 +145,13 @@ const StructureFormatExtensions: Record<ParseFormatT, (FileExtension | '*')[]> =
|
||||
lammpstrj: ['.lammpstrj'],
|
||||
// coordinates
|
||||
xtc: ['.xtc'],
|
||||
nctraj: ['.nc', '.nctraj'],
|
||||
dcd: ['.dcd'],
|
||||
trr: ['.trr'],
|
||||
// topology
|
||||
psf: ['.psf'],
|
||||
prmtop: ['.prmtop', '.parm7'],
|
||||
top: ['.top'],
|
||||
// volumes
|
||||
map: ['.map', '.ccp4', '.mrc', '.mrcs'],
|
||||
dx: ['.dx'],
|
||||
|
||||
@@ -21,12 +21,14 @@ export const MolstarTreeSchema = TreeSchema({
|
||||
...FullMVSTreeSchema.nodes.download,
|
||||
params: SimpleParamsSchema({
|
||||
...FullMVSTreeSchema.nodes.download.params.fields,
|
||||
/** Specifies whether file is downloaded as bytes array or string */
|
||||
is_binary: RequiredField(bool, 'Specifies whether file is downloaded as bytes array or string'),
|
||||
}),
|
||||
},
|
||||
parse: {
|
||||
...FullMVSTreeSchema.nodes.parse,
|
||||
params: SimpleParamsSchema({
|
||||
/** File format */
|
||||
format: RequiredField(MolstarParseFormatT, 'File format'),
|
||||
}),
|
||||
},
|
||||
@@ -35,6 +37,7 @@ export const MolstarTreeSchema = TreeSchema({
|
||||
description: "Auxiliary node corresponding to Molstar's CoordinatesFrom*.",
|
||||
parent: ['parse'],
|
||||
params: SimpleParamsSchema({
|
||||
/** File format */
|
||||
format: RequiredField(MolstarParseFormatT, 'File format'),
|
||||
}),
|
||||
},
|
||||
@@ -43,6 +46,7 @@ export const MolstarTreeSchema = TreeSchema({
|
||||
description: "Auxiliary node corresponding to Molstar's TrajectoryFrom*.",
|
||||
parent: ['parse'],
|
||||
params: SimpleParamsSchema({
|
||||
/** File format */
|
||||
format: RequiredField(MolstarParseFormatT, 'File format'),
|
||||
...pickObjectKeys(FullMVSTreeSchema.nodes.structure.params.fields, ['block_header', 'block_index'] as const),
|
||||
}),
|
||||
@@ -52,13 +56,22 @@ export const MolstarTreeSchema = TreeSchema({
|
||||
description: 'Auxiliary node corresponding to assigning a separate coordinates to a trajectory.',
|
||||
parent: ['model'],
|
||||
params: SimpleParamsSchema({
|
||||
/** Coordinates reference */
|
||||
coordinates_ref: RequiredField(str, 'Coordinates reference'),
|
||||
}),
|
||||
},
|
||||
topology_with_coordinates: {
|
||||
description: 'Auxiliary node corresponding to assigning a separate coordinates to a topology.',
|
||||
parent: ['parse'],
|
||||
params: SimpleParamsSchema({
|
||||
format: RequiredField(MolstarParseFormatT, 'File format'),
|
||||
coordinates_ref: RequiredField(str, 'Coordinates reference'),
|
||||
}),
|
||||
},
|
||||
/** Auxiliary node corresponding to Molstar's ModelFromTrajectory. */
|
||||
model: {
|
||||
description: "Auxiliary node corresponding to Molstar's ModelFromTrajectory.",
|
||||
parent: ['trajectory', 'trajectory_with_coordinates'],
|
||||
parent: ['trajectory', 'trajectory_with_coordinates', 'topology_with_coordinates'],
|
||||
params: SimpleParamsSchema(
|
||||
pickObjectKeys(FullMVSTreeSchema.nodes.structure.params.fields, ['model_index'] as const)
|
||||
),
|
||||
|
||||
@@ -403,12 +403,24 @@ export class Primitives extends _Base<'primitives'> implements FocusMixin {
|
||||
return this;
|
||||
}
|
||||
focus = bindMethod(this, FocusMixinImpl, 'focus');
|
||||
|
||||
/** Add a 'clip' node and return builder pointing back to the representation node. 'clip' node instructs to apply clipping to a visual representation. */
|
||||
clip(params: MVSNodeParams<'clip'> & CustomAndRef): Primitives {
|
||||
this.addChild('clip', params);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** MVS builder pointing to a 'primitives_from_uri' node */
|
||||
class PrimitivesFromUri extends _Base<'primitives_from_uri'> implements FocusMixin {
|
||||
focus = bindMethod(this, FocusMixinImpl, 'focus');
|
||||
|
||||
/** Add a 'clip' node and return builder pointing back to the representation node. 'clip' node instructs to apply clipping to a visual representation. */
|
||||
clip(params: MVSNodeParams<'clip'> & CustomAndRef): PrimitivesFromUri {
|
||||
this.addChild('clip', params);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
import { bool, dict, float, int, list, literal, nullable, OptionalField, RequiredField, str, tuple, union } from '../generic/field-schema';
|
||||
import { SimpleParamsSchema } from '../generic/params-schema';
|
||||
import { NodeFor, ParamsOfKind, SubtreeOfKind, TreeFor, TreeSchema, TreeSchemaWithAllRequired } from '../generic/tree-schema';
|
||||
import { MVSClipParams, MVSRepresentationParams, MVSVolumeRepresentationParams } from './mvs-tree-representations';
|
||||
import { MVSPrimitiveParams } from './mvs-tree-primitives';
|
||||
import { ColorT, ComponentExpressionT, ComponentSelectorT, Matrix, Palette, ParseFormatT, SchemaFormatT, SchemaT, StrList, StructureTypeT, Vector3 } from './param-types';
|
||||
import { MVSClipParams, MVSRepresentationParams, MVSVolumeRepresentationParams } from './mvs-tree-representations';
|
||||
import { ColorT, ComponentExpressionT, ComponentSelectorT, LabelAttachments, Matrix, Palette, ParseFormatT, SchemaFormatT, SchemaT, StrList, StructureTypeT, Vector3 } from './param-types';
|
||||
|
||||
|
||||
const _DataFromUriParams = {
|
||||
@@ -50,8 +50,6 @@ const _DataFromSourceParams = {
|
||||
/** Color to be used e.g. for representations without 'color' node */
|
||||
export const DefaultColor = 'white';
|
||||
|
||||
const LabelAttachments = literal('bottom-left', 'bottom-center', 'bottom-right', 'middle-left', 'middle-center', 'middle-right', 'top-left', 'top-center', 'top-right');
|
||||
|
||||
const TransformParams = SimpleParamsSchema({
|
||||
/** Rotation matrix (3x3 matrix flattened in column major format (j*3+i indexing), this is equivalent to Fortran-order in numpy). This matrix will multiply the structure coordinates from the left. The default value is the identity matrix (corresponds to no rotation). */
|
||||
rotation: OptionalField(Matrix, [1, 0, 0, 0, 1, 0, 0, 0, 1], 'Rotation matrix (3x3 matrix flattened in column major format (j*3+i indexing), this is equivalent to Fortran-order in numpy). This matrix will multiply the structure coordinates from the left. The default value is the identity matrix (corresponds to no rotation).'),
|
||||
@@ -179,6 +177,7 @@ export const MVSTreeSchema = TreeSchema({
|
||||
description: 'This node instructs to create a volume from a parsed data resource. "Volume" refers to an internal representation of volumetric data without any visual representation.',
|
||||
parent: ['parse'],
|
||||
params: SimpleParamsSchema({
|
||||
/** Channel identifier (only applies when the input data contain multiple channels). */
|
||||
channel_id: OptionalField(nullable(str), null, 'Channel identifier (only applies when the input data contain multiple channels).'),
|
||||
}),
|
||||
},
|
||||
@@ -226,7 +225,7 @@ export const MVSTreeSchema = TreeSchema({
|
||||
/** This node instructs to apply clipping to a visual representation. */
|
||||
clip: {
|
||||
description: 'This node instructs to apply clipping to a visual representation.',
|
||||
parent: ['representation', 'volume_representation'],
|
||||
parent: ['representation', 'volume_representation', 'primitives', 'primitives_from_uri'],
|
||||
params: MVSClipParams,
|
||||
},
|
||||
/** This node instructs to apply opacity/transparency to a visual representation. */
|
||||
@@ -324,6 +323,8 @@ export const MVSTreeSchema = TreeSchema({
|
||||
position: RequiredField(Vector3, 'Coordinates of the camera.'),
|
||||
/** Vector which will be aligned with the screen Y axis. */
|
||||
up: OptionalField(Vector3, [0, 1, 0], 'Vector which will be aligned with the screen Y axis.'),
|
||||
/** Near clipping plane distance from the position. */
|
||||
near: OptionalField(nullable(float), null, 'Near clipping plane distance from the position.'),
|
||||
}),
|
||||
},
|
||||
/** This node sets canvas properties. */
|
||||
|
||||
@@ -6,12 +6,20 @@
|
||||
*/
|
||||
|
||||
import * as iots from 'io-ts';
|
||||
import { ColorName, HexColor } from '../../helpers/utils';
|
||||
import { ColorNames } from '../../../../mol-util/color/names';
|
||||
import { ValueFor, bool, dict, float, int, list, literal, nullable, object, partial, str, tuple, union } from '../generic/field-schema';
|
||||
|
||||
|
||||
/** `format` parameter values for `parse` node in MVS tree */
|
||||
export const ParseFormatT = literal(
|
||||
export type ParseFormatT =
|
||||
// trajectory
|
||||
| 'mmcif' | 'bcif' | 'pdb' | 'pdbqt' | 'gro' | 'xyz' | 'mol' | 'sdf' | 'mol2' | 'lammpstrj'
|
||||
// coordinates
|
||||
| 'xtc' | 'nctraj' | 'dcd' | 'trr'
|
||||
// topology
|
||||
| 'psf' | 'prmtop' | 'top'
|
||||
// volumes
|
||||
| 'map' | 'dx' | 'dxbin'
|
||||
export const ParseFormatT = literal<ParseFormatT>(
|
||||
// trajectory
|
||||
'mmcif',
|
||||
'bcif', // +volumes
|
||||
@@ -25,15 +33,30 @@ export const ParseFormatT = literal(
|
||||
'lammpstrj', // + coordinates
|
||||
// coordinates
|
||||
'xtc',
|
||||
'nctraj',
|
||||
'dcd',
|
||||
'trr',
|
||||
// topology
|
||||
'psf',
|
||||
'prmtop',
|
||||
'top',
|
||||
// volumes
|
||||
'map',
|
||||
'dx',
|
||||
'dxbin',
|
||||
);
|
||||
export type ParseFormatT = ValueFor<typeof ParseFormatT>
|
||||
|
||||
/** `format` parameter values for `parse` node in Molstar tree */
|
||||
export const MolstarParseFormatT = literal(
|
||||
export type MolstarParseFormatT =
|
||||
// trajectory
|
||||
| 'cif' | 'pdb' | 'pdbqt' | 'gro' | 'xyz' | 'mol' | 'sdf' | 'mol2' | 'lammpstrj'
|
||||
// coordinates
|
||||
| 'xtc' | 'nctraj' | 'dcd' | 'trr'
|
||||
// topology
|
||||
| 'psf' | 'prmtop' | 'top'
|
||||
// volumes
|
||||
| 'map' | 'dx' | 'dxbin'
|
||||
export const MolstarParseFormatT = literal<MolstarParseFormatT>(
|
||||
// trajectory
|
||||
'cif', // +volumes
|
||||
'pdb',
|
||||
@@ -46,21 +69,29 @@ export const MolstarParseFormatT = literal(
|
||||
'lammpstrj',
|
||||
// coordinates
|
||||
'xtc',
|
||||
'nctraj',
|
||||
'dcd',
|
||||
'trr',
|
||||
// topology
|
||||
'psf',
|
||||
'prmtop',
|
||||
'top',
|
||||
// volumes
|
||||
'map',
|
||||
'dx',
|
||||
'dxbin',
|
||||
);
|
||||
export type MolstarParseFormatT = ValueFor<typeof MolstarParseFormatT>
|
||||
|
||||
/** `kind` parameter values for `structure` node in MVS tree */
|
||||
export const StructureTypeT = literal('model', 'assembly', 'symmetry', 'symmetry_mates');
|
||||
export type StructureTypeT = 'model' | 'assembly' | 'symmetry' | 'symmetry_mates';
|
||||
export const StructureTypeT = literal<StructureTypeT>('model', 'assembly', 'symmetry', 'symmetry_mates');
|
||||
|
||||
/** `selector` parameter values for `component` node in MVS tree */
|
||||
export const ComponentSelectorT = literal('all', 'polymer', 'protein', 'nucleic', 'branched', 'ligand', 'ion', 'water', 'coarse');
|
||||
export type ComponentSelectorT = 'all' | 'polymer' | 'protein' | 'nucleic' | 'branched' | 'ligand' | 'ion' | 'water' | 'coarse';
|
||||
export const ComponentSelectorT = literal<ComponentSelectorT>('all', 'polymer', 'protein', 'nucleic', 'branched', 'ligand', 'ion', 'water', 'coarse');
|
||||
|
||||
/** `selector` parameter values for `component` node in MVS tree */
|
||||
export const ComponentExpressionT = partial({
|
||||
const _ComponentExpressionT = partial({
|
||||
label_entity_id: str,
|
||||
label_asym_id: str,
|
||||
auth_asym_id: str,
|
||||
@@ -84,24 +115,39 @@ export const ComponentExpressionT = partial({
|
||||
* like 'ASM-X0-1' for assemblies or '1_555' for crystals */
|
||||
instance_id: str,
|
||||
});
|
||||
export type ComponentExpressionT = ValueFor<typeof ComponentExpressionT>
|
||||
/** `selector` parameter values for `component` node in MVS tree */
|
||||
export interface ComponentExpressionT extends ValueFor<typeof _ComponentExpressionT> { }
|
||||
export const ComponentExpressionT: iots.Type<ComponentExpressionT> = _ComponentExpressionT;
|
||||
|
||||
|
||||
/** `schema` parameter values for `*_from_uri` and `*_from_source` nodes in MVS tree */
|
||||
export const SchemaT = literal('whole_structure', 'entity', 'chain', 'auth_chain', 'residue', 'auth_residue', 'residue_range', 'auth_residue_range', 'atom', 'auth_atom', 'all_atomic');
|
||||
export type SchemaT = 'whole_structure' | 'entity' | 'chain' | 'auth_chain' | 'residue' | 'auth_residue' | 'residue_range' | 'auth_residue_range' | 'atom' | 'auth_atom' | 'all_atomic';
|
||||
export const SchemaT = literal<SchemaT>('whole_structure', 'entity', 'chain', 'auth_chain', 'residue', 'auth_residue', 'residue_range', 'auth_residue_range', 'atom', 'auth_atom', 'all_atomic');
|
||||
|
||||
/** `format` parameter values for `*_from_uri` nodes in MVS tree */
|
||||
export const SchemaFormatT = literal('cif', 'bcif', 'json');
|
||||
export type SchemaFormatT = 'cif' | 'bcif' | 'json';
|
||||
export const SchemaFormatT = literal<SchemaFormatT>('cif', 'bcif', 'json');
|
||||
|
||||
/** Parameter values for vector params, e.g. `position` */
|
||||
export const Vector3 = tuple([float, float, float]);
|
||||
export type Vector3 = ValueFor<typeof Vector3>
|
||||
export type Vector3 = [number, number, number];
|
||||
export const Vector3: iots.Type<Vector3> = tuple([float, float, float]);
|
||||
|
||||
/** Parameter values for matrix params, e.g. `rotation` */
|
||||
export const Matrix = list(float);
|
||||
export const Matrix = list(float); // TODO impl custom types Matrix3x3 and Matrix4x4
|
||||
|
||||
export type LabelAttachments = 'bottom-left' | 'bottom-center' | 'bottom-right' | 'middle-left' | 'middle-center' | 'middle-right' | 'top-left' | 'top-center' | 'top-right';
|
||||
export const LabelAttachments = literal<LabelAttachments>('bottom-left', 'bottom-center', 'bottom-right', 'middle-left', 'middle-center', 'middle-right', 'top-left', 'top-center', 'top-right');
|
||||
|
||||
/** Primitives-related types */
|
||||
export const PrimitiveComponentExpressionT = partial({ structure_ref: str, expression_schema: SchemaT, expressions: list(ComponentExpressionT) });
|
||||
export type PrimitiveComponentExpressionT = ValueFor<typeof PrimitiveComponentExpressionT>
|
||||
const _PrimitiveComponentExpressionT = partial({
|
||||
structure_ref: str,
|
||||
expression_schema: SchemaT,
|
||||
expressions: list(ComponentExpressionT),
|
||||
});
|
||||
/** Primitives-related types */
|
||||
export interface PrimitiveComponentExpressionT extends ValueFor<typeof _PrimitiveComponentExpressionT> { }
|
||||
export const PrimitiveComponentExpressionT: iots.Type<PrimitiveComponentExpressionT> = _PrimitiveComponentExpressionT;
|
||||
|
||||
export const PrimitivePositionT = union(Vector3, ComponentExpressionT, PrimitiveComponentExpressionT);
|
||||
export type PrimitivePositionT = ValueFor<typeof PrimitivePositionT>
|
||||
|
||||
@@ -110,27 +156,61 @@ export const IntList = list(int);
|
||||
export const StrList = list(str);
|
||||
|
||||
|
||||
/** `color` parameter values for `color` node in MVS tree */
|
||||
export const HexColorT = new iots.Type<HexColor>(
|
||||
/** Hexadecimal color string, e.g. '#FF1100' (the type matches more than just valid HexColor strings) */
|
||||
export type HexColorT = `#${string}`;
|
||||
export const HexColorT = new iots.Type<HexColorT>(
|
||||
'HexColor',
|
||||
((value: any) => typeof value === 'string') as any,
|
||||
(value, ctx) => HexColor.is(value) ? { _tag: 'Right', right: value } : { _tag: 'Left', left: [{ value: value, context: ctx, message: `"${value}" is not a valid hex color string` }] },
|
||||
(value, ctx) => isHexColorT(value) ? { _tag: 'Right', right: value } : { _tag: 'Left', left: [{ value: value, context: ctx, message: `"${value}" is not a valid hex color string` }] },
|
||||
value => value
|
||||
);
|
||||
/** Regular expression matching a hexadecimal color string, e.g. '#FF1100' or '#f10' */
|
||||
const hexColorRegex = /^#([0-9A-F]{3}){1,2}$/i;
|
||||
/** Decide if a string is a valid hexadecimal color string (6-digit or 3-digit, e.g. '#FF1100' or '#f10') */
|
||||
function isHexColorT(str: any): str is HexColorT {
|
||||
return typeof str === 'string' && hexColorRegex.test(str);
|
||||
}
|
||||
|
||||
/** `color` parameter values for `color` node in MVS tree */
|
||||
export const ColorNameT = new iots.Type<ColorName>(
|
||||
/** Named color string (e.g. 'red') for `color` parameter values for `color` node in MVS tree */
|
||||
export const ColorNameT = new iots.Type<ColorNameT>(
|
||||
'ColorName',
|
||||
((value: any) => typeof value === 'string') as any,
|
||||
(value, ctx) => ColorName.is(value) ? { _tag: 'Right', right: value } : { _tag: 'Left', left: [{ value: value, context: ctx, message: `"${value}" is not a valid color name` }] },
|
||||
(value, ctx) => isColorNameT(value) ? { _tag: 'Right', right: value } : { _tag: 'Left', left: [{ value: value, context: ctx, message: `"${value}" is not a valid color name` }] },
|
||||
value => value
|
||||
);
|
||||
export type ColorNameT =
|
||||
| 'aliceblue' | 'antiquewhite' | 'aqua' | 'aquamarine' | 'azure' | 'beige' | 'bisque' | 'black'
|
||||
| 'blanchedalmond' | 'blue' | 'blueviolet' | 'brown' | 'burlywood' | 'cadetblue' | 'chartreuse'
|
||||
| 'chocolate' | 'coral' | 'cornflower' | 'cornflowerblue' | 'cornsilk' | 'crimson' | 'cyan' | 'darkblue'
|
||||
| 'darkcyan' | 'darkgoldenrod' | 'darkgray' | 'darkgreen' | 'darkgrey' | 'darkkhaki' | 'darkmagenta'
|
||||
| 'darkolivegreen' | 'darkorange' | 'darkorchid' | 'darkred' | 'darksalmon' | 'darkseagreen' | 'darkslateblue'
|
||||
| 'darkslategray' | 'darkslategrey' | 'darkturquoise' | 'darkviolet' | 'deeppink' | 'deepskyblue' | 'dimgray'
|
||||
| 'dimgrey' | 'dodgerblue' | 'firebrick' | 'floralwhite' | 'forestgreen' | 'fuchsia' | 'gainsboro'
|
||||
| 'ghostwhite' | 'gold' | 'goldenrod' | 'gray' | 'green' | 'greenyellow' | 'grey' | 'honeydew' | 'hotpink'
|
||||
| 'indianred' | 'indigo' | 'ivory' | 'khaki' | 'laserlemon' | 'lavender' | 'lavenderblush' | 'lawngreen'
|
||||
| 'lemonchiffon' | 'lightblue' | 'lightcoral' | 'lightcyan' | 'lightgoldenrod' | 'lightgoldenrodyellow'
|
||||
| 'lightgray' | 'lightgreen' | 'lightgrey' | 'lightpink' | 'lightsalmon' | 'lightseagreen' | 'lightskyblue'
|
||||
| 'lightslategray' | 'lightslategrey' | 'lightsteelblue' | 'lightyellow' | 'lime' | 'limegreen' | 'linen'
|
||||
| 'magenta' | 'maroon' | 'maroon2' | 'maroon3' | 'mediumaquamarine' | 'mediumblue' | 'mediumorchid' | 'mediumpurple'
|
||||
| 'mediumseagreen' | 'mediumslateblue' | 'mediumspringgreen' | 'mediumturquoise' | 'mediumvioletred' | 'midnightblue'
|
||||
| 'mintcream' | 'mistyrose' | 'moccasin' | 'navajowhite' | 'navy' | 'oldlace' | 'olive' | 'olivedrab' | 'orange'
|
||||
| 'orangered' | 'orchid' | 'palegoldenrod' | 'palegreen' | 'paleturquoise' | 'palevioletred' | 'papayawhip'
|
||||
| 'peachpuff' | 'peru' | 'pink' | 'plum' | 'powderblue' | 'purple' | 'purple2' | 'purple3' | 'rebeccapurple'
|
||||
| 'red' | 'rosybrown' | 'royalblue' | 'saddlebrown' | 'salmon' | 'sandybrown' | 'seagreen' | 'seashell' | 'sienna'
|
||||
| 'silver' | 'skyblue' | 'slateblue' | 'slategray' | 'slategrey' | 'snow' | 'springgreen' | 'steelblue' | 'tan'
|
||||
| 'teal' | 'thistle' | 'tomato' | 'turquoise' | 'violet' | 'wheat' | 'white' | 'whitesmoke' | 'yellow' | 'yellowgreen'
|
||||
/** Decide if a string is a valid named color string */
|
||||
function isColorNameT(str: any): str is ColorNameT {
|
||||
return str in ColorNames;
|
||||
}
|
||||
|
||||
/** `color` parameter values for `color` node in MVS tree */
|
||||
export const ColorT = union(ColorNameT, HexColorT);
|
||||
export type ColorT = ValueFor<typeof ColorT>
|
||||
export type ColorT = ColorNameT | HexColorT;
|
||||
export const ColorT: iots.Type<ColorT> = union(ColorNameT, HexColorT);
|
||||
|
||||
|
||||
// Type helpers
|
||||
|
||||
/** Type helpers */
|
||||
export function isVector3(x: any): x is Vector3 {
|
||||
return !!x && Array.isArray(x) && x.length === 3 && typeof x[0] === 'number';
|
||||
}
|
||||
@@ -144,7 +224,23 @@ export function isComponentExpression(x: any): x is ComponentExpressionT {
|
||||
}
|
||||
|
||||
|
||||
export const ColorListNameT = literal(
|
||||
export type ColorListNameT =
|
||||
// Color lists from https://observablehq.com/@d3/color-schemes (definitions: https://colorbrewer2.org/export/colorbrewer.js)
|
||||
// Sequential single-hue
|
||||
| 'Reds' | 'Oranges' | 'Greens' | 'Blues' | 'Purples' | 'Greys'
|
||||
// Sequential multi-hue
|
||||
| 'OrRd' | 'BuGn' | 'PuBuGn' | 'GnBu' | 'PuBu' | 'BuPu' | 'RdPu' | 'PuRd' | 'YlOrRd' | 'YlOrBr' | 'YlGn' | 'YlGnBu'
|
||||
| 'Magma' | 'Inferno' | 'Plasma' | 'Viridis' | 'Cividis' | 'Turbo' | 'Warm' | 'Cool' | 'CubehelixDefault'
|
||||
// Cyclical
|
||||
| 'Rainbow' | 'Sinebow'
|
||||
// Diverging
|
||||
| 'RdBu' | 'RdGy' | 'PiYG' | 'BrBG' | 'PRGn' | 'PuOr' | 'RdYlGn' | 'RdYlBu' | 'Spectral'
|
||||
// Categorical
|
||||
| 'Category10' | 'Observable10' | 'Tableau10'
|
||||
| 'Set1' | 'Set2' | 'Set3' | 'Pastel1' | 'Pastel2' | 'Dark2' | 'Paired' | 'Accent'
|
||||
// Additional lists, not standard for visualization in general, but commonly used for structures
|
||||
| 'Chainbow'
|
||||
export const ColorListNameT = literal<ColorListNameT>(
|
||||
// Color lists from https://observablehq.com/@d3/color-schemes (definitions: https://colorbrewer2.org/export/colorbrewer.js)
|
||||
// Sequential single-hue
|
||||
'Reds', 'Oranges', 'Greens', 'Blues', 'Purples', 'Greys',
|
||||
@@ -162,13 +258,12 @@ export const ColorListNameT = literal(
|
||||
// Additional lists, not standard for visualization in general, but commonly used for structures
|
||||
'Chainbow',
|
||||
);
|
||||
export type ColorListNameT = ValueFor<typeof ColorListNameT>;
|
||||
|
||||
export const ColorDictNameT = literal('ElementSymbol', 'ResidueName', 'ResidueProperties', 'SecondaryStructure');
|
||||
export type ColorDictNameT = ValueFor<typeof ColorDictNameT>;
|
||||
export type ColorDictNameT = 'ElementSymbol' | 'ResidueName' | 'ResidueProperties' | 'SecondaryStructure';
|
||||
export const ColorDictNameT = literal<ColorDictNameT>('ElementSymbol', 'ResidueName', 'ResidueProperties', 'SecondaryStructure');
|
||||
|
||||
|
||||
export const CategoricalPalette = object(
|
||||
const _CategoricalPalette = object(
|
||||
{
|
||||
kind: literal('categorical'),
|
||||
},
|
||||
@@ -192,7 +287,8 @@ export const CategoricalPalette = object(
|
||||
missing_color: nullable(ColorT),
|
||||
}
|
||||
);
|
||||
export type CategoricalPalette = ValueFor<typeof CategoricalPalette>;
|
||||
export interface CategoricalPalette extends ValueFor<typeof _CategoricalPalette> { }
|
||||
export const CategoricalPalette: iots.Type<CategoricalPalette> = _CategoricalPalette;
|
||||
|
||||
export const CategoricalPaletteDefaults: Required<CategoricalPalette> = {
|
||||
kind: 'categorical',
|
||||
@@ -205,7 +301,7 @@ export const CategoricalPaletteDefaults: Required<CategoricalPalette> = {
|
||||
};
|
||||
|
||||
|
||||
export const DiscretePalette = object(
|
||||
const _DiscretePalette = object(
|
||||
{
|
||||
kind: literal('discrete'),
|
||||
},
|
||||
@@ -231,7 +327,8 @@ export const DiscretePalette = object(
|
||||
value_domain: tuple([nullable(float), nullable(float)]),
|
||||
}
|
||||
);
|
||||
export type DiscretePalette = ValueFor<typeof DiscretePalette>;
|
||||
export interface DiscretePalette extends ValueFor<typeof _DiscretePalette> { }
|
||||
export const DiscretePalette: iots.Type<DiscretePalette> = _DiscretePalette;
|
||||
|
||||
export const DiscretePaletteDefaults: Required<DiscretePalette> = {
|
||||
kind: 'discrete',
|
||||
@@ -242,10 +339,9 @@ export const DiscretePaletteDefaults: Required<DiscretePalette> = {
|
||||
};
|
||||
|
||||
|
||||
export const ContinuousPalette = object(
|
||||
const _ContinuousPalette = object(
|
||||
{
|
||||
kind: literal('continuous'),
|
||||
|
||||
},
|
||||
// Optionals:
|
||||
{
|
||||
@@ -269,7 +365,8 @@ export const ContinuousPalette = object(
|
||||
overflow_color: nullable(union(literal('auto'), ColorT)),
|
||||
}
|
||||
);
|
||||
export type ContinuousPalette = ValueFor<typeof ContinuousPalette>;
|
||||
export interface ContinuousPalette extends ValueFor<typeof _ContinuousPalette> { }
|
||||
export const ContinuousPalette: iots.Type<ContinuousPalette> = _ContinuousPalette;
|
||||
|
||||
export const ContinuousPaletteDefaults: Required<ContinuousPalette> = {
|
||||
kind: 'continuous',
|
||||
|
||||
@@ -5,13 +5,16 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Mat4, Vec3, Vec4, EPSILON } from '../mol-math/linear-algebra';
|
||||
import { Viewport, cameraProject, cameraUnproject } from './camera/util';
|
||||
import { CameraTransitionManager } from './camera/transition';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { Scene } from '../mol-gl/scene';
|
||||
import { assertUnreachable } from '../mol-util/type-helpers';
|
||||
import { Ray3D } from '../mol-math/geometry/primitives/ray3d';
|
||||
import { Mat4 } from '../mol-math/linear-algebra/3d/mat4';
|
||||
import { Vec4 } from '../mol-math/linear-algebra/3d/vec4';
|
||||
import { Vec3 } from '../mol-math/linear-algebra/3d/vec3';
|
||||
import { EPSILON } from '../mol-math/linear-algebra/3d/common';
|
||||
|
||||
export type { ICamera };
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
*/
|
||||
|
||||
import { Camera } from '../camera';
|
||||
import { Quat, Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { lerp } from '../../mol-math/interpolate';
|
||||
import { Quat } from '../../mol-math/linear-algebra/3d/quat';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra/3d/vec3';
|
||||
|
||||
export { CameraTransitionManager };
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Mat4, Vec3, Vec4 } from '../../mol-math/linear-algebra';
|
||||
import { Mat4 } from '../../mol-math/linear-algebra/3d/mat4';
|
||||
import { Vec3 } from '../../mol-math/linear-algebra/3d/vec3';
|
||||
import { Vec4 } from '../../mol-math/linear-algebra/3d/vec4';
|
||||
|
||||
export { Viewport };
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ export const Canvas3DParams = {
|
||||
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' }),
|
||||
minNear: PD.Numeric(5, { min: 0.1, max: 100, step: 0.1 }, { description: 'Note, may cause performance issues rendering impostors when set too small and cause issues with outline rendering when too close to 0.' }),
|
||||
minNear: PD.Numeric(1, { min: 0.1, max: 100, step: 0.1 }, { description: 'Minimal allowed distance of near clipping plane from the camera. Note, may cause performance issues rendering impostors when set too small and cause issues with outline rendering when too close to 0.' }),
|
||||
}, { pivot: 'radius' }),
|
||||
viewport: PD.MappedStatic('canvas', {
|
||||
canvas: PD.Group({}),
|
||||
@@ -124,6 +124,9 @@ export const DefaultCanvas3DAttribs = {
|
||||
xr: DefaultXRManagerAttribs,
|
||||
};
|
||||
export type Canvas3DAttribs = typeof DefaultCanvas3DAttribs
|
||||
export type PartialCanvas3DAttribs = {
|
||||
[K in keyof Canvas3DAttribs]?: Canvas3DAttribs[K] extends { name: string, params: any } ? Canvas3DAttribs[K] : Partial<Canvas3DAttribs[K]>
|
||||
}
|
||||
|
||||
export { Canvas3DContext };
|
||||
|
||||
@@ -373,6 +376,7 @@ interface Canvas3D {
|
||||
readonly boundingSphere: Readonly<Sphere3D>
|
||||
readonly boundingSphereVisible: Readonly<Sphere3D>
|
||||
setProps(props: PartialCanvas3DProps | ((old: Canvas3DProps) => Partial<Canvas3DProps> | void), doNotRequestDraw?: boolean /* = false */): void
|
||||
setAttribs(attribs: PartialCanvas3DAttribs): void
|
||||
getImagePass(props: Partial<ImageProps>): ImagePass
|
||||
getRenderObjects(): GraphicsRenderObject[]
|
||||
|
||||
@@ -515,7 +519,7 @@ namespace Canvas3D {
|
||||
}
|
||||
}
|
||||
|
||||
const xrManager = new XRManager(webgl, input, scene, camera, stereoCamera, helper.pointer, interactionHelper);
|
||||
const xrManager = new XRManager(webgl, input, scene, camera, stereoCamera, helper.pointer, interactionHelper, p.xr, a.xr);
|
||||
|
||||
const xr = {
|
||||
request: async () => {
|
||||
@@ -1358,8 +1362,12 @@ namespace Canvas3D {
|
||||
requestDraw();
|
||||
}
|
||||
},
|
||||
setAttribs: (attribs: PartialCanvas3DAttribs) => {
|
||||
if (attribs.trackball) controls.setAttribs(attribs.trackball);
|
||||
if (attribs.xr) xrManager.setAttribs(attribs.xr);
|
||||
},
|
||||
getImagePass: (props: Partial<ImageProps> = {}) => {
|
||||
return new ImagePass(webgl, assetManager, renderer, scene, camera, helper, passes.draw.transparency, props);
|
||||
return new ImagePass(webgl, assetManager, renderer, scene, camera, helper, props);
|
||||
},
|
||||
getRenderObjects(): GraphicsRenderObject[] {
|
||||
const renderObjects: GraphicsRenderObject[] = [];
|
||||
@@ -1371,7 +1379,10 @@ namespace Canvas3D {
|
||||
return getProps();
|
||||
},
|
||||
get attribs() {
|
||||
return a;
|
||||
return {
|
||||
trackball: controls.attribs,
|
||||
xr: xrManager.attribs,
|
||||
};
|
||||
},
|
||||
get input() {
|
||||
return input;
|
||||
|
||||
@@ -75,7 +75,7 @@ export const TrackballControlsParams = {
|
||||
animate: PD.MappedStatic('off', {
|
||||
off: PD.EmptyGroup(),
|
||||
spin: PD.Group({
|
||||
speed: PD.Numeric(0.3, { min: -5, max: 5, step: 0.1 }, { description: 'Number of rotations per second' }),
|
||||
speed: PD.Numeric(0.1, { min: -2, max: 2, step: 0.01 }, { description: 'Number of rotations per second' }),
|
||||
}, { description: 'Spin the 3D scene around the x-axis in view space' }),
|
||||
rock: PD.Group({
|
||||
speed: PD.Numeric(0.3, { min: -5, max: 5, step: 0.1 }, { description: 'Number of oscilations per second' }),
|
||||
|
||||
@@ -90,11 +90,16 @@ export class XRManager {
|
||||
private hit: Vec3 | undefined = undefined;
|
||||
|
||||
readonly props: XRManagerProps;
|
||||
readonly attribs: XRManagerAttribs;
|
||||
|
||||
setProps(props: Partial<XRManagerProps>) {
|
||||
Object.assign(this.props, props);
|
||||
}
|
||||
|
||||
setAttribs(attribs: Partial<XRManagerAttribs>) {
|
||||
Object.assign(this.attribs, attribs);
|
||||
}
|
||||
|
||||
private intersect(camera: ICamera, view: Mat4, plane: Plane3D, targetRayPose: XRPose): { point: Vec3, screen: Vec2 } | undefined {
|
||||
const point = Vec3();
|
||||
const ray = getRayFromPose(targetRayPose, view);
|
||||
@@ -310,6 +315,7 @@ export class XRManager {
|
||||
|
||||
constructor(private webgl: WebGLContext, private input: InputObserver, private scene: Scene, private camera: Camera, private stereoCamera: StereoCamera, private pointerHelper: PointerHelper, private interactionHelper: Canvas3dInteractionHelper, props: Partial<XRManagerProps> = {}, attribs: Partial<XRManagerAttribs> = {}) {
|
||||
this.props = { ...PD.getDefaultValues(XRManagerParams), ...props };
|
||||
this.attribs = { ...DefaultXRManagerAttribs, ...attribs };
|
||||
|
||||
this.hoverSub = this.interactionHelper.events.hover.subscribe(({ position }) => {
|
||||
this.hit = position;
|
||||
@@ -323,9 +329,9 @@ export class XRManager {
|
||||
this.checkSupported();
|
||||
navigator.xr?.addEventListener('devicechange', this.checkSupported);
|
||||
|
||||
const b = { ...DefaultXRManagerBindings, ...attribs.bindings };
|
||||
|
||||
this.keyUpSub = input.keyUp.subscribe(({ code, modifiers, key }) => {
|
||||
const b = this.attribs.bindings;
|
||||
|
||||
if (Binding.matchKey(b.exit, code, modifiers, key)) {
|
||||
this.end();
|
||||
}
|
||||
@@ -336,6 +342,8 @@ export class XRManager {
|
||||
});
|
||||
|
||||
this.gestureSub = input.gesture.subscribe(({ scale, button, modifiers }) => {
|
||||
const b = this.attribs.bindings;
|
||||
|
||||
if (Binding.match(b.gestureScale, button, modifiers)) {
|
||||
this.setScaleFactor(scale);
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ export class IlluminationPass {
|
||||
const { gl, state } = this.webgl;
|
||||
|
||||
const markingEnabled = MarkingPass.isEnabled(props.marking);
|
||||
const hasTransparent = scene.opacityAverage < 1;
|
||||
const hasTransparent = scene.opacityAverage < 1 || scene.volumes.renderables.length > 0;
|
||||
const hasMarking = markingEnabled && scene.markerAverage > 0;
|
||||
|
||||
this.transparentTarget.bind();
|
||||
@@ -347,7 +347,7 @@ export class IlluminationPass {
|
||||
const dofEnabled = DofPass.isEnabled(props.postprocessing);
|
||||
|
||||
const markingEnabled = MarkingPass.isEnabled(props.marking);
|
||||
const hasTransparent = scene.opacityAverage < 1;
|
||||
const hasTransparent = scene.opacityAverage < 1 || scene.volumes.renderables.length > 0;
|
||||
const hasMarking = markingEnabled && scene.markerAverage > 0;
|
||||
|
||||
let needsUpdateCompose = false;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
@@ -57,10 +58,10 @@ export class ImagePass {
|
||||
get width() { return this._width; }
|
||||
get height() { return this._height; }
|
||||
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, private renderer: Renderer, private scene: Scene, private camera: Camera, helper: Helper, transparency: 'wboit' | 'dpoit' | 'blended', props: Partial<ImageProps>) {
|
||||
constructor(private webgl: WebGLContext, assetManager: AssetManager, private renderer: Renderer, private scene: Scene, private camera: Camera, helper: Helper, props: Partial<ImageProps>) {
|
||||
this.props = { ...PD.getDefaultValues(ImageParams), ...props };
|
||||
|
||||
this.drawPass = new DrawPass(webgl, assetManager, 128, 128, transparency);
|
||||
this.drawPass = new DrawPass(webgl, assetManager, 128, 128, scene.transparency);
|
||||
this.illuminationPass = new IlluminationPass(webgl, this.drawPass);
|
||||
this.multiSamplePass = new MultiSamplePass(webgl, this.drawPass);
|
||||
this.multiSampleHelper = new MultiSampleHelper(this.multiSamplePass);
|
||||
@@ -104,6 +105,7 @@ export class ImagePass {
|
||||
}
|
||||
|
||||
async render(runtime: RuntimeContext) {
|
||||
this.drawPass.setTransparency(this.scene.transparency);
|
||||
ShaderManager.ensureRequired(this.webgl, this.scene, this.props);
|
||||
Camera.copySnapshot(this._camera.state, this.camera.state);
|
||||
Viewport.set(this._camera.viewport, 0, 0, this._width, this._height);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { EquivalenceClasses } from '../util';
|
||||
import { EquivalenceClasses } from '../util/equivalence-classes';
|
||||
|
||||
describe('equiv-classes', () => {
|
||||
it('integer mod classes', () => {
|
||||
|
||||
@@ -6,8 +6,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 { Tensor as Tensors } from '../../mol-math/linear-algebra/tensor';
|
||||
import type { 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> {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { Column } from './column';
|
||||
import { sortArray } from '../util/sort';
|
||||
import { StringBuilder } from '../../mol-util';
|
||||
import { StringBuilder } from '../../mol-util/string-builder';
|
||||
|
||||
/** A collection of columns */
|
||||
type Table<Schema extends Table.Schema = any> = {
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
|
||||
import { sortArray, hash3, hash4, createRangeArray } from '../../util';
|
||||
import { createRangeArray } from '../../util/array';
|
||||
import { hash3, hash4 } from '../../util/hash-functions';
|
||||
import { sortArray } from '../../util/sort';
|
||||
import { Interval } from '../interval';
|
||||
|
||||
type Nums = ArrayLike<number>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { iterableToArray } from '../util';
|
||||
import { iterableToArray } from '../util/array';
|
||||
|
||||
// TODO: rename to "linear map" and just do key value mapping from index?
|
||||
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Segmentation, OrderedSet, SortedArray, Interval } from '../int';
|
||||
import { Iterator as _Iterator } from '../iterator';
|
||||
import { Interval } from './interval';
|
||||
import { OrderedSet } from './ordered-set';
|
||||
import { Segmentation } from './segmentation';
|
||||
import { SortedArray } from './sorted-array';
|
||||
|
||||
/** Pairs of min and max indices of sorted, non-overlapping ranges */
|
||||
type SortedRanges<T extends number = number> = SortedArray<T>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { hash2 } from '../util';
|
||||
import { hash2 } from '../util/hash-functions';
|
||||
|
||||
/**
|
||||
* Represents a pair of two integers as a double,
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Interval, OrderedSet, SortedArray } from '../../int';
|
||||
import { Interval } from '../../int/interval';
|
||||
import { OrderedSet } from '../../int/ordered-set';
|
||||
import { SortedArray } from '../../int/sorted-array';
|
||||
import { IntervalIterator } from '../interval-iterator';
|
||||
|
||||
describe('interval', () => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { Column } from '../db';
|
||||
import { Column } from '../db/column';
|
||||
|
||||
export interface Grouping<V, K> {
|
||||
map: Map<K, V[]>,
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Interval } from '../int/interval';
|
||||
import { OrderedSet } from '../int/ordered-set';
|
||||
import { Segmentation } from '../int/segmentation';
|
||||
import { Iterator } from '../iterator';
|
||||
import { OrderedSet, Interval, Segmentation } from '../int';
|
||||
|
||||
/** Emits a segment of length one for each element in the interval that is also in the set */
|
||||
export class IntervalIterator<I extends number = number> implements Iterator<Segmentation.Segment<I>> {
|
||||
|
||||
@@ -122,7 +122,9 @@ export function createValueColor(value: Color, colorData?: ColorData): ColorData
|
||||
|
||||
/** Creates color uniform */
|
||||
function createUniformColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData {
|
||||
return createValueColor(color(NullLocation, false), colorData);
|
||||
locationIt.reset();
|
||||
const loc = locationIt.hasNext ? locationIt.move() : { location: NullLocation, isSecondary: false };
|
||||
return createValueColor(color(loc.location, loc.isSecondary), colorData);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { hashFnv32a } from '../../../mol-data/util';
|
||||
import { LocationIterator, PositionLocation } from '../../../mol-geo/util/location-iterator';
|
||||
import { LocationIterator, PositionLocation } from '../../util/location-iterator';
|
||||
import { RenderableState } from '../../../mol-gl/renderable';
|
||||
import { DirectVolumeValues } from '../../../mol-gl/renderable/direct-volume';
|
||||
import { calculateTransformBoundingSphere } from '../../../mol-gl/renderable/util';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { hashFnv32a } from '../../../mol-data/util';
|
||||
import { LocationIterator } from '../../../mol-geo/util/location-iterator';
|
||||
import { LocationIterator } from '../../util/location-iterator';
|
||||
import { RenderableState } from '../../../mol-gl/renderable';
|
||||
import { calculateTransformBoundingSphere, createTextureImage, TextureImage } from '../../../mol-gl/renderable/util';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { ChunkedArray } from '../../../mol-data/util';
|
||||
import { Lines } from './lines';
|
||||
import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { Cage } from '../../../mol-geo/primitive/cage';
|
||||
import { Cage } from '../../primitive/cage';
|
||||
|
||||
export interface LinesBuilder {
|
||||
add(startX: number, startY: number, startZ: number, endX: number, endY: number, endZ: number, group: number): void
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Vec3, Mat4, Mat3 } from '../../../mol-math/linear-algebra';
|
||||
import { ChunkedArray } from '../../../mol-data/util';
|
||||
import { Mesh } from './mesh';
|
||||
import { Primitive } from '../../primitive/primitive';
|
||||
import { Cage } from '../../../mol-geo/primitive/cage';
|
||||
import { Cage } from '../../primitive/cage';
|
||||
import { addSphere } from './builder/sphere';
|
||||
import { addCylinder } from './builder/cylinder';
|
||||
|
||||
|
||||
@@ -77,7 +77,9 @@ export function createValueSize(value: number, sizeData?: SizeData): SizeData {
|
||||
|
||||
/** Creates size uniform */
|
||||
export function createUniformSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
|
||||
return createValueSize(sizeFn(NullLocation), sizeData);
|
||||
locationIt.reset();
|
||||
const location = locationIt.hasNext ? locationIt.move().location : NullLocation;
|
||||
return createValueSize(sizeFn(location), sizeData);
|
||||
}
|
||||
|
||||
export function createTextureSize(sizes: TextureImage<Uint8Array>, type: SizeType, sizeData?: SizeData): SizeData {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ValueCell } from '../../../mol-util';
|
||||
import { GeometryUtils } from '../geometry';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { TransformData } from '../transform-data';
|
||||
import { LocationIterator, PositionLocation } from '../../../mol-geo/util/location-iterator';
|
||||
import { LocationIterator, PositionLocation } from '../../util/location-iterator';
|
||||
import { Theme } from '../../../mol-theme/theme';
|
||||
import { SpheresValues } from '../../../mol-gl/renderable/spheres';
|
||||
import { createColors } from '../color-data';
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { GeometryUtils } from '../geometry';
|
||||
import { LocationIterator, PositionLocation } from '../../../mol-geo/util/location-iterator';
|
||||
import { LocationIterator, PositionLocation } from '../../util/location-iterator';
|
||||
import { TransformData } from '../transform-data';
|
||||
import { Theme } from '../../../mol-theme/theme';
|
||||
import { createColors } from '../color-data';
|
||||
@@ -333,5 +334,5 @@ function getPadding(mappings: Float32Array, depths: Float32Array, charCount: num
|
||||
const d = Math.abs(depths[i]);
|
||||
if (d > maxDepth) maxDepth = d;
|
||||
}
|
||||
return scale * Math.max(maxDepth, maxOffset);
|
||||
return Math.max(maxDepth, scale * maxOffset);
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { LocationIterator, PositionLocation } from '../../../mol-geo/util/location-iterator';
|
||||
import { LocationIterator, PositionLocation } from '../../util/location-iterator';
|
||||
import { TransformData } from '../transform-data';
|
||||
import { createColors } from '../color-data';
|
||||
import { createMarkers } from '../marker-data';
|
||||
|
||||
@@ -786,5 +786,6 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
stencilOp: function () { },
|
||||
stencilOpSeparate: function () { },
|
||||
unpackColorSpace: 'srgb',
|
||||
makeXRCompatible: async function () { },
|
||||
};
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { LinkedList } from '../mol-data/generic';
|
||||
import { LinkedList } from '../mol-data/generic/linked-list';
|
||||
import { GraphicsRenderObject } from './render-object';
|
||||
|
||||
type N = LinkedList.Node<GraphicsRenderObject>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -38,6 +38,7 @@ const IsosurfaceSchema = {
|
||||
|
||||
uGridDim: UniformSpec('v3'),
|
||||
uGridTexDim: UniformSpec('v3'),
|
||||
uGridDataDim: UniformSpec('v3'),
|
||||
uGridTransform: UniformSpec('m4'),
|
||||
uGridTransformAdjoint: UniformSpec('m3'),
|
||||
uScale: UniformSpec('v2'),
|
||||
@@ -54,7 +55,7 @@ function valueChannel(ctx: WebGLContext, volumeData: Texture) {
|
||||
return isWebGL2(ctx.gl) && volumeData.format === ctx.gl.RED ? 'red' : 'alpha';
|
||||
}
|
||||
|
||||
function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean): ComputeRenderable<IsosurfaceValues> {
|
||||
function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridDataDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean): ComputeRenderable<IsosurfaceValues> {
|
||||
if (ctx.namedComputeRenderables[IsosurfaceName]) {
|
||||
const v = ctx.namedComputeRenderables[IsosurfaceName].values as IsosurfaceValues;
|
||||
|
||||
@@ -71,6 +72,7 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
|
||||
|
||||
ValueCell.update(v.uGridDim, gridDim);
|
||||
ValueCell.update(v.uGridTexDim, gridTexDim);
|
||||
ValueCell.update(v.uGridDataDim, gridDataDim);
|
||||
ValueCell.update(v.uGridTransform, transform);
|
||||
ValueCell.update(v.uGridTransformAdjoint, Mat3.adjointFromMat4(Mat3(), transform));
|
||||
ValueCell.update(v.uScale, scale);
|
||||
@@ -81,12 +83,12 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
|
||||
|
||||
ctx.namedComputeRenderables[IsosurfaceName].update();
|
||||
} else {
|
||||
ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder, constantGroup);
|
||||
ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, gridDataDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder, constantGroup);
|
||||
}
|
||||
return ctx.namedComputeRenderables[IsosurfaceName];
|
||||
}
|
||||
|
||||
function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean) {
|
||||
function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridDataDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean) {
|
||||
// console.log('uSize', Math.pow(2, levels))
|
||||
const values: IsosurfaceValues = {
|
||||
...QuadValues,
|
||||
@@ -105,6 +107,7 @@ function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Text
|
||||
|
||||
uGridDim: ValueCell.create(gridDim),
|
||||
uGridTexDim: ValueCell.create(gridTexDim),
|
||||
uGridDataDim: ValueCell.create(gridDataDim),
|
||||
uGridTransform: ValueCell.create(transform),
|
||||
uGridTransformAdjoint: ValueCell.create(Mat3.adjointFromMat4(Mat3(), transform)),
|
||||
uScale: ValueCell.create(scale),
|
||||
@@ -132,7 +135,7 @@ function setRenderingDefaults(ctx: WebGLContext) {
|
||||
state.clearColor(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, gridDataDim: Vec3, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
const { drawBuffers } = ctx.extensions;
|
||||
if (!drawBuffers) throw new Error('need WebGL draw buffers');
|
||||
|
||||
@@ -189,7 +192,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
|
||||
groupTexture.attachFramebuffer(framebuffer, 1);
|
||||
normalTexture.attachFramebuffer(framebuffer, 2);
|
||||
|
||||
const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder, constantGroup);
|
||||
const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, gridDataDim, transform, isoValue, levels, scale, count, invert, packedGroup, axisOrder, constantGroup);
|
||||
ctx.state.currentRenderItemId = -1;
|
||||
|
||||
framebuffer.bind();
|
||||
@@ -225,11 +228,11 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
|
||||
*
|
||||
* Implementation based on http://www.miaumiau.cat/2016/10/stream-compaction-in-webgl/
|
||||
*/
|
||||
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridDataDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, axisOrder: Vec3, constantGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
|
||||
if (isTimingMode) ctx.timer.mark('extractIsosurface');
|
||||
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
|
||||
const compacted = createHistogramPyramid(ctx, activeVoxelsTex, gridTexScale, gridTexDim);
|
||||
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, axisOrder, constantGroup, vertexTexture, groupTexture, normalTexture);
|
||||
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, gridDataDim, transform, isoValue, invert, packedGroup, axisOrder, constantGroup, vertexTexture, groupTexture, normalTexture);
|
||||
if (isTimingMode) ctx.timer.markEnd('extractIsosurface');
|
||||
|
||||
return gv;
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Vec3, Mat4 } from '../mol-math/linear-algebra';
|
||||
import { Mat4 } from '../mol-math/linear-algebra/3d/mat4';
|
||||
import { Vec3 } from '../mol-math/linear-algebra/3d/vec3';
|
||||
|
||||
export interface Object3D {
|
||||
readonly view: Mat4
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
import { Program } from './webgl/program';
|
||||
import { RenderableValues, Values, RenderableSchema, BaseValues } from './renderable/schema';
|
||||
import { GraphicsRenderItem, ComputeRenderItem, GraphicsRenderVariant, MultiDrawBaseData, Transparency } from './webgl/render-item';
|
||||
import { ValueCell } from '../mol-util';
|
||||
import { ValueCell } from '../mol-util/value-cell';
|
||||
import { idFactory } from '../mol-util/id-factory';
|
||||
import { clamp } from '../mol-math/interpolate';
|
||||
import { Frustum3D } from '../mol-math/geometry/primitives/frustum3d';
|
||||
import { Plane3D } from '../mol-math/geometry/primitives/plane3d';
|
||||
import { Sphere3D } from '../mol-math/geometry';
|
||||
import { Sphere3D } from '../mol-math/geometry/primitives/sphere3d';
|
||||
import { Vec4 } from '../mol-math/linear-algebra/3d/vec4';
|
||||
import { WebGLStats } from './webgl/context';
|
||||
import { isTimingMode } from '../mol-util/debug';
|
||||
|
||||
@@ -9,8 +9,7 @@ import { WebGLContext } from '../webgl/context';
|
||||
import { createGraphicsRenderItem, Transparency } from '../webgl/render-item';
|
||||
import { AttributeSpec, Values, GlobalUniformSchema, InternalSchema, TextureSpec, ElementsSpec, DefineSpec, InternalValues, BaseSchema, UniformSpec, GlobalTextureSchema, GlobalDefineValues, GlobalDefines, GlobalDefineSchema } from './schema';
|
||||
import { ImageShaderCode } from '../shader-code';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
import { InterpolationTypeNames } from '../../mol-geo/geometry/image/image';
|
||||
import { ValueCell } from '../../mol-util/value-cell';
|
||||
|
||||
export const ImageSchema = {
|
||||
...BaseSchema,
|
||||
@@ -33,7 +32,8 @@ export const ImageSchema = {
|
||||
|
||||
uIsoLevel: UniformSpec('f'),
|
||||
|
||||
dInterpolation: DefineSpec('string', InterpolationTypeNames),
|
||||
/** Same as `InterpolationTypeNames` in '../../mol-geo/geometry/image/image' */
|
||||
dInterpolation: DefineSpec('string', ['nearest', 'catmulrom', 'mitchell', 'bspline']),
|
||||
};
|
||||
export type ImageSchema = typeof ImageSchema
|
||||
export type ImageValues = Values<ImageSchema>
|
||||
|
||||
@@ -70,6 +70,7 @@ interface Scene extends Object3D {
|
||||
readonly renderables: ReadonlyArray<GraphicsRenderable>
|
||||
readonly boundingSphere: Sphere3D
|
||||
readonly boundingSphereVisible: Sphere3D
|
||||
readonly transparency: Transparency
|
||||
|
||||
readonly primitives: Scene.Group
|
||||
readonly volumes: Scene.Group
|
||||
@@ -383,6 +384,9 @@ namespace Scene {
|
||||
}
|
||||
return boundingSphereVisible;
|
||||
},
|
||||
get transparency() {
|
||||
return transparency;
|
||||
},
|
||||
get markerAverage() {
|
||||
if (markerAverageDirty) {
|
||||
markerAverage = calculateMarkerAverage();
|
||||
|
||||
@@ -22,6 +22,7 @@ uniform bool uInvert;
|
||||
|
||||
uniform vec3 uGridDim;
|
||||
uniform vec3 uGridTexDim;
|
||||
uniform vec3 uGridDataDim;
|
||||
uniform mat4 uGridTransform;
|
||||
uniform mat3 uGridTransformAdjoint;
|
||||
|
||||
@@ -93,20 +94,19 @@ vec4 baseVoxel(vec2 pos) {
|
||||
}
|
||||
|
||||
vec4 getGroup(const in vec3 p) {
|
||||
vec3 gridDim = uGridDim - vec3(1.0, 1.0, 0.0); // remove xy padding
|
||||
// note that we swap x and z because the texture is flipped around y
|
||||
#if defined(dAxisOrder_012)
|
||||
float group = p.z + p.y * gridDim.z + p.x * gridDim.z * gridDim.y; // 210
|
||||
float group = p.z + p.y * uGridDataDim.z + p.x * uGridDataDim.z * uGridDataDim.y; // 210
|
||||
#elif defined(dAxisOrder_021)
|
||||
float group = p.y + p.z * gridDim.y + p.x * gridDim.y * gridDim.z; // 120
|
||||
float group = p.y + p.z * uGridDataDim.y + p.x * uGridDataDim.y * uGridDataDim.z; // 120
|
||||
#elif defined(dAxisOrder_102)
|
||||
float group = p.z + p.x * gridDim.z + p.y * gridDim.z * gridDim.x; // 201
|
||||
float group = p.z + p.x * uGridDataDim.z + p.y * uGridDataDim.z * uGridDataDim.x; // 201
|
||||
#elif defined(dAxisOrder_120)
|
||||
float group = p.x + p.z * gridDim.x + p.y * gridDim.x * gridDim.z; // 021
|
||||
float group = p.x + p.z * uGridDataDim.x + p.y * uGridDataDim.x * uGridDataDim.z; // 021
|
||||
#elif defined(dAxisOrder_201)
|
||||
float group = p.y + p.x * gridDim.y + p.z * gridDim.y * gridDim.x; // 102
|
||||
float group = p.y + p.x * uGridDataDim.y + p.z * uGridDataDim.y * uGridDataDim.x; // 102
|
||||
#elif defined(dAxisOrder_210)
|
||||
float group = p.x + p.y * gridDim.x + p.z * gridDim.x * gridDim.y; // 012
|
||||
float group = p.x + p.y * uGridDataDim.x + p.z * uGridDataDim.x * uGridDataDim.y; // 012
|
||||
#endif
|
||||
return vec4(group > 16777215.5 ? vec3(1.0) : packIntToRGB(group), 1.0);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
@@ -48,7 +48,7 @@ vec2 getDepthTransparentWithAlpha(const in vec2 coords) {
|
||||
}
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
return depth > 0.9999;
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
float getPixelSize(const in vec2 coords, const in float depth) {
|
||||
@@ -108,8 +108,8 @@ void main(void) {
|
||||
transparentOutlineFlag = 0.0;
|
||||
bestTransparentAlpha = 0.0;
|
||||
}
|
||||
|
||||
vec2 depthPacked; // Pack depth in G/B channels
|
||||
|
||||
vec2 depthPacked; // Pack depth in G/B channels
|
||||
float outlineTypeFlag = 0.0;
|
||||
if (opaqueOutlineFlag > 0.0 && transparentOutlineFlag > 0.0) {
|
||||
outlineTypeFlag = 0.75; // Both
|
||||
@@ -121,7 +121,7 @@ void main(void) {
|
||||
outlineTypeFlag = 0.25; // Opaque only
|
||||
depthPacked = packUnitIntervalToRG(bestOpaqueDepth);
|
||||
}
|
||||
|
||||
|
||||
float alpha = clamp(bestTransparentAlpha, 0.0, 0.5) * 2.0; // limiting to range [0.0, 0.5] to improve alpha precision since we don't need a wider range
|
||||
float packedFlagWithAlpha = pack2x4(vec2(outlineTypeFlag, alpha)); // pack outlineType with alpha
|
||||
gl_FragColor = vec4(packedFlagWithAlpha, depthPacked.x, depthPacked.y, bestTransparentDepth);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
@@ -54,13 +54,13 @@ float getDepthTransparent(const in vec2 coords) {
|
||||
}
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
return depth > 0.9999; // handle depth packing precision issues
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
int squaredOutlineScale = dOutlineScale * dOutlineScale;
|
||||
void getOutline(const in vec2 coords, out bool hasOpaque, out bool hasTransparent, out float opaqueDepth, out float transparentDepth, out float alpha) {
|
||||
vec2 invTexSize = 1.0 / uTexSize;
|
||||
|
||||
|
||||
hasOpaque = false;
|
||||
hasTransparent = false;
|
||||
opaqueDepth = 1.0;
|
||||
@@ -81,14 +81,14 @@ void getOutline(const in vec2 coords, out bool hasOpaque, out bool hasTransparen
|
||||
|
||||
float sampleFlag = sampleFlagWithAlpha.x;
|
||||
float sampleAlpha = clamp(sampleFlagWithAlpha.y * 0.5, 0.01, 1.0);
|
||||
|
||||
|
||||
if ((sampleFlag > 0.20 && sampleFlag < 0.30) || (sampleFlag > 0.70 && sampleFlag < 0.80)) { // transparent || both
|
||||
if (sampleOpaqueDepth < opaqueDepth) {
|
||||
hasOpaque = true;
|
||||
opaqueDepth = sampleOpaqueDepth;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((((sampleFlag > 0.45 && sampleFlag < 0.55) || (sampleFlag > 0.70 && sampleFlag < 0.80))) && sampleTransparentDepth < transparentDepth) { // transparent || both
|
||||
hasTransparent = true;
|
||||
transparentDepth = sampleTransparentDepth;
|
||||
@@ -184,15 +184,15 @@ void main(void) {
|
||||
if (hasOpaque) {
|
||||
float viewDist = abs(getViewZ(outlineOpaqueDepth));
|
||||
float fogFactor = smoothstep(uFogNear, uFogFar, viewDist);
|
||||
if (!uTransparentBackground) {
|
||||
if (!uTransparentBackground) {
|
||||
color.rgb = mix(uOutlineColor, uFogColor, fogFactor);
|
||||
} else {
|
||||
color.a = 1.0 - fogFactor;
|
||||
color.rgb = mix(uOutlineColor, vec3(0.0), fogFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef dBlendTransparency
|
||||
#ifdef dBlendTransparency
|
||||
if (hasTransparent) {
|
||||
if (hasOpaque && outlineOpaqueDepth < outlineTransparentDepth) {
|
||||
blendTransparency = false;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
* @author Gianluca Tomasello <giagitom@gmail.com>
|
||||
*/
|
||||
|
||||
export const ssaoBlur_frag = `
|
||||
@@ -36,8 +37,7 @@ float getViewZ(const in float depth) {
|
||||
}
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
// checking for 1.0 is not enough, because of precision issues
|
||||
return depth >= 0.999;
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
bool isNearClip(const in float depth) {
|
||||
@@ -78,8 +78,9 @@ void main(void) {
|
||||
|
||||
float sum = 0.0;
|
||||
float kernelSum = 0.0;
|
||||
int halfKernelSize = dOcclusionKernelSize / 2;
|
||||
// only if kernelSize is odd
|
||||
for (int i = -dOcclusionKernelSize / 2; i <= dOcclusionKernelSize / 2; i++) {
|
||||
for (int i = -halfKernelSize; i <= halfKernelSize; i++) {
|
||||
if (abs(float(i)) > 1.0 && abs(float(i)) * pixelSize > 0.8) continue;
|
||||
|
||||
vec2 sampleCoords = coords + float(i) * offset;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
|
||||
@@ -64,7 +64,7 @@ vec2 getNoiseVec2(const in vec2 coords) {
|
||||
}
|
||||
|
||||
bool isBackground(const in float depth) {
|
||||
return depth > 0.999; // handle precision issues with packed depth
|
||||
return depth == 1.0;
|
||||
}
|
||||
|
||||
float getDepth(const in vec2 coords, const in int transparentFlag) {
|
||||
|
||||
@@ -108,9 +108,9 @@ function resetValueChanges(valueChanges: ValueChanges) {
|
||||
|
||||
//
|
||||
|
||||
export type Transparency = 'blended' | 'wboit' | 'dpoit' | undefined
|
||||
export type Transparency = 'blended' | 'wboit' | 'dpoit'
|
||||
|
||||
function getRenderVariant(variant: string, transparency: Transparency): string {
|
||||
function getRenderVariant(variant: string, transparency: Transparency | undefined): string {
|
||||
if (variant === 'color') {
|
||||
switch (transparency) {
|
||||
case 'blended': return 'colorBlended';
|
||||
@@ -136,7 +136,7 @@ export function createComputeRenderItem(ctx: WebGLContext, drawMode: DrawMode, s
|
||||
*
|
||||
* - assumes that `values.drawCount` and `values.instanceCount` exist
|
||||
*/
|
||||
export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number, renderVariants: T[], transparency: Transparency): RenderItem<T> {
|
||||
export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number, renderVariants: T[], transparency: Transparency | undefined): RenderItem<T> {
|
||||
const id = getNextRenderItemId();
|
||||
const { stats, state, resources } = ctx;
|
||||
const { instancedArrays, vertexArrayObject, multiDrawInstancedBaseVertexBaseInstance, drawInstancedBaseVertexBaseInstance } = ctx.extensions;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.406, IHM 1.28, MA 1.4.7.
|
||||
* Code-generated 'BIRD' schema file. Dictionary versions: mmCIF 5.408, IHM 1.28, MA 1.4.8.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.406, IHM 1.28, MA 1.4.7.
|
||||
* Code-generated 'CCD' schema file. Dictionary versions: mmCIF 5.408, IHM 1.28, MA 1.4.8.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
|
||||
@@ -40,7 +40,7 @@ export const CifCore_Schema = {
|
||||
* in exceptional circumstances (Brock, 2025) may be reported as
|
||||
* non-integral.
|
||||
*
|
||||
* Reference: Brock, C. P. (2025). Acta Cryst. A81, nnn-nnn.
|
||||
* Reference: Brock, C. P. (2025). Acta Cryst. A81, 405-408.
|
||||
*/
|
||||
formula_units_z: float,
|
||||
/**
|
||||
@@ -336,7 +336,12 @@ export const CifCore_Schema = {
|
||||
*/
|
||||
site_symmetry_2: str,
|
||||
/**
|
||||
* Bond valence calculated from the bond distance.
|
||||
* Valence assigned to the bond between the sites identified by
|
||||
* _geom_bond.id calculated according to the bond-valence model
|
||||
* (Brown, 2002) from the bond distance.
|
||||
*
|
||||
* Ref: Brown, I. D. (2002). The Chemical Bond in Inorganic Chemistry:
|
||||
* the Bond-Valence Model, eq. (3.1). Oxford: Oxford University Press.
|
||||
*/
|
||||
valence: float,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.406, IHM 1.28, MA 1.4.7.
|
||||
* Code-generated 'mmCIF' schema file. Dictionary versions: mmCIF 5.408, IHM 1.28, MA 1.4.8.
|
||||
*
|
||||
* @author molstar/ciftools package
|
||||
*/
|
||||
@@ -5078,7 +5078,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The type of data held in the dataset.
|
||||
*/
|
||||
content_type: Aliased<'target' | 'template structure' | 'polymeric template library' | 'spatial restraints' | 'target-template alignment' | 'coevolution MSA' | 'model coordinates' | 'input structure' | 'reference database' | 'other'>(str),
|
||||
content_type: Aliased<'target' | 'template structure' | 'polymeric template library' | 'spatial restraints' | 'target-template alignment' | 'coevolution MSA' | 'model coordinates' | 'input structure' | 'reference database' | 'intermediate backbone' | 'intermediate sequence' | 'model quality assessment scores' | 'energy estimate' | 'experimental validation' | 'other'>(str),
|
||||
/**
|
||||
* Details for other content types.
|
||||
*/
|
||||
@@ -5131,7 +5131,7 @@ export const mmCIF_Schema = {
|
||||
/**
|
||||
* The mode of calculation of the QA metric.
|
||||
*/
|
||||
mode: Aliased<'local' | 'global' | 'local-pairwise' | 'per-feature' | 'per-feature-pair'>(str),
|
||||
mode: Aliased<'local' | 'global' | 'local-pairwise' | 'per-feature' | 'per-feature-pair' | 'dihedral'>(str),
|
||||
/**
|
||||
* Identifier to the set of software used to calculate the QA metric.
|
||||
* This data item is a pointer to the _ma_software_group.group_id in the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2025 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>
|
||||
@@ -109,7 +109,7 @@ function eatEscaped(state: TokenizerState, esc: number) {
|
||||
++state.position;
|
||||
return;
|
||||
default:
|
||||
if (next === void 0) { // = "end of stream"
|
||||
if (!Number.isFinite(next)) { // = "end of stream"
|
||||
// get rid of the quotes.
|
||||
state.tokenStart++;
|
||||
state.tokenEnd = state.position;
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { chunkedSubtask, RuntimeContext } from '../../../../mol-task';
|
||||
import { RuntimeContext } from '../../../../mol-task/execution/runtime-context';
|
||||
import { chunkedSubtask } from '../../../../mol-task/util/chunked';
|
||||
import { StringLike } from '../../../common/string-like';
|
||||
|
||||
export { Tokenizer };
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
import { GridLookup3D } from '../../geometry';
|
||||
import { sortArray } from '../../../mol-data/util';
|
||||
import { OrderedSet } from '../../../mol-data/int';
|
||||
import { sortArray } from '../../../mol-data/util/sort';
|
||||
import { OrderedSet } from '../../../mol-data/int/ordered-set';
|
||||
import { getBoundary } from '../boundary';
|
||||
|
||||
const xs = [0, 0, 1];
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { PositionData } from './common';
|
||||
import { Vec3 } from '../linear-algebra';
|
||||
import { OrderedSet } from '../../mol-data/int';
|
||||
import { OrderedSet } from '../../mol-data/int/ordered-set';
|
||||
import { BoundaryHelper } from './boundary-helper';
|
||||
import { Box3D } from '../geometry/primitives/box3d';
|
||||
import { Sphere3D } from '../geometry/primitives/sphere3d';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Vec3 } from '../../mol-math/linear-algebra/3d/vec3';
|
||||
import { Vec3 } from '../linear-algebra/3d/vec3';
|
||||
import { Sphere3D } from './primitives/sphere3d';
|
||||
|
||||
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2025 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 { OrderedSet } from '../../mol-data/int';
|
||||
import { Mat4, Tensor, Vec3, Vec2 } from '../linear-algebra';
|
||||
import { OrderedSet } from '../../mol-data/int/ordered-set';
|
||||
import { Mat4 } from '../linear-algebra/3d/mat4';
|
||||
import { Vec3 } from '../linear-algebra/3d/vec3';
|
||||
import { Tensor } from '../linear-algebra/tensor';
|
||||
import { Box3D } from './primitives/box3d';
|
||||
import { Texture } from '../../mol-gl/webgl/texture';
|
||||
|
||||
export interface PositionData {
|
||||
x: ArrayLike<number>,
|
||||
@@ -30,15 +31,6 @@ export type DensityData = {
|
||||
maxRadius: number,
|
||||
}
|
||||
|
||||
export type DensityTextureData = {
|
||||
transform: Mat4,
|
||||
texture: Texture,
|
||||
bbox: Box3D,
|
||||
gridDim: Vec3,
|
||||
gridTexDim: Vec3
|
||||
gridTexScale: Vec2
|
||||
}
|
||||
|
||||
export interface RegularGrid3d {
|
||||
box: Box3D,
|
||||
dimensions: Vec3
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Box3D, DensityData, DensityTextureData } from '../geometry';
|
||||
import { Box3D, DensityData } from '../geometry';
|
||||
import { PositionData } from './common';
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
import { Texture } from '../../mol-gl/webgl/texture';
|
||||
import { GaussianDensityTexture2d, GaussianDensityTexture3d } from './gaussian-density/gpu';
|
||||
import { Task } from '../../mol-task/task';
|
||||
import { GaussianDensityCPU } from './gaussian-density/cpu';
|
||||
import { Mat4 } from '../linear-algebra/3d/mat4';
|
||||
import { Vec3 } from '../linear-algebra/3d/vec3';
|
||||
import { Vec2 } from '../linear-algebra/3d/vec2';
|
||||
|
||||
export const DefaultGaussianDensityProps = {
|
||||
resolution: 1,
|
||||
@@ -27,7 +30,14 @@ export type GaussianDensityTextureData = {
|
||||
radiusFactor: number
|
||||
resolution: number
|
||||
maxRadius: number
|
||||
} & DensityTextureData
|
||||
transform: Mat4,
|
||||
texture: Texture,
|
||||
bbox: Box3D,
|
||||
gridDim: Vec3,
|
||||
gridTexDim: Vec3
|
||||
gridDataDim: Vec3
|
||||
gridTexScale: Vec2
|
||||
}
|
||||
|
||||
export function computeGaussianDensity(position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps) {
|
||||
return Task.create('Gaussian Density', async ctx => {
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Box3D, fillGridDim } from '../../geometry';
|
||||
import { Vec3, Mat4, Tensor } from '../../linear-algebra';
|
||||
import { RuntimeContext } from '../../../mol-task';
|
||||
import { PositionData } from '../common';
|
||||
import { OrderedSet } from '../../../mol-data/int';
|
||||
import { fillGridDim, PositionData } from '../common';
|
||||
import { OrderedSet } from '../../../mol-data/int/ordered-set';
|
||||
import { GaussianDensityProps, GaussianDensityData } from '../gaussian-density';
|
||||
import { fasterExp } from '../../approx';
|
||||
import { Box3D } from '../primitives/box3d';
|
||||
import { Vec3 } from '../../linear-algebra/3d/vec3';
|
||||
import { Tensor } from '../../linear-algebra/tensor';
|
||||
import { Mat4 } from '../../linear-algebra/3d/mat4';
|
||||
|
||||
export async function GaussianDensityCPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<GaussianDensityData> {
|
||||
const { resolution, radiusOffset, smoothness } = props;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Michael Krone <michael.krone@uni-tuebingen.de>
|
||||
@@ -99,8 +99,8 @@ export function GaussianDensityTexture3d(webgl: WebGLContext, position: Position
|
||||
return finalizeGaussianDensityTexture(data);
|
||||
}
|
||||
|
||||
function finalizeGaussianDensityTexture({ texture, scale, bbox, gridDim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius }: _GaussianDensityTextureData): GaussianDensityTextureData {
|
||||
return { transform: getTransform(scale, bbox), texture, bbox, gridDim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
function finalizeGaussianDensityTexture({ texture, scale, bbox, gridDim, gridTexDim, gridDataDim, gridTexScale, radiusFactor, resolution, maxRadius }: _GaussianDensityTextureData): GaussianDensityTextureData {
|
||||
return { transform: getTransform(scale, bbox), texture, bbox, gridDim, gridTexDim, gridDataDim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
function getTransform(scale: Vec3, bbox: Box3D) {
|
||||
@@ -118,6 +118,7 @@ type _GaussianDensityTextureData = {
|
||||
bbox: Box3D,
|
||||
gridDim: Vec3,
|
||||
gridTexDim: Vec3
|
||||
gridDataDim: Vec3
|
||||
gridTexScale: Vec2
|
||||
radiusFactor: number
|
||||
resolution: number
|
||||
@@ -206,7 +207,7 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat
|
||||
|
||||
// printTextureImage(readTexture(webgl, minDistTex), { scale: 0.75 });
|
||||
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim, gridDataDim: dim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps, texture?: Texture): _GaussianDensityTextureData {
|
||||
@@ -262,7 +263,7 @@ function calcGaussianDensityTexture3d(webgl: WebGLContext, position: PositionDat
|
||||
setupGroupIdRendering(webgl, renderable);
|
||||
render(texture, false);
|
||||
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim: dim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
return { texture, scale, bbox: expandedBox, gridDim: dim, gridTexDim: dim, gridDataDim: dim, gridTexScale, radiusFactor, resolution, maxRadius };
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
* ported from NGL (https://github.com/arose/ngl), licensed under MIT
|
||||
*/
|
||||
|
||||
import { Vec3, Tensor } from '../../mol-math/linear-algebra';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { RuntimeContext } from '../../mol-task';
|
||||
import { OrderedSet } from '../../mol-data/int';
|
||||
import { PositionData } from './common';
|
||||
import { Mat4 } from '../../mol-math/linear-algebra/3d/mat4';
|
||||
import { Box3D, GridLookup3D, fillGridDim } from '../../mol-math/geometry';
|
||||
import { BaseGeometry } from '../../mol-geo/geometry/base';
|
||||
import { OrderedSet } from '../../mol-data/int/ordered-set';
|
||||
import { fillGridDim, PositionData } from './common';
|
||||
import { Boundary } from './boundary';
|
||||
import { GridLookup3D } from './lookup3d/grid';
|
||||
import { Box3D } from './primitives/box3d';
|
||||
import { Vec3 } from '../linear-algebra/3d/vec3';
|
||||
import { Tensor } from '../linear-algebra/tensor';
|
||||
import { Mat4 } from '../linear-algebra/3d/mat4';
|
||||
|
||||
function normalToLine(out: Vec3, p: Vec3) {
|
||||
out[0] = out[1] = out[2] = 1.0;
|
||||
@@ -48,8 +49,8 @@ function getAngleTables(probePositions: number): AnglesTables {
|
||||
|
||||
export const MolecularSurfaceCalculationParams = {
|
||||
probeRadius: PD.Numeric(1.4, { min: 0, max: 10, step: 0.1 }, { description: 'Radius of the probe tracing the molecular surface.' }),
|
||||
resolution: PD.Numeric(0.5, { min: 0.01, max: 20, step: 0.01 }, { description: 'Grid resolution/cell spacing.', ...BaseGeometry.CustomQualityParamInfo }),
|
||||
probePositions: PD.Numeric(36, { min: 12, max: 90, step: 1 }, { description: 'Number of positions tested for probe target intersection.', ...BaseGeometry.CustomQualityParamInfo }),
|
||||
resolution: PD.Numeric(0.5, { min: 0.01, max: 20, step: 0.01 }, { description: 'Grid resolution/cell spacing.' }),
|
||||
probePositions: PD.Numeric(36, { min: 12, max: 90, step: 1 }, { description: 'Number of positions tested for probe target intersection.' }),
|
||||
};
|
||||
export const DefaultMolecularSurfaceCalculationProps = PD.getDefaultValues(MolecularSurfaceCalculationParams);
|
||||
export type MolecularSurfaceCalculationProps = typeof DefaultMolecularSurfaceCalculationProps
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
import { PositionData } from '../common';
|
||||
import { OrderedSet } from '../../../mol-data/int';
|
||||
import { OrderedSet } from '../../../mol-data/int/ordered-set';
|
||||
import { Sphere3D } from './sphere3d';
|
||||
import { Vec3 } from '../../linear-algebra/3d/vec3';
|
||||
import { Mat4 } from '../../linear-algebra/3d/mat4';
|
||||
|
||||
@@ -5,13 +5,15 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Vec3, Mat4, EPSILON } from '../../linear-algebra';
|
||||
import { PositionData } from '../common';
|
||||
import { OrderedSet } from '../../../mol-data/int';
|
||||
import { OrderedSet } from '../../../mol-data/int/ordered-set';
|
||||
import { NumberArray, PickRequired } from '../../../mol-util/type-helpers';
|
||||
import { Box3D } from './box3d';
|
||||
import { Axes3D } from './axes3d';
|
||||
import { PrincipalAxes } from '../../linear-algebra/matrix/principal-axes';
|
||||
import { Vec3 } from '../../linear-algebra/3d/vec3';
|
||||
import { Mat4 } from '../../linear-algebra/3d/mat4';
|
||||
import { EPSILON } from '../../linear-algebra/3d/common';
|
||||
|
||||
interface Sphere3D {
|
||||
center: Vec3,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { lerp as scalar_lerp } from '../../mol-math/interpolate';
|
||||
import { lerp as scalar_lerp } from '../interpolate';
|
||||
import { Mat3 } from '../linear-algebra/3d/mat3';
|
||||
import { Mat4 } from '../linear-algebra/3d/mat4';
|
||||
import { Quat } from '../linear-algebra/3d/quat';
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace Mat3 {
|
||||
}
|
||||
|
||||
export function hasNaN(m: Mat3) {
|
||||
for (let i = 0; i < 9; i++) if (isNaN(m[i])) return true;
|
||||
for (let i = 0; i < 9; i++) if (Number.isNaN(m[i])) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Mat4 {
|
||||
}
|
||||
|
||||
export function hasNaN(m: Mat4) {
|
||||
for (let i = 0; i < 16; i++) if (isNaN(m[i])) return true;
|
||||
for (let i = 0; i < 16; i++) if (Number.isNaN(m[i])) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
import { Mat4 } from './mat4';
|
||||
import { Vec3 } from './vec3';
|
||||
import { EVD } from '../matrix/evd';
|
||||
import { CentroidHelper } from '../../../mol-math/geometry/centroid-helper';
|
||||
import { Matrix } from '../matrix/matrix';
|
||||
import { Sphere3D } from '../../geometry/primitives/sphere3d';
|
||||
import { CentroidHelper } from '../../geometry/centroid-helper';
|
||||
|
||||
export { MinimizeRmsd };
|
||||
namespace MinimizeRmsd {
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Quat {
|
||||
}
|
||||
|
||||
export function hasNaN(q: Quat) {
|
||||
return isNaN(q[0]) || isNaN(q[1]) || isNaN(q[2]) || isNaN(q[3]);
|
||||
return Number.isNaN(q[0]) || Number.isNaN(q[1]) || Number.isNaN(q[2]) || Number.isNaN(q[3]);
|
||||
}
|
||||
|
||||
export function create(x: number, y: number, z: number, w: number) {
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Vec2 {
|
||||
}
|
||||
|
||||
export function hasNaN(a: Vec2) {
|
||||
return isNaN(a[0]) || isNaN(a[1]);
|
||||
return Number.isNaN(a[0]) || Number.isNaN(a[1]);
|
||||
}
|
||||
|
||||
export function toArray<T extends NumberArray>(a: Vec2, out: T, offset: number) {
|
||||
|
||||
@@ -52,8 +52,12 @@ export namespace Vec3 {
|
||||
return _isFinite(a[0]) && _isFinite(a[1]) && _isFinite(a[2]);
|
||||
}
|
||||
|
||||
export function isInteger(a: Vec3): boolean {
|
||||
return Number.isInteger(a[0]) && Number.isInteger(a[1]) && Number.isInteger(a[2]);
|
||||
}
|
||||
|
||||
export function hasNaN(a: Vec3) {
|
||||
return isNaN(a[0]) || isNaN(a[1]) || isNaN(a[2]);
|
||||
return Number.isNaN(a[0]) || Number.isNaN(a[1]) || Number.isNaN(a[2]);
|
||||
}
|
||||
|
||||
export function setNaN(out: Vec3) {
|
||||
@@ -573,8 +577,8 @@ export namespace Vec3 {
|
||||
const a0 = a[0], a1 = a[1], a2 = a[2];
|
||||
const b0 = b[0], b1 = b[1], b2 = b[2];
|
||||
return (Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
|
||||
Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
|
||||
Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
|
||||
Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
|
||||
Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)));
|
||||
}
|
||||
|
||||
const rotTemp = zero();
|
||||
@@ -620,8 +624,28 @@ export namespace Vec3 {
|
||||
}
|
||||
|
||||
/** Get a vector that is similar to `b` but orthogonal to `a` */
|
||||
export function orthogonalize(out: Vec3, a: Vec3, b: Vec3) {
|
||||
return normalize(out, cross(out, cross(out, a, b), a));
|
||||
export function orthogonalize(out: Vec3, a: Vec3, b: Vec3): Vec3 {
|
||||
// Regular case (`b` not parallel to `a`)
|
||||
normalize(out, cross(out, cross(out, a, b), a));
|
||||
if (!Vec3.isZero(out)) return out;
|
||||
|
||||
// `b` was parallel to `a`, try orthogonalize(a, X)
|
||||
out[0] = 1; out[1] = 0; out[2] = 0;
|
||||
normalize(out, cross(out, cross(out, a, out), a));
|
||||
if (!Vec3.isZero(out)) return out;
|
||||
|
||||
// `X` was parallel to `a`, try orthogonalize(a, Y)
|
||||
out[0] = 0; out[1] = 1; out[2] = 0;
|
||||
normalize(out, cross(out, cross(out, a, out), a));
|
||||
if (!Vec3.isZero(out)) return out;
|
||||
|
||||
// `a` was zero, return normalized `b`
|
||||
normalize(out, b);
|
||||
if (!Vec3.isZero(out)) return out;
|
||||
|
||||
// `b` was zero, return whatever
|
||||
out[0] = 1; out[1] = 0; out[2] = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
|
||||
import { Mat4 } from './mat4';
|
||||
import { NumberArray } from '../../../mol-util/type-helpers';
|
||||
import { Sphere3D } from '../../geometry/primitives/sphere3d';
|
||||
import { EPSILON } from './common';
|
||||
|
||||
type SphereLike = { center: number[], radius: number };
|
||||
|
||||
interface Vec4 extends Array<number> { [d: number]: number, '@type': 'vec4', length: 4 }
|
||||
|
||||
function Vec4() {
|
||||
@@ -54,7 +55,7 @@ namespace Vec4 {
|
||||
return out;
|
||||
}
|
||||
|
||||
export function fromSphere(out: Vec4, sphere: Sphere3D) {
|
||||
export function fromSphere(out: Vec4, sphere: SphereLike) {
|
||||
out[0] = sphere.center[0];
|
||||
out[1] = sphere.center[1];
|
||||
out[2] = sphere.center[2];
|
||||
@@ -62,12 +63,12 @@ namespace Vec4 {
|
||||
return out;
|
||||
}
|
||||
|
||||
export function ofSphere(sphere: Sphere3D) {
|
||||
export function ofSphere(sphere: SphereLike) {
|
||||
return fromSphere(zero(), sphere);
|
||||
}
|
||||
|
||||
export function hasNaN(a: Vec4) {
|
||||
return isNaN(a[0]) || isNaN(a[1]) || isNaN(a[2]) || isNaN(a[3]);
|
||||
return Number.isNaN(a[0]) || Number.isNaN(a[1]) || Number.isNaN(a[2]) || Number.isNaN(a[3]);
|
||||
}
|
||||
|
||||
export function toArray<T extends NumberArray>(a: Vec4, out: T, offset: number) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Mat3 } from './3d/mat3';
|
||||
/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
@@ -9,6 +8,7 @@ import { Mat3 } from './3d/mat3';
|
||||
import { Mat4 } from './3d/mat4';
|
||||
import { Vec3 } from './3d/vec3';
|
||||
import { Vec4 } from './3d/vec4';
|
||||
import { Mat3 } from './3d/mat3';
|
||||
|
||||
export interface Tensor { data: Tensor.Data, space: Tensor.Space }
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* @author Yana Rose <yana.v.rose@gmail.com>
|
||||
*/
|
||||
|
||||
import { substringStartsWith } from '../../../mol-util/string';
|
||||
import { CifCategory, CifField, CifFrame } from '../../../mol-io/reader/cif';
|
||||
import { Tokenizer } from '../../../mol-io/reader/common/text/tokenizer';
|
||||
import { PdbFile } from '../../../mol-io/reader/pdb/schema';
|
||||
@@ -23,6 +22,16 @@ import { parseConect } from './conect';
|
||||
import { isDebugMode } from '../../../mol-util/debug';
|
||||
import { PdbHeaderData, addHeader } from './header';
|
||||
import { mmCIF_Schema } from '../../../mol-io/reader/cif/schema/mmcif';
|
||||
import { StringLike } from '../../../mol-io/common/string-like';
|
||||
|
||||
function substringStartsWith(str: StringLike, start: number, end: number, target: string) {
|
||||
const len = target.length;
|
||||
if (len > end - start) return false;
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (str.charCodeAt(start + i) !== target.charCodeAt(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> {
|
||||
const { lines } = pdb;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { Volume } from '../../mol-model/volume';
|
||||
import { Grid, Volume } from '../../mol-model/volume';
|
||||
import { Task } from '../../mol-task';
|
||||
import { SpacegroupCell, Box3D } from '../../mol-math/geometry';
|
||||
import { Mat4, Tensor, Vec3 } from '../../mol-math/linear-algebra';
|
||||
@@ -71,19 +71,22 @@ export function volumeFromCcp4(source: Ccp4File, params?: { voxelSize?: Vec3, of
|
||||
// always calculate stats when all stats related values are zero
|
||||
const calcStats = header.AMIN === 0 && header.AMAX === 0 && header.AMEAN === 0 && header.ARMS === 0;
|
||||
|
||||
const volgrid: Grid = {
|
||||
transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3(), origin_frac, dimensions_frac)) },
|
||||
cells: data,
|
||||
stats: {
|
||||
min: (Number.isNaN(header.AMIN) || calcStats) ? arrayMin(values) : header.AMIN,
|
||||
max: (Number.isNaN(header.AMAX) || calcStats) ? arrayMax(values) : header.AMAX,
|
||||
mean: (Number.isNaN(header.AMEAN) || calcStats) ? arrayMean(values) : header.AMEAN,
|
||||
sigma: (Number.isNaN(header.ARMS) || header.ARMS === 0) ? arrayRms(values) : header.ARMS
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
label: params?.label,
|
||||
entryId: params?.entryId,
|
||||
grid: {
|
||||
transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) },
|
||||
cells: data,
|
||||
stats: {
|
||||
min: (isNaN(header.AMIN) || calcStats) ? arrayMin(values) : header.AMIN,
|
||||
max: (isNaN(header.AMAX) || calcStats) ? arrayMax(values) : header.AMAX,
|
||||
mean: (isNaN(header.AMEAN) || calcStats) ? arrayMean(values) : header.AMEAN,
|
||||
sigma: (isNaN(header.ARMS) || header.ARMS === 0) ? arrayRms(values) : header.ARMS
|
||||
},
|
||||
},
|
||||
periodicity: Vec3.isInteger(dimensions_frac) ? 'xyz' : 'none',
|
||||
grid: volgrid,
|
||||
instances: [{ transform: Mat4.identity() }],
|
||||
sourceData: Ccp4Format.create(source),
|
||||
customProperties: new CustomProperties(),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2018-2025 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 { DensityServer_Data_Database } from '../../mol-io/reader/cif/schema/density-server';
|
||||
@@ -38,6 +39,7 @@ export function volumeFromDensityServerData(source: DensityServer_Data_Database,
|
||||
return {
|
||||
label: params?.label,
|
||||
entryId: params?.entryId,
|
||||
periodicity: Vec3.isInteger(dimensions) ? 'xyz' : 'none',
|
||||
grid: {
|
||||
transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin, Vec3.add(Vec3.zero(), origin, dimensions)) },
|
||||
cells: data,
|
||||
|
||||
@@ -36,6 +36,7 @@ export function volumeFromDsn6(source: Dsn6File, params?: { voxelSize?: Vec3, la
|
||||
return {
|
||||
label: params?.label,
|
||||
entryId: params?.entryId,
|
||||
periodicity: Vec3.isInteger(dimensions_frac) ? 'xyz' : 'none',
|
||||
grid: {
|
||||
transform: { kind: 'spacegroup', cell, fractionalBox: Box3D.create(origin_frac, Vec3.add(Vec3.zero(), origin_frac, dimensions_frac)) },
|
||||
cells: data,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user