codexplane-point-normal-orthogonal-projection.py
plane-point-normal-orthogonal-projection.py
"""Original plane/point/normal geometry; write the opaque PNG to cwd."""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
def main():
n = np.array([2., -1., 2.])
p = np.array([4., 1., 2.])
q = p - (np.dot(n, p) - 3) / np.dot(n, n) * n
x, y = np.meshgrid(np.linspace(.4, 4.7, 19), np.linspace(.35, 3.4, 15))
z = (3 - 2*x + y) / 2
fig = plt.figure(figsize=(10.4, 6.4), facecolor='white')
ax = fig.add_axes((.03, .15, .66, .73), projection='3d')
ax.plot_surface(x, y, z, color='#94c5dd', alpha=.3, linewidth=0)
ax.plot_wireframe(x, y, z, color='#7298ac', linewidth=.45, alpha=.65)
ax.plot(*np.array([p, q]).T, color='#b44e22', lw=3.4)
ax.scatter(*p, color='#b44e22', s=65, depthshade=False)
ax.scatter(*q, color='#146352', s=65, depthshade=False)
ax.text(*(p + [.12, -.06, .2]), 'p = (4, 1, 2)', fontsize=11, color='#923c19')
ax.text(*(q + [.09, -.13, -.36]), 'q', fontsize=12, color='#146352')
unit = n / np.linalg.norm(n)
ax.quiver(*q, *unit, length=.72, color='#146352', linewidth=2,
arrow_length_ratio=.22)
ax.set_xlabel('x', labelpad=8)
ax.set_ylabel('y', labelpad=8)
ax.set_zlabel('z', labelpad=6)
ax.set_xlim(.3, 4.8)
ax.set_ylim(.25, 3.55)
ax.set_zlim(-3.3, 2.8)
ax.set_box_aspect((4.5, 3.3, 6.1))
ax.view_init(elev=23, azim=-61)
ax.set_facecolor('white')
for axis in (ax.xaxis, ax.yaxis, ax.zaxis):
axis.pane.set_facecolor((1, 1, 1, 1))
fig.suptitle('A plane, its normal, and the closest point', fontsize=18, weight='bold', y=.965)
fig.text(.71, .75, 'Plane', fontsize=12, weight='bold', color='#226483')
fig.text(.71, .70, r'$2x-y+2z=3$', fontsize=15)
fig.text(.71, .59, 'Normal vector', fontsize=12, weight='bold', color='#146352')
fig.text(.71, .54, r'$\mathbf{n}=(2,-1,2)$', fontsize=14)
fig.text(.71, .43, 'Closest point', fontsize=12, weight='bold', color='#146352')
fig.text(.71, .38, r'$\mathbf{q}=(20/9,17/9,2/9)$', fontsize=13)
fig.text(.71, .27, 'Perpendicular distance', fontsize=12, weight='bold', color='#b44e22')
fig.text(.71, .22, r'$\|\mathbf{p}-\mathbf{q}\|=8/3$', fontsize=14)
fig.text(.5, .055, 'The mesh is a displayed patch; the mathematical plane has no edges.',
ha='center', fontsize=11, color='#405063')
fig.savefig(Path.cwd() / (Path(__file__).stem + '.png'), dpi=120, facecolor='white')
plt.close(fig)
if __name__ == '__main__':
main()