%!PS-Adobe-2.0 %%BoundingBox: 0 0 612 792 %%Pages: 1 %%EndComments %%Page: 1 1 % hisui1.ps - Don Yang (uguu.org) % Mandelbrot set renderer % % 10/29/05 % Constants /ITERATION_COUNT 26 def /MIN_X 72 def /MIN_Y 72 def /MAX_X 540 def /MAX_Y 720 def /X_STEPS MAX_X MIN_X sub 2 div def /Y_STEPS MAX_Y MIN_Y sub 2 div def /ASPECT_RATIO MAX_X MIN_X sub MAX_Y MIN_Y sub div def % Render a point by exponentiating it repeatedly. Returns number of % iterations it takes for the number to diverge, clamped by % ITERATION_COUNT. /render_point % z_r z_i -> int { dup /z_i exch def /z0_i exch def dup /z_r exch def /z0_r exch def /iter 0 def 1 ITERATION_COUNT add { % Exit loop early if magnitude > 2.0 z_r z_r mul z_i z_i mul add 4.0 gt {exit} {} ifelse % z^2 + z0 /z_r z_r z_r mul z_i z_i mul sub z0_r add % z_r = z_r^2 - z_i^2 + z0_r /z_i z_r z_i mul 2.0 mul z0_i add % z_i = 2*z_r*z_i + z0_i def def % iter = iter + 1 /iter iter 1 add def } repeat iter } bind def % Convert iteration value to color /iter_color % iter -> () { /iter exch def % Hue = iter / ITERATION_COUNT iter 0 lt iter ITERATION_COUNT gt or {0.0} {iter ITERATION_COUNT div} ifelse 1.0 1.0 sethsbcolor } bind def % Check if a particular set of coordinates is interesting by checking % for high variety of values in sampled points /interesting % x0 x1 y0 y1 -> bool { /test_y1 exch def /test_y0 exch def /test_x1 exch def /test_x0 exch def % Render 5 points test_x0 test_y0 render_point test_x0 test_y1 render_point test_x1 test_y0 render_point test_x1 test_y1 render_point test_x0 test_x1 add 2 div test_y0 test_y1 add 2 div render_point % average = sum(iter0 .. iter4) 5 copy add add add add 5 div /average exch def % delta_n = (iter_n - average) ^ 2 5 { average sub dup mul 5 1 roll } repeat % stddev = sum(delta0 .. delta4) / 5 add add add add 5 div % stddev > ITERATION_COUNT * 4.6 ITERATION_COUNT 4.6 mul gt } bind def % Render image /render_image % x0 x1 xsteps y0 y1 ysteps -> () { gsave /logical_ysteps exch def /logical_y1 exch def /logical_y0 exch def /logical_xsteps exch def /logical_x1 exch def /logical_x0 exch def % Convert loop iterations to real coordinates MIN_X MIN_Y translate MAX_X MIN_X sub logical_xsteps div MAX_Y MIN_Y sub logical_ysteps div scale % Convert loop iterations to logical coordinates /convert_to_logical_x { logical_x1 logical_x0 sub mul logical_xsteps div logical_x0 add } bind def /convert_to_logical_y { logical_y1 logical_y0 sub mul logical_ysteps div logical_y0 add } bind def % iter_y = 0 .. logical_ysteps-1 0 1 logical_ysteps 1 sub { dup /iter_y exch def convert_to_logical_y /logical_y exch def % iter_x = 0 .. logical_xsteps-1 0 1 logical_xsteps 1 sub { dup /iter_x exch def convert_to_logical_x /logical_x exch def % Render point as a colored rectangle. This is bigger than % the size needed because we need some overlap to cover the % gap between pixels caused by numerical errors. % Anti-aliasing becomes slightly broken, but this looks % better than image with blank gridlines. logical_x logical_y render_point iter_color iter_x iter_y 1.5 1.5 rectfill } for } for % Draw white borders to cover the pixels on the edges 0.0 0.0 1.0 sethsbcolor 0 logical_ysteps logical_xsteps 2 add 2 rectfill logical_xsteps 0 2 logical_ysteps 2 add rectfill grestore } bind def % Random numbers realtime srand /random_range % x0 x1 -> float { 2 copy exch sub rand 16#1000000 mod 16#1000000 div mul exch pop add } bind def % Generate coordinates repeatedly until an interesting one is found, % then render image. /render_random_image { { /x -1 1 random_range def /y -1 1 random_range def /s 0.1 1.0 random_range def x x s ASPECT_RATIO mul add y y s add interesting {exit} {} ifelse } loop x x s ASPECT_RATIO mul add X_STEPS y y s add Y_STEPS render_image } bind def erasepage render_random_image showpage