def processAlgorithm(self, progress): 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 == 2: try: y = int(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to integer' % unicode(comparisonvalue)) elif selectType == 6: try: y = float(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to float' % unicode(comparisonvalue)) elif selectType == 10: # 10: string, boolean try: y = unicode(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to unicode' % unicode(comparisonvalue)) elif selectType == 14: # 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' % (unicode(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"' % (unicode(dateAndFormat[0]), dateAndFormat[1])) else: y = QDate() msg = '' if y.isNull(): # Conversion was unsuccessfull 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 != 10: 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 == 2: x = int(aValue) elif selectType == 6: x = float(aValue) elif selectType == 10: # 10: string, boolean x = unicode(aValue) elif selectType == 14: # 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.setSelectedFeatures(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 progress.setPercentage(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 = QgsGeometry(feat.geometry()) bbox = geom2Eliminate.boundingBox() fit = processLayer.getFeatures( QgsFeatureRequest().setFilterRect(bbox)) mergeWithFid = None mergeWithGeom = None max = 0 min = -1 selFeat = QgsFeature() while fit.nextFeature(selFeat): selGeom = QgsGeometry(selFeat.geometry()) if geom2Eliminate.intersects(selGeom): # We have a candidate iGeom = geom2Eliminate.intersection(selGeom) if iGeom is None: 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 progress.setPercentage(start) else: featNotEliminated.append(feat) # End for featToEliminate featToEliminate = featNotEliminated # End while # Create output provider = processLayer.dataProvider() output = self.getOutputFromName(self.OUTPUT) writer = output.getVectorWriter(provider.fields(), provider.geometryType(), 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): 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 == 2: try: y = int(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to integer' % unicode(comparisonvalue)) elif selectType == 6: try: y = float(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to float' % unicode(comparisonvalue)) elif selectType == 10: # 10: string, boolean try: y = unicode(comparisonvalue) except ValueError: selectionError = True msg = self.tr('Cannot convert "%s" to unicode' % unicode(comparisonvalue)) elif selectType == 14: # 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' % (unicode(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"' % (unicode(dateAndFormat[0]), dateAndFormat[1])) else: y = QDate() msg = '' if y.isNull(): # Conversion was unsuccessfull 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 != 10: 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 == 2: x = int(aValue) elif selectType == 6: x = float(aValue) elif selectType == 10: # 10: string, boolean x = unicode(aValue) elif selectType == 14: # 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.setSelectedFeatures(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 progress.setPercentage(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 = QgsGeometry(feat.geometry()) bbox = geom2Eliminate.boundingBox() fit = processLayer.getFeatures( QgsFeatureRequest().setFilterRect(bbox)) mergeWithFid = None mergeWithGeom = None max = 0 min = -1 selFeat = QgsFeature() while fit.nextFeature(selFeat): selGeom = QgsGeometry(selFeat.geometry()) if geom2Eliminate.intersects(selGeom): # We have a candidate iGeom = geom2Eliminate.intersection(selGeom) if iGeom is None: 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 progress.setPercentage(start) else: featNotEliminated.append(feat) # End for featToEliminate featToEliminate = featNotEliminated # End while # Create output provider = processLayer.dataProvider() output = self.getOutputFromName(self.OUTPUT) writer = output.getVectorWriter(provider.fields(), provider.geometryType(), 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)