plozone 0.1.1

3D spatial zone engine: geofencing, octree hole-scanning, realtime sync (WebSocket + QUIC + io_uring), voxel pathfinding, and AV sensor fusion.
Documentation
//! End-to-end smoke test: convert geodetic zones, query them, ingest points
//! into the octree, and scan a zone for unsampled holes.

use plozone::{
    EnuConverter, OctreeNode, ScanMode, Zone, ZoneEntry, ZoneStore, run_scan, scan_holes,
};

#[test]
fn geofence_query_and_hole_scan() {
    let conv = EnuConverter::new(10.7626, 106.6601, 0.0);

    // A cylindrical zone and an overlapping box, both geodetic.
    let mut store = ZoneStore::from_entries(
    &[
        ZoneEntry::new(
            1,
            Zone::Cylinder { center: [10.7626, 106.6601], radius_m: 30.0, z_min: 0.0, z_max: 10.0 },
        ),
        ZoneEntry::new(
            2,
            Zone::Aabb { min: [10.7620, 106.6595, 0.0], max: [10.7632, 106.6607, 10.0] },
        ),
    ],
        &conv,
    );
    assert_eq!(store.len(), 2);

    // The origin sits inside both zones.
    let mut hits = store.query_geodetic(10.7626, 106.6601, 5.0, &conv);
    hits.sort();
    let expected: smallvec::SmallVec<[u32; 8]> = smallvec::smallvec![1, 2];
    assert_eq!(hits, expected);

    // Remove the box; only the cylinder remains.
    store.remove(2);
    let expected2: smallvec::SmallVec<[u32; 8]> = smallvec::smallvec![1];
    assert_eq!(store.query_geodetic(10.7626, 106.6601, 5.0, &conv), expected2);

    // Empty octree over the same neighbourhood → the cylinder is entirely holes.
    let octree = OctreeNode::new([0.0; 3], 64.0);
    let empty = run_scan(&octree, &store, 1, &ScanMode::Coarse { depth: 4 });
    assert_eq!(empty.coverage_pct, 0.0, "no points sampled yet");
    assert_eq!(empty.holes.len(), empty.node_count);

    // Sample a cluster of points; coverage must rise and holes must drop.
    let mut octree = OctreeNode::new([0.0; 3], 64.0);
    for dx in -10..=10 {
        for dy in -10..=10 {
            octree.insert([dx as f64, dy as f64, 5.0], 32);
        }
    }
    let sampled = run_scan(&octree, &store, 1, &ScanMode::Coarse { depth: 4 });
    assert!(sampled.coverage_pct > empty.coverage_pct);
    assert!(scan_holes(&octree, &store, 1, 4).len() < empty.holes.len());
}