2010-08-16 131 views
1

我是新來的python和圖形,但之前已編程。據http://en.wikipedia.org/wiki/Transformation_matrix#Rotation順時針方向旋轉2d形狀

對於由θ 逆時針繞原點的角度旋轉時, 函數形式爲x '=xcosθ - ysinθ 和y'=xsinθ+ycosθ

但下面python代碼以順時針方向旋轉它。有人可以解釋這一點嗎?還將矩形轉換爲原點並返回到中心似乎是開銷。有什麼辦法可以避免這種情況?提前致謝。

PS:我已經看過pygame.transform.rotate這是做什麼的,但我想從頭開始,以便更好地瞭解圖形。有沒有辦法從python解釋器中看到這種方法的來源?

import pygame, sys, time 
from math import * 
from pygame.locals import * 
co_ordinates =((200,200),(400,200),(400,300),(200,300)) 

window_surface = pygame.display.set_mode((500,500),0,32) 
BLACK=(0,0,0) 
GREEN=(0,255,0) 
RED=(255,0,0) 
window_surface.fill(BLACK) 
ang=radians(30) 
"""orig=pygame.draw.polygon(window_surface,GREEN,co_ordinates) 
n_co_ordinates = tuple([(((x[0])*cos(ang)-(x[1])*sin(ang)),((x[0])*sin(ang)+(x[1])*cos(ang))) for x in n_co_ordinates]) 
n_co_ordinates = tuple([((x[0]+300),(x[1]+250)) for x in n_co_ordinates]) 
print(n_co_ordinates) 
pygame.draw.polygon(window_surface,RED,n_co_ordinates)""" 


pygame.display.update() 
while True: 
    for event in pygame.event.get(): 
     if event.type == QUIT: 
      pygame.quit() 
      sys.exit() 
    for i in range(360): 
     ang=radians(i) 
     if i>=360: 
      i=0 
     n_co_ordinates = tuple([((x[0]-300),(x[1]-250)) for x in co_ordinates]) 
     n_co_ordinates = tuple([((x[0]*cos(ang)-x[1]*sin(ang)),(x[0]*sin(ang)+x[1]*cos(ang))) for x in n_co_ordinates]) 
     n_co_ordinates = tuple([((x[0]+300),(x[1]+250)) for x in n_co_ordinates]) 
     window_surface.fill(BLACK) 
     pygame.draw.polygon(window_surface,RED,n_co_ordinates) 
     pygame.display.update() 
     time.sleep(0.02) 

回答

1

要反方向旋轉ang改爲-ang。我懷疑你在旋轉矩陣中有一個錯誤的標誌,但我永遠不會記得。 (編輯:這相當於更改sin條款的符號,因爲sin(-x)==-sin(x)cos(-x)==cos(x)。)

您無法避免將翻譯轉到中心位置。原因是您的轉換修復了原點(0,0)(因爲0*cos(...)==0),所以您始終圍繞原點旋轉。因此,要在其他地方旋轉,您必須首先將該點轉換爲原點。

這是rotate的來源,transform.c位於pygame源文件中。它寫在C.

static void 
rotate (SDL_Surface *src, SDL_Surface *dst, Uint32 bgcolor, double sangle, 
     double cangle) 
{ 
    int x, y, dx, dy; 

    Uint8 *srcpix = (Uint8*) src->pixels; 
    Uint8 *dstrow = (Uint8*) dst->pixels; 
    int srcpitch = src->pitch; 
    int dstpitch = dst->pitch; 

    int cy = dst->h/2; 
    int xd = ((src->w - dst->w) << 15); 
    int yd = ((src->h - dst->h) << 15); 

    int isin = (int)(sangle * 65536); 
    int icos = (int)(cangle * 65536); 

    int ax = ((dst->w) << 15) - (int)(cangle * ((dst->w - 1) << 15)); 
    int ay = ((dst->h) << 15) - (int)(sangle * ((dst->w - 1) << 15)); 

    int xmaxval = ((src->w) << 16) - 1; 
    int ymaxval = ((src->h) << 16) - 1; 

    switch (src->format->BytesPerPixel) 
    { 
    case 1: 
     for (y = 0; y < dst->h; y++) 
     { 
      Uint8 *dstpos = (Uint8*)dstrow; 
      dx = (ax + (isin * (cy - y))) + xd; 
      dy = (ay - (icos * (cy - y))) + yd; 
      for (x = 0; x < dst->w; x++) 
      { 
       if(dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval) 
        *dstpos++ = bgcolor; 
       else 
        *dstpos++ = *(Uint8*) 
         (srcpix + ((dy >> 16) * srcpitch) + (dx >> 16)); 
       dx += icos; 
       dy += isin; 
      } 
      dstrow += dstpitch; 
     } 
     break; 
    case 2: 
     for (y = 0; y < dst->h; y++) 
     { 
      Uint16 *dstpos = (Uint16*)dstrow; 
      dx = (ax + (isin * (cy - y))) + xd; 
      dy = (ay - (icos * (cy - y))) + yd; 
      for (x = 0; x < dst->w; x++) 
      { 
       if (dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval) 
        *dstpos++ = bgcolor; 
       else 
        *dstpos++ = *(Uint16*) 
         (srcpix + ((dy >> 16) * srcpitch) + (dx >> 16 << 1)); 
       dx += icos; 
       dy += isin; 
      } 
      dstrow += dstpitch; 
     } 
     break; 
    case 4: 
     for (y = 0; y < dst->h; y++) 
     { 
      Uint32 *dstpos = (Uint32*)dstrow; 
      dx = (ax + (isin * (cy - y))) + xd; 
      dy = (ay - (icos * (cy - y))) + yd; 
      for (x = 0; x < dst->w; x++) 
      { 
       if (dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval) 
        *dstpos++ = bgcolor; 
       else 
        *dstpos++ = *(Uint32*) 
         (srcpix + ((dy >> 16) * srcpitch) + (dx >> 16 << 2)); 
       dx += icos; 
       dy += isin; 
      } 
      dstrow += dstpitch; 
     } 
     break; 
    default: /*case 3:*/ 
     for (y = 0; y < dst->h; y++) 
     { 
      Uint8 *dstpos = (Uint8*)dstrow; 
      dx = (ax + (isin * (cy - y))) + xd; 
      dy = (ay - (icos * (cy - y))) + yd; 
      for (x = 0; x < dst->w; x++) 
      { 
       if (dx < 0 || dy < 0 || dx > xmaxval || dy > ymaxval) 
       { 
        dstpos[0] = ((Uint8*) &bgcolor)[0]; 
        dstpos[1] = ((Uint8*) &bgcolor)[1]; 
        dstpos[2] = ((Uint8*) &bgcolor)[2]; 
        dstpos += 3; 
       } 
       else 
       { 
        Uint8* srcpos = (Uint8*) 
         (srcpix + ((dy >> 16) * srcpitch) + ((dx >> 16) * 3)); 
        dstpos[0] = srcpos[0]; 
        dstpos[1] = srcpos[1]; 
        dstpos[2] = srcpos[2]; 
        dstpos += 3; 
       } 
       dx += icos; dy += isin; 
      } 
      dstrow += dstpitch; 
     } 
     break; 
    } 
} 
+0

非常感謝。否定角度的作品,但不應該沒有這樣做符合維基?的工作。 – pyguy12 2010-08-16 13:34:05

+0

呵呵。是的,我認爲它應該按照你的方式逆時針旋轉。非常奇怪。 – katrielalex 2010-08-16 14:23:05

+0

嗯..它可能是維基中的錯誤? – pyguy12 2010-08-16 14:46:36

0

變化的正弦項的標誌,就像這樣:

n_co_ordinates = tuple([(((x[0])*cos(ang)+(x[1])*sin(ang)),((-x[0])*sin(ang)+(x[1])*cos(ang))) for x in n_co_ordinates]) 

看看是否有幫助。

1

關於翻譯它,再次旋轉和翻譯,你實際上必須這樣做。但是,如果您爲每個步驟計算一次變換矩陣並將它們相乘以得到一個包含旋轉的兩個變換的變換矩陣,那麼您只需要將每個頂點乘以一個矩陣。要在矩陣轉換中包含翻譯,您需要使用「同質座標」 - 請參閱wiki文章的更深層次部分。基本上你使用座標(x,y,1)而不是(x,y),然後使用3x3矩陣。額外的數字允許轉換。

+0

+1爲齊次座標。 – katrielalex 2010-08-16 13:29:57

+0

謝謝,我會研究這一點。 – pyguy12 2010-08-16 13:34:58

+0

這看起來像是一個更難消化的概念:-)。一直看http://www.teamten.com/lawrence/graphics/homogeneous/有一段時間瞭解這一點。 – pyguy12 2010-08-16 14:44:01

2

Pygame使用座標系,其中[0,0]是左上角。你的旋轉在座標系中工作得很好,點越高,y座標越高,但pygame則相反:點越低,y座標越高。這使得一切都「翻轉」,所以你的物體看起來旋轉的角度將與你旋轉它的角度相反。解決這個問題的最簡單方法可能就是輸入與你想旋轉的角度相反的角度。