Building Routes
The RouteCloud API builds routes by POSTing build requests in JSON format to /v1/build. The "build routes" call generates entirely new routes using a collection of empty routes and jobs. RouteCloud attempts to place as many jobs as possible onto the given routes, while also minimizing the cost of the routes and respecting any constraints that have been applied on the routes and jobs. If a job cannot be placed on a route, it is placed in the unrouted_jobs list instead.
Note
To run the examples in this tutorial, you will need:
- A RouteCloud API login. Use your Verizon Connect Enterprise username and password to authenticate with the RouteCloud API. To obtain a username and password, contact Verizon Connect sales.
- cURL to run the requests. You can download a cURL binary from here.
You can download a copy of the quick_start_build.json
example build request from here.
Run the request in the command line using cURL:
curl -u "youraccount%3Amain:password" "https://routecloud.telogis.com/v1/build?wait=1" -H "Content-Type: application/json" --data-binary "@quick_start_build.json" -L
Substitute youraccount%3Amain
for your username (replacing the colon with %3A
), and password
with your password. See the Authentication topic for more information and alternative authentication methods.
The wait=1
parameter instructs RouteCloud to return the results synchronously. This means that results are returned directly to the command window.
See Retrieving API Results for more information about synchronous and asynchronous tasks.
RouteCloud will route the jobs and should return a response within 20 seconds.
Request
{
"id": "quick_start_build",
"routes": [
{
"id": "route0",
"location": "39.718005, -104.969531",
"start_time": "09:00",
"max_working_time": "08:00",
"date": "2016-1-18",
"breaks": [
{ "id": "route0_lunch_break", "start": "12:00", "length": "00:30" }
]
}, {
"id": "route1",
"location": "39.718005, -104.969531",
"start_time": "09:00",
"max_working_time": "08:00",
"route_attributes": ["hazmat"],
"date": "2016-1-19",
"breaks": [
{ "id": "route1_lunch_break", "start": "12:00", "length": "00:30" }
]
}, {
"id": "route2",
"location": "39.718005, -104.969531",
"start_time": "09:00",
"max_working_time": "04:00",
"date": "2016-1-20",
"breaks": [
{ "id": "route2_lunch_break", "start": "12:00", "length": "00:30" }
]
}
],
"jobs": [
{ "id": "job0", "time_on_site": "00:10", "location": "39.635928, -105.049219" },
{ "id": "job1", "time_on_site": "00:10", "location": "39.725375, -104.791080", "date": "2016-1-18" },
{ "id": "job2", "time_on_site": "00:15", "location": "39.708990, -105.026954", "date": "2016-1-19" },
{ "id": "job3", "time_on_site": "00:10", "location": "39.653975, -105.093750", "allowed_dates": [ "2016-1-18", "2016-1-19" ] },
{ "id": "job4", "time_on_site": "00:15", "location": "39.590789, -105.084376", "allowed_dates": [ "2016-1-20" ] },
{ "id": "job5", "time_on_site": "00:10", "location": "39.638635, -105.128906", "required_route_attributes": [ "hazmat" ] },
{ "id": "job6", "time_on_site": "00:10", "location": "39.597111, -105.041015", "disallowed_route_attributes": [ "hazmat" ] },
{ "id": "job7", "time_on_site": "00:10", "location": "39.727919, -105.103126", "required_route_attributes": [ "heavy_truck" ] },
{ "id": "job8", "time_on_site": "00:10", "location": "39.615167, -104.887500", "time_window": { "start" : "13:00", "end" : "15:00" } },
{ "id": "job9", "time_on_site": "00:10", "location": "39.820688, -105.133594" },
{ "id": "job10", "time_on_site": "00:10", "location": "39.749546, -105.069141" },
{ "id": "job11", "time_on_site": "00:10", "location": "39.556465, -104.976563" }
]
}
The quick_start_build.json request. Click here to open in the UI.
The request JSON consists of an array of routes and an array of jobs. The jobs are assigned to routes by the RouteCloud optimizer, and returned in a response object.
The request defines three routes:
route0
, which starts on January 18 at 9:00 AM and has a maximum duration of 8 hours.route1
, which starts on January 19 at 9:00 AM, has a maximum duration of 8 hours, and provides the route attributehazmat
(hazardous materials).route2
, which starts on January 20 at 9:00 AM and has a maximum duration of 4 hours.
All routes start and end at latitude/longitude coordinates 39.718005, -104.969531
(a location in Denver, Colorado) and have a lunch break set at 12:00 PM.
The request defines 12 jobs:
job0
is a simple job, with a location and a 10 minute time on site value. Asjob0
demands no further constraints, it can be placed on any route.job1
andjob2
define a required delivery date using thedate
field -job1
on January 18 andjob2
on January 19. These requirements dictate thatjob1
can be placed only onroute0
, andjob2
can be placed only onroute1
.job3
andjob4
use the array syntax to define a set of allowed delivery dates.job3
can be delivered on January 18 or 19, so can be placed onroute0
orroute1
.job4
can be delivered only on January 20, so can be placed only onroute2
.job5
,job6
, andjob7
demand the following route attributes:job8
defines a time window, which constrains the delivery of the job to between 1:00 PM and 3:00 PM. The job will be assigned to the route that can most efficently satisfy this window.job9
,job10
, andjob11
define no complex constraints and will be placed on the routes that can most efficiently service them.
Response
{
"routes": [
{
"id": "route0",
"cost": 23.78,
"internal_cost": 132.02,
"distance_meters": 38810.0,
"working_time": "01:04:04",
"driving_time": "00:54:04",
"stops": [
{
"location": "39.718005,-104.969531",
"type": "depot",
"arrival_datetime": "2016-01-18T09:00:00",
"time_on_site": "00:00:00",
"distance_to_meters": 0.0,
"time_to": "00:00:00"
},
{
"type": "job",
"id": "job1",
"arrival_datetime": "2016-01-18T09:26:58",
"time_on_site": "00:10:00",
"distance_to_meters": 19440.0,
"time_to": "00:26:58"
},
{
"location": "39.718005,-104.969531",
"type": "depot",
"arrival_datetime": "2016-01-18T10:04:04",
"time_on_site": "00:00:00",
"distance_to_meters": 19370.0,
"time_to": "00:27:06"
}
]
},
{
"id": "route1", ...
"stops": [
{ "type": "depot", ... },
{ "id": "job2", ... },
{ "id": "job10", ... },
{ "id": "job9", ... },
{ "id": "job5", ... },
{ "id": "job3", ... },
{ "id": "job0", ... },
{ "id": "job11", ... },
{ "type": "break", ... }
{ "id": "job8", "idle_time": "00:12:56", ... },
{ "type": "depot", ... }
]
},
{
"id": "route2", ...
"stops": [
{ "type": "depot", ... },
{ "id": "job4", ... },
{ "id": "job6", ... },
{ "type": "depot", ... }
]
}
],
"unrouted_jobs": [
{ "id": "job7" }
]
}
A snipped version of the quick_start_build.json response. The full response is available here. Click here to open in the UI.
The response object consists of an array of route objects, and an array of unrouted jobs.
- Each route contains an ordered list of stops as well as information about the route, such as its total time and distance in meters.
- Each stop in the route.stops array can be either a job, break, or depot. The arrival time and the time/distance are calculated from the previous stop.
The quick_start_build.json request produces a response with the following assignments and sequences:
route0
:depot
,job1
,depot
route1
:depot
,job2
,job10
,job9
,job5
,job3
,job0
,job11
,break
,job8
,depot
route2
:depot
,job4
,job6
,depot
unrouted_jobs
:job7
These route assignments minimize cost while obeying all of the job constraints specified in the quick_start_build.json request.
Explanation:
- A depot stop at route.location has been automatically inserted at the start and end of every route.
- The lunch break specified in route.breaks has been automatically added to
route1
at 12:00 PM. It has not been added to any other route because the other routes all finish before 12:00 PM. See Routing with Driver Breaks for more information about breaks. - Accurate arrival times, driving times, and driving distances have been calculated for every stop.
- All date constraints on
job1
,job2
,job3
, andjob4
were respected. See Routing with Dates for more information on dates. - All attribute constraints on
job5
,job6
andjob7
were respected. See Routing with Attributes for more information on attributes.job5
was placed onroute1
because it required thehazmat
attribute.job6
was placed onroute2
. It was not placed onroute1
because it disallowed thehazmat
attribute.job7
was not routed as its requiredheavy_truck
attribute could not be satisfied.
job8
has an idle_time of"00:12:56"
. This means that the driver is idle for 12 minutes and 56 seconds before the job is delivered.- This happens because the previous 7 jobs on the route take less than 4 hours to complete, so given the route.start_time of 9:00 AM,
the driver has to wait for
job8
's time window of 1:00 PM to 3:00 PM to open. - Note that RouteCloud has optimally placed
job8
at the end of the route to make the most efficient use of time. If there were fewer jobs beforejob8
, less time would be used beforejob8
, resulting in more idle time. - See Routing with Time Windows for more information on time windows.
- This happens because the previous 7 jobs on the route take less than 4 hours to complete, so given the route.start_time of 9:00 AM,
the driver has to wait for
An image of the routes generated by quick_start_build.json.
Basic Vehicle Routing
Most of the data specified in the quick_start_build.json
request is not required - the only mandatory fields for routes and jobs are id
and location
.
For comparison, here is the same example with all driver break, date, attribute, and time window constraints removed:
- Request: basic_vehicle_routing_build.json - open in UI.
- Response: basic_vehicle_routing_build_response.json - open in UI.
What Next?
- Continue to Optimizing Routes.
- View the /v1/build reference.
- Back to Introduction.