package mandelbrot; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; /** * * @author Rolf */ public class Mandelbrot extends JPanel implements MouseListener, KeyListener, MouseWheelListener { static int width = 800; // pixel size of our image static int height = 600; // pixel size of our image double centreX = 0; // center of our image double centreY = 0; // center of our image double dx = 4; // real size betwenn max,min of X int max_iteration = 50; int printScale = 5; // x time larger than screen for printing int mouse_X = 0; int mouse_Y = 0; boolean busy = false; BufferedImage img = null; JProgressBar progressBar; int regOffset = 0; public Mandelbrot(JFrame frame) { // constructor: Add mouse Listener addMouseListener(this); frame.addKeyListener(this); addMouseWheelListener(this); progressBar = new JProgressBar(0, width); progressBar.setValue(0); progressBar.setStringPainted(true); add(progressBar); img = createMyImage(width, height, max_iteration, 1); } private void saveFile(BufferedImage img) { Calendar now = Calendar.getInstance(); File outputfile = new File("c:\\temp\\MandelBrot " + now.get(Calendar.YEAR) + "." + now.get(Calendar.MONTH) + "." + now.get(Calendar.DAY_OF_MONTH) + " " + now.get(Calendar.HOUR_OF_DAY) + "_" + now.get(Calendar.MINUTE) + ".png"); System.out.println("Start writing to file: " + outputfile.getAbsolutePath()); try { //ImageIO.write(img, "jpg", outputfile); BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputfile)); ImageIO.write(img, "png", outputStream); outputStream.close(); } catch (IOException ex) { Logger.getLogger(Mandelbrot.class.getName()).log(Level.SEVERE, null, ex); } System.out.println(" created"); } public void paint(Graphics g) { // try to get real point dimensions //Rectangle r = g.getClipBounds(); if (img != null) { g.drawImage(img, 0, 0, this); } } private double getMinCx() { return centreX - dx / 2.0; } private double getMaxCx() { return centreX + dx / 2.0; } private double getMinCy() { return centreY - dx / 2.0 * (double) height / (double) width; } private double getMaxCy() { return centreY + dx / 2.0 * (double) height / (double) width; } private int getPixW(double p, int width, int height) { // get X Pixel for Point p, where real dimension are between min and max return (int) (width * (p - getMinCx()) / (getMaxCx() - getMinCx())); } private int getPixH(double p, int width, int height) { // get Y Pixel for Point p, where real dimension are between min and max return (int) (height * (p - getMinCy()) / (getMaxCy() - getMinCy())); } private double getResolution(int width) { return (getMaxCx() - getMinCx()) / width; } private BufferedImage createMyImage(int width, int height, int max_iteration, int zoom) { BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); double max_betrags_quadrat = 4; double point_dx = getResolution(width); progressBar.setMaximum(width); for (int pix_x = 0; pix_x < width; pix_x++) { progressBar.setValue(pix_x); double cx = getMinCx() + pix_x * point_dx; for (int pix_y = 0; pix_y < height; pix_y++) { double cy = getMinCy() + pix_y * point_dx; int iteration = punkt_iteration(cx, cy, max_betrags_quadrat, max_iteration); int rgb = set_rgb(iteration, max_iteration); bufferedImage.setRGB(pix_x, pix_y, rgb); } } // axis Graphics g = bufferedImage.getGraphics(); g.setColor(Color.WHITE); g.setFont(new Font("TimesRoman", Font.PLAIN, 12 * zoom)); //g.drawString("Z[n+1] = Z²[n] + c; Z[0]=0; c=complex; n=0,1,2,...; |Z[n]|>=2", 24 * zoom, 24 * zoom); g.drawString("Z[n+1] = Z²[n] + c; Z[0]=0; c=complex; n=0,1,2,...; |Z[n]|>=2", 32 * zoom, 32 * zoom); g.drawString("center: " + (getMinCx() + width / 2 * point_dx) + " " + (-(getMinCy() + height / 2 * point_dx)) + "j", 32 * zoom, 55 * zoom); // axis int y = getPixH(0, width, height); g.drawLine(0, y, width, y); int x = getPixW(0, width, height); g.drawLine(x, 0, x, height); progressBar.setValue(width); //System.out.println("Ready x=" + minCx + "/" + maxCx + " y=" + minCy + "/" + maxCy); return bufferedImage; } private int get_rgb(int Wert) { // Regenbogen Farbe /* * es gibt 3*2 Phasen * * 1.2. Phase: Grün steigt von 0..255 und dann wieder auf 0 * * 3.4. Phase: Blau steigt und fällt * * 5.6. Phase: Rot steigt und fällt */ Wert = Wert * 4; Wert = Wert % 254; int Red, Green, Blue = 0; int Phase = Wert / 51; int Level = Wert % 51; switch (Phase) { case 0: Red = 255; Green = Level * 5; Blue = 0; break; case 1: Red = 255 - Level * 5; Green = 255; Blue = 0; break; case 2: Red = 0; Green = 255; Blue = Level * 5; break; case 3: Red = 0; Green = 255 - Level * 5; Blue = 255; break; case 4: Red = Level * 5; Green = 0; Blue = 255; break; default: Red = Green = Blue = 255; } return Red * 256 * 256 + Green * 256 + Blue; } private int set_rgb(int iteration, int max_iteration) { if (iteration == max_iteration) { return Color.BLACK.getRGB(); } return get_rgb(regOffset + iteration); //return iteration * 0x18; } private int punkt_iteration(double cx, double cy, double max_betrag_quadrat, int max_iter) { double betrag_quadrat = 0; int iter = 0; double x = 0; double y = 0; while (betrag_quadrat <= max_betrag_quadrat && iter < max_iter) { double xt = x * x - y * y + cx; double yt = 2 * x * y + cy; x = xt; y = yt; iter++; betrag_quadrat = x * x + y * y; } return iter; } //-------------------------------------------------------------------------- // mouse Handler //-------------------------------------------------------------------------- @Override public void mouseClicked(MouseEvent e) { if (!busy) { busy = true; mouse_X = e.getX(); mouse_Y = e.getY(); double zoom = 2; switch (e.getModifiers()) { case InputEvent.BUTTON1_MASK: { new Thread(new Runnable() { @Override public void run() { img = createMyImage(width, height, max_iteration, 1); repaint(); busy = false; } }).start(); break; } case InputEvent.BUTTON2_MASK: { zoom = 1.0; mouse_X = width / 2; mouse_Y = height / 2; new Thread(new Runnable() { @Override public void run() { saveFile(createMyImage(width * printScale, height * printScale, max_iteration, printScale)); busy = false; } }).start(); break; } case InputEvent.BUTTON3_MASK: { zoom = 1 / zoom; new Thread(new Runnable() { @Override public void run() { img = createMyImage(width, height, max_iteration, 1); repaint(); busy = false; } }).start(); break; } } centreX = getMinCx() + (dx * (double) (mouse_X) / (double) width); double dy = (getMaxCy() - getMinCy()); centreY = getMinCy() + (dy * (double) (mouse_Y) / (double) height); dx = dx / zoom; } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { // throw new UnsupportedOperationException("Not supported yet."); } //-------------------------------------------------------------------------- // Key Handler //-------------------------------------------------------------------------- @Override public void keyTyped(KeyEvent e) { //throw new UnsupportedOperationException("Not supported yet."); } @Override public void keyPressed(KeyEvent e) { boolean repaint = true; switch (e.getKeyChar()) { case 'u': max_iteration = max_iteration * 2; break; case 'd': max_iteration = max_iteration / 2; break; default: System.out.println("not supported: " + e.getKeyChar()); repaint = false; } if (!busy && repaint) { busy = true; new Thread(new Runnable() { @Override public void run() { img = createMyImage(width, height, max_iteration, 1); repaint(); busy = false; } }).start(); } } @Override public void keyReleased(KeyEvent e) { //throw new UnsupportedOperationException("Not supported yet."); } //-------------------------------------------------------------------------- // MouseWheel //-------------------------------------------------------------------------- @Override public void mouseWheelMoved(MouseWheelEvent e) { //throw new UnsupportedOperationException("Not supported yet."); if (!busy) { busy = true; int n = e.getUnitsToScroll(); regOffset += n; regOffset = (regOffset + 256) % 256; new Thread(new Runnable() { @Override public void run() { img = createMyImage(width, height, max_iteration, 1); repaint(); busy = false; } }).start(); } } //-------------------------------------------------------------------------- // Main //-------------------------------------------------------------------------- public static void main(String[] args) { //1. Create the frame. JFrame frame = new JFrame("Mandelbrot"); //2. Optional: What happens when the frame closes? frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //4. Size the frame. frame.setSize(width + 8, height + 27); // frame.pack(); frame.getContentPane().add(new Mandelbrot(frame)); //5. Show it. frame.setVisible(true); System.out.println("--------------------------------"); System.out.println("Welcome to Mandelbrot 2014-11-17"); System.out.println("--------------------------------"); System.out.println("use mouse to rebuild picture"); System.out.println("- left button: zoom in"); System.out.println("- right button: zoom out"); System.out.println("- middle button: save as file"); System.out.println("- scroll wheel to change color\n"); System.out.println("u key to increase max iteration"); System.out.println("d key to decrease max iteration"); } }