use std::{
collections::HashSet,
fs::File,
io::{
BufReader,
BufWriter,
Read,
Write
}
};
use crate::base::{
ReadBin,
WriteBin
};
const DEF_U_RADIUS: isize = 0;
const DEF_V_RADIUS: isize = 2;
const DEF_W_RADIUS: isize = 2;
pub struct Neighbourhood (pub HashSet<(isize, isize, isize)>);
impl<W: Write> WriteBin<&Neighbourhood> for W {
fn write_bin(&mut self, nbhood: &Neighbourhood) -> Result<(), String> {
self.write_bin(nbhood.0.len())?;
for &(du, dv, dw) in & nbhood.0 {
self.write_bin(du as i16)?;
self.write_bin(dv as i16)?;
self.write_bin(dw as i16)?;
}
Ok(())
}
}
impl<R: Read> ReadBin<Neighbourhood> for R {
fn read_bin(&mut self) -> Result<Neighbourhood, String> {
let mut nbhood = HashSet::<(isize, isize, isize)>::new();
let n: usize = self.read_bin()?;
for _ in 0..n {
let du: i16 = self.read_bin()?;
let dv: i16 = self.read_bin()?;
let dw: i16 = self.read_bin()?;
nbhood.insert((du as isize, dv as isize, dw as isize));
}
Ok(Neighbourhood(nbhood))
}
}
impl Neighbourhood {
pub fn new_default() -> Self {
let mut neighbourhood = HashSet::<(isize, isize, isize)>::new();
for du in -DEF_U_RADIUS..=DEF_U_RADIUS {
for dv in -DEF_V_RADIUS..=DEF_V_RADIUS {
for dw in -DEF_W_RADIUS..=DEF_W_RADIUS {
neighbourhood.insert((du, dv, dw));
}
}
}
Self(neighbourhood)
}
pub fn reset(&mut self) {
*self = Self::new_default();
}
pub fn is_symmetric(&self) -> bool {
for &(du, dv, dw) in & self.0 {
if ! self.0.contains(&(-du, -dv, -dw)) {
return false;
}
}
true
}
pub fn perpetuator(&self) -> f64 {
let neigh_len = self.0.len();
if neigh_len > 0 {
let neigh_len = neigh_len as f64;
2.0 / neigh_len * ((1.0 + 2.0 * neigh_len).sqrt() - 1.0) } else {
2.0
}
}
pub fn load(filepath: &str) -> Result<Self, String> {
let mut reader = BufReader::new(File::open(filepath).map_err(|e| e.to_string())?);
reader.read_bin()
}
pub fn save(&self, filepath: &str) -> Result<(), String> {
let mut writer = BufWriter::new(File::create(filepath).map_err(|e| e.to_string())?);
writer.write_bin(self)?;
writer.flush().map_err(|e| e.to_string())?;
Ok(())
}
}