Created
July 22, 2015 20:37
-
-
Save ethan2-0/d4850b1c37e7cda55d93 to your computer and use it in GitHub Desktop.
Mandelbrot/Julia set in Processing/Python.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# IF YOU WANT A JULIA SET, SET isMandelbrot TO False. | |
# Copyright (c) 2015 Ethan White. Licensed under 3-clause BSD. | |
# Requires the Python mode for Processing. | |
import time | |
import math | |
# Fudge factors | |
startSize = (1000, 1000) | |
widthMultFudge = float(4) | |
heightMultFudge = float(4) | |
widthAddFudge = 10 | |
scaleAddFudge = complex(2, 2) | |
escapeFudge = 2.0 # The maximum possible absolute value that a point can reach before it is assumed to be growing indefinitely; anything >= 2 works. Trying < 2 is fun, though. | |
minTimePerIteration = 0 # The minimum time, in seconds, between iterations. Zero disables this feature. | |
isMandelbrot = True # If set to true, `iterator` is ignored and is assumed to be precisely pt.complex**2 + pt.initialComplex; to remove the overhead of function calls. | |
iterator = lambda pt: pt.complex**5 + 0.544 # The function that is iterated on each point. A Point object is passed in. The one it starts out with is a Julia set. | |
# If isMandelbrot is true, this is ignored, and a Mandelbrot set is drawn instead, although one could draw a Mandelbrot set with iterator, | |
# too; it's just an optimization to avoid the overhead of function calls. | |
# 0.544 is not in the Mandelbrot set. | |
# Here are some other possible Julia sets that are interesting: | |
# Consider: the Julia set for x^n + c consists of one island if and only if c is in the mandelbrot set | |
# Here's a function to test if something is in the mandelbrot set: | |
# def mand(n): | |
# origN = n | |
# for i in xrange(10000): | |
# n = n**2 + origN | |
# if n.real**2 + n.imag**2 > 4: | |
# return "Eliminated on iter %s" % str(i) | |
# return "In mandelbrot" | |
# iterator = lambda pt: pt.complex**7 + 0.626 # c _not_ in mandelbrot | |
# iterator = lambda pt: pt.complex**4 + 0.484 # c _not_ in mandelbrot | |
# iterator = lambda pt: math.e**(pt.complex**3) - 0.621 # c in mandelbrot | |
# iterator = lambda pt: pt.complex**3 * math.e**(pt.complex) + 0.33333 # c _not_ in mandelbrot | |
# iterator = lambda pt: pt.complex**3 + 0.85 # c _not_ in mandelbrot | |
# iterator = lambda pt: pt.complex**2 + 0.25 # c in mandelbrot | |
# iterator = lambda pt: pt.complex**2 + 0.75 # c _not_ in mandelbrot | |
# iterator = lambda pt: pt.complex**2 + complex(0.123, 0.745) # c _not_ in mandelbrot | |
# iterator = lambda pt: pt.complex**3 + complex(0.123, 0.628) # c in mandelbrot | |
# iterator = lambda pt: pt.complex**2 + 1 # c _not_ in mandelbrot | |
# iterator = lambda pt: pt.complex**2 - 1 # c in mandelbrot | |
def complexToPoint(c): | |
c += scaleAddFudge | |
return (c.imag * float(width + widthAddFudge) / widthMultFudge, c.real * float(height) / heightMultFudge) | |
def pointToComplex(pt): | |
x, y = pt | |
return complex(float(x) * widthMultFudge / (width + widthAddFudge), float(y) * heightMultFudge / height) - scaleAddFudge | |
class Point: | |
def __init__(self, pt): | |
self.complex = pointToComplex(pt) | |
self.initialComplex = self.complex | |
self.pt = pt | |
self.x, self.y = pt | |
self.dead = False | |
def iterate(self): | |
global escapeFudge | |
if isMandelbrot: | |
self.complex = self.complex**2 + self.initialComplex | |
else: | |
self.complex = iterator(self) | |
ret = self.complex.imag**2 + self.complex.real**2 <= escapeFudge**2 | |
if not ret: | |
self.dead = True | |
return ret | |
def drawIfDead(self): | |
if not self.iterate(): | |
point(self.x, self.y) | |
return False | |
return True | |
points = [] | |
def setup(): | |
startW, startH = startSize | |
size(startW, startH) | |
fill(0, 0, 0) | |
stroke(0, 0, 0) | |
clear() | |
for x in xrange(width): | |
for y in xrange(height): | |
points.append(Point((x, y))) | |
iterationNum = 0 | |
# Here are some possible color schemes: | |
# (Color schemes are arrays of tuples of the form (r, g, b)). | |
# colors = [(0xff, 0xff, 0xff), (0xdd, 0xdd, 0xdd), (0xbb, 0xbb, 0xbb), (0x99, 0x99, 0x99)] # Completely desaturated color scheme | |
# colors = [(0xd1, 0xc4, 0xe9), (0x95, 0x75, 0xcd), (0x67, 0x3a, 0xb7), (0x51, 0x2d, 0xa8), (0x31, 0x1b, 0x92)] # 100, 300, 500, 700, and 900 variants of Deep Purple from Material Design | |
# colors = [(0x95, 0x75, 0xcd), (0x67, 0x3a, 0xb7), (0x51, 0x2d, 0xa8), (0x31, 0x1b, 0x92)] # Same as above, minus the 100 variant | |
# colors = [(0xff, 0xcc, 0xbc), (0xff, 0x8a, 0x65), (0xff, 0x57, 0x22), (0xe6, 0x4a, 0x19), (0xbf, 0x36, 0x0c)] # 100, 300, 500, 700, 900 of Deep Orange | |
colors = [(0xff, 0x8a, 0x65), (0xff, 0x57, 0x22), (0xe6, 0x4a, 0x19), (0xbf, 0x36, 0x0c)] # 300, 500, 700, 900 of Deep Orange | |
# colors = [(0xb2, 0xdf, 0xdb), (0x4d, 0xb6, 0xac), (0x00, 0x96, 0x88), (0x00, 0x79, 0x6b), (0x00, 0x4d, 0x40)] # 100, 300, 500, 700, 900 of Teal | |
# colors = [(0x4d, 0xb6, 0xac), (0x00, 0x96, 0x88), (0x00, 0x79, 0x6b), (0x00, 0x4d, 0x40)] # 300, 500, 700, 900 of Teal | |
# colors = [(0xff, 0xe0, 0xb2), (0xff, 0xb7, 0x4d), (0xff, 0x98, 0x00), (0xf5, 0x7c, 0x00), (0xe6, 0x51, 0x00)] # 100, 300, 500, 700, 900 of Orange | |
# colors = [(0xff, 0xb7, 0x4d), (0xff, 0x98, 0x00), (0xf5, 0x7c, 0x00), (0xe6, 0x51, 0x00)] # 300, 500, 700, 900 of Orange | |
# colors = [(0xbb, 0xde, 0xfb), (0x64, 0xb5, 0xf6), (0x21, 0x96, 0xf3), (0x19, 0x76, 0xd2), (0x0d, 0x47, 0xa1)] # 100, 300, 500, 700, 900 of Blue | |
# colors = [(0x64, 0xb5, 0xf6), (0x21, 0x96, 0xf3), (0x19, 0x76, 0xd2), (0x0d, 0x47, 0xa1)] # 300, 500, 700, 900 of Blue | |
# For minTimePerIteration | |
lastTimeDrawn = 0 | |
# Last time something was eliminated | |
lastTimeEliminated = 0 | |
def draw(): | |
global iterationNum | |
global points | |
global escapeFudge | |
global lastTimeDrawn | |
global lastTimeEliminated | |
if time.time() - lastTimeDrawn < minTimePerIteration: | |
time.sleep(minTimePerIteration - (time.time() - lastTimeDrawn)) | |
lastTimeDrawn = time.time() | |
iterationNum += 1 | |
numDeleted = 0 | |
r, g, b = colors[iterationNum % len(colors)] | |
fill(r, g, b) | |
stroke(r, g, b) | |
for pt in points: | |
if not pt.dead: | |
if not pt.drawIfDead(): | |
numDeleted += 1 | |
lastTimeEliminated = iterationNum | |
print "Eliminated %s on the iteration %s" % (numDeleted, iterationNum) | |
# Draw the informational overlay | |
text("ABC", 0, 0) | |
if iterationNum - lastTimeEliminated > 30: | |
frameRate(0) # Stop rendering |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment