以turtle函数的应用:L系统为例。(turtle函数是画图的库)
论文:《Graphical modeling using L-systems》
L系统的解释有点偏生物细胞方向,详细介绍移步百度百科。本质上就是一个重写系统。
b站up主指路:正月点灯笼
我这里只是学习了根据需求如何编写程序,程序的逻辑该是怎样的。
主要学到了替换规则和连接元素的编程思路。
‘F’:前进 ‘-’:左转 ‘+’:右转
前进长度:length(L) 转弯角度:angle(A)
原始路径:"F-F-F-F"(含义:前进L,左转A,前进L,左转A,前进L,左转A,前进L)
规则:F --> F-F+F+FF-F-F+F (含义,将所有的前进F替换成"F-F+F+FF-F-F+F")
比如:迭代一次后路径变成"F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F"
画图:(angle = 90。length根据图形复杂度定义大小,复杂图形想看到全貌length就定义小一点)
原始路径的图形"F-F-F-F":
规则使用一次(迭代一次)之后的图形:
规则使用两次(迭代两次)之后的图形:
代码:(论文图1.6的复现)
无规则时的代码:
from turtle import *
length = 10 # 定义前进长度
angle = 90 # 定义转弯角度
def draw_path(path): # 画图的方法,输入变量为原始路径
for symbol in path: # 遍历原始路径
if symbol == 'F': # 如果是F,那么前进length;如果是-,那么左转angle度;如果是+,那么右转angle度
forward(length)
elif symbol == '-':
left(angle)
elif symbol == '+':
right(angle)
path = "F-F-F-F" # 原始路径
speed(0)
draw_path(path) # 调用画图的方法
exitonclick()
有规则时的代码:
from turtle import *
length = 10 # 定义前进长度
angle = 90 # 定义转弯角度
def draw_path(path): # 画图的方法,输入变量为原始路径
for symbol in path: # 遍历原始路径
if symbol == 'F': # 如果是F,那么前进length;如果是-,那么左转angle度;如果是+,那么右转angle度
forward(length)
elif symbol == '-':
left(angle)
elif symbol == '+':
right(angle)
def apply_rule(path): # 使用规则的代码,输入参数为路径
rule = "F-F+F+FF-F-F+F" # 规则
path = path.replace("F", rule) # 将所有的F替换成规则
return path # 返回替换之后的路径
path = "F-F-F-F" # 原始路径
speed(0)
path = apply_rule(path) # 调用规则的方法
#path = apply_rule(path) # 使用几次(迭代几次)就调用几次
draw_path(path)
exitonclick()
复杂一点的该怎么处理?比如图1.10
可以看到,原始路径是Fl,但有两条规则。如果根据上面的replace函数编写代码(如下图)
那么,会出状况:
原始路径:Fl
程序第一步运行:查找原始路径中的Fl,将其替换成"Fl+Fr+",路径成为了Fl+Fr+
程序第二步运行:运行第一条规则,查找原始路径中的Fl并替换,路径成为Fl+Fr++Fr+;
注意:这里出现了两个Fr,第一个是已经运用了第一条规则的Fr,第二个是上一步路径里的Fr。理想的,在使用第二条规则时,应该是第一个Fr不变,而改变第二个Fr。但如果还是使用replace函数,则不会按照理想步骤进行下去。
因此,需要另外一种替换规则的方式:
将Fl+Fr+变成数组的形式:['Fl','Fr','+']。在数组里面遍历每个元素,如果有Fl,那就第一条规则将对应元素替换;如果有Fr,那就第二条规则将对应元素替换。同时进行。
于是:
1、拆分路径:
def split_path(path): # 拆分路径成为数组的形式
i = 0
lst = []
while i < len(path):
# 如果第i个元素是F的话,那么将当前元素和后一个元素进行组合。这一步是得到Fl或者Fr。
# 如果不这么切片的话,path[i]是“F”和“l”,或者是“F”和“r”
if path[i] == 'F':
lst.append(path[i:i+2])
i += 2
else: # 否则,就直接放入创建的数组里。这一步是得到“+”或者“-”
lst.append(path[i])
i += 1
return lst
2、使用规则,然后合成一个完整的路径:
def apply_rule(path, rules): # 将数组使用规则,然后合成一个完整的路径
lst = split_path(path) # 得到切开的数组
for symbol in lst: # 遍历数组元素
if symbol in rules: # 如果数组中有元素是字典rules里的,那么就使用规则进行替换
# lst.index(symbol)是想找到元素symbol在lst数组里所在的索引位置
# 比如数组['Fl','+','Fr','+']。Fl的索引为0,那么lst.index(symbol)的值为0。lst[0]就是指代数组lst的第一个元素变成rules[symbol]
# 而rules是一个字典,symbol是Fl,那么rules[symbol]就是冒号后面的值"Fl+Fr+"
lst[lst.index(symbol)] = rules[symbol]
# 这组合的方式精髓了(该学习的)
# 用join函数进行连接。最前面的""的含义是用什么方式进行连接,双引号之间什么都没有就不用任何字符,如果双引号之间有空格等字符,就是用空格等字符去连接。
# join后面是遍历lst里面的每个元素,取名为symbol,然后将symbol连起来得到path。path的值就是“Fl+Fr+++-Fl-Fr+”
path = "".join(symbol for symbol in lst)
return path
规则的编写:
rules = {
"Fl": "Fl+Fr+",
"Fr": "-Fl-Fr"
}
3、画图(和之前差不多):
def draw_path(path): # 画图的方法,输入变量为原始路径
lst = split_path(path)
for symbol in lst:
if symbol == 'Fl' or symbol == 'Fr':
forward(length)
elif symbol == '-':
left(angle)
elif symbol == '+':
right(angle)
完整代码:
from turtle import *
length = 5 # 定义前进长度
angle = 90 # 定义转弯角度
def split_path(path): # 拆分路径成为数组的形式
i = 0
lst = []
while i < len(path):
# 如果第i个元素是F的话,那么将当前元素和后一个元素进行组合。这一步是得到Fl或者Fr。
# 如果不这么切片的话,path[i]是“F”和“l”,或者是“F”和“r”
if path[i] == 'F':
lst.append(path[i:i+2])
i += 2
else: # 否则,就直接放入创建的数组里。这一步是得到“+”或者“-”
lst.append(path[i])
i += 1
return lst
def apply_rule(path, rules): # 将数组使用规则,然后合成一个完整的路径
lst = split_path(path) # 得到切开的数组
for symbol in lst: # 遍历数组元素
if symbol in rules: # 如果数组中有元素是字典rules里的,那么就使用规则进行替换
# lst.index(symbol)是想找到元素symbol在lst数组里所在的索引位置
# 比如数组['Fl','+','Fr','+']。Fl的索引为0,那么lst.index(symbol)的值为0。lst[0]就是指代数组lst的第一个元素变成rules[symbol]
# 而rules是一个字典,symbol是Fl,那么rules[symbol]就是冒号后面的值"Fl+Fr+"
lst[lst.index(symbol)] = rules[symbol]
# 这组合的方式精髓了(该学习的)
# 用join函数进行连接。最前面的""的含义是用什么方式进行连接,双引号之间什么都没有就不用任何字符,如果双引号之间有空格等字符,就是用空格等字符去连接。
# join后面是遍历lst里面的每个元素,取名为symbol,然后将symbol连起来得到path。path的值就是“Fl+Fr+++-Fl-Fr+”
path = "".join(symbol for symbol in lst)
return path
def draw_path(path): # 画图的方法,输入变量为原始路径
lst = split_path(path)
for symbol in lst:
if symbol == 'Fl' or symbol == 'Fr':
forward(length)
elif symbol == '-':
left(angle)
elif symbol == '+':
right(angle)
rules = {
"Fl": "Fl+Fr+",
"Fr": "-Fl-Fr"
}
path = "Fl+Fr+" # 原始路径
speed(0)
path = apply_rule(path,rules) # 调用规则的方法
draw_path(path)
exitonclick()
论文后面还有一堆高大上画树的方式,但我不是生物领域的。目前就学到此。
综上:
1、学到了规则替换的方式:
- 简单的替换可以使用replace函数。
- 复杂的替换可以使用字典的方式进行书写规则,然后拆分成元素,将每个元素进行查找和替换。
2、连接元素的方式:join函数