Changing the center of a GUI with mouseclick, and repainting

286 views Asked by At

I've got a GUI that generates a graphics image using the Mandelbrot set. I've implemented some zoom buttons, but I'd like to be able to change the centre of my GUI with a mouseclick (make mouse coordinates the new centre-point). It's proving to be quite difficult. Any suggestions? My attempt can be found at the moveGraph method.

Thanks in advance!

package assn4_12mgs;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class MandelBrot extends JFrame{
    MandelPanel mp;
    double xMax = 2.26;
    double xMin = -2.24;
    double yMax = 2.26;
    double yMin = -2.24;
    double yMove, xMove;

    static double ESCAPE_MODULUS = 2.0;
    static int MAX_ITERATIONS = 32;

    public MandelBrot(){
        super();
        setLayout(new BorderLayout());
        setTitle("Graham's Mandelbrot GUI");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600,700);
        setResizable(false);

        mp = new MandelPanel();
        mp.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent evt) {
                MoveGraph(evt);
            }
        });

        JPanel panel = new JPanel(new FlowLayout());
        JButton zoomIn = new JButton("+");
        zoomIn.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent evt) {
                ZoomIn(evt);
            }
        });

        JButton zoomOut = new JButton("-");
        zoomOut.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent evt) {
                ZoomOut(evt);
            }
        });
        JButton reset = new JButton("Reset");
        reset.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent evt) {
                reset(evt);
            }
        });

        panel.add(reset, BorderLayout.WEST); ///How to change positioning?
        panel.add(zoomOut, BorderLayout.EAST);
        panel.add(zoomIn, BorderLayout.EAST); 
        add(panel, BorderLayout.SOUTH);
        add(mp, BorderLayout.NORTH);
    }

    private void MoveGraph(MouseEvent evt){
        int x = evt.getPoint().x;
        int y = evt.getPoint().y;
        xMove = x/100;
        yMove = y/100;
        mp.repaint();
    }
    private void ZoomIn(MouseEvent evt){
        xMax /= 2;
        xMin /= 2;
        yMax /= 2;
        yMin /= 2;
        mp.repaint();
    }
    private void ZoomOut(MouseEvent evt){
        xMax *= 2;
        xMin *= 2;
        yMax *= 2;
        yMin *= 2;
        mp.repaint();
    }
    private void reset(MouseEvent evt){
        xMax = 2.26;
        xMin = -2.24;
        yMax = 2.26;
        yMin = -2.24;
        xMove = 0;
        yMove = 0;
        mp.repaint();
    }

    public class MandelPanel extends JPanel {
        public MandelPanel() {
            setPreferredSize(new Dimension(600,600));
        }

        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            // draw here
            int row, col;
            ComplexNumber c, z;
            double xPos, yPos;
            double modulus = 0;
            boolean escaped = false;
            int iterations = 0;
            int desiredColour;
            // Calculate the scale factor to go from pixels to actual units
            int height = mp.getHeight();   // drawingZone is the JPanel drawing area
            int width = mp.getWidth();
            double xScale = (xMax - xMin) / width;  // These are min and max values in actual
            double yScale = (yMax - yMin) / height; // coordinates.

            Graphics2D g2D = (Graphics2D)g;

            BufferedImage pretty = new BufferedImage(width, height, 
                        BufferedImage.TYPE_3BYTE_BGR);

            // Iterate through the entire panel, pixel by pixel
            for (row = 0; row < height; row++) {
                // Calculate the actual y position
                yPos = yMax - row * yScale;// - yMove
                for (col = 0; col < width; col++) {
                    // Calculate the actual x position
                    xPos = xMin + col * xScale;// + xMove;
                    // Create the complex number for this position
                    c = new ComplexNumber(xPos, yPos);
                    z = new ComplexNumber(0, 0);
                    iterations = 0;
                    // Iterate the fractal equation z = z*z + c
                    // until z either escapes or the maximum number of iterations
                    // is reached
                    do {
                        z = (z.multiply(z)).add(c);
                        modulus = z.abs();
                        escaped = modulus > ESCAPE_MODULUS;
                        iterations++;
                    } while (iterations < MAX_ITERATIONS && !escaped);
                    // Set the colour according to what stopped the above loop
                    if (escaped) {
                        desiredColour = setEscapeColour(iterations);
                    } else {
                        desiredColour = setColour(modulus);
                    }
                    pretty.setRGB(col, row, desiredColour);

                } // end for
            } // end for
            g2D.drawImage(pretty, null, 0, 0);

            //yMove = 0;
            //xMove = 0;
        }
    }

    // Sets gray level for escape situation
    private static int setEscapeColour(int numIterations) {
        float grayLevel = 0.5F - (float) numIterations / MAX_ITERATIONS;
        grayLevel = Math.max(grayLevel, 0.1F);
        return new Color(grayLevel, grayLevel, grayLevel).getRGB();
    } // end setEscapeColour

    // Sets colour level for interior situation
    // The algorithm used here is *totally* empirical!
    private static int setColour(double modulus) {
        float factor = (float) (modulus / ESCAPE_MODULUS);
        float incr = (float) Math.log10(factor * 5.5);
        float r = Math.min(Math.abs(10.0F * incr) * factor, 1.0F);
        float g = Math.min(Math.abs(6.0F * incr) * factor, 1.0F);
        float b = Math.min(Math.abs(0.5F * factor + incr), 1.0F);
        return new Color(r, g, b).getRGB();
    } // end setColour

    public static void main(String args[]){
        MandelBrot manBrot = new MandelBrot();
        manBrot.setVisible(true);

    }
}
1

There are 1 answers

0
Developer Marius Žilėnas On

We take a point on which a user has clicked as a center point for drawing, then calculate the window (half the distance up and down, left and right) around that point. See

                /**
                 * Calculate real coordinates of the point we clicked.
                 */
                double xDist = Math.abs(xMax) + Math.abs(xMin);
                double yDist = Math.abs(yMax) + Math.abs(yMin);
                double xTr   = xDist / 600.0 * ((double) e.getX());
                double yTr   = yDist / 700.0 * ((double) e.getY());

                /**
                 * Calculate the window coordinates. It is relative to the point where the user clicked.
                 */
                xMax = xTr + xDist/2.0;
                xMin = xTr - xDist/2.0;
                yMax = yTr + yDist/2.0;
                yMin = yTr - yDist/2.0;

** The Code**

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JOptionPane;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class MandelBrot 
    extends JFrame
{
    public static class ComplexNumber
    {
        double re;
        double im;

        public void setRe(double re)
        {
            this.re = re;
        }

        public double re()
        {
            return re;
        }

        public void setIm(double im)
        {
            this.im = im;
        }

        public double im()
        {
            return im;
        }

        public ComplexNumber(double re, double im)
        {
            this.re = re;
            this.im = im;
        }

        public ComplexNumber add(ComplexNumber c)
        { 
            setRe(re() + c.re());
            setIm(im() + c.im());
            return this;
        }

        public ComplexNumber multiply(ComplexNumber z)
        {
            setRe(re()*z.re() - im()*z.im());
            setIm(im()*z.re() - re()*z.im());
            return this;
        }

        public double abs()
        {
            return Math.sqrt(re()*re() + im()*im());
        }
    }

    MandelPanel mp;
    double xMax = 2.26;
    double xMin = -2.24;
    double yMax = 2.26;
    double yMin = -2.24;
    double yMove, xMove;

    static double ESCAPE_MODULUS = 2.0;
    static int MAX_ITERATIONS = 32;

    public MandelBrot()
    {
        super();
        setLayout(new BorderLayout());
        setTitle("Graham's Mandelbrot GUI");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 700);
        setResizable(false);

        mp = new MandelPanel();
        mp.addMouseListener(new MouseAdapter()
        {
            public void mouseClicked(MouseEvent e)
            { 
                JOptionPane.showMessageDialog(
                        null, 
                        "You clicked on a picture area (x,y): (" + e.getX() + "," + e.getY() + ")" ,
                        "Info",
                        JOptionPane.INFORMATION_MESSAGE);

                double xDist = Math.abs(xMax) + Math.abs(xMin);
                double yDist = Math.abs(yMax) + Math.abs(yMin);
                double xTr   = xDist / 600.0 * ((double) e.getX());
                double yTr   = yDist / 700.0 * ((double) e.getY());

                xMax = xTr + xDist/2.0;
                xMin = xTr - xDist/2.0;
                yMax = yTr + yDist/2.0;
                yMin = yTr - yDist/2.0;
                System.out.format("%f %f %f %f %n", xDist, yDist, xTr, yTr);
                System.out.format("%f %f %f %f %n", xMin, xMax, yMin, yMax);

                mp.repaint();
            }
            public void mouseReleased(MouseEvent evt)
            {
                MoveGraph(evt);
            }
        });

        JPanel panel = new JPanel(new FlowLayout());
        JButton zoomIn = new JButton("+");
        zoomIn.addMouseListener(new MouseAdapter()
        {
            public void mouseReleased(MouseEvent evt)
            {
                ZoomIn(evt);
            }
        });

        JButton zoomOut = new JButton("-");
        zoomOut.addMouseListener(new MouseAdapter()
        {
            public void mouseReleased(MouseEvent evt)
            {
                ZoomOut(evt);
            }
        });
        JButton reset = new JButton("Reset");
        reset.addMouseListener(new MouseAdapter()
        {
            public void mouseReleased(MouseEvent evt)
            {
                reset(evt);
            }
        });

        panel.add(reset, BorderLayout.WEST); ///How to change positioning?
        panel.add(zoomOut, BorderLayout.EAST);
        panel.add(zoomIn, BorderLayout.EAST);
        add(panel, BorderLayout.SOUTH);
        add(mp, BorderLayout.NORTH);
    }

    private void MoveGraph(MouseEvent evt)
    {
        int x = evt.getPoint().x;
        int y = evt.getPoint().y;
        xMove = x / 100;
        yMove = y / 100;
        mp.repaint();
    }

    private void ZoomIn(MouseEvent evt)
    {
        xMax /= 2;
        xMin /= 2;
        yMax /= 2;
        yMin /= 2;
        mp.repaint();
    }

    private void ZoomOut(MouseEvent evt)
    {
        xMax *= 2;
        xMin *= 2;
        yMax *= 2;
        yMin *= 2;
        mp.repaint();
    }

    private void reset(MouseEvent evt)
    {
        xMax = 2.26;
        xMin = -2.24;
        yMax = 2.26;
        yMin = -2.24;
        xMove = 0;
        yMove = 0;
        mp.repaint();
    }

    public class MandelPanel
            extends JPanel
    {

        public MandelPanel()
        {
            setPreferredSize(new Dimension(600, 600));
        }

        @Override
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);

            // draw here
            int row, col;
            ComplexNumber c, z;
            double xPos, yPos;
            double modulus = 0;
            boolean escaped = false;
            int iterations = 0;
            int desiredColour;
            // Calculate the scale factor to go from pixels to actual units
            int height = mp.getHeight();   // drawingZone is the JPanel drawing area
            int width = mp.getWidth();
            double xScale = (xMax - xMin) / width;  // These are min and max values in actual
            double yScale = (yMax - yMin) / height; // coordinates.

            Graphics2D g2D = (Graphics2D) g;

            BufferedImage pretty = new BufferedImage(width, height,
                    BufferedImage.TYPE_3BYTE_BGR);

            // Iterate through the entire panel, pixel by pixel
            for (row = 0; row < height; row++)
            {
                // Calculate the actual y position
                yPos = yMax - row * yScale;// - yMove
                for (col = 0; col < width; col++)
                {
                    // Calculate the actual x position
                    xPos = xMin + col * xScale;// + xMove;
                    // Create the complex number for this position
                    c = new ComplexNumber(xPos, yPos);
                    z = new ComplexNumber(0, 0);
                    iterations = 0;
                    // Iterate the fractal equation z = z*z + c
                    // until z either escapes or the maximum number of iterations
                    // is reached
                    do
                    {
                        z = (z.multiply(z)).add(c);
                        modulus = z.abs();
                        escaped = modulus > ESCAPE_MODULUS;
                        iterations++;
                    }
                    while (iterations < MAX_ITERATIONS && !escaped);
                    // Set the colour according to what stopped the above loop
                    if (escaped)
                    {
                        desiredColour = setEscapeColour(iterations);
                    }
                    else
                    {
                        desiredColour = setColour(modulus);
                    }
                    pretty.setRGB(col, row, desiredColour);

                } // end for
            } // end for
            g2D.drawImage(pretty, null, 0, 0);

            //yMove = 0;
            //xMove = 0;
        }
    }

    // Sets gray level for escape situation
    private static int setEscapeColour(int numIterations)
    {
        float grayLevel = 0.5F - (float) numIterations / MAX_ITERATIONS;
        grayLevel = Math.max(grayLevel, 0.1F);
        return new Color(grayLevel, grayLevel, grayLevel).getRGB();
    } // end setEscapeColour

    // Sets colour level for interior situation
    // The algorithm used here is *totally* empirical!
    private static int setColour(double modulus)
    {
        float factor = (float) (modulus / ESCAPE_MODULUS);
        float incr = (float) Math.log10(factor * 5.5);
        float r = Math.min(Math.abs(10.0F * incr) * factor, 1.0F);
        float g = Math.min(Math.abs(6.0F * incr) * factor, 1.0F);
        float b = Math.min(Math.abs(0.5F * factor + incr), 1.0F);
        return new Color(r, g, b).getRGB();
    } // end setColour

    public static void main(String args[])
    {
        MandelBrot manBrot = new MandelBrot();
        manBrot.setVisible(true);
    }
}