Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate moment of inertia given an arbitrary convex 2D polygon

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.

like image 276
Parker Hoyes Avatar asked Jun 29 '15 01:06

Parker Hoyes


1 Answers

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);
}
like image 195
John Alexiou Avatar answered Oct 20 '22 13:10

John Alexiou