views:

588

answers:

2

I have created a Python file to generate a Mandelbrot set image. The original maths code was not mine, so I do not understand it - I only heavily modified it to make it about 250x faster (Threads rule!).

Anyway, I was wondering how I could modify the maths part of the code to make it render one specific bit. Here is the maths part:

for y in xrange(size[1]):
        coords = (uleft[0] + (x/size[0]) * (xwidth),uleft[1] - (y/size[1]) * (ywidth))
        z = complex(coords[0],coords[1])
        o = complex(0,0)
        dotcolor = 0  # default, convergent
        for trials in xrange(n):
            if abs(o) <= 2.0:
                o = o**2 + z
            else:
                dotcolor = trials
                break  # diverged
        im.putpixel((x,y),dotcolor)

And the size definitions:

size1 = 500
size2 = 500
n=64
box=((-2,1.25),(0.5,-1.25))
plus = size[1]+size[0]
uleft = box[0]
lright = box[1]
xwidth = lright[0] - uleft[0]
ywidth = uleft[1] - lright[1]

what do I need to modify to make it render a certain section of the set?

+11  A: 

The line:

box=((-2,1.25),(0.5,-1.25))

is the bit that defines the area of coordinate space that is being rendered, so you just need to change this line. First coordinate pair is the top-left of the area, the second is the bottom right.

To get a new coordinate from the image should be quite straightforward. You've got two coordinate systems, your "image" system 100x100 pixels in size, origin at (0,0). And your "complex" plane coordinate system defined by "box". For X:

X_complex=X_complex_origin+(X_image/X_image_width)*X_complex_width
Ian Hopkinson
Thanks man! How can I convert these to X and Y values? Is it possible?
Lobe
Box contains two x,y pairs:box=((x,y),(x,y))Does that answer your question?
Ian Hopkinson
Ahh, sorry about that, I got the wrong end of the stick. I meant, if I had the dimensions of the full rendered image (Say 100x100), how could I convert the x and y values of a section of the 100x100 image to a x and y value to 'zoom' in on? I doubt its possible - and thanks for answering!
Lobe
That should be quite straightforward. You've got two coordinate systems, your "image" system 100x100 pixels in size, origin at (0,0). And your "complex" plane coordinate system defined by "box". For X:X_complex=X_complex_origin+(X_image/X_image_width)*X_complex_widthmaybe I should edit my answer!
Ian Hopkinson
Thanks man! Could you update your answer, incase I need to check back here and forget about the comments!
Lobe
There you go, calculating Mandelbrot sets brings back fond memories of my distant computing past!
Ian Hopkinson
+2  A: 

The key in understanding how to do this is to understand what the coords = line is doing:

coords = (uleft[0] + (x/size[0]) * (xwidth),uleft[1] - (y/size[1]) * (ywidth))

Effectively, the x and y values you are looping through which correspond to the coordinates of the on-screen pixel are being translated to the corresponding point on the complex plane being looked at. This means that (0,0) screen coordinate will translate to the upper left region being looked at (-2,1.25), and (1,0) will be the same, but moved 1/500 of the distance (assuming a 500 pixel width window) between the -2 and 0.5 x-coordinate.

That's exactly what that line is doing - I'll expand just the X-coordinate bit with more illustrative variable names to indicate this:

mandel_x = mandel_start_x + (screen_x / screen_width) * mandel_width

(The mandel_ variables refer to the coordinates on the complex plane, the screen_ variables refer to the on-screen coordinates of the pixel being plotted.)

If you want then to take a region of the screen to zoom into, you want to do exactly the same: take the screen coordinates of the upper-left and lower-right region, translate them to the complex-plane coordinates, and make those the new uleft and lright variables. ie to zoom in on the box delimited by on-screen coordinates (x1,y1)..(x2,y2), use:

new_uleft = (uleft[0] + (x1/size[0]) * (xwidth), uleft[1] - (y1/size[1]) * (ywidth))
new_lright = (uleft[0] + (x2/size[0]) * (xwidth), uleft[1] - (y2/size[1]) * (ywidth))

(Obviously you'll need to recalculate the size, xwidth, ywidth and other dependent variables based on the new coordinates)

In case you're curious, the maths behind the mandelbrot set isn't that complicated (just complex). All it is doing is taking a particular coordinate, treating it as a complex number, and then repeatedly squaring it and adding the original number to it.

For some numbers, doing this will cause the result diverge, constantly growing towards infinity as you repeat the process. For others, it will always stay below a certain level (eg. obviously (0.0, 0.0) never gets any bigger under this process. The mandelbrot set (the black region) is those coordinates which don't diverge. Its been shown that if any number gets above the square root of 5, it will diverge - your code is just using 2.0 as its approximation to sqrt(5) (~2.236), but this won't make much noticeable difference.

Usually the regions that diverge get plotted with the number of iterations of the process that it takes for them to exceed this value (the trials variable in your code) which is what produces the coloured regions.

Brian