def validateQgsExpressions(self, qgsExpression): exp = QgsExpression(qgsExpression) if exp.isValid(): if exp.isField(): return False return True return False
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) close_path = self.parameterAsBool(parameters, self.CLOSE_PATH, context) group_field_name = self.parameterAsString(parameters, self.GROUP_FIELD, context) order_field_name = self.parameterAsString(parameters, self.ORDER_FIELD, context) order_expression = self.parameterAsString(parameters, self.ORDER_EXPRESSION, context) date_format = self.parameterAsString(parameters, self.DATE_FORMAT, context) text_dir = self.parameterAsString(parameters, self.OUTPUT_TEXT_DIR, context) group_field_index = source.fields().lookupField(group_field_name) if group_field_index >= 0: group_field_def = source.fields().at(group_field_index) else: group_field_def = None if order_field_name: order_expression = QgsExpression.quotedColumnRef(order_field_name) if not order_expression: raise QgsProcessingException( self.tr('ORDER_EXPRESSION parameter is missing.')) expression_context = self.createExpressionContext( parameters, context, source) expression = QgsExpression(order_expression) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) expression.prepare(expression_context) order_field_type = QVariant.String if expression.isField(): field_name = next(iter(expression.referencedColumns())) order_field_type = source.fields().field(field_name).type() fields = QgsFields() if group_field_def is not None: fields.append(group_field_def) begin_field = QgsField('begin', order_field_type) fields.append(begin_field) end_field = QgsField('end', order_field_type) fields.append(end_field) output_wkb = QgsWkbTypes.LineString if QgsWkbTypes.hasM(source.wkbType()): output_wkb = QgsWkbTypes.addM(output_wkb) if QgsWkbTypes.hasZ(source.wkbType()): output_wkb = QgsWkbTypes.addZ(output_wkb) (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, output_wkb, source.sourceCrs()) if sink is None: raise QgsProcessingException( self.invalidSinkError(parameters, self.OUTPUT)) if text_dir and not (os.path.exists(text_dir)): raise QgsProcessingException( self.tr("The text output directory does not exist")) points = dict() required_fields = expression.referencedColumns() required_fields.add(group_field_name) features = source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes(required_fields, source.fields()), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks) total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, f in enumerate(features): if feedback.isCanceled(): break if not f.hasGeometry(): continue point = f.geometry().constGet().clone() if group_field_index >= 0: group = f[group_field_index] else: group = 1 expression_context.setFeature(f) order = expression.evaluate(expression_context) if date_format != '': order = datetime.strptime(str(order), date_format) if group in points: points[group].append((order, point)) else: points[group] = [(order, point)] feedback.setProgress(int(current * total)) feedback.setProgress(0) da = QgsDistanceArea() da.setSourceCrs(source.sourceCrs(), context.transformContext()) da.setEllipsoid(context.ellipsoid()) current = 0 total = 100.0 / len(points) if points else 1 for group, vertices in points.items(): if feedback.isCanceled(): break vertices.sort(key=lambda x: (x[0] is None, x[0])) f = QgsFeature() attributes = [] if group_field_index >= 0: attributes.append(group) attributes.extend([vertices[0][0], vertices[-1][0]]) f.setAttributes(attributes) line = [node[1] for node in vertices] if close_path is True: if line[0] != line[-1]: line.append(line[0]) if text_dir: fileName = os.path.join(text_dir, '%s.txt' % group) with open(fileName, 'w') as fl: fl.write('angle=Azimuth\n') fl.write('heading=Coordinate_System\n') fl.write('dist_units=Default\n') for i in range(len(line)): if i == 0: fl.write('startAt=%f;%f;90\n' % (line[i].x(), line[i].y())) fl.write('survey=Polygonal\n') fl.write('[data]\n') else: angle = line[i - 1].azimuth(line[i]) distance = da.measureLine(QgsPointXY(line[i - 1]), QgsPointXY(line[i])) fl.write('%f;%f;90\n' % (angle, distance)) f.setGeometry(QgsGeometry(QgsLineString(line))) sink.addFeature(f, QgsFeatureSink.FastInsert) current += 1 feedback.setProgress(int(current * total)) return {self.OUTPUT: dest_id}