关于分形的简单研究

初次接触分形是由于动漫《分形世界》,当时就觉得好高大上,然后就想知道这到底是是怎么回事。于是就在网上找了一些资料,简单地研究了一下。

递归画法

最简单的分形图形应该是Koch曲线了吧,曲线的绘制我是参考大佬的博客的 

https://blog.csdn.net/ryan_jianjian/article/details/53678062

我们来看一下绘制的过程

这是用递归实现的,下面来看代码。

import turtle
import math

#初始化画布
def init():
    turtle.screensize(800, 600, "white")
    turtle.pensize(2)
    turtle.pencolor("orange")
    turtle.speed(1)

#画连接两点的直线
def draw(x1, y1, x2, y2):
    turtle.penup()          #提起笔
    turtle.setposition(x1, y1)
    turtle.pendown()        #放下笔
    turtle.goto(x2, y2)

#画koch曲线程序,递归方法
def koch(x0, y0, x1, y1, k):
    #算法这里就不赘述了
    x2 = x0*2.0/3 + x1*1.0/3
    y2 = y0*2.0/3 + y1*1.0/3
    x3 = x0*1.0/3 + x1*2.0/3
    y3 = y0*1.0/3 + y1*2.0/3
    x4 = x2 + ((x1-x0) - (y1-y0)*math.sqrt(3))/6
    y4 = y2 + ((x1-x0)*math.sqrt(3) + (y1-y0))/6
    if(k > 1):  #递归
        koch(x0, y0, x2, y2, k-1)
        koch(x2, y2, x4, y4, k-1)
        koch(x4, y4, x3, y3, k-1)
        koch(x3, y3, x1, y1, k-1)
    else:
        draw(x0, y0, x2, y2)
        draw(x2, y2, x4, y4)
        draw(x4, y4, x3, y3)
        draw(x3, y3, x1, y1)


#主函数
if __name__ == "__main__":
    init()
    koch(-400, 0 , 400, 0, 5)
    turtle.done()

这里关于点的计算是难点。首先我们选定了一条直线的首位两个点作为原点,他们是(x0, y0)和(x1, y1)然后在第一次迭代之后中间的三分之一就会由(x2, y2)和(x3, y3)组成,等边三角形的另一个定点就是(x4, y4)。其中(x2, y2)和(x3,y3)的计算并不困难,拿(x2, y2)距离。

x2 = 1/3*(x1-x0) + x0 = 2/3*x0 + 1/3*x1

y2 = 1/3*(y1-y0) + y0 = 2/3*y0 + 1/3*y1

(x4, y4)可以看成中间的线段旋转60°得到的点,所以可以使用旋转坐标公式

x0= (x - rx0)*cos(a) - (y - ry0)*sin(a) + rx0
y0= (x - rx0)*sin(a) + (y - ry0)*cos(a) + ry0
其中(rx0,ry0)是旋转中心,(x,y)待旋转点,(x0,y0)旋转后的新坐标。
计算得

x5 = x3 + ((x2 - x1) - (y2 - y1) * Math.sqrt(3)) / 6;
y5 = y3 + ((x2 - x1) * Math.sqrt(3) + (y2 - y1))  / 6;

L系统

这部分我是从灯神的视频里学的

https://www.bilibili.com/video/av28637396?t=1133

L系统有三个要素:变量集合,原始公式和递推式

每次迭代,所有原始公式中可以递推的元素都要进行替换。

我们先来看一个例子

import turtle

length = 20
angle = 90
path = "F-F-F-F"    #最原始的规则


#画图函数
def draw_path(path):
    for symbol in path:
        if symbol == "F":
            turtle.forward(length)
        elif symbol == "-":
            turtle.left(angle)
        elif symbol == "+":
            turtle.right(angle)

#将路径迭代
def apply_rule(path):
    rule = "F-F+F+FF-F+F"   #这个规则可以随意改,画出来的图形都很好看
    path = path.replace("F", rule) #将所有F换成rule
    return path


turtle.speed(5)
turtle.pensize(2)
turtle.pencolor("orange")
for i in range(2):
    path = apply_rule(path)
draw_path(path)
turtle.done()

这个例子中,变量集合有{F, + , -};初始公式为“F-F-F-F”;递推式为“F->F-F+F+FF-F+F”

我们再来看一个稍微复杂一点的例子

在这个例子中,递推式变成了两个

变量集合{Fl, Fr, + ,-};初始公式为Fl;

递推式为“Fl->Fl+Fr++Fr-Fl--FlFl-Fr+” ; "Fr->-Fl+FrFr++Fr+Fl--Fl-Fr"

import turtle

length = 10
angle = 60

rules = {
    "Fl" : "Fl+Fr++Fr-Fl--FlFl-Fr+",
    "Fr" : "-Fl+FrFr++Fr+Fl--Fl-Fr"
}

path = "Fl"

def split_path(path):
    i = 0
    lst = []
    while i < len(path):
        if path[i] == "F":
            lst.append(path[i:i+2]) #组合成一个元素
            i = i+2
        else:
            lst.append(path[i])
            i = i+1
    return lst

def apply_rule(path, rules):
    lst = split_path(path)
    for i in range(len(lst)):
        symbol = lst[i]
        if symbol in rules:
            lst[i] = rules[symbol]
    path = "".join(symbol for symbol in lst)    #将lst所有元素连接成字符串
    return path

def draw_path(path):
    lst = split_path(path)
    for symbol in lst:
        if symbol == "Fl" or symbol == "Fr":
            turtle.forward(length)
        elif symbol == "-":
            turtle.left(angle)
        elif symbol == "+":
            turtle.right(angle)

turtle.speed(0)
turtle.pensize(2)
turtle.pencolor("orange")
turtle.penup()
turtle.setposition(100, 200)
turtle.pendown()
for i in range(4):
    path = apply_rule(path, rules)
draw_path(path)

turtle.done()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值