Example #1
0
    def get_feature_value(self, model=None):
        self.layer.startEditing()
        feature = None

        request = QgsFeatureRequest()
        if model is None:
            model = self.host.model()
        request.setFilterFid(model.id)
        feature_itr = self.layer.getFeatures(request)
        for feat in feature_itr:
            feature = feat
            break

        exp = QgsExpression(self.column.expression)

        if exp.hasParserError():
            raise Exception(exp.parserErrorString())

        exp.prepare(self.layer.pendingFields())
        if feature is not None:
            value = exp.evaluate(feature)

            return value
        else:
            return None
Example #2
0
    def get_wkt(self, spatial_column, feature_id):
        """
        Gets feature geometry in Well-Known Text
        format and returns it.
        :param spatial_column: The spatial column name.
        :type spatial_column: String
        :param feature_id: Feature id
        :type feature_id: Integer
        :return: Well-Known Text format of a geometry
        :rtype: WKT
        """
        geom_wkt = None
        fid = feature_id
        request = QgsFeatureRequest()
        request.setFilterFid(fid)
        features = self.layer.getFeatures(request)

        geom_col_obj = self.entity.columns[spatial_column]
        geom_type = geom_col_obj.geometry_type()

        # get the wkt of the geometry
        for feature in features:
            geometry = feature.geometry()
            if geometry.isGeosValid():
                if geom_type in ['MULTIPOLYGON', 'MULTILINESTRING']:
                    geometry.convertToMultiType()

                geom_wkt = geometry.exportToWkt()

        return geom_wkt
Example #3
0
    def processAlgorithm(self, progress):
        network = dataobjects.getObjectFromUri(
            self.getParameterValue(self.NETWORK_LAYER))

        # Ensure that upstream and downstream arc detected
        idxUpArcId= findField(network, 'UpArcId')
        if idxUpArcId == -1:
            raise GeoAlgorithmExecutionException(
                self.tr('Seems upstream and downstream arcs is not set. '
                        'Please run corresponding tool and try again.'))

        # First add new fields to the network layer
        networkProvider = network.dataProvider()

        (idxStrahler, fieldList) = findOrCreateField(network,
            network.pendingFields(), 'StrahOrder', QVariant.Int, 10, 0)

        writer = self.getOutputFromName(self.STRAHLER_ORDER).getVectorWriter(
            fieldList.toList(), networkProvider.geometryType(),
            networkProvider.crs())

        # Generate helper dictionaries
        myNetwork, arcsPerNodeId = makeHelperDictionaries(network)

        # Write output file
        for f in network.getFeatures():
            writer.addFeature(f)
        del writer

        vl = QgsVectorLayer(self.getOutputValue(self.STRAHLER_ORDER), 'tmp', 'ogr')
        provider = vl.dataProvider()

        # calculate Strahler orders
        # Algorithm at pages 65-66 "Automated AGQ4Vector Watershed.pdf"
        req = QgsFeatureRequest()
        progress.setInfo(self.tr('Calculating Strahler orders...'))
        # Iterate over upsteram node ids starting from the last ones
        # which represents source arcs
        for nodeId in sorted(myNetwork.keys(), reverse=True):
            f = vl.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            fid = f.id()
            upstreamArcs = f['UpArcId']
            if upstreamArcs == NULL:
                provider.changeAttributeValues({fid:{idxStrahler: 1}})
            else:
                orders = []
                for i in upstreamArcs.split(','):
                    f = vl.getFeatures(req.setFilterFid(int(i))).next()
                    if f['StrahOrder']:
                        orders.append(f['StrahOrder'])
                orders.sort(reverse=True)
                if len(orders) == 1:
                    order = orders[0]
                elif len(orders) >= 2:
                    diff = orders[0] - orders[1]
                    if diff == 0:
                        order = orders[0] + 1
                    else:
                        order = max([orders[0], orders[1]])
                provider.changeAttributeValues({fid:{idxStrahler: order}})
 def testCopyMoveFeature(self):
     """ Test copy and move features"""
     rqst = QgsFeatureRequest()
     rqst.setFilterFid(4)
     self.vl.startEditing()
     (ok, rqst, msg) = self.vltools.copyMoveFeatures(self.vl, rqst, -0.1, 0.2)
     self.assertTrue(ok)
     for f in self.vl.getFeatures(rqst):
         geom = f.geometry()
         self.assertAlmostEqual(geom.asPoint().x(), -65.42)
         self.assertAlmostEqual(geom.asPoint().y(), 78.5)
    def layerData(self, layer, request={}, offset=0):
        # Retrieve the data for a layer
        first = True
        data = {}
        fields = []
        fieldTypes = []
        fr = QgsFeatureRequest()
        if request:
            if 'exact' in request and request['exact']:
                fr.setFlags(QgsFeatureRequest.ExactIntersect)
            if 'nogeom' in request and request['nogeom']:
                fr.setFlags(QgsFeatureRequest.NoGeometry)
            if 'fid' in request:
                fr.setFilterFid(request['fid'])
            elif 'extents' in request:
                fr.setFilterRect(QgsRectangle(*request['extents']))
            if 'attributes' in request:
                fr.setSubsetOfAttributes(request['attributes'])

        # IMPORTANT - we do not use `for f in layer.getFeatures(fr):` as we need
        # to verify that existing attributes and geometry are correctly cleared
        # from the feature when calling nextFeature()
        it = layer.getFeatures(fr)
        f = QgsFeature()
        while it.nextFeature(f):
            if first:
                first = False
                for field in f.fields():
                    fields.append(str(field.name()))
                    fieldTypes.append(str(field.typeName()))
            if sys.version_info.major == 2:
                fielddata = dict((name, str(f[name])) for name in fields)
            else:
                fielddata = dict((name, str(f[name])) for name in fields)
            g = f.geometry()
            if not g.isEmpty():
                fielddata[geomkey] = str(g.exportToWkt())
            else:
                fielddata[geomkey] = "None"

            fielddata[fidkey] = f.id()
            id = fielddata[fields[0]]
            description = fielddata[fields[1]]
            fielddata['id'] = id
            fielddata['description'] = description
            data[f.id() + offset] = fielddata

        if 'id' not in fields:
            fields.insert(0, 'id')
        if 'description' not in fields:
            fields.insert(1, 'description')
        fields.append(fidkey)
        fields.append(geomkey)
        return fields, fieldTypes, data
Example #6
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.VECTOR))
        pointCount = int(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))

        bbox = layer.extent()
        idxLayer = vector.spatialindex(layer)

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, QgsWkbTypes.Point, layer.crs())

        nPoints = 0
        nIterations = 0
        maxIterations = pointCount * 200
        total = 100.0 / pointCount

        index = QgsSpatialIndex()
        points = dict()

        request = QgsFeatureRequest()

        random.seed()

        while nIterations < maxIterations and nPoints < pointCount:
            rx = bbox.xMinimum() + bbox.width() * random.random()
            ry = bbox.yMinimum() + bbox.height() * random.random()

            pnt = QgsPoint(rx, ry)
            geom = QgsGeometry.fromPoint(pnt)
            ids = idxLayer.intersects(geom.buffer(5, 5).boundingBox())
            if len(ids) > 0 and \
                    vector.checkMinDistance(pnt, index, minDistance, points):
                for i in ids:
                    f = next(layer.getFeatures(request.setFilterFid(i)))
                    tmpGeom = f.geometry()
                    if geom.within(tmpGeom):
                        f = QgsFeature(nPoints)
                        f.initAttributes(1)
                        f.setFields(fields)
                        f.setAttribute('id', nPoints)
                        f.setGeometry(geom)
                        writer.addFeature(f)
                        index.insertFeature(f)
                        points[nPoints] = pnt
                        nPoints += 1
                        progress.setPercentage(int(nPoints * total))
            nIterations += 1

        if nPoints < pointCount:
            ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                   self.tr('Can not generate requested number of random points. '
                                           'Maximum number of attempts exceeded.'))

        del writer
def layerData(layer, request={}, offset=0):
    first = True
    data = {}
    fields = []
    fieldTypes = []
    fr = QgsFeatureRequest()
    if request:
        if 'exact' in request and request['exact']:
            fr.setFlags(QgsFeatureRequest.ExactIntersect)
        if 'nogeom' in request and request['nogeom']:
            fr.setFlags(QgsFeatureRequest.NoGeometry)
        if 'fid' in request:
            fr.setFilterFid(request['fid'])
        elif 'extents' in request:
            fr.setFilterRect(QgsRectangle(*request['extents']))
        if 'attributes' in request:
            fr.setSubsetOfAttributes(request['attributes'])

    for f in layer.getFeatures(fr):
        if first:
            first = False
            for field in f.fields():
                fields.append(str(field.name()))
                fieldTypes.append(str(field.typeName()))
        fielddata = dict((name, unicode(f[name])) for name in fields)
        g = f.geometry()
        if g:
            fielddata[geomkey] = str(g.exportToWkt())
        else:
            fielddata[geomkey] = "None"

        fielddata[fidkey] = f.id()
        id = fielddata[fields[0]]
        description = fielddata[fields[1]]
        fielddata['id'] = id
        fielddata['description'] = description
        data[f.id() + offset] = fielddata
    if 'id' not in fields:
        fields.insert(0, 'id')
    if 'description' not in fields:
        fields.insert(1, 'description')
    fields.append(fidkey)
    fields.append(geomkey)
    return fields, fieldTypes, data
Example #8
0
    def testStatistics(self):
        """Test zonal stats"""
        sep = os.sep
        TEST_DATA_DIR = unitTestDataPath() + sep + "zonalstatistics" + sep
        myTempPath = QDir.tempPath() + sep
        testDir = QDir(TEST_DATA_DIR)
        for f in testDir.entryList(QDir.Files):
            QFile.remove(myTempPath + f)
            QFile.copy(TEST_DATA_DIR + f, myTempPath + f)

        myVector = QgsVectorLayer(myTempPath + "polys.shp", "poly", "ogr")
        myRasterPath = myTempPath + "edge_problem.asc"
        zs = QgsZonalStatistics(myVector, myRasterPath, "", 1)
        zs.calculateStatistics(None)

        feat = QgsFeature()
        # validate statistics for each feature
        request = QgsFeatureRequest().setFilterFid(0)
        feat = myVector.getFeatures(request).next()
        myMessage = ('Expected: %f\nGot: %f\n' % (12.0, feat[1]))
        assert feat[1] == 12.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (8.0, feat[2]))
        assert feat[2] == 8.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.666666666666667, feat[3]))
        assert abs(feat[3] - 0.666666666666667) < 0.00001, myMessage

        request.setFilterFid(1)
        feat = myVector.getFeatures(request).next()
        myMessage = ('Expected: %f\nGot: %f\n' % (9.0, feat[1]))
        assert feat[1] == 9.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (5.0, feat[2]))
        assert feat[2] == 5.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.555555555555556, feat[3]))
        assert abs(feat[3] - 0.555555555555556) < 0.00001, myMessage

        request.setFilterFid(2)
        feat = myVector.getFeatures(request).next()
        myMessage = ('Expected: %f\nGot: %f\n' % (6.0, feat[1]))
        assert feat[1] == 6.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (5.0, feat[2]))
        assert feat[2] == 5.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.833333333333333, feat[3]))
        assert abs(feat[3] - 0.833333333333333) < 0.00001, myMessage
Example #9
0
    def on_zoomButton_clicked(self):
        """
        Slot used to zoom the mapcanvas to the features associated to a complex
        """
        #case no item is selected we should warn the user
        if len(self.treeWidget.selectedItems()) == 0:
            QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select an item to zoom."))
            return

        item = self.treeWidget.selectedItems()[0]
        #checking if the item is a complex (it should have depth = 2)
        if self.depth(item) == 2:
            bbox = QgsRectangle()
            for i in range(item.childCount()):
                aggregated_item = item.child(i)
                aggregated_class = aggregated_item.text(0)
                #getting the layer the needs to be updated
                aggregated_layer = None
                layers = self.iface.mapCanvas().layers()
                for layer in layers:
                    if layer.name() == aggregated_class:
                        aggregated_layer = layer
                        break

                if not aggregated_layer:
                    QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("The associated classes must be loaded in the table of contents."))
                    return

                for j in range(aggregated_item.childCount()):
                    id = aggregated_item.child(j).text(0)
                    freq = QgsFeatureRequest()
                    freq.setFilterFid(int(id))
                    feature = layer.getFeatures( freq ).next()
                    if j==0 and i == 0:
                        bbox=feature.geometry().boundingBox()
                    bbox.combineExtentWith(feature.geometry().boundingBox())

            self.iface.mapCanvas().setExtent(bbox)
            self.iface.mapCanvas().refresh()
        else:
            QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Select a complex."))
            return
Example #10
0
    def processAlgorithm(self, progress):
        fileName = self.getParameterValue(self.INPUT)
        layer = dataobjects.getObjectFromUri(fileName)
        fieldName = self.getParameterValue(self.FIELD)
        value = self.getParameterValue(self.VALUE)

        selected = layer.selectedFeaturesIds()
        if len(selected) == 0:
            GeoAlgorithmExecutionException(
                self.tr('There is no selection in the input layer. '
                        'Select one feature and try again.'))

        ft = layer.selectedFeatures()[0]
        geom = QgsGeometry(ft.geometry())
        attrSum = ft[fieldName]

        idx = QgsSpatialIndex(layer.getFeatures())
        req = QgsFeatureRequest()
        completed = False
        while not completed:
            intersected = idx.intersects(geom.boundingBox())
            if len(intersected) < 0:
                progress.setInfo(self.tr('No adjacent features found.'))
                break

            for i in intersected:
                ft = layer.getFeatures(req.setFilterFid(i)).next()
                tmpGeom = QgsGeometry(ft.geometry())
                if tmpGeom.touches(geom):
                    geom = tmpGeom.combine(geom)
                    selected.append(i)
                    attrSum += ft[fieldName]
                    if attrSum >= value:
                        completed = True
                        break

        layer.setSelectedFeatures(selected)
        self.setOutputValue(self.OUTPUT, fileName)
    def processAlgorithm(self, progress):
        radius = self.getParameterValue(self.DISTANCE)
        horizontal = self.getParameterValue(self.HORIZONTAL)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

        features = vector.features(layer)

        total = 100.0 / len(features) if len(features) > 0 else 1

        duplicates = dict()
        for current, f in enumerate(features):
            wkt = f.geometry().exportToWkt()
            if wkt not in duplicates:
                duplicates[wkt] = [f.id()]
            else:
                duplicates[wkt].extend([f.id()])

            progress.setPercentage(int(current * total))

        current = 0
        total = 100.0 / len(duplicates) if len(duplicates) > 0 else 1
        progress.setPercentage(0)

        fullPerimeter = 2 * math.pi

        request = QgsFeatureRequest()
        for (geom, fids) in duplicates.iteritems():
            count = len(fids)
            if count == 1:
                f = layer.getFeatures(request.setFilterFid(fids[0])).next()
                writer.addFeature(f)
            else:
                angleStep = fullPerimeter / count
                if count == 2 and horizontal:
                    currentAngle = math.pi / 2
                else:
                    currentAngle = 0

                old_point = QgsGeometry.fromWkt(geom).asPoint()
                for fid in fids:
                    sinusCurrentAngle = math.sin(currentAngle)
                    cosinusCurrentAngle = math.cos(currentAngle)
                    dx = radius * sinusCurrentAngle
                    dy = radius * cosinusCurrentAngle

                    f = layer.getFeatures(request.setFilterFid(fid)).next()

                    new_point = QgsPoint(old_point.x() + dx, old_point.y()
                                         + dy)
                    out_feature = QgsFeature()
                    out_feature.setGeometry(QgsGeometry.fromPoint(new_point))
                    out_feature.setAttributes(f.attributes())

                    writer.addFeature(out_feature)
                    currentAngle += angleStep

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

        del writer
Example #12
0
    def processAlgorithm(self, progress):
        network = dataobjects.getObjectFromUri(
            self.getParameterValue(self.NETWORK_LAYER))
        # Ensure that outlet arc is selected
        if network.selectedFeatureCount() != 1:
            raise GeoAlgorithmExecutionException(
                self.tr('Seems oulet arc is not selected. Select outlet'
                        'arc in the stream network layer and try again.'))

        # First add new fields to the network layer
        networkProvider = network.dataProvider()
        networkProvider.addAttributes(
            [QgsField('StrahOrder', QVariant.Int, '', 10),    # Strahler order
             QgsField('DownNodeId', QVariant.Int, '', 10),    # downstream node id
             QgsField('UpNodeId', QVariant.Int, '', 10),      # upstream node id
             QgsField('DownArcId', QVariant.Int, '', 10),     # downstream arc id
             QgsField('UpArcId', QVariant.String, '', 250),   # comma separated list of upstream arc ids
             QgsField('Length', QVariant.Double, '', 20, 6),  # length of the arc
             QgsField('LengthDown', QVariant.Double, '', 20, 6), # length downstream
             QgsField('LengthUp', QVariant.Double, '', 20, 6)])  # length upstream
        network.updateFields()

        # Determine indexes of the fields
        idxStrahler = network.fieldNameIndex('StrahOrder')
        idxDownNodeId = network.fieldNameIndex('DownNodeId')
        idxUpNodeId = network.fieldNameIndex('UpNodeId')
        idxDownArcId = network.fieldNameIndex('DownArcId')
        idxUpArcId = network.fieldNameIndex('UpArcId')
        idxLength = network.fieldNameIndex('Length')
        idxLenDown = network.fieldNameIndex('LengthDown')
        idxLenUp = network.fieldNameIndex('LengthUp')

        # Generate arc adjacency dictionary
        # Algorithm at pages 79-80 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Generating arc adjacency dictionary...'))
        self.arcsPerNode = arcsAadjacencyDictionary(network)

        # Node indexing
        # Algorithm at pages 80-81 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Indexing nodes...'))
        self.dwUpNodesId = dict()

        # Outlet arc and its upstream node
        outletArc = network.selectedFeatures()[0]
        upNode = outletArc.geometry().asPolyline()[-1]

        # Dictionary for storing node indexes per arc.
        # For outlet arc we assign -1 for downstream and 0 for upstream nodes
        self.dwUpNodesId[outletArc.id()] = [-1, 0]
        # Current node id
        self.nodeId = 0

        # Start recursive node indexing procedure
        self.nodeIndexing(outletArc, upNode)

        # Write node indices to the network layer attributes
        progress.setInfo(self.tr('Assigning indices...'))
        for i in self.dwUpNodesId.keys():
            nodeIds = self.dwUpNodesId[i]
            attrs = {idxDownNodeId:nodeIds[0], idxUpNodeId:nodeIds[1]}
            networkProvider.changeAttributeValues({i: attrs})

        # Mapping between upstream node id from attribute table and  QGIS
        # feature id. Will be used to sort features from the network table
        myNetwork = dict()

        # Find upstream and downstream arc ids for each arc in the stream
        # network layer. First we generate helper arcPerNodeId dictionary
        # with node ids as keys and lists of arc ids connected to this node
        # as values
        # Algorithm at pages 55-56 "Automated AGQ4Vector Watershed.pdf"
        arcsPerNodeId = dict()
        for f in network.getFeatures():
            if f['UpNodeId'] not in arcsPerNodeId:
                arcsPerNodeId[f['UpNodeId']] = [f.id()]
            else:
                arcsPerNodeId[f['UpNodeId']].append(f.id())

            if f['DownNodeId'] not in arcsPerNodeId:
                arcsPerNodeId[f['DownNodeId']] = [f.id()]
            else:
                arcsPerNodeId[f['DownNodeId']].append(f.id())

            # Also populate mapping between upstream node id and feature id
            myNetwork[f['UpNodeId']] = f.id()

        # Populating upstream and downstream arc ids
        # Iterate over all arcs in the stream network layer
        for f in network.getFeatures():
            fid = f.id()
            # Determine upstream node id
            upNodeId = f['UpNodeId']

            attrs = {idxDownArcId:fid}
            changes = dict()
            ids = []

            # Iterate over all arcs connected to the upstream node with
            # given id, skipping current arc
            for i in arcsPerNodeId[upNodeId]:
                if i != fid:
                    # Modify DownArcId
                    changes[i] = attrs
                    # Collect ids of the arcs located upstream
                    ids.append(str(i))

            networkProvider.changeAttributeValues(changes)
            networkProvider.changeAttributeValues({fid:{idxUpArcId:','.join(ids)}})

            # Also calculate length of the current arc
            networkProvider.changeAttributeValues({fid:{idxLength:f.geometry().length()}})

        # Calculate length upstream for arcs
        # Algorithm at pages 61-62 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating length upstream...'))
        req = QgsFeatureRequest()
        # Iterate over upsteram node ids starting from the last ones
        # which represents source arcs
        for nodeId in sorted(myNetwork.keys(), reverse=True):
            f = network.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            arcLen = f['Length']
            upstreamArcs = f['UpArcId']
            if not upstreamArcs:
                networkProvider.changeAttributeValues({f.id():{idxLenUp: arcLen}})
            else:
                length = []
                for i in upstreamArcs.split(','):
                    f = network.getFeatures(req.setFilterFid(int(i))).next()
                    if f['LengthUp']:
                        length.append(f['LengthUp'])
                    upLen = max(length) if len(length) > 0  else 0.0
                networkProvider.changeAttributeValues({myNetwork[nodeId]:{idxLenUp:arcLen + upLen}})

        # Calculate length downstream for arcs
        # Algorithm at pages 62-63 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating length downstream...'))
        first = True
        # Iterate over upsteram node ids starting from the first one
        # which represents downstream node of the outlet arc
        for nodeId in sorted(myNetwork.keys()):
            f = network.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            # for outlet arc downstream length set to zero
            if first:
                networkProvider.changeAttributeValues({myNetwork[nodeId]:{idxLenDown:0.0}})
                first = False
                continue

            arcLen = f['Length']
            downArcId = f['DownArcId']
            f = network.getFeatures(req.setFilterFid(downArcId)).next()
            lenDown = f['LengthDown'] if f['LengthDown'] else 0.0
            networkProvider.changeAttributeValues({myNetwork[nodeId]:{idxLenDown: arcLen + lenDown}})

        # calculate Strahler orders
        # Algorithm at pages 65-66 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating Strahler orders...'))
        # Iterate over upsteram node ids starting from the last ones
        # which represents source arcs
        for nodeId in sorted(myNetwork.keys(), reverse=True):
            f = network.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            fid = f.id()
            upstreamArcs = f['UpArcId']
            if upstreamArcs == NULL:
                networkProvider.changeAttributeValues({fid:{idxStrahler: 1}})
            else:
                orders = []
                for i in upstreamArcs.split(','):
                    f = network.getFeatures(req.setFilterFid(int(i))).next()
                    if f['StrahOrder']:
                        orders.append(f['StrahOrder'])
                orders.sort(reverse=True)
                if len(orders) == 1:
                    order = orders[0]
                elif len(orders) >= 2:
                    diff = orders[0] - orders[1]
                    if diff == 0:
                        order = orders[0] + 1
                    else:
                        order = max([orders[0], orders[1]])
                networkProvider.changeAttributeValues({fid:{idxStrahler: order}})

        # Calculate order frequency
        progress.setInfo(self.tr('Calculating order frequency...'))

        maxOrder = int(network.maximumValue(idxStrahler))
        ordersFrequency = dict()
        bifRatios = dict()

        # Initialize dictionaries
        for i in xrange(1, maxOrder + 1):
            ordersFrequency[i] = dict(N=0.0, Ndu=0.0, Na=0.0)
            bifRatios[i] = dict(Rbu=0.0, Rbdu=0.0, Ru=0.0)

        for i in xrange(1, maxOrder + 1):
            req.setFilterExpression('"StrahOrder" = %s' % i)
            for f in network.getFeatures(req):
                order = int(f['StrahOrder'])
                upstreamArcs = f['UpArcId'].split(',') if f['UpArcId'] else []
                if len(upstreamArcs) == 0:
                    ordersFrequency[i]['N'] += 1.0
                elif len(upstreamArcs) > 1:
                    ordersFrequency[order]['N'] += 1.0
                    for j in upstreamArcs:
                        f = network.getFeatures(QgsFeatureRequest().setFilterFid(int(j))).next()
                        upOrder = int(f['StrahOrder'])
                        diff = upOrder - order
                        if diff == 1:
                            ordersFrequency[upOrder]['Ndu'] += 1.0
                        if diff > 1:
                            ordersFrequency[upOrder]['Na'] += 1.0

        writerOrders = self.getOutputFromName(
            self.ORDER_FREQUENCY).getTableWriter(['order', 'N', 'NDU', 'NA'])

        writerBifrat = self.getOutputFromName(
            self.BIFURCATION_PARAMS).getTableWriter(['order', 'RBD', 'RB', 'RU'])

        # Calculate bifurcation parameters
        progress.setInfo(self.tr('Calculating bifurcation parameters...'))
        for k, v in ordersFrequency.iteritems():
            if k != maxOrder:
                bifRatios[k]['Rbu'] = ordersFrequency[k]['N'] / ordersFrequency[k + 1]['N']
                bifRatios[k]['Rbdu'] = ordersFrequency[k]['Ndu'] / ordersFrequency[k + 1]['N']
            else:
                bifRatios[k]['Rbu'] = 0.0
                bifRatios[k]['Rbdu'] = 0.0

            bifRatios[k]['Ru'] = bifRatios[k]['Rbu'] - bifRatios[k]['Rbdu']

            writerOrders.addRecord([k, v['N'], v['Ndu'], v['Na']])
            writerBifrat.addRecord([k, bifRatios[k]['Rbdu'], bifRatios[k]['Rbu'], bifRatios[k]['Ru']])

        del writerOrders
        del writerBifrat
def map_sg_codes_to_provinces(
        db_manager,
        site_layer,
        parcels_layer,
        sg_code_field,
        all_features=False):
    """Obtains sg codes from target layer.

    :param db_manager: A database manager
    :type db_manager: DatabaseManager

    :param site_layer: The target layer.
    :type site_layer: QgsVectorLayer

    :param parcels_layer: Vector layer that has sg code in one of its fields.
    :type parcels_layer: QgsVectorLayer

    :param sg_code_field: Name of the field that contains sg code
    :type sg_code_field: str

    :param all_features: If True select all features, else only the selected
        ones.
    :type all_features: bool

    :returns: Dict where key is sg code and value is province name
    :rtype: dict
    """
    intersecting_parcels = []
    sg_code_provinces = {}

    sg_code_index = parcels_layer.fieldNameIndex(sg_code_field)
    if sg_code_index == -1:
        message = 'Field "%s" not found' % sg_code_field
        raise Exception(message)

    parcels_provider = parcels_layer.dataProvider()
    site_crs = site_layer.crs()
    parcel_crs = parcels_layer.crs()
    province_crs = QgsCoordinateReferenceSystem(4326)

    site_parcel_transformer = QgsCoordinateTransform(site_crs, parcel_crs)

    province_transformer = QgsCoordinateTransform(parcel_crs, province_crs)

    if not all_features:
        selected_features = site_layer.selectedFeatures()
    else:
        selected_features = site_layer.getFeatures()
    for selected_feature in selected_features:
        for feature in parcels_provider.getFeatures():
            geometry = selected_feature.geometry()
            feature_geometry = feature.geometry()

            geometry.transform(site_parcel_transformer)

            intersect = geometry.intersects(feature_geometry)
            if intersect:
                intersecting_parcels.append(feature.id())

    feature = QgsFeature()
    for intersect in intersecting_parcels:
        index = int(intersect)
        request = QgsFeatureRequest()
        request.setFilterFid(index)
        parcels_provider.getFeatures(request).nextFeature(feature)
        sg_code = feature.attributes()[sg_code_index]
        geometry = feature.geometry()
        centroid = geometry.centroid().asPoint()
        centroid = province_transformer.transform(centroid)
        # noinspection PyTypeChecker
        province_name = province_for_point(db_manager, centroid)
        sg_code_provinces[sg_code] = province_name

    return sg_code_provinces
Example #14
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))

        pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER,
                                            context)
        minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE,
                                             context)

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

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

        nPoints = 0
        nIterations = 0
        maxIterations = pointCount * 200
        featureCount = source.featureCount()
        total = 100.0 / pointCount if pointCount else 1

        index = QgsSpatialIndex()
        points = dict()

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

        request = QgsFeatureRequest()

        random.seed()

        while nIterations < maxIterations and nPoints < pointCount:
            if feedback.isCanceled():
                break

            # pick random feature
            fid = random.randint(0, featureCount - 1)
            f = next(
                source.getFeatures(
                    request.setFilterFid(fid).setSubsetOfAttributes([])))
            fGeom = f.geometry()

            if fGeom.isMultipart():
                lines = fGeom.asMultiPolyline()
                # pick random line
                lineId = random.randint(0, len(lines) - 1)
                vertices = lines[lineId]
            else:
                vertices = fGeom.asPolyline()

            # pick random segment
            if len(vertices) == 2:
                vid = 0
            else:
                vid = random.randint(0, len(vertices) - 2)
            startPoint = vertices[vid]
            endPoint = vertices[vid + 1]
            length = da.measureLine(startPoint, endPoint)
            dist = length * random.random()

            if dist > minDistance:
                d = dist / (length - dist)
                rx = (startPoint.x() + d * endPoint.x()) / (1 + d)
                ry = (startPoint.y() + d * endPoint.y()) / (1 + d)

                # generate random point
                p = QgsPointXY(rx, ry)
                geom = QgsGeometry.fromPointXY(p)
                if vector.checkMinDistance(p, index, minDistance, points):
                    f = QgsFeature(nPoints)
                    f.initAttributes(1)
                    f.setFields(fields)
                    f.setAttribute('id', nPoints)
                    f.setGeometry(geom)
                    sink.addFeature(f, QgsFeatureSink.FastInsert)
                    index.addFeature(f)
                    points[nPoints] = p
                    nPoints += 1
                    feedback.setProgress(int(nPoints * total))
            nIterations += 1

        if nPoints < pointCount:
            feedback.pushInfo(
                self.tr(
                    'Could not generate requested number of random points. '
                    'Maximum number of attempts exceeded.'))

        return {self.OUTPUT: dest_id}
Example #15
0
    def on_btnRun_clicked(self):

        #Check for combo and list box selections
        if self.ui.cmbBaseLayer.count() < 1 or self.ui.cmbProcessLayer.count(
        ) < 1:
            QMessageBox.critical(self, 'Vector Geoprocessor',
                                 'Invalid layer selection.')
            return
        if len(self.ui.listFields.selectedItems()) < 1:
            QMessageBox.critical(self, 'Vector Geoprocessor',
                                 'Invalid field selection.')
            return

        #Initializations
        self.ui.ProgressBar.setValue(0)
        self.setCursor(Qt.WaitCursor)
        data = []

        #Add new attributes to base layer
        bprovider = self.blayer.dataProvider()
        pprovider = self.player.dataProvider()
        pfields = pprovider.fields()
        for item in self.ui.listFields.selectedItems():
            fname = item.text()
            for fld in pfields.toList():
                if fname == fld.name():
                    newfield = QgsField()
                    newfield.setName(fld.name())
                    newfield.setType(fld.type())
                    newfield.setTypeName(fld.typeName())
                    newfield.setLength(fld.length())
                    newfield.setPrecision(fld.precision())
                    newfield.setComment(fld.comment())
                    bprovider.addAttributes([newfield])

        #Create a spatial index for faster processing
        spindex = QgsSpatialIndex()
        for pfeat in pprovider.getFeatures():
            spindex.insertFeature(pfeat)

        #Find the intersection of process layer features with base layer
        #To increase speed, intersect with a bounding box rectangle first
        #Then further process within the geometric shape
        #Add requested processed information to base layer
        featreq = QgsFeatureRequest()
        bfields = bprovider.fields()
        ddic = {}
        len1 = len(self.ui.listFields.selectedItems())
        len2 = len(bfields)
        b1 = 0
        b2 = bprovider.featureCount()
        attr = {}
        for bfeat in bprovider.getFeatures():
            b1 += 1
            attr.clear()
            bgeom = bfeat.geometry()
            intersect = spindex.intersects(bgeom.boundingBox())
            data[:] = []
            for fid in intersect:
                pfeat = next(self.player.getFeatures(
                    featreq.setFilterFid(fid)))
                if pfeat.geometry().intersects(bgeom) == False:
                    data.append(fid)
            for fid in data:
                intersect.pop(intersect.index(fid))

            count = 0
            for item in self.ui.listFields.selectedItems():
                pfindx = pprovider.fieldNameIndex(item.text())
                if pfindx < 0:
                    self.setCursor(Qt.ArrowCursor)
                    QMessageBox.critical(self, 'Vector Geoprocessor',
                                         'Processing error.')
                    return
                data[:] = []
                for fid in intersect:
                    pfeat = next(
                        self.player.getFeatures(featreq.setFilterFid(fid)))
                    if self.oindex in [0, 1, 2, 3, 4]:
                        data.append(float(pfeat.attribute(item.text())))
                    elif self.oindex in [5, 6]:
                        data.append(str(pfeat.attribute(item.text())))
                if len(data) == 0:
                    value = None
                elif self.oindex == 0:  #Find mean value of points within polygons
                    value = sum(data) / float(len(data))
                elif self.oindex == 1:  #Find median value of points within polygons
                    data = sorted(data)
                    lendata = len(data)
                    if lendata % 2:
                        value = data[(lendata + 1) / 2 - 1]
                    else:
                        d1 = data[lendata / 2 - 1]
                        d2 = data[lendata / 2]
                        value = (d1 + d2) / 2.0
                elif self.oindex == 2:  #Find maximum value of points within polygons
                    value = max(data)
                elif self.oindex == 3:  #Find minimum value of points within polygons
                    value = min(data)
                elif self.oindex == 4:  #Find mean value (area-weighted) of polygons within polygons
                    value = 0.0
                    totalarea = 0.0
                    for fid in intersect:
                        pfeat = next(
                            self.player.getFeatures(featreq.setFilterFid(fid)))
                        pgeom = pfeat.geometry()
                        isect = bgeom.intersection(pgeom)
                        parea = isect.area()
                        value += (float(pfeat.attribute(item.text()) * parea))
                        totalarea += parea
                    value = value / totalarea
                elif self.oindex == 5:  #Find largest area polygon within polygons
                    data = list(set(data))  #Get unique items in data
                    ddic.clear()
                    for i in data:
                        ddic.update({i: 0.0})
                    for fid in intersect:
                        pfeat = next(
                            self.player.getFeatures(featreq.setFilterFid(fid)))
                        pgeom = pfeat.geometry()
                        isect = bgeom.intersection(pgeom)
                        parea = isect.area()
                        key = str(pfeat.attribute(item.text()))
                        parea = parea + ddic[key]
                        ddic.update({key: parea})
                    parea = -1
                    for key in list(ddic.keys()):
                        if ddic[key] > parea:
                            parea = ddic[key]
                            value = key
                elif self.oindex == 6:  #Add polygon attribute to points
                    if len(data) != 1:
                        QMessageBox.warning(
                            self, 'Vector Geoprocessor',
                            'Point intersects more than one polygon.')
                    value = data[0]

                attr.update({(len2 - len1 + count): value})
                count += 1
            result = bprovider.changeAttributeValues({bfeat.id(): attr})
            if not result:
                QMessageBox.critical(self, 'Vector Geoprocessor',
                                     'Could not change attribute value.')
                return
            self.ui.ProgressBar.setValue(float(b1) / float(b2) * 100.0)
            QApplication.processEvents()

        self.setCursor(Qt.ArrowCursor)
Example #16
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.VECTOR))
        pointCount = float(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, QgsWkbTypes.Point, layer.crs())

        nPoints = 0
        nIterations = 0
        maxIterations = pointCount * 200
        featureCount = layer.featureCount()
        total = 100.0 / pointCount

        index = QgsSpatialIndex()
        points = dict()

        da = QgsDistanceArea()
        request = QgsFeatureRequest()

        random.seed()

        while nIterations < maxIterations and nPoints < pointCount:
            # pick random feature
            fid = random.randint(0, featureCount - 1)
            f = next(layer.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
            fGeom = f.geometry()

            if fGeom.isMultipart():
                lines = fGeom.asMultiPolyline()
                # pick random line
                lineId = random.randint(0, len(lines) - 1)
                vertices = lines[lineId]
            else:
                vertices = fGeom.asPolyline()

            # pick random segment
            if len(vertices) == 2:
                vid = 0
            else:
                vid = random.randint(0, len(vertices) - 2)
            startPoint = vertices[vid]
            endPoint = vertices[vid + 1]
            length = da.measureLine(startPoint, endPoint)
            dist = length * random.random()

            if dist > minDistance:
                d = dist / (length - dist)
                rx = (startPoint.x() + d * endPoint.x()) / (1 + d)
                ry = (startPoint.y() + d * endPoint.y()) / (1 + d)

                # generate random point
                pnt = QgsPoint(rx, ry)
                geom = QgsGeometry.fromPoint(pnt)
                if vector.checkMinDistance(pnt, index, minDistance, points):
                    f = QgsFeature(nPoints)
                    f.initAttributes(1)
                    f.setFields(fields)
                    f.setAttribute('id', nPoints)
                    f.setGeometry(geom)
                    writer.addFeature(f)
                    index.insertFeature(f)
                    points[nPoints] = pnt
                    nPoints += 1
                    progress.setPercentage(int(nPoints * total))
            nIterations += 1

        if nPoints < pointCount:
            ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                   self.tr('Can not generate requested number of random points. '
                                           'Maximum number of attempts exceeded.'))

        del writer
Example #17
0
    def on_btnRun_clicked(self):
        
        #Check for combo and list box selections
        if self.ui.cmbBaseLayer.count() < 1 or self.ui.cmbProcessLayer.count() < 1:
            QMessageBox.critical(self, 'Vector Geoprocessor', 'Invalid layer selection.')
            return
        if len(self.ui.listFields.selectedItems()) < 1:
            QMessageBox.critical(self, 'Vector Geoprocessor', 'Invalid field selection.')
            return            
      
        #Initializations
        self.ui.ProgressBar.setValue(0)
        self.setCursor(Qt.WaitCursor)
        data = []
            
        #Add new attributes to base layer
        bprovider = self.blayer.dataProvider()
        pprovider = self.player.dataProvider()
        pfields = pprovider.fields()
        for item in self.ui.listFields.selectedItems():
            fname = item.text()
            for fld in pfields.toList():
                if fname == fld.name():                                               
                    newfield = QgsField()
                    newfield.setName(fld.name())
                    newfield.setType(fld.type())
                    newfield.setTypeName(fld.typeName())
                    newfield.setLength(fld.length())
                    newfield.setPrecision(fld.precision())
                    newfield.setComment(fld.comment())
                    bprovider.addAttributes([newfield])            

        #Create a spatial index for faster processing
        spindex = QgsSpatialIndex()
        for pfeat in pprovider.getFeatures():
            spindex.insertFeature(pfeat)
        
        #Find the intersection of process layer features with base layer
        #To increase speed, intersect with a bounding box rectangle first
        #Then further process within the geometric shape
        #Add requested processed information to base layer                
        featreq = QgsFeatureRequest()
        bfields = bprovider.fields()
        ddic = {}
        len1 = len(self.ui.listFields.selectedItems())
        len2 = len(bfields)
        b1 = 0
        b2 = bprovider.featureCount()
        attr={}
        for bfeat in bprovider.getFeatures():
            b1+=1
            attr.clear()
            bgeom = bfeat.geometry()                                          
            intersect = spindex.intersects(bgeom.boundingBox())
            data[:] = []
            for fid in intersect:               
                pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next()
                if pfeat.geometry().intersects(bgeom) == False:
                    data.append(fid)           
            for fid in data:        
                intersect.pop(intersect.index(fid))
                              
            count = 0
            for item in self.ui.listFields.selectedItems():
                pfindx = pprovider.fieldNameIndex(item.text())
                if pfindx < 0:
                    self.setCursor(Qt.ArrowCursor)
                    QMessageBox.critical(self, 'Vector Geoprocessor', 'Processing error.')
                    return
                data[:] = []
                for fid in intersect:
                    pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next()
                    if self.oindex in [0,1,2,3,4]:
                        data.append(float(pfeat.attribute(item.text())))
                    elif self.oindex in [5,6]:
                        data.append(str(pfeat.attribute(item.text())))
                if len(data) == 0:
                    value = None
                elif self.oindex == 0: #Find mean value of points within polygons
                    value = sum(data)/float(len(data))
                elif self.oindex == 1: #Find median value of points within polygons
                    data = sorted(data)
                    lendata = len(data)
                    if lendata % 2:
                        value = data[(lendata+1)/2-1]
                    else:
                        d1 = data[lendata/2-1]
                        d2 = data[lendata/2]
                        value = (d1 + d2)/2.0
                elif self.oindex == 2: #Find maximum value of points within polygons
                    value = max(data)
                elif self.oindex == 3: #Find minimum value of points within polygons
                    value = min(data)
                elif self.oindex == 4: #Find mean value (area-weighted) of polygons within polygons
                    value = 0.0
                    totalarea = 0.0
                    for fid in intersect:
                        pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next()
                        pgeom = pfeat.geometry()
                        isect = bgeom.intersection(pgeom)
                        parea = isect.area()
                        value+=(float(pfeat.attribute(item.text())*parea))
                        totalarea+=parea
                    value = value / totalarea
                elif self.oindex == 5: #Find largest area polygon within polygons
                    data = list(set(data))  #Get unique items in data                          
                    ddic.clear()
                    for i in data:
                        ddic.update({i : 0.0})
                    for fid in intersect:
                        pfeat = self.player.getFeatures(featreq.setFilterFid(fid)).next()
                        pgeom = pfeat.geometry()
                        isect = bgeom.intersection(pgeom)
                        parea = isect.area()
                        key = str(pfeat.attribute(item.text()))
                        parea = parea + ddic[key]
                        ddic.update({key : parea})
                    parea = -1
                    for key in ddic.keys():
                        if ddic[key] > parea:
                            parea = ddic[key]
                            value = key
                elif self.oindex == 6: #Add polygon attribute to points
                    if len(data) != 1:
                        QMessageBox.warning(self, 'Vector Geoprocessor',
                                            'Point intersects more than one polygon.')
                    value = data[0]
                
                attr.update({(len2-len1+count):value})
                count+=1
            result = bprovider.changeAttributeValues({bfeat.id():attr})
            if not result:
                QMessageBox.critical(self, 'Vector Geoprocessor', 'Could not change attribute value.')
                return           
            self.ui.ProgressBar.setValue(float(b1)/float(b2) * 100.0)
            QApplication.processEvents()

        self.setCursor(Qt.ArrowCursor)
Example #18
0
    def testStatistics(self):
        """Test zonal stats"""
        TEST_DATA_DIR = unitTestDataPath() + "/zonalstatistics/"
        myTempPath = QDir.tempPath() + "/"
        testDir = QDir(TEST_DATA_DIR)
        for f in testDir.entryList(QDir.Files):
            QFile.remove(myTempPath + f)
            QFile.copy(TEST_DATA_DIR + f, myTempPath + f)

        myVector = QgsVectorLayer(myTempPath + "polys.shp", "poly", "ogr")
        myRaster = QgsRasterLayer(myTempPath + "edge_problem.asc", "raster", "gdal")
        zs = QgsZonalStatistics(myVector, myRaster, "", 1, QgsZonalStatistics.All)
        zs.calculateStatistics(None)

        feat = QgsFeature()
        # validate statistics for each feature
        request = QgsFeatureRequest().setFilterFid(0)
        feat = next(myVector.getFeatures(request))
        myMessage = ('Expected: %f\nGot: %f\n' % (12.0, feat[1]))
        assert feat[1] == 12.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (8.0, feat[2]))
        assert feat[2] == 8.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.666666666666667, feat[3]))
        assert abs(feat[3] - 0.666666666666667) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[4]))
        assert feat[4] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.47140452079103201, feat[5]))
        assert abs(feat[5] - 0.47140452079103201) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[6]))
        assert feat[6] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[7]))
        assert feat[7] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[8]))
        assert feat[8] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[9]))
        assert feat[9] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[10]))
        assert feat[10] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (2.0, feat[11]))
        assert feat[11] == 2.0, myMessage

        request.setFilterFid(1)
        feat = next(myVector.getFeatures(request))
        myMessage = ('Expected: %f\nGot: %f\n' % (9.0, feat[1]))
        assert feat[1] == 9.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (5.0, feat[2]))
        assert feat[2] == 5.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.555555555555556, feat[3]))
        assert abs(feat[3] - 0.555555555555556) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[4]))
        assert feat[4] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.49690399499995302, feat[5]))
        assert abs(feat[5] - 0.49690399499995302) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[6]))
        assert feat[6] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[7]))
        assert feat[7] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[8]))
        assert feat[8] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[9]))
        assert feat[9] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[10]))
        assert feat[10] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (2.0, feat[11]))
        assert feat[11] == 2.0, myMessage

        request.setFilterFid(2)
        feat = next(myVector.getFeatures(request))
        myMessage = ('Expected: %f\nGot: %f\n' % (6.0, feat[1]))
        assert feat[1] == 6.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (5.0, feat[2]))
        assert feat[2] == 5.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.833333333333333, feat[3]))
        assert abs(feat[3] - 0.833333333333333) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[4]))
        assert feat[4] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.372677996249965, feat[5]))
        assert abs(feat[5] - 0.372677996249965) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[6]))
        assert feat[6] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[7]))
        assert feat[7] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[8]))
        assert feat[8] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[9]))
        assert feat[9] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[10]))
        assert feat[10] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (2.0, feat[11]))
        assert feat[11] == 2.0, myMessage
Example #19
0
def addDiffLayers(repo, commit, commit2, layernames):

    styles = [diffStylePoints, diffStyleLines, diffStylePolygons]
    geomTypes = ["Point","LineString","Polygon"]
    beforeFilename = tempFilename("gpkg")
    repo.exportdiff(commit.commitid, commit2.commitid, beforeFilename)
    afterFilename = tempFilename("gpkg")
    repo.exportdiff(commit2.commitid, commit.commitid, afterFilename)
    for layername in layernames:
        styles = [diffStylePoints, diffStyleLines, diffStylePolygons]
        geomTypes = ["Point","LineString","Polygon"]
        beforeLayer = loadLayerNoCrsDialog("%s|layername=%s" % (beforeFilename, layername), layername, "ogr")
        afterLayer = loadLayerNoCrsDialog("%s|layername=%s" % (afterFilename, layername), layername, "ogr")
        beforeCon = sqlite3.connect(beforeFilename)
        beforeCursor = beforeCon.cursor()
        afterCon = sqlite3.connect(afterFilename)
        afterCursor = afterCon.cursor()

        attributes = [v[1] for v in beforeCursor.execute("PRAGMA table_info('%s');" % layername)]
        attrnames = [f.name() for f in beforeLayer.pendingFields()]

        layerFeatures = []

        beforeCursor.execute("SELECT * FROM %s_changes WHERE audit_op=2;" % layername)
        modified = beforeCursor.fetchall()
        for m in modified:
            geogigfid = m[0]
            beforeGpkgfid = gpkgfidFromGeogigfid(beforeCursor, layername, geogigfid)
            beforeCursor.execute("SELECT * FROM %s WHERE fid='%s';" % (layername, beforeGpkgfid))
            featureRow = beforeCursor.fetchone()
            attrs = {attr: featureRow[attributes.index(attr)] for attr in attrnames}
            attrs["changetype"] = MODIFIED_BEFORE
            request = QgsFeatureRequest()
            request.setFilterFid(beforeGpkgfid)
            feature = next(beforeLayer.getFeatures(request))
            layerFeatures.append({"attrs":attrs, "geom": QgsGeometry(feature.geometry())})
            afterGpkgfid = gpkgfidFromGeogigfid(afterCursor, layername, geogigfid)
            afterCursor.execute("SELECT * FROM %s WHERE fid='%s';" % (layername,afterGpkgfid))
            featureRow = afterCursor.fetchone()
            attrs = {attr: featureRow[attributes.index(attr)] for attr in attrnames}
            attrs["changetype"] = MODIFIED_AFTER
            request = QgsFeatureRequest()
            request.setFilterFid(afterGpkgfid)
            feature = next(afterLayer.getFeatures(request))
            layerFeatures.append({"attrs":attrs, "geom": QgsGeometry(feature.geometry())})


        afterCursor.execute("SELECT * FROM %s_changes WHERE audit_op=1;" % layername)
        added = afterCursor.fetchall()
        for a in added:
            geogigfid = a[0]
            afterGpkgfid = gpkgfidFromGeogigfid(afterCursor, layername, geogigfid)
            afterCursor.execute("SELECT * FROM %s WHERE fid='%s';" % (layername, afterGpkgfid))
            featureRow = afterCursor.fetchone()
            attrs = {attr: featureRow[attributes.index(attr)] for attr in attrnames}
            attrs["changetype"] = ADDED
            request = QgsFeatureRequest()
            request.setFilterFid(afterGpkgfid)
            feature = next(afterLayer.getFeatures(request))
            layerFeatures.append({"attrs":attrs, "geom": QgsGeometry(feature.geometry())})

        beforeCursor.execute("SELECT * FROM %s_changes WHERE audit_op=1;" % layername)
        removed = beforeCursor.fetchall()
        for r in removed:
            geogigfid = r[0]
            beforeGpkgfid = gpkgfidFromGeogigfid(beforeCursor, layername, geogigfid)
            beforeCursor.execute("SELECT * FROM %s WHERE fid='%s';" % (layername, beforeGpkgfid))
            featureRow = beforeCursor.fetchone()
            attrs = {attr: featureRow[attributes.index(attr)] for attr in attrnames}
            attrs["changetype"] = REMOVED
            request = QgsFeatureRequest()
            request.setFilterFid(beforeGpkgfid)
            feature = next(beforeLayer.getFeatures(request))
            layerFeatures.append({"attrs":attrs, "geom": QgsGeometry(feature.geometry())})

        if layerFeatures:
            attrnames.append("changetype")
            uriFields = "&".join(["field=%s" % f for f in attrnames])
            uri = "%s?crs=%s&%s" % (geomTypes[beforeLayer.geometryType()], beforeLayer.crs().authid(), uriFields)
            layer = QgsVectorLayer(uri, "%s(diff)" % layername, "memory")
            featuresList = []
            for feature in layerFeatures:
                qgsfeature = QgsFeature()
                qgsfeature.setGeometry(feature["geom"])
                qgsfeature.setAttributes([feature["attrs"][attr] for attr in attrnames])
                featuresList.append(qgsfeature)

            layer.dataProvider().addFeatures(featuresList)
            layer.updateExtents()
            QgsMapLayerRegistry.instance().addMapLayers([layer])
            layer.loadNamedStyle(styles[layer.geometryType()])
Example #20
0
def mapLayer_getFeatures(iface, request):
    """
    Return information about features of the given vector layer.

    Retrieve information about (and, optionally, geometry of) features of the given vector layer by querying the underlying datasource programmatically. To retrieve features that were manually selected by the user within QGIS, see /qgis/mapLayer/selectedFeatures


    HTTP query arguments:
        id (optional): ID of layer from which selected features should be retrieved. If not specified, defaults to the currently active layer.

        geometry (optional, default false): if true, returns all feature information including their geometry in GeoJSON format. Accepts several string representations of booleans (e.g. 1, 0, true, false, yes, no, ...).

        orderBy (optional): expression that the results should be ordered by. If you want to order by a field, you'll have to give its name in quotes, e.g. ?orderBy="length"

        ascending (optional, default true): whether the results should be listen in ascending or descending order. Accepts several string representations of booleans (e.g. 1, 0, true, false, yes, no, ...).

        nullsfirst (optional): how null values should be treated in the ordering. Accepts several string representations of booleans (e.g. 1, 0, true, false, yes, no, ...).


    The different ways to filter features follow the different constructor signatures defined by the QgsFeatureRequest class, in particular:

        If the request is a HTTP POST request, the request body is treated as a QGIS filter expression, and the result of applying that filter is returned.

        If the request is a HTTP GET request, the following query arguments are considered in order, and the first one provided is applied:

            fid (integer): Construct a request with a QGIS feature ID filter

            rect (string): Construct a request with a rectangle filter. The rectangle should be specified as four numbers in the format "xmin,ymin,xmax,ymax".

            A GET request in which none of the arguments are specified returns ALL features of the given vector layer, which can produce very large results.


    Returns:
        If the 'geometry' argument was passed: a GeoJSON FeatureCollection with complete attribute and geometry data for all features of the layer.
        If the 'geometry' argument was not passed: a list of all features of the vector layer in JSON format, where each feature is an object specifying the feature's 'id' and all its 'attributes'.
    """
    layer = qgis_layer_by_id_or_current(iface, request)

    # construct and run QgsFeatureRequest depending on arguments

    featurerequest = QgsFeatureRequest()
    featurerequest.addOrderBy(request.args.get('orderBy', ''), strtobool(request.args.get('ascending', 'y')), strtobool(request.args.get('nullsfirst', 'n')))

    if request.command == 'POST':
        # POST request: complex QgsExpression passed as string
        featurerequest.setFilterExpression(QgsExpression(request.headers.get_payload()))
    else:
        if request.args.get('fid'):
            # query by feature id
            featurerequest.setFilterFid(int(request.args['fid']))
        elif request.args.get('rect'):
            # query by rectangle
            r = [float(x) for x in request.args['rect'].split(',')]
            if len(r) != 4:
                raise ValueError('"rect" argument to getFeatures requires exactly four floats in the format "xmin,ymin,xmax,ymax"')
            featurerequest.setFilterRect(QgsRectangle(r[0], r[1], r[2], r[3]))

    result = layer.getFeatures(featurerequest)

    if strtobool(request.args.get('geometry', 'n')):
        return NetworkAPIResult(toGeoJSON(layer, result), 'application/geo+json; charset=utf-8')
    else:
        # note that the lazy QgsFeatureIterator returned here is currently
        # turned into a full in-memory list during conversion to JSON
        return NetworkAPIResult(result)
Example #21
0
    def evaluate(self):

        #Write parameters to GIS
        bfeat = QgsFeature()
        featreq = QgsFeatureRequest()
        i = 0
        attr = {}
        for featid in self.bfeatids:
            i += 1
            attr.clear()
            bfeat = next(
                self.sim.blayer.getFeatures(featreq.setFilterFid(featid)))
            for key in sorted(self.ofile.OptAttributes.keys()):
                bfindx = self.sim.bprovider.fieldNameIndex(
                    self.ofile.OptAttributes[key][0])
                ftype = str(self.sim.bprovider.fields()[bfindx].typeName())
                if ftype in ['Integer', 'Integer64']:
                    value = int(self.current.x[key])
                elif ftype in ['Real', 'Double']:
                    value = float(self.current.x[key])
                if int(self.ofile.OptAttributes[key][4]) in [0, i]:
                    attr.update({bfindx: value})
            result = self.sim.bprovider.changeAttributeValues(
                {bfeat.id(): attr})
            if not result:
                self.setCursor(Qt.ArrowCursor)
                QMessageBox.critical(self, 'Simulation Optimizer',
                                     'Could not change attribute value1.')
                return

        #Can't get attribute table repainting to work for all conditions.
        self.sim.blayer.selectByIds(self.bfeatids)
        QApplication.processEvents()

        #Run simulations
        for featid in self.bfeatids:
            self.sim.ui.cbxOnlySelected.setChecked(1)
            self.sim.blayer.selectByIds([featid])
            self.sim.on_btnRun_clicked()
            self.ui.textSimulation.append(self.sim.p.stdout)
            self.ui.textSimulation.append(self.sim.p.stderr)

        #Calculate error
        sqrerr = []
        for featid in self.bfeatids:
            bfeat = next(
                self.sim.blayer.getFeatures(featreq.setFilterFid(featid)))
            for key in sorted(self.ofile.ObjAttributes.keys()):
                measured = float(
                    bfeat.attribute(self.ofile.ObjAttributes[key][0]))
                simulated = float(
                    bfeat.attribute(self.ofile.ObjAttributes[key][1]))
                factor = float(self.ofile.ObjAttributes[key][2])
                error = (simulated - measured) * factor
                #error = (simulated - measured) / measured
                #error = (simulated - measured)
                sqrerr.append(error * error)

        sumsq = sum(sqrerr) / len(sqrerr)
        rmse = math.sqrt(sumsq)

        #Output
        string = '%4d ' % self.iterat
        string += '%11.5f ' % self.T
        string += '%5d ' % self.feval
        string += '%5.3f ' % self.p
        string += '%4d ' % self.accepted
        string += '%4d ' % self.declined
        if self.best.cost:
            string += ('%10.4f ' % self.best.cost)
        else:
            string += ('%10.4f ' % rmse)
        string += ('%10.4f ' % rmse)
        for i in self.best.x:
            string += '%10.4f ' % i
        for i in self.current.x:
            string += '%10.4f ' % i
        self.ui.textOptimization.append(string)
        f = open(self.logfile, 'a')
        f.write(string + '\n')
        f.close()

        return rmse
    def processAlgorithm(self, progress):
        radius = self.getParameterValue(self.DISTANCE)
        horizontal = self.getParameterValue(self.HORIZONTAL)
        output = self.getOutputFromName(self.OUTPUT_LAYER)

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

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

        features = vector.features(layer)

        total = 100.0 / len(features) if len(features) > 0 else 1

        duplicates = dict()
        for current, f in enumerate(features):
            wkt = f.geometry().exportToWkt()
            if wkt not in duplicates:
                duplicates[wkt] = [f.id()]
            else:
                duplicates[wkt].extend([f.id()])

            progress.setPercentage(int(current * total))

        current = 0
        total = 100.0 / len(duplicates) if len(duplicates) > 0 else 1
        progress.setPercentage(0)

        fullPerimeter = 2 * math.pi

        request = QgsFeatureRequest()
        for (geom, fids) in duplicates.iteritems():
            count = len(fids)
            if count == 1:
                f = layer.getFeatures(request.setFilterFid(fids[0])).next()
                writer.addFeature(f)
            else:
                angleStep = fullPerimeter / count
                if count == 2 and horizontal:
                    currentAngle = math.pi / 2
                else:
                    currentAngle = 0

                old_point = QgsGeometry.fromWkt(geom).asPoint()
                for fid in fids:
                    sinusCurrentAngle = math.sin(currentAngle)
                    cosinusCurrentAngle = math.cos(currentAngle)
                    dx = radius * sinusCurrentAngle
                    dy = radius * cosinusCurrentAngle

                    f = layer.getFeatures(request.setFilterFid(fid)).next()

                    new_point = QgsPoint(old_point.x() + dx,
                                         old_point.y() + dy)
                    out_feature = QgsFeature()
                    out_feature.setGeometry(QgsGeometry.fromPoint(new_point))
                    out_feature.setAttributes(f.attributes())

                    writer.addFeature(out_feature)
                    currentAngle += angleStep

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

        del writer
        def run_checks():
            self.assertEqual([f.name() for f in vl.fields()], ['fid', 'type', 'value'])

            # expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16")
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fid
            req = QgsFeatureRequest()
            req.setFilterFid(5)
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fids
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # check with subset of attributes
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            req.setSubsetOfAttributes([2])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes()[2], 16)
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16 or value=14")
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and fids
            req = QgsFeatureRequest()
            req.setFilterFids([3, 5])
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()], ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed
            req = QgsFeatureRequest()
            req.setSubsetOfAttributes([])
            it = vl.getFeatures(req)
            ids = []
            geoms = {}
            while it.nextFeature(f):
                ids.append(f.id())
                geoms[f.id()] = f.geometry().asWkt()
            self.assertCountEqual(ids, [3, 4, 5])
            self.assertEqual(geoms, {3: 'Point (3 3)', 4: 'Point (4 4)', 5: 'Point (5 5)'})
    def processAlgorithm(self, progress):
        network = dataobjects.getObjectFromUri(
            self.getParameterValue(self.NETWORK_LAYER))

        # Ensure that nodes already indexed
        idxDownNodeId = findField(network, 'DownNodeId')
        idxUpNodeId = findField(network, 'UpNodeId')
        if idxDownNodeId == -1 or idxUpNodeId == -1:
            raise GeoAlgorithmExecutionException(
                self.tr('Seems nodes are not indexed. Please run node '
                        'indexing tool first and try again.'))

        # First add new fields to the network layer
        networkProvider = network.dataProvider()

        (idxDownArcId, fieldList) = findOrCreateField(network,
            network.pendingFields(), 'DownArcId', QVariant.Int, 10, 0)
        (idxUpArcId, fieldList) = findOrCreateField(network, fieldList,
            'UpArcId', QVariant.String, 250, 0)
        (idxLength, fieldList) = findOrCreateField(network, fieldList,
            'Length', QVariant.Double, 20, 6)
        (idxLenDown, fieldList) = findOrCreateField(network, fieldList,
            'LengthDown', QVariant.Double, 20, 6)
        (idxLenUp, fieldList) = findOrCreateField(network, fieldList,
            'LengthUp', QVariant.Double, 20, 6)

        writer = self.getOutputFromName(self.UPDOWN_LAYER).getVectorWriter(
            fieldList.toList(), networkProvider.geometryType(),
            networkProvider.crs())

        # Generate helper dictionaries
        myNetwork, arcsPerNodeId = makeHelperDictionaries(network)

        # Write output file
        for f in network.getFeatures():
            writer.addFeature(f)
        del writer

        vl = QgsVectorLayer(self.getOutputValue(self.UPDOWN_LAYER), 'tmp', 'ogr')
        provider = vl.dataProvider()
        for f in vl.getFeatures():
            fid = f.id()

            # Determine upstream node id
            upNodeId = f['UpNodeId']

            attrs = {idxDownArcId:fid}
            changes = dict()
            ids = []

            # Iterate over all arcs connected to the upstream node with
            # given id, skipping current arc
            for i in arcsPerNodeId[upNodeId]:
                if i != fid:
                    # Modify DownArcId
                    changes[i] = attrs
                    # Collect ids of the arcs located upstream
                    ids.append(str(i))

            provider.changeAttributeValues(changes)
            provider.changeAttributeValues({fid:{idxUpArcId:','.join(ids)}})

            # Also calculate length of the current arc
            provider.changeAttributeValues({fid:{idxLength:f.geometry().length()}})

        # Calculate length upstream for arcs
        # Algorithm at pages 61-62 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating length upstream...'))
        req = QgsFeatureRequest()
        # Iterate over upsteram node ids starting from the last ones
        # which represents source arcs
        for nodeId in sorted(myNetwork.keys(), reverse=True):
            f = vl.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            arcLen = f['Length'] if f['Length'] else 0.0
            upstreamArcs = f['UpArcId']
            if not upstreamArcs:
                provider.changeAttributeValues({f.id():{idxLenUp: arcLen}})
            else:
                length = []
                for i in upstreamArcs.split(','):
                    f = vl.getFeatures(req.setFilterFid(int(i))).next()
                    if f['LengthUp']:
                        length.append(f['LengthUp'])
                    upLen = max(length) if len(length) > 0  else 0.0
                provider.changeAttributeValues({myNetwork[nodeId]:{idxLenUp:arcLen + upLen}})

        # Calculate length downstream for arcs
        # Algorithm at pages 62-63 "Automated AGQ4Vector Watershed.pdf"
        progress.setInfo(self.tr('Calculating length downstream...'))
        first = True
        # Iterate over upsteram node ids starting from the first one
        # which represents downstream node of the outlet arc
        for nodeId in sorted(myNetwork.keys()):
            f = vl.getFeatures(req.setFilterFid(myNetwork[nodeId])).next()
            # for outlet arc downstream length set to zero
            if first:
                provider.changeAttributeValues({myNetwork[nodeId]:{idxLenDown:0.0}})
                first = False
                continue

            arcLen = f['Length'] if f['Length'] else 0.0
            downArcId = f['DownArcId']
            f = vl.getFeatures(req.setFilterFid(downArcId)).next()
            lenDown = f['LengthDown'] if f['LengthDown'] else 0.0
            provider.changeAttributeValues({myNetwork[nodeId]:{idxLenDown: arcLen + lenDown}})
Example #25
0
    def on_btnRun_clicked(self):

        #Initializations
        b1 = 0
        self.ui.ProgressBar.setValue(0)
        self.setCursor(Qt.WaitCursor)
        featreq = QgsFeatureRequest()
        if self.ui.cbxOnlySelected.isChecked():
            self.selectedIDs = self.sim.blayer.selectedFeatureIds()
        else:
            self.selectedIDs = []
            for bfeat in self.sim.bprovider.getFeatures():
                self.selectedIDs.append(bfeat.id())
        self.selectedIDs.sort()
        b2 = len(self.selectedIDs)

        #Set up optimization and run
        x0 = []
        lower = []
        upper = []
        if self.ui.cbxDoGroup.isChecked():
            for key in sorted(self.ofile.OptAttributes.keys()):
                x0.append(float(self.ofile.OptAttributes[key][1]))
                lower.append(float(self.ofile.OptAttributes[key][2]))
                upper.append(float(self.ofile.OptAttributes[key][3]))

            string = 'Optimizing grouped features\n'
            string += 'Iter Temperature  Eval  Prob  Acc  Dec   BestEval    CurEval  Parameters....'
            f = open(self.logfile, 'a')
            f.write(string + '\n')
            f.close()
            self.ui.textOptimization.append(string)
            opt = Optimize(x0,
                           lower,
                           upper,
                           T0=self.ofile.T0,
                           Tf=self.ofile.Tf,
                           dwell=self.ofile.dwell,
                           feps=self.ofile.feps,
                           maxeval=self.ofile.maxeval,
                           maxiter=self.ofile.maxiter,
                           maxaccept=self.ofile.maxaccept,
                           m=self.ofile.m,
                           n=self.ofile.n,
                           quench=self.ofile.quench,
                           boltzmann=self.ofile.boltzmann)
            opt.init(self.sim, self.selectedIDs, self.ui, self.ofile,
                     self.logfile, self.iface)
            solution = opt.run()
            self.UpdateGIS(solution, self.selectedIDs)
            self.WriteResult(solution)
            self.ui.ProgressBar.setValue(float(b2) / float(b2) * 100.0)

        else:  #Run optimization for individual features

            for featid in self.selectedIDs:
                b1 += 1
                x0[:] = []
                lower[:] = []
                upper[:] = []
                bfeat = next(
                    self.sim.blayer.getFeatures(featreq.setFilterFid(featid)))
                for key in sorted(self.ofile.OptAttributes.keys()):
                    x0.append(float(self.ofile.OptAttributes[key][1]))
                    lower.append(float(self.ofile.OptAttributes[key][2]))
                    upper.append(float(self.ofile.OptAttributes[key][3]))

                string = 'Optimizing feature ID#: %d\n' % featid
                string += 'Iter Temperature  Eval  Prob  Acc  Dec   BestEval    CurEval  Parameters....'
                f = open(self.logfile, 'a')
                f.write(string + '\n')
                f.close()
                self.ui.textOptimization.append(string)
                opt = Optimize(x0,
                               lower,
                               upper,
                               T0=self.ofile.T0,
                               Tf=self.ofile.Tf,
                               dwell=self.ofile.dwell,
                               feps=self.ofile.feps,
                               maxeval=self.ofile.maxeval,
                               maxiter=self.ofile.maxiter,
                               maxaccept=self.ofile.maxaccept,
                               m=self.ofile.m,
                               n=self.ofile.n,
                               quench=self.ofile.quench,
                               boltzmann=self.ofile.boltzmann)
                opt.init(self.sim, [bfeat.id()], self.ui, self.ofile,
                         self.logfile, self.iface)
                solution = opt.run()
                self.UpdateGIS(solution, [bfeat.id()])
                self.WriteResult(solution)
                self.ui.ProgressBar.setValue(float(b1) / float(b2) * 100.0)

        if self.ui.cbxOnlySelected.isChecked():
            self.sim.blayer.selectByIds(self.selectedIDs)
        else:
            self.sim.blayer.removeSelection()

        self.setCursor(Qt.ArrowCursor)
Example #26
0
        def run_checks():
            self.assertEqual([f.name() for f in vl.fields()],
                             ['fid', 'type', 'value'])

            # expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16")
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fid
            req = QgsFeatureRequest()
            req.setFilterFid(5)
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter fids
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # check with subset of attributes
            req = QgsFeatureRequest()
            req.setFilterFids([5])
            req.setSubsetOfAttributes([2])
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes()[2], 16)
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and expression
            req = QgsFeatureRequest()
            req.setFilterExpression("value=16 or value=14")
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # filter rect and fids
            req = QgsFeatureRequest()
            req.setFilterFids([3, 5])
            req.setFilterRect(QgsRectangle(4.5, 4.5, 5.5, 5.5))
            it = vl.getFeatures(req)
            f = QgsFeature()
            self.assertTrue(it.nextFeature(f))
            self.assertEqual(f.id(), 5)
            self.assertEqual(f.attributes(), [5, 2, 16])
            self.assertEqual([field.name() for field in f.fields()],
                             ['fid', 'type', 'value'])
            self.assertEqual(f.geometry().asWkt(), 'Point (5 5)')

            # Ensure that orig_ogc_fid is still retrieved even if attribute subset is passed
            req = QgsFeatureRequest()
            req.setSubsetOfAttributes([])
            it = vl.getFeatures(req)
            ids = []
            geoms = {}
            while it.nextFeature(f):
                ids.append(f.id())
                geoms[f.id()] = f.geometry().asWkt()
            self.assertCountEqual(ids, [3, 4, 5])
            self.assertEqual(geoms, {
                3: 'Point (3 3)',
                4: 'Point (4 4)',
                5: 'Point (5 5)'
            })
Example #27
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))

        pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context)
        minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)

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

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

        nPoints = 0
        nIterations = 0
        maxIterations = pointCount * 200
        featureCount = source.featureCount()
        total = 100.0 / pointCount if pointCount else 1

        index = QgsSpatialIndex()
        points = dict()

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

        request = QgsFeatureRequest()

        random.seed()

        while nIterations < maxIterations and nPoints < pointCount:
            if feedback.isCanceled():
                break

            # pick random feature
            fid = random.randint(0, featureCount - 1)
            f = next(source.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
            fGeom = f.geometry()

            if fGeom.isMultipart():
                lines = fGeom.asMultiPolyline()
                # pick random line
                lineId = random.randint(0, len(lines) - 1)
                vertices = lines[lineId]
            else:
                vertices = fGeom.asPolyline()

            # pick random segment
            if len(vertices) == 2:
                vid = 0
            else:
                vid = random.randint(0, len(vertices) - 2)
            startPoint = vertices[vid]
            endPoint = vertices[vid + 1]
            length = da.measureLine(startPoint, endPoint)
            dist = length * random.random()

            if dist > minDistance:
                d = dist / (length - dist)
                rx = (startPoint.x() + d * endPoint.x()) / (1 + d)
                ry = (startPoint.y() + d * endPoint.y()) / (1 + d)

                # generate random point
                p = QgsPointXY(rx, ry)
                geom = QgsGeometry.fromPointXY(p)
                if vector.checkMinDistance(p, index, minDistance, points):
                    f = QgsFeature(nPoints)
                    f.initAttributes(1)
                    f.setFields(fields)
                    f.setAttribute('id', nPoints)
                    f.setGeometry(geom)
                    sink.addFeature(f, QgsFeatureSink.FastInsert)
                    index.addFeature(f)
                    points[nPoints] = p
                    nPoints += 1
                    feedback.setProgress(int(nPoints * total))
            nIterations += 1

        if nPoints < pointCount:
            feedback.pushInfo(self.tr('Could not generate requested number of random points. '
                                      'Maximum number of attempts exceeded.'))

        return {self.OUTPUT: dest_id}
Example #28
0
    def testStatistics(self):
        """Test zonal stats"""
        TEST_DATA_DIR = unitTestDataPath() + "/zonalstatistics/"
        myTempPath = QDir.tempPath() + "/"
        testDir = QDir(TEST_DATA_DIR)
        for f in testDir.entryList(QDir.Files):
            QFile.remove(myTempPath + f)
            QFile.copy(TEST_DATA_DIR + f, myTempPath + f)

        myVector = QgsVectorLayer(myTempPath + "polys.shp", "poly", "ogr")
        myRaster = QgsRasterLayer(myTempPath + "edge_problem.asc", "raster",
                                  "gdal")
        zs = QgsZonalStatistics(myVector, myRaster, "", 1,
                                QgsZonalStatistics.All)
        zs.calculateStatistics(None)

        feat = QgsFeature()
        # validate statistics for each feature
        request = QgsFeatureRequest().setFilterFid(0)
        feat = next(myVector.getFeatures(request))
        myMessage = ('Expected: %f\nGot: %f\n' % (12.0, feat[1]))
        assert feat[1] == 12.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (8.0, feat[2]))
        assert feat[2] == 8.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.666666666666667, feat[3]))
        assert abs(feat[3] - 0.666666666666667) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[4]))
        assert feat[4] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' %
                     (0.47140452079103201, feat[5]))
        assert abs(feat[5] - 0.47140452079103201) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[6]))
        assert feat[6] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[7]))
        assert feat[7] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[8]))
        assert feat[8] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[9]))
        assert feat[9] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[10]))
        assert feat[10] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (2.0, feat[11]))
        assert feat[11] == 2.0, myMessage

        request.setFilterFid(1)
        feat = next(myVector.getFeatures(request))
        myMessage = ('Expected: %f\nGot: %f\n' % (9.0, feat[1]))
        assert feat[1] == 9.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (5.0, feat[2]))
        assert feat[2] == 5.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.555555555555556, feat[3]))
        assert abs(feat[3] - 0.555555555555556) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[4]))
        assert feat[4] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' %
                     (0.49690399499995302, feat[5]))
        assert abs(feat[5] - 0.49690399499995302) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[6]))
        assert feat[6] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[7]))
        assert feat[7] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[8]))
        assert feat[8] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[9]))
        assert feat[9] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[10]))
        assert feat[10] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (2.0, feat[11]))
        assert feat[11] == 2.0, myMessage

        request.setFilterFid(2)
        feat = next(myVector.getFeatures(request))
        myMessage = ('Expected: %f\nGot: %f\n' % (6.0, feat[1]))
        assert feat[1] == 6.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (5.0, feat[2]))
        assert feat[2] == 5.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.833333333333333, feat[3]))
        assert abs(feat[3] - 0.833333333333333) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[4]))
        assert feat[4] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.372677996249965, feat[5]))
        assert abs(feat[5] - 0.372677996249965) < 0.00001, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[6]))
        assert feat[6] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[7]))
        assert feat[7] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[8]))
        assert feat[8] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (0.0, feat[9]))
        assert feat[9] == 0.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (1.0, feat[10]))
        assert feat[10] == 1.0, myMessage
        myMessage = ('Expected: %f\nGot: %f\n' % (2.0, feat[11]))
        assert feat[11] == 2.0, myMessage
Example #29
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.VECTOR), context)
        pointCount = float(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, QgsWkbTypes.Point, layer.crs(), context)

        nPoints = 0
        nIterations = 0
        maxIterations = pointCount * 200
        featureCount = layer.featureCount()
        total = 100.0 / pointCount

        index = QgsSpatialIndex()
        points = dict()

        da = QgsDistanceArea()
        request = QgsFeatureRequest()

        random.seed()

        while nIterations < maxIterations and nPoints < pointCount:
            # pick random feature
            fid = random.randint(0, featureCount - 1)
            f = next(
                layer.getFeatures(
                    request.setFilterFid(fid).setSubsetOfAttributes([])))
            fGeom = f.geometry()

            if fGeom.isMultipart():
                lines = fGeom.asMultiPolyline()
                # pick random line
                lineId = random.randint(0, len(lines) - 1)
                vertices = lines[lineId]
            else:
                vertices = fGeom.asPolyline()

            # pick random segment
            if len(vertices) == 2:
                vid = 0
            else:
                vid = random.randint(0, len(vertices) - 2)
            startPoint = vertices[vid]
            endPoint = vertices[vid + 1]
            length = da.measureLine(startPoint, endPoint)
            dist = length * random.random()

            if dist > minDistance:
                d = dist / (length - dist)
                rx = (startPoint.x() + d * endPoint.x()) / (1 + d)
                ry = (startPoint.y() + d * endPoint.y()) / (1 + d)

                # generate random point
                pnt = QgsPointXY(rx, ry)
                geom = QgsGeometry.fromPoint(pnt)
                if vector.checkMinDistance(pnt, index, minDistance, points):
                    f = QgsFeature(nPoints)
                    f.initAttributes(1)
                    f.setFields(fields)
                    f.setAttribute('id', nPoints)
                    f.setGeometry(geom)
                    writer.addFeature(f)
                    index.insertFeature(f)
                    points[nPoints] = pnt
                    nPoints += 1
                    feedback.setProgress(int(nPoints * total))
            nIterations += 1

        if nPoints < pointCount:
            QgsMessageLog.logMessage(
                self.tr('Can not generate requested number of random points. '
                        'Maximum number of attempts exceeded.'),
                self.tr('Processing'), QgsMessageLog.INFO)

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

        t_troncon = self.parameterAsSource(parameters, self.SEGMENTS_TABLE,
                                           context)
        g_troncon = self.parameterAsSource(parameters, self.GEOM_SEGMENTS,
                                           context)
        t_obs = self.parameterAsSource(parameters, self.OBSERVATION_TABLE,
                                       context)
        g_obs = self.parameterAsVectorLayer(parameters, self.GEOM_OBSERVATION,
                                            context)

        # Get troncon ids and file ids
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(t_troncon.createExpressionContextScope())

        exp_str = '"id_geom_troncon" IS NOT NULL'
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression %s has eval error: %s').format(
                    exp.expression(), exp.evalErrorString()))

        request = QgsFeatureRequest(exp, exp_context)
        request.setSubsetOfAttributes(
            ['id', 'aab', 'aad', 'aaf', 'abq', 'id_file', 'id_geom_troncon'],
            t_troncon.fields())
        has_geo_troncon = False
        troncons = {}
        file_ids = []
        for tro in t_troncon.getFeatures(request):
            troncons[tro['id']] = tro
            file_ids.append(tro['id_file'])
            has_geo_troncon = True

            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.OBSERVATIONS_CREATED: None}

        if not has_geo_troncon:
            raise QgsProcessingException(tr('* ERROR: No troncon geometries'))

        # Get observation ids
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(t_obs.createExpressionContextScope())

        exp_str = ('"id_troncon" IN ({}) AND '
                   '"id_file" IN ({})').format(
                       ','.join([str(i) for i in troncons.keys()]),
                       ','.join([str(i) for i in file_ids]))
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    exp.expression(), exp.evalErrorString()))

        obs_ids = []
        request = QgsFeatureRequest(exp, exp_context)
        for obs in t_obs.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.OBSERVATIONS_CREATED: None}

            troncon = troncons[obs['id_troncon']]

            # verifying ITV file
            if troncon['id_file'] != obs['id_file']:
                continue

            obs_ids.append(obs['id'])

        if not obs_ids:
            raise QgsProcessingException(
                tr('* ERROR: No observations to geolocalize found'))

        # Check observations already geolocalised on troncon
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(g_obs))

        exp_str = '"id" IN ({})'.format(','.join([str(i) for i in obs_ids]))
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    exp.expression(), exp.evalErrorString()))

        request = QgsFeatureRequest(exp, exp_context)
        geo_observations = []
        for obs in g_obs.getFeatures(request):
            geo_observations.append(obs['id'])

            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.OBSERVATIONS_CREATED: None}

        # build observation geometry based on table
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(
            QgsExpressionContextUtils.projectScope(context.project()))
        exp_context.appendScope(t_obs.createExpressionContextScope())

        exp_str = ('"id_troncon" IN ({}) AND '
                   '"id_file" IN ({})').format(
                       ','.join([str(i) for i in troncons.keys()]),
                       ','.join([str(i) for i in file_ids]))
        if geo_observations:
            exp_str += ' AND id NOT IN ({})'.format(','.join(
                [str(i) for i in geo_observations]))
        exp = QgsExpression(exp_str)

        exp.prepare(exp_context)
        if exp.hasEvalError():
            raise QgsProcessingException(
                tr('* ERROR: Expression {} has eval error: {}').format(
                    exp.expression(), exp.evalErrorString()))

        request = QgsFeatureRequest(exp, exp_context)
        features = []
        fields = provider_fields(g_obs.fields())
        for obs in t_obs.getFeatures(request):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                return {self.OBSERVATIONS_CREATED: None}

            troncon = troncons[obs['id_troncon']]

            # verifying ITV file
            if troncon['id_file'] != obs['id_file']:
                continue

            geo_req = QgsFeatureRequest()
            geo_req.setFilterFid(troncon['id_geom_troncon'])
            for g_tro in g_troncon.getFeatures(geo_req):
                # Stop the algorithm if cancel button has been clicked
                if feedback.isCanceled():
                    return {self.OBSERVATIONS_CREATED: None}

                geom = g_tro.geometry()
                pt = None
                if troncon['aab'] == troncon['aad']:
                    pt = geom.interpolate(geom.length() * obs['i'] /
                                          troncon['abq'])
                else:
                    pt = geom.interpolate(geom.length() *
                                          (1 - obs['i'] / troncon['abq']))
                fet = QgsFeature(fields)
                fet.setGeometry(pt)
                fet.setAttribute('id', obs['id'])
                features.append(fet)

        # Ajout des objets observations
        if features:
            g_obs.startEditing()
            (res, outFeats) = g_obs.dataProvider().addFeatures(features)
            if not res or not outFeats:
                raise QgsProcessingException(
                    tr('* ERREUR: lors de l\'enregistrement '
                       'des regards {}').format(', '.join(
                           g_obs.dataProvider().errors())))
            if not g_obs.commitChanges():
                raise QgsProcessingException(
                    tr('* ERROR: Commit {}.').format(g_obs.commitErrors()))

        # Returns empty dict if no outputs
        return {self.OBSERVATIONS_CREATED: len(features)}