Python基于歐拉角繪制一個(gè)立方體
先畫個(gè)立方體
工欲善其事、必先利其器,在開始學(xué)習(xí)歐拉角模擬之前,可先繪制一個(gè)立方體。
在matplotlib
中,這個(gè)任務(wù)可通過plt.voxels
實(shí)現(xiàn),下面先繪制一個(gè)最質(zhì)樸的立方體
代碼為
import matplotlib.pyplot as plt import numpy as np x, y, z = np.indices((2, 2, 2)) filled = np.ones((1,1,1)) ax = plt.subplot(projection='3d') ax.voxels(x,y,z, filled=filled) plt.show()
其中,x,y,z表示頂點(diǎn),filled表示被填充的區(qū)域。由于其頂點(diǎn)數(shù)量為2×2×2,故只有一個(gè)立方體,從而filled是一個(gè)1×1×1的張量。
有了立方體之后,就可以進(jìn)行歐拉角仿真了。
歐拉角和旋轉(zhuǎn)矩陣
為了盡快進(jìn)入演示部分,故對(duì)原理的介紹從略,僅從二維平面上的旋轉(zhuǎn)矩陣出發(fā),做一個(gè)簡(jiǎn)單的推導(dǎo),而三維旋轉(zhuǎn)矩陣,至少在形式上與二維是雷同的。
假設(shè)坐標(biāo)系中有一個(gè)向量(x,y),其模長(zhǎng)為r=√x2+y2,角度為θ0=arctan(y/x).若將其圍繞坐標(biāo)原點(diǎn)逆時(shí)針旋轉(zhuǎn)θ,則其坐標(biāo)變?yōu)?/p>
由于x=rcosθ0, y=rsinθ0,則上式可以寫為
寫成矩陣形式即為
也就是說,在平面直角坐標(biāo)系上,向量繞原點(diǎn)順時(shí)針旋轉(zhuǎn)θ,相當(dāng)于左乘一個(gè)旋轉(zhuǎn)矩陣。
推廣到三維,為了限制xy坐標(biāo)平面上的旋轉(zhuǎn),要將其旋轉(zhuǎn)中心從原點(diǎn)擴(kuò)展為繞著z軸旋轉(zhuǎn),從而三維旋轉(zhuǎn)矩陣可推廣為
同理可得到繞三個(gè)軸轉(zhuǎn)動(dòng)的旋轉(zhuǎn)矩陣,為了書寫方便,記Sθ=sinθ,Cθ=cosθ,可列出下表。
初步演示
將旋轉(zhuǎn)矩陣寫成函數(shù)是十分方便的,下面用lambda
表達(dá)式來實(shí)現(xiàn)
import numpy as np # 將角度轉(zhuǎn)弧度后再求余弦 cos = lambda th : np.cos(np.deg2rad(th)) sin = lambda th : np.sin(np.deg2rad(th)) # 即 Rx(th) => Matrix Rx = lambda th : np.array([ [1, 0, 0], [0, cos(th), -sin(th)], [0, sin(th), cos(th)]]) Ry = lambda th : np.array([ [cos(th), 0, sin(th)], [0 , 1, 0], [-sin(th), 0, cos(th)] ]) Rz = lambda th : np.array([ [cos(th) , sin(th), 0], [-sin(th), cos(th), 0], [0 , 0, 1]])
有了旋轉(zhuǎn)矩陣,就可以旋轉(zhuǎn),接下來讓正方體沿著三個(gè)軸分別旋轉(zhuǎn)30°,其效果如下
由于ax.voxels在繪圖時(shí),要求輸入的是擁有三個(gè)維度的數(shù)組,而旋轉(zhuǎn)矩陣是3 × 3 3\times33×3矩陣,相當(dāng)于是二維數(shù)組,彼此之間可能很難計(jì)算,所以實(shí)際計(jì)算時(shí),需要對(duì)數(shù)組維度進(jìn)行調(diào)整
import matplotlib.pyplot as plt # 用于批量調(diào)節(jié)x,y,z的數(shù)組維度 Reshape = lambda x,y,z : [x.reshape(2,2,2), y.reshape(2,2,2), z.reshape(2,2,2)] filled = np.ones((1,1,1)) x, y, z = np.indices((2, 2, 2)) # 將x,y,z展開,以便于矩陣計(jì)算 xyz = np.array([x,y,z]).reshape(3,-1) fig = plt.figure("rotate") # 此為未旋轉(zhuǎn)的正方體 ax = fig.add_subplot(1,4,1, projection='3d') ax.voxels(x,y,z, filled=filled) # 繞x軸旋轉(zhuǎn)30° X, Y, Z = Rx(30) @ xyz ax = fig.add_subplot(1,4,2, projection='3d') ax.voxels(*Reshape(X, Y, Z), filled=filled) # 繞y軸旋轉(zhuǎn)30° X, Y, Z = Ry(30) @ xyz ax = fig.add_subplot(1,4,3, projection='3d') ax.voxels(*Reshape(X, Y, Z), filled=filled) # 繞z軸旋轉(zhuǎn)30° X, Y, Z = Rz(30) @ xyz ax = fig.add_subplot(1,4,4, projection='3d') ax.voxels(*Reshape(X, Y, Z), filled=filled) plt.show()
不同轉(zhuǎn)動(dòng)順序的影響
眾所周知,矩陣計(jì)算是不能交換的,反映到實(shí)際生活中,就是不同的旋轉(zhuǎn)次序,可能會(huì)導(dǎo)致完全不同的結(jié)果,接下來沿著不同的旋轉(zhuǎn)次序,來對(duì)正方體進(jìn)行旋轉(zhuǎn),效果如下
需要注意的是,由于矩陣左乘向量表示對(duì)向量進(jìn)行旋轉(zhuǎn),所以距離向量最近的矩陣表示最先進(jìn)行的操作,即RzRyRxr ? 表示先轉(zhuǎn)Rx ,Ry次之,Rz最后。
代碼如下
filled = np.ones((1,1,1)) x, y, z = np.indices((2, 2, 2)) xyz = np.array([x,y,z]).reshape(3,-1) fig = plt.figure("rotate") # 旋轉(zhuǎn)順序 x, y, z X, Y, Z = Rz(30) @ Ry(30) @ Rx(30) @ xyz ax = fig.add_subplot(1,3,1, projection='3d') ax.voxels(*Reshape(X, Y, Z), filled=filled) # 旋轉(zhuǎn)順序 z, y, x X, Y, Z = Rx(30) @ Ry(30) @ Rz(30) @ xyz ax = fig.add_subplot(1,3,2, projection='3d') ax.voxels(*Reshape(X, Y, Z), filled=filled) # 旋轉(zhuǎn)順序 y, x, z X, Y, Z = Rz(30) @ Rx(30) @ Ry(30) @ xyz ax = fig.add_subplot(1,3,3, projection='3d') ax.voxels(*Reshape(X, Y, Z), filled=filled) plt.show()
總之,雖然分不清誰是誰,但最起碼可以看清楚,不同的旋轉(zhuǎn)順序的確導(dǎo)致了不同的旋轉(zhuǎn)結(jié)果。
旋轉(zhuǎn)演示
為了更加清楚地表示這一過程,可以將正方體的旋轉(zhuǎn)過程繪制下來,先考慮單軸旋轉(zhuǎn),假設(shè)每次旋轉(zhuǎn)3°,繞X軸旋轉(zhuǎn)30次,則可得到
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm import imageio filled = np.ones((1,1,1)) x, y, z = np.indices((2, 2, 2)) xyz = np.array([x,y,z]).reshape(3,-1) def saveGif(X,Y,Z, gifs): plt.cla() ax = plt.subplot(projection='3d') ax.voxels(*Reshape(X, Y, Z), filled=filled) ax.set_xlim(-0.5,1.5) ax.set_ylim(-0.5,1.5) ax.set_zlim(-0.5,1.5) ax.set_title(f"theta={th}") plt.tight_layout() plt.savefig(f"tmp.jpg") gifs.append(imageio.imread(f"tmp.jpg")) gifImgs = [] th = 0 for i in range(30): X,Y,Z = Rx(th)@xyz th += 3 saveGif(X, Y, Z, gifImgs) imageio.mimsave("test.gif",gifImgs,fps=10)
通過這個(gè)方法,可以將不同順序的旋轉(zhuǎn)矩陣可視化表示,
filled = np.ones((1,1,1)) x, y, z = np.indices((2, 2, 2)) xyz = np.array([x,y,z]).reshape(3,-1) gifImgs = [] th = 0 for _ in range(10): X,Y,Z = Rz(0) @ Rx(0) @ Ry(th) @ xyz th += 3 saveGif(X, Y, Z, gifImgs) th = 0 for i in range(10): X,Y,Z = Rz(0) @ Rx(th) @ Ry(30) @ xyz th += 3 saveGif(X, Y, Z, gifImgs) th = 0 for i in range(10): X,Y,Z = Rz(th) @ Rx(30) @ Ry(30) @ xyz th += 3 saveGif(X, Y, Z, gifImgs) imageio.mimsave("test.gif",gifImgs,fps=10)
最后得到三種不同旋轉(zhuǎn)順序的區(qū)別
x-y-z
z-y-x
y-x-z
到此這篇關(guān)于Python基于歐拉角繪制一個(gè)立方體的文章就介紹到這了,更多相關(guān)Python歐拉角實(shí)現(xiàn)剛體轉(zhuǎn)動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
對(duì)python中的 os.mkdir和os.mkdirs詳解
今天小編就為大家分享一篇對(duì)python中的 os.mkdir和os.mkdirs詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-10-10舉例區(qū)分Python中的淺復(fù)制與深復(fù)制
這篇文章主要介紹了舉例區(qū)分Python中的淺復(fù)制與深復(fù)制,是Python入門學(xué)習(xí)中的重要知識(shí),需要的朋友可以參考下2015-07-07基于Python編寫一個(gè)有趣的進(jìn)程勾選器(Process?Selector)
本文主要介紹了如何利用Python編寫一個(gè)有趣的進(jìn)程勾選器,可以在Checklistbox中列出系統(tǒng)中正在運(yùn)行的進(jìn)程的名稱和PID,并允許用戶選擇進(jìn)程并將其保存到文本文件中,需要的可以參考一下2023-05-05python 三種方法實(shí)現(xiàn)對(duì)Excel表格的讀寫
這篇文章主要介紹了python 三種方法實(shí)現(xiàn)對(duì)Excel表格的讀寫,幫助大家更好的利用python處理表格,感興趣的朋友可以了解下2020-11-11Python使用Py2neo創(chuàng)建Neo4j的節(jié)點(diǎn)和關(guān)系
Neo4j是一款開源圖數(shù)據(jù)庫,使用Python語言訪問Neo4j可以使用Py2neo。本文介紹了使用Py2neo訪問Neo4j,批量創(chuàng)建節(jié)點(diǎn)和關(guān)系的方法2021-08-08python 圖像判斷,清晰度(明暗),彩色與黑白實(shí)例
這篇文章主要介紹了python 圖像判斷,清晰度(明暗),彩色與黑白實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06一個(gè)基于flask的web應(yīng)用誕生(1)
這篇文章主要為大家詳細(xì)介紹了基于flask的web應(yīng)用誕生,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04python抓取并保存html頁面時(shí)亂碼問題的解決方法
這篇文章主要介紹了python抓取并保存html頁面時(shí)亂碼問題的解決方法,結(jié)合實(shí)例形式分析了Python頁面抓取過程中亂碼出現(xiàn)的原因與相應(yīng)的解決方法,需要的朋友可以參考下2016-07-07python3代碼輸出嵌套式對(duì)象實(shí)例詳解
在本篇文章里小編給大家整理了關(guān)于python3代碼輸出嵌套式對(duì)象實(shí)例詳解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2020-12-12