Я пытался сделать обтравочные полигоны, объединяя этот код с кодом кубинга "postGIS in action", но создан только один полигон ... Я что-то забыл? СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ФУНКЦИЮ makegrid (geometry, integer, integer) ВОЗВРАЩАЕТ геометрию AS SELECT st_intersection (g1.geom1, g2.geom2) AS geom FROM (ВЫБРАТЬ $ 1 AS geom1) КАК g1 INNER JOIN (Выбрать st_setsrid (CAST (ST_MakeBox2d (st_sets) ST_Point (x, y), $ 3), st_setsrid (ST_Point (x + $ 2, y + $ 2), $ 3)) как геометрия), $ 3) как geom2 FROM generate_series (floor (st_xmin ($ 1)) :: int, потолок ( st_xmax ($ 1)) :: int, $ 2) как x, generate_series (floor (st_ymin ($ 1)) :: int, потолок (st_ymax (
aurel_nc
посмотрите на мой подробный ответ.
Мухаммед Имран Сиддик
Ответы:
30
Вы делаете это с помощью generate_series.
Если вы не хотите писать вручную, где сетка должна начинаться и останавливаться, проще всего создать функцию.
Я не проверял ниже должным образом, но я думаю, что это должно работать:
CREATEOR REPLACE FUNCTION makegrid(geometry, integer)
RETURNS geometry AS'SELECT ST_Collect(ST_POINT(x,y)) FROM
generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1)-st_xmin($1))::int, $2) as x
,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1)-st_ymin($1))::int,$2) as y
where st_intersects($1,ST_POINT(x,y))'
LANGUAGE sql
Чтобы использовать его, вы можете сделать:
SELECT makegrid(the_geom,1000)from mytable;
где первый аргумент - это полигон, в котором вы хотите использовать сетку, а второй аргумент - это расстояние между точками в сетке.
Если вы хотите получить одно очко за строку, вы просто используете ST_Dump, например:
SELECT(ST_Dump(makegrid(the_geom,1000))).geom as the_geom from mytable;
Вам может понадобиться добавить st_setSRID () к функциям st_point, иначе st_intersects не работает.
JaakL
Добавил мою проверенную версию в качестве отдельного ответа.
JaakL
12
Я взял код функции Nicklas Avén makegrid и сделал его более универсальным, читая и используя srid из геометрии многоугольника. В противном случае использование многоугольника с определенным srid приведет к ошибке.
Функция:
CREATEOR REPLACE FUNCTION makegrid(geometry, integer)
RETURNS geometry AS'SELECT ST_Collect(ST_SetSRID(ST_POINT(x,y),ST_SRID($1))) FROM
generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1)-st_xmin($1))::int, $2) as x
,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1)-st_ymin($1))::int,$2) as y
where st_intersects($1,ST_SetSRID(ST_POINT(x,y),ST_SRID($1)))'
LANGUAGE sql
Чтобы использовать функцию сделано точно так, как написал Никлас Авен :
SELECT makegrid(the_geom,1000)from mytable;
или если вы хотите одну точку в строке:
SELECT(ST_Dump(makegrid(the_geom,1000))).geom as the_geom from mytable;
Принятый ответ не работает с моими данными из-за ошибок SRID. Эта модификация работает лучше.
Виталий Исаев
Возможно, вы захотите что-то добавить, когда полигон пересекает антимеридиан? Я могу предположить, что это вызвало бы проблему с xmin / xmax.
Томас
2
Это не сработало для меня. Использование Postgres 9.6 и PostGIS 2.3.3. Внутри вызова generate_series я должен был поместить это как второй параметр «потолок (st_xmax ($ 1)) :: int» вместо «потолок (st_xmax ($ 1) -st_xmin ($ 1)) :: int» и «потолок ( st_ymax ($ 1)) :: int "вместо" потолка (st_ymax ($ 1) -st_ymin ($ 1)) :: int "
Vitor Sapucaia
Я одобряю предыдущий комментарий; верхняя граница generate_series должна быть максимальным значением, а не верхним пределом разницы (max - min).
Р. Буржон
10
Люди, использующие геометрию wgs84, вероятно, будут иметь проблемы с этой функцией, так как
generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1))::int,$2)as x
,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1))::int,$2)as y
вернуть только целые числа. За исключением очень больших геометрий, таких как страны (которые лежат на нескольких широтах, долготах), это приведет к тому, что будет собираться только 1 точка, которая в большинстве случаев даже не пересекает саму геометрию ... => пустой результат!
Моя проблема была в том, что я не могу использовать generate_series () с десятичным расстоянием для плавающих чисел, таких как WSG84 ... Вот почему я настроил функцию, чтобы она все равно работала:
SELECT ST_Collect(st_setsrid(ST_POINT(x/1000000::float,y/1000000::float),st_srid($1)))FROM
generate_series(floor(st_xmin($1)*1000000)::int, ceiling(st_xmax($1)*1000000)::int,$2)as x ,
generate_series(floor(st_ymin($1)*1000000)::int, ceiling(st_ymax($1)*1000000)::int,$2)as y
WHERE st_intersects($1,ST_SetSRID(ST_POINT(x/1000000::float,y/1000000::float),ST_SRID($1)))
В основном точно так же. Просто умножьте и разделите на 1000000, чтобы получить десятичные дроби в игре, когда мне это нужно.
Конечно, есть лучшее решение для достижения этой цели. ++
Это умный обходной путь. Вы проверили результаты? Они последовательны?
Пабло
Здравствуй. Да пабло. Я доволен результатами до сих пор. Мне нужно было построить полигон с относительной высотой над землей. (Я использую SRTM для расчета высоты, которую я хочу для каждой точки сетки). Сейчас мне не хватает только способа включить точки, которые лежат по периметру многоугольника. В настоящее время визуализированная форма несколько обрезана по краю.
Жюльен Гарсия
сработало, когда все остальные решения потерпели неудачу, спасибо!
Обратите внимание, что если у вас есть большие сложные области полигонов (например, у меня есть буфер береговой линии), то этот подход не совсем оптимален.
Простой и лучший подход, использующий фактическое расстояние от Земли до координат x и y. Алгоритм работает с любым SRID, внутренне он работает с WGS 1984 (EPSG: 4326) и преобразовывает результат обратно во входной SRID.
Функция ======================================================= ==================
CREATEOR REPLACE FUNCTIONpublic.I_Grid_Point_Distance(geom public.geometry, x_side decimal, y_side decimal)
RETURNS public.geometry AS$BODY$DECLARE
x_min decimal;
x_max decimal;
y_max decimal;
x decimal;
y decimal;
returnGeom public.geometry[];
i integer :=-1;
srid integer :=4326;
input_srid integer;BEGINCASE st_srid(geom)WHEN0THEN
geom := ST_SetSRID(geom, srid);----RAISE NOTICE 'No SRID Found.';ELSE----RAISE NOTICE 'SRID Found.';ENDCASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_min := ST_XMin(geom);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
y := ST_YMin(geom);
x := x_min;
i := i +1;
returnGeom[i]:= st_setsrid(ST_MakePoint(x, y), srid);<<yloop>>
LOOP
IF(y > y_max)THENEXIT;ENDIF;CASE i WHEN0THEN
y := ST_Y(returnGeom[0]);ELSE
y := ST_Y(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), y_side, radians(0))::geometry);ENDCASE;
x := x_min;<<xloop>>
LOOP
IF(x > x_max)THENEXIT;ENDIF;
i := i +1;
returnGeom[i]:= st_setsrid(ST_MakePoint(x, y), srid);
x := ST_X(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), x_side, radians(90))::geometry);END LOOP xloop;END LOOP yloop;RETURN
ST_CollectionExtract(st_transform(ST_Intersection(st_collect(returnGeom), geom), input_srid),1);END;$BODY$ LANGUAGE plpgsql IMMUTABLE;
Используйте функцию с простым запросом, геометрия должна быть верной и полигона, многогранника или типа конверта
SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;
Результат ================================================= =====================
Вторая функция основана на алгоритме Никласа Авена . Я улучшил его для обработки любого SRID.
Обновите следующие изменения в алгоритме.
Отдельная переменная для направления x и y для размера пикселя,
Новая переменная для расчета расстояния в сфероиде или эллипсоиде.
Введите любой SRID, функция преобразования Geom в рабочую среду Spheroid или Ellipsoid Datum, затем примените расстояние к каждой стороне, получите результат и преобразуйте его во входной SRID.
Функция ======================================================= ==================
CREATEOR REPLACE FUNCTION makegrid(geometry, integer, integer)
RETURNS geometry AS'SELECT ST_Collect(st_setsrid(ST_POINT(x,y),$3)) FROM
generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1))::int,$2) as x
,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1))::int,$2) as y
where st_intersects($1,st_setsrid(ST_POINT(x,y),$3))'
LANGUAGE sql
Использование:
SELECT(ST_Dump(makegrid(the_geom,1000,3857))).geom as the_geom from my_polygon_table
Привет, я получаю пустой результат с функцией makegrid. Шейп-файл был импортирован в PostGIS с помощью shp2pgsql. Понятия не имею, что может вызвать проблемы, srs установлен на wgs84.
Михал Циммерман
3
Вот еще один подход, который, безусловно, быстрее и проще для понимания.
Например, для сетки 1000 на 1000 м:
SELECT(ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0))).geom
FROM the_polygon
Также сохраняется оригинальный SRID.
Этот фрагмент преобразует геометрию многоугольника в пустой растр, а затем преобразует каждый пиксель в точку. Преимущество: нам не нужно снова проверять, пересекает ли исходный многоугольник точки.
Необязательный:
Вы также можете добавить выравнивание сетки с помощью параметров gridx и gridy. Но так как мы используем центр тяжести каждого пикселя (а не угол), нам нужно использовать модуль для вычисления правильного значения:
SELECT(ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0,mod(1000/2,100),mod(1000/2,100)))).geom
FROM the_polygon
С mod(grid_size::integer/2,grid_precision)
Вот функция postgres:
CREATEOR REPLACE FUNCTION st_makegrid(geometry, float, integer)
RETURNS SETOF geometry AS'SELECT (ST_PixelAsCentroids(ST_AsRaster($1,$2::float,$2::float,mod($2::int/2,$3),mod($2::int/2,$3)))).geom'
LANGUAGE sql;
Может использоваться с:
SELECT makegrid(the_geom,1000.0,100)as geom from the_polygon
-- makegrid(the_geom,grid_size,alignement)
Небольшое потенциальное обновление к предыдущим ответам - третий аргумент в качестве масштаба для wgs84 (или используйте 1 для нормальных), а также округление внутри кода для выравнивания масштабированных точек на нескольких фигурах.
Надеюсь, это поможет, Мартин
CREATEOR REPLACE FUNCTION makegrid(geometry, integer, integer)
RETURNS geometry AS/*geometry column , integer: distance between points, integer: scale factor for distance (useful for wgs84, e.g. use there 50000 as distance and 1000000 as scale factor*/'
SELECT ST_Collect(st_setsrid(ST_POINT(x/$3::float,y/$3::float),st_srid($1))) FROM
generate_series(
(round(floor(st_xmin($1)*$3)::int/$2)*$2)::int,
(round(ceiling(st_xmax($1)*$3)::int/$2)*$2)::int,
$2) as x ,
generate_series(
(round(floor(st_ymin($1)*$3)::int/$2)*$2)::int,
(round(ceiling(st_ymax($1)*$3)::int/$2)*$2)::int,
$2) as y
WHERE st_intersects($1,ST_SetSRID(ST_POINT(x/$3::float,y/$3::float),ST_SRID($1)))
'
LANGUAGE sql
Ответы:
Вы делаете это с помощью generate_series.
Если вы не хотите писать вручную, где сетка должна начинаться и останавливаться, проще всего создать функцию.
Я не проверял ниже должным образом, но я думаю, что это должно работать:
Чтобы использовать его, вы можете сделать:
где первый аргумент - это полигон, в котором вы хотите использовать сетку, а второй аргумент - это расстояние между точками в сетке.
Если вы хотите получить одно очко за строку, вы просто используете ST_Dump, например:
НТН
Никлас
источник
Я взял код функции Nicklas Avén makegrid и сделал его более универсальным, читая и используя srid из геометрии многоугольника. В противном случае использование многоугольника с определенным srid приведет к ошибке.
Функция:
Чтобы использовать функцию сделано точно так, как написал Никлас Авен :
или если вы хотите одну точку в строке:
Надеюсь, это будет полезно для кого-то.
Alex
источник
Люди, использующие геометрию wgs84, вероятно, будут иметь проблемы с этой функцией, так как
вернуть только целые числа. За исключением очень больших геометрий, таких как страны (которые лежат на нескольких широтах, долготах), это приведет к тому, что будет собираться только 1 точка, которая в большинстве случаев даже не пересекает саму геометрию ... => пустой результат!
Моя проблема была в том, что я не могу использовать generate_series () с десятичным расстоянием для плавающих чисел, таких как WSG84 ... Вот почему я настроил функцию, чтобы она все равно работала:
В основном точно так же. Просто умножьте и разделите на 1000000, чтобы получить десятичные дроби в игре, когда мне это нужно.
Конечно, есть лучшее решение для достижения этой цели. ++
источник
Этот алгоритм должен быть в порядке:
где «полигон» - это полигон, а «разрешение» - требуемое разрешение сетки.
Для его реализации в PostGIS могут потребоваться следующие функции:
Удачи!
источник
Три алгоритма с использованием разных методов.
Github Repo Link
Функция ======================================================= ==================
Используйте функцию с простым запросом, геометрия должна быть верной и полигона, многогранника или типа конверта
SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;
Результат ================================================= =====================
Вторая функция основана на алгоритме Никласа Авена . Я улучшил его для обработки любого SRID.
Обновите следующие изменения в алгоритме.
Функция ======================================================= ==================
Используйте это с простым запросом.
SELECT I_Grid_Point(geom, 22, 15, false) from polygons;
Результат ================================================= ==================
Функция ================================================= =================
Используйте это с простым запросом.
SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons;
Результат ================================================= =========================источник
Итак, моя исправленная версия:
Использование:
источник
Вот еще один подход, который, безусловно, быстрее и проще для понимания.
Например, для сетки 1000 на 1000 м:
Также сохраняется оригинальный SRID.
Этот фрагмент преобразует геометрию многоугольника в пустой растр, а затем преобразует каждый пиксель в точку. Преимущество: нам не нужно снова проверять, пересекает ли исходный многоугольник точки.
Необязательный:
Вы также можете добавить выравнивание сетки с помощью параметров gridx и gridy. Но так как мы используем центр тяжести каждого пикселя (а не угол), нам нужно использовать модуль для вычисления правильного значения:
С
mod(grid_size::integer/2,grid_precision)
Вот функция postgres:
Может использоваться с:
источник
Небольшое потенциальное обновление к предыдущим ответам - третий аргумент в качестве масштаба для wgs84 (или используйте 1 для нормальных), а также округление внутри кода для выравнивания масштабированных точек на нескольких фигурах.
Надеюсь, это поможет, Мартин
источник