Created
June 6, 2017 11:22
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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