这是我尝试使用Pygame模块在Python 3.5中编写Mandelbrot集。
import math, pygame
pygame.init()
def mapMandelbrot(c,r,dim,xRange,yRange):
x = (dim-c)/dim
y = (dim-r)/dim
#print([x,y])
x = x*(xRange[1]-xRange[0])
y = y*(yRange[1]-yRange[0])
x = xRange[0] + x
y = yRange[0] + y
return [x,y]
def checkDrawBox(surface):
for i in pygame.event.get():
if i.type == pygame.QUIT:
pygame.quit()
elif i.type == pygame.MOUSEBUTTONDOWN:
startXY = pygame.mouse.get_pos()
boxExit = False
while boxExit == False:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP:
boxExit = True
if boxExit == True:
return [startXY,pygame.mouse.get_pos()]
pygame.draw.rect(surface,[255,0,0],[startXY,[pygame.mouse.get_pos()[0]-startXY[0],pygame.mouse.get_pos()[1]-startXY[1]]],1)
pygame.display.update()
def setup():
dimensions = 500
white = [255,255,255]
black = [0,0,0]
checkIterations = 100
canvas = pygame.display.set_mode([dimensions,dimensions])
canvas.fill(black)
xRange = [-2,2]
yRange = [-2,2]
xRangePrev = [0,0]
yRangePrev = [0,0]
newxRange = [0,0]
newyRange = [0,0]
while True:
if not ([xRange,yRange] == [xRangePrev,yRangePrev]):
draw(dimensions, canvas, xRange, yRange, checkIterations)
pygame.display.update()
xRangePrev = xRange
yRangePrev = yRange
box = checkDrawBox(canvas)
if box != None:
maxX = max([box[0][0],box[1][0]])
maxY = max([box[0][1],box[1][1]])
newxRange[0] = mapMandelbrot(box[0][0],0,dimensions,xRange,yRange)[0]
newxRange[1] = mapMandelbrot(box[1][0],0,dimensions,xRange,yRange)[0]
newyRange[0] = mapMandelbrot(0,box[0][1],dimensions,xRange,yRange)[1]
newyRange[1] = mapMandelbrot(0,box[1][1],dimensions,xRange,yRange)[1]
xRange = newxRange
yRange = newyRange
def draw(dim, surface, xRange, yRange, checkIterations):
for column in range(dim):
for row in range(dim):
greyVal = iteration(0,0,mapMandelbrot(column,row,dim,xRange,yRange),checkIterations,checkIterations)
surface.set_at([dim-column,row],greyVal)
def iteration(a, b, c, iterCount, maxIter):
a = (a*a) - (b*b) + c[0]
b = (2*a*b) + c[1]
iterCount = iterCount - 1
if iterCount == 0:
return [0,0,0]
elif abs(a+b) > 17:
b = (iterCount/maxIter)*255
return [b,b,b]
else:
return iteration(a,b,c,iterCount,maxIter)
setup()
我相信迭代算法是正确的,但输出看起来不正确:
想知道可能是什么问题?很抱歉代码转储,只是不确定哪个部分可能会使它看起来像那样。
答案 0 :(得分:10)
引人入胜的bug - 它看起来像一个被压扁的bug:)
问题在于两行:
a = (a*a) - (b*b) + c[0]
b = (2*a*b) + c[1]
您正在更改第一行中a
的含义,因此在第二行中使用了错误的a
。
修复很简单:
a, b = (a*a) - (b*b) + c[0], (2*a*b) + c[1]
将导致a
的相同值用于计算右侧。
确定你的bug产生的内容会很有趣。即使它不是Mandelbrot集合,它本身似乎也是一个有趣的分形。从这个意义上说,你有一个非常幸运的错误。百分之九十九的时间,虫子会导致垃圾,但偶尔会产生一些非常有趣的东西,但这些都是无意识的。
点击编辑:
Mandelbrot集基于迭代复数多项式:
f(z) = z^2 + c
此错误产生的伪Mandelbrot集基于迭代函数
f(z) = Re(z^2 + c) + i*[2*Re(z^2 + c)*Im(z) + Im(c)]
其中Re()
和Im()
是提取复数的实部和虚部的运算符。这不是z
中的多项式,但很容易看出它是z,z*
中的多项式(其中z*
是z
的复共轭)。由于这是一个相当自然的错误,几乎可以肯定这已经出现在Mandelbrot集的文献中,尽管我不记得曾经看过它。
答案 1 :(得分:0)
我决定了解mandelbrot集并编写我自己的版本!我使用了python的complex
数据类型,它应该使每个像素的mandelbrot计算更清晰一些。以下是结果的屏幕截图:
这是源代码/代码转储:
import pygame
import sys
def calc_complex_coord(x, y):
real = min_corner.real + x * (max_corner.real - min_corner.real) / (width - 1.0)
imag = min_corner.imag + y * (max_corner.imag - min_corner.imag) / (height - 1.0)
return complex(real, imag)
def calc_mandelbrot(c):
z = c
for i in range(1, max_iterations+1):
if abs(z) > 2:
return i
z = z*z + c
return i
def calc_color_score(i):
if i == max_iterations:
return black
frac = 255.0 - (255.0 * i / max_iterations)
return (frac, frac, frac)
def update_mandelbrot():
for y in range(height):
for x in range(width):
c = calc_complex_coord(x, y)
mandel_score = calc_mandelbrot(c)
color = calc_color_score(mandel_score)
mandel_surface.set_at((x, y), color)
if __name__ == "__main__":
pygame.init()
(width, height) = (500, 500)
display = pygame.display.set_mode((width, height))
pygame.display.set_caption("Mandelbrot Magic")
clock = pygame.time.Clock()
mandel_surface = pygame.Surface((width, height))
black = (0, 0, 0)
red = (255, 0, 0)
max_iterations = 50
min_corner = complex(-2, -2)
max_corner = complex(2, 2)
box = pygame.Rect(0, 0, width, height)
update_mandel = True
draw_box = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
box = pygame.Rect(x, y, 0, 0)
draw_box = True
elif event.type == pygame.MOUSEMOTION:
x, y = event.pos
if draw_box:
box = pygame.Rect(box.left, box.top, x - box.left, y - box.top)
elif event.type == pygame.MOUSEBUTTONUP:
x, y = event.pos
update_mandel = True
display.blit(mandel_surface, (0, 0))
if draw_box:
pygame.draw.rect(display, red, box, 1)
if update_mandel:
box.normalize()
new_min_corner = calc_complex_coord(box.left, box.top)
new_max_corner = calc_complex_coord(box.right, box.bottom)
min_corner, max_corner = new_min_corner, new_max_corner
update_mandelbrot()
update_mandel = False
draw_box = False
pygame.display.update()
clock.tick(60)
这个代码的两个问题是,一个,更新mandelbrot集很慢,两个,如果使用非方形窗口或框选择,宽高比会变形。如果有任何代码不清楚,请告诉我!