1use crate::api::IfcAPI;
12use js_sys::Function;
13use wasm_bindgen::prelude::*;
14
15pub(super) fn set_stream_meta_props(
21 obj: &js_sys::Object,
22 meta: &ifc_lite_processing::stream_meta::StreamMeta,
23) {
24 crate::api::set_js_prop(obj, "unitScale", &meta.length_unit_scale.into());
25 crate::api::set_js_prop(obj, "planeAngleToRadians", &meta.plane_angle_to_radians.into());
26 let rtc_arr = js_sys::Float64Array::new_with_length(3);
27 rtc_arr.set_index(0, meta.rtc_offset.0);
28 rtc_arr.set_index(1, meta.rtc_offset.1);
29 rtc_arr.set_index(2, meta.rtc_offset.2);
30 crate::api::set_js_prop(obj, "rtcOffset", &rtc_arr);
31 crate::api::set_js_prop(obj, "needsShift", &meta.needs_shift.into());
32 match meta.building_rotation {
33 Some(rot) => crate::api::set_js_prop(obj, "buildingRotation", &rot.into()),
34 None => crate::api::set_js_prop(obj, "buildingRotation", &JsValue::NULL),
35 };
36}
37
38#[wasm_bindgen]
39impl IfcAPI {
40 #[wasm_bindgen(js_name = buildPrePassStreamingSharded)]
54 #[allow(clippy::too_many_arguments)]
55 pub fn build_pre_pass_streaming_sharded(
56 &self,
57 data: &[u8],
58 on_event: &Function,
59 chunk_size: u32,
60 disabled_type_names: Option<Vec<String>>,
61 skip_type_geometry: bool,
62 index_ids: &[u32],
63 index_starts: &[u32],
64 index_lengths: &[u32],
65 index_classes: &[u8],
66 ) -> Result<JsValue, JsValue> {
67 let prebuilt = ifc_lite_core::ColumnarEntityIndex::from_columns(
68 index_ids,
69 index_starts,
70 index_lengths,
71 );
72 self.pre_pass_streaming_impl(
73 data,
74 on_event,
75 chunk_size,
76 disabled_type_names,
77 skip_type_geometry,
78 Some(prebuilt),
79 true,
80 Some((index_ids, index_starts, index_lengths, index_classes)),
81 )
82 }
83
84 #[wasm_bindgen(js_name = scanEntityIndexShard)]
108 pub fn scan_entity_index_shard(
109 &self,
110 data: &[u8],
111 range_start: u32,
112 range_end: u32,
113 ) -> JsValue {
114 let total = data.len();
115 let start = (range_start as usize).min(total);
116 let end = (range_end as usize).min(total);
117 let (records, classes, handoff) =
118 ifc_lite_processing::scan_shard_classified(data, start, end);
119
120 let n = records.len() as u32;
121 let ids = js_sys::Uint32Array::new_with_length(n);
122 let starts = js_sys::Uint32Array::new_with_length(n);
123 let lengths = js_sys::Uint32Array::new_with_length(n);
124 for (i, &(id, s, e)) in records.iter().enumerate() {
125 let i = i as u32;
126 ids.set_index(i, id);
127 starts.set_index(i, s as u32);
128 lengths.set_index(i, (e - s) as u32);
129 }
130
131 let result = js_sys::Object::new();
132 crate::api::set_js_prop(&result, "ids", &ids);
133 crate::api::set_js_prop(&result, "starts", &starts);
134 crate::api::set_js_prop(&result, "lengths", &lengths);
135 crate::api::set_js_prop(&result, "classes", &js_sys::Uint8Array::from(classes.as_slice()));
141 let handoff_val: f64 = match handoff {
142 Some(h) => h as f64,
143 None => -1.0,
144 };
145 crate::api::set_js_prop(&result, "handoff", &handoff_val.into());
146 result.into()
147 }
148
149 #[wasm_bindgen(js_name = resolveStyledItemsShard)]
158 pub fn resolve_styled_items_shard(&self, data: &[u8], spans: &[u32]) -> Result<JsValue, JsValue> {
159 use ifc_lite_core::EntityDecoder;
160 let index = {
161 let slot = self
162 .cached_entity_index
163 .lock()
164 .unwrap_or_else(std::sync::PoisonError::into_inner);
165 slot.clone()
166 };
167 let Some(index) = index else {
168 return Err(JsValue::from_str(
169 "resolveStyledItemsShard: no entity index installed (setEntityIndex must run first)",
170 ));
171 };
172 let mut decoder = EntityDecoder::with_arc_columnar_index(data, index);
173 let styled: Vec<(u32, usize, usize)> = spans
174 .chunks_exact(3)
175 .map(|c| (c[0], c[1] as usize, c[1] as usize + c[2] as usize))
176 .collect();
177 let mut orphan = rustc_hash::FxHashMap::default();
178 let mut geom = rustc_hash::FxHashMap::default();
179 let mut deferred = Vec::new();
180 ifc_lite_processing::prepass::resolve_styled_items_into(
181 &styled,
182 &mut decoder,
183 false,
184 &mut orphan,
185 &mut geom,
186 &mut deferred,
187 );
188
189 let orphan_ids = js_sys::Uint32Array::new_with_length(orphan.len() as u32);
190 let orphan_colors = js_sys::Float32Array::new_with_length((orphan.len() * 4) as u32);
191 for (i, (&id, color)) in orphan.iter().enumerate() {
192 orphan_ids.set_index(i as u32, id);
193 for (j, &c) in color.iter().enumerate() {
194 orphan_colors.set_index((i * 4 + j) as u32, c);
195 }
196 }
197 let geom_ids = js_sys::Uint32Array::new_with_length(geom.len() as u32);
198 let geom_colors = js_sys::Float32Array::new_with_length((geom.len() * 4) as u32);
199 for (i, (&id, info)) in geom.iter().enumerate() {
200 geom_ids.set_index(i as u32, id);
201 for (j, &c) in info.color.iter().enumerate() {
202 geom_colors.set_index((i * 4 + j) as u32, c);
203 }
204 }
205 let result = js_sys::Object::new();
206 crate::api::set_js_prop(&result, "orphanIds", &orphan_ids);
207 crate::api::set_js_prop(&result, "orphanColors", &orphan_colors);
208 crate::api::set_js_prop(&result, "geomIds", &geom_ids);
209 crate::api::set_js_prop(&result, "geomColors", &geom_colors);
210 Ok(result.into())
211 }
212
213 #[wasm_bindgen(js_name = finalizePrepassStyles)]
220 #[allow(clippy::too_many_arguments)]
221 pub fn finalize_prepass_styles(
222 &self,
223 data: &[u8],
224 orphan_ids: &[u32],
225 orphan_colors: &[f32],
226 geom_ids: &[u32],
227 geom_colors: &[f32],
228 colour_map_spans: &[u32],
229 material_def_spans: &[u32],
230 rel_material_spans: &[u32],
231 void_spans: &[u32],
232 fills_spans: &[u32],
233 aggregate_spans: &[u32],
234 plane_angle_to_radians: f64,
235 ) -> Result<JsValue, JsValue> {
236 use ifc_lite_core::EntityDecoder;
237 fn triples(v: &[u32]) -> Vec<(u32, usize, usize)> {
238 v.chunks_exact(3)
239 .map(|c| (c[0], c[1] as usize, c[1] as usize + c[2] as usize))
240 .collect()
241 }
242 let stashed_support = ifc_lite_processing::prepass::PrepassSpans {
243 styled_items: Vec::new(),
244 indexed_colour_maps: triples(colour_map_spans),
245 material_def_reprs: triples(material_def_spans),
246 rel_associates_material: triples(rel_material_spans),
247 void_rels: triples(void_spans),
248 fills_rels: triples(fills_spans),
249 aggregate_rels: triples(aggregate_spans),
250 };
251 let index = {
252 let slot = self
253 .cached_entity_index
254 .lock()
255 .unwrap_or_else(std::sync::PoisonError::into_inner);
256 slot.clone()
257 };
258 let Some(index) = index else {
259 return Err(JsValue::from_str("finalizePrepassStyles: no entity index"));
260 };
261 let mut decoder = EntityDecoder::with_arc_columnar_index(data, index);
262 decoder.seed_unit_scales(1.0, plane_angle_to_radians);
263
264 let mut orphan_seed = rustc_hash::FxHashMap::default();
269 for (i, &id) in orphan_ids.iter().enumerate() {
270 orphan_seed.insert(id, [
271 orphan_colors[i * 4],
272 orphan_colors[i * 4 + 1],
273 orphan_colors[i * 4 + 2],
274 orphan_colors[i * 4 + 3],
275 ]);
276 }
277 let resolved = ifc_lite_processing::prepass::resolve_prepass_with_style_seeds(
281 &stashed_support,
282 &mut decoder,
283 ifc_lite_processing::prepass::ResolveOptions {
284 collect_indexed_colour_full: false,
285 defer_attached_styles: false,
286 },
287 Some((orphan_seed, rustc_hash::FxHashMap::default())),
288 );
289 let flat = ifc_lite_processing::flat_styles_rgba8_from_geometry_columns(
290 geom_ids,
291 geom_colors,
292 &resolved,
293 &mut decoder,
294 );
295
296 Ok(styles_payload_with_flat(flat, &resolved).into())
297 }
298}
299
300pub(super) fn styles_payload(
305 resolved: &ifc_lite_processing::prepass::ResolvedPrepass,
306 decoder: &mut ifc_lite_core::EntityDecoder,
307) -> js_sys::Object {
308 let flat = ifc_lite_processing::prepass::flat_styles_rgba8(resolved, decoder);
309 styles_payload_with_flat(flat, resolved)
310}
311
312pub(super) fn styles_payload_with_flat(
315 (style_ids_vec, style_colors_vec): (Vec<u32>, Vec<u8>),
316 resolved: &ifc_lite_processing::prepass::ResolvedPrepass,
317) -> js_sys::Object {
318 let (void_keys_vec, void_counts_vec, void_values_vec) =
319 ifc_lite_processing::prepass::flat_voids(&resolved.void_index);
320 let (mat_ids_vec, mat_counts_vec, mat_colors_vec) =
321 ifc_lite_processing::prepass::flat_material_colors(&resolved.element_material_colors);
322 let result = js_sys::Object::new();
323 crate::api::set_js_prop(&result, "styleIds", &js_sys::Uint32Array::from(style_ids_vec.as_slice()));
324 crate::api::set_js_prop(&result, "styleColors", &js_sys::Uint8Array::from(style_colors_vec.as_slice()));
325 crate::api::set_js_prop(&result, "voidKeys", &js_sys::Uint32Array::from(void_keys_vec.as_slice()));
326 crate::api::set_js_prop(&result, "voidCounts", &js_sys::Uint32Array::from(void_counts_vec.as_slice()));
327 crate::api::set_js_prop(&result, "voidValues", &js_sys::Uint32Array::from(void_values_vec.as_slice()));
328 crate::api::set_js_prop(&result, "materialElementIds", &js_sys::Uint32Array::from(mat_ids_vec.as_slice()));
329 crate::api::set_js_prop(&result, "materialColorCounts", &js_sys::Uint32Array::from(mat_counts_vec.as_slice()));
330 crate::api::set_js_prop(&result, "materialColors", &js_sys::Uint8Array::from(mat_colors_vec.as_slice()));
331 result
332}