cosmol-viewer 0.1.0__tar.gz → 0.1.1.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cosmol-viewer might be problematic. Click here for more details.
- {cosmol_viewer-0.1.0 → cosmol_viewer-0.1.1.dev2}/Cargo.lock +143 -9
- cosmol_viewer-0.1.1.dev2/Cargo.toml +22 -0
- {cosmol_viewer-0.1.0 → cosmol_viewer-0.1.1.dev2}/PKG-INFO +1 -1
- {cosmol_viewer-0.1.0/cosmol_viewer_core → cosmol_viewer-0.1.1.dev2/crates/core}/Cargo.toml +4 -0
- cosmol_viewer-0.1.1.dev2/crates/core/src/lib.rs +72 -0
- cosmol_viewer-0.1.1.dev2/crates/core/src/parser/mod.rs +2 -0
- cosmol_viewer-0.1.1.dev2/crates/core/src/parser/sdf.rs +197 -0
- cosmol_viewer-0.1.1.dev2/crates/core/src/scene.rs +63 -0
- cosmol_viewer-0.1.0/cosmol_viewer_core/src/shader/app.rs → cosmol_viewer-0.1.1.dev2/crates/core/src/shader/canvas.rs +111 -62
- {cosmol_viewer-0.1.0/cosmol_viewer_core → cosmol_viewer-0.1.1.dev2/crates/core}/src/shader/fragment.glsl +2 -4
- cosmol_viewer-0.1.1.dev2/crates/core/src/shader/mod.rs +3 -0
- {cosmol_viewer-0.1.0/cosmol_viewer_core → cosmol_viewer-0.1.1.dev2/crates/core}/src/shader/vertex.glsl +1 -1
- cosmol_viewer-0.1.1.dev2/crates/core/src/shapes/mod.rs +3 -0
- cosmol_viewer-0.1.1.dev2/crates/core/src/shapes/molecules.rs +276 -0
- cosmol_viewer-0.1.0/cosmol_viewer_core/src/utils.rs → cosmol_viewer-0.1.1.dev2/crates/core/src/shapes/sphere.rs +31 -62
- cosmol_viewer-0.1.1.dev2/crates/core/src/shapes/stick.rs +153 -0
- cosmol_viewer-0.1.1.dev2/crates/core/src/utils.rs +85 -0
- {cosmol_viewer-0.1.0/cosmol_viewer_python → cosmol_viewer-0.1.1.dev2/crates/python}/Cargo.toml +6 -2
- cosmol_viewer-0.1.1.dev2/crates/python/build.rs +22 -0
- cosmol_viewer-0.1.1.dev2/crates/python/src/lib.rs +342 -0
- cosmol_viewer-0.1.1.dev2/crates/python/src/parser.rs +24 -0
- cosmol_viewer-0.1.1.dev2/crates/python/src/shapes.rs +97 -0
- {cosmol_viewer-0.1.0 → cosmol_viewer-0.1.1.dev2}/pyproject.toml +6 -7
- cosmol_viewer-0.1.0/Cargo.toml +0 -15
- cosmol_viewer-0.1.0/cosmol_viewer_core/src/lib.rs +0 -113
- cosmol_viewer-0.1.0/cosmol_viewer_core/src/shader/mod.rs +0 -3
- cosmol_viewer-0.1.0/cosmol_viewer_python/build.rs +0 -22
- cosmol_viewer-0.1.0/cosmol_viewer_python/src/lib.rs +0 -150
- {cosmol_viewer-0.1.0/cosmol_viewer_core → cosmol_viewer-0.1.1.dev2/crates/core}/src/shader/bg_fragment.glsl +0 -0
- {cosmol_viewer-0.1.0/cosmol_viewer_core → cosmol_viewer-0.1.1.dev2/crates/core}/src/shader/bg_vertex.glsl +0 -0
|
@@ -431,6 +431,15 @@ version = "0.22.1"
|
|
|
431
431
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
432
432
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|
433
433
|
|
|
434
|
+
[[package]]
|
|
435
|
+
name = "bincode"
|
|
436
|
+
version = "1.3.3"
|
|
437
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
438
|
+
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
|
439
|
+
dependencies = [
|
|
440
|
+
"serde",
|
|
441
|
+
]
|
|
442
|
+
|
|
434
443
|
[[package]]
|
|
435
444
|
name = "bit-set"
|
|
436
445
|
version = "0.8.0"
|
|
@@ -688,35 +697,75 @@ dependencies = [
|
|
|
688
697
|
"libc",
|
|
689
698
|
]
|
|
690
699
|
|
|
700
|
+
[[package]]
|
|
701
|
+
name = "cosmol_viewer"
|
|
702
|
+
version = "0.1.1-nightly.2"
|
|
703
|
+
dependencies = [
|
|
704
|
+
"bytemuck",
|
|
705
|
+
"cosmol_viewer_core",
|
|
706
|
+
"eframe",
|
|
707
|
+
"egui_extras",
|
|
708
|
+
"glam",
|
|
709
|
+
"hex",
|
|
710
|
+
"ipc-channel",
|
|
711
|
+
"serde",
|
|
712
|
+
"serde_json",
|
|
713
|
+
"sha2",
|
|
714
|
+
"wasm-bindgen-futures",
|
|
715
|
+
"web-sys",
|
|
716
|
+
]
|
|
717
|
+
|
|
691
718
|
[[package]]
|
|
692
719
|
name = "cosmol_viewer_core"
|
|
693
|
-
version = "0.1.
|
|
720
|
+
version = "0.1.1-nightly.2"
|
|
721
|
+
dependencies = [
|
|
722
|
+
"bytemuck",
|
|
723
|
+
"eframe",
|
|
724
|
+
"egui_extras",
|
|
725
|
+
"glam",
|
|
726
|
+
"serde",
|
|
727
|
+
"serde_json",
|
|
728
|
+
"wasm-bindgen-futures",
|
|
729
|
+
"web-sys",
|
|
730
|
+
]
|
|
731
|
+
|
|
732
|
+
[[package]]
|
|
733
|
+
name = "cosmol_viewer_gui"
|
|
734
|
+
version = "0.1.1-nightly.2"
|
|
694
735
|
dependencies = [
|
|
695
736
|
"bytemuck",
|
|
737
|
+
"cosmol_viewer_core",
|
|
696
738
|
"eframe",
|
|
697
739
|
"egui_extras",
|
|
698
740
|
"glam",
|
|
741
|
+
"ipc-channel",
|
|
699
742
|
"serde",
|
|
743
|
+
"serde_json",
|
|
744
|
+
"wasm-bindgen-futures",
|
|
745
|
+
"web-sys",
|
|
700
746
|
]
|
|
701
747
|
|
|
702
748
|
[[package]]
|
|
703
749
|
name = "cosmol_viewer_python"
|
|
704
|
-
version = "0.
|
|
750
|
+
version = "0.0.0"
|
|
705
751
|
dependencies = [
|
|
706
752
|
"base64 0.22.1",
|
|
707
753
|
"cosmol_viewer_core",
|
|
708
754
|
"eframe",
|
|
709
755
|
"egui_extras",
|
|
710
756
|
"glam",
|
|
757
|
+
"hex",
|
|
758
|
+
"ipc-channel",
|
|
711
759
|
"pyo3",
|
|
712
760
|
"serde_json",
|
|
761
|
+
"sha2",
|
|
713
762
|
"uuid",
|
|
714
763
|
"wasm-bindgen",
|
|
715
764
|
]
|
|
716
765
|
|
|
717
766
|
[[package]]
|
|
718
767
|
name = "cosmol_viewer_wasm"
|
|
719
|
-
version = "0.1.
|
|
768
|
+
version = "0.1.1-nightly.2"
|
|
720
769
|
dependencies = [
|
|
721
770
|
"cosmol_viewer_core",
|
|
722
771
|
"eframe",
|
|
@@ -747,6 +796,15 @@ dependencies = [
|
|
|
747
796
|
"cfg-if",
|
|
748
797
|
]
|
|
749
798
|
|
|
799
|
+
[[package]]
|
|
800
|
+
name = "crossbeam-channel"
|
|
801
|
+
version = "0.5.15"
|
|
802
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
803
|
+
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
|
804
|
+
dependencies = [
|
|
805
|
+
"crossbeam-utils",
|
|
806
|
+
]
|
|
807
|
+
|
|
750
808
|
[[package]]
|
|
751
809
|
name = "crossbeam-utils"
|
|
752
810
|
version = "0.8.21"
|
|
@@ -1132,6 +1190,12 @@ version = "0.9.0"
|
|
|
1132
1190
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1133
1191
|
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
|
1134
1192
|
|
|
1193
|
+
[[package]]
|
|
1194
|
+
name = "fnv"
|
|
1195
|
+
version = "1.0.7"
|
|
1196
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1197
|
+
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
1198
|
+
|
|
1135
1199
|
[[package]]
|
|
1136
1200
|
name = "foldhash"
|
|
1137
1201
|
version = "0.1.5"
|
|
@@ -1603,6 +1667,24 @@ version = "2.0.6"
|
|
|
1603
1667
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1604
1668
|
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
|
1605
1669
|
|
|
1670
|
+
[[package]]
|
|
1671
|
+
name = "ipc-channel"
|
|
1672
|
+
version = "0.20.0"
|
|
1673
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1674
|
+
checksum = "5b1c98b70019c830a1fc39cecfe1f60ff99c4122f0a189697c810c90ec545c14"
|
|
1675
|
+
dependencies = [
|
|
1676
|
+
"bincode",
|
|
1677
|
+
"crossbeam-channel",
|
|
1678
|
+
"fnv",
|
|
1679
|
+
"libc",
|
|
1680
|
+
"mio",
|
|
1681
|
+
"rand 0.9.1",
|
|
1682
|
+
"serde",
|
|
1683
|
+
"tempfile",
|
|
1684
|
+
"uuid",
|
|
1685
|
+
"windows",
|
|
1686
|
+
]
|
|
1687
|
+
|
|
1606
1688
|
[[package]]
|
|
1607
1689
|
name = "itoa"
|
|
1608
1690
|
version = "1.0.15"
|
|
@@ -1826,6 +1908,17 @@ dependencies = [
|
|
|
1826
1908
|
"simd-adler32",
|
|
1827
1909
|
]
|
|
1828
1910
|
|
|
1911
|
+
[[package]]
|
|
1912
|
+
name = "mio"
|
|
1913
|
+
version = "1.0.4"
|
|
1914
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1915
|
+
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
|
1916
|
+
dependencies = [
|
|
1917
|
+
"libc",
|
|
1918
|
+
"wasi 0.11.1+wasi-snapshot-preview1",
|
|
1919
|
+
"windows-sys 0.59.0",
|
|
1920
|
+
]
|
|
1921
|
+
|
|
1829
1922
|
[[package]]
|
|
1830
1923
|
name = "naga"
|
|
1831
1924
|
version = "24.0.0"
|
|
@@ -2318,7 +2411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
2318
2411
|
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
|
2319
2412
|
dependencies = [
|
|
2320
2413
|
"phf_shared",
|
|
2321
|
-
"rand",
|
|
2414
|
+
"rand 0.8.5",
|
|
2322
2415
|
]
|
|
2323
2416
|
|
|
2324
2417
|
[[package]]
|
|
@@ -2579,8 +2672,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
2579
2672
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
2580
2673
|
dependencies = [
|
|
2581
2674
|
"libc",
|
|
2582
|
-
"rand_chacha",
|
|
2583
|
-
"rand_core",
|
|
2675
|
+
"rand_chacha 0.3.1",
|
|
2676
|
+
"rand_core 0.6.4",
|
|
2677
|
+
]
|
|
2678
|
+
|
|
2679
|
+
[[package]]
|
|
2680
|
+
name = "rand"
|
|
2681
|
+
version = "0.9.1"
|
|
2682
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2683
|
+
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
|
2684
|
+
dependencies = [
|
|
2685
|
+
"rand_chacha 0.9.0",
|
|
2686
|
+
"rand_core 0.9.3",
|
|
2584
2687
|
]
|
|
2585
2688
|
|
|
2586
2689
|
[[package]]
|
|
@@ -2590,7 +2693,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
2590
2693
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
2591
2694
|
dependencies = [
|
|
2592
2695
|
"ppv-lite86",
|
|
2593
|
-
"rand_core",
|
|
2696
|
+
"rand_core 0.6.4",
|
|
2697
|
+
]
|
|
2698
|
+
|
|
2699
|
+
[[package]]
|
|
2700
|
+
name = "rand_chacha"
|
|
2701
|
+
version = "0.9.0"
|
|
2702
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2703
|
+
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
|
2704
|
+
dependencies = [
|
|
2705
|
+
"ppv-lite86",
|
|
2706
|
+
"rand_core 0.9.3",
|
|
2594
2707
|
]
|
|
2595
2708
|
|
|
2596
2709
|
[[package]]
|
|
@@ -2602,6 +2715,15 @@ dependencies = [
|
|
|
2602
2715
|
"getrandom 0.2.16",
|
|
2603
2716
|
]
|
|
2604
2717
|
|
|
2718
|
+
[[package]]
|
|
2719
|
+
name = "rand_core"
|
|
2720
|
+
version = "0.9.3"
|
|
2721
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2722
|
+
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
|
2723
|
+
dependencies = [
|
|
2724
|
+
"getrandom 0.3.3",
|
|
2725
|
+
]
|
|
2726
|
+
|
|
2605
2727
|
[[package]]
|
|
2606
2728
|
name = "raw-window-handle"
|
|
2607
2729
|
version = "0.6.2"
|
|
@@ -2805,6 +2927,17 @@ dependencies = [
|
|
|
2805
2927
|
"digest",
|
|
2806
2928
|
]
|
|
2807
2929
|
|
|
2930
|
+
[[package]]
|
|
2931
|
+
name = "sha2"
|
|
2932
|
+
version = "0.10.9"
|
|
2933
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2934
|
+
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
|
2935
|
+
dependencies = [
|
|
2936
|
+
"cfg-if",
|
|
2937
|
+
"cpufeatures",
|
|
2938
|
+
"digest",
|
|
2939
|
+
]
|
|
2940
|
+
|
|
2808
2941
|
[[package]]
|
|
2809
2942
|
name = "shlex"
|
|
2810
2943
|
version = "1.3.0"
|
|
@@ -3027,8 +3160,9 @@ dependencies = [
|
|
|
3027
3160
|
|
|
3028
3161
|
[[package]]
|
|
3029
3162
|
name = "test"
|
|
3030
|
-
version = "0.1.
|
|
3163
|
+
version = "0.1.1-nightly.2"
|
|
3031
3164
|
dependencies = [
|
|
3165
|
+
"cosmol_viewer",
|
|
3032
3166
|
"cosmol_viewer_core",
|
|
3033
3167
|
"eframe",
|
|
3034
3168
|
"egui_extras",
|
|
@@ -4242,7 +4376,7 @@ dependencies = [
|
|
|
4242
4376
|
"hex",
|
|
4243
4377
|
"nix",
|
|
4244
4378
|
"ordered-stream",
|
|
4245
|
-
"rand",
|
|
4379
|
+
"rand 0.8.5",
|
|
4246
4380
|
"serde",
|
|
4247
4381
|
"serde_repr",
|
|
4248
4382
|
"sha1",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[workspace.package]
|
|
2
|
+
edition = "2024"
|
|
3
|
+
version = "0.1.1-nightly.2"
|
|
4
|
+
authors = ["9028 wjt@cosmol.org"]
|
|
5
|
+
repository = "https://github.com/COSMol-repl/COSMol-viewer"
|
|
6
|
+
homepage = "https://github.com/COSMol-repl/COSMol-viewer"
|
|
7
|
+
keywords = ["molecular", "visualization"]
|
|
8
|
+
|
|
9
|
+
[workspace]
|
|
10
|
+
resolver = "2"
|
|
11
|
+
members = ["crates/python"]
|
|
12
|
+
|
|
13
|
+
[workspace.dependencies]
|
|
14
|
+
cosmol_viewer = {path = "cosmol_viewer"}
|
|
15
|
+
cosmol_viewer_core = { path = "crates/core" }
|
|
16
|
+
eframe = { version = "0.31.1"}
|
|
17
|
+
egui_extras = { version = "0.31.1", features = ["svg"] }
|
|
18
|
+
glam = { version = "0.30.3" , features = ["serde"] }
|
|
19
|
+
serde_json = "1.0.140"
|
|
20
|
+
sha2 = "0.10.9"
|
|
21
|
+
hex = "0.4.3"
|
|
22
|
+
ipc-channel = "0.20.0"
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
name = "cosmol_viewer_core"
|
|
3
3
|
version.workspace = true
|
|
4
4
|
edition = "2024"
|
|
5
|
+
publish = false
|
|
5
6
|
|
|
6
7
|
[dependencies]
|
|
7
8
|
eframe.workspace = true
|
|
9
|
+
serde_json.workspace = true
|
|
8
10
|
glam.workspace = true
|
|
9
11
|
egui_extras.workspace = true
|
|
10
12
|
serde = { version = "1.0.219" , features = ["derive"] }
|
|
11
13
|
bytemuck = "1.23.1"
|
|
14
|
+
web-sys = "0.3.77"
|
|
15
|
+
wasm-bindgen-futures = "0.4.50"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
mod shader;
|
|
2
|
+
use std::{
|
|
3
|
+
sync::{Arc, Mutex},
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
pub mod utils;
|
|
7
|
+
pub mod parser;
|
|
8
|
+
|
|
9
|
+
use eframe::egui::{self, Color32, Stroke};
|
|
10
|
+
|
|
11
|
+
use shader::Canvas;
|
|
12
|
+
|
|
13
|
+
pub use crate::utils::{Shape};
|
|
14
|
+
pub mod shapes;
|
|
15
|
+
use crate::{scene::Scene};
|
|
16
|
+
|
|
17
|
+
pub mod scene;
|
|
18
|
+
|
|
19
|
+
pub struct AppWrapper(pub Arc<Mutex<Option<App>>>);
|
|
20
|
+
|
|
21
|
+
impl eframe::App for AppWrapper {
|
|
22
|
+
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
|
23
|
+
if let Some(app) = &mut *self.0.lock().unwrap() {
|
|
24
|
+
app.update(ctx, frame);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pub struct App {
|
|
30
|
+
canvas: Canvas,
|
|
31
|
+
gl: Option<Arc<eframe::glow::Context>>,
|
|
32
|
+
pub ctx: egui::Context,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
impl App {
|
|
36
|
+
// #[cfg(not(target_arch = "wasm32"))]
|
|
37
|
+
pub fn new(cc: &eframe::CreationContext<'_>, scene: Scene) -> Self {
|
|
38
|
+
let gl = cc.gl.clone();
|
|
39
|
+
let canvas = Canvas::new(gl.as_ref().unwrap().clone(), scene).unwrap();
|
|
40
|
+
App {
|
|
41
|
+
gl,
|
|
42
|
+
canvas,
|
|
43
|
+
ctx: cc.egui_ctx.clone(),
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn update_scene(&mut self, scene: Scene) {
|
|
48
|
+
self.canvas.update_scene(scene);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
impl eframe::App for App {
|
|
53
|
+
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
|
54
|
+
egui_extras::install_image_loaders(ctx);
|
|
55
|
+
egui::CentralPanel::default()
|
|
56
|
+
.frame(
|
|
57
|
+
egui::Frame::default()
|
|
58
|
+
.fill(Color32::from_rgb(48, 48, 48))
|
|
59
|
+
.inner_margin(0.0)
|
|
60
|
+
.outer_margin(0.0)
|
|
61
|
+
.stroke(Stroke::new(0.0, Color32::from_rgb(30, 200, 30))),
|
|
62
|
+
)
|
|
63
|
+
.show(ctx, |ui| {
|
|
64
|
+
ui.set_width(ui.available_width());
|
|
65
|
+
ui.set_height(ui.available_height());
|
|
66
|
+
|
|
67
|
+
self.canvas.custom_painting(ui);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#[derive(Debug, Clone)]
|
|
2
|
+
pub struct Atom {
|
|
3
|
+
pub atom: String,
|
|
4
|
+
pub elem: String,
|
|
5
|
+
pub x: f32,
|
|
6
|
+
pub y: f32,
|
|
7
|
+
pub z: f32,
|
|
8
|
+
pub serial: usize,
|
|
9
|
+
pub index: usize,
|
|
10
|
+
pub hetflag: bool,
|
|
11
|
+
pub bonds: Vec<usize>,
|
|
12
|
+
pub bond_order: Vec<f32>,
|
|
13
|
+
pub properties: std::collections::HashMap<String, String>,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
pub type Molecule = Vec<Atom>;
|
|
17
|
+
pub type MoleculeData = Vec<Molecule>;
|
|
18
|
+
|
|
19
|
+
#[derive(Default)]
|
|
20
|
+
pub struct ParserOptions {
|
|
21
|
+
pub keep_h: bool,
|
|
22
|
+
pub multimodel: bool,
|
|
23
|
+
pub onemol: bool,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pub fn parse_sdf(sdf: &str, options: &ParserOptions) -> MoleculeData {
|
|
27
|
+
let lines: Vec<&str> = sdf.lines().collect();
|
|
28
|
+
if lines.len() > 3 && lines[3].len() > 38 {
|
|
29
|
+
let version = lines[3][34..39].trim();
|
|
30
|
+
match version {
|
|
31
|
+
"V3000" => parse_v3000(lines, options),
|
|
32
|
+
_ => parse_v2000(lines, options),
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
vec![vec![]]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fn parse_v2000(mut lines: Vec<&str>, options: &ParserOptions) -> MoleculeData {
|
|
40
|
+
let mut molecules = vec![vec![]];
|
|
41
|
+
let mut current = 0;
|
|
42
|
+
|
|
43
|
+
while lines.len() >= 4 {
|
|
44
|
+
let header = lines[3];
|
|
45
|
+
let atom_count = header[0..3].trim().parse::<usize>().unwrap_or(0);
|
|
46
|
+
let bond_count = header[3..6].trim().parse::<usize>().unwrap_or(0);
|
|
47
|
+
|
|
48
|
+
if atom_count == 0 || lines.len() < 4 + atom_count + bond_count {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let mut serial_to_index = vec![None; atom_count];
|
|
53
|
+
let mut offset = 4;
|
|
54
|
+
let start = molecules[current].len();
|
|
55
|
+
|
|
56
|
+
for i in 0..atom_count {
|
|
57
|
+
let line = lines[offset + i];
|
|
58
|
+
let elem = line[31..34].trim();
|
|
59
|
+
let elem_cap = capitalize(elem);
|
|
60
|
+
if elem_cap != "H" || options.keep_h {
|
|
61
|
+
let atom = Atom {
|
|
62
|
+
atom: elem_cap.clone(),
|
|
63
|
+
elem: elem_cap,
|
|
64
|
+
x: line[0..10].trim().parse().unwrap_or(0.0),
|
|
65
|
+
y: line[10..20].trim().parse().unwrap_or(0.0),
|
|
66
|
+
z: line[20..30].trim().parse().unwrap_or(0.0),
|
|
67
|
+
serial: start + i,
|
|
68
|
+
index: molecules[current].len(),
|
|
69
|
+
hetflag: true,
|
|
70
|
+
bonds: vec![],
|
|
71
|
+
bond_order: vec![],
|
|
72
|
+
properties: std::collections::HashMap::new(),
|
|
73
|
+
};
|
|
74
|
+
serial_to_index[i] = Some(molecules[current].len());
|
|
75
|
+
molecules[current].push(atom);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
offset += atom_count;
|
|
80
|
+
|
|
81
|
+
for i in 0..bond_count {
|
|
82
|
+
let line = lines[offset + i];
|
|
83
|
+
let from = line[0..3].trim().parse::<usize>().unwrap_or(0).saturating_sub(1);
|
|
84
|
+
let to = line[3..6].trim().parse::<usize>().unwrap_or(0).saturating_sub(1);
|
|
85
|
+
let order = line[6..].trim().parse::<f32>().unwrap_or(1.0);
|
|
86
|
+
if let (Some(f), Some(t)) = (serial_to_index.get(from).and_then(|x| *x), serial_to_index.get(to).and_then(|x| *x)) {
|
|
87
|
+
molecules[current][f].bonds.push(t);
|
|
88
|
+
molecules[current][f].bond_order.push(order);
|
|
89
|
+
molecules[current][t].bonds.push(f);
|
|
90
|
+
molecules[current][t].bond_order.push(order);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let mut next_offset = offset + bond_count;
|
|
95
|
+
if options.multimodel {
|
|
96
|
+
if !options.onemol {
|
|
97
|
+
molecules.push(vec![]);
|
|
98
|
+
current += 1;
|
|
99
|
+
}
|
|
100
|
+
while next_offset < lines.len() && lines[next_offset] != "$$$$" {
|
|
101
|
+
next_offset += 1;
|
|
102
|
+
}
|
|
103
|
+
lines.drain(0..=next_offset);
|
|
104
|
+
} else {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
molecules
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn parse_v3000(mut lines: Vec<&str>, options: &ParserOptions) -> MoleculeData {
|
|
113
|
+
let mut molecules = vec![vec![]];
|
|
114
|
+
let mut current = 0;
|
|
115
|
+
|
|
116
|
+
while lines.len() >= 8 {
|
|
117
|
+
if !lines[4].starts_with("M V30 BEGIN CTAB") || !lines[5].starts_with("M V30 COUNTS") {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let counts: Vec<_> = lines[5][13..].split_whitespace().collect();
|
|
122
|
+
let atom_count = counts.get(0).and_then(|s| s.parse::<usize>().ok()).unwrap_or(0);
|
|
123
|
+
let bond_count = counts.get(1).and_then(|s| s.parse::<usize>().ok()).unwrap_or(0);
|
|
124
|
+
let mut offset = 7;
|
|
125
|
+
|
|
126
|
+
let mut serial_to_index = vec![None; atom_count];
|
|
127
|
+
let start = molecules[current].len();
|
|
128
|
+
|
|
129
|
+
for i in 0..atom_count {
|
|
130
|
+
let line = lines[offset + i];
|
|
131
|
+
let parts: Vec<_> = line[6..].split_whitespace().collect();
|
|
132
|
+
if parts.len() > 4 {
|
|
133
|
+
let elem_cap = capitalize(parts[1]);
|
|
134
|
+
if elem_cap != "H" || options.keep_h {
|
|
135
|
+
let atom = Atom {
|
|
136
|
+
atom: elem_cap.clone(),
|
|
137
|
+
elem: elem_cap,
|
|
138
|
+
x: parts[2].parse().unwrap_or(0.0),
|
|
139
|
+
y: parts[3].parse().unwrap_or(0.0),
|
|
140
|
+
z: parts[4].parse().unwrap_or(0.0),
|
|
141
|
+
serial: start + i,
|
|
142
|
+
index: molecules[current].len(),
|
|
143
|
+
hetflag: true,
|
|
144
|
+
bonds: vec![],
|
|
145
|
+
bond_order: vec![],
|
|
146
|
+
properties: std::collections::HashMap::new(),
|
|
147
|
+
};
|
|
148
|
+
serial_to_index[i] = Some(molecules[current].len());
|
|
149
|
+
molecules[current].push(atom);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
offset += atom_count + 1; // skip "END ATOM"
|
|
155
|
+
offset += 1; // BEGIN BOND
|
|
156
|
+
|
|
157
|
+
for i in 0..bond_count {
|
|
158
|
+
let line = lines[offset + i];
|
|
159
|
+
let parts: Vec<_> = line[6..].split_whitespace().collect();
|
|
160
|
+
if parts.len() > 3 {
|
|
161
|
+
let from = parts[2].parse::<usize>().unwrap_or(0).saturating_sub(1);
|
|
162
|
+
let to = parts[3].parse::<usize>().unwrap_or(0).saturating_sub(1);
|
|
163
|
+
let order = parts[1].parse::<f32>().unwrap_or(1.0);
|
|
164
|
+
if let (Some(f), Some(t)) = (serial_to_index.get(from).and_then(|x| *x), serial_to_index.get(to).and_then(|x| *x)) {
|
|
165
|
+
molecules[current][f].bonds.push(t);
|
|
166
|
+
molecules[current][f].bond_order.push(order);
|
|
167
|
+
molecules[current][t].bonds.push(f);
|
|
168
|
+
molecules[current][t].bond_order.push(order);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let mut next_offset = offset + bond_count;
|
|
174
|
+
if options.multimodel {
|
|
175
|
+
if !options.onemol {
|
|
176
|
+
molecules.push(vec![]);
|
|
177
|
+
current += 1;
|
|
178
|
+
}
|
|
179
|
+
while next_offset < lines.len() && lines[next_offset] != "$$$$" {
|
|
180
|
+
next_offset += 1;
|
|
181
|
+
}
|
|
182
|
+
lines.drain(0..=next_offset);
|
|
183
|
+
} else {
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
molecules
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fn capitalize(s: &str) -> String {
|
|
192
|
+
let mut chars = s.chars();
|
|
193
|
+
match chars.next() {
|
|
194
|
+
Some(first) => first.to_ascii_uppercase().to_string() + &chars.as_str().to_ascii_lowercase(),
|
|
195
|
+
None => String::new(),
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use serde::{Deserialize, Serialize};
|
|
4
|
+
|
|
5
|
+
use crate::{shader::CameraState, utils::{self, ToMesh}, Shape};
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
#[derive(Deserialize, Serialize, Clone)]
|
|
9
|
+
pub struct Scene {
|
|
10
|
+
pub background_color: [f32; 3],
|
|
11
|
+
pub camera_state: CameraState,
|
|
12
|
+
pub named_shapes: HashMap<String, Shape>,
|
|
13
|
+
pub unnamed_shapes: Vec<Shape>,
|
|
14
|
+
pub scale: f32,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl Scene {
|
|
18
|
+
pub fn _get_meshes(&self) -> Vec<utils::MeshData> {
|
|
19
|
+
self.named_shapes
|
|
20
|
+
.values()
|
|
21
|
+
.chain(self.unnamed_shapes.iter())
|
|
22
|
+
.map(|s| s.to_mesh(self.scale))
|
|
23
|
+
.collect()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pub fn new() -> Self {
|
|
27
|
+
Scene {
|
|
28
|
+
background_color: [1.0, 1.0, 1.0],
|
|
29
|
+
camera_state: CameraState::new(1.0),
|
|
30
|
+
named_shapes: HashMap::new(),
|
|
31
|
+
unnamed_shapes: Vec::new(),
|
|
32
|
+
scale: 1.0,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn scale(&mut self, scale: f32) {
|
|
37
|
+
self.scale = scale;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn add_shape<S: Into<Shape>>(&mut self, shape: S, id: Option<&str>) {
|
|
41
|
+
let shape = shape.into();
|
|
42
|
+
if let Some(id) = id {
|
|
43
|
+
self.named_shapes.insert(id.into(), shape);
|
|
44
|
+
} else {
|
|
45
|
+
self.unnamed_shapes.push(shape);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn delete_shape(&mut self, id: &str) {
|
|
50
|
+
if self.named_shapes.remove(id).is_none() {
|
|
51
|
+
panic!("Sphere with ID '{}' not found", id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn update_shape<S: Into<Shape>>(&mut self, id: &str, shape: S) {
|
|
56
|
+
let shape = shape.into();
|
|
57
|
+
if let Some(existing_shape) = self.named_shapes.get_mut(id) {
|
|
58
|
+
*existing_shape = shape;
|
|
59
|
+
} else {
|
|
60
|
+
panic!("Shape with ID '{}' not found", id);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|