Tag: SHP

  • QGIS bez GUI

    Dziś wyjaśnię jak uruchomić QGIS z poziomu Pythona bez włączania GUI (Graphical User Interface) QGIS. Brzmi to dziwnie, ale jest przydatne gdy robimy coś co ma działać w tle, być uruchamiane regularnie jako task, wykonywać złożone analizy nie wymagające gui QGIS.

    Zacznijmy od konfiguracji Pythona w Visual Studio, w końcu na czymś pisać musimy.

    Najpierw tworzymy klasyczną aplikacją Pythona, nazwałem to qgisnogui.

    Utworzyło nam pusty projekt, musimy teraz dodać naszą instalację Pythona, tj Python Environment z zainstalowanego QGIS-a. Klikamy prawym klawiszem myszy na Python Environments, Add Environment…

    Potem wybieramy Existing Environment i wybieramy <Custom>

    Rozwinie się dialog, musimy tylko wskazać lokalizację PYTHONA (Prefix path) w folderze QGIS, reszta powinna się sama wypełnić…

    Klikamy Add. Nasze nowo utworzona konfiguracja środowiska się automatycznie zmieni w projekcie.

    Teraz tylko musimy jeszcze dodać do Search Paths folder z bibliotekami QGIS pythona. Prawy klawisz na Search Paths. Add Folder to Search Path i u mnie to był : C:\qgis3421\apps\qgis\python.

    No i teraz już można uruchomić QGIS-a z poziomu pythona (i tutaj cenna uwaga, nie do wszystkiego qgisapp jest potrzebna, część bibliotek pracuje zupełnie niezależnie, np jak chcemy tylko „obrobić” geometrię to wystarczy sam Python i api qgis, ale jak już chcemy skorzystać z providera, załadować warstwę, wydrukować pdf, a może nawet napisać własną nakładkę gui bazującą na api QGIS to już musimy zainicjować aplikację qgis)

    Dla przykładu prosty kod :

    # zacznijmy od czegoś prostego czyli zdefiniowania geometrii
    
    from qgis.core import QgsGeometry
    geom1 = QgsGeometry.fromWkt("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))")
    
    print(geom1.area())
    

    po kliknięciu uruchom oblicza nam powierzchnię poligonu.

    Teraz uruchommy QGIS i załadujmy warstwę:

    # uruchamiamy qgisapp bez gui, ale z możliwością korzystania z jego funkcji
    import sys
    from qgis.core import QgsApplication
    # Inicjalizacja aplikacji QGIS bez GUI
    qgs = QgsApplication([], False)
    qgs.initQgis()
    # Teraz możemy korzystać z funkcji QGIS, np. wczytać warstwę
    from qgis.core import QgsVectorLayer
    layer = QgsVectorLayer(r"D:\dane\dzialki_krakow_2180.shp", "dzialki", "ogr")
    if not layer.isValid():
        print("Layer failed to load!")
    
    print(f"Ilość obiektów : {layer.featureCount()}")
    
    i = 0
    for feature in layer.getFeatures():
        i+=1
        print(f"Obiekt {feature.id()}, ID_DZIALKI = {feature['ID_DZIALKI']}")
        if i > 10:
            break
    

    No i wynik :

    Tutaj jeszcze cenna uwaga dla początkujących, jak używamy polskich znaków w Pythonie to pamiętajmy o tym aby przed uruchomieniem kodu zrobić Save As…, potem Save with Encoding… i wybrać UTF-8 (65001) 🙂

    Na tym zakończymy dzisiejszy wywód, pozdrawiam, przepraszając równocześnie za długą nieobecność. Praca praca i praca, ale będzie o czym pisać w przyszłości 🙂

  • QGIS i tworzenie mapy do slużebności przesyłu

    Dzisiaj trochę inny model podejścia do problemu. Jak już pisałem w poprzednich wpisach Polska nie publikuje w formie wektorowej obiektów, którymi chciałem się dzisiaj zająć (czyli uzbrojenia terenu). Stworzyłem więc swój własny obszar prac. Działki zostały wycięte w losowym miejscu mapy udostępnianym w ramach https://epodgik.pl/, natomiast sieć wodociągową i kanalizacyjną „wymyśliłem” sam na potrzeby przedstawienia rozwiązania problemu. Chciałbym zaznaczyć, że dane do „prawdziwych” służebności przesyłu powinny wywodzić się z danych urzędowych, a niniejszy przykład przedstawia demonstracyjne rozwiązanie problemu.

    W załączeniu plik z danymi do dzisiejszej zabawy : projekt z danymi (spakowany 7zip) (fix: dodałem brakującą warstwę do pliku)

    Mamy tu 3 warstwy z czego dzialki_temp zawiera pola ID i NR_DZIALKI, a warstwy woda i kanal zawieraja ID i DN (srednice sieci).

    Do stworzenia załącznika do służebności przesyłu potrzebujemy

    • pas i jego powierzchnie
    • długości i średnice sieci objętych

    Zajmijmy się pasem, dla przykładowej działki :

    Zaznaczamy wszystkie obiekty na warstwie woda i kanał które dotykają działki. Z mojego doświadczenia lepiej zaznaczyć więcej sieci żeby nie wynikły problemy, że nagle pas na granicy działki zmniejsza się(powstaje łuk), chociaż wiemy że sieć ta biegnie dalej i pas powinien być równo oddalony po osi aż do granicy.

    Dla przykładu zaznaczymy przez lokalizację wszystko w warstwie kanal co przecina dzialki_temp (tylko zaznaczone) – 5 features selected, tak samo robimy dla warstwy woda, także 5 features selected, czyli mamy po 5 obiektów wodnych i kanalizacyjnych.

    Stwórzmy teraz pasy wokół zaznaczonych sieci. Załóżmy że pas ma mieć metr + połowę średnicy sieci od osi przewodu (jak w niektórych urzędach się przyjmuje). Użyjemy do tego narzędzia Bufor

    Wyjaśnijmy parametry po kolei.

    • najpierw warstwa wejściowa, tutaj kanał,
    • potem powinniśmy zaznaczyć „Tylko zaznaczone obiekty”, tutaj mamy dokładnie wszystkie obiekty zaznaczone wiec nie robi to różnicy.
    • odległość, tu możemy podać jedną stałą odległość bufora, my użyjemy bardziej zaawansowanego podejscia i klikniemy w pole Edytuj…

    i wpisujemy :

    Już wyjaśniam dlaczego tak robimy. Możemy wymusić aby dla każdego obiektu dla którego będzie powstawał bufor, była to zmienna a nie stała. Tutaj jest to:

    dla przykładu DN = 100:

    • Potrzebujemy średnice wyrażoną w metrach zatem =100mm / 1000 = 0.1m
    • połowa średnicy czyli (/ 2) = 0.05m
    • dodajmy metr od krawędzi przewodu czyli 0.05m + 1 m
    • wynikowo dla DN=100 bufor będzie wynosił 1.05m

    Klikamy Ok

    Wróćmy do Bufora

    • Pole Odcinki określa stopień zaokrąglenia bufora na końcach(zostawmy 5).
    • Styl zakończenia „zaokrąglony” – chcemy mieć równo odsunięty bufor na końcach
    • Styl połączenia „zaokrąglony” – chcemy mieć równo odsunięty bufor na łączeniach
    • Limit fazy (uciosu) – nie mamy połączeń ostrych więc nas nie interesuje
    • Zaznaczamy Agreguj wyniki, spowoduje to powstanie jednego połączonego obiektu.

    Wybieramy Uruchom

    Otrzymaliśmy 1 tymczasowy bufor dla kanału.

    Tak samo skonfigurujemy to dla wody i otrzymujemy:

    Łączymy teraz warstwy, albo narzędziem albo kopiując obiekty z jednej warstwy do drugiej. Ja użyję złączenia:

    Klikamy … i zaznaczamy warstwy Bufor i Bufor, Klikamy Uruchom, Powstała nam warstwa Złączone którą przenosimy na samą górę, odznaczamy też niepotrzebne warstwy Bufor.

    używamy teraz Narzędzia Agreguj

    Da nam to warstwę zagregowaną

    Pozostaje tylko przyciąć do granic działki, narzędzie Przytnij:

    Wybieramy kolejno:

    • Warstwa wejsciowa : Zgrupowane obiekty
    • Warstwa nakładki : dzialki_temp
    • Zaznaczamy „Tylko zaznaczone obiekty” – bo chcemy tylko dla zaznaczonej działki wycięcie
    • I klikamy Uruchom…

    Po odznaczeniu niepotrzebnych warstw mamy warstwę Przycięte – nasz pas dla działki.

    Teraz spróbujmy przyciąć sieci:

    Przechodzimy na warstwę woda, wybieramy znowu Przytnij i tym razem:

    • Warstwa wejsciowa : woda
    • Zaznaczamy : Tylko zaznaczone obiekty
    • Warstwa nakładki: dzialki_temp
    • Zaznaczamy „Tylko zaznaczone obiekty” – bo chcemy tylko dla zaznaczonej działki wycięcie
    • I znowu Uruchom…

    Tak samo robimy dla warstwy kanal

    Odznaczamy warstwę woda i kanał, Odznaczamy też wszystkie obiekty zaznaczone. Mamy w projekcie 3 warstwy Przycięte, warstwę pasa i 2 warstwy domiarów odrębnie dla kanału i wody

    Pozostaje nam skonfigurować wyglad i etykiety i wynikowo otrzymamy:

    Czego się dzisiaj nauczyliśmy, co zrobiliśmy:

    • zaznaczyliśmy po lokalizacji warstwy liniowe
    • stworzyliśmy i zagregowaliśmy bufory poszczególnych warstw liniowych
    • docięliśmy bufory do wymaganego zakresu
    • wynikowo powstał zagregowany pas służebności ze zmienną długością pasa dla 2 odrębnych warstw.

    W przyszłych wpisach pokażę jak zautomatyzować to za pomocą Pythona.

    Jak zawsze zapraszam do dyskusji…