433 | | |
434 | | |
435 | | -- Creating a table corresponding to MINHO |
436 | | set search_path to portugal ; |
437 | | |
438 | | -- Table of basins |
439 | | drop table if exists minho_cuenca; |
440 | | create table minho_cuenca as select * from vw_baccod_25k_ptcont where basinorder like '181%'; |
441 | | |
442 | | CREATE INDEX minho_cuenca_geom_idx |
443 | | ON minho_cuenca |
444 | | USING gist |
445 | | (geom); |
446 | | |
447 | | -- Table of rivers |
448 | | drop table if exists minho_rio; |
449 | | create table minho_rio as select * from netElementL where id_localid like '181%'; |
450 | | |
451 | | CREATE INDEX minho_rio_geom_idx |
452 | | ON minho_rio |
453 | | USING gist |
454 | | (geom); |
455 | | |
456 | | -- Configure the table of rivers to use pgrouting: creating source and target |
457 | | ALTER TABLE minho_rio DROP COLUMN source; |
458 | | ALTER TABLE minho_rio DROP COLUMN target; |
459 | | ALTER TABLE minho_rio ADD COLUMN source integer; |
460 | | ALTER TABLE minho_rio ADD COLUMN target integer; |
461 | | CREATE INDEX minho_rio_source_idx ON minho_rio (source); |
462 | | CREATE INDEX minho_rio_target_idx ON minho_rio (target); |
463 | | |
464 | | --------------------------------------------------------------------- |
465 | | -- Using pgrouting: createTopology also creates vertices_pgr |
466 | | ------------------------------------------------------------------ |
467 | | set search_path to portugal, public; |
468 | | SELECT pgr_createTopology('minho_rio', 0.0001, 'geom', 'gid'); |
469 | | |
470 | | SELECT * from minho_rio limit 10 |
471 | | |
472 | | }}} |
| 430 | }}} |
| 431 | |
| 432 | Adding a column identifying basin flowing to the sea to rivers |
| 433 | |
| 434 | {{{#!sql |
| 435 | comment ON TABLE portugal.atagua_bacias_bacias_snirh_pc IS 'River basins flowing to the sea'; |
| 436 | }}} |
| 437 | |
| 438 | Trial to join river layer with basin that flows into the sea (this layer "AtAgua_Bacias_bacias_snirh_PC" has the name of basin: "nome") |
| 439 | |
| 440 | {{{#!sql |
| 441 | SELECT rivers.gid, nome FROM portugal.atagua_bacias_bacias_snirh_pc bs -- bassins sea |
| 442 | |
| 443 | JOIN portugal.rivers ON st_intersects(bs.geom, rivers.geom); |
| 444 | |
| 445 | SELECT * FROM portugal.rivers LIMIT 10; -- Just a view of the rivers |
| 446 | }}} |
| 447 | |
| 448 | Adding the basin name in the river table: update the table rivers to fill in the column nome using the subquery |
| 449 | |
| 450 | {{{#!sql |
| 451 | ALTER TABLE portugal.rivers ADD COLUMN nome CHARACTER VARYING(50); |
| 452 | UPDATE portugal.rivers SET nome = sub.nome |
| 453 | FROM( |
| 454 | SELECT |
| 455 | rivers.gid, |
| 456 | bs.nome |
| 457 | FROM |
| 458 | portugal.atagua_bacias_bacias_snirh_pc bs -- bassins sea |
| 459 | JOIN portugal.rivers ON |
| 460 | st_intersects( |
| 461 | bs.geom, |
| 462 | rivers.geom |
| 463 | ) |
| 464 | ) sub |
| 465 | WHERE |
| 466 | rivers.gid = sub.gid;-- 75386 |
| 467 | |
| 468 | SELECT * FROM portugal.rivers WHERE nome IS NOT NULL; |
| 469 | }}} |
| 470 | |
| 471 | Using pgrouting: createTopology also creates vertices_pgr (target is the nearest point to the sea) |
| 472 | |
| 473 | {{{#!sql |
| 474 | SET search_path TO portugal, public; |
| 475 | ALTER TABLE portugal.rivers DROP COLUMN IF EXISTS SOURCE; |
| 476 | ALTER TABLE portugal.rivers DROP COLUMN IF EXISTS target; |
| 477 | ALTER TABLE portugal.rivers ADD COLUMN SOURCE INTEGER; |
| 478 | ALTER TABLE portugal.rivers ADD COLUMN target INTEGER; |
| 479 | CREATE INDEX rivers_source_idx ON portugal.rivers(SOURCE); |
| 480 | CREATE INDEX rivers_target_idx ON portugal.rivers(target); |
| 481 | |
| 482 | SELECT pgr_createTopology('rivers', 0.0001, 'geom', 'gid'); |
| 483 | |
| 484 | -- notes: fails with id_localid if character varying so must be gid |
| 485 | }}} |
| 486 | |
| 487 | Create q view of coastal waters: first it is projected to the portugese projection 3763, and second we just need one big water mass for st_distance to the sea hence the UNION |
| 488 | |
| 489 | {{{#!sql |
| 490 | DROP VIEW european_wise2008.coastal_waters_3763; |
| 491 | |
| 492 | CREATE OR replace VIEW european_wise2008.coastal_waters_3763 AS SELECT |
| 493 | st_union( |
| 494 | st_transform( |
| 495 | the_geom, |
| 496 | 3763 |
| 497 | ) |
| 498 | ) AS geom |
| 499 | FROM |
| 500 | european_wise2008.costal_waters |
| 501 | WHERE |
| 502 | cty_id = 'PT'; |
| 503 | }}} |
| 504 | |
| 505 | Creating a table of downstream points |
| 506 | |
| 507 | {{{#!sql |
| 508 | DROP TABLE IF EXISTS portugal.downstream_points; |
| 509 | |
| 510 | CREATE TABLE portugal.downstream_points |
| 511 | AS (SELECT target, nome, TRUE AS at_sea, v.the_geom FROM(SELECT * FROM rivers) r |
| 512 | JOIN portugal.rivers_vertices_pgr v ON v.id = r.target |
| 513 | WHERE nextdownid = 0);--466 |
| 514 | |
| 515 | ALTER TABLE portugal.downstream_points ADD CONSTRAINT c_pk_target PRIMARY KEY(target); |
| 516 | |
| 517 | ALTER TABLE portugal.downstream_points ADD COLUMN distance NUMERIC; |
| 518 | |
| 519 | -- ALTER TABLE portugal.downstream_points ADD INDEX |
| 520 | -- DROP INDEX portugal.downsteam_points_thegeom_idx; |
| 521 | |
| 522 | CREATE INDEX downstream_points_thegeom_idx ON portugal.downstream_points USING gist(the_geom); |
| 523 | }}} |
| 524 | |
| 525 | Some of the basins are endoreic (red points), not flowing to the sea |
| 526 | |
| 527 | [[Image(source:eda/data/Docs/trac/sudoang/downstream_points.png, 200px)]][[BR]] |
| 528 | |
| 529 | So, we calculate distance to the sea and only choose distance <500m as AT_SEA = TRUE |
| 530 | |
| 531 | {{{#!sql |
| 532 | DROP TABLE IF EXISTS portugal.coastalwater_union; |
| 533 | |
| 534 | CREATE TABLE portugal.coastalwater_union AS SELECT st_union(geom) FROM european_wise2008.coastal_waters_3763; |
| 535 | |
| 536 | UPDATE portugal.downstream_points |
| 537 | SET distance = st_distance(cw.geom, the_geom) |
| 538 | FROM european_wise2008.coastal_waters_3763 cw; |
| 539 | |
| 540 | UPDATE portugal.downstream_points SET at_sea = FALSE WHERE distance > 500; |
| 541 | }}} |
| 542 | |
| 543 | We start with "Lis e Ribeiras Costeiras" as an example, where there are 26 downstream segments |
| 544 | |
| 545 | {{{#!sql |
| 546 | SELECT * FROM downstream_points WHERE nome = 'Lis e Ribeiras Costeiras' --26 |
| 547 | }}} |
| 548 | |
| 549 | ||target||nome||at_sea||the_geom||distance|| |
| 550 | ||42602||Lis e Ribeiras Costeiras||f||0101000020B30E00008007CE19EFD0E8C000A8A44E10CDBAC0||29907.6770989189|| |
| 551 | ||39176||Lis e Ribeiras Costeiras||t||0101000020B30E0000C0DCB5845C29F0C000470378AB0CE340||0|| |
| 552 | ||39812||Lis e Ribeiras Costeiras||t||0101000020B30E000000FBCBEE7D90F0C0005A643BFFC8E040||15.2036257782544|| |
| 553 | ||39365||Lis e Ribeiras Costeiras||t||0101000020B30E0000C0627FD93C3FF0C0006ADE71AC8FE240||2.44673969528912|| |
| 554 | ||39433||Lis e Ribeiras Costeiras||t||0101000020B30E00004050FC18DD4EF0C000E25817ED31E240||0|| |
| 555 | ||39649||Lis e Ribeiras Costeiras||t||0101000020B30E0000802BF6975D74F0C00063EE5AEE69E140||0|| |
| 556 | ||39815||Lis e Ribeiras Costeiras||t||0101000020B30E000040A835CD8D85F0C000D3BCE30E09E140||0|| |
| 557 | ||39601||Lis e Ribeiras Costeiras||t||0101000020B30E0000C08BDB68BD64F0C000F697DD0DB8E140||0|| |
| 558 | ||40528||Lis e Ribeiras Costeiras||t||0101000020B30E000040431CEB6EFFF0C0009ECDAA63EBDC40||9.27728846536787|| |
| 559 | ||40005||Lis e Ribeiras Costeiras||t||0101000020B30E0000803255309EACF0C00022FDF6CF3AE040||0|| |
| 560 | ||40154||Lis e Ribeiras Costeiras||t||0101000020B30E0000C0F5285CAEBAF0C00010C7BA60C0DF40||10.7529801188864|| |
| 561 | ||40328||Lis e Ribeiras Costeiras||t||0101000020B30E00008009F9A0AED3F0C000941804E2A0DE40||0|| |
| 562 | ||40371||Lis e Ribeiras Costeiras||t||0101000020B30E00000068226CEEC0F0C0004CC807A17BDF40||2.92664241883266|| |
| 563 | ||40616||Lis e Ribeiras Costeiras||t||0101000020B30E000040D8F0F41E04F1C000D2DEE043B6DC40||8.5398098285145|| |
| 564 | ||73504||Lis e Ribeiras Costeiras||t||0101000020B30E000000BF0E9CF396EEC0001F85EB7D36E840||0.715212896922981|| |
| 565 | ||73603||Lis e Ribeiras Costeiras||t||0101000020B30E00000073D71234B6EEC000A3923A6FC4E740||16.3837915282055|| |
| 566 | ||73690||Lis e Ribeiras Costeiras||t||0101000020B30E000080C2F52874BCEEC0006C787A8FAEE740||19.2806257837849|| |
| 567 | ||73814||Lis e Ribeiras Costeiras||t||0101000020B30E0000809DEFA7D4DEEEC000EFC9C3F03AE740||66.9101252528966|| |
| 568 | ||73894||Lis e Ribeiras Costeiras||t||0101000020B30E000000DFE00B15FEEEC0005F07CE31DDE640||25.1780872038218|| |
| 569 | ||74140||Lis e Ribeiras Costeiras||t||0101000020B30E000080499D807684EFC000151DC9056EE540||0|| |
| 570 | ||74397||Lis e Ribeiras Costeiras||t||0101000020B30E000000508D979687EFC0006DE7FB455BE540||16.3373603370103|| |
| 571 | ||74423||Lis e Ribeiras Costeiras||t||0101000020B30E00008087855AD7BFEFC000CCEEC927A9E440||0|| |
| 572 | ||74703||Lis e Ribeiras Costeiras||t||0101000020B30E0000C0EEC9C3FEE7F0C0003AB4C8E2D8DD40||4.00492099466328|| |
| 573 | ||74866||Lis e Ribeiras Costeiras||t||0101000020B30E0000C0D32B658F34F1C0002C6519E66DDA40||4.5315444659325|| |
| 574 | ||75021||Lis e Ribeiras Costeiras||t||0101000020B30E0000C04B3789BF45F1C00016FBCBA6B8D940||8.50403554270985|| |
| 575 | ||75270||Lis e Ribeiras Costeiras||t||0101000020B30E000000E78C289886F1C00070F085892BD740||8.23462515206324|| |
| 576 | |
| 577 | The target 75270 is the largest flow of this basin |
| 578 | Be careful! The target and source attributes are calculating randomly (so this example can be a different number for you) |
| 579 | |
| 580 | [[Image(source:eda/data/Docs/trac/sudoang/lis_ribeiras_example.png, 300px)]][[BR]] |
| 581 | |
| 582 | We select everything in basin 75270 |
| 583 | The following function (recusrsive) selects everyting in the basin by a recursive query, using source and target created by the pg_routing algorythm (it is much quicker than a spatial recursive) |
| 584 | |
| 585 | {{{#!sql |
| 586 | DROP function if exists portugal.upstream_segments(INTEGER); |
| 587 | |
| 588 | CREATE FUNCTION portugal.upstream_segments(INTEGER) |
| 589 | |
| 590 | RETURNS TABLE(source integer, target integer) AS |
| 591 | $$ |
| 592 | BEGIN |
| 593 | RETURN QUERY |
| 594 | WITH RECURSIVE parcours AS( |
| 595 | SELECT |
| 596 | r0.source, |
| 597 | r0.target |
| 598 | FROM |
| 599 | portugal.rivers r0 |
| 600 | WHERE |
| 601 | r0.target = $1 |
| 602 | UNION SELECT |
| 603 | r1.source, |
| 604 | r1.target |
| 605 | FROM |
| 606 | parcours |
| 607 | JOIN portugal.rivers r1 ON parcours.source = r1.target) |
| 608 | SELECT * FROM parcours; |
| 609 | END |
| 610 | $$ |
| 611 | LANGUAGE plpgsql VOLATILE; |
| 612 | |
| 613 | -- select * from portugal.upstream_segments(75270); --1s and 733rows of source and target |
| 614 | }}} |
| 615 | |
| 616 | Creating indexes to do the routing function and join the result with the river table to get the id of the river segment |
| 617 | |
| 618 | {{{#!sql |
| 619 | ALTER TABLE portugal.rivers ADD COLUMN chemin ltree; |
| 620 | CREATE INDEX chemin_gist_rivers_idx ON portugal.rivers USING GIST(chemin); |
| 621 | CREATE INDEX chemin_rivers_idx ON portugal.rivers USING btree(chemin); |
| 622 | |
| 623 | DROP function if exists portugal.get_path(integer,integer); |
| 624 | CREATE OR REPLACE FUNCTION portugal.get_path(_from integer, _to integer) |
| 625 | RETURNS SETOF ltree AS |
| 626 | $$ |
| 627 | BEGIN |
| 628 | RETURN QUERY |
| 629 | SELECT text2ltree(string_agg(gid::text, '.')) AS gid_list |
| 630 | FROM (SELECT gid FROM pgr_dijkstra('SELECT gid as id, source, target, st_length(geom) as cost FROM portugal.rivers', _from, _to, FALSE) pt |
| 631 | JOIN portugal.rivers r ON pt.edge = r.gid order by seq) sub; |
| 632 | |
| 633 | END |
| 634 | $$ |
| 635 | LANGUAGE plpgsql VOLATILE; |
| 636 | }}} |
| 637 | |
| 638 | Different options to calculate topology |
| 639 | |
| 640 | {{{#!sql |
| 641 | select portugal.get_path(75270, source) from portugal.upstream_segments(75270); --5:09 |
| 642 | |
| 643 | select portugal.get_path(57647, source) from portugal.rivers where nome = 'Lis e Ribeiras Costeiras'; --5:59 |
| 644 | |
| 645 | UPDATE portugal.rivers set chemin=get_path(75270,u.source) from portugal.upstream_segments(75270) u |
| 646 | where rivers.source = u.source; -- 5:13 |
| 647 | }}} |
| 648 | |
| 649 | Pass a vector and insert the values: |
| 650 | -- this function writes the path for every basin in an aera (set by the name of the hydrographic region, nome) [[BR]] |
| 651 | -- for this, we need to pass the function get_path(target, source) where the target is the node at the estuary [[BR]] |
| 652 | -- and the source is all the nodes from the basin connected to that basin [[BR]] |
| 653 | -- To achieve the connection to all elements in the basin we used the recursive function upstream_segments [[BR]] |
| 654 | Details : |
| 655 | -- this function uses a cursor, we could have used a for loop for the cursor [[BR]] |
| 656 | -- here following an example http://www.postgresqltutorial.com/plpgsql-cursor/ [[BR]] |
| 657 | -- we open the cursor, and loop throught it, and exist at the end with EXIT WHEN NOT FOUND [[BR]] |
| 658 | -- We have struggled because we forget to retreive the columns using the * so no column was returned [[BR]] |
| 659 | |
| 660 | {{{#!sql |
| 661 | DROP function if exists portugal.write_chemin(TEXT); |
| 662 | CREATE OR REPLACE FUNCTION portugal.write_chemin(_nome text) |
| 663 | RETURNS integer AS |
| 664 | $$ |
| 665 | DECLARE |
| 666 | current_count integer default 0; |
| 667 | the_downstream_point RECORD; |
| 668 | cur_target integer; |
| 669 | cur_down CURSOR(_text text) |
| 670 | FOR SELECT * |
| 671 | FROM portugal.downstream_points |
| 672 | WHERE nome = _nome; |
| 673 | BEGIN |
| 674 | -- Open the cursor |
| 675 | OPEN cur_down(_nome); |
| 676 | |
| 677 | LOOP |
| 678 | -- fetch row one by one into the_downstream_point |
| 679 | FETCH cur_down INTO the_downstream_point; |
| 680 | -- exit when no more row to fetch |
| 681 | EXIT WHEN NOT FOUND; |
| 682 | current_count := current_count+1; |
| 683 | cur_target := the_downstream_point.target; |
| 684 | -- raise notice for now |
| 685 | RAISE NOTICE 'target :%',cur_target; |
| 686 | -- create the chemin for this target and all upstream segments |
| 687 | UPDATE portugal.rivers set chemin=get_path(cur_target,u.source) from portugal.upstream_segments(cur_target) u |
| 688 | where rivers.source = u.source; |
| 689 | END LOOP; |
| 690 | |
| 691 | -- Close the cursor |
| 692 | CLOSE cur_down; |
| 693 | |
| 694 | RETURN current_count; |
| 695 | END; |
| 696 | $$ |
| 697 | LANGUAGE plpgsql; |
| 698 | |
| 699 | select portugal.write_chemin('Lis e Ribeiras Costeiras'); |
| 700 | select * from portugal.downstream_points where nome = 'Lis e Ribeiras Costeiras'; |
| 701 | }}} |