Changes between Initial Version and Version 1 of UsersWikiExamplesNetworkTopology


Ignore:
Timestamp:
Jun 14, 2009, 8:22:53 PM (15 years ago)
Author:
kneufeld
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • UsersWikiExamplesNetworkTopology

    v1 v1  
     1= Examples Network Topology =
     2
     3Suppose you had a table of linestrings that represented a linear network (i.e. roads).  Here's one approach to linking the line segments together via to_node / from_node attributes.
     4
     51. First, generate a table of distinct nodes, that is, a distinct collection of all the start and end points of the line segments.
     6
     7{{{
     8CREATE TABLE nodes AS
     9SELECT
     10        the_geom,
     11        array_accum(road_leaving) AS road_leaving,
     12        array_accum(road_entering) AS road_entering
     13FROM (
     14  SELECT
     15    ST_StartPoint(the_geom) AS the_geom,
     16    road_id AS road_leaving,
     17    NULL::integer AS road_entering
     18  FROM roads
     19  UNION ALL
     20  SELECT
     21    ST_EndPoint(the_geom) AS the_geom,
     22    NULL::integer AS road_leaving,
     23    road_id AS road_entering
     24  FROM roads
     25) AS foo
     26GROUP BY the_geom;
     27}}}
     28
     29The above query creates a node table from a roads table by selecting all the start and end points from the road segments while maintaining the link between the node geometry and the line segment id.  Then nodes are grouped into a single topologically distinct set where every POINT references an array of line segment ids as integer[].
     30
     312. The next step is to assign a unique id for each node and to add two new attributes to the roads table to hold the node references.
     32
     33{{{
     34ALTER TABLE nodes ADD COLUMN node_id serial;
     35ALTER TABLE nodes ADD PRIMARY KEY (node_id);
     36
     37ALTER TABLE roads ADD from_node integer;
     38ALTER TABLE roads ADD to_node integer;
     39}}}
     40
     413. Now that we have our node table with line segment references, we want to update the from_node and to_node attributes of the roads table to reference the appropriate node.  The obvious first approach would be to simply update the roads table using the appropriate reference in the nodes table:
     42
     43{{{
     44UPDATE roads a
     45  SET from_node = b.node_id
     46  FROM nodes b
     47  WHERE a.road_id = ANY (b.road_leaving);
     48UPDATE roads a
     49  SET to_node = b.node_id
     50  FROM nodes b
     51  WHERE a.road_id = ANY (b.road_entering);
     52}}}
     53
     54Unfortunately, PostgreSQL does not seem to use any btree indexes we might have placed on the id arrays, road_leaving and road_entering.  Such queries estimated to take many hours to execute on a small table of 50000 roads.  Subsequently, the following approach can be taken:
     55
     56{{{
     57CREATE TABLE nodes_expanded AS
     58SELECT
     59  node_id,
     60  road_leaving[leaving_upper],
     61  road_entering[entering_upper]
     62FROM (
     63  SELECT
     64    node_id,
     65    road_leaving,
     66    generate_series(1, array_upper(road_leaving, 1)) AS leaving_upper,
     67    road_entering,
     68    generate_series(1, array_upper(road_entering, 1)) AS entering_upper
     69  FROM nodes
     70) AS foo;
     71
     72CREATE UNIQUE INDEX nodes_expanded_leav_idx ON nodes_expanded (road_leaving);
     73CREATE UNIQUE INDEX nodes_expanded_ent_idx ON nodes_expanded (road_entering);
     74ANALYZE nodes_expanded;
     75}}}
     76
     77The above query expands the node table, essentially removing the integer array field we created earlier.
     78
     79Now we can update our roads table with appropriate from_node / to_node values taking mere seconds to process.
     80
     81{{{
     82
     83UPDATE roads a
     84  SET from_node = b.node_id
     85  FROM nodes_expanded b
     86  WHERE a.road_id = b.road_leaving;
     87UPDATE roads a
     88  SET to_node = b.node_id
     89  FROM nodes_expanded b
     90  WHERE a.road_id = b.road_entering;
     91}}}
     92
     93
     94Notes: Alternatively, we could have first created a distinct set of nodes, assigned a unique id to the nodes, and spatially transferred a node_id attribute to every road by intersecting the roads and nodes.  However, such spatial operations are very expensive to perform.  Also, in this case, it's not needed since we already have a relationship between a line and a node (the node is just the start or end point of the line it originated from).
     95