示例#1
0
    def run(self):
        """Experimental impact function."""
        self.validate()
        self.prepare()

        # Get parameters from layer's keywords
        self.hazard_class_attribute = self.hazard.keyword('field')
        self.hazard_class_mapping = self.hazard.keyword('value_map')
        self.exposure_class_attribute = self.exposure.keyword(
            'structure_class_field')

        # Prepare Hazard Layer
        hazard_provider = self.hazard.layer.dataProvider()

        # Check affected field exists in the hazard layer
        affected_field_index = hazard_provider.fieldNameIndex(
            self.hazard_class_attribute)
        if affected_field_index == -1:
            message = tr(
                'Field "%s" is not present in the attribute table of the '
                'hazard layer. Please change the Affected Field parameter in '
                'the IF Option.') % self.hazard_class_attribute
            raise GetDataError(message)

        srs = self.exposure.layer.crs().toWkt()
        exposure_provider = self.exposure.layer.dataProvider()
        exposure_fields = exposure_provider.fields()

        # Check self.exposure_class_attribute exists in exposure layer
        building_type_field_index = exposure_provider.fieldNameIndex(
            self.exposure_class_attribute)
        if building_type_field_index == -1:
            message = tr('Field "%s" is not present in the attribute table of '
                         'the exposure layer. Please change the Building Type '
                         'Field parameter in the IF Option.'
                         ) % self.exposure_class_attribute
            raise GetDataError(message)

        # If target_field does not exist, add it:
        if exposure_fields.indexFromName(self.target_field) == -1:
            exposure_provider.addAttributes(
                [QgsField(self.target_field, QVariant.Int)])
        target_field_index = exposure_provider.fieldNameIndex(
            self.target_field)
        exposure_fields = exposure_provider.fields()

        # Create layer to store the lines from E and extent
        building_layer = QgsVectorLayer('Polygon?crs=' + srs,
                                        'impact_buildings', 'memory')
        building_provider = building_layer.dataProvider()

        # Set attributes
        building_provider.addAttributes(exposure_fields.toList())
        building_layer.startEditing()
        building_layer.commitChanges()

        # Filter geometry and data using the requested extent
        requested_extent = QgsRectangle(*self.requested_extent)

        # This is a hack - we should be setting the extent CRS
        # in the IF base class via safe/engine/core.py:calculate_impact
        # for now we assume the extent is in 4326 because it
        # is set to that from geo_extent
        # See issue #1857
        transform = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem('EPSG:%i' %
                                         self._requested_extent_crs),
            self.hazard.layer.crs())
        projected_extent = transform.transformBoundingBox(requested_extent)
        request = QgsFeatureRequest()
        request.setFilterRect(projected_extent)

        # Split building_layer by H and save as result:
        #   1) Filter from H inundated features
        #   2) Mark buildings as inundated (1) or not inundated (0)

        # make spatial index of affected polygons
        hazard_index = QgsSpatialIndex()
        hazard_geometries = {}  # key = feature id, value = geometry
        has_hazard_objects = False
        for feature in self.hazard.layer.getFeatures(request):
            value = feature[affected_field_index]
            if value not in self.hazard_class_mapping[self.wet]:
                continue
            hazard_index.insertFeature(feature)
            hazard_geometries[feature.id()] = QgsGeometry(feature.geometry())
            has_hazard_objects = True

        if not has_hazard_objects:
            message = tr(
                'There are no objects in the hazard layer with %s '
                'value in %s. Please check your data or use another '
                'attribute.') % (self.hazard_class_attribute, ', '.join(
                    self.hazard_class_mapping[self.wet]))
            raise GetDataError(message)

        features = []
        for feature in self.exposure.layer.getFeatures(request):
            building_geom = feature.geometry()
            affected = False
            # get tentative list of intersecting hazard features
            # only based on intersection of bounding boxes
            ids = hazard_index.intersects(building_geom.boundingBox())
            for fid in ids:
                # run (slow) exact intersection test
                if hazard_geometries[fid].intersects(building_geom):
                    affected = True
                    break
            f = QgsFeature()
            f.setGeometry(building_geom)
            f.setAttributes(feature.attributes())
            f[target_field_index] = 1 if affected else 0
            features.append(f)

            # every once in a while commit the created features
            # to the output layer
            if len(features) == 1000:
                (_, __) = building_provider.addFeatures(features)
                features = []

        (_, __) = building_provider.addFeatures(features)
        building_layer.updateExtents()

        # Generate simple impact report
        self.buildings = {}
        self.affected_buildings = OrderedDict([(tr('Flooded'), {})])
        buildings_data = building_layer.getFeatures()
        building_type_field_index = building_layer.fieldNameIndex(
            self.exposure_class_attribute)
        for building in buildings_data:
            record = building.attributes()
            building_type = record[building_type_field_index]
            if building_type in [None, 'NULL', 'null', 'Null']:
                building_type = 'Unknown type'
            if building_type not in self.buildings:
                self.buildings[building_type] = 0
                for category in self.affected_buildings.keys():
                    self.affected_buildings[category][
                        building_type] = OrderedDict([
                            (tr('Buildings Affected'), 0)
                        ])
            self.buildings[building_type] += 1

            if record[target_field_index] == 1:
                self.affected_buildings[tr('Flooded')][building_type][tr(
                    'Buildings Affected')] += 1

        # Lump small entries and 'unknown' into 'other' category
        self._consolidate_to_other()

        impact_summary = self.html_report()

        # For printing map purpose
        map_title = tr('Buildings inundated')
        legend_title = tr('Structure inundated status')

        style_classes = [
            dict(label=tr('Not Inundated'),
                 value=0,
                 colour='#1EFC7C',
                 transparency=0,
                 size=0.5),
            dict(label=tr('Inundated'),
                 value=1,
                 colour='#F31A1C',
                 transparency=0,
                 size=0.5)
        ]
        style_info = dict(target_field=self.target_field,
                          style_classes=style_classes,
                          style_type='categorizedSymbol')

        # Convert QgsVectorLayer to inasafe layer and return it.
        if building_layer.featureCount() < 1:
            raise ZeroImpactException(
                tr('No buildings were impacted by this flood.'))
        building_layer = Vector(data=building_layer,
                                name=tr('Flooded buildings'),
                                keywords={
                                    'impact_summary':
                                    impact_summary,
                                    'map_title':
                                    map_title,
                                    'legend_title':
                                    legend_title,
                                    'target_field':
                                    self.target_field,
                                    'buildings_total':
                                    self.total_buildings,
                                    'buildings_affected':
                                    self.total_affected_buildings
                                },
                                style_info=style_info)
        self._impact = building_layer
        return building_layer
示例#2
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        proximity = self.parameterAsDouble(parameters, self.PROXIMITY, context)
        radius = self.parameterAsDouble(parameters, self.DISTANCE, context)
        horizontal = self.parameterAsBool(parameters, self.HORIZONTAL, context)

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

        features = source.getFeatures()

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

        def searchRect(p):
            return QgsRectangle(p.x() - proximity,
                                p.y() - proximity,
                                p.x() + proximity,
                                p.y() + proximity)

        index = QgsSpatialIndex()

        # NOTE: this is a Python port of QgsPointDistanceRenderer::renderFeature. If refining this algorithm,
        # please port the changes to QgsPointDistanceRenderer::renderFeature also!

        clustered_groups = []
        group_index = {}
        group_locations = {}
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            point = f.geometry().asPoint()

            other_features_within_radius = index.intersects(searchRect(point))
            if not other_features_within_radius:
                index.insertFeature(f)
                group = [f]
                clustered_groups.append(group)
                group_index[f.id()] = len(clustered_groups) - 1
                group_locations[f.id()] = point
            else:
                # find group with closest location to this point (may be more than one within search tolerance)
                min_dist_feature_id = other_features_within_radius[0]
                min_dist = group_locations[min_dist_feature_id].distance(point)
                for i in range(1, len(other_features_within_radius)):
                    candidate_id = other_features_within_radius[i]
                    new_dist = group_locations[candidate_id].distance(point)
                    if new_dist < min_dist:
                        min_dist = new_dist
                        min_dist_feature_id = candidate_id

                group_index_pos = group_index[min_dist_feature_id]
                group = clustered_groups[group_index_pos]

                # calculate new centroid of group
                old_center = group_locations[min_dist_feature_id]
                group_locations[min_dist_feature_id] = QgsPointXY(
                    (old_center.x() * len(group) + point.x()) /
                    (len(group) + 1.0),
                    (old_center.y() * len(group) + point.y()) /
                    (len(group) + 1.0))
                # add to a group
                clustered_groups[group_index_pos].append(f)
                group_index[f.id()] = group_index_pos

            feedback.setProgress(int(current * total))

        current = 0
        total = 100.0 / len(clustered_groups) if clustered_groups else 1
        feedback.setProgress(0)

        fullPerimeter = 2 * math.pi

        for group in clustered_groups:
            if feedback.isCanceled():
                break

            count = len(group)
            if count == 1:
                sink.addFeature(group[0], QgsFeatureSink.FastInsert)
            else:
                angleStep = fullPerimeter / count
                if count == 2 and horizontal:
                    currentAngle = math.pi / 2
                else:
                    currentAngle = 0

                old_point = group_locations[group[0].id()]

                for f in group:
                    if feedback.isCanceled():
                        break

                    sinusCurrentAngle = math.sin(currentAngle)
                    cosinusCurrentAngle = math.cos(currentAngle)
                    dx = radius * sinusCurrentAngle
                    dy = radius * cosinusCurrentAngle

                    # we want to keep any existing m/z values
                    point = f.geometry().constGet().clone()
                    point.setX(old_point.x() + dx)
                    point.setY(old_point.y() + dy)
                    f.setGeometry(QgsGeometry(point))

                    sink.addFeature(f, QgsFeatureSink.FastInsert)
                    currentAngle += angleStep

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

        return {self.OUTPUT: dest_id}
示例#3
0
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

        geomType = QgsWkbTypes.multiType(sourceA.wkbType())
        fields = vector.combineFields(sourceA.fields(), sourceB.fields())

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

        featB = QgsFeature()
        outFeat = QgsFeature()

        indexA = QgsSpatialIndex(sourceA)
        indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))

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

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

            geom = featA.geometry()
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            intersects = indexB.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
            request.setDestinationCrs(sourceA.sourceCrs())
            for featB in sourceB.getFeatures(request):
                if feedback.isCanceled():
                    break
                tmpGeom = featB.geometry()
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))

            try:
                outFeat.setGeometry(diffGeom)
                outFeat.setAttributes(attrs)
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
            except:
                QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'),
                                         self.tr('Processing'), QgsMessageLog.WARNING)
                continue

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

        length = len(sourceA.fields())

        for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs())):
            if feedback.isCanceled():
                break

            geom = featA.geometry()
            diffGeom = QgsGeometry(geom)
            attrs = featA.attributes()
            attrs = [NULL] * length + attrs
            intersects = indexA.intersects(geom.boundingBox())
            request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
            for featB in sourceA.getFeatures(request):
                if feedback.isCanceled():
                    break

                tmpGeom = featB.geometry()
                if diffGeom.intersects(tmpGeom):
                    diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))

            try:
                outFeat.setGeometry(diffGeom)
                outFeat.setAttributes(attrs)
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
            except:
                QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'),
                                         self.tr('Processing'), QgsMessageLog.WARNING)
                continue

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

        return {self.OUTPUT: dest_id}
示例#4
0
 def createSpatialIndex(self):
     if self._spatialindex is None:
         self._spatialindex = QgsSpatialIndex()
         for f in self._features.values():
             self._spatialindex.insertFeature(f)
     return True
    def regularMatrix(self, parameters, context, source, inField,
                      target_source, targetField, nPoints, feedback):

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

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

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

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

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

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

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

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

        return {self.OUTPUT: dest_id}
    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, QGis.WKBPoint, 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 = layer.getFeatures(request.setFilterFid(fid)).next()
            fGeom = QgsGeometry(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
示例#7
0
    def processAlgorithm(self, feedback):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.VECTOR))
        value = float(self.getParameterValue(self.VALUE))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))
        strategy = self.getParameterValue(self.STRATEGY)

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

        da = QgsDistanceArea()

        features = vector.features(layer)
        for current, f in enumerate(features):
            fGeom = f.geometry()
            bbox = fGeom.boundingBox()
            if strategy == 0:
                pointCount = int(value)
            else:
                pointCount = int(round(value * da.measureArea(fGeom)))

            index = QgsSpatialIndex()
            points = dict()

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

            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)
                if geom.within(fGeom) and \
                        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:
                ProcessingLog.addToLog(
                    ProcessingLog.LOG_INFO,
                    self.tr('Can not generate requested number of random '
                            'points. Maximum number of attempts exceeded.'))

            feedback.setProgress(0)

        del writer
示例#8
0
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.INTERSECT, context)

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

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

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

        fieldListB = vector.testForUniqueness(fieldListA, fieldListB)
        for b in fieldListB:
            fieldListA.append(b)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fieldListA,
                                               QgsWkbTypes.Point,
                                               sourceA.sourceCrs())

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

        outFeat = QgsFeature()
        features = sourceA.getFeatures(
            QgsFeatureRequest().setSubsetOfAttributes(field_indices_a))
        total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 0
        for current, inFeatA in enumerate(features):
            if feedback.isCanceled():
                break

            if not inFeatA.hasGeometry():
                continue

            inGeom = inFeatA.geometry()
            has_intersections = False
            lines = spatialIndex.intersects(inGeom.boundingBox())

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

            if has_intersections:
                request = QgsFeatureRequest().setFilterFids(lines)
                request.setDestinationCrs(sourceA.sourceCrs())
                request.setSubsetOfAttributes(field_indices_b)

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

                    tmpGeom = inFeatB.geometry()

                    points = []
                    if engine.intersects(tmpGeom.geometry()):
                        tempGeom = inGeom.intersection(tmpGeom)
                        out_attributes = [
                            inFeatA.attributes()[i] for i in field_indices_a
                        ]
                        out_attributes.extend(
                            [inFeatB.attributes()[i] for i in field_indices_b])
                        if tempGeom.type() == QgsWkbTypes.PointGeometry:
                            if tempGeom.isMultipart():
                                points = tempGeom.asMultiPoint()
                            else:
                                points.append(tempGeom.asPoint())

                            for j in points:
                                outFeat.setGeometry(tempGeom.fromPoint(j))
                                outFeat.setAttributes(out_attributes)
                                sink.addFeature(outFeat,
                                                QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        if source is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

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

        features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]))

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        geoms = dict()
        null_geom_features = set()
        index = QgsSpatialIndex()
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                null_geom_features.add(f.id())
                continue

            geoms[f.id()] = f.geometry()
            index.addFeature(f)

            feedback.setProgress(int(0.10 * current * total)) # takes about 10% of time

        # start by assuming everything is unique, and chop away at this list
        unique_features = dict(geoms)

        current = 0
        removed = 0
        for feature_id, geometry in geoms.items():
            if feedback.isCanceled():
                break

            if feature_id not in unique_features:
                # feature was already marked as a duplicate
                continue

            candidates = index.intersects(geometry.boundingBox())
            candidates.remove(feature_id)

            for candidate_id in candidates:
                if candidate_id not in unique_features:
                    # candidate already marked as a duplicate (not sure if this is possible,
                    # since it would mean the current feature would also have to be a duplicate!
                    # but let's be safe!)
                    continue

                if geometry.isGeosEqual(geoms[candidate_id]):
                    # candidate is a duplicate of feature
                    del unique_features[candidate_id]
                    removed += 1

            current += 1
            feedback.setProgress(int(0.80 * current * total) + 10)  # takes about 80% of time

        # now, fetch all the feature attributes for the unique features only
        # be super-smart and don't re-fetch geometries
        distinct_geoms = set(unique_features.keys())
        output_feature_ids = distinct_geoms.union(null_geom_features)
        total = 100.0 / len(output_feature_ids) if output_feature_ids else 1

        request = QgsFeatureRequest().setFilterFids(list(output_feature_ids)).setFlags(QgsFeatureRequest.NoGeometry)
        for current, f in enumerate(source.getFeatures(request)):
            if feedback.isCanceled():
                break

            # use already fetched geometry
            if f.id() not in null_geom_features:
                f.setGeometry(unique_features[f.id()])
            sink.addFeature(f, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(0.10 * current * total) + 90) # takes about 10% of time

        feedback.pushInfo(self.tr('{} duplicate features removed'.format(removed)))
        return {self.OUTPUT: dest_id,
                self.DUPLICATE_COUNT: removed,
                self.RETAINED_COUNT: len(output_feature_ids)}
示例#10
0
    def processAlgorithm(self, feedback):
        layerA = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_A))
        splitLayer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.INPUT_B))

        sameLayer = self.getParameterValue(
            self.INPUT_A) == self.getParameterValue(self.INPUT_B)
        fieldList = layerA.fields()

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

        spatialIndex = QgsSpatialIndex()
        splitGeoms = {}
        request = QgsFeatureRequest()
        request.setSubsetOfAttributes([])

        for aSplitFeature in vector.features(splitLayer, request):
            splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry()
            spatialIndex.insertFeature(aSplitFeature)
            # honor the case that user has selection on split layer and has setting "use selection"

        outFeat = QgsFeature()
        features = vector.features(layerA)

        if len(features) == 0:
            total = 100
        else:
            total = 100.0 / float(len(features))

        for current, inFeatA in enumerate(features):
            inGeom = inFeatA.geometry()
            attrsA = inFeatA.attributes()
            outFeat.setAttributes(attrsA)

            if inGeom.isMultipart():
                inGeoms = []

                for g in inGeom.asGeometryCollection():
                    inGeoms.append(g)
            else:
                inGeoms = [inGeom]

            lines = spatialIndex.intersects(inGeom.boundingBox())

            if len(lines) > 0:  # has intersection of bounding boxes
                splittingLines = []

                engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                engine.prepareGeometry()

                for i in lines:
                    try:
                        splitGeom = splitGeoms[i]
                    except:
                        continue

                    # check if trying to self-intersect
                    if sameLayer:
                        if inFeatA.id() == i:
                            continue

                    if engine.intersects(splitGeom.geometry()):
                        splittingLines.append(splitGeom)

                if len(splittingLines) > 0:
                    for splitGeom in splittingLines:
                        splitterPList = None
                        outGeoms = []

                        split_geom_engine = QgsGeometry.createGeometryEngine(
                            splitGeom.geometry())
                        split_geom_engine.prepareGeometry()

                        while len(inGeoms) > 0:
                            inGeom = inGeoms.pop()

                            if inGeom.isNull(
                            ):  # this has been encountered and created a run-time error
                                continue

                            if split_geom_engine.intersects(inGeom.geometry()):
                                inPoints = vector.extractPoints(inGeom)
                                if splitterPList == None:
                                    splitterPList = vector.extractPoints(
                                        splitGeom)

                                try:
                                    result, newGeometries, topoTestPoints = inGeom.splitGeometry(
                                        splitterPList, False)
                                except:
                                    ProcessingLog.addToLog(
                                        ProcessingLog.LOG_WARNING,
                                        self.
                                        tr('Geometry exception while splitting'
                                           ))
                                    result = 1

                                # splitGeometry: If there are several intersections
                                # between geometry and splitLine, only the first one is considered.
                                if result == 0:  # split occurred
                                    if inPoints == vector.extractPoints(
                                            inGeom):
                                        # bug in splitGeometry: sometimes it returns 0 but
                                        # the geometry is unchanged
                                        outGeoms.append(inGeom)
                                    else:
                                        inGeoms.append(inGeom)

                                        for aNewGeom in newGeometries:
                                            inGeoms.append(aNewGeom)
                                else:
                                    outGeoms.append(inGeom)
                            else:
                                outGeoms.append(inGeom)

                        inGeoms = outGeoms

            parts = []

            for aGeom in inGeoms:
                passed = True

                if QgsWkbTypes.geometryType(
                        aGeom.wkbType()) == QgsWkbTypes.LineGeometry:
                    numPoints = aGeom.geometry().numPoints()

                    if numPoints <= 2:
                        if numPoints == 2:
                            passed = not aGeom.geometry().isClosed(
                            )  # tests if vertex 0 = vertex 1
                        else:
                            passed = False
                            # sometimes splitting results in lines of zero length

                if passed:
                    parts.append(aGeom)

            if len(parts) > 0:
                outFeat.setGeometry(QgsGeometry.collectGeometry(parts))
                writer.addFeature(outFeat)

            feedback.setProgress(int(current * total))
        del writer
示例#11
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE,
                                             context)

        expression = QgsExpression(
            self.parameterAsString(parameters, self.EXPRESSION, context))
        if expression.hasParserError():
            raise ProcessingException(expression.parserErrorString())

        expressionContext = self.createExpressionContext(parameters, context)
        if not expression.prepare(expressionContext):
            raise ProcessingException(
                self.tr('Evaluation error: {0}').format(
                    expression.evalErrorString()))

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

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

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

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

            expressionContext.setFeature(f)
            value = expression.evaluate(expressionContext)
            if expression.hasEvalError():
                feedback.pushInfo(
                    self.tr('Evaluation error for feature ID {}: {}').format(
                        f.id(), expression.evalErrorString()))
                continue

            fGeom = f.geometry()
            bbox = fGeom.boundingBox()
            if strategy == 0:
                pointCount = int(value)
            else:
                pointCount = int(round(value * da.measureArea(fGeom)))

            if pointCount == 0:
                feedback.pushInfo(
                    "Skip feature {} as number of points for it is 0.")
                continue

            index = QgsSpatialIndex()
            points = dict()

            nPoints = 0
            nIterations = 0
            maxIterations = pointCount * 200
            total = 100.0 / pointCount if pointCount else 1

            random.seed()

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

                rx = bbox.xMinimum() + bbox.width() * random.random()
                ry = bbox.yMinimum() + bbox.height() * random.random()

                p = QgsPointXY(rx, ry)
                geom = QgsGeometry.fromPointXY(p)
                if geom.within(fGeom) and \
                        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.insertFeature(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.'))

            feedback.setProgress(0)

        return {self.OUTPUT: dest_id}
示例#12
0
    def graph_builder(self, network, cost_field, origins, tolerance, crs,
                      epsg):

        # Settings
        otf = False

        # Get index of cost field
        network_fields = network.fields()
        network_cost_index = network_fields.indexFromName(cost_field)

        # Setting up graph build director
        director = QgsVectorLayerDirector(network, -1, '', '', '',
                                          QgsVectorLayerDirector.DirectionBoth)

        # Determining cost calculation
        if cost_field != 'length':
            strategy = ct.CustomCost(network_cost_index, 0.01)
        else:
            strategy = QgsNetworkDistanceStrategy()

        # Creating graph builder
        director.addStrategy(strategy)
        builder = QgsGraphBuilder(crs, otf, tolerance, epsg)

        # Reading origins and making list of coordinates
        graph_origin_points = []

        # Loop through the origin points and add graph vertex indices
        for index, origin in enumerate(origins):
            graph_origin_points.append(origins[index]['geom'].asPoint())

        # Get origin graph vertex index
        tied_origin_vertices = director.makeGraph(builder, graph_origin_points)

        # Build the graph
        graph = builder.graph()

        # Create dictionary of origin names and tied origins
        tied_origins = {}

        # Combine origin names and tied point vertices
        for index, tied_origin in enumerate(tied_origin_vertices):
            tied_origins[index] = {
                'name': origins[index]['name'],
                'vertex': tied_origin
            }

        self.spIndex = QgsSpatialIndex()
        self.indices = {}
        self.attributes_dict = {}
        self.centroids = {}
        i = 0
        for f in network.getFeatures():
            if f.geometry().type() == QgsWkbTypes.LineGeometry:
                if not f.geometry().isMultipart():
                    self.attributes_dict[f.id()] = f.attributes()
                    polyline = f.geometry().asPolyline()
                    for idx, p in enumerate(polyline[1:]):
                        ml = QgsGeometry.fromPolylineXY([polyline[idx], p])
                        new_f = QgsFeature()
                        new_f.setGeometry(ml.centroid())
                        new_f.setAttributes([f.id()])
                        new_f.setId(i)
                        self.spIndex.addFeature(new_f)
                        self.centroids[i] = f.id()
                        i += 1
                else:
                    self.attributes_dict[f.id()] = f.attributes()
                    for pl in f.geometry().asMultiPolyline():
                        for idx, p in enumerate(pl[1:]):
                            ml = QgsGeometry.fromPolylineXY([pl[idx], p])
                            new_f = QgsFeature()
                            new_f.setGeometry(ml.centroid())
                            new_f.setAttributes([f.id()])
                            new_f.setId(i)
                            self.spIndex.addFeature(new_f)
                            self.centroids[i] = f.id()
                            i += 1

        self.network_fields = network_fields
        return graph, tied_origins
示例#13
0
    def processAlgorithm(self, parameters, context, feedback):

        self.feature_source = self.parameterAsSource(parameters, self.INPUT,
                                                     context)
        raster_lyr = self.parameterAsRasterLayer(parameters, self.RASTER_INPUT,
                                                 context)
        all_rasters = self.parameterAsBool(parameters, self.ALL_ACTIVE_RASTERS,
                                           context)
        temp_path = self.parameterAsString(parameters, '', context)
        self.dest_field = self.parameterAsString(parameters, self.FIELD,
                                                 context)
        psm = self.parameterAsInt(parameters, 'PSM', context)
        oem = self.parameterAsInt(parameters, 'OEM', context)
        self.comma = self.parameterAsBool(parameters, 'Remove_comma', context)
        (self.sink,
         dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                         self.feature_source.fields(),
                                         self.feature_source.wkbType(),
                                         self.feature_source.sourceCrs())
        self.source_layer = self.feature_source.materialize(
            QgsFeatureRequest())
        feedback.pushInfo('Temporary files path: ' + str(temp_path))
        self.source_encod = self.source_layer.dataProvider().encoding()
        '''context.setDefaultEncoding(self.source_encod)
        self.output_encod = context.defaultEncoding()
        
        feedback.pushInfo('sys.getdefaultencoding(): ' + sys.getdefaultencoding())
        feedback.pushInfo('in: ' + self.source_encod + ', out: ' + self.output_encod)'''

        if self.source_layer == None:
            list = QgsProject.instance().mapLayersByName(
                self.feature_source.sourceName())
            for lyr in list:
                if self.feature_source.sourceCrs() == lyr.sourceCrs():
                    self.source_layer = lyr

        #feedback.pushInfo('self.source_layer.name(): ' + self.source_layer.name())

        if self.feature_source is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))
        if raster_lyr is None and not all_rasters:
            feedback.pushInfo('\nNo raster layer selected!\n')
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.RASTER_INPUT))
        self.output_temp_tif = os.path.normpath(
            os.path.join(temp_path, 'output.tif'))
        self.output_temp_shp = os.path.normpath(
            os.path.join(temp_path, 'each_feature.shp'))
        self.output_temp_page = os.path.normpath(
            os.path.join(temp_path, 'current_page.tif'))
        '''here is tesseract config string'''
        self.config = '--psm ' + str(psm) + ' --oem ' + str(oem)
        feedback.pushInfo('Tessearct config: ' + self.config)
        '''creating temporary shp file, necessary for clipping'''
        self.crs = self.feature_source.sourceCrs().authid()
        layer = QgsVectorLayer(
            "multipolygon?crs=" + self.crs + "&field=id:integer",
            "temporary layer", "memory")
        QgsVectorFileWriter.writeAsVectorFormat(
            layer, self.output_temp_shp, self.source_encod,
            self.feature_source.sourceCrs(), "ESRI Shapefile", False)
        self.temp_shp_layer = QgsVectorLayer(self.output_temp_shp, "temp",
                                             "ogr")

        features = self.feature_source.getFeatures(QgsFeatureRequest())

        self.index = QgsSpatialIndex()
        for feat in features:
            self.index.insertFeature(feat)

        feedback.pushInfo('\nprocessing time calculating...\n')
        n = []
        if not all_rasters and raster_lyr:
            n = self.index.intersects(raster_lyr.extent())
        else:
            for layer in iface.mapCanvas().layers():
                if layer.type() == 1:
                    n = n + self.index.intersects(layer.extent())
        self.total = len(n)
        self.actual = 0
        if self.total > 0: feedback.setProgress(self.actual / self.total * 100)

        if not all_rasters:
            self.OnThisRaster(feedback, raster_lyr)
        else:
            for layer in iface.mapCanvas().layers():
                if feedback.isCanceled(): break
                if layer.type() == 1:
                    self.OnThisRaster(feedback, layer)

        return {self.OUTPUT: dest_id}
示例#14
0
    def processAlgorithm(self, parameters, context, feedback):
        feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName())))
        network = self.parameterAsVectorLayer(parameters, self.INPUT, context) #QgsVectorLayer
        startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) #QgsPointXY
        max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float
        cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int
        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int
        interpolation_method = self.parameterAsEnum(parameters, self.METHOD, context)#int

        entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int
        directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given)
        forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str
        backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str
        bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str
        defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int
        speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str
        defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float
        tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float
        output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)

        analysisCrs = network.sourceCrs()
        input_coordinates = [startPoint]
        input_point = getFeatureFromPointParameter(startPoint)
        
        feedback.pushInfo("[QNEAT3Algorithm] Building Graph...")
        feedback.setProgress(10)  
        net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback)
        feedback.setProgress(40)
        
        analysis_point = Qneat3AnalysisPoint("point", input_point, "point_id", net, net.list_tiedPoints[0], entry_cost_calc_method, feedback)
        
        feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...")
        iso_pointcloud = net.calcIsoPoints([analysis_point], max_dist)
        feedback.setProgress(70)
        
        uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid())
        
        iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory")
        iso_pointcloud_provider = iso_pointcloud_layer.dataProvider()
        iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert)
        
        feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...")
        if interpolation_method == 0:
            feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...")
            net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path)
            feedback.setProgress(99)
        else:


            #prepare numpy coordinate grids
            NoData_value = -9999
            raster_rectangle = iso_pointcloud_layer.extent()
            
            #implement spatial index for lines (closest line, etc...)
            spt_idx = QgsSpatialIndex(iso_pointcloud_layer.getFeatures(QgsFeatureRequest()), feedback)
            
            #top left point
            xmin = raster_rectangle.xMinimum()
            ymin = raster_rectangle.yMinimum()
            xmax = raster_rectangle.xMaximum()
            ymax = raster_rectangle.yMaximum()
            
            cols = int((xmax - xmin) / cell_size)
            rows = int((ymax - ymin) / cell_size)
            
            output_interpolation_raster = gdal.GetDriverByName('GTiff').Create(output_path, cols, rows, 1, gdal.GDT_Float64 )
            output_interpolation_raster.SetGeoTransform((xmin, cell_size, 0, ymax, 0, -cell_size))
            
            band = output_interpolation_raster.GetRasterBand(1)
            band.SetNoDataValue(NoData_value)
            
            #initialize zero array with 2 dimensions (according to rows and cols)
            raster_routingcost_data = zeros(shape=(rows, cols))
            
            #compute raster cell MIDpoints
            x_pos = linspace(xmin+(cell_size/2), xmax -(cell_size/2), raster_routingcost_data.shape[1])
            y_pos = linspace(ymax-(cell_size/2), ymin + (cell_size/2), raster_routingcost_data.shape[0])
            x_grid, y_grid = meshgrid(x_pos, y_pos) 
            
            feedback.pushInfo('[QNEAT3Network][calcQneatInterpolation] Beginning with interpolation')
            total_work = rows * cols
            counter = 0
    
            feedback.pushInfo('[QNEAT3Network][calcQneatInterpolation] Total workload: {} cells'.format(total_work))
            feedback.setProgress(0)
            for i in range(rows):
                for j in range(cols):
                    current_pixel_midpoint = QgsPointXY(x_grid[i,j],y_grid[i,j])
    
                    nearest_vertex_fid = spt_idx.nearestNeighbor(current_pixel_midpoint, 1)[0]
    
                    nearest_feature = iso_pointcloud_layer.getFeature(nearest_vertex_fid)
    
                    nearest_vertex = net.network.vertex(nearest_feature['vertex_id'])
    
                    #yields a list of all incoming and outgoing edges    
                    edges = nearest_vertex.incomingEdges() + nearest_vertex.outgoingEdges() 
                    
                    vertex_found = False
                    nearest_counter = 2
                    while vertex_found == False:
                        #find the second nearest vertex (eg, the vertex with least cost of all edges incoming to the first nearest vertex)
                        second_nearest_feature_fid = spt_idx.nearestNeighbor(current_pixel_midpoint, nearest_counter)[nearest_counter-1] 
                        second_nearest_feature = iso_pointcloud_layer.getFeature(second_nearest_feature_fid)
                        second_nearest_vertex_id = second_nearest_feature['vertex_id']
    
                        for edge_id in edges:
                            from_vertex_id = net.network.edge(edge_id).fromVertex()
                            to_vertex_id = net.network.edge(edge_id).toVertex()
    
                            if second_nearest_vertex_id == from_vertex_id: 
                                vertex_found = True
                                vertex_type = "from_vertex"
                                from_point = second_nearest_feature.geometry().asPoint()
                                from_vertex_cost = second_nearest_feature['cost']
                                
                            if second_nearest_vertex_id == to_vertex_id:
                                vertex_found = True
                                vertex_type = "to_vertex"
                                to_point = second_nearest_feature.geometry().asPoint()
                                to_vertex_cost = second_nearest_feature['cost']
                                
    
                        nearest_counter = nearest_counter + 1
                        """
                        if nearest_counter == 5:
                            vertex_found = True
                            vertex_type = "end_vertex"
                        """
    
                    if vertex_type == "from_vertex":
                        nearest_edge_geometry = QgsGeometry().fromPolylineXY([from_point, nearest_vertex.point()])
                        res = nearest_edge_geometry.closestSegmentWithContext(current_pixel_midpoint)
                        segment_point = res[1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                        dist_to_segment = segment_point.distance(current_pixel_midpoint)
                        dist_edge = from_point.distance(segment_point)
                        #feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                        #feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                        #feedback.pushInfo("cost = {}".format(from_vertex_cost))
                        pixel_cost = from_vertex_cost + dist_edge + dist_to_segment
                        raster_routingcost_data[i,j] = pixel_cost
                    elif vertex_type == "to_vertex":
                        nearest_edge_geometry = QgsGeometry().fromPolylineXY([nearest_vertex.point(), to_point])
                        res = nearest_edge_geometry.closestSegmentWithContext(current_pixel_midpoint)
                        segment_point = res[1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping]
                        dist_to_segment = segment_point.distance(current_pixel_midpoint)
                        dist_edge = to_point.distance(segment_point)
                        #feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment))
                        #feedback.pushInfo("dist_on_edge = {}".format(dist_edge))
                        #feedback.pushInfo("cost = {}".format(from_vertex_cost))
                        pixel_cost = to_vertex_cost + dist_edge + dist_to_segment
                        raster_routingcost_data[i,j] = pixel_cost
                    else:
                        pixel_cost = -99999#nearest_feature['cost'] + (nearest_vertex.point().distance(current_pixel_midpoint))
    
    
                    """
                    nearest_feature_pointxy = nearest_feature.geometry().asPoint()
                    nearest_feature_cost = nearest_feature['cost']
                    
                    dist_to_vertex = current_pixel_midpoint.distance(nearest_feature_pointxy)
                    #implement time cost
                    pixel_cost = dist_to_vertex + nearest_feature_cost
                    
                    raster_data[i,j] = pixel_cost
                    """
                    counter = counter+1
                    if counter%1000 == 0:
                        feedback.pushInfo("[QNEAT3Network][calcQneatInterpolation] Interpolated {} cells...".format(counter))
                    feedback.setProgress((counter/total_work)*100)
    
    
            band.WriteArray(raster_routingcost_data)
            outRasterSRS = osr.SpatialReference()
            outRasterSRS.ImportFromWkt(net.AnalysisCrs.toWkt())
            output_interpolation_raster.SetProjection(outRasterSRS.ExportToWkt())
            band.FlushCache()

        
        feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm")
        feedback.setProgress(100)           
        
        results = {}
        results[self.OUTPUT] = output_path
        return results
示例#15
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))

        strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
        if self.MIN_DISTANCE in parameters and parameters[
                self.MIN_DISTANCE] is not None:
            minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE,
                                                 context)
        else:
            minDistance = None

        expressionContext = self.createExpressionContext(
            parameters, context, source)
        dynamic_value = QgsProcessingParameters.isDynamic(parameters, "VALUE")
        value_property = None
        if self.EXPRESSION in parameters and parameters[
                self.EXPRESSION] is not None:
            expression = QgsExpression(
                self.parameterAsString(parameters, self.EXPRESSION, context))
            value = None
            if expression.hasParserError():
                raise QgsProcessingException(expression.parserErrorString())
            expression.prepare(expressionContext)
        else:
            expression = None
            if dynamic_value:
                value_property = parameters["VALUE"]
            value = self.parameterAsDouble(parameters, self.VALUE, 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(),
                                         QgsFeatureSink.RegeneratePrimaryKey)
        if sink is None:
            raise QgsProcessingException(
                self.invalidSinkError(parameters, self.OUTPUT))

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

        total = 100.0 / source.featureCount() if source.featureCount() else 0
        current_progress = 0
        pointId = 0
        for current, f in enumerate(source.getFeatures()):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                continue

            current_progress = total * current
            feedback.setProgress(current_progress)

            this_value = value
            if value_property is not None or expression is not None:
                expressionContext.setFeature(f)
                if value_property:
                    this_value, _ = value_property.valueAsDouble(
                        expressionContext, value)
                else:
                    this_value = expression.evaluate(expressionContext)
                    if expression.hasEvalError():
                        feedback.pushInfo(
                            self.tr('Evaluation error for feature ID {}: {}').
                            format(f.id(), expression.evalErrorString()))
                        continue

            fGeom = f.geometry()
            engine = QgsGeometry.createGeometryEngine(fGeom.constGet())
            engine.prepareGeometry()

            bbox = fGeom.boundingBox()
            if strategy == 0:
                pointCount = int(this_value)
            else:
                pointCount = int(round(this_value * da.measureArea(fGeom)))

            if pointCount == 0:
                feedback.pushInfo(
                    "Skip feature {} as number of points for it is 0.".format(
                        f.id()))
                continue

            index = None
            if minDistance:
                index = QgsSpatialIndex()
            points = dict()

            nPoints = 0
            nIterations = 0
            maxIterations = pointCount * 200
            feature_total = total / pointCount if pointCount else 1

            random.seed()

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

                rx = bbox.xMinimum() + bbox.width() * random.random()
                ry = bbox.yMinimum() + bbox.height() * random.random()

                p = QgsPointXY(rx, ry)
                geom = QgsGeometry.fromPointXY(p)
                if engine.contains(geom.constGet()) and \
                        (not minDistance or vector.checkMinDistance(p, index, minDistance, points)):
                    f = QgsFeature(nPoints)
                    f.initAttributes(1)
                    f.setFields(fields)
                    f.setAttribute('id', pointId)
                    f.setGeometry(geom)
                    sink.addFeature(f, QgsFeatureSink.FastInsert)
                    if minDistance:
                        index.addFeature(f)
                    points[nPoints] = p
                    nPoints += 1
                    pointId += 1
                    feedback.setProgress(current_progress +
                                         int(nPoints * feature_total))
                nIterations += 1

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

        feedback.setProgress(100)

        return {self.OUTPUT: dest_id}
    def doWork(self):
        flayer = self.flayer
        tlayer = self.tlayer
        ffield = self.ffield
        tfield = self.tfield

        self.from_layer = get_vector_layer_by_name(flayer)
        self.to_layer = get_vector_layer_by_name(tlayer)

        self.transform = None
        if self.from_layer.dataProvider().crs() != self.to_layer.dataProvider().crs():
            self.transform = QgsCoordinateTransform(self.from_layer.dataProvider().crs(),
                                                    self.to_layer.dataProvider().crs())

        # FIELDS INDICES
        idx = self.from_layer.fieldNameIndex(ffield)
        fid = self.to_layer.fieldNameIndex(tfield)

        # We create an spatial self.index to hold all the features of the layer that will receive the data
        # And a dictionary that will hold all the features IDs found to intersect with each feature in the spatial index
        self.emit(SIGNAL("ProgressMaxValue( PyQt_PyObject )"), self.to_layer.dataProvider().featureCount())
        self.emit(SIGNAL("ProgressText( PyQt_PyObject )"), 'Building Spatial Index')
        allfeatures = {}
        merged = {}
        self.index = QgsSpatialIndex()
        for i, feature in enumerate(self.to_layer.getFeatures()):
            allfeatures[feature.id()] = feature
            merged[feature.id()] = feature
            self.index.insertFeature(feature)
            self.emit(SIGNAL("ProgressValue( PyQt_PyObject )"), i)

        self.emit(SIGNAL("ProgressText( PyQt_PyObject )"), 'Duplicating Layers')
        self.all_attr = {}
        # We create the memory layer that will have the analysis result, which is the lowest common
        # denominator of both layers
        epsg_code = int(self.to_layer.crs().authid().split(":")[1])
        if self.from_layer.wkbType() in self.poly_types and self.to_layer.wkbType() in self.poly_types:
            lcd_layer = QgsVectorLayer("MultiPolygon?crs=epsg:" + str(epsg_code), "output", "memory")
            self.output_type = 'Poly'

        elif self.from_layer.wkbType() in self.poly_types + self.line_types and \
                self.to_layer.wkbType() in self.poly_types + self.line_types:
            lcd_layer = QgsVectorLayer("MultiLineString?crs=epsg:" + str(epsg_code), "output", "memory")
            self.output_type = 'Line'
        else:
            lcd_layer = QgsVectorLayer("MultiPoint?crs=epsg:" + str(epsg_code), "output", "memory")
            self.output_type = 'Point'

        lcdpr = lcd_layer.dataProvider()
        lcdpr.addAttributes([QgsField("Part_ID", QVariant.Int),
                             QgsField(ffield, self.from_layer.fields().field(idx).type()),
                             QgsField(tfield, self.to_layer.fields().field(fid).type()),
                             QgsField('P-' + str(ffield), QVariant.Double),  # percentage of the from field
                             QgsField('P-' + str(tfield), QVariant.Double)])  # percentage of the to field
        lcd_layer.updateFields()

        # PROGRESS BAR
        self.emit(SIGNAL("ProgressMaxValue( PyQt_PyObject )"), self.from_layer.dataProvider().featureCount())
        self.emit(SIGNAL("ProgressText( PyQt_PyObject )"), 'Running Analysis')
        part_id = 1
        features = []
        for fc, feat in enumerate(self.from_layer.getFeatures()):
            geom = feat.geometry()
            if geom is not None:
                if self.transform is not None:
                    a = geom.transform(self.transform)
                geometry, statf = self.find_geometry(geom)
                uncovered, statf = self.find_geometry(geom)
                # uncovered = copy.deepcopy(geometry)

                intersecting = self.index.intersects(geometry.boundingBox())
                # Find all intersecting parts
                for f in intersecting:
                    g = geometry.intersection(allfeatures[f].geometry())
                    if g.area() > 0:
                        feature = QgsFeature()
                        geo, stati = self.find_geometry(g)
                        feature.setGeometry(geo)
                        geo, statt = self.find_geometry(allfeatures[f].geometry())
                        perct = stati / statt
                        percf = stati / statf
                        feature.setAttributes([part_id,
                                               feat.attributes()[idx],
                                               allfeatures[f].attributes()[fid],
                                               percf,
                                               perct])
                        features.append(feature)

                        # prepare the data for the non overlapping
                        if uncovered is not None:
                            uncovered = uncovered.difference(g)
                            aux = merged[f].geometry().difference(g)
                            if aux is not None:
                                merged[f].setGeometry(aux)
                            part_id += 1

                # Find the part that does not intersect anything
                if uncovered is not None:
                    if uncovered.area() > 0:
                        feature = QgsFeature()
                        geo, stati = self.find_geometry(uncovered)
                        feature.setGeometry(geo)
                        perct = 0
                        percf = stati / statf
                        feature.setAttributes([part_id,
                                               feat.attributes()[idx],
                                               '',
                                               percf,
                                               perct])
                        features.append(feature)
                        part_id += 1

            self.emit(SIGNAL("ProgressValue( PyQt_PyObject )"), fc)
            self.emit(SIGNAL("ProgressText( PyQt_PyObject )"),
                      'Running Analysis (' + "{:,}".format(fc) + '/' + "{:,}".format(
                          self.from_layer.featureCount()) + ')')

        # Find the features on TO that have no correspondence in FROM
        for f, feature in merged.iteritems():
            geom = feature.geometry()
            aux, statt = self.find_geometry(allfeatures[f].geometry())
            if geom.area() > 0:
                feature = QgsFeature()
                geo, stati = self.find_geometry(geom)
                feature.setGeometry(geo)
                perct = stati / statt
                percf = 0
                feature.setAttributes([part_id,
                                       '',
                                       allfeatures[f].attributes()[fid],
                                       percf,
                                       perct])
                features.append(feature)
                part_id += 1

        if features:
            a = lcdpr.addFeatures(features)
        self.result = lcd_layer

        self.emit(SIGNAL("ProgressValue( PyQt_PyObject )"), self.from_layer.dataProvider().featureCount())
        self.emit(SIGNAL("finished_threaded_procedure( PyQt_PyObject )"), "procedure")
示例#17
0
文件: Union.py 项目: MieWinstrup/QGIS
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

        geomType = QgsWkbTypes.multiType(sourceA.wkbType())
        fields = QgsProcessingUtils.combineFields(sourceA.fields(), sourceB.fields())

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

        featA = QgsFeature()
        featB = QgsFeature()
        outFeat = QgsFeature()

        indexA = QgsSpatialIndex(sourceA, feedback)
        indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs(), context.transformContext())), feedback)

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

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

            lstIntersectingB = []
            geom = featA.geometry()
            atMapA = featA.attributes()
            intersects = indexB.intersects(geom.boundingBox())
            if len(intersects) < 1:
                try:
                    geom.convertToMultiType()
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMapA)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    # This really shouldn't happen, as we haven't
                    # edited the input geom at all
                    feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
            else:
                request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
                request.setDestinationCrs(sourceA.sourceCrs(), context.transformContext())

                engine = QgsGeometry.createGeometryEngine(geom.constGet())
                engine.prepareGeometry()

                for featB in sourceB.getFeatures(request):
                    atMapB = featB.attributes()
                    tmpGeom = featB.geometry()

                    if engine.intersects(tmpGeom.constGet()):
                        int_geom = geom.intersection(tmpGeom)
                        lstIntersectingB.append(tmpGeom)

                        if not int_geom:
                            # There was a problem creating the intersection
                            feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
                            int_geom = QgsGeometry()
                        else:
                            int_geom = QgsGeometry(int_geom)

                        if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.wkbType()) == QgsWkbTypes.GeometryCollection:
                            # Intersection produced different geomety types
                            temp_list = int_geom.asGeometryCollection()
                            for i in temp_list:
                                if i.type() == geom.type():
                                    int_geom = QgsGeometry(i)
                                    try:
                                        int_geom.convertToMultiType()
                                        outFeat.setGeometry(int_geom)
                                        outFeat.setAttributes(atMapA + atMapB)
                                        sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                                    except:
                                        feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
                        else:
                            # Geometry list: prevents writing error
                            # in geometries of different types
                            # produced by the intersection
                            # fix #3549
                            if QgsWkbTypes.geometryType(int_geom.wkbType()) == QgsWkbTypes.geometryType(geomType):
                                try:
                                    int_geom.convertToMultiType()
                                    outFeat.setGeometry(int_geom)
                                    outFeat.setAttributes(atMapA + atMapB)
                                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                                except:
                                    feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))

                # the remaining bit of featA's geometry
                # if there is nothing left, this will just silently fail and we're good
                diff_geom = QgsGeometry(geom)
                if len(lstIntersectingB) != 0:
                    intB = QgsGeometry.unaryUnion(lstIntersectingB)
                    diff_geom = diff_geom.difference(intB)

                if diff_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(diff_geom.wkbType()) == QgsWkbTypes.GeometryCollection:
                    temp_list = diff_geom.asGeometryCollection()
                    for i in temp_list:
                        if i.type() == geom.type():
                            diff_geom = QgsGeometry(i)
                try:
                    diff_geom.convertToMultiType()
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMapA)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))

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

        length = len(sourceA.fields())
        atMapA = [None] * length

        for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs(), context.transformContext())):
            if feedback.isCanceled():
                break

            add = False
            geom = featA.geometry()
            diff_geom = QgsGeometry(geom)
            atMap = [None] * length
            atMap.extend(featA.attributes())
            intersects = indexA.intersects(geom.boundingBox())

            if len(intersects) < 1:
                try:
                    geom.convertToMultiType()
                    outFeat.setGeometry(geom)
                    outFeat.setAttributes(atMap)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
            else:
                request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
                request.setDestinationCrs(sourceA.sourceCrs(), context.transformContext())

                # use prepared geometries for faster intersection tests
                engine = QgsGeometry.createGeometryEngine(diff_geom.constGet())
                engine.prepareGeometry()

                for featB in sourceA.getFeatures(request):
                    atMapB = featB.attributes()
                    tmpGeom = featB.geometry()

                    if engine.intersects(tmpGeom.constGet()):
                        add = True
                        diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
                    else:
                        try:
                            # Ihis only happens if the bounding box
                            # intersects, but the geometry doesn't
                            diff_geom.convertToMultiType()
                            outFeat.setGeometry(diff_geom)
                            outFeat.setAttributes(atMap)
                            sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                        except:
                            feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))

            if add:
                try:
                    diff_geom.convertToMultiType()
                    outFeat.setGeometry(diff_geom)
                    outFeat.setAttributes(atMap)
                    sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
                except:
                    feedback.pushInfo(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))

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

        return {self.OUTPUT: dest_id}
示例#18
0
    def processAlgorithm(self, parameters, context, feedback):
        sourceA = self.parameterAsSource(parameters, self.INPUT, context)
        sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

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

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

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

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

        output_fields = QgsProcessingUtils.combineFields(
            fieldListA, fieldListB)

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

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

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

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

            if not featA.hasGeometry():
                continue

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

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

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

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

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

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

        return {self.OUTPUT: dest_id}
示例#19
0
文件: SumLines.py 项目: peppsac/QGIS
    def processAlgorithm(self, parameters, context, feedback):
        line_source = self.parameterAsSource(parameters, self.LINES, context)
        poly_source = self.parameterAsSource(parameters, self.POLYGONS,
                                             context)

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

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

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               poly_source.wkbType(),
                                               poly_source.sourceCrs())

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

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

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

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

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

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

                output_feature.setGeometry(poly_geom)

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

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
示例#20
0
    def processAlgorithm(self, progress):
        layerA = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_A))
        splitLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_B))

        sameLayer = self.getParameterValue(self.INPUT_A) == self.getParameterValue(self.INPUT_B)
        fieldList = layerA.fields()

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

        spatialIndex = QgsSpatialIndex()
        splitGeoms = {}
        request = QgsFeatureRequest()
        request.setSubsetOfAttributes([])

        for aSplitFeature in vector.features(splitLayer, request):
            splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry()
            spatialIndex.insertFeature(aSplitFeature)
            # honor the case that user has selection on split layer and has setting "use selection"

        outFeat = QgsFeature()
        features = vector.features(layerA)

        if len(features) == 0:
            total = 100
        else:
            total = 100.0 / float(len(features))

        multiGeoms = 0 # how many multi geometries were encountered

        for current, inFeatA in enumerate(features):
            inGeom = inFeatA.geometry()

            if inGeom.isMultipart():
                multiGeoms += 1
                # MultiGeometries are not allowed because the result of a splitted part cannot be clearly defined:
                # 1) add both new parts as new features
                # 2) store one part as a new feature and the other one as part of the multi geometry
                # 2a) which part should be which, seems arbitrary
            else:
                attrsA = inFeatA.attributes()
                outFeat.setAttributes(attrsA)
                inGeoms = [inGeom]
                lines = spatialIndex.intersects(inGeom.boundingBox())

                if len(lines) > 0:  # has intersection of bounding boxes
                    splittingLines = []

                    engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
                    engine.prepareGeometry()

                    for i in lines:
                        try:
                            splitGeom = splitGeoms[i]
                        except:
                            continue

                        # check if trying to self-intersect
                        if sameLayer:
                            if inFeatA.id() == i:
                                continue

                        if engine.intersects(splitGeom.geometry()):
                            splittingLines.append(splitGeom)

                    if len(splittingLines) > 0:
                        for splitGeom in splittingLines:
                            splitterPList = None
                            outGeoms = []

                            split_geom_engine = QgsGeometry.createGeometryEngine(splitGeom.geometry())
                            split_geom_engine.prepareGeometry()

                            while len(inGeoms) > 0:
                                inGeom = inGeoms.pop()

                                if split_geom_engine.intersects(inGeom.geometry()):
                                    inPoints = vector.extractPoints(inGeom)
                                    if splitterPList == None:
                                        splitterPList = vector.extractPoints(splitGeom)

                                    try:
                                        result, newGeometries, topoTestPoints = inGeom.splitGeometry(splitterPList, False)
                                    except:
                                        ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
                                                               self.tr('Geometry exception while splitting'))
                                        result = 1

                                    # splitGeometry: If there are several intersections
                                    # between geometry and splitLine, only the first one is considered.
                                    if result == 0:  # split occurred
                                        if inPoints == vector.extractPoints(inGeom):
                                            # bug in splitGeometry: sometimes it returns 0 but
                                            # the geometry is unchanged
                                            QgsMessageLog.logMessage("appending")
                                            outGeoms.append(inGeom)
                                        else:
                                            inGeoms.append(inGeom)

                                            for aNewGeom in newGeometries:
                                                inGeoms.append(aNewGeom)
                                    else:
                                        QgsMessageLog.logMessage("appending else")
                                        outGeoms.append(inGeom)
                                else:
                                    outGeoms.append(inGeom)

                            inGeoms = outGeoms

                for aGeom in inGeoms:
                    passed = True

                    if QgsWkbTypes.geometryType( aGeom.wkbType() )  == QgsWkbTypes.LineGeometry \
                            and not QgsWkbTypes.isMultiType(aGeom.wkbType()):
                        passed = len(aGeom.asPolyline()) > 2

                        if not passed:
                            passed = (len(aGeom.asPolyline()) == 2 and
                                      aGeom.asPolyline()[0] != aGeom.asPolyline()[1])
                            # sometimes splitting results in lines of zero length

                    if passed:
                        outFeat.setGeometry(aGeom)
                        writer.addFeature(outFeat)

            progress.setPercentage(int(current * total))

        if multiGeoms > 0:
            ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                   self.tr('Feature geometry error: %s input features ignored due to multi-geometry.') % str(multiGeoms))

        del writer
示例#21
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER,
                                            context)
        minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE,
                                             context)

        bbox = source.sourceExtent()
        sourceIndex = QgsSpatialIndex(source, feedback)

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

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

        nPoints = 0
        nIterations = 0
        maxIterations = pointCount * 200
        total = 100.0 / pointCount if pointCount else 1

        index = QgsSpatialIndex()
        points = dict()

        random.seed()

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

            rx = bbox.xMinimum() + bbox.width() * random.random()
            ry = bbox.yMinimum() + bbox.height() * random.random()

            p = QgsPointXY(rx, ry)
            geom = QgsGeometry.fromPoint(p)
            ids = sourceIndex.intersects(geom.buffer(5, 5).boundingBox())
            if len(ids) > 0 and \
                    vector.checkMinDistance(p, index, minDistance, points):
                request = QgsFeatureRequest().setFilterFids(
                    ids).setSubsetOfAttributes([])
                for f in source.getFeatures(request):
                    if feedback.isCanceled():
                        break

                    tmpGeom = f.geometry()
                    if geom.within(tmpGeom):
                        f = QgsFeature(nPoints)
                        f.initAttributes(1)
                        f.setFields(fields)
                        f.setAttribute('id', nPoints)
                        f.setGeometry(geom)
                        sink.addFeature(f, QgsFeatureSink.FastInsert)
                        index.insertFeature(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}
示例#22
0
    def processAlgorithm(self, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.VECTOR), context)
        fieldName = self.getParameterValue(self.FIELD)
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))
        strategy = self.getParameterValue(self.STRATEGY)

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

        da = QgsDistanceArea()

        features = QgsProcessingUtils.getFeatures(layer, context)
        for current, f in enumerate(features):
            fGeom = f.geometry()
            bbox = fGeom.boundingBox()
            if strategy == 0:
                pointCount = int(f[fieldName])
            else:
                pointCount = int(round(f[fieldName] * da.measureArea(fGeom)))

            if pointCount == 0:
                feedback.pushInfo("Skip feature {} as number of points for it is 0.")
                continue

            index = QgsSpatialIndex()
            points = dict()

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

            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)
                if geom.within(fGeom) and \
                   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)

            feedback.setProgress(0)

        del writer
示例#23
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.insertFeature(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}
示例#24
0
    def generate_sampling_points(self, pixel_values, number_of_samples, min_distance,
                                 neighbor_aggregation, attempts_by_sampling, progress_bar, random_seed):
        """Some code base from (by Alexander Bruy):
        https://github.com/qgis/QGIS/blob/release-2_18/python/plugins/processing/algs/qgis/RandomPointsExtent.py
        """
        self.pixel_values = pixel_values
        self.number_of_samples = number_of_samples  # desired
        self.total_of_samples = None  # total generated
        self.min_distance = min_distance
        self.neighbor_aggregation = neighbor_aggregation
        progress_bar.setValue(0)  # init progress bar

        self.ThematicR_boundaries = QgsGeometry().fromRect(self.ThematicR.extent())

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))
        thematic_CRS = self.ThematicR.qgs_layer.crs()
        file_format = \
            "GPKG" if self.output_file.endswith(".gpkg") else "ESRI Shapefile" if self.output_file.endswith(".shp") else None
        writer = QgsVectorFileWriter(self.output_file, "System", fields, QgsWkbTypes.Point, thematic_CRS, file_format)

        if self.sampling_type == "simple":
            total_of_samples = self.number_of_samples
        if self.sampling_type == "stratified":
            total_of_samples = sum(self.number_of_samples)
            self.samples_in_categories = [0] * len(self.number_of_samples)  # total generated by categories

        nPoints = 0
        nIterations = 0
        self.index = QgsSpatialIndex()
        if attempts_by_sampling:
            maxIterations = total_of_samples * attempts_by_sampling
        else:
            maxIterations = float('Inf')

        # init the random sampling seed
        self.random_seed = random_seed
        random.seed(self.random_seed)

        points_generated = []
        while nIterations < maxIterations and nPoints < total_of_samples:

            random_sampling_point = RandomPoint(self.ThematicR.extent())

            # checks to the sampling point, else discard and continue
            if not self.check_sampling_point(random_sampling_point):
                nIterations += 1
                continue

            if self.sampling_type == "stratified":
                self.samples_in_categories[random_sampling_point.index_pixel_value] += 1

            points_generated.append(random_sampling_point)

            # it requires tmp save the point to check min distance for the next sample
            f = QgsFeature(nPoints)
            f.setGeometry(random_sampling_point.QgsGeom)
            self.index.insertFeature(f)
            self.points[nPoints] = random_sampling_point.QgsPnt

            nPoints += 1
            nIterations += 1
            # update progress bar
            progress_bar.setValue(int(nPoints))

        # guarantee the random order for the classification
        random.shuffle(points_generated)
        self.points = dict()  # restart

        for num_point, point_generated in enumerate(points_generated):
            # random sampling point passed the checks, save it
            f = QgsFeature()
            f.initAttributes(1)
            f.setFields(fields)
            f.setAttribute('id', num_point+1)
            f.setGeometry(point_generated.QgsGeom)
            writer.addFeature(f)
            self.points[num_point] = point_generated.QgsPnt

        # save the total point generated
        self.total_of_samples = len(points_generated)
        del writer, self.index
示例#25
0
    def linearMatrix(self, parameters, context, source, inField, target_source, targetField,
                     matType, nPoints, feedback):
        inIdx = source.fields().lookupField(inField)
        outIdx = target_source.fields().lookupField(targetField)

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

        out_wkb = QgsWkbTypes.multiType(source.wkbType()) if matType == 0 else source.wkbType()
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               fields, out_wkb, source.sourceCrs())

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

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

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

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

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

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

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

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

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
示例#26
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))

        output_file = self.parameterAsFileOutput(parameters,
                                                 self.OUTPUT_HTML_FILE,
                                                 context)

        spatialIndex = QgsSpatialIndex(source, feedback)

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

        sumDist = 0.00
        A = source.sourceExtent()
        A = float(A.width() * A.height())

        features = source.getFeatures()
        count = source.featureCount()
        total = 100.0 / count if count else 1
        for current, feat in enumerate(features):
            if feedback.isCanceled():
                break

            neighbourID = spatialIndex.nearestNeighbor(
                feat.geometry().asPoint(), 2)[1]
            request = QgsFeatureRequest().setFilterFid(
                neighbourID).setSubsetOfAttributes([])
            neighbour = next(source.getFeatures(request))
            sumDist += distance.measureLine(neighbour.geometry().asPoint(),
                                            feat.geometry().asPoint())

            feedback.setProgress(int(current * total))

        do = float(sumDist) / count
        de = float(0.5 / math.sqrt(count / A))
        d = float(do / de)
        SE = float(0.26136 / math.sqrt(count**2 / A))
        zscore = float((do - de) / SE)

        results = {}
        results[self.OBSERVED_MD] = do
        results[self.EXPECTED_MD] = de
        results[self.NN_INDEX] = d
        results[self.POINT_COUNT] = count
        results[self.Z_SCORE] = zscore

        if output_file:
            data = []
            data.append('Observed mean distance: ' + str(do))
            data.append('Expected mean distance: ' + str(de))
            data.append('Nearest neighbour index: ' + str(d))
            data.append('Number of points: ' + str(count))
            data.append('Z-Score: ' + str(zscore))
            self.createHTML(output_file, data)
            results[self.OUTPUT_HTML_FILE] = output_file

        return results
示例#27
0
    def processAlgorithm(self, parameters, context, feedback):
        poly_source = self.parameterAsSource(parameters, self.POLYGONS,
                                             context)
        point_source = self.parameterAsSource(parameters, self.POINTS, context)

        weight_field = self.parameterAsString(parameters, self.WEIGHT, context)
        weight_field_index = -1
        if weight_field:
            weight_field_index = point_source.fields().lookupField(
                weight_field)

        class_field = self.parameterAsString(parameters, self.CLASSFIELD,
                                             context)
        class_field_index = -1
        if class_field:
            class_field_index = point_source.fields().lookupField(class_field)

        field_name = self.parameterAsString(parameters, self.FIELD, context)

        fields = poly_source.fields()
        if fields.lookupField(field_name) < 0:
            fields.append(QgsField(field_name, QVariant.Int))
        field_index = fields.lookupField(field_name)

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
                                               context, fields,
                                               poly_source.wkbType(),
                                               poly_source.sourceCrs())

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

        point_attribute_indices = []
        if weight_field_index >= 0:
            point_attribute_indices.append(weight_field_index)
        if class_field_index >= 0:
            point_attribute_indices.append(class_field_index)

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

            count = 0
            output_feature = QgsFeature()
            if polygon_feature.hasGeometry():
                geom = polygon_feature.geometry()
                engine = QgsGeometry.createGeometryEngine(geom.geometry())
                engine.prepareGeometry()

                count = 0
                classes = set()

                points = spatialIndex.intersects(geom.boundingBox())
                if len(points) > 0:
                    request = QgsFeatureRequest().setFilterFids(
                        points).setDestinationCrs(poly_source.sourceCrs())
                    request.setSubsetOfAttributes(point_attribute_indices)
                    for point_feature in point_source.getFeatures(request):
                        if feedback.isCanceled():
                            break

                        if engine.contains(
                                point_feature.geometry().geometry()):
                            if weight_field_index >= 0:
                                weight = point_feature.attributes(
                                )[weight_field_index]
                                try:
                                    count += float(weight)
                                except:
                                    # Ignore fields with non-numeric values
                                    pass
                            elif class_field_index >= 0:
                                point_class = point_feature.attributes(
                                )[class_field_index]
                                if point_class not in classes:
                                    classes.add(point_class)
                            else:
                                count += 1

                output_feature.setGeometry(geom)

            attrs = polygon_feature.attributes()

            if class_field_index >= 0:
                score = len(classes)
            else:
                score = count
            if field_index == len(attrs):
                attrs.append(score)
            else:
                attrs[field_index] = score
            output_feature.setAttributes(attrs)
            sink.addFeature(output_feature, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
示例#28
0
def get_feats_on_bbox(layer, bbox):
    index = QgsSpatialIndex(layer.getFeatures())
    feats_int = index.intersects(bbox)
    return feats_int
示例#29
0
    def processAlgorithm(self, parameters, context, feedback):
        if parameters[self.INPUT] == parameters[self.HUBS]:
            raise QgsProcessingException(
                self.tr('Same layer given for both hubs and spokes'))

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

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

        fieldName = self.parameterAsString(parameters, self.FIELD, context)

        units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT,
                                                context)]

        fields = point_source.fields()
        fields.append(QgsField('HubName', QVariant.String))
        fields.append(QgsField('HubDist', QVariant.Double))

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

        index = QgsSpatialIndex(
            hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(
                []).setDestinationCrs(point_source.sourceCrs(),
                                      context.transformContext())))

        distance = QgsDistanceArea()
        distance.setSourceCrs(point_source.sourceCrs(),
                              context.transformContext())
        distance.setEllipsoid(context.project().ellipsoid())

        # Scan source points, find nearest hub, and write to output file
        features = point_source.getFeatures()
        total = 100.0 / point_source.featureCount(
        ) if point_source.featureCount() else 0
        for current, f in enumerate(features):
            if feedback.isCanceled():
                break

            if not f.hasGeometry():
                sink.addFeature(f, QgsFeatureSink.FastInsert)
                continue

            src = f.geometry().boundingBox().center()

            neighbors = index.nearestNeighbor(src, 1)
            ft = next(
                hub_source.getFeatures(QgsFeatureRequest().setFilterFid(
                    neighbors[0]).setSubsetOfAttributes(
                        [fieldName], hub_source.fields()).setDestinationCrs(
                            point_source.sourceCrs(),
                            context.transformContext())))
            closest = ft.geometry().boundingBox().center()
            hubDist = distance.measureLine(src, closest)

            if units != self.LAYER_UNITS:
                hub_dist_in_desired_units = distance.convertLengthMeasurement(
                    hubDist, units)
            else:
                hub_dist_in_desired_units = hubDist

            attributes = f.attributes()
            attributes.append(ft[fieldName])
            attributes.append(hub_dist_in_desired_units)

            feat = QgsFeature()
            feat.setAttributes(attributes)

            feat.setGeometry(QgsGeometry.fromPointXY(src))

            sink.addFeature(feat, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        return {self.OUTPUT: dest_id}
    def addTransportData(self,
                         shapefile,
                         startTime,
                         epsgCode,
                         roadTypeField,
                         roadTypeNames,
                         inputIdField,
                         speedDataField=None,
                         speedConversionFactor=None,
                         totalAADTField=None,
                         vAADTFields=None):
        ''' Adds transport data to the object, associates it with a start time and calculates disaggregated hourly mean transport QF
        :param shapefile: string: path to input shapefile
        :param startTime: datetime: time from which this data should be used
        :param roadTypeField: string: Attribute containing the road classification
        :param roadTypeNames: dict: How the main road types are identified in the shapefile {'motorway':str, 'primary_road':str, 'secondary_road':str}
        :param inputIdField: str: Name of shapefile field containing unique identifiers for each road segment
        :param speedDataField: str: shapefile attribute containing speed data (None if not available)
        :param speedConversionFactor: float: if speed is read from shapefile, multiply it by this factor to convert it to km/h
        :param totalAADTField: str: shapefile attribute containing total Annual Averaged Daily Total traffic count (total across all vechile types) (None if not available)
        :param vADDTflds: dict: shapefile attributes to use for each separate vehicle type's AADT
            Two variants allowed, one with separate fuels for LGVs and cars, and one without:
            Allowed keys 1: diesel_car, petrol_car, diesel_lgv, petrol_lgv, motorcycle, taxi, bus, coach, rigid, artic
            Allowed keys 2: total_car, total_lgv, motorcycle, taxi, bus, coach, rigid, artic
        :param epsgCode: int: EPSG code of shapefile
        :return: QgsVectorLayer: Mean hourly transport heat flux in each output area polygon
        '''

        # Flags to identify the level of detail of the input data
        speedDataAvailable = False  # Mean traffic speed available for each road segment
        # AADT is broken down into the vehicles listed in completeInputs
        completeInputAADTprovided = False
        # AADT data is broken down into the vehicles listed in modelledTypes
        modelledTypesAADTprovided = False
        self.validateInputs(startTime, shapefile, epsgCode, roadTypeField,
                            roadTypeNames)

        # This is a way to look up our version of the road type, given the shapefile's version of the road type
        roadTypeLookup = {roadTypeNames[key]: key for key in self.roadTypes}
        # For all other road types that don't match the above
        roadTypeLookup['other'] = 'other'

        # Establish what speed data is available
        # TODO: Use speed in fuel efficiency lookup
        # Master list of all the fields to sample from the shapefile. Gets built up as we go along...
        fieldsToSample = [roadTypeField]

        if type(speedDataField) is str:
            speedDataAvailable = True
            try:
                speedConversionFactor = float(speedConversionFactor)
            except Exception:
                raise ValueError('Vehicle speed multiplier must be a number')
            fieldsToSample.append(speedDataField)

        # Establish what AADT data is available
        if type(totalAADTField) is str:
            fieldsToSample.append(totalAADTField)

        # Validate fields for AADT by vehicle type, if it was provided
        if type(vAADTFields) is dict:
            allowedKeys1 = self.completeInputs
            allowedKeys2 = self.modelledTypes
            missingFrom1 = list(
                set(allowedKeys1).difference(list(vAADTFields.keys())))
            missingFrom2 = list(
                set(allowedKeys2).difference(list(vAADTFields.keys())))
            if len(missingFrom1) == 0:
                completeInputAADTprovided = True
            elif len(missingFrom2) == 0:
                modelledTypesAADTprovided = True
            else:
                raise ValueError(
                    'The vehicle AADT field names provided are incomplete. Expected: '
                    + str(allowedKeys1) + ' OR ' + str(allowedKeys2) +
                    '. Got: ' + str(list(vAADTFields.keys())))
            fieldsToSample.extend(list(vAADTFields.values()))

        # Make a copy of the shapefile in a temp folder (we wish to change it)
        # Ensure the input layer has the right projection when it gets there
        shapefile = reprojectVectorLayer(shapefile,
                                         self.transport.templateEpsgCode)
        #inputLayer = loadShapeFile(shapefile)
        inputLayer = openShapeFileInMemory(shapefile,
                                           self.transport.templateEpsgCode,
                                           'transport')

        try:
            # Try to delete tempfile but don't explode if fail as QGIS sometimes hangs onto them for slightly too long
            rmtree(os.path.dirname(shapefile))
        except:
            pass

        # TODO: Explain to the logger what we are doing with the various fields

        # Get lookup between field names and indices
        fieldNames = {
            a.name(): i
            for i, a in enumerate(inputLayer.dataProvider().fields())
        }

        # Check that the requested field names are actually present in the layer
        missingFields = list(
            set(fieldsToSample).difference(list(fieldNames.keys())))
        if len(missingFields) > 0:
            raise ValueError(
                'Some of the transport shapefile fields referenced were not found in the shapefile:'
                + str(missingFields))

        # Calculate fuel use in each segment
        # TODO 2: Support a vehicle age profile (only a static profile is likely to be tractable)
        # TODO 1: Get this from the parameters file
        # For now, just assumes every vehicle was made in 2005 and looks up values from the fuel consumption object
        vehDate = pd.datetime.strptime('2005-01-01', '%Y-%m-%d')

        # Come up with a read-across between transport road types and euroclass road types
        # Any roads not matching these are assumed to be very minor and are omitted
        # TODO: Refine this treatment

        # Clone the output layer (populate this with [dis]aggregated data) and create spatial index
        outputLayer = duplicateVectorLayer(
            self.transport.outputLayer,
            targetEPSG=self.transport.templateEpsgCode)
        inputIndex = QgsSpatialIndex()

        for feat in inputLayer.getFeatures():
            inputIndex.addFeature(feat)

        # Get translation to look up internal feature ID based on our preferred ID field
        t = shapefile_attributes(outputLayer)[self.transport.templateIdField]
        featureMapper = pd.Series(index=list(map(intOrString, t.values)),
                                  data=list(map(intOrString, t.index)))
        t = None

        # Convert road lengths and AADT data to total fuel use each day on each segment of road
        fuelUseDict = calculate_fuel_use(
            inputLayer,
            inputIdField,
            totalAADTField=totalAADTField,
            roadTypeField=roadTypeField,
            vAADTFields=vAADTFields,
            completeInputs=self.completeInputs,
            modelParams=self.modelParams,
            age=vehDate,
            fuelCon=self.fc,
            roadTypeLookup=roadTypeLookup,
            completeInputAADTprovided=completeInputAADTprovided,
            modelledTypesAADTprovided=modelledTypesAADTprovided)

        fuelUseData = fuelUseDict['fuelUse']
        fuelUseNames = fuelUseDict['names']
        allFuelFields = list(fuelUseNames['petrol'].values())
        allFuelFields.extend(list(fuelUseNames['diesel'].values()))
        # Get road segment lengths inside each output polygon, along with attributes of each of these intersected segments
        intersectedLines = intersecting_amounts([], inputIndex, inputLayer,
                                                outputLayer, inputIdField,
                                                self.transport.templateIdField)

        # Add total fuel consumption fields to output layer into which fuel consumption will go]
        for newField in allFuelFields:
            outputLayer = addNewField(outputLayer, newField)
        # Find out where new fields reside
        newFieldIndices = [
            get_field_index(outputLayer, fn) for fn in fuelUseData.columns
        ]
        # Refer to everything in terms of field index instead
        fuelUseData.columns = newFieldIndices

        # intersecting_amounts gives us enough information (original segment length and intersected length)
        # to disaggregate fuel use into each output feature, and to calculate total fuel use in each output feature
        areas = self.transport.getAreas()
        outputLayer.startEditing()
        fuelConsumption = pd.DataFrame(
            index=list(intersectedLines.keys()),
            columns=newFieldIndices)  # Results container for each feature
        for outfeat_id in list(intersectedLines.keys()):
            fuelConsumption[:].loc[outfeat_id] = 0

            if len(intersectedLines[outfeat_id]) > 0:
                # If there are any areas intersected by this polygon
                # Total fuel consumption within this output area
                lengths = pd.DataFrame().from_dict(
                    intersectedLines[outfeat_id]).T

                proportionIntersected = lengths['amountIntersected'] / \
                    lengths['originalAmount']
                # Get total of each fuel/vehicle combination by summing across segments in output area
                fuelConsumption[:].loc[outfeat_id] = fuelUseData[:].loc[lengths.index]\
                    .multiply(proportionIntersected, axis=0)\
                    .sum(axis=0, skipna=True)
            # Update shapefile attributes one by one. Doing it in bulk via the dataprovider /should/ work too, but doesn't seem to
            # Convert to kg fuel per square metre of output area too
            [
                outputLayer.changeAttributeValue(
                    featureMapper[outfeat_id], fi,
                    float(fuelConsumption[fi][outfeat_id]) /
                    float(areas[outfeat_id])) for fi in newFieldIndices
            ]

        outputLayer.commitChanges()

        # This output layer is a set of polygons with associated fuel use and can be treated like any other
        # fuel consumption input shapefile
        confirmedOutput = self.transport.addInput(
            outputLayer,
            startTime,
            allFuelFields,
            self.transport.templateIdField,
            epsgCode=epsgCode)
        return confirmedOutput