Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Sunday, 28 September 2014
Running ribiprocessing from netbeans
Above is a screenshot of me running seeking_neural.rb from Netbeans using ribiprocessing,a really lighweight wrapper for processing. To do this all I needed was the netbeans ruby plugin and then to install (to netbeans) the local gem ribiprocessing-0.1.0.gem.
Labels:
ide,
netbeans,
processing,
ruby
Thursday, 25 September 2014
Light-weight ruby-processing, heavy-weight example
Recently I had cause to mess with Philip Cunninghams Ribiprocessing (a light-weight ruby-processing, I've beefed it up a bit with some helper methods and Vec2D and Deglut jruby extensions). Here is a ruby-processing sketch I translated to work on my modified ribiprocessing (makes use of range clip function, a replacement for processing constrain):-
Update 27 September 2014, turns out ribiprocessing was a project that Philip Cunnigham created as university project but abandoned in favor of clojure!!! Didn't take too much to give it some pretty decent functionality. Update 4 October 2014, I have gone quite a further created a new ruby-processing implementation JRubyArt.
# Based on SeekingNeural example by Daniel Shiffman # The Nature of Code # http://natureofcode.com require 'ribiprocessing' module SeekingNeural class Perceptron # Perceptron is created with n weights and learning constant def initialize(n, c) @weights = Array.new(n) { rand(0..1.0) } @c = c end # Function to train the Perceptron # Weights are adjusted based on vehicle's error def train(forces, error) trained = @weights.zip(forces.map { |f| f.to_a } .map { |a, b| (a * error.x + b * error.y) * @c }) .map { |w, c| (0.0 .. 1.0).clip(w + c) } @weights = trained end # Give me a steering result def feedforward(forces) # Sum all values forces.zip(@weights).map { |a, b| a * b }.reduce(Vec2D.new, :+) # forces.zip(@weights).map { |a, b| a * b }.reduce(:+) end end # Seek # Daniel Shiffman <http://www.shiffman.net> class Vehicle MAX_SPEED = 4 MAX_FORCE = 0.1 attr_reader :brain, :sz, :location, :targets, :desired def initialize(n, x, y) @brain = Perceptron.new(n, 0.001) @acceleration = Vec2D.new @velocity = Vec2D.new @location = Vec2D.new(x, y) @sz = 6.0 end # Method to update location def update(width, height) # Update velocity @velocity += @acceleration # Limit speed @velocity.set_mag(MAX_SPEED) { @velocity.mag > MAX_SPEED } @location += @velocity # Reset acceleration to 0 each cycle @acceleration *= 0 @location.x = (0 .. width).clip location.x @location.y = (0 .. height).clip location.y end def apply_force(force) # We could add mass here if we want A = F / M @acceleration += force end # Here is where the brain processes everything def steer(targets, desired) # Steer towards all targets forces = targets.map { |target| seek(target) } # That array of forces is the input to the brain result = brain.feedforward(forces) # Use the result to steer the vehicle apply_force(result) # Train the brain according to the error error = desired - location brain.train(forces, error) end # A method that calculates a steering force towards a target # STEER = DESIRED MINUS VELOCITY def seek(target) desired = target - location # A vector pointing from the location to the target # Normalize desired and scale to the maximum speed desired.normalize! desired *= MAX_SPEED # Steering = Desired minus velocity steer = desired - @velocity steer.set_mag(MAX_FORCE) { steer.mag > MAX_FORCE } # Limit to a maximum steering force steer end def display(app) # Draw a triangle rotated in the direction of velocity theta = @velocity.heading + Math::PI / 2 app.fill(175) app.stroke(0) app.stroke_weight(1) app.push_matrix app.translate(location.x, location.y) app.rotate(theta) app.begin_shape app.vertex(0, -sz) app.vertex(-sz * 0.5, sz) app.vertex(sz * 0.5, sz) app.end_shape(Java::ProcessingCore.PConstants::CLOSE) app.pop_matrix end end end class Seeking < Ribiprocessing::SimpleApp include SeekingNeural # A Vehicle controlled by a Perceptron attr_reader :targets, :desired, :v def setup size(640, 360) # The Vehicle's desired location @desired = Vec2D.new(width / 2, height / 2) # Create a list of targets make_targets # Create the Vehicle (it has to know about the number of targets # in order to configure its brain) @v = Vehicle.new(targets.size, rand(width), rand(height)) end # Make a random ArrayList of targets to steer towards def make_targets @targets = Array.new(8) { Vec2D.new(rand(width), rand(height)) } end def draw background(255) # Draw a circle to show the Vehicle's goal stroke(0) stroke_weight(2) fill(0, 100) ellipse(desired.x, desired.y, 36, 36) # Draw the targets targets.each do |target| no_fill stroke(0) stroke_weight(2) ellipse(target.x, target.y, 16, 16) line(target.x, target.y - 16, target.x, target.y + 16) line(target.x - 16, target.y, target.x + 16, target.y) end # Update the Vehicle v.steer(targets, desired) v.update(width, height) v.display self end def mouse_pressed make_targets end end Seeking.new title: 'Seeking Neural'
Update 27 September 2014, turns out ribiprocessing was a project that Philip Cunnigham created as university project but abandoned in favor of clojure!!! Didn't take too much to give it some pretty decent functionality. Update 4 October 2014, I have gone quite a further created a new ruby-processing implementation JRubyArt.
Labels:
Dan Shiffman,
ribiprocessing,
ruby-processing,
seeking neural
Saturday, 20 September 2014
Using libraries from processing-3.0a4 in ruby processing
Up to and including processing-2.2.1 the path to sketchbook was/is discovered by "reading" the preferences.txt configuration file for ruby processing. For processing-3.0a4 the name has changed (to allow different libraries/sketches to co-exist for different versions?). For processing-3.0a4 you can set the "sketchbook_path" in the ".rp5rc" file, works for me on linux see yaml file below (will override preferences.txt value).
--- PROCESSING_ROOT: /home/tux/processing-3.0a4 JRUBY: "true" sketchbook_path: /home/tux/sketchbook
Labels:
libraries,
processing-3.0a4,
rp5rc,
ruby-processing
Wednesday, 17 September 2014
Using the Range class in ruby processing
Since ruby-processing-2.6.3 the processing constrain function is actually implemented using the clip function of Range (this method has been added to Range in ruby-processing). However in ruby processing we should probably prefer to use the clip method directly, as I have here in my World class:-
For the sketch using this code see my fork Dan Shiffmans The Nature of Code Examples.
# Class provides an OO way constraining a Mover in a 2D space # use # world = World.new((0..width), (0..height)) # world.constrain_mover(mover) class World attr_reader :xrange, :yrange def initialize(xrange, yrange) @xrange, @yrange = xrange, yrange end # @param mover is expected respond to loc, vel # that in turn respond to x and y getter/setters (Vec2D does this) def constrain_mover(mover) # Note clip functionality, extends Range in ruby-processing unless xrange.cover? mover.loc.x mover.vel.x *= -1 mover.loc.x = xrange.clip mover.loc.x end return if yrange.cover? mover.loc.y mover.vel.y *= -1 mover.loc.y = yrange.clip mover.loc.y end end
For the sketch using this code see my fork Dan Shiffmans The Nature of Code Examples.
Labels:
clip,
constrain,
Dan Shiffman,
range,
ruby-processing,
Vec2D
Monday, 15 September 2014
Include Processing::Proxy to mimic the processing inner classes
If you have been using processing for some time, then you should be aware of the inner classes used by processing to make variables/methods available across classes (strictly non OOP but convenient).
In the processing ide, the use of java inner classes is hidden (because the code is post-processed). However if you look at the generated java you will find that if you create a class in the processing ide, it becomes an inner class. Use of the inner class is there to allow easy access to the methods and variables of the outer class (your sketch). If you graduated from using the processing ide to using Eclipse (see tutorial) or Netbeans (other ides are available) you will know that when you create a new java class you can't use the methods and variables, unless you call the instance of the PApplet from you sketch (typically a PApplet variable parent created in your new class, and the class constructor is used to initialize that variable). To give a similar level of access to that provided by processings inner classes you should include the ruby processing Processing::Proxy module in your sketches (however sketch width, and height are not available). The more 'pure' way to to provide such access is to copy the "Eclipse" way of accessing these variables and methods, and that is what you "should" do to access sketch width and height. The "dirty" way to do it is access the sketches '$app' global variable "width = $app.width" for example. A template for creating Processing::Proxy class (in a separate file) is included in ruby-processing:-
Of course you will give a different more relevant name to your inner classes!!
Then vim inner_class.rb, other editors are available
rp5 create inner_class --inner
Of course you will give a different more relevant name to your inner classes!!
Then vim inner_class.rb, other editors are available
class InnerClass include Processing::Proxy end
Thursday, 4 September 2014
New features in ruby-processing-2.6.2
# Hooky class demonstrates how to use the post_initialize hook, # available since ruby-processing-2.6.2, to add additional attribute # in this case :background as an array of int (splat to color) # Not sure how clever it is to have multiple sketch instances. class Hooky < Processing::App attr_reader :back def setup size 200, 200 background(*back) end def post_initialize(args) @back = (args[:background]) end end red = [200, 0, 0] green = [0, 200, 0] blue = [0, 0, 200] colors = [red, green, blue] colors.each_with_index do |col, i| Hooky.new(x: i * 90, y: i * 90, title: "Hooky #{i}", background: col) end
Read more about post-initialization hooks in POODR by Sandi Metz.
Monday, 1 September 2014
Instrumenting ruby-processing
Enhance your geek credibility by using JMXBeans to monitor your ruby-processing sketch.
See jruby wiki for details. Above was done using a modified version of JRubyArt (the development version of ruby-processing) where I sent --manage flag to jruby when running the sketch.
Labels:
instrumentation.,
JMXBeans
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.
Open a new console and 'vim classic_sketch.rb' or us another suitable editor
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
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
Next create a blue box.
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)...
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)...
Labels:
DSL,
processing,
ruby-processing,
Sandi Metz,
vim,
watch
Subscribe to:
Posts (Atom)
Followers
Blog Archive
-
▼
2014
(79)
-
▼
September
(8)
- Running ribiprocessing from netbeans
- Light-weight ruby-processing, heavy-weight example
- Using libraries from processing-3.0a4 in ruby proc...
- Using the Range class in ruby processing
- Include Processing::Proxy to mimic the processing ...
- New features in ruby-processing-2.6.2
- Instrumenting ruby-processing
- Getting started with ruby-processing for ruby purists
-
▼
September
(8)
About Me
- monkstone
- I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2