1# -*- coding: utf-8 -*-
2
3"""
4***************************************************************************
5    rasterize.py
6    ---------------------
7    Date                 : September 2013
8    Copyright            : (C) 2013 by Alexander Bruy
9    Email                : alexander dot bruy at gmail dot com
10***************************************************************************
11*                                                                         *
12*   This program is free software; you can redistribute it and/or modify  *
13*   it under the terms of the GNU General Public License as published by  *
14*   the Free Software Foundation; either version 2 of the License, or     *
15*   (at your option) any later version.                                   *
16*                                                                         *
17***************************************************************************
18"""
19
20__author__ = 'Alexander Bruy'
21__date__ = 'September 2013'
22__copyright__ = '(C) 2013, Alexander Bruy'
23
24import os
25
26from qgis.PyQt.QtCore import QVariant
27from qgis.PyQt.QtGui import QIcon
28
29from qgis.core import (QgsRasterFileWriter,
30                       QgsProcessingParameterDefinition,
31                       QgsProcessingParameterFeatureSource,
32                       QgsProcessingParameterField,
33                       QgsProcessingParameterRasterLayer,
34                       QgsProcessingParameterNumber,
35                       QgsProcessingParameterString,
36                       QgsProcessingParameterEnum,
37                       QgsProcessingParameterExtent,
38                       QgsProcessingParameterBoolean,
39                       QgsProcessingParameterRasterDestination)
40from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
41from processing.algs.gdal.GdalUtils import GdalUtils
42
43pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
44
45
46class rasterize(GdalAlgorithm):
47    INPUT = 'INPUT'
48    FIELD = 'FIELD'
49    BURN = 'BURN'
50    USE_Z = 'USE_Z'
51    WIDTH = 'WIDTH'
52    HEIGHT = 'HEIGHT'
53    UNITS = 'UNITS'
54    NODATA = 'NODATA'
55    EXTENT = 'EXTENT'
56    INIT = 'INIT'
57    INVERT = 'INVERT'
58    ALL_TOUCH = 'ALL_TOUCH'
59    OPTIONS = 'OPTIONS'
60    DATA_TYPE = 'DATA_TYPE'
61    EXTRA = 'EXTRA'
62    OUTPUT = 'OUTPUT'
63
64    TYPES = ['Byte', 'Int16', 'UInt16', 'UInt32', 'Int32', 'Float32', 'Float64', 'CInt16', 'CInt32', 'CFloat32', 'CFloat64']
65
66    def __init__(self):
67        super().__init__()
68
69    def initAlgorithm(self, config=None):
70        self.units = [self.tr("Pixels"),
71                      self.tr("Georeferenced units")]
72
73        self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
74                                                              self.tr('Input layer')))
75        self.addParameter(QgsProcessingParameterField(self.FIELD,
76                                                      self.tr('Field to use for a burn-in value'),
77                                                      None,
78                                                      self.INPUT,
79                                                      QgsProcessingParameterField.Numeric,
80                                                      optional=True))
81        self.addParameter(QgsProcessingParameterNumber(self.BURN,
82                                                       self.tr('A fixed value to burn'),
83                                                       type=QgsProcessingParameterNumber.Double,
84                                                       defaultValue=0.0,
85                                                       optional=True))
86        self.addParameter(QgsProcessingParameterBoolean(self.USE_Z,
87                                                        self.tr('Burn value extracted from the "Z" values of the feature'),
88                                                        defaultValue=False,
89                                                        optional=True))
90        self.addParameter(QgsProcessingParameterEnum(self.UNITS,
91                                                     self.tr('Output raster size units'),
92                                                     self.units))
93        self.addParameter(QgsProcessingParameterNumber(self.WIDTH,
94                                                       self.tr('Width/Horizontal resolution'),
95                                                       type=QgsProcessingParameterNumber.Double,
96                                                       minValue=0.0,
97                                                       defaultValue=0.0))
98        self.addParameter(QgsProcessingParameterNumber(self.HEIGHT,
99                                                       self.tr('Height/Vertical resolution'),
100                                                       type=QgsProcessingParameterNumber.Double,
101                                                       minValue=0.0,
102                                                       defaultValue=0.0))
103        self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
104                                                       self.tr('Output extent')))
105        nodataParam = QgsProcessingParameterNumber(self.NODATA,
106                                                   self.tr('Assign a specified nodata value to output bands'),
107                                                   type=QgsProcessingParameterNumber.Double,
108                                                   optional=True)
109        nodataParam.setGuiDefaultValueOverride(QVariant(QVariant.Double))
110        self.addParameter(nodataParam)
111
112        options_param = QgsProcessingParameterString(self.OPTIONS,
113                                                     self.tr('Additional creation options'),
114                                                     defaultValue='',
115                                                     optional=True)
116        options_param.setFlags(options_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
117        options_param.setMetadata({
118            'widget_wrapper': {
119                'class': 'processing.algs.gdal.ui.RasterOptionsWidget.RasterOptionsWidgetWrapper'}})
120        self.addParameter(options_param)
121
122        dataType_param = QgsProcessingParameterEnum(self.DATA_TYPE,
123                                                    self.tr('Output data type'),
124                                                    self.TYPES,
125                                                    allowMultiple=False,
126                                                    defaultValue=5)
127        dataType_param.setFlags(dataType_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
128        self.addParameter(dataType_param)
129
130        init_param = QgsProcessingParameterNumber(self.INIT,
131                                                  self.tr('Pre-initialize the output image with value'),
132                                                  type=QgsProcessingParameterNumber.Double,
133                                                  optional=True)
134        init_param.setFlags(init_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
135        self.addParameter(init_param)
136
137        invert_param = QgsProcessingParameterBoolean(self.INVERT,
138                                                     self.tr('Invert rasterization'),
139                                                     defaultValue=False)
140        invert_param.setFlags(invert_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
141        self.addParameter(invert_param)
142
143        extra_param = QgsProcessingParameterString(self.EXTRA,
144                                                   self.tr('Additional command-line parameters'),
145                                                   defaultValue=None,
146                                                   optional=True)
147        extra_param.setFlags(extra_param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
148        self.addParameter(extra_param)
149
150        self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
151                                                                  self.tr('Rasterized')))
152
153    def name(self):
154        return 'rasterize'
155
156    def displayName(self):
157        return self.tr('Rasterize (vector to raster)')
158
159    def group(self):
160        return self.tr('Vector conversion')
161
162    def groupId(self):
163        return 'vectorconversion'
164
165    def icon(self):
166        return QIcon(os.path.join(pluginPath, 'images', 'gdaltools', 'rasterize.png'))
167
168    def commandName(self):
169        return 'gdal_rasterize'
170
171    def getConsoleCommands(self, parameters, context, feedback, executing=True):
172        ogrLayer, layerName = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
173
174        arguments = [
175            '-l',
176            layerName
177        ]
178        fieldName = self.parameterAsString(parameters, self.FIELD, context)
179        use_z = self.parameterAsBoolean(parameters, self.USE_Z, context)
180        if use_z:
181            arguments.append('-3d')
182        elif fieldName:
183            arguments.append('-a')
184            arguments.append(fieldName)
185        else:
186            arguments.append('-burn')
187            arguments.append(self.parameterAsDouble(parameters, self.BURN, context))
188
189        units = self.parameterAsEnum(parameters, self.UNITS, context)
190        if units == 0:
191            arguments.append('-ts')
192        else:
193            arguments.append('-tr')
194        arguments.append(self.parameterAsDouble(parameters, self.WIDTH, context))
195        arguments.append(self.parameterAsDouble(parameters, self.HEIGHT, context))
196
197        if self.INIT in parameters and parameters[self.INIT] is not None:
198            initValue = self.parameterAsDouble(parameters, self.INIT, context)
199            arguments.append('-init')
200            arguments.append(initValue)
201
202        if self.parameterAsBoolean(parameters, self.INVERT, context):
203            arguments.append('-i')
204
205        if self.parameterAsBoolean(parameters, self.ALL_TOUCH, context):
206            arguments.append('-at')
207
208        if self.NODATA in parameters and parameters[self.NODATA] is not None:
209            nodata = self.parameterAsDouble(parameters, self.NODATA, context)
210            arguments.append('-a_nodata')
211            arguments.append(nodata)
212
213        extent = self.parameterAsExtent(parameters, self.EXTENT, context)
214        if not extent.isNull():
215            arguments.append('-te')
216            arguments.append(extent.xMinimum())
217            arguments.append(extent.yMinimum())
218            arguments.append(extent.xMaximum())
219            arguments.append(extent.yMaximum())
220
221        arguments.append('-ot')
222        arguments.append(self.TYPES[self.parameterAsEnum(parameters, self.DATA_TYPE, context)])
223
224        out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
225        self.setOutputValue(self.OUTPUT, out)
226        arguments.append('-of')
227        arguments.append(QgsRasterFileWriter.driverForExtension(os.path.splitext(out)[1]))
228
229        options = self.parameterAsString(parameters, self.OPTIONS, context)
230        if options:
231            arguments.extend(GdalUtils.parseCreationOptions(options))
232
233        if self.EXTRA in parameters and parameters[self.EXTRA] not in (None, ''):
234            extra = self.parameterAsString(parameters, self.EXTRA, context)
235            arguments.append(extra)
236
237        arguments.append(ogrLayer)
238        arguments.append(out)
239
240        return [self.commandName(), GdalUtils.escapeAndJoin(arguments)]
241