Skip to content

Instantly share code, notes, and snippets.

@ploeh
Created June 6, 2017 11:22
Show Gist options
  • Save ploeh/f3b6099920305a690789eda785719c1e to your computer and use it in GitHub Desktop.
Save ploeh/f3b6099920305a690789eda785719c1e to your computer and use it in GitHub Desktop.
Fractal tree in F#. Our solution from dojo in Copenhagen, 2017-05-30
open System
open System.Drawing
open System.Windows.Forms
// Create a form to display the graphics
let width, height = 500, 500
let form = new Form(Width = width, Height = height)
let box = new PictureBox(BackColor = Color.White, Dock = DockStyle.Fill)
let image = new Bitmap(width, height)
let graphics = Graphics.FromImage(image)
//The following line produces higher quality images,
//at the expense of speed. Uncomment it if you want
//more beautiful images, even if it's slower.
//Thanks to https://twitter.com/AlexKozhemiakin for the tip!
graphics.SmoothingMode <- System.Drawing.Drawing2D.SmoothingMode.HighQuality
let brush = new SolidBrush(Color.FromArgb(0, 0, 0))
box.Image <- image
form.Controls.Add(box)
// Compute the endpoint of a line
// starting at x, y, going at a certain angle
// for a certain length.
let endpoint x y angle length =
x + length * cos angle,
y + length * sin angle
let flip x = (float)height - x
// Utility function: draw a line of given width,
// starting from x, y
// going at a certain angle, for a certain length.
let drawLine (target : Graphics) (brush : Brush)
(x : float) (y : float)
(angle : float) (length : float) (width : float) =
let x_end, y_end = endpoint x y angle length
let origin = PointF((single)x, (single)(y |> flip))
let destination = PointF((single)x_end, (single)(y_end |> flip))
let pen = new Pen(brush, (single)width)
target.DrawLine(pen, origin, destination)
let draw = drawLine graphics brush
let pi = Math.PI
type Line = { X : float; Y : float; Angle : float; Length : float; Width : float }
let drawL line = draw line.X line.Y line.Angle line.Length line.Width
type Parameters = { LeftAngle : float; RightAngle : float; ShrinkFactor : float }
let getBranches p line =
let x, y = endpoint line.X line.Y line.Angle line.Length
let left = {
X = x
Y = y
Angle = (pi * (line.Angle / pi + p.LeftAngle))
Length = line.Length * p.ShrinkFactor
Width = line.Width * p.ShrinkFactor }
let right = {
X = x
Y = y
Angle = (pi * (line.Angle / pi - p.RightAngle))
Length = line.Length * p.ShrinkFactor
Width = line.Width * p.ShrinkFactor }
[left; right]
let rec createTree counter p trunk =
if counter > 0
then
let branches = getBranches p trunk
trunk :: List.collect (createTree (counter - 1) p) branches
else [trunk]
{ X = 250.; Y = 50.; Angle = (pi*(0.5)); Length = 100.; Width = 4. }
|> createTree 10 { LeftAngle = 0.1; RightAngle = 0.1; ShrinkFactor = 0.8 }
|> List.iter drawL
form.ShowDialog()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment