Merge pull request #7505 from alexbruy/network-analysis

[processing] port shortest path algs to C++
This commit is contained in:
Alexander Bruy 2018-08-01 13:40:31 +03:00 committed by GitHub
commit bbc33309a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1646 additions and 856 deletions

View File

@ -98,6 +98,7 @@
<file>themes/default/algorithms/mAlgorithmMergeLayers.svg</file>
<file>themes/default/algorithms/mAlgorithmMultiToSingle.svg</file>
<file>themes/default/algorithms/mAlgorithmNearestNeighbour.svg</file>
<file>themes/default/algorithms/mAlgorithmNetworkAnalysis.svg</file>
<file>themes/default/algorithms/mAlgorithmPolygonToLine.svg</file>
<file>themes/default/algorithms/mAlgorithmRandomPointsWithinPolygon.svg</file>
<file>themes/default/algorithms/mAlgorithmRandomPointsWithinExtent.svg</file>

View File

@ -0,0 +1,798 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg5692"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="road-fast.svg"
inkscape:export-filename="/mnt/home1/robert/svn/graphics/trunk/toolbar-icons/24x24/road-fast.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
style="display:inline">
<title
id="title3609">Fast road</title>
<defs
id="defs5694">
<linearGradient
inkscape:collect="always"
id="linearGradient3718">
<stop
style="stop-color:#9a9c96;stop-opacity:1"
offset="0"
id="stop3720" />
<stop
style="stop-color:#d8d9d7;stop-opacity:1"
offset="1"
id="stop3722" />
</linearGradient>
<linearGradient
id="linearGradient3710">
<stop
style="stop-color:#9a9c96;stop-opacity:1;"
offset="0"
id="stop3712" />
<stop
style="stop-color:#eff0ef;stop-opacity:1;"
offset="1"
id="stop3714" />
</linearGradient>
<linearGradient
id="linearGradient3696">
<stop
id="stop3698"
offset="0"
style="stop-color:#ff0000;stop-opacity:1;" />
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0.5"
id="stop3702" />
<stop
id="stop3700"
offset="1"
style="stop-color:#ffffff;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3688">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3690" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3692" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2937">
<stop
style="stop-color:#ce5c00;stop-opacity:1;"
offset="0"
id="stop2939" />
<stop
style="stop-color:#ce5c00;stop-opacity:0;"
offset="1"
id="stop2941" />
</linearGradient>
<linearGradient
id="linearGradient7624">
<stop
style="stop-color:#555753;stop-opacity:1;"
offset="0"
id="stop7626" />
<stop
id="stop7634"
offset="0.40000001"
style="stop-color:#555753;stop-opacity:0.39215687;" />
<stop
style="stop-color:#555753;stop-opacity:0;"
offset="0.5"
id="stop7640" />
<stop
id="stop7632"
offset="0.60000002"
style="stop-color:#555753;stop-opacity:0.39215687;" />
<stop
style="stop-color:#555753;stop-opacity:1;"
offset="1"
id="stop7628" />
</linearGradient>
<linearGradient
id="linearGradient7614">
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="0"
id="stop7616" />
<stop
id="stop7636"
offset="0.40000001"
style="stop-color:#d3d7cf;stop-opacity:0.38666666;" />
<stop
style="stop-color:#d3d7cf;stop-opacity:0;"
offset="0.5"
id="stop7638" />
<stop
id="stop7622"
offset="0.60000002"
style="stop-color:#d3d7cf;stop-opacity:0.39215687;" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1;"
offset="1"
id="stop7618" />
</linearGradient>
<linearGradient
id="linearGradient2843">
<stop
style="stop-color:#eeeeec;stop-opacity:1;"
offset="0"
id="stop2845" />
<stop
style="stop-color:#c8c8c2;stop-opacity:1;"
offset="1"
id="stop2847" />
</linearGradient>
<linearGradient
id="linearGradient2835">
<stop
style="stop-color:#ccf2a6;stop-opacity:1;"
offset="0"
id="stop2837" />
<stop
style="stop-color:#8ae234;stop-opacity:1;"
offset="1"
id="stop2839" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective3257" />
<inkscape:perspective
id="perspective6979"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7934"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8023"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8057"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8095"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8219"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8279"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3803"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3869"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3929"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3968"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4002"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4032"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4053"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2905"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2979"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2842"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2978"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective6803"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3034"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5795"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5850"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5892"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5932"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective5981"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective6018"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3800"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3494"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3528"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8590"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8612"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3221"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7131"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7196"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7227"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8031"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8138"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8138-2"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8138-4"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8175"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8196"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8196-6"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8225"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8225-2"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8225-4"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8225-0"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8225-40"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8278"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8299"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8320"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective14145"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective14200"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective6861"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2937"
id="linearGradient2943"
x1="7"
y1="17"
x2="2"
y2="22"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2937"
id="linearGradient2947"
gradientUnits="userSpaceOnUse"
x1="7"
y1="17"
x2="2"
y2="22"
gradientTransform="matrix(-1,0,0,-1,26,30)" />
<inkscape:perspective
id="perspective4866"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4855"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4880"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4921"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4981"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3696"
id="linearGradient3694"
x1="20.5"
y1="30.5"
x2="3.5"
y2="30.5"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3710"
id="radialGradient3716"
cx="11.72698"
cy="30.008162"
fx="11.72698"
fy="30.008162"
r="13.875"
gradientTransform="matrix(1.90991,2.4623411e-8,-1.6458322e-8,0.64864861,-31.897477,7.035247)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3718"
id="linearGradient3724"
x1="11.5"
y1="23.5"
x2="11.499999"
y2="14.5"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-21,3)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3710"
id="radialGradient3727"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.90991,2.4623411e-8,-1.6458322e-8,0.64864861,-11.397477,12.535247)"
cx="11.72698"
cy="30.008162"
fx="11.72698"
fy="30.008162"
r="13.875" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3718"
id="linearGradient3729"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-0.5,8.5)"
x1="11.5"
y1="23.5"
x2="11.499999"
y2="14.5" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3696"
id="linearGradient3735"
gradientUnits="userSpaceOnUse"
x1="20.5"
y1="30.5"
x2="3.5"
y2="30.5" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="14.916667"
inkscape:cx="8.8415486"
inkscape:cy="15.694268"
inkscape:current-layer="layer4"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
borderlayer="false"
inkscape:window-width="1280"
inkscape:window-height="950"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-bbox="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-nodes="true"
inkscape:snap-to-guides="false">
<inkscape:grid
type="xygrid"
id="grid5700"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
dotted="true"
originx="2.5px"
originy="2.5px"
spacingx="1px"
spacingy="1px" />
</sodipodi:namedview>
<metadata
id="metadata5697">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Fast road</dc:title>
<dc:date>2012-08-13</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:rights>
<dc:subject>
<rdf:Bag>
<rdf:li>vector</rdf:li>
<rdf:li>network</rdf:li>
<rdf:li>optimization</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:coverage>GIS icons 0.2</dc:coverage>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
<dc:description />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="1"
style="display:inline"
transform="translate(0,-8)">
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m -3.5,11 c 7,-1.5 22,-2.5 31,-2.5 l 0,17.5 -31,0 0,-15 z"
id="rect3741"
sodipodi:nodetypes="ccccc" />
<path
style="color:#000000;fill:url(#radialGradient3727);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3729);stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m -2,23 c 0,0 5.333861,-1 13,-1 8,0 14,1 14,1 l 0,10 -27,0 0,-10 z"
id="rect3708"
sodipodi:nodetypes="czcccc" />
<g
id="g3731"
transform="translate(-3,0)">
<path
style="fill:url(#linearGradient3735);fill-opacity:1;fill-rule:evenodd;stroke:#babdb6;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 20.5,31.5 c 0,-5 -3.5,-7 -8.5,-7 -6,0 -8.5,2 -8.5,7 4.3333333,0 12.666667,0 17,0 z"
id="path3724"
sodipodi:nodetypes="cscc" />
<path
id="path2914"
d="M 10.981843,30.625698 13.018157,31.5 l 3,-6 -5.036314,5.125698 z"
style="color:#000000;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#555753;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 22.5,11.5 0,3"
id="path3739" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3737"
width="11"
height="4"
x="16.5"
y="11.5" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 8.5,16.5 0,2"
id="path3744"
transform="translate(0,8)" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 3.5,17.5 1,1"
id="path3746"
transform="translate(0,8)" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 1.3407821,20.446927 2.5,21.5"
id="path3748"
transform="translate(0,8)" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 16.5,19.5 -2,1"
id="path3750"
transform="translate(0,8)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -125,9 +125,6 @@ from .SetMValue import SetMValue
from .SetRasterStyle import SetRasterStyle
from .SetVectorStyle import SetVectorStyle
from .SetZValue import SetZValue
from .ShortestPathLayerToPoint import ShortestPathLayerToPoint
from .ShortestPathPointToLayer import ShortestPathPointToLayer
from .ShortestPathPointToPoint import ShortestPathPointToPoint
from .SingleSidedBuffer import SingleSidedBuffer
from .Slope import Slope
from .SnapGeometries import SnapGeometriesToLayer
@ -239,9 +236,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider):
SetRasterStyle(),
SetVectorStyle(),
SetZValue(),
ShortestPathLayerToPoint(),
ShortestPathPointToLayer(),
ShortestPathPointToPoint(),
SingleSidedBuffer(),
Slope(),
SnapGeometriesToLayer(),

View File

@ -1,295 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
ShortestPathLayerToPoint.py
---------------------
Date : December 2016
Copyright : (C) 2016 by Alexander Bruy
Email : alexander dot bruy at gmail dot com
***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Alexander Bruy'
__date__ = 'December 2016'
__copyright__ = '(C) 2016, Alexander Bruy'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from collections import OrderedDict
from qgis.PyQt.QtCore import QVariant, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.core import (QgsWkbTypes,
QgsUnitTypes,
QgsFeature,
QgsFeatureRequest,
QgsFeatureSink,
QgsGeometry,
QgsField,
QgsPointXY,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterEnum,
QgsProcessingParameterPoint,
QgsProcessingParameterField,
QgsProcessingParameterNumber,
QgsProcessingParameterDistance,
QgsProcessingParameterString,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterDefinition)
from qgis.analysis import (QgsVectorLayerDirector,
QgsNetworkDistanceStrategy,
QgsNetworkSpeedStrategy,
QgsGraphBuilder,
QgsGraphAnalyzer
)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class ShortestPathLayerToPoint(QgisAlgorithm):
INPUT = 'INPUT'
START_POINTS = 'START_POINTS'
END_POINT = 'END_POINT'
STRATEGY = 'STRATEGY'
DIRECTION_FIELD = 'DIRECTION_FIELD'
VALUE_FORWARD = 'VALUE_FORWARD'
VALUE_BACKWARD = 'VALUE_BACKWARD'
VALUE_BOTH = 'VALUE_BOTH'
DEFAULT_DIRECTION = 'DEFAULT_DIRECTION'
SPEED_FIELD = 'SPEED_FIELD'
DEFAULT_SPEED = 'DEFAULT_SPEED'
TOLERANCE = 'TOLERANCE'
OUTPUT = 'OUTPUT'
def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg'))
def group(self):
return self.tr('Network analysis')
def groupId(self):
return 'networkanalysis'
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
self.DIRECTIONS = OrderedDict([
(self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward),
(self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward),
(self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)])
self.STRATEGIES = [self.tr('Shortest'),
self.tr('Fastest')
]
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Vector layer representing network'),
[QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterFeatureSource(self.START_POINTS,
self.tr('Vector layer with start points'),
[QgsProcessing.TypeVectorPoint]))
self.addParameter(QgsProcessingParameterPoint(self.END_POINT,
self.tr('End point')))
self.addParameter(QgsProcessingParameterEnum(self.STRATEGY,
self.tr('Path type to calculate'),
self.STRATEGIES,
defaultValue=0))
params = []
params.append(QgsProcessingParameterField(self.DIRECTION_FIELD,
self.tr('Direction field'),
None,
self.INPUT,
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_FORWARD,
self.tr('Value for forward direction'),
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_BACKWARD,
self.tr('Value for backward direction'),
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_BOTH,
self.tr('Value for both directions'),
optional=True))
params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION,
self.tr('Default direction'),
list(self.DIRECTIONS.keys()),
defaultValue=2))
params.append(QgsProcessingParameterField(self.SPEED_FIELD,
self.tr('Speed field'),
None,
self.INPUT,
optional=True))
params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED,
self.tr('Default speed (km/h)'),
QgsProcessingParameterNumber.Double,
5.0, False, 0, 99999999.99))
params.append(QgsProcessingParameterDistance(self.TOLERANCE,
self.tr('Topology tolerance'),
0.0, self.INPUT, False, 0, 99999999.99))
for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(p)
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Shortest path'),
QgsProcessing.TypeVectorLine))
def name(self):
return 'shortestpathlayertopoint'
def displayName(self):
return self.tr('Shortest path (layer to point)')
def processAlgorithm(self, parameters, context, feedback):
network = self.parameterAsSource(parameters, self.INPUT, context)
if network is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
startPoints = self.parameterAsSource(parameters, self.START_POINTS, context)
if startPoints is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.START_POINTS))
endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs())
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
fields = startPoints.fields()
fields.append(QgsField('start', QVariant.String, '', 254, 0))
fields.append(QgsField('end', QVariant.String, '', 254, 0))
fields.append(QgsField('cost', QVariant.Double, '', 20, 7))
feat = QgsFeature()
feat.setFields(fields)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.LineString, network.sourceCrs())
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
directionField = -1
if directionFieldName:
directionField = network.fields().lookupField(directionFieldName)
speedField = -1
if speedFieldName:
speedField = network.fields().lookupField(speedFieldName)
director = QgsVectorLayerDirector(network,
directionField,
forwardValue,
backwardValue,
bothValue,
defaultDirection)
distUnit = context.project().crs().mapUnits()
multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
if strategy == 0:
strategy = QgsNetworkDistanceStrategy()
else:
strategy = QgsNetworkSpeedStrategy(speedField,
defaultSpeed,
multiplier * 1000.0 / 3600.0)
multiplier = 3600
director.addStrategy(strategy)
builder = QgsGraphBuilder(network.sourceCrs(),
True,
tolerance)
feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Loading start points…'))
request = QgsFeatureRequest()
request.setDestinationCrs(network.sourceCrs(), context.transformContext())
features = startPoints.getFeatures(request)
total = 100.0 / startPoints.featureCount() if startPoints.featureCount() else 0
points = [endPoint]
source_attributes = {}
i = 1
for current, f in enumerate(features):
if feedback.isCanceled():
break
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(QCoreApplication.translate('ShortestPathLayerToPoint', 'Building graph…'))
snappedPoints = director.makeGraph(builder, points, feedback)
feedback.pushInfo(QCoreApplication.translate('ShortestPathLayerToPoint', 'Calculating shortest paths…'))
graph = builder.graph()
idxEnd = graph.findVertex(snappedPoints[0])
nPoints = len(snappedPoints)
total = 100.0 / nPoints if nPoints else 1
for i in range(1, nPoints):
if feedback.isCanceled():
break
idxStart = graph.findVertex(snappedPoints[i])
tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
if tree[idxEnd] == -1:
msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(points[i].toString(), endPoint.toString()))
feedback.reportError(msg)
# add feature with no geometry
feat.clearGeometry()
attrs = source_attributes[i]
attrs.append(points[i].toString())
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
continue
route = [graph.vertex(idxEnd).point()]
cost = costs[idxEnd]
current = idxEnd
while current != idxStart:
current = graph.edge(tree[current]).fromVertex()
route.append(graph.vertex(current).point())
route.reverse()
geom = QgsGeometry.fromPolylineXY(route)
feat.setGeometry(geom)
attrs = source_attributes[i]
attrs.extend([points[i].toString(), endPoint.toString(), cost / multiplier])
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(i * total))
return {self.OUTPUT: dest_id}

View File

@ -1,295 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
ShortestPathPointToLayer.py
---------------------
Date : December 2016
Copyright : (C) 2016 by Alexander Bruy
Email : alexander dot bruy at gmail dot com
***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Alexander Bruy'
__date__ = 'December 2016'
__copyright__ = '(C) 2016, Alexander Bruy'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from collections import OrderedDict
from qgis.PyQt.QtCore import QVariant, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.core import (NULL,
QgsWkbTypes,
QgsUnitTypes,
QgsFeature,
QgsFeatureSink,
QgsGeometry,
QgsFeatureRequest,
QgsField,
QgsPointXY,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterEnum,
QgsProcessingParameterDistance,
QgsProcessingParameterPoint,
QgsProcessingParameterField,
QgsProcessingParameterNumber,
QgsProcessingParameterString,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterDefinition)
from qgis.analysis import (QgsVectorLayerDirector,
QgsNetworkDistanceStrategy,
QgsNetworkSpeedStrategy,
QgsGraphBuilder,
QgsGraphAnalyzer
)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class ShortestPathPointToLayer(QgisAlgorithm):
INPUT = 'INPUT'
START_POINT = 'START_POINT'
END_POINTS = 'END_POINTS'
STRATEGY = 'STRATEGY'
DIRECTION_FIELD = 'DIRECTION_FIELD'
VALUE_FORWARD = 'VALUE_FORWARD'
VALUE_BACKWARD = 'VALUE_BACKWARD'
VALUE_BOTH = 'VALUE_BOTH'
DEFAULT_DIRECTION = 'DEFAULT_DIRECTION'
SPEED_FIELD = 'SPEED_FIELD'
DEFAULT_SPEED = 'DEFAULT_SPEED'
TOLERANCE = 'TOLERANCE'
OUTPUT = 'OUTPUT'
def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg'))
def group(self):
return self.tr('Network analysis')
def groupId(self):
return 'networkanalysis'
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
self.DIRECTIONS = OrderedDict([
(self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward),
(self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward),
(self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)])
self.STRATEGIES = [self.tr('Shortest'),
self.tr('Fastest')
]
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Vector layer representing network'),
[QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterPoint(self.START_POINT,
self.tr('Start point')))
self.addParameter(QgsProcessingParameterFeatureSource(self.END_POINTS,
self.tr('Vector layer with end points'),
[QgsProcessing.TypeVectorPoint]))
self.addParameter(QgsProcessingParameterEnum(self.STRATEGY,
self.tr('Path type to calculate'),
self.STRATEGIES,
defaultValue=0))
params = []
params.append(QgsProcessingParameterField(self.DIRECTION_FIELD,
self.tr('Direction field'),
None,
self.INPUT,
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_FORWARD,
self.tr('Value for forward direction'),
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_BACKWARD,
self.tr('Value for backward direction'),
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_BOTH,
self.tr('Value for both directions'),
optional=True))
params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION,
self.tr('Default direction'),
list(self.DIRECTIONS.keys()),
defaultValue=2))
params.append(QgsProcessingParameterField(self.SPEED_FIELD,
self.tr('Speed field'),
None,
self.INPUT,
optional=True))
params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED,
self.tr('Default speed (km/h)'),
QgsProcessingParameterNumber.Double,
5.0, False, 0, 99999999.99))
params.append(QgsProcessingParameterDistance(self.TOLERANCE,
self.tr('Topology tolerance'),
0.0, self.INPUT, False, 0, 99999999.99))
for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(p)
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Shortest path'),
QgsProcessing.TypeVectorLine))
def name(self):
return 'shortestpathpointtolayer'
def displayName(self):
return self.tr('Shortest path (point to layer)')
def processAlgorithm(self, parameters, context, feedback):
network = self.parameterAsSource(parameters, self.INPUT, context)
if network is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
endPoints = self.parameterAsSource(parameters, self.END_POINTS, context)
if endPoints is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.END_POINTS))
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
fields = endPoints.fields()
fields.append(QgsField('start', QVariant.String, '', 254, 0))
fields.append(QgsField('end', QVariant.String, '', 254, 0))
fields.append(QgsField('cost', QVariant.Double, '', 20, 7))
feat = QgsFeature()
feat.setFields(fields)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.LineString, network.sourceCrs())
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
directionField = -1
if directionFieldName:
directionField = network.fields().lookupField(directionFieldName)
speedField = -1
if speedFieldName:
speedField = network.fields().lookupField(speedFieldName)
director = QgsVectorLayerDirector(network,
directionField,
forwardValue,
backwardValue,
bothValue,
defaultDirection)
distUnit = context.project().crs().mapUnits()
multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
if strategy == 0:
strategy = QgsNetworkDistanceStrategy()
else:
strategy = QgsNetworkSpeedStrategy(speedField,
defaultSpeed,
multiplier * 1000.0 / 3600.0)
multiplier = 3600
director.addStrategy(strategy)
builder = QgsGraphBuilder(network.sourceCrs(),
True,
tolerance)
feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToLayer', 'Loading end points…'))
request = QgsFeatureRequest()
request.setDestinationCrs(network.sourceCrs(), context.transformContext())
features = endPoints.getFeatures(request)
total = 100.0 / endPoints.featureCount() if endPoints.featureCount() else 0
points = [startPoint]
source_attributes = {}
i = 1
for current, f in enumerate(features):
if feedback.isCanceled():
break
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(QCoreApplication.translate('ShortestPathPointToLayer', 'Building graph…'))
snappedPoints = director.makeGraph(builder, points, feedback)
feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToLayer', 'Calculating shortest paths…'))
graph = builder.graph()
idxStart = graph.findVertex(snappedPoints[0])
tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
nPoints = len(snappedPoints)
total = 100.0 / nPoints if nPoints else 1
for i in range(1, nPoints):
if feedback.isCanceled():
break
idxEnd = graph.findVertex(snappedPoints[i])
if tree[idxEnd] == -1:
msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(startPoint.toString(), points[i].toString()))
feedback.reportError(msg)
# add feature with no geometry
feat.clearGeometry()
attrs = source_attributes[i]
attrs.extend([NULL, points[i].toString()])
feat.setAttributes(attrs)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
continue
route = [graph.vertex(idxEnd).point()]
cost = costs[idxEnd]
current = idxEnd
while current != idxStart:
current = graph.edge(tree[current]).fromVertex()
route.append(graph.vertex(current).point())
route.reverse()
geom = QgsGeometry.fromPolylineXY(route)
attrs = source_attributes[i]
attrs.extend([startPoint.toString(), points[i].toString(), cost / multiplier])
feat.setAttributes(attrs)
feat.setGeometry(geom)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(i * total))
return {self.OUTPUT: dest_id}

View File

@ -1,255 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
ShortestPathPointToPoint.py
---------------------
Date : November 2016
Copyright : (C) 2016 by Alexander Bruy
Email : alexander dot bruy at gmail dot com
***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Alexander Bruy'
__date__ = 'November 2016'
__copyright__ = '(C) 2016, Alexander Bruy'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from collections import OrderedDict
from qgis.PyQt.QtCore import QVariant, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.core import (QgsWkbTypes,
QgsUnitTypes,
QgsFeature,
QgsFeatureSink,
QgsGeometry,
QgsFields,
QgsField,
QgsProcessing,
QgsProcessingException,
QgsProcessingOutputNumber,
QgsProcessingParameterDistance,
QgsProcessingParameterEnum,
QgsProcessingParameterPoint,
QgsProcessingParameterField,
QgsProcessingParameterNumber,
QgsProcessingParameterString,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterDefinition)
from qgis.analysis import (QgsVectorLayerDirector,
QgsNetworkDistanceStrategy,
QgsNetworkSpeedStrategy,
QgsGraphBuilder,
QgsGraphAnalyzer
)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class ShortestPathPointToPoint(QgisAlgorithm):
INPUT = 'INPUT'
START_POINT = 'START_POINT'
END_POINT = 'END_POINT'
STRATEGY = 'STRATEGY'
DIRECTION_FIELD = 'DIRECTION_FIELD'
VALUE_FORWARD = 'VALUE_FORWARD'
VALUE_BACKWARD = 'VALUE_BACKWARD'
VALUE_BOTH = 'VALUE_BOTH'
DEFAULT_DIRECTION = 'DEFAULT_DIRECTION'
SPEED_FIELD = 'SPEED_FIELD'
DEFAULT_SPEED = 'DEFAULT_SPEED'
TOLERANCE = 'TOLERANCE'
TRAVEL_COST = 'TRAVEL_COST'
OUTPUT = 'OUTPUT'
def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'networkanalysis.svg'))
def group(self):
return self.tr('Network analysis')
def groupId(self):
return 'networkanalysis'
def __init__(self):
super().__init__()
def initAlgorithm(self, config=None):
self.DIRECTIONS = OrderedDict([
(self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward),
(self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward),
(self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)])
self.STRATEGIES = [self.tr('Shortest'),
self.tr('Fastest')
]
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Vector layer representing network'),
[QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterPoint(self.START_POINT,
self.tr('Start point')))
self.addParameter(QgsProcessingParameterPoint(self.END_POINT,
self.tr('End point')))
self.addParameter(QgsProcessingParameterEnum(self.STRATEGY,
self.tr('Path type to calculate'),
self.STRATEGIES,
defaultValue=0))
params = []
params.append(QgsProcessingParameterField(self.DIRECTION_FIELD,
self.tr('Direction field'),
None,
self.INPUT,
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_FORWARD,
self.tr('Value for forward direction'),
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_BACKWARD,
self.tr('Value for backward direction'),
optional=True))
params.append(QgsProcessingParameterString(self.VALUE_BOTH,
self.tr('Value for both directions'),
optional=True))
params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION,
self.tr('Default direction'),
list(self.DIRECTIONS.keys()),
defaultValue=2))
params.append(QgsProcessingParameterField(self.SPEED_FIELD,
self.tr('Speed field'),
None,
self.INPUT,
optional=True))
params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED,
self.tr('Default speed (km/h)'),
QgsProcessingParameterNumber.Double,
5.0, False, 0, 99999999.99))
params.append(QgsProcessingParameterDistance(self.TOLERANCE,
self.tr('Topology tolerance'),
0.0, self.INPUT, False, 0, 99999999.99))
for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(p)
self.addOutput(QgsProcessingOutputNumber(self.TRAVEL_COST,
self.tr('Travel cost')))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Shortest path'),
QgsProcessing.TypeVectorLine))
def name(self):
return 'shortestpathpointtopoint'
def displayName(self):
return self.tr('Shortest path (point to point)')
def processAlgorithm(self, parameters, context, feedback):
network = self.parameterAsSource(parameters, self.INPUT, context)
if network is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs())
endPoint = self.parameterAsPoint(parameters, self.END_POINT, context, network.sourceCrs())
strategy = self.parameterAsEnum(parameters, self.STRATEGY, context)
directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context)
forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context)
backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context)
bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context)
defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context)
speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context)
defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context)
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
fields = QgsFields()
fields.append(QgsField('start', QVariant.String, '', 254, 0))
fields.append(QgsField('end', QVariant.String, '', 254, 0))
fields.append(QgsField('cost', QVariant.Double, '', 20, 7))
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.LineString, network.sourceCrs())
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
directionField = -1
if directionField:
directionField = network.fields().lookupField(directionFieldName)
speedField = -1
if speedFieldName:
speedField = network.fields().lookupField(speedFieldName)
director = QgsVectorLayerDirector(network,
directionField,
forwardValue,
backwardValue,
bothValue,
defaultDirection)
distUnit = context.project().crs().mapUnits()
multiplier = QgsUnitTypes.fromUnitToUnitFactor(distUnit, QgsUnitTypes.DistanceMeters)
if strategy == 0:
strategy = QgsNetworkDistanceStrategy()
else:
strategy = QgsNetworkSpeedStrategy(speedField,
defaultSpeed,
multiplier * 1000.0 / 3600.0)
multiplier = 3600
director.addStrategy(strategy)
builder = QgsGraphBuilder(network.sourceCrs(),
True,
tolerance)
feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Building graph…'))
snappedPoints = director.makeGraph(builder, [startPoint, endPoint], feedback)
feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Calculating shortest path…'))
graph = builder.graph()
idxStart = graph.findVertex(snappedPoints[0])
idxEnd = graph.findVertex(snappedPoints[1])
tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
if tree[idxEnd] == -1:
raise QgsProcessingException(
self.tr('There is no route from start point to end point.'))
route = [graph.vertex(idxEnd).point()]
cost = costs[idxEnd]
current = idxEnd
while current != idxStart:
current = graph.edge(tree[current]).fromVertex()
route.append(graph.vertex(current).point())
route.reverse()
feedback.pushInfo(QCoreApplication.translate('ShortestPathPointToPoint', 'Writing results…'))
geom = QgsGeometry.fromPolylineXY(route)
feat = QgsFeature()
feat.setFields(fields)
feat['start'] = startPoint.toString()
feat['end'] = endPoint.toString()
feat['cost'] = cost / multiplier
feat.setGeometry(geom)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
results = {}
results[self.TRAVEL_COST] = cost / multiplier
results[self.OUTPUT] = dest_id
return results

View File

@ -2977,7 +2977,7 @@ tests:
name: expected/join_attribute_table_subset.gml
type: vector
- algorithm: qgis:shortestpathpointtopoint
- algorithm: native:shortestpathpointtopoint
name: Shortest path (point to point, shortest route)
params:
DEFAULT_DIRECTION: 2
@ -3006,7 +3006,7 @@ tests:
start: skip
end: skip
- algorithm: qgis:shortestpathpointtopoint
- algorithm: native:shortestpathpointtopoint
name: Shortest path (point to point, fastest route)
params:
DEFAULT_DIRECTION: 2
@ -3036,7 +3036,7 @@ tests:
start: skip
end: skip
- algorithm: qgis:shortestpathlayertopoint
- algorithm: native:shortestpathlayertopoint
name: Shortest path layer to point
params:
DEFAULT_DIRECTION: 2
@ -3066,7 +3066,7 @@ tests:
start: skip
end: skip
- algorithm: qgis:shortestpathpointtolayer
- algorithm: native:shortestpathpointtolayer
name: Shortest path point to layer
params:
DEFAULT_DIRECTION: 2
@ -5799,7 +5799,7 @@ tests:
OUTPUT:
name: expected/dbscan_multiple_clusters.gml
type: vector
- algorithm: qgis:rastersampling
name: Single band raster
params:

View File

@ -77,6 +77,9 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmrotate.cpp
processing/qgsalgorithmsaveselectedfeatures.cpp
processing/qgsalgorithmsegmentize.cpp
processing/qgsalgorithmshortestpathlayertopoint.cpp
processing/qgsalgorithmshortestpathpointtolayer.cpp
processing/qgsalgorithmshortestpathpointtopoint.cpp
processing/qgsalgorithmsimplify.cpp
processing/qgsalgorithmsmooth.cpp
processing/qgsalgorithmsnaptogrid.cpp
@ -95,6 +98,8 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmwedgebuffers.cpp
processing/qgsalgorithmzonalhistogram.cpp
processing/qgsalgorithmnetworkanalysisbase.cpp
processing/qgsnativealgorithms.cpp
processing/qgsoverlayutils.cpp
processing/qgsrasteranalysisutils.cpp

View File

@ -0,0 +1,166 @@
/***************************************************************************
qgsalgorithmnetworkanalysisbase.cpp
---------------------
begin : July 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsalgorithmnetworkanalysisbase.h"
#include "qgsgraphanalyzer.h"
#include "qgsnetworkspeedstrategy.h"
#include "qgsnetworkdistancestrategy.h"
///@cond PRIVATE
//
// QgsNetworkAnalysisAlgorithmBase
//
QString QgsNetworkAnalysisAlgorithmBase::group() const
{
return QObject::tr( "Network analysis" );
}
QString QgsNetworkAnalysisAlgorithmBase::groupId() const
{
return QStringLiteral( "networkanalysis" );
}
void QgsNetworkAnalysisAlgorithmBase::addCommonParams()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Vector layer representing network" ), QList< int >() << QgsProcessing::TypeVectorLine ) );
addParameter( new QgsProcessingParameterEnum( QStringLiteral( "STRATEGY" ), QObject::tr( "Path type to calculate" ), QStringList() << QObject::tr( "Shortest" ) << QObject::tr( "Fastest" ), false, 0 ) );
std::unique_ptr< QgsProcessingParameterField > directionField = qgis::make_unique< QgsProcessingParameterField >( QStringLiteral( "DIRECTION_FIELD" ),
QObject::tr( "Direction field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, false, true );
directionField->setFlags( directionField->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( directionField.release() );
std::unique_ptr< QgsProcessingParameterString > forwardValue = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "VALUE_FORWARD" ),
QObject::tr( "Value for forward direction" ), QVariant(), false, true );
forwardValue->setFlags( forwardValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( forwardValue.release() );
std::unique_ptr< QgsProcessingParameterString > backwardValue = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "VALUE_BACKWARD" ),
QObject::tr( "Value for backward direction" ), QVariant(), false, true );
backwardValue->setFlags( backwardValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( backwardValue.release() );
std::unique_ptr< QgsProcessingParameterString > bothValue = qgis::make_unique< QgsProcessingParameterString >( QStringLiteral( "VALUE_BOTH" ),
QObject::tr( "Value for both directions" ), QVariant(), false, true );
bothValue->setFlags( bothValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( bothValue.release() );
std::unique_ptr< QgsProcessingParameterEnum > directionValue = qgis::make_unique< QgsProcessingParameterEnum >( QStringLiteral( "DEFAULT_DIRECTION" ),
QObject::tr( "Default direction" ), QStringList() << QObject::tr( "Forward direction" ) << QObject::tr( "Backward direction" ) << QObject::tr( "Both directions" ), false, 2 );
directionValue->setFlags( directionValue->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( directionValue.release() );
std::unique_ptr< QgsProcessingParameterField > speedField = qgis::make_unique< QgsProcessingParameterField >( QStringLiteral( "SPEED_FIELD" ),
QObject::tr( "Speed field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Numeric, false, true );
speedField->setFlags( speedField->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( speedField.release() );
std::unique_ptr< QgsProcessingParameterNumber > speed = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DEFAULT_SPEED" ), QObject::tr( "Default speed (km/h)" ), QgsProcessingParameterNumber::Double, 50, false, 0 );
speed->setFlags( speed->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( speed.release() );
std::unique_ptr< QgsProcessingParameterNumber > tolerance = qgis::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "TOLERANCE" ), QObject::tr( "Topology tolerance" ), 0, QStringLiteral( "INPUT" ), false, 0 );
tolerance->setFlags( tolerance->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
addParameter( tolerance.release() );
}
void QgsNetworkAnalysisAlgorithmBase::loadCommonParams( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
Q_UNUSED( feedback );
mNetwork.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mNetwork )
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
int strategy = parameterAsInt( parameters, QStringLiteral( "STRATEGY" ), context );
QString directionFieldName = parameterAsString( parameters, QStringLiteral( "DIRECTION_FIELD" ), context );
QString forwardValue = parameterAsString( parameters, QStringLiteral( "VALUE_FORWARD" ), context );
QString backwardValue = parameterAsString( parameters, QStringLiteral( "VALUE_BACKWARD" ), context );
QString bothValue = parameterAsString( parameters, QStringLiteral( "VALUE_BOTH" ), context );
QgsVectorLayerDirector::Direction defaultDirection = static_cast< QgsVectorLayerDirector::Direction>( parameterAsInt( parameters, QStringLiteral( "DEFAULT_DIRECTION" ), context ) );
QString speedFieldName = parameterAsString( parameters, QStringLiteral( "SPEED_FIELD" ), context );
double defaultSpeed = parameterAsDouble( parameters, QStringLiteral( "DEFAULT_SPEED" ), context );
double tolerance = parameterAsDouble( parameters, QStringLiteral( "TOLERANCE" ), context );
int directionField = -1;
if ( !directionFieldName.isEmpty() )
{
directionField = mNetwork->fields().lookupField( directionFieldName );
}
int speedField = -1;
if ( !speedFieldName.isEmpty() )
{
speedField = mNetwork->fields().lookupField( speedFieldName );
}
mDirector = new QgsVectorLayerDirector( mNetwork.get(), directionField, forwardValue, backwardValue, bothValue, defaultDirection );
QgsUnitTypes::DistanceUnit distanceUnits = context.project()->crs().mapUnits();
mMultiplier = QgsUnitTypes::fromUnitToUnitFactor( distanceUnits, QgsUnitTypes::DistanceMeters );
if ( strategy )
{
mDirector->addStrategy( new QgsNetworkSpeedStrategy( speedField, defaultSpeed, mMultiplier * 1000.0 / 3600.0 ) );
mMultiplier = 3600;
}
else
{
mDirector->addStrategy( new QgsNetworkDistanceStrategy() );
}
mBuilder = qgis::make_unique< QgsGraphBuilder >( mNetwork->sourceCrs(), true, tolerance );
}
void QgsNetworkAnalysisAlgorithmBase::loadPoints( QgsFeatureSource *source, QVector< QgsPointXY > &points, QHash< int, QgsAttributes > &attributes, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
feedback->pushInfo( QObject::tr( "Loading points…" ) );
QgsFeature feat;
int i = 0;
int pointId = 1;
double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0;
QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest().setDestinationCrs( mNetwork->sourceCrs(), context.transformContext() ) );
while ( features.nextFeature( feat ) )
{
i++;
if ( feedback->isCanceled() )
{
break;
}
feedback->setProgress( i * step );
if ( !feat.hasGeometry() )
continue;
QgsGeometry geom = feat.geometry();
QgsAbstractGeometry::vertex_iterator it = geom.vertices_begin();
while ( it != geom.vertices_end() )
{
points.push_back( QgsPointXY( *it ) );
attributes.insert( pointId, feat.attributes() );
it++;
pointId++;
}
}
}
///@endcond

View File

@ -0,0 +1,71 @@
/***************************************************************************
qgsalgorithmnetworkanalysisbase.h
---------------------
begin : July 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSALGORITHMNETWORKANALYSISBASE_H
#define QGSALGORITHMNETWORKANALYSISBASE_H
#define SIP_NO_FILE
#include "qgis.h"
#include "qgsprocessingalgorithm.h"
#include "qgsgraph.h"
#include "qgsgraphbuilder.h"
#include "qgsvectorlayerdirector.h"
///@cond PRIVATE
/**
* Base class for networkanalysis algorithms.
*/
class QgsNetworkAnalysisAlgorithmBase : public QgsProcessingAlgorithm
{
public:
QString group() const final;
QString groupId() const final;
QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmNetworkAnalysis.svg" ) ); }
QString svgIconPath() const override { return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmNetworkAnalysis.svg" ) ); }
protected:
/**
* Adds common algorithm parameters.
*/
void addCommonParams();
/**
* Populates common parameters with values.
*/
void loadCommonParams( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
/**
* Loads point from the feature source for further processing.
*/
void loadPoints( QgsFeatureSource *source, QVector< QgsPointXY > &points, QHash< int, QgsAttributes > &attributes, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
std::unique_ptr< QgsFeatureSource > mNetwork;
QgsVectorLayerDirector *mDirector = nullptr;
std::unique_ptr< QgsGraphBuilder > mBuilder;
std::unique_ptr< QgsGraph > mGraph;
double mMultiplier = 1;
};
///@endcond PRIVATE
#endif // QGSALGORITHMNETWORKANALYSISBASE_H

View File

@ -0,0 +1,158 @@
/***************************************************************************
qgsalgorithmshortestpathlayertopoint.cpp
---------------------
begin : July 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsalgorithmshortestpathlayertopoint.h"
#include "qgsgraphanalyzer.h"
#include "qgsmessagelog.h"
///@cond PRIVATE
QString QgsShortestPathLayerToPointAlgorithm::name() const
{
return QStringLiteral( "shortestpathlayertopoint" );
}
QString QgsShortestPathLayerToPointAlgorithm::displayName() const
{
return QObject::tr( "Shortest path (layer to point)" );
}
QStringList QgsShortestPathLayerToPointAlgorithm::tags() const
{
return QObject::tr( "network,path,shortest,fastest" ).split( ',' );
}
QString QgsShortestPathLayerToPointAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm computes optimal (shortest or fastest) route from multiple start points defined by vector layer and given end point." );
}
QgsShortestPathLayerToPointAlgorithm *QgsShortestPathLayerToPointAlgorithm::createInstance() const
{
return new QgsShortestPathLayerToPointAlgorithm();
}
void QgsShortestPathLayerToPointAlgorithm::initAlgorithm( const QVariantMap & )
{
addCommonParams();
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "START_POINTS" ), QObject::tr( "Vector layer with start points" ), QList< int >() << QgsProcessing::TypeVectorPoint ) );
addParameter( new QgsProcessingParameterPoint( QStringLiteral( "END_POINT" ), QObject::tr( "End point" ) ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) );
}
QVariantMap QgsShortestPathLayerToPointAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
loadCommonParams( parameters, context, feedback );
QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, mNetwork->sourceCrs() );
std::unique_ptr< QgsFeatureSource > startPoints( parameterAsSource( parameters, QStringLiteral( "START_POINTS" ), context ) );
if ( !startPoints )
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "START_POINTS" ) ) );
QgsFields fields = startPoints->fields();
fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) );
fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) );
fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) );
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) );
if ( !sink )
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
QVector< QgsPointXY > points;
points.push_front( endPoint );
QHash< int, QgsAttributes > sourceAttributes;
loadPoints( startPoints.get(), points, sourceAttributes, context, feedback );
feedback->pushInfo( QObject::tr( "Building graph…" ) );
QVector< QgsPointXY > snappedPoints;
mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback );
feedback->pushInfo( QObject::tr( "Calculating shortest paths…" ) );
QgsGraph *graph = mBuilder->graph();
int idxEnd = graph->findVertex( snappedPoints[0] );
int idxStart;
int currentIdx;
QVector< int > tree;
QVector< double > costs;
QVector<QgsPointXY> route;
double cost;
QgsFeature feat;
feat.setFields( fields );
QgsAttributes attributes;
int step = points.size() > 0 ? 100.0 / points.size() : 1;
for ( int i = 1; i < points.size(); i++ )
{
if ( feedback->isCanceled() )
{
break;
}
idxStart = graph->findVertex( snappedPoints[i] );
QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs );
if ( tree.at( idxEnd ) == -1 )
{
feedback->reportError( QObject::tr( "There is no route from start point (%1) to end point (%2)." )
.arg( points[i].toString() )
.arg( endPoint.toString() ) );
feat.clearGeometry();
attributes = sourceAttributes.value( i );
attributes.append( points[i].toString() );
feat.setAttributes( attributes );
sink->addFeature( feat, QgsFeatureSink::FastInsert );
continue;
}
route.clear();
route.push_front( graph->vertex( idxEnd ).point() );
cost = costs.at( idxEnd );
currentIdx = idxEnd;
while ( currentIdx != idxStart )
{
currentIdx = graph->edge( tree.at( currentIdx ) ).fromVertex();
route.push_front( graph->vertex( currentIdx ).point() );
}
QgsGeometry geom = QgsGeometry::fromPolylineXY( route );
QgsFeature feat;
feat.setFields( fields );
attributes = sourceAttributes.value( i );
attributes.append( points[i].toString() );
attributes.append( endPoint.toString() );
attributes.append( cost / mMultiplier );
feat.setAttributes( attributes );
feat.setGeometry( geom );
sink->addFeature( feat, QgsFeatureSink::FastInsert );
feedback->setProgress( i * step );
}
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
///@endcond

View File

@ -0,0 +1,53 @@
/***************************************************************************
qgsalgorithmshortestpathlayertopoint.h
---------------------
begin : JUly 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSALGORITHMSHORTESTPATHLAYERTOPOINT_H
#define QGSALGORITHMSHORTESTPATHLAYERTOPOINT_H
#define SIP_NO_FILE
#include "qgis.h"
#include "qgsalgorithmnetworkanalysisbase.h"
///@cond PRIVATE
/**
* Native shortest path (layer to point) algorithm.
*/
class QgsShortestPathLayerToPointAlgorithm : public QgsNetworkAnalysisAlgorithmBase
{
public:
QgsShortestPathLayerToPointAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QgsShortestPathLayerToPointAlgorithm *createInstance() const override SIP_FACTORY;
protected:
QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
///@endcond PRIVATE
#endif // QGSALGORITHMSHORTESTPATHLAYERTOPOINT_H

View File

@ -0,0 +1,156 @@
/***************************************************************************
qgsalgorithmshortestpathpointtolayer.cpp
---------------------
begin : July 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsalgorithmshortestpathpointtolayer.h"
#include "qgsgraphanalyzer.h"
#include "qgsmessagelog.h"
///@cond PRIVATE
QString QgsShortestPathPointToLayerAlgorithm::name() const
{
return QStringLiteral( "shortestpathpointtolayer" );
}
QString QgsShortestPathPointToLayerAlgorithm::displayName() const
{
return QObject::tr( "Shortest path (point to layer)" );
}
QStringList QgsShortestPathPointToLayerAlgorithm::tags() const
{
return QObject::tr( "network,path,shortest,fastest" ).split( ',' );
}
QString QgsShortestPathPointToLayerAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start point and multiple end points defined by point vector layer." );
}
QgsShortestPathPointToLayerAlgorithm *QgsShortestPathPointToLayerAlgorithm::createInstance() const
{
return new QgsShortestPathPointToLayerAlgorithm();
}
void QgsShortestPathPointToLayerAlgorithm::initAlgorithm( const QVariantMap & )
{
addCommonParams();
addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) );
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "END_POINTS" ), QObject::tr( "Vector layer with end points" ), QList< int >() << QgsProcessing::TypeVectorPoint ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) );
}
QVariantMap QgsShortestPathPointToLayerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
loadCommonParams( parameters, context, feedback );
QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() );
std::unique_ptr< QgsFeatureSource > endPoints( parameterAsSource( parameters, QStringLiteral( "END_POINTS" ), context ) );
if ( !endPoints )
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "END_POINTS" ) ) );
QgsFields fields = endPoints->fields();
fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) );
fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) );
fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) );
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) );
if ( !sink )
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
QVector< QgsPointXY > points;
points.push_front( startPoint );
QHash< int, QgsAttributes > sourceAttributes;
loadPoints( endPoints.get(), points, sourceAttributes, context, feedback );
feedback->pushInfo( QObject::tr( "Building graph…" ) );
QVector< QgsPointXY > snappedPoints;
mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback );
feedback->pushInfo( QObject::tr( "Calculating shortest paths…" ) );
QgsGraph *graph = mBuilder->graph();
int idxStart = graph->findVertex( snappedPoints[0] );
int idxEnd;
QVector< int > tree;
QVector< double > costs;
QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs );
QVector<QgsPointXY> route;
double cost;
QgsFeature feat;
feat.setFields( fields );
QgsAttributes attributes;
int step = points.size() > 0 ? 100.0 / points.size() : 1;
for ( int i = 1; i < points.size(); i++ )
{
if ( feedback->isCanceled() )
{
break;
}
idxEnd = graph->findVertex( snappedPoints[i] );
if ( tree.at( idxEnd ) == -1 )
{
feedback->reportError( QObject::tr( "There is no route from start point (%1) to end point (%2)." )
.arg( startPoint.toString() )
.arg( points[i].toString() ) );
feat.clearGeometry();
attributes = sourceAttributes.value( i );
attributes.append( QVariant() );
attributes.append( points[i].toString() );
feat.setAttributes( attributes );
sink->addFeature( feat, QgsFeatureSink::FastInsert );
continue;
}
route.clear();
route.push_front( graph->vertex( idxEnd ).point() );
cost = costs.at( idxEnd );
while ( idxEnd != idxStart )
{
idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex();
route.push_front( graph->vertex( idxEnd ).point() );
}
QgsGeometry geom = QgsGeometry::fromPolylineXY( route );
QgsFeature feat;
feat.setFields( fields );
attributes = sourceAttributes.value( i );
attributes.append( startPoint.toString() );
attributes.append( points[i].toString() );
attributes.append( cost / mMultiplier );
feat.setAttributes( attributes );
feat.setGeometry( geom );
sink->addFeature( feat, QgsFeatureSink::FastInsert );
feedback->setProgress( i * step );
}
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
///@endcond

View File

@ -0,0 +1,53 @@
/***************************************************************************
qgsalgorithmshortestpathpointtolayer.h
---------------------
begin : JUly 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H
#define QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H
#define SIP_NO_FILE
#include "qgis.h"
#include "qgsalgorithmnetworkanalysisbase.h"
///@cond PRIVATE
/**
* Native shortest path (point to layer) algorithm.
*/
class QgsShortestPathPointToLayerAlgorithm : public QgsNetworkAnalysisAlgorithmBase
{
public:
QgsShortestPathPointToLayerAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QgsShortestPathPointToLayerAlgorithm *createInstance() const override SIP_FACTORY;
protected:
QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
///@endcond PRIVATE
#endif // QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H

View File

@ -0,0 +1,121 @@
/***************************************************************************
qgsalgorithmshortestpathpointtopoint.cpp
---------------------
begin : July 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsalgorithmshortestpathpointtopoint.h"
#include "qgsgraphanalyzer.h"
///@cond PRIVATE
QString QgsShortestPathPointToPointAlgorithm::name() const
{
return QStringLiteral( "shortestpathpointtopoint" );
}
QString QgsShortestPathPointToPointAlgorithm::displayName() const
{
return QObject::tr( "Shortest path (point to point)" );
}
QStringList QgsShortestPathPointToPointAlgorithm::tags() const
{
return QObject::tr( "network,path,shortest,fastest" ).split( ',' );
}
QString QgsShortestPathPointToPointAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm computes optimal (shortest or fastest) route between given start and end points." );
}
QgsShortestPathPointToPointAlgorithm *QgsShortestPathPointToPointAlgorithm::createInstance() const
{
return new QgsShortestPathPointToPointAlgorithm();
}
void QgsShortestPathPointToPointAlgorithm::initAlgorithm( const QVariantMap & )
{
addCommonParams();
addParameter( new QgsProcessingParameterPoint( QStringLiteral( "START_POINT" ), QObject::tr( "Start point" ) ) );
addParameter( new QgsProcessingParameterPoint( QStringLiteral( "END_POINT" ), QObject::tr( "End point" ) ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Shortest path" ), QgsProcessing::TypeVectorLine ) );
addOutput( new QgsProcessingOutputNumber( QStringLiteral( "TRAVEL_COST" ), QObject::tr( "Travel cost" ) ) );
}
QVariantMap QgsShortestPathPointToPointAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
loadCommonParams( parameters, context, feedback );
QgsFields fields;
fields.append( QgsField( QStringLiteral( "start" ), QVariant::String ) );
fields.append( QgsField( QStringLiteral( "end" ), QVariant::String ) );
fields.append( QgsField( QStringLiteral( "cost" ), QVariant::Double ) );
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::LineString, mNetwork->sourceCrs() ) );
if ( !sink )
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
QgsPointXY startPoint = parameterAsPoint( parameters, QStringLiteral( "START_POINT" ), context, mNetwork->sourceCrs() );
QgsPointXY endPoint = parameterAsPoint( parameters, QStringLiteral( "END_POINT" ), context, mNetwork->sourceCrs() );
feedback->pushInfo( QObject::tr( "Building graph…" ) );
QVector< QgsPointXY > points;
points << startPoint << endPoint;
QVector< QgsPointXY > snappedPoints;
mDirector->makeGraph( mBuilder.get(), points, snappedPoints, feedback );
feedback->pushInfo( QObject::tr( "Calculating shortest path…" ) );
QgsGraph *graph = mBuilder->graph();
int idxStart = graph->findVertex( snappedPoints[0] );
int idxEnd = graph->findVertex( snappedPoints[1] );
QVector< int > tree;
QVector< double > costs;
QgsGraphAnalyzer::dijkstra( graph, idxStart, 0, &tree, &costs );
if ( tree.at( idxEnd ) == -1 )
{
throw QgsProcessingException( QObject::tr( "There is no route from start point to end point." ) );
}
QVector<QgsPointXY> route;
route.push_front( graph->vertex( idxEnd ).point() );
double cost = costs.at( idxEnd );
while ( idxEnd != idxStart )
{
idxEnd = graph->edge( tree.at( idxEnd ) ).fromVertex();
route.push_front( graph->vertex( idxEnd ).point() );
}
feedback->pushInfo( QObject::tr( "Writing results…" ) );
QgsGeometry geom = QgsGeometry::fromPolylineXY( route );
QgsFeature feat;
feat.setFields( fields );
QgsAttributes attributes;
attributes << startPoint.toString() << endPoint.toString() << cost / mMultiplier;
feat.setGeometry( geom );
feat.setAttributes( attributes );
sink->addFeature( feat, QgsFeatureSink::FastInsert );
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
outputs.insert( QStringLiteral( "TRAVEL_COST" ), cost / mMultiplier );
return outputs;
}
///@endcond

View File

@ -0,0 +1,53 @@
/***************************************************************************
qgsalgorithmshortestpathpointtopoint.h
---------------------
begin : JUly 2018
copyright : (C) 2018 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSALGORITHMSHORTESTPATHPOINTTOPOINT_H
#define QGSALGORITHMSHORTESTPATHPOINTTOPOINT_H
#define SIP_NO_FILE
#include "qgis.h"
#include "qgsalgorithmnetworkanalysisbase.h"
///@cond PRIVATE
/**
* Native shortest path (point to point) algorithm.
*/
class QgsShortestPathPointToPointAlgorithm : public QgsNetworkAnalysisAlgorithmBase
{
public:
QgsShortestPathPointToPointAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QgsShortestPathPointToPointAlgorithm *createInstance() const override SIP_FACTORY;
protected:
QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
///@endcond PRIVATE
#endif // QGSALGORITHMSHORTESTPATHPOINTTOPOINT_H

View File

@ -74,6 +74,9 @@
#include "qgsalgorithmrotate.h"
#include "qgsalgorithmsaveselectedfeatures.h"
#include "qgsalgorithmsegmentize.h"
#include "qgsalgorithmshortestpathlayertopoint.h"
#include "qgsalgorithmshortestpathpointtolayer.h"
#include "qgsalgorithmshortestpathpointtopoint.h"
#include "qgsalgorithmsimplify.h"
#include "qgsalgorithmsmooth.h"
#include "qgsalgorithmsnaptogrid.h"
@ -196,6 +199,9 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsSegmentizeByMaximumAngleAlgorithm() );
addAlgorithm( new QgsSegmentizeByMaximumDistanceAlgorithm() );
addAlgorithm( new QgsSelectByLocationAlgorithm() );
addAlgorithm( new QgsShortestPathLayerToPointAlgorithm() );
addAlgorithm( new QgsShortestPathPointToLayerAlgorithm() );
addAlgorithm( new QgsShortestPathPointToPointAlgorithm() );
addAlgorithm( new QgsSimplifyAlgorithm() );
addAlgorithm( new QgsSmoothAlgorithm() );
addAlgorithm( new QgsSnapToGridAlgorithm() );