Resources
The actors performing work
A Resource represents a vehicle, a technician, a driver, or any entity that visits nodes and performs tasks. Resources define where work starts, when it can happen, and what capacity is available. The optimizer assigns nodes to resources and sequences them into routes that respect working hours, travel limits, and all other constraints.
The primary resource type in JOpt.TourOptimizer is the CapacityResource. It models a mobile actor with a home location, working hours, maximum working time, maximum travel distance, and optional capacity for pickup and delivery scenarios.
Overview
- CapacityResource: the primary type
- Constructor parameters
- Working hours
- Maximum working time
- Maximum distance
- Cost model
- Additional capabilities
- Builder pattern
- Adding resources to the optimization
- Summary
CapacityResource: the primary type
CapacityResource implements the IResource interface and is the standard resource type for all routing and scheduling scenarios. It models a resource with a home location (latitude/longitude), one or more working hours defining when it can operate, and limits on working time and travel distance.
Basic construction
Duration maxWorkingTime = Duration.ofHours(9);
Quantity<Length> maxDistance = Quantities.getQuantity(1200.0, KILO(METRE));
List<IWorkingHours> workingHours = new ArrayList<>();
workingHours.add(new WorkingHours(
ZonedDateTime.of(2020, MAY.getValue(), 6, 8, 0, 0, 0, ZoneId.of("Europe/Berlin")),
ZonedDateTime.of(2020, MAY.getValue(), 6, 17, 0, 0, 0, ZoneId.of("Europe/Berlin"))));
workingHours.add(new WorkingHours(
ZonedDateTime.of(2020, MAY.getValue(), 7, 8, 0, 0, 0, ZoneId.of("Europe/Berlin")),
ZonedDateTime.of(2020, MAY.getValue(), 7, 17, 0, 0, 0, ZoneId.of("Europe/Berlin"))));
IResource jack = new CapacityResource(
"Jack", // unique ID
50.775346, // latitude (home location)
6.083887, // longitude (home location)
maxWorkingTime, // maximum working time per shift
maxDistance, // maximum travel distance per shift
workingHours // list of working hours
);
Constructor parameters
| Parameter | Type | Description |
|---|---|---|
id | String | Unique identifier for the resource (e.g. "Jack", "Truck-42") |
latitude | double | Latitude of the resource's home/start location |
longitude | double | Longitude of the resource's home/start location |
maxWorkingTime | Duration | Maximum working time per shift (soft constraint) |
maxDistance | Quantity<Length> | Maximum travel distance per shift (soft constraint) |
workingHours | List<IWorkingHours> | Time windows during which the resource can operate |
Unique ID
Each resource needs a unique string identifier. This ID appears in result routes, event streams, and violation reports. No two resources may share the same ID.
Home location
The latitude and longitude define where the resource starts and (by default) returns to at the end of each shift. This is the base position for calculating travel times to the first node and from the last node. In open-route scenarios or with overnight stays, the end-of-day position may differ from the home location.
Working hours
Working hours define when the resource is available to work. Each IWorkingHours entry represents one shift or one day. A resource with multiple working hours entries can operate across multiple days or shifts.
IWorkingHours day1 = new WorkingHours(
ZonedDateTime.of(2020, MAY.getValue(), 6, 8, 0, 0, 0, ZoneId.of("Europe/Berlin")),
ZonedDateTime.of(2020, MAY.getValue(), 6, 17, 0, 0, 0, ZoneId.of("Europe/Berlin")));
IWorkingHours day2 = new WorkingHours(
ZonedDateTime.of(2020, MAY.getValue(), 7, 8, 0, 0, 0, ZoneId.of("Europe/Berlin")),
ZonedDateTime.of(2020, MAY.getValue(), 7, 17, 0, 0, 0, ZoneId.of("Europe/Berlin")));
Alternatively, construct from a TimeWindow:
TimeWindow tw = new TimeWindow(start, end);
IWorkingHours hours = new WorkingHours(tw);
Working hours are the primary carrier of many resource-level constraints and configurations:
- ZoneCode constraints are attached to individual WorkingHours, enabling per-shift territory definitions. See the ZoneCodes feature guide.
- Overnight stay availability is set per WorkingHours via
setIsAvailableForStay(true). See the Overnight Stay feature guide. - Resource type conditions and other per-shift constraints are attached at the WorkingHours level.
This per-shift architecture is a deliberate design decision. It allows the same resource to have different territories, different capabilities, and different policies on different days, all through data configuration without model changes.
Each WorkingHours entry produces exactly one route in the result. A resource with 5 working hours produces 5 routes (one per day/shift).
Maximum working time
The maximum working time defines how long a resource should work within each shift. This is a soft constraint: the optimizer aims to keep total productive and travel time within this limit, but overtime can occur if the schedule demands it.
Duration maxWorkingTime = Duration.ofHours(9);
If overtime occurs, it is reported as a violation and penalized through the cost function. Use JOptWeight.WorkingTime to control how strongly overtime is penalized.
Maximum working time is per shift. A resource with a 9-hour max and two working hours entries has a 9-hour limit on each day independently.
Maximum distance
The maximum travel distance defines how far a resource should travel per shift. Like working time, this is a soft constraint: the optimizer targets this limit but may exceed it if necessary.
Quantity<Length> maxDistance = Quantities.getQuantity(1200.0, KILO(METRE));
Distance violations are penalized through the cost function. Use JOptWeight.MaxRouteDistance to control the penalty weight.
In practice, set maxDistance generously for the initial setup and tighten it based on observed results. An overly restrictive maxDistance can prevent the optimizer from assigning distant nodes at all.
Cost model
The resource cost model defines the per-unit costs for three components:
resource.setCost(
0, // fixed cost per route (e.g. vehicle dispatch cost)
1, // cost per unit of distance
1 // cost per unit of time
);
| Parameter | Description |
|---|---|
| Fixed cost | A constant cost incurred whenever the resource is used. Set to 0 if there is no dispatch cost. |
| Distance cost | Cost per unit of distance traveled. Higher values make the optimizer prefer shorter routes. |
| Time cost | Cost per unit of time spent. Higher values make the optimizer prefer faster routes. |
The cost model interacts with the optimizer's objective function. Adjusting the ratio between distance cost and time cost shifts the optimizer's preference: a high distance cost produces geographically compact routes, while a high time cost produces time-efficient routes.
// Prefer short distances over short times
resource.setCost(0, 2, 1);
// Prefer short times over short distances
resource.setCost(0, 1, 2);
Additional capabilities
After construction, resources can be configured with additional features:
FlexTime (flexible shift start)
// Allow starting up to 2 hours later (reduce idle time)
resource.setFlexTime(Duration.ofHours(2));
// Allow starting up to 1 hour earlier (driving only)
resource.setMaxRouteStartReductionTime(Duration.ofHours(1), true);
resource.setReductionTimeIsIncludedInWorkingTime(true);
See the FlexTime feature guide.
Overnight stay policies
// Stay-out policy: minimum distance or time from home
resource.setStayOutPolicy(
Quantities.getQuantity(100, KILO(METRE)),
Duration.ofHours(2));
resource.setStayOutPolicyReturnDistanceActive(true);
// Consecutive-night limits
resource.setStaysOut(-1, 4, 2); // unlimited total, max 3 in a row, 2 nights recovery
See the Overnight Stay feature guide.
Visit duration efficiency
// This resource is 50% faster than default (senior technician)
resource.setVisitDurationEfficiency(0.5);
A resource with efficiency 0.5 completes a 30-minute task in 15 minutes (at nodes where route-dependent visit duration is enabled). This models skill differences between resources.
Resource depot (pickup and delivery)
IResourceDepot depot = new SimpleResourceDepot("TruckDepot");
ILoadCapacity capacity = new SimpleLoadCapacity("Bread", 20, 0);
depot.add(capacity);
resource.setResourceDepot(depot);
This attaches a cargo capacity to the resource for pickup and delivery scenarios. See the Pickup & Delivery feature guide.
Qualifications and constraints
Resources can carry qualifications (skills, types) and constraints (zones, binding/excluding resource conditions) that control which nodes they can visit:
// ZoneCode constraint on a specific WorkingHours
ZoneNumberConstraint zoneConstraint = new ZoneNumberConstraint();
zoneConstraint.setIsHard(true);
zoneConstraint.addZoneCode(new ZoneNumber(1));
workingHoursDay1.addConstraint(zoneConstraint);
Builder pattern
For enterprise integrations, resources can be constructed using the immutable builder pattern:
Resource resource = Resource.builder()
.id("Jack from Aachen")
.type(CapacityResource.of())
.position(Position.of(50.775346, 6.083887))
.maxTime(Duration.ofHours(9))
.maxDistance(Quantities.getQuantity(1200, KILO(METRE)))
.addWorkingHours(
WorkingHours.builder()
.begin(begin.toInstant())
.end(end.toInstant())
.zoneId(begin.getZone())
.build())
.build();
The builder produces an immutable object that can be serialized to JSON and used across REST, SDK, and test environments. The OptimizationConfig builder composes resources alongside nodes and properties into a single reproducible configuration.
Adding resources to the optimization
Resources are added to the optimization instance using the same method as nodes:
opti.addElement(resource);
Resource IDs must be unique. The optimizer matches resources to nodes based on time window compatibility, geographic proximity, constraints, and cost.
Summary
| Property | Type | Constraint type | Description |
|---|---|---|---|
| Home location | double, double | n/a | Start/end position for each shift |
| Working hours | List<IWorkingHours> | Hard (defines available shifts) | When the resource can operate |
| Max working time | Duration | Soft (penalized via cost) | Target shift duration |
| Max distance | Quantity<Length> | Soft (penalized via cost) | Target travel distance per shift |
| Cost model | setCost(fixed, dist, time) | n/a | Per-unit costs for the objective function |
| FlexTime | setFlexTime(...) | Hard (bounded) | Flexible shift start |
| Overnight stay | setStayOutPolicy(...) | Policy-driven | Multi-day routing control |
| Visit efficiency | setVisitDurationEfficiency(...) | n/a | Skill-based task speed |
| Resource depot | setResourceDepot(...) | n/a | Cargo capacity for PND |
Per-shift configurations (zones, overnight availability, constraints) are attached to individual WorkingHours entries, not to the resource as a whole. This enables daily territory switching, per-shift capabilities, and granular policy control.
For the next step, see the Basic Elements tutorial to learn how nodes and resources work together in an optimization.
Authors
A product by dna-evolutions ©