Advertisement
Guest User

Untitled

a guest
May 15th, 2015
372
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.44 KB | None | 0 0
  1. import tkinter as tk
  2. from tkinter import messagebox
  3. from tkinter import ttk
  4. import os, sys, math, time
  5. from PIL import Image, ImageTk
  6.  
  7. PATH = os.getcwd() + "\\"
  8. WIDTH = 400
  9. HEIGHT = 400
  10. DEPTH = 5000
  11. ZOOM_FACTOR = 5
  12. MAX_COLOR = 255
  13. RECURS_LIMIT = 999999
  14. sys.setrecursionlimit(RECURS_LIMIT)
  15. MINUTE = 60
  16.  
  17. RGB_PALETTE = [(128,0,0), (139,0,0), (165,42,42), (178,34,34), (220,20,60),
  18. (255,0,0), (255,99,71), (255,127,80), (205,92,92),
  19. (240,128,128), (233,150,122), (250,128,114), (255,160,122),
  20. (255,69,0), (255,140,0), (255,165,0), (255,215,0),
  21. (184,134,11), (218,165,32), (238,232,170), (189,183,107),
  22. (240,230,140), (128,128,0), (255,255,0), (154,205,50),
  23. (85,107,47), (107,142,35), (124,252,0), (127,255,0),
  24. (173,255,47), (0,100,0), (0,128,0), (34,139,34), (0,255,0),
  25. (50,205,50), (144,238,144), (152,251,152), (143,188,143),
  26. (0,250,154), (0,255,127), (46,139,87), (102,205,170),
  27. (60,179,113), (32,178,170), (47,79,79), (0,128,128),
  28. (0,139,139), (0,255,255), (224,255,255), (0,206,209),
  29. (64,224,208), (72,209,204), (175,238,238), (127,255,212),
  30. (176,224,230), (95,158,160), (70,130,180), (100,149,237),
  31. (0,191,255), (30,144,255), (173,216,230), (135,206,235),
  32. (135,206,250), (25,25,112), (0,0,128), (0,0,139), (0,0,205),
  33. (65,105,225), (138,43,226), (75,0,130), (72,61,139),
  34. (106,90,205), (123,104,238), (147,112,219), (139,0,139),
  35. (148,0,211), (153,50,204), (186,85,211), (128,0,128),
  36. (216,191,216), (221,160,221), (238,130,238), (255,0,255),
  37. (218,112,214), (199,21,133), (219,112,147), (255,20,147),
  38. (255,105,180), (255,182,193), (255,192,203), (250,235,215),
  39. (245,245,220), (255,228,196), (255,235,205), (245,222,179),
  40. (255,248,220), (255,250,205), (250,250,210), (255,255,224),
  41. (139,69,19), (160,82,45), (210,105,30), (205,133,63),
  42. (244,164,96), (222,184,135), (210,180,140), (188,143,143),
  43. (255,228,181), (255,222,173), (255,218,185), (255,228,225),
  44. (255,240,245), (250,240,230), (253,245,230), (255,239,213),
  45. (255,245,238), (245,255,250), (112,128,144), (119,136,153),
  46. (176,196,222), (230,230,250), (255,250,240), (240,248,255),
  47. (248,248,255), (240,255,240), (255,255,240), (240,255,255),
  48. (255,250,250), (0,0,0), (105,105,105), (128,128,128),
  49. (169,169,169), (192,192,192), (211,211,211), (220,220,220),
  50. (245,245,245), (255,255,255)]
  51.  
  52.  
  53. #Class representing complex numbers
  54. class Complex:
  55.  
  56. def __init__(self, real, imag=0.0):
  57. self.real = real
  58. self.imag = imag
  59.  
  60. def __add__(self, other):
  61. return Complex(self.real + other.real,
  62. self.imag + other.imag)
  63.  
  64. def __sub__(self, other):
  65. return Complex(self.real - other.real,
  66. self.imag - other.imag)
  67.  
  68. def __mul__(self, other):
  69. return Complex(self.real*other.real - self.imag*other.imag,
  70. self.imag*other.real + self.real*other.imag)
  71.  
  72. def __abs__(self):
  73. return math.sqrt((self.real * self.real) + (self.imag * self.imag))
  74.  
  75. def __str__(self):
  76. return '(%g, %g)' % (self.real, self.imag)
  77.  
  78. def __repr__(self):
  79. return 'Complex' + str(self)
  80.  
  81. #Class to represent the mandelbrot fractal
  82. class Fractal:
  83.  
  84. #Pre: None Post: Initialization of the class attributes
  85. def __init__(self):
  86.  
  87. self.palette()
  88. self.range = None
  89. self.image = None
  90. self.c = None
  91. self.min_a = None
  92. self.max_a = None
  93. self.min_b = None
  94. self.max_b = None
  95. self.canvas = None
  96. self.iterations = 0
  97. self.center_x, self.center_y = None, None
  98. self.progress_bar = None
  99. self.save = True
  100.  
  101. #This was a quick fix to get the number of colors to be ~255
  102. def palette(self):
  103. for i in range(len(RGB_PALETTE) - 1):
  104. RGB_PALETTE.insert(i + 1, self.linear_interp(RGB_PALETTE[i], RGB_PALETTE[i + 1], i))
  105.  
  106.  
  107. def read_start(self, a_file):
  108. a_list = []
  109. a_file = open(a_file, 'r')
  110. a_list = a_file.readlines()
  111. a_list = a_list[0][:-1]
  112. a_list = a_list.split(' ')
  113. self.range = float(a_list[2])
  114. self.center_x, self.center_y = float(a_list[0]), float(a_list[1])
  115. self.min_a = float(a_list[0]) - (float(a_list[2]) / 2)
  116. self.max_a = float(a_list[0]) + (float(a_list[2]) / 2)
  117. self.min_b = float(a_list[1]) - (float(a_list[2]) / 2)
  118. self.max_b = float(a_list[1]) + (float(a_list[2]) / 2)
  119. a_file.close()
  120.  
  121.  
  122.  
  123. def linear_interp(self, color_1, color_2, i):
  124.  
  125. r = (color_1[0] * (1 - i)) + (color_2[0] * i)
  126. g = (color_1[1] * (1 - i)) + (color_2[1] * i)
  127. b = (color_1[2] * (1 - i)) + (color_2[2] * i)
  128. rgb_list = [r, g, b]
  129. for value in rgb_list:
  130. if value > MAX_COLOR:
  131. rgb_list[rgb_list.index(value)] = MAX_COLOR
  132. if value < 0:
  133. rgb_list[rgb_list.index(value)] = abs(value)
  134.  
  135. return (rgb_list[0], rgb_list[1], rgb_list[2])
  136.  
  137. def rgb_to_hex(self, color):
  138. return "#%02x%02x%02x" % color
  139.  
  140.  
  141. def mandel(self, x, y, z, iteration):
  142.  
  143. mod_z = math.sqrt((z.real * z.real) + (z.imag * z.imag))
  144.  
  145. #If its not in the set or we have reached the maximum depth
  146. if mod_z >= 100.0 or iteration == DEPTH:
  147. if iteration < DEPTH:
  148. if iteration > MAX_COLOR:
  149. iteration = iteration % MAX_COLOR
  150. nu = math.log2(math.log2(abs(mod_z)) / math.log2(2)) / math.log2(2)
  151. value = iteration + 5 - nu
  152. print(iteration)
  153. color_1 = RGB_PALETTE[math.floor(value)]
  154. color_2 = RGB_PALETTE[math.floor(value) + 1]
  155. fractional_iteration = value % 1
  156.  
  157. color = self.linear_interp(color_1, color_2, fractional_iteration)
  158.  
  159. self.canvas.create_line(x, y, x + 1, y + 1,
  160. fill = self.rgb_to_hex(color))
  161.  
  162. else:
  163.  
  164. z = (z * z) + self.c
  165. self.mandel(x, y, z, iteration + 1)
  166.  
  167. return z
  168.  
  169. def create_image(self):
  170. begin = time.time() #For computing how long it took (start time)
  171. diam_a = self.max_a - self.min_a
  172. diam_b = self.max_b - self.min_b
  173. for y in range(HEIGHT):
  174. for x in range(WIDTH):
  175. self.c = complex(x * (diam_a / WIDTH) + self.min_a,
  176. y * (diam_b / HEIGHT) + self.min_b)
  177.  
  178. constant = 1.0
  179. z = self.c
  180.  
  181. bound = 1 / 4
  182. q = (self.c.real - bound)**2 + (self.c.imag * self.c.imag)
  183. x1 = self.c.real
  184. y2 = self.c.imag * self.c.imag
  185. sixteenth = 1 / 16
  186.  
  187. if not (q*(q + (x1 - bound)) < y2 / (constant * 4) or
  188. (x1 + constant)**2 + y2 < sixteenth):
  189.  
  190. #value of the recursive call while it is not in the set
  191. z = self.mandel(x, y, z, iteration = 0)
  192.  
  193. if self.progress_bar != None:
  194. self.progress_bar["value"] = y
  195.  
  196. self.canvas.update()#Update the progress bar
  197. print("Took %s Minutes to Render" % ((time.time() - begin) / MINUTE))
  198.  
  199. def create_canvas(self):
  200. self.canvas = tk.Canvas(root, width = WIDTH, height = HEIGHT)
  201. self.make_menu()
  202. self.progress_bar = ttk.Progressbar(orient = "horizontal",
  203. length = WIDTH,
  204. mode = "determinate",
  205. maximum = HEIGHT,
  206. value = 0)
  207. self.progress_bar.pack(side = "bottom")
  208. self.canvas.pack()
  209.  
  210. def zoom_in(self, event):
  211. self.canvas.delete(tk.ALL)
  212. messagebox.showinfo("Zooming in the Mandelbrot",
  213. "Please wait until the next image loads")
  214. self.range = float(self.range / ZOOM_FACTOR)
  215. self.center_x = float((self.canvas.canvasx(event.x) /
  216. float(WIDTH)) *
  217. (self.max_a - self.min_a) + self.min_a)
  218. self.center_y = float((self.canvas.canvasy(event.y) /
  219. float(HEIGHT)) *
  220. (self.max_b - self.min_b) + self.min_b)
  221. #Compute new boundaries
  222. self.min_a = self.center_x - (self.range)
  223. self.max_a = self.center_x + (self.range)
  224. self.min_b = self.center_y - (self.range)
  225. self.max_b = self.center_y + (self.range)
  226. self.create_image() #Redraw the image
  227.  
  228. def zoom_out(self, event):
  229. self.canvas.delete(tk.ALL)
  230. messagebox.showinfo("Zooming in the Mandelbrot",
  231. "Please wait until the next image loads")
  232. self.range = float(self.range * ZOOM_FACTOR)
  233. self.center_x = float((self.canvas.canvasx(event.x) /
  234. float(WIDTH)) *
  235. (self.max_a - self.min_a) + self.min_a)
  236. self.center_y = float((self.canvas.canvasy(event.y) /
  237. float(HEIGHT)) *
  238. (self.max_b - self.min_b) + self.min_b)
  239. #Compute new boundaries
  240. self.min_a = self.center_x - (self.range)
  241. self.max_a = self.center_x + (self.range)
  242. self.min_b = self.center_y - (self.range)
  243. self.max_b = self.center_y + (self.range)
  244. self.create_image() #Redraw the image
  245.  
  246.  
  247. root = tk.Tk()
  248. root.title("Mandelbrot Viewer")
  249.  
  250. if __name__ == '__main__':
  251. fractal = Fractal()
  252.  
  253. if fractal.range == None:
  254. fractal.read_start("zoom_location.txt")
  255. fractal.create_canvas()
  256. fractal.create_image()
  257. root.bind("<Double-Button-1>", fractal.zoom_in)
  258. root.bind("<Double-Button-3>", fractal.zoom_out)
  259. root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement