вращение 2-й формы по часовой стрелке - PullRequest
1 голос
/ 16 августа 2010

Я новичок в питоне и графике, но программировал раньше. По 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)

Ответы [ 4 ]

2 голосов
/ 30 мая 2016

Pygame использует систему координат, где [0,0] - верхний левый угол. Ваше вращение будет работать нормально в системе координат, где чем выше точка, тем выше координата y, но pygame противоположна: чем ниже точка, тем выше координата y Это делает все «перевернутым», и поэтому угол поворота вашего объекта будет противоположен углу поворота. Вероятно, самый простой способ исправить это - просто ввести противоположный угол поворота, который вы хотите повернуть.

1 голос
/ 16 августа 2010

Чтобы повернуть в обратном направлении, измените ang на -ang.Я подозреваю, что вы ошиблись знаком в матрице вращения, но я никогда не смогу вспомнить.(РЕДАКТИРОВАТЬ: Это эквивалентно изменению знака условий sin, потому что sin(-x)==-sin(x) и cos(-x)==cos(x).)

Вы не можете избежать перевода в центр.Причина в том, что ваше преобразование фиксирует источник (0,0) (начиная с 0*cos(...)==0), поэтому вы всегда вращаетесь вокруг источника.Таким образом, чтобы повернуть куда-либо еще, вы должны сначала перевести эту точку в начало координат.

Вот источник rotate из transform.c в источнике пигмеев.Это написано в 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;
    }
}
1 голос
/ 16 августа 2010

О переводе, вращении и повторном переводе вы фактически должны это сделать.Однако если вы вычисляете матрицу преобразования для каждого шага один раз и умножаете их вместе, чтобы получить одну матрицу преобразования, которая включает в себя два преобразования и вращение, то вам нужно только умножить каждую вершину на одну матрицу.Чтобы включить перевод в матричные преобразования, вам нужно использовать «однородные координаты» - см. Далее в статье вики.В основном вы используете координаты (x, y, 1) вместо (x, y), а затем используете матрицу 3x3.Дополнительные числа позволяют для преобразования.

0 голосов
/ 16 августа 2010

Измените знаки синусоидальных терминов, например:

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]) 

Посмотрите, поможет ли это.

...