Macierze jako przekształcenia i krzywe Béziera¶
Wyświetlanie wektorów: vector_shower.py¶
Zanim zaczniemy przekształcać kształty, musimy umieć je wyświetlić.
Do tego posłuży nam biblioteka vector_shower.py (i towarzyszący jej program w C++).
Archiwum z biblioteką, potrzebnym do niej programem i jego kodem źródłowym możesz
pobrać stąd.
Ważne
Rozpakuj pobranego zipa do tego samego folderu, w którym będziesz pisać programy na dzisiejszych zajęciach. W folderze z programami z dzisiejszych zajęć będą potrzebne:
folder
vector_showerrospakowany z zipa,plik
matrices.pyz implementacją klasy macierzy.
Biblioteka ta posiada dwie główne funkcje:
show_vector(vec, color)— rysuje pojedynczy wektor (punkt) na ekranie.show_vector_cloud(vectors, color)— koloruje piksele tła zależnie od tego, jakie wektory znajdują się na obszarze ekranu pod tym pikselem. „Chmura” jest opisana za pomocą listy wektorów.Tych funkcji możesz używać zarówno ze skryptu, jak i z trybu interaktywnego.
Kolejne wywołania będą rysować na tym samym obrazku; zamnkięcie okna spowoduje, że kolejne polecenia rysowania będą zaczynać od czystego obrazka.

Informacja
Biblioteka vector_shower odczytuje współrzędne z wektorów na dowolny z poniższych sposobów -
wystarczy, żeby tylko jeden z nich był dostępny w klasie wektorów:
x=v.x, y=v.yx=v[0], y=v[1]- dzięki temu można używać list jako wektorów.x=[0, 0], y=[1, 0]x=v.get(0,0), y=v.get(1,0)- z tego będziemy korzystać.
Po uruchomieniu okna z wizualizacją możesz z nim wchodzić w interakcję:
Strzałki — przesuwanie widoku.
Klawisze + / - — przybliżanie i oddalanie (zoom); przybliżanie powoduje, że pojedynczy piksel tła pokrywa coraz mniejszy obszar na ekranie, dlatego „chmury” wektorów tworzące spójny kształt przy większym oddaleniu, po przybliżeniu zaczną mieć widoczne dziury.
W parametrze color możesz podawać nazwy kolorów (np. "red", "blue") lub ich kody HTML
(np. "#ff0000" dla czerwonego, "#123456" dla ciemnego niebieskiego).
Macierze jako wektory¶
Dzisiaj zamiast korzystać z klasy Vector2D tego, będziemy używać klasy do macierzy o wymiarach
\(2 \times 1\).
Dzięki temu będziemy mogli łatwo opisywać przekształcenia liniowe tych wektorów jako \(v' = Mv\).
Pomocna będzie też funkcja tworzenia, dodawania i mnożenia macierzy-wektorów:
def vec2d(x, y):
v = Matrix(2, 1)
v.set(0, 0, x)
v.set(1, 0, y)
return v
def vmul(a, v):
return vec2d(a * v.get(0, 0), a * v.get(1, 0))
def vadd(v1, v2):
return vec2d(v1.get(0, 0) + v2.get(0, 0), v1.get(1, 0) + v2.get(1, 0))
Budowanie kształtów z wektorów¶
Poniższy przykładowy kod wyświetla kwadrat z narożnikami:
from vector_shower import show_vector, show_vector_cloud
from matrices import Matrix
def vec2d(x, y):
m = Matrix(2, 1)
m.set(0, 0, x)
m.set(1, 0, y)
return m
def vmul(a, v):
return vec2d(a * v.get(0, 0), a * v.get(1, 0))
def vadd(v1, v2):
return vec2d(v1.get(0, 0) + v2.get(0, 0), v1.get(1, 0) + v2.get(1, 0))
unit_square = []
x = 0
while x <= 1:
y = 0
while y <= 1:
unit_square.append(vec2d(x, y))
y += 0.01
x += 0.01
show_vector_cloud(unit_square, "#f00")
show_vector(vec2d(0,0))
show_vector(vec2d(1,0))
show_vector(vec2d(0,1))
show_vector(vec2d(1,1))
shift = vec2d(0.6, 0)
i = 0
while i < len(unit_square):
unit_square[i] = vadd(shift, unit_square[i])
i += 1
show_vector_cloud(unit_square, "#0f0")
shift = vec2d(-0.3, 0.6)
i = 0
while i < len(unit_square):
unit_square[i] = vadd(shift, unit_square[i])
i += 1
show_vector_cloud(unit_square, "#00f")

Mnożenie macierzy¶
Aby pomnożyć dwie macierze \(A\) i \(B\), element w \(i\)-tym wierszu i \(j\)-tej kolumnie macierzy wynikowej \(C\) obliczamy jako sumę iloczynów elementów z \(i\)-tego wiersza macierzy \(A\) i \(j\)-tej kolumny macierzy \(B\):
Przykład:
Przekształcanie wektorów¶
Macierz obrotu o kąt \(\alpha\) (w kierunku przeciwnym do ruchu wskazówek zegara) ma postać:
Składanie przekształceń¶
To zadanie przypomina, że składanie przekształceń nie jest przemienne - ważna jest kolejność.
Tak życiowo możemy to zilustrować następująco - obracanie działa jak zegar (zawsze przeciwnie do ruchu jego wskazówek), ale kiedy patrzymy na zegar w lustrze (odbiciu), to wskazówki ruszają się w złą stronę. Tak więc obrót następujący po odbiciu symetrycznym obraca w inną stronę, niż normalnie.
Krzywe Béziera i algorytm De Casteljau¶
Algorytm De Casteljau pozwala wyznaczyć punkt na krzywej dla parametru \(t \in [0, 1]\) poprzez wielokrotne wyznaczanie punktów pośrednich na odcinkach — podobnie do rysowania odcinka, ale obliczanie pojedynczego punktu jest bardziej skomplikowane:
Masz listę punktów kontrolnych \([P_0, P_1, \dots, P_n]\).
Jeśli na liście jest tylko jeden punkt, to jest on wynikiem.
Jeśli jest więcej punktów, utwórz nową listę o jeden krótszą: \(Q_i = (1-t)P_i + tP_{i+1}\).
Powtórz algorytm dla nowej listy punktów.