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

(cherry picked from commit b295bd5)
  • Loading branch information
nyalldawson committed Jan 15, 2021
1 parent 5eec9e4 commit 39a6b58
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])
elif isinstance(param, QgsProcessingParameterCrs):
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())
# For everything else, we assume that it is a string
else:
Expand Down Expand Up @@ -1031,23 +1033,25 @@ def setSessionProjectionFromProject(self):
We creates a PROJ4 definition which is transmitted to Grass
"""
if not Grass7Utils.projectionSet and iface:
self.destination_crs = iface.mapCanvas().mapSettings().destinationCrs()
proj4 = iface.mapCanvas().mapSettings().destinationCrs().toProj()
command = 'g.proj -c proj4="{}"'.format(proj4)
self.commands.append(command)
Grass7Utils.projectionSet = True
self.setSessionProjection(iface.mapCanvas().mapSettings().destinationCrs())

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

def setSessionProjection(self, crs):
"""
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):
# 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,
QgsApplication,
QgsProcessingUtils,
QgsMessageLog)
QgsMessageLog,
QgsCoordinateReferenceSystem)
from qgis.PyQt.QtCore import QCoreApplication
from processing.core.ProcessingConfig import ProcessingConfig
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')
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
def installedVersion(run=False):
"""
Expand Down
@@ -1,5 +1,5 @@
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.*)
QgsProcessingParameterRasterLayer|input|Input raster to reproject|None|False
QgsProcessingParameterCrs|crs|New coordinate reference system|None|False
Expand Down
@@ -1,5 +1,5 @@
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.*)
QgsProcessingParameterFeatureSource|input|Input vector to reproject|-1|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'

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):
# Grab the projection from the input vector layer
layer = alg.parameterAsLayer(parameters, 'input', context)
layerCrs = layer.crs().toProj()

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

# Go to the newly created location
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
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
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'
__copyright__ = '(C) 2017, Médéric Ribreux'

from processing.algs.grass7.Grass7Utils import Grass7Utils


def processOutputs(alg, parameters, context, feedback):
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'

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


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

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

# Go to the newly created location
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
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
alg.removeParameter('crs')
Expand Down

0 comments on commit 39a6b58

Please sign in to comment.