use itertools::Itertools;
use once_cell::sync::OnceCell;
use rand::distributions::Uniform;
use rand::rngs::ThreadRng;
use rand::Rng;
use similari::test_stuff::vec2;
use similari::track::{AttributeUpdate, Feature};
use thiserror::Error;
const FEATURE0: u64 = 0;
#[derive(Debug, Error)]
enum AppErrors {
#[error("Cam id passed ({0}) != id set ({1})")]
WrongCamID(u64, u64),
#[error("Time passed {0} < time set {1}")]
WrongTime(u64, u64),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
enum Gender {
Female,
Male,
#[default]
Unknown,
}
#[derive(Debug, Clone, Default)]
struct CamTrackingAttributes {
start_time: u64, end_time: u64, camera_id: OnceCell<u64>, age: Vec<u8>, gender: Vec<Gender>, screen_pos: Vec<(u16, u16)>, }
impl CamTrackingAttributes {
pub fn get_age(&self) -> Option<u8> {
if self.age.len() == 0 {
return None;
}
u8::try_from(self.age.iter().map(|e| *e as u32).sum::<u32>() / self.age.len() as u32).ok()
}
pub fn get_gender(&self) -> Gender {
if self.gender.is_empty() {
return Gender::Unknown;
}
let groups = self.gender.clone();
let mut groups = groups.into_iter().counts().into_iter().collect::<Vec<_>>();
groups.sort_by(|(_, l), (_, r)| r.partial_cmp(l).unwrap());
groups[0].0.clone()
}
}
#[test]
fn test_attributes_age_gender() {
use Gender::*;
let attrs = CamTrackingAttributes {
screen_pos: vec![(0, 0), (10, 15), (20, 25), (30, 35)],
start_time: 0,
end_time: 0,
camera_id: Default::default(),
age: vec![17, 24, 36],
gender: vec![Male, Female, Female, Unknown],
};
assert_eq!(attrs.get_age(), Some(25));
assert_eq!(attrs.get_gender(), Female);
}
#[derive(Clone)]
struct CamTrackingAttributesUpdate {
time: u64,
gender: Option<Gender>,
age: Option<u8>,
camera_id: u64,
screen_pos: (u16, u16),
}
impl AttributeUpdate<CamTrackingAttributes> for CamTrackingAttributesUpdate {
fn apply(&self, attrs: &mut CamTrackingAttributes) -> anyhow::Result<()> {
if attrs.start_time == 0 {
attrs.start_time = self.time;
}
if attrs.end_time > self.time {
return Err(AppErrors::WrongTime(self.time, attrs.end_time).into());
}
attrs.end_time = self.time;
if let Some(gender) = &self.gender {
attrs.gender.push(gender.clone());
}
if let Some(age) = &self.age {
attrs.age.push(*age);
}
if let Err(_r) = attrs.camera_id.set(self.camera_id) {
if self.camera_id != *attrs.camera_id.get().unwrap() {
return Err(
AppErrors::WrongCamID(self.camera_id, *attrs.camera_id.get().unwrap()).into(),
);
}
}
attrs.screen_pos.push(self.screen_pos);
Ok(())
}
}
#[test]
fn cam_tracking_attributes_update_test() {
use Gender::*;
let mut attrs = CamTrackingAttributes {
start_time: 0,
end_time: 0,
camera_id: Default::default(),
age: Vec::default(),
gender: Vec::default(),
screen_pos: Vec::default(),
};
let update = CamTrackingAttributesUpdate {
time: 10,
gender: Some(Female),
age: Some(30),
camera_id: 10,
screen_pos: (10, 10),
};
assert!(update.apply(&mut attrs).is_ok());
let update = CamTrackingAttributesUpdate {
time: 20,
gender: Some(Female),
age: Some(10),
camera_id: 20,
screen_pos: (10, 15),
};
assert!(update.apply(&mut attrs).is_err());
let update = CamTrackingAttributesUpdate {
time: 5,
gender: Some(Female),
age: Some(10),
camera_id: 20,
screen_pos: (20, 25),
};
assert!(update.apply(&mut attrs).is_err());
}
struct FeatGen2 {
x: f32,
y: f32,
gen: ThreadRng,
dist: Uniform<f32>,
}
impl FeatGen2 {
pub fn new(x: f32, y: f32) -> Self {
Self {
x,
y,
gen: rand::thread_rng(),
dist: Uniform::new(-0.01, 0.01),
}
}
}
impl Iterator for FeatGen2 {
type Item = Feature;
fn next(&mut self) -> Option<Self::Item> {
self.x += self.gen.sample(&self.dist);
self.y += self.gen.sample(&self.dist);
Some(vec2(self.x, self.y))
}
}
fn main() {}