2024-10-29 21:40:31 -04:00
|
|
|
// L-System KCL
|
|
|
|
// Zoo Corporation ⓒ 2024
|
|
|
|
|
|
|
|
// Comparators
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn cond(@bools) {
|
2025-04-30 13:12:40 +12:00
|
|
|
return fn(a, b) {
|
2025-04-30 11:07:05 -04:00
|
|
|
x = min([max([-1, a-b]), 1]) + 1
|
2024-10-29 21:40:31 -04:00
|
|
|
return bools[x]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn Not(@b) { return if b { false } else { true } }
|
2025-04-30 13:12:40 +12:00
|
|
|
fn And(a, b) { return if a { if b { true } else { false } } else { false }}
|
|
|
|
fn Or(a, b) { return if a { true } else { if b { true } else { false }}}
|
2024-10-29 21:40:31 -04:00
|
|
|
|
|
|
|
Eq = cond([false, true, false])
|
|
|
|
Lt = cond([true, false, false])
|
|
|
|
Gt = cond([false, false, true])
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn Lte(a, b) { return Not(Gt(a = a, b = b)) }
|
|
|
|
fn Gte(a, b) { return Not(Lt(a = a, b = b)) }
|
2024-10-29 21:40:31 -04:00
|
|
|
|
2025-03-01 16:32:46 -08:00
|
|
|
// L-system
|
2024-10-29 21:40:31 -04:00
|
|
|
// Note: it was most concise to encode productions directly in axioms.
|
|
|
|
// Change them as you need.
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn setSketch(@state, q) {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
2025-04-30 13:12:40 +12:00
|
|
|
depthMax = state.depthMax,
|
|
|
|
depth = state.depth + 1,
|
|
|
|
currentLength = state.currentLength,
|
|
|
|
factor = state.factor,
|
|
|
|
currentAngle = state.currentAngle,
|
|
|
|
angle = state.angle,
|
2024-12-17 09:01:51 +13:00
|
|
|
q
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn setDepth(@state, q) {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
2025-04-30 13:12:40 +12:00
|
|
|
depthMax = state.depthMax,
|
|
|
|
depth = q,
|
|
|
|
currentLength = state.currentLength,
|
|
|
|
factor = state.factor,
|
|
|
|
currentAngle = state.currentAngle,
|
|
|
|
angle = state.angle,
|
|
|
|
q = state.q
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn setAngle(@state, q) {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
2025-04-30 13:12:40 +12:00
|
|
|
depthMax = state.depthMax,
|
|
|
|
depth = state.depth,
|
|
|
|
currentLength = state.currentLength,
|
|
|
|
factor = state.factor,
|
|
|
|
currentAngle = q,
|
|
|
|
angle = state.angle,
|
|
|
|
q = state.q
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn setLength(@state, q) {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
2025-04-30 13:12:40 +12:00
|
|
|
depthMax = state.depthMax,
|
|
|
|
depth = state.depth,
|
|
|
|
currentLength = q,
|
|
|
|
factor = state.factor,
|
|
|
|
currentAngle = state.currentAngle,
|
|
|
|
angle = state.angle,
|
|
|
|
q = state.q
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn Gt2(@state) { return setLength(state, q = state.currentLength * state.factor) }
|
|
|
|
fn Lt2(@state) { return setLength(state, q = state.currentLength / state.factor) }
|
|
|
|
fn Add(@state) { return setAngle(state, q = rem(state.currentAngle - state.angle, divisor = 360)) }
|
|
|
|
fn Sub(@state) { return setAngle(state, q = rem(state.currentAngle + state.angle, divisor = 360)) }
|
2024-10-29 21:40:31 -04:00
|
|
|
|
|
|
|
// Only necessary to get around recursion limitations...
|
2025-05-01 11:36:51 -05:00
|
|
|
fn F(@state, F) {
|
|
|
|
return if Lt(a = state.depth, b = state.depthMax) {
|
|
|
|
stateNext = state |> setDepth(%, q = state.depth + 1)
|
2024-10-29 21:40:31 -04:00
|
|
|
|
|
|
|
// Produce
|
|
|
|
// Note:if you need [ and ], just save state to a variable.
|
|
|
|
stateNext
|
2025-05-01 11:36:51 -05:00
|
|
|
|> F(%, F = F) |> Sub(%) |> F(%, F = F)
|
2024-10-29 21:40:31 -04:00
|
|
|
|> Add(%) |> Add(%)
|
2025-05-01 11:36:51 -05:00
|
|
|
|> F(%, F = F) |> Sub(%) |> F(%, F = F)
|
|
|
|
|> setDepth(%, q = stateNext.depth - 1)
|
2024-10-29 21:40:31 -04:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Pass onto the next instruction
|
2025-05-01 11:36:51 -05:00
|
|
|
state |> setSketch(%, q = angledLine(state.q, angle = state.currentAngle, length = state.currentLength))
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-01 11:36:51 -05:00
|
|
|
fn LSystem(@args, axioms) {
|
2025-03-01 16:32:46 -08:00
|
|
|
myThing = startSketchOn(XY)
|
2025-04-25 16:01:35 -05:00
|
|
|
|> startProfile(at = [0, 0])
|
2024-10-29 21:40:31 -04:00
|
|
|
return axioms({
|
2025-04-30 13:12:40 +12:00
|
|
|
depthMax = args.iterations,
|
|
|
|
depth = 0,
|
|
|
|
currentLength = 1.0,
|
|
|
|
factor = args.factor,
|
|
|
|
currentAngle = 0,
|
|
|
|
angle = args.angle,
|
2025-03-01 16:32:46 -08:00
|
|
|
q = myThing,
|
2024-10-29 21:40:31 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
LSystem({
|
2025-04-30 13:12:40 +12:00
|
|
|
iterations = 1,
|
|
|
|
factor = 1.36,
|
|
|
|
angle = 60,
|
2025-05-01 11:36:51 -05:00
|
|
|
}, axioms = fn(@q) {
|
|
|
|
result = q |> F(%, F = F) |> Add(%) |> Add(%) |> F(%, F = F) |> Add(%) |> Add(%) |> F(%, F = F)
|
2024-12-17 09:01:51 +13:00
|
|
|
return result.q
|
2024-10-29 21:40:31 -04:00
|
|
|
})
|
2025-05-01 11:36:51 -05:00
|
|
|
|