Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zooming in on Mandelbrot set fractal in Java

I am beginning to make a mandelbrot set fractal viewer. I am having a lot of issues when it comes to zooming in on the fractal. If you try to zoom, the viewer will just close in on the center. I have done as much as I can to understand this dilemma. How can I zoom in on my fractal in such a way that when I zoom, it will zoom in on the center of the screen, and not the center of the fractal?

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.awt.event.*;



public class Mandelbrot extends JFrame implements ActionListener {

    private JPanel ctrlPanel;
    private JPanel btnPanel;
    private int numIter = 50;
    private double zoom = 130;
    private double zoomIncrease = 100;
    private int colorIter = 20;
    private BufferedImage I;
    private double zx, zy, cx, cy, temp;
    private int xMove, yMove = 0;
    private JButton[] ctrlBtns = new JButton[9];
    private Color themeColor = new Color(150,180,200);

    public Mandelbrot() {
        super("Mandelbrot Set");
        setBounds(100, 100, 800, 600);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        plotPoints();

        Container contentPane = getContentPane();

        contentPane.setLayout(null);




        ctrlPanel = new JPanel();
        ctrlPanel.setBounds(600,0,200,600);
        ctrlPanel.setBackground(themeColor);
        ctrlPanel.setLayout(null);

        btnPanel = new JPanel();
        btnPanel.setBounds(0,200,200,200);
        btnPanel.setLayout(new GridLayout(3,3));
        btnPanel.setBackground(themeColor);

        ctrlBtns[1] = new JButton("up");
        ctrlBtns[7] = new JButton("down");
        ctrlBtns[3] = new JButton ("left");
        ctrlBtns[5] = new JButton("right");
        ctrlBtns[2] = new JButton("+");
        ctrlBtns[0] = new JButton("-");
        ctrlBtns[8] = new JButton(">");
        ctrlBtns[6] = new JButton("<");
        ctrlBtns[4] = new JButton();

        contentPane.add(ctrlPanel);
        contentPane.add(new imgPanel());
        ctrlPanel.add(btnPanel);

        for (int x = 0; x<ctrlBtns.length;x++){
            btnPanel.add(ctrlBtns[x]);
            ctrlBtns[x].addActionListener(this);
        }

        validate();

    }

    public class imgPanel extends JPanel{
        public imgPanel(){
            setBounds(0,0,600,600);

        }

        @Override
        public void paint (Graphics g){
            super.paint(g);
            g.drawImage(I, 0, 0, this);
        }
    }

    public void plotPoints(){
        I = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        for (int y = 0; y < getHeight(); y++) {
            for (int x = 0; x < getWidth(); x++) {
                zx = zy = 0;
                cx = (x - 320+xMove) / zoom;
                cy = (y - 290+yMove) / zoom;
                int iter = numIter;
                while (zx * zx + zy * zy < 4 && iter > 0) {
                    temp = zx * zx - zy * zy + cx;
                    zy = 2 * zx * zy + cy;
                    zx = temp;
                    iter--;
                }
                I.setRGB(x, y, iter | (iter << colorIter));
            }
        }
    }

    public void actionPerformed(ActionEvent ae){
        String event = ae.getActionCommand();

        switch (event){
        case "up":
            yMove-=100;
            break;
        case "down":
            yMove+=100;
            break;
        case "left":
            xMove-=100;
            break;
        case "right":
            xMove+=100;
            break;
        case "+":
            zoom+=zoomIncrease;
            zoomIncrease+=100;
            break;
        case "-":
            zoom-=zoomIncrease;
            zoomIncrease-=100;
            break;
        case ">":
            colorIter++;
            break;
        case "<":
            colorIter--;
            break;
        }



        plotPoints();
        validate();
        repaint();
    }




    public static void main(String[] args) {
        new Mandelbrot().setVisible(true);
    }
}
like image 714
user1938979 Avatar asked Dec 31 '12 04:12

user1938979


1 Answers

The Mandelbrot set exists in a mathematical plane with natural coordinates. You "view" this with a BufferedImage I using "view port" coordinates. It is all in the mapping between these. You have labeled the viewport coordinates as x and y, and the "real" coordinates into the Mandelbrot space as cx and cy. These are the formulae:

        cx = (x - 320+xMove) / zoom;
        cy = (y - 290+yMove) / zoom;

In order to zoom in and out of a particular "real" spot, you want the amount of your displacement to be constant as you zoom. The problem is that the amount of displacement is being scaled by the zoom amount. Remember cx and cy are the real coordinates in the Mandelbrot plane and x & y are the viewport coordinates. Thus, when looking at the middle of the viewport, as you change zoom, you want cx & cy to remain constant.

My guess is that you want something like:

    cx = ((x - 320) / zoom) + xMove;
    cy = ((y - 290) / zoom) + yMove;

This will make the "movement" in the Mandelbrot plane remain independent of zoom amount. I am assuming that the 320 and 290 is related to viewport size and gives you a zero in the middle of the viewport.

You are going to want the amount that xMove & yMove change on a keystroke to not be a fixed amount (100) but rather an amount that depends on zoom level. As you zoom in a lot you want the amount of movement in the real Mandelbrot plane to be smaller for each keystroke.

like image 130
AgilePro Avatar answered Sep 19 '22 15:09

AgilePro