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 3D
Rotera punkter runt origo, punkter som t.ex. kan representera hörn i en figur, en mesh.
matematiken
Så, matematiken för att rotera i 3 dimensioner är samma som rotation i 2D dimensioner, den enda skillnaden är att vi i våra matriser har ytterligare en rad och kolumn, vilket representerar ytterligare en dimension. Dessutom rotationsmatriser för 3D istället för 2D.
Vi tittar på koden för rotation i 2D bara för att kunna jämföra med koden som roterar i 3D precis nedanför denna kod.
rotation i 2 dimensioner
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["canvaz11"]
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["canvaz11"]
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)
rotation i 3 dimensioner
Så, vi fixar fram koordinaterna för hörnen i vår 3D -kub.
Nu roterar vi i 3D här nedan. Det som tillkommer är att vi skapar rotationsmatriser för 3D och väljer här nedan 2 av 3 möjliga axlar rotera runt. Det tillkommer också lite fler punkter för att skapa en kub och det tillkommer lite fler rader med multiplikationer. Annars är allt samma som med rotation i 2D.
Det är 100% medvetet att jag låtit koden nedan bara bygga vidare på rotation i 2D. Som du ser börjar det bli uppenbart att man kan optimera lite saker här. T.ex. skapa en lista av koordinater. Man kan också matematiskt optimera multiplikationerna. Mer om det längre fram.
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 rotationsmatris3DZ(z):
R = [
[ 1, 0, 0],
[ 0, math.cos(z), -math.sin(z)],
[ 0, math.sin(z), math.cos(z)]
]
return(Matrix(R))
def rotationsmatris3DY(y):
R = [
[ math.cos(y), 0, math.sin(y)],
[ 0, 1, 0],
[-math.sin(y), 0, math.cos(y)]
]
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],[ 1]])
B = Matrix([[ 0],[ 1],[ 1]])
C = Matrix([[-1],[ 0],[ 1]])
D = Matrix([[ 0],[-1],[ 1]])
E = Matrix([[ 1],[ 0],[-1]])
F = Matrix([[ 0],[ 1],[-1]])
G = Matrix([[-1],[ 0],[-1]])
H = Matrix([[ 0],[-1],[-1]])
def rotera():
global A,B,C,D,E,F,G,H
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=1
# Roterar våra koordinater ...
R1 = rotationsmatris3DY(math.radians(5))
R2 = rotationsmatris3DZ(math.radians(3))
A = R1 @ R2 @ A
B = R1 @ R2 @ B
C = R1 @ R2 @ C
D = R1 @ R2 @ D
E = R1 @ R2 @ E
F = R1 @ R2 @ F
G = R1 @ R2 @ G
H = R1 @ R2 @ H
# Vi ritar kuben med A,B,C,D,E,F,G,H 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.moveTo(150-E.X*70, 150+E.Y*70)
ctx.lineTo(150-F.X*70, 150+F.Y*70)
ctx.lineTo(150-G.X*70, 150+G.Y*70)
ctx.lineTo(150-H.X*70, 150+H.Y*70)
ctx.lineTo(150-E.X*70, 150+E.Y*70)
ctx.moveTo(150-A.X*70, 150+A.Y*70)
ctx.lineTo(150-E.X*70, 150+E.Y*70)
ctx.moveTo(150-B.X*70, 150+B.Y*70)
ctx.lineTo(150-F.X*70, 150+F.Y*70)
ctx.moveTo(150-C.X*70, 150+C.Y*70)
ctx.lineTo(150-G.X*70, 150+G.Y*70)
ctx.moveTo(150-D.X*70, 150+D.Y*70)
ctx.lineTo(150-H.X*70, 150+H.Y*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 15000)
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 rotationsmatris3DZ(z):
R = [
[ 1, 0, 0],
[ 0, math.cos(z), -math.sin(z)],
[ 0, math.sin(z), math.cos(z)]
]
return(Matrix(R))
def rotationsmatris3DY(y):
R = [
[ math.cos(y), 0, math.sin(y)],
[ 0, 1, 0],
[-math.sin(y), 0, math.cos(y)]
]
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],[ 1]])
B = Matrix([[ 0],[ 1],[ 1]])
C = Matrix([[-1],[ 0],[ 1]])
D = Matrix([[ 0],[-1],[ 1]])
E = Matrix([[ 1],[ 0],[-1]])
F = Matrix([[ 0],[ 1],[-1]])
G = Matrix([[-1],[ 0],[-1]])
H = Matrix([[ 0],[-1],[-1]])
def rotera():
global A,B,C,D,E,F,G,H
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath()
ctx.lineWidth=1
# Roterar våra koordinater ...
R1 = rotationsmatris3DY(math.radians(5))
R2 = rotationsmatris3DZ(math.radians(3))
A = R1 @ R2 @ A
B = R1 @ R2 @ B
C = R1 @ R2 @ C
D = R1 @ R2 @ D
E = R1 @ R2 @ E
F = R1 @ R2 @ F
G = R1 @ R2 @ G
H = R1 @ R2 @ H
# Vi ritar kuben med A,B,C,D,E,F,G,H 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.moveTo(150-E.X*70, 150+E.Y*70)
ctx.lineTo(150-F.X*70, 150+F.Y*70)
ctx.lineTo(150-G.X*70, 150+G.Y*70)
ctx.lineTo(150-H.X*70, 150+H.Y*70)
ctx.lineTo(150-E.X*70, 150+E.Y*70)
ctx.moveTo(150-A.X*70, 150+A.Y*70)
ctx.lineTo(150-E.X*70, 150+E.Y*70)
ctx.moveTo(150-B.X*70, 150+B.Y*70)
ctx.lineTo(150-F.X*70, 150+F.Y*70)
ctx.moveTo(150-C.X*70, 150+C.Y*70)
ctx.lineTo(150-G.X*70, 150+G.Y*70)
ctx.moveTo(150-D.X*70, 150+D.Y*70)
ctx.lineTo(150-H.X*70, 150+H.Y*70)
ctx.stroke()
t = browser.timer.set_interval(rotera, 25)
def clear():
browser.timer.clear_interval(t)
browser.timer.set_timeout(clear, 15000)
projektion
Det kanske är lite baklänges -pedagogik här, men jag utelämnade förklara en viktig grej ovan.
Så, i ovan modell roterar vi punkter i 3 dimensioner. Men vilka punkter (som vi drar linjer mellan på skärmen) hamnar på vår 2D -canvas som vi tittar på? Vad är beräkningarna för detta? Svaret är att i enklaste fallet, vilket detta är, behövs inga beräkningar.
ortogonal projektion i enklaste fallet
Tänk dig en 3D -kub (i glas). Tänk dig att något roterar inne i kuben, som kuben ovan. En mindre kub roterar inuti en större kub, den stora kuben står still. Du kan vandra runt den stora kuben och titta på den lilla kuben som roterar där inne. I enklaste fallet tittar du in antingen från xy -sidan, xz -sidan eller yz -sidan. Tittar du från xy så är z djupet. Du ser inte djupet, du ser bara koordinaterma xy. Motsvarande resonemang på alla sidor. Enklaste formen av projektion, då tar vi våra koordinater (x,y,z) och vi tar helt enkelt bara bort en dimension så vi får kvar (x,y), sedan drar vi linjer på vår 2D -canvas mellan dessa (x,y) -punkter, där vi helt sonika bortser från z. Det är sedan vad du ser på skärmen. Vilken dimension vi tar bort beror på vilken sida vi står och tittar, vilket i ovan exempel inte spelar någon roll.
Som du ser om du tittar på klassen Matrix, så plockar vi bara X och Y vilka är de 2 första elementen i radvektorn som representerar punkten. Dvs, vi struntar i Z.
Om du tvivlar, klicka på koden ovan, ändra sedan i klassen Matrix, så att du istället plockar X och Z eller Y och Z. Dvs, en snabb test ändra bara index, kör och se resultatet.