How Matter.Vertices.clockwiseSorting Works in Matter.js
This article explains how the
Matter.Vertices.clockwiseSorting method functions within
the Matter.js 2D physics engine. It explores the geometric mechanics
behind the sorting algorithm, why a consistent clockwise winding order
is required for physics simulation, and how it prevents errors during
collision detection, area determination, and inertia calculations.
The Importance of Winding Order in Physics Engines
Physics engines rely on predictable geometric structures to calculate collisions and physical properties. In Matter.js, polygonal bodies are defined by an array of vertices. For the engine to interpret these vertices as a solid, closed polygon, the points must follow a consistent winding order—specifically clockwise.
Matter.js enforces clockwise winding primarily for the following reasons:
- Separating Axis Theorem (SAT): Matter.js uses SAT for collision detection between convex shapes. SAT works by projecting shapes onto axes perpendicular to each polygon's edges (edge normals). To calculate outward-facing normals, the engine assumes edges transition from one vertex to the next in a clockwise direction. If vertices are out of order, the calculated normals may face inward, causing collisions to fail or objects to interpenetrate incorrectly.
- Mass, Inertia, and Centroid Calculations: Matter.js calculates properties like area, center of mass, and moment of inertia using polygon integration (similar to the Shoelace formula). These algorithms assume consecutive vertices represent the boundary of the shape. Erratic vertex orders produce self-intersecting polygons with negative or incorrect areas, leading to invalid mass values.
How
Matter.Vertices.clockwiseSorting Operates
The Matter.Vertices.clockwiseSorting function normalizes
an unordered set of points into a coherent, clockwise loop. It achieves
this using a polar angle sorting approach relative to the polygon's
geometric center.
1. Finding the Geometric Center
The method first determines the centroid (average position) of all vertices provided in the array:
\[\text{center}_x = \frac{1}{n} \sum_{i=1}^{n} x_i, \quad \text{center}_y = \frac{1}{n} \sum_{i=1}^{n} y_i\]
This reference point acts as the origin for angular calculations.
2. Computing Polar Angles
For every vertex in the set, the algorithm calculates its angle relative to the computed center using the standard two-argument arctangent function:
\[\theta = \operatorname{atan2}(y - \text{center}_y, x - \text{center}_x)\]
Because the screen coordinate system in Matter.js places \((0,0)\) at the top-left (meaning the positive y-axis points downward), standard trigonometric angles progress clockwise rather than counter-clockwise.
3. Sorting by Angle
The function sorts the array of vertices based on these computed angles in ascending order. By ordering the points as their angles increase around the centroid, the algorithm guarantees that traversing the array traces the perimeter of the shape in a clockwise direction.
Geometric Considerations and Limitations
While Matter.Vertices.clockwiseSorting creates a valid
clockwise perimeter for point clouds, developers must consider shape
convexity:
- Convex Polygons: The sorting algorithm works reliably on convex point sets, producing a clean convex boundary ready for rigid-body simulation.
- Concave Polygons: Radial sorting around a single
centroid can distort complex concave shapes, because points located
along inward indentations may share angular intervals with outer points.
For complex concave paths, shapes must be decomposed into convex parts
using utilities like
Matter.Vertices.hullor polygon decomposition libraries before sorting and rigid body creation.