@osmix/router 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +149 -0
- package/dist/src/algorithms/bidirectional.d.ts +19 -0
- package/dist/src/algorithms/bidirectional.d.ts.map +1 -0
- package/dist/src/algorithms/bidirectional.js +128 -0
- package/dist/src/algorithms/bidirectional.js.map +1 -0
- package/dist/src/algorithms/index.d.ts +17 -0
- package/dist/src/algorithms/index.d.ts.map +1 -0
- package/dist/src/algorithms/index.js +19 -0
- package/dist/src/algorithms/index.js.map +1 -0
- package/dist/src/algorithms/shortest-path.d.ts +24 -0
- package/dist/src/algorithms/shortest-path.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path.js +115 -0
- package/dist/src/algorithms/shortest-path.js.map +1 -0
- package/dist/src/binary-heap.d.ts +40 -0
- package/dist/src/binary-heap.d.ts.map +1 -0
- package/dist/src/binary-heap.js +122 -0
- package/dist/src/binary-heap.js.map +1 -0
- package/dist/src/graph.d.ts +135 -0
- package/dist/src/graph.d.ts.map +1 -0
- package/dist/src/graph.js +339 -0
- package/dist/src/graph.js.map +1 -0
- package/dist/src/index.d.ts +41 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +41 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/router.d.ts +55 -0
- package/dist/src/router.d.ts.map +1 -0
- package/dist/src/router.js +189 -0
- package/dist/src/router.js.map +1 -0
- package/dist/src/types.d.ts +118 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +20 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +101 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/test/algorithms.test.d.ts +2 -0
- package/dist/test/algorithms.test.d.ts.map +1 -0
- package/dist/test/algorithms.test.js +382 -0
- package/dist/test/algorithms.test.js.map +1 -0
- package/dist/test/router.bench.d.ts +2 -0
- package/dist/test/router.bench.d.ts.map +1 -0
- package/dist/test/router.bench.js +191 -0
- package/dist/test/router.bench.js.map +1 -0
- package/dist/test/router.test.d.ts +2 -0
- package/dist/test/router.test.d.ts.map +1 -0
- package/dist/test/router.test.js +515 -0
- package/dist/test/router.test.js.map +1 -0
- package/package.json +51 -0
- package/src/algorithms/bidirectional.ts +147 -0
- package/src/algorithms/index.ts +23 -0
- package/src/algorithms/shortest-path.ts +149 -0
- package/src/binary-heap.ts +147 -0
- package/src/graph.ts +414 -0
- package/src/index.ts +41 -0
- package/src/router.ts +262 -0
- package/src/types.ts +138 -0
- package/src/utils.ts +114 -0
- package/test/algorithms.test.ts +466 -0
- package/test/router.bench.ts +257 -0
- package/test/router.test.ts +738 -0
- package/tsconfig.json +9 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the routing module.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { BufferType } from "@osmix/core"
|
|
7
|
+
import type { LonLat, OsmTags } from "@osmix/shared/types"
|
|
8
|
+
|
|
9
|
+
/** Per-way segment with distance and time (consecutive same-name ways merged). */
|
|
10
|
+
export interface WaySegment {
|
|
11
|
+
/** OSM way IDs included in this segment (multiple if merged). */
|
|
12
|
+
wayIds: number[]
|
|
13
|
+
/** Way name from tags (may be empty). */
|
|
14
|
+
name: string
|
|
15
|
+
/** Highway type from tags. */
|
|
16
|
+
highway: string
|
|
17
|
+
/** Distance travelled on this segment in meters. */
|
|
18
|
+
distance: number
|
|
19
|
+
/** Time travelled on this segment in seconds. */
|
|
20
|
+
time: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Route statistics (distance and time). */
|
|
24
|
+
export interface RouteStatistics {
|
|
25
|
+
/** Total route distance in meters. */
|
|
26
|
+
distance: number
|
|
27
|
+
/** Total route time in seconds. */
|
|
28
|
+
time: number
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Route path info (segments and turn points). */
|
|
32
|
+
export interface RoutePathInfo {
|
|
33
|
+
/** Per-way breakdown (consecutive same-name ways merged). */
|
|
34
|
+
segments: WaySegment[]
|
|
35
|
+
/** Coordinates where way name changes (turn points). */
|
|
36
|
+
turnPoints: LonLat[]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Route result containing the path geometry and metadata. */
|
|
40
|
+
export interface RouteResult {
|
|
41
|
+
/** Coordinates along the route. */
|
|
42
|
+
coordinates: LonLat[]
|
|
43
|
+
/** Way indexes traversed, in order. */
|
|
44
|
+
wayIndexes: number[]
|
|
45
|
+
/** Node indexes at turns and intersections. */
|
|
46
|
+
nodeIndexes: number[]
|
|
47
|
+
/** Total route distance in meters (when includeStats is true). */
|
|
48
|
+
distance?: number
|
|
49
|
+
/** Total route time in seconds (when includeStats is true). */
|
|
50
|
+
time?: number
|
|
51
|
+
/** Per-way breakdown (when includePathInfo is true). */
|
|
52
|
+
segments?: WaySegment[]
|
|
53
|
+
/** Coordinates where way name changes (when includePathInfo is true). */
|
|
54
|
+
turnPoints?: LonLat[]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Filter function to determine which highways are routable. Default: common vehicle highways. */
|
|
58
|
+
export type HighwayFilter = (tags?: OsmTags) => boolean
|
|
59
|
+
|
|
60
|
+
/** Available routing algorithms. */
|
|
61
|
+
export type RoutingAlgorithm = "dijkstra" | "astar" | "bidirectional"
|
|
62
|
+
|
|
63
|
+
/** Routing metric to optimize. */
|
|
64
|
+
export type RoutingMetric = "distance" | "time"
|
|
65
|
+
|
|
66
|
+
/** Speed limits by highway type (km/h). */
|
|
67
|
+
export type DefaultSpeeds = Record<string, number>
|
|
68
|
+
|
|
69
|
+
/** Router configuration options. */
|
|
70
|
+
export interface RouteOptions {
|
|
71
|
+
/** Routing algorithm. Default: "astar". */
|
|
72
|
+
algorithm: RoutingAlgorithm
|
|
73
|
+
/** Optimization metric. Default: "distance". */
|
|
74
|
+
metric: RoutingMetric
|
|
75
|
+
/** Include distance and time in result. Default: false. */
|
|
76
|
+
includeStats?: boolean
|
|
77
|
+
/** Include segments and turnPoints in result. Default: false. */
|
|
78
|
+
includePathInfo?: boolean
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Edge in the routing graph. */
|
|
82
|
+
export interface GraphEdge {
|
|
83
|
+
/** Target node index. */
|
|
84
|
+
targetNodeIndex: number
|
|
85
|
+
/** Way index this edge belongs to. */
|
|
86
|
+
wayIndex: number
|
|
87
|
+
/** Distance in meters. */
|
|
88
|
+
distance: number
|
|
89
|
+
/** Travel time in seconds. */
|
|
90
|
+
time: number
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Serializable representation of a RoutingGraph for worker transfer.
|
|
95
|
+
* Uses CSR (Compressed Sparse Row) format for efficient storage and zero-copy transfer.
|
|
96
|
+
*/
|
|
97
|
+
export interface RoutingGraphTransferables {
|
|
98
|
+
/** Total number of nodes in the graph. */
|
|
99
|
+
nodeCount: number
|
|
100
|
+
/** Total number of edges in the graph. */
|
|
101
|
+
edgeCount: number
|
|
102
|
+
/** CSR offsets: edges for node i are at indices [edgeOffsets[i], edgeOffsets[i+1]) */
|
|
103
|
+
edgeOffsets: BufferType
|
|
104
|
+
/** Target node index for each edge. */
|
|
105
|
+
edgeTargets: BufferType
|
|
106
|
+
/** Way index for each edge. */
|
|
107
|
+
edgeWayIndexes: BufferType
|
|
108
|
+
/** Distance in meters for each edge. */
|
|
109
|
+
edgeDistances: BufferType
|
|
110
|
+
/** Travel time in seconds for each edge. */
|
|
111
|
+
edgeTimes: BufferType
|
|
112
|
+
/** Bitset: 1 bit per node indicating if routable. */
|
|
113
|
+
routableBits: BufferType
|
|
114
|
+
/** Bitset: 1 bit per node indicating if intersection. */
|
|
115
|
+
intersectionBits: BufferType
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Path segment returned by routing algorithms. */
|
|
119
|
+
export interface PathSegment {
|
|
120
|
+
/** Node index. */
|
|
121
|
+
nodeIndex: number
|
|
122
|
+
/** Way index used to reach this node. */
|
|
123
|
+
wayIndex?: number
|
|
124
|
+
/** Previous node in path. */
|
|
125
|
+
previousNodeIndex?: number
|
|
126
|
+
/** Cost to reach this node. */
|
|
127
|
+
cost: number
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Function signature for routing algorithms. */
|
|
131
|
+
export type RoutingAlgorithmFn = (
|
|
132
|
+
graph: (nodeIndex: number) => GraphEdge[],
|
|
133
|
+
startNodeIndex: number,
|
|
134
|
+
endNodeIndex: number,
|
|
135
|
+
getEdgeWeight: (edge: GraphEdge) => number,
|
|
136
|
+
getNodeCoord?: (nodeIndex: number) => LonLat | undefined,
|
|
137
|
+
metric?: RoutingMetric,
|
|
138
|
+
) => PathSegment[] | null
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routing utility functions.
|
|
3
|
+
*
|
|
4
|
+
* Provides highway filtering, speed limit parsing, and travel time calculation.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { OsmTags } from "@osmix/shared/types"
|
|
10
|
+
import type { DefaultSpeeds } from "./types"
|
|
11
|
+
|
|
12
|
+
/** Default speeds (km/h) by highway type. */
|
|
13
|
+
export const DEFAULT_SPEEDS: DefaultSpeeds = {
|
|
14
|
+
motorway: 120,
|
|
15
|
+
motorway_link: 60,
|
|
16
|
+
trunk: 100,
|
|
17
|
+
trunk_link: 50,
|
|
18
|
+
primary: 80,
|
|
19
|
+
primary_link: 50,
|
|
20
|
+
secondary: 70,
|
|
21
|
+
secondary_link: 50,
|
|
22
|
+
tertiary: 60,
|
|
23
|
+
tertiary_link: 50,
|
|
24
|
+
unclassified: 50,
|
|
25
|
+
residential: 30,
|
|
26
|
+
living_street: 20,
|
|
27
|
+
service: 20,
|
|
28
|
+
footway: 5,
|
|
29
|
+
path: 5,
|
|
30
|
+
cycleway: 20,
|
|
31
|
+
bridleway: 10,
|
|
32
|
+
steps: 2,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Highways included in default vehicle routing. */
|
|
36
|
+
const VEHICLE_HIGHWAYS = new Set([
|
|
37
|
+
"motorway",
|
|
38
|
+
"motorway_link",
|
|
39
|
+
"trunk",
|
|
40
|
+
"trunk_link",
|
|
41
|
+
"primary",
|
|
42
|
+
"primary_link",
|
|
43
|
+
"secondary",
|
|
44
|
+
"secondary_link",
|
|
45
|
+
"tertiary",
|
|
46
|
+
"tertiary_link",
|
|
47
|
+
"unclassified",
|
|
48
|
+
"residential",
|
|
49
|
+
"living_street",
|
|
50
|
+
"service",
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
/** Footways included in default pedestrian routing. */
|
|
54
|
+
const FOOT_HIGHWAYS = new Set([
|
|
55
|
+
"footway",
|
|
56
|
+
"path",
|
|
57
|
+
"cycleway",
|
|
58
|
+
"bridleway",
|
|
59
|
+
"steps",
|
|
60
|
+
])
|
|
61
|
+
|
|
62
|
+
/** Parse maxspeed tag to km/h. Handles "50", "50 km/h", "30 mph". */
|
|
63
|
+
export function parseMaxSpeed(
|
|
64
|
+
value: string | number | undefined,
|
|
65
|
+
): number | null {
|
|
66
|
+
if (!value) return null
|
|
67
|
+
|
|
68
|
+
const str = String(value).trim().toLowerCase()
|
|
69
|
+
|
|
70
|
+
// Numeric: assume km/h
|
|
71
|
+
const numeric = str.match(/^(\d+)$/)
|
|
72
|
+
if (numeric) return Number.parseInt(numeric[1]!, 10)
|
|
73
|
+
|
|
74
|
+
// Explicit km/h
|
|
75
|
+
const kmh = str.match(/^(\d+)\s*(km\/h|kmh|kph)$/)
|
|
76
|
+
if (kmh) return Number.parseInt(kmh[1]!, 10)
|
|
77
|
+
|
|
78
|
+
// MPH -> km/h
|
|
79
|
+
const mph = str.match(/^(\d+)\s*mph$/)
|
|
80
|
+
if (mph) return Math.round(Number.parseInt(mph[1]!, 10) * 1.60934)
|
|
81
|
+
|
|
82
|
+
// Special values
|
|
83
|
+
if (str === "walk" || str === "none") return 5
|
|
84
|
+
|
|
85
|
+
return null
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Get speed limit (km/h) for a way. */
|
|
89
|
+
export function getSpeedLimit(
|
|
90
|
+
tags: OsmTags | undefined,
|
|
91
|
+
defaultSpeeds: DefaultSpeeds = DEFAULT_SPEEDS,
|
|
92
|
+
): number {
|
|
93
|
+
if (tags?.["maxspeed"]) {
|
|
94
|
+
const parsed = parseMaxSpeed(tags["maxspeed"])
|
|
95
|
+
if (parsed !== null) return parsed
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const highway = tags?.["highway"] ? String(tags["highway"]) : undefined
|
|
99
|
+
if (highway && defaultSpeeds[highway]) return defaultSpeeds[highway]!
|
|
100
|
+
|
|
101
|
+
return 50
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Default filter: common vehicle highways. */
|
|
105
|
+
export function defaultHighwayFilter(tags?: OsmTags): boolean {
|
|
106
|
+
if (!tags?.["highway"]) return false
|
|
107
|
+
return VEHICLE_HIGHWAYS.has(String(tags["highway"]))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Default pedestrian filter */
|
|
111
|
+
export function defaultPedestrianFilter(tags?: OsmTags): boolean {
|
|
112
|
+
if (!tags?.["highway"]) return false
|
|
113
|
+
return FOOT_HIGHWAYS.has(String(tags["highway"]))
|
|
114
|
+
}
|