STContains - тесты не пройдены для точек ВНУТРИ полигона

Во-первых, версия SQL:

Microsoft SQL Server 2016 (окончательная первоначальная версия) — 13.0.1601.5 (X64) 29 апреля 2016 г. 23:23:58 Авторские права (c) Microsoft Corporation Standard Edition (64-разрядная версия) в Windows Server 2012 R2 Standard 6.3 (сборка 9600:) (гипервизор)

Я объявляю один замкнутый многоугольник (правильно ориентированный по правилу левой руки), который, согласно SQL, действителен:

DECLARE @g geography;
SET @g = geography::STPolyFromText('POLYGON((-141.251221 60.177476, -134.351807 52.952478, -124.859620 48.440718, -123.623658 48.163009, -123.132020 48.232578, -122.906113 48.998367, -95.169068 48.966372, -94.980927 49.021337, -94.627991 48.700606, -93.907013 48.594450, -93.845215 48.495351, -93.510132 48.517642, -93.197022 48.583549, -92.743836 48.507408, -92.422486 48.211991, -91.573792 48.021520, -90.973664 48.095065, -90.146256 48.021693, -89.428711 47.911409, -88.442688 48.232120, -84.935303 46.850463, -84.819947 46.614678, -84.531556 46.397991, -84.200593 46.493917, -84.117508 46.124608, -83.620034 45.782175, -82.591267 45.290317, -82.166749 43.592965, -82.661133 42.606311, -82.886353 42.391659, -83.097840 42.332805, -83.187104 42.071357, -83.135605 41.842088, -82.865410 41.657411, -82.463379 41.587347, -81.068116 42.119252, -80.049134 42.334835, -78.887330 42.783953, -78.868104 42.953046, -78.995820 43.161758, -79.090577 43.433616, -78.664856 43.557148, -76.766968 43.541223, -76.398926 44.064539, -74.852601 44.971250, -71.471558 44.957647, -70.846711 45.205884, -70.589219 45.379779, -70.207787 45.900179, -69.238587 47.291005, -68.891488 47.116066, -68.297196 47.291936, -67.850361 47.016678, -67.864953 45.667941, -65.966034 43.191802, -49.229737 45.124550, -59.425049 68.026407, -75.421143 74.789051, -73.663331 78.324047, -57.315674 82.569900, -71.378174 83.545629, -112.335206 79.852216, -141.163331 70.394745, -141.251221 60.177476 ))', 4326);
SELECT @g.IsValidDetailed() AS 'IsValidDetailed', @g.STIsClosed() AS 'STIsClosed', @g.EnvelopeAngle() AS 'EnvelopeAngle';

Когда приведенный выше запрос выполняется, SQL отвечает:

IsValidDetailed STIsClosed  EnvelopeAngle
24400: Valid    True        33.0780372828377

Для визуальной проверки я начертил многоугольник (через карты Google), а также включил 3 точки ВНУТРИ многоугольника, а также 3 точки СНАРУЖИ многоугольника. Ниже приведен снимок экрана с многоугольником и точками на уровне масштабирования, показывающем полный многоугольник (красная область обозначает «границы», которые окружают многоугольник):

Полигон на карте

Увеличивая карту, вы можете начать видеть отдельные точки, т.е.:

Точки внутри и снаружи полигона

Увеличив масштаб, вы можете увидеть, что две точки находятся очень близко к краю многоугольника, одна внутри (зеленая), одна снаружи (красная):

Точки рядом с краем многоугольника

Следующий запрос использовался для проверки точек, находящихся ВНУТРИ полигона:

SELECT lat, lon, 
       @g.STContains( geography::Point( lat, lon, 4326 ) ) AS STContains,
       geography::Point( lat, lon, 4326 ).STWithin( @g ) AS STWithin
 FROM ( VALUES ( 49.119404, -102.988586 ),
               ( 49.004776, -102.996875 ),
               ( 48.975416, -103.005152 )
       ) points( lat, lon )

SQL отвечает:

lat         lon         STContains  STWithin
49.119404   -102.988586 False       False
49.004776   -102.996875 False       False
48.975416   -103.005152 False       False

-- Ожидалось ли, что STContains и STwithin вернут "True" для точек внутри многоугольника???

Следующий запрос использовался для проверки точек ВНЕШНИХ многоугольников:

SELECT lat, lon, 
       @g.STContains( geography::Point( lat, lon, 4326 ) ) AS STContains,
       geography::Point( lat, lon, 4326 ).STWithin( @g ) AS STWithin
 FROM ( VALUES ( 48.975409, -103.005151 ),
               ( 48.974153, -103.005144 ),
               ( 48.951739, -103.005627 )
       ) points( lat, lon )

SQL отвечает:

lat         lon         STContains  STWithin
48.975409   -103.005151 False       False
48.974153   -103.005144 False       False
48.951739   -103.005627 False       False

-- Ожидаемые результаты, так как все точки находятся ВНЕ полигона.

Вопрос:

Почему STContains/STWithin не работает для точек, находящихся ВНУТРИ полигона?

Я должен предположить, что делаю что-то неправильно, но я следовал правилам (слева) для построения многоугольника, и SQL указывает, что многоугольник «действителен».

Любой совет будет принят во внимание.


person bdcoder    schedule 11.05.2020    source источник
comment
Вы уверены, что используете левостороннюю ориентацию? Изменятся ли ваши ожидаемые результаты, если вы SET @g = @g.ReorientObject() сначала?   -  person AlwaysLearning    schedule 12.05.2020
comment
@AlwaysLearning - Используя EnvelopeAngle в качестве эвристики, я ожидаю, что он будет ближе (если не точно) к 180 °, если он будет ориентирован неправильно. Из других новостей: Канада большая.   -  person Ben Thul    schedule 12.05.2020
comment
Что возвращает @g.STDistance( geography::Point( lat, lon, 4326 )) как для набора точек, которые, как вы ожидаете, будут внутри полигона, так и для точек за его пределами?   -  person Ben Thul    schedule 12.05.2020
comment
@AlwaysLearning - Да, я проверил угол конверта (‹ 180), а также: g.STArea() ‹ g.ReorientObject().STArea()   -  person bdcoder    schedule 12.05.2020
comment
@BenThul - я ожидаю, что расстояние от g.EnvelopeCenter для внутренних точек будет меньше, чем расстояние для внешних точек, то есть: g.EnvelopeCenter().STDistance( geography::Point(широта, долгота, 4326)) AS STDistance - попробовал это и подтвердил - расстояние для внутренних точек меньше, чем расстояние для внешних точек. До сих пор нет ответа, почему STContains / STWithin не работает для внутренних точек.   -  person bdcoder    schedule 12.05.2020
comment
Я не спрашиваю о расстоянии до центра конверта, а о расстоянии от точки до многоугольника. Если они действительно внутри, я ожидаю, что расстояние равно нулю. Возможно, те, которые, как вы ожидаете, будут находиться внутри, находятся на очень небольшом расстоянии от вашего полигона.   -  person Ben Thul    schedule 13.05.2020
comment
@BenThul Извините, я не понимаю расстояния вашего комментария от точки до многоугольника .. Для вычисления расстояния, очевидно, нужны две точки. Вы имеете в виду точку на краю многоугольника?, точку внутри многоугольника? Я выбрал центральную точку многоугольника, и все тесты прошли в том, что расстояние от центра многоугольника до любой точки внутри многоугольника было меньше, чем расстояние от центра многоугольника до любой точки вне многоугольника.   -  person bdcoder    schedule 16.05.2020
comment
Очевидно, что для вычисления расстояния нужны две точки. Наоборот. Хотя вы можете измерить расстояние между двумя точками, измерение расстояния между двумя произвольными объектами имеет не меньшее значение. В вашем случае это означает кратчайшее расстояние между точкой и всеми точками многоугольника. Что, кстати, и делает STDistance(). Пример, приведенный в документации, измеряет даже расстояние между линией и точкой!   -  person Ben Thul    schedule 16.05.2020
comment
@BenThul - А, спасибо - однако... STDistance тоже, похоже, не работает - Регина, SK (находится ВНУТРИ полигона) - показывает нулевое расстояние: SELECT geography::Point( 50.44609833063177, -104.61851168432615, 4326 ).STDistance( @g ) AS STDistance = 0 116 км к югу -- все еще ВНУТРИ полигона, Weyburn, SK: SELECT geography::Point( 49.667922159371074, -103.85796595373533, 4326 ).STDistance( @g ) AS STDistance = 3387.28093070478 -- НЕ показывает ноль ? -- Вернуться к доске для рисования.   -  person bdcoder    schedule 18.05.2020
comment
Мое обоснование, задав вопрос, заключалось в том, чтобы увидеть, есть ли какая-то грязь в ваших данных. Учитывая, что 49-я параллель определяет большую часть южной границы Канады, я бы поставил под сомнение источник ваших данных о форме канадской суши на данный момент.   -  person Ben Thul    schedule 18.05.2020
comment
Многоугольник был построен вручную (против часовой стрелки), а затем точки были нанесены с помощью карт Google. Все инструменты, к которым у меня есть доступ, указывают, что полигон (форма) является правильным в отношении его использования с географическими методами SQL. Если у кого-то есть какие-либо (бесплатные / онлайн) инструменты, которые они рекомендуют для проверки правильности, пожалуйста, не стесняйтесь вмешиваться - на данный момент я потерял веру - в основном в себя :)   -  person bdcoder    schedule 18.05.2020


Ответы (1)


Потому что в сферической геометрии линии широты не прямые. Дуги большого круга. Ближайший край вашего многоугольника — -122.906113 48.998367, -95.169068 48.966372, который находится значительно севернее 49-й параллели на -103 долготы.

select geography::STLineFromText('LINESTRING(-122.906113 48.998367, -95.169068 48.966372)', 4326);

is

введите здесь описание изображения

person David Browne - Microsoft    schedule 16.06.2020
comment
Мистер Браун - снова вы проходите!! Итак, как нам настроить использование проекции Меркатора с географическими типами SQL, чтобы точки, попадающие внутрь полигона, отображались визуально на карте Bing или Google? Кроме того, если бы был способ показать ОБА полигон и точку в пространственном представлении в SSMS, ответ был бы очевиден. Любой способ показать ОБА многоугольник и точку в пространственном представлении? - person bdcoder; 17.06.2020
comment
Я пробовал все, что мог придумать, чтобы отобразить оба, прежде чем просто построить ближайший край. Возможно, элемент обратной связи SSMS: aka.ms/sqlfeedback. - person David Browne - Microsoft; 17.06.2020
comment
Уже сделано — простое изменение в пространственном представлении, которое позволило бы нам выбирать несколько столбцов для отображения (а не один столбец, как в настоящее время реализовано), было бы ОЧЕНЬ долгожданной функцией. Спасибо еще раз !! - person bdcoder; 17.06.2020