Обнаружение столкновения между 2 «линейно» движущиеся объекты в WGS84

[Полное повторное редактирование 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

TEST CASE 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;

3

Решение

[Edit5] Завершите reedit, если вам нужны старые источники, смотрите историю изменений

Как отметил Нико Шертлер, проверка пересечения между линиями — это безумие, так как вероятность пересечения двух траекторий в одном и том же положении и времени практически отсутствует (даже с учетом совпадений точности округления). Вместо этого вы должны найти место на каждой траектории, которое достаточно близко (чтобы столкнуться), и оба объекта находятся там относительно одновременно. Другая проблема заключается в том, что ваши траектории не являются линейными вообще. Да, они могут казаться линейными для коротких времен в кабине WGS84 и декартовой, но с увеличением времени траектория изгибается вокруг Земли. Кроме того, ваши единицы входных значений для скорости делают это немного сложнее, поэтому позвольте мне повторить нормализованные значения, с которыми я сейчас буду иметь дело:

  1. вход

    состоит из двух объектов. Для каждого известна его фактическая позиция (в WGS84 [rad]) и фактические скорости [m/s] но не в декартовом пространстве, а WGS84 локальные оси вместо. Например что-то вроде этого:

    const double kmh=1.0/3.6;
    const double deg=M_PI/180.0;
    const double rad=180.0/M_PI;
    //                      lon            lat      alt
    double pos0[3]={  23.000000*deg, 48.000000*deg,2500.000000 };
    double pos1[3]={  23.000000*deg, 35.000000*deg,2500.000000 };
    double vel0[3]={ 100.000000*kmh,-20.000000*kmh,   0.000000*kmh };
    double vel1[3]={ 100.000000*kmh, 20.000000*kmh,   0.000000*kmh };
    

    Осторожно, мои координаты находятся в Long,Lat,Alt порядок / соглашение !!!

  2. выход

    Вам необходимо вычислить время, в которое два объекта «сталкиваются». Дополнительные ограничения к решению могут быть добавлены позднее. Как упоминалось ранее, мы ищем не пересечение, а «самый близкий» подход, который удовлетворяет условиям столкновения (например, расстояние меньше некоторого порога).

После некоторого обучения и тестирования я решил использовать итеративный подход в WGS84 пространство. Это поднимает некоторые проблемы, например, как конвертировать скорость в [m/s] в WGS84 пространство для [rad/s] в WGS84 пространство. Это соотношение меняется в зависимости от высоты объекта и широты. На самом деле нам нужно вычислить изменение угла в long а также lat оси, которые «точно» равны 1m пройденное расстояние, а затем умножьте скорости на него. Это может быть аппроксимировано уравнением длины дуги:

l = dang.R

куда R фактический радиус углового перемещения, ang это изменение угла и l пройденное расстояние, поэтому, когда l=1.0 затем:

dang = 1.0/R

Если у нас есть декартова позиция x,y,z (z является осью вращения Земли) тогда:

Rlon = sqrt (x*x + y*y)
Rlat = sqrt (x*x + y*y + z*z)

Теперь мы можем перебирать позиции со временем, которые можно использовать для аппроксимации времени ближайшего сближения. Однако нам нужно ограничить максимальный шаг по времени, чтобы мы не пропускали большую часть кривизны Земли. Этот предел зависит от используемых скоростей и точности цели. Итак, вот алгоритм, чтобы найти подход:

  1. в этом

    установить начальный шаг времени к верхнему пределу, как dt=1000.0 и вычислить фактическое положение объектов стенда в декартовом пространстве. Из этого вычислить их расстояние d1,

  2. итерация

    задавать d0=d1 затем вычислите фактические скорости в WGS84 для фактических позиций и добавить speed*dt каждому объекту актуально WGS84 позиция. Теперь просто вычислите фактические позиции в декартовом пространстве и вычислите их расстояние d1

    если d0>d1 затем мы приближаемся к ближайшему подходу, так что # 2 снова.

    В случае d0==d1 траектории параллельны, поэтому время возврата t=0.0

    В случае d0<d1 мы уже перешли самый близкий подход, так что установите dt = -0.1*dt и если dt>=desired_accuracy идти к # 2 иначе остановись.

  3. восстановить лучше t

    После итерации в # 2 мы должны восстановить лучшее время назад, чтобы вернуться t+10.0*dt;

Теперь у нас самое близкое время приближения t, Остерегайтесь, это может быть отрицательным (если объекты удаляются друг от друга). Теперь вы можете добавить свои ограничения как

if (d0<_max_d)
if ((t>=0.0)&&(t<=_max_T))
return collision ...

Вот C ++ Источник для этого:

//---------------------------------------------------------------------------
#include <math.h>
//---------------------------------------------------------------------------
const double kmh=1.0/3.6;
const double deg=M_PI/180.0;
const double rad=180.0/M_PI;
const double  _earth_a=6378137.00000;   // [m] WGS84 equator radius
const double  _earth_b=6356752.31414;   // [m] WGS84 epolar radius
const double  _earth_e=8.1819190842622e-2; //  WGS84 eccentricity
const double  _earth_ee=_earth_e*_earth_e;
//--------------------------------------------------------------------------
const double _max_d=2500.0;         // [m] collision gap
const double _max_T=3600000.0;      // [s] max collision time
const double _max_dt=1000.0;        // [s] max iteration time step (for preserving accuracy)
//--------------------------------------------------------------------------
//                      lon            lat      alt
double pos0[3]={  23.000000*deg, 48.000000*deg,2500.000000 }; // [rad,rad,m]
double pos1[3]={  23.000000*deg, 35.000000*deg,2500.000000 }; // [rad,rad,m]
double vel0[3]={ 100.000000*kmh,-20.000000*kmh,   0.000000*kmh }; // [m/s,m/s,m/s]
double vel1[3]={ 100.000000*kmh,+20.000000*kmh,   0.000000*kmh }; // [m/s,m/s,m/s]
//---------------------------------------------------------------------------
double divide(double x,double y)
{
if ((y>=-1e-30)&&(y<=+1e-30)) return 0.0;
return x/y;
}
void  vector_copy(double *c,double *a)         { for(int i=0;i<3;i++) c[i]=a[i];       }
double vector_len(double *a) { return sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2])); }
void  vector_len(double *c,double *a,double l)
{
l=divide(l,sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2])));
c[0]=a[0]*l;
c[1]=a[1]*l;
c[2]=a[2]*l;
}
void  vector_sub(double *c,double *a,double *b) { for(int i=0;i<3;i++) c[i]=a[i]-b[i]; }
//---------------------------------------------------------------------------
void WGS84toXYZ(double *xyz,double *abh)
{
double  a,b,h,l,c,s;
a=abh[0];
b=abh[1];
h=abh[2];
c=cos(b);
s=sin(b);
// WGS84 from eccentricity
l=_earth_a/sqrt(1.0-(_earth_ee*s*s));
xyz[0]=(l+h)*c*cos(a);
xyz[1]=(l+h)*c*sin(a);
xyz[2]=(((1.0-_earth_ee)*l)+h)*s;
}
//---------------------------------------------------------------------------
void WGS84_m2rad(double &da,double &db,double *abh)
{
// WGS84 from eccentricity
double p[3],rr;
WGS84toXYZ(p,abh);
rr=(p[0]*p[0])+(p[1]*p[1]);
da=divide(1.0,sqrt(rr));
rr+=p[2]*p[2];
db=divide(1.0,sqrt(rr));
}
//---------------------------------------------------------------------------
double collision(double *pos0,double *vel0,double *pos1,double *vel1)
{
int e,i,n;
double p0[3],p1[3],q0[3],q1[3],da,db,dt,t,d0,d1,x,y,z;
vector_copy(p0,pos0);
vector_copy(p1,pos1);
// find closest d1[m] approach in time t[sec]
dt=_max_dt; // [sec] initial time step (accuracy = dt/10^(n-1)
n=6;        // acuracy loops
for (t=0.0,i=0;i<n;i++)
for (e=0;;e=1)
{
d0=d1;
// compute xyz distance
WGS84toXYZ(q0,p0);
WGS84toXYZ(q1,p1);
vector_sub(q0,q0,q1);
d1=vector_len(q0);
// nearest approach crossed?
if (e)
{
if (d0<d1){ dt*=-0.1; break; }                  // crossing trajectories
if (fabs(d0-d1)<=1e-10) { i=n; t=0.0; break; }  // parallel trajectories
}
// apply time step
t+=dt;
WGS84_m2rad(da,db,p0);
p0[0]+=vel0[0]*dt*da;
p0[1]+=vel0[1]*dt*db;
p0[2]+=vel0[2]*dt;
WGS84_m2rad(da,db,p1);
p1[0]+=vel1[0]*dt*da;
p1[1]+=vel1[1]*dt*db;
p1[2]+=vel1[2]*dt;
}
t+=10.0*dt; // recover original t
//  if ((d0<_max_d)&&(t>=0.0)&&(t<=_max_T)) return collision; else return no_collision;
return t;
}
//---------------------------------------------------------------------------

Вот краткий обзор примера:

обзор

Красный — это объект0, а зеленый — это объект1. Белые квадраты представляют положение при вычисленном столкновении во время t_coll [s] с расстояния d_coll [m], Желтые квадраты — это позиции в определенное пользователем время. t_anim [s] с расстояния d_anim [m] который контролируется пользователем в целях отладки. Как вы можете видеть, этот подход работает также в течение 36 часов …

Надеюсь, я не забыл скопировать что-то (если да, прокомментируйте меня, и я добавлю это)

2

Другие решения

Вы не показываете никакого кода, поэтому я просто дам основные идеи и оставлю кодирование вам. Возвращайтесь, если вы попробуете какой-то код и застряли, но покажите свои усилия и свой код.

Есть несколько способов решить вашу проблему. Один из способов — установить параметрические уравнения для каждого объекта, предоставляя две ваши функции по времени. t, Установите результаты этих функций равными и решите за время. Для трехмерных координат, которые дают вам три вопроса, по одному для каждой координаты, и очень маловероятно, что значения t будет одинаковым для всех трех уравнений. Если они одинаковы, то это время вашего столкновения.

Другой способ, который допускает некоторые ошибки округления с плавающей запятой, состоит в том, чтобы изменить систему отсчета для одного из объектов. Вы вычитаете два вектора скорости, скажем v2-v1и теперь у вас есть скорость второго объекта относительно первого объекта. Теперь найдите расстояние от ныне неподвижного первого объекта до линии движущегося второго объекта. Если вы не знаете, как это сделать, найдите «расстояние от точки до линии» в своей любимой поисковой системе. Затем вы видите, достаточно ли это расстояние для вас, чтобы рассматривать его как столкновение — вы вряд ли получите идеальное столкновение с нулевым расстоянием, учитывая ошибки округления с плавающей точкой. Если он достаточно мал, вы увидите, достигнуто ли это столкновение в будущем или в прошлом. Возможно, вы захотите найти проекцию точки на линии в качестве промежуточного значения для этого последнего расчета.

Это понятно?

1

По вопросам рекламы [email protected]