Dan Mayer over at devver.net has kindly analysed and re-factored my penrose_snowflake with caliper (something I've never heard of but then I'm not really in the community, just ploughing my own furrow). He also extended my code in an interesting way to produce a "snowflake screensaver" which labours a bit.
Well I tried out Dans refactoring on my own code (which I had already changed to have a separate grammar library). Here is my revised penrose_snowflake.rb (requires grammar.rb and runs with penrose.rb) incorporating some additional refactoring, which you may or may not like depending on your view of the ternary operator (my multiplier has fewer lines of code and is 4% faster according to my benchmark test). However I have since come up with a different version which I have now used to replace my original posting!!! I think the new version will come into its own for my bracketed L-Systems and my Island fractal which is next on the list for refactoring.
class PenroseSnowflake
include Processing::Proxy
attr_accessor :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
DELTA = (Math::PI/180) * 18.0 # convert degrees to radians
def initialize
@axiom = "F3-F3-F3-F3-F"
@grammar = Grammar.new axiom
grammar.add_rule "F", "F3-F3-F45-F++F3-F"
@start_length = 450.0
@theta = 0
@xpos = width * 0.8
@ypos = height * 0.95
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing or L-Systems in my iterate
# 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
production.each_char do |element|
case element
when 'F'
line(xpos, ypos, (@xpos -= multiplier(repeats, :cos)), (@ypos += multiplier(repeats, :sin)))
repeats = 1
when '+'
@theta += DELTA * repeats
repeats = 1
when '-'
@theta -= DELTA * repeats
repeats = 1
when '3', '4', '5'
repeats += Integer(element)
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.4**gen
@production = grammar.generate gen
end
def multiplier(repeats, type)
value = draw_length * repeats
(type == :cos)? value * Math.cos(theta) : value * Math.sin(theta)
end
end
No comments:
Post a Comment