def __init__(self, name='', description='', options=[], default=None, isSource=False, optional=False): Parameter.__init__(self, name, description, default, optional) isSource = parseBool(isSource) self.options = options if isSource: self.options = [] layer = QgsVectorLayer(options[0], "layer", "ogr") if layer.isValid(): try: index = resolveFieldIndex(layer, options[1]) feats = features(layer) for feature in feats: self.options.append(unicode(feature.attributes()[index])) except ValueError: pass elif isinstance(self.options, basestring): self.options = self.options.split(";") if default is not None: try: self.default = int(default) except: self.default = 0 self.value = self.default
def __init__(self, name='', description='', options=[], default=None, isSource=False, multiple=False, optional=False): Parameter.__init__(self, name, description, default, optional) self.multiple = multiple isSource = parseBool(isSource) self.options = options if isSource: self.options = [] layer = QgsVectorLayer(options[0], "layer", "ogr") if layer.isValid(): try: index = resolveFieldIndex(layer, options[1]) feats = QgsProcessingUtils.getFeatures(layer, dataobjects.createContext()) for feature in feats: self.options.append(str(feature.attributes()[index])) except ValueError: pass elif isinstance(self.options, str): self.options = self.options.split(";") # compute options as (value, text) options = [] for i, option in enumerate(self.options): if option is None or isinstance(option, basestring): options.append((i, option)) else: options.append((option[0], option[1])) self.options = options self.values = [option[0] for option in options] self.value = None
def processAlgorithm(self, feedback): inLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) boundary = self.getParameterValue(self.MODE) == self.MODE_BOUNDARY smallestArea = self.getParameterValue( self.MODE) == self.MODE_SMALLEST_AREA keepSelection = self.getParameterValue(self.KEEPSELECTION) processLayer = vector.duplicateInMemory(inLayer) if not keepSelection: # Make a selection with the values provided attribute = self.getParameterValue(self.ATTRIBUTE) comparison = self.comparisons[self.getParameterValue( self.COMPARISON)] comparisonvalue = self.getParameterValue(self.COMPARISONVALUE) selectindex = vector.resolveFieldIndex(processLayer, attribute) selectType = processLayer.fields()[selectindex].type() selectionError = False if selectType in [ QVariant.Int, QVariant.LongLong, QVariant.UInt, QVariant.ULongLong ]: try: y = int(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to integer' % str(comparisonvalue)) elif selectType == QVariant.Double: try: y = float(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to float' % str(comparisonvalue)) elif selectType == QVariant.String: # 10: string, boolean try: y = str(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to Unicode' % str(comparisonvalue)) elif selectType == QVariant.Date: # date dateAndFormat = comparisonvalue.split(' ') if len(dateAndFormat) == 1: # QDate object y = QLocale.system().toDate(dateAndFormat[0]) if y.isNull(): msg = self.tr( 'Cannot convert "%s" to date with system date format %s' % (str(dateAndFormat), QLocale.system().dateFormat())) elif len(dateAndFormat) == 2: y = QDate.fromString(dateAndFormat[0], dateAndFormat[1]) if y.isNull(): msg = self.tr( 'Cannot convert "%s" to date with format string "%s"' % (str(dateAndFormat[0]), dateAndFormat[1])) else: y = QDate() msg = '' if y.isNull(): # Conversion was unsuccessful selectionError = True msg += self.tr( 'Enter the date and the date format, e.g. "07.26.2011" "MM.dd.yyyy".' ) if (comparison == 'begins with' or comparison == 'contains') \ and selectType != QVariant.String: selectionError = True msg = self.tr('"%s" can only be used with string fields' % comparison) selected = [] if selectionError: raise GeoAlgorithmExecutionException( self.tr('Error in selection input: %s' % msg)) else: for feature in processLayer.getFeatures(): aValue = feature.attributes()[selectindex] if aValue is None: continue if selectType in [ QVariant.Int, QVariant.LongLong, QVariant.UInt, QVariant.ULongLong ]: x = int(aValue) elif selectType == QVariant.Double: x = float(aValue) elif selectType == QVariant.String: # 10: string, boolean x = str(aValue) elif selectType == QVariant.Date: # date x = aValue # should be date match = False if comparison == '==': match = x == y elif comparison == '!=': match = x != y elif comparison == '>': match = x > y elif comparison == '>=': match = x >= y elif comparison == '<': match = x < y elif comparison == '<=': match = x <= y elif comparison == 'begins with': match = x.startswith(y) elif comparison == 'contains': match = x.find(y) >= 0 if match: selected.append(feature.id()) processLayer.selectByIds(selected) if processLayer.selectedFeatureCount() == 0: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self.tr('%s: (No selection in input layer "%s")' % (self.commandLineName(), self.getParameterValue(self.INPUT)))) # Keep references to the features to eliminate featToEliminate = [] for aFeat in processLayer.selectedFeatures(): featToEliminate.append(aFeat) # Delete all features to eliminate in processLayer (we won't save this) processLayer.startEditing() processLayer.deleteSelectedFeatures() # ANALYZE if len(featToEliminate) > 0: # Prevent zero division start = 20.00 add = 80.00 / len(featToEliminate) else: start = 100 feedback.setProgress(start) madeProgress = True # We go through the list and see if we find any polygons we can # merge the selected with. If we have no success with some we # merge and then restart the whole story. while madeProgress: # Check if we made any progress madeProgress = False featNotEliminated = [] # Iterate over the polygons to eliminate for i in range(len(featToEliminate)): feat = featToEliminate.pop() geom2Eliminate = feat.geometry() bbox = geom2Eliminate.boundingBox() fit = processLayer.getFeatures( QgsFeatureRequest().setFilterRect( bbox).setSubsetOfAttributes([])) mergeWithFid = None mergeWithGeom = None max = 0 min = -1 selFeat = QgsFeature() # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine( geom2Eliminate.geometry()) engine.prepareGeometry() while fit.nextFeature(selFeat): selGeom = selFeat.geometry() if engine.intersects(selGeom.geometry()): # We have a candidate iGeom = geom2Eliminate.intersection(selGeom) if not iGeom: continue if boundary: selValue = iGeom.length() else: # area. We need a common boundary in # order to merge if 0 < iGeom.length(): selValue = selGeom.area() else: selValue = -1 if -1 != selValue: useThis = True if smallestArea: if -1 == min: min = selValue else: if selValue < min: min = selValue else: useThis = False else: if selValue > max: max = selValue else: useThis = False if useThis: mergeWithFid = selFeat.id() mergeWithGeom = QgsGeometry(selGeom) # End while fit if mergeWithFid is not None: # A successful candidate newGeom = mergeWithGeom.combine(geom2Eliminate) if processLayer.changeGeometry(mergeWithFid, newGeom): madeProgress = True else: raise GeoAlgorithmExecutionException( self. tr('Could not replace geometry of feature with id %s' % mergeWithFid)) start = start + add feedback.setProgress(start) else: featNotEliminated.append(feat) # End for featToEliminate featToEliminate = featNotEliminated # End while # Create output output = self.getOutputFromName(self.OUTPUT) writer = output.getVectorWriter(processLayer.fields(), processLayer.wkbType(), processLayer.crs()) # Write all features that are left over to output layer iterator = processLayer.getFeatures() for feature in iterator: writer.addFeature(feature) # Leave processLayer untouched processLayer.rollBack() for feature in featNotEliminated: writer.addFeature(feature)
def processAlgorithm(self, feedback): inLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT)) boundary = self.getParameterValue(self.MODE) == self.MODE_BOUNDARY smallestArea = self.getParameterValue(self.MODE) == self.MODE_SMALLEST_AREA keepSelection = self.getParameterValue(self.KEEPSELECTION) processLayer = vector.duplicateInMemory(inLayer) if not keepSelection: # Make a selection with the values provided attribute = self.getParameterValue(self.ATTRIBUTE) comparison = self.comparisons[self.getParameterValue(self.COMPARISON)] comparisonvalue = self.getParameterValue(self.COMPARISONVALUE) selectindex = vector.resolveFieldIndex(processLayer, attribute) selectType = processLayer.fields()[selectindex].type() selectionError = False if selectType in [QVariant.Int, QVariant.LongLong, QVariant.UInt, QVariant.ULongLong]: try: y = int(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to integer' % str(comparisonvalue)) elif selectType == QVariant.Double: try: y = float(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to float' % str(comparisonvalue)) elif selectType == QVariant.String: # 10: string, boolean try: y = str(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to Unicode' % str(comparisonvalue)) elif selectType == QVariant.Date: # date dateAndFormat = comparisonvalue.split(' ') if len(dateAndFormat) == 1: # QDate object y = QLocale.system().toDate(dateAndFormat[0]) if y.isNull(): msg = self.tr('Cannot convert "%s" to date with system date format %s' % (str(dateAndFormat), QLocale.system().dateFormat())) elif len(dateAndFormat) == 2: y = QDate.fromString(dateAndFormat[0], dateAndFormat[1]) if y.isNull(): msg = self.tr('Cannot convert "%s" to date with format string "%s"' % (str(dateAndFormat[0]), dateAndFormat[1])) else: y = QDate() msg = '' if y.isNull(): # Conversion was unsuccessful selectionError = True msg += self.tr('Enter the date and the date format, e.g. "07.26.2011" "MM.dd.yyyy".') if (comparison == 'begins with' or comparison == 'contains') \ and selectType != QVariant.String: selectionError = True msg = self.tr('"%s" can only be used with string fields' % comparison) selected = [] if selectionError: raise GeoAlgorithmExecutionException( self.tr('Error in selection input: %s' % msg)) else: for feature in processLayer.getFeatures(): aValue = feature.attributes()[selectindex] if aValue is None: continue if selectType in [QVariant.Int, QVariant.LongLong, QVariant.UInt, QVariant.ULongLong]: x = int(aValue) elif selectType == QVariant.Double: x = float(aValue) elif selectType == QVariant.String: # 10: string, boolean x = str(aValue) elif selectType == QVariant.Date: # date x = aValue # should be date match = False if comparison == '==': match = x == y elif comparison == '!=': match = x != y elif comparison == '>': match = x > y elif comparison == '>=': match = x >= y elif comparison == '<': match = x < y elif comparison == '<=': match = x <= y elif comparison == 'begins with': match = x.startswith(y) elif comparison == 'contains': match = x.find(y) >= 0 if match: selected.append(feature.id()) processLayer.selectByIds(selected) if processLayer.selectedFeatureCount() == 0: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, self.tr('%s: (No selection in input layer "%s")' % (self.commandLineName(), self.getParameterValue(self.INPUT)))) # Keep references to the features to eliminate featToEliminate = [] for aFeat in processLayer.selectedFeatures(): featToEliminate.append(aFeat) # Delete all features to eliminate in processLayer (we won't save this) processLayer.startEditing() processLayer.deleteSelectedFeatures() # ANALYZE if len(featToEliminate) > 0: # Prevent zero division start = 20.00 add = 80.00 / len(featToEliminate) else: start = 100 feedback.setProgress(start) madeProgress = True # We go through the list and see if we find any polygons we can # merge the selected with. If we have no success with some we # merge and then restart the whole story. while madeProgress: # Check if we made any progress madeProgress = False featNotEliminated = [] # Iterate over the polygons to eliminate for i in range(len(featToEliminate)): feat = featToEliminate.pop() geom2Eliminate = feat.geometry() bbox = geom2Eliminate.boundingBox() fit = processLayer.getFeatures( QgsFeatureRequest().setFilterRect(bbox).setSubsetOfAttributes([])) mergeWithFid = None mergeWithGeom = None max = 0 min = -1 selFeat = QgsFeature() # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(geom2Eliminate.geometry()) engine.prepareGeometry() while fit.nextFeature(selFeat): selGeom = selFeat.geometry() if engine.intersects(selGeom.geometry()): # We have a candidate iGeom = geom2Eliminate.intersection(selGeom) if not iGeom: continue if boundary: selValue = iGeom.length() else: # area. We need a common boundary in # order to merge if 0 < iGeom.length(): selValue = selGeom.area() else: selValue = -1 if -1 != selValue: useThis = True if smallestArea: if -1 == min: min = selValue else: if selValue < min: min = selValue else: useThis = False else: if selValue > max: max = selValue else: useThis = False if useThis: mergeWithFid = selFeat.id() mergeWithGeom = QgsGeometry(selGeom) # End while fit if mergeWithFid is not None: # A successful candidate newGeom = mergeWithGeom.combine(geom2Eliminate) if processLayer.changeGeometry(mergeWithFid, newGeom): madeProgress = True else: raise GeoAlgorithmExecutionException( self.tr('Could not replace geometry of feature with id %s' % mergeWithFid)) start = start + add feedback.setProgress(start) else: featNotEliminated.append(feat) # End for featToEliminate featToEliminate = featNotEliminated # End while # Create output output = self.getOutputFromName(self.OUTPUT) writer = output.getVectorWriter(processLayer.fields(), processLayer.wkbType(), processLayer.crs()) # Write all features that are left over to output layer iterator = processLayer.getFeatures() for feature in iterator: writer.addFeature(feature) # Leave processLayer untouched processLayer.rollBack() for feature in featNotEliminated: writer.addFeature(feature)
def processAlgorithm(self, progress): # Retrieve the values of the parameters entered by the user sourceLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.SOURCE_LAYER)) sourceField = self.getParameterValue(self.SOURCE_FIELD) targetLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.TARGET_LAYER)) targetField = self.getParameterValue(self.TARGET_FIELD) # check for tdg_id fields in source and target progress.setPercentage(0) progress.setInfo('Checking for tdg_id fields') exists = False try: vector.resolveFieldIndex(sourceLayer,'tdg_id') exists = True except: pass if not exists: raise GeoAlgorithmExecutionException('No tdg_id field was found in \ layer %s' % sourceLayer.name()) exists = False try: vector.resolveFieldIndex(targetLayer,'tdg_id') exists = True except: pass if not exists: raise GeoAlgorithmExecutionException('No tdg_id field was found in \ layer %s' % targetLayer.name()) progress.setPercentage(2) # build dict of source data progress.setInfo('Reading source values') count = 0 totalCount = len(vector.features(sourceLayer)) sourceValues = {} for feat in vector.features(sourceLayer): count += 1 progress.setPercentage(2 + 28*count/totalCount) tdgId = feat['tdg_id'] copyAttr = feat[sourceField] if tdgId is None: continue sourceValues[tdgId] = copyAttr # start editing targetLayer.startEditing() # iterate target features and assign matching source value progress.setInfo('Copying to target features') count = 0 totalCount = len(vector.features(targetLayer)) for targetFeat in vector.features(targetLayer): count += 1 progress.setPercentage(30 + 68*count/totalCount) tdgId = targetFeat['tdg_id'] if tdgId is None: continue if tdgId in sourceValues: fieldIndex = vector.resolveFieldIndex(targetLayer,targetField) sourceVal = sourceValues.get(tdgId) targetFeat.setAttribute(fieldIndex,sourceVal) targetLayer.updateFeature(targetFeat) progress.setInfo('Editing has been left active for layer %s.' % targetLayer.name()) progress.setInfo('Please finalize this operation by checking values, saving your edits, and closing the edit session.')
def __init__(self, input_network, input_points, # must be qgsvectorlayer (either form disc or built from coord) input_directionFieldName=None, input_directDirectionValue=None, input_reverseDirectionValue=None, input_bothDirectionValue=None, input_defaultDirection=None): logPanel("__init__[QneatBaseCalculator]: setting up parameters") logPanel("__init__[QneatBaseCalculator]: setting up datasets") #init datasets and check for right geometry if isGeometryType(input_network, QGis.Line): self.input_network = input_network else: logPanel("ERROR: Network layer should be dataset layer") raise QneatGeometryException(input_network.geometryType(), QGis.Line) if isGeometryType(input_points, QGis.Point): self.input_points = input_points else: logPanel("ERROR: Point layer should be point dataset") raise QneatGeometryException(input_points.geometryType(), QGis.Point) #init computabiliyt and crs logPanel("__init__[QneatBaseCalculator]: checking computability") self.ComputabilityStatus = self.checkComputabilityStatus() if self.ComputabilityStatus == True: logPanel("__init__[QneatBaseCalculator]: computability OK") logPanel("__init__[QneatBaseCalculator]: setting up network analysis parameters") self.AnalysisCrs = self.setAnalysisCrs() #init direction fields self.directedAnalysis = self.checkIfDirected((input_directDirectionValue, input_reverseDirectionValue, input_bothDirectionValue, input_defaultDirection)) if self.directedAnalysis == True: logPanel("...Analysis is directed") logPanel("...setting up Director") self.director = QgsLineVectorLayerDirector(self.input_network, resolveFieldIndex(self.input_network, input_directionFieldName), input_directDirectionValue, input_reverseDirectionValue, input_bothDirectionValue, input_defaultDirection) else: logPanel("...Analysis is undirected") logPanel("...defaulting to normal director") self.director = QgsLineVectorLayerDirector(self.input_network, -1, '', '', '', 3) #init graph analysis logPanel("__init__[QneatBaseCalculator]: setting up network analysis") logPanel("...getting all analysis points") self.list_input_points = self.input_points.getFeatures(QgsFeatureRequest().setFilterFids(self.input_points.allFeatureIds())) #Use distance as cost-strategy pattern. logPanel("...Setting distance as cost property") self.properter = QgsDistanceArcProperter() #add the properter to the QgsGraphDirector self.director.addProperter(self.properter) logPanel("...Setting the graph builders spatial reference") self.builder = QgsGraphBuilder(self.AnalysisCrs) #tell the graph-director to make the graph using the builder object and tie the start point geometry to the graph logPanel("...Tying input_points to the graph") self.list_tiedPoints = self.director.makeGraph(self.builder, getListOfPoints(self.input_points)) #get the graph logPanel("...Build the graph") self.network = self.builder.graph() logPanel("__init__[QneatBaseCalculator]: init complete")
def processAlgorithm(self, progress): # Retrieve the values of the parameters entered by the user targetLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.TARGET_LAYER)) targetFieldName = self.getParameterValue(self.TARGET_IDS) sourceLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.SOURCE_LAYER)) sourceFieldName = self.getParameterValue(self.SOURCE_IDS) tolerance = self.getParameterValue(self.TOLERANCE) method = self.METHODS[self.getParameterValue(self.METHOD)] keepNulls = self.getParameterValue(self.KEEP_NULLS) # get input field types and set output fields targetField = targetLayer.dataProvider().fields().at(vector.resolveFieldIndex(targetLayer, targetFieldName)) sourceField = sourceLayer.dataProvider().fields().at(vector.resolveFieldIndex(sourceLayer, sourceFieldName)) fields = QgsFields() fields.append(QgsField("target_id", targetField.type())) fields.append(QgsField("source_id", sourceField.type())) # set up output writer writer = self.getOutputFromName(self.OUT_LAYER).getVectorWriter(fields, QGis.WKBLineString, targetLayer.crs()) # create spatial index for source features progress.setInfo("Indexing source features") index = vector.spatialindex(sourceLayer) # build dictionary of source features sourceFeatures = {} for sourceFeat in vector.features(sourceLayer): sourceFeatures[sourceFeat.id()] = sourceFeat # loop through target features progress.setInfo("Checking target features") targetFeats = vector.features(targetLayer) count = 0 totalCount = len(targetFeats) progress.setInfo("%i target features identified" % totalCount) for targetFeat in targetFeats: count += 1 progress.setPercentage(int(100 * count / totalCount)) outFeat = QgsFeature(fields) targetId = targetFeat[targetFieldName] if targetId is None: raise GeoAlgorithmExecutionException("Target ID value cannot be empty") matchId = None outFeat.setAttribute(0, targetId) targetGeom = QgsGeometry(targetFeat.geometry()) if targetGeom is None: continue # get first, last, and mid points of target feature targetLength = targetGeom.length() firstPoint = targetGeom.interpolate(0) midPoint = targetGeom.interpolate(targetLength * 0.5) lastPoint = targetGeom.interpolate(targetLength) # get source features within the tolerance targetBox = targetGeom.buffer(tolerance, 5).boundingBox() sourceIds = index.intersects(targetBox) # test for nearness if method == "Midpoint": # get the 5 nearest neighbors midSourceIds = index.nearestNeighbor(midPoint.asPoint(), 5) # loop through the nearest features and identify the closest match minDist = -1 for sourceId in midSourceIds: if not sourceId in sourceIds: continue sourceGeom = QgsGeometry(sourceFeatures.get(sourceId).geometry()) if midPoint.distance(sourceGeom) > tolerance: continue # get distances firstDist = firstPoint.distance(sourceGeom) lastDist = lastPoint.distance(sourceGeom) if minDist < 0: minDist = firstDist + lastDist matchId = sourceFeatures[sourceId][sourceFieldName] elif minDist > firstDist + lastDist: minDist = firstDist + lastDist matchId = sourceFeatures[sourceId][sourceFieldName] elif method == "Thirds": thirdPoint = targetGeom.interpolate(targetLength * 0.33) twoThirdsPoint = targetGeom.interpolate(targetLength * 0.67) # get the 5 nearest neighbors thirdSourceIds = index.nearestNeighbor(thirdPoint.asPoint(), 5) twoThirdsSourceIds = index.nearestNeighbor(twoThirdsPoint.asPoint(), 5) # find common ids # loop through the nearest features and identify the closest match minDist = -1 for sourceId in midSourceIds: if not sourceId in sourceIds: continue sourceGeom = QgsGeometry(sourceFeatures.get(sourceId).geometry()) if midPoint.distance(sourceGeom) > tolerance: continue # get distances firstDist = firstPoint.distance(sourceGeom) lastDist = lastPoint.distance(sourceGeom) if minDist < 0: minDist = firstDist + lastDist matchId = sourceFeatures[sourceId][sourceFieldName] elif minDist > firstDist + lastDist: minDist = firstDist + lastDist matchId = sourceFeatures[sourceId][sourceFieldName] elif method == "Endpoints": avgDist = None for sourceId in sourceIds: sourceGeom = QgsGeometry(sourceFeatures.get(sourceId).geometry()) # skip a feature if it's not at least 1/2 as long as target if sourceGeom.length() < (targetGeom.length() * 0.5): continue # get distances firstDist = firstPoint.distance(sourceGeom) midDist = midPoint.distance(sourceGeom) lastDist = lastPoint.distance(sourceGeom) # skip a feature if it's beyond the tolerance at any point on the target if firstDist > tolerance or midDist > tolerance or lastDist > tolerance: continue # check deviation dev = sqrt((midDist - firstDist) ** 2 + (midDist - lastDist) ** 2) if dev > (targetLength / 2): continue # get the closest match checkDist = sum([firstDist, midDist, lastDist]) / 3 if avgDist is None: avgDist = checkDist matchId = sourceFeatures[sourceId][sourceFieldName] elif checkDist < avgDist: avgDist = checkDist matchId = sourceFeatures[sourceId][sourceFieldName] outFeat.setAttribute(1, matchId) outFeat.setGeometry(targetGeom) if keepNulls: writer.addFeature(outFeat) elif not matchId is None: writer.addFeature(outFeat) del writer