2022年 11月 9日

Python 用turtle库画八卦

 练习项目,用turtle绘图库画个八卦。

关于八卦的具体细节,在画之前,除了知道这叫八卦外(曾一度叫它太极,没想到外面多了几行就不一样了),一无所知,画完后也不过多认识了个阴阳,所以,表述中基本都是口语字词,还有位置什么的是不是准确,也不知道,有熟悉之人可以在评论区科普下,不甚感激。


开始前先罗列下下手逻辑:内,太极部分;外,八卦部分。

作图中碰到的主要问题:

  1. 初始化画笔原点,以便于开始下一个命令清晰画笔位置和朝向;
  2. 初始作图起点,保证整体处于画布中间;
  3. 卦象的画法。                    

 上面三个问题中,卦象的画法花费时间最近,最开始是用:使用for循环画三个同心逐级变小的八边形,再用辐射擦除的方法来完成的:

 整体看起来,没什么问题,但是总觉得有些难看。


 更给目标:保持每一卦的线段长短一致,中间断点一致,在每一卦的外围加上卦名。


1.引入库

代码如下:turtle

from turtle import *

2.代码

代码如下:

  1. # python 3.6
  2. # pycharm
  3. from turtle import *
  4. # 返回原点
  5. def rset():
  6. pensize(1)
  7. pencolor('black')
  8. penup()
  9. home()
  10. pendown()
  11. # 设置画笔偏移,初始化八卦和太极的画笔起始点,保持整体居中
  12. def offset(off_set, angle=0, mode='taiji'):
  13. # off_set太极时为大圆半径,八卦时要大于半径,否则会与太极重合。
  14. # angle默认为0,mode默认为‘taiji’,画太极的时候,不需要设置,默认即可;画卦的时候angle=angl,mode=‘bagua’。
  15. penup()
  16. home() # 回到原点,朝向东
  17. if mode == 'taiji': # 太极
  18. right(90)
  19. fd(off_set)
  20. seth(0) # 朝向东
  21. else: # 八卦
  22. left(angle) # 每画一卦旋转45度的倍数,开始下一卦。
  23. fd(off_set)
  24. left(90)
  25. pendown()
  26. # 太极生成
  27. def taiji(radius, pen_size=2, color='black'):
  28. rset() # 初始化画笔
  29. pensize(pen_size)
  30. pencolor(color)
  31. offset(radius) # 画笔偏移至起始点
  32. fillcolor('black') # 填充颜色
  33. begin_fill() # 开始填充
  34. circle(radius, 180) # 画大圆的半圆
  35. circle(radius / 2, 180) # 画s型
  36. circle(-radius / 2, 180) # 画s型
  37. end_fill() # 结束填充
  38. circle(-radius, 180) # 画大圆的另一半圆
  39. # 上面小圆
  40. begin_fill()
  41. fillcolor('white')
  42. penup()
  43. home() # 返回原点,默认朝东
  44. left(90)
  45. fd(radius * 0.7) # 初始化小圆画笔起始点
  46. right(90)
  47. pendown()
  48. circle(-radius * 0.2) # 画小圆
  49. end_fill()
  50. rset()
  51. # 下面小圆
  52. penup()
  53. begin_fill()
  54. fillcolor('black')
  55. right(90)
  56. fd(radius * 0.7)
  57. left(90)
  58. pendown()
  59. circle(radius * 0.2)
  60. end_fill()
  61. # 八卦生成
  62. def bagua(off_set, side, gua_lis):
  63. pensize(side / 2)
  64. for j, k in enumerate(gua_lis): # 枚举八卦列表,获取元素和下标,下标拿来判断旋转多少度
  65. angl = j * 45 # 偏移角度:0,45,90,135,180,225,270,315,360
  66. rset() # 初始化到原点
  67. offset(off_set, angle=angl, mode='bagua') # 偏移到八卦画笔,此时画笔位于线段中间点,下面3行代码初始到线段开头
  68. pencolor('white')
  69. pensize(5)
  70. bk(side / 2)
  71. for i in k: # 遍历每一卦的集合,1为阳也就是完整线段,0为阴,带断点的线段
  72. pencolor('black')
  73. if i == 1:
  74. fd(side)
  75. elif i == 0:
  76. fd(side * (1 / 3))
  77. penup()
  78. fd(side * (1 / 3))
  79. pendown()
  80. fd(side * (1 / 3))
  81. elif isinstance(i, str) and j <= 4: # 判断集合内内容,为字符串时,且为前5卦时,直接用write方法打印
  82. penup()
  83. fd(side / 2)
  84. pendown()
  85. write(i, align='center', font=('楷体', 15, "bold")) # align有三个选项:’left‘,’center‘,’right‘,i后面两项可不填
  86. else: # 后3卦,多偏移了一些距离,再用write方法打印,避免文字与卦重叠,影响效果
  87. penup()
  88. fd(side / 2)
  89. right(90)
  90. fd(15)
  91. pendown()
  92. write(i, align='center', font=('楷体', 15, "bold"))
  93. penup() # 每画完一卦中的一条线后,回到中点,向外移动后,开始画下一段线段
  94. bk(side / 2)
  95. right(90)
  96. fd(side / 2)
  97. left(90)
  98. bk(side / 2)
  99. pendown()
  100. gua_lis = [(1, 1, 0, '兑'), (0, 0, 0, '坤'), (1, 0, 1, '离'), (0, 1, 1, '巽'), (1, 0, 0, '震'), (0, 0, 1, '艮'),
  101. (0, 1, 0, '坎'), (1, 1, 1, '乾')]
  102. taiji(50)
  103. bagua(70, 30, gua_lis)
  104. hideturtle()
  105. done()