Skip to content

Commit

Permalink
Merge pull request #5199 from nyalldawson/extract_by_extent2
Browse files Browse the repository at this point in the history
[processing] Extent handling improvements
  • Loading branch information
nyalldawson committed Sep 15, 2017
2 parents 8d088c0 + 8605be0 commit c5ae3a0
Show file tree
Hide file tree
Showing 22 changed files with 633 additions and 19 deletions.
30 changes: 29 additions & 1 deletion python/core/processing/qgsprocessingalgorithm.sip
Expand Up @@ -662,12 +662,40 @@ class QgsProcessingAlgorithm
:rtype: QgsCoordinateReferenceSystem
%End

QgsRectangle parameterAsExtent( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const;
QgsRectangle parameterAsExtent( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const;
%Docstring
Evaluates the parameter with matching ``name`` to a rectangular extent.

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. In this case the extent of the reproject rectangle will be returned.

.. seealso:: parameterAsExtentGeometry()
:rtype: QgsRectangle
%End

QgsGeometry parameterAsExtentGeometry( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
%Docstring
Evaluates the parameter with matching ``name`` to a rectangular extent, and returns a geometry covering this extent.

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. Unlike parameterAsExtent(), the reprojected rectangle returned by this function
will no longer be a rectangle itself (i.e. this method returns the geometry of the actual reprojected rectangle, while parameterAsExtent() returns
just the extent of the reprojected rectangle).

.. seealso:: parameterAsExtent()
:rtype: QgsGeometry
%End

QgsCoordinateReferenceSystem parameterAsExtentCrs( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context );
%Docstring
Returns the coordinate reference system associated with an extent parameter value.

.. seealso:: parameterAsExtent()
:rtype: QgsCoordinateReferenceSystem
%End

QgsPointXY parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const;
%Docstring
Evaluates the parameter with matching ``name`` to a point.
Expand Down
32 changes: 31 additions & 1 deletion python/core/processing/qgsprocessingparameters.sip
Expand Up @@ -534,12 +534,42 @@ class QgsProcessingParameters
:rtype: QgsCoordinateReferenceSystem
%End

static QgsRectangle parameterAsExtent( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
static QgsRectangle parameterAsExtent( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
%Docstring
Evaluates the parameter with matching ``definition`` to a rectangular extent.

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. In this case the extent of the reproject rectangle will be returned.

.. seealso:: parameterAsExtentGeometry()
.. seealso:: parameterAsExtentCrs()
:rtype: QgsRectangle
%End

static QgsGeometry parameterAsExtentGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
%Docstring
Evaluates the parameter with matching ``definition`` to a rectangular extent, and returns a geometry covering this extent.

If ``crs`` is set, and the original coordinate reference system of the parameter can be determined, then the extent will be automatically
reprojected so that it is in the specified ``crs``. Unlike parameterAsExtent(), the reprojected rectangle returned by this function
will no longer be a rectangle itself (i.e. this method returns the geometry of the actual reprojected rectangle, while parameterAsExtent() returns
just the extent of the reprojected rectangle).

.. seealso:: parameterAsExtent()
.. seealso:: parameterAsExtentCrs()
:rtype: QgsGeometry
%End

static QgsCoordinateReferenceSystem parameterAsExtentCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
%Docstring
Returns the coordinate reference system associated with an extent parameter value.

.. seealso:: parameterAsExtent()
:rtype: QgsCoordinateReferenceSystem
%End

static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
%Docstring
Evaluates the parameter with matching ``definition`` to a point.
Expand Down
Expand Up @@ -76,8 +76,8 @@ def displayName(self):
return self.tr('Create constant raster layer')

def processAlgorithm(self, parameters, context, feedback):
extent = self.parameterAsExtent(parameters, self.EXTENT, context)
crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs)
value = self.parameterAsDouble(parameters, self.NUMBER, context)
pixelSize = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context)

Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/GridLine.py
Expand Up @@ -105,8 +105,8 @@ def processAlgorithm(self, parameters, context, feedback):
hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context)
vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context)

bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
crs = self.parameterAsCrs(parameters, self.CRS, context)
bbox = self.parameterAsExtent(parameters, self.EXTENT, context, crs)

width = bbox.width()
height = bbox.height()
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/GridPolygon.py
Expand Up @@ -113,8 +113,8 @@ def processAlgorithm(self, parameters, context, feedback):
hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context)
vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context)

bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
crs = self.parameterAsCrs(parameters, self.CRS, context)
bbox = self.parameterAsExtent(parameters, self.EXTENT, context, crs)

width = bbox.width()
height = bbox.height()
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/RandomPointsExtent.py
Expand Up @@ -94,10 +94,10 @@ def displayName(self):
return self.tr('Random points in extent')

def processAlgorithm(self, parameters, context, feedback):
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
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)

Expand Down
3 changes: 1 addition & 2 deletions python/plugins/processing/algs/qgis/RegularPoints.py
Expand Up @@ -93,13 +93,12 @@ def displayName(self):
return self.tr('Regular points')

def processAlgorithm(self, parameters, context, feedback):
extent = self.parameterAsExtent(parameters, self.EXTENT, context)

spacing = self.parameterAsDouble(parameters, self.SPACING, context)
inset = self.parameterAsDouble(parameters, self.INSET, context)
randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context)
isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context)
crs = self.parameterAsCrs(parameters, self.CRS, context)
extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs)

fields = QgsFields()
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
Expand Down
5 changes: 4 additions & 1 deletion python/plugins/processing/gui/AlgorithmDialog.py
Expand Up @@ -216,7 +216,10 @@ def accept(self):
self.tr('<b>Algorithm \'{0}\' starting...</b>').format(self.alg.displayName()), escape_html=False)

feedback.pushInfo(self.tr('Input parameters:'))
feedback.pushCommandInfo(pformat(parameters))
display_params = []
for k, v in parameters.items():
display_params.append("'" + k + "' : " + self.alg.parameterDefinition(k).valueAsPythonString(v, context))
feedback.pushCommandInfo('{ ' + ', '.join(display_params) + ' }')
feedback.pushInfo('')
start_time = time.time()

Expand Down
22 changes: 19 additions & 3 deletions python/plugins/processing/gui/ExtentSelectionPanel.py 100644 → 100755
Expand Up @@ -36,7 +36,11 @@
from qgis.utils import iface
from qgis.core import (QgsProcessingUtils,
QgsProcessingParameterDefinition,
QgsProject)
QgsProcessingParameters,
QgsProject,
QgsCoordinateReferenceSystem,
QgsRectangle,
QgsReferencedRectangle)
from processing.gui.RectangleMapTool import RectangleMapTool
from processing.core.ProcessingConfig import ProcessingConfig
from processing.tools.dataobjects import createContext
Expand All @@ -54,6 +58,8 @@ def __init__(self, dialog, param):

self.dialog = dialog
self.param = param
self.crs = QgsProject.instance().crs()

if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional:
if hasattr(self.leText, 'setPlaceholderText'):
self.leText.setPlaceholderText(
Expand Down Expand Up @@ -126,7 +132,7 @@ def useLayerExtent(self):
(item, ok) = QInputDialog.getItem(self, self.tr('Select extent'),
self.tr('Use extent from'), extents, False)
if ok:
self.setValueFromRect(extentsDict[item]["extent"])
self.setValueFromRect(QgsReferencedRectangle(extentsDict[item]["extent"], QgsCoordinateReferenceSystem(extentsDict[item]["authid"])))
if extentsDict[item]["authid"] != iface.mapCanvas().mapSettings().destinationCrs().authid():
iface.messageBar().pushMessage(self.tr("Warning"),
self.tr("The projection of the chosen layer is not the same as canvas projection! The selected extent might not be what was intended."),
Expand All @@ -146,6 +152,10 @@ def setValueFromRect(self, r):
r.xMinimum(), r.xMaximum(), r.yMinimum(), r.yMaximum())

self.leText.setText(s)
try:
self.crs = r.crs()
except:
self.crs = QgsProject.instance().crs()
self.tool.reset()
canvas = iface.mapCanvas()
canvas.setMapTool(self.prevMapTool)
Expand All @@ -155,7 +165,13 @@ def setValueFromRect(self, r):

def getValue(self):
if str(self.leText.text()).strip() != '':
return str(self.leText.text())
try:
parts = self.leText.text().split(',')
parts = [float(p) for p in parts]
r = QgsReferencedRectangle(QgsRectangle(parts[0], parts[2], parts[1], parts[3]), self.crs)
return r
except:
return str(self.leText.text())
else:
return None

Expand Down
@@ -0,0 +1,32 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>extract_by_extent</Name>
<ElementPath>extract_by_extent</ElementPath>
<!--POLYGON-->
<GeometryType>3</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>2</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>6.00000</ExtentXMax>
<ExtentYMin>-3.00000</ExtentYMin>
<ExtentYMax>3.00000</ExtentYMax>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>name</Name>
<ElementPath>name</ElementPath>
<Type>String</Type>
<Width>5</Width>
</PropertyDefn>
<PropertyDefn>
<Name>intval</Name>
<ElementPath>intval</ElementPath>
<Type>Integer</Type>
</PropertyDefn>
<PropertyDefn>
<Name>floatval</Name>
<ElementPath>floatval</ElementPath>
<Type>Real</Type>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,30 @@
<?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>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>6</gml:X><gml:Y>3</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:extract_by_extent fid="polys.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>aaaaa</ogr:name>
<ogr:intval>33</ogr:intval>
<ogr:floatval>44.123456</ogr:floatval>
</ogr:extract_by_extent>
</gml:featureMember>
<gml:featureMember>
<ogr:extract_by_extent fid="polys.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>elim</ogr:name>
<ogr:intval>2</ogr:intval>
<ogr:floatval>3.33</ogr:floatval>
</ogr:extract_by_extent>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,32 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>extract_by_extent_clip</Name>
<ElementPath>extract_by_extent_clip</ElementPath>
<!--MULTIPOLYGON-->
<GeometryType>6</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>2</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>4.77500</ExtentXMax>
<ExtentYMin>-2.38750</ExtentYMin>
<ExtentYMax>3.00000</ExtentYMax>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>name</Name>
<ElementPath>name</ElementPath>
<Type>String</Type>
<Width>5</Width>
</PropertyDefn>
<PropertyDefn>
<Name>intval</Name>
<ElementPath>intval</ElementPath>
<Type>Integer</Type>
</PropertyDefn>
<PropertyDefn>
<Name>floatval</Name>
<ElementPath>floatval</ElementPath>
<Type>Real</Type>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,30 @@
<?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>-1</gml:X><gml:Y>-2.3875</gml:Y></gml:coord>
<gml:coord><gml:X>4.775</gml:X><gml:Y>3</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:extract_by_extent_clip fid="polys.0">
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
<ogr:name>aaaaa</ogr:name>
<ogr:intval>33</ogr:intval>
<ogr:floatval>44.123456</ogr:floatval>
</ogr:extract_by_extent_clip>
</gml:featureMember>
<gml:featureMember>
<ogr:extract_by_extent_clip fid="polys.5">
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 4.775,1.40833333333333 4.775,-2.3875 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
<ogr:name>elim</ogr:name>
<ogr:intval>2</ogr:intval>
<ogr:floatval>3.33</ogr:floatval>
</ogr:extract_by_extent_clip>
</gml:featureMember>
</ogr:FeatureCollection>
28 changes: 27 additions & 1 deletion python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml 100644 → 100755
Expand Up @@ -3937,4 +3937,30 @@ tests:
- name
compare:
fields:
fid: skip
fid: skip

- algorithm: native:extractbyextent
name: Extract by extent
params:
CLIP: false
EXTENT: -1.1650000000000003,4.775,-2.444285714285715,3.4171428571428573
INPUT:
name: polys.gml
type: vector
results:
OUTPUT:
name: expected/extract_by_extent.gml
type: vector

- algorithm: native:extractbyextent
name: Extract by extent (clipped)
params:
CLIP: true
EXTENT: -1.1650000000000003,4.775,-2.444285714285715,3.4171428571428573
INPUT:
name: polys.gml
type: vector
results:
OUTPUT:
name: expected/extract_by_extent_clip.gml
type: vector

0 comments on commit c5ae3a0

Please sign in to comment.