11 votos

PostGIS ST_ConvexHull() ¿pero perpendicular a una línea?

Tengo un requisito bastante especial para la manipulación de geometría en PostGIS.

Considera el siguiente caso:

introducir descripción de la imagen aquí

Tengo un polígono y una característica de línea. Si hago un ST_ConvexHull() o ST_ConcaveHull() obtendría algo como en el lado izquierdo. Sin embargo, lo que necesito es el área que encierra el polígono y la línea donde las líneas perpendiculares tocan el polígono. ¿Existe una función o alguna otra forma de varios pasos para lograr esto en PostGIS?

Creo que con ST_ShortestLine() desde cada vértice del polígono hasta la línea podría ser posible. Sin embargo, todavía no sé cómo puedo obtener el área a partir del conjunto de líneas más cortas.

11voto

JoeBe Puntos 13

OK. Lo resolví por mi cuenta. Al realizar un ST_ShortestLine() en cada vértice del polígono y luego un ST_Convexhull() en este conjunto de líneas y finalmente un ST_Difference() entre esa área y el área del polígono obtendré lo que necesito.

4voto

mathieu Puntos 53

En el caso específico (es decir, tu ejemplo) donde

  • la línea sigue el eje Y
  • el borde opuesto (más alto) del polígono es igual al segmento de la caja delimitadora (más alto)

puedes simplemente extender la caja delimitadora del polígono para obtener el área deseada:

SELECT ST_MakeBox2D(
        ST_MakePoint(ST_XMin(ply.box), ST_YMin(ln.box)),
        ST_MakePoint(ST_XMax(ply.box), ST_YMax(ply.box))
       )::GEOMETRY(POLYGON) AS geom
FROM   (
    SELECT ply.geom::BOX2D AS box
    FROM   
) AS ply, (
    SELECT ln.geom::BOX2D AS box
    FROM   
) AS ln
;

Esto permite relaciones de conjunto de entrada (creando esta área solo para el par más cercano de geometrías, etc.) y ajustes al área resultante.


En todos los demás casos, probablemente sería más eficiente simplemente volcar todos los vértices del polígono, obtener su proyección en la línea y crear la envolvente convexa directamente a partir del conjunto de puntos, ya sea

  • pre-colectando pares:

    SELECT ST_ConvexHull(
             ST_Collect(geom)
           ) AS geom
    FROM   (
      SELECT ST_Collect(
               dmp.geom,
               ST_LineinterpolatePoint(
                 ln.geom,
                 ST_LineLocatePoint(
                   ln.geom,
                   dmp.geom
                 )
               )
             ) AS geom
      FROM    AS ply,
              AS ln,
             LATERAL ST_DumpPoints(ply.geom) AS dmp
    ) q
    ;
  • o una simple UNION de todos los puntos individuales:

    WITH
      pts AS (
        SELECT dmp.geom
        FROM   ply,
               LATERAL ST_DumpPoints(geom) AS dmp
      )
    SELECT ST_ConvexHull(
             ST_Collect(geom)
           ) AS geom
    FROM   (
      SELECT geom
      FROM   pts
      UNION ALL
      SELECT ST_LineinterpolatePoint(
               ln.geom,
               ST_LineLocatePoint(
                 ln.geom,
                 pts.geom
               )
             ) AS geom
      FROM   ln, pts
    ) q
    ;

Preferiría el primero, excepto cuando ya hay una lista de CTEs.

2voto

Cyril Puntos 141

Otra implementación.

Por lo tanto, si tus formas tienen líneas verticales perpendiculares a la línea horizontal, como se muestra en tu ilustración,

ejecuta el script:

CON
tbla COMO (SELECT ST_ShortestLine(a.geom, b.geom) geom DE (SELECT (ST_DumpPoints(geom)).geom DE polígono) a JOIN línea b ON true),
tblb COMO (SELECT geom, ST_Length(geom) longitud DE tbla AGRUPAR POR geom ORDENAR POR longitud DESC LIMIT 2)
SELECT ST_PointsInStarPolygon(geom) geom DE (SELECT ST_Union(geom) geom DE
        (SELECT (ST_DumpPoints(geom)).geom DE tblb) a) b;

Además de las funciones básicas, no olvides la existencia de funciones personalizadas, como: ST_PointsInStarPolygon(https://gis.stackexchange.com/a/350004/120129) - desarrollado por Martin Davis - (usuario:14766).

¡Soluciones espaciales originales! :-)

Actualizar

¡dr-jts, así es como nacen nuevas funciones espaciales personalizadas simples escritas en GEO SQL! :-)

¡No dejaré que se desperdicien buenas herramientas geoespaciales escritas en lenguaje de programación SQL! :-)

CREAR O REEMPLAZAR FUNCION ST_SnapPolygonToLine(
    geom1 GEOMETRÍA,
    geom2 GEOMETRÍA)
DEVUELVE GEOMETRÍA COM 
$BODY$
CON
tbla COMO (SELECT (ST_Dump($1)).geom),
tblb COMO (SELECT (ST_Dump($2)).geom),
tblc COMO (SELECT ST_ShortestLine(a.geom, b.geom) geom DE (SELECT (ST_DumpPoints(geom)).geom DE tbla) a JOIN tblb b ON true)
SELECT ST_PointsInStarPolygon(geom) geom DE (SELECT ST_Union(geom) geom DE
        (SELECT (ST_DumpPoints(geom)).geom DE tblc) a) b;
$BODY$
LENGUAJE SQL

EJECUTAR

SELECT ST_SnapPolygonToLine(a.geom, b.geom) geom DE polígono a JOIN línea b ON true

1voto

dr_jts Puntos 61

Aquí tienes un esquema de otra solución:

  1. Para cada vértice en el contorno del polígono, usa ST_LineLocatePoint para encontrar su índice fraccional a lo largo de la línea.
  2. Construye los segmentos de línea desde cada vértice hasta la línea, y elige los más cortos con índice máximo y mínimo
  3. Construye la sublínea a lo largo de la línea base entre los índices máximo y mínimo
  4. Extrae todos los segmentos de línea del polígono
  5. Polygoniza los segmentos de línea extraídos y construidos. Esto debería producir dos polígonos
  6. Une los resultados de la polygonización

Esto va a ser complejo de implementar en SQL. Una función podría ser una mejor forma de implementar esto.

i-Ciencias.com

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.

Powered by:

X