学习Python中turtle模块的基本用法(4:绘制科赫曲线和谢尔宾斯基三角形)

  科赫曲线和谢尔宾斯基三角形是常见的分形图形(详细介绍见参考文献1),本文使用turtle库绘制这两类图形。

科赫曲线

  科赫曲线的详细介绍见参考文献2,其中的绘图思路是“画正三角形,并把每一边三等分,取三等分后的一边中间一段为边向外作正三角形,并把这“中间一段”擦掉,重复上述两步,画出更小的三角形。”考虑到绘制完三角形再处理每条边的话,使用turtle的绘制函数不便于计算坐标,于是调整为绘制每条边时都将其三等分,只处理要显示的前后两个子边,重复该过程至指定的迭代次数(看下面录制的绘图动画比较直观)。最终的绘图代码及绘图效果如下所示。

from turtle import *

def Kohn(length, n):
    if n==0:
        forward(length)
    else:
        thirdLen=length/3
        Kohn(thirdLen, n-1)
        right(60)
        Kohn(thirdLen, n-1)        
        left(120)
        Kohn(thirdLen, n-1)  
        right(60)
        Kohn(thirdLen, n-1)  

screensize(600,400)
tracer(0, 0)
penup()
goto(-180,-90)
pendown()
Kohn(360,8)
left(120)
Kohn(360,8)
left(120)
Kohn(360,8)
left(120)
hideturtle()
        
exitonclick()

在这里插入图片描述

在这里插入图片描述

谢尔宾斯基三角形

  参考文献3中介绍的谢尔宾斯基三角形的画法有去掉中心法、Chaos Game法和L系统,本文中采用Chaos Game法绘制。最初采用参考文献3中的构造方法绘图,绘图代码及绘出的图形如下所示(判断点是否在三角形内的代码来自参考文献4)。:

def Sierpinski_1(x1,y1,x2,y2,x3,y3):
    maxX=max((x1,x2,x3))
    minX=min((x1,x2,x3))
    maxY=max((y1,y2,y3))
    minY=min((y1,y2,y3))        
    rx=random.randint(minX+1,maxX-1)
    ry=random.randint(minY+1,maxY-1)

    while(not IsInside(x1,y1,x2,y2,x3,y3,rx,ry)):
          rx=random.randint(minX+1,maxX-1)
          ry=random.randint(minY+1,maxY-1)
       
    tmp=((x1,y1),(x2,y2),(x3,y3))[random.randint(0,2)]
    mx=(tmp[0]+rx)/2
    my=(tmp[1]+ry)/2
    penup() 
    goto(mx-1,my)
    pendown()
    right(90)
    circle(1)
    left(90)

screensize(600,400)
tracer(0, 0)
x1=-250
y1=-150
x2=150
y2=-150
x3=0
y3=100

for i in range(0,5000):    
    Sierpinski_1(x1,y1,x2,y2,x3,y3)

hideturtle()

在这里插入图片描述
  估计应该是绘图思路不对,百度谢尔宾斯基三角形的混沌游戏画法,发现步骤都大致相同,但重复的步骤不一致,最终基于参考文献5-6中的介绍,调整绘图思路为:
  1、随机生成三个点A,B,C,组成三角形;
  2、随机生成三角形的一点P;
  3、绘制点P,同时计算P与A,B,C中任意一点的中点,并将中点坐标赋予P;
  4、重复步骤3。
基于上述步骤,重新调整代码,绘图代码及绘图效果如下:

def Sierpinski_2(x1,y1,x2,y2,x3,y3,n):
    maxX=max((x1,x2,x3))
    minX=min((x1,x2,x3))
    maxY=max((y1,y2,y3))
    minY=min((y1,y2,y3))        
    px=random.randint(minX+1,maxX-1)
    py=random.randint(minY+1,maxY-1)

    while(not IsInside(x1,y1,x2,y2,x3,y3,px,py)):
          px=random.randint(minX+1,maxX-1)
          py=random.randint(minY+1,maxY-1)
    penup()
    goto(px-1,py)
    pendown()
    right(90)
    circle(1)
    left(90)

    points=((x1,y1),(x2,y2),(x3,y3))
    for index in range(0,n):
        tmp=points[random.randint(0,2)]
        px=(tmp[0]+px)/2
        py=(tmp[1]+py)/2
        penup() 
        goto(px-1,py)
        pendown()
        right(90)
        circle(1)
        left(90)

screensize(600,400)
tracer(0, 0)
x1=-250
y1=-150
x2=150
y2=-150
x3=0
y3=100

Sierpinski_2(x1,y1,x2,y2,x3,y3,5000)

hideturtle()

在这里插入图片描述
  最后是一个完成的随机版谢尔宾斯基三角形绘制代码

from turtle import *
import random

def IsTrangleOrArea(x1,y1,x2,y2,x3,y3):
    return abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0)

def IsInside(x1,y1,x2,y2,x3,y3,x,y): 
    ABC = IsTrangleOrArea(x1,y1,x2,y2,x3,y3)
    PBC = IsTrangleOrArea(x,y,x2,y2,x3,y3)
    PAC = IsTrangleOrArea(x1,y1,x,y,x3,y3)
    PAB = IsTrangleOrArea(x1,y1,x2,y2,x,y) 
    return (ABC == PBC + PAC + PAB)

    maxX=max((x1,x2,x3))
    minX=min((x1,x2,x3))
    maxY=max((y1,y2,y3))
    minY=min((y1,y2,y3))        
    px=random.randint(minX+1,maxX-1)
    py=random.randint(minY+1,maxY-1)

    while(not IsInside(x1,y1,x2,y2,x3,y3,px,py)):
          px=random.randint(minX+1,maxX-1)
          py=random.randint(minY+1,maxY-1)
    penup()
    goto(px-1,py)
    pendown()
    right(90)
    circle(1)
    left(90)

    points=((x1,y1),(x2,y2),(x3,y3))
    for index in range(0,n):
        tmp=points[random.randint(0,2)]
        px=(tmp[0]+px)/2
        py=(tmp[1]+py)/2
        penup() 
        goto(px-1,py)
        pendown()
        right(90)
        circle(1)
        left(90)

width=600
height=400

screensize(width,400)
tracer(0, 0)

x1=random.randint(1-width/2,width/2-1)
y1=random.randint(1-height/2,height/2-1)
x2=random.randint(1-width/2,width/2-1)
y2=random.randint(1-height/2,height/2-1)
x3=random.randint(1-width/2,width/2-1)
y3=random.randint(1-height/2,height/2-1)
Sierpinski_2(x1,y1,x2,y2,x3,y3,5000)
hideturtle()
exitonclick()

在这里插入图片描述

参考文献
[1]https://baike.baidu.com/item/%E5%88%86%E5%BD%A2/85449?fr=aladdin
[2]https://baike.baidu.com/item/%E7%A7%91%E8%B5%AB%E6%9B%B2%E7%BA%BF/7090673?fromModule=lemma_inlink
[3]https://baike.baidu.com/item/%E8%B0%A2%E5%B0%94%E5%AE%BE%E6%96%AF%E5%9F%BA%E4%B8%89%E8%A7%92%E5%BD%A2?fromModule=lemma_inlink
[4]https://blog.csdn.net/mxw322/article/details/56026607
[5]https://zhuanlan.zhihu.com/p/103610498?utm_source=wechat_session&ivk_sa=1024320u
[6]https://wiki.swarma.org/index.php?title=%E8%B0%A2%E5%B0%94%E5%AE%BE%E6%96%AF%E5%9F%BA%E4%B8%89%E8%A7%92%E5%BD%A2

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值