用Python绘图,感受编程之美冬日里,树叶都已落下,还好可以用Python,重现银杏树的美
用Python绘图,发现编程之美
冬日里,树叶都已落下,还好可以用Python,重现银杏树的美
昨日的雪,提醒着我冬天已到,这让我更加怀念京城的秋景。北京的秋天除了看红叶就要属赏银杏了,美丽的银杏树总是让人百看不厌。满眼的金黄映着秋日的暖阳美极了。
美丽的银杏银杏特写
银杏树,可算是活化石,恐龙也曾目睹过他的风姿。同时银杏又是“晚熟晚育”,一棵银杏树苗长成大树结果,需要几十年时间,所以有爷爷种树,孙儿乘凉的说法。因此银杏又被称作公孙树。
可惜北京的秋天总是稍纵即逝。叶子总有落下掉没的一天。我想到也许可以用Python编程,模仿银杏的美。用Python的Turtle绘图函数库,随时都可以看到漂亮的银杏树。
我的设计思路
我的想法是:分成3个部分。1、画树叶 2、画树干和树枝 3、加特效(光影和飘落效果),下面我从这三部分分别介绍:
1、画树叶
如果仔细看一下银杏树叶的特写,其是银杏叶有一个很复杂的结构。不是简单的一个扇面,叶片的轮廓其实是由多个弧形连续组成。而且中间还会有个很大的分叉。真实的银杏叶
当然我这里用了简化思维,降低了难度,我把银杏看成是由三个弧形构成,最终完成一个闭合的形状。
代码实现lv.begin_fill()
lv.circle(10, 120) # 画一段120度的弧线
lv.penup() # 抬起笔来
lv.goto(px, py) # 回到圆点位置
lv.setheading(an+90) # 向上画
lv.pendown() # 落笔,开始画
lv.circle(-10, 120) # 画一段120度的弧线
lv.setheading(an+100)
lv.circle(15, 150) 画一段150度的弧线,围一个形状即可
lv.end_fill()#叶子的效果
2、画树干和树枝
树干和树枝要麻烦很多。首先树干走向和枝条的分布,好像并没有规律可循。如果完全按照小象学院介绍的使用分形树(即利用递归函数,不断调用自身,你可以理解为套娃),可能会看起来不太自然。真实的树不可能如此的对称。(不是所有的节点都需要分叉)普通的分形树
用什么方式可以近似模拟自然树的分叉方式。或者看上去自然一些呢??这时我想到了意大利一位伟大的数学家,斐波那契。据说他是在观察一窝兔子产子数量规律时,发现了伟大的斐波那契数列。该数列特性很多,最根本一条:从第三项起,任何一个数字均是其前两个数字的和数。在大自然界中和日常生活中能看到很多这样的例子比如:依照黄金分割率画出的螺旋形其实也是符合斐波那契数列的。其实自然生长的树的分叉规律也可以套用这个数列。如下图所示,是不是看着自然得多。斐波那契数列在树上的应用
我们可以利用斐波那契数列的定义,通过循环得出。并存储在一个列表中。代码实现:def Fibonacci_Recursion_tool(n):
if n <= 0:
return 0
elif n == 1:
return 1
else:
return Fibonacci_Recursion_tool(n - 1) + Fibonacci_Recursion_tool(n - 2)
def Fibonacci_Recursion(n):
result_list = []
for i in range(1, n + 3):
result_list.append(Fibonacci_Recursion_tool(i))
return result_list
之后就是精华。我自己想出来的哈哈。通过变量level,得到当前层数,然后套用该层的斐波那契数列,每画一个分支都对该层的数列做减一操作并给开关变量取反。这样保证每层分叉数量可以满足斐波那契数列。同时我在是否画树枝上还加了随机判断,这样保证我的树形不会太单调。
代码实现if level==top and x==5 :
turtle.forward(length) # 画树枝
yu[level] = yu[level] - 1
c=random.randint(2,10)
for i in range(1,c):
leaf(turtle.xcor(), turtle.ycor(), node)
elif level>3 and (x==8 or x==3) :
turtle.pendown()
turtle.forward(length)
c = random.randint(4, 6)
for i in range(3, c):
leaf(turtle.xcor(), turtle.ycor(), node)
leaf(turtle.xcor(), turtle.ycor(),node)
button=1# jump"""终结下面的递归
else:
turtle.forward(length) # 画树枝
yu[level] = yu[level] -1
if node>0 and button==0: # 开始执行递归
3、画光影特效和飘落效果
光影特效这部分主要参考了网友的帖子,将画笔的角度转换为改变RGB颜色值的参考系。
代码实现t = cos(radians(turtle.heading()+5)) / 8 + 0.25
turtle.pencolor(t*1.6, t*1.2, t*1.4)
飘落效果这部分也是参考了网友的帖子,我的主要贡献是把他原来为python2.0语法写的代码,用3.0重写了一遍。(大言不惭)
代码实现if random.random() >0.5:
turtle.penup()
# 飘落
t1 = turtle.heading()
an1 = -40 + random.random() * 40
turtle.setheading(an1)
dis = int(800 * random.random() * 0.5 + 400 * random.random() * 0.3 + 200 * random.random() * 0.2)
turtle.forward(dis)
turtle.setheading(t1)
turtle.right(90)
# 画叶子
leaf(turtle.xcor(), turtle.ycor(), node)
turtle.left(90)
# 返回
t2 = turtle.heading()
turtle.setheading(an1)
turtle.backward(dis)
turtle.setheading(t2)
最终看效果,每次只需要输入节点数量和主干长度就可以随机画出一棵还算自然的银杏树
做好的效果
长按扫码关注