先构建两个矩形:
aOrigin = np.array([
[2, 1],
[5, 1],
[5, 3],
[2, 3],
])
bOrigin = np.array([
[2, 3],
[4, 3],
[4, 4],
[2, 4],
])
# 中心点位置
aPosOrigin = np.array([3.5, 2])
bPosOrigin = np.array([3, 3.5])
# x,y一半的长度
ahOrigin = np.array([1.5, 1])
bhOrigin = np.array([1, 0.5])
加入旋转:
rotateA = np.array([
[math.cos(math.pi / 180 * 40), math.sin(math.pi / 180 * 40) * -1],
[math.sin(math.pi / 180 * 40), math.cos(math.pi / 180 * 40)]
])
rotateB = np.array([
[math.cos(math.pi / 180 * 50), math.sin(math.pi / 180 * 50) * -1],
[math.sin(math.pi / 180 * 50), math.cos(math.pi / 180 * 50)]
])
iRotateA = np.linalg.inv(rotateA) # A的逆矩阵,后续有用
a = np.array([rotateA.dot(item) for item in aOrigin])
b = np.array([rotateB.dot(item) for item in bOrigin])
aPos = rotateA.dot(aPosOrigin)
bPos = rotateB.dot(bPosOrigin)
此刻我们得到了两个旋转过的矩形,下面来判断它两是否有重叠部分
首先我们将坐标系变换为以a矩形的旋转为基准的坐标系,这样做可以让a矩形变为横平竖直方便后续计算
aBase = np.array([iRotateA.dot(item) for item in a])
iAPos = iRotateA.dot(aPos)
接下里将b矩形也变换到a矩形的坐标系中
bBase = np.array([iRotateA.dot(item) for item in b])
iBPos = iRotateA.dot(bPos)
此时让两个矩形的中心点向量相减就可以得到中心点之间的x,y轴距离
posTotal = abs(iBPos - iAPos) # array([1.15334536, 1.96777167])
中心点x轴相差1.15334536,y轴差1.96777167
在建立矩形时我们已知了横屏竖直的a矩形的x,y一半的长度为变量ahOrigin 如果我们计算出此时b矩形的最大x,y一半的长度(下图绿色线段,假设为bh)
则posTotal - bh - ahOrigin得到的向量如果x,y都为负数则两个矩形是有重叠的
遍历b矩形四个点即可求出bh,这里我们介绍一种无需遍历的方法:
我们已知横平竖直的b矩形的最大x,y的一半为bhOrigin,b矩形一共经历了两次旋转变换rotateB和iRotateA
先合并两次变换:
rotateC = iRotateA.dot(rotateB)
将rotateC取绝对值,再点乘bhOrigin即可得到bh
bh = np.array([ abs(item) for item in rotateC ]).dot(bhOrigin)
posTotal - bh - ahOrigin # 结果:array([-1.41828648, 0.30171961]) x,y不全为负,所以不碰撞
下面介绍下bh的求法原理(个人理解,有不对请评论指出):
由矩阵乘法公式我们可以得到rotateC和一个点的点积结果的x轴值为(y轴同理):
cos * x - sin * y
cos和sin在坐标系四个象限的正负分别是
[+, +]
[-, +]
[-, -]
[+, -]
我们现在以b矩形的中心为[0, 0]点
f向量为bhOrigin
假设现在旋转角度为30度(第一象限),那么cos和sin都为正,矩形四个点的坐标为:
cos * -1 - sin * 0.5
cos * 1 - sin * 0.5
cos * 1 + sin * 0.5
cos * -1 + sin * 0.5
最大的x轴值为 cos * 1 + sin * 0.5
假设现在旋转角度为100度(第二象限),那么cos是负,sin是正,矩形四个点的坐标为:
cos * 1 - sin * 0.5
-cos * 1 - sin * 0.5
-cos * 1 + sin * 0.5
cos * 1 + sin * 0.5
最大的x轴值还是 cos * 1 + sin * 0.5
以此类推会发现无论旋转角度在哪个象限最大的x轴值都是 cos * 1 + sin * 0.5
所以仅需将变换矩阵每一项取绝对值然后点乘bhOrigin,即可得到想要的bh
参考资料: box2d-lite Box2D-Lite源码阅读笔记