Użyj macierzy. Mnożenie dwóch macierzy 3x3 to prosta matematyka.
Macierz obrotu wokół punktu (0, 0) o kąt α
R(α)=
[ -sin(α) cos(α) 0 ]
[ cos(α) sin(α) 0 ]
[ 0 0 1 ]
Macierz przesunięcia o wektor (x, y):
T(x,y)=
[ 1 0 x ]
[ 0 1 y ]
[ 0 0 1 ]
Obrót wokół punktu (x,y) o kąt α można rozłożyć na 3 operacje:
- przesunięcie o wektor (-x, -y) (wtedy punkt (x,y) "staje się" punktem (0,0) )
- obrót o α wokół (0, 0)
- przesunięcie o wektor (x, y) (wtedy punkt (x,y) z powrotem wraca na miejsce)
Zatem macierz takiego przekształcenia to (z prawej strony mnożenia dajemy transformacje "wcześniejsze", z lewej "późniejsze")
Q(x, y, α) = T(x, y) * R(α) * T(-x, -y)
Aby przekształcić punkt (px, py) o macierz T trzeba pomnożyć macierz T przez macierz postaci:
[ px ]
[ py ]
[ 1 ]
W wyniku dostaniesz macierz
[ qx ]
[ qy ]
[ 1 ]
gdzie qx
i qy
to współrzędne punktu przetransformowanego.
Jeśli chodzi o implementację to ostatniego wiersza macierzy nie trzeba zapamiętywać (zawsze 0, 0, 1), ale trzeba to uwzględnić w algorytmie. Tak samo nie trzeba zapamiętywać tej dodatkowej jedynki przy punkcie.
#include <cmath>
#include <iostream>
using namespace std;
struct Punkt {
double x;
double y;
};
struct Transformacja {
double m[2][3];
double *operator [] (int wiersz) { return this->m[wiersz]; }
const double *operator [] (int wiersz) const { return this->m[wiersz]; }
friend Transformacja operator * (const Transformacja &a, const Transformacja &b);
static Transformacja Translacja(double tx, double ty)
{
Transformacja wynik = { {
{ 1, 0, tx },
{ 0, 1, ty }
} };
return wynik;
}
static Transformacja Rotacja(double kat)
{
Transformacja wynik = { {
{ -sin(kat), cos(kat), 0 },
{ cos(kat), sin(kat), 0 }
} };
return wynik;
}
static Transformacja Rotacja(double kat, double cx, double cy)
{
return Translacja(cx, cy) * Rotacja(kat) * Translacja(-cx, -cy);
}
};
/* kombinacja dwóch transformacji */
Transformacja operator * (const Transformacja &a, const Transformacja &b)
{
Transformacja wynik = { { {
a[0][0] * b[0][0] + a[0][1] * b[1][0],
a[0][0] * b[0][1] + a[0][1] * b[1][1],
a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2]
}, {
a[1][0] * b[0][0] + a[1][1] * b[1][0],
a[1][0] * b[0][1] + a[1][1] * b[1][1],
a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2]
} } };
return wynik;
}
/* zastosuj transformacje na punkcie */
Punkt operator * (const Transformacja &t, const Punkt &p)
{
Punkt wynik = {
t[0][0] * p.x + t[0][1] * p.y + t[0][2],
t[1][0] * p.x + t[1][1] * p.y + t[1][2]
};
return wynik;
}
int main()
{
Punkt p = { 1, 1 };
Punkt q = Transformacja::Rotacja(0.5 * 3.14159265358979323846, 2, 2) * p; // obrót punktu 'p' o 90 stopni w lewo wokół punktu 2,2
cout << q.x << " " << q.y << endl;
}