2024-10-29 21:40:31 -04:00
|
|
|
// L-System KCL
|
|
|
|
// Zoo Corporation ⓒ 2024
|
|
|
|
|
|
|
|
// Comparators
|
|
|
|
|
2025-04-30 13:12:40 +12:00
|
|
|
fn cond(bools) {
|
|
|
|
return fn(a, b) {
|
2025-04-30 15:59:19 +12:00
|
|
|
x = math::min([math::max([-1, a-b]), 1]) + 1
|
2024-10-29 21:40:31 -04:00
|
|
|
return bools[x]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-30 13:12:40 +12:00
|
|
|
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 }}}
|
2024-10-29 21:40:31 -04:00
|
|
|
|
|
|
|
Eq = cond([false, true, false])
|
|
|
|
Lt = cond([true, false, false])
|
|
|
|
Gt = cond([false, false, true])
|
|
|
|
|
2025-04-30 13:12:40 +12:00
|
|
|
fn Lte(a, b) { return Not(Gt(a, b)) }
|
|
|
|
fn Gte(a, b) { return Not(Lt(a, 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-04-30 13:12:40 +12: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-04-30 13:12:40 +12: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-04-30 13:12:40 +12: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-04-30 13:12:40 +12: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-04-30 13:12:40 +12:00
|
|
|
fn Gt2(state) { return setLength(state, state.currentLength * state.factor) }
|
|
|
|
fn Lt2(state) { return setLength(state, state.currentLength / state.factor) }
|
2025-04-30 15:59:19 +12:00
|
|
|
fn Add(state) { return setAngle(state, math::rem(state.currentAngle - state.angle, divisor = 360)) }
|
|
|
|
fn Sub(state) { return setAngle(state, math::rem(state.currentAngle + state.angle, divisor = 360)) }
|
2024-10-29 21:40:31 -04:00
|
|
|
|
|
|
|
// Only necessary to get around recursion limitations...
|
2025-04-30 13:12:40 +12:00
|
|
|
fn F(state, F) {
|
2024-10-29 21:40:31 -04:00
|
|
|
return if Lt(state.depth, state.depthMax) {
|
|
|
|
stateNext = state |> setDepth(%, state.depth + 1)
|
|
|
|
|
|
|
|
// Produce
|
|
|
|
// Note:if you need [ and ], just save state to a variable.
|
|
|
|
stateNext
|
|
|
|
|> F(%, F) |> Sub(%) |> F(%, F)
|
|
|
|
|> Add(%) |> Add(%)
|
|
|
|
|> F(%, F) |> Sub(%) |> F(%, F)
|
|
|
|
|> setDepth(%, stateNext.depth - 1)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Pass onto the next instruction
|
KCL: Angled line should use keyword args (#5803)
We continue migrating KCL stdlib functions to use keyword arguments. Next up is the `angledLine` family of functions (except `angledLineThatIntersects, which will be a quick follow-up).
Before vs. after:
`angledLine({angle = 90, length = 3}, %, $edge)`
=> `angledLine(angle = 90, length = 3, tag = $edge)`
`angledLineOfXLength({angle = 90, length = 3}, %, $edge)`
=> `angledLine(angle = 90, lengthX = 3, tag = $edge)`
`angledLineOfYLength({angle = 90, length = 3}, %, $edge)`
=> `angledLine(angle = 90, lengthY = 3, tag = $edge)`
`angledLineToX({angle = 90, length = 3}, %, $edge)`
=> `angledLine(angle = 90, endAbsoluteX = 3, tag = $edge)`
`angledLineToY({angle = 90, length = 3}, %, $edge)`
=> `angledLine(angle = 90, endAbsoluteY = 3, tag = $edge)`
2025-04-09 14:55:15 -05:00
|
|
|
state |> setSketch(%, angledLine(state.q, angle = state.currentAngle, length = state.currentLength))
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-30 13:12:40 +12: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,
|
|
|
|
}, fn(q) {
|
2025-03-01 16:32:46 -08:00
|
|
|
result = q |> F(%, F) |> Add(%) |> Add(%) |> F(%, F) |> Add(%) |> Add(%) |> F(%, F)
|
2024-12-17 09:01:51 +13:00
|
|
|
return result.q
|
2024-10-29 21:40:31 -04:00
|
|
|
})
|