mirror of
git://projects.qi-hardware.com/nanomap.git
synced 2024-11-28 06:56:14 +02:00
f1a2430393
This reverts commit da88ec21cd
.
This was not the right solution
408 lines
13 KiB
C++
408 lines
13 KiB
C++
/*
|
|
Copyright 2010 Christian Vetter veaac.fdirct@gmail.com
|
|
|
|
This file is part of MoNav.
|
|
|
|
MoNav 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
MoNav is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY
|
|
{
|
|
}
|
|
without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with MoNav. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "contractionhierarchiesclient.h"
|
|
#include "utils/qthelpers.h"
|
|
#include <QtDebug>
|
|
#include <stack>
|
|
#ifndef NOGUI
|
|
#include <QMessageBox>
|
|
#endif
|
|
|
|
ContractionHierarchiesClient::ContractionHierarchiesClient()
|
|
{
|
|
m_heapForward = NULL;
|
|
m_heapBackward = NULL;
|
|
}
|
|
|
|
ContractionHierarchiesClient::~ContractionHierarchiesClient()
|
|
{
|
|
unload();
|
|
}
|
|
|
|
|
|
QString ContractionHierarchiesClient::GetName()
|
|
{
|
|
return "Contraction Hierarchies";
|
|
}
|
|
|
|
void ContractionHierarchiesClient::SetInputDirectory( const QString& dir )
|
|
{
|
|
m_directory = dir;
|
|
}
|
|
|
|
void ContractionHierarchiesClient::ShowSettings()
|
|
{
|
|
#ifndef NOGUI
|
|
QMessageBox::information( NULL, "Settings", "No settings available" );
|
|
#endif
|
|
}
|
|
|
|
void ContractionHierarchiesClient::unload()
|
|
{
|
|
if ( m_heapForward != NULL )
|
|
delete m_heapForward;
|
|
m_heapForward = NULL;
|
|
if ( m_heapBackward != NULL )
|
|
delete m_heapBackward;
|
|
m_heapBackward = NULL;
|
|
m_types.clear();
|
|
}
|
|
|
|
bool ContractionHierarchiesClient::LoadData()
|
|
{
|
|
QString filename = fileInDirectory( m_directory,"Contraction Hierarchies" );
|
|
unload();
|
|
|
|
if ( !m_graph.loadGraph( filename, 1024 * 1024 * 4 ) )
|
|
return false;
|
|
|
|
m_namesFile.setFileName( filename + "_names" );
|
|
if ( !openQFile( &m_namesFile, QIODevice::ReadOnly ) )
|
|
return false;
|
|
m_names = ( const char* ) m_namesFile.map( 0, m_namesFile.size() );
|
|
if ( m_names == NULL )
|
|
return false;
|
|
m_namesFile.close();
|
|
|
|
m_heapForward = new Heap( m_graph.numberOfNodes() );
|
|
m_heapBackward = new Heap( m_graph.numberOfNodes() );
|
|
|
|
QFile typeFile( filename + "_types" );
|
|
if ( !openQFile( &typeFile, QIODevice::ReadOnly ) )
|
|
return false;
|
|
|
|
QByteArray buffer = typeFile.readAll();
|
|
QString types = QString::fromUtf8( buffer.constData() );
|
|
m_types = types.split( ';' );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ContractionHierarchiesClient::GetRoute( double* distance, QVector< Node>* pathNodes, QVector< Edge >* pathEdges, const IGPSLookup::Result& source, const IGPSLookup::Result& target )
|
|
{
|
|
m_heapForward->Clear();
|
|
m_heapBackward->Clear();
|
|
|
|
*distance = computeRoute( source, target, pathNodes, pathEdges );
|
|
if ( *distance == std::numeric_limits< int >::max() )
|
|
return false;
|
|
|
|
// is it shorter to drive along the edge?
|
|
if ( target.source == source.source && target.target == source.target && source.edgeID == target.edgeID ) {
|
|
EdgeIterator targetEdge = m_graph.findEdge( target.source, target.target, target.edgeID );
|
|
double onEdgeDistance = fabs( target.percentage - source.percentage ) * targetEdge.distance();
|
|
if ( onEdgeDistance < *distance ) {
|
|
if ( ( targetEdge.forward() && targetEdge.backward() ) || source.percentage < target.percentage ) {
|
|
pathNodes->clear();
|
|
pathEdges->clear();
|
|
pathNodes->push_back( source.nearestPoint );
|
|
|
|
QVector< Node > tempNodes;
|
|
if ( targetEdge.unpacked() )
|
|
m_graph.path( targetEdge, &tempNodes, pathEdges, target.target == targetEdge.target() );
|
|
else
|
|
pathEdges->push_back( targetEdge.description() );
|
|
|
|
if ( target.previousWayCoordinates < source.previousWayCoordinates ) {
|
|
for ( unsigned pathID = target.previousWayCoordinates; pathID < source.previousWayCoordinates; pathID++ )
|
|
pathNodes->push_back( tempNodes[pathID - 1] );
|
|
std::reverse( pathNodes->begin() + 1, pathNodes->end() );
|
|
} else {
|
|
for ( unsigned pathID = source.previousWayCoordinates; pathID < target.previousWayCoordinates; pathID++ )
|
|
pathNodes->push_back( tempNodes[pathID - 1] );
|
|
}
|
|
|
|
pathNodes->push_back( target.nearestPoint );
|
|
pathEdges->front().length = pathNodes->size() - 1;
|
|
*distance = onEdgeDistance;
|
|
}
|
|
}
|
|
}
|
|
|
|
*distance /= 10;
|
|
return true;
|
|
}
|
|
|
|
bool ContractionHierarchiesClient::GetName( QString* result, unsigned name )
|
|
{
|
|
*result = QString::fromUtf8( m_names + name );
|
|
return true;
|
|
}
|
|
|
|
bool ContractionHierarchiesClient::GetNames( QVector< QString >* result, QVector< unsigned > names )
|
|
{
|
|
result->resize( names.size() );
|
|
for ( int i = 0; i < names.size(); i++ )
|
|
( *result )[i] = QString::fromUtf8( m_names + names[i] );
|
|
return true;
|
|
}
|
|
|
|
bool ContractionHierarchiesClient::GetType( QString* result, unsigned type )
|
|
{
|
|
*result = m_types[type];
|
|
return true;
|
|
}
|
|
|
|
bool ContractionHierarchiesClient::GetTypes( QVector< QString >* result, QVector< unsigned > types )
|
|
{
|
|
result->resize( types.size() );
|
|
for ( int i = 0; i < types.size(); i++ )
|
|
( *result )[i] = m_types[types[i]];
|
|
return true;
|
|
}
|
|
|
|
template< class EdgeAllowed, class StallEdgeAllowed >
|
|
void ContractionHierarchiesClient::computeStep( Heap* heapForward, Heap* heapBackward, const EdgeAllowed& edgeAllowed, const StallEdgeAllowed& stallEdgeAllowed, NodeIterator* middle, int* targetDistance ) {
|
|
|
|
const NodeIterator node = heapForward->DeleteMin();
|
|
const int distance = heapForward->GetKey( node );
|
|
|
|
if ( heapForward->GetData( node ).stalled )
|
|
return;
|
|
|
|
if ( heapBackward->WasInserted( node ) && !heapBackward->GetData( node ).stalled ) {
|
|
const int newDistance = heapBackward->GetKey( node ) + distance;
|
|
if ( newDistance < *targetDistance ) {
|
|
*middle = node;
|
|
*targetDistance = newDistance;
|
|
}
|
|
}
|
|
|
|
if ( distance > *targetDistance ) {
|
|
heapForward->DeleteAll();
|
|
return;
|
|
}
|
|
for ( EdgeIterator edge = m_graph.edges( node ); edge.hasEdgesLeft(); ) {
|
|
m_graph.unpackNextEdge( &edge );
|
|
const NodeIterator to = edge.target();
|
|
const int edgeWeight = edge.distance();
|
|
assert( edgeWeight > 0 );
|
|
const int toDistance = distance + edgeWeight;
|
|
|
|
if ( stallEdgeAllowed( edge.forward(), edge.backward() ) && heapForward->WasInserted( to ) ) {
|
|
const int shorterDistance = heapForward->GetKey( to ) + edgeWeight;
|
|
if ( shorterDistance < distance ) {
|
|
//perform a bfs starting at node
|
|
//only insert nodes when a sub-optimal path can be proven
|
|
//insert node into the stall queue
|
|
heapForward->GetKey( node ) = shorterDistance;
|
|
heapForward->GetData( node ).stalled = true;
|
|
m_stallQueue.push( node );
|
|
|
|
while ( !m_stallQueue.empty() ) {
|
|
//get node from the queue
|
|
const NodeIterator stallNode = m_stallQueue.front();
|
|
m_stallQueue.pop();
|
|
const int stallDistance = heapForward->GetKey( stallNode );
|
|
|
|
//iterate over outgoing edges
|
|
for ( EdgeIterator stallEdge = m_graph.edges( stallNode ); stallEdge.hasEdgesLeft(); ) {
|
|
m_graph.unpackNextEdge( &stallEdge );
|
|
//is edge outgoing/reached/stalled?
|
|
if ( !edgeAllowed( stallEdge.forward(), stallEdge.backward() ) )
|
|
continue;
|
|
const NodeIterator stallTo = stallEdge.target();
|
|
if ( !heapForward->WasInserted( stallTo ) )
|
|
continue;
|
|
if ( heapForward->GetData( stallTo ).stalled == true )
|
|
continue;
|
|
|
|
const int stallToDistance = stallDistance + stallEdge.distance();
|
|
//sub-optimal path found -> insert stallTo
|
|
if ( stallToDistance < heapForward->GetKey( stallTo ) ) {
|
|
if ( heapForward->WasRemoved( stallTo ) )
|
|
heapForward->GetKey( stallTo ) = stallToDistance;
|
|
else
|
|
heapForward->DecreaseKey( stallTo, stallToDistance );
|
|
|
|
m_stallQueue.push( stallTo );
|
|
heapForward->GetData( stallTo ).stalled = true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( edgeAllowed( edge.forward(), edge.backward() ) ) {
|
|
//New Node discovered -> Add to Heap + Node Info Storage
|
|
if ( !heapForward->WasInserted( to ) )
|
|
heapForward->Insert( to, toDistance, node );
|
|
|
|
//Found a shorter Path -> Update distance
|
|
else if ( toDistance <= heapForward->GetKey( to ) ) {
|
|
heapForward->DecreaseKey( to, toDistance );
|
|
//new parent + unstall
|
|
heapForward->GetData( to ).parent = node;
|
|
heapForward->GetData( to ).stalled = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int ContractionHierarchiesClient::computeRoute( const IGPSLookup::Result& source, const IGPSLookup::Result& target, QVector< Node>* pathNodes, QVector< Edge >* pathEdges ) {
|
|
EdgeIterator sourceEdge = m_graph.findEdge( source.source, source.target, source.edgeID );
|
|
unsigned sourceWeight = sourceEdge.distance();
|
|
EdgeIterator targetEdge = m_graph.findEdge( target.source, target.target, target.edgeID );
|
|
unsigned targetWeight = targetEdge.distance();
|
|
|
|
//insert source into heap
|
|
m_heapForward->Insert( source.target, sourceWeight - sourceWeight * source.percentage, source.target );
|
|
if ( sourceEdge.backward() && sourceEdge.forward() && source.target != source.source )
|
|
m_heapForward->Insert( source.source, sourceWeight * source.percentage, source.source );
|
|
|
|
//insert target into heap
|
|
m_heapBackward->Insert( target.source, targetWeight * target.percentage, target.source );
|
|
if ( targetEdge.backward() && targetEdge.forward() && target.target != target.source )
|
|
m_heapBackward->Insert( target.target, targetWeight - targetWeight * target.percentage, target.target );
|
|
|
|
int targetDistance = std::numeric_limits< int >::max();
|
|
NodeIterator middle = ( NodeIterator ) 0;
|
|
AllowForwardEdge forward;
|
|
AllowBackwardEdge backward;
|
|
|
|
while ( m_heapForward->Size() + m_heapBackward->Size() > 0 ) {
|
|
|
|
if ( m_heapForward->Size() > 0 )
|
|
computeStep( m_heapForward, m_heapBackward, forward, backward, &middle, &targetDistance );
|
|
|
|
if ( m_heapBackward->Size() > 0 )
|
|
computeStep( m_heapBackward, m_heapForward, backward, forward, &middle, &targetDistance );
|
|
|
|
}
|
|
|
|
if ( targetDistance == std::numeric_limits< int >::max() )
|
|
return std::numeric_limits< int >::max();
|
|
|
|
std::stack< NodeIterator > stack;
|
|
NodeIterator pathNode = middle;
|
|
while ( true ) {
|
|
NodeIterator parent = m_heapForward->GetData( pathNode ).parent;
|
|
stack.push( pathNode );
|
|
if ( parent == pathNode )
|
|
break;
|
|
pathNode = parent;
|
|
}
|
|
|
|
pathNodes->push_back( source.nearestPoint );
|
|
bool reverseSourceDescription = pathNode != source.target;
|
|
if ( source.source == source.target && sourceEdge.backward() && sourceEdge.forward() && source.percentage < 0.5 )
|
|
reverseSourceDescription = !reverseSourceDescription;
|
|
if ( sourceEdge.unpacked() ) {
|
|
bool unpackSourceForward = source.target != sourceEdge.target() ? reverseSourceDescription : !reverseSourceDescription;
|
|
m_graph.path( sourceEdge, pathNodes, pathEdges, unpackSourceForward );
|
|
if ( reverseSourceDescription ) {
|
|
pathNodes->remove( 1, pathNodes->size() - 1 - source.previousWayCoordinates );
|
|
} else {
|
|
pathNodes->remove( 1, source.previousWayCoordinates - 1 );
|
|
}
|
|
} else {
|
|
pathNodes->push_back( m_graph.node( pathNode ) );
|
|
pathEdges->push_back( sourceEdge.description() );
|
|
}
|
|
pathEdges->front().length = pathNodes->size() - 1;
|
|
|
|
while ( stack.size() > 1 ) {
|
|
const NodeIterator node = stack.top();
|
|
stack.pop();
|
|
unpackEdge( node, stack.top(), true, pathNodes, pathEdges );
|
|
}
|
|
|
|
pathNode = middle;
|
|
while ( true ) {
|
|
NodeIterator parent = m_heapBackward->GetData( pathNode ).parent;
|
|
if ( parent == pathNode )
|
|
break;
|
|
unpackEdge( parent, pathNode, false, pathNodes, pathEdges );
|
|
pathNode = parent;
|
|
}
|
|
|
|
int begin = pathNodes->size();
|
|
bool reverseTargetDescription = pathNode != target.source;
|
|
if ( target.source == target.target && targetEdge.backward() && targetEdge.forward() && target.percentage > 0.5 )
|
|
reverseSourceDescription = !reverseSourceDescription;
|
|
if ( targetEdge.unpacked() ) {
|
|
bool unpackTargetForward = target.target != targetEdge.target() ? reverseTargetDescription : !reverseTargetDescription;
|
|
m_graph.path( targetEdge, pathNodes, pathEdges, unpackTargetForward );
|
|
if ( reverseTargetDescription ) {
|
|
pathNodes->resize( pathNodes->size() - target.previousWayCoordinates );
|
|
} else {
|
|
pathNodes->resize( begin + target.previousWayCoordinates - 1 );
|
|
}
|
|
} else {
|
|
pathEdges->push_back( targetEdge.description() );
|
|
}
|
|
pathNodes->push_back( target.nearestPoint );
|
|
pathEdges->back().length = pathNodes->size() - begin;
|
|
|
|
return targetDistance;
|
|
}
|
|
|
|
bool ContractionHierarchiesClient::unpackEdge( const NodeIterator source, const NodeIterator target, bool forward, QVector< Node >* pathNodes, QVector< Edge >* pathEdges ) {
|
|
EdgeIterator shortestEdge;
|
|
|
|
unsigned distance = std::numeric_limits< unsigned >::max();
|
|
for ( EdgeIterator edge = m_graph.edges( source ); edge.hasEdgesLeft(); ) {
|
|
m_graph.unpackNextEdge( &edge );
|
|
if ( edge.target() != target )
|
|
continue;
|
|
if ( forward && !edge.forward() )
|
|
continue;
|
|
if ( !forward && !edge.backward() )
|
|
continue;
|
|
if ( edge.distance() > distance )
|
|
continue;
|
|
distance = edge.distance();
|
|
shortestEdge = edge;
|
|
}
|
|
|
|
if ( shortestEdge.unpacked() ) {
|
|
m_graph.path( shortestEdge, pathNodes, pathEdges, forward );
|
|
return true;
|
|
}
|
|
|
|
if ( !shortestEdge.shortcut() ) {
|
|
pathEdges->push_back( shortestEdge.description() );
|
|
if ( forward )
|
|
pathNodes->push_back( m_graph.node( target ).coordinate );
|
|
else
|
|
pathNodes->push_back( m_graph.node( source ).coordinate );
|
|
return true;
|
|
}
|
|
|
|
const NodeIterator middle = shortestEdge.middle();
|
|
|
|
if ( forward ) {
|
|
unpackEdge( middle, source, false, pathNodes, pathEdges );
|
|
unpackEdge( middle, target, true, pathNodes, pathEdges );
|
|
return true;
|
|
} else {
|
|
unpackEdge( middle, target, false, pathNodes, pathEdges );
|
|
unpackEdge( middle, source, true, pathNodes, pathEdges );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Q_EXPORT_PLUGIN2( contractionhierarchiesclient, ContractionHierarchiesClient )
|
|
|