2012. szeptember 27., csütörtök

Topológiailag helyes digitalizálás

Az egyik beadandómhoz környezeti rekonstrukciót kell készítenem (kettőnknek, úgyhogy készítenünk). A feladat erdők, mezők, települések, tehát felületek digitalizálása. Sajnos a postgis 2.0-át még nem követte a QGIS, így az adatbáziskezelőhöz írt legújabb fejlesztést a topológikus adattárolást, csak mint elemi geometriát képes megjeleníteni (nodes, edges, faces). Pedig nekem ezekre nincs szükségem. Viszont arra igen, hogy még szándékosan se lehessen olyan poligont beszúrni, ami fed már egy korábban létrehozott poligont. 
Ezt a feladatot életem első trigger funkciójával oldottam meg.

A teljes fájl letölthető innen.

DROP TABLE IF EXISTS felulet CASCADE;

CREATE TABLE felulet (tipus int,pk_gid serial not null primary key);
SELECT addgeometrycolumn('felulet','the_geom', 23700, 'POLYGON', 2);

CREATE OR REPLACE FUNCTION rewrite_overlap() RETURNS TRIGGER AS $foo$
DECLARE
    --Kurzor megnyitása és adott sorokra szűkítése
    cur CURSOR FOR SELECT * FROM felulet WHERE ST_INTERSECTS(the_geom,NEW.the_geom);
    --Kurzor adott sorait ebbe a változóba mentem, ezt kötelező itt deklarálni
    temp_row felulet%ROWTYPE;

BEGIN
    --kurzor aktiválása
    OPEN cur;
    --Ha beszúrás történi akkor
    IF TG_OP = 'INSERT' THEN
        -- Ciklus eleje, ciklusra azért van szükség, mert több poligonnal is találkozhat
        LOOP
            -- Kurzor soron következő sorát olvassa be a temp_row változóba
            FETCH cur INTO temp_row;
            -- Ha nincs kiolvasandó érték a ciklus érjen véget
            EXIT WHEN NOT FOUND;
            -- Abban az esetben, ha azonos típusú felület érintkezik (pl erdő-erdővel) olvassza egybe
            IF NEW.tipus = temp_row.tipus THEN
                --Az új geometriában egyesítődnek az érintkező azonos típusú felületek
                NEW.the_geom = (SELECT ST_UNION(NEW.the_geom,temp_row.the_geom)) as the_geom;
                --A beolvasztott felületek törlésre kerűlnek
                DELETE FROM felulet WHERE CURRENT OF cur;
            ELSE   
                --Ha különböző típusú felülettel találkozik, akkor vágja ki a fedésben lévő részt az újból
                NEW.the_geom = (SELECT ST_DIFFERENCE(NEW.the_geom,temp_row.the_geom)) as the_geom;
            END IF;
        END LOOP; -- ciklus vége
    END IF;
    IF TG_OP = 'UPDATE' THEN
        LOOP
            FETCH cur INTO temp_row;
            EXIT WHEN NOT FOUND;
            --Update, vagyis módosítás esetén ki kell emelni a módosítandó geometriát
            IF NEW.pk_gid <> temp_row.pk_gid THEN
                IF NEW.tipus = temp_row.tipus THEN
                    NEW.the_geom = (SELECT ST_UNION(NEW.the_geom,temp_row.the_geom)) as the_geom;
                    DELETE FROM felulet WHERE CURRENT OF cur;
                ELSE
                    NEW.the_geom = (SELECT ST_DIFFERENCE(NEW.the_geom,temp_row.the_geom)) as the_geom;
                END IF;
            END IF;
        END LOOP;
    END IF;
    CLOSE cur;
    RETURN NEW;
END
$foo$
LANGUAGE plpgsql;
 

DROP TRIGGER IF EXISTS teszt ON felulet  CASCADE;
--Trigger regisztrálása
CREATE TRIGGER teszt BEFORE INSERT OR UPDATE ON felulet FOR EACH ROW EXECUTE PROCEDURE rewrite_overlap();


Vígan lehet digitalizálni, és végre értelmet nyer, az ötpercenkénti mentés is:)

Az erdőt mocsár veszi körbe, a trigger automatikusan kivágja az erdőt (jó mi?)

Tessék, ki van vágva az erdő... Kössz trigger :)

Nincsenek megjegyzések:

Megjegyzés küldése