确定LineString是否为多边形内圆的可靠方法

时间:2015-07-21 16:23:47

标签: sql-server tsql sql-server-2012

我已经编写了这个基本代码,它首先从多边形中提取多边形,然后是与内圆和外圆相对应的特定LineStrings:

DECLARE @SomeMultiPolygon GEOGRAPHY = 'MULTIPOLYGON (
((-2 -2, 2 -2, 2 2, -2 2, -2 -2), (-1 -0.5, 0 -0.5, 0 -1.5, -1 -1.5, -1 -0.5), (0 1, 1 1, 1 0, 0 0, 0 1))
, ((-4 -3, -4 -5, 0 -5, 0 -3, -4 -3)))';
SET @SomeMultiPolygon.STSrid = 4326;

DECLARE @i int = 1  
DECLARE @Results TABLE ( Id INT IDENTITY(1,1), PolygonData GEOGRAPHY )  
WHILE @i <= @SomeMultiPolygon.STNumGeometries()  
    BEGIN 
        INSERT INTO @Results VALUES (@SomeMultiPolygon.STGeometryN(@i))
        SET @i = @i + 1  
    END 

SELECT 
    Id,
    PolygonData.STGeometryType(), 
    PolygonData, 
    PolygonData.STAsText() AS PolygonWkt,
    PolygonData.NumRings() AS NumberOfRings
FROM @Results

IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
    DROP TABLE #Temp

CREATE TABLE #Temp
(
    ParentId INT,
    SubPolygon GEOGRAPHY
)

DECLARE @Id INT, @InnerLoop INT, @SubPolygon GEOGRAPHY;  
SELECT @Id = MAX(Id) FROM @Results    
WHILE @Id >= 1
    BEGIN   
        SELECT @InnerLoop = PolygonData.NumRings() FROM @Results WHERE Id = @Id
        WHILE @InnerLoop > 0
            BEGIN
                SELECT @SubPolygon = PolygonData.RingN(@InnerLoop) FROM @Results WHERE Id = @Id

                INSERT INTO #Temp
                        ( ParentId, SubPolygon )
                VALUES  ( @Id, 
                          @SubPolygon
                          )

                SET @InnerLoop = @InnerLoop - 1;
            END

        SET @Id = @Id - 1                              
    END

SELECT 
    *, 
    SubPolygon.STAsText() AS SubPolygonText,
    SubPolygon.EnvelopeAngle() AS EnvelopeAngle
FROM #Temp

我是否正确地假设,如果EnvelopeAngle小于1度,则LineString对应于内圈?

顺便说一句,是否有基于集合的方法来实现上述目标 - 我并不是TSql中循环的粉丝。

PS:

这是上述示例的可视化:

enter image description here

1 个答案:

答案 0 :(得分:1)

按顺序回答您的问题:

  

我是否正确地假设,如果EnvelopeAngle小于1度,LineString对应一个内圈?

没有。这是您的测试数据的工件,但您不能一般地做出这个断言。你的问题来得很愉快,因为前几天我刚刚了解了EnvelopeAngle。我喜欢将它视为&#34;这个对象有多宽(以度为单位)?&#34;。如果您向上或向下重新缩放所有对象,则EnvelopeAngle启发式不再有效。

但是,我可能尝试的启发式是针对结果表中的给定ID,最大(按区域)是包含其他ID的那个。你也可以玩STDifference,但区域似乎最直接。

  

[我]有一套基于集合的方法来实现上述目标吗? - 我真的不喜欢TSql中的循环。

是的!这是:

DECLARE @SomeMultiPolygon GEOGRAPHY = 'MULTIPOLYGON (
    (
        (-2 -2, 2 -2, 2 2, -2 2, -2 -2), 
        (-1 -0.5, 0 -0.5, 0 -1.5, -1 -1.5, -1 -0.5), 
        (0 1, 1 1, 1 0, 0 0, 0 1)
    )
    , (
        (-4 -3, -4 -5, 0 -5, 0 -3, -4 -3)
    )
)';
SET @SomeMultiPolygon.STSrid = 4326;

DECLARE @Results TABLE ( 
    Id INT IDENTITY(1,1), 
    PolygonData GEOGRAPHY 
);

INSERT INTO @Results
        ( [PolygonData] )
SELECT @SomeMultiPolygon.STGeometryN([n].[n])
FROM Util.dbo.[Numbers] AS [n]
WHERE n <= @SomeMultiPolygon.STNumGeometries();

SELECT 
    Id,
    PolygonData.STGeometryType(), 
    PolygonData, 
    PolygonData.STAsText() AS PolygonWkt,
    PolygonData.NumRings() AS NumberOfRings
FROM @Results;

CREATE TABLE #Temp (
    ParentId INT,
    SubPolygon GEOGRAPHY
);

INSERT INTO [#Temp]
        ( [ParentId], [SubPolygon] )
SELECT r.ID, rings.[ring]
FROM @Results AS [r]
CROSS APPLY (
   SELECT r.[PolygonData].RingN(n) AS ring
   FROM [Util].[dbo].[Numbers] AS [n]
   WHERE n <= r.[PolygonData].NumRings() 
) AS rings;

SELECT 
    *, 
    SubPolygon.STAsText() AS SubPolygonText,
    SubPolygon.EnvelopeAngle() AS EnvelopeAngle
FROM #Temp