[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Rotation question



On 6/19/06, Kamilche <klachemin@xxxxxxxxxxx> wrote:
Andre Roberge wrote:
> Ok, here's a quick stab at it...

I couldn't get that to work. Maybe it's something else.
If you have a moment, this code rotates a box on the screen and shows
what point I'm interested in tracking. Can you see what I'm doing wrong?

[snip]
I'd rather be lazy.... Here's something I wrote a while ago when I was
thinking of writing a pygame tutorial that could be of interest (to
you and others).  I strongly suspect it will take care of what you
want (and more).  Let me know if I'm wrong, and I'll have another look
at your code.

André
===========
# test_new_image.py
# Author: Andre Roberge
# You are free to use this code as you see fit.

import sys
import pygame
from pygame.locals import *
from toolbox import new_image, rotate_about
import math

pygame.init()
screen = pygame.display.set_mode((500, 300))
pygame.display.set_caption("Testing rotating image")

red = 255, 0, 0
blue = 0, 0, 255
black = 0, 0, 0
white = 255, 255, 255
green = 0, 255, 0
yellow = 255, 255, 0

deg2rad = math.pi/180
angle = 0
surf_c = pygame.Surface((64, 64))
pygame.draw.circle(surf_c, red, (32, 32), 32, 1)
pygame.draw.arc(surf_c, blue, (0, 0, 64, 64), 0, 90*deg2rad, 31)


surf_ref = pygame.Surface((64, 64)) pygame.draw.rect(surf_ref, white, (0, 0, 64, 64), 1) surf_ref.set_colorkey(black)

surf_tr = pygame.Surface((64, 64))
pygame.draw.rect(surf_tr, red, (0, 0, 64, 64), 1)
surf_tr.set_colorkey(black)

surf_tl = pygame.Surface((64, 64))
pygame.draw.rect(surf_tl, blue, (0, 0, 64, 64), 1)
surf_tl.set_colorkey(black)

surf_bl = pygame.Surface((64, 64))
pygame.draw.rect(surf_bl, green, (0, 0, 64, 64), 1)
surf_bl.set_colorkey(black)

surf_br = pygame.Surface((64, 64))
pygame.draw.rect(surf_br, yellow, (0, 0, 64, 64), 1)
surf_br.set_colorkey(black)

surf_arbitrary = pygame.Surface((64, 64))
f_p = (15, 15)
pygame.draw.rect(surf_arbitrary, white, (1, 1, 63, 32))
pygame.draw.circle(surf_arbitrary, red, (15, 15), 2)
surf_arbitrary.set_colorkey(black)

while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
          sys.exit()
   screen.fill(black)
   s_c, position = rotate_about(surf_c, angle)
   x = position[0]
   y = position[1]
   screen.blit(s_c, (x+100, y+100))

   s_tr, position = rotate_about(surf_tr, angle, fixed_point="top_right")
   x = position[0]
   y = position[1]
   screen.blit(s_tr, (x+100, y+100))

   s_tl, position = rotate_about(surf_tl, angle, fixed_point="top_left")
   x = position[0]
   y = position[1]
   screen.blit(s_tl, (x+100, y+100))

   s_bl, position = rotate_about(surf_bl, angle, fixed_point="bottom_left")
   x = position[0]
   y = position[1]
   screen.blit(s_bl, (x+100, y+100))

   s_br, position = rotate_about(surf_br, angle, fixed_point="bottom_right")
   x = position[0]
   y = position[1]
   screen.blit(s_br, (x+100, y+100))

   s_arb, position = rotate_about(surf_arbitrary, angle, fixed_point=f_p)
   x = position[0]
   y = position[1]
   screen.blit(s_arb, (x+300, y+100))

   screen.blit(surf_ref, (100, 100))

   pygame.display.flip()

   angle += 1

======================
# toolbox.py
# Author: Andre Roberge
# You are free to use this code as you see fit.

import os
import pygame
from pygame.locals import *
import math

def new_image(filename, path=None, convert=True, key_pixel=None):
   ''' new_image() loads an image from a file, with the option of setting
       a given colour as being transparent.
       arguments:
           filename: name of the file containing the source image
       optional arguments:
           path: relative path (from the program to the image location)
           convert: set to None (or False) if you do not want the resulting
                    pygame Surface to have its pixel format converted.
           key_pixel: tuple of the form (x, y) specifying the
                      pixel location of a transparent colour
       returns:
           a tuple: pygame Surface object, pygame rect object
   '''
   if path:
       filename = os.path.join(path, filename)
   image = pygame.image.load(filename)
   if convert:
       image.convert()
   if key_pixel:
       colorkey = image.get_at(key_pixel)
       image.set_colorkey(colorkey, RLEACCEL)
   return image, image.get_rect()

def rotate_about(surf, angle, fixed_point="center"):
   ''' rotate_about() rotates a surface counterclockwise, about a fixed point.
       arguments:
           surf: pygame Surface object
           angle: rotation angle, expressed in degrees
       optional arguments:
           fixed_point: "center" (default value), "top_left", "top_right",
                        "bottom_left", "bottom_right"
       returns:
           a tuple: pygame Surface object, position tuple
           The position tuple is to be used as an argument in a blit operation.
           For example:
               rotated, position = rotate_about(surf, angle)
               screen.blit(rotated, position)
           will rotate the Surface "surf" about its center.
   '''
   rotated_surf = pygame.transform.rotate(surf, angle)
   # To maintain a fixed point, we need to make use of geometric and
   # trigonometric transformations, which are too complicated to
   # explain here in details
   w, h = surf.get_size()
   x = w/2
   y = h/2
   # trigonometric values with angle conversion
   deg2rad = math.pi/180
   rad_angle = angle*deg2rad
   cos = math.cos(rad_angle)
   sin = math.sin(rad_angle)
   # rotation of coordinates
   X1 = x*cos + y*sin
   Y1 = -x*sin + y*cos
   X2 = x*cos - y*sin
   Y2 = x*sin + y*cos

   X = max(abs(X1), abs(X2)) # 2*X, 2*Y == rotated_surf.get_size() !!
   Y = max(abs(Y1), abs(Y2))

   if fixed_point=="center":
       blit_shift = (int(x-X), int(y-Y))
   elif fixed_point =="top_left":
       blit_shift = (int(X1-X), int(Y1-Y))
   elif fixed_point =="top_right":
       blit_shift = (int(-X2+2*x-X), int(Y2-Y))
   elif fixed_point =="bottom_left":
       blit_shift = (int(X2-X), int(-Y2+2*y-Y))
   elif fixed_point =="bottom_right":
       blit_shift = (int(-X1+2*x-X), int(-Y1+2*y-Y))
   else:
       try:
           xx, yy = fixed_point
           xx -= x
           yy -= y
           X1 = xx*cos + yy*sin
           Y1 = -xx*sin + yy*cos
           blit_shift = (int(xx-X1-X), int(yy-Y1-Y))
           return rotated_surf, blit_shift
       except:
           return rotated_surf, (0, 0)

   return rotated_surf, blit_shift