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

Sunday 15 September 2013

Why ruby-processing?

No not _why ruby-processing, but what might make you want to explore ruby-processing?Well if you are coming from a ruby background, the answer is quite obvious you can write processing sketches in ruby (a language you know and love), and thanks to jruby mirroring regular ruby you are pretty much up to date (the same cannot be said for jython on which processing.py is based, which shows no signs of catching up with python any time soon).
Vanilla processing itself is in a bit of time-warp and only really supports language features consistent with java 5 (whereas java 7 is now the de-facto standard).
Perhaps it is the "permissive" nature of the ruby-language that is one of its most attractive features, which is well illustrated in the following sketch. Where you can readily extend the behaviour of a java class (PVector in this case), and what is more it is possible to do the same to an instance of a ruby array, ruby is a language that just lets you get things done (it does not stand in the way). Also it can be extremely elegant and expressive.
Then there is the community, rubyists are generally warm, welcoming and open, and thanks to the ecology (rubygems and the like eg json gem see example use here) you will find it is a lot easier to collaborate in ruby than many other programming environments (we also do not have a huge repo containing legacy code cf vanilla processing 1.38Gb+ they must be joking).
# Drawolver: draw 2D & revolve 3D

# Example to show how to extend Ruby classes in a useful way and how to
# use PVector and the Array is extended to yield one_of_each 
# pair of pts. See the drawolver library. Also features the use each_cons, 
# possibly a rare use for this ruby Enumerable method?
# 2010-03-22 - fjenett (last revised by monkstone 2013-09-13)

attr_reader :drawing_mode, :points, :rot_x, :rot_y, :vertices

module ExtendedArray
  # send one item from each array, expects array to be 2D:
  # array [[1,2,3], [a,b,c]] sends
  # [1,a] , [2,b] , [3,c]
  def one_of_each( &block )
    i = 0
    one = self[0]
    two = self[1]
    mi = one.length > two.length ? two.length : one.length
    while i < mi do
      yield( one[i], two[i] )
      i += 1
    end
  end
end


def setup
  size 1024, 768, P3D
  frame_rate 30
  reset_scene
end

def draw
  background 0
  if (!drawing_mode)
    translate(width/2, height/2)
    rotate_x rot_x
    rotate_y rot_y
    @rot_x += 0.01
    @rot_y += 0.02
    translate(-width/2, -height/2)
  end
  no_fill
  stroke 255
  points.each_cons(2) { |ps, pe| line ps.x, ps.y, pe.x, pe.y}

  if (!drawing_mode)
    stroke 125
    fill 120
    lights
    ambient_light 120, 120, 120
    vertices.each_cons(2) do |r1, r2|
      begin_shape(TRIANGLE_STRIP)
      ext_array = [r1,r2].extend ExtendedArray # extend an instance of Array
      ext_array.one_of_each do |v1, v2|
        vertex v1.x, v1.y, v1.z
        vertex v2.x, v2.y, v2.z
      end
      end_shape
    end
  end
end

def reset_scene
  @drawing_mode = true
  @points = []
  @rot_x = 0.0
  @rot_y = 0.0
end

def mouse_pressed
  reset_scene
  points << RPVector.new(mouse_x, mouse_y)
end

def mouse_dragged
  points << RPVector.new(mouse_x, mouse_y)
end

def mouse_released
  points << RPVector.new(mouse_x, mouse_y)
  recalculate_shape
end

def recalculate_shape
  @vertices = []
  points.each_cons(2) do |ps, pe|
    b = points.last - points.first
    len = b.mag
    b.normalize
    a = ps - points.first
    dot = a.dot b
    b = b * dot
    normal = points.first + b
    c = ps - normal
    nlen = c.mag
    vertices << []
    (0..TWO_PI).step(PI/15) do |ang|
      e = normal + c * cos(ang)
      e.z = c.mag * sin(ang)
      vertices.last << e
    end
  end
  @drawing_mode = false
end

# a wrapper around PVector that implements operators methods for +, -, *, /
#
class RPVector < Java::ProcessingCore::PVector

  def + (vect)
    RPVector.new self.x + vect.x, self.y + vect.y, self.z + vect.z
  end

  def - (vect)
    RPVector.new self.x - vect.x, self.y - vect.y, self.z - vect.z
  end

  def * (scalar)
    RPVector.new self.x * scalar, self.y * scalar, self.z * scalar
  end

  def / (scalar)
    RPVector.new(self.x / scalar, self.y / scalar, self.z / scalar) unless scalar == 0
  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