Esempio n. 1
0
class Navigator:
    def __init__(self, dbname: str):
        """
        Constructor

        :param dbname: Entspricht dem Datei-Pfad zur SpatiaLite-Datenbank.
        """
        self.__dbname = dbname
        self.__error_msg = ""
        self.db = DBConnection(dbname)
        if not self.db.connected:
            main_logger.error(
                (
                    "Fehler in navigation:\n"
                    + "QKan-Datenbank {:s} wurde nicht gefunden oder war nicht aktuell!\nAbbruch!"
                ).format(dbname)
            )
            raise Exception()  # TODO: ???
        self.log = logging.getLogger("QKan.navigation.Navigator")

    def calculate_route_schacht(
        self, nodes: List[str]
    ) -> Optional[Dict[str, Union[List[str], Dict[str, Union[str, float]]]]]:
        """
        * Wird ausgeführt, wenn eine Route zwischen Schächten gefunden werden soll.
        * Berechnet die Route aus Start- und Endpunkt, prüft am Ende, ob alle anderen Schächte innerhalb der
        berechneten Route liegen.
        * Benötigt mindestens zwei Schächte

        :param nodes: Entspricht einer Liste von den selektierten Schacht-Namen aus QGIS.
        :return: Gibt ein Routen-Objekt zurück mit allen Haltungen und Schächten
        """
        self.log.debug("Übergebene Schächte:\t{}".format(nodes))
        endpoint = nodes[0]
        startpoint = nodes[0]
        statement = """
        SELECT sohlhoehe FROM schaechte WHERE schnam="{}"
        """
        self.db.sql(statement.format(nodes[0]))
        (min_value,) = self.db.fetchone()
        max_value = min_value
        for n in nodes:
            self.db.sql(statement.format(n))
            (value,) = self.db.fetchone()
            if value < min_value:
                min_value = value
                endpoint = n
            elif value > max_value:
                max_value = value
                startpoint = n
        self.log.info("Start- und Endpunkt wurden gesetzt")
        self.log.debug("Startpunkt:\t{}\nEndpunkt:\t{}".format(startpoint, endpoint))
        nodes.remove(startpoint)
        nodes.remove(endpoint)
        self.log.debug(u"Zusätzliche Punkte:\t{}".format(nodes))
        return self.__calculate_route_schacht(
            startpoint, endpoint, additional_points=nodes
        )

    def __calculate_route_schacht(
        self, startpoint: str, endpoint: str, additional_points: List[str]
    ) -> Optional[Dict[str, Union[List[str], Dict[str, Union[str, float]]]]]:
        """
        Berechnet die Schächte und Haltungen, die zwischen einem Start- und Endpunkt liegen.
        * Start- und Endhöhe müssen nicht in der richtigen Reihenfolge übergeben werden.
        * Zusätzliche Punkte müssen nur übergeben werden, wenn der Endpunkt über mehrere Wege zu erreichen ist.

        :param startpoint: Entspricht dem Schacht-Namen aus QGIS.
        :param endpoint: Entspricht dem Schacht-Namen aus QGIS.
        :param additional_points: Entspricht einer Liste von Schacht-Namen, die zusätzlich ausgewählt wurden.
        :return: Gibt ein Routen-Objekt zurück, bestehend aus allen Haltungen und Schächten
        """
        statement = u"""
        SELECT name
        FROM (SELECT
                haltnam AS name,
                schoben
              FROM haltungen
              UNION SELECT
                      wnam AS name,
                      schoben
                    FROM wehre
              UNION SELECT
                      pnam AS name,
                      schoben
                    FROM pumpen)
        WHERE schoben ="{}"
                """
        self.db.sql(statement.format(startpoint))
        start_haltungen = [h[0] for h in self.db.fetchall()]
        self.log.debug(u"Start-Haltungen:\t{}".format(start_haltungen))
        statement_2 = u"""
                SELECT name
                FROM (SELECT
                        haltnam AS name,
                        schunten
                      FROM haltungen
                      UNION SELECT
                              wnam AS name,
                              schunten
                            FROM wehre
                      UNION SELECT
                              pnam AS name,
                              schunten
                            FROM pumpen)
                WHERE schunten ="{}"
                        """
        self.db.sql(statement_2.format(endpoint))
        end_haltungen = [h[0] for h in self.db.fetchall()]
        self.log.debug(u"End-Haltungen:\t{}".format(end_haltungen))
        nodes = []
        if len(additional_points) > 0:
            for p in additional_points:
                self.db.sql(statement.format(p))
                nodes.append([h[0] for h in self.db.fetchall()])
        permutations = cast(List[List[float]], itertools.product(*nodes))
        permutations = [list(p) for p in permutations]
        possibilities = 0
        route = None
        self.log.debug(u"Zusätzliche Haltungen:\t{}".format(nodes))
        self.log.info(u"Alle nötigen Haltungen gesetzt")
        for start_haltung in start_haltungen:
            for end_haltung in end_haltungen:
                for permutation in permutations:
                    _nodes = list(set([start_haltung, end_haltung] + list(permutation)))
                    self.log.debug(u"Aktuelle Haltungen:\t{}".format(_nodes))
                    _route = self.calculate_route_haltung(_nodes)
                    if _route:
                        self.log.info(u"Aktuelle Route ist valide")
                        possibilities += 1
                        if possibilities > 1:
                            self.log.error(
                                u"Zu viele Möglichkeiten zwischen Start- und End-Haltung."
                            )
                            self.__error_msg = (
                                u"Zu viele Möglichkeiten. Bitte wählen Sie einen Wegpunkt auf"
                                u" dem kritischen Pfad!"
                            )
                            return None
                        route = _route
        return route

    def calculate_route_haltung(
        self, nodes: List[str]
    ) -> Optional[Dict[str, Union[List[str], Dict[str, Union[str, float]]]]]:
        """
        Berechnet eine Route zwischen mehreren Haltungen.

        :param nodes: Alle selektierten Haltungs-Namen aus QGIS
        :return: Gibt eine Routen-Objekt mit allen Haltungen und Schächten zurück
        """
        if len(nodes) == 1:
            routes = [nodes]
        else:
            tasks = Tasks(self.__dbname, nodes)
            self.log.info(u"Tasks wurden initialisiert")
            routes = tasks.start()
            self.log.info(u"Alle möglichen Routen ({}) berechnet".format(len(routes)))
        if len(routes) == 1:
            self.log.info(u"Eine einzige mögliche Route gefunden")
            return self.__fetch_data(routes[0])
        elif len(routes) == 0:
            self.log.error(u"Keine Route gefunden. Pfad ist fehlerhaft!")
            self.__error_msg = u"Übergebener Pfad ist fehlerhaft."
            return None
        else:
            self.log.error(
                u"Es gibt {} mögliche Routen. Der Pfad muss spezifiziert werden".format(
                    len(routes)
                )
            )
            self.__error_msg = (
                u"Mehrere Möglichkeiten ({}) den Endpunkt zu erreichen. "
                u"Bitte spezifizieren Sie die Route."
            ).format(len(routes))
            return None

    def __fetch_data(
        self, haltungen: List[str]
    ) -> Dict[str, Union[List[str], Dict[str, Union[str, float]]]]:
        """
        Fragt die Datenbank nach den benötigten Attributen ab und speichert sie in einem Dictionary.
        Das Dictionary hat folgende Struktur:
        *{haltungen:[haltungsnamen],
        schaechte:[schachtnamen],
        schachtinfo:{schachtname:
            {sohlhoehe:float,
            deckelhoehe:float}
            },
        haltunginfo:{haltungsname:
            {schachtoben: schachtname,
            schachtunten: schachtname,
            laenge: float,
            sohlhoeheoben: float,
            sohlhoeheunten: float,
            querschnitt: float}
            }
        }

        :param haltungen: Liste aller Haltungs-Namen aus QGIS
        :return: Gibt ein Routen-Objekt zurück.
        """
        statement = u"""
         SELECT schoben
         FROM (SELECT
                 haltnam AS name,
                 schoben
               FROM haltungen
               UNION SELECT
                       wnam AS name,
                       schoben
                     FROM wehre
               UNION SELECT
                       pnam AS name,
                       schoben
                     FROM pumpen)
         WHERE name = "{}"
                 """
        schaechte = []
        self.log.debug(u"Haltungen:\t{}".format(haltungen))
        self.db.sql(statement.format(haltungen[0]))
        schaechte.append(self.db.fetchone()[0])
        statement = u"""
             SELECT schunten
             FROM (SELECT
                  haltnam AS name,
                  schunten
                   FROM haltungen
                   UNION SELECT
                   wnam AS name,
                   schunten
                    FROM wehre
                    UNION SELECT
                   pnam AS name,
                   schunten
                  FROM pumpen)
             WHERE name = "{}"
             """
        for h in haltungen:
            self.db.sql(statement.format(h))
            schaechte.append(self.db.fetchone()[0])
        self.log.debug(u"Schächte:\t{}".format(schaechte))

        route = {"haltungen": haltungen, "schaechte": schaechte}
        rinfo = self.get_info(route)

        rval: Dict[str, Union[List[str], Dict[str, Union[str, float]]]] = {
            "haltungen": haltungen,
            "schaechte": schaechte,
            "schachtinfo": rinfo[0],
            "haltunginfo": rinfo[1],
        }

        self.log.info("Route wurde erfolgreich erstellt!")
        return rval

    def get_info(self, route: Dict[str, List[str]]) -> Tuple[Dict, Dict]:
        """
        Methode muss überschrieben werden bei Verwendung dieses Moduls

         :param route: Die Haltungen und Schächte in einem Dictionary
         :type route: dict
         :return Gibt zwei Dictionaries mit zusätzlichen Informationen aus der Datenbank zurück
         :rtype: dict, dict
        """

    def get_error_msg(self) -> str:
        """
        Getter der Error-Message.

        :return: Gibt die Error-Message zurück
        """
        return self.__error_msg
Esempio n. 2
0
class CreateUnbefFl:
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'CreateUnbefFl_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        # Create the dialog (after translation) and keep reference
        self.dlg = CreateUnbefFlDialog()

        # Anfang Eigene Funktionen -------------------------------------------------
        # (jh, 12.06.2017)

        logger.info(u'\n\nQKan_CreateUnbefFlaechen initialisiert...')

        # --------------------------------------------------------------------------
        # Pfad zum Arbeitsverzeichnis sicherstellen
        wordir = os.path.join(site.getuserbase(), u'qkan')

        if not os.path.isdir(wordir):
            os.makedirs(wordir)

        # --------------------------------------------------------------------------------------------------
        # Konfigurationsdatei qkan.json lesen
        #

        self.configfil = os.path.join(wordir, u'qkan.json')
        if os.path.exists(self.configfil):
            with open(self.configfil, 'r') as fileconfig:
                self.config = json.loads(fileconfig.read())
        else:
            self.config = {'epsg': '25832'}  # Projektionssystem
            with open(self.configfil, 'w') as fileconfig:
                fileconfig.write(json.dumps(self.config))

        # Formularereignisse anbinden ----------------------------------------------

        self.dlg.tw_selAbflparamTeilgeb.itemClicked.connect(
            self.tw_selAbflparamTeilgebClick)
        self.dlg.cb_selActive.stateChanged.connect(self.selActiveClick)
        self.dlg.button_box.helpRequested.connect(self.helpClick)

        # Ende Eigene Funktionen ---------------------------------------------------

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('CreateUnbefFl', message)

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/qkan/createunbeffl/icon.png'
        Dummy.instance.add_action(
            icon_path,
            text=self.tr(u'Erzeuge unbefestigte Flächen...'),
            callback=self.run,
            parent=self.iface.mainWindow())

    def unload(self):
        pass

    # -------------------------------------------------------------------------
    # Formularfunktionen

    def helpClick(self):
        """Reaktion auf Klick auf Help-Schaltfläche"""
        helpfile = os.path.join(
            self.plugin_dir,
            '../doc/sphinx/build/html/Qkan_Formulare.html#erzeugen-der-unbefestigten-flachen'
        )
        webbrowser.open_new_tab(helpfile)

    def tw_selAbflparamTeilgebClick(self):
        """Reaktion auf Klick in Tabelle"""

        self.dlg.cb_selActive.setChecked(True)
        self.countselection()

    def selActiveClick(self):
        """Reagiert auf Checkbox zur Aktivierung der Auswahl"""

        # Checkbox hat den Status nach dem Klick
        if self.dlg.cb_selActive.isChecked():
            # Nix tun ...
            logger.debug('\nChecked = True')
        else:
            # Auswahl deaktivieren und Liste zurücksetzen
            anz = self.dlg.tw_selAbflparamTeilgeb.rowCount()
            range = QTableWidgetSelectionRange(0, 0, anz - 1, 4)
            self.dlg.tw_selAbflparamTeilgeb.setRangeSelected(range, False)
            logger.debug('\nChecked = False\nQWidget: anzahl = {}'.format(anz))

            # Anzahl in der Anzeige aktualisieren
            self.countselection()

    def countselection(self):
        """Zählt nach Änderung der Auswahlen in den Listen im Formular die Anzahl
        der betroffenen TEZG-Flächen"""

        liste_selAbflparamTeilgeb = self.listselectedTabitems(
            self.dlg.tw_selAbflparamTeilgeb)

        # logger.debug(u'QKan.createunbeffl.application.countselection (1)\nlen(liste_selAbflparamTeilgeb) = {}'.format(len(liste_selAbflparamTeilgeb)))
        # logger.debug(u'QKan.createunbeffl.application.countselection (2)\nliste_selAbflparamTeilgeb = {}'.format(str(liste_selAbflparamTeilgeb)))

        # Aufbereiten für SQL-Abfrage

        # Unterschiedliches Vorgehen, je nachdem ob mindestens eine oder keine Zeile
        # ausgewählt wurde

        # if len(liste_selAbflparamTeilgeb) == 0:
        # anzahl = sum([int(attr[-2]) for attr in self.listetezg])
        # else:
        # anzahl = sum([int(attr[-2]) for attr in liste_selAbflparamTeilgeb])

        # Vorbereitung des Auswahlkriteriums für die SQL-Abfrage: Kombination aus abflussparameter und teilgebiet
        # Dieser Block ist identisch in k_unbef und in application enthalten

        if len(liste_selAbflparamTeilgeb) == 0:
            auswahl = u''
        elif len(liste_selAbflparamTeilgeb) == 1:
            auswahl = u' AND'
        elif len(liste_selAbflparamTeilgeb) >= 2:
            auswahl = u' AND ('
        else:
            fehlermeldung(u"Interner Fehler", u"Fehler in Fallunterscheidung!")
            return False

        # Anfang SQL-Krierien zur Auswahl der tezg-Flächen
        first = True
        for attr in liste_selAbflparamTeilgeb:
            if attr[4] == u'None' or attr[1] == u'None':
                fehlermeldung(
                    u'Datenfehler: ',
                    u'In den ausgewählten Daten sind noch Datenfelder nicht definiert ("NULL").'
                )
                return False
            if first:
                first = False
                auswahl += u""" (tezg.abflussparameter = '{abflussparameter}' AND
                                tezg.teilgebiet = '{teilgebiet}')""".format(
                    abflussparameter=attr[0], teilgebiet=attr[1])
            else:
                auswahl += u""" OR\n      (tezg.abflussparameter = '{abflussparameter}' AND
                                tezg.teilgebiet = '{teilgebiet}')""".format(
                    abflussparameter=attr[0], teilgebiet=attr[1])

        if len(liste_selAbflparamTeilgeb) >= 2:
            auswahl += u")"
        # Ende SQL-Krierien zur Auswahl der tezg-Flächen

        # Ende SQL-Krierien zur Auswahl der tezg-Flächen

        # Trick: Der Zusatz "WHERE 1" dient nur dazu, dass der Block zur Zusammenstellung von 'auswahl' identisch mit dem
        # Block in 'k_unbef.py' bleiben kann...
        sql = u"""SELECT count(*) AS anz
                FROM tezg WHERE 1{auswahl}
        """.format(auswahl=auswahl)

        if not self.dbQK.sql(sql, u"QKan.CreateUnbefFlaechen (5)"):
            return False

        data = self.dbQK.fetchone()

        if not (data is None):
            self.dlg.lf_anzahl_tezg.setText(u'{}'.format(data[0]))
        else:
            self.dlg.lf_anzahl_tezg.setText(u'0')

    # -------------------------------------------------------------------------
    # Funktion zur Zusammenstellung einer Auswahlliste für eine SQL-Abfrage
    def listselectedTabitems(self, tableWidget, nCols=5):
        """Erstellt eine Liste aus den in einem Auswahllisten-Widget angeklickten Objektnamen

        :param tableWidget: Tabelle zur Auswahl der Arten von Haltungsflächen.
        :type tableWidget: QTableWidget

        :param nCols:       Anzahl Spalten des tableWidget-Elements
        :type nCols:        integer

        :returns: Tuple mit ausgewählten Abflussparametern
        :rtype: tuple
        """
        items = tableWidget.selectedItems()
        anz = len(items)
        nRows = anz // nCols

        if len(items) > nCols:
            # mehr als eine Zeile ausgewählt
            if tableWidget.row(items[1]) == 1:
                # Elemente wurden spaltenweise übergeben
                liste = [[el.text() for el in items][i:anz:nRows]
                         for i in range(nRows)]
            else:
                # Elemente wurden zeilenweise übergeben
                liste = [[el.text() for el in items][i:i + 5]
                         for i in range(0, anz, 5)]
        else:
            # Elemente wurden zeilenweise übergeben oder Liste ist leer
            liste = [[el.text() for el in items][i:i + 5]
                     for i in range(0, anz, 5)]

        return liste

    # ------------------------------------------------------------------------------------------------------------
    # Vorbereiten und Öffnen des Formulars

    def run(self):
        """Run method that performs all the real work"""

        database_QKan, epsg = get_database_QKan()
        if not database_QKan:
            fehlermeldung(
                u"Fehler in CreateUnbefFl",
                u"database_QKan konnte nicht aus den Layern ermittelt werden. Abbruch!"
            )
            logger.error(
                u"CreateUnbefFl: database_QKan konnte nicht aus den Layern ermittelt werden. Abbruch!"
            )
            return False

        # Abfragen der Tabelle tezg nach verwendeten Abflussparametern
        self.dbQK = DBConnection(
            dbname=database_QKan
        )  # Datenbankobjekt der QKan-Datenbank zum Lesen

        if self.dbQK is None:
            fehlermeldung(
                u"Fehler in QKan_CreateUnbefFl",
                u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format(
                    database_QKan))
            iface.messageBar().pushMessage(u"Fehler in QKan_Import_from_HE",
                                           u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format( \
                                               database_QKan), level=QgsMessageBar.CRITICAL)
            return None

        # Kontrolle, ob in Tabelle "abflussparameter" ein Datensatz für unbefestigte Flächen vorhanden ist
        # (Standard: apnam = '$Default_Unbef')

        sql = u"""SELECT apnam
            FROM abflussparameter
            WHERE bodenklasse IS NOT NULL AND trim(bodenklasse) <> ''"""

        if not self.dbQK.sql(sql, u'createunbeffl.run (1)'):
            return False

        data = self.dbQK.fetchone()

        if data is None:
            if autokorrektur:
                daten = [
                    u"'$Default_Unbef', u'von QKan ergänzt', 0.5, 0.5, 2, 5, 0, 0, 'LehmLoess', '13.01.2011 08:44:50'"
                ]

                for ds in daten:
                    sql = u"""INSERT INTO abflussparameter
                             ( 'apnam', 'kommentar', 'anfangsabflussbeiwert', 'endabflussbeiwert', 'benetzungsverlust', 
                               'muldenverlust', 'benetzung_startwert', 'mulden_startwert', 'bodenklasse', 
                               'createdat') Values ({})""".format(ds)
                    if not self.dbQK.sql(sql, u'createunbeffl.run (2)'):
                        return False
            else:
                fehlermeldung(
                    u'Datenfehler: ',
                    u'Bitte ergänzen Sie in der Tabelle "abflussparameter" einen Datensatz für unbefestigte Flächen ("bodenklasse" darf nicht leer oder NULL sein)'
                )

        # # Kontrolle, ob noch Flächen in Tabelle "tezg" ohne Zuordnung zu einem Abflussparameter oder zu einem
        # # Abflussparameter, bei dem keine Bodenklasse definiert ist (Kennzeichen für undurchlässige Flächen).

        # sql = u"""SELECT te.abflussparameter, te.teilgebiet, count(*) AS anz
        # FROM tezg AS te
        # LEFT JOIN abflussparameter AS ap
        # ON te.abflussparameter = ap.apnam
        # WHERE ap.bodenklasse IS NULL
        # GROUP BY abflussparameter, teilgebiet"""

        # if not self.dbQK.sql(sql, u'createunbeffl.run (3)'):
        # return False

        # data = self.dbQK.fetchall()

        # if len(data) > 0:
        # liste = [u'{}\t{}\t{}'.format(el1, el2, el3) for el1, el2, el3 in data]
        # liste.insert(0, u'\nAbflussparameter\tTeilgebiet\tAnzahl')

        # fehlermeldung(u'In Tabelle "tezg" fehlen Abflussparameter oder gehören zu befestigten Flächen (Bodenklasse = NULL):\n',
        # u'\n'.join(liste))
        # return False

        sql = u"""SELECT te.abflussparameter, te.teilgebiet, bk.bknam, count(*) AS anz, 
                CASE WHEN te.abflussparameter ISNULL THEN 'Fehler: Kein Abflussparameter angegeben' ELSE
                    CASE WHEN bk.infiltrationsrateanfang ISNULL THEN 'Fehler: Keine Bodenklasse angegeben' 
                         WHEN bk.infiltrationsrateanfang < 0.00001 THEN 'Fehler: undurchlässige Bodenart'
                         ELSE ''
                    END
                END AS status
                            FROM tezg AS te
                            LEFT JOIN abflussparameter AS ap
                            ON te.abflussparameter = ap.apnam
                            LEFT JOIN bodenklassen AS bk
                            ON bk.bknam = ap.bodenklasse
                            GROUP BY abflussparameter, teilgebiet"""
        if not self.dbQK.sql(sql, u'createunbeffl.run (4)'):
            return None

        self.listetezg = self.dbQK.fetchall()
        nzeilen = len(self.listetezg)
        self.dlg.tw_selAbflparamTeilgeb.setRowCount(nzeilen)
        self.dlg.tw_selAbflparamTeilgeb.setHorizontalHeaderLabels([
            u"Abflussparameter", u"Teilgebiet", u"Bodenklasse", u"Anzahl",
            u"Anmerkungen"
        ])
        self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(
            0, 144)  # 17 Pixel für Rand und Nummernspalte (und je Spalte?)
        self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(1, 140)
        self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(2, 90)
        self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(3, 50)
        self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(4, 200)
        for i, elem in enumerate(self.listetezg):
            for j, item in enumerate(elem):
                cell = u'{}'.format(elem[j])
                self.dlg.tw_selAbflparamTeilgeb.setItem(
                    i, j, QTableWidgetItem(cell))
                self.dlg.tw_selAbflparamTeilgeb.setRowHeight(i, 20)

        # config in Dialog übernehmen

        # Autokorrektur

        if 'autokorrektur' in self.config:
            autokorrektur = self.config['autokorrektur']
        else:
            autokorrektur = True
        self.dlg.cb_autokorrektur.setChecked(autokorrektur)

        self.countselection()

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        logger.debug('\n\nresult = {}'.format(repr(result)))
        # See if OK was pressed
        if result:
            # Do something useful here - delete the line containing pass and
            # substitute with your code.
            # pass

            # Start der Verarbeitung
            liste_selAbflparamTeilgeb = self.listselectedTabitems(
                self.dlg.tw_selAbflparamTeilgeb)
            logger.debug(u'\nliste_selAbflparamTeilgeb (1): {}'.format(
                liste_selAbflparamTeilgeb))
            autokorrektur = self.dlg.cb_autokorrektur.isChecked()

            self.config['autokorrektur'] = autokorrektur

            with open(self.configfil, 'w') as fileconfig:
                fileconfig.write(json.dumps(self.config))

            createUnbefFlaechen(self.dbQK, liste_selAbflparamTeilgeb,
                                autokorrektur)
Esempio n. 3
0
def qgsadapt(projectTemplate,
             qkanDB,
             epsg,
             projectFile,
             setPathToTemplateDir=True,
             dbtyp=u'SpatiaLite'):
    '''Lädt eine (Vorlage-) Projektdatei (*.qgs) und adaptiert diese auf eine QKan-Datenbank an. 
    Anschließend wird dieses Projekt geladen. 
    Voraussetzungen: keine

    :projectTemplate:           Vorlage-Projektdatei
    :type database:             String

    :qkanDB:                    Ziel-Datenbank, auf die die Projektdatei angepasst werden soll
    :type qkanDB:               String

    :projectFile:               Zu Erzeugende Projektdatei
    :type projectFile:          String

    :setPathToTemplateDir:      Option, ob das Suchverzeichnis auf das Template-Verzeichnis gesetzt werden soll. 
    :type setPathToTemplateDir: Boolean

    :dbtyp:                     Typ der Datenbank (SpatiaLite, PostGIS)
    :type dbtyp:                String
    
    :returns: void
    '''

    # ------------------------------------------------------------------------------
    # Datenbankverbindungen

    dbQK = DBConnection(
        dbname=qkanDB,
        epsg=epsg)  # Datenbankobjekt der QKan-Datenbank zum Schreiben

    if dbQK is None:
        fehlermeldung(
            u"Fehler in qgsadapt",
            u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format(
                qkanDB))
        iface.messageBar().pushMessage(u"Fehler in qgsadapt",
                    u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format( \
            qkanDB), level=QgsMessageBar.CRITICAL)
        return None

    # --------------------------------------------------------------------------
    # Zoom-Bereich für die Projektdatei vorbereiten
    sql = u'''SELECT min(xsch) AS xmin, 
                    max(xsch) AS xmax, 
                    min(ysch) AS ymin, 
                    max(ysch) AS ymax
             FROM schaechte'''
    try:
        dbQK.sql(sql)
    except BaseException as e:
        fehlermeldung('SQL-Fehler', str(e))
        fehlermeldung("Fehler in qgsadapt",
                      u"\nFehler in sql_zoom: \n" + sql + '\n\n')

    daten = dbQK.fetchone()
    try:
        zoomxmin, zoomxmax, zoomymin, zoomymax = daten
    except BaseException as e:
        fehlermeldung('SQL-Fehler', str(e))
        fehlermeldung("Fehler in qgsadapt",
                      u"\nFehler in sql_zoom; daten= " + str(daten) + '\n')

    # --------------------------------------------------------------------------
    # Projektionssystem für die Projektdatei vorbereiten
    sql = """SELECT srid
            FROM geom_cols_ref_sys
            WHERE Lower(f_table_name) = Lower('schaechte')
            AND Lower(f_geometry_column) = Lower('geom')"""
    if not dbQK.sql(sql, 'importkanaldaten_dyna (37)'):
        return None

    srid = dbQK.fetchone()[0]
    try:
        crs = QgsCoordinateReferenceSystem(
            srid, QgsCoordinateReferenceSystem.EpsgCrsId)
        srsid = crs.srsid()
        proj4text = crs.toProj4()
        description = crs.description()
        projectionacronym = crs.projectionAcronym()
        if 'ellipsoidacronym' in dir(crs):
            ellipsoidacronym = crs.ellipsoidacronym()
        else:
            ellipsoidacronym = None
    except BaseException as e:
        srid, srsid, proj4text, description, projectionacronym, ellipsoidacronym = \
            'dummy', 'dummy', 'dummy', 'dummy', 'dummy', 'dummy'

        fehlermeldung('\nFehler in "daten"', str(e))
        fehlermeldung("Fehler in qgsadapt",
                      u"\nFehler bei der Ermittlung der srid: \n" + str(daten))

    # --------------------------------------------------------------------------
    # Datenbankverbindungen schliessen

    del dbQK

    # --------------------------------------------------------------------------
    # Projektdatei schreiben, falls ausgewählt

    if projectFile is None or projectFile == u'':
        fehlermeldung(u'Bedienerfehler!',
                      u'Es wurde keine Projektdatei ausgewählt')
        return False

    if setPathToTemplateDir:
        templatepath = os.path.join(pluginDirectory('qkan'),
                                    u"database/templates")

    projectpath = os.path.dirname(projectFile)
    if os.path.dirname(qkanDB) == projectpath:
        datasource = qkanDB.replace(os.path.dirname(qkanDB), u'.')
    else:
        datasource = qkanDB

    # Liste der Geotabellen aus QKan, um andere Tabellen von der Bearbeitung auszuschliessen
    # Liste steht in 3 Modulen: tools.k_tools, importdyna.import_from_dyna, importhe.import_from_he
    tabliste = [
        u'einleit', u'einzugsgebiete', u'flaechen', u'haltungen', u'linkfl',
        u'linksw', u'pumpen', u'schaechte', u'teilgebiete', u'tezg', u'wehre'
    ]

    # Liste der QKan-Formulare, um individuell erstellte Formulare von der Bearbeitung auszuschliessen
    formsliste = [
        'qkan_abflussparameter.ui', 'qkan_anbindungageb.ui',
        'qkan_anbindungeinleit.ui', 'qkan_anbindungflaechen.ui',
        'qkan_auslaesse.ui', 'qkan_auslasstypen.ui', 'qkan_aussengebiete.ui',
        'qkan_bodenklassen.ui', 'qkan_einleit.ui', 'qkan_einzugsgebiete.ui',
        'qkan_entwaesserungsarten.ui', 'qkan_flaechen.ui', 'qkan_haltungen.ui',
        'qkan_profildaten.ui', 'qkan_profile.ui', 'qkan_pumpen.ui',
        'qkan_pumpentypen.ui', 'qkan_schaechte.ui',
        'qkan_simulationsstatus.ui', 'qkan_speicher.ui',
        'qkan_speicherkennlinien.ui', 'qkan_swref.ui', 'qkan_teilgebiete.ui',
        'qkan_tezg.ui', 'qkan_wehre.ui'
    ]

    # Lesen der Projektdatei ------------------------------------------------------------------
    qgsxml = ET.parse(projectTemplate)
    root = qgsxml.getroot()

    # Projektionssystem anpassen --------------------------------------------------------------

    for tag_maplayer in root.findall(u".//projectlayers/maplayer"):
        tag_datasource = tag_maplayer.find(u"./datasource")
        tex = tag_datasource.text
        # Nur QKan-Tabellen bearbeiten
        if tex[tex.index(u'table="') + 7:].split(u'" ')[0] in tabliste:

            # <extend> löschen
            for tag_extent in tag_maplayer.findall(u"./extent"):
                tag_maplayer.remove(tag_extent)

            for tag_spatialrefsys in tag_maplayer.findall(
                    u"./srs/spatialrefsys"):
                tag_spatialrefsys.clear()

                elem = ET.SubElement(tag_spatialrefsys, u'proj4')
                elem.text = proj4text
                elem = ET.SubElement(tag_spatialrefsys, u'srsid')
                elem.text = u'{}'.format(srsid)
                elem = ET.SubElement(tag_spatialrefsys, u'srid')
                elem.text = u'{}'.format(srid)
                elem = ET.SubElement(tag_spatialrefsys, u'authid')
                elem.text = u'EPSG: {}'.format(srid)
                elem = ET.SubElement(tag_spatialrefsys, u'description')
                elem.text = description
                elem = ET.SubElement(tag_spatialrefsys, u'projectionacronym')
                elem.text = projectionacronym
                if ellipsoidacronym is not None:
                    elem = ET.SubElement(tag_spatialrefsys,
                                         u'ellipsoidacronym')
                    elem.text = ellipsoidacronym

    # Pfad zu Formularen auf plugin-Verzeichnis setzen -----------------------------------------

    formspath = os.path.join(pluginDirectory('qkan'), u"forms")
    for tag_maplayer in root.findall(u".//projectlayers/maplayer"):
        tag_editform = tag_maplayer.find(u"./editform")
        dateiname = os.path.basename(tag_editform.text)
        if dateiname in formsliste:
            # Nur QKan-Tabellen bearbeiten
            tag_editform.text = os.path.join(formspath, dateiname)

    # Zoom für Kartenfenster einstellen -------------------------------------------------------

    for tag_extent in root.findall(u".//mapcanvas/extent"):
        elem = tag_extent.find(u"./xmin")
        elem.text = u'{:.3f}'.format(zoomxmin)
        elem = tag_extent.find(u"./ymin")
        elem.text = u'{:.3f}'.format(zoomymin)
        elem = tag_extent.find(u"./xmax")
        elem.text = u'{:.3f}'.format(zoomxmax)
        elem = tag_extent.find(u"./ymax")
        elem.text = u'{:.3f}'.format(zoomymax)

    # Projektionssystem anpassen --------------------------------------------------------------

    for tag_spatialrefsys in root.findall(
            u".//mapcanvas/destinationsrs/spatialrefsys"):
        tag_spatialrefsys.clear()

        elem = ET.SubElement(tag_spatialrefsys, u'proj4')
        elem.text = proj4text
        elem = ET.SubElement(tag_spatialrefsys, u'srid')
        elem.text = u'{}'.format(srid)
        elem = ET.SubElement(tag_spatialrefsys, u'authid')
        elem.text = u'EPSG: {}'.format(srid)
        elem = ET.SubElement(tag_spatialrefsys, u'description')
        elem.text = description
        elem = ET.SubElement(tag_spatialrefsys, u'projectionacronym')
        elem.text = projectionacronym
        if ellipsoidacronym is not None:
            elem = ET.SubElement(tag_spatialrefsys, u'ellipsoidacronym')
            elem.text = ellipsoidacronym

    # Pfad zur QKan-Datenbank anpassen

    for tag_datasource in root.findall(
            u".//projectlayers/maplayer/datasource"):
        text = tag_datasource.text
        tag_datasource.text = u"dbname='" + datasource + u"' " + text[
            text.find(u'table='):]

    qgsxml.write(projectFile)  # writing modified project file
    logger.debug(u'Projektdatei: {}'.format(projectFile))
    # logger.debug(u'encoded string: {}'.format(tex))

    # ------------------------------------------------------------------------------
    # Abschluss: Ggfs. Protokoll schreiben und Datenbankverbindungen schliessen

    iface.mainWindow().statusBar().clearMessage()
    iface.messageBar().pushMessage(
        "Information",
        "Projektdatei ist angepasst und muss neu geladen werden!",
        level=QgsMessageBar.INFO)