mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #7505 from alexbruy/network-analysis
[processing] port shortest path algs to C++
This commit is contained in:
commit
bbc33309a3
@ -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>
|
||||
|
798
images/themes/default/algorithms/mAlgorithmNetworkAnalysis.svg
Normal file
798
images/themes/default/algorithms/mAlgorithmNetworkAnalysis.svg
Normal 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 |
@ -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(),
|
||||
|
@ -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}
|
@ -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}
|
@ -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
|
@ -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:
|
||||
|
@ -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
|
||||
|
166
src/analysis/processing/qgsalgorithmnetworkanalysisbase.cpp
Normal file
166
src/analysis/processing/qgsalgorithmnetworkanalysisbase.cpp
Normal 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 ¶meters, 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
|
71
src/analysis/processing/qgsalgorithmnetworkanalysisbase.h
Normal file
71
src/analysis/processing/qgsalgorithmnetworkanalysisbase.h
Normal 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 ¶meters, 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
|
||||
|
158
src/analysis/processing/qgsalgorithmshortestpathlayertopoint.cpp
Normal file
158
src/analysis/processing/qgsalgorithmshortestpathlayertopoint.cpp
Normal 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 ¶meters, 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
|
@ -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 ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMSHORTESTPATHLAYERTOPOINT_H
|
156
src/analysis/processing/qgsalgorithmshortestpathpointtolayer.cpp
Normal file
156
src/analysis/processing/qgsalgorithmshortestpathpointtolayer.cpp
Normal 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 ¶meters, 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
|
@ -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 ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMSHORTESTPATHPOINTTOLAYER_H
|
121
src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp
Normal file
121
src/analysis/processing/qgsalgorithmshortestpathpointtopoint.cpp
Normal 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 ¶meters, 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
|
@ -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 ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMSHORTESTPATHPOINTTOPOINT_H
|
@ -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() );
|
||||
|
Loading…
x
Reference in New Issue
Block a user