Search code examples
javaimagezooming

What should I do to allow a general rectangular region of the complex plane to be viewed in the image?


I hope everyone's doing fine :) I have a Java program that shows an image and I need to modify it in order to allow a general rectangular region of the complex plane to be viewed in the image. The user may select the rectangle by dragging the mouse. Could anyone help me do it ? Here's the code :

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

 public class Mandelbrot extends JApplet {
 public static void main(String s[]) {
 JFrame frame = new JFrame();
  frame.setTitle("Mandelbrot set");
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 JApplet applet = new Mandelbrot();
 applet.init();
 frame.getContentPane().add(applet);
 frame.pack();
 frame.setVisible(true);
 }

 public void init() {
 JPanel panel = new MandelbrotPanel();
 getContentPane().add(panel);
 }
 }

 class MandelbrotPanel extends JPanel{
 BufferedImage bi;

 public MandelbrotPanel() {
 int w = 500;
 int h = 500;
 setPreferredSize(new Dimension(w, h));
 setBackground(Color.white);
 bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
 WritableRaster raster = bi.getRaster();
 int[] rgb = new int[3];
 float xmin = -2;
 float ymin = -2;
 float xscale = 4f/w;
 float yscale = 4f/h;
 for (int i = 0; i < h; i++) {
 for (int j = 0; j < w; j++) {
 float cr = xmin + j * xscale;
 float ci = ymin + i * yscale;
 int count = iterCount(cr, ci);
 rgb[0] = (count & 0x07) << 5;
 rgb[1] = ((count >> 3) & 0x07) << 5;
 rgb[2] = ((count >> 6) & 0x07) << 5;
 raster.setPixel(j, i, rgb);
 }
 }
 }

 private int iterCount(float cr, float ci) {
 int max = 512;
 float zr = 0;
 float zi = 0;
 float lengthsq = 0;
 int count = 0;
 while ((lengthsq < 4.0) && (count < max)) {
 float temp = zr * zr - zi * zi + cr;
 zi = 2 * zr * zi + ci;
 zr = temp;
 lengthsq = zr * zr + zi * zi;
 count++;
 }
 return max-count;
 }

 public void paintComponent(Graphics g) {
 super.paintComponent(g);
 g.drawImage(bi, 0, 0, this);
 }
 }

Thank you in advance :)


Solution

  • You'll need to keep track of the rectangle of the complex plane you are showing the user. You can use the Rectangle2D.Double class in java.awt.geom for that. The initial rectangle has a top-left corner of -2+2i and width and height 4:

    Rectangle2D.Double viewRect = new Rectangle2D.Double(-2, 2, 4, 4);
    

    You'll need to move the drawing code outside the constructor so it can run more than once, and adjust it so it takes into account the current viewRect:

     float xmin = viewRect.x;
     float ymin = viewRect.y;
     float xscale = viewRect.width/w;
     float yscale = viewRect.height/h;
    

    When you add the methods to get notified of mouse drag, you'll need to compute the new viewRect. The top-left corner corresponds to the complex number where the drag started. Since there's no complex number class in Java, let's use Point2D.Double temporarily:

        Point2D.Double dragStartComplex = new Point2D.Double(
                viewRect.x + viewRect.width * dragStart.x/w,
                viewRect.y - viewRect.height * dragStart.y/h);
    

    Similarly you can figure out on which complex number the drag ended:

        Point2D.Double dragEndComplex = new Point2D.Double(
                viewRect.x + viewRect.width * dragEnd.x/w,
                viewRect.y - viewRect.height * dragEnd.y/h);
    

    Once you have the corners, you can compute the new view rectangle. After that you would repaint.

        viewRect.setRect(dragStartPoint.x, dragStartPoint.y, 
                dragEndPoint.x-dragStartPoint.x, dragEndPoint.y-dragStartPoint.y);
    

    This is a slight over-simplification because nothing guarantees the user will always drag from left to right and from top to down. To support other drag directions you'll have to juggle the coordinates, so that (viewRect.x,viewRect.y) is always the top-left corner.