@ingissa/navcore-simulator 1.0.3 → 1.0.4

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 (48) hide show
  1. package/README.md +18 -10
  2. package/dist/index-i9TY71RY.d.mts +494 -0
  3. package/dist/index-i9TY71RY.d.ts +494 -0
  4. package/dist/index.d.mts +1 -0
  5. package/dist/index.d.ts +1 -28
  6. package/dist/index.js +937 -29
  7. package/dist/index.mjs +929 -0
  8. package/dist/node.d.mts +1 -0
  9. package/dist/node.d.ts +1 -26
  10. package/dist/node.js +937 -25
  11. package/dist/node.mjs +929 -0
  12. package/dist/react-native.d.mts +82 -0
  13. package/dist/react-native.d.ts +82 -0
  14. package/dist/react-native.js +1370 -0
  15. package/dist/react-native.mjs +1360 -0
  16. package/package.json +15 -5
  17. package/dist/core/NoiseEngine.d.ts +0 -46
  18. package/dist/core/NoiseEngine.d.ts.map +0 -1
  19. package/dist/core/NoiseEngine.js +0 -106
  20. package/dist/core/RouteWalker.d.ts +0 -75
  21. package/dist/core/RouteWalker.d.ts.map +0 -1
  22. package/dist/core/RouteWalker.js +0 -177
  23. package/dist/core/SimulatorEngine.d.ts +0 -53
  24. package/dist/core/SimulatorEngine.d.ts.map +0 -1
  25. package/dist/core/SimulatorEngine.js +0 -283
  26. package/dist/core/types.d.ts +0 -129
  27. package/dist/core/types.d.ts.map +0 -1
  28. package/dist/core/types.js +0 -7
  29. package/dist/fleet/FleetSimulator.d.ts +0 -60
  30. package/dist/fleet/FleetSimulator.d.ts.map +0 -1
  31. package/dist/fleet/FleetSimulator.js +0 -114
  32. package/dist/index.d.ts.map +0 -1
  33. package/dist/node.d.ts.map +0 -1
  34. package/dist/react-native/SimulatorControls.d.ts +0 -35
  35. package/dist/react-native/SimulatorControls.d.ts.map +0 -1
  36. package/dist/react-native/SimulatorControls.js +0 -254
  37. package/dist/react-native/useSimulator.d.ts +0 -55
  38. package/dist/react-native/useSimulator.d.ts.map +0 -1
  39. package/dist/react-native/useSimulator.js +0 -97
  40. package/dist/replay/GpxParser.d.ts +0 -40
  41. package/dist/replay/GpxParser.d.ts.map +0 -1
  42. package/dist/replay/GpxParser.js +0 -95
  43. package/dist/replay/SessionRecorder.d.ts +0 -37
  44. package/dist/replay/SessionRecorder.d.ts.map +0 -1
  45. package/dist/replay/SessionRecorder.js +0 -120
  46. package/dist/scenarios/ScenarioInjector.d.ts +0 -55
  47. package/dist/scenarios/ScenarioInjector.d.ts.map +0 -1
  48. package/dist/scenarios/ScenarioInjector.js +0 -150
@@ -1,283 +0,0 @@
1
- /**
2
- * SimulatorEngine — The headless GPS simulation core.
3
- *
4
- * Works in Node.js for CI tests. NO React, NO Expo APIs.
5
- * All timers are cleaned up on destroy(). No memory leaks.
6
- *
7
- * State machine: idle → running ⇄ paused → complete
8
- */
9
- import { NoiseEngine } from './NoiseEngine';
10
- import { RouteWalker } from './RouteWalker';
11
- import { ScenarioInjector } from '../scenarios/ScenarioInjector';
12
- /** Generate a UUID v4 without external dependencies */
13
- function uuidV4() {
14
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
15
- const r = (Math.random() * 16) | 0;
16
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
17
- return v.toString(16);
18
- });
19
- }
20
- export class SimulatorEngine {
21
- constructor(config) {
22
- // ── State ────────────────────────────────────────────────────────────────────
23
- this._state = 'idle';
24
- this._position = null;
25
- this._timer = null;
26
- this._lastTick = 0;
27
- // ── Recording ────────────────────────────────────────────────────────────────
28
- this._recording = false;
29
- this._recordedPositions = [];
30
- this._recordedScenarios = [];
31
- this._sessionId = null;
32
- this._sessionStart = null;
33
- this._noiseSamplesAdded = 0;
34
- const geometry = config.routeGeometry;
35
- if (!geometry || geometry.length < 2) {
36
- throw new Error('SimulatorEngine: routeGeometry must have at least 2 points');
37
- }
38
- this._speedMultiplier = config.speedMultiplier ?? 1;
39
- this.config = {
40
- routeGeometry: geometry,
41
- speedKmh: config.speedKmh ?? 50,
42
- speedMultiplier: this._speedMultiplier,
43
- noiseProfile: config.noiseProfile ?? NoiseEngine.STANDARD,
44
- loop: config.loop ?? false,
45
- startIndex: config.startIndex ?? 0,
46
- autoStart: config.autoStart ?? false,
47
- onPositionUpdate: config.onPositionUpdate,
48
- onRouteComplete: config.onRouteComplete,
49
- onScenarioStart: config.onScenarioStart,
50
- onScenarioEnd: config.onScenarioEnd,
51
- };
52
- this.walker = new RouteWalker(geometry, this.config.startIndex);
53
- this.noise = new NoiseEngine(this.config.noiseProfile);
54
- this.injector = new ScenarioInjector((s) => {
55
- if (this._recording) {
56
- this._recordedScenarios.push({ scenario: s, firedAt: Date.now() });
57
- }
58
- try {
59
- this.config.onScenarioStart?.(s);
60
- }
61
- catch (_) { /* never throw */ }
62
- }, (s) => {
63
- try {
64
- this.config.onScenarioEnd?.(s);
65
- }
66
- catch (_) { /* never throw */ }
67
- });
68
- if (this.config.autoStart) {
69
- this.start();
70
- }
71
- }
72
- // ── Playback controls ────────────────────────────────────────────────────────
73
- start() {
74
- if (this._state === 'running')
75
- return;
76
- if (this._state === 'complete')
77
- return;
78
- this._state = 'running';
79
- this._startTimer();
80
- }
81
- stop() {
82
- this._stopTimer();
83
- this._state = 'idle';
84
- this._position = null;
85
- }
86
- pause() {
87
- if (this._state !== 'running')
88
- return;
89
- this._stopTimer();
90
- this._state = 'paused';
91
- }
92
- resume() {
93
- if (this._state !== 'paused')
94
- return;
95
- this._state = 'running';
96
- this._startTimer();
97
- }
98
- /**
99
- * Jump to any geometry index.
100
- * Bearing is recalculated from the new segment — seek() is always bearing-safe.
101
- */
102
- seek(geometryIndex) {
103
- const wasRunning = this._state === 'running';
104
- if (wasRunning)
105
- this._stopTimer();
106
- const pos = this.walker.seek(geometryIndex);
107
- this._buildAndEmitPosition(pos.coord, pos.bearing, pos.distanceTravelled, false);
108
- // Reset the completion flag so simulation can continue from the new index
109
- if (this._state === 'complete' && !pos.isComplete) {
110
- this._state = 'idle';
111
- }
112
- if (wasRunning && !pos.isComplete) {
113
- this._state = 'running';
114
- this._startTimer();
115
- }
116
- }
117
- setSpeed(multiplier) {
118
- this._speedMultiplier = multiplier;
119
- // No need to restart timer anymore as it's a fixed frequency
120
- }
121
- // ── Scenario management ──────────────────────────────────────────────────────
122
- addScenario(scenario) {
123
- this.injector.register(scenario);
124
- }
125
- removeScenario(name) {
126
- this.injector.remove(name);
127
- }
128
- clearScenarios() {
129
- this.injector.clear();
130
- }
131
- // ── State accessors ──────────────────────────────────────────────────────────
132
- get state() {
133
- return this._state;
134
- }
135
- get position() {
136
- return this._position;
137
- }
138
- get progress() {
139
- if (this.walker.totalPoints <= 1)
140
- return 0;
141
- return Math.min(1, this.walker.currentIndex / (this.walker.totalPoints - 1));
142
- }
143
- // ── Session recording ────────────────────────────────────────────────────────
144
- startRecording(sessionId) {
145
- this._recording = true;
146
- this._recordedPositions = [];
147
- this._recordedScenarios = [];
148
- this._sessionId = sessionId ?? uuidV4();
149
- this._sessionStart = Date.now();
150
- this._noiseSamplesAdded = 0;
151
- }
152
- stopRecording() {
153
- this._recording = false;
154
- const endedAt = Date.now();
155
- const startedAt = this._sessionStart ?? endedAt;
156
- const positions = this._recordedPositions;
157
- const durationMs = endedAt - startedAt;
158
- let distanceTravelledM = 0;
159
- if (positions.length > 0) {
160
- distanceTravelledM = positions[positions.length - 1]?.metadata?.distanceTravelled ?? 0;
161
- }
162
- const avgSpeedKmh = durationMs > 0
163
- ? ((distanceTravelledM / (durationMs / 1000)) * 3.6)
164
- : 0;
165
- return {
166
- id: this._sessionId ?? uuidV4(),
167
- startedAt: new Date(startedAt).toISOString(),
168
- endedAt: new Date(endedAt).toISOString(),
169
- route: this.config.routeGeometry,
170
- positions,
171
- scenarios: this._recordedScenarios,
172
- stats: {
173
- durationMs,
174
- distanceTravelledM,
175
- avgSpeedKmh,
176
- noiseSamplesAdded: this._noiseSamplesAdded,
177
- scenariosFired: this._recordedScenarios.length,
178
- },
179
- };
180
- }
181
- // ── Destroy ──────────────────────────────────────────────────────────────────
182
- destroy() {
183
- this._stopTimer();
184
- this.injector.destroy();
185
- this._state = 'idle';
186
- this._position = null;
187
- this._recording = false;
188
- this._recordedPositions = [];
189
- }
190
- // ── Private ──────────────────────────────────────────────────────────────────
191
- _startTimer() {
192
- this._lastTick = Date.now();
193
- this._timer = setInterval(() => this._tick(), SimulatorEngine.TICK_MS);
194
- }
195
- _stopTimer() {
196
- if (this._timer !== null) {
197
- clearInterval(this._timer);
198
- this._timer = null;
199
- }
200
- }
201
- _tick() {
202
- if (this._state !== 'running')
203
- return;
204
- const now = Date.now();
205
- const deltaMs = now - this._lastTick;
206
- this._lastTick = now;
207
- // Calculate physical distance to move in this tick
208
- // meters = (km/h / 3.6) * seconds * multiplier
209
- const speedMs = (this.config.speedKmh / 3.6);
210
- const distanceToMove = speedMs * (deltaMs / 1000) * this._speedMultiplier;
211
- const walkerPos = this.walker.advanceByDistance(distanceToMove);
212
- // Fire any scenarios at this index
213
- const activeScenarioName = this.injector.tick(walkerPos.index);
214
- // Apply noise (skip if GPS_BLACKOUT scenario is active)
215
- const activeScenario = this.injector.activeScenario;
216
- let coord = walkerPos.coord;
217
- let isNoisy = false;
218
- if (activeScenario?.type !== 'GPS_BLACKOUT') {
219
- coord = this.noise.apply(walkerPos.coord);
220
- isNoisy = this.noise.currentProfile.stdDevM > 0;
221
- if (isNoisy)
222
- this._noiseSamplesAdded++;
223
- }
224
- // Compute speed — apply speed spike if active
225
- //let speedMs = (this.config.speedKmh / 3.6);
226
- if (activeScenario?.type === 'SPEED_SPIKE') {
227
- const spikeKmh = activeScenario.params?.['spikeKmh'] ?? this.config.speedKmh;
228
- //speedMs = spikeKmh / 3.6;
229
- }
230
- // Compute accuracy — degrade if ACCURACY_DROP scenario is active
231
- let accuracy = 8 + Math.random() * 6;
232
- if (activeScenario?.type === 'ACCURACY_DROP') {
233
- accuracy = activeScenario.params?.['newAccuracyM'] ?? accuracy;
234
- }
235
- this._buildAndEmitPosition(coord, walkerPos.bearing, walkerPos.distanceTravelled, isNoisy, {
236
- speedMs,
237
- accuracy,
238
- activeScenarioName,
239
- segmentIndex: Math.floor(walkerPos.index),
240
- });
241
- if (walkerPos.isComplete) {
242
- this._stopTimer();
243
- if (this.config.loop) {
244
- // Restart from the beginning
245
- this.walker = new RouteWalker(this.config.routeGeometry, 0);
246
- this._startTimer();
247
- }
248
- else {
249
- this._state = 'complete';
250
- }
251
- try {
252
- this.config.onRouteComplete?.();
253
- }
254
- catch (_) { /* never throw */ }
255
- }
256
- }
257
- _buildAndEmitPosition(coord, bearing, distanceTravelled, isNoisy, opts) {
258
- const speedMs = opts?.speedMs ?? (this.config.speedKmh / 3.6);
259
- const accuracy = opts?.accuracy ?? 8;
260
- const pos = {
261
- coord: coord,
262
- bearing,
263
- speed: speedMs,
264
- accuracy,
265
- timestamp: Date.now(),
266
- metadata: {
267
- segmentIndex: opts?.segmentIndex ?? Math.floor(this.walker.currentIndex),
268
- distanceTravelled,
269
- isNoisy,
270
- scenarioActive: opts?.activeScenarioName,
271
- },
272
- };
273
- this._position = pos;
274
- if (this._recording) {
275
- this._recordedPositions.push(pos);
276
- }
277
- try {
278
- this.config.onPositionUpdate?.(pos);
279
- }
280
- catch (_) { /* never throw */ }
281
- }
282
- }
283
- SimulatorEngine.TICK_MS = 50; // 20 FPS for smooth movement
@@ -1,129 +0,0 @@
1
- /**
2
- * @navcore/simulator — Core Types
3
- *
4
- * These types are the foundation of the entire simulator package.
5
- * All other modules build on top of these definitions.
6
- */
7
- export type Coordinate = [number, number];
8
- /**
9
- * A single simulated GPS position, emitted by SimulatorEngine on every tick.
10
- * Shape is intentionally identical to the current inline SimPosition in
11
- * NavCoreTestScreen so that migration is a search-and-replace.
12
- */
13
- export interface SimPosition {
14
- /** [longitude, latitude] */
15
- coord: Coordinate;
16
- /** Heading in degrees 0–360 */
17
- bearing: number;
18
- /** Speed in metres per second */
19
- speed: number;
20
- /** Simulated GPS accuracy radius in metres */
21
- accuracy: number;
22
- /** Unix timestamp in milliseconds */
23
- timestamp: number;
24
- /** Optional debug metadata */
25
- metadata?: {
26
- /** Which geometry segment the vehicle is currently on */
27
- segmentIndex: number;
28
- /** Total metres travelled from route start */
29
- distanceTravelled: number;
30
- /** Whether noise was applied on this tick */
31
- isNoisy: boolean;
32
- /** Name of the active scenario, if any */
33
- scenarioActive?: string;
34
- };
35
- }
36
- /**
37
- * Noise model applied to simulated GPS coordinates each tick.
38
- */
39
- export interface NoiseProfile {
40
- /** Noise type */
41
- type: 'NONE' | 'GAUSSIAN' | 'URBAN' | 'TUNNEL' | 'CUSTOM';
42
- /** Standard deviation of the Gaussian noise in metres (default: 12) */
43
- stdDevM: number;
44
- /**
45
- * Optional seed for deterministic noise generation.
46
- * Same seed + same route = identical output (critical for regression tests).
47
- */
48
- seed?: number;
49
- /**
50
- * For CUSTOM type: return [lngOffset, latOffset] for each tick.
51
- * @param index - current geometry segment index
52
- */
53
- customFn?: (index: number) => [number, number];
54
- }
55
- /**
56
- * A scenario that is injected at a specific geometry index during simulation.
57
- */
58
- export interface Scenario {
59
- /** Unique name for this scenario */
60
- name: string;
61
- /** Geometry index at which the scenario fires */
62
- triggerIndex: number;
63
- /** Scenario type */
64
- type: 'GPS_BLACKOUT' | 'WRONG_SIDE_ROAD' | 'UTURN' | 'SPEED_SPIKE' | 'ACCURACY_DROP' | 'CUSTOM';
65
- /** How long the scenario lasts in milliseconds */
66
- durationMs?: number;
67
- /** Scenario-specific configuration */
68
- params?: Record<string, unknown>;
69
- }
70
- /**
71
- * Full configuration object passed to SimulatorEngine.
72
- * All callback fields are optional — the engine is fully usable without them
73
- * (useful for CI/headless tests).
74
- */
75
- export interface SimulatorConfig {
76
- /** The route geometry to simulate along */
77
- routeGeometry: Coordinate[];
78
- /** Simulated vehicle speed in km/h (default: 50) */
79
- speedKmh?: number;
80
- /** Playback speed multiplier: 1×, 2×, 4×, 8× (default: 1) */
81
- speedMultiplier?: 1 | 2 | 4 | 8;
82
- /** Noise model applied to each position (default: NoiseEngine.STANDARD) */
83
- noiseProfile?: NoiseProfile;
84
- /** Whether to restart from the beginning when the route ends (default: false) */
85
- loop?: boolean;
86
- /** Start simulation from this geometry index (default: 0) */
87
- startIndex?: number;
88
- /** If true, start() is called automatically after construction (default: false) */
89
- autoStart?: boolean;
90
- /** Called on every tick with the new simulated position */
91
- onPositionUpdate?: (pos: SimPosition) => void;
92
- /** Called when the route end is reached (or loop restarts) */
93
- onRouteComplete?: () => void;
94
- /** Called when a scenario begins */
95
- onScenarioStart?: (scenario: Scenario) => void;
96
- /** Called when a scenario ends */
97
- onScenarioEnd?: (scenario: Scenario) => void;
98
- }
99
- /**
100
- * A complete recorded simulation session.
101
- * Produced by SimulatorEngine.stopRecording() / SessionRecorder.stop().
102
- */
103
- export interface SimSession {
104
- /** UUID v4 session identifier */
105
- id: string;
106
- /** ISO 8601 start timestamp */
107
- startedAt: string;
108
- /** ISO 8601 end timestamp */
109
- endedAt: string;
110
- /** The route geometry used */
111
- route: Coordinate[];
112
- /** All SimPositions emitted during the session */
113
- positions: SimPosition[];
114
- /** Scenarios that fired, with their tick timestamps */
115
- scenarios: Array<{
116
- scenario: Scenario;
117
- /** Unix ms when the scenario fired */
118
- firedAt: number;
119
- }>;
120
- /** Aggregate statistics for this session */
121
- stats: {
122
- durationMs: number;
123
- distanceTravelledM: number;
124
- avgSpeedKmh: number;
125
- noiseSamplesAdded: number;
126
- scenariosFired: number;
127
- };
128
- }
129
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- /**
2
- * @navcore/simulator — Core Types
3
- *
4
- * These types are the foundation of the entire simulator package.
5
- * All other modules build on top of these definitions.
6
- */
7
- export {};
@@ -1,60 +0,0 @@
1
- /**
2
- * FleetSimulator — Phase 2 skeleton.
3
- *
4
- * Spawns N SimulatorEngine instances with optional per-vehicle profile
5
- * overrides, runs them in parallel, and produces aggregate reports.
6
- *
7
- * @experimental — fully typed but not tested in Phase 1.
8
- * Activate in a future iteration once SimulatorEngine is validated in CI.
9
- */
10
- import { SimulatorEngine } from '../core/SimulatorEngine';
11
- import type { SimulatorConfig, SimSession } from '../core/types';
12
- export interface VehicleProfile extends Partial<SimulatorConfig> {
13
- /** Human-readable label for this vehicle profile */
14
- label?: string;
15
- }
16
- export interface FleetReport {
17
- vehicles: Array<{
18
- id: number;
19
- label: string;
20
- session: SimSession;
21
- profile: VehicleProfile;
22
- }>;
23
- comparison: {
24
- /** Average stats keyed by vehicle label */
25
- avgScoreByProfile: Record<string, number>;
26
- /** Per-segment noise deviation across all vehicles (heatmap data) */
27
- deviationsBySegment: number[];
28
- };
29
- }
30
- export declare class FleetSimulator {
31
- private readonly engines;
32
- private readonly profiles;
33
- private readonly baseConfig;
34
- private constructor();
35
- /**
36
- * Spawn N SimulatorEngine instances.
37
- *
38
- * @param count - number of vehicles
39
- * @param config - base config (onPositionUpdate is per-vehicle, excluded here)
40
- */
41
- static spawn(count: number, config: Omit<SimulatorConfig, 'onPositionUpdate'> & {
42
- profiles?: VehicleProfile[];
43
- }): FleetSimulator;
44
- /** Start all engines simultaneously */
45
- start(): void;
46
- /** Stop all engines */
47
- stop(): void;
48
- /**
49
- * Get the engine at the given index.
50
- * Use this for per-vehicle control (seek, setSpeed, addScenario, etc.)
51
- */
52
- vehicle(index: number): SimulatorEngine;
53
- /**
54
- * Stop all engines, collect sessions, and return an aggregate report.
55
- */
56
- report(): FleetReport;
57
- /** Destroy all engines and clean up */
58
- destroy(): void;
59
- }
60
- //# sourceMappingURL=FleetSimulator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FleetSimulator.d.ts","sourceRoot":"","sources":["../../src/fleet/FleetSimulator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEjE,MAAM,WAAW,cAAe,SAAQ,OAAO,CAAC,eAAe,CAAC;IAC9D,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,UAAU,CAAC;QACpB,OAAO,EAAE,cAAc,CAAC;KACzB,CAAC,CAAC;IACH,UAAU,EAAE;QACV,2CAA2C;QAC3C,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1C,qEAAqE;QACrE,mBAAmB,EAAE,MAAM,EAAE,CAAC;KAC/B,CAAC;CACH;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4C;IAEvE,OAAO;IAUP;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG;QAClD,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;KAC7B,GACA,cAAc;IAsBjB,uCAAuC;IACvC,KAAK,IAAI,IAAI;IAOb,uBAAuB;IACvB,IAAI,IAAI,IAAI;IAMZ;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe;IAMvC;;OAEG;IACH,MAAM,IAAI,WAAW;IA8CrB,uCAAuC;IACvC,OAAO,IAAI,IAAI;CAKhB"}
@@ -1,114 +0,0 @@
1
- /**
2
- * FleetSimulator — Phase 2 skeleton.
3
- *
4
- * Spawns N SimulatorEngine instances with optional per-vehicle profile
5
- * overrides, runs them in parallel, and produces aggregate reports.
6
- *
7
- * @experimental — fully typed but not tested in Phase 1.
8
- * Activate in a future iteration once SimulatorEngine is validated in CI.
9
- */
10
- import { SimulatorEngine } from '../core/SimulatorEngine';
11
- export class FleetSimulator {
12
- constructor(engines, profiles, baseConfig) {
13
- this.engines = engines;
14
- this.profiles = profiles;
15
- this.baseConfig = baseConfig;
16
- }
17
- /**
18
- * Spawn N SimulatorEngine instances.
19
- *
20
- * @param count - number of vehicles
21
- * @param config - base config (onPositionUpdate is per-vehicle, excluded here)
22
- */
23
- static spawn(count, config) {
24
- const { profiles = [], ...baseConfig } = config;
25
- const engines = [];
26
- const resolvedProfiles = [];
27
- for (let i = 0; i < count; i++) {
28
- const profile = profiles[i] ?? {};
29
- resolvedProfiles.push(profile);
30
- const engine = new SimulatorEngine({
31
- ...baseConfig,
32
- ...profile,
33
- onPositionUpdate: undefined,
34
- });
35
- engines.push(engine);
36
- }
37
- return new FleetSimulator(engines, resolvedProfiles, baseConfig);
38
- }
39
- /** Start all engines simultaneously */
40
- start() {
41
- for (const engine of this.engines) {
42
- engine.startRecording();
43
- engine.start();
44
- }
45
- }
46
- /** Stop all engines */
47
- stop() {
48
- for (const engine of this.engines) {
49
- engine.stop();
50
- }
51
- }
52
- /**
53
- * Get the engine at the given index.
54
- * Use this for per-vehicle control (seek, setSpeed, addScenario, etc.)
55
- */
56
- vehicle(index) {
57
- const engine = this.engines[index];
58
- if (!engine)
59
- throw new Error(`FleetSimulator: no vehicle at index ${index}`);
60
- return engine;
61
- }
62
- /**
63
- * Stop all engines, collect sessions, and return an aggregate report.
64
- */
65
- report() {
66
- const vehicleReports = this.engines.map((engine, i) => {
67
- const session = engine.stopRecording();
68
- const profile = this.profiles[i] ?? {};
69
- return {
70
- id: i,
71
- label: profile.label ?? `vehicle-${i}`,
72
- session,
73
- profile,
74
- };
75
- });
76
- // Compute average speed per profile label
77
- const avgScoreByProfile = {};
78
- for (const v of vehicleReports) {
79
- const key = v.label;
80
- const existing = avgScoreByProfile[key];
81
- if (existing === undefined) {
82
- avgScoreByProfile[key] = v.session.stats.avgSpeedKmh;
83
- }
84
- else {
85
- avgScoreByProfile[key] = (existing + v.session.stats.avgSpeedKmh) / 2;
86
- }
87
- }
88
- // Per-segment noise deviation: average accuracy across all vehicles per segment
89
- const segmentCount = this.baseConfig.routeGeometry.length;
90
- const deviationsBySegment = new Array(segmentCount).fill(0);
91
- for (const v of vehicleReports) {
92
- for (const pos of v.session.positions) {
93
- const segIdx = pos.metadata?.segmentIndex ?? 0;
94
- if (segIdx < segmentCount) {
95
- deviationsBySegment[segIdx] = (deviationsBySegment[segIdx] ?? 0) + pos.accuracy;
96
- }
97
- }
98
- }
99
- // Average
100
- for (let i = 0; i < deviationsBySegment.length; i++) {
101
- deviationsBySegment[i] = (deviationsBySegment[i] ?? 0) / Math.max(1, vehicleReports.length);
102
- }
103
- return {
104
- vehicles: vehicleReports,
105
- comparison: { avgScoreByProfile, deviationsBySegment },
106
- };
107
- }
108
- /** Destroy all engines and clean up */
109
- destroy() {
110
- for (const engine of this.engines) {
111
- engine.destroy();
112
- }
113
- }
114
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,YAAY,EACV,WAAW,EACX,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,UAAU,GACX,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAK1E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,YAAY,EACV,WAAW,EACX,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,UAAU,GACX,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
@@ -1,35 +0,0 @@
1
- /**
2
- * SimulatorControls — Self-contained React Native control panel for SimulatorEngine.
3
- *
4
- * Three style variants:
5
- * 'minimal' — compact horizontal bar: speed selector + pause/resume
6
- * 'full' — full card with speed, seek, scenario log, recorder, stats
7
- * 'floating' — collapsible bottom sheet (Animated, no external libs)
8
- *
9
- * Colour tokens match the Klaroways design system used in NavCoreTestScreen.
10
- */
11
- import type { SimulatorControls as Controls, SessionControls } from './useSimulator';
12
- import type { SimSession } from '../core/types';
13
- export interface ScenarioLogEntry {
14
- ts: number;
15
- name: string;
16
- type: string;
17
- }
18
- export interface SimulatorControlsProps {
19
- simulator: Controls;
20
- session?: SessionControls;
21
- style?: 'minimal' | 'full' | 'floating';
22
- showScenarioLog?: boolean;
23
- showSessionRecorder?: boolean;
24
- scenarioLog?: ScenarioLogEntry[];
25
- /** Current speed multiplier (controlled externally) */
26
- currentSpeed?: 1 | 2 | 4 | 8;
27
- /** Current engine state */
28
- engineState?: 'idle' | 'running' | 'paused' | 'complete';
29
- isRecording?: boolean;
30
- onExportSession?: (session: SimSession) => void;
31
- /** Additional style for the root container */
32
- containerStyle?: object;
33
- }
34
- export declare function SimulatorControls({ simulator, session, style, showScenarioLog, showSessionRecorder, scenarioLog, currentSpeed, engineState, isRecording, onExportSession, containerStyle, }: SimulatorControlsProps): import("react/jsx-runtime").JSX.Element;
35
- //# sourceMappingURL=SimulatorControls.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SimulatorControls.d.ts","sourceRoot":"","sources":["../../src/react-native/SimulatorControls.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH,OAAO,KAAK,EAAE,iBAAiB,IAAI,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAuBhD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;IACxC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,uDAAuD;IACvD,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA0MD,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,OAAO,EACP,KAAiB,EACjB,eAAuB,EACvB,mBAA2B,EAC3B,WAAgB,EAChB,YAAgB,EAChB,WAAoB,EACpB,WAAmB,EACnB,eAAe,EACf,cAAc,GACf,EAAE,sBAAsB,2CA6GxB"}