Skip to main content

Routes

|

The Route class provides functionalities for managing and optimizing routes within a Vehicle Routing Problem (VRP) solution. A route represents the trip that a vehicle takes to visit a set of orders, and it is part of an optimization solution. The API allows users to:

  • Retrieve existing routes by ID or list all routes.
  • Update route parameters such as vehicle, constraints, or orders.
  • Delete routes when no longer needed.
  • Reoptimize existing routes to find better solutions.
  • Add or remove orders from an existing route.
  • Merge multiple routes into a single route.
  • Export route data in various formats.

Route Structure

Each route object consists of the following attributes:

NameTypeDescriptionSetterGetter
IdLargeIntegerUnique identifier for the route, used for updates.
OptimizationIdLargeIntegerIdentifier of the optimization to which the route belongs.
ConfigurationParametersConfigurationParametersParameters used to configure the route.
OrdersRouteOrderListList of orders in the route, ordered by the visit order.
VehicleVehicleThe vehicle assigned to the route.
VehicleConstraintsIVehicleConstraintsConstraints that apply to the vehicle for the route.
DepartureDepartureDeparture details of the route.
DestinationDestinationDestination details of the route.
MatrixBuildTypeEMatrixBuildType

Defines the method used to construct the distance and time matrices.
Possible values:
MBT_Set (0): Matrices are set by the user.
MBT_Real (1): Real road distance or time traveled by the vehicle.

DistanceMatricesstd::map<EVehicleType, FloatListList>Distance matrices for the route (used when matrixBuildType is MBT_Set).
TimeMatricesstd::map<EVehicleType, IntListList>Time matrices for the route (used when matrixBuildType is MBT_Set).
RideStatusERideStatus

The current status of the ride.
Possible values:
RS_Finished (0): Ride is completed.
RS_New (1): Ride is ready to start.
RS_Started (2): Ride is in progress.
RS_CanceledByDriver (3): Canceled by driver.
RS_CanceledByFleet (4): Canceled by fleet.

TotalDistancefloatTotal distance traveled by the vehicle (in the set distance unit).
TotalTimeintTotal duration of the route in seconds.
TotalServiceTimeintTotal service time of all the orders in the route (in seconds).
TotalWaitTimeintTotal wait time during the route (in seconds).
NeededFuelfloatTotal fuel used during the route.
CostfloatTotal cost of the route.
Calculated based on fuel consumption and distance for driving, or 0 for walking.
ShapeCoordinatesListShape of the route as a list of coordinates.
CreationTimeTimeTime when the route was created.

Managing Routes

Retrieving a Route

There are two ways to retrieve Routes:

a) Get a Route by ID

Get a certain route.

How it works

  1. Create a ProgressListener, a vrp::Service and a vrp::Route.
  2. Call the getRoute() method from the vrp::Service using the vrp::Route from 1.), the ID of the route that you want to retrieve and the ProgressListener.
  3. Once the operation completes, the vrp::Route from 1.) will be populated.
ProgressListener listener;
gem::vrp::Service service;

gem::vrp::Route route;
gem::LargeInteger routeId = 0; // Set your route id

// Retrieve a specific route by id
int res = service.getRoute(&listener, route, routeId);

if (res == gem::KNoError)
{
// Wait for completion
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 10000);

// Check operation success
if (listener.IsFinished() && listener.GetError() == gem::KNoError)
std::cout << "Route returned successfully" << std::endl;
else
std::cout << "Failed to retrive route: Operation timed out or server returned an error." << std::endl;
}
else
std::cout << "Failed to send getRoute request." << std::endl;

b) Get All Routes

Returns all routes of the API user (which contain the search term).

How it works

  1. Create a ProgressListener, a vrp::Service and a vrp::RouteList.
  2. Call the getRoutes() method from the vrp::Service using the list from 1.) and the ProgressListener.
  3. Once the operation completes, the list from 1.) will be populated.
ProgressListener listener;
gem::vrp::Service service;

gem::vrp::RouteList routes;
gem::String searchTerm = "Route";
// Retrieve all routes
int res = service.getRoutes(listener, routes);
if (res == gem::KNoError)
{
// Wait for completion
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 5000);

// Check operation success
if (listener.IsFinished() && listener.GetError() == gem::KNoError)
std::cout << "Routes retrieved successfully." << std::endl;
else
std::cout << "Failed to retrive routes: Operation timed out or server returned an error." << std::endl;
}
else
std::cout << "Failed to send getRoutes request." << std::endl;

Updating a Route

Routes can be updated with new parameters, such as vehicle or constraints. Make changes on Route and return the new solution after reptimizing the changed route.

Note

Orders within a route cannot be updated directly using UpdateRoute(). However, all other fields in the route can be modified using this method.

To modify orders, refer to the following examples:

How it works

  1. Create a ProgressListener and a vrp::Service.
  2. Retrieve the route you want to update (see Get Route) in a vrp::Route.
  3. Change the desired fields of the vrp::Route.
  4. Call the updateRoute() method from the vrp::Service using the vrp::Route from 2.), the route will be reoptimized.
  5. Check if the associated request has reached the finished status. Once completed, you can retrieve the updated route by calling the getRoute() method, which returns a vrp::Route containing the updated route.

Example

ProgressListener listener;
gem::vrp::Service service;

gem::vrp::Route route;
gem::LargeInteger routeId = 0; // Set your route id
int res = service.getRoute(&listener, route, routeId);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 20000);

gem::vrp::ConfigurationParameters configParams = route.getConfigurationParameters();
configParams.setName(configParams.getName() + " updated");
configParams.setRouteType(gem::vrp::ERouteType::RT_RoundRoute);

gem::vrp::Vehicle vehicle;
int vehicleId = 0; // Set your vehicle id
res = service.getVehicle(&listener, vehicle, vehicleId);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 5000);

gem::vrp::VehicleConstraints vehConstr = route.getVehicleConstraints();
vehConstr.setMaxNumberOfPackages(80);
vehConstr.setMaxDistance(700);

route.setConfigurationParameters(configParams);
route.setVehicleConstraints(vehConstr);

// Update route properties
std::shared_ptr<gem::vrp::Request> request = std::make_shared<gem::vrp::Request>();
res = service.updateRoute(&listener, route, request);
// Wait for completion
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 20000);

WAIT_UNTIL([&]() {
service.getRequest(&listener, request, request->id);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 7000);
return request->status == gem::vrp::ERequestStatus::eFinished;
}, 40000);

// Check operation success
if (listener.IsFinished() && listener.GetError() == gem::KNoError && res == gem::KNoError)
std::cout << "Route updated successfully" << std::endl;
else
std::cout << "Route couldn't be updated or reoptimized" << std::endl;

Deleting a Route

Delete the routes from the list. Routes can be deleted individually or in bulk.

Note

The orders of a deleted route will also be deleted from the optimization to which the route belongs. If the route is the only route of an optimization, then it cannot be deleted, instead delete the optimization (see Delete Optimization).

How it works

  1. Create a ProgressListener and vrp::Service.
  2. Call the deleteRoute() method from the vrp::Service using the routes' IDs and ProgressListener and wait for the operation to be done.

Example

ProgressListener listener;
gem::vrp::Service service;

// Remove multiple routes by IDs
LargeIntList routesToDelete = {101, 202, 303};
int res = service.deleteRoute(listener, routesToDelete);
if (res == gem::KNoError)
{
// Wait for completion
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 5000);

// Check operation success
if (listener.IsFinished() && listener.GetError() == gem::KNoError)
std::cout << "Routes deleted successfully." << std::endl;
else
std::cout << "Failed to delete route: Operation timed out or server returned an error." << std::endl;
}
else
std::cout << "Failed to send deleteRoute request." << std::endl;

Reoptimizing a Route

Reoptimization allows you to find a better solution for an existing route.

Note

Rearranges the orders in a better order of visit, if exists. The latest fuel prices are used to calculate the route's cost (see Get Fuel PricesGet Fuel Prices example).

How it works

  1. Create a ProgressListener, a vrp::Service and a vrp::Route.
  2. Call the route.reoptimize() using the vrp::Route from 1.) and the ProgressListener.
  3. Check if the associated request has reached the finished status. Once completed, you can retrieve the updated route by calling the getRoute() method, which returns a vrp::Route containing the reoptimized route.

Example

ProgressListener listener;
gem::vrp::Service serv;

gem::vrp::Route route;
gem::LargeInteger routeId = 0; // Set your route id

// Retrive a specific optimization by id
int res = serv.getRoute(&listener, route, routeId);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 10000);

// Reoptimize an existing optimization
std::shared_ptr<gem::vrp::Request> request = std::make_shared<gem::vrp::Request>();
res = route.reoptimize(&listener, request);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 20000);

WAIT_UNTIL([&]() {
serv.getRequest(&listener, request, request->id);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 7000);
return request->status == gem::vrp::ERequestStatus::eFinished;
}, 40000);

// Check operation success
if (listener.IsFinished() && listener.GetError() == gem::KNoError && res == gem::KNoError)
std::cout << "Route reoptimized successfully" << std::endl;
else
std::cout << "Route couldn't be reoptimized" << std::endl;

Adding Orders to a Route

Add a list of orders into an existing route's orders list. The orders will also be added in the optimization's orders list.

Note

There are three options to add orders to a route:

  • at the end of the route's orders list.
  • at the optimal positions, which are determined by the algorithm.The orders are inserted at the best positions between the route's orders, without rearranging the route's orders.
  • at specified positions between the route's orders.

The route can be reoptimized, which means that after the addition, the route orders will be rearranged in the best order of visit, so it doesn’t matter which option was chosen to add the orders. The orders will be also added in the list of orders of the route's optimization.

How it works

  1. Create a vrp::RouteOrder for each order that will be added. Set the specified position at which it will be added using the method setIndexInRoute() and set other desired fields.
  2. Insert all the vrp::RouteOrder created at 1.) in a vrp::RouteOrderList.
  3. Create a ProgressListener, vrp::Service and a vrp::Request that will be used for traking the request status.
  4. Retrieve the route like in the example GetRoute() in a vrp::Route. 5 Call the route.addOrders() method from vrp::Route, using the list from 2.), a boolean to specify if the route should be reoptimized, a boolean to specify if the orders should be added at the optimal position (in this examples it has to be false) and the ProgressListener.
  5. Check if the associated request has reached the finished status. Once completed, you can retrieve the updated route by calling the getRoute() method, which returns a vrp::Route containing the reoptimized route.

Example

Add orders at specified postions. You can also see more examples here: Examples

ProgressListener listener;
gem::vrp::Service serv;

// Get customer
gem::vrp::Customer customer;
gem::LargeInteger customerId = ; // Set your customer id
int res = serv.getCustomer(&listener, customer, customerId);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 5000);

// Initialize orders
gem::vrp::RouteOrderList ordersToAdd;
gem::vrp::RouteOrder orderToAdd1(customer); // The order will have the name, coordinates, address and phone number of the customer
orderToAdd1.setCoordinates(gem::Coordinates(47.904776, 1.216904));
orderToAdd1.setIndexInRoute(2); // Added at position 2
orderToAdd1.setNumberOfPackages(4);
orderToAdd1.setServiceTime(420);
orderToAdd1.setTimeWindow(std::make_pair(gem::Time(2021, 5, 18, 10, 15), gem::Time(2021, 5, 18, 13)));
orderToAdd1.setType(gem::vrp::EOrderType::OT_PickUp);
res = serv.addOrder(&listener, orderToAdd1, false);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 5000);
ordersToAdd.push_back(orderToAdd1);

gem::vrp::RouteOrder orderToAdd2(customer);
orderToAdd2.setCoordinates(gem::Coordinates(46.869536, 3.251640));
orderToAdd2.setIndexInRoute(5); // Added at position 5
orderToAdd2.setNumberOfPackages(5);
orderToAdd2.setTimeWindow(std::make_pair(gem::Time(2021, 5, 18, 9, 30), gem::Time(2021, 5, 18, 15, 30)));
orderToAdd2.setServiceTime(240);
orderToAdd2.setType(gem::vrp::EOrderType::OT_Delivery);
res = serv.addOrder(&listener, orderToAdd2, false);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 5000);
ordersToAdd.push_back(orderToAdd2);

gem::vrp::Route route;
gem::LargeInteger routeId = -1; // Set your route id
res = serv.getRoute(&listener, route, routeId);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 10000);

bool reoptimize = false;
bool optimzalPosition = false;
std::shared_ptr<gem::vrp::Request> request = std::make_shared<gem::vrp::Request>();
res = route.addOrders(&listener, ordersToAdd, optimzalPosition, request, reoptimize);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 10000);

WAIT_UNTIL([&]() {
serv.getRequest(&listener, request, request->id);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 7000);
return request->status == gem::vrp::ERequestStatus::eFinished;
}, 40000);

if (listener.IsFinished() && listener.GetError() == gem::KNoError && res == gem::KNoError)
std::cout << "Orders added successfully" << std::endl;
else
std::cout << "Orders couldn't be added" << std::endl;

Deleting an Order from a Route

Delete an order from an existing route. The order will also be deleted from the optimization.

Note

A route must contain at least two orders for one to be deleted. If the order you want to delete is the only one in the route, it cannot be deleted.

How it works

  1. Create a ProgressListener and a vrp::Service.
  2. Retrieve the route like in the example GetRoute() in a vrp::Route.
  3. Create a vrp::RouteOrder and initialize it with the order that you want to delete.
  4. Call the deleteOrder() method from vrp::Route from 2.) using the vrp::RouteOrder from 3.) and the ProgressListener.
  5. Once the operation completes, the vrp::Route from 2.) will be updated.

Example

ProgressListener listener;
gem::vrp::Service service;
gem::vrp::Route route;
gem::LargeInteger routeId = 0; // Set your route id

// Retrieve a specific route by id
int res = service.getRoute(&listener, route, routeId);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 10000);

if (route.getOrders().size() > 4) // Check if the route has at least four orders to avoid going out of range
{
//Delete the fourth order of the route
gem::vrp::RouteOrder order4 = route.getOrders().at(4);
res = route.deleteOrder(&listener, order4);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 20000);
if (listener.IsFinished() && listener.GetError() == gem::KNoError && res == gem::KNoError)
std::cout << "Order deleted successfully" << std::endl;

else
std::cout << "Orders couldn't be deleted" << std::endl;
}
else
std::cout << "The route hasn't at least four orders" << std::endl;

Unlinks a route from its optimization. The route will no longer be a part of the optimization's solution. The orders used in this route will be deleted from the optimization. A new optimization will be created for the unlinked route. The new optimization will have same configuration parameters, vehicle constraints and the rest of the fields as the unlinked route.

Warning

The route cannot be unlinked if it is the only route in the optimization's solution.

How it works

  1. Create a ProgressListener and a vrp::Service.
  2. Call the unlinkRoute() method from the vrp::Service using the route's id which will be unlinked and the ProgressListener and wait for the operation to be done.

Example

ProgressListener listener;
gem::vrp::Service service;

gem::vrp::Route route;
gem::LargeInteger routeId = 0; // Set your route id

// Retrieve a specific route by id
int res = service.getRoute(&listener, route, routeId);
if (res == gem::KNoError)
{
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 10000);

if(listener.IsFinished() && listener.GetError() == gem::KNoError)
{
// Unlink route from the optimization
res = route.unlink(&listener);
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 20000);
if (res == gem::KNoError)
{
if (listener.IsFinished() && listener.GetError() == gem::KNoError &
std::cout << "Route unlinked successfully" << std::endl;
else
std::cout << "Failed to unlink route: Operation timed out or server returned an error." << std::endl;
}
else
std::cout << "Failed to send unlink request." << std::endl;
}
else
std::cout << "Failed to retrive route: Operation timed out or server returned an error." << std::endl;
}
else
std::cout << "Failed to send getRoute request." << std::endl;

Merging Routes

Merge multiple routes into a new one. A new optimization will be created for the merged route. The optimization will have same configuration parameters, vehicle constraints and the rest of the fields as the first route from the list. The merged route will not be optimized.

Warning

Routes with matrices build type set to EMatrixBuildType::MBT_Set, cannot be merged.

How it works

  1. Create a ProgressListener, a vrp::Service, a LargeIntList with the route ids to be merged and a vrp::Route in which the merged route will be returned.
  2. Call the mergeRoutes() method from the vrp::Service using the vrp::Route and list from 1.) and the ProgressListener.
  3. Once the operation completes, the merged route will be returned in the vrp::Route from 1.)

Example

ProgressListener listener;
gem::vrp::Service service;

gem::LargeIntList routeIds;
routeIds.push_back(0); // Set the id of the first route
routeIds.push_back(0); // Set the id of the second route
routeIds.push_back(0); // Set the id of the third route

// Merge multiple routes into one
gem::vrp::Route route;
int res = service.mergeRoutes(&listener, route, routeIds);
if (res == gem::KNoError)
{
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 20000);

if (listener.IsFinished() && listener.GetError() == gem::KNoError)
std::cout << "Routes merged successfully." << std::endl;
else
std::cout << "Failed to merge route: Operation timed out or server returned an error." << std::endl;
}
else
std::cout << "Failed to send mergeRoutes request." << std::endl;

Error Handling

The API provides specific error codes to identify potential issues. Below is a summary of common errors and their solutions:

| Error Code | Description | Solution | ||-|-| | KInvalidInput | Missing required fields or invalid data. | Ensure all mandatory fields are filled. | | KNotFound | The specified route ID does not exist. | Verify that the correct route ID is used. | | KInternalAbort | Server-side issue or unexpected error. | Retry the request or check API status. | | KNoRoute | Route could not be reoptimized. | Check constraints and parameters. |

Request Handling

Route operations such as reoptimize, addOrders, and mergeRoutes return a Request object. This object allows you to track the status of the operation.

Request Structure

  • Request ID (LargeInteger): Unique identifier for the request.
  • Creation Time (LargeInteger): The time when the request was created.
  • Entity ID (LargeInteger): The ID of the entity (e.g., route) associated with the request.
  • Status (ERequestStatus): The current status of the request (e.g., created, in progress, finished).
  • ErrorMessage (std::string): A message describing any errors that occurred.

Example of Tracking a Request

// Retrieve the status of a request
std::shared_ptr<gem::vrp::Request> request = std::make_shared<gem::vrp::Request>();
int res = service.getRequest(listener, request, requestId);

if (res == gem::KNoError)
{
// Wait for completion
WAIT_UNTIL(std::bind(&ProgressListener::IsFinished, &listener), 5000);

// Check operation success
if (listener.IsFinished() && listener.GetError() == gem::KNoError && res == gem::KNoError)
std::cout << "Request status: " << request->status << std::endl;
else
std::cout << "Failed to retrive request: Operation timed out or server returned an error." << std::endl;
}
else
std::cout << "Failed to send getRequest request." << std::endl;