(archive 'newLISPer)

October 1, 2010

Tree fun

Filed under: newLISP — newlisper @ 17:47

I stumbled across a neat little piece of code this week, over at Learning Clojure. It’s a simple program that draws fractal trees. I don’t use Clojure here, so I wanted to make a newLISP version that I could draw some trees with. It looked easy enough to translate the algorithm, and, because I didn’t understand the graphical code, I knocked up a simple, and I hope, equivalent-ish version, using the newLISP-GS Java graphics environment. Here’s a screenshot of the luxuriant growth generated so far:


And here’s the code.

    #!/usr/bin/env newlisp

    (load (append (env "NEWLISPDIR") "/guiserver.lsp")) 

    (constant 'PI 3.141592653589793)

    (define (deg->rad d)
     (mul d (div PI 180)))

    (define (draw-tree angle x y len branch-angle depth)
        (if (> depth 0)
            (letn ((new-x (sub x (mul len (sin (deg->rad angle)))))
                         (new-y (sub y (mul len (cos (deg->rad angle)))))
                         (new-length (fn () (mul len (add 0.75 (random 0.01 0.1)))))
                         (new-angle  (fn (op) (op angle (mul branch-angle (add 0.75 (random 0 3)))))))
                (gs:draw-line 'T (int x) (int y) (int new-x) (int new-y) '(0.1 0.9 0.1))
                ; for slow drawing: (sleep 10) (gs:update)
                (draw-tree (new-angle add) new-x new-y (new-length) branch-angle (- depth 1))
                (draw-tree (new-angle sub) new-x new-y (new-length) branch-angle (- depth 1)))))

    (define (render w h max-depth branch-angle)
        (letn ((init-length (div (min w h) 2)))
            (gs:delete-tag 'T)
            (draw-tree 0 (/ w 2) h init-length branch-angle max-depth branch-angle)))

    ; handlers

    (define (update)
         (gs:set-text 'depth-label (string {depth: } *depth))
         (gs:set-text 'branch-angle-label (string {branch-angle: } *branch-angle))
         (render *width *height *depth *branch-angle))

    (define (depth-slider-handler id value)
        (set '*depth (int value))

    (define (branch-angle-slider-handler id value)
        (set '*branch-angle (int value))

    ; global variables 
    (set '*width 150 '*height 150 '*depth 12 '*branch-angle 10)

    (gs:frame 'f 50 50 530 670 "tree")
    (gs:set-border-layout 'f)
    (gs:set-resizable 'f true)

    ; canvas
    (gs:canvas 'tree-canvas)
    (gs:set-size 'tree-canvas 530 450)
    (gs:set-background 'tree-canvas 0.2 0.1 0.1)
    (gs:set-stroke 1)

    ; controls
    (gs:panel 'controls )
    (gs:set-grid-layout 'controls 3 1)

    ; labels
    (gs:slider 'depth-slider 'depth-slider-handler "depth" 3 15 *depth) 
    (gs:label 'depth-label (string "depth: " *depth) "left")

    (gs:slider 'branch-angle-slider 'branch-angle-slider-handler "branch-angle" 3 18 *branch-angle) 
    (gs:label 'branch-angle-label (string "branch-angle: " *branch-angle) "left")

    ; go for it
    (gs:add-to 'controls 'depth-slider 'depth-label 'branch-angle-slider 'branch-angle-label) 
    (gs:add-to 'f 'tree-canvas "center" 'controls "south")
    (gs:set-translation 200 300)
    (gs:set-visible 'f true)
    (render *width *height *depth *branch-angle)

I like the way that the declaration section of the draw-tree function defines two anonymous functions, new-length and new-angle, which generate new values for the next recursive call. Notice that I had to switch to floating-point arithmetic…it’s easy to forget when looking at other languages.

Fractal trees are cool, and it’s easy to add a few controls to the script so that you can design different types of tree by adjusting the parameters.

It would be simple enough to add parameters for changing line width, adjusting the colour of the branches, and so on.


John’s original post was focused on Clojure performance, but that doesn’t interest me here, not being a Clojurer. I’ve never considered the newLISP graphics system to be a speed demon, but that’s probably because it always takes a couple of seconds to start up the Java server, on my machine at least. I wouldn’t expect interpreted trees to grow as fast as the compiled ones!

As for Clojure: I’m very pleased to see more members of the Lisp family, and Clojure looks impressive and exciting. However, as a non-programmer and amateur scripter I’ve tried and failed to make progress in learning it so far. But there’s always tomorrow.


Leave a Comment »

No comments yet.

RSS feed for comments on this post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: