Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing TODO stuff #1

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,14 @@ 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 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'.
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'.

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 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.

107 changes: 57 additions & 50 deletions networkReach.sql
Original file line number Diff line number Diff line change
@@ -1,86 +1,93 @@
/*
--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: 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 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 here, we now return a table instead of declaring types
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 '
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;';

INSERT INTO tempNetwork(id, the_geom)
SELECT allNodes.id, st_linesubstring(allNodes.the_geom,1-((networkReachDistance-allNodes.distance)/allNodes.Cost),1)
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
(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;';

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;