require 'complex' WIDTH,HEIGHT = 640,480 MAX_COLOR = 360 ZOOM_FACT = 0.8 MAX_ITERATIONS = 40 CENTER = -0.65 X_INC = WIDTH / (200000 * ZOOM_FACT) Y_INC = HEIGHT / (150000 * ZOOM_FACT) SAT = 0.85 VAL = 0.85 class HSV def initialize h, s, v @h,@s,@v = h,s,v end def hi (@h / 60).floor % 6 end def f @h / 60 - hi end def p (1 - @s) * @v end def q (1 - f * @s) * @v end def t (1 - ((1 - f) * @s)) * @v end def to_rgb h = hi case h when 0 [@v, t, p] when 1 [q, @v, p] when 2 [p, @v, t] when 3 [p, q, @v] when 4 [t, p ,@v] else [@v, p, q] end end end def scale x return (x * 255).to_i end def scale_rgb rgb [scale(rgb[0]),scale(rgb[1]),scale(rgb[2])] end def make_color_map nb_cols out = [] nb_cols.times do |i| hsv = HSV.new((360.0 * i) / (nb_cols + 1), SAT, VAL) color = scale_rgb hsv.to_rgb out << ('' << color[0] << color[1] << color[2]) end out end COLOR_MAP = make_color_map [MAX_ITERATIONS,MAX_COLOR].min def c i,j Complex(X_INC * i + CENTER - X_INC * WIDTH / 2, Y_INC * j - Y_INC * HEIGHT / 2) end class Complex def absq real*real + image*image end end def pixel c z = Complex(0) i = MAX_ITERATIONS while i > -1 do z = z*z + c if z.absq >= 4.0 return i end i -= 1 end return nil end def color iterations if iterations != nil COLOR_MAP[iterations % COLOR_MAP.length] else return "\0\0\0" end end def render HEIGHT.times do |j| WIDTH.times do |i| print color pixel(c i,j) end end end def ppm_header print "P6\n#{WIDTH} #{HEIGHT}\n255\n" end ppm_header render