mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -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/mAlgorithmMergeLayers.svg</file>
|
||||||
<file>themes/default/algorithms/mAlgorithmMultiToSingle.svg</file>
|
<file>themes/default/algorithms/mAlgorithmMultiToSingle.svg</file>
|
||||||
<file>themes/default/algorithms/mAlgorithmNearestNeighbour.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/mAlgorithmPolygonToLine.svg</file>
|
||||||
<file>themes/default/algorithms/mAlgorithmRandomPointsWithinPolygon.svg</file>
|
<file>themes/default/algorithms/mAlgorithmRandomPointsWithinPolygon.svg</file>
|
||||||
<file>themes/default/algorithms/mAlgorithmRandomPointsWithinExtent.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 .SetRasterStyle import SetRasterStyle
|
||||||
from .SetVectorStyle import SetVectorStyle
|
from .SetVectorStyle import SetVectorStyle
|
||||||
from .SetZValue import SetZValue
|
from .SetZValue import SetZValue
|
||||||
from .ShortestPathLayerToPoint import ShortestPathLayerToPoint
|
|
||||||
from .ShortestPathPointToLayer import ShortestPathPointToLayer
|
|
||||||
from .ShortestPathPointToPoint import ShortestPathPointToPoint
|
|
||||||
from .SingleSidedBuffer import SingleSidedBuffer
|
from .SingleSidedBuffer import SingleSidedBuffer
|
||||||
from .Slope import Slope
|
from .Slope import Slope
|
||||||
from .SnapGeometries import SnapGeometriesToLayer
|
from .SnapGeometries import SnapGeometriesToLayer
|
||||||
@ -239,9 +236,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider):
|
|||||||
SetRasterStyle(),
|
SetRasterStyle(),
|
||||||
SetVectorStyle(),
|
SetVectorStyle(),
|
||||||
SetZValue(),
|
SetZValue(),
|
||||||
ShortestPathLayerToPoint(),
|
|
||||||
ShortestPathPointToLayer(),
|
|
||||||
ShortestPathPointToPoint(),
|
|
||||||
SingleSidedBuffer(),
|
SingleSidedBuffer(),
|
||||||
Slope(),
|
Slope(),
|
||||||
SnapGeometriesToLayer(),
|
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
|
name: expected/join_attribute_table_subset.gml
|
||||||
type: vector
|
type: vector
|
||||||
|
|
||||||
- algorithm: qgis:shortestpathpointtopoint
|
- algorithm: native:shortestpathpointtopoint
|
||||||
name: Shortest path (point to point, shortest route)
|
name: Shortest path (point to point, shortest route)
|
||||||
params:
|
params:
|
||||||
DEFAULT_DIRECTION: 2
|
DEFAULT_DIRECTION: 2
|
||||||
@ -3006,7 +3006,7 @@ tests:
|
|||||||
start: skip
|
start: skip
|
||||||
end: skip
|
end: skip
|
||||||
|
|
||||||
- algorithm: qgis:shortestpathpointtopoint
|
- algorithm: native:shortestpathpointtopoint
|
||||||
name: Shortest path (point to point, fastest route)
|
name: Shortest path (point to point, fastest route)
|
||||||
params:
|
params:
|
||||||
DEFAULT_DIRECTION: 2
|
DEFAULT_DIRECTION: 2
|
||||||
@ -3036,7 +3036,7 @@ tests:
|
|||||||
start: skip
|
start: skip
|
||||||
end: skip
|
end: skip
|
||||||
|
|
||||||
- algorithm: qgis:shortestpathlayertopoint
|
- algorithm: native:shortestpathlayertopoint
|
||||||
name: Shortest path layer to point
|
name: Shortest path layer to point
|
||||||
params:
|
params:
|
||||||
DEFAULT_DIRECTION: 2
|
DEFAULT_DIRECTION: 2
|
||||||
@ -3066,7 +3066,7 @@ tests:
|
|||||||
start: skip
|
start: skip
|
||||||
end: skip
|
end: skip
|
||||||
|
|
||||||
- algorithm: qgis:shortestpathpointtolayer
|
- algorithm: native:shortestpathpointtolayer
|
||||||
name: Shortest path point to layer
|
name: Shortest path point to layer
|
||||||
params:
|
params:
|
||||||
DEFAULT_DIRECTION: 2
|
DEFAULT_DIRECTION: 2
|
||||||
@ -5799,7 +5799,7 @@ tests:
|
|||||||
OUTPUT:
|
OUTPUT:
|
||||||
name: expected/dbscan_multiple_clusters.gml
|
name: expected/dbscan_multiple_clusters.gml
|
||||||
type: vector
|
type: vector
|
||||||
|
|
||||||
- algorithm: qgis:rastersampling
|
- algorithm: qgis:rastersampling
|
||||||
name: Single band raster
|
name: Single band raster
|
||||||
params:
|
params:
|
||||||
|
@ -77,6 +77,9 @@ SET(QGIS_ANALYSIS_SRCS
|
|||||||
processing/qgsalgorithmrotate.cpp
|
processing/qgsalgorithmrotate.cpp
|
||||||
processing/qgsalgorithmsaveselectedfeatures.cpp
|
processing/qgsalgorithmsaveselectedfeatures.cpp
|
||||||
processing/qgsalgorithmsegmentize.cpp
|
processing/qgsalgorithmsegmentize.cpp
|
||||||
|
processing/qgsalgorithmshortestpathlayertopoint.cpp
|
||||||
|
processing/qgsalgorithmshortestpathpointtolayer.cpp
|
||||||
|
processing/qgsalgorithmshortestpathpointtopoint.cpp
|
||||||
processing/qgsalgorithmsimplify.cpp
|
processing/qgsalgorithmsimplify.cpp
|
||||||
processing/qgsalgorithmsmooth.cpp
|
processing/qgsalgorithmsmooth.cpp
|
||||||
processing/qgsalgorithmsnaptogrid.cpp
|
processing/qgsalgorithmsnaptogrid.cpp
|
||||||
@ -95,6 +98,8 @@ SET(QGIS_ANALYSIS_SRCS
|
|||||||
processing/qgsalgorithmwedgebuffers.cpp
|
processing/qgsalgorithmwedgebuffers.cpp
|
||||||
processing/qgsalgorithmzonalhistogram.cpp
|
processing/qgsalgorithmzonalhistogram.cpp
|
||||||
|
|
||||||
|
processing/qgsalgorithmnetworkanalysisbase.cpp
|
||||||
|
|
||||||
processing/qgsnativealgorithms.cpp
|
processing/qgsnativealgorithms.cpp
|
||||||
processing/qgsoverlayutils.cpp
|
processing/qgsoverlayutils.cpp
|
||||||
processing/qgsrasteranalysisutils.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 "qgsalgorithmrotate.h"
|
||||||
#include "qgsalgorithmsaveselectedfeatures.h"
|
#include "qgsalgorithmsaveselectedfeatures.h"
|
||||||
#include "qgsalgorithmsegmentize.h"
|
#include "qgsalgorithmsegmentize.h"
|
||||||
|
#include "qgsalgorithmshortestpathlayertopoint.h"
|
||||||
|
#include "qgsalgorithmshortestpathpointtolayer.h"
|
||||||
|
#include "qgsalgorithmshortestpathpointtopoint.h"
|
||||||
#include "qgsalgorithmsimplify.h"
|
#include "qgsalgorithmsimplify.h"
|
||||||
#include "qgsalgorithmsmooth.h"
|
#include "qgsalgorithmsmooth.h"
|
||||||
#include "qgsalgorithmsnaptogrid.h"
|
#include "qgsalgorithmsnaptogrid.h"
|
||||||
@ -196,6 +199,9 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
|||||||
addAlgorithm( new QgsSegmentizeByMaximumAngleAlgorithm() );
|
addAlgorithm( new QgsSegmentizeByMaximumAngleAlgorithm() );
|
||||||
addAlgorithm( new QgsSegmentizeByMaximumDistanceAlgorithm() );
|
addAlgorithm( new QgsSegmentizeByMaximumDistanceAlgorithm() );
|
||||||
addAlgorithm( new QgsSelectByLocationAlgorithm() );
|
addAlgorithm( new QgsSelectByLocationAlgorithm() );
|
||||||
|
addAlgorithm( new QgsShortestPathLayerToPointAlgorithm() );
|
||||||
|
addAlgorithm( new QgsShortestPathPointToLayerAlgorithm() );
|
||||||
|
addAlgorithm( new QgsShortestPathPointToPointAlgorithm() );
|
||||||
addAlgorithm( new QgsSimplifyAlgorithm() );
|
addAlgorithm( new QgsSimplifyAlgorithm() );
|
||||||
addAlgorithm( new QgsSmoothAlgorithm() );
|
addAlgorithm( new QgsSmoothAlgorithm() );
|
||||||
addAlgorithm( new QgsSnapToGridAlgorithm() );
|
addAlgorithm( new QgsSnapToGridAlgorithm() );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user