Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
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
Labels:
context free,
DSL,
penrose tiling,
ruby processing
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
#########################
# 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
Labels:
context free,
DSL,
path,
ruby processing
Monday, 17 May 2010
Colored Penrose Tiling using LSystems
Colored Penrose Tiling uses my lsystem library see previous post for library/grammar.rb
#######################################################
# penrose tiling in ruby processing using LSystems
# in ruby-processing by Martin Prout
######################################################
require 'penrose_colored'
class Penrose < Processing::App
load_libraries "grammar"
attr_reader :penrose
def setup
size 800, 800
stroke_weight 2
smooth
@penrose = PenroseColored.new
penrose.create_grammar 5
no_loop
end
def draw
background 0
penrose.render
end
end
#############################
# penrose_colored.rb
#############################
class PenroseColored
include Processing::Proxy
attr_reader :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
XPOS = 0 # placeholders for pen array
YPOS = 1
ANGLE = 2
COL = 3
DELTA = PI/5 # radians or 36 degrees
RED = 70<<24|200<<16|0<<8|0 # using bit operations to set color int
BLUE = 70<<24|0<<16|0<<8|200
def initialize
@axiom = "[X]2+[X]2+[X]2+[X]2+[X]" # Note use abbrev form in axiom and rule
@grammar = Grammar.new axiom # here number equals number of repeats
@grammar.add_rule "F", "" # delete 'F'
@grammar.add_rule "W", "YBF2+ZRF4-XBF[-YBF4-WRF]2+" # substitution rules
@grammar.add_rule "X", "+YBF2-ZRF[3-WRF2-XBF]+"
@grammar.add_rule "Y", "-WRF2+XBF[3+YBF2+ZRF]-"
@grammar.add_rule "Z", "2-YBF4+WRF[+ZRF4+XBF]2-XBF"
@start_length = 1000.0
@theta = 0
@xpos = width/2
@ypos = height/2
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing in my render
# function I have ignored the processing translate/rotate functions in favour
# of the direct calculation of the new x and y positions, thus avoiding such
# affine transformations.
##############################################################################
def render()
repeats = 1
pen = [xpos, ypos, theta, :R] # simple array for pen, symbol :R = red
stack = [] # simple array for stack
production.scan(/./).each do |element|
case element
when 'F'
pen = draw_line(pen, draw_length)
when '+'
pen[ANGLE] += DELTA * repeats
repeats = 1
when '-'
pen[ANGLE] -= DELTA * repeats
repeats = 1
when '['
stack.push(pen.dup) # push a copy current pen to stack
when ']'
pen = stack.pop # assign current pen to instance off the stack
when 'R', 'B'
pen[COL] = element.to_sym # set pen color as symbol
when 'W', 'X', 'Y', 'Z'
when '1', '2', '3', '4'
repeats = Integer(element)
else puts "Character '#{element}' not in grammar"
end
end
end
#####################################################
# create grammar from axiom and # rules (adjust scale)
#####################################################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = grammar.generate gen
end
private
####################################################################
# draws line using current pen position, color and length parameters
# returns a pen corresponding to the new position
###################################################################
def draw_line(pen, length)
stroke (pen[COL] == :R)? RED : BLUE
new_xpos = pen[XPOS] - length * cos(pen[ANGLE])
new_ypos = pen[YPOS] - length * sin(pen[ANGLE])
line(pen[XPOS], pen[YPOS], new_xpos, new_ypos) # draw line
return [new_xpos, new_ypos, pen[ANGLE], pen[COL]] # return pen @ new pos
end
end
#######################################################
# penrose tiling in ruby processing using LSystems
# in ruby-processing by Martin Prout
######################################################
require 'penrose_colored'
class Penrose < Processing::App
load_libraries "grammar"
attr_reader :penrose
def setup
size 800, 800
stroke_weight 2
smooth
@penrose = PenroseColored.new
penrose.create_grammar 5
no_loop
end
def draw
background 0
penrose.render
end
end
#############################
# penrose_colored.rb
#############################
class PenroseColored
include Processing::Proxy
attr_reader :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
XPOS = 0 # placeholders for pen array
YPOS = 1
ANGLE = 2
COL = 3
DELTA = PI/5 # radians or 36 degrees
RED = 70<<24|200<<16|0<<8|0 # using bit operations to set color int
BLUE = 70<<24|0<<16|0<<8|200
def initialize
@axiom = "[X]2+[X]2+[X]2+[X]2+[X]" # Note use abbrev form in axiom and rule
@grammar = Grammar.new axiom # here number equals number of repeats
@grammar.add_rule "F", "" # delete 'F'
@grammar.add_rule "W", "YBF2+ZRF4-XBF[-YBF4-WRF]2+" # substitution rules
@grammar.add_rule "X", "+YBF2-ZRF[3-WRF2-XBF]+"
@grammar.add_rule "Y", "-WRF2+XBF[3+YBF2+ZRF]-"
@grammar.add_rule "Z", "2-YBF4+WRF[+ZRF4+XBF]2-XBF"
@start_length = 1000.0
@theta = 0
@xpos = width/2
@ypos = height/2
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing in my render
# function I have ignored the processing translate/rotate functions in favour
# of the direct calculation of the new x and y positions, thus avoiding such
# affine transformations.
##############################################################################
def render()
repeats = 1
pen = [xpos, ypos, theta, :R] # simple array for pen, symbol :R = red
stack = [] # simple array for stack
production.scan(/./).each do |element|
case element
when 'F'
pen = draw_line(pen, draw_length)
when '+'
pen[ANGLE] += DELTA * repeats
repeats = 1
when '-'
pen[ANGLE] -= DELTA * repeats
repeats = 1
when '['
stack.push(pen.dup) # push a copy current pen to stack
when ']'
pen = stack.pop # assign current pen to instance off the stack
when 'R', 'B'
pen[COL] = element.to_sym # set pen color as symbol
when 'W', 'X', 'Y', 'Z'
when '1', '2', '3', '4'
repeats = Integer(element)
else puts "Character '#{element}' not in grammar"
end
end
end
#####################################################
# create grammar from axiom and # rules (adjust scale)
#####################################################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = grammar.generate gen
end
private
####################################################################
# draws line using current pen position, color and length parameters
# returns a pen corresponding to the new position
###################################################################
def draw_line(pen, length)
stroke (pen[COL] == :R)? RED : BLUE
new_xpos = pen[XPOS] - length * cos(pen[ANGLE])
new_ypos = pen[YPOS] - length * sin(pen[ANGLE])
line(pen[XPOS], pen[YPOS], new_xpos, new_ypos) # draw line
return [new_xpos, new_ypos, pen[ANGLE], pen[COL]] # return pen @ new pos
end
end
Labels:
LSystems,
penrose tiling
Monday, 10 May 2010
Op Art using Voronoi Cell, Ruby Processing
load_libraries 'mesh' # http://www.leebyron.com/else/mesh/
import 'megamu.mesh.Voronoi'
require 'set'
attr_reader :voronoi, :points, :left, :right, :top, :bottom
def setup()
size(1000, 1000)
color_mode HSB, 1.0
@points = Set.new
@points.clear
@left = MRect.new 10, height/2, 20, height, 20
@right = MRect.new 990, height/2, 20, height, 20
@top = MRect.new width/2, 10, width, 20, 20
@bottom = MRect.new width/2, 990, width, 20, 20
smooth
# no_loop
end
def draw
@points.clear
shape = MPoly.new width/3, height/3, 8, 150, 4
shape1 = MPoly.new width/2, height/2, 8, 120, 4
shape2 = MPoly.new width*0.667, height*0.667, 8, 150, 4
shape3 = MPoly.new width/3, height*0.667, 3, 150, 4
shape4 = MPoly.new width*0.667, height/3, 3, 150, 4
@points.merge(left.points)
@points.merge(right.points)
@points.merge(top.points)
@points.merge(bottom.points)
@points.merge(shape.points)
@points.merge(shape1.points)
@points.merge(shape2.points)
@points.merge(shape3.points)
@points.merge(shape4.points)
voronoi = Voronoi.new((@points.to_a).to_java(Java::float[]))
regions = voronoi.get_regions
regions.each do |region|
region_coordinates = region.get_coords
fill(rand)
region.draw(self)
end
end
class MRect # border for now
attr_reader :x, :y, :w, :h, :skip, :points
def initialize x, y, w, h, skip
@x = x - w/2
@y = y - h/2
@w = w
@h = h
@skip = skip
@points = calculate_points
end
def calculate_points
mpoints = Array.new
(w/skip).times do
(h/skip).times do
mpoints.push([rand*w + x, rand*h + y])
end
end
return mpoints
end
end
class MPoly # shape
attr_reader :x, :y, :sides, :size, :theta, :delta, :repeats, :len, :points
def initialize x, y, sides, size, density
@delta = -PI/sides
@x = x
@y = y
@sides = sides
@size = size
@theta = 2 * PI/sides
@repeats = density
@len = size/repeats
@points = calculate_points
end
def calculate_points
mpoints = Array.new
repeats.times do |i|
sides.times do |j|
mpoint_x = x + (i + 1) * len * cos(j * theta + delta)
mpoint_y = y - (i + 1) * len * sin(j * theta + delta)
mpoints.push [mpoint_x, mpoint_y]
end
end
return mpoints
end
# def rotate delta
# @delta += delta
# calculate_points
# end
end
Labels:
pop art,
ruby processing,
voronoi mesh
Saturday, 8 May 2010
Voronoi Cells from the Coordinates of A Penrose Tiling
Here's an idea to create 'regular' voronoi cells from fractal dimensions. Well recently I was working on Penrose Tiling created using LSystems, so that's were I started.
#########################################################
# Voronoi cells centered on penrose tiling coordinates
# generated by a Lindenmayer System in ruby-processing
# by Martin Prout
#######################################################
require 'penrose_tiling'
require 'set'
load_libraries 'grammar', 'mesh'
import 'megamu.mesh.Voronoi'
attr_reader :regions
def setup
size 300, 300
stroke 255, 255, 0 # yellow mesh
stroke_weight 3
fill 255, 0, 0 # red regions
smooth
penrose = PenroseTiling.new
penrose.create_grammar 4
set = penrose.get_points
voronoi = Voronoi.new((set.to_a).to_java(Java::float[]))
@regions = voronoi.get_regions
no_loop
end
def draw
background 0
regions.each do |region|
region_coordinates = region.get_coords
region.draw(self)
end
end
#######################################
# penrose_tiling.rb
# #####################################
require 'set'
class PenroseTiling
include Processing::Proxy
attr_reader :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
XPOS = 0 # placeholders for turtle array
YPOS = 1
ANGLE = 2
DELTA = PI/5 # radians or 36 degrees
def initialize
@axiom = "[X]2+[X]2+[X]2+[X]2+[X]" # Note use of abbreviated rule
@grammar = Grammar.new axiom # here number equals number of repeats
@grammar.add_rule "F", ""
@grammar.add_rule "X", "+YF2-ZF[3-WF2-XF]+"
@grammar.add_rule "Y", "-WF2+XF[3+YF2+ZF]-"
@grammar.add_rule "Z", "2-YF4+WF[+ZF4+XF]2-XF"
@grammar.add_rule "W", "YF2+ZF4-XF[-YF4-WF]2+"
@start_length = 300.0
@theta = 0
@xpos = width/2
@ypos = height/2
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing in my get_points
# function I have ignored the processing translate/rotate functions in favour
# of the direct calculation of the new x and y positions, thus avoiding such
# affine transformations. Returns a Set of unique [x, y] coordinates.
##############################################################################
def get_points()
points = Set.new
repeats = 1
turtle = [xpos, ypos, theta] # simple array for turtle
points.add([xpos.round, ypos.round])
stack = [] # simple array for stack
production.scan(/./).each do |element|
case element
when 'F'
turtle = next_point(turtle, draw_length)
points.add([turtle[XPOS].round, turtle[YPOS].round]) unless (turtle[XPOS] < 0) || (turtle[YPOS] < 0)
when '+'
turtle[ANGLE] += DELTA * repeats
repeats = 1
when '-'
turtle[ANGLE] -= DELTA * repeats
repeats = 1
when '['
stack.push(turtle.clone) # push a copy current turtle to stack
when ']'
turtle = stack.pop # assign current turtle a instance popped from the stack
when 'W', 'X', 'Y', 'Z'
when '1', '2', '3', '4'
repeats = Integer(element)
else puts "Character '#{element}' not in grammar"
end
end
return points
end
##############################
# create grammar from axiom and # rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = grammar.generate gen
end
private
######################################################
# uses current turtle and length parameters to calculate
# a turtle corresponding to the new position
######################################################
def next_point(turtle, length)
new_xpos = turtle[XPOS] + length * cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * sin(turtle[ANGLE])
return [new_xpos, new_ypos, turtle[ANGLE]]
end
end
For the grammar library see my PenroseTiling post.
#########################################################
# Voronoi cells centered on penrose tiling coordinates
# generated by a Lindenmayer System in ruby-processing
# by Martin Prout
#######################################################
require 'penrose_tiling'
require 'set'
load_libraries 'grammar', 'mesh'
import 'megamu.mesh.Voronoi'
attr_reader :regions
def setup
size 300, 300
stroke 255, 255, 0 # yellow mesh
stroke_weight 3
fill 255, 0, 0 # red regions
smooth
penrose = PenroseTiling.new
penrose.create_grammar 4
set = penrose.get_points
voronoi = Voronoi.new((set.to_a).to_java(Java::float[]))
@regions = voronoi.get_regions
no_loop
end
def draw
background 0
regions.each do |region|
region_coordinates = region.get_coords
region.draw(self)
end
end
#######################################
# penrose_tiling.rb
# #####################################
require 'set'
class PenroseTiling
include Processing::Proxy
attr_reader :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
XPOS = 0 # placeholders for turtle array
YPOS = 1
ANGLE = 2
DELTA = PI/5 # radians or 36 degrees
def initialize
@axiom = "[X]2+[X]2+[X]2+[X]2+[X]" # Note use of abbreviated rule
@grammar = Grammar.new axiom # here number equals number of repeats
@grammar.add_rule "F", ""
@grammar.add_rule "X", "+YF2-ZF[3-WF2-XF]+"
@grammar.add_rule "Y", "-WF2+XF[3+YF2+ZF]-"
@grammar.add_rule "Z", "2-YF4+WF[+ZF4+XF]2-XF"
@grammar.add_rule "W", "YF2+ZF4-XF[-YF4-WF]2+"
@start_length = 300.0
@theta = 0
@xpos = width/2
@ypos = height/2
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing in my get_points
# function I have ignored the processing translate/rotate functions in favour
# of the direct calculation of the new x and y positions, thus avoiding such
# affine transformations. Returns a Set of unique [x, y] coordinates.
##############################################################################
def get_points()
points = Set.new
repeats = 1
turtle = [xpos, ypos, theta] # simple array for turtle
points.add([xpos.round, ypos.round])
stack = [] # simple array for stack
production.scan(/./).each do |element|
case element
when 'F'
turtle = next_point(turtle, draw_length)
points.add([turtle[XPOS].round, turtle[YPOS].round]) unless (turtle[XPOS] < 0) || (turtle[YPOS] < 0)
when '+'
turtle[ANGLE] += DELTA * repeats
repeats = 1
when '-'
turtle[ANGLE] -= DELTA * repeats
repeats = 1
when '['
stack.push(turtle.clone) # push a copy current turtle to stack
when ']'
turtle = stack.pop # assign current turtle a instance popped from the stack
when 'W', 'X', 'Y', 'Z'
when '1', '2', '3', '4'
repeats = Integer(element)
else puts "Character '#{element}' not in grammar"
end
end
return points
end
##############################
# create grammar from axiom and # rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = grammar.generate gen
end
private
######################################################
# uses current turtle and length parameters to calculate
# a turtle corresponding to the new position
######################################################
def next_point(turtle, length)
new_xpos = turtle[XPOS] + length * cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * sin(turtle[ANGLE])
return [new_xpos, new_ypos, turtle[ANGLE]]
end
end
For the grammar library see my PenroseTiling post.
Labels:
LSystems,
penrose tiling,
ruby-processing,
voronoi mesh
Random Voronoi Sketch
Here is a simple sketch, that flashes new random voronoi cells, with random fill.
load_libraries 'mesh' # http://www.leebyron.com/else/mesh/
import 'megamu.mesh.Voronoi'
require 'set'
attr_reader :voronoi, :points
def setup()
size(300, 300)
color_mode HSB, 1.0
end
def draw
points = Set.new
10.times do
10.times do
points.add([rand*300, rand*300])
end
end
voronoi = Voronoi.new((points.to_a).to_java(Java::float[]))
regions = voronoi.get_regions
regions.each do |region|
region_coordinates = region.get_coords
fill(rand, rand, rand)
region.draw(self)
end
end
load_libraries 'mesh' # http://www.leebyron.com/else/mesh/
import 'megamu.mesh.Voronoi'
require 'set'
attr_reader :voronoi, :points
def setup()
size(300, 300)
color_mode HSB, 1.0
end
def draw
points = Set.new
10.times do
10.times do
points.add([rand*300, rand*300])
end
end
voronoi = Voronoi.new((points.to_a).to_java(Java::float[]))
regions = voronoi.get_regions
regions.each do |region|
region_coordinates = region.get_coords
fill(rand, rand, rand)
region.draw(self)
end
end
Labels:
ruby processing,
voronoi mesh
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
Labels:
context free,
DSL,
flower
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
#########################
# 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
Labels:
context free,
DSL,
PCR gel,
ruby processing
Wednesday, 5 May 2010
Penrose Tiling Ruby-Processing LSystems
######################################################
# A Lindenmayer System in ruby-processing by Martin Prout
# Loosely based on a processing PenroseTiling sketch
# by Geraldine Sarmiento
# tiling.rb
######################################################
require 'penrose_tiling'
class Penrose < Processing::App
load_libraries "grammar"
attr_reader :penrose
def setup
size 1000, 1000
stroke 255, 60
stroke_weight 2
smooth
@penrose = PenroseTiling.new
penrose.create_grammar 4
no_loop
end
def draw
background 0
penrose.render
end
end
########################################
# penrose_tiling.rb
########################################
class PenroseTiling
include Processing::Proxy
attr_reader :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
XPOS = 0 # placeholders for turtle array
YPOS = 1
ANGLE = 2
DELTA = PI/5 # radians or 36 degrees
def initialize
@axiom = "[X]2+[X]2+[X]2+[X]2+[X]" # Note use of abbreviated rule
@grammar = Grammar.new axiom # here number equals number of repeats
@grammar.add_rule "F", ""
@grammar.add_rule "X", "+YF2-ZF[3-WF2-XF]+"
@grammar.add_rule "Y", "-WF2+XF[3+YF2+ZF]-"
@grammar.add_rule "Z", "2-YF4+WF[+ZF4+XF]2-XF"
@grammar.add_rule "W", "YF2+ZF4-XF[-YF4-WF]2+"
@start_length = 1000.0
@theta = 0
@xpos = width/2
@ypos = height/2
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing in my render
# function I have ignored the processing translate/rotate functions in favour
# of the direct calculation of the new x and y positions, thus avoiding such
# affine transformations.
##############################################################################
def render()
repeats = 1
turtle = [xpos, ypos, theta] # a simple array for turtle
stack = [] # a simple array for stack
production.scan(/./).each do |element|
case element
when 'F'
turtle = draw_line(turtle, draw_length)
when '+'
turtle[ANGLE] += DELTA * repeats
repeats = 1
when '-'
turtle[ANGLE] -= DELTA * repeats
repeats = 1
when '['
stack.push(turtle.dup) # push a copy current turtle to stack
when ']'
turtle = stack.pop # assign current turtle a instance popped from the stack
when 'W', 'X', 'Y', 'Z'
when '2', '3', '4'
repeats = Integer(element)
else puts "Character '#{element}' not in grammar"
end
end
end
##############################
# create grammar from axiom and # rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = grammar.generate gen
end
private
######################################################
# draws line using current turtle and length parameters
# returns a turtle corresponding to the new position
######################################################
def draw_line(turtle, length)
new_xpos = turtle[XPOS] - length * cos(turtle[ANGLE])
new_ypos = turtle[YPOS] - length * sin(turtle[ANGLE])
line(turtle[XPOS], turtle[YPOS], new_xpos, new_ypos)
return [new_xpos, new_ypos, turtle[ANGLE]]
end
end
#############################################################
# library/grammar.rb
# Non-stochastic grammar
# with unique premise/rules
############################################################
class Grammar
attr_accessor :axiom, :rules
def initialize axiom
@axiom = axiom
@rules = Hash.new
end
def add_rule premise, rule
rules.store(premise, rule)
end
##########################################
# replace each pre char with a unique rule
##########################################
def new_production production
production.gsub!(/./) { |c| (r = @rules[c]) ? r : c }
end
##########################################
# control the number of iterations
# default 0, returns the axiom
##########################################
def generate repeat = 0
prod = axiom
repeat.times do
prod = new_production prod
end
return prod
end
end
Labels:
l-system fractal,
penrose tiling,
ruby processing
Subscribe to:
Posts (Atom)
Followers
Blog Archive
-
▼
2010
(73)
-
▼
May
(9)
- Towards Penrose Tiling Using ruby-processing conte...
- Ruby Processing Context Free DSL (how to do a cfdg...
- Colored Penrose Tiling using LSystems
- Op Art using Voronoi Cell, Ruby Processing
- Voronoi Cells from the Coordinates of A Penrose Ti...
- Random Voronoi Sketch
- A Simple flower using ruby processing context free...
- Custom hbar shape for ruby processing Context Free...
- Penrose Tiling Ruby-Processing LSystems
-
▼
May
(9)
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