[由 Spektre 完成重新编辑] 基于评论
我有两个 3D 起点和速度矢量(WGS84)我如何检查它们是否在某个指定时间内以 3D 形式发生碰撞?
样本输入:
// WGS84 objects positions
const double deg=M_PI/180.0;
double pos0[3]={17.76 *deg,48.780 *deg,6054.0}; // lon[rad],lat[rad],alt[m]
double pos1[3]={17.956532816382374*deg,48.768667387202690*deg,3840.0}; // lon[rad],lat[rad],alt[m]
// WGS84 speeds in [km/h] not in [deg/sec]!!!
double vel0[3]={- 29.346910862289782, 44.526061886823861,0.0}; // [km/h] lon,lat,alt
double vel1[3]={- 44.7 ,-188.0 ,0.0}; // [km/h] lon,lat,alt
在这里正确地将位置转换为笛卡尔坐标(使用下面链接的在线转换器):
double pos0[3]={ 4013988.58505233,1285660.27718040,4779026.13957769 }; // [m]
double pos1[3]={ 4009069.35282446,1299263.86628867,4776529.76526759 }; // [m]
这些使用我从下面链接的 QA 进行的转换(差异可能是由不同的椭球和/或浮点错误引起的):
double pos0[3] = { 3998801.90188399, 1280796.05923908, 4793000.78262020 }; // [m]
double pos1[3] = { 3993901.28864493, 1294348.18237911, 4790508.28581325 }; // [m]
double vel0[3] = { 11.6185787807449, 41.1080659685389, 0 }; // [km/h]
double vel1[3] = { 17.8265828114202,-173.3281435179590, 0 }; // [km/h]
我的问题是:如何检测物体是否会碰撞以及何时发生碰撞?
我真正需要的是如果在某个指定时间内发生碰撞,例如_min_t
.
当心速度是在[km/h]
局部North,East,High/Up
向量的方向上!有关将此类速度转换为笛卡尔坐标的更多信息,请参阅相关:
要验证/检查 WGS84 位置变换,您可以使用以下在线计算器:
如果可能的话,我想避免使用网格、基元或类似的东西。
这是安德烈试图解决这个问题(基于我的回答,但缺少速度转换)从原始帖子中留下:
bool collisionDetection()
{
const double _min_t = 10.0; // min_time
const double _max_d = 5000; // max_distance
const double _max_t = 0.001; // max_time
double dt;
double x, y, z, d0, d1;
VectorXYZd posObj1 = WGS84::ToCartesian(m_sPos1);
VectorXYZd posObj2 = WGS84::ToCartesian(m_sPos2);
const QList<QVariant> velocity;
if (velocity.size() == 3)
{
dt = _max_t;
x = posObj1 .x - posObj2 .x;
y = posObj1 .y - posObj2 .y;
z = posObj1 .z - posObj2 .z;
d0 = sqrt((x*x) + (y*y) + (z*z));
x = posObj1 .x - posObj2 .x + (m_sVelAV.x - velocity.at(0).toDouble())*dt;
y = posObj1 .y - posObj2 .y + (m_sVelAV.y - velocity.at(1).toDouble())*dt;
z = posObj1 .z - posObj2 .z + (m_sVelAV.z - velocity.at(2).toDouble())*dt;
d1 = sqrt((x*x) + (y*y) + (z*z));
double t = (_max_d - d0)*dt / (d1 - d0);
if (d0 <= _max_d)
{
return true;
}
if (d0 <= d1)
{
return false;
}
if (t < _min_t)
{
return true;
}
}
return false;
}
这应该是有效的笛卡尔变换位置和速度,但由于x, y, z
参数顺序错误而错误变换。上面的数据是正确的lon, lat, alt
,x, y, z
这显然不是:
posObject2 = {x=1296200.8297778680 y=4769355.5802477235 z=4022514.8921807557 }
posObject1 = {x=1301865.2949957885 y=4779902.8263504291 z=4015541.3863254949 }
velocity object 2: x = -178, y = -50, z = 8
velocity object 1: x = 0, y = -88, z = 0;
更不用说速度仍然不在笛卡尔空间上......
编辑:新测试用例
m_sPosAV = {North=48.970020901863471 East=18.038928517158574 Altitude=550.00000000000000 }
m_position = {North=48.996515594886858 East=17.989637729707006 Altitude=550.00000000000000 }
d0 = 4654.6937995573062
d1 = 4648.3896597230259
t = 65.904213878080199
dt = 0.1
velocityPoi = {x=104.92401431817457 y=167.91352303897233 z=0.00000000000000000 }
m_sVelAV = {x=0.00000000000000000 y=0.00000000000000000 z=0.00000000000000000 }
另一个测试用例:
m_sPosAV = {North=49.008020930461598 East=17.920928503349856 Altitude=550.00000000000000 }
m_position = {North=49.017421151053824 East=17.989399013104570 Altitude=550.00000000000000 }
d0 = 144495.56021027692
d1 = 144475.91709961568
velocityPoi = {x=104.92401431817457 y=167.91352303897233 z=0.00000000000000000 }
m_sVelAV = {x=0.89000000000000001 y=0.00000000000000000 z=0.
00000000000000000 }
t = 733.05884538126884
测试用例 3 碰撞时间为 0
m_sPosAV = {North=48.745020278145105 East=17.951529239281793 Altitude=4000.0000000000000 }
m_position = {North=48.734919749542570 East=17.943535418223373 Altitude=4000.0000000000000 }
v1 = {61.452929549676597, -58.567847120366054, 8.8118360639107198}
v0 = {0.00000000000000000, 0.00000000000000000, 0.00000000000000000}
pos0 = {0.85076109780503417, 0.31331329099350030, 4000.0000000000000}
pos1 = {0.85058481032472799, 0.31317377249621559, 3993.0000000000000}
d1 = 2262.4742373961790
最后一个测试案例:
p0 = 0x001dc7c4 {3933272.5980855357, 4681348.9804422557, 1864104.1897091190}
p1 = 0x001dc7a4 {3927012.3039519843, 4673002.8791717924, 1856993.0651808924}
dt = 100;
n = 6;
v1 = 0x001dc764 {18.446446996578750, 214.19570794229870, -9.9777430316824578}
v0 = 0x001dc784 {0.00000000000000000, 0.00000000000000000, 0.00000000000000000}
const double _max_d = 2500;
double _max_T = 120;
最终测试用例:
m_sPosAV = {North=49.958099932390311 East=16.958899924978102 Altitude=9000.0000000000000 }
m_position = {North=49.956106045262935 East=16.928683918401916 Altitude=9000.0000000000000 }
p0 = 0x0038c434 {3931578.2438977188, 4678519.9203961492, 1851108.3449359399}
p1 = 0x0038c414 {3933132.4705292359, 4679955.4705412844, 1850478.2954359739}
vel0 = 0x0038c3b4 {0.00000000000000000, 0.00000000000000000, 0.00000000000000000}
vel1 = 0x0038c354 {-55.900000000000006, 185.69999999999999, -8.0000000000000000}
dt = 1; // [sec] initial time step (accuracy = dt/10^(n-1)
n = 5; // accuracy loops
最终代码:
const double _max_d = 2500; // max_distance m
m_Time = 3600.0;
int i, e, n;
double t, dt;
double x, y, z, d0, d1 = 0;
double p0[3], p1[3], v0[3], v1[3];
double vel0[3], pos0[3], pos1[3], vel1[3];
vel0[0] = m_sVelAV.x;
vel0[1] = m_sVelAV.y;
vel0[2] = m_sVelAV.z;
vel1[0] = velocityPoi.x;
vel1[1] = velocityPoi.y;
vel1[2] = velocityPoi.z;
pos0[0] = (m_sPosAV.GetLatitude()*pi) / 180;
pos0[1] = (m_sPosAV.GetLongitude()*pi) / 180;
pos0[2] = m_sPosAV.GetAltitude();
pos1[0] = (poi.Position().GetLatitude()*pi) / 180;
pos1[1] = (poi.Position().GetLongitude()*pi) / 180;
pos1[2] = poi.Position().GetAltitude();
WGS84toXYZ_posvel(p0, v0, pos0, vel0);
WGS84toXYZ_posvel(p1, v1, pos1, vel1);
dt = 1; // [sec] initial time step (accuracy = dt/10^(n-1)
n = 5; // accuracy loops
for (t = 0.0, i = 0; i<n; i++)
for (e = 1; t <= m_Time; t += dt)
{
d0 = d1;
// d1 = relative distance in time t
x = p0[0] - p1[0] + (v0[0] - v1[0])*t;
y = p0[1] - p1[1] + (v0[1] - v1[1])*t;
z = p0[2] - p1[2] + (v0[2] - v1[2])*t;
d1 = sqrt((x*x) + (y*y) + (z*z));
if (e) { e = 0; continue; }
// if bigger then last step stop (and search with 10x smaller time step)
if (d0<d1) { d1 = d0; t -= dt + dt; dt *= 0.1; if (t<0.0) t = 0.0; break; }
}
// handle big distance as no collision
if (d1 > _max_d) return false;
if (t >= m_Time) return false;
qDebug() << "Collision at time t= " << t;