vehicle-path 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.
@@ -0,0 +1,1346 @@
1
+ import { useState as L, useMemo as Z, useRef as P, useEffect as b, useCallback as G, createContext as he, useContext as pe } from "react";
2
+ function j(e, t) {
3
+ const n = t.x - e.x, r = t.y - e.y;
4
+ return Math.sqrt(n * n + r * r);
5
+ }
6
+ function Q(e, t) {
7
+ const n = t.x - e.x, r = t.y - e.y, s = Math.sqrt(n * n + r * r);
8
+ return s === 0 ? { x: 0, y: 0 } : { x: n / s, y: r / s };
9
+ }
10
+ function Ie(e, t) {
11
+ return t * (e === "proportional-40" ? 0.4 : 0.5522);
12
+ }
13
+ function ue(e, t, n, r = !1, s) {
14
+ const { wheelbase: c, tangentMode: o } = n;
15
+ let i;
16
+ s?.fromOffset !== void 0 ? i = ee(e, s.fromOffset, s.fromIsPercentage ?? !1) : i = e.end;
17
+ let f;
18
+ s?.toOffset !== void 0 ? f = ee(t, s.toOffset, s.toIsPercentage ?? !1) : f = t.start;
19
+ const a = Q(e.start, e.end), u = r ? {
20
+ // Transition with flip: kurva dimulai dari P (baseP0 - wheelbase in line direction)
21
+ x: i.x - a.x * c,
22
+ y: i.y - a.y * c
23
+ } : i, d = Q(e.start, e.end), m = Q(t.start, t.end), I = j(u, f), h = Ie(o, I), l = r ? { x: u.x - d.x * h, y: u.y - d.y * h } : { x: u.x + d.x * h, y: u.y + d.y * h }, p = {
24
+ x: f.x - m.x * h,
25
+ y: f.y - m.y * h
26
+ };
27
+ return { p0: u, p1: l, p2: p, p3: f };
28
+ }
29
+ function ve(e, t) {
30
+ return {
31
+ x: e.start.x + (e.end.x - e.start.x) * t,
32
+ y: e.start.y + (e.end.y - e.start.y) * t
33
+ };
34
+ }
35
+ function ee(e, t, n) {
36
+ const r = j(e.start, e.end);
37
+ let s;
38
+ return n ? s = t / 100 : s = r > 0 ? t / r : 0, s = Math.max(0, Math.min(1, s)), ve(e, s);
39
+ }
40
+ function ne(e, t) {
41
+ const { p0: n, p1: r, p2: s, p3: c } = e, o = 1 - t, i = o * o, f = i * o, a = t * t, u = a * t;
42
+ return {
43
+ x: f * n.x + 3 * i * t * r.x + 3 * o * a * s.x + u * c.x,
44
+ y: f * n.y + 3 * i * t * r.y + 3 * o * a * s.y + u * c.y
45
+ };
46
+ }
47
+ function xe(e, t = 100) {
48
+ const n = [{ t: 0, distance: 0 }];
49
+ let r = e.p0, s = 0;
50
+ for (let c = 1; c <= t; c++) {
51
+ const o = c / t, i = ne(e, o);
52
+ s += j(r, i), n.push({ t: o, distance: s }), r = i;
53
+ }
54
+ return n;
55
+ }
56
+ function ye(e, t) {
57
+ if (t <= 0) return 0;
58
+ const n = e[e.length - 1].distance;
59
+ if (t >= n) return 1;
60
+ let r = 0, s = e.length - 1;
61
+ for (; r < s - 1; ) {
62
+ const u = Math.floor((r + s) / 2);
63
+ e[u].distance < t ? r = u : s = u;
64
+ }
65
+ const c = e[r].distance, o = e[s].distance, i = e[r].t, f = e[s].t;
66
+ if (o === c) return i;
67
+ const a = (t - c) / (o - c);
68
+ return i + a * (f - i);
69
+ }
70
+ function je(e) {
71
+ return e[e.length - 1].distance;
72
+ }
73
+ function Me(e, t = 100) {
74
+ let n = 0, r = e.p0;
75
+ for (let s = 1; s <= t; s++) {
76
+ const c = s / t, o = ne(e, c);
77
+ n += j(r, o), r = o;
78
+ }
79
+ return n;
80
+ }
81
+ function ze(e, t, n, r) {
82
+ const s = j(e.start, e.end);
83
+ return t === void 0 ? r / 100 * s : n ? t / 100 * s : t;
84
+ }
85
+ function fe(e, t, n, r, s) {
86
+ const c = j(e.start, e.end), o = c - s;
87
+ if (o <= 0)
88
+ return c;
89
+ let i;
90
+ if (t === void 0)
91
+ i = r;
92
+ else if (n)
93
+ i = t;
94
+ else
95
+ return Math.max(s, Math.min(t, c));
96
+ return s + i / 100 * o;
97
+ }
98
+ function le(e, t, n, r, s) {
99
+ const o = j(e.start, e.end) - s;
100
+ if (o <= 0)
101
+ return 0;
102
+ let i;
103
+ if (t === void 0)
104
+ i = r;
105
+ else if (n)
106
+ i = t;
107
+ else
108
+ return Math.max(0, Math.min(t, o));
109
+ return i / 100 * o;
110
+ }
111
+ function Le(e, t, n) {
112
+ const r = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map();
113
+ for (const o of e)
114
+ s.set(o.id, o), c.set(o.id, j(o.start, o.end)), r.set(o.id, []);
115
+ for (let o = 0; o < t.length; o++) {
116
+ const i = t[o], f = s.get(i.fromLineId), a = s.get(i.toLineId);
117
+ if (!f || !a) continue;
118
+ const u = fe(f, i.fromOffset, i.fromIsPercentage, 100, n.wheelbase), d = le(a, i.toOffset, i.toIsPercentage, 0, n.wheelbase), m = ue(
119
+ f,
120
+ a,
121
+ n,
122
+ !1,
123
+ // willFlip is always false now
124
+ {
125
+ fromOffset: u,
126
+ fromIsPercentage: !1,
127
+ // Already resolved to absolute
128
+ toOffset: d,
129
+ toIsPercentage: !1
130
+ // Already resolved to absolute
131
+ }
132
+ ), I = Me(m), h = {
133
+ curveIndex: o,
134
+ fromLineId: i.fromLineId,
135
+ toLineId: i.toLineId,
136
+ fromOffset: u,
137
+ toOffset: d,
138
+ curveLength: I
139
+ };
140
+ r.get(i.fromLineId).push(h);
141
+ }
142
+ return { adjacency: r, lines: s, lineLengths: c };
143
+ }
144
+ function de(e, t, n, r, s = !1) {
145
+ const { adjacency: c, lines: o, lineLengths: i } = e;
146
+ if (!o.get(n)) return null;
147
+ const a = i.get(n), u = s ? r / 100 * a : r, d = [], m = /* @__PURE__ */ new Map(), I = (l, p) => `${l}:${Math.round(p)}`;
148
+ if (t.lineId === n && u >= t.offset) {
149
+ const l = u - t.offset;
150
+ return {
151
+ segments: [{
152
+ type: "line",
153
+ lineId: t.lineId,
154
+ startOffset: t.offset,
155
+ endOffset: u,
156
+ length: l
157
+ }],
158
+ totalDistance: l
159
+ };
160
+ }
161
+ const h = c.get(t.lineId) || [];
162
+ for (const l of h) {
163
+ if (l.fromOffset < t.offset) continue;
164
+ const p = l.fromOffset - t.offset, S = p + l.curveLength, M = {
165
+ type: "line",
166
+ lineId: t.lineId,
167
+ startOffset: t.offset,
168
+ endOffset: l.fromOffset,
169
+ length: p
170
+ }, g = {
171
+ type: "curve",
172
+ curveIndex: l.curveIndex,
173
+ startOffset: 0,
174
+ endOffset: l.curveLength,
175
+ length: l.curveLength
176
+ };
177
+ d.push({
178
+ lineId: l.toLineId,
179
+ entryOffset: l.toOffset,
180
+ totalDistance: S,
181
+ path: [M, g]
182
+ });
183
+ }
184
+ for (d.sort((l, p) => l.totalDistance - p.totalDistance); d.length > 0; ) {
185
+ const l = d.shift(), p = I(l.lineId, l.entryOffset), S = m.get(p);
186
+ if (S !== void 0 && S <= l.totalDistance)
187
+ continue;
188
+ if (m.set(p, l.totalDistance), l.lineId === n) {
189
+ const g = Math.abs(u - l.entryOffset);
190
+ if (u >= l.entryOffset) {
191
+ const v = {
192
+ type: "line",
193
+ lineId: n,
194
+ startOffset: l.entryOffset,
195
+ endOffset: u,
196
+ length: g
197
+ };
198
+ return {
199
+ segments: [...l.path, v],
200
+ totalDistance: l.totalDistance + g
201
+ };
202
+ }
203
+ }
204
+ const M = c.get(l.lineId) || [];
205
+ for (const g of M) {
206
+ if (g.fromOffset < l.entryOffset) continue;
207
+ const v = g.fromOffset - l.entryOffset, O = l.totalDistance + v + g.curveLength, C = I(g.toLineId, g.toOffset), E = m.get(C);
208
+ if (E !== void 0 && E <= O)
209
+ continue;
210
+ const D = {
211
+ type: "line",
212
+ lineId: l.lineId,
213
+ startOffset: l.entryOffset,
214
+ endOffset: g.fromOffset,
215
+ length: v
216
+ }, x = {
217
+ type: "curve",
218
+ curveIndex: g.curveIndex,
219
+ startOffset: 0,
220
+ endOffset: g.curveLength,
221
+ length: g.curveLength
222
+ };
223
+ d.push({
224
+ lineId: g.toLineId,
225
+ entryOffset: g.toOffset,
226
+ totalDistance: O,
227
+ path: [...l.path, D, x]
228
+ });
229
+ }
230
+ d.sort((g, v) => g.totalDistance - v.totalDistance);
231
+ }
232
+ return null;
233
+ }
234
+ function Je(e, t, n, r, s = !1) {
235
+ return de(e, t, n, r, s) !== null;
236
+ }
237
+ function Ke(e, t, n) {
238
+ return (e.adjacency.get(t) || []).filter((s) => s.fromOffset >= n);
239
+ }
240
+ function me(e, t) {
241
+ const n = Math.sqrt(
242
+ Math.pow(e.end.x - e.start.x, 2) + Math.pow(e.end.y - e.start.y, 2)
243
+ ), r = n > 0 ? t / n : 0;
244
+ return {
245
+ x: e.start.x + (e.end.x - e.start.x) * Math.min(1, Math.max(0, r)),
246
+ y: e.start.y + (e.end.y - e.start.y) * Math.min(1, Math.max(0, r))
247
+ };
248
+ }
249
+ function Oe(e) {
250
+ return Math.sqrt(
251
+ Math.pow(e.end.x - e.start.x, 2) + Math.pow(e.end.y - e.start.y, 2)
252
+ );
253
+ }
254
+ function Se(e, t, n) {
255
+ let r = 0;
256
+ for (let s = 0; s < t; s++)
257
+ r += e.segments[s].length;
258
+ return r += n, r;
259
+ }
260
+ function Ce(e, t) {
261
+ let n = 0;
262
+ for (let r = 0; r < e.segments.length; r++) {
263
+ const s = e.segments[r], c = n + s.length;
264
+ if (t < c)
265
+ return {
266
+ segmentIndex: r,
267
+ segmentDistance: t - n
268
+ };
269
+ if (t === c)
270
+ return r + 1 < e.segments.length ? {
271
+ segmentIndex: r + 1,
272
+ segmentDistance: 0
273
+ } : {
274
+ segmentIndex: r,
275
+ segmentDistance: s.length
276
+ };
277
+ n += s.length;
278
+ }
279
+ return null;
280
+ }
281
+ function te(e, t, n, r) {
282
+ const c = Se(
283
+ e,
284
+ t,
285
+ n
286
+ ) + r;
287
+ return Ce(e, c);
288
+ }
289
+ function ge(e, t, n) {
290
+ const r = e.execution, s = n.vehicleQueues.get(e.vehicle.id), c = s?.[r.currentCommandIndex];
291
+ if (c && n.onCommandComplete && n.onCommandComplete({
292
+ vehicleId: e.vehicle.id,
293
+ command: c,
294
+ finalPosition: {
295
+ lineId: e.vehicle.rear.lineId,
296
+ absoluteOffset: e.vehicle.rear.absoluteOffset,
297
+ position: e.vehicle.rear.position
298
+ },
299
+ payload: c.payload
300
+ }), c?.awaitConfirmation)
301
+ return {
302
+ handled: !0,
303
+ vehicle: { ...e.vehicle, state: "waiting" },
304
+ newExecution: r,
305
+ // Keep execution state for resume
306
+ isWaiting: !0
307
+ };
308
+ const o = r.currentCommandIndex + 1;
309
+ if (s && o < s.length) {
310
+ const f = s[o], a = n.graphRef.current;
311
+ if (a) {
312
+ const u = {
313
+ graph: a,
314
+ linesMap: n.linesMap,
315
+ curves: n.curves,
316
+ config: n.config
317
+ }, d = n.prepareCommandPath(
318
+ e.vehicle,
319
+ f,
320
+ u
321
+ );
322
+ if (d) {
323
+ const m = te(
324
+ d.path,
325
+ 0,
326
+ t,
327
+ n.config.wheelbase
328
+ ), I = {
329
+ path: d.path,
330
+ curveDataMap: d.curveDataMap,
331
+ currentCommandIndex: o,
332
+ rear: {
333
+ currentSegmentIndex: 0,
334
+ segmentDistance: t
335
+ },
336
+ front: m ? {
337
+ currentSegmentIndex: m.segmentIndex,
338
+ segmentDistance: m.segmentDistance
339
+ } : {
340
+ currentSegmentIndex: 0,
341
+ segmentDistance: t
342
+ }
343
+ };
344
+ return { handled: !0, vehicle: { ...e.vehicle, state: "moving" }, newExecution: I };
345
+ }
346
+ }
347
+ }
348
+ return { handled: !0, vehicle: {
349
+ ...e.vehicle,
350
+ state: "idle"
351
+ }, newExecution: null };
352
+ }
353
+ function Ge(e, t) {
354
+ const n = e.execution;
355
+ return n ? n.rear.currentSegmentIndex >= n.path.segments.length ? ge(e, n.rear.segmentDistance, t) : { handled: !1, vehicle: e.vehicle } : { handled: !1, vehicle: e.vehicle };
356
+ }
357
+ function W(e, t) {
358
+ return { position: me(e, t), lineId: e.id, absoluteOffset: t };
359
+ }
360
+ function H(e, t) {
361
+ const n = ye(e.arcLengthTable, t);
362
+ return { position: ne(e.bezier, n) };
363
+ }
364
+ function se(e, t, n, r, s, c, o) {
365
+ const i = n.segments[t.currentSegmentIndex], f = t.segmentDistance + r;
366
+ if (f >= i.length) {
367
+ const u = f - i.length, d = t.currentSegmentIndex + 1;
368
+ if (d >= n.segments.length) {
369
+ if (o !== void 0 && i.type === "line") {
370
+ const l = s.get(i.lineId), p = i.startOffset + f;
371
+ if (p <= o) {
372
+ const M = W(l, p);
373
+ return {
374
+ axleState: { ...e, ...M },
375
+ execution: { ...t, segmentDistance: f },
376
+ completed: !1
377
+ };
378
+ }
379
+ const S = W(l, o);
380
+ return {
381
+ axleState: { ...e, ...S },
382
+ execution: { ...t, segmentDistance: o - i.startOffset },
383
+ completed: !0
384
+ };
385
+ }
386
+ const h = i.type === "line" ? W(
387
+ s.get(i.lineId),
388
+ i.endOffset
389
+ ) : H(
390
+ c.get(i.curveIndex),
391
+ i.length
392
+ );
393
+ return {
394
+ axleState: { ...e, ...h },
395
+ execution: { ...t, segmentDistance: i.length },
396
+ completed: !0
397
+ };
398
+ }
399
+ const m = n.segments[d], I = m.type === "line" ? W(
400
+ s.get(m.lineId),
401
+ m.startOffset + u
402
+ ) : H(
403
+ c.get(m.curveIndex),
404
+ u
405
+ );
406
+ return {
407
+ axleState: { ...e, ...I },
408
+ execution: {
409
+ currentSegmentIndex: d,
410
+ segmentDistance: u
411
+ },
412
+ completed: !1
413
+ };
414
+ }
415
+ const a = i.type === "line" ? W(
416
+ s.get(i.lineId),
417
+ i.startOffset + f
418
+ ) : H(
419
+ c.get(i.curveIndex),
420
+ f
421
+ );
422
+ return {
423
+ axleState: { ...e, ...a },
424
+ execution: { ...t, segmentDistance: f },
425
+ completed: !1
426
+ };
427
+ }
428
+ function De(e, t, n, r) {
429
+ const s = Math.sqrt(
430
+ Math.pow(r.end.x - r.start.x, 2) + Math.pow(r.end.y - r.start.y, 2)
431
+ );
432
+ let c = t + n;
433
+ c = Math.min(c, s);
434
+ const o = me(r, c);
435
+ return {
436
+ lineId: e,
437
+ position: o,
438
+ absoluteOffset: c
439
+ };
440
+ }
441
+ function we(e, t) {
442
+ return {
443
+ ...e,
444
+ state: "idle"
445
+ };
446
+ }
447
+ function Te(e) {
448
+ return {
449
+ vehicle: e,
450
+ execution: null
451
+ };
452
+ }
453
+ function oe(e, t) {
454
+ const n = [], r = /* @__PURE__ */ new Map();
455
+ for (const s of e) {
456
+ if (!t.get(s.lineId)) continue;
457
+ const o = we(s);
458
+ n.push(o);
459
+ const i = Te(o);
460
+ r.set(s.id, i);
461
+ }
462
+ return { movingVehicles: n, stateMap: r };
463
+ }
464
+ function Pe(e, t, n, r) {
465
+ const s = /* @__PURE__ */ new Map();
466
+ for (const c of e.segments)
467
+ if (c.type === "curve" && c.curveIndex !== void 0) {
468
+ const o = t[c.curveIndex];
469
+ if (o) {
470
+ const i = n.get(o.fromLineId), f = n.get(o.toLineId);
471
+ if (i && f) {
472
+ const a = fe(
473
+ i,
474
+ o.fromOffset,
475
+ o.fromIsPercentage,
476
+ 100,
477
+ r.wheelbase
478
+ ), u = le(
479
+ f,
480
+ o.toOffset,
481
+ o.toIsPercentage,
482
+ 0,
483
+ r.wheelbase
484
+ ), d = ue(
485
+ i,
486
+ f,
487
+ r,
488
+ !1,
489
+ // willFlip is always false now
490
+ {
491
+ fromOffset: a,
492
+ fromIsPercentage: !1,
493
+ // Already resolved to absolute
494
+ toOffset: u,
495
+ toIsPercentage: !1
496
+ // Already resolved to absolute
497
+ }
498
+ ), m = xe(d);
499
+ s.set(c.curveIndex, { bezier: d, arcLengthTable: m });
500
+ }
501
+ }
502
+ }
503
+ return s;
504
+ }
505
+ function X(e, t, n) {
506
+ const { graph: r, linesMap: s, curves: c, config: o } = n, i = s.get(t.targetLineId);
507
+ if (!i) return null;
508
+ const a = Oe(i) - o.wheelbase;
509
+ if (a <= 0) return null;
510
+ const u = t.isPercentage ? t.targetOffset / 100 * a : Math.min(t.targetOffset, a), d = de(
511
+ r,
512
+ { lineId: e.lineId, offset: e.rear.absoluteOffset },
513
+ t.targetLineId,
514
+ u,
515
+ !1
516
+ );
517
+ if (!d) return null;
518
+ const m = Pe(d, c, s, o);
519
+ return { path: d, curveDataMap: m };
520
+ }
521
+ function Ue({
522
+ vehicles: e,
523
+ lines: t,
524
+ vehicleQueues: n,
525
+ velocity: r,
526
+ wheelbase: s,
527
+ tangentMode: c,
528
+ curves: o,
529
+ eventEmitter: i
530
+ }) {
531
+ const [f, a] = L("stopped"), [u, d] = L([]), m = Z(() => ({
532
+ wheelbase: s,
533
+ tangentMode: c
534
+ }), [s, c]), I = Z(
535
+ () => new Map(t.map((x) => [x.id, x])),
536
+ [t]
537
+ ), h = P(null), l = P(/* @__PURE__ */ new Map());
538
+ b(() => {
539
+ const { movingVehicles: x, stateMap: y } = oe(e, I);
540
+ l.current = y;
541
+ const w = setTimeout(() => {
542
+ d(x);
543
+ }, 0);
544
+ return () => clearTimeout(w);
545
+ }, [e, I]);
546
+ const p = P(null);
547
+ b(() => {
548
+ t.length > 0 && (p.current = Le(t, o, m));
549
+ }, [t, o, m]);
550
+ const S = P(!1), M = P(() => {
551
+ }), g = P(0), v = P(/* @__PURE__ */ new Set());
552
+ b(() => {
553
+ M.current = () => {
554
+ const x = r;
555
+ let y = !1;
556
+ for (const [, w] of l.current)
557
+ w.vehicle.state === "moving" && (y = !0);
558
+ if (!y) {
559
+ S.current = !1, g.current = 0;
560
+ return;
561
+ }
562
+ d((w) => w.map((q) => {
563
+ const T = l.current.get(q.id);
564
+ if (!T || q.state !== "moving" || !T.execution)
565
+ return q;
566
+ const $ = T.execution;
567
+ let A;
568
+ if ($.front.currentSegmentIndex < $.path.segments.length) {
569
+ const N = $.path.segments[$.front.currentSegmentIndex];
570
+ if (N.type === "line") {
571
+ const V = I.get(N.lineId);
572
+ V && (A = Math.sqrt(
573
+ Math.pow(V.end.x - V.start.x, 2) + Math.pow(V.end.y - V.start.y, 2)
574
+ ));
575
+ }
576
+ }
577
+ const F = se(
578
+ q.rear,
579
+ $.rear,
580
+ $.path,
581
+ x,
582
+ I,
583
+ $.curveDataMap
584
+ ), R = se(
585
+ q.front,
586
+ $.front,
587
+ $.path,
588
+ x,
589
+ I,
590
+ $.curveDataMap,
591
+ A
592
+ );
593
+ if (F.completed) {
594
+ const N = {
595
+ linesMap: I,
596
+ config: m,
597
+ vehicleQueues: n,
598
+ curves: o,
599
+ graphRef: p,
600
+ prepareCommandPath: X,
601
+ onCommandComplete: i ? (K) => i.emit("commandComplete", K) : void 0
602
+ }, V = {
603
+ ...q,
604
+ rear: F.axleState,
605
+ front: R.axleState
606
+ };
607
+ T.vehicle = V, T.execution.rear = F.execution, T.execution.front = R.execution;
608
+ const re = F.execution.segmentDistance, J = ge(T, re, N);
609
+ if (T.vehicle = J.vehicle, J.newExecution !== void 0 && (T.execution = J.newExecution), i) {
610
+ const K = J.vehicle.rear.position, U = J.vehicle.front.position;
611
+ i.emit("positionUpdate", {
612
+ vehicleId: J.vehicle.id,
613
+ rear: K,
614
+ front: U,
615
+ center: {
616
+ x: (K.x + U.x) / 2,
617
+ y: (K.y + U.y) / 2
618
+ },
619
+ angle: Math.atan2(U.y - K.y, U.x - K.x)
620
+ });
621
+ }
622
+ return J.vehicle;
623
+ }
624
+ const z = {
625
+ ...q,
626
+ rear: F.axleState,
627
+ front: R.axleState
628
+ };
629
+ if (T.vehicle = z, T.execution.rear = F.execution, T.execution.front = R.execution, i) {
630
+ const N = z.rear.position, V = z.front.position;
631
+ i.emit("positionUpdate", {
632
+ vehicleId: z.id,
633
+ rear: N,
634
+ front: V,
635
+ center: {
636
+ x: (N.x + V.x) / 2,
637
+ y: (N.y + V.y) / 2
638
+ },
639
+ angle: Math.atan2(V.y - N.y, V.x - N.x)
640
+ });
641
+ }
642
+ return z;
643
+ })), S.current && (h.current = requestAnimationFrame(() => M.current()));
644
+ };
645
+ }, [r, I, o, m, n, i]), b(() => (f === "running" ? (S.current = !0, h.current = requestAnimationFrame(() => M.current())) : S.current = !1, () => {
646
+ h.current && cancelAnimationFrame(h.current);
647
+ }), [f]);
648
+ const O = G(() => {
649
+ if (f === "running") return;
650
+ const x = p.current;
651
+ x && (g.current = 0, v.current.clear(), d((y) => y.map((w) => {
652
+ const q = n.get(w.id);
653
+ if (!q || q.length === 0)
654
+ return w;
655
+ const T = q[0], A = X(
656
+ w,
657
+ T,
658
+ { graph: x, linesMap: I, curves: o, config: m }
659
+ );
660
+ if (!A)
661
+ return console.warn(`No path found for vehicle ${w.id}`), w;
662
+ const F = l.current.get(w.id);
663
+ if (F) {
664
+ const R = te(
665
+ A.path,
666
+ 0,
667
+ 0,
668
+ s
669
+ );
670
+ F.execution = {
671
+ path: A.path,
672
+ curveDataMap: A.curveDataMap,
673
+ currentCommandIndex: 0,
674
+ rear: {
675
+ currentSegmentIndex: 0,
676
+ segmentDistance: 0
677
+ },
678
+ front: R ? {
679
+ currentSegmentIndex: R.segmentIndex,
680
+ segmentDistance: R.segmentDistance
681
+ } : {
682
+ currentSegmentIndex: 0,
683
+ segmentDistance: 0
684
+ }
685
+ }, F.vehicle = { ...w, state: "moving" };
686
+ }
687
+ return { ...w, state: "moving" };
688
+ })), a("running"));
689
+ }, [f, I, o, n, m, s]), C = G(() => {
690
+ h.current && (cancelAnimationFrame(h.current), h.current = null), a("paused");
691
+ }, []), E = G(() => {
692
+ h.current && (cancelAnimationFrame(h.current), h.current = null);
693
+ const { movingVehicles: x, stateMap: y } = oe(e, I);
694
+ l.current = y, d(x), a("stopped");
695
+ }, [e, I]), D = G((x) => {
696
+ const y = l.current.get(x);
697
+ if (!y || y.vehicle.state !== "waiting")
698
+ return !1;
699
+ const w = n.get(x), q = y.execution;
700
+ if (!q) return !1;
701
+ const T = q.currentCommandIndex + 1;
702
+ if (w && T < w.length) {
703
+ const $ = p.current;
704
+ if ($) {
705
+ const A = w[T], F = { graph: $, linesMap: I, curves: o, config: m }, R = X(y.vehicle, A, F);
706
+ if (R) {
707
+ const z = te(R.path, 0, 0, s);
708
+ return y.execution = {
709
+ path: R.path,
710
+ curveDataMap: R.curveDataMap,
711
+ currentCommandIndex: T,
712
+ rear: { currentSegmentIndex: 0, segmentDistance: 0 },
713
+ front: z ? { currentSegmentIndex: z.segmentIndex, segmentDistance: z.segmentDistance } : { currentSegmentIndex: 0, segmentDistance: 0 }
714
+ }, y.vehicle = { ...y.vehicle, state: "moving" }, d((N) => N.map((V) => V.id === x ? y.vehicle : V)), f !== "running" && a("running"), !0;
715
+ }
716
+ }
717
+ }
718
+ return y.vehicle = { ...y.vehicle, state: "idle" }, y.execution = null, d(($) => $.map((A) => A.id === x ? y.vehicle : A)), !0;
719
+ }, [n, I, o, m, s, f]);
720
+ return {
721
+ movingVehicles: u,
722
+ playbackState: f,
723
+ handleRun: O,
724
+ handlePause: C,
725
+ handleReset: E,
726
+ continueVehicle: D
727
+ };
728
+ }
729
+ class $e {
730
+ listeners = /* @__PURE__ */ new Map();
731
+ /**
732
+ * Subscribe to an event
733
+ * @param event - The event type to listen for
734
+ * @param callback - Function to call when event is emitted
735
+ * @returns Unsubscribe function
736
+ */
737
+ on(t, n) {
738
+ return this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(n), () => {
739
+ this.listeners.get(t)?.delete(n);
740
+ };
741
+ }
742
+ /**
743
+ * Emit an event to all subscribers
744
+ * @param event - The event type to emit
745
+ * @param data - The event data
746
+ */
747
+ emit(t, n) {
748
+ this.listeners.get(t)?.forEach((r) => {
749
+ try {
750
+ r(n);
751
+ } catch (s) {
752
+ console.error(`Error in event listener for "${t}":`, s);
753
+ }
754
+ });
755
+ }
756
+ /**
757
+ * Remove all listeners for a specific event, or all events if no event specified
758
+ * @param event - Optional event type to clear listeners for
759
+ */
760
+ off(t) {
761
+ t ? this.listeners.delete(t) : this.listeners.clear();
762
+ }
763
+ /**
764
+ * Get the number of listeners for a specific event
765
+ * @param event - The event type
766
+ * @returns Number of listeners
767
+ */
768
+ listenerCount(t) {
769
+ return this.listeners.get(t)?.size ?? 0;
770
+ }
771
+ }
772
+ const Ve = he(null);
773
+ function be() {
774
+ const e = pe(Ve);
775
+ if (!e)
776
+ throw new Error("useVehicleEventEmitter must be used within a VehicleEventProvider");
777
+ return e;
778
+ }
779
+ function We() {
780
+ return Z(() => new $e(), []);
781
+ }
782
+ function Be(e, t, n = []) {
783
+ const r = be();
784
+ b(() => r.on(e, t), [r, e, ...n]);
785
+ }
786
+ function ie(e) {
787
+ const t = [], n = [], r = [], s = e.trim().split(`
788
+ `);
789
+ for (const c of s) {
790
+ const o = c.trim();
791
+ if (!o || o.startsWith("#")) continue;
792
+ const i = o.match(/^(\w+)\s*:\s*\((\d+),\s*(\d+)\)\s*->\s*\((\d+),\s*(\d+)\)/);
793
+ if (i) {
794
+ t.push({
795
+ id: i[1],
796
+ start: { x: parseInt(i[2]), y: parseInt(i[3]) },
797
+ end: { x: parseInt(i[4]), y: parseInt(i[5]) }
798
+ });
799
+ continue;
800
+ }
801
+ const f = o.match(/^(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))??\s*->\s*(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))?/);
802
+ if (f) {
803
+ const u = {
804
+ fromLineId: f[1],
805
+ toLineId: f[4]
806
+ };
807
+ f[2] && (u.fromOffset = parseFloat(f[2]), u.fromIsPercentage = f[3] === "%"), f[5] && (u.toOffset = parseFloat(f[5]), u.toIsPercentage = f[6] === "%"), n.push(u);
808
+ continue;
809
+ }
810
+ const a = o.match(/^(\w+)\s+start\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);
811
+ if (a) {
812
+ const u = parseFloat(a[3]), d = a[4] === "%";
813
+ r.push({
814
+ vehicleId: a[1],
815
+ lineId: a[2],
816
+ offset: u,
817
+ isPercentage: d
818
+ });
819
+ continue;
820
+ }
821
+ }
822
+ return { lines: t, curves: n, vehicles: r };
823
+ }
824
+ function Ee(e) {
825
+ const t = [];
826
+ return e.lines.forEach((n) => {
827
+ t.push(`${n.id} : (${Math.round(n.start.x)}, ${Math.round(n.start.y)}) -> (${Math.round(n.end.x)}, ${Math.round(n.end.y)})`);
828
+ }), e.lines.length > 0 && e.curves.length > 0 && t.push(""), e.curves.forEach((n) => {
829
+ let r = `${n.fromLineId}`;
830
+ n.fromOffset !== void 0 && (r += ` ${n.fromOffset}${n.fromIsPercentage ? "%" : ""}`), r += " -> ", r += `${n.toLineId}`, n.toOffset !== void 0 && (r += ` ${n.toOffset}${n.toIsPercentage ? "%" : ""}`), t.push(r);
831
+ }), (e.lines.length > 0 || e.curves.length > 0) && e.vehicles.length > 0 && t.push(""), e.vehicles.forEach((n) => {
832
+ const r = n.isPercentage ? `${n.offset}%` : `${n.offset}`;
833
+ t.push(`${n.vehicleId} start ${n.lineId} ${r}`);
834
+ }), t.join(`
835
+ `);
836
+ }
837
+ function B(e) {
838
+ const t = [], n = e.trim().split(`
839
+ `);
840
+ for (const r of n) {
841
+ const s = r.trim();
842
+ if (!s || s.startsWith("#")) continue;
843
+ const c = s.match(/^(\w+)\s+start\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);
844
+ c && t.push({
845
+ vehicleId: c[1],
846
+ lineId: c[2],
847
+ offset: parseFloat(c[3]),
848
+ isPercentage: c[4] === "%"
849
+ });
850
+ }
851
+ return t;
852
+ }
853
+ function qe(e) {
854
+ return e.map((t) => {
855
+ const n = t.isPercentage ? `${t.offset}%` : `${t.offset}`;
856
+ return `${t.vehicleId} start ${t.lineId} ${n}`;
857
+ }).join(`
858
+ `);
859
+ }
860
+ function Y(e) {
861
+ const t = [], n = e.trim().split(`
862
+ `);
863
+ for (const r of n) {
864
+ const s = r.trim();
865
+ if (!s || s.startsWith("#")) continue;
866
+ const c = s.match(/^(\w+)\s+goto\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);
867
+ if (c) {
868
+ const o = s.slice(c[0].length), i = o.includes("--wait");
869
+ let f;
870
+ const a = o.match(/--payload\s+(\{.*\})/);
871
+ if (a)
872
+ try {
873
+ f = JSON.parse(a[1]);
874
+ } catch {
875
+ console.warn(`Invalid JSON payload in goto command: ${a[1]}`);
876
+ }
877
+ t.push({
878
+ vehicleId: c[1],
879
+ targetLineId: c[2],
880
+ targetOffset: parseFloat(c[3]),
881
+ isPercentage: c[4] === "%",
882
+ awaitConfirmation: i,
883
+ payload: f
884
+ });
885
+ }
886
+ }
887
+ return t;
888
+ }
889
+ function Re(e) {
890
+ return e.map((t) => {
891
+ const n = t.isPercentage ? `${t.targetOffset}%` : `${t.targetOffset}`, r = t.awaitConfirmation ? " --wait" : "", s = t.payload !== void 0 ? ` --payload ${JSON.stringify(t.payload)}` : "";
892
+ return `${t.vehicleId} goto ${t.targetLineId} ${n}${r}${s}`;
893
+ }).join(`
894
+ `);
895
+ }
896
+ function ke() {
897
+ const [e, t] = L([]), [n, r] = L([]), [s, c] = L(""), [o, i] = L(null), [f, a] = L(!1), [u, d] = L(0), m = P(!1), I = P("");
898
+ return b(() => {
899
+ I.current = s;
900
+ }, [s]), b(() => {
901
+ if (m.current)
902
+ return;
903
+ const h = ie(I.current), l = Ee({
904
+ lines: e,
905
+ curves: n,
906
+ vehicles: h.vehicles
907
+ });
908
+ l !== I.current && (m.current = !0, c(l), setTimeout(() => {
909
+ m.current = !1;
910
+ }, 50));
911
+ }, [e, n]), b(() => {
912
+ if (m.current)
913
+ return;
914
+ const h = setTimeout(() => {
915
+ a(!0), d((p) => p + 1);
916
+ }, 0), l = setTimeout(() => {
917
+ try {
918
+ const p = ie(s);
919
+ a(!1);
920
+ const S = JSON.stringify(p.lines) !== JSON.stringify(e), M = JSON.stringify(p.curves) !== JSON.stringify(n);
921
+ (S || M) && (m.current = !0, S && t(p.lines), M && r(p.curves), setTimeout(() => {
922
+ m.current = !1;
923
+ }, 100)), i(null);
924
+ } catch (p) {
925
+ a(!1), i(p instanceof Error ? p.message : "Invalid scene definition");
926
+ }
927
+ }, 2e3);
928
+ return () => {
929
+ clearTimeout(h), clearTimeout(l);
930
+ };
931
+ }, [s, e, n]), {
932
+ lines: e,
933
+ curves: n,
934
+ sceneDefinitionText: s,
935
+ sceneError: o,
936
+ isDebouncing: f,
937
+ debounceKey: u,
938
+ setLines: t,
939
+ setCurves: r,
940
+ setSceneDefinitionText: c
941
+ };
942
+ }
943
+ function k(e, t, n = 0) {
944
+ const r = [], s = [], c = /* @__PURE__ */ new Set();
945
+ for (const o of e) {
946
+ if (c.has(o.vehicleId)) {
947
+ s.push(`Duplicate vehicle ID: ${o.vehicleId}`);
948
+ continue;
949
+ }
950
+ c.add(o.vehicleId);
951
+ const i = t.find((h) => h.id === o.lineId);
952
+ if (!i) {
953
+ s.push(`Vehicle ${o.vehicleId}: Line "${o.lineId}" not found`);
954
+ continue;
955
+ }
956
+ const f = j(i.start, i.end), a = Math.max(0, f - n);
957
+ let u;
958
+ if (o.isPercentage) {
959
+ if (o.offset < 0 || o.offset > 100) {
960
+ s.push(`Vehicle ${o.vehicleId}: Offset ${o.offset}% must be between 0% and 100%`);
961
+ continue;
962
+ }
963
+ u = o.offset / 100 * a;
964
+ } else {
965
+ if (o.offset < 0 || o.offset > f) {
966
+ s.push(`Vehicle ${o.vehicleId}: Offset ${o.offset} exceeds line length ${f.toFixed(2)}`);
967
+ continue;
968
+ }
969
+ u = Math.min(o.offset, a);
970
+ }
971
+ const d = ee(i, u, !1), m = {
972
+ lineId: o.lineId,
973
+ position: d,
974
+ absoluteOffset: u
975
+ }, I = De(
976
+ o.lineId,
977
+ u,
978
+ n,
979
+ i
980
+ );
981
+ r.push({
982
+ id: o.vehicleId,
983
+ lineId: o.lineId,
984
+ offset: o.offset,
985
+ isPercentage: o.isPercentage,
986
+ state: "idle",
987
+ rear: m,
988
+ front: I
989
+ });
990
+ }
991
+ return { vehicles: r, errors: s };
992
+ }
993
+ function Ae(e) {
994
+ const t = e.map((r) => {
995
+ const s = r.vehicleId.match(/^v(\d+)$/);
996
+ return s ? parseInt(s[1]) : 0;
997
+ }).filter((r) => r > 0);
998
+ return `v${(t.length > 0 ? Math.max(...t) : 0) + 1}`;
999
+ }
1000
+ function _(e, t, n) {
1001
+ const r = [], s = [], c = /* @__PURE__ */ new Map(), o = new Set(t.map((a) => a.id)), i = new Set(n.map((a) => a.id)), f = new Map(n.map((a) => {
1002
+ const u = a.end.x - a.start.x, d = a.end.y - a.start.y;
1003
+ return [a.id, Math.sqrt(u * u + d * d)];
1004
+ }));
1005
+ for (const a of e) {
1006
+ if (!o.has(a.vehicleId)) {
1007
+ r.push(`Vehicle "${a.vehicleId}" does not exist`);
1008
+ continue;
1009
+ }
1010
+ if (!i.has(a.targetLineId)) {
1011
+ r.push(`Line "${a.targetLineId}" does not exist`);
1012
+ continue;
1013
+ }
1014
+ const u = f.get(a.targetLineId), d = a.isPercentage ? a.targetOffset / 100 * u : a.targetOffset;
1015
+ if (d < 0 || d > u) {
1016
+ r.push(`Offset ${a.targetOffset}${a.isPercentage ? "%" : ""} is out of bounds for ${a.targetLineId}`);
1017
+ continue;
1018
+ }
1019
+ s.push(a);
1020
+ const m = c.get(a.vehicleId) || [];
1021
+ m.push(a), c.set(a.vehicleId, m);
1022
+ }
1023
+ return { commands: s, errors: r, vehicleQueues: c };
1024
+ }
1025
+ function Fe(e, t) {
1026
+ if (t.length === 0) return null;
1027
+ if (e.length === 0)
1028
+ return t[0].id;
1029
+ const n = /* @__PURE__ */ new Map();
1030
+ for (const r of t)
1031
+ n.set(r.id, 0);
1032
+ for (const r of e) {
1033
+ const s = n.get(r.vehicleId) || 0;
1034
+ n.set(r.vehicleId, s + 1);
1035
+ }
1036
+ return t[0].id;
1037
+ }
1038
+ function Qe({ lines: e, wheelbase: t }) {
1039
+ const [n, r] = L([]), [s, c] = L(""), [o, i] = L(null), [f, a] = L(!1), [u, d] = L(0), m = P(!1), I = P(e), h = P(e), l = P(t), p = P(t);
1040
+ b(() => {
1041
+ I.current = e;
1042
+ }, [e]), b(() => {
1043
+ l.current = t;
1044
+ }, [t]), b(() => {
1045
+ if (m.current)
1046
+ return;
1047
+ const M = setTimeout(() => {
1048
+ a(!0), d((v) => v + 1);
1049
+ }, 0), g = setTimeout(() => {
1050
+ try {
1051
+ const v = B(s), { vehicles: O, errors: C } = k(
1052
+ v,
1053
+ I.current,
1054
+ l.current
1055
+ );
1056
+ a(!1), C.length > 0 ? (i(C.join(`
1057
+ `)), r(O)) : (i(null), r(O));
1058
+ } catch (v) {
1059
+ a(!1), i(v instanceof Error ? v.message : "Invalid initial movement"), r([]);
1060
+ }
1061
+ }, 2e3);
1062
+ return () => {
1063
+ clearTimeout(M), clearTimeout(g);
1064
+ };
1065
+ }, [s]), b(() => {
1066
+ if (!(JSON.stringify(h.current) !== JSON.stringify(e)) || (h.current = e, m.current || !s.trim()))
1067
+ return;
1068
+ const g = setTimeout(() => {
1069
+ try {
1070
+ const v = B(s), { vehicles: O, errors: C } = k(
1071
+ v,
1072
+ e,
1073
+ l.current
1074
+ );
1075
+ C.length > 0 ? (i(C.join(`
1076
+ `)), r(O)) : (i(null), r(O));
1077
+ } catch (v) {
1078
+ i(v instanceof Error ? v.message : "Invalid initial movement"), r([]);
1079
+ }
1080
+ }, 0);
1081
+ return () => clearTimeout(g);
1082
+ }, [e, s]), b(() => {
1083
+ if (p.current === t || (p.current = t, m.current || !s.trim()))
1084
+ return;
1085
+ const M = setTimeout(() => {
1086
+ try {
1087
+ const g = B(s), { vehicles: v, errors: O } = k(
1088
+ g,
1089
+ I.current,
1090
+ t
1091
+ );
1092
+ O.length > 0 ? (i(O.join(`
1093
+ `)), r(v)) : (i(null), r(v));
1094
+ } catch (g) {
1095
+ i(g instanceof Error ? g.message : "Invalid initial movement"), r([]);
1096
+ }
1097
+ }, 0);
1098
+ return () => clearTimeout(M);
1099
+ }, [t, s]);
1100
+ const S = G(() => {
1101
+ const M = B(s), g = Ae(M), v = e.length > 0 ? e[0] : null;
1102
+ if (!v) {
1103
+ i("No lines available. Please create at least one line first.");
1104
+ return;
1105
+ }
1106
+ const O = {
1107
+ vehicleId: g,
1108
+ lineId: v.id,
1109
+ offset: 0,
1110
+ isPercentage: !1
1111
+ }, C = [...M, O], E = qe(C), { vehicles: D, errors: x } = k(
1112
+ C,
1113
+ e,
1114
+ t
1115
+ );
1116
+ m.current = !0, c(E), x.length > 0 ? i(x.join(`
1117
+ `)) : i(null), r(D), setTimeout(() => {
1118
+ m.current = !1;
1119
+ }, 50);
1120
+ }, [s, e, t]);
1121
+ return {
1122
+ vehicles: n,
1123
+ initialMovementText: s,
1124
+ movementError: o,
1125
+ isDebouncing: f,
1126
+ debounceKey: u,
1127
+ setInitialMovementText: c,
1128
+ handleAddStartCommand: S
1129
+ };
1130
+ }
1131
+ function He({ lines: e, vehicles: t }) {
1132
+ const [n, r] = L(""), [s, c] = L([]), [o, i] = L(/* @__PURE__ */ new Map()), [f, a] = L(null), [u, d] = L(!1), [m, I] = L(0), h = P(!1), l = P(t), p = P(e);
1133
+ b(() => {
1134
+ l.current = t, p.current = e;
1135
+ }, [t, e]), b(() => {
1136
+ if (h.current)
1137
+ return;
1138
+ const M = setTimeout(() => {
1139
+ d(!0), I((v) => v + 1);
1140
+ }, 0), g = setTimeout(() => {
1141
+ try {
1142
+ const v = Y(n), { commands: O, errors: C, vehicleQueues: E } = _(
1143
+ v,
1144
+ l.current,
1145
+ p.current
1146
+ );
1147
+ d(!1), C.length > 0 ? a(C.join(`
1148
+ `)) : a(null), c(O), i(E);
1149
+ } catch (v) {
1150
+ d(!1), a(v instanceof Error ? v.message : "Invalid movement sequence"), c([]), i(/* @__PURE__ */ new Map());
1151
+ }
1152
+ }, 2e3);
1153
+ return () => {
1154
+ clearTimeout(M), clearTimeout(g);
1155
+ };
1156
+ }, [n]), b(() => {
1157
+ if (h.current || !n.trim())
1158
+ return;
1159
+ const M = setTimeout(() => {
1160
+ try {
1161
+ const g = Y(n), { commands: v, errors: O, vehicleQueues: C } = _(
1162
+ g,
1163
+ t,
1164
+ e
1165
+ );
1166
+ O.length > 0 ? a(O.join(`
1167
+ `)) : a(null), c(v), i(C);
1168
+ } catch (g) {
1169
+ a(g instanceof Error ? g.message : "Invalid movement sequence"), c([]), i(/* @__PURE__ */ new Map());
1170
+ }
1171
+ }, 0);
1172
+ return () => clearTimeout(M);
1173
+ }, [t, e, n]);
1174
+ const S = G(() => {
1175
+ if (t.length === 0) {
1176
+ a("No vehicles available. Please create at least one vehicle first.");
1177
+ return;
1178
+ }
1179
+ if (e.length === 0) {
1180
+ a("No lines available. Please create at least one line first.");
1181
+ return;
1182
+ }
1183
+ const M = Y(n), g = Fe(M, t);
1184
+ if (!g) {
1185
+ a("No vehicles available.");
1186
+ return;
1187
+ }
1188
+ const v = e[0], O = {
1189
+ vehicleId: g,
1190
+ targetLineId: v.id,
1191
+ targetOffset: 100,
1192
+ isPercentage: !0
1193
+ }, C = [...M, O], E = Re(C), { commands: D, errors: x, vehicleQueues: y } = _(
1194
+ C,
1195
+ t,
1196
+ e
1197
+ );
1198
+ h.current = !0, r(E), x.length > 0 ? a(x.join(`
1199
+ `)) : a(null), c(D), i(y), setTimeout(() => {
1200
+ h.current = !1;
1201
+ }, 50);
1202
+ }, [n, t, e]);
1203
+ return {
1204
+ movementSequenceText: n,
1205
+ gotoCommands: s,
1206
+ vehicleQueues: o,
1207
+ sequenceError: f,
1208
+ isDebouncing: u,
1209
+ debounceKey: m,
1210
+ setMovementSequenceText: r,
1211
+ handleAddGotoCommand: S
1212
+ };
1213
+ }
1214
+ function ce(e, t, n) {
1215
+ if (!t || !n) return { x: 0, y: 0 };
1216
+ const r = t.getBoundingClientRect();
1217
+ return {
1218
+ x: e.clientX - r.left,
1219
+ y: e.clientY - r.top
1220
+ };
1221
+ }
1222
+ function ae(e, t, n = 10) {
1223
+ for (const r of t) {
1224
+ if (j(e, r.start) < n)
1225
+ return { lineId: r.id, endpoint: "start" };
1226
+ if (j(e, r.end) < n)
1227
+ return { lineId: r.id, endpoint: "end" };
1228
+ }
1229
+ return null;
1230
+ }
1231
+ function Xe({
1232
+ canvasRef: e,
1233
+ containerRef: t,
1234
+ drawMode: n,
1235
+ lines: r,
1236
+ curves: s,
1237
+ setLines: c,
1238
+ setCurves: o,
1239
+ lineCounterRef: i
1240
+ }) {
1241
+ const [f, a] = L(!1), [u, d] = L(null), [m, I] = L(null), [h, l] = L(null), [p, S] = L(null), [M, g] = L({ x: 0, y: 0 });
1242
+ return {
1243
+ handleMouseDown: (E) => {
1244
+ const D = ce(E, e.current, t.current), x = ae(D, r);
1245
+ if (n === "line")
1246
+ x || (a(!0), d({ start: D, current: D }));
1247
+ else if (n === "drag")
1248
+ x && l(x);
1249
+ else if (n === "curve")
1250
+ if (x)
1251
+ if (!p)
1252
+ S(x);
1253
+ else {
1254
+ if (p.lineId !== x.lineId) {
1255
+ const y = {
1256
+ fromLineId: p.lineId,
1257
+ toLineId: x.lineId
1258
+ };
1259
+ o([...s, y]);
1260
+ }
1261
+ S(null);
1262
+ }
1263
+ else
1264
+ p && S(null);
1265
+ },
1266
+ handleMouseMove: (E) => {
1267
+ const D = ce(E, e.current, t.current);
1268
+ if (g(D), f && u)
1269
+ d({ ...u, current: D });
1270
+ else if (h) {
1271
+ const x = r.map((y) => y.id === h.lineId ? h.endpoint === "start" ? { ...y, start: D } : { ...y, end: D } : y);
1272
+ c(x);
1273
+ } else {
1274
+ const x = ae(D, r);
1275
+ I(x);
1276
+ }
1277
+ },
1278
+ handleMouseUp: () => {
1279
+ if (f && u) {
1280
+ if (j(u.start, u.current) > 20) {
1281
+ const D = {
1282
+ id: `line${String(i.current).padStart(3, "0")}`,
1283
+ start: u.start,
1284
+ end: u.current
1285
+ };
1286
+ i.current++, c([...r, D]);
1287
+ }
1288
+ d(null), a(!1);
1289
+ } else h && l(null);
1290
+ },
1291
+ tempLine: u,
1292
+ hoveredEndpoint: m,
1293
+ curveStart: p,
1294
+ mousePos: M
1295
+ };
1296
+ }
1297
+ export {
1298
+ Ve as VehicleEventContext,
1299
+ $e as VehicleEventEmitter,
1300
+ Ce as arcLengthToSegmentPosition,
1301
+ xe as buildArcLengthTable,
1302
+ Le as buildGraph,
1303
+ Me as calculateBezierArcLength,
1304
+ te as calculateFrontAxlePosition,
1305
+ De as calculateInitialFrontPosition,
1306
+ H as calculatePositionOnCurve,
1307
+ W as calculatePositionOnLine,
1308
+ Je as canReachTarget,
1309
+ Ge as checkRearCompletion,
1310
+ ue as createBezierCurve,
1311
+ Te as createInitialMovementState,
1312
+ j as distance,
1313
+ ye as distanceToT,
1314
+ de as findPath,
1315
+ Re as generateGotoCommands,
1316
+ Ee as generateSceneDefinition,
1317
+ qe as generateVehicleStarts,
1318
+ je as getArcLength,
1319
+ Se as getCumulativeArcLength,
1320
+ Oe as getLineLength,
1321
+ ne as getPointOnBezier,
1322
+ ve as getPointOnLine,
1323
+ ee as getPointOnLineByOffset,
1324
+ me as getPositionFromOffset,
1325
+ Ke as getReachableCurves,
1326
+ ge as handleArrival,
1327
+ oe as initializeAllVehicles,
1328
+ we as initializeMovingVehicle,
1329
+ Q as normalize,
1330
+ Y as parseGotoCommands,
1331
+ ie as parseSceneDefinition,
1332
+ B as parseVehicleStarts,
1333
+ X as prepareCommandPath,
1334
+ fe as resolveFromLineOffset,
1335
+ ze as resolveOffset,
1336
+ le as resolveToLineOffset,
1337
+ se as updateAxlePosition,
1338
+ Xe as useCanvasInteraction,
1339
+ We as useCreateVehicleEventEmitter,
1340
+ Qe as useInitialMovement,
1341
+ He as useMovementSequence,
1342
+ ke as useSceneDefinition,
1343
+ Be as useVehicleEvent,
1344
+ be as useVehicleEventEmitter,
1345
+ Ue as useVehicleMovement
1346
+ };