Files
INF6B/simulations/mandelbrotset/mandelbrotset.py
rattatwinko d0eaabdd87 some new stuff.
idk its all pretty fun! some C++ too!
2025-10-15 11:16:51 +02:00

96 lines
3.4 KiB
Python

import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import threading
import numpy as np
import generate # your mandelbrot_numba / generate_mandelbrot module
class MandelbrotApp:
def __init__(self, root):
self.root = root
self.root.title("Mandelbrot Viewer")
self.frame = ttk.Frame(root)
self.frame.pack(fill=tk.BOTH, expand=True)
self.canvas = tk.Canvas(self.frame, bg="black", scrollregion=(0, 0, 2000, 2000))
self.hbar = ttk.Scrollbar(self.frame, orient=tk.HORIZONTAL, command=self.canvas.xview)
self.vbar = ttk.Scrollbar(self.frame, orient=tk.VERTICAL, command=self.canvas.yview)
self.canvas.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set)
self.hbar.pack(side=tk.BOTTOM, fill=tk.X)
self.vbar.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# Mandelbrot view window
self.xmin, self.xmax = -2.0, 1.0
self.ymin, self.ymax = -1.5, 1.5
self.zoom_factor = 1.0
self.image_on_canvas = None
self.render_image()
# Mouse bindings
self.canvas.bind("<MouseWheel>", self.zoom)
self.canvas.bind("<Button-1>", self.drag_start)
self.canvas.bind("<B1-Motion>", self.drag_motion)
def render_image(self):
width, height = 800, 600
max_iter = 200
def render_task():
# Generate the Mandelbrot array
img_array = generate.generate_mandelbrot(
self.xmin, self.xmax, self.ymin, self.ymax,
width, height, max_iter
)
# Convert NumPy array to RGB image
img_rgb = np.zeros((height, width, 3), dtype=np.uint8)
img_rgb[:, :, 0] = img_array % 256
img_rgb[:, :, 1] = (img_array * 2) % 256
img_rgb[:, :, 2] = (img_array * 3) % 256
# Convert NumPy array → PIL Image → ImageTk.PhotoImage
img = Image.fromarray(img_rgb)
self.tk_img = ImageTk.PhotoImage(img)
# Update canvas
self.canvas.delete("all")
self.image_on_canvas = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.tk_img)
self.canvas.config(scrollregion=(0, 0, width, height))
threading.Thread(target=render_task, daemon=True).start()
def zoom(self, event):
zoom_amount = 0.9 if event.delta > 0 else 1.1
self.zoom_factor *= zoom_amount
center_x = (self.xmin + self.xmax) / 2
center_y = (self.ymin + self.ymax) / 2
width = (self.xmax - self.xmin) * zoom_amount
height = (self.ymax - self.ymin) * zoom_amount
self.xmin, self.xmax = center_x - width / 2, center_x + width / 2
self.ymin, self.ymax = center_y - height / 2, center_y + height / 2
self.render_image()
def drag_start(self, event):
self.last_x, self.last_y = event.x, event.y
def drag_motion(self, event):
dx = event.x - self.last_x
dy = event.y - self.last_y
x_shift = (self.xmax - self.xmin) * dx / 800
y_shift = (self.ymax - self.ymin) * dy / 600
self.xmin -= x_shift
self.xmax -= x_shift
self.ymin += y_shift
self.ymax += y_shift
self.last_x, self.last_y = event.x, event.y
self.render_image()
if __name__ == "__main__":
root = tk.Tk()
app = MandelbrotApp(root)
root.mainloop()