donderdag 4 oktober 2018

demo.kunstwerkdeel (duiker)

De Basisregistratie Grootschalige Topografie (BGT) bevat veel gegevens over kunstwerkdelen (brugen, stuwen, duikers, ..).  Helaas mankeert er nog het een en ander aan waardoor deze kunstwerkdelen pas na een bewerking  gebruikt kunnen worden in eigen informatiesystemen. In de nabije toekomst zullen onderstaande handelingen hopelijk overbodig zijn.



Zie hieronder een BGT kaartje. De sloten links en rechts van de weg zijn met elkaar verbonden via een duiker die onder de weg doorloopt. Deze duiker is in de BGT  kennelijk opgeknipt in 3  zelfstandige duiker-objecten. Een waterbeheerder wil in zijn eigen informatiesysteem uiteraard maar één duiker, conform de werkelijkheid buiten. Welke van de drie dat zou moeten zijn is niet duidelijk.




De duiker in het plaatje is kennelijk topologisch doorsneden met de wegdelen. Daarbij worden duiker, weg en bermen opgeknipt in kleinere objecten. Soms is dat opknippen wenselijk, maar hier zeker niet. Voor vlakken onderling is het toepassen van topologie terecht en conform afspraak. Sloten en wegen overlappen elkaar immers niet (opdelend principe). Een duiker is voor een terrein functioneel gezien niet relevant, de aanwezigheid is daarentegen wel van belang voor de inrichting van het terrein/weg/spoorbaan/.. (indelend principe).

Hier een ander voorbeeld van een duiker waarbij het opdelende principe onterecht is toegepast:



Zo zou het moeten zijn:





Maar hoe kom je nu van de ene tot de andere situatie?

Er zijn een aantal opties:
  • In QGIS alle duikers nalopen en objecten telkens handmatig samenvoegen tot één object, en de rest verwijderen. Er is al snel sprake van duizenden duikers, dus dit is wel even wat werk.. En als de BGT muteert uiteraard niet vergeten de eigen systemen weer bij te werken.
  • In Python een uitvoerbaar programma (executable) schrijven die de handelingen in QGIS automatiseert. Dit scheelt uren uren handwerk en, nog belangrijker, het proces is betrouwbaar en herhaalbaar. Wel goed onthouden waar je het script opslaat en hoe het gestart moet worden, het zal nooit dagelijkse routine worden (waarmee ik maar wil zeggen dat er extra beheerlast is).
  • In de DEMO database een database functie (function) schrijven in één van de beschikbare talen (SQL, Python, pgsql, ..). De functie is daarmee altijd onder de motorkap beschikbaar en lift mee met het onderhoud op de database. Het gebruik is simpel, betrouwbaar, herhaalbaar bij updates van de BGT.
Er is gekozen voor de laatste optie.

Functie 1 (get_kunstwerkdelenset) geeft van een duiker naar keuze een lijst van alle verbonden (duiker) objecten:


CREATE TYPE kunstwerkdelenset AS (object_pk integer);

--DROP FUNCTION get_kunstwerkdelenset(integer);
CREATE OR REPLACE FUNCTION get_kunstwerkdelenset(integer) RETURNS SETOF kunstwerkdelenset AS $$
 WITH RECURSIVE kunstwerkdelen (object_pk, geometrie, alle_delen, cyclus) AS (
   SELECT object_pk, geometrie, ARRAY[object_pk], FALSE
   FROM kunstwerkdeel WHERE object_pk = $1 AND ST_GeometryType(geometrie) = 'ST_LineString'
   UNION ALL
     SELECT k.object_pk, k.geometrie, alle_delen || k.object_pk, k.object_pk = ANY(alle_delen)
     FROM kunstwerkdeel k
     JOIN kunstwerkdelen ON
       cyclus = FALSE
       AND ST_GeometryType(k.geometrie) = 'ST_LineString'
       AND ST_Touches(k.geometrie, kunstwerkdelen.geometrie))
 SELECT object_pk FROM kunstwerkdelen WHERE cyclus = FALSE ORDER BY object_pk;
$$ LANGUAGE SQL;

Even testen..

psql>SELECT get_kunstwerkdelenset(248667)

248667
256557
256595
264497
264716

Het werkt..

Functie 2 (merge_kunstwerkdelenset) doorloopt alle demo.kunstwerkdelen van het type 'duiker'  en vraagt telkens een setje te maken van alle verbonden duikers. Als er inderdaad een setje te vinden is, dan wordt de eerste duiker bijgewerkt en de overige ' duikers'  verwijderd uit demo.kunstwerkdelen.


--DROP FUNCTION merge_kunstwerkdelenset();
CREATE OR REPLACE FUNCTION merge_kunstwerkdelenset() RETURNS void AS
$BODY$
DECLARE
 r record;
 q record;
BEGIN
 FOR r IN SELECT * FROM kunstwerkdeel WHERE typekunstwerk = 'duiker' AND ST_GeometryType(geometrie) = 'ST_LineString'
 LOOP
     FOR q IN SELECT * FROM get_kunstwerkdelenset(r.object_pk::integer)
     LOOP
        IF (q.object_pk <> r.object_pk)  THEN
          UPDATE kunstwerkdeel SET geometrie = ST_Union(geometrie,
            (SELECT s.geometrie FROM kunstwerkdeel s WHERE s.object_pk = q.object_pk))
          WHERE object_pk = r.object_pk;
          DELETE FROM kunstwerkdeel WHERE object_pk = q.object_pk;
        END IF;
     END LOOP;
 END LOOP;
END
$BODY$
LANGUAGE 'plpgsql';

Nu is het nog een kwestie van:

psql>SELECT merge_kunstwerkdelenset()

en dan is het even wachten... (1/2 uur voor 17.000 duikers) .. klaar.

Omdat de tabel demo.kunstwerkdelen een standaard DEMO opzet kent (zie eerdere blogs), zal de database de bovenstaande UPDATE en DELETE wijzigingen automatisch loggen. Het is later dus altijd te achterhalen wat er met individuele BGT objecten is gebeurd. Deze eigenschap komt weer goed van pas bij de bijhouding van de eigen objecten als de BGT wijzigt. Dat zal ik later laten zien.

Volgende keer zien we waar deze opschoning van duikers (en andere kunstwerken) toe leidt

Geen opmerkingen:

Een reactie posten