QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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(
68 "This algorithm extracts the end points (nodes) from a network line layer.\n\n"
69 "Two definitions are available for identifying end points:\n\n"
70 "1. Nodes with only all incoming or all outgoing edges: Identifies 'Source' or 'Sink' nodes "
71 "based on the direction of flow. These are nodes where flow can start (only outgoing) or stop "
72 "(only incoming).\n"
73 "2. Nodes connected to a single edge: Identifies topological 'dead-ends' or 'dangles', regardless "
74 "of directionality. This checks if the node is connected to only one other distinct node."
75 );
76}
77
78QgsExtractNetworkEndpointsAlgorithm *QgsExtractNetworkEndpointsAlgorithm::createInstance() const
79{
80 return new QgsExtractNetworkEndpointsAlgorithm();
81}
82
83Qgis::ProcessingAlgorithmDocumentationFlags QgsExtractNetworkEndpointsAlgorithm::documentationFlags() const
84{
85 // override QgsNetworkAnalysisAlgorithmBase flag for ellipsoid use -- we don't use distances
86 // here
88}
89
90void QgsExtractNetworkEndpointsAlgorithm::initAlgorithm( const QVariantMap & )
91{
92 addCommonParams();
93
94 // remove unused common parameters
95 removeParameter( u"STRATEGY"_s );
96 removeParameter( u"SPEED_FIELD"_s );
97 removeParameter( u"DEFAULT_SPEED"_s );
98
99 QStringList definitions;
100 definitions << QObject::tr( "Extract Nodes with only All Incoming or All Outgoing Edges" ) << QObject::tr( "Extract Nodes Connected to a Single Edge" );
101
102 auto strategyParam = std::make_unique<QgsProcessingParameterEnum>( u"ENDPOINT_DEFINITION"_s, QObject::tr( "End point definition" ), definitions, false, 1 );
103 addParameter( strategyParam.release() );
104
105 auto outputPoints = std::make_unique<QgsProcessingParameterFeatureSink>( u"OUTPUT"_s, QObject::tr( "Network endpoints" ), Qgis::ProcessingSourceType::VectorPoint );
106 addParameter( outputPoints.release() );
107}
108
109QVariantMap QgsExtractNetworkEndpointsAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
110{
111 QgsProcessingMultiStepFeedback multiFeedback( 2, feedback );
112 multiFeedback.setStepWeights( { 80, 20 } );
113 multiFeedback.setCurrentStep( 0 );
114
115 loadCommonParams( parameters, context, &multiFeedback );
116
117 const int definition = parameterAsEnum( parameters, u"ENDPOINT_DEFINITION"_s, context );
118
119 QgsFields outFields;
120 outFields.append( QgsField( u"node_id"_s, QMetaType::Type::Int ) );
121
122 QString dest;
123 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, outFields, Qgis::WkbType::Point, mNetwork->sourceCrs() ) );
124 if ( !sink )
125 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
126
127 multiFeedback.pushInfo( QObject::tr( "Building graph…" ) );
128 QVector<QgsPointXY> snappedPoints;
129 mDirector->makeGraph( mBuilder.get(), {}, snappedPoints, &multiFeedback );
130 if ( multiFeedback.isCanceled() )
131 return {};
132
133 multiFeedback.setCurrentStep( 1 );
134 multiFeedback.pushInfo( QObject::tr( "Calculating endpoints…" ) );
135 std::unique_ptr<QgsGraph> graph( mBuilder->takeGraph() );
136
137 const int vertexCount = graph->vertexCount();
138 double step = vertexCount > 0 ? 20.0 / vertexCount : 1;
139 long endpointsFound = 0;
140
141 for ( int i = 0; i < vertexCount; ++i )
142 {
143 if ( multiFeedback.isCanceled() )
144 break;
145
146 const QgsGraphVertex &v = graph->vertex( i );
147 bool isEndPoint = false;
148
149 if ( definition == 0 )
150 {
151 // definition = only all incoming or only all outgoing edges
152 const bool hasIncoming = !v.incomingEdges().empty();
153 const int hasOutgoing = !v.outgoingEdges().empty();
154 if ( ( hasIncoming && !hasOutgoing ) || ( hasOutgoing && !hasIncoming ) )
155 {
156 isEndPoint = true;
157 }
158 }
159 else
160 {
161 // definition = single connected edge
162 // count unique neighbors to handle bidirectional segments (A->B and B->A) counting as one connection
163 QSet<int> adjacentNodeIndices;
164 for ( int edgeId : v.outgoingEdges() )
165 {
166 adjacentNodeIndices.insert( graph->edge( edgeId ).toVertex() );
167 }
168 for ( int edgeId : v.incomingEdges() )
169 {
170 adjacentNodeIndices.insert( graph->edge( edgeId ).fromVertex() );
171 }
172 if ( adjacentNodeIndices.count() == 1 )
173 {
174 isEndPoint = true;
175 }
176 }
177
178 if ( isEndPoint )
179 {
180 QgsFeature f;
182 f.setAttributes( QgsAttributes() << i );
183 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
184 {
185 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
186 }
187 endpointsFound++;
188 }
189
190 multiFeedback.setProgress( i * step );
191 }
192 sink->finalize();
193
194 multiFeedback.pushInfo( QObject::tr( "Found %1 end points." ).arg( endpointsFound ) );
195 feedback->setProgress( 100 );
196
197 QVariantMap outputs;
198 outputs.insert( u"OUTPUT"_s, dest );
199 return outputs;
200}
201
@ VectorPoint
Vector point layers.
Definition qgis.h:3648
QFlags< ProcessingAlgorithmDocumentationFlag > ProcessingAlgorithmDocumentationFlags
Flags describing algorithm behavior for documentation purposes.
Definition qgis.h:3745
@ Point
Point.
Definition qgis.h:296
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:65
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:75
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:199
QgsGraphEdgeIds incomingEdges() const
Returns the incoming edge ids, i.e.
Definition qgsgraph.cpp:194
QgsPointXY point() const
Returns point associated with graph vertex.
Definition qgsgraph.cpp:204
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.