Created
June 15, 2025 17:41
-
-
Save tivrfoa/2d6338740268166357ce018ceaa24ae1 to your computer and use it in GitHub Desktop.
Mandelbrot Set JavaFX - Gemini
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.mandelbrot; | |
import javafx.application.Application; | |
import javafx.scene.Scene; | |
import javafx.scene.canvas.Canvas; | |
import javafx.scene.canvas.GraphicsContext; | |
import javafx.scene.layout.Pane; | |
import javafx.scene.paint.Color; | |
import javafx.stage.Stage; | |
import javafx.scene.image.PixelWriter; | |
import javafx.scene.input.MouseButton; // Import for mouse button detection | |
public class MandelbrotSet extends Application { | |
// --- Configuration --- | |
private static final int WIDTH = 800; | |
private static final int HEIGHT = 600; | |
private static final int MAX_ITERATIONS = 500; // Increase for more detail, decrease for faster rendering | |
private static final double ZOOM_FACTOR = 0.8; // Factor by which to zoom in (0.8 means view becomes 80% of original) | |
// Current view of the complex plane (these define the boundaries of the Mandelbrot rendering) | |
private double realMin; | |
private double realMax; | |
private double imaginaryMin; | |
private double imaginaryMax; | |
@Override | |
public void start(Stage primaryStage) { | |
primaryStage.setTitle("Mandelbrot Set with Zoom"); | |
// Initialize the view to the default Mandelbrot set range | |
resetView(); | |
// Create a canvas to draw on | |
Canvas canvas = new Canvas(WIDTH, HEIGHT); | |
GraphicsContext gc = canvas.getGraphicsContext2D(); | |
// Add mouse click event handler for zooming | |
canvas.setOnMouseClicked(event -> { | |
if (event.getButton() == MouseButton.PRIMARY) { // Left click to zoom in | |
// Get the clicked pixel coordinates on the canvas | |
double mouseX = event.getX(); | |
double mouseY = event.getY(); | |
// Convert the pixel coordinates to complex plane coordinates within the current view | |
// This determines the new center of our zoomed view. | |
double clickedReal = realMin + (mouseX / WIDTH) * (realMax - realMin); | |
double clickedImaginary = imaginaryMin + (mouseY / HEIGHT) * (imaginaryMax - imaginaryMin); | |
// Calculate the current width and height of the complex plane view | |
double currentRealRange = realMax - realMin; | |
double currentImaginaryRange = imaginaryMax - imaginaryMin; | |
// Determine the new, smaller ranges after applying the zoom factor | |
double newRealRange = currentRealRange * ZOOM_FACTOR; | |
double newImaginaryRange = currentImaginaryRange * ZOOM_FACTOR; | |
// Update the boundaries of the complex plane to center on the clicked point | |
// and use the new, smaller ranges. | |
realMin = clickedReal - (newRealRange / 2.0); | |
realMax = clickedReal + (newRealRange / 2.0); | |
imaginaryMin = clickedImaginary - (newImaginaryRange / 2.0); | |
imaginaryMax = clickedImaginary + (newImaginaryRange / 2.0); | |
// Redraw the Mandelbrot set with the new zoomed view | |
drawMandelbrot(gc); | |
} else if (event.getButton() == MouseButton.SECONDARY) { // Right click to reset view | |
// Reset the complex plane view to its initial, default state | |
resetView(); | |
// Redraw the Mandelbrot set after resetting the view | |
drawMandelbrot(gc); | |
} | |
}); | |
// Draw the initial Mandelbrot set when the application starts | |
drawMandelbrot(gc); | |
// Set up the scene and show the stage | |
Pane root = new Pane(); | |
root.getChildren().add(canvas); | |
Scene scene = new Scene(root, WIDTH, HEIGHT); | |
primaryStage.setScene(scene); | |
primaryStage.setResizable(false); // Set to false to maintain fixed canvas size | |
primaryStage.show(); | |
} | |
/** | |
* Resets the complex plane view to the default, wide range for the Mandelbrot set. | |
*/ | |
private void resetView() { | |
realMin = -2.5; // Default minimum real value | |
realMax = 1.0; // Default maximum real value | |
imaginaryMin = -1.5; // Default minimum imaginary value | |
imaginaryMax = 1.5; // Default maximum imaginary value | |
} | |
/** | |
* Iterates through each pixel on the canvas, maps it to the current complex plane view, | |
* and colors it based on the Mandelbrot set algorithm. | |
* @param gc The GraphicsContext of the canvas to draw upon. | |
*/ | |
private void drawMandelbrot(GraphicsContext gc) { | |
PixelWriter pixelWriter = gc.getPixelWriter(); | |
// Calculate the current width and height of the complex plane that is being displayed | |
double realRange = realMax - realMin; | |
double imaginaryRange = imaginaryMax - imaginaryMin; | |
// Loop through every pixel on the canvas | |
for (int x = 0; x < WIDTH; x++) { | |
for (int y = 0; y < HEIGHT; y++) { | |
// Map the current pixel coordinates (x, y) to a point in the complex plane | |
// based on the current real and imaginary ranges. | |
double real = realMin + (double)x / WIDTH * realRange; | |
double imaginary = imaginaryMin + (double)y / HEIGHT * imaginaryRange; | |
// Initialize complex numbers for the Mandelbrot iteration | |
Complex c = new Complex(real, imaginary); // The constant 'c' for the current pixel | |
Complex z = new Complex(0, 0); // The iterated 'z' value, starts at (0,0) | |
int iterations = 0; | |
// The core Mandelbrot algorithm: z = z^2 + c | |
// Continue iterating as long as the magnitude of z is less than 2 | |
// and the maximum number of iterations has not been reached. | |
while (z.abs() < 2 && iterations < MAX_ITERATIONS) { | |
z = z.multiply(z).add(c); | |
iterations++; | |
} | |
// Color the pixel based on the number of iterations it took to escape (or not escape) | |
if (iterations == MAX_ITERATIONS) { | |
// If MAX_ITERATIONS was reached, the point is likely in the Mandelbrot set. | |
// Color it black. | |
pixelWriter.setColor(x, y, Color.BLACK); | |
} else { | |
// If the point escaped, color it based on how quickly it escaped. | |
// Using HSB (Hue, Saturation, Brightness) color space creates a smooth gradient effect. | |
double hue = 360.0 * iterations / MAX_ITERATIONS; // Hue varies based on iterations | |
pixelWriter.setColor(x, y, Color.hsb(hue, 0.9, 0.9)); // Solid saturation and brightness | |
} | |
} | |
} | |
} | |
/** | |
* A helper class to represent complex numbers and their basic operations (addition, multiplication, absolute value). | |
* This makes the Mandelbrot calculation more readable and mathematically accurate. | |
*/ | |
private static class Complex { | |
private final double real; | |
private final double imaginary; | |
public Complex(double real, double imaginary) { | |
this.real = real; | |
this.imaginary = imaginary; | |
} | |
// Returns the magnitude (absolute value) of the complex number: |a + bi| = sqrt(a^2 + b^2) | |
public double abs() { | |
return Math.sqrt(real * real + imaginary * imaginary); | |
} | |
// Returns the sum of this complex number and another complex number: (a + bi) + (c + di) = (a+c) + (b+d)i | |
public Complex add(Complex other) { | |
return new Complex(this.real + other.real, this.imaginary + other.imaginary); | |
} | |
// Returns the product of this complex number and another: (a + bi) * (c + di) = (ac - bd) + (ad + bc)i | |
public Complex multiply(Complex other) { | |
double newReal = this.real * other.real - this.imaginary * other.imaginary; | |
double newImaginary = this.real * other.imaginary + this.imaginary * other.real; | |
return new Complex(newReal, newImaginary); | |
} | |
} | |
public static void main(String[] args) { | |
launch(args); | |
} | |
} | |
Author
tivrfoa
commented
Jun 15, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment