def prepareAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, 'INPUT', context) mapping = self.parameterAsFieldsMapping(parameters, self.FIELDS_MAPPING, context) self.fields = QgsFields() self.expressions = [] da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs()) da.setEllipsoid(context.project().ellipsoid()) # create an expression context using thread safe processing context self.expr_context = self.createExpressionContext(parameters, context, source) for field_def in mapping: self.fields.append(QgsField(name=field_def['name'], type=field_def['type'], typeName="", len=field_def.get('length', 0), prec=field_def.get('precision', 0))) expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) if expression.hasParserError(): raise QgsProcessingException( self.tr(u'Parser error in expression "{}": {}') .format(str(expression.expression()), str(expression.parserErrorString()))) self.expressions.append(expression) return True
def prepareAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, 'INPUT', context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, 'INPUT')) mapping = self.parameterAsFieldsMapping(parameters, self.FIELDS_MAPPING, context) self.fields = QgsFields() self.expressions = [] da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.project().ellipsoid()) # create an expression context using thread safe processing context self.expr_context = self.createExpressionContext( parameters, context, source) for field_def in mapping: self.fields.append( QgsField(name=field_def['name'], type=field_def['type'], typeName="", len=field_def.get('length', 0), prec=field_def.get('precision', 0))) if field_def['expression']: expression = QgsExpression(field_def['expression']) expression.setGeomCalculator(da) expression.setDistanceUnits(context.project().distanceUnits()) expression.setAreaUnits(context.project().areaUnits()) if expression.hasParserError(): feedback.reportError( self.tr(u'Parser error in expression "{}": {}').format( expression.expression(), expression.parserErrorString())) return False self.expressions.append(expression) else: self.expressions.append(None) return True
def processAlgorithm(self, 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(QgsProject.instance().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(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( 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) 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, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = 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) progress.setPercentage(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 processAlgorithm(self, parameters, context: QgsProcessingContext, feedback: QgsProcessingFeedback): """Here is where the processing itself takes place.""" feedback.setProgress(0) na = qgis_utils.plugins["qgepplugin"].network_analyzer # init params reach_layer = self.parameterAsVectorLayer(parameters, self.REACH_LAYER, context) flow_layer = self.parameterAsVectorLayer(parameters, self.FLOWTIMES_LAYER, context) fk_reach_field = self.parameterAsFields(parameters, self.FK_REACH_FIELD, context)[0] flow_time_field = self.parameterAsFields(parameters, self.FLOWTIMES_FIELD, context)[0] # create feature sink fields = QgsFields() fields.append(QgsField('flow_time', QVariant.Double)) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.LineString, reach_layer.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) # get selected reach iterator = reach_layer.getSelectedFeatures() feature_count = reach_layer.selectedFeatureCount() if feature_count != 1: raise QgsProcessingException( self.invalidSourceError(parameters, self.REACH_LAYER)) reach_feature = QgsFeature() iterator.nextFeature(reach_feature) assert reach_feature.isValid() qgep_reach_obj_id = reach_feature.attribute('obj_id') # get top node reach_features = na.getFeaturesByAttr(na.getEdgeLayer(), 'obj_id', [qgep_reach_obj_id]).asDict() assert len(reach_features) > 0 from_pos = 1 top_node = None for fid, reach_feature in reach_features.items(): if from_pos > reach_feature.attribute('from_pos'): top_node = reach_feature.attribute('from_obj_id_interpolate') from_pos = reach_feature.attribute('from_pos') assert top_node is not None nodes = na.getFeaturesByAttr(na.getNodeLayer(), 'obj_id', [top_node]).asDict() assert len(nodes) == 1 top_node_id = next(iter(nodes.values())).id() # create graph _, edges = na.getTree(top_node_id) feedback.setProgress(50) cache_edge_features = na.getFeaturesById( na.getEdgeLayer(), [edge[2]['feature'] for edge in edges]).asDict() # join and accumulate flow times i = -1 flow_time = 0.0 while True: i += 1 feedback.setProgress(50 + i / len(edges) * 50) if i >= len(edges): break edge = edges[i] edge_feature = cache_edge_features[edge[2]['feature']] # TODO: if top_pos != 1 => merge if edge_feature.attribute('type') != 'reach': continue rate = edge_feature.attribute('to_pos') - edge_feature.attribute( 'from_pos') assert 0 < rate <= 1 expression = QgsExpression("{fk_reach} = '{obj_id}'".format( fk_reach=fk_reach_field, obj_id=edge_feature['obj_id'])) print(expression.expression()) request = QgsFeatureRequest(expression) flow_time_feature = next(flow_layer.getFeatures(request)) if not flow_time_feature.isValid(): break flow_time += rate * flow_time_feature.attribute(flow_time_field) sf = QgsFeature() sf.setFields(fields) sf.setAttribute('flow_time', flow_time) sf.setGeometry(edge_feature.geometry()) sink.addFeature(sf, QgsFeatureSink.FastInsert) #f.setAttributes(attrs) #sink.addFeature(f, QgsFeatureSink.FastInsert) #feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}
def processAlgorithm(self, progress): layer = self.getParameterValue(self.INPUT_LAYER) mapping = self.getParameterValue(self.FIELDS_MAPPING) output = self.getOutputFromName(self.OUTPUT_LAYER) layer = dataobjects.getObjectFromUri(layer) fields = [] expressions = [] da = QgsDistanceArea() da.setSourceCrs(layer.crs().srsid()) da.setEllipsoidalMode( iface.mapCanvas().mapSettings().hasCrsTransformEnabled()) da.setEllipsoid(QgsProject.instance().readEntry( 'Measure', '/Ellipsoid', GEO_NONE)[0]) exp_context = 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) progress.setPercentage(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 virtualFields(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 """ layer_name = params.get('LAYER', '') if not layer_name: raise ExpressionServiceError( "Bad request error", "Invalid 'VirtualFields' REQUEST: LAYER parameter is mandatory", 400) # get layer layer = find_vector_layer(layer_name, project) # layer not found if not layer: raise ExpressionServiceError( "Bad request error", "Invalid LAYER parameter for 'VirtualFields': {} provided".format(layer_name), 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 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 with_geom = params.get('WITH_GEOMETRY', '').lower() in ['true', '1', 't'] if not with_geom: req.setFlags(QgsFeatureRequest.NoGeometry) # Fields pk_attributes = layer.primaryKeyAttributes() attribute_list = [i for i in pk_attributes] fields = layer.fields() r_fields = [f.strip() for f in params.get('FIELDS', '').split(',') if f] for f in r_fields: attribute_list.append(fields.indexOf(f)) # response response.setStatusCode(200) response.setHeader("Content-Type", "application/json") response.write('{ "type": "FeatureCollection","features":[') response.flush() json_exporter = QgsJsonExporter(layer) if attribute_list: json_exporter.setAttributes(attribute_list) separator = '' for feat in layer.getFeatures(req): fid = layer_name + '.' + get_server_fid(feat, pk_attributes) 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 + json_exporter.exportFeature(feat, extra, fid)) response.flush() separator = ',\n' response.write(']}') return
def evaluate(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 = find_vector_layer(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 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 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 add_form_scope = 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 add_form_scope: 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 add_form_scope: # need to prepare the expression because the context has 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 processAlgorithm(self, parameters, context, feedback): t_regard = self.parameterAsSource(parameters, self.MANHOLES_TABLE, context) g_regard = self.parameterAsSource(parameters, self.GEOM_MANHOLES, context) t_troncon = self.parameterAsVectorLayer(parameters, self.SEGMENTS_TABLE, context) g_troncon = self.parameterAsVectorLayer(parameters, self.GEOM_SEGMENTS, context) exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_troncon)) exp_str = '"id_geom_troncon" IS NULL' 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) r_ids = [] # identifiant des regards l_t_f = {} # lien troncon fichier l_f_t = {} # lien fichier troncons troncons = {} sorties = {} entrees = {} for tro in t_troncon.getFeatures(request): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} segment_number = tro['id'] r1 = tro['id_regard1'] r2 = tro['id_regard2'] if r1 not in r_ids: r_ids.append(r1) if r2 not in r_ids: r_ids.append(r2) fid = tro['id_file'] l_t_f[segment_number] = fid if fid in l_f_t: l_f_t[fid] = l_f_t[fid] + [segment_number] else: l_f_t[fid] = [segment_number] troncons[segment_number] = (r1, r2) if r1 in sorties: sorties[r1] = sorties[r1] + [segment_number] else: sorties[r1] = [segment_number] if r2 in entrees: entrees[r2] = entrees[r2] + [segment_number] else: entrees[r2] = [segment_number] exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(t_regard.createExpressionContextScope()) exp_str = ('"id_geom_regard" IS NOT NULL ' 'AND ' '"id" IN ({})').format(','.join([str(i) for i in r_ids] + ['-1'])) 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) g_ids = [] # identifiants des géométrie de regards l_r_g = {} # lien regard geometrie l_g_r = {} # lien geometrie regards for reg in t_regard.getFeatures(request): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} segment_number = reg['id'] fid = reg['id_file'] if segment_number in sorties: sorties[segment_number] = [ trid for trid in sorties[segment_number] if l_t_f[trid] == fid ] if segment_number in entrees: entrees[segment_number] = [ trid for trid in entrees[segment_number] if l_t_f[trid] == fid ] gid = reg['id_geom_regard'] l_r_g[segment_number] = gid if gid not in g_ids: g_ids.append(gid) if gid in l_g_r: l_g_r[gid] = l_g_r[gid] + [segment_number] else: l_g_r[gid] = [segment_number] exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(g_regard.createExpressionContextScope()) exp_str = '"id" IN ({})'.format(','.join([str(i) for i in g_ids] + ['-1'])) 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) points = {} pt_labels = {} for reg in g_regard.getFeatures(request): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} segment_number = reg['id'] points[segment_number] = reg.geometry().asPoint() pt_labels[segment_number] = reg['label'] lines = {} for gid in points: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} if gid not in l_g_r: continue for rid in l_g_r[gid]: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} if rid in sorties: for tid in sorties[rid]: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} if tid in lines: continue if tid not in troncons: continue r2 = troncons[tid][1] if r2 not in l_r_g: continue g2 = l_r_g[r2] if g2 not in points: continue lines[tid] = (gid, g2) if rid in entrees: for tid in entrees[rid]: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} if tid in lines: continue if tid not in troncons: continue r1 = troncons[tid][0] if r1 not in l_r_g: continue g1 = l_r_g[r1] if g1 not in points: continue lines[tid] = (g1, gid) # Creation des troncons l_t_g = {} # lien troncon et geometrie troncon l_pts_t = {} # lien points troncons features = [] # les objets de geometrie de troncon geom_point_keys = [] # liste des clés des points troncons for tid, pts in lines.items(): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope( QgsExpressionContextUtils.layerScope(g_troncon)) exp_str = ('"id_geom_regard_amont" = {} AND ' '"id_geom_regard_aval" = {}').format(pts[0], pts[1]) 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 tro in g_troncon.getFeatures(request): l_t_g[tid] = tro['id'] continue if (pts[0], pts[1]) in geom_point_keys: l_pts_t[(pts[0], pts[1])].append(tid) continue else: l_pts_t[(pts[0], pts[1])] = [tid] geom_point_keys.append((pts[0], pts[1])) feat_t = QgsVectorLayerUtils.createFeature(g_troncon) feat_t.setAttribute( 'label', '{}-{}'.format(pt_labels[pts[0]], pt_labels[pts[1]])) feat_t.setAttribute('id_geom_regard_amont', pts[0]) feat_t.setAttribute('id_geom_regard_aval', pts[1]) feat_t.setGeometry( QgsGeometry.fromPolylineXY([points[pts[0]], points[pts[1]]])) features.append(feat_t) # Ajout des objets troncons if features: g_troncon.startEditing() (res, outFeats) = g_troncon.dataProvider().addFeatures(features) if not res or not outFeats: raise QgsProcessingException( tr('* ERREUR: lors de l\'enregistrement ' 'des regards {}').format(', '.join( g_troncon.dataProvider().errors()))) if not g_troncon.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format(g_troncon.commitErrors())) for tro in outFeats: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} if not tro['id']: continue key = (tro['id_geom_regard_amont'], tro['id_geom_regard_aval']) if key not in geom_point_keys: continue for tid in l_pts_t[(pts[0], pts[1])]: l_t_g[tid] = tro['id'] # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} for tid, pts in lines.items(): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} if tid in l_t_g: continue exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope( QgsExpressionContextUtils.layerScope(g_troncon)) exp_str = ('"id_geom_regard_amont" = {} AND ' '"id_geom_regard_aval" = {}').format(pts[0], pts[1]) 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 tro in g_troncon.getFeatures(request): l_t_g[tid] = tro['id'] # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} if not l_t_g.keys(): raise QgsProcessingException( tr('* ERREUR: Aucune géométrie de tronçon')) # Mise a jour de la table troncon exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_troncon)) exp_str = ('"id_geom_troncon" IS NULL AND ' 'id IN ({})').format(','.join( [str(i) for i in l_t_g.keys()])) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression %s has eval error: %s').format( exp.expression(), exp.evalErrorString())) # Mise a jour de la table de tronçon request = QgsFeatureRequest(exp, exp_context) t_troncon.startEditing() segment_number = 0 for tro in t_troncon.getFeatures(request): tro.setAttribute('id_geom_troncon', l_t_g[tro['id']]) t_troncon.updateFeature(tro) # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SEGMENT_CREATED: None} segment_number += 1 if not t_troncon.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit %s.') % t_troncon.commitErrors()) # Returns empty dict if no outputs return {self.SEGMENT_CREATED: segment_number}
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): path = self.parameterAsFile(parameters, self.INPUT, context) t_file = self.parameterAsVectorLayer( parameters, self.FILE_TABLE, context ) t_troncon = self.parameterAsVectorLayer( parameters, self.SEGMENT_TABLE, context ) t_obs = self.parameterAsVectorLayer( parameters, self.OBSERVATIONS_TABLE, context ) t_regard = self.parameterAsVectorLayer( parameters, self.MANHOLES_TABLE, context ) paths = path.split(';') if len(paths) != 1: raise QgsProcessingException( tr('* ERREUR: 1 fichier a la fois {}.').format(path) ) if not os.path.exists(path): raise QgsProcessingException( tr('* ERREUR: {} n\'existe pas.').format(path) ) # add date fields to itv file table # relation_aggregate( # 'itv_tronco_id_file_itv_file20_id', # 'max', # "abf" # ) if 'date_debut' not in t_file.dataProvider().fields().names(): with edit(t_file): res = t_file.dataProvider().addAttributes([ QgsField("date_debut", QVariant.String), QgsField("date_fin", QVariant.String) ]) if res: t_file.updateFields() feat_file = None with open(path, 'rb') as f: basename = os.path.basename(path) md = hashlib.md5() md.update(f.read()) hashcontent = md.hexdigest() feat_file = QgsVectorLayerUtils.createFeature(t_file) feat_file.setAttribute('basename', basename) feat_file.setAttribute('hashcontent', hashcontent) if not feat_file: raise QgsProcessingException( tr( '* ERREUR: le fichier {} n\'a pas été lu ' 'correctement.' ).format(path) ) exp_context = QgsExpressionContext() exp_context.appendScope( QgsExpressionContextUtils.globalScope() ) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project()) ) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_file) ) exp_str = QgsExpression.createFieldEqualityExpression( 'basename', feat_file['basename'] ) + ' AND ' + QgsExpression.createFieldEqualityExpression( 'hashcontent', feat_file['hashcontent'] ) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString() ) ) request = QgsFeatureRequest(exp, exp_context) request.setLimit(1) for _t in t_file.getFeatures(request): raise QgsProcessingException( tr('* ERREUR: le fichier {} a deja ete lu').format( path ) ) exp_str = QgsExpression.createFieldEqualityExpression( 'hashcontent', feat_file['hashcontent'] ) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( (exp.expression(), exp.evalErrorString()) ) ) request = QgsFeatureRequest(exp, exp_context) request.setLimit(1) for _t in t_file.getFeatures(request): raise QgsProcessingException( tr( '* ERREUR: le fichier {} semble deja avoir ete lu' ).format(path) ) exp_context = QgsExpressionContext() exp_context.appendScope( QgsExpressionContextUtils.globalScope() ) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project()) ) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_troncon) ) exp_str = 'maximum("id")' exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr( '* ERROR: Expression {} has eval error: {}' ).format(exp.expression(), exp.evalErrorString()) ) last_t_id = exp.evaluate(exp_context) if not last_t_id: last_t_id = 0 exp_context = QgsExpressionContext() exp_context.appendScope( QgsExpressionContextUtils.globalScope() ) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project()) ) exp_context.appendScope( QgsExpressionContextUtils.layerScope(t_regard) ) exp_str = 'maximum("id")' exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr( '* ERROR: Expression {} has eval error: {}' ).format(exp.expression(), exp.evalErrorString()) ) last_r_id = exp.evaluate(exp_context) if not last_r_id: last_r_id = 0 # lecture des entetes ENCODING = 'ISO-8859-1' LANG = 'fr' DELIMITER = ',' DECIMAL = '.' QUOTECHAR = '"' VERSION = '' with open(path, 'rb') as f: for line in f: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} try: line = line.decode() except UnicodeDecodeError: raise QgsProcessingException( 'Error while reading {}'.format(path) ) # remove break line line = line.replace('\n', '').replace('\r', '') if line.startswith('#'): if line.startswith('#A'): if line.startswith('#A1'): ENCODING = line[4:] if ENCODING.find(':') != -1: ENCODING = ENCODING[:ENCODING.find(':')] elif line.startswith('#A2'): LANG = line[4:] elif line.startswith('#A3'): DELIMITER = line[4:] elif line.startswith('#A4'): DECIMAL = line[4:] elif line.startswith('#A5'): QUOTECHAR = line[4:] else: break # Dialect CSV pour la lecture des tableaux de valeurs du # fichier d'ITV class itvDialect(csv.Dialect): strict = True skipinitialspace = True quoting = csv.QUOTE_MINIMAL delimiter = DELIMITER quotechar = QUOTECHAR lineterminator = '\r\n' # Liste des troncons, observations et regards troncons = [] regards = [] observations = [] # Lectures des donnees with open(path, 'rb') as f: # Identifiant de départ t_id = last_t_id r_id = last_r_id # Entête header = [] # Nom du tableau array = '' # Observations de troncons ? obs_for_troncon = False # initialisation du Dialect CSV pour ITV dia = itvDialect() # Lecture ligne à ligne du fichier for line in f: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} # Decoding line en utilisant l'encoding du fichier line = line.decode(ENCODING) # remove break line line = line.replace('\n', '').replace('\r', '') # Ligne commençant par un # est une ligne d'entête if line.startswith('#'): # Entête de troncon ou regard if line.startswith('#B'): l_b = io.StringIO(line[5:]) for l_r in csv.reader(l_b, dia): header = l_r break array = line[1:4] continue # Entête d'observation elif line.startswith('#C'): if header[0].startswith('A'): obs_for_troncon = True else: obs_for_troncon = False l_b = io.StringIO(line[3:]) for l_r in csv.reader(l_b, dia): header = l_r break array = line[1:2] continue # Fin d'observation elif line.startswith('#Z'): header = [] array = '' obs_for_troncon = False continue # La ligne contient des donnees else: if not header: # an error in the file structure continue l_b = io.StringIO(line) for l_r in csv.reader(l_b, dia): data = l_r row = list( zip( [h.lower() for h in header], [t for t in data] ) ) # observation if array == 'C': if obs_for_troncon: observations.append( row + [('id_troncon', t_id)] ) # Premiere ligne de description d'un troncon ou regard elif array == 'B01': if header[0].startswith('A'): t_id += 1 troncons.append([('id', t_id)] + row) elif header[0].startswith('C'): r_id += 1 regards.append([('id', r_id)] + row) # Ligne complémentaire de description else: if header[0].startswith('A'): troncons[-1] += row elif header[0].startswith('C'): regards[-1] += row # Recuperation des references de noeuds et dates itv_dates = [] regard_node_refs = [] regard_ref_id = {} max_r_id = last_r_id for reg in regards: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} d_rg = dict(reg) if d_rg['caa'] and d_rg['caa'] not in regard_node_refs: regard_node_refs.append(d_rg['caa']) regard_ref_id[d_rg['caa']] = d_rg['id'] if d_rg['id'] and d_rg['id'] > max_r_id: max_r_id = d_rg['id'] if 'cbf' in d_rg and d_rg['cbf'] not in itv_dates: itv_dates.append(d_rg['cbf']) node_refs = [] for tro in troncons: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} d_tr = dict(tro) # The nodes ref are stored in AAB, AAD, AAF and AAT if 'aab' in d_tr and \ d_tr['aab'] and \ d_tr['aab'] not in regard_node_refs and \ d_tr['aab'] not in node_refs: node_refs.append(d_tr['aab']) if 'aad' in d_tr and \ d_tr['aad'] and \ d_tr['aad'] not in regard_node_refs and \ d_tr['aad'] not in node_refs: node_refs.append(d_tr['aad']) if 'aaf' in d_tr and \ d_tr['aaf'] and \ d_tr['aaf'] not in regard_node_refs and \ d_tr['aaf'] not in node_refs: node_refs.append(d_tr['aaf']) if 'aat' in d_tr and \ d_tr['aat'] and \ d_tr['aat'] not in regard_node_refs and \ d_tr['aat'] not in node_refs: node_refs.append(d_tr['aat']) if 'abf' in d_tr and d_tr['abf'] not in itv_dates: itv_dates.append(d_tr['abf']) # Ajout des regards manquant for n_ref in node_refs: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} max_r_id += 1 regards.append([('id', max_r_id), ('caa', n_ref)]) regard_ref_id[n_ref] = max_r_id # Ajout des identifiants de regards aux tronçons regard_refs = regard_ref_id.keys() for tro in troncons: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} d_tr = dict(tro) # If AAD is not defined then it is equal to AAB if 'aad' not in d: d['aad'] = d['aab'] if d_tr['aad'] and \ d_tr['aad'] in regard_refs: tro += [('id_regard1', regard_ref_id[d_tr['aad']])] if d_tr['aaf'] and \ d_tr['aaf'] in regard_refs: tro += [('id_regard2', regard_ref_id[d_tr['aaf']])] if 'aat' in d_tr.keys() and \ d_tr['aat'] and \ d_tr['aat'] in regard_refs: tro += [('id_regard3', regard_ref_id[d_tr['aat']])] # Verification des champs fields = provider_fields(t_troncon.fields()) for tro in troncons: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} for key, val in tro: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} if fields.indexOf(key) == -1: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de tronçon "{}" est inconnue' ).format(key) ) field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: try: float(val.replace(DECIMAL, '.')) except BaseException: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de tronçon "{}" est ' 'numérique mais pas la valeur "{}"' ).format(key, val) ) fields = provider_fields(t_obs.fields()) for obs in observations: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} for key, val in obs: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} if fields.indexOf(key) == -1: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs d\'observation "{}" est ' 'inconnue' ).format(key) ) field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: try: float(val.replace(DECIMAL, '.')) except BaseException: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs d\'observation "{}" est ' 'numérique mais pas la valeur "{}"' ).format(key, val) ) fields = provider_fields(t_regard.fields()) for reg in regards: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} for key, val in reg: # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} if fields.indexOf(key) == -1: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de regard "{}" est inconnue' ).format(key) ) field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: try: float(val.replace(DECIMAL, '.')) except BaseException: raise QgsProcessingException( tr( '* ERREUR dans le fichier : ' 'le champs de regard "{}" est ' 'numérique mais pas la valeur "{}"' ).format(key, val) ) # Finalisation objet fichier feat_file.setAttribute('encoding', ENCODING) feat_file.setAttribute('lang', LANG) if VERSION: feat_file.setAttribute('version', VERSION) if itv_dates: feat_file.setAttribute('date_debut', min(itv_dates)) feat_file.setAttribute('date_fin', max(itv_dates)) # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.SUCCESS: 0} # Ajout de l'objet fichier t_file.startEditing() (res, outFeats) = t_file.dataProvider().addFeatures([feat_file]) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement du fichier {}' ).format(', '.join(t_file.dataProvider().errors())) ) if not t_file.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format(t_file.commitErrors()) ) # Mise a jour de l'identifiant de l'objet fichier feat_file.setAttribute('id', outFeats[0]['id']) # Creation des objets troncons features = [] fields = provider_fields(t_troncon.fields()) for tro in troncons: feat_t = QgsVectorLayerUtils.createFeature(t_troncon) feat_t.setAttribute('id_file', feat_file['id']) for key, val in tro: field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: feat_t.setAttribute( key, float(val.replace(DECIMAL, '.')) ) else: feat_t.setAttribute(key, val) features.append(feat_t) # Ajout des objets troncons if features: t_troncon.startEditing() (res, outFeats) = t_troncon.dataProvider().addFeatures(features) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement ' 'des troncon {}' ).format( ', '.join(t_troncon.dataProvider().errors()) ) ) if not t_troncon.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format( t_troncon.commitErrors() ) ) # Creation des objets observations features = [] fields = provider_fields(t_obs.fields()) for obs in observations: feat_o = QgsVectorLayerUtils.createFeature(t_obs) feat_o.setAttribute('id_file', feat_file['id']) for key, val in obs: field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: feat_o.setAttribute( key, float(val.replace(DECIMAL, '.')) ) else: feat_o.setAttribute(key, val) features.append(feat_o) # Ajout des objets observations if features: t_obs.startEditing() (res, outFeats) = t_obs.dataProvider().addFeatures(features) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement ' 'des observations {}' ).format( ', '.join(t_obs.dataProvider().errors()) ) ) if not t_obs.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format( t_obs.commitErrors() ) ) # Creation des objets regards features = [] fields = provider_fields(t_regard.fields()) for reg in regards: feat_r = QgsVectorLayerUtils.createFeature(t_regard) feat_r.setAttribute('id_file', feat_file['id']) for key, val in reg: field = fields.field(key) if isinstance(val, str) and field.isNumeric(): if val: feat_r.setAttribute( key, float(val.replace(DECIMAL, '.')) ) else: feat_r.setAttribute(key, val) features.append(feat_r) # Ajout des objets regards if features: t_regard.startEditing() (res, outFeats) = t_regard.dataProvider().addFeatures( features ) if not res or not outFeats: raise QgsProcessingException( tr( '* ERREUR: lors de l\'enregistrement ' 'des regards {}' ).format( ', '.join(t_regard.dataProvider().errors()) ) ) if not t_regard.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit %s.').format( t_regard.commitErrors() ) ) # Returns empty dict if no outputs return {self.SUCCESS: 1}
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context) expression = self.parameterAsString(parameters, self.EXPRESSION, context) expr = QgsExpression(expression) if expr.hasParserError(): raise QgsProcessingException(expr.parserErrorString()) context = QgsExpressionContext() count = vectorLayer.featureCount() if vectorLayer.featureCount() else 0 total = 100.0 / count # And now we can process attributes = [] duplicates = [] index = 0 protokoll = [] #Iterating over Vector Layer feedback.pushInfo("Processing ") iter = vectorLayer.getFeatures() for current, feature in enumerate(iter): try: #create value from Expression context.setFeature(feature) value = expr.evaluate(context) except Exception as err: msg = "Error while run Expression" + str( expr.expression()) + " on feature " + str( feature.attributes()) + ": " + str( err.args) + ";" + str(repr(err)) feedback.reportError(msg) raise QgsProcessingException(msg) try: #is the attribut in the list yet index = attributes.index(value) feedback.pushInfo("Index " + str(value) + ": " + str(index)) #index=attributes.index(feature[fidx]) except ValueError as err: # value is not in the list index = -1 #feedback.reportError( str(repr(err)) ) # "ValueError: "+str( value ) + ": " + str(err.args) + ";" + except KeyError as err: # value is not in the list index = -1 #feedback.reportError( "KeyError: "+str(value) + ": " + str(err.args) + ";" + str(repr(err)) ) if index == -1: # add new attribute in the list attributes.append(value) else: # it is a duplicate duplicates.append(feature.id()) # Update the progress bar proz = int((current + 1) * total) feedback.setProgress(proz) feedback.pushInfo(str(len(duplicates)) + " duplicates were selected!") if len(duplicates) > 0: vectorLayer.select(duplicates) return {self.OUTPUT: parameters[self.INPUT]}
def processAlgorithm(self, parameters, context, feedback): t_troncon = self.parameterAsSource(parameters, self.SEGMENTS_TABLE, context) g_troncon = self.parameterAsSource(parameters, self.GEOM_SEGMENTS, context) t_obs = self.parameterAsSource(parameters, self.OBSERVATION_TABLE, context) g_obs = self.parameterAsVectorLayer(parameters, self.GEOM_OBSERVATION, context) # Get troncon ids and file ids exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(t_troncon.createExpressionContextScope()) exp_str = '"id_geom_troncon" IS NOT NULL' exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression %s has eval error: %s').format( exp.expression(), exp.evalErrorString())) request = QgsFeatureRequest(exp, exp_context) request.setSubsetOfAttributes( ['id', 'aab', 'aad', 'aaf', 'abq', 'id_file', 'id_geom_troncon'], t_troncon.fields()) has_geo_troncon = False troncons = {} file_ids = [] for tro in t_troncon.getFeatures(request): troncons[tro['id']] = tro file_ids.append(tro['id_file']) has_geo_troncon = True # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} if not has_geo_troncon: raise QgsProcessingException(tr('* ERROR: No troncon geometries')) # Get observation ids exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(t_obs.createExpressionContextScope()) exp_str = ('"id_troncon" IN ({}) AND ' '"id_file" IN ({})').format( ','.join([str(i) for i in troncons.keys()]), ','.join([str(i) for i in file_ids])) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString())) obs_ids = [] request = QgsFeatureRequest(exp, exp_context) for obs in t_obs.getFeatures(request): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} troncon = troncons[obs['id_troncon']] # verifying ITV file if troncon['id_file'] != obs['id_file']: continue obs_ids.append(obs['id']) if not obs_ids: raise QgsProcessingException( tr('* ERROR: No observations to geolocalize found')) # Check observations already geolocalised on troncon exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(QgsExpressionContextUtils.layerScope(g_obs)) exp_str = '"id" IN ({})'.format(','.join([str(i) for i in obs_ids])) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString())) request = QgsFeatureRequest(exp, exp_context) geo_observations = [] for obs in g_obs.getFeatures(request): geo_observations.append(obs['id']) # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} # build observation geometry based on table exp_context = QgsExpressionContext() exp_context.appendScope(QgsExpressionContextUtils.globalScope()) exp_context.appendScope( QgsExpressionContextUtils.projectScope(context.project())) exp_context.appendScope(t_obs.createExpressionContextScope()) exp_str = ('"id_troncon" IN ({}) AND ' '"id_file" IN ({})').format( ','.join([str(i) for i in troncons.keys()]), ','.join([str(i) for i in file_ids])) if geo_observations: exp_str += ' AND id NOT IN ({})'.format(','.join( [str(i) for i in geo_observations])) exp = QgsExpression(exp_str) exp.prepare(exp_context) if exp.hasEvalError(): raise QgsProcessingException( tr('* ERROR: Expression {} has eval error: {}').format( exp.expression(), exp.evalErrorString())) request = QgsFeatureRequest(exp, exp_context) features = [] fields = provider_fields(g_obs.fields()) for obs in t_obs.getFeatures(request): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} troncon = troncons[obs['id_troncon']] # verifying ITV file if troncon['id_file'] != obs['id_file']: continue geo_req = QgsFeatureRequest() geo_req.setFilterFid(troncon['id_geom_troncon']) for g_tro in g_troncon.getFeatures(geo_req): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): return {self.OBSERVATIONS_CREATED: None} geom = g_tro.geometry() pt = None if troncon['aab'] == troncon['aad']: pt = geom.interpolate(geom.length() * obs['i'] / troncon['abq']) else: pt = geom.interpolate(geom.length() * (1 - obs['i'] / troncon['abq'])) fet = QgsFeature(fields) fet.setGeometry(pt) fet.setAttribute('id', obs['id']) features.append(fet) # Ajout des objets observations if features: g_obs.startEditing() (res, outFeats) = g_obs.dataProvider().addFeatures(features) if not res or not outFeats: raise QgsProcessingException( tr('* ERREUR: lors de l\'enregistrement ' 'des regards {}').format(', '.join( g_obs.dataProvider().errors()))) if not g_obs.commitChanges(): raise QgsProcessingException( tr('* ERROR: Commit {}.').format(g_obs.commitErrors())) # Returns empty dict if no outputs return {self.OBSERVATIONS_CREATED: len(features)}