Skip to content

Commit

Permalink
[processing][grass] Export CRS definitions as WKT2 strings instead
Browse files Browse the repository at this point in the history
of proj strings wherever possible

Because proj strings are lossy

Fixes #18596
  • Loading branch information
nyalldawson committed Jan 12, 2021
1 parent c703d81 commit b295bd5
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 22 deletions.
24 changes: 14 additions & 10 deletions python/plugins/processing/algs/grass7/Grass7Algorithm.py
Expand Up @@ -636,6 +636,8 @@ def processCommand(self, parameters, context, feedback, delOutputs=False):
value = '{},{}'.format(v[0], v[1]) value = '{},{}'.format(v[0], v[1])
elif isinstance(param, QgsProcessingParameterCrs): elif isinstance(param, QgsProcessingParameterCrs):
if self.parameterAsCrs(parameters, paramName, context): if self.parameterAsCrs(parameters, paramName, context):
# TODO: ideally we should be exporting to WKT here, but it seems not all grass algorithms
# will accept a wkt string for a crs value (e.g. r.tileset)
value = '"{}"'.format(self.parameterAsCrs(parameters, paramName, context).toProj()) value = '"{}"'.format(self.parameterAsCrs(parameters, paramName, context).toProj())
# For everything else, we assume that it is a string # For everything else, we assume that it is a string
else: else:
Expand Down Expand Up @@ -1031,23 +1033,25 @@ def setSessionProjectionFromProject(self):
We creates a PROJ4 definition which is transmitted to Grass We creates a PROJ4 definition which is transmitted to Grass
""" """
if not Grass7Utils.projectionSet and iface: if not Grass7Utils.projectionSet and iface:
self.destination_crs = iface.mapCanvas().mapSettings().destinationCrs() self.setSessionProjection(iface.mapCanvas().mapSettings().destinationCrs())
proj4 = iface.mapCanvas().mapSettings().destinationCrs().toProj()
command = 'g.proj -c proj4="{}"'.format(proj4)
self.commands.append(command)
Grass7Utils.projectionSet = True


def setSessionProjectionFromLayer(self, layer): def setSessionProjectionFromLayer(self, layer):
""" """
Set the projection from a QgsVectorLayer. Set the projection from a QgsVectorLayer.
We creates a PROJ4 definition which is transmitted to Grass We creates a PROJ4 definition which is transmitted to Grass
""" """
if not Grass7Utils.projectionSet: if not Grass7Utils.projectionSet:
proj4 = str(layer.crs().toProj()) self.setSessionProjection(layer.crs())
self.destination_crs = layer.crs()
command = 'g.proj -c proj4="{}"'.format(proj4) def setSessionProjection(self, crs):
self.commands.append(command) """
Grass7Utils.projectionSet = True Set the session projection to the specified CRS
"""
self.destination_crs = crs
file_name = Grass7Utils.exportCrsWktToFile(crs)
command = 'g.proj -c wkt="{}"'.format(file_name)
self.commands.append(command)
Grass7Utils.projectionSet = True


def convertToHtml(self, fileName): def convertToHtml(self, fileName):
# Read HTML contents # Read HTML contents
Expand Down
15 changes: 14 additions & 1 deletion python/plugins/processing/algs/grass7/Grass7Utils.py
Expand Up @@ -31,7 +31,8 @@
from qgis.core import (Qgis, from qgis.core import (Qgis,
QgsApplication, QgsApplication,
QgsProcessingUtils, QgsProcessingUtils,
QgsMessageLog) QgsMessageLog,
QgsCoordinateReferenceSystem)
from qgis.PyQt.QtCore import QCoreApplication from qgis.PyQt.QtCore import QCoreApplication
from processing.core.ProcessingConfig import ProcessingConfig from processing.core.ProcessingConfig import ProcessingConfig
from processing.tools.system import userFolder, isWindows, isMac, mkdir from processing.tools.system import userFolder, isWindows, isMac, mkdir
Expand Down Expand Up @@ -82,6 +83,18 @@ def grassBatchJobFilename():
batchFile = os.path.join(gisdbase, 'grass_batch_job.sh') batchFile = os.path.join(gisdbase, 'grass_batch_job.sh')
return batchFile return batchFile


@staticmethod
def exportCrsWktToFile(crs):
"""
Exports a crs as a WKT definition to a text file, and returns the path
to this file
"""
wkt = crs.toWkt(QgsCoordinateReferenceSystem.WKT_PREFERRED)
wkt_file = QgsProcessingUtils.generateTempFilename('crs.prj')
with open(wkt_file, 'wt') as f:
f.write(wkt)
return wkt_file

@staticmethod @staticmethod
def installedVersion(run=False): def installedVersion(run=False):
""" """
Expand Down
@@ -1,5 +1,5 @@
r.proj r.proj
Re-projects a vector map from one location to the current location Re-projects a raster layer to another coordinate reference system
Raster (r.*) Raster (r.*)
QgsProcessingParameterRasterLayer|input|Input raster to reproject|None|False QgsProcessingParameterRasterLayer|input|Input raster to reproject|None|False
QgsProcessingParameterCrs|crs|New coordinate reference system|None|False QgsProcessingParameterCrs|crs|New coordinate reference system|None|False
Expand Down
@@ -1,5 +1,5 @@
v.proj v.proj
Re-projects a vector map from one location to the current location Re-projects a vector layer to another coordinate reference system
Vector (v.*) Vector (v.*)
QgsProcessingParameterFeatureSource|input|Input vector to reproject|-1|None|False QgsProcessingParameterFeatureSource|input|Input vector to reproject|-1|None|False
QgsProcessingParameterCrs|crs|New coordinate reference system|None|False QgsProcessingParameterCrs|crs|New coordinate reference system|None|False
Expand Down
12 changes: 7 additions & 5 deletions python/plugins/processing/algs/grass7/ext/r_proj.py
Expand Up @@ -22,18 +22,19 @@
__copyright__ = '(C) 2017, Médéric Ribreux' __copyright__ = '(C) 2017, Médéric Ribreux'


from qgis.core import QgsProcessingParameterString from qgis.core import QgsProcessingParameterString
from ..Grass7Utils import isWindows from processing.tools.system import isWindows
from processing.algs.grass7.Grass7Utils import Grass7Utils




def processInputs(alg, parameters, context, feedback): def processInputs(alg, parameters, context, feedback):
# Grab the projection from the input vector layer # Grab the projection from the input vector layer
layer = alg.parameterAsLayer(parameters, 'input', context) layer = alg.parameterAsLayer(parameters, 'input', context)
layerCrs = layer.crs().toProj()


# Creates a new location with this Crs # Creates a new location with this Crs
wkt_file_name = Grass7Utils.exportCrsWktToFile(layer.crs())
newLocation = 'newProj{}'.format(alg.uniqueSuffix) newLocation = 'newProj{}'.format(alg.uniqueSuffix)
alg.commands.append('g.proj proj4="{}" location={}'.format( alg.commands.append('g.proj wkt="{}" location={}'.format(
layerCrs, newLocation)) wkt_file_name, newLocation))


# Go to the newly created location # Go to the newly created location
alg.commands.append('g.mapset mapset=PERMANENT location={}'.format( alg.commands.append('g.mapset mapset=PERMANENT location={}'.format(
Expand All @@ -48,7 +49,8 @@ def processInputs(alg, parameters, context, feedback):


# Grab the projected Crs # Grab the projected Crs
crs = alg.parameterAsCrs(parameters, 'crs', context) crs = alg.parameterAsCrs(parameters, 'crs', context)
alg.commands.append('g.proj -c proj4="{}"'.format(crs.toProj())) wkt_file_name = Grass7Utils.exportCrsWktToFile(crs)
alg.commands.append('g.proj -c wkt="{}"'.format(wkt_file_name))


# Remove crs parameter # Remove crs parameter
alg.removeParameter('crs') alg.removeParameter('crs')
Expand Down
5 changes: 4 additions & 1 deletion python/plugins/processing/algs/grass7/ext/r_tileset.py
Expand Up @@ -21,8 +21,11 @@
__date__ = 'October 2017' __date__ = 'October 2017'
__copyright__ = '(C) 2017, Médéric Ribreux' __copyright__ = '(C) 2017, Médéric Ribreux'


from processing.algs.grass7.Grass7Utils import Grass7Utils



def processOutputs(alg, parameters, context, feedback): def processOutputs(alg, parameters, context, feedback):
crs = alg.parameterAsCrs(parameters, 'sourceproj', context) crs = alg.parameterAsCrs(parameters, 'sourceproj', context)


alg.commands.insert(0, 'g.proj -c proj4="{}"'.format(crs.toProj())) wkt_file_name = Grass7Utils.exportCrsWktToFile(crs)
alg.commands.insert(0, 'g.proj -c wkt="{}"'.format(wkt_file_name))
9 changes: 6 additions & 3 deletions python/plugins/processing/algs/grass7/ext/v_proj.py
Expand Up @@ -22,6 +22,7 @@
__copyright__ = '(C) 2017, Médéric Ribreux' __copyright__ = '(C) 2017, Médéric Ribreux'


from qgis.core import QgsProcessingParameterString from qgis.core import QgsProcessingParameterString
from processing.algs.grass7.Grass7Utils import Grass7Utils




def processInputs(alg, parameters, context, feedback): def processInputs(alg, parameters, context, feedback):
Expand All @@ -31,9 +32,10 @@ def processInputs(alg, parameters, context, feedback):
layerCrs = layer.crs().toProj() layerCrs = layer.crs().toProj()


# Creates a new location with this Crs # Creates a new location with this Crs
wkt_file_name = Grass7Utils.exportCrsWktToFile(layer.crs())
newLocation = 'newProj{}'.format(alg.uniqueSuffix) newLocation = 'newProj{}'.format(alg.uniqueSuffix)
alg.commands.append('g.proj proj4="{}" location={}'.format( alg.commands.append('g.proj wkt="{}" location={}'.format(
layerCrs, newLocation)) wkt_file_name, newLocation))


# Go to the newly created location # Go to the newly created location
alg.commands.append('g.mapset mapset=PERMANENT location={}'.format( alg.commands.append('g.mapset mapset=PERMANENT location={}'.format(
Expand All @@ -48,7 +50,8 @@ def processInputs(alg, parameters, context, feedback):


# Grab the projected Crs # Grab the projected Crs
crs = alg.parameterAsCrs(parameters, 'crs', context) crs = alg.parameterAsCrs(parameters, 'crs', context)
alg.commands.append('g.proj -c proj4="{}"'.format(crs.toProj())) wkt_file_name = Grass7Utils.exportCrsWktToFile(crs)
alg.commands.append('g.proj -c wkt="{}"'.format(wkt_file_name))


# Remove crs parameter # Remove crs parameter
alg.removeParameter('crs') alg.removeParameter('crs')
Expand Down

0 comments on commit b295bd5

Please sign in to comment.