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

Showing posts with label DSL. Show all posts
Showing posts with label DSL. Show all posts

Monday, 1 September 2014

Getting started with ruby-processing for ruby purists

Previously in my post getting started for wizards I showed how to create a sketch that would be more familiar to people coming from processing to ruby-processing. The sketch does not need to be explicitly wrapped as a class (that extends from Processing::App), since ruby-processing does that for you under the hood. This is the DSL approach to writing ruby-processing sketches which I favour, and makes it easier to read across from other processing modes to ruby-processing. However since ruby-processing-2.6.0 it is just as easy to create a classical sketch.
rp5 create classic_sketch 200 200 --wrap
rp5 watch classic_sketch.rb


Open a new console and 'vim classic_sketch.rb' or us another suitable editor

class ClassicSketch < Processing::App
  def setup
    size 200, 200
  end

  def draw

  end
end

# ClassicSketch.new(x: 20, y: 20)

For instant gratification and to relocate the sketch on your display un-comment the last line of the sketch and save (also note this line was "not" required to run the sketch, rp5 run or rp5 watch takes care of creating a new instance of sketch for you). You only use this form to send parameters, such as 'x offset' to your sketch

class ClassicSketch < Processing::App
  def setup
    size 200, 200
  end

  def draw

  end
end

ClassicSketch.new(x: 20, y: 20)
The sketch updates auto-magically...
Already in the works for the next release is the possibility of placing the sketch on your screen using the config file '~/.rp5rc' so this is kind of redundant, but a post initialization hook might get added so you will be able to send all sorts of other parameters. Which are then available by overriding the post_initialization hook method (See Sandi Metz POODR)

Next change the background of your sketch

class ClassicSketch < Processing::App
  def setup
    size 200, 200
  end

  def draw
    background 0
  end
end

ClassicSketch.new(x: 20, y: 20)

Next create a blue box.

class ClassicSketch < Processing::App
  def setup
    size 200, 200
  end

  def draw
    background 0
    fill 0, 0, 200
    rect 40, 50, 120, 100
  end
end

ClassicSketch.new(x: 20, y: 20)


To create class wrapped P3D sketch just "rp5 create classy_sketch 200 200 p3d --wrap" actually it probably doesn't matter where you put the --wrap option after create (but the order of the other variables is important)...

Wednesday, 16 June 2010

Cesàro fractal using ruby processing context free DSL.

Approximate Cesàro fractal loosely based on mariojan C++ version.

load_library 'context_free'


def setup_the_triangle

  @triangle = ContextFree.define do
    class << self
      define_method(:wedge) do |some_options# thin triangle
        size, options = *get_shape_values(some_options)
        rot = options[:rotation]
        rotate(rot) if rot    
        super.triangle(-0.03 * size, 0, 0, -size, 0.03 * size, 0)
        rotate(-rot) if rot
      end
    end

    rule :tri do
      wedge :y => -0.5
      split do    
        [90, -90, 180, 0].each do |rot|    
        rewind
        tri :y => 0.66667, :rotation => rot, :size => 0.5, :set_brightness => 1, :set_saturation => 1, :set_alpha => 1
        rewind
      end
      end
    end

    rule :four do
      split do
      4.times do |i|
        split do
        tri :rotation => 90 * i
      rewind
      end
      end
      end
    end

    rule :cesaro do
      four :rotation => 45
    end
  end
end

def setup
  size 400, 400
  setup_the_triangle
  no_stroke
  color_mode HSB, 1.0
  smooth
  draw_it
end

def draw_it
  background 0, 0.1, 0.1, 1.0
  @triangle.render :cesaro, :size => height * 1.05, :stop_size => 3, :start_y => height/2, :start_x => width/2, :color => [0, 0.8, 0.8, 0.2]
end




Friday, 11 June 2010

Exploring Dynamic Randomness in ruby-processing context-free DSL

Here is a context free sketch that really needs to be run to appreciate it (links to library download at github above). I'm not sure why the bands don't fit edge to edge, still it does not spoil the effect. There is definitely an illusion of lateral movement with the colored bands, further owing to persistence of vision, the circles and squares seem to dissolve into each other.

load_library 'context_free'


def setup_the_streak

  @streak = ContextFree.define do

    rule :streak do
      split do
      10.times do |j|
        lines :y => j
        rewind
      end
      end
    end
    rule :lines do
      split do
      10.times do |i|
        tri :x => i
        rewind
      end
    end
    end
 
    rule :tri do
      square :size => 1.0, :color => [rand, 1.0, 1.0, 1.0]
    end
 
    rule :tri do
      circle :size => 1.0, :color => [rand, 1.0, 1.0, 1.0]
    end
  end

end

def setup
  size 600, 600
  color_mode HSB, 1.0
  setup_the_streak
  no_stroke
  smooth
  draw_it
end

def draw_it
  background 0.1
  @streak.render :streak, :size => height/9, :stop_size => 3, :start_y => 0, :start_x => 0
end

def draw
  draw_it      
end


Sunday, 6 June 2010

Towards an Escher Bird Tiling (Ruby processing context-free DSL)


load_libraries 'context_free'

def setup_the_birds


  @birds= ContextFree.define do
 
    ############ Begin defining custom terminal, an wavy_triangle triangle        
    class << self     
      define_method(:wavy_diamond) do |some_options# wavy_triangle triangle
        size, options = *self.get_shape_values(some_options)
        rot = options[:rotation]
        x0 = options[:x]
        y0 = options[:y]
        disp = options[:disp]
        pts = Array.new(16)
        pts[0] = PVector.new(x0 - 0.25 * size, y0 - size/Math.sqrt(3))     # A
        pts[2] = PVector.new(x0 + 0.75 * size, y0 - size/Math.sqrt(3))     # B
        pts[4] = PVector.new(x0 + 0.25 * size, y0 + (Math.sqrt(3)*size)/6) # C
        pts[6] = PVector.new(x0 - 0.75 * size, y0 + (Math.sqrt(3)*size)/6) # D
        pts[1] = get_mid_point(pts[0], pts[2])#Ab
        pts[3] = get_mid_point(pts[2], pts[4])#Bc
        pts[5] = get_mid_point(pts[4], pts[6])#Cd
        pts[7] = get_mid_point(pts[6], pts[0])#Da
        pts[8] = get_mid_point(pts[0], pts[1])#Aba
        adjust_bezier(pts[8], PI/2, -disp * size)#Aba
        pts[9] = get_mid_point(pts[1], pts[2])
        adjust_bezier(pts[9], PI/2, disp * size)
        pts[10] = get_mid_point(pts[2], pts[3])
        adjust_bezier(pts[10], PI/3, disp * size)
        pts[11] = get_mid_point(pts[3], pts[4])
        adjust_bezier(pts[11], PI/3, -disp * size)
        pts[12] = get_mid_point(pts[4], pts[5])
        adjust_bezier(pts[12], PI/2, disp * size)
        pts[13] = get_mid_point(pts[5], pts[6])
        adjust_bezier(pts[13], PI/2, -disp * size)
        pts[14] = get_mid_point(pts[6], pts[7])
        adjust_bezier(pts[14], PI/3, -disp * size)
        pts[15] = get_mid_point(pts[7], pts[0])
        adjust_bezier(pts[15], PI/3, disp * size)
        rotate(rot) if rot
        smooth
        stroke 0
        begin_shape
        vertex(pts[0].x, pts[0].y)
        bezier_vertex(pts[0].x, pts[0].y, pts[8].x, pts[8].y, pts[1].x, pts[1].y)
        bezier_vertex(pts[1].x, pts[1].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[3].x, pts[3].y)
        bezier_vertex(pts[3].x, pts[3].y, pts[11].x, pts[11].y, pts[4].x, pts[4].y)
        bezier_vertex(pts[4].x, pts[4].y, pts[12].x, pts[12].y, pts[5].x, pts[5].y)
        bezier_vertex(pts[5].x, pts[5].y, pts[13].x, pts[13].y, pts[6].x, pts[6].y)
        bezier_vertex(pts[6].x, pts[6].y, pts[14].x, pts[14].y, pts[7].x, pts[7].y)
        bezier_vertex(pts[7].x, pts[7].y, pts[15].x, pts[15].y, pts[0].x, pts[0].y)
        vertex(pts[0].x, pts[0].y)
        end_shape(CLOSE)        
        rotate(-rot) if rot
      end
   
      private
      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
    end
 
    ########### End definition of custom terminal 'wavy_diamond' shape
    rule :birds do
      10.times do |i|
        10.times do |j|
          wavy_diamond :size => 1, :x => (i*2 + 0.5 * j%2), :y => j * 0.9
        end
      end
    end
  end
end

def setup
  size 400, 400
  smooth
  setup_the_birds
  draw_it
end

def draw_it
  background 255
  @birds.render :birds, :start_x => -50, :start_y => 20,
  :size => height/6, :color => [0, 0.8, 0.8, 1], :disp => 0.32
end

def draw
  # do nothing
end




Saturday, 5 June 2010

Weird Flower Ruby Processing Context Free DSL


load_library 'context_free'

def setup_the_flower
  @flower= ContextFree.define do
    ############ Begin defining custom terminal, an wavy triangle        
    class << self    
      define_method(:wavy) do |some_options# wavy triangle
        size, options = *self.get_shape_values(some_options)
        rot = options[:rotation]
        disp = 0.32          # could introduce a rule option?
        x0 = options[:x]
        y0 = options[:y]
        pts = Array.new(12)
        pts[0] = PVector.new(x0, y0 - size/Math.sqrt(3))                  # A
        pts[1] = PVector.new(x0 - 0.5 * size, y0 + (Math.sqrt(3)*size)/6) # B
        pts[2] = PVector.new(x0 + 0.5 * size, y0 + (Math.sqrt(3)*size)/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], PI/3, disp*size)                            # Aba
        pts[7] = get_mid_point(pts[3], pts[1])                            # Abb
        adjust_bezier(pts[7], PI/3, -disp*size)                           # Abb
        pts[8] = get_mid_point(pts[1], pts[4])
        adjust_bezier(pts[8], PI/2, -disp*size)
        pts[9] = get_mid_point(pts[4], pts[2])
        adjust_bezier(pts[9], PI/2, disp*size)
        pts[10] = get_mid_point(pts[2], pts[5])
        adjust_bezier(pts[10], -PI/3, -disp*size)
        pts[11] = get_mid_point(pts[5], pts[0])
        adjust_bezier(pts[11], -PI/3, disp*size)
        rotate(rot) if rot
        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)        
        rotate(-rot) if rot
      end
    
      private
      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
    end
  
    ########### End definition of custom terminal 'wavy' shape
    rule :flower do
      split do
      6.times do |i|
        petal :size => 1, :rotation => 60 * i, :y => -0.2866
        rewind
      end
      end
    end
  
    rule :petal do
      wavy :rotation => 7.5
    end
  end
end

def setup
  size 400, 400
  background 255
  smooth
  setup_the_flower
  draw_it
end

def draw_it
  @flower.render :flower, :start_x => width/2, :start_y => height*0.66,
               :size => height*0.55, :color => [0, 0.5, 0.8, 0.5]
end




Thursday, 3 June 2010

Red Dwarf (Ruby Processing Context Free DSL)


load_library 'context_free'

def setup_the_red_dwarf
  @red_dwarf = ContextFree.define do
  
    rule :red_dwarf do  
      5.times do |i|
        angle :rotation => 72
      end    
    end
  
    rule :angle do
      110.times do |i|
        triangle :size => 1.01, :rotation => i, :y => -1, :alpha => 0.1
      end
    end
  
  end
end

def setup
  size 600, 600
  smooth
  setup_the_red_dwarf
  draw_it
end

def draw
  # do nothing
end

def draw_it
  background 0
  @red_dwarf.render :red_dwarf,
               :start_x => width/2, :start_y => height/2,
               :size => height/1.5, :color => [0.01, 1, 1, 0.1]
end

def mouse_clicked
  draw_it
end




Monday, 24 May 2010

Towards Penrose Tiling Using ruby-processing context-free DSL


#########################
# rubystar.rb
#########################
load_library 'context_free'

PHI = (1 + Math.sqrt(5))/2

def setup_the_sunstar
  @hexa = ContextFree.define do
  ############ Begin defining custom terminals, as a sharp and flat triangles
    class << self
    include Math
      define_method(:sharp) do |some_options|      
        size, options = *self.get_shape_values(some_options)
        rot = options[:rotation]
        rotate(rot) if rot           # NB: sin(0) = 0, cos(0) = 1                                        
        super.triangle(0, 0, size, 0, size * cos(PI/5), size * sin(PI/5))
        rotate(-rot) if rot
      end
      define_method(:flat) do |some_options|      
        size, options = *self.get_shape_values(some_options)
        rot = options[:rotation]
        rotate(rot) if rot
        f = (options[:flip])? -1 : 1  # flip adjustment NB: sin(0) = 0, cos(0) = 1
        super.triangle(0, 0, size/PHI, 0, size * cos(PI * f/5), size * sin(PI * f/5))
        rotate(-rot) if rot
      end
    end
    ########### End definition of custom terminals 'sharp and flat'
    rule :tiling do    
      sun :brightness => 0.8
      star :brightness => 0.8, :alpha => 0.8
      tiling :size => 1/PHI, :brightness => 1.0
    end
  
    rule :dart do
      flat :size => 1, :color => [0.18, 0.6, 0.6]
      flat :size => 1, :color => [0.18, 1.0, 1.0], :flip => true
    end
  
    rule :kite do
      sharp :size => 1, :color => [0, 0.6, 0.6]
      sharp :size => 1, :color => [0, 1.0, 1.0], :rotation => 180, :flip => true
    end
  
    rule :star do    
      split do
        5.times do |i|
          dart :rotation => 72 * i
          rewind
        end
      end
    end
  
    rule :sun do
      split do
        5.times do |i|
          kite :rotation => 72 * i
          rewind
        end
      end
    end
  end
end

def setup
  size 800, 800
  background 150, 20, 0
  smooth
  setup_the_sunstar
  draw_it
end

def draw_it
  @hexa.render :tiling, :start_x => width/2, :start_y => height/2,
               :size => height
end




Sunday, 23 May 2010

Ruby Processing Context Free DSL (how to do a cfdg PATH)

One way to create an equivalent of PATH (from C++ cfdg) is to use the processing shape facilities, here I have created a custom line-strip hexagon shape (ie no fill). But of course you could just as easily create a filled shape.


#########################
# hextube.rb
#########################
load_library 'context_free'

def setup_the_hextube
  @hexa = ContextFree.define do
    ############ Begin defining custom terminal, as a hexagon (path C++ cfdg)
    class << self    
      define_method(:hexagon) do |some_options|
        size, options = *self.get_shape_values(some_options)
        rot = (options[:rotation])? options[:rotation]: 0
        no_fill
        stroke(*options[:color])
        stroke_weight(size/30)
        begin_shape
        6.times do |i|
          vertex(size * Math.cos(Math::PI * i/3 + rot), size * Math.sin(Math::PI * i/3 + rot))
        end
        end_shape(CLOSE)
      end
    end
    ########### End definition of custom terminal 'hexagon'
    rule :hextube do
      hexa :brightness => 1.0
    end

    rule :hexa do
      hexagon :size => 1, :brightness => 1.0
      hexa :size => 0.9, :rotation => 5
    end
  end
end

def setup
  size 800, 800
  background 0
  smooth
  setup_the_hextube
  draw_it
end

def draw_it
  @hexa.render :hextube, :start_x => width/2, :start_y => height/2,
               :size => height/2.1, :color => [0, 1, 1, 0.5]
end




Thursday, 6 May 2010

A Simple flower using ruby processing context free DSL


#########################################
# A Simple context free DSL flower
# flower.rb after leaf.cfdg by apoc
#########################################

load_library 'context_free'

def setup_the_flower
  @petal= ContextFree.define do  
   
    rule :flower do
      circle :size => 5.0, :hue => 0.1, :saturation => 1.0, :brightness => 1.0, :alpha => 0.6
      split do
        12.times do |i|
          petal :rotation => 30*i, :brightness => 1.0
          rewind
        end
      end
    end

    rule :petal do
      split do
        petal_border :y => -17.5, :rotation => -30
        rewind
        petal_border :y => -17.5, :flip => true, :rotation => 330
      end
    end
   
    rule :petal_border do
      circle :size => 0.75, :hue => 0.1, :saturation => 0.8, :brightness => 0.2
      petal_border :y => 0.1, :rotation => 0.17, :size => 0.995
    end

  end
end

def setup
  size 400, 400
  color_mode HSB, 1.0
  background 0.1, 0.2, 0.8
  smooth
  setup_the_flower
  draw_it
end

def draw_it
  @petal.render :flower, :start_x => width/2, :start_y => height/2,
               :size => height/40
end




Custom hbar shape for ruby processing Context Free DSL

Here I use a custom horizontal bar to mimic a electrophoresis gel (such as PCR). Also demonstrates the use of a low probability, empty rule to terminate recursion (see the third definition of the band rule).

#########################
# electrophoresis.rb
# demonstrates the hbar
# custom terminal
#########################
load_library 'context_free'

def setup_the_gel
  @pcr = ContextFree.define do
    ############ Begin defining custom terminal, a proportional horizontal bar
    class << self   
      define_method(:hbar) do |some_options|
        size, options = *self.get_shape_values(some_options)
        ht = some_options[:ht]|| 0.1    # default hbar width is 0.1
        ratio = ht * size
        rot = options[:rotation]
        rect_mode(CENTER)
        rotate(rot) if rot
        rect(-0.5 * size, -0.5 * ratio, 0.5 * size, 0.5 * ratio)
      end
    end
    ########### End definition of custom terminal 'hbar'
 
    rule :gel do
      dna :brightness => 1.0
    end
 
    rule :dna do
      split do
        26.times do
          band :x => 0.6
          rewind
        end
      end
    end
 
    rule :band do       # narrow band with 0.66' probability        
      hbar :size => 0.8, :ht => 0.1, :brightness => 0.3, :alpha => 0.3, :hue => 0.7, :saturation => 1.0
      band :brightness => 0.5
    end
 
    rule :band, 0.5 do   # double width band with 0.33' probability      
      hbar :size => 0.8, :ht => 0.15, :brightness => 0.8, :alpha => 0.6, :hue => -0.1, :saturation => 1.0
      band :brightness => 0.5
    end
 
    rule :band, 0.08 do  # a low probability empty rule used to end recursion    
    end 
   
   rule :band do            
     band :y => -0.23
   end
 
    rule :band do         
      band :y => 0.17
    end
 
    rule :band do
       band :y => 0.29 
    end

   rule :band do
      band :y => -0.33 
   end

  end
end

def setup
  size 500, 300
  background 0, 0, 180
  smooth
  setup_the_gel
  draw_it
end

def draw_it
  @pcr.render :gel, :start_x => -50, :start_y => height/2,
               :size => height/5, :color => [0.7, 0.8, 0.8, 1.0]
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