Nodes

A node is the work to be scheduled: a task, a location or an appointment that a resource visits or performs, and the primary demand object in JOpt.TourOptimizer. The optimizer assigns nodes to resources and sequences them into routes, respecting time windows, capacity and all other constraints. This page describes the node types of JOpt, each designed for a different modeling scenario, and how to add them to an optimization. The Basic elements tutorial shows how nodes and resources work together.
Table of contents
- Common properties
- TimeWindowGeoNode
- EventNode
- PillarTimeWindowGeoNode
- PillarEventNode
- Optional nodes
- Stay nodes
- Builder pattern
- Adding nodes to the optimization
- Node types compared
- Related pages
Common properties
All node types implement the INode interface and share the following properties: the id, the opening hours, the visit duration and the importance. They differ in what additional information they carry and how the optimizer treats them.
Unique ID
Every node needs a unique string identifier. This ID is used throughout the optimization for assignment, reporting, and result analysis. No two nodes may share the same ID.
String nodeId = "Cologne";
Opening hours
A node holds a list of IOpeningHours entries. Each entry defines a time window during which the node can be visited. Multiple opening hours represent multiple days or multiple time slots.
ZonedDateTime start = ZonedDateTime.of(2020, MAY.getValue(), 6, 8, 0, 0, 0,
ZoneId.of("Europe/Berlin"));
ZonedDateTime end = ZonedDateTime.of(2020, MAY.getValue(), 6, 17, 0, 0, 0,
ZoneId.of("Europe/Berlin"));
IOpeningHours firstDay = new OpeningHours(start, end);
Alternatively, you can construct an OpeningHours from a TimeWindow object:
TimeWindow tw = new TimeWindow(start, end);
IOpeningHours firstDay = new OpeningHours(tw);
Multiple opening hours are collected into a list:
List<IOpeningHours> openingHours = new ArrayList<>();
openingHours.add(dayOneHours);
openingHours.add(dayTwoHours);
Each opening hour corresponds to a potential visit slot. If a resource has matching WorkingHours on the same day, the optimizer can schedule the visit during that window.
Visit duration
The visit duration is the time required to perform the task at the node: the productive service time, not including travel.
Duration visitDuration = Duration.ofMinutes(20);
The optimizer accounts for this duration when scheduling: the resource must arrive, spend the visit duration at the node, and then travel to the next stop. A node with a 20-minute visit duration and a 30-minute driving time from the previous stop consumes at least 50 minutes of the resource's working time.
Visit duration can be made route-dependent using the visit duration efficiency feature, where different resources can perform the same task faster or slower. See setHasRouteDependentVisitDuration(true) and setMinimalVisitDuration(...).
Importance
The importance is a relative integer value that influences how the optimizer prioritizes nodes when violations are unavoidable. A node with higher importance is less likely to be violated (late arrival, skipping) than a node with lower importance.
int importance = 1; // default
Importance is relative. If all nodes have the same importance value, the optimizer treats them equally. The value only matters when nodes compete for limited resources or time windows. Common practice: use a small integer scale (for example 1 to 10) and assign higher values to contractually important tasks.
TimeWindowGeoNode
TimeWindowGeoNode is the most common node type: a physical location that must be visited within a time window.
TimeWindowGeoNode constructor
INode node = new TimeWindowGeoNode(
"Cologne", // unique ID
50.9333, // latitude
6.95, // longitude
openingHours, // List<IOpeningHours>
Duration.ofMinutes(20), // visit duration
1 // importance
);
| Parameter | Type | Description |
|---|---|---|
id | String | Unique identifier for the node |
latitude | double | Geographic latitude of the node's location |
longitude | double | Geographic longitude of the node's location |
openingHours | List<IOpeningHours> | Time windows when the node can be visited |
visitDuration | Duration | Service time required at the node |
importance | int | Relative priority (higher = more protected from violations) |
The geo coordinates define where the node is located on the map. The optimizer uses these coordinates to calculate distances and travel times between nodes, either through external connection data or the built-in backup connector.
When to use a TimeWindowGeoNode
Use TimeWindowGeoNode for any task that requires physical presence at a location: customer visits, deliveries, inspections, maintenance jobs, installations.
EventNode
EventNode is a node without a geographical location: a task that must happen within a time window but does not require travel.
EventNode constructor
INode event = new EventNode(
"Customer Call", // unique ID
openingHours, // List<IOpeningHours>
Duration.ofMinutes(30), // visit duration
1 // importance
);
| Parameter | Type | Description |
|---|---|---|
id | String | Unique identifier |
openingHours | List<IOpeningHours> | Time windows when the task can be performed |
visitDuration | Duration | Time required for the task |
importance | int | Relative priority |
An EventNode has no latitude or longitude. It is placed into the route timeline like any other node (consuming visit duration within the opening hours), but it does not introduce travel distance. The optimizer schedules it in a gap between physical visits where it fits the time window.
When to use an EventNode
Use EventNode for phone calls, remote support sessions, paperwork, compliance steps, administrative tasks, or any work that can be done from anywhere within working hours. Event nodes can be mixed freely with geo nodes in the same optimization.
PillarTimeWindowGeoNode
PillarTimeWindowGeoNode is a geo-located node with a hard-constrained time window. The optimizer's architecture guarantees that the opening hours of a pillar cannot be violated. The guarantee is a structural property of the solution space, not a soft constraint with a high penalty.
PillarTimeWindowGeoNode constructor
IOpeningHours pillarWindow = new OpeningHours(
ZonedDateTime.of(2020, MAY.getValue(), 6, 10, 0, 0, 0, ZoneId.of("Europe/Berlin")),
ZonedDateTime.of(2020, MAY.getValue(), 6, 10, 50, 0, 0, ZoneId.of("Europe/Berlin")));
IPillarNode pillar = new PillarTimeWindowGeoNode(
"Plumbing Appointment", // unique ID
50.9333, // latitude
6.95, // longitude
pillarWindow // single OpeningHours (the SLA window)
);
When the visit duration equals the opening hours window, it is not necessary to provide the duration separately. The node must be visited during exactly this window.
A pillar can optionally be attached to a specific resource:
pillar.attachResource(john);
This guarantees both when the task is done and who does it.
When to use a PillarTimeWindowGeoNode
Use PillarTimeWindowGeoNode for contractual SLAs, legal obligations, appointments with fixed time commitments, or any task where "almost on time" is not acceptable. The Pillar nodes feature guide describes how conflicts are resolved.
PillarEventNode
PillarEventNode is a non-geographical pillar: the same hard time-window guarantee as PillarTimeWindowGeoNode, but without a physical location.
PillarEventNode constructor
IPillarNode pillarCall = new PillarEventNode(
"Important Call", // unique ID
pillarOpeningHours, // single OpeningHours
Duration.ofMinutes(30) // visit duration
);
pillarCall.attachResource(jack);
When to use a PillarEventNode
Use PillarEventNode for time-critical phone calls, compliance deadlines, or remote tasks that must happen in an exact window and cannot be missed.
Optional nodes
Any node type can be marked as optional. An optional node may or may not be visited, depending on what is globally optimal. The optimizer decides whether including the node improves or worsens the total cost.
node.setIsOptional(true);
Optional nodes are useful for:
- Intermediate stops in pickup and delivery (for example waste dumps or reload points)
- Nice-to-have visits that can be deferred if the schedule is too tight
- Buffer nodes that absorb excess capacity
When an optional node is not visited, it does not appear in the result routes. The optimizer reports which optional nodes were included and which were skipped.
Stay nodes
Any geo node can be marked as a stay node, making it eligible as an overnight position for multi-day routing:
node.setIsStayNode(true);
A stay node can be optional at the same time. The optimizer then visits the hotel only if staying out is beneficial. The Overnight stay feature guide describes the policy controls.
Builder pattern
For integrations and REST-compatible workflows, JOpt provides an immutable builder pattern. Instead of using a constructor, you compose a node with builder calls:
Node node = Node.builder()
.id("Cologne")
.type(GeoNode.of(Position.of(50.9333, 6.95)))
.visitDuration(Duration.ofMinutes(20))
.addOpeningHours(
OpeningHours.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 nodes, resources, and properties into a single immutable configuration:
OptimizationConfig<JSONConfig> config = OptimizationConfig.<JSONConfig>builder()
.addAllNodes(createNodes())
.addAllResources(createResources())
.extension(createExtension())
.options(createOptions())
.build();
This is the recommended approach when building optimization inputs programmatically, especially in service contexts where reproducibility and serialization matter.
Adding nodes to the optimization
Once constructed, nodes are added to the optimization instance:
opti.addElement(node);
All node types use the same addElement(...) method. Geo nodes, event nodes, pillars, and optional nodes are all added the same way. The optimizer identifies the type internally and applies the appropriate handling.
Node IDs must be unique. If you add a node with an ID that already exists, it is rejected.
Node types compared
| Node type | Has location | Hard time window | Typical use case |
|---|---|---|---|
TimeWindowGeoNode | Yes | No (soft) | Customer visits, deliveries, inspections |
EventNode | No | No (soft) | Phone calls, remote tasks, paperwork |
PillarTimeWindowGeoNode | Yes | Yes (architectural) | Contractual SLAs, fixed appointments |
PillarEventNode | No | Yes (architectural) | Time-critical calls, compliance deadlines |
Additional flags applicable to any node:
setIsOptional(true): the optimizer decides whether to visit the nodesetIsStayNode(true): the node is eligible as an overnight position
Related pages
- Basic elements: how nodes and resources work together in an optimization
- Resources: the resources that visit the nodes
- Pillar nodes: the pillar guarantee and how conflicts are resolved
- Overnight stay: stay nodes and the stay policies of a resource
Authors
DNA Evolutions GmbH
Added: 2026-04-09 (JOpt core 7.5.3-j17) | Last updated: 2026-10-19