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

Thursday, 19 November 2009

Lindenmayer system in ruby-processing


##
# Lindenmayer System in ruby-processing by Martin Prout
# Loosely based on processing Pentigree L-System by Geraldine Sarmiento
###

require 'pentigree'

class Pentigree_Test < Processing::App 
  load_library :grammar
  attr_reader :pentigree
  def setup
    size 800, 800
    @pentigree = Pentigree.new
    pentigree.create_grammar(5)  
    no_loop
  end
  
  def draw
    background 0
    pentigree.render
  end
end

######################
# pentigree.rb
######################
class Pentigree
  include Processing::Proxy  
 
  attr_reader :axiom, :grammar, :start_length, :theta, :production, :generations, :draw_length
  
  def initialize
    @axiom = "F-F-F-F-F"
    @grammar = Grammar.new(axiom)
    grammar.add_rule("F", "F-F++F+F-F-F")
    @start_length = 40.0
    @theta = (Math::PI/180) * 72.0 # convert degrees to radians
    @production = axiom
    @draw_length = start_length
  end
    
  def render 
    translate(width * 0.8, height * 0.75)
    @production.each_char do |prod|      
      case prod
      when 'F'
        no_fill
        stroke 255
        line(0, 0, 0, draw_length)        
        translate(0, draw_length)
      when '+' 
        rotate(theta)
      when '-'
        rotate(-theta)
      when '['
        push_matrix()
      when ']' 
        pop_matrix()
      else            
        puts "Character '#{element}' is not in grammar" 
      end
    end
  end
  
  def create_grammar(gen)
    @draw_length *=  0.6**gen
    @production = grammar.generate gen
  end
end





Tuesday, 17 November 2009

Tessellated "curvy" triangles in ruby-processing


# alhambra.rb by Martin Prout

class CurvyTriangle < Processing::App

  def setup()  
    size(700, 650)
    @x_values = [100, 300, 500, 700]
    @y_values = [50 * Math.sqrt(3), 150 * Math.sqrt(3), 250 * Math.sqrt(3), 350 * Math.sqrt(3)]
    background 21, 15, 72
    smooth
    render
    save_frame "alahambra.png"
  end

  def draw_hexagon(xpos, ypos, sz, theta)
    begin_shape
      6.times do |i|
      vertex(xpos + sz*Math.cos((Math::PI/3 * i) + theta), ypos + sz*Math.sin((Math::PI/3 * i) +theta));
    end
    end_shape CLOSE
  end

  def draw_triangle(x0, y0, sz, color, disp)
    # Calculate  triangle points
    pts = Array.new(12)
    pts[0] = PVector.new(x0, y0 - sz/Math.sqrt(3))               # A
    pts[1] = PVector.new(x0 - 0.5 * sz, y0 + (Math.sqrt(3)*sz)/6)# B
    pts[2] = PVector.new(x0 + 0.5 * sz, y0 + (Math.sqrt(3)*sz)/6)# C
    pts[3] = get_mid_point(pts[0], pts[1])                       # Ab
    pts[4] = get_mid_point(pts[1], pts[2])                       # Bc
    pts[5] = get_mid_point(pts[0], pts[2])                       # Ca
    pts[6] = get_mid_point(pts[0], pts[3])                       # Aba
    adjust_bezier(pts[6], Math::PI/3, disp*sz)                   # Aba
    pts[7] = get_mid_point(pts[3], pts[1])                       # Abb
    adjust_bezier(pts[7], Math::PI/3, -disp*sz)                  # Abb
    pts[8] = get_mid_point(pts[1], pts[4])
    adjust_bezier(pts[8], Math::PI/2, -disp*sz)
    pts[9] = get_mid_point(pts[4], pts[2])
    adjust_bezier(pts[9], Math::PI/2, disp*sz)
    pts[10] = get_mid_point(pts[2], pts[5])
    adjust_bezier(pts[10], -Math::PI/3, -disp*sz)
    pts[11] = get_mid_point(pts[5], pts[0])
    adjust_bezier(pts[11], -Math::PI/3, disp*sz)
    # render triangle
    fill color
    begin_shape()
      vertex(pts[0].x, pts[0].y)
      bezier_vertex(pts[0].x, pts[0].y, pts[6].x, pts[6].y, pts[3].x, pts[3].y)
      bezier_vertex(pts[3].x, pts[3].y, pts[7].x, pts[7].y, pts[1].x, pts[1].y)
      bezier_vertex(pts[1].x, pts[1].y, pts[8].x, pts[8].y, pts[4].x, pts[4].y)
      bezier_vertex(pts[4].x, pts[4].y, pts[9].x, pts[9].y, pts[2].x, pts[2].y)
      bezier_vertex(pts[2].x, pts[2].y, pts[10].x, pts[10].y, pts[5].x, pts[5].y)
      bezier_vertex(pts[5].x, pts[5].y, pts[11].x, pts[11].y, pts[0].x, pts[0].y)
      end_shape(CLOSE)
      # set color and render small hexagon
      fill(255);
      draw_hexagon(x0 + 4, y0, sz * 0.214, 0);
    end
  
    def adjust_bezier(base, theta, disp)
      base.add(PVector.new(Math.cos(theta)*disp, Math.sin(theta)*disp))
    end
  
    def get_mid_point(a, b)
      mid = PVector.add(a, b)
      mid.div(2)
      return mid
    end
  
    def render
      @x_values.length.times do |column|
    
      @y_values.length.times do |row|
        if (row % 2 == 0) then
          if (column % 3 ==0) then
            draw_triangle(@x_values[column], @y_values[row], 200, color(255, 0, 0), 0.32)
          else
            draw_triangle(@x_values[column], @y_values[row], 200, color(255, 0, 255), 0.32)
          end
        # end
        # offset tiles so that they tesselate
        elsif ((column - 2) % 3 ==0) then
            draw_triangle(@x_values[column] - 100, @y_values[row], 200, color(255, 0, 0), 0.32)
          else
            draw_triangle(@x_values[column] - 100, @y_values[row], 200, color(255, 0, 255), 0.32)
          end
        end
      end
    end
end


Wednesday, 11 November 2009

Dynamic rand with ruby-processing context-free DSL

Regular context free can't do dynamic random, here I experiment with the possibilities of ruby-processing DSL. This example is essentially a modified city.rb that is included as a sample with the application. Note I have added a convenience method rand_range for use in the DSL, partly as an experiment in ways of extending the program.


load_library 'context_free'

def setup_the_spots
  @spots = ContextFree.define do
    
    class << self 
      define_method (:rand_range) do |max, min|  # nice to have a range
      rand * (max - min) + min
      end
    end
    
    rule :region do
      split do
        block :x => -0.25, :y => -0.25, :brightness => 1.0, :saturation => 1.0
        rewind
        block :x => 0.25, :y => -0.25, :brightness => 1.0, :saturation => 1.0
        rewind
        block :x => 0.25, :y => 0.25, :brightness => 1.0, :saturation => 1.0
        rewind
        block :x => -0.25, :y => 0.25, :brightness => 1.0, :saturation => 1.0
      end
    end
    
    rule :block do
      spots :size => 0.85, :hue => rand, :saturation => rand_range(1.0, 0.8), :brightness => rand_range(1.0, 0.8)
    end
    
    rule :block, 5 do
      region :size => 0.5, :rotation => rand_range(8, 4), :hue => rand_range(0.8, 0.5), :saturation => rand_range(1.0, 0.5), :brightness => rand_range(1.0, 0.5)
    end
    
    rule :block, 0.1 do
      # Do nothing
    end
    
    rule :spots do
      circle :hue => rand_range(0.8, 0.5), :saturation => 1.0, :brightness => 1.0, :alpha => 0.4
    end
    
  end
end


def setup
  size 600, 600
  background 255, 255, 0
  smooth
  color_mode HSB, 1.0  
  setup_the_spots
  draw_it
end

def draw
  # Do nothing
end

def draw_it
  @spots.render :region, :color => [0.2, 1.0, 1.0, 1.0],
               :start_x => width/2, :start_y => height/2,
               :size => height/2.5
end

def mouse_clicked
  draw_it
end




 

Tuesday, 10 November 2009

Flower in ruby-processing DSL

# flower.rb ruby-processing
load_library 'context_free'
 

ROT = 180*(Math.sqrt(5) - 1)
 

def setup_the_flower
  @flower = ContextFree.define do
    @rot = 0
    @pet = 0
    rule :start do
      flower :brightness => 1.0
    end
 

    rule :flower do
      @rot += ROT
      @rot = @rot % 360
      split do
        petal :brightness => 1.0, :saturation =>  0.5
      rewind
        flower :rotation => @rot, :size =>  0.99, :hue =>  0.15
      rewind
      end
    end
  
    rule :petal do
      @pet += 15
      split do
        triangle :x => 4.1, :rotation => @pet
      rewind
        petal :size => 0.995, :alpha => 0.4, :brightness => 0.5
      #rewind
      end
    end
  end
end
  
def setup
  size 800, 800
  setup_the_flower
  smooth
  draw_it
  save_frame("flower.png")
end


def draw
  # Do nothing.
end


def draw_it
  background 60, 0, 0
  @flower.render :start, :size => width*0.8, :stop_size => 2,
        :start_x => width/2, :start_y => height/2
end



 

Sunday, 8 November 2009

Heighway Dragon in ruby-processing context free DSL

This implementation of the Heighway dragon starts with square, that is hidden by being transparent, the rotations scaling and translations used make this solution similar to the paper folding solution.

# dragon.rb ruby-processing NB: :alpha is now implemented in ruby-processing (since 8 Nov 2009) the brightness, of dragon in the start rule has no effect, but the DSL doesn't like to call rules with no arguments.

 
load_library 'context_free'

def setup_the_dragon
  @dragon = ContextFree.define do
    rule :start do
      dragon :brightness => 1.0
    end
    rule :dragon do
      split do
        fractal :hue => 0, :brightness => 1.0, :saturation => 1.0
      rewind
        fractal :hue => 0.2, :brightness => 1.0, :saturation => 1.0, :rotation => 90, :x => -0.4
      rewind
        fractal :hue => 0.7, :brightness => 1.0, :saturation => 1.0, :rotation => 270, :x => -0.4, :y => -0.33
      rewind
      end
    end
    rule :fractal do
      square :alpha => 0.01
      split do
        fractal :size => 1/Math.sqrt(2), :rotation => -45, :x => 0.25, :y => 0.25
        rewind
        fractal :size => 1/Math.sqrt(2), :rotation => 135, :x => 0.25, :y => 0.25
        rewind
      end
    end
  end
end


def setup
  size 800, 800
  setup_the_dragon
  smooth
  draw_it
  save_frame("dragon.png")
end


def draw
  # Do nothing.
end


def draw_it
  background 0
  @dragon.render :start, :size => width*0.6, :stop_size => 2,
        :start_x => width*0.6, :start_y => height*0.6
end



 

Thursday, 5 November 2009

Lévy curve implemented in ruby-processing context free DSL

NB I modified the context_free.rb to accept :alpha to get this script to work properly, these mods are now included in ruby-processing (since 8th Nov 2009).


# levy.rb ruby-processing NB: :alpha is now implemented ruby-processing
load_library 'context_free'

def setup_the_levy
  @levy = ContextFree.define do
    rule :start do
      levy :brightness => 0.9
    end
    rule :levy do
      square :alpha => 0.1
      split do
        levy  :size => 1/Math.sqrt(2), :rotation => -45, :x => 0.5, :brightness => 0.9
        rewind
        levy  :size => 1/Math.sqrt(2), :rotation => 45, :x => 0.5, :brightness => 0.9
      end
    end
  end
end


def setup
  size 400, 400
  setup_the_levy
  smooth
  draw_it
  save_frame("levy.png")
end


def draw
  # Do nothing.
end


def draw_it
  background 255
  @levy.render :start, :size => 250,  :stop_size => 2,
        :start_x => width/4, :start_y => height/2
end


 

jEdit as a cross platform GUI?

I have created a commando file 'rp5.xml' that allows me to run the file I am editing in jEdit (runs 'rp5 run buffer.rb'), directly from jEdit. You can download my file from the jEdit community downloads. It is easy to edit the commando file, so you could add watch as alternative to run.
You could also use a bsh macro to launch the command file, this is mine:-

new console.commando.CommandoDialog(view,"commando.rp5");

Here is a screenshot of the jedit buffer window a running ruby-processing applet, and the associated console pane.


Followers

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