Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Вычисление расстояния между двумя координатами X, Y в PHP

Автор вопроса: UmopepisdnОтветов: 7

Я пишу инструмент для игры, которая включает в себя вычисление расстояния между двумя координатами на тороидальной плоскости 500 единиц в поперечнике. То есть от [0,0] до [499,499] являются допустимыми координатами, а [0,0] и [499,499] также находятся рядом друг с другом.

В настоящее время в моем приложении я сравниваю расстояние между городом с местоположением [X, Y] относительно собственного местоположения пользователя [X, Y], которое они настроили заранее.

Для этого я нашел такой алгоритм, который вроде работает:

Math.sqrt ( dx * dx + dy * dy );

Поскольку сортировка списка страниц по расстоянию полезна, я реализовал этот алгоритм в запросе MySQL и сделал его доступным для своего приложения, используя следующую часть моего оператора SELECT:

SQRT( POW( ( ".strval($sourceX)." - cityX ) , 2 ) + POW( ( ".strval($sourceY)." - cityY ) , 2 ) ) AS distance

Это прекрасно работает для многих вычислений, но не принимает во внимание тот факт, что [0,0] и [499,499] находятся друг напротив друга.

Можно ли каким-либо образом настроить этот алгоритм для получения точного расстояния, учитывая, что 0 и 499 являются соседними?

  • Возможно, это может помочь: en.wikipedia.org/wiki/Great-circle_distance Изменить: stackoverflow.com/questions/27928/ seriousdev 02.01.2011

phpalgorithmmathcoordinate-systems

Ответы

Ответ 1 · рейтинг 5 · Andrew Jaffe

Обновление (тор):

Хорошо, из ваших собственных комментариев кажется, что вы действительно имеете в виду тор - поверхность пончика - а не сферу. (Это большая разница, и вам следует отредактировать свой вопрос: называть его сферой неправильно.)

На это ответ довольно прост - приведенная вами декартова формула более или менее правильна. Однако вам нужно обернуть расстояния так, чтобы все, что больше или равно 250 = 500/2, было переведено в диапазон от 0 до 250.

Итак, ответ примерно такой (я вообще не знаю PHP, поэтому, возможно, его нужно изменить для синтаксиса)

dx1 = min(dx, 500-dx)
dy1 = min(dy, 500-dy);
distance = Math.sqrt(dx1*dx1 + dy1*dy1);

(Это предполагает, что вы определили dx и dy как абсолютное значение разностей.)

Только что нашел эту процедуру, которая реализует тот же расчет в красиво упакованная функция.

Исходный ответ (сфера):

Вы не объяснили, как ваши координаты (x, y) сопоставляются с точками на сфере!

Существует (буквально) бесконечное количество вариантов, каждый из которых соответствует своей картографической проекции, и формула для каждого из них разная. Обратите внимание, что независимо от того, какой выбор вы сделаете, значение двух координат сильно различается.

Если ваши (x, y) действительно являются долготой и широтой, например, существует множество стандартных формул (например, гаверсинус), но вам придется сначала перевести 0-> 499 в 0-> 360 градусов для долготы и -90 ->90 градусов для широты. (Обратите внимание, что долгота и широта ведут себя на сфере совершенно по-разному!)

Но я подчеркиваю, что любой выбор, который вы сделаете, будет искажать плоскую геометрию, которую вы получите, если нанесете график в (x,y), по сравнению с тем, как он действительно выглядит на сфере.

(Наконец, если вы действительно имеете в виду, что верхний край такой же, как нижний, а правый такой же, как левый, то у вас, вероятно, тор, а не сфера!)

Ответ 2 · рейтинг 7 · Ishtar

Я предполагаю, что вы имеете в виду перенос координат и ничего сферического. Как плоский лист бумаги, концы которого волшебным образом соединены друг с другом.

Это означает, что для карты размером 500x500 расстояние в направлении x (или y) не превышает 250. (Если бы это было более 250 шагов, мы могли бы пройти 500-x шагов назад.)

Простым способом исправить это было бы

dx = Math.abs(dx);
dy = Math.abs(dy);
if (dx > 250)
  dx = 500 - dx;
if (dy > 250)
  dy = 500 - dy;
distance = Math.sqrt ( dx * dx + dy * dy );

Ответ 3 · рейтинг 1 · Agnius Vasiliauskas

Если вы знаете широту и долготу двух точек, вы можете использовать формулу гаверсина для вычисления расстояния между двумя точками на сфере.

Но, как я понял, вам нужна формула, точная для почти противоположных точек. Формула Хаверсина здесь не работает. В таком случае вам нужна формула Винсенти, которая точна даже в противоположных случаях.

http://en.wikipedia.org/wiki/Great-circle_distance#Formulae

Ответ 4 · рейтинг 1 · Stretto

Похоже, вы просто используете специальное конечное декартово пространство, которое "плиточное". В этом случае каждый объект не имеет уникальной позиции. Вместо (x, y) это (x + i*w, y + j*h) для всех возможных целых значений i и j, где w и h - ширина и высота вашего "окна" соответственно.

Очевидно, что тогда расстояние не уникально, а минимальное расстояние равно min(d(p1,p2))) по всем i, j.

Если ваши координаты завернуты, вам просто нужно вычислить их для i = -1,0,1 и j = -1,0,1, а затем взять наименьший.

Ответ 5 · duffymo

Этот общий алгоритм хорош для прямоугольных систем координат или очень точных расстояний в сферических координатах, но не подходит для сферической системы координат.

Я думаю, что лучший подход будет основан на широте и долготе, например:

http://jan.ucc.nau.edu/~cvm/latlongdist.html а>

В MySQL встроено геокодирование. Почему бы не использовать это?

http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL

Ответ 6 · Umopepisdn

Хотя некоторые из ответов здесь были очень близки, проблема была наконец решена с помощью этого сегмента SELECT:

SQRT( POW( LEAST( ABS($sourceXstr-cityX), ( 500 +LEAST($sourceXstr,cityX)-GREATEST($sourceXstr,cityX))) , 2 ) + POW( LEAST( ABS($sourceYstr-cityY), ( 500 +LEAST($sourceYstr,cityY)-GREATEST($sourceYstr,cityY))) , 2 ) ) AS distance

Ответ 7 · Somnath Muluk

Я пишу ответ, если две координаты находятся в двумерной плоскости, где концы не встречаются друг с другом, о чем ОП не спрашивал. Но это может помочь кому-то в будущем.

Если ваши точки находятся в двумерной плоскости, расстояние между точками (x1, y1) и (x2, y2) определяется теоремой Пифагора:

d = squareroot( square(x2 - x1) + square(y2 - y1) )

В PHP,

$x1 = $y1 = 2;
$x2 = $y2 = 5;
$distance = sqrt( pow(($x2-$x1),2) + pow(($y2-$y1),2) );
echo $distance;              // 4.2426406871193

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы