2010-09-29 2 views
1

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

Здесь приведен пример кода для демонстрации проблемы. У кого-нибудь есть идея сделать эти неперекрывающиеся полигоны? (За исключением «не делают ваши многоугольники настолько сложны»)

-- 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))) 

ответ

0

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

-- 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 

Final Выбрать:

MULTIPOINT ((-79830220.96484375 42976022.375), (-79831832.015625 42966999.5078125)) 
+0

Я могу понять этот результат. В моем исходном SQL вторая строка SET ... STDifference использует @ Geo1, которая была изменена в первом SET. Но на самом деле мне не нужно было делать второй. Первый должен сделать Geo1 не перекрывающимся с Geo2.Тот факт, что у меня установлен Geo2, потому что я думал, что это поможет. Спасибо за наблюдение. Я посмотрю, поможет ли это мне в конце. –

0

Я подозреваю, что это происходит из-за метода/точности, с которой SQL Server выполняет пространственные расчеты. Для таких операций, как STIntersection() и т. Д., SQL Server округляет предоставленные значения координат float до 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

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

СМ Лит А в изображении

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

СМ Лит B в образе

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

enter image description here

Смежные вопросы