@ingissa/navcore-react-native 1.0.8 → 1.0.9

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 (123) hide show
  1. package/dist/index.d.mts +131 -0
  2. package/dist/index.d.ts +131 -0
  3. package/dist/index.js +233 -0
  4. package/dist/index.mjs +223 -0
  5. package/package.json +7 -15
  6. package/dist/core/src/NavCore.d.ts +0 -142
  7. package/dist/core/src/NavCore.d.ts.map +0 -1
  8. package/dist/core/src/NavCore.js +0 -390
  9. package/dist/core/src/bearing/BearingEngine.d.ts +0 -24
  10. package/dist/core/src/bearing/BearingEngine.d.ts.map +0 -1
  11. package/dist/core/src/bearing/BearingEngine.js +0 -50
  12. package/dist/core/src/constants.d.ts +0 -34
  13. package/dist/core/src/constants.d.ts.map +0 -1
  14. package/dist/core/src/constants.js +0 -41
  15. package/dist/core/src/corridor/DeviationDetector.d.ts +0 -33
  16. package/dist/core/src/corridor/DeviationDetector.d.ts.map +0 -1
  17. package/dist/core/src/corridor/DeviationDetector.js +0 -83
  18. package/dist/core/src/corridor/DynamicCorridor.d.ts +0 -13
  19. package/dist/core/src/corridor/DynamicCorridor.d.ts.map +0 -1
  20. package/dist/core/src/corridor/DynamicCorridor.js +0 -26
  21. package/dist/core/src/dead-reckoning/DeadReckoning.d.ts +0 -35
  22. package/dist/core/src/dead-reckoning/DeadReckoning.d.ts.map +0 -1
  23. package/dist/core/src/dead-reckoning/DeadReckoning.js +0 -49
  24. package/dist/core/src/directions/DirectionsProvider.d.ts +0 -70
  25. package/dist/core/src/directions/DirectionsProvider.d.ts.map +0 -1
  26. package/dist/core/src/directions/DirectionsProvider.js +0 -7
  27. package/dist/core/src/directions/OSRMDirectionsProvider.d.ts +0 -26
  28. package/dist/core/src/directions/OSRMDirectionsProvider.d.ts.map +0 -1
  29. package/dist/core/src/directions/OSRMDirectionsProvider.js +0 -90
  30. package/dist/core/src/directions/OpenRouteServiceProvider.d.ts +0 -30
  31. package/dist/core/src/directions/OpenRouteServiceProvider.d.ts.map +0 -1
  32. package/dist/core/src/directions/OpenRouteServiceProvider.js +0 -111
  33. package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts +0 -33
  34. package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts.map +0 -1
  35. package/dist/core/src/directions/ValhallaDirectionsProvider.js +0 -155
  36. package/dist/core/src/eta/ETAEngine.d.ts +0 -61
  37. package/dist/core/src/eta/ETAEngine.d.ts.map +0 -1
  38. package/dist/core/src/eta/ETAEngine.js +0 -74
  39. package/dist/core/src/features.d.ts +0 -76
  40. package/dist/core/src/features.d.ts.map +0 -1
  41. package/dist/core/src/features.js +0 -76
  42. package/dist/core/src/geo/bearing.d.ts +0 -11
  43. package/dist/core/src/geo/bearing.d.ts.map +0 -1
  44. package/dist/core/src/geo/bearing.js +0 -25
  45. package/dist/core/src/geo/cumulative.d.ts +0 -9
  46. package/dist/core/src/geo/cumulative.d.ts.map +0 -1
  47. package/dist/core/src/geo/cumulative.js +0 -20
  48. package/dist/core/src/geo/haversine.d.ts +0 -13
  49. package/dist/core/src/geo/haversine.d.ts.map +0 -1
  50. package/dist/core/src/geo/haversine.js +0 -39
  51. package/dist/core/src/geo/projection.d.ts +0 -7
  52. package/dist/core/src/geo/projection.d.ts.map +0 -1
  53. package/dist/core/src/geo/projection.js +0 -17
  54. package/dist/core/src/geofencing/GeofencingEngine.d.ts +0 -93
  55. package/dist/core/src/geofencing/GeofencingEngine.d.ts.map +0 -1
  56. package/dist/core/src/geofencing/GeofencingEngine.js +0 -154
  57. package/dist/core/src/index.d.ts +0 -66
  58. package/dist/core/src/index.d.ts.map +0 -1
  59. package/dist/core/src/index.js +0 -62
  60. package/dist/core/src/kalman/KalmanFilter2D.d.ts +0 -46
  61. package/dist/core/src/kalman/KalmanFilter2D.d.ts.map +0 -1
  62. package/dist/core/src/kalman/KalmanFilter2D.js +0 -77
  63. package/dist/core/src/license/LicenseManager.d.ts +0 -40
  64. package/dist/core/src/license/LicenseManager.d.ts.map +0 -1
  65. package/dist/core/src/license/LicenseManager.js +0 -119
  66. package/dist/core/src/license/verifyP256Signature.d.ts +0 -2
  67. package/dist/core/src/license/verifyP256Signature.d.ts.map +0 -1
  68. package/dist/core/src/license/verifyP256Signature.js +0 -26
  69. package/dist/core/src/off-route/NavigationFSM.d.ts +0 -42
  70. package/dist/core/src/off-route/NavigationFSM.d.ts.map +0 -1
  71. package/dist/core/src/off-route/NavigationFSM.js +0 -56
  72. package/dist/core/src/off-route/OffRouteFSM.d.ts +0 -70
  73. package/dist/core/src/off-route/OffRouteFSM.d.ts.map +0 -1
  74. package/dist/core/src/off-route/OffRouteFSM.js +0 -151
  75. package/dist/core/src/predictor/RouteOffsetPredictor.d.ts +0 -24
  76. package/dist/core/src/predictor/RouteOffsetPredictor.d.ts.map +0 -1
  77. package/dist/core/src/predictor/RouteOffsetPredictor.js +0 -55
  78. package/dist/core/src/progress/InstructionEditor.d.ts +0 -77
  79. package/dist/core/src/progress/InstructionEditor.d.ts.map +0 -1
  80. package/dist/core/src/progress/InstructionEditor.js +0 -151
  81. package/dist/core/src/progress/InstructionResolver.d.ts +0 -25
  82. package/dist/core/src/progress/InstructionResolver.d.ts.map +0 -1
  83. package/dist/core/src/progress/InstructionResolver.js +0 -78
  84. package/dist/core/src/progress/ProgressTracker.d.ts +0 -12
  85. package/dist/core/src/progress/ProgressTracker.d.ts.map +0 -1
  86. package/dist/core/src/progress/ProgressTracker.js +0 -22
  87. package/dist/core/src/renderer/MapRendererAdapter.d.ts +0 -72
  88. package/dist/core/src/renderer/MapRendererAdapter.d.ts.map +0 -1
  89. package/dist/core/src/renderer/MapRendererAdapter.js +0 -19
  90. package/dist/core/src/route-builder/CustomRouteBuilder.d.ts +0 -83
  91. package/dist/core/src/route-builder/CustomRouteBuilder.d.ts.map +0 -1
  92. package/dist/core/src/route-builder/CustomRouteBuilder.js +0 -160
  93. package/dist/core/src/route-plan/RoutePlan.d.ts +0 -38
  94. package/dist/core/src/route-plan/RoutePlan.d.ts.map +0 -1
  95. package/dist/core/src/route-plan/RoutePlan.js +0 -102
  96. package/dist/core/src/session/NavigationSession.d.ts +0 -81
  97. package/dist/core/src/session/NavigationSession.d.ts.map +0 -1
  98. package/dist/core/src/session/NavigationSession.js +0 -115
  99. package/dist/core/src/snapper/ParallelRoadResolver.d.ts +0 -86
  100. package/dist/core/src/snapper/ParallelRoadResolver.d.ts.map +0 -1
  101. package/dist/core/src/snapper/ParallelRoadResolver.js +0 -83
  102. package/dist/core/src/snapper/RouteSnapper.d.ts +0 -38
  103. package/dist/core/src/snapper/RouteSnapper.d.ts.map +0 -1
  104. package/dist/core/src/snapper/RouteSnapper.js +0 -80
  105. package/dist/core/src/voice/VoiceTriggerEngine.d.ts +0 -80
  106. package/dist/core/src/voice/VoiceTriggerEngine.d.ts.map +0 -1
  107. package/dist/core/src/voice/VoiceTriggerEngine.js +0 -108
  108. package/dist/react-native/src/NavCoreProvider.d.ts +0 -33
  109. package/dist/react-native/src/NavCoreProvider.d.ts.map +0 -1
  110. package/dist/react-native/src/NavCoreProvider.js +0 -41
  111. package/dist/react-native/src/index.d.ts +0 -10
  112. package/dist/react-native/src/index.d.ts.map +0 -1
  113. package/dist/react-native/src/index.js +0 -8
  114. package/dist/react-native/src/useNavCore.d.ts +0 -60
  115. package/dist/react-native/src/useNavCore.d.ts.map +0 -1
  116. package/dist/react-native/src/useNavCore.js +0 -119
  117. package/dist/react-native/src/useNavSelectors.d.ts +0 -42
  118. package/dist/react-native/src/useNavSelectors.d.ts.map +0 -1
  119. package/dist/react-native/src/useNavSelectors.js +0 -103
  120. package/src/NavCoreProvider.tsx +0 -59
  121. package/src/index.ts +0 -18
  122. package/src/useNavCore.ts +0 -208
  123. package/src/useNavSelectors.ts +0 -143
@@ -1,390 +0,0 @@
1
- /**
2
- * NavCore — Main Orchestrator
3
- *
4
- * Fuses all extracted modules into a single engine class.
5
- * Framework-agnostic; license verification does not require platform crypto APIs.
6
- *
7
- * Usage:
8
- * const engine = new NavCore({ licenseKey: '...' });
9
- * engine.setRoute(routeCoords, instructions);
10
- * engine.update(gpsUpdate);
11
- * const state = engine.getState();
12
- */
13
- import { haversineDistance } from './geo/haversine';
14
- import { buildForwardCumulativeDistances, buildReverseCumulativeDistances } from './geo/cumulative';
15
- import { KalmanFilter2D } from './kalman/KalmanFilter2D';
16
- import { RouteSnapper } from './snapper/RouteSnapper';
17
- import { DeadReckoningEngine } from './dead-reckoning/DeadReckoning';
18
- import { calculateDynamicCorridor } from './corridor/DynamicCorridor';
19
- import { DeviationDetector, findClosestSegment } from './corridor/DeviationDetector';
20
- import { applyBearingSmoothing } from './bearing/BearingEngine';
21
- import { validateProgressUpdate } from './progress/ProgressTracker';
22
- import { resolveNextInstruction } from './progress/InstructionResolver';
23
- import { advancePredictor, applyGpsCorrection } from './predictor/RouteOffsetPredictor';
24
- import { NavigationFSM } from './off-route/NavigationFSM';
25
- import { OffRouteFSM } from './off-route/OffRouteFSM';
26
- import { LicenseManager } from './license/LicenseManager';
27
- import * as C from './constants';
28
- import { FEATURES } from './features';
29
- // ── NavCore class ─────────────────────────────────────────────
30
- export class NavCore {
31
- constructor(options) {
32
- // ── Route data ───────────────────────────────────────────────
33
- this.route = [];
34
- this.instructions = [];
35
- this.forwardCum = new Float64Array(0);
36
- this.reverseCum = new Float64Array(0);
37
- // ── State ────────────────────────────────────────────────────
38
- this.snappedCoord = null;
39
- this.ghostCoord = null;
40
- this.rawGpsCoord = null;
41
- this.bearing = 0;
42
- this.rawGpsBearing = null;
43
- this.routeIndex = 0;
44
- this.maxProgressIdx = 0;
45
- this.prevSegment = null;
46
- this.distanceToRoute = 0;
47
- this.corridor = C.BASE_CORRIDOR_METERS;
48
- this.prevDistToNext = null;
49
- this.currentSpeed = 0;
50
- this.lastGpsTimestamp = 0;
51
- this.instrIdx = 0;
52
- this.linearOffset = 0;
53
- this.hasArrived = false;
54
- // ── Events ───────────────────────────────────────────────────
55
- this.listeners = new Map();
56
- this.options = {
57
- licenseKey: options?.licenseKey ?? '',
58
- isDev: options?.isDev ?? false,
59
- isCircuit: options?.isCircuit ?? false,
60
- kalmanQ: options?.kalmanQ ?? 0.00001,
61
- kalmanRBase: options?.kalmanRBase ?? 0.00005,
62
- baseCorridorMeters: options?.baseCorridorMeters ?? C.BASE_CORRIDOR_METERS,
63
- maxCorridorMeters: options?.maxCorridorMeters ?? C.MAX_CORRIDOR_METERS,
64
- arrivalThresholdMeters: options?.arrivalThresholdMeters ?? C.ARRIVAL_THRESHOLD_METERS,
65
- bearingSmoothingAlpha: options?.bearingSmoothingAlpha ?? C.BEARING_SMOOTHING_ALPHA,
66
- };
67
- this.kalman = new KalmanFilter2D(this.options.kalmanQ, this.options.kalmanRBase);
68
- this.snapper = new RouteSnapper({ useBearingPenalty: true, useInertiaPenalty: true });
69
- this.deadReckoning = new DeadReckoningEngine();
70
- this.deviationDetector = new DeviationDetector();
71
- this.lifecycleFSM = new NavigationFSM();
72
- this.offRouteFSM = new OffRouteFSM();
73
- this.license = new LicenseManager(this.options.licenseKey, this.options.isDev);
74
- }
75
- // ── License gate helper ──────────────────────────────────────
76
- /**
77
- * Returns true if the feature is unlocked (dev mode OR valid license).
78
- * Emits a one-time console warning when a Pro feature is blocked.
79
- */
80
- has(feature) {
81
- const ok = this.license.hasFeature(feature);
82
- if (!ok)
83
- this.license.warnOnce(feature);
84
- return ok;
85
- }
86
- // ── Public API ───────────────────────────────────────────────
87
- /** Load route geometry and instructions */
88
- setRoute(route, instructions) {
89
- // Keep engine state isolated from consumer-owned provider responses.
90
- this.route = route.map((coord) => [coord[0], coord[1]]);
91
- this.instructions = (instructions ?? []).map((instruction) => ({
92
- ...instruction,
93
- location: [instruction.location[0], instruction.location[1]],
94
- }));
95
- this.forwardCum = buildForwardCumulativeDistances(this.route);
96
- this.reverseCum = buildReverseCumulativeDistances(this.route);
97
- this.routeIndex = 0;
98
- this.maxProgressIdx = 0;
99
- this.prevSegment = null;
100
- this.instrIdx = 0;
101
- this.linearOffset = 0;
102
- this.hasArrived = false;
103
- this.snappedCoord = null;
104
- this.prevDistToNext = null;
105
- this.lifecycleFSM.dispatch({ type: 'ROUTE_LOADED' });
106
- // Auto-fill missing cumulative offsets for instructions
107
- for (const instr of this.instructions) {
108
- if (instr.cumulativeOffset === undefined && instr.geometryIndex < this.forwardCum.length) {
109
- instr.cumulativeOffset = this.forwardCum[instr.geometryIndex];
110
- }
111
- }
112
- this.emit('routeLoaded', { routeLength: this.route.length });
113
- }
114
- /** Load a provider-normalized route plan without exposing mutable route state. */
115
- loadRoute(plan) {
116
- this.setRoute(plan.geometry, plan.instructions);
117
- }
118
- /** Start navigation */
119
- startNavigation() {
120
- this.lifecycleFSM.dispatch({ type: 'USER_START_NAVIGATION' });
121
- this.emit('navigationStarted');
122
- }
123
- /** Process a GPS update — the main engine tick */
124
- update(gps) {
125
- this.rawGpsCoord = gps.coord;
126
- this.rawGpsBearing = gps.bearing;
127
- this.currentSpeed = gps.speed;
128
- this.lastGpsTimestamp = gps.timestamp;
129
- if (this.route.length < 2)
130
- return this.getState();
131
- // 1. Kalman filter
132
- const [filteredLng, filteredLat] = this.kalman.update(gps.coord[0], gps.coord[1], gps.accuracy ?? 10, gps.timestamp);
133
- const filteredCoord = [filteredLng, filteredLat];
134
- // 2. Snap to route
135
- const startIdx = Math.max(0, this.routeIndex - 2);
136
- const snap = this.snapper.snap(filteredCoord, this.route, startIdx, C.SNAP_WINDOW_SIZE, this.options.isCircuit, this.maxProgressIdx, this.routeIndex, gps.bearing, this.prevSegment);
137
- this.ghostCoord = snap.proj;
138
- // Look ahead to upcoming maneuver for dynamic corridor widening
139
- let distToUpcomingManeuver = null;
140
- if (this.instructions.length > 0 && this.instrIdx < this.instructions.length) {
141
- const upcoming = this.instructions[this.instrIdx];
142
- distToUpcomingManeuver = upcoming.cumulativeOffset !== undefined
143
- ? Math.max(0, upcoming.cumulativeOffset - this.linearOffset)
144
- : haversineDistance(filteredCoord[1], filteredCoord[0], upcoming.location[1], upcoming.location[0]);
145
- }
146
- // 3. Dynamic corridor
147
- this.corridor = calculateDynamicCorridor(gps.speed, gps.accuracy, this.options.baseCorridorMeters, this.options.maxCorridorMeters, C.SPEED_CORRIDOR_FACTOR, C.GPS_ACCURACY_FACTOR, distToUpcomingManeuver);
148
- // 4. Progress validation
149
- const validatedIdx = validateProgressUpdate(this.routeIndex, snap.idx, this.route, snap.dist, C.MAX_SNAP_DISTANCE);
150
- this.prevSegment = this.routeIndex;
151
- this.routeIndex = validatedIdx;
152
- this.maxProgressIdx = Math.max(this.maxProgressIdx, validatedIdx);
153
- this.snappedCoord = snap.proj;
154
- this.distanceToRoute = snap.dist;
155
- // 5. Linear offset update
156
- if (this.forwardCum.length > validatedIdx) {
157
- const measuredOffset = this.forwardCum[validatedIdx] ?? 0;
158
- this.linearOffset = applyGpsCorrection(this.linearOffset, measuredOffset, C.BETA_CORRECTION);
159
- }
160
- // 6. Bearing smoothing (PRO: ADVANCED_BEARING)
161
- if (this.has(FEATURES.ADVANCED_BEARING)) {
162
- this.bearing = applyBearingSmoothing(this.bearing, this.route, this.routeIndex, gps.speed, gps.bearing, this.options.bearingSmoothingAlpha);
163
- }
164
- else if (gps.bearing !== null) {
165
- this.bearing = gps.bearing;
166
- }
167
- // 7. Deviation detection & Route Rejoin Handling
168
- const isProDeviation = this.has(FEATURES.COMPOUND_DEVIATION);
169
- if (this.offRouteFSM.state === 'ON_ROUTE' || this.offRouteFSM.state === 'DEVIATING') {
170
- if (isProDeviation) {
171
- const closest = findClosestSegment(filteredCoord, this.route, startIdx, C.SNAP_WINDOW_SIZE);
172
- const signals = this.deviationDetector.evaluate(filteredCoord, gps.bearing, gps.speed, closest, this.route, this.corridor, this.prevDistToNext);
173
- // Update moving-away tracker
174
- if (closest.segmentIndex < this.route.length - 1) {
175
- const nextEnd = this.route[Math.min(closest.segmentIndex + 2, this.route.length - 1)];
176
- this.prevDistToNext = haversineDistance(filteredCoord[1], filteredCoord[0], nextEnd[1], nextEnd[0]);
177
- }
178
- if (signals.confirmed) {
179
- if (this.offRouteFSM.state === 'ON_ROUTE') {
180
- this.offRouteFSM.dispatch({
181
- type: 'DEVIATION_SUSPECTED',
182
- deviationSegmentIdx: closest.segmentIndex
183
- });
184
- }
185
- else if (this.offRouteFSM.isDeviationConfirmed()) {
186
- this.offRouteFSM.dispatch({
187
- type: 'DEVIATION_CONFIRMED',
188
- deviationSegmentIdx: closest.segmentIndex
189
- });
190
- this.emit('deviation', {
191
- anchorIndex: closest.segmentIndex,
192
- ghostCoord: snap.proj,
193
- });
194
- }
195
- }
196
- else if (this.offRouteFSM.state === 'DEVIATING') {
197
- this.offRouteFSM.dispatch({ type: 'RESUME' });
198
- }
199
- }
200
- else {
201
- // Core fallback: simple distance-based off-route check
202
- if (snap.dist > this.corridor && this.offRouteFSM.state === 'ON_ROUTE') {
203
- this.offRouteFSM.dispatch({ type: 'DEVIATION_SUSPECTED', deviationSegmentIdx: snap.idx });
204
- this.emit('deviation', { anchorIndex: snap.idx, ghostCoord: snap.proj });
205
- }
206
- else if (snap.dist <= this.corridor && this.offRouteFSM.state === 'DEVIATING') {
207
- this.offRouteFSM.dispatch({ type: 'RESUME' });
208
- }
209
- }
210
- }
211
- else {
212
- // Vehicle is in OFF_ROUTE, REJOINING, or REJOINED state.
213
- // If the vehicle re-enters the valid corridor, resume ON_ROUTE and emit 'rejoined'.
214
- if (snap.dist <= this.corridor) {
215
- const wasOffRoute = this.offRouteFSM.state === 'OFF_ROUTE' ||
216
- this.offRouteFSM.state === 'REJOINING' ||
217
- this.offRouteFSM.state === 'REJOINED';
218
- this.offRouteFSM.dispatch({ type: 'RESUME' });
219
- if (wasOffRoute) {
220
- this.emit('rejoined', { resumeIndex: snap.idx });
221
- }
222
- }
223
- }
224
- // 8. Lifecycle join detection
225
- if (this.lifecycleFSM.state === 'APPROACHING_ROUTE' && snap.dist < this.corridor) {
226
- this.lifecycleFSM.dispatch({ type: 'ROUTE_JOINED', data: { index: snap.idx } });
227
- }
228
- // 9. Instruction resolution
229
- if (this.instructions.length > 0) {
230
- const instrResult = resolveNextInstruction(this.routeIndex, this.instructions, this.instrIdx, this.route, filteredCoord, gps.bearing, this.linearOffset, gps.speed, this.options.isCircuit);
231
- if (instrResult.nextIdx !== this.instrIdx) {
232
- this.instrIdx = instrResult.nextIdx;
233
- }
234
- if (instrResult.wasTriggered && instrResult.instruction) {
235
- this.emit('instruction', instrResult.instruction);
236
- this.instrIdx = instrResult.nextIdx + 1;
237
- }
238
- }
239
- // 10. Arrival detection
240
- if (!this.hasArrived && this.route.length > 0) {
241
- const dest = this.route[this.route.length - 1];
242
- const distToDest = haversineDistance(filteredCoord[1], filteredCoord[0], dest[1], dest[0]);
243
- // Prevent immediate arrival on circuits by ensuring we've traversed at least 80% of the waypoints
244
- const hasTraveledFarEnough = this.options.isCircuit ?
245
- (this.routeIndex >= this.route.length * 0.8) : true;
246
- if (distToDest < this.options.arrivalThresholdMeters && hasTraveledFarEnough) {
247
- this.hasArrived = true;
248
- this.lifecycleFSM.dispatch({ type: 'NAVIGATION_FINISHED' });
249
- this.emit('arrival');
250
- }
251
- }
252
- // 11. Dead reckoning anchor (PRO: DEAD_RECKONING)
253
- if (this.has(FEATURES.DEAD_RECKONING)) {
254
- this.deadReckoning.setAnchor(snap.proj, snap.idx, gps.timestamp);
255
- }
256
- const state = this.getState();
257
- this.emit('update', state);
258
- return state;
259
- }
260
- /** Time-advance tick for dead reckoning (call at RAF rate) */
261
- tick(nowMs) {
262
- if (this.has(FEATURES.DEAD_RECKONING)) {
263
- const dr = this.deadReckoning.predict(this.currentSpeed, this.bearing, nowMs);
264
- if (dr.isActive) {
265
- this.snappedCoord = dr.predictedCoord;
266
- }
267
- }
268
- // Advance linear offset predictor
269
- if (this.lastGpsTimestamp > 0) {
270
- const dt = (nowMs - this.lastGpsTimestamp) / 1000;
271
- if (dt > 0 && dt < C.GPS_AGE_CAP_SECONDS) {
272
- this.linearOffset = advancePredictor(this.linearOffset, this.currentSpeed, dt);
273
- }
274
- }
275
- const state = this.getState();
276
- this.emit('update', state);
277
- return state;
278
- }
279
- /** Get the current engine state snapshot */
280
- getState() {
281
- const distToDest = this.route.length > 0 && this.reverseCum.length > this.routeIndex
282
- ? (this.reverseCum[this.routeIndex] ?? null)
283
- : null;
284
- const distToNextInstr = this.instrIdx < this.instructions.length
285
- ? (() => {
286
- const instr = this.instructions[this.instrIdx];
287
- return instr.cumulativeOffset !== undefined
288
- ? Math.max(0, instr.cumulativeOffset - this.linearOffset)
289
- : null;
290
- })()
291
- : null;
292
- const gpsAgeMs = this.lastGpsTimestamp > 0 ? Date.now() - this.lastGpsTimestamp : 0;
293
- const confidence = Math.max(0, Math.min(1, 1 - (this.distanceToRoute / Math.max(1, this.corridor))));
294
- const alertState = this.offRouteFSM.state === 'DEVIATING' ? 'DEVIATING' :
295
- this.offRouteFSM.state === 'OFF_ROUTE' || this.offRouteFSM.state === 'REROUTING' ? 'RECALCULATING' :
296
- this.offRouteFSM.state === 'REJOINING' ? 'REJOINING' :
297
- this.offRouteFSM.state === 'REJOINED' ? 'REJOINED' : 'NONE';
298
- const isOff = this.offRouteFSM.state !== 'ON_ROUTE' && this.offRouteFSM.state !== 'DEVIATING';
299
- const detourMode = this.offRouteFSM.state === 'OFF_ROUTE' || this.offRouteFSM.state === 'REROUTING' ? 'FREE' : 'NONE';
300
- const detourCommitProgress = this.offRouteFSM.state === 'OFF_ROUTE' ? 1.0 : 0.0;
301
- const rejoinCandidate = this.offRouteFSM.context.rejoinTarget
302
- ? {
303
- coord: this.offRouteFSM.context.rejoinTarget.coordinates,
304
- index: this.offRouteFSM.context.rejoinTarget.index,
305
- }
306
- : null;
307
- const confidenceCone = this.snappedCoord
308
- ? {
309
- center: this.snappedCoord,
310
- bearing: this.bearing,
311
- angle: 30,
312
- length: Math.max(10, Math.min(50, this.currentSpeed * 3)),
313
- }
314
- : null;
315
- const nextIdx = this.instrIdx < this.instructions.length ? this.instrIdx : null;
316
- return {
317
- snappedCoord: this.snappedCoord,
318
- ghostCoord: this.ghostCoord ?? this.snappedCoord,
319
- rawGpsCoord: this.rawGpsCoord,
320
- bearing: this.bearing,
321
- rawGpsBearing: this.rawGpsBearing,
322
- routeIndex: this.routeIndex,
323
- anchorRouteIndex: this.prevSegment ?? this.routeIndex,
324
- distanceToRoute: this.distanceToRoute,
325
- corridor: this.corridor,
326
- confidence,
327
- isOffRoute: isOff,
328
- navFsmState: this.lifecycleFSM.state,
329
- progressIndex: this.routeIndex,
330
- hasArrived: this.hasArrived,
331
- rejoinCandidate,
332
- confidenceCone,
333
- alertState,
334
- detourMode,
335
- detourCommitProgress,
336
- distanceToDestination: distToDest,
337
- distanceToNextInstruction: distToNextInstr,
338
- nextInstrIdx: nextIdx,
339
- nextInstructionIndex: nextIdx,
340
- currentSpeed: this.currentSpeed,
341
- isGpsStale: gpsAgeMs > C.GPS_STALE_MS,
342
- gpsAgeMs,
343
- licenseStatus: this.license.getStatus(),
344
- offRouteState: this.offRouteFSM.state,
345
- lifecycleState: this.lifecycleFSM.state,
346
- };
347
- }
348
- /** Destroy the engine */
349
- destroy() {
350
- this.listeners.clear();
351
- this.route = [];
352
- this.instructions = [];
353
- this.snappedCoord = null;
354
- this.ghostCoord = null;
355
- this.rawGpsCoord = null;
356
- this.kalman.reset();
357
- this.deadReckoning.clearAnchor();
358
- this.lifecycleFSM.reset();
359
- this.offRouteFSM.reset();
360
- }
361
- // ── Event system ─────────────────────────────────────────────
362
- on(event, handler) {
363
- if (!this.listeners.has(event)) {
364
- this.listeners.set(event, []);
365
- }
366
- this.listeners.get(event).push(handler);
367
- }
368
- off(event, handler) {
369
- const handlers = this.listeners.get(event);
370
- if (handlers) {
371
- const idx = handlers.indexOf(handler);
372
- if (idx >= 0)
373
- handlers.splice(idx, 1);
374
- }
375
- }
376
- emit(event, ...args) {
377
- const handlers = this.listeners.get(event);
378
- if (handlers) {
379
- for (const handler of handlers) {
380
- handler(...args);
381
- }
382
- }
383
- }
384
- // ── Getters ──────────────────────────────────────────────────
385
- getLicenseManager() { return this.license; }
386
- getRoute() { return this.route; }
387
- getInstructions() { return this.instructions; }
388
- getOffRouteFSM() { return this.offRouteFSM; }
389
- getLifecycleFSM() { return this.lifecycleFSM; }
390
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * Module 5: BearingEngine
3
- * Speed-adaptive IIR bearing smoothing.
4
- */
5
- import { type Coordinate } from '../geo/haversine';
6
- /**
7
- * Calculate speed-adaptive smoothing factor.
8
- * Higher speed → less smoothing (alpha closer to 1).
9
- * Lower speed → more smoothing (alpha closer to base value).
10
- */
11
- export declare function getSpeedAdaptiveAlpha(speedMps: number, baseAlpha?: number): number;
12
- /**
13
- * Compute bearing from the route geometry at the current segment.
14
- */
15
- export declare function calculateRobustBearing(route: Coordinate[], currentIdx: number, lookAhead?: number): number;
16
- /**
17
- * Blend two bearings using the shortest angular path.
18
- */
19
- export declare function blendBearing(current: number, target: number, alpha: number): number;
20
- /**
21
- * Full bearing smoothing pipeline: route bearing → IIR blend → output.
22
- */
23
- export declare function applyBearingSmoothing(currentBearing: number, route: Coordinate[], routeIdx: number, speedMps: number, gpsBearing: number | null, baseAlpha?: number): number;
24
- //# sourceMappingURL=BearingEngine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BearingEngine.d.ts","sourceRoot":"","sources":["../../../../../core/src/bearing/BearingEngine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAOnD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAgC,GAC1C,MAAM,CAIR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EAAE,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAU,GACpB,MAAM,CAQR;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,UAAU,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,SAAS,GAAE,MAAgC,GAC1C,MAAM,CAWR"}
@@ -1,50 +0,0 @@
1
- /**
2
- * Module 5: BearingEngine
3
- * Speed-adaptive IIR bearing smoothing.
4
- */
5
- import { getBearingBetweenPoints, normalizeAngle } from '../geo/bearing';
6
- import { BEARING_SMOOTHING_ALPHA, BEARING_MIN_SPEED_MPS, } from '../constants';
7
- /**
8
- * Calculate speed-adaptive smoothing factor.
9
- * Higher speed → less smoothing (alpha closer to 1).
10
- * Lower speed → more smoothing (alpha closer to base value).
11
- */
12
- export function getSpeedAdaptiveAlpha(speedMps, baseAlpha = BEARING_SMOOTHING_ALPHA) {
13
- if (speedMps < BEARING_MIN_SPEED_MPS)
14
- return baseAlpha * 0.5;
15
- if (speedMps > 20)
16
- return Math.min(0.9, baseAlpha * 2);
17
- return baseAlpha;
18
- }
19
- /**
20
- * Compute bearing from the route geometry at the current segment.
21
- */
22
- export function calculateRobustBearing(route, currentIdx, lookAhead = 3) {
23
- const endIdx = Math.min(currentIdx + lookAhead, route.length - 1);
24
- if (currentIdx >= route.length - 1 || currentIdx === endIdx) {
25
- return currentIdx > 0
26
- ? getBearingBetweenPoints(route[currentIdx - 1], route[currentIdx])
27
- : 0;
28
- }
29
- return getBearingBetweenPoints(route[currentIdx], route[endIdx]);
30
- }
31
- /**
32
- * Blend two bearings using the shortest angular path.
33
- */
34
- export function blendBearing(current, target, alpha) {
35
- const diff = normalizeAngle(target - current);
36
- return (current + alpha * diff + 360) % 360;
37
- }
38
- /**
39
- * Full bearing smoothing pipeline: route bearing → IIR blend → output.
40
- */
41
- export function applyBearingSmoothing(currentBearing, route, routeIdx, speedMps, gpsBearing, baseAlpha = BEARING_SMOOTHING_ALPHA) {
42
- const alpha = getSpeedAdaptiveAlpha(speedMps, baseAlpha);
43
- const routeBearing = calculateRobustBearing(route, routeIdx);
44
- // Use GPS bearing if available and speed is sufficient, blend with route bearing
45
- if (gpsBearing !== null && speedMps > BEARING_MIN_SPEED_MPS) {
46
- const gpsBlended = blendBearing(currentBearing, gpsBearing, alpha * 0.3);
47
- return blendBearing(gpsBlended, routeBearing, alpha);
48
- }
49
- return blendBearing(currentBearing, routeBearing, alpha);
50
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * Engine constants — centralized tuning parameters.
3
- * Extracted from packages/nav-sdk/src/shared/constants.ts
4
- */
5
- export declare const BASE_CORRIDOR_METERS = 25;
6
- export declare const MAX_CORRIDOR_METERS = 60;
7
- export declare const SPEED_CORRIDOR_FACTOR = 1.2;
8
- export declare const GPS_ACCURACY_FACTOR = 0.5;
9
- export declare const TURN_LOOKAHEAD_DISTANCE_METERS = 40;
10
- export declare const TURN_CORRIDOR_MULTIPLIER = 1.4;
11
- export declare const MAX_SNAP_DISTANCE = 80;
12
- export declare const BEARING_MISMATCH_THRESHOLD = 90;
13
- export declare const BEARING_MISMATCH_PENALTY = 500;
14
- export declare const INERTIA_PENALTY = 200;
15
- export declare const INERTIA_SEGMENT_DIST = 5;
16
- export declare const SNAP_WINDOW_SIZE = 25;
17
- export declare const BEARING_SMOOTHING_ALPHA = 0.3;
18
- export declare const BEARING_MIN_SPEED_MPS = 1.5;
19
- export declare const BEARING_ALIGNMENT_THRESHOLD = 55;
20
- export declare const DR_MAX_AGE_MS = 5000;
21
- export declare const OFF_ROUTE_CONFIRM_MS = 2000;
22
- export declare const REJOIN_CONFIRM_MS = 1500;
23
- export declare const REJOIN_COOLDOWN_MS = 12000;
24
- export declare const STARTUP_GRACE_MS = 3000;
25
- export declare const DETOUR_COMMIT_MS = 4000;
26
- export declare const GPS_STALE_MS = 3000;
27
- export declare const GPS_AGE_CAP_SECONDS = 10;
28
- export declare const MANEUVER_TRIGGER_DIST = 25;
29
- export declare const BETA_CORRECTION = 0.15;
30
- export declare const LOOK_AHEAD_SECONDS = 3;
31
- export declare const MIN_LOOK_AHEAD_METERS = 20;
32
- export declare const MAX_LOOK_AHEAD_METERS = 100;
33
- export declare const ARRIVAL_THRESHOLD_METERS = 30;
34
- //# sourceMappingURL=constants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../core/src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,8BAA8B,KAAK,CAAC;AACjD,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAG5C,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAC7C,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAGnC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAG9C,eAAO,MAAM,aAAa,OAAO,CAAC;AAGlC,eAAO,MAAM,oBAAoB,OAAO,CAAC;AACzC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAGtC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAGxC,eAAO,MAAM,eAAe,OAAO,CAAC;AACpC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAGzC,eAAO,MAAM,wBAAwB,KAAK,CAAC"}
@@ -1,41 +0,0 @@
1
- /**
2
- * Engine constants — centralized tuning parameters.
3
- * Extracted from packages/nav-sdk/src/shared/constants.ts
4
- */
5
- // ── Corridor ──────────────────────────────────────────────────
6
- export const BASE_CORRIDOR_METERS = 25;
7
- export const MAX_CORRIDOR_METERS = 60;
8
- export const SPEED_CORRIDOR_FACTOR = 1.2;
9
- export const GPS_ACCURACY_FACTOR = 0.5;
10
- export const TURN_LOOKAHEAD_DISTANCE_METERS = 40;
11
- export const TURN_CORRIDOR_MULTIPLIER = 1.4;
12
- // ── Snapping ──────────────────────────────────────────────────
13
- export const MAX_SNAP_DISTANCE = 80;
14
- export const BEARING_MISMATCH_THRESHOLD = 90;
15
- export const BEARING_MISMATCH_PENALTY = 500;
16
- export const INERTIA_PENALTY = 200;
17
- export const INERTIA_SEGMENT_DIST = 5;
18
- export const SNAP_WINDOW_SIZE = 25;
19
- // ── Bearing ───────────────────────────────────────────────────
20
- export const BEARING_SMOOTHING_ALPHA = 0.3;
21
- export const BEARING_MIN_SPEED_MPS = 1.5;
22
- export const BEARING_ALIGNMENT_THRESHOLD = 55;
23
- // ── Dead Reckoning ────────────────────────────────────────────
24
- export const DR_MAX_AGE_MS = 5000;
25
- // ── Timing ────────────────────────────────────────────────────
26
- export const OFF_ROUTE_CONFIRM_MS = 2000;
27
- export const REJOIN_CONFIRM_MS = 1500;
28
- export const REJOIN_COOLDOWN_MS = 12000;
29
- export const STARTUP_GRACE_MS = 3000;
30
- export const DETOUR_COMMIT_MS = 4000;
31
- export const GPS_STALE_MS = 3000;
32
- export const GPS_AGE_CAP_SECONDS = 10;
33
- // ── Instruction ───────────────────────────────────────────────
34
- export const MANEUVER_TRIGGER_DIST = 25;
35
- // ── Predictor ─────────────────────────────────────────────────
36
- export const BETA_CORRECTION = 0.15;
37
- export const LOOK_AHEAD_SECONDS = 3;
38
- export const MIN_LOOK_AHEAD_METERS = 20;
39
- export const MAX_LOOK_AHEAD_METERS = 100;
40
- // ── Arrival ───────────────────────────────────────────────────
41
- export const ARRIVAL_THRESHOLD_METERS = 30;
@@ -1,33 +0,0 @@
1
- /**
2
- * Module 4b: DeviationDetector
3
- * Compound deviation detection using distance, bearing, and movement signals.
4
- */
5
- import { type Coordinate } from '../geo/haversine';
6
- export interface DeviationSignals {
7
- /** Distance from GPS to nearest route segment (metres) */
8
- distanceToRoute: number;
9
- /** Whether the distance exceeds the dynamic corridor */
10
- outsideCorridor: boolean;
11
- /** Whether the vehicle bearing diverges from the route bearing */
12
- bearingMismatch: boolean;
13
- /** Whether the vehicle is moving away from the next segment */
14
- movingAway: boolean;
15
- /** Compound confirmed: outsideCorridor AND (bearingMismatch OR movingAway) */
16
- confirmed: boolean;
17
- }
18
- export interface ClosestSegment {
19
- segmentIndex: number;
20
- distance: number;
21
- projection: Coordinate;
22
- }
23
- /**
24
- * Find the closest segment to a GPS point within a search window.
25
- */
26
- export declare function findClosestSegment(gps: Coordinate, route: Coordinate[], startIdx: number, windowSize: number, routeFlowBearing?: number | null): ClosestSegment;
27
- export declare class DeviationDetector {
28
- /**
29
- * Evaluate deviation signals for the current GPS position.
30
- */
31
- evaluate(gps: Coordinate, gpsBearing: number | null, speedMps: number, closest: ClosestSegment, route: Coordinate[], corridor: number, prevDistToNextSegment: number | null): DeviationSignals;
32
- }
33
- //# sourceMappingURL=DeviationDetector.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeviationDetector.d.ts","sourceRoot":"","sources":["../../../../../core/src/corridor/DeviationDetector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,kBAAkB,CAAC;AAKtE,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,eAAe,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,eAAe,EAAE,OAAO,CAAC;IACzB,+DAA+D;IAC/D,UAAU,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,UAAU,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,gBAAgB,GAAE,MAAM,GAAG,IAAW,GACrC,cAAc,CA8ChB;AAED,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,QAAQ,CACN,GAAG,EAAE,UAAU,EACf,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,UAAU,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,qBAAqB,EAAE,MAAM,GAAG,IAAI,GACnC,gBAAgB;CAiCpB"}