2

在此处输入图像描述

我今天在一个学习小组中遇到了一个挑战,要在 python 海龟库中绘制这个形状。

我想不出一种方法来表达几何解决方案来找到转弯的角度和我需要的线的大小。

你能告诉我如何单独绘制第一个多边形吗?我已经知道如何制作图案了。

我在五年级。所以请给我一个我能理解的解决方案。

4

6 回答 6

7

这是我想出的解决方案。它基于此图:

在此处输入图像描述

数学背景

我的解决方案使用“三角法”,这是一种从另一边的长度和三角形的角度计算三角形一侧的长度的方法。这是我希望在 9 年级或 10 年级时教授的高等数学。我不希望五年级的人知道三角学。我也无法解释三角学的每一个细节,因为我必须写很多,而且我不认为我有讲清楚的教学技能。我建议您查看例如此视频以了解该方法:

https://www.youtube.com/watch?v=5tp74g4N8EY

您也可以向您的老师询问更多信息,或自行在互联网上进行研究。

第 1 步:计算角度

我们可以在没有三角函数的情况下做到这一点。

首先,我们看到中间有一个“五边形”(5 边多边形)。我想知道这个“五边形”中一个角的内角。我称这个角度为X

在此处输入图像描述

我们如何计算角度X?我们首先要记住三角形内角的和是180°。我们看到我们可以将一个 5 边的多边形分成5-2如下三角形:

在此处输入图像描述

每个5-2三角形的内角之和为180°。所以对于整个 5 边多边形,内角之和为180° * (5-2)。由于所有角的大小都相同,因此每个角都是180°*(5-2) / 5 = 108°。所以我们有X = 108°.

另一边的角度与 相同X。这允许我们计算两者之间的角度X。我称这个角度为Y

在此处输入图像描述

既然是一整圈360°,我们就知道了360° = 2*X + 2*Y。因此,Y = (360° - 2*X) / 2。我们知道X = 108°,所以我们得到Y = 72°

接下来,我们看到有一个包含Y角度的三角形。我想知道Z三角形另一个角的角度:

在此处输入图像描述

三角形的内角之和为180°*(3-2) = 180°。因此,我们知道180° = 2*Y + Z,所以Z = 180° - 2*Y。我们知道Y = 72°,所以我们得到Z = 36°

我们将Z大量使用角度。你可以看到绿星的每个角落都有角度Z。蓝色的星星和绿色的星星一样,只是它是旋转的,所以所有蓝色的角也有角度Z。红星的角是绿星和蓝星角的两倍宽,所以红星的角有角2*Z

第 2 步:计算长度

首先,我们观察到所有外角都在一个圆上。我们称这个圆的半径R。我们不必计算R。相反,我们可以为R. 我们总是会得到相同的形状,但尺寸不同。我们可以称之为R形状的“参数”。

在此处输入图像描述

给定一些值R,我想知道以下长度:

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

计算A

我们从A. 我们可以看到下面的三角形:

在此处输入图像描述

三角形的长边是我们的半径R。另一边有长度A/2,我们不关心第三边。最右边的角度是Z/2Z = 36°我们在上一节中计算的角度)。角S是直角,所以S = 90°. 我们可以计算第三个角T,因为我们知道三角形的内角总和为180°。因此,180° = S + Z/2 + T。求解T,我们得到T = 180° - S - Z/2 = 180° - 90° - 36°/2 = 72°

接下来,我们使用三角函数来计算A/2。三角学告诉我们这一点A/2 = R * sin(T)。代入公式T,我们得到A/2 = R * sin(72°)。求解A,我们得到A = 2*R*sin(72°)

R例如,如果您为 选择一些值R = 100,您现在可以A使用此公式进行计算。你需要一个计算器sin(72°),因为在你的头脑中计算这个是非常困难的。放入sin(72)我的计算器给了我0.951056516。所以对于我们的选择R = 100,我们深知A = 2 * R * sin(72°) = 2 * 100 * 0.951056516 = 190.211303259

计算B

我们使用相同的技术来找到 的公式B。我们看到下面的三角形:

在此处输入图像描述

所以底边是我们半径的长度R。右边是B/2。我们不关心第三方。最右边的角度是三倍Z/2。角度S是直角,所以我们有S = 90°T我们可以用计算剩余角度180° = S + T + 3*Z/2。求解T,我们得到T = 180° - S - 3*Z/2 = 180° - 90° - 3*36°/2 = 36°。好的T = Z,我们也可以从图片中看到这一点,但现在我们已经计算过了。

使用三角函数,我们知道B/2 = R * sin(T),所以我们得到公式B = 2 * R * sin(36°)来计算B的某些选择R

计算C

我们看到下面的三角形:

在此处输入图像描述

所以底边有长度A/2,顶边有长度B。我们已经有了这两个方面的公式。第三边是C,我们要为其找到一个公式。最右边的角度是Z。角S是直角,所以S = 90°. 最高的角度是三倍Z/2

使用三角函数,我们得到C = sin(Z) * B

计算D

我们看到下面的三角形:

在此处输入图像描述

我们已经有了一个公式C。我们想找到一个公式D。最上面的角度是Z/2(我无法将文本放入三角形中)。左下角S是直角。

使用三角函数,我们知道D = tan(Z/2) * C. 该tan函数类似于sin前面的公式。您可以再次将其放入您的计算器中计算该值,因此对于Z = 36°,我可以放入tan(36/2)我的计算器中,它给了我0.324919696.

计算E

好的,这很容易,E = 2*D.

已经完成了一半!

计算F

这类似于AB

在此处输入图像描述

我们想找到一个公式F。顶面有长度F/2。底边的长度是我们的半径R。最右边的角有 angle ZS是直角。我们可以计算T = 180° - S - Z = 180° - 90° - Z = 90° - Z

使用三角函数,我们得到F/2 = R * sin(T)。放入公式为T我们给出了F/2 = R*sin(90° - Z). 解决F给我们F = 2*R*sin(90°-Z)

计算G

我们看到下面的三角形:

在此处输入图像描述

顶部有 length F,我们已经知道了它的公式。右边有长度G,我们想找到它的公式。我们不关心底部。最左边的角有角度Z/2。最右边的角有 angle 2*Z。底角有角S,是直角,所以S = 90°。对我来说,红线和绿线完全垂直,所以这S确实是一个直角对我来说并不是很明显,但是你可以通过使用三角形内角的公式来验证这一点,它给了你180° = Z/2 + 2*Z + S. 解决S给我们S = 180° - Z/2 - 2*Z。使用Z = 36°,我们得到S = 180° - 36°/2 - 2* 36° = 90°

使用三角函数,我们得到G = F * sin(Z/2)

计算H

我们看到下面的三角形:

在此处输入图像描述

右边有 length G,我们已经有公式了。底边有 length H,我们想找到一个公式。我们不关心第三方。上角有角度Z,右下角有角度S。从上一节我们已经知道这S是一个直角。

使用三角函数,我们得到H = G * tan(Z)

计算I

这很简单,IA. 我们可以看到,A可以分为A = I + H + E + H + I。我们可以将其简化为A = 2*I + 2*H + E。解决I给我们I = (A - 2*H - E)/2

计算J

同样,这很容易,JF. 我们可以看到,F可以分为F = G + J + G。我们可以将其简化为F = 2*G + J. 解决J给我们J = F - 2*G

编写 Python 程序

我们现在有我们感兴趣的所有行的公式!我们现在可以将这些放入 Python 程序中来绘制图片。

Python 为您提供了用于计算sintan. 它们包含在math模块中。因此,您将添加import math到程序的顶部,然后您可以在程序中使用math.sin(...)math.tan(...)。但是,有一个问题:这些 Python 函数不使用度数来测量角度。相反,他们使用称为“弧度”的不同单位。幸运的是,度数和弧度之间的转换很容易:以度为单位,一个完整的圆是360°. 以弧度表示,一个完整的圆是2*pi,其中pi是一个特殊常数,大约是3.14159265359...。因此,我们可以将以度为单位的角度转换为以弧度为单位的角度,方法是将角度除以360°然后乘以2*pi. 我们可以在 Python 中编写以下辅助函数:

import math

def degree_to_radians(angle_in_degrees):
  full_circle_in_degrees = 360
  full_circle_in_radians = 2 * math.pi

  angle_in_radians = angle_in_degrees / full_circle_in_degrees * full_circle_in_radians

  return angle_in_radians

def sin_from_degrees(angle_in_degrees):
  angle_in_radians = degree_to_radians(angle_in_degrees)
  return math.sin(angle_in_radians)

def tan_from_degrees(angle_in_degrees):
  angle_in_radians = degree_to_radians(angle_in_degrees)
  return math.tan(angle_in_radians)

我们现在可以使用我们的函数sin_from_degreestan_from_degrees计算以sintan为单位的角度。

把它们放在一起:

from turtle import *

import math

# Functions to calculate sin and tan ###########################################

def degree_to_radians(angle_in_degrees):
  full_circle_in_degrees = 360
  full_circle_in_radians = 2 * math.pi

  angle_in_radians = angle_in_degrees / full_circle_in_degrees * full_circle_in_radians

  return angle_in_radians

def sin_from_degrees(angle_in_degrees):
  angle_in_radians = degree_to_radians(angle_in_degrees)
  return math.sin(angle_in_radians)

def tan_from_degrees(angle_in_degrees):
  angle_in_radians = degree_to_radians(angle_in_degrees)
  return math.tan(angle_in_radians)

# Functions to calculate the angles ############################################

def get_X():
  num_corners = 5
  return (num_corners-2)*180 / num_corners

def get_Y():
  return (360 - 2*get_X()) / 2

def get_Z():
  return 180 - 2*get_Y()

# Functions to calculate the lengths ###########################################

def get_A(radius):
  Z = get_Z()
  return 2 * radius * sin_from_degrees(90 - Z/2)

def get_B(radius):
  Z = get_Z()
  return 2 * radius * sin_from_degrees(90 - 3*Z/2)

def get_C(radius):
  Z = get_Z()
  return sin_from_degrees(Z) * get_B(radius)

def get_D(radius):
  Z = get_Z()
  return tan_from_degrees(Z/2) * get_C(radius)

def get_E(radius):
  return 2 * get_D(radius)

def get_F(radius):
  Z = get_Z()
  return 2 * radius * sin_from_degrees(90 - Z)

def get_G(radius):
  Z = get_Z()
  return get_F(radius) * sin_from_degrees(Z/2)

def get_H(radius):
  Z = get_Z()
  return get_G(radius) * tan_from_degrees(Z)

def get_I(radius):
  A = get_A(radius)
  E = get_E(radius)
  H = get_H(radius)
  return (A - E - 2*H) / 2

def get_J(radius):
  F = get_F(radius)
  G = get_G(radius)
  return F - 2*G

# Functions to draw the stars ##################################################

def back_to_center():
  penup()
  goto(0, 0)
  setheading(0)
  pendown()

def draw_small_star(radius):
  penup()
  forward(radius)
  pendown()

  Z = get_Z()

  left(180)
  right(Z/2)

  E = get_E(radius)
  H = get_H(radius)
  I = get_I(radius)

  for i in range(0,5):
    penup()
    forward(I)

    pendown()
    forward(H)

    penup()
    forward(E)

    pendown()
    forward(H)

    penup()
    forward(I)

    left(180)
    right(Z)

  back_to_center()

def draw_green_star(radius):
  pencolor('green')
  draw_small_star(radius)

def draw_blue_star(radius):
  pencolor('blue')

  Z = get_Z()
  left(Z)

  draw_small_star(radius)

def draw_red_star(radius):
  pencolor('red')

  Z = get_Z()

  penup()
  forward(radius)
  pendown()

  left(180)
  right(Z)

  G = get_G(radius)
  J = get_J(radius)

  for i in range(0,10):
    pendown()
    forward(G)

    penup()
    forward(J)

    pendown()
    forward(G)

    left(180)
    right(2*Z)

  back_to_center()

def draw_shape(radius):
  draw_green_star(radius)
  draw_blue_star(radius)
  draw_red_star(radius)

radius = 400
draw_shape(radius)
done()

输出:

在此处输入图像描述

于 2020-05-16T15:41:55.537 回答
2

这是一个不同的解决方案。它基于一个风筝多边形,其中上部是一对 3-4-5 直角三角形,下部是一对 8-15-17 直角三角形:

from turtle import Screen, Turtle

KITES = 10
RADIUS = 100

def kite(t):
    t.right(37)
    t.forward(100)
    t.right(81)
    t.forward(170)

    t.right(124)

    t.forward(170)
    t.right(81)
    t.forward(100)
    t.right(37)

turtle = Turtle()
turtle.penup()
turtle.sety(-RADIUS)

for _ in range(KITES):
    turtle.circle(RADIUS, extent=180/KITES)
    turtle.pendown()

    kite(turtle)

    turtle.penup()
    turtle.circle(RADIUS, extent=180/KITES)

turtle.hideturtle()

screen = Screen()
screen.exitonclick()

在此处输入图像描述

于 2020-05-17T02:33:09.687 回答
1

(是的,我对这个谜题很着迷。)@AnnZen 的解决方案的简洁给我留下了深刻的印象,我决定看看我是否能想出一个更短的解决方案。这个多边形中唯一独特的结构是风筝的侧面:

在此处输入图像描述

所以问题变成了以循环方式绘制其中的十个,然后反转代码以相反的方向再次绘制它们:

from turtle import *

for _ in range(2):
    for _ in range(10):
        fd(105)
        lt(90)
        fd(76.5)
        pu()
        bk(153)
        rt(54)
        pd()

    lt(72)
    lt, rt = rt, lt

done()

在此处输入图像描述

于 2020-05-18T23:45:11.700 回答
1

这是解决方案:

import turtle
#turtle.tracer(0)
a = turtle.Turtle()
for _ in range(10):
    a.forward(100)
    a.right(90)
    a.forward(73)
    a.right(72)
    a.forward(73)
    a.backward(73)
    a.right(108)
    a.forward(73)
    a.right(90)
    a.penup()
    a.forward(100)
    a.pendown()
    a.forward(100)
    a.right(108)
#turtle.update()

结果:

于 2020-05-16T15:20:50.113 回答
1

让我们看一下绘制此形状的另一种方法。我们将从与@f9c69e9781fa194211448473495534 相同的图表开始

在此处输入图像描述

在 OP 的原始图像上使用尺子 (1" = 100px) 和量角器,我们可以用非常简单的代码来近似这个图:

from turtle import Screen, Turtle

turtle = Turtle()
turtle.hideturtle()
turtle.penup()  # center on the screen
turtle.setposition(-170, -125)
turtle.pendown()

for _ in range(10):
    turtle.forward(340)
    turtle.left(126)
    turtle.forward(400)
    turtle.left(126)

screen = Screen()
screen.exitonclick()

这相当于用铅笔绘图,而不是抬起它,也没有在任何线上过度绘制(备份)。

为了使我们想要的形状弹出,我们将上面绘制的两条线分成更细和更粗的部分。第一行分为三段,第二行分为五段:

在此处输入图像描述

为此,我们只需将forward()循环中的调用分成宽段和窄段:

for _ in range(10):
    turtle.width(4)
    turtle.forward(105)
    turtle.width(1)
    turtle.forward(130)
    turtle.width(4)
    turtle.forward(105)

    turtle.left(126)

    turtle.width(1)
    turtle.forward(76.5)
    turtle.width(4)
    turtle.forward(76.5)
    turtle.width(1)
    turtle.forward(94)
    turtle.width(4)
    turtle.forward(76.5)
    turtle.width(1)
    turtle.forward(76.5)

    turtle.left(126)

最后,我们用升降笔代替粗细变化:

在此处输入图像描述

这只是用and替换width()调用的问题:penup()pendown()

for _ in range(10):
    turtle.pendown()
    turtle.forward(105)
    turtle.penup()
    turtle.forward(130)
    turtle.pendown()
    turtle.forward(105)

    turtle.left(126)

    turtle.penup()
    turtle.forward(76.5)
    turtle.pendown()
    turtle.forward(76.5)
    turtle.penup()
    turtle.forward(94)
    turtle.pendown()
    turtle.forward(76.5)
    turtle.penup()
    turtle.forward(76.5)

    turtle.left(126)
于 2020-05-17T08:39:40.517 回答
0

我的短代码:

from turtle import *
for f, t in [(0,-72),(71,108),(71,0)]*10+[(29,90),(73,72),(73,90),(29,72)]*10:fd(f),rt(t)
于 2020-05-19T16:36:12.447 回答