猫史档案馆


【Python作品分享】Newton's Fractal_牛顿分形【作品秀】

用户:小小小嘟嘟小小小嘟嘟查看:1 回复:2 评论:1 创建时间:2022-08-01T12:42:25


【作品展示】

center_image

 

【作品介绍】

【作品说明】:

此程序可以模拟牛顿分形。

收敛的点用对应颜色着色(红绿蓝),不收敛的根用灰色着色。

牛顿分形的原理的视频链接附在代码末尾的注释。

【使用方法】:

①鼠标移到一个根并按下鼠标左键拖动,可拖动根,拖动时自动降低分辨率保证流畅,放开鼠标以高分辨率刷新

②点击上下调节迭代次数,点击左右调节放大倍数,点击f将中心移动到鼠标所在位置,点击h调整回初始视角,点击空格(回车)以低(高)分辨率刷新。

请在海龟编辑器上运行此程序,在库管理安装需要安装的库。

(由于gif是在笔记本电脑上录制的,所以很卡)

 

【作品源代码】

import numpy as np
import pygame, sys


print()
Iter = 20  # iterations
roots = np.array([1.0+0.0j, -0.5+0.8660254037844386j, -0.5-0.8660254037844386j], dtype=complex)

def f(x):
    a, b, c = x-roots[0], x-roots[1], x-roots[2]
    return x-a*b*c/(a*b+b*c+c*a)

def get_z(x):
    for i in range(Iter):
        x = f(x)
    return x

def get_index():
    x0 = np.resize(np.linspace(-focus, focus, pl), (pl, pl))
    x0 = x0+x0.transpose()*1j+middle  # initial values
    z = get_z(x0)  # calculate limities

    # calculate colors
    zc = np.zeros(shape=(pl, pl, 3), dtype='u1')
    npsum = np.sum
    for i in range(pl):
        for j in range(pl):
            w = 1/(abs(roots-z[i][j])+0.000001)
            zc[i][j] = 256*w/npsum(w)-1
    return zc

pygame.init()

rslt = 200  # resolution
middle = 0.0+0.0j
focus = 2
pl = 2*rslt+1  # real and imaginary part len
size = 200
d = size/rslt
screen = pygame.display.set_mode((2*size, 2*size))

def render(zc):
    for j in range(pl):
        for i in range(pl):
            pygame.draw.rect(screen, zc[i][j], (j*d, 2*size-i*d, d, d), 0)
    pygame.display.update()

button_size = 7
def draw_button(touched_index=-1):
    i = 0
    for pos in (roots_cpos-size/focus*middle.conjugate()):
        pygame.draw.circle(screen, (255, 255, 255), (pos.real, pos.imag), button_size, 2)
        i += 1
    pygame.display.update()
    print('roots = {}, focus = {}, middle = {}'.format(roots, focus, middle)+' '*15, end='\r')

def roots_trans(cpos):
    trans1 = cpos/size
    return focus*((trans1.real-1)+(-trans1.imag+1)*1j)

def roots_invtrans(cpos):
    trans1 = cpos/focus
    return size*(((1+trans1.real)+(1-trans1.imag)*1j))


roots_cpos = roots_invtrans(roots)

def check_pos(cpos):
    is_touch_buttons = (abs(roots_cpos-size/focus*middle.conjugate()-cpos) <= 2*button_size)
    for i in range(3):
        if is_touch_buttons[i]:
            return i
    return -1

def set_rslt(val):
    global rslt, pl, d
    rslt = val
    pl = 2*rslt+1
    d = size/rslt

render(get_index())
draw_button()

down = 0
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN:
                set_rslt(200)
                render(get_index())
                draw_button()
            elif event.key == pygame.K_UP:
                if Iter <= 50:
                    Iter += 1
            elif event.key == pygame.K_DOWN:
                if Iter > 0:
                    Iter -= 1
            elif event.key == pygame.K_LEFT:
                focus *= np.sqrt(2)
                roots_cpos = roots_invtrans(roots)
            elif event.key == pygame.K_RIGHT:
                focus /= np.sqrt(2)
                roots_cpos = roots_invtrans(roots)
            elif event.key == pygame.K_f:
                middle += (cpos.conjugate()/size-1+1j)*focus
                middle = np.around(middle.real, 9)+np.around(middle.imag, 9)*1j
            elif event.key == pygame.K_h:
                focus, middle = 2, 0.0+0.0j
                roots_cpos = roots_invtrans(roots)
            elif event.key == pygame.K_RETURN:
                set_rslt(200)
                render(get_index())
                draw_button()
            elif event.key == pygame.K_SPACE:
                set_rslt(50)
                render(get_index())
                draw_button()
        elif event.type == pygame.MOUSEBUTTONUP:
            down = 0
            set_rslt(200)
            render(get_index())
            draw_button()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            down = 1
            set_rslt(50)
            break
    x, y = pygame.mouse.get_pos()
    cpos = complex(x, y)
    if down == 0:
        index = check_pos(cpos)
    else:
        if index != -1:
            roots_cpos[index] = cpos
            roots[index] = roots_trans(cpos)

            render(get_index())
            draw_button()

# 相关视频 https://www.bilibili.com/video/BV1HQ4y1q78v?spm_id_from=333.337.search-card.all.click
# 类似程喵lessons/newtons-fractal

 

【提示】

部分含有Python第三方库相关内容的作品,在海龟编辑器网页端无法运行哦!如遇到这种情况,可以打开下面的链接,下载海龟编辑器客户端:

https://python.codemao.cn


回复

上一页1 页 / 共 1下一页
小小小嘟嘟小小小嘟嘟

不知为什么代码末尾的类似程序为喵喵喵…… 这里附上喵lessons/newtons-fractal

点赞1


评论


小小小嘟嘟小小小嘟嘟

终于摸索出怎么发这个网址了:(请自行把h后面的0删掉,就是网址了!)h0ttps://www.3blue1brown.com/lessons/newtons-fractal

点赞1


评论