¿Cómo crear, dentro de un polígono, una cuadrícula regular de puntos espaciados x,y en PostGIS?
Como el ejemplo:
¿Cómo crear, dentro de un polígono, una cuadrícula regular de puntos espaciados x,y en PostGIS?
Como el ejemplo:
Eso se hace con generate_series.
Si no quieres escribir manualmente dónde debe empezar y parar la cuadrícula, lo más fácil es crear una función.
No he probado bien lo siguiente, pero creo que debería funcionar:
CREATE OR 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
Para utilizarlo puedes hacerlo:
SELECT makegrid(the_geom, 1000) from mytable;
donde el primer argumento es el polígono en el que quieres la cuadrícula, y el segundo argumento es la distancia entre los puntos de la cuadrícula.
Si quieres un punto por fila sólo tienes que usar ST_Dump como:
SELECT (ST_Dump(makegrid(the_geom, 1000))).geom as the_geom from mytable;
He recogido Nicklas Avén código de la función makegrid y lo hizo un poco más genérico mediante la lectura y el uso de la srid de la geometría del polígono. De lo contrario, el uso de un polígono con un srid definido, daría un error.
La función:
CREATE OR 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
Para utilizar la función se hace exactamente como Nicklas Avén escribió:
SELECT makegrid(the_geom, 1000) from mytable;
o si quiere un punto por fila:
SELECT (ST_Dump(makegrid(the_geom, 1000))).geom as the_geom from mytable;
Espero que esto sea útil para alguien.
Alex
Las personas que utilizan una geometría wgs84 probablemente tendrán problemas con esta función ya que
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
sólo devuelven números enteros. Excepto en el caso de geometrías muy grandes, como los países (que se encuentran en varios grados lat, lng), esto hará que se recoja sólo un punto que la mayoría de las veces ni siquiera se cruza con la propia geometría... => ¡resultado vacío!
Mi problema fue que no puedo usar generate_series() con una distancia decimal en números flotantes como los WSG84... Es por eso que he ajustado la función para conseguir que funcione de todos modos :
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)))
Básicamente es lo mismo. Sólo multiplicar y dividir por 1000000 para obtener los decimales en el juego cuando lo necesito.
Seguro que hay una solución mejor para conseguirlo. ++
Tres algoritmos que utilizan diferentes métodos.
Repo de Github: https://github.com/imran-5/Postgis-Custom
Function ===================================================================
CREATE OR REPLACE FUNCTION public.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;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
----RAISE NOTICE 'No SRID Found.';
ELSE
----RAISE NOTICE 'SRID Found.';
END CASE;
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) THEN
EXIT;
END IF;
CASE i WHEN 0 THEN
y := ST_Y(returnGeom[0]);
ELSE
y := ST_Y(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), y_side, radians(0))::geometry);
END CASE;
x := x_min;
<<xloop>>
LOOP
IF (x > x_max) THEN
EXIT;
END IF;
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;
Utilice la función con una consulta simple, la geometría debe ser válida y de tipo polígono, multipolígono o envolvente
SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;
Segunda función basada en Nicklas Avén algoritmo. He implementado una forma de manejar cualquier SRID.
han actualizado los siguientes cambios en el algoritmo.
Function ===================================================================
CREATE OR REPLACE FUNCTION I_Grid_Point(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
RETURNS SETOF geometry AS $BODY$
DECLARE
x_max decimal;
y_max decimal;
x_min decimal;
y_min decimal;
srid integer := 4326;
input_srid integer;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
RAISE NOTICE 'SRID Not Found.';
ELSE
RAISE NOTICE 'SRID Found.';
END CASE;
CASE spheroid WHEN false THEN
RAISE NOTICE 'Spheroid False';
srid := 4326;
x_side := x_side / 100000;
y_side := y_side / 100000;
else
srid := 900913;
RAISE NOTICE 'Spheroid True';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
x_min := ST_XMin(geom);
y_min := ST_YMin(geom);
RETURN QUERY
WITH res as (SELECT ST_SetSRID(ST_MakePoint(x, y), srid) point FROM
generate_series(x_min, x_max, x_side) as x,
generate_series(y_min, y_max, y_side) as y
WHERE st_intersects(geom, ST_SetSRID(ST_MakePoint(x, y), srid))
) select ST_TRANSFORM(ST_COLLECT(point), input_srid) from res;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
Utilízalo con una simple consulta.
SELECT I_Grid_Point(geom, 22, 15, false) from polygons;
Result===================================================================
Function==================================================================
CREATE OR REPLACE FUNCTION I_Grid_Point_Series(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
RETURNS SETOF geometry AS $BODY$
DECLARE
x_max decimal;
y_max decimal;
x_min decimal;
y_min decimal;
srid integer := 4326;
input_srid integer;
x_series DECIMAL;
y_series DECIMAL;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
geom := ST_SetSRID(geom, srid);
RAISE NOTICE 'SRID Not Found.';
ELSE
RAISE NOTICE 'SRID Found.';
END CASE;
CASE spheroid WHEN false THEN
RAISE NOTICE 'Spheroid False';
else
srid := 900913;
RAISE NOTICE 'Spheroid True';
END CASE;
input_srid:=st_srid(geom);
geom := st_transform(geom, srid);
x_max := ST_XMax(geom);
y_max := ST_YMax(geom);
x_min := ST_XMin(geom);
y_min := ST_YMin(geom);
x_series := CEIL ( @( x_max - x_min ) / x_side);
y_series := CEIL ( @( y_max - y_min ) / y_side );
RETURN QUERY
SELECT st_collect(st_setsrid(ST_MakePoint(x * x_side + x_min, y*y_side + y_min), srid)) FROM
generate_series(0, x_series) as x,
generate_series(0, y_series) as y
WHERE st_intersects(st_setsrid(ST_MakePoint(x*x_side + x_min, y*y_side + y_min), srid), geom);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;
Utilízalo con una simple consulta.
SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons;
Result==========================================================================
Este algoritmo debería estar bien:
createGridInPolygon(polygon, resolution) {
for(x=polygon.xmin; x<polygon.xmax; x+=resolution) {
for(y=polygon.ymin; y<polygon.ymax; y+=resolution) {
if(polygon.contains(x,y)) createPoint(x,y);
}
}
}
donde "polígono" es el polígono y "resolución" es la resolución de malla requerida.
Para implementarlo en PostGIS, pueden ser necesarias las siguientes funciones:
Buena suerte.
I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.