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

Task
Barnsley fern
You are encouraged to solve this task according to the task description, using any language you may know.


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

C++

 

<lang cpp>

  1. include <windows.h>
  2. include <ctime>
  3. include <string>

const int BMP_SIZE = 600, ITERATIONS = static_cast<int>( 15e5 );

class myBitmap { public:

   myBitmap() : pen( NULL ), brush( NULL ), clr( 0 ), wid( 1 ) {}
   ~myBitmap() {
       DeleteObject( pen ); DeleteObject( brush );
       DeleteDC( hdc ); DeleteObject( bmp );
   }
   bool create( int w, int h ) {
       BITMAPINFO bi;
       ZeroMemory( &bi, sizeof( bi ) );
       bi.bmiHeader.biSize        = sizeof( bi.bmiHeader );
       bi.bmiHeader.biBitCount    = sizeof( DWORD ) * 8;
       bi.bmiHeader.biCompression = BI_RGB;
       bi.bmiHeader.biPlanes      = 1;
       bi.bmiHeader.biWidth       =  w;
       bi.bmiHeader.biHeight      = -h;
       HDC dc = GetDC( GetConsoleWindow() );
       bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 );
       if( !bmp ) return false;
       hdc = CreateCompatibleDC( dc );
       SelectObject( hdc, bmp );
       ReleaseDC( GetConsoleWindow(), dc );
       width = w; height = h;
       return true;
   }
   void clear( BYTE clr = 0 ) {
       memset( pBits, clr, width * height * sizeof( DWORD ) );
   }
   void setBrushColor( DWORD bClr ) {
       if( brush ) DeleteObject( brush );
       brush = CreateSolidBrush( bClr );
       SelectObject( hdc, brush );
   }
   void setPenColor( DWORD c ) {
       clr = c; createPen();
   }
   void setPenWidth( int w ) {
       wid = w; createPen();
   }
   void saveBitmap( std::string path ) {
       BITMAPFILEHEADER fileheader;
       BITMAPINFO       infoheader;
       BITMAP           bitmap;
       DWORD            wb;
       GetObject( bmp, sizeof( bitmap ), &bitmap );
       DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
       ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
       ZeroMemory( &infoheader, sizeof( BITMAPINFO ) );
       ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );
       infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
       infoheader.bmiHeader.biCompression = BI_RGB;
       infoheader.bmiHeader.biPlanes = 1;
       infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader );
       infoheader.bmiHeader.biHeight = bitmap.bmHeight;
       infoheader.bmiHeader.biWidth = bitmap.bmWidth;
       infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );
       fileheader.bfType    = 0x4D42;
       fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER );
       fileheader.bfSize    = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
       GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );
       HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 
           FILE_ATTRIBUTE_NORMAL, NULL );
       WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL );
       WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL );
       WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL );
       CloseHandle( file );
       delete [] dwpBits;
   }
   HDC getDC() const     { return hdc; }
   int getWidth() const  { return width; }
   int getHeight() const { return height; }

private:

   void createPen() {
       if( pen ) DeleteObject( pen );
       pen = CreatePen( PS_SOLID, wid, clr );
       SelectObject( hdc, pen );
   }
   HBITMAP bmp; HDC    hdc;
   HPEN    pen; HBRUSH brush;
   void    *pBits; int    width, height, wid;
   DWORD    clr;

}; class fern { public:

   void draw() {
       bmp.create( BMP_SIZE, BMP_SIZE );
       float x = 0, y = 0; HDC dc = bmp.getDC();
       int hs = BMP_SIZE >> 1;
       for( int f = 0; f < ITERATIONS; f++ ) {
           SetPixel( dc, hs + static_cast<int>( x * 55.f ), 
                     BMP_SIZE - 15 - static_cast<int>( y * 55.f ), 
                     RGB( static_cast<int>( rnd() * 80.f ) + 20, 
                          static_cast<int>( rnd() * 128.f ) + 128, 
                          static_cast<int>( rnd() * 80.f ) + 30 ) ); 
           getXY( x, y );
       }
       bmp.saveBitmap( "./bf.bmp" );
   }

private:

   void getXY( float& x, float& y ) {
       float g, xl, yl;
       g = rnd();
       if( g < .01f ) { xl = 0; yl = .16f * y; } 
       else if( g < .07f ) {
           xl = .2f * x - .26f * y;
           yl = .23f * x + .22f * y + 1.6f;
       } else if( g < .14f ) {
           xl = -.15f * x + .28f * y;
           yl = .26f * x + .24f * y + .44f;
       } else {
           xl = .85f * x + .04f * y;
           yl = -.04f * x + .85f * y + 1.6f;
       }
       x = xl; y = yl;
   }
   float rnd() {
       return static_cast<float>( rand() ) / static_cast<float>( RAND_MAX );
   }
   myBitmap bmp;

}; int main( int argc, char* argv[]) {

   srand( static_cast<unsigned>( time( 0 ) ) );
   fern f; f.draw(); return 0;    

} </lang>

C#

<lang csharp>using System; using System.Diagnostics; using System.Drawing;

namespace RosettaBarnsleyFern {

   class Program
   {
       static void Main(string[] args)
       {
           const int w = 600;
           const int h = 600;
           var bm = new Bitmap(w, h);
           var r = new Random();
           double x = 0;
           double y = 0;
           for (int count = 0; count < 100000; count++)
           {
               bm.SetPixel((int)(300 + 58 * x), (int)(58 * y), Color.ForestGreen);
               int roll = r.Next(100);
               double xp = x;
               if (roll < 1)
               {
                   x = 0;
                   y = 0.16 * y;
               } else if (roll < 86)
               {
                   x = 0.85 * x + 0.04 * y;
                   y = -0.04 * xp + 0.85 * y + 1.6;
               } else if (roll < 93)
               {
                   x = 0.2 * x - 0.26 * y;
                   y = 0.23 * xp + 0.22 * y + 1.6;
               } else
               {
                   x = -0.15 * x + 0.28 * y;
                   y = 0.26 * xp + 0.24 * y + 0.44;
               }
           }
           const string filename = "Fern.png";
           bm.Save(filename);
           Process.Start(filename);
       }
   }

}</lang>

Delphi

Translation of: Java

Hint: After putting a TPaintBox on the main form align it to alClient. Client width / heigth of the main form should be no less than 640 x 480. <lang delphi>unit Unit1;

interface

uses

 Windows, SysUtils, Graphics, Forms, Controls, Classes, ExtCtrls;

type

 TForm1 = class(TForm)
   PaintBox1: TPaintBox;
   procedure FormPaint(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var

 Form1: TForm1;

implementation

{$R *.dfm}

procedure CreateFern(const w, h: integer); var r, x, y: double;

   tmpx, tmpy: double;
   i: integer;

begin

   x := 0;
   y := 0;
   randomize();
   for i := 0 to 200000 do begin
       r := random(100000000) / 99999989;
       if r <= 0.01 then begin
           tmpx := 0;
           tmpy := 0.16 * y;
       end
       else if r <= 0.08 then begin
           tmpx := 0.2 * x - 0.26 * y;
           tmpy := 0.23 * x + 0.22 * y + 1.6;
       end
       else if r <= 0.15 then begin
           tmpx := -0.15 * x + 0.28 * y;
           tmpy := 0.26 * x + 0.24 * y + 0.44;
       end
       else begin
           tmpx := 0.85 * x + 0.04 * y;
           tmpy := -0.04 * x + 0.85 * y + 1.6;
       end;
       x := tmpx;
       y := tmpy;
       Form1.PaintBox1.Canvas.Pixels[round(w / 2 + x * w / 11), round(h - y * h / 11)] := clGreen;
   end;

end;

procedure TForm1.FormPaint(Sender: TObject); begin

   CreateFern(Form1.ClientWidth, Form1.ClientHeight);

end;

end.</lang>

FreeBASIC

<lang freebasic>' version 10-10-2016 ' compile with: fbc -s console

Sub barnsley(height As UInteger)

 Dim As Double x, y, xn, yn
 Dim As Double f = height / 10.6
 Dim As UInteger offset_x = height \ 4 - height \ 40
 Dim As UInteger n, r
 ScreenRes height \ 2, height, 32
 For n = 1 To height * 50
   r = Int(Rnd * 100)      ' f from 0 to 99
   Select Case As Const r
     Case 0 To 84
       xn  =  0.85 * x + 0.04 * y
       yn  = -0.04 * x + 0.85 * y + 1.6
     Case 85 To 91
       xn  = 0.2  * x - 0.26 * y
       yn  = 0.23 * x + 0.22 * y + 1.6
     Case 92 To 98
       xn  = -0.15 * x + 0.28 * y
       yn  =  0.26 * x + 0.24 * y + 0.44
     Case Else
       xn = 0
       yn = 0.16 * y
   End Select
   x = xn : y = yn
   PSet( offset_x + x * f, height - y * f), RGB(0, 255, 0)
 Next

' remove comment (') in next line to save window as .bmp file ' BSave "barnsley_fern_" + Str(height) + ".bmp", 0

End Sub


' ------=< MAIN >=------

' adjustable window height ' call the subroutine with the height you want ' it's possible to have a window that's large than your display

barnsley(800)


' empty keyboard buffer While Inkey <> "" : Wend Windowtitle "hit any key to end program" Sleep End</lang>

G'MIC

<lang c>

  1. Put this into a new file 'fern.gmic' and invoke it from the command line, like this:
  2. $ gmic fern.gmic -barnsley_fern

barnsley_fern :

 1024,2048
 -skip {"
     f1 = [ 0,0,0,0.16 ];           g1 = [ 0,0 ];
     f2 = [ 0.2,-0.26,0.23,0.22 ];  g2 = [ 0,1.6 ];
     f3 = [ -0.15,0.28,0.26,0.24 ]; g3 = [ 0,0.44 ];
     f4 = [ 0.85,0.04,-0.04,0.85 ]; g4 = [ 0,1.6 ];
     xy = [ 0,0 ];
     for (n = 0, n<2e6, ++n,
       r = u(100);
       xy = r<=1?((f1**xy)+=g1):
            r<=8?((f2**xy)+=g2):
            r<=15?((f3**xy)+=g3):
                  ((f4**xy)+=g4);
       uv = xy*200 + [ 480,0 ];
       uv[1] = h - uv[1];
       I(uv) = 0.7*I(uv) + 0.3*255;
     )"}
 -r 40%,40%,1,1,2

</lang>

Go

<lang go>package main

import (

   "image"
   "image/color"
   "image/draw"
   "image/png"
   "log"
   "math/rand"
   "os"

)

// values from WP const (

   xMin = -2.1820
   xMax = 2.6558
   yMin = 0.
   yMax = 9.9983

)

// parameters var (

   width = 200
   n     = int(1e6)
   c     = color.RGBA{34, 139, 34, 255} // forest green

)

func main() {

   dx := xMax - xMin
   dy := yMax - yMin
   fw := float64(width)
   fh := fw * dy / dx
   height := int(fh)
   r := image.Rect(0, 0, width, height)
   img := image.NewRGBA(r)
   draw.Draw(img, r, &image.Uniform{color.White}, image.ZP, draw.Src)
   var x, y float64
   plot := func() {
       // transform computed float x, y to integer image coordinates
       ix := int(fw * (x - xMin) / dx)
       iy := int(fh * (yMax - y) / dy)
       img.SetRGBA(ix, iy, c)
   }
   plot()
   for i := 0; i < n; i++ {
       switch s := rand.Intn(100); {
       case s < 85:
           x, y =
               .85*x+.04*y,
               -.04*x+.85*y+1.6
       case s < 85+7:
           x, y =
               .2*x-.26*y,
               .23*x+.22*y+1.6
       case s < 85+7+7:
           x, y =
               -.15*x+.28*y,
               .26*x+.24*y+.44
       default:
           x, y = 0, .16*y
       }
       plot()
   }
   // write img to png file
   f, err := os.Create("bf.png")
   if err != nil {
       log.Fatal(err)
   }
   if err := png.Encode(f, img); err != nil {
       log.Fatal(err)
   }

}</lang>

Haskell

<lang haskell>import Data.List (scanl') import Diagrams.Backend.Rasterific.CmdLine import Diagrams.Prelude import System.Random

type Pt = (Double, Double)

-- Four affine transformations used to produce a Barnsley fern. f1, f2, f3, f4 :: Pt -> Pt f1 (x, y) = ( 0, 0.16 * y) f2 (x, y) = ( 0.85 * x + 0.04 * y , -0.04 * x + 0.85 * y + 1.60) f3 (x, y) = ( 0.20 * x - 0.26 * y , 0.23 * x + 0.22 * y + 1.60) f4 (x, y) = (-0.15 * x + 0.28 * y , 0.26 * x + 0.24 * y + 0.44)

-- Given a random number in [0, 1) transform an initial point by a randomly -- chosen function. func :: Pt -> Double -> Pt func p r | r < 0.01 = f1 p

        | r < 0.86  = f2 p
        | r < 0.93  = f3 p
        | otherwise = f4 p

-- Using a sequence of uniformly distributed random numbers in [0, 1) return -- the same number of points in the fern. fern :: [Double] -> [Pt] fern = scanl' func (0, 0)

-- Given a supply of random values and a count, generate a diagram of a fern -- composed of that number of points. drawFern :: [Double] -> Int -> Diagram B drawFern rs n = frame 0.5 . diagramFrom . take n $ fern rs

 where diagramFrom = flip atPoints (repeat dot) . map p2
       dot = circle 0.005 # lc green

-- To generate a PNG image of a fern, call this program like: -- -- fern -o fern.png -w 640 -h 640 50000 -- -- where the arguments specify the width, height and number of points in the -- image. main :: IO () main = do

 rand <- getStdGen
 mainWith $ drawFern (randomRs (0, 1) rand)</lang>

J

 

<lang j>require 'plot'

f=: |: 0 ". ];._2 noun define

 0     0     0    0.16   0 0      0.01
 0.85 -0.04  0.04 0.85   0 1.60   0.85
 0.20  0.23 -0.26 0.22   0 1.60   0.07
-0.15  0.26  0.28 0.24   0 0.44   0.07

)

fm=: {&(|: 2 2 $ f) fa=: {&(|: 4 5 { f) prob=: (+/\ 6 { f) I. ?@0:

ifs=: (fa@] + fm@] +/ .* [) prob getPoints=: ifs^:(<200000) plotFern=: 'dot;grids 0 0;tics 0 0;labels 0 0;color green' plot ;/@|:

  plotFern getPoints 0 0</lang>

Java

 
Works with: Java version 8

<lang java>import java.awt.*; import java.awt.image.BufferedImage; import javax.swing.*;

public class BarnsleyFern extends JPanel {

   BufferedImage img;
   public BarnsleyFern() {
       final int dim = 640;
       setPreferredSize(new Dimension(dim, dim));
       setBackground(Color.white);
       img = new BufferedImage(dim, dim, BufferedImage.TYPE_INT_ARGB);
       createFern(dim, dim);
   }
   void createFern(int w, int h) {
       double x = 0;
       double y = 0;
       for (int i = 0; i < 200_000; i++) {
           double tmpx, tmpy;
           double r = Math.random();
           if (r <= 0.01) {
               tmpx = 0;
               tmpy = 0.16 * y;
           } else if (r <= 0.08) {
               tmpx = 0.2 * x - 0.26 * y;
               tmpy = 0.23 * x + 0.22 * y + 1.6;
           } else if (r <= 0.15) {
               tmpx = -0.15 * x + 0.28 * y;
               tmpy = 0.26 * x + 0.24 * y + 0.44;
           } else {
               tmpx = 0.85 * x + 0.04 * y;
               tmpy = -0.04 * x + 0.85 * y + 1.6;
           }
           x = tmpx;
           y = tmpy;
           img.setRGB((int) Math.round(w / 2 + x * w / 11),
                   (int) Math.round(h - y * h / 11), 0xFF32CD32);
       }
   }
   @Override
   public void paintComponent(Graphics gg) {
       super.paintComponent(gg);
       Graphics2D g = (Graphics2D) gg;
       g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);
       g.drawImage(img, 0, 0, null);
   }
   public static void main(String[] args) {
       SwingUtilities.invokeLater(() -> {
           JFrame f = new JFrame();
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.setTitle("Barnsley Fern");
           f.setResizable(false);
           f.add(new BarnsleyFern(), BorderLayout.CENTER);
           f.pack();
           f.setLocationRelativeTo(null);
           f.setVisible(true);
       });
   }

}</lang>

JavaScript

Translation of: PARI/GP
File:BarnsleyFernjs.png
Output BarnsleyFernjs.png

<lang javascript> // Barnsley fern fractal //6/17/16 aev function pBarnsleyFern(canvasId,lim) {

 // DCLs
 var canvas = document.getElementById(canvasId);
 var ctx = canvas.getContext("2d");
 var w = canvas.width;
 var h = canvas.height;
 var x=0.,y=0.,xw=0.,yw=0.,r;
 // Like in PARI/GP: return random number 0..max-1
 function randgp(max) {return Math.floor(Math.random()*max)}
 // Clean canvas
 ctx.fillStyle="white"; ctx.fillRect(0,0,w,h);
 // MAIN LOOP
 for(var i=0; i<lim; i++) {
   r=randgp(100);
   if (r<=1) {xw=0;yw=0.16*y;}
   else if (r<=8) {xw=0.2*x-0.26*y;yw=0.23*x+0.22*y+1.6;}
   else if (r<=15) {xw=-0.15*x+0.28*y;yw=0.26*x+0.24*y+0.44;}
   else {xw=0.85*x+0.04*y;yw=-0.04*x+0.85*y+1.6;}
   x=xw;y=yw; ctx.fillStyle="green"; ctx.fillRect(x*50+260,-y*50+540,1,1);
 }//fend i

} </lang> Executing: <lang html> <html>

<head><script src="BarnsleyFern.js"></script></head>
<body onload="pBarnsleyFern('canvas', 100000)">


Barnsley fern fractal

  <canvas id="canvas" width="540" height="540" style="border: 2px inset;"></canvas>
</body>

</html> </lang>

Output:
Page with BarnsleyFernjs.png

Nim

<lang Nim> import nimPNG, random

randomize()

const

 width = 640
 height = 640
 minX = -2.1815
 maxX = 2.6556
 minY = 0.0
 maxY = 9.9982
 iterations = 1_000_000

var img: array[width * height * 3, char]

proc floatToPixel(x,y:float): tuple[a:int,b:int] =

 var px = abs(x - minX) / abs(maxX - minX)
 var py = abs(y - minY) / abs(maxY - minY)
 var a:int = (int)(width * px)
 var b:int = (int)(height * py)
 a = a.clamp(0, width-1)
 b = b.clamp(0, height-1)
 # flip the y axis
 (a:a,b:height-b-1)

proc pixelToOffset(a,b: int): int =

 b * width * 3 + a * 3

proc toString(a: openArray[char]): string =

 result = newStringOfCap(a.len)
 for ch in items(a):
   result.add(ch)

proc drawPixel(x,y:float) =

 var (a,b) = floatToPixel(x,y)
 var offset = pixelToOffset(a,b)
 #img[offset] = 0 # red channel
 img[offset+1] = char(250) # green channel
 #img[offset+2] = 0 # blue channel
  1. main

var x, y: float = 0.0

for i in 1..iterations:

 var r = random(101)
 var nx, ny: float
 if r <= 85:
   nx = 0.85 * x + 0.04 * y
   ny = -0.04 * x + 0.85 * y + 1.6
 elif r <= 85 + 7:
   nx = 0.2 * x - 0.26 * y
   ny = 0.23 * x + 0.22 * y + 1.6
 elif r <= 85 + 7 + 7:
   nx = -0.15 * x + 0.28 * y
   ny = 0.26 * x + 0.24 * y + 0.44
 else:
   nx = 0
   ny = 0.16 * y
 x = nx
 y = ny
 drawPixel(x,y)

discard savePNG24("fern.png",img.toString, width, height) </lang>

PARI/GP

Translation of: zkl
Works with: PARI/GP version 2.7.4 and above
File:BarnsleyFern.png
Output BarnsleyFern.png

<lang parigp> \\ Barnsley fern fractal \\ 6/17/16 aev pBarnsleyFern(size,lim)={ my(X=List(),Y=X,x=y=xw=yw=0.0,r); print(" *** Barnsley Fern, size=",size," lim=",lim); plotinit(0); plotcolor(0,6); \\green plotscale(0, -3,3, 0,10); plotmove(0, 0,0); for(i=1, lim,

 r=random(100);
 if(r<=1, xw=0;yw=0.16*y,
   if(r<=8, xw=0.2*x-0.26*y;yw=0.23*x+0.22*y+1.6,
     if(r<=15, xw=-0.15*x+0.28*y;yw=0.26*x+0.24*y+0.44,
       xw=0.85*x+0.04*y;yw=-0.04*x+0.85*y+1.6)));
 x=xw;y=yw; listput(X,x); listput(Y,y);

);\\fend i plotpoints(0,Vec(X),Vec(Y)); plotdraw([0,-3,-0]); } {\\ Executing: pBarnsleyFern(530,100000); \\ BarnsleyFern.png } </lang>

Output:
> pBarnsleyFern(530,100000);  \\ BarnsleyFern.png
 *** Barnsley Fern, size=530 lim=100000

Perl

 

<lang perl>use Imager;

my $w = 640; my $h = 640;

my $img = Imager->new(xsize => $w, ysize => $h, channels => 3); my $green = Imager::Color->new('#00FF00');

my ($x, $y) = (0, 0);

foreach (1 .. 2e5) {

 my $r = rand(100);
 ($x, $y) = do {
   if    ($r <=  1) { ( 0.00 * $x - 0.00 * $y,  0.00 * $x + 0.16 * $y + 0.00) }
   elsif ($r <=  8) { ( 0.20 * $x - 0.26 * $y,  0.23 * $x + 0.22 * $y + 1.60) }
   elsif ($r <= 15) { (-0.15 * $x + 0.28 * $y,  0.26 * $x + 0.24 * $y + 0.44) }
   else             { ( 0.85 * $x + 0.04 * $y, -0.04 * $x + 0.85 * $y + 1.60) }
 };
 $img->setpixel(x => $w / 2 + $x * 60, y => $y * 60, color => $green);

}

$img->flip(dir => 'v'); $img->write(file => 'barnsleyFern.png');</lang>

Perl 6

Works with: Rakudo version 2016.03
Translation of: Perl
 

<lang perl6>use Image::PNG::Portable;

my ($w, $h) = (640, 640);

my $png = Image::PNG::Portable.new: :width($w), :height($h);

my ($x, $y) = (0, 0);

for ^2e5 {

   my $r = 100.rand;
   ($x, $y) = do given $r {
       when  $r <=  1 { (                     0,              0.16 * $y       ) }
       when  $r <=  8 { ( 0.20 * $x - 0.26 * $y,  0.23 * $x + 0.22 * $y + 1.60) }
       when  $r <= 15 { (-0.15 * $x + 0.28 * $y,  0.26 * $x + 0.24 * $y + 0.44) }
       default        { ( 0.85 * $x + 0.04 * $y, -0.04 * $x + 0.85 * $y + 1.60) }
   };
   $png.set(($w / 2 + $x * 60).Int, $h - ($y * 60).Int, 0, 255, 0);

}

$png.write: 'Barnsley-fern-perl6.png';</lang>

Phix

This file is included in the distro as demo\rosetta\BarnsleyFern.exw

File:PhixBarnsleyFern.png

<lang Phix>include ..\pGUI\pGUI.e

Ihandle dlg, canvas cdCanvas cddbuffer, cdcanvas

function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/) atom {x,y,r} @= 0 integer {width, height} = IupGetIntInt(canvas, "DRAWSIZE")

   cdCanvasActivate(cddbuffer)
   for i=1 to 20000 do
       r = rand(100)
       {x, y} = iff(r<=1? {             0,        0.16*y     } :
                iff(r<=8? { 0.20*x-0.26*y, 0.23*x+0.22*y+1.60} :
                iff(r<=15?{-0.15*x+0.28*y, 0.26*x+0.24*y+0.44} :
                          { 0.85*x+0.04*y,-0.04*x+0.85*y+1.60})))
       cdCanvasPixel(cddbuffer, width/2+x*60, y*60, #00FF00) 
   end for
   cdCanvasFlush(cddbuffer)
   return IUP_DEFAULT

end function

function map_cb(Ihandle ih)

   cdcanvas = cdCreateCanvas(CD_IUP, ih)
   cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
   cdCanvasSetBackground(cddbuffer, CD_WHITE)
   cdCanvasSetForeground(cddbuffer, CD_RED)
   return IUP_DEFAULT

end function

function esc_close(Ihandle /*ih*/, atom c)

   if c=K_ESC then return IUP_CLOSE end if
   return IUP_CONTINUE

end function

procedure main()

   IupOpen("..\\pGUI\\")
   canvas = IupCanvas(NULL)
   IupSetAttribute(canvas, "RASTERSIZE", "340x620") -- initial size
   IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
   dlg = IupDialog(canvas)
   IupSetAttribute(dlg, "TITLE", "Barnsley Fern")
   IupSetCallback(dlg, "K_ANY",     Icallback("esc_close"))
   IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
   IupMap(dlg)
   IupSetAttribute(canvas, "RASTERSIZE", NULL) -- release the minimum limitation
   IupShowXY(dlg,IUP_CENTER,IUP_CENTER)
   IupMainLoop()
   IupClose()

end procedure

main()</lang>

Processing

<lang java>void setup() {

 size(640, 640);
 background(0, 0, 0);

}

float x = 0; float y = 0;

void draw() {

 for (int i = 0; i < 100000; i++) {
   float xt = 0;
   float yt = 0;
   float r = random(100);
   if (r <= 1) {
     xt = 0;
     yt = 0.16*y;
   } else if (r <= 8) {
     xt = 0.20*x - 0.26*y;
     yt = 0.23*x + 0.22*y + 1.60;
   } else if (r <= 15) {
     xt = -0.15*x + 0.28*y;
     yt =  0.26*x + 0.24*y + 0.44;
   } else {
     xt =  0.85*x + 0.04*y;
     yt = -0.04*x + 0.85*y + 1.60;
   }
   x = xt;
   y = yt;
   int m = round(width/2 + 60*x);
   int n = height-round(60*y);
   set(m, n, #00ff00);
 }
 noLoop();

}</lang>


Python

<lang Python>

import random from PIL import Image


class BarnsleyFern(object):

   def __init__(self, img_width, img_height, paint_color=(0, 150, 0),
                bg_color=(255, 255, 255)):
       self.img_width, self.img_height = img_width, img_height
       self.paint_color = paint_color
       self.x, self.y = 0, 0
       self.age = 0
       self.fern = Image.new('RGB', (img_width, img_height), bg_color)
       self.pix = self.fern.load()
       self.pix[self.scale(0, 0)] = paint_color
   def scale(self, x, y):
       h = (x + 2.182)*(self.img_width - 1)/4.8378
       k = (9.9983 - y)*(self.img_height - 1)/9.9983
       return h, k
   def transform(self, x, y):
       rand = random.uniform(0, 100)
       if rand < 1:
           return 0, 0.16*y
       elif 1 <= rand < 86:
           return 0.85*x + 0.04*y, -0.04*x + 0.85*y + 1.6
       elif 86 <= rand < 93:
           return 0.2*x - 0.26*y, 0.23*x + 0.22*y + 1.6
       else:
           return -0.15*x + 0.28*y, 0.26*x + 0.24*y + 0.44
   def iterate(self, iterations):
       for _ in range(iterations):
           self.x, self.y = self.transform(self.x, self.y)
           self.pix[self.scale(self.x, self.y)] = self.paint_color
       self.age += iterations

fern = BarnsleyFern(500, 500) fern.iterate(1000000) fern.fern.show()

</lang>

R

Translation of: PARI/GP
File:BarnsleyFernR.png
Output BarnsleyFernR.png

<lang r>

    1. pBarnsleyFern(fn, n, clr, ttl, psz=600): Plot Barnsley fern fractal.
    2. Where: fn - file name; n - number of dots; clr - color; ttl - plot title;
    3. psz - picture size.
    4. 7/27/16 aev

pBarnsleyFern <- function(fn, n, clr, ttl, psz=600) {

 cat(" *** START:", date(), "n=", n, "clr=", clr, "psz=", psz, "\n");
 cat(" *** File name -", fn, "\n");
 pf = paste0(fn,".png"); # pf - plot file name
 A1 <- matrix(c(0,0,0,0.16,0.85,-0.04,0.04,0.85,0.2,0.23,-0.26,0.22,-0.15,0.26,0.28,0.24), ncol=4, nrow=4, byrow=TRUE);
 A2 <- matrix(c(0,0,0,1.6,0,1.6,0,0.44), ncol=2, nrow=4, byrow=TRUE);
 P <- c(.01,.85,.07,.07);
 # Creating matrices M1 and M2.
 M1=vector("list", 4); M2 = vector("list", 4);
 for (i in 1:4) {
   M1i <- matrix(c(A1[i,1:4]), nrow=2);
   M2i <- matrix(c(A2[i, 1:2]), nrow=2);
 }
 x <- numeric(n); y <- numeric(n);
 x[1] <- y[1] <- 0;
 for (i in 1:(n-1)) {
   k <- sample(1:4, prob=P, size=1);
   M <- as.matrix(M1k);
   z <- M%*%c(x[i],y[i]) + M2k; 
   x[i+1] <- z[1]; y[i+1] <- z[2];
 }
 plot(x, y, main=ttl, axes=FALSE, xlab="", ylab="", col=clr, cex=0.1);
 # Writing png-file
 dev.copy(png, filename=pf,width=psz,height=psz);
 # Cleaning 
 dev.off(); graphics.off();
 cat(" *** END:",date(),"\n");

}

    1. Executing:

pBarnsleyFern("BarnsleyFernR", 100000, "dark green", "Barnsley Fern Fractal", psz=600) </lang>

Output:
> pBarnsleyFern("BarnsleyFernR", 100000, "dark green", "Barnsley Fern Fractal", psz=600)
 *** START: Wed Jul 27 13:50:49 2016 n= 1e+05 clr= dark green psz= 600 
 *** File name - BarnsleyFernR 
 *** END: Wed Jul 27 13:50:56 2016 
+ BarnsleyFernR.png file

Racket

<lang racket>#lang racket

(require racket/draw)

(define fern-green (make-color #x32 #xCD #x32 0.66))

(define (fern dc n-iterations w h)

 (for/fold ((x #i0) (y #i0))
           ((i n-iterations))
   (define-values (x′ y′)
     (let ((r (random)))
       (cond
         [(<= r 0.01) (values 0
                              (* y 16/100))]
         [(<= r 0.08) (values (+ (* x 20/100) (* y -26/100))
                              (+ (* x 23/100) (* y 22/100) 16/10))]
         [(<= r 0.15) (values (+ (* x -15/100) (* y 28/100))
                              (+ (* x 26/100) (* y 24/100) 44/100))]
         [else (values (+ (* x 85/100) (* y 4/100))
                       (+ (* x -4/100) (* y 85/100) 16/10))])))
   (define px (+ (/ w 2) (* x w 1/11)))
   (define py (- h (* y h 1/11)))
   (send dc set-pixel (exact-round px) (exact-round py) fern-green)                   
   (values x′ y′)))


(define bmp (make-object bitmap% 640 640 #f #t 2))

(fern (new bitmap-dc% [bitmap bmp]) 200000 640 640)

bmp (send bmp save-file "images/barnsley-fern.png" 'png)</lang>

Ring

<lang Ring>

Load "guilib.ring"

/*

+---------------------------------------------------------------------------
+        Program Name : Draw Barnsley Fern
+        Date         : 2016.06.12
+        Author       : Bert Mariani
+        Purpose      : Draw Fern using Quadratic Equation and Random Number
+---------------------------------------------------------------------------
  • /
      1. -------------------------------
      2. DRAW CHART size 400 x 500
      3. -------------------------------


New qapp { win1 = new qwidget() { ### Position and Size on Screen setwindowtitle("Drawing using QPainter") setgeometry( 10, 25, 400, 500)

### Draw within this Win Box label1 = new qlabel(win1) { ### Label Position and Size setgeometry(10, 10, 400, 500) settext(" ") }

buttonFern = new qpushbutton(win1) { ### Button DrawFern setgeometry(10, 10, 80, 20) settext("Draw Fern") setclickevent("DrawFern()") ### Call DRAW function }

show() } exec() }

      1. ------------------------
      2. FUNCTIONS
      3. ------------------------

Func DrawFern p1 = new qpicture()

colorGreen = new qcolor() { setrgb(0,255,0,255) } penGreen = new qpen() { setcolor(colorGreen) setwidth(1) }

new qpainter() { begin(p1) setpen(penGreen)

###------------------------------------- ### Quadratic equation matrix of arrays

a = [ 0, 0.85, 0.2, -0.15 ] b = [ 0, 0.04, -0.26, 0.28 ] c = [ 0, -0.04, 0.23, 0.26 ] d = [ 0.16, 0.85, 0.22, 0.24 ] e = [ 0, 0, 0, 0 ] f = [ 0, 1.6, 1.6, 0.44 ]

### Initialize x, y points

xf = 0.0 yf = 0.0

### Size of output screen

MaxX = 400 MaxY = 500 MaxIterations = MaxY * 200 Count = 0

###------------------------------------------------

while ( Count <= MaxIterations )

### NOTE *** RING *** starts at Index 1, ### Do NOT use Random K=0 result

k = random() % 100 k = k +1

### if (k = 0) k = 1 ok ### Do NOT use

if ((k > 0) and (k <= 85)) k = 2 ok if ((k > 85) and (k <= 92)) k = 3 ok if (k > 92) k = 4 ok

TempX = ( a[k] * xf ) + ( b[k] * yf ) + e[k] TempY = ( c[k] * xf ) + ( d[k] * yf ) + f[k]

xf = TempX yf = TempY

if( (Count >= MaxIterations) or (Count != 0) ) xPoint = (floor(xf * MaxY / 11) + floor(MaxX / 2)) yPoint = (floor(yf * -MaxY / 11) + MaxY ) drawpoint( xPoint , yPoint ) ok

Count++ end

###----------------------------------------------------

endpaint() }

label1 { setpicture(p1) show() } return

</lang>

Run BASIC

<lang runbasic>maxpoints = 20000 graphic #g, 200, 200

  1. g fill("blue")

FOR n = 1 TO maxpoints p = RND(0)*100 IF p <= 1 THEN nx = 0 ny = 0.16 * y else if p <= 8 THEN nx = 0.2 * x - 0.26 * y ny = 0.23 * x + 0.22 * y + 1.6 else if p <= 15 THEN nx = -0.15 * x + 0.28 * y ny = 0.26 * x + 0.24 * y + 0.44 else nx = 0.85 * x +0.04 * y ny = -0.04 * x +0.85 * y + 1.6 end if x = nx y = ny

  1. g "color green ; set "; x * 17 + 100; " "; y * 17

NEXT n render #g

  1. g "flush"</lang>

SequenceL

Tail-Recursive SequenceL Code:
<lang sequencel>import <Utilities/Math.sl>; import <Utilities/Random.sl>;

transform(p(1), rand) :=

   let
       x := p[1]; y := p[2];
   in
       [0.0, 0.16*y] when rand <= 0.01
   else
       [0.85*x + 0.04*y, -0.04*x + 0.85*y + 1.6] when rand <= 0.86
   else
       [0.2*x - 0.26*y, 0.23*x + 0.22*y + 1.6] when rand <= 0.93
   else
       [-0.15*x + 0.28*y, 0.26*x + 0.24*y + 0.44];
       

barnsleyFern(rand, count, result(2)) :=

   let
       nextRand := getRandom(rand);
       next := transform(result[size(result)], nextRand.value / 2147483647.0);
   in
       result when count <= 0
   else
       barnsleyFern(nextRand.generator, count - 1, result ++ [next]);

scale(p(1), width, height) := [round((p[1] + 2.182) * width / 4.8378),

                              round((9.9983 - p[2]) * height / 9.9983)];
       

entry(seed, count, width, height) :=

   let
       fern := barnsleyFern(seedRandom(seed), count, 0.0,0.0);
   in
       scale(fern, width, height);</lang>

C++ Driver Code:

Library: CImg

<lang c>#include "SL_Generated.h"

  1. include "CImg.h"

using namespace cimg_library;

int main(int argc, char** argv) {

   int threads = 0; if(argc > 1) threads = atoi(argv[1]);
   int width = 300; if(argc > 2) width = atoi(argv[2]);
   int height = 600; if(argc > 3) height = atoi(argv[3]);
   int steps = 10000; if(argc > 4) steps = atoi(argv[4]);
   int seed = 314159; if(argc > 5) seed = atoi(argv[5]);
   
   CImg<unsigned char> visu(width, height, 1, 3, 0);
   Sequence< Sequence<int> > result;
   sl_init(threads);
   sl_entry(seed, steps, width-1, height-1, threads, result);
   
   visu.fill(0);
   for(int i = 1; i <= result.size(); i++)
       visu(result[i][1], result[i][2],1) = 255;
   
   CImgDisplay draw_disp(visu);
   draw_disp.set_title("Barnsley Fern in SequenceL");
   visu.display(draw_disp);
   
   while(!draw_disp.is_closed()) draw_disp.wait();
   sl_done();
   return 0;

}</lang>

Output:

Output Screenshot


Sidef

<lang ruby>require('Imager')

var w = 640 var h = 640

var img = %s<Imager>.new(xsize => w, ysize => h, channels => 3) var green = %s<Imager::Color>.new('#00FF00')

var (x, y) = (0, 0)

for r in (^1e5 -> lazy.map { 100.rand }) {

 (x, y) = (
   if    (r <=  1) { ( 0.00*x - 0.00*y,  0.00*x + 0.16*y + 0.00) }
   elsif (r <=  8) { ( 0.20*x - 0.26*y,  0.23*x + 0.22*y + 1.60) }
   elsif (r <= 15) { (-0.15*x + 0.28*y,  0.26*x + 0.24*y + 0.44) }
   else            { ( 0.85*x + 0.04*y, -0.04*x + 0.85*y + 1.60) }
 )
 img.setpixel(x => w/2 + 60*x, y => 60*y, color => green)

}

img.flip(dir => 'v') img.write(file => 'barnsleyFern.png')</lang>

zkl

 

Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl

Translation of: Java

<lang zkl>fcn barnsleyFern(){

  w,h:=640,640;
  bitmap:=PPM(w+1,h+1,0xFF|FF|FF);  // White background
  x,y, nx,ny:=0.0, 0.0, 0.0, 0.0;
  do(0d100_000){
     r:=(0).random(100);  // [0..100)%
     if     (r<= 1) nx,ny= 0, 		      0.16*y;
     else if(r<= 8) nx,ny= 0.2*x  - 0.26*y,  0.23*x + 0.22*y + 1.6;
     else if(r<=15) nx,ny=-0.15*x + 0.28*y,  0.26*x + 0.24*y + 0.44;
     else           nx,ny= 0.85*x + 0.04*y, -0.04*x + 0.85*y + 1.6;
     x,y=nx,ny;
     bitmap[w/2 + x*60, y*60] = 0x00|FF|00;  // Green dot
  }
  bitmap.writeJPGFile("barnsleyFern.jpg");

}();</lang>

ZX Spectrum Basic

Translation of: zkl

<lang zxbasic>10 REM Fractal Fern 20 PAPER 7: BORDER 7: BRIGHT 1: INK 4: CLS 30 LET maxpoints=20000: LET x=0: LET y=0 40 FOR n=1 TO maxpoints 50 LET p=RND*100 60 IF p<=1 THEN LET nx=0: LET ny=0.16*y: GO TO 100 70 IF p<=8 THEN LET nx=0.2*x-0.26*y: LET ny=0.23*x+0.22*y+1.6: GO TO 100 80 IF p<=15 THEN LET nx=-0.15*x+0.28*y: LET ny=0.26*x+0.24*y+0.44: GO TO 100 90 LET nx=0.85*x+0.04*y: LET ny=-0.04*x+0.85*y+1.6 100 LET x=nx: LET y=ny 110 PLOT x*17+127,y*17 120 NEXT n </lang> It is recommended to run on an emulator that supports running at full speed.