Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
with
250 additions
and 37 deletions.
- +2 −2 python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py
- +1 −1 python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
- +2 −0 src/analysis/CMakeLists.txt
- +33 −33 src/analysis/processing/qgsalgorithmnetworkanalysisbase.cpp
- +1 −1 src/analysis/processing/qgsalgorithmnetworkanalysisbase.h
- +156 −0 src/analysis/processing/qgsalgorithmshortestpathpointtolayer.cpp
- +53 −0 src/analysis/processing/qgsalgorithmshortestpathpointtolayer.h
- +2 −0 src/analysis/processing/qgsnativealgorithms.cpp
@@ -0,0 +1,156 @@ | ||
/*************************************************************************** | ||
qgsalgorithmshortestpathpointtolayer.cpp | ||
--------------------- | ||
begin : July 2018 | ||
copyright : (C) 2018 by Alexander Bruy | ||
email : alexander dot bruy at gmail dot com | ||
***************************************************************************/ | ||
|
||
/*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsalgorithmshortestpathpointtolayer.h" | ||
|
||
#include "qgsgraphanalyzer.h" | ||
|
||
#include "qgsmessagelog.h" | ||
|
||
///@cond PRIVATE | ||
|
||
QString QgsShortestPathPointToLayerAlgorithm::name() const | ||
{ | ||
return QStringLiteral( "shortestpathpointtolayer" ); | ||
} | ||
|
||
QString QgsShortestPathPointToLayerAlgorithm::displayName() const | ||
{ | ||
return QObject::tr( "Shortest path (point to layer)" ); | ||
} | ||
|
||
QStringList QgsShortestPathPointToLayerAlgorithm::tags() const | ||
{ | ||
return QObject::tr( "network,path,shortest,fastest" ).split( ',' ); | ||
} | ||
|
||
QString QgsShortestPathPointToLayerAlgorithm::shortHelpString() const | ||
{ | ||
return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start point and multiple end points defined by point vector layer." ); | ||
} | ||
|
||
QgsShortestPathPointToLayerAlgorithm *QgsShortestPathPointToLayerAlgorithm::createInstance() const | ||
{ | ||
return new QgsShortestPathPointToLayerAlgorithm(); | ||
} | ||
|
||
void QgsShortestPathPointToLayerAlgorithm::initAlgorithm( const QVariantMap & ) | ||
{ | ||
addCommonParams(); | ||
addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) ); | ||
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "END_POINTS" ), QObject::tr( "Vector layer with end points" ), QList< int >() << QgsProcessing::TypeVectorPoint ) ); | ||
|
||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) ); | ||
} | ||
|
||
QVariantMap QgsShortestPathPointToLayerAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) | ||
{ | ||
loadCommonParams( parameters, context, feedback ); | ||
|
||
QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() ); | ||
|
||
std::unique_ptr< QgsFeatureSource > endPoints( parameterAsSource( parameters, QStringLiteral( "END_POINTS" ), context ) ); | ||
if ( !endPoints ) | ||
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "END_POINTS" ) ) ); | ||
|
||
QgsFields fields = endPoints->fields(); | ||
fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) ); | ||
fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) ); | ||
fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) ); | ||
|
||
QString dest; | ||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) ); | ||
if ( !sink ) | ||
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); | ||
|
||
QVector< QgsPointXY > points; | ||
points.push_front( startPoint ); | ||
QHash< int, QgsAttributes > sourceAttributes; | ||
loadPoints( endPoints.get(), points, sourceAttributes, context, feedback ); | ||
|
||
feedback->pushInfo( QObject::tr( "Building graph…" ) ); | ||
QVector< QgsPointXY > snappedPoints; | ||
mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); | ||
|
||
feedback->pushInfo( QObject::tr( "Calculating shortest paths…" ) ); | ||
QgsGraph *graph = mBuilder->graph(); | ||
int idxStart = graph->findVertex( snappedPoints[0] ); | ||
int idxEnd; | ||
|
||
QVector< int > tree; | ||
QVector< double > costs; | ||
QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); | ||
|
||
QVector<QgsPointXY> route; | ||
double cost; | ||
|
||
QgsFeature feat; | ||
feat.setFields( fields ); | ||
QgsAttributes attributes; | ||
|
||
int step = points.size() > 0 ? 100.0 / points.size() : 1; | ||
for ( int i = 1; i < points.size(); i++ ) | ||
{ | ||
if ( feedback->isCanceled() ) | ||
{ | ||
break; | ||
} | ||
|
||
idxEnd = graph->findVertex( snappedPoints[i] ); | ||
if ( tree.at( idxEnd ) == -1 ) | ||
{ | ||
feedback->reportError( QObject::tr( "There is no route from start point (%1) to end point (%2)." ) | ||
.arg( startPoint.toString() ) | ||
.arg( points[i].toString() ) ); | ||
feat.clearGeometry(); | ||
attributes = sourceAttributes.value( i ); | ||
attributes.append( QVariant() ); | ||
attributes.append( points[i].toString() ); | ||
feat.setAttributes( attributes ); | ||
sink->addFeature( feat, QgsFeatureSink::FastInsert ); | ||
continue; | ||
} | ||
|
||
route.clear(); | ||
route.push_front( graph->vertex( idxEnd ).point() ); | ||
cost = costs.at( idxEnd ); | ||
while ( idxEnd != idxStart ) | ||
{ | ||
idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex(); | ||
route.push_front( graph->vertex( idxEnd ).point() ); | ||
} | ||
|
||
QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); | ||
QgsFeature feat; | ||
feat.setFields( fields ); | ||
attributes = sourceAttributes.value( i ); | ||
attributes.append( startPoint.toString() ); | ||
attributes.append( points[i].toString() ); | ||
attributes.append( cost / mMultiplier ); | ||
feat.setAttributes( attributes ); | ||
feat.setGeometry( geom ); | ||
sink->addFeature( feat, QgsFeatureSink::FastInsert ); | ||
|
||
feedback->setProgress( i * step ); | ||
} | ||
|
||
QVariantMap outputs; | ||
outputs.insert( QStringLiteral( "OUTPUT" ), dest ); | ||
return outputs; | ||
} | ||
|
||
///@endcond |
@@ -0,0 +1,53 @@ | ||
/*************************************************************************** | ||
qgsalgorithmshortestpathpointtolayer.h | ||
--------------------- | ||
begin : JUly 2018 | ||
copyright : (C) 2018 by Alexander Bruy | ||
email : alexander dot bruy at gmail dot com | ||
***************************************************************************/ | ||
|
||
/*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H | ||
#define QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H | ||
|
||
#define SIP_NO_FILE | ||
|
||
#include "qgis.h" | ||
#include "qgsalgorithmnetworkanalysisbase.h" | ||
|
||
///@cond PRIVATE | ||
|
||
/** | ||
* Native shortest path (point to layer) algorithm. | ||
*/ | ||
class QgsShortestPathPointToLayerAlgorithm : public QgsNetworkAnalysisAlgorithmBase | ||
{ | ||
|
||
public: | ||
|
||
QgsShortestPathPointToLayerAlgorithm() = default; | ||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override; | ||
QString name() const override; | ||
QString displayName() const override; | ||
QStringList tags() const override; | ||
QString shortHelpString() const override; | ||
QgsShortestPathPointToLayerAlgorithm *createInstance() const override SIP_FACTORY; | ||
|
||
protected: | ||
|
||
QVariantMap processAlgorithm( const QVariantMap ¶meters, | ||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; | ||
|
||
}; | ||
|
||
///@endcond PRIVATE | ||
|
||
#endif // QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H |