将轴分离:计算多边形的MTV&线段

时间:2017-01-08 07:53:22

标签: c++ algorithm math computational-geometry

几个月来,我一直在尝试编写一个函数来返回应用于线段所需的最小平移,以便将其与相交的多边形分开。我正在使用分离轴定理,似乎我能够正确计算大小,但返回的方向有时是错误的。然而,当返回的翻译不正确时,反向总是正确的。

在下图中,黄线是计算中使用的线,紫线是黄线+平移,红线是黄线减去平移。你可以看到紫色或红色线在不同位置是正确的,但我不确定在什么条件下返回哪一行。

correct incorrect

所以我的问题是:在什么条件下翻译实际上需要翻转,这样我的函数总能返回一个方向正确的翻译?

const Projection Polygon::Project(const Axis &a) const
{
    float min = a.Dot(GetPoint(0));
    float max = min;

    for (unsigned i = 1; i < GetPointCount(); i++)
    {
        float prj = a.Dot(GetPoint(i));

        if (prj < min)
            min = prj;

        else if (prj > max)
            max = prj;
    }

    return Projection(min, max);
}

const Projection Segment::Project(const Axis &a) const
{
    const float dot0 = a.Dot(GetPoint(0));
    const float dot1 = a.Dot(GetPoint(1));

    return Projection(std::min(dot0, dot1), std::max(dot0, dot1));
}

const float Projection::GetOverlap(const Projection &p) const
{
    // x = min & y = max
    return std::min(y - p.x, p.y - x);
}

const Vector2 Segment::GetTranslation(const Polygon &p) const
{
    float Overlap = std::numeric_limits<float>::infinity();
    Axis smallest;
    Vector2 translation;

    AxesVec axes(p.GetAxes());
    axes.push_back(GetAxis());

    for (auto && axis : axes)
    {
        const Projection pA = p.Project(axis);
        const Projection pB = Project(axis);

        if (pA.IsOverlap(pB))
        {
            const float o = pA.GetOverlap(pB);

            if (o < Overlap)
            {
                Overlap = o;
                smallest = axis;
            }
        }
    }

    translation = smallest * (Overlap + 1);

    return translation;
}

1 个答案:

答案 0 :(得分:0)

问题是你的GetOverlap函数会返回重叠的幅度,而不是感觉(左或右)。

您可以将其更改为:

if(y - p.x < p.y - x)
  return y - p.x;
else
  return x - p.y;

然后在GetTranslation

const float o = pA.GetOverlap(pB);

if (abs(o) < abs(Overlap))
{
  ...
}

if (Overlap > 0)
  ++Overlap;
else
  --Overlap;

translation = smallest * Overlap;