How Matter.Axes.rotate Updates Axes in Matter.js

This article provides an overview of how the Matter.Axes.rotate method updates projection axes for rotating bodies in Matter.js. It explains the underlying 2D rotation mathematics, the in-place array mutation used for performance, and the critical role these updated axes play in rigid body collision detection via the Separating Axis Theorem (SAT).

The Role of Axes in Matter.js

Matter.js relies on the Separating Axis Theorem (SAT) to detect collisions between convex polygonal bodies. SAT requires projecting the vertices of two shapes onto a set of 1D axes (normal vectors perpendicular to each polygon's edges). If the projections overlap on all axes, a collision occurs.

When a rigid body rotates, the orientation of its edges changes. To keep collision detection accurate without recalculating normal vectors from scratch every frame, Matter.js stores normalized axis vectors on the body and rotates them dynamically to match the body's angular displacement.

The Mathematical Transformation

The Matter.Axes.rotate method takes an array of axis vectors and an angle \(\theta\) (in radians). It applies a standard 2D rotation matrix to each vector in the collection:

\[\begin{bmatrix} x' \\ y' \end{bmatrix} = \begin{bmatrix} \cos(\theta) & -\sin(\theta) \\ \sin(\theta) & \cos(\theta) \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix}\]

In code, this operation is executed as follows:

  1. Precompute Trigonometry: The function calculates Math.cos(angle) and Math.sin(angle) once per call, minimizing redundant trigonometric operations across the axis array.
  2. Transform Coordinates: For each axis vector \((x, y)\), the new coordinates are computed:
    • \(x_{new} = x \cdot \cos(\theta) - y \cdot \sin(\theta)\)
    • \(y_{new} = x \cdot \sin(\theta) + y \cdot \cos(\theta)\)
  3. In-Place Mutation: The function directly assigns the new values back to the axis object properties (axis.x = x_new and axis.y = y_new).

Because pure rotation preserves vector magnitude, the normalized unit length of each axis vector remains unchanged, eliminating the need for an expensive square root normalization step after rotation.

Execution Within the Body Update Lifecycle

Matter.Axes.rotate is typically invoked during calls to Matter.Body.rotate or when angular velocity is integrated during the engine's update cycle.

  1. Trigger: An angular change \(\Delta\theta\) is applied to a body.
  2. Vertices Update: The body's actual vertices are rotated around its center of mass using Matter.Vertices.rotate.
  3. Axes Update: Matter.Axes.rotate(body.axes, angle) is executed immediately to align the normal vectors with the new edge orientations.
  4. Collision Pipeline: The updated axes are subsequently queried by Matter.Detector and Matter.SAT to perform broadphase and narrowphase collision checks against other bodies in world space.

By rotating pre-existing vectors in-place rather than allocating new objects, Matter.Axes.rotate avoids garbage collection overhead, ensuring steady frame rates during complex multi-body simulations.