def joinattributesbylocation(self,
                                 input,
                                 join,
                                 inputonlyselected=False,
                                 joinonlyselected=False,
                                 joinfiels=[],
                                 method=0,
                                 predicate=[0],
                                 prefix='',
                                 discardnomatching=False,
                                 output='TEMPORARY_OUTPUT'):

        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'qgis:joinattributesbylocation'

        inputsource = input
        joinsource = join

        if inputonlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)
        if joinonlyselected:
            joinsource = QgsProcessingFeatureSourceDefinition(join, True)

        params = dict(
            INPUT=inputsource,
            JOIN=joinsource,
            JOIN_FIELDS=joinfiels,
            METHOD=method,  # 0 — (one-to-many), 1 — (one - to - one)
            PREDICATE=
            predicate,  # 0 — intersects, 1 — contains, 2 — equals, 3 — touches, 4 — overlaps, 5 — within, 6 — crosses
            PREFIX=prefix,
            DISCARD_NONMATCHING=discardnomatching,
            OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
    def joinattributetable(self,
                           input1,
                           input1onlyselected,
                           input2,
                           input2onlyselected,
                           field1,
                           field2,
                           prefix='M_',
                           output='TEMPORARY_OUTPUT'):

        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'native:joinattributestable'

        inputsource1 = input1
        inputsource2 = input2
        if input1onlyselected:
            inputsource1 = QgsProcessingFeatureSourceDefinition(input1, True)
        if input2onlyselected:
            inputsource2 = QgsProcessingFeatureSourceDefinition(input2, True)

        params = dict(INPUT=inputsource1,
                      FIELD=field1,
                      INPUT_2=inputsource2,
                      FIELD_2=field2,
                      FIELDS_TO_COPY=[],
                      METHOD=1,
                      PREFIX=prefix,
                      DISCARD_NONMATCHING=False,
                      OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
    def distancematrix(self,
                       input,
                       inputonlyselected,
                       inputfield,
                       target,
                       targetonlyseleted,
                       targetfield,
                       matrixtype=2,
                       output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'qgis:distancematrix'

        inputsource = input
        tarsource = target
        if inputonlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)
        if targetonlyseleted:
            tarsource = QgsProcessingFeatureSourceDefinition(target, True)

        params = dict(INPUT=inputsource,
                      INPUT_FIELD=inputfield,
                      TARGET=tarsource,
                      TARGET_FIELD=targetfield,
                      MATRIX_TYPE=matrixtype,
                      NEAREST_POINTS=0,
                      OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
    def countpointsinpolygon(self,
                             polygons,
                             points,
                             field,
                             polyonlyselected=False,
                             pointonlyseleced=False,
                             weight=None,
                             classfield=None,
                             output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'qgis:countpointsinpolygon'

        polyinputsource = polygons
        if polyonlyselected:
            polyinputsource = QgsProcessingFeatureSourceDefinition(
                polygons, True)

        pointinputsource = points
        if pointonlyseleced:
            pointinputsource = QgsProcessingFeatureSourceDefinition(
                points, True)

        params = dict(POLYGONS=polyinputsource,
                      POINTS=pointinputsource,
                      FIELD=field,
                      WEIGHT=weight,
                      CLASSFIELD=classfield,
                      OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
    def intersection(self,
                     input,
                     inputonlyseleceted,
                     inputfields,
                     overlay,
                     overayprefix,
                     overonlyselected=False,
                     overlayer_fields=None,
                     output='TEMPORARY_OUTPUT'):

        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'native:intersection'

        inputsource = input
        if inputonlyseleceted:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        overlaysource = overlay
        if overonlyselected:
            overlaysource = QgsProcessingFeatureSourceDefinition(overlay, True)

        params = dict(INPUT=inputsource,
                      INPUT_FIELDS=inputfields,
                      OVERLAY=overlaysource,
                      OVERLAY_FIELDS_PREFIX=overayprefix,
                      OVERLAY_FIELDS=overlayer_fields,
                      OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #6
0
def execute_in_place(alg, parameters, context=None, feedback=None):
    """Executes an algorithm modifying features in-place in the active layer.

    The input layer must be editable or an exception is raised.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :param context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :param feedback: QgsProcessingFeedback, optional
    :raises QgsProcessingException: raised when the layer is not editable or the layer cannot be found in the current project
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(
        iface.activeLayer().id(), True)
    ok, results = execute_in_place_run(alg,
                                       iface.activeLayer(),
                                       parameters,
                                       context=context,
                                       feedback=feedback)
    if ok:
        iface.activeLayer().triggerRepaint()
    return ok, results
    def nearesthubpoints(self,
                         input,
                         onlyselected,
                         sf_hub,
                         hubfield,
                         output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = "qgis:distancetonearesthubpoints"

        inputsource = input
        if onlyselected:
            # self.feedback.pushInfo('onlyselected')
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource,
                      HUBS=sf_hub,
                      FIELD=hubfield,
                      UNIT=0,
                      OUTPUT=output)

        result = self.run_algprocessing(algname=algname,
                                        params=params)['OUTPUT']

        if output.find('TEMPORARY_OUTPUT') < 0:
            basename = 'output'
            result = self.renameField(layer=result,
                                      fromName='HubName',
                                      toName=hubfield,
                                      baseName=basename)
        else:
            result.startEditing()
            idx = result.fields().indexFromName('HubName')
            result.renameAttribute(idx, hubfield)
            result.commitChanges()
        return result
Exemple #8
0
 def createCentroidsLayer(self, layer, filt, name):
     #Dato un layer di tipo poligonale, ne crea una copia utilizzandone i centroidi;
     #In base al filtro scelto utilizza solo le features selezionate (o tutte le features se non esiste un filtro):
     #aggiunge i campi prob, ruolo e probRuolo
     if filt:
         QueryLayer().selectionByExpr(layer, filt)
     else:
         layer.selectAll()
     context = dataobjects.createContext()
     context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)
     params = {
         'INPUT': QgsProcessingFeatureSourceDefinition(layer.id(), True),
         'ALL_PARTS': False,
         'OUTPUT': 'memory:'
     }
     newLayer = processing.run("native:centroids", params, context=context)
     layerOutput = newLayer['OUTPUT']
     data_provider = layerOutput.dataProvider()
     data_provider.addAttributes([QgsField('prob', QVariant.Int)])
     data_provider.addAttributes([QgsField('ruolo', QVariant.String)])
     data_provider.addAttributes([QgsField('probRuolo', QVariant.String)])
     layerOutput.updateFields()
     layerOutput.setName(name)
     QgsProject.instance().addMapLayer(layerOutput)
     QgsProject.instance().layerTreeRoot().findLayer(
         layerOutput.id()).setItemVisibilityChecked(False)
     layer.removeSelection()
     iface.setActiveLayer(layerOutput)
     return layerOutput
    def testGetOgrCompatibleSourceFromOgrLayer(self):
        p = QgsProject()
        source = os.path.join(testDataPath, 'points.gml')
        vl = QgsVectorLayer(source)
        self.assertTrue(vl.isValid())
        p.addMapLayer(vl)

        context = QgsProcessingContext()
        context.setProject(p)
        feedback = QgsProcessingFeedback()

        alg = ogr2ogr()
        alg.initAlgorithm()
        path, layer = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl.id()},
                                                 context, feedback, True)
        self.assertEqual(path, source)
        path, layer = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl.id()},
                                                 context, feedback, False)
        self.assertEqual(path, source)

        # with selected features only - if not executing, the 'selected features only' setting
        # should be ignored (because it has no meaning for the gdal command outside of QGIS!)
        parameters = {
            'INPUT': QgsProcessingFeatureSourceDefinition(vl.id(), True)
        }
        path, layer = alg.getOgrCompatibleSource('INPUT', parameters, context,
                                                 feedback, False)
        self.assertEqual(path, source)

        # with subset string
        vl.setSubsetString('x')
        path, layer = alg.getOgrCompatibleSource('INPUT', parameters, context,
                                                 feedback, False)
        self.assertEqual(path, source)
        # subset of layer must be exported
        path, layer = alg.getOgrCompatibleSource('INPUT', parameters, context,
                                                 feedback, True)
        self.assertNotEqual(path, source)
        self.assertTrue(path)
        self.assertTrue(path.endswith('.gpkg'))
        self.assertTrue(os.path.exists(path))
        self.assertTrue(layer)

        # geopackage with layer
        source = os.path.join(testDataPath, 'custom', 'circular_strings.gpkg')
        vl2 = QgsVectorLayer(source + '|layername=circular_strings')
        self.assertTrue(vl2.isValid())
        p.addMapLayer(vl2)
        path, layer = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl2.id()},
                                                 context, feedback, True)
        self.assertEqual(path, source)
        self.assertEqual(layer, 'circular_strings')
        vl3 = QgsVectorLayer(source + '|layername=circular_strings_with_line')
        self.assertTrue(vl3.isValid())
        p.addMapLayer(vl3)
        path, layer = alg.getOgrCompatibleSource('INPUT', {'INPUT': vl3.id()},
                                                 context, feedback, True)
        self.assertEqual(path, source)
        self.assertEqual(layer, 'circular_strings_with_line')
    def testFeatureSourceInput(self):
        # create a memory layer and add to project and context
        layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
                               "testmem", "memory")
        self.assertTrue(layer.isValid())
        pr = layer.dataProvider()
        f = QgsFeature()
        f.setAttributes(["test", 123])
        f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
        f2 = QgsFeature()
        f2.setAttributes(["test2", 457])
        f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200)))
        self.assertTrue(pr.addFeatures([f, f2]))
        self.assertEqual(layer.featureCount(), 2)

        # select first feature
        layer.selectByIds([next(layer.getFeatures()).id()])
        self.assertEqual(len(layer.selectedFeatureIds()), 1)

        QgsProject.instance().addMapLayer(layer)
        context = QgsProcessingContext()
        context.setProject(QgsProject.instance())

        alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
        self.assertIsNotNone(alg)
        temp_file = os.path.join(self.temp_dir, 'grass_output_sel.shp')
        parameters = {'input': QgsProcessingFeatureSourceDefinition('testmem', True),
                      'cats': '',
                      'where': '',
                      'type': [0, 1, 4],
                      'distance': 1,
                      'minordistance': None,
                      'angle': 0,
                      'column': None,
                      'scale': 1,
                      'tolerance': 0.01,
                      '-s': False,
                      '-c': False,
                      '-t': False,
                      'output': temp_file,
                      'GRASS_REGION_PARAMETER': None,
                      'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
                      'GRASS_MIN_AREA_PARAMETER': 0.0001,
                      'GRASS_OUTPUT_TYPE_PARAMETER': 0,
                      'GRASS_VECTOR_DSCO': '',
                      'GRASS_VECTOR_LCO': ''}
        feedback = QgsProcessingFeedback()

        results, ok = alg.run(parameters, context, feedback)
        self.assertTrue(ok)
        self.assertTrue(os.path.exists(temp_file))

        # make sure that layer has correct features
        res = QgsVectorLayer(temp_file, 'res')
        self.assertTrue(res.isValid())
        self.assertEqual(res.featureCount(), 1)

        QgsProject.instance().removeMapLayer(layer)
Exemple #11
0
    def differencelayer(self,
                        input,
                        onlyselected,
                        overlay,
                        overonlyselected,
                        output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = "native:difference"

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        oversource = overlay
        if overonlyselected:
            oversource = QgsProcessingFeatureSourceDefinition(overlay, True)

        params = dict(INPUT=inputsource, OVERLAY=oversource, OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #12
0
def get_processing_value(param: QgsProcessingParameterDefinition,
                         inp: WPSInput, context: ProcessingContext) -> Any:
    """ Return processing values from WPS input data
    """
    if isinstance(param, DESTINATION_LAYER_TYPES):
        #
        # Destination layer: a new layer is created as file with the input name.
        # Do not supports memory layer because we need persistence
        #
        param.setSupportsNonFileBasedOutput(False)
        #
        # Enforce pushing created layers to layersToLoadOnCompletion list
        # i.e layer will be stored in the destination project

        # get extension from input metadata (should always exist for destination)
        extension = get_metadata(inp[0], 'processing:extension')[0]

        destination = inp[0].data

        if confservice.getboolean('processing',
                                  'unsafe.raw_destination_input_sink'):
            sink, destination = parse_root_destination_path(
                param, destination, extension)
        else:
            # Use canonical file name
            sink = "./%s.%s" % (get_valid_filename(param.name()), extension)

        value = QgsProcessingOutputLayerDefinition(sink,
                                                   context.destination_project)
        value.destinationName = destination

        LOGGER.debug("Handling destination layer: %s, details name: %s",
                     param.name(), value.destinationName)

    elif isinstance(param, QgsProcessingParameterFeatureSource):
        #
        # Support feature selection
        #
        value, has_selection = parse_layer_spec(inp[0].data,
                                                context,
                                                allow_selection=True)
        value = QgsProcessingFeatureSourceDefinition(
            value, selectedFeaturesOnly=has_selection)

    elif isinstance(param, INPUT_LAYER_TYPES):
        if len(inp) > 1:
            value = [parse_layer_spec(i.data, context)[0] for i in inp]
        else:
            value, _ = parse_layer_spec(inp[0].data, context)
    else:
        value = None

    return value
Exemple #13
0
    def recherche(self):
        # Paramètres en entrée:
        # { 'INPUT' : 'C:/Olivier/Documents/Carto/References/Vecteur/communes-20140629-5m-shp/communes-20140629-5m.shp',
        # 'INTERSECT' : QgsProcessingFeatureSourceDefinition('TraceMatin20160930224546251', True),
        # 'OUTPUT' : 'C:/Olivier/Documents/Collectif/Telethon 2018/Cartes/Enduro/SuiviValidation.shp',
        # 'PREDICATE' : [0] }
        ss = False

        ll = self.parent.dlg.MasqueLignePoint.currentData()
        if (self.parent.dlg.selectionSeulement.isChecked()):
            self.parent.iface.messageBar().pushMessage(
                "Selection seulement dans {0}".format(ll.name()),
                Qgis.MessageLevel.Info)
            self.parent.iface.messageBar().update()
            ss = True
            print(ll.selectedFeatureCount())
            if (ll.selectedFeatureCount() == 0):
                self.parent.iface.messageBar().pushCritical(
                    "Erreur",
                    "Pas d entite selectionnee dans {0}".format(ll.name()))

        self.parent.message("Recherche ...")
        QGuiApplication.setOverrideCursor(Qt.WaitCursor)

        paramin = {
            'INPUT': self.parent.dlg.MasqueListeCouches.currentData().id(),
            'INTERSECT': QgsProcessingFeatureSourceDefinition(ll.id(), ss),
            'OUTPUT': 'memory:',
            'PREDICATE': [0]
        }
        res = processing.run('native:extractbylocation', paramin)
        # verifier si erreur
        print(res['OUTPUT'])
        l = res['OUTPUT']

        # Ajout des champs
        res=l.dataProvider().addAttributes([QgsField("valide", QVariant.Date), QgsField("note", QVariant.String), \
                                           QgsField("supprime", QVariant.Date), QgsField("ajoute", QVariant.Date)])
        l.updateFields()
        if (not res):
            print("Erreur creation attributs")
            self.parent.iface.messageBar().pushCritical(
                "Erreur", "Erreur de creation des attributs")

        if (len(self.parent.dlg.MasqueNomCouche.displayText().strip()) > 0):
            l.setName(self.parent.dlg.MasqueNomCouche.displayText().strip())

        self.defStyle(l)

        QgsProject.instance().addMapLayer(l)

        QGuiApplication.restoreOverrideCursor()
        self.parent.message("Done")
Exemple #14
0
 def runSplitLinesWithLines(self,
                            inputLyr,
                            linesLyr,
                            context,
                            feedback=None,
                            onlySelected=False,
                            outputLyr=None):
     usedInput = inputLyr if not onlySelected else \
             QgsProcessingFeatureSourceDefinition(inputLyr.id(), True)
     usedLines = linesLyr if not onlySelected else \
             QgsProcessingFeatureSourceDefinition(linesLyr.id(), True)
     outputLyr = 'memory:' if outputLyr is None else outputLyr
     parameters = {
         'INPUT': usedInput,
         'LINES': usedLines,
         'OUTPUT': outputLyr
     }
     output = processing.run("native:splitwithlines",
                             parameters,
                             context=context,
                             feedback=feedback)
     return output['OUTPUT']
Exemple #15
0
    def multiparttosingleparts(self,
                               input,
                               onlyselected,
                               output='TEMPORARY_OUTPUT'):

        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'native:multiparttosingleparts'
        #algname = 'qgis:multiparttosingleparts'

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource, OUTPUT=output)
        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #16
0
    def centroidlayer(self,
                      input,
                      onlyselected,
                      allparts=False,
                      output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'native:centroids'

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource, ALL_PARTS=allparts, OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #17
0
 def runAddCount(self, inputLyr, boolVar):
     output = processing.run(
         "native:addautoincrementalfield",
         {
             'INPUT':QgsProcessingFeatureSourceDefinition(inputLyr.sourceName(), not boolVar), # boolVar recebe o contrario da checkbox de feições selecionadas
             'FIELD_NAME':'AUTO',
             'START':0,
             'GROUP_FIELDS':[],
             'SORT_EXPRESSION':'',
             'SORT_ASCENDING':False,
             'SORT_NULLS_FIRST':False,
             'OUTPUT':'TEMPORARY_OUTPUT'
         }
     )
     return output['OUTPUT']
Exemple #18
0
    def dissolvewithQgis2(self,
                          input,
                          onlyselected,
                          field=None,
                          output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'qgis:dissolve'

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource, FIELD=field, OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #19
0
    def clipwithQgis(self,
                     input,
                     onlyselected,
                     overlay,
                     output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = "native:clip"

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource, OVERLAY=overlay, OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #20
0
 def createConvexHull(self, lBeni, b1, b2):
     #Data una lista di beni calcola il convexhull corrispondente;
     #utilizza l'algoritmo minimumboundinggeometry;
     #setta il context affinchè non ci sia il check sulle geometrie invalide
     layer = Utils().getLayerBeni()
     layerOutput = False
     for feat in layer.getFeatures():
         if feat['ident'] in lBeni:
             beneId = str(feat['id'])
             dipendentiIds = QueryLayer().getDependenciesList(
                 beneId, b1, b2)
             if len(dipendentiIds) > 2:
                 expr = QueryLayer().IdListToExpr(dipendentiIds)
                 QueryLayer().selectionByExpr(layer, expr)
                 context = dataobjects.createContext()
                 context.setInvalidGeometryCheck(
                     QgsFeatureRequest.GeometryNoCheck)
                 params = {
                     'INPUT':
                     QgsProcessingFeatureSourceDefinition(layer.id(), True),
                     'TYPE':
                     3,
                     'OUTPUT':
                     'memory:'
                 }
                 newconvexhulllayer = processing.run(
                     "qgis:minimumboundinggeometry",
                     params,
                     context=context)
                 layerOutput = newconvexhulllayer['OUTPUT']
                 layerOutput.setName('areaBene' + beneId)
                 layerOutput.startEditing()
                 for feat in layerOutput.getFeatures():
                     feat['id'] = beneId
                     layerOutput.updateFeature(feat)
                 layerOutput.commitChanges()
                 Utils().setStyle("buffer", layerOutput)
                 QgsProject.instance().addMapLayer(layerOutput)
     if layerOutput != False:
         if len(lBeni) > 1:
             Utils().zoomToLayer(Utils().getLayerBeni())
         else:
             Utils().zoomToLayer(layerOutput)
     else:
         iface.messageBar().pushMessage(
             'Attenzione',
             'Non esistono beni o relazioni con queste caratteristiche',
             level=Qgis.Critical)
Exemple #21
0
    def _alg_tester(self, alg_name, input_layer, parameters):

        alg = self.registry.createAlgorithmById(alg_name)

        self.assertIsNotNone(alg)
        parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(
            input_layer.id(), True)
        parameters['OUTPUT'] = 'memory:'

        old_features = [f for f in input_layer.getFeatures()]
        input_layer.selectByIds([old_features[0].id()])
        # Check selected
        self.assertEqual(input_layer.selectedFeatureIds(),
                         [old_features[0].id()], alg_name)

        context = QgsProcessingContext()
        context.setProject(QgsProject.instance())
        feedback = ConsoleFeedBack()

        input_layer.rollBack()
        with self.assertRaises(QgsProcessingException) as cm:
            execute_in_place_run(alg,
                                 input_layer,
                                 parameters,
                                 context=context,
                                 feedback=feedback,
                                 raise_exceptions=True)

        ok = False
        input_layer.startEditing()
        ok, _ = execute_in_place_run(alg,
                                     input_layer,
                                     parameters,
                                     context=context,
                                     feedback=feedback,
                                     raise_exceptions=True)
        new_features = [f for f in input_layer.getFeatures()]

        # Check ret values
        self.assertTrue(ok, alg_name)

        # Check geometry types (drop Z or M)
        self.assertEqual(new_features[0].geometry().wkbType(),
                         old_features[0].geometry().wkbType())

        return old_features, new_features
Exemple #22
0
    def bufferwithQgis(self,
                       input,
                       onlyselected,
                       distance,
                       output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'native:multiringconstantbuffer'

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource,
                      DISTANCE=distance,
                      OUTPUT=output,
                      RINGS=1)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
    def testGetOgrCompatibleSourceFromFeatureSource(self):
        # create a memory layer and add to project and context
        layer = QgsVectorLayer(
            "Point?field=fldtxt:string&field=fldint:integer", "testmem",
            "memory")
        self.assertTrue(layer.isValid())
        pr = layer.dataProvider()
        f = QgsFeature()
        f.setAttributes(["test", 123])
        f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
        f2 = QgsFeature()
        f2.setAttributes(["test2", 457])
        f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
        self.assertTrue(pr.addFeatures([f, f2]))
        self.assertEqual(layer.featureCount(), 2)
        # select first feature
        layer.selectByIds([next(layer.getFeatures()).id()])
        self.assertEqual(len(layer.selectedFeatureIds()), 1)
        QgsProject.instance().addMapLayer(layer)
        context = QgsProcessingContext()
        context.setProject(QgsProject.instance())

        alg = QgsApplication.processingRegistry().createAlgorithmById(
            'gdal:buffervectors')
        self.assertIsNotNone(alg)
        parameters = {
            'INPUT': QgsProcessingFeatureSourceDefinition('testmem', True)
        }
        feedback = QgsProcessingFeedback()
        # check that memory layer is automatically saved out to geopackage when required by GDAL algorithms
        ogr_data_path, ogr_layer_name = alg.getOgrCompatibleSource(
            'INPUT', parameters, context, feedback, executing=True)
        self.assertTrue(ogr_data_path)
        self.assertTrue(ogr_data_path.endswith('.gpkg'))
        self.assertTrue(os.path.exists(ogr_data_path))
        self.assertTrue(ogr_layer_name)

        # make sure that layer has only selected feature
        res = QgsVectorLayer(ogr_data_path, 'res')
        self.assertTrue(res.isValid())
        self.assertEqual(res.featureCount(), 1)

        QgsProject.instance().removeMapLayer(layer)
Exemple #24
0
    def statisticsbycategories(self,
                               input,
                               onlyselected,
                               categoriesfields,
                               valuefield,
                               output='TEMPORARY_OUTPUT'):
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = 'qgis:statisticsbycategories'

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource,
                      CATEGORIES_FIELD_NAME=categoriesfields,
                      METHOD=0,
                      VALUES_FIELD_NAME=valuefield,
                      OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #25
0
    def refactorfields(self,
                       input,
                       onlyselected,
                       refieldmapping,
                       output='TEMPORARY_OUTPUT'):
        # qgis:refactorfields
        # {'FIELDS_MAPPING': [{'expression': '"NEAR_FID"', 'length': 10, 'name': 'NEAR_FID', 'precision': 0, 'type': 4},
        #                     {'expression': '"pop_all"', 'length': 18, 'name': 'pop_all', 'precision': 11, 'type': 6}],
        #  'INPUT': '/Users/song-ansup/Desktop/KoALA_data/logfile/cliped_pop.shp', 'OUTPUT': 'TEMPORARY_OUTPUT'}
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'
        algname = "qgis:refactorfields"

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource,
                      FIELDS_MAPPING=refieldmapping,
                      OUTPUT=output)
        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
Exemple #26
0
    def rectanglesovalsdiamonds(self,
                                input,
                                onlyselected=False,
                                shape=0,
                                width=1.0,
                                height=1.0,
                                rotation=None,
                                segment=36,
                                output='TEMPORARY_OUTPUT'):
        # 0 — Rectangles
        # 1 — Ovals
        # 2 — Diamonds
        if output is None or output == '': output = 'TEMPORARY_OUTPUT'

        algname = ""
        if algname == "":
            algname = self.checkAlgname("qgis:rectanglesovalsdiamondsfixed")
        if algname == "":
            algname = self.checkAlgname("native:rectanglesovalsdiamondsfixed")
        if algname == "":
            algname = self.checkAlgname("qgis:rectanglesovalsdiamonds")
        if algname == "":
            algname = self.checkAlgname("native:rectanglesovalsdiamonds")

        self.feedback.pushInfo("************ checkAlgname %s : " % algname)

        inputsource = input
        if onlyselected:
            inputsource = QgsProcessingFeatureSourceDefinition(input, True)

        params = dict(INPUT=inputsource,
                      SHAPE=shape,
                      WIDTH=width,
                      HEIGHT=height,
                      ROTATION=rotation,
                      SEGMENTS=segment,
                      OUTPUT=output)

        return self.run_algprocessing(algname=algname, params=params)['OUTPUT']
    def _test_copy_selected(self,
                            input_layer_name,
                            output_layer_name,
                            select_id=1):
        print("### ", input_layer_name, output_layer_name)
        gpkg = get_test_file_copy_path('insert_features_to_layer_test.gpkg')

        input_layer_path = "{}|layername={}".format(gpkg, input_layer_name)
        output_layer_path = "{}|layername={}".format(gpkg, output_layer_name)
        input_layer = QgsVectorLayer(input_layer_path, 'layer name', 'ogr')
        self.assertTrue(input_layer.isValid())
        output_layer = QgsVectorLayer(output_layer_path, 'layer name', 'ogr')
        self.assertTrue(output_layer.isValid())
        QgsProject.instance().addMapLayers([input_layer, output_layer])

        input_layer.select(select_id)  # fid=1

        res = processing.run(
            "etl_load:appendfeaturestolayer", {
                'SOURCE_LAYER':
                QgsProcessingFeatureSourceDefinition(input_layer_path, True),
                'SOURCE_FIELD':
                None,
                'TARGET_LAYER':
                output_layer,
                'TARGET_FIELD':
                None,
                'ACTION_ON_DUPLICATE':
                0
            })  # No action

        self.assertIsNone(
            res[UPDATED_COUNT]
        )  # These are None because ACTION_ON_DUPLICATE is None
        self.assertIsNone(res[SKIPPED_COUNT])

        return res
Exemple #28
0
    def test_feature_source_definition(self):
        """
        Test that QgsProcessingFeatureSourceDefinition values are correctly loaded and written
        """
        doc = QDomDocument("properties")

        definition = QgsProcessingFeatureSourceDefinition(QgsProperty.fromValue('my source'))
        definition.selectedFeaturesOnly = True
        definition.featureLimit = 27
        definition.flags = QgsProcessingFeatureSourceDefinition.FlagCreateIndividualOutputPerInputFeature
        definition.geometryCheck = QgsFeatureRequest.GeometrySkipInvalid

        elem = QgsXmlUtils.writeVariant(definition, doc)
        c = QgsXmlUtils.readVariant(elem)
        self.assertEqual(c.source.staticValue(), 'my source')
        self.assertTrue(c.selectedFeaturesOnly)
        self.assertEqual(c.featureLimit, 27)
        self.assertEqual(c.flags, QgsProcessingFeatureSourceDefinition.FlagCreateIndividualOutputPerInputFeature)
        self.assertEqual(c.geometryCheck, QgsFeatureRequest.GeometrySkipInvalid)
Exemple #29
0
def execute_in_place_run(alg,
                         parameters,
                         context=None,
                         feedback=None,
                         raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :type context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :type feedback: QgsProcessingFeedback, optional
    :param raise_exceptions: useful for testing, if True exceptions are raised, normally exceptions will be forwarded to the feedback
    :type raise_exceptions: boo, default to False
    :raises QgsProcessingException: raised when there is no active layer, or it cannot be made editable
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    # Only feature based algs have sourceFlags
    try:
        if alg.sourceFlags(
        ) & QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks:
            context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)
    except AttributeError:
        pass

    active_layer = parameters['INPUT']

    # Run some checks and prepare the layer for in-place execution by:
    # - getting the active layer and checking that it is a vector
    # - making the layer editable if it was not already
    # - selecting all features if none was selected
    # - checking in-place support for the active layer/alg/parameters
    # If one of the check fails and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        if active_layer is None:
            raise QgsProcessingException(tr("There is not active layer."))

        if not isinstance(active_layer, QgsVectorLayer):
            raise QgsProcessingException(
                tr("Active layer is not a vector layer."))

        if not active_layer.isEditable():
            if not active_layer.startEditing():
                raise QgsProcessingException(
                    tr("Active layer is not editable (and editing could not be turned on)."
                       ))

        if not alg.supportInPlaceEdit(active_layer):
            raise QgsProcessingException(
                tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
                   ))
    except QgsProcessingException as e:
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing',
                                 Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)
        return False, {}

    if not active_layer.selectedFeatureIds():
        active_layer.selectAll()

    # Make sure we are working on selected features only
    parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(
        active_layer.id(), True)
    parameters['OUTPUT'] = 'memory:'

    req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
    req.setFlags(QgsFeatureRequest.NoGeometry)
    req.setSubsetOfAttributes([])

    # Start the execution
    # If anything goes wrong and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        new_feature_ids = []

        active_layer.beginEditCommand(alg.displayName())

        # Checks whether the algorithm has a processFeature method
        if hasattr(alg, 'processFeature'):  # in-place feature editing
            # Make a clone or it will crash the second time the dialog
            # is opened and run
            alg = alg.create()
            if not alg.prepare(parameters, context, feedback):
                raise QgsProcessingException(
                    tr("Could not prepare selected algorithm."))
            # Check again for compatibility after prepare
            if not alg.supportInPlaceEdit(active_layer):
                raise QgsProcessingException(
                    tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
                       ))
            field_idxs = range(len(active_layer.fields()))
            iterator_req = QgsFeatureRequest(active_layer.selectedFeatureIds())
            iterator_req.setInvalidGeometryCheck(
                context.invalidGeometryCheck())
            feature_iterator = active_layer.getFeatures(iterator_req)
            step = 100 / len(active_layer.selectedFeatureIds()
                             ) if active_layer.selectedFeatureIds() else 1
            for current, f in enumerate(feature_iterator):
                feedback.setProgress(current * step)
                if feedback.isCanceled():
                    break

                # need a deep copy, because python processFeature implementations may return
                # a shallow copy from processFeature
                input_feature = QgsFeature(f)
                new_features = alg.processFeature(input_feature, context,
                                                  feedback)
                new_features = QgsVectorLayerUtils.makeFeaturesCompatible(
                    new_features, active_layer)

                if len(new_features) == 0:
                    active_layer.deleteFeature(f.id())
                elif len(new_features) == 1:
                    new_f = new_features[0]
                    if not f.geometry().equals(new_f.geometry()):
                        active_layer.changeGeometry(f.id(), new_f.geometry())
                    if f.attributes() != new_f.attributes():
                        active_layer.changeAttributeValues(
                            f.id(), dict(zip(field_idxs, new_f.attributes())),
                            dict(zip(field_idxs, f.attributes())))
                    new_feature_ids.append(f.id())
                else:
                    active_layer.deleteFeature(f.id())
                    # Get the new ids
                    old_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    if not active_layer.addFeatures(new_features):
                        raise QgsProcessingException(
                            tr("Error adding processed features back into the layer."
                               ))
                    new_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    new_feature_ids += list(new_ids - old_ids)

            results, ok = {}, True

        else:  # Traditional 'run' with delete and add features cycle

            # There is no way to know if some features have been skipped
            # due to invalid geometries
            if context.invalidGeometryCheck(
            ) == QgsFeatureRequest.GeometrySkipInvalid:
                selected_ids = active_layer.selectedFeatureIds()
            else:
                selected_ids = []

            results, ok = alg.run(parameters, context, feedback)

            if ok:
                result_layer = QgsProcessingUtils.mapLayerFromString(
                    results['OUTPUT'], context)
                # TODO: check if features have changed before delete/add cycle

                new_features = []

                # Check if there are any skipped features
                if context.invalidGeometryCheck(
                ) == QgsFeatureRequest.GeometrySkipInvalid:
                    missing_ids = list(
                        set(selected_ids) - set(result_layer.allFeatureIds()))
                    if missing_ids:
                        for f in active_layer.getFeatures(
                                QgsFeatureRequest(missing_ids)):
                            if not f.geometry().isGeosValid():
                                new_features.append(f)

                active_layer.deleteFeatures(active_layer.selectedFeatureIds())

                for f in result_layer.getFeatures():
                    new_features.extend(
                        QgsVectorLayerUtils.makeFeaturesCompatible(
                            [f], active_layer))

                # Get the new ids
                old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                if not active_layer.addFeatures(new_features):
                    raise QgsProcessingException(
                        tr("Error adding processed features back into the layer."
                           ))
                new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                new_feature_ids += list(new_ids - old_ids)

        active_layer.endEditCommand()

        if ok and new_feature_ids:
            active_layer.selectByIds(new_feature_ids)
        elif not ok:
            active_layer.rollBack()

        return ok, results

    except QgsProcessingException as e:
        active_layer.endEditCommand()
        active_layer.rollBack()
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing',
                                 Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)

    return False, {}
Exemple #30
0
    def fill_right_of_way_relations(self, db):
        layers = {
            db.names.LC_ADMINISTRATIVE_SOURCE_T: None,
            db.names.LC_PARCEL_T: None,
            db.names.LC_PLOT_T: None,
            db.names.LC_RESTRICTION_T: None,
            db.names.LC_RESTRICTION_TYPE_D: None,
            db.names.LC_RIGHT_OF_WAY_T: None,
            db.names.COL_RRR_SOURCE_T: None,
            db.names.LC_SURVEY_POINT_T: None,
            db.names.COL_UE_BAUNIT_T: None
        }

        # Load layers
        self.app.core.get_layers(db, layers, load=True)
        if not layers:
            return None

        exp = "\"{}\" = '{}'".format(
            db.names.ILICODE_F,
            LADMNames.RESTRICTION_TYPE_D_RIGHT_OF_WAY_ILICODE_VALUE)
        restriction_right_of_way_t_id = [
            feature for feature in layers[
                db.names.LC_RESTRICTION_TYPE_D].getFeatures(exp)
        ][0][db.names.T_ID_F]

        if layers[db.names.LC_PLOT_T].selectedFeatureCount() == 0 or layers[
                db.names.LC_RIGHT_OF_WAY_T].selectedFeatureCount(
                ) == 0 or layers[
                    db.names.LC_ADMINISTRATIVE_SOURCE_T].selectedFeatureCount(
                    ) == 0:
            if self.app.core.get_ladm_layer_from_qgis(
                    db, db.names.LC_PLOT_T,
                    EnumLayerRegistryType.IN_LAYER_TREE) is None:
                self.logger.message_with_button_load_layer_emitted.emit(
                    QCoreApplication.translate(
                        "RightOfWay",
                        "First load the layer {} into QGIS and select at least one plot!"
                    ).format(db.names.LC_PLOT_T),
                    QCoreApplication.translate("RightOfWay",
                                               "Load layer {} now").format(
                                                   db.names.LC_PLOT_T),
                    db.names.LC_PLOT_T, Qgis.Warning)
            else:
                self.logger.warning_msg(
                    __name__,
                    QCoreApplication.translate(
                        "RightOfWay",
                        "Select at least one benefited plot, one right of way and at least one administrative source to create relations!"
                    ))
                return
        else:
            ue_baunit_features = layers[db.names.COL_UE_BAUNIT_T].getFeatures()
            # Get unique pairs id_right_of_way-id_parcel
            existing_pairs = [
                (ue_baunit_feature[db.names.COL_UE_BAUNIT_T_PARCEL_F],
                 ue_baunit_feature[db.names.COL_UE_BAUNIT_T_LC_RIGHT_OF_WAY_F])
                for ue_baunit_feature in ue_baunit_features
            ]
            existing_pairs = set(existing_pairs)

            plot_ids = [
                f[db.names.T_ID_F]
                for f in layers[db.names.LC_PLOT_T].selectedFeatures()
            ]

            right_of_way_id = layers[
                db.names.LC_RIGHT_OF_WAY_T].selectedFeatures()[0].attribute(
                    db.names.T_ID_F)
            id_pairs = list()
            for plot in plot_ids:
                exp = "\"{uebaunit}\" = {plot}".format(
                    uebaunit=db.names.COL_UE_BAUNIT_T_LC_PLOT_F, plot=plot)
                parcels = layers[db.names.COL_UE_BAUNIT_T].getFeatures(exp)
                for parcel in parcels:
                    id_pair = (parcel.attribute(
                        db.names.COL_UE_BAUNIT_T_PARCEL_F), right_of_way_id)
                    id_pairs.append(id_pair)

            if len(id_pairs) < len(plot_ids):
                # If any relationship plot-parcel is not found, we don't need to continue
                self.logger.warning_msg(
                    __name__,
                    QCoreApplication.translate(
                        "RightOfWay",
                        "One or more pairs id_plot-id_parcel weren't found, this is needed to create benefited and restriction relations."
                    ))
                return

            if id_pairs:
                new_features = list()
                for id_pair in id_pairs:
                    if not id_pair in existing_pairs:
                        #Create feature
                        new_feature = QgsVectorLayerUtils().createFeature(
                            layers[db.names.COL_UE_BAUNIT_T])
                        new_feature.setAttribute(
                            db.names.COL_UE_BAUNIT_T_PARCEL_F, id_pair[0])
                        new_feature.setAttribute(
                            db.names.COL_UE_BAUNIT_T_LC_RIGHT_OF_WAY_F,
                            id_pair[1])
                        self.logger.info(
                            __name__, "Saving RightOfWay-Parcel: {}-{}".format(
                                id_pair[1], id_pair[0]))
                        new_features.append(new_feature)

                layers[db.names.COL_UE_BAUNIT_T].dataProvider().addFeatures(
                    new_features)
                self.logger.info_msg(
                    __name__,
                    QCoreApplication.translate(
                        "RightOfWay",
                        "{} out of {} records were saved into {}! {} out of {} records already existed in the database."
                    ).format(len(new_features), len(id_pairs),
                             db.names.COL_UE_BAUNIT_T,
                             len(id_pairs) - len(new_features), len(id_pairs)))

            spatial_join_layer = processing.run(
                "qgis:joinattributesbylocation", {
                    'INPUT':
                    layers[db.names.LC_PLOT_T],
                    'JOIN':
                    QgsProcessingFeatureSourceDefinition(
                        layers[db.names.LC_RIGHT_OF_WAY_T].id(), True),
                    'PREDICATE': [0],
                    'JOIN_FIELDS': [db.names.T_ID_F],
                    'METHOD':
                    0,
                    'DISCARD_NONMATCHING':
                    True,
                    'PREFIX':
                    '',
                    'OUTPUT':
                    'memory:'
                })['OUTPUT']

            restriction_features = layers[
                db.names.LC_RESTRICTION_T].getFeatures()
            existing_restriction_pairs = [
                (restriction_feature[db.names.COL_BAUNIT_RRR_T_UNIT_F],
                 restriction_feature[db.names.COL_RRR_T_DESCRIPTION_F])
                for restriction_feature in restriction_features
            ]
            existing_restriction_pairs = set(existing_restriction_pairs)
            id_pairs_restriction = list()
            plot_ids = spatial_join_layer.getFeatures()

            for plot in plot_ids:
                exp = "\"uebaunit\" = {plot}".format(
                    uebaunit=db.names.COL_UE_BAUNIT_T_LC_PLOT_F,
                    plot=plot.attribute(db.names.T_ID_F))
                parcels = layers[db.names.COL_UE_BAUNIT_T].getFeatures(exp)
                for parcel in parcels:
                    id_pair_restriction = (parcel.attribute(
                        db.names.COL_UE_BAUNIT_T_PARCEL_F),
                                           QCoreApplication.translate(
                                               "RightOfWay", "Right of way"))
                    id_pairs_restriction.append(id_pair_restriction)

            new_restriction_features = list()
            if id_pairs_restriction:
                for id_pair in id_pairs_restriction:
                    if not id_pair in existing_restriction_pairs:
                        #Create feature
                        new_feature = QgsVectorLayerUtils().createFeature(
                            layers[db.names.LC_RESTRICTION_T])
                        new_feature.setAttribute(
                            db.names.COL_BAUNIT_RRR_T_UNIT_F, id_pair[0])
                        new_feature.setAttribute(
                            db.names.COL_RRR_T_DESCRIPTION_F, id_pair[1])
                        new_feature.setAttribute(
                            db.names.LC_RESTRICTION_T_TYPE_F,
                            restriction_right_of_way_t_id)
                        self.logger.info(
                            __name__, "Saving RightOfWay-Parcel: {}-{}".format(
                                id_pair[1], id_pair[0]))
                        new_restriction_features.append(new_feature)

                layers[db.names.LC_RESTRICTION_T].dataProvider().addFeatures(
                    new_restriction_features)
                self.logger.info_msg(
                    __name__,
                    QCoreApplication.translate(
                        "RightOfWay",
                        "{} out of {} records were saved into {}! {} out of {} records already existed in the database."
                    ).format(
                        len(new_restriction_features),
                        len(id_pairs_restriction), db.names.LC_RESTRICTION_T,
                        len(id_pairs_restriction) -
                        len(new_restriction_features),
                        len(id_pairs_restriction)))

            administrative_source_ids = [
                f[db.names.T_ID_F] for f in layers[
                    db.names.LC_ADMINISTRATIVE_SOURCE_T].selectedFeatures()
            ]

            source_relation_features = layers[
                db.names.COL_RRR_SOURCE_T].getFeatures()

            existing_source_pairs = [
                (source_relation_feature[db.names.COL_RRR_SOURCE_T_SOURCE_F],
                 source_relation_feature[
                     db.names.COL_RRR_SOURCE_T_LC_RESTRICTION_F])
                for source_relation_feature in source_relation_features
            ]
            existing_source_pairs = set(existing_source_pairs)

            rrr_source_relation_pairs = list()

            for administrative_source_id in administrative_source_ids:
                for restriction_feature in new_restriction_features:
                    rrr_source_relation_pair = (administrative_source_id,
                                                restriction_feature.attribute(
                                                    db.names.T_ID_F))
                    rrr_source_relation_pairs.append(rrr_source_relation_pair)

            new_rrr_source_relation_features = list()
            if rrr_source_relation_pairs:
                for id_pair in rrr_source_relation_pairs:
                    if not id_pair in existing_source_pairs:
                        new_feature = QgsVectorLayerUtils().createFeature(
                            layers[db.names.COL_RRR_SOURCE_T])
                        new_feature.setAttribute(
                            db.names.COL_RRR_SOURCE_T_SOURCE_F, id_pair[0])
                        new_feature.setAttribute(
                            db.names.COL_RRR_SOURCE_T_LC_RESTRICTION_F,
                            id_pair[1])
                        self.logger.info(
                            __name__,
                            "Saving Restriction-Source: {}-{}".format(
                                id_pair[1], id_pair[0]))
                        new_rrr_source_relation_features.append(new_feature)

                layers[db.names.COL_RRR_SOURCE_T].dataProvider().addFeatures(
                    new_rrr_source_relation_features)
                self.logger.info_msg(
                    __name__,
                    QCoreApplication.translate(
                        "RightOfWay",
                        "{} out of {} records were saved into {}! {} out of {} records already existed in the database."
                    ).format(
                        len(new_rrr_source_relation_features),
                        len(rrr_source_relation_pairs),
                        db.names.COL_RRR_SOURCE_T,
                        len(rrr_source_relation_pairs) -
                        len(new_rrr_source_relation_features),
                        len(rrr_source_relation_pairs)))