Operacje na wektorach
gringoM
Wektory 2D
Wektor dwuwymiarowy to nic innego, jak przyporządkowana para liczb często z wiadomych przyczyn nazywana "x" i "y".
W C++ WinApi dostępna jest struktura, którą można nazwać namiastką wektora, a nazywa się ona POINT, jednak dla umożliwienia pełnego wykorzystania operacji wektorowych lepiej napisać własną klasę, która mogła by wyglądać następująco:
class dPoint{
public:
double x;
double y;
};
Podstawowe operacje wektorowe
dwa wektory V1 i V2 można dodawać do siebie w następujący sposób otrzymując wektor V3:
V3.x = V1.x + V2.x;
V3.y = V1.y + V2.y;
analogicznie odejmowanie
V3.x = V1.x - V2.x;
V3.x = V1.y - V2.y;
mnożenie wektora przez stałą wartość k nazywa się skalowaniem wektora i pozwala na zmianę jego długości danego wektora przy zachowaniu kąta jego położenia.
V1.x *= k;
V1.y *= k;
Długość wektora oblicza się korzystając ze wzoru Pitagorasa:
L1 = sqrt(V1.x * V1.x + V1.y * V1.y);
Znając długość wektora można go przeskalować tak, aby jego nowa długość wynosiła określoną wartość "a" w następujący sposób
V1.x = V1.x / L1 * a;
V1.y = V1.y / L1 * a;
lub bardziej w stylu C++
V1.x *= a / L1;
V1.y *= a / L1;
Nie trudno domyślić się, że gdy a = 1 to długość wektora przeskalowanego przez 1 / L1 daje wektor o długości równej 1.
Dzielenie przez wartość "a" jest niczym innym jak operacją mnożenia przez wartość 1 / a (odwrotność a), więc nie będę się tu o tym rozpisywał.
Mnożenie wektora przez wektor (to zwykłe, nie skalarne)
V3.x = V1.x * V2.x;
V3.y = V1.y * V2.y;
A więc zwykłe mnożenie wektora przez wektor daje wektor, a skalarne (iloczyn skalarny)
IloczynSkalarny = V1.x * V2.x + V1.y * V2.y; Jak widać daje liczbę
można go obliczyć nieco innaczej
IloczynSkalarny = L1 * L2 * cos alfa; I tu też liczbę daje
gdzie:
L1 - długość wektora V1
L2 - długość wektora V2
alfa - kąt pomiędzy wektorem V1 a V2
No dobra, bo zaraz ktoś napisze "a skąd ja mam wziąć kąt pomiędzy dwoma znanym już wektorami", ano zazwyczaj jest tak, że ten kąt jest komuś potrzebny i można go wyliczyć gdy się chce go poznać, w jaki sposób a w taki:
V1.x * V2.x + V1.y * V2.y = L1 * L2 * cos alfa
V1.x * V2.x + V1.y *V2.y
cos alfa = ------------------------------
L1 * L2
|V1.x * V2.x + V1.y *V2.y|
alfa = acos|------------------------------| to już wyprowadzony wzór na kąt alfa
| L1 * L2 |
Do czego jeszcze przyda się iloczyn skalarny
Do sprawdzenia, czy dwa wektory są prostopadłe, a robi się to tak
jeżeli V1 x V2 == 0 to
"V1 jest prostopadły do V2"
w przeciwnym razie
"V1 nie jest prostopadły do V2"
x - czytaj tutaj jako iloczyn skalarny
Jest jeszcze coś czego nie pisałem, niektórzy mówią na to wyznacznik dwóch wektorów, a liczy się to tak:
|V1.x V1.y|
w(V1,V2) = | | = V1.x * V2.y - V2.x * V1.y
|V2.x V2.y|
w(V1,V2) - należy czytać: wyznacznik wektorów V1 i V2
Zaraz ktoś powie a to na co komu Jeżeli czytaliście uważnie przypowieść o iloczynie skalarnym to wiecie już, że występuje tam wartość cos alfa, no cóż wyznacznik dwóch wektorów jest nieco podobny do iloczynu skalarnego w wersji L1 * L2 * cos alfa, jedyną różnicą jest to, że zamiast cos jest sin a więc
w(V1,V2) = L1 * L2 * sin alfa
gdzie: L1, L2 i alfa już wiecie czym są
Za pomocą wyznacznika można sprawdzić warunek równoległości dwóch wektorów w następujący sposób:
jeżeli w(V1,V2) == 0 to
V1 jest równoległe do V2
w przeciwnym przypadku
V1 nie jest równoległe do V2
No i teraz można powiedzieć, że podstawowe informacje o wektorach nie są nam obce.
A teraz z czym to się je, czyli jak to wykorzystać
Załóżmy, że mam punkt 2D o nazwie p1 i drugi punkt p2. Chcę przesunąć p1 o p2 a więc należy zastosować dodawanie wektorów.
Wygodnie byłoby użyć następującego zapisu w c++: p1 += p2; lub p1 = p1 + p2; ale żeby to zrobić trzeba obsłużyć odpowiednie operatory (w tym przypadku dodawania). Podobnie można, a nawet należy postąpić z odejmowaniem, mnożeniem (ale nie skalarnym) i dzieleniem. Jak się obsługuje operatory w C++ to chyba już temat na inny artykuł, ale znawcą nie jestem więc napiszę przykład dla operatora dodawania:
class dPoint2D{
public:
double x;
double y;
dPoint2D operator +(dPoint2D &dp2d);
};
dPoint2D dPoint2D::operator +(dPoint2D &dp2d){
dPoint2D nowy; Tutaj przydałby się jakiś fajny konstruktor, np. przyjmujący za parametry "x" i "y"
nowy.x = this->x + dp2d.x;
nowy.y = this->y + dp2d.y;
return nowy;
}
z pozostałymi tak samo postępujemy, tylko że inaczej
No dobra a jak zrobić z obliczeniami długości wektora, iloczynu skalarnego i wyznacznika dwóch wektorów Tutaj można zastosować metody, o których istnieniu mam nadzieję wiecie, ale piszę to na wszelki wypadek dla tych co nie wiedzą.
Co jeszcze można zrobić z wektorami A można je obracać (najłatwiej względem środka układu współrzędnych, za który bierzemy x = 0 i y = 0) w następujący sposób:
xt = x;
yt = y;
x = xt * cos(Angle) - yt * sin(Angle);
y = xt * sin(Angle) + yt * cos(Angle);
gdzie: Angle - kąt obrotu w radianach, aby przeliczyć kąt z radianów na stopnie należy: Angle * PI / 180 (PI jest zadeklarowane w pliku math.h trzeba tylko przed jego załączeniem umieścić #define _USE_MATH_DEFINES a nazwa stałej to M_PI.
Obrócenie punktu p1 względem punktu p2 można opisać następująco:
p1 -= p2; Przesunięcie środka układu dla punktu p1 do punktu p2
p1.Rotate(Angle); Tą metodę trzeba napisać w klasie dPoint
p1 += p2; Powrót do "normalnego" układu współrzędnych
I to by było narazie tyle o wektorach.
A może by tak w bloki [code] ująć kod??