Fractals are infinitely complex, never-ending patterns that are self-similar across different scales. They are created by repeating a simple process over and over in an ongoing feedback loop.
Nature is full of fractals. For example, trees are natural fractals, patterns that repeat smaller and smaller copies of themselves to create the biodiversity of a forest. Fern is another example of fractal in nature. One really good example of fractal form in nature is Romanesco broccoli, showing self-similar form approximating a natural fractal:
The Mandelbrot Set is an Abstract Fractal which can be generated by a computer calculating a simple equation over and over. It is a structure with an infinite amount of details. It is possible to zoom in on the edge of the fractal forever, and it will continue to reveal ever-smaller details.
The Mandelbrot set is calculated by equation: f(z) = z2 + c
, where c is complex number: c = x + iy
In this function i is a square root of -1 and x and y are the horizontal and vertical position whose color we calculate. The function is applied many times, and the output value of z from each iteration is being used as input for the next iteration. During iteration, if the value of z exceeds 2, then iteration halts and the value of c determines if it is located outside the border of the Mandelbrot set (in blue zone) or it lies inside the border of the Mandelbrot set.
To implement the function in our program we have to take in account the x and y coordinate values of the display. Now our fractal function looks like this:
fun calculateMandelbrot(cX: Double, cY: Double): Int {
var zx = 0.0
var zy = 0.0
var i = 0
while (i < iter && (zx * zx + zy * zy) < 4) {
val zxtmp = zx * zx - zy * zy + cX + positionX
zy = 2 * zx * zy + cY + positionY
zx = zxtmp
i++
}
return i
}
This function has to be called for every dot on the screen and we do this with two while loops. At the same time, for each of those points we add the color values to the IntArray variable mImage:
while (y < mHeight) {
val cY = -1.0 + y * (2.0/mHeight) / zoom
var x = 0
while (x < mWidth) {
val cX = -2.5 + x * (3.5/mWidth) / zoom
val colorIndex = calculateMandelbrot(cX, cY) * (mPalette.size - 1) / iter
mImage[y * mWidth + x] = mPalette[colorIndex]
x++
}
y++
}
The variable iter is number of iteration we do. A higher value increase the complexity of the Mandelbrot set, but also increase the time required to calculate and render the final image.
And finally, with the collected information we can create an image with the createImage() function in the SurfView class:
private fun createImage() {
val can = holder.lockCanvas()
val bitmap = Bitmap.createBitmap(mImage!!, mWidth, mHeight, Bitmap.Config.ARGB_8888)
can.drawBitmap(bitmap, 0f, 0f, null)
holder.unlockCanvasAndPost(can)
}
And here is a full code in Kotlin.