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

Monday, 7 December 2009

A Cesàro (or torn square) fractal in ruby processing (using a grammar library)

Includes code for grammar library...
To use the library as a local library put grammar.rb in a folder grammar, and put that folder
in a library folder along with the ruby code (otherwise place it with the other libraries in the distribution, in my test local libraries get called first).


#############################################################
# A Cesaro fractal implemented (uses a grammar.rb library)
# Lindenmayer System in ruby-processing by Martin Prout
#############################################################
require 'cesaro'

class Cesaro_Test < Processing::App
  load_library :grammar
  
  attr_reader :cesaro
  
  def setup
    size 600, 600
    @cesaro = Cesaro.new  
    cesaro.create_grammar 5  
    no_loop
  end
  
  def draw
    background 0
    cesaro.render
  end
end

############################
# cesaro.rb
###########################
class Cesaro
  include Processing::Proxy
  
  attr_reader :grammar, :axiom, :draw_length, :theta, :xpos, :ypos, :production
  
  XPOS = 0     # placeholders for turtle array
  YPOS = 1
  ANGLE = 2 
  DELTA = Math::PI/16
  
  def initialize  
    setup_grammar
    @draw_length = 200
    stroke 0, 255, 0
    stroke_weight 2  
    @xpos = width/7
    @ypos = height/7
    @theta = Math::PI/2  # this way is up?
  end
  
  def setup_grammar
    @axiom = "F7-F7-F7-F"
    @grammar = Grammar.new axiom
    grammar.add_rule "F", "F6-F67+F6-F" 
    @production = axiom
  end

  def render
    repeats = 1
    stack = Array.new     # directly using a locally defined array as the turtle stack
    turtle = [xpos, ypos, theta]    # simple array for turtle
    production.scan(/./).each do |element|
      case element
      when 'F'                     # NB NOT using affine transforms
        turtle = draw_line(turtle, draw_length, repeats)
        repeats = 1
      when '+'
        turtle[ANGLE] += DELTA * repeats    
        repeats = 1
      when '-'
        turtle[ANGLE] -= DELTA * repeats      
        repeats = 1
      when '6', '7'   # NB '6' means seven repeats etc.
        repeats += Integer(element)
      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
  
  private
  ######################################################
  # draws line using current turtle and length parameters
  # returns a turtle corresponding to the new position
  ######################################################

  def draw_line(turtle, length, repeats)
    length *= repeats
    new_xpos = turtle[XPOS] + length * Math.cos(turtle[ANGLE])
    new_ypos = turtle[YPOS] + length * Math.sin(turtle[ANGLE])
    line(turtle[XPOS], turtle[YPOS], new_xpos, new_ypos)
    turtle = [new_xpos, new_ypos, turtle[ANGLE]]
  end
end

############################
# grammar.rb Non-stochastic grammar
# library with unique premise/rules
############################
class Grammar
  attr_accessor :axiom, :rules
  
  def initialize axiom
    @axiom = axiom
    @rules = Hash.new
  end
  
  def add_rule premise, rule
    rules.store(premise, rule)
  end
  
  ##########################################
  # replace each pre char with a unique rule
  ##########################################
  def new_production production
    production.gsub!(/./) { |c| (r = @rules[c]) ? r : c }
  end
  
  ##########################################
  # control the number of iterations
  # default 0, returns the axiom
  ##########################################
  def generate repeat = 0
    prod = axiom
    repeat.times do
      prod = new_production prod
    end
    return prod
  end  
end  




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