use ifc_lite_geometry::{bake_source_at_world, SharedMappedItemCache};
use ifc_lite_processing::{MeshData, RawInstanceOccurrence};
use rustc_hash::FxHashMap;
pub(super) struct TemplateInfo {
pub eligible: bool,
}
pub(super) struct ShardOccurrence {
pub entity_id: u32,
pub color: [f32; 4],
pub rep_identity: u128,
pub world_transform: [f64; 16],
}
pub(super) fn resolve_batch_occurrences(
raw: Vec<RawInstanceOccurrence>,
template_by_rep: &FxHashMap<u128, TemplateInfo>,
mapped_item_cache: &SharedMappedItemCache,
rtc: [f64; 3],
min_occurrences: usize,
recovered_flats: &mut Vec<MeshData>,
) -> Vec<ShardOccurrence> {
if raw.is_empty() {
return Vec::new();
}
let mut by_rep: FxHashMap<u128, Vec<RawInstanceOccurrence>> = FxHashMap::default();
for occ in raw {
by_rep.entry(occ.rep_identity).or_default().push(occ);
}
let mut groups: Vec<(u128, Vec<RawInstanceOccurrence>)> = by_rep.into_iter().collect();
groups.sort_by_key(|(rep, _)| *rep);
let mut shard: Vec<ShardOccurrence> = Vec::new();
for (rep, occs) in groups {
let keep = template_by_rep
.get(&rep)
.is_some_and(|t| t.eligible)
&& (occs.len() + 1) >= min_occurrences;
if keep {
for occ in occs {
shard.push(ShardOccurrence {
entity_id: occ.express_id,
color: occ.color,
rep_identity: rep,
world_transform: occ.world_transform,
});
}
} else {
recover_flat(rep, &occs, mapped_item_cache, rtc, recovered_flats);
}
}
shard.sort_by_key(|o| (o.entity_id, o.rep_identity));
shard
}
fn recover_flat(
rep: u128,
occs: &[RawInstanceOccurrence],
mapped_item_cache: &SharedMappedItemCache,
rtc: [f64; 3],
out: &mut Vec<MeshData>,
) {
let source_id = rep as u32;
let source = mapped_item_cache
.lock()
.unwrap_or_else(|e| e.into_inner())
.get(&source_id)
.cloned();
let Some(source) = source else {
return;
};
for occ in occs {
let (positions, normals, indices) =
bake_source_at_world(&source, &occ.world_transform, rtc);
if positions.is_empty() || indices.is_empty() {
continue;
}
out.push(
MeshData::new(
occ.express_id,
occ.ifc_type.clone(),
positions,
normals,
indices,
occ.color,
)
.with_element_metadata(
occ.global_id.clone(),
occ.name.clone(),
occ.presentation_layer.clone(),
),
);
}
}