I am just learning to code using the book "Think Python" and I'm so confused. The problem I ran into was in creating the flowers in TurtleWorld. The functions I am creating are not consistent in their requirements. First let me post the finished product, that actually works:
from swampy.TurtleWorld import*
world=TurtleWorld()
bob=Turtle()
print bob
bob.delay=.001
def polyline(t,n,length,angle):
t=Turtle
print t
for i in range(n):
fd(bob,length)
lt(bob,angle)
def arc(t, r, angle):
t=Turtle
arc_length=2*math.pi*r*angle/360
n=int(arc_length/3)+1
step_length=arc_length/n
step_angle=float(angle)/n
polyline(t,n,step_length,step_angle)
def petal(t,r,angle):
for i in range(2):
arc(t,r,angle)
lt(t,180-angle)
def flower(t, n, r, angle):
t=Turtle
for i in range(n):
petal(bob,r,angle)
lt(bob,360/n)
flower(bob,5,77,99)
wait_for_user
On the function definition of arc and petal, t suffices for turtle, though when I began, using t in the definitions of flower and polyline returned an error unbound method(fd and lt). turtle instance required, got type instance instead.
The t=Turtle and print turtle added to half the function definitions were added after the fact to try and fix this error. This is the working version, I just want to know why it didn't work before. I'm not even sure why this worked, as I mainly put bob in as t out of frustration, I didn't actually expect it to work.
Although I use Python's supplied turtle library below, instead of swampy.TurtleWorld, I don't think it makes a difference with respect to the issue you're having. You seem to have a basic misunderstanding of formal parameters in function calls and the distinction between function calls and method invocations. Consider this sequence of events:
flower(bob,5,77,99)
def flower(t, n, r, angle):
t=Turtle
...
Here a perfectly good turtle, bob, gets passed in as the turtle argument t only to be immediately replaced with something else. Or consider polyline which has a turtle argument t but instead the global bob gets used when a turtle is required. Here's how I picture your program should come together:
from turtle import Turtle, Screen
from math import pi
def polyline(turtle, n, length, angle):
for _ in range(n):
turtle.fd(length)
turtle.lt(angle)
def arc(turtle, radius, angle):
arc_length = 2 * pi * radius * angle / 360
n = int(arc_length / 3) + 1
step_length = arc_length / n
step_angle = float(angle) / n
polyline(turtle, n, step_length, step_angle)
def petal(turtle, radius, angle):
for _ in range(2):
arc(turtle, radius, angle)
turtle.lt(180 - angle)
def flower(turtle, n, radius, angle):
for _ in range(n):
petal(turtle, radius, angle)
turtle.lt(360 / n)
screen = Screen()
bob = Turtle()
flower(bob, 5, 77, 99)
screen.exitonclick()
OUTPUT
Related
Link to the Exercises can be accessed here - Case Study: Interface Design, Exercise Section 4.3
Quoting the question, it seems I have to implement an arc() function:
Make a more general version of circle called arc that takes an additional parameter angle, which determines what fraction of a circle to draw. angle is in units of degrees, so when angle=360, arc should draw a complete circle.
The code I've written so far:
import turtle
import math
bob = turtle.Turtle()
def polygon(t, n, length):
for i in range(n):
t.fd(length)
t.lt(360/n)
def circle(t, r):
circumference = 2 * math.pi * r
n = int(circumference/3) + 1
length = circumference/n
polygon(t, n, length)
def arc(t, r, angle):
arc_length = 2 * math.pi * r * (angle/360)
n = (arc_length/4) + 1
arc(bob, 1000, 45)
turtle.mainloop()
I'm intending to call the circle() function within arc() just as polygon() was called within circle(), but I'm confused on how I should do that. Apart from that, the arc() function does not draw anything, rather just shows me a stationary Turtle.
I believe that the Turtle object bob isn't receiving any of the movement instructions assigned within polygon(). Thus all that it's doing is displaying the Turtle object!
I could be wrong, and this where I need clarification. Should I call circle() within arc() as well as make the Turtle object move? Are there easier alternatives? Calling functions within a function is still confusing for me, so more resources to learn about them would be great as well!
import turtle
bob=turtle.Turtle()
import math
def arc(t,radius,angle):
circumference = 2.0*math.pi*radius
frac = angle/360.0
arclength = circumference*frac
n = 50 # pick a number
len = arclength/n;
turnang = angle/n
for i in range(n):
t.fd(len)
t.lt(turnang)
arc(bob, 130,360)
turtle.done()
I'm trying to ... call the circle() function
within arc() just as polygon() was called within circle()
You've got this backward. The problem states:
Make a more general version of circle called arc
Just as you could draw a circle with the more general function polygon(), you should be able to draw a circle with the more general function arc(). Here's a skeletal program for thinking about this:
from turtle import Screen, Turtle
from math import pi
def polygon(turtle, sides, length):
outside_angle = 360 / sides
for _ in range(sides):
turtle.forward(length)
turtle.left(outside_angle)
def circle_using_polygon(turtle, radius):
circumference = 2 * pi * radius
sides = min(60, int(circumference / 3))
length = circumference / sides
polygon(turtle, sides, length)
def arc(turtle, radius, angle):
# implement arc not by calling *circle() nor by
# calling polygon() but rather by borrowing code
# from both and adding one more step to reduce
# the number of sides based on the arc angle
def circle_using_arc(turtle, radius):
arc(turtle, radius, 360)
bob = Turtle(visible=False)
# Draw overlapping circles three different ways:
bob.color("green")
circle_using_polygon(bob, 100)
for color in ['cyan', 'magenta', 'yellow', 'black']:
bob.color(color)
arc(bob, 100, 90)
bob.color("blue")
circle_using_arc(bob, 100)
screen = Screen()
screen.mainloop()
import tkinter
import swampy
from swampy.TurtleWorld import *
def polygon(n, t, length, angle):
print(t)
k= angle/360
for i in range(0,int(n*k)):
fd(t, length)
p= 360
lt(t,p/n)
t.delay
world = TurtleWorld()
bob = Turtle()
#def circle(r):
#l1= 2*3.14*r
#l= l1/60
#polygon(30, bob, l)
polygon(60, bob, 10, 180)
I have a homework to draw a spiral(from inside to outside) in python with turtle, but I cant think of a way to do that, beside what I did its need to be like this:
I tried to do it like that, but its not working properly.
import turtle
turtle.shape ('turtle')
d = 20 #Distance
a = 1 #StartingAngle
x = 200 #Num of loops
for i in range (x):
turtle.left(a)
turtle.forward(d)
a = a + 5
You are increasing the wrong variable in your loop.
A spiral is like a "circunference whose radius increases over time".
You should increase the d variable over time, and not the angle a. The amount of the increase of each loop will be essential to determine the appearance of your spiral, but you can obtain a good value for the increase with some calculation or by trial and error.
import turtle
from math import sin,cos,pi
t=turtle.Turtle()
t.speed(0)
n=50 #number of spirals
d=10 #distance between 2 spirals
r=0 #radius
x,y = 0, 0
cur_r = r
for i in range(n):
for a in range(1,360, 4):
r = cur_r + d*a/360.0
a *= pi/180.0
y = r*sin(a)
x = r*cos(a)
turtle.goto(x,y)
cur_r += d
import turtle
i=0
while i<4:
turtle.speed(0)
turtle.pensize(1+i)
turtle.forward(1+i)
t.color("blue")
turtle.bgcolor("pink")
t.lt(3)
i+=0.003
If you are using program other than IDLE(such as pycharm), add
turtle.mainloop()
at the end of the code
import turtle as t
for i in range(360):
t.circle(i,20)
Source: Explained here
import turtle
bob = turtle.Turtle()
def polygon(t,length,n):
for i in range(n):
t.fd(length)
t.lt(360/n)
print(t)
polygon(bob,30,15)
turtle.mainloop()
How can I make a circle by calling polygon function?
You already have written the correct code to produce a circle. In the view of turtle's own circle() method, a circle is just a polygon with 60 sides (fewer if the circle is small.) I.e. it's about perception and how many sides do you need before you can't tell the difference.
import turtle
def polygon(t, length, n):
for _ in range(n):
t.fd(length)
t.lt(360 / n)
bob = turtle.Turtle()
bob.penup()
bob.sety(-270)
bob.pendown()
polygon(bob, 30, 60)
turtle.mainloop()
Your problem now is to control the drawing of the polygon/circle to produce it with a specific radius. Your length parameter doesn't map to a radius as the circle is coming out way too large. Here length represents 1/60 (1/n) of the circumference and we know that:
circumference = 2 * math.pi * radius
We can calculate, in our circle(t, radius) function, what length needs to be given radius (i.e. circumference/n), and call polygon(t, length, n) with these parameters. Here's a visual comparison drawing a radius 100 circle with turtle's circle() method (red) and drawing it with the solution I just described (blue):
import turtle
bob=turtle.Turtle()
bob.color('green', 'cyan')
bob.begin_fill()
def polygon(t,length, n):
for i in range(n):
bob.forward(length)
bob.left(360/n)
import math
def circle(t, r):
circum= 2*math.pi*r
n= int(circum/10)+1
length= circum/n
polygon(t,length, n)
circle(bob, 100)
bob.end_fill()
turtle.done()
I'm trying to create a hexagonal array of spheres around a center sphere in the XY plane using a python loop function (couldn't figure out how to do it using duplicate special). It should end up looking something like this:
0 0
0 0 0
0 0
Here's my code. I' getting a syntax error
# Error: line 1: invalid syntax #
when I call it, though I'm pretty sure there's nothing wrong with line one.
import maya.cmds as cmds
class Sphere(radius, tx=0, ty=0, tz=0, sx=0, sy=0, sz=0):
self.diameter = 2*radius
def createSphere(radius, tx, ty):
newSphere = Sphere(radius=radius, tx=tx, ty=ty)
return newSphere
def duplicateSphere(wholeSphere):
for i in range(6, 1, -1):
createSphere(tx=wholeSphere.diameter*math.cos(2*math.pi/i), ty=wholeSphere.diameter*math.sin(2*math.pi/i))
# create spheres with projections onto x and y axes as translation params
duplicateSphere(createSphere(1.03))
Any ideas as to what's going on?
Ok, first off to answer your question, the SyntaxError is caused by improper class instantiation. class declaration must be separated from the constructor method in python, like so:
class Sphere(object):
def __init__(self, radius, tx=0, ty=0, tz=0, sx=0, sy=0, sz=0):
self.diameter = 2 * radius
Tip: In the maya script editor panel, if you enable History->Show Stack Trace it will give you a better idea of where the actual error is occurring.
However, there are a couple other issues at play. For one, you are never storing the parameters you pass into the sphere class (except radius, which you are storing implicitly by storing the diameter). You probably wanted:
class Sphere(object):
def __init__(self, radius, tx=0, ty=0, tz=0, sx=1, sy=1, sz=1):
self.radius = radius
self.tx = tx
self.ty = ty
self.tz = tz
self.sx = sx
self.sy = sy
self.sz = sz
self.diameter = 2 * radius
I changed the scale defaults to 1 instead of 0 so that the default sphere is not invisibly small.
Also, as theodox pointed out, you have a TypeError in your createSphere method, which takes 3 params (none of them are keyword arguments currently and therefore not optional) and you are only passing in 1.
However, the main issue is that currently you are not actually creating any spheres in maya. If the intention is that your sphere object is an object-oriented wrapper around maya.cmds, you will need it to call cmds.sphere somewhere, and you will probably want to cmds.move() and cmds.scale() it to by your t* and s* values. If you do all this in the constructor, you could actually then avoid setting instance variables for all the sphere properties if you wanted.
This would look something like this:
cmds.sphere(radius=self.radius)
cmds.move(self.tx,self.ty,self.tz)
cmds.scale(self.sx,self.sy,self.sz)
Finally, I think your trig is a bit off (you want each iteration to vary by exactly 60° or π/3 radians). To get the proper angles, I think you want something more along the lines of:
import math
for i in range(6,0,-1):
angle = math.pi * i / 3.0
distance = wholeSphere.diameter
tx = distance * math.cos(angle)
ty = distance * math.sin(angle)
# ...
As a last note, consider looking at an object-oriented solution like pymel to avoid needing to reinvent the wheel in terms of wrapping maya.cmds commands in objects.
Anyways, applying all these corrections produces something like:
import maya.cmds as cmds
import math
class Sphere(object):
def __init__(self, radius, tx=0, ty=0, tz=0, sx=1, sy=1, sz=1):
self.diameter = 2*radius
self.radius = radius
self.tx = tx
self.ty = ty
self.tz = tz
self.sx = sx
self.sy = sy
self.sz = sz
cmds.sphere(radius=self.radius)
cmds.move(self.tx,self.ty,self.tz)
cmds.scale(self.sx,self.sy,self.sz)
def createSphere(radius, tx=0, ty=0):
newSphere = Sphere(radius, tx=tx, ty=ty)
return newSphere
def duplicateSphere(wholeSphere):
for i in range(6, 0, -1):
angle = math.pi * i / 3.0
distance = wholeSphere.diameter
tx = distance * math.cos(angle)
ty = distance * math.sin(angle)
createSphere(wholeSphere.radius, tx=tx, ty=ty)
duplicateSphere(createSphere(1.03))
I have a logic error for this function. I need to write a function called spikes() that draw
lines radiating from a common starting point. It takes three parameters, which are
numLines for number of lines to draw, lengthIncr for the length of the first line and
increase in length of the successive lines, and angle that goes clockwise and it is the angle between successive lines. I use the latest version of Python (3.4.2). Also, the function spides must repeatedly call the function drawLine(). I think the error is the call function for drawLine in the function spikes, but I don't know how to fix it. The output I get is a very long curve line that goes downward forever. The real output I should get is spikes. Here is the code:
#Question 14 Part a-
import turtle
s = turtle.Screen()
t = turtle.Turtle()
def drawLine(t, length):
t.pendown()
t.forward(length)
t.penup()
length = 50
drawLine(t, length)
#Question 14 Part b-
def spikes(numLines, lengthIncr, angle):
for i in range(numLines):
drawLine(t, lengthIncr * i)
t.right(angle)
print(spikes(36, 25, 5))
#Output I should get: '''
I'm not an expert on turtle, but is this what you're looking for?
import turtle
s = turtle.Screen()
t = turtle.Turtle()
def drawLine(t, length):
t.pendown()
t.forward(length)
t.penup()
def there_and_back(t, length):
drawLine(t, length)
t.penup()
t.right(180)
t.forward(length)
t.right(180)
t.pendown()
length = 50
#Question 14 Part b-
def spikes(numLines, lengthIncr, angle):
for i in range(numLines):
length = lengthIncr * i
there_and_back(t, length)
t.right(angle)
print(spikes(36, 25, 5))