Skip to content

Instantly share code, notes, and snippets.

@mpilosov
Created May 31, 2018 05:51
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 mpilosov/2af9eb6bf8dd0259c99bb0306ffa84f9 to your computer and use it in GitHub Desktop.
Save mpilosov/2af9eb6bf8dd0259c99bb0306ffa84f9 to your computer and use it in GitHub Desktop.
Three-Dimensional Projections (with Linear Algebra)
import numpy as np
from matplotlib import pyplot as plt
## DEFINE RE-USABLE METHODS
def rotX(theta): # build a rotation matrix around the y-axis
R = np.eye(3)
R[1,1] = np.cos(theta)
R[1,2] = -np.sin(theta)
R[2,1] = np.sin(theta)
R[2,2] = np.cos(theta)
return R
def rotY(theta): # build a rotation matrix around the y-axis
R = np.eye(3)
R[0,0] = np.cos(theta)
R[0,2] = np.sin(theta)
R[2,0] = -np.sin(theta)
R[2,2] = np.cos(theta)
return R
def rotZ(theta): # build a rotation matrix around the y-axis
R = np.eye(3)
R[0,0] = np.cos(theta)
R[0,1] = -np.sin(theta)
R[1,0] = np.sin(theta)
R[1,1] = np.cos(theta)
return R
class plane(object): # make a child of the base class `object`
def __init__(self, num_points_sides = 30, num_points_back = 20):
# these define our frame in the xy-plane
self.tail = [0, -20, 0]
self.nose = [0, 50, 0]
self.leftwing = [-20, -20, 0]
self.rightwing = [20, -20, 0]
self.points = []
# we fit a parabola on the back
xwidth = self.rightwing[0] - self.leftwing[0]
for x in np.linspace(self.leftwing[0], self.rightwing[0], num_points_back): # x values from wing to wing
self.points.append( [x, -(1.5/xwidth)*(x-self.rightwing[0])*(x-self.leftwing[0]) + self.leftwing[1], 0 ] )
# we can add a parabola as a spine
ywidth = self.nose[1] - self.tail[1]
for y in np.linspace(self.tail[1], self.nose[1], num_points_back): # x values from wing to wing
self.points.append( [0, y, -(0.5/ywidth)*(y-self.nose[1])*(y-self.tail[1]) ] )
# and lines on the sides
slope_left = (self.nose[1] - self.leftwing[1])/(self.nose[0] - self.leftwing[0] )
slope_right = (self.nose[1] - self.rightwing[1])/(self.nose[0] - self.rightwing[0])
for x in np.linspace(self.leftwing[0], self.nose[0], num_points_sides): # x values from left wing to center
self.points.append( [x, slope_left*x + self.nose[1], 0] )
for x in np.linspace(self.nose[0], self.rightwing[0], num_points_sides): # x values from center to right wing
self.points.append( [x, slope_right*x + self.nose[1], 0] )
# you can add more points to the geometry of our airplane, for now we leave it as a triangle.
def update(self, R): # this is the utility function that is used by the others.
l = []
for p in self.points:
l.append(np.dot(R, p))
self.points = l
pass
def pitch(self, theta=np.pi/16):
R = rotX(theta) # get rotation matrix
self.update(R) # call the update function.
pass
def roll(self, theta=np.pi/16):
R = rotY(theta) # get rotation matrix
self.update(R) # call the update function.
pass
def yaw(self, theta=np.pi/16):
R = rotZ(theta) # get rotation matrix
self.update(R) # call the update function.
pass
def plot(self, min_dot_size = 10, scale_factor = 40):
plt.cla() # clear our axes
N = np.array(self.points).transpose()
m = np.max(N[:,2]) - np.min(N[:,2])
# alpha=0.1+0.9*(p[2]-np.min(N[:,2]))/m,
for p in self.points:
plt.scatter(p[0], p[1], c='k', s=min_dot_size +scale_factor*(p[2]-np.min(N[:,2]))/m )
# plt.xlim([-50, 50])
# plt.ylim([-20, 70])
plt.axis('equal')
plt.show()
### HANDLER FUNCTION.
def render(roll_angle, pitch_angle, yaw_angle):
try:
P = plane() # instantiate our class.
P.roll(roll_angle)
P.pitch(pitch_angle)
P.yaw(yaw_angle)
P.plot()
except RuntimeWarning:
pass
return None
##### OPTIONAL SLIDERS
# from ipywidgets import widgets
# from ipywidgets import interactive
# sliders = [widgets.FloatSlider(val = 0, min=-np.pi/2, max=np.pi/2, step=np.pi/50, continuous_update=False)
# for _ in range(3)]
# interactive(render, roll_angle=sliders[0], pitch_angle=sliders[1], yaw_angle=sliders[2])
@mpilosov
Copy link
Author

mpilosov commented May 31, 2018

USAGE

Jupyter

paste into a python notebook with widgets enabled (for instructions, see my writeup ), then uncomment the code at the bottom.

Command-Line (iPython) or through plain old .py files

from jetplane import *
import numpy as np

roll_angle, pitch_angle, yaw_angle = 0, 0, 0
render(roll_angle, pitch_angle, yaw_angle)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment