给定任意凸2D多边形,计算惯性矩

时间:2015-06-29 01:08:41

标签: physics game-physics inertia

我一直在研究这个问题几个小时,由于某种原因,我找不到解决方案。

如果凸多边形被定义为围绕多边形质心的顺时针顺序的点阵列,我该如何计算多边形的惯性矩?

我已经能够找到各种形状的方程,例如矩形或圆形,但不能找到任意凸多边形。

例如,计算围绕质心旋转的矩形的惯性矩,其质量 m ,高度 h ,宽度 w 为:

Moment of Inertia for a Rectangle

我正在寻找类似的公式/算法,而是寻找凸多边形。

2 个答案:

答案 0 :(得分:0)

惯性矩的等式非常简单,你可以在这里解释:https://en.wikipedia.org/wiki/Moment_of_inertia

例如,它用于推导出你引用的等式。

正如Andy Newman所说,凸多边形可以被认为是由三角形组成。但是将它们的个体惯性相加并不是一个解决方案 - 它不会产生一个考虑旋转轴的有效方程。

所以你需要做的就是为你的多边形推导一个你想要旋转它的旋转轴的方程式。

您可能会发现以下定理之一有用,具体取决于您所考虑的形状类型:

答案 1 :(得分:0)

有一种方法可以使用矢量代数分析2D多边形,我认为该方法比依赖三角函数的方法更易于编程实现。

每个Vector数量具有两个分量.x.y以及方法矢量代数矢量,包括点积和叉积

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)

下面的方法遍历多边形的所有边,并求和由该边和原点定义的每个三角形的坐标原点的面积,中心和质量惯性矩。最终的总和用于在原点附近增加或减少的区域,并产生准确的结果

最后,质量矩从原点转移到质量中心。

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));
}

上面是类似的过程as outlined in this answer。链接的答案中包含更多详细信息。


下面是上述c#的实现,但是指定了质量,而不是密度和厚度。

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);
}

在测试中,我使用了以下形状

shape

center = [1.0, 0.75]mmoi = 787.5的结果与在CAD软件包中进行的分析相符

CAD

以下是检查CAD数据的单元测试:

[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);
}