2d rotation gives unexpected results.

2d rotation gives unexpected results.

Postby Zirgon » Tue Jul 23, 2013 12:13 pm

Hello!
This is my first post, nice to meet you all!
I`m biology student from Russia, trying to learn python to perform some simple simulations.

Here`s my first problem.
I`m trying to perform some simple 2d vector rotations in pygame, in order to learn the basics of linear algebra and 2d transformations. So far i understand matrix multiplication pretty well, and probably all my math is right. Eventually i`m planning to write Poly class, and use it to rotate and translate some simple shapes. But when i try and write it in the program, i get very weird results, like all points of rectangle with coordinates [0,0],[0,100],[100,0],[100,100] start to go spiral and eventually shrink to the center instead of rotating right. Although even Excel calculations with this formulas give me right result.
What is wrong with my code?

Code: Select all
import pygame
import math as m

black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)

class Poly():
    pos = [100,100] #x and y coordinates of a point
    rot = m.radians(1) #rotation in degrees
    def draw(self): #draw point
        pygame.draw.circle(screen,white,self.pos,10,0)
    def rotate(self): # rotation method
        sin = m.sin(self.rot) #calculationg sin and cos
        cos = m.cos(self.rot)
        x_rot = int(self.pos[0]*cos-self.pos[1]*sin) #mulpitplicating vector to rotation matrix
        y_rot = int(self.pos[0]*sin+self.pos[1]*cos)

        self.pos[0] = x_rot #set new coordinates to a point
        self.pos[1] = y_rot

a = Poly() #Some simple sample points giving rectangle
b = Poly()
c = Poly()
d = Poly()

b.pos = [0,100]
c.pos = [100,0]
d.pos = [0,0]

pygame.init()
size = [700,500]
screen = pygame.display.set_mode(size)
done = False
clock = pygame.time.Clock()
while done == False:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    a.rotate() #perform rotation
    b.rotate()
    c.rotate()
    d.rotate()

    screen.fill(black)
   
    a.draw() #draw point
    b.draw()
    c.draw()
    d.draw()
    pygame.display.flip()
    clock.tick(30)

pygame.quit()


P.S. I use Python 3.3. Sorry for my english, bit rusty in that department.
Zirgon
 
Posts: 3
Joined: Tue Jul 23, 2013 11:48 am

Re: 2d rotation gives unexpected results.

Postby Zirgon » Tue Jul 23, 2013 2:27 pm

Well, with some help, i did it.
The main problem was with float to integer coordinate conversion in this code:
Code: Select all
        x_rot = int(self.pos[0]*cos-self.pos[1]*sin) #mulpitplicating vector to rotation matrix
        y_rot = int(self.pos[0]*sin+self.pos[1]*cos)

For each cycle we get more and more error with conversion.
Instead, it should be like this:
Code: Select all
        x_rot = self.pos[0]*cos-self.pos[1]*sin #mulpitplicating vector to rotation matrix
        y_rot = self.pos[0]*sin+self.pos[1]*cos

And coordinate conversion should happen when point calls a draw method:
Code: Select all
    def draw(self): #draw point
        pygame.draw.circle(screen,white,[int(self.pos[0]),int(self.pos[1])],10,0)

Hope this helps someone.
Zirgon
 
Posts: 3
Joined: Tue Jul 23, 2013 11:48 am

Re: 2d rotation gives unexpected results.

Postby Mekire » Tue Jul 23, 2013 3:10 pm

Zirgon wrote:Well, with some help, i did it.
The main problem was with float to integer coordinate conversion in this code.

Lol. I was mid-writing this post when you posted saying you solved it. So I'll say this instead.

You should really properly __init__ your Point class. And you should try to resist the urge to use class wide variables that should be instance specific.
Code: Select all
import math,sys
import pygame


class Point(object):
    def __init__(self,x,y):
        self.x,self.y = x,y

    def rotate(self,axis,angle):
        angle = math.radians(angle)
        sin_of_angle = math.sin(angle)
        cos_of_angle = math.cos(angle)
        adjust_x = self.x-axis[0]
        adjust_y = self.y-axis[1]
        x_new = adjust_x*cos_of_angle-adjust_y*sin_of_angle
        y_new = adjust_x*sin_of_angle+adjust_y*cos_of_angle
        self.x = x_new+axis[0]
        self.y = y_new+axis[1]

    def draw(self,surface):
        draw_location = int(self.x),int(self.y)
        pygame.draw.circle(surface,(255,255,255),draw_location,10,0)


class Control(object):
    def __init__(self):
        pygame.init()
        self.size = [700,500]
        self.screen = pygame.display.set_mode(self.size)
        self.screen_rect = self.screen.get_rect()
        self.done = False
        self.clock = pygame.time.Clock()
        self.make_some_points()

    def make_some_points(self):
        rect = pygame.Rect(0,0,100,100)
        rect.center = (200,self.screen_rect.centery)
        self.points = []
        for (x,y) in (rect.topleft,rect.topright,rect.bottomleft,rect.bottomright):
            self.points.append(Point(x,y))

    def event_loop(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.done = True

    def main_loop(self):
        while not self.done:
            self.event_loop()
            self.screen.fill(0)
            for point in self.points:
                point.rotate(self.screen_rect.center,3)
                point.draw(self.screen)
            pygame.display.update()
            self.clock.tick(60)


if __name__ == "__main__":
    run_it = Control()
    run_it.main_loop()
    pygame.quit();sys.exit()

-Mek
User avatar
Mekire
 
Posts: 818
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: 2d rotation gives unexpected results.

Postby Zirgon » Tue Jul 23, 2013 5:11 pm

It`s helpful example of good structured code, thanks!
Zirgon
 
Posts: 3
Joined: Tue Jul 23, 2013 11:48 am


Return to Game Development

Who is online

Users browsing this forum: No registered users and 2 guests