簡單的D0L-系統生成分形

簡單的D0L-系統

描述

考慮由a、b組成的字符串,每一個字母代表一個改寫規則,例如,規定a->ab,b->a,分別表示a可被改寫爲ab,b被改寫爲a。改寫過程從一個被稱爲 公理 的字符串開始。

例如:

公理omega:b

改寫規則:a->ab; b->a

第1次改寫:a

第2次改寫:ab

第3次改寫:aba

第4次改寫:abaab

......

這就是簡單的D0L-系統

字符串的海龜解釋

假設有一隻海龜在行動,我們假定海龜遇到字符 f 則向前走一個步長,遇到字符 + 就向左轉彎一定角度,遇到字符 - 就向右轉彎一定角度。具體走動情況就不顯示了,我們直接進入主題就行。

Python自帶海龜(turtle)模塊,但是效率不夠,因此我們改寫pygame模塊以適應我們的需求

"""
    簡單D0L系統
"""
from math import sin, cos, pi
import pygame


def left(screen, st, angle, d):
    # st: 起點座標
    # angle: 向左偏轉的度數
    # d: 距離
    angle = pi * angle / 180
    return [st[0] + d * cos(angle), st[1] - d * sin(angle)]


class Pen:

    def __init__(self, size, title=""):
        # size 畫布的寬高 [width, hight]
        # title 畫布標題
        pygame.init()
        self.screen = pygame.display.set_mode(size)
        pygame.display.set_caption(title)
        self.screen.fill([255, 255, 255])
        self.setPoint([size[0]/2, size[1]/2])
        pygame.display.flip()
        self.pos = [0, 0]  # 當前頭的位置
        self.angle = 0  # 當前角度
        self.color = [0, 0, 0]  # 畫筆顏色
        self.width = 2

    def setPoint(self, pos):
        # 設置筆的位置
        self.pos = pos

    def setWidth(self, width):
        # 設置線寬
        self.width = width

    def setColor(self, color):
        # 設置顏色
        self.color = color

    def left(self, angle):
        # 向左轉angle度
        self.angle = self.angle + angle

    def right(self, angle):
        # 向右轉angle度
        self.angle = self.angle - angle

    def forward(self, d):
        # 向前走d步長
        np = left(self.screen, self.pos, self.angle, d)
        pygame.draw.line(self.screen, self.color, self.pos, np, self.width)
        pygame.display.flip()
        self.pos = np

    def doD0L(self, omega, P, delta, times, length, rate, delta0 = 0):
        # omega: 公理(初始字符串)
        # P: 產生式(映射規則)
        # delta0: 初始偏移量
        # delta: 角度增量
        # times: 迭代次數
        # length: 初始線長
        # rate: 每次迭代後縮小的倍數

        length /= (rate**times)
        for i in range(times):
            for key in P:
                omega = omega.replace(key, P[key])
        self.left(delta0)
        for j in omega:
            if j == '+':
                self.left(delta)
            elif j == '-':
                self.right(delta)
            else:
                self.forward(length)

    def save(self, title):
        # 保存圖片,title爲文件名
        pygame.image.save(self.screen, title)

    def wait(self):
        # 繪製結束等用戶關閉程序
        while 1:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    exit()

由於我已經將其放到pypi上,因此,如果安裝的話只需要執行:

pip install fractal

就可以了。

1.Koch曲線

**omega: ** f

P: f-->f+f--f+f

說明: 初始角度 0, 角度增量 60 度, 步長d(本次取步長爲490px)在相鄰兩次迭代間縮短了3倍,這裏我們顯示迭代4次後的圖像

代碼:

# 科赫曲線
from fractal import Pen

p = Pen([500, 300], title="Koch")
p.setPoint([5, 190])
p.doD0L(omega="f", P={"f": "f+f--f+f"}, delta=60, times=4, length=490, rate=3)
p.wait()

結果:

2.Koch 雪花

omega: f--f--f

P: f-->f+f--f+f

說明: 初始角度:0、角度增量:60°、每一次迭代步長縮小3倍

代碼:

# 科赫雪花
from fractal import Pen

p = Pen([500,500],title = "Koch Snow")

p.setPoint([30,130])

p.doD0L(omega = "f--f--f", P = {"f": "f+f--f+f"}, delta = 60, times = 5, length = 400, rate = 3)

p.wait()

結果:

3.Sierpinski 三角

omega: f--f--f

P: g-->gg; f-->f--f--f--gg

說明: 初始角度0,角度增量60°,每次迭代三角形邊長就縮短兩倍,g的含義與f一樣

代碼:

# 謝爾賓斯基三角

from fractal import Pen

p = Pen([500, 460], title="Sierpinski")
p.setPoint([5, 5])
p.doD0L(omega="f--f--f", P={"g": "gg", "f": "f--f--f--gg"},
        delta=60, times=5, length=490, rate=2)
p.wait()

結果:

4.二次 Koch 島

**omega: ** f-f-f-f

**P: ** f-->f+f-f-ff+f+f-f

說明: 初始角度0,角度增量90°,兩次迭代間縮小4倍

代碼:

# 二次Koch島
from fractal import Pen

p = Pen([500, 500], title="Koch island")
p.setPoint([100, 100])
p.doD0L(omega="f-f-f-f", P={"f": "f+f-f-ff+f+f-f"},
        delta=90, times=4, length=300, rate=4)
p.wait()

結果:

5.窗花

omega: f+f+f+f

P: f-->ff+f--f+f

說明: 初始角度90°,角度增量90°,縮小率3

代碼:

# 窗花
from fractal import Pen

p = Pen([500, 500], title="Window")
p.setPoint([495, 495])
p.doD0L(omega="f+f+f+f", P={"f": "ff+f--f+f"},
        delta=90, times=5, length=490, rate=3, delta0 = 90)
p.wait()

結果:

當然了,還有很多有趣的圖案,按簡單D0L-系統都是可以生成的,目前 fractal 模塊還很不成熟,日後會慢慢改進,有興趣的小夥伴歡迎加入一起做,項目地址:fractal

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章