def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY) wkb_type = None if geometry_type == 0: wkb_type = QgsWkbTypes.Polygon elif geometry_type == 1: wkb_type = QgsWkbTypes.LineString else: wkb_type = QgsWkbTypes.Point if self.getParameterValue(self.WITH_Z): wkb_type = QgsWkbTypes.addZ(wkb_type) if self.getParameterValue(self.WITH_M): wkb_type = QgsWkbTypes.addM(wkb_type) writer = self.getOutputFromName( self.OUTPUT_LAYER).getVectorWriter( layer.fields(), wkb_type, layer.crs()) expression = QgsExpression(self.getParameterValue(self.EXPRESSION)) if expression.hasParserError(): raise GeoAlgorithmExecutionException(expression.parserErrorString()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not expression.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % expression.evalErrorString())) features = vector.features(layer) total = 100.0 / len(features) for current, input_feature in enumerate(features): output_feature = input_feature exp_context.setFeature(input_feature) value = expression.evaluate(exp_context) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % expression.evalErrorString())) if not value: output_feature.setGeometry(QgsGeometry()) else: if not isinstance(value, QgsGeometry): raise GeoAlgorithmExecutionException( self.tr('{} is not a geometry').format(value)) output_feature.setGeometry(value) writer.addFeature(output_feature) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context) geometry_type = self.getParameterValue(self.OUTPUT_GEOMETRY) wkb_type = None if geometry_type == 0: wkb_type = QgsWkbTypes.Polygon elif geometry_type == 1: wkb_type = QgsWkbTypes.LineString else: wkb_type = QgsWkbTypes.Point if self.getParameterValue(self.WITH_Z): wkb_type = QgsWkbTypes.addZ(wkb_type) if self.getParameterValue(self.WITH_M): wkb_type = QgsWkbTypes.addM(wkb_type) writer = self.getOutputFromName( self.OUTPUT_LAYER).getVectorWriter(layer.fields(), wkb_type, layer.crs(), context) expression = QgsExpression(self.getParameterValue(self.EXPRESSION)) if expression.hasParserError(): raise GeoAlgorithmExecutionException(expression.parserErrorString()) exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer)) if not expression.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: {0}').format(expression.evalErrorString())) features = QgsProcessingUtils.getFeatures(layer, context) total = 100.0 / QgsProcessingUtils.featureCount(layer, context) for current, input_feature in enumerate(features): output_feature = input_feature exp_context.setFeature(input_feature) value = expression.evaluate(exp_context) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: {0}').format(expression.evalErrorString())) if not value: output_feature.setGeometry(QgsGeometry()) else: if not isinstance(value, QgsGeometry): raise GeoAlgorithmExecutionException( self.tr('{} is not a geometry').format(value)) output_feature.setGeometry(value) writer.addFeature(output_feature) feedback.setProgress(int(current * total)) del writer
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)] width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) new_field = self.parameterAsBool(parameters, self.NEW_FIELD, context) formula = self.parameterAsString(parameters, self.FORMULA, context) expression = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs()) da.setEllipsoid(context.project().ellipsoid()) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) fields = source.fields() field_index = fields.lookupField(field_name) if new_field or field_index < 0: fields.append(QgsField(field_name, field_type, '', width, precision)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) exp_context = self.createExpressionContext(parameters, context) if layer is not None: exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not expression.prepare(exp_context): raise QgsProcessingException( self.tr('Evaluation error: {0}').format(expression.parserErrorString())) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): feedback.reportError(expression.evalErrorString()) else: attrs = f.attributes() if new_field or field_index < 0: attrs.append(value) else: attrs[field_index] = value f.setAttributes(attrs) sink.addFeature(f, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def testAutoArgsAreExpanded(self): function = self.expandargs args = function.params() self.assertEqual(args, 3) values = [1, 2, 3] exp = QgsExpression("") result = function.func(values, None, exp, None) # Make sure there is no eval error self.assertEqual(exp.evalErrorString(), "") self.assertEqual(result, (1, 2, 3))
def where(layer, exp): exp = QgsExpression(exp) if exp.hasParserError(): raise Exception(exp.parserErrorString()) exp.prepare(layer.pendingFields()) for feature in layer.getFeatures(): value = exp.evaluate(feature) if exp.hasEvalError(): raise ValueError(exp.evalErrorString()) if bool(value): yield feature
def evaluateExpression(self, text): context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope()) exp = QgsExpression(text) if exp.hasParserError(): raise Exception(exp.parserErrorString()) result = exp.evaluate(context) if exp.hasEvalError(): raise ValueError(exp.evalErrorString()) return result
def layer_value(feature, layer, defaultconfig): if not canvas: roam.utils.warning("No canvas set for using layer_values default function") return None layers = [] # layer name can also be a list of layers to search layername = defaultconfig['layer'] if isinstance(layername, basestring): layers.append(layername) else: layers = layername expression = defaultconfig['expression'] field = defaultconfig['field'] for searchlayer in layers: try: searchlayer = QgsMapLayerRegistry.instance().mapLayersByName(searchlayer)[0] except IndexError: RoamEvents.raisemessage("Missing layer", "Unable to find layer used in widget expression {}".format(searchlayer), level=1) roam.utils.warning("Unable to find expression layer {}".format(searchlayer)) return if feature.geometry(): rect = feature.geometry().boundingBox() if layer.geometryType() == QGis.Point: point = feature.geometry().asPoint() rect = QgsRectangle(point.x(), point.y(), point.x() + 10, point.y() + 10) rect.scale(20) rect = canvas.mapRenderer().mapToLayerCoordinates(layer, rect) rq = QgsFeatureRequest().setFilterRect(rect)\ .setFlags(QgsFeatureRequest.ExactIntersect) features = searchlayer.getFeatures(rq) else: features = searchlayer.getFeatures() exp = QgsExpression(expression) exp.prepare(searchlayer.pendingFields()) if exp.hasParserError(): error = exp.parserErrorString() roam.utils.warning(error) for f in features: value = exp.evaluate(f) if exp.hasEvalError(): error = exp.evalErrorString() roam.utils.warning(error) if value: return f[field] raise DefaultError('No features found')
def where(self, exp): '''Request feature by QgsExpression Usage : for feat in layer.where("myfield" = 2): ... ''' exp = QgsExpression(exp) if exp.hasParserError(): raise Exception(exp.parserErrorString()) if exp.hasEvalError(): raise ValueError(exp.evalErrorString()) return self.getFeatures(QgsFeatureRequest(exp))
def calculate( self, layer, fieldName, expression ): if ( layer.featureCount() == 0 ): self.msg.show( "[Info] * No existing features on layer " + layer.name() + " to calculate expression.", 'info', True ) return expression = QgsExpression( expression ) if expression.hasParserError(): self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Parsing) " ) + \ expression.parserErrorString(), 'critical' ) return context = QgsExpressionContext() context.appendScope( QgsExpressionContextUtils.globalScope() ) context.appendScope( QgsExpressionContextUtils.projectScope() ) context.appendScope( QgsExpressionContextUtils.layerScope( layer ) ) context.setFields( layer.fields() ) if expression.needsGeometry(): if self.iface: # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py da = QgsDistanceArea() da.setSourceCrs( layer.crs().srsid() ) da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() ) da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] ) expression.setGeomCalculator( da ) if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14 expression.setDistanceUnits( QgsProject.instance().distanceUnits() ) expression.setAreaUnits( QgsProject.instance().areaUnits() ) expression.prepare( context ) fieldIndex = layer.fieldNameIndex( fieldName ) if fieldIndex == -1: return field = layer.fields()[fieldIndex] dictResults = {} for feature in layer.getFeatures(): context.setFeature( feature ) result = expression.evaluate( context ) if expression.hasEvalError(): self.msg.show( QApplication.translate( "AutoFields-FieldCalculator", "[Error] (Evaluating) " ) + \ expression.evalErrorString(), 'critical' ) return dictResults[feature.id()] = { fieldIndex: field.convertCompatible( result ) } layer.dataProvider().changeAttributeValues( dictResults ) self.msg.show( "[Info] * An expression was calculated on existing features of layer " + layer.name() + ", field " + fieldName + ".", 'info', True )
def testExpression(self, row): self._errors[row] = None field = self._mapping[row] expression = QgsExpression(field['expression']) if expression.hasParserError(): self._errors[row] = expression.parserErrorString() return if self._layer is None: return dp = self._layer.dataProvider() for feature in dp.getFeatures(): expression.evaluate(feature, dp.fields()) if expression.hasEvalError(): self._errors[row] = expression.evalErrorString() return break
def testExpression(self, row): self._errors[row] = None field = self._mapping[row] expression = QgsExpression(field['expression']) if expression.hasParserError(): self._errors[row] = expression.parserErrorString() return if self._layer is None: return context = QgsExpressionContextUtils.createFeatureBasedContext(QgsFeature(), self._layer.fields()) for feature in self._layer.getFeatures(): context.setFeature(feature) expression.evaluate(context) if expression.hasEvalError(): self._errors[row] = expression.evalErrorString() return break
def testExpression(self, row): self._errors[row] = None field = self._mapping[row] exp_context = self.contextGenerator().createExpressionContext() expression = QgsExpression(field['expression']) expression.prepare(exp_context) if expression.hasParserError(): self._errors[row] = expression.parserErrorString() return # test evaluation on the first feature if self._layer is None: return for feature in self._layer.getFeatures(): exp_context.setFeature(feature) exp_context.lastScope().setVariable("row_number", 1) expression.evaluate(exp_context) if expression.hasEvalError(): self._errors[row] = expression.evalErrorString() break
def processAlgorithm(self, parameters, context, feedback): path = self.parameterAsFile(parameters, self.INPUT, context) t_file = self.parameterAsVectorLayer( parameters, self.FILE_TABLE, context ) t_troncon = self.parameterAsVectorLayer( parameters, self.SEGMENT_TABLE, context ) t_obs = self.parameterAsVectorLayer( parameters, self.OBSERVATIONS_TABLE, context ) t_regard = self.parameterAsVectorLayer( parameters, self.MANHOLES_TABLE, context ) paths = path.split(';') if len(paths) != 1: raise QgsProcessingException( tr('* ERREUR: 1 fichier a la fois {}.').format(path) ) if not os.path.exists(path): raise QgsProcessingException( tr('* ERREUR: {} n\'existe pas.').format(path) ) # add date fields to itv file table # relation_aggregate( # 'itv_tronco_id_file_itv_file20_id', # 'max', # "abf" # ) if 'date_debut' not in t_file.dataProvider().fields().names(): with edit(t_file): res = t_file.dataProvider().addAttributes([ QgsField("date_debut", QVariant.String), QgsField("date_fin", QVariant.String) ]) if res: t_file.updateFields() feat_file = None with open(path, 'rb') as f: basename = os.path.basename(path) md = hashlib.md5() md.update(f.read()) hashcontent = md.hexdigest() feat_file = QgsVectorLayerUtils.createFeature(t_file) feat_file.setAttribute('basename', basename) feat_file.setAttribute('hashcontent', hashcontent) if not feat_file: raise QgsProcessingException( tr( '* ERREUR: le fichier {} n\'a pas été lu ' 'correctement.' ).format(path) ) exp_context = QgsExpressionContext() exp_context.appendScope( QgsExpressionContextUtils.globalScope() ) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project()) ) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_file) ) exp_str = QgsExpression.createFieldEqualityExpression( 'basename', feat_file['basename'] ) + ' AND ' + QgsExpression.createFieldEqualityExpression( 'hashcontent', feat_file['hashcontent'] ) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString() ) ) request = QgsFeatureRequest(exp, exp_context) request.setLimit(1) for _t in t_file.getFeatures(request): raise QgsProcessingException( tr('* ERREUR: le fichier {} a deja ete lu').format( path ) ) exp_str = QgsExpression.createFieldEqualityExpression( 'hashcontent', feat_file['hashcontent'] ) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( (exp.expression(), exp.evalErrorString()) ) ) request = QgsFeatureRequest(exp, exp_context) request.setLimit(1) for _t in t_file.getFeatures(request): raise QgsProcessingException( tr( '* ERREUR: le fichier {} semble deja avoir ete lu' ).format(path) ) exp_context = QgsExpressionContext() exp_context.appendScope( QgsExpressionContextUtils.globalScope() ) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project()) ) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_troncon) ) exp_str = 'maximum("id")' exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr( '* ERROR: Expression {} has eval error: {}' ).format(exp.expression(), exp.evalErrorString()) ) last_t_id = exp.evaluate(exp_context) if not last_t_id: last_t_id = 0 exp_context = QgsExpressionContext() exp_context.appendScope( QgsExpressionContextUtils.globalScope() ) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project()) ) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_regard) ) exp_str = 'maximum("id")' exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr( '* ERROR: Expression {} has eval error: {}' ).format(exp.expression(), exp.evalErrorString()) ) last_r_id = exp.evaluate(exp_context) if not last_r_id: last_r_id = 0 # lecture des entetes ENCODING = 'ISO-8859-1' LANG = 'fr' DELIMITER = ',' DECIMAL = '.' QUOTECHAR = '"' VERSION = '' with open(path, 'rb') as f: for line in f: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} try: line = line.decode() except UnicodeDecodeError: raise QgsProcessingException( 'Error while reading {}'.format(path) ) # remove break line line = line.replace('\n', '').replace('\r', '') if line.startswith('#'): if line.startswith('#A'): if line.startswith('#A1'): ENCODING = line[4:] if ENCODING.find(':') != -1: ENCODING = ENCODING[:ENCODING.find(':')] elif line.startswith('#A2'): LANG = line[4:] elif line.startswith('#A3'): DELIMITER = line[4:] elif line.startswith('#A4'): DECIMAL = line[4:] elif line.startswith('#A5'): QUOTECHAR = line[4:] else: break # Dialect CSV pour la lecture des tableaux de valeurs du # fichier d'ITV class itvDialect(csv.Dialect): strict = True skipinitialspace = True quoting = csv.QUOTE_MINIMAL delimiter = DELIMITER quotechar = QUOTECHAR lineterminator = '\r\n' # Liste des troncons, observations et regards troncons = [] regards = [] observations = [] # Lectures des donnees with open(path, 'rb') as f: # Identifiant de départ t_id = last_t_id r_id = last_r_id # Entête header = [] # Nom du tableau array = '' # Observations de troncons ? obs_for_troncon = False # initialisation du Dialect CSV pour ITV dia = itvDialect() # Lecture ligne à ligne du fichier for line in f: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} # Decoding line en utilisant l'encoding du fichier line = line.decode(ENCODING) # remove break line line = line.replace('\n', '').replace('\r', '') # Ligne commençant par un # est une ligne d'entête if line.startswith('#'): # Entête de troncon ou regard if line.startswith('#B'): l_b = io.StringIO(line[5:]) for l_r in csv.reader(l_b, dia): header = l_r break array = line[1:4] continue # Entête d'observation elif line.startswith('#C'): if header[0].startswith('A'): obs_for_troncon = True else: obs_for_troncon = False l_b = io.StringIO(line[3:]) for l_r in csv.reader(l_b, dia): header = l_r break array = line[1:2] continue # Fin d'observation elif line.startswith('#Z'): header = [] array = '' obs_for_troncon = False continue # La ligne contient des donnees else: if not header: # an error in the file structure continue l_b = io.StringIO(line) for l_r in csv.reader(l_b, dia): data = l_r row = list( zip( [h.lower() for h in header], [t for t in data] ) ) # observation if array == 'C': if obs_for_troncon: observations.append( row + [('id_troncon', t_id)] ) # Premiere ligne de description d'un troncon ou regard elif array == 'B01': if header[0].startswith('A'): t_id += 1 troncons.append([('id', t_id)] + row) elif header[0].startswith('C'): r_id += 1 regards.append([('id', r_id)] + row) # Ligne complémentaire de description else: if header[0].startswith('A'): troncons[-1] += row elif header[0].startswith('C'): regards[-1] += row # Recuperation des references de noeuds et dates itv_dates = [] regard_node_refs = [] regard_ref_id = {} max_r_id = last_r_id for reg in regards: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} d_rg = dict(reg) if d_rg['caa'] and d_rg['caa'] not in regard_node_refs: regard_node_refs.append(d_rg['caa']) regard_ref_id[d_rg['caa']] = d_rg['id'] if d_rg['id'] and d_rg['id'] > max_r_id: max_r_id = d_rg['id'] if 'cbf' in d_rg and d_rg['cbf'] not in itv_dates: itv_dates.append(d_rg['cbf']) node_refs = [] for tro in troncons: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} d_tr = dict(tro) # The nodes ref are stored in AAB, AAD, AAF and AAT if 'aab' in d_tr and \ d_tr['aab'] and \ d_tr['aab'] not in regard_node_refs and \ d_tr['aab'] not in node_refs: node_refs.append(d_tr['aab']) if 'aad' in d_tr and \ d_tr['aad'] and \ d_tr['aad'] not in regard_node_refs and \ d_tr['aad'] not in node_refs: node_refs.append(d_tr['aad']) if 'aaf' in d_tr and \ d_tr['aaf'] and \ d_tr['aaf'] not in regard_node_refs and \ d_tr['aaf'] not in node_refs: node_refs.append(d_tr['aaf']) if 'aat' in d_tr and \ d_tr['aat'] and \ d_tr['aat'] not in regard_node_refs and \ d_tr['aat'] not in node_refs: node_refs.append(d_tr['aat']) if 'abf' in d_tr and d_tr['abf'] not in itv_dates: itv_dates.append(d_tr['abf']) # Ajout des regards manquant for n_ref in node_refs: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} max_r_id += 1 regards.append([('id', max_r_id), ('caa', n_ref)]) regard_ref_id[n_ref] = max_r_id # Ajout des identifiants de regards aux tronçons regard_refs = regard_ref_id.keys() for tro in troncons: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} d_tr = dict(tro) # If AAD is not defined then it is equal to AAB if 'aad' not in d: d['aad'] = d['aab'] if d_tr['aad'] and \ d_tr['aad'] in regard_refs: tro += [('id_regard1', regard_ref_id[d_tr['aad']])] if d_tr['aaf'] and \ d_tr['aaf'] in regard_refs: tro += [('id_regard2', regard_ref_id[d_tr['aaf']])] if 'aat' in d_tr.keys() and \ d_tr['aat'] and \ d_tr['aat'] in regard_refs: tro += [('id_regard3', regard_ref_id[d_tr['aat']])] # Verification des champs fields = provider_fields(t_troncon.fields()) for tro in troncons: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} for key, val in tro: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} if fields.indexOf(key) == -1: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de tronçon "{}" est inconnue' ).format(key) ) field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: try: float(val.replace(DECIMAL, '.')) except BaseException: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de tronçon "{}" est ' 'numérique mais pas la valeur "{}"' ).format(key, val) ) fields = provider_fields(t_obs.fields()) for obs in observations: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} for key, val in obs: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} if fields.indexOf(key) == -1: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs d\'observation "{}" est ' 'inconnue' ).format(key) ) field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: try: float(val.replace(DECIMAL, '.')) except BaseException: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs d\'observation "{}" est ' 'numérique mais pas la valeur "{}"' ).format(key, val) ) fields = provider_fields(t_regard.fields()) for reg in regards: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} for key, val in reg: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} if fields.indexOf(key) == -1: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de regard "{}" est inconnue' ).format(key) ) field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: try: float(val.replace(DECIMAL, '.')) except BaseException: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de regard "{}" est ' 'numérique mais pas la valeur "{}"' ).format(key, val) ) # Finalisation objet fichier feat_file.setAttribute('encoding', ENCODING) feat_file.setAttribute('lang', LANG) if VERSION: feat_file.setAttribute('version', VERSION) if itv_dates: feat_file.setAttribute('date_debut', min(itv_dates)) feat_file.setAttribute('date_fin', max(itv_dates)) # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} # Ajout de l'objet fichier t_file.startEditing() (res, outFeats) = t_file.dataProvider().addFeatures([feat_file]) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement du fichier {}' ).format(', '.join(t_file.dataProvider().errors())) ) if not t_file.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format(t_file.commitErrors()) ) # Mise a jour de l'identifiant de l'objet fichier feat_file.setAttribute('id', outFeats[0]['id']) # Creation des objets troncons features = [] fields = provider_fields(t_troncon.fields()) for tro in troncons: feat_t = QgsVectorLayerUtils.createFeature(t_troncon) feat_t.setAttribute('id_file', feat_file['id']) for key, val in tro: field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: feat_t.setAttribute( key, float(val.replace(DECIMAL, '.')) ) else: feat_t.setAttribute(key, val) features.append(feat_t) # Ajout des objets troncons if features: t_troncon.startEditing() (res, outFeats) = t_troncon.dataProvider().addFeatures(features) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement ' 'des troncon {}' ).format( ', '.join(t_troncon.dataProvider().errors()) ) ) if not t_troncon.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format( t_troncon.commitErrors() ) ) # Creation des objets observations features = [] fields = provider_fields(t_obs.fields()) for obs in observations: feat_o = QgsVectorLayerUtils.createFeature(t_obs) feat_o.setAttribute('id_file', feat_file['id']) for key, val in obs: field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: feat_o.setAttribute( key, float(val.replace(DECIMAL, '.')) ) else: feat_o.setAttribute(key, val) features.append(feat_o) # Ajout des objets observations if features: t_obs.startEditing() (res, outFeats) = t_obs.dataProvider().addFeatures(features) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement ' 'des observations {}' ).format( ', '.join(t_obs.dataProvider().errors()) ) ) if not t_obs.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format( t_obs.commitErrors() ) ) # Creation des objets regards features = [] fields = provider_fields(t_regard.fields()) for reg in regards: feat_r = QgsVectorLayerUtils.createFeature(t_regard) feat_r.setAttribute('id_file', feat_file['id']) for key, val in reg: field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: feat_r.setAttribute( key, float(val.replace(DECIMAL, '.')) ) else: feat_r.setAttribute(key, val) features.append(feat_r) # Ajout des objets regards if features: t_regard.startEditing() (res, outFeats) = t_regard.dataProvider().addFeatures( features ) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement ' 'des regards {}' ).format( ', '.join(t_regard.dataProvider().errors()) ) ) if not t_regard.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit %s.').format( t_regard.commitErrors() ) ) # Returns empty dict if no outputs return {self.SUCCESS: 1}
def evaluate(self, params: Dict[str, str], response: QgsServerResponse, project: QgsProject) -> None: """ Evaluate expressions against layer or features In parameters: LAYER=wms-layer-name EXPRESSION=An expression to evaluate or EXPRESSIONS=["first expression", "second expression"] or EXPRESSIONS={"key1": "first expression", "key2": "second expression"} // optionals FEATURE={"type": "Feature", "geometry": {}, "properties": {}} or FEATURES=[{"type": "Feature", "geometry": {}, "properties": {}}, {"type": "Feature", "geometry": {}, "properties": {}}] FORM_SCOPE=boolean to add formScope based on provided features """ layername = params.get('LAYER', '') if not layername: raise ExpressionServiceError( "Bad request error", "Invalid 'Evaluate' REQUEST: LAYER parameter is mandatory", 400) # get layer layer = findVectorLayer(layername, project) # layer not found if not layer: raise ExpressionServiceError( "Bad request error", "Invalid LAYER parameter for 'Evaluate': {} provided".format( layername), 400) # get expressions expressions = params.get('EXPRESSIONS', '') if not expressions: expression = params.get('EXPRESSION', '') if not expression: raise ExpressionServiceError( "Bad request error", "Invalid 'Evaluate' REQUEST: EXPRESSION or EXPRESSIONS parameter is mandatory", 400) expressions = '["{}"]'.format(expression) # try to load expressions list or dict exp_json = None try: exp_json = json.loads(expressions) except Exception: QgsMessageLog.logMessage( "JSON loads expressions '{}' exception:\n{}".format( expressions, traceback.format_exc()), "lizmap", Qgis.Critical) raise ExpressionServiceError( "Bad request error", "Invalid 'Evaluate' REQUEST: EXPRESSIONS '{}' are not well formed" .format(expressions), 400) # create expression context exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(project)) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) # create distance area context da = QgsDistanceArea() da.setSourceCrs(layer.crs(), project.transformContext()) da.setEllipsoid(project.ellipsoid()) # parse expressions exp_map = {} exp_parser_errors = [] exp_items = [] if isinstance(exp_json, list): exp_items = enumerate(exp_json) elif isinstance(exp_json, dict): exp_items = exp_json.items() for k, e in exp_items: exp = QgsExpression(e) exp.setGeomCalculator(da) exp.setDistanceUnits(project.distanceUnits()) exp.setAreaUnits(project.areaUnits()) if exp.hasParserError(): exp_parser_errors.append('Error "{}": {}'.format( e, exp.parserErrorString())) continue if not exp.isValid(): exp_parser_errors.append('Expression not valid "{}"'.format(e)) continue exp.prepare(exp_context) exp_map[k] = exp # expression parser errors found if exp_parser_errors: raise ExpressionServiceError( "Bad request error", "Invalid EXPRESSIONS for 'Evaluate':\n{}".format( '\n'.join(exp_parser_errors)), 400) # get features features = params.get('FEATURES', '') if not features: feature = params.get('FEATURE', '') if feature: features = '[' + feature + ']' # create the body body = { 'status': 'success', 'results': [], 'errors': [], 'features': 0 } # without features just evaluate expression with layer context if not features: result = {} error = {} for k, exp in exp_map.items(): value = exp.evaluate(exp_context) if exp.hasEvalError(): result[k] = None error[k] = exp.evalErrorString() else: result[k] = json.loads(QgsJsonUtils.encodeValue(value)) body['results'].append(result) body['errors'].append(error) write_json_response(body, response) return # Check features geojson = [] try: geojson = json.loads(features) except Exception: QgsMessageLog.logMessage( "JSON loads features '{}' exception:\n{}".format( features, traceback.format_exc()), "lizmap", Qgis.Critical) raise ExpressionServiceError( "Bad request error", "Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formed" .format(features), 400) if not geojson or not isinstance(geojson, list) or len(geojson) == 0: raise ExpressionServiceError( "Bad request error", "Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formed" .format(features), 400) if ('type' not in geojson[0]) or geojson[0]['type'] != 'Feature': raise ExpressionServiceError( "Bad request error", "Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formed: type not defined or not Feature." .format(features), 400) # try to load features # read fields feature_fields = QgsJsonUtils.stringToFields( '{ "type": "FeatureCollection","features":' + features + '}', QTextCodec.codecForName("UTF-8")) # read features feature_list = QgsJsonUtils.stringToFeatureList( '{ "type": "FeatureCollection","features":' + features + '}', feature_fields, QTextCodec.codecForName("UTF-8")) # features not well formed if not feature_list: raise ExpressionServiceError( "Bad request error", "Invalid FEATURES for 'Evaluate': not GeoJSON features array provided\n{}" .format(features), 400) # Extend layer fields with this provided in GeoJSON Features feat_fields = QgsFields(layer.fields()) feat_fields.extend(feature_fields) # form scope addFormScope = params.get('FORM_SCOPE', '').lower() in ['true', '1', 't'] # loop through provided features to evaluate expressions for f in feature_list: # clone the features with all attributes # those defined in layer + fields from GeoJSON Features feat = QgsFeature(feat_fields) feat.setGeometry(f.geometry()) for field in f.fields(): fname = field.name() if feat_fields.indexOf(fname) != -1: feat.setAttribute(fname, f[fname]) # Add form scope to expression context if addFormScope: exp_context.appendScope( QgsExpressionContextUtils.formScope(feat)) exp_context.setFeature(feat) exp_context.setFields(feat.fields()) # Evaluate expressions with the new feature result = {} error = {} for k, exp in exp_map.items(): if addFormScope: # need to prepare the expression because the context as been updated with a new scope exp.prepare(exp_context) value = exp.evaluate(exp_context) if exp.hasEvalError(): result[k] = None error[k] = exp.evalErrorString() else: result[k] = json.loads(QgsJsonUtils.encodeValue(value)) error[k] = exp.expression() body['results'].append(result) body['errors'].append(error) write_json_response(body, response) return
def layer_value(feature, layer, defaultconfig): if not canvas: roam.utils.warning( "No canvas set for using layer_values default function") return None layers = [] # layer name can also be a list of layers to search layername = defaultconfig['layer'] if isinstance(layername, basestring): layers.append(layername) else: layers = layername expression = defaultconfig['expression'] field = defaultconfig['field'] for searchlayer in layers: try: searchlayer = QgsMapLayerRegistry.instance().mapLayersByName( searchlayer)[0] except IndexError: RoamEvents.raisemessage( "Missing layer", "Unable to find layer used in widget expression {}".format( searchlayer), level=1) roam.utils.warning( "Unable to find expression layer {}".format(searchlayer)) return if feature.geometry(): rect = feature.geometry().boundingBox() if layer.geometryType() == QGis.Point: point = feature.geometry().asPoint() rect = QgsRectangle(point.x(), point.y(), point.x() + 10, point.y() + 10) rect.scale(20) rect = canvas.mapRenderer().mapToLayerCoordinates(layer, rect) rq = QgsFeatureRequest().setFilterRect(rect)\ .setFlags(QgsFeatureRequest.ExactIntersect) features = searchlayer.getFeatures(rq) else: features = searchlayer.getFeatures() exp = QgsExpression(expression) exp.prepare(searchlayer.pendingFields()) if exp.hasParserError(): error = exp.parserErrorString() roam.utils.warning(error) for f in features: value = exp.evaluate(f) if exp.hasEvalError(): error = exp.evalErrorString() roam.utils.warning(error) if value: return f[field] raise DefaultError('No features found')
def virtualFields(self, params: Dict[str, str], response: QgsServerResponse, project: QgsProject) -> None: """ Get virtual fields for features In parameters: LAYER=wms-layer-name VIRTUALS={"key1": "first expression", "key2": "second expression"} // optionals FILTER=An expression to filter layer FIELDS=list of requested field separated by comma WITH_GEOMETRY=False """ layername = params.get('LAYER', '') if not layername: raise ExpressionServiceError( "Bad request error", "Invalid 'VirtualFields' REQUEST: LAYER parameter is mandatory", 400) # get layer layer = findVectorLayer(layername, project) # layer not found if not layer: raise ExpressionServiceError( "Bad request error", "Invalid LAYER parameter for 'VirtualFields': {} provided". format(layername), 400) # get virtuals virtuals = params.get('VIRTUALS', '') if not virtuals: raise ExpressionServiceError( "Bad request error", "Invalid 'VirtualFields' REQUEST: VIRTUALS parameter is mandatory", 400) # try to load virtuals dict vir_json = None try: vir_json = json.loads(virtuals) except Exception: QgsMessageLog.logMessage( "JSON loads virtuals '{}' exception:\n{}".format( virtuals, traceback.format_exc()), "lizmap", Qgis.Critical) raise ExpressionServiceError( "Bad request error", "Invalid 'VirtualFields' REQUEST: VIRTUALS '{}' are not well formed" .format(virtuals), 400) if not isinstance(vir_json, dict): raise ExpressionServiceError( "Bad request error", "Invalid 'VirtualFields' REQUEST: VIRTUALS '{}' are not well formed" .format(virtuals), 400) # create expression context exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(project)) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) # create distance area context da = QgsDistanceArea() da.setSourceCrs(layer.crs(), project.transformContext()) da.setEllipsoid(project.ellipsoid()) # parse virtuals exp_map = {} exp_parser_errors = [] for k, e in vir_json.items(): exp = QgsExpression(e) exp.setGeomCalculator(da) exp.setDistanceUnits(project.distanceUnits()) exp.setAreaUnits(project.areaUnits()) if exp.hasParserError(): exp_parser_errors.append('Error "{}": {}'.format( e, exp.parserErrorString())) continue if not exp.isValid(): exp_parser_errors.append('Expression not valid "{}"'.format(e)) continue exp.prepare(exp_context) exp_map[k] = exp # expression parser errors found if exp_parser_errors: raise ExpressionServiceError( "Bad request error", "Invalid VIRTUALS for 'VirtualFields':\n{}".format( '\n'.join(exp_parser_errors)), 400) req = QgsFeatureRequest() # get filter req_filter = params.get('FILTER', '') if req_filter: req_exp = QgsExpression(req_filter) req_exp.setGeomCalculator(da) req_exp.setDistanceUnits(project.distanceUnits()) req_exp.setAreaUnits(project.areaUnits()) if req_exp.hasParserError(): raise ExpressionServiceError( "Bad request error", "Invalid FILTER for 'VirtualFields' Error \"{}\": {}". format(req_filter, req_exp.parserErrorString()), 400) if not req_exp.isValid(): raise ExpressionServiceError( "Bad request error", "Invalid FILTER for 'VirtualFields' Expression not valid \"{}\"" .format(req_filter), 400) req_exp.prepare(exp_context) req = QgsFeatureRequest(req_exp, exp_context) # With geometry withGeom = params.get('WITH_GEOMETRY', '').lower() in ['true', '1', 't'] if not withGeom: req.setFlags(QgsFeatureRequest.NoGeometry) # Fields pkAttributes = layer.primaryKeyAttributes() attributeList = [i for i in pkAttributes] fields = layer.fields() r_fields = [ f.strip() for f in params.get('FIELDS', '').split(',') if f ] for f in r_fields: attributeList.append(fields.indexOf(f)) # response response.setStatusCode(200) response.setHeader("Content-Type", "application/json") response.write('{ "type": "FeatureCollection","features":[') response.flush() jsonExporter = QgsJsonExporter(layer) if attributeList: jsonExporter.setAttributes(attributeList) separator = '' for feat in layer.getFeatures(req): fid = layername + '.' + getServerFid(feat, pkAttributes) extra = {} # Update context exp_context.setFeature(feat) exp_context.setFields(feat.fields()) # Evaluate expressions for virtual fields errors = {} for k, exp in exp_map.items(): value = exp.evaluate(exp_context) if exp.hasEvalError(): extra[k] = None errors[k] = exp.evalErrorString() else: extra[k] = json.loads(QgsJsonUtils.encodeValue(value)) errors[k] = exp.expression() response.write(separator + jsonExporter.exportFeature(feat, extra, fid)) response.flush() separator = ',\n' response.write(']}') return
def export_all_features(self): pdf_painter = None """Export map to pdf atlas style (one page per feature)""" if VRP_DEBUG is True: QgsMessageLog.logMessage(u'exporting map', DLG_CAPTION) try: result = self.__delete_pdf() if not result is None: return result ids = [] exp = QgsExpression(self.feature_filter) if exp.hasParserError(): raise Exception(exp.parserErrorString()) exp.prepare(self.coverage_layer.pendingFields()) for feature in self.coverage_layer.getFeatures(): value = exp.evaluate(feature) if exp.hasEvalError(): raise ValueError(exp.evalErrorString()) if bool(value): if VRP_DEBUG is True: QgsMessageLog.logMessage(u'export map, feature id:{0}'.format(feature.id()), DLG_CAPTION) ids.append(feature.id()) self.coverage_layer.select(ids) bbox = self.coverage_layer.boundingBoxOfSelected() self.canvas.zoomToSelected(self.coverage_layer) if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox:{0}'.format(bbox.toString()), DLG_CAPTION) #self.map_renderer.setExtent(bbox) #self.map_renderer.updateScale() #read plotlayout composition = QgsComposition(self.map_renderer) self.composition = composition composition.setPlotStyle(QgsComposition.Print) error, xml_doc = self.__read_template() if not error is None: return error if composition.loadFromTemplate(xml_doc) is False: return u'Konnte Template nicht laden!\n{0}'.format(self.template_qpt) #read textinfo layout self.comp_textinfo = QgsComposition(self.map_renderer) self.comp_textinfo.setPlotStyle(QgsComposition.Print) error, xml_doc = self.__read_template(True) if not error is None: return error if self.comp_textinfo.loadFromTemplate(xml_doc) is False: return u'Konnte Template nicht laden!\n{0}'.format(self.settings.textinfo_layout()) new_ext = bbox if QGis.QGIS_VERSION_INT > 20200: compmaps = self.__get_items(QgsComposerMap) if len(compmaps) < 1: return u'Kein Kartenfenster im Layout vorhanden!' compmap = compmaps[0] else: if len(composition.composerMapItems()) < 1: return u'Kein Kartenfenster im Layout vorhanden!' compmap = composition.composerMapItems()[0] self.composermap = compmap #self.composermap.setPreviewMode(QgsComposerMap.Render) #self.composermap.setPreviewMode(QgsComposerMap.Rectangle) #taken from QgsComposerMap::setNewAtlasFeatureExtent (not yet available in QGIS 2.0) #http://www.qgis.org/api/qgscomposermap_8cpp_source.html#l00610 old_ratio = compmap.rect().width() / compmap.rect().height() new_ratio = new_ext.width() / new_ext.height() if old_ratio < new_ratio: new_height = new_ext.width() / old_ratio delta_height = new_height - new_ext.height() new_ext.setYMinimum( bbox.yMinimum() - delta_height / 2) new_ext.setYMaximum(bbox.yMaximum() + delta_height / 2) else: new_width = old_ratio * new_ext.height() delta_width = new_width - new_ext.width() new_ext.setXMinimum(bbox.xMinimum() - delta_width / 2) new_ext.setXMaximum(bbox.xMaximum() + delta_width / 2) if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox old:{0}'.format(compmap.extent().toString()), DLG_CAPTION) compmap.setNewExtent(new_ext) if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox new:{0}'.format(compmap.extent().toString()), DLG_CAPTION) #round up to next 1000 compmap.setNewScale(math.ceil((compmap.scale()/1000.0)) * 1000.0) if VRP_DEBUG is True: QgsMessageLog.logMessage(u'bbox new (after scale):{0}'.format(compmap.extent().toString()), DLG_CAPTION) #add ORTHO after new extent -> performance if not self.ortho is None: self.ortho_lyr = self.__add_raster_layer(self.ortho, self.lyrname_ortho) self.__reorder_layers() self.comp_leg = self.__get_items(QgsComposerLegend) self.comp_lbl = self.__get_items(QgsComposerLabel) self.__update_composer_items(self.settings.dkm_gemeinde(self.gem_name)['lyrnamegstk']) if VRP_DEBUG is True: QgsMessageLog.logMessage(u'paperWidth:{0} paperHeight:{1}'.format(composition.paperWidth(), composition.paperHeight()), DLG_CAPTION) printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(self.pdf_map) printer.setPaperSize(QSizeF(composition.paperWidth(), composition.paperHeight()), QPrinter.Millimeter) printer.setFullPage(True) printer.setColorMode(QPrinter.Color) printer.setResolution(composition.printResolution()) pdf_painter = QPainter(printer) paper_rect_pixel = printer.pageRect(QPrinter.DevicePixel) paper_rect_mm = printer.pageRect(QPrinter.Millimeter) QgsPaintEngineHack.fixEngineFlags(printer.paintEngine()) #DKM only if len(self.themen) < 1: composition.render(pdf_painter, paper_rect_pixel, paper_rect_mm) else: self.statistics = OrderedDict() try: pass #lyr = QgsVectorLayer('/home/bergw/VoGIS-Raumplanung-Daten/Geodaten/Raumplanung/Flaechenwidmung/Dornbirn/Flaechenwidmungsplan/fwp_flaeche.shp', 'flaeiw', 'ogr') #lyr.loadNamedStyle('/home/bergw/VoGIS-Raumplanung-Daten/Geodaten/Raumplanung/Flaechenwidmung/Vorarlberg/Flaechenwidmungsplan/fwp_flaeche.qml') #QgsMapLayerRegistry.instance().addMapLayer(lyr) except: QgsMessageLog.logMessage('new lyr:{0}'.format(sys.exc_info()[0]), DLG_CAPTION) #QgsMapLayerRegistry.instance().addMapLayer(lyr) cntr = 0 for thema, sub_themen in self.themen.iteritems(): if VRP_DEBUG is True: QgsMessageLog.logMessage('drucke Thema:{0}'.format(thema.name), DLG_CAPTION) if sub_themen is None: layers = self.__add_layers(thema) self.__calculate_statistics(thema, thema, layers) #no qml -> not visible -> means no map if self.__at_least_one_visible(layers) is True: if cntr > 0: printer.newPage() self.__reorder_layers() self.__update_composer_items(thema.name, layers=layers) composition.renderPage(pdf_painter, 0) QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers]) cntr += 1 else: QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers]) if not sub_themen is None: for sub_thema in sub_themen: if VRP_DEBUG is True: QgsMessageLog.logMessage(u'drucke SubThema:{0}'.format(sub_thema.name), DLG_CAPTION) layers = self.__add_layers(sub_thema) self.__calculate_statistics(thema, sub_thema, layers) #no qml -> not visible -> means no map if self.__at_least_one_visible(layers) is True: if cntr > 0: printer.newPage() self.__reorder_layers() self.__update_composer_items(thema.name, subthema=sub_thema.name, layers=layers) composition.renderPage(pdf_painter, 0) QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers]) cntr += 1 else: QgsMapLayerRegistry.instance().removeMapLayers([lyr.id() for lyr in layers]) #output statistics if len(self.statistics) > 0: printer.setPaperSize(QSizeF(210, 297), QPrinter.Millimeter) tabelle = self.__get_item_byid(self.comp_textinfo, 'TABELLE') if tabelle is None: self.iface.messageBar().pushMessage(u'Layout (Textinfo): Kein Textelement mit ID "TABELLE" vorhanden.', QgsMessageBar.CRITICAL) else: try: str_flaechen = '' idx = 0 for gnr, stats in self.statistics.iteritems(): comma = ', ' if idx > 0 else '' str_flaechen += u'{0}{1} ({2:.2f}m²)'.format(comma, gnr, stats[0].flaeche) idx += 1 lbls = self.__get_items(QgsComposerLabel, self.comp_textinfo) self.__update_composer_items('', labels=lbls, gnrflaeche=str_flaechen) html = tabelle.text() html += u'<table>' #gnrcnt = 0 for gnr, stats in self.statistics.iteritems(): #if gnrcnt > 0: # html += u'<tr class="abstand"><td> </td><td> </td><td> </td></tr>' html += u'<tr><th class="gnr"></th><th class="gnr">{0}</th><th class="gnr"></th></tr>'.format(gnr) #html += u'<tr class="abstand"><td> </td><td> </td><td> </td></tr>' curr_thema = '' for stat in stats: if stat.thema != curr_thema: html += u'<tr><th class="thema"></th><th class="thema">{0}</th><th class="thema"></th></tr>'.format(stat.thema) curr_thema = stat.thema for thema, subthema in stat.subthemen.iteritems(): for quelle in subthema: html += u'<tr><td class="col1">{0}</td>'.format(quelle.name) attr_val = '' attr_area = '' for text, area in quelle.txt_area.iteritems(): attr_val += u'{0}<br />'.format(text) attr_area += u'{0:.2f}m² <br />'.format(area) html += u'<td class="col2">{0}</td><td class="col3">{1}</td></tr>'.format(attr_val, attr_area) #gnrcnt += 1 html += u'</table>' tabelle.setText(html) printer.newPage() self.comp_textinfo.renderPage(pdf_painter, 0) except: msg = 'Statistikausgabe:\n\n{0}'.format(traceback.format_exc()) QgsMessageLog.logMessage(msg, DLG_CAPTION) self.iface.messageBar().pushMessage(msg, QgsMessageBar.CRITICAL) except: msg = 'export pdf (catch all):\n\n{0}'.format(traceback.format_exc()) QgsMessageLog.logMessage(msg, DLG_CAPTION) self.iface.messageBar().pushMessage(msg.replace(u'\n', u''), QgsMessageBar.CRITICAL) return msg finally: #end pdf if not pdf_painter is None: pdf_painter.end() return None
def processAlgorithm(self, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) provider = layer.dataProvider() fields = [] expressions = [] for field_def in mapping: fields.append(QgsField(name=field_def['name'], type=field_def['type'], len=field_def['length'], prec=field_def['precision'])) expression = QgsExpression(field_def['expression']) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}') .format(unicode(field_def['expression']), unicode(expression.parserErrorString()))) expression.prepare(provider.fields()) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}') .format(unicode(field_def['expression']), unicode(expression.evalErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, provider.geometryType(), layer.crs()) # Create output vector layer with new attributes error = '' calculationSuccess = True inFeat = QgsFeature() outFeat = QgsFeature() features = vector.features(layer) count = len(features) for current, inFeat in enumerate(features): rownum = current + 1 outFeat.setGeometry(inFeat.geometry()) attrs = [] for i in xrange(0, len(mapping)): field_def = mapping[i] expression = expressions[i] expression.setCurrentRowNumber(rownum) value = expression.evaluate(inFeat) if expression.hasEvalError(): calculationSuccess = False error = expression.evalErrorString() break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) current += 1 progress.setPercentage(100 * current / float(count)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation' ' string:\n') + error)
def processAlgorithm(self, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) for field_def in mapping: fields.append( QgsField(name=field_def['name'], type=field_def['type'], len=field_def['length'], prec=field_def['precision'])) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(QgsProject.instance().distanceUnits()) expression.setAreaUnits(QgsProject.instance().areaUnits()) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}').format( unicode(field_def['expression']), unicode(expression.parserErrorString()))) expression.prepare(exp_context) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}').format( unicode(field_def['expression']), unicode(expression.evalErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) # Create output vector layer with new attributes error = '' calculationSuccess = True inFeat = QgsFeature() outFeat = QgsFeature() features = vector.features(layer) total = 100.0 / len(features) for current, inFeat in enumerate(features): rownum = current + 1 geometry = inFeat.geometry() outFeat.setGeometry(geometry) attrs = [] for i in xrange(0, len(mapping)): field_def = mapping[i] expression = expressions[i] exp_context.setFeature(inFeat) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): calculationSuccess = False error = expression.evalErrorString() break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation' ' string:\n') + error)
def processAlgorithm(self, parameters, context, feedback): t_troncon = self.parameterAsSource(parameters, self.SEGMENTS_TABLE, context) g_troncon = self.parameterAsSource(parameters, self.GEOM_SEGMENTS, context) t_obs = self.parameterAsSource(parameters, self.OBSERVATION_TABLE, context) g_obs = self.parameterAsVectorLayer(parameters, self.GEOM_OBSERVATION, context) # Get troncon ids and file ids exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(t_troncon.createExpressionContextScope()) exp_str = '"id_geom_troncon" IS NOT NULL' exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression %s has eval error: %s').format( exp.expression(), exp.evalErrorString())) request = QgsFeatureRequest(exp, exp_context) request.setSubsetOfAttributes( ['id', 'aab', 'aad', 'aaf', 'abq', 'id_file', 'id_geom_troncon'], t_troncon.fields()) has_geo_troncon = False troncons = {} file_ids = [] for tro in t_troncon.getFeatures(request): troncons[tro['id']] = tro file_ids.append(tro['id_file']) has_geo_troncon = True # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} if not has_geo_troncon: raise QgsProcessingException(tr('* ERROR: No troncon geometries')) # Get observation ids exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(t_obs.createExpressionContextScope()) exp_str = ('"id_troncon" IN ({}) AND ' '"id_file" IN ({})').format( ','.join([str(i) for i in troncons.keys()]), ','.join([str(i) for i in file_ids])) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString())) obs_ids = [] request = QgsFeatureRequest(exp, exp_context) for obs in t_obs.getFeatures(request): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} troncon = troncons[obs['id_troncon']] # verifying ITV file if troncon['id_file'] != obs['id_file']: continue obs_ids.append(obs['id']) if not obs_ids: raise QgsProcessingException( tr('* ERROR: No observations to geolocalize found')) # Check observations already geolocalised on troncon exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(QgsExpressionContextUtils.layerScope(g_obs)) exp_str = '"id" IN ({})'.format(','.join([str(i) for i in obs_ids])) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString())) request = QgsFeatureRequest(exp, exp_context) geo_observations = [] for obs in g_obs.getFeatures(request): geo_observations.append(obs['id']) # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} # build observation geometry based on table exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(t_obs.createExpressionContextScope()) exp_str = ('"id_troncon" IN ({}) AND ' '"id_file" IN ({})').format( ','.join([str(i) for i in troncons.keys()]), ','.join([str(i) for i in file_ids])) if geo_observations: exp_str += ' AND id NOT IN ({})'.format(','.join( [str(i) for i in geo_observations])) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString())) request = QgsFeatureRequest(exp, exp_context) features = [] fields = provider_fields(g_obs.fields()) for obs in t_obs.getFeatures(request): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} troncon = troncons[obs['id_troncon']] # verifying ITV file if troncon['id_file'] != obs['id_file']: continue geo_req = QgsFeatureRequest() geo_req.setFilterFid(troncon['id_geom_troncon']) for g_tro in g_troncon.getFeatures(geo_req): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} geom = g_tro.geometry() pt = None if troncon['aab'] == troncon['aad']: pt = geom.interpolate(geom.length() * obs['i'] / troncon['abq']) else: pt = geom.interpolate(geom.length() * (1 - obs['i'] / troncon['abq'])) fet = QgsFeature(fields) fet.setGeometry(pt) fet.setAttribute('id', obs['id']) features.append(fet) # Ajout des objets observations if features: g_obs.startEditing() (res, outFeats) = g_obs.dataProvider().addFeatures(features) if not res or not outFeats: raise QgsProcessingException( tr('* ERREUR: lors de l\'enregistrement ' 'des regards {}').format(', '.join( g_obs.dataProvider().errors()))) if not g_obs.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format(g_obs.commitErrors())) # Returns empty dict if no outputs return {self.OBSERVATIONS_CREATED: len(features)}
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) if output.value == '': ext = output.getDefaultFileExtension(self) output.value = system.getTempFilenameInTempFolder(output.name + '.' + ext) provider = layer.dataProvider() fields = layer.pendingFields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, provider.geometryType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) if not exp.prepare(layer.pendingFields()): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True current = 0 features = vector.features(layer) total = 100.0 / len(features) rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp.setCurrentRowNumber(rownum) value = exp.evaluate(f) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occured while evaluating the calculation ' 'string:\n%s' % error))
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) if output.value == '': ext = output.getDefaultFileExtension(self) output.value = system.getTempFilenameInTempFolder(output.name + '.' + ext) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) # add layer to registry to fix https://issues.qgis.org/issues/17300 # it is necessary only for aggregate expressions that verify that layer # is registered removeRegistryAfterEvaluation = False if not QgsMapLayerRegistry.instance().mapLayer(layer.id()): removeRegistryAfterEvaluation = True QgsMapLayerRegistry.instance().addMapLayer(layer, addToLegend=False) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) if len(features) > 0 else 1 rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer # remove from registry if added for expression requirement # see above comment about fix #17300 if removeRegistryAfterEvaluation: QgsMapLayerRegistry.instance().removeMapLayer(layer) if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs()) da.setEllipsoidalMode(True) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) feedback.setProgress(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def print_layout(project, layout_name, feature_filter: str = None, scales=None, scale=None, **kwargs): """Generate a PDF for an atlas or a report. :param project: The QGIS project. :type project: QgsProject :param layout_name: Name of the layout of the atlas or report. :type layout_name: basestring :param feature_filter: QGIS Expression to use to select the feature. It can return many features, a multiple pages PDF will be returned. This is required to print atlas, not report :type feature_filter: basestring :param scale: A scale to force in the atlas context. Default to None. :type scale: int :param scales: A list of predefined list of scales to force in the atlas context. Default to None. :type scales: list :return: Path to the PDF. :rtype: basestring """ canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge( project.layerTreeRoot(), canvas ) bridge.setCanvasLayers() manager = project.layoutManager() master_layout = manager.layoutByName(layout_name) settings = QgsLayoutExporter.PdfExportSettings() atlas = None atlas_layout = None report_layout = None if not master_layout: raise AtlasPrintException('Layout `{}` not found'.format(layout_name)) if master_layout.layoutType() == QgsMasterLayoutInterface.PrintLayout: for _print_layout in manager.printLayouts(): if _print_layout.name() == layout_name: atlas_layout = _print_layout break atlas = atlas_layout.atlas() if not atlas.enabled(): raise AtlasPrintException('The layout is not enabled for an atlas') layer = atlas.coverageLayer() if feature_filter is None: raise AtlasPrintException('EXP_FILTER is mandatory to print an atlas layout') feature_filter = optimize_expression(layer, feature_filter) expression = QgsExpression(feature_filter) if expression.hasParserError(): raise AtlasPrintException('Expression is invalid, parser error: {}'.format(expression.parserErrorString())) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope(project)) context.appendScope(QgsExpressionContextUtils.layoutScope(atlas_layout)) context.appendScope(QgsExpressionContextUtils.atlasScope(atlas)) context.appendScope(QgsExpressionContextUtils.layerScope(layer)) expression.prepare(context) if expression.hasEvalError(): raise AtlasPrintException('Expression is invalid, eval error: {}'.format(expression.evalErrorString())) atlas.setFilterFeatures(True) atlas.setFilterExpression(feature_filter) if scale: atlas_layout.referenceMap().setAtlasScalingMode(QgsLayoutItemMap.Fixed) atlas_layout.referenceMap().setScale(scale) if scales: atlas_layout.referenceMap().setAtlasScalingMode(QgsLayoutItemMap.Predefined) if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = scales else: atlas_layout.reportContext().setPredefinedScales(scales) if not scales and atlas_layout.referenceMap().atlasScalingMode() == QgsLayoutItemMap.Predefined: if Qgis.QGIS_VERSION_INT >= 30900: use_project = project.useProjectScales() map_scales = project.mapScales() else: map_scales = project_scales(project) use_project = len(map_scales) == 0 if not use_project or len(map_scales) == 0: logger.info( 'Map scales not found in project, fetching predefined map scales in global config' ) map_scales = global_scales() if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = map_scales else: atlas_layout.reportContext().setPredefinedScales(map_scales) elif master_layout.layoutType() == QgsMasterLayoutInterface.Report: report_layout = master_layout else: raise AtlasPrintException('The layout is not supported by the plugin') for key, value in kwargs.items(): found = False if atlas_layout: item = atlas_layout.itemById(key.lower()) if isinstance(item, QgsLayoutItemLabel): item.setText(value) found = True logger.info( 'Additional parameters: {} found in layout {}, value {}'.format(key, found, value)) export_path = os.path.join( tempfile.gettempdir(), '{}_{}.pdf'.format(layout_name, uuid4()) ) result, error = QgsLayoutExporter.exportToPdf(atlas or report_layout, export_path, settings) if result != QgsLayoutExporter.Success and not os.path.isfile(export_path): raise Exception('export not generated {} ({})'.format(export_path, error)) return export_path
def expressionBasedUpdate( self, layer, dictProperties, featureId, index=None, value=None ): """ Defines the logic of the expression-based update to be applied. This SLOT listens to featureAdded, geometryChanged, and attributeValueChanged SIGNALS. """ # Check if AutoField is there, otherwise return fieldIndex = layer.fieldNameIndex( dictProperties['field'] ) if fieldIndex == -1: self.msg.show( QApplication.translate( "EventManager", "[Error] Updating AutoField " ) + \ dictProperties['field'] + \ QApplication.translate( "EventManager", " in layer " ) + \ layer.name() + QApplication.translate( "EventManager", " was NOT possible." ) + \ QApplication.translate( "EventManager", " Perhaps you just removed it but haven't saved the changes yet?" ), 'warning' ) return event = "" result = None expression = QgsExpression( dictProperties['expression'] ) if expression.hasParserError(): self.msg.show( QApplication.translate( "EventManager", "[Error] (Parsing) " ) + \ expression.parserErrorString(), 'critical' ) result = NULL # Avoid infinite recursion (changing the same attribute value infinitely). if not index is None: # Filters out the featureAdded SIGNAL if type( index ) == int: # Filters out the geometryChanged SIGNAL if index == fieldIndex: # This call comes from the same AutoField, so return return if self.afm.isFieldAnAutoField( layer, layer.fields()[index].name() ): # Call from AutoField, don't listen # This is to prevent corrupting the layerEditBuffer and being bitten by: # Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585 return #if type(value)==QPyNullVariant: # Vector layers with numeric field whose value for 1st feature is NULL # trigger an attributeValueChanged SIGNAL when start editing from the # attribute table window. We use this conditional to avoid such SIGNAL. # The ideal case is that such NULL valued SIGNAL shouldn't be emitted by QGIS. # return # While the previous block reduces the number of times attributeValueChanged # is called from the attribute table, it leads to a QGIS bug: # Fatal: ASSERT: "mChangedAttributeValues.isEmpty()" in file /tmp/buildd/qgis-2.14.2+20trusty/src/core/qgsvectorlayereditbuffer.cpp, line 585 # I prefer the attributeValueChanged to be called multiple # times (inefficient) than to open the possibility to a bug. # As soon as QGIS bug #15272 is solved, the number of calls will be reduced! event = "attributeValueChanged" else: event = "geometryChanged" else: event = "featureAdded" feature = layer.getFeatures( QgsFeatureRequest( featureId ) ).next() if result is None: context = QgsExpressionContext() context.appendScope( QgsExpressionContextUtils.globalScope() ) context.appendScope( QgsExpressionContextUtils.projectScope() ) context.appendScope( QgsExpressionContextUtils.layerScope( layer ) ) context.setFields( feature.fields() ) context.setFeature( feature ) if expression.needsGeometry(): if self.iface: # This block was borrowed from QGIS/python/plugins/processing/algs/qgis/FieldsCalculator.py da = QgsDistanceArea() da.setSourceCrs( layer.crs().srsid() ) da.setEllipsoidalMode( self.iface.mapCanvas().mapSettings().hasCrsTransformEnabled() ) da.setEllipsoid( QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE )[0] ) expression.setGeomCalculator( da ) if QGis.QGIS_VERSION_INT >= 21400: # Methods added in QGIS 2.14 expression.setDistanceUnits( QgsProject.instance().distanceUnits() ) expression.setAreaUnits( QgsProject.instance().areaUnits() ) expression.prepare( context ) result = expression.evaluate( context ) if expression.hasEvalError(): self.msg.show( QApplication.translate( "EventManager", "[Error] (Evaluating) " ) + \ expression.evalErrorString(), 'critical' ) result = NULL field = layer.fields()[fieldIndex] res = field.convertCompatible( result ) # If result is None, res will be None, but even in that case, QGIS knows # what to do with it while saving, it seems it's treated as NULL. # TODO when bug #15311 is fixed, this block should work better #if dictProperties['expression'] in self.listProviderExpressions: # # Save directly to provider # layer.dataProvider().changeAttributeValues( { featureId : { fieldIndex : res } } ) #else: # Save to layer # layer.changeAttributeValue( featureId, fieldIndex, res ) # Workaround if event == 'featureAdded': # Save directly to the provider layer.dataProvider().changeAttributeValues( { featureId : { fieldIndex : res } } ) else: # Save to layer layer.changeAttributeValue( featureId, fieldIndex, res ) self.msg.show( "[Info] * AutoField's value updated to " + unicode(res) + \ ", (" + layer.name() + "." + dictProperties['field'] + ") by " + event +".", 'info', True )
def processAlgorithm(self, parameters, context, feedback): layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(), context) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs()) da.setEllipsoid(QgsProject.instance().ellipsoid()) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext(QgsExpressionContextUtils.globalProjectLayerScopes(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: {0}').format(exp.evalErrorString())) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = QgsProcessingUtils.getFeatures(layer, context) total = 100.0 / layer.featureCount() if layer.featureCount() else 0 rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n{0}').format(error))
def processAlgorithm(self, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) for field_def in mapping: fields.append(QgsField(name=field_def['name'], type=field_def['type'], len=field_def['length'], prec=field_def['precision'])) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(QgsProject.instance().distanceUnits()) expression.setAreaUnits(QgsProject.instance().areaUnits()) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}') .format(str(field_def['expression']), str(expression.parserErrorString()))) expression.prepare(exp_context) if expression.hasEvalError(): raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}') .format(str(field_def['expression']), str(expression.evalErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) # Create output vector layer with new attributes error = '' calculationSuccess = True inFeat = QgsFeature() outFeat = QgsFeature() features = vector.features(layer) total = 100.0 / len(features) for current, inFeat in enumerate(features): rownum = current + 1 geometry = inFeat.geometry() outFeat.setGeometry(geometry) attrs = [] for i in range(0, len(mapping)): field_def = mapping[i] expression = expressions[i] exp_context.setFeature(inFeat) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): calculationSuccess = False error = expression.evalErrorString() break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation' ' string:\n') + error)
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER)) fieldName = self.getParameterValue(self.FIELD_NAME) fieldType = self.TYPES[self.getParameterValue(self.FIELD_TYPE)] width = self.getParameterValue(self.FIELD_LENGTH) precision = self.getParameterValue(self.FIELD_PRECISION) newField = self.getParameterValue(self.NEW_FIELD) formula = self.getParameterValue(self.FORMULA) output = self.getOutputFromName(self.OUTPUT_LAYER) if output.value == '': ext = output.getDefaultFileExtension(self) output.value = system.getTempFilenameInTempFolder( output.name + '.' + ext) fields = layer.fields() if newField: fields.append(QgsField(fieldName, fieldType, '', width, precision)) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) exp = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp.setGeomCalculator(da) exp.setDistanceUnits(QgsProject.instance().distanceUnits()) exp.setAreaUnits(QgsProject.instance().areaUnits()) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope(QgsExpressionContextUtils.projectScope()) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) if not exp.prepare(exp_context): raise GeoAlgorithmExecutionException( self.tr('Evaluation error: %s' % exp.evalErrorString())) # add layer to registry to fix https://issues.qgis.org/issues/17300 # it is necessary only for aggregate expressions that verify that layer # is registered removeRegistryAfterEvaluation = False if not QgsMapLayerRegistry.instance().mapLayer(layer.id()): removeRegistryAfterEvaluation = True QgsMapLayerRegistry.instance().addMapLayer(layer, addToLegend=False) outFeature = QgsFeature() outFeature.initAttributes(len(fields)) outFeature.setFields(fields) error = '' calculationSuccess = True features = vector.features(layer) total = 100.0 / len(features) if len(features) > 0 else 1 rownum = 1 for current, f in enumerate(features): rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = exp.evaluate(exp_context) if exp.hasEvalError(): calculationSuccess = False error = exp.evalErrorString() break else: outFeature.setGeometry(f.geometry()) for fld in f.fields(): outFeature[fld.name()] = f[fld.name()] outFeature[fieldName] = value writer.addFeature(outFeature) progress.setPercentage(int(current * total)) del writer # remove from registry if added for expression requirement # see above comment about fix #17300 if removeRegistryAfterEvaluation: QgsMapLayerRegistry.instance().removeMapLayer(layer) if not calculationSuccess: raise GeoAlgorithmExecutionException( self.tr('An error occurred while evaluating the calculation ' 'string:\n%s' % error))
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)] width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) new_field = self.parameterAsBool(parameters, self.NEW_FIELD, context) formula = self.parameterAsString(parameters, self.FORMULA, context) expression = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) fields = source.fields() field_index = fields.lookupField(field_name) if new_field or field_index < 0: fields.append(QgsField(field_name, field_type, '', width, precision)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, source.wkbType(), source.sourceCrs()) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) exp_context = self.createExpressionContext(parameters, context) if layer is not None: exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) expression.prepare(exp_context) features = source.getFeatures() total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): feedback.reportError(expression.evalErrorString()) else: attrs = f.attributes() if new_field or field_index < 0: attrs.append(value) else: attrs[field_index] = value f.setAttributes(attrs) sink.addFeature(f, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) if self.MIN_DISTANCE in parameters and parameters[self.MIN_DISTANCE] is not None: minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) else: minDistance = None expressionContext = self.createExpressionContext(parameters, context, source) dynamic_value = QgsProcessingParameters.isDynamic(parameters, "VALUE") value_property = None if self.EXPRESSION in parameters and parameters[self.EXPRESSION] is not None: expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context)) value = None if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) expression.prepare(expressionContext) else: expression = None if dynamic_value: value_property = parameters["VALUE"] value = self.parameterAsDouble(parameters, self.VALUE, context) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, source.sourceCrs(), QgsFeatureSink.RegeneratePrimaryKey) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.ellipsoid()) total = 100.0 / source.featureCount() if source.featureCount() else 0 current_progress = 0 pointId = 0 for current, f in enumerate(source.getFeatures()): if feedback.isCanceled(): break if not f.hasGeometry(): continue current_progress = total * current feedback.setProgress(current_progress) this_value = value if value_property is not None or expression is not None: expressionContext.setFeature(f) if value_property: this_value, _ = value_property.valueAsDouble(expressionContext, value) else: this_value = expression.evaluate(expressionContext) if expression.hasEvalError(): feedback.pushInfo( self.tr('Evaluation error for feature ID {}: {}').format(f.id(), expression.evalErrorString())) continue fGeom = f.geometry() engine = QgsGeometry.createGeometryEngine(fGeom.constGet()) engine.prepareGeometry() bbox = fGeom.boundingBox() if strategy == 0: pointCount = int(this_value) else: pointCount = int(round(this_value * da.measureArea(fGeom))) if pointCount == 0: feedback.pushInfo("Skip feature {} as number of points for it is 0.".format(f.id())) continue index = None if minDistance: index = QgsSpatialIndex() points = {} nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 feature_total = total / pointCount if pointCount else 1 random.seed() while nIterations < maxIterations and nPoints < pointCount: if feedback.isCanceled(): break rx = bbox.xMinimum() + bbox.width() * random.random() ry = bbox.yMinimum() + bbox.height() * random.random() p = QgsPointXY(rx, ry) geom = QgsGeometry.fromPointXY(p) if engine.contains(geom.constGet()) and \ (not minDistance or vector.checkMinDistance(p, index, minDistance, points)): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', pointId) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) if minDistance: index.addFeature(f) points[nPoints] = p nPoints += 1 pointId += 1 feedback.setProgress(current_progress + int(nPoints * feature_total)) nIterations += 1 if nPoints < pointCount: feedback.pushInfo(self.tr('Could not generate requested number of random ' 'points. Maximum number of attempts exceeded.')) feedback.setProgress(100) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context)) if expression.hasParserError(): raise ProcessingException(expression.parserErrorString()) expressionContext = self.createExpressionContext(parameters, context) if not expression.prepare(expressionContext): raise ProcessingException( self.tr('Evaluation error: {0}').format(expression.evalErrorString())) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, source.sourceCrs()) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs()) da.setEllipsoid(context.project().ellipsoid()) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(source.getFeatures()): if feedback.isCanceled(): break expressionContext.setFeature(f) value = expression.evaluate(expressionContext) if expression.hasEvalError(): feedback.pushInfo( self.tr('Evaluation error for feature ID {}: {}').format(f.id(), expression.evalErrorString())) continue fGeom = f.geometry() bbox = fGeom.boundingBox() if strategy == 0: pointCount = int(value) else: pointCount = int(round(value * da.measureArea(fGeom))) if pointCount == 0: feedback.pushInfo("Skip feature {} as number of points for it is 0.") continue index = QgsSpatialIndex() points = dict() nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 total = 100.0 / pointCount if pointCount else 1 random.seed() while nIterations < maxIterations and nPoints < pointCount: if feedback.isCanceled(): break rx = bbox.xMinimum() + bbox.width() * random.random() ry = bbox.yMinimum() + bbox.height() * random.random() p = QgsPointXY(rx, ry) geom = QgsGeometry.fromPoint(p) if geom.within(fGeom) and \ vector.checkMinDistance(p, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) index.insertFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(int(nPoints * total)) nIterations += 1 if nPoints < pointCount: feedback.pushInfo(self.tr('Could not generate requested number of random ' 'points. Maximum number of attempts exceeded.')) feedback.setProgress(0) return {self.OUTPUT: dest_id}
class GeometryByExpression(QgisFeatureBasedAlgorithm): OUTPUT_GEOMETRY = 'OUTPUT_GEOMETRY' WITH_Z = 'WITH_Z' WITH_M = 'WITH_M' EXPRESSION = 'EXPRESSION' def group(self): return self.tr('Vector geometry') def groupId(self): return 'vectorgeometry' def __init__(self): super().__init__() self.geometry_types = [self.tr('Polygon'), 'Line', 'Point'] def initParameters(self, config=None): self.addParameter(QgsProcessingParameterEnum( self.OUTPUT_GEOMETRY, self.tr('Output geometry type'), options=self.geometry_types, defaultValue=0)) self.addParameter(QgsProcessingParameterBoolean(self.WITH_Z, self.tr('Output geometry has z dimension'), defaultValue=False)) self.addParameter(QgsProcessingParameterBoolean(self.WITH_M, self.tr('Output geometry has m values'), defaultValue=False)) self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION, self.tr("Geometry expression"), defaultValue='$geometry', parentLayerParameterName='INPUT')) def name(self): return 'geometrybyexpression' def displayName(self): return self.tr('Geometry by expression') def outputName(self): return self.tr('Modified geometry') def prepareAlgorithm(self, parameters, context, feedback): self.geometry_type = self.parameterAsEnum(parameters, self.OUTPUT_GEOMETRY, context) self.wkb_type = None if self.geometry_type == 0: self.wkb_type = QgsWkbTypes.Polygon elif self.geometry_type == 1: self.wkb_type = QgsWkbTypes.LineString else: self.wkb_type = QgsWkbTypes.Point if self.parameterAsBool(parameters, self.WITH_Z, context): self.wkb_type = QgsWkbTypes.addZ(self.wkb_type) if self.parameterAsBool(parameters, self.WITH_M, context): self.wkb_type = QgsWkbTypes.addM(self.wkb_type) self.expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context)) if self.expression.hasParserError(): feedback.reportError(self.expression.parserErrorString()) return False self.expression_context = self.createExpressionContext(parameters, context) self.expression.prepare(self.expression_context) return True def outputWkbType(self, input_wkb_type): return self.wkb_type def inputLayerTypes(self): return [QgsProcessing.TypeVector] def sourceFlags(self): return QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks def processFeature(self, feature, context, feedback): self.expression_context.setFeature(feature) value = self.expression.evaluate(self.expression_context) if self.expression.hasEvalError(): raise QgsProcessingException( self.tr('Evaluation error: {0}').format(self.expression.evalErrorString())) if not value: feature.setGeometry(QgsGeometry()) else: if not isinstance(value, QgsGeometry): raise QgsProcessingException( self.tr('{} is not a geometry').format(value)) feature.setGeometry(value) return [feature]
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context)) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) expressionContext = self.createExpressionContext(parameters, context, source) expression.prepare(expressionContext) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, source.sourceCrs(), QgsFeatureSink.RegeneratePrimaryKey) if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) total = 100.0 / source.featureCount() if source.featureCount() else 0 current_progress = 0 for current, f in enumerate(source.getFeatures()): if feedback.isCanceled(): break if not f.hasGeometry(): continue current_progress = total * current feedback.setProgress(current_progress) expressionContext.setFeature(f) value = expression.evaluate(expressionContext) if expression.hasEvalError(): feedback.pushInfo( self.tr('Evaluation error for feature ID {}: {}').format(f.id(), expression.evalErrorString())) continue fGeom = f.geometry() engine = QgsGeometry.createGeometryEngine(fGeom.constGet()) engine.prepareGeometry() bbox = fGeom.boundingBox() if strategy == 0: pointCount = int(value) else: pointCount = int(round(value * da.measureArea(fGeom))) if pointCount == 0: feedback.pushInfo("Skip feature {} as number of points for it is 0.".format(f.id())) continue index = QgsSpatialIndex() points = dict() nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 feature_total = total / pointCount if pointCount else 1 random.seed() while nIterations < maxIterations and nPoints < pointCount: if feedback.isCanceled(): break rx = bbox.xMinimum() + bbox.width() * random.random() ry = bbox.yMinimum() + bbox.height() * random.random() p = QgsPointXY(rx, ry) geom = QgsGeometry.fromPointXY(p) if engine.contains(geom.constGet()) and \ vector.checkMinDistance(p, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) sink.addFeature(f, QgsFeatureSink.FastInsert) index.addFeature(f) points[nPoints] = p nPoints += 1 feedback.setProgress(current_progress + int(nPoints * feature_total)) nIterations += 1 if nPoints < pointCount: feedback.pushInfo(self.tr('Could not generate requested number of random ' 'points. Maximum number of attempts exceeded.')) feedback.setProgress(100) return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)] width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context) precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context) new_field = self.parameterAsBool(parameters, self.NEW_FIELD, context) formula = self.parameterAsString(parameters, self.FORMULA, context) expression = QgsExpression(formula) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) field_index = layer.fields().lookupField(field_name) if new_field or field_index < 0: res = layer.dataProvider().addAttributes([QgsField(field_name, field_type, '', width, precision)]) if not res: raise QgsProcessingException("The new field couldn't be created! We suggest you to create it using QGIS tools and then update its values with this algorithm.") layer.updateFields() field_index = layer.fields().lookupField(field_name) field = layer.fields()[field_index] exp_context = self.createExpressionContext(parameters, context) if layer is not None: exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) expression.prepare(exp_context) features = layer.getFeatures() total = 100.0 / layer.featureCount() if layer.featureCount() else 0 dict_results = dict() for current, f in enumerate(features): if feedback.isCanceled(): break rownum = current + 1 exp_context.setFeature(f) exp_context.lastScope().setVariable("row_number", rownum) value = expression.evaluate(exp_context) if expression.hasEvalError(): feedback.reportError(expression.evalErrorString()) else: dict_results[f.id()] = {field_index: field.convertCompatible(value)} feedback.setProgress(int(current * total)) layer.dataProvider().changeAttributeValues(dict_results) return {self.OUTPUT: layer}
class GeometryByExpression(QgisFeatureBasedAlgorithm): OUTPUT_GEOMETRY = 'OUTPUT_GEOMETRY' WITH_Z = 'WITH_Z' WITH_M = 'WITH_M' EXPRESSION = 'EXPRESSION' def group(self): return self.tr('Vector geometry') def groupId(self): return 'vectorgeometry' def __init__(self): super().__init__() self.geometry_types = [self.tr('Polygon'), 'Line', 'Point'] def initParameters(self, config=None): self.addParameter(QgsProcessingParameterEnum( self.OUTPUT_GEOMETRY, self.tr('Output geometry type'), options=self.geometry_types, defaultValue=0)) self.addParameter(QgsProcessingParameterBoolean(self.WITH_Z, self.tr('Output geometry has z dimension'), defaultValue=False)) self.addParameter(QgsProcessingParameterBoolean(self.WITH_M, self.tr('Output geometry has m values'), defaultValue=False)) self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION, self.tr("Geometry expression"), defaultValue='$geometry', parentLayerParameterName='INPUT')) def name(self): return 'geometrybyexpression' def displayName(self): return self.tr('Geometry by expression') def outputName(self): return self.tr('Modified geometry') def prepareAlgorithm(self, parameters, context, feedback): self.geometry_type = self.parameterAsEnum(parameters, self.OUTPUT_GEOMETRY, context) self.wkb_type = None if self.geometry_type == 0: self.wkb_type = QgsWkbTypes.Polygon elif self.geometry_type == 1: self.wkb_type = QgsWkbTypes.LineString else: self.wkb_type = QgsWkbTypes.Point if self.parameterAsBool(parameters, self.WITH_Z, context): self.wkb_type = QgsWkbTypes.addZ(self.wkb_type) if self.parameterAsBool(parameters, self.WITH_M, context): self.wkb_type = QgsWkbTypes.addM(self.wkb_type) self.expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context)) if self.expression.hasParserError(): feedback.reportError(self.expression.parserErrorString()) return False self.expression_context = self.createExpressionContext(parameters, context) self.expression.prepare(self.expression_context) return True def outputWkbType(self, input_wkb_type): return self.wkb_type def sourceFlags(self): return QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks def processFeature(self, feature, context, feedback): self.expression_context.setFeature(feature) value = self.expression.evaluate(self.expression_context) if self.expression.hasEvalError(): raise QgsProcessingException( self.tr('Evaluation error: {0}').format(self.expression.evalErrorString())) if not value: feature.setGeometry(QgsGeometry()) else: if not isinstance(value, QgsGeometry): raise QgsProcessingException( self.tr('{} is not a geometry').format(value)) feature.setGeometry(value) return [feature]
def testSuccessfulEvaluationReturnsNoEvalErrorString(self): exp = QgsExpression("True is False") # the result does not matter self.assertEqual(exp.evalErrorString(), "")