10

I've been researching this question for hours and for some reason I haven't been able to find the solution.

Given a convex polygon that is defined as an array of points in clockwise order around the polygon's centroid, how can I calculate the polygon's moment of inertia?

I've been able to find the equation for various shapes such as rectangles or circles, but not for an arbitrary convex polygon.

For example, the moment of inertia of a rectangle rotating about its centroid with mass m, height h, and width w is calculated as:

Moment of Inertia for a Rectangle

I am looking for a similar fomula / algorithm but for a convex polygon instead.

Linus Juhlin
  • 1,175
  • 10
  • 31
Parker Hoyes
  • 2,118
  • 1
  • 23
  • 38
  • 1
    Find one of the (many) algorithms for subdividing a convex polygon into triangles (graphics needs to do this a lot). Calculate the moment of each triangle. Add them all up. – Andy Newman Jun 29 '15 at 09:38
  • Juts for clarification you want the _mass moment of inertia_ used for dynamics and not the _second moment of area_ used in beam deflections? – John Alexiou Nov 21 '19 at 15:18
  • Does this answer your question? [Computing tensor of Inertia in 2D](https://stackoverflow.com/questions/41592034/computing-tensor-of-inertia-in-2d) – John Alexiou Nov 21 '19 at 18:40

2 Answers2

9

There is method to analyze a 2D polygon using vector algebra that is in my opinion easier to implement programmatically than the methods relying on trigonometry.

Each Vector quantity has two components .x and .y as well as methods vector algebra vectors including for dot and cross product

add(a,b) = [a.x+b.x, a.y+b.y]    // a+b = add(a,b)
scale(f,x) = [f*a.x, f*a.y]      // 2*a = scale(2,a), a/3 = scale(1/3,a)
dot(a,b) = a.x*b.x + a.y*b.y     // a·b = dot(a,b)
cross(a,b) = a.x*b.y - a.y*b.x   // a×b = cross(a,b)

The method below goes through all the sides of a polygon and sum up the area, the center and the mass moment of inertia about the coordinate origin of each triangle defined by the side and the origin. The final sum takes care of adding or subtracting areas near or far from the origin and yield the accurate results.

Finally, the mass moment is transferred from the origin to the center of mass.

polygon(Vector[] points, double depth, double density)
{
    // Accumulate the following values
    double area = 0.0;
    double mass = 0.0;
    Vector center = [0.0, 0.0];
    double mmoi = 0.0;

    // Take each vertex pair starting from the last-first vertex
    // in order to consider all sides.
    int count = points.Length;
    int prev = count - 1;
    for(int index=0; index<count; index++)
    {
        Vector a = points[prev];
        Vector b = points[index];

        double area_step = TriangleArea(a,b);
        double mass_step = density * area_step * depth;
        Vector center_step = TriangleCenter(a,b);
        double mmoi_step = TriangleMmoi(a,b, mass_step);

        area += area_step;
        center = (mass*center + mass_step*center_step)/(mass+mass_step);
        mass += mass_step;
        mmoi += mmoi_step;

        prev = index;
    }

    // Transfer mass moment of inertia from the origin to the center of mass
    mmoi -= mass*dot(center,center);

    // use area, mass, center and mmoi
}

double TriangleArea(Vector a, Vector b)
{
    return cross(a,b)/2;
}
double TriangleCenter(Vector a, Vector b)
{
    return (a+b)/3;
{
double TriangleMmoi(Vector a, Vector b, double triangleMass)
{
    return triangleMass/6*(dot(a,a)+dot(b.b)+dot(a.b));
}

The above is a similar process as outlined in this answer. More details are included in the linked answer.


Below is a c# implementation of the above, but with specifying the mass, instead of the density and thickness.

public static RigidBody2 FromShape(double mass, params Vector2[] polygon)
{
    double area = 0;
    Vector2 center = Vector2.Zero;
    double mmoi = 0;

    int prev = polygon.Length-1;
    for (int index = 0; index < polygon.Length; index++)
    {
        var a = polygon[prev];
        var b = polygon[index];

        var area_step = Vector2.Cross(a, b)/2;
        var center_step = (a+b)/3;
        var mmoi_step = area_step*(Vector2.Dot(a, a)+Vector2.Dot(b, b)+Vector2.Dot(a, b))/6;

        center = (center*area + center_step * area_step)/(area + area_step);
        area += area_step;
        mmoi += mmoi_step;

        prev = index;
    }

    double density = mass/area;
    mmoi *= density;
    mmoi -= mass * Vector2.Dot(center, center);

    return new RigidBody2(mass, mmoi, center);
}

In testing I used the following shape

shape

and the results of center = [1.0, 0.75] and mmoi = 687.5 match with analysis done in CAD package

CAD

Here is the unit test that checks against the CAD data:

[TestMethod, TestCategory("Linear Algebra, Planar")]
public void Geom_PlanarPolygonMass()
{
    Vector2[] points = new Vector2[] {
        Vector2.Cartesian(0.75, 0),
        Vector2.Cartesian(2, 0),
        Vector2.Cartesian(2, 0.5),
        Vector2.Cartesian(1.25, 0.5),
        Vector2.Cartesian(1.25, 1.5),
        Vector2.Cartesian(0, 1.5),
        Vector2.Cartesian(0, 1.0),
        Vector2.Cartesian(0.75, 1),
    };

    var rg = RigidBody2.FromShape(1500, points);

    Assert.AreEqual(1500, rg.Mass);
    CollectionAssert.AreEqual(Vector2.Cartesian(1.0, 0.75), rg.LocalCg, AbsComparer(TinyNumber));
    Assert.AreEqual(687.5, rg.LocalMmoi, DoubleEx.TinyNumber);
}
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • 1
    I can't do an edit of just one character, but the MMOI is 687.5, not 787.5 - there's a typo in the answer. – John Aaron Jan 16 '22 at 22:13
  • 1
    @JohnAaron - good catch, thank you. – John Alexiou Jan 16 '22 at 22:29
  • I know this is old, but there seem to be a bug if you use a Vector2(0, 0) somewhere in your points test for the C# implementation. Then you get center(NaN, NaN) (Dividing by 0). – Cobse Aug 18 '22 at 13:45
  • 1
    @Cobse - check if `step_area` is zero. If yes, proceed to the next iteration. Otherwise, you are dividing by zero if the zero area element is the first element to consider (and `area=0`) – John Alexiou Aug 18 '22 at 21:13
0

The equation for a moment of inertia is pretty straightforward, and you can find it explained here: https://en.wikipedia.org/wiki/Moment_of_inertia

It was used for example to derive the equation you quoted.

As Andy Newman mentioned, a convex polygon can be considered as comprised of triangles. But summing their individual inertias up is not an solution - it won't produce a valid equation that takes the rotation axis into account.

So what you would need to do basically is derive an equation for your polygon with respect to the rotation axis you want to rotate it about.

You may find one of the following theorems helpful, depending on the type of shape you have in mind:

Piotr Trochim
  • 693
  • 5
  • 15