use crate::schema_gen::DecodedEntity;
pub(super) fn compound_plane_angle_to_degrees(entity: &DecodedEntity, index: usize) -> Option<f64> {
let list = entity.get_list(index)?;
let mut numbers = Vec::with_capacity(4);
for value in list {
if let Some(v) = value.as_float() {
numbers.push(v);
}
}
if numbers.len() < 3 {
return None;
}
let millionths = numbers.get(3).copied().unwrap_or(0.0);
let sign = if numbers[0] < 0.0 || numbers[1] < 0.0 || numbers[2] < 0.0 || millionths < 0.0 {
-1.0
} else {
1.0
};
let degrees = numbers[0].abs();
let minutes = numbers[1].abs();
let seconds = numbers[2].abs();
let millionths = millionths.abs();
Some(sign * (degrees + minutes / 60.0 + (seconds + millionths / 1_000_000.0) / 3600.0))
}
pub(super) fn compound_angle_has_literal_negative_zero(bytes: &[u8], attr_index: usize) -> bool {
let Some(list_bytes) = nth_top_level_attribute(bytes, attr_index) else {
return false;
};
let trimmed = list_bytes.trim_ascii();
let Some(inner) = trimmed
.strip_prefix(b"(")
.and_then(|b| b.strip_suffix(b")"))
else {
return false;
};
inner
.split(|&b| b == b',')
.any(|component| component.trim_ascii() == b"-0")
}
fn nth_top_level_attribute(bytes: &[u8], attr_index: usize) -> Option<&[u8]> {
let len = bytes.len();
let mut i = 0;
while i < len && bytes[i] != b'(' {
i += 1;
}
if i >= len {
return None;
}
i += 1;
let mut depth: i32 = 1;
let mut in_string: Option<u8> = None;
let mut attr_start = i;
let mut attr_idx = 0usize;
while i < len {
let b = bytes[i];
if let Some(q) = in_string {
if b == q {
if i + 1 < len && bytes[i + 1] == q {
i += 2; continue;
}
in_string = None;
}
i += 1;
continue;
}
match b {
b'\'' | b'"' => {
in_string = Some(b);
i += 1;
}
b'(' => {
depth += 1;
i += 1;
}
b')' => {
depth -= 1;
if depth == 0 {
return (attr_idx == attr_index).then(|| &bytes[attr_start..i]);
}
i += 1;
}
b',' if depth == 1 => {
if attr_idx == attr_index {
return Some(&bytes[attr_start..i]);
}
attr_idx += 1;
i += 1;
attr_start = i;
}
_ => i += 1,
}
}
None
}