Skip to content

Instantly share code, notes, and snippets.

@mirrornerror
Last active December 31, 2019 17:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mirrornerror/0ac20c84259eb82089a512c01a91a5ab to your computer and use it in GitHub Desktop.
Save mirrornerror/0ac20c84259eb82089a512c01a91a5ab to your computer and use it in GitHub Desktop.
Jupyters/Quaternion/Quaternion_Cube.ipynb
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": "# Quaternion: Rotation of Cube"
},
{
"metadata": {
"ExecuteTime": {
"start_time": "2019-12-27T05:16:29.904730Z",
"end_time": "2019-12-27T05:16:30.587317Z"
},
"trusted": true
},
"cell_type": "code",
"source": "import numpy as np\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\n%matplotlib inline",
"execution_count": 1,
"outputs": []
},
{
"metadata": {
"ExecuteTime": {
"start_time": "2019-12-27T05:16:30.789196Z",
"end_time": "2019-12-27T05:16:30.929659Z"
},
"trusted": true
},
"cell_type": "code",
"source": "# quaternion multiplication function\ndef QbyQ(q1, q2): # q = [w, x, y, z]\n w = q1[0]*q2[0] - q1[1]*q2[1] - q1[2]*q2[2] - q1[3]*q2[3]\n i = q1[0]*q2[1] + q1[1]*q2[0] + q1[2]*q2[3] - q1[3]*q2[2]\n j = q1[0]*q2[2] - q1[1]*q2[3] + q1[2]*q2[0] + q1[3]*q2[1]\n k = q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1] + q1[3]*q2[0]\n return np.array([w, i, j, k])\n\n# quaternion rotation function\ndef QPQc(P, UV, t): # P: quaternion, UV: unit vector, t: rotation angle theta\n q = [np.cos(t/2), UV[0] * np.sin(t/2), UV[1] * np.sin(t/2), UV[2] * np.sin(t/2)]\n qc = [np.cos(t/2), -UV[0] * np.sin(t/2), -UV[1] * np.sin(t/2), -UV[2] * np.sin(t/2)]\n qP = QbyQ(q, P)\n result = QbyQ(qP, qc)\n return result\n\n# plot unit sphere\ndef plot_base(elev=25, azim=-70):\n fig = plt.figure(figsize=(10, 10))\n ax = fig.add_subplot(111, projection='3d')\n ax.view_init(elev=elev, azim=azim)\n ax.set(xlim=(-1, 1), ylim=(-1 ,1), zlim=(-1, 1))\n ax.set(xlabel='X', ylabel='Y', zlabel='Z')\n ax.xaxis.pane.fill = ax.yaxis.pane.fill = ax.zaxis.pane.fill = False\n\n t = np.linspace(0, 2*np.pi, 128+1)\n alpha = 0.7\n ax.plot(np.cos(t), np.sin(t), [0]*len(t), linestyle=':', c='red', alpha=alpha)\n ax.plot(np.cos(t), [0]*len(t), np.sin(t), linestyle=':', c='red', alpha=alpha)\n ax.plot([0]*len(t), np.cos(t), np.sin(t), linestyle=':', c='red', alpha=alpha)\n ax.plot([-1, 1], [0, 0], [0, 0], linestyle=':', c='red', alpha=alpha)\n ax.plot([0, 0], [-1, 1], [0, 0], linestyle=':', c='red', alpha=alpha)\n ax.plot([0, 0], [0, 0], [-1, 1], linestyle=':', c='red', alpha=alpha)\n return ax",
"execution_count": 2,
"outputs": []
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2019-12-24T02:45:54.704700Z",
"start_time": "2019-12-24T02:45:54.699747Z"
}
},
"cell_type": "markdown",
"source": "## Rotating Cube with ipywidgets"
},
{
"metadata": {
"ExecuteTime": {
"start_time": "2019-12-27T05:16:44.200242Z",
"end_time": "2019-12-27T05:16:44.726548Z"
},
"trusted": true
},
"cell_type": "code",
"source": "from ipywidgets import interact\nfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection\n\n@interact(theta=(-np.pi, np.pi, np.pi/100), w=(0.1, 1, 0.1), l=(0.1, 1, 0.1), h=(0.1, 1, 0.1)) # theta: rotation angle on unit vector\ndef cube(theta=0, w=0.5, l=0.5, h=0.5):\n scale = np.array([w, l, h]) # scale of the cube\n pos = np.array([-w/2, -l/2, 1]) # position of the cube\n UV = [1, 0, 0] # unit vector: rotation axis\n\n CUBE = np.array([[0,0,0],[1,0,0],[1,1,0],[0,1,0], \n [0,0,1],[1,0,1],[1,1,1],[0,1,1]]) * scale + pos # cube vertices with scale and position\n CUBEs = np.vstack([np.linalg.norm(c) for c in CUBE]) # scalar\n CUBEn = np.array([v / s if s != 0 else v * 0 for v, s in zip(CUBE, CUBEs)]) # normalization\n QCUBE = np.insert(CUBEn, 0, 0, axis=1) # quaternion\n\n UV = np.array(UV) / np.linalg.norm(UV) # normalization of unit vector\n\n QCUBE_R = np.array([QPQc(qc, UV, theta) for qc in QCUBE]) # quaternion rotation\n CX, CY, CZ = (QCUBE_R[:, 1:] * CUBEs).T # vectors of cube\n\n ax = plot_base()\n ax.plot([0, UV[0]], [0, UV[1]], [0, UV[2]], c='r')\n ax.scatter(UV[0], UV[1], UV[2], c='r')\n ax.plot(np.r_[CX[:4], CX[0]], np.r_[CY[:4], CY[0]], np.r_[CZ[:4], CZ[0]], c='b') # 4 bottom edges\n ax.plot(np.r_[CX[4:], CX[4]], np.r_[CY[4:], CY[4]], np.r_[CZ[4:], CZ[4]], c='g') # 4 top edges\n [ax.plot([CX[i], CX[i+4]], [CY[i], CY[i+4]], [CZ[i], CZ[i+4]], c='m') for i in range(4)] # 4 colomns edges\n \n bottom = list(zip(CX[:4], CY[:4], CZ[:4]))\n ax.add_collection3d(Poly3DCollection([bottom], color='#ddddff')) # fill in color : bottom side\n top = list(zip(CX[4:], CY[4:], CZ[4:]))\n ax.add_collection3d(Poly3DCollection([top], color='#ddffdd')) # fill in color : top side",
"execution_count": 3,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": "interactive(children=(FloatSlider(value=0.0, description='theta', max=3.141592653589793, min=-3.14159265358979…",
"application/vnd.jupyter.widget-view+json": {
"version_major": 2,
"version_minor": 0,
"model_id": "805616efe6394cd2b648d4d961e8d128"
}
},
"metadata": {}
}
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2019-12-26T10:16:10.686158Z",
"start_time": "2019-12-26T10:16:10.175231Z"
},
"trusted": true
},
"cell_type": "code",
"source": "from ipywidgets import interact\nfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection\n\n@interact(theta=(-np.pi, np.pi, np.pi/100), ux=(-1, 1, 0.1), uy=(-1, 1, 0.1), uz=(-1, 1, 0.1)) # theta: rotation angle on unit vector\ndef cube(theta=0, ux=1, uy=0, uz=0):\n scale = np.array([1/2, 1/2, 1/2]) # scale of the cube\n pos = np.array([-1/4, -1/4, 1]) # position of the cube\n UV = [ux, uy, uz] # unit vector: rotation axis\n\n CUBE = np.array([[0,0,0],[1,0,0],[1,1,0],[0,1,0], \n [0,0,1],[1,0,1],[1,1,1],[0,1,1]]) * scale + pos # cube vertices with scale and position\n CUBEs = np.vstack([np.linalg.norm(c) for c in CUBE]) # scalar\n CUBEn = np.array([v / s if s != 0 else v * 0 for v, s in zip(CUBE, CUBEs)]) # normalization\n QCUBE = np.insert(CUBEn, 0, 0, axis=1) # quaternion\n\n UV = np.array(UV) / np.linalg.norm(UV) # normalization of unit vector\n\n QCUBE_R = np.array([QPQc(qc, UV, theta) for qc in QCUBE]) # quaternion rotation\n CX, CY, CZ = (QCUBE_R[:, 1:] * CUBEs).T # vectors of cube\n\n ax = plot_base()\n ax.plot([0, UV[0]], [0, UV[1]], [0, UV[2]], c='r')\n ax.scatter(UV[0], UV[1], UV[2], c='r')\n ax.plot(np.r_[CX[:4], CX[0]], np.r_[CY[:4], CY[0]], np.r_[CZ[:4], CZ[0]], c='b') # 4 bottom edges\n ax.plot(np.r_[CX[4:], CX[4]], np.r_[CY[4:], CY[4]], np.r_[CZ[4:], CZ[4]], c='g') # 4 top edges\n [ax.plot([CX[i], CX[i+4]], [CY[i], CY[i+4]], [CZ[i], CZ[i+4]], c='m') for i in range(4)] # 4 colomns edges\n ax.text(ux, uy, uz, s=' unit vector')\n \n bottom = list(zip(CX[:4], CY[:4], CZ[:4]))\n ax.add_collection3d(Poly3DCollection([bottom], color='#ddddff')) # fill in color : bottom side\n top = list(zip(CX[4:], CY[4:], CZ[4:]))\n ax.add_collection3d(Poly3DCollection([top], color='#ddffdd')) # fill in color : top side",
"execution_count": 3,
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "fe33abe096184ed7a474b6ec6d7a5872",
"version_major": 2,
"version_minor": 0
},
"text/plain": "interactive(children=(FloatSlider(value=0.0, description='theta', max=3.141592653589793, min=-3.14159265358979…"
},
"metadata": {},
"output_type": "display_data"
}
]
},
{
"metadata": {
"trusted": true
},
"cell_type": "code",
"source": "",
"execution_count": null,
"outputs": []
}
],
"metadata": {
"kernelspec": {
"name": "py36",
"display_name": "py36",
"language": "python"
},
"language_info": {
"name": "python",
"version": "3.6.7",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
},
"gist": {
"id": "",
"data": {
"description": "Jupyters/Quaternion/Quaternion_Cube.ipynb",
"public": true
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
numpy
matplotlib
ipywidgets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment