예제 #1
0
 def __init__(self, iface, parent=None):
     """
     Constructor
     """
     super(StyleManagerTool, self).__init__(parent)
     self.setupUi(self)
     self.iface = iface
     self.splitter.hide()
     self.refreshDb()
     self.dbFactory = DbFactory()
     # self.applyPushButton.setEnabled(False)
     self.utils = Utils()
     self.algRunner = AlgRunner()
예제 #2
0
 def runGrassDissolve(self, inputLyr, context, feedback=None, column=None, outputLyr=None, onFinish=None):
     """
     Runs dissolve from GRASS algorithm provider.
     :param inputLyr: (QgsVectorLayer) layer to be dissolved.
     :param context: (QgsProcessingContext) processing context.
     :param feedback: (QgsProcessingFeedback) QGIS object to keep track of progress/cancelling option.
     :param column: ()
     :param outputLyr: (str) URI to output layer.
     :param onFinish: (list-of-str) sequence of algs to be run after dissolve is executed, in execution order.
     :return: (QgsVectorLayer) dissolved (output) layer.
     """
     return AlgRunner().runGrassDissolve(inputLyr, context, feedback=None, column=None, outputLyr=None, onFinish=None)
예제 #3
0
 def prepareConversion(self, inputLyr, context, inputExpression=None, filterLyr=None,\
                      behavior=None, bufferRadius=None, conversionMap=None, feedback=None):
     bufferRadius = 0 if bufferRadius is None else bufferRadius
     algRunner = AlgRunner()
     if feedback is not None:
         count = 0
         if inputExpression is not None:
             count += 1
         if filterLyr is not None:
             count += 1
             if behavior == 3:
                 count += 1
         elif count == 0:
             return inputLyr
         multiStepFeedback = QgsProcessingMultiStepFeedback(count, feedback)
     else:
         multiStepFeedback = None
     localLyr = inputLyr
     currentStep = 0
     if inputExpression is not None and inputExpression != '':
         if multiStepFeedback is not None:
             multiStepFeedback.setCurrentStep(currentStep)
         localLyr = algRunner.runFilterExpression(
             inputLyr=localLyr,
             context=context,
             expression = inputExpression,
             feedback=multiStepFeedback
         )
         currentStep+=1
     if filterLyr is not None:
         if multiStepFeedback is not None:
             multiStepFeedback.setCurrentStep(currentStep)
         if behavior == 3:
             filterLyr = algRunner.runBuffer(filterLyr, bufferRadius, context, feedback=multiStepFeedback)
             currentStep += 1
         localLyr = algRunner.runIntersection(localLyr, context, overlayLyr=filterLyr)
     return localLyr
예제 #4
0
 def filterByExpression(self, layer, expression, context, feedback=None):
     """
     Filters a given layer using a filtering expression. The original layer is not modified.
     :param layer: (QgsVectorLayer) layer to be filtered.
     :param expression: (str) expression to be used as filter.
     :param context: (QgsProcessingContext) processing context in which algorithm should be executed.
     :param feedback: (QgsFeedback) QGIS feedback component (progress bar).
     :return: (QgsVectorLayer) filtered layer.
     """
     return AlgRunner().runFilterExpression(
             inputLyr=layer,
             context=context,
             expression = expression,
             feedback=feedback
         )
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        #get the network handler
        layerHandler = LayerHandler()
        networkHandler = NetworkHandler()
        algRunner = AlgRunner()
        self.nodeTypeNameDict = networkHandler.nodeTypeDict
        # get network layer
        networkLayer = self.parameterAsLayer(parameters, self.NETWORK_LAYER, context)
        if networkLayer is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.NETWORK_LAYER))
        attributeBlackList = self.parameterAsFields(parameters, self.ATTRIBUTE_BLACK_LIST, context)
        ignoreVirtual = self.parameterAsBool(parameters, self.IGNORE_VIRTUAL_FIELDS, context)
        ignorePK = self.parameterAsBool(parameters, self.IGNORE_PK_FIELDS, context)
        # get network node layer
        (nodeSink, dest_id) = self.parameterAsSink(parameters, self.NETWORK_NODES,
                context, self.getFields(), QgsWkbTypes.MultiPoint, networkLayer.sourceCrs())
        #prepairs flag sink for raising errors
        self.prepareFlagSink(parameters, networkLayer, QgsWkbTypes.MultiPoint, context)
        
        waterBodyClasses = self.parameterAsLayer(parameters, self.WATER_BODY_LAYERS, context)
        waterBodyClasses = waterBodyClasses if waterBodyClasses is not None else []
        # get water sink layer
        waterSinkLayer = self.parameterAsLayer(parameters, self.SINK_LAYER, context)
        # get spillway layer
        spillwayLayer = self.parameterAsLayer(parameters, self.SPILLWAY_LAYER, context)
        # get frame layer
        frameLayer = self.parameterAsLayer(parameters, self.REF_LAYER, context)
        currStep = 0
        if frameLayer is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.REF_LAYER))
        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Preparing bounds...'))
        frame = layerHandler.getFrameOutterBounds(frameLayer, algRunner, context, feedback=multiStepFeedback)
        currStep += 1
        # get search radius
        searchRadius = self.parameterAsDouble(parameters, self.SEARCH_RADIUS, context)
        # get ditch layer
        ditchLayer = self.parameterAsLayer(parameters, self.DITCH_LAYER, context)

        #new step
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Performing node identification...'))
        self.nodeDict = networkHandler.identifyAllNodes(networkLayer=networkLayer, feedback=multiStepFeedback) #zoado, mudar lógica
        multiStepFeedback.pushInfo(self.tr('{node_count} node(s) identificated...').format(node_count=len(self.nodeDict)))
        currStep += 1
        #new step
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Performing node classification...'))
        networkHandler.nodeDict = self.nodeDict
        self.nodeTypeDict, nodeFlagDict = networkHandler.classifyAllNodes(
                networkLayer=networkLayer,
                frameLyrContourList=frame,
                waterBodiesLayers=waterBodyClasses,
                searchRadius=searchRadius,
                waterSinkLayer=waterSinkLayer,
                spillwayLayer=spillwayLayer,
                feedback=multiStepFeedback,
                attributeBlackList=attributeBlackList,
                excludePrimaryKeys=ignorePK,
                ignoreVirtualFields=ignoreVirtual,
                ditchLayer=ditchLayer
            )
        currStep += 1
        #new step
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Writing nodes...'))
        self.fillNodeSink(
            nodeSink=nodeSink,
            networkLineLayerName=networkLayer.name(),
            nodeFlagDict=nodeFlagDict,
            feedback=multiStepFeedback)
        return {self.NETWORK_NODES : dest_id, self.FLAGS : self.flag_id}
예제 #6
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        spatialRealtionsHandler = SpatialRealtionsHandler()
        algRunner = AlgRunner()
        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        if inputLyr is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        contourFieldName = self.parameterAsField(parameters, self.CONTOUR_ATTR, context)
        threshold = self.parameterAsDouble(parameters, self.TOLERANCE, context)
        topology_radius = self.parameterAsDouble(parameters, self.TOPOLOGY_RADIUS, context)
        refLyr = self.parameterAsVectorLayer(parameters, self.REFERENCE_LYR, context)
        self.prepareFlagSink(parameters, inputLyr, QgsWkbTypes.Polygon, context)

        #1. Get all lines into one line lyr
        currentStep = 0
        if refLyr is not None:
            multiStepFeedback = QgsProcessingMultiStepFeedback(4, feedback)
            multiStepFeedback.setCurrentStep(currentStep)
            multiStepFeedback.pushInfo(self.tr('Identifying dangles...'))
            dangles = algRunner.runIdentifyDangles(
                inputLayer=inputLayer,
                searchRadius=topology_radius,
                context=context,
                onlySelected=onlySelected,
                polygonFilter=refLyr,
                feedback=multiStepFeedback
            )
            currentStep += 1
            #2. Snap frame to dangles
            multiStepFeedback.setCurrentStep(currentStep)
            multiStepFeedback.pushInfo(self.tr('Adjusting frame lyr...'))
            snappedFrame = algRunner.runSnapGeometriesToLayer(
                inputLayer=inputLyr,
                referenceLayer=dangles,
                tol=topology_radius,
                context=context
                feedback=multiStepFeedback
            )
            currentStep += 1
        else:
            multiStepFeedback = QgsProcessingMultiStepFeedback(2, feedback)

        #3. Validate contour lines
        multiStepFeedback.setCurrentStep(currentStep)
        multiStepFeedback.pushInfo(self.tr('Validating contour lines...'))
        invalidDict = spatialRealtionsHandler.validateContourLines(
            contourLyr=inputLyr,
            contourAttrName=contourFieldName,
            refLyr=refLyr,
            feedback=multiStepFeedback
        )
        currentStep+=1
        multiStepFeedback.setCurrentStep(currentStep)
        multiStepFeedback.pushInfo(self.tr('Raising flags...'))
        nFlags = len(invalidDict)
        step = 100/nFlags if nFlags else 0
        for current, (geom, text) in enumerate(invalidDict.items()):
            self.flagFeature(geom, text, fromWkb=True)
            multiStepFeedback.setProgress(step * current)
            
        return {self.FLAGS: self.flag_id}
예제 #7
0
class StyleManagerTool(QWidget, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """
        Constructor
        """
        super(StyleManagerTool, self).__init__(parent)
        self.setupUi(self)
        self.iface = iface
        self.splitter.hide()
        self.refreshDb()
        self.dbFactory = DbFactory()
        # self.applyPushButton.setEnabled(False)
        self.utils = Utils()
        self.algRunner = AlgRunner()

    @pyqtSlot(bool)
    def on_layerPushButton_toggled(self, toggled):
        """
        Shows/Hides the tool bar
        """
        if toggled:
            self.refreshDb()
            self.splitter.show()
        else:
            self.splitter.hide()

    @pyqtSlot(bool, name='on_refreshPushButton_clicked')
    def refreshDb(self):
        self.dbComboBox.clear()
        self.dbComboBox.addItem(self.tr('Select Database'))
        #populate database list
        for dbName in self.getDatabaseList():
            self.dbComboBox.addItem(dbName)

    @pyqtSlot(int, name='on_styleComboBox_currentIndexChanged')
    def enableApply(self):
        dbIdx = self.dbComboBox.currentIndex()
        stylesIdx = self.styleComboBox.currentIndex()
        if dbIdx > 0 and stylesIdx > 0:
            self.applyPushButton.setEnabled(True)
        else:
            self.applyPushButton.setEnabled(False)

    @pyqtSlot(bool)
    def on_applyPushButton_clicked(self):
        try:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            dbName = self.dbComboBox.currentText()
            styleName = self.styleComboBox.currentText()
            lyrList = self.getLayers(dbName)
            abstractDb = self.getAbstractDb(dbName)
            dbVersion = abstractDb.getDatabaseVersion()
            stylesDict = abstractDb.getStyleDict(dbVersion)
            selectedStyle = stylesDict[styleName]
            if 'db:' in selectedStyle:
                self.algRunner.runApplStylesFromDatabaseToLayers(
                    inputList=lyrList,
                    context=QgsProcessingContext(),
                    styleName=selectedStyle.split(':')[-1])
            else:
                stylePath = os.path.join(
                    abstractDb.getStyleDirectory(dbVersion), selectedStyle)
                self.algRunner.runMatchAndApplyQmlStylesToLayer(
                    inputList=lyrList,
                    qmlFolder=stylePath,
                    context=QgsProcessingContext())
            # localProgress = ProgressWidget(1, len(lyrList) - 1, self.tr('Loading style {0}').format(styleName), parent=self.iface.mapCanvas())
            # for lyr in lyrList:
            #     try:
            #         uri = QgsDataSourceUri(lyr.dataProvider().dataSourceUri())
            #         fullPath = self.getStyle(abstractDb, selectedStyle, lyr.name())
            #         if fullPath:
            #             lyr.loadNamedStyle(fullPath, True)
            #             # remove qml temporary file
            #             self.utils.deleteQml(fullPath)
            #             # clear fullPath variable
            #             del fullPath
            #     except:
            #         pass
            #     localProgress.step()
            # self.iface.mapCanvas().refreshAllLayers()
            QApplication.restoreOverrideCursor()
        except Exception as e:
            QgsMessageLog.logMessage(
                self.tr('Error setting style ') + styleName + ': ' +
                ':'.join(e.args), "DSGTools Plugin", Qgis.Critical)
            QApplication.restoreOverrideCursor()

    def getLayers(self, dbName):
        lyrList = []
        for lyr in self.iface.mapCanvas().layers():
            if isinstance(lyr, QgsVectorLayer):
                candidateUri = QgsDataSourceUri(
                    lyr.dataProvider().dataSourceUri())
                if (candidateUri.database() == dbName and lyr.providerType() in ['postgres', 'spatialite']) \
                    or (os.path.splitext(os.path.basename(candidateUri.uri().split('|')[0]))[0] == dbName and lyr.providerType() == 'ogr'):
                    lyrList.append(lyr)
        return lyrList

    def getDatabaseList(self):
        # dbList = list()
        dbSet = set()
        for lyr in self.iface.mapCanvas().layers():
            if isinstance(lyr, QgsVectorLayer):
                candidateUri = QgsDataSourceUri(
                    lyr.dataProvider().dataSourceUri())
                dbName = candidateUri.database()
                # if dbName not in dbList and lyr.providerType() in ['postgres', 'spatialite']:
                if lyr.providerType() in ['postgres', 'spatialite']:
                    dbSet.add(dbName)
                elif lyr.providerType() == 'ogr':
                    dbName = os.path.splitext(
                        os.path.basename(
                            lyr.dataProvider().dataSourceUri().split(
                                '|')[0]))[0]
                    # if db not in dbList:
                    dbSet.add(dbName)
        return dbSet

    def loadStylesCombo(self, abstractDb):
        dbVersion = abstractDb.getDatabaseVersion()
        styleDict = abstractDb.getStyleDict(dbVersion)
        self.styleComboBox.clear()
        styleList = list(styleDict.keys())
        numberOfStyles = len(styleList)
        if numberOfStyles > 0:
            self.styleComboBox.addItem(self.tr('Select Style'))
            for i in range(numberOfStyles):
                self.styleComboBox.addItem(styleList[i])
        else:
            self.styleComboBox.addItem(self.tr('No available styles'))

    def getParametersFromLyr(self, dbName):
        for lyr in self.iface.mapCanvas().layers():
            if isinstance(lyr, QgsVectorLayer):
                candidateUri = QgsDataSourceUri(
                    lyr.dataProvider().dataSourceUri())
                if candidateUri.database() == dbName or \
                        os.path.splitext(os.path.basename(candidateUri.uri().split('|')[0]))[0] == dbName:
                    currLyr = lyr
                    break
        dbParameters = dict()
        if currLyr.providerType() == 'postgres':
            dbParameters['host'] = candidateUri.host()
            dbParameters['port'] = candidateUri.port()
            dbParameters['user'] = candidateUri.username()
            dbParameters['password'] = candidateUri.password()
            return dbParameters, DsgEnums.DriverPostGIS
        elif currLyr.providerType() == 'spatialite':
            dbParameters['dbPath'] = candidateUri.database()
            return dbParameters, DsgEnums.DriverSpatiaLite
        elif currLyr.providerType() == 'ogr':
            # geopackage provider type is ogr
            dbParameters['dbPath'] = candidateUri.database()
            return dbParameters, DsgEnums.DriverGeopackage
        else:
            raise Exception(
                self.tr('Feature only implemented for PostGIS and Spatialite'))

    def getAbstractDb(self, dbName):
        dbParameters, driverName = self.getParametersFromLyr(dbName)
        abstractDb = self.dbFactory.createDbFactory(driverName)
        if 'host' in list(dbParameters.keys()):
            abstractDb.connectDatabaseWithParameters(dbParameters['host'],
                                                     dbParameters['port'],
                                                     dbName,
                                                     dbParameters['user'],
                                                     dbParameters['password'])
        else:
            abstractDb.connectDatabase(dbParameters['dbPath'])
        return abstractDb

    @pyqtSlot(int)
    def on_dbComboBox_currentIndexChanged(self, idx):
        self.enableApply()
        if self.sender().objectName() == 'dbComboBox':
            if idx <= 0:
                self.styleComboBox.clear()
                self.styleComboBox.addItem(self.tr('Select Style'))
                self.styleComboBox.setEnabled(False)
            elif idx > 0:
                self.styleComboBox.setEnabled(True)
                dbName = self.dbComboBox.currentText()
                abstractDb = self.getAbstractDb(dbName)
                self.loadStylesCombo(abstractDb)