Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsalgorithmshortestpathpointtolayer.cpp 3 : : --------------------- 4 : : begin : July 2018 5 : : copyright : (C) 2018 by Alexander Bruy 6 : : email : alexander dot bruy 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 : : 18 : : #include "qgsalgorithmshortestpathpointtolayer.h" 19 : : 20 : : #include "qgsgraphanalyzer.h" 21 : : 22 : : #include "qgsmessagelog.h" 23 : : 24 : : ///@cond PRIVATE 25 : : 26 : 0 : QString QgsShortestPathPointToLayerAlgorithm::name() const 27 : : { 28 : 0 : return QStringLiteral( "shortestpathpointtolayer" ); 29 : : } 30 : : 31 : 0 : QString QgsShortestPathPointToLayerAlgorithm::displayName() const 32 : : { 33 : 0 : return QObject::tr( "Shortest path (point to layer)" ); 34 : : } 35 : : 36 : 0 : QStringList QgsShortestPathPointToLayerAlgorithm::tags() const 37 : : { 38 : 0 : return QObject::tr( "network,path,shortest,fastest" ).split( ',' ); 39 : 0 : } 40 : : 41 : 0 : QString QgsShortestPathPointToLayerAlgorithm::shortHelpString() const 42 : : { 43 : 0 : return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start point and multiple end points defined by point vector layer." ); 44 : : } 45 : : 46 : 0 : QgsShortestPathPointToLayerAlgorithm *QgsShortestPathPointToLayerAlgorithm::createInstance() const 47 : : { 48 : 0 : return new QgsShortestPathPointToLayerAlgorithm(); 49 : : } 50 : : 51 : 0 : void QgsShortestPathPointToLayerAlgorithm::initAlgorithm( const QVariantMap & ) 52 : : { 53 : 0 : addCommonParams(); 54 : 0 : addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) ); 55 : 0 : addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "END_POINTS" ), QObject::tr( "Vector layer with end points" ), QList< int >() << QgsProcessing::TypeVectorPoint ) ); 56 : : 57 : 0 : addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) ); 58 : 0 : } 59 : : 60 : 0 : QVariantMap QgsShortestPathPointToLayerAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) 61 : : { 62 : 0 : loadCommonParams( parameters, context, feedback ); 63 : : 64 : 0 : QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() ); 65 : : 66 : 0 : std::unique_ptr< QgsFeatureSource > endPoints( parameterAsSource( parameters, QStringLiteral( "END_POINTS" ), context ) ); 67 : 0 : if ( !endPoints ) 68 : 0 : throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "END_POINTS" ) ) ); 69 : : 70 : 0 : QgsFields fields = endPoints->fields(); 71 : 0 : fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) ); 72 : 0 : fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) ); 73 : 0 : fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) ); 74 : : 75 : 0 : QString dest; 76 : 0 : std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs(), QgsFeatureSink::RegeneratePrimaryKey ) ); 77 : 0 : if ( !sink ) 78 : 0 : throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); 79 : : 80 : 0 : QVector< QgsPointXY > points; 81 : 0 : points.push_front( startPoint ); 82 : 0 : QHash< int, QgsAttributes > sourceAttributes; 83 : 0 : loadPoints( endPoints.get(), points, sourceAttributes, context, feedback ); 84 : : 85 : 0 : feedback->pushInfo( QObject::tr( "Building graph…" ) ); 86 : 0 : QVector< QgsPointXY > snappedPoints; 87 : 0 : mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); 88 : : 89 : 0 : feedback->pushInfo( QObject::tr( "Calculating shortest paths…" ) ); 90 : 0 : QgsGraph *graph = mBuilder->graph(); 91 : 0 : int idxStart = graph->findVertex( snappedPoints[0] ); 92 : : int idxEnd; 93 : : 94 : 0 : QVector< int > tree; 95 : 0 : QVector< double > costs; 96 : 0 : QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); 97 : : 98 : 0 : QVector<QgsPointXY> route; 99 : : double cost; 100 : : 101 : 0 : QgsFeature feat; 102 : 0 : feat.setFields( fields ); 103 : 0 : QgsAttributes attributes; 104 : : 105 : 0 : int step = points.size() > 0 ? 100.0 / points.size() : 1; 106 : 0 : for ( int i = 1; i < points.size(); i++ ) 107 : : { 108 : 0 : if ( feedback->isCanceled() ) 109 : : { 110 : 0 : break; 111 : : } 112 : : 113 : 0 : idxEnd = graph->findVertex( snappedPoints[i] ); 114 : 0 : if ( tree.at( idxEnd ) == -1 ) 115 : : { 116 : 0 : feedback->reportError( QObject::tr( "There is no route from start point (%1) to end point (%2)." ) 117 : 0 : .arg( startPoint.toString(), 118 : 0 : points[i].toString() ) ); 119 : 0 : feat.clearGeometry(); 120 : 0 : attributes = sourceAttributes.value( i ); 121 : 0 : attributes.append( QVariant() ); 122 : 0 : attributes.append( points[i].toString() ); 123 : 0 : feat.setAttributes( attributes ); 124 : 0 : sink->addFeature( feat, QgsFeatureSink::FastInsert ); 125 : 0 : continue; 126 : : } 127 : : 128 : 0 : route.clear(); 129 : 0 : route.push_front( graph->vertex( idxEnd ).point() ); 130 : 0 : cost = costs.at( idxEnd ); 131 : 0 : while ( idxEnd != idxStart ) 132 : : { 133 : 0 : idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex(); 134 : 0 : route.push_front( graph->vertex( idxEnd ).point() ); 135 : : } 136 : : 137 : 0 : QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); 138 : 0 : QgsFeature feat; 139 : 0 : feat.setFields( fields ); 140 : 0 : attributes = sourceAttributes.value( i ); 141 : 0 : attributes.append( startPoint.toString() ); 142 : 0 : attributes.append( points[i].toString() ); 143 : 0 : attributes.append( cost / mMultiplier ); 144 : 0 : feat.setAttributes( attributes ); 145 : 0 : feat.setGeometry( geom ); 146 : 0 : sink->addFeature( feat, QgsFeatureSink::FastInsert ); 147 : : 148 : 0 : feedback->setProgress( i * step ); 149 : 0 : } 150 : : 151 : 0 : QVariantMap outputs; 152 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), dest ); 153 : 0 : return outputs; 154 : 0 : } 155 : : 156 : : ///@endcond