def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.PrmInputLayer, context) preserve_final_pt = self.parameterAsBool(parameters, self.PrmPreserveFinalPoint, context) min_distance = self.parameterAsDouble(parameters, self.PrmMinDistance, context) units = self.parameterAsInt(parameters, self.PrmUnitsOfMeasure, context) # Get the minimum distance in meters min_distance = min_distance * conversionToMeters(units) wkbtype = source.wkbType() num_bad = 0 if QgsWkbTypes.geometryType(wkbtype) != QgsWkbTypes.LineGeometry: feedback.reportError(tr("Please select a valid line layer.")) return({}) layercrs = source.sourceCrs() (sink, dest_id) = self.parameterAsSink( parameters, self.PrmOutputLayer, context, source.fields(), wkbtype, layercrs) if layercrs != epsg4326: transto4326 = QgsCoordinateTransform(layercrs, epsg4326, QgsProject.instance()) transfrom4326 = QgsCoordinateTransform(epsg4326, layercrs, QgsProject.instance()) total = 100.0 / source.featureCount() if source.featureCount() else 0 iterator = source.getFeatures() num_bad = 0 for cnt, feature in enumerate(iterator): if feedback.isCanceled(): break geom = feature.geometry() # Force the geometry to be in degrees so that we can use the geodesic algorithms if layercrs != epsg4326: results = geom.transform(transto4326) num_parts = geom.constGet().partCount() # feedback.pushInfo('num_parts {}'.format(num_parts)) try: fline = QgsFeature() fgeom = QgsGeometry() is_valid = False for part in geom.constGet().parts(): vertex_cnt = part.vertexCount() # feedback.pushInfo('vertex_cnt {}'.format(vertex_cnt)) if vertex_cnt <= 1: # line of 1 or less points is invalid continue pts = [] for vcnt, vertex in enumerate(part.vertices()): if vcnt == 0: # This is the first point so we will save it pts.append(vertex) ptLast = vertex else: ptNext = vertex gline = geod.InverseLine(ptLast.y(), ptLast.x(), ptNext.y(), ptNext.x()) if gline.s13 >= min_distance: pts.append(ptNext) ptLast = ptNext elif (vcnt == vertex_cnt - 1) and preserve_final_pt: if len(pts) >= 2: # We have two or more points already on our pts list. Check to see if # the next to last entry distance and the end point are greater than the # the minimum distance. If so replace the last entry with this one else # because the user has selected to preserve the last end point we will # accept the end point. gline = geod.InverseLine(pts[-2].y(), pts[-2].x(), ptNext.y(), ptNext.x()) if gline.s13 >= min_distance: pts[-1] = ptNext else: pts.append(ptNext) elif len(pts) == 1: # We have only the beginning point of the line and because the user has # selected that the last point to be preserved we will allow a distance less # than the minimum so that the line can be preserved. pts.append(ptNext) if len(pts) > 1: # There must be more than one point to make a valid line fgeom.addPoints(pts, QgsWkbTypes.LineGeometry) is_valid = True if is_valid: # Only save the feature if it is valid fline.setAttributes(feature.attributes()) if layercrs != epsg4326: fgeom.transform(transfrom4326) fline.setGeometry(fgeom) sink.addFeature(fline) else: num_bad += 1 except Exception: '''s = traceback.format_exc() feedback.pushInfo(s)''' num_bad += 1 feedback.setProgress(int(cnt * total)) if num_bad > 0: feedback.pushInfo(tr("{} out of {} features from input layer were invalid and were skipped.".format(num_bad, source.featureCount()))) return {self.PrmOutputLayer: dest_id}