给定:
在时间0,目标在A点,拦截器在B点。在未来的某个时间点,它们将在C点相交。
线段a与A点相对,b与B、c与C亦然。
我们知道 A 和 B 的位置。我们可以从目标的航向推导出角度 CAB。我们知道线段a和b的长度之比等于(interceptor.speed/target.speed)。
首先,找到角度CAB。
让向量 B^ 等于目标的速度。
让向量 C^ 等于 (interceptor.position.x - target.position.x, interceptor.position.y - target.position.y)。
使用点积公式确定它们之间的角度。
B dot C = ||B|| * ||C|| * cos(angle)
cos(angle) = (B dot C) / (||B|| * ||C||)
angle = arccos((B dot C) / (||B|| * ||C||))
...其中“点”是dot product,而||B||是向量 B 的标量大小。angle 是角度 CAB。
现在我们将找到角 ABC。
使用law of sines,我们知道sin(ABC) / b == sin(CAB) / a。
将等式重新排列为ABC = arcsin( sin(CAB) * (b/a) )。
我们在上一步找到了 CAB,我们知道 b/a 是 target.speed/interceptor.speed,所以将这些值代入并找到 ABC。
现在您知道了两个角和两个点,您应该能够推导出 C 的位置。如果使用度数,角 ACB 等于 180 - (CAB + ABC),或者 Pi - (CAB + ABC ) 如果您使用的是弧度。使用正弦定律确定边 b 和 c 的长度。现在您可以使用T = b / target.speed 找到T,使用C = target.position + (target.velocity * T) 找到C。
我的 C# 有点生疏,所以 here 是一个示例 Python 实现。让我们插入您的示例值,结果是:
Collision pos: Point(163.065368246, 57.2261472985)
Time: 8.61307364926
Angle A: 113.198590514
Angle B: 29.6680851288
Angle C: 37.1333243575
a: 86.1307364926
b: 46.3828210973
c: 56.5685424949
位置和时间与 gdir 找到的相同,因此我非常有信心我们的方法都有效。
编辑:MikeT:C# 版本
public static double Dot(Vector a, Vector b)
{
return a.X * b.X + a.Y * b.Y;
}
public static double Magnitude(Vector vec)
{
return Math.Sqrt(vec.X * vec.X + vec.Y * vec.Y);
}
public static double AngleBetween(Vector b, Vector c)
{
return Math.Acos(Dot(b, c) / (Magnitude(b) * Magnitude(c)));
}
public static Vector? Find_collision_point(Point target_pos, Vector target_vel, Point interceptor_pos, double interceptor_speed)
{
var k = Magnitude(target_vel) / interceptor_speed;
var distance_to_target = Magnitude(interceptor_pos - target_pos);
var b_hat = target_vel;
var c_hat = interceptor_pos - target_pos;
var CAB = AngleBetween(b_hat, c_hat);
var ABC = Math.Asin(Math.Sin(CAB) * k);
var ACB = (Math.PI) - (CAB + ABC);
var j = distance_to_target / Math.Sin(ACB);
var a = j * Math.Sin(CAB);
var b = j * Math.Sin(ABC);
var time_to_collision = b / Magnitude(target_vel);
var collision_pos = target_pos + (target_vel * time_to_collision);
return interceptor_pos - collision_pos;
}