Fractal tree
You are encouraged to solve this task according to the task description, using any language you may know.
Generate and draw a fractal tree.
To draw a fractal tree is simple:
- Draw the trunk
- At the end of the trunk, split by some angle and draw two branches
- Repeat at the end of each branch until a sufficient level of branching is reached
C
or
<lang c>#include <SDL/SDL.h>
- ifdef WITH_CAIRO
- include <cairo.h>
- else
- include <SDL/sge.h>
- endif
- include <cairo.h>
- include <stdlib.h>
- include <time.h>
- include <math.h>
- ifdef WITH_CAIRO
- define PI 3.1415926535
- endif
- define SIZE 800 // determines size of window
- define SCALE 5 // determines how quickly branches shrink (higher value means faster shrinking)
- define BRANCHES 14 // number of branches
- define ROTATION_SCALE 0.75 // determines how slowly the angle between branches shrinks (higher value means slower shrinking)
- define INITIAL_LENGTH 50 // length of first branch
double rand_fl(){
return (double)rand() / (double)RAND_MAX;
}
void draw_tree(SDL_Surface * surface, double offsetx, double offsety,
double directionx, double directiony, double size, double rotation, int depth) {
- ifdef WITH_CAIRO
cairo_surface_t *surf = cairo_image_surface_create_for_data( surface->pixels, CAIRO_FORMAT_RGB24,
surface->w, surface->h, surface->pitch );
cairo_t *ct = cairo_create(surf);
cairo_set_line_width(ct, 1); cairo_set_source_rgba(ct, 0,0,0,1); cairo_move_to(ct, (int)offsetx, (int)offsety); cairo_line_to(ct, (int)(offsetx + directionx * size), (int)(offsety + directiony * size)); cairo_stroke(ct);
- else
sge_AALine(surface, (int)offsetx, (int)offsety, (int)(offsetx + directionx * size), (int)(offsety + directiony * size), SDL_MapRGB(surface->format, 0, 0, 0));
- endif
if (depth > 0){ // draw left branch draw_tree(surface, offsetx + directionx * size, offsety + directiony * size, directionx * cos(rotation) + directiony * sin(rotation), directionx * -sin(rotation) + directiony * cos(rotation), size * rand_fl() / SCALE + size * (SCALE - 1) / SCALE, rotation * ROTATION_SCALE, depth - 1); // draw right branch draw_tree(surface, offsetx + directionx * size, offsety + directiony * size, directionx * cos(-rotation) + directiony * sin(-rotation), directionx * -sin(-rotation) + directiony * cos(-rotation), size * rand_fl() / SCALE + size * (SCALE - 1) / SCALE, rotation * ROTATION_SCALE, depth - 1); }
}
void render(SDL_Surface * surface){
SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, 255, 255, 255)); draw_tree(surface, surface->w / 2.0, surface->h - 10.0, 0.0, -1.0, INITIAL_LENGTH, PI / 8, BRANCHES); SDL_UpdateRect(surface, 0, 0, 0, 0);
}
int main(){
SDL_Surface * screen; SDL_Event evt; SDL_Init(SDL_INIT_VIDEO); srand((unsigned)time(NULL)); screen = SDL_SetVideoMode(SIZE, SIZE, 32, SDL_HWSURFACE); render(screen); while(1){ if (SDL_PollEvent(&evt)){ if(evt.type == SDL_QUIT) break; } SDL_Delay(1); } SDL_Quit(); return 0;
}</lang>
Java
<lang java>import java.awt.Color; import java.awt.Graphics; import javax.swing.JFrame;
public class FractalTree extends JFrame {
private final double DEG_TO_RAD = Math.PI / 180.0;
public FractalTree() { super("Fractal Tree"); setBounds(100, 100, 800, 600); setResizable(false); setDefaultCloseOperation(EXIT_ON_CLOSE); }
private void drawTree(Graphics g, int x1, int y1, double angle, int depth) { if (depth == 0) return; int x2 = x1 + (int) (Math.cos(angle * DEG_TO_RAD) * depth * 10.0); int y2 = y1 + (int) (Math.sin(angle * DEG_TO_RAD) * depth * 10.0); g.drawLine(x1, y1, x2, y2); drawTree(g, x2, y2, angle - 20, depth - 1); drawTree(g, x2, y2, angle + 20, depth - 1); }
@Override public void paint(Graphics g) { g.setColor(Color.BLACK); drawTree(g, 400, 500, -90, 9); }
public static void main(String[] args) { new FractalTree().setVisible(true); }
}</lang>
Logo
<lang logo>to tree :depth :length :scale :angle
if :depth=0 [stop] setpensize round :depth/2 forward :length right :angle tree :depth-1 :length*:scale :scale :angle left 2*:angle tree :depth-1 :length*:scale :scale :angle right :angle back :length
end
clearscreen tree 10 80 0.7 30</lang>
OCaml
<lang ocaml>#directory "+cairo"
- load "bigarray.cma"
- load "cairo.cma"
let img_name = "/tmp/fractree.png" let width = 480 let height = 640
let level = 9 let line_width = 4.0
let color = (1.0, 0.5, 0.0)
let pi = 4.0 *. atan 1.0
let angle_split = pi *. 0.12 let angle_rand = pi *. 0.12
let () =
Random.self_init(); let surf = Cairo.image_surface_create Cairo.FORMAT_RGB24 ~width ~height in let ctx = Cairo.create surf in Cairo.set_antialias ctx Cairo.ANTIALIAS_SUBPIXEL; Cairo.set_line_cap ctx Cairo.LINE_CAP_ROUND;
let draw_line (x,y) (dx,dy) = Cairo.move_to ctx x (float height -. y); Cairo.line_to ctx dx (float height -. dy); Cairo.stroke ctx; in let set_color (r,g,b) v = Cairo.set_source_rgb ctx ~red:(r *. v) ~green:(g *. v) ~blue:(b *. v); in let trans_pos (x,y) len angle = let _x = cos angle and _y = sin angle in (x +. (_x *. len), y +. (_y *. len)) in
let rec loop ~level ~pos ~line_width ~line_len ~angle ~angle_split ~angle_rand ~intc = if level > 0 then begin (* draw the current segment *) Cairo.set_line_width ctx line_width; set_color color intc; let pos_to = trans_pos pos line_len angle in draw_line pos pos_to; (* evolution of the parameters *) let line_width = line_width *. 0.8 and line_len = line_len *. 0.62 and angle_split = angle_split *. 1.02 and angle_rand = angle_rand *. 1.02 and intc = intc *. 0.9 in let next_loop = loop ~level:(pred level) ~pos:pos_to ~intc ~line_width ~line_len ~angle_split ~angle_rand in (* split *) let angle_left = angle +. angle_split +. Random.float angle_rand and angle_right = angle -. angle_split -. Random.float angle_rand in next_loop ~angle:angle_left; next_loop ~angle:angle_right end in
let pos = (float width *. 0.5, float height *. 0.1) and line_len = float height *. 0.3 in loop ~level ~pos ~angle:(pi /. 2.0) ~angle_split ~angle_rand ~line_width ~line_len ~intc:1.0;
Cairo_png.surface_write_to_file surf img_name (*Cairo_png.surface_write_to_channel surf stdout*)</lang>
Perl
using the GD::Simple module. <lang perl>use GD::Simple;
my ($width, $height) = (1000,1000); # image dimension my $scale = 6/10; # branch scale relative to trunk my $length = 400; # trunk size
my $img = GD::Simple->new($width,$height); $img->fgcolor('black'); $img->penSize(1,1);
tree($width/2, $height, $length, 270);
print $img->png;
sub tree
{
my ($x, $y, $len, $angle) = @_;
return if $len < 1;
$img->moveTo($x,$y); $img->angle($angle); $img->line($len);
($x, $y) = $img->curPos();
tree($x, $y, $len*$scale, $angle+35); tree($x, $y, $len*$scale, $angle-35);
}</lang>
PostScript
<lang postscript>%!PS %%BoundingBox: 0 0 300 300 %%EndComments /origstate save def /ld {load def} bind def /m /moveto ld /g /setgray ld /t /translate ld /r /rotate ld /l /lineto ld /rl /rlineto ld /s /scale ld %%EndProlog /PerturbateAngle {} def /PerturbateLength {} def % ** To add perturbations, define properly PerturbateAngle and PerturbateLength, e.g. % /PerturbateAngle {realtime 20 mod realtime 2 mod 1 eq {add} {sub} ifelse} def % /PerturbateLength {realtime 10 mod 100 div realtime 2 mod 1 eq {add} {sub} ifelse} def /fractree { % [INITLENGTH, SPLIT, SFACTOR, BRANCHES]
dup 3 get 0 gt { 0 0 m dup 0 get 0 exch l gsave dup 0 get 0 exch t dup 1 get PerturbateAngle r dup 2 get dup PerturbateLength s dup aload pop 1 sub 4 array astore fractree stroke grestore gsave dup 0 get 0 exch t dup 1 get neg PerturbateAngle r dup 2 get dup PerturbateLength s dup aload pop 1 sub 4 array astore fractree stroke grestore } if pop
} def % /BRANCHES 14 def /INITLENGTH 50 def /SPLIT 35 def /SFACTOR .75 def % % BB check %0 0 m 300 0 rl 0 300 rl -300 0 rl closepath stroke % 0 g 150 0 t [INITLENGTH SPLIT SFACTOR BRANCHES] fractree stroke % showpage origstate restore %%EOF</lang>
POV-Ray
<lang povray>#include "colors.inc"
- include "transforms.inc"
- declare CamLoc = <0, 5, 0>;
- declare CamLook = <0,0,0>;
camera {
location CamLoc look_at CamLook rotate y*90
}
light_source {
CamLoc color White
}
- declare Init_Height = 10;
- declare Spread_Ang = 35;
- declare Branches = 14;
- declare Scaling_Factor = 0.75;
- macro Stick(P0, P1)
cylinder { P0, P1, 0.02 texture { pigment { Green } } }
- end
- macro FractalTree(O, D, S, R, B)
#if (B > 0) Stick(O, O+D*S) FractalTree(O+D*S, vtransform(D, transform{rotate y*R}), S*Scaling_Factor, R, B-1) FractalTree(O+D*S, vtransform(D, transform{rotate -y*R}), S*Scaling_Factor, R, B-1) #end
- end
union {
FractalTree(<-2,0,0>, <1,0,0>, 1, Spread_Ang, Branches)
}</lang>
PureBasic
<lang PureBasic>#Spread_Ang = 35
- Scaling_Factor = 0.75
- Deg_to_Rad = #PI / 180
- SizeH = 500
- SizeV = 375
- Init_Size = 100
Procedure drawTree(x1, y1, Size, theta, depth)
Protected x2 = x1 + Cos(theta * #Deg_to_Rad) * Size, y2 = y1 + Sin(theta * #Deg_to_Rad) * Size LineXY(x1, y1, x2, y2, RGB(255, 255, 255)) If depth <= 0 ProcedureReturn EndIf ;draw left branch drawTree(x2, y2, Size * #Scaling_Factor, theta - #Spread_Ang, depth - 1) ;draw right branch drawTree(x2, y2, Size * #Scaling_Factor, theta + #Spread_Ang, depth - 1)
EndProcedure
OpenWindow(0, 0, 0, #SizeH, #SizeV, "Fractal Tree", #PB_Window_SystemMenu)
Define fractal = CreateImage(#PB_Any, #SizeH, #SizeV, 32)
ImageGadget(0, 0, 0, 0, 0, ImageID(fractal))
If StartDrawing(ImageOutput(fractal))
drawTree(#SizeH / 2, #SizeV, #Init_Size, -90, 9) StopDrawing() SetGadgetState(0, ImageID(fractal))
EndIf
Repeat: Until WaitWindowEvent(10) = #PB_Event_CloseWindow</lang>
Python
<lang python>from pygame.locals import * import pygame, sys, math
pygame.init()
WINDOWSIZE = 400 COLOR = (255, 255, 255) REDUCTION = 8.3/10 ANGLE = 27
window = pygame.display.set_mode((WINDOWSIZE, WINDOWSIZE)) pygame.display.set_caption("Fractal Tree")
screen = pygame.display.get_surface()
def getEnd(start, length, angle):
x, y = start x += length*math.cos(math.radians(angle)) y += length*math.sin(math.radians(angle)) return (x, y)
def drawTrunk(surface, start, length, angle=-90, count=0):
if count < 10: end = getEnd(start, length, angle) pygame.draw.line(surface, COLOR, start, end, 2) drawTrunk(surface, end, length*REDUCTION, angle-ANGLE, count+1) drawTrunk(surface, end, length*REDUCTION, angle+ANGLE, count+1)
def input(event):
if event.type == QUIT: sys.exit(0)
drawTrunk(screen, (WINDOWSIZE/2, WINDOWSIZE-10), 45.0, -90) pygame.display.flip()
while True:
input(pygame.event.wait())
</lang>
Ruby
<lang Ruby> Shoes.app(:title => "Fractal Tree", :width => 600, :height => 600) do
background "#fff" stroke "#000" @deg_to_rad = Math::PI / 180.0 def drawTree(x1, y1, angle, depth) if !(depth == 0) x2 = x1 + (Math.cos(angle * @deg_to_rad) * depth * 10.0).to_i y2 = y1 + (Math.sin(angle * @deg_to_rad) * depth * 10.0).to_i line x1, y1, x2, y2 drawTree(x2, y2, angle - 20, depth - 1) drawTree(x2, y2, angle + 20, depth - 1) end end drawTree(300,550,-90,9)
end
</lang>
SVG
In the same style as Dragon curve#SVG. SVG has no parameterized definitions, so the recursion must be unrolled.
<lang xml><?xml version="1.0" standalone="yes"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="320"> <style type="text/css"><![CDATA[ line { stroke: black; stroke-width: .05; } circle { fill: black; } ]]></style>
<defs>
<g id="stem"> <line x1="0" y1="0" x2="0" y2="-1"/> </g> <g id="l0"><use xlink:href="#stem"/></g> <g id="l1"> <use xlink:href="#l0" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l0" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l2"> <use xlink:href="#l1" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l1" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l3"> <use xlink:href="#l2" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l2" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l4"> <use xlink:href="#l3" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l3" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l5"> <use xlink:href="#l4" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l4" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l6"> <use xlink:href="#l5" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l5" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l7"> <use xlink:href="#l6" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l6" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l8"> <use xlink:href="#l7" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l7" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g> <g id="l9"> <use xlink:href="#l8" transform="translate(0, -1) rotate(-35) scale(.7)"/> <use xlink:href="#l8" transform="translate(0, -1) rotate(+35) scale(.7)"/> <use xlink:href="#stem"/></g>
</defs>
<g transform="translate(200, 320) scale(100)">
<use xlink:href="#l9"/>
</g>
</svg></lang>
Tcl
<lang tcl>package require Tk
set SIZE 800 set SCALE 4.0 set BRANCHES 14 set ROTATION_SCALE 0.85 set INITIAL_LENGTH 50.0
proc draw_tree {w x y dx dy size theta depth} {
global SCALE ROTATION_SCALE $w create line $x $y [expr {$x + $dx*$size}] [expr {$y + $dy*$size}] if {[incr depth -1] >= 0} {
set x [expr {$x + $dx*$size}] set y [expr {$y + $dy*$size}] set ntheta [expr {$theta * $ROTATION_SCALE}]
# Draw left branch draw_tree $w $x $y \ [expr {$dx*cos($theta) + $dy*sin($theta)}] \ [expr {$dy*cos($theta) - $dx*sin($theta)}] \ [expr {$size * (rand() + $SCALE - 1) / $SCALE}] $ntheta $depth # Draw right branch draw_tree $w $x $y \ [expr {$dx*cos(-$theta) + $dy*sin(-$theta)}] \ [expr {$dy*cos(-$theta) - $dx*sin(-$theta)}] \ [expr {$size * (rand() + $SCALE - 1) / $SCALE}] $ntheta $depth
}
}
pack [canvas .c -width $SIZE -height $SIZE] draw_tree .c [expr {$SIZE/2}] [expr {$SIZE-10}] 0.0 -1.0 $INITIAL_LENGTH \
[expr {3.1415927 / 8}] $BRANCHES</lang>