2D genetic fractals makers guide (part 2): plotting fractals

Previous article: Implementing the Genetic Equation

Next article: Accessory functions

In the last post on 2D genetic fractals, we introduced the Genetic Equation without branches and saw that using the driver functions we generate any path that we want. The Excel example was useful for messing around with the driver functions. But for branches, in particular fractal branches, Excel is not the right tool. We need some sort of programmable canvas. There are thousands to choose from and there is no right choice. Here at planet Genetic Fractals we (as in I) use Ruby and TK graphical toolkit. I don’t know if Ruby is growing or shrinking in popularity but I love it. And TK is simple; enough said.

A bit of theory first. The genetic equation does two things:

  • It generates arbitrary paths based on driver functions and
  • It allows for smooth and continuous branches.

The first point we saw illustrated in the previous post. The second is what makes the Genetic Equation so special. It allows the creation of smooth, continuous and analytic branches in fractals,  i.e. we can differentiate these fractals analytically. (I promise to post on this!). You should perhaps have a glance at the section “Multi-varied driver functions” on the Genetic Equation page to understand how and why this works. For our purposes here, it is enough to say that these fractals here split into two branches anytime D_{\varphi+} =  D_{\varphi-} = 0.

In the Ruby code below, we read D_{r}D_{\varphi+} and D_{varphi-} from an external data.txt file in the same directory. This is produced by exporting an Excel file as tab delimited CSV. Some usable examples at the bottom of this post.

The Ruby code for this GeneticFractal2D class is here on GitHub.

I won’t comment on all the code here, there are some boring bits that are commented in the source file. Let’s just look at the main elements.

First we declare the class and in initialize it. Here we just create an empty array for the driver functions.

class GeneticFractal2D
#create an instance variable to keep the driver functions
attr_accessor :drivers

#create an empty array for the driver function
def initialize
@drivers = Array.new
end

Then we read the external CSV file. This CSV file is named “data.txt” and is created using excel and saved in CSV format. There are 4 colomns: s,  D_{r}D_{varphi+} and D_{varphi-}. At the bottom of this post there are sample excel and data.txt files for you to change and experiment with.

<pre> #read and parse CSV file in one line. Don't you love ruby!?
 def readDrivers(dfile)
    CSV.foreach(dfile,:col_sep=>"t") do |row| @drivers<<row end
 end

Next we have the Genetic Equation. We use it in its trigonometric form in 2D:

C(s)=\left\{\begin{matrix}x(s)\\ y(s)\end{matrix}\right.=\left \{\begin{matrix} \int_s D_{r}\textrm{sin}(\int_s D_{\varphi}ds)ds\\\int_s D_{r}\textrm{cos}(\int_s D_{\varphi}ds)ds\end{matrix} \right.

There are two integrals here. They both serve as a “memory”, i.e. the first integral remembers the coordinates of the last point on the fractal path and the second integral remembers what the direction was at that point. In this example, we approximate the integral by a simple summation, a Riemann Sum where Delta s=1.


#the Genetic Equation is implemented in its trigonemtric form for simplicity

def geneticEquation(dR,dPhi, lastPoint, lastPhi)
newPhi=lastPhi+dPhi #integrate over phi (it's summation really)
return [lastPoint[0]+dR*sin(newPhi),lastPoint[1]+dR*cos(newPhi)],newPhi
end

For plotting we use the RCL/TK library. It’s easy to use, so we’re good. We create a canvas, call the method that calculates the fractal and we hand off to the Tk.mainloop. This Tk.mainloop would allow interaction with the canvas which we don’t actually need. But that is how it works.

The plotPoint simply plots a line segment using one of the TK primitives TkcLine.

def mainPlot
   root = TkRoot.new(:title => "Genetic Fractals rule!")
   canvas = TkCanvas.new(root, :height => $canvasWidth, :width => $canvasHeight)
   evaluate(canvas,[0,0],3.141,0,2)
   canvas.pack
   Tk.mainloop
end
def plotPoint(canvas,beginPoint,endPoint)
   #plot the line segment between the points.
   #the coordinates are scaled and shifted to center it on the canvas
   #offset and scale are defined above
   TkcLine.new(
      canvas,
      beginPoint[0]*$scale+$xc+$canvasWidth/2,
      beginPoint[1]*$scale-$yc+$canvasHeight/2,
      endPoint[0]*$scale+$xc+$canvasWidth/2,
      endPoint[1]*$scale-$yc+$canvasHeight/2,
      'width' => '1',
      'fill' => 'black')
 end

Now we get to the core of the class: the part where we calculate the fractal. The first part calculates the points of a branch (wherever we are on the fractal, we’re always on a branch). If it encounters a branch point (i.e. vertex on the fractal) which occurs when  D_{varphi+} =  D_{varphi-} = 0, then we leave the while loop and assuming that we haven’t reached the maximum path length that we have set,  we can recursively evaluate the two branches that follow this node: one left branch and one right branch.


def evaluate(canvas,lastPoint,lastPhi,s,b)
   #get the driver values for Dr and Dphi
   dR=@drivers[s][1].to_f
   dPhi=@drivers[s][b].to_f

   #first calculate the points of a branch until we hit a branch point
   while dPhi!=0 and s<$maxS# i.e. while it is not a branch point
      #calculate next point using the Genetic Equation
      nextPoint, lastPhi = geneticEquation(dR, dPhi, lastPoint, lastPhi)

      #plot it on the canvas
      plotPoint(canvas,lastPoint,nextPoint)

      #for the next iteration, what was the next point is now the last point
      lastPoint = nextPoint.dup

      #get the next driver values for Dr and Dphi and increment s
      dR=@drivers[s][1].to_f
      dPhi=@drivers[s][b].to_f
      s+=1
   end

   # if we are here,
   # => either we have a branch point so we recursively create two branches;
   # => or we reach the maximum value of s that we allowed and will skip this.
   if s<$maxS #check s hasn't reached the maximum
      evaluate(canvas,nextPoint, lastPhi,s,2) # right branch uses column 2 of the data.txt file
      evaluate(canvas,nextPoint, lastPhi,s,3) # left branch uses column 3 of the data.txt file
   end
end

Now that the class has been implemented, we can instantiate it and trigger the plotting of the fracta.


# instantiate a fractal
niceFractal=GeneticFractal2D.new

# read the driver data
niceFractal.readDrivers("data.txt")

# create a canvas and start evaluating the fractal
niceFractal.mainPlot

# all done

Below are a few examples of fractals created with this little program. The links to source data.txt files are shown as well. It would be seriously brilliant if you tried to run the code yourself! If you do, leave a comment and “make my day”.
[You’ll see that the source data.txt has more than 4 columns. I used these to calculate the first 4 columns and the program will ignore them]

Note how these are all continuous smooth and analytic fractals. Seriously cool, right!
f1Fractal f1.jpg from data-1.txt

f2Fractal f2.jpg from data-2.txt

f3

Fractal f3.jpg from data-3.txt


f4

Fractal f4.jpg from data-4.txt


f5

Fractal f5.jpg from data-5.txt


f6

Fractal f5.jpg from data-6.txt

Previous article: Implementing the Genetic Equation

Next article: Accessory functions

Advertisements

7 thoughts on “2D genetic fractals makers guide (part 2): plotting fractals

  1. Pingback: 2D genetic fractals makers guide (part 3): Accessory functions | Genetic Fractals Laboratory

  2. Pingback: 2D genetic fractals: a Makers Guide | Genetic Fractals Laboratory

So what do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s