python turtle绘制正多边形

目录

 

引言

正文

§1  绘画部分

§1.1  核心内容

§1.2  基本程序

§2  其他程序设计

§2.1  交互

§2.2  容错和排错设计

§3  完整程序代码

后记


引言

        正多边形是指二维平面内各边相等,各角也相等的多边形。这些平面图形往往给人平衡之美。本文将简单介绍一种绘制正多边形的python方法。

正文

§1  绘画部分

§1.1  核心内容

        要想绘制一个正多边形,首先要知道它的边数nos(number of side)、半径r(radius)和边长ls(lenth of side)。由于在实际绘画场景中,绘图器使用者往往会自定义边数、半径或边长,所以这三个量应当成为本程序函数里的自变量。

        经过研究,这三者存在内部联系,其中以边长和半径之间联系最为紧密,在这两个量之间存在函数关系,而因为半径r比边长ls更能在几何上给人直观的大小关系和空间感,所以选取半径r作为自变量,边长ls作为因变量。

       一般地,在同一个正多边形中,边长ls和半径r存在如下函数关系,其中边数nos作为参数参与计算:

ls与r的函数关系式:

而这个函数关系式用python表达式表示出来就是:

ls = m.sin(m.radians(180 / nos)) * 2 * r
#标识字母m标识了math库

(介于此公式推导较为简单,就不作赘述)

§1.2  基本程序

        基本程序功能应包含指定边数的正多边形绘制,在此基础上,可增设交互环节、绘画样板和可调节参数(如画笔颜色、画笔速度、画布颜色等)等。笔者在这里提供基础功能函数、交互环节、绘画样板和可调节参数选项,后期也可以根据需要安排基础功能函数,绘制更精美的图形。

(a)基础功能函数

基础功能函数:

def _init_(angle, radius, pencolor = 'black', bgcolor = 'white', pensize = 25, speed = 0):
    an = angle; r = radius
    t.hideturtle()
    t.pencolor(pencolor)
    t.bgcolor(bgcolor)
    t.pensize(pensize)
    t.speed(speed)
    t.pu()
    t.goto(0, r)
    t.seth(180)
    t.left(an / 2)
    t.pd()
def get_side_lenth(radius, number_of_side):
    nos = number_of_side; r = radius
    ls = m.sin(m.radians(180 / nos)) * 2 * r
    return ls
def get_exterior_angle(nos):
    an = 360 / nos
    return an
def custom_regular_polygon(number_of_side, lenth_of_side, angle, changer = changer):
    nos = number_of_side; ls = lenth_of_side; an = angle
    for i in range(nos):
        t.forward(ls)
        t.left(an)
    print(f'正{nos}边形绘画完毕。\nDone.')

#标识字母指向:t -> turtle; m -> math

其中,包含了几个重要变量:

序号变量名表示意义
1nos; number_of_side正多边形边数
2ls; lenth_of_side正多边形边长
3r; radius正多边形半径
4an; angle  正多边形外角度数

拆分来看,这四个基础函数的功能指向明确: 

序号函数名参数及其默认值

1

_init_angle, radius, pencolor = 'black', bgcolor = 'white', pensize = 25, speed = 0
2get_side_lenthradius, number_of_side
3get_exterior_anglenos
4custom_regular_polygonnumber_of_side, lenth_of_side, angle, changer = changer 

注:custom_regular_polygon函数参数changer是将阿拉伯数字替换为汉字的字典,仅为了增强输出时文字的美观性,不是必须的。

函数名功能返回值
_init_初始化turtle,做好画图准备
get_side_lenth通过给定的半径长度计算边长边长ls
get_exterior_angle通过给定的半径长度计算外角度数外角度数an
custom_regular_polygon在_init_函数运行的基础上,运用get_side_lenth函数、get_exterior_angle函数的返回值绘制指定边数的正多边形。

运行程序时,应将四者先后一并使用:

def custom_mode(nos, radius, pensize, speed, pencolor, bgcolor):
    ls = get_side_lenth(radius, nos) #计算边长
    an = get_exterior_angle(nos) #计算外角度数
    _init_(radius = radius, angle = an, pencolor = pencolor, bgcolor = bgcolor, pensize = pensize, speed = speed) #初始化turtle画笔、画布
    custom_regular_polygon(nos, ls, an) #绘制图形

可以像笔者一样将其统一为函数。

(b)样板模式

        在基础功能函数的基础上,可以设计几个绘制样板作为绘制实例,提供给使用者以便快速得到图形。

        笔者准备了从正三角形到正十边形,外加正一百边形共9个普通样板:

class classic:

    #初始化turtle画笔和画布,这里给定了除了angle和radius外的诸多参数的默认值(初始化不需要nos参与,故未提及)
    def _init_(angle, radius, pencolor = 'black', bgcolor = 'white', pensize = 2, speed = 0):
        an = angle; r = radius
        t.hideturtle()
        t.pencolor(pencolor)
        t.bgcolor(bgcolor)
        t.pensize(pensize)
        t.speed(speed)
        t.pu()
        t.goto(0, r)
        t.seth(180)
        t.left(an / 2)
        t.pd()

    #计算边长
    def get_side_lenth(radius, number_of_side):
        nos = number_of_side; r = radius
        ls = m.sin(m.radians(180 / nos)) * 2 * r
        return ls

    #计算外角度数
    def get_exterior_angle(nos):
        an = 360 / nos
        return an

    #正多边形样板
    def regular_triangle(ls, an):
        for i in range(3):
            t.forward(ls)
            t.left(an)
        print('正三角形(等边三角形)绘画完毕。\nDone.')
    def square(ls, an):
        for i in range(4):
            t.forward(ls)
            t.left(an)
        print('正四边形(正方形)绘画完毕。\nDone.')
    def regular_pentagon(ls, an):
        for i in range(5):
            t.forward(ls)
            t.left(an)
        print('正五边形绘画完毕。\nDone.')
    def regular_hexagon(ls, an):
        for i in range(6):
            t.forward(ls)
            t.left(an)
        print('正六边形绘画完毕。\nDone.')
    def regular_heptagon(ls, an):
        for i in range(7):
            t.forward(ls)
            t.left(an)
        print('正七边形绘画完毕。\nDone.')
    def regular_octagon(ls, an):
        for i in range(8):
            t.forward(ls)
            t.left(an)
        print('正八边形绘画完毕。\nDone.')
    def regular_nonagon(ls, an):
        for i in range(9):
            t.forward(ls)
            t.left(an)
        print('正九边形绘画完毕。\nDone.')
    def regular_decagon(ls, an):
        for i in range(10):
            t.forward(ls)
            t.left(an)
        print('正十边形绘画完毕。\nDone.')
    def regular_100_polygon(ls, an):
        for i in range(100):
            t.forward(ls)
            t.left(an)
        print('正一百边形绘画完毕。\nDone.')

§2  其他程序设计

        一个较为完善的交互式、提供计算服务和绘图功能的程序不仅要有计算核心(算法等)、绘图功能(基础功能函数、样板函数等),还要有通俗强大的交互能力、一定的容错能力和排错功能。所以,笔者在此写下自己的交互设计和容错、排错设计。

§2.1  交互

        本程序中交互的主要作用就是获取使用者提供的绘图需求,笔者将交互设计为函数。

def inter():
    choice = input('请选择绘画模式:\n(1)样板模式\n(2)自定义模式\n\nPlease select drawing mode:\n(1)default mode\n(2)DIY mode\n\n>>[')
    if '1' in choice:
        nos = input('''在此模式(样板模式)下,您可以选择预先设置好的正多边形绘图作为参考案例,下面是菜单:
In this mode (default mode), you can select the pre-set regular polygon drawing as a reference case. The following is the menu:
(1)正三角形(等边三角形)//regular triangle\n(2)正四边形(正方形)//square\n(3)正五边形//regular pentagon
(4)正六边形//regular hexagon\n(5)正七边形//regular heptagon\n(6)正八边形//regular octagon
(7)正九边形//regular nonagon\n(8)正十边形//regular decagon\n(9)正一百边形//regular polygon of 100 sides
请填写边数。\nPlease input the number of sides.\n>>[''').strip()
        try:
            nos = int(nos)
        except:
            print('请正确输入边数。\nPlease input the number correctly.')
            sys.exit()
        sample_mode(nos)
    else:
        nos = eval(input('请输入正多边形边数\nnumber of sides\n>>['))
        choice = input(f'边数nos:{nos}\n半径r:200\n画笔pen:5,black\n画布paper:white\n速度v:0\n请问是否需要更改参数?(Y/N)>>[').strip().upper()
        if 'Y' in choice:
            nos = eval(input('请输入正多边形边数\nnumber of sides\n>>['))
            radius = eval(input('请输入半径长度\nradius\n>>['))
            pensize = eval(input('请输入画笔粗细\npen size\n>>['))
            speed = int(input('请输入画笔速度\npen speed\n>>['))
            pencolor = input('请输入画笔颜色\npen colour\n>>[').strip().lower()
            bgcolor = input('请输入画布颜色\nbackground colour\n>>[').strip().lower()
        else:
            radius = 200; pensize = 5; speed = 0; pencolor = 'black'; bgcolor = 'white'
        custom_mode(nos, radius, pensize, speed, pencolor, bgcolor)

注:sample_mode函数就是样板功能的集合函数,custom_mode函数就是基础功能函数。

        在主干分支上也有交互:

if __name__ == '__main__':
    choice = input('欢迎使用正多边形绘图器,使用主功能请输入1,查看绘图范例请输入2。\n>>[')
    if '1' in choice:
        draw.inter()
    else:
        print('\n\n下面是调用示例:')
        for i in range(8):
            draw.example(10 - i, 200 - i * 20, 4, 10, 'white', 'gold')

注:draw.example函数是另一个样板,组合了多个正多边形。

§2.2  容错和排错设计

        笔者为程序设计的排错功能主要在于排除不规范输入对程序流程的干扰。

        如下:

def _error_raiser_(nos, radius, pensize, speed, pencolor, bgcolor):
    if type(nos) != int:
        print('下一次请输入一个整数。\nPlease input an integer next time.')
        sys.exit()
    if nos < 3:
        print('下一次请输入一个大于2的整数。\nPlease input an integer bigger than two next time.')
        sys.exit()
    if type(radius) != int:
        if type(radius) != float:
            print('下一次请输入一个数值作为半径。\nPlease input a number as the radius next time.')
            sys.exit()
    if type(pensize) != int:
        if type(radius) != float:
            print('下一次请输入一个数值作为画笔粗细。\nPlease input a number as the pen size next time.')
            sys.exit()
    if type(speed) != int:
        print('下一次请输入一个整数值作为画笔速度。\nPlease input an integer as the pen speed next time.')
        sys.exit()
    if type(pencolor) != str:
        print('下一次请输入一个有效字符串作为画笔颜色。\nPlease input a useful number as the pen color next time.')
        sys.exit()
    if type(bgcolor) != str:
        print('下一次请输入一个有效字符串作为画布颜色。\nPlease input a useful number as the background color next time.')
        sys.exit()
        #若半径为0或负数,则使用默认值180。
    if radius <= 0:
        radius = 180
    if pensize <= 0:
        pensize = 5
    if speed < 0:
        speed = 0
    if pencolor == 'default':
        pencolor = 'black'
    if bgcolor == 'default':
        bgcolor = 'white'
    return radius, pensize, speed, pencolor, bgcolor

注:输入种类甚繁,请诸位过目,笔者不作赘述。

PS:虽然名字叫“error_raiser”,但笔者选择直接用sys.exit(),当然实操时也可以换为raise Exception()。

        笔者还在小规模输入处安插了如try...except...等排错设置。

        至于容错能力,其实一般般,没有怎么用心设计,主要在于多分支结构强大的“顺流而下”能力。

§3  完整程序代码

        本程序的完整程序代码如下所示。

import turtle as t
import random as ran
import math as m
import sys
import time as tm
class classic:
    def _init_(angle, radius, pencolor = 'black', bgcolor = 'white', pensize = 2, speed = 0):
        an = angle; r = radius
        t.hideturtle()
        t.pencolor(pencolor)
        t.bgcolor(bgcolor)
        t.pensize(pensize)
        t.speed(speed)
        t.pu()
        t.goto(0, r)
        t.seth(180)
        t.left(an / 2)
        t.pd()
    def get_side_lenth(radius, number_of_side):
        nos = number_of_side; r = radius
        ls = m.sin(m.radians(180 / nos)) * 2 * r
        return ls
    def get_exterior_angle(nos):
        an = 360 / nos
        return an
    def regular_triangle(ls, an):
        for i in range(3):
            t.forward(ls)
            t.left(an)
        print('正三角形(等边三角形)绘画完毕。\nDone.')
    def square(ls, an):
        for i in range(4):
            t.forward(ls)
            t.left(an)
        print('正四边形(正方形)绘画完毕。\nDone.')
    def regular_pentagon(ls, an):
        for i in range(5):
            t.forward(ls)
            t.left(an)
        print('正五边形绘画完毕。\nDone.')
    def regular_hexagon(ls, an):
        for i in range(6):
            t.forward(ls)
            t.left(an)
        print('正六边形绘画完毕。\nDone.')
    def regular_heptagon(ls, an):
        for i in range(7):
            t.forward(ls)
            t.left(an)
        print('正七边形绘画完毕。\nDone.')
    def regular_octagon(ls, an):
        for i in range(8):
            t.forward(ls)
            t.left(an)
        print('正八边形绘画完毕。\nDone.')
    def regular_nonagon(ls, an):
        for i in range(9):
            t.forward(ls)
            t.left(an)
        print('正九边形绘画完毕。\nDone.')
    def regular_decagon(ls, an):
        for i in range(10):
            t.forward(ls)
            t.left(an)
        print('正十边形绘画完毕。\nDone.')
    def regular_100_polygon(ls, an):
        for i in range(100):
            t.forward(ls)
            t.left(an)
        print('正一百边形绘画完毕。\nDone.')
class custom:
    changer = {3 : '三' , 4 : '四' , 5 : '五' , 6 : '六' , 7 : '七' ,
               8 : '八' , 9 : '九' , 10 : '十' , 100 : '一百'}
    def _error_raiser_(nos, radius, pensize, speed, pencolor, bgcolor):
        if type(nos) != int:
            print('下一次请输入一个整数。\nPlease input an integer next time.')
            sys.exit()
        if nos < 3:
            print('下一次请输入一个大于2的整数。\nPlease input an integer bigger than two next time.')
            sys.exit()
        if type(radius) != int:
            if type(radius) != float:
                print('下一次请输入一个数值作为半径。\nPlease input a number as the radius next time.')
                sys.exit()
        if type(pensize) != int:
            if type(radius) != float:
                print('下一次请输入一个数值作为画笔粗细。\nPlease input a number as the pen size next time.')
                sys.exit()
        if type(speed) != int:
            print('下一次请输入一个整数值作为画笔速度。\nPlease input an integer as the pen speed next time.')
            sys.exit()
        if type(pencolor) != str:
            print('下一次请输入一个有效字符串作为画笔颜色。\nPlease input a useful number as the pen color next time.')
            sys.exit()
        if type(bgcolor) != str:
            print('下一次请输入一个有效字符串作为画布颜色。\nPlease input a useful number as the background color next time.')
            sys.exit()
        #若半径为0或负数,则使用默认值180。
        if radius <= 0:
            radius = 180
        if pensize <= 0:
            pensize = 5
        if speed < 0:
            speed = 0
        if pencolor == 'default':
            pencolor = 'black'
        if bgcolor == 'default':
            bgcolor = 'white'
        return radius, pensize, speed, pencolor, bgcolor
    def _init_(angle, radius, pencolor = 'black', bgcolor = 'white', pensize = 25, speed = 0):
        an = angle; r = radius
        t.hideturtle()
        t.pencolor(pencolor)
        t.bgcolor(bgcolor)
        t.pensize(pensize)
        t.speed(speed)
        t.pu()
        t.goto(0, r)
        t.seth(180)
        t.left(an / 2)
        t.pd()
    def get_side_lenth(radius, number_of_side):
        nos = number_of_side; r = radius
        ls = m.sin(m.radians(180 / nos)) * 2 * r
        return ls
    def get_exterior_angle(nos):
        an = 360 / nos
        return an
    def custom_regular_polygon(number_of_side, lenth_of_side, angle, changer = changer):
        nos = number_of_side; ls = lenth_of_side; an = angle
        for i in range(nos):
            t.forward(ls)
            t.left(an)
        print(f'正{nos}边形绘画完毕。\nDone.')
class draw:
    class main_:
        def sample_mode(nos):
            if nos not in [3,4,5,6,7,8,9,10,100]:
                print('请检查您的输入。此边数不在样板之内。\nPlease check your inputs.It\'s not in samples.')
                sys.exit()
            ls = classic.get_side_lenth(180, nos)
            an = classic.get_exterior_angle(nos)
            classic._init_(angle = an, radius = 180)
            if nos == 3:
                classic.regular_triangle(ls, an)
            elif nos == 4:
                classic.square(ls, an)
            elif nos == 5:
                classic.regular_pentagon(ls, an)
            elif nos == 6:
                classic.regular_hexagon(ls, an)
            elif nos == 7:
                classic.regular_heptagon(ls, an)
            elif nos == 8:
                classic.regular_octagon(ls, an)
            elif nos == 9:
                classic.regular_nonagon(ls, an)
            elif nos == 10:
                classic.regular_decagon(ls, an)
            else:
                classic.regular_100_polygon(ls, an)
        def custom_mode(nos, radius, pensize, speed, pencolor, bgcolor):
            radius, pensize, speed, pencolor, bgcolor = custom._error_raiser_(nos, radius, pensize, speed, pencolor, bgcolor)
            ls = custom.get_side_lenth(radius, nos)
            an = custom.get_exterior_angle(nos)
            custom._init_(radius = radius, angle = an, pencolor = pencolor, bgcolor = bgcolor, pensize = pensize, speed = speed)
            custom.custom_regular_polygon(nos, ls, an)
    def example(nos, radius, pensize, speed, pencolor, bgcolor):
        custom._error_raiser_(nos, radius, pensize, speed, pencolor, bgcolor)
        ls = custom.get_side_lenth(radius, nos)
        an = custom.get_exterior_angle(nos)
        custom._init_(radius = radius, angle = an, pencolor = pencolor, bgcolor = bgcolor, pensize = pensize, speed = speed)    
        custom.custom_regular_polygon(nos, ls, an)
    def inter():
        choice = input('请选择绘画模式:\n(1)样板模式\n(2)自定义模式\n\nPlease select drawing mode:\n(1)default mode\n(2)DIY mode\n\n>>[')
        if '1' in choice:
            nos = input('''在此模式(样板模式)下,您可以选择预先设置好的正多边形绘图作为参考案例,下面是菜单:
In this mode (default mode), you can select the pre-set regular polygon drawing as a reference case. The following is the menu:
(1)正三角形(等边三角形)//regular triangle\n(2)正四边形(正方形)//square\n(3)正五边形//regular pentagon
(4)正六边形//regular hexagon\n(5)正七边形//regular heptagon\n(6)正八边形//regular octagon
(7)正九边形//regular nonagon\n(8)正十边形//regular decagon\n(9)正一百边形//regular polygon of 100 sides
请填写边数。\nPlease input the number of sides.\n>>[''').strip()
            try:
                nos = int(nos)
            except:
                print('请正确输入边数。\nPlease input the number correctly.')
                sys.exit()
            draw.main_.sample_mode(nos)
        else:
            nos = eval(input('请输入正多边形边数\nnumber of sides\n>>['))
            choice = input(f'边数nos:{nos}\n半径r:200\n画笔pen:5,black\n画布paper:white\n速度v:0\n请问是否需要更改参数?(Y/N)>>[').strip().upper()
            if 'Y' in choice:
                nos = eval(input('请输入正多边形边数\nnumber of sides\n>>['))
                radius = eval(input('请输入半径长度\nradius\n>>['))
                pensize = eval(input('请输入画笔粗细\npen size\n>>['))
                speed = int(input('请输入画笔速度\npen speed\n>>['))
                pencolor = input('请输入画笔颜色\npen colour\n>>[').strip().lower()
                bgcolor = input('请输入画布颜色\nbackground colour\n>>[').strip().lower()
            else:
                radius = 200; pensize = 5; speed = 0; pencolor = 'black'; bgcolor = 'white'
            draw.main_.custom_mode(nos, radius, pensize, speed, pencolor, bgcolor)
if __name__ == '__main__':
    choice = input('欢迎使用正多边形绘图器,使用主功能请输入1,查看绘图范例请输入2。\n>>[')
    if '1' in choice:
        draw.inter()
    else:
        print('\n\n下面是调用示例:')
        for i in range(8):
            draw.example(10 - i, 200 - i * 20, 4, 10, 'white', 'gold')
        t.exitonclick()

#正多边形画图器 V3.5
#创建日期  3 Oct, 2022
#Author starlight_2007

        总结一下,流程图如下 :

 (程序导出的原图水印很烦人,只能先用截屏)

后记

        本程序功能简单,结构明晰,笔者也一步步分析了设计理念。

        希望读者遇见新的知识!

PS:题外话,说真的,要是闲的没事,这套流程还可以再接一个数据库,各个报错端口都能接,还可以再多加几个,记录访客等。要是喜欢,自己分析一下数据也很好玩。不过这些并不适合用在这样一个功能性极强且简单的程序上。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值