首页 文章

如何在除了冲压之外的Python龟图形中绘制椭圆?

提问于
浏览
1

我试图用Python龟图形绘制一个字母“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")

用户可以使用另一个按键提示的对话框,在10-170之间的任何值更改 letter_heightletter_width 变量 . 现在,如果 letter_height = 170letter_width = 10 ,"O"如下所示:

O when letter_height = 170 & letter_width = 10

但是,如果将其与“H”(我的程序可以绘制的另一个字母)进行比较,您可以很容易地看出它们不是按比例分配的:

O next to H

我想要做的是为"O"绘制一个椭圆,其垂直半径等于 letter_height ,其水平半径等于 letter_width ,这样"O"会随着 letter_width 的增加而变短,而随着 letter_height 的增加会更高 . 问题是,我真的不知道该怎么做!我听说你可以盖章,但我真的想要使用stamp方法,因为它的动画看起来并不吸引人 . 此外,当我尝试将 letter_heightletter_width 值映射到它时,由于某种原因它覆盖了整个屏幕!

总之,我想知道如何在乌龟图形中绘制一个椭圆 that can be manipulated like a circle (改变椭圆的半径长度,改变椭圆的范围等) . 我 don't want 使用 turtle.stamp() 方法,所以有没有办法绘制一个椭圆而不是在画布上加一个椭圆?任何帮助深表感谢!

2 回答

  • 2

    在测试@ moomoomoo309的椭圆代码并发现问题(打印错误的地方,宽度和高度与参数不匹配,忽略龟头,因此无法打印倾斜的椭圆, Headers 不跟踪绘图,不会使笔处于原始状态等我决定尝试自己写 .

    我选择使用 turtle.circle() 作为相对于现有龟位置和 Headers 绘制椭圆的位置的模型,允许用户更改步骤(即制作其他不规则多边形),保留笔状态和开始位置,这就是我提出的(我使用了 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()
    

    (可选)根据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()
    

    EXAMPLE OUTPUT

    enter image description here

    我试图实现 extent a la turtle.circle() 但是无法使其适当地在任意范围内工作(即以这样的方式,你可以以相同的范围调用 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:

    enter image description here

  • 0

    我很确定这会起作用,但宽度为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()
    

相关问题