Я новичок в python и графике, но заранее запрограммировал. Согласно http://en.wikipedia.org/wiki/Transformation_matrix#Rotation,
Для поворота на угол θ против часовой стрелки относительно начала координат, функциональной формой является 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)
Чтобы повернуть в обратном направлении, измените ang
на -ang
. Я подозреваю, что у вас неправильный знак в матрице вращения, но я никогда не помню. (EDIT: Это эквивалентно изменению знака терминов 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;
}
}
Pygame использует систему координат, где [0,0] - верхний левый угол. Ваше вращение будет отлично работать в системе координат, где чем выше точка, тем выше координата y, но pygame - наоборот: чем ниже точка, тем выше координата y. Это делает все "перевернутым", и поэтому угол, который ваш объект будет поворачивать, будет находиться напротив угла, которым вы его вращали. Вероятно, самый простой способ исправить это - просто ввести противоположный угол, который вы хотите повернуть.
О переводе, вращении и переводе снова, вам действительно нужно это сделать. Однако, если вы вычислите матрицу преобразования для каждого шага один раз и умножьте их вместе, чтобы получить одну матрицу преобразования, которая включает в себя два преобразования при вращении, вам нужно только умножить каждую вершину на одну матрицу. Чтобы включить перевод в матричные преобразования, вам нужно использовать "однородные координаты" - см. Далее статью wiki. В основном вы используете координаты (x, y, 1) вместо (x, y), а затем используете матрицу 3x3. Дополнительные числа позволяют преобразовать.
Измените знаки на синусоидальных терминах, например:
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])
Посмотрите, поможет ли это.