Skip to content

Instantly share code, notes, and snippets.

@Phrogz
Created February 25, 2010 23:43
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 Phrogz/315189 to your computer and use it in GitHub Desktop.
Save Phrogz/315189 to your computer and use it in GitHub Desktop.
class String
def dindent
gsub(/^#{self[/\A\s+/]}/,'')
end
end
class Turtle
attr_accessor :x, :y, :a
attr_reader :path
def initialize( x=0, y=0, a=0 )
@x, @y, @a = x, y, a
@path = [ [@x, @y] ]
end
def fwd( dist )
puts "fwd %.3f" % dist if $DEBUG
@x += dist * Math.sin( @a * Math::PI/180 )
@y -= dist * Math.cos( @a * Math::PI/180 )
path << [@x, @y]
end
def rt( angle )
puts " rt %.3f" % angle if $DEBUG
@a += angle
end
def lt( angle )
puts " lt %.3f" % angle if $DEBUG
@a -= angle
end
def koch(dist,angle=66,iterations=6,bloat=1,curl=1)
if iterations==0
fwd dist
else
d2 = dist/2
a2 = angle*2
koch(d2,angle,iterations-1,bloat,curl)
lt(angle)
koch(d2*bloat*curl,angle,iterations-1,bloat,curl)
rt(a2)
koch(d2*bloat,angle,iterations-1,bloat,curl)
lt angle
koch(d2*curl,angle,iterations-1,bloat,curl)
end
end
def spark(dist,angle=66,iterations=6)
if iterations==0
fwd dist
else
a2 = angle*2
spark(dist,angle,iterations-1)
lt angle
spark(dist,angle,iterations-1)
rt a2
spark(dist*2,angle,iterations-1)
lt a2
spark(dist,angle,iterations-1)
rt angle
spark(dist,angle,iterations-1)
end
end
def spark2(dist,angle=66,iterations=6)
if iterations==0
fwd dist
else
d3 = dist/3.0
da = dist/(12*Math.cos(angle*Math::PI/180))
a2 = angle*2
spark2(d3,angle,iterations-1)
lt angle
spark2(da,angle,iterations-1)
rt a2
spark2(2*da,angle,iterations-1)
lt a2
spark2(da,angle,iterations-1)
rt angle
spark2(d3,angle,iterations-1)
end
end
def svg( file )
x = @path.map{ |p| p[0] }
y = @path.map{ |p| p[1] }
minx = x.min
maxx = x.max
miny = y.min
maxy = y.max
File.open(file,'w') do |f|
f << <<-ENDSVG
<svg width='100%' height='100%' xmlns='http://www.w3.org/2000/svg' viewBox='#{"%.2f %.2f %.2f %.2f" % [minx, miny, maxx-minx, maxy-miny] }'>
<path d='M #{ "%.2f %.2f" % @path.first } #{@path[1..-1].map{ |p| "L %.2f %.2f" % p }.join(" ")}' fill='none' stroke='black' stroke-width='#{(maxy-miny)/400.0}'/>
</svg>
ENDSVG
end
end
def self.animsvg( file, duration, *turtles )
paths = turtles.flatten.map{ |turtle| turtle.path }
points = paths.inject([]){ |all,path| all.concat(path) }
x = points.map{ |p| p[0] }
y = points.map{ |p| p[1] }
minx = x.min
maxx = x.max
miny = y.min
maxy = y.max
width = maxx - minx
height = maxy - miny
stroke = height/1000.0
path_datas = paths.map{ |path| "M %.0f %.0f #{'L %.0f %.0f '*(path.length-1)}" % path.flatten }
File.open(file,'w') do |f|
f << <<-ENDSVG.dindent
<svg width='100%' height='100%' xmlns='http://www.w3.org/2000/svg' viewBox='#{ "%.2f %.2f %.2f %.2f" % [minx, miny, width, height] }'>
<path d='#{path_datas.first}' fill='none' stroke='black' stroke-width='#{stroke}'>
#{
(1...path_datas.length).map{ |i|
"<animate attributeType='XML' attributeName='d' from='#{path_datas[i-1]}' to='#{path_datas[i]}' begin='#{(i-1)*duration}s' dur='#{duration}s' fill='#{i==(path_datas.length-1) ? 'freeze' : 'remove'}' />"
}.join("\n\t")
}
</path>
</svg>
ENDSVG
end
end
end
if __FILE__==$0
turtles = []
sides = 3
30.step(74,1) do |a|
turtle = Turtle.new(0,0,90)
turtles << turtle
sides.times do
turtle.spark2(1000,a,4)
turtle.rt 360.0/sides
end
end
Turtle.animsvg( ARGV[0] || "out.svg",0.1, turtles )
# $DEBUG = true
# turtle = Turtle.new(0,0,90)
# turtle.spark2(1000,70,2)
# turtle.svg( ARGV[0] || "out.svg" )
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment