1use crate::*;
26
27use std::{
28 fmt,
29 io::{BufRead, Error as ioError},
30};
31
32use super::{types::*, utils::*};
33
34pub fn load_off_mesh<EM, P, R>(read: &mut R, mesh: &mut EM) -> OffResult<()>
38where
39 EM: IsFaceEditableMesh<P, Face3> + IsVertexEditableMesh<P, Face3>,
40 P: IsBuildable3D + Clone,
41 R: BufRead,
42{
43 let mut line_buffer = Vec::new();
44 let mut i_line = 0;
45
46 let mut off_seen = false;
47 let mut counts = None;
48
49 while let Ok(line) = fetch_line(read, &mut line_buffer) {
50 i_line += 1;
51
52 if !off_seen && line.starts_with(b"OFF") {
53 off_seen = true;
54 continue;
55 }
56
57 if line.is_empty() || line.starts_with(b"#") {
58 continue;
59 }
60
61 if counts.is_none() {
62 let mut words = to_words_skip_empty(line);
63 let n_vertices = words
64 .next()
65 .and_then(|word| from_ascii(word))
66 .ok_or(OffError::VertexCount)
67 .line(i_line, line)?;
68 let n_faces = words
69 .next()
70 .and_then(|word| from_ascii(word))
71 .ok_or(OffError::FaceCount)
72 .line(i_line, line)?;
73
74 mesh.reserve_vertices(n_vertices);
75 mesh.reserve_faces(n_faces);
76
77 counts = Some([n_vertices, n_faces]);
78 continue;
79 }
80
81 if mesh.num_vertices() < counts.unwrap()[0] {
83 let mut words = to_words_skip_empty(line);
84
85 let x = words
86 .next()
87 .and_then(|word| from_ascii(word))
88 .ok_or(OffError::Vertex)
89 .line(i_line, line)?;
90
91 let y = words
92 .next()
93 .and_then(|word| from_ascii(word))
94 .ok_or(OffError::Vertex)
95 .line(i_line, line)?;
96
97 let z = words
98 .next()
99 .and_then(|word| from_ascii(word))
100 .ok_or(OffError::Vertex)
101 .line(i_line, line)?;
102
103 mesh.add_vertex(P::new(x, y, z));
104 } else {
105 let mut words = to_words_skip_empty(line);
106
107 let count_face = words
108 .next()
109 .ok_or(OffError::FaceVertexCount)
110 .line(i_line, line)?;
111
112 if count_face == b"3" {
113 let a = words
114 .next()
115 .and_then(|word| from_ascii(word))
116 .ok_or(OffError::Face)
117 .line(i_line, line)?;
118
119 let b = words
120 .next()
121 .and_then(|word| from_ascii(word))
122 .ok_or(OffError::Face)
123 .line(i_line, line)?;
124
125 let c = words
126 .next()
127 .and_then(|word| from_ascii(word))
128 .ok_or(OffError::Face)
129 .line(i_line, line)?;
130
131 mesh.try_add_connection(VId { val: a }, VId { val: b }, VId { val: c })
132 .or(Err(OffError::InvalidMeshIndices).line(i_line, line))?;
133 }
134 }
135 }
136
137 Ok(())
138}
139
140pub fn load_off_points<IP, P, R>(read: &mut R, ip: &mut IP) -> OffResult<()>
142where
143 IP: IsPushable<P>,
144 P: IsBuildable3D,
145 R: BufRead,
146{
147 let mut line_buffer = Vec::new();
148 let mut i_line = 0;
149
150 let mut off_seen = false;
151 let mut n_vertices = None;
152 let mut n_added = 0;
153
154 while let Ok(line) = fetch_line(read, &mut line_buffer) {
155 i_line += 1;
156
157 if !off_seen && line.starts_with(b"OFF") {
158 off_seen = true;
159 continue;
160 }
161
162 if line.is_empty() || line.starts_with(b"#") {
163 continue;
164 }
165
166 if n_vertices.is_none() {
167 let mut words = to_words_skip_empty(line);
168 n_vertices = Some(
169 words
170 .next()
171 .and_then(|word| from_ascii(word))
172 .ok_or(OffError::VertexCount)
173 .line(i_line, line)?,
174 );
175 ip.reserve(n_vertices.unwrap());
176
177 continue;
178 }
179
180 if n_added < n_vertices.unwrap() {
182 let mut words = to_words_skip_empty(line);
183
184 let x = words
185 .next()
186 .and_then(|word| from_ascii(word))
187 .ok_or(OffError::Vertex)
188 .line(i_line, line)?;
189
190 let y = words
191 .next()
192 .and_then(|word| from_ascii(word))
193 .ok_or(OffError::Vertex)
194 .line(i_line, line)?;
195
196 let z = words
197 .next()
198 .and_then(|word| from_ascii(word))
199 .ok_or(OffError::Vertex)
200 .line(i_line, line)?;
201
202 ip.push(P::new(x, y, z));
203 n_added += 1;
204 } else {
205 break;
206 }
207 }
208
209 Ok(())
210}
211
212pub enum OffError {
216 AccessFile,
217 InvalidMeshIndices,
218 VertexCount,
219 FaceCount,
220 Vertex,
221 Face,
222 FaceVertexCount,
223}
224
225pub type OffResult<T> = IOResult<T, OffError>;
227
228impl fmt::Debug for OffError {
229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 match self {
231 Self::AccessFile => write!(f, "Unable to access file"),
232 Self::VertexCount => write!(f, "Unable to parse vertex count"),
233 Self::FaceCount => write!(f, "Unable to parse face count"),
234 Self::Vertex => write!(f, "Unable to parse vertex"),
235 Self::Face => write!(f, "Unable to parse face"),
236 Self::FaceVertexCount => write!(f, "Unable to parse vertex count of face"),
237 Self::InvalidMeshIndices => write!(f, "File contains invalid mesh indices"),
238 }
239 }
240}
241
242impl fmt::Display for OffError {
243 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
244 write!(f, "{:?}", self)
245 }
246}
247
248impl From<ioError> for OffError {
249 fn from(_error: ioError) -> Self {
250 OffError::AccessFile
251 }
252}