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

Showing posts with label inner class. Show all posts
Showing posts with label inner class. Show all posts

Sunday, 5 April 2015

Replacing Processing::Proxy in ruby-processing

I have often thought that Processing::Proxy in ruby-processing is a bit of hack (further it doesn't always do what you need to mimic vanilla processings "inner" class access to methods/variables), here is a more respectable alternative using forwardable. As a bonus shows the neat Vec3D :to_vertex method in action:-
require 'forwardable'
load_libraries :icosahedron, :vecmath

def setup
  size 640, 360, P3D
  @ico1 = Icosahedron.new self, 75.0
  @ico2 = Icosahedron.new self, 75.0
  @ico3 = Icosahedron.new self, 75.0
end

def draw
  background 0
  lights
  translate(width / 2, height / 2)
  push_matrix
  translate(-width / 3.5, 0)
  rotate_x frame_count * PI / 185
  rotate_y frame_count * PI / -200
  stroke 170, 0, 0
  no_fill
  @ico1.draw
  pop_matrix
  push_matrix
  rotate_x frame_count * PI / 200
  rotate_y frame_count * PI / 300
  stroke 170, 0, 180
  fill 170, 170, 0
  @ico2.draw
  pop_matrix
  push_matrix
  translate(width / 3.5, 0)
  rotate_x frame_count * PI / -200
  rotate_y frame_count * PI / 200
  no_stroke
  fill 0, 0, 185
  @ico3.draw
  pop_matrix
end
Here is the library class that uses forwardable:-
# Example of replacing Processing::Proxy with extend Forwardable
# And using Vec3D :to_vertex function
class Icosahedron
  extend Forwardable   # replacing Processing::Proxy mixin
  def_delegators(:@app, :begin_shape, :end_shape)
  attr_reader :r, :app, :renderer

  def initialize(app, radius)
    @r = radius
    @app = app
    @renderer = AppRender.new(app)
  end

  ##
  # Draw an icosahedron defined by a radius r.
  #
  def draw
    # Calculate vertex data for an icosahedron inscribed by a sphere radius 'r'.
    # Use 4 Golden Ratio rectangles as the basis.
    phi = (1.0 + Math.sqrt(5.0)) / 2.0
    h = r / Math.sqrt(1.0 + phi * phi)
    v =
    [
      Vec3D.new(0, -h, h * phi), Vec3D.new(0, -h, -h * phi),
      Vec3D.new(0, h, -h * phi), Vec3D.new(0, h, h * phi),
      Vec3D.new(h, -h * phi, 0), Vec3D.new(h, h * phi, 0),
      Vec3D.new(-h, h * phi, 0), Vec3D.new(-h, -h * phi, 0),
      Vec3D.new(-h * phi, 0, h), Vec3D.new(-h * phi, 0, -h),
      Vec3D.new(h * phi, 0, -h), Vec3D.new(h * phi, 0, h)
    ]

    begin_shape(Java::ProcessingCore::PConstants::TRIANGLES)
    draw_triangle(v[0], v[7], v[4])
    draw_triangle(v[0], v[4], v[11])
    draw_triangle(v[0], v[11], v[3])
    draw_triangle(v[0], v[3], v[8])
    draw_triangle(v[0], v[8], v[7])
    draw_triangle(v[1], v[4], v[7])
    draw_triangle(v[1], v[10], v[4])
    draw_triangle(v[10], v[11], v[4])
    draw_triangle(v[11], v[5], v[10])
    draw_triangle(v[5], v[3], v[11])
    draw_triangle(v[3], v[6], v[5])
    draw_triangle(v[6], v[8], v[3])
    draw_triangle(v[8], v[9], v[6])
    draw_triangle(v[9], v[7], v[8])
    draw_triangle(v[7], v[1], v[9])
    draw_triangle(v[2], v[1], v[9])
    draw_triangle(v[2], v[10], v[1])
    draw_triangle(v[2], v[5], v[10])
    draw_triangle(v[2], v[6], v[5])
    draw_triangle(v[2], v[9], v[6])
    end_shape
  end

  def draw_triangle(p1, p2, p3)
    p1.to_vertex(renderer)
    p2.to_vertex(renderer)
    p3.to_vertex(renderer)
  end
end

Tuesday, 5 May 2009

Inner classes, workaround for ruby processing

Developments are moving a pace over on the processing implementation discourse http://processing.org/discourse/yabb2/YaBB.pl?num=1238452139. As you may have realized that classes in processing are generally inner classes, and so have access to methods of the enclosing PApplet class. This is not the same in ruby however Jeremy Ashkenas aka jashkenas has been busy developing a workaround for ruby processing (including processing as a mixin) which seems quite interesting. Here is an example using my Saucer class, I'm not super keen about my render method it doesn't look too ruby like (inherited from my java processing code):-

# saucer.rb

include Math

class Saucer

        include Processing::Proxy

        # include processing as Mixin

        R1 = 4.0  # class constants that together

        R2 = 3.0  # with PI constants are used

        R3 = 6.0  # to define the Saucer shape

        A1 = 0.25

        A2 = 0.60

        A3 = 0.0

        MAX_THETA = QUARTER_PI/2

        attr_reader :xpos, :ypos, :my_scale, :tilt

        def initialize xpos, ypos

                @xpos = xpos

                @ypos = ypos

                @my_scale = 10.0

                @tilt = 0

        end

        def get_point radius, theta

                x = xpos + (radius * Math.cos(theta + tilt)) *my_scale

                y = ypos + (radius * Math.sin(theta + tilt)) *my_scale

                return x, y

        end

        def set_tilt(theta)

                theta = Saucer::MAX_THETA if theta > Saucer::MAX_THETA

                theta = -Saucer::MAX_THETA if theta < -Saucer::MAX_THETA

                @tilt = theta

        end

        def set_scale(scale)

                @my_scale = scale unless scale < 0

        end

        def render

                smooth

                curve_tightness -0.05

                begin_shape

                x, y = get_point(Saucer::R1, Saucer::A1)

                curve_vertex(x, y)

                x, y = get_point(Saucer::R2, TWO_PI - Saucer::A2)

                curve_vertex(x, y)

                x, y = get_point(Saucer::R2, PI + Saucer::A2)

                curve_vertex(x, y)

                x, y = get_point(Saucer::R1, PI - Saucer::A1)

                curve_vertex(x, y)

                x, y = get_point(Saucer::R2, PI + Saucer::A2)

                vertex(x, y)

                x, y = get_point(Saucer::R3, PI)

                vertex(x, y)

                vertex(x, y)

                x, y = get_point(Saucer::R1, PI - Saucer::A1)

                vertex(x, y)

                vertex(x, y)

                x, y = get_point(Saucer::R1, Saucer::A1)

                vertex(x, y)

                vertex(x, y)

                x, y = get_point(Saucer::R3, Saucer::A3)

                vertex(x, y)

                vertex(x, y)

                end_shape CLOSE

        end

end



Here is the main code:-


require 'saucer'

class MixinsTest < Processing::App

        def setup

                @saucer = Saucer.new 70, 50

                @saucer.set_tilt QUARTER_PI/2

                @saucer1 = Saucer.new 130, 170

                @saucer1.set_scale 15

                @saucer1.set_tilt QUARTER_PI/3

                @saucer2 = Saucer.new 210, 340

                @saucer2.set_scale 25

        end

        def draw

                background 11, 17, 67

                fill 116, 39, 39

                @saucer.render

                fill 255, 0, 0

                @saucer1.render

                @saucer2.render

                save_frame("saucer.png")

        end

end



MixinsTest.new :width => 400, :height => 400, :title => "Inner Test"



Heres the result of running the code 'rp5 run main.rb'

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