2010-01-27 6 views
1

데이터베이스에 LINESTRING이 들어있는 GEOGRAPHY SQL Server 2008 데이터 형식이 있습니다. LINESTRING은 잠재적으로 매력적인 도로를 설명합니다.포인트가 LINESTRING의 다른 두 지점 사이에 있는지 확인하십시오 (SQL Server 2008 지리)

도로 상에 시작 지점과 끝 지점 (모두 GEOGRAPHYPOINT)을 포함하는 다른 테이블이 있습니다. 도로의 두 지점 사이에 세 번째 지점이 있는지 알아야합니다 (LINESTRING).

현재, 그 테스트 해요 :

  • 세 번째 포인트는 라인
  • 시작 지점에 새 지점과 새로운 지점과 끝 지점이다 사이의 거리 사이의 거리에 모두 시작점과

작품 끝 지점 사이의 거리보다 덜하지만, 그 자체에 모든 도로 U 턴 경우 작동하지 않습니다 정말 우아 보인다! 작동하는 방법이 있습니까?

+2

도로가 커브로 돌아가는 경우 현재 방법이 작동합니까? 예를 들어, U 턴의 각 끝에 두 개의 점이 있고 U 턴 뒤의 점을 확인하는 경우 해당 점과 시작점과 종점 사이의 거리가 시작점과 끝점 사이의 거리보다 작을 수 있습니다. 하지만 두 지점 사이의 도로에는 나타나지 않습니다. –

+0

Eep, 네 말이 맞아! 좋아, 이제 정말로 대답이 필요해. :-) –

답변

3

당신이 언급 한 것처럼, 당신의 방법은 S 시작점은 다음과 같은 경우에 실패는, E는 엔드 포인트이고, X는 테스트중인 지점입니다 :

Determine if a POINT is between two other POINTs on a LINESTRING http://img10.imageshack.us/img10/4937/gmap.png

사용 이 방법을 사용하면 포인트 X는 포인트 S와 포인트 E 사이에있는 것으로 잘못 판단하게됩니다. 이는 알고리즘의 테스트 1과 테스트 2를 모두 통과하기 때문입니다. 포인트 X는 선 스트링에 있고,

당신은 "폭발 할 수 있습니다 X에서 S와 X에서 E까지의 거리가 모두 E.


하나의 가능한 해결 방법에 S까지의 거리보다 작은 "별도의 줄에 당신의 선 스트링의 경로는 두 점 segmenets 각각 있도록 :

:

LINESTRING(-122.360 47.656, -122.343 47.656, -122.310 47.690, -122.310 47.670) 

는로 나누어받을 것

위의 각 선분을 반복하고 STIntersects을 사용하여이 세그먼트 중 하나에 점이 있는지 테스트 할 수 있습니다. 이 테스트를 통과 한 지점이 시작 지점과 끝 지점에 있는지 확인할 수 있습니다.

가능한 경우 시작 지점/끝 지점을 원시 지리 지점이 아닌 선 스트링 경로의 지점에 대한 인덱스로 저장하는 것이 좋습니다. 우선이 방법으로이 문제를 쉽게 해결할 수 있지만 데이터 중복을 제거하고 선 스트링의 일부가 아닌 시작/끝점을 가질 수 없다는 보장이 제공됩니다. 단점은 선 세그먼트의 중간에 시작/끝점을 가질 수는 없지만 경로의 구석 중 하나에 있어야한다는 것입니다. 이제 응용 프로그램에서이 제한이 수용 가능한지 여부를 결정해야합니다.위의 표현을 선택하는 경우, 우리는 @path 도로를 나타내는 선 스트링입니다 다음 재귀 함수와이 문제를 해결할 수

, @start_point@end_end@path에 두 지점의 인덱스를 나타냅니다 (첫 번째 인덱스는 1) , @test_point은 테스트 할 지리 포인트입니다. 테스트 포인트는 거짓말을 할 수 있습니다.

CREATE FUNCTION [dbo].[func_PointBetween](@path  geography, 
              @start_point int, 
              @end_point int, 
              @test_point geography) 
RETURNS tinyint 
AS 
BEGIN 
    DECLARE @result  tinyint = 0; 
    DECLARE @num_points int = @path.STNumPoints(); 
    DECLARE @line_segment geography; 

    IF (@start_point < @end_point) AND (@end_point < @num_points) 
    BEGIN 
     /* Generate the line segment from the current start point 
      to the following point (@start_point + 1). */ 

     SET @line_segment = geography::STLineFromText('LINESTRING(' + 
      CAST(@path.STPointN(@start_point).Long AS varchar(32))+ ' ' + 
      CAST(@path.STPointN(@start_point).Lat AS varchar(32)) + ',' + 
      CAST(@path.STPointN(@start_point + 1).Long AS varchar(32))+ ' ' + 
      CAST(@path.STPointN(@start_point + 1).Lat AS varchar(32)) + ')', 
      4326); 

     /* Add a buffer of 25m to @test_point. This is optional, but 
      recommended, otherwise it will be very difficult to get a 
      point exactly on the line. The buffer value may be tweaked 
      as necessary for your application. */ 

     IF @test_point.STBuffer(25).STIntersects(@line_segment) = 1 
     BEGIN 
      /* The test point is on one of the line segments between 
       @start_point and @end_point. Return 1 and stop the 
       recursion. */ 

      SET @result = 1; 
     END 
     ELSE 
     BEGIN 
      /* The test point is not between the @start_point and 
       @start_point + 1. Increment @start_point by 1 and 
       continue recursively. */ 

      SET @result = [dbo].[func_PointBetween](@path, 
                @start_point + 1, 
                @end_point, 
                @test_point); 
     END 
    END 
    ELSE 
    BEGIN 
     /* There are no further points. The test point is not between the 
      @start_point and @end_point. Return 0 and stop the recursion. */ 

     SET @result = 0; 
    END 

    RETURN @result; 
END 

위의 기능을 테스트하려면 위의 맵에 표시된 6 포인트 선 스트링을 정의합니다. 두 번째 테스트 포인트를 정의 할 것입니다 : @test_point_a은 정확하게 세 번째와 네 번째 포인트 사이에 있고, @test_point_b은 경로에서 벗어납니다.

DECLARE @road geography; 
DECLARE @test_point_a geography; 
DECLARE @test_point_b geography; 

SET @road = geography::STGeomFromText('LINESTRING(-122.360 47.656, 
                -122.343 47.656, 
                -122.310 47.690, 
                -122.310 47.670, 
                -122.300 47.670, 
                -122.290 47.660)', 
                4326); 

/* This point lies between point 3 and point 4 */   
SET @test_point_a = geography::STGeomFromText('POINT(-122.310 47.680)', 4326); 

/* This point lies outside the path */ 
SET @test_point_b = geography::STGeomFromText('POINT(-122.310 47.700)', 4326); 

/* This returns 1, because the test point is between start and end */ 
SELECT dbo.func_PointBetween(@road, 2, 5, @test_point_a); 

/* This returns 0 because the test point is not between start and end */ 
SELECT dbo.func_PointBetween(@road, 4, 5, @test_point_a); 

/* This returns 0 because the test point lies outside the path */ 
SELECT dbo.func_PointBetween(@road, 1, 6, @test_point_b); 
0

새 점과 시작점과 끝점 사이의 선분 하위 집합 사이의 거리 (STDistance)를 확인할 수 있어야합니다. 그 거리는 0으로 평가됩니다. 지리 데이터 유형을 자세히 파헤 칠 기회가 있다면 정확한 쿼리를 작성하려고 노력하겠습니다.하지만 희망적으로 시작됩니다.

+0

물론 정확하지만 선분의 해당 부분 집합을 만드는 방법을 찾을 수 없습니다. –