@ingissa/navcore-simulator 1.0.7 → 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.
- package/README.md +2 -0
- package/dist/index.d.mts +87 -0
- package/dist/{simulator/src/react-native/useSimulator.d.ts → index.d.ts} +37 -9
- package/dist/index.js +1393 -0
- package/dist/index.mjs +1383 -0
- package/dist/node.d.mts +527 -0
- package/dist/node.d.ts +527 -0
- package/dist/node.js +957 -0
- package/dist/node.mjs +949 -0
- package/dist/react-native.d.mts +4 -0
- package/dist/react-native.d.ts +4 -0
- package/dist/react-native.js +1393 -0
- package/dist/react-native.mjs +1383 -0
- package/package.json +19 -16
- package/dist/core/src/NavCore.d.ts +0 -142
- package/dist/core/src/NavCore.d.ts.map +0 -1
- package/dist/core/src/NavCore.js +0 -390
- package/dist/core/src/bearing/BearingEngine.d.ts +0 -24
- package/dist/core/src/bearing/BearingEngine.d.ts.map +0 -1
- package/dist/core/src/bearing/BearingEngine.js +0 -50
- package/dist/core/src/constants.d.ts +0 -34
- package/dist/core/src/constants.d.ts.map +0 -1
- package/dist/core/src/constants.js +0 -41
- package/dist/core/src/corridor/DeviationDetector.d.ts +0 -33
- package/dist/core/src/corridor/DeviationDetector.d.ts.map +0 -1
- package/dist/core/src/corridor/DeviationDetector.js +0 -83
- package/dist/core/src/corridor/DynamicCorridor.d.ts +0 -13
- package/dist/core/src/corridor/DynamicCorridor.d.ts.map +0 -1
- package/dist/core/src/corridor/DynamicCorridor.js +0 -26
- package/dist/core/src/dead-reckoning/DeadReckoning.d.ts +0 -35
- package/dist/core/src/dead-reckoning/DeadReckoning.d.ts.map +0 -1
- package/dist/core/src/dead-reckoning/DeadReckoning.js +0 -49
- package/dist/core/src/directions/DirectionsProvider.d.ts +0 -70
- package/dist/core/src/directions/DirectionsProvider.d.ts.map +0 -1
- package/dist/core/src/directions/DirectionsProvider.js +0 -7
- package/dist/core/src/directions/OSRMDirectionsProvider.d.ts +0 -26
- package/dist/core/src/directions/OSRMDirectionsProvider.d.ts.map +0 -1
- package/dist/core/src/directions/OSRMDirectionsProvider.js +0 -90
- package/dist/core/src/directions/OpenRouteServiceProvider.d.ts +0 -30
- package/dist/core/src/directions/OpenRouteServiceProvider.d.ts.map +0 -1
- package/dist/core/src/directions/OpenRouteServiceProvider.js +0 -111
- package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts +0 -33
- package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts.map +0 -1
- package/dist/core/src/directions/ValhallaDirectionsProvider.js +0 -155
- package/dist/core/src/eta/ETAEngine.d.ts +0 -61
- package/dist/core/src/eta/ETAEngine.d.ts.map +0 -1
- package/dist/core/src/eta/ETAEngine.js +0 -74
- package/dist/core/src/features.d.ts +0 -76
- package/dist/core/src/features.d.ts.map +0 -1
- package/dist/core/src/features.js +0 -76
- package/dist/core/src/geo/bearing.d.ts +0 -11
- package/dist/core/src/geo/bearing.d.ts.map +0 -1
- package/dist/core/src/geo/bearing.js +0 -25
- package/dist/core/src/geo/cumulative.d.ts +0 -9
- package/dist/core/src/geo/cumulative.d.ts.map +0 -1
- package/dist/core/src/geo/cumulative.js +0 -20
- package/dist/core/src/geo/haversine.d.ts +0 -13
- package/dist/core/src/geo/haversine.d.ts.map +0 -1
- package/dist/core/src/geo/haversine.js +0 -39
- package/dist/core/src/geo/projection.d.ts +0 -7
- package/dist/core/src/geo/projection.d.ts.map +0 -1
- package/dist/core/src/geo/projection.js +0 -17
- package/dist/core/src/geofencing/GeofencingEngine.d.ts +0 -93
- package/dist/core/src/geofencing/GeofencingEngine.d.ts.map +0 -1
- package/dist/core/src/geofencing/GeofencingEngine.js +0 -154
- package/dist/core/src/index.d.ts +0 -66
- package/dist/core/src/index.d.ts.map +0 -1
- package/dist/core/src/index.js +0 -62
- package/dist/core/src/kalman/KalmanFilter2D.d.ts +0 -46
- package/dist/core/src/kalman/KalmanFilter2D.d.ts.map +0 -1
- package/dist/core/src/kalman/KalmanFilter2D.js +0 -77
- package/dist/core/src/license/LicenseManager.d.ts +0 -40
- package/dist/core/src/license/LicenseManager.d.ts.map +0 -1
- package/dist/core/src/license/LicenseManager.js +0 -119
- package/dist/core/src/license/verifyP256Signature.d.ts +0 -2
- package/dist/core/src/license/verifyP256Signature.d.ts.map +0 -1
- package/dist/core/src/license/verifyP256Signature.js +0 -26
- package/dist/core/src/off-route/NavigationFSM.d.ts +0 -42
- package/dist/core/src/off-route/NavigationFSM.d.ts.map +0 -1
- package/dist/core/src/off-route/NavigationFSM.js +0 -56
- package/dist/core/src/off-route/OffRouteFSM.d.ts +0 -70
- package/dist/core/src/off-route/OffRouteFSM.d.ts.map +0 -1
- package/dist/core/src/off-route/OffRouteFSM.js +0 -151
- package/dist/core/src/predictor/RouteOffsetPredictor.d.ts +0 -24
- package/dist/core/src/predictor/RouteOffsetPredictor.d.ts.map +0 -1
- package/dist/core/src/predictor/RouteOffsetPredictor.js +0 -55
- package/dist/core/src/progress/InstructionEditor.d.ts +0 -77
- package/dist/core/src/progress/InstructionEditor.d.ts.map +0 -1
- package/dist/core/src/progress/InstructionEditor.js +0 -151
- package/dist/core/src/progress/InstructionResolver.d.ts +0 -25
- package/dist/core/src/progress/InstructionResolver.d.ts.map +0 -1
- package/dist/core/src/progress/InstructionResolver.js +0 -78
- package/dist/core/src/progress/ProgressTracker.d.ts +0 -12
- package/dist/core/src/progress/ProgressTracker.d.ts.map +0 -1
- package/dist/core/src/progress/ProgressTracker.js +0 -22
- package/dist/core/src/renderer/MapRendererAdapter.d.ts +0 -72
- package/dist/core/src/renderer/MapRendererAdapter.d.ts.map +0 -1
- package/dist/core/src/renderer/MapRendererAdapter.js +0 -19
- package/dist/core/src/route-builder/CustomRouteBuilder.d.ts +0 -83
- package/dist/core/src/route-builder/CustomRouteBuilder.d.ts.map +0 -1
- package/dist/core/src/route-builder/CustomRouteBuilder.js +0 -160
- package/dist/core/src/route-plan/RoutePlan.d.ts +0 -38
- package/dist/core/src/route-plan/RoutePlan.d.ts.map +0 -1
- package/dist/core/src/route-plan/RoutePlan.js +0 -102
- package/dist/core/src/session/NavigationSession.d.ts +0 -81
- package/dist/core/src/session/NavigationSession.d.ts.map +0 -1
- package/dist/core/src/session/NavigationSession.js +0 -115
- package/dist/core/src/snapper/ParallelRoadResolver.d.ts +0 -86
- package/dist/core/src/snapper/ParallelRoadResolver.d.ts.map +0 -1
- package/dist/core/src/snapper/ParallelRoadResolver.js +0 -83
- package/dist/core/src/snapper/RouteSnapper.d.ts +0 -38
- package/dist/core/src/snapper/RouteSnapper.d.ts.map +0 -1
- package/dist/core/src/snapper/RouteSnapper.js +0 -80
- package/dist/core/src/voice/VoiceTriggerEngine.d.ts +0 -80
- package/dist/core/src/voice/VoiceTriggerEngine.d.ts.map +0 -1
- package/dist/core/src/voice/VoiceTriggerEngine.js +0 -108
- package/dist/simulator/src/core/NoiseEngine.d.ts +0 -46
- package/dist/simulator/src/core/NoiseEngine.d.ts.map +0 -1
- package/dist/simulator/src/core/NoiseEngine.js +0 -106
- package/dist/simulator/src/core/RouteWalker.d.ts +0 -78
- package/dist/simulator/src/core/RouteWalker.d.ts.map +0 -1
- package/dist/simulator/src/core/RouteWalker.js +0 -180
- package/dist/simulator/src/core/SimulatorEngine.d.ts +0 -53
- package/dist/simulator/src/core/SimulatorEngine.d.ts.map +0 -1
- package/dist/simulator/src/core/SimulatorEngine.js +0 -298
- package/dist/simulator/src/core/types.d.ts +0 -157
- package/dist/simulator/src/core/types.d.ts.map +0 -1
- package/dist/simulator/src/core/types.js +0 -7
- package/dist/simulator/src/fleet/FleetSimulator.d.ts +0 -60
- package/dist/simulator/src/fleet/FleetSimulator.d.ts.map +0 -1
- package/dist/simulator/src/fleet/FleetSimulator.js +0 -114
- package/dist/simulator/src/index.d.ts +0 -28
- package/dist/simulator/src/index.d.ts.map +0 -1
- package/dist/simulator/src/index.js +0 -29
- package/dist/simulator/src/node.d.ts +0 -26
- package/dist/simulator/src/node.d.ts.map +0 -1
- package/dist/simulator/src/node.js +0 -25
- package/dist/simulator/src/react-native/SimulatorControls.d.ts +0 -35
- package/dist/simulator/src/react-native/SimulatorControls.d.ts.map +0 -1
- package/dist/simulator/src/react-native/SimulatorControls.js +0 -254
- package/dist/simulator/src/react-native/useSimulator.d.ts.map +0 -1
- package/dist/simulator/src/react-native/useSimulator.js +0 -100
- package/dist/simulator/src/replay/GpxParser.d.ts +0 -40
- package/dist/simulator/src/replay/GpxParser.d.ts.map +0 -1
- package/dist/simulator/src/replay/GpxParser.js +0 -95
- package/dist/simulator/src/replay/SessionRecorder.d.ts +0 -37
- package/dist/simulator/src/replay/SessionRecorder.d.ts.map +0 -1
- package/dist/simulator/src/replay/SessionRecorder.js +0 -120
- package/dist/simulator/src/scenarios/ScenarioInjector.d.ts +0 -55
- package/dist/simulator/src/scenarios/ScenarioInjector.d.ts.map +0 -1
- package/dist/simulator/src/scenarios/ScenarioInjector.js +0 -150
- package/src/__tests__/integration/simulator-pipeline.test.ts +0 -233
- package/src/core/NoiseEngine.ts +0 -137
- package/src/core/RouteWalker.ts +0 -227
- package/src/core/SimulatorEngine.ts +0 -364
- package/src/core/__tests__/NoiseEngine.test.ts +0 -131
- package/src/core/__tests__/RouteWalker.test.ts +0 -139
- package/src/core/__tests__/SimulatorEngine.test.ts +0 -317
- package/src/core/types.ts +0 -191
- package/src/fleet/FleetSimulator.ts +0 -162
- package/src/index.ts +0 -54
- package/src/node.ts +0 -48
- package/src/react-native/SimulatorControls.tsx +0 -473
- package/src/react-native/useSimulator.ts +0 -155
- package/src/replay/GpxParser.ts +0 -122
- package/src/replay/SessionRecorder.ts +0 -138
- package/src/replay/__tests__/GpxParser.test.ts +0 -136
- package/src/scenarios/ScenarioInjector.ts +0 -170
- package/src/scenarios/__tests__/ScenarioInjector.test.ts +0 -171
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
import { Coordinate as Coordinate$1 } from '@ingissa/navcore-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @navcore/simulator — Core Types
|
|
5
|
+
*
|
|
6
|
+
* These types are the foundation of the entire simulator package.
|
|
7
|
+
* All other modules build on top of these definitions.
|
|
8
|
+
*/
|
|
9
|
+
/** [longitude, latitude] — Mapbox/GeoJSON order */
|
|
10
|
+
type Coordinate = [number, number];
|
|
11
|
+
/**
|
|
12
|
+
* Standard coords conforming to expo-location LocationObject['coords']
|
|
13
|
+
* and @react-native-community/geolocation.
|
|
14
|
+
*/
|
|
15
|
+
interface SimLocationCoords {
|
|
16
|
+
latitude: number;
|
|
17
|
+
longitude: number;
|
|
18
|
+
altitude: number | null;
|
|
19
|
+
accuracy: number | null;
|
|
20
|
+
altitudeAccuracy: number | null;
|
|
21
|
+
heading: number | null;
|
|
22
|
+
speed: number | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Standard LocationObject conforming to expo-location.
|
|
26
|
+
*/
|
|
27
|
+
interface SimLocationObject {
|
|
28
|
+
coords: SimLocationCoords;
|
|
29
|
+
timestamp: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A single simulated GPS position, emitted by SimulatorEngine on every tick.
|
|
33
|
+
* Shape includes standard LocationObject coords for drop-in Expo/React Native usage.
|
|
34
|
+
*/
|
|
35
|
+
interface SimPosition {
|
|
36
|
+
/** [longitude, latitude] */
|
|
37
|
+
coord: Coordinate;
|
|
38
|
+
/** Heading in degrees 0–360 */
|
|
39
|
+
bearing: number;
|
|
40
|
+
/** Speed in metres per second */
|
|
41
|
+
speed: number;
|
|
42
|
+
/** Simulated GPS accuracy radius in metres */
|
|
43
|
+
accuracy: number;
|
|
44
|
+
/** Unix timestamp in milliseconds */
|
|
45
|
+
timestamp: number;
|
|
46
|
+
/**
|
|
47
|
+
* Standard LocationObject coords conforming to expo-location & React Native geolocation.
|
|
48
|
+
*/
|
|
49
|
+
coords: SimLocationCoords;
|
|
50
|
+
/**
|
|
51
|
+
* Full standard LocationObject conforming to expo-location.
|
|
52
|
+
*/
|
|
53
|
+
location?: SimLocationObject;
|
|
54
|
+
/** Optional debug metadata */
|
|
55
|
+
metadata?: {
|
|
56
|
+
/** Which geometry segment the vehicle is currently on */
|
|
57
|
+
segmentIndex: number;
|
|
58
|
+
/** Total metres travelled from route start */
|
|
59
|
+
distanceTravelled: number;
|
|
60
|
+
/** Whether noise was applied on this tick */
|
|
61
|
+
isNoisy: boolean;
|
|
62
|
+
/** Name of the active scenario, if any */
|
|
63
|
+
scenarioActive?: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Noise model applied to simulated GPS coordinates each tick.
|
|
68
|
+
*/
|
|
69
|
+
interface NoiseProfile {
|
|
70
|
+
/** Noise type */
|
|
71
|
+
type: 'NONE' | 'GAUSSIAN' | 'URBAN' | 'TUNNEL' | 'CUSTOM';
|
|
72
|
+
/** Standard deviation of the Gaussian noise in metres (default: 12) */
|
|
73
|
+
stdDevM: number;
|
|
74
|
+
/**
|
|
75
|
+
* Optional seed for deterministic noise generation.
|
|
76
|
+
* Same seed + same route = identical output (critical for regression tests).
|
|
77
|
+
*/
|
|
78
|
+
seed?: number;
|
|
79
|
+
/**
|
|
80
|
+
* For CUSTOM type: return [lngOffset, latOffset] for each tick.
|
|
81
|
+
* @param index - current geometry segment index
|
|
82
|
+
*/
|
|
83
|
+
customFn?: (index: number) => [number, number];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A scenario that is injected at a specific geometry index during simulation.
|
|
87
|
+
*/
|
|
88
|
+
interface Scenario {
|
|
89
|
+
/** Unique name for this scenario */
|
|
90
|
+
name: string;
|
|
91
|
+
/** Geometry index at which the scenario fires */
|
|
92
|
+
triggerIndex: number;
|
|
93
|
+
/** Scenario type */
|
|
94
|
+
type: 'GPS_BLACKOUT' | 'WRONG_SIDE_ROAD' | 'UTURN' | 'SPEED_SPIKE' | 'ACCURACY_DROP' | 'CUSTOM';
|
|
95
|
+
/** How long the scenario lasts in milliseconds */
|
|
96
|
+
durationMs?: number;
|
|
97
|
+
/** Scenario-specific configuration */
|
|
98
|
+
params?: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Full configuration object passed to SimulatorEngine.
|
|
102
|
+
* All callback fields are optional — the engine is fully usable without them
|
|
103
|
+
* (useful for CI/headless tests).
|
|
104
|
+
*/
|
|
105
|
+
interface SimulatorConfig {
|
|
106
|
+
/** The route geometry to simulate along */
|
|
107
|
+
routeGeometry: Coordinate[];
|
|
108
|
+
/** Simulated vehicle speed in km/h (default: 50) */
|
|
109
|
+
speedKmh?: number;
|
|
110
|
+
/** Playback speed multiplier: 1×, 2×, 4×, 8× (default: 1) */
|
|
111
|
+
speedMultiplier?: 1 | 2 | 4 | 8;
|
|
112
|
+
/** Noise model applied to each position (default: NoiseEngine.STANDARD) */
|
|
113
|
+
noiseProfile?: NoiseProfile;
|
|
114
|
+
/** Whether to restart from the beginning when the route ends (default: false) */
|
|
115
|
+
loop?: boolean;
|
|
116
|
+
/** Start simulation from this geometry index (default: 0) */
|
|
117
|
+
startIndex?: number;
|
|
118
|
+
/** If true, start() is called automatically after construction (default: false) */
|
|
119
|
+
autoStart?: boolean;
|
|
120
|
+
/** Called on every tick with the new simulated position */
|
|
121
|
+
onPositionUpdate?: (pos: SimPosition) => void;
|
|
122
|
+
/** Called when the route end is reached (or loop restarts) */
|
|
123
|
+
onRouteComplete?: () => void;
|
|
124
|
+
/** Called when a scenario begins */
|
|
125
|
+
onScenarioStart?: (scenario: Scenario) => void;
|
|
126
|
+
/** Called when a scenario ends */
|
|
127
|
+
onScenarioEnd?: (scenario: Scenario) => void;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A complete recorded simulation session.
|
|
131
|
+
* Produced by SimulatorEngine.stopRecording() / SessionRecorder.stop().
|
|
132
|
+
*/
|
|
133
|
+
interface SimSession {
|
|
134
|
+
/** UUID v4 session identifier */
|
|
135
|
+
id: string;
|
|
136
|
+
/** ISO 8601 start timestamp */
|
|
137
|
+
startedAt: string;
|
|
138
|
+
/** ISO 8601 end timestamp */
|
|
139
|
+
endedAt: string;
|
|
140
|
+
/** The route geometry used */
|
|
141
|
+
route: Coordinate[];
|
|
142
|
+
/** All SimPositions emitted during the session */
|
|
143
|
+
positions: SimPosition[];
|
|
144
|
+
/** Scenarios that fired, with their tick timestamps */
|
|
145
|
+
scenarios: Array<{
|
|
146
|
+
scenario: Scenario;
|
|
147
|
+
/** Unix ms when the scenario fired */
|
|
148
|
+
firedAt: number;
|
|
149
|
+
}>;
|
|
150
|
+
/** Aggregate statistics for this session */
|
|
151
|
+
stats: {
|
|
152
|
+
durationMs: number;
|
|
153
|
+
distanceTravelledM: number;
|
|
154
|
+
avgSpeedKmh: number;
|
|
155
|
+
noiseSamplesAdded: number;
|
|
156
|
+
scenariosFired: number;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* SimulatorEngine — The headless GPS simulation core.
|
|
162
|
+
*
|
|
163
|
+
* Works in Node.js for CI tests. NO React, NO Expo APIs.
|
|
164
|
+
* All timers are cleaned up on destroy(). No memory leaks.
|
|
165
|
+
*
|
|
166
|
+
* State machine: idle → running ⇄ paused → complete
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
type EngineState = 'idle' | 'running' | 'paused' | 'complete';
|
|
170
|
+
declare class SimulatorEngine {
|
|
171
|
+
private readonly config;
|
|
172
|
+
private walker;
|
|
173
|
+
private noise;
|
|
174
|
+
private injector;
|
|
175
|
+
private _state;
|
|
176
|
+
private _position;
|
|
177
|
+
private _speedMultiplier;
|
|
178
|
+
private _timer;
|
|
179
|
+
private _lastTick;
|
|
180
|
+
private static readonly TICK_MS;
|
|
181
|
+
private _recording;
|
|
182
|
+
private _recordedPositions;
|
|
183
|
+
private _recordedScenarios;
|
|
184
|
+
private _sessionId;
|
|
185
|
+
private _sessionStart;
|
|
186
|
+
private _noiseSamplesAdded;
|
|
187
|
+
constructor(config: SimulatorConfig);
|
|
188
|
+
start(): void;
|
|
189
|
+
stop(): void;
|
|
190
|
+
pause(): void;
|
|
191
|
+
resume(): void;
|
|
192
|
+
/**
|
|
193
|
+
* Jump to any geometry index.
|
|
194
|
+
* Bearing is recalculated from the new segment — seek() is always bearing-safe.
|
|
195
|
+
*/
|
|
196
|
+
seek(geometryIndex: number): void;
|
|
197
|
+
setSpeed(multiplier: 1 | 2 | 4 | 8): void;
|
|
198
|
+
addScenario(scenario: Scenario): void;
|
|
199
|
+
removeScenario(name: string): void;
|
|
200
|
+
clearScenarios(): void;
|
|
201
|
+
get state(): EngineState;
|
|
202
|
+
get position(): SimPosition | null;
|
|
203
|
+
get progress(): number;
|
|
204
|
+
startRecording(sessionId?: string): void;
|
|
205
|
+
stopRecording(): SimSession;
|
|
206
|
+
destroy(): void;
|
|
207
|
+
private _startTimer;
|
|
208
|
+
private _stopTimer;
|
|
209
|
+
private _tick;
|
|
210
|
+
private _buildAndEmitPosition;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* RouteWalker — Manages traversal of a route geometry array.
|
|
215
|
+
*
|
|
216
|
+
* Extracted from the inline useGpsSimulator hook so the traversal logic
|
|
217
|
+
* is testable independently of React, timers, or noise.
|
|
218
|
+
*
|
|
219
|
+
* ZERO dependencies beyond @navcore/core types.
|
|
220
|
+
*/
|
|
221
|
+
|
|
222
|
+
interface WalkerPosition {
|
|
223
|
+
/** Current floating-point index (e.g. 3.75 = between points 3 and 4) */
|
|
224
|
+
index: number;
|
|
225
|
+
/** Interpolated coordinate at the current index */
|
|
226
|
+
coord: Coordinate$1;
|
|
227
|
+
/** Forward-looking bearing at the current segment */
|
|
228
|
+
bearing: number;
|
|
229
|
+
/** Total metres travelled from route start */
|
|
230
|
+
distanceTravelled: number;
|
|
231
|
+
/** True if the walker has reached or passed the last point */
|
|
232
|
+
isComplete: boolean;
|
|
233
|
+
}
|
|
234
|
+
declare class RouteWalker {
|
|
235
|
+
private readonly geometry;
|
|
236
|
+
private _index;
|
|
237
|
+
private _distanceTravelled;
|
|
238
|
+
private readonly _cumulativeDistances;
|
|
239
|
+
private _isComplete;
|
|
240
|
+
constructor(geometry: Coordinate$1[], startIndex?: number);
|
|
241
|
+
/**
|
|
242
|
+
* Advance the walker by `steps` geometry points.
|
|
243
|
+
* Fractional steps are supported for sub-second precision.
|
|
244
|
+
*/
|
|
245
|
+
advance(steps: number): WalkerPosition;
|
|
246
|
+
/**
|
|
247
|
+
* Advance the walker by a physical distance in metres.
|
|
248
|
+
* This is the preferred way for smooth constant-speed simulation.
|
|
249
|
+
*/
|
|
250
|
+
advanceByDistance(meters: number): WalkerPosition;
|
|
251
|
+
private _finalizeAdvance;
|
|
252
|
+
/**
|
|
253
|
+
* Seek directly to a geometry index (integer or fractional).
|
|
254
|
+
* Recalculates bearing from the new position.
|
|
255
|
+
*/
|
|
256
|
+
seek(index: number): WalkerPosition;
|
|
257
|
+
/**
|
|
258
|
+
* Get an interpolated coordinate between geometry[index] and geometry[index+1].
|
|
259
|
+
* @param index - integer index
|
|
260
|
+
* @param fraction - 0..1 interpolation factor
|
|
261
|
+
*/
|
|
262
|
+
interpolate(index: number, fraction: number): Coordinate$1;
|
|
263
|
+
/**
|
|
264
|
+
* Compute the forward-looking bearing at a given integer index.
|
|
265
|
+
* At the last point, returns the bearing of the final segment.
|
|
266
|
+
*/
|
|
267
|
+
bearingAt(index: number): number;
|
|
268
|
+
/**
|
|
269
|
+
* Total haversine distance from the route start to the given index.
|
|
270
|
+
* Uses the pre-computed cumulative distances (O(1)).
|
|
271
|
+
*/
|
|
272
|
+
distanceAtIndex(index: number): number;
|
|
273
|
+
/**
|
|
274
|
+
* Alias for distanceAtIndex.
|
|
275
|
+
*/
|
|
276
|
+
distanceToIndex(index: number): number;
|
|
277
|
+
/**
|
|
278
|
+
* Convert a distance in metres back to a fractional index.
|
|
279
|
+
* Uses binary search for O(log N) performance.
|
|
280
|
+
*/
|
|
281
|
+
private _distanceToIndex;
|
|
282
|
+
get totalDistanceM(): number;
|
|
283
|
+
get totalPoints(): number;
|
|
284
|
+
get isComplete(): boolean;
|
|
285
|
+
get currentIndex(): number;
|
|
286
|
+
private _currentPosition;
|
|
287
|
+
/** Interpolate cumulative distance for fractional index */
|
|
288
|
+
private _interpolatedDistance;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* NoiseEngine — GPS noise simulation.
|
|
293
|
+
*
|
|
294
|
+
* Formalises the ±0.00011° noise from the original useGpsSimulator
|
|
295
|
+
* into a testable, seeded, swappable noise model.
|
|
296
|
+
*
|
|
297
|
+
* Box-Muller transform for Gaussian sampling — ZERO external dependencies.
|
|
298
|
+
*
|
|
299
|
+
* Degrees-per-metre constants:
|
|
300
|
+
* 1° latitude ≈ 110540 m
|
|
301
|
+
* 1° longitude ≈ 111320 m (at equator; good enough for noise simulation)
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
declare class NoiseEngine {
|
|
305
|
+
private profile;
|
|
306
|
+
private rng;
|
|
307
|
+
private _tickIndex;
|
|
308
|
+
constructor(profile: NoiseProfile);
|
|
309
|
+
/** No noise — returns the exact coordinate */
|
|
310
|
+
static readonly NONE: NoiseProfile;
|
|
311
|
+
/** Good urban GPS — ~3m standard deviation */
|
|
312
|
+
static readonly CLEAN: NoiseProfile;
|
|
313
|
+
/** Standard Go4Exams value — ~12m standard deviation (matches original ±0.00011°) */
|
|
314
|
+
static readonly STANDARD: NoiseProfile;
|
|
315
|
+
/** Dense city canyon — ~25m standard deviation */
|
|
316
|
+
static readonly URBAN: NoiseProfile;
|
|
317
|
+
/** Bad conditions — ~50m standard deviation */
|
|
318
|
+
static readonly DEGRADED: NoiseProfile;
|
|
319
|
+
/**
|
|
320
|
+
* Apply noise to a coordinate.
|
|
321
|
+
* Returns a new coordinate — never mutates the input.
|
|
322
|
+
*/
|
|
323
|
+
apply(coord: Coordinate$1): Coordinate$1;
|
|
324
|
+
/** Hot-swap the noise profile mid-simulation */
|
|
325
|
+
setProfile(profile: NoiseProfile): void;
|
|
326
|
+
get currentProfile(): NoiseProfile;
|
|
327
|
+
/**
|
|
328
|
+
* Box-Muller transform: produces Gaussian N(0, stdDev²) offset.
|
|
329
|
+
* Returns [lngOffset, latOffset] in degrees.
|
|
330
|
+
*/
|
|
331
|
+
private _gaussianOffset;
|
|
332
|
+
/** Returns a float in [0, 1) — uses seeded RNG if available, else Math.random */
|
|
333
|
+
private _rand;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* ScenarioInjector — Registers and fires Scenario objects at geometry indices.
|
|
338
|
+
*
|
|
339
|
+
* Called internally by SimulatorEngine on each tick.
|
|
340
|
+
* Also provides static factory methods for the built-in scenario types.
|
|
341
|
+
*/
|
|
342
|
+
|
|
343
|
+
type ScenarioFireCallback = (scenario: Scenario) => void;
|
|
344
|
+
type ScenarioEndCallback = (scenario: Scenario) => void;
|
|
345
|
+
declare class ScenarioInjector {
|
|
346
|
+
/** Map from triggerIndex → Scenario */
|
|
347
|
+
private readonly scenarios;
|
|
348
|
+
/** Tracks which scenarios have already fired (by name) to avoid double-fire */
|
|
349
|
+
private readonly fired;
|
|
350
|
+
/** Currently active scenario, if any */
|
|
351
|
+
private _activeScenario;
|
|
352
|
+
private _activeEndTimer;
|
|
353
|
+
private onStart;
|
|
354
|
+
private onEnd;
|
|
355
|
+
constructor(onStart?: ScenarioFireCallback, onEnd?: ScenarioEndCallback);
|
|
356
|
+
register(scenario: Scenario): void;
|
|
357
|
+
remove(name: string): void;
|
|
358
|
+
clear(): void;
|
|
359
|
+
/**
|
|
360
|
+
* Check and fire any scenario whose triggerIndex matches (or was passed) by
|
|
361
|
+
* currentIndex. Called by SimulatorEngine on every tick.
|
|
362
|
+
*
|
|
363
|
+
* Returns the name of the active scenario (if any), for metadata injection.
|
|
364
|
+
*/
|
|
365
|
+
tick(currentIndex: number): string | undefined;
|
|
366
|
+
get activeScenario(): Scenario | null;
|
|
367
|
+
/** Clean up any pending timers */
|
|
368
|
+
destroy(): void;
|
|
369
|
+
/**
|
|
370
|
+
* GPS blackout: no position updates for `durationMs`.
|
|
371
|
+
* Engine handles signal loss; this scenario signals the blackout period.
|
|
372
|
+
*/
|
|
373
|
+
static gpsBlackout(atIndex: number, durationMs: number): Scenario;
|
|
374
|
+
/**
|
|
375
|
+
* Wrong-side road: offset the simulated position by `offsetM` metres
|
|
376
|
+
* perpendicular to the route to stress-test the parallel road resolver.
|
|
377
|
+
*/
|
|
378
|
+
static wrongSideRoad(atIndex: number, offsetM: number): Scenario;
|
|
379
|
+
/** U-turn at the given index — stress-tests U-turn protection. */
|
|
380
|
+
static uTurn(atIndex: number): Scenario;
|
|
381
|
+
/** Speed spike: briefly report spikeKmh instead of the configured speed. */
|
|
382
|
+
static speedSpike(atIndex: number, spikeKmh: number, durationMs?: number): Scenario;
|
|
383
|
+
/**
|
|
384
|
+
* Accuracy drop: GPS accuracy degrades to newAccuracyM for durationMs.
|
|
385
|
+
*/
|
|
386
|
+
static accuracyDrop(atIndex: number, newAccuracyM: number, durationMs: number): Scenario;
|
|
387
|
+
private _fire;
|
|
388
|
+
private _clearActiveTimer;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* GpxParser — Parse GPX 1.1 files into NavCore coordinate arrays.
|
|
393
|
+
*
|
|
394
|
+
* ZERO dependencies. Pure string/regex parsing.
|
|
395
|
+
* No DOMParser, no xml2js, no cheerio.
|
|
396
|
+
*
|
|
397
|
+
* Supports:
|
|
398
|
+
* <trkpt> (track points — most common)
|
|
399
|
+
* <wpt> (waypoints)
|
|
400
|
+
*/
|
|
401
|
+
|
|
402
|
+
interface GpxParseResult {
|
|
403
|
+
coordinates: Coordinate$1[];
|
|
404
|
+
/** Milliseconds since epoch for each coordinate (0 if no time element) */
|
|
405
|
+
timestamps: number[];
|
|
406
|
+
metadata: {
|
|
407
|
+
name?: string;
|
|
408
|
+
/** Total number of coordinate points */
|
|
409
|
+
totalPoints: number;
|
|
410
|
+
/** Duration in ms (first to last timestamp, 0 if no timestamps) */
|
|
411
|
+
durationMs: number;
|
|
412
|
+
/** Total route distance in metres */
|
|
413
|
+
distanceM: number;
|
|
414
|
+
/** Average speed in km/h (0 if no timestamps) */
|
|
415
|
+
avgSpeedKmh: number;
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
declare class GpxParser {
|
|
419
|
+
/**
|
|
420
|
+
* Parse a GPX XML string into coordinates and metadata.
|
|
421
|
+
* Supports both <trkpt> and <wpt> elements.
|
|
422
|
+
*/
|
|
423
|
+
static parse(gpxString: string): GpxParseResult;
|
|
424
|
+
/**
|
|
425
|
+
* Parse a base64-encoded GPX string.
|
|
426
|
+
* Works in React Native (uses atob) and Node.js (uses Buffer.from).
|
|
427
|
+
*/
|
|
428
|
+
static fromBase64(base64: string): GpxParseResult;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* SessionRecorder — Record and export simulation sessions.
|
|
433
|
+
*
|
|
434
|
+
* Supports JSON, GPX 1.1, and CSV export formats.
|
|
435
|
+
*
|
|
436
|
+
* The GPX export is the critical format: a session recorded in the simulator
|
|
437
|
+
* can be exported as GPX, then replayed via GpxParser on a future run.
|
|
438
|
+
* This creates a full regression test loop:
|
|
439
|
+
* real GPS trace → gpx → GpxParser → SimulatorEngine → CI test
|
|
440
|
+
*/
|
|
441
|
+
|
|
442
|
+
type ExportFormat = 'json' | 'gpx' | 'csv';
|
|
443
|
+
declare class SessionRecorder {
|
|
444
|
+
private _sessionId;
|
|
445
|
+
private _startedAt;
|
|
446
|
+
private _session;
|
|
447
|
+
/**
|
|
448
|
+
* Start a new recording.
|
|
449
|
+
* If the engine already has a session via startRecording(), you can pass
|
|
450
|
+
* the existing sessionId to keep IDs consistent.
|
|
451
|
+
*/
|
|
452
|
+
start(sessionId?: string): void;
|
|
453
|
+
/**
|
|
454
|
+
* Stop recording and return the captured session.
|
|
455
|
+
* If called with an existing SimSession (from SimulatorEngine.stopRecording()),
|
|
456
|
+
* it stores that session for subsequent export() calls.
|
|
457
|
+
*/
|
|
458
|
+
stop(existing?: SimSession): SimSession;
|
|
459
|
+
/**
|
|
460
|
+
* Export the most recent session in the specified format.
|
|
461
|
+
* Must call stop() first.
|
|
462
|
+
*/
|
|
463
|
+
export(format: ExportFormat): string;
|
|
464
|
+
private static _toGpx;
|
|
465
|
+
private static _toCsv;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* FleetSimulator — Phase 2 skeleton.
|
|
470
|
+
*
|
|
471
|
+
* Spawns N SimulatorEngine instances with optional per-vehicle profile
|
|
472
|
+
* overrides, runs them in parallel, and produces aggregate reports.
|
|
473
|
+
*
|
|
474
|
+
* @experimental — fully typed but not tested in Phase 1.
|
|
475
|
+
* Activate in a future iteration once SimulatorEngine is validated in CI.
|
|
476
|
+
*/
|
|
477
|
+
|
|
478
|
+
interface VehicleProfile extends Partial<SimulatorConfig> {
|
|
479
|
+
/** Human-readable label for this vehicle profile */
|
|
480
|
+
label?: string;
|
|
481
|
+
}
|
|
482
|
+
interface FleetReport {
|
|
483
|
+
vehicles: Array<{
|
|
484
|
+
id: number;
|
|
485
|
+
label: string;
|
|
486
|
+
session: SimSession;
|
|
487
|
+
profile: VehicleProfile;
|
|
488
|
+
}>;
|
|
489
|
+
comparison: {
|
|
490
|
+
/** Average stats keyed by vehicle label */
|
|
491
|
+
avgScoreByProfile: Record<string, number>;
|
|
492
|
+
/** Per-segment noise deviation across all vehicles (heatmap data) */
|
|
493
|
+
deviationsBySegment: number[];
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
declare class FleetSimulator {
|
|
497
|
+
private readonly engines;
|
|
498
|
+
private readonly profiles;
|
|
499
|
+
private readonly baseConfig;
|
|
500
|
+
private constructor();
|
|
501
|
+
/**
|
|
502
|
+
* Spawn N SimulatorEngine instances.
|
|
503
|
+
*
|
|
504
|
+
* @param count - number of vehicles
|
|
505
|
+
* @param config - base config (onPositionUpdate is per-vehicle, excluded here)
|
|
506
|
+
*/
|
|
507
|
+
static spawn(count: number, config: Omit<SimulatorConfig, 'onPositionUpdate'> & {
|
|
508
|
+
profiles?: VehicleProfile[];
|
|
509
|
+
}): FleetSimulator;
|
|
510
|
+
/** Start all engines simultaneously */
|
|
511
|
+
start(): void;
|
|
512
|
+
/** Stop all engines */
|
|
513
|
+
stop(): void;
|
|
514
|
+
/**
|
|
515
|
+
* Get the engine at the given index.
|
|
516
|
+
* Use this for per-vehicle control (seek, setSpeed, addScenario, etc.)
|
|
517
|
+
*/
|
|
518
|
+
vehicle(index: number): SimulatorEngine;
|
|
519
|
+
/**
|
|
520
|
+
* Stop all engines, collect sessions, and return an aggregate report.
|
|
521
|
+
*/
|
|
522
|
+
report(): FleetReport;
|
|
523
|
+
/** Destroy all engines and clean up */
|
|
524
|
+
destroy(): void;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export { type Coordinate, type EngineState, type ExportFormat, type FleetReport, FleetSimulator, type GpxParseResult, GpxParser, NoiseEngine, type NoiseProfile, RouteWalker, type Scenario, ScenarioInjector, SessionRecorder, type SimLocationCoords, type SimLocationObject, type SimPosition, type SimSession, type SimulatorConfig, SimulatorEngine, type VehicleProfile, type WalkerPosition };
|