gjk算法创建具有两个相反点的单纯形

hgb9j2n6  于 2021-08-20  发布在  Java
关注(0)|答案(0)|浏览(178)

我正在制作一个物理引擎,我正在使用gjk算法。现在我根据这篇博文写了这篇文章,下面是我的代码:

class CollManager:
    @staticmethod
    def supportPoint(a, b, direction):
        return a.supportPoint(direction) - \
            b.supportPoint(-direction)

    @staticmethod
    def nextSimplex(args):
        length = len(args[0])
        if length == 2:
            return CollManager.lineSimplex(args)
        if length == 3:
            return CollManager.triSimplex(args)
        if length == 4:
            return CollManager.tetraSimplex(args)
        return False

    @staticmethod
    def lineSimplex(args):
        a, b = args[0]
        ab = b - a
        ao = -a
        if ab.dot(ao) > 0:
            args[1] = ab.cross(ao).cross(ab)
        else:
            args[0] = [a]
            args[1] = ao

    @staticmethod
    def triSimplex(args):
        a, b, c = args[0]
        ab = b - a
        ac = c - a
        ao = -a
        abc = ab.cross(ac)
        if abc.cross(ac).dot(ao) > 0:
            if ac.dot(ao) > 0:
                args[0] = [a, c]
                args[1] = ac.cross(ao).cross(ac)
            else:
                args[0] = [a, b]
                return CollManager.lineSimplex(args)
        elif ab.cross(abc).dot(ao) > 0:
            args[0] = [a, b]
            return CollManager.lineSimplex(args)
        else:
            if abc.dot(ao) > 0:
                args[1] = abc
            else:
                args[0] = [a, c, b]
                args[1] = -abc
        return False

    @staticmethod
    def tetraSimplex(args):
        a, b, c, d = args[0]
        ab = b - a
        ac = c - a
        ad = d - a
        ao = -a
        abc = ab.cross(ac)
        acd = ac.cross(ad)
        adb = ad.cross(ab)
        if abc.dot(ao) > 0:
            args[0] = [a, b, c]
            return CollManager.triSimplex(args)
        if acd.dot(ao) > 0:
            args[0] = [a, c, d]
            return CollManager.triSimplex(args)
        if adb.dot(ao) > 0:
            args[0] = [a, d, b]
            return CollManager.triSimplex(args)
        return True

    @staticmethod
    def gjk(a, b):
        ab = a.pos - b.pos
        c = Vector3(ab.z, ab.z, -ab.x - ab.y)
        if c == Vector3.zero():
            c = Vector3(-ab.y - ab.z, ab.x, ab.x)

        support = CollManager.supportPoint(a, b, ab.cross(c))
        points = [support]
        direction = -support
        while True:
            support = CollManager.supportPoint(a, b, direction)
            if support.dot(direction) <= 0:
                return None
            points.insert(0, support)
            args = [points, direction]
            if CollManager.nextSimplex(args):
                return args[0]
            points, direction = args

我已经检查了支撑点函数是否按预期工作,因为我已经计算出了它背后的数学。我所做的是创建了两个边长均为2的立方体,位置分别为(0,0,0)和(1,0,0)。计算的第一个方向是 Vector3(0, 1, 0) ,所以单纯形上的第一个点是 Vector3(1, -2, 0) . 第二点,从另一个方向看,正好相反, Vector3(-1, 2, 0) . 这就产生了一个问题,因为创建的下一个方向使用了这两个方向的叉积,这就产生了 Vector3(0, 0, 0) . 显然,没有向量和这个方向相同,所以直线 if support.dot(direction) <= 0: 失败。
但是,将第二个多维数据集移动到1.00000000000001将使函数返回 True ,并将一直执行,直到我将其移动到1.999999999为止。在2处,函数返回 False . 这与-2和-1.0000000000001相同。
如何确保在单纯形上找到的第二个点与第一个点不完全相反,从而使检查提前返回?
最小可复制示例(使用完全相同的代码):


# main.py

from vector3 import Vector3
import math

class BoxCollider:
    def __init__(self, position, side_length):
        self.pos = position
        self.side_length = side_length

    def supportPoint(self, direction):
        maxDistance = -math.inf
        min, max = self.pos - self.side_length // 2, self.pos + self.side_length // 2
        for x in (min.x, max.x):
            for y in (min.y, max.y):
                for z in (min.z, max.z):
                    distance = Vector3(x, y, z).dot(direction)
                    if distance > maxDistance:
                        maxDistance = distance
                        maxVertex = Vector3(x, y, z)
        return maxVertex

def supportPoint(a, b, direction):
    return a.supportPoint(direction) - \
        b.supportPoint(-direction)

def nextSimplex(args):
    length = len(args[0])
    if length == 2:
        return lineSimplex(args)
    if length == 3:
        return triSimplex(args)
    if length == 4:
        return tetraSimplex(args)
    return False

def lineSimplex(args):
    a, b = args[0]
    ab = b - a
    ao = -a
    if ab.dot(ao) > 0:
        args[1] = ab.cross(ao).cross(ab)
    else:
        args[0] = [a]
        args[1] = ao

def triSimplex(args):
    a, b, c = args[0]
    ab = b - a
    ac = c - a
    ao = -a
    abc = ab.cross(ac)
    if abc.cross(ac).dot(ao) > 0:
        if ac.dot(ao) > 0:
            args[0] = [a, c]
            args[1] = ac.cross(ao).cross(ac)
        else:
            args[0] = [a, b]
            return lineSimplex(args)
    elif ab.cross(abc).dot(ao) > 0:
        args[0] = [a, b]
        return lineSimplex(args)
    else:
        if abc.dot(ao) > 0:
            args[1] = abc
        else:
            args[0] = [a, c, b]
            args[1] = -abc
    return False

def tetraSimplex(args):
    a, b, c, d = args[0]
    ab = b - a
    ac = c - a
    ad = d - a
    ao = -a
    abc = ab.cross(ac)
    acd = ac.cross(ad)
    adb = ad.cross(ab)
    if abc.dot(ao) > 0:
        args[0] = [a, b, c]
        return triSimplex(args)
    if acd.dot(ao) > 0:
        args[0] = [a, c, d]
        return triSimplex(args)
    if adb.dot(ao) > 0:
        args[0] = [a, d, b]
        return triSimplex(args)
    return True

def gjk(a, b):
    ab = a.pos - b.pos
    c = Vector3(ab.z, ab.z, -ab.x - ab.y)
    if c == Vector3.zero():
        c = Vector3(-ab.y - ab.z, ab.x, ab.x)

    support = supportPoint(a, b, ab.cross(c))
    points = [support]
    direction = -support
    while True:
        support = supportPoint(a, b, direction)
        if support.dot(direction) <= 0:
            return None
        points.insert(0, support)
        args = [points, direction]
        if nextSimplex(args):
            return args[0]
        points, direction = args

a = BoxCollider(Vector3(0, 0, 0), 2)
b = BoxCollider(Vector3(1, 0, 0), 2)
print(gjk(a, b))

我的vector3.py文件太长,这里有一个等效文件也可以使用:https://github.com/pyunity/pyunity/blob/07fed7871ace0c1b1b3cf8051d08d6677fe18209/pyunity/vector3.py

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题