7 votos

Encontrar el inicio del río

Editar: Pregunta de seguimiento aquí (= Encontrar polígonos de cabecera ).

¿Cómo puedo determinar el inicio de un río en PostGIS?

Tengo una red fluvial (Multiline) y quiero encontrar los puntos de inicio de los ríos.

enter image description here

Puedo seleccionar los puntos de inicio (rectángulos en el gráfico) utilizando

SELECT
  ST_StartPoint(ST_LineMerge(a.geom)) as stp, a.gid AS gid
FROM 
  spatial.stream AS a

y de forma similar los puntos finales (cruces). Pero, ¿cómo puedo encontrar el inicio del río - no de los segmentos de la línea?

He intentado algo así como (encontrar los puntos de inicio, que no se cruzan con los puntos finales):

SELECT
  ST_StartPoint(ST_LineMerge(a.geom)) as stp, a.gid AS gid
FROM 
  spatial.stream AS a, spatial.stream AS b
WHERE   
  ST_Disjoint(ST_StartPoint(ST_LineMerge(a.geom)), ST_EndPoint(ST_LineMerge(b.geom)))

Pero esto lleva una eternidad:

"Nested Loop  (cost=0.00..1019343418.86 rows=525839789 width=323)"
"  Join Filter: st_disjoint(st_startpoint(st_linemerge(a.geom)), st_endpoint(st_linemerge(b.geom)))"
"  ->  Seq Scan on stream_typ b  (cost=0.00..4498.18 rows=39718 width=323)"
"  ->  Materialize  (cost=0.00..6364.77 rows=39718 width=319)"
"        ->  Seq Scan on stream_typ a  (cost=0.00..4498.18 rows=39718 width=319)"

Editar: No lo ejecuté hasta que terminó, por lo que incluso no sé si esta consulta devuelve el resultado deseado. Pero mirando las filas devueltas, esto no parece correcto (demasiado)).

Al final quiero encontrar los polígonos (grises en el gráfico) donde empieza un/un río (los polígonos verdes), pero no aquellos donde los ríos sólo pasan (el polígono rojo, sin inicios dentro). ¡Pero tener sólo los puntos de inicio sería un buen comienzo!

¿Alguna idea de cómo se puede hacer esto en PostGis? (también otras soluciones de código abierto como GRASS, R, etc. son bienvenidas).

Actualización : Mi idea de extraer sólo los puntos de inicio no era lo suficientemente concisa :( Por ejemplo, considere la siguiente situación: enter image description here

Los polígonos verdes tienen ambos puntos de arranque (verdaderos) dentro y son los que quiero. El polígono rojo también tiene puntos de inicio dentro, pero el río fluye a través (así que no hay polígono de cabecera). Con la solución de John abajo obtengo ambos. Sólo quiero los arroyos de cabecera. No estoy seguro de si mi idea con los puntos de inicio llevará a la solución (me invento una nueva pregunta si lo deseo). He pensado en dos cláusulas Where:

  • El polígono contiene un punto de inicio
  • sin flujo de paso (= sólo 1 intersección del polígono con el arroyo).

He probado esto:

SELECT 
    polyg.*
FROM 
    polyg, start_points, stream
WHERE 
    st_contains(polyg.geom, start_points.geom)
    AND ST_Npoints(ST_Intersection(poly.geom, stream.geom)) < 2

Pero nunca termina :( ¿Hay alguna forma mejor de consultar los polígonos de la cabecera?

4voto

Patrick Puntos 20392

ST_StartPoint es la función correcta para encontrar nodos individuales al inicio de un Linestring Sin embargo, no funciona con MultiLinestring por lo que tendrá que utilizar ST_Dump para obtener el constituyente Linestrings . Si he entendido bien su pregunta, entonces quiere todos los puntos de inicio que no sean también puntos finales de más de una línea, es decir, los puntos donde se unen dos ríos.

Como ejemplo, la siguiente Multilínea tiene 3 segmentos de línea con puntos de inicio que se encuentran en el punto (0, 0), y uno que sale de él.

WITH start_nodes as 
  (SELECT ST_StartPoint((ST_Dump(ST_Geomfromtext('MULTILINESTRING((10 10, 0 0), (5 5, 0 0), 
    (1 1, 0 0), (0 0, 20 20))'))).geom) as geom),
  end_nodes as 
   (SELECT ST_EndPoint((ST_Dump(st_geomfromtext('MULTILINESTRING((10 10, 0 0), (5 5, 0 0), 
     (1 1, 0 0), (0 0, 20 20))'))).geom) as geom)
  SELECT st_astext(sn.geom) 
  FROM start_nodes sn 
  WHERE sn.geom NOT IN (SELECT geom FROM end_nodes);

que devuelve

 POINT(10 10)
 POINT(5 5)
 POINT(1 1)

excluyendo Point(0,0) como era de esperar. La idea es incluir sólo aquellos puntos de inicio que no sean también puntos finales.

En tu caso, la consulta podría escribirse como,

WITH linestrings as 
  (SELECT (ST_DUMP(ST_LineMerge(geom))).geom as geom FROM spatial.stream),
start_points as
   (SELECT ST_StartPoint(geom) as geom, from linestrings),
end_points as 
   (SELECT ST_EndPoint(geom) as geom from linestrings)
SELECT sp.geom from start_points sp 
WHERE sp.geom not in (SELECT geom from end_points);

La idea es primero fusionar y dividir (st_dump) las líneas que componen el río, luego agarrar los puntos de inicio y final, y finalmente seleccionar sólo aquellos puntos de inicio que no son también puntos finales - ya que esto es donde dos, o más, ríos se unen.

Descargo de responsabilidad: no he probado esta segunda consulta y puede que haya entendido mal la pregunta o haya cometido un error lógico, pero creo que es un buen punto de partida.

1voto

bob-the-destroyer Puntos 138

Echa un vistazo a http://blog.cleverelephant.ca/2010/07/network-walking-in-postgis.html?m=1 (Justo en la dirección opuesta de "caminar")

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