QGIS API Documentation 3.99.0-Master (357b655ed83)
Loading...
Searching...
No Matches
qgsalgorithmvalidatenetwork.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmvalidatenetwork.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 QgsValidateNetworkAlgorithm::name() const
36{
37 return u"validatenetwork"_s;
38}
39
40QString QgsValidateNetworkAlgorithm::displayName() const
41{
42 return QObject::tr( "Validate network" );
43}
44
45QStringList QgsValidateNetworkAlgorithm::tags() const
46{
47 return QObject::tr( "topological,topology,check,graph,shortest,path" ).split( ',' );
48}
49
50QString QgsValidateNetworkAlgorithm::group() const
51{
52 return QObject::tr( "Network analysis" );
53}
54
55QString QgsValidateNetworkAlgorithm::groupId() const
56{
57 return u"networkanalysis"_s;
58}
59
60QIcon QgsValidateNetworkAlgorithm::icon() const
61{
62 return QgsApplication::getThemeIcon( u"/algorithms/mAlgorithmNetworkAnalysis.svg"_s );
63}
64
65QString QgsValidateNetworkAlgorithm::svgIconPath() const
66{
67 return QgsApplication::iconPath( u"/algorithms/mAlgorithmNetworkAnalysis.svg"_s );
68}
69
70QString QgsValidateNetworkAlgorithm::shortDescription() const
71{
72 return QObject::tr( "Validates a network line layer, identifying data and topology errors that may affect network analysis tools." );
73}
74
75QString QgsValidateNetworkAlgorithm::shortHelpString() const
76{
77 return QObject::tr( "This algorithm analyzes a network vector layer to identify data and topology errors "
78 "that may affect network analysis tools (like shortest path).\n\n"
79 "Optional checks include:\n\n"
80 "1. Validating the 'Direction' field to ensure all direction field values in the input layer "
81 "match the configured forward/backward/both values. Errors will be reported if the direction field "
82 "value is non-null and does not match one of the configured values.\n"
83 "2. Checking node-to-node separation. This check identifies nodes from the network graph that "
84 "are closer to other nodes than the specified tolerance distance. This often indicates missed "
85 "snaps or short segments in the input layer. In the case that a node violates this condition with multiple other "
86 "nodes, only the closest violation will be reported.\n"
87 "3. Checking node-to-segment separation: This check identifies nodes that are closer to a line "
88 "segment (e.g. a graph edge) than the specified tolerance distance, without being connected to it. In the case "
89 "that a node violates this condition with multiple other edges, only the closest violation will be reported.\n\n"
90 "Two layers are output by this algorithm:\n"
91 "1. An output containing features from the original network layer which failed the direction validation checks.\n"
92 "2. An output representing the problematic node locations with a 'error' field explaining the error. This is "
93 "a line layer, where the output features join the problematic node to the node or "
94 "segment which failed the tolerance checks." );
95}
96
97QgsValidateNetworkAlgorithm *QgsValidateNetworkAlgorithm::createInstance() const
98{
99 return new QgsValidateNetworkAlgorithm();
100}
101
102void QgsValidateNetworkAlgorithm::initAlgorithm( const QVariantMap & )
103{
104 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Vector layer representing network" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) ) );
105
106 auto separationNodeNodeParam = std::make_unique<QgsProcessingParameterDistance>( u"TOLERANCE_NODE_NODE"_s, QObject::tr( "Minimum separation between nodes" ), QVariant(), u"INPUT"_s, true );
107 separationNodeNodeParam->setFlags( separationNodeNodeParam->flags() | Qgis::ProcessingParameterFlag::Optional );
108 separationNodeNodeParam->setHelp( QObject::tr( "The minimum allowed distance between two distinct graph nodes.\n\n"
109 "Nodes closer than this distance (but not identical) will be flagged as errors.\n\n"
110 "Leave empty to disable this check." ) );
111 addParameter( separationNodeNodeParam.release() );
112
113 auto separationNodeSegmentParam = std::make_unique<QgsProcessingParameterDistance>( u"TOLERANCE_NODE_SEGMENT"_s, QObject::tr( "Minimum separation between nodes and non-noded segments" ), QVariant(), u"INPUT"_s, true );
114 separationNodeSegmentParam->setFlags( separationNodeSegmentParam->flags() | Qgis::ProcessingParameterFlag::Optional );
115 separationNodeSegmentParam->setHelp( QObject::tr( "The minimum allowed distance between a graph node and a graph edge (segment) "
116 "that is not connected to the node.\n\n"
117 "Nodes closer to a segment than this distance "
118 "will be flagged. Leave empty to disable this check." ) );
119 addParameter( separationNodeSegmentParam.release() );
120
121 auto directionField = std::make_unique<QgsProcessingParameterField>( u"DIRECTION_FIELD"_s, QObject::tr( "Direction field" ), QVariant(), u"INPUT"_s, Qgis::ProcessingFieldParameterDataType::Any, false, true );
122 directionField->setHelp( QObject::tr( "The attribute field specifying the direction of traffic flow for each segment." ) );
123 addParameter( directionField.release() );
124
125 auto forwardValue = std::make_unique<QgsProcessingParameterString>( u"VALUE_FORWARD"_s, QObject::tr( "Value for forward direction" ), QVariant(), false, true );
126 forwardValue->setHelp( QObject::tr( "The string value in the direction field that indicates one-way traffic in the digitized direction." ) );
127 addParameter( forwardValue.release() );
128
129 auto backwardValue = std::make_unique<QgsProcessingParameterString>( u"VALUE_BACKWARD"_s, QObject::tr( "Value for backward direction" ), QVariant(), false, true );
130 backwardValue->setHelp( QObject::tr( "The string value in the direction field that indicates one-way traffic opposite to the digitized direction." ) );
131 addParameter( backwardValue.release() );
132
133 auto bothValue = std::make_unique<QgsProcessingParameterString>( u"VALUE_BOTH"_s, QObject::tr( "Value for both directions" ), QVariant(), false, true );
134 bothValue->setHelp( QObject::tr( "The string value in the direction field that indicates two-way traffic." ) );
135 addParameter( bothValue.release() );
136
137 std::unique_ptr<QgsProcessingParameterNumber> tolerance = std::make_unique<QgsProcessingParameterDistance>( u"TOLERANCE"_s, QObject::tr( "Topology tolerance" ), 0, u"INPUT"_s, false, 0 );
138 tolerance->setFlags( tolerance->flags() | Qgis::ProcessingParameterFlag::Advanced );
139 addParameter( tolerance.release() );
140
141 auto invalidNetworkOutput = std::make_unique< QgsProcessingParameterFeatureSink >( u"OUTPUT_INVALID_NETWORK"_s, QObject::tr( "Invalid network features" ), Qgis::ProcessingSourceType::VectorLine, QVariant(), true, true );
142 invalidNetworkOutput->setHelp( QObject::tr( "Output line layer containing geometries representing features from the network layer with validity errors.\n\n"
143 "This output includes an attribute explaining why each feature is invalid." ) );
144 addParameter( invalidNetworkOutput.release() );
145
146 addOutput( new QgsProcessingOutputNumber( u"COUNT_INVALID_NETWORK_FEATURES"_s, QObject::tr( "Count of invalid network features" ) ) );
147
148 auto invalidNodeOutput = std::make_unique< QgsProcessingParameterFeatureSink >( u"OUTPUT_INVALID_NODES"_s, QObject::tr( "Invalid network nodes" ), Qgis::ProcessingSourceType::VectorLine, QVariant(), true, true );
149 invalidNodeOutput->setHelp( QObject::tr( "Output line layer containing geometries representing nodes from the network layer with validity errors.\n\n"
150 "This output includes an attribute explaining why each node is invalid." ) );
151 addParameter( invalidNodeOutput.release() );
152
153 addOutput( new QgsProcessingOutputNumber( u"COUNT_INVALID_NODES"_s, QObject::tr( "Count of invalid network nodes" ) ) );
154}
155
156QVariantMap QgsValidateNetworkAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
157{
158 std::unique_ptr<QgsFeatureSource> networkSource( parameterAsSource( parameters, u"INPUT"_s, context ) );
159 if ( !networkSource )
160 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
161
162 const QString directionFieldName = parameterAsString( parameters, u"DIRECTION_FIELD"_s, context );
163 const QString forwardValue = parameterAsString( parameters, u"VALUE_FORWARD"_s, context );
164 const QString backwardValue = parameterAsString( parameters, u"VALUE_BACKWARD"_s, context );
165 const QString bothValue = parameterAsString( parameters, u"VALUE_BOTH"_s, context );
166 const double tolerance = parameterAsDouble( parameters, u"TOLERANCE"_s, context );
167
168 double toleranceNodeToNode = 0;
169 bool checkNodeToNodeDistance = false;
170 if ( parameters.value( u"TOLERANCE_NODE_NODE"_s ).isValid() )
171 {
172 toleranceNodeToNode = parameterAsDouble( parameters, u"TOLERANCE_NODE_NODE"_s, context );
173 checkNodeToNodeDistance = ( toleranceNodeToNode > 0 );
174 }
175
176 double toleranceNodeToSegment = 0;
177 bool checkNodeToSegmentDistance = false;
178 if ( parameters.value( u"TOLERANCE_NODE_SEGMENT"_s ).isValid() )
179 {
180 toleranceNodeToSegment = parameterAsDouble( parameters, u"TOLERANCE_NODE_SEGMENT"_s, context );
181 checkNodeToSegmentDistance = ( toleranceNodeToSegment > 0 );
182 }
183
184 QgsFields newNetworkErrorFields;
185 newNetworkErrorFields.append( QgsField( u"error"_s, QMetaType::Type::QString ) );
186 const QgsFields networkErrorFields = QgsProcessingUtils::combineFields( networkSource->fields(), newNetworkErrorFields );
187
188 QString networkErrorDest;
189 std::unique_ptr<QgsFeatureSink> networkErrorSink( parameterAsSink( parameters, u"OUTPUT_INVALID_NETWORK"_s, context, networkErrorDest, networkErrorFields, networkSource->wkbType(), networkSource->sourceCrs() ) );
190
191 QgsFields nodeErrorFields;
192 nodeErrorFields.append( QgsField( u"error"_s, QMetaType::Type::QString ) );
193
194 QString nodeErrorDest;
195 std::unique_ptr<QgsFeatureSink> nodeErrorSink( parameterAsSink( parameters, u"OUTPUT_INVALID_NODES"_s, context, nodeErrorDest, nodeErrorFields, Qgis::WkbType::LineString, networkSource->sourceCrs() ) );
196
197 QgsProcessingMultiStepFeedback multiFeedback( 4, feedback );
198 multiFeedback.setStepWeights( { 10, 40, 10, 40 } );
199 multiFeedback.setCurrentStep( 0 );
200
201 QVariantMap outputs;
202 if ( networkErrorSink )
203 outputs.insert( u"OUTPUT_INVALID_NETWORK"_s, networkErrorDest );
204 if ( nodeErrorSink )
205 outputs.insert( u"OUTPUT_INVALID_NODES"_s, nodeErrorDest );
206
207 // attribute validation
208 int directionFieldIdx = -1;
209 long long countInvalidFeatures = 0;
210 if ( !directionFieldName.isEmpty() )
211 {
212 directionFieldIdx = networkSource->fields().lookupField( directionFieldName );
213 if ( directionFieldIdx < 0 )
214 {
215 throw QgsProcessingException( QObject::tr( "Missing field %1 in input layer" ).arg( directionFieldName ) );
216 }
217
218 multiFeedback.pushInfo( QObject::tr( "Validating direction attributes…" ) );
219 const long long count = networkSource->featureCount();
220 long long current = 0;
221 const double step = count > 0 ? 100.0 / static_cast< double >( count ) : 1;
222
223 QgsFeatureIterator fit = networkSource->getFeatures();
224 QgsFeature feature;
225 while ( fit.nextFeature( feature ) )
226 {
227 if ( multiFeedback.isCanceled() )
228 break;
229
230 const QVariant val = feature.attribute( directionFieldIdx );
231 if ( !QgsVariantUtils::isNull( val ) )
232 {
233 const QString directionValueString = val.toString();
234 if ( directionValueString != forwardValue && directionValueString != backwardValue && directionValueString != bothValue )
235 {
236 if ( networkErrorSink )
237 {
238 QgsFeature outputFeature = feature;
239 QgsAttributes outputFeatureAttrs = outputFeature.attributes();
240 outputFeatureAttrs.append( QObject::tr( "Invalid direction value: '%1'" ).arg( directionValueString ) );
241 outputFeature.setAttributes( outputFeatureAttrs );
242 if ( !networkErrorSink->addFeature( outputFeature, QgsFeatureSink::FastInsert ) )
243 {
244 throw QgsProcessingException( writeFeatureError( networkErrorSink.get(), parameters, u"OUTPUT_INVALID_NETWORK"_s ) );
245 }
246 }
247 countInvalidFeatures++;
248 }
249 }
250
251 current++;
252 multiFeedback.setProgress( static_cast< double >( current ) * step );
253 }
254
255 if ( networkErrorSink )
256 {
257 networkErrorSink->finalize();
258 }
259 }
260
261 outputs.insert( u"COUNT_INVALID_NETWORK_FEATURES"_s, countInvalidFeatures );
262 if ( countInvalidFeatures > 0 )
263 {
264 multiFeedback.reportError( QObject::tr( "Found %1 invalid network features" ).arg( countInvalidFeatures ) );
265 }
266
267 if ( !checkNodeToNodeDistance && !checkNodeToSegmentDistance )
268 {
269 // nothing more to do
270 return outputs;
271 }
272
273 multiFeedback.pushInfo( QObject::tr( "Building graph for topology validation…" ) );
274 multiFeedback.setCurrentStep( 1 );
275
276 QgsVectorLayerDirector director( networkSource.get(), directionFieldIdx, forwardValue, backwardValue, bothValue, QgsVectorLayerDirector::DirectionBoth );
277 QgsGraphBuilder builder( networkSource->sourceCrs(), true, tolerance, context.ellipsoid() );
278
279 QVector<QgsPointXY> snappedPoints;
280 director.makeGraph( &builder, {}, snappedPoints, &multiFeedback );
281
282 std::unique_ptr<QgsGraph> graph( builder.takeGraph() );
283
284 if ( multiFeedback.isCanceled() )
285 return outputs;
286
287 multiFeedback.pushInfo( QObject::tr( "Indexing graph nodes and edges…" ) );
288 multiFeedback.setCurrentStep( 2 );
289
290 // better index choice for point node index -- we satisfy the requirements
291 // of point geometries only, finalized once before reading
292 QgsSpatialIndexKDBush nodeIndex;
293 // standard QgsSpatialIndex for edges -- we can't use the faster KDBush index for these, as that is point only
295
296 const int vertexCount = graph->vertexCount();
297
298 const long long totalGraphElements = ( checkNodeToNodeDistance ? vertexCount : 0 ) + ( checkNodeToSegmentDistance ? graph->edgeCount() : 0 );
299 const double indexStep = totalGraphElements > 0 ? 100.0 / static_cast< double >( totalGraphElements ) : 1;
300 long long elementsProcessed = 0;
301
302 if ( checkNodeToNodeDistance )
303 {
304 for ( int i = 0; i < vertexCount; ++i )
305 {
306 if ( multiFeedback.isCanceled() )
307 break;
308 nodeIndex.addFeature( i, graph->vertex( i ).point() );
309 elementsProcessed++;
310 multiFeedback.setProgress( static_cast< double >( elementsProcessed ) * indexStep );
311 }
312 nodeIndex.finalize();
313 }
314
315 if ( checkNodeToSegmentDistance )
316 {
317 for ( int i = 0; i < graph->edgeCount(); ++i )
318 {
319 if ( multiFeedback.isCanceled() )
320 break;
321
322 const QgsGraphEdge &edge = graph->edge( i );
323 const QgsPointXY p1 = graph->vertex( edge.fromVertex() ).point();
324 const QgsPointXY p2 = graph->vertex( edge.toVertex() ).point();
325
326 edgeIndex.addFeature( i, QgsRectangle( p1, p2 ) );
327 elementsProcessed++;
328 multiFeedback.setProgress( static_cast< double >( elementsProcessed ) * indexStep );
329 }
330 }
331
332 // perform topology checks
333 multiFeedback.pushInfo( QObject::tr( "Validating graph topology…" ) );
334 multiFeedback.setCurrentStep( 2 );
335
336 const double topoStep = vertexCount > 0 ? 100.0 / vertexCount : 1;
337
338 struct NodeError
339 {
340 long long id = 0;
341 QgsPointXY pt;
342 double distance = std::numeric_limits<double>::max();
343 };
344
345 QSet< QPair< long long, long long > > alreadyReportedNodes;
346 long long countInvalidNodes = 0;
347
348 for ( long long i = 0; i < vertexCount; ++i )
349 {
350 if ( multiFeedback.isCanceled() )
351 break;
352
353 const QgsGraphVertex &v = graph->vertex( i );
354 const QgsPointXY &pt = v.point();
355
356 if ( checkNodeToNodeDistance )
357 {
358 const QList<QgsSpatialIndexKDBushData> candidates = nodeIndex.intersects(
359 QgsRectangle::fromCenterAndSize( pt, toleranceNodeToNode * 2, toleranceNodeToNode * 2 )
360 );
361
362 // only keep the closest violation
363 NodeError closestError;
364 for ( const QgsSpatialIndexKDBushData &data : candidates )
365 {
366 // skip self
367 if ( data.id == i )
368 continue;
369
370 // ignore nodes which are directly connected to each other
371 bool skip = false;
372 for ( const int edge : v.incomingEdges() )
373 {
374 if ( graph->edge( edge ).fromVertex() == i )
375 {
376 skip = true;
377 break;
378 }
379 }
380 if ( skip )
381 continue;
382 for ( const int edge : v.outgoingEdges() )
383 {
384 if ( graph->edge( edge ).toVertex() == data.id )
385 {
386 skip = true;
387 break;
388 }
389 }
390 if ( skip )
391 continue;
392
393 const double distanceNodeToNode = pt.distance( data.point() );
394 if ( distanceNodeToNode < toleranceNodeToNode && distanceNodeToNode < closestError.distance )
395 {
396 closestError.distance = distanceNodeToNode;
397 closestError.id = data.id;
398 closestError.pt = data.point();
399 }
400 }
401
402 if ( !closestError.pt.isEmpty() )
403 {
404 const QPair< long long, long long > nodeId = qMakePair( std::min( closestError.id, i ), std::max( closestError.id, i ) );
405 if ( alreadyReportedNodes.contains( nodeId ) )
406 {
407 // already reported this -- eg when checking the other node in the pair
408 continue;
409 }
410 alreadyReportedNodes.insert( nodeId );
411
412 if ( nodeErrorSink )
413 {
414 QgsFeature nodeErrorFeature( nodeErrorFields );
415 nodeErrorFeature.setGeometry( std::make_unique< QgsLineString >( QVector<QgsPointXY>() << pt << closestError.pt ) );
416 nodeErrorFeature.setAttributes( QgsAttributes() << QObject::tr( "Node too close to adjacent node (%1 < %2)" ).arg( closestError.distance ).arg( toleranceNodeToNode ) );
417 if ( !nodeErrorSink->addFeature( nodeErrorFeature, QgsFeatureSink::FastInsert ) )
418 throw QgsProcessingException( writeFeatureError( nodeErrorSink.get(), parameters, u"OUTPUT_INVALID_NODES"_s ) );
419 }
420 countInvalidNodes++;
421 }
422 }
423
424 if ( checkNodeToSegmentDistance )
425 {
426 // only keep the closest violation
427 NodeError closestError;
428
429 const QList<QgsFeatureId> edgeIds = edgeIndex.intersects( QgsRectangle::fromCenterAndSize( pt, toleranceNodeToSegment * 2, toleranceNodeToSegment * 2 ) );
430 for ( QgsFeatureId edgeIdx : edgeIds )
431 {
432 const QgsGraphEdge &edge = graph->edge( static_cast< int >( edgeIdx ) );
433 // skip edges connected to this node
434 if ( edge.fromVertex() == i || edge.toVertex() == i )
435 continue;
436
437 const QgsPointXY p1 = graph->vertex( edge.fromVertex() ).point();
438 const QgsPointXY p2 = graph->vertex( edge.toVertex() ).point();
439
440 QgsPointXY closestPt;
441 const double distanceToSegment = std::sqrt( pt.sqrDistToSegment( p1.x(), p1.y(), p2.x(), p2.y(), closestPt ) );
442 if ( distanceToSegment >= toleranceNodeToSegment )
443 continue;
444
445 // we don't consider this a node-to-segment error if the closest point is actually one of the segment endpoints.
446 // in that case it's a node-to-NODE error.
447 if ( closestPt.compare( p1 ) || closestPt.compare( p2 ) )
448 {
449 continue;
450 }
451
452 if ( distanceToSegment > closestError.distance )
453 {
454 continue;
455 }
456 closestError.distance = distanceToSegment;
457 closestError.pt = closestPt;
458 }
459
460 if ( !closestError.pt.isEmpty() )
461 {
462 if ( nodeErrorSink )
463 {
464 QgsFeature nodeErrorFeature( nodeErrorFields );
465 nodeErrorFeature.setGeometry( std::make_unique< QgsLineString >( QVector<QgsPointXY>() << pt << closestError.pt ) );
466 nodeErrorFeature.setAttributes( QgsAttributes() << QObject::tr( "Node too close to non-noded segment (%1 < %2)" ).arg( closestError.distance ).arg( toleranceNodeToSegment ) );
467 if ( !nodeErrorSink->addFeature( nodeErrorFeature, QgsFeatureSink::FastInsert ) )
468 throw QgsProcessingException( writeFeatureError( nodeErrorSink.get(), parameters, u"OUTPUT_INVALID_NODES"_s ) );
469 }
470 countInvalidNodes++;
471 }
472 }
473
474 multiFeedback.setProgress( static_cast< double >( i ) * topoStep );
475 if ( nodeErrorSink )
476 {
477 nodeErrorSink->finalize();
478 }
479 }
480
481 feedback->setProgress( 100 );
482 if ( countInvalidNodes > 0 )
483 {
484 multiFeedback.reportError( QObject::tr( "Found %1 invalid network nodes" ).arg( countInvalidNodes ) );
485 }
486
487 outputs.insert( u"COUNT_INVALID_NODES"_s, countInvalidNodes );
488
489 return outputs;
490}
491
@ VectorLine
Vector line layers.
Definition qgis.h:3606
@ LineString
LineString.
Definition qgis.h:283
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3834
@ Optional
Parameter is optional.
Definition qgis.h:3836
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.
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.
@ 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
QgsAttributes attributes
Definition qgsfeature.h:69
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
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
Used for making the QgsGraph object.
Represents an edge in a graph.
Definition qgsgraph.h:44
int fromVertex() const
Returns the index of the vertex at the start of this edge.
Definition qgsgraph.cpp:180
int toVertex() const
Returns the index of the vertex at the end of this edge.
Definition qgsgraph.cpp:185
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
Represents a 2D point.
Definition qgspointxy.h:62
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition qgspointxy.h:208
bool compare(const QgsPointXY &other, double epsilon=4 *std::numeric_limits< double >::epsilon()) const
Compares this point with another point with a fuzzy tolerance.
Definition qgspointxy.h:255
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=Qgis::DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
Contains information about the context in which a processing algorithm is executed.
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.
Processing feedback object for multi-step operations.
A numeric output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
A rectangle specified with double values.
static QgsRectangle fromCenterAndSize(const QgsPointXY &center, double width, double height)
Creates a new rectangle, given the specified center point and width and height.
A container for data stored inside a QgsSpatialIndexKDBush index.
A very fast static spatial index for 2D points based on a flat KD-tree.
void finalize()
Finalizes the index after manually adding features.
QList< QgsSpatialIndexKDBushData > intersects(const QgsRectangle &rectangle) const
Returns the list of features which fall within the specified rectangle.
bool addFeature(QgsFeatureId id, const QgsPointXY &point)
Adds a single feature to the index.
A spatial index for QgsFeature objects.
@ FlagStoreFeatureGeometries
Indicates that the spatial index should also store feature geometries. This requires more memory,...
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Determines creating a graph from a vector line layer.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features