use ifc_lite_core::{EntityDecoder, IfcType};
fn read_colour_rgb(color_id: u32, decoder: &mut EntityDecoder) -> Option<[f32; 4]> {
let color = decoder.decode_by_id(color_id).ok()?;
if color.ifc_type != IfcType::IfcColourRgb {
return None;
}
let r = color.get_float(1).unwrap_or(0.8) as f32;
let g = color.get_float(2).unwrap_or(0.8) as f32;
let b = color.get_float(3).unwrap_or(0.8) as f32;
Some([r, g, b, 1.0])
}
fn rendering_colours(
rendering_id: u32,
decoder: &mut EntityDecoder,
) -> Option<([f32; 4], Option<[f32; 4]>)> {
let rendering = decoder.decode_by_id(rendering_id).ok()?;
match rendering.ifc_type {
IfcType::IfcSurfaceStyleRendering | IfcType::IfcSurfaceStyleShading => {
let color_ref = rendering.get_ref(0)?;
let [sr, sg, sb, _] = read_colour_rgb(color_ref, decoder)?;
let transparency = rendering.get_float(1).unwrap_or(0.0);
let alpha = (1.0 - transparency as f32).clamp(0.0, 1.0);
let surface_rgba = [sr, sg, sb, alpha];
let mut apparent = surface_rgba;
let mut shading: Option<[f32; 4]> = None;
if rendering.ifc_type == IfcType::IfcSurfaceStyleRendering {
if let Some(diffuse_id) = rendering.get_ref(2) {
if let Some([dr, dg, db, _]) = read_colour_rgb(diffuse_id, decoder) {
let diffuse_rgba = [dr, dg, db, alpha];
if diffuse_rgba != surface_rgba {
shading = Some(diffuse_rgba);
}
}
} else if let Some(factor) = rendering.get_float(2) {
let f = (factor as f32).clamp(0.0, 1.0);
apparent = [sr * f, sg * f, sb * f, alpha];
}
}
Some((apparent, shading))
}
_ => None,
}
}
pub fn extract_surface_style_colors(
surface_style_id: u32,
decoder: &mut EntityDecoder,
) -> Option<([f32; 4], Option<[f32; 4]>)> {
let style = decoder.decode_by_id(surface_style_id).ok()?;
if style.ifc_type != IfcType::IfcSurfaceStyle {
return None;
}
let styles_attr = style.get(2)?;
let list = styles_attr.as_list()?;
for item in list {
if let Some(element_id) = item.as_entity_ref() {
if let Some(pair) = rendering_colours(element_id, decoder) {
return Some(pair);
}
}
}
None
}