///|
/// A rectangular scalar field used to drive color, scale and displacement.
pub(all) struct ScalarField {
width : Int
height : Int
values : Array[Double]
} derive(Eq, Debug, ToJson)
///|
pub fn ScalarField::new(
width : Int,
height : Int,
fill? : Double = 0.0,
) -> ScalarField {
let values = []
if width > 0 && height > 0 {
for _ in 0..<(width * height) {
values.push(fill)
}
}
{ width, height, values }
}
///|
pub fn[N : NoiseSampler] ScalarField::from_sampler(
width : Int,
height : Int,
scale : Double,
sampler : N,
) -> ScalarField {
let field = ScalarField::new(width, height)
for y in 0.. Int {
y * self.width + x
}
///|
pub fn ScalarField::in_bounds(self : ScalarField, x : Int, y : Int) -> Bool {
x >= 0 && y >= 0 && x < self.width && y < self.height
}
///|
pub fn ScalarField::get(self : ScalarField, x : Int, y : Int) -> Double? {
if self.in_bounds(x, y) {
Some(self.values[self.index(x, y)])
} else {
None
}
}
///|
pub fn ScalarField::set(
self : ScalarField,
x : Int,
y : Int,
value : Double,
) -> Bool {
if self.in_bounds(x, y) {
self.values[self.index(x, y)] = value
true
} else {
false
}
}
///|
pub fn ScalarField::map(
self : ScalarField,
transform : (Double) -> Double,
) -> ScalarField {
let result = ScalarField::new(self.width, self.height)
for i, value in self.values {
result.values[i] = transform(value)
}
result
}
///|
pub fn ScalarField::normalize(self : ScalarField) -> ScalarField {
let stats = sample_stats(self.values)
if stats.maximum == stats.minimum {
self.map(fn(_value) { 0.0 })
} else {
self.map(fn(value) {
(value - stats.minimum) / (stats.maximum - stats.minimum)
})
}
}
///|
pub fn ScalarField::blur(self : ScalarField, radius : Int) -> ScalarField {
let result = ScalarField::new(self.width, self.height)
if radius <= 0 {
self
} else {
for y in 0.. {
total += value
count += 1
}
None => ()
}
}
}
let _ = result.set(
x,
y,
if count == 0 {
0.0
} else {
total / count.to_double()
},
)
}
}
result
}
}
///|
pub fn ScalarField::to_points(
self : ScalarField,
threshold : Double,
) -> Array[Vec2] {
let points = []
for y in 0..= threshold {
points.push(Vec2::new(x.to_double(), y.to_double()))
}
}
}
points
}
///|
pub fn ScalarField::to_svg(
self : ScalarField,
cell_size : Double,
low : Color,
high : Color,
) -> SvgDocument {
let document = SvgDocument::new(
self.width.to_double() * cell_size,
self.height.to_double() * cell_size,
)
let normalized = self.normalize()
for y in 0..