96 lines
3.4 KiB
Python
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()
|