Skip to main content

grana_object/
spot.rs

1use crate::IntensityTable;
2
3#[derive(Clone, Copy, Debug, PartialEq)]
4pub struct Spot {
5    center: [f32; 3],
6    radius: f32,
7    quality: f32,
8}
9
10impl Spot {
11    pub fn new(center: [f32; 3], radius: f32, quality: f32) -> Self {
12        assert!(
13            center.iter().all(|value| value.is_finite()),
14            "a spot center must be finite"
15        );
16        assert!(
17            radius.is_finite() && radius > 0.0,
18            "a spot radius must be a positive length"
19        );
20        assert!(
21            quality.is_finite(),
22            "a spot quality must be a finite contrast"
23        );
24        Self {
25            center,
26            radius,
27            quality,
28        }
29    }
30
31    pub fn center(self) -> [f32; 3] {
32        self.center
33    }
34
35    pub fn radius(self) -> f32 {
36        self.radius
37    }
38
39    pub fn quality(self) -> f32 {
40        self.quality
41    }
42}
43
44#[derive(Clone, Debug, PartialEq)]
45pub struct SpotSet {
46    level: usize,
47    spots: Vec<Spot>,
48    intensities: IntensityTable,
49}
50
51impl SpotSet {
52    pub fn new(level: usize, spots: Vec<Spot>, intensities: IntensityTable) -> Self {
53        assert_eq!(
54            intensities.objects(),
55            spots.len(),
56            "every spot is measured in every channel"
57        );
58        Self {
59            level,
60            spots,
61            intensities,
62        }
63    }
64
65    pub fn level(&self) -> usize {
66        self.level
67    }
68
69    pub fn spots(&self) -> &[Spot] {
70        &self.spots
71    }
72
73    pub fn intensities(&self) -> &IntensityTable {
74        &self.intensities
75    }
76
77    pub fn len(&self) -> usize {
78        self.spots.len()
79    }
80
81    pub fn is_empty(&self) -> bool {
82        self.spots.is_empty()
83    }
84
85    pub fn mean_quality(&self) -> Option<f32> {
86        if self.spots.is_empty() {
87            return None;
88        }
89        let total: f32 = self.spots.iter().map(|spot| spot.quality).sum();
90        Some(total / self.spots.len() as f32)
91    }
92}