Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0

Saturday 17 April 2010

How to Draw a Tree in Processing

Another query on the discourse was how can I draw a line of fixed length, but with a random angle, someone else came up with standard cos(theta)*x, sin(theta)*y solution (that I usually favour), so I gave this as alternative, or at least a pointer to it. I also pointed out that truly random a angle would be a bad idea, but I neglected to point out the upside-down coordinate system in processing.

def setup
 size(300, 300)
 length = 70
 stroke_weight 3
 translate(width/2, height - 20)
 rotate(-PI/2)
 line(0, 0, length, 0)
 translate(length, 0)
 push_matrix
 rotate(PI/4)
 line(0, 0, length, 0)
 pop_matrix
 push_matrix
 rotate(-PI/4)
 line(0, 0, length, 0)
 pop_matrix
 line(0, 0, length, 0)
 translate(length, 0)
 push_matrix
 rotate(PI/4)
 line(0, 0, length, 0)
 pop_matrix
 push_matrix
 rotate(-PI/4)
 line(0, 0, length, 0)
 pop_matrix
 line(0, 0, length, 0)
end



Then I thought it would be a bit of fun to develop a kind of tree tutorial, so moving from this very procedural approach I thought the least I could do would be to extract a couple of functions. One to produce a trunk element and another to produce a branch element:-

def setup
 size(300, 300)
 length = 70
 stroke_weight 3
 translate(width/2, height - 20)
 rotate(-PI/2)
 trunk length
 branch PI/4, length
 branch -PI/4, length
 trunk length
 length *= 0.8 # reduce length
 branch PI/4, length
 branch -PI/4, length
 trunk length
end

def branch angle, len
  push_matrix
  rotate angle
  line 0, 0, len, 0
  pop_matrix
end

def trunk len
  line 0, 0, len, 0
  translate len, 0
end 





















Making the tree a bit more complicated, creating one new function gave the following:-


def setup
  size(300, 300)
  length = 70
  stroke_weight 3
  translate(width/2, height - 20)
  rotate(-PI/2)
  trunk length
  branch PI/4, length
  branch -PI/4, length
  length *= 0.9 # reduce overall length
  branch 0, length
  trunk length
  branch 0, length
  save_frame "tree3.png"
end

def branch angle, len
  push_matrix
  rotate angle
  trunk len
  angle = PI/4 if angle == 0 # then vertical branch element
  terminal_branch angle, len
  terminal_branch -angle, len
  trunk len
  pop_matrix
end

def terminal_branch angle, len
  push_matrix
  rotate angle
  line 0, 0, len*0.8, 0 # reduce length of terminal branch
  pop_matrix
end

def trunk len
  line 0, 0, len, 0
  translate len, 0
end




Now there has got to be easier way to do this and there are several. One way is to use LSystems to describe the tree, and another is to use recursion like in context free art.












Here are some context free rules (by curran) run with the c++ program cfdg with variation set to JIQ

rule tree 20 {
    CIRCLE{ size 0.25 }
    scraggle { y 0.1 }
}

rule scraggle {
    tree { rotate 5 }
}

rule scraggle {
    tree { rotate -5 }
}

rule tree 1 {
    branch { size 0.7}
}

rule branch {
    tree { rotate -10 }
    tree { rotate 10 }
}



















Here are the cfdg rules above translated to run as ruby-processing context-free DSL script:-

 

#################################################################
# A non deterministic sketch run it until you get a result you like
# uncomment "srand 5" to get a more deterministic result. It looked
# pretty good on my linux box (however I'm not sure how universal the
# random seeding is in jruby)
#################################################################

load_library 'context_free'

def setup_the_tree
  @tree = ContextFree.define do
    rule :trunk, 20 do                        # rule has a probability weighting of 20
      circle :size => 0.25, :brightness => 0  # giving an actual probability = 0.952381
      scraggle :y => -0.1                     # the minus is require by the upside down coordinate system            
    end
 
    rule :trunk, 1 do                         # rule has a probability weighting of 1
      branch :size => 0.7                     # giving an actual probability = 0.047619  
    end
 
    rule :branch do
      split do                               # split is like a branch, rewind returns original context
        trunk :rotation => 10
      rewind
        trunk :rotation => -10
      end
    end

    rule :scraggle do                          # without an explicit weighting    
      trunk :rotation => 5                      # probability of each scraggle rule
    end                                        # is 0.5

    rule :scraggle do
      trunk :rotation => -5
    end
  end
end

def setup
  size 600, 600
  # srand 5
  smooth
  setup_the_tree
  background 255         # NB color mode here is "RGB 255", within context free definition
  draw_it                # the color mode is "HSB 1.0", supports :hue, :saturation, :brightness
end

def draw_it
  @tree.render :trunk,
               :start_x => width/2, :start_y => height * 0.9,
               :size => height/18
end





Follow this link to see an LSystem tree implementation



Context free programs run with multiple definitions of a rule are non-deterministic, so it is quite usual to get different results each time the program is run.

No comments:

Post a Comment

Followers

Blog Archive

About Me

My photo
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2