1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use crate::*;
use std::{
error::Error,
fs::File,
io::Write as IoWrite,
path::{Path, PathBuf},
};
impl Polyhedron {
#[cfg(feature = "obj")]
pub fn write_obj(
&self,
destination: &Path,
reverse_winding: bool,
) -> Result<PathBuf, Box<dyn Error>> {
let path = destination.join(format!("polyhedron-{}.obj", self.name));
let mut file = File::create(path.clone())?;
writeln!(file, "o {}", self.name)?;
for vertex in &self.positions {
writeln!(file, "v {} {} {}", vertex.x, vertex.y, vertex.z)?;
}
match reverse_winding {
true => {
for face in &self.face_index {
write!(file, "f")?;
for vertex_index in face.iter().rev() {
write!(file, " {}", vertex_index + 1)?;
}
writeln!(file)?;
}
}
false => {
for face in &self.face_index {
write!(file, "f")?;
for vertex_index in face {
write!(file, " {}", vertex_index + 1)?;
}
writeln!(file)?;
}
}
};
file.flush()?;
Ok(path)
}
pub fn read_obj(
source: &Path,
reverse_winding: bool,
) -> Result<Self, tobj::LoadError> {
let (geometry, _) =
tobj::load_obj(source, &tobj::OFFLINE_RENDERING_LOAD_OPTIONS)?;
Ok(Polyhedron {
face_index: {
let mut index = 0;
geometry[0]
.mesh
.face_arities
.iter()
.map(|&face_arity| {
assert!(0 != face_arity);
let face_arity = face_arity as usize;
let mut face_indices = geometry[0].mesh.indices
[index..index + face_arity]
.to_vec();
if reverse_winding {
face_indices.reverse();
}
index += face_arity;
face_indices
})
.collect()
},
positions: geometry[0]
.mesh
.positions
.iter()
.array_chunks::<3>()
.map(|p| Point::new(*p[0], *p[1], *p[2]))
.collect(),
name: geometry[0].name.clone(),
..Default::default()
})
}
}