///|
/// Regular scalar grid used for masks, heatmaps, and calibration residuals.
pub(all) struct ScalarGrid {
width : Int
height : Int
values : Array[Double]
}
///|
pub fn ScalarGrid::new(
width~ : Int,
height~ : Int,
fill~ : Double,
) -> ScalarGrid {
let values : Array[Double] = []
for _ in 0..<(width.max(0) * height.max(0)) {
values.push(fill)
}
{ width: width.max(0), height: height.max(0), values }
}
///|
pub fn ScalarGrid::width(grid : ScalarGrid) -> Int {
grid.width
}
///|
pub fn ScalarGrid::height(grid : ScalarGrid) -> Int {
grid.height
}
///|
pub fn ScalarGrid::length(grid : ScalarGrid) -> Int {
grid.values.length()
}
///|
pub fn ScalarGrid::contains(grid : ScalarGrid, x : Int, y : Int) -> Bool {
x >= 0 && y >= 0 && x < grid.width && y < grid.height
}
///|
pub fn ScalarGrid::get(grid : ScalarGrid, x : Int, y : Int) -> Double? {
if grid.contains(x, y) {
Some(grid.values[y * grid.width + x])
} else {
None
}
}
///|
pub fn ScalarGrid::set(
grid : ScalarGrid,
x : Int,
y : Int,
value : Double,
) -> Bool {
if !grid.contains(x, y) {
return false
}
grid.values[y * grid.width + x] = value
true
}
///|
pub fn ScalarGrid::map(grid : ScalarGrid, f : (Double) -> Double) -> ScalarGrid {
let result = ScalarGrid::new(width=grid.width, height=grid.height, fill=0.0)
for i in 0.. Double {
let mut total = 0.0
for value in grid.values {
total += value
}
total
}
///|
pub fn ScalarGrid::mean(grid : ScalarGrid) -> Double {
if grid.values.length() == 0 {
0.0
} else {
grid.sum() / grid.values.length().to_double()
}
}
///|
pub fn ScalarGrid::min_max(grid : ScalarGrid) -> (Double, Double)? {
if grid.values.length() == 0 {
return None
}
let mut minimum = grid.values[0]
let mut maximum = grid.values[0]
for value in grid.values {
minimum = minimum.min(value)
maximum = maximum.max(value)
}
Some((minimum, maximum))
}
///|
pub fn ScalarGrid::bilinear(
grid : ScalarGrid,
x : Double,
y : Double,
) -> Double? {
let x0 = x.floor().to_int()
let y0 = y.floor().to_int()
if !grid.contains(x0, y0) || !grid.contains(x0 + 1, y0 + 1) {
return None
}
let tx = x - x0.to_double()
let ty = y - y0.to_double()
let a = grid.values[y0 * grid.width + x0]
let b = grid.values[y0 * grid.width + x0 + 1]
let c = grid.values[(y0 + 1) * grid.width + x0]
let d = grid.values[(y0 + 1) * grid.width + x0 + 1]
Some(
a * (1.0 - tx) * (1.0 - ty) +
b * tx * (1.0 - ty) +
c * (1.0 - tx) * ty +
d * tx * ty,
)
}
///|
pub fn downsample_grid(grid : ScalarGrid, factor : Int) -> ScalarGrid {
if factor <= 1 {
return grid
}
let width = (grid.width / factor).max(1)
let height = (grid.height / factor).max(1)
let result = ScalarGrid::new(width~, height~, fill=0.0)
for y in 0..