├── .gitignore ├── .project ├── .pydevproject ├── .settings └── org.eclipse.core.resources.prefs ├── LICENSE ├── Qneat3Exceptions.py ├── Qneat3Framework.py ├── Qneat3Plugin.py ├── Qneat3Provider.py ├── Qneat3Utilities.py ├── README.md ├── __init__.py ├── algs ├── DummyAlgorithm.py ├── IsoAreaAsContoursFromLayer.py ├── IsoAreaAsContoursFromPoint.py ├── IsoAreaAsInterpolationFromLayer.py ├── IsoAreaAsInterpolationFromPoint.py ├── IsoAreaAsPointcloudFromLayer.py ├── IsoAreaAsPointcloudFromPoint.py ├── IsoAreaAsPolygonsFromLayer.py ├── IsoAreaAsPolygonsFromPoint.py ├── IsoAreaAsQneatInterpolationFromPoint.py ├── OdMatrixFromLayersAsLines.py ├── OdMatrixFromLayersAsTable.py ├── OdMatrixFromPointsAsCsv.py ├── OdMatrixFromPointsAsLines.py ├── OdMatrixFromPointsAsTable.py └── ShortestPathBetweenPoints.py ├── icon_qneat3.svg ├── icons ├── icon_dijkstra_onetoone.svg ├── icon_matrix.svg ├── icon_servicearea_contour.svg ├── icon_servicearea_contour_multiple.svg ├── icon_servicearea_interpolation.png ├── icon_servicearea_interpolation_multiple.png ├── icon_servicearea_points.svg ├── icon_servicearea_points_multiple.svg ├── icon_servicearea_polygon.svg ├── icon_servicearea_polygon_missing_import.svg └── icon_servicearea_polygon_multiple.svg ├── metadata.txt └── testdata ├── minimal_testnetwork.cpg ├── minimal_testnetwork.dbf ├── minimal_testnetwork.prj ├── minimal_testnetwork.qpj ├── minimal_testnetwork.shp └── minimal_testnetwork.shx /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .settings/org.eclipse.core.resources.prefs 3 | .project 4 | .pydevproject 5 | *.pyc 6 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | QNEAT3 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | python37 4 | python interpreter 5 | 6 | /${PROJECT_DIR_NAME} 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//algs/DummyAlgorithm.py=utf-8 3 | encoding//algs/IsoAreaAsContoursFromLayer.py=utf-8 4 | encoding//algs/IsoAreaAsContoursFromPoint.py=utf-8 5 | encoding//algs/IsoAreaAsInterpolationFromLayer.py=utf-8 6 | encoding//algs/IsoAreaAsInterpolationFromPoint.py=utf-8 7 | encoding//algs/IsoAreaAsPointcloudFromLayer.py=utf-8 8 | encoding//algs/IsoAreaAsPointcloudFromPoint.py=utf-8 9 | encoding//algs/IsoAreaAsPolygonsFromLayer.py=utf-8 10 | encoding//algs/IsoAreaAsPolygonsFromPoint.py=utf-8 11 | encoding//algs/OdMatrixFromLayersAsLines.py=utf-8 12 | encoding//algs/OdMatrixFromLayersAsTable.py=utf-8 13 | encoding//algs/OdMatrixFromPointsAsCsv.py=utf-8 14 | encoding//algs/OdMatrixFromPointsAsLines.py=utf-8 15 | encoding//algs/OdMatrixFromPointsAsTable.py=utf-8 16 | encoding//algs/ShortestPathBetweenPoints.py=utf-8 17 | encoding/Qneat3Exceptions.py=utf-8 18 | encoding/Qneat3Framework.py=utf-8 19 | encoding/Qneat3Plugin.py=utf-8 20 | encoding/Qneat3Provider.py=utf-8 21 | encoding/Qneat3Utilities.py=utf-8 22 | encoding/__init__.py=utf-8 23 | -------------------------------------------------------------------------------- /Qneat3Exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | Qneat3Exceptions.py 5 | --------------------- 6 | 7 | Date : January 2018 8 | Copyright : (C) 2018 by Clemens Raffler 9 | Email : clemens dot raffler at gmail dot com 10 | *************************************************************************** 11 | * * 12 | * This program is free software; you can redistribute it and/or modify * 13 | * it under the terms of the GNU General Public License as published by * 14 | * the Free Software Foundation; either version 2 of the License, or * 15 | * (at your option) any later version. * 16 | * * 17 | *************************************************************************** 18 | """ 19 | 20 | class Qneat3GeometryException(Exception): 21 | def __init__(self, given_geom_type, expected_geom_type): 22 | 23 | self.message = "Dataset has wrong geometry type. Got {} dataset but expected {} dataset instead. ".format( given_geom_type, expected_geom_type) 24 | 25 | super(Qneat3GeometryException, self).__init__(self.message) 26 | 27 | class Qneat3CrsException(Exception): 28 | def __init__(self, *crs): 29 | 30 | self.message = "Coordinate Reference Systems don't match up: {} Reproject all datasets so that their CRSs match up.".format(list(crs)) 31 | 32 | super(Qneat3CrsException, self).__init__(self.message) -------------------------------------------------------------------------------- /Qneat3Plugin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | Qneat3Plugin.py 5 | --------------------- 6 | 7 | Date : January 2018 8 | Copyright : (C) 2018 by Clemens Raffler 9 | Email : clemens dot raffler at gmail dot com 10 | *************************************************************************** 11 | * * 12 | * This program is free software; you can redistribute it and/or modify * 13 | * it under the terms of the GNU General Public License as published by * 14 | * the Free Software Foundation; either version 2 of the License, or * 15 | * (at your option) any later version. * 16 | * * 17 | *************************************************************************** 18 | """ 19 | 20 | 21 | from QNEAT3.Qneat3Provider import Qneat3Provider 22 | from qgis.core import QgsApplication 23 | 24 | class Qneat3Plugin: 25 | def __init__(self, iface): 26 | self.provider = None 27 | 28 | def initProcessing(self): 29 | self.provider = Qneat3Provider() 30 | QgsApplication.processingRegistry().addProvider(self.provider) 31 | 32 | def initGui(self): 33 | self.initProcessing() 34 | 35 | def unload(self): 36 | QgsApplication.processingRegistry().removeProvider(self.provider) 37 | 38 | 39 | -------------------------------------------------------------------------------- /Qneat3Provider.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | /*************************************************************************** 4 | QNEAT3 - Qgis Network Analysis Toolbox 3 5 | A QGIS processing provider for network analysis 6 | 7 | Qneat3Provider.py 8 | 9 | ------------------- 10 | begin : 2018-01-15 11 | copyright : (C) 2018 by Clemens Raffler 12 | email : clemens.raffler@gmail.com 13 | ***************************************************************************/ 14 | 15 | /*************************************************************************** 16 | * * 17 | * This program is free software; you can redistribute it and/or modify * 18 | * it under the terms of the GNU General Public License as published by * 19 | * the Free Software Foundation; either version 2 of the License, or * 20 | * (at your option) any later version. * 21 | * * 22 | ***************************************************************************/ 23 | """ 24 | 25 | import os 26 | 27 | from qgis.core import QgsProcessingProvider 28 | from qgis.PyQt.QtGui import QIcon 29 | 30 | from importlib import util 31 | matplotlib_specification = util.find_spec("matplotlib", "pyplot") 32 | matplotlib_found = matplotlib_specification is not None #evaluates to true if matplotlib.pyplot can be importet 33 | 34 | 35 | #import all algorithms that work with basic qgis modules 36 | from .algs import ( 37 | ShortestPathBetweenPoints, 38 | IsoAreaAsPointcloudFromPoint, 39 | IsoAreaAsPointcloudFromLayer, 40 | IsoAreaAsInterpolationFromPoint, 41 | IsoAreaAsInterpolationFromLayer, 42 | #IsoAreaAsQneatInterpolationFromPoint, 43 | OdMatrixFromPointsAsCsv, 44 | OdMatrixFromPointsAsLines, 45 | OdMatrixFromPointsAsTable, 46 | OdMatrixFromLayersAsTable, 47 | OdMatrixFromLayersAsLines 48 | ) 49 | 50 | #import all algorithms that require manually installed modules 51 | if matplotlib_found: 52 | from .algs import ( 53 | IsoAreaAsContoursFromPoint, 54 | IsoAreaAsContoursFromLayer, 55 | IsoAreaAsPolygonsFromPoint, 56 | IsoAreaAsPolygonsFromLayer 57 | ) 58 | else: #import dummy if manually installed modules are missing 59 | from .algs import ( 60 | DummyAlgorithm 61 | ) 62 | 63 | pluginPath = os.path.split(os.path.dirname(__file__))[0] 64 | 65 | class Qneat3Provider(QgsProcessingProvider): 66 | def __init__(self): 67 | super().__init__() 68 | self.matplotlib_specification = util.find_spec("matplotlib", "pyplot") 69 | self.matplotlib_found = self.matplotlib_specification is not None #evaluates to true if matplotlib.pyplot can be importet 70 | 71 | 72 | def id(self, *args, **kwargs): 73 | return 'qneat3' 74 | 75 | def name(self, *args, **kwargs): 76 | return 'QNEAT3 - Qgis Network Analysis Toolbox' 77 | 78 | def icon(self): 79 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icon_qneat3.svg')) 80 | 81 | def svgIconPath(self): 82 | return os.path.join(pluginPath, 'QNEAT3', 'icon_qneat3.svg') 83 | 84 | def loadAlgorithms(self, *args, **kwargs): 85 | self.addAlgorithm(ShortestPathBetweenPoints.ShortestPathBetweenPoints()) 86 | self.addAlgorithm(IsoAreaAsPointcloudFromPoint.IsoAreaAsPointcloudFromPoint()) 87 | self.addAlgorithm(IsoAreaAsPointcloudFromLayer.IsoAreaAsPointcloudFromLayer()) 88 | self.addAlgorithm(IsoAreaAsInterpolationFromPoint.IsoAreaAsInterpolationFromPoint()) 89 | self.addAlgorithm(IsoAreaAsInterpolationFromLayer.IsoAreaAsInterpolationFromLayer()) 90 | #self.addAlgorithm(IsoAreaAsQneatInterpolationFromPoint.IsoAreaAsQneatInterpolationFromPoint()) 91 | self.addAlgorithm(OdMatrixFromPointsAsCsv.OdMatrixFromPointsAsCsv()) 92 | self.addAlgorithm(OdMatrixFromPointsAsLines.OdMatrixFromPointsAsLines()) 93 | self.addAlgorithm(OdMatrixFromPointsAsTable.OdMatrixFromPointsAsTable()) 94 | self.addAlgorithm(OdMatrixFromLayersAsTable.OdMatrixFromLayersAsTable()) 95 | self.addAlgorithm(OdMatrixFromLayersAsLines.OdMatrixFromLayersAsLines()) 96 | 97 | if self.matplotlib_found: 98 | self.addAlgorithm(IsoAreaAsContoursFromPoint.IsoAreaAsContoursFromPoint()) 99 | self.addAlgorithm(IsoAreaAsPolygonsFromPoint.IsoAreaAsPolygonsFromPoint()) 100 | self.addAlgorithm(IsoAreaAsPolygonsFromLayer.IsoAreaAsPolygonsFromLayer()) 101 | self.addAlgorithm(IsoAreaAsContoursFromLayer.IsoAreaAsContoursFromLayer()) 102 | else: 103 | self.addAlgorithm(DummyAlgorithm.DummyAlgorithm()) -------------------------------------------------------------------------------- /Qneat3Utilities.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | Qneat3Utilities.py 5 | --------------------- 6 | 7 | Date : January 2018 8 | Copyright : (C) 2018 by Clemens Raffler 9 | Email : clemens dot raffler at gmail dot com 10 | *************************************************************************** 11 | * * 12 | * This program is free software; you can redistribute it and/or modify * 13 | * it under the terms of the GNU General Public License as published by * 14 | * the Free Software Foundation; either version 2 of the License, or * 15 | * (at your option) any later version. * 16 | * * 17 | *************************************************************************** 18 | """ 19 | 20 | from qgis.core import QgsWkbTypes, QgsMessageLog, QgsVectorLayer, QgsFeature, QgsGeometry, QgsFields, QgsField, QgsFeatureRequest 21 | 22 | from qgis.PyQt.QtCore import QVariant 23 | from QNEAT3.Qneat3Exceptions import Qneat3GeometryException 24 | 25 | def AssignAnalysisCrs(vlayer): 26 | logPanel("Setting analysis CRS") 27 | AnalysisCrs = vlayer.crs() 28 | return AnalysisCrs 29 | 30 | def logPanel(message): 31 | QgsMessageLog.logMessage(message, "QNEAT3") 32 | 33 | def isGeometryType(vlayer, type_obj): 34 | geom_type = vlayer.geometryType() 35 | if geom_type == type_obj: 36 | return True 37 | else: 38 | return False 39 | 40 | def buildQgsVectorLayer(string_geomtype, string_layername, crs, feature_list, list_qgsfield): 41 | 42 | #create new vector layer from self.crs 43 | vector_layer = QgsVectorLayer(string_geomtype, string_layername, "memory") 44 | 45 | #set crs from class 46 | vector_layer.setCrs(crs) 47 | 48 | #set fields 49 | provider = vector_layer.dataProvider() 50 | provider.addAttributes(list_qgsfield) #[QgsField('fid',QVariant.Int),QgsField("origin_point_id", QVariant.Double),QgsField("iso", QVariant.Int)] 51 | vector_layer.updateFields() 52 | 53 | #fill layer with geom and attrs 54 | vector_layer.startEditing() 55 | for feat in feature_list: 56 | vector_layer.addFeature(feat, True) 57 | vector_layer.commitChanges() 58 | 59 | return vector_layer 60 | 61 | def getFeatureFromPointParameter(qgs_point_xy): 62 | feature = QgsFeature() 63 | fields = QgsFields() 64 | fields.append(QgsField('point_id', QVariant.String, '', 254, 0)) 65 | feature.setFields(fields) 66 | feature.setGeometry(QgsGeometry.fromPointXY(qgs_point_xy)) 67 | feature['point_id']="Start Point" 68 | return feature 69 | 70 | def getFeaturesFromQgsIterable(qgs_feature_storage):#qgs_feature_storage can be any vectorLayer/QgsProcessingParameterFeatureSource/etc 71 | fRequest = QgsFeatureRequest().setFilterFids(qgs_feature_storage.allFeatureIds()) 72 | return qgs_feature_storage.getFeatures(fRequest) 73 | 74 | def mergeFeaturesFromQgsIterable(qgs_feature_storage_list): 75 | result_feature_list = [] 76 | for qgs_feature_storage in qgs_feature_storage_list: 77 | fRequest = QgsFeatureRequest().setFilterFids(qgs_feature_storage.allFeatureIds()) 78 | result_feature_list.extend(qgs_feature_storage.getFeatures(fRequest)) 79 | return result_feature_list 80 | 81 | 82 | def getFieldIndexFromQgsProcessingFeatureSource(feature_source, field_name): 83 | if field_name != "": 84 | return feature_source.fields().lookupField(field_name) 85 | else: 86 | return -1 87 | 88 | def getListOfPoints(qgs_feature_storage): #qgs_feature_storage can be any vectorLayer/QgsProcessingParameterFeatureSource/etc 89 | given_geom_type = qgs_feature_storage.wkbType() #GetStringRepresentation of WKB Type 90 | 91 | if given_geom_type == QgsWkbTypes().Point: 92 | qgsfeatureiterator = getFeaturesFromQgsIterable(qgs_feature_storage) 93 | return [f.geometry().asPoint() for f in qgsfeatureiterator] 94 | else: 95 | raise Qneat3GeometryException(given_geom_type, QgsWkbTypes().Point) 96 | 97 | def getFieldDatatype(qgs_feature_storage, fieldname): 98 | fields_list = qgs_feature_storage.fields() 99 | qvariant_type = fields_list.field(fieldname).type() 100 | return qvariant_type 101 | 102 | def getFieldDatatypeFromPythontype(pythonvar): 103 | if isinstance(pythonvar, str): 104 | return QVariant.String 105 | elif isinstance(pythonvar, int): 106 | return QVariant.Int 107 | elif isinstance(pythonvar, float): 108 | return QVariant.Double 109 | else: 110 | return QVariant.String 111 | 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QNEAT3 2 | 3 | The QNEAT3 (short for Qgis Network Analysis Toolbox 3) Plugin aims to provide sophisticated QGIS Processing-Toolbox algorithms in the Field of Network Analysis. In order to assure usability and consitency in the QGIS software design, the QNEAT3-Plugin is not designed as a simple GUI extension but as an QGIS Processing provider for Processing toolbox algorithms. Further information will be provided at the corresponding [ResearchGate](https://www.researchgate.net/project/Design-of-advanced-network-analysis-algorithms-for-the-QGIS-processing-library) project-website. 4 | 5 | ### Currently implemented algorithms: 6 | - **Shortest Path** (Dijkstra) between two points (pairs of coordinates obtained by using QGIS-GUI) 7 | - **Origin-Destination Matrices** Matrix between all points of a layer. 8 | - **ISO-Area Algorithms** Algorithms for isochrone area calculation (pointcloud, interpolation-based raster, contours and polygon) -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | __init__.py 5 | --------------------- 6 | 7 | Date : January 2018 8 | Copyright : (C) 2018 by Clemens Raffler 9 | Email : clemens dot raffler at gmail dot com 10 | *************************************************************************** 11 | * * 12 | * This program is free software; you can redistribute it and/or modify * 13 | * it under the terms of the GNU General Public License as published by * 14 | * the Free Software Foundation; either version 2 of the License, or * 15 | * (at your option) any later version. * 16 | * * 17 | *************************************************************************** 18 | """ 19 | 20 | 21 | def classFactory(iface): 22 | from .Qneat3Plugin import Qneat3Plugin 23 | return Qneat3Plugin(iface) 24 | 25 | -------------------------------------------------------------------------------- /algs/DummyAlgorithm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | DummyAlgorithm.py 5 | --------------------- 6 | Date : February 2018 7 | Copyright : (C) 2018 by Clemens Raffler 8 | Email : clemens dot raffler at gmail dot com 9 | *************************************************************************** 10 | * * 11 | * This program is free software; you can redistribute it and/or modify * 12 | * it under the terms of the GNU General Public License as published by * 13 | * the Free Software Foundation; either version 2 of the License, or * 14 | * (at your option) any later version. * 15 | * * 16 | *************************************************************************** 17 | """ 18 | 19 | __author__ = 'Clemens Raffler' 20 | __date__ = 'February 2018' 21 | __copyright__ = '(C) 2018, Clemens Raffler' 22 | 23 | # This will get replaced with a git SHA1 when you do a git archive 24 | 25 | __revision__ = '$Format:%H$' 26 | 27 | import os 28 | 29 | from qgis.PyQt.QtGui import QIcon 30 | from qgis.core import QgsProcessingParameterString 31 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 32 | 33 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 34 | 35 | 36 | class DummyAlgorithm(QgisAlgorithm): 37 | 38 | MESSAGE1 = 'MESSAGE1' 39 | MESSAGE2 = 'MESSAGE2' 40 | 41 | def icon(self): 42 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_polygon_missing_import.svg')) 43 | 44 | def group(self): 45 | return self.tr('Iso-Areas') 46 | 47 | def groupId(self): 48 | return 'isoareas' 49 | 50 | def name(self): 51 | return 'DummyAlgorithmIsoAreas' 52 | 53 | def displayName(self): 54 | return self.tr('[matplotlib not installed] Iso-Area as Polygon (open for install help)') 55 | 56 | def print_typestring(self, var): 57 | return "Type:"+str(type(var))+" repr: "+var.__str__() 58 | 59 | def __init__(self): 60 | super().__init__() 61 | 62 | def initAlgorithm(self, config=None): 63 | self.addParameter(QgsProcessingParameterString(self.MESSAGE1, self.tr("[matplotlib not installed]
Some QNEAT3 isochrone area algorithms require matplotlib so that they can be executed properly. Depending on your operating system you may install matplotlib manually using the following options:

Windows:
  1. Open the OSGeo4W shell that has been installed alongside QGIS (click Start - type OSGeo4W Shell - hit Enter)
  2. Copy the command displayed in the textbox below and paste it into the shell
  3. Accept the installation by typing 'yes' when prompted
"), self.tr('python-qgis -m pip install matplotlib'), False, False)) 64 | self.addParameter(QgsProcessingParameterString(self.MESSAGE2, self.tr("
Linux
  1. Open a terminal
  2. Copy the command displayed below and paste it into the terminal, then hit Enter and confirm installation with 'yes' when prompted
"), self.tr("pip install matplotlib"),False,False)) 65 | 66 | def processAlgorithm(self, parameters, context, feedback): 67 | output_message = self.parameterAsString(parameters, self.MESSAGE1, context) 68 | feedback.pushInfo("You need to install matplotlib to enable this algorithm.") 69 | 70 | results = {} 71 | results[self.MESSAGE1] = 'Refer to the help provided in the algorithm.' 72 | return results 73 | 74 | -------------------------------------------------------------------------------- /algs/IsoAreaAsContoursFromLayer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | IsoAreaAsContourFromLayer.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : February 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtCore import QVariant 35 | from qgis.PyQt.QtGui import QIcon 36 | 37 | from qgis.core import (QgsWkbTypes, 38 | QgsVectorLayer, 39 | QgsFeatureSink, 40 | QgsFields, 41 | QgsField, 42 | QgsProcessing, 43 | QgsProcessingParameterEnum, 44 | QgsProcessingParameterField, 45 | QgsProcessingParameterNumber, 46 | QgsProcessingParameterRasterDestination, 47 | QgsProcessingParameterString, 48 | QgsProcessingParameterFeatureSource, 49 | QgsProcessingParameterFeatureSink, 50 | QgsProcessingParameterDefinition) 51 | 52 | from qgis.analysis import QgsVectorLayerDirector 53 | 54 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 55 | from QNEAT3.Qneat3Utilities import getListOfPoints, getFeaturesFromQgsIterable 56 | 57 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 58 | 59 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 60 | 61 | 62 | class IsoAreaAsContoursFromLayer(QgisAlgorithm): 63 | 64 | INPUT = 'INPUT' 65 | START_POINTS = 'START_POINTS' 66 | ID_FIELD = 'ID_FIELD' 67 | MAX_DIST = "MAX_DIST" 68 | CELL_SIZE = "CELL_SIZE" 69 | INTERVAL = "INTERVAL" 70 | STRATEGY = 'STRATEGY' 71 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 72 | DIRECTION_FIELD = 'DIRECTION_FIELD' 73 | VALUE_FORWARD = 'VALUE_FORWARD' 74 | VALUE_BACKWARD = 'VALUE_BACKWARD' 75 | VALUE_BOTH = 'VALUE_BOTH' 76 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 77 | SPEED_FIELD = 'SPEED_FIELD' 78 | DEFAULT_SPEED = 'DEFAULT_SPEED' 79 | TOLERANCE = 'TOLERANCE' 80 | OUTPUT_INTERPOLATION = 'OUTPUT_INTERPOLATION' 81 | OUTPUT_CONTOURS = 'OUTPUT_CONTOURS' 82 | 83 | def icon(self): 84 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_contour_multiple.svg')) 85 | 86 | def group(self): 87 | return self.tr('Iso-Areas') 88 | 89 | def groupId(self): 90 | return 'isoareas' 91 | 92 | def name(self): 93 | return 'isoareaascontoursfromlayer' 94 | 95 | def displayName(self): 96 | return self.tr('Iso-Area as Contours (from Layer)') 97 | 98 | def shortHelpString(self): 99 | return "General:
"\ 100 | "This algorithm implements iso-area contours to return the isochrone areas for a maximum cost level and interval levels on a given network dataset for a layer of points.
"\ 101 | "It accounts for points outside of the network (eg. non-network-elements) and increments the iso-areas cost regarding to distance/default speed value. Distances are measured accounting for ellipsoids.
Please, only use a projected coordinate system (eg. no WGS84) for this kind of analysis.

"\ 102 | "Parameters (required):
"\ 103 | "Following Parameters must be set to run the algorithm:"\ 104 | "
"\ 105 | "Parameters (optional):
"\ 106 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 107 | "
"\ 108 | "Output:
"\ 109 | "The output of the algorithm are two layers:"\ 110 | "" 111 | 112 | def msg(self, var): 113 | return "Type:"+str(type(var))+" repr: "+var.__str__() 114 | 115 | def __init__(self): 116 | super().__init__() 117 | 118 | def initAlgorithm(self, config=None): 119 | self.DIRECTIONS = OrderedDict([ 120 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 121 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 122 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 123 | 124 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 125 | self.tr('Fastest Path (time optimization)') 126 | ] 127 | 128 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Planar (only use with projected CRS)')] 129 | 130 | 131 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 132 | self.tr('Network Layer'), 133 | [QgsProcessing.TypeVectorLine])) 134 | self.addParameter(QgsProcessingParameterFeatureSource(self.START_POINTS, 135 | self.tr('Start Points'), 136 | [QgsProcessing.TypeVectorPoint])) 137 | self.addParameter(QgsProcessingParameterField(self.ID_FIELD, 138 | self.tr('Unique Point ID Field'), 139 | None, 140 | self.START_POINTS, 141 | optional=False)) 142 | self.addParameter(QgsProcessingParameterNumber(self.MAX_DIST, 143 | self.tr('Size of Iso-Area (distance or time value)'), 144 | QgsProcessingParameterNumber.Double, 145 | 2500.0, False, 0, 99999999.99)) 146 | self.addParameter(QgsProcessingParameterNumber(self.INTERVAL, 147 | self.tr('Contour Interval (distance or time value)'), 148 | QgsProcessingParameterNumber.Double, 149 | 500.0, False, 0, 99999999.99)) 150 | self.addParameter(QgsProcessingParameterNumber(self.CELL_SIZE, 151 | self.tr('Cellsize of interpolation raster'), 152 | QgsProcessingParameterNumber.Integer, 153 | 10, False, 1, 99999999)) 154 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 155 | self.tr('Optimization Criterion'), 156 | self.STRATEGIES, 157 | defaultValue=0)) 158 | 159 | params = [] 160 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 161 | self.tr('Entry Cost calculation method'), 162 | self.ENTRY_COST_CALCULATION_METHODS, 163 | defaultValue=0)) 164 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 165 | self.tr('Direction field'), 166 | None, 167 | self.INPUT, 168 | optional=True)) 169 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 170 | self.tr('Value for forward direction'), 171 | optional=True)) 172 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 173 | self.tr('Value for backward direction'), 174 | optional=True)) 175 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 176 | self.tr('Value for both directions'), 177 | optional=True)) 178 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 179 | self.tr('Default direction'), 180 | list(self.DIRECTIONS.keys()), 181 | defaultValue=2)) 182 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 183 | self.tr('Speed field'), 184 | None, 185 | self.INPUT, 186 | optional=True)) 187 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 188 | self.tr('Default speed (km/h)'), 189 | QgsProcessingParameterNumber.Double, 190 | 5.0, False, 0, 99999999.99)) 191 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 192 | self.tr('Topology tolerance'), 193 | QgsProcessingParameterNumber.Double, 194 | 0.0, False, 0, 99999999.99)) 195 | 196 | for p in params: 197 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 198 | self.addParameter(p) 199 | 200 | self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT_INTERPOLATION, self.tr('Output Interpolation'))) 201 | self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_CONTOURS, self.tr('Output Contours'), QgsProcessing.TypeVectorLine)) 202 | 203 | def processAlgorithm(self, parameters, context, feedback): 204 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 205 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 206 | startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) #QgsProcessingFeatureSource 207 | id_field = self.parameterAsString(parameters, self.ID_FIELD, context) #str 208 | interval = self.parameterAsDouble(parameters, self.INTERVAL, context)#float 209 | max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float 210 | cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int 211 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 212 | 213 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 214 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 215 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 216 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 217 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 218 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 219 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 220 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 221 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 222 | output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT_INTERPOLATION, context) #string 223 | 224 | analysisCrs = network.sourceCrs() 225 | input_coordinates = getListOfPoints(startPoints) 226 | 227 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 228 | feedback.setProgress(10) 229 | net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 230 | feedback.setProgress(40) 231 | 232 | list_apoints = [Qneat3AnalysisPoint("from", feature, id_field, net, net.list_tiedPoints[i], entry_cost_calc_method, feedback) for i, feature in enumerate(getFeaturesFromQgsIterable(startPoints))] 233 | 234 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") 235 | iso_pointcloud = net.calcIsoPoints(list_apoints, max_dist+(max_dist*0.1)) 236 | feedback.setProgress(50) 237 | 238 | uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid()) 239 | 240 | iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory") 241 | iso_pointcloud_provider = iso_pointcloud_layer.dataProvider() 242 | iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) 243 | 244 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...") 245 | net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path) 246 | feedback.setProgress(70) 247 | 248 | fields = QgsFields() 249 | fields.append(QgsField('id', QVariant.Int, '', 254, 0)) 250 | fields.append(QgsField('cost_level', QVariant.Double, '', 20, 7)) 251 | 252 | (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_CONTOURS, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) 253 | 254 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Contours using numpy and matplotlib...") 255 | contour_featurelist = net.calcIsoContours(max_dist, interval, output_path) 256 | feedback.setProgress(90) 257 | 258 | sink.addFeatures(contour_featurelist, QgsFeatureSink.FastInsert) 259 | 260 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 261 | feedback.setProgress(100) 262 | 263 | results = {} 264 | results[self.OUTPUT_INTERPOLATION] = output_path 265 | results[self.OUTPUT_CONTOURS] = dest_id 266 | return results 267 | 268 | -------------------------------------------------------------------------------- /algs/IsoAreaAsContoursFromPoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | IsoAreaAsContourFromPoint.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : February 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtCore import QVariant 35 | from qgis.PyQt.QtGui import QIcon 36 | 37 | from qgis.core import (QgsWkbTypes, 38 | QgsVectorLayer, 39 | QgsFeatureSink, 40 | QgsFields, 41 | QgsField, 42 | QgsProcessing, 43 | QgsProcessingParameterEnum, 44 | QgsProcessingParameterPoint, 45 | QgsProcessingParameterField, 46 | QgsProcessingParameterNumber, 47 | QgsProcessingParameterRasterDestination, 48 | QgsProcessingParameterString, 49 | QgsProcessingParameterFeatureSource, 50 | QgsProcessingParameterFeatureSink, 51 | QgsProcessingParameterDefinition) 52 | 53 | from qgis.analysis import QgsVectorLayerDirector 54 | 55 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 56 | from QNEAT3.Qneat3Utilities import getFeatureFromPointParameter 57 | 58 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 59 | 60 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 61 | 62 | 63 | class IsoAreaAsContoursFromPoint(QgisAlgorithm): 64 | 65 | INPUT = 'INPUT' 66 | START_POINT = 'START_POINT' 67 | MAX_DIST = "MAX_DIST" 68 | CELL_SIZE = "CELL_SIZE" 69 | INTERVAL = "INTERVAL" 70 | STRATEGY = 'STRATEGY' 71 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 72 | DIRECTION_FIELD = 'DIRECTION_FIELD' 73 | VALUE_FORWARD = 'VALUE_FORWARD' 74 | VALUE_BACKWARD = 'VALUE_BACKWARD' 75 | VALUE_BOTH = 'VALUE_BOTH' 76 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 77 | SPEED_FIELD = 'SPEED_FIELD' 78 | DEFAULT_SPEED = 'DEFAULT_SPEED' 79 | TOLERANCE = 'TOLERANCE' 80 | OUTPUT_INTERPOLATION = 'OUTPUT_INTERPOLATION' 81 | OUTPUT_CONTOURS = 'OUTPUT_CONTOURS' 82 | 83 | def icon(self): 84 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_contour.svg')) 85 | 86 | def group(self): 87 | return self.tr('Iso-Areas') 88 | 89 | def groupId(self): 90 | return 'isoareas' 91 | 92 | def name(self): 93 | return 'isoareaascontoursfrompoint' 94 | 95 | def displayName(self): 96 | return self.tr('Iso-Area as Contours (from Point)') 97 | 98 | def shortHelpString(self): 99 | return "General:
"\ 100 | "This algorithm implements isochrone contours to return the isochrone areas for a maximum cost level and interval levels on a given network dataset for a manually chosen point.
"\ 101 | "It accounts for points outside of the network (eg. non-network-elements) and increments the isochrone areas cost regarding to distance/default speed value. Distances are measured accounting for ellipsoids.
Please, only use a projected coordinate system (eg. no WGS84) for this kind of analysis.

"\ 102 | "Parameters (required):
"\ 103 | "Following Parameters must be set to run the algorithm:"\ 104 | "
"\ 105 | "Parameters (optional):
"\ 106 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 107 | "
"\ 108 | "Output:
"\ 109 | "The output of the algorithm are two layers:"\ 110 | "" 111 | 112 | 113 | def msg(self, var): 114 | return "Type:"+str(type(var))+" repr: "+var.__str__() 115 | 116 | def __init__(self): 117 | super().__init__() 118 | 119 | def initAlgorithm(self, config=None): 120 | self.DIRECTIONS = OrderedDict([ 121 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 122 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 123 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 124 | 125 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 126 | self.tr('Fastest Path (time optimization)') 127 | ] 128 | 129 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Planar (only use with projected CRS)')] 130 | 131 | 132 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 133 | self.tr('Network Layer'), 134 | [QgsProcessing.TypeVectorLine])) 135 | self.addParameter(QgsProcessingParameterPoint(self.START_POINT, 136 | self.tr('Start point'))) 137 | self.addParameter(QgsProcessingParameterNumber(self.MAX_DIST, 138 | self.tr('Size of Iso-Area (distance or time value)'), 139 | QgsProcessingParameterNumber.Double, 140 | 2500.0, False, 0, 99999999.99)) 141 | self.addParameter(QgsProcessingParameterNumber(self.INTERVAL, 142 | self.tr('Contour Interval (distance or time value)'), 143 | QgsProcessingParameterNumber.Double, 144 | 500.0, False, 0, 99999999.99)) 145 | self.addParameter(QgsProcessingParameterNumber(self.CELL_SIZE, 146 | self.tr('Cellsize of interpolation raster'), 147 | QgsProcessingParameterNumber.Integer, 148 | 10, False, 1, 99999999)) 149 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 150 | self.tr('Optimization Criterion'), 151 | self.STRATEGIES, 152 | defaultValue=0)) 153 | 154 | params = [] 155 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 156 | self.tr('Entry Cost calculation method'), 157 | self.ENTRY_COST_CALCULATION_METHODS, 158 | defaultValue=0)) 159 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 160 | self.tr('Direction field'), 161 | None, 162 | self.INPUT, 163 | optional=True)) 164 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 165 | self.tr('Value for forward direction'), 166 | optional=True)) 167 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 168 | self.tr('Value for backward direction'), 169 | optional=True)) 170 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 171 | self.tr('Value for both directions'), 172 | optional=True)) 173 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 174 | self.tr('Default direction'), 175 | list(self.DIRECTIONS.keys()), 176 | defaultValue=2)) 177 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 178 | self.tr('Speed field'), 179 | None, 180 | self.INPUT, 181 | optional=True)) 182 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 183 | self.tr('Default speed (km/h)'), 184 | QgsProcessingParameterNumber.Double, 185 | 5.0, False, 0, 99999999.99)) 186 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 187 | self.tr('Topology tolerance'), 188 | QgsProcessingParameterNumber.Double, 189 | 0.0, False, 0, 99999999.99)) 190 | 191 | for p in params: 192 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 193 | self.addParameter(p) 194 | 195 | self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT_INTERPOLATION, self.tr('Output Interpolation'))) 196 | self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_CONTOURS, self.tr('Output Contours'), QgsProcessing.TypeVectorLine)) 197 | 198 | def processAlgorithm(self, parameters, context, feedback): 199 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 200 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 201 | startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) #QgsPointXY 202 | interval = self.parameterAsDouble(parameters, self.INTERVAL, context)#float 203 | max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float 204 | cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int 205 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 206 | 207 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 208 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 209 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 210 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 211 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 212 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 213 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 214 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 215 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 216 | output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT_INTERPOLATION, context) #string 217 | 218 | analysisCrs = network.sourceCrs() 219 | input_coordinates = [startPoint] 220 | input_point = getFeatureFromPointParameter(startPoint) 221 | 222 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 223 | feedback.setProgress(10) 224 | net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 225 | feedback.setProgress(40) 226 | 227 | analysis_point = Qneat3AnalysisPoint("point", input_point, "point_id", net, net.list_tiedPoints[0], entry_cost_calc_method, feedback) 228 | 229 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") 230 | iso_pointcloud = net.calcIsoPoints([analysis_point], (max_dist+(max_dist*0.1))) 231 | feedback.setProgress(50) 232 | 233 | uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid()) 234 | 235 | iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory") 236 | iso_pointcloud_provider = iso_pointcloud_layer.dataProvider() 237 | iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) 238 | 239 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...") 240 | net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path) 241 | feedback.setProgress(70) 242 | 243 | fields = QgsFields() 244 | fields.append(QgsField('id', QVariant.Int, '', 254, 0)) 245 | fields.append(QgsField('cost_level', QVariant.Double, '', 20, 7)) 246 | 247 | (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_CONTOURS, context, fields, QgsWkbTypes.LineString, network.sourceCrs()) 248 | 249 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Contours using numpy and matplotlib...") 250 | contour_featurelist = net.calcIsoContours(max_dist, interval, output_path) 251 | feedback.setProgress(90) 252 | 253 | sink.addFeatures(contour_featurelist, QgsFeatureSink.FastInsert) 254 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 255 | feedback.setProgress(100) 256 | 257 | results = {} 258 | results[self.OUTPUT_INTERPOLATION] = output_path 259 | results[self.OUTPUT_CONTOURS] = dest_id 260 | return results 261 | 262 | -------------------------------------------------------------------------------- /algs/IsoAreaAsInterpolationFromLayer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | IsoAreaAsInterpolationFromLayer.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : March 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtGui import QIcon 35 | 36 | from qgis.core import (QgsFeatureSink, 37 | QgsVectorLayer, 38 | QgsProcessing, 39 | QgsProcessingParameterEnum, 40 | QgsProcessingParameterField, 41 | QgsProcessingParameterNumber, 42 | QgsProcessingParameterString, 43 | QgsProcessingParameterFeatureSource, 44 | QgsProcessingParameterRasterDestination, 45 | QgsProcessingParameterDefinition) 46 | 47 | from qgis.analysis import QgsVectorLayerDirector 48 | 49 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 50 | from QNEAT3.Qneat3Utilities import getListOfPoints, getFeaturesFromQgsIterable 51 | 52 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 53 | 54 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 55 | 56 | 57 | class IsoAreaAsInterpolationFromLayer(QgisAlgorithm): 58 | 59 | INPUT = 'INPUT' 60 | START_POINTS = 'START_POINTS' 61 | ID_FIELD = 'ID_FIELD' 62 | MAX_DIST = "MAX_DIST" 63 | CELL_SIZE = "CELL_SIZE" 64 | STRATEGY = 'STRATEGY' 65 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 66 | DIRECTION_FIELD = 'DIRECTION_FIELD' 67 | VALUE_FORWARD = 'VALUE_FORWARD' 68 | VALUE_BACKWARD = 'VALUE_BACKWARD' 69 | VALUE_BOTH = 'VALUE_BOTH' 70 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 71 | SPEED_FIELD = 'SPEED_FIELD' 72 | DEFAULT_SPEED = 'DEFAULT_SPEED' 73 | TOLERANCE = 'TOLERANCE' 74 | OUTPUT = 'OUTPUT' 75 | 76 | def icon(self): 77 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_interpolation_multiple.png')) 78 | 79 | def group(self): 80 | return self.tr('Iso-Areas') 81 | 82 | def groupId(self): 83 | return 'isoareas' 84 | 85 | def name(self): 86 | return 'isoareaasinterpolationfromlayer' 87 | 88 | def displayName(self): 89 | return self.tr('Iso-Area as Interpolation (from Layer)') 90 | 91 | def shortHelpString(self): 92 | return "General:
"\ 93 | "This algorithm implements iso-area analysis to return the network-distance interpolation for a maximum cost level on a given network dataset for a layer of points.
"\ 94 | "It accounts for points outside of the network (eg. non-network-elements) and increments the iso-areas cost regarding to distance/default speed value. Distances are measured accounting for ellipsoids.
Please, only use a projected coordinate system (eg. no WGS84) for this kind of analysis.

"\ 95 | "Parameters (required):
"\ 96 | "Following Parameters must be set to run the algorithm:"\ 97 | "
"\ 98 | "Parameters (optional):
"\ 99 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 100 | "
"\ 101 | "Output:
"\ 102 | "The output of the algorithm is one layer:"\ 103 | "" 104 | 105 | 106 | def msg(self, var): 107 | return "Type:"+str(type(var))+" repr: "+var.__str__() 108 | 109 | def __init__(self): 110 | super().__init__() 111 | 112 | def initAlgorithm(self, config=None): 113 | self.DIRECTIONS = OrderedDict([ 114 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 115 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 116 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 117 | 118 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 119 | self.tr('Fastest Path (time optimization)') 120 | ] 121 | 122 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Planar (only use with projected CRS)')] 123 | 124 | 125 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 126 | self.tr('Network Layer'), 127 | [QgsProcessing.TypeVectorLine])) 128 | self.addParameter(QgsProcessingParameterFeatureSource(self.START_POINTS, 129 | self.tr('Start Points'), 130 | [QgsProcessing.TypeVectorPoint])) 131 | self.addParameter(QgsProcessingParameterField(self.ID_FIELD, 132 | self.tr('Unique Point ID Field'), 133 | None, 134 | self.START_POINTS, 135 | optional=False)) 136 | self.addParameter(QgsProcessingParameterNumber(self.MAX_DIST, 137 | self.tr('Size of Iso-Area (distance or time value)'), 138 | QgsProcessingParameterNumber.Double, 139 | 2500.0, False, 0, 99999999.99)) 140 | self.addParameter(QgsProcessingParameterNumber(self.CELL_SIZE, 141 | self.tr('Cellsize of interpolation raster'), 142 | QgsProcessingParameterNumber.Integer, 143 | 10, False, 1, 99999999)) 144 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 145 | self.tr('Optimization Criterion'), 146 | self.STRATEGIES, 147 | defaultValue=0)) 148 | 149 | params = [] 150 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 151 | self.tr('Entry Cost calculation method'), 152 | self.ENTRY_COST_CALCULATION_METHODS, 153 | defaultValue=0)) 154 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 155 | self.tr('Direction field'), 156 | None, 157 | self.INPUT, 158 | optional=True)) 159 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 160 | self.tr('Value for forward direction'), 161 | optional=True)) 162 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 163 | self.tr('Value for backward direction'), 164 | optional=True)) 165 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 166 | self.tr('Value for both directions'), 167 | optional=True)) 168 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 169 | self.tr('Default direction'), 170 | list(self.DIRECTIONS.keys()), 171 | defaultValue=2)) 172 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 173 | self.tr('Speed field'), 174 | None, 175 | self.INPUT, 176 | optional=True)) 177 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 178 | self.tr('Default speed (km/h)'), 179 | QgsProcessingParameterNumber.Double, 180 | 5.0, False, 0, 99999999.99)) 181 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 182 | self.tr('Topology tolerance'), 183 | QgsProcessingParameterNumber.Double, 184 | 0.0, False, 0, 99999999.99)) 185 | 186 | for p in params: 187 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 188 | self.addParameter(p) 189 | 190 | self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Output Interpolation'))) 191 | 192 | def processAlgorithm(self, parameters, context, feedback): 193 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 194 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 195 | startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) #QgsProcessingFeatureSource 196 | id_field = self.parameterAsString(parameters, self.ID_FIELD, context) #str 197 | max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float 198 | cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int 199 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 200 | 201 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 202 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 203 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 204 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 205 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 206 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 207 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 208 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 209 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 210 | output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) 211 | 212 | analysisCrs = network.sourceCrs() 213 | input_coordinates = getListOfPoints(startPoints) 214 | 215 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 216 | feedback.setProgress(10) 217 | net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 218 | feedback.setProgress(40) 219 | 220 | list_apoints = [Qneat3AnalysisPoint("from", feature, id_field, net, net.list_tiedPoints[i], entry_cost_calc_method, feedback) for i, feature in enumerate(getFeaturesFromQgsIterable(startPoints))] 221 | 222 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") 223 | iso_pointcloud = net.calcIsoPoints(list_apoints, max_dist) 224 | feedback.setProgress(70) 225 | 226 | uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid()) 227 | 228 | iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory") 229 | iso_pointcloud_provider = iso_pointcloud_layer.dataProvider() 230 | iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) 231 | 232 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...") 233 | net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path) 234 | feedback.setProgress(99) 235 | 236 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 237 | feedback.setProgress(100) 238 | 239 | results = {} 240 | results[self.OUTPUT] = output_path 241 | return results 242 | 243 | -------------------------------------------------------------------------------- /algs/IsoAreaAsInterpolationFromPoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | IsoAreaAsInterpolationPoint.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : March 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtGui import QIcon 35 | 36 | from qgis.core import (QgsFeatureSink, 37 | QgsVectorLayer, 38 | QgsProcessing, 39 | QgsProcessingParameterEnum, 40 | QgsProcessingParameterPoint, 41 | QgsProcessingParameterField, 42 | QgsProcessingParameterNumber, 43 | QgsProcessingParameterString, 44 | QgsProcessingParameterFeatureSource, 45 | QgsProcessingParameterRasterDestination, 46 | QgsProcessingParameterDefinition) 47 | 48 | from qgis.analysis import QgsVectorLayerDirector 49 | 50 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 51 | from QNEAT3.Qneat3Utilities import getFeatureFromPointParameter 52 | 53 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 54 | 55 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 56 | 57 | 58 | class IsoAreaAsInterpolationFromPoint(QgisAlgorithm): 59 | 60 | INPUT = 'INPUT' 61 | START_POINT = 'START_POINT' 62 | MAX_DIST = "MAX_DIST" 63 | CELL_SIZE = "CELL_SIZE" 64 | STRATEGY = 'STRATEGY' 65 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 66 | DIRECTION_FIELD = 'DIRECTION_FIELD' 67 | VALUE_FORWARD = 'VALUE_FORWARD' 68 | VALUE_BACKWARD = 'VALUE_BACKWARD' 69 | VALUE_BOTH = 'VALUE_BOTH' 70 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 71 | SPEED_FIELD = 'SPEED_FIELD' 72 | DEFAULT_SPEED = 'DEFAULT_SPEED' 73 | TOLERANCE = 'TOLERANCE' 74 | OUTPUT = 'OUTPUT' 75 | 76 | def icon(self): 77 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_interpolation.png')) 78 | 79 | def group(self): 80 | return self.tr('Iso-Areas') 81 | 82 | def groupId(self): 83 | return 'isoareas' 84 | 85 | def name(self): 86 | return 'isoareaasinterpolationfrompoint' 87 | 88 | def displayName(self): 89 | return self.tr('Iso-Area as Interpolation (from Point)') 90 | 91 | def shortHelpString(self): 92 | return "General:
"\ 93 | "This algorithm implements iso-area analysis to return the network-distance interpolation for a maximum cost level on a given network dataset for a manually chosen point.
"\ 94 | "It accounts for points outside of the network (eg. non-network-elements) and increments the iso-areas cost regarding to distance/default speed value. Distances are measured accounting for ellipsoids.
Please, only use a projected coordinate system (eg. no WGS84) for this kind of analysis.

"\ 95 | "Parameters (required):
"\ 96 | "Following Parameters must be set to run the algorithm:"\ 97 | "
"\ 98 | "Parameters (optional):
"\ 99 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 100 | "
"\ 101 | "Output:
"\ 102 | "The output of the algorithm is one layer:"\ 103 | "" 104 | 105 | def msg(self, var): 106 | return "Type:"+str(type(var))+" repr: "+var.__str__() 107 | 108 | def __init__(self): 109 | super().__init__() 110 | 111 | def initAlgorithm(self, config=None): 112 | self.DIRECTIONS = OrderedDict([ 113 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 114 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 115 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 116 | 117 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 118 | self.tr('Fastest Path (time optimization)') 119 | ] 120 | 121 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Planar (only use with projected CRS)')] 122 | 123 | 124 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 125 | self.tr('Network Layer'), 126 | [QgsProcessing.TypeVectorLine])) 127 | self.addParameter(QgsProcessingParameterPoint(self.START_POINT, 128 | self.tr('Start point'))) 129 | self.addParameter(QgsProcessingParameterNumber(self.MAX_DIST, 130 | self.tr('Size of Iso-Area (distance or time value)'), 131 | QgsProcessingParameterNumber.Double, 132 | 2500.0, False, 0, 99999999.99)) 133 | self.addParameter(QgsProcessingParameterNumber(self.CELL_SIZE, 134 | self.tr('Cellsize of interpolation raster'), 135 | QgsProcessingParameterNumber.Integer, 136 | 10, False, 1, 99999999)) 137 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 138 | self.tr('Optimization Criterion'), 139 | self.STRATEGIES, 140 | defaultValue=0)) 141 | 142 | params = [] 143 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 144 | self.tr('Entry Cost calculation method'), 145 | self.ENTRY_COST_CALCULATION_METHODS, 146 | defaultValue=0)) 147 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 148 | self.tr('Direction field'), 149 | None, 150 | self.INPUT, 151 | optional=True)) 152 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 153 | self.tr('Value for forward direction'), 154 | optional=True)) 155 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 156 | self.tr('Value for backward direction'), 157 | optional=True)) 158 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 159 | self.tr('Value for both directions'), 160 | optional=True)) 161 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 162 | self.tr('Default direction'), 163 | list(self.DIRECTIONS.keys()), 164 | defaultValue=2)) 165 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 166 | self.tr('Speed field'), 167 | None, 168 | self.INPUT, 169 | optional=True)) 170 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 171 | self.tr('Default speed (km/h)'), 172 | QgsProcessingParameterNumber.Double, 173 | 5.0, False, 0, 99999999.99)) 174 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 175 | self.tr('Topology tolerance'), 176 | QgsProcessingParameterNumber.Double, 177 | 0.0, False, 0, 99999999.99)) 178 | 179 | for p in params: 180 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 181 | self.addParameter(p) 182 | 183 | self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT, self.tr('Output Interpolation'))) 184 | 185 | def processAlgorithm(self, parameters, context, feedback): 186 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 187 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 188 | startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) #QgsPointXY 189 | max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float 190 | cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int 191 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 192 | 193 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 194 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 195 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 196 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 197 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 198 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 199 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 200 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 201 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 202 | output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) 203 | 204 | analysisCrs = network.sourceCrs() 205 | input_coordinates = [startPoint] 206 | input_point = getFeatureFromPointParameter(startPoint) 207 | 208 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 209 | feedback.setProgress(10) 210 | net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 211 | feedback.setProgress(40) 212 | 213 | analysis_point = Qneat3AnalysisPoint("point", input_point, "point_id", net, net.list_tiedPoints[0], entry_cost_calc_method, feedback) 214 | 215 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") 216 | iso_pointcloud = net.calcIsoPoints([analysis_point], max_dist) 217 | feedback.setProgress(70) 218 | 219 | uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid()) 220 | 221 | iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory") 222 | iso_pointcloud_provider = iso_pointcloud_layer.dataProvider() 223 | iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) 224 | 225 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...") 226 | net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path) 227 | feedback.setProgress(99) 228 | 229 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 230 | feedback.setProgress(100) 231 | 232 | results = {} 233 | results[self.OUTPUT] = output_path 234 | return results 235 | 236 | -------------------------------------------------------------------------------- /algs/IsoAreaAsPointcloudFromLayer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | IsoAreaAsPointcloudFromLayer.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : February 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtCore import QVariant 35 | from qgis.PyQt.QtGui import QIcon 36 | 37 | from qgis.core import (QgsWkbTypes, 38 | QgsFeatureSink, 39 | QgsFields, 40 | QgsField, 41 | QgsProcessing, 42 | QgsProcessingParameterEnum, 43 | QgsProcessingParameterField, 44 | QgsProcessingParameterNumber, 45 | QgsProcessingParameterString, 46 | QgsProcessingParameterFeatureSource, 47 | QgsProcessingParameterFeatureSink, 48 | QgsProcessingParameterDefinition) 49 | 50 | from qgis.analysis import QgsVectorLayerDirector 51 | 52 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 53 | from QNEAT3.Qneat3Utilities import getListOfPoints, getFeaturesFromQgsIterable, getFieldDatatype 54 | 55 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 56 | 57 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 58 | 59 | 60 | class IsoAreaAsPointcloudFromLayer(QgisAlgorithm): 61 | 62 | INPUT = 'INPUT' 63 | START_POINTS = 'START_POINTS' 64 | ID_FIELD = 'ID_FIELD' 65 | MAX_DIST = "MAX_DIST" 66 | STRATEGY = 'STRATEGY' 67 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 68 | DIRECTION_FIELD = 'DIRECTION_FIELD' 69 | VALUE_FORWARD = 'VALUE_FORWARD' 70 | VALUE_BACKWARD = 'VALUE_BACKWARD' 71 | VALUE_BOTH = 'VALUE_BOTH' 72 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 73 | SPEED_FIELD = 'SPEED_FIELD' 74 | DEFAULT_SPEED = 'DEFAULT_SPEED' 75 | TOLERANCE = 'TOLERANCE' 76 | OUTPUT = 'OUTPUT' 77 | 78 | def icon(self): 79 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_points_multiple.svg')) 80 | 81 | def group(self): 82 | return self.tr('Iso-Areas') 83 | 84 | def groupId(self): 85 | return 'isoareas' 86 | 87 | def name(self): 88 | return 'isoareaaspointcloudfromlayer' 89 | 90 | def displayName(self): 91 | return self.tr('Iso-Area as Pointcloud (from Layer)') 92 | 93 | def shortHelpString(self): 94 | return "General:
"\ 95 | "This algorithm implements iso-pointcloud analysis to return all network nodes reachable within a maximum cost level as pointcloud on a given network dataset for a layer of points.
"\ 96 | "It accounts for points outside of the network (eg. non-network-elements) and increments the iso-areas cost regarding to distance/default speed value. Distances are measured accounting for ellipsoids.
Please, only use a projected coordinate system (eg. no WGS84) for this kind of analysis.

"\ 97 | "Parameters (required):
"\ 98 | "Following Parameters must be set to run the algorithm:"\ 99 | "
"\ 100 | "Parameters (optional):
"\ 101 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 102 | "
"\ 103 | "Output:
"\ 104 | "The output of the algorithm is one layer:"\ 105 | "
"\ 106 | "You may use the output pointcloud as input for further analyses." 107 | 108 | def msg(self, var): 109 | return "Type:"+str(type(var))+" repr: "+var.__str__() 110 | 111 | def __init__(self): 112 | super().__init__() 113 | 114 | def initAlgorithm(self, config=None): 115 | self.DIRECTIONS = OrderedDict([ 116 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 117 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 118 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 119 | 120 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 121 | self.tr('Fastest Path (time optimization)') 122 | ] 123 | 124 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Ellipsoidal'), 125 | self.tr('Planar (only use with projected CRS)')] 126 | 127 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 128 | self.tr('Network Layer'), 129 | [QgsProcessing.TypeVectorLine])) 130 | self.addParameter(QgsProcessingParameterFeatureSource(self.START_POINTS, 131 | self.tr('Startpoint Layer'), 132 | [QgsProcessing.TypeVectorPoint])) 133 | self.addParameter(QgsProcessingParameterField(self.ID_FIELD, 134 | self.tr('Unique Point ID Field'), 135 | None, 136 | self.START_POINTS, 137 | optional=False)) 138 | self.addParameter(QgsProcessingParameterNumber(self.MAX_DIST, 139 | self.tr('Size of Iso-Area (Distance or Seconds depending on Strategy)'), 140 | QgsProcessingParameterNumber.Double, 141 | 2500.0, False, 0, 99999999.99)) 142 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 143 | self.tr('Optimization criterion'), 144 | self.STRATEGIES, 145 | defaultValue=0)) 146 | 147 | params = [] 148 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 149 | self.tr('Entry Cost calculation method'), 150 | self.ENTRY_COST_CALCULATION_METHODS, 151 | defaultValue=0)) 152 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 153 | self.tr('Direction field'), 154 | None, 155 | self.INPUT, 156 | optional=True)) 157 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 158 | self.tr('Value for forward direction'), 159 | optional=True)) 160 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 161 | self.tr('Value for backward direction'), 162 | optional=True)) 163 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 164 | self.tr('Value for both directions'), 165 | optional=True)) 166 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 167 | self.tr('Default direction'), 168 | list(self.DIRECTIONS.keys()), 169 | defaultValue=2)) 170 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 171 | self.tr('Speed field'), 172 | None, 173 | self.INPUT, 174 | optional=True)) 175 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 176 | self.tr('Default speed (km/h)'), 177 | QgsProcessingParameterNumber.Double, 178 | 5.0, False, 0, 99999999.99)) 179 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 180 | self.tr('Topology tolerance'), 181 | QgsProcessingParameterNumber.Double, 182 | 0.0, False, 0, 99999999.99)) 183 | 184 | for p in params: 185 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 186 | self.addParameter(p) 187 | 188 | self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, 189 | self.tr('Output Pointcloud'), 190 | QgsProcessing.TypeVectorPoint)) 191 | 192 | def processAlgorithm(self, parameters, context, feedback): 193 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 194 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 195 | startPoints = self.parameterAsSource(parameters, self.START_POINTS, context) #QgsProcessingFeatureSource 196 | id_field = self.parameterAsString(parameters, self.ID_FIELD, context) #str 197 | max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float 198 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 199 | 200 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 201 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 202 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 203 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 204 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 205 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 206 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 207 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 208 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 209 | 210 | analysisCrs = network.sourceCrs() 211 | input_coordinates = getListOfPoints(startPoints) 212 | 213 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 214 | feedback.setProgress(10) 215 | net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 216 | feedback.setProgress(40) 217 | 218 | list_apoints = [Qneat3AnalysisPoint("from", feature, id_field, net, net.list_tiedPoints[i], entry_cost_calc_method, feedback) for i, feature in enumerate(getFeaturesFromQgsIterable(startPoints))] 219 | 220 | fields = QgsFields() 221 | fields.append(QgsField('vertex_id', QVariant.Int, '', 254, 0)) 222 | fields.append(QgsField('cost', QVariant.Double, '', 254, 7)) 223 | fields.append(QgsField('origin_point_id', getFieldDatatype(startPoints, id_field))) 224 | 225 | (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, network.sourceCrs()) 226 | 227 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") 228 | iso_pointcloud = net.calcIsoPoints(list_apoints, max_dist) 229 | feedback.setProgress(90) 230 | 231 | sink.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) 232 | 233 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 234 | feedback.setProgress(100) 235 | 236 | results = {} 237 | results[self.OUTPUT] = dest_id 238 | return results 239 | 240 | -------------------------------------------------------------------------------- /algs/IsoAreaAsPointcloudFromPoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | IsoAreaAsPointcloudFromPoint.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : February 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtCore import QVariant 35 | from qgis.PyQt.QtGui import QIcon 36 | 37 | from qgis.core import (QgsWkbTypes, 38 | QgsFeatureSink, 39 | QgsFields, 40 | QgsField, 41 | QgsProcessing, 42 | QgsProcessingParameterEnum, 43 | QgsProcessingParameterPoint, 44 | QgsProcessingParameterField, 45 | QgsProcessingParameterNumber, 46 | QgsProcessingParameterString, 47 | QgsProcessingParameterFeatureSource, 48 | QgsProcessingParameterFeatureSink, 49 | QgsProcessingParameterDefinition) 50 | 51 | from qgis.analysis import QgsVectorLayerDirector 52 | 53 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 54 | from QNEAT3.Qneat3Utilities import getFeatureFromPointParameter 55 | 56 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 57 | 58 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 59 | 60 | 61 | class IsoAreaAsPointcloudFromPoint(QgisAlgorithm): 62 | 63 | INPUT = 'INPUT' 64 | START_POINT = 'START_POINT' 65 | MAX_DIST = "MAX_DIST" 66 | STRATEGY = 'STRATEGY' 67 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 68 | DIRECTION_FIELD = 'DIRECTION_FIELD' 69 | VALUE_FORWARD = 'VALUE_FORWARD' 70 | VALUE_BACKWARD = 'VALUE_BACKWARD' 71 | VALUE_BOTH = 'VALUE_BOTH' 72 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 73 | SPEED_FIELD = 'SPEED_FIELD' 74 | DEFAULT_SPEED = 'DEFAULT_SPEED' 75 | TOLERANCE = 'TOLERANCE' 76 | OUTPUT = 'OUTPUT' 77 | 78 | def icon(self): 79 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_points.svg')) 80 | 81 | def group(self): 82 | return self.tr('Iso-Areas') 83 | 84 | def groupId(self): 85 | return 'isoareas' 86 | 87 | def name(self): 88 | return 'isoareaaspointcloudfrompoint' 89 | 90 | def displayName(self): 91 | return self.tr('Iso-Area as Pointcloud (from Point)') 92 | 93 | def shortHelpString(self): 94 | return "General:
"\ 95 | "This algorithm implements iso-pointcloud analysis to return all network nodes reachable within a maximum cost level as pointcloud on a given network dataset for a manually chosen point.
"\ 96 | "It accounts for points outside of the network (eg. non-network-elements) and increments the iso-areas cost regarding to distance/default speed value. Distances are measured accounting for ellipsoids.
Please, only use a projected coordinate system (eg. no WGS84) for this kind of analysis.

"\ 97 | "Parameters (required):
"\ 98 | "Following Parameters must be set to run the algorithm:"\ 99 | "
"\ 100 | "Parameters (optional):
"\ 101 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 102 | "
"\ 103 | "Output:
"\ 104 | "The output of the algorithm is one layer:"\ 105 | "
"\ 106 | "You may use the output pointcloud as input for further analyses." 107 | 108 | def msg(self, var): 109 | return "Type:"+str(type(var))+" repr: "+var.__str__() 110 | 111 | def __init__(self): 112 | super().__init__() 113 | 114 | def initAlgorithm(self, config=None): 115 | self.DIRECTIONS = OrderedDict([ 116 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 117 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 118 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 119 | 120 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 121 | self.tr('Fastest Path (time optimization)') 122 | ] 123 | 124 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Ellipsoidal'), 125 | self.tr('Planar (only use with projected CRS)')] 126 | 127 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 128 | self.tr('Network Layer'), 129 | [QgsProcessing.TypeVectorLine])) 130 | self.addParameter(QgsProcessingParameterPoint(self.START_POINT, 131 | self.tr('Start Point'))) 132 | self.addParameter(QgsProcessingParameterNumber(self.MAX_DIST, 133 | self.tr('Size of Iso-Area (distance or seconds depending on strategy)'), 134 | QgsProcessingParameterNumber.Double, 135 | 2500.0, False, 0, 99999999.99)) 136 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 137 | self.tr('Optimization Criterion'), 138 | self.STRATEGIES, 139 | defaultValue=0)) 140 | 141 | params = [] 142 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 143 | self.tr('Entry Cost calculation method'), 144 | self.ENTRY_COST_CALCULATION_METHODS, 145 | defaultValue=0)) 146 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 147 | self.tr('Direction field'), 148 | None, 149 | self.INPUT, 150 | optional=True)) 151 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 152 | self.tr('Value for forward direction'), 153 | optional=True)) 154 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 155 | self.tr('Value for backward direction'), 156 | optional=True)) 157 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 158 | self.tr('Value for both directions'), 159 | optional=True)) 160 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 161 | self.tr('Default direction'), 162 | list(self.DIRECTIONS.keys()), 163 | defaultValue=2)) 164 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 165 | self.tr('Speed field'), 166 | None, 167 | self.INPUT, 168 | optional=True)) 169 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 170 | self.tr('Default speed (km/h)'), 171 | QgsProcessingParameterNumber.Double, 172 | 5.0, False, 0, 99999999.99)) 173 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 174 | self.tr('Topology tolerance'), 175 | QgsProcessingParameterNumber.Double, 176 | 0.0, False, 0, 99999999.99)) 177 | 178 | for p in params: 179 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 180 | self.addParameter(p) 181 | 182 | self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, 183 | self.tr('Output Pointcloud'), 184 | QgsProcessing.TypeVectorPoint)) 185 | 186 | def processAlgorithm(self, parameters, context, feedback): 187 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 188 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 189 | startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) #QgsPointXY 190 | max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float 191 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 192 | 193 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 194 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 195 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 196 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 197 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 198 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 199 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 200 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 201 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 202 | 203 | analysisCrs = network.sourceCrs() 204 | input_coordinates = [startPoint] 205 | input_point = getFeatureFromPointParameter(startPoint) 206 | 207 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 208 | feedback.setProgress(10) 209 | net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 210 | feedback.setProgress(40) 211 | 212 | analysis_point = Qneat3AnalysisPoint("point", input_point, "point_id", net, net.list_tiedPoints[0], entry_cost_calc_method, feedback) 213 | 214 | fields = QgsFields() 215 | fields.append(QgsField('vertex_id', QVariant.Int, '', 254, 0)) 216 | fields.append(QgsField('cost', QVariant.Double, '', 254, 7)) 217 | fields.append(QgsField('origin_point_id',QVariant.String, '', 254, 7)) 218 | 219 | (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, QgsWkbTypes.Point, network.sourceCrs()) 220 | 221 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") 222 | iso_pointcloud = net.calcIsoPoints([analysis_point], max_dist) 223 | feedback.setProgress(90) 224 | 225 | sink.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) 226 | 227 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 228 | feedback.setProgress(100) 229 | 230 | results = {} 231 | results[self.OUTPUT] = dest_id 232 | return results 233 | 234 | -------------------------------------------------------------------------------- /algs/IsoAreaAsPolygonsFromPoint.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | IsoAreaAsPolygonFromPoint.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : April 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'April 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtCore import QVariant 35 | from qgis.PyQt.QtGui import QIcon 36 | 37 | from qgis.core import (QgsWkbTypes, 38 | QgsVectorLayer, 39 | QgsFeatureSink, 40 | QgsFields, 41 | QgsField, 42 | QgsProcessing, 43 | QgsProcessingParameterEnum, 44 | QgsProcessingParameterPoint, 45 | QgsProcessingParameterField, 46 | QgsProcessingParameterNumber, 47 | QgsProcessingParameterRasterDestination, 48 | QgsProcessingParameterString, 49 | QgsProcessingParameterFeatureSource, 50 | QgsProcessingParameterFeatureSink, 51 | QgsProcessingParameterDefinition) 52 | 53 | from qgis.analysis import QgsVectorLayerDirector 54 | 55 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 56 | from QNEAT3.Qneat3Utilities import getFeatureFromPointParameter 57 | 58 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 59 | 60 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 61 | 62 | 63 | class IsoAreaAsPolygonsFromPoint(QgisAlgorithm): 64 | 65 | INPUT = 'INPUT' 66 | START_POINT = 'START_POINT' 67 | MAX_DIST = "MAX_DIST" 68 | CELL_SIZE = "CELL_SIZE" 69 | INTERVAL = "INTERVAL" 70 | STRATEGY = 'STRATEGY' 71 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 72 | DIRECTION_FIELD = 'DIRECTION_FIELD' 73 | VALUE_FORWARD = 'VALUE_FORWARD' 74 | VALUE_BACKWARD = 'VALUE_BACKWARD' 75 | VALUE_BOTH = 'VALUE_BOTH' 76 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 77 | SPEED_FIELD = 'SPEED_FIELD' 78 | DEFAULT_SPEED = 'DEFAULT_SPEED' 79 | TOLERANCE = 'TOLERANCE' 80 | OUTPUT_INTERPOLATION = 'OUTPUT_INTERPOLATION' 81 | OUTPUT_POLYGONS = 'OUTPUT_POLYGONS' 82 | 83 | def icon(self): 84 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_servicearea_polygon.svg')) 85 | 86 | def group(self): 87 | return self.tr('Iso-Areas') 88 | 89 | def groupId(self): 90 | return 'isoareas' 91 | 92 | def shortHelpString(self): 93 | return "General:
"\ 94 | "This algorithm implements iso-area analysis to return the iso-area polygons for a maximum cost level and interval levels on a given network dataset for a manually chosen point.
"\ 95 | "It accounts for points outside of the network (eg. non-network-elements) and increments the iso-areas cost regarding to distance/default speed value. Distances are measured accounting for ellipsoids.
Please, only use a projected coordinate system (eg. no WGS84) for this kind of analysis.

"\ 96 | "Parameters (required):
"\ 97 | "Following Parameters must be set to run the algorithm:"\ 98 | "
"\ 99 | "Parameters (optional):
"\ 100 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 101 | "
"\ 102 | "Output:
"\ 103 | "The output of the algorithm are two layers:"\ 104 | "" 105 | 106 | def name(self): 107 | return 'isoareaaspolygonsfrompoint' 108 | 109 | def displayName(self): 110 | return self.tr('Iso-Area as Polygons (from Point)') 111 | 112 | def msg(self, var): 113 | return "Type:"+str(type(var))+" repr: "+var.__str__() 114 | 115 | def __init__(self): 116 | super().__init__() 117 | 118 | def initAlgorithm(self, config=None): 119 | self.DIRECTIONS = OrderedDict([ 120 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 121 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 122 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 123 | 124 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 125 | self.tr('Fastest Path (time optimization)') 126 | ] 127 | 128 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Planar (only use with projected CRS)')] 129 | 130 | 131 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 132 | self.tr('Network Layer'), 133 | [QgsProcessing.TypeVectorLine])) 134 | self.addParameter(QgsProcessingParameterPoint(self.START_POINT, 135 | self.tr('Start Point'))) 136 | self.addParameter(QgsProcessingParameterNumber(self.MAX_DIST, 137 | self.tr('Size of Iso-Area (distance or time value)'), 138 | QgsProcessingParameterNumber.Double, 139 | 2500.0, False, 0, 99999999.99)) 140 | self.addParameter(QgsProcessingParameterNumber(self.INTERVAL, 141 | self.tr('Contour Interval (distance or time value)'), 142 | QgsProcessingParameterNumber.Double, 143 | 500.0, False, 0, 99999999.99)) 144 | self.addParameter(QgsProcessingParameterNumber(self.CELL_SIZE, 145 | self.tr('Cellsize of interpolation raster'), 146 | QgsProcessingParameterNumber.Integer, 147 | 10, False, 1, 99999999)) 148 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 149 | self.tr('Optimization Criterion'), 150 | self.STRATEGIES, 151 | defaultValue=0)) 152 | 153 | params = [] 154 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 155 | self.tr('Entry Cost calculation method'), 156 | self.ENTRY_COST_CALCULATION_METHODS, 157 | defaultValue=0)) 158 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 159 | self.tr('Direction field'), 160 | None, 161 | self.INPUT, 162 | optional=True)) 163 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 164 | self.tr('Value for forward direction'), 165 | optional=True)) 166 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 167 | self.tr('Value for backward direction'), 168 | optional=True)) 169 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 170 | self.tr('Value for both directions'), 171 | optional=True)) 172 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 173 | self.tr('Default direction'), 174 | list(self.DIRECTIONS.keys()), 175 | defaultValue=2)) 176 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 177 | self.tr('Speed field'), 178 | None, 179 | self.INPUT, 180 | optional=True)) 181 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 182 | self.tr('Default speed (km/h)'), 183 | QgsProcessingParameterNumber.Double, 184 | 5.0, False, 0, 99999999.99)) 185 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 186 | self.tr('Topology tolerance'), 187 | QgsProcessingParameterNumber.Double, 188 | 0.0, False, 0, 99999999.99)) 189 | 190 | for p in params: 191 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 192 | self.addParameter(p) 193 | 194 | self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT_INTERPOLATION, self.tr('Output Interpolation'))) 195 | self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_POLYGONS, self.tr('Output Polygon'), QgsProcessing.TypeVectorPolygon)) 196 | 197 | def processAlgorithm(self, parameters, context, feedback): 198 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 199 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 200 | startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) #QgsPointXY 201 | interval = self.parameterAsDouble(parameters, self.INTERVAL, context)#float 202 | max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float 203 | cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int 204 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 205 | 206 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 207 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 208 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 209 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 210 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 211 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 212 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 213 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 214 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 215 | output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT_INTERPOLATION, context) #string 216 | 217 | analysisCrs = network.sourceCrs() 218 | input_coordinates = [startPoint] 219 | input_point = getFeatureFromPointParameter(startPoint) 220 | 221 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 222 | feedback.setProgress(10) 223 | net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 224 | feedback.setProgress(40) 225 | 226 | analysis_point = Qneat3AnalysisPoint("point", input_point, "point_id", net, net.list_tiedPoints[0], entry_cost_calc_method, feedback) 227 | 228 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") 229 | iso_pointcloud = net.calcIsoPoints([analysis_point], max_dist+(max_dist*0.1)) 230 | feedback.setProgress(50) 231 | 232 | uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid()) 233 | 234 | iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory") 235 | iso_pointcloud_provider = iso_pointcloud_layer.dataProvider() 236 | iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) 237 | 238 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...") 239 | net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path) 240 | feedback.setProgress(70) 241 | 242 | fields = QgsFields() 243 | fields.append(QgsField('id', QVariant.Int, '', 254, 0)) 244 | fields.append(QgsField('cost_level', QVariant.Double, '', 20, 7)) 245 | 246 | (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_POLYGONS, context, fields, QgsWkbTypes.Polygon, network.sourceCrs()) 247 | 248 | feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Polygons using numpy and matplotlib...") 249 | polygon_featurelist = net.calcIsoPolygons(max_dist, interval, output_path) 250 | feedback.setProgress(90) 251 | 252 | sink.addFeatures(polygon_featurelist, QgsFeatureSink.FastInsert) 253 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 254 | feedback.setProgress(100) 255 | 256 | results = {} 257 | results[self.OUTPUT_INTERPOLATION] = output_path 258 | results[self.OUTPUT_POLYGONS] = dest_id 259 | return results 260 | 261 | 262 | -------------------------------------------------------------------------------- /algs/OdMatrixFromPointsAsCsv.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | OdMatrixFromPointsAsCsv.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : February 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | import csv 33 | from collections import OrderedDict 34 | 35 | from qgis.PyQt.QtGui import QIcon 36 | 37 | from qgis.core import (QgsProcessing, 38 | QgsProcessingParameterEnum, 39 | QgsProcessingParameterFileDestination, 40 | QgsProcessingParameterFeatureSource, 41 | QgsProcessingParameterField, 42 | QgsProcessingParameterNumber, 43 | QgsProcessingParameterString, 44 | QgsProcessingParameterDefinition) 45 | 46 | from qgis.analysis import (QgsVectorLayerDirector) 47 | 48 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 49 | from QNEAT3.Qneat3Utilities import getFeaturesFromQgsIterable 50 | 51 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 52 | 53 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 54 | 55 | 56 | class OdMatrixFromPointsAsCsv(QgisAlgorithm): 57 | 58 | INPUT = 'INPUT' 59 | POINTS = 'POINTS' 60 | ID_FIELD = 'ID_FIELD' 61 | STRATEGY = 'STRATEGY' 62 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 63 | DIRECTION_FIELD = 'DIRECTION_FIELD' 64 | VALUE_FORWARD = 'VALUE_FORWARD' 65 | VALUE_BACKWARD = 'VALUE_BACKWARD' 66 | VALUE_BOTH = 'VALUE_BOTH' 67 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 68 | SPEED_FIELD = 'SPEED_FIELD' 69 | DEFAULT_SPEED = 'DEFAULT_SPEED' 70 | TOLERANCE = 'TOLERANCE' 71 | OUTPUT = 'OUTPUT' 72 | 73 | def icon(self): 74 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_matrix.svg')) 75 | 76 | def group(self): 77 | return self.tr('Distance Matrices') 78 | 79 | def groupId(self): 80 | return 'networkbaseddistancematrices' 81 | 82 | def name(self): 83 | return 'OdMatrixFromPointsAsCsv' 84 | 85 | def displayName(self): 86 | return self.tr('OD-Matrix from Points as CSV (n:n)') 87 | 88 | def shortHelpString(self): 89 | return "General:
"\ 90 | "This algorithm implements OD-Matrix analysis to return the matrix of origin-destination pairs as csv-file yielding network based costs on a given network dataset between the elements of one point layer(n:n).
"\ 91 | "It accounts for points outside of the network (eg. non-network-elements). Distances are measured accounting for ellipsoids, entry-, exit-, network- and total costs are listed in the result attribute-table.

"\ 92 | "Parameters (required):
"\ 93 | "Following Parameters must be set to run the algorithm:"\ 94 | "
"\ 95 | "Parameters (optional):
"\ 96 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 97 | "
"\ 98 | "Output:
"\ 99 | "The output of the algorithm is one file:"\ 100 | "" 101 | 102 | def print_typestring(self, var): 103 | return "Type:"+str(type(var))+" repr: "+var.__str__() 104 | 105 | def __init__(self): 106 | super().__init__() 107 | 108 | def initAlgorithm(self, config=None): 109 | self.DIRECTIONS = OrderedDict([ 110 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 111 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 112 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 113 | 114 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 115 | self.tr('Fastest Path (time optimization)') 116 | ] 117 | 118 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Ellipsoidal'), 119 | self.tr('Planar (only use with projected CRS)')] 120 | 121 | 122 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 123 | self.tr('Network Layer'), 124 | [QgsProcessing.TypeVectorLine])) 125 | self.addParameter(QgsProcessingParameterFeatureSource(self.POINTS, 126 | self.tr('Point Layer'), 127 | [QgsProcessing.TypeVectorPoint])) 128 | self.addParameter(QgsProcessingParameterField(self.ID_FIELD, 129 | self.tr('Unique Point ID Field'), 130 | None, 131 | self.POINTS, 132 | optional=False)) 133 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 134 | self.tr('Optimization Criterion'), 135 | self.STRATEGIES, 136 | defaultValue=0)) 137 | 138 | params = [] 139 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 140 | self.tr('Entry Cost calculation method'), 141 | self.ENTRY_COST_CALCULATION_METHODS, 142 | defaultValue=0)) 143 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 144 | self.tr('Direction field'), 145 | None, 146 | self.INPUT, 147 | optional=True)) 148 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 149 | self.tr('Value for forward direction'), 150 | optional=True)) 151 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 152 | self.tr('Value for backward direction'), 153 | optional=True)) 154 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 155 | self.tr('Value for both directions'), 156 | optional=True)) 157 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 158 | self.tr('Default direction'), 159 | list(self.DIRECTIONS.keys()), 160 | defaultValue=2)) 161 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 162 | self.tr('Speed field'), 163 | None, 164 | self.INPUT, 165 | optional=True)) 166 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 167 | self.tr('Default speed (km/h)'), 168 | QgsProcessingParameterNumber.Double, 169 | 5.0, False, 0, 99999999.99)) 170 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 171 | self.tr('Topology tolerance'), 172 | QgsProcessingParameterNumber.Double, 173 | 0.0, False, 0, 99999999.99)) 174 | 175 | for p in params: 176 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 177 | self.addParameter(p) 178 | 179 | self.addParameter(QgsProcessingParameterFileDestination(self.OUTPUT, self.tr('Output OD Matrix'), self.tr('CSV files (*.csv)')),True) 180 | 181 | def processAlgorithm(self, parameters, context, feedback): 182 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 183 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 184 | points = self.parameterAsSource(parameters, self.POINTS, context) #QgsProcessingFeatureSource 185 | id_field = self.parameterAsString(parameters, self.ID_FIELD, context) #str 186 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 187 | 188 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 189 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 190 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 191 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 192 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 193 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 194 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 195 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 196 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 197 | output_path = self.parameterAsFileOutput(parameters, self.OUTPUT, context) #str (filepath) 198 | feedback.pushInfo(pluginPath) 199 | 200 | analysisCrs = network.sourceCrs() 201 | 202 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 203 | net = Qneat3Network(network, points, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 204 | 205 | list_analysis_points = [Qneat3AnalysisPoint("point", feature, id_field, net, net.list_tiedPoints[i], entry_cost_calc_method, feedback) for i, feature in enumerate(getFeaturesFromQgsIterable(net.input_points))] 206 | 207 | total_workload = float(pow(len(list_analysis_points),2)) 208 | feedback.pushInfo("[QNEAT3Algorithm] Expecting total workload of {} iterations".format(int(total_workload))) 209 | 210 | with open(output_path, 'w', newline='') as csvfile: 211 | csv_writer = csv.writer(csvfile, delimiter=';', 212 | quotechar='|', 213 | quoting=csv.QUOTE_MINIMAL) 214 | #write header 215 | csv_writer.writerow(["origin_id","destination_id","entry_cost", "network_cost", "exit_cost", "total_cost"]) 216 | 217 | current_workstep_number = 0 218 | 219 | for start_point in list_analysis_points: 220 | #optimize in case of undirected (not necessary to call calcDijkstra as it has already been calculated - can be replaced by reading from list) 221 | dijkstra_query = net.calcDijkstra(start_point.network_vertex_id, 0) 222 | for query_point in list_analysis_points: 223 | if (current_workstep_number%1000)==0: 224 | feedback.pushInfo("[QNEAT3Algorithm] {} OD-pairs processed...".format(current_workstep_number)) 225 | if query_point.point_id == start_point.point_id: 226 | csv_writer.writerow([start_point.point_id, query_point.point_id, float(0), float(0), float(0), float(0)]) 227 | elif dijkstra_query[0][query_point.network_vertex_id] == -1: 228 | csv_writer.writerow([start_point.point_id, query_point.point_id, None, None, None, None]) 229 | else: 230 | entry_cost = start_point.entry_cost 231 | network_cost = dijkstra_query[1][query_point.network_vertex_id] 232 | exit_cost = query_point.entry_cost 233 | total_cost = entry_cost + network_cost + exit_cost 234 | csv_writer.writerow([start_point.point_id, query_point.point_id, entry_cost, network_cost, exit_cost, total_cost]) 235 | current_workstep_number=current_workstep_number+1 236 | feedback.setProgress((current_workstep_number/total_workload)*100) 237 | 238 | feedback.pushInfo("[QNEAT3Algorithm] Total number of OD-pairs processed: {}".format(current_workstep_number)) 239 | 240 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 241 | 242 | results = {self.OUTPUT: output_path} 243 | return results 244 | 245 | -------------------------------------------------------------------------------- /algs/OdMatrixFromPointsAsTable.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | *************************************************************************** 4 | OdMatrixFromPointsAsTable.py 5 | --------------------- 6 | 7 | Partially based on QGIS3 network analysis algorithms. 8 | Copyright 2016 Alexander Bruy 9 | 10 | Date : February 2018 11 | Copyright : (C) 2018 by Clemens Raffler 12 | Email : clemens dot raffler at gmail dot com 13 | *************************************************************************** 14 | * * 15 | * This program is free software; you can redistribute it and/or modify * 16 | * it under the terms of the GNU General Public License as published by * 17 | * the Free Software Foundation; either version 2 of the License, or * 18 | * (at your option) any later version. * 19 | * * 20 | *************************************************************************** 21 | """ 22 | 23 | __author__ = 'Clemens Raffler' 24 | __date__ = 'February 2018' 25 | __copyright__ = '(C) 2018, Clemens Raffler' 26 | 27 | # This will get replaced with a git SHA1 when you do a git archive 28 | 29 | __revision__ = '$Format:%H$' 30 | 31 | import os 32 | from collections import OrderedDict 33 | 34 | from qgis.PyQt.QtCore import QVariant 35 | from qgis.PyQt.QtGui import QIcon 36 | 37 | from qgis.core import (QgsWkbTypes, 38 | QgsFields, 39 | QgsField, 40 | QgsFeature, 41 | QgsFeatureSink, 42 | QgsProcessing, 43 | QgsProcessingParameterEnum, 44 | QgsProcessingParameterFeatureSink, 45 | QgsProcessingParameterFeatureSource, 46 | QgsProcessingParameterField, 47 | QgsProcessingParameterNumber, 48 | QgsProcessingParameterString, 49 | QgsProcessingParameterDefinition) 50 | 51 | from qgis.analysis import (QgsVectorLayerDirector) 52 | 53 | from QNEAT3.Qneat3Framework import Qneat3Network, Qneat3AnalysisPoint 54 | from QNEAT3.Qneat3Utilities import getFeaturesFromQgsIterable, getFieldDatatype 55 | 56 | from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm 57 | 58 | pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] 59 | 60 | 61 | class OdMatrixFromPointsAsTable(QgisAlgorithm): 62 | 63 | INPUT = 'INPUT' 64 | POINTS = 'POINTS' 65 | ID_FIELD = 'ID_FIELD' 66 | STRATEGY = 'STRATEGY' 67 | ENTRY_COST_CALCULATION_METHOD = 'ENTRY_COST_CALCULATION_METHOD' 68 | DIRECTION_FIELD = 'DIRECTION_FIELD' 69 | VALUE_FORWARD = 'VALUE_FORWARD' 70 | VALUE_BACKWARD = 'VALUE_BACKWARD' 71 | VALUE_BOTH = 'VALUE_BOTH' 72 | DEFAULT_DIRECTION = 'DEFAULT_DIRECTION' 73 | SPEED_FIELD = 'SPEED_FIELD' 74 | DEFAULT_SPEED = 'DEFAULT_SPEED' 75 | TOLERANCE = 'TOLERANCE' 76 | OUTPUT = 'OUTPUT' 77 | 78 | def icon(self): 79 | return QIcon(os.path.join(pluginPath, 'QNEAT3', 'icons', 'icon_matrix.svg')) 80 | 81 | def group(self): 82 | return self.tr('Distance Matrices') 83 | 84 | def groupId(self): 85 | return 'networkbaseddistancematrices' 86 | 87 | def name(self): 88 | return 'OdMatrixFromPointsAsTable' 89 | 90 | def displayName(self): 91 | return self.tr('OD Matrix from Points as Table (n:n)') 92 | 93 | def shortHelpString(self): 94 | return "General:
"\ 95 | "This algorithm implements OD-Matrix analysis to return the matrix of origin-destination pairs as table yielding network based costs on a given network dataset between the elements of one point layer(n:n).
"\ 96 | "It accounts for points outside of the network (eg. non-network-elements). Distances are measured accounting for ellipsoids, entry-, exit-, network- and total costs are listed in the result attribute-table.

"\ 97 | "Parameters (required):
"\ 98 | "Following Parameters must be set to run the algorithm:"\ 99 | "
"\ 100 | "Parameters (optional):
"\ 101 | "There are also a number of optional parameters to implement direction dependent shortest paths and provide information on speeds on the networks edges."\ 102 | "
"\ 103 | "Output:
"\ 104 | "The output of the algorithm is one table:"\ 105 | "" 106 | 107 | def print_typestring(self, var): 108 | return "Type:"+str(type(var))+" repr: "+var.__str__() 109 | 110 | def __init__(self): 111 | super().__init__() 112 | 113 | def initAlgorithm(self, config=None): 114 | self.DIRECTIONS = OrderedDict([ 115 | (self.tr('Forward direction'), QgsVectorLayerDirector.DirectionForward), 116 | (self.tr('Backward direction'), QgsVectorLayerDirector.DirectionBackward), 117 | (self.tr('Both directions'), QgsVectorLayerDirector.DirectionBoth)]) 118 | 119 | self.STRATEGIES = [self.tr('Shortest Path (distance optimization)'), 120 | self.tr('Fastest Path (time optimization)')] 121 | 122 | self.ENTRY_COST_CALCULATION_METHODS = [self.tr('Ellipsoidal'), 123 | self.tr('Planar (only use with projected CRS)')] 124 | 125 | 126 | self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, 127 | self.tr('Network Layer'), 128 | [QgsProcessing.TypeVectorLine])) 129 | self.addParameter(QgsProcessingParameterFeatureSource(self.POINTS, 130 | self.tr('Point Layer'), 131 | [QgsProcessing.TypeVectorPoint])) 132 | self.addParameter(QgsProcessingParameterField(self.ID_FIELD, 133 | self.tr('Unique Point ID Field'), 134 | None, 135 | self.POINTS, 136 | optional=False)) 137 | self.addParameter(QgsProcessingParameterEnum(self.STRATEGY, 138 | self.tr('Optimization Criterion'), 139 | self.STRATEGIES, 140 | defaultValue=0)) 141 | 142 | params = [] 143 | params.append(QgsProcessingParameterEnum(self.ENTRY_COST_CALCULATION_METHOD, 144 | self.tr('Entry Cost calculation method'), 145 | self.ENTRY_COST_CALCULATION_METHODS, 146 | defaultValue=0)) 147 | params.append(QgsProcessingParameterField(self.DIRECTION_FIELD, 148 | self.tr('Direction field'), 149 | None, 150 | self.INPUT, 151 | optional=True)) 152 | params.append(QgsProcessingParameterString(self.VALUE_FORWARD, 153 | self.tr('Value for forward direction'), 154 | optional=True)) 155 | params.append(QgsProcessingParameterString(self.VALUE_BACKWARD, 156 | self.tr('Value for backward direction'), 157 | optional=True)) 158 | params.append(QgsProcessingParameterString(self.VALUE_BOTH, 159 | self.tr('Value for both directions'), 160 | optional=True)) 161 | params.append(QgsProcessingParameterEnum(self.DEFAULT_DIRECTION, 162 | self.tr('Default direction'), 163 | list(self.DIRECTIONS.keys()), 164 | defaultValue=2)) 165 | params.append(QgsProcessingParameterField(self.SPEED_FIELD, 166 | self.tr('Speed field'), 167 | None, 168 | self.INPUT, 169 | optional=True)) 170 | params.append(QgsProcessingParameterNumber(self.DEFAULT_SPEED, 171 | self.tr('Default speed (km/h)'), 172 | QgsProcessingParameterNumber.Double, 173 | 5.0, False, 0, 99999999.99)) 174 | params.append(QgsProcessingParameterNumber(self.TOLERANCE, 175 | self.tr('Topology tolerance'), 176 | QgsProcessingParameterNumber.Double, 177 | 0.0, False, 0, 99999999.99)) 178 | 179 | for p in params: 180 | p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced) 181 | self.addParameter(p) 182 | 183 | self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output OD Matrix'), QgsProcessing.TypeVectorLine), True) 184 | 185 | def processAlgorithm(self, parameters, context, feedback): 186 | feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) 187 | network = self.parameterAsSource(parameters, self.INPUT, context) #QgsProcessingFeatureSource 188 | points = self.parameterAsSource(parameters, self.POINTS, context) #QgsProcessingFeatureSource 189 | id_field = self.parameterAsString(parameters, self.ID_FIELD, context) #str 190 | strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int 191 | 192 | entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int 193 | directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) 194 | forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str 195 | backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str 196 | bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str 197 | defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int 198 | speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str 199 | defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float 200 | tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float 201 | 202 | analysisCrs = network.sourceCrs() 203 | 204 | feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") 205 | net = Qneat3Network(network, points, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) 206 | 207 | list_analysis_points = [Qneat3AnalysisPoint("point", feature, id_field, net, net.list_tiedPoints[i], entry_cost_calc_method, feedback) for i, feature in enumerate(getFeaturesFromQgsIterable(net.input_points))] 208 | 209 | feat = QgsFeature() 210 | fields = QgsFields() 211 | output_id_field_data_type = getFieldDatatype(points, id_field) 212 | fields.append(QgsField('origin_id', output_id_field_data_type, '', 254, 0)) 213 | fields.append(QgsField('destination_id', output_id_field_data_type, '', 254, 0)) 214 | fields.append(QgsField('entry_cost', QVariant.Double, '', 20,7)) 215 | fields.append(QgsField('network_cost', QVariant.Double, '', 20, 7)) 216 | fields.append(QgsField('exit_cost', QVariant.Double, '', 20,7)) 217 | fields.append(QgsField('total_cost', QVariant.Double, '', 20,7)) 218 | feat.setFields(fields) 219 | 220 | (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, 221 | fields, QgsWkbTypes.NoGeometry, network.sourceCrs()) 222 | 223 | 224 | total_workload = float(pow(len(list_analysis_points),2)) 225 | feedback.pushInfo("[QNEAT3Algorithm] Expecting total workload of {} iterations".format(int(total_workload))) 226 | 227 | 228 | current_workstep_number = 0 229 | 230 | for start_point in list_analysis_points: 231 | #optimize in case of undirected (not necessary to call calcDijkstra as it has already been calculated - can be replaced by reading from list) 232 | dijkstra_query = net.calcDijkstra(start_point.network_vertex_id, 0) 233 | for query_point in list_analysis_points: 234 | if (current_workstep_number%1000)==0: 235 | feedback.pushInfo("[QNEAT3Algorithm] {} OD-pairs processed...".format(current_workstep_number)) 236 | if query_point.point_id == start_point.point_id: 237 | feat['origin_id'] = start_point.point_id 238 | feat['destination_id'] = query_point.point_id 239 | feat['entry_cost'] = 0.0 240 | feat['network_cost'] = 0.0 241 | feat['exit_cost'] = 0.0 242 | feat['total_cost'] = 0.0 243 | sink.addFeature(feat, QgsFeatureSink.FastInsert) 244 | elif dijkstra_query[0][query_point.network_vertex_id] == -1: 245 | feat['origin_id'] = start_point.point_id 246 | feat['destination_id'] = query_point.point_id 247 | feat['entry_cost'] = None 248 | feat['network_cost'] = None 249 | feat['exit_cost'] = None 250 | feat['total_cost'] = None 251 | sink.addFeature(feat, QgsFeatureSink.FastInsert) 252 | else: 253 | network_cost = dijkstra_query[1][query_point.network_vertex_id] 254 | feat['origin_id'] = start_point.point_id 255 | feat['destination_id'] = query_point.point_id 256 | feat['entry_cost'] = start_point.entry_cost 257 | feat['network_cost'] = network_cost 258 | feat['exit_cost'] = query_point.entry_cost 259 | feat['total_cost'] = start_point.entry_cost + network_cost + query_point.entry_cost 260 | sink.addFeature(feat, QgsFeatureSink.FastInsert) 261 | current_workstep_number=current_workstep_number+1 262 | feedback.setProgress(current_workstep_number/total_workload) 263 | 264 | feedback.pushInfo("[QNEAT3Algorithm] Total number of OD-pairs processed: {}".format(current_workstep_number)) 265 | 266 | feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") 267 | 268 | results = {} 269 | results[self.OUTPUT] = dest_id 270 | return results 271 | 272 | -------------------------------------------------------------------------------- /icon_qneat3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 23 | 25 | 26 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /icons/icon_dijkstra_onetoone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 19 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /icons/icon_matrix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /icons/icon_servicearea_contour.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 29 | 39 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /icons/icon_servicearea_contour_multiple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 17 | 27 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /icons/icon_servicearea_interpolation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/root676/QNEAT3/3f0e9ee21963ce1edb2fd691d6a23e53145b8e02/icons/icon_servicearea_interpolation.png -------------------------------------------------------------------------------- /icons/icon_servicearea_interpolation_multiple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/root676/QNEAT3/3f0e9ee21963ce1edb2fd691d6a23e53145b8e02/icons/icon_servicearea_interpolation_multiple.png -------------------------------------------------------------------------------- /icons/icon_servicearea_points.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /icons/icon_servicearea_points_multiple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /icons/icon_servicearea_polygon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 28 | 37 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /icons/icon_servicearea_polygon_missing_import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 26 | 35 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /icons/icon_servicearea_polygon_multiple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 16 | 25 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /metadata.txt: -------------------------------------------------------------------------------- 1 | # Mandatory items: 2 | 3 | 4 | [general] 5 | name=QNEAT3 6 | qgisMinimumVersion=3.00 7 | qgisMaximumVersion=3.99 8 | description=QNEAT3 - QGIS Network Analysis Toolbox 3 9 | about=The QNEAT3 (short for Qgis Network Analysis Toolbox 3) Plugin aims to provide sophisticated QGIS Processing-Toolbox algorithms in the field of network analysis. QNEAT3 is integrated in the QGIS3 Processing Framework. It offers algorithms that range from simple shortest path solving to more complex tasks like Iso-Area (aka service areas, accessibility polygons) and OD-Matrix (Origin-Destination-Matrix) computation. The usage of some Iso-Area algorithms require the installation of the matplotlib python library from OSGeo4W (see algorithm and help page for more information). 10 | version=1.0.5 11 | author=Clemens Raffler 12 | email=clemens.raffler@gmail.com 13 | 14 | # end of mandatory metadata 15 | 16 | # Optional items: 17 | 18 | # Uncomment the following line and add your changelog entries: 19 | changelog=1.0.0: 20 | - First release of QNEAT3 Plugin. Enjoy! 21 | 1.0.1: 22 | - Fix fatal QGIS crash: Network Strategy must not be added multiple times. 23 | - Minor user-feedback and icon tweaks. 24 | - Fixed deprecation warning. 25 | 1.0.2: 26 | - Fix bug #10 OD Matrix randomly dropping one record 27 | - Fix bug #8 related to QGIS bug #16858, error in the QNEAT3 provider 28 | - Experiments with QNEAT interpolation, probably a solution to fix bug #6 29 | - Minor enhancements for log messages 30 | 1.0.3: 31 | - Fix bug #22 Issue with QgsPoint() being constructed from QgsPointXY() in QGIS 3.10 is resolved temporary 32 | 1.0.4: 33 | - Fix bug #25 Wire tolerance parameter permanently to QgsGraphBuilder 34 | 1.0.5: 35 | - New Feature: allow output of route geometry from OD Matrix algorithms (thanks to @garci66) 36 | - Fix issue #26: report NULL or delete OD pairs with no routes 37 | - Fix issue #57: Current processing setup does not allow qgis_process (CLI) to access QNEAT3 (thanks to @JanCaha) 38 | - Fix issue #62: API break in wkbType() (thanks to @merkato) 39 | - Fix issue #29: fix analysis crs in contours and interpolation algorithms (thanks to @kufreu and @josephholler) 40 | - fix issue #36: OD Matrix miscalculates time cost if network CRS does not use linear units of meters (thanks to @kufreu and @josephholler) 41 | - fix issue #31: Allow for different origin and destination ID data types (thanks to @kufreu and @josephholler) 42 | 43 | # tags are comma separated with spaces allowed 44 | tags= network analysis, graph analysis, od matrix, distance matrix, od matrices, OD, isochrone areas, catchment areas, shortest path, dijkstra 45 | 46 | homepage=https://root676.github.io 47 | tracker=https://github.com/root676/QNEAT3/issues 48 | repository=https://github.com/root676/QNEAT3 49 | icon=icon_qneat3.svg 50 | # experimental flag 51 | experimental=False 52 | 53 | #set processing provider flag 54 | hasProcessingProvider=yes 55 | 56 | # deprecated flag (applies to the whole plugin, not just a single version 57 | deprecated=False 58 | 59 | -------------------------------------------------------------------------------- /testdata/minimal_testnetwork.cpg: -------------------------------------------------------------------------------- 1 | UTF-8 -------------------------------------------------------------------------------- /testdata/minimal_testnetwork.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/root676/QNEAT3/3f0e9ee21963ce1edb2fd691d6a23e53145b8e02/testdata/minimal_testnetwork.dbf -------------------------------------------------------------------------------- /testdata/minimal_testnetwork.prj: -------------------------------------------------------------------------------- 1 | PROJCS["MGI_Austria_GK_East",GEOGCS["GCS_MGI",DATUM["D_MGI",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",16.33333333333333],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",-5000000],UNIT["Meter",1]] -------------------------------------------------------------------------------- /testdata/minimal_testnetwork.qpj: -------------------------------------------------------------------------------- 1 | PROJCS["MGI / Austria GK East",GEOGCS["MGI",DATUM["Militar_Geographische_Institute",SPHEROID["Bessel 1841",6377397.155,299.1528128,AUTHORITY["EPSG","7004"]],TOWGS84[577.326,90.129,463.919,5.137,1.474,5.297,2.4232],AUTHORITY["EPSG","6312"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4312"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",16.33333333333333],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",-5000000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","31256"]] 2 | -------------------------------------------------------------------------------- /testdata/minimal_testnetwork.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/root676/QNEAT3/3f0e9ee21963ce1edb2fd691d6a23e53145b8e02/testdata/minimal_testnetwork.shp -------------------------------------------------------------------------------- /testdata/minimal_testnetwork.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/root676/QNEAT3/3f0e9ee21963ce1edb2fd691d6a23e53145b8e02/testdata/minimal_testnetwork.shx --------------------------------------------------------------------------------