Files
modeling-app/rust/kcl-lib/e2e/executor/inputs/lsystem.kcl

123 lines
3.0 KiB
Plaintext
Raw Normal View History

// L-System KCL
// Zoo Corporation ⓒ 2024
// Comparators
fn cond(@bools) {
return fn(a, b) {
x = min([max([-1, a-b]), 1]) + 1
return bools[x]
}
}
fn Not(@b) { return if b { false } else { true } }
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 }}}
Eq = cond([false, true, false])
Lt = cond([true, false, false])
Gt = cond([false, false, true])
fn Lte(a, b) { return Not(Gt(a = a, b = b)) }
fn Gte(a, b) { return Not(Lt(a = a, b = b)) }
// L-system
// Note: it was most concise to encode productions directly in axioms.
// Change them as you need.
fn setSketch(@state, q) {
return {
depthMax = state.depthMax,
depth = state.depth + 1,
currentLength = state.currentLength,
factor = state.factor,
currentAngle = state.currentAngle,
angle = state.angle,
q
}
}
fn setDepth(@state, q) {
return {
depthMax = state.depthMax,
depth = q,
currentLength = state.currentLength,
factor = state.factor,
currentAngle = state.currentAngle,
angle = state.angle,
q = state.q
}
}
fn setAngle(@state, q) {
return {
depthMax = state.depthMax,
depth = state.depth,
currentLength = state.currentLength,
factor = state.factor,
currentAngle = q,
angle = state.angle,
q = state.q
}
}
fn setLength(@state, q) {
return {
depthMax = state.depthMax,
depth = state.depth,
currentLength = q,
factor = state.factor,
currentAngle = state.currentAngle,
angle = state.angle,
q = state.q
}
}
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)) }
// Only necessary to get around recursion limitations...
fn F(@state, F) {
return if Lt(a = state.depth, b = state.depthMax) {
stateNext = state |> setDepth(%, q = state.depth + 1)
// Produce
// Note:if you need [ and ], just save state to a variable.
stateNext
|> F(%, F = F) |> Sub(%) |> F(%, F = F)
|> Add(%) |> Add(%)
|> F(%, F = F) |> Sub(%) |> F(%, F = F)
|> setDepth(%, q = stateNext.depth - 1)
} else {
// Pass onto the next instruction
state |> setSketch(%, q = angledLine(state.q, angle = state.currentAngle, length = state.currentLength))
}
}
fn LSystem(@args, axioms) {
myThing = startSketchOn(XY)
|> startProfile(at = [0, 0])
return axioms({
depthMax = args.iterations,
depth = 0,
currentLength = 1.0,
factor = args.factor,
currentAngle = 0,
angle = args.angle,
q = myThing,
})
}
LSystem({
iterations = 1,
factor = 1.36,
angle = 60,
}, axioms = fn(@q) {
result = q |> F(%, F = F) |> Add(%) |> Add(%) |> F(%, F = F) |> Add(%) |> Add(%) |> F(%, F = F)
return result.q
})