From 1eaf63e2fee1b20c38a70349f2803f668fa98fb8 Mon Sep 17 00:00:00 2001 From: Falko Habel Date: Wed, 29 May 2024 18:38:08 +0200 Subject: [PATCH] performace not very good but it is working --- MandelbrotVisualizer.java | 186 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 MandelbrotVisualizer.java diff --git a/MandelbrotVisualizer.java b/MandelbrotVisualizer.java new file mode 100644 index 0000000..27f5d2e --- /dev/null +++ b/MandelbrotVisualizer.java @@ -0,0 +1,186 @@ +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class MandelbrotVisualizer extends JPanel implements MouseWheelListener, MouseMotionListener, MouseListener { + private static final int WIDTH = 800; + private static final int HEIGHT = 800; + private BufferedImage image; + private double zoom = 200; + private double offsetX = 0; + private double offsetY = 0; + private int lastX, lastY; + private ExecutorService executor; + + public MandelbrotVisualizer() { + image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); + addMouseWheelListener(this); + addMouseMotionListener(this); + addMouseListener(this); + executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + renderMandelbrot(); + } + + /** + * Renders the Mandelbrot set in the window. + */ + private void renderMandelbrot() { + // Shutdown the existing executor and create a new one with the number of available processors. + executor.shutdownNow(); + executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + + // Iterate through each pixel in the image. + for (int x = 0; x < WIDTH; x++) { + final int fx = x; + + // Submit a task to the executor for each row in the image. + executor.submit(() -> { + for (int y = 0; y < HEIGHT; y++) { + double zx = (fx - WIDTH / 2) / zoom + offsetX; + double zy = (y - HEIGHT / 2) / zoom + offsetY; + + // Calculate the complex number c. + float c = mandelbrot(zx, zy); + + // Determine the color for the pixel based on the value of c. + int color = Color.HSBtoRGB(0.7f + 10 * c, 0.7f, c > 0 ? 1 : 0); + + // Set the color of the pixel in the image. + image.setRGB(fx, y, color); + } + + // Repaint the window to display the updated image. + repaint(); + }); + } + + // Shutdown the executor and wait for all tasks to complete. + /** + * Attempts to shut down the executor and wait for all tasks to complete. If an InterruptedException occurs, print the stack trace. + */ + try { + executor.shutdown(); + executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } +} + + /** +* Calculates the number of iterations for a given point in the Mandelbrot set. +* @param zx the real part of the complex number +* @param zy the imaginary part of the complex number +* @return the number of iterations, scaled between 0 and 1 +*/ +private float mandelbrot(double zx, double zy) { + double x = 0, y = 0; + int maxIter = 1000; + int iter; + for (iter = 0; iter < maxIter && x * x + y * y < 4; iter++) { + double temp = x * x - y * y + zx; + y = 2 * x * y + zy; + x = temp; + } + return iter < maxIter ? (float) iter / maxIter : 0; +} + + /** + * Paints the Mandelbrot set in the given Graphics object. + * @param g the Graphics object to paint onto + */ + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + g.drawImage(image, 0, 0, null); + } + + /** + * Handles the mouse wheel event. Zooms in or out based on the scroll direction, and pans the view accordingly. Then repaints the window. + * @param e the MouseWheelEvent that triggered this method call + */ + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + int notches = e.getWheelRotation(); + double mouseX = (e.getX() - WIDTH / 2.0) / zoom + offsetX; + double mouseY = (e.getY() - HEIGHT / 2.0) / zoom + offsetY; + + if (notches < 0) { + zoom *= 1.1; + } else { + zoom /= 1.1; + } + + offsetX = mouseX - (e.getX() - WIDTH / 2.0) / zoom; + offsetY = mouseY - (e.getY() - HEIGHT / 2.0) / zoom; + + renderMandelbrot(); + } + + + /** + * Handles the mouse dragged event. Updates the offset values for zooming and panning, then repaints the window. + */ + @Override + public void mouseDragged(MouseEvent e) { + int dx = e.getX() - lastX; + int dy = e.getY() - lastY; + + offsetX -= dx / zoom; + offsetY -= dy / zoom; + + lastX = e.getX(); + lastY = e.getY(); + + renderMandelbrot(); + } + + + @Override + public void mousePressed(MouseEvent e) { + lastX = e.getX(); + lastY = e.getY(); + } + + @Override + public void mouseMoved(MouseEvent e) {} + + @Override + public void mouseClicked(MouseEvent e) {} + + @Override + public void mouseReleased(MouseEvent e) {} + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseExited(MouseEvent e) {} + +/** +* The main method that initializes and displays the Mandelbrot visualizer window. +*/ + public static void main(String[] args) { + // Create a JFrame to hold the MandelbrotVisualizer panel. + JFrame frame = new JFrame("Mandelbrot Visualizer"); + + // Instantiate the MandelbrotVisualizer panel. + MandelbrotVisualizer panel = new MandelbrotVisualizer(); + + // Add the panel to the frame. + frame.add(panel); + + // Set the size of the frame. + frame.setSize(WIDTH, HEIGHT); + + // Configure the frame's default close operation and center it on the screen. + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setLocationRelativeTo(null); + + // Make the frame visible. + frame.setVisible(true); + } +}