vehicle-path2 1.0.0

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 (42) hide show
  1. package/README.md +160 -0
  2. package/dist/animation-loop-bZEm2pMN.js +37 -0
  3. package/dist/animation-loop-fC2LjxCd.cjs +1 -0
  4. package/dist/core/algorithms/math.d.ts +35 -0
  5. package/dist/core/algorithms/pathFinding.d.ts +62 -0
  6. package/dist/core/algorithms/vehicleMovement.d.ts +174 -0
  7. package/dist/core/index.d.ts +20 -0
  8. package/dist/core/types/api.d.ts +185 -0
  9. package/dist/core/types/config.d.ts +9 -0
  10. package/dist/core/types/geometry.d.ts +26 -0
  11. package/dist/core/types/movement.d.ts +56 -0
  12. package/dist/core/types/vehicle.d.ts +65 -0
  13. package/dist/core.cjs +1 -0
  14. package/dist/core.js +551 -0
  15. package/dist/index.d.ts +45 -0
  16. package/dist/react/dsl-hooks/useInitialMovement.d.ts +24 -0
  17. package/dist/react/dsl-hooks/useMovementSequence.d.ts +27 -0
  18. package/dist/react/dsl-hooks/useSceneDefinition.d.ts +22 -0
  19. package/dist/react/hooks/useAnimation.d.ts +43 -0
  20. package/dist/react/hooks/useMovementQueue.d.ts +52 -0
  21. package/dist/react/hooks/useScene.d.ts +78 -0
  22. package/dist/react/hooks/useVehicleSimulation.d.ts +126 -0
  23. package/dist/react/hooks/useVehicles.d.ts +55 -0
  24. package/dist/react/index.d.ts +48 -0
  25. package/dist/react/providers/useVehicleEvents.d.ts +78 -0
  26. package/dist/react.cjs +1 -0
  27. package/dist/react.js +18 -0
  28. package/dist/useVehicleEvents-B2JQFNjc.js +923 -0
  29. package/dist/useVehicleEvents-CBymulau.cjs +3 -0
  30. package/dist/utils/animation-loop.d.ts +105 -0
  31. package/dist/utils/dsl-parser.d.ts +152 -0
  32. package/dist/utils/event-emitter.d.ts +94 -0
  33. package/dist/utils/index.d.ts +15 -0
  34. package/dist/utils/type-converters.d.ts +38 -0
  35. package/dist/utils/vehicle-helpers.d.ts +8 -0
  36. package/dist/utils.cjs +1 -0
  37. package/dist/utils.js +17 -0
  38. package/dist/vehicle-helpers-DIcksrtO.cjs +7 -0
  39. package/dist/vehicle-helpers-_72KxCqO.js +276 -0
  40. package/dist/vehicle-path.cjs +1 -0
  41. package/dist/vehicle-path.js +62 -0
  42. package/package.json +103 -0
@@ -0,0 +1,923 @@
1
+ import { useState as T, useCallback as P, useRef as j, useMemo as F, useEffect as U, createContext as ae, useContext as ue } from "react";
2
+ import { distance as fe, initializeAllVehicles as ee, buildGraph as le, updateAxlePosition as te, handleArrival as de, prepareCommandPath as H, calculateFrontAxlePosition as re } from "./core.js";
3
+ import { v as z, p as me, a as B, f as ge, h as he, e as ve, V as se } from "./vehicle-helpers-_72KxCqO.js";
4
+ import { jsx as pe } from "react/jsx-runtime";
5
+ function G(r) {
6
+ return Array.isArray(r) ? { x: r[0], y: r[1] } : r;
7
+ }
8
+ function K(r) {
9
+ return {
10
+ id: r.id,
11
+ start: G(r.start),
12
+ end: G(r.end)
13
+ };
14
+ }
15
+ function k(r) {
16
+ const o = r.fromIsPercentage !== !1, I = r.toIsPercentage !== !1;
17
+ return {
18
+ fromLineId: r.from,
19
+ toLineId: r.to,
20
+ fromOffset: r.fromPosition !== void 0 ? o ? r.fromPosition * 100 : r.fromPosition : void 0,
21
+ fromIsPercentage: r.fromPosition !== void 0 ? o : void 0,
22
+ toOffset: r.toPosition !== void 0 ? I ? r.toPosition * 100 : r.toPosition : void 0,
23
+ toIsPercentage: r.toPosition !== void 0 ? I : void 0
24
+ };
25
+ }
26
+ function X(r) {
27
+ const o = r.position ?? 0, I = r.isPercentage !== !1;
28
+ return {
29
+ vehicleId: r.id,
30
+ lineId: r.lineId,
31
+ offset: I ? o * 100 : o,
32
+ isPercentage: I
33
+ };
34
+ }
35
+ function Y(r) {
36
+ const o = r.isPercentage !== !1, I = r.targetPosition ?? 1;
37
+ return {
38
+ vehicleId: r.vehicleId,
39
+ targetLineId: r.targetLineId,
40
+ targetOffset: o ? I * 100 : I,
41
+ isPercentage: o,
42
+ awaitConfirmation: r.wait,
43
+ payload: r.payload
44
+ };
45
+ }
46
+ function Pe(r) {
47
+ const o = [], I = /* @__PURE__ */ new Set();
48
+ for (const s of r.lines)
49
+ I.has(s.id) && o.push(`Duplicate line ID: ${s.id}`), I.add(s.id);
50
+ if (r.connections)
51
+ for (const s of r.connections) {
52
+ I.has(s.from) || o.push(`Connection references non-existent line: ${s.from}`), I.has(s.to) || o.push(`Connection references non-existent line: ${s.to}`);
53
+ const d = s.fromIsPercentage !== !1, t = s.toIsPercentage !== !1;
54
+ !d && s.fromPosition === void 0 && o.push("fromPosition is required when fromIsPercentage is false"), !t && s.toPosition === void 0 && o.push("toPosition is required when toIsPercentage is false"), s.fromPosition !== void 0 && (d && (s.fromPosition < 0 || s.fromPosition > 1) ? o.push(`Invalid fromPosition: ${s.fromPosition} (must be 0-1 for percentage)`) : !d && s.fromPosition < 0 && o.push(`Invalid fromPosition: ${s.fromPosition} (must be >= 0 for absolute distance)`)), s.toPosition !== void 0 && (t && (s.toPosition < 0 || s.toPosition > 1) ? o.push(`Invalid toPosition: ${s.toPosition} (must be 0-1 for percentage)`) : !t && s.toPosition < 0 && o.push(`Invalid toPosition: ${s.toPosition} (must be >= 0 for absolute distance)`));
55
+ }
56
+ return { valid: o.length === 0, errors: o };
57
+ }
58
+ function ne() {
59
+ const [r, o] = T([]), [I, s] = T([]), [d, t] = T(null), f = P((n, p) => {
60
+ o(n), s(p), t(null);
61
+ }, []), y = P((n) => {
62
+ const p = Pe(n);
63
+ if (!p.valid)
64
+ return t(p.errors.join("; ")), { success: !1, errors: p.errors };
65
+ const c = n.lines.map(K), l = n.connections?.map(k) || [];
66
+ return f(c, l), { success: !0 };
67
+ }, [f]), O = P((n) => {
68
+ if (r.some((c) => c.id === n.id)) {
69
+ const c = `Line with ID '${n.id}' already exists`;
70
+ return t(c), { success: !1, error: c };
71
+ }
72
+ return o((c) => [...c, K(n)]), t(null), { success: !0 };
73
+ }, [r]), S = P((n, p) => {
74
+ if (r.findIndex((l) => l.id === n) === -1) {
75
+ const l = `Line with ID '${n}' not found`;
76
+ return t(l), { success: !1, error: l };
77
+ }
78
+ return o((l) => l.map((x) => x.id !== n ? x : {
79
+ ...x,
80
+ start: p.start ? G(p.start) : x.start,
81
+ end: p.end ? G(p.end) : x.end
82
+ })), t(null), { success: !0 };
83
+ }, [r]), C = P((n) => {
84
+ if (!r.some((c) => c.id === n)) {
85
+ const c = `Line with ID '${n}' not found`;
86
+ return t(c), { success: !1, error: c };
87
+ }
88
+ return o((c) => c.filter((l) => l.id !== n)), s((c) => c.filter((l) => l.fromLineId !== n && l.toLineId !== n)), t(null), { success: !0 };
89
+ }, [r]), $ = P((n) => {
90
+ const p = r.some((i) => i.id === n.from), c = r.some((i) => i.id === n.to);
91
+ if (!p) {
92
+ const i = `Line '${n.from}' not found`;
93
+ return t(i), { success: !1, error: i };
94
+ }
95
+ if (!c) {
96
+ const i = `Line '${n.to}' not found`;
97
+ return t(i), { success: !1, error: i };
98
+ }
99
+ const l = n.fromIsPercentage !== !1, x = n.toIsPercentage !== !1;
100
+ if (!l && n.fromPosition === void 0) {
101
+ const i = "fromPosition is required when fromIsPercentage is false";
102
+ return t(i), { success: !1, error: i };
103
+ }
104
+ if (!x && n.toPosition === void 0) {
105
+ const i = "toPosition is required when toIsPercentage is false";
106
+ return t(i), { success: !1, error: i };
107
+ }
108
+ if (I.some((i) => i.fromLineId === n.from && i.toLineId === n.to)) {
109
+ const i = `Connection from '${n.from}' to '${n.to}' already exists`;
110
+ return t(i), { success: !1, error: i };
111
+ }
112
+ return s((i) => [...i, k(n)]), t(null), { success: !0 };
113
+ }, [r, I]), m = P((n, p, c) => {
114
+ const l = I.findIndex((e) => e.fromLineId === n && e.toLineId === p);
115
+ if (l === -1) {
116
+ const e = `Connection from '${n}' to '${p}' not found`;
117
+ return t(e), { success: !1, error: e };
118
+ }
119
+ const x = I[l], V = c.fromIsPercentage ?? x.fromIsPercentage, i = c.toIsPercentage ?? x.toIsPercentage;
120
+ let w;
121
+ c.fromOffset !== void 0 ? w = c.fromOffset : x.fromOffset !== void 0 && (w = x.fromIsPercentage !== !1 ? x.fromOffset / 100 : x.fromOffset);
122
+ let g;
123
+ if (c.toOffset !== void 0 ? g = c.toOffset : x.toOffset !== void 0 && (g = x.toIsPercentage !== !1 ? x.toOffset / 100 : x.toOffset), w !== void 0) {
124
+ if (V !== !1 && (w < 0 || w > 1)) {
125
+ const e = `Invalid fromOffset: ${w} (must be 0-1 for percentage)`;
126
+ return t(e), { success: !1, error: e };
127
+ }
128
+ if (V === !1 && w < 0) {
129
+ const e = `Invalid fromOffset: ${w} (must be >= 0 for absolute distance)`;
130
+ return t(e), { success: !1, error: e };
131
+ }
132
+ }
133
+ if (g !== void 0) {
134
+ if (i !== !1 && (g < 0 || g > 1)) {
135
+ const e = `Invalid toOffset: ${g} (must be 0-1 for percentage)`;
136
+ return t(e), { success: !1, error: e };
137
+ }
138
+ if (i === !1 && g < 0) {
139
+ const e = `Invalid toOffset: ${g} (must be >= 0 for absolute distance)`;
140
+ return t(e), { success: !1, error: e };
141
+ }
142
+ }
143
+ if (V === !1 && w === void 0) {
144
+ const e = "fromOffset is required when fromIsPercentage is false";
145
+ return t(e), { success: !1, error: e };
146
+ }
147
+ if (i === !1 && g === void 0) {
148
+ const e = "toOffset is required when toIsPercentage is false";
149
+ return t(e), { success: !1, error: e };
150
+ }
151
+ const M = {
152
+ from: n,
153
+ to: p,
154
+ fromPosition: w,
155
+ fromIsPercentage: V,
156
+ toPosition: g,
157
+ toIsPercentage: i
158
+ };
159
+ return s((e) => e.map(
160
+ (a, u) => u === l ? k(M) : a
161
+ )), t(null), { success: !0 };
162
+ }, [I]), h = P((n, p) => {
163
+ if (!I.some((l) => l.fromLineId === n && l.toLineId === p)) {
164
+ const l = `Connection from '${n}' to '${p}' not found`;
165
+ return t(l), { success: !1, error: l };
166
+ }
167
+ return s((l) => l.filter((x) => !(x.fromLineId === n && x.toLineId === p))), t(null), { success: !0 };
168
+ }, [I]), v = P(() => {
169
+ o([]), s([]), t(null);
170
+ }, []);
171
+ return {
172
+ lines: r,
173
+ curves: I,
174
+ setScene: y,
175
+ addLine: O,
176
+ updateLine: S,
177
+ removeLine: C,
178
+ addConnection: $,
179
+ updateConnection: m,
180
+ removeConnection: h,
181
+ clear: v,
182
+ error: d,
183
+ _loadScene: f
184
+ };
185
+ }
186
+ function oe({ lines: r, wheelbase: o }) {
187
+ const [I, s] = T([]), [d, t] = T(null), f = j([]), y = P((m) => {
188
+ f.current = m, s(m), t(null);
189
+ }, []), O = P((m) => {
190
+ const h = Array.isArray(m) ? m : [m], v = [];
191
+ for (const l of h)
192
+ f.current.some((V) => V.id === l.id) && v.push(`Vehicle with ID '${l.id}' already exists`);
193
+ if (v.length > 0)
194
+ return t(v.join("; ")), { success: !1, errors: v };
195
+ const n = h.map(X), { vehicles: p, errors: c } = z(
196
+ n,
197
+ r,
198
+ o
199
+ );
200
+ return c.length > 0 ? (t(c.join("; ")), { success: !1, errors: c }) : (f.current = [...f.current, ...p], s(f.current), t(null), { success: !0 });
201
+ }, [r, o]), S = P((m, h) => {
202
+ const v = f.current.findIndex((g) => g.id === m);
203
+ if (v === -1) {
204
+ const g = `Vehicle with ID '${m}' not found`;
205
+ return t(g), { success: !1, error: g };
206
+ }
207
+ const n = f.current[v];
208
+ if (n.state !== "idle") {
209
+ const g = `Cannot update vehicle '${m}' while it is ${n.state}. Vehicle must be idle.`;
210
+ return t(g), { success: !1, error: g };
211
+ }
212
+ const p = h.lineId ?? n.lineId;
213
+ if (!r.find((g) => g.id === p)) {
214
+ const g = `Line '${p}' not found`;
215
+ return t(g), { success: !1, error: g };
216
+ }
217
+ let l, x;
218
+ h.lineId !== void 0 && h.position === void 0 ? (l = 0, x = !0) : h.position !== void 0 ? (l = h.position, x = h.isPercentage ?? !0) : (l = n.offset, x = n.isPercentage);
219
+ const V = {
220
+ vehicleId: m,
221
+ lineId: p,
222
+ offset: x ? l * 100 : l,
223
+ // Convert to internal format (0-100 for %)
224
+ isPercentage: x
225
+ }, { vehicles: i, errors: w } = z(
226
+ [V],
227
+ r,
228
+ o
229
+ );
230
+ return w.length > 0 ? (t(w.join("; ")), { success: !1, error: w.join("; ") }) : (f.current = f.current.map(
231
+ (g, M) => M === v ? i[0] : g
232
+ ), s(f.current), t(null), { success: !0 });
233
+ }, [r, o]), C = P((m) => {
234
+ if (!f.current.some((v) => v.id === m)) {
235
+ const v = `Vehicle with ID '${m}' not found`;
236
+ return t(v), { success: !1, error: v };
237
+ }
238
+ return f.current = f.current.filter((v) => v.id !== m), s(f.current), t(null), { success: !0 };
239
+ }, []), $ = P(() => {
240
+ f.current = [], s([]), t(null);
241
+ }, []);
242
+ return {
243
+ vehicles: I,
244
+ addVehicles: O,
245
+ updateVehicle: S,
246
+ removeVehicle: C,
247
+ clear: $,
248
+ error: d,
249
+ _loadVehicles: y
250
+ };
251
+ }
252
+ function ce({ vehicles: r, lines: o }) {
253
+ const [I, s] = T(/* @__PURE__ */ new Map()), [d, t] = T(null), f = P((S) => {
254
+ s(S), t(null);
255
+ }, []), y = P((S, C) => {
256
+ if (!r.some((c) => c.id === S)) {
257
+ const c = `Vehicle '${S}' not found`;
258
+ return t(c), { success: !1, error: c };
259
+ }
260
+ const m = o.find((c) => c.id === C.targetLineId);
261
+ if (!m) {
262
+ const c = `Line '${C.targetLineId}' not found`;
263
+ return t(c), { success: !1, error: c };
264
+ }
265
+ const h = C.isPercentage !== !1, v = fe(m.start, m.end);
266
+ if (!h && C.targetPosition === void 0) {
267
+ const c = "targetPosition is required when isPercentage is false";
268
+ return t(c), { success: !1, error: c };
269
+ }
270
+ const n = C.targetPosition ?? 1;
271
+ if (h) {
272
+ if (n < 0 || n > 1) {
273
+ const c = `Invalid targetPosition: ${n} (must be 0-1 for percentage)`;
274
+ return t(c), { success: !1, error: c };
275
+ }
276
+ } else {
277
+ if (n < 0) {
278
+ const c = `Invalid targetPosition: ${n} (must be >= 0 for absolute distance)`;
279
+ return t(c), { success: !1, error: c };
280
+ }
281
+ if (n > v) {
282
+ const c = `Position ${n} exceeds line length ${v}`;
283
+ return t(c), { success: !1, error: c };
284
+ }
285
+ }
286
+ const p = Y({ vehicleId: S, ...C });
287
+ return s((c) => {
288
+ const l = new Map(c), x = l.get(S) || [];
289
+ return l.set(S, [...x, p]), l;
290
+ }), t(null), { success: !0 };
291
+ }, [r, o]), O = P((S) => {
292
+ if (S !== void 0) {
293
+ if (!r.some(($) => $.id === S)) {
294
+ const $ = `Vehicle '${S}' not found`;
295
+ return t($), { success: !1, error: $ };
296
+ }
297
+ s(($) => {
298
+ const m = new Map($);
299
+ return m.delete(S), m;
300
+ });
301
+ } else
302
+ s(/* @__PURE__ */ new Map());
303
+ return t(null), { success: !0 };
304
+ }, [r]);
305
+ return {
306
+ vehicleQueues: I,
307
+ queueMovement: y,
308
+ clearQueue: O,
309
+ error: d,
310
+ _loadQueues: f
311
+ };
312
+ }
313
+ function Ie({
314
+ vehicles: r,
315
+ lines: o,
316
+ vehicleQueues: I,
317
+ wheelbase: s,
318
+ tangentMode: d,
319
+ curves: t,
320
+ eventEmitter: f
321
+ }) {
322
+ const [y, O] = T([]), S = F(() => ({
323
+ wheelbase: s,
324
+ tangentMode: d
325
+ }), [s, d]), C = F(
326
+ () => new Map(o.map((V) => [V.id, V])),
327
+ [o]
328
+ ), $ = j(/* @__PURE__ */ new Map());
329
+ U(() => {
330
+ const { movingVehicles: V, stateMap: i } = ee(r, C);
331
+ $.current = i;
332
+ const w = setTimeout(() => {
333
+ O(V);
334
+ }, 0);
335
+ return () => clearTimeout(w);
336
+ }, [r, C]);
337
+ const m = j(null);
338
+ U(() => {
339
+ o.length > 0 && (m.current = le(o, t, S));
340
+ }, [o, t, S]);
341
+ const h = j(0), v = j(!1), n = P((V) => {
342
+ if (!v.current) return !1;
343
+ let i = !1;
344
+ for (const [, g] of $.current)
345
+ if (g.vehicle.state === "moving") {
346
+ i = !0;
347
+ break;
348
+ }
349
+ if (!i)
350
+ return !1;
351
+ const w = [];
352
+ for (const [g, M] of $.current) {
353
+ if (M.vehicle.state !== "moving" || !M.execution) continue;
354
+ const e = M.execution;
355
+ let a;
356
+ if (e.front.currentSegmentIndex < e.path.segments.length) {
357
+ const D = e.path.segments[e.front.currentSegmentIndex];
358
+ if (D.type === "line") {
359
+ const L = C.get(D.lineId);
360
+ L && (a = Math.sqrt(
361
+ Math.pow(L.end.x - L.start.x, 2) + Math.pow(L.end.y - L.start.y, 2)
362
+ ));
363
+ }
364
+ }
365
+ const u = te(
366
+ M.vehicle.rear,
367
+ e.rear,
368
+ e.path,
369
+ V,
370
+ C,
371
+ e.curveDataMap
372
+ ), E = te(
373
+ M.vehicle.front,
374
+ e.front,
375
+ e.path,
376
+ V,
377
+ C,
378
+ e.curveDataMap,
379
+ a
380
+ );
381
+ if (M.vehicle = {
382
+ ...M.vehicle,
383
+ rear: u.axleState,
384
+ front: E.axleState
385
+ }, M.execution.rear = u.execution, M.execution.front = E.execution, u.completed) {
386
+ const L = de(M, {
387
+ linesMap: C,
388
+ config: S,
389
+ vehicleQueues: I,
390
+ curves: t,
391
+ graphRef: m,
392
+ prepareCommandPath: H,
393
+ onCommandComplete: (Q) => w.push({ type: "commandComplete", data: Q }),
394
+ onCommandStart: (Q) => w.push({ type: "commandStart", data: Q })
395
+ });
396
+ M.vehicle = L.vehicle, L.newExecution !== void 0 && (M.execution = L.newExecution), L.vehicle.state !== "moving" && w.push({
397
+ type: "stateChange",
398
+ data: { vehicleId: g, from: "moving", to: L.vehicle.state }
399
+ });
400
+ const q = L.vehicle.rear.position, b = L.vehicle.front.position;
401
+ w.push({
402
+ type: "positionUpdate",
403
+ data: {
404
+ vehicleId: g,
405
+ rear: q,
406
+ front: b,
407
+ center: { x: (q.x + b.x) / 2, y: (q.y + b.y) / 2 },
408
+ angle: Math.atan2(b.y - q.y, b.x - q.x)
409
+ }
410
+ });
411
+ }
412
+ }
413
+ if (O((g) => g.map((M) => {
414
+ const e = $.current.get(M.id);
415
+ return e ? e.vehicle : M;
416
+ })), f && w.length > 0) {
417
+ const g = h.current;
418
+ setTimeout(() => {
419
+ h.current === g && w.forEach(({ type: M, data: e }) => {
420
+ f.emit(M, e);
421
+ });
422
+ }, 0);
423
+ }
424
+ for (const [, g] of $.current)
425
+ if (g.vehicle.state === "moving")
426
+ return !0;
427
+ return !1;
428
+ }, [C, t, S, I, f]), p = P(() => {
429
+ if (v.current) return !0;
430
+ const V = m.current;
431
+ if (!V) return !1;
432
+ const i = [];
433
+ let w = !1;
434
+ for (const [g, M] of $.current) {
435
+ const e = M.vehicle, a = I.get(g);
436
+ if (!a || a.length === 0) continue;
437
+ const u = a[0], D = H(e, u, { graph: V, linesMap: C, curves: t, config: S });
438
+ if (!D) {
439
+ console.warn(`No path found for vehicle ${g}`);
440
+ continue;
441
+ }
442
+ const L = re(D.path, 0, 0, s);
443
+ $.current.set(g, {
444
+ ...M,
445
+ execution: {
446
+ path: D.path,
447
+ curveDataMap: D.curveDataMap,
448
+ currentCommandIndex: 0,
449
+ rear: { currentSegmentIndex: 0, segmentDistance: 0 },
450
+ front: L ? { currentSegmentIndex: L.segmentIndex, segmentDistance: L.segmentDistance } : { currentSegmentIndex: 0, segmentDistance: 0 }
451
+ },
452
+ vehicle: { ...e, state: "moving" }
453
+ }), w = !0, e.state !== "moving" && i.push({
454
+ id: g,
455
+ fromState: e.state,
456
+ command: u,
457
+ startPosition: {
458
+ lineId: e.rear.lineId,
459
+ absoluteOffset: e.rear.absoluteOffset,
460
+ position: e.rear.position
461
+ }
462
+ });
463
+ }
464
+ if (!w) return !1;
465
+ if (v.current = !0, O((g) => g.map((M) => {
466
+ const e = $.current.get(M.id);
467
+ return e ? e.vehicle : M;
468
+ })), f && i.length > 0) {
469
+ const g = h.current;
470
+ setTimeout(() => {
471
+ h.current === g && i.forEach(({ id: M, fromState: e, command: a, startPosition: u }) => {
472
+ f.emit("commandStart", {
473
+ vehicleId: M,
474
+ command: a,
475
+ commandIndex: 0,
476
+ startPosition: u
477
+ }), f.emit("stateChange", {
478
+ vehicleId: M,
479
+ from: e,
480
+ to: "moving"
481
+ });
482
+ });
483
+ }, 0);
484
+ }
485
+ return !0;
486
+ }, [C, t, I, S, s, f]), c = P(() => {
487
+ h.current++, v.current = !1;
488
+ const { movingVehicles: V, stateMap: i } = ee(r, C);
489
+ $.current = i, O(V);
490
+ }, [r, C]), l = P((V) => {
491
+ const i = $.current.get(V);
492
+ if (!i || i.vehicle.state !== "waiting")
493
+ return !1;
494
+ const w = I.get(V), g = i.execution;
495
+ if (!g) return !1;
496
+ const M = g.currentCommandIndex + 1;
497
+ if (w && M < w.length) {
498
+ const e = m.current;
499
+ if (e) {
500
+ const a = w[M], u = { graph: e, linesMap: C, curves: t, config: S }, E = H(i.vehicle, a, u);
501
+ if (E) {
502
+ const D = re(E.path, 0, 0, s);
503
+ if (i.execution = {
504
+ path: E.path,
505
+ curveDataMap: E.curveDataMap,
506
+ currentCommandIndex: M,
507
+ rear: { currentSegmentIndex: 0, segmentDistance: 0 },
508
+ front: D ? { currentSegmentIndex: D.segmentIndex, segmentDistance: D.segmentDistance } : { currentSegmentIndex: 0, segmentDistance: 0 }
509
+ }, i.vehicle = { ...i.vehicle, state: "moving" }, O((L) => L.map((q) => q.id === V ? i.vehicle : q)), f) {
510
+ const L = h.current;
511
+ setTimeout(() => {
512
+ h.current === L && f.emit("stateChange", {
513
+ vehicleId: V,
514
+ from: "waiting",
515
+ to: "moving"
516
+ });
517
+ }, 0);
518
+ }
519
+ return !0;
520
+ }
521
+ }
522
+ }
523
+ if (i.vehicle = { ...i.vehicle, state: "idle" }, i.execution = null, O((e) => e.map((a) => a.id === V ? i.vehicle : a)), f) {
524
+ const e = h.current;
525
+ setTimeout(() => {
526
+ h.current === e && f.emit("stateChange", {
527
+ vehicleId: V,
528
+ from: "waiting",
529
+ to: "idle"
530
+ });
531
+ }, 0);
532
+ }
533
+ return !0;
534
+ }, [I, C, t, S, s, f]), x = P(() => {
535
+ for (const [, V] of $.current)
536
+ if (V.vehicle.state === "moving")
537
+ return !0;
538
+ return !1;
539
+ }, []);
540
+ return {
541
+ movingVehicles: y,
542
+ prepare: p,
543
+ tick: n,
544
+ reset: c,
545
+ continueVehicle: l,
546
+ isMoving: x,
547
+ isPrepared: v.current
548
+ };
549
+ }
550
+ function Ve({
551
+ wheelbase: r,
552
+ tangentMode: o = "proportional-40",
553
+ eventEmitter: I
554
+ }) {
555
+ const s = ne(), d = oe({ lines: s.lines, wheelbase: r }), t = ce({
556
+ vehicles: d.vehicles,
557
+ lines: s.lines,
558
+ curves: s.curves
559
+ }), f = Ie({
560
+ vehicles: d.vehicles,
561
+ lines: s.lines,
562
+ vehicleQueues: t.vehicleQueues,
563
+ wheelbase: r,
564
+ tangentMode: o,
565
+ curves: s.curves,
566
+ eventEmitter: I
567
+ }), y = P((e) => d.vehicles.filter((a) => a.lineId === e || a.rear.lineId === e), [d.vehicles]), O = P((e) => y(e).length > 0, [y]), S = P((e) => {
568
+ const a = s.addLine(e);
569
+ return a.success ? { success: !0 } : { success: !1, error: a.error };
570
+ }, [s]), C = P((e, a) => {
571
+ const u = s.updateLine(e, a);
572
+ return u.success ? { success: !0 } : { success: !1, error: u.error };
573
+ }, [s]), $ = P((e) => {
574
+ const a = [], u = y(e);
575
+ u.length > 0 && (a.push({
576
+ type: "vehicle_on_removed_line",
577
+ message: `${u.length} vehicle(s) are on line '${e}'`,
578
+ details: {
579
+ lineId: e,
580
+ vehicleIds: u.map((L) => L.id)
581
+ }
582
+ }), u.forEach((L) => {
583
+ d.removeVehicle(L.id), t.clearQueue(L.id);
584
+ }));
585
+ const E = s.curves.filter(
586
+ (L) => L.fromLineId === e || L.toLineId === e
587
+ );
588
+ E.length > 0 && a.push({
589
+ type: "orphaned_connection",
590
+ message: `${E.length} connection(s) will be removed`,
591
+ details: {
592
+ lineId: e,
593
+ connectionCount: E.length
594
+ }
595
+ });
596
+ const D = s.removeLine(e);
597
+ return D.success ? {
598
+ success: !0,
599
+ warnings: a.length > 0 ? a : void 0
600
+ } : { success: !1, error: D.error };
601
+ }, [s, y, d, t]), m = P(() => {
602
+ s.clear(), d.clear(), t.clearQueue();
603
+ }, [s, d, t]), h = P((e, a, u) => {
604
+ const E = s.addConnection({
605
+ from: e,
606
+ to: a,
607
+ fromPosition: u?.fromOffset,
608
+ fromIsPercentage: u?.fromIsPercentage,
609
+ toPosition: u?.toOffset,
610
+ toIsPercentage: u?.toIsPercentage
611
+ });
612
+ return E.success ? { success: !0 } : { success: !1, error: E.error };
613
+ }, [s]), v = P((e, a, u) => {
614
+ const E = s.updateConnection(e, a, u);
615
+ return E.success ? { success: !0 } : { success: !1, error: E.error };
616
+ }, [s]), n = P((e, a) => {
617
+ const u = s.removeConnection(e, a);
618
+ return u.success ? { success: !0 } : { success: !1, error: u.error };
619
+ }, [s]), p = P((e) => {
620
+ const a = d.addVehicles(e);
621
+ return a.success ? { success: !0 } : { success: !1, error: a.errors?.join("; ") };
622
+ }, [d]), c = P((e, a) => {
623
+ const u = d.updateVehicle(e, a);
624
+ return u.success ? { success: !0 } : { success: !1, error: u.error };
625
+ }, [d]), l = P((e) => {
626
+ const a = [], u = t.vehicleQueues.get(e);
627
+ u && u.length > 0 && (a.push({
628
+ type: "movement_queue_cleared",
629
+ message: `${u.length} queued movement(s) will be cleared for vehicle '${e}'`,
630
+ details: {
631
+ vehicleId: e
632
+ }
633
+ }), t.clearQueue(e));
634
+ const E = d.removeVehicle(e);
635
+ return E.success ? {
636
+ success: !0,
637
+ warnings: a.length > 0 ? a : void 0
638
+ } : { success: !1, error: E.error };
639
+ }, [d, t]), x = P(() => {
640
+ d.clear(), t.clearQueue();
641
+ }, [d, t]), V = P((e) => {
642
+ const a = {
643
+ targetLineId: e.lineId,
644
+ targetPosition: e.position ?? 1,
645
+ isPercentage: e.isPercentage,
646
+ wait: e.wait,
647
+ payload: e.payload
648
+ }, u = t.queueMovement(e.id, a);
649
+ return u.success ? { success: !0 } : { success: !1, error: u.error };
650
+ }, [t]), i = P((e) => {
651
+ const a = t.clearQueue(e);
652
+ return a.success ? { success: !0 } : { success: !1, error: a.error };
653
+ }, [t]), w = P((e) => {
654
+ const a = [], u = [], { scene: E, vehicles: D, movements: L } = me(e);
655
+ E.errors.length > 0 && u.push(...E.errors), D.errors.length > 0 && u.push(...D.errors), L.errors.length > 0 && u.push(...L.errors);
656
+ const q = E.data.lines.map(K), b = (E.data.connections || []).map(k), Q = D.data.map(X), { vehicles: _, errors: A } = z(Q, q, r);
657
+ A.length > 0 && u.push(...A);
658
+ const N = /* @__PURE__ */ new Map();
659
+ for (const J of L.data) {
660
+ const Z = N.get(J.vehicleId) || [];
661
+ Z.push(Y(J)), N.set(J.vehicleId, Z);
662
+ }
663
+ return s._loadScene(q, b), d._loadVehicles(_), t._loadQueues(N), u.length > 0 && a.push({
664
+ type: "dsl_parse_error",
665
+ message: `DSL loading had ${u.length} error(s)`,
666
+ details: { errors: u }
667
+ }), {
668
+ success: !0,
669
+ warnings: a.length > 0 ? a : void 0
670
+ };
671
+ }, [s, d, t, r]), g = P((e) => {
672
+ const a = [], u = [], E = e.lines.map(K), D = (e.connections || []).map(k), L = (e.vehicles || []).map(X), { vehicles: q, errors: b } = z(L, E, r);
673
+ b.length > 0 && u.push(...b);
674
+ const Q = /* @__PURE__ */ new Map();
675
+ for (const _ of e.movements || []) {
676
+ const A = Q.get(_.vehicleId) || [];
677
+ A.push(Y({
678
+ vehicleId: _.vehicleId,
679
+ targetLineId: _.targetLineId,
680
+ targetPosition: _.targetPosition,
681
+ isPercentage: _.isPercentage,
682
+ wait: _.wait,
683
+ payload: _.payload
684
+ })), Q.set(_.vehicleId, A);
685
+ }
686
+ return s._loadScene(E, D), d._loadVehicles(q), t._loadQueues(Q), u.length > 0 && a.push({
687
+ type: "dsl_parse_error",
688
+ message: `JSON loading had ${u.length} error(s)`,
689
+ details: { errors: u }
690
+ }), {
691
+ success: !0,
692
+ warnings: a.length > 0 ? a : void 0
693
+ };
694
+ }, [s, d, t, r]), M = F(() => s.error || d.error || t.error, [s.error, d.error, t.error]);
695
+ return {
696
+ // State
697
+ lines: s.lines,
698
+ curves: s.curves,
699
+ vehicles: d.vehicles,
700
+ movingVehicles: f.movingVehicles,
701
+ vehicleQueues: t.vehicleQueues,
702
+ error: M,
703
+ // Scene operations
704
+ addLine: S,
705
+ updateLine: C,
706
+ removeLine: $,
707
+ clearScene: m,
708
+ // Connection operations
709
+ connect: h,
710
+ updateConnection: v,
711
+ disconnect: n,
712
+ // Vehicle operations
713
+ addVehicles: p,
714
+ updateVehicle: c,
715
+ removeVehicle: l,
716
+ clearVehicles: x,
717
+ // Movement operations
718
+ goto: V,
719
+ clearQueue: i,
720
+ // Animation (delegated to useVehicleMovement)
721
+ prepare: f.prepare,
722
+ tick: f.tick,
723
+ reset: f.reset,
724
+ continueVehicle: f.continueVehicle,
725
+ isMoving: f.isMoving,
726
+ // DSL Loading
727
+ loadFromDSL: w,
728
+ // JSON Loading
729
+ loadFromJSON: g,
730
+ // Utility
731
+ getVehiclesOnLine: y,
732
+ hasVehiclesOnLine: O
733
+ };
734
+ }
735
+ function R(r) {
736
+ return r.map((o) => ({
737
+ id: o.id,
738
+ start: o.start,
739
+ end: o.end
740
+ }));
741
+ }
742
+ function W(r) {
743
+ return r.map((o) => ({
744
+ from: o.fromLineId,
745
+ to: o.toLineId,
746
+ fromPosition: o.fromOffset !== void 0 ? o.fromIsPercentage ? o.fromOffset / 100 : o.fromOffset : void 0,
747
+ fromIsPercentage: o.fromIsPercentage,
748
+ toPosition: o.toOffset !== void 0 ? o.toIsPercentage ? o.toOffset / 100 : o.toOffset : void 0,
749
+ toIsPercentage: o.toIsPercentage
750
+ }));
751
+ }
752
+ function we() {
753
+ const [r, o] = T(""), [I, s] = T(null), { lines: d, curves: t, setScene: f } = ne(), y = j(!1), O = j("");
754
+ U(() => {
755
+ O.current = r;
756
+ }, [r]), U(() => {
757
+ if (y.current)
758
+ return;
759
+ const m = {
760
+ lines: R(d),
761
+ connections: t.length > 0 ? W(t) : void 0
762
+ }, h = B(m);
763
+ h !== O.current && (y.current = !0, o(h), setTimeout(() => {
764
+ y.current = !1;
765
+ }, 50));
766
+ }, [d, t]);
767
+ const S = P((m) => {
768
+ y.current = !0, o(m);
769
+ try {
770
+ const { data: h, errors: v } = ge(m);
771
+ v.length > 0 && s(v.join("; "));
772
+ const n = f(h);
773
+ !n.success && n.errors ? s((p) => p ? `${p}; ${n.errors.join("; ")}` : n.errors.join("; ")) : v.length === 0 && s(null);
774
+ } catch (h) {
775
+ s(h instanceof Error ? h.message : "Invalid scene definition");
776
+ }
777
+ setTimeout(() => {
778
+ y.current = !1;
779
+ }, 50);
780
+ }, [f]), C = P((m) => {
781
+ const h = typeof m == "function" ? m(d) : m, v = W(t);
782
+ f({
783
+ lines: R(h),
784
+ connections: v.length > 0 ? v : void 0
785
+ });
786
+ const n = {
787
+ lines: R(h),
788
+ connections: v.length > 0 ? v : void 0
789
+ }, p = B(n);
790
+ y.current = !0, o(p), setTimeout(() => {
791
+ y.current = !1;
792
+ }, 50);
793
+ }, [d, t, f]), $ = P((m) => {
794
+ const h = typeof m == "function" ? m(t) : m, v = W(h);
795
+ f({
796
+ lines: R(d),
797
+ connections: v.length > 0 ? v : void 0
798
+ });
799
+ const n = {
800
+ lines: R(d),
801
+ connections: v.length > 0 ? v : void 0
802
+ }, p = B(n);
803
+ y.current = !0, o(p), setTimeout(() => {
804
+ y.current = !1;
805
+ }, 50);
806
+ }, [d, t, f]);
807
+ return {
808
+ lines: d,
809
+ curves: t,
810
+ sceneDefinitionText: r,
811
+ sceneError: I,
812
+ isDebouncing: !1,
813
+ // No debouncing - parsing is immediate
814
+ debounceKey: 0,
815
+ // Kept for API compatibility
816
+ setLines: C,
817
+ setCurves: $,
818
+ setSceneDefinitionText: S
819
+ };
820
+ }
821
+ function $e({ lines: r, wheelbase: o }) {
822
+ const [I, s] = T(""), [d, t] = T(null), { vehicles: f, addVehicles: y, clear: O, error: S } = oe({ lines: r, wheelbase: o }), C = j(!1), $ = P((m) => {
823
+ C.current = !0, s(m);
824
+ try {
825
+ const { data: h, errors: v } = he(m), n = [...v];
826
+ O();
827
+ for (const p of h) {
828
+ const c = y(p);
829
+ !c.success && c.errors && n.push(...c.errors);
830
+ }
831
+ n.length > 0 ? t(n.join(`
832
+ `)) : t(null);
833
+ } catch (h) {
834
+ t(h instanceof Error ? h.message : "Invalid initial movement");
835
+ }
836
+ setTimeout(() => {
837
+ C.current = !1;
838
+ }, 50);
839
+ }, [y, O]);
840
+ return {
841
+ vehicles: f,
842
+ initialMovementText: I,
843
+ movementError: d || S,
844
+ isDebouncing: !1,
845
+ // No debouncing - parsing is immediate
846
+ debounceKey: 0,
847
+ // Kept for API compatibility
848
+ setInitialMovementText: $
849
+ };
850
+ }
851
+ function ye({ lines: r, vehicles: o }) {
852
+ const [I, s] = T(""), [d, t] = T([]), [f, y] = T(null), { vehicleQueues: O, queueMovement: S, clearQueue: C, error: $ } = ce({
853
+ vehicles: o,
854
+ lines: r
855
+ }), m = j(!1), h = P((v) => {
856
+ m.current = !0, s(v);
857
+ try {
858
+ const { data: n, errors: p } = ve(v), c = [...p];
859
+ C();
860
+ for (const l of n) {
861
+ const x = S(l.vehicleId, {
862
+ targetLineId: l.targetLineId,
863
+ targetPosition: l.targetPosition,
864
+ isPercentage: l.isPercentage,
865
+ wait: l.wait,
866
+ payload: l.payload
867
+ });
868
+ !x.success && x.error && c.push(x.error);
869
+ }
870
+ t(n), c.length > 0 ? y(c.join(`
871
+ `)) : y(null);
872
+ } catch (n) {
873
+ y(n instanceof Error ? n.message : "Invalid movement sequence"), t([]);
874
+ }
875
+ setTimeout(() => {
876
+ m.current = !1;
877
+ }, 50);
878
+ }, [S, C]);
879
+ return {
880
+ movementSequenceText: I,
881
+ gotoCommands: d,
882
+ vehicleQueues: O,
883
+ sequenceError: f || $,
884
+ isDebouncing: !1,
885
+ // No debouncing - parsing is immediate
886
+ debounceKey: 0,
887
+ // Kept for API compatibility
888
+ setMovementSequenceText: h
889
+ };
890
+ }
891
+ const ie = ae(null);
892
+ function xe() {
893
+ const r = ue(ie);
894
+ if (!r)
895
+ throw new Error("useVehicleEventEmitter must be used within a VehicleEventProvider");
896
+ return r;
897
+ }
898
+ function Ee() {
899
+ return F(() => new se(), []);
900
+ }
901
+ function Oe(r, o, I = []) {
902
+ const s = xe();
903
+ U(() => s.on(r, o), [s, r, ...I]);
904
+ }
905
+ function De({ children: r }) {
906
+ const o = F(() => new se(), []);
907
+ return /* @__PURE__ */ pe(ie.Provider, { value: o, children: r });
908
+ }
909
+ export {
910
+ ie as V,
911
+ De as a,
912
+ Ee as b,
913
+ $e as c,
914
+ ce as d,
915
+ ye as e,
916
+ ne as f,
917
+ we as g,
918
+ Oe as h,
919
+ xe as i,
920
+ Ve as j,
921
+ oe as k,
922
+ Ie as u
923
+ };