Подтвердить что ты не робот

Получать результаты, попадающие в радиусы маркеров из базы данных

Обновление от 16 ноября 2012 г.

Я хотел бы снова поднять этот вопрос, предлагая новую щедрость для солидного, хорошего решения. Кажется, что только решение (shubhansh answer) не работает эффективно. Я объясню, почему.

Во-первых, это живая карта с радиусами и людьми, радиусы находятся в red, а люди находятся в blue.

enter image description here

Как вы можете видеть, на этой карте есть люди с two с радиусами eight, в основном я получаю только человека, который Person A, но я не получаю Person B, я предполагаю, что SQL неправильно подбирает его, для чего мне нужно, чтобы он был точным и точным из радиуса человека и радиусы маркера.

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

Я ищу точный и точный SQL, чем ответ shubhansh. Вы можете прочитать ниже, чтобы прочитать, как именно мне нужен запрос, чтобы действовать и подбирать точных людей.

Данные PEOPLE:

+-----------+-----------+--------+
| latitude  | longitude | radius |
+-----------+-----------+--------+
| 51.517395 | -0.053129 | 5.6    |
| 51.506607 | -0.116129 | 0.7    |
+-----------+-----------+--------+

Обратите внимание, что radius находится в километрах.

+-----------+-----------+-----+
| latitude  | longitude | km  |
+-----------+-----------+-----+
| 51.502117 | -0.103340 | 0.3 |
| 51.498913 | -0.120850 | 0.7 |
| 51.496078 | -0.108919 | 0.7 |
| 51.496506 | -0.095873 | 0.7 |
| 51.503399 | -0.090723 | 0.7 |
| 51.508049 | -0.100336 | 0.7 |
| 51.508797 | -0.112610 | 0.7 |
| 51.505535 | -0.125227 | 0.7 |
| 51.502331 | -0.108061 | 0.7 |
+-----------+-----------+-----+

В текущем SQL я использую:

SELECT ppl.latitude,
       ppl.longitude,
       ppl.radius
FROM 
(
    people ppl
),
(
    SELECT latitude, longitude 
    FROM radiuses
) AS radius
WHERE (POW((ppl.longitude - radius.longitude) * 111.12 * COS(ppl.latitude), 2) + POW((ppl.longitude - radius.longitude) * 111.12, 2)) <= 4
GROUP BY ppl.id

Данные для MySQL, которые вы можете использовать для проверки вашего запроса,

INSERT INTO radiuses (id, latitude, longitude, km) VALUES ('1', '51.502117', '-0.103340', '0.3'), ('2', '51.498913', '-0.120850', '0.7'), ('3', '51.496078', '-0.108919', '0.7'), ('4', '51.496506', '-0.095873', '0.7'), ('5', '51.503399', '-0.090723', '0.7'), ('6', '51.508049', '-0.100336', '0.7'), ('7', '51.508797', '-0.112610', '0.7'), ('8', '51.505535', '-0.125227', '0.7'), ('9', '51.502331', '-0.108061', '0.7');

INSERT INTO people (id, latitude, longitude, radius) VALUES ('1', '51.517395', '-0.053129', '5.6'), ('2', '51.506607', '-0.116129', '0.7');

Старое резюме

Примечание: все широты и долготы просто произвольно сделаны.

У меня есть апплет карты, который пользователь может разместить радиус местоположения lat/lng с радиусом 1 км.

Теперь есть еще один пользователь, который может поместить свои радиусы в любом месте на карте с радиусом 1 км (так же, как пользователь выше).

Подобно этому Пользователь A красный, а Пользовательский B синий.

enter image description here

В основном Пользователь A сохраняет свои радиусы в таблице, которая выглядит так:

+-----------+---------+-----------+-----------+
| radius_id | user_id | latitude  | longitude |
+-----------+---------+-----------+-----------+
|         1 |       1 | 81.802117 | -1.110035 |
|         2 |       1 | 81.798272 | -1.144196 |
|         3 |       1 | 81.726782 | -1.135919 |
+-----------+---------+-----------+-----------+

И Пользователь B сохраняет свой радиус в другой таблице, которая выглядит так: (обратите внимание: они могут хранить только 1 координаты для каждой учетной записи):

+---------+-----------+-----------+
| user_id | latitude  | longitude |
+---------+-----------+-----------+
|       6 | 81.444126 | -1.244910 |
+---------+-----------+-----------+

Я хочу, чтобы можно было забрать тех пользователей, которые попадают в определенные радиусы, даже если круги радиуса касаются, на картинке. Только маркер C мог бы получить единственный радиус, когда A и B не делают.

Я уверен, что это возможно, но я не знаю, как придумать такую ​​систему в MySQL.

Я нашел это на сайте разработчиков Google, но не только то, что оно мне нужно.

EDIT: я нашел лучший, это очень близко, но все же не то, что я ищу, поскольку он использует 1 границу координат широты и долготы, когда у меня есть несколько в таблице.

4b9b3361

Ответ 1

Существенной точкой вашей геометрии является то, что два круга перекрываются, если расстояние между их центрами меньше суммы их радиусов. Поскольку мы проводим сравнение, мы можем использовать квадрат расстояния, поскольку это позволяет избежать операции с квадратным корнем. В оригинале каждый радиус фиксирован в точке 1, сумма двух радиусов равна 2, а квадрат суммы равен 4.

Там существует большая разница между исходным вопросом и новым вопросом. В первом у вас есть круги с фиксированным радиусом, а во втором - круги разного радиуса. Константу 4 в выражении сравнения [...distance^2...] <= 4 необходимо заменить, поскольку это артефакт фиксированного радиуса оригинала. Чтобы реализовать это, добавьте поле km в запрос. И, как вы должны проверить, вы не использовали ppl.radius в фильтрах WHERE, поэтому вряд ли удивительно, что изменение этого значения не изменило ваши результаты запроса.

SELECT ppl.latitude, ppl.longitude, ppl.radius
FROM 
  ( people ppl ),
  ( SELECT latitude, longitude, km FROM radiuses ) AS B
WHERE [...distance^2...] <= POW( ppl.radius + B.km, 2)

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

Ответ 2

Для решения этого вам нужно понять уравнение круга, что-то вроде этого Для любой точки (x, y), которая попадает в круг с центром (x1, y1) и единицами радиуса r

(x-x1)^2 + (y - y1)^2 <= r^2

where a^b = a to the power b

Здесь в вашем случае пользователь B (широта, долгота) является центром круга, пользователь A (широта, долгота) - это точки (x, y) и радиус = 2kms.

Но основная проблема заключается в изменении степеней широт на долготы, так что вот решение, 1 градус = 111,12 км. Таким образом, чтобы единицы были одинаковыми по обе стороны уравнения, мы преобразуем их в Kms

Итак, наше окончательное уравнение становится:

((x-x1)*111.12)^2 + ((y-y1)*111.12)^2 = 4      (=2^2) 

SQL-оператор для этого должен выглядеть примерно так:

SELECT A.user_id, A.radius_id, A.latitude, A.logitude
FROM UserA AS A, 
     (SELECT user_id, latitude, longitude 
       FROM UserB 
       WHERE user_id = 8) AS B
WHERE (POW((A.latitude-B.latitude)*111.12, 2) + POW((A.longitude - B.longitude)*111.12, 2)) <= 4
/* **Edit** Here I have used (A.longitude - B.longitude)*111.12, for more accurate results one can replace it with (A.longitude - B.longitude)*111.12*cos(A.latitude)) or (A.longitude - B.longitude)*111.12*cos(B.latitude)) 

And, as i have suggested in the comments that first filter some records based on approximation, so whether one uses A.latitude or B.latitude it will not make much difference */

Надеюсь, это поможет...

Ответ 3

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

Другим ответом является обработка широты и долготы, как будто они содержат декартову плоскость. которые они не имеют (долгота стремится к нулю, когда вы приближаетесь к полюсам от экватора). Теперь, в качестве приближения, он может отлично работать для вашего решения, в зависимости от точности, необходимой вашему решению. С другой стороны, если вам нужно, чтобы это было очень точно, вам нужна формула Хаверсина. Там отличное описание того, как реализовать его в MySQL здесь:

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

Из слайда 7 этой презентации вы имеете следующую формулу:

3956*2*ASIN(SQRT(POWER(SIN((orig.lat-dest.lat)*pi()/180/2),2)+
    COS(orig.lat*pi()/180)*COS(dest.lat*pi()/180)*
    POWER(SIN((orig.lon-dest.lon)*pi()/180/2),2)))

Обратите внимание, что первое число - это средний радиус земли в милях; измените это на 6371 за километры.

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

Я упоминаю об этом, потому что производительность будет проблемой, особенно если у вас есть значительный объем данных и/или он постоянно обновляется (например, местоположения пользователей на основе их данных GPS-телефона).

Один из способов помочь с проблемой производительности - использовать квадраты вместо кругов и использовать приближение одной ступени = 111,12 км. Таким образом, вы можете автоматически отбирать любые точки, которые явно находятся далеко друг от друга. Затем вы просто вычисляете формулу Хаверсина только для нескольких точек, попадающих в интересующую область.

Я надеюсь, что это поможет указать вам в правильном направлении.