2

I have coded a Mandelbrot Set Fractal in Java and have included the ability to pan and zoom in on the fractal a certain amount. The only thing is that when I pan the image and try to zoom in, it looks as if it tries to zoom in on the center and pans away a bit. The panning and zooming isn't really panning or zooming more it is actually a recalculation of the fractal to seem as if it is panning or zooming.

Here is my code.

package core;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;

public class Main extends JFrame implements KeyListener
{
    // Constant screen dimensions
    private final int SCREEN_WIDTH = 800;
    private final int SCREEN_HEIGHT = 600;

    // Fractal image
    private BufferedImage fractal;

    // Number of max iterations
    private int maxIter = 500;
    // Zoom factor
    private double zoom = 150;
    // Coordinates
    private double xPos = SCREEN_WIDTH / 2;
    private double yPos = SCREEN_HEIGHT / 2;

    // Algorithm variables
    private double zx, zy, cX, cY, tmp;

    public static void main(String[] args)
    {
        // Create the frame and make it visible
        new Main().setVisible(true);
    }

    public Main()
    {
        super("Mandelbrot Set");
        setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        addKeyListener(this);
        setResizable(false);

        // Compute the fractal to start
        ComputeFractal();
    }

    public void ComputeFractal()
    {
        fractal = new BufferedImage(SCREEN_WIDTH, SCREEN_HEIGHT, BufferedImage.TYPE_INT_RGB);

        for (int y = 0; y < fractal.getHeight(); y++)
        {
            for (int x = 0; x < fractal.getWidth(); x++)
            {
                zx = zy = 0;
                cX = (x - xPos) / zoom;
                cY = (y - yPos) / zoom;

                int iter;

                for (iter = 0; iter < maxIter && zx * zx + zy * zy < 4; iter++)
                {
                    tmp = zx * zx - zy * zy + cX;
                    zy = 2.0 * zx * zy + cY;
                    zx = tmp;
                }

                // If the point is in the set
                if (iter == maxIter)
                {
                    Color color = new Color(0, 0, 0);
                    fractal.setRGB(x, y, color.getRGB());
                }
                // If the point is not in the set
                else
                {   
                    double r = iter | (iter << 2);
                    while (r > 255) { r-=255; }
                    double g = iter | (iter << 4);
                    while (g > 255) { g-=255; }
                    double b = iter | (iter << 8);
                    while (b > 255) { b-=255; }

                    Color color = new Color((int) r, (int) g, (int) b);
                    fractal.setRGB(x, y, color.getRGB());
                }
            }
        }

        repaint();
    }

    public void paint(Graphics g)
    {
        // Draw the fractal
        g.drawImage(fractal, 0, 0, this);
    }

    public void keyReleased(KeyEvent e)
    {
        if (e.getKeyCode() == KeyEvent.VK_SPACE)
        {
            zoom += 100;
            ComputeFractal();
        }
        else if (e.getKeyCode() == KeyEvent.VK_LEFT)
        {
            xPos += 50;
            ComputeFractal();
        }
        else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
        {
            xPos -= 50;
            ComputeFractal();
        }
        else if (e.getKeyCode() == KeyEvent.VK_UP)
        {
            yPos += 50;
            ComputeFractal();
        }
        else if (e.getKeyCode() == KeyEvent.VK_DOWN)
        {
            yPos -= 50;
            ComputeFractal();
        }
    }

    public void keyTyped(KeyEvent e)
    {

    }

    public void keyPressed(KeyEvent e)
    {

    }
}

Can anyone tell me what I can do to make the zooming more accurate to where the user pans the 'camera'?

Thank you in advance.

Edit: Picture for anyone wondering what this program will render.

enter image description here

BigBerger
  • 1,765
  • 4
  • 23
  • 43
  • It is nitpicking on insignificant details,but you really should make those xPos,yPos and zoom variables as arguments to the ComputeFractal() function.I don't see the exact reason of the problem,but: **1.)** If I am correct, that (x - xPos) can be negative,which I don't see how is handled. **2.)** your graphic displaying relies entirely on screen pixels (which could work), but I'd do that with some reference to the real Mandlebrot coordinates (those, between -2;1 for x and -1;-1 for y) **3.)** you should calculate pixels from the top-left.Now you define the center of the screen to xPos and yPos – karatedog May 09 '14 at 08:49

1 Answers1

0

Basically whats going on is that in the center of the mandelbrot is the xPos 0 and yPos 0. Your zoom is deviding you xPos and yPos (cX = (x - xPos) / zoom;). For example if your xPos is -500 and you increase your zoom, it will be -500/ zoom, so it will be about - 4, and next time you zoom it will be - 3 and so on until it hit 0.

What you want to do is to set a fixed position (x, y) on mandelbrot from (-2:2) for x and y. So that position will be center of your rendered image on mandelbrot. Zoom will just tell how far away from the center is each pixel on the mandelbrod set. For example if center pixel is 0,0 on mandelbrot then center pixel + 1 will be 0.1,0 or 0.00005,0 based on the zoom. Arrow keys will move the fixed position.

cX = xPos/SCREEN_WIDTH + (x - (fractal.getWidth() >> 1)) / zoom;
cY = yPos/SCREEN_HEIGHT + (y - (fractal.getHeight() >> 1)) / zoom;

If you paste that in you code it will work, but i recommend to use xPos, yPos values mostly in range (-2:2), it will make more sense. Also I recommend to change a bit the way you zoom things. For that you need to change...

private double zoom = 0.01;
private double xPos = 0;
private double yPos = 0;
...

cX = xPos + (x - (fractal.getWidth() >> 1)) * zoom;
cY = yPos + (y - (fractal.getHeight() >> 1)) * zoom;
... 

public void keyReleased(KeyEvent e)
{
    if (e.getKeyCode() == KeyEvent.VK_SPACE)
    {
        zoom *= 0.9;
        ComputeFractal();
    }
    else if (e.getKeyCode() == KeyEvent.VK_LEFT)
    {
        xPos -= 10 * zoom;
        ComputeFractal();
    }
    else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
    {
        xPos += 10 * zoom;
        ComputeFractal();
    }
    else if (e.getKeyCode() == KeyEvent.VK_UP)
    {
        yPos -= 10 * zoom;
        ComputeFractal();
    }
    else if (e.getKeyCode() == KeyEvent.VK_DOWN)
    {
        yPos += 10 * zoom;
        ComputeFractal();
    }
}

I had to do mandelbrot as my homework in university, so you can check it out here here if you are interested.

Fauser
  • 1
  • 2