科赫雪花
科赫雪花于 1904 年由瑞士数学家黑格尔 - 冯 - 科赫提出,是一种分形,即一种不断放大时会重复自己的图形。分形源自递归,递归操作本身就是在重复使用自己定义自己。其图片如下:
介绍科赫雪花的分形数学原理及递归概念。利用 Python turtle 库,通过递归函数将线段三等分并构建等边三角形凸起来绘制雪花。包含垂直向量计算、坐标公式推导及代码实现步骤,展示从基础三角形到完整雪花的生成过程。

科赫雪花于 1904 年由瑞士数学家黑格尔 - 冯 - 科赫提出,是一种分形,即一种不断放大时会重复自己的图形。分形源自递归,递归操作本身就是在重复使用自己定义自己。其图片如下:

Step 1: 定义一个基线条件,达到条件时,自动结束递归。
Step 2: 写一个算法可能用到多次递归。
阶层的表达式就是一个经典的递归:
def factorial(N):
if N == 1:
return 1
else:
return N * factorial(N - 1)
循环与递归的选择方面:各有千秋,递归优雅紧凑,循环高效快捷,本节我们将用递归绘制分形。
垂直向量计算技巧:已知点 A(a,b),当点 B 为 B (-b,a) 时:
从空间中的一点 A 沿着向量 n 出发,到达点 B 的坐标运算公式:
已知线段的两个端点 A 和 B,求其上面任意一点 C 的坐标公式,其中 a 为点 A 到点 C 的距离,b 为点 B 到点 C 的距离:

这是科赫雪花的第一个片段,我们一共需要 3 个相连接的片段。





t.up() / t.down():海龟绘图的核心操作,抬笔移动不画线,落笔移动才画线,这里用来'跳'到指定坐标,避免画多余的线;setpos(x,y):等价于 goto(x,y),让画笔移动到指定坐标,落笔时会画直线;import turtle
def draw_triangle(x1, y1, x2, y2, x3, y3, t):
t.up()
t.setpos(x1, y1)
t.down()
t.setpos(x2, y2)
t.setpos(x3, y3)
t.setpos(x1, y1)
t.up()
def main():
print('testing turtle graphics...')
# 创建海龟对象
t = turtle.Turtle()
# 隐藏海龟图标
t.hideturtle()
# 调用函数,传入海龟对象和坐标,确保绘制完成后不会关闭 tkinter 窗口
draw_triangle(t, -100, 0, 0, 173.2, 100, 0)
turtle.mainloop()
if __name__ == "__main__":
main()

第一步:把原始大线段 (x1,y1)→(x2,y2) 拆成 4 段更小的线段(科赫雪花的规则):
(x1,y1) → p1(三等分第一个点)p1 → p2(等边三角形的第一条边)p2 → p3(等边三角形的第二条边)p3 → (x2,y2)(三等分第二个点)第二步:对这 4 条小线段,重复调用同一个函数(递归),让每条小线段也执行'拆分成 4 段 / 直接画'的逻辑 —— 所以形参变成了每条小线段的'起点 + 终点'。
import turtle
import math
# drawKochSF() 计算点的坐标
def drawKochSF(x1, y1, x2, y2, t):
d = math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))
r = d/3.0
h = r*math.sqrt(3)/2.0
p3 = ((x1 + 2*x2)/3.0, (y1 + 2*y2)/3.0)
p1 = ((2*x1 + x2)/3.0, (2*y1 + y2)/3.0)
c = (0.5*(x1+x2), 0.5*(y1+y2))
n = ((y1-y2)/d, (x2-x1)/d)
p2 = (c[0]+h*n[0], c[1]+h*n[1])
# 递归
if d > 10: # flake
# flake #1/片段
drawKochSF(x1, y1, p1[0], p1[1], t)
# flake #2/片段
drawKochSF(p1[0], p1[1], p2[0], p2[1], t)
# flake #3/片段
drawKochSF(p2[0], p2[1], p3[0], p3[1], t)
# flake #4/片段
drawKochSF(p3[0], p3[1], x2, y2, t)
else: # draw cone
t.up()
t.setpos(p1[0], p1[1])
t.down()
t.setpos(p2[0], p2[1])
t.setpos(p3[0], p3[1])
# draw sides
t.up()
t.setpos(x1, y1)
t.down()
t.setpos(p1[0], p1[1])
t.up()
t.setpos(p3[0], p3[1])
t.down()
t.setpos(x2, y2)
# main() function
def main():
print('Drawing the Koch Snowflake...')
t = turtle.Turtle()
t.hideturtle()
# draw
try:
drawKochSF(-100, 0, 100, 0, t)
drawKochSF(0, -173.2, -100, 0, t)
drawKochSF(100, 0, 0, -173.2, t)
except:
print("Exception, exiting.")
exit(0)
# wait for user to click on screen to exit
turtle.Screen().exitonclick()
# call main
if __name__ == '__main__':
main()
try-except 代码块,异常捕获机制,专门用来处理绘制过程中可能出现的错误,避免程序直接崩溃。

d > 10 时递归拆分,d ≤ 10 时执行 else 里的绘制逻辑;(-100,0)→(100,0)、(0,-173.2)→(-100,0)、(100,0)→(0,-173.2);if __name__ == '__main__':
main() # 调用主函数
main() 函数,首先打印提示:Drawing the Koch Snowflake...;t = turtle.Turtle(),隐藏画笔箭头:t.hideturtle()(画笔默认速度,无加速);try 代码块,准备依次绘制 3 条科赫边。drawKochSF(-100, 0, 100, 0, t)d = √[(-100-100)² + (0-0)²] = 200(>10,触发递归);r = 200/3 ≈ 66.67,等边三角形高 h = 66.67×√3/2 ≈ 57.74;p1 = (2×(-100)+100)/3, (2×0+0)/3 = (-33.33, 0);p3 = (-100+2×100)/3, (0+2×0)/3 = (33.33, 0);c = (0, 0);n = (0-0)/200, (100-(-100))/200 = (0, 1);p2 = (0 + 57.74×0, 0 + 57.74×1) = (0, 57.74)。函数不绘制,而是拆成 4 段,依次递归调用自身:
drawKochSF(-100, 0, -33.33, 0, t) → 处理第一段(起点→p1);drawKochSF(-33.33, 0, 0, 57.74, t) → 处理第二段(p1→p2);drawKochSF(0, 57.74, 33.33, 0, t) → 处理第三段(p2→p3);drawKochSF(33.33, 0, 100, 0, t) → 处理第四段(p3→终点)。以「调用 1:drawKochSF(-100, 0, -33.33, 0, t)」为例,继续拆解:
d = √[(-100+33.33)² + 0] ≈ 66.67(>10,继续拆);p1/p2/p3(比如新 p1≈-77.78,新 p3≈-55.56,新 p2≈-66.67, 19.25);d ≤ 10(比如拆到第 3 层,d≈7.41),触发 else 分支。else:
# 1. 绘制'凸起':p1→p2→p3
t.up()
t.setpos(p1[0], p1[1]) # 移动到当前短线段的 p1
t.down()
t.setpos(p2[0], p2[1]) # 画 p1→p2
t.setpos(p3[0], p3[1]) # 画 p2→p3
# 2. 绘制两端:起点→p1,p3→终点
t.up()
t.setpos(x1, y1) # 移动到当前短线段的起点
t.down()
t.setpos(p1[0], p1[1]) # 画起点→p1
t.up()
t.setpos(p3[0], p3[1]) # 移动到当前短线段的 p3
t.down()
t.setpos(x2, y2) # 画 p3→终点
完成当前短线段的绘制后,函数执行完毕,回到上一层递归调用,继续处理下一段,直到第一层递归的 4 段都处理完,第一条边绘制结束。
drawKochSF(0, -173.2, -100, 0, t):
else 绘制逻辑;drawKochSF(100, 0, 0, -173.2, t):
turtle.Screen().exitonclick():等待你点击画布,程序退出;若绘制中出现任何错误(比如递归深度超限、坐标计算异常),触发 except 块:打印 Exception, exiting. 并退出程序。


微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online