Barnsley Fern
This article describes a uLisp program to plot an intriguing fractal graphic called the Barnsley Fern, that produces leaf shapes like natural ferns:
The above photograph shows the program running on a MAiX One Dock, using the uLisp graphics extensions.
This article originally appeared on the uLisp Forum.
Introduction
The Barnsley Fern [1] is an Iterated Function System (IFS) created by the British mathematician Michael Barnsley that draws a fractal resembling a fern. It uses four affine transformations that, when called over and over again, transform a single point around the screen.
The transformations are defined in uLisp using a two-dimensional array. For example, the soft bracken fern above (Calochlaena dubia) is generated by the following values designed by David Nicholls [2]:
(defvar f #2A((0 0 0 0.25 0 -0.14 0.02) (0.85 0.02 -0.02 0.83 0 1.0 0.84) (0.09 -0.28 0.3 0.11 0 0.6 0.07) (-0.09 0.28 0.3 0.09 0 0.7 0.07)))
Which of the transformations is picked depends on the last value in each row of the array. So the first transformation is picked with a probability of 0.02, the second with a probability of 0.84, etc.
By altering the numbers you can create fractals with a different appearance. For example, the following values were the ones originally suggested by Michael Barnsley:
(defvar f #2A((0 0 0 0.16 0 0 0.01) (0.85 0.04 -0.04 0.85 0 1.6 0.85) (0.2 -0.26 0.23 0.22 0 1.6 0.07) (-0.15 0.28 0.26 0.24 0 0.44 0.07))) (defvar *factor* (/ *height* 12.5))
This gives a fern resembling the black spleenwort (Asplenium adiantum-nigrum):
Here’s the whole program, suitable for running on a 360x240 display. To run it on a different display change these constants:
; ; Barnsley Fern (defvar *width* 240) (defvar *height* 360) (defvar *factor* (/ *height* 7)) (defvar *x-offset* (/ *width* 2)) (defvar *y-offset* (/ *height* 24)) (defvar *dark-green* #b0000001111100000)
The array f defines the transformations:
(defvar f #2A((0 0 0 0.25 0 -0.14 0.02) (0.85 0.02 -0.02 0.83 0 1.0 0.84) (0.09 -0.28 0.3 0.11 0 0.6 0.07) (-0.09 0.28 0.3 0.09 0 0.7 0.07)))
The program uses these functions:
(defun fn (n) #'(lambda (x y) (list (+ (* (aref f n 0) x) (* (aref f n 1) y) (aref f n 4)) (+ (* (aref f n 2) x) (* (aref f n 3) y) (aref f n 5))))) (defun choose-transform () (let ((r (random 1.0)) (p 0)) (dotimes (i 4) (when (<= r (incf p (aref f i 6))) (return (fn i)))))) (defun plot-pixel (x y) (let ((xx (round (+ (* *factor* y) *y-offset*))) (yy (round (- *width* (+ (* *factor* x) *x-offset*))))) (draw-pixel xx yy *dark-green*)))
Finally, here’s the main function:
(defun fern (&optional (iterations 50000)) (fill-screen #xFFFF) (let ((x 0) (y 0)) (dotimes (i iterations) (plot-pixel x y) (let ((xy (funcall (choose-transform) x y))) (setq x (first xy)) (setq y (second xy))))))
To plot the fern call:
(fern)
- ^ Barnsley Fern on Wikipedia.
- ^ Fractal ferns on Byzantium.