Skip to content

Commit 14a48c0

Browse files
authored
Merge pull request #5201 from nyalldawson/point_crs
[processing] Transparently handle CRS for point parameters
2 parents f4d5ca7 + d72309e commit 14a48c0

16 files changed

+473
-68
lines changed

python/core/processing/qgsprocessingalgorithm.sip

+15-1
Original file line numberDiff line numberDiff line change
@@ -696,12 +696,26 @@ class QgsProcessingAlgorithm
696696
:rtype: QgsCoordinateReferenceSystem
697697
%End
698698

699-
QgsPointXY parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const;
699+
QgsPointXY parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
700+
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const;
700701
%Docstring
701702
Evaluates the parameter with matching ``name`` to a point.
703+
704+
If ``crs`` is set then the point will be automatically
705+
reprojected so that it is in the specified ``crs``.
706+
707+
.. seealso:: parameterAsPointCrs()
702708
:rtype: QgsPointXY
703709
%End
704710

711+
QgsCoordinateReferenceSystem parameterAsPointCrs( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context );
712+
%Docstring
713+
Returns the coordinate reference system associated with an point parameter value.
714+
715+
.. seealso:: parameterAsPoint()
716+
:rtype: QgsCoordinateReferenceSystem
717+
%End
718+
705719
QString parameterAsFile( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const;
706720
%Docstring
707721
Evaluates the parameter with matching ``name`` to a file/folder name.

python/core/processing/qgsprocessingparameters.sip

+16-1
Original file line numberDiff line numberDiff line change
@@ -570,12 +570,25 @@ class QgsProcessingParameters
570570
:rtype: QgsCoordinateReferenceSystem
571571
%End
572572

573-
static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
573+
static QgsPointXY parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context,
574+
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
574575
%Docstring
575576
Evaluates the parameter with matching ``definition`` to a point.
577+
578+
If ``crs`` is set then the point will be automatically reprojected so that it is in the specified ``crs``.
579+
580+
.. seealso:: parameterAsPointCrs()
576581
:rtype: QgsPointXY
577582
%End
578583

584+
static QgsCoordinateReferenceSystem parameterAsPointCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
585+
%Docstring
586+
Returns the coordinate reference system associated with an point parameter value.
587+
588+
.. seealso:: parameterAsPoint()
589+
:rtype: QgsCoordinateReferenceSystem
590+
%End
591+
579592
static QString parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
580593
%Docstring
581594
Evaluates the parameter with matching ``definition`` to a file/folder name.
@@ -817,6 +830,8 @@ class QgsProcessingParameterPoint : QgsProcessingParameterDefinition
817830
virtual QString type() const;
818831
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
819832

833+
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
834+
820835

821836
static QgsProcessingParameterPoint *fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition ) /Factory/;
822837
%Docstring

python/plugins/processing/algs/qgis/ServiceAreaFromLayer.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
QgsUnitTypes,
3636
QgsFeature,
3737
QgsFeatureSink,
38+
QgsFeatureRequest,
3839
QgsGeometry,
3940
QgsFields,
4041
QgsField,
@@ -208,7 +209,7 @@ def processAlgorithm(self, parameters, context, feedback):
208209
multiplier * 1000.0 / 3600.0)
209210

210211
director.addStrategy(strategy)
211-
builder = QgsGraphBuilder(context.project().crs(),
212+
builder = QgsGraphBuilder(network.sourceCrs(),
212213
True,
213214
tolerance)
214215

python/plugins/processing/algs/qgis/ServiceAreaFromPoint.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def displayName(self):
163163

164164
def processAlgorithm(self, parameters, context, feedback):
165165
network = self.parameterAsSource(parameters, self.INPUT, context)
166-
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context)
166+
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
167167
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
168168
travelCost = self.parameterAsDouble(parameters, self.TRAVEL_COST, context)
169169

@@ -200,7 +200,7 @@ def processAlgorithm(self, parameters, context, feedback):
200200
multiplier * 1000.0 / 3600.0)
201201

202202
director.addStrategy(strategy)
203-
builder = QgsGraphBuilder(context.project().crs(),
203+
builder = QgsGraphBuilder(network.sourceCrs(),
204204
True,
205205
tolerance)
206206
feedback.pushInfo(self.tr('Building graph...'))

python/plugins/processing/algs/qgis/ShortestPathLayerToPoint.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from qgis.core import (QgsWkbTypes,
3535
QgsUnitTypes,
3636
QgsFeature,
37+
QgsFeatureRequest,
3738
QgsFeatureSink,
3839
QgsGeometry,
3940
QgsFields,
@@ -158,7 +159,7 @@ def displayName(self):
158159
def processAlgorithm(self, parameters, context, feedback):
159160
network = self.parameterAsSource(parameters, self.INPUT, context)
160161
startPoints = self.parameterAsSource(parameters, self.START_POINTS, context)
161-
endPoint = self.parameterAsPoint(parameters, self.END_POINT, context)
162+
endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs())
162163
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
163164

164165
directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
@@ -206,7 +207,7 @@ def processAlgorithm(self, parameters, context, feedback):
206207
multiplier = 3600
207208

208209
director.addStrategy(strategy)
209-
builder = QgsGraphBuilder(context.project().crs(),
210+
builder = QgsGraphBuilder(network.sourceCrs(),
210211
True,
211212
tolerance)
212213

@@ -236,7 +237,7 @@ def processAlgorithm(self, parameters, context, feedback):
236237

237238
nPoints = len(snappedPoints)
238239
total = 100.0 / nPoints if nPoints else 1
239-
for i in range(1, count + 1):
240+
for i in range(1, nPoints + 1):
240241
if feedback.isCanceled():
241242
break
242243

python/plugins/processing/algs/qgis/ShortestPathPointToLayer.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
QgsFeature,
3737
QgsFeatureSink,
3838
QgsGeometry,
39+
QgsFeatureRequest,
3940
QgsFields,
4041
QgsField,
4142
QgsMessageLog,
@@ -157,7 +158,7 @@ def displayName(self):
157158

158159
def processAlgorithm(self, parameters, context, feedback):
159160
network = self.parameterAsSource(parameters, self.INPUT, context)
160-
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context)
161+
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
161162
endPoints = self.parameterAsSource(parameters, self.END_POINTS, context)
162163
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
163164

@@ -206,7 +207,7 @@ def processAlgorithm(self, parameters, context, feedback):
206207
multiplier = 3600
207208

208209
director.addStrategy(strategy)
209-
builder = QgsGraphBuilder(context.project().crs(),
210+
builder = QgsGraphBuilder(network.sourceCrs(),
210211
True,
211212
tolerance)
212213

@@ -237,7 +238,7 @@ def processAlgorithm(self, parameters, context, feedback):
237238

238239
nPoints = len(snappedPoints)
239240
total = 100.0 / nPoints if nPoints else 1
240-
for i in range(1, count + 1):
241+
for i in range(1, nPoints + 1):
241242
if feedback.isCanceled():
242243
break
243244

python/plugins/processing/algs/qgis/ShortestPathPointToPoint.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ def displayName(self):
160160

161161
def processAlgorithm(self, parameters, context, feedback):
162162
network = self.parameterAsSource(parameters, self.INPUT, context)
163-
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context)
164-
endPoint = self.parameterAsPoint(parameters, self.END_POINT, context)
163+
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
164+
endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs())
165165
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
166166

167167
directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
@@ -206,7 +206,7 @@ def processAlgorithm(self, parameters, context, feedback):
206206
multiplier = 3600
207207

208208
director.addStrategy(strategy)
209-
builder = QgsGraphBuilder(context.project().crs(),
209+
builder = QgsGraphBuilder(network.sourceCrs(),
210210
True,
211211
tolerance)
212212
feedback.pushInfo(self.tr('Building graph...'))

python/plugins/processing/gui/ExtentSelectionPanel.py

+9-12
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,14 @@ def __init__(self, dialog, param):
7979
if param.defaultValue() is not None:
8080
context = createContext()
8181
rect = QgsProcessingParameters.parameterAsExtent(param, {param.name(): param.defaultValue()}, context)
82+
crs = QgsProcessingParameters.parameterAsExtentCrs(param, {param.name(): param.defaultValue()}, context)
8283
if not rect.isNull():
8384
try:
8485
s = '{},{},{},{}'.format(
8586
rect.xMinimum(), rect.xMaximum(), rect.yMinimum(), rect.yMaximum())
87+
if crs.isValid():
88+
s += ' [' + crs.authid() + ']'
89+
self.crs = crs
8690
self.leText.setText(s)
8791
except:
8892
pass
@@ -133,10 +137,6 @@ def useLayerExtent(self):
133137
self.tr('Use extent from'), extents, False)
134138
if ok:
135139
self.setValueFromRect(QgsReferencedRectangle(extentsDict[item]["extent"], QgsCoordinateReferenceSystem(extentsDict[item]["authid"])))
136-
if extentsDict[item]["authid"] != iface.mapCanvas().mapSettings().destinationCrs().authid():
137-
iface.messageBar().pushMessage(self.tr("Warning"),
138-
self.tr("The projection of the chosen layer is not the same as canvas projection! The selected extent might not be what was intended."),
139-
QgsMessageBar.WARNING, 8)
140140

141141
def selectOnCanvas(self):
142142
canvas = iface.mapCanvas()
@@ -151,11 +151,14 @@ def setValueFromRect(self, r):
151151
s = '{},{},{},{}'.format(
152152
r.xMinimum(), r.xMaximum(), r.yMinimum(), r.yMaximum())
153153

154-
self.leText.setText(s)
155154
try:
156155
self.crs = r.crs()
157156
except:
158157
self.crs = QgsProject.instance().crs()
158+
if self.crs.isValid():
159+
s += ' [' + self.crs.authid() + ']'
160+
161+
self.leText.setText(s)
159162
self.tool.reset()
160163
canvas = iface.mapCanvas()
161164
canvas.setMapTool(self.prevMapTool)
@@ -165,13 +168,7 @@ def setValueFromRect(self, r):
165168

166169
def getValue(self):
167170
if str(self.leText.text()).strip() != '':
168-
try:
169-
parts = self.leText.text().split(',')
170-
parts = [float(p) for p in parts]
171-
r = QgsReferencedRectangle(QgsRectangle(parts[0], parts[2], parts[1], parts[3]), self.crs)
172-
return r
173-
except:
174-
return str(self.leText.text())
171+
return str(self.leText.text())
175172
else:
176173
return None
177174

python/plugins/processing/gui/PointMapTool.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,23 @@
2525

2626
__revision__ = '$Format:%H$'
2727

28-
from qgis.PyQt.QtCore import Qt
28+
from qgis.PyQt.QtCore import Qt, pyqtSignal
2929

3030
from qgis.gui import QgsMapToolEmitPoint
3131

3232

3333
class PointMapTool(QgsMapToolEmitPoint):
3434

35+
complete = pyqtSignal()
36+
3537
def __init__(self, canvas):
3638
QgsMapToolEmitPoint.__init__(self, canvas)
3739

3840
self.canvas = canvas
39-
self.cursor = Qt.ArrowCursor
41+
self.cursor = Qt.CrossCursor
4042

4143
def activate(self):
4244
self.canvas.setCursor(self.cursor)
4345

44-
def canvasPressEvent(self, event):
45-
pnt = self.toMapCoordinates(event.pos())
46-
self.canvasClicked.emit(pnt, event.button())
46+
def canvasReleaseEvent(self, event):
47+
self.complete.emit()

python/plugins/processing/gui/PointSelectionPanel.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
import os
3030

31+
from qgis.core import (QgsProject,
32+
QgsReferencedPointXY,
33+
QgsPointXY)
3134
from qgis.PyQt import uic
3235

3336
from qgis.utils import iface
@@ -48,13 +51,15 @@ def __init__(self, dialog, default=None):
4851
self.btnSelect.clicked.connect(self.selectOnCanvas)
4952

5053
self.dialog = dialog
54+
self.crs = QgsProject.instance().crs()
5155

5256
if iface is not None:
5357
canvas = iface.mapCanvas()
5458
self.prevMapTool = canvas.mapTool()
5559

5660
self.tool = PointMapTool(canvas)
5761
self.tool.canvasClicked.connect(self.updatePoint)
62+
self.tool.complete.connect(self.pointPicked)
5863
else:
5964
self.prevMapTool = None
6065
self.tool = None
@@ -76,8 +81,12 @@ def selectOnCanvas(self):
7681

7782
def updatePoint(self, point, button):
7883
s = '{},{}'.format(point.x(), point.y())
79-
84+
self.crs = QgsProject.instance().crs()
85+
if self.crs.isValid():
86+
s += ' [' + self.crs.authid() + ']'
8087
self.leText.setText(s)
88+
89+
def pointPicked(self):
8190
canvas = iface.mapCanvas()
8291
canvas.setMapTool(self.prevMapTool)
8392
self.dialog.showNormal()

src/core/processing/qgsprocessingalgorithm.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -565,9 +565,14 @@ QgsGeometry QgsProcessingAlgorithm::parameterAsExtentGeometry( const QVariantMap
565565
return QgsProcessingParameters::parameterAsExtentGeometry( parameterDefinition( name ), parameters, context, crs );
566566
}
567567

568-
QgsPointXY QgsProcessingAlgorithm::parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const
568+
QgsPointXY QgsProcessingAlgorithm::parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs ) const
569569
{
570-
return QgsProcessingParameters::parameterAsPoint( parameterDefinition( name ), parameters, context );
570+
return QgsProcessingParameters::parameterAsPoint( parameterDefinition( name ), parameters, context, crs );
571+
}
572+
573+
QgsCoordinateReferenceSystem QgsProcessingAlgorithm::parameterAsPointCrs( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context )
574+
{
575+
return QgsProcessingParameters::parameterAsPointCrs( parameterDefinition( name ), parameters, context );
571576
}
572577

573578
QString QgsProcessingAlgorithm::parameterAsFile( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const

src/core/processing/qgsprocessingalgorithm.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -680,8 +680,21 @@ class CORE_EXPORT QgsProcessingAlgorithm
680680

681681
/**
682682
* Evaluates the parameter with matching \a name to a point.
683+
*
684+
* If \a crs is set then the point will be automatically
685+
* reprojected so that it is in the specified \a crs.
686+
*
687+
* \see parameterAsPointCrs()
688+
*/
689+
QgsPointXY parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context,
690+
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const;
691+
692+
/**
693+
* Returns the coordinate reference system associated with an point parameter value.
694+
*
695+
* \see parameterAsPoint()
683696
*/
684-
QgsPointXY parameterAsPoint( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const;
697+
QgsCoordinateReferenceSystem parameterAsPointCrs( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context );
685698

686699
/**
687700
* Evaluates the parameter with matching \a name to a file/folder name.

0 commit comments

Comments
 (0)