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
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Monday, 30 November 2009
Subscribe to:
Post Comments (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
No comments:
Post a Comment