Mapping 4D Geometry
Visualizing 4D objects in a 3D space using vpython modeling and vector geometry.
This project was focused on trying to essentially visualize a 4D object (tesseract) within a 3D layout, which I achieved using vpython and numpy.
To visualize the tesseract in 3 dimensions, I essentially used a projection using this formula:
\[ \begin{bmatrix} x' \\ y' \\ z' \end{bmatrix} = \begin{bmatrix} \frac{x}{w+d} \\ \frac{y}{w+d} \\ \frac{z}{w+d} \end{bmatrix} \]
Rotation in 4D space requires a 4x4 rotation matrix. For simplicity, rotations can be performed in pairs of dimensions (ie, \(xy\)-plane, \(xz\)-plane). A rotation matrix for a plane (say \(xy\)-plane) in 4D is:
\[ R_{xy}(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta & 0 & 0 \\ \sin\theta & \cos\theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \]
The final rotation is a combination of rotations in different planes:
\[ R(\theta_x, \theta_y, \theta_z) = R_{xy}(\theta_x) R_{xz}(\theta_y) R_{yz}(\theta_z) \]
To make it more interesting, I implemented a slider to adjust rotation speed. Unfortunately, Python does not have a lot of good libraries (afaik) for rendering 3D visuals in a fully separated application, so it currently opens within a web browser.
Technologies Used
- Python
- VPython
- MathJax
- Numpy
Raw Code
import numpy as np from vpython import canvas, sphere, vector, curve, color, rate, slider, wtext tesseract_size = 2 projection_distance = 5 rotation_speed = 0.05 scene = canvas(title='4D Visualization', width=800, height=800, center=vector(0,0,0), background=color.black) # vertices of the tesseract in all possible combinations vertices_4d = np.array([ [-1, -1, -1, -1], [-1, -1, -1, 1], [-1, -1, 1, -1], [-1, -1, 1, 1], [-1, 1, -1, -1], [-1, 1, -1, 1], [-1, 1, 1, -1], [-1, 1, 1, 1], [1, -1, -1, -1], [1, -1, -1, 1], [1, -1, 1, -1], [1, -1, 1, 1], [1, 1, -1, -1], [1, 1, -1, 1], [1, 1, 1, -1], [1, 1, 1, 1] ]) * tesseract_size # function to project 4d vertices to 3d space def project_to_3d(vertices_4d): vertices_3d = [] for vertex in vertices_4d: w = 1 / (projection_distance - vertex[3]) x = vertex[0] * w y = vertex[1] * w z = vertex[2] * w vertices_3d.append([x, y, z]) return np.array(vertices_3d) # function to rotate vertices in 4d space def rotate_4d(vertices, angle, axis1, axis2): rotation_matrix = np.eye(4) cos_angle = np.cos(angle) sin_angle = np.sin(angle) rotation_matrix[axis1, axis1] = cos_angle rotation_matrix[axis1, axis2] = -sin_angle rotation_matrix[axis2, axis1] = sin_angle rotation_matrix[axis2, axis2] = cos_angle return np.dot(vertices, rotation_matrix) # function to create edges between vertices def create_edges(vertices_3d): edges = [ (0, 1), (0, 2), (0, 4), (0, 8), (1, 3), (1, 5), (1, 9), (2, 3), (2, 6), (2, 10), (3, 7), (3, 11), (4, 5), (4, 6), (4, 12), (5, 7), (5, 13), (6, 7), (6, 14), (7, 15), (8, 9), (8, 10), (8, 12), (9, 11), (9, 13), (10, 11), (10, 14), (11, 15), (12, 13), (12, 14), (13, 15), (14, 15) ] edge_objects = [] for edge in edges: edge_obj = curve(color=color.white, radius=0.02) edge_obj.append(vector(*vertices_3d[edge[0]]), vector(*vertices_3d[edge[1]])) edge_objects.append(edge_obj) return edge_objects, edges # initial projection and visualization vertices_3d = project_to_3d(vertices_4d) spheres = [sphere(pos=vector(*vertex), radius=0.1, color=color.cyan) for vertex in vertices_3d] edges, edge_indices = create_edges(vertices_3d) # control for animation speed wtext(text="Rotation Speed: ") speed_slider = slider(min=0.01, max=0.2, value=rotation_speed, length=220, bind=lambda s: set_rotation_speed(s.value)) def set_rotation_speed(value): global rotation_speed rotation_speed = value # simulation loop with continuous rotation while True: rate(30) # rotate the tesseract in 4D space around different axes vertices_4d = rotate_4d(vertices_4d, rotation_speed, 0, 3) vertices_4d = rotate_4d(vertices_4d, rotation_speed, 1, 2) # update the projection and visualization vertices_3d = project_to_3d(vertices_4d) for i, vertex in enumerate(vertices_3d): spheres[i].pos = vector(*vertex) for edge, (start, end) in zip(edges, edge_indices): edge.modify(0, vector(*vertices_3d[start])) edge.modify(1, vector(*vertices_3d[end]))
Sources
https://brilliant.org/wiki/tesseract/
https://en.wikipedia.org/wiki/Tesseract