///|
/// One observation at an explicit UTC instant; no clock or I/O is consulted.
pub(all) struct Observation {
time : Instant
sun : Position
moon : MoonPosition
illumination : Illumination
} derive(Eq, Debug)
///|
/// Fixed-step, bounded sampling. All timestamps are validated before allocation.
/// Step must be a positive whole number of milliseconds; count is 1..4096.
pub fn sample_observations(
start : Instant,
step_ms : Double,
count : Int,
site : Observer,
) -> Result[Array[Observation], InputError] {
if count < 1 || count > 4096 {
return Err(InvalidSampleCount)
}
if !(step_ms > 0.0 && step_ms <= 7920806400000.0) ||
@math.trunc(step_ms) != step_ms {
return Err(InvalidSamplingStep)
}
let last = start.ms + step_ms * (count - 1).to_double()
match instant(last) {
Err(e) => return Err(e)
Ok(_) => ()
}
let samples : Array[Observation] = []
for i = 0; i < count; i = i + 1 {
let time = { ms: start.ms + step_ms * i.to_double(), }
samples.push({
time,
sun: sun_position(time, site),
moon: moon_position(time, site),
illumination: moon_illumination(time),
})
}
Ok(samples)
}