wangsh 2011-11-20
qgis是一款稳定高效的gis桌面产品(参考1),而开发者提供了最短路径功能(参考2),其主要功能为:
两点间的最短路径;
最短路径Tree。
首先编译qgis(参考链接)
最短路径核心代码:代码位置:QGIS\src\analysis\network\qgsgraphanalyzer.cpp
void QgsGraphAnalyzer::shortestpath( const QgsGraph* source, int startPointIdx, int criterionNum, const QVector<int>& destPointCost, QVector<double>& cost, QgsGraph* treeResult )
{
// QMap< cost, vertexIdx > not_begin
// I use it and not create any struct or class.
QMap< double, int > not_begin;
QMap< double, int >::iterator it;
// QVector< QPair< cost, arc id > result
QVector< QPair< double, int > > result;
result.reserve( source->vertexCount() );
int i;
for ( i = 0; i < source->vertexCount(); ++i )
{
result.push_back( QPair<double, int> ( std::numeric_limits<double>::infinity() , i ) );
}
result[ startPointIdx ] = QPair<double, int> ( 0.0, -1 );
not_begin.insert( 0.0, startPointIdx );
// begin Dijkstra algorithm
while ( !not_begin.empty() )
{
it = not_begin.begin();
double curCost = it.key();
int curVertex = it.value();
not_begin.erase( it );
// edge index list
QgsGraphArcIdList l = source->vertex( curVertex ).outArc();
QgsGraphArcIdList::iterator arcIt;
for ( arcIt = l.begin(); arcIt != l.end(); ++arcIt )
{
const QgsGraphArc& arc = source->arc( *arcIt );
double cost = arc.property( criterionNum ).toDouble() + curCost;
if ( cost < result[ arc.inVertex()].first )
{
result[ arc.inVertex()] = QPair< double, int >( cost, *arcIt );
not_begin.insert( cost, arc.inVertex() );
}
}
}
// fill shortestpath tree
if ( treeResult != NULL )
{
// sourceVertexIdx2resultVertexIdx
QVector<int> source2result( result.size(), -1 );
for ( i = 0; i < source->vertexCount(); ++i )
{
if ( result[ i ].first < std::numeric_limits<double>::infinity() )
{
source2result[ i ] = treeResult->addVertex( source->vertex( i ).point() );
}
}
for ( i = 0; i < source->vertexCount(); ++i )
{
if ( result[ i ].first < std::numeric_limits<double>::infinity() && result[i].second != -1 )
{
const QgsGraphArc& arc = source->arc( result[i].second );
treeResult->addArc( source2result[ arc.outVertex()], source2result[ i ],
arc.properties() );
}
}
}
// fill shortestpath's costs
for ( i = 0; i < destPointCost.size(); ++i )
{
cost[i] = result[ destPointCost[i] ].first;
}
}
QgsGraph* QgsGraphAnalyzer::shortestTree( const QgsGraph* source, int startVertexIdx, int criterionNum )
{
QgsGraph *g = new QgsGraph;
QVector<int> v;
QVector<double> vv;
QgsGraphAnalyzer::shortestpath( source, startVertexIdx, criterionNum, v, vv, g );
return g;
}
调用最短路径:
位置:QGIS\src\plugins\roadgraph\shortestpathwidget.cpp
bool RgShortestPathWidget::getPath( QgsGraph* shortestTree, 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 false;
}
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 false;
}
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 false;
}
if ( p2 == QgsPoint( 0.0, 0.0 ) )
{
QMessageBox::critical( this, tr( "Tie point failed" ), tr( "Stop point doesn't tie to the road!" ) );
return false;
}
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;
QgsGraphAnalyzer::shortestpath( graph, startVertexIdx, criterionNum, pointIdx, pointCost, shortestTree );
delete graph;
if ( shortestTree->findVertex( p2 ) == -1 )
{
QMessageBox::critical( this, tr( "Path not found" ), tr( "Path not found" ) );
return false;
}
return true;
}
参考资料
1. Qgis主页 http://www.qgis.org/
2. RoadGraph开发介绍 http://gis-lab.info/qa/road-graph-eng.html
3. Qgis编译 http://blog.csdn.net/wsh6759/article/details/6894073
4. 测试数据地址:http://svn.gis-lab.info/road-graph/
5. 源码:http://svn.gis-lab.info/road-graph/