Network-Analysis-between-2-points / network_analysis.py
KawgKawgKawg's picture
Upload 3 files
706ed73 verified
#Libraries To Import For Doing Network Analysis using QGis
#Using The Core QGIS functions and we're using PyQT classes for graph building and layer manipulation to learn 2 points to another
import sys
import os
from qgis.analysis import QgsGraphBuilder #Used To analyze two points
from qgis.analysis import QgsGraphAnalyzer #Uses Djikstra's Algorithm to find the most optimal path between 2 points
from qgis.core import (
QgsApplication,
QgsWkbTypes,
QgsProject, #Project Manager
QgsVectorLayer, #To Load Shapefiles and geopackages
QgsFeature, #Single row in a vector layer
QgsGeometry, #For mathematical geometry operations
QgsPointXY, #Makes a 2D point
QgsPoint,
QgsFields,
QgsField, #For multple attribute schemas and individual attribute field
QgsVectorFileWriter #For Package Export
)
from qgis.PyQt.QtCore import QVariant # Used to define field data types
#Now we load the Philippine roads dataset from a non-profit organization called Humanitarian Open Street map team
#This will give us an open dataset about roads in NCR and give us the shortest path between two points
#Setup QGIS Paths
QGIS_PREFIX_PATH = "/usr" # Common for Ubuntu QGIS installs
QGIS_PLUGIN_PATH = "/usr/lib/qgis/plugins"
qgs = QgsApplication([], False)
qgs.setPrefixPath(QGIS_PREFIX_PATH, True)
qgs.initQgis()
layer = QgsVectorLayer("phl_roads_lines.gpkg", "roads", "ogr")
#print("Layer loaded:", layer.name())
#We are going to find shortest path for Quezon city
start_point = QgsPointXY(121.0365, 14.6760)
end_point = QgsPointXY(121.0000, 14.5550)
tolerance = 0.001 #to snap nearest vortex
builder = QgsGraphBuilder(layer.sourceCrs())
points = [start_point, end_point]
graph = builder.graph()
#getting the feature graphs
for feature in layer.getFeatures():
geom = feature.geometry()
if geom.isMultipart():
lines = geom.asMultiPolyline()
else:
lines = [geom.asPolyline()]
for line in lines:
for i in range(len(line) - 1):
#Then we convert it to a QgisPoint
p1 = QgsPointXY(line[i].x(), line[i].y())
p2 = QgsPointXY(line[i + 1].x(), line[i + 1].y())
builder.addVertex(-1, p1)
builder.addVertex(-1, p2)
id1 = builder.graph().findVertex(p1)
id2 = builder.graph().findVertex(p2)
distance = p1.distance(p2)
builder.addEdge(id1, p1, id2, p2, [distance])
graph = builder.graph()
# Convert the coordinates (start_point and end_point) into node indexes in the graph
start_idx = graph.findVertex(start_point)
end_idx = graph.findVertex(end_point)
# Use Dijkstra's algorithm to compute the shortest path tree from the start node
# 0 is the index for cost (in our case: distance)
tree, cost = QgsGraphAnalyzer.dijkstra(graph, start_idx, 0)
# If cost is infinite, it means there’s no possible path between start and end
if cost[end_idx] == float('inf'):
print("No Path Found")
sys.exit(1)
# Backtrack from end point to start to extract the shortest path
route = []
cur_pos = end_idx
while cur_pos != start_idx:
incoming_edge = tree[cur_pos] # The edge that leads to current vertex
if incoming_edge == -1:
print("No Route!")
sys.exit(1)
# Get the source vertex of this edge, and retrieve its point
from_vertex = graph.edge(incoming_edge).fromVertex()
point = graph.vertex(from_vertex).point()
route.append(point)
# Move to the previous vertex
cur_pos = from_vertex
# Add the final starting point to complete the route
route.append(start_point)
route.reverse() # Reverse because we built the route from end to start
# Define fields for the output layer
fields = QgsFields()
fields.append(QgsField("id", QVariant.Int)) # We'll assign an ID = 1 to this feature
# Define the GeoPackage file path for saving the shortest path result
output_path = "shortest_path.gpkg"
# Create the output vector layer writer (LineString geometry, same CRS as roads layer)
output_layer = QgsVectorFileWriter.create(
output_path, # File to save
fields, # Attribute schema
QgsWkbTypes.LineString, # Geometry type
layer.sourceCrs(), # Coordinate reference system
"GPKG" # Format
)
# Create a feature from the route geometry
feat = QgsFeature()
feat.setFields(fields)
feat.setAttribute("id", 1)
feat.setGeometry(QgsGeometry.fromPolylineXY(route))
# Add the feature to the output file
output_layer.addFeature(feat)
# Close and save the layer to disk
del output_layer
print(f"✅ Shortest path successfully saved to: {output_path}")
# Exit QGIS to clean up resources and avoid memory leaks
qgs.exitQgis()