#!/usr/pkg/bin/python """simple program to display Mandelbrot set this variation uses reals instead of complex numbers""" Copyright = """ mandelbrot -- display image of Mandelbrot set Copyright (C) 2005 John Comeau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. """ errormessage = "Not all needed libraries found, upgrade or check path: " try: True # not defined in older Python releases except: True, False = 1, 0 try: import sys, os, types, re, pwd sys.path.append(os.path.join(pwd.getpwuid(os.geteuid())[5], 'lib', 'python')) errormessage = errormessage + repr(sys.path) from com.jcomeau import gpl, jclicense except: try: sys.stderr.write("%s\n" % errormessage) except: print errormessage raise # get name this program was called as myself = os.path.split(sys.argv[0])[1] command = os.path.splitext(myself)[0] # chop any suffix (extension) # now get name we gave it when we wrote it originalself = re.compile('[0-9A-Za-z]+').search(Copyright).group() # globals and routines that should be in every program # (yes, you could import them, but there are problems in that approach too) def DebugPrint(*whatever): return False # defined instead by pytest module, use that for debugging def join(*args): "for pythons without str.join" string, array = args if type(array) == types.StringType: array = eval(array) if hasattr(str, 'join'): return string.join(array) else: joined = '' for index in range(0, len(array)): joined = joined + array[index] if index != (len(array) - 1): joined = joined + string return joined def split(*args): "for pythons without str.split" string, string_to_split = args if not len(string): string = None if hasattr('str', 'split'): return string_to_split.split(string) else: return re.compile(re.escape(string)).split(string_to_split) # other globals, specific to this program import Tkinter from Tkconstants import * # start values chosen to match 4:3 aspect ratio (800x600, 1024*768) start = {'left': -2.1, 'right': 1.1, 'top': 1.2, 'bottom': -1.2} width = 320 height = 240 current = dict(start) color = '#%02x%02x%02x' # pattern for setting color iterations = [0] * (width * height) maxiterations = (1 << 8) - 1 # 8-bit color values according to iteration # if you make maxvalue 2, and only check z.real for it, you'll see what # resemble magnetic lines of force around the Mandelbrot "lake". maxvalue = 4 # x^2 + y^2 constants, values = list(iterations), list(iterations) pixels = list(iterations) def mandelbrot(*args): """main routine draws outline of Mandelbrot set, eventually to allow zoom each pixel is z -> z^2 + z0 """ DebugPrint('myself, command, originalself', myself, command, originalself) initconstants() tk = Tkinter.Tk() frame = Mandelbrot() frame.pack() frame.mainloop() class Mandelbrot(Tkinter.Frame): def __init__(self): Tkinter.Frame.__init__(self) self.canvas = Tkinter.Canvas(self, width=width, height=height) self.canvas.pack() self.buttonbar = Tkinter.Frame(self) Tkinter.Button(self.buttonbar, text = 'Go', command = self.generate).pack(side=LEFT) Tkinter.Button(self.buttonbar, text = 'Quit', command = self.stop).pack(side=LEFT) self.buttonbar.pack() stop_requested = False def generate(self, *args): self.canvas.config(cursor = 'wait') # mark window "busy" for y in range(height): if self.stop_requested: return for x in range(width): index = (y * width) + x i = maxiterations - iterations[index] pixels[index] = self.canvas.create_line(x, y, x + 1, y, {'fill': color % (i, i, i)}) for n in range(maxiterations): if self.stop_requested: return DebugPrint('starting iteration', n + 1) self.iterate() self.update() #DebugPrint('iterations', iterations) self.canvas.config(cursor = '') def iterate(self, *args): # updates globals 'values' and 'pixels' for index in range(len(values)): z = values[index] if z != [2, 2]: values[index] = complex_add(complex_multiply(z, z), constants[index]) try: if ((values[index][0] ** 2) + (values[index][1] ** 2)) < maxvalue: iterations[index] += 1 i = maxiterations - iterations[index] self.canvas.itemconfigure(pixels[index], {'fill': color % (i, i, i)}) except: values[index] = [2, 2] def stop(self): self.stop_requested = True self.quit() def complex_multiply(i, j): [a, b], [c, d] = i, j return [(a * c) - (b * d), (b * c) + (a * d)] def complex_add(i, j): [a, b], [c, d] = i, j return [a + c, b + d] def heightvalue(*args): heightspan = current['top'] - current['bottom'] pixelheight = args[0] return current['top'] - ((heightspan * pixelheight) / height) def widthvalue(*args): widthspan = current['right'] - current['left'] pixelwidth = args[0] return current['left'] + ((widthspan * pixelwidth) / width) def initconstants(*args): global constants, values for n in range(len(constants)): x, y = n % width, int(n / width) constants[n] = [widthvalue(x), heightvalue(y)] values = list(constants) DebugPrint('constants initialized', constants[0:10], '...', constants[-10:]) if __name__ == '__main__': # if this program was imported by another, the above test will fail, # and this following code won't be used... function = command; args = sys.argv[1:] # default case if command == originalself: try: if len(args) and eval('type(%s) == types.FunctionType' % args[0]): function = sys.argv[1]; args = sys.argv[2:] except: pass print eval('%s%s' % (function, repr(tuple(args)))) or '' else: # if you want something to be done on import, do it here; otherwise pass pass