I solved this problem by indeed adding a temporary node on the clicked edge and adding 2 temporary edges to this temporary node. By manually joining these temporary node and edges before calling shortest_path_astar they are being used for calculating the correct path but they dont clutter your database with extra records that are only interesting for 1 particular user (at 1 particular moment in time).
Here the SQL query i used (in Python):
"SELECT
row_number() over (range unbounded preceding) as rownumber,
astar.vertex_id,
astar.edge_id,
astar.cost
FROM
shortest_path_astar('SELECT
gid as id,
source::integer as source,
target::integer as target,
length::double precision as cost,
ST_X(ST_Startpoint(the_geom)) as x1,
ST_Y(ST_Startpoint(the_geom)) as y1,
ST_X(ST_Endpoint(the_geom)) as x2,
ST_Y(ST_Endpoint(the_geom)) as y2
FROM ways
%s',
%s,
%s,
false,
false) astar" % (extra_edges, route_origin, route_destination)
where route_origin or route_destination can be the new temporary (negative) id of the virtual node and extra_edges looks like:
" UNION SELECT %d, %s, %d, ww.length * %f, ST_X(ST_Startpoint(ww.the_geom)), ST_Y(ST_Startpoint(ww.the_geom)), ST_X(ST_Line_Interpolate_Point(ww.the_geom, %f)), ST_Y(ST_Line_Interpolate_Point(ww.the_geom, %f)) FROM ways ww WHERE ww.source = %s AND ww.target = %s" % (edgeid, edge_fromnode, nodeid, perc, perc, perc, edge_fromnode, edge_tonode)
+ " UNION SELECT %d, %d, %s, ww.length * (1-%f), ST_X(ST_Line_Interpolate_Point(ww.the_geom, %f)), ST_Y(ST_Line_Interpolate_Point(ww.the_geom, %f)), ST_X(ST_Endpoint(ww.the_geom)), ST_Y(ST_Endpoint(ww.the_geom)) FROM ways ww WHERE ww.source = %s AND ww.target = %s" % (edgeid-1, nodeid, edge_tonode, perc, perc, perc, edge_fromnode, edge_tonode);
Where edgeid is a unique (negative) id for this temp edge, nodeid a unique (negative) id for this virtual node, edge_fromnode the from node of the original edge, edge_tonode the to node of the original edge, perc is the percentage on the original edge (edge_fromnode, edge_tonode) of the new virtual node.
A week ago (9-1-2012) the pgrouting newsletter also touched this subject. See: Pgrouting-users Digest, Vol 40, Issue 2 -> http://lists.osgeo.org/pipermail/pgrouting-users/2012-January/000927.html
Based on Detlev's answer, I have developed a QGIS plugin which should allow others to solve similar problems easily. It is available in the official QGIS plugins repository and can be found in the QGIS menu: Plugins / Manage and Install Plugins... and search for Disconnected Islands.
http://plugins.qgis.org/plugins/disconnected-islands/
This plugin runs on a line layer, building up a road (or rail, etc.) network graph of connected links. It then analyses connected subgraphs, ones that are connected to each other, but not connected to isolated or floating links. It creates an additional attribute containing the group ID of the subgraph. This can then be used to style the layer with Categorised styles, or Zoom to selection. The disconnected links can then be fixed.
Sample data to test this plugin can be found in your plugins directory: ~/.qgis2/python/plugins/disconnected-islands/sample-data/islands.zip
Source code can be forked from: https://github.com/AfriGIS-South-Africa/disconnected-islands
Best Answer
Use this expression to get a comma separated list of
LinkID
values from the layer callednetwork
:The expression, used here for visualization purpose as a dynamic label:
Create a new field with Field calculator, copy the value from there and paste it to Excel or wherever you need the values. To get each value on a new row, add
,delimiter:= '\n'
at the end of the expression above, before the last closing bracket)
Edit: in my case, the segments are ordered in the correct way. If this is not the case, as in the test data you shared, the approach is a bit more complex. The first line of the expression creates a variable with the name of your
test
layer - rename it accordingly (see below for explanation):Explanantion:
Create an array of all the feature ids (
$id
) for each segment that is covered by the shortest path, usingoverlay_contains()
Get the centroid of each covered segment with
centroid()
Get the distance each centroid is away from the start point of the shortest, along the shortest path line with
line_locate_point()
and by converting the$id
value from step 1 to the feature's geometry withgeometry()
Add the features's id (the
$id
from the array in step 1) after this distance (concatenate with||
and insert','
as delimiter) by calling the@element
inside anarray_foreach()
loopYou get an array where each elements consist of two parts, separated by comma:
distance from start point,$id
(pseudocode)Sort the array with
array_sort()
. Like this, the shortest distance (corresponding to the first covered segment) is at the beginningNow get rid of the distance, keeping only the
$id
, the second part of each element in the array, usingregexp_replace()
You have now the
$id
values in the order the segments are covered. If you want to get an attribute value instead, access it, based on the feature id ($id
) withattribute()
Convert the array to a string with
array_to_string()