2024-10-29 21:40:31 -04:00
|
|
|
// L-System KCL
|
|
|
|
// Zoo Corporation ⓒ 2024
|
|
|
|
|
|
|
|
// Comparators
|
|
|
|
|
|
|
|
fn cond = (bools) => {
|
|
|
|
return (a, b) => {
|
2024-11-25 10:50:43 +13:00
|
|
|
x = min(max(-1, a-b), 1) + 1
|
2024-10-29 21:40:31 -04:00
|
|
|
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, b)) }
|
|
|
|
fn Gte = (a, b) => { return Not(Lt(a, b)) }
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
deg = pi()*2 / 360
|
|
|
|
|
2024-12-17 09:01:51 +13:00
|
|
|
fn setSketch = (state, q) => {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-17 09:01:51 +13:00
|
|
|
fn setDepth = (state, q) => {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
|
|
|
depthMax: state.depthMax,
|
2024-12-17 09:01:51 +13:00
|
|
|
depth: q,
|
2024-10-29 21:40:31 -04:00
|
|
|
currentLength: state.currentLength,
|
|
|
|
factor: state.factor,
|
|
|
|
currentAngle: state.currentAngle,
|
|
|
|
angle: state.angle,
|
2024-12-17 09:01:51 +13:00
|
|
|
q: state.q
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-17 09:01:51 +13:00
|
|
|
fn setAngle = (state, q) => {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
|
|
|
depthMax: state.depthMax,
|
|
|
|
depth: state.depth,
|
|
|
|
currentLength: state.currentLength,
|
|
|
|
factor: state.factor,
|
2024-12-17 09:01:51 +13:00
|
|
|
currentAngle: q,
|
2024-10-29 21:40:31 -04:00
|
|
|
angle: state.angle,
|
2024-12-17 09:01:51 +13:00
|
|
|
q: state.q
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-17 09:01:51 +13:00
|
|
|
fn setLength = (state, q) => {
|
2024-10-29 21:40:31 -04:00
|
|
|
return {
|
|
|
|
depthMax: state.depthMax,
|
|
|
|
depth: state.depth,
|
2024-12-17 09:01:51 +13:00
|
|
|
currentLength: q,
|
2024-10-29 21:40:31 -04:00
|
|
|
factor: state.factor,
|
|
|
|
currentAngle: state.currentAngle,
|
|
|
|
angle: state.angle,
|
2024-12-17 09:01:51 +13:00
|
|
|
q: state.q
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn Gt2 = (state) => { return setLength(state, state.currentLength * state.factor) }
|
|
|
|
fn Lt2 = (state) => { return setLength(state, state.currentLength / state.factor) }
|
2024-12-12 11:53:35 -06:00
|
|
|
fn Add = (state) => { return setAngle(state, rem(int(state.currentAngle - state.angle), divisor = 360)) }
|
|
|
|
fn Sub = (state) => { return setAngle(state, rem(int(state.currentAngle + state.angle), divisor = 360)) }
|
2024-10-29 21:40:31 -04:00
|
|
|
|
|
|
|
// Only necessary to get around recursion limitations...
|
|
|
|
fn F = (state, F) => {
|
|
|
|
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
|
2024-12-17 09:01:51 +13:00
|
|
|
state |> setSketch(%, angledLine({ angle: state.currentAngle, length: state.currentLength }, state.q))
|
2024-10-29 21:40:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn LSystem = (args, axioms) => {
|
2025-03-01 16:32:46 -08:00
|
|
|
myThing = startSketchOn(XY)
|
|
|
|
|> startProfileAt([0, 0], %)
|
2024-10-29 21:40:31 -04:00
|
|
|
return axioms({
|
|
|
|
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({
|
|
|
|
iterations: 1,
|
|
|
|
factor: 1.36,
|
|
|
|
angle: 60,
|
2024-12-17 09:01:51 +13:00
|
|
|
}, (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
|
|
|
})
|