示例#1
0
    def testGetGeometry(self):
        idx = QgsSpatialIndex()
        idx2 = QgsSpatialIndex(QgsSpatialIndex.FlagStoreFeatureGeometries)
        fid = 0
        for y in range(5):
            for x in range(10, 15):
                ft = QgsFeature()
                ft.setId(fid)
                ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))
                idx.insertFeature(ft)
                idx2.insertFeature(ft)
                fid += 1

        # not storing geometries, a keyerror should be raised
        with self.assertRaises(KeyError):
            idx.geometry(-100)
        with self.assertRaises(KeyError):
            idx.geometry(1)
        with self.assertRaises(KeyError):
            idx.geometry(2)
        with self.assertRaises(KeyError):
            idx.geometry(1000)

        self.assertEqual(idx2.geometry(1).asWkt(1), 'Point (11 0)')
        self.assertEqual(idx2.geometry(2).asWkt(1), 'Point (12 0)')
        with self.assertRaises(KeyError):
            idx2.geometry(-100)
        with self.assertRaises(KeyError):
            idx2.geometry(1000)
示例#2
0
    def poly2nb(self):
        lst = []

        index = QgsSpatialIndex()
        featsA = self.lyr.getFeatures()
        featsB = self.lyr.getFeatures()
        for ft in featsA:
            index.insertFeature(ft)

        featB = QgsFeature()
        prv = self.lyr.dataProvider()
        while featsB.nextFeature(featB):
            geomB = featB.constGeometry()
            idb = featB.id()
            idxs = index.intersects(geomB.boundingBox())
            sor = []
            for idx in idxs:
                rqst = QgsFeatureRequest().setFilterFid(idx)
                featA = prv.getFeatures(rqst).next()
                ida = featA.id()
                geomA = QgsGeometry(featA.geometry())
                if idb!=ida:
                    if geomB.touches(geomA)==True:
                        sor.append(ida)

            lst.append(sor)

        return lst
示例#3
0
    def compute(self, line1, line2, field1, field2, outPath, matType, nearest, progressBar):
        layer1 = ftools_utils.getVectorLayerByName(line1)
        layer2 = ftools_utils.getVectorLayerByName(line2)
        if layer1.id() == layer2.id():
            if nearest > 0:
                nearest = nearest + 1
        provider1 = layer1.dataProvider()
        provider2 = layer2.dataProvider()
        sindex = QgsSpatialIndex()
        inFeat = QgsFeature()
        fit2 = provider2.getFeatures()
        while fit2.nextFeature(inFeat):
            sindex.insertFeature(inFeat)
        if nearest < 1:
            nearest = layer2.featureCount()
        else:
            nearest = nearest
        index1 = provider1.fieldNameIndex(field1)
        index2 = provider2.fieldNameIndex(field2)
        distArea = QgsDistanceArea()
        #use srs of the first layer (users should ensure that they are both in the same projection)
        # sRs = provider1.crs()
        # distArea.setSourceSRS(sRs)

        f = open(unicode(outPath), "wb")
        writer = UnicodeWriter(f)
        if matType != "Standard":
            if matType == "Linear":
                writer.writerow(["InputID", "TargetID", "Distance"])
            else:
                writer.writerow(["InputID", "MEAN", "STDDEV", "MIN", "MAX"])
            self.linearMatrix(writer, provider1, provider2, index1, index2, nearest, distArea, matType, sindex, progressBar)
        else:
            self.regularMatrix(writer, provider1, provider2, index1, index2, nearest, distArea, sindex, progressBar)
        f.close()
示例#4
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.fromPointXY(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}
示例#5
0
    def testIndex(self):
        idx = QgsSpatialIndex()
        fid = 0
        for y in range(5, 15, 5):
            for x in range(5, 25, 5):
                ft = QgsFeature()
                ft.setFeatureId(fid)
                ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(x, y)))
                idx.insertFeature(ft)
                fid += 1

        # intersection test
        rect = QgsRectangle(7.0, 3.0, 17.0, 13.0)
        fids = idx.intersects(rect)
        myExpectedValue = 4
        myValue = len(fids)
        myMessage = 'Expected: %s Got: %s' % (myExpectedValue, myValue)
        self.assertEqual(myValue, myExpectedValue, myMessage)
        fids.sort()
        myMessage = ('Expected: %s\nGot: %s\n' %
                     ([1, 2, 5, 6], fids))
        assert fids == [1, 2, 5, 6], myMessage

        # nearest neighbor test
        fids = idx.nearestNeighbor(QgsPoint(8.75, 6.25), 3)
        myExpectedValue = 0
        myValue = len(fids)
        myMessage = 'Expected: %s Got: %s' % (myExpectedValue, myValue)

        fids.sort()
        myMessage = ('Expected: %s\nGot: %s\n' %
                     ([0, 1, 5], fids))
        assert fids == [0, 1, 5], myMessage
示例#6
0
def createIndex(provider):
    feat = QgsFeature()
    index = QgsSpatialIndex()
    fit = provider.getFeatures()
    while fit.nextFeature(feat):
        index.insertFeature(feat)
    return index
示例#7
0
class LayerIndex:
    
    def __init__(self, layer):
        self.__layer = layer        
        self.__index = QgsSpatialIndex()
        feats = vector.features(layer)
        for ft in feats:
            self.__index.insertFeature(ft)
        
    def contains(self, point):
        """Return true if the point intersects the layer"""
        intersects = self.__index.intersects(point.boundingBox())
        for i in intersects:
            request = QgsFeatureRequest().setFilterFid(i)
            feat = self.__layer.getFeatures(request).next()
            tmpGeom = QgsGeometry(feat.geometry())
            if point.intersects(tmpGeom):
                return True
        return False
    
    def countIntersection(self,bufferGeom,nb):
        """Return true if the buffer intersects enough entities"""
        count = 0
        intersects = self.__index.intersects(bufferGeom.boundingBox())
        for i in intersects:
            request = QgsFeatureRequest().setFilterFid(i)
            feat = self.__layer.getFeatures(request).next()
            tmpGeom = QgsGeometry(feat.geometry())
            if bufferGeom.intersects(tmpGeom):
                count += 1
                if count >= nb:
                    return True
        return False
def get_spatial_index(data_provider):
    """Create spatial index from a data provider."""
    qgs_feature = QgsFeature()
    index = QgsSpatialIndex()
    qgs_features = data_provider.getFeatures()
    while qgs_features.nextFeature(qgs_feature):
        index.insertFeature(qgs_feature)
    return index
示例#9
0
文件: vector.py 项目: a11656358/QGIS
def spatialindex(layer):
    """Creates a spatial index for the passed vector layer.
    """
    idx = QgsSpatialIndex()
    feats = features(layer)
    for ft in feats:
        idx.insertFeature(ft)
    return idx
示例#10
0
 def buildReferenceIndex(self, segments):
     refDict = {}
     index = QgsSpatialIndex()
     for i, segment in enumerate(segments):
         refDict[i] = segment
         feature = QgsFeature(i)
         feature.setGeometry(segment)
         index.insertFeature(feature)
     return refDict, index
示例#11
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.VECTOR))
        pointCount = int(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))

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

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

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

        index = QgsSpatialIndex()
        points = dict()

        request = QgsFeatureRequest()

        random.seed()

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

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

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

        del writer
示例#12
0
    def processAlgorithm(self, feedback):
        pointCount = int(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))
        extent = str(self.getParameterValue(self.EXTENT)).split(',')

        crsId = self.getParameterValue(self.CRS)
        crs = QgsCoordinateReferenceSystem()
        crs.createFromUserInput(crsId)

        xMin = float(extent[0])
        xMax = float(extent[1])
        yMin = float(extent[2])
        yMax = float(extent[3])
        extent = QgsGeometry().fromRect(
            QgsRectangle(xMin, yMin, xMax, yMax))

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

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

        index = QgsSpatialIndex()
        points = dict()

        random.seed()

        while nIterations < maxIterations and nPoints < pointCount:
            rx = xMin + (xMax - xMin) * random.random()
            ry = yMin + (yMax - yMin) * random.random()

            pnt = QgsPoint(rx, ry)
            geom = QgsGeometry.fromPoint(pnt)
            if geom.within(extent) 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.'))

        del writer
示例#13
0
    def processAlgorithm(self, parameters, context, feedback):
        pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context)
        minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
        crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
        bbox = self.parameterAsExtent(parameters, self.EXTENT, context, crs)

        extent = QgsGeometry().fromRect(bbox)

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

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

        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.fromPointXY(p)
            if geom.within(extent) 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.'))

        return {self.OUTPUT: dest_id}
    def processAlgorithm(self, progress):
        pointCount = int(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))
        extent = unicode(self.getParameterValue(self.EXTENT)).split(',')

        xMin = float(extent[0])
        xMax = float(extent[1])
        yMin = float(extent[2])
        yMax = float(extent[3])
        extent = QgsGeometry().fromRect(
            QgsRectangle(xMin, yMin, xMax, yMax))

        fields = QgsFields()
        fields.append(QgsField('id', QVariant.Int, '', 10, 0))
        mapCRS = iface.mapCanvas().mapSettings().destinationCrs()
        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
            fields, QGis.WKBPoint, mapCRS)

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

        index = QgsSpatialIndex()
        points = dict()

        random.seed()

        while nIterations < maxIterations and nPoints < pointCount:
            rx = xMin + (xMax - xMin) * random.random()
            ry = yMin + (yMax - yMin) * random.random()

            pnt = QgsPoint(rx, ry)
            geom = QgsGeometry.fromPoint(pnt)
            if geom.within(extent) 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
                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
示例#15
0
def createIndex( provider ):
  '''
  return Spatial Index of line layer features
  @param provider: QgsDataProvider
  '''
  feat = QgsFeature()
  index = QgsSpatialIndex()
  provider.rewind()
  provider.select()
  while provider.nextFeature( feat ):
    index.insertFeature( feat )
  return index
示例#16
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.VECTOR), context)
        pointCount = int(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))

        bbox = layer.extent()
        idxLayer = QgsProcessingUtils.createSpatialIndex(layer, context)

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

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

        index = QgsSpatialIndex()
        points = dict()

        random.seed()

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

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

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

        del writer
示例#17
0
class TriangleMesh:

  # 0 - 3
  # | / |
  # 1 - 2

  def __init__(self, xmin, ymin, xmax, ymax, x_segments, y_segments):
    self.flen = 0
    self.quadrangles = []
    self.spatial_index = QgsSpatialIndex()

    xres = (xmax - xmin) / x_segments
    yres = (ymax - ymin) / y_segments
    for y in range(y_segments):
      for x in range(x_segments):
        pt0 = QgsPoint(xmin + x * xres, ymax - y * yres)
        pt1 = QgsPoint(xmin + x * xres, ymax - (y + 1) * yres)
        pt2 = QgsPoint(xmin + (x + 1) * xres, ymax - (y + 1) * yres)
        pt3 = QgsPoint(xmin + (x + 1) * xres, ymax - y * yres)
        self._addQuadrangle(pt0, pt1, pt2, pt3)

  def _addQuadrangle(self, pt0, pt1, pt2, pt3):
    f = QgsFeature(self.flen)
    f.setGeometry(QgsGeometry.fromPolygon([[pt0, pt1, pt2, pt3, pt0]]))
    self.quadrangles.append(f)
    self.spatial_index.insertFeature(f)
    self.flen += 1

  def intersects(self, geom):
    for fid in self.spatial_index.intersects(geom.boundingBox()):
      quad = self.quadrangles[fid].geometry()
      if quad.intersects(geom):
        yield quad

  def splitPolygons(self, geom):
    for quad in self.intersects(geom):
      pts = quad.asPolygon()[0]
      tris = [[[pts[0], pts[1], pts[3], pts[0]]], [[pts[3], pts[1], pts[2], pts[3]]]]
      if geom.contains(quad):
        yield tris[0]
        yield tris[1]
      else:
        for i, tri in enumerate(map(QgsGeometry.fromPolygon, tris)):
          if geom.contains(tri):
            yield tris[i]
          elif geom.intersects(tri):
            poly = geom.intersection(tri)
            if poly.isMultipart():
              for sp in poly.asMultiPolygon():
                yield sp
            else:
              yield poly.asPolygon()
def get_spatial_index(data_provider):
    """Create spatial index from a data provider.

    :param data_provider: QGIS data provider name .e.g.'ogr'.
    :type data_provider: str
    """
    qgs_feature = QgsFeature()
    index = QgsSpatialIndex()
    # noinspection PyUnresolvedReferences
    qgs_features = data_provider.getFeatures()
    while qgs_features.nextFeature(qgs_feature):
        index.insertFeature(qgs_feature)
    return index
示例#19
0
    def compute_graph(features, feedback, create_id_graph=False, min_distance=0):
        """ compute topology from a layer/field """
        s = Graph(sort_graph=False)
        id_graph = None
        if create_id_graph:
            id_graph = Graph(sort_graph=True)

        # skip features without geometry
        features_with_geometry = {f_id: f for (f_id, f) in features.items() if f.hasGeometry()}

        total = 70.0 / len(features_with_geometry) if features_with_geometry else 1
        index = QgsSpatialIndex()

        i = 0
        for feature_id, f in features_with_geometry.items():
            if feedback.isCanceled():
                break

            g = f.geometry()
            if min_distance > 0:
                g = g.buffer(min_distance, 5)

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

            feature_bounds = g.boundingBox()
            # grow bounds a little so we get touching features
            feature_bounds.grow(feature_bounds.width() * 0.01)
            intersections = index.intersects(feature_bounds)
            for l2 in intersections:
                f2 = features_with_geometry[l2]
                if engine.intersects(f2.geometry().constGet()):
                    s.add_edge(f.id(), f2.id())
                    s.add_edge(f2.id(), f.id())
                    if id_graph:
                        id_graph.add_edge(f.id(), f2.id())

            index.insertFeature(f)
            i += 1
            feedback.setProgress(int(i * total))

        for feature_id, f in features_with_geometry.items():
            if feedback.isCanceled():
                break

            if feature_id not in s.node_edge:
                s.add_edge(feature_id, None)

        return s, id_graph
示例#20
0
 def create_spatial_index(self, layer):
     spatial_index = QgsSpatialIndex()
     
     # features dictionary
     centroid_features = {}
     
     features = layer.getFeatures()
     for feature in features:
         # convert to point feature
         point_feature = QgsFeature(layer.fields())
         point_feature.setId(feature.id())
         point_feature.setAttributes(feature.attributes())
         point_feature.setGeometry(feature.geometry().centroid())
         centroid_features[point_feature.id()] = point_feature
         
         spatial_index.insertFeature(point_feature)
     
     return (spatial_index, centroid_features)
示例#21
0
文件: tools.py 项目: inasafe/inasafe
def create_spatial_index(layer):
    """Helper function to create the spatial index on a vector layer.

    This function is mainly used to see the processing time with the decorator.

    :param layer: The vector layer.
    :type layer: QgsVectorLayer

    :return: The index.
    :rtype: QgsSpatialIndex
    """
    request = QgsFeatureRequest().setSubsetOfAttributes([])
    try:
        spatial_index = QgsSpatialIndex(layer.getFeatures(request))
    except BaseException:
        # Spatial index is creating an unknown exception.
        # https://github.com/inasafe/inasafe/issues/4304
        # or https://gitter.im/inasafe/inasafe?at=5a2903d487680e6230e0359a
        LOGGER.warning(
            'An Exception has been raised from the spatial index creation. '
            'We will clean your layer and try again.')
        new_layer = clean_layer(layer)
        try:
            spatial_index = QgsSpatialIndex(new_layer.getFeatures())
        except BaseException:
            # We got another exception.
            # We try now to insert feature by feature.
            # It's slower than the using the feature iterator.
            spatial_index = QgsSpatialIndex()
            for feature in new_layer.getFeatures(request):
                try:
                    spatial_index.insertFeature(feature)
                except BaseException:
                    LOGGER.critical(
                        'A feature has been removed from the spatial index.')

            # # We tried one time to clean the layer, we can't do more.
            # LOGGER.critical(
            #     'An Exception has been raised from the spatial index '
            #     'creation. Unfortunately, we already try to clean your '
            #     'layer. We will stop here the process.')
            # raise SpatialIndexCreationError
    return spatial_index
示例#22
0
class LayerIndex(object):
    """Check an intersection between a QgsGeometry and a QgsVectorLayer."""

    def __init__(self, layer):
        self.__layer = layer

        if QGis.QGIS_VERSION_INT >= 20700:
            self.__index = QgsSpatialIndex(layer.getFeatures())
        else:
            self.__index = QgsSpatialIndex()
            for ft in layer.getFeatures():
                self.__index.insertFeature(ft)

    def contains(self, point):
        """Return true if the point intersects the layer."""
        intersects = self.__index.intersects(point.boundingBox())
        for i in intersects:
            request = QgsFeatureRequest().setFilterFid(i)
            feat = self.__layer.getFeatures(request).next()
            if point.intersects(QgsGeometry(feat.geometry())):
                return True
        return False

    def count_intersection(self, buffer_geom, nb):
        """Return true if the buffer intersects enough entities."""
        count = 0
        intersects = self.__index.intersects(buffer_geom.boundingBox())
        for i in intersects:
            request = QgsFeatureRequest().setFilterFid(i)
            feat = self.__layer.getFeatures(request).next()

            if buffer_geom.intersects(QgsGeometry(feat.geometry())):
                count += 1
                if count >= nb:
                    return True
        return False
示例#23
0
class breakTool(QObject):

    finished = pyqtSignal(object)
    error = pyqtSignal(Exception, basestring)
    progress = pyqtSignal(float)
    warning = pyqtSignal(str)
    killed = pyqtSignal(bool)

    def __init__(self,layer, tolerance, uid, errors, unlinks):
        QObject.__init__(self)

        self.layer = layer
        self.feat_count = self.layer.featureCount()
        self.tolerance = tolerance
        self.uid = uid

        self.errors = errors
        self.errors_features = {}
        self.unlinks = unlinks
        self.unlinked_features = []
        self.unlinks_count = 0
        self.ml_keys = {}
        self.br_keys = {}

        self.features = []
        self.attributes = {}
        self.geometries = {}
        self.geometries_wkt = {}
        self.geometries_vertices = {}
        # create spatial index object
        self.spIndex = QgsSpatialIndex()
        self.layer_fields = [QgsField(i.name(), i.type()) for i in self.layer.dataProvider().fields()]

    def add_edges(self):

        new_key_count = 0
        f_count = 1

        for f in self.layer.getFeatures():

            self.progress.emit(3 * f_count / self.feat_count)
            f_count += 1

            if self.killed is True:
                break

            geom_type = f.geometry().wkbType()

            if geom_type not in [5,2,1] and f.geometry().geometry().is3D():
                f.geometry().geometry().dropZValue()
                geom_type = f.geometry().wkbType()

            if geom_type == 5:
                if self.errors:
                    self.errors_features[f.id()] = ('multipart', f.geometry().exportToWkt())
                for multipart in f.geometry().asGeometryCollection():
                    new_key_count += 1
                    attr = f.attributes()
                    new_feat = QgsFeature()
                    new_feat.setAttributes(attr)
                    new_feat.setFeatureId(new_key_count)
                    if self.tolerance:
                        snapped_wkt = make_snapped_wkt(multipart.exportToWkt(), self.tolerance)
                    else:
                        snapped_wkt = multipart.exportToWkt()
                    snapped_geom = QgsGeometry.fromWkt(snapped_wkt)
                    new_feat.setGeometry(snapped_geom)
                    self.features.append(new_feat)
                    self.attributes[new_key_count] = attr
                    self.geometries[new_key_count] = new_feat.geometryAndOwnership()
                    self.geometries_wkt[new_key_count] = snapped_wkt
                    self.geometries_vertices[new_key_count] = [vertex for vertex in vertices_from_wkt_2(snapped_wkt)]
                    # insert features to index
                    self.spIndex.insertFeature(new_feat)
                    self.ml_keys[new_key_count] = f.id()
            elif geom_type == 1:
                if self.errors:
                    self.errors_features[f.id()] = ('point', QgsGeometry().exportToWkt())
            elif not f.geometry().isGeosValid():
                if self.errors:
                    self.errors_features[f.id()] = ('invalid', QgsGeometry().exportToWkt())
            elif geom_type == 2:
                attr = f.attributes()
                if self.tolerance:
                    snapped_wkt = make_snapped_wkt(f.geometry().exportToWkt(), self.tolerance)
                else:
                    snapped_wkt = f.geometry().exportToWkt()
                snapped_geom = QgsGeometry.fromWkt(snapped_wkt)
                f.setGeometry(snapped_geom)
                new_key_count += 1
                f.setFeatureId(new_key_count)
                self.features.append(f)
                self.attributes[f.id()] = attr
                self.geometries[f.id()] = f.geometryAndOwnership()
                self.geometries_wkt[f.id()] = snapped_wkt
                self.geometries_vertices[f.id()] = [vertex for vertex in vertices_from_wkt_2(snapped_wkt)]
                # insert features to index
                self.spIndex.insertFeature(f)
                self.ml_keys[new_key_count] = f.id()

    def break_features(self):

        broken_features = []
        f_count = 1

        for fid in self.geometries.keys():

            if self.killed is True:
                break

            f_geom = self.geometries[fid]
            f_attrs = self.attributes[fid]

            # intersecting lines
            gids = self.spIndex.intersects(f_geom.boundingBox())

            self.progress.emit((45 * f_count / self.feat_count) + 5)
            f_count += 1

            f_errors, vertices = self.find_breakages(fid, gids)

            if self.errors and f_errors:
                original_id = self.ml_keys[fid]
                try:
                    updated_errors = self.errors_features[original_id][0] + f_errors
                    self.errors_features[original_id] = (updated_errors, self.errors_features[original_id][1])
                except KeyError:
                    self.errors_features[original_id] = (f_errors, self.geometries[fid].exportToWkt())

            if f_errors is None:
                vertices = [0, len(f_geom.asPolyline()) - 1 ]

            if f_errors in ['breakage, overlap', 'breakage', 'overlap', None]:
                for ind, index in enumerate(vertices):
                    if ind != len(vertices) - 1:
                        points = [self.geometries_vertices[fid][i] for i in range(index, vertices[ind + 1] + 1)]
                        p = ''
                        for point in points:
                            p += point[0] + ' ' + point[1] + ', '
                        wkt = 'LINESTRING(' + p[:-2] + ')'
                        self.feat_count += 1
                        new_fid = self.feat_count
                        new_feat = [new_fid, f_attrs, wkt]
                        broken_features.append(new_feat)
                        self.br_keys[new_fid] = fid

        return broken_features

    def kill(self):
        self.br_killed = True

    def find_breakages(self, fid, gids):

        f_geom = self.geometries[fid]

        # errors checks
        must_break = False
        is_closed = False
        if f_geom.asPolyline()[0] == f_geom.asPolyline()[-1]:
            is_closed = True
        is_orphan = True
        is_duplicate = False
        has_overlaps = False

        # get breaking points
        breakages = []

        # is self intersecting
        is_self_intersersecting = False
        for i in f_geom.asPolyline():
            if f_geom.asPolyline().count(i) > 1:
                point = QgsGeometry().fromPoint(QgsPoint(i[0], i[1]))
                breakages.append(point)
                is_self_intersersecting = True
                must_break = True

        for gid in gids:

            g_geom = self.geometries[gid]

            if gid < fid:
                # duplicate geometry
                if f_geom.isGeosEqual(g_geom):
                    is_duplicate = True

                if self.unlinks:
                    if f_geom.crosses(g_geom):
                        crossing_point = f_geom.intersection(g_geom)
                        if crossing_point.wkbType() == 1:
                            self.unlinks_count += 1
                            unlinks_attrs = [[self.unlinks_count], [gid], [fid], [crossing_point.asPoint()[0]],
                                             [crossing_point.asPoint()[1]]]
                            self.unlinked_features.append([self.unlinks_count, unlinks_attrs, crossing_point.exportToWkt()])
                        elif crossing_point.wkbType() == 4:
                            for cr_point in crossing_point.asGeometryCollection():
                                self.unlinks_count += 1
                                unlinks_attrs = [[self.unlinks_count], [gid], [fid], [cr_point.asPoint()[0]],
                                                 [cr_point.asPoint()[1]]]
                                self.unlinked_features.append([self.unlinks_count, unlinks_attrs, cr_point.exportToWkt()])

            if is_duplicate is False:
                intersection = f_geom.intersection(g_geom)
                # intersecting geometries at point
                if intersection.wkbType() == 1 and point_is_vertex(intersection, f_geom):
                    breakages.append(intersection)
                    is_orphan = False
                    must_break = True

                # intersecting geometries at multiple points
                elif intersection.wkbType() == 4:
                    for point in intersection.asGeometryCollection():
                        if point_is_vertex(point, f_geom):
                            breakages.append(point)
                            is_orphan = False
                            must_break = True

                # overalpping geometries
                elif intersection.wkbType() == 2 and intersection.length() != f_geom.length():
                    point1 = QgsGeometry.fromPoint(QgsPoint(intersection.asPolyline()[0]))
                    point2 = QgsGeometry.fromPoint(QgsPoint(intersection.asPolyline()[-1]))
                    if point_is_vertex(point1, f_geom):
                        breakages.append(point1)
                        is_orphan = False
                        must_break = True
                    if point_is_vertex(point2, f_geom):
                        breakages.append(point2)
                        is_orphan = False
                        must_break = True

                # overalpping multi-geometries
                # every feature overlaps with itself as a multilinestring
                elif intersection.wkbType() == 5 and intersection.length() != f_geom.length():
                    point1 = QgsGeometry.fromPoint(QgsPoint(intersection.asGeometryCollection()[0].asPolyline()[0]))
                    point2 = QgsGeometry.fromPoint(QgsPoint(intersection.asGeometryCollection()[-1].asPolyline()[-1]))
                    if point_is_vertex(point1, f_geom):
                        is_orphan = False
                        has_overlaps = True
                        breakages.append(point1)
                    if point_is_vertex(point2, f_geom):
                        is_orphan = False
                        has_overlaps = True
                        breakages.append(point2)

        if is_duplicate is True:
            return 'duplicate', []
        else:
            # add first and last vertex
            vertices = set([vertex for vertex in find_vertex_index(breakages, f_geom)])
            vertices = list(vertices) + [0] + [len(f_geom.asPolyline()) - 1]
            vertices = list(set(vertices))
            vertices.sort()

            if is_orphan:
                if is_closed is True:
                    return 'closed polyline', []
                else:
                    return 'orphan', []

            elif is_self_intersersecting:
                if has_overlaps:
                    return 'breakage, overlap', vertices
                else:
                    return 'breakage', vertices

            elif has_overlaps or must_break:
                if has_overlaps is True and must_break is True:
                    return 'breakage, overlap', vertices
                elif has_overlaps is True and must_break is False:
                    return 'overlap', vertices
                elif has_overlaps is False and must_break is True:
                    if len(vertices) > 2:
                        return 'breakage', vertices
                    else:
                        return None, []
            else:
                return None, []

    def updateErrors(self, errors_dict):

        for k, v in errors_dict.items():

            try:
                original_id = self.br_keys[k]
                try:
                    original_id = self.ml_keys[k]
                except KeyError:
                    pass
            except KeyError:
                original_id = None

            if original_id:
                try:
                    updated_errors = self.errors_features[original_id][0]
                    if ', continuous line' not in self.errors_features[original_id][0]:
                        updated_errors += ', continuous line'
                    self.errors_features[original_id] = (updated_errors, self.errors_features[original_id][1])
                except KeyError:
                    self.errors_features[original_id] = ('continuous line', self.geometries[original_id].exportToWkt())
示例#24
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}
示例#25
0
 def SpatialIndex(self, mem_layer):
     # Create Spatial Index
     index = QgsSpatialIndex()
     for f in mem_layer.getFeatures():
         index.insertFeature(f)
     return index
示例#26
0
def _raster_to_vector_cells(raster, minimum_threshold, maximum_threshold,
                            output_crs):
    """Generate vectors features (rectangles) for raster cells.

     Cells which are not within threshold (threshold_min < V < threshold_max)
     will be excluded. The provided CRS will be used to determine the
     CRS of the output vector cells layer.

    :param minimum_threshold: The minimum threshold for pixels to be included.
    :type minimum_threshold: float

    :param maximum_threshold: The maximum threshold for pixels to be included.
    :type maximum_threshold: float

    :param raster: A raster layer that will be vectorised.
    :type raster: QgsRasterLayer

    :param output_crs: The CRS to use for the output vector cells layer.
    :type output_crs: QgsCoordinateReferenceSystem

    :returns: A two-tuple containing a spatial index and a map (dict) where
        map keys are feature id's and the value is the feature for that id.
    :rtype: (QgsSpatialIndex, dict)
    """

    # get raster data
    provider = raster.dataProvider()
    extent = provider.extent()
    raster_cols = provider.xSize()
    raster_rows = provider.ySize()
    block = provider.block(1, extent, raster_cols, raster_rows)
    raster_xmin = extent.xMinimum()
    raster_ymax = extent.yMaximum()
    cell_width = extent.width() / raster_cols
    cell_height = extent.height() / raster_rows

    uri = "Polygon?crs=" + output_crs.authid()
    vl = QgsVectorLayer(uri, "cells", "memory")
    features = []

    # prepare coordinate transform to reprojection
    ct = QgsCoordinateTransform(raster.crs(), output_crs)

    for y in xrange(raster_rows):
        for x in xrange(raster_cols):
            # only use cells that are within the specified threshold
            value = block.value(y, x)
            if value < minimum_threshold or value > maximum_threshold:
                continue

            # construct rectangular polygon feature for the cell
            x0 = raster_xmin + (x * cell_width)
            x1 = raster_xmin + ((x + 1) * cell_width)
            y0 = raster_ymax - (y * cell_height)
            y1 = raster_ymax - ((y + 1) * cell_height)
            outer_ring = [
                QgsPoint(x0, y0),
                QgsPoint(x1, y0),
                QgsPoint(x1, y1),
                QgsPoint(x0, y1),
                QgsPoint(x0, y0)
            ]
            # noinspection PyCallByClass
            geometry = QgsGeometry.fromPolygon([outer_ring])
            geometry.transform(ct)
            f = QgsFeature()
            f.setGeometry(geometry)
            features.append(f)

    _, features = vl.dataProvider().addFeatures(features)

    # construct a temporary map for fast access to features by their IDs
    # (we will be getting feature IDs from spatial index)
    flood_cells_map = {}
    for f in features:
        flood_cells_map[f.id()] = f

    # build a spatial index so we can quickly identify
    # flood cells overlapping roads
    if QGis.QGIS_VERSION_INT >= 20800:
        # woohoo we can use bulk insert (much faster)
        index = QgsSpatialIndex(vl.getFeatures())
    else:
        index = QgsSpatialIndex()
        for f in vl.getFeatures():
            index.insertFeature(f)

    return index, flood_cells_map
示例#27
0
    def enclaveRemover(self):
        field_id = self.activeLayer.fieldNameIndex(self.distfield)
        self.activeLayer.startEditing()
        # Create a dictionary of all features
        feature_dict = {f.id(): f for f in self.activeLayer.getFeatures()}

        QgsMessageLog.logMessage("Building spatial index...")
        # Build a spatial index
        index = QgsSpatialIndex()
        for f in feature_dict.values():
            index.insertFeature(f)

        QgsMessageLog.logMessage("Finding neighbors...")
        # Loop through all features and find features that touch each feature
        for f in feature_dict.values():
            geom = f.geometry()
            # Find all features that intersect the bounding box of the current feature.
            # We use spatial index to find the features intersecting the bounding box
            # of the current feature. This will narrow down the features that we need
            # to check neighboring features.
            intersecting_ids = index.intersects(geom.boundingBox())
            # Initalize neighbors list and sum
            neighbors = []
            neighbors_district = -1
            finished = 0
            if f[self.distfield] == 0:
                QgsMessageLog.logMessage("feature " + str(f.id()) +
                                         " with null distfield found!")
                while neighbors_district <> -2 and finished == 0:
                    finished = 0
                    for intersecting_id in intersecting_ids:
                        # Look up the feature from the dictionary
                        intersecting_f = feature_dict[intersecting_id]
                        QgsMessageLog.logMessage("Neighbor found!")
                        # For our purpose we consider a feature as 'neighbor' if it touches or
                        # intersects a feature. We use the 'disjoint' predicate to satisfy
                        # these conditions. So if a feature is not disjoint, it is a neighbor.
                        if (f != intersecting_f and
                                not intersecting_f.geometry().disjoint(geom)):
                            if intersecting_f[self.distfield] > 0:
                                QgsMessageLog.logMessage(
                                    "Neighbor found with > 0!")
                                if neighbors_district == -1:
                                    neighbors_district = intersecting_f[
                                        self.distfield]
                                    QgsMessageLog.logMessage(
                                        "neighbors_district set to " +
                                        str(neighbors_district))
                                elif neighbors_district != intersecting_f[
                                        self.distfield]:
                                    neighbors_district = -2
                                    QgsMessageLog.logMessage(
                                        "neighbors_district set to " +
                                        str(neighbors_district) + ", " +
                                        str(intersecting_f[self.distfield]) +
                                        " not matching")
                    if neighbors_district > 0:
                        QgsMessageLog.logMessage(
                            str(f.id()) + " updating district to " +
                            str(neighbors_district))
                        self.activeLayer.changeAttributeValue(
                            f.id(), field_id, neighbors_district)
                        # Update the layer with new attribute values.
                    finished = 1

        self.activeLayer.commitChanges()
示例#28
0
class LeastCommonDenominatorProcedure(WorkerThread):
    def __init__(self, parentThread, flayer, tlayer, ffield, tfield):
        WorkerThread.__init__(self, parentThread)
        self.flayer = flayer
        self.tlayer = tlayer
        self.ffield = ffield
        self.tfield = tfield
        self.error = None
        self.result = None
        self.output_type = None
        self.transform = None
        self.poly_types = poly_types + multi_poly
        self.line_types = line_types + multi_line
        self.point_types = point_types + multi_point

    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)

        EPSG1 = QgsCoordinateReferenceSystem(
            int(self.from_layer.crs().authid().split(":")[1]))
        EPSG2 = QgsCoordinateReferenceSystem(
            int(self.to_layer.crs().authid().split(":")[1]))
        if EPSG1 != EPSG2:
            self.transform = QgsCoordinateTransform(EPSG1, EPSG2,
                                                    QgsProject.instance())

        # FIELDS INDICES
        idx = self.from_layer.dataProvider().fieldNameIndex(ffield)
        fid = self.to_layer.dataProvider().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.ProgressMaxValue.emit(self.to_layer.dataProvider().featureCount())
        self.ProgressText.emit("Building Spatial Index")
        self.ProgressValue.emit(0)
        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.ProgressValue.emit(i)

        self.ProgressText.emit("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.ProgressMaxValue.emit(
            self.from_layer.dataProvider().featureCount())
        self.ProgressText.emit("Running Analysis")
        self.ProgressValue.emit(0)
        part_id = 1
        features = []
        areas = {}
        for fc, feat in enumerate(self.from_layer.getFeatures()):
            geom = feat.geometry()
            if geom is not None:
                if self.transform is not None:
                    geom = 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
                        areas[f] = statt
                        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.ProgressValue.emit(fc)
            self.ProgressText.emit(
                "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.items():
            geom = feature.geometry()
            if geom.area() > 0:
                feature = QgsFeature()
                geo, stati = self.find_geometry(geom)
                feature.setGeometry(geo)
                perct = stati / areas[f]
                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.ProgressValue.emit(self.from_layer.dataProvider().featureCount())
        self.finished_threaded_procedure.emit("procedure")

    def find_geometry(self, g):
        if self.output_type == "Poly":
            stat = g.area()
            if g.isMultipart():
                geometry = QgsGeometry.fromMultiPolygonXY(g.asMultiPolygon())
            else:
                geometry = QgsGeometry.fromPolygonXY(g.asPolygon())
        elif self.output_type == "Line":
            stat = g.length()
            if g.isMultipart():
                geometry = QgsGeometry.fromMultiPolylineXY(g.asMultiPolyLine())
            else:
                geometry = QgsGeometry.fromPolyline(g.asPoly())
        else:
            stat = 1
            if g.isMultipart():
                geometry = QgsGeometry.fromMultiPointXY(g.asMultiPoint())
            else:
                geometry = QgsGeometry.fromPointXY(g.asPoint())
        return geometry, stat
    def processAlgorithm(self, parameters, context, feedback):
        source_poly = self.parameterAsSource(parameters, self.INPUT_POLYGONS,
                                             context)
        source_add = self.parameterAsVectorLayer(parameters,
                                                 self.INPUT_ADDITIONAL,
                                                 context)
        val_field = self.parameterAsString(parameters, self.VALUE_FIELD,
                                           context)
        feature_value = self.parameterAsEnum(parameters, self.M_VAL, context)
        if feature_value == 0:
            m_val = max
        elif feature_value == 1:
            m_val = min

        max_ids = []
        att_col_idx = source_add.fields().indexFromName(val_field)
        fcount = source_poly.featureCount()
        polygons = source_poly.getFeatures()
        points = source_add.getFeatures()
        index = QgsSpatialIndex(
        )  # this spatial index contains all the features of the point layer
        for point in points:
            index.insertFeature(point)

        for current, polygon in enumerate(polygons):
            if feedback.isCanceled():
                break
            f = int(current + 1)
            pcnt = int(f / fcount * 100 / 1)
            feedback.setProgress(pcnt)
            ids = []
            vals = []
            poly_geom = polygon.geometry()
            engine = QgsGeometry.createGeometryEngine(poly_geom.constGet())
            engine.prepareGeometry()
            idx_ids = index.intersects(poly_geom.boundingBox())
            for f in source_add.getFeatures(QgsFeatureRequest(idx_ids)):
                geom = f.geometry()
                if engine.contains(geom.constGet()):
                    ids.append(f.id())
                    vals.append(f.attributes()[att_col_idx])
            #Note that the three lines below are all in the polygon feature loop so they are executed once for each polygon feature
            d = dict(
                zip(ids, vals)
            )  #creates dictionaries with id as key and elevation as value
            if d:
                n_max = m_val(
                    d.values()
                )  #m_val is either max or min depending on combo box selection
                max_ids.append([
                    a for a, b in d.items() if b == n_max
                ])  #gets ids from each dictionary as keys with highest value
        all_max_min_ids = [item for sublist in max_ids for item in sublist
                           ]  # creates the flat list from list of lists

        method = self.parameterAsEnum(parameters, self.METHOD, context)
        if method == 0:
            behaviour = QgsVectorLayer.SetSelection
        elif method == 1:
            behaviour = QgsVectorLayer.AddToSelection
        elif method == 2:
            behaviour = QgsVectorLayer.RemoveFromSelection
        elif method == 3:
            behaviour = QgsVectorLayer.IntersectSelection

        source_add.selectByIds(all_max_min_ids, behaviour)

        return {self.OUTPUT: parameters[self.M_VAL]}
    def processAlgorithm(self, progress):
        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
                    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.'))

            progress.setPercentage(0)

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

        self.provenance.append_step(
            'Calculating Step',
            'Impact function is calculating the impact.')

        # 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 buildings from E and extent
        buildings_are_points = is_point_layer(self.exposure.layer)
        if buildings_are_points:
            building_layer = QgsVectorLayer(
                'Point?crs=' + srs, 'impact_buildings', 'memory')
        else:
            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(
            self.requested_extent_crs, self.hazard.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)

        # Filter out just those EXPOSURE features in the analysis extents
        transform = QgsCoordinateTransform(
            self.requested_extent_crs, self.exposure.layer.crs())
        projected_extent = transform.transformBoundingBox(requested_extent)
        request = QgsFeatureRequest()
        request.setFilterRect(projected_extent)

        # We will use this transform to project each exposure feature into
        # the CRS of the Hazard.
        transform = QgsCoordinateTransform(
            self.exposure.crs(), self.hazard.crs())
        features = []
        for feature in self.exposure.layer.getFeatures(request):
            # Make a deep copy as the geometry is passed by reference
            # If we don't do this, subsequent operations will affect the
            # original feature geometry as well as the copy TS
            building_geom = QgsGeometry(feature.geometry())
            # Project the building geometry to hazard CRS
            building_bounds = transform.transform(building_geom.boundingBox())
            affected = False
            # get tentative list of intersecting hazard features
            # only based on intersection of bounding boxes
            ids = hazard_index.intersects(building_bounds)
            for fid in ids:
                # run (slow) exact intersection test
                building_geom.transform(transform)
                if hazard_geometries[fid].intersects(building_geom):
                    affected = True
                    break
            new_feature = QgsFeature()
            # We write out the original feature geom, not the projected one
            new_feature.setGeometry(feature.geometry())
            new_feature.setAttributes(feature.attributes())
            new_feature[target_field_index] = 1 if affected else 0
            features.append(new_feature)

            # 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
        # Building threshold #2468
        postprocessors = self.parameters['postprocessors']
        building_postprocessors = postprocessors['BuildingType'][0]
        self.building_report_threshold = building_postprocessors.value[0].value
        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.'))

        extra_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
        }

        self.set_if_provenance()

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        building_layer = Vector(
            data=building_layer,
            name=tr('Flooded buildings'),
            keywords=impact_layer_keywords,
            style_info=style_info)
        self._impact = building_layer
        return building_layer
示例#32
0
class sGraph(QObject):

    finished = pyqtSignal(object)
    error = pyqtSignal(Exception, basestring)
    progress = pyqtSignal(float)
    warning = pyqtSignal(str)

    def __init__(self, edges, source_col='default', target_col='default'):
        QObject.__init__(self)
        self.edges = edges
        self.edge_flds = [i.name() for i in self.edges[0].fields()]
        self.edge_qflds = []
        for field in self.edges[0].fields():
            self.edge_qflds.append(QgsField(field.name(), field.type()))
        self.n_edges = len(self.edges)
        self.source_col = source_col
        self.target_col = target_col

        self.topology = {}
        self.adj_lines = {}
        self.dual_edges = {}
        # TODO: do not duplicate key if it is already in attributes e.g. 'identifier'

        self.nodes = []
        self.edge_attrs = {}
        self.edge_geoms = {}
        self.node_attrs = {}

        self.superNodes = {}
        self.superEdges = {}

        # create spatial index object
        self.spIndex = QgsSpatialIndex()

        for f in self.edges:

            #self.progress.emit(45 * f_count / self.road_layer_count)
            #f_count += 1

            attr = f.attributes()
            attrs = dict(zip(self.edge_flds, attr))
            self.edge_attrs[f.id()] = attrs
            f_geom = f.geometry()
            vertices = [vertex for vertex in get_vertices(f_geom)]
            # TODO: some of the centroids are not correct
            self.edge_geoms[f.id()] = {
                'wkt': f_geom.exportToWkt(),
                'source': f[self.source_col],
                'target': f[self.target_col],
                'vertices': vertices,
                'centroid': pl_midpoint(f_geom),
                'angular change': pl_angle(f_geom),
                'ends': [vertices[0], vertices[1]]
            }

            self.node_attrs[f[self.source_col]] = vertices[0]
            self.node_attrs[f[self.target_col]] = vertices[-1]

            # insert features to index
            self.spIndex.insertFeature(f)

            # create topology & adjacent lines dictionary
            if self.source_col == 'default':
                startnode = f.geometry().asPolyline()[0]
            else:
                startnode = f[self.source_col]
            if self.target_col == 'default':
                endnode = f.geometry().asPolyline()[-1]
            else:
                endnode = f[self.target_col]
            try:
                self.topology[startnode] += [endnode]
            except KeyError, e:
                self.topology[startnode] = [endnode]
            try:
                self.topology[endnode] += [startnode]
            except KeyError, e:
                self.topology[endnode] = [startnode]
            self.nodes.append(startnode)
            self.nodes.append(endnode)
            try:
                self.adj_lines[startnode] += [f.id()]
            except KeyError, e:
                self.adj_lines[startnode] = [f.id()]
示例#33
0
def interpolate_polygon_polygon(source, target, wgs84_extent):
    """ Transfer values from source polygon layer to the target polygon layer.

    This method will do a spatial join: the output layer will contain all
    features from target layer, with the addition of attributes of intersecting
    feature from the source layer. If there is not intersecting source feature,
    the output layer will still contain the target feature, with null
    attributes from the source layer.

    The intersection test considers only centroids of target features
    (not the whole polygon geometry).

    If more features from source layer intersect a target feature, only
    the first intersecting source feature will be used.

    :param source: Source polygon layer
    :type source: QgsVectorLayer

    :param target: Target polygon layer
    :type target: QgsVectorLayer

    :param wgs84_extent: Requested extent for analysis, in WGS84 coordinates
    :type wgs84_extent: QgsRectangle

    :return: output layer
    :rtype: QgsVectorLayer
    """

    source_field_count = source.dataProvider().fields().count()
    target_field_count = target.dataProvider().fields().count()

    # Create new layer for writing resulting features.
    # It will contain attributes of both target and source layers
    result = create_layer(target)
    new_fields = source.dataProvider().fields().toList()
    new_fields.append(QgsField('polygon_id', QVariant.Int))
    result.dataProvider().addAttributes(new_fields)
    result.updateFields()
    result_fields = result.dataProvider().fields()

    # setup transform objects between different CRS
    crs_wgs84 = QgsCoordinateReferenceSystem("EPSG:4326")
    wgs84_to_source = QgsCoordinateTransform(crs_wgs84, source.crs())
    wgs84_to_target = QgsCoordinateTransform(crs_wgs84, target.crs())
    source_to_target = QgsCoordinateTransform(source.crs(), target.crs())

    # compute extents in CRS of layers
    source_extent = wgs84_to_source.transformBoundingBox(wgs84_extent)
    target_extent = wgs84_to_target.transformBoundingBox(wgs84_extent)

    # cache source layer (in CRS of target layer)
    source_index = QgsSpatialIndex()
    source_geometries = {}  # key = feature ID, value = QgsGeometry
    source_attributes = {}
    for f in source.getFeatures(QgsFeatureRequest(source_extent)):
        f.geometry().transform(source_to_target)
        source_index.insertFeature(f)
        source_geometries[f.id()] = QgsGeometry(f.geometry())
        source_attributes[f.id()] = f.attributes()

    # Go through all features in target layer and for each decide
    # whether it is intersected by any source feature
    result_features = []
    for f in target.getFeatures(QgsFeatureRequest(target_extent)):
        # we use just centroids of target polygons
        centroid_geometry = f.geometry().centroid()
        centroid = centroid_geometry.asPoint()
        rect = QgsRectangle(
            centroid.x(), centroid.y(),
            centroid.x(), centroid.y())
        ids = source_index.intersects(rect)

        has_matching_source = False
        for source_id in ids:
            if source_geometries[source_id].intersects(centroid_geometry):
                # we have found intersection between source and target
                f_result = QgsFeature(result_fields)
                f_result.setGeometry(f.geometry())
                for i in xrange(target_field_count):
                    f_result[i] = f[i]
                for i in xrange(source_field_count):
                    f_result[i + target_field_count] = source_attributes[
                        source_id][i]
                f_result['polygon_id'] = source_id
                result_features.append(f_result)
                has_matching_source = True
                break   # assuming just one source for each target feature

        # if there is no intersecting feature from source layer,
        # we will keep the source attributes null
        if not has_matching_source:
            f_result = QgsFeature(result_fields)
            f_result.setGeometry(f.geometry())
            for i in xrange(target_field_count):
                f_result[i] = f[i]
            result_features.append(f_result)

        if len(result_features) == 1000:
            result.dataProvider().addFeatures(result_features)
            result_features = []

    result.dataProvider().addFeatures(result_features)
    return result
    class SequenceGenerator:
        def __init__(self,
                     centroid_layer,
                     trajectory_layer,
                     feedback,
                     timezone,
                     weight_field=None):
            centroids = [f for f in centroid_layer.getFeatures()]
            self.cell_index = QgsSpatialIndex()
            for f in centroids:
                self.cell_index.insertFeature(f)
            self.id_to_centroid = {
                f.id(): [f, [0, 0, 0, 0, 0]]
                for (f) in centroids
            }
            self.timezone = timezone
            self.weight_field = weight_field
            if weight_field is not None:
                self.weightIdx = trajectory_layer.fields().indexFromName(
                    weight_field)
            else:
                self.weightIdx = None
            self.sequences = {}

            n_traj = float(trajectory_layer.featureCount())
            for i, traj in enumerate(trajectory_layer.getFeatures()):
                self.evaluate_trajectory(traj)
                feedback.setProgress(i / n_traj * 100)

        def evaluate_trajectory(self, trajectory):
            points = trajectory.geometry().asPolyline()
            this_sequence = []
            weight = 1 if self.weight_field is None else trajectory.attributes(
            )[self.weightIdx]
            prev_cell_id = None
            for i, pt in enumerate(points):
                nn_id = self.cell_index.nearestNeighbor(pt, 1)[0]
                nearest_cell = self.id_to_centroid[nn_id][0]
                nearest_cell_id = nearest_cell.id()
                if len(this_sequence) >= 1:
                    prev_cell_id = this_sequence[-1]
                    if nearest_cell_id != prev_cell_id:
                        if (prev_cell_id, nearest_cell_id) in self.sequences:
                            self.sequences[(prev_cell_id,
                                            nearest_cell_id)] += weight
                        else:
                            self.sequences[(prev_cell_id,
                                            nearest_cell_id)] = weight
                if nearest_cell_id != prev_cell_id:
                    # we have changed to a new cell --> up the counter
                    m = trajectory.geometry().vertexAt(i).m()
                    if math.isnan(m):
                        m = 0
                    t = datetime(1970, 1, 1) + timedelta(
                        seconds=m) + timedelta(hours=self.timezone)
                    h = t.hour
                    self.id_to_centroid[nn_id][1][0] += weight
                    self.id_to_centroid[nn_id][1][int(h / 6) + 1] += weight
                    this_sequence.append(nearest_cell_id)

        def create_flow_lines(self):
            lines = []
            for key, value in self.sequences.items():
                p1 = self.id_to_centroid[key[0]][0].geometry().asPoint()
                p2 = self.id_to_centroid[key[1]][0].geometry().asPoint()
                p1 = QgsPoint(p1.x(), p1.y())
                p2 = QgsPoint(p2.x(), p2.y())
                feat = QgsFeature()
                feat.setGeometry(QgsGeometry.fromPolyline([p1, p2]))
                feat.setAttributes([key[0], key[1], value])
                lines.append(feat)
            return lines
示例#35
0
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.VECTOR))
        pointCount = float(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))

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

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

        index = QgsSpatialIndex()
        points = dict()

        da = QgsDistanceArea()
        request = QgsFeatureRequest()

        random.seed()

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

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

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

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

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

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

        del writer
示例#36
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """

        # Retrieve the feature source and sink. The 'dest_id' variable is used
        # to uniquely identify the feature sink, and must be included in the
        # dictionary returned by the processAlgorithm function.
        couche_lines = self.parameterAsVectorLayer(parameters, self.LINES,
                                                   context)
        couche_points = self.parameterAsVectorLayer(parameters, self.NODES,
                                                    context)
        radius = self.parameterAsDouble(parameters, self.RAYON, context)

        # Compute the number of steps to display within the progress bar and
        # get features from source
        delta = float(radius)
        index = QgsSpatialIndex()
        lines = couche_lines.getFeatures()
        for i in lines:
            if i.geometry().isMultipart():
                i.setGeometry(
                    QgsGeometry.fromPolylineXY(
                        i.geometry().asMultiPolyline()[0]))
            index.insertFeature(i)

        couche_lines.startEditing()
        couche_lines.beginEditCommand(
            self.tr("Split polylines at connections"))
        points = couche_points.getFeatures()
        nb = couche_points.featureCount()
        feedback.setProgressText(self.tr("Connecting points to lines..."))
        for pos, pt in enumerate(points):
            feedback.setProgress(pos * 100.0 / nb)
            ptg = pt.geometry()
            if ptg.isMultipart():
                ptg = QgsGeometry.fromPoint(ptg.asMultiPoint()[0])
            coor = ptg.asPoint()
            nearest = index.intersects(
                QgsRectangle(coor.x() - delta,
                             coor.y() - delta,
                             coor.x() + delta,
                             coor.y() + delta))
            dmin = 1e38
            if len(nearest) > 0:
                for n in nearest:
                    f = couche_lines.getFeatures(request=QgsFeatureRequest(n))
                    for g in f:
                        d = g.geometry().distance(pt.geometry())
                        if d <= dmin:
                            dmin = d
                            gmin = g
                            gid = g.id()
                g = gmin
                if g.geometry().distance(pt.geometry()) < delta:
                    a = g.geometry().closestSegmentWithContext(ptg.asPoint())
                    if not (a[2] == 0):
                        geom = g.geometry()
                        geom.convertToSingleType()
                        geom_id = g.id()
                        att = g.attributes()
                        connexion = QgsFeature()
                        connexion.setGeometry(
                            QgsGeometry.fromPolylineXY([ptg.asPoint(), a[1]]))
                        connexion.setAttributes(att)
                        couche_lines.addFeature(connexion)
                        geom.insertVertex(a[1][0], a[1][1], a[2])
                        geoma = geom.asPolyline()[:a[2] + 1]
                        geomb = geom.asPolyline()[a[2]:]
                        feedback.setProgressText(unicode(geomb))
                        fa = QgsFeature()
                        fa.setGeometry(QgsGeometry.fromPolylineXY(geoma))
                        fa.setAttributes(att)
                        couche_lines.addFeature(fa)
                        index.insertFeature(fa)
                        fb = QgsFeature()
                        fb.setGeometry(QgsGeometry.fromPolylineXY(geomb))
                        fb.setAttributes(att)
                        couche_lines.addFeature(fb)
                        index.insertFeature(fb)
                        couche_lines.deleteFeature(g.id())
                        index.deleteFeature(g)
        couche_lines.commitChanges()
        couche_lines.endEditCommand()
        return {self.LINES: 'OK'}
示例#37
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().geometry().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}
示例#38
0
class Sampling(object):
    # for save all instances
    samplings = dict()  # {name_in_qgis: class instance}

    def __init__(self,
                 sampling_type,
                 ThematicR,
                 CategoricalR,
                 sampling_method=None,
                 srs_config=None,
                 output_file=None):
        # set and init variables
        # sampling_type => "simple" (simple random sampling),
        #                  "stratified" (stratified random sampling)
        self.sampling_type = sampling_type
        self.ThematicR = ThematicR
        self.CategoricalR = CategoricalR
        # for stratified sampling
        self.sampling_method = sampling_method
        # save some stratified sampling configuration
        self.srs_config = srs_config
        # set the output dir for save sampling
        self.output_file = output_file
        # save instance
        self.filename = os.path.splitext(
            os.path.basename(output_file))[0]  # without extension
        Sampling.samplings[self.filename] = self
        # for save all sampling points
        self.points = dict()

    @wait_process
    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

    def check_sampling_point(self, sampling_point):
        """Make several checks to the sampling point, else discard
        """
        if not sampling_point.in_valid_data(self.ThematicR):
            return False

        if not sampling_point.in_extent(self.ThematicR_boundaries):
            return False

        if not sampling_point.in_mim_distance(self.index, self.min_distance,
                                              self.points):
            return False

        if self.sampling_type == "simple":
            if not sampling_point.in_categorical_raster_SimpRS(
                    self.pixel_values, self.CategoricalR):
                return False
        if self.sampling_type == "stratified":
            if not sampling_point.in_categorical_raster_StraRS(
                    self.pixel_values, self.number_of_samples,
                    self.CategoricalR, self.samples_in_categories):
                return False

        if self.neighbor_aggregation and \
                not sampling_point.check_neighbors_aggregation(self.ThematicR, *self.neighbor_aggregation):
            return False

        return True

    def save_config(self, file_out):
        from AcATaMa.gui.acatama_dockwidget import AcATaMaDockWidget as AcATaMa

        config = configparser.RawConfigParser()

        config.add_section('thematic')
        config.set('thematic', 'thematic_raster', self.ThematicR.file_path)
        config.set('thematic', 'thematic_raster_band',
                   str(self.ThematicR.band))
        config.set('thematic', 'thematic_raster_nodata',
                   str(self.ThematicR.nodata))

        config.add_section('sampling')
        config.set('sampling', 'type',
                   '{} random sampling'.format(self.sampling_type))
        if self.sampling_type == "simple":
            config.add_section('sampling options')
            config.set('sampling options', 'total_of_samples',
                       self.total_of_samples)
            config.set('sampling options', 'min_distance', self.min_distance)

            config.add_section('sampling in categorical raster')
            if isinstance(self.CategoricalR, Raster):
                config.set('sampling in categorical raster',
                           'categorical_raster', self.CategoricalR.file_path)
                config.set('sampling in categorical raster',
                           'categorical_raster_band', self.CategoricalR.band)
            else:
                config.set('sampling in categorical raster',
                           'categorical_raster', 'None')
                config.set('sampling in categorical raster',
                           'categorical_raster_band', 'None')
            config.set(
                'sampling in categorical raster', 'set_pixel_values',
                ','.join(map(str, self.pixel_values))
                if self.pixel_values is not None else 'None')

        if self.sampling_type == "stratified":
            config.add_section('categorical raster')
            if isinstance(self.CategoricalR, Raster):
                config.set('categorical raster', 'categorical_raster',
                           self.CategoricalR.file_path)
                config.set('categorical raster', 'categorical_raster_band',
                           self.CategoricalR.band)
                config.set('categorical raster', 'categorical_raster_nodata',
                           self.CategoricalR.nodata)
            else:
                config.set('categorical raster', 'categorical_raster', 'None')
                config.set('categorical raster', 'categorical_raster_band',
                           'None')
                config.set('categorical raster', 'categorical_raster_nodata',
                           'None')

            config.add_section('stratified random sampling method')
            config.set('stratified random sampling method', 'sampling_method',
                       self.sampling_method)
            if self.sampling_method == "area based proportion":
                config.set('stratified random sampling method',
                           'total_expected_std_error',
                           self.srs_config["total_std_error"])
            config.set('stratified random sampling method', 'total_of_samples',
                       self.total_of_samples)

            config.add_section('num_samples')
            for pixel, count in zip(self.pixel_values,
                                    self.samples_in_categories):
                if count > 0:
                    config.set('num_samples', 'pix_val_' + str(pixel),
                               str(count))

            if self.sampling_method == "area based proportion":
                config.set('stratified random sampling method',
                           'total_expected_std_error',
                           self.srs_config["total_std_error"])
                config.add_section('std_dev')
                for pixel, count, std_dev in zip(self.pixel_values,
                                                 self.samples_in_categories,
                                                 self.srs_config["std_dev"]):
                    if count > 0:
                        config.set('std_dev', 'pix_val_' + str(pixel),
                                   str(std_dev))

            config.add_section('sampling options')
            config.set('sampling options', 'min_distance', self.min_distance)

        config.add_section('with neighbors aggregation')
        config.set(
            'with neighbors aggregation', 'min_neighbors_with_the_same_class',
            '{1}/{0}'.format(*self.neighbor_aggregation)
            if self.neighbor_aggregation is not None else 'None')

        config.add_section('generation')
        if AcATaMa.dockwidget.widget_generate_SimpRS.button_attempts_by_sampling.isChecked(
        ):
            config.set(
                'generation', 'maximum_attempts_by_sampling',
                AcATaMa.dockwidget.widget_generate_SimpRS.attempts_by_sampling.
                value())
        else:
            config.set('generation', 'maximum_attempts_by_sampling',
                       "until reaching the set sampling numbers")
        config.set(
            'generation', 'random_seed',
            self.random_seed if self.random_seed is not None else "automatic")

        with open(file_out, 'w') as configfile:
            config.write(configfile)
示例#39
0
class TriangleMesh:

    # 0 - 3
    # | / |
    # 1 - 2

    def __init__(self, xmin, ymin, xmax, ymax, x_segments, y_segments):
        self.vbands = []
        self.hbands = []
        self.vidx = QgsSpatialIndex()
        self.hidx = QgsSpatialIndex()

        xres = (xmax - xmin) / x_segments
        yres = (ymax - ymin) / y_segments
        self.xmin, self.ymax, self.xres, self.yres = xmin, ymax, xres, yres

        def addVBand(idx, geom):
            f = QgsFeature(idx)
            f.setGeometry(geom)
            self.vbands.append(f)
            self.vidx.insertFeature(f)

        def addHBand(idx, geom):
            f = QgsFeature(idx)
            f.setGeometry(geom)
            self.hbands.append(f)
            self.hidx.insertFeature(f)

        for x in range(x_segments):
            addVBand(
                x,
                QgsGeometry.fromRect(
                    QgsRectangle(xmin + x * xres, ymin, xmin + (x + 1) * xres,
                                 ymax)))

        for y in range(y_segments):
            addHBand(
                y,
                QgsGeometry.fromRect(
                    QgsRectangle(xmin, ymax - (y + 1) * yres, xmax,
                                 ymax - y * yres)))

    def vSplit(self, geom):
        """split polygon vertically"""
        for idx in self.vidx.intersects(geom.boundingBox()):
            geometry = geom.intersection(self.vbands[idx].geometry())
            if geometry is not None:
                yield idx, geometry

    def hIntersects(self, geom):
        """indices of horizontal bands that intersect with geom"""
        for idx in self.hidx.intersects(geom.boundingBox()):
            if geom.intersects(self.hbands[idx].geometry()):
                yield idx

    def splitPolygon(self, geom):
        xmin, ymax, xres, yres = self.xmin, self.ymax, self.xres, self.yres

        polygons = []
        for x, vi in self.vSplit(geom):
            for y in self.hIntersects(vi):
                pt0 = QgsPointXY(xmin + x * xres, ymax - y * yres)
                pt1 = QgsPointXY(xmin + x * xres, ymax - (y + 1) * yres)
                pt2 = QgsPointXY(xmin + (x + 1) * xres, ymax - (y + 1) * yres)
                pt3 = QgsPointXY(xmin + (x + 1) * xres, ymax - y * yres)
                quad = QgsGeometry.fromPolygonXY([[pt0, pt1, pt2, pt3, pt0]])
                tris = [[[pt0, pt1, pt3, pt0]], [[pt3, pt1, pt2, pt3]]]

                if geom.contains(quad):
                    polygons += tris
                else:
                    for i, tri in enumerate(
                            map(QgsGeometry.fromPolygonXY, tris)):
                        if geom.contains(tri):
                            polygons.append(tris[i])
                        elif geom.intersects(tri):
                            poly = geom.intersection(tri)
                            if poly.isMultipart():
                                polygons += poly.asMultiPolygon()
                            else:
                                polygons.append(poly.asPolygon())
        return QgsGeometry.fromMultiPolygonXY(polygons)

    def splitPolygonA(self, geom):
        xmin, ymax, xres, yres = self.xmin, self.ymax, self.xres, self.yres

        for x, vi in self.vSplit(geom):
            for y in self.hIntersects(vi):
                pt0 = QgsPointXY(xmin + x * xres, ymax - y * yres)
                pt1 = QgsPointXY(xmin + x * xres, ymax - (y + 1) * yres)
                pt2 = QgsPointXY(xmin + (x + 1) * xres, ymax - (y + 1) * yres)
                pt3 = QgsPointXY(xmin + (x + 1) * xres, ymax - y * yres)
                quad = QgsGeometry.fromPolygonXY([[pt0, pt1, pt2, pt3, pt0]])
                tris = [[[pt0, pt1, pt3, pt0]], [[pt3, pt1, pt2, pt3]]]

                if geom.contains(quad):
                    yield tris[0]
                    yield tris[1]
                else:
                    for i, tri in enumerate(
                            map(QgsGeometry.fromPolygonXY, tris)):
                        if geom.contains(tri):
                            yield tris[i]
                        elif geom.intersects(tri):
                            poly = geom.intersection(tri)
                            if poly.isMultipart():
                                for sp in poly.asMultiPolygon():
                                    yield sp
                            else:
                                yield poly.asPolygon()
class PW_Abbreviations_Algorithm(QgsProcessingAlgorithm):

    INPUT = 'INPUT'
    INPUT_MATRIX = 'INPUT MATRIX'
    FIELD = 'FIELD'
    OUTPUT_FIELD = 'OUTPUT FIELD'
    LIST = 'LIST'
    RESOLVE_CASE = 'RESOLVE CASE'
    RESOLVE_FIRST = 'RESOLVE FIRST'
    OUTPUT = 'OUTPUT'

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return PW_Abbreviations_Algorithm()

    def name(self):
        return 'pw_abbreviations'

    def displayName(self):
        return self.tr('PW ABBREVIATIONS')

    def group(self):
        return self.tr('PW')

    def groupId(self):
        return 'pw'

    def shortHelpString(self):
        help = """This algorithm expands abbreviations from input features; if text is recognized as abbreviation, the algorithm replaces it by last previous word in the text (in reading order).\
        Additionally it changes first letters in the words to capitals and the others to lower. If words in the text are sorted in alphabetical order, the algorithm can recognize words with first letter not matching to its neighborhood and change it to proper letter.\
        <hr>
        <b>Input abbreviations layer</b>\
        <br>The features contain abbreviations to expand.\
        <br><br><b>Input sheets layer</b>\
        <br>The features with extands of sheets.\
        <br><br><b>Text input field</b>\
        <br>The field in the input table contains abbreviations to expand.\
        <br><br><b>Text output field</b>\
        <br>The field in the input table in which the expanded abbreviations will be add.\
        <br><br><b>Characters to remove on edges</b>\
        <br>If input text starts or ends with character from the list, this character will be remove from text.\
        <br><br><b>Resolve first</b>\
        <br>Changes first letters in the words to capitals and the others to lower letters.\
        <br><br><b>Resolve capitalization</b>\
        <br>Recognizes words with first letter not matching to its neighborhood and changes it to proper letter.\
        (Alphabetical order of text words is necassery)\
        <br><br><b>Output layer</b>\
        <br>Location of the output layer.\
        """
        return self.tr(help)

    def initAlgorithm(self, config=None):

        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT, self.tr('Input abbreviations layer'),
                [QgsProcessing.TypeVectorPolygon]))
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT_MATRIX, self.tr('Input sheets layer'),
                [QgsProcessing.TypeVectorPolygon]))
        self.addParameter(
            QgsProcessingParameterField(
                self.FIELD,
                self.tr('Text input field'),
                parentLayerParameterName=self.INPUT,
                type=QgsProcessingParameterField.DataType.String))
        self.addParameter(
            QgsProcessingParameterField(
                self.OUTPUT_FIELD,
                self.tr('Text output field'),
                parentLayerParameterName=self.INPUT,
                type=QgsProcessingParameterField.DataType.String))
        global CharsList
        CharsList = [
            '.', ',', ':', ';', '/', '\\', '"', "'", '|', '_', '*', '!', '^',
            '~', '+', '@', '#', '$', '&', '(', ')', ' ', '0', '1', '2', '3',
            '4', '5', '6', '7', '8', '9', '-'
        ]
        global Checklist
        Checklist = []
        for i in range(0, len(CharsList), 1):
            Checklist.append(i)

        self.addParameter(
            QgsProcessingParameterEnum(
                self.LIST,
                self.tr('Characters to remove on edges'),
                options=CharsList,
                allowMultiple=True,
                defaultValue=Checklist,
                optional=True,
            ))
        self.addParameter(
            QgsProcessingParameterBoolean(self.RESOLVE_FIRST,
                                          self.tr('Resolve first')))
        self.addParameter(
            QgsProcessingParameterBoolean(self.RESOLVE_CASE,
                                          self.tr('Resolve capitalization')))
        self.addParameter(
            QgsProcessingParameterFeatureSink(self.OUTPUT,
                                              self.tr('Output layer')))

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

        self.source_layer = self.parameterAsLayer(parameters, self.INPUT,
                                                  context)
        self.feature_source = self.parameterAsSource(parameters, self.INPUT,
                                                     context)
        self.field = self.parameterAsString(parameters, self.FIELD, context)
        self.dest_field = self.parameterAsString(parameters, self.OUTPUT_FIELD,
                                                 context)
        self.matrix_feature_source = self.parameterAsSource(
            parameters, self.INPUT_MATRIX, context)
        self.chars_indices = self.parameterAsEnums(parameters, 'LIST', context)
        self.case = self.parameterAsBool(parameters, self.RESOLVE_CASE,
                                         context)
        self.first = self.parameterAsBool(parameters, self.RESOLVE_FIRST,
                                          context)
        (self.sink,
         dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                         self.feature_source.fields(),
                                         self.feature_source.wkbType(),
                                         self.feature_source.sourceCrs())
        feedback.setProgressText('\nsorting sheets in reading order...\n')
        matrix_features_iterator = self.matrix_feature_source.getFeatures(
            QgsFeatureRequest())
        matrix_features = []
        for feat in matrix_features_iterator:
            matrix_features.append(feat)
        SheetsOrderedList = self.PutInOrderFeatures(feedback, matrix_features)

        features_iterator = self.feature_source.getFeatures(
            QgsFeatureRequest())
        self.index = QgsSpatialIndex()
        for feat in features_iterator:
            self.index.insertFeature(feat)
        feedback.setProgressText('\nsorting features in reading order...\n')
        OrderedFeatures = []
        for sheet in SheetsOrderedList:
            if feedback.isCanceled(): break
            FirstColumnRect = self.TakeColumnRect(feedback, sheet)[0]
            SecondColumnRect = self.TakeColumnRect(feedback, sheet)[1]
            FeaturesInFirstColumn = self.index.intersects(FirstColumnRect)
            FeaturesInSecondColumn = self.index.intersects(SecondColumnRect)
            self.RemoveWrongIds(feedback, FirstColumnRect,
                                FeaturesInFirstColumn)
            self.RemoveWrongIds(feedback, SecondColumnRect,
                                FeaturesInSecondColumn)
            if len(FeaturesInFirstColumn) > 0:
                OrderedFeatures = OrderedFeatures + self.PutInOrderFeatures(
                    feedback,
                    self.IdsListToFeaturesList(feedback,
                                               FeaturesInFirstColumn))
            if len(FeaturesInSecondColumn) > 0:
                OrderedFeatures = OrderedFeatures + self.PutInOrderFeatures(
                    feedback,
                    self.IdsListToFeaturesList(feedback,
                                               FeaturesInSecondColumn))
        global CharsList
        self.CharsToRemove = [CharsList[index] for index in self.chars_indices]
        feedback.pushCommandInfo('Characters to remove: ' +
                                 str(self.CharsToRemove))
        feedback.setProgressText('\nprocessing time calculating...\n')
        self.total = len(OrderedFeatures)
        self.actual = 0
        if self.total > 0: feedback.setProgress(self.actual / self.total * 100)
        if OrderedFeatures: lastlong = str(OrderedFeatures[0][self.field])
        for feat in OrderedFeatures:
            if feedback.isCanceled(): break
            lp = OrderedFeatures.index(feat)
            string = str(feat[self.field])
            feedback.pushCommandInfo('old: ' + string)
            string = self.OnEachFeatureChars(feedback, string)

            if self.if_short(string,
                             2):  #alternatively it could be a parameter
                string = lastlong
            else:
                if self.first:
                    string = self.OnEachFeatureResolveFirst(
                        feedback, string, feat, OrderedFeatures)
                if self.case:
                    string = self.OnEachFeatureCaseSens(feedback, string)
                lastlong = string
            feedback.pushCommandInfo('new: ' + string)
            self.actual = self.actual + 1
            feedback.setProgress(self.actual / self.total * 100)
            feedback.setProgressText(
                str(self.actual) + '/' + str(self.total) + '       ' +
                'id:  ' + str(feat.id()))
            feat[self.dest_field] = string
            self.sink.addFeature(feat, QgsFeatureSink.FastInsert)
        return {self.OUTPUT: dest_id}

    def if_short(self, string, maximum):
        bool = True
        if len(string) > maximum: bool = False
        if string == 'NULL': bool = True
        return bool

    def most_frequent(self, List):
        '''returns most frquent first character, if it is not in list of characters to remove'''
        char = ''
        #rank of frequency
        freq_rank = [{
            'char': char,
            'count': List.count(char)
        } for char in List]  #.sort(key = self.sortFreq)
        freq_rank.sort(key=self.sortFreq)
        for element in freq_rank:
            if element['char'] not in self.CharsToRemove:
                char = element['char']
                break
        print(freq_rank)
        print('char: ' + char)
        return char

    def sortFreq(self, element):
        return element['count'] * (-1)

    def OnEachFeatureResolveFirst(self, feedback, string, feat, featlist):
        coms = False
        m = 8
        list = []
        index = featlist.index(feat)
        if coms: feedback.pushCommandInfo('index: ' + str(index))
        for i in range(0, m, 1):
            n = index - int(m / 2) + i
            if n < 0: continue
            try:
                list.append(featlist[n][self.field][0])
            except:
                continue
        if coms: feedback.pushCommandInfo('list: ' + str(list))
        most = self.most_frequent(list)
        if coms: feedback.pushCommandInfo('most: ' + str(most))
        prefix = ''
        for i in string:
            if (i.isupper() or i == ' '):
                prefix += i
            else:
                break
        preflen = len(prefix)
        firstmostindex = 0
        if preflen == 0:
            if string[0] != most.lower():
                string = most + string[1:]
        elif preflen < len(string):
            for i in prefix:
                if i == most:
                    break
                else:
                    firstmostindex = firstmostindex + 1
            if firstmostindex < preflen:
                string = string[firstmostindex:]
            else:
                if string[firstmostindex] == most.lower():
                    string = string[firstmostindex:]
                else:
                    string = most + string[firstmostindex:]

        return string

    def OnEachFeatureCaseSens(self, feedback, string):
        lista = []
        listb = []
        for word in string.split():
            listw = list(word)
            for i in range(0, len(listw), 1):
                if i == 0: word = listw[i].upper()
                else:
                    word += listw[i].lower()
            lista.append(word)
        string = ' '.join(lista)
        for word in string.split("-"):
            listw = list(word)
            for i in range(0, len(listw), 1):
                if i == 0: word = word[0].upper()
                else:
                    word += listw[i]
            listb.append(word)
        string = '-'.join(listb)
        return string

    def OnEachFeatureChars(self, feedback, string):
        coms = False
        if coms: feedback.pushCommandInfo('string:' + string)

        ln = len(string)
        for i in range(0, ln - 1, 1):
            if coms: feedback.pushCommandInfo('ln: ' + str(ln))
            if coms: feedback.pushCommandInfo('i: ' + str(i))
            if string[i] not in self.CharsToRemove:
                string = string[i:]
                break

        ln = len(string)
        for i in range(1, ln - 1, 1):
            if coms: feedback.pushCommandInfo('ln: ' + str(ln))
            if coms: feedback.pushCommandInfo('i: ' + str(i))
            j = ln - i
            if coms: feedback.pushCommandInfo('j: ' + str(j))
            if string[j] in self.CharsToRemove:
                if coms:
                    feedback.pushCommandInfo('string[j]: ' + str(string[j]))
                string = string[:j]
                if coms: feedback.pushCommandInfo('finally string:' + string)
            else:
                break

        return string

    def IdsListToFeaturesList(self, feedback, IdsList):
        FeatList = []
        for id in IdsList:
            FeatList.append(self.source_layer.getFeature(id))
        return FeatList

    def RemoveWrongIds(self, feedback, ColumnRect, IdsList):
        for id in IdsList:
            if not ColumnRect.contains(
                    self.source_layer.getFeature(
                        id).geometry().centroid().asPoint()):
                IdsList.remove(id)

    def TakeColumnRect(self, feedback, sheet):
        """Returns two rectangles: first and second column"""
        bbox = sheet.geometry().boundingBox()
        x1, x2, x3, y1, y2 = bbox.xMinimum(), bbox.xMinimum() + (
            bbox.xMaximum() - bbox.xMinimum()) / 2, bbox.xMaximum(
            ), bbox.yMinimum(), bbox.yMaximum()
        FirstColumnRect = QgsRectangle(QgsPointXY(x1, y2), QgsPointXY(x2, y1))
        SecondColumnRect = QgsRectangle(QgsPointXY(x2, y2), QgsPointXY(x3, y1))

        return [FirstColumnRect, SecondColumnRect]

    def PutInOrderFeatures(self, feedback, features_list):
        """ Function puts features in reading order; from left to right in text lines. Used to arrange matrix features and text features in columns"""
        ListByX = features_list.copy()
        ListByX.sort(key=self.sortX)
        ListByY = features_list.copy()
        ListByY.sort(key=self.sortY)
        w, h = len(features_list), len(features_list)
        matrix = [[None] * w for i in range(h)]
        """This part builds 2D features positions table. Each row and column contains only one feature. Teble is inversed, beacause y canvas coord ascends up"""
        for feat in features_list:
            x = ListByX.index(feat)
            y = ListByY.index(feat)
            matrix[y][x] = feat
        """Identifying features lying in the same line; merging and deleting these rows"""
        for row in matrix:
            if matrix.index(row) < (len(matrix) - 1):
                for element in matrix[matrix.index(row) + 1]:
                    if element != None:
                        y_upper = element.geometry().centroid().asPoint().y()
                for element in row:
                    if element != None:
                        if element.geometry().boundingBox().height() / 2 > (
                                y_upper -
                                element.geometry().centroid().asPoint().y()):
                            matrix[matrix.index(row) +
                                   1][row.index(element)] = element
                            row[row.index(element)] = None
        ToDelete = [None] * w
        if ToDelete in matrix: matrix.remove(ToDelete)
        """Inverting table order and rewriting features ti list ordered properly"""
        matrix.reverse()
        OrderedList = []
        for row in matrix:
            for element in row:
                if element != None:
                    OrderedList.append(element)

        return OrderedList

    def sortX(self, feat):
        return feat.geometry().centroid().asPoint().x()

    def sortY(self, feat):
        return feat.geometry().centroid().asPoint().y()
示例#41
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))

        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())
        if sink is None:
            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))

        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}
示例#42
0
class TriangleMesh:

  # 0 - 3
  # | / |
  # 1 - 2

  def __init__(self, xmin, ymin, xmax, ymax, x_segments, y_segments):
    self.vbands = []
    self.hbands = []
    self.vidx = QgsSpatialIndex()
    self.hidx = QgsSpatialIndex()

    xres = (xmax - xmin) / x_segments
    yres = (ymax - ymin) / y_segments
    self.xmin, self.ymax, self.xres, self.yres = xmin, ymax, xres, yres

    def addVBand(idx, geom):
      f = QgsFeature(idx)
      f.setGeometry(geom)
      self.vbands.append(f)
      self.vidx.insertFeature(f)

    def addHBand(idx, geom):
      f = QgsFeature(idx)
      f.setGeometry(geom)
      self.hbands.append(f)
      self.hidx.insertFeature(f)

    for x in range(x_segments):
      addVBand(x, QgsGeometry.fromRect(QgsRectangle(xmin + x * xres, ymin, xmin + (x + 1) * xres, ymax)))

    for y in range(y_segments):
      addHBand(y, QgsGeometry.fromRect(QgsRectangle(xmin, ymax - (y + 1) * yres, xmax, ymax - y * yres)))

  def vSplit(self, geom):
    """split polygon vertically"""
    for idx in self.vidx.intersects(geom.boundingBox()):
      yield idx, geom.intersection(self.vbands[idx].geometry())

  def hIntersects(self, geom):
    """indices of horizontal bands that intersect with geom"""
    for idx in self.hidx.intersects(geom.boundingBox()):
      if geom.intersects(self.hbands[idx].geometry()):
        yield idx

  def splitPolygons(self, geom):
    xmin, ymax, xres, yres = self.xmin, self.ymax, self.xres, self.yres

    for x, vi in self.vSplit(geom):
      for y in self.hIntersects(vi):
        pt0 = QgsPoint(xmin + x * xres, ymax - y * yres)
        pt1 = QgsPoint(xmin + x * xres, ymax - (y + 1) * yres)
        pt2 = QgsPoint(xmin + (x + 1) * xres, ymax - (y + 1) * yres)
        pt3 = QgsPoint(xmin + (x + 1) * xres, ymax - y * yres)
        quad = QgsGeometry.fromPolygon([[pt0, pt1, pt2, pt3, pt0]])
        tris = [[[pt0, pt1, pt3, pt0]], [[pt3, pt1, pt2, pt3]]]

        if geom.contains(quad):
          yield tris[0]
          yield tris[1]
        else:
          for i, tri in enumerate(map(QgsGeometry.fromPolygon, tris)):
            if geom.contains(tri):
              yield tris[i]
            elif geom.intersects(tri):
              poly = geom.intersection(tri)
              if poly.isMultipart():
                for sp in poly.asMultiPolygon():
                  yield sp
              else:
                yield poly.asPolygon()
示例#43
0
 def __sp_index_factory(layer):
     index = QgsSpatialIndex()
     for ft in layer.getFeatures():
         index.insertFeature(ft)
     return index
示例#44
0
    def run(self):
        """Run the impact function.

        :returns: A vector layer with affected areas marked.
        :type: safe_layer
        """
        hazard_layer = self.hazard.layer
        exposure = self.exposure.layer

        # Thresholds for tsunami hazard zone breakdown.
        low_max = self.parameters['low_threshold'].value
        medium_max = self.parameters['medium_threshold'].value
        high_max = self.parameters['high_threshold'].value
        ranges = ranges_according_thresholds(low_max, medium_max, high_max)

        hazard_value_to_class = {}
        for i, interval in enumerate(ranges):
            hazard_value_to_class[interval] = self.hazard_classes[i]

        # Get parameters from layer's keywords
        class_field = self.exposure.keyword('field')

        # reproject self.extent to the hazard projection
        hazard_crs = hazard_layer.crs()
        hazard_authid = hazard_crs.authid()

        if hazard_authid == 'EPSG:4326':
            viewport_extent = self.requested_extent
        else:
            geo_crs = QgsCoordinateReferenceSystem()
            geo_crs.createFromSrid(4326)
            viewport_extent = extent_to_geo_array(
                QgsRectangle(*self.requested_extent), geo_crs, hazard_crs)

        small_raster = align_clip_raster(hazard_layer, viewport_extent)

        # Create vector features from the flood raster
        hazard_class_attribute = 'hazard'
        vector_file_path = reclassify_polygonize(
            small_raster.source(), ranges, name_field=hazard_class_attribute)

        hazard = QgsVectorLayer(vector_file_path, 'tsunami', 'ogr')

        # prepare objects for re-projection of geometries
        crs_wgs84 = QgsCoordinateReferenceSystem('EPSG:4326')
        hazard_to_exposure = QgsCoordinateTransform(
            hazard.crs(), exposure.crs())
        wgs84_to_hazard = QgsCoordinateTransform(
            crs_wgs84, hazard.crs())
        wgs84_to_exposure = QgsCoordinateTransform(
            crs_wgs84, exposure.crs())

        extent = QgsRectangle(
            self.requested_extent[0], self.requested_extent[1],
            self.requested_extent[2], self.requested_extent[3])
        extent_hazard = wgs84_to_hazard.transformBoundingBox(extent)
        extent_exposure = wgs84_to_exposure.transformBoundingBox(extent)
        extent_exposure_geom = QgsGeometry.fromRect(extent_exposure)

        # make spatial index of hazard
        hazard_index = QgsSpatialIndex()
        hazard_features = {}
        for f in hazard.getFeatures(QgsFeatureRequest(extent_hazard)):
            f.geometry().transform(hazard_to_exposure)
            hazard_index.insertFeature(f)
            hazard_features[f.id()] = QgsFeature(f)

        # create impact layer
        filename = unique_filename(suffix='.shp')
        impact_fields = exposure.dataProvider().fields()
        impact_fields.append(QgsField(self.target_field, QVariant.String))
        writer = QgsVectorFileWriter(
            filename, 'utf-8', impact_fields, QGis.WKBPolygon, exposure.crs())

        # iterate over all exposure polygons and calculate the impact
        _calculate_landcover_impact(
            exposure, extent_exposure, extent_exposure_geom,
            hazard_class_attribute, hazard_features, hazard_index,
            hazard_value_to_class, impact_fields, writer)

        del writer
        impact_layer = QgsVectorLayer(filename, 'Impacted Land Cover', 'ogr')

        if impact_layer.featureCount() == 0:
            raise ZeroImpactException()

        zone_field = None
        if self.aggregator:
            zone_field = self.aggregator.exposure_aggregation_field

        impact_data = LandCoverReportMixin(
            question=self.question,
            impact_layer=impact_layer,
            target_field=self.target_field,
            ordered_columns=self.hazard_classes,
            affected_columns=self.affected_hazard_columns,
            land_cover_field=class_field,
            zone_field=zone_field
        ).generate_data()

        # Define style for the impact layer
        style_classes = [
            dict(
                label=self.hazard_classes[0] + ': 0m',
                value=self.hazard_classes[0],
                colour='#00FF00',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[1] + ': >0 - %.1f m' % low_max,
                value=self.hazard_classes[1],
                colour='#FFFF00',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[2] + ': %.1f - %.1f m' % (
                    low_max + 0.1, medium_max),
                value=self.hazard_classes[2],
                colour='#FFB700',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[3] + ': %.1f - %.1f m' % (
                    medium_max + 0.1, high_max),
                value=self.hazard_classes[3],
                colour='#FF6F00',
                border_color='#000000',
                transparency=0),
            dict(
                label=self.hazard_classes[4] + ' > %.1f m' % high_max,
                value=self.hazard_classes[4],
                colour='#FF0000',
                border_color='#000000',
                transparency=0),
        ]
        style_info = dict(
            target_field=self.target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        extra_keywords = {
            'map_title': self.map_title(),
            'target_field': self.target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Create vector layer and return
        impact_layer = Vector(
            data=impact_layer,
            name=self.map_title(),
            keywords=impact_layer_keywords,
            style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
示例#45
0
    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
        completeInputAADTprovided = False  # AADT is broken down into the vehicles listed in completeInputs
        modelledTypesAADTprovided = False  # AADT data is broken down into the vehicles listed in modelledTypes
        self.validateInputs(startTime, shapefile, epsgCode, roadTypeField,
                            roadTypeNames)

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

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

        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(vAADTFields.keys()))
            missingFrom2 = list(
                set(allowedKeys2).difference(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(vAADTFields.keys()))
            fieldsToSample.extend(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(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
        vehDate = pd.datetime.strptime(
            '2005-01-01', '%Y-%m-%d'
        )  # For now, just assumes every vehicle was made in 2005 and looks up values from the fuel consumption object

        # 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.insertFeature(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=map(intOrString, t.values),
                                  data=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 = fuelUseNames['petrol'].values()
        allFuelFields.extend(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=intersectedLines.keys(),
            columns=newFieldIndices)  # Results container for each feature
        for outfeat_id in 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
示例#46
0
    def processAlgorithm(self, parameters, context, feedback):
        layer = QgsProcessingUtils.mapLayerFromString(
            self.getParameterValue(self.VECTOR), context)
        pointCount = float(self.getParameterValue(self.POINT_NUMBER))
        minDistance = float(self.getParameterValue(self.MIN_DISTANCE))

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

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

        index = QgsSpatialIndex()
        points = dict()

        da = QgsDistanceArea()
        request = QgsFeatureRequest()

        random.seed()

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

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

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

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

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

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

        del writer
示例#47
0
class PyProvider(QgsVectorDataProvider):

    next_feature_id = 1

    @classmethod
    def providerKey(cls):
        """Returns the memory provider key"""
        return 'pythonprovider'

    @classmethod
    def description(cls):
        """Returns the memory provider description"""
        return 'Python Test Provider'

    @classmethod
    def createProvider(cls, uri, providerOptions):
        return PyProvider(uri, providerOptions)

    # Implementation of functions from QgsVectorDataProvider

    def __init__(self, uri='', providerOptions=QgsDataProvider.ProviderOptions()):
        super().__init__(uri)
        # Use the memory layer to parse the uri
        mlayer = QgsVectorLayer(uri, 'ml', 'memory')
        self.setNativeTypes(mlayer.dataProvider().nativeTypes())
        self._uri = uri
        self._fields = mlayer.fields()
        self._wkbType = mlayer.wkbType()
        self._features = {}
        self._extent = QgsRectangle()
        self._extent.setMinimal()
        self._subset_string = ''
        self._crs = mlayer.crs()
        self._spatialindex = None
        self._provider_options = providerOptions
        if 'index=yes'in self._uri:
            self.createSpatialIndex()

    def featureSource(self):
        return PyFeatureSource(self)

    def dataSourceUri(self, expandAuthConfig=True):
        return self._uri

    def storageType(self):
        return "Python test memory storage"

    def getFeatures(self, request=QgsFeatureRequest()):
        return QgsFeatureIterator(PyFeatureIterator(PyFeatureSource(self), request))

    def uniqueValues(self, fieldIndex, limit=1):
        results = set()
        if fieldIndex >= 0 and fieldIndex < self.fields().count():
            req = QgsFeatureRequest()
            req.setFlags(QgsFeatureRequest.NoGeometry)
            req.setSubsetOfAttributes([fieldIndex])
            for f in self.getFeatures(req):
                results.add(f.attributes()[fieldIndex])
        return results

    def wkbType(self):
        return self._wkbType

    def featureCount(self):
        if not self.subsetString():
            return len(self._features)
        else:
            req = QgsFeatureRequest()
            req.setFlags(QgsFeatureRequest.NoGeometry)
            req.setSubsetOfAttributes([])
            return len([f for f in self.getFeatures(req)])

    def fields(self):
        return self._fields

    def addFeatures(self, flist, flags=None):
        added = False
        f_added = []
        for f in flist:
            if f.hasGeometry() and (f.geometry().wkbType() != self.wkbType()):
                return added, f_added

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

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

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

        return added, f_added

    def deleteFeatures(self, ids):
        if not ids:
            return True
        removed = False
        for id in ids:
            if id in self._features:
                if self._spatialindex is not None:
                    self._spatialindex.deleteFeature(self._features[id])
                del self._features[id]
                removed = True
        if removed:
            self.clearMinMaxCache()
            self.updateExtents()
        return removed

    def addAttributes(self, attrs):
        try:
            for new_f in attrs:
                if new_f.type() not in (QVariant.Int, QVariant.Double, QVariant.String, QVariant.Date, QVariant.Time, QVariant.DateTime, QVariant.LongLong, QVariant.StringList, QVariant.List):
                    continue
                self._fields.append(new_f)
                for f in self._features.values():
                    old_attrs = f.attributes()
                    old_attrs.append(None)
                    f.setAttributes(old_attrs)
            self.clearMinMaxCache()
            return True
        except Exception:
            return False

    def renameAttributes(self, renamedAttributes):
        result = True
        # We need to replace all fields because python bindings return a copy from [] and at()
        new_fields = [self._fields.at(i) for i in range(self._fields.count())]
        for fieldIndex, new_name in renamedAttributes.items():
            if fieldIndex < 0 or fieldIndex >= self._fields.count():
                result = False
                continue
            if self._fields.indexFromName(new_name) >= 0:
                #field name already in use
                result = False
                continue
            new_fields[fieldIndex].setName(new_name)
        if result:
            self._fields = QgsFields()
            for i in range(len(new_fields)):
                self._fields.append(new_fields[i])
        return result

    def deleteAttributes(self, attributes):
        attrIdx = sorted(attributes, reverse=True)

        # delete attributes one-by-one with decreasing index
        for idx in attrIdx:
            self._fields.remove(idx)
            for f in self._features.values():
                attr = f.attributes()
                del(attr[idx])
                f.setAttributes(attr)
        self.clearMinMaxCache()
        return True

    def changeAttributeValues(self, attr_map):
        for feature_id, attrs in attr_map.items():
            try:
                f = self._features[feature_id]
            except KeyError:
                continue
            for k, v in attrs.items():
                f.setAttribute(k, v)
        self.clearMinMaxCache()
        return True

    def changeGeometryValues(self, geometry_map):
        for feature_id, geometry in geometry_map.items():
            try:
                f = self._features[feature_id]
                f.setGeometry(geometry)
            except KeyError:
                continue
        self.updateExtents()
        return True

    def allFeatureIds(self):
        return list(self._features.keys())

    def subsetString(self):
        return self._subset_string

    def setSubsetString(self, subsetString):
        if subsetString == self._subset_string:
            return True
        self._subset_string = subsetString
        self.updateExtents()
        self.clearMinMaxCache()
        self.dataChanged.emit()
        return True

    def supportsSubsetString(self):
        return True

    def createSpatialIndex(self):
        if self._spatialindex is None:
            self._spatialindex = QgsSpatialIndex()
            for f in self._features.values():
                self._spatialindex.insertFeature(f)
        return True

    def capabilities(self):
        return QgsVectorDataProvider.AddFeatures | QgsVectorDataProvider.DeleteFeatures | QgsVectorDataProvider.CreateSpatialIndex | QgsVectorDataProvider.ChangeGeometries | QgsVectorDataProvider.ChangeAttributeValues | QgsVectorDataProvider.AddAttributes | QgsVectorDataProvider.DeleteAttributes | QgsVectorDataProvider.RenameAttributes | QgsVectorDataProvider.SelectAtId | QgsVectorDataProvider. CircularGeometries

    #/* Implementation of functions from QgsDataProvider */

    def name(self):
        return self.providerKey()

    def extent(self):
        if self._extent.isEmpty() and self._features:
            self._extent.setMinimal()
            if not self._subset_string:
                # fast way - iterate through all features
                for feat in self._features.values():
                    if feat.hasGeometry():
                        self._extent.combineExtentWith(feat.geometry().boundingBox())
            else:
                for f in self.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])):
                    if f.hasGeometry():
                        self._extent.combineExtentWith(f.geometry().boundingBox())

        elif not self._features:
            self._extent.setMinimal()
        return QgsRectangle(self._extent)

    def updateExtents(self):
        self._extent.setMinimal()

    def isValid(self):
        return True

    def crs(self):
        return self._crs
示例#48
0
class PW_OCR_Advanced_Algorithm(QgsProcessingAlgorithm):
    # Constants used to refer to parameters and outputs. They will be
    # used when calling the algorithm from another algorithm, or when
    # calling from the QGIS console.

    INPUT = 'INPUT'
    RASTER_INPUT = 'RASTER INPUT'
    FIELD = 'FIELD'
    CONF_FIELD = 'CONF FIELD'
    ALL_ACTIVE_RASTERS = 'ALL ACTIVE RASTERS'
    PSM = 'PSM'
    OEM = 'OEM'
    ZERO_CONF = 'ZERO CONF'
    OUTPUT = 'OUTPUT'

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return PW_OCR_Advanced_Algorithm()

    def name(self):
        return 'pw_ocr_adv'

    def displayName(self):
        return self.tr('PW OCR ADVANCED')

    def group(self):
        return self.tr('PW')

    def groupId(self):
        return 'pw'

    def shortHelpString(self):
        help = """This algorithm recognizes text from raster images inside input polygon features and saves as attribute value of output layer.\
        <hr>
        <b>Input polygon layer</b>\
        <br>The features used to recognize text inside them.\
        <br><br><b>Text output field</b>\
        <br>The field in the input table in which the recognized text will be add.\
        <br><br><b>Confidence output field</b>\
        <br>The field in the input table in which the text recognition confidence will be add. Confidence is saved in the list; one value for each word.\
        <br><br><b>Run for all raster layers</b>\
        <br>The algorithm will recognize text from all active raster layers, if checked.\
        <br><br><b>Input raster layer</b>\
        <br>If above checkbox unchecked, the algorithm will recognize text only from this raster layer.\
        <br>In case of multiband raster images, the only first band will be used.\
        <br><br><b>Page Segmentation Mode</b>\
        <br><i>Tesseract</i> Page Segmentation Mode.\
        <br><br><b>OCR Engine Model</b>\
        <br><i>Tesseract</i> OCR Engine Model.\
        <br><br><b>Add words recognized with zero confidence</b>\
        <br>If there are some words recognized with zero confidence, they will be add too.\
        <br><br><b>Output layer</b>\
        <br>Location of the output layer with filled text attribute.\
        """
        return self.tr(help)

    def initAlgorithm(self, config=None):

        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT, self.tr('Input polygon layer'),
                [QgsProcessing.TypeVectorPolygon]))
        self.addParameter(
            QgsProcessingParameterField(
                self.FIELD,
                self.tr('Text output field'),
                parentLayerParameterName=self.INPUT,
                type=QgsProcessingParameterField.DataType.String))
        self.addParameter(
            QgsProcessingParameterField(
                self.CONF_FIELD,
                self.tr('Confidence output field'),
                parentLayerParameterName=self.INPUT,
                type=QgsProcessingParameterField.DataType.String,
                optional=True,
            ))
        self.addParameter(
            QgsProcessingParameterBoolean(
                self.ALL_ACTIVE_RASTERS, self.tr('Run for all raster layers')))
        self.addParameter(
            QgsProcessingParameterRasterLayer(
                self.RASTER_INPUT,
                self.tr('Input raster layer'),
                optional=True,
            ))
        self.addParameter(
            QgsProcessingParameterEnum(
                self.PSM,
                self.tr('Page Segmentation Mode'),
                options=[
                    'Orientation and script detection (OSD) only.',
                    'Automatic page segmentation with OSD.',
                    'Automatic page segmentation, but no OSD, or OCR.',
                    'Fully automatic page segmentation, but no OSD. (Default if no config)',
                    'Assume a single column of text of variable sizes.',
                    'Assume a single uniform block of vertically aligned text.',
                    'Assume a single uniform block of text.',
                    'Treat the image as a single text line.',
                    'Treat the image as a single word.',
                    'Treat the image as a single word in a circle.',
                    'Treat the image as a single character.',
                    'Sparse text. Find as much text as possible in no particular order.',
                    'Sparse text with OSD.',
                    'Raw line. Treat the image as a single text line, bypassing hacks that are Tesseract-specific.'
                ],
                defaultValue=3))
        self.addParameter(
            QgsProcessingParameterEnum(
                self.OEM,
                self.tr('OCR Engine Model'),
                options=['Legacy Tesseract', 'LSTM', '2', '3'],
                defaultValue=1))
        self.addParameter(
            QgsProcessingParameterBoolean(
                self.ZERO_CONF,
                self.tr('Add words recognized with zero confidence'), True))
        self.addParameter(
            QgsProcessingParameterFeatureSink(self.OUTPUT,
                                              self.tr('Output layer')))

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

        self.source_layer = self.parameterAsLayer(parameters, self.INPUT,
                                                  context)
        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)
        self.conf_field = self.parameterAsString(parameters, self.CONF_FIELD,
                                                 context)
        psm = self.parameterAsInt(parameters, 'PSM', context)
        oem = self.parameterAsInt(parameters, 'OEM', context)
        self.zero_conf = self.parameterAsBool(parameters, self.ZERO_CONF,
                                              context)
        (self.sink,
         dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                         self.feature_source.fields(),
                                         self.feature_source.wkbType(),
                                         self.feature_source.sourceCrs())

        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

        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))
        '''here is tesseract config string'''
        self.config = '--psm ' + str(psm) + ' --oem ' + str(oem)
        feedback.pushInfo('TESSERACT CONFIG: ' + self.config)

        self.conf_treshold = 0
        if self.zero_conf:
            self.conf_treshold = -1
        else:
            self.conf_treshold = 0

        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}

    def OnThisRaster(self, feedback, Raster_lyr):

        idsList = self.index.intersects(Raster_lyr.extent())
        if idsList and len(idsList) > 0:
            feedback.pushCommandInfo('\nComputing image ' +
                                     str(Raster_lyr.name()) + '.\n')
            data = pytesseract.image_to_data(Raster_lyr.source(),
                                             lang='pol',
                                             config=self.config,
                                             output_type=Output.DICT)
            text = data['text']
            table_of_words = []
            for i in range(0, len(text), 1):
                pix_centroid_left = data['left'][i] + data['width'][i] / 2
                pix_centroid_top = data['top'][i] + data['height'][i] / 2
                crs_point = self.PixelCoordsToCRSPoint(feedback, Raster_lyr,
                                                       pix_centroid_left,
                                                       pix_centroid_top)
                element = [crs_point, data['text'][i], data['conf'][i]]
                table_of_words.append(element)
            for id in idsList:
                for feat in self.feature_source.getFeatures(
                        QgsFeatureRequest()):
                    if feedback.isCanceled(): break
                    if int(feat.id()) == id:
                        self.OnThisFeature(feedback, feat, table_of_words)
                        break
        else:
            feedback.pushCommandInfo('\nImage ' + str(Raster_lyr.name()) +
                                     ' does not intersect any feature.\n')

    def OnThisFeature(self, feedback, feat, table_of_words):
        chosen_elements = []
        for element in table_of_words:
            if feat.geometry().contains(element[0]):
                chosen_elements.append(element)
        chosen_elements.sort(key=self.sortByX)
        strings = []
        conf = []
        if chosen_elements:
            for element in chosen_elements:
                if int(element[2]) > self.conf_treshold:
                    strings.append(element[1])
                if int(element[2]) > -1: conf.append(int(element[2]))
        string = ' '.join(strings)

        feat[self.dest_field] = string
        if self.conf_field:
            feat[self.conf_field] = str(
                conf)  #.encode('utf8')#.decode('CP1250')

        self.actual = self.actual + 1
        feedback.setProgress(self.actual / self.total * 100)
        feedback.setProgressText(
            str(self.actual) + '/' + str(self.total) + '       ' + 'id:  ' +
            str(feat.id()))
        feedback.pushCommandInfo('\n' + string + '\nConfidence:' + str(conf) +
                                 '\n')
        self.sink.addFeature(feat, QgsFeatureSink.FastInsert)

    def sortByX(self, element):
        return element[0].x()

    def PixelCoordsToCRSPoint(self, feedback, lyr, left, top):
        rect = lyr.extent()
        x = rect.xMinimum() + lyr.rasterUnitsPerPixelY() * left
        y = rect.yMaximum() - lyr.rasterUnitsPerPixelX() * top
        point = QgsPointXY(x, y)

        return point
示例#49
0
class ContourTool(object):
    def updateReference(self, referenceLayer):
        """
        Updates the reference layer and updates the spatial index
        """
        self.first_value = None
        self.reference = referenceLayer
        self.populateIndex()

    def populateIndex(self):
        """
        Populates the spatial index
        """
        #spatial index
        self.index = QgsSpatialIndex()
        for feat in self.reference.getFeatures():
            self.index.insertFeature(feat)

    def getCandidates(self, bbox):
        """
        Gets candidates using the spatial index to speedup the process
        """
        #features that might satisfy the query
        ids = self.index.intersects(bbox)
        candidates = []
        for id in ids:
            candidates.append(
                next(
                    self.reference.getFeatures(
                        QgsFeatureRequest().setFilterFid(id))))
        return candidates

    def getFeatures(self, geom):
        """
        Gets the features that intersect geom to be updated
        """
        #features that satisfy the query
        ret = []

        rect = geom.boundingBox()
        candidates = self.getCandidates(rect)
        for candidate in candidates:
            featGeom = candidate.geometry()
            if featGeom.intersects(geom):
                ret.append(candidate)

        return ret

    def getKey(self, item):
        """
        Gets the key
        """
        return item[0]

    def sortFeatures(self, geom, features):
        """
        Sorts features according to the distance
        """
        #sorting by distance
        distances = []

        firstPoint = geom.asPolyline()[0]
        pointGeom = QgsGeometry.fromPointXY(firstPoint)

        for intersected in features:
            intersection = geom.intersection(intersected.geometry())
            if intersection.type() == QgsWkbTypes.PointGeometry:
                distance = intersection.distance(pointGeom)
                distances.append((distance, intersected))

        ordered = sorted(distances, key=self.getKey)
        #returning a list of tuples (distance, feature)
        return ordered

    def reproject(self, geom, canvasCrs):
        """
        Reprojects geom to the reference layer crs
        """
        destCrs = self.reference.crs()
        if canvasCrs.authid() != destCrs.authid():
            coordinateTransformer = QgsCoordinateTransform(canvasCrs, destCrs)
            geom.transform(coordinateTransformer)

    def setFirstValue(self, value):
        self.first_value = value

    def assignValues(self, attribute, pace, geom, canvasCrs):
        """
        Assigns attribute values to all features that intersect geom.
        """
        self.reproject(geom, canvasCrs)
        features = self.getFeatures(geom)
        if len(features) == 0:
            return -2

        ordered = self.sortFeatures(geom, features)
        if len(ordered) == 0:
            return -1

        self.reference.startEditing()
        #the first feature must have the initial value already assigned
        first_feature = ordered[0][1]
        #getting the filed index that must be updated
        fieldIndex = self.reference.fields().indexFromName(attribute)
        #getting the initial value
        first_value = first_feature.attribute(attribute)
        if not first_value:
            first_value_dlg = ContourValue(self)
            retorno = first_value_dlg.exec_()
            if self.first_value:
                id = first_feature.id()
                first_value = self.first_value
                if not self.reference.changeAttributeValue(
                        id, fieldIndex, self.first_value):
                    return 0
            else:
                return -3
            self.first_value = None

        for i in range(1, len(ordered)):
            #value to be adjusted
            value = first_value + pace * i
            #feature that will be updated
            feature = ordered[i][1]
            #feature id that will be updated
            id = feature.id()
            #actual update in the layer
            if not self.reference.changeAttributeValue(id, fieldIndex, value):
                return 0
        return 1
示例#50
0
class PyProvider(QgsVectorDataProvider):

    next_feature_id = 1

    @classmethod
    def providerKey(cls):
        """Returns the memory provider key"""
        return 'pythonprovider'

    @classmethod
    def description(cls):
        """Returns the memory provider description"""
        return 'Python Test Provider'

    @classmethod
    def createProvider(cls, uri, providerOptions):
        return PyProvider(uri, providerOptions)

    # Implementation of functions from QgsVectorDataProvider

    def __init__(self, uri='', providerOptions=QgsDataProvider.ProviderOptions()):
        super().__init__(uri)
        # Use the memory layer to parse the uri
        mlayer = QgsVectorLayer(uri, 'ml', 'memory')
        self.setNativeTypes(mlayer.dataProvider().nativeTypes())
        self._uri = uri
        self._fields = mlayer.fields()
        self._wkbType = mlayer.wkbType()
        self._features = {}
        self._extent = QgsRectangle()
        self._extent.setMinimal()
        self._subset_string = ''
        self._crs = mlayer.crs()
        self._spatialindex = None
        self._provider_options = providerOptions
        if 'index=yes'in self._uri:
            self.createSpatialIndex()

    def featureSource(self):
        return PyFeatureSource(self)

    def dataSourceUri(self, expandAuthConfig=True):
        return self._uri

    def storageType(self):
        return "Python test memory storage"

    def getFeatures(self, request=QgsFeatureRequest()):
        return QgsFeatureIterator(PyFeatureIterator(PyFeatureSource(self), request))

    def uniqueValues(self, fieldIndex, limit=1):
        results = set()
        if fieldIndex >= 0 and fieldIndex < self.fields().count():
            req = QgsFeatureRequest()
            req.setFlags(QgsFeatureRequest.NoGeometry)
            req.setSubsetOfAttributes([fieldIndex])
            for f in self.getFeatures(req):
                results.add(f.attributes()[fieldIndex])
        return results

    def wkbType(self):
        return self._wkbType

    def featureCount(self):
        if not self.subsetString():
            return len(self._features)
        else:
            req = QgsFeatureRequest()
            req.setFlags(QgsFeatureRequest.NoGeometry)
            req.setSubsetOfAttributes([])
            return len([f for f in self.getFeatures(req)])

    def fields(self):
        return self._fields

    def addFeatures(self, flist, flags=None):
        added = False
        f_added = []
        for f in flist:
            if f.hasGeometry() and (f.geometry().wkbType() != self.wkbType()):
                return added, f_added

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

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

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

        return added, f_added

    def deleteFeatures(self, ids):
        if not ids:
            return True
        removed = False
        for id in ids:
            if id in self._features:
                if self._spatialindex is not None:
                    self._spatialindex.deleteFeature(self._features[id])
                del self._features[id]
                removed = True
        if removed:
            self.clearMinMaxCache()
            self.updateExtents()
        return removed

    def addAttributes(self, attrs):
        try:
            for new_f in attrs:
                if new_f.type() not in (QVariant.Int, QVariant.Double, QVariant.String, QVariant.Date, QVariant.Time, QVariant.DateTime, QVariant.LongLong, QVariant.StringList, QVariant.List):
                    continue
                self._fields.append(new_f)
                for f in self._features.values():
                    old_attrs = f.attributes()
                    old_attrs.append(None)
                    f.setAttributes(old_attrs)
            self.clearMinMaxCache()
            return True
        except Exception:
            return False

    def renameAttributes(self, renamedAttributes):
        result = True
        # We need to replace all fields because python bindings return a copy from [] and at()
        new_fields = [self._fields.at(i) for i in range(self._fields.count())]
        for fieldIndex, new_name in renamedAttributes.items():
            if fieldIndex < 0 or fieldIndex >= self._fields.count():
                result = False
                continue
            if self._fields.indexFromName(new_name) >= 0:
                #field name already in use
                result = False
                continue
            new_fields[fieldIndex].setName(new_name)
        if result:
            self._fields = QgsFields()
            for i in range(len(new_fields)):
                self._fields.append(new_fields[i])
        return result

    def deleteAttributes(self, attributes):
        attrIdx = sorted(attributes, reverse=True)

        # delete attributes one-by-one with decreasing index
        for idx in attrIdx:
            self._fields.remove(idx)
            for f in self._features.values():
                attr = f.attributes()
                del(attr[idx])
                f.setAttributes(attr)
        self.clearMinMaxCache()
        return True

    def changeAttributeValues(self, attr_map):
        for feature_id, attrs in attr_map.items():
            try:
                f = self._features[feature_id]
            except KeyError:
                continue
            for k, v in attrs.items():
                f.setAttribute(k, v)
        self.clearMinMaxCache()
        return True

    def changeGeometryValues(self, geometry_map):
        for feature_id, geometry in geometry_map.items():
            try:
                f = self._features[feature_id]
                f.setGeometry(geometry)
            except KeyError:
                continue
        self.updateExtents()
        return True

    def allFeatureIds(self):
        return list(self._features.keys())

    def subsetString(self):
        return self._subset_string

    def setSubsetString(self, subsetString):
        if subsetString == self._subset_string:
            return True
        self._subset_string = subsetString
        self.updateExtents()
        self.clearMinMaxCache()
        self.dataChanged.emit()
        return True

    def supportsSubsetString(self):
        return True

    def createSpatialIndex(self):
        if self._spatialindex is None:
            self._spatialindex = QgsSpatialIndex()
            for f in self._features.values():
                self._spatialindex.insertFeature(f)
        return True

    def capabilities(self):
        return QgsVectorDataProvider.AddFeatures | QgsVectorDataProvider.DeleteFeatures | QgsVectorDataProvider.CreateSpatialIndex | QgsVectorDataProvider.ChangeGeometries | QgsVectorDataProvider.ChangeAttributeValues | QgsVectorDataProvider.AddAttributes | QgsVectorDataProvider.DeleteAttributes | QgsVectorDataProvider.RenameAttributes | QgsVectorDataProvider.SelectAtId | QgsVectorDataProvider. CircularGeometries

    #/* Implementation of functions from QgsDataProvider */

    def name(self):
        return self.providerKey()

    def extent(self):
        if self._extent.isEmpty() and self._features:
            self._extent.setMinimal()
            if not self._subset_string:
                # fast way - iterate through all features
                for feat in self._features.values():
                    if feat.hasGeometry():
                        self._extent.combineExtentWith(feat.geometry().boundingBox())
            else:
                for f in self.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])):
                    if f.hasGeometry():
                        self._extent.combineExtentWith(f.geometry().boundingBox())

        elif not self._features:
            self._extent.setMinimal()
        return QgsRectangle(self._extent)

    def updateExtents(self):
        self._extent.setMinimal()

    def isValid(self):
        return True

    def crs(self):
        return self._crs
示例#51
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,
                        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.isEmpty(): # 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)

            progress.setPercentage(int(current * total))
        del writer
示例#52
0
    def processAlgorithm(self, parameters, 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 = QgsPointXY(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
示例#53
0
    def processAlgorithm(self, context, feedback):
        layerA = dataobjects.getLayerFromString(
            self.getParameterValue(self.INPUT_A))
        splitLayer = dataobjects.getLayerFromString(
            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(),
            context)

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

        for aSplitFeature in QgsProcessingUtils.getFeatures(
                splitLayer, context, 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 = QgsProcessingUtils.getFeatures(layerA, context)

        if QgsProcessingUtils.featureCount(layerA, context) == 0:
            total = 100
        else:
            total = 100.0 / QgsProcessingUtils.featureCount(layerA, context)

        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 is None:
                                    splitterPList = vector.extractPoints(
                                        splitGeom)

                                try:
                                    result, newGeometries, topoTestPoints = inGeom.splitGeometry(
                                        splitterPList, False)
                                except:
                                    QgsMessageLog.logMessage(
                                        self.
                                        tr('Geometry exception while splitting'
                                           ), self.tr('Processing'),
                                        QgsMessageLog.WARNING)
                                    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
示例#54
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}
    def processAlgorithm(self, progress):
        layer = dataobjects.getObjectFromUri(
            self.getParameterValue(self.VECTOR))
        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, QGis.WKBPoint, layer.crs())

        da = QgsDistanceArea()

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

            if strategy == 0 and pointCount == 0:
                continue

            index = QgsSpatialIndex()
            points = dict()

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

            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
                    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.'))

            progress.setPercentage(0)

        del writer
示例#56
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.fromPointXY(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}
示例#57
0
    def run(self):
        """Risk plugin for classified polygon hazard on land cover.

        Counts area of land cover types exposed to hazard zones.

        :returns: Impact layer
        :rtype: Vector
        """

        # Identify hazard and exposure layers
        hazard = self.hazard.layer
        exposure = self.exposure.layer

        type_attr = self.exposure.keyword('field')

        self.hazard_class_attribute = self.hazard.keyword('field')
        hazard_value_to_class = {}
        self.hazard_class_mapping = self.hazard.keyword('value_map')
        for key, values in self.hazard_class_mapping.items():
            for value in values:
                hazard_value_to_class[value] = self.hazard_columns[key]

        # prepare objects for re-projection of geometries
        crs_wgs84 = QgsCoordinateReferenceSystem('EPSG:4326')
        hazard_to_exposure = QgsCoordinateTransform(hazard.crs(),
                                                    exposure.crs())
        wgs84_to_hazard = QgsCoordinateTransform(crs_wgs84, hazard.crs())
        wgs84_to_exposure = QgsCoordinateTransform(crs_wgs84, exposure.crs())

        extent = QgsRectangle(self.requested_extent[0],
                              self.requested_extent[1],
                              self.requested_extent[2],
                              self.requested_extent[3])
        extent_hazard = wgs84_to_hazard.transformBoundingBox(extent)
        extent_exposure = wgs84_to_exposure.transformBoundingBox(extent)
        extent_exposure_geom = QgsGeometry.fromRect(extent_exposure)

        # make spatial index of hazard
        hazard_index = QgsSpatialIndex()

        hazard_features = {}
        for f in hazard.getFeatures(QgsFeatureRequest(extent_hazard)):
            f.geometry().transform(hazard_to_exposure)
            hazard_index.insertFeature(f)
            hazard_features[f.id()] = QgsFeature(f)

        # create impact layer
        filename = unique_filename(suffix='.shp')
        impact_fields = exposure.dataProvider().fields()
        impact_fields.append(QgsField(self.target_field, QVariant.String))
        writer = QgsVectorFileWriter(filename, 'utf-8', impact_fields,
                                     QGis.WKBPolygon, exposure.crs())

        # Iterate over all exposure polygons and calculate the impact.
        _calculate_landcover_impact(exposure, extent_exposure,
                                    extent_exposure_geom,
                                    self.hazard_class_attribute,
                                    hazard_features, hazard_index,
                                    hazard_value_to_class, impact_fields,
                                    writer)

        del writer
        impact_layer = QgsVectorLayer(filename, 'Impacted Land Cover', 'ogr')

        if impact_layer.featureCount() == 0:
            raise ZeroImpactException()

        zone_field = None
        if self.aggregator:
            zone_field = self.aggregator.exposure_aggregation_field

        # This is not the standard way to use mixins
        # Martin preferred to call it directly - normally it is called with
        # multiple inheritance. Thats ok but we need to monkey patch the
        # notes function as it is not overloaded by this class
        mixin = LandCoverReportMixin(
            question=self.question,
            impact_layer=impact_layer,
            target_field=self.target_field,
            ordered_columns=self.hazard_columns.values(),
            affected_columns=self.affected_hazard_columns,
            land_cover_field=type_attr,
            zone_field=zone_field)

        mixin.notes = self.notes
        impact_data = mixin.generate_data()

        # Define style for the impact layer
        style_classes = [
            dict(label=self.hazard_columns['low'],
                 value=self.hazard_columns['low'],
                 colour='#acffb6',
                 border_color='#000000',
                 transparency=0,
                 size=0.5),
            dict(label=self.hazard_columns['medium'],
                 value=self.hazard_columns['medium'],
                 colour='#ffe691',
                 border_color='#000000',
                 transparency=0,
                 size=0.5),
            dict(label=self.hazard_columns['high'],
                 value=self.hazard_columns['high'],
                 colour='#F31A1C',
                 border_color='#000000',
                 transparency=0,
                 size=0.5),
        ]
        style_info = dict(target_field=self.target_field,
                          style_classes=style_classes,
                          style_type='categorizedSymbol')

        extra_keywords = {
            'map_title': self.map_title(),
            'target_field': self.target_field
        }

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Create vector layer and return
        impact_layer = Vector(data=impact_layer,
                              name=self.map_title(),
                              keywords=impact_layer_keywords,
                              style_info=style_info)

        impact_layer.impact_data = impact_data
        self._impact = impact_layer
        return impact_layer
示例#58
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())
        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.fromPoint(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}
示例#59
0
    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        line_source = self.parameterAsSource(parameters, self.LINES, context)

        sameLayer = parameters[self.INPUT] == parameters[self.LINES]

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

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

        for aSplitFeature in line_source.getFeatures(request):
            if feedback.isCanceled():
                break

            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 = source.getFeatures()

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

        for current, inFeatA in enumerate(features):
            if feedback.isCanceled():
                break

            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:
                            if feedback.isCanceled():
                                break

                            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 is None:
                                    splitterPList = vector.extractPoints(
                                        splitGeom)

                                try:
                                    result, newGeometries, topoTestPoints = inGeom.splitGeometry(
                                        splitterPList, False)
                                except:
                                    feedback.reportError(
                                        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:
                if feedback.isCanceled():
                    break

                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))
                sink.addFeature(outFeat, QgsFeatureSink.FastInsert)

            feedback.setProgress(int(current * total))
        return {self.OUTPUT: dest_id}
示例#60
0
    def run(self):
        """Risk plugin for classified polygon hazard on polygon population.

        Counts population in an area exposed to hazard zones and then
        computes the proportion of each area that is affected.
        The population in each area is then calculated as the proportion
        of the original population to the affected area.

        :returns: Impact layer
        :rtype: Vector
        """
        self.validate()
        self.prepare()

        self.provenance.append_step(
            'Calculating Step',
            'Impact function is calculating the impact.')

        # Identify hazard and exposure layers
        hazard = self.hazard.layer
        exposure = self.exposure.layer

        # prepare objects for re-projection of geometries
        crs_wgs84 = QgsCoordinateReferenceSystem("EPSG:4326")
        hazard_to_exposure = QgsCoordinateTransform(
            hazard.crs(), exposure.crs())
        wgs84_to_hazard = QgsCoordinateTransform(
            crs_wgs84, hazard.crs())
        wgs84_to_exposure = QgsCoordinateTransform(
            crs_wgs84, exposure.crs())

        extent = QgsRectangle(
            self.requested_extent[0], self.requested_extent[1],
            self.requested_extent[2], self.requested_extent[3])
        extent_hazard = wgs84_to_hazard.transformBoundingBox(extent)
        extent_exposure = wgs84_to_exposure.transformBoundingBox(extent)
        extent_exposure_geom = QgsGeometry.fromRect(extent_exposure)

        # make spatial index of hazard
        hazard_index = QgsSpatialIndex()
        hazard_features = {}
        for feature in hazard.getFeatures(QgsFeatureRequest(extent_hazard)):
            feature.geometry().transform(hazard_to_exposure)
            hazard_index.insertFeature(feature)
            hazard_features[feature.id()] = QgsFeature(feature)

        # create impact layer
        filename = unique_filename(suffix='.shp')
        impact_fields = exposure.dataProvider().fields()
        impact_fields.append(QgsField(self.target_field, QVariant.Int))
        unaffected_fields = exposure.dataProvider().fields()
        unaffected_fields.append(QgsField(self.target_field, QVariant.Int))

        writer = QgsVectorFileWriter(
            filename, "utf-8", impact_fields, QGis.WKBPolygon, exposure.crs())

        # Evaluating the impact
        self.evaluate_impact(
            exposure,
            extent_exposure,
            extent_exposure_geom,
            hazard_index,
            hazard_features,
            writer,
            unaffected_fields,
            impact_fields)

        del writer
        impact_layer = QgsVectorLayer(filename, "Impacted People", "ogr")

        # Generate the report of affected populations in the areas
        # To avoid Null
        for value in self.all_areas_population.values():
            if isinstance(value, QPyNullVariant):
                value = 0
            self.total_population += value
        self.areas = self.all_areas_ids
        self.affected_areas = self.all_affected_areas
        self.areas_population = self.all_areas_population

        # Calculating number of people affected
        # This will help area report mixin to know how
        # to calculate the all row values before other
        # rows values in the report table

        self.evaluate_affected_people()

        impact_summary = self.html_report()

        # Define style for the impact layer
        transparent_color = QColor()
        transparent_color.setAlpha(0)

        # Retrieve the classification that is used by the hazard layer.
        vector_hazard_classification = self.hazard.keyword(
            'vector_hazard_classification')
        # Get the dictionary that contains the definition of the classification
        vector_hazard_classification = definition(vector_hazard_classification)
        # Get the list classes in the classification
        vector_hazard_classes = vector_hazard_classification['classes']

        classes = self.hazard_class_mapping

        classes_colours = {}

        color_mapping = {
            'wet': '#F31A1C',
            'low': '#1EFC7C',
            'medium': '#FFA500',
            'high': '#F31A1C'
            }
        classes_values = {
            'wet': 1,
            'low': 1,
            'medium': 2,
            'high': 3
        }
        # Assigning colors
        for vector_hazard_class in vector_hazard_classes:
            key = vector_hazard_class['key']
            if key in classes.keys() and key in color_mapping.keys():
                classes_colours[key] = color_mapping[key]

        # Define style info for output polygons showing population counts
        style_classes = []
        index = 0
        for class_key, colour in classes_colours.items():
            style_class = dict()
            if class_key in classes.keys():
                label = classes[class_key][0]
            else:
                continue
            transparency = 0
            style_class['label'] = label
            style_class['value'] = classes_values[class_key]
            style_class['colour'] = colour
            style_class['transparency'] = transparency
            style_classes.append(style_class)

            index = index + 1

        style_info = dict(
            target_field=self.target_field,
            style_classes=style_classes,
            style_type='categorizedSymbol')

        extra_keywords = {
            'impact_summary': impact_summary,
            'target_field': self.target_field,
            'map_title': tr('Affected People'),
        }

        self.set_if_provenance()

        impact_layer_keywords = self.generate_impact_keywords(extra_keywords)

        # Create vector layer and return
        impact_layer = Vector(
            data=impact_layer,
            name=tr('People affected by each hazard zone'),
            keywords=impact_layer_keywords,
            style_info=style_info)

        self._impact = impact_layer
        return impact_layer