Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions functions/CostBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@ class CostBase(FunctionBase):
def __init__(self, ui):
FunctionBase.__init__(self, ui)

@classmethod
def isSupportedVersion(self, version):
''' Checks supported version '''
# valid starting pgr v2.1
return version >= 2.1

@classmethod
def canExportMerged(self):
return False
Expand Down Expand Up @@ -67,12 +61,32 @@ def getExportQuery(self, args):

return sql.SQL("""
WITH
result AS ( {result_query} )
SELECT result.*, ST_MakeLine(a.the_geom, b.the_geom) AS path_geom
result AS ( {result_query} ),
departure AS (
SELECT start_vid, end_vid, ST_startPoint(geom) AS depart
FROM result JOIN {edge_table} ON ({edge_table}.{source} = start_vid)

UNION

SELECT start_vid, end_vid, ST_endPoint(geom)
FROM result JOIN {edge_table} ON ({edge_table}.{target} = start_vid)
),

destination AS (
SELECT start_vid, end_vid, ST_startPoint(geom) AS arrive
FROM result JOIN {edge_table} ON ({edge_table}.{source} = end_vid)

UNION

SELECT start_vid, end_vid, ST_endPoint(geom)
FROM result JOIN {edge_table} ON ({edge_table}.{target} = end_vid)
)

SELECT result.*, ST_MakeLine(depart, arrive) AS path_geom

FROM result
JOIN {vertex_schema}.{vertex_table} AS a ON (start_vid = a.id)
JOIN {vertex_schema}.{vertex_table} AS b ON (end_vid = b.id)
JOIN departure USING (start_vid, end_vid)
JOIN destination USING (start_vid, end_vid)
""").format(**args)

def draw(self, rows, con, args, geomType, canvasItemList, mapCanvas):
Expand Down
11 changes: 5 additions & 6 deletions functions/DijkstraBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,12 @@ def prepare(self, canvasItemList):
@classmethod
def getQuery(self, args):
''' returns the sql query in required signature format of pgr_dijkstra '''
return sql.SQL("""
SELECT seq, '(' || start_vid || ',' || end_vid || ')' AS path_name,
return sql.SQL("""SELECT seq,
'(' || start_vid || ',' || end_vid || ')' AS path_name,
path_seq AS _path_seq, start_vid AS _start_vid, end_vid AS _end_vid,
node AS _node, edge AS _edge, cost AS _cost, lead(agg_cost) over() AS _agg_cost
FROM {function}('
{innerQuery}
',
node AS _node, edge AS _edge,
cost AS _cost, agg_cost AS _agg_cost
FROM {function}('{innerQuery}',
{source_ids}, {target_ids}, {directed})
""").format(**args)

Expand Down
107 changes: 33 additions & 74 deletions functions/FunctionBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@
from psycopg2 import sql

from pgRoutingLayer import pgRoutingLayer_utils as Utils
from pgRoutingLayer.utilities import pgr_queries as PgrQ


class FunctionBase(object):

minPGRversion = 2.1
minPGRversion = 3.0

# the mayority of the functions have this values
exportButton = True
Expand Down Expand Up @@ -239,47 +240,21 @@ def drawManyPaths(self, rows, columns, con, args, geomType, canvasItemList, mapC
resultPathsRubberBands.append(rubberBand)
rubberBand = None

@classmethod
def drawOnePath(self, rows, con, args, geomType, canvasItemList, mapCanvas):
''' draws line string on the mapCanvas. '''
resultPathRubberBand = canvasItemList['path']
for row in rows:
cur2 = con.cursor()
args['result_node_id'] = sql.Literal(row[1])
args['result_edge_id'] = sql.Literal(row[2])
args['result_cost'] = row[3]
if row[2] != -1:
query2 = sql.SQL("""
SELECT ST_AsText({geom_t} FROM {edge_schema}.{edge_table}
WHERE {source} = {result_node_id} AND {id} = {result_edge_id}
UNION
SELECT ST_AsText(ST_Reverse({geom_t}) FROM {edge_schema}.{edge_table}
WHERE {target} = {result_node_id} AND {id} = {result_edge_id};
""").format(**args)

cur2.execute(query2)
row2 = cur2.fetchone()

geom = QgsGeometry().fromWkt(str(row2[0]))
if geom.wkbType() == QgsWkbTypes.MultiLineString:
for line in geom.asMultiPolyline():
for pt in line:
resultPathRubberBand.addPoint(pt)
elif geom.wkbType() == QgsWkbTypes.LineString:
for pt in geom.asPolyline():
resultPathRubberBand.addPoint(pt)

@classmethod
def drawCostPaths(self, rows, con, args, geomType, canvasItemList, mapCanvas):
resultPathsRubberBands = canvasItemList['paths']
rubberBand = None
cur_path_id = -1
resultNodesTextAnnotations = canvasItemList['annotations']
for row in rows:
cur2 = con.cursor()
cursor = con.cursor()
midPointCursor = con.cursor()
args['result_path_id'] = row[0]
args['result_source_id'] = sql.Literal(row[1])
args['result_target_id'] = sql.Literal(row[2])
args['result_cost'] = row[3]
args['result_path_name'] = row[4]

if args['result_path_id'] != cur_path_id:
cur_path_id = args['result_path_id']
if rubberBand:
Expand All @@ -290,18 +265,14 @@ def drawCostPaths(self, rows, con, args, geomType, canvasItemList, mapCanvas):
rubberBand.setColor(QColor(255, 0, 0, 128))
rubberBand.setWidth(4)
if args['result_cost'] != -1:
query2 = sql.SQL("""
SELECT ST_AsText( ST_MakeLine(
(SELECT {geometry_vt} FROM {vertex_schema}.{vertex_table} WHERE id = {result_source_id}),
(SELECT {geometry_vt} FROM {vertex_schema}.{vertex_table} WHERE id = {result_target_id})
))
""").format(**args)
# Utils.logMessage(query2)
cur2.execute(query2)
row2 = cur2.fetchone()
# Utils.logMessage(str(row2[0]))

geom = QgsGeometry().fromWkt(str(row2[0]))
costLine = PgrQ.getCostLine(args, sql.Literal(row[1]), sql.Literal(row[2]))
# Utils.logMessage(costLine.as_string(cursor))
cursor.execute(costLine)
row2 = cursor.fetchone()
line = str(row2[0])
# Utils.logMessage(line)

geom = QgsGeometry().fromWkt(line)
if geom.wkbType() == QgsWkbTypes.MultiLineString:
for line in geom.asMultiPolyline():
for pt in line:
Expand All @@ -310,36 +281,24 @@ def drawCostPaths(self, rows, con, args, geomType, canvasItemList, mapCanvas):
for pt in geom.asPolyline():
rubberBand.addPoint(pt)

# TODO label the edge instead of labeling the target points
# Label the edge
midPoint = PgrQ.getMidPoint()
midPointstr = midPoint.as_string(con)
midPointCursor.execute(midPoint,(line,))
pointRow = midPointCursor.fetchone()
# Utils.logMessage("The point:" + str(pointRow[0]))

ptgeom = QgsGeometry().fromWkt(str(pointRow[0]))
pt = ptgeom.asPoint()
textDocument = QTextDocument("{0!s}:{1}".format(args['result_path_name'], args['result_cost']))
textAnnotation = QgsTextAnnotation()
textAnnotation.setMapPosition(pt)
textAnnotation.setFrameSizeMm(QSizeF(20, 5))
textAnnotation.setFrameOffsetFromReferencePointMm(QPointF(5, -5))
textAnnotation.setDocument(textDocument)
QgsMapCanvasAnnotationItem(textAnnotation, mapCanvas)
resultNodesTextAnnotations.append(textAnnotation)

if rubberBand:
resultPathsRubberBands.append(rubberBand)
rubberBand = None
resultNodesTextAnnotations = canvasItemList['annotations']
for row in rows:
cur2 = con.cursor()
args['result_seq'] = row[0]
args['result_source_id'] = sql.Literal(row[1])
result_target_id = row[2]
args['result_target_id'] = sql.Literal(result_target_id)
result_cost = row[3]
query2 = sql.SQL("""
SELECT ST_AsText( ST_startPoint({geometry}) ) FROM {edge_schema}.{edge_table}
WHERE {source} = {result_target_id}
UNION
SELECT ST_AsText( ST_endPoint( {geometry} ) ) FROM {edge_schema}.{edge_table}
WHERE {target} = {result_target_id}
""").format(**args)
cur2.execute(query2)
row2 = cur2.fetchone()

geom = QgsGeometry().fromWkt(str(row2[0]))
pt = geom.asPoint()
textDocument = QTextDocument("{0!s}:{1}".format(result_target_id, result_cost))
textAnnotation = QgsTextAnnotation()
textAnnotation.setMapPosition(geom.asPoint())
textAnnotation.setFrameSize(QSizeF(textDocument.idealWidth(), 20))
textAnnotation.setFrameOffsetFromReferencePoint(QPointF(20, -40))
textAnnotation.setDocument(textDocument)

QgsMapCanvasAnnotationItem(textAnnotation, mapCanvas)
resultNodesTextAnnotations.append(textAnnotation)
61 changes: 18 additions & 43 deletions functions/pgr_KSP.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,16 @@

class Function(FunctionBase):

minPGRversion = 2.1
minPGRversion = 3.6

def __init__(self, ui):
FunctionBase.__init__(self, ui)

@classmethod
def isSupportedVersion(self, version):
''' Checks supported version '''
return version >= 3.6

@classmethod
def getName(self):
''' returns Function name. '''
Expand All @@ -45,59 +50,29 @@ def getName(self):
def getControlNames(self, version):
''' returns control names. '''
return self.commonControls + self.commonBoxes + [
'labelSourceId', 'lineEditSourceId', 'buttonSelectSourceId',
'labelTargetId', 'lineEditTargetId', 'buttonSelectTargetId',
'labelSourceIds', 'lineEditSourceIds', 'buttonSelectSourceIds',
'labelTargetIds', 'lineEditTargetIds', 'buttonSelectTargetIds',
'labelPaths', 'lineEditPaths', 'checkBoxHeapPaths']

def getQuery(self, args):
''' returns the sql query in required signature format of pgr_KSP '''
return sql.SQL("""
SELECT seq,
'(' || {source_id} || ', ' || {target_id} || ')-' || path_id AS path_name,
path_id AS _path_id,
path_seq AS _path_seq,
node AS _node,
edge AS _edge,
cost AS _cost
FROM pgr_KSP(' {innerQuery} ',
{source_id}, {target_id}, {Kpaths}, {directed}, {heap_paths})
return sql.SQL("""SELECT seq,
'(' || start_vid || ',' || end_vid || ')-' || path_id AS path_name,
path_seq AS _path_seq, start_vid AS _start_vid, end_vid AS _end_vid,
node AS _node, edge AS _edge,
path_id AS _path_id,
cost AS _cost, agg_cost AS _agg_cost
FROM pgr_KSP('{innerQuery}',
{source_ids}, {target_ids}, {Kpaths}, {directed}, {heap_paths})
""").format(**args)

def getExportQuery(self, args):
return self.getJoinResultWithEdgeTable(args)

def getExportMergeQuery(self, args):
args['result_query'] = self.getQuery(args)
return sql.SQL("""WITH
result AS ( {result_query} ),
with_geom AS (
SELECT seq, result.path_name,
CASE
WHEN result._node = et.{source}
THEN et.{geometry}
ELSE ST_Reverse(et.{geometry})
END AS path_geom
FROM {edge_schema}.{edge_table} AS et JOIN result ON et.{id} = result._edge
),
one_geom AS (
SELECT path_name, ST_LineMerge(ST_Union(path_geom)) AS path_geom
FROM with_geom GROUP BY path_name ORDER BY path_name
),
aggregates AS (
SELECT
path_name, _path_id,
SUM(_cost) AS agg_cost,
array_agg(_node ORDER BY _path_seq) AS _nodes,
array_agg(_edge ORDER BY _path_seq) AS _edges
FROM result
GROUP BY path_name, _path_id
)
SELECT row_number() over() as seq,
_path_id, path_name, _nodes, _edges, agg_cost, path_geom
FROM aggregates JOIN one_geom USING (path_name) ORDER BY _path_id
""").format(**args)
return self.getExportManySourceManyTargetMergeQuery(args)

def draw(self, rows, con, args, geomType, canvasItemList, mapCanvas):
''' draw the result '''
columns = [2, 4, 5]
columns = [2, 5, 6]
self.drawManyPaths(rows, columns, con, args, geomType, canvasItemList, mapCanvas)
10 changes: 4 additions & 6 deletions help/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
#
# PhotoLinker documentation build configuration file, created by
# sphinx-quickstart on Sun Feb 12 17:11:03 2012.
#
# pgRoutingLayer documentation build configuration file, created by
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
Expand All @@ -25,7 +23,7 @@

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.todo', 'sphinx.ext.imgmath', 'sphinx.ext.viewcode']
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.imgmath', 'sphinx.ext.viewcode']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Expand All @@ -48,9 +46,9 @@
# built documents.
#
# The short X.Y version.
version = '3.0'
version = '4.0'
# The full version, including alpha/beta/rc tags.
release = '3.0'
release = '4.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
5 changes: 2 additions & 3 deletions help/source/index.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
.. PhotoLinker documentation master file, created by
sphinx-quickstart on Sun Feb 12 17:11:03 2012.
.. pgRoutingLayer documentation master file, created by
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.

Welcome to PhotoLinker's documentation!
Welcome to pgRoutingLayer's documentation!
============================================

Contents:
Expand Down
10 changes: 7 additions & 3 deletions metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ about=Dockable widget that adds pgRouting layers
- pgr_bdDijstra pgr_bdDijstraCost
- pgr_KSP
version=3.0.2
qgisMinimumVersion=3.0
qgisMinimumVersion=3.10
qgisMaximumVersion=3.99
author=Anita Graser, Ko Nagase, Vicky Vergara, Cayetano Benavent, Aasheesh Tiwari
[email protected]
changelog=3.0.2
changelog=4.0.0
- Works best for pgRouting 4.0.0
- No longer Support of QGIS < 3.10
- Using PyQt5
3.0.1
- Support for QGIS >= 3.24.
- Fixed non-existence database error issue.
3.0.1
Expand All @@ -25,7 +29,7 @@ changelog=3.0.2
- Last experimental release works only for QGIS 2.x
tags=pgRouting,PostGIS,routing,network analysis
icon=icon.png
experimental=False
experimental=True
homepage=https://qgis.pgrouting.org/
tracker=https://github.com/pgRouting/pgRoutingLayer/issues
repository=https://github.com/pgRouting/pgRoutingLayer
Expand Down
11 changes: 0 additions & 11 deletions pb_tool.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[plugin]
# Name of the plugin. This is the name of the directory that will
# be created in .qgis2/python/plugins
name: pgRoutingLayer

# Full path to where you want your plugin directory copied. If empty,
Expand Down Expand Up @@ -30,13 +29,3 @@ extras: metadata.txt icon.png
# Other directories to be deployed with the plugin.
# These must be subdirectories under the plugin directory
extra_dirs: functions connectors utilities icons

# ISO code(s) for any locales (translations), separated by spaces.
# Corresponding .ts files must exist in the i18n directory
locales:

[help]
# the built help directory that should be deployed with the plugin
dir: help/build/html
# the name of the directory to target in the deployed plugin
target: help
Loading