some new stuff.
idk its all pretty fun! some C++ too!
This commit is contained in:
95
simulations/mandelbrotset/mandelbrotset.py
Normal file
95
simulations/mandelbrotset/mandelbrotset.py
Normal file
@@ -0,0 +1,95 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user