L-system-animated.frink

View or download L-system-animated.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

g = new graphics
garray = new array
win = g.show[]

for turn = 0 degrees to 90 degrees step .1 degree
{
   // 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 = 10
   // This is our starting string
   start = "fx"
   // These are the rules we apply
   rules = [["f","f"],["x","x+yf"],["y","fx-y"]]

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

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

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

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

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

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

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

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

   // 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
   theta = -4.5 turn   // This value keeps a Dragon curve from rotating
   g.stroke[2]
   x = 0
   y = 0
   stack = []  
   for i = 0 to length[current]-1
   {
      // This produces a nice sort of rainbow effect where most colors appear
      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"
      {
         nx = x + cos[theta]
         ny = y + sin[theta]
         g.line[x,y,nx,ny]
         x = nx
         y = ny
      }
      if cur == "[" 
         stack.push[[theta,x,y]]
      if cur == "]" 
         [theta,x,y] = stack.pop[]
      }

      // Draw the new frame after it's been calculated.
      win.replaceGraphics[g]
      garray.push[g]
      //g.write["dragon.png",1024,768]
}

// Now animate the already-calculated curves.
for a=1 to 3
{
   reverse[garray]  // Reverses array in-place.
   sleep[2 s]
   
   // Now animate in a loop.
   for g = garray
   {
      win.replaceGraphics[g]
      sleep[1/30 s]
   }
}


View or download L-system-animated.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 17596 days, 22 hours, 4 minutes ago.