Files
edalyze/src/bin/regionfilter.rs
2023-06-22 00:26:43 +02:00

151 lines
4.5 KiB
Rust

use std::io::Write;
use anyhow::anyhow;
use simd_json::Node;
use edalyze::tapetool::{TapeCursor, TapeObject, Value};
use edalyze::bindata::{System, Point, Box};
fn star_typ(sub_type: &str) -> u8 {
use edalyze::bindata::{IS_FUEL, IS_WDRF, IS_NEUT};
if sub_type.starts_with("Wh") {
return IS_WDRF;
} else if sub_type.starts_with("N") {
return IS_NEUT;
} else {
let c2 = &sub_type.as_bytes()[..2];
if b"OBAFGKM".contains(&c2[0]) && c2[1] == b' ' {
return IS_FUEL;
} else {
return 0;
}
}
}
fn parse_coords(c: TapeObject) -> Result<Point, &'static str> {
let mut pt = Point::default();
for (k,v) in c {
let v = v.as_f64().ok_or("Coord value must be f64")? as f32;
let v = (v * 32.) as i32;
match k {
"x" => pt.0 = v,
"y" => pt.1 = v,
"z" => pt.2 = v,
_ => return Err("Unexpected coord field"),
}
}
Ok(pt)
}
fn parse_body(v: Value) -> Option<(f32, u8)> {
let mut distance = None;
let mut star_flags = 255;
let mut is_star = false;
for (k,v) in v.as_object()? {
match k {
"type" => {
is_star = v.as_str()? == "Star";
if !is_star {
return None;
}
}
"subType" => star_flags = star_typ(v.as_str()?),
"distanceToArrival" => distance = Some(v.as_f64()? as f32),
_ => continue,
}
if is_star && star_flags != 255 && distance.is_some() {
return Some((distance.unwrap(), star_flags));
}
}
return None
}
fn parse_system<'a>(tape: &'a [Node<'a>]) -> Result<System, &'static str> {
let mut system = System::default();
let mut csr = TapeCursor::new(tape);
let mut obj = csr.next()
.ok_or("Expected a JSON object")?
.as_object()
.ok_or("Expected a JSON object")?;
while let Some((k,v)) = obj.next() {
match k {
"name" => system.name = v.as_str().map(str::to_owned).ok_or("name must be str")?,
"coords" => system.coords = parse_coords(v.as_object().ok_or("coords must be object")?)?,
"bodies" => {
system.star_flags = v.as_array().ok_or("bodies should be array")?
.filter_map(parse_body)
.map(|x| x.1)
.fold(0, |x,y| x|y)
}
_ => (),
}
}
Ok(system)
}
fn id<T> (x:T) -> T { x }
fn processor_e(line: &mut [u8]) -> anyhow::Result<System> {
let tape = simd_json::to_tape(line)?;
parse_system(tape.as_slice())
.map_err(|err| anyhow!(err))
}
fn processor(line: &mut [u8]) -> Option<System> {
match processor_e(line) {
Ok(v) => Some(v),
Err(e) => {
let json = String::from_utf8_lossy(line).to_owned();
eprintln!("Error: {e}\nIn system: {}", json);
None
}
}
}
//static FILENAME: &str = "/space/data/ed-utils/spansh/galaxy_subset.json.zst";
static FILENAME: &str = "/space/data/ed-utils/spansh/galaxy.json.zst";
fn main() -> anyhow::Result<()> {
let f = edalyze::ioutil::Processor::open_file(FILENAME, processor)?;
// Small region
#[cfg(ignore)]
let region = Box::from_corners(
Point(11900*32, -3800*32, -11510*32),
Point(17400*32, 3800*32, -6500*32),
);
// Everything southeast of Haffner 18 LSS 27
let region = Box::from_corners(
Point(11900*32, -3800*32, -18510*32),
Point(64400*32, 3800*32, -6500*32),
);
let mut reg_name = std::io::BufWriter::new(std::fs::File::create("region.nam")?);
let mut reg_data = std::io::BufWriter::new(std::fs::File::create("region.dat")?);
let mut name_pos = 0;
for mut sys in f.filter_map(id).filter(|sys| region.contains(sys.coords)) {
sys.name_off = name_pos as usize;
let hdr = [sys.name.len().min(255) as u8];
if hdr[0] == 255 {
eprintln!("WARNING: Long system name {}", sys.name);
}
reg_name.write(&hdr[..])?;
reg_name.write(&sys.name.as_bytes()[..hdr[0] as usize])?;
name_pos += hdr[0] as u32 + 1;
reg_data.write(&sys.coords.0 .to_be_bytes()[..])?;
reg_data.write(&sys.coords.1 .to_be_bytes()[..])?;
reg_data.write(&sys.coords.2 .to_be_bytes()[..])?;
let rest = (sys.star_flags as u32) + (name_pos << 4);
reg_data.write(&rest.to_be_bytes()[..])?;
}
Ok(())
}