如何检查单纯形是否包含原点?

时间:2014-02-17 01:10:14

标签: math haskell physics linear-algebra collision

我正在实现Gilbert-Johnson-Keerthi算法,该算法计算两个对象是否相交(即碰撞)。

我的代码的入口点是hasCollided函数,它接受两个点列表,如果它们相交则返回True。我相信我已经正确地实现了论文 - 但是,我仍然需要实现contains函数。

contains函数应确定单纯形是否包含原点。我不确定如何实现这一点。

如何有效地确定单面(点集合)是否包含原点?


以下是我的实施:

type Simplex = Set (Vector Double)

hasCollided :: [Vector Double] -> [Vector Double] -> Bool
hasCollided points1 points2 = gjk points1 points2 simplex (scale (-1) direction) p
  where simplex   = insert p empty
        p         = support points1 points2 direction
        direction = fromList [1, 0, 0]

gjk :: [Vector Double] -> [Vector Double] -> Simplex -> Vector Double -> Vector Double -> Bool
gjk points1 points2 simplex direction lastAdded =
  if p <.> direction < 0 then False
  else
    if contains simplex' (fromList [0, 0, 0]) direction p then True
    else gjk points1 points2 simplex' direction' p
  where p          = support points1 points2 direction
        simplex'   = insert p simplex
        direction' = cross ab $ cross ao ab
        ab         = sub p lastAdded
        ao         = sub origin3D lastAdded

辅助函数是:

contains :: Simplex -> Vector Double -> Vector Double -> Vector Double -> Bool
contains simplex point direction lastAdded = undefined


support :: [Vector Double] -> [Vector Double] -> Vector Double -> Vector Double
support points1 points2 direction = sub p1 p2
  where p1 = getFarthestPoint points1 direction
        p2 = getFarthestPoint points2 direction

getFarthestPoint :: [Vector Double] -> Vector Double -> Vector Double
getFarthestPoint points direction = points !! index
  where index       = fromJust $ elemIndex (maximum dotproducts) dotproducts
        dotproducts = map (direction <.>) points

origin3D :: Vector Double
origin3D = fromList [0, 0, 0]

3 个答案:

答案 0 :(得分:7)

我会采取非聪明的方式,让我们做一些线性代数来解决它&#34;方法

单形内的每个点都是定义单形的点的convex combination。凸组合只是线性组合,其中系数都>≥0并且加起来为1.

&#34;单纯形是否包含原点&#34;与询问是否存在等于零向量的单纯点的凸组合相同。我们可以把它写成矩阵表达式吗?

我们说我们正在使用由四个向量定义的单纯形,x1x4

我们将形成这些向量y = a1*x1 + a2*x2 + a3*x3 + a4*x4的任意线性组合。

我们希望找到a1a4,以便y是零向量和a1 + a2 + a3 + a4 = 1

如果单纯形是三维欧几里德空间中的点,我将展示线性系统的样子。让向量xi包含组件xi1xi2xi3

[ x11  x21  x31  x41 ] [ a1 ]   [ 0 ]
[ x12  x22  x32  x42 ] [ a2 ] = [ 0 ]
[ x13  x23  x33  x43 ] [ a3 ]   [ 0 ]
[  1    1    1    1  ] [ a4 ]   [ 1 ]

此线性系统的前三行对应y必须为零的约束,即我们可以通过x1x4的某些线性组合来到原点。最后一行对应于系数加起来为1的约束,这对于线性组合是凸组合是必要但不充分的。矩阵方程未表示的约束是ai >= 0

选择您最喜欢的解决线性系统的方法并应用它。如果组成单形的向量是线性独立的,那么您将无法找到任何解决方案。如果线性系统有一个或多个解决方案,至少有一个解决方案具有全部ai >= 0,那么单纯形就包含原点。

对于最后一步的算法,我没有任何准备好的描述,确定解决方案集是否包括所有系数均为正的任何点。我建议在纸上写几个例子 - 我希望你能找到一个。

编辑:确定解集是否包括所有系数均为正的任何点实际上与确定解空间与ai >= 0的交集所定义的单形是否包括除原点之外的任何点相同。 / p>

这意味着这种解决方案可以减少

的问题

&#34; 输入单纯 是否包含原点?&#34;

&#34; 另一个单纯形(从输入单纯形中派生)是否包含除原点之外的任何点?&#34;

我认为这是将问题转移到另一个问题(希望更容易)的一个可爱的例子。

答案 1 :(得分:5)

要严格确定该点是否属于单纯形或无,您只需要知道最大d + 2d * d大小j,k行列式的符号。

让:

simplex and point

然后我们可以构造一个矩阵(j索引意味着:排除k行,并从剩余d个行中的每个j中减去向量到点d!;所有行中的左侧边定义了一个面向d顶点的小平面:

determinant of this is <code>d!</code> times of oriented hypervolume of simplex constructed from points involved

上述矩阵的行列式是j0 - 单向的面向维度的超体积,由公式中涉及的点构成(严格地说是并行交换的定向超体积,其边缘给出通过矩阵行)。

如果点在单纯形内部,则以下所有方程都为真(匹配?j点相对于小平面的方向(定向超体积的符号):

The Condition

但我们可以注意到,

source for simplification

因此,我们只能从比较的左侧计算一个决定因素(2):

A^{j,j}, j = 1

并假设,该标志会翻转下一个d*d s。

因此,我们应该至少计算d + 2矩阵的j个决定因素,以及最大{{1}}(A 1,1 和A j,0 。如果某个步骤上的符号不匹配,则该点在单纯形的当前面之外,从而完全不在单纯形中。

其他

如果右侧的一些决定因素为零,则该点与相应方面的平面共面。

答案 2 :(得分:0)

您可以使用重心坐标! 检查 this 问题的答案以查看详细信息。

查看点 $p = (p_1, \dots, p_n)$ 是否属于单纯形的想法是将其写在重心坐标 $p_\lambda = (\lambda_1, \dots, \lambda_n)$ 中尊重你想检查的单纯形。

如果$p$的重心坐标满足

$$ \lambda_i \ge 0,\ \sum \lambda_i \le 1, \i = 1, \dots, n+1 $$

那么 $p$ 属于单纯形。否则就不行。

这减少了寻找点的重心坐标的问题。