Revised version as of 10th January 2010 now uses my grammar library.
########################################################
# Lindenmayer System in ruby-processing by Martin Prout
# Exploring terminals with minimum logic (Seasonal)
########################################################
require 'seasonal'
class Seasonal_Test < Processing::App
load_library :grammar
attr_reader :seasonal
def setup
size 600, 800
@seasonal = Seasonal.new
seasonal.create_grammar(3)
no_loop
end
def draw
background 0
seasonal.render
end
end
############################
# seasonal.rb
###########################
class Seasonal
include Processing::Proxy
attr_reader :grammar, :axiom, :draw_length, :theta, :xpos, :ypos, :production
DELTA = Math::PI/4
def initialize
@axiom = "F"
@grammar = Grammar.new axiom
grammar.add_rule("F", "F[-F]F[+F][F]")
@draw_length = 600
@xpos = width/2
@ypos = height * 0.9
@theta = Math::PI/2 # this way is up?
end
def render
stack = Array.new # directly using locally defined array as turtle stack
production.each_char do |element|
case element
when 'F' # NB NOT using affine transforms
x_temp = xpos
y_temp = ypos
@xpos += draw_length * Math.cos(theta) * 0.5 # looks neater here
@ypos -= draw_length * Math.sin(theta) * 0.5
stroke 0, 255, 0
stroke_weight 4
line(x_temp, y_temp, xpos, ypos)
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
when '['
stack.push([xpos, ypos, theta])
when ']'
no_stroke
fill 255, 0, 0
# add some seasonal red berries as terminals using minimal logic
ellipse(xpos, ypos, draw_length/3, draw_length/3) unless stack.length < 2
@xpos, @ypos, @theta = *stack.pop
else
puts "Character '#{element}' is not in grammar"
end
end
end
##############################
# create grammar from axiom and
# rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = @grammar.generate gen
end
end
No comments:
Post a Comment