2015-12-15 212 views
1

我想用Python龜圖形畫一個字母「O」。爲了提示「O」的繪圖,用按鍵調用它的功能。以下是我迄今爲止:如何在Python中繪製橢圓圖形而不是蓋印圖形?

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_height & letter_width變量可以由用戶從任何值10-170之間使用另一個按鍵提示的對話框改變。眼下,「O」出來如下圖所示,如果letter_height = 170 & letter_width = 10

O when letter_height = 170 & letter_width = 10

但是,如果你比較這對「H」(另一封信中,可以通過我的程序繪製),你不難看出,他們是不成正比責任:

O next to H

我想要做的就是繪製一個橢圓的「O」,其中它的垂直半徑等於letter_height &它的地平線半徑等於letter_width,使得隨着letter_width增加「O」將變短,並且隨着letter_height增加而變高。問題是,我真的不知道該怎麼做!我聽說你可以蓋一個,但我真的不是想要使用郵票的方法,因爲它的動畫看起來不吸引人。另外,當我嘗試將我的letter_heightletter_width值映射到它時,出於某種原因它會覆蓋整個屏幕!最後,我想知道如何在龜圖形中繪製橢圓,可以像圓圈一樣操作(更改橢圓的半徑長度,更改橢圓的範圍等)。我不要想要使用turtle.stamp()方法,所以有什麼辦法可以繪製一個橢圓而不是在畫布上加蓋一個?任何幫助深表感謝!

+0

你意味着動態操縱?或只是參數化? –

+0

@ Peter Wood那麼,是一個參數化或動態操作的圓? –

+0

我認爲你必須用很多直線來近似它。 –

回答

0

我很肯定這會工作,寬度180/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() 
+0

此代碼不繪製橢圓在x,y;它不會將寬度「寬度」或「高度」拉高。 「width/180」和「height/180」表達式中的180應該更接近60,除了你用'penX + ='而不用'penX +'之外根本不應該存在(同上'penY + =')。這段代碼忽略了龜的當前標題,所以你不能繪製對角橢圓。我試圖自己實現'ellipse()'來解決這些問題。 – cdlane

1

經過測試@ 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() 

(可選)這個方法每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() 

示例輸出

enter image description here

我試圖實現extent一拉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