Browse Source

Split into bin and lib, add clap, binary format

Tyler Hallada 4 years ago
parent
commit
74eac6115e
4 changed files with 370 additions and 89 deletions
  1. 106 0
      Cargo.lock
  2. 11 0
      Cargo.toml
  3. 169 0
      src/bin.rs
  4. 84 89
      src/lib.rs

+ 106 - 0
Cargo.lock

@@ -1,3 +1,13 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+[[package]]
4
+name = "ansi_term"
5
+version = "0.11.0"
6
+source = "registry+https://github.com/rust-lang/crates.io-index"
7
+dependencies = [
8
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
9
+]
10
+
1 11
 [[package]]
2 12
 name = "approx"
3 13
 version = "0.3.1"
@@ -6,6 +16,16 @@ dependencies = [
6 16
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
7 17
 ]
8 18
 
19
+[[package]]
20
+name = "atty"
21
+version = "0.2.11"
22
+source = "registry+https://github.com/rust-lang/crates.io-index"
23
+dependencies = [
24
+ "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
25
+ "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
26
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
27
+]
28
+
9 29
 [[package]]
10 30
 name = "autocfg"
11 31
 version = "0.1.2"
@@ -16,6 +36,11 @@ name = "bitflags"
16 36
 version = "1.0.4"
17 37
 source = "registry+https://github.com/rust-lang/crates.io-index"
18 38
 
39
+[[package]]
40
+name = "byteorder"
41
+version = "1.3.2"
42
+source = "registry+https://github.com/rust-lang/crates.io-index"
43
+
19 44
 [[package]]
20 45
 name = "cgmath"
21 46
 version = "0.17.0"
@@ -27,6 +52,20 @@ dependencies = [
27 52
  "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
28 53
 ]
29 54
 
55
+[[package]]
56
+name = "clap"
57
+version = "2.33.0"
58
+source = "registry+https://github.com/rust-lang/crates.io-index"
59
+dependencies = [
60
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
61
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
62
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
63
+ "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
64
+ "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
65
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
66
+ "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
67
+]
68
+
30 69
 [[package]]
31 70
 name = "cloudabi"
32 71
 version = "0.0.3"
@@ -44,7 +83,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
44 83
 name = "icosahedron"
45 84
 version = "0.1.0"
46 85
 dependencies = [
86
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
47 87
  "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
88
+ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
89
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
48 90
  "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
49 91
  "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
50 92
 ]
@@ -64,6 +106,11 @@ name = "num-traits"
64 106
 version = "0.2.6"
65 107
 source = "registry+https://github.com/rust-lang/crates.io-index"
66 108
 
109
+[[package]]
110
+name = "numtoa"
111
+version = "0.1.0"
112
+source = "registry+https://github.com/rust-lang/crates.io-index"
113
+
67 114
 [[package]]
68 115
 name = "proc-macro2"
69 116
 version = "0.4.27"
@@ -184,6 +231,19 @@ dependencies = [
184 231
  "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
185 232
 ]
186 233
 
234
+[[package]]
235
+name = "redox_syscall"
236
+version = "0.1.56"
237
+source = "registry+https://github.com/rust-lang/crates.io-index"
238
+
239
+[[package]]
240
+name = "redox_termios"
241
+version = "0.1.1"
242
+source = "registry+https://github.com/rust-lang/crates.io-index"
243
+dependencies = [
244
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
245
+]
246
+
187 247
 [[package]]
188 248
 name = "rustc_version"
189 249
 version = "0.2.3"
@@ -238,6 +298,11 @@ dependencies = [
238 298
  "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
239 299
 ]
240 300
 
301
+[[package]]
302
+name = "strsim"
303
+version = "0.8.0"
304
+source = "registry+https://github.com/rust-lang/crates.io-index"
305
+
241 306
 [[package]]
242 307
 name = "syn"
243 308
 version = "0.15.26"
@@ -248,11 +313,40 @@ dependencies = [
248 313
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
249 314
 ]
250 315
 
316
+[[package]]
317
+name = "termion"
318
+version = "1.5.3"
319
+source = "registry+https://github.com/rust-lang/crates.io-index"
320
+dependencies = [
321
+ "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
322
+ "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
323
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
324
+ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
325
+]
326
+
327
+[[package]]
328
+name = "textwrap"
329
+version = "0.11.0"
330
+source = "registry+https://github.com/rust-lang/crates.io-index"
331
+dependencies = [
332
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
333
+]
334
+
335
+[[package]]
336
+name = "unicode-width"
337
+version = "0.1.5"
338
+source = "registry+https://github.com/rust-lang/crates.io-index"
339
+
251 340
 [[package]]
252 341
 name = "unicode-xid"
253 342
 version = "0.1.0"
254 343
 source = "registry+https://github.com/rust-lang/crates.io-index"
255 344
 
345
+[[package]]
346
+name = "vec_map"
347
+version = "0.8.1"
348
+source = "registry+https://github.com/rust-lang/crates.io-index"
349
+
256 350
 [[package]]
257 351
 name = "winapi"
258 352
 version = "0.3.6"
@@ -273,15 +367,20 @@ version = "0.4.0"
273 367
 source = "registry+https://github.com/rust-lang/crates.io-index"
274 368
 
275 369
 [metadata]
370
+"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
276 371
 "checksum approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c57ff1a5b00753647aebbbcf4ea67fa1e711a65ea7a30eb90dbf07de2485aee"
372
+"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
277 373
 "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
278 374
 "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
375
+"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
279 376
 "checksum cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7"
377
+"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
280 378
 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
281 379
 "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
282 380
 "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
283 381
 "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
284 382
 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
383
+"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
285 384
 "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
286 385
 "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
287 386
 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
@@ -295,6 +394,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
295 394
 "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
296 395
 "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
297 396
 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
397
+"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
398
+"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
298 399
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
299 400
 "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
300 401
 "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
@@ -302,8 +403,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
302 403
 "checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850"
303 404
 "checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4"
304 405
 "checksum serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "27dce848e7467aa0e2fcaf0a413641499c0b745452aaca1194d24dedde9e13c9"
406
+"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
305 407
 "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
408
+"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
409
+"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
410
+"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
306 411
 "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
412
+"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
307 413
 "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
308 414
 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
309 415
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 11 - 0
Cargo.toml

@@ -4,7 +4,18 @@ version = "0.1.0"
4 4
 authors = ["Tyler Hallada <tyler@hallada.net>"]
5 5
 edition = "2018"
6 6
 
7
+[lib]
8
+name = "icosahedron"
9
+path = "src/lib.rs"
10
+
11
+[[bin]]
12
+name = "icosahedron"
13
+path = "src/bin.rs"
14
+
7 15
 [dependencies]
16
+byteorder = "1.3.2"
17
+clap = "2.33.0"
8 18
 cgmath = { version = "0.17.0", features = ["serde"] }
19
+rand = "0.6.5"
9 20
 serde = { version = "1.0", features = ["derive"] }
10 21
 serde_json = "1.0"

+ 169 - 0
src/bin.rs

@@ -0,0 +1,169 @@
1
+#[macro_use]
2
+extern crate clap;
3
+extern crate byteorder;
4
+extern crate icosahedron;
5
+
6
+use std::fs::{File, metadata};
7
+use std::io::{BufWriter, Write};
8
+use std::path::Path;
9
+
10
+use byteorder::{WriteBytesExt, LittleEndian};
11
+use icosahedron::{Polyhedron};
12
+
13
+fn write_to_binary_file(polyhedron: Polyhedron, path: &Path) {
14
+    let bin_file = File::create(path).expect("Can't create file");
15
+    let mut writer = BufWriter::new(bin_file);
16
+    let write_error_message = "Error encountered while writing to binary file";
17
+    writer.write_u32::<LittleEndian>(polyhedron.positions.len() as u32)
18
+        .expect(write_error_message);
19
+    writer.write_u32::<LittleEndian>(polyhedron.cells.len() as u32)
20
+        .expect(write_error_message);
21
+    for position in polyhedron.positions.iter() {
22
+        writer.write_f32::<LittleEndian>(position.0.x).expect(write_error_message);
23
+        writer.write_f32::<LittleEndian>(position.0.y).expect(write_error_message);
24
+        writer.write_f32::<LittleEndian>(position.0.z).expect(write_error_message);
25
+    }
26
+    for normal in polyhedron.normals.iter() {
27
+        writer.write_f32::<LittleEndian>(normal.0.x).expect(write_error_message);
28
+        writer.write_f32::<LittleEndian>(normal.0.y).expect(write_error_message);
29
+        writer.write_f32::<LittleEndian>(normal.0.z).expect(write_error_message);
30
+    }
31
+    for color in polyhedron.colors.iter() {
32
+        writer.write_f32::<LittleEndian>(color.0.x).expect(write_error_message);
33
+        writer.write_f32::<LittleEndian>(color.0.y).expect(write_error_message);
34
+        writer.write_f32::<LittleEndian>(color.0.z).expect(write_error_message);
35
+    }
36
+    for cell in polyhedron.cells.iter() {
37
+        writer.write_u32::<LittleEndian>(cell.a as u32).expect(write_error_message);
38
+        writer.write_u32::<LittleEndian>(cell.b as u32).expect(write_error_message);
39
+        writer.write_u32::<LittleEndian>(cell.c as u32).expect(write_error_message);
40
+    }
41
+}
42
+
43
+fn write_to_json_file(polyhedron: Polyhedron, path: &Path) {
44
+    let mut json_file = File::create(path).expect("Can't create file");
45
+    let json = serde_json::to_string(&polyhedron).expect("Problem serializing");
46
+    json_file.write_all(json.as_bytes()).expect("Can't write to file");
47
+}
48
+
49
+fn generate_files(dir: &str, format: Format, truncated: bool, colored: bool,
50
+                  param_list: Vec<(f32, u32)>) {
51
+    let mesh_type = if truncated {
52
+        "hexsphere"
53
+    } else {
54
+        "icosahedron"
55
+    };
56
+
57
+    for param in param_list {
58
+        println!(
59
+            "Generating {} with radius {} and detail {}...",
60
+            mesh_type, param.0, param.1
61
+        );
62
+
63
+
64
+        let polyhedron = if truncated {
65
+            let mut hexsphere = Polyhedron::new_truncated_isocahedron(param.0, param.1);
66
+            hexsphere.compute_triangle_normals();
67
+            hexsphere
68
+        } else {
69
+            let mut icosahedron = Polyhedron::new_isocahedron(param.0, param.1);
70
+            icosahedron.compute_triangle_normals();
71
+            icosahedron
72
+        };
73
+
74
+        let colored_polyhedron = if colored {
75
+            let mut colored = Polyhedron::new();
76
+            colored.unique_vertices(polyhedron);
77
+            colored.assign_random_face_colors();
78
+            colored
79
+        } else {
80
+            polyhedron
81
+        };
82
+
83
+        println!("triangles: {}", colored_polyhedron.cells.len());
84
+        println!("vertices: {}", colored_polyhedron.positions.len());
85
+
86
+        let filename = Path::new(dir).join(
87
+            format!("{}_r{}_d{}.{}", mesh_type, param.0, param.1, format.extension())
88
+        );
89
+        match format {
90
+            Format::Bin => write_to_binary_file(colored_polyhedron, &filename),
91
+            Format::Json => write_to_json_file(colored_polyhedron, &filename),
92
+        };
93
+    }
94
+}
95
+
96
+arg_enum!{
97
+    #[derive(Debug)]
98
+    enum Format {
99
+        Json,
100
+        Bin,
101
+    }
102
+}
103
+
104
+impl Format {
105
+    fn extension(&self) -> String {
106
+        match self {
107
+            Format::Bin => "bin".to_string(),
108
+            Format::Json => "json".to_string(),
109
+        }
110
+    }
111
+}
112
+
113
+fn main() {
114
+    let dir_exists = |path: String| {
115
+        let path_clone = path.clone();
116
+        match metadata(path) {
117
+            Ok(metadata) => {
118
+                if metadata.is_dir() {
119
+                    Ok(())
120
+                } else {
121
+                    Err(String::from(format!("Output '{}' is not a directory", &path_clone)))
122
+                }
123
+            }
124
+            Err(_) => Err(String::from(format!("Directory '{}' doesn't exist", &path_clone)))
125
+        }
126
+    };
127
+
128
+    let matches = clap_app!(icosahedron =>
129
+        (version: "1.0")
130
+        (author: "Tyler Hallada <tyler@hallada.net>")
131
+        (about: "Generates 3D icosahedra meshes")
132
+        (@arg truncated: -t --truncated "Generate truncated icosahedra (hexspheres).")
133
+        (@arg colored: -c --colored "Assigns a random color to every face \
134
+            (increases vertices count).")
135
+        (@arg detail: -d --detail +takes_value default_value("7")
136
+            "Maximum detail level to generate. \
137
+            Each level multiplies the number of triangles by 4.")
138
+        (@arg radius: -r --radius +takes_value default_value("1.0")
139
+            "Radius of the polyhedron,")
140
+        (@arg format: -f --format +takes_value possible_values(&Format::variants())
141
+            default_value("Bin")
142
+            "Format to write the files in.")
143
+        (@arg output: [OUTPUT] {dir_exists} default_value("output/")
144
+            "Directory to write the output files to.")
145
+    ).get_matches();
146
+
147
+    let truncated = matches.is_present("truncated");
148
+    let colored = matches.is_present("colored");
149
+    let detail = value_t!(matches.value_of("detail"), u32).unwrap_or(7);
150
+    let radius = value_t!(matches.value_of("radius"), f32).unwrap_or(1.0);
151
+    let format = value_t!(matches.value_of("format"), Format).unwrap_or(Format::Bin);
152
+    let output = matches.value_of("output").unwrap_or("output/");
153
+
154
+    let param_list = |detail: u32, radius: f32| -> Vec<(f32, u32)> {
155
+        let mut params = vec![];
156
+        for detail in 0..(detail + 1) {
157
+            params.push((radius, detail));
158
+        }
159
+        params
160
+    };
161
+
162
+    generate_files(
163
+        output,
164
+        format,
165
+        truncated,
166
+        colored,
167
+        param_list(detail, radius),
168
+    );
169
+}

src/main.rs → src/lib.rs

@@ -1,23 +1,22 @@
1 1
 extern crate cgmath;
2
+extern crate rand;
2 3
 
3 4
 use std::collections::HashMap;
4
-use std::fs::File;
5
-use std::io::Write;
6 5
 use std::ops::AddAssign;
7
-use std::path::Path;
8 6
 
9 7
 use cgmath::prelude::*;
10 8
 use cgmath::Vector3;
9
+use rand::prelude::*;
11 10
 use serde::ser::{SerializeSeq, Serializer};
12 11
 use serde::Serialize;
13 12
 
14 13
 const VERT_CACHE_PRECISION: f32 = 10000_f32;
15 14
 
16 15
 #[derive(Debug)]
17
-struct Triangle {
18
-    a: usize,
19
-    b: usize,
20
-    c: usize,
16
+pub struct Triangle {
17
+    pub a: usize,
18
+    pub b: usize,
19
+    pub c: usize,
21 20
 }
22 21
 
23 22
 impl Triangle {
@@ -41,13 +40,14 @@ impl Serialize for Triangle {
41 40
 }
42 41
 
43 42
 #[derive(Debug)]
44
-struct ArraySerializedVector(Vector3<f32>);
43
+pub struct ArraySerializedVector(pub Vector3<f32>);
45 44
 
46 45
 #[derive(Serialize, Debug)]
47
-struct Polyhedron {
48
-    positions: Vec<ArraySerializedVector>,
49
-    cells: Vec<Triangle>,
50
-    normals: Vec<ArraySerializedVector>,
46
+pub struct Polyhedron {
47
+    pub positions: Vec<ArraySerializedVector>,
48
+    pub cells: Vec<Triangle>,
49
+    pub normals: Vec<ArraySerializedVector>,
50
+    pub colors: Vec<ArraySerializedVector>,
51 51
     #[serde(skip)]
52 52
     added_vert_cache: HashMap<(i32, i32, i32), usize>,
53 53
     faces: Vec<Vec<usize>>,
@@ -74,17 +74,18 @@ impl AddAssign for ArraySerializedVector {
74 74
 }
75 75
 
76 76
 impl Polyhedron {
77
-    fn new() -> Polyhedron {
77
+    pub fn new() -> Polyhedron {
78 78
         Polyhedron {
79 79
             positions: vec![],
80 80
             cells: vec![],
81 81
             normals: vec![],
82
+            colors: vec![],
82 83
             added_vert_cache: HashMap::new(),
83 84
             faces: vec![],
84 85
         }
85 86
     }
86 87
 
87
-    fn new_isocahedron(radius: f32, detail: usize) -> Polyhedron {
88
+    pub fn new_isocahedron(radius: f32, detail: u32) -> Polyhedron {
88 89
         let t = (1.0 + (5.0 as f32).sqrt()) / 2.0;
89 90
         let mut base_isocahedron = Polyhedron {
90 91
             positions: vec![],
@@ -111,6 +112,7 @@ impl Polyhedron {
111 112
                 Triangle::new(9, 8, 1),
112 113
             ],
113 114
             normals: vec![],
115
+            colors: vec![],
114 116
             added_vert_cache: HashMap::new(),
115 117
             faces: vec![],
116 118
         };
@@ -129,17 +131,18 @@ impl Polyhedron {
129 131
 
130 132
         let mut subdivided = Polyhedron::new();
131 133
         subdivided.subdivide(base_isocahedron, radius, detail);
134
+        subdivided.triangles_to_faces();
132 135
         subdivided
133 136
     }
134 137
 
135
-    fn new_truncated_isocahedron(radius: f32, detail: usize) -> Polyhedron {
138
+    pub fn new_truncated_isocahedron(radius: f32, detail: u32) -> Polyhedron {
136 139
         let isocahedron = Polyhedron::new_isocahedron(radius, detail);
137 140
         let mut truncated_isocahedron = Polyhedron::new();
138 141
         truncated_isocahedron.truncated(isocahedron);
139 142
         truncated_isocahedron
140 143
     }
141 144
 
142
-    fn subdivide(&mut self, other: Polyhedron, radius: f32, detail: usize) {
145
+    fn subdivide(&mut self, other: Polyhedron, radius: f32, detail: u32) {
143 146
         for triangle in other.cells {
144 147
             let a = other.positions[triangle.a].0;
145 148
             let b = other.positions[triangle.b].0;
@@ -148,15 +151,21 @@ impl Polyhedron {
148 151
         }
149 152
     }
150 153
 
154
+    fn triangles_to_faces(&mut self) {
155
+        for (cell_index, _) in self.cells.iter().enumerate() {
156
+            self.faces.push(vec![cell_index]);
157
+        }
158
+    }
159
+
151 160
     fn subdivide_triangle(
152 161
         &mut self,
153 162
         a: Vector3<f32>,
154 163
         b: Vector3<f32>,
155 164
         c: Vector3<f32>,
156 165
         radius: f32,
157
-        detail: usize,
166
+        detail: u32,
158 167
     ) {
159
-        let cols = 2usize.pow(detail as u32);
168
+        let cols = 2usize.pow(detail);
160 169
         let mut new_vertices: Vec<Vec<Vector3<f32>>> = vec![];
161 170
 
162 171
         for i in 0..=cols {
@@ -207,6 +216,8 @@ impl Polyhedron {
207 216
             self.positions.push(ArraySerializedVector(vertex));
208 217
             self.normals
209 218
                 .push(ArraySerializedVector(Vector3::new(0.0, 0.0, 0.0)));
219
+            self.colors
220
+                .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0)));
210 221
             let added_index = self.positions.len() - 1;
211 222
             self.added_vert_cache.insert(vertex_key, added_index);
212 223
             return added_index;
@@ -220,7 +231,6 @@ impl Polyhedron {
220 231
         let mut mid_centroid_cache: HashMap<(usize, usize, usize), Vector3<f32>> = HashMap::new();
221 232
         let mut hex_count = 0;
222 233
         let mut pent_count = 0;
223
-        let mut count = 0;
224 234
         for i in 0..original_vert_count {
225 235
             let faces = &vert_to_faces[&i];
226 236
             if faces.len() == 6 {
@@ -285,6 +295,34 @@ impl Polyhedron {
285 295
         println!("pentagons: {}", pent_count);
286 296
     }
287 297
 
298
+    pub fn unique_vertices(&mut self, other: Polyhedron) {
299
+        for triangle in other.cells {
300
+            let vertex_a = other.positions[triangle.a].0;
301
+            let vertex_b = other.positions[triangle.b].0;
302
+            let vertex_c = other.positions[triangle.c].0;
303
+            let normal_a = other.normals[triangle.a].0;
304
+            let normal_b = other.normals[triangle.b].0;
305
+            let normal_c = other.normals[triangle.c].0;
306
+
307
+            self.positions.push(ArraySerializedVector(vertex_a));
308
+            self.positions.push(ArraySerializedVector(vertex_b));
309
+            self.positions.push(ArraySerializedVector(vertex_c));
310
+            self.normals.push(ArraySerializedVector(normal_a));
311
+            self.normals.push(ArraySerializedVector(normal_b));
312
+            self.normals.push(ArraySerializedVector(normal_c));
313
+            self.colors
314
+                .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0)));
315
+            self.colors
316
+                .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0)));
317
+            self.colors
318
+                .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0)));
319
+            let added_index = self.positions.len() - 1;
320
+            self.cells
321
+                .push(Triangle::new(added_index - 2, added_index - 1, added_index));
322
+        }
323
+        self.faces = other.faces;
324
+    }
325
+
288 326
     fn vert_to_faces(&self) -> HashMap<usize, Vec<usize>> {
289 327
         let mut vert_to_faces: HashMap<usize, Vec<usize>> = HashMap::new();
290 328
         for i in 0..self.cells.len() {
@@ -375,7 +413,7 @@ impl Polyhedron {
375 413
         None
376 414
     }
377 415
 
378
-    fn compute_triangle_normals(&mut self) {
416
+    pub fn compute_triangle_normals(&mut self) {
379 417
         let origin = Vector3::new(0.0, 0.0, 0.0);
380 418
         for i in 0..self.cells.len() {
381 419
             let vertex_a = &self.positions[self.cells[i].a].0;
@@ -406,7 +444,7 @@ impl Polyhedron {
406 444
         }
407 445
     }
408 446
 
409
-    fn compute_face_normals(&mut self) {
447
+    pub fn compute_face_normals(&mut self) {
410 448
         let origin = Vector3::new(0.0, 0.0, 0.0);
411 449
         for i in 0..self.faces.len() {
412 450
             let first_cell = &self.cells[self.faces[i][0]];
@@ -442,6 +480,31 @@ impl Polyhedron {
442 480
             *normal = ArraySerializedVector(normal.0.normalize());
443 481
         }
444 482
     }
483
+
484
+    pub fn assign_random_face_colors(&mut self) {
485
+        let mut rng = rand::thread_rng();
486
+        for i in 0..self.faces.len() {
487
+            let face_color = Vector3::new(rng.gen(), rng.gen(), rng.gen());
488
+
489
+            for c in 0..self.faces[i].len() {
490
+                let face_cell = &self.cells[self.faces[i][c]];
491
+
492
+                self.colors[face_cell.a] = ArraySerializedVector(face_color);
493
+                self.colors[face_cell.b] = ArraySerializedVector(face_color);
494
+                self.colors[face_cell.c] = ArraySerializedVector(face_color);
495
+            }
496
+        }
497
+    }
498
+
499
+    pub fn export_cells(&self) -> Vec<u32> {
500
+        let mut cell_vec: Vec<u32> = vec![];
501
+        for cell in &self.cells {
502
+            cell_vec.push(cell.a as u32);
503
+            cell_vec.push(cell.b as u32);
504
+            cell_vec.push(cell.c as u32);
505
+        }
506
+        cell_vec
507
+    }
445 508
 }
446 509
 
447 510
 fn calculate_centroid(pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>) -> Vector3<f32> {
@@ -461,71 +524,3 @@ fn find_center_of_triangles(
461 524
     center_point /= triangle_indices.len() as f32;
462 525
     center_point
463 526
 }
464
-
465
-fn generate_icosahedron_files(dir: &str, param_list: Vec<(f32, usize)>) {
466
-    for param in param_list {
467
-        println!(
468
-            "Generating icosahedron with radius {} and detail {}...",
469
-            param.0, param.1
470
-        );
471
-        let filename = Path::new(dir).join(format!("icosahedron_r{}_d{}.json", param.0, param.1));
472
-        let mut file = File::create(filename).expect("Can't create file");
473
-        let mut icosahedron = Polyhedron::new_isocahedron(param.0, param.1);
474
-        icosahedron.compute_triangle_normals();
475
-        println!("triangles: {}", icosahedron.cells.len());
476
-        println!("vertices: {}", icosahedron.positions.len());
477
-        let icosahedron_json = serde_json::to_string(&icosahedron).expect("Problem serializing");
478
-        file.write_all(icosahedron_json.as_bytes())
479
-            .expect("Can't write to file");
480
-    }
481
-}
482
-
483
-fn generate_hexsphere_files(dir: &str, param_list: Vec<(f32, usize)>) {
484
-    for param in param_list {
485
-        println!(
486
-            "Generating hexsphere with radius {} and detail {}...",
487
-            param.0, param.1
488
-        );
489
-        let filename = Path::new(dir).join(format!("hexsphere_r{}_d{}.json", param.0, param.1));
490
-        let mut file = File::create(filename).expect("Can't create file");
491
-        let mut hexsphere = Polyhedron::new_truncated_isocahedron(param.0, param.1);
492
-        hexsphere.compute_triangle_normals();
493
-        // hexsphere.compute_face_normals();
494
-        println!("triangles: {}", hexsphere.cells.len());
495
-        println!("vertices: {}", hexsphere.positions.len());
496
-        let hexsphere_json = serde_json::to_string(&hexsphere).expect("Problem serializing");
497
-        file.write_all(hexsphere_json.as_bytes())
498
-            .expect("Can't write to file");
499
-    }
500
-}
501
-
502
-fn main() {
503
-    generate_hexsphere_files(
504
-        "output/",
505
-        vec![
506
-            (1.0, 0),
507
-            (1.0, 1),
508
-            (1.0, 2),
509
-            (1.0, 3),
510
-            (1.0, 4),
511
-            (1.0, 5),
512
-            (1.0, 6),
513
-            (1.0, 7),
514
-            // (1.0, 8),
515
-            // (1.0, 9),
516
-        ],
517
-    );
518
-    generate_icosahedron_files(
519
-        "output/",
520
-        vec![
521
-            (1.0, 0),
522
-            (1.0, 1),
523
-            (1.0, 2),
524
-            (1.0, 3),
525
-            (1.0, 4),
526
-            (1.0, 5),
527
-            (1.0, 6),
528
-            (1.0, 7),
529
-        ],
530
-    );
531
-}