基于xyz的3d碰撞公式
3d collision formula based on xyz
问题来了。我们在 xyz 中有两个点(球体),信息如下:
1- x,y,z => 对象的中心当前位于
2- r => 物体的碰撞半径
3- Vx, Vy, Vz => 物体沿着向量行进。如果该向量是 (0,0,0),则对象是静止的。
注意:半径和位置以米为单位,速度以米/秒为单位。
问题:对于每个测试,输出一行包含自测试开始以来两个对象首次碰撞的时间(以秒为单位)。如果它们从未发生碰撞,则改为打印 No collision。
我想知道这次的计算公式。任何想法将不胜感激。
示例:
1-
xyz(1): -7 5 0
v(1): -1 0 3
r(1): 3
xyz(2): 10 7 -6
v(2): -2 0 4
r(2): 6
t: 8.628 // this is the answer
2-
xyz(1): 10 3 -10
v(1): -9 3 -8
r(1): 5
xyz(2): 2 0 0
v(2): 6
r(2): -4 3 -10
t: 0.492 // this is the answer
为了简化问题,让我们使用哈利略原理。将第一个对象作为基点,因此第二个对象相对于它移动。
将第一个对象位置放在坐标原点。
从第二个坐标减去第一个对象初始坐标,对速度分量做同样的事情
x2_0 = x2_0 - x1_0 (same for y,z)
Vx2 = Vx2 - Vx1 (same for y,z)
现在我们有了相对于时间的第二个中心坐标
x = x2_0 + Vx2 * t
y = y2_0 + Vy2 * t
z = z2_0 + Vz2 * t
和到原点的平方距离:
dd = x*x + y*y + z*z =
(x2_0 + Vx2 * t)^2 + ... =
x2_0^2 + 2*x2_0*Vx2*t + Vx2^2*t^2 + ...
我们需要计算什么时候dd
等于半径平方和(r1+r2)^2
t^2 * (Vx2^2+Vy2^2+Vz2^2) + t*(2*x2_0*Vx2+2*y2_0*Vy2+2*z2_0*Vz2) +
x2_0^2 + y2_0^2 + y2_0^2 - (r1+r2)^2 = 0
求解此二次方程 t
,得到 0,1 或 2 个解。
案例 0 个解决方案 - 无碰撞
1 个解决方案的案例 t
- 触摸时刻
两种解决方案的情况 - 在碰撞时刻获得更小的正值 t
。
t
的负值表示碰撞“过去”,在测试开始之前
快速测试 Python (ideone)
from math import sqrt, isclose
def collisiontime(x1,y1,z1,vx1,vy1,vz1,r1, x2,y2,z2,vx2,vy2,vz2,r2):
x2 -= x1
y2 -= y1
z2 -= z1
vx2 -= vx1
vy2 -= vy1
vz2 -= vz1
a = vx2**2 + vy2**2 + vz2**2
b = 2*x2*vx2 + 2*y2*vy2 + 2*z2*vz2
c = x2**2 + y2**2 + z2**2 - (r1+r2)**2
D = b**2-4*a*c
if D < 0:
return None
if isclose(D, 0):
return -b/2/a
return (-b - sqrt(D)) / 2 /a, (-b + sqrt(D)) / 2 /a
print(collisiontime(0, 0, 0, 2, 0, 0, 2, 25, 0, 0, -3, 0, 0, 3)) # 1=> <=2
print(collisiontime(0, 0, 0, 2, 0, 0, 2, 25, 5, 0, 1, 0, 0, 3)) # 1==> 2=> chase with touching
print(collisiontime(-7, 5, 0,-1, 0, 3, 3, 10, 7, -6, -2, 0, 4, 6))
print(collisiontime(10, 3, -10,-9, 3, -8,5, 2, 0, 0, -4, 3, -10, 6))
(4.0, 6.0)
25.0
(8.627718676730986, 14.372281323269014)
(0.4917797757201004, 3.646151258762658)
问题来了。我们在 xyz 中有两个点(球体),信息如下:
1- x,y,z => 对象的中心当前位于
2- r => 物体的碰撞半径
3- Vx, Vy, Vz => 物体沿着向量行进。如果该向量是 (0,0,0),则对象是静止的。
注意:半径和位置以米为单位,速度以米/秒为单位。
问题:对于每个测试,输出一行包含自测试开始以来两个对象首次碰撞的时间(以秒为单位)。如果它们从未发生碰撞,则改为打印 No collision。
我想知道这次的计算公式。任何想法将不胜感激。
示例:
1-
xyz(1): -7 5 0
v(1): -1 0 3
r(1): 3
xyz(2): 10 7 -6
v(2): -2 0 4
r(2): 6
t: 8.628 // this is the answer
2-
xyz(1): 10 3 -10
v(1): -9 3 -8
r(1): 5
xyz(2): 2 0 0
v(2): 6
r(2): -4 3 -10
t: 0.492 // this is the answer
为了简化问题,让我们使用哈利略原理。将第一个对象作为基点,因此第二个对象相对于它移动。
将第一个对象位置放在坐标原点。
从第二个坐标减去第一个对象初始坐标,对速度分量做同样的事情
x2_0 = x2_0 - x1_0 (same for y,z)
Vx2 = Vx2 - Vx1 (same for y,z)
现在我们有了相对于时间的第二个中心坐标
x = x2_0 + Vx2 * t
y = y2_0 + Vy2 * t
z = z2_0 + Vz2 * t
和到原点的平方距离:
dd = x*x + y*y + z*z =
(x2_0 + Vx2 * t)^2 + ... =
x2_0^2 + 2*x2_0*Vx2*t + Vx2^2*t^2 + ...
我们需要计算什么时候dd
等于半径平方和(r1+r2)^2
t^2 * (Vx2^2+Vy2^2+Vz2^2) + t*(2*x2_0*Vx2+2*y2_0*Vy2+2*z2_0*Vz2) +
x2_0^2 + y2_0^2 + y2_0^2 - (r1+r2)^2 = 0
求解此二次方程 t
,得到 0,1 或 2 个解。
案例 0 个解决方案 - 无碰撞
1 个解决方案的案例 t
- 触摸时刻
两种解决方案的情况 - 在碰撞时刻获得更小的正值 t
。
t
的负值表示碰撞“过去”,在测试开始之前
快速测试 Python (ideone)
from math import sqrt, isclose
def collisiontime(x1,y1,z1,vx1,vy1,vz1,r1, x2,y2,z2,vx2,vy2,vz2,r2):
x2 -= x1
y2 -= y1
z2 -= z1
vx2 -= vx1
vy2 -= vy1
vz2 -= vz1
a = vx2**2 + vy2**2 + vz2**2
b = 2*x2*vx2 + 2*y2*vy2 + 2*z2*vz2
c = x2**2 + y2**2 + z2**2 - (r1+r2)**2
D = b**2-4*a*c
if D < 0:
return None
if isclose(D, 0):
return -b/2/a
return (-b - sqrt(D)) / 2 /a, (-b + sqrt(D)) / 2 /a
print(collisiontime(0, 0, 0, 2, 0, 0, 2, 25, 0, 0, -3, 0, 0, 3)) # 1=> <=2
print(collisiontime(0, 0, 0, 2, 0, 0, 2, 25, 5, 0, 1, 0, 0, 3)) # 1==> 2=> chase with touching
print(collisiontime(-7, 5, 0,-1, 0, 3, 3, 10, 7, -6, -2, 0, 4, 6))
print(collisiontime(10, 3, -10,-9, 3, -8,5, 2, 0, 0, -4, 3, -10, 6))
(4.0, 6.0)
25.0
(8.627718676730986, 14.372281323269014)
(0.4917797757201004, 3.646151258762658)