void RgShortestPathWidget::exportPath() { RgExportDlg dlg( this ); if ( !dlg.exec() ) return; QgsVectorLayer *vl = dlg.mapLayer(); if ( vl == NULL ) return; QgsPoint p1, p2; QgsGraph *path = getPath( p1, p2 ); if ( path == NULL ) return; QgsCoordinateTransform ct( mPlugin->iface()->mapCanvas()->mapSettings().destinationCrs(), vl->crs() ); int startVertexIdx = path->findVertex( p1 ); int stopVertexIdx = path->findVertex( p2 ); double time = 0.0; double cost = 0.0; Unit timeUnit = Unit::byName( mPlugin->timeUnitName() ); Unit distanceUnit = Unit::byName( mPlugin->distanceUnitName() ); QgsPolyline p; while ( startVertexIdx != stopVertexIdx ) { if ( stopVertexIdx < 0 ) break; QgsGraphArcIdList l = path->vertex( stopVertexIdx ).inArc(); if ( l.empty() ) break; const QgsGraphArc& e = path->arc( l.front() ); cost += e.property( 0 ).toDouble(); time += e.property( 1 ).toDouble(); p.push_front( ct.transform( path->vertex( e.inVertex() ).point() ) ); stopVertexIdx = e.outVertex(); } p.push_front( ct.transform( p1 ) ); QgsFeature f; f.initAttributes( vl->pendingFields().count() ); f.setGeometry( QgsGeometry::fromPolyline( p ) ); f.setAttribute( 0, cost / distanceUnit.multipler() ); f.setAttribute( 1, time / timeUnit.multipler() ); QgsFeatureList features; features << f; vl->dataProvider()->addFeatures( features ); vl->updateExtents(); mPlugin->iface()->mapCanvas()->update(); delete path; }
void RgShortestPathWidget::findingPath() { QgsPoint p1, p2; QgsGraph *path = getPath( p1, p2 ); if ( path == NULL ) return; mrbPath->reset( QGis::Line ); double time = 0.0; double cost = 0.0; int startVertexIdx = path->findVertex( p1 ); int stopVertexIdx = path->findVertex( p2 ); QList< QgsPoint > p; while ( startVertexIdx != stopVertexIdx ) { if ( stopVertexIdx < 0 ) break; QgsGraphArcIdList l = path->vertex( stopVertexIdx ).inArc(); if ( l.empty() ) break; const QgsGraphArc& e = path->arc( l.front() ); cost += e.property( 0 ).toDouble(); time += e.property( 1 ).toDouble(); p.push_front( path->vertex( e.inVertex() ).point() ); stopVertexIdx = e.outVertex(); } p.push_front( p1 ); QList< QgsPoint>::iterator it; for ( it = p.begin(); it != p.end(); ++it ) { mrbPath->addPoint( *it ); } Unit timeUnit = Unit::byName( mPlugin->timeUnitName() ); Unit distanceUnit = Unit::byName( mPlugin->distanceUnitName() ); mPathCostLineEdit->setText( QString().setNum( cost / distanceUnit.multipler() ) + distanceUnit.name() ); mPathTimeLineEdit->setText( QString().setNum( time / timeUnit.multipler() ) + timeUnit.name() ); mrbPath->setColor( Qt::red ); delete path; }
void RgShortestPathWidget::exportPath() { RgExportDlg dlg( this ); if ( !dlg.exec() ) return; QgsVectorLayer *vl = dlg.mapLayer(); if ( vl == NULL ) return; QgsPoint p1, p2; QgsGraph *path = getPath( p1, p2 ); if ( path == NULL ) return; QgsCoordinateTransform ct( mPlugin->iface()->mapCanvas()->mapRenderer()->destinationCrs(), vl->crs() ); int startVertexIdx = path->findVertex( p1 ); int stopVertexIdx = path->findVertex( p2 ); QgsPolyline p; while ( startVertexIdx != stopVertexIdx ) { QgsGraphArcIdList l = path->vertex( stopVertexIdx ).inArc(); if ( l.empty() ) break; const QgsGraphArc& e = path->arc( l.front() ); p.push_front( ct.transform( path->vertex( e.inVertex() ).point() ) ); stopVertexIdx = e.outVertex(); } p.push_front( ct.transform( p1 ) ); vl->startEditing(); QgsFeature f; f.setGeometry( QgsGeometry::fromPolyline( p ) ); vl->addFeature( f ); vl->updateExtents(); mPlugin->iface()->mapCanvas()->update(); delete path; }
QVariantMap QgsShortestPathPointToPointAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { loadCommonParams( parameters, context, feedback ); QgsFields 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" ) ) ); QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() ); QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, mNetwork->sourceCrs() ); feedback->pushInfo( QObject::tr( "Building graph…" ) ); QVector< QgsPointXY > points; points << startPoint << endPoint; QVector< QgsPointXY > snappedPoints; mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback ); feedback->pushInfo( QObject::tr( "Calculating shortest path…" ) ); QgsGraph *graph = mBuilder->graph(); int idxStart = graph->findVertex( snappedPoints[0] ); int idxEnd = graph->findVertex( snappedPoints[1] ); QVector< int > tree; QVector< double > costs; QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs ); if ( tree.at( idxEnd ) == -1 ) { throw QgsProcessingException( QObject::tr( "There is no route from start point to end point." ) ); } QVector<QgsPointXY> route; route.push_front( graph->vertex( idxEnd ).point() ); double cost = costs.at( idxEnd ); while ( idxEnd != idxStart ) { idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex(); route.push_front( graph->vertex( idxEnd ).point() ); } feedback->pushInfo( QObject::tr( "Writing results…" ) ); QgsGeometry geom = QgsGeometry::fromPolylineXY( route ); QgsFeature feat; feat.setFields( fields ); QgsAttributes attributes; attributes << startPoint.toString() << endPoint.toString() << cost / mMultiplier; feat.setGeometry( geom ); feat.setAttributes( attributes ); sink->addFeature( feat, QgsFeatureSink::FastInsert ); QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); outputs.insert( QStringLiteral( "TRAVEL_COST" ), cost / mMultiplier ); return outputs; }
QgsGraph* RgShortestPathWidget::getPath( QgsPoint& p1, QgsPoint& p2 ) { if ( mFrontPointLineEdit->text().isNull() || mBackPointLineEdit->text().isNull() ) { QMessageBox::critical( this, tr( "Point not selected" ), tr( "First, select start and stop points." ) ); return NULL; } QgsGraphBuilder builder( mPlugin->iface()->mapCanvas()->mapRenderer()->destinationCrs(), mPlugin->iface()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled(), mPlugin->topologyToleranceFactor() ); { const QgsGraphDirector *director = mPlugin->director(); if ( director == NULL ) { QMessageBox::critical( this, tr( "Plugin isn't configured" ), tr( "Plugin isn't configured!" ) ); return NULL; } connect( director, SIGNAL( buildProgress( int, int ) ), mPlugin->iface()->mainWindow(), SLOT( showProgress( int, int ) ) ); connect( director, SIGNAL( buildMessage( QString ) ), mPlugin->iface()->mainWindow(), SLOT( showStatusMessage( QString ) ) ); QVector< QgsPoint > points; QVector< QgsPoint > tiedPoint; points.push_back( mFrontPoint ); points.push_back( mBackPoint ); director->makeGraph( &builder, points, tiedPoint ); p1 = tiedPoint[ 0 ]; p2 = tiedPoint[ 1 ]; // not need delete director; } if ( p1 == QgsPoint( 0.0, 0.0 ) ) { QMessageBox::critical( this, tr( "Tie point failed" ), tr( "Start point doesn't tie to the road!" ) ); return NULL; } if ( p2 == QgsPoint( 0.0, 0.0 ) ) { QMessageBox::critical( this, tr( "Tie point failed" ), tr( "Stop point doesn't tie to the road!" ) ); return NULL; } QgsGraph *graph = builder.graph(); QVector< int > pointIdx( 0, 0 ); QVector< double > pointCost( 0, 0.0 ); int startVertexIdx = graph->findVertex( p1 ); int criterionNum = 0; if ( mCriterionName->currentIndex() > 0 ) criterionNum = 1; QgsGraph* shortestpathTree = QgsGraphAnalyzer::shortestTree( graph, startVertexIdx, criterionNum ); delete graph; if ( shortestpathTree->findVertex( p2 ) == -1 ) { QMessageBox::critical( this, tr( "Path not found" ), tr( "Path not found" ) ); return NULL; } return shortestpathTree; }
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(), 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; }
QgsGraph* RgShortestPathWidget::getPath( QgsPoint& p1, QgsPoint& p2 ) { if ( mFrontPointLineEdit->text().isNull() || mBackPointLineEdit->text().isNull() ) { QMessageBox::critical( this, tr( "Point not selected" ), tr( "First, select start and stop points." ) ); return nullptr; } QgsGraphBuilder builder( mPlugin->iface()->mapCanvas()->mapSettings().destinationCrs(), mPlugin->iface()->mapCanvas()->mapSettings().hasCrsTransformEnabled(), mPlugin->topologyToleranceFactor() ); { const QgsGraphDirector *director = mPlugin->director(); if ( !director ) { QMessageBox::critical( this, tr( "Plugin isn't configured" ), tr( "Plugin isn't configured! Please go to the Vector menu, Road Graph, Settings option to configure it." ) ); return nullptr; } connect( director, SIGNAL( buildProgress( int, int ) ), mPlugin->iface()->mainWindow(), SLOT( showProgress( int, int ) ) ); connect( director, SIGNAL( buildMessage( QString ) ), mPlugin->iface()->mainWindow(), SLOT( showStatusMessage( QString ) ) ); QVector< QgsPoint > points; QVector< QgsPoint > tiedPoint; points.push_back( mFrontPoint ); points.push_back( mBackPoint ); director->makeGraph( &builder, points, tiedPoint ); p1 = tiedPoint[ 0 ]; p2 = tiedPoint[ 1 ]; // not need delete director; } if ( p1 == QgsPoint( 0.0, 0.0 ) ) { QMessageBox::critical( this, tr( "Tie point failed" ), tr( "Start point doesn't tie to the road!" ) ); return nullptr; } if ( p2 == QgsPoint( 0.0, 0.0 ) ) { QMessageBox::critical( this, tr( "Tie point failed" ), tr( "Stop point doesn't tie to the road!" ) ); return nullptr; } QgsGraph *graph = builder.graph(); int startVertexIdx = graph->findVertex( p1 ); if ( startVertexIdx < 0 ) { mPlugin->iface()->messageBar()->pushMessage( tr( "Cannot calculate path" ), tr( "Could not find start vertex. Please check your input data." ), QgsMessageBar::WARNING, mPlugin->iface()->messageTimeout() ); delete graph; return nullptr; } int criterionNum = 0; if ( mCriterionName->currentIndex() > 0 ) criterionNum = 1; if ( graph->vertexCount() == 0 ) { mPlugin->iface()->messageBar()->pushMessage( tr( "Cannot calculate path" ), tr( "The created graph is empty. Please check your input data." ), QgsMessageBar::WARNING, mPlugin->iface()->messageTimeout() ); delete graph; return nullptr; } QgsGraph* shortestpathTree = QgsGraphAnalyzer::shortestTree( graph, startVertexIdx, criterionNum ); delete graph; if ( shortestpathTree->findVertex( p2 ) == -1 ) { delete shortestpathTree; QMessageBox::critical( this, tr( "Path not found" ), tr( "Path not found" ) ); return nullptr; } return shortestpathTree; }