L-system.frink

Download or view L-system.frink in plain text format

// General description:
// This code creates Lindenmayer rules via string manipulation
// It can generate many of the examples from the Wikipedia page
// discussing L-system fractals: http://en.wikipedia.org/wiki/L-system
//
// It does not support stochastic, context sensitive or parametric grammars
//
// It supports four special rules, and any number of variables in rules
// f = move forward one unit
// - = turn left one turn
// + = turn right one turn
// [ = save angle and position on a stack
// ] = restore angle and position from the stack

class LSystem
{
   var name
   var turn
   var start
   var rules

   // Array of LSystem
   class var systems = new array

   new[name, turn, start, rules] :=
   {
      this.name = name
      this.turn = turn
      this.start = start
      this.rules = rules
      systems.push[this]
   }
}

// The turn is how far each + or - in the final rule turns to either side
turn = 90 degrees
// This is how many times the rules get applied before we draw the result
times = 6
// This is our starting string
start = "++a"
// These are the rules we apply
rules = [["f","f"],["a","-bf+afa+fb-"], ["b","+af-bfb-fa+"]]

// L-System rules pulled from Wikipedia
// Dragon
new LSystem["Dragon", 90 degrees, "fx", [["f","f"],["x","x+yf"],["y","fx-y"]]]

// TerDragon
new LSystem["TerDragon", 120 degrees, "f", [["f","f+f-f"]]]

// Koch curve
// use "++f" as the start to flip it over
new LSystem["Koch", 90 degrees, "f", [["f","f+f-f-f+f"]]]

// Sierpinski Triangle
new LSystem["Sierpinski triangle", 60 degrees, "bf", [["f","f"],["a","bf-af-b"],["b","af+bf+a"]]]

// Plant
new LSystem["Plant", 25 degrees, "--x", [["f","ff"],["x","f-[[x]+x]+f[+fx]-x"]]]

// Hilbert space filling curve
new LSystem["Hilbert space-filling", 90 degrees, "++a", [["f","f"],["a","-bf+afa+fb-"], ["b","+af-bfb-fa+"]]]

// Peano-Gosper curve
new LSystem["Peano-Gosper", 60 degrees, "x", [["f","f"],["x","x+yf++yf-fx--fxfx-yf+"], ["y","-fx+yfyf++yf+fx--fx-y"]]]

// Lévy C curve
new LSystem["Lévy", 45 degrees, "f", [["f","+f--f+"]]]

// Kochawave curve,
// https://arxiv.org/abs/2210.17320
new LSystem["Kochawave", 30 degrees, "f", [["f", "f-f+++++f----f"]]]

prompt = ""
for i = rangeOf[LSystem.systems]
{
   lsys = LSystem.systems@i
   prompt=prompt+ "$i: " + lsys.name + "\n"
}
prompt = prompt + "\nChoose a system number:"

i = eval[input[prompt, 5]]
lsys = LSystem.systems@i
turn = lsys.turn
start = lsys.start
rules = lsys.rules

times = eval[input["Number of times:", 6]]

// This function will apply our rule once, using string substitutions based
// on the rules we pass it
// It does this in two passes to avoid problems with pairs of mutually referencing
// rules such as in the Sierpinski Triangle
// rules@k@1 could replace toString[k] and the entire second loop could
// vanish without adversely affecting the Dragon or Koch curves.

apply_rules[rules, current] :=
{
   n = current
   for k = 0 to length[rules]-1
   {
      rep = subst[rules@k@0,toString[k],"g"]
      n =~ rep
   }
   for k = 0 to length[rules]-1
   {
      rep = subst[toString[k],rules@k@1,"g"]
      n =~ rep
   }
   return n
}

// Here we will actually apply our rules the number of times specified
current = start
for i = 0 to times - 1
{
   current = apply_rules[rules, current]
   // Uncomment this line to see the string that is being produced at each stage
   // println[current]
}

// Go ahead and plot the image now that we've worked it out
g = new graphics
//g.antialiased[false]   // Comment this out for non-square rules. It looks better
theta = 0 degrees
x = 0
y = 0
stack = new array
for i = 0 to length[current]-1
{
   // This produces a nice sort of rainbow effect where most colors appear
   // comment it out for a plain black fractal
   // g.color[abs[sin[i degrees]],abs[cos[i*2 degrees]],abs[sin[i*4 degrees]]]

   cur = substrLen[current,i,1]
   if cur == "-"
      theta = theta - (turn)
   if cur == "+"
      theta = theta + (turn)
   if cur == "f" or cur == "F"
   {
      g.line[x,y,x + cos[theta],y + sin[theta]]
      x = x + cos[theta]
      y = y + sin[theta]
   }
   if cur == "[" 
      stack.push[[theta,x,y]]
   if cur == "]" 
      [theta,x,y] = stack.pop[]
}

g.show[]
g.write["hilbert.png",512,undef]


Download or view L-system.frink in plain text format


This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 19945 days, 6 hours, 4 minutes ago.