Obrót wokół punktu a przesunięcie

Odpowiedz Nowy wątek
2012-03-07 19:01
0

Cześć!

Mam prostokąt.
Chcę go obrócić o dany kąt wokół jednego z rogów.
Niestety, mam tylko możliwość obrotu wokół środka prostokąta.
Pomyślałem, że mogę go obrócić wokół środka a następnie przesunąć w odpowiednie miejsce aby uzyskać pożądany efekt.
Niestety matematyka nie jest moją mocną stroną i nie potrafię tego przesunięcia wyliczyć.
"pomożecie?" :)

pozdrawiam

Pozostało 580 znaków

2012-03-07 19:32
0

Tutaj masz: http://www.euclideanspace.com[...]/affine/aroundPoint/index.htm


"(...) otherwise, the behavior is undefined".

Pozostało 580 znaków

2012-03-22 12:23
2

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;
}
edytowany 3x, ostatnio: adf88, 2012-03-22 12:28
Profesjonalne rozwiązanie :>. Chociaż autorowi raczej nie potrzeba takich dział wytaczać. - msm 2012-03-22 17:12
Specjalnie podałem rozwiązanie ogólne. W ten sposób bardzo łatwo można "policzyć" dowolne inne transformacje afiniczne, pokazuję zasadę. Natomiast jeśli chodzi wyłącznie o obracanie prostokąta to można sobie wszystko "uprościć" do szczególnego przypadku. Tak czy siak od przemnożenia sobie macierzy trzeba zacząć zwłaszcza jeśli matma kuleje - sposób z macierzami jest prosty i uniwersalny. - adf88 2012-03-22 19:01
Bardzo fajnie, że chciało ci się to pisać :) - merlinnot 2012-03-23 22:10

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0