def getIntersectingFeatures(inputPath,
                            inputPath2,
                            outputPath,
                            minIntersectionPercent=1,
                            minAreaOfInput2Features=0):
    """
	Puts feature from input1 in output, if it has a intersecting feature with input2.

	:param inputPath:
	:type inputPath: str
	:param inputPath2:
	:type inputPath2: str
	:param outputPath:
	:param minAreaOfInput2Features: need for too small houses like garden houses
	:type minAreaOfInput2Features: float | int
	:param minIntersectionPercent:
	:type minIntersectionPercent: float | int
	"""
    minIntersectionPercent /= 100.
    vectorDataSource = ogr.Open(inputPath,
                                gdal.GA_ReadOnly)  # type: ogr.DataSource
    vectorLayer = vectorDataSource.GetLayerByIndex(0)  # type: ogr.Layer

    vectorDataSource2 = ogr.Open(inputPath2,
                                 gdal.GA_ReadOnly)  # type: ogr.DataSource
    vectorLayer2 = vectorDataSource2.GetLayerByIndex(0)  # type: ogr.Layer

    # create output shape file
    deleteFile(outputPath)
    outputDriver = vectorDataSource.GetDriver()
    outputDataSource = outputDriver.CreateDataSource(
        outputPath)  # type: ogr.DataSource
    outputLayer = outputDataSource.CreateLayer(
        "intersecting",
        srs=vectorLayer.GetSpatialRef(),
        geom_type=vectorLayer.GetGeomType())

    for feature1 in vectorLayer:  # type: ogr.Feature
        geom1 = feature1.geometry()  # type: ogr.Geometry
        areaOfIntersectingGeometries = 0
        vectorLayer2.SetSpatialFilter(geom1)
        for feature2 in vectorLayer2:  # type: ogr.Feature
            geom2 = feature2.geometry()  # type: ogr.Geometry
            if geom2.Area() > minAreaOfInput2Features:
                if geom1.Intersects(geom2):
                    areaOfIntersectingGeometries += geom1.Intersection(
                        geom2).Area()
        if areaOfIntersectingGeometries / geom1.Area(
        ) > minIntersectionPercent:
            outputLayer.CreateFeature(feature1.Clone())

    # save and cleanup
    outputDataSource.SyncToDisk()
    outputDataSource = None
    vectorDataSource = None
    vectorDataSource2 = None
Example #2
0
	def getPlantsAtCadastre(self, savePath, cadastrePolygonsPath, plantsMaskPath, distanceBetweenPoints=1, threshold=1):
		"""
		Creates plants at cadastre borders.

		Note: createPointsAlongLines uses qgis functionality, so there is dependency to qgis.

		:param savePath:
		:param cadastrePolygonsPath:
		:param plantsMaskPath:
		:param distanceBetweenPoints:
		:param threshold:
		"""
		filePathWithoutExtension, fileExtension = os.path.splitext(savePath)

		# Shrink to avoid overlapping borders
		polygonsBufferedPath = filePathWithoutExtension + "_bufferedPolygons.shp"
		createBuffers(
			inputPath=cadastrePolygonsPath,
			outputPath=polygonsBufferedPath,
			buffer=-0.5,
			outputFormat="ESRI Shapefile"
		)

		# Convert polygons to lines
		linesPath = filePathWithoutExtension + "_lines.shp"
		convertPolygonsToLines(polygonsBufferedPath, linesPath)

		# Creating points along lines
		# todo: dont use qgis functionality here
		pointsPath = filePathWithoutExtension + "_points.shp"
		createPointsAlongLines(
			inputPath=linesPath,
			outputPath=pointsPath,
			distanceBetweenPoints=distanceBetweenPoints
		)

		# Removing points where no vegetation is
		rasterDataSet = gdal.Open(plantsMaskPath)
		rasterData = np.array(rasterDataSet.ReadAsArray(), dtype=np.float16)
		rasterGeoTransform = rasterDataSet.GetGeoTransform()
		rasterDataSet = None
		getPointsGreaterThanThresholdInRasterImage(
			outputPath=savePath,
			vectorPath=pointsPath,
			rasterData=rasterData,
			rasterGeoTransform=rasterGeoTransform,
			pixelRadius=5,
			threshold=threshold
		)

		# clean up
		deleteFile(polygonsBufferedPath)
		# deleteFile(linesPath)
		deleteFile(pointsPath)
def convertPolygonsToLines(inputPath, outputPath):
    """
	Converts polygons of inputPath file to lines and saves at outputPath.
	Fields and Attributes will also be saved.
	Note: No multipolygon support right now.

	:type inputPath: str
	:type outputPath: str
	"""
    inputDataSource = ogr.Open(inputPath)  # type: ogr.DataSource
    inputLayer = inputDataSource.GetLayerByIndex(0)  # type: ogr.Layer

    # create output shape file
    deleteFile(outputPath)
    outputDriver = inputDataSource.GetDriver()
    outputDataSource = outputDriver.CreateDataSource(
        outputPath)  # type: ogr.DataSource

    outputLayer = outputDataSource.CreateLayer("lines",
                                               srs=inputLayer.GetSpatialRef(),
                                               geom_type=ogr.wkbLineString)

    # create attribute fields
    firstFeature = inputLayer.GetNextFeature(
    )  # read first feature to get attributes
    if firstFeature is not None:
        for i in range(firstFeature.GetFieldCount()):
            fieldDef = firstFeature.GetFieldDefnRef(i)
            outputLayer.CreateField(fieldDef)

        inputLayer.ResetReading()
        for feature in inputLayer:  # type: ogr.Feature
            # copy attributes
            outputFeature = ogr.Feature(inputLayer.GetLayerDefn())
            for fieldId in range(0, feature.GetFieldCount()):
                outputFeature.SetField2(fieldId, feature.GetField(fieldId))
            # create geometry
            if feature.geometry() is None:
                continue
            geom = feature.geometry().GetGeometryRef(0)  # type: ogr.Geometry
            if geom is not None and geom.GetPointCount() > 0:
                line = ogr.Geometry(ogr.wkbLinearRing)
                for i in range(0, geom.GetPointCount()):
                    x, y = geom.GetPoint_2D(i)
                    line.AddPoint_2D(x, y)
                outputFeature.SetGeometry(line)
                outputLayer.CreateFeature(outputFeature)

    # save and cleanup
    outputDataSource.SyncToDisk()
    outputDataSource = None
    inputDataSource = None
def convertLinesToPolygons(inputPath, outputPath):
    """
	Converts lines of inputPath file to polygons and saves at outputPath.
	Fields and Attributes will also be saved.

	:type inputPath: str
	:type outputPath: str
	"""
    inputDataSource = ogr.Open(inputPath)  # type: ogr.DataSource
    inputLayer = inputDataSource.GetLayerByIndex(0)  # type: ogr.Layer

    # create output shape file
    deleteFile(outputPath)
    outputDriver = inputDataSource.GetDriver()
    outputDataSource = outputDriver.CreateDataSource(
        outputPath)  # type: ogr.DataSource

    outputLayer = outputDataSource.CreateLayer("polygons",
                                               srs=inputLayer.GetSpatialRef(),
                                               geom_type=ogr.wkbPolygon)

    # create attribute fields
    firstFeature = inputLayer.GetNextFeature(
    )  # read first feature to get attributes
    if firstFeature is not None:
        for i in range(firstFeature.GetFieldCount()):
            fieldDef = firstFeature.GetFieldDefnRef(i)
            outputLayer.CreateField(fieldDef)

        inputLayer.ResetReading()
        for feature in inputLayer:  # type: ogr.Feature
            # copy attributes
            outputFeature = ogr.Feature(inputLayer.GetLayerDefn())
            for fieldId in range(0, feature.GetFieldCount()):
                outputFeature.SetField2(fieldId, feature.GetField(fieldId))
            # create geometry
            geom = feature.geometry()  # type: ogr.Geometry
            if geom.IsRing():
                outputGeom = ogr.Geometry(ogr.wkbPolygon)
                ring = ogr.Geometry(ogr.wkbLinearRing)
                for i in range(0, geom.GetPointCount()):
                    x, y = geom.GetPoint_2D(i)
                    ring.AddPoint_2D(x, y)
                outputGeom.AddGeometry(ring)
                outputFeature.SetGeometry(outputGeom)
                outputLayer.CreateFeature(outputFeature)

    # save and cleanup
    outputDataSource.SyncToDisk()
    outputDataSource = None
    inputDataSource = None
def convertToEPSG(inputPath, outputPath, outputFormat="GeoJSON", toEPSG=25832):
    """
	Converts the given input path to the given EPSG and saves it in outputPath.

	:param inputPath:
	:type inputPath: str
	:param outputPath:
	:type outputPath: str
	:param outputFormat: ogr2ogr output format http://www.gdal.org/ogr2ogr.html
	:type outputFormat: str
	:param toEPSG:
	:type toEPSG: int
	"""
    deleteFile(outputPath)
    subprocess.call([
        "ogr2ogr", "-f", outputFormat, "-t_srs",
        "EPSG:%d" % toEPSG, outputPath, inputPath
    ],
                    startupinfo=getSubprocessStartUpInfo())
Example #6
0
def convertRasterToVectorPolygons(dataPath, savePath, returnDataSource=False):
    """
	Creates a vector shp file from given image file.

	It must be a saved image because gdals polygonize will only operate with GDALRasterBandShadow.

	:param dataPath: path where image to convert is.
	:type dataPath: str
	:param savePath: where shape file will be saved (ending .shp)
	:type savePath: str
	:param returnDataSource: if True, the shape file data source will be returned, else it will be closed
	:type returnDataSource: bool

	:return:
	:rtype: ogr.DataSource
	"""
    dataSet = gdal.Open(dataPath, gdal.GA_ReadOnly)
    vectorDriver = ogr.GetDriverByName("ESRI Shapefile")  # type: ogr.Driver
    deleteFile(savePath)
    dataSource = vectorDriver.CreateDataSource(
        savePath)  # type: ogr.DataSource
    srs = osr.SpatialReference()
    srs.ImportFromWkt(dataSet.GetProjection())
    layer = dataSource.CreateLayer("polygonize", srs=srs)  # type: ogr.Layer

    # create feature with attribute "DN", where polygonize will write in the original color a polygon was created from
    fieldName = 'DN'
    fd = ogr.FieldDefn(fieldName, ogr.OFTInteger)
    layer.CreateField(fd)
    fieldId = 0

    gdal.Polygonize(dataSet.GetRasterBand(1),
                    None,
                    layer,
                    fieldId,
                    callback=None)

    dataSet = None
    if returnDataSource is True:
        return dataSource
    else:
        dataSource = None
def CopyExtentandEPSG(EEPSG, noEEPSG, targetPath):
    """
	Copy extent and EPSG from input raster to output raster
	"""

    i = 0
    while i < 2:
        source_extent = gdal.Open(EEPSG, GA_ReadOnly)
        target_extent = gdal.Open(noEEPSG, GA_Update)

        target_extent.SetGeoTransform(source_extent.GetGeoTransform())
        i = i + 1

    subprocess.call(
        'gdalwarp ' + noEEPSG + ' ' + targetPath +
        ' -t_srs "+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"'
    )

    # cleanup
    target_extent = None
    deleteFile(noEEPSG)
def createBuffers(inputPath, outputPath, outputFormat="GeoJSON", buffer=1):
    """
	Buffers input data.

	:param inputPath: path to polygon vector layer
	:type inputPath: str
	:param outputPath: path where raster will be saved
	:type outputPath: str
	:param buffer: buffer amount in epsg units
	:type buffer: float
	"""

    inputDataSource = ogr.Open(inputPath)  # type: ogr.DataSource
    inputLayer = inputDataSource.GetLayerByIndex(0)  # type: ogr.Layer
    layerName = inputLayer.GetName()
    inputDataSource = None
    deleteFile(outputPath)
    subprocess.call([
        "ogr2ogr", "-dialect", "sqlite", "-f", outputFormat, "-sql",
        "SELECT ST_Buffer( geometry , " + str(buffer) + " ),* FROM '" +
        layerName + "' ", outputPath, inputPath
    ],
                    startupinfo=getSubprocessStartUpInfo())
def getPointsGreaterThanThresholdInRasterImage(outputPath,
                                               vectorPath,
                                               rasterData,
                                               rasterGeoTransform,
                                               pixelRadius=5,
                                               threshold=0):
    """
	Samples rasterData with given points of a vector file and looks if these samples are higher than a given threshold.

	For each point in the vectorPath file do:
		- get position of point in the rasterData
		- at this position create a window with the pixelRadius
		- calculate the mean of all pixels in this window
		- if this mean is create than the given threshold, the point of the vectorPath file will be copied to output file

	:param outputPath:
	:type outputPath: str
	:param vectorPath: path to point vector data
	:type vectorPath: str
	:param rasterData:
	:type rasterData: np.ndarray
	:param rasterGeoTransform:
	:type rasterGeoTransform: tuple
	:param pixelRadius:
	:type pixelRadius: int
	:param threshold:
	:type threshold:
	"""
    vectorDataSource = ogr.Open(vectorPath,
                                gdal.GA_Update)  # type: ogr.DataSource
    vectorLayer = vectorDataSource.GetLayerByIndex(0)  # type: ogr.Layer

    # create output shape file
    deleteFile(outputPath)
    outputDriver = vectorDataSource.GetDriver()
    outputDataSource = outputDriver.CreateDataSource(
        outputPath)  # type: ogr.DataSource
    outputLayer = outputDataSource.CreateLayer("points",
                                               srs=vectorLayer.GetSpatialRef(),
                                               geom_type=ogr.wkbPoint)

    for feature in vectorLayer:  # type: ogr.Feature
        xCoord, yCoord = feature.geometry().GetPoint_2D(0)
        xRasterPos, yRasterPos = coord2pixel(rasterGeoTransform, xCoord,
                                             yCoord)
        if 0 <= xRasterPos < rasterData.shape[
                1] and 0 <= yRasterPos < rasterData.shape[0]:
            imageCutout = rasterData[yRasterPos - pixelRadius:yRasterPos +
                                     pixelRadius,
                                     xRasterPos - pixelRadius:xRasterPos +
                                     pixelRadius]  # type: np.ndarray
            mean = imageCutout.mean()
            if mean >= threshold:
                outputLayer.CreateFeature(feature.Clone())
            # else:
            # 	vectorLayer.DeleteFeature(feature.GetFID())

    # save and cleanup
    outputDataSource.SyncToDisk()
    outputDataSource = None
    vectorDataSource = None
def getVectorDataFromWFS(url,
                         layerName,
                         extent,
                         outputPath,
                         outputFormat="GeoJSON",
                         epsg=25832,
                         append=False,
                         attributeFilter=""):
    """
	Creates vector file from given WFS.
	If too many features (>10000) are requested, then the extent will be split up, so the features per extent decreases.
	This is done recursively. Because features can overlap at extent borders, the file will be searched for duplicates.
	These will be removed.

	:param url: url to WFS
	:type url: str
	:param layerName: name of the layer in the WFS which should be downloaded
	:type layerName: str
	:param extent: (minX, minY, maxX, maxY)
	:type extent: tuple[float, float, float, float]
	:param outputPath: save path
	:type outputPath: str
	:param outputFormat: ogr output format string like "GeoJSON" or "ESRI Shapefile", NOTE: the output format should
						allow appending data!
	:type outputFormat: str
	:param epsg: target epsg (in which extent is)
	:type epsg: int
	:param append: if True, the data will append to the output file
	:type append: bool
	:param attributeFilter: filtering of attributes with SQL WHERE like "Amtlicheflaeche > '300' AND Amtlicheflaeche < '2000'"
	:type attributeFilter: str
	"""
    MAX_FEATURE_COUNT = 9999999  # splitting not working anymore, don't know why, maybe its the server:
    # ERROR 1: Layer tlvermgeo:ALKIS_GESAMT_FKZ not found, and CreateLayer not supported by driver.
    # so data will now be caped at 10000

    if not append:
        deleteFile(outputPath)

    # check how many features we want (we can only get 10000)
    wfsDriver = ogr.GetDriverByName('WFS')
    wfs = wfsDriver.Open("WFS:" + url)  # type: ogr.DataSource
    wfsLayer = wfs.GetLayerByName(layerName)  # type: ogr.Layer
    minX = extent[0]
    minY = extent[1]
    maxX = extent[2]
    maxY = extent[3]
    extentWkt = "POLYGON ((" + str(minX) + " " + str(minY) + "," \
                   "" + str(minX) + " " + str(maxY) + ", " \
                           "" + str(
     maxX) + " " + str(maxY) + ", " \
             "" + str(maxX) + " " + str(minY) + "," \
                     "" + str(minX) + " " + str(minY) + "))"
    wfsLayer.SetSpatialFilter(ogr.CreateGeometryFromWkt(extentWkt))
    wfsLayer.SetAttributeFilter(attributeFilter)
    featureCount = wfsLayer.GetFeatureCount()
    if featureCount > MAX_FEATURE_COUNT:  # is maximal number of features exceeded, than split extent in 4 parts
        print "Too many features in WFS request %d, splitting up extent" % featureCount
        filePathWithoutExtension, fileExtension = os.path.splitext(outputPath)
        tempPath = filePathWithoutExtension + "_temp" + fileExtension

        wfs = None
        halfWidth = (maxX - minX) / 2
        halfHeight = (maxY - minY) / 2
        # lower left
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX, minY, minX + halfWidth,
                                     minY + halfHeight),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # lower right
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX + halfWidth, minY, maxX,
                                     minY + halfHeight),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # upper left
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX, minY + halfHeight, minX + halfWidth,
                                     maxY),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # upper right
        getVectorDataFromWFS(url,
                             layerName=layerName,
                             extent=(minX + halfWidth, minY + halfHeight, maxX,
                                     maxY),
                             outputPath=tempPath,
                             outputFormat=outputFormat,
                             append=True,
                             attributeFilter=attributeFilter)
        # remove duplicate entries from overlapping bounds
        tempDataSource = ogr.Open(tempPath)  # type: ogr.DataSource
        tempLayer = tempDataSource.GetLayer()  # type: ogr.Layer
        geometries = []
        for feature in tempLayer:  # type: ogr.Feature
            geometries.append(feature.geometry().ExportToWkt())

        uniqueGeometriesWkt = [
            attribute for attribute, count in Counter(geometries).items()
            if count > 1
        ]

        # create final output file and add unique features
        outputDriver = ogr.GetDriverByName(outputFormat)
        outputDataSource = outputDriver.CreateDataSource(
            outputPath)  # type: ogr.DataSource
        outputLayer = outputDataSource.CreateLayer(
            "cadastre",
            srs=tempLayer.GetSpatialRef(),
            geom_type=tempLayer.GetGeomType())  # type: ogr.Layer
        tempLayer.ResetReading()
        for feature in tempLayer:  # type: ogr.Feature
            geomWkt = feature.geometry().ExportToWkt()
            if geomWkt in uniqueGeometriesWkt:
                uniqueGeometriesWkt.remove(geomWkt)
                outputLayer.CreateFeature(feature.Clone())
        outputDataSource = None
        tempDataSource = None
        deleteFile(tempPath)
        return
    wfs = None
    subprocess.call([
        "ogr2ogr", "-f", outputFormat, "-t_srs",
        "EPSG:%d" % epsg, "-spat",
        str(extent[0]),
        str(extent[1]),
        str(extent[2]),
        str(extent[3]), outputPath, "WFS:" + url, "-append", "-where",
        attributeFilter, layerName
    ],
                    startupinfo=getSubprocessStartUpInfo())
def createLayer(geomType,
                name,
                memType="memory",
                deleteOldLayerFile=False,
                crs=25832,
                path=None,
                driverName="ESRI Shapefile"):
    """
	Creates a QGIS layer and adds the layer.

	:param geomType: geometry type, valid values: 'polygon', 'linestring', 'point'
	:type geomType: str
	:param name: name of the layer
	:type name: str
	:param memType: 'memory' for layer in memory or 'ogr' for shape file on disk in temp folder
	:type memType: str
	:param deleteOldLayerFile: if True, temporary data will be deleted first
	:type deleteOldLayerFile: bool
	:param crs: epsg id of coordinate reference system
	:type crs: int

	:rtype: QgsVectorLayer
	"""
    geomType = geomType.lower()
    memType = memType.lower()
    removeMapLayersByName(name)
    if memType == "memory":
        layer = QgsVectorLayer(geomType + "?crs=epsg:" + str(crs), name,
                               memType)
    elif memType == "ogr":
        if path is None:
            if driverName == "GeoJSON":
                path = getPathToTempFile(name + ".geojson")
            else:
                path = getPathToTempFile(name + ".shp")
        if QFileInfo(path).exists() is False or deleteOldLayerFile is True:
            if deleteOldLayerFile is True:
                deleteFile(path)
            # deleteFilesContainingName(name)

            if geomType == "polygon":
                geomType = QGis.WKBPolygon
            elif geomType == "linestring":
                geomType = QGis.WKBLineString
            elif geomType == "point":
                geomType = QGis.WKBPoint
            else:
                raise NotImplementedError(
                    "Only polygon, linestring and point support for now, not "
                    + memType)

            fields = QgsFields()
            fields.append(QgsField("id", QVariant.Int))
            writer = QgsVectorFileWriter(path, "CP1250", fields, geomType,
                                         QgsCoordinateReferenceSystem(crs),
                                         driverName)
            print writer.errorMessage()
            del writer
        else:
            print "Using existing file: " + path
        layer = QgsVectorLayer(path, name, "ogr")
    else:
        raise TypeError("MemoryType not found")
    return layer