0

I am creating an application which rotates a few points around a center point. The aim is to connect each point using eg. lines/arcs and have the points/(subsequent drawing) rotate around the center point.

I am trying to accomplish this by a method which rotates each point by a given amount each time the method is called, then distributing each point n times around the center point using a for loop.

(For future use I will also need some tkinter widgets running along side the code eg. entries to get user-input.)

My current code simply draws a circle for each point, instead of connecting them. There are a couple of things I dont currently understand:

  1. My code runs fine for a short while, then closes with Error: maximum recursion depth exceeded. - Is it bad to clear canvas by .delete ?

  2. The value of the .after function doesn't seem to have any effect at all hence using time.sleep.

(I have also used a while True: loop to run the code in an earlier version, but I read that it is bad practice to run an infinite loop inside the GUI event loop. And I edited it because of flickering)

Would it be better to structure my code differently? Sorry for any mis-terminology and the messy and long post/code, I am a new non-english python student.

class Create_gear:

    def __init__(self, location, ox, oy, rpm, n):
        self.location = location
        self.ox = ox
        self.oy = oy
        self.rpm = rpm
        self.n = n
        self.rotation_from_normal = 0

    #Rotates point px1, py1 by value of "rpm" each time method is called.
    def draw_rotating_gear(self, px1, py1, px2, py2, r):
        self.rotation_from_normal = self.rotation_from_normal +self.rpm
        self.location.delete("all")

        #rotates point px1, py1 n times around to form a circle. 
        for i in range (0, self.n):
            angle = (math.radians(self.rotation_from_normal + 360/self.n *i) )

            qx = ( self.ox + math.cos(angle) * (px1 - self.ox) - math.sin(angle) * (py1 - self.oy) )
            qy = ( self.oy + math.sin(angle) * (px1 - self.ox) + math.cos(angle) * (py1 - self.oy) )

            x0 = qx - r
            y0 = qy - r
            x1 = qx + r
            y1 = qy + r
            self.location.create_oval(x0, y0, x1, y1, fill = "black")
        self.location.update()
        time.sleep(0.01)
        self.location.after(1000000000, self.draw_rotating_gear(480, 200, 500, 300, 5))
3
  • In general, you probably shouldn't use recursive functions in Python because of the exact situation you've run into. See stackoverflow.com/questions/4278327/… Commented May 8, 2019 at 21:31
  • 1
    I wouldn't say that at all--there's nothing wrong with recursion when you need it, for example, to traverse a recursive data structure. But the code above will fail in every language--Python has nothing to do with it. Commented May 8, 2019 at 21:34
  • The cause of the problem is this statement: self.location.after(1000000000, self.draw_rotating_gear(480, 200, 500, 300, 5)). Change it to self.location.after(1000000000, self.draw_rotating_gear, 480, 200, 500, 300, 5) will fix it. However, calling the function with fixed parameters every time seems a design issue and how come the delay time 1000000000 is so large. Commented May 9, 2019 at 0:54

2 Answers 2

1

Nothing in the description of your problem indicates the need for recursion at all, and the way you implement it in your code will always fail. You have a call to draw_rotating_gear() at the end of the function draw_rotating_gear() with no conditional for stopping the recursion, so it will go infinitely deep on the first call. Reorganize it to use a simple loop.

Sign up to request clarification or add additional context in comments.

Comments

1

You didn't provide enough code for a working example solution but I believe the problem is you're invoking the .after() method with incorrect arguments. The first argument needs to be an integer, the number of milliseconds before the call, not a floating point value. The second argument needs to be a function to call after that delay, not a call to a function which is what you did. Fixing these, and simplifying your example slightly, I'd expect something like:

def draw_rotating_gear(self, px1, py1, r):
    self.rotation_from_normal = self.rotation_from_normal + self.rpm
    self.location.delete("all")

    # rotates point px1, py1 n times around to form a circle.
    for i in range(0, self.n):
        angle = (math.radians(self.rotation_from_normal + 360/self.n * i))

        qx = (self.ox + math.cos(angle) * (px1 - self.ox) - math.sin(angle) * (py1 - self.oy))
        qy = (self.oy + math.sin(angle) * (px1 - self.ox) + math.cos(angle) * (py1 - self.oy))

        x0 = qx - r
        y0 = qy - r
        x1 = qx + r
        y1 = qy + r
        self.location.create_oval(x0, y0, x1, y1, fill="black")

    self.location.update()
    self.location.after(100, lambda px1=qx, py1=qy, r=r: self.draw_rotating_gear(px1, py1, r))

(I may be passing the wrong variables to the lambda call as I don't have enough code context to work with.) The recursion error you got was due to your incorrect second argument to .after(), i.e. a false recursion due to a programming error.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.