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

Friday 12 February 2010

Developing the shapes

From the pentive? fractal it is clearly possible to develop some interesting "textured" shapes, here I produce an approximate circle from a set of rotations.


########################################################
# A Pentive fractal implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'pentive'

class Pentive_Test < Processing::App
  attr_reader :pentive,:points, :production

  def setup
    size(500, 500)
    @pentive = Pentive.new(0, 0)
    @production = pentive.create_grammar(6)
    @points = pentive.translate_rules(production)
    no_loop()
  end
 
  def draw_element()
    stroke(255)
    points.each do |tmp|
      line(*tmp)
    end
  end

  def draw()
    background(0)
    translate(width/2, height/2)
    10.times do
      rotate(Math::PI/180 * 36)    
      draw_element()
    end
    save_frame("/home/tux/advance.png")
  end
end




Thursday 11 February 2010

A Pentive? Fractal

The pentive fractal is another space filling fractal that I found over on a fractint site again for the grammar generator see my Cesàro fractal.

########################################################
# A Pentive fractal implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'pentive'

class Pentive_Test < Processing::App
  attr_reader :pentive,:points, :production

  def setup
    size(600, 400)
    @pentive = Pentive.new(width/95, height*0.9)
    @production = pentive.create_grammar(8)
    @points = pentive.translate_rules(production)
    no_loop()
  end

  def draw()
    background(0)
    stroke(255)
    points.each do |tmp|
      line(*tmp)
    end
  end
end

####################################################
# The Pentive? fractal
####################################################
class Pentive

  attr_reader :draw_length, :xpos, :ypos, :theta, :axiom, :grammar, :delta
  DELTA = Math::PI/180 * 36 # 36 degrees

  def initialize xpos, ypos
    @axiom = "Q"  
    @theta  = -DELTA
    @grammar = Grammar.new(axiom)
    grammar.add_rule("F", "")
    grammar.add_rule("P","1-FR3+FS1-FU")   # abbreviated grammar 1 = two & 3 = four repeats
    grammar.add_rule("Q", "FT1+FR3-FS1+")
    grammar.add_rule("R", "1+FP3-FQ1+FT")
    grammar.add_rule("S", "FU1-FP3+FQ1-")  
    grammar.add_rule("T", "+FU1-FP+")
    grammar.add_rule("U", "-FQ1+FT-")
    @draw_length = 12
    @xpos = xpos
    @ypos = ypos
  end

  def create_grammar(gen)  
    grammar.generate(gen)
  end

  def translate_rules(prod)
    repeats = 1
    points = [] # An empty array to store lines as an array of points
    prod.scan(/./) do |ch|
      case(ch)
      when "F"
        temp = [xpos, ypos, (@xpos += draw_length * Math.cos(theta)), (@ypos += draw_length * Math.sin(theta))]
        points.push(temp)    
      when "+"
        @theta += DELTA * repeats
        repeats = 1    
      when "-"
        @theta -= DELTA * repeats
        repeats = 1
      when '1', '3'
        repeats += Integer(ch)
      when "P", "Q", "R", "S", "T", "U"        
      else
        puts("character '#{ch}' not in grammar")
      end
   end
    return points
  end
end




MPeano Fractal (Traveling Salesman Problem)

Uses my grammar library see the Cesàro fractal, here I included it in the mpeano.rb file, which is why it didn't need to be separately loaded (omitted for brevity).

########################################################
# A MPeano fractal implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'mpeano'

class MPeano_Test < Processing::App
  attr_reader :mpeano, :points, :production

  def setup
    size(600, 600)
    @mpeano = MPeano.new(width/2, height*0.95)
    @production = mpeano.create_grammar(7)
    @points = mpeano.translate_rules(production)
    no_loop()
  end

  def draw()
    background(0)
    stroke(255)
    points.each do |tmp|
      line(*tmp)
    end
  end
end

####################################################
# The MPeano fractal has been used to study the
# Euclidean travelling salesman problem
####################################################
class MPeano

  attr_reader :draw_length, :xpos, :ypos, :theta, :axiom, :grammar, :delta

  def initialize xpos, ypos
    @axiom = "XFF--AFF--XFF--AFF"
    @delta = Math::PI/4 # 45 degrees
    @theta  = delta * 2
    @grammar = Grammar.new(axiom)
    grammar.add_rule("X", "+!X!FF-BQFI-!X!FF+")
    grammar.add_rule("F", "")
    grammar.add_rule("Y", "FFY")
    grammar.add_rule("A", "BQFI")
    grammar.add_rule("B", "AFF")
    @draw_length = 8
    @xpos = xpos
    @ypos = ypos
  end

  def create_grammar(gen)  
    grammar.generate(gen)
  end

  def translate_rules(prod)
    points = [] # An empty array to store lines as an array of points
    prod.scan(/./) do |ch|
      case(ch)
      when "F"
        temp = [xpos, ypos, (@xpos -= draw_length * Math.cos(theta)), (@ypos -= draw_length * Math.sin(theta))]
        points.push(temp)    
      when "+"
        @theta += delta    
      when "-"
        @theta -= delta  
      when "!"
        @delta = -delta
      when "I"
              @draw_length *= 1/Math.sqrt(2)    
      when "Q"
              @draw_length *= Math.sqrt(2)    
      when "X", "A", "B"    
      else
        puts("character '#{ch}' not in grammar")
      end
   end
   return points
  end
end


 

Wednesday 10 February 2010

DavidTour fractal

For the grammar.rb library see my Cesàro fractal (here it was included in the davidtour.rb file which is why it didn't need to be separately loaded, Grammar code omitted for brevity).

########################################################
# A David Tour fractal implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'davidtour'

class David_Test < Processing::App
  attr_reader :david, :points, :production

  def setup
    size(800, 900)
    @david = DavidTour.new(width * 0.6, height/4)
    @production = david.create_grammar(5)
    @points = david.translate_rules(production)
    no_loop()
  end
  
  def draw()
    background(0)
    stroke(255)
    points.each do |tmp|
      line(*tmp)
    end
  end
end

####################################################
# The DavidTour fractal has been used to study the
# Euclidean travelling salesmam problem
####################################################
class DavidTour

  attr_reader :draw_length, :xpos, :ypos, :theta, :axiom, :grammar
  DELTA = Math::PI/3 # 60 degrees
  
  def initialize xpos, ypos
    @axiom = "FX-XFX-XFX-XFX-XFX-XF"
    @theta  = 0
    @grammar = Grammar.new(axiom)
    grammar.add_rule("F", "!F!-F-!F!")
    grammar.add_rule("X", "!X")
    @draw_length = 15
    @xpos = xpos
    @ypos = ypos
  end

  def create_grammar(gen)  
    @draw_length *= @draw_length * 0.5**gen
    grammar.generate(gen)
  end
  
  def translate_rules(prod)
    swap = false
    points = [] # An empty array to store lines as an array of points
    prod.scan(/./) do |ch|
      case(ch)
      when 'F'
        temp = [xpos, ypos, (@xpos += draw_length * Math.cos(theta)), (@ypos -= draw_length * Math.sin(theta))]
        points.push(temp)      
      when '+'
        @theta += (DELTA)      
      when '-'
        @theta += (swap ? DELTA : -DELTA)
      when '!'
        swap = !swap
      when 'X'    
      else
        puts("character '#{ch}' not in grammar")
      end
    end
    return points
  end
end



Tuesday 2 February 2010

The Best of Both Worlds (combining PeasyCam and control_panel

This ruby processing sketch shows how to get the best of both worlds; the smooth easily setup PeasyCam, that you can use the scroll-wheel to zoom, and mouse to drag, and the possible fine grain control of a control panel. In this example I have initially disabled mouse control; use the button to toggle mouse control on or off. Use the control panel slider to set off the rotation or the freeze! button (to stop the rotation). If you only want fine grain rotation (cf. continuous rotation with the slider) then you will need get the camera to remember state (I believe Quark has done this in vanilla processing). If you are really keen you could also implement a slider to control the zoom of the peasy cam (in place of the mouse-wheel).

load_libraries 'PeasyCam', 'control_panel'
import 'peasy'

attr_reader :cam, :x_rotate, :y_rotate, :z_rotate, :controlled

def setup()
  size(200, 200, P3D)
  configure_panel()
  @controlled = true
  configure_camera()
end

def configure_camera()    
  @cam = PeasyCam.new(self, 100)
  cam.set_minimum_distance(50)
  cam.set_maximum_distance(500)
  mouse_control()
end

def configure_panel()
  control_panel do |c|
    c.slider(:x_rotate, -1.0..1.0, 0.0)
    c.slider(:y_rotate, -1.0..1.0, 0.0)
    c.slider(:z_rotate, -1.0..1.0, 0.0)
    c.button(:freeze!)
    c.button(:mouse_control)
  end
end

def freeze!()
  @x_rotate = 0.0
  @y_rotate = 0.0
  @z_rotate = 0.0
end

def mouse_control()     # toggle mouse controlled camera
  cam.set_mouse_controlled(!controlled)
  @controlled = !controlled
end

def draw()
  cam.rotate_x(x_rotate/100)
  cam.rotate_y(y_rotate/100)
  cam.rotate_z(z_rotate/100)
  rotate_x(-0.5)
  rotate_y(-0.5)
  background(0)
  fill(255, 0, 0)
  box(30)
  push_matrix()
  translate(0, 0, 20)
  fill(0, 0, 255)
  box(5)
  pop_matrix()
end




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