Si puedes usar Postgresql/PostGIS tengo este fragmento de código para ti. Puede que te sirva de ayuda. La estrategia consiste en calcular la distancia entre cada vértice del río y el punto de la estación (lista de adyacencia) y seleccionar los dos más cercanos para construir el segmento correspondiente. Creo que una transcripción en Python será fácil.
Preparación del conjunto de datos del río:
-- create a river table
CREATE TABLE river (id SERIAL);
-- add a PostGIS LINESTRING column
SELECT addGeometryColumn('public','river','geom',4326,'LINESTRING',2);
-- bring in a river ...
INSERT INTO river(geom)
VALUES (ST_GeometryFromText(
'LINESTRING(
13.6938847 53.8612068,
13.6974361 53.8628047,
13.7013093 53.8634454,
13.7038579 53.8632003,
13.7058647 53.8627565,
13.7085524 53.8616235,
13.7102725 53.8610502,
13.7127681 53.8602984,
13.7166154 53.8596167,
13.7185271 53.8596682,
13.7216061 53.8607707)',
4326));
Preparación del conjunto de datos de la estación:
-- create a table for the river_stations
CREATE TABLE river_station (id SERIAL);
-- add a PostGIS POINT column
SELECT addGeometryColumn('public','river_station','geom',4326,'POINT',2);
-- Set some pointes near the river
INSERT INTO river_station(geom) VALUES
(ST_GeometryFromText('POINT(13.70 53.85)',4326)),
(ST_GeometryFromText('POINT(13.71 53.86)',4326));
La función que ayudará a encontrar el segmento.
-- Function to find the neares segment of a STATION type POINT
-- to a LINESTRING hold in table river
-- as gives you the corresponding WKT LINESTRING
CREATE OR REPLACE FUNCTION nearest_segment (GEOMETRY)
RETURNS TEXT AS $$
DECLARE result TEXT;
pos INTEGER;
rec RECORD;
station GEOMETRY;
river_id INTEGER;
posX TEXT;
posY TEXT;
BEGIN
-- Station Geometry parameter
station := $1;
-- Flag for adding the comma in WKT
pos := 0;
-- LINSTRING prefix in result
result ='LINESTRING(';
-- Find the two closest points of the river goemetry to the station
FOR rec IN SELECT
(ST_DumpPoints(geom)).geom as point,
st_distance((ST_DumpPoints(geom)).geom, station) as distance
FROM river
-- WHERE id = $2 if you want to a special select a river object
ORDER BY distance ASCI LIMIT 2
LOOP
-- FLOAT8 to TEXT conversation of the segement part
posX := st_X(rec.point)::TEXT;
posY := st_Y(rec.point)::TEXT;
-- BUILD the WKT STRING
IF pos = 0 THEN
result := result||posX||' '||posY;
ELSE
result := result||', '||posX||' '||posY;
END IF;
-- set mark to use commas before
pos := pos + 1;
END LOOP;
-- give back the WKT String, as an alternative a geometry
RETURN result||')';
END;
$$ LANGUAGE plpgsql;
Consultar los segmentos:
-- Find the segments for the river
SELECT
st_astext(geom) as station,
nearest_segment(geom) as segment
FROM
river_station;
El resultado:
station | segment
--------------------+----------------------------------------------------------
POINT(13.7 53.85) | LINESTRING(13.6938847 53.8612068, 13.6974361 53.8628047)
POINT(13.71 53.86) | LINESTRING(13.7102725 53.8610502, 13.7085524 53.8616235)
Puede haber problemas, si dos segmentos de ríos diferentes están muy cerca de la estación. Entonces necesitará un parámetro (un river_id en el conjunto de estaciones) para resolver la situación ambigua.
Para añadir los ID's de las river_stations se pueden utilizar sentencias SQL:
Prepara la mesa para colocar los segmentos:
CREATE TABLE river_segments (id SERIAL, ref_station INTEGER);
SELECT addGeometryColumn('public','river_segments','geom',4326,'LINESTRING',2);
Introduzca los conjuntos de datos:
INSERT INTO river_segments (ref_station, geom)
SELECT
id as ref_station,
ST_GeometryFromText(nearest_segment(geom),4326) AS geom
FROM river_station;