Previous article: Plotting fractals

Next article: Arbitrary branchings

In the previous post we created the Ruby code to implement the Genetic Equation and generated a few fractals like the one below.

This is could be the end of the 2D genetic fractal story: with the tool we made, we can generate many types of 2D fractals. But why stop there? These fractals are only skeletons that show us the architecture of these fractals but nothing else. No color, no line width, no nothing. Let’s fix this in this post.

You will recall the equation of genetic fractals:

The geometry, i.e. the shape of the fractal is determined by the driver functions: and .

We haven’t said much about the variable *s*. The fractal is a function of this variable, i.e. as *s* increases, the fractal evolves. You could think of s as the distance along any path on the fractal. We started this post by saying that we wanted to add features like color and width to these fractals and now we have a way of doing that. We can define “accessory functions” that have *s *as a variable and define the color and width along the paths of the fractal. In a way, we can also think of and as accessory functions. The fractal is now defined as:

with accessory functions:

This may not seem pertinent at a first glance since all we have done is define a set of functions. The crucial point is that for a given value of *s* we can know exactly what this fractal will look like at that point, without knowing what it looks like elsewhere. Put this in contrast with many formulations of fractals which are iterative, i.e. you need to construct the fractal up to the given value of *s* to know what the fractal looks like at that point. As we implement the accessory functions, we will also see a key feature of genetic fractals: copy & paste bits of fractal by taking a chunk of the accessory functions over a range of *s.*

Enough of the theory; let’s upgrade the Ruby code.

We take the same approach as before and define the values of the accessory functions in an Excel sheet that we save in a tab delimited format. The way the code was written before works for any number of columns. So we don’t have to change anything but to avoid confusion, we name the columns, put a column header in the Excel sheet for clarity and remove that column on import.

# a few constants to define the data columns in the CSV AccSCol=0 AccDrCol=1 AccDrPhiLeftCol=2 AccDrPhiRightCol=3 AccBranchCol=4 AccWidthCol=5 AccColorColR=6 AccColorColG=7 AccColorColB=8 AccLuminocityColB=9 def readAccessoryFunctions(dfile) #read and parse CSV file in one line. Don't you love ruby!? CSV.foreach(dfile,:col_sep=&amp;amp;amp;gt;&amp;amp;amp;quot;t&amp;amp;amp;quot;) do |row| @AccFunctions&amp;amp;amp;lt;&amp;amp;amp;lt;row end #delete the column headers that were read from the CSV file @drivers.delete_at(0) end

All we have to do now is implement the color and width functions. We could simply use the color and width properties of the TkcLine function:

&amp;amp;amp;lt;/pre&amp;amp;amp;gt; &amp;amp;amp;amp;nbsp; &amp;amp;amp;lt;pre&amp;amp;amp;gt;def plotPoint(canvas,beginPoint,endPoint,color, width) #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' =&amp;amp;amp;amp;gt; width, 'fill' =&amp;amp;amp;amp;gt; color) end&amp;amp;amp;lt;/pre&amp;amp;amp;gt; &amp;amp;amp;lt;pre&amp;amp;amp;gt;

This gives the result below. We see immediately that the use of the TkcLine width property doesn’t do a good job. The individual lines aren’t properly joined and the line width can only take on integer values.

Instead of using TkcLine we should use TkcPolygon and create trapezoid shapes for the line segments. To calculate the four corners of a trapezoid with a given ‘length’ and ‘widths’ at either end and do so in an arbitrary direction isn’t hard but you need to concentrate as you figure it out. The most important thing to know is how to calculate a line perpendicular to another. Wolfram would be a good place to look. The rest is just translations. So, here is the revised code to draw a line with a certain width.

def plotPoint(canvas,beginPoint,endPoint,width,color) # Plot the line segment between the points. # Instead of using a TkcLine and change its width, we draw a polygon that # allows us to have a different width at the start and end of the line # segment. We do this by working out the normal (perpendicukar) line segment # of the normalized line segment (brought back to zero) and adding it to the # endPoint. # # Note that we only need to calculate the left and right points with respect # to the new end point since we already know the left and right points of the # previous point # # The coordinates are scaled and shifted to center it on the canvas # offset and scale are defined above normalizedPoint=Array.new normalPoint=Array.new normalizedPoint[0]=endPoint.point[0]-beginPoint.point[0] #bring the current vector back to the origin normalizedPoint[1]=endPoint.point[1]-beginPoint.point[1] #bring the current vector back to the origin normalPoint[0]=-normalizedPoint[1] # find its normal (perpendicular vector) normalPoint[1]=normalizedPoint[0] # find its normal (perpendicular vector) endPoint.left[0]=endPoint.point[0]-normalPoint[0]/2*width # translate half the normal vector the end point of the new vector (left point) endPoint.left[1]=endPoint.point[1]-normalPoint[1]/2*width # translate half the normal vector the end point of the new vector (left point) endPoint.right[0]=endPoint.point[0]+normalPoint[0]/2*width # translate half the normal vector the end point of the new vector (right point) endPoint.right[1]=endPoint.point[1]+normalPoint[1]/2*width # translate half the normal vector the end point of the new vector (right point) TkcPolygon.new( canvas, beginPoint.left[0]*$scale+$xc+$canvasWidth/2, beginPoint.left[1]*$scale-$yc+$canvasHeight/2, endPoint.left[0]*$scale+$xc+$canvasWidth/2, endPoint.left[1]*$scale-$yc+$canvasHeight/2, endPoint.right[0]*$scale+$xc+$canvasWidth/2, endPoint.right[1]*$scale-$yc+$canvasHeight/2, beginPoint.right[0]*$scale+$xc+$canvasWidth/2, beginPoint.right[1]*$scale-$yc+$canvasHeight/2, 'width' =&amp;amp;amp;gt; width, 'fill' =&amp;amp;amp;gt; color) end

The line rendering is much better now:

The last thing we’ll improve is the control of the fractal branching. As explained in the theory of the Creation Equation, the function will split into two branches when the value of . This is an important notion for the theory of these fractals since it allows us to to analysis on the fractals whilst the function remains analytic. However, when we implement this trigger for branching, it makes the editing of the Excel sheet more clumsy because we have to put in those zeros into the column. It’s easier to separate the curving from the branching and we introduce an additional “branch” column into the Excel sheet. The condition in the “Evaluate” method has been adapted as well.

The final source code is here.

As usual, a few examples below, showing the coloring and line width facilities. The data files are shown underneath.

Fractal-21 (data here).

Fractal-22 (data here)

Fractal-23 (data here)

Previous article: Plotting fractals

Next article: Arbitrary branchings

Pingback: 2D genetic fractals makers guide (part 2): plotting fractals | Genetic Fractals Laboratory

Pingback: 2D genetic fractals makers guide (part 4): Arbitrary branchings | Genetic Fractals Laboratory