use crate::Scalar;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DensityMapError {
WrongDataLength(usize, usize),
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct DensityMap {
width: usize,
height: usize,
scale: usize,
data: Vec<Scalar>,
steepness: Vec<Scalar>,
}
impl DensityMap {
pub fn new(
width: usize,
height: usize,
scale: usize,
data: Vec<u8>,
) -> Result<Self, DensityMapError> {
if data.len() == width * height {
let data = data
.into_iter()
.map(|v| v as Scalar / 255.0)
.collect::<Vec<_>>();
let steepness = (0..data.len())
.map(|i| {
let col = (i % width) as isize;
let row = (i / width) as isize;
let mut result = 0.0;
for x in (col - 1)..(col + 1) {
for y in (row - 1)..(row + 1) {
let a = Self::raw_value(x, y, width, height, &data);
let b = Self::raw_value(x + 1, y, width, height, &data);
let c = Self::raw_value(x + 1, y + 1, width, height, &data);
let d = Self::raw_value(x, y + 1, width, height, &data);
let ab = (a - b).abs();
let cd = (c - d).abs();
let ac = (a - c).abs();
let bd = (b - d).abs();
let ad = (a - d).abs();
let bc = (b - c).abs();
result += (ab + cd + ac + bd + ad + bc) / 12.0;
}
}
result
})
.collect::<Vec<_>>();
Ok(Self {
width,
height,
scale,
data,
steepness,
})
} else {
Err(DensityMapError::WrongDataLength(data.len(), width * height))
}
}
pub fn scale(&self) -> usize {
self.scale
}
pub fn width(&self) -> usize {
self.width * self.scale.max(1)
}
pub fn height(&self) -> usize {
self.height * self.scale.max(1)
}
pub fn unscaled_width(&self) -> usize {
self.width
}
pub fn unscaled_height(&self) -> usize {
self.height
}
pub fn values(&self) -> &[Scalar] {
&self.data
}
pub fn steepness(&self) -> &[Scalar] {
&self.steepness
}
pub fn value_at_point(&self, point: (isize, isize)) -> Scalar {
let scale = self.scale.max(1) as isize;
let col = point.0 / scale;
let row = point.1 / scale;
if col >= 0 && col < self.width as _ && row >= 0 && row < self.height as _ {
self.data
.get(row as usize * self.width + col as usize)
.copied()
.unwrap_or(0.0)
} else {
0.0
}
}
pub fn steepness_at_point(&self, point: (isize, isize)) -> Scalar {
let scale = self.scale.max(1) as isize;
let col = point.0 / scale;
let row = point.1 / scale;
if col >= 0 && col < self.width as _ && row >= 0 && row < self.height as _ {
self.steepness
.get(row as usize * self.width + col as usize)
.copied()
.unwrap_or(0.0)
} else {
0.0
}
}
pub fn value_steepness_iter<'a>(
&'a self,
) -> impl Iterator<Item = (usize, usize, Scalar, Scalar)> + 'a {
self.data
.iter()
.zip(self.steepness.iter())
.enumerate()
.map(move |(i, (v, s))| (i % self.width, i / self.width, *v, *s))
}
pub fn crop(&self, col: usize, row: usize, width: usize, height: usize) -> Self {
let fx = col.min(self.width);
let fy = row.min(self.height);
let tx = (col + width).min(self.width);
let ty = (row + height).min(self.height);
let w = tx - fx;
let h = ty - fy;
let data = (0..(w * h))
.map(|i| {
let x = fx + i % w;
let y = fy + i / w;
self.data[y * self.width + x]
})
.collect::<Vec<_>>();
let steepness = (0..(w * h))
.map(|i| {
let x = fx + i % w;
let y = fy + i / w;
self.steepness[y * self.width + x]
})
.collect::<Vec<_>>();
Self {
width: w,
height: h,
scale: self.scale,
data,
steepness,
}
}
pub fn change(
&mut self,
col: usize,
row: usize,
width: usize,
height: usize,
data: Vec<u8>,
) -> Result<(), DensityMapError> {
if col == 0 && row == 0 && width == self.width && height == self.height {
*self = Self::new(width, height, self.scale, data)?;
Ok(())
} else if data.len() == width * height {
for (i, v) in data.into_iter().enumerate() {
let x = col + i % width;
let y = row + i / width;
self.data[y * self.width + x] = v as Scalar / 255.0;
}
let fx = col.checked_sub(1).unwrap_or(col);
let fy = row.checked_sub(1).unwrap_or(row);
let tx = (col + width + 1).min(self.width);
let ty = (row + height + 1).min(self.height);
for row in fy..ty {
for col in fx..tx {
let mut result = 0.0;
{
let col = col as isize;
let row = row as isize;
for x in (col - 1)..(col + 1) {
for y in (row - 1)..(row + 1) {
let a = Self::raw_value(x, y, self.width, self.height, &self.data);
let b =
Self::raw_value(x + 1, y, self.width, self.height, &self.data);
let c = Self::raw_value(
x + 1,
y + 1,
self.width,
self.height,
&self.data,
);
let d =
Self::raw_value(x, y + 1, self.width, self.height, &self.data);
let ab = (a - b).abs();
let cd = (c - d).abs();
let ac = (a - c).abs();
let bd = (b - d).abs();
let ad = (a - d).abs();
let bc = (b - c).abs();
result += (ab + cd + ac + bd + ad + bc) / 12.0;
}
}
}
self.steepness[row * self.width + col] = result;
}
}
Ok(())
} else {
Err(DensityMapError::WrongDataLength(data.len(), width * height))
}
}
fn raw_value(x: isize, y: isize, w: usize, h: usize, data: &[Scalar]) -> Scalar {
if x >= 0 && x < w as _ && y >= 0 && y < h as _ {
data[y as usize * w + x as usize]
} else {
0.0
}
}
}