def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) expressionContext = self.createExpressionContext( parameters, context, source) x_expression = self.parameterAsString(parameters, self.XEXPRESSION, context) x_expression = QgsExpression(x_expression) if x_expression.hasParserError(): x_expression.prepare(expressionContext) raise QgsProcessingException(x_expression.parserErrorString()) y_expression = self.parameterAsString(parameters, self.YEXPRESSION, context) y_expression = QgsExpression(y_expression) if y_expression.hasParserError(): y_expression.prepare(expressionContext) raise QgsProcessingException(y_expression.parserErrorString()) size = self.parameterAsDouble(parameters, self.SIZE, context) size_property = None if QgsProcessingParameters.isDynamic(parameters, "SIZE"): size_property = parameters["SIZE"] color = self.parameterAsColor(parameters, self.COLOR, context) color_property = None if QgsProcessingParameters.isDynamic(parameters, "COLOR"): color_property = parameters["COLOR"] facet_row = self.parameterAsString(parameters, self.FACET_ROW, context) facet_row_expression = QgsExpression(facet_row) if facet_row and facet_row_expression.hasParserError(): facet_row_expression.prepare(expressionContext) raise QgsProcessingException( facet_row_expression.parserErrorString()) facet_col = self.parameterAsString(parameters, self.FACET_COL, context) facet_col_expression = QgsExpression(facet_col) if facet_col and facet_col_expression.hasParserError(): facet_col_expression.prepare(expressionContext) raise QgsProcessingException( facet_col_expression.parserErrorString()) offline = self.parameterAsBool(parameters, self.OFFLINE, context) if offline is not True: offline = 'cdn' output_html = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context) output_json = self.parameterAsFileOutput(parameters, self.OUTPUT_JSON_FILE, context) colnames = ['x', 'y', 'customdata'] data = [] request = QgsFeatureRequest() request.setFlags(QgsFeatureRequest.NoGeometry) for current, f in enumerate(source.getFeatures(request)): tl = [] expressionContext.setFeature(f) x_val = x_expression.evaluate(expressionContext) y_val = y_expression.evaluate(expressionContext) ids = f.id() tl.append(x_val) tl.append(y_val) tl.append(ids) if facet_row: facet_row_val = facet_row_expression.evaluate( expressionContext) tl.append(facet_row_val) if facet_col: facet_col_val = facet_col_expression.evaluate( expressionContext) tl.append(facet_col_val) if size_property: the_size, _ = size_property.valueAsDouble( expressionContext, size) tl.append(the_size) if color_property: the_color, _ = color_property.value(expressionContext, color) tl.append(the_color) data.append(tl) if facet_row: colnames.append('facet_row') if facet_col: colnames.append('facet_col') if size_property: colnames.append('size') if color_property: colnames.append('color') df = pd.DataFrame(data=data, columns=colnames) feedback.pushDebugInfo(f'{df}') fig = px.scatter(df, x='x', y='y', size='size' if size_property else None, color='color' if color_property else None, facet_row="facet_row" if facet_row else None, facet_col="facet_col" if facet_col else None) if size_property is None: fig.update_traces(marker_size=size) if color_property is None: fig.update_traces(marker_color=color.name()) fig.update_layout(showlegend=True) results = {} fig.write_html(output_html, include_plotlyjs=offline) results[self.OUTPUT_HTML_FILE] = output_html if output_json: fig.write_json(output_json, pretty=True) results[self.OUTPUT_JSON_FILE] = output_json return results
def testCanEvaluateFunction(self): QgsExpression.registerFunction(self.testfun) exp = QgsExpression('testfun(1)') result = exp.evaluate() self.assertEqual('Testing_1', result)
def testReferencedColumnsSet(self): QgsExpression.registerFunction(self.referenced_columns_set) exp = QgsExpression('referenced_columns_set()') self.assertEqual(set(exp.referencedColumns()), set(['a', 'b']))
def processAlgorithm(self, parameters, context, feedback): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = QgsProcessingUtils.mapLayerFromString(layer, context) fields = QgsFields() expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs()) da.setEllipsoid(context.project().ellipsoid()) exp_context = layer.createExpressionContext() for field_def in mapping: fields.append( QgsField(field_def['name'], field_def['type'], field_def['length'], field_def['precision'])) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) expression.prepare(exp_context) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}').format( str(expression.expression()), str(expression.parserErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs(), context) # Create output vector layer with new attributes error_exp = None inFeat = QgsFeature() outFeat = QgsFeature() features = QgsProcessingUtils.getFeatures(layer, context) count = QgsProcessingUtils.featureCount(layer, context) if count > 0: total = 100.0 / count 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(): error_exp = expression break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) else: feedback.setProgress(100) del writer if error_exp is not None: raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}').format( str(error_exp.expression()), str(error_exp.parserErrorString())))
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()) 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.insertFeature(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 showExpressionsBuilder(self): context = createExpressionContext() dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context) context.popScope() values = self.modelParametersDialog.getAvailableValuesOfType( QgsProcessingParameterNumber, QgsProcessingOutputNumber) variables = {} for value in values: if isinstance(value, QgsProcessingModelAlgorithm.ChildParameterSource): if value.source( ) == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter: name = value.parameterName() element = self.modelParametersDialog.model.parameterDefinition( name) desc = element.description() elif value.source( ) == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput: name = "%s_%s" % (value.outputChildId(), value.outputName()) alg = self.modelParametersDialog.model.childAlgorithm( value.outputChildId()) out = alg.algorithm().outputDefinition(value.outputName()) desc = self.tr("Output '{0}' from algorithm '{1}'").format( out.description(), alg.description()) variables[name] = desc values = self.modelParametersDialog.getAvailableValuesOfType([ QgsProcessingParameterFeatureSource, QgsProcessingParameterRasterLayer ], [QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer]) for value in values: if isinstance(value, QgsProcessingModelAlgorithm.ChildParameterSource): if value.source( ) == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter: name = value.parameterName() element = self.modelParametersDialog.model.parameterDefinition( name) desc = element.description() elif value.source( ) == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput: name = "%s_%s" % (value.outputChildId(), value.outputName()) alg = self.modelParametersDialog.model.childAlgorithm( value.outputChildId()) out = alg.algorithm().outputDefinition(value.outputName()) desc = self.tr("Output '{0}' from algorithm '{1}'").format( out.description(), alg.description()) variables['%s_minx' % name] = self.tr("Minimum X of {0}").format(desc) variables['%s_miny' % name] = self.tr("Minimum Y of {0}").format(desc) variables['%s_maxx' % name] = self.tr("Maximum X of {0}").format(desc) variables['%s_maxy' % name] = self.tr("Maximum Y of {0}").format(desc) if isinstance(element, (QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer)): variables['%s_min' % name] = self.tr("Minimum value of {0}").format(desc) variables['%s_max' % name] = self.tr("Maximum value of {0}").format(desc) variables['%s_avg' % name] = self.tr("Mean value of {0}").format(desc) variables['%s_stddev' % name] = self.tr( "Standard deviation of {0}").format(desc) for variable, desc in variables.items(): dlg.expressionBuilder().registerItem("Modeler", variable, "@" + variable, desc, highlightedItem=True) dlg.setWindowTitle(self.tr('Expression based input')) if dlg.exec_() == QDialog.Accepted: exp = QgsExpression(dlg.expressionText()) if not exp.hasParserError(): self.setValue(dlg.expressionText())
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 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 getFeatureWithFormScope(self, params: Dict[str, str], response: QgsServerResponse, project: QgsProject) -> None: """ Get filtered features with a form scope In parameters: LAYER=wms-layer-name FILTER=An expression to filter layer FORM_FEATURE={"type": "Feature", "geometry": {}, "properties": {}} // optionals FIELDS=list of requested field separated by comma WITH_GEOMETRY=False """ layername = params.get('LAYER', '') if not layername: raise ExpressionServiceError( "Bad request error", "Invalid 'GetFeatureWithFormScope' 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 'VirtualField': {} provided". format(layername), 400) # get filter exp_filter = params.get('FILTER', '') if not exp_filter: raise ExpressionServiceError( "Bad request error", "Invalid 'GetFeatureWithFormScope' REQUEST: FILTER parameter is mandatory", 400) # get form feature form_feature = params.get('FORM_FEATURE', '') if not form_feature: raise ExpressionServiceError( "Bad request error", "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE parameter is mandatory", 400) # Check features geojson = {} try: geojson = json.loads(form_feature) except Exception: QgsMessageLog.logMessage( "JSON loads form feature '{}' exception:\n{}".format( form_feature, traceback.format_exc()), "lizmap", Qgis.Critical) raise ExpressionServiceError( "Bad request error", "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed" .format(form_feature), 400) if not geojson or not isinstance(geojson, dict): raise ExpressionServiceError( "Bad request error", "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed" .format(form_feature), 400) if ('type' not in geojson) or geojson['type'] != 'Feature': raise ExpressionServiceError( "Bad request error", "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed: type not defined or not Feature." .format(form_feature), 400) # try to load form feature # read fields form_feature_fields = QgsJsonUtils.stringToFields( form_feature, QTextCodec.codecForName("UTF-8")) # read features form_feature_list = QgsJsonUtils.stringToFeatureList( form_feature, form_feature_fields, QTextCodec.codecForName("UTF-8")) # features not well formed if not form_feature_list: raise ExpressionServiceError( "Bad request error", "Invalid FORM_FEATURE for 'GetFeatureWithFormScope': not GeoJSON feature provided\n{}" .format(form_feature), 400) if len(form_feature_list) != 1: raise ExpressionServiceError( "Bad request error", "Invalid FORM_FEATURE for 'GetFeatureWithFormScope': not GeoJSON feature provided\n{}" .format(form_feature), 400) # Get the form feature form_feat = form_feature_list[0] # create expression context exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(project)) exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer)) exp_context.appendScope(QgsExpressionContextUtils.formScope(form_feat)) # create distance area context da = QgsDistanceArea() da.setSourceCrs(layer.crs(), project.transformContext()) da.setEllipsoid(project.ellipsoid()) # Get filter expression exp_f = QgsExpression(exp_filter) exp_f.setGeomCalculator(da) exp_f.setDistanceUnits(project.distanceUnits()) exp_f.setAreaUnits(project.areaUnits()) if exp_f.hasParserError(): raise ExpressionServiceError( "Bad request error", "Invalid FILTER for 'GetFeatureWithFormScope': Error \"{}\": {}" .format(exp_filter, exp_f.parserErrorString()), 400) if not exp_f.isValid(): raise ExpressionServiceError( "Bad request error", "Invalid FILTER for 'GetFeatureWithFormScope': Expression not valid \"{}\"" .format(exp_filter), 400) exp_f.prepare(exp_context) req = QgsFeatureRequest(exp_f, 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) response.write(separator + jsonExporter.exportFeature(feat, {}, fid)) response.flush() separator = ',\n' response.write(']}') return
def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=None, raise_exceptions=False): """Executes an algorithm modifying features in-place in the input layer. The input layer must be editable or an exception is raised. :param alg: algorithm to run :type alg: QgsProcessingAlgorithm :param active_layer: the editable layer :type active_layer: QgsVectoLayer :param parameters: parameters of the algorithm :type parameters: dict :param context: context, defaults to None :param context: QgsProcessingContext, optional :param feedback: feedback, defaults to None :param feedback: QgsProcessingFeedback, optional :raises QgsProcessingException: raised when the layer is not editable or the layer cannot be found in the current project :return: a tuple with true if success and results :rtype: tuple """ if feedback is None: feedback = QgsProcessingFeedback() if context is None: context = dataobjects.createContext(feedback) if active_layer is None or not active_layer.isEditable(): raise QgsProcessingException( tr("Layer is not editable or layer is None.")) if not alg.supportInPlaceEdit(active_layer): raise QgsProcessingException( tr("Selected algorithm and parameter configuration are not compatible with in-place modifications." )) parameters['OUTPUT'] = 'memory:' try: new_feature_ids = [] active_layer.beginEditCommand(alg.name()) req = QgsFeatureRequest(QgsExpression(r"$id < 0")) req.setFlags(QgsFeatureRequest.NoGeometry) req.setSubsetOfAttributes([]) # Checks whether the algorithm has a processFeature method if hasattr(alg, 'processFeature'): # in-place feature editing # Make a clone or it will crash the second time the dialog # is opened and run alg = alg.create() if not alg.prepare(parameters, context, feedback): raise QgsProcessingException( tr("Could not prepare selected algorithm.")) # Check again for compatibility after prepare if not alg.supportInPlaceEdit(active_layer): raise QgsProcessingException( tr("Selected algorithm and parameter configuration are not compatible with in-place modifications." )) field_idxs = range(len(active_layer.fields())) feature_iterator = active_layer.getFeatures( QgsFeatureRequest(active_layer.selectedFeatureIds()) ) if parameters[ 'INPUT'].selectedFeaturesOnly else active_layer.getFeatures() for f in feature_iterator: new_features = alg.processFeature(f, context, feedback) new_features = make_features_compatible( new_features, active_layer) if len(new_features) == 0: active_layer.deleteFeature(f.id()) elif len(new_features) == 1: new_f = new_features[0] if not f.geometry().equals(new_f.geometry()): active_layer.changeGeometry(f.id(), new_f.geometry()) if f.attributes() != new_f.attributes(): active_layer.changeAttributeValues( f.id(), dict(zip(field_idxs, new_f.attributes())), dict(zip(field_idxs, f.attributes()))) new_feature_ids.append(f.id()) else: active_layer.deleteFeature(f.id()) # Get the new ids old_ids = set( [f.id() for f in active_layer.getFeatures(req)]) if not active_layer.addFeatures(new_features): raise QgsProcessingException( tr("Error adding processed features back into the layer." )) new_ids = set( [f.id() for f in active_layer.getFeatures(req)]) new_feature_ids += list(new_ids - old_ids) results, ok = {}, True else: # Traditional 'run' with delete and add features cycle results, ok = alg.run(parameters, context, feedback) if ok: result_layer = QgsProcessingUtils.mapLayerFromString( results['OUTPUT'], context) # TODO: check if features have changed before delete/add cycle active_layer.deleteFeatures(active_layer.selectedFeatureIds()) new_features = [] for f in result_layer.getFeatures(): new_features.extend( make_features_compatible([f], active_layer)) # Get the new ids old_ids = set([f.id() for f in active_layer.getFeatures(req)]) if not active_layer.addFeatures(new_features): raise QgsProcessingException( tr("Error adding processed features back into the layer." )) new_ids = set([f.id() for f in active_layer.getFeatures(req)]) new_feature_ids += list(new_ids - old_ids) active_layer.endEditCommand() if ok and new_feature_ids: active_layer.selectByIds(new_feature_ids) elif not ok: active_layer.rollBack() return ok, results except QgsProcessingException as e: active_layer.endEditCommand() active_layer.rollBack() if raise_exceptions: raise e QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical) if feedback is not None: feedback.reportError(getattr(e, 'msg', str(e))) return False, {}
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 processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ ueberhoehung = self.parameterAsInt(parameters, self.INPUTZFACTOR, context) rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUTRASTER, context) baseLineLayer = self.parameterAsVectorLayer(parameters, self.INPUTBASELINE, context) lineLayer = self.parameterAsVectorLayer(parameters, self.INPUTINTERSECTIONLAYER, context) exprBaselineID = self.parameterAsExpression(parameters, self.SOURCE_BASLINE_ID, context) outputGeomType = 1 #Output Geometry Type Point # Retrieve the feature source and sink. The 'dest_id' variable is used # to uniquely identify the feature sink, and must be included in the # dictionary returned by the processAlgorithm function. fields=lineLayer.fields() fields.append( QgsField( "station" , QVariant.Double) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py) fields.append( QgsField( "z_factor" , QVariant.Int) ) fields.append( QgsField( "profil_id" , QVariant.Int) ) # If source was not found, throw an exception to indicate that the algorithm # encountered a fatal error. The exception text can be any string, but in this # case we use the pre-built invalidSourceError method to return a standard # helper text for when a source cannot be evaluated if lineLayer is None: raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUTINTERSECTIONLAYER)) (sink, dest_id) = self.parameterAsSink( parameters, self.OUTPUT, context, fields, outputGeomType, lineLayer.sourceCrs() ) try: # Send some information to the user #feedback.pushInfo('CRS is {}'.format(lineLayer.sourceCrs().authid())) # If sink was not created, throw an exception to indicate that the algorithm # encountered a fatal error. The exception text can be any string, but in this # case we use the pre-built invalidSinkError method to return a standard # helper text for when a sink cannot be evaluated if sink is None: raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) features=[] #QgsFeatureIterator if len( baseLineLayer.selectedFeatures() ) > 0: features = baseLineLayer.selectedFeatures() else: features = [feat for feat in baseLineLayer.getFeatures()] feedback.pushInfo( 'Features {} used'.format( len( features ) ) ) # Compute the number of steps to display within the progress bar and # get features from source total = 100.0 / len( features ) if len( features ) else 0 #names = [field.name()+"; " for field in fields] #feedback.pushInfo(''.join( names ) ) #Clear Selection baseLineLayer.removeSelection() counter=0 for current, feature in enumerate(features): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break expr = QgsExpression( exprBaselineID ) exprContext = QgsExpressionContext() exprContext.setFeature(feature) profilID = expr.evaluate ( exprContext ) #, baseLineLayer.fields() ) feedback.pushInfo(str(exprBaselineID) + ": Profil-ID: " + str(profilID) ) #select to current feature baseLineLayer.select( feature.id() ) #create profile feature for selected line #if False: #feedback.pushInfo( "Selection " + str( lineLayer.selectedFeatureCount() ) + " Objects" ) feedback.pushInfo("Counter: " + str(counter) ) profil_features = None try: profil_features = self.runLineIntersection( lineLayer, baseLineLayer, rasterLayer, ueberhoehung, context, feedback) count=0 for grFeature in profil_features: #feedback.pushInfo("Type: " + str(type(grFeature)) ) if not str(type(grFeature)) == "<class 'qgis._core.QgsFeature'>": feedback.pushInfo("Abbruch Type: " + str(type(grFeature)) ) break feedback.pushInfo("Abbruch Type: " + str( grFeature.attributes() ) ) newFeature = QgsFeature( fields ) attrs = grFeature.attributes() attrs.append( ueberhoehung ) attrs.append( profilID ) newFeature.setAttributes( attrs ) newFeature.setGeometry( grFeature.geometry() ) # Add a feature in the sink sink.addFeature( newFeature, QgsFeatureSink.FastInsert) count=count+1 print( "Count: " + str(count) + ' at profile ' + str( profilID ) ) feedback.pushInfo("Count: " + str(count) + ' at profile ' + str( profilID ) ) except Exception as err: print("ERROR at profile " + str( profilID ) + ': '+ str(err.args) + " " + str(repr( err )) + " Fehler: " ) feedback.pushInfo("ERROR at profile " + str( profilID ) + ': '+ str(err.args) + " " + str(repr( err )) + " Fehler: " ) #Clear Selection baseLineLayer.removeSelection() # Update the progress bar feedback.setProgress(int(current * total)) counter=counter+1 except Exception as err: feedback.pushInfo("ERROR: "+ str(err.args) + " " + str(repr( err )) + " Fehler: " ) # # print("ERROR:", err.args, repr( err ), "Fehler: " ) # To run another Processing algorithm as part of this algorithm, you can use # processing.run(...). Make sure you pass the current context and feedback # to processing.run to ensure that all temporary layer outputs are available # to the executed algorithm, and that the executed algorithm can send feedback # reports to the user (and correctly handle cancelation and progress reports!) # Return the results of the algorithm. In this case our only result is # the feature sink which contains the processed features, but some # algorithms may return multiple feature sinks, calculated numeric # statistics, etc. These should all be included in the returned # dictionary, with keys matching the feature corresponding parameter # or output names. return {self.OUTPUT: dest_id}
def populateByExpression(self, adding=False): """ Populates the panel using an expression """ context = dataobjects.createContext() expression_context = context.expressionContext() # use the first row parameter values as a preview during expression creation params, ok = self.panel.parametersForRow(0, warnOnInvalid=False) alg_scope = QgsExpressionContextUtils.processingAlgorithmScope( self.panel.alg, params, context) # create explicit variables corresponding to every parameter for k, v in params.items(): alg_scope.setVariable(k, v, True) # add batchCount in the alg scope to be used in the expressions. 0 is only an example value alg_scope.setVariable('row_number', 0, False) expression_context.appendScope(alg_scope) # mark the parameter variables as highlighted for discoverability highlighted_vars = expression_context.highlightedVariables() highlighted_vars.extend(list(params.keys())) highlighted_vars.append('row_number') expression_context.setHighlightedVariables(highlighted_vars) dlg = QgsExpressionBuilderDialog(layer=None, context=context.expressionContext()) if adding: dlg.setExpectedOutputFormat( self.tr( 'An array of values corresponding to each new row to add')) if not dlg.exec_(): return if adding: exp = QgsExpression(dlg.expressionText()) res = exp.evaluate(expression_context) if type(res) is not list: res = [res] first_row = self.panel.batchRowCount( ) if self.panel.batchRowCount() > 1 else 0 self.panel.addRow(len(res)) self.panel.tblParameters.setUpdatesEnabled(False) for row, value in enumerate(res): self.setRowValue(row + first_row, value, context) self.panel.tblParameters.setUpdatesEnabled(True) else: self.panel.tblParameters.setUpdatesEnabled(False) for row in range(self.panel.batchRowCount()): params, ok = self.panel.parametersForRow(row, warnOnInvalid=False) # remove previous algorithm scope -- we need to rebuild this completely, using the # other parameter values from the current row expression_context.popScope() alg_scope = QgsExpressionContextUtils.processingAlgorithmScope( self.panel.alg, params, context) for k, v in params.items(): alg_scope.setVariable(k, v, True) # add batch row number as evaluable variable in algorithm scope alg_scope.setVariable('row_number', row, False) expression_context.appendScope(alg_scope) # rebuild a new expression every time -- we don't want the expression compiler to replace # variables with precompiled values exp = QgsExpression(dlg.expressionText()) value = exp.evaluate(expression_context) self.setRowValue(row, value, context) self.panel.tblParameters.setUpdatesEnabled(True)
def processAlgorithm(self, feedback): 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 = layer.createExpressionContext() 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()) expression.prepare(exp_context) if expression.hasParserError(): raise GeoAlgorithmExecutionException( self.tr(u'Parser error in expression "{}": {}').format( unicode(expression.expression()), unicode(expression.parserErrorString()))) expressions.append(expression) writer = output.getVectorWriter(fields, layer.wkbType(), layer.crs()) # Create output vector layer with new attributes error_exp = None 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(): error_exp = expression break attrs.append(value) outFeat.setAttributes(attrs) writer.addFeature(outFeat) feedback.setProgress(int(current * total)) del writer if error_exp is not None: raise GeoAlgorithmExecutionException( self.tr(u'Evaluation error in expression "{}": {}').format( unicode(error_exp.expression()), unicode(error_exp.parserErrorString())))
def showExpressionsBuilder(self): context = self.param.expressionContext() dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context) context.popScope() values = self.modelParametersDialog.getAvailableValuesOfType( ParameterNumber, OutputNumber) variables = {} for value in values: if isinstance(value, ValueFromInput): name = value.name element = self.modelParametersDialog.model.inputs[name].param desc = element.description else: name = "%s_%s" % (value.alg, value.output) alg = self.modelParametersDialog.model.algs[value.alg] out = alg.algorithm.getOutputFromName(value.output) desc = self.tr("Output '{0}' from algorithm '{1}'").format( out.description, alg.description) variables[name] = desc values = self.modelParametersDialog.getAvailableValuesOfType( ParameterVector, OutputVector) values.extend( self.modelParametersDialog.getAvailableValuesOfType( ParameterRaster, OutputRaster)) for value in values: if isinstance(value, ValueFromInput): name = value.name element = self.modelParametersDialog.model.inputs[name].param desc = element.description else: name = "%s_%s" % (value.alg, value.output) alg = self.modelParametersDialog.model.algs[value.alg] element = alg.algorithm.getOutputFromName(value.output) desc = self.tr("Output '{0}' from algorithm '{1}'").format( element.description, alg.description) variables['%s_minx' % name] = self.tr("Minimum X of {0}").format(desc) variables['%s_miny' % name] = self.tr("Minimum Y of {0}").format(desc) variables['%s_maxx' % name] = self.tr("Maximum X of {0}").format(desc) variables['%s_maxy' % name] = self.tr("Maximum Y of {0}").format(desc) if isinstance(element, (ParameterRaster, OutputRaster)): variables['%s_min' % name] = self.tr("Minimum value of {0}").format(desc) variables['%s_max' % name] = self.tr("Maximum value of {0}").format(desc) variables['%s_avg' % name] = self.tr("Mean value of {0}").format(desc) variables['%s_stddev' % name] = self.tr( "Standard deviation of {0}").format(desc) for variable, desc in variables.items(): dlg.expressionBuilder().registerItem("Modeler", variable, "@" + variable, desc, highlightedItem=True) dlg.setWindowTitle(self.tr('Expression based input')) if dlg.exec_() == QDialog.Accepted: exp = QgsExpression(dlg.expressionText()) if not exp.hasParserError(): self.setValue(dlg.expressionText())
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 __ok(self, withVertex, withPoint): """ To realize the interpolation :param withVertex: if we want a new interpolated vertex :param withPoint: if we want a new interpolated point """ line_v2, curved = GeometryV2.asLineV2( self.__selectedFeature.geometry(), self.__iface) vertex_v2 = QgsPointV2() vertex_id = QgsVertexId() line_v2.closestSegment(QgsPointV2(self.__mapPoint), vertex_v2, vertex_id, 0) x0 = line_v2.xAt(vertex_id.vertex - 1) y0 = line_v2.yAt(vertex_id.vertex - 1) d0 = Finder.sqrDistForCoords(x0, vertex_v2.x(), y0, vertex_v2.y()) x1 = line_v2.xAt(vertex_id.vertex) y1 = line_v2.yAt(vertex_id.vertex) d1 = Finder.sqrDistForCoords(x1, vertex_v2.x(), y1, vertex_v2.y()) z0 = line_v2.zAt(vertex_id.vertex - 1) z1 = line_v2.zAt(vertex_id.vertex) vertex_v2.addZValue(old_div((d0 * z1 + d1 * z0), (d0 + d1))) if withPoint: pt_feat = QgsFeature(self.__layer.pendingFields()) pt_feat.setGeometry(QgsGeometry(vertex_v2)) for i in range(len(self.__layer.pendingFields())): # default = self.__layer.defaultValue(i, pt_feat) # if default is not None: # print(pt_feat.fields().at(i).name(), pt_feat.fields().at(i).defaultValueExpression(), default) # print(self.__layer.defaultValueExpression(i), self.__layer.expressionField(i)) e = QgsExpression(self.__layer.defaultValueExpression(i)) default = e.evaluate(pt_feat) pt_feat.setAttribute(i, default) if self.__layer.editFormConfig().suppress( ) == QgsEditFormConfig.SuppressOn: self.__layer.addFeature(pt_feat) else: self.__iface.openFeatureForm(self.__layer, pt_feat) if withVertex: line_v2.insertVertex(vertex_id, vertex_v2) self.__lastLayer.changeGeometry(self.__selectedFeature.id(), QgsGeometry(line_v2)) found_features = self.__lastLayer.selectedFeatures() if len(found_features) > 0: if len(found_features) > 1: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "One feature at a time"), level=QgsMessageBar.INFO) else: self.__selectedFeature = found_features[0] else: self.__iface.messageBar().pushMessage( QCoreApplication.translate("VDLTools", "No more feature selected"), level=QgsMessageBar.INFO) self.__iface.mapCanvas().refresh() self.__done() self.__findVertex = True
def testReferencedAttributeIndexesNonExistingField(self): e = QgsExpression() e.setExpression("foo = 1") self.assertTrue(e.isValid()) self.assertEqual(len(e.referencedAttributeIndexes(QgsFields())), 0)
def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exceptions=False): """Executes an algorithm modifying features in-place in the input layer. :param alg: algorithm to run :type alg: QgsProcessingAlgorithm :param parameters: parameters of the algorithm :type parameters: dict :param context: context, defaults to None :type context: QgsProcessingContext, optional :param feedback: feedback, defaults to None :type feedback: QgsProcessingFeedback, optional :param raise_exceptions: useful for testing, if True exceptions are raised, normally exceptions will be forwarded to the feedback :type raise_exceptions: boo, default to False :raises QgsProcessingException: raised when there is no active layer, or it cannot be made editable :return: a tuple with true if success and results :rtype: tuple """ if feedback is None: feedback = QgsProcessingFeedback() if context is None: context = dataobjects.createContext(feedback) # Only feature based algs have sourceFlags try: if alg.sourceFlags( ) & QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks: context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck) except AttributeError: pass active_layer = parameters['INPUT'] # Run some checks and prepare the layer for in-place execution by: # - getting the active layer and checking that it is a vector # - making the layer editable if it was not already # - selecting all features if none was selected # - checking in-place support for the active layer/alg/parameters # If one of the check fails and raise_exceptions is True an exception # is raised, else the execution is aborted and the error reported in # the feedback try: if active_layer is None: raise QgsProcessingException(tr("There is not active layer.")) if not isinstance(active_layer, QgsVectorLayer): raise QgsProcessingException( tr("Active layer is not a vector layer.")) if not active_layer.isEditable(): if not active_layer.startEditing(): raise QgsProcessingException( tr("Active layer is not editable (and editing could not be turned on)." )) if not alg.supportInPlaceEdit(active_layer): raise QgsProcessingException( tr("Selected algorithm and parameter configuration are not compatible with in-place modifications." )) except QgsProcessingException as e: if raise_exceptions: raise e QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical) if feedback is not None: feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True) return False, {} if not active_layer.selectedFeatureIds(): active_layer.selectAll() # Make sure we are working on selected features only parameters['INPUT'] = QgsProcessingFeatureSourceDefinition( active_layer.id(), True) parameters['OUTPUT'] = 'memory:' req = QgsFeatureRequest(QgsExpression(r"$id < 0")) req.setFlags(QgsFeatureRequest.NoGeometry) req.setSubsetOfAttributes([]) # Start the execution # If anything goes wrong and raise_exceptions is True an exception # is raised, else the execution is aborted and the error reported in # the feedback try: new_feature_ids = [] active_layer.beginEditCommand(alg.displayName()) # Checks whether the algorithm has a processFeature method if hasattr(alg, 'processFeature'): # in-place feature editing # Make a clone or it will crash the second time the dialog # is opened and run alg = alg.create() if not alg.prepare(parameters, context, feedback): raise QgsProcessingException( tr("Could not prepare selected algorithm.")) # Check again for compatibility after prepare if not alg.supportInPlaceEdit(active_layer): raise QgsProcessingException( tr("Selected algorithm and parameter configuration are not compatible with in-place modifications." )) field_idxs = range(len(active_layer.fields())) iterator_req = QgsFeatureRequest(active_layer.selectedFeatureIds()) iterator_req.setInvalidGeometryCheck( context.invalidGeometryCheck()) feature_iterator = active_layer.getFeatures(iterator_req) step = 100 / len(active_layer.selectedFeatureIds() ) if active_layer.selectedFeatureIds() else 1 for current, f in enumerate(feature_iterator): feedback.setProgress(current * step) if feedback.isCanceled(): break # need a deep copy, because python processFeature implementations may return # a shallow copy from processFeature input_feature = QgsFeature(f) new_features = alg.processFeature(input_feature, context, feedback) new_features = QgsVectorLayerUtils.makeFeaturesCompatible( new_features, active_layer) if len(new_features) == 0: active_layer.deleteFeature(f.id()) elif len(new_features) == 1: new_f = new_features[0] if not f.geometry().equals(new_f.geometry()): active_layer.changeGeometry(f.id(), new_f.geometry()) if f.attributes() != new_f.attributes(): active_layer.changeAttributeValues( f.id(), dict(zip(field_idxs, new_f.attributes())), dict(zip(field_idxs, f.attributes()))) new_feature_ids.append(f.id()) else: active_layer.deleteFeature(f.id()) # Get the new ids old_ids = set( [f.id() for f in active_layer.getFeatures(req)]) if not active_layer.addFeatures(new_features): raise QgsProcessingException( tr("Error adding processed features back into the layer." )) new_ids = set( [f.id() for f in active_layer.getFeatures(req)]) new_feature_ids += list(new_ids - old_ids) results, ok = {}, True else: # Traditional 'run' with delete and add features cycle # There is no way to know if some features have been skipped # due to invalid geometries if context.invalidGeometryCheck( ) == QgsFeatureRequest.GeometrySkipInvalid: selected_ids = active_layer.selectedFeatureIds() else: selected_ids = [] results, ok = alg.run(parameters, context, feedback) if ok: result_layer = QgsProcessingUtils.mapLayerFromString( results['OUTPUT'], context) # TODO: check if features have changed before delete/add cycle new_features = [] # Check if there are any skipped features if context.invalidGeometryCheck( ) == QgsFeatureRequest.GeometrySkipInvalid: missing_ids = list( set(selected_ids) - set(result_layer.allFeatureIds())) if missing_ids: for f in active_layer.getFeatures( QgsFeatureRequest(missing_ids)): if not f.geometry().isGeosValid(): new_features.append(f) active_layer.deleteFeatures(active_layer.selectedFeatureIds()) for f in result_layer.getFeatures(): new_features.extend( QgsVectorLayerUtils.makeFeaturesCompatible( [f], active_layer)) # Get the new ids old_ids = set([f.id() for f in active_layer.getFeatures(req)]) if not active_layer.addFeatures(new_features): raise QgsProcessingException( tr("Error adding processed features back into the layer." )) new_ids = set([f.id() for f in active_layer.getFeatures(req)]) new_feature_ids += list(new_ids - old_ids) active_layer.endEditCommand() if ok and new_feature_ids: active_layer.selectByIds(new_feature_ids) elif not ok: active_layer.rollBack() return ok, results except QgsProcessingException as e: active_layer.endEditCommand() active_layer.rollBack() if raise_exceptions: raise e QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical) if feedback is not None: feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True) return False, {}
def get_igac_basic_query(names, ladm_units): required_address_fields = [ DomainOwnField(names.EXT_ADDRESS_S_ADDRESS_TYPE_F, "Tipo dirección", names.EXT_ADDRESS_TYPE_D), OwnField(names.EXT_ADDRESS_S_POSTAL_CODE_F, 'Código postal'), EvalExpressionOwnField("Dirección", QgsExpression("""trim( coalesce(get_domain_value_from_code( '{dominio_clase_via_principal}', "{clase_via_principal}" , False, False)||' ', '') || coalesce({valor_via_principal} || ' ', '') || coalesce({letra_via_principal} || ' ', '') || coalesce(get_domain_value_from_code( '{dominio_sector_ciudad}', "{sector_ciudad}", False, False)||' ', '') || coalesce({valor_via_generadora} || ' ', '') || coalesce({letra_via_generadora} || ' ', '') || coalesce({numero_predio} || ' ', '') || coalesce(get_domain_value_from_code( '{dominio_sector_predio}', "{sector_predio}", False, False)||' ', '') || coalesce({complemento} || ' ', '') || coalesce({nombre_predio}, '') )""".format( dominio_clase_via_principal=names.EXT_ADDRESS_TYPE_MAIN_ROAD_CLASS_D, clase_via_principal=names.EXT_ADDRESS_S_MAIN_ROAD_CLASS_F, valor_via_principal=names.EXT_ADDRESS_S_VALUE_MAIN_ROAD_F, letra_via_principal=names.EXT_ADDRESS_S_LETTER_MAIN_ROAD_F, dominio_sector_ciudad=names.EXT_ADDRESS_TYPE_CITY_SECTOR_D, sector_ciudad=names.EXT_ADDRESS_S_CITY_SECTOR_F, valor_via_generadora=names.EXT_ADDRESS_S_VALUE_GENERATOR_ROAD_F, letra_via_generadora=names.EXT_ADDRESS_S_LETTER_GENERATOR_ROAD_F, numero_predio=names.EXT_ADDRESS_S_PARCEL_NUMBER_F, dominio_sector_predio=names.EXT_ADDRESS_TYPE_PARCEL_SECTOR_D, sector_predio=names.EXT_ADDRESS_S_PARCEL_SECTOR_F, complemento=names.EXT_ADDRESS_S_COMPLEMENT_F, nombre_predio=names.EXT_ADDRESS_S_PARCEL_NAME_F)))] query = { QueryNames.LEVEL_TABLE: { QueryNames.LEVEL_TABLE_NAME: names.LC_PLOT_T, QueryNames.LEVEL_TABLE_ALIAS: names.LC_PLOT_T, QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.T_ID_F, names.LC_PLOT_T, names.T_ID_F), QueryNames.TABLE_FIELDS: [OwnField(names.LC_PLOT_T_PLOT_AREA_F, get_full_alias("Área", ladm_units, names.LC_PLOT_T, names.LC_PLOT_T_PLOT_AREA_F)), RelatedOwnFieldObject(names.EXT_ADDRESS_S, names.EXT_ADDRESS_S, required_address_fields, names.EXT_ADDRESS_S_LC_PLOT_F)], QueryNames.LEVEL_TABLE: { QueryNames.LEVEL_TABLE_NAME: names.LC_PARCEL_T, QueryNames.LEVEL_TABLE_ALIAS: names.LC_PARCEL_T, QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.COL_UE_BAUNIT_T_PARCEL_F, names.COL_UE_BAUNIT_T, names.COL_UE_BAUNIT_T_LC_PLOT_F), QueryNames.TABLE_FIELDS: [ OwnField(names.COL_BAUNIT_T_NAME_F, "Nombre"), OwnField(names.LC_PARCEL_T_DEPARTMENT_F, "Departamento"), OwnField(names.LC_PARCEL_T_MUNICIPALITY_F, "Municipio"), OwnField(names.LC_PARCEL_T_NUPRE_F, "NUPRE"), OwnField(names.LC_PARCEL_T_ID_OPERATION_F, "Id operación"), OwnField(names.LC_PARCEL_T_FMI_F, "FMI"), OwnField(names.LC_PARCEL_T_PARCEL_NUMBER_F, "Número predial"), OwnField(names.LC_PARCEL_T_PREVIOUS_PARCEL_NUMBER_F, "Número predial anterior"), DomainOwnField(names.LC_PARCEL_T_TYPE_F, "Tipo", names.COL_BAUNIT_TYPE_D) ], QueryNames.LEVEL_TABLE: { QueryNames.LEVEL_TABLE_NAME: names.LC_BUILDING_T, QueryNames.LEVEL_TABLE_ALIAS: names.LC_BUILDING_T, QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.COL_UE_BAUNIT_T_LC_BUILDING_F, names.COL_UE_BAUNIT_T, names.COL_UE_BAUNIT_T_PARCEL_F), QueryNames.TABLE_FIELDS: [ OwnField(names.LC_BUILDING_T_BUILDING_AREA_F, "Área"), RelatedOwnFieldObject(names.EXT_ADDRESS_S, names.EXT_ADDRESS_S, required_address_fields, names.EXT_ADDRESS_S_LC_BUILDING_F) ], QueryNames.LEVEL_TABLE: { QueryNames.LEVEL_TABLE_NAME: names.LC_BUILDING_UNIT_T, QueryNames.LEVEL_TABLE_ALIAS: names.LC_BUILDING_UNIT_T, QueryNames.FILTER_SUB_LEVEL: FilterSubLevel(names.T_ID_F, names.LC_BUILDING_UNIT_T, names.LC_BUILDING_UNIT_T_BUILDING_F), QueryNames.TABLE_FIELDS: [ OwnField(names.LC_BUILDING_UNIT_T_TOTAL_FLOORS_F, "Número de pisos"), OwnField(names.LC_BUILDING_UNIT_T_TOTAL_ROOMS_F, "Número de habitaciones"), OwnField(names.LC_BUILDING_UNIT_T_TOTAL_BATHROOMS_F, "Número de baños"), OwnField(names.LC_BUILDING_UNIT_T_TOTAL_LOCALS_F, "Número de locales"), DomainOwnField(names.LC_BUILDING_UNIT_T_BUILDING_TYPE_F, "Tipo construcción", names.LC_BUILDING_TYPE_D), DomainOwnField(names.LC_BUILDING_UNIT_T_BUILDING_UNIT_TYPE_F, "Tipo unidad de construcción", names.LC_BUILDING_UNIT_TYPE_D), DomainOwnField(names.LC_BUILDING_UNIT_T_FLOOR_TYPE_F, "Tipo de planta", names.LC_BUILDING_FLOOR_TYPE_D), DomainOwnField(names.LC_BUILDING_UNIT_T_DOMAIN_TYPE_F, "Tipo dominio", names.LC_DOMAIN_BUILDING_TYPE_D), OwnField(names.LC_BUILDING_UNIT_T_FLOOR_F, "Ubicación en el piso"), OwnField(names.LC_BUILDING_UNIT_T_BUILT_AREA_F, get_full_alias("Área construida", ladm_units, names.LC_BUILDING_UNIT_T, names.LC_BUILDING_UNIT_T_BUILT_AREA_F)), DomainOwnField(names.LC_BUILDING_UNIT_T_USE_F, "Uso", names.LC_BUILDING_UNIT_USE_D), RelatedOwnFieldObject(names.EXT_ADDRESS_S, names.EXT_ADDRESS_S, required_address_fields, names.EXT_ADDRESS_S_LC_BUILDING_UNIT_F) ] } } } } } return query
def responseComplete(self): ''' Send new response ''' self.handler = self.serverIface.requestHandler() params = self.handler.parameterMap( ) # Check if needed params are passed # If not, do not change QGIS Server response if params['SERVICE'].lower() != 'wms': return # Check if getprintatlas request. If not, just send the response if 'REQUEST' not in params or params['REQUEST'].lower() not in ['getprintatlas', 'getcapabilitiesatlas']: return # Get capabilities if params['REQUEST'].lower() == 'getcapabilitiesatlas': body = { 'status': 'success', 'metadata': self.metadata } self.setJsonResponse( '200', body) return # Check if needed params are set if 'TEMPLATE' not in params or 'FORMAT' not in params or 'DPI' not in params or 'MAP' not in params or 'EXP_FILTER' not in params: body = { 'status': 'fail', 'message': 'Missing parameters: TEMPLATE, FORMAT, DPI, MAP, EXP_FILTER are required ' } self.setJsonResponse( '200', body) return self.project_path = self.serverInterface().configFilePath() self.composer_name = params['TEMPLATE'] self.feature_filter = params['EXP_FILTER'] # check expression qExp = QgsExpression(self.feature_filter) if not qExp.hasParserError(): qReq = QgsFeatureRequest(qExp) qReq.setLimit(1) ok = True else: body = { 'status': 'fail', 'message': 'An error occured while parsing the given expression: %s' % qExp.parserErrorString() } syslog.syslog(syslog.LOG_ERR, "ATLAS - ERROR EXPRESSION: %s" % qExp.parserErrorString()) self.setJsonResponse( '200', body) return try: pdf = self.print_atlas( project_path=self.project_path, composer_name=self.composer_name, predefined_scales=self.predefined_scales, feature_filter=self.feature_filter ) except: pdf = None if not pdf: body = { 'status': 'fail', 'message': 'ATLAS - Error while generating the PDF' } QgsMessageLog.logMessage("ATLAS - No PDF generated in %s" % pdf, 'atlasprint', Qgis.Info) self.setJsonResponse( '200', body) return # Send PDF self.handler.clear() self.handler.setResponseHeader('Content-type', 'application/pdf') self.handler.setResponseHeader('Status', '200') try: with open(pdf, 'rb') as f: loads = f.readlines() ba = QByteArray(b''.join(loads)) self.handler.appendBody(ba) except: body = { 'status': 'fail', 'message': 'Error occured while reading PDF file', } self.setJsonResponse( '200', body) finally: os.remove(pdf) return
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ ueberhoehung = self.parameterAsDouble(parameters, self.INPUTZFACTOR, context) baseLineLayer = self.parameterAsVectorLayer(parameters, self.INPUTBASELINE, context) vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUTVECTORLAYER, context) baselineIDFieldName = self.parameterAsExpression( parameters, self.PROFIL_BASELINE_ID, context) offsetFieldName = self.parameterAsString(parameters, self.OFFSETFIELD, context) vectorLayerBaselineIDFieldName = self.parameterAsExpression( parameters, self.INPUTVECTORLAYER_BASLINE_ID, context) outputGeomType = vectorLayer.wkbType() #Output Geometry Type Point offsetExpr = QgsExpression(offsetFieldName) if offsetExpr.hasParserError(): feedback.reportError("Offset Expression failed: " + offsetExpr.parserErrorString()) offsetExpr = "0" # Retrieve the feature source and sink. The 'dest_id' variable is used # to uniquely identify the feature sink, and must be included in the # dictionary returned by the processAlgorithm function. fields = vectorLayer.fields() #fields.append( QgsField( "station" , QVariant.Double ) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py) #.append( QgsField( "abstand" , QVariant.Double ) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py) #fields.append( QgsField( "z_factor" , QVariant.Int ) ) # will be added and filled by Subprocess (algorithm_TransformToProfil_LineIntersection.py) #fields.append( QgsField( "profil_id" , QVariant.Int ) ) if vectorLayer is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUTVECTORLAYER)) if vectorLayer is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.OUTPUT)) #check if vectorlayer has Features if vectorLayer.featureCount() == 0: msg = self.tr("Error: Layer ", vectorLayer.name(), "is emty! ") feedback.reportError(msg) raise QgsProcessingException(msg) #check if baselineLayer has Features if baseLineLayer.featureCount() == 0: msg = self.tr("Error: Layer ", baseLineLayer.name(), "is emty! ") feedback.reportError(msg) raise QgsProcessingException(msg) #take CRS from Project crsProject = QgsProject.instance().crs() (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, outputGeomType, vectorLayer.sourceCrs()) # If sink was not created, throw an exception to indicate that the algorithm # encountered a fatal error. The exception text can be any string, but in this # case we use the pre-built invalidSinkError method to return a standard # helper text for when a sink cannot be evaluated if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) offsetExprContext = QgsExpressionContext() # Send some information to the user #feedback.pushInfo('CRS is {}'.format(vectorLayer.sourceCrs().authid())) features = [] #QgsFeatureIterator if len(vectorLayer.selectedFeatures()) > 0: features = vectorLayer.selectedFeatures() else: features = [feat for feat in vectorLayer.getFeatures()] feedback.pushInfo('Features {} used'.format(len(features))) # Compute the number of steps to display within the progress bar and # get features from source total = 100.0 / len(features) if len(features) else 0 #names = [field.name()+"; " for field in fields] #feedback.pushInfo(''.join( names ) ) #Clear Selection vectorLayer.removeSelection() i = 0 for current, feature in enumerate(features): try: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break # Offset abstand = 0 offsetExprContext.setFeature(feature) try: abstand = offsetExpr.evaluate(offsetExprContext) except: msg = self.tr( "Error while calculating Offset from Expression. Feature " + str(feat.attributes())) feedback.reportError(msg) raise QgsProcessingException(msg) try: #check for numeric Expression Data type a = int(abstand) b = float(abstand) except: msg = self.tr( "Feature(" + feature.id() + "): " + "Error Offset Experession result must be numeric, not " + str(type(abstand))) feedback.reportError(msg) raise QgsProcessingException(msg) # get Profile Baseline by ID #profil_id of the profile feature expr = QgsExpression(vectorLayerBaselineIDFieldName) exprContext = QgsExpressionContext() exprContext.setFeature(feature) profil_id = expr.evaluate(exprContext) # baseline ID exprBaseLineID = QgsExpression(baselineIDFieldName) # remove quotes "" if baselineIDFieldName.startswith('\"'): baselineIDFieldName = baselineIDFieldName.replace('\"', '') exprText = baselineIDFieldName + '=' + str(profil_id) #feedback.pushInfo('waehle Basislinie: ' + exprText ) exprBaseLine = QgsExpression(exprText) selection = baseLineLayer.getFeatures( QgsFeatureRequest(exprBaseLine)) baseLineFeature = next(selection) linRef = LinearReferencingMaschine(baseLineFeature.geometry(), crsProject, feedback) #feedback.pushInfo("Profil_id: " + str( profil_id ) + ' feature: ' + str( feature.attributes() ) ) geom = feature.geometry() feedback.pushInfo("srcgeom: " + str(geom.asWkt())) subFeatureList = [] layerUtils = LayerUtils(crsProject, feedback) subFeatureList = layerUtils.multiPartToSinglePartFeature( feature) feedback.pushInfo("subFeatureList: " + str(len(subFeatureList))) #preparation of profile geometrys prepSubFeatureList = [] for iP, f in enumerate(subFeatureList): if linRef.isSimpleLine or vectorLayer.geometryType( ) == 0 or vectorLayer.geometryType( ) == 1: #Point (Line nur temporär): prepSubFeatureList.append(f) #keep old feature else: # Basisline hat Knickpunkte, Profilgeometrien müssen ggf. mit zusätzlichen Stützpunkten gefüllt werden # Baseline has breakpoints, we have to fill the profile geometrys with additional vertices filledSingleGeom = None if vectorLayer.geometryType() == 2: #Polygon filledSingleGeomList = self.fillPolygonVertices( f.geometry(), linRef, crsProject, feedback) #elif vectorLayer.geometryType() == 1: #Line if len(filledSingleGeomList) > 0: for g in filledSingleGeomList: #create a feature for each filled sub geometry filledFeature = QgsFeature(f) filledFeature.setGeometry(g) filledFeature.setAttributes(f.attributes()) prepSubFeatureList.append(filledFeature) else: prepSubFeatureList.append(f) #keep old feature feedback.reportError( "Feature geometry can not be filled: " + str(f.attributes())) feedback.pushInfo("prepSubFeatureList: " + str(len(prepSubFeatureList))) #Back to Real World Transformation for each sub Feature realWorldSubFeatureList = [] for pFeat in prepSubFeatureList: #Create Real World geometry with LinearReferencingMaschine realWorldFeat = linRef.transformProfileFeatureToRealWorld( pFeat, vectorLayer.crs(), feedback, abstand, ueberhoehung) realWorldSubFeatureList.append(realWorldFeat) feedback.pushInfo(str(realWorldFeat.geometry().asWkt())) ##### ggf features könnten hier wieder gruppiert werden ###### #write real worl Features to output layer for rwFeat in realWorldSubFeatureList: sink.addFeature(rwFeat, QgsFeatureSink.FastInsert) i = i + 1 # Update the progress bar feedback.setProgress(int(i * total)) except: msg = self.tr("Error on Feature " + str(i) + " " + str(feature.attributes())) feedback.reportError(msg) raise QgsProcessingException(msg) msgInfo = self.tr( str(i) + " Features were transformed to real world coordinates") feedback.pushInfo(msgInfo) # Return the results of the algorithm. In this case our only result is return {self.OUTPUT: dest_id} # # print("ERROR:", err.args, repr( err ), "Fehler: " ) # To run another Processing algorithm as part of this algorithm, you can use # processing.run(...). Make sure you pass the current context and feedback # to processing.run to ensure that all temporary layer outputs are available # to the executed algorithm, and that the executed algorithm can send feedback # reports to the user (and correctly handle cancelation and progress reports!) # Return the results of the algorithm. In this case our only result is # the feature sink which contains the processed features, but some # algorithms may return multiple feature sinks, calculated numeric # statistics, etc. These should all be included in the returned # dictionary, with keys matching the feature corresponding parameter # or output names. feedback.pushInfo(str(counter) + " Profile Baslines processed") return {self.OUTPUT: dest_id}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ sourceL = self.parameterAsSource(parameters, self.INPUT_L, context) sourceF = self.parameterAsMatrix(parameters, self.INPUT_F, context) filtro = self.parameterAsString(parameters, self.GROUP_BY, context) titolo = self.parameterAsString(parameters, self.INPUT_T, context) html = self.parameterAsFileOutput(parameters, self.OUTPUT, context) source_path = self.parameterAsString(parameters, self.INPUT_L, context) f_base = self.parameterAsString(parameters, self.INPUT_D, context) icona = self.parameterAsString(parameters, self.INPUT_I, context) fogliocss = self.parameterAsString(parameters, self.INPUT_S, context) rel_path = self.parameterAsBool(parameters, self.INPUT_ABS, context) #FASE #01 - cerco la path del progetto if QgsProject.instance().homePath(): path_proj = QgsProject.instance().homePath() #windowizzo la path quale che sia path_proj = str(Path(path_proj)) #rimuovo geopakage: se presente path_proj = path_proj.replace('geopackage:', '') #print('path proj ', path_proj) else: feedback.reportError( 'WARNING NO PROJECT PATH: the html file may not work correctly\n' ) #print('***** no project path') path_proj = '' #tolgo %20 e metto spazio path_proj = path_proj.replace('%20', ' ') #FASE #02 - cerco la path del file di input path_file = (self.parameterDefinition('INPUT_L').valueAsPythonString( parameters['INPUT_L'], context)) path_file = path_file[1:path_file.rfind('/') + 1] if 'memory' in path_file: file_mem = True path_file = '' #print('temporary file') else: file_mem = False #windowizzo la path quale che sia path_file = str(Path(path_file)) #print('file path ', path_file) #tolgo %20 e metto spazio path_file = path_file.replace('%20', ' ') #FASE #03 - scelgo la path da usare tra le due: prioritaria quella di progetto if path_proj: path_dir = path_proj if path_proj not in path_file and path_file != '': feedback.reportError('WARNING PATH FILE ' + path_file) feedback.reportError('OUTSIDE PROJECT PATH ' + path_proj) feedback.reportError('MOST LIKELY IT WON' 'T WORK' + '\n') elif path_file == '': feedback.reportError('WARNING TEMPORARY LAYER WITHOUT PATH\n') else: path_dir = path_file if path_dir: feedback.reportError( 'WARNING use the path of the input file ' + path_dir + '\n') else: feedback.reportError('WARNING TEMPORARY LAYER WITHOUT PATH\n') #FASE #04 - controllo se si sta salvando file con percorsi relativi nella cartella di progetto if path_dir not in str(Path(html)) and 'processing' not in str( Path(html)): #print('html ', str(Path(html))) feedback.reportError( 'WARNING HTML WITH RELATIVE PATH SAVED OUTSIDE THE PROJECT PATH DOES NOT WORK PROPERLY\n' ) if 'processing' in str(Path(html)): #print('html ', str(Path(html))) feedback.reportError( 'WARNING TEMPORARY HTML WORK PROPERLY ONLY WITH ABSOLUTE PATH\n' ) #FASE #05 - controllo se icona e css sono entro la cartella progetto if fogliocss and (path_dir not in fogliocss): feedback.reportError( 'WARNING css PATH OUTSIDE PROJECT PATH: the html file may not work correctly\n' ) if icona and path_dir not in icona: feedback.reportError( 'WARNING icon PATH OUTSIDE PROJECT PATH: the html file may not work correctly\n' ) #FASE #06 - aggiungo terminatore di percorso se non è un file temporaneo if path_dir != '': path_dir = path_dir + '\\' #print('Final path ', path_dir) #FASE #07 - modifica se csv in input if source_path.find(".csv"): source_path = 'file:///' + source_path[0:source_path.rfind('/') + 1] #FASE #08 recupero dimensioni foto e icona, titolo e riordino a causa di un bug wi, hi, wf, hf = f_base.split(';') titolo = titolo.replace('\"', '') intestazione = titolo.replace('"', '') intestazione = titolo.replace('\'', '') #riordino campi come da selezione per bug cleanlist = [] [cleanlist.append(x) for x in sourceF if x not in cleanlist] sourceF = cleanlist #FASE #09 - inizializzo variabile per barra % esecuzione script # Compute the number of steps to display within the progress bar and # get features from source total = 100.0 / sourceL.featureCount() if sourceL.featureCount() else 0 #FASE #10 - filtra dati se richiesto if len(filtro) > 0: request = QgsFeatureRequest(QgsExpression(filtro)) features = sourceL.getFeatures(request) else: features = sourceL.getFeatures() #FASE #11 - produco il file in uscita with open(html, 'w') as output_file: # write header line = '<html>\r' output_file.write(line) #FASE #11.01 - se richiesto inserisco foglio css if fogliocss: if not rel_path or 'processing' in html: fogliocss = 'file:///' + fogliocss else: fogliocss = str(Path(fogliocss)) fogliocss = fogliocss.replace(path_dir, '') line = '<head>\r<link rel="stylesheet" href="' + fogliocss + '">\r</head>' output_file.write(line) #FASE #11.02 - se richiesto inserisco icona e titolo if icona or titolo: line = '<div>' if icona: if not rel_path or 'processing' in html: icona = 'file:///' + icona else: icona = str(Path(icona)) icona = icona.replace(path_dir, '') line = '<img src="' + icona + '" style="width:' + wi + ';height:' + hi + ';">' output_file.write(line) line = '' if titolo: if icona: line = line + '<b>' + '  ' + titolo + '</b>' else: line = line + '<b>' + titolo + '</b>' output_file.write(line) line = '</div>' output_file.write(line) line = None #FASE #11.03 - compongo tabella line = '<table class="Table">\r<thead>\r<tr>\r' output_file.write(line) #titoli colonne line = ''.join(('<th style="width:auto">' + str(name) + '</<th>\r') for name in sourceF) + '</tr>\r' output_file.write(line) line = '</thead>\r<tbody>\r' output_file.write(line) #righe tabella for current, f in enumerate(features): line = '<tr>\r' output_file.write(line) for name in sourceF: #controllo se si tratta di una immagine try: img_type = f[name].split(".") img_type = img_type[len(img_type) - 1] #print('img ok ', name, f[name], img_type) except: img_type = '' #print('img no ', name, f[name], img_type) #se è un'immagine e/o ha un percorso if img_type in [ "JPEG", "jpeg", "JPG", "jpg", "PNG", "png" ]: #se non è un file temporaneo o non voglio riferimenti relativi if not rel_path or 'processing' in html: if file_mem: img_name = 'file:///' else: img_name = '' if path_dir not in str(Path(f[name])): img_name = img_name + path_dir img_name = img_name + f[name] else: #se voglio riferimenti relativi img_name = str(Path(f[name])) img_name = img_name.replace(path_dir, '') line = ''.join('<td><center><img src =' + "'" + img_name + "'" + 'alt=' + "'" + img_name + "'" + 'width="' + wf + '" height="' + hf + '"></center></td>\r') else: try: line = ''.join('<td>' + f[name].toString("dd.MM.yyyy") + '</td>\r') except: line = ''.join('<td>' + str(f[name]) + '</td>\r') output_file.write(line) line = '</tr>\r' output_file.write(line) # Update the progress bar feedback.setProgress(int(current * total)) line = '</tbody>\r</table>\r</html>' output_file.write(line) return {self.OUTPUT: html}
def testQgsExpressionRepr(self): e = QgsExpression('my expression') self.assertEqual(e.__repr__(), "<QgsExpression: 'my expression'>")
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 testReferencedColumnsNoSet(self): success = QgsExpression.registerFunction( self.no_referenced_columns_set) exp = QgsExpression('no_referenced_columns_set()') self.assertEqual(exp.referencedColumns(), {QgsFeatureRequest.AllAttributes})
def testReferencedColumnsNoSet(self): QgsExpression.registerFunction(self.no_referenced_columns_set) exp = QgsExpression('no_referenced_columns_set()') self.assertEqual(exp.referencedColumns(), {QgsFeatureRequest.ALL_ATTRIBUTES})
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, 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().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 = 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{0}').format(error))
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}