@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
175 lines (174 loc) • 8.66 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 { RouteResultEditorBase } from "./route-result-editor-base";
import { RoutePlanner } from "../../route-planner";
import { Utils } from "../utils";
export class RouteResultJobEditor extends RouteResultEditorBase {
assignJobs(agentIndex, jobIndexes, newPriority) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
this.validateAgent(agentIndex);
this.validateJobs(jobIndexes, agentIndex);
// Set job priorities in the original data (permanent change)
for (const jobIndex of jobIndexes) {
this.setJobPriority(jobIndex, newPriority);
}
// Clone the input data for planning
const inputDataCopy = Utils.cloneObject(this.result.getRawData().properties.params);
// Apply temporary requirements and capabilities for planning
if ((_a = this.result.getRawData().properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_jobs) {
this.markJobsUnassigned(inputDataCopy.jobs, this.result.getRawData().properties.issues.unassigned_jobs);
}
this.markJobsForAgent(inputDataCopy.jobs, jobIndexes, agentIndex);
this.markRemainingJobsWithAgentRequirement(inputDataCopy.jobs, jobIndexes);
this.addAgentCapabilities(inputDataCopy.agents);
const planner = new RoutePlanner(this.result.getOptions(), inputDataCopy);
const newResult = yield planner.plan();
this.updateResult(newResult);
return true;
});
}
removeJobs(jobIndexes) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
this.validateJobs(jobIndexes);
const inputDataCopy = Utils.cloneObject(this.result.getRawData().properties.params);
this.markJobsUnassigned(inputDataCopy.jobs, jobIndexes);
if ((_a = this.result.getRawData().properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_jobs) {
this.markJobsUnassigned(inputDataCopy.jobs, this.result.getRawData().properties.issues.unassigned_jobs);
}
this.markRemainingJobsWithAgentRequirement(inputDataCopy.jobs, jobIndexes);
this.addAgentCapabilities(inputDataCopy.agents);
const planner = new RoutePlanner(this.result.getOptions(), inputDataCopy);
const newResult = yield planner.plan();
this.updateResult(newResult);
return true;
});
}
addNewJobs(agentIndex, jobs) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
let jobsRaw = jobs.map(job => job.getRaw());
this.validateAgent(agentIndex);
this.validateNewJobs(jobsRaw);
// Add new jobs to the original data (permanent change)
const initialJobsCount = this.result.getRawData().properties.params.jobs.length;
this.result.getRawData().properties.params.jobs.push(...jobsRaw);
// Get the indexes of the newly added jobs
const newJobIndexes = jobsRaw.map((_, index) => initialJobsCount + index);
// Clone the input data for planning
const inputDataCopy = Utils.cloneObject(this.result.getRawData().properties.params);
// Apply temporary requirements and capabilities for planning
if ((_a = this.result.getRawData().properties.issues) === null || _a === void 0 ? void 0 : _a.unassigned_jobs) {
this.markJobsUnassigned(inputDataCopy.jobs, this.result.getRawData().properties.issues.unassigned_jobs);
}
this.markJobsForAgent(inputDataCopy.jobs, newJobIndexes, agentIndex);
this.markRemainingJobsWithAgentRequirement(inputDataCopy.jobs, newJobIndexes);
this.addAgentCapabilities(inputDataCopy.agents);
const planner = new RoutePlanner(this.result.getOptions(), inputDataCopy);
const newResult = yield planner.plan();
this.updateResult(newResult);
return true;
});
}
markJobsUnassigned(jobs, jobIndexes) {
jobIndexes.forEach(jobIndex => {
if (jobs[jobIndex]) {
if (!jobs[jobIndex].requirements) {
jobs[jobIndex].requirements = [];
}
if (!jobs[jobIndex].requirements.includes(this.unassignedReq)) {
jobs[jobIndex].requirements.push(this.unassignedReq);
}
}
});
}
markRemainingJobsWithAgentRequirement(jobs, jobIndexes) {
for (let i = 0; i < jobs.length; i++) {
if (!jobIndexes.includes(i)) {
// This is a remaining job, find which agent it belongs to
const jobInfo = this.result.getJobInfoByIndex(i);
if (jobInfo) {
const agentIndex = jobInfo.getAgent().getAgentIndex();
const assignAgentReq = `${this.assignAgentReqStart}${agentIndex}`;
if (!jobs[i].requirements) {
jobs[i].requirements = [];
}
if (jobs[i].requirements.includes('unassigned')) {
jobs[i].requirements.splice(jobs[i].requirements.indexOf('unassigned'), 1);
}
if (!jobs[i].requirements.includes(assignAgentReq)) {
jobs[i].requirements.push(assignAgentReq);
}
}
}
}
}
markJobsForAgent(jobs, jobIndexes, agentIndex) {
jobIndexes.forEach(jobIndex => {
if (jobs[jobIndex]) {
const assignAgentReq = `assign-agent-${agentIndex}`;
if (!jobs[jobIndex].requirements) {
jobs[jobIndex].requirements = [];
}
if (jobs[jobIndex].requirements.includes('unassigned')) {
jobs[jobIndex].requirements.splice(jobs[jobIndex].requirements.indexOf('unassigned'), 1);
}
if (!jobs[jobIndex].requirements.includes(assignAgentReq)) {
jobs[jobIndex].requirements.push(assignAgentReq);
}
}
});
}
validateJobs(jobIndexes, agentIndex) {
if (jobIndexes.length == 0) {
throw new Error("No jobs provided");
}
if (!this.checkIfArrayIsUnique(jobIndexes)) {
throw new Error("Jobs are not unique");
}
jobIndexes.forEach((jobIndex) => {
let jobInfo = this.result.getJobInfoByIndex(jobIndex);
if (jobInfo == undefined) {
this.validateJobExists(jobIndex);
}
if (agentIndex != undefined) {
if ((jobInfo === null || jobInfo === void 0 ? void 0 : jobInfo.getAgent().getAgentIndex()) == agentIndex) {
throw new Error(`Job with index ${jobIndex} already assigned to agent with index ${agentIndex}`);
}
}
});
}
validateJobExists(jobIndex) {
let jobFound = this.getJobByIndex(jobIndex);
if (!jobFound) {
throw new Error(`Job with index ${jobIndex} not found`);
}
else {
let isUnassignedJob = this.result.getRawData().properties.issues.unassigned_jobs.includes(jobIndex);
if (!isUnassignedJob) {
throw new Error(`Job with index ${jobIndex} is invalid`);
}
}
}
validateNewJobs(jobs) {
if (jobs.length == 0) {
throw new Error("No jobs provided");
}
if (!this.checkIfArrayIsUnique(jobs)) {
throw new Error("Jobs are not unique");
}
}
setJobPriority(jobIndex, newPriority) {
if (newPriority != undefined) {
this.result.getRawData().properties.params.jobs[jobIndex].priority = newPriority;
}
}
}