Подтвердить что ты не робот

SQL Server 2008 Spatial: найти точку в многоугольнике

Я использую пространственные типы данных SQL Server 2008. У меня есть таблица со всеми государствами (как многоугольники) как тип данных GEOMETRY. Теперь я хочу проверить, находится ли точечная координата (широты, долготы) как тип данных GEOGRAPHY внутри этого состояния или нет.

Я не смог найти какой-либо пример, используя новые типы пространственных данных. В настоящее время у меня есть обходное решение, которое было реализовано много лет назад, но оно имеет некоторые недостатки.

У меня как SQL Server 2008, так и 2012. Если новая версия имеет некоторые улучшения, я тоже могу начать работать с ней.

Спасибо.

ОБНОВЛЕНИЕ 1:

Я добавляю образец кода для большей ясности.

declare @s geometry  --GeomCol is of this type too.
declare @z geography --GeogCol is of this type too.

select @s = GeomCol
from AllStates
where STATE_ABBR = 'NY'

select @z = GeogCol
from AllZipCodes
where ZipCode = 10101
4b9b3361

Ответ 1

Я думаю, что метод географии STIntersects() будет делать то, что вы хотите:

DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText('POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))', 4326);
SET @h = geography::Point(47.653, -122.358, 4326)

SELECT @g.STIntersects(@h)

Ответ 2

Если вы не можете изменить тип данных для сохраненных полигонов на GEOGRAPHY, тогда вы можете преобразовать широту и долготу ввода в GEOMETRY и использовать STContains или STIntersects для преобразованного значения.

DECLARE @PointGeography GEOGRAPHY = geography::Point(43.365267, -80.971974, 4326)
DECLARE @PointGeometry GEOMETRY = geometry::STGeomFromWKB(@PointGeography.STAsBinary(), 4326);

SELECT @PolygonGeometry.STContains(@PointGeometry);

Переход в противоположном направлении - попытка преобразования полигонов GEOMETRY в GEOGRPAHY - подвержена ошибкам и, вероятно, не сработает из моего опыта.

И обратите внимание, что если вы попытаетесь создать точку GEOMETRY непосредственно из значений широты и долготы, то STContains (или STIntersects) не будет работать (т.е. не даст совпадения, когда они должны).

Ответ 3

declare @g geometry
set @g=geometry::STGeomFromText('POLYGON((-33.229869 -70.891988, -33.251124 -70.476616, -33.703094 -70.508045, -33.693931 -70.891052,-33.229869 -70.891988))',0)

DECLARE @h geometry;

SET @h = geometry::STGeomFromText('POINT(-33.3906300 -70.5725020)', 0);
SELECT @g.STContains(@h);

Ответ 4

  • Вам не следует смешивать геометрию и географию. Геометрия для FLAT PLANES, Geography для SPHEROIDS (например, Earth).
  • Вы должны "примирить SRID", чтобы справиться с этим. Каждый SRID (например, 2913 = NZG2000) описывает отношение трансформации. Каждый SRID можно использовать для отображения в/из однородной сферы, то есть как вы получаете от одного к другому.
  • Пока вы не дойдете до "одного" SRID по обоим значениям, многие из функций .STXXX вернут NULL (в обоих случаях у вас может быть 0)
  • Если они не совпадают, но вы притворяетесь, что у вас могут быть ошибки в случаях краев.
  • Если вы потратите некоторое время "precalc", вы можете определить верхние/левые и нижние/правые точки для связанных ограничителей (и хранить их) и использовать эти значения в индексах для ограничения проверяемых записей. Если A T/L < B B/R и A B/R > B T/L они не могут перекрываться, что означает, что простая 4-значная проверка в вашем WHERE ограничит ваши проверки STWithin.

Вот пример, который я использовал в SRID 2193. Все дороги в радиусе 3 км данной точки и внутри определенной школьной зоны

DECLARE @g geometry

SELECT @g = GEO2193 FROM dbo.schoolzones WHERE schoolID = 319

SELECT DD.full_road_name, MIN(convert(int,  dd.address_number)), MAX(convert(int,  dd.address_number))
FROM (

select A.* from dbo.[street-address] A

WHERE (((A.Shape_X - 1566027.50505) * (A.Shape_X - 1566027.50505)) + ((A.Shape_Y - 5181211.81675) * (A.Shape_Y - 5181211.81675))) < 9250000

and a.shape_y > 5181076.1943481788

and a.shape_y < 5185097.2169968253

and a.shape_x < 1568020.2202472512

and a.shape_x > 1562740.328937705

and a.geo2193.STWithin(@g) = 1
) DD
GROUP BY DD.full_road_name
ORDER BY DD.full_road_name

Ответ 5

Если у вас есть таблица (пример: SubsriberGeo), в которой один из столбцов (пример: местоположение) имеет географические точки в качестве значений, и вы хотите найти все точки из этой таблицы, которые находятся внутри многоугольника, вот способ сделать это:

 WITH polygons
 AS (SELECT 'p1' id, 
            geography::STGeomFromText('polygon ((-113.754429 52.471834 , 1 5, 5 5, -113.754429 52.471834))', 4326) poly
),
 points
 AS (SELECT [SubscriberId],[Location] as p FROM [DatabaseName].[dbo].[SubscriberGeo])
 SELECT DISTINCT 
        points.SubscriberId, 
        points.p.STAsText() as Location
 FROM polygons
      RIGHT JOIN points ON polygons.poly.STIntersects(points.p) = 1
 WHERE polygons.id IS NOT NULL;