除了冲压之外,如何在 Python 海龟图形中绘制椭圆? [英] How to draw an ellipse in Python turtle graphics other than stamping?

查看:160
本文介绍了除了冲压之外,如何在 Python 海龟图形中绘制椭圆?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用 Python 海龟图形绘制一个字母O".为了提示O"的绘制,通过按键调用它的函数.这是我目前所拥有的:

def draw_O():# 画一个OPenup()向前(字母高度/4)笔下()转发(字母宽度/2)圆(字母高度/4, 90)向前(字母高度/2)圆(字母高度/4, 90)转发(字母宽度/2)圆(字母高度/4, 90)向前(字母高度/2)圆(字母高度/4, 90)转发(字母宽度/2)Penup()向前(空格宽度 + 字母高度/4)笔下()onkey(draw_O,o")

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

但是,如果将其与H"(我的程序可以绘制的另一个字母)进行比较,您会很容易看出它们之间的比例并不成正比:

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

总而言之,我想知道如何在海龟图形中绘制椭圆可以像圆一样操作(改变椭圆的半径长度,改变椭圆的范围等).我不想使用 turtle.stamp() 方法,所以除了在上面盖上一个椭圆之外,还有什么方法可以绘制一个椭圆画布?非常感谢任何帮助!

解决方案

经过测试@moomoomoo309的椭圆代码并发现问题(打印位置错误,宽度和高度不匹配参数,忽略龟头所以不能打印倾斜省略号、标题不跟踪绘图、不让笔保持原始状态等)我决定尝试自己写.

我选择使用 turtle.circle() 作为相对于现有海龟位置和方向绘制椭圆的位置的模型,允许用户更改步骤(即制作其他不规则多边形),离开笔的状态和它开始的位置,等等.这就是我想出的(我用 self 而不是 turtlepen 因为我打算将它作为方法安装):

导入海龟导入数学定义椭圆(自我,x_radius,y_radius,steps=60):down = self.isdown() # 记录笔状态以便稍后恢复如果没有下来:self.pendown()Heading_radians = math.radians(self.heading())theta_radians = -math.pi/2范围弧度 = 2 * math.pistep_radians = extent_radians/步长extent_radians += theta_radiansx_center, y_start = self.position()y_center = y_start + y_radiuscos_heading, sin_heading = math.cos(heading_radians), math.sin(heading_radians)为真:x, y = x_center + math.cos(theta_radians) * x_radius, y_center + math.sin(theta_radians) * y_radius# 重新调整 x &y 根据乌龟的原始航向设置椭圆的角度x, y = x - x_center, y - y_startx, y = x * cos_heading - y * sin_heading, x * sin_heading + y * cos_headingx, y = x + x_center, y + y_startself.setheading(self.towards(x, y)) # 海龟朝向绘制椭圆的方向self.goto(x, y)如果 theta_radians == extent_radians:休息theta_radians = min(theta_radians + step_radians, extent_radians) # 不要超过我们的起点self.setheading(self.towards(x_center, y_start)) # 为我们绘制的下一个东西设置正确的方向如果没有关闭:# 返回时恢复笔状态self.penup()

(可选)根据

我试图实现 extent 一个 la turtle.circle() 但无法让它在任意范围内正确工作(即以这样的方式)你可以以相同的范围调用 turtle.ellipse() 两次,并让它继续它停止的曲线)所以我把它留到另一天.

将我的答案带回 OP 的原始问题,我们现在可以这样做:

导入海龟导入数学定义椭圆(自我,x_radius,y_radius,steps=60):# ...def draw_O():# 画一个O乌龟.penup()海龟.前进(字母高度/4)乌龟.pendown()椭圆(乌龟,letter_width,letter_height)乌龟.penup()海龟.转发(空间宽度+字母高度/4)乌龟.pendown()信宽 = 10字母高度 = 170空间宽度 = 5乌龟.onkey(draw_O,o")海龟.听()乌龟.完成()

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

I am trying to draw a letter "O" with Python turtle graphics. To cue the drawing of the "O", the function for it is invoked with a key press. Here is what I have so far:

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")

The letter_height & letter_width variables can be changed by the user from any value between 10-170 using a dialog box cued by another key press. Right now, the "O" comes out as shown below if letter_height = 170 & letter_width = 10:

However, if you compare this to the "H" (another letter that can be drawn by my program), you can easily see that they are not in proportion whatsoever:

What I want to do is draw an ellipse for the "O" where its vertical radius is equal to letter_height & its horizontal radius is equal to letter_width such that the "O" will get shorter as letter_width increases, and taller as letter_height increases. The problem is, I don't really know how to do that! I heard that you can stamp one, but I really do not want to use the stamp method since its animation does not look as appealing. Also, when I try to map my letter_height and letter_width values to it, it covers the entire screen for some reason!

In conclusion, I would like to know how to draw an ellipse in turtle graphics that can be manipulated like a circle (change radii lengths of the ellipse, change the ellipse's extent, etc). I don't want to use the turtle.stamp() method, so is there any way to draw an ellipse other than stamping one onto the canvas? Any help is much appreciated!

解决方案

After testing @moomoomoo309's ellipse code and finding problems (prints in wrong place, width and height don't match arguments, ignores turtle heading so can't print slanted ellipses, heading doesn't track drawing, doesn't leave pen in original state, etc.) I decide to try to write my own.

I chose to use turtle.circle() as a model with respect to where the ellipse is drawn relative to the existing turtle position and heading, allowing the user to change the steps (i.e. make other irregular polygons), leave the pen state and position where it started, etc. This is what I came up with (I used self instead of turtle or pen as I intended it to be installed as a method):

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()

(Optionally) add this method to our turtle per Adding a Method to an Existing Object Instance:

from functools import partial

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

Demonstration code to show all the new shapes we can draw with 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

I tried to implement the extent a la turtle.circle() but wasn't able to get it to work for arbitrary extents properly (i.e. in such a way that you could invoke turtle.ellipse() twice with the same extent and have it continue the curve where it left off) so I've left that for another day.

Bringing my answer back to the OP's original problem, we can now do:

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()

To generate the skinny ellipse-based letter O that the OP desired:

这篇关于除了冲压之外,如何在 Python 海龟图形中绘制椭圆?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆