///|
pub(all) enum SampleQuality {
Valid
Missing
NonFinite
BelowPhysicalLimit
AbovePhysicalLimit
} derive(Debug, Eq, ToJson)
///|
pub(all) struct QualitySummary {
total : Int
valid : Int
missing : Int
non_finite : Int
below_limit : Int
above_limit : Int
min_valid : Double
max_valid : Double
} derive(Debug, Eq, ToJson)
///|
pub(all) struct TemperatureLimits {
minimum : Double
maximum : Double
} derive(Debug, Eq, ToJson)
///|
pub fn TemperatureLimits::new(
minimum~ : Double,
maximum~ : Double,
) -> TemperatureLimits {
{ minimum, maximum }
}
///|
pub fn TemperatureLimits::contains(
limits : TemperatureLimits,
value : Double,
) -> Bool {
value >= limits.minimum && value <= limits.maximum
}
///|
pub fn classify_temperature(
value : Double,
limits : TemperatureLimits,
) -> SampleQuality {
if value != value {
NonFinite
} else if value < limits.minimum {
BelowPhysicalLimit
} else if value > limits.maximum {
AbovePhysicalLimit
} else {
Valid
}
}
///|
pub fn ThermalMatrix::quality(
matrix : ThermalMatrix,
limits : TemperatureLimits,
) -> QualitySummary {
let mut valid = 0
let mut missing = 0
let mut non_finite = 0
let mut below_limit = 0
let mut above_limit = 0
let mut min_valid = 0.0
let mut max_valid = 0.0
for value in matrix.values {
match classify_temperature(value, limits) {
Valid => {
if valid == 0 {
min_valid = value
max_valid = value
} else {
min_valid = Double::min(min_valid, value)
max_valid = Double::max(max_valid, value)
}
valid += 1
}
Missing => missing += 1
NonFinite => non_finite += 1
BelowPhysicalLimit => below_limit += 1
AbovePhysicalLimit => above_limit += 1
}
}
{
total: matrix.values.length(),
valid,
missing,
non_finite,
below_limit,
above_limit,
min_valid,
max_valid,
}
}
///|
pub fn ThermalMatrix::valid_mask(
matrix : ThermalMatrix,
limits : TemperatureLimits,
) -> ThermalMask {
let cells = matrix.values.map(fn(value) {
classify_temperature(value, limits) is Valid
})
{ width: matrix.width, height: matrix.height, cells }
}
///|
pub fn ThermalMask::bounding_box(mask : ThermalMask) -> ThermalRegion? {
let mut min_x = mask.width
let mut min_y = mask.height
let mut max_x = -1
let mut max_y = -1
let pixels : Array[ThermalPoint] = []
for y in 0.. ThermalMask {
{
width: mask.width,
height: mask.height,
cells: mask.cells.map(fn(x) { !x }),
}
}
///|
pub fn ThermalMask::intersection(
a : ThermalMask,
b : ThermalMask,
) -> ThermalMask raise ThermalError {
if a.width != b.width || a.height != b.height {
raise InvalidDimensions(
width=a.width,
height=a.height,
values=b.cells.length(),
)
}
let cells : Array[Bool] = []
for i, value in a.cells {
cells.push(value && b.cells[i])
}
{ width: a.width, height: a.height, cells }
}
///|
pub fn ThermalMask::union(
a : ThermalMask,
b : ThermalMask,
) -> ThermalMask raise ThermalError {
if a.width != b.width || a.height != b.height {
raise InvalidDimensions(
width=a.width,
height=a.height,
values=b.cells.length(),
)
}
let cells : Array[Bool] = []
for i, value in a.cells {
cells.push(value || b.cells[i])
}
{ width: a.width, height: a.height, cells }
}