ifc_lite_server/services/
parquet_mesh_tables.rs1use crate::services::parquet::ParquetError;
18use crate::services::parquet_layout::ParquetLayout;
19use crate::services::parquet_shape_plan::{ShapePlan, ShapeRef};
20use crate::services::parquet_vertex_columns::{shape_vertices, VertexColumns};
21use crate::services::parquet_schema::{
22 index_schema, mesh_schema, vertex_schema, MeshRow, RowPlacement, ABSENT_SOURCE_ID,
23};
24use crate::types::MeshData;
25use arrow::array::{Float32Array, Float64Array, StringArray, UInt8Array, UInt32Array};
26use arrow::record_batch::RecordBatch;
27use rayon::prelude::*;
28use std::sync::Arc;
29
30pub(super) fn build_mesh_tables(
37 meshes: &[MeshData],
38 plan: &ShapePlan,
39 layout: ParquetLayout,
40 base_vertex_offset: u32,
41 base_index_offset: u32,
42) -> Result<(RecordBatch, RecordBatch, RecordBatch), ParquetError> {
43 debug_assert!(
47 plan.row_count().is_none_or(|n| n == meshes.len()),
48 "shape plan was built from a different mesh slice"
49 );
50 let shape_meshes = plan.shape_meshes(meshes);
51 let total_vertices: usize = shape_meshes.iter().map(|m| m.positions.len() / 3).sum();
52 let total_triangles: usize = shape_meshes.iter().map(|m| m.indices.len() / 3).sum();
53 let mesh_count = meshes.len();
54
55 let mut shape_vertex_start = Vec::with_capacity(shape_meshes.len());
57 let mut shape_index_start = Vec::with_capacity(shape_meshes.len());
58 let mut vertex_offset: u32 = base_vertex_offset;
59 let mut index_offset: u32 = base_index_offset;
60 for shape in &shape_meshes {
61 shape_vertex_start.push(vertex_offset);
62 shape_index_start.push(index_offset);
63 vertex_offset += (shape.positions.len() / 3) as u32;
64 index_offset += shape.indices.len() as u32;
65 }
66
67 let metadata: Vec<MeshRow<'_>> = (0..mesh_count)
69 .into_par_iter()
70 .map(|i| {
71 let (shape, origin, rotation) = plan.row(meshes, i);
72 let placement = match shape {
73 ShapeRef::Slot(slot) => RowPlacement {
74 v_start: shape_vertex_start[slot],
75 vert_count: (shape_meshes[slot].positions.len() / 3) as u32,
76 i_start: shape_index_start[slot],
77 index_count: shape_meshes[slot].indices.len() as u32,
78 origin,
79 rotation,
80 },
81 ShapeRef::Emitted(emitted) => RowPlacement {
84 v_start: emitted.vertex_start,
85 vert_count: emitted.vertex_count,
86 i_start: emitted.index_start,
87 index_count: emitted.index_count,
88 origin,
89 rotation,
90 },
91 };
92 MeshRow::new(&meshes[i], placement)
93 })
94 .collect();
95
96 let mut express_ids = Vec::with_capacity(mesh_count);
97 let mut ifc_types: Vec<&str> = Vec::with_capacity(mesh_count);
98 let mut vertex_starts = Vec::with_capacity(mesh_count);
99 let mut vertex_counts = Vec::with_capacity(mesh_count);
100 let mut index_starts = Vec::with_capacity(mesh_count);
101 let mut index_counts = Vec::with_capacity(mesh_count);
102 let mut color_r = Vec::with_capacity(mesh_count);
103 let mut color_g = Vec::with_capacity(mesh_count);
104 let mut color_b = Vec::with_capacity(mesh_count);
105 let mut color_a = Vec::with_capacity(mesh_count);
106 let mut origin_x = Vec::with_capacity(mesh_count);
107 let mut origin_y = Vec::with_capacity(mesh_count);
108 let mut origin_z = Vec::with_capacity(mesh_count);
109 let mut geometry_class = Vec::with_capacity(mesh_count);
110 let mut geometry_item_ids: Vec<u32> = Vec::with_capacity(mesh_count);
111 let mut material_ids: Vec<u32> = Vec::with_capacity(mesh_count);
112 let mut metallic: Vec<f32> = Vec::with_capacity(mesh_count);
113 let mut roughness: Vec<f32> = Vec::with_capacity(mesh_count);
114 let mut rotation: [Vec<f32>; 9] = std::array::from_fn(|_| Vec::with_capacity(mesh_count));
115
116 for m in metadata {
117 express_ids.push(m.express_id);
118 ifc_types.push(m.ifc_type);
119 vertex_starts.push(m.v_start);
120 vertex_counts.push(m.vert_count);
121 index_starts.push(m.i_start);
122 index_counts.push(m.index_count);
123 color_r.push(m.color[0]);
124 color_g.push(m.color[1]);
125 color_b.push(m.color[2]);
126 color_a.push(m.color[3]);
127 origin_x.push(m.origin[0]);
128 origin_y.push(m.origin[1]);
129 origin_z.push(m.origin[2]);
130 geometry_class.push(m.geometry_class);
131 geometry_item_ids.push(m.geometry_item_id.unwrap_or(ABSENT_SOURCE_ID));
132 material_ids.push(m.material_id.unwrap_or(ABSENT_SOURCE_ID));
133 metallic.push(m.finish[0]);
134 roughness.push(m.finish[1]);
135 for (column, value) in rotation.iter_mut().zip(m.rotation.iter()) {
136 column.push(*value);
137 }
138 }
139
140 let vertex_data: Vec<VertexColumns> =
144 shape_meshes.par_iter().map(|mesh| shape_vertices(mesh)).collect();
145
146 let mut pos_x = Vec::with_capacity(total_vertices);
147 let mut pos_y = Vec::with_capacity(total_vertices);
148 let mut pos_z = Vec::with_capacity(total_vertices);
149 let mut norm_x = Vec::with_capacity(total_vertices);
150 let mut norm_y = Vec::with_capacity(total_vertices);
151 let mut norm_z = Vec::with_capacity(total_vertices);
152 for (px, py, pz, nx, ny, nz) in vertex_data {
153 pos_x.extend(px);
154 pos_y.extend(py);
155 pos_z.extend(pz);
156 norm_x.extend(nx);
157 norm_y.extend(ny);
158 norm_z.extend(nz);
159 }
160
161 let index_data: Vec<(Vec<u32>, Vec<u32>, Vec<u32>)> = shape_meshes
162 .par_iter()
163 .map(|mesh| {
164 let tri_count = mesh.indices.len() / 3;
165 let mut i0 = Vec::with_capacity(tri_count);
166 let mut i1 = Vec::with_capacity(tri_count);
167 let mut i2 = Vec::with_capacity(tri_count);
168 for i in 0..tri_count {
169 i0.push(mesh.indices[i * 3]);
170 i1.push(mesh.indices[i * 3 + 1]);
171 i2.push(mesh.indices[i * 3 + 2]);
172 }
173 (i0, i1, i2)
174 })
175 .collect();
176
177 let mut idx_0 = Vec::with_capacity(total_triangles);
178 let mut idx_1 = Vec::with_capacity(total_triangles);
179 let mut idx_2 = Vec::with_capacity(total_triangles);
180 for (i0, i1, i2) in index_data {
181 idx_0.extend(i0);
182 idx_1.extend(i1);
183 idx_2.extend(i2);
184 }
185
186 let mut mesh_columns: Vec<arrow::array::ArrayRef> = vec![
187 Arc::new(UInt32Array::from(express_ids)),
188 Arc::new(StringArray::from(ifc_types)),
189 Arc::new(UInt32Array::from(vertex_starts)),
190 Arc::new(UInt32Array::from(vertex_counts)),
191 Arc::new(UInt32Array::from(index_starts)),
192 Arc::new(UInt32Array::from(index_counts)),
193 Arc::new(Float32Array::from(color_r)),
194 Arc::new(Float32Array::from(color_g)),
195 Arc::new(Float32Array::from(color_b)),
196 Arc::new(Float32Array::from(color_a)),
197 Arc::new(Float64Array::from(origin_x)),
198 Arc::new(Float64Array::from(origin_y)),
199 Arc::new(Float64Array::from(origin_z)),
200 Arc::new(UInt8Array::from(geometry_class)),
201 Arc::new(UInt32Array::from(geometry_item_ids)),
202 Arc::new(UInt32Array::from(material_ids)),
203 Arc::new(Float32Array::from(metallic)),
204 Arc::new(Float32Array::from(roughness)),
205 ];
206 if layout.has_rotation() {
207 for column in rotation {
208 mesh_columns.push(Arc::new(Float32Array::from(column)));
209 }
210 }
211 let mesh_batch = RecordBatch::try_new(mesh_schema(layout.has_rotation()), mesh_columns)?;
212
213 let vertex_batch = RecordBatch::try_new(
214 vertex_schema(),
215 vec![
216 Arc::new(Float32Array::from(pos_x)),
217 Arc::new(Float32Array::from(pos_y)),
218 Arc::new(Float32Array::from(pos_z)),
219 Arc::new(Float32Array::from(norm_x)),
220 Arc::new(Float32Array::from(norm_y)),
221 Arc::new(Float32Array::from(norm_z)),
222 ],
223 )?;
224
225 let index_batch = RecordBatch::try_new(
226 index_schema(),
227 vec![
228 Arc::new(UInt32Array::from(idx_0)),
229 Arc::new(UInt32Array::from(idx_1)),
230 Arc::new(UInt32Array::from(idx_2)),
231 ],
232 )?;
233
234 Ok((mesh_batch, vertex_batch, index_batch))
235}
236
237#[cfg(test)]
240#[path = "parquet_mesh_tables_tests.rs"]
241mod parquet_mesh_tables_tests;