QGIS API Documentation 3.99.0-Master (357b655ed83)
Loading...
Searching...
No Matches
qgsalgorithmnetworkextractendpoints.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmnetworkextractendpoints.cpp
3 -------------------------------
4 begin : January 2026
5 copyright : (C) 2026 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgis.h"
21#include "qgsapplication.h"
22#include "qgsgraph.h"
23#include "qgsgraphbuilder.h"
24#include "qgslinestring.h"
28
29#include <QString>
30
31using namespace Qt::StringLiterals;
32
34
35QString QgsExtractNetworkEndpointsAlgorithm::name() const
36{
37 return u"extractnetworkendpoints"_s;
38}
39
40QString QgsExtractNetworkEndpointsAlgorithm::displayName() const
41{
42 return QObject::tr( "Extract network end points" );
43}
44
45QStringList QgsExtractNetworkEndpointsAlgorithm::tags() const
46{
47 return QObject::tr( "network,dead,end,node,degree,terminal,dangle" ).split( ',' );
48}
49
50QIcon QgsExtractNetworkEndpointsAlgorithm::icon() const
51{
52 return QgsApplication::getThemeIcon( u"/algorithms/mAlgorithmNetworkAnalysis.svg"_s );
53}
54
55QString QgsExtractNetworkEndpointsAlgorithm::svgIconPath() const
56{
57 return QgsApplication::iconPath( u"/algorithms/mAlgorithmNetworkAnalysis.svg"_s );
58}
59
60QString QgsExtractNetworkEndpointsAlgorithm::shortDescription() const
61{
62 return QObject::tr( "Extracts the end points (nodes) from a network line layer." );
63}
64
65QString QgsExtractNetworkEndpointsAlgorithm::shortHelpString() const
66{
67 return QObject::tr( "This algorithm extracts the end points (nodes) from a network line layer.\n\n"
68 "Two definitions are available for identifying end points:\n\n"
69 "1. Nodes with only all incoming or all outgoing edges: Identifies 'Source' or 'Sink' nodes "
70 "based on the direction of flow. These are nodes where flow can start (only outgoing) or stop "
71 "(only incoming).\n"
72 "2. Nodes connected to a single edge: Identifies topological 'dead-ends' or 'dangles', regardless "
73 "of directionality. This checks if the node is connected to only one other distinct node." );
74}
75
76QgsExtractNetworkEndpointsAlgorithm *QgsExtractNetworkEndpointsAlgorithm::createInstance() const
77{
78 return new QgsExtractNetworkEndpointsAlgorithm();
79}
80
81Qgis::ProcessingAlgorithmDocumentationFlags QgsExtractNetworkEndpointsAlgorithm::documentationFlags() const
82{
83 // override QgsNetworkAnalysisAlgorithmBase flag for ellipsoid use -- we don't use distances
84 // here
86}
87
88void QgsExtractNetworkEndpointsAlgorithm::initAlgorithm( const QVariantMap & )
89{
90 addCommonParams();
91
92 // remove unused common parameters
93 removeParameter( u"STRATEGY"_s );
94 removeParameter( u"SPEED_FIELD"_s );
95 removeParameter( u"DEFAULT_SPEED"_s );
96
97 QStringList definitions;
98 definitions << QObject::tr( "Extract Nodes with only All Incoming or All Outgoing Edges" )
99 << QObject::tr( "Extract Nodes Connected to a Single Edge" );
100
101 auto strategyParam = std::make_unique<QgsProcessingParameterEnum>( u"ENDPOINT_DEFINITION"_s, QObject::tr( "End point definition" ), definitions, false, 1 );
102 addParameter( strategyParam.release() );
103
104 auto outputPoints = std::make_unique<QgsProcessingParameterFeatureSink>( u"OUTPUT"_s, QObject::tr( "Network endpoints" ), Qgis::ProcessingSourceType::VectorPoint );
105 addParameter( outputPoints.release() );
106}
107
108QVariantMap QgsExtractNetworkEndpointsAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
109{
110 QgsProcessingMultiStepFeedback multiFeedback( 2, feedback );
111 multiFeedback.setStepWeights( { 80, 20 } );
112 multiFeedback.setCurrentStep( 0 );
113
114 loadCommonParams( parameters, context, &multiFeedback );
115
116 const int definition = parameterAsEnum( parameters, u"ENDPOINT_DEFINITION"_s, context );
117
118 QgsFields outFields;
119 outFields.append( QgsField( u"node_id"_s, QMetaType::Type::Int ) );
120
121 QString dest;
122 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, outFields, Qgis::WkbType::Point, mNetwork->sourceCrs() ) );
123 if ( !sink )
124 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
125
126 multiFeedback.pushInfo( QObject::tr( "Building graph…" ) );
127 QVector<QgsPointXY> snappedPoints;
128 mDirector->makeGraph( mBuilder.get(), {}, snappedPoints, &multiFeedback );
129 if ( multiFeedback.isCanceled() )
130 return {};
131
132 multiFeedback.setCurrentStep( 1 );
133 multiFeedback.pushInfo( QObject::tr( "Calculating endpoints…" ) );
134 std::unique_ptr<QgsGraph> graph( mBuilder->takeGraph() );
135
136 const int vertexCount = graph->vertexCount();
137 double step = vertexCount > 0 ? 20.0 / vertexCount : 1;
138 long endpointsFound = 0;
139
140 for ( int i = 0; i < vertexCount; ++i )
141 {
142 if ( multiFeedback.isCanceled() )
143 break;
144
145 const QgsGraphVertex &v = graph->vertex( i );
146 bool isEndPoint = false;
147
148 if ( definition == 0 )
149 {
150 // definition = only all incoming or only all outgoing edges
151 const bool hasIncoming = !v.incomingEdges().empty();
152 const int hasOutgoing = !v.outgoingEdges().empty();
153 if ( ( hasIncoming && !hasOutgoing ) || ( hasOutgoing && !hasIncoming ) )
154 {
155 isEndPoint = true;
156 }
157 }
158 else
159 {
160 // definition = single connected edge
161 // count unique neighbors to handle bidirectional segments (A->B and B->A) counting as one connection
162 QSet<int> adjacentNodeIndices;
163 for ( int edgeId : v.outgoingEdges() )
164 {
165 adjacentNodeIndices.insert( graph->edge( edgeId ).toVertex() );
166 }
167 for ( int edgeId : v.incomingEdges() )
168 {
169 adjacentNodeIndices.insert( graph->edge( edgeId ).fromVertex() );
170 }
171 if ( adjacentNodeIndices.count() == 1 )
172 {
173 isEndPoint = true;
174 }
175 }
176
177 if ( isEndPoint )
178 {
179 QgsFeature f;
181 f.setAttributes( QgsAttributes() << i );
182 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
183 {
184 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
185 }
186 endpointsFound++;
187 }
188
189 multiFeedback.setProgress( i * step );
190 }
191 sink->finalize();
192
193 multiFeedback.pushInfo( QObject::tr( "Found %1 end points." ).arg( endpointsFound ) );
194 feedback->setProgress( 100 );
195
196 QVariantMap outputs;
197 outputs.insert( u"OUTPUT"_s, dest );
198 return outputs;
199}
200
@ VectorPoint
Vector point layers.
Definition qgis.h:3605
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3701
@ Point
Point.
Definition qgis.h:282
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
A vector of attributes.
@ 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...
Definition qgsfeature.h:60
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:63
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:76
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
Represents vertex in a graph.
Definition qgsgraph.h:89
QgsGraphEdgeIds outgoingEdges() const
Returns outgoing edge ids, i.e.
Definition qgsgraph.cpp:200
QgsGraphEdgeIds incomingEdges() const
Returns the incoming edge ids, i.e.
Definition qgsgraph.cpp:195
QgsPointXY point() const
Returns point associated with graph vertex.
Definition qgsgraph.cpp:205
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
Processing feedback object for multi-step operations.