如何在Python turtle graphics中绘制椭圆而不是冲压?

jfgube3f  于 2023-11-20  发布在  Python
关注(0)|答案(2)|浏览(111)

我试图用Python turtle图形绘制一个字母“O”。为了提示“O”的绘制,它的函数是用按键调用的。下面是我到目前为止所做的:

def draw_O():
# Draw an O

penup()
forward(letter_height/4)
pendown()
forward(letter_width/2)
circle(letter_height/4, 90)
forward(letter_height/2)
circle(letter_height/4, 90)
forward(letter_width/2)
circle(letter_height/4, 90)
forward(letter_height/2)
circle(letter_height/4, 90)
forward(letter_width/2)
penup()
forward(space_width + letter_height/4)
pendown()

onkey(draw_O, "o")

字符串
letter_heightletter_width变量可以由用户使用另一个按键提示的对话框从10-170之间的任何值进行更改。现在,如果letter_height = 170letter_width = 10,则“O”出现如下所示:
x1c 0d1x的数据
然而,如果你把它和“H”(我的程序可以画出的另一个字母)比较,你可以很容易地看到它们并不成比例:



我想做的是为“O”画一个椭圆,它的垂直半径等于letter_height,水平半径等于letter_width,这样“O”会随着letter_width的增加而变短,随着letter_height的增加而变高。问题是,我真的不知道怎么做!我听说你可以戳一个,但我真的做 * 不想使用戳方法,因为它的动画看起来不那么吸引人。而且,当我试图Map我的letter_heightletter_width值到它,它覆盖了整个屏幕出于某种原因!
最后,我想知道如何在turtle graphics中绘制一个椭圆**,它可以像圆一样操作**(改变椭圆的半径长度,改变椭圆的范围等)。我 * 不想**使用turtle.stamp()方法,所以除了在画布上冲压一个椭圆之外,还有什么方法可以绘制一个椭圆吗?任何帮助都非常感谢!

piok6c0g

piok6c0g1#

在测试@moomoomoo309的椭圆代码并发现问题(打印在错误的地方,宽度和高度不匹配参数,忽略海龟标题,所以不能打印倾斜的椭圆,标题不跟踪绘图,不离开笔在原始状态,等等)后,我决定尝试写我自己的。
我选择使用turtle.circle()作为相对于现有海龟位置和航向绘制椭圆的模型,允许用户更改步骤(即,制作其他不规则多边形),离开笔的状态和位置,这就是我的想法(我使用self而不是turtlepen,因为我打算将其作为一种方法安装):

import turtle
import math

def ellipse(self, x_radius, y_radius, steps=60):

    down = self.isdown()  # record pen state for restoration later

    if not down:
        self.pendown()

    heading_radians = math.radians(self.heading())
    theta_radians = -math.pi / 2
    extent_radians = 2 * math.pi
    step_radians = extent_radians / steps
    extent_radians += theta_radians
    x_center, y_start = self.position()
    y_center = y_start + y_radius

    cos_heading, sin_heading = math.cos(heading_radians), math.sin(heading_radians)

    while True:
        x, y = x_center + math.cos(theta_radians) * x_radius, y_center + math.sin(theta_radians) * y_radius
        # readjust x & y to set the angle of the ellipse based on the original heading of the turtle
        x, y = x - x_center, y - y_start
        x, y = x * cos_heading - y * sin_heading, x * sin_heading + y * cos_heading
        x, y = x + x_center, y + y_start

        self.setheading(self.towards(x, y))  # turtle faces direction in which ellipse is drawn
        self.goto(x, y)

        if theta_radians == extent_radians:
            break

        theta_radians = min(theta_radians + step_radians, extent_radians)  # don't overshoot our starting point

    self.setheading(self.towards(x_center, y_start))  # set correct heading for the next thing we draw

    if not down:  # restore pen state on return
        self.penup()

字符串
(可选)将此方法添加到我们的turtle per Adding a Method to an Existing Object Instance

from functools import partial

yertle = turtle.Turtle()
yertle.ellipse = partial(ellipse, yertle)


演示代码显示我们可以用turtle.ellipse()绘制的所有新形状:

if __name__ == "__main__":

    from functools import partial

    yertle = turtle.Turtle()
    yertle.ellipse = partial(ellipse, yertle)

    import random

    yertle.speed("fastest")
    yertle.hideturtle()
    yertle.penup()

    screen = turtle.Screen()

    for _ in range(75):

        radius = random.randint(10, 50)

        yertle.setheading(random.randint(0, 360))
        yertle.setx(random.randint(-screen.window_width()//2 + radius * 2, screen.window_width()//2 - radius * 2))
        yertle.sety(random.randint(-screen.window_height()//2 + radius + 2, screen.window_height()//2 - radius * 2))
        yertle.color((random.random(), random.random(), random.random()), (random.random(), random.random(), random.random()))

        flag = random.choice([True, False, False])

        if flag:
            yertle.begin_fill()

        yertle.ellipse(radius, radius / 0.5 + random.random() * 3, steps=random.choice([3, 4, 5, 6, 7, 8, 60, 60, 60]))

        if flag:
            yertle.end_fill()

    screen.exitonclick()

示例输出

x1c 0d1x的数据
我试着用turtle.circle()来实现extent,但是不能让它在任意范围内正常工作(也就是说,你可以用相同的范围调用turtle.ellipse()两次,让它继续它停止的曲线),所以我把它留到另一天。
把我的答案带回到OP的原始问题,我们现在可以做:

import turtle
import math

def ellipse(self, x_radius, y_radius, steps=60):

    # ...

def draw_O():
    # Draw an O

    turtle.penup()
    turtle.forward(letter_height/4)
    turtle.pendown()

    ellipse(turtle, letter_width, letter_height)

    turtle.penup()
    turtle.forward(space_width + letter_height/4)
    turtle.pendown()

letter_width = 10
letter_height = 170

space_width = 5

turtle.onkey(draw_O, "o")

turtle.listen()
turtle.done()


要生成OP所需的基于椭圆的瘦字母O:


tzdcorbm

tzdcorbm2#

我敢肯定这将工作,180在宽度/180和高度/180可能关闭虽然。

from math import sin,cos,pi
def ellipse(pen, x, y, width, height):
    pen.penup()
    pen.goto(x + width / 2, height)
    pen.pendown()
    penX, penY = pen.pos()
    for i in range(0, 360):
        penX += cos(i*pi/180)*width/180
        penY += sin(i*pi/180)*height/180
        pen.goto(penX, penY)
    pen.penup()

字符串

相关问题