28QString QgsPointsToPathsAlgorithm::name()
 const 
   30  return QStringLiteral( 
"pointstopath" );
 
   33QString QgsPointsToPathsAlgorithm::displayName()
 const 
   35  return QObject::tr( 
"Points to path" );
 
   38QString QgsPointsToPathsAlgorithm::shortHelpString()
 const 
   40  return QObject::tr( 
"This algorithm takes a point layer and connects its features to create a new line layer.\n\n" 
   41                      "An attribute or expression may be specified to define the order the points should be connected. " 
   42                      "If no order expression is specified, the feature ID is used.\n\n" 
   43                      "A natural sort can be used when sorting by a string attribute " 
   44                      "or expression (ie. place 'a9' before 'a10').\n\n" 
   45                      "An attribute or expression can be selected to group points having the same value into the same resulting line." );
 
   48QString QgsPointsToPathsAlgorithm::shortDescription()
 const 
   50  return QObject::tr( 
"Takes a point layer and connects its features to create a new line layer." );
 
   53QStringList QgsPointsToPathsAlgorithm::tags()
 const 
   55  return QObject::tr( 
"create,lines,points,connect,convert,join,path" ).split( 
',' );
 
   58QString QgsPointsToPathsAlgorithm::group()
 const 
   60  return QObject::tr( 
"Vector creation" );
 
   63QString QgsPointsToPathsAlgorithm::groupId()
 const 
   65  return QStringLiteral( 
"vectorcreation" );
 
   68void QgsPointsToPathsAlgorithm::initAlgorithm( 
const QVariantMap & )
 
   70  addParameter( std::make_unique<QgsProcessingParameterFeatureSource>( QStringLiteral( 
"INPUT" ), QObject::tr( 
"Input layer" ), QList<int>() << 
static_cast<int>( 
Qgis::ProcessingSourceType::VectorPoint ) ) );
 
   71  addParameter( std::make_unique<QgsProcessingParameterBoolean>( QStringLiteral( 
"CLOSE_PATH" ), QObject::tr( 
"Create closed paths" ), 
false ) );
 
   72  addParameter( std::make_unique<QgsProcessingParameterExpression>( QStringLiteral( 
"ORDER_EXPRESSION" ), QObject::tr( 
"Order expression" ), QVariant(), QStringLiteral( 
"INPUT" ), 
true ) );
 
   73  addParameter( std::make_unique<QgsProcessingParameterBoolean>( QStringLiteral( 
"NATURAL_SORT" ), QObject::tr( 
"Sort text containing numbers naturally" ), 
false ) );
 
   74  addParameter( std::make_unique<QgsProcessingParameterExpression>( QStringLiteral( 
"GROUP_EXPRESSION" ), QObject::tr( 
"Path group expression" ), QVariant(), QStringLiteral( 
"INPUT" ), 
true ) );
 
   77  addParameter( std::make_unique<QgsProcessingParameterFolderDestination>( QStringLiteral( 
"OUTPUT_TEXT_DIR" ), QObject::tr( 
"Directory for text output" ), QVariant(), 
true, 
false ) );
 
   78  addOutput( std::make_unique<QgsProcessingOutputNumber>( QStringLiteral( 
"NUM_PATHS" ), QObject::tr( 
"Number of paths" ) ) );
 
   84  addParameter( std::move( orderField ) );
 
   86  auto groupField = std::make_unique<QgsProcessingParameterField>( QStringLiteral( 
"GROUP_FIELD" ), QObject::tr( 
"Group field" ), QVariant(), QStringLiteral( 
"INPUT" ), 
Qgis::ProcessingFieldParameterDataType::Any, 
false, 
true );
 
   88  addParameter( std::move( groupField ) );
 
   90  auto dateFormat = std::make_unique<QgsProcessingParameterString>( QStringLiteral( 
"DATE_FORMAT" ), QObject::tr( 
"Date format (if order field is DateTime)" ), QVariant(), 
false, 
true );
 
   92  addParameter( std::move( dateFormat ) );
 
   95QgsPointsToPathsAlgorithm *QgsPointsToPathsAlgorithm::createInstance()
 const 
   97  return new QgsPointsToPathsAlgorithm();
 
  102  std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( 
"INPUT" ), context ) );
 
  106  const bool closePaths = parameterAsBool( parameters, QStringLiteral( 
"CLOSE_PATH" ), context );
 
  108  QString orderExpressionString = parameterAsString( parameters, QStringLiteral( 
"ORDER_EXPRESSION" ), context );
 
  109  const QString orderFieldString = parameterAsString( parameters, QStringLiteral( 
"ORDER_FIELD" ), context );
 
  110  if ( !orderFieldString.isEmpty() )
 
  115    QString dateFormat = parameterAsString( parameters, QStringLiteral( 
"DATE_FORMAT" ), context );
 
  116    if ( !dateFormat.isEmpty() )
 
  118      QVector<QPair<QString, QString>> codeMap;
 
  119      codeMap << QPair<QString, QString>( 
"%%", 
"%" )
 
  120              << QPair<QString, QString>( 
"%a", 
"ddd" )
 
  121              << QPair<QString, QString>( 
"%A", 
"dddd" )
 
  122              << QPair<QString, QString>( 
"%w", 
"" ) 
 
  123              << QPair<QString, QString>( 
"%d", 
"dd" )
 
  124              << QPair<QString, QString>( 
"%b", 
"MMM" )
 
  125              << QPair<QString, QString>( 
"%B", 
"MMMM" )
 
  126              << QPair<QString, QString>( 
"%m", 
"MM" )
 
  127              << QPair<QString, QString>( 
"%y", 
"yy" )
 
  128              << QPair<QString, QString>( 
"%Y", 
"yyyy" )
 
  129              << QPair<QString, QString>( 
"%H", 
"hh" )
 
  130              << QPair<QString, QString>( 
"%I", 
"hh" ) 
 
  131              << QPair<QString, QString>( 
"%p", 
"AP" )
 
  132              << QPair<QString, QString>( 
"%M", 
"mm" )
 
  133              << QPair<QString, QString>( 
"%S", 
"ss" )
 
  134              << QPair<QString, QString>( 
"%f", 
"zzz" ) 
 
  135              << QPair<QString, QString>( 
"%z", 
"" )    
 
  136              << QPair<QString, QString>( 
"%Z", 
"" )    
 
  137              << QPair<QString, QString>( 
"%j", 
"" )    
 
  138              << QPair<QString, QString>( 
"%U", 
"" )    
 
  139              << QPair<QString, QString>( 
"%W", 
"" )    
 
  140              << QPair<QString, QString>( 
"%c", 
"" )    
 
  141              << QPair<QString, QString>( 
"%x", 
"" )    
 
  142              << QPair<QString, QString>( 
"%X", 
"" )    
 
  143              << QPair<QString, QString>( 
"%G", 
"yyyy" )
 
  144              << QPair<QString, QString>( 
"%u", 
"" )  
 
  145              << QPair<QString, QString>( 
"%V", 
"" ); 
 
  146      for ( 
const auto &pair : codeMap )
 
  148        dateFormat.replace( pair.first, pair.second );
 
  150      orderExpressionString = QString( 
"to_datetime(%1, '%2')" ).arg( orderExpressionString ).arg( dateFormat );
 
  153  else if ( orderExpressionString.isEmpty() )
 
  156    orderExpressionString = QString( 
"$id" );
 
  158  QgsExpressionContext expressionContext = createExpressionContext( parameters, context, source.get() );
 
  163  QStringList requiredFields = QStringList( orderExpression.
referencedColumns().values() );
 
  164  orderExpression.
prepare( &expressionContext );
 
  166  QMetaType::Type orderFieldType = QMetaType::Type::QString;
 
  167  if ( orderExpression.
isField() )
 
  169    const int orderFieldIndex = source->fields().indexFromName( orderExpression.
referencedColumns().values().first() );
 
  170    orderFieldType = source->fields().field( orderFieldIndex ).type();
 
  174  QString groupExpressionString = parameterAsString( parameters, QStringLiteral( 
"GROUP_EXPRESSION" ), context );
 
  176  const QString groupFieldString = parameterAsString( parameters, QStringLiteral( 
"GROUP_FIELD" ), context );
 
  177  if ( !groupFieldString.isEmpty() )
 
  185  if ( !groupExpressionString.isEmpty() )
 
  188    const QgsField field = groupExpression.
isField() ? source->fields().field( requiredFields.last() ) : QStringLiteral( 
"group" );
 
  189    outputFields.
append( field );
 
  194  const bool naturalSort = parameterAsBool( parameters, QStringLiteral( 
"NATURAL_SORT" ), context );
 
  196  collator.setNumericMode( 
true );
 
  205  std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral( 
"OUTPUT" ), context, dest, outputFields, wkbType, source->sourceCrs() ) );
 
  209  const QString textDir = parameterAsString( parameters, QStringLiteral( 
"OUTPUT_TEXT_DIR" ), context );
 
  210  if ( !textDir.isEmpty() && !QDir().mkpath( textDir ) )
 
  220  QHash<QVariant, QVector<QPair<QVariant, QgsPoint>>> allPoints;
 
  225  const double totalPoints = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0;
 
  226  long currentPoint = 0;
 
  234    feedback->
setProgress( 0.5 * currentPoint * totalPoints );
 
  239      const QVariant orderValue = orderExpression.
evaluate( &expressionContext );
 
  240      const QVariant groupValue = groupExpressionString.isEmpty() ? QVariant() : groupExpression.evaluate( &expressionContext );
 
  242      if ( !allPoints.contains( groupValue ) )
 
  243        allPoints[groupValue] = QVector<QPair<QVariant, QgsPoint>>();
 
  247        const QgsMultiPoint mp( *qgsgeometry_cast<const QgsMultiPoint *>( geom ) );
 
  248        for ( 
auto pit = mp.const_parts_begin(); pit != mp.const_parts_end(); ++pit )
 
  250          if ( 
const QgsPoint *point = qgsgeometry_cast<const QgsPoint *>( *pit ) )
 
  252            allPoints[groupValue] << qMakePair( orderValue, *point );
 
  258        if ( 
const QgsPoint *point = qgsgeometry_cast<const QgsPoint *>( geom ) )
 
  260          allPoints[groupValue] << qMakePair( orderValue, *point );
 
  269  QHashIterator<QVariant, QVector<QPair<QVariant, QgsPoint>>> hit( allPoints );
 
  271  while ( hit.hasNext() )
 
  278    QVector<QPair<QVariant, QgsPoint>> pairs = hit.value();
 
  282      std::stable_sort( pairs.begin(), pairs.end(), [&collator]( 
const QPair<const QVariant, QgsPoint> &pair1, 
const QPair<const QVariant, QgsPoint> &pair2 ) {
 
  283        return collator.compare( pair1.first.toString(), pair2.first.toString() ) < 0;
 
  288      std::stable_sort( pairs.begin(), pairs.end(), []( 
const QPair<const QVariant, QgsPoint> &pair1, 
const QPair<const QVariant, QgsPoint> &pair2 ) {
 
  289        return qgsVariantLessThan( pair1.first, pair2.first );
 
  294    QVector<QgsPoint> pathPoints;
 
  295    for ( 
auto pit = pairs.constBegin(); pit != pairs.constEnd(); ++pit )
 
  301      feedback->
setProgress( 50 + 0.5 * currentPoint * totalPoints );
 
  302      pathPoints.append( pit->second );
 
  305    if ( pathPoints.size() < 2 )
 
  307      feedback->
pushInfo( QObject::tr( 
"Skipping path with group %1 : insufficient vertices" ).arg( hit.key().toString() ) );
 
  310    if ( closePaths && pathPoints.size() > 2 && pathPoints.constFirst() != pathPoints.constLast() )
 
  311      pathPoints.append( pathPoints.constFirst() );
 
  315    if ( !groupExpressionString.isEmpty() )
 
  316      attrs.append( hit.key() );
 
  317    attrs.append( pairs.first().first );
 
  318    attrs.append( pairs.last().first );
 
  324    if ( !textDir.isEmpty() )
 
  326      const QString filename = QDir( textDir ).filePath( hit.key().toString() + QString( 
".txt" ) );
 
  327      QFile textFile( filename );
 
  328      if ( !textFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
 
  331      QTextStream out( &textFile );
 
  332#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) 
  333      out.setCodec( 
"UTF-8" );
 
  335      out << QString( 
"angle=Azimuth\n" 
  336                      "heading=Coordinate_System\n" 
  337                      "dist_units=Default\n" 
  341               .arg( pathPoints.at( 0 ).x() )
 
  342               .arg( pathPoints.at( 0 ).y() );
 
  344      for ( 
int i = 1; i < pathPoints.size(); ++i )
 
  346        const double angle = pathPoints.at( i - 1 ).azimuth( pathPoints.at( i ) );
 
  350          distance = da.
measureLine( pathPoints.at( i - 1 ), pathPoints.at( i ) );
 
  356        out << QString( 
"%1;%2;90\n" ).arg( angle ).arg( distance );
 
  366  outputs.insert( QStringLiteral( 
"OUTPUT" ), dest );
 
  367  outputs.insert( QStringLiteral( 
"NUM_PATHS" ), pathCount );
 
  368  if ( !textDir.isEmpty() )
 
  370    outputs.insert( QStringLiteral( 
"OUTPUT_TEXT_DIR" ), textDir );
 
@ VectorPoint
Vector point layers.
 
@ VectorLine
Vector line layers.
 
@ SkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
 
WkbType
The WKB type describes the number of dimensions a geometry has.
 
@ Hidden
Parameter is hidden and should not be shown to users.
 
Abstract base class for all geometries.
 
Custom exception class for Coordinate Reference System related exceptions.
 
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
 
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
 
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
 
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
 
Handles parsing and evaluation of expressions (formerly called "search strings").
 
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
 
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
 
QString parserErrorString() const
Returns parser error.
 
bool isField() const
Checks whether an expression consists only of a single field reference.
 
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
 
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
 
QVariant evaluate()
Evaluate the feature and return the result.
 
Wrapper for iterator of features from vector data provider or vector layer.
 
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
 
Wraps a request for features to a vector layer (or directly its vector data provider).
 
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
 
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
 
bool hasGeometry() const
Returns true if the feature has an associated geometry.
 
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
void setProgress(double progress)
Sets the current progress for the feedback object.
 
Encapsulate a field in an attribute table or data source.
 
Container of fields for a vector layer.
 
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
 
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
 
static QgsGeometry fromPolyline(const QgsPolyline &polyline)
Creates a new LineString geometry from a list of QgsPoint points.
 
Multi point geometry collection.
 
Point geometry type, with support for z-dimension and m-values.
 
Contains information about the context in which a processing algorithm is executed.
 
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
 
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
 
Custom exception class for processing related exceptions.
 
Base class for providing feedback from a processing algorithm.
 
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
 
virtual void setProgressText(const QString &text)
Sets a progress report text string.
 
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
 
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
 
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
 
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
 
static Q_INVOKABLE bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
 
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)