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

Showing posts with label vecmath. Show all posts
Showing posts with label vecmath. Show all posts

Saturday, 19 July 2014

Ruby-processing at version 2.5.0 on github

Can't wait to try it out? The latest version of ruby-processing is now available at github. It is a bit trickier to build than previous versions and requires an installed jruby, ruby-compiler (gem) see instructions here. Actually the build is really easy just do "rake" and you are done (but you need to set your procssing root and you might not have ruby-compiler installed?). The compiled jruby extensions offer an interesting way in which to extend ruby-processing to use java libraries (not necessarily restricted to processing libraries), but especially with libraries that rely on reflection in their interface. The best exemplar of this the ArcBall utility, that uses reflection under the hood (to register pre()) so we can implement ArcBall functionality in a ruby processing sketch in one line (updates are sent to sketch via pre()). Obvious candidates for such an approach is java JBox2D, so would not have to rely on Dan Schiffmans PBox2D (now Box2DProcessing) or Ricard Marxers fisica, which could build on ruby-processings Vec2D.

ArcBall sketch code:-
# 1. drag mouse to rotate arcball
# 2. hold down x, y, or z to constrain arcball rotation to that axis
#

load_library :vecmath

# initialize arcball in setup and you are done...........

  # either provide arc ball center (sketch is translated to center)

  ArcBall.init(self, width/2.0, height/2.0)

  # or alternative form, where camera is set to point at center

  ArcBall.init(self)

DegLut sketch code:-
# DegLut.sin() and DegLut.cos() values

load_library :fastmath
# draw minute markers for analogue clock
  (0..360).step(6) do |a|
    x = 100 + DegLut.cos(a) * 72
    y = 100 + DegLut.sin(a) * 72
    point x, y
  end

A complete example showing how to initialize AppRender, and use it to allow Vec2D to be written (by sketch authors) directly as PApplet vertices
#
# Morph. 
# 
# Changing one shape into another by interpolating
# vertices from one to another
#
load_library :vecmath

attr_reader :circle, :square, :morph, :state, :v1, :v2, :renderer

ALPHA = Math::PI / 4.0
OMEGA = TAU + ALPHA
THETA = Math::PI / 20.0

def setup
  size(640, 360)
  @circle = []
  @square = []
  @morph = []
  @state = false
  @renderer = AppRender.new(self)
  frame_rate(15)
  # Create a circle using vectors pointing from center
  (ALPHA .. OMEGA).step(THETA) do |angle|
    # Note we are not starting from 0 in order to match the
    # path of a circle.  
    circle << Vec2D.from_angle(angle) * 100
    # Let's fill out morph Array with blank Vec2Ds while we are at it
    morph << Vec2D.new
  end

  # A square is a bunch of vertices along straight lines
  # Top of square
  (-50 .. 50).step(10) do |x|
    square << Vec2D.new(x, -50)
  end
  # Right side
  (-50 .. 50).step(10) do |y|
    square << Vec2D.new(50, y)
  end
  # Bottom, NB: can't negative step ruby so use your loaf
  5.downto(-5) do |x|
    square << Vec2D.new(x * 10, 50)
  end
  # Left side
  5.downto(-5) do |y|
    square << Vec2D.new(-50, y * 10)
  end
end

def draw
  background(51)

  # We will keep how far the vertices are from their target
  @total_distance = 0

  # Look at each vertex
  circle.length.times do |i|
    # Are we lerping to the circle or square?
    v1 = (state)?  circle[i] : square[i]
    # Get the vertex we will draw
    v2 = morph[i]

    # Lerp to the target
    v2.lerp!(v1, 0.1)
    # Check how far we are from target
    @total_distance += v1.dist(v2)
  end

  # If all the vertices are close, switch shape
  if (@total_distance < 0.08)
    @state = !state
  end

  # Draw relative to center
  translate(width/2, height/2)
  stroke_weight(4)
  # Draw a polygon that makes up all the vertices
  begin_shape
  no_fill
  stroke(255)
  morph.each do |v|
    v.to_vertex(renderer)
  end
  end_shape(CLOSE)
end
New updated version since (26 July 2014), attempts to set processing root automatically if there is no ~/.rp5rc. JRUBY config option allows users to default to using jruby-complete without the --nojruby flag.

Thursday, 15 May 2014

Lambda clock (featuring DegLut tables now only in JRubyArt, soon ruby-processing)

There exists this vanilla processing example, which is ideal for our degree sin/cos lookup tables (and a more functional approach in ruby processing using lambda). Basically if you can do the math then I think you should (rather than hide behind dubious vanilla processing map/normalize utility they are not helping you they are hindering your brain).
# The current time can be read with the second(), minute(), 
# and hour() functions. In this example, DegLut.sin() and DegLut.cos() values
# are used to set the position of the hands, perfect for degree precision Lookup Table.
load_library :fastmath

def setup
  size 200, 200
  stroke 255
  smooth 8
end

def draw
  background 0
  fill 80
  no_stroke
  # adj factor to map 0-60 to 0-360 (seconds/minutes) & 0-12 to 0-360 (hours)
  # since angles for DegLut.sin() and DegLut.cos() start at 3 o'clock we
  # subtract 90 degrees to make them start at the top.
  clock_x = ->(val, adj, length){DegLut.cos((val * adj).to_i - 90) * length + width / 2}
  clock_y = ->(val, adj, length){DegLut.sin((val * adj).to_i - 90) * length + height / 2}
  ellipse 100, 100, 160, 160
  stroke 220
  stroke_weight 6
  line( 100, 100, clock_x.call(hour % 12 + (minute / 60.0), 30, 50), clock_y.call(hour % 12 + (minute / 60.0), 30, 50) )
  stroke_weight 3
  line( 100, 100, clock_x.call(minute + (second / 60.0), 6, 60), clock_y.call(minute + (second / 60.0), 6, 60) )
  stroke 255, 0, 0
  stroke_weight 1
  line( 100, 100, clock_x.call(second, 6, 72), clock_y.call(second, 6, 72) )
  # Draw the minute ticks
  stroke_weight 2
  stroke 255
  (0..360).step(6) do |a|
    x = 100 + DegLut.cos(a) * 72
    y = 100 + DegLut.sin(a) * 72
    point x, y
  end
end

Tuesday, 18 February 2014

Nature of Code examples now ported to ruby

Thanks to Pierre-Pat, Shiffmans the nature of code examples have now been ported to ruby-processing, get them here. Naturally enough PVectors were retained in the examples (the code after all originally comes from Dan Shiffman). I am not a big fan of the PVector class (which I think is trying to do too much, which is why I created the vecmath library for ruby-processing) so here is one of examples that could easily use the Vec2D class instead of PVector:-
# The Nature of Code
# http://natureofcode.com
# NOC_1_11_motion101_acceleration_array

load_library :vecmath

class Mover
  TOP_SPEED = 6
  attr_reader :location, :velocity, :topspeed_squared

  def initialize(width, height)
    @location = Vec2D.new(rand(width/2), rand(height/2))
    @velocity = Vec2D.new(0, 0)
    @topspeed_squared = TOP_SPEED * TOP_SPEED
  end

  def update
    mouse = Vec2D.new(mouse_x, mouse_y)
    acceleration = mouse - location
    acceleration.normalize!
    acceleration *= 0.2

    @velocity += acceleration
    @velocity.set_mag(TOP_SPEED) if velocity.mag_squared > topspeed_squared
    @location += velocity
  end

  def display
    stroke(0)
    stroke_weight(2)
    fill(127)
    ellipse(location.x, location.y, 48, 48)
  end
end

def setup
  size(800, 200)
  @movers = Array.new(20) { Mover.new(width, height) }
end

def draw
  background(255)

  @movers.each do |mover|
    mover.update
    mover.display
  end
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