2016-03-25 2 views
0

Я пытаюсь выполнить очень эффективную проверку, чтобы увидеть, находятся ли две точки в пределах мили друг от друга.Учитывая два лата/longs, как я могу определить, находятся ли они в пределах 1 мили друг от друга?

Я только уход, являются ли они в пределах мили - ничего о вопросах расстояния до меня.

Из-за этого узкого внимания, я не ищет общие цели «how far apart are these points».

Мой текущий подход - вычислить Haversine distance, а затем проверить, не меньше ли мили.

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

Итак, каков наиболее эффективный способ узнать, находятся ли две лат/длинные точки в миле друг от друга?

Я делаю эту проверку в T-SQL, но это не так важно. Мое текущее вычисление haversine ниже.

CREATE FUNCTION dbo.USR_UFN_HAVERSINE_DISTANCE 
(
    @LAT1 FLOAT(18) 
,@LONG1 FLOAT(18) 
,@LAT2 FLOAT(18) 
,@LONG2 FLOAT(18) 
,@UnitOfMeasure NVARCHAR(10) = 'KILOMETERS' 
) 
RETURNS FLOAT(18) 
AS 
BEGIN 
    DECLARE 
    @R FLOAT(8) 
    ,@DLAT FLOAT(18) 
    ,@DLON FLOAT(18) 
    ,@A FLOAT(18) 
    ,@C FLOAT(18) 
    ,@D FLOAT(18) 
    ; 
    SET @R = 
    CASE @UnitOfMeasure 
     WHEN 'MILES'  THEN 3956.55 
     WHEN 'KILOMETERS' THEN 6367.45 
     WHEN 'FEET'  THEN 20890584 
     WHEN 'METERS'  THEN 6367450 
     ELSE 6367.45 --km 
    END 
    SET @DLAT = RADIANS(@LAT2 - @LAT1); 
    SET @DLON = RADIANS(@LONG2 - @LONG1); 
    SET @A = SIN(@DLAT/2) 
     * SIN(@DLAT/2) 
     + COS(RADIANS(@LAT1)) 
     * COS(RADIANS(@LAT2)) 
     * SIN(@DLON/2) 
     * SIN(@DLON/2); 
    SET @C = 2 * ASIN(MIN(SQRT(@A))); 
    SET @D = @R * @C; 
    RETURN @D; 
END; 
+0

Возможный дубликат [Самый быстрый способ найти расстояние между двумя Lat/Long Points] (http://stackoverflow.com/questions/1006654/fastest-way-to-find-distance-between-two-lat -long-points) –

+0

@ KenY-N Спасибо, что указал на меня. У меня уже есть функция общего назначения, чтобы получить расстояние между двумя точками. Поскольку в этом случае мне все равно, если расстояние находится в миле или нет, я надеюсь, что есть более быстрый способ, не имея на самом деле вычисления полного расстояния. Я отредактировал вопрос, чтобы попытаться сделать это различие понятным. – JosephStyons

+0

Проверьте второй ответ на этот вопрос? Кажется, что вы приближаетесь к тому, что хотите ... –

ответ

1

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

create function dbo.fn_areWithinOneMile(@long1 float, @lat1 float, @long2 float, @lat2 float) 
returns table 
as 
return 

    select cast(
     case when 
      geography::Point(@lat1, @long1, 4236).STDistance(geography::Point(@lat2, @long2, 4236)) > 1609.34 then 0 
      else 1 
     end as bit) as [withinOneMile?] 

go 

with cte as (select * from (values 
    (42, 42), 
    (43, 43), 
    (44, 44) 
    ) as x(lat, long) 
), j as (
    select long, lat, lag(long, 1) over (order by lat) as long2, lag(lat, 1) over (order by lat) as lat2 
    from cte 
) 
select * 
from j 
cross apply dbo.fn_areWithinOneMile(long, lat, long2, lat2) as o 
where long2 is not null; 
1
DECLARE 
    @pt1 geography, 
    @pt2 geography; 

    SET @pt1 = geography::Point(45.65100, -120.34900, 4326); 
    SET @pt2 = geography::Point(44.65100, -120.37654, 4326); 

    SELECT @pt1.STDistance(@pt2); 

-The возвращаемое значение в метрах, хотя вы можете указать возврат путем изменения SRID.

-The список SRID годов доступны здесь

Select * from sys.spatial_reference_systems