From ccb8b04e6071c574e5f3ce71ba40fc86d36755e3 Mon Sep 17 00:00:00 2001 From: Gregers Petersen Date: Thu, 5 Dec 2013 14:58:46 +0100 Subject: [PATCH 1/6] Modified to take table, cost and geometry field as arguments --- networkReach.sql | 105 +++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/networkReach.sql b/networkReach.sql index 712a2e4..d67fe99 100644 --- a/networkReach.sql +++ b/networkReach.sql @@ -1,86 +1,91 @@ -/* ---create the following TYPE in your database: -CREATE TYPE networkReachType AS +/* +--Returns the following : +Table ( - id integer, - the_geom geometry + id integer, -- The edge's ID + geom geometry, -- The geometry (is partial if factor <> 1) + factor double precision -- How much of the original edge (based on length) did we take ); */ /* networkReach parameters: -1: id of the starting point in the vertices_tmp table -2: network reach distance (in units of the edge table cost column) +1: The edge table +2: Id of the starting point in the vertices_tmp table +3: Network reach distance (in units of the edge table cost column) */ - -CREATE OR REPLACE FUNCTION networkReach(integer, integer) -RETURNS SETOF networkReachType AS +CREATE OR REPLACE FUNCTION parkering_routing.networkReachPartial(edgeTable regclass, costfield character varying, geomfield character varying, startnode integer, networkReachDistance double precision) +RETURNS TABLE(id integer, geom geometry, factor double precision) AS $BODY$ DECLARE - startNode ALIAS FOR $1; - networkReachDistance ALIAS FOR $2; - - networkReach networkReachType; + -- nothing to declare BEGIN - + + -- Create a temporary table for the network whilst we process it + -- DROP on commit so we do not get problems reusing it again in this session CREATE TEMP TABLE tempNetwork ( id integer NOT NULL, - the_geom geometry NOT NULL - ); - - INSERT INTO tempNetwork(id, the_geom) - SELECT s.id edgeID, s.the_geom + geom geometry NOT NULL, + factor double precision NOT NULL + ) + ON COMMIT DROP; + + + EXECUTE ' + INSERT INTO tempNetwork(id, geom, factor) + SELECT et.id, et.' || format('%s',geomfield) || ' AS geom, 1 as factor FROM (SELECT id1,cost from pgr_drivingDistance( - 'SELECT id, source, target, cost FROM streets', - startNode,networkReachDistance,false,false) - ) firstPath + ''SELECT id, source, target, ' || quote_ident(costField) || ' AS cost FROM ' || format('%s',edgeTable) || ''', + ' || format('%s',startnode) || ',' || format('%s', networkReachDistance) || ',false,false) + ) firstPath CROSS JOIN (SELECT id1,cost from pgr_drivingDistance( - 'SELECT id, source, target, cost FROM streets', - startNode,networkReachDistance,false,false) - ) secondPath - INNER JOIN streets s - ON firstPath.id1 = s.source - AND secondPath.id1 = s.target; + ''SELECT id, source, target, ' || quote_ident(costField) || ' AS cost FROM ' || format('%s',edgeTable) || ''', + ' || format('%s',startnode) || ',' || format('%s', networkReachDistance) || ',false,false) + ) secondPath + INNER JOIN ' || format('%s',edgeTable) || ' et + ON firstPath.id1 = et.source + AND secondPath.id1 = et.target;'; - INSERT INTO tempNetwork(id, the_geom) - SELECT allNodes.id, st_linesubstring(allNodes.the_geom, 0.0, (networkReachDistance-allNodes.distance)/allNodes.Cost) + EXECUTE format(' + INSERT INTO tempNetwork(id, geom, factor) + SELECT allNodes.id, st_line_substring(allNodes.geom, 0.0, (' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost), (' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost AS factor FROM - (SELECT reachNodes.id1, s1.id, s1.cost, reachNodes.cost distance, s1.the_geom + (SELECT reachNodes.id1, et.id, et.cost, reachNodes.cost distance, et.' || format('%s',geomfield) || ' FROM (SELECT id1, cost FROM pgr_drivingDistance( - 'SELECT id, source, target, cost FROM streets', - startNode,networkReachDistance,false,false) - ) reachNodes - JOIN (SELECT id, target, source, cost, the_geom FROM streets) s1 ON reachNodes.id1 = s1.source + ''SELECT id, source, target, ' || quote_ident(costField) || ' AS cost FROM ' || format('%s',edgeTable) || ''', + ' || format('%s',startnode) || ',' || format('%s', networkReachDistance) || ',false,false) + ) reachNodes + JOIN (SELECT p.id, p.target, p.source, p.' || quote_ident(costField) || ' AS cost, p.geom FROM ' || format('%s',edgeTable) || ' p) et ON reachNodes.id1 = et.source ORDER BY reachNodes.id1 ) allNodes FULL OUTER JOIN tempNetwork ON tempNetwork.id = allNodes.id - WHERE tempNetwork.id IS NULL; + WHERE tempNetwork.id IS NULL;', edgeTable); - INSERT INTO tempNetwork(id, the_geom) - SELECT allNodes.id, st_linesubstring(allNodes.the_geom,1-((networkReachDistance-allNodes.distance)/allNodes.Cost),1) + EXECUTE format(' + INSERT INTO tempNetwork(id, geom, factor) + SELECT allNodes.id, st_line_substring(allNodes.geom,1-((' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost),1), (' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost AS factor FROM - (SELECT reachNodes.id1, s1.id, s1.cost, reachNodes.cost distance, s1.the_geom + (SELECT reachNodes.id1, et.id, et.cost, reachNodes.cost distance, et.' || format('%s',geomfield) || ' FROM (SELECT id1, cost FROM pgr_drivingDistance( - 'SELECT id, source, target, cost FROM streets', - startNode,networkReachDistance,false,false) - ) reachNodes - JOIN (SELECT id, target, source, cost, the_geom FROM streets) s1 ON reachNodes.id1 = s1.target + ''SELECT id, source, target, ' || quote_ident(costField) || ' AS cost FROM ' || format('%s',edgeTable) || ''', + ' || format('%s',startnode) || ',' || format('%s', networkReachDistance) || ',false,false) + ) reachNodes + JOIN (SELECT p.id, p.target, p.source, p.' || quote_ident(costField) || ' AS cost, p.' || format('%s',geomfield) || ' FROM ' || format('%s',edgeTable) || ' p) et ON reachNodes.id1 = et.target ORDER BY reachNodes.id1 ) allNodes FULL OUTER JOIN tempNetwork ON tempNetwork.id = allNodes.id - WHERE tempNetwork.id IS NULL; + WHERE tempNetwork.id IS NULL;', edgeTable); - FOR networkReach IN SELECT * FROM tempNetwork - LOOP - RETURN NEXT networkReach; - END LOOP; + + RETURN QUERY SELECT t.id, t.geom, t.factor FROM tempNetwork t; + END; $BODY$ - LANGUAGE plpgsql; + LANGUAGE plpgsql; \ No newline at end of file From 85d8652fb2c26117d5674d21ab93381db82af1d4 Mon Sep 17 00:00:00 2001 From: Gregers Petersen Date: Thu, 5 Dec 2013 15:00:34 +0100 Subject: [PATCH 2/6] Rectified some of the descriptions etc. --- networkReach.sql | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/networkReach.sql b/networkReach.sql index d67fe99..28f390e 100644 --- a/networkReach.sql +++ b/networkReach.sql @@ -11,14 +11,16 @@ Table /* networkReach parameters: 1: The edge table -2: Id of the starting point in the vertices_tmp table -3: Network reach distance (in units of the edge table cost column) +2: The cost field in the edgeTable to base calculations on +3: The geometry field in the edgeTable +4: Id of the starting point in the vertices_tmp table +5: Network reach distance (in units of the edge table cost column) */ CREATE OR REPLACE FUNCTION parkering_routing.networkReachPartial(edgeTable regclass, costfield character varying, geomfield character varying, startnode integer, networkReachDistance double precision) RETURNS TABLE(id integer, geom geometry, factor double precision) AS $BODY$ DECLARE - -- nothing to declare + -- nothing to declare here, we now return a table instead of declaring types BEGIN -- Create a temporary table for the network whilst we process it From faca42d176a9045baa470be4fa7109d4c55542ce Mon Sep 17 00:00:00 2001 From: Gregers Petersen Date: Thu, 5 Dec 2013 15:03:00 +0100 Subject: [PATCH 3/6] Modified README according to new type --- README.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 62abccd..26823cb 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,11 @@ This SQL function returns all the edges associated with accessible nodes on the and returns partial edges when the last node is not accessible but some part of the edge is within the accessible distance. -The function currently uses a table named 'streets', a field for the distance value named 'cost', and a field -for edge geometry named 'the_geom'. Also the 'streets' table needs to have a unique id field named 'id'. - -There is a custom type that needs to be created for this to work. The SQL for creating the custom type is commented -out at the beginning of the networkReach.sql file. +The function takes as arguments the edge table name, the geometry field, the cost, the startnode, and the maximum cost in the network (calculated on said cost field) +Also the edge table needs to have a unique id field named 'id'. +The function no longer uses a custom type, but declares the table type returned. ============ Things to do ========================= -Add table name and cost field name parameters to the function so it can work on any database. - -Make it so that any lon/lat input will find the closest point on the closest line and then do the network reach. From 99f57d9f981fe0c683d0951b7d49c77a4c27d93c Mon Sep 17 00:00:00 2001 From: Gregers Petersen Date: Thu, 5 Dec 2013 15:06:29 +0100 Subject: [PATCH 4/6] Removed unnecessary format(... from the code. --- networkReach.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/networkReach.sql b/networkReach.sql index 28f390e..a651a44 100644 --- a/networkReach.sql +++ b/networkReach.sql @@ -51,7 +51,7 @@ $BODY$ ON firstPath.id1 = et.source AND secondPath.id1 = et.target;'; - EXECUTE format(' + EXECUTE ' INSERT INTO tempNetwork(id, geom, factor) SELECT allNodes.id, st_line_substring(allNodes.geom, 0.0, (' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost), (' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost AS factor FROM @@ -66,9 +66,9 @@ $BODY$ ) allNodes FULL OUTER JOIN tempNetwork ON tempNetwork.id = allNodes.id - WHERE tempNetwork.id IS NULL;', edgeTable); + WHERE tempNetwork.id IS NULL;'; - EXECUTE format(' + EXECUTE ' INSERT INTO tempNetwork(id, geom, factor) SELECT allNodes.id, st_line_substring(allNodes.geom,1-((' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost),1), (' || format('%s', networkReachDistance) || '-allNodes.distance)/allNodes.Cost AS factor FROM @@ -83,7 +83,7 @@ $BODY$ ) allNodes FULL OUTER JOIN tempNetwork ON tempNetwork.id = allNodes.id - WHERE tempNetwork.id IS NULL;', edgeTable); + WHERE tempNetwork.id IS NULL;'; RETURN QUERY SELECT t.id, t.geom, t.factor FROM tempNetwork t; From 159e5abbf29778efd671dec5ef493c6d737f9ed9 Mon Sep 17 00:00:00 2001 From: Gregers Petersen Date: Fri, 6 Dec 2013 09:22:19 +0100 Subject: [PATCH 5/6] Fixed README formatting... --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 26823cb..710642f 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ The function takes as arguments the edge table name, the geometry field, the cos Also the edge table needs to have a unique id field named 'id'. The function no longer uses a custom type, but declares the table type returned. + ============ Things to do ========================= From 1beb9145046a968d680803c28f0ffc2812cd02ce Mon Sep 17 00:00:00 2001 From: Gregers Petersen Date: Fri, 6 Dec 2013 09:23:58 +0100 Subject: [PATCH 6/6] Added description of factor returned --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 710642f..b2463df 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This SQL function finds the network reach from a given node for the input distan This SQL function returns all the edges associated with accessible nodes on the network within the input distance, and returns partial edges when the last node is not accessible but some part of the edge is within the accessible -distance. +distance. The function returns for each edge the factor (how much of the original edge's geometry is returned) for said edge (based on edge length). The function takes as arguments the edge table name, the geometry field, the cost, the startnode, and the maximum cost in the network (calculated on said cost field) Also the edge table needs to have a unique id field named 'id'.