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