1

データベースに . を含むSQL Server 2008GEOGRAPHYデータ型がありますLINESTRING。はLINESTRING、曲がりくねった道を示しています。

GEOGRAPHY POINT道路上の始点と終点 (どちらも ) を含む別のテーブルがあります。道路上のこれら 2 点の間に 3 番目の点があるかどうかを知る必要があります ( LINESTRING)。

現在、私はそれをテストしています:

  • 3 番目の点は直線上にあります
  • 新しい点から始点までの距離と、新しい点から終点までの距離がどちらも、始点と終点の間の距離よりも小さい

これは機能しますが、道路が自動的に U ターンする場合、まったく機能しないように見えます。うまくいく方法はありますか?

4

2 に答える 2

3

お気づきのように、S が開始点、E が終了点、X がテストしている点である次の場合、メソッドは失敗します。

POINT が LINESTRING 上の他の 2 つの POINT の間にあるかどうかを判断します http://img10.imageshack.us/img10/4937/gmap.png

この方法を使用すると、ポイント X は、アルゴリズムのテスト 1 とテスト 2 の両方に合格するため、ポイント S とポイント E の間にあるという誤った結果になります。点 X は線ストリング上にあり、X から S までの距離と X から E までの距離はどちらも、S から E までの距離よりも小さいです。


考えられる解決策の 1 つ

ラインストリング パスを、それぞれ 2 つのポイントだけを持つ個別のライン セグメントに「分解」することができます。

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

次のように分類されます。

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

次に、上記の各線分を繰り返し処理し、 を使用して点がこれらの線分の 1 つにあるかどうかをテストできますSTIntersects。ポイントがこのテストに合格すると、これが開始ポイントと終了ポイント内にあるかどうかを判断できます。

可能であれば、生の地理ポイントではなく、線ストリング パス上のポイントへのインデックスとして開始/終了ポイントを保存することをお勧めします。まず第一に、これはこの問題を解決しやすくしますが、それとは別に、データの重複を排除します。これには、折れ線の一部ではない始点/終点を持つことができないという保証も付いています。これの欠点は、始点/終点を線分の中央に置くことができず、パスの角の 1 つに配置する必要があることです。ここで、アプリケーションでこの制限が許容できるかどうかを判断する必要があります。

上記の表現を選択した場合、次の再帰関数を使用してこの問題@path@start_point解決できます@end_end。テストされます。テストポイントは、ライのどこにでも置くことができます。@path@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 ポイントの折れ線を定義しています。次に、2 つのテスト ポイントを定義します@test_point_a。3 番目と 4 番目のポイントの間にある と@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);
于 2010-01-28T01:50:49.147 に答える
0

新しいポイントと、始点と終点の間の線分のサブセットとの間の距離 (STDistance) を確認できるはずです。その距離はゼロに評価されるはずです。地理データ型をさらに掘り下げる機会があれば、正確なクエリをまとめようと思いますが、うまくいけば、これで始めることができます。

于 2010-01-28T01:23:53.607 に答える