Revised as of 16 January 2010 to uses a custom grammar library (see Cesàro fractal in a later post) and various modifications
########################################################
# koch_test.rb uses grammar library
#
# A Koch curve implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'koch'
class KochCurve < Processing::App
load_library :grammar
attr_reader :koch
def setup
size 600, 600
@koch = Koch.new
koch.create_grammar 4
no_loop
end
def draw
background 0
koch.render
end
end
############################
# koch.rb
#
# Koch Curve
###########################
class Koch
include Processing::Proxy
attr_accessor :axiom, :grammar, :start_length, :theta, :production, :draw_length, :xpos, :ypos
XPOS = 0 # placeholders for turtle array
YPOS = 1
ANGLE = 2
DELTA = (Math::PI/180) * 90.0 # convert degrees to radians
def initialize
@axiom = "F-F-F-F"
@grammar = Grammar.new axiom
grammar.add_rule('F', "FF-F-F-F-F-F+F")
@start_length = 10
@theta = 0.0
@xpos = width * 0.6
@ypos = height * 0.8
stroke 255
@production = axiom
@draw_length = start_length
end
def render
turtle = [xpos, ypos, 0.0] # simple array act as turtle
production.scan(/./).each do |element|
case element
when 'F' # NB NOT using affine transforms
turtle = draw_line(turtle, draw_length)
when '+'
turtle[ANGLE] += DELTA
when '-'
turtle[ANGLE] -= DELTA
else
puts "Character '#{element}' is not in grammar"
end
end
end
##############################
# create grammar from axiom and
# rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.75**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 * Math.cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * Math.sin(turtle[ANGLE])
line(turtle[XPOS], turtle[YPOS], new_xpos, new_ypos)
turtle = [new_xpos, new_ypos, turtle[ANGLE]]
end
end
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Monday, 30 November 2009
Koch curve using l-systems
Labels:
koch curve,
Lindenmayer system,
ruby processing
Towards a forest, or too many matrix calls
If you wanted to create a 'forest' using the Lindenmayer system, you might want to avoid too much pushing and popping of the picture matrix. This is a simple example; where you will find that you need to preserve the original context if you want to draw a second 'tree', otherwise you will not be quite sure where it will get placed, and it will almost certainly be canted over to some extent. All this pushing and popping has a memory load, and creates a lot of 'garbage' for the jvm to cleanup.
########################################################
# Toward a forest implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'fplant'
class Forest_Test < Processing::App
attr_reader :fplant, :fplant2
def setup
size 600, 600
@fplant = FPlant.new
@fplant2 = FPlant.new
fplant.simulate 6
fplant2.simulate 6
no_loop
end
def draw
background 0
push_matrix # save original context
translate 200, 550
fplant.render
pop_matrix # restore original context
translate 350, 570
fplant2.render
save_frame "forest.png"
end
end
############################
# fplant.rb
###########################
require 'jcode' ## required until jruby supports ruby 1.9
class FPlant
include Processing::Proxy
DELTA = (Math::PI/180) * 22.5
attr_accessor :axiom, :rule, :rule1, :start_length, :production, :draw_length
def initialize
@axiom = "X"
@rule = "FF"
@rule1 = "F-[[X]+X]+F[+FX]-F" # note nested matrices
@start_length = 200
stroke 0, 255, 0 # ghastly green
stroke_weight 3
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_, rule1_
@draw_length *= 0.5
new_production = prod_
new_production.gsub!('F', rule_)
new_production.gsub!('X', rule1_)
end
def render
production.each_char do |element|
case element
when 'F' # NB using affine transforms
line(0, 0, 0, -draw_length)
translate(0, -draw_length)
when '+'
rotate(+DELTA)
when '-'
rotate(-DELTA)
when '['
push_matrix
when ']'
pop_matrix
when 'X'
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(production, rule, rule1)
end
end
end
Here is a possible solution, implement your own stack, and only store what you need to, it must be more efficient (see later post, my ripped square fractal for an even lighter weight implementation)!!!
########################################################
# Toward a forest implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'fplant'
class Forest_Test < Processing::App
attr_reader :fplant, :fplant2
def setup
size 600, 600
@fplant = FPlant.new 200, 550, Math::PI/2
@fplant2 = FPlant.new 350, 570, Math::PI/2
fplant.simulate 6
fplant2.simulate 6
no_loop
end
def draw
background 0
fplant.render
fplant2.render
save_frame "forest.png"
end
end
############################
# fplant.rb
###########################
require 'jcode' ## required until jruby supports ruby 1.9
require 'stack'
class FPlant
include Processing::Proxy
DELTA = (Math::PI/180) * 22.5
attr_accessor :axiom, :rule, :rule1, :start_length, :production, :draw_length, :stack, :xpos, :ypos, :theta
def initialize x0, y0, angle = 0
@stack = Stack.new
@xpos = x0
@ypos = y0
@theta = angle
@axiom = "X"
@rule = "FF"
@rule1 = "F-[[X]+X]+F[+FX]-F" # note nested matrices
@start_length = 200
stroke 0, 255, 0 # ghastly green
stroke_weight 3
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_, rule1_
@draw_length *= 0.5
new_production = prod_
new_production.gsub!('F', rule_)
new_production.gsub!('X', rule1_)
end
def render
production.each_char do |element|
case element
when 'F' # NB NOT using affine transforms
line(xpos, ypos, (@xpos += -draw_length * Math.cos(theta)), (@ypos += -draw_length * Math.sin(theta)))
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
when '['
stack.push xpos, ypos, theta # using a simple stack to store individual turtle values
when ']'
@xpos, @ypos, @theta = stack.pop
when 'X'
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(production, rule, rule1)
end
end
end
############################
# stack.rb a lightweight stack utility, tuned for turtles
###########################
class Stack # a simple turtle stack
def initialize
@the_stack = []
end
def push(xpos, ypos, angle)
turtle = [xpos, ypos, angle]
@the_stack.push turtle
end
def pop
@the_stack.pop
end
def count
@the_stack.length
end
end
########################################################
# Toward a forest implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'fplant'
class Forest_Test < Processing::App
attr_reader :fplant, :fplant2
def setup
size 600, 600
@fplant = FPlant.new
@fplant2 = FPlant.new
fplant.simulate 6
fplant2.simulate 6
no_loop
end
def draw
background 0
push_matrix # save original context
translate 200, 550
fplant.render
pop_matrix # restore original context
translate 350, 570
fplant2.render
save_frame "forest.png"
end
end
############################
# fplant.rb
###########################
require 'jcode' ## required until jruby supports ruby 1.9
class FPlant
include Processing::Proxy
DELTA = (Math::PI/180) * 22.5
attr_accessor :axiom, :rule, :rule1, :start_length, :production, :draw_length
def initialize
@axiom = "X"
@rule = "FF"
@rule1 = "F-[[X]+X]+F[+FX]-F" # note nested matrices
@start_length = 200
stroke 0, 255, 0 # ghastly green
stroke_weight 3
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_, rule1_
@draw_length *= 0.5
new_production = prod_
new_production.gsub!('F', rule_)
new_production.gsub!('X', rule1_)
end
def render
production.each_char do |element|
case element
when 'F' # NB using affine transforms
line(0, 0, 0, -draw_length)
translate(0, -draw_length)
when '+'
rotate(+DELTA)
when '-'
rotate(-DELTA)
when '['
push_matrix
when ']'
pop_matrix
when 'X'
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(production, rule, rule1)
end
end
end
Here is a possible solution, implement your own stack, and only store what you need to, it must be more efficient (see later post, my ripped square fractal for an even lighter weight implementation)!!!
########################################################
# Toward a forest implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'fplant'
class Forest_Test < Processing::App
attr_reader :fplant, :fplant2
def setup
size 600, 600
@fplant = FPlant.new 200, 550, Math::PI/2
@fplant2 = FPlant.new 350, 570, Math::PI/2
fplant.simulate 6
fplant2.simulate 6
no_loop
end
def draw
background 0
fplant.render
fplant2.render
save_frame "forest.png"
end
end
############################
# fplant.rb
###########################
require 'jcode' ## required until jruby supports ruby 1.9
require 'stack'
class FPlant
include Processing::Proxy
DELTA = (Math::PI/180) * 22.5
attr_accessor :axiom, :rule, :rule1, :start_length, :production, :draw_length, :stack, :xpos, :ypos, :theta
def initialize x0, y0, angle = 0
@stack = Stack.new
@xpos = x0
@ypos = y0
@theta = angle
@axiom = "X"
@rule = "FF"
@rule1 = "F-[[X]+X]+F[+FX]-F" # note nested matrices
@start_length = 200
stroke 0, 255, 0 # ghastly green
stroke_weight 3
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_, rule1_
@draw_length *= 0.5
new_production = prod_
new_production.gsub!('F', rule_)
new_production.gsub!('X', rule1_)
end
def render
production.each_char do |element|
case element
when 'F' # NB NOT using affine transforms
line(xpos, ypos, (@xpos += -draw_length * Math.cos(theta)), (@ypos += -draw_length * Math.sin(theta)))
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
when '['
stack.push xpos, ypos, theta # using a simple stack to store individual turtle values
when ']'
@xpos, @ypos, @theta = stack.pop
when 'X'
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(production, rule, rule1)
end
end
end
############################
# stack.rb a lightweight stack utility, tuned for turtles
###########################
class Stack # a simple turtle stack
def initialize
@the_stack = []
end
def push(xpos, ypos, angle)
turtle = [xpos, ypos, angle]
@the_stack.push turtle
end
def pop
@the_stack.pop
end
def count
@the_stack.length
end
end
Labels:
pushing and popping,
ruby processing
Sunday, 29 November 2009
Seaweed using Lindenmayer system on ruby processing
Note that the rules here are essentially the same as the simple plant in my previous post, but here I've reduced the basic angle and added some numbers (repeat factors) to the 'rule'.
########################################################
# A simple seaweed implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'wrack'
class Wrack_Test < Processing::App
attr_reader :wrack
def setup
size 600, 600
@wrack = Wrack.new
wrack.simulate 4
no_loop
end
def draw
background 0
translate 200, 550
wrack.render
save_frame "wrack_4.png"
end
end
############################
# wrack.rb
###########################
require 'jcode' ## required until jruby supports ruby 1.9
class Wrack
include Processing::Proxy
DELTA = (Math::PI/180) * 18
attr_accessor :axiom, :rule, :rule1, :start_length, :theta, :production, :draw_length, :xpos, :ypos
def initialize
@axiom = "F"
@rule = "3F[2-F]2F[+F][F]"
@start_length = 90
stroke 255
stroke_weight 4
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_
@draw_length *= 0.5
new_production = prod_
new_production.gsub!('F', rule_)
end
def render
repeats = 1
production.each_char do |element|
case element
when 'F' # NB using affine transforms
line(0, 0, 0, -draw_length * repeats)
translate(0, -draw_length * repeats)
repeats = 1
when '+'
rotate(+DELTA * repeats)
repeats = 1
when '-'
rotate(-DELTA * repeats)
repeats = 1
when '['
push_matrix
when ']'
pop_matrix
when '1', '2', '3', '4' # extend this to '9' if you need to
repeats = Integer(element)
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(production, rule)
end
end
end
four iterations
five iterations (might look better green?)
########################################################
# A simple seaweed implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'wrack'
class Wrack_Test < Processing::App
attr_reader :wrack
def setup
size 600, 600
@wrack = Wrack.new
wrack.simulate 4
no_loop
end
def draw
background 0
translate 200, 550
wrack.render
save_frame "wrack_4.png"
end
end
############################
# wrack.rb
###########################
require 'jcode' ## required until jruby supports ruby 1.9
class Wrack
include Processing::Proxy
DELTA = (Math::PI/180) * 18
attr_accessor :axiom, :rule, :rule1, :start_length, :theta, :production, :draw_length, :xpos, :ypos
def initialize
@axiom = "F"
@rule = "3F[2-F]2F[+F][F]"
@start_length = 90
stroke 255
stroke_weight 4
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_
@draw_length *= 0.5
new_production = prod_
new_production.gsub!('F', rule_)
end
def render
repeats = 1
production.each_char do |element|
case element
when 'F' # NB using affine transforms
line(0, 0, 0, -draw_length * repeats)
translate(0, -draw_length * repeats)
repeats = 1
when '+'
rotate(+DELTA * repeats)
repeats = 1
when '-'
rotate(-DELTA * repeats)
repeats = 1
when '['
push_matrix
when ']'
pop_matrix
when '1', '2', '3', '4' # extend this to '9' if you need to
repeats = Integer(element)
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(production, rule)
end
end
end
four iterations
five iterations (might look better green?)
Labels:
l-system,
ruby processing,
seaweed
A basic example of a plant Lindenmayer systems in ruby processing
########################################################
# A basic plant implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'plant'
class Plant_Test < Processing::App
attr_reader :plant
def setup
size 600, 600
@plant = Plant.new
plant.simulate 4
no_loop
end
def draw
background 0
translate 300, 550
plant.render
save_frame "plant_4.png"
end
end
############################
# plant.rb
###########################
require 'jcode' ## required until jruby supports ruby 1.9
class Plant
include Processing::Proxy
DELTA = (Math::PI/180) * 60
attr_accessor :axiom, :rule, :start_length, :theta, :production, :draw_length, :xpos, :ypos
def initialize
@axiom = "F"
@rule = "F[-F]F[+F][F]"
@start_length = 250
stroke 255
stroke_weight 4
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_
@draw_length *= 0.5
new_production = prod_
new_production.gsub!('F', rule_)
end
def render
production.each_char do |element|
case element
when 'F' # NB here I am using affine transforms here, and push_matrix to save context
line(0, 0, 0, -draw_length)
translate(0, -draw_length)
when '+'
rotate(+DELTA)
when '-'
rotate(-DELTA)
when '['
push_matrix
when ']'
pop_matrix # pop_matrix to return to original context
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(production, rule)
end
end
end
two repetitions
three repetitions
four repetitions
Labels:
l-system,
plant structure,
ruby processing
Pentagonal Fractal
Here as as far as I know I have created my own pentagonal fractal, key things are the axiom has 5 go forward turn right elements, to go with a pentagonal structure.
The angle is 72 degrees to go with a pentagonal structure. The reduce factor has been calculated for nesting pentagon structures. There is an interesting diversion in shapes with the different number of repetitions. If you want to run other that the three repetitions you will need to adjust the starting position (and size particularly for the four repetitions).
##
# A Pentagonal Fractal created using a
# Lindenmayer System in ruby-processing by Martin Prout
###
require 'pentagonal'
class Pentagonal_Test < Processing::App
attr_reader :pentagonal
def setup
size 800, 800
@pentagonal = Pentagonal.new
pentagonal.simulate 3
no_loop
end
def draw
background 0
pentagonal.render
end
end
############################
# pentagonal.rb here I roll one of my own
###########################
require 'jcode' ## required until jruby supports ruby 1.9
class Pentagonal
include Processing::Proxy
SCALE = (3 - Math.sqrt(5))/2 # approximately 0.382
DELTA = (Math::PI/180) * 72.0 # convert degrees to radians
attr_accessor :axiom, :rule, :start_length, :theta, :production, :draw_length, :xpos, :ypos
def initialize
@axiom = "F-F-F-F-F"
@rule = "F+F+F-F-F-F+F+F" # replace F with this string see iterate function
@start_length = 220
@theta = 0.0
@xpos = width*0.75
@ypos = height*0.85
stroke 255
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_
@draw_length *= SCALE
new_production = prod_
new_production.gsub!('F', rule_)
end
def render
production.each_char do |element|
case element
when 'F' # you could use affine transforms here, I prefer to do the Math
line(xpos, ypos, (@xpos -= draw_length * Math.cos(theta)), (@ypos += draw_length * Math.sin(theta)))
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(@production, @rule)
end
end
end
two repetitions
three repetitions
four repetitions
The angle is 72 degrees to go with a pentagonal structure. The reduce factor has been calculated for nesting pentagon structures. There is an interesting diversion in shapes with the different number of repetitions. If you want to run other that the three repetitions you will need to adjust the starting position (and size particularly for the four repetitions).
##
# A Pentagonal Fractal created using a
# Lindenmayer System in ruby-processing by Martin Prout
###
require 'pentagonal'
class Pentagonal_Test < Processing::App
attr_reader :pentagonal
def setup
size 800, 800
@pentagonal = Pentagonal.new
pentagonal.simulate 3
no_loop
end
def draw
background 0
pentagonal.render
end
end
############################
# pentagonal.rb here I roll one of my own
###########################
require 'jcode' ## required until jruby supports ruby 1.9
class Pentagonal
include Processing::Proxy
SCALE = (3 - Math.sqrt(5))/2 # approximately 0.382
DELTA = (Math::PI/180) * 72.0 # convert degrees to radians
attr_accessor :axiom, :rule, :start_length, :theta, :production, :draw_length, :xpos, :ypos
def initialize
@axiom = "F-F-F-F-F"
@rule = "F+F+F-F-F-F+F+F" # replace F with this string see iterate function
@start_length = 220
@theta = 0.0
@xpos = width*0.75
@ypos = height*0.85
stroke 255
reset
end
def reset # initialize or reset variables
@production = axiom
@draw_length = start_length
end
def iterate prod_, rule_
@draw_length *= SCALE
new_production = prod_
new_production.gsub!('F', rule_)
end
def render
production.each_char do |element|
case element
when 'F' # you could use affine transforms here, I prefer to do the Math
line(xpos, ypos, (@xpos -= draw_length * Math.cos(theta)), (@ypos += draw_length * Math.sin(theta)))
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
else puts "Grammar not recognized"
end
end
end
def simulate gen
gen.times do
@production = iterate(@production, @rule)
end
end
end
two repetitions
four repetitions
Labels:
l-system,
pentagonal fractal,
ruby processing
Saturday, 28 November 2009
Minkowski island using L-System in ruby processing
Revised as of 28 December 2009 to use a custom grammar library (see Cesàro fractal in a later post)
#################################################
# minkowski_test.rb
#
# A Minkowski island implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
#################################################
require 'minkowski'
require 'grammar'
class Minkowski_Test < Processing::App
attr_reader :minkowski
def setup
size 800, 800
@minkowski = Minkowski.new
minkowski.create_grammar 4
no_loop
end
def draw
background 0
minkowski.render
end
end
#############################
# Minkowski Fractal
#
# minkowski.rb
###########################
class Minkowski
include Processing::Proxy
require 'grammar'
DELTA = (Math::PI/180) * 90.0 # L-System angle increment constant, in radians
attr_accessor :axiom, :grammar, :start_length, :theta, :production, :draw_length, :xpos, :ypos
def initialize
@axiom = 'F+F+F+F' # just one F for a Minkowski sausage
@grammar = Grammar.new axiom
grammar.add_rule 'F', 'F-F+F+FF-F-F+F' # replace F with this string, see iterate function
@start_length = 400
@theta = (Math::PI/180) * 30.0 # initialize angle variable
@xpos = width * 0.6 # starting x position
@ypos = height/6 # starting y position
stroke 0, 255, 0
stroke_weight 2
@draw_length = start_length
@production = axiom
end
def next_x
@xpos -= draw_length * Math.cos(theta)
end
# a helper function that sets and returns next position x coordinate
# you could use affine transforms instead but this avoids that overhead
def next_y
@ypos += draw_length * Math.sin(theta)
end
def render
production.each_char do |element|
case element
when 'F' # draw element and move forward
line(xpos, ypos, next_x, next_y)
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
else puts "Grammar not recognized"
end
end
end
##############################
# create grammar from axiom and
# rules (adjust scale)
##############################
def create_grammar(gen = 1)
@draw_length *= 0.25**gen
@production = @grammar.generate gen
end
end
#################################################
# minkowski_test.rb
#
# A Minkowski island implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
#################################################
require 'minkowski'
require 'grammar'
class Minkowski_Test < Processing::App
attr_reader :minkowski
def setup
size 800, 800
@minkowski = Minkowski.new
minkowski.create_grammar 4
no_loop
end
def draw
background 0
minkowski.render
end
end
#############################
# Minkowski Fractal
#
# minkowski.rb
###########################
class Minkowski
include Processing::Proxy
require 'grammar'
DELTA = (Math::PI/180) * 90.0 # L-System angle increment constant, in radians
attr_accessor :axiom, :grammar, :start_length, :theta, :production, :draw_length, :xpos, :ypos
def initialize
@axiom = 'F+F+F+F' # just one F for a Minkowski sausage
@grammar = Grammar.new axiom
grammar.add_rule 'F', 'F-F+F+FF-F-F+F' # replace F with this string, see iterate function
@start_length = 400
@theta = (Math::PI/180) * 30.0 # initialize angle variable
@xpos = width * 0.6 # starting x position
@ypos = height/6 # starting y position
stroke 0, 255, 0
stroke_weight 2
@draw_length = start_length
@production = axiom
end
def next_x
@xpos -= draw_length * Math.cos(theta)
end
# a helper function that sets and returns next position x coordinate
# you could use affine transforms instead but this avoids that overhead
def next_y
@ypos += draw_length * Math.sin(theta)
end
def render
production.each_char do |element|
case element
when 'F' # draw element and move forward
line(xpos, ypos, next_x, next_y)
when '+'
@theta += DELTA
when '-'
@theta -= DELTA
else puts "Grammar not recognized"
end
end
end
##############################
# create grammar from axiom and
# rules (adjust scale)
##############################
def create_grammar(gen = 1)
@draw_length *= 0.25**gen
@production = @grammar.generate gen
end
end
Labels:
l-system,
Minkowski island,
ruby processing
Friday, 27 November 2009
Sierpinski Fractal Implemented in ruby-processing using an L-System
Revised as of 17 January 2010 uses a custom grammar library (see Cesàro fractal in a later post)
##
# A Sierpinski Triangle implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
###
require 'sierpinski'
class Sierpinski_Test < Processing::App
load_library :grammar
attr_reader :sierpinski
def setup
size 610, 600
@sierpinski = Sierpinski.new
sierpinski.create_grammar 8
no_loop
end
def draw
background 0
sierpinski.render
end
end
############################
# sierpinski.rb
###########################
class Sierpinski
include Processing::Proxy
attr_accessor :axiom, :grammar, :start_length, :production, :draw_length, :xpos, :ypos
XPOS = 0
YPOS = 1
ANGLE = 2
DELTA = (Math::PI/180) * 120 # convert degrees to radians
def initialize
@start_length = 300
setup_grammar
@xpos = width/60
@ypos = height*0.9
stroke 255
@draw_length = start_length
end
def setup_grammar
@axiom = "FX"
@grammar = Grammar.new axiom
grammar.add_rule "F", "FF" # replace F rule see grammar library
grammar.add_rule "X", "-FXF+FXF+FXF-" # replace X rule see grammar library
@production = axiom
end
def render # NB not using affine transforms here
turtle = [xpos, ypos, 0.0]
production.scan(/./).each do |element|
case element
when 'F'
turtle = draw_line(turtle, draw_length)
when '+'
turtle[ANGLE] += DELTA # rotate by + theta if going the affine transform route
when '-'
turtle[ANGLE] -= DELTA # rotate by - theta if going the affine transform route
when 'X' # do nothing except recognize 'X' as a word in the L-system grammar
else
puts "Character '#{element}' is 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 * Math.cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * Math.sin(turtle[ANGLE])
line(turtle[XPOS], turtle[YPOS], new_xpos, new_ypos)
turtle = [new_xpos, new_ypos, turtle[ANGLE]]
end
end
##
# A Sierpinski Triangle implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
###
require 'sierpinski'
class Sierpinski_Test < Processing::App
load_library :grammar
attr_reader :sierpinski
def setup
size 610, 600
@sierpinski = Sierpinski.new
sierpinski.create_grammar 8
no_loop
end
def draw
background 0
sierpinski.render
end
end
############################
# sierpinski.rb
###########################
class Sierpinski
include Processing::Proxy
attr_accessor :axiom, :grammar, :start_length, :production, :draw_length, :xpos, :ypos
XPOS = 0
YPOS = 1
ANGLE = 2
DELTA = (Math::PI/180) * 120 # convert degrees to radians
def initialize
@start_length = 300
setup_grammar
@xpos = width/60
@ypos = height*0.9
stroke 255
@draw_length = start_length
end
def setup_grammar
@axiom = "FX"
@grammar = Grammar.new axiom
grammar.add_rule "F", "FF" # replace F rule see grammar library
grammar.add_rule "X", "-FXF+FXF+FXF-" # replace X rule see grammar library
@production = axiom
end
def render # NB not using affine transforms here
turtle = [xpos, ypos, 0.0]
production.scan(/./).each do |element|
case element
when 'F'
turtle = draw_line(turtle, draw_length)
when '+'
turtle[ANGLE] += DELTA # rotate by + theta if going the affine transform route
when '-'
turtle[ANGLE] -= DELTA # rotate by - theta if going the affine transform route
when 'X' # do nothing except recognize 'X' as a word in the L-system grammar
else
puts "Character '#{element}' is 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 * Math.cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * Math.sin(turtle[ANGLE])
line(turtle[XPOS], turtle[YPOS], new_xpos, new_ypos)
turtle = [new_xpos, new_ypos, turtle[ANGLE]]
end
end
Wednesday, 25 November 2009
Snake Kolam Ruby Processing
##
# Lindenmayer System in ruby-processing by Martin Prout
###
require 'snake_kolam'
class Kolam_Test < Processing::App
load_libraries 'grammar'
attr_reader :snake
def setup
size 900, 900
@snake = SnakeKolam.new
snake.create_grammar 4
no_loop
end
def draw
background 0
stroke(255)
snake.render
end
end
############################
# snake_kolam.rb using l-systems
############################
class SnakeKolam
include Processing::Proxy
attr_accessor :axiom, :start_length, :xpos, :ypos, :grammar, :production, :draw_length
XPOS = 0
YPOS = 1
ANGLE = 2
DELTA = (Math::PI/180) * 90.0 # convert degrees to radians
def initialize
setup_grammar
@start_length = 160.0
@theta = (Math::PI/180) * 90.0 # convert degrees to radians
@draw_length = start_length
@draw_length = start_length
@xpos = width/8
@ypos = height*0.8
end
def setup_grammar
@axiom = "FX+F+FX+F"
@grammar = Grammar.new(axiom)
grammar.add_rule("X", "X-F-F+FX+F+FX-F-F+FX")
@production = axiom
end
def render # NB not using affine transforms here
turtle = [xpos, ypos, 0.0]
production.scan(/./).each do |element|
case element
when 'F'
turtle = draw_line(turtle, draw_length)
when '+'
turtle[ANGLE] += DELTA # rotate by + theta if going the affine transform route
when '-'
turtle[ANGLE] -= DELTA # rotate by - theta if going the affine transform route
when 'X' # do nothing except recognize 'X' as a word in the L-system grammar
else
puts "Character '#{element}' is not in grammar"
end
end
end
##############################
# create grammar from axiom and
# rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.6**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 * Math.cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * Math.sin(turtle[ANGLE])
line(turtle[XPOS], turtle[YPOS], new_xpos, new_ypos)
turtle = [new_xpos, new_ypos, turtle[ANGLE]]
end
end
Labels:
l-system,
ruby-processing,
snake kolam
Subscribe to:
Posts (Atom)
Followers
Blog Archive
-
▼
2009
(50)
-
▼
November
(18)
- Koch curve using l-systems
- Towards a forest, or too many matrix calls
- Seaweed using Lindenmayer system on ruby processing
- A basic example of a plant Lindenmayer systems in...
- Pentagonal Fractal
- Minkowski island using L-System in ruby processing
- Sierpinski Fractal Implemented in ruby-processing ...
- Snake Kolam Ruby Processing
- Penrose Snowflake L-Systems using ruby-processing
- Dragon Fractal Using L-Systems and ruby-processing
- Koch Island Using Lindemayer System in Ruby Proces...
- Lindenmayer system in ruby-processing
- Tessellated "curvy" triangles in ruby-processing
- Dynamic rand with ruby-processing context-free DSL
- Flower in ruby-processing DSL
- Heighway Dragon in ruby-processing context free DSL
- Lévy curve implemented in ruby-processing context ...
- jEdit as a cross platform GUI?
-
▼
November
(18)
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