TotalApp Docs

Route Optimization Engine

The backend engine that re-sequences a crew's stops into the shortest practical order, then hands back a ready-to-draw route map. It powers the "Optimize Route" action on the Crew Routing screen.

What Is the Route Optimization Engine?

The Route Optimization Engine is one of TotalApp's backend engines. Its job is to take a crew route — a list of stops a field team needs to visit — and re-order those stops so the total distance travelled is as short as practical, without requiring an external mapping or routing API.

It exists behind exactly one action: the Optimize Route button on the Crew Routing screen inside the Energy & Utilities add-on. When a dispatcher clicks it, the current stop list is sent to this engine, which returns the same stops in a shorter order plus a new total distance — ready to save straight back onto the route record.

In one sentence

Give the Route Optimization Engine a list of stops (with coordinates or known location names) — it returns those same stops re-ordered for the shortest practical tour, the new total distance in kilometers, and a map payload ready to render.

How It Works — Haversine, Nearest-Neighbor, 2-Opt

This is a classic, simplified solution to the Traveling Salesperson Problem (TSP) — finding the shortest possible route that visits every stop once. An exact solution gets expensive fast as the stop count grows, so the engine uses a fast three-step approximation that runs instantly for a realistic crew route (2–15 stops) and lands very close to optimal in practice.

1. Haversine Distance 2. Nearest-Neighbor Seed Tour 3. 2-Opt Refinement
StepWhat happens
1. Haversine DistanceEvery pair of stops is measured using the Haversine formula — the great-circle (straight-line) distance between two latitude/longitude points on a sphere, using Earth's real radius (6,371 km). This is the same distance math used throughout the calculation.
2. Nearest-Neighbor Seed TourA fast, greedy first pass: starting from the origin (by default "Istanbul Hub"), the engine always jumps to the closest stop that hasn't been visited yet, then repeats until every stop is included. This produces a decent tour quickly, but greedy choices can leave an awkward, long jump near the end.
3. 2-Opt RefinementThe seed tour is then improved: the engine tests reversing every possible segment of the route and keeps any reversal that shortens the total distance. It keeps repeating this until no further reversal helps. This is the standard "2-opt local search" technique from TSP literature, and it specifically fixes the bad long jumps the greedy seed tour tends to leave behind.

Fast by design

The whole pipeline is O(n²) — for the handful of stops a real crew route actually has (2–15), this computes essentially instantly with no external routing service and no network call. Routes with fewer than 3 stops skip the 2-opt step entirely, since there's nothing left to reorder.

Input & Output

The engine is called with POST /api/en/crew-routing/optimize and takes the route's current stops; it returns those stops re-ordered, the new total distance, and a ready-to-render map payload.

FieldDirectionMeaning
routeIdInputThe route being optimized, so the client can match the response back to the correct record.
stops[]InputThe route's current stop list — same shape as RouteStop used on the Crew Routing screen. Each stop may carry its own latitude/longitude, or just a locationName.
originLat / originLngInput (optional)Starting point for the tour. If omitted, the engine defaults to "Istanbul Hub".
optimizedStopsOutputThe same stops, re-ordered for the shortest practical tour, with each stop's stopOrder updated to match.
totalDistanceKmOutputThe tour's new total distance, recalculated after optimization and rounded to one decimal place.
map.pointsOutputThe origin plus every stop, each with an id, name, coordinates, and order — ready for numbered map pins.
map.connectorOutputThe same tour in AnyChart connector-series format: a flat [lat, lng, lat, lng, ...] array plus short and full tooltip text.

Empty stop list

If a route has zero stops, the engine returns immediately with zero distance and empty map data — it never runs the TSP calculation for an empty route.

Resolving Coordinates for Each Stop

Not every stop on a Crew Routing route has GPS coordinates entered — some are just a free-text locationName. The engine resolves a usable coordinate for each stop in this order:

  1. If the stop has its own latitude/longitude, that value is used directly (the most accurate source).
  2. Otherwise, if the stop's locationName matches one of a small built-in list of known Turkey hubs (Istanbul Hub, Ankara DC, Izmir Port, Bursa, Konya Hub, Eskişehir), that hub's coordinates are used.
  3. If neither is available, the stop falls back to the default origin ("Istanbul Hub").

This fallback list is intentionally small and is duplicated on both the client and the server so the server has no dependency on the client's application bundle — see Limitations below for what that means in practice.

Which Screen Uses This

Exactly one screen calls this engine:

ScreenAdd-on / Sidebar GroupAction that triggers it
Crew Routing Energy & Utilities → Field & Dispatch Operations Optimize Route button on a route row

"Optimize Route" vs. "View on Map"

Crew Routing also has a View on Map button, and it's easy to assume the two are connected — they aren't. View on Map draws the route's stops exactly as they currently stand, with no call to this engine at all. Only Optimize Route invokes the Route Optimization Engine; after it returns, the updated stop order is saved and the map naturally reflects the new sequence the next time it's viewed.

The engine itself performs no persistence — it is a pure calculation. The client receives the result, saves the updated route through the normal Crew Routing save path, and shows a success notification. This keeps the engine stateless, testable, and reusable on its own.

Limitations

Straight-line, not road distance

Haversine distance is "as the crow flies" — it does not know about roads, traffic, one-way streets, or actual drive time. A shorter Haversine distance is not always a shorter real-world drive.

No global-optimal guarantee

2-opt finds a local minimum — a tour that can't be improved by reversing one segment — not necessarily the mathematically shortest possible tour. For the small stop counts a crew route realistically has, it's very close to optimal in practice.

Small fallback hub list

Only six named hubs (Istanbul Hub, Ankara DC, Izmir Port, Bursa, Konya Hub, Eskişehir) have built-in coordinates. A stop with no coordinates and an unrecognized location name silently falls back to Istanbul Hub, which can produce a misleading result for that stop.

Frequently Asked Questions

Does optimizing a route save it automatically?
The engine itself never writes to disk — it's a pure calculation. The Crew Routing screen takes the returned stop order and distance and saves the route through its normal save path immediately after the call succeeds, so from the user's perspective the click does save the result.
What happens if I click Optimize Route on a route with only one or two stops?
With fewer than three stops there is only one possible order, so the 2-opt refinement step is skipped entirely — the engine still returns a result (with the recalculated distance), it just has nothing to reorder.
Can this engine use real road distances instead of straight-line distance?
Not currently — it uses the Haversine formula exclusively. The distance calculation is isolated in its own function, so swapping in a real routing API (Google Directions, Mapbox, OSRM) in the future would only require changing that one function, not the rest of the pipeline.
Is my optimized route data shared with other tenants?
No. The engine itself holds no state and stores nothing — the resulting route is saved through the standard Crew Routing service, which persists to the current tenant's own server-backed data store, isolated from every other tenant.