Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 18 additions & 48 deletions backend/controllers/getCongestion.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,22 @@
const axios = require("axios");
const API_URL = "https://route.ls.hereapi.com/routing/7.2/calculateroute.json";
const getColorForPercentage = require("../utils/getColorForPercentage");

async function getCongestionData(route, results, departureTime) {
let promises = [];
for (let i = 0; i < route.length; i++) {
let p = axios.get(API_URL, {
params: {
waypoint0: `${route[i].begin.lat},${route[i].begin.lng}`,
waypoint1: `${route[i].end.lat},${route[i].end.lng}`,
mode: "fastest;car;traffic:enabled",
apiKey: process.env.here_api_key,
departure: departureTime,
},
});
promises.push(p);
}
try {
let responses = await Promise.all(promises);
let result = [];
for (let i = 0; i < route.length; i++) {
let { baseTime, travelTime } = responses[
i
].data.response.route[0].summary;
let congestionValue = travelTime / baseTime;
let congestionColor =
route[i].transport.mode === "pedestrian"
? "green"
: getCongestionColor(congestionValue);

result = [...result, { ...route[i], congestionColor }];
}
results.push(result);
} catch (err) {
console.log(err);
}
}
async function calculateCongestion(routes, departureTime) {
let results = [];
for (let i = 0; i < routes.length; i++) {
await getCongestionData(routes[i], results, departureTime);
}
return results;
async function calculateCongestion(congestionParams) {
const congestionData =
congestionParams && congestionParams.length
? congestionParams.map((param, index) => {
const { baseDuration, duration } = param
? param
: { baseDuration: 1, duration: 1 };
const congestionValue =
duration / baseDuration < 1 ? 1 : duration / baseDuration;
const normalizedCongestion = Math.min(congestionValue - 1, 1);
return {
congestionValue,
congestionColor: getColorForPercentage(normalizedCongestion),
};
})
: [];
return congestionData;
}

function getCongestionColor(congestionValue) {
if (congestionValue < 1.25) return "green";
else if (congestionValue >= 1.25 && congestionValue < 1.5) return "blue";
else if (congestionValue >= 1.5 && congestionValue < 2) return "orange";
else if (congestionValue >= 2) return "red";
}
module.exports = calculateCongestion;
51 changes: 37 additions & 14 deletions backend/controllers/getPM2_5.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ exports.updateDatabase = async () => {
let lat1 = 28.08652,
lat2 = 28.921631,
long1 = 76.730347,
long2 = 77.631226;
long2 = 77.631226; // bouding coordinates for delhi region
const api_url = `https://api.waqi.info/map/bounds/?latlng=${lat1},${long1},${lat2},${long2}&token=${process.env.waqi_api_key}`;
await axios
.get(api_url)
Expand Down Expand Up @@ -41,7 +41,7 @@ exports.updateDatabase = async () => {
// console.log(database);
};

exports.getPM2_5 = (lat, lng) => {
exports.getPM2_5 = (lat, lng, currentDatabase) => {
const x1 = lat;
const y1 = lng;

Expand All @@ -58,7 +58,6 @@ exports.getPM2_5 = (lat, lng) => {

return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}
const currentDatabase = [...database]; // use contant value for a particular calculation as database is updated every 10 seconds
for (let i = 0; i < currentDatabase.length; i++) {
const x2 = currentDatabase[i].latitude;
const y2 = currentDatabase[i].longitude;
Expand All @@ -84,19 +83,43 @@ exports.getPMColor = (routes = [], minPm, maxPm) => {
routes.forEach((route) => {
colorizedPmRoutes = [
...colorizedPmRoutes,
route && route.length > 0
? route.map((section) => {
const normalizedPm =
maxPm > minPm ? (section.pmValue - minPm) / (maxPm - minPm) : -1;
return {
...section,
normalizedPm,
pmColor: getColorForPercentage(normalizedPm),
};
})
: {},
{
...route,
sections:
route.sections && route.sections.length > 0
? route.sections.map((section) => {
const normalizedPm =
maxPm > minPm
? (section.travelSummary.pmValue - minPm) / (maxPm - minPm)
: -1;
return {
...section,
travelSummary: {
...section.travelSummary,
normalizedPm,
pmColor: getColorForPercentage(normalizedPm),
},
};
})
: [],
},
];
});
// console.log(colorizedPmRoutes)
return colorizedPmRoutes;
};

exports.calculatePmValuesList = async (locationsList) => {
const currentDatabase = [...database]; // use contant value for a particular calculation as database is updated every 10 seconds
const promises = locationsList.map((location) => {
return new Promise((resolve, reject) =>
resolve(this.getPM2_5(location.lat, location.lng, currentDatabase))
);
});
try {
const responses = await Promise.all(promises);
return responses;
} catch (err) {
console.log(err);
}
};
213 changes: 128 additions & 85 deletions backend/views/travelData.js
Original file line number Diff line number Diff line change
@@ -1,110 +1,153 @@
const axios = require("axios");
const querystring = require("querystring");
const calculateCongestion = require("../controllers/getCongestion");
const { getPM2_5, getPMColor } = require("../controllers/getPM2_5");
const API_URL = "https://intermodal.router.hereapi.com/v8/routes";
const {
getPMColor,
calculatePmValuesList,
} = require("../controllers/getPM2_5");
const API_URL = "https://router.hereapi.com/v8/routes";

function getTravelData(req, res) {
let queryStr = req.params.query;
let queryObj = querystring.parse(queryStr);
let origin = queryObj.origin;
let dest = queryObj.dest;
let departureTime = queryObj.departureTime
? new Date(queryObj.departureTime)
: new Date();

let p = axios.get(API_URL, {
const queryStr = req && req.params ? req.params.query : null;
const queryObj = queryStr ? querystring.parse(queryStr) : null;
const origin = queryObj && queryObj.origin ? queryObj.origin : null;
const dest = queryObj && queryObj.dest ? queryObj.dest : null;
const departureTime =
queryObj && queryObj.departureTime
? queryObj.departureTime
: new Date().toISOString();
const transportMode =
queryObj && queryObj.transportMode ? queryObj.transportMode : "car";
// validate data
if (!origin || !dest) {
const validate = [!origin, !dest];
res.status(400).json({
msg: ["Select a valid origin", "Select a valid destination"].filter(
(val, index) => validate[index]
),
});
}
let intermodalApiCall = axios.get(API_URL, {
params: {
apiKey: process.env.here_api_key,
alternatives: 10,
alternatives: 6,
destination: dest,
origin: origin,
return: "polyline,travelSummary",
"transit[modes]": "-subway,-lightRail,-highSpeedTrain,-cityTrain", // remove undesirable transports
departureTime: departureTime,
transportMode,
departureTime,
spans: "names,length",
},
});
p.then(async (response) => {
let result = [];
let minPm = 500,
maxPm = 0;
for (var i = 0; i < response.data.routes.length; i++) {
intermodalApiCall
.then(async (response) => {
const routes =
response.data && response.data.routes ? [...response.data.routes] : [];
let result = [];
let minPm = 1000;
let maxPm = 0;
for (var i = 0; i < routes.length; i++) {
try {
const updatedRoute = await fetchCongestionAndPM(
routes[i],
maxPm,
minPm,
departureTime
);
result = [...result, updatedRoute.route];
(maxPm = updatedRoute.maxPm), (minPm = updatedRoute.minPm);
} catch (err) {
console.log(err);
}
}
try {
const formattedRoute = await formatData(
response.data.routes[i],
const pmResult = getPMColor(result, minPm, maxPm);
const summary = {
routesCount: pmResult.length,
minPm,
maxPm,
minPm
);
result = [...result, formattedRoute.routeData];
(maxPm = formattedRoute.maxPm), (minPm = formattedRoute.minPm);
};
res.json({ routes: pmResult, summary }).status(200);
} catch (err) {
console.log(err);
res.json({ msg: "Error in processing data" }).status(400);
}
}
try {
const pmResult = getPMColor(result, minPm, maxPm);
const finalResult = await calculateCongestion(pmResult, departureTime);
res.json(finalResult).status(200);
} catch (err) {
console.log(err);
res.json({ msg: "Error in processing data" }).status(400);
}
}).catch((error) => {
if (error.response) {
if (error.response.status == 400) {
res.json({ msg: error.response.title }).status(400);
} else if (error.response.status == 401) {
})
.catch((error) => {
if (error.response) {
if (error.response.status == 400) {
res.json({ msg: error.response.title }).status(400);
} else if (error.response.status == 401) {
res
.json({ msg: "error while authorisation to the HERE map server" })
.status(401);
} else {
res
.json({
msg: "Unknown error occured while fetching the data from server",
})
.status(error.response.status);
}
} else if (error.request) {
res
.json({ msg: "error while authorisation to the HERE map server" })
.status(401);
.json({ msg: "The request was made but no response was received" })
.status(500);
} else {
res
.json({
msg: "Unknown error occured while fetching the data from server",
})
.status(error.response.status);
res.json({ msg: "Internal server error" }).status(500);
}
} else if (error.request) {
res
.json({ msg: "The request was made but no response was received" })
.status(500);
} else {
res.json({ msg: "Internal server error" }).status(500);
}
});
});
}
async function formatData(route, maxPm, minPm) {
let routeData = [];
for (let i = 0; i < route.sections.length; i++) {
try {
const pmValue = await getPM2_5(
(route.sections[i].departure.place.location.lat +
route.sections[i].arrival.place.location.lat) /
2,
(route.sections[i].departure.place.location.lng +
route.sections[i].arrival.place.location.lng) /
2
); // get PM of midpoint
maxPm = Math.max(pmValue, maxPm);
minPm = Math.min(pmValue, minPm);
// console.log(pmvalue);
let travelTime = route.sections[i].travelSummary.duration;
const sec = {
travelTime,
distance: route.sections[i].travelSummary.length,
pmValue,
begin: route.sections[i].departure.place.location,
end: route.sections[i].arrival.place.location,
transport: route.sections[i].transport,
polyline: route.sections[i].polyline,
};
// console.log(sec)
routeData = [...routeData, sec];
} catch (err) {
console.log(err);
}
async function fetchCongestionAndPM(route, maxPm, minPm, departureTime) {
const midPointLocations =
route && route.sections
? route.sections.map((section) => {
return {
lat:
(section.departure.place.location.lat +
section.arrival.place.location.lat) /
2,
lng:
(section.departure.place.location.lng +
section.arrival.place.location.lng) /
2,
};
})
: [];
const congestionParams =
route && route.sections
? route.sections.map((section) => {
return {
duration: section.travelSummary.duration,
baseDuration: section.travelSummary.baseDuration,
};
})
: [];
try {
const pmValues = await calculatePmValuesList(midPointLocations);
const congestionData = await calculateCongestion(congestionParams);
minPm = Math.min(...pmValues);
maxPm = Math.max(...pmValues);
const updatedRoute = {
...route,
sections:
route && route.sections
? route.sections.map((section, i) => {
return {
...section,
travelSummary: {
...section.travelSummary,
pmValue: pmValues[i],
...congestionData[i],
},
};
})
: [],
};
// console.log(updatedRoute);
return { route: updatedRoute, maxPm, minPm };
} catch (err) {
console.log(err);
}
return { routeData, maxPm, minPm };
}

module.exports = getTravelData;