use ifc_model::{Entity, EntityId, Model, Value};
use super::violation::{RuleViolation, ViolationKind};
pub fn check(_model: &Model, id: EntityId, entity: &Entity, out: &mut Vec<RuleViolation>) {
let name = entity.type_name.to_ascii_uppercase();
if name.starts_with("IFCCARTESIANTRANSFORMATIONOPERATOR") {
let scl = real_at(entity, 3).unwrap_or(1.0);
positive(id, &name, "ScaleGreaterZero", "Scl", scl, false, out);
if name == "IFCCARTESIANTRANSFORMATIONOPERATOR2DNONUNIFORM" {
let s2 = real_at(entity, 4).unwrap_or(scl);
positive(id, &name, "Scale2GreaterZero", "Scl2", s2, false, out);
} else if name == "IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM" {
let s2 = real_at(entity, 5).unwrap_or(scl);
let s3 = real_at(entity, 6).unwrap_or(scl);
positive(id, &name, "Scale2GreaterZero", "Scl2", s2, false, out);
positive(id, &name, "Scale3GreaterZero", "Scl3", s3, false, out);
}
}
if name == "IFCREPARAMETRISEDCOMPOSITECURVESEGMENT" {
if let Some(v) = real_at(entity, 3) {
positive(
id,
&name,
"PositiveLengthParameter",
"ParamLength",
v,
false,
out,
);
}
}
if name == "IFCSURFACEOFLINEAREXTRUSION" {
if let Some(v) = real_at(entity, 3) {
positive(id, &name, "DepthGreaterZero", "Depth", v, false, out);
}
}
if name == "IFCVECTOR" {
if let Some(v) = real_at(entity, 1) {
positive(
id,
&name,
"MagGreaterOrEqualZero",
"Magnitude",
v,
true,
out,
);
}
}
}
fn real_at(entity: &Entity, slot: usize) -> Option<f64> {
match entity.attribute(slot)?.unwrap_typed() {
Value::Real(v) => Some(*v),
Value::Integer(v) => Some(*v as f64),
_ => None,
}
}
fn positive(
id: EntityId,
type_name: &str,
rule: &'static str,
label: &str,
value: f64,
zero_ok: bool,
out: &mut Vec<RuleViolation>,
) {
let ok = if zero_ok { value >= 0.0 } else { value > 0.0 };
if ok {
return;
}
let bound = if zero_ok {
"at least 0"
} else {
"greater than 0"
};
out.push(RuleViolation::new(
id,
type_name.to_string(),
rule,
ViolationKind::Degenerate,
format!("{label} is {value}, must be {bound}"),
));
}