Detta skapar en PDF som du sedan kan skriva ut. Du kan även spara ner PDFn och skriva ut senare.
Titel på utskriften?
Tack för ditt bidrag
Om vi kan använda det så lägger vi upp det på sidan. Nedan en länk till ditt bidrag om du vill spara det.
Spara som ...
Du sparar ditt skript under detta namn och kan sedan hämta tillbaka det med samma namn.
Läs in
Läs in ett tidigare sparat skript. Obs att du enbart kan läsa in skript i den webbläsare där du sparade skriptet. Vill du kunna läsa in och spara skript oberoende av webbläsare, så behöver du skaffa ett login (enkelt och gratis).
Skicka in bidrag
Föreslå rubrik
Beskriv vad din kod gör
Skapa kort länk
Använd en kort URL för att skicka länk till koden via SMS eller epost. När mottagaren klickar på länken, så öppnas denna webbsida, med din kod och din text. Länken rensas bort automatiskt om den inte används.
Rubrik (frivilligt)
Beskrivning (frivilligt)
Länk (kopiera hela)
Rotation i 2D
Låt oss multiplicera lite matriser så att grejer börjar rotera.
rotationsmatris
Säger vi rotera en punkt eller rotera en vektor? Rent matematiskt roterar vi förstås vektor men vektorn i sin tur representerar i detta fall en punkt. Det är ju i slutändan punkten vi jobbar med.
Om vi tänker oss en geometrisk figur så består den av punkter mellan vilka vi drar linjer. Om vi flyttar punkterna, så flyttar vi figuren. Om vi flyttar punkterna, så att vi roterar dem alla runt origo, då kommer vår figur rotera runt origo. Vår punkt hamnar dock i ekvationerna som en radvektor och det är ju, om man ska vara petnoga, en vektor från origo till punkten ifråga. Men vi använder den som en punkt och spänner upp linjer mellan punkterna - inte längs vektorerna.
rotera en punkt runt origo
Vi kan enkelt rotera en vektor, som representerar en punkt, runt origo (0,0) genom att skapa en rotationsmatris1 i vilken vi stoppar in vinkeln vi vill rotera allting med. När vi skapat denna rotationsmatris, då tar vi denna matris och multiplicerar med vår punkt, beskriven som en radvektor. Ut kommer en ny punkt, som roterat så många grader, runt origo, som vi angav i vår roationsmatris.
1 Hur skapar vi den då? Det enkla svaret är att det finns en rotationsmatris för 2D och 3 stycken för 3D och det är bara att lära sig! Om du inte nöjer dig med det svaret, såhär kan du t.ex. härleda rotationsmatrisen för 2D.
Visa lösning
Det är alltså så vi får fram denna rotationsmatris:
Vi stoppar helt enkelt in önskad vinkel och rotationsmatrisen vi får, den multiplicerar vi med punkten vi vill rotera. Ut kommer punkten roterad. Genom att göra detta med en scens alla punkter, så roteras hela scenen.
exempel
I detta enkla inledande exempel ska vi bara rotera en enda punkt. Vi kan t.ex. välja punkten (x,y) = (1,0). Om vi tänker oss enhetscirkeln, så tänker vi oss att vi roterar punkten 90 grader. Var hamnar vi då? Vi borde ha flyttat punkten från (1,0) till (0,1). Eller hur?
Vi knappar ner lite pythonkod för detta. Den svåra biten, matrismultiplikation, den är ju redan avklarad. Så vi skapar en rotationsmatris och sedan multiplicerar vi den med en punkt, t.ex. (1,0) för att se om 90 grader rotation flyttar den till (0,1).
import math
class Matrix:
def __init__(self, I=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
def __str__(self):
s = str(self.h)+'x'+str(self.w)+"\n"
for i in range(self.h):
for j in range(self.w):
s = s + "{:>6}".format(round(self.I[i][j],1))
s = s + "\n"
return(s)
def __matmul__(self,B):
C = [[0]*B.w for i in range(self.h)]
for i in range(B.w):
for j in range(self.h):
for s in range(B.h):
C[j][i]+= self.I[j][s] * B.I[s][i]
return(Matrix(C))
def rotationsmatris2D(alfa):
R = [
[math.cos(alfa), -math.sin(alfa)],
[math.sin(alfa), math.cos(alfa)]
]
return(Matrix(R))
A = Matrix([
[1],
[0]
])
R = rotationsmatris2D(math.radians(90))
print("Rotationsmatris för +90 grader")
print(R)
print("Punkt innan rotation")
print(A)
B = R @ A
print("Punkt efter rotation")
print(B)
import math
class Matrix:
def __init__(self, I=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
def __str__(self):
s = str(self.h)+'x'+str(self.w)+"\n"
for i in range(self.h):
for j in range(self.w):
s = s + "{:>6}".format(round(self.I[i][j],1))
s = s + "\n"
return(s)
def __matmul__(self,B):
C = [[0]*B.w for i in range(self.h)]
for i in range(B.w):
for j in range(self.h):
for s in range(B.h):
C[j][i]+= self.I[j][s] * B.I[s][i]
return(Matrix(C))
def rotationsmatris2D(alfa):
R = [
[math.cos(alfa), -math.sin(alfa)],
[math.sin(alfa), math.cos(alfa)]
]
return(Matrix(R))
A = Matrix([
[1],
[0]
])
R = rotationsmatris2D(math.radians(90))
print("Rotationsmatris för +90 grader")
print(R)
print("Punkt innan rotation")
print(A)
B = R @ A
print("Punkt efter rotation")
print(B)
Nu är vi förstås nyfikna på hur det ser ut om vi ritar det i 2D och gör upprepande rotationer. Vi kopplar en timer till en funktion som ritar grafik på canvas under 10 sekunder...
import math
from browser import document as doc
import browser.timer
class Matrix:
def __init__(self, I=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
@property
def X(self):
return(self.I[0][0])
@property
def Y(self):
return(self.I[1][0])
def __matmul__(self,B):
C = [[0]*B.w for i in range(self.h)]
for i in range(B.w):
for j in range(self.h):
for s in range(B.h):
C[j][i]+= self.I[j][s] * B.I[s][i]
return(Matrix(C))
def rotationsmatris2D(alfa):
R = [
[math.cos(alfa), -math.sin(alfa)],
[math.sin(alfa), math.cos(alfa)]
]
return(Matrix(R))
canvas = doc["canvaz12"]
canvas.width = 250
canvas.height = 250
ctx = canvas.getContext('2d')
ctx.strokeStyle = 'rgba(100, 255, 100, 1)'
A = Matrix([
[1],
[0]
])
def rotera():
global A
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=3
# rita cirkel, origo 150,150
ctx.arc(150,150,75,0,2*math.pi);
#roterar våra koordinater, 3 grader varje rotation
R = rotationsmatris2D(math.radians(3))
A = R @ A
# vi drar vår linje från origo 150,150
# till koordinaten vi beräknat
ctx.moveTo(150, 150)
ctx.lineTo(150-A.X*70, 150+A.Y*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 10000)
import math
from browser import document as doc
import browser.timer
class Matrix:
def __init__(self, I=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
@property
def X(self):
return(self.I[0][0])
@property
def Y(self):
return(self.I[1][0])
def __matmul__(self,B):
C = [[0]*B.w for i in range(self.h)]
for i in range(B.w):
for j in range(self.h):
for s in range(B.h):
C[j][i]+= self.I[j][s] * B.I[s][i]
return(Matrix(C))
def rotationsmatris2D(alfa):
R = [
[math.cos(alfa), -math.sin(alfa)],
[math.sin(alfa), math.cos(alfa)]
]
return(Matrix(R))
canvas = doc["canvaz12"]
canvas.width = 250
canvas.height = 250
ctx = canvas.getContext('2d')
ctx.strokeStyle = 'rgba(100, 255, 100, 1)'
A = Matrix([
[1],
[0]
])
def rotera():
global A
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=3
# rita cirkel, origo 150,150
ctx.arc(150,150,75,0,2*math.pi);
#roterar våra koordinater, 3 grader varje rotation
R = rotationsmatris2D(math.radians(3))
A = R @ A
# vi drar vår linje från origo 150,150
# till koordinaten vi beräknat
ctx.moveTo(150, 150)
ctx.lineTo(150-A.X*70, 150+A.Y*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 10000)
Nu undrar du kanske varför det står ett minustecken framför A.X på raden lineTo och det beror på att canvas räknar x-axeln uppifrån och ner, dvs rotationen kommer bli åt fel håll om vi inte vänder på tecknet p.g.a. spegelvänt.
När vi ändå håller på och undrar en massa, behöver man verkligen linjär algebra för att få en visare att snurra runt moturs? Nej, verkligen inte. Vad linjär algebran gör, är i princip att trolla fram nedanstående lösning. Det är vad det kokar ner till om man gör matematiken.
import math
from browser import document as doc
import browser.timer
canvas = doc["canvaz13"]
canvas.width = 250
canvas.height = 250
ctx = canvas.getContext('2d')
ctx.strokeStyle = 'rgba(100, 255, 100, 1)'
vinkel = 0
def rotera():
global vinkel
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=3
# rita cirkel, origo 150,150
ctx.arc(150,150,75,0,2*math.pi);
# vi drar vår linje från origo 150,150
# till koordinaten vi nu beräknar med sinus och cosinus
vinkel += math.radians(3)
ctx.moveTo(150, 150)
ctx.lineTo(150-math.cos(vinkel)*70, 150+math.sin(vinkel)*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 10000)
import math
from browser import document as doc
import browser.timer
canvas = doc["canvaz13"]
canvas.width = 250
canvas.height = 250
ctx = canvas.getContext('2d')
ctx.strokeStyle = 'rgba(100, 255, 100, 1)'
vinkel = 0
def rotera():
global vinkel
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=3
# rita cirkel, origo 150,150
ctx.arc(150,150,75,0,2*math.pi);
# vi drar vår linje från origo 150,150
# till koordinaten vi nu beräknar med sinus och cosinus
vinkel += math.radians(3)
ctx.moveTo(150, 150)
ctx.lineTo(150-math.cos(vinkel)*70, 150+math.sin(vinkel)*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 10000)
Poängen med linjär algebra, det är att vi kan skapa en bild - eller snarare en mesh - av miljontals punkter. Sedan kan vi rotera alla dessa punkter. Det är lite jobbigt knappa in miljoner punkter, men vi kan utöka till 4 punkter och rita en kvadrat.
import math
from browser import document as doc
import browser.timer
class Matrix:
def __init__(self, I=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
@property
def X(self):
return(self.I[0][0])
@property
def Y(self):
return(self.I[1][0])
def __matmul__(self,B):
C = [[0]*B.w for i in range(self.h)]
for i in range(B.w):
for j in range(self.h):
for s in range(B.h):
C[j][i]+= self.I[j][s] * B.I[s][i]
return(Matrix(C))
def rotationsmatris2D(alfa):
R = [
[math.cos(alfa), -math.sin(alfa)],
[math.sin(alfa), math.cos(alfa)]
]
return(Matrix(R))
canvas = doc["canvaz14"]
canvas.width = 250
canvas.height = 250
ctx = canvas.getContext('2d')
ctx.strokeStyle = 'rgba(100, 255, 100, 1)'
A = Matrix([
[ 1],
[ 0]
])
B = Matrix([
[ 0],
[ 1]
])
C = Matrix([
[-1],
[ 0]
])
D = Matrix([
[ 0],
[-1]
])
def rotera():
global A,B,C,D
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=3
# Roterar våra koordinater, 3 grader varje rotation
R = rotationsmatris2D(math.radians(3))
A = R @ A
B = R @ B
C = R @ C
D = R @ D
# Vi ritar en kvadrat med A,B,C,D som hörn
ctx.moveTo(150-A.X*70, 150+A.Y*70)
ctx.lineTo(150-B.X*70, 150+B.Y*70)
ctx.lineTo(150-C.X*70, 150+C.Y*70)
ctx.lineTo(150-D.X*70, 150+D.Y*70)
ctx.lineTo(150-A.X*70, 150+A.Y*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 10000)
import math
from browser import document as doc
import browser.timer
class Matrix:
def __init__(self, I=None):
self.I = I
self.w = len(self.I[0])
self.h = len(self.I)
@property
def X(self):
return(self.I[0][0])
@property
def Y(self):
return(self.I[1][0])
def __matmul__(self,B):
C = [[0]*B.w for i in range(self.h)]
for i in range(B.w):
for j in range(self.h):
for s in range(B.h):
C[j][i]+= self.I[j][s] * B.I[s][i]
return(Matrix(C))
def rotationsmatris2D(alfa):
R = [
[math.cos(alfa), -math.sin(alfa)],
[math.sin(alfa), math.cos(alfa)]
]
return(Matrix(R))
canvas = doc["canvaz14"]
canvas.width = 250
canvas.height = 250
ctx = canvas.getContext('2d')
ctx.strokeStyle = 'rgba(100, 255, 100, 1)'
A = Matrix([
[ 1],
[ 0]
])
B = Matrix([
[ 0],
[ 1]
])
C = Matrix([
[-1],
[ 0]
])
D = Matrix([
[ 0],
[-1]
])
def rotera():
global A,B,C,D
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=3
# Roterar våra koordinater, 3 grader varje rotation
R = rotationsmatris2D(math.radians(3))
A = R @ A
B = R @ B
C = R @ C
D = R @ D
# Vi ritar en kvadrat med A,B,C,D som hörn
ctx.moveTo(150-A.X*70, 150+A.Y*70)
ctx.lineTo(150-B.X*70, 150+B.Y*70)
ctx.lineTo(150-C.X*70, 150+C.Y*70)
ctx.lineTo(150-D.X*70, 150+D.Y*70)
ctx.lineTo(150-A.X*70, 150+A.Y*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 10000)