mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #5090 from nyalldawson/raster_layer_extent
[FEATURE] New algorithm for creating vector layer from raster layer's extent
This commit is contained in:
commit
9fa12ac57f
@ -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.
|
||||
|
||||
|
@ -49,7 +49,7 @@ pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
class ExtentFromLayer(QgisAlgorithm):
|
||||
|
||||
INPUT_LAYER = 'INPUT_LAYER'
|
||||
INPUT = 'INPUT'
|
||||
BY_FEATURE = 'BY_FEATURE'
|
||||
|
||||
OUTPUT = 'OUTPUT'
|
||||
@ -67,7 +67,7 @@ class ExtentFromLayer(QgisAlgorithm):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer')))
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer')))
|
||||
self.addParameter(QgsProcessingParameterBoolean(self.BY_FEATURE,
|
||||
self.tr('Calculate extent for each feature separately'), False))
|
||||
|
||||
@ -77,10 +77,10 @@ class ExtentFromLayer(QgisAlgorithm):
|
||||
return 'polygonfromlayerextent'
|
||||
|
||||
def displayName(self):
|
||||
return self.tr('Polygon from layer extent')
|
||||
return self.tr('Polygon from vector extent')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context)
|
||||
|
||||
fields = QgsFields()
|
||||
|
127
python/plugins/processing/algs/qgis/ExtentFromRasterLayer.py
Executable file
127
python/plugins/processing/algs/qgis/ExtentFromRasterLayer.py
Executable file
@ -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 .Explode import Explode
|
||||
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 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
ExportGeometryInfo(),
|
||||
ExtendLines(),
|
||||
ExtentFromLayer(),
|
||||
ExtentFromRasterLayer(),
|
||||
ExtractNodes(),
|
||||
ExtractSpecificNodes(),
|
||||
FieldsCalculator(),
|
||||
|
@ -27,6 +27,7 @@ __copyright__ = '(C) 2013, Victor Olaya'
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import yaml
|
||||
import hashlib
|
||||
@ -81,7 +82,8 @@ def extractSchemaPath(filepath):
|
||||
if part == 'testdata' and not localpath:
|
||||
localparts = parts
|
||||
localparts.reverse()
|
||||
localpath = os.path.join(*localparts)
|
||||
# we always want posix style paths here
|
||||
localpath = posixpath.join(*localparts)
|
||||
|
||||
parts.append(part)
|
||||
|
||||
|
66
python/plugins/processing/tests/testdata/expected/raster_extent.gfs
vendored
Executable file
66
python/plugins/processing/tests/testdata/expected/raster_extent.gfs
vendored
Executable file
@ -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>
|
29
python/plugins/processing/tests/testdata/expected/raster_extent.gml
vendored
Executable file
29
python/plugins/processing/tests/testdata/expected/raster_extent.gml
vendored
Executable file
@ -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>
|
@ -2845,7 +2845,7 @@ tests:
|
||||
name: Standard polygon from layer extent
|
||||
params:
|
||||
BY_FEATURE: false
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: polys.gml
|
||||
type: vector
|
||||
results:
|
||||
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user