cadmpeg-codec-catia 0.3.0

Read geometry and topology from .CATPart files.
Documentation
// SPDX-License-Identifier: Apache-2.0
//! Record-decoder tests for the `zero_entity` family over synthetic byte fixtures.

#![allow(clippy::unwrap_used)]

use crate::tests::{le_f32, le_f64, zero_entity_record, OUTER_MAGIC};

#[test]
fn zero_entity_vertices_exclude_framed_payload_markers() {
    let mut bytes = vec![0u8; 16];
    bytes[..8].copy_from_slice(OUTER_MAGIC);
    let mut record = vec![0u8; 0x15 + 12];
    record[..4].copy_from_slice(&[0xa9, 0x03, 0x10, 0x15]);
    record[4..7].copy_from_slice(&[0x05, 0x08, 0x01]);
    for (index, value) in [90.0f32, 91.0, 92.0].into_iter().enumerate() {
        record[7 + index * 4..11 + index * 4].copy_from_slice(&le_f32(value));
    }
    bytes.extend_from_slice(&record);
    bytes.extend_from_slice(&[0x05, 0x08, 0x01]);
    for value in [1.0f32, 2.0, 3.0] {
        bytes.extend_from_slice(&le_f32(value));
    }

    assert_eq!(
        crate::families::zero_entity::graph::unframed_vertices(&bytes),
        [cadmpeg_ir::math::Point3::new(1.0, 2.0, 3.0)]
    );

    let mut malformed = vec![0xa9, 0x03, 0x10, 0xff, 0x05, 0x08, 0x01];
    malformed.extend_from_slice(&[0; 12]);
    assert!(crate::families::zero_entity::graph::unframed_vertices(&malformed).is_empty());
}

#[test]
fn zero_entity_parser_decodes_face_loop_lanes_and_packed_senses() {
    let mut carrier = zero_entity_record(0x27, vec![0; 106]);
    for (offset, value) in [
        (14usize, 10.0f64),
        (22, 0.0),
        (30, 0.0),
        (38, 1.0),
        (46, 0.0),
        (54, 0.0),
        (62, 0.0),
        (70, 1.0),
        (78, 0.0),
    ] {
        carrier[offset..offset + 8].copy_from_slice(&le_f64(value));
    }
    let mut support_tail = vec![0; 113];
    support_tail[0] = 0x10;
    support_tail[1..5].copy_from_slice(&2u32.to_le_bytes());
    for (offset, value) in [(81usize, 1.0f64), (89, 2.0), (97, 3.0), (105, 4.0)] {
        support_tail[offset..offset + 8].copy_from_slice(&le_f64(value));
    }
    let support = zero_entity_record(0x21, support_tail);
    let mut face_tail = vec![0x82, 0x10];
    face_tail.extend_from_slice(&1000u32.to_le_bytes());
    face_tail.push(0x10);
    face_tail.extend_from_slice(&900u32.to_le_bytes());
    face_tail.push(0);
    let face = zero_entity_record(0x5f, face_tail);

    let mut loop_tail = vec![0x85];
    for reference in [98u32, 500, 97, 501, 100] {
        loop_tail.push(0x10);
        loop_tail.extend_from_slice(&reference.to_le_bytes());
    }
    loop_tail.extend_from_slice(&[0x82, 0x41, 0b01_0111, 0x01]);
    let loop_record = zero_entity_record(0x62, loop_tail);
    let mut physical_edge = zero_entity_record(0x5e, vec![0; 26]);
    for (offset, reference) in [
        (7usize, 10u32),
        (12, 20),
        (17, 30),
        (22, 40),
        (27, 50),
        (32, 60),
    ] {
        physical_edge[offset] = 0x10;
        physical_edge[offset + 1..offset + 5].copy_from_slice(&reference.to_le_bytes());
    }
    let mut side_pair_tail = vec![0x82, 0x10];
    side_pair_tail.extend_from_slice(&1000u32.to_le_bytes());
    side_pair_tail.push(0x10);
    side_pair_tail.extend_from_slice(&2000u32.to_le_bytes());
    side_pair_tail.resize(105, 0);
    let side_pair = zero_entity_record(0x25, side_pair_tail);
    let coedge_twin = |side: u8| {
        let mut record = zero_entity_record(0x06, vec![0; 56]);
        record[7] = 0x10;
        record[8..12].copy_from_slice(&1u32.to_le_bytes());
        record[12..15].copy_from_slice(&[0x83, 0x10, side]);
        for (offset, reference) in [
            (15usize, 1000u32 + u32::from(side)),
            (20, 2000u32 + u32::from(side)),
        ] {
            record[offset] = 0x10;
            record[offset + 1..offset + 5].copy_from_slice(&reference.to_le_bytes());
        }
        record
    };
    let mut incidence_tail = vec![0x83];
    for item in [700u32, 701, 702] {
        incidence_tail.push(0x10);
        incidence_tail.extend_from_slice(&item.to_le_bytes());
    }
    let incidence = zero_entity_record(0x05, incidence_tail);
    let vertex_marker = zero_entity_record(0x5d, vec![0; 6]);
    let mut bytes = carrier;
    bytes.extend_from_slice(&support);
    bytes.extend_from_slice(&face);
    bytes.extend_from_slice(&loop_record);
    bytes.extend_from_slice(&physical_edge);
    bytes.extend_from_slice(&side_pair);
    bytes.extend_from_slice(&coedge_twin(1));
    bytes.extend_from_slice(&coedge_twin(2));
    bytes.extend_from_slice(&incidence);
    bytes.extend_from_slice(&vertex_marker);

    let topology =
        crate::families::zero_entity::graph::parse(&bytes).expect("zero-entity topology records");
    assert_eq!(topology.faces[0].loop_terminals, vec![100]);
    assert_eq!(topology.loops[0].member_ids, vec![98, 97]);
    assert_eq!(topology.loops[0].secondary_refs, vec![500, 501]);
    assert_eq!(topology.loops[0].terminal_id, 100);
    assert_eq!(topology.loops[0].reversed, vec![false, true]);
    assert!(!topology.loops[0].inner);
    assert_eq!(topology.carrier_runs[0].support_ordinals, vec![1]);
    assert_eq!(topology.supports[0].slot, 2);
    assert_eq!(
        topology.supports[0].uv_endpoints,
        Some([[1.0, 2.0], [3.0, 4.0]])
    );
    assert_eq!(topology.faces[0].loop_indices, vec![0]);
    assert_eq!(topology.loops[0].support_indices, vec![Some(0), None]);
    assert_eq!(
        topology.supports[0].lifted_endpoints,
        Some([[11.0, 2.0, 0.0], [13.0, 4.0, 0.0]])
    );
    assert_eq!(
        topology.physical_edges[0].references,
        [10, 20, 30, 40, 50, 60]
    );
    assert_eq!(topology.side_pairs[0].bases, [1000, 2000]);
    assert_eq!(
        topology.side_pairs[0].composite_keys,
        [[1001, 2001], [1002, 2002]]
    );
    assert_eq!(topology.coedge_twins[1].side, 2);
    assert_eq!(topology.vertices[0].incidence_items, vec![700, 701, 702]);
}