Commit 358ba3ac authored by Rashad Kanavath's avatar Rashad Kanavath
Browse files

upgdate to same code in qgis pr

parent dc71c82c
......@@ -34,21 +34,29 @@ from qgis.PyQt.QtGui import QIcon
from qgis.core import (Qgis,
QgsMessageLog,
QgsRasterLayer,
QgsMapLayer,
QgsApplication,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterDefinition,
QgsProcessingOutputLayerDefinition,
QgsProcessingParameterCrs,
QgsProcessingParameterString,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterBoolean,
QgsProcessingParameterFile,
QgsProcessingParameterNumber,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterVectorDestination,
QgsProcessingParameterEnum)
from processing.core.parameters import getParameterFromString
from otb.OtbChoiceWidget import OtbParameterChoice
from otb import OtbUtils
class OtbAlgorithm(QgsProcessingAlgorithm):
def __init__(self, group, name, descriptionfile, display_name='', groupId=''):
super().__init__()
......@@ -61,30 +69,13 @@ class OtbAlgorithm(QgsProcessingAlgorithm):
if not groupId:
self._groupId = ''.join(c for c in self._group if c in validChars)
self.pixelTypes = ['unit8','int','float','double']
self.pixelTypes = ['uint8', 'uint16', 'int16', 'uint32', 'int32',
'float', 'double', 'cint16', 'cint32', 'cfloat', 'cdouble']
self._descriptionfile = descriptionfile
self.defineCharacteristicsFromFile()
# def canExecute( self, msg=None):
# if len(self.parameterDefinitions()) > 0:
# return True, None
# try:
# self.defineCharacteristicsFromFile()
# except BaseException as e:
# return False, None
# return True, None
# TODO: check if this method is really required.
def checkParameterValues(self, parameters, context):
for key, value in parameters.items():
param = self.parameterDefinition(key)
if not param.checkValueIsAcceptable(value, context):
return False, "Incorrect parameter value for {}".format(param.name())
return True, None
def icon(self):
return QIcon(os.path.join(pluginPath, 'otb', 'otb.png'))
return QIcon(os.path.join(pluginPath, 'otb', 'providerOtb.svg'))
def createInstance(self):
return self.__class__(self._group, self._name, self._descriptionfile)
......@@ -171,6 +162,12 @@ class OtbAlgorithm(QgsProcessingAlgorithm):
if name in ["elev.dem.geoid", "elev.geoid"]:
param.setDefaultValue(OtbUtils.geoidFile())
# outputpixeltype is a special parameter associated with raster output
# reset list of options to 'self.pixelTypes'.
if name == 'outputpixeltype':
param.setOptions(self.pixelTypes)
param.setDefaultValue(self.pixelTypes.index('float'))
self.addParameter(param)
#parameter is added now and we must move to next line
line = lines.readline().strip('\n').strip()
......@@ -183,17 +180,13 @@ class OtbAlgorithm(QgsProcessingAlgorithm):
def preprocessParameters(self, parameters):
valid_params = {}
for k,v in parameters.items():
for k, v in parameters.items():
param = self.parameterDefinition(k)
#If parameterDefinition(k) return None, this is considered a invalid parameter.
#just continue for loop
if param is None:
continue
#if name of parameter is 'pixtype',
#it is considered valid if it has value other than float
if k == 'outputpixeltype' and self.pixelTypes[int(v)] == 'float':
continue
# Any other valid parameters have:
#- empty or no metadata
#- metadata without a 'group_key'
......@@ -206,50 +199,71 @@ class OtbAlgorithm(QgsProcessingAlgorithm):
return valid_params
def get_value(self, v):
if isinstance(v, QgsMapLayer):
return v.source()
elif isinstance(v, QgsProcessingOutputLayerDefinition):
return v.sink.staticValue()
else:
return str(v)
def outputParameterName(self):
with open(self._descriptionfile) as df:
first_line = df.readline().strip()
tokens = first_line.split("|")
#params = [t if str(t) != str(None) else None for t in tokens[1:]]
if len(tokens) == 2:
return tokens[1]
else:
return ''
def processAlgorithm(self, parameters, context, feedback):
output_key = self.outputParameterName()
otb_cli_file = OtbUtils.cliPath()
command = '"{}" {} {}'.format(otb_cli_file, self.name(), OtbUtils.appFolder())
outputPixelType = None
for k, v in parameters.items():
if k == 'outputpixeltype' or not v:
# if value is None for a parameter we don't have any businees with this key
if v is None:
continue
# for 'outputpixeltype' parameter we find the pixeltype string from self.pixelTypes
if k == 'outputpixeltype':
pixel_type = self.pixelTypes[int(parameters['outputpixeltype'])]
outputPixelType = None if pixel_type == 'float' else pixel_type
continue
if 'epsg' in k and v.startswith('EPSG:'):
v = v.split('EPSG:')[1]
if isinstance(v, str) and '\n' in v:
v = v.split('\n')
if isinstance(v, list):
value = ''
for i in list(filter(None, v)):
value += '"{}" '.format(self.get_value(i))
param = self.parameterDefinition(k)
if param.isDestination():
continue
if isinstance(param, QgsProcessingParameterEnum):
value = self.parameterAsEnum(parameters, param.name(), context)
elif isinstance(param, QgsProcessingParameterBoolean):
value = self.parameterAsBool(parameters, param.name(), context)
elif isinstance(param, QgsProcessingParameterCrs):
crsValue = self.parameterAsCrs(parameters, param.name(), context)
authid = crsValue.authid()
if authid.startswith('EPSG:'):
value = authid.split('EPSG:')[1]
else:
value = '"{}"'.format(self.get_value(v))
if k == output_key and 'outputpixeltype' in parameters:
output_pixel_type = self.pixelTypes[int(parameters['outputpixeltype'])]
value = '"{}" "{}"'.format(value, output_pixel_type)
raise QgsProcessingException(
self.tr("Incorrect value for parameter '{}'. No EPSG code found in '{}'".format(
param.name(),
authid)))
elif isinstance(param, QgsProcessingParameterFile):
value = self.parameterAsFile(parameters, param.name(), context)
elif isinstance(param, QgsProcessingParameterMultipleLayers):
layers = self.parameterAsLayerList(parameters, param.name(), context)
if layers is None or len(layers) == 0:
continue
value = ' '.join(['"{}"'.format(self.getLayerSource(param.name(), layer)) for layer in layers])
elif isinstance(param, QgsProcessingParameterNumber):
if param.dataType() == QgsProcessingParameterNumber.Integer:
value = self.parameterAsInt(parameters, param.name(), context)
else:
value = self.parameterAsDouble(parameters, param.name(), context)
elif isinstance(param, (QgsProcessingParameterRasterLayer, QgsProcessingParameterVectorLayer)):
value = '"{}"'.format(self.getLayerSource(param.name(), self.parameterAsLayer(parameters, param.name(), context)))
elif isinstance(param, QgsProcessingParameterString):
value = '"{}"'.format(self.parameterAsString(parameters, param.name(), context))
else:
# Use whatever is given
value = '"{}"'.format(parameters[param.name()])
# Check if value is set in above if elif ladder and update command string
if value and value is not None:
command += ' -{} {}'.format(k, value)
output_files = {}
for out in self.destinationParameterDefinitions():
filePath = self.parameterAsOutputLayer(parameters, out.name(), context)
output_files[out.name()] = filePath
if outputPixelType is not None:
command += ' -{} "{}" "{}"'.format(out.name(), filePath, outputPixelType)
else:
command += ' -{} "{}"'.format(out.name(), filePath)
QgsMessageLog.logMessage(self.tr('cmd={}'.format(command)), self.tr('Processing'), Qgis.Info)
if not os.path.exists(otb_cli_file) or not os.path.isfile(otb_cli_file):
import errno
......@@ -258,7 +272,16 @@ class OtbAlgorithm(QgsProcessingAlgorithm):
OtbUtils.executeOtb(command, feedback)
result = {}
for out in self.destinationParameterDefinitions():
filePath = self.parameterAsOutputLayer(parameters, out.name(), context)
result[out.name()] = filePath
for o in self.outputDefinitions():
if o.name() in output_files:
result[o.name()] = output_files[o.name()]
return result
def getLayerSource(self, name, layer):
providerName = layer.dataProvider().name()
#TODO: add other provider support in OTB, eg: memory
if providerName in ['ogr', 'gdal']:
return layer.source()
else:
raise QgsProcessingException(
self.tr("OTB currently support only gdal and ogr provider. Parameter '{}' uses '{}' provider".format(name, providerName)))
......@@ -4,10 +4,10 @@
/***************************************************************************
OtbAlgorithmProvider.py
-----------------------
date : 2018-01-30
copyright : (C) 2018 by CNES
email : rkm
***************************************************************************/
Date : 2018-01-30
Copyright : (C) 2018 by CNES
Email : rashad dot kanavath at c-s fr
****************************************************************************/
/***************************************************************************
* *
......@@ -31,28 +31,29 @@ import os
import re
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (Qgis, QgsApplication, QgsProcessingProvider, QgsMessageLog)
from qgis.core import (Qgis, QgsProcessingProvider, QgsMessageLog)
from qgis import utils
from processing.core.ProcessingConfig import ProcessingConfig, Setting
from otb import OtbUtils
from otb.OtbSettings import OtbSettings
from otb.OtbAlgorithm import OtbAlgorithm
pluginPath = os.path.split(os.path.dirname(__file__))[0]
def otb_exe_file(f):
if os.name == 'nt':
return f + '.exe'
else:
return f
class OtbAlgorithmProvider(QgsProcessingProvider):
def __init__(self):
super().__init__()
self.algs = []
#!hack for 6.6!#
self.version = '6.6.0'
self.descriptionFile = ''
def load(self):
group = self.name()
......@@ -117,16 +118,16 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
line = lines.readline().strip('\n').strip()
while line != '' and not line.startswith('#'):
data = line.split('|')
self.descriptionFile = self.descrFile(folder, str(data[1]) + '.txt')
descriptionFile = self.descrFile(folder, str(data[1]) + '.txt')
group, name = str(data[0]), str(data[1])
if name not in alg_names:
algs.append(OtbAlgorithm(group, name, self.descriptionFile))
algs.append(OtbAlgorithm(group, name, descriptionFile))
#avoid duplicate algorithms from algs.txt file (possible but rare)
alg_names.append(name)
line = lines.readline().strip('\n').strip()
except Exception as e:
import traceback
errmsg = "Could not open OTB algorithm from file: \n" + self.descriptionFile + "\nError:\n" + traceback.format_exc()
errmsg = "Could not open OTB algorithm from file: \n" + descriptionFile + "\nError:\n" + traceback.format_exc()
QgsMessageLog.logMessage(self.tr(errmsg), self.tr('Processing'), Qgis.Critical)
return algs
......@@ -152,13 +153,11 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
self.addAlgorithm(a)
self.algs = []
self.create_otbcli()
def create_otbcli(self):
otb_folder = self.normalize_path(OtbUtils.otbFolder())
otb_app_path_env = os.pathsep.join(self.appDirs(OtbUtils.appFolder()))
gdal_data_dir = None
geotiff_csv_dir = None
otbcli_path = OtbUtils.cliPath()
try:
if os.name == 'nt':
app_vargs = " %*"
......@@ -168,12 +167,13 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
gdal_data_dir = os.path.join(otb_folder, 'share', 'data')
geotiff_csv_dir = os.path.join(otb_folder, 'share', 'epsg_csv')
else:
app_vargs = " $@"
app_vargs = " \"$@\""
export_cmd = 'export '
first_line = '#!/bin/sh'
otb_app_launcher = os.path.join(otb_folder, 'bin', 'otbApplicationLauncherCommandLine')
lines = None
env_profile = os.path.join(otb_folder, 'otbenv.profile')
if os.path.exists(env_profile):
with open(env_profile) as f:
lines = f.readlines()
lines = [x.strip() for x in lines]
......@@ -184,8 +184,6 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
gdal_data_dir = line.split("GDAL_DATA=")[1]
if 'GEOTIFF_CSV='in line:
geotiff_csv_dir = line.split("GEOTIFF_CSV=")[1]
otbcli_path = OtbUtils.cliPath()
with open(otbcli_path, 'w') as otb_cli_file:
otb_cli_file.write(first_line + os.linesep)
otb_cli_file.write(export_cmd + "LC_NUMERIC=C" + os.linesep)
......@@ -195,10 +193,10 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
if geotiff_csv_dir:
otb_cli_file.write(export_cmd + "GEOTIFF_CSV=" + "\"" + geotiff_csv_dir + "\"" + os.linesep)
if OtbUtils.loggerLevel():
otb_cli_file.write(export_cmd + "OTB_LOGGER_LEVEL=" + "\"" + OtbUtils.loggerLevel() + "\"" + os.linesep)
otb_cli_file.write(export_cmd + "OTB_LOGGER_LEVEL=" + OtbUtils.loggerLevel() + os.linesep)
max_ram_hint = OtbUtils.maxRAMHint()
if max_ram_hint and not int(max_ram_hint) == 128 :
otb_cli_file.write(export_cmd + "OTB_MAX_RAM_HINT=" + "\"" + max_ram_hint + "\"" + os.linesep)
if max_ram_hint and not int(max_ram_hint) == 128:
otb_cli_file.write(export_cmd + "OTB_MAX_RAM_HINT=" + max_ram_hint + os.linesep)
otb_cli_file.write(export_cmd + "OTB_APPLICATION_PATH=" + "\"" + otb_app_path_env + "\"" + os.linesep)
otb_cli_file.write("\"" + otb_app_launcher + "\"" + app_vargs + os.linesep)
......@@ -267,6 +265,8 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
OtbUtils.executeOtb(commands, feedback=None)
if isValid:
# if check needed for testsing
if utils.iface is not None:
utils.iface.messageBar().pushInfo("OTB", "OTB provider is activated from '{}'.".format(folder))
else:
self.setActive(False)
......@@ -301,12 +301,8 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
return os.path.join(self.descrFolder(d), f)
def appDirs(self, v):
#!hack needed for QGIS < 3.2!#
v = v.replace(';', os.pathsep)
#!hack needed for QGIS < 3.2!#
folders = v.split(os.pathsep)
app_dirs = []
for f in folders:
for f in v.split(';'):
if f is not None and os.path.exists(f):
app_dirs.append(self.normalize_path(f))
return app_dirs
......@@ -328,7 +324,7 @@ class OtbAlgorithmProvider(QgsProcessingProvider):
def icon(self):
pluginPath = os.path.split(os.path.dirname(__file__))[0]
return QIcon(os.path.join(pluginPath, 'otb', 'otb.png'))
return QIcon(os.path.join(pluginPath, 'otb', 'providerOtb.svg'))
def tr(self, string, context=''):
if context == '':
......
......@@ -33,6 +33,7 @@ from processing.gui.wrappers import (WidgetWrapper,
DIALOG_BATCH,
DIALOG_MODELER)
class OtbChoiceWidgetWrapper(WidgetWrapper):
def createWidget(self):
widget = QComboBox()
......@@ -123,8 +124,10 @@ class OtbChoiceWidgetWrapper(WidgetWrapper):
if wrapper.wrappedLabel():
wrapper.wrappedLabel().setVisible(v)
from qgis.core import QgsProcessingParameterDefinition
class OtbParameterChoice(QgsProcessingParameterDefinition):
def __init__(self, name='', description='', options=[], default=None, isSource=False,
......@@ -154,4 +157,3 @@ class OtbParameterChoice(QgsProcessingParameterDefinition):
def type(self):
#This value is written by otbQgisDescriptor.
return 'OTBParameterChoice'
......@@ -18,6 +18,7 @@ __copyright__ = '(C) CNES 2019'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
class OtbSettings(object):
"""
OtbSetting's key names
......@@ -57,4 +58,3 @@ class OtbSettings(object):
OtbSettings.LOGGER_LEVEL,
OtbSettings.MAX_RAM_HINT
]
......@@ -39,25 +39,32 @@ from qgis.core import (Qgis, QgsApplication, QgsMessageLog)
from qgis.PyQt.QtCore import QCoreApplication
from otb.OtbSettings import OtbSettings
def cliPath():
cli_ext = '.bat' if os.name == 'nt' else ''
return os.path.normpath(os.path.join(QgsApplication.qgisSettingsDirPath(),
'processing', 'qgis_otb_cli' + cli_ext))
def version():
return ProcessingConfig.getSetting(OtbSettings.VERSION) or '0.0.0'
def loggerLevel():
return ProcessingConfig.getSetting(OtbSettings.LOGGER_LEVEL) or 'INFO'
def maxRAMHint():
return ProcessingConfig.getSetting(OtbSettings.MAX_RAM_HINT) or ''
def otbFolder():
if ProcessingConfig.getSetting(OtbSettings.FOLDER):
return os.path.normpath(os.sep.join(re.split(r'\\|/', ProcessingConfig.getSetting(OtbSettings.FOLDER))))
else:
return None
def appFolder():
app_folder = ProcessingConfig.getSetting(OtbSettings.APP_FOLDER)
if app_folder:
......@@ -65,17 +72,19 @@ def appFolder():
else:
return None
def srtmFolder():
return ProcessingConfig.getSetting(OtbSettings.SRTM_FOLDER) or ''
def geoidFile():
return ProcessingConfig.getSetting(OtbSettings.GEOID_FILE) or ''
def executeOtb(commands, feedback, addToLog=True):
loglines = []
def executeOtb(command, feedback, addToLog=True):
loglines = []
with subprocess.Popen(
commands,
[command],
shell=True,
stdout=subprocess.PIPE,
stdin=subprocess.DEVNULL,
......@@ -115,6 +124,7 @@ def executeOtb(commands, feedback, addToLog=True):
# else:
# feedback.pushConsoleInfo(logline)
def tr(string, context=''):
if context == '':
context = 'OtbUtils'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment