def testUpperCase(self): """ test uppercase """ self.assertFalse(QgsStringUtils.capitalize(None, QgsStringUtils.AllUppercase)) self.assertEqual(QgsStringUtils.capitalize('', QgsStringUtils.AllUppercase), '') self.assertEqual(QgsStringUtils.capitalize('testing 123', QgsStringUtils.AllUppercase), 'TESTING 123') self.assertEqual(QgsStringUtils.capitalize(' tESTinG abc ', QgsStringUtils.AllUppercase), ' TESTING ABC ') self.assertEqual(QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.AllUppercase), ' TESTING ABC')
def testMixed(self): """ test mixed capitalization - ie, no change! """ self.assertFalse(QgsStringUtils.capitalize(None, QgsStringUtils.MixedCase)) self.assertEqual(QgsStringUtils.capitalize('', QgsStringUtils.MixedCase), '') self.assertEqual(QgsStringUtils.capitalize('testing 123', QgsStringUtils.MixedCase), 'testing 123') self.assertEqual(QgsStringUtils.capitalize(' tESTinG 123 ', QgsStringUtils.MixedCase), ' tESTinG 123 ') self.assertEqual(QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.MixedCase), ' TESTING ABC')
def addAlgorithmEntry(alg, menuName, submenuName, actionText=None, icon=None, addButton=False): if actionText is None: if (QgsGui.higFlags() & QgsGui.HigMenuTextIsTitleCase) and not (alg.flags() & QgsProcessingAlgorithm.FlagDisplayNameIsLiteral): alg_title = QgsStringUtils.capitalize(alg.displayName(), QgsStringUtils.TitleCase) else: alg_title = alg.displayName() actionText = alg_title + QCoreApplication.translate('Processing', '…') action = QAction(icon or alg.icon(), actionText, iface.mainWindow()) alg_id = alg.id() action.setData(alg_id) action.triggered.connect(lambda: _executeAlgorithm(alg_id)) action.setObjectName("mProcessingUserMenu_%s" % alg_id) if menuName: menu = getMenu(menuName, iface.mainWindow().menuBar()) submenu = getMenu(submenuName, menu) submenu.addAction(action) if addButton: global algorithmsToolbar if algorithmsToolbar is None: algorithmsToolbar = iface.addToolBar(QCoreApplication.translate('MainWindow', 'Processing Algorithms')) algorithmsToolbar.setObjectName("ProcessingAlgorithms") algorithmsToolbar.setToolTip(QCoreApplication.translate('MainWindow', 'Processing Algorithms Toolbar')) algorithmsToolbar.addAction(action)
def testLowerCase(self): """ test lowercase """ self.assertFalse( QgsStringUtils.capitalize(None, QgsStringUtils.AllLowercase)) self.assertEqual( QgsStringUtils.capitalize('', QgsStringUtils.AllLowercase), '') self.assertEqual( QgsStringUtils.capitalize('testing 123', QgsStringUtils.AllLowercase), 'testing 123') self.assertEqual( QgsStringUtils.capitalize(' tESTinG abc ', QgsStringUtils.AllLowercase), ' testing abc ') self.assertEqual( QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.AllLowercase), ' testing abc')
def testCapitalizeFirst(self): """ test capitalize first """ self.assertFalse(QgsStringUtils.capitalize(None, QgsStringUtils.ForceFirstLetterToCapital)) self.assertEqual(QgsStringUtils.capitalize('', QgsStringUtils.ForceFirstLetterToCapital), '') self.assertEqual(QgsStringUtils.capitalize('testing 123', QgsStringUtils.ForceFirstLetterToCapital), 'Testing 123') self.assertEqual(QgsStringUtils.capitalize('testing', QgsStringUtils.ForceFirstLetterToCapital), 'Testing') self.assertEqual(QgsStringUtils.capitalize('Testing', QgsStringUtils.ForceFirstLetterToCapital), 'Testing') self.assertEqual(QgsStringUtils.capitalize('TESTING', QgsStringUtils.ForceFirstLetterToCapital), 'TESTING') self.assertEqual(QgsStringUtils.capitalize(' tESTinG abc ', QgsStringUtils.ForceFirstLetterToCapital), ' TESTinG Abc ') self.assertEqual(QgsStringUtils.capitalize(' TESTING ABC', QgsStringUtils.ForceFirstLetterToCapital), ' TESTING ABC') self.assertEqual(QgsStringUtils.capitalize(' testing abc', QgsStringUtils.ForceFirstLetterToCapital), ' Testing Abc')
def fetchResults(self, string, context, feedback): # collect results in main thread, since this method is inexpensive and # accessing the processing registry/current layer is not thread safe if iface.activeLayer() is None or iface.activeLayer().type( ) != QgsMapLayerType.VectorLayer: return for a in QgsApplication.processingRegistry().algorithms(): if not a.flags() & QgsProcessingAlgorithm.FlagSupportsInPlaceEdits: continue if not a.supportInPlaceEdit(iface.activeLayer()): continue result = QgsLocatorResult() result.filter = self result.displayString = a.displayName() result.icon = a.icon() result.userData = a.id() result.score = 0 if (context.usingPrefix and not string): self.resultFetched.emit(result) if not string: return string = string.lower() tagScore = 0 tags = [*a.tags(), a.provider().name()] if a.group(): tags.append(a.group()) for t in tags: if string in t.lower(): tagScore = 1 break result.score = QgsStringUtils.fuzzyScore( result.displayString, string) * 0.5 + tagScore * 0.5 if result.score > 0: self.resultFetched.emit(result)
def addAlgorithmEntry(alg, menuName, submenuName, actionText=None, icon=None, addButton=False): if actionText is None: actionText = QgsStringUtils.capitalize(alg.displayName(), QgsStringUtils.TitleCase) + QCoreApplication.translate('Processing', '…') action = QAction(icon or alg.icon(), actionText, iface.mainWindow()) action.setData(alg.id()) action.triggered.connect(lambda: _executeAlgorithm(alg)) action.setObjectName("mProcessingUserMenu_%s" % alg.id()) if menuName: menu = getMenu(menuName, iface.mainWindow().menuBar()) submenu = getMenu(submenuName, menu) submenu.addAction(action) if addButton: global algorithmsToolbar if algorithmsToolbar is None: algorithmsToolbar = iface.addToolBar(QCoreApplication.translate('MainWindow', 'Processing Algorithms')) algorithmsToolbar.setToolTip(QCoreApplication.translate('MainWindow', 'Processing Algorithms Toolbar')) algorithmsToolbar.addAction(action)
def search(self, search_term): if not search_term or search_term.isspace(): self.last_search_result = 100 return 100 ret_val = 0 # give more weight if exact search term occurs in title or description if search_term.lower() in self.__title.lower(): ret_val += 10 if search_term.lower() in self.description.lower(): ret_val += 5 for search_token in search_term.split(): for title_token in self.title.split(): if QgsStringUtils.levenshteinDistance(title_token, search_token, False) < 2: ret_val += 1 # always put custom instances first if self.is_custom: ret_val *= 100 self.last_search_result = ret_val return ret_val
def fetchResults(self, string, context, feedback): # collect results in main thread, since this method is inexpensive and # accessing the processing registry is not thread safe for a in QgsApplication.processingRegistry().algorithms(): if a.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox: continue if not ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES) and \ a.flags() & QgsProcessingAlgorithm.FlagKnownIssues: continue result = QgsLocatorResult() result.filter = self result.displayString = a.displayName() result.icon = a.icon() result.userData = a.id() result.score = 0 if (context.usingPrefix and not string): self.resultFetched.emit(result) if not string: return string = string.lower() tagScore = 0 tags = [*a.tags(), a.provider().name()] if a.group(): tags.append(a.group()) for t in tags: if string in t.lower(): tagScore = 1 break result.score = QgsStringUtils.fuzzyScore( result.displayString, string) * 0.5 + tagScore * 0.5 if result.score > 0: self.resultFetched.emit(result)
def addAlgorithmEntry(alg, menuName, submenuName, object_name, actionText=None, icon=None, addButton=False): if actionText is None: if (QgsGui.higFlags() & QgsGui.HigMenuTextIsTitleCase) and not ( alg.flags() & QgsProcessingAlgorithm.FlagDisplayNameIsLiteral): alg_title = QgsStringUtils.capitalize(alg.displayName(), QgsStringUtils.TitleCase) else: alg_title = alg.displayName() actionText = alg_title + QCoreApplication.translate('Processing', '…') action = QAction(icon or alg.icon(), actionText, iface.mainWindow()) alg_id = alg.id() action.setData(alg_id) action.triggered.connect(lambda: _executeAlgorithm(alg_id)) action.setObjectName("mProcessingUserMenu_%s" % alg_id) if menuName: menu = getMenu(menuName, iface.mainWindow().menuBar()) submenu = getMenu(submenuName, menu) submenu.setObjectName(object_name) submenu.addAction(action) if addButton: global algorithmsToolbar if algorithmsToolbar is None: algorithmsToolbar = iface.addToolBar( QCoreApplication.translate('MainWindow', 'Processing Algorithms')) algorithmsToolbar.setObjectName("ProcessingAlgorithms") algorithmsToolbar.setToolTip( QCoreApplication.translate('MainWindow', 'Processing Algorithms Toolbar')) algorithmsToolbar.addAction(action)
def processAlgorithm(self, parameters, context, feedback): # Get Parameters and assign to variable to work with layer = self.parameterAsLayer(parameters, self.SOURCE_LYR, context) field = self.parameterAsString(parameters, self.SOURCE_FIELD, context) maxdist = self.parameterAsDouble(parameters, self.MAX_DISTANCE, context) th_levenshtein = self.parameterAsInt(parameters, self.THRESHOLD_LEVENSHTEIN, context) th_substring = self.parameterAsInt(parameters, self.THRESHOLD_SUBSTRING, context) th_hamming = self.parameterAsInt(parameters, self.THRESHOLD_HAMMING, context) alg = self.parameterAsEnums(parameters, self.ALGORITHM, context) ao = self.parameterAsInt(parameters, self.ANDORALG, context) op = self.parameterAsString(parameters, self.OPERATOR, context) total = 100.0 / layer.featureCount() if layer.featureCount( ) else 0 # Initialize progress for progressbar layer.removeSelection() # clear selection before every run #totalfeatcount = layer.featureCount() for current, feat in enumerate( layer.getFeatures()): # iterate over source s = None # reset selection indicator s0 = None s1 = None s2 = None s3 = None s4 = None th_levenshtein_new = th_levenshtein th_substring_new = th_substring th_hamming_new = th_hamming if feat[field] is not None and len(str( feat[field])) > 0: # only compare if field is not empty # recalc thresholds based on current attribute values th_levenshtein_new = th_levenshtein_new if th_levenshtein_new < 0: # set to 0 if it would be negative th_levenshtein_new = 0 th_substring_new = len(str(feat[field])) - th_substring if th_substring_new < 0: # set to 0 if it would be negative th_substring_new = 0 th_hamming_new = len(str(feat[field])) - th_hamming if th_hamming_new < 0: # set to 0 if it would be negative th_hamming_new = 0 for lookupnr in range( 1, feat.id(), 1 ): # only compare to previous features, because we do not want to select the first feature of each duplicate group lookup = layer.getFeature( lookupnr) # get the lookup-feature if lookup[field] is not None and len( str(lookup[field] )) > 0: # only compare if field is not empty if feat.geometry().centroid().distance( lookup.geometry().centroid() ) <= maxdist: # only select if within given maxdistance if 0 in alg: # Exact Duplicates if feat[field] == lookup[field]: s0 = 1 else: s0 = 0 if 1 in alg: # Soundex if QgsStringUtils.soundex( str(feat[field] )) == QgsStringUtils.soundex( str(lookup[field])): s1 = 1 else: s1 = 0 if 2 in alg: # Levenshtein if QgsStringUtils.levenshteinDistance( str(feat[field]), str(lookup[field]) ) < th_levenshtein_new: s2 = 1 else: s2 = 0 if 3 in alg: # Longest Common Substring if len( QgsStringUtils.longestCommonSubstring( str(feat[field]), str( lookup[field])) ) > th_substring_new: s3 = 1 else: s3 = 0 if 4 in alg: # Hamming Distance: if QgsStringUtils.hammingDistance( str(feat[field]), str( lookup[field])) > th_hamming_new: s4 = 1 else: s4 = 0 if ao == 0: # All chosen algorithms need to match if 0 in ( s0, s1, s2, s3, s4 ): # Dont select current feature if at least one used algorithm returned 0 s = 0 else: # Select current feature if all algorithms returned 1 or None s = 1 elif ao == 1: # Only at least one algorithm needs to match if 1 in ( s0, s1, s2, s3, s4 ): # Select current feature if at least one used algorithm returned 1 s = 1 else: # Dont select current feature if no used algorithm returned 1 s = 0 if s == 1: # select the current feature if indicator is true layer.select(feat.id()) if feedback.isCanceled( ): # Cancel algorithm if button is pressed break feedback.setProgress(int(current * total)) # Set Progress in Progressbar return { self.OUTPUT: parameters[self.SOURCE_LYR] } # Return result of algorithm
def testfuzzyScore(self): self.assertEqual(QgsStringUtils.fuzzyScore('', ''), 0) self.assertEqual(QgsStringUtils.fuzzyScore('foo', ''), 0) self.assertEqual(QgsStringUtils.fuzzyScore('', 'foo'), 0) self.assertEqual(QgsStringUtils.fuzzyScore('foo', 'foo'), 1) self.assertEqual(QgsStringUtils.fuzzyScore('bar', 'foo'), 0) self.assertEqual(QgsStringUtils.fuzzyScore('FOO', 'foo'), 1) self.assertEqual(QgsStringUtils.fuzzyScore('foo', 'FOO'), 1) self.assertEqual(QgsStringUtils.fuzzyScore(' foo ', 'foo'), 1) self.assertEqual(QgsStringUtils.fuzzyScore('foo', ' foo '), 1) self.assertEqual(QgsStringUtils.fuzzyScore('foo', ' foo '), 1) self.assertEqual(QgsStringUtils.fuzzyScore('foo_bar', 'foo bar'), 1) self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'foo'), 0) self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'fooba'), 0) self.assertGreater(QgsStringUtils.fuzzyScore('foo_bar', 'ob'), 0) self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'foobar'), 0) self.assertGreater(QgsStringUtils.fuzzyScore('foo bar', 'foo_bar'), 0) self.assertGreater(QgsStringUtils.fuzzyScore('foo_bar', 'foo bar'), 0) self.assertEqual(QgsStringUtils.fuzzyScore('foo bar', 'foobar'), QgsStringUtils.fuzzyScore('foo_bar', 'foobar')) self.assertEqual(QgsStringUtils.fuzzyScore('foo bar', 'foo_bar'), QgsStringUtils.fuzzyScore('foo_bar', 'foo_bar')) self.assertEqual(QgsStringUtils.fuzzyScore('foo bar', 'foo bar'), QgsStringUtils.fuzzyScore('foo_bar', 'foo bar')) # note the accent self.assertEqual(QgsStringUtils.fuzzyScore('foo_bér', 'foober'), QgsStringUtils.fuzzyScore('foo_ber', 'foobér')) self.assertGreater( QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd hig'), QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd e h')) # full words are preferred, even though the same number of characters used self.assertGreater( QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd hig'), QgsStringUtils.fuzzyScore('abcd efg hig', 'abcd e hi'))
def processAlgorithm(self, parameters, context, feedback): line_source = self.parameterAsSource(parameters, self.LINES, context) if line_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.LINES)) point_source = self.parameterAsSource(parameters, self.POINTS, context) if point_source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.POINTS)) distance = self.parameterAsDouble(parameters, self.DIST, context) field_rn_line = self.parameterAsString(parameters, self.LINES_ROAD_NAMES, context) field_rn_point = self.parameterAsString(parameters, self.POINTS_ROAD_NAMES, context) if field_rn_line: feedback.pushInfo( 'Calculation with Levenshtein matching between \'{}\' (lines) and \'{}\' (points)' .format(field_rn_line, field_rn_point)) field_rn_line_index = line_source.fields().lookupField( field_rn_line) if field_rn_point is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.POINTS_ROAD_NAMES)) if field_rn_point: field_rn_point_index = point_source.fields().lookupField( field_rn_point) # raise QgsProcessingException(self.invalidSourceError(parameters, self.POINTS_ROAD_NAMES)) field_name = self.parameterAsString(parameters, self.FIELD, context) self.field_name = field_name fields = line_source.fields() fields.append(QgsField(field_name, QVariant.LongLong)) field_count_index = fields.lookupField(field_name) if fields.lookupField('fid') < 0: fields.append(QgsField('fid', QVariant.Int)) field_id_index = fields.lookupField('fid') fields_point = QgsFields() fields_point.append(QgsField("fid", QVariant.Int, "int", 9, 0)) fields_point.append(QgsField("line_id", QVariant.Int, "int", 9, 0)) fields_point.append(QgsField(self.field_name, QVariant.LongLong)) field_point_count_index = fields_point.lookupField(field_name) field_point_id_index = fields_point.lookupField('fid') field_point_lid_index = fields_point.lookupField('line_id') if field_rn_point: fields_point.append(QgsField(field_rn_point, QVariant.String)) field_point_rname_index = fields_point.lookupField(field_rn_point) fields_point.append( QgsField(field_rn_point + "_levenshtein", QVariant.String)) field_point_rname_clean_index = fields_point.lookupField( field_rn_point + "_levenshtein") (self.sink, self.dest_id) = self.parameterAsSink( parameters, self.OUTPUT_LINE, context, fields, line_source.wkbType(), line_source.sourceCrs(), QgsFeatureSink.RegeneratePrimaryKey) if self.sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT_LINE)) (self.sink_point, self.dest_id_point) = self.parameterAsSink( parameters, self.OUTPUT_POINT, context, fields_point, point_source.wkbType(), point_source.sourceCrs(), QgsFeatureSink.RegeneratePrimaryKey) if self.sink_point is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT_POINT)) #Calculate Proportional Symbol Map features = point_source.getFeatures() total = 100.0 / point_source.featureCount( ) if point_source.featureCount() else 0 feedback.setProgressText( self.tr('Create a Proportional Symbols Map with points')) points = {} for current, point_feature in enumerate(features): if feedback.isCanceled(): break point = point_feature.geometry().asPoint() idList = [] key = str(point.x()) + "_" + str(point.y()) if key in points: idList = points[key][1] idList.append(point_feature.id()) points[key] = [point, idList] if field_rn_point: points[key].append(point_feature[field_rn_point_index]) for i, key in enumerate(points): if feedback.isCanceled(): break point = points[key][0] output_feature = QgsFeature() inGeom = QgsGeometry() output_feature.setGeometry(inGeom.fromPointXY(point)) attrs = [i, None, len(points[key][1])] if field_rn_point: attrs.append(points[key][2]) attrs.append(self.NameClean(points[key][2], feedback)) output_feature.setAttributes(attrs) self.sink_point.addFeature(output_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) #Calculate Graduated Line Map prop_point_source = QgsProcessingUtils.mapLayerFromString( self.dest_id_point, context) prop_point_source.startEditing() segList = {} t = QgsCoordinateTransform(point_source.sourceCrs(), line_source.sourceCrs(), context.transformContext()) request = QgsFeatureRequest().setFilterRect( t.transform(line_source.sourceExtent(), QgsCoordinateTransform.ReverseTransform)) count = count_iterable(prop_point_source.getFeatures(request)) total = 100.0 / count if count else 0 feedback.setProgressText( self.tr('Calculate the number points for each segment')) for current, point_feature in enumerate( prop_point_source.getFeatures(request)): if feedback.isCanceled(): break minDist = None minFeatId = None point = point_feature.geometry().asPoint() point = t.transform(point) pointBox = QgsRectangle(point.x() - distance, point.y() - distance, point.x() + distance, point.y() + distance) request = QgsFeatureRequest().setFilterRect(pointBox) if field_rn_line: # récupérer le nom de la rue pour feat pointRoadName = point_feature[field_point_rname_index] #Première boucle pour identifier la rue qui match le mieux bestMatchingFeats = None matchingScores = {} bestMatchingScore = None #SK : pre-traitement du point pointRoadNameClean = self.NameClean(pointRoadName, feedback) if pointRoadNameClean != '': # verifie qu'il y a bien un nom de rue pour le point minDist = None for line_feature in line_source.getFeatures(request): # feedback.pushInfo('Line: {}'.format(line_feature)) if feedback.isCanceled(): break # récupérer le nom de la rue pour inFeat lineRoadName = line_feature[field_rn_line_index] # SK: pre-traitement segment lineRoadNameClean = self.NameClean( lineRoadName, feedback) if pointRoadNameClean == '': # verifie qu'il y a bien un nom de rue pour la ligne continue # SK: Calcul de la distance de Levenshtein matchScore = QgsStringUtils.levenshteinDistance( pointRoadNameClean, lineRoadNameClean) if matchScore is not None: #on stock tous les scores dans un dictionnaire que l'on interrogera plus tard avec le meilleur score #on stock la liste des feature pour chaque score if matchScore in matchingScores: matchingScores[matchScore].append(line_feature) else: matchingScores[matchScore] = [line_feature] #On identifie le meilleur score dans la boucle if bestMatchingScore is None or matchScore < bestMatchingScore: bestMatchingScore = matchScore #QR : compute minDist in case MatchingScore is empty geom = line_feature.geometry() dist = geom.closestSegmentWithContext( point) #closestVertex if minDist == None or dist[0] < minDist: minDist = dist[0] minFeatId = line_feature.id() #On récupère la liste des segments qui ont le meilleur matching if bestMatchingScore is None: #Gestion erreur inconnue if minFeatId is not None: feedback.pushInfo( 'No matching line for {} at line: {} (closest road id used: {})' .format(pointRoadName, current, minFeatId)) else: bestMatchingFeats = matchingScores[bestMatchingScore] #réutiliser ici la liste "bestMatchingFeats" pour assurer que les 2 conditions soient prises en compte : matchingName + distance la plus courte minDist = None oldFeatId = minFeatId minFeatId = None for line_feature in bestMatchingFeats: geom = line_feature.geometry() dist = geom.closestSegmentWithContext( point) #closestVertex if minDist == None or dist[0] < minDist: minDist = dist[0] minFeatId = line_feature.id() # if oldFeatId != minFeatId: # feedback.pushInfo('Line change based on name {} - {} for {})'.format(oldFeatId, minFeatId, pointRoadName)) else: # si le champ nom est vide minDist = None minFeatId = None # passe au calcul juste sur la distance for line_feature in line_source.getFeatures(request): # feedback.pushInfo('Line: {}'.format(line_feature)) if feedback.isCanceled(): break geom = line_feature.geometry() dist = geom.closestSegmentWithContext( point) #closestVertex if minDist == None or dist[0] < minDist: minDist = dist[0] minFeatId = line_feature.id() feedback.pushInfo( 'Cleaned address is Empty for {} at line {} (closest road id used: {})' .format(pointRoadName, current, minFeatId)) #FIN else: for line_feature in line_source.getFeatures(request): # feedback.pushInfo('Line: {}'.format(line_feature)) if feedback.isCanceled(): break geom = line_feature.geometry() dist = geom.closestSegmentWithContext( point) #closestVertex if minDist == None or dist[0] < minDist: minDist = dist[0] minFeatId = line_feature.id() if minFeatId is not None: if minFeatId in segList: segList[minFeatId]["TOT"] += point_feature[ field_point_count_index] else: segList[minFeatId] = { "TOT": point_feature[field_point_count_index] } prop_point_source.changeAttributeValue(point_feature.id(), field_point_lid_index, minFeatId) feedback.setProgress(int(current * total)) prop_point_source.commitChanges() if len(segList) == 0: feedback.reportError( self.tr('No match between points and lines layers'), fatalError=True) return {} feedback.setProgressText(self.tr('Create the layer')) total = 100.0 / len(segList) current = 0 for fid, values in segList.items(): feat = QgsFeature() line_source.getFeatures(QgsFeatureRequest(fid)).nextFeature(feat) attrs = feat.attributes() attrs.append(values["TOT"]) #count attrs.append(fid) output_feature = QgsFeature() output_feature.setGeometry(feat.geometry()) output_feature.setAttributes(attrs) self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) current += 1 return {self.OUTPUT_LINE: self.dest_id}
def test_truncate_from_middle(self): """ Test QgsStringUtils.truncateMiddleOfString """ self.assertEqual(QgsStringUtils.truncateMiddleOfString('', 0), '') self.assertEqual(QgsStringUtils.truncateMiddleOfString('', 10), '') self.assertEqual(QgsStringUtils.truncateMiddleOfString('abcdef', 10), 'abcdef') self.assertEqual( QgsStringUtils.truncateMiddleOfString('abcdefghij', 10), 'abcdefghij') self.assertEqual( QgsStringUtils.truncateMiddleOfString('abcdefghijk', 10), 'abcd…ghijk') self.assertEqual( QgsStringUtils.truncateMiddleOfString('abcdefghijkl', 10), 'abcde…ijkl') self.assertEqual( QgsStringUtils.truncateMiddleOfString('abcdefghijklmnop', 10), 'abcde…mnop') self.assertEqual( QgsStringUtils.truncateMiddleOfString('this is a test', 11), 'this … test') self.assertEqual( QgsStringUtils.truncateMiddleOfString('this is a test', 1), '…') self.assertEqual( QgsStringUtils.truncateMiddleOfString('this is a test', 2), 't…') self.assertEqual( QgsStringUtils.truncateMiddleOfString('this is a test', 3), 't…t') self.assertEqual( QgsStringUtils.truncateMiddleOfString('this is a test', 0), '…')
def testSubstituteVerticalCharacters(self): """ test subsitute vertical characters """ self.assertEqual( QgsStringUtils.substituteVerticalCharacters('123{[(45654)]}321'), '123︷﹇︵45654︶﹈︸321')