conspire/geometry/mesh/tessellation/read/
mod.rs1#[cfg(test)]
2mod test;
3
4use crate::{
5 geometry::{
6 Coordinate, Coordinates, Direction, Directions,
7 mesh::{
8 Connectivity,
9 tessellation::{D, Tessellation},
10 },
11 },
12 io::invalid,
13 math::{Tensor, TensorVec},
14};
15use std::{
16 cell::OnceCell,
17 collections::HashMap,
18 fs::File,
19 io::{BufReader, Error as ErrorIO, Read, Seek, SeekFrom},
20 path::Path,
21 str::SplitWhitespace,
22};
23
24impl TryFrom<&Path> for Tessellation {
25 type Error = ErrorIO;
26 fn try_from(path: &Path) -> Result<Self, Self::Error> {
27 let mut file = File::open(path)?;
28 if let Some(triangle_count) = binary_triangle_count(&mut file)? {
29 read_binary(BufReader::new(file), triangle_count)
30 } else {
31 file.seek(SeekFrom::Start(0))?;
32 let mut contents = String::new();
33 BufReader::new(file).read_to_string(&mut contents)?;
34 read_ascii(&contents)
35 }
36 }
37}
38
39fn binary_triangle_count(file: &mut File) -> Result<Option<usize>, ErrorIO> {
40 let length = file.metadata()?.len();
41 if length < 84 {
42 return Ok(None);
43 }
44 let mut header = [0u8; 84];
45 file.read_exact(&mut header)?;
46 let triangle_count = u32::from_le_bytes([header[80], header[81], header[82], header[83]]);
47 Ok((84 + 50 * triangle_count as u64 == length).then_some(triangle_count as usize))
48}
49
50fn read_binary<R: Read>(mut reader: R, triangle_count: usize) -> Result<Tessellation, ErrorIO> {
51 let mut builder = Builder::with_capacity(triangle_count);
52 (0..triangle_count).try_for_each(|_| {
53 let normal = read_vec3_f32(&mut reader)?;
54 let vertices = [
55 read_vec3_f32(&mut reader)?,
56 read_vec3_f32(&mut reader)?,
57 read_vec3_f32(&mut reader)?,
58 ];
59 let mut attribute_byte_count = [0u8; 2];
60 reader.read_exact(&mut attribute_byte_count)?;
61 builder.push(normal, vertices);
62 Ok::<(), ErrorIO>(())
63 })?;
64 Ok(builder.into())
65}
66
67fn read_ascii(contents: &str) -> Result<Tessellation, ErrorIO> {
68 let mut builder = Builder::with_capacity(contents.len() / 200);
69 let mut tokens = contents.split_whitespace();
70 while let Some(token) = tokens.next() {
71 if token == "facet" {
72 expect(&mut tokens, "normal")?;
73 let normal = read_vec3_ascii(&mut tokens)?;
74 expect(&mut tokens, "outer")?;
75 expect(&mut tokens, "loop")?;
76 let mut vertices = [[0.0; D]; 3];
77 vertices.iter_mut().try_for_each(|vertex| {
78 expect(&mut tokens, "vertex")?;
79 *vertex = read_vec3_ascii(&mut tokens)?;
80 Ok::<(), ErrorIO>(())
81 })?;
82 expect(&mut tokens, "endloop")?;
83 expect(&mut tokens, "endfacet")?;
84 builder.push(normal, vertices);
85 }
86 }
87 Ok(builder.into())
88}
89
90fn expect(tokens: &mut SplitWhitespace, keyword: &str) -> Result<(), ErrorIO> {
91 match tokens.next() {
92 Some(token) if token.eq_ignore_ascii_case(keyword) => Ok(()),
93 token => Err(invalid(format!(
94 "Expected {keyword} but found {}",
95 token.unwrap_or("end of file")
96 ))),
97 }
98}
99
100fn read_vec3_ascii(tokens: &mut SplitWhitespace) -> Result<[f64; D], ErrorIO> {
101 let mut vector = [0.0; D];
102 vector.iter_mut().try_for_each(|entry| {
103 match tokens.next() {
104 Some(token) => {
105 *entry = token
106 .parse()
107 .map_err(|_| invalid(format!("Expected a number but found {token}")))?
108 }
109 None => {
110 return Err(invalid(
111 "Expected a number but found end of file".to_string(),
112 ));
113 }
114 }
115 Ok(())
116 })?;
117 Ok(vector)
118}
119
120fn read_vec3_f32<R: Read>(reader: &mut R) -> Result<[f64; D], ErrorIO> {
121 Ok([read_f32(reader)?, read_f32(reader)?, read_f32(reader)?])
122}
123
124fn read_f32<R: Read>(reader: &mut R) -> Result<f64, ErrorIO> {
125 let mut bytes = [0u8; 4];
126 reader.read_exact(&mut bytes)?;
127 Ok(f32::from_le_bytes(bytes) as f64)
128}
129
130struct Builder {
131 connectivity: Vec<[usize; D]>,
132 normals: Directions<D>,
133 vertex_map: HashMap<[u64; D], usize>,
134 vertices: Coordinates<D>,
135}
136
137impl Builder {
138 fn with_capacity(triangle_count: usize) -> Self {
139 Self {
140 connectivity: Vec::with_capacity(triangle_count),
141 normals: Directions::with_capacity(triangle_count),
142 vertex_map: HashMap::with_capacity(D * triangle_count),
143 vertices: Coordinates::with_capacity(D * triangle_count),
144 }
145 }
146 fn push(&mut self, normal: [f64; D], vertices: [[f64; D]; 3]) {
147 let nodes = [
148 self.dedup(vertices[0]),
149 self.dedup(vertices[1]),
150 self.dedup(vertices[2]),
151 ];
152 self.connectivity.push(nodes);
153 self.normals.push(Direction::const_from(normal));
154 }
155 fn dedup(&mut self, vertex: [f64; D]) -> usize {
156 let key = vertex.map(|entry| entry.to_bits());
157 if let Some(&index) = self.vertex_map.get(&key) {
158 index
159 } else {
160 let index = self.vertices.len();
161 self.vertices.push(Coordinate::const_from(vertex));
162 self.vertex_map.insert(key, index);
163 index
164 }
165 }
166}
167
168impl From<Builder> for Tessellation {
169 fn from(builder: Builder) -> Self {
170 let Builder {
171 connectivity,
172 normals,
173 vertices,
174 ..
175 } = builder;
176 Self {
177 mesh: (
178 vec![Connectivity::Triangular(connectivity.into())],
179 vertices,
180 )
181 .into(),
182 normals: vec![normals].into(),
183 bvh: OnceCell::new(),
184 features: OnceCell::new(),
185 }
186 }
187}