proof of concept MDD
This commit is contained in:
commit
6f1c60fc70
|
@ -0,0 +1 @@
|
|||
/target
|
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "pointcache"
|
||||
version = "0.1.0"
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "pointcache"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,4 @@
|
|||
# Parser / Encoder for pointcache file formats
|
||||
|
||||
## References
|
||||
- https://github.com/brainexcerpts/MDD_file_exporter
|
Binary file not shown.
|
@ -0,0 +1,213 @@
|
|||
use std::fmt::Display;
|
||||
use std::io::Write;
|
||||
use std::mem::size_of;
|
||||
use std::ops::Range;
|
||||
use std::{
|
||||
error::Error,
|
||||
fs::File,
|
||||
io::{BufReader, Read, Seek, SeekFrom},
|
||||
iter::repeat,
|
||||
};
|
||||
|
||||
pub trait PointCache {
|
||||
fn map<F: FnMut(MDDFrame) -> Result<(), Box<dyn Error>>>(
|
||||
infile: File,
|
||||
op: F,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
fn map_to<F: FnMut(MDDFrame) -> Result<MDDFrame, Box<dyn Error>>>(
|
||||
infile: File,
|
||||
outfile: File,
|
||||
op: F,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
pub struct MDDSeekableFile;
|
||||
struct MDDSeekableFileReader {
|
||||
total_frames: i32,
|
||||
total_points: i32,
|
||||
data: Box<dyn Iterator<Item = Result<MDDFrame, Box<dyn Error>>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Point {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct MDDFrame {
|
||||
frame_idx: usize,
|
||||
point_idx: usize,
|
||||
time: f32,
|
||||
point: Point,
|
||||
}
|
||||
|
||||
impl MDDSeekableFile {
|
||||
fn read_header(infile: &mut File) -> Result<(i32, i32), Box<dyn Error>> {
|
||||
infile.seek(SeekFrom::Start(0));
|
||||
let mut buff = [0u8; size_of::<i32>()];
|
||||
infile.read_exact(&mut buff)?;
|
||||
let total_frames = i32::from_be_bytes(buff);
|
||||
infile.read_exact(&mut buff)?;
|
||||
let total_points = i32::from_be_bytes(buff);
|
||||
|
||||
return Ok((total_frames, total_points));
|
||||
}
|
||||
fn write_header(
|
||||
outfile: &mut File,
|
||||
total_frames: i32,
|
||||
total_points: i32,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
outfile.seek(SeekFrom::Start(0));
|
||||
outfile.write_all(&total_frames.to_be_bytes())?;
|
||||
outfile.write_all(&total_points.to_be_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
fn read(mut infile: File) -> Result<MDDSeekableFileReader, Box<dyn Error>> {
|
||||
let (total_frames, total_points) = MDDSeekableFile::read_header(&mut infile)?;
|
||||
let time_byte_offset = (total_frames as usize) * size_of::<f32>();
|
||||
|
||||
let mut buff = [0u8; size_of::<f32>()];
|
||||
let times = Box::new(
|
||||
repeat(())
|
||||
.map::<Result<_, Box<dyn Error>>, _>(move |()| {
|
||||
//times.read_exact(&mut buff)?;
|
||||
//Ok(f32::from_be_bytes(buff))
|
||||
Ok(0.0)
|
||||
})
|
||||
.take(total_frames.try_into()?),
|
||||
);
|
||||
|
||||
let header_size: u64 = (size_of::<i32>() * 2).try_into()?;
|
||||
let f32_size: u64 = size_of::<f32>().try_into()?;
|
||||
let mut buff = [0u8; size_of::<f32>()];
|
||||
let data = Box::new(
|
||||
(0..((total_frames * total_points) as u64)).map::<Result<_, Box<dyn Error>>, _>(
|
||||
move |count| {
|
||||
let frame_idx: usize = (count / (total_points as u64)).try_into()?;
|
||||
let time_offset: u64 = f32_size * (frame_idx as u64);
|
||||
let time_size: u64 = f32_size * (total_frames as u64);
|
||||
let data_offset: u64 = f32_size * count * 3;
|
||||
|
||||
infile.seek(SeekFrom::Start(header_size + time_offset))?;
|
||||
infile.read_exact(&mut buff)?;
|
||||
let time = f32::from_be_bytes(buff);
|
||||
|
||||
infile.seek(SeekFrom::Start(header_size + time_size + data_offset))?;
|
||||
infile.read_exact(&mut buff)?;
|
||||
let x = f32::from_be_bytes(buff);
|
||||
infile.read_exact(&mut buff)?;
|
||||
let y = f32::from_be_bytes(buff);
|
||||
infile.read_exact(&mut buff)?;
|
||||
let z = f32::from_be_bytes(buff);
|
||||
let point = Point { x, y, z };
|
||||
|
||||
let point_idx: usize = (count % (total_points as u64)).try_into()?;
|
||||
Ok(MDDFrame {
|
||||
frame_idx,
|
||||
point_idx,
|
||||
time,
|
||||
point,
|
||||
})
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
Ok(MDDSeekableFileReader {
|
||||
total_frames,
|
||||
total_points,
|
||||
data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExaustedPointsUnexpectedly;
|
||||
impl Display for ExaustedPointsUnexpectedly {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "ExaustedPointsUnexpectedly")
|
||||
}
|
||||
}
|
||||
impl Error for ExaustedPointsUnexpectedly {}
|
||||
|
||||
impl PointCache for MDDSeekableFile {
|
||||
fn map<F>(infile: File, mut op: F) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
F: FnMut(MDDFrame) -> Result<(), Box<dyn Error>>,
|
||||
{
|
||||
let MDDSeekableFileReader {
|
||||
total_frames: _,
|
||||
total_points: _,
|
||||
data,
|
||||
} = MDDSeekableFile::read(infile)?;
|
||||
|
||||
for frame in data {
|
||||
op(frame?)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map_to<F>(mut infile: File, mut outfile: File, mut op: F) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
F: FnMut(MDDFrame) -> Result<MDDFrame, Box<dyn Error>>,
|
||||
{
|
||||
let (total_frames, total_points) = MDDSeekableFile::read_header(&mut infile)?;
|
||||
MDDSeekableFile::write_header(&mut outfile, total_frames, total_points)?;
|
||||
|
||||
let header_size: u64 = (size_of::<i32>() * 2).try_into()?;
|
||||
let f32_size: u64 = size_of::<f32>().try_into()?;
|
||||
let mut count = 0;
|
||||
|
||||
Self::map(infile, |frame| {
|
||||
let frame = op(frame)?;
|
||||
let frame_idx: u64 = count / (total_points as u64);
|
||||
let time_offset: u64 = f32_size * frame_idx;
|
||||
let time_size: u64 = f32_size * (total_frames as u64);
|
||||
let data_offset: u64 = f32_size * count * 3;
|
||||
|
||||
outfile.seek(SeekFrom::Start(header_size + time_offset))?;
|
||||
outfile.write_all(&frame.time.to_be_bytes())?;
|
||||
|
||||
outfile.seek(SeekFrom::Start(header_size + time_size + data_offset))?;
|
||||
outfile.write_all(&frame.point.x.to_be_bytes())?;
|
||||
outfile.write_all(&frame.point.y.to_be_bytes())?;
|
||||
outfile.write_all(&frame.point.z.to_be_bytes())?;
|
||||
|
||||
count += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() -> Result<(), Box<dyn Error>> {
|
||||
let infile = File::open("test_cube.mdd")?;
|
||||
let outfile = File::create("output.mdd")?;
|
||||
println!("MAPPING test_cube.mdd to output.mdd");
|
||||
MDDSeekableFile::map_to(infile, outfile, |mut frame| {
|
||||
frame.point.x = frame.frame_idx as f32;
|
||||
frame.point.y = (frame.frame_idx * 2) as f32;
|
||||
frame.point.z = 0.0;
|
||||
|
||||
println!("{:?}", frame);
|
||||
Ok(frame)
|
||||
})?;
|
||||
println!("\nReading back output.mdd");
|
||||
let infile = File::open("output.mdd")?;
|
||||
MDDSeekableFile::map(infile, |frame| {
|
||||
println!("{:?}", frame);
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
Binary file not shown.
Loading…
Reference in New Issue