use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use las::{Bounds, Vector, Vlr};
use std::hash::Hash;
use std::io::{Cursor, Read, Write};
#[derive(Clone, Debug, Default)]
pub struct CopcInfo {
pub center: Vector<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(crate) fn read_from<R: Read>(mut read: R) -> crate::Result<Self> {
Ok(CopcInfo {
center: Vector {
x: read.read_f64::<LittleEndian>()?,
y: read.read_f64::<LittleEndian>()?,
z: read.read_f64::<LittleEndian>()?,
},
halfsize: read.read_f64::<LittleEndian>()?,
spacing: read.read_f64::<LittleEndian>()?,
root_hier_offset: read.read_u64::<LittleEndian>()?,
root_hier_size: read.read_u64::<LittleEndian>()?,
gpstime_minimum: read.read_f64::<LittleEndian>()?,
gpstime_maximum: read.read_f64::<LittleEndian>()?,
})
}
pub(crate) fn into_vlr(self) -> crate::Result<Vlr> {
let mut buffer = Cursor::new([0_u8; 160]);
buffer.write_f64::<LittleEndian>(self.center.x)?;
buffer.write_f64::<LittleEndian>(self.center.y)?;
buffer.write_f64::<LittleEndian>(self.center.z)?;
buffer.write_f64::<LittleEndian>(self.halfsize)?;
buffer.write_f64::<LittleEndian>(self.spacing)?;
buffer.write_u64::<LittleEndian>(self.root_hier_offset)?;
buffer.write_u64::<LittleEndian>(self.root_hier_size)?;
buffer.write_f64::<LittleEndian>(self.gpstime_minimum)?;
buffer.write_f64::<LittleEndian>(self.gpstime_maximum)?;
Ok(Vlr {
user_id: "copc".to_string(),
record_id: 1,
description: "COPC info VLR".to_string(),
data: Vec::from(buffer.into_inner()),
})
}
}
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
pub struct VoxelKey {
pub level: i32,
pub x: i32,
pub y: i32,
pub z: i32,
}
impl Default for VoxelKey {
fn default() -> Self {
VoxelKey {
level: -1,
x: 0,
y: 0,
z: 0,
}
}
}
impl VoxelKey {
pub(crate) fn read_from<R: Read>(read: &mut R) -> crate::Result<Self> {
Ok(VoxelKey {
level: read.read_i32::<LittleEndian>()?,
x: read.read_i32::<LittleEndian>()?,
y: read.read_i32::<LittleEndian>()?,
z: read.read_i32::<LittleEndian>()?,
})
}
pub(crate) fn write_to<W: Write>(self, write: &mut W) -> crate::Result<()> {
write.write_i32::<LittleEndian>(self.level)?;
write.write_i32::<LittleEndian>(self.x)?;
write.write_i32::<LittleEndian>(self.y)?;
write.write_i32::<LittleEndian>(self.z)?;
Ok(())
}
pub(crate) fn child(&self, dir: i32) -> VoxelKey {
VoxelKey {
level: self.level + 1,
x: (self.x << 1) | (dir & 0x1),
y: (self.y << 1) | ((dir >> 1) & 0x1),
z: (self.z << 1) | ((dir >> 2) & 0x1),
}
}
pub(crate) fn children(&self) -> Vec<VoxelKey> {
(0..8).map(|i| self.child(i)).collect()
}
pub(crate) fn bounds(&self, root_bounds: &Bounds) -> Bounds {
let side_size =
(root_bounds.max.x - root_bounds.min.x) / 2_u32.pow(self.level as u32) as f64;
Bounds {
min: Vector {
x: root_bounds.min.x + self.x as f64 * side_size,
y: root_bounds.min.y + self.y as f64 * side_size,
z: root_bounds.min.z + self.z as f64 * side_size,
},
max: Vector {
x: root_bounds.min.x + (self.x + 1) as f64 * side_size,
y: root_bounds.min.y + (self.y + 1) as f64 * side_size,
z: root_bounds.min.z + (self.z + 1) as f64 * side_size,
},
}
}
}
#[derive(Clone, Default, Debug)]
pub struct Entry {
pub key: VoxelKey,
pub offset: u64,
pub byte_size: i32,
pub point_count: i32,
}
impl Entry {
pub(crate) fn read_from<R: Read>(read: &mut R) -> crate::Result<Self> {
Ok(Entry {
key: VoxelKey::read_from(read)?,
offset: read.read_u64::<LittleEndian>()?,
byte_size: read.read_i32::<LittleEndian>()?,
point_count: read.read_i32::<LittleEndian>()?,
})
}
pub(crate) fn write_to<W: Write>(self, write: &mut W) -> crate::Result<()> {
self.key.write_to(write)?;
write.write_u64::<LittleEndian>(self.offset)?;
write.write_i32::<LittleEndian>(self.byte_size)?;
write.write_i32::<LittleEndian>(self.point_count)?;
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct HierarchyPage {
pub entries: Vec<Entry>,
}
impl HierarchyPage {
pub(crate) fn read_from<R: Read>(mut read: R, page_size: u64) -> crate::Result<Self> {
let num_entries = page_size as usize / 32;
let mut entries = Vec::with_capacity(num_entries);
for _ in 0..num_entries {
let entry = Entry::read_from(&mut read)?;
entries.push(entry);
}
Ok(HierarchyPage { entries })
}
pub(crate) fn into_evlr(self) -> crate::Result<Vlr> {
let mut buffer = Cursor::new(vec![0_u8; self.entries.len() * 32]);
for e in self.entries {
e.write_to(&mut buffer)?;
}
Ok(Vlr {
user_id: "copc".to_string(),
record_id: 1000,
description: "EPT Hierarchy".to_string(),
data: buffer.into_inner(),
})
}
pub fn byte_size(&self) -> u64 {
(self.entries.len() * 32) as u64
}
}
#[derive(Clone, Debug)]
pub(crate) struct OctreeNode {
pub entry: Entry,
pub bounds: Bounds,
pub children: Vec<OctreeNode>,
}
impl OctreeNode {
pub fn new() -> Self {
OctreeNode {
entry: Entry::default(),
bounds: Bounds {
min: Vector::default(),
max: Vector::default(),
},
children: Vec::with_capacity(8),
}
}
pub fn is_full(&self, max_size: i32) -> bool {
self.entry.point_count >= max_size
}
}