mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
[FEATURE][processing] Choice of units for non degree/unknown distances
When an algorithm has a distance parameter in meters/feet/etc (i.e. non-geographic distances), show a combo box allowing choice of unit type. (We don't (and should never) expose this for distances in degrees -- it's up to users in this situation to choose a suitable local projection and reproject their data to match. Refs: a recent talk by @volaya)
This commit is contained in:
parent
d1d6840a5f
commit
2692de6ed0
@ -32,7 +32,7 @@ import warnings
|
||||
|
||||
from qgis.PyQt import uic
|
||||
from qgis.PyQt.QtCore import pyqtSignal, QSize
|
||||
from qgis.PyQt.QtWidgets import QDialog, QLabel
|
||||
from qgis.PyQt.QtWidgets import QDialog, QLabel, QComboBox
|
||||
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsExpression,
|
||||
@ -268,10 +268,21 @@ class DistanceInputPanel(NumberInputPanel):
|
||||
super().__init__(param)
|
||||
|
||||
self.label = QLabel('')
|
||||
|
||||
self.units_combo = QComboBox()
|
||||
self.base_units = QgsUnitTypes.DistanceUnknownUnit
|
||||
for u in (QgsUnitTypes.DistanceMeters,
|
||||
QgsUnitTypes.DistanceKilometers,
|
||||
QgsUnitTypes.DistanceFeet,
|
||||
QgsUnitTypes.DistanceMiles,
|
||||
QgsUnitTypes.DistanceYards):
|
||||
self.units_combo.addItem(QgsUnitTypes.toString(u), u)
|
||||
|
||||
label_margin = self.fontMetrics().width('X')
|
||||
self.layout().insertSpacing(1, label_margin / 2)
|
||||
self.layout().insertWidget(2, self.label)
|
||||
self.layout().insertSpacing(3, label_margin / 2)
|
||||
self.layout().insertWidget(3, self.units_combo)
|
||||
self.layout().insertSpacing(4, label_margin / 2)
|
||||
self.warning_label = QLabel()
|
||||
icon = QgsApplication.getThemeIcon('mIconWarning.svg')
|
||||
size = max(24, self.spnValue.height() * 0.5)
|
||||
@ -279,11 +290,20 @@ class DistanceInputPanel(NumberInputPanel):
|
||||
self.warning_label.setToolTip(self.tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.'))
|
||||
self.layout().insertWidget(4, self.warning_label)
|
||||
self.layout().insertSpacing(5, label_margin)
|
||||
|
||||
self.setUnits(QgsUnitTypes.DistanceUnknownUnit)
|
||||
|
||||
def setUnits(self, units):
|
||||
self.label.setText(QgsUnitTypes.toString(units))
|
||||
if QgsUnitTypes.unitType(units) != QgsUnitTypes.Standard:
|
||||
self.units_combo.hide()
|
||||
self.label.show()
|
||||
else:
|
||||
self.units_combo.setCurrentIndex(self.units_combo.findData(units))
|
||||
self.units_combo.show()
|
||||
self.label.hide()
|
||||
self.warning_label.setVisible(units == QgsUnitTypes.DistanceDegrees)
|
||||
self.base_units = units
|
||||
|
||||
def setUnitParameterValue(self, value):
|
||||
units = QgsUnitTypes.DistanceUnknownUnit
|
||||
@ -297,3 +317,17 @@ class DistanceInputPanel(NumberInputPanel):
|
||||
if crs.isValid():
|
||||
units = crs.mapUnits()
|
||||
self.setUnits(units)
|
||||
|
||||
def getValue(self):
|
||||
val = super().getValue()
|
||||
if isinstance(val, float) and self.units_combo.isVisible():
|
||||
display_unit = self.units_combo.currentData()
|
||||
return val * QgsUnitTypes.fromUnitToUnitFactor(display_unit, self.base_units)
|
||||
|
||||
return val
|
||||
|
||||
def setValue(self, value):
|
||||
try:
|
||||
self.spnValue.setValue(float(value))
|
||||
except:
|
||||
return
|
||||
|
@ -176,35 +176,72 @@ class WrappersTest(unittest.TestCase):
|
||||
widget.setUnitParameterValue('EPSG:3111')
|
||||
self.assertEqual(widget.label.text(), 'meters')
|
||||
self.assertFalse(widget.warning_label.isVisible())
|
||||
self.assertTrue(widget.units_combo.isVisible())
|
||||
self.assertFalse(widget.label.isVisible())
|
||||
self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters)
|
||||
|
||||
widget.setUnitParameterValue('EPSG:4326')
|
||||
self.assertEqual(widget.label.text(), 'degrees')
|
||||
self.assertTrue(widget.warning_label.isVisible())
|
||||
self.assertFalse(widget.units_combo.isVisible())
|
||||
self.assertTrue(widget.label.isVisible())
|
||||
|
||||
widget.setUnitParameterValue(QgsCoordinateReferenceSystem('EPSG:3111'))
|
||||
self.assertEqual(widget.label.text(), 'meters')
|
||||
self.assertFalse(widget.warning_label.isVisible())
|
||||
self.assertTrue(widget.units_combo.isVisible())
|
||||
self.assertFalse(widget.label.isVisible())
|
||||
self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters)
|
||||
|
||||
widget.setUnitParameterValue(QgsCoordinateReferenceSystem('EPSG:4326'))
|
||||
self.assertEqual(widget.label.text(), 'degrees')
|
||||
self.assertTrue(widget.warning_label.isVisible())
|
||||
self.assertFalse(widget.units_combo.isVisible())
|
||||
self.assertTrue(widget.label.isVisible())
|
||||
|
||||
# layer values
|
||||
vl = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory")
|
||||
widget.setUnitParameterValue(vl)
|
||||
self.assertEqual(widget.label.text(), 'meters')
|
||||
self.assertFalse(widget.warning_label.isVisible())
|
||||
self.assertTrue(widget.units_combo.isVisible())
|
||||
self.assertFalse(widget.label.isVisible())
|
||||
self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters)
|
||||
|
||||
vl2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=pk:int", "vl", "memory")
|
||||
widget.setUnitParameterValue(vl2)
|
||||
self.assertEqual(widget.label.text(), 'degrees')
|
||||
self.assertTrue(widget.warning_label.isVisible())
|
||||
self.assertFalse(widget.units_combo.isVisible())
|
||||
self.assertTrue(widget.label.isVisible())
|
||||
|
||||
# unresolvable values
|
||||
widget.setUnitParameterValue(vl.id())
|
||||
self.assertEqual(widget.label.text(), '<unknown>')
|
||||
self.assertFalse(widget.warning_label.isVisible())
|
||||
self.assertFalse(widget.units_combo.isVisible())
|
||||
self.assertTrue(widget.label.isVisible())
|
||||
|
||||
# resolvable text value
|
||||
QgsProject.instance().addMapLayer(vl)
|
||||
widget.setUnitParameterValue(vl.id())
|
||||
self.assertEqual(widget.label.text(), 'meters')
|
||||
self.assertFalse(widget.warning_label.isVisible())
|
||||
self.assertTrue(widget.units_combo.isVisible())
|
||||
self.assertFalse(widget.label.isVisible())
|
||||
self.assertEqual(widget.units_combo.currentData(), QgsUnitTypes.DistanceMeters)
|
||||
|
||||
widget.setValue(5)
|
||||
self.assertEqual(widget.getValue(), 5)
|
||||
widget.units_combo.setCurrentIndex(widget.units_combo.findData(QgsUnitTypes.DistanceKilometers))
|
||||
self.assertEqual(widget.getValue(), 5000)
|
||||
widget.setValue(2)
|
||||
self.assertEqual(widget.getValue(), 2000)
|
||||
|
||||
widget.setUnitParameterValue(vl.id())
|
||||
self.assertEqual(widget.getValue(), 2)
|
||||
widget.setValue(5)
|
||||
self.assertEqual(widget.getValue(), 5)
|
||||
|
||||
widget.deleteLater()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user