pico_detect/localize/
perturbate.rs1use std::{
2 convert::{TryFrom, TryInto},
3 ops::Range,
4};
5
6use rand::{
7 distr::{uniform::Error, Uniform},
8 Rng, RngCore,
9};
10
11use crate::geometry::Target;
12
13#[derive(Clone, Copy, Debug, PartialEq)]
14pub struct Perturbator {
16 pub scale: Uniform<f32>,
17 pub translate: Uniform<f32>,
18}
19
20impl Perturbator {
21 #[inline]
23 pub fn from_ranges(scale: Range<f32>, translate: Range<f32>) -> Result<Self, Error> {
24 Ok(Self {
25 scale: scale.try_into()?,
26 translate: translate.try_into()?,
27 })
28 }
29}
30
31impl Default for Perturbator {
32 #[inline]
35 fn default() -> Self {
36 Self {
37 scale: Uniform::try_from(0.925..0.94).unwrap(),
38 translate: Uniform::try_from(-0.075..0.075).unwrap(),
39 }
40 }
41}
42
43impl Perturbator {
44 #[inline]
47 pub fn run<R, F>(&self, rng: &mut R, count: usize, init: Target, f: F)
48 where
49 R: RngCore,
50 F: FnMut(Target),
51 {
52 perturbate(rng, self.scale, self.translate, count, init, f)
53 }
54}
55
56#[inline]
67pub fn perturbate<R, F>(
68 rng: &mut R,
69 scale: Uniform<f32>,
70 translate: Uniform<f32>,
71 count: usize,
72 init: Target,
73 mut f: F,
74) where
75 R: RngCore,
76 F: FnMut(Target),
77{
78 let size = init.size();
79
80 for _ in 0..count {
81 let s = size * rng.sample(scale);
82
83 let x = s.mul_add(rng.sample(translate), init.x());
84 let y = s.mul_add(rng.sample(translate), init.y());
85
86 f(Target::new(x, y, s));
87 }
88}