Amit Jaiswal Amit Jaiswal - 5 months ago 69
Python Question

How to draw smily (arc) using python turtle

I want to draw a smily using python turtle. Circle extent will be 120.
I am trying following

import turtle
turtle.goto(0, 30)
turtle.down(), 120)

Problem is smile part. How to draw a face smile?


The turtle module does not provide advanced methods to drow arcs of circles or parabolas, however it isn't hard to come up with the right equations.

A circle C with origin at (x0, y0) and radius r is described by the equation:

(x-x0)^2 + (y-y0)^2 = r^2

We can expand this to get:

x^2 -2x·x0 + x0^2 + y^2 -2y·y0 + y0^2 - r^2 = 0

Now we can take for example the y as variable and obtain the second degree equation:

y^2 -2y0·y +(x^2-2x0·x+x0^2+y0^2-r^2) = 0

Let d = x^2-2x0·x+x0^2+y0^2-r^2. We can solve this using the usual formula:

y1 = (2y0 + sqrt(4y0^2 - 4d))/2 = y0 + sqrt(y0^2 - d)
y2 = (2y0 - sqrt(4y0^2 - 4d))/2 = y0 - sqrt(y0^2 - d)

So now you can write down a function that, given the coordinates of the center of the circle and the radius, and the value for x it returns the coordinate y and use these coordinates to move the turtle:

def find_circle_coord(x0, y0, r, x):
    d = x**2 - 2*x0*x + x0**2 + y0**2 - r**2
    D = y0**2 - d
    if D < 0:
        raise ValueError("Value for x is outside the circle!")
    return y0 - D**.5, y0 + D**.5

As in:

>>> # bob is a turtle
>>> bob.pendown()
>>> for x in range(-50, 50):
...     y1, _ = find_circle_coord(0, 0, 100, x)
...     bob.goto(x, y1)

By choosing one of the two coordinates returned you choose whether to draw the "upper" or "lower" arc.

to draw a smile you simply have to come up with two circles one smaller and a larger one but with the center slightly above the previous one so that they have that kind of intersection.

So you have to choose a circle C1 centered in x0, y0 with radius r and a circle C2 centered in x0, y0+K with radius R > r. Note that C2's center is vertically aligned with C1 center (hence the same x coordinate for the center) but it is above it (note: I'm not sure of y-axis orientation so the +K might be -K...)

To find the intersections you have to solve the system of their equations:

(x-x0)^2 + (y-y0)^2-r^2 = 0
(x-x0^2) + (y-y0-K)^2-R^2 = 0

Now subtracting the second equation from the first you get:

(y-y0)^2 - (y-y0-K)^2 -r^2 + R^2 = 0
y^2 -2y·y0 +y0^2 - y^2 -y0^2 -K^2 +2y·y0 +2K·y -2K·y0 -r^2 + R^2 = 0
-K^2 +2K·y -2K·y0 -r^2 + R^2 = 0

Where you get:

y = (K^2 +2K·y0 +r^2 -R^2)/(2K)

And you can substitute the y in one of the circle equations to obtain the xs corresponding to such y. Then you know which x to draw using find_circle_coord.

If you want to make the mouth more open you could use a circle and a parabola. To find the y value of a point on a parabole it's easy:

def find_parabola_coord(a, b, c, x):
    return a*x**2 + b*x + c

Or you could use the form of equation of a parabola given its vertex V = (xv, yv):

y - yv = a(x - xv)^2

where a controls how steep the parabola is.