Skip to content

Commit

Permalink
Add close-enough compactor
Browse files Browse the repository at this point in the history
  • Loading branch information
JayKickliter committed Nov 24, 2023
1 parent c3fcd17 commit 61f67ab
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 59 deletions.
27 changes: 8 additions & 19 deletions hexit/src/combine.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
elevation::{Elevation, ReducedElevation, ReductionCompactor},
elevation::{CloseEnoughCompactor, Elevation, ReducedElevation},
options::Combine,
progress,
};
Expand All @@ -13,24 +13,23 @@ use std::{ffi::OsStr, fs::File, io::BufReader, path::Path};
impl Combine {
pub fn run(&self) -> Result<()> {
assert!(!self.input.is_empty());
let mut hextree: HexTreeMap<Elevation, ReductionCompactor> =
HexTreeMap::with_compactor(ReductionCompactor {
source_resolution: self.source_resolution as u8,
target_resolution: self.target_resolution as u8,
let mut hextree: HexTreeMap<Elevation, CloseEnoughCompactor> =
HexTreeMap::with_compactor(CloseEnoughCompactor {
tolerance: self.tolerance,
});
let progress_group = MultiProgress::new();
for tess_file_path in &self.input {
Self::read_tessellation(tess_file_path, &progress_group, &mut hextree)?;
}
let hextree = self.reduce_hextree(&hextree, &progress_group);
let hextree = Self::reduce_hextree(&hextree, &progress_group);
self.write_disktree(&hextree, &progress_group)?;
Ok(())
}

fn read_tessellation(
tess_file_path: &Path,
progress_group: &MultiProgress,
hextree: &mut HexTreeMap<Elevation, ReductionCompactor>,
hextree: &mut HexTreeMap<Elevation, CloseEnoughCompactor>,
) -> Result<()> {
let tess_file = File::open(tess_file_path)?;
let tess_buf_rdr = BufReader::new(tess_file);
Expand Down Expand Up @@ -59,22 +58,12 @@ impl Combine {
}

fn reduce_hextree(
&self,
hextree: &HexTreeMap<Elevation, ReductionCompactor>,
hextree: &HexTreeMap<Elevation, CloseEnoughCompactor>,
_progress_group: &MultiProgress,
) -> HexTreeMap<ReducedElevation> {
let mut reduced_hextree = HexTreeMap::new();
let max_child_cnt =
7_usize.pow(self.source_resolution as u32 - self.target_resolution as u32);
for (cell, elev) in hextree.iter() {
match elev {
elevation if cell.res() == self.target_resolution as u8 => {
assert_eq!(elevation.n, max_child_cnt);
let reduction = elevation.reduce();
reduced_hextree.insert(cell, reduction);
}
_ => {}
};
reduced_hextree.insert(cell, elev.reduce());
}
reduced_hextree
}
Expand Down
37 changes: 37 additions & 0 deletions hexit/src/elevation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,40 @@ impl Compactor<Elevation> for ReductionCompactor {
}
}
}

pub struct CloseEnoughCompactor {
// Maximum differance between min and max child elevations
// allowable for a cell to be coalesced.
pub tolerance: i16,
}

impl Compactor<Elevation> for CloseEnoughCompactor {
fn compact(&mut self, _cell: Cell, children: [Option<&Elevation>; 7]) -> Option<Elevation> {
if let [Some(v0), Some(v1), Some(v2), Some(v3), Some(v4), Some(v5), Some(v6)] = children {
let mut n_min = i16::MAX;
let mut n_sum = 0;
let mut n_max = i16::MIN;
let mut n_n = 0;
for Elevation { min, sum, max, n } in [v0, v1, v2, v3, v4, v5, v6] {
n_min = i16::min(n_min, *min);
n_sum += sum;
n_max = i16::max(n_max, *max);
n_n += n;
}
let error = n_max - n_min;
assert!(error >= 0, "error can't be negative");
if error <= self.tolerance {
Some(Elevation {
min: n_min,
sum: n_sum,
max: n_max,
n: n_n,
})
} else {
None
}
} else {
None
}
}
}
39 changes: 9 additions & 30 deletions hexit/src/lookup.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::options::Lookup;
use crate::{elevation::ReducedElevation, options::Lookup};
use anyhow::Result;
use byteorder::{LittleEndian as LE, ReadBytesExt};
use hextree::{disktree::DiskTree, Cell};
use std::{fs::File, io::Write};
use std::fs::File;

impl Lookup {
pub fn run(&self) -> Result<()> {
Expand All @@ -13,11 +12,7 @@ impl Lookup {
let cell = Cell::try_from(raw_cell)?;
let mut disktree = DiskTree::open(&self.disktree)?;

if self.iter {
Self::by_iter(cell, &mut disktree)
} else {
Self::by_get(cell, &mut disktree)
}
Self::by_get(cell, &mut disktree)
}

fn by_get(cell: Cell, disktree: &mut DiskTree<File>) -> Result<()> {
Expand All @@ -26,29 +21,13 @@ impl Lookup {
None => (),
Some((cell, rdr)) => {
let t_seek = t0.elapsed();
let elev = rdr.read_i16::<LE>()?;
let ReducedElevation { min, avg, max } = ReducedElevation::from_reader(rdr)?;
let t_tot = t0.elapsed();
println!("{cell}: {elev}");
println!("{t_seek:?} {t_tot:?}");
}
}
Ok(())
}

fn by_iter(_target_cell: Cell, disktree: &mut DiskTree<File>) -> Result<()> {
fn read_elev(res: hextree::Result<(Cell, &mut File)>) -> Result<Option<(Cell, i16)>> {
let (cell, rdr) = res?;
let mask = Cell::try_from(0x8126bffffffffff)?;
if cell.is_related_to(&mask) {
Ok(Some((cell, rdr.read_i16::<LE>()?)))
} else {
Ok(None)
}
}
let mut stderr = std::io::stderr().lock();
for res in disktree.iter(read_elev)? {
if let Some((cell, elev)) = res? {
writeln!(&mut stderr, "{cell}: {elev}")?;
println!("cell: {cell} (res {})", cell.res());
println!("min: {min}");
println!("avg: {avg}");
println!("max: {max}");
println!("seek: {t_seek:?}");
}
}
Ok(())
Expand Down
11 changes: 1 addition & 10 deletions hexit/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,8 @@ pub struct Tesselate {
/// Combine previously tesselated files into a single
#[derive(Debug, Clone, Args)]
pub struct Combine {
/// Path GeoJSON mask.
///
/// Any samples which do not intersect the mask are ignored.
#[arg(short, long)]
pub mask: Option<PathBuf>,

#[arg(short, long)]
pub source_resolution: Resolution,

#[arg(short, long)]
pub target_resolution: Resolution,
pub tolerance: i16,

#[arg(short, long)]
pub out: PathBuf,
Expand Down

0 comments on commit 61f67ab

Please sign in to comment.