
A Barnsley fern is a fractal named after British mathematician Michael Barnsley and can be created using an iterated function system (IFS).



Task

Create this fractal fern, using the following transformations:

 ƒ1   (chosen 1% of the time)
        xn + 1 = 0
        yn + 1 = 0.16 yn

 ƒ2   (chosen 85% of the time)
        xn + 1 = 0.85 xn + 0.04 yn
        yn + 1 = −0.04 xn + 0.85 yn + 1.6

 ƒ3   (chosen 7% of the time)
        xn + 1 = 0.2 xn − 0.26 yn
        yn + 1 = 0.23 xn + 0.22 yn + 1.6

 ƒ4   (chosen 7% of the time)
        xn + 1 = −0.15 xn + 0.28 yn
        yn + 1 = 0.26 xn + 0.24 yn + 0.44.

Starting position: x = 0, y = 0




; Barnsley fern
 
(defun make-array (size)
  "Create an empty array with size*size elements."
  (setq m-array (make-vector size nil))
  (dotimes (i size)
    (setf (aref m-array i) (make-vector size 0)))
  m-array)
 
(defun barnsley-next (p)
  "Return the next Barnsley fern coordinates."
  (let ((r (random 100))
        (x (car p))
        (y (cdr p)))
      (cond ((< r 2)  (setq nx 0) (setq ny (* 0.16 y)))
            ((< r 9)  (setq nx (- (* 0.2 x) (* 0.26 y))) 
                        (setq ny (+ 1.6 (* 0.23 x) (* 0.22 y))))
            ((< r 16) (setq nx (+ (* -0.15 x) (* 0.28 y))) 
                        (setq ny (+ 0.44 (* 0.26 x) (* 0.24 y))))
            (t        (setq nx (+ (* 0.85 x) (* 0.04 y)))
                        (setq ny (+ 1.6 (* -0.04 x) (* 0.85 y)))))
      (cons nx ny)))
 
(defun barnsley-lines (arr size)
  "Turn array into a string for XPM conversion."
  (setq all "")
  (dotimes (y size)
    (setq line "")
    (dotimes (x size)
      (setq line (concat line (if (= (elt (elt arr y) x) 1) "*" "."))))
    (setq all (concat all "\"" line "\",\n")))
  all)
 
(defun barnsley-show (arr size)
  "Convert size*size array to XPM image and show it."
  (insert-image (create-image (concat (format "/* XPM */
static char * barnsley[] = {
\"%i %i 2 1\",
\".      c #000000\",
\"*      c #00ff00\"," size size)
    (barnsley-lines arr size) "};") 'xpm t)))
 
(defun barnsley (size scale max-iter)
  "Plot the Barnsley fern."
  (let ((arr (make-array size))
        (p (cons 0 0)))
    (dotimes (it max-iter)
      (setq p (barnsley-next p))
      (setq x (round (+ (/ size 2) (* scale (car p)))))
      (setq y (round (- size (* scale (cdr p)) 1)))
      (setf (elt (elt arr y) x) 1))
    (barnsley-show arr size)))
 
(barnsley 400 35 100000)