RoutingKit Documentation
repository·master·Indexed 19 days ago
https://github.com/routingkit/routingkitA high-performance C++ library for advanced route planning on large-scale OpenStreetMap datasets. It specializes in index-based shortest path queries using (Customizable) Contraction Hierarchies (CH) to achieve millisecond-level query times on continental-scale data. The library provides tools for loading OSM PBF data, building and persisting CH indices, performing one-to-one and many-to-many queries via node pinning, and computing path lengths using secondary extra weights.
What's inside RoutingKit
- RoutingKit is a C++ library designed for advanced route planning. Its primary feature is an index-based data structure called (Customizable) Contraction Hierarchy (CH). This allows for extremely fast shortest-path queries (often in milliseconds or less) on continental-scale datasets while maintaining flexibility for arc weights. The library is designed to bridge the gap between recent research and practical application development, providing an interface that balances usability with high performance.
Include RoutingKit headers
masterRoutingKit provides functionality through specific headers to allow for fine-grained control over what is included in your project.
- For specific functionality, include the relevant header (e.g.,
<routingkit/contraction_hierarchy.h>). - For convenience, you can include
<routingkit/all.h>, which includes all available RoutingKit functionality.
All functions and classes are located within the
RoutingKitnamespace.- For specific functionality, include the relevant header (e.g.,
Understand OSM Relation Members
masterWhen decoding OSM relations, the
relation_callbackprovides a list ofOSMRelationMemberobjects. Each member represents an element that is part of the relation.An
OSMRelationMembercontains:type: AnOSMIDTypeenum indicating if the member is anode,way, orrelation.id: Theuint64_tOSM ID of the member.role: Aconst char*describing the role of the object within that specific relation.
enum class OSMIDType{ node, way, relation }; struct OSMRelationMember{ OSMIDType type; uint64_t id; const char*role; };Compute path lengths using extra weights in ContractionHierarchyQuery
masterWhile
ContractionHierarchyoptimizes for a primary weight, you can compute the length of the resulting shortest path according to secondary "extra weights" that were not used during preprocessing.Key Concepts
- Extra Weights: These do not need to be positive; they can be integers, strings, or other types. They must support
operator[](e.g.,std::vector, pointers). - Link Function: Since extra weights can be non-numeric (like strings), you must provide a link function with the signature
Weight link(Weight first, Weight second). This function defines how to combine weights along a path (e.g., addition for numbers, concatenation for strings). - SaturatedWeightAddition: A recommended link function for numeric weights that handles overflows and underflows (e.g., capping at
INT_MINor handlinginf_weight) safely.
Methods
get_extra_weight_distance(const ExtraWeight& extra_weight, const LinkFunction& link): Computes the extra weight distance for the path found by the primary weight optimization.get_extra_weight_distances_to_targets(...): A many-to-many version for pinned targets.get_extra_weight_distances_to_sources(...): A many-to-many version for added sources.
Warning: Non-unique Shortest Paths
If multiple paths have the same primary weight but different extra weights, the behavior is undefined. The algorithm is free to pick any of the shortest paths, so the extra weight result may vary depending on which path is chosen.
auto ch = ContractionHierarchy::build(node_count, tail, head, weight); ContractionHierarchyQuery q(ch); q.add_source(0).add_target(3).run(); // Using numeric weights with SaturatedWeightAddition assert(q.get_extra_weight_distance(extra_weight1, SaturatedWeightAddition()) == 20); // Using complex types (strings) with a custom link function assert(q.get_extra_weight_distance(extra_weight3, [](std::string l, std::string r){return l+r;}) == "foobar");- Extra Weights: These do not need to be positive; they can be integers, strings, or other types. They must support
Use OSM way filters for different transport modes
masterWhen importing OSM PBF files, you can filter ways based on the intended transport mode. RoutingKit provides specific functions for this purpose, which are used analogously to one another. For pedestrian routing, useis_osm_way_used_by_pedestrians. Other available filters includeis_osm_way_used_by_bicyclesandis_osm_way_used_by_cars.How Contraction Hierarchy (CH) works
masterContraction Hierarchy (CH) is an index-based speedup technique for shortest path computations. It operates in two distinct phases:
- Preprocessing (Index Generation): A slow phase that depends only on the graph and its weights. The resulting index is independent of specific source or target nodes.
- Query: A very fast phase that uses the precomputed index to find shortest paths.
All core functionality is located in
<routingkit/contraction_hierarchy.h>.How graphs are represented in RoutingKit
masterRoutingKit represents directed graphs using two primary formats: arc-lists and adjacency-arrays.
Arc-list
An arc-list is a simple structure suitable for most tasks except graph traversal. It consists of:
node_count: The number of nodes in the graph.tail: A vector wheretail[i]is the source node of arci.head: A vector wherehead[i]is the destination node of arci.- Arc IDs: The position
iin thetailandheadvectors is the unique ID of the arc. - Properties: Additional properties like
geo_distance(meters),travel_time(seconds), andspeed(km/h) can be stored in parallel vectors.
RoutingKit supports multi-arcs, loops, disconnected graphs, and zero-weights.
Adjacency-array
An adjacency-array is optimized for graph traversal (e.g., iterating over outgoing arcs). It consists of:
first_out: A vector of sizenode_count + 1.first_out[x]is the index inheadwhere the outgoing arcs of nodexbegin.first_out[x+1]is where they end.head: A vector containing the destination node IDs.
To iterate over outgoing arcs of node
x:for(unsigned xy=first_out[x]; xy<first_out[x+1]; ++xy){ unsigned y = head[xy]; // xy is the arc from node x to node y }// Arc-list structure unsigned node_count; std::vector<unsigned>tail; std::vector<unsigned>head; // Adjacency-array structure std::vector<unsigned>first_out; std::vector<unsigned>head;How Customizable Contraction Hierarchies (CCH) work
masterCustomizable Contraction Hierarchies (CCH) are an index-based technique for shortest paths in directed graphs that allows for rapid adaptation to new edge weights. Unlike standard Contraction Hierarchies (CH), CCH uses a three-phase lifecycle:
- Preprocessing: A slow phase that builds the index structure. Crucially, this phase does not depend on arc weights and only needs to be performed once.
- Customization: A relatively fast phase where specific weights (e.g., live traffic data) are introduced into the preprocessed index.
- Query: The phase where actual shortest paths are computed using the customized weights.
A common deployment pattern is to perform preprocessing once, and perform customization per user upon login or whenever traffic updates occur.
/* The lifecycle follows: Preprocessing -> Customization -> Query */Map IDs using LocalIDMapper and IDMapper
masterWhen filtering elements from a large ID range (e.g., OSM node IDs) into a smaller subset, you need a way to map the original (global) IDs to their new (local) indices.
LocalIDMapper
Found in
<routingkit/id_mapper.h>,LocalIDMapperis memory-efficient, requiring less than one bit per element in addition to theBitVectorused for filtering.to_local(x): Maps a global ID to its new local index. Warning: Only call this ifkeep_filter.is_set(x)is true.to_local(x, default_value): Returnsdefault_valueif the global IDxwas removed during filtering.is_global_id_mapped(x): Checks if the global IDxexists in the filtered set.local_id_count(): Returns the number of elements in the filtered set.global_id_count(): Returns the size of the original range.
IDMapper
IDMapperprovides all the functionality ofLocalIDMapperbut includes an additionalto_global(local_id)method to map from the small range back to the large range. This requires more memory thanLocalIDMapper.Lifecycle Warning
Both mappers store a pointer to the
BitVectorused to create them. You must ensure theBitVectoris not destroyed while the mapper is still in use.vector<string> names = {"Bob", "Alice", "Charlie", "Malice"}; // Create a filter: keep names where the second character is not 'a' BitVector keep_filter = make_bit_vector(names.size(), [&](unsigned i){return names[i][1] != 'a';}); LocalIDMapper map(keep_filter); vector<string> filtered_names = keep_element_of_vector_if(keep_filter, names); // Mapping back to check correctness for(unsigned i=0; i<names.size(); ++i){ if(keep_filter.is_set(i)) assert(filtered_names[map.to_local(i)] == names[i]); }Convert an adjacency-array to an arc-list
masterYou can convert an adjacency-array back to an arc-list using functions from the
<routingkit/inverse_vector.h>header. This is useful when you need to access arcs by their ID rather than traversing via nodes.unsigned node_count = first_out.size()-1; auto tail = invert_inverse_vector(first_out);Extract a car routing graph using standard profiles
masterRoutingKit provides out-of-the-box functions in
<routingkit/osm_profile.h>to interpret OSM tags specifically for car routing. This avoids manual tag parsing.Phase 1 (ID Mapping)
Use
is_osm_way_used_by_carsto determine if a way should be included in the graph.Phase 2 (Graph Decoding)
Use the following functions within your callbacks:
get_osm_way_speed: Returns speed in km/h.get_osm_way_name: Returns the name of the way.get_osm_car_direction_category: Determines directionality (OSMWayDirectionCategory).decode_osm_car_turn_restrictions: Processes turn restrictions within theturn_restriction_classifiercallback.
// In Phase 1 callback: bool used = is_osm_way_used_by_cars(osm_way_id, tags); // In Phase 2 oneway_classifier: OSMWayDirectionCategory dir = get_osm_car_direction_category(osm_way_id, tags); // In Phase 2 turn_restriction_classifier: decode_osm_car_turn_restrictions(osm_relation_id, member_list, tags, on_new_turn_restriction, log_message);Install dependencies for RoutingKit
masterRoutingKit requires
zlibto function. On Debian-based distributions like Ubuntu, you can install the necessary development headers usingapt-get.sudo apt-get install zlib1g-dev