From 529a4cc3bdd15092f6ffd8603adb18fbc11f4eb9 Mon Sep 17 00:00:00 2001
From: Aeonoi <143847987+Aeonoi@users.noreply.github.com>
Date: Fri, 22 Sep 2023 16:49:31 -0400
Subject: [PATCH 1/2] Added byRequest property
---
Public/routes-data/fall23.gpx | 14 ++++++++++++++
Sources/App/Migrations/CreateStops.swift | 1 +
Sources/App/Models/Stop.swift | 6 +++++-
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/Public/routes-data/fall23.gpx b/Public/routes-data/fall23.gpx
index 8a0d4b7..9e1f973 100644
--- a/Public/routes-data/fall23.gpx
+++ b/Public/routes-data/fall23.gpx
@@ -13,45 +13,59 @@
Student Union
+ No Request
Academy Hall
+ Request Only
Tibbits Avenue
+ Request Only
Polytechnic Residence Commons
+ No Request
City Station
+ No Request
Blitman Residence Commons
+ No Request
West Hall
+ No Request
’87 Gymnasium
+ No Request
Barton Hall
+ Request Only
B-Lot
+ Request Only
Stacwyck
+ No Request
Bryckwyck
+ No Request
RAHP-B
+ No Request
Colonie
+ No Request
West Route
diff --git a/Sources/App/Migrations/CreateStops.swift b/Sources/App/Migrations/CreateStops.swift
index b24f647..eaf62dc 100644
--- a/Sources/App/Migrations/CreateStops.swift
+++ b/Sources/App/Migrations/CreateStops.swift
@@ -17,6 +17,7 @@ struct CreateStops: AsyncMigration {
.field("name", .string, .required)
.field("coordinate", .dictionary, .required)
.field("schedule", .dictionary, .required)
+ .field("isByRequest", .string, .required)
.create()
}
diff --git a/Sources/App/Models/Stop.swift b/Sources/App/Models/Stop.swift
index 90c28a0..d118793 100644
--- a/Sources/App/Models/Stop.swift
+++ b/Sources/App/Models/Stop.swift
@@ -28,6 +28,9 @@ final class Stop: Equatable, Hashable, Model, Content {
@Field(key: "schedule")
var schedule: MapSchedule
+
+ @Field(key: "isByRequest")
+ var isByRequest: Bool
init() { }
@@ -37,12 +40,13 @@ final class Stop: Equatable, Hashable, Model, Content {
/// - schedule: The schedule for when the stop will be active.
/// - Note: This initializer fails and returns `nil` if the provided GPX waypoint doesn’t contain sufficient information to create a stop object.
init?(from gpxWaypoint: any GPXWaypointProtocol, withSchedule schedule: MapSchedule) {
- guard let name = gpxWaypoint.name, let coordinate = Coordinate(from: gpxWaypoint) else {
+ guard let name = gpxWaypoint.name, let coordinate = Coordinate(from: gpxWaypoint), let isByRequest: String? = gpxWaypoint.desc else {
return nil
}
self.name = name
self.coordinate = coordinate
self.schedule = schedule
+ self.isByRequest = (isByRequest == "Request Only")
}
func hash(into hasher: inout Hasher) {
From 1f072f9e0cee7540cb4cc438616bb258d87f2f8f Mon Sep 17 00:00:00 2001
From: Aeonoi <143847987+Aeonoi@users.noreply.github.com>
Date: Fri, 6 Oct 2023 16:42:17 -0400
Subject: [PATCH 2/2] Associated Stops With Routes
---
Public/routes-data/fall22-event.gpx | 15 ++++++++++++
Public/routes-data/fall22.gpx | 16 +++++++++++++
Public/routes-data/spring22.gpx | 15 ++++++++++++
Public/routes-data/spring23.gpx | 16 +++++++++++++
.../routes-data/summer22-weekday-testing.gpx | 7 ++++++
Public/routes-data/summer22-weekday.gpx | 6 +++++
Public/routes-data/summer22-weekend.gpx | 7 ++++++
Sources/App/Jobs/GPXImportingJob.swift | 13 ++++++----
Sources/App/Migrations/CreateStops.swift | 3 ++-
Sources/App/Models/Route.swift | 21 +++++++++++++++-
Sources/App/Models/Stop.swift | 24 ++++++++++++++-----
Sources/App/Utilities.swift | 2 ++
12 files changed, 132 insertions(+), 13 deletions(-)
diff --git a/Public/routes-data/fall22-event.gpx b/Public/routes-data/fall22-event.gpx
index 592410d..a42aeb8 100644
--- a/Public/routes-data/fall22-event.gpx
+++ b/Public/routes-data/fall22-event.gpx
@@ -13,48 +13,63 @@
Student Union
+ No Request
Academy Hall
+ Request Only
Tibbits Avenue
+ Request Only
Polytechnic Residence Commons
+ No Request
City Station
+ No Request
Blitman Residence Commons
+ No Request
Heffner Alumni House
+ No Request
Barton Hall
+ No Request
B-Lot
+ Request Only
E-Lot
+ No Request
Stacwyck
+ No Request
Bryckwyck
+ No Request
RAHP-B
+ No Request
Georgian Court
+ Request Only
Colonie
+ No Request
Special Event West Route
diff --git a/Public/routes-data/fall22.gpx b/Public/routes-data/fall22.gpx
index 6954dac..999cb2c 100644
--- a/Public/routes-data/fall22.gpx
+++ b/Public/routes-data/fall22.gpx
@@ -13,51 +13,67 @@
Student Union
+ No Request
Academy Hall
+ Request Only
Tibbits Avenue
+ Request Only
Polytechnic Residence Commons
+ No Request
City Station
+ No Request
Blitman Residence Commons
+ No Request
West Hall
+ No Request
’87 Gymnasium
+ No Request
Barton Hall
+ Request Only
B-Lot
+ Request Only
E-Lot
+ No Request
Stacwyck
+ No Request
Bryckwyck
+ No Request
RAHP-B
+ No Request
Georgian Court
+ Request Only
Colonie
+ No Request
West Route
diff --git a/Public/routes-data/spring22.gpx b/Public/routes-data/spring22.gpx
index c2fb5c7..f8e6d27 100644
--- a/Public/routes-data/spring22.gpx
+++ b/Public/routes-data/spring22.gpx
@@ -13,48 +13,63 @@
Student Union
+ No Request
Academy Hall
+ Request Only
Tibbits Avenue
+ Request Only
Polytechnic Residence Commons
+ No Request
City Station
+ No Request
Blitman Residence Commons
+ No Request
West Hall
+ No Request
’87 Gymnasium
+ No Request
Barton Hall
+ Request Only
B-Lot
+ Request Only
ECAV Arena
+ No Request
Stacwyck
+ No Request
Bryckwyck
+ No Request
Beman Lane
+ No Request
The Armory
+ No Request
Route
diff --git a/Public/routes-data/spring23.gpx b/Public/routes-data/spring23.gpx
index a1c3306..65ee78b 100644
--- a/Public/routes-data/spring23.gpx
+++ b/Public/routes-data/spring23.gpx
@@ -13,51 +13,67 @@
Student Union
+ No Request
Academy Hall
+ Request Only
Tibbits Avenue
+ Request Only
Polytechnic Residence Commons
+ No Request
City Station
+ No Request
Blitman Residence Commons
+ No Request
West Hall
+ No Request
’87 Gymnasium
+ No Request
Barton Hall
+ Request Only
B-Lot
+ Request Only
E-Lot
+ Request Only
Stacwyck
+ No Request
Bryckwyck
+ No Request
RAHP-B
+ No Request
Georgian Court
+ Request Only
Colonie
+ No Request
West Route
diff --git a/Public/routes-data/summer22-weekday-testing.gpx b/Public/routes-data/summer22-weekday-testing.gpx
index a47febc..330e532 100644
--- a/Public/routes-data/summer22-weekday-testing.gpx
+++ b/Public/routes-data/summer22-weekday-testing.gpx
@@ -13,24 +13,31 @@
Student Union
+ No Request
Academy Hall
+ Request Only
West Hall
+ No Request
’87 Gymnasium
+ No Request
Barton Hall
+ Request Only
East Campus Athletic Village
+ No Request
Burdett Avenue
+ No Request
Weekday Testing Route
diff --git a/Public/routes-data/summer22-weekday.gpx b/Public/routes-data/summer22-weekday.gpx
index 2ad5093..cd406a7 100644
--- a/Public/routes-data/summer22-weekday.gpx
+++ b/Public/routes-data/summer22-weekday.gpx
@@ -13,21 +13,27 @@
Student Union
+ No Request
Academy Hall
+ Request Only
West Hall
+ No Request
’87 Gymnasium
+ No Request
Barton Hall
+ Request Only
Burdett Avenue
+ No Request
Weekday Route
diff --git a/Public/routes-data/summer22-weekend.gpx b/Public/routes-data/summer22-weekend.gpx
index b1ec5a9..3cb186a 100644
--- a/Public/routes-data/summer22-weekend.gpx
+++ b/Public/routes-data/summer22-weekend.gpx
@@ -13,24 +13,31 @@
Student Union
+ No Request
Academy Hall
+ Request Only
Blitman Residence Commons
+ No Request
West Hall
+ No Request
’87 Gymnasium
+ No Request
Barton Hall
+ Request Only
Burdett Avenue
+ No Request
Weekend Route
diff --git a/Sources/App/Jobs/GPXImportingJob.swift b/Sources/App/Jobs/GPXImportingJob.swift
index 67b2353..5f312cb 100644
--- a/Sources/App/Jobs/GPXImportingJob.swift
+++ b/Sources/App/Jobs/GPXImportingJob.swift
@@ -55,18 +55,21 @@ struct GPXImportingJob: AsyncScheduledJob {
errorPrint("Couldn’t parse GPX file “\(routesFileURL.lastPathComponent)”")
continue
}
+ var allRoutes: Set = []
for gpxRoute in gpx.routes {
do {
- try await Route(from: gpxRoute, schedule: schedule)
+ let route = Route(from: gpxRoute, schedule: schedule)
+ allRoutes.insert(route)
+ try await route
.save(on: context.application.db(.sqlite))
- for gpxWaypoint in gpx.waypoints {
- try await Stop(from: gpxWaypoint, withSchedule: schedule)!
- .save(on: context.application.db(.sqlite))
- }
} catch {
errorPrint("Couldn’t import GPX route from file “\(routesFileURL.lastPathComponent)”: \(error)")
}
}
+ for gpxWaypoint in gpx.waypoints {
+ try await Stop(from: gpxWaypoint, withSchedule: schedule, selectingRoutesFrom: allRoutes)!
+ .save(on: context.application.db(.sqlite))
+ }
}
}
diff --git a/Sources/App/Migrations/CreateStops.swift b/Sources/App/Migrations/CreateStops.swift
index eaf62dc..0f4d2a3 100644
--- a/Sources/App/Migrations/CreateStops.swift
+++ b/Sources/App/Migrations/CreateStops.swift
@@ -17,7 +17,8 @@ struct CreateStops: AsyncMigration {
.field("name", .string, .required)
.field("coordinate", .dictionary, .required)
.field("schedule", .dictionary, .required)
- .field("isByRequest", .string, .required)
+ .field("is_by_request", .string, .required)
+ .field("route_id", .array(of: .uuid), .required)
.create()
}
diff --git a/Sources/App/Models/Route.swift b/Sources/App/Models/Route.swift
index 2f79dee..33fafc2 100644
--- a/Sources/App/Models/Route.swift
+++ b/Sources/App/Models/Route.swift
@@ -14,7 +14,7 @@ import Vapor
/// A representation of a shuttle route.
///
/// A route is represented as a sequence of geospatial coordinates.
-final class Route: Model, Content, Collection {
+final class Route: Equatable, Hashable, Model, Content, Collection {
static let schema = "routes"
@@ -118,6 +118,14 @@ final class Route: Model, Content, Collection {
return self.coordinates[index]
}
+ func hash(into hasher: inout Hasher) {
+ hasher.combine(self.id)
+ }
+
+ static func == (lhs: Route, rhs: Route) -> Bool {
+ return lhs.id == rhs.id && lhs.name == rhs.name
+ }
+
func index(after oldIndex: Int) -> Int {
return oldIndex + 1
}
@@ -135,5 +143,16 @@ final class Route: Model, Content, Collection {
}
return distance < Constants.isOnRouteThreshold
}
+
+ func checkStopIsOnRoute(Coordinate: Coordinate) -> Bool {
+ let distance = LineString(self.coordinates)
+ .closestCoordinate(to: Coordinate)?
+ .coordinate
+ .distance(to: Coordinate)
+ guard let distance else {
+ return false
+ }
+ return distance < Constants.isStopOnRouteThreshold
+ }
}
diff --git a/Sources/App/Models/Stop.swift b/Sources/App/Models/Stop.swift
index d118793..13329cb 100644
--- a/Sources/App/Models/Stop.swift
+++ b/Sources/App/Models/Stop.swift
@@ -29,26 +29,39 @@ final class Stop: Equatable, Hashable, Model, Content {
@Field(key: "schedule")
var schedule: MapSchedule
- @Field(key: "isByRequest")
+ @Field(key: "is_by_request")
var isByRequest: Bool
-
+
+ @Field(key: "route_id")
+ var routeID: Set
+
init() { }
/// Creates a stop object from a GPX waypoint.
/// - Parameters:
/// - gpxWaypoint: The GPX waypoint from which to create a stop object.
/// - schedule: The schedule for when the stop will be active.
+ /// - route: The set of routes to associate each stop object with a routeID
/// - Note: This initializer fails and returns `nil` if the provided GPX waypoint doesn’t contain sufficient information to create a stop object.
- init?(from gpxWaypoint: any GPXWaypointProtocol, withSchedule schedule: MapSchedule) {
- guard let name = gpxWaypoint.name, let coordinate = Coordinate(from: gpxWaypoint), let isByRequest: String? = gpxWaypoint.desc else {
+ init?(from gpxWaypoint: any GPXWaypointProtocol, withSchedule schedule: MapSchedule, selectingRoutesFrom allRoutes: Set) {
+ guard let name = gpxWaypoint.name, let coordinate = Coordinate(from: gpxWaypoint), let isByRequest = gpxWaypoint.desc
+ else {
return nil
}
self.name = name
self.coordinate = coordinate
self.schedule = schedule
self.isByRequest = (isByRequest == "Request Only")
+ self.routeID = []
+ for route in allRoutes {
+ if let id = route.id{
+ if (route.checkStopIsOnRoute(Coordinate: self.coordinate)) {
+ self.routeID.insert(id)
+ }
+ }
+ }
}
-
+
func hash(into hasher: inout Hasher) {
hasher.combine(self.name) // Hashing the ID could potentially violate Hashable’s invariants when the ID is determined by the database, so we hash the name instead. This means that stop names must be globally unique, which doesn’t seem to be too far-fetched as an assumption/requirement.
}
@@ -56,5 +69,4 @@ final class Stop: Equatable, Hashable, Model, Content {
static func == (lhs: Stop, rhs: Stop) -> Bool {
return lhs.name == rhs.name && lhs.coordinate == rhs.coordinate
}
-
}
diff --git a/Sources/App/Utilities.swift b/Sources/App/Utilities.swift
index d89428f..e248ac8 100644
--- a/Sources/App/Utilities.swift
+++ b/Sources/App/Utilities.swift
@@ -121,6 +121,8 @@ enum Constants {
/// The maximum perpendicular distance, in meters, away from a route at which a coordinate is considered to be “on” that route.
static let isOnRouteThreshold: Double = 5
+ static let isStopOnRouteThreshold: Double = 20
+
static let apnsTopic = "com.gerzer.shuttletracker"
}