Как искать по радиусу на основе широты и долготы? - PullRequest
4 голосов
/ 12 декабря 2011

Я хочу показать данные на основе широты и долготы с указанным радиусом.

Пример:

У меня есть запись с широтой 55.0628 и долготой -162.3056 без указанного состояния.

Как я могу показать только записи, которые в пределах одного состояния, используя entity для linq?

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

Table Data

id            item             latitude                 longitude
1             townhome          55.0628                 -162.3056


Table postal codes

id               state                 city            latitude            longitude
1                alaska                Akutan          54.143              -165.7854
2                Alabama               Huntsville      34.7448             -86.6704

Ответы [ 3 ]

4 голосов
/ 12 декабря 2011

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

Вот пользовательская функция SQL, которую я использую для вычисления расстояния между двумя точками. Он использует новые функции географии, представленные в SQL Server 2008.

CREATE FUNCTION [dbo].[GetDistanceBetween]
(
    @Lat1 float,
    @Long1 float,
    @Lat2 float,
    @Long2 float
)
RETURNS float
AS
BEGIN

    DECLARE @RetVal float;
    SET @RetVal = ( SELECT geography::Point(@Lat1, @Long1, 4326).STDistance(geography::Point(@Lat2, @Long2, 4326)) / 1609.344 );

RETURN @RetVal;

END

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

Вы можете назвать это, используя что-то вроде:

DECLARE @StartingLatitude FLOAT, @StartingLongitude FLOAT;
DECLARE @MaxDistance FLOAT = 50;

SELECT * FROM PostalCodes 
WHERE dbo.GetDistanceBetween(@StartingLatitude, @StartingLongitude, latitude, longitude) <= @MaxDistance;
1 голос
/ 12 декабря 2011

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

Если у вас есть эти данные, это становится проблемой Point in Polygon . Я обнаружил, что трассировку лучей было довольно легко реализовать как в SQL, так и в C #, так что было бы неплохо иметь такую ​​функцию, чтобы вы понимали Linq, хотя я делал это только в Linq2SQL, а не в Linq2Entities.

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

Если вы согласны с этим, но не используете SQL 2008 (поэтому нет STDistance), вы можете получить приблизительное приближение, заказав ((lat1 - lat2) * (lat1 - lat2)) + ((lng1 - lng2) * (lng1 - lng2)). Это дает относительное расстояние, как будто мир действительно был прямоугольником, как предполагает проекция Меркатора. Погрешность усугубляется по мере удаления точек от экватора, поэтому она может быть почти приемлемой для штатов США, но не удалась для канадских провинций.

0 голосов
/ 12 декабря 2011

Правильный и быстрый способ - начать с лат-парной пары почтового индекса и найти точки Востока, Запада, Севера и Юга для заданного расстояния (радиуса). Следуйте этой ссылке для соответствующих формул. Затем используйте эти точки, чтобы получить почтовые индексы из базы данных; что-то вроде:

select *
from zipcodes
where
    lat >= South
    and lat <= North
    and lon >= West
    and lon <= East
    -- and state = 'FL' -- use it optionally

Теперь, когда все почтовые записи в квадрате, определенном точками Востока, Севера, Запада и Юга (в виде линий), приступают к расчетам расстояний (используйте код Тима) и сохраняют только записи в радиусе. (Если все точки в квадрате, где есть записи, то что-то вроде 22% будет вне радиуса).
Очевидно, что если вы используете CTE, вы выполните весь SQL-запрос только одним запросом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...