简体   繁体   中英

Python turtle concentric circles

我确实被一个任务困扰:用户输入半径r,然后乌龟绘制圆,然后继续绘制另一个具有相同中心但小10像素的圆,直到半径为0

First let us approximate a circle as a regular polygon with 36 sides/segments. To draw this shape given a radius r we need to know;

  1. The length of each segment
  2. The angle to turn between each segment

To calculate the length, we first need the circumference, which is 2πr (we will approximate pi as 3.1415), giving us

circumference = 2 * 3.1415 * radius

Next we divide this by the number of segments we are approximating, giving

circumference = 2 * 3.1415 * radius
seg_lenght = circumferece/36

Now we need the angle difference between the segments, or the external angle. This is simply 360/n for a regular n-gon(polygon with n sides), so we do 360/36 = 10

We can now define a function to generate the segment length and draw the circle:

def circle_around_point(radius):
    circumference = 2 * 3.1415 * radius 
    seg_length = circumference/36

    penup()         
    fd(radius)   #Move from the centre to the circumference
    right(90)    #Face ready to start drawing the circle
    pendown()

    for i in range(36): #Draw each segment
        fd(seg_length)
        right(10)

    penup()
    right(90)    #Face towards the centre of the circle
    fd(radius)   #Go back to the centre of the circle
    right(180)   #Restore original rotation
    pendown()

Now for the concentric circles:

def concentric_circles(radius):
    while radius > 0:
        circle_around_point(radius)
        radius -= 10

It's not clear why @IbraheemRodrigues felt the need to recode turtle's circle() function based on your problem description, but we can simplify his solution by not reinventing the wheel:

def circle_around_point(turtle, radius):
    is_down = turtle.isdown()

    if is_down:
        turtle.penup()
    turtle.forward(radius)  # move from the center to the circumference
    turtle.left(90)  # face ready to start drawing the circle
    turtle.pendown()

    turtle.circle(radius)

    turtle.penup()
    turtle.right(90)  # face awary from the center of the circle
    turtle.backward(radius)  # go back to the center of the circle

    if is_down:
        turtle.pendown()  # restore original pen state

def concentric_circles(turtle, radius):
    for r in range(radius, 0, -10):
        circle_around_point(turtle, r)

The key to circle() is that the current position is on the edge of the circle so you need to shift your position by the radius to make a specific point the center of the circle.

However, to solve this problem, I might switch from drawing to stamping and do it this way to speed it up and simplify the code:

import turtle

STAMP_SIZE = 20

radius = int(input("Please input a radius: "))

turtle.shape('circle')
turtle.fillcolor('white')

for r in range(radius, 0, -10):
    turtle.shapesize(r * 2 / STAMP_SIZE)
    turtle.stamp()

turtle.mainloop()

However, this draws crude circles as it's blowing up a small one:

在此处输入图片说明

To fix that, I might compromise between the two solutions above and do:

import turtle

radius = int(input("Please input a radius: "))

turtle.penup()
turtle.forward(radius)
turtle.left(90)
turtle.pendown()

turtle.begin_poly()
turtle.circle(radius)
turtle.penup()
turtle.end_poly()

turtle.addshape('round', turtle.get_poly())  # 'circle' is already taken

turtle.right(90)
turtle.backward(radius)

turtle.shape('round')
turtle.fillcolor('white')

for r in range(radius - 10, 0, -10):
    turtle.shapesize(r / radius)
    turtle.stamp()

turtle.mainloop()

This improves circle quality by shrinking a large one instead of enlarging a small one:

在此处输入图片说明

Where quality of the circle can be controlled using the steps= argument to the call to circle() .

But, if I really wanted to minimize code while keeping quality high and speed fast, I might do:

import turtle

radius = int(input("Please input a radius: "))

for diameter in range(radius * 2, 0, -20):
    turtle.dot(diameter, 'black')
    turtle.dot(diameter - 2, 'white')

turtle.hideturtle()

turtle.mainloop()

The dot() method draws from the center instead of the edge, uses diameters instead of radii, draws only filled circles, and seems our best solution to this particular exercise:

在此处输入图片说明

import turtle

####     #####   #### Below class draws concentric circles. 

class Circle:

    def __init__(self, pen, cx, cy, radius):
        self.pen = pen
        self.cx = cx
        self.cy = cy
        self.radius = radius

    def drawCircle(self):
        self.pen.up()
        self.pen.setposition( self.cx, self.cy - self.radius )
        self.pen.down()
        self.pen.circle(self.radius)

    def drawConCircle(self, minRadius = 10, delta = 10):
        if( self.radius > minRadius ) :
            self.drawCircle()
            self.radius -= delta  # reduce radius of next circle
            self.drawConCircle()
 ####    End class circle #######

win = turtle.Screen()
win.bgcolor("white")
s = Circle( turtle.Turtle(), 0, 0, 200 )
s.drawConCircle()
win.exitonclick() 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM