起因
一开始看到这张图片,觉得很好看,于是用示例代码跑了跑。NetworkX包的example里有此实例。
自己动手用turtle也画出来了,这篇博文将介绍如何用turtle库来画这个Circular Tree
分析
- 可以很明显地看出来图形是递归生成的,可以无限画下去。这意味着可以用深度来控制图形
- 每一层结点都在同一个圆上,且这些圆构成了一组等距同心圆。每层结点个数为    3 n \;3^n 3n(假设原点位于第0层),且它们等分该层的圆,相邻结点与原点构成的角度为 2 π 3 n \frac{2\pi}{3^n} 3n2π。
思路
- 从原点生成3个结点,每个结点又各生成三个结点(即每个非叶子结点都有三个孩子结点),以此类推,直至达到深度限制
- 任意结点都可以很方便地由深度和角度来表示,即采用极坐标的方式计算位置,转换为直角坐标作图
- 任意结点的坐标不受父结点的坐标的影响,而是只受父结点的角度的影响
举例
- O O O为原点,第0层
- A 1 A_1 A1为第1层(结点之间角度为 2 π 3 \frac{2\pi}{3} 32π)的一个结点,与原点距离为 r r r,与x轴正向夹角为 − π -\pi −π
- A 2 A_2 A2为第2层(结点之间角度为 2 π 9 \frac{2\pi}{9} 92π)的一个结点,与原点距离为 2 r 2r 2r,与x轴正向夹角为 − π − 2 π 9 -\pi-\frac{2\pi}{9} −π−92π
- B 2 B_2 B2为第2层(结点之间角度为 2 π 9 \frac{2\pi}{9} 92π)的一个结点,与原点距离为 2 r 2r 2r,与x轴正向夹角为 − π -\pi −π
- C 2 C_2 C2为第2层(结点之间角度为 2 π 9 \frac{2\pi}{9} 92π)的一个结点,与原点距离为 2 r 2r 2r,与x轴正向夹角为 − π + 2 π 9 -\pi+\frac{2\pi}{9} −π+92π
- 由上可知,只需要知道父结点的角度,根据当前层数,就可以计算出三个孩子结点的坐标
代码
import turtle
import math
# 线段的宽度
line = 2
# 结点的半径
dot = 10
# 层距
r = 50
# turtle.speed(1)
turtle.hideturtle()
def draw_twopi(n):
# 第1层的角度
angle=2*math.pi/3
# 根结点
l=[[0,0,-math.pi/3]]
turtle.pensize(dot)
turtle.goto(0,0)
for i in range(0,n-1):
# 计算新的距离
new_r = r*(i+1)
for j in range(3**i):
# 取队列里的第一个元素
point = l[0]
# 该结点已使用 出队列
del l[0]
# 用该结点 生成左中右三个孩子结点
angle_offset=[-angle,0,+angle]
for k in range(3):
new_angle = point[2]+angle_offset[k]
cos=math.cos(new_angle)
sin=math.sin(new_angle)
# 孩子结点入队
l.append([new_r*cos,new_r*sin,new_angle])
turtle.goto(point[0],point[1])
turtle.down()
turtle.pensize(line)
turtle.goto(new_r*cos,new_r*sin)
turtle.pensize(dot)
turtle.goto(new_r*cos,new_r*sin)
turtle.up()
# 下一层 角度/=3
angle/=3
draw_twopi(5)
turtle.mainloop()
拓展
层间距未必要相等,如果让层间距递增或者递减,会产生不同的效果