use byteorder::{LittleEndian, WriteBytesExt};
use std::io::Write;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VoxelKey {
pub level: i32,
pub x: i32,
pub y: i32,
pub z: i32,
}
impl VoxelKey {
pub fn parent(self) -> Option<VoxelKey> {
if self.level == 0 {
return None;
}
Some(VoxelKey {
level: self.level - 1,
x: self.x / 2,
y: self.y / 2,
z: self.z / 2,
})
}
}
#[derive(Debug, Clone)]
pub struct CopcInfo {
pub center_x: f64,
pub center_y: f64,
pub center_z: f64,
pub halfsize: f64,
pub spacing: f64,
pub root_hier_offset: u64,
pub root_hier_size: u64,
pub gpstime_minimum: f64,
pub gpstime_maximum: f64,
}
impl CopcInfo {
pub fn write<W: Write>(&self, w: &mut W) -> anyhow::Result<()> {
w.write_f64::<LittleEndian>(self.center_x)?;
w.write_f64::<LittleEndian>(self.center_y)?;
w.write_f64::<LittleEndian>(self.center_z)?;
w.write_f64::<LittleEndian>(self.halfsize)?;
w.write_f64::<LittleEndian>(self.spacing)?;
w.write_u64::<LittleEndian>(self.root_hier_offset)?;
w.write_u64::<LittleEndian>(self.root_hier_size)?;
w.write_f64::<LittleEndian>(self.gpstime_minimum)?;
w.write_f64::<LittleEndian>(self.gpstime_maximum)?;
for _ in 0..11 {
w.write_u64::<LittleEndian>(0)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct HierarchyEntry {
pub key: VoxelKey,
pub offset: u64,
pub byte_size: i32,
pub point_count: i32,
}
impl HierarchyEntry {
pub fn write<W: Write>(&self, w: &mut W) -> anyhow::Result<()> {
w.write_i32::<LittleEndian>(self.key.level)?;
w.write_i32::<LittleEndian>(self.key.x)?;
w.write_i32::<LittleEndian>(self.key.y)?;
w.write_i32::<LittleEndian>(self.key.z)?;
w.write_u64::<LittleEndian>(self.offset)?;
w.write_i32::<LittleEndian>(self.byte_size)?;
w.write_i32::<LittleEndian>(self.point_count)?;
Ok(())
}
}
pub fn write_vlr<W: Write>(
w: &mut W,
user_id: &str,
record_id: u16,
description: &str,
payload: &[u8],
) -> anyhow::Result<()> {
w.write_u16::<LittleEndian>(0)?;
let mut uid = [0u8; 16];
let b = user_id.as_bytes();
uid[..b.len().min(16)].copy_from_slice(&b[..b.len().min(16)]);
w.write_all(&uid)?;
w.write_u16::<LittleEndian>(record_id)?;
w.write_u16::<LittleEndian>(payload.len() as u16)?;
let mut desc = [0u8; 32];
let db = description.as_bytes();
desc[..db.len().min(32)].copy_from_slice(&db[..db.len().min(32)]);
w.write_all(&desc)?;
w.write_all(payload)?;
Ok(())
}
pub fn write_evlr<W: Write>(
w: &mut W,
user_id: &str,
record_id: u16,
description: &str,
payload: &[u8],
) -> anyhow::Result<()> {
w.write_u16::<LittleEndian>(0)?;
let mut uid = [0u8; 16];
let b = user_id.as_bytes();
uid[..b.len().min(16)].copy_from_slice(&b[..b.len().min(16)]);
w.write_all(&uid)?;
w.write_u16::<LittleEndian>(record_id)?;
w.write_u64::<LittleEndian>(payload.len() as u64)?;
let mut desc = [0u8; 32];
let db = description.as_bytes();
desc[..db.len().min(32)].copy_from_slice(&db[..db.len().min(32)]);
w.write_all(&desc)?;
w.write_all(payload)?;
Ok(())
}
pub const EVLR_HEADER_SIZE: usize = 60;