我正在实现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]
答案 0 :(得分:7)
我会采取非聪明的方式,让我们做一些线性代数来解决它&#34;方法
单形内的每个点都是定义单形的点的convex combination。凸组合只是线性组合,其中系数都>≥0并且加起来为1.
&#34;单纯形是否包含原点&#34;与询问是否存在等于零向量的单纯点的凸组合相同。我们可以把它写成矩阵表达式吗?
我们说我们正在使用由四个向量定义的单纯形,x1
到x4
。
我们将形成这些向量y = a1*x1 + a2*x2 + a3*x3 + a4*x4
的任意线性组合。
我们希望找到a1
到a4
,以便y
是零向量和a1 + a2 + a3 + a4 = 1
。
如果单纯形是三维欧几里德空间中的点,我将展示线性系统的样子。让向量xi
包含组件xi1
,xi2
和xi3
。
[ 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
必须为零的约束,即我们可以通过x1
到x4
的某些线性组合来到原点。最后一行对应于系数加起来为1的约束,这对于线性组合是凸组合是必要但不充分的。矩阵方程未表示的约束是ai >= 0
。
选择您最喜欢的解决线性系统的方法并应用它。如果组成单形的向量是线性独立的,那么您将无法找到任何解决方案。如果线性系统有一个或多个解决方案和,至少有一个解决方案具有全部ai >= 0
,那么单纯形就包含原点。
对于最后一步的算法,我没有任何准备好的描述,确定解决方案集是否包括所有系数均为正的任何点。我建议在纸上写几个例子 - 我希望你能找到一个。
编辑:确定解集是否包括所有系数均为正的任何点实际上与确定解空间与ai >= 0
的交集所定义的单形是否包括除原点之外的任何点相同。 / p>
这意味着这种解决方案可以减少
的问题&#34; 输入单纯 是否包含原点?&#34;
到
&#34; 另一个单纯形(从输入单纯形中派生)是否包含除原点之外的任何点?&#34;
我认为这是将问题转移到另一个问题(希望更容易)的一个可爱的例子。
答案 1 :(得分:5)
要严格确定该点是否属于单纯形或无,您只需要知道最大d + 2
个d * d
大小j,k
行列式的符号。
让:
然后我们可以构造一个矩阵(j
索引意味着:排除k
行,并从剩余d
个行中的每个j
中减去向量到点d!
;所有行中的左侧边定义了一个面向d
顶点的小平面:
上述矩阵的行列式是j
次0
- 单向的面向维度的超体积,由公式中涉及的点构成(严格地说是并行交换的定向超体积,其边缘给出通过矩阵行)。
如果点在单纯形内部,则以下所有方程都为真(匹配?
和j
点相对于小平面的方向(定向超体积的符号):
但我们可以注意到,
因此,我们只能从比较的左侧计算一个决定因素(2
):
并假设,该标志会翻转下一个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$ 属于单纯形。否则就不行。
这减少了寻找点的重心坐标的问题。