Skip to content

Commit

Permalink
Merge pull request #123 from agiledev-students-fall2023/Jaden's-Branch
Browse files Browse the repository at this point in the history
Walking-route display, UI overhaul
  • Loading branch information
anaspacheco authored Dec 6, 2023
2 parents 3c1cdb8 + 0b9d30c commit 657f3b9
Show file tree
Hide file tree
Showing 12 changed files with 507 additions and 141 deletions.
24 changes: 14 additions & 10 deletions back-end/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,19 @@ app.post("/getRoute", async (req, res) => {
const routeFinding = require("./getOptimizedRoute.js");
const busStops = {};
//parse stops into a dictionary of coordinates
for (let stopkey in req.body.stops) {
let latitude = req.body.stops[stopkey].latitude
let longitude = req.body.stops[stopkey].longitude
let stopID = req.body.stops[stopkey].stopId
busStops[stopID] = [latitude, longitude]
for (let stopKey in req.body.stops) {
let latitude = req.body.stops[stopKey].latitude;
let longitude = req.body.stops[stopKey].longitude;
let stopID = req.body.stops[stopKey].stopId;

// Initialize the object if it doesn't exist
if (!busStops[stopID]) {
busStops[stopID] = {};
}

busStops[stopID].geoLoc = [latitude, longitude];
busStops[stopID].stopId = stopID;
}
console.log('<----------Stops---------->')
console.log(busStops)

//parse routes into a dictionary of routes, each holding an
//array of stops
let routes = {};
Expand Down Expand Up @@ -87,8 +91,8 @@ app.post("/getRoute", async (req, res) => {
req.body.destination_lat,
req.body.destination_lng,
);
console.log(optimalRoute.onSameRoute);
res.send(optimalRoute.onSameRoute);
console.log(optimalRoute.originStop.stopId);
res.send(optimalRoute);
}
catch(err){
console.log(err);
Expand Down
106 changes: 80 additions & 26 deletions back-end/getOptimizedRoute.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
//this function creates a directed circular graph representation of of bus stops and the routes.
/*in the output graph, the key represents a bus stop, and the value represents all the bus stops that
are directly reachavble from the key bus stop.*/
async function createGraph(routes, busstops) {
async function createGraph(routes, busStops) {
let graph = {};

// Initialize the graph with all stops and an empty list of routes
for (let stop in busstops) {
let stopKey = busstops[stop].toString();
graph[stopKey] = { routes: [], connections: [] };
for (let stopKey in busStops) {
graph[stopKey] = { routes: [], connections: [], stopId: busStops[stopKey].stopId, geoLoc: busStops[stopKey].geoLoc };
}

for (let routeId in routes) {
let stops = routes[routeId];
for (let i = 0; i < stops.length; i++) {
let currentStop = stops[i];
let nextStop = stops[(i + 1) % stops.length];
let currentKey = currentStop.toString();
let currentStopId = stops[i].stopId;
let nextStopId = stops[(i + 1) % stops.length].stopId;

// Add the current route to the list of routes for this stop
if (!graph[currentKey].routes.includes(routeId)) {
graph[currentKey].routes.push(routeId);
if (!graph[currentStopId].routes.includes(routeId)) {
graph[currentStopId].routes.push(routeId);
}

// Add the connection information
graph[currentKey].connections.push({ coordinates: nextStop, route: graph[currentKey].routes });
// Assuming that you only need the next stop's ID
graph[currentStopId].connections.push({ stopId: nextStopId, coordinates: stops[i].geoLoc });
}
}
return graph;
Expand All @@ -31,25 +31,43 @@ async function createGraph(routes, busstops) {
function getEuclideanDistance (a, b) {
let x1 = a[0];
let y1 = a[1];
let x2 = b.split(',')[0];
let y2 = b.split(',')[1];
let x2;
let y2;
try{
x2 = b.split(',')[0];
y2 = b.split(',')[1];
}
catch(err){
x2 = b[0];
y2 = b[1];
}
console.log('x1: '+x1+', y1: '+y1+', x2: '+x2+', y2: '+y2)

return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
}

//find bus stops that are relatively close in term of walking distance
async function findAllReachableStops(graph, origin, threshold=0.01) {
async function findAllReachableStops(graph, origin, threshold=0.008, maxThreshold=0.1) {

let resolvedGraph = await graph; // Waits for the graph Promise to resolve

console.log('resolvedGraph:',Object.keys(resolvedGraph))
let reachableStops = [];
for (let busstop in resolvedGraph) {
busstop = busstop.toString();
let distance = getEuclideanDistance(origin, busstop);
console.log('geoloc:', resolvedGraph[busstop].geoLoc)
let geoLoc = resolvedGraph[busstop].geoLoc;
let busstopId = resolvedGraph[busstop].stopId;
let distance = getEuclideanDistance(origin, geoLoc);
console.log('distance: '+distance)
if (distance < threshold) {
console.log('reachable stop found: ' + resolvedGraph[busstop].routes);
reachableStops.push({ coordinates: busstop, route: resolvedGraph[busstop].route });
console.log('reachable stop found for: '+ origin + ', ' + resolvedGraph[busstop].routes);
reachableStops.push({ coordinates: geoLoc, route: resolvedGraph[busstop].routes, stopId: busstopId });
}
}
//when no stops are found, keep calling itself with larger and larger threshold
if (reachableStops.length == 0 && threshold < maxThreshold) {
console.log('no reachable stop found, increasing threshold');
reachableStops = findAllReachableStops(graph, origin, threshold + 0.002)
}

return reachableStops;
}
Expand All @@ -67,15 +85,19 @@ async function getWalkingDistance(origin, destination) {
destination = destination.join('%2C');
}

let res = await fetch(`https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=${origin}&destinations=${destination}&key=${process.env.EXPRESS_APP_MAP_API_KEY}`)
let res = await fetch(`https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=${origin}&destinations=${destination}&mode=walking&key=${process.env.EXPRESS_APP_MAP_API_KEY}`)
let data = await res.json();
res = data.rows[0].elements[0].duration.value;
res = {
distance: data.rows[0].elements[0].distance.value,
time: data.rows[0].elements[0].duration.text
};
return res;
}

async function isOnSameRoute(graph, stop1, stop2, routes, busstops) {
let resolvedGraph = await graph;
let sharedRoutes = await resolvedGraph[stop1.coordinates].routes.filter(element => resolvedGraph[stop2.coordinates].routes.includes(element));
console.log(Object.keys(resolvedGraph))
let sharedRoutes = await resolvedGraph[stop1.stopId].routes.filter(element => resolvedGraph[stop2.stopId].routes.includes(element));
if(sharedRoutes.length == 0){
return false;
}
Expand All @@ -91,23 +113,49 @@ async function findOptimalRoute(graph, routes, busstops, origin_lat, origin_lng,
let reachableFromOrigin = await findAllReachableStops(graph, origin);

let reachableFromDestination = await findAllReachableStops(graph, destination);
console.log('TOTAL REACHABLE STOPS: '+Number(reachableFromOrigin.length + reachableFromDestination.length))
// Calculate route distances
for (let originStop of reachableFromOrigin) {
for (let destinationStop of reachableFromDestination) {
let onSameRoute = await isOnSameRoute(graph, originStop, destinationStop, routes, busstops);
console.log('on same route result: '+onSameRoute)
if (onSameRoute.length > 0) {
let distanceToOriginStop = await getWalkingDistance(origin, originStop.coordinates);
let distanceFromDestinationStop = await getWalkingDistance(destinationStop.coordinates, destination);
let totalDistance = distanceToOriginStop + distanceFromDestinationStop;
console.log('fetched from Google Maps API, total distance: '+totalDistance);
let distanceToOriginStop
let distanceFromDestinationStop
let totalDistance
let totalTime
console.log('TOTAL REACHABLE STOPS2: '+reachableFromOrigin.length + reachableFromDestination.length)
if (Number(reachableFromOrigin.length + reachableFromDestination.length) < 20){

distanceToOriginStop = await getWalkingDistance(origin, originStop.coordinates);
distanceFromDestinationStop = await getWalkingDistance(destinationStop.coordinates, destination);
totalDistance = distanceToOriginStop.distance + distanceFromDestinationStop.distance;
console.log('fetched from Google Maps API, total distance: '+totalDistance);
totalTime = Number(distanceToOriginStop.time.split(' ')[0]) + Number(distanceFromDestinationStop.time.split(' ')[0]);
console.log('fetched from Google Maps API, total time: '+totalTime);
}
else{
distanceToOriginStop = await getEuclideanDistance(origin, originStop.coordinates);
distanceFromDestinationStop = await getEuclideanDistance(destinationStop.coordinates, destination);
totalDistance = distanceToOriginStop + distanceFromDestinationStop;
console.log('getting euclidean distance, total distance: '+totalDistance);

}

// Create an object with route names as keys and {distance, time} as values
let routeDetails = {};
for (let route of onSameRoute) {
routeDetails[route] = {distance: totalDistance, time: totalTime};
}

// Check if this route is better than the current best
if (totalDistance < minTotalDistance) {
console.log('new optimal route found')
minTotalDistance = totalDistance;
optimalRoute = { originStop, destinationStop, onSameRoute };
optimalRoute = { origin, originStop, destination, destinationStop, onSameRoute: routeDetails };
}
}

}
}

Expand All @@ -117,6 +165,12 @@ async function findOptimalRoute(graph, routes, busstops, origin_lat, origin_lng,
}
console.log('-------------------------------------')
console.log('optimal route: '+optimalRoute.onSameRoute);
for (let route in optimalRoute.onSameRoute) {

console.log('<-----------Route Name: '+route+'--------------->');
console.log('Total Distance: '+optimalRoute.onSameRoute[route].distance);
console.log('Total Time: '+optimalRoute.onSameRoute[route].time);
}
console.log('origin stop location: '+optimalRoute.originStop.coordinates);
console.log('destination stop location: '+optimalRoute.destinationStop.coordinates);

Expand Down
30 changes: 30 additions & 0 deletions front-end/src/components/RouteButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useState, useEffect } from 'react';
function RouteButton({ route }) {
const [color, setColor] = useState('rgba(0, 0, 0, 0)');
function hexToRGBA(hex, alpha) {
if (hex === undefined) {
return 'rgba(0, 0, 0, 0)'; // return transparent color if hex is undefined
}
let r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);

if (alpha) {
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
} else {
return `rgb(${r}, ${g}, ${b})`;
}
}

useEffect(() => {
setColor(hexToRGBA(route.color, 0.5));
}, [route.color]);

return (
<button className="w-20 h-20" style={{ backgroundColor: color }}>
{route.name}
</button>
);
}

export default RouteButton;
9 changes: 8 additions & 1 deletion front-end/src/components/RouteMap.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useEffect, useRef } from "react";
import "../css/routeMap.css";
import SaveRouteButton from "./SaveRouteButton";

function RouteMap({ location1, location2 }) {
const mapRef = useRef(null);
Expand Down Expand Up @@ -54,7 +55,13 @@ function RouteMap({ location1, location2 }) {
});
}, [location1, location2]);

return <div ref={mapRef} className="route_map"></div>;
return (
<div className="relative w-full">
<SaveRouteButton />
<div ref={mapRef} className="route_map"> </div>
</div>
)

}

export default RouteMap;
19 changes: 14 additions & 5 deletions front-end/src/components/RoutesPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,16 @@ function RoutesPage() {
console.log('awaiting data');
return }
if (fromLocation.name === lastLocation1.current.name && toLocation.name === lastLocation2.current.name) {
awaitingData.current = false;
return;
}
}
catch(typeError){
console.log('same input, no need to fetch new route');
}
if (fromLocation.name && toLocation.name) {
if (fromLocation.name && toLocation.name && fromLocation.name !== toLocation.name) {
awaitingData.current = true;
let reachableRoutes = fetch(`http://localhost:4000/getRoute`, {
let reachableRoutes = fetch(`/getRoute`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
Expand All @@ -97,13 +98,21 @@ function RoutesPage() {
.then((data) => {
lastLocation1.current = fromLocation;
lastLocation2.current = toLocation;
if (Object.keys(data).length === 0){
if (Object.keys(data.onSameRoute).length === 0){
alert('No route found');
return;
}
setRoutes(data);

console.log(Object.keys(data.onSameRoute).length)
if (Object.keys(data.onSameRoute).length === 7){
setRoutes(['You should walk instead!']);
}
else{
setRoutes(data.onSameRoute);
window.nyushuttle.startStopLocation = data.originStop.stopId;
window.nyushuttle.endStopLocation = data.destinationStop.stopId;
}
setShowSubpage(true);
alert('Starting' + JSON.stringify(data[0]));
return data;
})
.catch((error) => {
Expand Down
Loading

0 comments on commit 657f3b9

Please sign in to comment.