@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.
Files changed (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +149 -0
  3. package/dist/src/algorithms/bidirectional.d.ts +19 -0
  4. package/dist/src/algorithms/bidirectional.d.ts.map +1 -0
  5. package/dist/src/algorithms/bidirectional.js +128 -0
  6. package/dist/src/algorithms/bidirectional.js.map +1 -0
  7. package/dist/src/algorithms/index.d.ts +17 -0
  8. package/dist/src/algorithms/index.d.ts.map +1 -0
  9. package/dist/src/algorithms/index.js +19 -0
  10. package/dist/src/algorithms/index.js.map +1 -0
  11. package/dist/src/algorithms/shortest-path.d.ts +24 -0
  12. package/dist/src/algorithms/shortest-path.d.ts.map +1 -0
  13. package/dist/src/algorithms/shortest-path.js +115 -0
  14. package/dist/src/algorithms/shortest-path.js.map +1 -0
  15. package/dist/src/binary-heap.d.ts +40 -0
  16. package/dist/src/binary-heap.d.ts.map +1 -0
  17. package/dist/src/binary-heap.js +122 -0
  18. package/dist/src/binary-heap.js.map +1 -0
  19. package/dist/src/graph.d.ts +135 -0
  20. package/dist/src/graph.d.ts.map +1 -0
  21. package/dist/src/graph.js +339 -0
  22. package/dist/src/graph.js.map +1 -0
  23. package/dist/src/index.d.ts +41 -0
  24. package/dist/src/index.d.ts.map +1 -0
  25. package/dist/src/index.js +41 -0
  26. package/dist/src/index.js.map +1 -0
  27. package/dist/src/router.d.ts +55 -0
  28. package/dist/src/router.d.ts.map +1 -0
  29. package/dist/src/router.js +189 -0
  30. package/dist/src/router.js.map +1 -0
  31. package/dist/src/types.d.ts +118 -0
  32. package/dist/src/types.d.ts.map +1 -0
  33. package/dist/src/types.js +5 -0
  34. package/dist/src/types.js.map +1 -0
  35. package/dist/src/utils.d.ts +20 -0
  36. package/dist/src/utils.d.ts.map +1 -0
  37. package/dist/src/utils.js +101 -0
  38. package/dist/src/utils.js.map +1 -0
  39. package/dist/test/algorithms.test.d.ts +2 -0
  40. package/dist/test/algorithms.test.d.ts.map +1 -0
  41. package/dist/test/algorithms.test.js +382 -0
  42. package/dist/test/algorithms.test.js.map +1 -0
  43. package/dist/test/router.bench.d.ts +2 -0
  44. package/dist/test/router.bench.d.ts.map +1 -0
  45. package/dist/test/router.bench.js +191 -0
  46. package/dist/test/router.bench.js.map +1 -0
  47. package/dist/test/router.test.d.ts +2 -0
  48. package/dist/test/router.test.d.ts.map +1 -0
  49. package/dist/test/router.test.js +515 -0
  50. package/dist/test/router.test.js.map +1 -0
  51. package/package.json +51 -0
  52. package/src/algorithms/bidirectional.ts +147 -0
  53. package/src/algorithms/index.ts +23 -0
  54. package/src/algorithms/shortest-path.ts +149 -0
  55. package/src/binary-heap.ts +147 -0
  56. package/src/graph.ts +414 -0
  57. package/src/index.ts +41 -0
  58. package/src/router.ts +262 -0
  59. package/src/types.ts +138 -0
  60. package/src/utils.ts +114 -0
  61. package/test/algorithms.test.ts +466 -0
  62. package/test/router.bench.ts +257 -0
  63. package/test/router.test.ts +738 -0
  64. 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
+ }