def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))

        geomType = self.multiToSingleGeom(layer.dataProvider().geometryType())

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            layer.pendingFields().toList(), geomType, layer.crs())

        outFeat = QgsFeature()
        inGeom = QgsGeometry()

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, f in enumerate(features):
            inGeom = f.geometry()
            attrs = f.attributes()

            geometries = self.extractAsSingle(inGeom)
            outFeat.setAttributes(attrs)

            for g in geometries:
                outFeat.setGeometry(g)
                writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
Example #2
0
    def testCreateUniqueValue(self):
        """ test creating a unique value """
        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
                               "addfeat", "memory")
        # add a bunch of features
        f = QgsFeature()
        f.setAttributes(["test", 123, 1.0])
        f1 = QgsFeature(2)
        f1.setAttributes(["test_1", 124, 1.1])
        f2 = QgsFeature(3)
        f2.setAttributes(["test_2", 125, 2.4])
        f3 = QgsFeature(4)
        f3.setAttributes(["test_3", 126, 1.7])
        f4 = QgsFeature(5)
        f4.setAttributes(["superpig", 127, 0.8])
        self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4]))

        # bad field indices
        self.assertFalse(QgsVectorLayerUtils.createUniqueValue(layer, -10))
        self.assertFalse(QgsVectorLayerUtils.createUniqueValue(layer, 10))

        # integer field
        self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 1), 128)

        # double field
        self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 2), 3.0)

        # string field
        self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0), 'test_4')
        self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'test_1'), 'test_4')
        self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'seed'), 'seed')
        self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'superpig'), 'superpig_1')
Example #3
0
    def test_ValueMap_representValue(self):
        layer = QgsVectorLayer("none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string",
                               "layer", "memory")
        assert layer.isValid()
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        f = QgsFeature()
        f.setAttributes([2, 2.5, 'NULL', None, None, None])
        assert layer.dataProvider().addFeatures([f])
        reg = QgsEditorWidgetRegistry.instance()
        factory = reg.factory("ValueMap")
        self.assertIsNotNone(factory)

        # Tests with different value types occurring in the value map
        config = {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL',
                  'nothing': self.VALUEMAP_NULL_TEXT}
        self.assertEqual(factory.representValue(layer, 0, config, None, 2), 'two')
        self.assertEqual(factory.representValue(layer, 1, config, None, 2.5), 'twoandhalf')
        self.assertEqual(factory.representValue(layer, 2, config, None, 'NULL'), 'NULL text')
        # Tests with null values of different types, if value map contains null
        self.assertEqual(factory.representValue(layer, 3, config, None, None), 'nothing')
        self.assertEqual(factory.representValue(layer, 4, config, None, None), 'nothing')
        self.assertEqual(factory.representValue(layer, 5, config, None, None), 'nothing')
        # Tests with fallback display for different value types
        config = {}
        self.assertEqual(factory.representValue(layer, 0, config, None, 2), '(2)')
        self.assertEqual(factory.representValue(layer, 1, config, None, 2.5), '(2.50000)')
        self.assertEqual(factory.representValue(layer, 2, config, None, 'NULL'), '(NULL)')
        # Tests with fallback display for null in different types of fields
        self.assertEqual(factory.representValue(layer, 3, config, None, None), '(NULL)')
        self.assertEqual(factory.representValue(layer, 4, config, None, None), '(NULL)')
        self.assertEqual(factory.representValue(layer, 5, config, None, None), '(NULL)')

        QgsMapLayerRegistry.instance().removeAllMapLayers()
Example #4
0
    def testGeopackageLargeFID(self):

        tmpfile = os.path.join(self.basetestpath, 'testGeopackageLargeFID.gpkg')
        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
        lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
        ds = None

        vl = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=" + "test", 'test', u'ogr')
        f = QgsFeature()
        f.setAttributes([1234567890123, None])
        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.dataProvider().addFeatures([f]))
        self.assertTrue(vl.commitChanges())

        got = [feat for feat in vl.getFeatures()][0]
        self.assertEqual(got['fid'], 1234567890123)

        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.changeGeometry(1234567890123, QgsGeometry.fromWkt('Point (3 50)')))
        self.assertTrue(vl.changeAttributeValue(1234567890123, 1, 'foo'))
        self.assertTrue(vl.commitChanges())

        got = [feat for feat in vl.getFeatures()][0]
        self.assertEqual(got['str_field'], 'foo')
        got_geom = got.geometry()
        self.assertIsNotNone(got_geom)

        self.assertTrue(vl.startEditing())
        self.assertTrue(vl.deleteFeature(1234567890123))
        self.assertTrue(vl.commitChanges())
    def processAlgorithm(self, progress):
        fieldname = self.getParameterValue(self.FIELD)
        output = self.getOutputFromName(self.OUTPUT)
        vlayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        vprovider = vlayer.dataProvider()
        fieldindex = vlayer.fieldNameIndex(fieldname)
        fields = vprovider.fields()
        fields.append(QgsField('NUM_FIELD', QVariant.Int))
        writer = output.getVectorWriter(fields, vprovider.geometryType(),
                                        vlayer.crs())
        outFeat = QgsFeature()
        classes = {}

        features = vector.features(vlayer)
        total = 100.0 / len(features)
        for current, feature in enumerate(features):
            progress.setPercentage(int(current * total))
            inGeom = feature.geometry()
            outFeat.setGeometry(inGeom)
            atMap = feature.attributes()
            clazz = atMap[fieldindex]

            if clazz not in classes:
                classes[clazz] = len(classes.keys())

            atMap.append(classes[clazz])
            outFeat.setAttributes(atMap)
            writer.addFeature(outFeat)

        del writer
    def testFilter(self):
        """ test calculating aggregate with filter """

        layer = QgsVectorLayer("Point?field=fldint:integer", "layer", "memory")
        pr = layer.dataProvider()

        int_values = [4, 2, 3, 2, 5, None, 8]

        features = []
        for v in int_values:
            f = QgsFeature()
            f.setFields(layer.fields())
            f.setAttributes([v])
            features.append(f)
        assert pr.addFeatures(features)

        agg = QgsAggregateCalculator(layer)

        filter_string = "fldint > 2"
        agg.setFilter(filter_string)
        self.assertEqual(agg.filter(), filter_string)

        val, ok = agg.calculate(QgsAggregateCalculator.Sum, 'fldint')
        self.assertTrue(ok)
        self.assertEqual(val, 20)

        # remove filter and retest
        agg.setFilter(None)
        val, ok = agg.calculate(QgsAggregateCalculator.Sum, 'fldint')
        self.assertTrue(ok)
        self.assertEqual(val, 24)
Example #7
0
    def createLayer(cls):
        vl = QgsVectorLayer(
            'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk',
            'test', 'pythonprovider')
        assert (vl.isValid())

        f1 = QgsFeature()
        f1.setAttributes([5, -200, NULL, 'NuLl', '5'])
        f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))

        f2 = QgsFeature()
        f2.setAttributes([3, 300, 'Pear', 'PEaR', '3'])

        f3 = QgsFeature()
        f3.setAttributes([1, 100, 'Orange', 'oranGe', '1'])
        f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)'))

        f4 = QgsFeature()
        f4.setAttributes([2, 200, 'Apple', 'Apple', '2'])
        f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)'))

        f5 = QgsFeature()
        f5.setAttributes([4, 400, 'Honey', 'Honey', '4'])
        f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)'))

        vl.dataProvider().addFeatures([f1, f2, f3, f4, f5])
        return vl
    def testAddMultipleFeatures(self):
        # test adding multiple features to an edit buffer
        layer = createEmptyLayer()
        self.assertTrue(layer.startEditing())

        self.assertEqual(layer.editBuffer().addedFeatures(), {})
        self.assertFalse(layer.editBuffer().isFeatureAdded(1))
        self.assertFalse(layer.editBuffer().isFeatureAdded(3))

        # add two features
        f1 = QgsFeature(layer.fields(), 1)
        f1.setGeometry(QgsGeometry.fromPoint(QgsPointXY(1, 2)))
        f1.setAttributes(["test", 123])
        f2 = QgsFeature(layer.fields(), 2)
        f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(2, 4)))
        f2.setAttributes(["test2", 246])

        self.assertTrue(layer.addFeatures([f1, f2]))

        # test contents of buffer
        added = layer.editBuffer().addedFeatures()
        new_feature_ids = list(added.keys())
        self.assertEqual(added[new_feature_ids[0]]['fldtxt'], 'test2')
        self.assertEqual(added[new_feature_ids[0]]['fldint'], 246)
        self.assertEqual(added[new_feature_ids[1]]['fldtxt'], 'test')
        self.assertEqual(added[new_feature_ids[1]]['fldint'], 123)

        self.assertTrue(layer.editBuffer().isFeatureAdded(new_feature_ids[0]))
        self.assertTrue(layer.editBuffer().isFeatureAdded(new_feature_ids[1]))
    def testDeleteMultipleFeatures(self):
        # test deleting multiple features from an edit buffer

        # make a layer with two features
        layer = createEmptyLayer()
        self.assertTrue(layer.startEditing())

        # add two features
        f1 = QgsFeature(layer.fields(), 1)
        f1.setGeometry(QgsGeometry.fromPoint(QgsPointXY(1, 2)))
        f1.setAttributes(["test", 123])
        self.assertTrue(layer.addFeature(f1))

        f2 = QgsFeature(layer.fields(), 2)
        f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(2, 4)))
        f2.setAttributes(["test2", 246])
        self.assertTrue(layer.addFeature(f2))

        layer.commitChanges()
        layer.startEditing()

        self.assertEqual(layer.editBuffer().deletedFeatureIds(), [])
        self.assertFalse(layer.editBuffer().isFeatureDeleted(1))
        self.assertFalse(layer.editBuffer().isFeatureDeleted(2))

        # delete features
        layer.deleteFeatures([1, 2])

        # test contents of buffer
        self.assertEqual(set(layer.editBuffer().deletedFeatureIds()), set([1, 2]))
        self.assertTrue(layer.editBuffer().isFeatureDeleted(1))
        self.assertTrue(layer.editBuffer().isFeatureDeleted(2))
Example #10
0
    def processAlgorithm(self, progress):
        fieldType = self.getParameterValue(self.FIELD_TYPE)
        fieldName = self.getParameterValue(self.FIELD_NAME)
        fieldLength = self.getParameterValue(self.FIELD_LENGTH)
        fieldPrecision = self.getParameterValue(self.FIELD_PRECISION)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))

        fields = layer.fields()
        fields.append(QgsField(fieldName, self.TYPES[fieldType], '',
                               fieldLength, fieldPrecision))
        writer = output.getVectorWriter(fields, layer.wkbType(),
                                        layer.crs())
        outFeat = QgsFeature()
        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, feat in enumerate(features):
            progress.setPercentage(int(current * total))
            geom = feat.geometry()
            outFeat.setGeometry(geom)
            atMap = feat.attributes()
            atMap.append(None)
            outFeat.setAttributes(atMap)
            writer.addFeature(outFeat)
        del writer
    def test_expressionRequiresFormScope(self):

        res = list(QgsValueRelationFieldFormatter.expressionFormAttributes("current_value('ONE') AND current_value('TWO')"))
        res = sorted(res)
        self.assertEqual(res, ['ONE', 'TWO'])

        res = list(QgsValueRelationFieldFormatter.expressionFormVariables("@current_geometry"))
        self.assertEqual(res, ['current_geometry'])

        self.assertFalse(QgsValueRelationFieldFormatter.expressionRequiresFormScope(""))
        self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresFormScope("current_value('TWO')"))
        self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresFormScope("current_value ( 'TWO' )"))
        self.assertTrue(QgsValueRelationFieldFormatter.expressionRequiresFormScope("@current_geometry"))

        self.assertTrue(QgsValueRelationFieldFormatter.expressionIsUsable("", QgsFeature()))
        self.assertFalse(QgsValueRelationFieldFormatter.expressionIsUsable("@current_geometry", QgsFeature()))
        self.assertFalse(QgsValueRelationFieldFormatter.expressionIsUsable("current_value ( 'TWO' )", QgsFeature()))

        layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string",
                               "layer", "memory")
        self.assertTrue(layer.isValid())
        QgsProject.instance().addMapLayer(layer)
        f = QgsFeature(layer.fields())
        f.setAttributes([1, 'value'])
        point = QgsGeometry.fromPointXY(QgsPointXY(123, 456))
        f.setGeometry(point)
        self.assertTrue(QgsValueRelationFieldFormatter.expressionIsUsable("current_geometry", f))
        self.assertFalse(QgsValueRelationFieldFormatter.expressionIsUsable("current_value ( 'TWO' )", f))
        self.assertTrue(QgsValueRelationFieldFormatter.expressionIsUsable("current_value ( 'pkid' )", f))
        self.assertTrue(QgsValueRelationFieldFormatter.expressionIsUsable("@current_geometry current_value ( 'pkid' )", f))

        QgsProject.instance().removeMapLayer(layer.id())
Example #12
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            layer.fields().toList(), QgsWkbTypes.Polygon, layer.crs()
        )

        outFeat = QgsFeature()
        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, f in enumerate(features):
            outGeomList = []
            if f.geometry().isMultipart():
                outGeomList = f.geometry().asMultiPolyline()
            else:
                outGeomList.append(f.geometry().asPolyline())

            polyGeom = self.removeBadLines(outGeomList)
            if len(polyGeom) != 0:
                outFeat.setGeometry(QgsGeometry.fromPolygon(polyGeom))
                attrs = f.attributes()
                outFeat.setAttributes(attrs)
                writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
Example #13
0
    def testAddFeature(self):
        if not getattr(self, 'getEditableLayer', None):
            return

        l = self.getEditableLayer()
        self.assertTrue(l.isValid())

        f1 = QgsFeature()
        f1.setAttributes([6, -220, NULL, 'String', '15'])
        f1.setGeometry(QgsGeometry.fromWkt('Point (-72.345 71.987)'))

        f2 = QgsFeature()
        f2.setAttributes([7, 330, 'Coconut', 'CoCoNut', '13'])

        if l.dataProvider().capabilities() & QgsVectorDataProvider.AddFeatures:
            # expect success
            result, added = l.dataProvider().addFeatures([f1, f2])
            self.assertTrue(result, 'Provider reported AddFeatures capability, but returned False to addFeatures')
            f1.setId(added[0].id())
            f2.setId(added[1].id())

            # check result
            self.testGetFeatures(l.dataProvider(), [f1, f2])

            # add empty list, should return true for consistency
            self.assertTrue(l.dataProvider().addFeatures([]))

        else:
            # expect fail
            self.assertFalse(l.dataProvider().addFeatures([f1, f2]),
                             'Provider reported no AddFeatures capability, but returned true to addFeatures')
    def layerOmmb(self, layer, writer, progress):
        current = 0

        fit = layer.getFeatures()
        inFeat = QgsFeature()
        total = 100.0 / layer.featureCount()
        newgeometry = QgsGeometry()
        first = True
        while fit.nextFeature(inFeat):
            if first:
                newgeometry = inFeat.geometry()
                first = False
            else:
                newgeometry = newgeometry.combine(inFeat.geometry())
            current += 1
            progress.setPercentage(int(current * total))

        geometry, area, perim, angle, width, height = self.OMBBox(newgeometry)

        if geometry:
            outFeat = QgsFeature()

            outFeat.setGeometry(geometry)
            outFeat.setAttributes([area,
                                   perim,
                                   angle,
                                   width,
                                   height])
            writer.addFeature(outFeat)
Example #15
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
        crsId = self.getParameterValue(self.TARGET_CRS)
        targetCrs = QgsCoordinateReferenceSystem()
        targetCrs.createFromUserInput(crsId)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            layer.fields().toList(), layer.wkbType(), targetCrs)

        layerCrs = layer.crs()
        crsTransform = QgsCoordinateTransform(layerCrs, targetCrs)

        outFeat = QgsFeature()
        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, f in enumerate(features):
            geom = f.geometry()
            geom.transform(crsTransform)
            outFeat.setGeometry(geom)
            outFeat.setAttributes(f.attributes())
            writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer

        self.crs = targetCrs
Example #16
0
    def test_representValue(self):
        QgsSettings().setValue("qgis/nullValue", "NULL")
        layer = QgsVectorLayer("none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string",
                               "layer", "memory")
        self.assertTrue(layer.isValid())
        QgsProject.instance().addMapLayer(layer)
        f = QgsFeature()
        f.setAttributes([2, 2.5, 'NULL', None, None, None])
        layer.dataProvider().addFeatures([f])
        fieldFormatter = QgsValueMapFieldFormatter()

        # Tests with different value types occurring in the value map
        config = {'map': {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL',
                          'nothing': self.VALUEMAP_NULL_TEXT}}
        self.assertEqual(fieldFormatter.representValue(layer, 0, config, None, 2), 'two')
        self.assertEqual(fieldFormatter.representValue(layer, 1, config, None, 2.5), 'twoandhalf')
        self.assertEqual(fieldFormatter.representValue(layer, 2, config, None, 'NULL'), 'NULL text')
        # Tests with null values of different types, if value map contains null
        self.assertEqual(fieldFormatter.representValue(layer, 3, config, None, None), 'nothing')
        self.assertEqual(fieldFormatter.representValue(layer, 4, config, None, None), 'nothing')
        self.assertEqual(fieldFormatter.representValue(layer, 5, config, None, None), 'nothing')
        # Tests with fallback display for different value types
        config = {}
        self.assertEqual(fieldFormatter.representValue(layer, 0, config, None, 2), '(2)')
        self.assertEqual(fieldFormatter.representValue(layer, 1, config, None, 2.5), '(2.50000)')
        self.assertEqual(fieldFormatter.representValue(layer, 2, config, None, 'NULL'), '(NULL)')
        # Tests with fallback display for null in different types of fields
        self.assertEqual(fieldFormatter.representValue(layer, 3, config, None, None), '(NULL)')
        self.assertEqual(fieldFormatter.representValue(layer, 4, config, None, None), '(NULL)')
        self.assertEqual(fieldFormatter.representValue(layer, 5, config, None, None), '(NULL)')

        QgsProject.instance().removeAllMapLayers()
Example #17
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_A))
        layerB = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_B))
        fieldA = self.getParameterValue(self.FIELD_A)
        fieldB = self.getParameterValue(self.FIELD_B)

        idxA = layerA.fields().lookupField(fieldA)
        idxB = layerB.fields().lookupField(fieldB)

        fieldList = [layerA.fields()[idxA],
                     layerB.fields()[idxB]]

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fieldList,
                                                                     QgsWkbTypes.Point, layerA.crs())

        spatialIndex = vector.spatialindex(layerB)

        outFeat = QgsFeature()
        features = vector.features(layerA)
        total = 100.0 / len(features)
        hasIntersections = False

        for current, inFeatA in enumerate(features):
            inGeom = inFeatA.geometry()
            hasIntersections = False
            lines = spatialIndex.intersects(inGeom.boundingBox())

            engine = None
            if len(lines) > 0:
                hasIntersections = True
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                engine.prepareGeometry()

            if hasIntersections:
                request = QgsFeatureRequest().setFilterFids(lines)
                for inFeatB in layerB.getFeatures(request):
                    tmpGeom = inFeatB.geometry()

                    points = []
                    attrsA = inFeatA.attributes()
                    attrsB = inFeatB.attributes()

                    if engine.intersects(tmpGeom.geometry()):
                        tempGeom = inGeom.intersection(tmpGeom)
                        if tempGeom.type() == QgsWkbTypes.PointGeometry:
                            if tempGeom.isMultipart():
                                points = tempGeom.asMultiPoint()
                            else:
                                points.append(tempGeom.asPoint())

                            for j in points:
                                outFeat.setGeometry(tempGeom.fromPoint(j))
                                outFeat.setAttributes([attrsA[idxA],
                                                       attrsB[idxB]])
                                writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        del writer
Example #18
0
    def test_link_feature(self):
        """
        Check if an existing feature can be linked
        """
        wrapper = self.createWrapper(self.vl_a, '"name"=\'Douglas Adams\'')  # NOQA

        f = QgsFeature(self.vl_b.fields())
        f.setAttributes([self.vl_b.dataProvider().defaultValueClause(0), 'The Hitchhiker\'s Guide to the Galaxy'])
        self.vl_b.addFeature(f)

        def choose_linked_feature():
            dlg = QApplication.activeModalWidget()
            dlg.setSelectedFeatures([f.id()])
            dlg.accept()

        btn = self.widget.findChild(QToolButton, 'mLinkFeatureButton')

        timer = QTimer()
        timer.setSingleShot(True)
        timer.setInterval(0)  # will run in the event loop as soon as it's processed when the dialog is opened
        timer.timeout.connect(choose_linked_feature)
        timer.start()

        btn.click()
        # magically the above code selects the feature here...

        link_feature = next(self.vl_link.getFeatures(QgsFeatureRequest().setFilterExpression('"fk_book"={}'.format(f[0]))))
        self.assertIsNotNone(link_feature[0])

        self.assertEqual(self.table_view.model().rowCount(), 1)
    def testSettingFeature(self):
        """ test that feature is set when item moves """
        a = QgsTextAnnotation()
        a.setFrameSizeMm(QSizeF(300 / 3.7795275, 200 / 3.7795275))
        a.setFrameOffsetFromReferencePointMm(QPointF(40 / 3.7795275, 50 / 3.7795275))
        a.setHasFixedMapPosition(True)
        a.setMapPosition(QgsPointXY(12, 34))
        a.setMapPositionCrs(QgsCoordinateReferenceSystem(4326))

        canvas = QgsMapCanvas()
        canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326))
        canvas.setFrameStyle(0)
        canvas.resize(600, 400)

        canvas.setExtent(QgsRectangle(10, 30, 20, 35))

        i = QgsMapCanvasAnnotationItem(a, canvas)  # NOQA

        layer = QgsVectorLayer("Point?crs=EPSG:4326&field=station:string&field=suburb:string",
                               'test', "memory")
        canvas.setLayers([layer])
        f = QgsFeature(layer.fields())
        f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(14, 31)))
        f.setValid(True)
        f.setAttributes(['hurstbridge', 'somewhere'])
        self.assertTrue(layer.dataProvider().addFeatures([f]))
        a.setMapLayer(layer)
        self.assertFalse(a.associatedFeature().isValid())

        a.setMapPosition(QgsPointXY(14, 31))
        self.assertTrue(a.associatedFeature().isValid())
        self.assertEqual(a.associatedFeature().attributes()[0], 'hurstbridge')

        a.setMapPosition(QgsPointXY(17, 31))
        self.assertFalse(a.associatedFeature().isValid())
Example #20
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
        values = source.uniqueValues(source.fields().lookupField(field_name))

        fields = QgsFields()
        field = source.fields()[source.fields().lookupField(field_name)]
        field.setName('VALUES')
        fields.append(field)
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
        results = {}
        if sink:
            for value in values:
                if feedback.isCanceled():
                    break

                f = QgsFeature()
                f.setAttributes([value])
                sink.addFeature(f, QgsFeatureSink.FastInsert)
            results[self.OUTPUT] = dest_id

        output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
        if output_file:
            self.createHTML(output_file, values)
            results[self.OUTPUT_HTML_FILE] = output_file

        results[self.TOTAL_VALUES] = len(values)
        results[self.UNIQUE_VALUES] = ';'.join([str(v) for v in
                                                values])
        return results
Example #21
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))

        writer = self.getOutputFromName(
            self.OUTPUT_LAYER).getVectorWriter(
                layer.fields(),
                QgsWkbTypes.Point,
                layer.crs())

        outFeat = QgsFeature()

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, feat in enumerate(features):
            inGeom = feat.geometry()
            attrs = feat.attributes()

            if inGeom.isEmpty():
                outGeom = QgsGeometry(None)
            else:
                outGeom = QgsGeometry(inGeom.centroid())
                if not outGeom:
                    raise GeoAlgorithmExecutionException(
                        self.tr('Error calculating centroid'))

            outFeat.setGeometry(outGeom)
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)
            progress.setPercentage(int(current * total))

        del writer
Example #22
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT))
        idx = layer.fieldNameIndex(self.getParameterValue(self.COLUMN))

        fields = layer.pendingFields()
        fields.remove(idx)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields,
            layer.wkbType(), layer.crs())

        features = vector.features(layer)
        count = len(features)
        total = 100.0 / float(count)

        feat = QgsFeature()
        for count, f in enumerate(features):
            feat.setGeometry(f.geometry())
            attributes = f.attributes()
            del attributes[idx]
            feat.setAttributes(attributes)
            writer.addFeature(feat)

            progress.setPercentage(int(count * total))

        del writer
Example #23
0
    def layerExtent(self, layer, writer, progress):
        rect = layer.extent()
        minx = rect.xMinimum()
        miny = rect.yMinimum()
        maxx = rect.xMaximum()
        maxy = rect.yMaximum()
        height = rect.height()
        width = rect.width()
        cntx = minx + width / 2.0
        cnty = miny + height / 2.0
        area = width * height
        perim = 2 * width + 2 * height

        rect = [QgsPoint(minx, miny), QgsPoint(minx, maxy), QgsPoint(maxx,
                maxy), QgsPoint(maxx, miny), QgsPoint(minx, miny)]
        geometry = QgsGeometry().fromPolygon([rect])
        feat = QgsFeature()
        feat.setGeometry(geometry)
        attrs = [
            minx,
            miny,
            maxx,
            maxy,
            cntx,
            cnty,
            area,
            perim,
            height,
            width,
        ]
        feat.setAttributes(attrs)
        writer.addFeature(feat)
Example #24
0
    def getSource(self):
        # create temporary table for edit tests
        self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.edit_data')
        self.execSQLCommand(
            """CREATE TABLE qgis_test.edit_data (pk INTEGER PRIMARY KEY,cnt integer, name nvarchar(max), name2 nvarchar(max), num_char nvarchar(max), geom geometry)""")

        vl = QgsVectorLayer(
            self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."edit_data" (geom) sql=',
            'test', 'mssql')

        self.assertTrue(vl.isValid(), vl.dataProvider().error().message())

        f1 = QgsFeature()
        f1.setAttributes([5, -200, NULL, 'NuLl', '5'])
        f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))

        f2 = QgsFeature()
        f2.setAttributes([3, 300, 'Pear', 'PEaR', '3'])

        f3 = QgsFeature()
        f3.setAttributes([1, 100, 'Orange', 'oranGe', '1'])
        f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)'))

        f4 = QgsFeature()
        f4.setAttributes([2, 200, 'Apple', 'Apple', '2'])
        f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)'))

        f5 = QgsFeature()
        f5.setAttributes([4, 400, 'Honey', 'Honey', '4'])
        f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)'))

        self.assertTrue(vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]))

        return vl
Example #25
0
    def layerOmmb(self, layer, writer, feedback):
        req = QgsFeatureRequest().setSubsetOfAttributes([])
        features = vector.features(layer, req)
        total = 100.0 / len(features)
        newgeometry = QgsGeometry()
        first = True
        for current, inFeat in enumerate(features):
            if first:
                newgeometry = inFeat.geometry()
                first = False
            else:
                newgeometry = newgeometry.combine(inFeat.geometry())
            feedback.setProgress(int(current * total))

        geometry, area, angle, width, height = newgeometry.orientedMinimumBoundingBox()

        if geometry:
            outFeat = QgsFeature()

            outFeat.setGeometry(geometry)
            outFeat.setAttributes([area,
                                   width * 2 + height * 2,
                                   angle,
                                   width,
                                   height])
            writer.addFeature(outFeat)
Example #26
0
    def test_check_validity(self):
        """Test that the output invalid contains the error reason"""

        polygon_layer = self._make_layer('Polygon')
        self.assertTrue(polygon_layer.startEditing())
        f = QgsFeature(polygon_layer.fields())
        f.setAttributes([1])
        # Flake!
        f.setGeometry(QgsGeometry.fromWkt(
            'POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))'))
        self.assertTrue(f.isValid())
        f2 = QgsFeature(polygon_layer.fields())
        f2.setAttributes([1])
        f2.setGeometry(QgsGeometry.fromWkt(
            'POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))'))
        self.assertTrue(f2.isValid())
        self.assertTrue(polygon_layer.addFeatures([f, f2]))
        polygon_layer.commitChanges()
        polygon_layer.rollBack()
        self.assertEqual(polygon_layer.featureCount(), 2)

        QgsProject.instance().addMapLayers([polygon_layer])

        alg = self.registry.createAlgorithmById('qgis:checkvalidity')

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

        self.assertIsNotNone(alg)
        parameters = {}
        parameters['INPUT_LAYER'] = polygon_layer.id()
        parameters['VALID_OUTPUT'] = 'memory:'
        parameters['INVALID_OUTPUT'] = 'memory:'
        parameters['ERROR_OUTPUT'] = 'memory:'

        # QGIS method
        parameters['METHOD'] = 1
        ok, results = execute(
            alg, parameters, context=context, feedback=feedback)
        self.assertTrue(ok)
        invalid_layer = QgsProcessingUtils.mapLayerFromString(
            results['INVALID_OUTPUT'], context)
        self.assertEqual(invalid_layer.fields().names()[-1], '_errors')
        self.assertEqual(invalid_layer.featureCount(), 1)
        f = next(invalid_layer.getFeatures())
        self.assertEqual(f.attributes(), [
                         1, 'segments 0 and 2 of line 0 intersect at 1, 1'])

        # GEOS method
        parameters['METHOD'] = 2
        ok, results = execute(
            alg, parameters, context=context, feedback=feedback)
        self.assertTrue(ok)
        invalid_layer = QgsProcessingUtils.mapLayerFromString(
            results['INVALID_OUTPUT'], context)
        self.assertEqual(invalid_layer.fields().names()[-1], '_errors')
        self.assertEqual(invalid_layer.featureCount(), 1)
        f = next(invalid_layer.getFeatures())
        self.assertEqual(f.attributes(), [1, 'Self-intersection'])
    def testWriteWithBinaryField(self):
        """
        Test writing with a binary field
        :return:
        """
        basetestpath = tempfile.mkdtemp()

        tmpfile = os.path.join(basetestpath, 'binaryfield.sqlite')
        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
        lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
        lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary))
        lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary))
        f = None
        ds = None

        vl = QgsVectorLayer(tmpfile)
        self.assertTrue(vl.isValid())

        # check that 1 of its fields is a bool
        fields = vl.fields()
        self.assertEqual(fields.at(fields.indexFromName('binfield')).type(), QVariant.ByteArray)

        dp = vl.dataProvider()
        f = QgsFeature(fields)
        bin_1 = b'xxx'
        bin_2 = b'yyy'
        bin_val1 = QByteArray(bin_1)
        bin_val2 = QByteArray(bin_2)
        f.setAttributes([1, 'str', 100, bin_val1, bin_val2])
        self.assertTrue(dp.addFeature(f))

        # write a gpkg package with a binary field
        filename = os.path.join(str(QDir.tempPath()), 'with_bin_field')
        rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl,
                                                             filename,
                                                             'utf-8',
                                                             vl.crs(),
                                                             'GPKG')

        self.assertEqual(rc, QgsVectorFileWriter.NoError)

        # open the resulting geopackage
        vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr')
        self.assertTrue(vl.isValid())
        fields = vl.fields()

        # test type of converted field
        idx = fields.indexFromName('binfield')
        self.assertEqual(fields.at(idx).type(), QVariant.ByteArray)
        idx2 = fields.indexFromName('binfield2')
        self.assertEqual(fields.at(idx2).type(), QVariant.ByteArray)

        # test values
        self.assertEqual(vl.getFeature(1).attributes()[idx], bin_val1)
        self.assertEqual(vl.getFeature(1).attributes()[idx2], bin_val2)

        del vl
        os.unlink(filename + '.gpkg')
Example #28
0
    def addFeatures(self, flist, flags=None):
        added = False
        f_added = []
        for f in flist:
            if f.hasGeometry() and (f.geometry().wkbType() != self.wkbType()):
                return added, f_added

        for f in flist:
            _f = QgsFeature(self.fields())
            _f.setGeometry(f.geometry())
            attrs = [None for i in range(_f.fields().count())]
            for i in range(min(len(attrs), len(f.attributes()))):
                attrs[i] = f.attributes()[i]
            _f.setAttributes(attrs)
            _f.setId(self.next_feature_id)
            self._features[self.next_feature_id] = _f
            self.next_feature_id += 1
            added = True
            f_added.append(_f)

            if self._spatialindex is not None:
                self._spatialindex.insertFeature(_f)

        if len(f_added):
            self.clearMinMaxCache()
            self.updateExtents()

        return added, f_added
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
        interval = self.getParameterValue(self.INTERVAL)

        isPolygon = layer.geometryType() == QgsWkbTypes.PolygonGeometry

        writer = self.getOutputFromName(
            self.OUTPUT).getVectorWriter(layer.fields().toList(),
                                         layer.wkbType(), layer.crs())

        features = vector.features(layer)
        total = 100.0 / len(features)
        for current, f in enumerate(features):
            featGeometry = f.geometry()
            attrs = f.attributes()
            newGeometry = self.densifyGeometry(featGeometry, interval,
                                               isPolygon)
            feature = QgsFeature()
            feature.setGeometry(newGeometry)
            feature.setAttributes(attrs)
            writer.addFeature(feature)

            progress.setPercentage(int(current * total))

        del writer
class_field_index = layer.fields().lookupField(class_field)
value_field_index = layer.fields().lookupField(value_field)

outFeat = QgsFeature()
classes = {}
feats = processing.features(layer)
nFeat = len(feats)
for n, inFeat in enumerate(feats):
    feedback.setProgress(int(100 * n / nFeat))
    attrs = inFeat.attributes()
    clazz = attrs[class_field_index]
    value = attrs[value_field_index]
    if clazz not in classes:
        classes[clazz] = []
    if value not in classes[clazz]:
        classes[clazz].append(value)

feats = processing.features(layer)
for n, inFeat in enumerate(feats):
    feedback.setProgress(int(100 * n / nFeat))
    inGeom = inFeat.geometry()
    outFeat.setGeometry(inGeom)
    attrs = inFeat.attributes()
    clazz = attrs[class_field_index]
    attrs.append(len(classes[clazz]))
    outFeat.setAttributes(attrs)
    writer.addFeature(outFeat)

del writer
Example #31
0
    def processAlgorithm(self, context, feedback):
        layer = self.getParameterValue(self.INPUT_LAYER)
        mapping = self.getParameterValue(self.FIELDS_MAPPING)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

        layer = dataobjects.getLayerFromString(layer)
        fields = []
        expressions = []

        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs())
        da.setEllipsoid(QgsProject.instance().ellipsoid())

        exp_context = layer.createExpressionContext()

        for field_def in mapping:
            fields.append(
                QgsField(name=field_def['name'],
                         type=field_def['type'],
                         len=field_def['length'],
                         prec=field_def['precision']))

            expression = QgsExpression(field_def['expression'])
            expression.setGeomCalculator(da)
            expression.setDistanceUnits(QgsProject.instance().distanceUnits())
            expression.setAreaUnits(QgsProject.instance().areaUnits())
            expression.prepare(exp_context)
            if expression.hasParserError():
                raise GeoAlgorithmExecutionException(
                    self.tr(u'Parser error in expression "{}": {}').format(
                        str(expression.expression()),
                        str(expression.parserErrorString())))
            expressions.append(expression)

        writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(),
                                        context)

        # Create output vector layer with new attributes
        error_exp = None
        inFeat = QgsFeature()
        outFeat = QgsFeature()
        features = QgsProcessingUtils.getFeatures(layer, context)
        count = QgsProcessingUtils.featureCount(layer, context)
        if count > 0:
            total = 100.0 / count
            for current, inFeat in enumerate(features):
                rownum = current + 1

                geometry = inFeat.geometry()
                outFeat.setGeometry(geometry)

                attrs = []
                for i in range(0, len(mapping)):
                    field_def = mapping[i]
                    expression = expressions[i]
                    exp_context.setFeature(inFeat)
                    exp_context.lastScope().setVariable("row_number", rownum)
                    value = expression.evaluate(exp_context)
                    if expression.hasEvalError():
                        error_exp = expression
                        break

                    attrs.append(value)
                outFeat.setAttributes(attrs)

                writer.addFeature(outFeat)

                feedback.setProgress(int(current * total))
        else:
            feedback.setProgress(100)

        del writer

        if error_exp is not None:
            raise GeoAlgorithmExecutionException(
                self.tr(u'Evaluation error in expression "{}": {}').format(
                    str(error_exp.expression()),
                    str(error_exp.parserErrorString())))
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        ueberhoehung = self.parameterAsInt(parameters, self.INPUTZFACTOR, context)
        rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUTRASTER, context)
        baseLineLayer = self.parameterAsVectorLayer(parameters, self.INPUTBASELINE, context)
        lineLayer =  self.parameterAsVectorLayer(parameters, self.INPUTINTERSECTIONLAYER, context)
        exprBaselineID = self.parameterAsExpression(parameters, self.SOURCE_BASLINE_ID, context)
        
        outputGeomType = 1 #Output Geometry Type Point

        # Retrieve the feature source and sink. The 'dest_id' variable is used
        # to uniquely identify the feature sink, and must be included in the
        # dictionary returned by the processAlgorithm function.
        fields=lineLayer.fields()
        fields.append( QgsField( "station" ,  QVariant.Double) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py)
        fields.append( QgsField( "z_factor" ,  QVariant.Int) ) 
        fields.append( QgsField( "profil_id" ,  QVariant.Int) ) 

        # If source was not found, throw an exception to indicate that the algorithm
        # encountered a fatal error. The exception text can be any string, but in this
        # case we use the pre-built invalidSourceError method to return a standard
        # helper text for when a source cannot be evaluated
        if lineLayer is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUTINTERSECTIONLAYER))

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            fields,
            outputGeomType,
            lineLayer.sourceCrs()
        )
        try:

            # Send some information to the user
            #feedback.pushInfo('CRS is {}'.format(lineLayer.sourceCrs().authid()))

            # If sink was not created, throw an exception to indicate that the algorithm
            # encountered a fatal error. The exception text can be any string, but in this
            # case we use the pre-built invalidSinkError method to return a standard
            # helper text for when a sink cannot be evaluated
            if sink is None:
                raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

            features=[] #QgsFeatureIterator
            if len( baseLineLayer.selectedFeatures() ) > 0:
                features = baseLineLayer.selectedFeatures()
            else:
                features = [feat for feat in baseLineLayer.getFeatures()]
            feedback.pushInfo( 'Features {} used'.format( len( features ) ) )

            # Compute the number of steps to display within the progress bar and
            # get features from source
            total = 100.0 / len( features ) if len( features ) else 0
            #names = [field.name()+"; " for field in fields]
            #feedback.pushInfo(''.join( names ) )
            #Clear Selection
            baseLineLayer.removeSelection()
            counter=0
            for current, feature in enumerate(features):
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    break
                
                expr = QgsExpression( exprBaselineID )
                exprContext = QgsExpressionContext()
                exprContext.setFeature(feature)
                
                profilID = expr.evaluate ( exprContext ) #, baseLineLayer.fields() )
                feedback.pushInfo(str(exprBaselineID) + ": Profil-ID: " + str(profilID) )
                #select to current feature
                baseLineLayer.select( feature.id() )
                #create profile feature for selected line 
                #if False:
                #feedback.pushInfo( "Selection " + str( lineLayer.selectedFeatureCount() ) + " Objects"  )
                feedback.pushInfo("Counter: " + str(counter) )
                profil_features = None
                try:
                    profil_features = self.runLineIntersection( lineLayer, baseLineLayer, rasterLayer, ueberhoehung, context, feedback)
                    count=0
                    for grFeature in profil_features:
                        #feedback.pushInfo("Type: " + str(type(grFeature)) )
                        if not str(type(grFeature)) == "<class 'qgis._core.QgsFeature'>":
                            feedback.pushInfo("Abbruch Type: " + str(type(grFeature)) )
                            break
                        feedback.pushInfo("Abbruch Type: " + str( grFeature.attributes() ) )

                        newFeature = QgsFeature( fields )
                        attrs = grFeature.attributes()
                        attrs.append( ueberhoehung )
                        attrs.append( profilID )
                    
                        newFeature.setAttributes( attrs )
                        newFeature.setGeometry( grFeature.geometry() )
                        # Add a feature in the sink
                        sink.addFeature( newFeature, QgsFeatureSink.FastInsert)
                        count=count+1
                    print( "Count: " + str(count) + ' at profile ' + str( profilID ) )
                    feedback.pushInfo("Count: " + str(count) + ' at profile ' + str( profilID ) )
                except Exception as err:
                    print("ERROR at profile " + str( profilID ) + ': '+ str(err.args) + " " + str(repr( err )) + " Fehler: "  )
                    feedback.pushInfo("ERROR at profile " + str( profilID ) + ': '+ str(err.args) + " " + str(repr( err )) + " Fehler: "  )


                #Clear Selection
                baseLineLayer.removeSelection()

                # Update the progress bar
                feedback.setProgress(int(current * total))
                counter=counter+1
        except Exception as err:
            feedback.pushInfo("ERROR: "+ str(err.args) + " " + str(repr( err )) + " Fehler: "  )
        #
        #    print("ERROR:", err.args, repr( err ), "Fehler: " )
        
        
        # To run another Processing algorithm as part of this algorithm, you can use
        # processing.run(...). Make sure you pass the current context and feedback
        # to processing.run to ensure that all temporary layer outputs are available
        # to the executed algorithm, and that the executed algorithm can send feedback
        # reports to the user (and correctly handle cancelation and progress reports!)

        # Return the results of the algorithm. In this case our only result is
        # the feature sink which contains the processed features, but some
        # algorithms may return multiple feature sinks, calculated numeric
        # statistics, etc. These should all be included in the returned
        # dictionary, with keys matching the feature corresponding parameter
        # or output names.
        return {self.OUTPUT: dest_id}
Example #33
0
    def test_representValue(self):
        QgsSettings().setValue("qgis/nullValue", "NULL")
        layer = QgsVectorLayer(
            "none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string",
            "layer", "memory")
        self.assertTrue(layer.isValid())
        QgsProject.instance().addMapLayer(layer)
        f = QgsFeature()
        f.setAttributes([2, 2.5, 'NULL', None, None, None])
        layer.dataProvider().addFeatures([f])
        fieldFormatter = QgsValueMapFieldFormatter()

        # Tests with different value types occurring in the value map
        # old style config (pre 3.0)
        config = {
            'map': {
                'two': '2',
                'twoandhalf': '2.5',
                'NULL text': 'NULL',
                'nothing': self.VALUEMAP_NULL_TEXT
            }
        }
        self.assertEqual(
            fieldFormatter.representValue(layer, 0, config, None, 2), 'two')
        self.assertEqual(
            fieldFormatter.representValue(layer, 1, config, None, 2.5),
            'twoandhalf')
        self.assertEqual(
            fieldFormatter.representValue(layer, 2, config, None, 'NULL'),
            'NULL text')
        # Tests with null values of different types, if value map contains null
        self.assertEqual(
            fieldFormatter.representValue(layer, 3, config, None, None),
            'nothing')
        self.assertEqual(
            fieldFormatter.representValue(layer, 4, config, None, None),
            'nothing')
        self.assertEqual(
            fieldFormatter.representValue(layer, 5, config, None, None),
            'nothing')

        # new style config (post 3.0)
        config = {
            'map': [{
                'two': '2'
            }, {
                'twoandhalf': '2.5'
            }, {
                'NULL text': 'NULL'
            }, {
                'nothing': self.VALUEMAP_NULL_TEXT
            }]
        }
        self.assertEqual(
            fieldFormatter.representValue(layer, 0, config, None, 2), 'two')
        self.assertEqual(
            fieldFormatter.representValue(layer, 1, config, None, 2.5),
            'twoandhalf')
        self.assertEqual(
            fieldFormatter.representValue(layer, 2, config, None, 'NULL'),
            'NULL text')
        # Tests with null values of different types, if value map contains null
        self.assertEqual(
            fieldFormatter.representValue(layer, 3, config, None, None),
            'nothing')
        self.assertEqual(
            fieldFormatter.representValue(layer, 4, config, None, None),
            'nothing')
        self.assertEqual(
            fieldFormatter.representValue(layer, 5, config, None, None),
            'nothing')

        # Tests with fallback display for different value types
        config = {}
        self.assertEqual(
            fieldFormatter.representValue(layer, 0, config, None, 2), '(2)')
        self.assertEqual(
            fieldFormatter.representValue(layer, 1, config, None, 2.5),
            '(2.50000)')
        self.assertEqual(
            fieldFormatter.representValue(layer, 2, config, None, 'NULL'),
            '(NULL)')
        # Tests with fallback display for null in different types of fields
        self.assertEqual(
            fieldFormatter.representValue(layer, 3, config, None, None),
            '(NULL)')
        self.assertEqual(
            fieldFormatter.representValue(layer, 4, config, None, None),
            '(NULL)')
        self.assertEqual(
            fieldFormatter.representValue(layer, 5, config, None, None),
            '(NULL)')

        QgsProject.instance().removeAllMapLayers()
Example #34
0
    def test_representValue(self):

        first_layer = QgsVectorLayer("none?field=foreign_key:integer",
                                     "first_layer", "memory")
        self.assertTrue(first_layer.isValid())
        second_layer = QgsVectorLayer(
            "none?field=pkid:integer&field=decoded:string", "second_layer",
            "memory")
        self.assertTrue(second_layer.isValid())
        QgsProject.instance().addMapLayers([first_layer, second_layer])
        f = QgsFeature()
        f.setAttributes([123])
        first_layer.dataProvider().addFeatures([f])
        f = QgsFeature()
        f.setAttributes([123, 'decoded_val'])
        second_layer.dataProvider().addFeatures([f])

        relMgr = QgsProject.instance().relationManager()

        fieldFormatter = QgsRelationReferenceFieldFormatter()

        rel = QgsRelation()
        rel.setId('rel1')
        rel.setName('Relation Number One')
        rel.setReferencingLayer(first_layer.id())
        rel.setReferencedLayer(second_layer.id())
        rel.addFieldPair('foreign_key', 'pkid')
        self.assertTrue(rel.isValid())

        relMgr.addRelation(rel)

        # Everything valid
        config = {'Relation': rel.id()}
        second_layer.setDisplayExpression('decoded')
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '123'),
            'decoded_val')

        # Code not find match in foreign layer
        config = {'Relation': rel.id()}
        second_layer.setDisplayExpression('decoded')
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '456'),
            '456')

        # Invalid relation id
        config = {'Relation': 'invalid'}
        second_layer.setDisplayExpression('decoded')
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '123'),
            '123')

        # No display expression
        config = {'Relation': rel.id()}
        second_layer.setDisplayExpression(None)
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '123'),
            '123')

        # Invalid display expression
        config = {'Relation': rel.id()}
        second_layer.setDisplayExpression('invalid +')
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '123'),
            '123')

        # Missing relation
        config = {}
        second_layer.setDisplayExpression('decoded')
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '123'),
            '123')

        # Inconsistent layer provided to representValue()
        config = {'Relation': rel.id()}
        second_layer.setDisplayExpression('decoded')
        self.assertEqual(
            fieldFormatter.representValue(second_layer, 0, config, None,
                                          '123'), '123')

        # Inconsistent idx provided to representValue()
        config = {'Relation': rel.id()}
        second_layer.setDisplayExpression('decoded')
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 1, config, None, '123'),
            '123')

        # Invalid relation
        rel = QgsRelation()
        rel.setId('rel2')
        rel.setName('Relation Number Two')
        rel.setReferencingLayer(first_layer.id())
        rel.addFieldPair('foreign_key', 'pkid')
        self.assertFalse(rel.isValid())

        relMgr.addRelation(rel)

        config = {'Relation': rel.id()}
        second_layer.setDisplayExpression('decoded')
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '123'),
            '123')

        QgsProject.instance().removeAllMapLayers()
Example #35
0
    def test_representValue(self):

        first_layer = QgsVectorLayer("none?field=foreign_key:integer",
                                     "first_layer", "memory")
        self.assertTrue(first_layer.isValid())
        second_layer = QgsVectorLayer(
            "none?field=pkid:integer&field=decoded:string", "second_layer",
            "memory")
        self.assertTrue(second_layer.isValid())
        QgsProject.instance().addMapLayer(second_layer)
        f = QgsFeature()
        f.setAttributes([123])
        first_layer.dataProvider().addFeatures([f])
        f = QgsFeature()
        f.setAttributes([123, 'decoded_val'])
        second_layer.dataProvider().addFeatures([f])

        fieldFormatter = QgsValueRelationFieldFormatter()

        # Everything valid
        config = {
            'Layer': second_layer.id(),
            'Key': 'pkid',
            'Value': 'decoded'
        }
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '123'),
            'decoded_val')

        # Code not find match in foreign layer
        config = {
            'Layer': second_layer.id(),
            'Key': 'pkid',
            'Value': 'decoded'
        }
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '456'),
            '(456)')

        # Missing Layer
        config = {'Key': 'pkid', 'Value': 'decoded'}
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '456'),
            '(456)')

        # Invalid Layer
        config = {'Layer': 'invalid', 'Key': 'pkid', 'Value': 'decoded'}
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '456'),
            '(456)')

        # Invalid Key
        config = {
            'Layer': second_layer.id(),
            'Key': 'invalid',
            'Value': 'decoded'
        }
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '456'),
            '(456)')

        # Invalid Value
        config = {
            'Layer': second_layer.id(),
            'Key': 'pkid',
            'Value': 'invalid'
        }
        self.assertEqual(
            fieldFormatter.representValue(first_layer, 0, config, None, '456'),
            '(456)')

        QgsProject.instance().removeMapLayer(second_layer.id())
Example #36
0
    def processAlgorithm(self, progress):
        lineLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.LINES))
        polyLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.POLYGONS))
        lengthFieldName = self.getParameterValue(self.LEN_FIELD)
        countFieldName = self.getParameterValue(self.COUNT_FIELD)

        polyProvider = polyLayer.dataProvider()

        (idxLength,
         fieldList) = vector.findOrCreateField(polyLayer,
                                               polyLayer.pendingFields(),
                                               lengthFieldName)
        (idxCount,
         fieldList) = vector.findOrCreateField(polyLayer, fieldList,
                                               countFieldName)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fieldList.toList(), polyProvider.geometryType(),
            polyProvider.crs())

        spatialIndex = vector.spatialindex(lineLayer)

        ftLine = QgsFeature()
        ftPoly = QgsFeature()
        outFeat = QgsFeature()
        inGeom = QgsGeometry()
        outGeom = QgsGeometry()
        distArea = QgsDistanceArea()

        current = 0
        features = vector.features(polyLayer)
        total = 100.0 / float(len(features))
        hasIntersections = False
        for ftPoly in features:
            inGeom = QgsGeometry(ftPoly.geometry())
            attrs = ftPoly.attributes()
            count = 0
            length = 0
            hasIntersections = False
            lines = spatialIndex.intersects(inGeom.boundingBox())
            if len(lines) > 0:
                hasIntersections = True

            if hasIntersections:
                for i in lines:
                    request = QgsFeatureRequest().setFilterFid(i)
                    ftLine = lineLayer.getFeatures(request).next()
                    tmpGeom = QgsGeometry(ftLine.geometry())
                    if inGeom.intersects(tmpGeom):
                        outGeom = inGeom.intersection(tmpGeom)
                        length += distArea.measure(outGeom)
                        count += 1

            outFeat.setGeometry(inGeom)
            if idxLength == len(attrs):
                attrs.append(length)
            else:
                attrs[idxLength] = length
            if idxCount == len(attrs):
                attrs.append(count)
            else:
                attrs[idxCount] = count
            outFeat.setAttributes(attrs)
            writer.addFeature(outFeat)

            current += 1
            progress.setPercentage(int(current * total))

        del writer
Example #37
0
    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))

        poly_source = self.parameterAsSource(parameters, self.POLYGONS, context)
        if poly_source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.POLYGONS))

        length_field_name = self.parameterAsString(parameters, self.LEN_FIELD, context)
        count_field_name = self.parameterAsString(parameters, self.COUNT_FIELD, context)

        fields = poly_source.fields()
        if fields.lookupField(length_field_name) < 0:
            fields.append(QgsField(length_field_name, QVariant.Double))
        length_field_index = fields.lookupField(length_field_name)
        if fields.lookupField(count_field_name) < 0:
            fields.append(QgsField(count_field_name, QVariant.Int))
        count_field_index = fields.lookupField(count_field_name)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, poly_source.wkbType(), poly_source.sourceCrs())
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        spatialIndex = QgsSpatialIndex(line_source.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs(), context.transformContext())), feedback)

        distArea = QgsDistanceArea()
        distArea.setSourceCrs(poly_source.sourceCrs(), context.transformContext())
        distArea.setEllipsoid(context.project().ellipsoid())

        features = poly_source.getFeatures()
        total = 100.0 / poly_source.featureCount() if poly_source.featureCount() else 0
        for current, poly_feature in enumerate(features):
            if feedback.isCanceled():
                break

            output_feature = QgsFeature()
            count = 0
            length = 0
            if poly_feature.hasGeometry():
                poly_geom = poly_feature.geometry()
                has_intersections = False
                lines = spatialIndex.intersects(poly_geom.boundingBox())
                engine = None
                if len(lines) > 0:
                    has_intersections = True
                    # use prepared geometries for faster intersection tests
                    engine = QgsGeometry.createGeometryEngine(poly_geom.constGet())
                    engine.prepareGeometry()

                if has_intersections:
                    request = QgsFeatureRequest().setFilterFids(lines).setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs(), context.transformContext())
                    for line_feature in line_source.getFeatures(request):
                        if feedback.isCanceled():
                            break

                        if engine.intersects(line_feature.geometry().constGet()):
                            outGeom = poly_geom.intersection(line_feature.geometry())
                            length += distArea.measureLength(outGeom)
                            count += 1

                output_feature.setGeometry(poly_geom)

            attrs = poly_feature.attributes()
            if length_field_index == len(attrs):
                attrs.append(length)
            else:
                attrs[length_field_index] = length
            if count_field_index == len(attrs):
                attrs.append(count)
            else:
                attrs[count_field_index] = count
            output_feature.setAttributes(attrs)
            sink.addFeature(output_feature, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #38
0
    def doCheck(self, method, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT_LAYER))

        (valid_output_sink,
         valid_output_dest_id) = self.parameterAsSink(parameters,
                                                      self.VALID_OUTPUT,
                                                      context, source.fields(),
                                                      source.wkbType(),
                                                      source.sourceCrs())
        valid_count = 0

        invalid_fields = source.fields()
        invalid_fields.append(
            QgsField('_errors', QVariant.String, 'string', 255))
        (invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink(
            parameters, self.INVALID_OUTPUT, context, invalid_fields,
            source.wkbType(), source.sourceCrs())
        invalid_count = 0

        error_fields = QgsFields()
        error_fields.append(QgsField('message', QVariant.String, 'string',
                                     255))
        (error_output_sink, error_output_dest_id) = self.parameterAsSink(
            parameters, self.ERROR_OUTPUT, context, error_fields,
            QgsWkbTypes.Point, source.sourceCrs())
        error_count = 0

        features = source.getFeatures(
            QgsFeatureRequest(),
            QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, inFeat in enumerate(features):
            if feedback.isCanceled():
                break
            geom = inFeat.geometry()
            attrs = inFeat.attributes()

            valid = True
            if not geom.isNull() and not geom.isEmpty():
                errors = list(geom.validateGeometry(method))
                if errors:
                    valid = False
                    reasons = []
                    for error in errors:
                        errFeat = QgsFeature()
                        error_geom = QgsGeometry.fromPointXY(error.where())
                        errFeat.setGeometry(error_geom)
                        errFeat.setAttributes([error.what()])
                        if error_output_sink:
                            error_output_sink.addFeature(
                                errFeat, QgsFeatureSink.FastInsert)
                        error_count += 1

                        reasons.append(error.what())

                    reason = "\n".join(reasons)
                    if len(reason) > 255:
                        reason = reason[:252] + '…'
                    attrs.append(reason)

            outFeat = QgsFeature()
            outFeat.setGeometry(geom)
            outFeat.setAttributes(attrs)

            if valid:
                if valid_output_sink:
                    valid_output_sink.addFeature(outFeat,
                                                 QgsFeatureSink.FastInsert)
                valid_count += 1

            else:
                if invalid_output_sink:
                    invalid_output_sink.addFeature(outFeat,
                                                   QgsFeatureSink.FastInsert)
                invalid_count += 1

            feedback.setProgress(int(current * total))

        results = {
            self.VALID_COUNT: valid_count,
            self.INVALID_COUNT: invalid_count,
            self.ERROR_COUNT: error_count
        }
        if valid_output_sink:
            results[self.VALID_OUTPUT] = valid_output_dest_id
        if invalid_output_sink:
            results[self.INVALID_OUTPUT] = invalid_output_dest_id
        if error_output_sink:
            results[self.ERROR_OUTPUT] = error_output_dest_id
        return results
Example #39
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_LAYER))

        fields = layer.fields()
        fields.append(QgsField('node_pos', QVariant.Int))
        fields.append(QgsField('node_index', QVariant.Int))
        fields.append(QgsField('distance', QVariant.Double))
        fields.append(QgsField('angle', QVariant.Double))

        writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(
            fields, QgsWkbTypes.Point, layer.crs())

        node_indices_string = self.getParameterValue(self.NODES)
        indices = []
        for node in node_indices_string.split(','):
            try:
                indices.append(int(node))
            except:
                raise GeoAlgorithmExecutionException(
                    self.tr('\'{}\' is not a valid node index').format(node))

        features = vector.features(layer)
        total = 100.0 / len(features)

        for current, f in enumerate(features):

            input_geometry = f.geometry()
            if not input_geometry:
                writer.addFeature(f)
            else:
                total_nodes = input_geometry.geometry().nCoordinates()

                for node in indices:
                    if node < 0:
                        node_index = total_nodes + node
                    else:
                        node_index = node

                    if node_index < 0 or node_index >= total_nodes:
                        continue

                    distance = input_geometry.distanceToVertex(node_index)
                    angle = math.degrees(
                        input_geometry.angleAtVertex(node_index))

                    output_feature = QgsFeature()
                    attrs = f.attributes()
                    attrs.append(node)
                    attrs.append(node_index)
                    attrs.append(distance)
                    attrs.append(angle)
                    output_feature.setAttributes(attrs)

                    point = input_geometry.vertexAt(node_index)
                    output_feature.setGeometry(QgsGeometry.fromPoint(point))

                    writer.addFeature(output_feature)

            progress.setPercentage(int(current * total))

        del writer
    def processAlgorithm(self, parameters, context, feedback):

        # Init ORS client
        providers = configmanager.read_config()['providers']
        provider = providers[self.parameterAsEnum(parameters, self.IN_PROVIDER,
                                                  context)]
        clnt = client.Client(provider)
        clnt.overQueryLimit.connect(
            lambda: feedback.reportError("OverQueryLimit: Retrying"))

        params = dict()

        # Get profile value
        profile = PROFILES[self.parameterAsEnum(parameters, self.IN_PROFILE,
                                                context)]

        # Get parameter values
        source = self.parameterAsSource(parameters, self.IN_START, context)
        source_field_name = self.parameterAsString(parameters,
                                                   self.IN_START_FIELD,
                                                   context)
        destination = self.parameterAsSource(parameters, self.IN_END, context)
        destination_field_name = self.parameterAsString(
            parameters, self.IN_END_FIELD, context)

        # Get fields from field name
        source_field_id = source.fields().lookupField(source_field_name)
        source_field = source.fields().field(source_field_id)

        destination_field_id = destination.fields().lookupField(
            destination_field_name)
        destination_field = destination.fields().field(destination_field_id)

        # Abort when MultiPoint type
        if (source.wkbType() or destination.wkbType()) == 4:
            raise QgsProcessingException(
                "TypeError: Multipoint Layers are not accepted. Please convert to single geometry layer."
            )

        # Get source and destination features
        sources_features = list(source.getFeatures())
        destination_features = list(destination.getFeatures())
        # Get feature amounts/counts
        sources_amount = source.featureCount()
        destinations_amount = destination.featureCount()

        # Allow for 50 features in source if source == destination
        source_equals_destination = parameters[
            'INPUT_START_LAYER'] == parameters['INPUT_END_LAYER']
        if source_equals_destination:
            features = sources_features
            xformer = transform.transformToWGS(source.sourceCrs())
            features_points = [
                xformer.transform(feat.geometry().asPoint())
                for feat in features
            ]
        else:
            xformer = transform.transformToWGS(source.sourceCrs())
            sources_features_xformed = [
                xformer.transform(feat.geometry().asPoint())
                for feat in sources_features
            ]

            xformer = transform.transformToWGS(destination.sourceCrs())
            destination_features_xformed = [
                xformer.transform(feat.geometry().asPoint())
                for feat in destination_features
            ]

            features_points = sources_features_xformed + destination_features_xformed

        # Get IDs
        sources_ids = list(
            range(sources_amount)) if source_equals_destination else list(
                range(sources_amount))
        destination_ids = list(
            range(sources_amount)) if source_equals_destination else list(
                range(sources_amount, sources_amount + destinations_amount))

        # Populate parameters further
        params.update({
            'locations': [[point.x(), point.y()] for point in features_points],
            'sources':
            sources_ids,
            'destinations':
            destination_ids,
            'metrics': ["duration", "distance"],
            'id':
            'Matrix'
        })

        # Make request and catch ApiError
        try:
            response = clnt.request('/v2/matrix/' + profile, {},
                                    post_json=params)

        except (exceptions.ApiError, exceptions.InvalidKey,
                exceptions.GenericServerError) as e:
            msg = "{}: {}".format(e.__class__.__name__, str(e))
            feedback.reportError(msg)
            logger.log(msg)

        (sink, dest_id) = self.parameterAsSink(
            parameters, self.OUT, context,
            self.get_fields(source_field.type(), destination_field.type()),
            QgsWkbTypes.NoGeometry)

        sources_attributes = [
            feat.attribute(source_field_name) for feat in sources_features
        ]
        destinations_attributes = [
            feat.attribute(destination_field_name)
            for feat in destination_features
        ]

        for s, source in enumerate(sources_attributes):
            for d, destination in enumerate(destinations_attributes):
                duration = response['durations'][s][d]
                distance = response['distances'][s][d]
                feat = QgsFeature()
                feat.setAttributes([
                    source, destination,
                    duration / 3600 if duration is not None else None,
                    distance / 1000 if distance is not None else None
                ])

                sink.addFeature(feat)

        return {self.OUT: dest_id}
    def ovals(self, sink, source, width, height, rotation, segments, feedback):
        features = source.getFeatures()
        ft = QgsFeature()

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        if rotation >= 0:
            for current, feat in enumerate(features):
                if feedback.isCanceled():
                    break

                if not feat.hasGeometry():
                    continue

                w = feat[width]
                h = feat[height]
                angle = feat[rotation]
                # block 0/NULL width or height, but allow 0 as angle value
                if not w or not h:
                    feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
                                                                 'width or height. '
                                                                 'Skipping…').format(feat.id()))
                    continue
                if angle == NULL:
                    feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
                                                                 'angle. '
                                                                 'Skipping…').format(feat.id()))
                    continue

                xOffset = w / 2.0
                yOffset = h / 2.0
                phi = angle * math.pi / 180

                point = feat.geometry().asPoint()
                x = point.x()
                y = point.y()
                points = []
                for t in [(2 * math.pi) / segments * i for i in range(segments)]:
                    points.append((xOffset * math.cos(t), yOffset * math.sin(t)))
                polygon = [[QgsPointXY(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x,
                                       -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points]]

                ft.setGeometry(QgsGeometry.fromPolygonXY(polygon))
                ft.setAttributes(feat.attributes())
                sink.addFeature(ft, QgsFeatureSink.FastInsert)
                feedback.setProgress(int(current * total))
        else:
            for current, feat in enumerate(features):
                if feedback.isCanceled():
                    break

                if not feat.hasGeometry():
                    continue

                w = feat[width]
                h = feat[height]
                if not w or not h:
                    feedback.pushInfo(QCoreApplication.translate('RectanglesOvalsDiamondsVariable', 'Feature {} has empty '
                                                                 'width or height. '
                                                                 'Skipping…').format(feat.id()))
                    continue

                xOffset = w / 2.0
                yOffset = h / 2.0

                point = feat.geometry().asPoint()
                x = point.x()
                y = point.y()
                points = []
                for t in [(2 * math.pi) / segments * i for i in range(segments)]:
                    points.append((xOffset * math.cos(t), yOffset * math.sin(t)))
                polygon = [[QgsPointXY(i[0] + x, i[1] + y) for i in points]]

                ft.setGeometry(QgsGeometry.fromPolygonXY(polygon))
                ft.setAttributes(feat.attributes())
                sink.addFeature(ft, QgsFeatureSink.FastInsert)
                feedback.setProgress(int(current * total))
Example #42
0
    def linearMatrix(self, parameters, context, source, inField, target_source,
                     targetField, same_source_and_target, matType, nPoints,
                     feedback):

        if same_source_and_target:
            # need to fetch an extra point from the index, since the closest match will always be the same
            # as the input feature
            nPoints += 1

        inIdx = source.fields().lookupField(inField)
        outIdx = target_source.fields().lookupField(targetField)

        fields = QgsFields()
        input_id_field = source.fields()[inIdx]
        input_id_field.setName('InputID')
        fields.append(input_id_field)
        if matType == 0:
            target_id_field = target_source.fields()[outIdx]
            target_id_field.setName('TargetID')
            fields.append(target_id_field)
            fields.append(QgsField('Distance', QVariant.Double))
        else:
            fields.append(QgsField('MEAN', QVariant.Double))
            fields.append(QgsField('STDDEV', QVariant.Double))
            fields.append(QgsField('MIN', QVariant.Double))
            fields.append(QgsField('MAX', QVariant.Double))

        out_wkb = QgsWkbTypes.multiType(
            source.wkbType()) if matType == 0 else source.wkbType()
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields, out_wkb,
                                               source.sourceCrs())
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        index = QgsSpatialIndex(
            target_source.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes(
                    []).setDestinationCrs(source.sourceCrs(),
                                          context.transformContext())),
            feedback)

        distArea = QgsDistanceArea()
        distArea.setSourceCrs(source.sourceCrs(), context.transformContext())
        distArea.setEllipsoid(context.project().ellipsoid())

        features = source.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes([inIdx]))
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, inFeat in enumerate(features):
            if feedback.isCanceled():
                break

            inGeom = inFeat.geometry()
            inID = str(inFeat[inIdx])
            featList = index.nearestNeighbor(inGeom.asPoint(), nPoints)
            distList = []
            vari = 0.0
            request = QgsFeatureRequest().setFilterFids(
                featList).setSubsetOfAttributes([outIdx]).setDestinationCrs(
                    source.sourceCrs(), context.transformContext())
            for outFeat in target_source.getFeatures(request):
                if feedback.isCanceled():
                    break

                if same_source_and_target and inFeat.id() == outFeat.id():
                    continue

                outID = outFeat[outIdx]
                outGeom = outFeat.geometry()
                dist = distArea.measureLine(inGeom.asPoint(),
                                            outGeom.asPoint())

                if matType == 0:
                    out_feature = QgsFeature()
                    out_geom = QgsGeometry.unaryUnion(
                        [inFeat.geometry(),
                         outFeat.geometry()])
                    out_feature.setGeometry(out_geom)
                    out_feature.setAttributes([inID, outID, dist])
                    sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
                else:
                    distList.append(float(dist))

            if matType != 0:
                mean = sum(distList) / len(distList)
                for i in distList:
                    vari += (i - mean) * (i - mean)
                vari = math.sqrt(vari / len(distList))

                out_feature = QgsFeature()
                out_feature.setGeometry(inFeat.geometry())
                out_feature.setAttributes(
                    [inID, mean, vari,
                     min(distList),
                     max(distList)])
                sink.addFeature(out_feature, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #43
0
    def processAlgorithm(self, context, feedback):
        layer = dataobjects.getLayerFromString(
            self.getParameterValue(self.INPUT))
        useField = self.getParameterValue(self.METHOD) == 1
        fieldName = self.getParameterValue(self.FIELD)

        f = QgsField('value', QVariant.String, '', 255)
        if useField:
            index = layer.fields().lookupField(fieldName)
            fType = layer.fields()[index].type()
            if fType in [
                    QVariant.Int, QVariant.UInt, QVariant.LongLong,
                    QVariant.ULongLong
            ]:
                f.setType(fType)
                f.setLength(20)
            elif fType == QVariant.Double:
                f.setType(QVariant.Double)
                f.setLength(20)
                f.setPrecision(6)
            else:
                f.setType(QVariant.String)
                f.setLength(255)

        fields = [
            QgsField('id', QVariant.Int, '', 20), f,
            QgsField('area', QVariant.Double, '', 20, 6),
            QgsField('perim', QVariant.Double, '', 20, 6)
        ]

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, QgsWkbTypes.Polygon, layer.crs(), context)

        outFeat = QgsFeature()
        inGeom = QgsGeometry()
        outGeom = QgsGeometry()

        fid = 0
        val = None
        features = QgsProcessingUtils.getFeatures(layer, context)
        if useField:
            unique = layer.uniqueValues(index)
            current = 0
            total = 100.0 / (QgsProcessingUtils.featureCount(layer, context) *
                             len(unique))
            for i in unique:
                first = True
                hull = []
                features = QgsProcessingUtils.getFeatures(layer, context)
                for f in features:
                    idVar = f[fieldName]
                    if str(idVar).strip() == str(i).strip():
                        if first:
                            val = idVar
                            first = False

                        inGeom = f.geometry()
                        points = vector.extractPoints(inGeom)
                        hull.extend(points)
                    current += 1
                    feedback.setProgress(int(current * total))

                if len(hull) >= 3:
                    tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull))
                    try:
                        outGeom = tmpGeom.convexHull()
                        (area, perim) = vector.simpleMeasure(outGeom)
                        outFeat.setGeometry(outGeom)
                        outFeat.setAttributes([fid, val, area, perim])
                        writer.addFeature(outFeat)
                    except:
                        raise GeoAlgorithmExecutionException(
                            self.tr('Exception while computing convex hull'))
                fid += 1
        else:
            hull = []
            total = 100.0 / layer.featureCount()
            features = QgsProcessingUtils.getFeatures(layer, context)
            for current, f in enumerate(features):
                inGeom = f.geometry()
                points = vector.extractPoints(inGeom)
                hull.extend(points)
                feedback.setProgress(int(current * total))

            tmpGeom = QgsGeometry(outGeom.fromMultiPoint(hull))
            try:
                outGeom = tmpGeom.convexHull()
                (area, perim) = vector.simpleMeasure(outGeom)
                outFeat.setGeometry(outGeom)
                outFeat.setAttributes([0, 'all', area, perim])
                writer.addFeature(outFeat)
            except:
                raise GeoAlgorithmExecutionException(
                    self.tr('Exception while computing convex hull'))

        del writer
Example #44
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

        fields = QgsFields()
        fields.append(QgsField('POINTA', QVariant.Double, '', 24, 15))
        fields.append(QgsField('POINTB', QVariant.Double, '', 24, 15))
        fields.append(QgsField('POINTC', QVariant.Double, '', 24, 15))

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.Polygon, source.sourceCrs())
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        pts = []
        ptDict = {}
        ptNdx = -1
        c = voronoi.Context()
        features = source.getFeatures()
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, inFeat in enumerate(features):
            if feedback.isCanceled():
                break

            geom = QgsGeometry(inFeat.geometry())
            if geom.isNull():
                continue
            if geom.isMultipart():
                points = geom.asMultiPoint()
            else:
                points = [geom.asPoint()]
            for n, point in enumerate(points):
                x = point.x()
                y = point.y()
                pts.append((x, y))
                ptNdx += 1
                ptDict[ptNdx] = (inFeat.id(), n)
            feedback.setProgress(int(current * total))

        if len(pts) < 3:
            raise QgsProcessingException(
                self.tr('Input file should contain at least 3 points. Choose '
                        'another file and try again.'))

        uniqueSet = set(item for item in pts)
        ids = [pts.index(item) for item in uniqueSet]
        sl = voronoi.SiteList([voronoi.Site(*i) for i in uniqueSet])
        c.triangulate = True
        voronoi.voronoi(sl, c)
        triangles = c.triangles
        feat = QgsFeature()

        total = 100.0 / len(triangles) if triangles else 1
        for current, triangle in enumerate(triangles):
            if feedback.isCanceled():
                break

            indices = list(triangle)
            indices.append(indices[0])
            polygon = []
            attrs = []
            step = 0
            for index in indices:
                fid, n = ptDict[ids[index]]
                request = QgsFeatureRequest().setFilterFid(fid)
                inFeat = next(source.getFeatures(request))
                geom = QgsGeometry(inFeat.geometry())
                if geom.isMultipart():
                    point = QgsPointXY(geom.asMultiPoint()[n])
                else:
                    point = QgsPointXY(geom.asPoint())
                polygon.append(point)
                if step <= 3:
                    attrs.append(ids[index])
                step += 1
            feat.setAttributes(attrs)
            geometry = QgsGeometry().fromPolygonXY([polygon])
            feat.setGeometry(geometry)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #45
0
    def regularMatrix(self, parameters, context, source, inField,
                      target_source, targetField, nPoints, feedback):

        distArea = QgsDistanceArea()
        distArea.setSourceCrs(source.sourceCrs(), context.transformContext())
        distArea.setEllipsoid(context.project().ellipsoid())

        inIdx = source.fields().lookupField(inField)
        targetIdx = target_source.fields().lookupField(targetField)

        index = QgsSpatialIndex(
            target_source.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes(
                    []).setDestinationCrs(source.sourceCrs(),
                                          context.transformContext())),
            feedback)

        first = True
        sink = None
        dest_id = None
        features = source.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes([inIdx]))
        total = 100.0 / source.featureCount() if source.featureCount() else 0
        for current, inFeat in enumerate(features):
            if feedback.isCanceled():
                break

            inGeom = inFeat.geometry()
            if first:
                featList = index.nearestNeighbor(inGeom.asPoint(), nPoints)
                first = False
                fields = QgsFields()
                input_id_field = source.fields()[inIdx]
                input_id_field.setName('ID')
                fields.append(input_id_field)
                for f in target_source.getFeatures(
                        QgsFeatureRequest().setFilterFids(
                            featList).setSubsetOfAttributes([
                                targetIdx
                            ]).setDestinationCrs(source.sourceCrs(),
                                                 context.transformContext())):
                    fields.append(
                        QgsField(str(f[targetField]), QVariant.Double))

                (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                                       context, fields,
                                                       source.wkbType(),
                                                       source.sourceCrs())
                if sink is None:
                    raise QgsProcessingException(
                        self.invalidSinkError(parameters, self.OUTPUT))

            data = [inFeat[inField]]
            for target in target_source.getFeatures(
                    QgsFeatureRequest().setSubsetOfAttributes(
                        []).setFilterFids(featList).setDestinationCrs(
                            source.sourceCrs(), context.transformContext())):
                if feedback.isCanceled():
                    break
                outGeom = target.geometry()
                dist = distArea.measureLine(inGeom.asPoint(),
                                            outGeom.asPoint())
                data.append(dist)

            out_feature = QgsFeature()
            out_feature.setGeometry(inGeom)
            out_feature.setAttributes(data)
            sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
Example #46
0
    def processAlgorithm(self, context, feedback):
        layerA = dataobjects.getLayerFromString(
            self.getParameterValue(self.INPUT_A))
        layerB = dataobjects.getLayerFromString(
            self.getParameterValue(self.INPUT_B))
        fieldA = self.getParameterValue(self.FIELD_A)
        fieldB = self.getParameterValue(self.FIELD_B)

        idxA = layerA.fields().lookupField(fieldA)
        idxB = layerB.fields().lookupField(fieldB)

        if idxA != -1:
            fieldListA = QgsFields()
            fieldListA.append(layerA.fields()[idxA])
        else:
            fieldListA = layerA.fields()

        if idxB != -1:
            fieldListB = QgsFields()
            fieldListB.append(layerB.fields()[idxB])
        else:
            fieldListB = layerB.fields()

        fieldListB = vector.testForUniqueness(fieldListA, fieldListB)
        fieldListA.extend(fieldListB)

        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fieldListA, QgsWkbTypes.Point, layerA.crs(), context)

        spatialIndex = vector.spatialindex(layerB)

        outFeat = QgsFeature()
        features = QgsProcessingUtils.getFeatures(layerA, context)
        total = 100.0 / QgsProcessingUtils.featureCount(layerA, context)
        hasIntersections = False

        for current, inFeatA in enumerate(features):
            inGeom = inFeatA.geometry()
            hasIntersections = False
            lines = spatialIndex.intersects(inGeom.boundingBox())

            engine = None
            if len(lines) > 0:
                hasIntersections = True
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                engine.prepareGeometry()

            if hasIntersections:
                request = QgsFeatureRequest().setFilterFids(lines)
                for inFeatB in layerB.getFeatures(request):
                    tmpGeom = inFeatB.geometry()

                    points = []
                    attrsA = inFeatA.attributes()
                    if idxA != -1:
                        attrsA = [attrsA[idxA]]
                    attrsB = inFeatB.attributes()
                    if idxB != -1:
                        attrsB = [attrsB[idxB]]

                    if engine.intersects(tmpGeom.geometry()):
                        tempGeom = inGeom.intersection(tmpGeom)
                        if tempGeom.type() == QgsWkbTypes.PointGeometry:
                            if tempGeom.isMultipart():
                                points = tempGeom.asMultiPoint()
                            else:
                                points.append(tempGeom.asPoint())

                            for j in points:
                                outFeat.setGeometry(tempGeom.fromPoint(j))
                                attrsA.extend(attrsB)
                                outFeat.setAttributes(attrsA)
                                writer.addFeature(outFeat)

            feedback.setProgress(int(current * total))

        del writer
Example #47
0
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

        geomType = QgsWkbTypes.multiType(sourceA.wkbType())

        fieldsA = self.parameterAsFields(parameters, self.INPUT_FIELDS,
                                         context)
        fieldsB = self.parameterAsFields(parameters, self.OVERLAY_FIELDS,
                                         context)

        fieldListA = QgsFields()
        field_indices_a = []
        if len(fieldsA) > 0:
            for f in fieldsA:
                idxA = sourceA.fields().lookupField(f)
                if idxA >= 0:
                    field_indices_a.append(idxA)
                    fieldListA.append(sourceA.fields()[idxA])
        else:
            fieldListA = sourceA.fields()
            field_indices_a = [i for i in range(0, fieldListA.count())]

        fieldListB = QgsFields()
        field_indices_b = []
        if len(fieldsB) > 0:
            for f in fieldsB:
                idxB = sourceB.fields().lookupField(f)
                if idxB >= 0:
                    field_indices_b.append(idxB)
                    fieldListB.append(sourceB.fields()[idxB])
        else:
            fieldListB = sourceB.fields()
            field_indices_b = [i for i in range(0, fieldListB.count())]

        output_fields = QgsProcessingUtils.combineFields(
            fieldListA, fieldListB)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, output_fields,
                                               geomType, sourceA.sourceCrs())

        outFeat = QgsFeature()
        indexB = QgsSpatialIndex(
            sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(
                []).setDestinationCrs(sourceA.sourceCrs())), feedback)

        total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1
        count = 0

        for featA in sourceA.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes(field_indices_a)):
            if feedback.isCanceled():
                break

            if not featA.hasGeometry():
                continue

            geom = featA.geometry()
            atMapA = featA.attributes()
            intersects = indexB.intersects(geom.boundingBox())

            request = QgsFeatureRequest().setFilterFids(intersects)
            request.setDestinationCrs(sourceA.sourceCrs())
            request.setSubsetOfAttributes(field_indices_b)

            engine = None
            if len(intersects) > 0:
                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(geom.constGet())
                engine.prepareGeometry()

            for featB in sourceB.getFeatures(request):
                if feedback.isCanceled():
                    break

                tmpGeom = featB.geometry()
                if engine.intersects(tmpGeom.constGet()):
                    out_attributes = [
                        featA.attributes()[i] for i in field_indices_a
                    ]
                    out_attributes.extend(
                        [featB.attributes()[i] for i in field_indices_b])
                    int_geom = QgsGeometry(geom.intersection(tmpGeom))
                    if int_geom.wkbType(
                    ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(
                            int_geom.wkbType(
                            )) == QgsWkbTypes.GeometryCollection:
                        int_com = geom.combine(tmpGeom)
                        int_geom = QgsGeometry()
                        if int_com:
                            int_sym = geom.symDifference(tmpGeom)
                            int_geom = QgsGeometry(int_com.difference(int_sym))
                    if int_geom.isEmpty() or not int_geom.isGeosValid():
                        raise QgsProcessingException(
                            self.tr('GEOS geoprocessing error: One or '
                                    'more input features have invalid '
                                    'geometry.'))
                    try:
                        if QgsWkbTypes.geometryType(int_geom.wkbType(
                        )) == QgsWkbTypes.geometryType(geomType):
                            int_geom.convertToMultiType()
                            outFeat.setGeometry(int_geom)
                            outFeat.setAttributes(out_attributes)
                            sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                    except:
                        raise QgsProcessingException(
                            self.tr('Feature geometry error: One or more '
                                    'output features ignored due to invalid '
                                    'geometry.'))

            count += 1
            feedback.setProgress(int(count * total))

        return {self.OUTPUT: dest_id}
Example #48
0
    def testFieldsWithSpecialCharacters(self):
        ml = QgsVectorLayer("Point?srid=EPSG:4326&field=123:int",
                            "mem_with_nontext_fieldnames", "memory")
        self.assertEqual(ml.isValid(), True)
        QgsProject.instance().addMapLayer(ml)

        ml.startEditing()
        self.assertTrue(ml.addAttribute(QgsField('abc:123', QVariant.String)))
        self.assertTrue(ml.addAttribute(QgsField(
            'map', QVariant.String)))  # matches QGIS expression function name
        f1 = QgsFeature(ml.fields())
        f1.setGeometry(QgsGeometry.fromWkt('POINT(0 0)'))
        f1.setAttributes([1, 'a', 'b'])
        f2 = QgsFeature(ml.fields())
        f2.setGeometry(QgsGeometry.fromWkt('POINT(1 1)'))
        f2.setAttributes([2, 'c', 'd'])
        ml.addFeatures([f1, f2])
        ml.commitChanges()

        vl = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames",
                            "vl", "virtual")
        self.assertEqual(vl.isValid(), True)
        self.assertEqual(vl.fields().at(0).name(), '123')
        self.assertEqual(vl.fields().at(1).name(), 'abc:123')

        self.assertEqual(vl.featureCount(), 2)

        features = [
            f for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                '"abc:123"=\'c\''))
        ]
        self.assertEqual(len(features), 1)
        self.assertEqual(features[0].attributes(), [2, 'c', 'd'])

        features = [
            f for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                '"map"=\'b\''))
        ]
        self.assertEqual(len(features), 1)
        self.assertEqual(features[0].attributes(), [1, 'a', 'b'])

        vl2 = QgsVectorLayer(
            "?query=select * from mem_with_nontext_fieldnames where \"abc:123\"='c'",
            "vl", "virtual")
        self.assertEqual(vl2.isValid(), True)
        self.assertEqual(vl2.fields().at(0).name(), '123')
        self.assertEqual(vl2.fields().at(1).name(), 'abc:123')

        self.assertEqual(vl2.featureCount(), 1)

        features = [f for f in vl2.getFeatures()]
        self.assertEqual(len(features), 1)
        self.assertEqual(features[0].attributes(), [2, 'c', 'd'])

        vl3 = QgsVectorLayer(
            "?query=select * from mem_with_nontext_fieldnames where \"map\"='b'",
            "vl", "virtual")
        self.assertEqual(vl3.isValid(), True)
        self.assertEqual(vl3.fields().at(0).name(), '123')
        self.assertEqual(vl3.fields().at(1).name(), 'abc:123')

        self.assertEqual(vl3.featureCount(), 1)

        features = [f for f in vl3.getFeatures()]
        self.assertEqual(len(features), 1)
        self.assertEqual(features[0].attributes(), [1, 'a', 'b'])

        QgsProject.instance().removeMapLayer(ml)
    def testFidSupport(self):

        # We do not use @unittest.expectedFailure since the test might actually succeed
        # on Linux 64bit with GDAL 1.11, where "long" is 64 bit...
        # GDAL 2.0 is guaranteed to properly support it on all platforms
        version_num = int(gdal.VersionInfo('VERSION_NUM'))
        if version_num < GDAL_COMPUTE_VERSION(2, 0, 0):
            return

        tmpfile = os.path.join(self.basetestpath, 'testFidSupport.sqlite')
        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
        lyr = ds.CreateLayer('test',
                             geom_type=ogr.wkbPoint,
                             options=['FID=fid'])
        lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
        lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
        f = ogr.Feature(lyr.GetLayerDefn())
        f.SetFID(12)
        f.SetField(0, 'foo')
        f.SetField(1, 123)
        lyr.CreateFeature(f)
        f = None
        ds = None

        vl = QgsVectorLayer('{}'.format(tmpfile), 'test', 'ogr')
        self.assertEqual(len(vl.fields()), 3)
        got = [(f.attribute('fid'), f.attribute('strfield'),
                f.attribute('intfield')) for f in vl.getFeatures()]
        self.assertEqual(got, [(12, 'foo', 123)])

        got = [(f.attribute('fid'), f.attribute('strfield'))
               for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                   "strfield = 'foo'"))]
        self.assertEqual(got, [(12, 'foo')])

        got = [(f.attribute('fid'), f.attribute('strfield'))
               for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                   "fid = 12"))]
        self.assertEqual(got, [(12, 'foo')])

        result = [
            f['strfield']
            for f in vl.dataProvider().getFeatures(QgsFeatureRequest(
            ).setSubsetOfAttributes(['strfield'],
                                    vl.dataProvider().fields()))
        ]
        self.assertEqual(result, ['foo'])

        result = [
            f['fid'] for f in vl.dataProvider().getFeatures(QgsFeatureRequest(
            ).setSubsetOfAttributes(['fid'],
                                    vl.dataProvider().fields()))
        ]
        self.assertEqual(result, [12])

        # Test that when the 'fid' field is not set, regular insertion is done
        f = QgsFeature()
        f.setFields(vl.fields())
        f.setAttributes([None, 'automatic_id'])
        (res, out_f) = vl.dataProvider().addFeatures([f])
        self.assertEqual(out_f[0].id(), 13)
        self.assertEqual(out_f[0].attribute('fid'), 13)
        self.assertEqual(out_f[0].attribute('strfield'), 'automatic_id')

        # Test that when the 'fid' field is set, it is really used to set the id
        f = QgsFeature()
        f.setFields(vl.fields())
        f.setAttributes([9876543210, 'bar'])
        (res, out_f) = vl.dataProvider().addFeatures([f])
        self.assertEqual(out_f[0].id(), 9876543210)
        self.assertEqual(out_f[0].attribute('fid'), 9876543210)
        self.assertEqual(out_f[0].attribute('strfield'), 'bar')

        got = [(f.attribute('fid'), f.attribute('strfield'))
               for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                   "fid = 9876543210"))]
        self.assertEqual(got, [(9876543210, 'bar')])

        self.assertTrue(vl.dataProvider().changeAttributeValues(
            {9876543210: {
                1: 'baz'
            }}))

        got = [(f.attribute('fid'), f.attribute('strfield'))
               for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                   "fid = 9876543210"))]
        self.assertEqual(got, [(9876543210, 'baz')])

        self.assertTrue(vl.dataProvider().changeAttributeValues(
            {9876543210: {
                0: 9876543210,
                1: 'baw'
            }}))

        got = [(f.attribute('fid'), f.attribute('strfield'))
               for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                   "fid = 9876543210"))]
        self.assertEqual(got, [(9876543210, 'baw')])

        # Not allowed: changing the fid regular field
        self.assertTrue(vl.dataProvider().changeAttributeValues(
            {9876543210: {
                0: 12,
                1: 'baw'
            }}))

        got = [(f.attribute('fid'), f.attribute('strfield'))
               for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression(
                   "fid = 9876543210"))]
        self.assertEqual(got, [(9876543210, 'baw')])

        # Cannot delete fid
        self.assertFalse(vl.dataProvider().deleteAttributes([0]))

        # Delete first "genuine" attribute
        self.assertTrue(vl.dataProvider().deleteAttributes([1]))

        got = [(f.attribute('fid'), f.attribute('intfield'))
               for f in vl.dataProvider().getFeatures(
                   QgsFeatureRequest().setFilterExpression("fid = 12"))]
        self.assertEqual(got, [(12, 123)])
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoints = self.parameterAsSource(parameters, self.START_POINTS, context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context)

        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = startPoints.fields()
        fields.append(QgsField('type', QVariant.String, '', 254, 0))
        fields.append(QgsField('start', QVariant.String, '', 254, 0))

        feat = QgsFeature()
        feat.setFields(fields)

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network,
                                          directionField,
                                          forwardValue,
                                          backwardValue,
                                          bothValue,
                                          defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField,
                                               defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(),
                                  True,
                                  tolerance)

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromLayer', 'Loading start points…'))
        request = QgsFeatureRequest()
        request.setDestinationCrs(network.sourceCrs(), context.transformContext())
        features = startPoints.getFeatures(request)
        total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0

        points = []
        source_attributes = {}
        i = 0
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            for p in f.geometry().vertices():
                points.append(QgsPointXY(p))
                source_attributes[i] = f.attributes()
                i += 1

            feedback.setProgress(int(current * total))

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromLayer', 'Building graph…'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(QCoreApplication.translate('ServiceAreaFromLayer', 'Calculating service areas…'))
        graph = builder.graph()

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, QgsWkbTypes.MultiPoint, network.sourceCrs())

        vertices = []
        upperBoundary = []
        lowerBoundary = []
        total = 100.0 / len(snappedPoints) if snappedPoints else 1
        for i, p in enumerate(snappedPoints):
            if feedback.isCanceled():
                break

            idxStart = graph.findVertex(snappedPoints[i])
            origPoint = points[i].toString()

            tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
            for j, v in enumerate(cost):
                if v > travelCost and tree[j] != -1:
                    vertexId = graph.edge(tree[j]).fromVertex()
                    if cost[vertexId] <= travelCost:
                        vertices.append(j)

            for j in vertices:
                upperBoundary.append(graph.vertex(graph.edge(tree[j]).toVertex()).point())
                lowerBoundary.append(graph.vertex(graph.edge(tree[j]).fromVertex()).point())

            geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
            geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

            feat.setGeometry(geomUpper)

            attrs = source_attributes[i]
            attrs.extend(['upper', origPoint])
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            feat.setGeometry(geomLower)
            attrs[-2] = 'lower'
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            vertices[:] = []
            upperBoundary[:] = []
            lowerBoundary[:] = []

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
Example #51
0
def buffering(feedback,
              context,
              sink,
              distance,
              field,
              useField,
              source,
              dissolve,
              segments,
              endCapStyle=1,
              joinStyle=1,
              miterLimit=2):

    if useField:
        field = source.fields().lookupField(field)

    outFeat = QgsFeature()

    current = 0
    total = 100.0 / source.featureCount() if source.featureCount() else 0

    # With dissolve
    if dissolve:
        attributes_to_fetch = []
        if useField:
            attributes_to_fetch.append(field)

        features = source.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes(attributes_to_fetch))
        buffered_geometries = []
        for inFeat in features:
            if feedback.isCanceled():
                break

            attrs = inFeat.attributes()
            if useField:
                value = attrs[field]
            else:
                value = distance

            inGeom = inFeat.geometry()

            buffered_geometries.append(
                inGeom.buffer(float(value), segments, endCapStyle, joinStyle,
                              miterLimit))

            current += 1
            feedback.setProgress(int(current * total))

        final_geometry = QgsGeometry.unaryUnion(buffered_geometries)
        outFeat.setGeometry(final_geometry)
        outFeat.setAttributes(attrs)
        sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
    else:

        features = source.getFeatures()

        # Without dissolve
        for inFeat in features:
            if feedback.isCanceled():
                break
            attrs = inFeat.attributes()
            if useField:
                value = attrs[field]
            else:
                value = distance
            inGeom = inFeat.geometry()
            outFeat = QgsFeature()
            outGeom = inGeom.buffer(float(value), segments, endCapStyle,
                                    joinStyle, miterLimit)
            outFeat.setGeometry(outGeom)
            outFeat.setAttributes(attrs)
            sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
            current += 1
            feedback.setProgress(int(current * total))
    def processAlgorithm(self, parameters, context, feedback):
        network = self.parameterAsSource(parameters, self.INPUT, context)
        startPoints = self.parameterAsSource(parameters, self.START_POINTS,
                                             context)
        endPoint = self.parameterAsPoint(parameters, self.END_POINT, context,
                                         network.sourceCrs())
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)

        directionFieldName = self.parameterAsString(parameters,
                                                    self.DIRECTION_FIELD,
                                                    context)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD,
                                              context)
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD,
                                               context)
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH,
                                           context)
        defaultDirection = self.parameterAsEnum(parameters,
                                                self.DEFAULT_DIRECTION,
                                                context)
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD,
                                                context)
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED,
                                              context)
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        fields = startPoints.fields()
        fields.append(QgsField('start', QVariant.String, '', 254, 0))
        fields.append(QgsField('end', QVariant.String, '', 254, 0))
        fields.append(QgsField('cost', QVariant.Double, '', 20, 7))

        feat = QgsFeature()
        feat.setFields(fields)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.LineString,
                                               network.sourceCrs())

        directionField = -1
        if directionFieldName:
            directionField = network.fields().lookupField(directionFieldName)
        speedField = -1
        if speedFieldName:
            speedField = network.fields().lookupField(speedFieldName)

        director = QgsVectorLayerDirector(network, directionField,
                                          forwardValue, backwardValue,
                                          bothValue, defaultDirection)

        distUnit = context.project().crs().mapUnits()
        multiplier = QgsUnitTypes.fromUnitToUnitFactor(
            distUnit, QgsUnitTypes.DistanceMeters)
        if strategy == 0:
            strategy = QgsNetworkDistanceStrategy()
        else:
            strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed,
                                               multiplier * 1000.0 / 3600.0)
            multiplier = 3600

        director.addStrategy(strategy)
        builder = QgsGraphBuilder(network.sourceCrs(), True, tolerance)

        feedback.pushInfo(self.tr('Loading start points...'))
        request = QgsFeatureRequest()
        request.setDestinationCrs(network.sourceCrs(),
                                  context.transformContext())
        features = startPoints.getFeatures(request)
        total = 100.0 / startPoints.featureCount() if startPoints.featureCount(
        ) else 0

        points = [endPoint]
        source_attributes = {}
        i = 1
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            for p in f.geometry().vertices():
                points.append(QgsPointXY(p))
                source_attributes[i] = f.attributes()
                i += 1

            feedback.setProgress(int(current * total))

        feedback.pushInfo(self.tr('Building graph...'))
        snappedPoints = director.makeGraph(builder, points, feedback)

        feedback.pushInfo(self.tr('Calculating shortest paths...'))
        graph = builder.graph()

        idxEnd = graph.findVertex(snappedPoints[0])

        nPoints = len(snappedPoints)
        total = 100.0 / nPoints if nPoints else 1
        for i in range(1, nPoints):
            if feedback.isCanceled():
                break

            idxStart = graph.findVertex(snappedPoints[i])

            tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)

            if tree[idxEnd] == -1:
                msg = self.tr(
                    'There is no route from start point ({}) to end point ({}).'
                    .format(points[i].toString(), endPoint.toString()))
                feedback.reportError(msg)
                # add feature with no geometry
                feat.clearGeometry()
                attrs = source_attributes[i]
                attrs.append(points[i].toString())
                feat.setAttributes(attrs)
                sink.addFeature(feat, QgsFeatureSink.FastInsert)
                continue

            route = [graph.vertex(idxEnd).point()]
            cost = costs[idxEnd]
            current = idxEnd
            while current != idxStart:
                current = graph.edge(tree[current]).fromVertex()
                route.append(graph.vertex(current).point())

            route.reverse()

            geom = QgsGeometry.fromPolylineXY(route)
            feat.setGeometry(geom)
            attrs = source_attributes[i]
            attrs.extend(
                [points[i].toString(),
                 endPoint.toString(), cost / multiplier])
            feat.setAttributes(attrs)
            sink.addFeature(feat, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(i * total))

        return {self.OUTPUT: dest_id}
Example #53
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """

        # Retrieve the feature source and sink. The 'dest_id' variable is used
        # to uniquely identify the feature sink, and must be included in the
        # dictionary returned by the processAlgorithm function.
        reseau = self.parameterAsVectorLayer(parameters, self.RESEAU, context)
        sens = self.parameterAsFields(parameters, self.SENS, context)
        ident = self.parameterAsFields(parameters, self.IDENT, context)
        prefixe = self.parameterAsString(parameters, self.PREFIXE, context)
        if len(sens) > 0:
            sens = sens[0]

        ##CEREMA=group
        ##reseau=vector line
        ##prefixe=optional string
        ##sens= field reseau
        ##fichier_noeuds=output vector
        layer = reseau
        nom_champs = []
        for i in layer.fields():
            nom_champs.append(i.name())
        if ("i" not in nom_champs):
            layer.dataProvider().addAttributes(
                [QgsField("i", QVariant.String, len=15)])
        if ("j" not in nom_champs):
            layer.dataProvider().addAttributes(
                [QgsField("j", QVariant.String, len=15)])
        if ("ij" not in nom_champs):
            layer.dataProvider().addAttributes(
                [QgsField("ij", QVariant.String, len=31)])
        layer.updateFields()
        layer.commitChanges()
        ida = layer.fields().indexFromName("i")
        idb = layer.fields().indexFromName("j")
        idij = layer.fields().indexFromName("ij")
        lines = layer.getFeatures()
        noeuds = {}
        #nom_fichier=fichier_noeuds
        champs = QgsFields()
        champs.append(QgsField("num", QVariant.String, len=35))
        champs.append(QgsField("nb", QVariant.Int))
        (table_noeuds, dest_id) = self.parameterAsSink(parameters, self.NOEUDS,
                                                       context, champs,
                                                       QgsWkbTypes.Point,
                                                       layer.sourceCrs())
        src = QgsCoordinateReferenceSystem(layer.crs())
        dest = QgsCoordinateReferenceSystem("EPSG:4326")
        xtr = QgsCoordinateTransform(src, dest, QgsProject.instance())
        for ligne in lines:
            if len(sens) == 0:
                test_sens = '1'
            else:
                if ligne[sens] == '1':
                    test_sens = '1'
                else:
                    test_sens = '0'
            gligne = ligne.geometry()
            if test_sens == '1':
                if gligne.wkbType() == QgsWkbTypes.MultiLineString:
                    g = gligne.asMultiPolyline()
                    na = g[0][0]
                    liba = str(
                        int(xtr.transform(na)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(na)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)
                    nb = g[-1][-1]
                    libb = str(
                        int(xtr.transform(nb)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(nb)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)

                elif gligne.wkbType() == QgsWkbTypes.LineString:
                    g = gligne.AsPolyline()
                    na = g[0]
                    liba = str(
                        int(xtr.transform(na)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(na)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)
                    nb = g[-1]
                    libb = str(
                        int(xtr.transform(nb)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(nb)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)
                if (na not in noeuds):
                    noeuds[na] = (prefixe + liba, 1)
                else:
                    noeuds[na] = (prefixe + liba, noeuds[na][1] + 1)
                if (nb not in noeuds):
                    noeuds[nb] = (prefixe + libb, 1)
                else:
                    noeuds[nb] = (prefixe + libb, noeuds[nb][1] + 1)
        #outs=open("c:/temp/noeuds.txt","w")
        for i, n in enumerate(noeuds):
            node = QgsFeature()
            node.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(n[0], n[1])))
            #node.setAttributes([noeuds[n]])
            #feedback.setProgressText(unicode(i)+" "+unicode(ident[0])+" "+unicode(ident[0]=='0'))
            if ident[0] == '0':
                noeuds[n] = (prefixe + unicode(i), noeuds[n][1])
                #feedback.setProgressText(unicode(noeuds[n][0]))
            node.setAttributes([noeuds[n][0], noeuds[n][1]])
            table_noeuds.addFeature(node)
        #outs.write(str(n)+";"+str(noeuds[n])+"\n")
        del table_noeuds
        #outs.close()
        lines = layer.getFeatures()
        layer.startEditing()
        layer.beginEditCommand(
            QCoreApplication.translate("Building graph", "Building graph"))
        for ligne in lines:
            if len(sens) == 0:
                test_sens = '1'
            else:
                if ligne[sens] == '1':
                    test_sens = '1'
                else:
                    test_sens = '0'
            if test_sens == '1':
                gligne = ligne.geometry()
                if gligne.wkbType() == QgsWkbTypes.MultiLineString:

                    g = gligne.asMultiPolyline()

                    na = g[0][0]
                    nb = g[-1][-1]
                    liba = str(
                        int(xtr.transform(na)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(na)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)
                    libb = str(
                        int(xtr.transform(nb)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(nb)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)
                elif gligne.wkbType() == QgsWkbTypes.LineString:

                    g = gligne.asPolyline()
                    na = g[0]
                    nb = g[-1]
                    liba = str(
                        int(xtr.transform(na)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(na)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)

                    libb = str(
                        int(xtr.transform(nb)[0] * 1e6 +
                            180 * 1e6)).zfill(9) + str(
                                int(xtr.transform(nb)[1] * 1e6 +
                                    180 * 1e6)).zfill(9)

                id = ligne.id()
                #valid={ida : noeuds[na], idb: noeuds[nb]}
                layer.changeAttributeValue(id, ida, unicode(noeuds[na][0]))
                layer.changeAttributeValue(id, idb, unicode(noeuds[nb][0]))
                layer.changeAttributeValue(
                    id, idij, unicode(noeuds[na][0] + "-" + noeuds[nb][0]))
        layer.commitChanges()
        layer.endEditCommand()
        return {self.NOEUDS: dest_id}
Example #54
0
    def testCreateExpression(self):
        """ Test creating an expression using the widget"""
        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "test", "memory")
        # setup value relation
        parent_layer = QgsVectorLayer("Point?field=stringkey:string&field=intkey:integer&field=display:string", "parent", "memory")
        f1 = QgsFeature(parent_layer.fields(), 1)
        f1.setAttributes(['a', 1, 'value a'])
        f2 = QgsFeature(parent_layer.fields(), 2)
        f2.setAttributes(['b', 2, 'value b'])
        f3 = QgsFeature(parent_layer.fields(), 3)
        f3.setAttributes(['c', 3, 'value c'])
        parent_layer.dataProvider().addFeatures([f1, f2, f3])
        QgsProject.instance().addMapLayers([layer, parent_layer])

        config = {"Layer": parent_layer.id(),
                  "Key": 'stringkey',
                  "Value": 'display'}

        w = QgsValueRelationSearchWidgetWrapper(layer, 0)
        w.setConfig(config)
        c = w.widget()

        # first, set it to the "select value" item
        c.setCurrentIndex(0)

        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '')

        c.setCurrentIndex(1)
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'a\'')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'a\'')
        c.setCurrentIndex(2)
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'b\'')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'b\'')

        # try with numeric field
        w = QgsValueRelationSearchWidgetWrapper(layer, 1)
        config['Key'] = 'intkey'
        w.setConfig(config)
        c = w.widget()
        c.setCurrentIndex(c.findText('value c'))
        self.assertEqual(c.currentIndex(), 3)
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=3')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>3')

        # try with allow null set
        w = QgsValueRelationSearchWidgetWrapper(layer, 1)
        config['AllowNull'] = True
        w.setConfig(config)
        c = w.widget()
        c.setCurrentIndex(c.findText('value c'))
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=3')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>3')

        # try with line edit
        w = QgsValueRelationSearchWidgetWrapper(layer, 1)
        config['UseCompleter'] = True
        w.setConfig(config)
        l = w.widget()
        l.setText('value b')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=2')
        self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>2')
Example #55
0
 def test_SetAttributes(self):
     feat = QgsFeature()
     feat.initAttributes(1)
     feat.setAttributes([0])
     feat.setAttributes([NULL])
     assert [NULL] == feat.attributes()
Example #56
0
    def testDuplicateFeature(self):
        """ test duplicating a feature """

        project = QgsProject().instance()

        # LAYERS
        # - add first layer (parent)
        layer1 = QgsVectorLayer("Point?field=fldtxt:string&field=pkid:integer",
                                "parentlayer", "memory")
        # > check first layer (parent)
        self.assertTrue(layer1.isValid())
        # -  set the value for the copy
        layer1.setDefaultValueDefinition(1, QgsDefaultValue("rand(1000,2000)"))
        # > check first layer (parent)
        self.assertTrue(layer1.isValid())
        # - add second layer (child)
        layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer",
                                "childlayer", "memory")
        # > check second layer (child)
        self.assertTrue(layer2.isValid())
        # - add layers
        project.addMapLayers([layer1, layer2])

        # FEATURES
        # - add 2 features on layer1 (parent)
        l1f1orig = QgsFeature()
        l1f1orig.setFields(layer1.fields())
        l1f1orig.setAttributes(["F_l1f1", 100])
        l1f2orig = QgsFeature()
        l1f2orig.setFields(layer1.fields())
        l1f2orig.setAttributes(["F_l1f2", 101])
        # > check by adding features
        self.assertTrue(layer1.dataProvider().addFeatures([l1f1orig, l1f2orig]))
        # add 4 features on layer2 (child)
        l2f1orig = QgsFeature()
        l2f1orig.setFields(layer2.fields())
        l2f1orig.setAttributes(["F_l2f1", 201, 100])
        l2f2orig = QgsFeature()
        l2f2orig.setFields(layer2.fields())
        l2f2orig.setAttributes(["F_l2f2", 202, 100])
        l2f3orig = QgsFeature()
        l2f3orig.setFields(layer2.fields())
        l2f3orig.setAttributes(["F_l2f3", 203, 100])
        l2f4orig = QgsFeature()
        l2f4orig.setFields(layer2.fields())
        l2f4orig.setAttributes(["F_l2f4", 204, 101])
        # > check by adding features
        self.assertTrue(layer2.dataProvider().addFeatures([l2f1orig, l2f2orig, l2f3orig, l2f4orig]))

        # RELATION
        # - create the relationmanager
        relMgr = project.relationManager()
        # - create the relation
        rel = QgsRelation()
        rel.setId('rel1')
        rel.setName('childrel')
        rel.setReferencingLayer(layer2.id())
        rel.setReferencedLayer(layer1.id())
        rel.addFieldPair('foreign_key', 'pkid')
        rel.setStrength(QgsRelation.Composition)
        # > check relation
        self.assertTrue(rel.isValid())
        # - add relation
        relMgr.addRelation(rel)
        # > check if referencedLayer is layer1
        self.assertEqual(rel.referencedLayer(), layer1)
        # > check if referencingLayer is layer2
        self.assertEqual(rel.referencingLayer(), layer2)
        # > check if the layers are correct in relation when loading from relationManager
        relations = project.relationManager().relations()
        relation = relations[list(relations.keys())[0]]
        # > check if referencedLayer is layer1
        self.assertEqual(relation.referencedLayer(), layer1)
        # > check if referencingLayer is layer2
        self.assertEqual(relation.referencingLayer(), layer2)
        # > check the relatedfeatures

        '''
        # testoutput 1
        print( "\nAll Features and relations")
        featit=layer1.getFeatures()
        f=QgsFeature()
        while featit.nextFeature(f):
            print( f.attributes())
            childFeature = QgsFeature()
            relfeatit=rel.getRelatedFeatures(f)
            while relfeatit.nextFeature(childFeature):
                 print( childFeature.attributes() )
        print( "\n--------------------------")

        print( "\nFeatures on layer1")
        for f in layer1.getFeatures():
            print( f.attributes() )

        print( "\nFeatures on layer2")
        for f in layer2.getFeatures():
            print( f.attributes() )
        '''

        # DUPLICATION
        # - duplicate feature l1f1orig with children
        layer1.startEditing()
        results = QgsVectorLayerUtils.duplicateFeature(layer1, l1f1orig, project, 0)

        # > check if name is name of duplicated (pk is different)
        result_feature = results[0]
        self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt'))
        # > check duplicated child layer
        result_layer = results[1].layers()[0]
        self.assertEqual(result_layer, layer2)
        #  > check duplicated child features
        self.assertTrue(results[1].duplicatedFeatures(result_layer))

        '''
        # testoutput 2
        print( "\nFeatures on layer1 (after duplication)")
        for f in layer1.getFeatures():
            print( f.attributes() )

        print( "\nFeatures on layer2 (after duplication)")
        for f in layer2.getFeatures():
            print( f.attributes() )
            
        print( "\nAll Features and relations")
        featit=layer1.getFeatures()
        f=QgsFeature()
        while featit.nextFeature(f):
            print( f.attributes())
            childFeature = QgsFeature()
            relfeatit=rel.getRelatedFeatures(f)
            while relfeatit.nextFeature(childFeature):
                 print( childFeature.attributes() )
        '''

        # > compare text of parent feature
        self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt'))

        # - create copyValueList
        childFeature = QgsFeature()
        relfeatit = rel.getRelatedFeatures(result_feature)
        copyValueList = []
        while relfeatit.nextFeature(childFeature):
            copyValueList.append(childFeature.attribute('fldtxt'))
        # - create origValueList
        childFeature = QgsFeature()
        relfeatit = rel.getRelatedFeatures(l1f1orig)
        origValueList = []
        while relfeatit.nextFeature(childFeature):
            origValueList.append(childFeature.attribute('fldtxt'))

        # - check if the ids are still the same
        self.assertEqual(copyValueList, origValueList)
Example #57
0
    def processAlgorithm(self, parameters, context, feedback):
        expr_context = self.createExpressionContext(parameters, context)
        self.group_by_expr.prepare(expr_context)

        # Group features in memory layers
        source = self.source
        count = self.source.featureCount()
        if count:
            progress_step = 50.0 / count
        current = 0
        groups = {}
        keys = []  # We need deterministic order for the tests
        feature = QgsFeature()
        for feature in self.source.getFeatures():
            expr_context.setFeature(feature)
            group_by_value = self.evaluateExpression(self.group_by_expr,
                                                     expr_context)

            # Get an hashable key for the dict
            key = group_by_value
            if isinstance(key, list):
                key = tuple(key)

            group = groups.get(key, None)
            if group is None:
                sink, id = QgsProcessingUtils.createFeatureSink(
                    'memory:', context, source.fields(), source.wkbType(),
                    source.sourceCrs())
                layer = QgsProcessingUtils.mapLayerFromString(id, context)
                group = {'sink': sink, 'layer': layer, 'feature': feature}
                groups[key] = group
                keys.append(key)

            group['sink'].addFeature(feature, QgsFeatureSink.FastInsert)

            current += 1
            feedback.setProgress(int(current * progress_step))
            if feedback.isCanceled():
                return

        (sink, dest_id) = self.parameterAsSink(
            parameters, self.OUTPUT, context, self.fields,
            QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())

        # Calculate aggregates on memory layers
        if len(keys):
            progress_step = 50.0 / len(keys)
        for current, key in enumerate(keys):
            group = groups[key]
            expr_context = self.createExpressionContext(parameters, context)
            expr_context.appendScope(
                QgsExpressionContextUtils.layerScope(group['layer']))
            expr_context.setFeature(group['feature'])

            geometry = self.evaluateExpression(self.geometry_expr,
                                               expr_context)
            if geometry is not None and not geometry.isEmpty():
                geometry = QgsGeometry.unaryUnion(
                    geometry.asGeometryCollection())
                if geometry.isEmpty():
                    raise QgsProcessingException(
                        'Impossible to combine geometries for {} = {}'.format(
                            self.group_by, group_by_value))

            attrs = []
            for fields_expr in self.fields_expr:
                attrs.append(self.evaluateExpression(fields_expr,
                                                     expr_context))

            # Write output feature
            outFeat = QgsFeature()
            if geometry is not None:
                outFeat.setGeometry(geometry)
            outFeat.setAttributes(attrs)
            sink.addFeature(outFeat, QgsFeatureSink.FastInsert)

            feedback.setProgress(50 + int(current * progress_step))
            if feedback.isCanceled():
                return

        return {self.OUTPUT: dest_id}
Example #58
0
    def testOverwriteLayer(self):
        """Tests writing a layer with a field value converter."""

        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([1])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename, update=1)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 1)
        ds.CreateLayer('another_layer')
        del f
        del lyr
        del ds

        caps = QgsVectorFileWriter.editionCapabilities(filename)
        self.assertTrue((caps & QgsVectorFileWriter.CanAddNewLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanAppendToExistingLayer))
        self.assertTrue(
            (caps & QgsVectorFileWriter.CanAddNewFieldsToExistingLayer))
        self.assertTrue((caps & QgsVectorFileWriter.CanDeleteLayer))

        self.assertTrue(QgsVectorFileWriter.targetLayerExists(
            filename, 'test'))

        self.assertFalse(
            QgsVectorFileWriter.areThereNewFieldsToCreate(
                filename, 'test', ml, [0]))

        # Test CreateOrOverwriteLayer
        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([2])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 2)
        # another_layer should still exist
        self.assertIsNotNone(ds.GetLayerByName('another_layer'))
        del f
        del lyr
        del ds

        # Test CreateOrOverwriteFile
        ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([3])
        provider.addFeatures([ft])

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        # another_layer should no longer exist
        self.assertIsNone(ds.GetLayerByName('another_layer'))
        del f
        del lyr
        del ds

        # Test AppendToLayerNoNewFields
        ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int',
                            'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([4, -10])
        provider.addFeatures([ft])

        self.assertTrue(
            QgsVectorFileWriter.areThereNewFieldsToCreate(
                filename, 'test', ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerNoNewFields
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 1)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 4)
        del f
        del lyr
        del ds

        # Test AppendToLayerAddFields
        ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int',
                            'test', 'memory')
        provider = ml.dataProvider()

        ft = QgsFeature()
        ft.setAttributes([5, -1])
        provider.addFeatures([ft])

        self.assertTrue(
            QgsVectorFileWriter.areThereNewFieldsToCreate(
                filename, 'test', ml, [0, 1]))

        options = QgsVectorFileWriter.SaveVectorOptions()
        options.driverName = 'GPKG'
        options.layerName = 'test'
        options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerAddFields
        filename = '/vsimem/out.gpkg'
        write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat(
            ml, filename, options)
        self.assertEqual(write_result, QgsVectorFileWriter.NoError,
                         error_message)

        ds = ogr.Open(filename)
        lyr = ds.GetLayerByName('test')
        self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 2)
        self.assertIsNotNone(lyr)
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 3)
        if hasattr(f, "IsFieldSetAndNotNull"):
            # GDAL >= 2.2
            self.assertFalse(f.IsFieldSetAndNotNull('secondfield'))
        else:
            self.assertFalse(f.IsFieldSet('secondfield'))
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 4)
        if hasattr(f, "IsFieldSetAndNotNull"):
            self.assertFalse(f.IsFieldSetAndNotNull('secondfield'))
        else:
            self.assertFalse(f.IsFieldSet('secondfield'))
        f = lyr.GetNextFeature()
        self.assertEqual(f['firstfield'], 5)
        self.assertEqual(f['secondfield'], -1)
        del f
        del lyr
        del ds

        gdal.Unlink(filename)
Example #59
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))

        field_name = self.parameterAsString(parameters, self.FIELD, context)
        type = self.parameterAsEnum(parameters, self.TYPE, context)
        use_field = bool(field_name)

        field_index = -1

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 20))

        if use_field:
            # keep original field type, name and parameters
            field_index = source.fields().lookupField(field_name)
            if field_index >= 0:
                fields.append(source.fields()[field_index])
        if type == 0:
            # envelope
            fields.append(QgsField('width', QVariant.Double, '', 20, 6))
            fields.append(QgsField('height', QVariant.Double, '', 20, 6))
            fields.append(QgsField('area', QVariant.Double, '', 20, 6))
            fields.append(QgsField('perimeter', QVariant.Double, '', 20, 6))
        elif type == 1:
            # oriented rect
            fields.append(QgsField('width', QVariant.Double, '', 20, 6))
            fields.append(QgsField('height', QVariant.Double, '', 20, 6))
            fields.append(QgsField('angle', QVariant.Double, '', 20, 6))
            fields.append(QgsField('area', QVariant.Double, '', 20, 6))
            fields.append(QgsField('perimeter', QVariant.Double, '', 20, 6))
        elif type == 2:
            # circle
            fields.append(QgsField('radius', QVariant.Double, '', 20, 6))
            fields.append(QgsField('area', QVariant.Double, '', 20, 6))
        elif type == 3:
            # convex hull
            fields.append(QgsField('area', QVariant.Double, '', 20, 6))
            fields.append(QgsField('perimeter', QVariant.Double, '', 20, 6))

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               QgsWkbTypes.Polygon,
                                               source.sourceCrs())
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

        if field_index >= 0:
            geometry_dict = {}
            bounds_dict = {}
            total = 50.0 / source.featureCount() if source.featureCount(
            ) else 1
            features = source.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes([field_index]))
            for current, f in enumerate(features):
                if feedback.isCanceled():
                    break

                if not f.hasGeometry():
                    continue

                if type == 0:
                    # bounding boxes - calculate on the fly for efficiency
                    if not f[field_index] in bounds_dict:
                        bounds_dict[
                            f[field_index]] = f.geometry().boundingBox()
                    else:
                        bounds_dict[f[field_index]].combineExtentWith(
                            f.geometry().boundingBox())
                else:
                    if not f[field_index] in geometry_dict:
                        geometry_dict[f[field_index]] = [f.geometry()]
                    else:
                        geometry_dict[f[field_index]].append(f.geometry())

                feedback.setProgress(int(current * total))

            if type == 0:
                # bounding boxes
                current = 0
                total = 50.0 / len(bounds_dict) if bounds_dict else 1
                for group, rect in bounds_dict.items():
                    if feedback.isCanceled():
                        break

                    # envelope
                    feature = QgsFeature()
                    feature.setGeometry(QgsGeometry.fromRect(rect))
                    feature.setAttributes([
                        current, group,
                        rect.width(),
                        rect.height(),
                        rect.area(),
                        rect.perimeter()
                    ])
                    sink.addFeature(feature, QgsFeatureSink.FastInsert)
                    geometry_dict[group] = None

                    feedback.setProgress(50 + int(current * total))
                    current += 1
            else:
                current = 0
                total = 50.0 / len(geometry_dict) if geometry_dict else 1

                for group, geometries in geometry_dict.items():
                    if feedback.isCanceled():
                        break

                    feature = self.createFeature(feedback, current, type,
                                                 geometries, group)
                    sink.addFeature(feature, QgsFeatureSink.FastInsert)
                    geometry_dict[group] = None

                    feedback.setProgress(50 + int(current * total))
                    current += 1
        else:
            total = 80.0 / source.featureCount() if source.featureCount(
            ) else 1
            features = source.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes([]))
            geometry_queue = []
            bounds = QgsRectangle()
            for current, f in enumerate(features):
                if feedback.isCanceled():
                    break

                if not f.hasGeometry():
                    continue

                if type == 0:
                    # bounding boxes, calculate on the fly for efficiency
                    bounds.combineExtentWith(f.geometry().boundingBox())
                else:
                    geometry_queue.append(f.geometry())
                feedback.setProgress(int(current * total))

            if not feedback.isCanceled():
                if type == 0:
                    feature = QgsFeature()
                    feature.setGeometry(QgsGeometry.fromRect(bounds))
                    feature.setAttributes([
                        0,
                        bounds.width(),
                        bounds.height(),
                        bounds.area(),
                        bounds.perimeter()
                    ])
                else:
                    feature = self.createFeature(feedback, 0, type,
                                                 geometry_queue)
                sink.addFeature(feature, QgsFeatureSink.FastInsert)

        return {self.OUTPUT: dest_id}
Example #60
-1
    def testInsertPolygonInMultiPolygon(self):
        layer = QgsVectorLayer("MultiPolygon?crs=epsg:4326&field=id:integer", "addfeat", "memory")
        pr = layer.dataProvider()
        f = QgsFeature()
        f.setAttributes([1])
        f.setGeometry(QgsGeometry.fromWkt('MultiPolygon(((0 0, 1 0, 1 1, 0 1, 0 0)),((10 0, 11 0, 11 1, 10 1, 10 0)))'))
        pr.addFeatures([f])

        uri = '{} table="qgis_test"."new_table_multipolygon" sql='.format(self.dbconn)
        error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql', QgsCoordinateReferenceSystem('EPSG:4326'))
        self.assertEqual(error, QgsVectorLayerExporter.NoError)

        new_layer = QgsVectorLayer(uri, 'new', 'mssql')
        self.assertTrue(new_layer.isValid())
        self.assertEqual(new_layer.wkbType(), QgsWkbTypes.MultiPolygon)
        geom = [f.geometry().asWkt() for f in new_layer.getFeatures()]
        self.assertEqual(geom, ['MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((10 0, 11 0, 11 1, 10 1, 10 0)))'])

        # add single part
        f2 = QgsFeature()
        f2.setAttributes([2])
        f2.setGeometry(QgsGeometry.fromWkt('Polygon((30 0, 31 0, 31 1, 30 1, 30 0))'))
        self.assertTrue(new_layer.dataProvider().addFeatures([f2]))

        # should become multipart
        geom = [f.geometry().asWkt() for f in new_layer.getFeatures()]
        self.assertEqual(geom, ['MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((10 0, 11 0, 11 1, 10 1, 10 0)))', 'MultiPolygon (((30 0, 31 0, 31 1, 30 1, 30 0)))'])