Skip to content

Instantly share code, notes, and snippets.

@monkstone
Created November 30, 2010 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monkstone/721792 to your computer and use it in GitHub Desktop.
Save monkstone/721792 to your computer and use it in GitHub Desktop.
A Snake Kolam in ruby-processing demonstrates the use of PGraphicsPDF
#############################################################
# 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 = String.new(axiom) # retain original axiom
repeat.times do
prod = new_production prod
end
return prod
end
#############################################
# Returns a string thst describes the LSystem
#############################################
def to_string
rule = "Axiom: #{axiom}\nSubstitution Rules:\n"
rules.each{|pr| rule << "#{pr[0]} => #{pr[1]}\n"}
return rule
end
end
#######################################################
# Lindenmayer System in ruby-processing by Martin Prout
# Demonstrates export to PDF format
#######################################################
require 'snake_kolam'
class Kolam_Test < Processing::App
load_libraries :grammar, :pdf
import "processing.pdf.PGraphicsPDF"
attr_reader :snake, :my_font
def setup
size 900, 900, P2D
@snake = SnakeKolam.new
snake.create_grammar 4
background(255)
hint(ENABLE_NATIVE_FONTS)
@my_font = create_font("/usr/share/fonts/truetype/freefont/FreeSans.ttf", 18) # for the benefit linux users
# @my_font = create_font(Any suitable ttf font, 18)
background 255
stroke 0
render_to_PDF
end
def render_to_PDF
begin_record PDF, "/home/tux/kolam.pdf" # requires an absolute address for output file
snake.render # render kolam (NB text does not appear in frame)
fill 0 # font fill
text_mode(SHAPE) # fonts as shape
textFont(my_font, 18)
text("Snake Kolam", 300, 40) # title
text(snake.to_string, 100, 780) # lsystem values
end_record
end
end
############################
# snake_kolam.rb using l-systems
############################
class SnakeKolam
include Processing::Proxy
attr_accessor :axiom, :start_length, :xpos, :ypos, :grammar, :production, :draw_length, :gen
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")
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)
@gen = gen
@draw_length *= 0.6**gen
@production = @grammar.generate gen
end
def to_string
rule = "Repeats: #{gen}\n"
rule << grammar.to_string
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment