Skip to content

Commit

Permalink
Merge pull request #5488 from nyalldawson/network
Browse files Browse the repository at this point in the history
[processing] Fix some issues with network analysis shortest path algs
  • Loading branch information
nyalldawson committed Oct 31, 2017
2 parents 9a1cd9d + 05ad0bc commit 5000f9a
Show file tree
Hide file tree
Showing 43 changed files with 1,189 additions and 374 deletions.
28 changes: 28 additions & 0 deletions doc/api_break.dox
Expand Up @@ -1379,13 +1379,34 @@ QgsGraduatedSymbolRenderer {#qgis_api_break_3_0_QgsGraduatedSymbolRendere
- sizeScaleFieldChanged() and scaleMethodChanged() were removed. These settings are no longer exposed in the widget's GUI.


QgsGraph {#qgis_api_break_3_0_QgsGraph}
--------

- addEdge now explicitly takes the fromVertex as first argument, and toVertex as second argument. The original
API design was unclear due to the reversed methods in QgsGraphEdge and QgsGraphVertex.


QgsGraphBuilderInterface {#qgis_api_break_3_0_QgsGraphBuilderInterface}
------------------------

- destinationCrs() now returns a copy instead of a reference to the CRS. This has no effect on PyQGIS code, but c++
plugins calling this method will need to be updated.


QgsGraphEdge {#qgis_api_break_3_0_QgsGraphEdge}
------------

- outVertex() was renamed as toVertex() (yes, the original name was the opposite of the returned value!)
- inVertex() was renamed as fromVertex() (yes, the original name was the opposite of the returned value!)


QgsGraphVertex {#qgis_api_break_3_0_QgsGraphVertex}
--------------

- outEdges() was renamed as incomingEdges() (yes, the original name was the opposite of the returned value!)
- inEdges() was renamed as outgoingEdges() (yes, the original name was the opposite of the returned value!)


QgsEditorWidgetRegistry {#qgis_api_break_3_0_QgsEditorWidgetRegistry}
-----------------------

Expand Down Expand Up @@ -1777,6 +1798,13 @@ QgsNetworkAccessManager {#qgis_api_break_3_0_QgsNetworkAccessManager}
- deleteReply() was removed. Use abort() and deleteLayer() on the reply directly.
- requestSent signal was removed. This is no longer emitted.


QgsNetworkStrategy {#qgis_api_break_3_0_QgsNetworkStrategy}
------------------

- requiredAttributes() now returns a set of attributes, instead of a list


QgsNewVectorLayerDialog {#qgis_api_break_3_0_QgsNewVectorLayerDialog}
-----------------------

Expand Down
29 changes: 18 additions & 11 deletions python/analysis/network/qgsgraph.sip
Expand Up @@ -41,15 +41,17 @@ class QgsGraphEdge
:rtype: list of QVariant
%End

int outVertex() const;
int toVertex() const;
%Docstring
Returns index of the outgoing vertex
Returns the index of the vertex at the end of this edge.
.. seealso:: fromVertex()
:rtype: int
%End

int inVertex() const;
int fromVertex() const;
%Docstring
Returns index of the incoming vertex
Returns the index of the vertex at the start of this edge.
.. seealso:: toVertex()
:rtype: int
%End

Expand All @@ -62,6 +64,7 @@ class QgsGraphVertex
{
%Docstring
This class implements a graph vertex
.. versionadded:: 3.0
%End

%TypeHeaderCode
Expand All @@ -80,21 +83,23 @@ class QgsGraphVertex
This constructor initializes QgsGraphVertex object and associates a vertex with a point
%End

QgsGraphEdgeIds outEdges() const;
QgsGraphEdgeIds incomingEdges() const;
%Docstring
Returns outgoing edges ids
Returns the incoming edge ids, i.e. edges which end at this node.
.. seealso:: outgoingEdges()
:rtype: QgsGraphEdgeIds
%End

QgsGraphEdgeIds inEdges() const;
QgsGraphEdgeIds outgoingEdges() const;
%Docstring
Return incoming edges ids
Returns outgoing edge ids, i.e. edges which start at this node.
.. seealso:: incomingEdges()
:rtype: QgsGraphEdgeIds
%End

QgsPointXY point() const;
%Docstring
Returns point associated with graph vertex
Returns point associated with graph vertex.
:rtype: QgsPointXY
%End

Expand All @@ -105,6 +110,7 @@ class QgsGraph
{
%Docstring
Mathematical graph representation
.. versionadded:: 3.0
%End

%TypeHeaderCode
Expand All @@ -124,9 +130,10 @@ class QgsGraph
:rtype: int
%End

int addEdge( int outVertexIdx, int inVertexIdx, const QVector< QVariant > &strategies );
int addEdge( int fromVertexIdx, int toVertexIdx, const QVector< QVariant > &strategies );
%Docstring
Add an edge to the graph
Add an edge to the graph, going from the ``fromVertexIdx``
to ``toVertexIdx``.
:rtype: int
%End

Expand Down
2 changes: 2 additions & 0 deletions python/analysis/network/qgsgraphbuilder.sip
Expand Up @@ -30,12 +30,14 @@ class QgsGraphBuilder : QgsGraphBuilderInterface
~QgsGraphBuilder();

virtual void addVertex( int id, const QgsPointXY &pt );

%Docstring
MANDATORY BUILDER PROPERTY DECLARATION
%End

virtual void addEdge( int pt1id, const QgsPointXY &pt1, int pt2id, const QgsPointXY &pt2, const QVector< QVariant > &prop );


QgsGraph *graph() /Factory/;
%Docstring
Returns generated QgsGraph
Expand Down
12 changes: 1 addition & 11 deletions python/analysis/network/qgsnetworkspeedstrategy.sip
Expand Up @@ -28,18 +28,8 @@ class QgsNetworkSpeedStrategy : QgsNetworkStrategy

virtual QVariant cost( double distance, const QgsFeature &f ) const;

%Docstring
Returns edge cost
:rtype: QVariant
%End

virtual QgsAttributeList requiredAttributes() const;
virtual QSet< int > requiredAttributes() const;

%Docstring
Returns list of the source layer attributes needed for cost calculation.
This method called by QgsGraphDirector.
:rtype: QgsAttributeList
%End

};

Expand Down
9 changes: 4 additions & 5 deletions python/analysis/network/qgsnetworkstrategy.sip
Expand Up @@ -45,12 +45,11 @@ class QgsNetworkStrategy

virtual ~QgsNetworkStrategy();

virtual QgsAttributeList requiredAttributes() const;
virtual QSet< int > requiredAttributes() const;
%Docstring
Returns list of the source layer attributes needed for cost calculation.
This method called by QgsGraphDirector.
:return: list of required attributes
:rtype: QgsAttributeList
Returns a list of the source layer attributes needed for cost calculation.
This is method called by QgsGraphDirector.
:rtype: set of int
%End

virtual QVariant cost( double distance, const QgsFeature &f ) const = 0;
Expand Down
35 changes: 23 additions & 12 deletions python/plugins/processing/algs/qgis/ServiceAreaFromLayer.py
Expand Up @@ -38,6 +38,7 @@
QgsFeatureRequest,
QgsGeometry,
QgsFields,
QgsPointXY,
QgsField,
QgsProcessing,
QgsProcessingParameterEnum,
Expand Down Expand Up @@ -88,8 +89,8 @@ def __init__(self):
def initAlgorithm(self, config=None):
self.DIRECTIONS = OrderedDict([
(self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward),
(self.tr('Backward direction'), QgsVectorLayerDirector.DirectionForward),
(self.tr('Both directions'), QgsVectorLayerDirector.DirectionForward)])
(self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward),
(self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)])

self.STRATEGIES = [self.tr('Shortest'),
self.tr('Fastest')
Expand Down Expand Up @@ -172,7 +173,7 @@ def processAlgorithm(self, parameters, context, feedback):
defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

fields = QgsFields()
fields = startPoints.fields()
fields.append(QgsField('type', QVariant.String, '', 254, 0))
fields.append(QgsField('start', QVariant.String, '', 254, 0))

Expand Down Expand Up @@ -209,17 +210,25 @@ def processAlgorithm(self, parameters, context, feedback):

feedback.pushInfo(self.tr('Loading start points...'))
request = QgsFeatureRequest()
request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes)
request.setDestinationCrs(network.sourceCrs())
features = startPoints.getFeatures(request)
total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0

points = []
source_attributes = {}
i = 0
for current, f in enumerate(features):
if feedback.isCanceled():
break

points.append(f.geometry().asPoint())
if not f.hasGeometry():
continue

for p in f.geometry().vertices():
points.append(QgsPointXY(p))
source_attributes[i] = f.attributes()
i += 1

feedback.setProgress(int(current * total))

feedback.pushInfo(self.tr('Building graph...'))
Expand All @@ -245,25 +254,27 @@ def processAlgorithm(self, parameters, context, feedback):
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
for j, v in enumerate(cost):
if v > travelCost and tree[j] != -1:
vertexId = graph.edge(tree[j]).outVertex()
vertexId = graph.edge(tree[j]).fromVertex()
if cost[vertexId] <= travelCost:
vertices.append(j)

for j in vertices:
upperBoundary.append(graph.vertex(graph.edge(tree[j]).inVertex()).point())
lowerBoundary.append(graph.vertex(graph.edge(tree[j]).outVertex()).point())
upperBoundary.append(graph.vertex(graph.edge(tree[j]).toVertex()).point())
lowerBoundary.append(graph.vertex(graph.edge(tree[j]).fromVertex()).point())

geomUpper = QgsGeometry.fromMultiPointXY(upperBoundary)
geomLower = QgsGeometry.fromMultiPointXY(lowerBoundary)

feat.setGeometry(geomUpper)
feat['type'] = 'upper'
feat['start'] = origPoint

attrs = source_attributes[i]
attrs.extend(['upper', origPoint])
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)

feat.setGeometry(geomLower)
feat['type'] = 'lower'
feat['start'] = origPoint
attrs[-2] = 'lower'
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)

vertices[:] = []
Expand Down
10 changes: 5 additions & 5 deletions python/plugins/processing/algs/qgis/ServiceAreaFromPoint.py
Expand Up @@ -87,8 +87,8 @@ def __init__(self):
def initAlgorithm(self, config=None):
self.DIRECTIONS = OrderedDict([
(self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward),
(self.tr('Backward direction'), QgsVectorLayerDirector.DirectionForward),
(self.tr('Both directions'), QgsVectorLayerDirector.DirectionForward)])
(self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward),
(self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)])

self.STRATEGIES = [self.tr('Shortest'),
self.tr('Fastest')
Expand Down Expand Up @@ -208,15 +208,15 @@ def processAlgorithm(self, parameters, context, feedback):
vertices = []
for i, v in enumerate(cost):
if v > travelCost and tree[i] != -1:
vertexId = graph.edge(tree[i]).outVertex()
vertexId = graph.edge(tree[i]).fromVertex()
if cost[vertexId] <= travelCost:
vertices.append(i)

upperBoundary = []
lowerBoundary = []
for i in vertices:
upperBoundary.append(graph.vertex(graph.edge(tree[i]).inVertex()).point())
lowerBoundary.append(graph.vertex(graph.edge(tree[i]).outVertex()).point())
upperBoundary.append(graph.vertex(graph.edge(tree[i]).toVertex()).point())
lowerBoundary.append(graph.vertex(graph.edge(tree[i]).fromVertex()).point())

feedback.pushInfo(self.tr('Writing results...'))

Expand Down

0 comments on commit 5000f9a

Please sign in to comment.