Skip to content
Permalink
Browse files
Add API to remove vertices or edges from QgsGraph
Useful when you've built a graph and want to perform multiple
different analysis on it after excluding routes without
having to rebuild the whole graph again

Eg. find the shortest path between two vertices, then remove all
these edge from this path and repeat to try to find the second-shortest
path which doesn't use any of the same edges from the shortest
path
  • Loading branch information
nyalldawson committed Nov 9, 2021
1 parent 9b02c30 commit c0b253a69bfc465ca3aa565b2b362a7a100884dd
Showing with 357 additions and 0 deletions.
  1. +51 −0 python/analysis/auto_generated/network/qgsgraph.sip.in
  2. +47 −0 src/analysis/network/qgsgraph.cpp
  3. +74 −0 src/analysis/network/qgsgraph.h
  4. +185 −0 tests/src/python/test_qgsgraph.py
@@ -161,6 +161,30 @@ Returns the vertex at the given index.
}
%End


void removeVertex( int index ) const;
%Docstring
Removes the vertex at specified ``index``.

All edges which are incoming or outgoing edges for the vertex will also be removed.

:raises IndexError: if the vertex is not found.

.. versionadded:: 3.24
%End
%MethodCode
auto it = sipCpp->mGraphVertices.constFind( a0 );
if ( it != sipCpp->mGraphVertices.constEnd() )
{
sipCpp->removeVertex( a0 );
}
else
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
%End

int edgeCount() const;
%Docstring
Returns number of graph edges
@@ -186,6 +210,33 @@ Returns the edge at the given index.
}
%End



void removeEdge( int index ) const;
%Docstring
Removes the edge at specified ``index``.

The incoming and outgoing edges for all graph vertices will be updated accordingly. Vertices which
no longer have any incoming or outgoing edges as a result will be removed from the graph automatically.

:raises IndexError: if the vertex is not found.

.. versionadded:: 3.24
%End
%MethodCode
auto it = sipCpp->mGraphEdges.constFind( a0 );
if ( it != sipCpp->mGraphEdges.constEnd() )
{
sipCpp->removeEdge( a0 );
}
else
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
%End


int findVertex( const QgsPointXY &pt ) const;
%Docstring
Find vertex by associated point
@@ -19,6 +19,7 @@
*/

#include "qgsgraph.h"
#include <QSet>

int QgsGraph::addVertex( const QgsPointXY &pt )
{
@@ -51,6 +52,24 @@ const QgsGraphVertex &QgsGraph::vertex( int idx ) const
Q_ASSERT_X( false, "QgsGraph::vertex()", "Invalid vertex ID" );
}

void QgsGraph::removeVertex( int index )
{
auto it = mGraphVertices.constFind( index );
if ( it != mGraphVertices.constEnd() )
{
QSet< int > affectedEdges = qgis::listToSet( it->incomingEdges() );
affectedEdges.unite( qgis::listToSet( it->outgoingEdges() ) );

mGraphVertices.erase( it );

// remove affected edges
for ( int edgeId : std::as_const( affectedEdges ) )
{
mGraphEdges.remove( edgeId );
}
}
}

const QgsGraphEdge &QgsGraph::edge( int idx ) const
{
auto it = mGraphEdges.constFind( idx );
@@ -59,6 +78,34 @@ const QgsGraphEdge &QgsGraph::edge( int idx ) const
Q_ASSERT_X( false, "QgsGraph::edge()", "Invalid edge ID" );
}

void QgsGraph::removeEdge( int index )
{
auto it = mGraphEdges.constFind( index );
if ( it != mGraphEdges.constEnd() )
{
const int fromVertex = it->fromVertex();
const int toVertex = it->toVertex();
mGraphEdges.erase( it );

// clean up affected vertices
auto vertexIt = mGraphVertices.find( fromVertex );
if ( vertexIt != mGraphVertices.end() )
{
vertexIt->mOutgoingEdges.removeAll( index );
if ( vertexIt->mOutgoingEdges.empty() && vertexIt->mIncomingEdges.empty() )
mGraphVertices.erase( vertexIt );
}

vertexIt = mGraphVertices.find( toVertex );
if ( vertexIt != mGraphVertices.end() )
{
vertexIt->mIncomingEdges.removeAll( index );
if ( vertexIt->mOutgoingEdges.empty() && vertexIt->mIncomingEdges.empty() )
mGraphVertices.erase( vertexIt );
}
}
}

int QgsGraph::vertexCount() const
{
return mGraphVertices.size();
@@ -193,6 +193,41 @@ class ANALYSIS_EXPORT QgsGraph
% End
#endif

#ifndef SIP_RUN

/**
* Removes the vertex at specified \a index.
*
* All edges which are incoming or outgoing edges for the vertex will also be removed.
*
* \since QGIS 3.24
*/
void removeVertex( int index );
#else

/**
* Removes the vertex at specified \a index.
*
* All edges which are incoming or outgoing edges for the vertex will also be removed.
*
* \throws IndexError if the vertex is not found.
* \since QGIS 3.24
*/
void removeVertex( int index ) const;
% MethodCode
auto it = sipCpp->mGraphVertices.constFind( a0 );
if ( it != sipCpp->mGraphVertices.constEnd() )
{
sipCpp->removeVertex( a0 );
}
else
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
% End
#endif

/**
* Returns number of graph edges
*/
@@ -226,6 +261,45 @@ class ANALYSIS_EXPORT QgsGraph
% End
#endif


#ifndef SIP_RUN

/**
* Removes the edge at specified \a index.
*
* The incoming and outgoing edges for all graph vertices will be updated accordingly. Vertices which
* no longer have any incoming or outgoing edges as a result will be removed from the graph automatically.
*
* \since QGIS 3.24
*/
void removeEdge( int index );
#else

/**
* Removes the edge at specified \a index.
*
* The incoming and outgoing edges for all graph vertices will be updated accordingly. Vertices which
* no longer have any incoming or outgoing edges as a result will be removed from the graph automatically.
*
* \throws IndexError if the vertex is not found.
* \since QGIS 3.24
*/
void removeEdge( int index ) const;
% MethodCode
auto it = sipCpp->mGraphEdges.constFind( a0 );
if ( it != sipCpp->mGraphEdges.constEnd() )
{
sipCpp->removeEdge( a0 );
}
else
{
PyErr_SetString( PyExc_IndexError, QByteArray::number( a0 ) );
sipIsErr = 1;
}
% End
#endif


/**
* Find vertex by associated point
* \returns vertex index
Loading

0 comments on commit c0b253a

Please sign in to comment.