Skip to content
Permalink
Browse files
[FEATURE] New algorithm for creating vector layer from raster layer's…
… extent

Allows creation of a new vector layer with a single feature containing
a raster layer's extent. Previously this was only possible for
vector layers.
  • Loading branch information
nyalldawson committed Aug 30, 2017
1 parent 12e69d0 commit 44e7f33
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 1 deletion.
@@ -402,12 +402,14 @@ qgis:polygoncentroids: >

NOTE: This algorithm is deprecated and the generic "centroids" algorithm (which works for line and multi geometry layers) should be used instead.


qgis:polygonfromlayerextent: >
This algorithm takes a vector layer and generates a new one with the minimum bounding box (rectangle with N-S orientation) that covers all the input features.

As an alternative, the output layer can contain not just a single bounding box, but one for each input feature, representing the bounding box of each of them.

qgis:polygonfromrasterextent: >
This algorithm takes a raster layer and generates a vector layer containing a feature with the minimum bounding box that covers the raster layer's extent.

qgis:polygonize: >
This algorithm takes a lines layer and creates a polygon layer, with polygons generated from the lines in the input layer.

@@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
ExtentFromRasterLayer.py
---------------------
Date : August 2017
Copyright : (C) 2017 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""

__author__ = 'Nyall Dawson'
__date__ = 'August 2017'
__copyright__ = '(C) 2017, Nyall Dawson'

# This will get replaced with a git SHA1 when you do a git archive

__revision__ = '$Format:%H$'

import os

from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QVariant

from qgis.core import (QgsField,
QgsFeatureSink,
QgsPointXY,
QgsGeometry,
QgsFeature,
QgsWkbTypes,
QgsProcessing,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterFeatureSink,
QgsFields)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]


class ExtentFromRasterLayer(QgisAlgorithm):

INPUT = 'INPUT'
OUTPUT = 'OUTPUT'

def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'layer_extent.png'))

def tags(self):
return self.tr('extent,envelope,bounds,bounding,boundary,layer').split(',')

def group(self):
return self.tr('Raster tools')

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT, self.tr('Input layer')))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extent'), type=QgsProcessing.TypeVectorPolygon))

def name(self):
return 'polygonfromrasterextent'

def displayName(self):
return self.tr('Polygon from raster extent')

def processAlgorithm(self, parameters, context, feedback):
raster = self.parameterAsRasterLayer(parameters, self.INPUT, context)

fields = QgsFields()
fields.append(QgsField('MINX', QVariant.Double))
fields.append(QgsField('MINY', QVariant.Double))
fields.append(QgsField('MAXX', QVariant.Double))
fields.append(QgsField('MAXY', QVariant.Double))
fields.append(QgsField('CNTX', QVariant.Double))
fields.append(QgsField('CNTY', QVariant.Double))
fields.append(QgsField('AREA', QVariant.Double))
fields.append(QgsField('PERIM', QVariant.Double))
fields.append(QgsField('HEIGHT', QVariant.Double))
fields.append(QgsField('WIDTH', QVariant.Double))

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, raster.crs())

self.layerExtent(raster, sink, feedback)

return {self.OUTPUT: dest_id}

def layerExtent(self, raster, sink, feedback):
rect = raster.extent()
geometry = QgsGeometry.fromRect(rect)
minx = rect.xMinimum()
miny = rect.yMinimum()
maxx = rect.xMaximum()
maxy = rect.yMaximum()
height = rect.height()
width = rect.width()
cntx = minx + width / 2.0
cnty = miny + height / 2.0
area = width * height
perim = 2 * width + 2 * height

feat = QgsFeature()
feat.setGeometry(geometry)
attrs = [
minx,
miny,
maxx,
maxy,
cntx,
cnty,
area,
perim,
height,
width,
]
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
@@ -70,6 +70,7 @@
from .ExportGeometryInfo import ExportGeometryInfo
from .ExtendLines import ExtendLines
from .ExtentFromLayer import ExtentFromLayer
from .ExtentFromRasterLayer import ExtentFromRasterLayer
from .ExtractNodes import ExtractNodes
from .ExtractSpecificNodes import ExtractSpecificNodes
from .FieldPyculator import FieldsPyculator
@@ -222,6 +223,7 @@ def getAlgs(self):
ExportGeometryInfo(),
ExtendLines(),
ExtentFromLayer(),
ExtentFromRasterLayer(),
ExtractNodes(),
ExtractSpecificNodes(),
FieldsCalculator(),
@@ -0,0 +1,66 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>raster_extent</Name>
<ElementPath>raster_extent</ElementPath>
<!--POLYGON-->
<GeometryType>3</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>1</FeatureCount>
<ExtentXMin>18.66630</ExtentXMin>
<ExtentXMax>18.70360</ExtentXMax>
<ExtentYMin>45.77670</ExtentYMin>
<ExtentYMax>45.81170</ExtentYMax>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>MINX</Name>
<ElementPath>MINX</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>MINY</Name>
<ElementPath>MINY</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>MAXX</Name>
<ElementPath>MAXX</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>MAXY</Name>
<ElementPath>MAXY</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>CNTX</Name>
<ElementPath>CNTX</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>CNTY</Name>
<ElementPath>CNTY</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>AREA</Name>
<ElementPath>AREA</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>PERIM</Name>
<ElementPath>PERIM</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>HEIGHT</Name>
<ElementPath>HEIGHT</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>WIDTH</Name>
<ElementPath>WIDTH</ElementPath>
<Type>Real</Type>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>18.6662979442</gml:X><gml:Y>45.7767014376</gml:Y></gml:coord>
<gml:coord><gml:X>18.7035979442</gml:X><gml:Y>45.8117014376</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:raster_extent fid="raster_extent.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>18.6662979442,45.7767014376 18.7035979442,45.7767014376 18.7035979442,45.8117014376 18.6662979442,45.8117014376 18.6662979442,45.7767014376</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:MINX>18.6662979442</ogr:MINX>
<ogr:MINY>45.7767014376</ogr:MINY>
<ogr:MAXX>18.7035979442</ogr:MAXX>
<ogr:MAXY>45.8117014376</ogr:MAXY>
<ogr:CNTX>18.6849479442</ogr:CNTX>
<ogr:CNTY>45.7942014376</ogr:CNTY>
<ogr:AREA>0.00130549999999981</ogr:AREA>
<ogr:PERIM>0.14459999999999</ogr:PERIM>
<ogr:HEIGHT>0.0349999999999966</ogr:HEIGHT>
<ogr:WIDTH>0.0372999999999983</ogr:WIDTH>
</ogr:raster_extent>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -3228,3 +3228,14 @@ tests:
OUTPUT:
name: expected/execute_sql.gml
type: vector

- algorithm: qgis:polygonfromrasterextent
name: Polygon from raster extent
params:
INPUT:
name: dem.tif
type: raster
results:
OUTPUT:
name: expected\raster_extent.gml
type: vector

0 comments on commit 44e7f33

Please sign in to comment.