@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
296 lines (295 loc) • 14.7 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());
});
};
import { Utils } from "../utils";
import { RoutePlanner } from "../../route-planner";
import { OptimizeAgentInput } from "./optimize-agent-input";
export class RouteResultEditorBase {
constructor(result) {
this.result = result;
}
optimizeRoute(optimizeAgentInput) {
return __awaiter(this, void 0, void 0, function* () {
let newRawData = Utils.cloneObject(this.result.getRawData().properties.params);
let originalIndexes = {
originalAgentIndex: optimizeAgentInput.agentIndex,
originalJobsIndexes: {},
originalShipmentsIndexes: {},
};
this.generateOptimizedRoute(newRawData, optimizeAgentInput, originalIndexes);
const planner = new RoutePlanner(this.result.getOptions(), newRawData);
let result = yield planner.plan();
let newFeatureResponse = result.getRawData().features[0];
if (newFeatureResponse) {
this.fixAgentIndex(optimizeAgentInput.agentIndex, newFeatureResponse);
this.fixShipmentJobIndexes(newFeatureResponse, originalIndexes);
this.fixWaypointIndexes(newFeatureResponse, originalIndexes);
this.fixUnassignedItems(result.getRawData(), originalIndexes);
}
return result;
});
}
generateOptimizedRoute(newRawData, optimizeAgentInput, originalIndexes) {
var _a, _b, _c;
newRawData.agents = (_a = newRawData.agents) === null || _a === void 0 ? void 0 : _a.filter((nextAgent, index) => index == optimizeAgentInput.agentIndex);
let newJobIndex = 0;
let newJobs = [];
(_b = newRawData.jobs) === null || _b === void 0 ? void 0 : _b.forEach(((nextJob, index) => {
if (optimizeAgentInput.agentJobIndexes.has(index)) {
newJobs[newJobIndex] = nextJob;
originalIndexes.originalJobsIndexes[newJobIndex] = index;
newJobIndex++;
}
}));
newRawData.jobs = newJobs;
let newShipmentIndex = 0;
let newShipments = [];
(_c = newRawData.shipments) === null || _c === void 0 ? void 0 : _c.forEach(((nextShipment, index) => {
if (optimizeAgentInput.agentShipmentIndexes.has(index)) {
newShipments[newShipmentIndex] = nextShipment;
originalIndexes.originalShipmentsIndexes[newShipmentIndex] = index;
newShipmentIndex++;
}
}));
newRawData.shipments = newShipments;
}
removeAgent(agentIndex) {
this.removeAgentWithIndex(agentIndex);
this.addUnassignedAgentIfNeeded(agentIndex);
// TODO: maybe we need to add shipments/locations in unassigned arrays
}
removeAgentWithIndex(agentIndex) {
this.result.getRawData().features = this.result.getRawData().features.filter(agent => agent.properties.agent_index != agentIndex);
}
updateAgent(newResult, originalAgentIndex) {
if (newResult.getUnassignedAgents().length > 0) {
if (!this.result.getRawData().properties.issues.unassigned_agents.includes(originalAgentIndex)) {
this.removeAgentWithIndex(originalAgentIndex);
}
else {
this.updateResultWithUpdatedAgent(newResult, originalAgentIndex);
}
this.updateUnassignedItems(newResult);
}
else {
let existingAgentSolution = this.result.getAgentSolutionByIndex(originalAgentIndex);
if (existingAgentSolution) {
this.removeAgentWithIndex(originalAgentIndex);
}
this.updateResultWithUpdatedAgent(newResult, originalAgentIndex);
this.updateUnassignedItems(newResult);
}
}
updateResultWithUpdatedAgent(newResult, originalAgentIndex) {
let newFeatureResponse = newResult.getRawData().features[0];
this.result.getRawData().features.push(newFeatureResponse);
}
generateOptimizeAgentInput(agentIndex, existingAgent) {
if (!existingAgent) {
return new OptimizeAgentInput(agentIndex, [], []);
}
let agentJobs = existingAgent.getActions()
.filter(action => action.getJobIndex() !== undefined)
.map(action => action.getJobIndex());
let agentShipments = existingAgent.getActions()
.filter(action => action.getShipmentIndex() !== undefined)
.map(action => action.getShipmentIndex());
return new OptimizeAgentInput(existingAgent.getAgentIndex(), agentJobs, agentShipments);
}
checkIfArrayIsUnique(myArray) {
return myArray.length === new Set(myArray).size;
}
getAgentByIndex(agentIndex) {
return this.result.getRawData().properties.params.agents[agentIndex];
}
getJobByIndex(jobIndex) {
return this.result.getRawData().properties.params.jobs[jobIndex];
}
getShipmentByIndex(shipmentIndex) {
return this.result.getRawData().properties.params.shipments[shipmentIndex];
}
validateAgent(agentIndex) {
let agentFound = this.getAgentByIndex(agentIndex);
if (!agentFound) {
throw new Error(`Agent with index ${agentIndex} not found`);
}
}
updateUnassignedItems(newResult) {
this.updateUnassignedAgents(newResult);
this.updateUnassignedJobs(newResult);
this.updateUnassignedShipments(newResult);
}
updateUnassignedAgents(newResult) {
if (newResult.getUnassignedAgents().length > 0) {
this.addUnassignedAgentIfNeeded(newResult.getRawData().properties.issues.unassigned_agents[0]);
}
else {
this.addIssuesPropertiesIfMissing();
if (!this.result.getRawData().properties.issues.unassigned_agents) {
this.result.getRawData().properties.issues.unassigned_agents = [];
}
this.result.getRawData().properties.issues.unassigned_agents =
this.result.getRawData().properties.issues.unassigned_agents.filter(unassignedAgentIndex => unassignedAgentIndex != newResult.getData().agents[0].agentIndex);
}
}
updateUnassignedJobs(newResult) {
let unassignedJobs = this.getUnassignedJobs(newResult);
unassignedJobs.forEach(jobIndex => {
var _a, _b;
if (!((_b = (_a = this.result.getRawData().properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_jobs) === null || _b === void 0 ? void 0 : _b.includes(jobIndex))) {
this.addIssuesPropertiesIfMissing();
this.generateEmptyUnassignedJobsIfNeeded();
this.result.getRawData().properties.issues.unassigned_jobs.push(jobIndex);
}
});
if (newResult.getRawData().features.length > 0) {
let assignedJobs = newResult.getRawData().features[0].properties.actions.filter(action => action.job_index != undefined).map(action => action.job_index);
assignedJobs.forEach(jobIndex => {
var _a, _b;
if ((_b = (_a = this.result.getRawData().properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_jobs) === null || _b === void 0 ? void 0 : _b.includes(jobIndex)) {
this.addIssuesPropertiesIfMissing();
this.generateEmptyUnassignedJobsIfNeeded();
this.result.getRawData().properties.issues.unassigned_jobs =
this.result.getRawData().properties.issues.unassigned_jobs.filter(unassignedJobIndex => unassignedJobIndex != jobIndex);
}
});
}
}
updateUnassignedShipments(newResult) {
let unassignedShipments = this.getUnassignedShipments(newResult);
unassignedShipments.forEach(shipmentIndex => {
var _a, _b;
if (!((_b = (_a = this.result.getRawData().properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_shipments) === null || _b === void 0 ? void 0 : _b.includes(shipmentIndex))) {
this.addIssuesPropertiesIfMissing();
this.generateEmptyUnassignedShipmentsIfNeeded();
this.result.getRawData().properties.issues.unassigned_shipments.push(shipmentIndex);
}
});
if (newResult.getRawData().features.length > 0) {
let assignedShipments = newResult.getRawData().features[0].properties.actions.filter(action => action.shipment_index != undefined).map(action => action.shipment_index);
assignedShipments.forEach(shipmentIndex => {
var _a, _b;
if ((_b = (_a = this.result.getRawData().properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_shipments) === null || _b === void 0 ? void 0 : _b.includes(shipmentIndex)) {
this.addIssuesPropertiesIfMissing();
this.generateEmptyUnassignedShipmentsIfNeeded();
this.result.getRawData().properties.issues.unassigned_shipments =
this.result.getRawData().properties.issues.unassigned_shipments.filter(unassignedShipmentIndex => unassignedShipmentIndex != shipmentIndex);
}
});
}
}
getUnassignedJobs(newResult) {
if (!newResult.getRawData().properties.issues || !newResult.getRawData().properties.issues.unassigned_jobs) {
return [];
}
return newResult.getRawData().properties.issues.unassigned_jobs;
}
getUnassignedShipments(newResult) {
if (!newResult.getRawData().properties.issues || !newResult.getRawData().properties.issues.unassigned_shipments) {
return [];
}
return newResult.getRawData().properties.issues.unassigned_shipments;
}
addUnassignedAgentIfNeeded(agentIndex) {
if (!this.result.getRawData().properties.issues.unassigned_agents.includes(agentIndex)) {
if (!this.result.getRawData().properties.issues.unassigned_agents) {
this.result.getRawData().properties.issues.unassigned_agents = [];
}
this.result.getRawData().properties.issues.unassigned_agents.push(agentIndex);
}
}
addIssuesPropertiesIfMissing() {
if (!this.result.getRawData().properties.issues) {
this.result.getRawData().properties.issues = {
unassigned_shipments: [],
unassigned_jobs: [],
unassigned_agents: []
};
}
}
fixAgentIndex(originalAgentIndex, agentData) {
if (originalAgentIndex != -1) {
agentData.properties.agent_index = originalAgentIndex;
}
else {
console.log(`Agent with index ${originalAgentIndex} not found in the result`);
}
}
fixShipmentJobIndexes(agentData, originalIndexes) {
agentData.properties.actions.forEach(action => {
if (action.shipment_index != undefined) {
action.shipment_index = originalIndexes.originalShipmentsIndexes[action.shipment_index];
}
if (action.job_index != undefined) {
action.job_index = originalIndexes.originalJobsIndexes[action.job_index];
}
});
}
fixWaypointIndexes(agentData, originalIndexes) {
agentData.properties.waypoints.forEach(waypoint => {
waypoint.actions.forEach(action => {
if (action.shipment_index != undefined) {
action.shipment_index = originalIndexes.originalShipmentsIndexes[action.shipment_index];
}
if (action.job_index != undefined) {
action.job_index = originalIndexes.originalJobsIndexes[action.job_index];
}
});
});
}
generateEmptyUnassignedShipmentsIfNeeded() {
if (!this.result.getRawData().properties.issues) {
this.result.getRawData().properties.issues = {
unassigned_jobs: [],
unassigned_agents: [],
unassigned_shipments: []
};
}
else {
if (!this.result.getRawData().properties.issues.unassigned_shipments) {
this.result.getRawData().properties.issues.unassigned_shipments = [];
}
}
}
generateEmptyUnassignedJobsIfNeeded() {
if (!this.result.getRawData().properties.issues) {
this.result.getRawData().properties.issues = {
unassigned_jobs: [],
unassigned_agents: [],
unassigned_shipments: []
};
}
else {
if (!this.result.getRawData().properties.issues.unassigned_jobs) {
this.result.getRawData().properties.issues.unassigned_jobs = [];
}
}
}
fixUnassignedItems(rawData, originalIndexes) {
var _a, _b, _c;
if ((_a = rawData.properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_agents) {
rawData.properties.issues.unassigned_agents =
rawData.properties.issues.unassigned_agents.map((agentIndex) => {
return originalIndexes.originalAgentIndex;
});
}
if ((_b = rawData.properties.issues) === null || _b === void 0 ? void 0 : _b.unassigned_jobs) {
rawData.properties.issues.unassigned_jobs =
rawData.properties.issues.unassigned_jobs.map((jobIndex) => {
return originalIndexes.originalJobsIndexes[jobIndex];
});
}
if ((_c = rawData.properties.issues) === null || _c === void 0 ? void 0 : _c.unassigned_shipments) {
rawData.properties.issues.unassigned_shipments =
rawData.properties.issues.unassigned_shipments.map((shipmentIndex) => {
return originalIndexes.originalShipmentsIndexes[shipmentIndex];
});
}
}
}