使用GJK的距离子算法

时间:2015-07-31 05:52:29

标签: algorithm collision-detection computational-geometry

我正在尝试实现Gilbert–Johnson–Keerthi distance algorithm(GJK),但我遇到了“距离子算法”的问题,也称为“约翰逊算法”,它用于确定单纯形上的点最接近原点的。我得到的结果不正确但我在代码中找不到任何错误,所以问题必须在我对算法的解释中。

在Johnson的算法中(如Gino van den Bergen的书“交互式3D环境中的碰撞检测”中所述),给出了最接近原点的单X = {yi : i ∈ Ix}的仿射壳上的点由:

enter image description here

其中Δi^ X值以增加X的基数的顺序递归地确定:

enter image description here

......和Δ^ X由下式给出:

enter image description here

对于两个维度,我使用以下方法找到与原点最接近的点:

Point ClosestPointToOrigin(Simplex simplex)
{
    float dx = 0;
    for (int i = 0; i < simplex.size(); ++i)
        dx += dj(simplex, i);

    Point closest_point(0,0);
    for (int i = 0; i < simplex.size(); ++i)
        closest_point += dj(simplex, i) / dx * simplex[i];

    return closest_point;
}

其中Δi值由下式确定:

float dj(Simplex simplex, int j)
{
    if (j == 0)
    {
        return 1;
    }
    else
    {
        float d = 0;

        for (int i = 0; i < j; ++i)
            d += dj(simplex, i) * (simplex[0] - simplex[j]).dotProduct(simplex[i]);

        return d;
    }
}

对于X = {y1, y2}y1 = (1,1)的单一y2 = (1,-1),上述代码返回(1.0, -0.333333),而最近的点实际上是(1, 0)。< / p>

我一定做错了什么,但我无法弄清楚那是什么。

1 个答案:

答案 0 :(得分:1)

您的错误是dj函数,可能您误解了dxi等式,或者您没有写出您想要的内容。

我会尝试解释自己,如果你不理解某事,请不要犹豫评论(我正在编写伪python代码,但它应该很容易理解)。

假设我有以下Simplex:

S  = Simplex ({
    1: Point (1, 1) # y1
    2: Point (1,-1) # y2
})

我可以立即计算2个增量值:

enter image description here

然后,我可以计算另外两个增量值:

enter image description here

enter image description here

希望到现在你将开始看到你的错误:Δ值是基于指数的,因此对于尺寸为n的每个单纯形X,你有n个Δ值。你的一个错误是假设你可以计算Δ X 0 和Δ X i ,无论其内容如何X,这是假的。

现在最后一个Δ:

enter image description here

请注意:

enter image description here

你来到这里:

enter image description here

这是一个用Python编写的代码,如果你不理解它,我会尝试用你理解的语言写一个:

import numpy

class Point (numpy.ndarray):
    def __new__ (cls, x, y):
        return numpy.asarray([x, y]).astype(float).view(cls)

    def __str__ (self):
        return repr(self)

    def __repr__ (self):
        return 'Point ({}, {})'.format(self.x, self.y)

    x = property (fget = lambda s: s[0])
    y = property (fget = lambda s: s[1])

class Simplex (dict):
    def __init__ (self, points):
        super(Simplex, self).__init__ (enumerate(points))

    def __str__ (self):
        return repr(self)

    def __repr__ (self):
        return 'Simplex <' + dict.__repr__ (self) + '>'

def closest_point (s):
    dx = sum(dj(s, i) for i in range(len(s)))
    return sum(dj(s, i) / dx * v for i, v in s.items())

def dj (s, j):
    if len(s) == 0 or (len(s) == 1 and not j in s):
        print(s, j)
        raise ValueError ()
    if len(s) == 1:
        return 1
    ts = s.copy()
    yj = s[j]
    del ts[j]
    return sum(dj(ts, i) * (ts[list(ts.keys())[0]] - yj).dot(v) for i, v in ts.items())

S = Simplex([Point(1, 1), Point(1, -1)])

print(closest_point (S))