SQL Server 2008 Geometry не работает? - PullRequest
1 голос
/ 30 сентября 2010

У меня проблема с SQL Server 2008 и функциями геометрии.Я пытаюсь создать непересекающиеся фигуры с помощью функции STDifference ... но, похоже, она не работает 100% времени.

Вот весь пример кода, демонстрирующий проблему.У кого-нибудь есть идея сделать эти непересекающиеся полигоны?(кроме "не делайте ваши полигоны такими сложными")

-- create our Geometry polygons.
    DECLARE @Geo1 Geometry, @Geo2 Geometry;
    SET @Geo1 = geometry::STGeomFromText('POLYGON ((-79725887.5234375 42951274.765625, -79699548.921875 42991827.84375, -79695546.375697568 42997990.498925969, -79695559.967852488 42998690.733179785, -79696152.0625 43029192.375, -79715247.75 43051708.75, -79802181.8984375 43020797.71875, -79806253.6640625 43018621.6953125, -79810436.03125 43014767.046875, -79825837.5 43000572.375, -79830640.625 42973672.03125, -79832936.7265625 42960812.4296875, -79725887.5234375 42951274.765625))',0);
    SET @Geo2 = geometry::STGeomFromText('POLYGON ((-79863430.6875 42937209.4375, -79850399.0625 42940068.75, -79850394.9375 42940069.625, -79845320.6875 42946082.625, -79843216.25 42948576.375, -79832949.125 42960743, -79814909.939453125 43061773.556640625, -79817218.30078125 43060262.947265625, -79823496.6875 43056154.3125, -79867800.5 43027161.5625, -79871834.50390625 43024521.70703125, -79875660.228515625 43022018.123046875, -79875666.8125 43022013.8125, -79875674.536313191 43022008.760254942, -79875676.408203125 43022007.53515625, -79875677.236328125 43022006.994140625, -79875718.458984375 43021980.017578125, -79875728.506891936 43021973.442301653, -79881723.017578125 43018050.58984375, -79882437.0625 43017583.3125, -79882585.375 43017486.25, -79884466.9375 43016254.9375, -79884550.875 43016200, -79886514.3125 43014915.125, -79887785.5 43014083.25, -79887790.4375 43014080, -79887793.125 43014078.26953125, -79887807.171875 43014069.076171875, -79887825.568359375 43014057.03515625, -79887831.322335 43014053.269705132, -79888029.5 43013923.5625, -79890094.5625 43012572.1875, -79934236.875 42983685.125, -79863430.6875 42937209.4375))',0);

    -- A quick test so you can see them
    SELECT @Geo1, 'Geo1' as MyName UNION ALL SELECT @Geo2, 'Geo2' as MyName;

    -- how do they compare initially?
    SELECT 
     @Geo1.STTouches(@Geo2) as 'Touches'
     ,@Geo1.STOverlaps(@Geo2) as 'Overlaps'
     ,@Geo1.STIntersects(@Geo2) as 'Intersects'

    -- try to make them NOT overlap or intersect
    SET @Geo1 = @Geo1.STDifference(@Geo2);
    SET @Geo2 = @Geo2.STDifference(@Geo1);

    -- Now, how do they compare?
    SELECT 
     @Geo1.STTouches(@Geo2) as 'Touches'
     ,@Geo1.STOverlaps(@Geo2) as 'Overlaps'
     ,@Geo1.STIntersects(@Geo2) as 'Intersects'

    -- what does the intersection look like?
    SELECT @Geo1.STIntersection(@Geo2).STAsText();

Это окончательный результат выбора:

MULTIPOLYGON (((-79831832.015625 42966999.5078125, -79830502.34765625 42974446.45703125, -79830181.430394545 42976243.79133676, -79830220.96484375 42976022.375, -79831832.015625 42966999.5078125)), ((-79832481.0538819 42963364.484146826, -79832328.75390625 42964217.45703125, -79831832.015625 42966999.5078125, -79832481.0538819 42963364.484146826)))

Ответы [ 3 ]

0 голосов
/ 25 ноября 2010

Я подозреваю, что это связано с методом / точностью, с которой SQL Server выполняет пространственные вычисления. Для таких операций, как STIntersection () и т. Д., SQL Server округляет предоставленные значения координат с плавающей запятой в 27-битную целочисленную сетку. Это может привести к небольшим искажениям координат, возвращаемых в результате пространственных операций.

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

См. Здесь объяснение, а также предположение, что эта ситуация была улучшена в SQL Server Denali: https://connect.microsoft.com/SQLServer/feedback/details/580254/spatial-operations-are-done-with-a-low-precision-causing-troubles-in-the-returned-data

0 голосов
/ 17 декабря 2013

Как отметил Джо Стефанелли, ваши полигоны технически не пересекаются, но они пересекаются.Причина в том, что если вы вырезаете отверстие из одного многоугольника, используя меньший многоугольник, меньший многоугольник не будет перекрывать новый многоугольник, но будет пересекать его вдоль края разреза.Это не похоже на настольную пилу, которая удаляет некоторый материал по краю реза.Я не мог включить код, потому что SO имеет проблему с определенными операторами SQL и блокирует сообщение.

ПОСМОТРЕТЬ ССЫЛКУ A на изображении

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

СМОТРЕТЬ ССЫЛКУ B на изображении

Я знаю, что этот пост старый, но он все еще уместендля тех из нас, кто еще будет в 2008 году.

enter image description here

0 голосов
/ 30 сентября 2010

Не ответ, просто наблюдение ... Я получу разные результаты, если я введу две новые переменные для двух различий.

-- create our Geometry polygons.
    DECLARE @Geo1 Geometry, @Geo2 Geometry, @Geo3 Geometry, @Geo4 Geometry;
    SET @Geo1 = geometry::STGeomFromText('POLYGON ((-79725887.5234375 42951274.765625, -79699548.921875 42991827.84375, -79695546.375697568 42997990.498925969, -79695559.967852488 42998690.733179785, -79696152.0625 43029192.375, -79715247.75 43051708.75, -79802181.8984375 43020797.71875, -79806253.6640625 43018621.6953125, -79810436.03125 43014767.046875, -79825837.5 43000572.375, -79830640.625 42973672.03125, -79832936.7265625 42960812.4296875, -79725887.5234375 42951274.765625))',0);
    SET @Geo2 = geometry::STGeomFromText('POLYGON ((-79863430.6875 42937209.4375, -79850399.0625 42940068.75, -79850394.9375 42940069.625, -79845320.6875 42946082.625, -79843216.25 42948576.375, -79832949.125 42960743, -79814909.939453125 43061773.556640625, -79817218.30078125 43060262.947265625, -79823496.6875 43056154.3125, -79867800.5 43027161.5625, -79871834.50390625 43024521.70703125, -79875660.228515625 43022018.123046875, -79875666.8125 43022013.8125, -79875674.536313191 43022008.760254942, -79875676.408203125 43022007.53515625, -79875677.236328125 43022006.994140625, -79875718.458984375 43021980.017578125, -79875728.506891936 43021973.442301653, -79881723.017578125 43018050.58984375, -79882437.0625 43017583.3125, -79882585.375 43017486.25, -79884466.9375 43016254.9375, -79884550.875 43016200, -79886514.3125 43014915.125, -79887785.5 43014083.25, -79887790.4375 43014080, -79887793.125 43014078.26953125, -79887807.171875 43014069.076171875, -79887825.568359375 43014057.03515625, -79887831.322335 43014053.269705132, -79888029.5 43013923.5625, -79890094.5625 43012572.1875, -79934236.875 42983685.125, -79863430.6875 42937209.4375))',0);

    -- A quick test so you can see them
    SELECT @Geo1, 'Geo1' as MyName UNION ALL SELECT @Geo2, 'Geo2' as MyName;

    -- how do they compare initially?
    SELECT 
     @Geo1.STTouches(@Geo2) as 'Touches'
     ,@Geo1.STOverlaps(@Geo2) as 'Overlaps'
     ,@Geo1.STIntersects(@Geo2) as 'Intersects'

    -- try to make them NOT overlap or intersect
    SET @Geo3 = @Geo1.STDifference(@Geo2);
    SET @Geo4 = @Geo2.STDifference(@Geo1);

    -- Now, how do they compare?
    SELECT 
     @Geo3.STTouches(@Geo4) as 'Touches'
     ,@Geo3.STOverlaps(@Geo4) as 'Overlaps'
     ,@Geo3.STIntersects(@Geo4) as 'Intersects'

    -- what does the intersection look like?
    SELECT @Geo3.STIntersection(@Geo4).STAsText();

Сравните:

Touches     Overlaps        Intersects
1           0               1

Окончательный выбор:

MULTIPOINT ((-79830220.96484375 42976022.375), (-79831832.015625 42966999.5078125))
...