@geoapify/route-planner-sdk
Version:
TypeScript SDK for the Geoapify Route Planner API. Supports route optimization, delivery planning, and timeline visualization in browser and Node.js
160 lines (159 loc) • 7.34 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
export const MISSING_LEG_DATA = -1;
export class LegRecalculator {
static replaceLegsForInsertedWaypoint(context, agentIndex, waypointIndex) {
const agentFeature = context.getAgentFeature(agentIndex);
const properties = agentFeature.properties;
if (!properties.legs) {
properties.legs = [];
}
const legs = properties.legs;
const waypoints = properties.waypoints;
const leg1 = {
from_waypoint_index: waypointIndex - 1,
to_waypoint_index: waypointIndex,
time: MISSING_LEG_DATA,
distance: MISSING_LEG_DATA,
steps: []
};
const leg2 = {
from_waypoint_index: waypointIndex,
to_waypoint_index: waypointIndex + 1,
time: MISSING_LEG_DATA,
distance: MISSING_LEG_DATA,
steps: []
};
if (waypoints.length <= 1) {
// do nothing, no legs
return;
}
if (waypointIndex === 0) {
legs.splice(waypointIndex, 0, leg2);
}
else if (waypointIndex === waypoints.length - 1) {
legs.splice(waypointIndex, 0, leg1);
}
else {
// Middle insertion, first remove the existing leg and add 2
legs.splice(waypointIndex - 1, 1, leg1, leg2);
}
// reindex waypoints
legs.forEach((leg, index) => {
leg.from_waypoint_index = index;
leg.to_waypoint_index = index + 1;
});
}
static fillMissingLegData(context, agentFeature) {
return __awaiter(this, void 0, void 0, function* () {
const waypoints = agentFeature.properties.waypoints || [];
const legs = agentFeature.properties.legs || [];
const missingLegIndices = this.findMissingLegIndices(legs);
if (missingLegIndices.length > 0) {
yield this.fillMissingOrderedLegs(context, waypoints, legs, missingLegIndices);
}
this.recreateGeometry(agentFeature, waypoints, legs);
});
}
static fillMissingOrderedLegs(context, waypoints, legs, missingLegIndices) {
var _a, _b, _c, _d, _e, _f;
return __awaiter(this, void 0, void 0, function* () {
const routingHelper = context.getRoutingHelper();
const routeResults = yield Promise.all(missingLegIndices.map((legIndex) => __awaiter(this, void 0, void 0, function* () {
const fromWaypoint = waypoints[legIndex];
const toWaypoint = waypoints[legIndex + 1];
const fromLocation = this.getWaypointLocation(fromWaypoint);
const toLocation = this.getWaypointLocation(toWaypoint);
if (!fromLocation || !toLocation) {
return { legIndex, routeData: null };
}
try {
const routeData = yield routingHelper.calculateRouteData([fromLocation, toLocation]);
return { legIndex, routeData };
}
catch (_error) {
return { legIndex, routeData: null };
}
})));
for (const result of routeResults) {
const leg = legs[result.legIndex];
if (!leg) {
continue;
}
const routeLeg = (_b = (_a = result.routeData) === null || _a === void 0 ? void 0 : _a.legs) === null || _b === void 0 ? void 0 : _b[0];
if (routeLeg) {
leg.time = (_c = routeLeg.time) !== null && _c !== void 0 ? _c : 0;
leg.distance = (_d = routeLeg.distance) !== null && _d !== void 0 ? _d : 0;
leg.steps = [{
distance: leg.distance,
time: routeLeg.time,
from_index: 0,
to_index: 1
}];
}
else {
leg.time = 0;
leg.distance = 0;
leg.steps = [];
}
const fromLocation = this.getMappedRouteWaypointLocation((_e = result.routeData) === null || _e === void 0 ? void 0 : _e.waypoints, 0);
const toLocation = this.getMappedRouteWaypointLocation((_f = result.routeData) === null || _f === void 0 ? void 0 : _f.waypoints, 1);
if (fromLocation) {
waypoints[result.legIndex].location = fromLocation;
}
if (toLocation) {
waypoints[result.legIndex + 1].location = toLocation;
}
}
});
}
static recreateGeometry(agentFeature, waypoints, legs) {
const coordinates = [];
for (let i = 0; i < legs.length; i++) {
const fromLocation = this.getWaypointLocation(waypoints[i]);
const toLocation = this.getWaypointLocation(waypoints[i + 1]);
if (!fromLocation || !toLocation) {
continue;
}
legs[i].from_waypoint_index = i;
legs[i].to_waypoint_index = i + 1;
coordinates.push([fromLocation, toLocation]);
}
agentFeature.geometry = Object.assign(Object.assign({}, agentFeature.geometry), { type: "MultiLineString", coordinates });
}
static getMappedRouteWaypointLocation(routeWaypoints, originalIndex) {
var _a;
if (!routeWaypoints || routeWaypoints.length === 0) {
return undefined;
}
const mappedWaypoint = routeWaypoints.find((waypoint) => (waypoint === null || waypoint === void 0 ? void 0 : waypoint.original_index) === originalIndex);
return (mappedWaypoint === null || mappedWaypoint === void 0 ? void 0 : mappedWaypoint.location) || ((_a = routeWaypoints[originalIndex]) === null || _a === void 0 ? void 0 : _a.location);
}
static getWaypointLocation(waypoint) {
if (!waypoint) {
return undefined;
}
return waypoint.location || waypoint.original_location;
}
static findMissingLegIndices(legs) {
const missingLegs = [];
for (let i = 0; i < legs.length; i++) {
const leg = legs[i];
if (!leg) {
continue;
}
if (leg.time === undefined || leg.time === MISSING_LEG_DATA || leg.time < 0 ||
leg.distance === undefined || leg.distance === MISSING_LEG_DATA || leg.distance < 0) {
missingLegs.push(i);
}
}
return missingLegs;
}
}