///|
pub fn Grid::extent(self : Grid) -> GridExtent {
let last_lat = self.origin_lat +
self.lat_step * Double::from_int(self.rows - 1)
let last_lon = self.origin_lon +
self.lon_step * Double::from_int(self.cols - 1)
{
min_lat: Double::min(self.origin_lat, last_lat),
max_lat: Double::max(self.origin_lat, last_lat),
min_lon: Double::min(self.origin_lon, last_lon),
max_lon: Double::max(self.origin_lon, last_lon),
}
}
///|
pub fn Grid::contains(self : Grid, point : GeoPoint) -> Bool {
let e = self.extent()
point.lat >= e.min_lat &&
point.lat <= e.max_lat &&
point.lon >= e.min_lon &&
point.lon <= e.max_lon
}
///|
pub fn Grid::point_at(self : Grid, row : Int, col : Int) -> GeoPoint? {
match self.index(row, col) {
Some(_) =>
Some({
lat: self.origin_lat + self.lat_step * Double::from_int(row),
lon: self.origin_lon + self.lon_step * Double::from_int(col),
elevation_m: 0.0,
})
None => None
}
}
///|
pub fn Grid::cell(self : Grid, row : Int, col : Int) -> GridCell? {
match (self.point_at(row, col), self.value_at(row, col)) {
(Some(point), Some(value)) => Some({ row, col, point, value })
_ => None
}
}
///|
pub fn Grid::cells(self : Grid) -> Array[GridCell] {
let output : Array[GridCell] = []
for row in 0.. output.push(cell)
None => ()
}
}
}
output
}
///|
pub fn Grid::map(self : Grid, transform : (Double) -> Double) -> Grid {
let values : Array[Double] = []
for value in self.values {
values.push(transform(value))
}
{ ..self, values, }
}
///|
pub fn Grid::map_cells(self : Grid, transform : (GridCell) -> Double) -> Grid {
let values : Array[Double] = []
for row in 0.. values.push(transform(cell))
None => values.push(0.0 / 0.0)
}
}
}
{ ..self, values, }
}
///|
pub fn Grid::replace_missing(self : Grid, replacement : Double) -> Grid {
self.map(fn(value) { if is_finite(value) { value } else { replacement } })
}
///|
pub fn Grid::row(self : Grid, row : Int) -> Array[Double] {
let output : Array[Double] = []
if row >= 0 && row < self.rows {
for col in 0.. output.push(value)
None => ()
}
}
}
output
}
///|
pub fn Grid::column(self : Grid, col : Int) -> Array[Double] {
let output : Array[Double] = []
if col >= 0 && col < self.cols {
for row in 0.. output.push(value)
None => ()
}
}
}
output
}
///|
pub fn Grid::summary(self : Grid) -> Summary {
summary(self.values)
}
///|
pub fn Grid::nearest_cell(self : Grid, point : GeoPoint) -> GridCell? {
let (r, c) = grid_position(self, point)
self.cell(r.round().to_int(), c.round().to_int())
}
///|
pub fn Grid::window(
self : Grid,
row : Int,
col : Int,
radius : Int,
) -> Array[Double] {
let output : Array[Double] = []
for r in (row - radius)..<=(row + radius) {
for c in (col - radius)..<=(col + radius) {
match self.value_at(r, c) {
Some(value) => output.push(value)
None => ()
}
}
}
output
}
///|
pub fn Grid::focal_mean(self : Grid, radius : Int) -> Grid {
self.map_cells(fn(cell) {
summary(self.window(cell.row, cell.col, radius)).mean
})
}
///|
pub fn Grid::focal_min(self : Grid, radius : Int) -> Grid {
self.map_cells(fn(cell) {
summary(self.window(cell.row, cell.col, radius)).minimum
})
}
///|
pub fn Grid::focal_max(self : Grid, radius : Int) -> Grid {
self.map_cells(fn(cell) {
summary(self.window(cell.row, cell.col, radius)).maximum
})
}
///|
pub fn Grid::transpose(self : Grid) -> Grid {
let values : Array[Double] = []
for col in 0.. values.push(value)
None => values.push(0.0 / 0.0)
}
}
}
{
origin_lat: self.origin_lon,
origin_lon: self.origin_lat,
lat_step: self.lon_step,
lon_step: self.lat_step,
rows: self.cols,
cols: self.rows,
values,
}
}
///|
pub fn Grid::scale(self : Grid, factor : Double) -> Grid {
self.map(fn(value) { value * factor })
}
///|
pub fn Grid::offset(self : Grid, amount : Double) -> Grid {
self.map(fn(value) { value + amount })
}
///|
pub fn Grid::difference(self : Grid, other : Grid) -> Grid? {
if self.rows != other.rows || self.cols != other.cols {
None
} else {
let values : Array[Double] = []
for i in 0.. Double,
) -> Grid? {
if self.rows != other.rows || self.cols != other.cols {
None
} else {
let values : Array[Double] = []
for i in 0.. (Double, Double) {
let s = self.summary()
(s.minimum, s.maximum)
}
///|
pub fn Grid::normalize(self : Grid) -> Grid {
let (minimum, maximum) = self.min_max()
if maximum == minimum {
self.map(fn(_) { 0.0 })
} else {
self.map(fn(value) { (value - minimum) / (maximum - minimum) })
}
}
///|
pub fn Grid::threshold(
self : Grid,
level : Double,
low : Double,
high : Double,
) -> Grid {
self.map(fn(value) { if value < level { low } else { high } })
}
///|
pub fn Grid::count_where(self : Grid, predicate : (Double) -> Bool) -> Int {
let mut count = 0
for value in self.values {
if predicate(value) {
count += 1
}
}
count
}
///|
pub fn Grid::mean_absolute(self : Grid) -> Double {
let values : Array[Double] = []
for value in self.values {
values.push(value.abs())
}
summary(values).mean
}
///|
pub fn Grid::integral(self : Grid) -> Double {
let area = degrees_latitude_to_metres(self.lat_step).abs() *
degrees_longitude_to_metres(self.lon_step, self.origin_lat).abs()
self.summary().sum * area
}