def getGapsOfCoverageWithFrame(self, coverage, frameLyr, context, feedback=None, onFinish=None): """ Identifies all gaps inside coverage layer and between coverage and frame layer. :param coverage: (QgsVectorLayer) unified coverage layer. :param frameLyr: (QgsVectorLayer) frame layer. :param context: (QgsProcessingContext) :param feedback: (QgsProcessingFeedback) QGIS' object for progress tracking and controlling. :param onFinish: (list-of-str) list of alg names to be executed after difference alg. """ # identify all holes in coverage layer first coverageHolesParam = { 'INPUT': coverage, 'FLAGS': 'memory:', 'SELECTED': False } coverageHoles = processing.run('dsgtools:identifygaps', coverageHolesParam, None, feedback, context)['FLAGS'] geometryHandler = GeometryHandler() gapSet = set() for feat in coverageHoles.getFeatures(): for geom in geometryHandler.deaggregateGeometry(feat.geometry()): self.flagFeature(geom, self.tr('Gap in coverage layer')) gapSet.add(geom) # missing possible holes between coverage and frame, but gaps in coverage may cause invalid geometries # while executing difference alg. Since its already identified, "add" them to the coverage layerHandler = LayerHandler() filledCoverage = layerHandler.createAndPopulateUnifiedVectorLayer( [coverage, coverageHoles], QgsWkbTypes.Polygon) # dissolveParameters = { # 'INPUT' : filledCoverage, # 'FIELD':[], # 'OUTPUT':'memory:' # } # dissolveOutput = processing.run('native:dissolve', dissolveParameters, context = context)['OUTPUT'] dissolveOutput = LayerHandler().runGrassDissolve( filledCoverage, context) differenceParameters = { 'INPUT': frameLyr, 'OVERLAY': dissolveOutput, 'OUTPUT': 'memory:' } differenceOutput = processing.run('native:difference', differenceParameters, onFinish, feedback, context) for feat in differenceOutput['OUTPUT'].getFeatures(): for geom in geometryHandler.deaggregateGeometry(feat.geometry()): if geom not in gapSet: self.flagFeature(geom, self.tr('Gap in coverage with frame'))
def attributeMap(self): """ Reads the field map data and set it to a button attribute map format. :return: (dict) read attribute map. """ attrMap = dict() table = self.attributeTableWidget vMaps = LayerHandler().valueMaps(self.vectorLayer()) \ if self.vectorLayer() else {} for row in range(table.rowCount()): attr = table.cellWidget(row, self.ATTR_COL).text().replace("&", "") attrMap[attr] = dict() valueWidget = table.cellWidget(row, self.VAL_COL) attrMap[attr]["ignored"] = table.cellWidget(row, self.IGNORED_COL)\ .cb.isChecked() # "ignored" still allows the value to be set as last priority attrMap[attr]["value"] = { QWidget: lambda: valueWidget.cb.isChecked(), QLineEdit: lambda: valueWidget.text(), QSpinBox: lambda: valueWidget.value(), QDoubleSpinBox: lambda: valueWidget.value(), QComboBox: lambda: vMaps[attr][valueWidget.currentText()] }[type(valueWidget)]() attrMap[attr]["isPk"] = isinstance( table.cellWidget(row, self.PK_COL), QPushButton) attrMap[attr]["editable"] = table.cellWidget(row, self.EDIT_COL)\ .cb.isChecked() return attrMap
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() algRunner = AlgRunner() inputPolygonLyrList = self.parameterAsLayerList( parameters, self.INPUT_POLYGONS, context) constraintLineLyrList = self.parameterAsLayerList( parameters, self.CONSTRAINT_LINE_LAYERS, context) constraintPolygonLyrList = self.parameterAsLayerList( parameters, self.CONSTRAINT_POLYGON_LAYERS, context) if set(constraintPolygonLyrList).intersection( set(inputPolygonLyrList)): raise QgsProcessingException( self. tr('Input polygon layers must not be in constraint polygon list.' )) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) boundaryLyr = self.parameterAsLayer(parameters, self.GEOGRAPHIC_BOUNDARY, context) # Compute the number of steps to display within the progress bar and # get features from source # alg steps: # 1- Build single polygon layer # 2- Compute center points # 3- Compute boundaries multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo(self.tr('Building single polygon layer')) singlePolygonLayer = layerHandler.getMergedLayer( inputPolygonLyrList, onlySelected=onlySelected, feedback=multiStepFeedback, context=context, algRunner=algRunner) multiStepFeedback.setCurrentStep(1) (output_center_point_sink, output_center_point_sink_id) = self.parameterAsSink( parameters, self.OUTPUT_CENTER_POINTS, context, singlePolygonLayer.fields(), QgsWkbTypes.Point, singlePolygonLayer.sourceCrs()) (output_boundaries_sink, output_boundaries_sink_id) = self.parameterAsSink( parameters, self.OUTPUT_BOUNDARIES, context, QgsFields(), QgsWkbTypes.LineString, singlePolygonLayer.sourceCrs()) layerHandler.getCentroidsAndBoundariesFromPolygons( singlePolygonLayer, output_center_point_sink, output_boundaries_sink, constraintLineLyrList=constraintLineLyrList, constraintPolygonLyrList=constraintPolygonLyrList, context=context, feedback=multiStepFeedback, algRunner=algRunner) return { self.OUTPUT_CENTER_POINTS: output_center_point_sink_id, self.OUTPUT_BOUNDARIES: output_boundaries_sink_id }
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() 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) refLyr = self.parameterAsVectorLayer(parameters, self.REFERENCE_LAYER, context) if refLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.REFERENCE_LAYER)) tol = self.parameterAsDouble(parameters, self.TOLERANCE, context) behavior = self.parameterAsEnum(parameters, self.BEHAVIOR, context) layerHandler.snapToLayer(inputLyr, refLyr, tol, behavior, onlySelected=onlySelected, feedback=feedback) return {self.OUTPUT: inputLyr}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context) if inputLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) outputLyr = self.parameterAsVectorLayer(parameters, self.OUTPUT, context) if outputLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.OUTPUT)) if inputLyr == outputLyr: raise QgsProcessingException( self.tr('Input must be different from output!')) inputExpression = self.parameterAsExpression( parameters, self.INPUT_FILTER_EXPRESSION, context) filterLyr = self.parameterAsVectorLayer(parameters, self.FILTER_LAYER, context) behavior = self.parameterAsEnum(parameters, self.BEHAVIOR, context) prepairedLyr = layerHandler.prepareConversion( inputLyr=inputLyr, context=context, inputExpression=inputExpression, filterLyr=filterLyr, behavior=behavior, feedback=feedback) return {self.INPUT: inputLyr}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() 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) searchRadius = self.parameterAsDouble(parameters, self.SEARCH_RADIUS, context) # output flag type is a polygon because the flag will be a circle with # radius tol and center as the vertex self.prepareFlagSink(parameters, inputLyr, QgsWkbTypes.Point, context) # Compute the number of steps to display within the progress bar and # get features from source multiStepFeedback = QgsProcessingMultiStepFeedback(2, feedback) multiStepFeedback.setCurrentStep(0) vertexNearEdgeFlagDict = layerHandler.getVertexNearEdgeDict( inputLyr, searchRadius, onlySelected=onlySelected, feedback=multiStepFeedback, context=context) multiStepFeedback.setCurrentStep(1) self.raiseFeaturesFlags(inputLyr, vertexNearEdgeFlagDict, multiStepFeedback) return {self.FLAGS: self.flag_id}
def __init__(self, layer, layerMap, attributeMap=None, valueMaps=None): """ Class constructor. :param layer: (QgsVectorLayer) layer that will receive the reclassified features. :param layerMap: (dict) a map from vector layer to feature list to be reclassified (allocated to another layer). :param attributeMap: (dict) a map from attribute name to its (reclassified) value. :param valueMaps: (dict) map of all value/relations maps set to layer's fields. These maps will be used for domain checking operations. """ super(CustomFeatureForm, self).__init__() self.setupUi(self) self._layer = layer self.layerMap = layerMap self.valueMaps = valueMaps or LayerHandler().valueMaps(layer) self.attributeMap = attributeMap or dict() self._layersWidgets = dict() self.setupReclassifiedLayers() self.widgetsLayout = QGridLayout(self.scrollAreaWidgetContents) self._fieldsWidgets = dict() self.setupFields() self.setWindowTitle(self.tr("DSGTools Feature Reclassification Form")) self.messageBar = QgsMessageBar(self)
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() inputLineLyrList = self.parameterAsLayerList(parameters, self.INPUT_LINES, context) inputPolygonLyrList = self.parameterAsLayerList( parameters, self.INPUT_POLYGONS, context) if inputLineLyrList + inputPolygonLyrList == []: raise QgsProcessingException(self.tr('Select at least one layer')) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) self.prepareFlagSink(parameters, (inputLineLyrList + inputPolygonLyrList)[0], QgsWkbTypes.Point, context) # Compute the number of steps to display within the progress bar and # get features from source multiStepFeedback = QgsProcessingMultiStepFeedback(2, feedback) multiStepFeedback.setCurrentStep(0) usharedIntersectionSet = layerHandler.getUnsharedVertexOnIntersections( inputLineLyrList, inputPolygonLyrList, onlySelected=onlySelected, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) self.raiseFeaturesFlags(usharedIntersectionSet, multiStepFeedback) return {self.FLAGS: self.flag_id}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() originalLyr = self.parameterAsVectorLayer(parameters, self.ORIGINALLAYER, context) if originalLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.ORIGINALLAYER)) processOutputLyr = self.parameterAsVectorLayer(parameters, self.PROCESSOUTPUTLAYER, context) if processOutputLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.PROCESSOUTPUTLAYER)) controlId = self.parameterAsFields(parameters, self.CONTROLID, context) keepFeatures = self.parameterAsBool(parameters, self.KEEPFEATURES, context) layerHandler.updateOriginalLayer(originalLyr, processOutputLyr, field=str(controlId[0]), feedback=feedback, keepFeatures=keepFeatures) return {self.ORIGINALLAYER: originalLyr}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() 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) 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) # Compute the number of steps to display within the progress bar and # get features from source multiStepFeedback = QgsProcessingMultiStepFeedback(2, feedback) multiStepFeedback.setCurrentStep(0) duplicatedGeomDict = layerHandler.getDuplicatedFeaturesDict( inputLyr, onlySelected=onlySelected, attributeBlackList=attributeBlackList, excludePrimaryKeys=ignorePK, ignoreVirtualFields=ignoreVirtual, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) self.deleteDuplicatedFeaturesFlags(inputLyr, duplicatedGeomDict, multiStepFeedback) return {self.OUTPUT: inputLyr}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) ignoreClosed = self.parameterAsBool(parameters, self.IGNORE_CLOSED, context) fixInput = self.parameterAsBool(parameters, self.TYPE, context) self.prepareFlagSink(parameters, inputLyr, QgsWkbTypes.Point, context) multiStepFeedback = QgsProcessingMultiStepFeedback(2, feedback) multiStepFeedback.setCurrentStep(0) flagDict = layerHandler.identifyAndFixInvalidGeometries( inputLyr=inputLyr, ignoreClosed=ignoreClosed, fixInput=fixInput, onlySelected=onlySelected, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) itemSize = len(flagDict) progressSize = 100 / itemSize if itemSize else 0 for current, (key, outDict) in enumerate(flagDict.items()): if multiStepFeedback.isCanceled(): break self.flagFeature(flagGeom=outDict['geom'], flagText=outDict['reason']) multiStepFeedback.setProgress(current * progressSize) return {self.FLAGS: self.flag_id, self.OUTPUT: inputLyr}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() self.algRunner = AlgRunner() inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context) if inputLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) overlayLyr = self.parameterAsVectorLayer(parameters, self.OVERLAY, context) if overlayLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.OVERLAY)) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) onlySelectedOverlay = self.parameterAsBool(parameters, self.SELECTED_OVERLAY, context) behavior = self.parameterAsEnum(parameters, self.BEHAVIOR, context) multiStepFeedback = QgsProcessingMultiStepFeedback(4, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo(self.tr('Populating temp layer...')) auxLyr = layerHandler.createAndPopulateUnifiedVectorLayer( [inputLyr], geomType=inputLyr.wkbType(), onlySelected=onlySelected, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) if onlySelectedOverlay: overlayLyr = layerHandler.createAndPopulateUnifiedVectorLayer( [overlayLyr], geomType=overlayLyr.wkbType(), onlySelected=onlySelectedOverlay, feedback=multiStepFeedback) overlayLyr.startEditing() overlayLyr.renameAttribute(0, 'fid') overlayLyr.renameAttribute(1, 'cl') overlayLyr.commitChanges() # 1- check method # 2- if overlay and keep, use clip and symetric difference # 3- if remove outside, use clip # 4- if remove inside, use symetric difference multiStepFeedback.setCurrentStep(2) multiStepFeedback.pushInfo(self.tr('Running overlay...')) outputLyr = self.runOverlay(auxLyr, overlayLyr, behavior, context, multiStepFeedback) multiStepFeedback.setCurrentStep(3) multiStepFeedback.pushInfo(self.tr('Updating original layer...')) layerHandler.updateOriginalLayersFromUnifiedLayer( [inputLyr], outputLyr, feedback=multiStepFeedback, onlySelected=onlySelected) return {self.OUTPUT: inputLyr}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() 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 ) tol = self.parameterAsDouble( parameters, self.TOLERANCE, context ) multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo(self.tr('Populating temp layer...')) auxLyr = layerHandler.createAndPopulateUnifiedVectorLayer( [inputLyr], geomType=inputLyr.wkbType(), onlySelected=onlySelected, feedback=multiStepFeedback ) multiStepFeedback.setCurrentStep(1) multiStepFeedback.pushInfo( self.tr( 'Snapping geometries from layer {input} to grid with size {tol}...' ).format(input=inputLyr.name(), tol=tol) ) snappedLayer = algRunner.runSnapToGrid( auxLyr, tol, context, feedback=multiStepFeedback ) multiStepFeedback.setCurrentStep(2) multiStepFeedback.pushInfo(self.tr('Updating original layer...')) layerHandler.updateOriginalLayersFromUnifiedLayer( [inputLyr], snappedLayer, feedback=multiStepFeedback, onlySelected=onlySelected ) return {self.OUTPUT: inputLyr}
def prepareInputLayers(self, inputLayers, stepConversionMap, context=None, feedback=None): """ Prepare layers for a translation unit (step) to be executed (e.g. applies filters). :param inputLayers: (dict) a map from layer name to each vector layer contained by the input datasource. :param stepConversionMap: (dict) conversion map generated by Datasource Conversion tool for a conversion step. :param context: (QgsProcessingContext) environment parameters in which processing tools are used. :param feedback: (QgsProcessingMultiStepFeedback) QGIS tool for progress tracking. :return: (dict) map of layers to have its features mapped to output format. """ lh = LayerHandler() context = context if context is not None else QgsProcessingContext() layerFilters = stepConversionMap["filter"]["layer_filter"] spatialFilters = stepConversionMap["filter"]["spatial_filter"] # in case a selection of layers was made, only chosen layers should be translated inputLayers = inputLayers if layerFilters == {} else { layer: inputLayers[layer] for layer in layerFilters } multiStepFeedback = QgsProcessingMultiStepFeedback( len(inputLayers), feedback) if spatialFilters: # spatial filtering behaviour is set based on the modes defined in convertLayer2LayerAlgorithm behaviour = self.getSpatialFilterBehaviour( spatialFilters["predicate"] if "predicate" in spatialFilters else None) spatialFilterlLayer = self.prepareSpatialFilterLayer( spatialFilters, context) else: behaviour = None spatialFilters = None preparedLayers = dict() currentStep = 0 for layer, vl in inputLayers.items(): if feedback is not None: multiStepFeedback.setCurrentStep(currentStep) if multiStepFeedback.isCanceled(): break currentStep += 1 translatedLayer = lh.prepareConversion( inputLyr=vl, context=context, inputExpression=layerFilters[layer]["expression"] if layer in layerFilters else None, filterLyr=spatialFilterlLayer, behavior=behaviour, conversionMap=stepConversionMap, feedback=multiStepFeedback if feedback is not None else None) if translatedLayer.featureCount() > 0: preparedLayers[layer] = translatedLayer return preparedLayers
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() algRunner = AlgRunner() inputLyrList = self.parameterAsLayerList(parameters, self.INPUTLAYERS, context) if inputLyrList is None or inputLyrList == []: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUTLAYERS)) for layer in inputLyrList: if layer.featureCount() > 0: geomType = next(layer.getFeatures()).geometry().wkbType() break else: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUTLAYERS), self.tr("Provided layers have no features in it.")) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) snap = self.parameterAsDouble(parameters, self.TOLERANCE, context) minArea = self.parameterAsDouble(parameters, self.MINAREA, context) self.prepareFlagSink(parameters, inputLyrList[0], geomType, context) multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo(self.tr('Building unified layer...')) # in order to check the topology of all layers as a whole, all features # are handled as if they formed a single layer coverage = layerHandler.createAndPopulateUnifiedVectorLayer( inputLyrList, geomType=geomType, onlySelected=onlySelected, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) multiStepFeedback.pushInfo( self.tr('Running clean on unified layer...')) cleanedCoverage, error = algRunner.runClean(coverage, [ algRunner.RMSA, algRunner.Break, algRunner.RmDupl, algRunner.RmDangle ], context, returnError=True, snap=snap, minArea=minArea, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(2) multiStepFeedback.pushInfo(self.tr('Updating original layer...')) layerHandler.updateOriginalLayersFromUnifiedLayer( inputLyrList, cleanedCoverage, feedback=multiStepFeedback) self.flagCoverageIssues(cleanedCoverage, error, feedback) return {self.INPUTLAYERS: inputLyrList, self.FLAGS: self.flagSink}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() algRunner = AlgRunner() inputLyrList = self.parameterAsLayerList(parameters, self.INPUTLAYERS, context) if inputLyrList is None or inputLyrList == []: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUTLAYERS)) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) tol = self.parameterAsDouble(parameters, self.TOLERANCE, context) multiStepFeedback = QgsProcessingMultiStepFeedback(5, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo(self.tr('Building unified layer...')) coverage = layerHandler.createAndPopulateUnifiedVectorLayer( inputLyrList, geomType=QgsWkbTypes.MultiPolygon, onlySelected=onlySelected, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) multiStepFeedback.pushInfo( self.tr('Identifying dangles on {layer}...').format( layer=coverage.name())) dangleLyr = algRunner.runIdentifyDangles(coverage, tol, context, feedback=multiStepFeedback, onlySelected=onlySelected) multiStepFeedback.setCurrentStep(2) layerHandler.filterDangles(dangleLyr, tol, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(3) multiStepFeedback.pushInfo( self.tr('Snapping layer {layer} to dangles...').format( layer=coverage.name())) algRunner.runSnapLayerOnLayer(coverage, dangleLyr, tol, context, feedback=multiStepFeedback, onlySelected=onlySelected, behavior=0) multiStepFeedback.setCurrentStep(4) multiStepFeedback.pushInfo(self.tr('Updating original layers...')) layerHandler.updateOriginalLayersFromUnifiedLayer( inputLyrList, coverage, feedback=multiStepFeedback) return {self.INPUTLAYERS: inputLyrList}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() algRunner = AlgRunner() inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) tol = self.parameterAsDouble(parameters, self.MIN_AREA, context) 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) tol = -1 if tol is None else tol nSteps = 4 if tol > 0 else 3 multiStepFeedback = QgsProcessingMultiStepFeedback(nSteps, feedback) currentStep = 0 multiStepFeedback.setCurrentStep(currentStep) multiStepFeedback.pushInfo(self.tr('Populating temp layer...\n')) unifiedLyr = layerHandler.createAndPopulateUnifiedVectorLayer( [inputLyr], geomType=QgsWkbTypes.MultiPolygon, attributeBlackList=attributeBlackList, onlySelected=onlySelected, feedback=multiStepFeedback) currentStep += 1 if tol > 0: multiStepFeedback.setCurrentStep(currentStep) multiStepFeedback.pushInfo( self.tr('Adding size constraint field...\n')) unifiedLyr = layerHandler.addDissolveField( unifiedLyr, tol, feedback=multiStepFeedback) currentStep += 1 multiStepFeedback.setCurrentStep(currentStep) multiStepFeedback.pushInfo(self.tr('Running dissolve...\n')) dissolvedLyr = algRunner.runDissolve(unifiedLyr, context, feedback=multiStepFeedback, field=['tupple']) layerHandler.updateOriginalLayersFromUnifiedLayer( [inputLyr], dissolvedLyr, feedback=multiStepFeedback, onlySelected=onlySelected) return {self.OUTPUT: inputLyr}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() algRunner = AlgRunner() inputLyrList = self.parameterAsLayerList(parameters, self.INPUTLAYERS, context) if inputLyrList is None or inputLyrList == []: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUTLAYERS)) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) snap = self.parameterAsDouble(parameters, self.SNAP, context) threshold = self.parameterAsDouble(parameters, self.DOUGLASPARAMETER, context) minArea = self.parameterAsDouble(parameters, self.MINAREA, context) self.prepareFlagSink(parameters, inputLyrList[0], QgsWkbTypes.MultiPolygon, context) multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo(self.tr('Building unified layer...')) coverage = layerHandler.createAndPopulateUnifiedVectorLayer( inputLyrList, geomType=QgsWkbTypes.MultiPolygon, onlySelected=onlySelected, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) multiStepFeedback.pushInfo( self.tr('Running clean on unified layer...')) simplifiedCoverage, error = algRunner.runDouglasSimplification( coverage, threshold, context, returnError=True, snap=snap, minArea=minArea, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(2) multiStepFeedback.pushInfo(self.tr('Updating original layer...')) layerHandler.updateOriginalLayersFromUnifiedLayer( inputLyrList, simplifiedCoverage, feedback=multiStepFeedback, onlySelected=onlySelected) self.flagCoverageIssues(simplifiedCoverage, error, feedback) return {self.INPUTLAYERS: inputLyrList, self.FLAGS: self.flag_id}
def setAttributeMap(self, attrMap): """ Sets the attribute value map for current button to GUI. :param attrMap: (dict) a map from each field and its value to be set. """ self.updateFieldTable() table = self.attributeTableWidget vl = self.vectorLayer() valueMaps = dict() # displayed values are always "aliased" when possible, so map needs to # be reversed (e.g. set to actual value to display name) if vl is not None: for fName, vMap in LayerHandler().valueMaps(vl).items(): valueMaps[fName] = {v: k for k, v in vMap.items()} def setMappedValue(cb, field, value): if value is None: return if not (value in valueMaps[field]): msg = self.tr("'{0}' is an invalid value for field {1}. (Is " "the layer style generated from the current data" " model?")\ .format(value, field) title = self.tr("DSGTools Custom Feature Tool Box") MessageRaiser().raiseIfaceMessage(title, msg, Qgis.Warning, 5) value = None cb.setCurrentText(valueMaps[field][value]) pkIdxList = vl.primaryKeyAttributes() if vl else [] for row in range(table.rowCount()): attr = table.cellWidget(row, self.ATTR_COL).text().replace("&", "") valueWidget = table.cellWidget(row, self.VAL_COL) isPk = row in pkIdxList if not attrMap or attr not in attrMap: attrMap[attr] = { "value": None, "editable": False, "ignored": isPk, # default is False unless it's a PK attr "isPk": isPk } { QWidget: lambda v: valueWidget.cb.setChecked(v or False), QLineEdit: lambda v: valueWidget.setText(v or ""), QSpinBox: lambda v: valueWidget.setValue(v or 0), QDoubleSpinBox: lambda v: valueWidget.setValue(v or 0.0), QComboBox: lambda v: setMappedValue(valueWidget, attr, v) }[type(valueWidget)](attrMap[attr]["value"]) valueWidget.setEnabled(not attrMap[attr]["ignored"]) table.cellWidget(row, self.EDIT_COL).cb.setChecked( attrMap[attr]["editable"]) table.cellWidget(row, self.IGNORED_COL).cb.setChecked( attrMap[attr]["ignored"]) table.setCellWidget(row, self.PK_COL, self.pkWidget() if isPk else QWidget())
def processAlgorithm(self, parameters, context, feedback): """ Method that triggers the data processing algorithm. :param parameters: (dict) mapping from algorithms input's name to its value. :param context: (QgsProcessingContext) execution's environmental info. :param feedback: (QgsProcessingFeedback) QGIS object to keep track of algorithm's progress/status. :return: (dict) output mapping for identified flags. """ layers, selected, silent, ratio = self.getParameters( parameters, context, feedback) if not layers: raise QgsProcessingException(self.tr("No layers were provided.")) for layer in layers: if layer.featureCount() > 0: geomType = next(layer.getFeatures()).geometry().wkbType() break else: raise QgsProcessingException(self.tr("All layers are empty.")) self.prepareFlagSink(parameters, layers[0], geomType, context) flags = dict() lh = LayerHandler() flagCount = 0 # a step for each input + 1 for loading flags into sink multiStepFeedback = QgsProcessingMultiStepFeedback( len(layers) + 1, feedback) multiStepFeedback.setCurrentStep(0) for step, layer in enumerate(layers): if multiStepFeedback.isCanceled(): break # running polygon slivers to purposely raise an exception if an # empty geometry is found multiStepFeedback.pushInfo( self.tr("Checking {0}...").format(layer.name())) slivers = lh.getPolygonSlivers(layer, ratio, selected, silent, multiStepFeedback) if slivers: # pushWarnign is only avalailable on 3.16.2+ # multiStepFeedback.pushWarning( multiStepFeedback.pushDebugInfo( self.tr("{0} slivers were found on {1}!")\ .format(len(slivers), layer.name()) ) flags[layer] = slivers flagCount += len(slivers) multiStepFeedback.setCurrentStep(step + 1) self.tr("Populating flags layer...") self.flagPolygonSlivers(flags, flagCount, multiStepFeedback) multiStepFeedback.setCurrentStep(step + 2) return {self.FLAGS: self.flag_id}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ geometryHandler = GeometryHandler() layerHandler = LayerHandler() inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context) if inputLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) isMulti = QgsWkbTypes.isMultiType(int(inputLyr.wkbType())) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) self.prepareFlagSink(parameters, inputLyr, QgsWkbTypes.Polygon, context) # Compute the number of steps to display within the progress bar and # get features from source multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback) multiStepFeedback.setCurrentStep(0) lyr = self.overlayCoverage(inputLyr, context, multiStepFeedback) featureList, total = self.getIteratorAndFeatureCount( lyr ) #only selected is not applied because we are using an inner layer, not the original ones QgsProject.instance().removeMapLayer(lyr) geomDict = dict() multiStepFeedback.setCurrentStep(1) for current, feat in enumerate(featureList): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break geom = feat.geometry() if isMulti and not geom.isMultipart(): geom.convertToMultiType() geomKey = geom.asWkb() if geomKey not in geomDict: geomDict[geomKey] = [] geomDict[geomKey].append(feat) # # Update the progress bar multiStepFeedback.setProgress(current * total) multiStepFeedback.setCurrentStep(2) total = 100 / len(geomDict) if len(geomDict) != 0 else 0 for k, v in geomDict.items(): if feedback.isCanceled(): break if len(v) > 1: flagText = self.tr('Features from {0} overlap.').format( inputLyr.name()) self.flagFeature(v[0].geometry(), flagText) multiStepFeedback.setProgress(current * total) return {self.FLAGS: self.flag_id}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() algRunner = AlgRunner() inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) tol = self.parameterAsDouble(parameters, self.TOLERANCE, context) multiStepFeedback = QgsProcessingMultiStepFeedback(4, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo( self.tr('Identifying dangles on {layer}...').format( layer=inputLyr.name())) dangleLyr = algRunner.runIdentifyDangles(inputLyr, tol, context, feedback=multiStepFeedback, onlySelected=onlySelected) multiStepFeedback.setCurrentStep(1) layerHandler.filterDangles(dangleLyr, tol, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(2) multiStepFeedback.pushInfo( self.tr('Snapping layer {layer} to dangles...').format( layer=inputLyr.name())) algRunner.runSnapLayerOnLayer(inputLyr, dangleLyr, tol, context, feedback=multiStepFeedback, onlySelected=onlySelected) multiStepFeedback.setCurrentStep(3) multiStepFeedback.pushInfo( self.tr('Cleanning layer {layer}...').format( layer=inputLyr.name())) algRunner.runDsgToolsClean(inputLyr, context, snap=tol, feedback=multiStepFeedback, onlySelected=onlySelected) return {self.OUTPUT: inputLyr}
def mapFeatures(self, inputPreparedLayers, outputLayers, featureConversionMap=None, feedback=None): """ Maps features from a given set of layers to a different set of layers (including attributes). :param inputPreparedLayers: (dict) map of layers to be translated. :param outputLayers: (dict) map of layers to be filled. :param featureConversionMap: (dict) map of features based on given input. :param feedback: (QgsProcessingMultiStepFeedback) QGIS tool for progress tracking. :return: (dict) map of (list-of-QgsFeature) features to be added to a (str) layer. """ if featureConversionMap is not None: # do the conversion in here using the map - NOT YET SUPPORTED pass else: featuresMap = collections.defaultdict(set) lh = LayerHandler() fh = FeatureHandler() if feedback is not None: stepSize = 100 / len(inputPreparedLayers) if len( inputPreparedLayers) else 0 for current, (layer, vl) in enumerate(inputPreparedLayers.items()): if feedback is not None and feedback.isCanceled(): break if vl.featureCount() == 0 or layer not in outputLayers: continue outuputLayer = outputLayers[layer] k = "{0}->{1}".format(vl.crs().authid(), outuputLayer.crs().authid()) if k not in self.coordinateTransformers: self.coordinateTransformers[ k] = lh.getCoordinateTransformer( inputLyr=vl, outputLyr=outuputLayer) coordinateTransformer = self.coordinateTransformers[k] param = lh.getDestinationParameters(vl) for feature in vl.getFeatures(QgsFeatureRequest()): featuresMap[layer] |= fh.handleConvertedFeature( feat=feature, lyr=outuputLayer, parameterDict=param, coordinateTransformer=coordinateTransformer) if feedback is not None: feedback.setProgress(current * stepSize) return featuresMap
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() 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) snap = self.parameterAsDouble(parameters, self.TOLERANCE, context) # if snap < 0 and snap != -1: # raise QgsProcessingException(self.invalidParameterError(parameters, self.TOLERANCE)) minArea = self.parameterAsDouble(parameters, self.MINAREA, context) self.prepareFlagSink(parameters, inputLyr, inputLyr.wkbType(), context) multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback) multiStepFeedback.setCurrentStep(0) multiStepFeedback.pushInfo(self.tr('Populating temp layer...')) auxLyr = layerHandler.createAndPopulateUnifiedVectorLayer( [inputLyr], geomType=inputLyr.wkbType(), onlySelected=onlySelected, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(1) multiStepFeedback.pushInfo(self.tr('Running clean...')) cleanedLyr, error = algRunner.runClean(auxLyr, \ [algRunner.RMSA, algRunner.Break, algRunner.RmDupl, algRunner.RmDangle], \ context, \ returnError=True, \ snap=snap, \ minArea=minArea, feedback=multiStepFeedback) multiStepFeedback.setCurrentStep(2) multiStepFeedback.pushInfo(self.tr('Updating original layer...')) layerHandler.updateOriginalLayersFromUnifiedLayer( [inputLyr], cleanedLyr, feedback=multiStepFeedback, onlySelected=onlySelected) self.flagIssues(cleanedLyr, error, feedback) return {self.OUTPUT: inputLyr, self.FLAGS: self.flag_id}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ source = self.parameterAsSource(parameters, self.INPUT, context) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) target = self.parameterAsVectorLayer(parameters, self.INPUT, context) target.startEditing() target.beginEditCommand('Updating layer') fields = target.fields() paramDict = LayerHandler().getDestinationParameters(target) featHandler = FeatureHandler() featuresToAdd = [] if onlySelected: total = 100.0 / target.selectedFeatureCount() if target.selectedFeatureCount() else 0 features = target.getSelectedFeatures() else: total = 100.0 / target.featureCount() if target.featureCount() else 0 features = target.getFeatures() for current, feature in enumerate(features): if feedback.isCanceled(): break if not feature.geometry(): target.deleteFeature(feature.id()) feedback.setProgress(int(current * total)) continue updtGeom, newFeatList, update = featHandler.handleFeature([feature], feature, target, paramDict) if not update: feature.setGeometry(updtGeom) target.updateFeature(feature) featuresToAdd += newFeatList feedback.setProgress(int(current * total)) if featuresToAdd: target.addFeatures(featuresToAdd, QgsFeatureSink.FastInsert) target.endEditCommand() # Return the results of the algorithm. In this case our only result is # the feature sink which contains the processed features, but some # algorithms may return multiple feature sinks, calculated numeric # statistics, etc. These should all be included in the returned # dictionary, with keys matching the feature corresponding parameter # or output names. return {self.OUTPUT: target}
def prepareSpatialFilterLayer(self, spatialFilters, context=None): """ Prepares layer used as reference for spatially filtering a dataset. :param spatialFilters: (dict) spatial filter's parameters. :param context: (QgsProcessingContext) environment parameters in which processing tools are used. :return: (QgsVectorLayer) reference layer as requested in the spatial filters. """ # layer always comes from canvas spatialFilterlLayer = QgsProject.instance().mapLayersByName( spatialFilters["layer"]) spatialFilterlLayer = spatialFilterlLayer[ 0] if spatialFilterlLayer != [] else None if spatialFilters["expression"]: context = context if context is not None else QgsProcessingContext( ) spatialFilterlLayer = LayerHandler().filterByExpression(layer=spatialFilterlLayer,\ expression=spatialFilters["expression"],\ context=context) return spatialFilterlLayer
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() algRunner = AlgRunner() inputCenterPointLyr = self.parameterAsVectorLayer( parameters, self.INPUT_CENTER_POINTS, context) if inputCenterPointLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT_CENTER_POINTS)) constraintLineLyrList = self.parameterAsLayerList( parameters, self.CONSTRAINT_LINE_LAYERS, context) constraintPolygonLyrList = self.parameterAsLayerList( parameters, self.CONSTRAINT_POLYGON_LAYERS, context) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) geographicBoundaryLyr = self.parameterAsLayer(parameters, self.GEOGRAPHIC_BOUNDARY, context) (output_polygon_sink, output_polygon_sink_id) = self.parameterAsSink( parameters, self.OUTPUT_POLYGONS, context, inputCenterPointLyr.fields(), QgsWkbTypes.Polygon, inputCenterPointLyr.sourceCrs()) self.prepareFlagSink(parameters, inputCenterPointLyr, QgsWkbTypes.Polygon, context) polygonFeatList, flagDict = layerHandler.getPolygonsFromCenterPointsAndBoundaries( inputCenterPointLyr, geographicBoundaryLyr=geographicBoundaryLyr, constraintLineLyrList=constraintLineLyrList, constraintPolygonLyrList=constraintPolygonLyrList, onlySelected=onlySelected, context=context, feedback=feedback, algRunner=algRunner) output_polygon_sink.addFeatures(polygonFeatList, QgsFeatureSink.FastInsert) for flagGeom, flagText in flagDict.items(): self.flagFeature(flagGeom, flagText, fromWkb=True) return { self.OUTPUT_POLYGONS: output_polygon_sink_id, self.FLAGS: self.flag_id }
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ geometryHandler = GeometryHandler() layerHandler = LayerHandler() inputLyrList = self.parameterAsLayerList(parameters, self.INPUTLAYERS, context) if inputLyrList == []: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUTLAYERS)) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) tol = self.parameterAsDouble(parameters, self.TOLERANCE, context) self.prepareFlagSink(parameters, inputLyrList[0], QgsWkbTypes.Point, context) for lyr in inputLyrList: if feedback.isCanceled(): break self.runIdentifyOutOfBoundsAngles(lyr, onlySelected, tol, context) epsg = inputLyrList[0].crs().authid().split(':')[-1] coverage = layerHandler.createAndPopulateUnifiedVectorLayer( inputLyrList, QgsWkbTypes.Point, epsg, onlySelected=onlySelected) cleanedCoverage = self.cleanCoverage(coverage, context) segmentDict = geometryHandler.getSegmentDict(cleanedCoverage) # Compute the number of steps to display within the progress bar and # get features from source # featureList, total = self.getIteratorAndFeatureCount(inputLyr) # for current, feat in enumerate(featureList): # # Stop the algorithm if cancel button has been clicked # if feedback.isCanceled(): # break # outOfBoundsList = geometryHandler.getOutOfBoundsAngle(feat, tol) # if outOfBoundsList: # for item in outOfBoundsList: # flagText = self.tr('Feature from layer {0} with id={1} has angle of value {2} degrees, which is lesser than the tolerance of {3} degrees.').format(inputLyr.name(), item['feat_id'], item['angle'], tol) # self.flagFeature(item['geom'], flagText) # # Update the progress bar # feedback.setProgress(int(current * total)) return {self.FLAGS: self.flag_id}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ geometryHandler = GeometryHandler() layerHandler = LayerHandler() inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context) if inputLyr is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) isMulti = QgsWkbTypes.isMultiType(int(inputLyr.wkbType())) onlySelected = self.parameterAsBool(parameters, self.SELECTED, context) self.prepareFlagSink(parameters, inputLyr, QgsWkbTypes.Polygon, context) # Compute the number of steps to display within the progress bar and # get features from source multiStepFeedback = QgsProcessingMultiStepFeedback(4, feedback) lyr = self.getGapLyr(inputLyr, context, multiStepFeedback, onlySelected=onlySelected) featureList, total = self.getIteratorAndFeatureCount( lyr ) #only selected is not applied because we are using an inner layer, not the original ones QgsProject.instance().removeMapLayer(lyr) geomDict = dict() multiStepFeedback.setCurrentStep(3) for current, feat in enumerate(featureList): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break attrList = feat.attributes() if attrList == len(attrList) * [None]: geom = feat.geometry() self.flagFeature( geom, self.tr('Gap in layer {0}.').format(inputLyr.name())) # # Update the progress bar multiStepFeedback.setProgress(current * total) return {self.FLAGS: self.flag_id}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ layerHandler = LayerHandler() inputLyr = self.parameterAsVectorLayer( parameters, self.INPUT, context ) onlySelected = self.parameterAsBool( parameters, self.SELECTED, context ) 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 ) layerHandler.mergeLinesOnLayer( inputLyr, feedback=feedback, onlySelected=onlySelected, ignoreVirtualFields=ignoreVirtual, attributeBlackList=attributeBlackList, excludePrimaryKeys=ignorePK ) return {self.OUTPUT: inputLyr}