From 132d4a305dc3cd698439f6324de9ade91f1c13db Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Sun, 17 Nov 2024 12:58:14 +0000
Subject: [PATCH 02/64] Add sprint 1 user stories
---
docs/readme.md | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index bb1c4e6..c76e28b 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -123,6 +123,8 @@ A-level Computer Science programming project
- [Sprint 4 upfront plan](#sprint-4-upfront-plan)
- [Sprint 5 upfront plan](#sprint-5-upfront-plan)
- [Sprint 1 (2024-11-17)](#sprint-1-2024-11-17)
+ - [Sprint 1 goals](#sprint-1-goals)
+ - [User stories](#user-stories)
## Analysis
@@ -1447,6 +1449,16 @@ Sprint 5 will be added if required, and will be planned in more detail once the
+### Sprint 1 goals
+
+#### User stories
+
+1. As a user, I want an interactive map that is intuitive and readable
+2. As a user, I want the map to clearly show my current location
+3. As a mobile user, I want the UI to fit well on my screen and be easy to use
+4. As a stakeholder, I want to get an initial idea of the UI layout so that I can give feedback
+5. As a technically-minded stakeholder, I want to see a proof of concept of the start of the routing engine
+
---
From 8992a04b09e61f5d9b02b31b3df795c50c39d4c1 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Sun, 17 Nov 2024 12:58:46 +0000
Subject: [PATCH 03/64] Sprint 1 upfront plan: Remove garbage bullet point
---
docs/readme.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/docs/readme.md b/docs/readme.md
index c76e28b..0275383 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1409,7 +1409,6 @@ gantt
- Generate a routing graph based on a very simple filter, e.g. `highway=*`
- Also start work on the frontend
- Create the general layout of the UI
- - Implement the combination button component
- Will require roughly designing what the UI will look like, and running it past my stakeholders
- Add an interactive map using Leaflet.js
- Show the user's current location on the map
From 1ddb6f2601fe710c7315b07827163cc958521888 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Sun, 17 Nov 2024 13:43:44 +0000
Subject: [PATCH 04/64] talk about OSMnx
wow this was actually helpful
---
.vscode/settings.json | 3 +++
docs/readme.md | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5cc3d25..b9d5906 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -11,10 +11,13 @@
"Mish",
"mockup",
"NetworkX",
+ "OpenStreetMap",
"optimise",
"optimising",
+ "OSM",
"OSMAnd",
"OSMF",
+ "OSMnx",
"OSRM",
"pathfinding",
"prioritise",
diff --git a/docs/readme.md b/docs/readme.md
index 0275383..fe2ea07 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -125,6 +125,11 @@ A-level Computer Science programming project
- [Sprint 1 (2024-11-17)](#sprint-1-2024-11-17)
- [Sprint 1 goals](#sprint-1-goals)
- [User stories](#user-stories)
+ - [Sprint 1 design](#sprint-1-design)
+ - [Sprint 1 library research](#sprint-1-library-research)
+ - [OSM data parsing requirements](#osm-data-parsing-requirements)
+ - [OSMnx research](#osmnx-research)
+ - [Sprint 1 pseudocode](#sprint-1-pseudocode)
## Analysis
@@ -1458,6 +1463,38 @@ Sprint 5 will be added if required, and will be planned in more detail once the
4. As a stakeholder, I want to get an initial idea of the UI layout so that I can give feedback
5. As a technically-minded stakeholder, I want to see a proof of concept of the start of the routing engine
+### Sprint 1 design
+
+#### Sprint 1 library research
+
+Before writing my pseudocode, I would like to research the libraries available for parsing OSM data in Python.
+
+##### OSM data parsing requirements
+
+- Supports `osm.pbf` files
+ - This is the format of region files from geofabrik.de
+- Supports `.osm` files
+ - This is the format of map data exports from openstreetmap.org and the Overpass API
+- Allows pythonic access to nodes, ways, relations and their tags
+ - Because this is the data that I wil be using to build the routing graph
+
+##### OSMnx research
+
+> OSMnx is a Python package to easily download, model, analyze, and visualize street networks and other geospatial features from OpenStreetMap. You can download and model walking, driving, or biking networks with a single line of code then analyze and visualize them. You can just as easily work with urban amenities/points of interest, building footprints, transit stops, elevation data, street orientations, speed/travel time, and routing.
+> — [osmnx.readthedocs.io](https://osmnx.readthedocs.io/en/stable/index.html)
+
+From reading its documentation, OSMnx appears to be a highly-featured tool for working with OpenStreetMap data, including routing use-cases. It also handles downloading of OSM data, although I might bypass this feature so that I can use a pre-downloaded data file for offline use. Its `graph` module will also help me to create a routing graph from OSM data, and it uses NetworkX, which is what I plan to use. While it's usually used for creating directional graphs, it also supports undirected graphs through its `convert` module.
+
+Since it uses the Overpass.de API, and Nominatim, I will need to ensure I follow their usage policies, i.e. the [Overpass API Commons documentation](https://dev.overpass-api.de/overpass-doc/en/preface/commons.html) and the [Nominatim Usage Policy](https://operations.osmfoundation.org/policies/nominatim/).
+
+My one concern with OSMnx is that, since it handles a large part of processing OSM data, it may not be customisable enough for my needs. For example, it may be too vehicle-oriented, making it difficult to construct a routing graph specific to pedestrians as I envisioned. However, it should mean that I can get a working prototype of the routing engine to my stakeholders sooner, which is a key goal of Sprint 1.
+
+OSMnx is also used by Routor, my beloved Python routing engine.
+
+#### Sprint 1 pseudocode
+
+
+
---
From 66974ac130bafcd1bea8c7562183f3d46a67773a Mon Sep 17 00:00:00 2001
From: RandomSearch18 <101704343+RandomSearch18@users.noreply.github.com>
Date: Mon, 18 Nov 2024 10:48:51 +0000
Subject: [PATCH 05/64] end of lesson aaaaaaa
---
.vscode/settings.json | 2 ++
docs/readme.md | 28 +++++++++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index b9d5906..5672193 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,7 @@
{
"cSpell.words": [
+ "PyOsmium",
+ "osmcode.org",
"daisyUI",
"deprioritise",
"Excalidraw",
diff --git a/docs/readme.md b/docs/readme.md
index fe2ea07..71e8b7c 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -129,7 +129,11 @@ A-level Computer Science programming project
- [Sprint 1 library research](#sprint-1-library-research)
- [OSM data parsing requirements](#osm-data-parsing-requirements)
- [OSMnx research](#osmnx-research)
+ - [OSMnx citation](#osmnx-citation)
+ - [PyOsmium research](#pyosmium-research)
+ - [OSM library research conclusion](#osm-library-research-conclusion)
- [Sprint 1 pseudocode](#sprint-1-pseudocode)
+ - [Creating a very basic graph](#creating-a-very-basic-graph)
## Analysis
@@ -1491,9 +1495,31 @@ My one concern with OSMnx is that, since it handles a large part of processing O
OSMnx is also used by Routor, my beloved Python routing engine.
+###### OSMnx citation
+
+Boeing, G. 2024. "Modeling and Analyzing Urban Networks and Amenities with OSMnx." Working paper. URL:
+
+##### PyOsmium research
+
+PyOsmium ([osmcode.org/pyosmium](https://osmcode.org/pyosmium/)) is a Python library for using Osmium ([wiki.osm.org/Osmium](https://wiki.openstreetmap.org/wiki/Osmium)), a general library for working with OSM data formats. It supports converting between OSM data formats, and extracting geographical areas from a larger OSM file.
+
+While it may be useful if I need to store OSM data in a specific format, its other features would be redundant if I use OSMnx, so I don't expect to need this library.
+
+##### OSM library research conclusion
+
+Due to its large number of features that are appropriate to my routing engine, OSMnx seems like a clear choice to use for my routing engine, and I look forward to experimenting with and making use of its features.
+
#### Sprint 1 pseudocode
-
+##### Creating a very basic graph
+
+- data_file = argv[1]
+- osm_data = osmnx.parse(data_file)
+- graph = networkx.Graph()
+- for way in osm_data.ways:
+ - if way.tags.get("highway").is_truthy():
+ - graph.add_edge(way=way)
+- print(graph)
---
From 3b3b48051fad1540f0c247f2d98cb9ace58ec59c Mon Sep 17 00:00:00 2001
From: RandomSearch18 <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 09:48:57 +0000
Subject: [PATCH 06/64] +
---
docs/readme.md | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/docs/readme.md b/docs/readme.md
index 71e8b7c..2587f29 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -132,8 +132,10 @@ A-level Computer Science programming project
- [OSMnx citation](#osmnx-citation)
- [PyOsmium research](#pyosmium-research)
- [OSM library research conclusion](#osm-library-research-conclusion)
- - [Sprint 1 pseudocode](#sprint-1-pseudocode)
- - [Creating a very basic graph](#creating-a-very-basic-graph)
+ - [Sprint 1 modules](#sprint-1-modules)
+ - [Backend: Creating a very basic graph](#backend-creating-a-very-basic-graph)
+ - [Approach](#approach)
+ - [Pseudocode](#pseudocode)
## Analysis
@@ -1334,7 +1336,6 @@ This would be used to select a preference for a certain routing option, like whe
This button was made with Excalidraw.
![A combination button, showing "avoid", neutral, and "prefer" states](assets/design/ui/combi-button-v1.excalidraw.svg)
-
Andrew's feedback:
- Neutral state is not very obvious
@@ -1509,9 +1510,19 @@ While it may be useful if I need to store OSM data in a specific format, its oth
Due to its large number of features that are appropriate to my routing engine, OSMnx seems like a clear choice to use for my routing engine, and I look forward to experimenting with and making use of its features.
-#### Sprint 1 pseudocode
+#### Sprint 1 modules
+
+##### Backend: Creating a very basic graph
+
+###### Approach
+
+I will take an OSM data file as a command-line argument, because that will be the easiest way to get map data for an intitial prototype. Later on managing and downloading map data will be automatically managed by the program, but for now I shall manually download some data for development.
+
+I plan to use OSMnx to parse the data as planned in my [library research](#sprint-1-library-research), and create a graph using NetworkX as planned in my [routing graph research](#routing-graph-research-conclusion). I will use the very basic filter of the `highway` tag being any value that isn't "no" to decide which ways to include in my graph.
+
+Since there isn't much I can do with the graph yet, I will print it to the screen to check that it looks alright.
-##### Creating a very basic graph
+###### Pseudocode
- data_file = argv[1]
- osm_data = osmnx.parse(data_file)
From 61de28f4cc313d1f642735f91154fff11a5abe1e Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:10:41 +0000
Subject: [PATCH 07/64] Creating a very basic graph: + validation table
---
docs/readme.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index 2587f29..672f60c 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -136,6 +136,7 @@ A-level Computer Science programming project
- [Backend: Creating a very basic graph](#backend-creating-a-very-basic-graph)
- [Approach](#approach)
- [Pseudocode](#pseudocode)
+ - [Validation table](#validation-table)
## Analysis
@@ -1532,6 +1533,15 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
- graph.add_edge(way=way)
- print(graph)
+###### Validation table
+
+| Expectation | Example unexpected data | Response |
+| --------------------------------- | ------------------------------------ | ------------------------ |
+| Command-line argument is provided | 0 arguments | Print "Please provide the OSM file, e.g. python main.py region.osm" |
+| Data file is present | File does not exist | Print e.g. "File region.osm not found" |
+| Data file is readable | Filesystem permissions forbid access | Print e.g. "Cannot access file region.osm, permission denied" |
+| Map data is valid | OSMnx throws an error while parsing | Print "Failed to parse OSM data" and print the error from OSMnx |
+
---
From e369638be13abb4980f1a0e9fc4a5d7325f0cdff Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:13:49 +0000
Subject: [PATCH 08/64] Creating a very basic graph: + variables and data
structures
---
docs/readme.md | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/docs/readme.md b/docs/readme.md
index 672f60c..11eef7b 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -137,6 +137,7 @@ A-level Computer Science programming project
- [Approach](#approach)
- [Pseudocode](#pseudocode)
- [Validation table](#validation-table)
+ - [Variables and d](#variables-and-d)
## Analysis
@@ -1535,12 +1536,20 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
###### Validation table
-| Expectation | Example unexpected data | Response |
-| --------------------------------- | ------------------------------------ | ------------------------ |
+| Expectation | Example unexpected data | Response |
+| --------------------------------- | ------------------------------------ | ------------------------------------------------------------------- |
| Command-line argument is provided | 0 arguments | Print "Please provide the OSM file, e.g. python main.py region.osm" |
-| Data file is present | File does not exist | Print e.g. "File region.osm not found" |
-| Data file is readable | Filesystem permissions forbid access | Print e.g. "Cannot access file region.osm, permission denied" |
-| Map data is valid | OSMnx throws an error while parsing | Print "Failed to parse OSM data" and print the error from OSMnx |
+| Data file is present | File does not exist | Print e.g. "File region.osm not found" |
+| Data file is readable | Filesystem permissions forbid access | Print e.g. "Cannot access file region.osm, permission denied" |
+| Map data is valid | OSMnx throws an error while parsing | Print "Failed to parse OSM data" and print the error from OSMnx |
+
+###### Variables and data structures
+
+- `data_file`
+- `osm_data`
+ - This data structure will be OSMnx's data format for map data
+- `graph`
+ - This will be an undirected graph, using the NetworkX library
---
From a337650f8fbb756ec31d238f67ada035eddb078e Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:31:56 +0000
Subject: [PATCH 09/64] Creating a very basic graph: + test data
---
docs/readme.md | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/docs/readme.md b/docs/readme.md
index 11eef7b..4594e8c 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1528,6 +1528,7 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
- data_file = argv[1]
- osm_data = osmnx.parse(data_file)
+- print("Successfully loaded OSM data from {data_file}")
- graph = networkx.Graph()
- for way in osm_data.ways:
- if way.tags.get("highway").is_truthy():
@@ -1539,8 +1540,9 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
| Expectation | Example unexpected data | Response |
| --------------------------------- | ------------------------------------ | ------------------------------------------------------------------- |
| Command-line argument is provided | 0 arguments | Print "Please provide the OSM file, e.g. python main.py region.osm" |
-| Data file is present | File does not exist | Print e.g. "File region.osm not found" |
-| Data file is readable | Filesystem permissions forbid access | Print e.g. "Cannot access file region.osm, permission denied" |
+| Data file is present | File does not exist | Print "File {path} not found" |
+| Data file is an actual file | Path to a block device provided | Print "Cannot access {path}: not a file" |
+| Data file is readable | Filesystem permissions forbid access | Print "Cannot access file {path}: permission denied" |
| Map data is valid | OSMnx throws an error while parsing | Print "Failed to parse OSM data" and print the error from OSMnx |
###### Variables and data structures
@@ -1551,6 +1553,18 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
- `graph`
- This will be an undirected graph, using the NetworkX library
+###### Test data
+
+
+| Test | Reason for test | Type | Test data | Expected outcome |
+| ---- | --------------- | ---- | --------- | ---------------- |
+| Accepts file | Ensure the program uses the provided CLI arg | Normal | `my-data-file.osm` (a valid data file) | Output shows that data was loaded from that file |
+| File exists | Program should check that the file exists | Erroneous | `missing-file.osm` (a non-existent file) | Print "File missing-file.osm not found" |
+| File is a file | Paths should only be accepted if they point to files that are file-y enough | Erroneous | `/tmp` (a directory) | Print "Cannot access /tmp: not a file" |
+| File is readable | Should notify the user if it can't read the file due to permissions | Erroneous | `my-data-file.osm` (file with permissions `333`) | Print "Cannot access file my-data-file.osm: permission denied" |
+| Check data file syntax | Errors from OSMnx should be handled, and the user should be notified | Erroneous |`.osm` file with a missing `>` | Print "Failed to parse OSM data" and some error from OSMnx relating to the specific problem |
+| Graph is created with edges | Ensure that the graph is created correctly | Normal | `my-data-file.osm` (small region file) | Graph is printed, containing some edges |
+
---
From 0add53ff50d7a7f58de27f2a0e9d16fd0a23f42a Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:37:10 +0000
Subject: [PATCH 10/64] Pseudocode: Use the OSMnx functions to create the graph
---
docs/readme.md | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/docs/readme.md b/docs/readme.md
index 4594e8c..0b0ed4c 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1529,10 +1529,8 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
- data_file = argv[1]
- osm_data = osmnx.parse(data_file)
- print("Successfully loaded OSM data from {data_file}")
-- graph = networkx.Graph()
-- for way in osm_data.ways:
- - if way.tags.get("highway").is_truthy():
- - graph.add_edge(way=way)
+- graph = osmnx.create_digraph(osm_data, filter="highway!=no")
+- converted_graph = osmnx.to_undirected_graph(graph)
- print(graph)
###### Validation table
@@ -1551,10 +1549,14 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
- `osm_data`
- This data structure will be OSMnx's data format for map data
- `graph`
- - This will be an undirected graph, using the NetworkX library
+ - This will be a directed graph, in the default OSMnx format, which is based on a NetworkX graph
+- `converted_graph`
+ - This will be an undirected graph, which is the format we want to use for the routing engine
###### Test data
+
+
| Test | Reason for test | Type | Test data | Expected outcome |
| ---- | --------------- | ---- | --------- | ---------------- |
From 3158989a5286eda48fa2f071c86a77bdb55699c6 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:42:37 +0000
Subject: [PATCH 11/64] Simplify the graph
---
docs/readme.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index 0b0ed4c..cba49ae 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1531,6 +1531,7 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
- print("Successfully loaded OSM data from {data_file}")
- graph = osmnx.create_digraph(osm_data, filter="highway!=no")
- converted_graph = osmnx.to_undirected_graph(graph)
+- simplified_graph = osmnx.simplify_graph(converted_graph)
- print(graph)
###### Validation table
@@ -1552,6 +1553,8 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
- This will be a directed graph, in the default OSMnx format, which is based on a NetworkX graph
- `converted_graph`
- This will be an undirected graph, which is the format we want to use for the routing engine
+- `simplified_graph`
+ - This will be another NetworkX undirected graph, but after graph simplification (removing nodes that aren't intersections)
###### Test data
From 77ee70ea65320e2bf95de8b489de2fa123d5673f Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:44:24 +0000
Subject: [PATCH 12/64] justify my other lines of code
---
docs/readme.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/docs/readme.md b/docs/readme.md
index cba49ae..efeedaf 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1518,10 +1518,12 @@ Due to its large number of features that are appropriate to my routing engine, O
###### Approach
-I will take an OSM data file as a command-line argument, because that will be the easiest way to get map data for an intitial prototype. Later on managing and downloading map data will be automatically managed by the program, but for now I shall manually download some data for development.
+I will take an OSM data file as a command-line argument, because that will be the easiest way to get map data for an initial prototype. Later on managing and downloading map data will be automatically managed by the program, but for now I shall manually download some data for development.
I plan to use OSMnx to parse the data as planned in my [library research](#sprint-1-library-research), and create a graph using NetworkX as planned in my [routing graph research](#routing-graph-research-conclusion). I will use the very basic filter of the `highway` tag being any value that isn't "no" to decide which ways to include in my graph.
+To process the graph, I will first convert is from OSMnx's default directed graph format to an undirected graph, as I plan to use an undirected graph for the routing engine (which was also described in [routing graph research](#routing-graph-research-conclusion)). I will then simplify the graph, removing nodes that aren't intersections, to make it easier to work with.
+
Since there isn't much I can do with the graph yet, I will print it to the screen to check that it looks alright.
###### Pseudocode
From 6cd429e1751630ee52817b494a31c2970f6d19b8 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:47:08 +0000
Subject: [PATCH 13/64] Split tests into before and after development
---
docs/readme.md | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/docs/readme.md b/docs/readme.md
index efeedaf..9ef0ad8 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1560,17 +1560,23 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
###### Test data
-
+###### During development
| Test | Reason for test | Type | Test data | Expected outcome |
| ---- | --------------- | ---- | --------- | ---------------- |
| Accepts file | Ensure the program uses the provided CLI arg | Normal | `my-data-file.osm` (a valid data file) | Output shows that data was loaded from that file |
| File exists | Program should check that the file exists | Erroneous | `missing-file.osm` (a non-existent file) | Print "File missing-file.osm not found" |
+| Graph is created with edges | Ensure that the graph is created correctly | Normal | `my-data-file.osm` (small region file) | Graph is printed, containing some edges |
+
+###### After development
+
+
+| Test | Reason for test | Type | Test data | Expected outcome |
+| ---- | --------------- | ---- | --------- | ---------------- |
| File is a file | Paths should only be accepted if they point to files that are file-y enough | Erroneous | `/tmp` (a directory) | Print "Cannot access /tmp: not a file" |
| File is readable | Should notify the user if it can't read the file due to permissions | Erroneous | `my-data-file.osm` (file with permissions `333`) | Print "Cannot access file my-data-file.osm: permission denied" |
| Check data file syntax | Errors from OSMnx should be handled, and the user should be notified | Erroneous |`.osm` file with a missing `>` | Print "Failed to parse OSM data" and some error from OSMnx relating to the specific problem |
-| Graph is created with edges | Ensure that the graph is created correctly | Normal | `my-data-file.osm` (small region file) | Graph is printed, containing some edges |
---
From 3ff6970d36620c333ce9a1fa63740b1295bff2d1 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 10:48:06 +0000
Subject: [PATCH 14/64] Test data: Mention osm.org/export
---
docs/readme.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index 9ef0ad8..e5faf09 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1560,6 +1560,8 @@ Since there isn't much I can do with the graph yet, I will print it to the scree
###### Test data
+I will download OSM data files from
for testing and development.
+
###### During development
From cf227c6a7c0b9d9381a2fb60865a239a3cc00588 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 17:17:37 +0000
Subject: [PATCH 15/64] Update ToC
---
docs/readme.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/docs/readme.md b/docs/readme.md
index e5faf09..97935f2 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -137,7 +137,10 @@ A-level Computer Science programming project
- [Approach](#approach)
- [Pseudocode](#pseudocode)
- [Validation table](#validation-table)
- - [Variables and d](#variables-and-d)
+ - [Variables and data structures](#variables-and-data-structures)
+ - [Test data](#test-data)
+ - [During development](#during-development)
+ - [After development](#after-development)
## Analysis
From ae1d47f79c57aa3665b2882844fcfaff606a9179 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 17:26:52 +0000
Subject: [PATCH 16/64] Start development for sprint 1
Yes I'm aware that the branch name is now incorrect-
---
docs/readme.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index 97935f2..48daaf6 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -141,6 +141,8 @@ A-level Computer Science programming project
- [Test data](#test-data)
- [During development](#during-development)
- [After development](#after-development)
+ - [Sprint 1 development](#sprint-1-development)
+ - [Starting work on the frontend](#starting-work-on-the-frontend)
## Analysis
@@ -1583,6 +1585,14 @@ I will download OSM data files from for t
| File is readable | Should notify the user if it can't read the file due to permissions | Erroneous | `my-data-file.osm` (file with permissions `333`) | Print "Cannot access file my-data-file.osm: permission denied" |
| Check data file syntax | Errors from OSMnx should be handled, and the user should be notified | Erroneous |`.osm` file with a missing `>` | Print "Failed to parse OSM data" and some error from OSMnx relating to the specific problem |
+### Sprint 1 development
+
+#### Starting work on the frontend
+
+I will bootstrap the frontend using the files from the web mockup I made, since it already has the important tools like Tailwind, Vite, and daisyUI set up.
+
+To separate frontend and backend code, I have put the files in a `frontend` directory, and shall create a similar `backend` directory when I start work on the backend.
+
---
From f6284b20f5818b955b683686b6d36263a7e2a002 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 17:32:15 +0000
Subject: [PATCH 17/64] +
---
docs/readme.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index 48daaf6..9aee99f 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1593,6 +1593,8 @@ I will bootstrap the frontend using the files from the web mockup I made, since
To separate frontend and backend code, I have put the files in a `frontend` directory, and shall create a similar `backend` directory when I start work on the backend.
+I started setting up my development environment by installing dependencies with Yarn (as per my [frontend technologies](#frontend-technologies) decision).
+
---
From 2aad36f6af23af548eef4dd5adc9508617a047b7 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 17:35:53 +0000
Subject: [PATCH 18/64] we're using Yarn v1
---
.vscode/settings.json | 5 +++--
docs/readme.md | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5672193..5bde8e0 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,7 +1,6 @@
{
"cSpell.words": [
- "PyOsmium",
- "osmcode.org",
+ "Codespaces",
"daisyUI",
"deprioritise",
"Excalidraw",
@@ -18,11 +17,13 @@
"optimising",
"OSM",
"OSMAnd",
+ "osmcode.org",
"OSMF",
"OSMnx",
"OSRM",
"pathfinding",
"prioritise",
+ "PyOsmium",
"Routor",
"runtimes",
"satnavs",
diff --git a/docs/readme.md b/docs/readme.md
index 9aee99f..2e7018b 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1593,7 +1593,7 @@ I will bootstrap the frontend using the files from the web mockup I made, since
To separate frontend and backend code, I have put the files in a `frontend` directory, and shall create a similar `backend` directory when I start work on the backend.
-I started setting up my development environment by installing dependencies with Yarn (as per my [frontend technologies](#frontend-technologies) decision).
+I started setting up my development environment by installing dependencies with Yarn (as per my [frontend technologies](#frontend-technologies) decision). While ideally I would use a modern Yarn version, I've decided to stick with Yarn 1, because it's installed by default in GitHub Codespaces (which I plan to use for some of my development), and I won't be using any advanced Yarn features.
---
From c65cb3130325e16c0971544df474d5b8eacae09b Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 18:52:08 +0000
Subject: [PATCH 19/64] talk about school blocking workarounds
---
docs/readme.md | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index 2e7018b..b3fd6d6 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -143,6 +143,8 @@ A-level Computer Science programming project
- [After development](#after-development)
- [Sprint 1 development](#sprint-1-development)
- [Starting work on the frontend](#starting-work-on-the-frontend)
+ - [Initial web app bootstrap](#initial-web-app-bootstrap)
+ - [Using unusual file extensions](#using-unusual-file-extensions)
## Analysis
@@ -1589,12 +1591,29 @@ I will download OSM data files from
for t
#### Starting work on the frontend
+##### Initial web app bootstrap
+
I will bootstrap the frontend using the files from the web mockup I made, since it already has the important tools like Tailwind, Vite, and daisyUI set up.
To separate frontend and backend code, I have put the files in a `frontend` directory, and shall create a similar `backend` directory when I start work on the backend.
I started setting up my development environment by installing dependencies with Yarn (as per my [frontend technologies](#frontend-technologies) decision). While ideally I would use a modern Yarn version, I've decided to stick with Yarn 1, because it's installed by default in GitHub Codespaces (which I plan to use for some of my development), and I won't be using any advanced Yarn features.
+##### Using unusual file extensions
+
+I made a couple of changes to the file extensions I use, away from what the Vite template used:
+
+- I changed my two JavaScript-language config files (`vite.config.js` and `tailwind.config.js`) to have the `.config.mjs` extension
+- I changed my empty TypeScript code file from `main.ts` to `main.mts`
+- Any future TypeScript files that I create will also use the `.mts` extension
+
+This decision was made to work around two different restrictions that I encounter when programming at school:
+
+- `.js` files are prohibited to be created in my home directory on the school network, so I wouldn't be able to work on them locally at school
+- When accessing the internet at school, any URL ending in `.ts` is blocked, which would make it more difficult to view those files on GitHub. This would be an inconvenience rather than a show-stopper though.
+
+To avoid those problems, I will use the `.mjs` and `.mts` extensions for my JavaScript and TypeScript files, respectively. While these are less common, they still have essentially the same meaning, and are supported by my tools (e.g. VSCode, Vite).
+
---
From 20931f1a5d7c9342d5c453cb4bfdf9168dd890b5 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 19:38:22 +0000
Subject: [PATCH 20/64] start work on the backend too
---
docs/readme.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/docs/readme.md b/docs/readme.md
index b3fd6d6..6bd001d 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -145,6 +145,10 @@ A-level Computer Science programming project
- [Starting work on the frontend](#starting-work-on-the-frontend)
- [Initial web app bootstrap](#initial-web-app-bootstrap)
- [Using unusual file extensions](#using-unusual-file-extensions)
+ - [Starting work on the backend](#starting-work-on-the-backend)
+ - [Preparing to start the backend](#preparing-to-start-the-backend)
+ - [Command-line argument parsing functions](#command-line-argument-parsing-functions)
+ - [Testing](#testing)
## Analysis
@@ -1599,6 +1603,8 @@ To separate frontend and backend code, I have put the files in a `frontend` dire
I started setting up my development environment by installing dependencies with Yarn (as per my [frontend technologies](#frontend-technologies) decision). While ideally I would use a modern Yarn version, I've decided to stick with Yarn 1, because it's installed by default in GitHub Codespaces (which I plan to use for some of my development), and I won't be using any advanced Yarn features.
+I initialised a Git repository, giving it the name `marvellous-mapping-machine`, because version control will be very useful. I also published it to a GitHub repository to let me access my code from different machines, and to allow anyone interested to view my code.
+
##### Using unusual file extensions
I made a couple of changes to the file extensions I use, away from what the Vite template used:
@@ -1614,6 +1620,65 @@ This decision was made to work around two different restrictions that I encounte
To avoid those problems, I will use the `.mjs` and `.mts` extensions for my JavaScript and TypeScript files, respectively. While these are less common, they still have essentially the same meaning, and are supported by my tools (e.g. VSCode, Vite).
+#### Starting work on the backend
+
+##### Preparing to start the backend
+
+I created a `backend` folder next to the `frontend` one. I considered using codenames for the frontend and backend to make the code project more interesting and unique, but decided against it because the names would be harder to remember and identify at a glance.
+
+##### Command-line argument parsing functions
+
+I then started implementing the command-line argument parsing functions that will be required to find the OSM data file.
+
+```python
+from sys import argv, stderr
+
+
+def print_error(message):
+ print(message, file=stderr)
+
+
+def validate_args():
+ if len(argv) == 2:
+ return True
+ if len(argv) < 2:
+ print_error(
+ f"Please provide a path to the OSM data file, e.g. {argv[0]} region.osm",
+ )
+ return False
+ print_error(
+ f"Too many arguments provided. Please provide a path to the OSM data file, e.g. {argv[0]} region.osm",
+ )
+ return False
+
+
+def get_data_file_path():
+ return argv[1]
+
+
+if __name__ == "__main__":
+ if not validate_args():
+ exit(1)
+
+ data_file_path = get_data_file_path()
+ print(data_file_path)
+```
+
+I decided to give the validation for arguments its own function, `validate_args()`, because it will allow me to write unit tests for it later on. I also decided to give the error printing its own function, `print_error()`, in case I want to use a library for logging or make it more complicated in some other way later on. Similarly, `get_data_file_path()` is its own function in case I want to make the logic more complicated later on, and to make it easier to test.
+
+I also improved my validation from my validation plan to also check if too many arguments are provided, to match usual argument parsing conventions.
+
+###### Testing
+
+I started off by testing the too many/few arguments cases:
+
+```shell
+$ python main.py
+Please provide a path to the OSM data file, e.g. main.py region.osm
+$ python main.py arg1 arg2
+Too many arguments provided. Please provide a path to the OSM data file, e.g. main.py region.osm
+```
+
---
From c8dc3b76b9e919e3c1ef4736f6bbccaddc44a72f Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 19:41:35 +0000
Subject: [PATCH 21/64] +
---
docs/readme.md | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/docs/readme.md b/docs/readme.md
index 6bd001d..d708f63 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -148,7 +148,6 @@ A-level Computer Science programming project
- [Starting work on the backend](#starting-work-on-the-backend)
- [Preparing to start the backend](#preparing-to-start-the-backend)
- [Command-line argument parsing functions](#command-line-argument-parsing-functions)
- - [Testing](#testing)
## Analysis
@@ -1668,9 +1667,7 @@ I decided to give the validation for arguments its own function, `validate_args(
I also improved my validation from my validation plan to also check if too many arguments are provided, to match usual argument parsing conventions.
-###### Testing
-
-I started off by testing the too many/few arguments cases:
+I then tested the too many/few arguments cases:
```shell
$ python main.py
@@ -1679,6 +1676,23 @@ $ python main.py arg1 arg2
Too many arguments provided. Please provide a path to the OSM data file, e.g. main.py region.osm
```
+The results are successful, but I wanted to adjust the error messages to be more consistent:
+
+```diff
+- Please provide a path to the OSM data file, e.g. {argv[0]} region.osm
++ Too few arguments. Please provide a path to the OSM data file, e.g. {argv[0]} region.osm
+
+- Too many arguments provided. Please provide a path to the OSM data file, e.g. {argv[0]} region.osm
++ Too many arguments. Please provide a path to the OSM data file, e.g. {argv[0]} region.osm
+```
+
+I then checked that it printed the filename I provided it with:
+
+```shell
+$ python main.py filee
+filee
+```
+
---
From 106267686437cd235c5708db383dc6f73edeeb6d Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Tue, 19 Nov 2024 19:57:14 +0000
Subject: [PATCH 22/64] +
---
.vscode/settings.json | 1 +
docs/readme.md | 43 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5bde8e0..3c5773b 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -3,6 +3,7 @@
"Codespaces",
"daisyUI",
"deprioritise",
+ "docstrings",
"Excalidraw",
"Geofabrik",
"GraphHopper",
diff --git a/docs/readme.md b/docs/readme.md
index d708f63..1cfbb84 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -148,6 +148,7 @@ A-level Computer Science programming project
- [Starting work on the backend](#starting-work-on-the-backend)
- [Preparing to start the backend](#preparing-to-start-the-backend)
- [Command-line argument parsing functions](#command-line-argument-parsing-functions)
+ - [Validating the provided file path](#validating-the-provided-file-path)
## Analysis
@@ -1693,6 +1694,48 @@ $ python main.py filee
filee
```
+This test was also successful.
+
+##### Validating the provided file path
+
+I created a function to handle validation of the file path provided, keeping it similar in structure to the argument validation function:
+
+```python
+def validate_file_is_readable(file_path: str):
+ """Returns True if the provided path points to an existing, readable, file-y file.
+ Otherwise, prints an appropriate error message and returns False."""
+ try:
+ with open(file_path, "r") as file:
+ if not Path(file.name).is_file():
+ print_error(f"Cannot access {file_path}: not a file")
+ return True
+
+ except FileNotFoundError:
+ print_error(f"File {file_path} not found.")
+ return False
+ except PermissionError:
+ print_error(f"Cannot access file {file_path}: permission denied")
+ return False
+```
+
+I then realised that my other functions didn't have docstrings or type annotations, so I added them to aid maintainability and readability:
+
+```python
+def print_error(message: str):
+ """Prints an error message to stderr"""
+```
+
+```python
+def validate_args():
+ """Returns True if the number of command-line arguments to the program is correct.
+ Otherwise, prints an appropriate error message and returns False."""
+```
+
+```python
+def get_data_file_path():
+ """Returns the path to the OSM data file that should be used by the routing engine"""
+```
+
---
From c74877d5634ecb570fc868cdecd1db4aa7687e55 Mon Sep 17 00:00:00 2001
From: RandomSearch <101704343+RandomSearch18@users.noreply.github.com>
Date: Wed, 20 Nov 2024 09:03:07 +0000
Subject: [PATCH 23/64] +
---
.vscode/settings.json | 2 +
.../sprint-1/file-validation-terminal.png | Bin 0 -> 113058 bytes
docs/readme.md | 60 ++++++++++++++++++
3 files changed, 62 insertions(+)
create mode 100644 docs/assets/sprint-1/file-validation-terminal.png
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3c5773b..cd7f30f 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,6 +4,7 @@
"daisyUI",
"deprioritise",
"docstrings",
+ "errno",
"Excalidraw",
"Geofabrik",
"GraphHopper",
@@ -28,6 +29,7 @@
"Routor",
"runtimes",
"satnavs",
+ "traceback",
"Travelling",
"typescriptlang.org",
"unsignalled"
diff --git a/docs/assets/sprint-1/file-validation-terminal.png b/docs/assets/sprint-1/file-validation-terminal.png
new file mode 100644
index 0000000000000000000000000000000000000000..cf57ea4e7f3f9be79b2530228cddd8e95047e873
GIT binary patch
literal 113058
zcmZs?bx>VR@Ft7|2p;_61b25QxD(vn-8De45ZwLZdU1DmcMlTu;sp20@^00y>ic&0
zk5g0CGiQ2ERZn-H?&pb6QIbYQB0z$If
p-!wva-@S!tsAh
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