#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct PaintMask {
pub weights: Vec<f32>,
}
impl PaintMask {
pub fn new(vertex_count: usize) -> Self {
Self {
weights: vec![0.0; vertex_count],
}
}
pub fn vertex_count(&self) -> usize {
self.weights.len()
}
pub fn set(&mut self, vertex: usize, weight: f32) {
if let Some(w) = self.weights.get_mut(vertex) {
*w = weight.clamp(0.0, 1.0);
}
}
pub fn get(&self, vertex: usize) -> f32 {
self.weights.get(vertex).copied().unwrap_or(0.0)
}
pub fn invert(&mut self) {
for w in &mut self.weights {
*w = 1.0 - *w;
}
}
pub fn clamp_range(&mut self, lo: f32, hi: f32) {
for w in &mut self.weights {
*w = w.clamp(lo, hi);
}
}
}
pub fn average_weight(mask: &PaintMask) -> f32 {
if mask.weights.is_empty() {
return 0.0;
}
let sum: f32 = mask.weights.iter().sum();
sum / mask.weights.len() as f32
}
pub fn count_above(mask: &PaintMask, threshold: f32) -> usize {
mask.weights.iter().filter(|&&w| w > threshold).count()
}
#[allow(clippy::needless_range_loop)]
pub fn from_bytes(mask: &mut PaintMask, data: &[u8]) {
let len = mask.weights.len().min(data.len());
for i in 0..len {
mask.weights[i] = data[i] as f32 / 255.0;
}
}
pub fn to_bytes(mask: &PaintMask) -> Vec<u8> {
mask.weights
.iter()
.map(|&w| (w.clamp(0.0, 1.0) * 255.0) as u8)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
fn mask4() -> PaintMask {
PaintMask::new(4)
}
#[test]
fn test_new_all_zero() {
let m = mask4();
assert!(m.weights.iter().all(|&w| w == 0.0));
}
#[test]
fn test_set_and_get() {
let mut m = mask4();
m.set(2, 0.75);
assert!((m.get(2) - 0.75).abs() < 1e-6);
}
#[test]
fn test_set_clamps() {
let mut m = mask4();
m.set(0, 1.5);
assert!((m.get(0) - 1.0).abs() < 1e-6);
m.set(0, -0.5);
assert!((m.get(0) - 0.0).abs() < 1e-6);
}
#[test]
fn test_invert() {
let mut m = mask4();
m.set(0, 0.25);
m.invert();
assert!((m.get(0) - 0.75).abs() < 1e-6);
}
#[test]
fn test_average_weight() {
let mut m = PaintMask::new(2);
m.set(0, 0.4);
m.set(1, 0.6);
assert!((average_weight(&m) - 0.5).abs() < 1e-5);
}
#[test]
fn test_count_above() {
let mut m = mask4();
m.set(0, 0.5);
m.set(1, 0.8);
assert_eq!(count_above(&m, 0.4), 2);
}
#[test]
fn test_from_to_bytes_round_trip() {
let mut m = PaintMask::new(3);
let data = vec![0u8, 128, 255];
from_bytes(&mut m, &data);
let out = to_bytes(&m);
assert_eq!(out[0], 0);
assert_eq!(out[2], 255);
}
#[test]
fn test_get_out_of_bounds() {
let m = mask4();
assert_eq!(m.get(999), 0.0);
}
}