Skip to content

Commit

Permalink
Merge pull request #80 from agiledev-students-fall2023/Jaden's-Branch
Browse files Browse the repository at this point in the history
added optimal route-finding algorithm
  • Loading branch information
anaspacheco authored Nov 27, 2023
2 parents ce41a67 + e04b7ae commit 52ce2e9
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 8 deletions.
33 changes: 33 additions & 0 deletions back-end/app.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
// import and instantiate express
const express = require('express'); // CommonJS import style!
const app = express(); // instantiate an Express object
require('dotenv').config();
// we will put some server logic here later...

const cors = require('cors');
const { createGraph, findOptimalRoute } = require('./getOptimizedRoute.js');
app.use(cors());

module.exports = app;



app.get('/getRoute', (req, res) => {
const busStops = {
unionsquare: [40.73498551788369, -73.990696048825],
tompkins: [40.7251277537963, -73.98121749968648],
hamilton: [40.720213039417494, -73.980207088181],
eastbroadway: [40.7141707879376, -73.9901227463216],
chinatown: [40.71559782189394, -73.99850504010124],
financial: [40.70811320415039, -74.00798229139403],
tribeca: [40.716765448621125, -74.00913568860388],
canal: [40.721857387647354, -74.00518353611693],
soho: [40.72488113646396, -74.00162848801607],
greenwich: [40.733368703161425, -74.00412600650982],
washingtonsquare: [40.731522867853634, -73.9971283464239],
jayst: [40.69225251854892, -73.98648974152808],
dumbo: [40.70372584858276, -73.98861865993923],
ikea: [40.672611811522145, -74.01009335210519]
}
const routes = {
route1: [busStops.washingtonsquare, busStops.unionsquare, busStops.tompkins, busStops.hamilton, busStops.eastbroadway, busStops.chinatown, busStops.financial, busStops.tribeca, busStops.canal, busStops.soho, busStops.greenwich, busStops.washingtonsquare],
route2: [busStops.jayst, busStops.dumbo, busStops.ikea],
route3: [busStops.jayst, busStops.eastbroadway, busStops.washingtonsquare, busStops.chinatown, busStops.financial],
route4: [busStops.eastbroadway, busStops.washingtonsquare, busStops.unionsquare, busStops.tompkins, busStops.hamilton, busStops.eastbroadway],
}
const graph = createGraph(routes);
let optimalRoute = findOptimalRoute(graph, req.query.origin, req.query.destination);
console.log(optimalRoute);
res.send('Hello World!');
})
101 changes: 101 additions & 0 deletions back-end/getOptimizedRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//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.*/
function createGraph(routes) {
let graph = {};
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();

if (!graph[currentKey]) {
graph[currentKey] = [];
}
graph[currentKey].push({ coordinates: nextStop, route: routeId });

}
}
return graph;
}

function getEuclideanDistance (origin, destination) {
let x1 = origin.split(',')[0];
let y1 = origin.split(',')[1];
let x2 = destination.split(',')[0];
let y2 = destination.split(',')[1];
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
function findAllReachableStops(graph, origin, threshold=0.013) {
let reachableStops = [];
for (busstop in graph){
busstop = busstop.toString();
let distance = getEuclideanDistance(busstop, origin);
if (distance < threshold) {
console.log('reachable stop found: '+graph[busstop][0].route);
reachableStops.push({coordinates: busstop, route: graph[busstop][0].route});
}
}

return reachableStops;

}
// return walking distance from point A to point B
async function getWalkingDistance(origin, destination) {
origin = origin.split(',').join('%2C');
destination = destination.split(',').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 data = await res.json();
res = data.rows[0].elements[0].duration.value;
return res;
}

function isOnSameRoute(stop1, stop2) {
console.log(stop1.route);
return stop1.route === stop2.route;
}

async function findOptimalRoute(graph, origin, destination) {
let minTotalDistance = Number.MAX_VALUE;
let optimalRoute = null;

// Find all reachable stops from origin and destination
let reachableFromOrigin = findAllReachableStops(graph, origin);
let reachableFromDestination = findAllReachableStops(graph, destination);

// Calculate route distances
for (let originStop of reachableFromOrigin) {
for (let destinationStop of reachableFromDestination) {
if (isOnSameRoute(originStop, destinationStop)) {
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);
console.log('----------------------------------')
// Check if this route is better than the current best
if (totalDistance < minTotalDistance) {
minTotalDistance = totalDistance;
optimalRoute = { originStop, destinationStop };
}
}
}
}
console.log('optimal route: '+optimalRoute.originStop.route);
console.log('origin stop: '+optimalRoute.originStop.coordinates);
console.log('destination stop: '+optimalRoute.destinationStop.coordinates);

return optimalRoute;
}

module.exports = {
createGraph,
getEuclideanDistance,
findAllReachableStops,
getWalkingDistance,
isOnSameRoute,
findOptimalRoute
}
22 changes: 14 additions & 8 deletions front-end/src/utils/transportMarker.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function updateTransportMarkers(transportData, markerRef, map) {
const lat = parseFloat(transportInfo.latitude);
const lng = parseFloat(transportInfo.longitude);
const newPosition = new window.google.maps.LatLng(lat, lng);
const iconUpdate = marker && marker.direction !== transportInfo.calculatedCourse;
const iconUpdate = marker && (marker.direction !== transportInfo.calculatedCourse || transportInfo.route === 'Ferry Route');

if (marker) {
// Update the position of the existing marker
Expand All @@ -29,12 +29,12 @@ export function updateTransportMarkers(transportData, markerRef, map) {

// Update the icon of the existing marker
if (iconUpdate) {
const newIcon = generateTransportMarkerIcon(transportInfo.color, transportInfo.calculatedCourse);
const newIcon = generateTransportMarkerIcon(transportInfo.color, transportInfo.calculatedCourse, transportInfo.route);
marker.setIcon(newIcon);
}
} else {
// Create a new marker
const newIcon = generateTransportMarkerIcon(transportInfo.color, transportInfo.calculatedCourse);
const newIcon = generateTransportMarkerIcon(transportInfo.color, transportInfo.calculatedCourse, transportInfo.route);
let transportMarker = createTransportMarker(newPosition, transportInfo, map, newIcon);
markerRef.current[transport] = transportMarker;
}
Expand All @@ -46,11 +46,11 @@ function createTransportMarker(position, transportInfo, map) {
position,
map,
title: String(transportInfo.busId),
icon: generateTransportMarkerIcon(transportInfo.color || '#000', transportInfo.calculatedCourse || 0),
icon: generateTransportMarkerIcon(transportInfo.color || '#000', transportInfo.calculatedCourse || 0, transportInfo.route || 0),
});

let infowindow = new window.google.maps.InfoWindow({
content: `<div><strong>No.${transportInfo.busId}</strong><br>Line: ${transportInfo.route}</div>`,
content: `<div><strong>No.${transportInfo.busId}</strong><br>Line: ${transportInfo.route}</div>Passenger Count: ${transportInfo.paxLoad}</div>`,
});

transportMarker.direction = transportInfo.calculatedCourse;
Expand Down Expand Up @@ -108,7 +108,7 @@ function animateMarker(marker, startPosition, endPosition, duration) {

// Generate custom transport marker icon (currently only support buses)
// Original source of bus svg path: www.svgrepo.com
function generateTransportMarkerIcon(color, direction) {
function generateTransportMarkerIcon(color, direction, route) {
const svg = `<?xml version="1.0" encoding="utf-8"?>
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
<g class="layer" transform="rotate(${direction}, 12, 12)">
Expand All @@ -122,9 +122,15 @@ function generateTransportMarkerIcon(color, direction) {
</g>
</g>
</svg>`;
let iconImg = 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg);
let scaledSize = new window.google.maps.Size(40, 40);
if (route === 'Ferry Route') {
iconImg = 'busIcons/busIcon_routeFerry_Route.png';
scaledSize= new window.google.maps.Size(30, 30);
}
const icon = {
url: 'data:image/svg+xml;charset=UTF-8;base64,' + btoa(svg),
scaledSize: new window.google.maps.Size(40, 40),
url: iconImg,
scaledSize: scaledSize,
};
return icon;
}
Expand Down

0 comments on commit 52ce2e9

Please sign in to comment.