///|
pub(all) struct PeriodicFloat {
run : FloatRun
wraps : Bool
unbounded : Bool
} derive(Eq, Debug, ToJson, FromJson)
///|
fn cyclic_runs(
bits : Array[Bool],
direction : Direction,
thread : Int,
min_length : Int,
) -> Array[PeriodicFloat] {
let n = bits.length()
let out = []
if bits.iter().all(fn(b) { b }) {
out.push({
run: { direction, thread, start: 0, length: n, },
wraps: true,
unbounded: true,
})
return out
}
for i = 0; i < n; i = i + 1 {
if !bits[i] || bits[(i + n - 1) % n] {
continue
}
let mut length = 1
while length < n && bits[(i + length) % n] {
length = length + 1
}
if length >= min_length {
out.push({
run: { direction, thread, start: i, length, },
wraps: i + length > n,
unbounded: false,
})
}
}
out
}
///|
/// Infinite tiled fabric. A wholly exposed thread is unbounded, never merely period-length.
pub fn Draft::periodic_floats(
self : Draft,
min_length : Int,
back? : Bool = false,
) -> Result[Array[PeriodicFloat], String] {
if min_length < 1 {
return Err("weave.float-limit")
}
let cells = self.drawdown()
let out = []
for x = 0; x < self.width(); x = x + 1 {
for
r in cyclic_runs(
cells.map(fn(row) { row[x] != back }),
Warp,
x,
min_length,
) {
out.push(r)
}
}
for y = 0; y < self.height(); y = y + 1 {
for r in cyclic_runs(cells[y].map(fn(b) { b == back }), Weft, y, min_length) {
out.push(r)
}
}
Ok(out)
}