///|
/// Integrate a scalar field over unit lattice cells.
pub fn Field2D::integral(self : Field2D) -> Double {
sum_values(self.data)
}
///|
/// Integrate absolute values over unit lattice cells.
pub fn Field2D::absolute_integral(self : Field2D) -> Double {
let mut total = 0.0
for value in self.data {
total += abs_double(value)
}
total
}
///|
/// Count values above a threshold.
pub fn Field2D::count_above(self : Field2D, level~ : Double) -> Int {
let mut count = 0
for value in self.data {
if value >= level {
count += 1
}
}
count
}
///|
/// Count values that are not numerically zero.
pub fn Field2D::nonzero_count(
self : Field2D,
tolerance? : Double = 0.000000001,
) -> Int {
let mut count = 0
for value in self.data {
if abs_double(value) > tolerance {
count += 1
}
}
count
}
///|
/// Return the magnitude of the centered gradient at a cell.
pub fn Field2D::gradient_magnitude(
self : Field2D,
x~ : Int,
y~ : Int,
) -> Double {
gradient_at(self, x~, y~).length()
}
///|
/// Return the x component of the centered gradient.
pub fn Field2D::gradient_x(self : Field2D, x~ : Int, y~ : Int) -> Double {
gradient_at(self, x~, y~).x
}
///|
/// Return the y component of the centered gradient.
pub fn Field2D::gradient_y(self : Field2D, x~ : Int, y~ : Int) -> Double {
gradient_at(self, x~, y~).y
}
///|
/// Return a threshold mask with high values marked solid.
pub fn Field2D::threshold(self : Field2D, level~ : Double) -> DomainMask {
let mask = DomainMask::new(size=self.size)
for y in 0..= level {
mask.set(x~, y~, solid=true)
}
}
}
mask
}
///|
/// Apply a bounded pointwise transform.
pub fn Field2D::clamp(self : Field2D, low~ : Double, high~ : Double) -> Field2D {
self.map((_, _, value) => clamp_double(value, low~, high~))
}
///|
/// Normalize a field into a requested range.
pub fn Field2D::normalize(
self : Field2D,
low? : Double = 0.0,
high? : Double = 1.0,
) -> Field2D {
let statistics = self.statistics()
let denominator = statistics.maximum - statistics.minimum
if denominator == 0.0 {
Field2D::new(size=self.size, initial=low)
} else {
self.map((_, _, value) => {
let t = (value - statistics.minimum) / denominator
lerp(low, high, t)
})
}
}
///|
/// Average each cell with a square neighborhood.
pub fn Field2D::smooth(self : Field2D, radius? : Int = 1) -> Field2D {
let result = Field2D::new(size=self.size)
let r = radius.max(0)
for y in 0.. Field2D {
let result = Field2D::new(size=self.size)
for y in 0.. Double {
let values = Array::new()
for y in 0.. GridPoint {
if self.size.width <= 0 || self.size.height <= 0 {
GridPoint::{ x: 0, y: 0 }
} else {
let mut best = self.get(0, 0)
let mut location = GridPoint::{ x: 0, y: 0 }
for y in 0.. best {
best = value
location = GridPoint::{ x, y }
}
}
}
location
}
}
///|
/// Return the coordinate of a minimum value.
pub fn Field2D::minimum_location(self : Field2D) -> GridPoint {
if self.size.width <= 0 || self.size.height <= 0 {
GridPoint::{ x: 0, y: 0 }
} else {
let mut best = self.get(0, 0)
let mut location = GridPoint::{ x: 0, y: 0 }
for y in 0.. Double {
let n = left.data.length().min(right.data.length())
let mut total = 0.0
for i in 0.. Field2D {
let result = Field2D::new(size=left.size)
for y in 0.. Field2D {
let t = clamp_double(weight, low=0.0, high=1.0)
let result = Field2D::new(size=left.size)
for y in 0..