vehicle-path2 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.cjs +1 -1
- package/dist/core.js +48 -46
- package/dist/react.cjs +1 -1
- package/dist/react.js +1 -1
- package/dist/{useVehicleEvents-D69WkcSs.cjs → useVehicleEvents-B7Z-9Hn2.cjs} +1 -1
- package/dist/{useVehicleEvents-BOJPYrlM.js → useVehicleEvents-t_p-Bwhj.js} +1 -1
- package/dist/utils.cjs +1 -1
- package/dist/utils.js +1 -1
- package/dist/{vehicle-helpers-BXX3GPzk.js → vehicle-helpers-BYb2Ibex.js} +76 -76
- package/dist/{vehicle-helpers-82D2V4MI.cjs → vehicle-helpers-bgHGBdo9.cjs} +5 -5
- package/dist/vehicle-path.cjs +1 -1
- package/dist/vehicle-path.js +2 -2
- package/package.json +1 -1
package/dist/core.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function I(e,t){const s=t.x-e.x,n=t.y-e.y;return Math.sqrt(s*s+n*n)}function P(e,t){const s=t.x-e.x,n=t.y-e.y,o=Math.sqrt(s*s+n*n);return o===0?{x:0,y:0}:{x:s/o,y:n/o}}function V(e,t){return t*(e==="proportional-40"?.4:.5522)}function C(e,t,s,n=!1,o){const{wheelbase:c,tangentMode:r}=s;let i;o?.fromOffset!==void 0?i=D(e,o.fromOffset,o.fromIsPercentage??!1):i=e.end;let l;o?.toOffset!==void 0?l=D(t,o.toOffset,o.toIsPercentage??!1):l=t.start;const d=P(e.start,e.end),f=n?{x:i.x-d.x*c,y:i.y-d.y*c}:i,u=P(e.start,e.end),g=P(t.start,t.end),p=I(f,l),v=V(r,p),a=n?{x:f.x-u.x*v,y:f.y-u.y*v}:{x:f.x+u.x*v,y:f.y+u.y*v},m={x:l.x-g.x*v,y:l.y-g.y*v};return{p0:f,p1:a,p2:m,p3:l}}function B(e,t){return{x:e.start.x+(e.end.x-e.start.x)*t,y:e.start.y+(e.end.y-e.start.y)*t}}function D(e,t,s){const n=I(e.start,e.end);let o;return s?o=t:o=n>0?t/n:0,o=Math.max(0,Math.min(1,o)),B(e,o)}function w(e,t){const{p0:s,p1:n,p2:o,p3:c}=e,r=1-t,i=r*r,l=i*r,d=t*t,f=d*t;return{x:l*s.x+3*i*t*n.x+3*r*d*o.x+f*c.x,y:l*s.y+3*i*t*n.y+3*r*d*o.y+f*c.y}}function H(e,t,s=10){return I(e,t)<=s}function q(e,t=100){const s=[{t:0,distance:0}];let n=e.p0,o=0;for(let c=1;c<=t;c++){const r=c/t,i=w(e,r);o+=I(n,i),s.push({t:r,distance:o}),n=i}return s}function F(e,t){if(t<=0)return 0;const s=e[e.length-1].distance;if(t>=s)return 1;let n=0,o=e.length-1;for(;n<o-1;){const f=Math.floor((n+o)/2);e[f].distance<t?n=f:o=f}const c=e[n].distance,r=e[o].distance,i=e[n].t,l=e[o].t;if(r===c)return i;const d=(t-c)/(r-c);return i+d*(l-i)}function J(e){return e[e.length-1].distance}function j(e,t=100){let s=0,n=e.p0;for(let o=1;o<=t;o++){const c=o/t,r=w(e,c);s+=I(n,r),n=r}return s}function S(e,t,s,n,o){const c=I(e.start,e.end),r=c-o;if(r<=0)return c;let i;if(t===void 0)i=n;else if(s)i=t;else{const l=Math.max(0,Math.min(t,r));return o+l}return o+i*r}function T(e,t,s,n,o){const r=I(e.start,e.end)-o;if(r<=0)return 0;let i;if(t===void 0)i=n;else if(s)i=t;else return Math.max(0,Math.min(t,r));return i*r}function U(e,t,s){const n=new Map,o=new Map,c=new Map;for(const r of e)o.set(r.id,r),c.set(r.id,I(r.start,r.end)),n.set(r.id,[]);for(let r=0;r<t.length;r++){const i=t[r],l=o.get(i.fromLineId),d=o.get(i.toLineId);if(!l||!d)continue;const f=S(l,i.fromOffset,i.fromIsPercentage,1,s.wheelbase),u=T(d,i.toOffset,i.toIsPercentage,0,s.wheelbase),g=C(l,d,s,!1,{fromOffset:f,fromIsPercentage:!1,toOffset:u,toIsPercentage:!1}),p=j(g),v={curveIndex:r,fromLineId:i.fromLineId,toLineId:i.toLineId,fromOffset:f,toOffset:u,curveLength:p};n.get(i.fromLineId).push(v)}return{adjacency:n,lines:o,lineLengths:c}}function K(e,t,s,n,o=!1){const{adjacency:c,lines:r,lineLengths:i}=e;if(!r.get(s))return null;const d=i.get(s),f=o?n/100*d:n,u=[],g=new Map,p=(a,m)=>`${a}:${Math.round(m)}`;if(t.lineId===s&&f>=t.offset){const a=f-t.offset;return{segments:[{type:"line",lineId:t.lineId,startOffset:t.offset,endOffset:f,length:a}],totalDistance:a}}const v=c.get(t.lineId)||[];for(const a of v){if(a.fromOffset<t.offset)continue;const m=a.fromOffset-t.offset,L=m+a.curveLength,x={type:"line",lineId:t.lineId,startOffset:t.offset,endOffset:a.fromOffset,length:m},h={type:"curve",curveIndex:a.curveIndex,startOffset:0,endOffset:a.curveLength,length:a.curveLength};u.push({lineId:a.toLineId,entryOffset:a.toOffset,totalDistance:L,path:[x,h]})}for(u.sort((a,m)=>a.totalDistance-m.totalDistance);u.length>0;){const a=u.shift(),m=p(a.lineId,a.entryOffset),L=g.get(m);if(L!==void 0&&L<=a.totalDistance)continue;if(g.set(m,a.totalDistance),a.lineId===s){const h=Math.abs(f-a.entryOffset);if(f>=a.entryOffset){const y={type:"line",lineId:s,startOffset:a.entryOffset,endOffset:f,length:h};return{segments:[...a.path,y],totalDistance:a.totalDistance+h}}}const x=c.get(a.lineId)||[];for(const h of x){if(h.fromOffset<a.entryOffset)continue;const y=h.fromOffset-a.entryOffset,A=a.totalDistance+y+h.curveLength,W=p(h.toLineId,h.toOffset),z=g.get(W);if(z!==void 0&&z<=A)continue;const _={type:"line",lineId:a.lineId,startOffset:a.entryOffset,endOffset:h.fromOffset,length:y},E={type:"curve",curveIndex:h.curveIndex,startOffset:0,endOffset:h.curveLength,length:h.curveLength};u.push({lineId:h.toLineId,entryOffset:h.toOffset,totalDistance:A,path:[...a.path,_,E]})}u.sort((h,y)=>h.totalDistance-y.totalDistance)}return null}function b(e,t){const s=Math.sqrt(Math.pow(e.end.x-e.start.x,2)+Math.pow(e.end.y-e.start.y,2)),n=s>0?t/s:0;return{x:e.start.x+(e.end.x-e.start.x)*Math.min(1,Math.max(0,n)),y:e.start.y+(e.end.y-e.start.y)*Math.min(1,Math.max(0,n))}}function G(e){return Math.sqrt(Math.pow(e.end.x-e.start.x,2)+Math.pow(e.end.y-e.start.y,2))}function N(e,t,s){let n=0;for(let o=0;o<t;o++)n+=e.segments[o].length;return n+=s,n}function $(e,t){let s=0;for(let n=0;n<e.segments.length;n++){const o=e.segments[n],c=s+o.length;if(t<c)return{segmentIndex:n,segmentDistance:t-s};if(t===c)return n+1<e.segments.length?{segmentIndex:n+1,segmentDistance:0}:{segmentIndex:n,segmentDistance:o.length};s+=o.length}return null}function k(e,t,s,n){const c=N(e,t,s)+n;return $(e,c)}function X(e,t,s,n){const o=Math.sqrt(Math.pow(n.end.x-n.start.x,2)+Math.pow(n.end.y-n.start.y,2));let c=t+s;c=Math.min(c,o);const r=b(n,c);return{lineId:e,position:r,absoluteOffset:c}}function Q(e,t){return{...e,state:"idle"}}function R(e){return{vehicle:e,execution:null}}function Y(e,t){const s=[],n=new Map;for(const o of e){if(!t.get(o.lineId))continue;const r=Q(o);s.push(r);const i=R(r);n.set(o.id,i)}return{movingVehicles:s,stateMap:n}}function O(e,t){return{position:b(e,t),lineId:e.id,absoluteOffset:t}}function M(e,t){const s=F(e.arcLengthTable,t);return{position:w(e.bezier,s)}}function Z(e,t,s,n,o,c,r){const i=s.segments[t.currentSegmentIndex],l=t.segmentDistance+n;if(l>=i.length){const f=l-i.length,u=t.currentSegmentIndex+1;if(u>=s.segments.length){if(r!==void 0&&i.type==="line"){const a=o.get(i.lineId),m=i.startOffset+l;if(m<=r){const x=O(a,m);return{axleState:{...e,...x},execution:{...t,segmentDistance:l},completed:!1}}const L=O(a,r);return{axleState:{...e,...L},execution:{...t,segmentDistance:r-i.startOffset},completed:!0}}const v=i.type==="line"?O(o.get(i.lineId),i.endOffset):M(c.get(i.curveIndex),i.length);return{axleState:{...e,...v},execution:{...t,segmentDistance:i.length},completed:!0}}const g=s.segments[u],p=g.type==="line"?O(o.get(g.lineId),g.startOffset+f):M(c.get(g.curveIndex),f);return{axleState:{...e,...p},execution:{currentSegmentIndex:u,segmentDistance:f},completed:!1}}const d=i.type==="line"?O(o.get(i.lineId),i.startOffset+l):M(c.get(i.curveIndex),l);return{axleState:{...e,...d},execution:{...t,segmentDistance:l},completed:!1}}function ee(e,t,s,n){const o=new Map;for(const c of e.segments)if(c.type==="curve"&&c.curveIndex!==void 0){const r=t[c.curveIndex];if(r){const i=s.get(r.fromLineId),l=s.get(r.toLineId);if(i&&l){const d=S(i,r.fromOffset,r.fromIsPercentage,1,n.wheelbase),f=T(l,r.toOffset,r.toIsPercentage,0,n.wheelbase),u=C(i,l,n,!1,{fromOffset:d,fromIsPercentage:!1,toOffset:f,toIsPercentage:!1}),g=q(u);o.set(c.curveIndex,{bezier:u,arcLengthTable:g})}}}return o}function te(e,t,s){const{graph:n,linesMap:o,curves:c,config:r}=s,i=o.get(t.targetLineId);if(!i)return null;const d=G(i)-r.wheelbase;if(d<=0)return null;const f=t.isPercentage?t.targetOffset*d:Math.min(t.targetOffset,d),u=K(n,{lineId:e.rear.lineId,offset:e.rear.absoluteOffset},t.targetLineId,f,!1);if(!u)return null;const g=ee(u,c,o,r);return{path:u,curveDataMap:g}}function ne(e,t){const s=e.execution,n=t.vehicleQueues.get(e.vehicle.id),o=n?.[s.currentCommandIndex];if(o&&t.onCommandComplete&&t.onCommandComplete({vehicleId:e.vehicle.id,command:o,finalPosition:{lineId:e.vehicle.rear.lineId,absoluteOffset:e.vehicle.rear.absoluteOffset,position:e.vehicle.rear.position},payload:o.payload}),o?.awaitConfirmation)return{handled:!0,vehicle:{...e.vehicle,state:"waiting"},newExecution:s,isWaiting:!0};const c=s.currentCommandIndex+1;if(n&&c<n.length){const i=n[c],l=t.graphRef.current;if(l){const d={graph:l,linesMap:t.linesMap,curves:t.curves,config:t.config},f=t.prepareCommandPath(e.vehicle,i,d);if(f){const u=k(f.path,0,0,t.config.wheelbase);t.onCommandStart&&t.onCommandStart({vehicleId:e.vehicle.id,command:i,commandIndex:c,startPosition:{lineId:e.vehicle.rear.lineId,absoluteOffset:e.vehicle.rear.absoluteOffset,position:e.vehicle.rear.position}});const g={path:f.path,curveDataMap:f.curveDataMap,currentCommandIndex:c,rear:{currentSegmentIndex:0,segmentDistance:0},front:u?{currentSegmentIndex:u.segmentIndex,segmentDistance:u.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}};return{handled:!0,vehicle:{...e.vehicle,state:"moving"},newExecution:g}}}}return{handled:!0,vehicle:{...e.vehicle,state:"idle"},newExecution:null}}exports.arcLengthToSegmentPosition=$;exports.buildArcLengthTable=q;exports.buildGraph=U;exports.calculateBezierArcLength=j;exports.calculateFrontAxlePosition=k;exports.calculateInitialFrontPosition=X;exports.calculatePositionOnCurve=M;exports.calculatePositionOnLine=O;exports.calculateTangentLength=V;exports.createBezierCurve=C;exports.createInitialMovementState=R;exports.distance=I;exports.distanceToT=F;exports.findPath=K;exports.getArcLength=J;exports.getCumulativeArcLength=N;exports.getLineLength=G;exports.getPointOnBezier=w;exports.getPointOnLine=B;exports.getPointOnLineByOffset=D;exports.getPositionFromOffset=b;exports.handleArrival=ne;exports.initializeAllVehicles=Y;exports.initializeMovingVehicle=Q;exports.isPointNearPoint=H;exports.normalize=P;exports.prepareCommandPath=te;exports.resolveFromLineOffset=S;exports.resolveToLineOffset=T;exports.updateAxlePosition=Z;
|
package/dist/core.js
CHANGED
|
@@ -15,11 +15,11 @@ function T(e, t, o, n = !1, s) {
|
|
|
15
15
|
s?.fromOffset !== void 0 ? r = S(e, s.fromOffset, s.fromIsPercentage ?? !1) : r = e.end;
|
|
16
16
|
let l;
|
|
17
17
|
s?.toOffset !== void 0 ? l = S(t, s.toOffset, s.toIsPercentage ?? !1) : l = t.start;
|
|
18
|
-
const
|
|
18
|
+
const u = M(e.start, e.end), a = n ? {
|
|
19
19
|
// Transition with flip: kurva dimulai dari P (baseP0 - wheelbase in line direction)
|
|
20
|
-
x: r.x -
|
|
21
|
-
y: r.y -
|
|
22
|
-
} : r,
|
|
20
|
+
x: r.x - u.x * c,
|
|
21
|
+
y: r.y - u.y * c
|
|
22
|
+
} : r, d = M(e.start, e.end), g = M(t.start, t.end), p = v(a, l), I = F(i, p), f = n ? { x: a.x - d.x * I, y: a.y - d.y * I } : { x: a.x + d.x * I, y: a.y + d.y * I }, m = {
|
|
23
23
|
x: l.x - g.x * I,
|
|
24
24
|
y: l.y - g.y * I
|
|
25
25
|
};
|
|
@@ -37,10 +37,10 @@ function S(e, t, o) {
|
|
|
37
37
|
return o ? s = t : s = n > 0 ? t / n : 0, s = Math.max(0, Math.min(1, s)), K(e, s);
|
|
38
38
|
}
|
|
39
39
|
function D(e, t) {
|
|
40
|
-
const { p0: o, p1: n, p2: s, p3: c } = e, i = 1 - t, r = i * i, l = r * i,
|
|
40
|
+
const { p0: o, p1: n, p2: s, p3: c } = e, i = 1 - t, r = i * i, l = r * i, u = t * t, a = u * t;
|
|
41
41
|
return {
|
|
42
|
-
x: l * o.x + 3 * r * t * n.x + 3 * i *
|
|
43
|
-
y: l * o.y + 3 * r * t * n.y + 3 * i *
|
|
42
|
+
x: l * o.x + 3 * r * t * n.x + 3 * i * u * s.x + a * c.x,
|
|
43
|
+
y: l * o.y + 3 * r * t * n.y + 3 * i * u * s.y + a * c.y
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
function J(e, t, o = 10) {
|
|
@@ -66,8 +66,8 @@ function $(e, t) {
|
|
|
66
66
|
}
|
|
67
67
|
const c = e[n].distance, i = e[s].distance, r = e[n].t, l = e[s].t;
|
|
68
68
|
if (i === c) return r;
|
|
69
|
-
const
|
|
70
|
-
return r +
|
|
69
|
+
const u = (t - c) / (i - c);
|
|
70
|
+
return r + u * (l - r);
|
|
71
71
|
}
|
|
72
72
|
function U(e) {
|
|
73
73
|
return e[e.length - 1].distance;
|
|
@@ -89,8 +89,10 @@ function b(e, t, o, n, s) {
|
|
|
89
89
|
r = n;
|
|
90
90
|
else if (o)
|
|
91
91
|
r = t;
|
|
92
|
-
else
|
|
93
|
-
|
|
92
|
+
else {
|
|
93
|
+
const l = Math.max(0, Math.min(t, i));
|
|
94
|
+
return s + l;
|
|
95
|
+
}
|
|
94
96
|
return s + r * i;
|
|
95
97
|
}
|
|
96
98
|
function A(e, t, o, n, s) {
|
|
@@ -111,11 +113,11 @@ function X(e, t, o) {
|
|
|
111
113
|
for (const i of e)
|
|
112
114
|
s.set(i.id, i), c.set(i.id, v(i.start, i.end)), n.set(i.id, []);
|
|
113
115
|
for (let i = 0; i < t.length; i++) {
|
|
114
|
-
const r = t[i], l = s.get(r.fromLineId),
|
|
115
|
-
if (!l || !
|
|
116
|
-
const a = b(l, r.fromOffset, r.fromIsPercentage, 1, o.wheelbase),
|
|
116
|
+
const r = t[i], l = s.get(r.fromLineId), u = s.get(r.toLineId);
|
|
117
|
+
if (!l || !u) continue;
|
|
118
|
+
const a = b(l, r.fromOffset, r.fromIsPercentage, 1, o.wheelbase), d = A(u, r.toOffset, r.toIsPercentage, 0, o.wheelbase), g = T(
|
|
117
119
|
l,
|
|
118
|
-
|
|
120
|
+
u,
|
|
119
121
|
o,
|
|
120
122
|
!1,
|
|
121
123
|
// willFlip is always false now
|
|
@@ -123,7 +125,7 @@ function X(e, t, o) {
|
|
|
123
125
|
fromOffset: a,
|
|
124
126
|
fromIsPercentage: !1,
|
|
125
127
|
// Already resolved to absolute
|
|
126
|
-
toOffset:
|
|
128
|
+
toOffset: d,
|
|
127
129
|
toIsPercentage: !1
|
|
128
130
|
// Already resolved to absolute
|
|
129
131
|
}
|
|
@@ -132,7 +134,7 @@ function X(e, t, o) {
|
|
|
132
134
|
fromLineId: r.fromLineId,
|
|
133
135
|
toLineId: r.toLineId,
|
|
134
136
|
fromOffset: a,
|
|
135
|
-
toOffset:
|
|
137
|
+
toOffset: d,
|
|
136
138
|
curveLength: p
|
|
137
139
|
};
|
|
138
140
|
n.get(r.fromLineId).push(I);
|
|
@@ -142,7 +144,7 @@ function X(e, t, o) {
|
|
|
142
144
|
function G(e, t, o, n, s = !1) {
|
|
143
145
|
const { adjacency: c, lines: i, lineLengths: r } = e;
|
|
144
146
|
if (!i.get(o)) return null;
|
|
145
|
-
const
|
|
147
|
+
const u = r.get(o), a = s ? n / 100 * u : n, d = [], g = /* @__PURE__ */ new Map(), p = (f, m) => `${f}:${Math.round(m)}`;
|
|
146
148
|
if (t.lineId === o && a >= t.offset) {
|
|
147
149
|
const f = a - t.offset;
|
|
148
150
|
return {
|
|
@@ -172,15 +174,15 @@ function G(e, t, o, n, s = !1) {
|
|
|
172
174
|
endOffset: f.curveLength,
|
|
173
175
|
length: f.curveLength
|
|
174
176
|
};
|
|
175
|
-
|
|
177
|
+
d.push({
|
|
176
178
|
lineId: f.toLineId,
|
|
177
179
|
entryOffset: f.toOffset,
|
|
178
180
|
totalDistance: y,
|
|
179
181
|
path: [L, h]
|
|
180
182
|
});
|
|
181
183
|
}
|
|
182
|
-
for (
|
|
183
|
-
const f =
|
|
184
|
+
for (d.sort((f, m) => f.totalDistance - m.totalDistance); d.length > 0; ) {
|
|
185
|
+
const f = d.shift(), m = p(f.lineId, f.entryOffset), y = g.get(m);
|
|
184
186
|
if (y !== void 0 && y <= f.totalDistance)
|
|
185
187
|
continue;
|
|
186
188
|
if (g.set(m, f.totalDistance), f.lineId === o) {
|
|
@@ -218,14 +220,14 @@ function G(e, t, o, n, s = !1) {
|
|
|
218
220
|
endOffset: h.curveLength,
|
|
219
221
|
length: h.curveLength
|
|
220
222
|
};
|
|
221
|
-
|
|
223
|
+
d.push({
|
|
222
224
|
lineId: h.toLineId,
|
|
223
225
|
entryOffset: h.toOffset,
|
|
224
226
|
totalDistance: P,
|
|
225
227
|
path: [...f.path, z, B]
|
|
226
228
|
});
|
|
227
229
|
}
|
|
228
|
-
|
|
230
|
+
d.sort((h, x) => h.totalDistance - x.totalDistance);
|
|
229
231
|
}
|
|
230
232
|
return null;
|
|
231
233
|
}
|
|
@@ -324,8 +326,8 @@ function w(e, t) {
|
|
|
324
326
|
function ee(e, t, o, n, s, c, i) {
|
|
325
327
|
const r = o.segments[t.currentSegmentIndex], l = t.segmentDistance + n;
|
|
326
328
|
if (l >= r.length) {
|
|
327
|
-
const a = l - r.length,
|
|
328
|
-
if (
|
|
329
|
+
const a = l - r.length, d = t.currentSegmentIndex + 1;
|
|
330
|
+
if (d >= o.segments.length) {
|
|
329
331
|
if (i !== void 0 && r.type === "line") {
|
|
330
332
|
const f = s.get(r.lineId), m = r.startOffset + l;
|
|
331
333
|
if (m <= i) {
|
|
@@ -356,7 +358,7 @@ function ee(e, t, o, n, s, c, i) {
|
|
|
356
358
|
completed: !0
|
|
357
359
|
};
|
|
358
360
|
}
|
|
359
|
-
const g = o.segments[
|
|
361
|
+
const g = o.segments[d], p = g.type === "line" ? O(
|
|
360
362
|
s.get(g.lineId),
|
|
361
363
|
g.startOffset + a
|
|
362
364
|
) : w(
|
|
@@ -366,13 +368,13 @@ function ee(e, t, o, n, s, c, i) {
|
|
|
366
368
|
return {
|
|
367
369
|
axleState: { ...e, ...p },
|
|
368
370
|
execution: {
|
|
369
|
-
currentSegmentIndex:
|
|
371
|
+
currentSegmentIndex: d,
|
|
370
372
|
segmentDistance: a
|
|
371
373
|
},
|
|
372
374
|
completed: !1
|
|
373
375
|
};
|
|
374
376
|
}
|
|
375
|
-
const
|
|
377
|
+
const u = r.type === "line" ? O(
|
|
376
378
|
s.get(r.lineId),
|
|
377
379
|
r.startOffset + l
|
|
378
380
|
) : w(
|
|
@@ -380,7 +382,7 @@ function ee(e, t, o, n, s, c, i) {
|
|
|
380
382
|
l
|
|
381
383
|
);
|
|
382
384
|
return {
|
|
383
|
-
axleState: { ...e, ...
|
|
385
|
+
axleState: { ...e, ...u },
|
|
384
386
|
execution: { ...t, segmentDistance: l },
|
|
385
387
|
completed: !1
|
|
386
388
|
};
|
|
@@ -393,7 +395,7 @@ function H(e, t, o, n) {
|
|
|
393
395
|
if (i) {
|
|
394
396
|
const r = o.get(i.fromLineId), l = o.get(i.toLineId);
|
|
395
397
|
if (r && l) {
|
|
396
|
-
const
|
|
398
|
+
const u = b(
|
|
397
399
|
r,
|
|
398
400
|
i.fromOffset,
|
|
399
401
|
i.fromIsPercentage,
|
|
@@ -406,22 +408,22 @@ function H(e, t, o, n) {
|
|
|
406
408
|
i.toIsPercentage,
|
|
407
409
|
0,
|
|
408
410
|
n.wheelbase
|
|
409
|
-
),
|
|
411
|
+
), d = T(
|
|
410
412
|
r,
|
|
411
413
|
l,
|
|
412
414
|
n,
|
|
413
415
|
!1,
|
|
414
416
|
// willFlip is always false now
|
|
415
417
|
{
|
|
416
|
-
fromOffset:
|
|
418
|
+
fromOffset: u,
|
|
417
419
|
fromIsPercentage: !1,
|
|
418
420
|
// Already resolved to absolute
|
|
419
421
|
toOffset: a,
|
|
420
422
|
toIsPercentage: !1
|
|
421
423
|
// Already resolved to absolute
|
|
422
424
|
}
|
|
423
|
-
), g = j(
|
|
424
|
-
s.set(c.curveIndex, { bezier:
|
|
425
|
+
), g = j(d);
|
|
426
|
+
s.set(c.curveIndex, { bezier: d, arcLengthTable: g });
|
|
425
427
|
}
|
|
426
428
|
}
|
|
427
429
|
}
|
|
@@ -430,18 +432,18 @@ function H(e, t, o, n) {
|
|
|
430
432
|
function te(e, t, o) {
|
|
431
433
|
const { graph: n, linesMap: s, curves: c, config: i } = o, r = s.get(t.targetLineId);
|
|
432
434
|
if (!r) return null;
|
|
433
|
-
const
|
|
434
|
-
if (
|
|
435
|
-
const a = t.isPercentage ? t.targetOffset *
|
|
435
|
+
const u = N(r) - i.wheelbase;
|
|
436
|
+
if (u <= 0) return null;
|
|
437
|
+
const a = t.isPercentage ? t.targetOffset * u : Math.min(t.targetOffset, u), d = G(
|
|
436
438
|
n,
|
|
437
439
|
{ lineId: e.rear.lineId, offset: e.rear.absoluteOffset },
|
|
438
440
|
t.targetLineId,
|
|
439
441
|
a,
|
|
440
442
|
!1
|
|
441
443
|
);
|
|
442
|
-
if (!
|
|
443
|
-
const g = H(
|
|
444
|
-
return { path:
|
|
444
|
+
if (!d) return null;
|
|
445
|
+
const g = H(d, c, s, i);
|
|
446
|
+
return { path: d, curveDataMap: g };
|
|
445
447
|
}
|
|
446
448
|
function ne(e, t) {
|
|
447
449
|
const o = e.execution, n = t.vehicleQueues.get(e.vehicle.id), s = n?.[o.currentCommandIndex];
|
|
@@ -466,7 +468,7 @@ function ne(e, t) {
|
|
|
466
468
|
if (n && c < n.length) {
|
|
467
469
|
const r = n[c], l = t.graphRef.current;
|
|
468
470
|
if (l) {
|
|
469
|
-
const
|
|
471
|
+
const u = {
|
|
470
472
|
graph: l,
|
|
471
473
|
linesMap: t.linesMap,
|
|
472
474
|
curves: t.curves,
|
|
@@ -474,10 +476,10 @@ function ne(e, t) {
|
|
|
474
476
|
}, a = t.prepareCommandPath(
|
|
475
477
|
e.vehicle,
|
|
476
478
|
r,
|
|
477
|
-
|
|
479
|
+
u
|
|
478
480
|
);
|
|
479
481
|
if (a) {
|
|
480
|
-
const
|
|
482
|
+
const d = W(
|
|
481
483
|
a.path,
|
|
482
484
|
0,
|
|
483
485
|
0,
|
|
@@ -501,9 +503,9 @@ function ne(e, t) {
|
|
|
501
503
|
currentSegmentIndex: 0,
|
|
502
504
|
segmentDistance: 0
|
|
503
505
|
},
|
|
504
|
-
front:
|
|
505
|
-
currentSegmentIndex:
|
|
506
|
-
segmentDistance:
|
|
506
|
+
front: d ? {
|
|
507
|
+
currentSegmentIndex: d.segmentIndex,
|
|
508
|
+
segmentDistance: d.segmentDistance
|
|
507
509
|
} : {
|
|
508
510
|
currentSegmentIndex: 0,
|
|
509
511
|
segmentDistance: 0
|
package/dist/react.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./useVehicleEvents-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./useVehicleEvents-B7Z-9Hn2.cjs");exports.VehicleEventContext=e.VehicleEventContext;exports.VehicleEventProvider=e.VehicleEventProvider;exports.useAnimation=e.useAnimation;exports.useCreateVehicleEventEmitter=e.useCreateVehicleEventEmitter;exports.useInitialMovement=e.useInitialMovement;exports.useMovement=e.useMovementQueue;exports.useMovementQueue=e.useMovementQueue;exports.useMovementSequence=e.useMovementSequence;exports.useScene=e.useScene;exports.useSceneDefinition=e.useSceneDefinition;exports.useVehicleEvent=e.useVehicleEvent;exports.useVehicleEventEmitter=e.useVehicleEventEmitter;exports.useVehicleMovement=e.useAnimation;exports.useVehicleSimulation=e.useVehicleSimulation;exports.useVehicles=e.useVehicles;
|
package/dist/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as t, a as i, u as a, b as n, c as u, d as c, d as o, e as v, f as l, g as m, h, i as V, u as r, j as E, k as M } from "./useVehicleEvents-
|
|
1
|
+
import { V as t, a as i, u as a, b as n, c as u, d as c, d as o, e as v, f as l, g as m, h, i as V, u as r, j as E, k as M } from "./useVehicleEvents-t_p-Bwhj.js";
|
|
2
2
|
export {
|
|
3
3
|
t as VehicleEventContext,
|
|
4
4
|
i as VehicleEventProvider,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";const r=require("react"),R=require("./core.cjs"),A=require("./vehicle-helpers-82D2V4MI.cjs"),se=require("react/jsx-runtime");function G(t){return Array.isArray(t)?{x:t[0],y:t[1]}:t}function K(t){return{id:t.id,start:G(t.start),end:G(t.end)}}function U(t){const c=t.fromIsPercentage!==!1,M=t.toIsPercentage!==!1;return{fromLineId:t.from,toLineId:t.to,fromOffset:t.fromPosition,fromIsPercentage:t.fromPosition!==void 0?c:void 0,toOffset:t.toPosition,toIsPercentage:t.toPosition!==void 0?M:void 0}}function H(t){const c=t.position??0,M=t.isPercentage!==!1;return{vehicleId:t.id,lineId:t.lineId,offset:c,isPercentage:M}}function J(t){const c=t.isPercentage!==!1,M=t.targetPosition??1;return{vehicleId:t.vehicleId,targetLineId:t.targetLineId,targetOffset:M,isPercentage:c,awaitConfirmation:t.wait,payload:t.payload}}function re(t){const c=[],M=new Set;for(const s of t.lines)M.has(s.id)&&c.push(`Duplicate line ID: ${s.id}`),M.add(s.id);if(t.connections)for(const s of t.connections){M.has(s.from)||c.push(`Connection references non-existent line: ${s.from}`),M.has(s.to)||c.push(`Connection references non-existent line: ${s.to}`);const g=s.fromIsPercentage!==!1,e=s.toIsPercentage!==!1;!g&&s.fromPosition===void 0&&c.push("fromPosition is required when fromIsPercentage is false"),!e&&s.toPosition===void 0&&c.push("toPosition is required when toIsPercentage is false"),s.fromPosition!==void 0&&(g&&(s.fromPosition<0||s.fromPosition>1)?c.push(`Invalid fromPosition: ${s.fromPosition} (must be 0-1 for percentage)`):!g&&s.fromPosition<0&&c.push(`Invalid fromPosition: ${s.fromPosition} (must be >= 0 for absolute distance)`)),s.toPosition!==void 0&&(e&&(s.toPosition<0||s.toPosition>1)?c.push(`Invalid toPosition: ${s.toPosition} (must be 0-1 for percentage)`):!e&&s.toPosition<0&&c.push(`Invalid toPosition: ${s.toPosition} (must be >= 0 for absolute distance)`))}return{valid:c.length===0,errors:c}}function B(){const[t,c]=r.useState([]),[M,s]=r.useState([]),[g,e]=r.useState(null),d=r.useCallback((n,p)=>{c(n),s(p),e(null)},[]),x=r.useCallback(n=>{const p=re(n);if(!p.valid)return e(p.errors.join("; ")),{success:!1,errors:p.errors};const u=n.lines.map(K),v=n.connections?.map(U)||[];return d(u,v),{success:!0}},[d]),y=r.useCallback(n=>{if(t.some(u=>u.id===n.id)){const u=`Line with ID '${n.id}' already exists`;return e(u),{success:!1,error:u}}return c(u=>[...u,K(n)]),e(null),{success:!0}},[t]),D=r.useCallback((n,p)=>{if(t.findIndex(v=>v.id===n)===-1){const v=`Line with ID '${n}' not found`;return e(v),{success:!1,error:v}}return c(v=>v.map(V=>V.id!==n?V:{...V,start:p.start?G(p.start):V.start,end:p.end?G(p.end):V.end})),e(null),{success:!0}},[t]),k=r.useCallback(n=>{if(!t.some(u=>u.id===n)){const u=`Line with ID '${n}' not found`;return e(u),{success:!1,error:u}}return c(u=>u.filter(v=>v.id!==n)),s(u=>u.filter(v=>v.fromLineId!==n&&v.toLineId!==n)),e(null),{success:!0}},[t]),b=r.useCallback(n=>{const p=t.some(m=>m.id===n.from),u=t.some(m=>m.id===n.to);if(!p){const m=`Line '${n.from}' not found`;return e(m),{success:!1,error:m}}if(!u){const m=`Line '${n.to}' not found`;return e(m),{success:!1,error:m}}const v=n.fromIsPercentage!==!1,V=n.toIsPercentage!==!1;if(!v&&n.fromPosition===void 0){const m="fromPosition is required when fromIsPercentage is false";return e(m),{success:!1,error:m}}if(!V&&n.toPosition===void 0){const m="toPosition is required when toIsPercentage is false";return e(m),{success:!1,error:m}}if(M.some(m=>m.fromLineId===n.from&&m.toLineId===n.to)){const m=`Connection from '${n.from}' to '${n.to}' already exists`;return e(m),{success:!1,error:m}}return s(m=>[...m,U(n)]),e(null),{success:!0}},[t,M]),P=r.useCallback((n,p,u)=>{const v=M.findIndex(f=>f.fromLineId===n&&f.toLineId===p);if(v===-1){const f=`Connection from '${n}' to '${p}' not found`;return e(f),{success:!1,error:f}}const V=M[v],Q=u.fromIsPercentage??V.fromIsPercentage,m=u.toIsPercentage??V.toIsPercentage;let $;u.fromOffset!==void 0?$=u.fromOffset:V.fromOffset!==void 0&&($=V.fromOffset);let L;if(u.toOffset!==void 0?L=u.toOffset:V.toOffset!==void 0&&(L=V.toOffset),$!==void 0){if(Q!==!1&&($<0||$>1)){const f=`Invalid fromOffset: ${$} (must be 0-1 for percentage)`;return e(f),{success:!1,error:f}}if(Q===!1&&$<0){const f=`Invalid fromOffset: ${$} (must be >= 0 for absolute distance)`;return e(f),{success:!1,error:f}}}if(L!==void 0){if(m!==!1&&(L<0||L>1)){const f=`Invalid toOffset: ${L} (must be 0-1 for percentage)`;return e(f),{success:!1,error:f}}if(m===!1&&L<0){const f=`Invalid toOffset: ${L} (must be >= 0 for absolute distance)`;return e(f),{success:!1,error:f}}}if(Q===!1&&$===void 0){const f="fromOffset is required when fromIsPercentage is false";return e(f),{success:!1,error:f}}if(m===!1&&L===void 0){const f="toOffset is required when toIsPercentage is false";return e(f),{success:!1,error:f}}const j={from:n,to:p,fromPosition:$,fromIsPercentage:Q,toPosition:L,toIsPercentage:m};return s(f=>f.map((o,a)=>a===v?U(j):o)),e(null),{success:!0}},[M]),C=r.useCallback((n,p)=>{if(!M.some(v=>v.fromLineId===n&&v.toLineId===p)){const v=`Connection from '${n}' to '${p}' not found`;return e(v),{success:!1,error:v}}return s(v=>v.filter(V=>!(V.fromLineId===n&&V.toLineId===p))),e(null),{success:!0}},[M]),i=r.useCallback(()=>{c([]),s([]),e(null)},[]);return{lines:t,curves:M,setScene:x,addLine:y,updateLine:D,removeLine:k,addConnection:b,updateConnection:P,removeConnection:C,clear:i,error:g,_loadScene:d}}function W({lines:t,wheelbase:c}){const[M,s]=r.useState([]),[g,e]=r.useState(null),d=r.useRef([]),x=r.useCallback(P=>{d.current=P,s(P),e(null)},[]),y=r.useCallback(P=>{const C=Array.isArray(P)?P:[P],i=[];for(const v of C)d.current.some(Q=>Q.id===v.id)&&i.push(`Vehicle with ID '${v.id}' already exists`);if(i.length>0)return e(i.join("; ")),{success:!1,errors:i};const n=C.map(H),{vehicles:p,errors:u}=A.validateAndCreateVehicles(n,t,c);return u.length>0?(e(u.join("; ")),{success:!1,errors:u}):(d.current=[...d.current,...p],s(d.current),e(null),{success:!0})},[t,c]),D=r.useCallback((P,C)=>{const i=d.current.findIndex(L=>L.id===P);if(i===-1){const L=`Vehicle with ID '${P}' not found`;return e(L),{success:!1,error:L}}const n=d.current[i];if(n.state!=="idle"){const L=`Cannot update vehicle '${P}' while it is ${n.state}. Vehicle must be idle.`;return e(L),{success:!1,error:L}}const p=C.lineId??n.lineId;if(!t.find(L=>L.id===p)){const L=`Line '${p}' not found`;return e(L),{success:!1,error:L}}let v,V;C.lineId!==void 0&&C.position===void 0?(v=0,V=!0):C.position!==void 0?(v=C.position,V=C.isPercentage??!0):(v=n.offset,V=n.isPercentage);const Q={vehicleId:P,lineId:p,offset:v,isPercentage:V},{vehicles:m,errors:$}=A.validateAndCreateVehicles([Q],t,c);return $.length>0?(e($.join("; ")),{success:!1,error:$.join("; ")}):(d.current=d.current.map((L,j)=>j===i?m[0]:L),s(d.current),e(null),{success:!0})},[t,c]),k=r.useCallback(P=>{if(!d.current.some(i=>i.id===P)){const i=`Vehicle with ID '${P}' not found`;return e(i),{success:!1,error:i}}return d.current=d.current.filter(i=>i.id!==P),s(d.current),e(null),{success:!0}},[]),b=r.useCallback(()=>{d.current=[],s([]),e(null)},[]);return{vehicles:M,addVehicles:y,updateVehicle:D,removeVehicle:k,clear:b,error:g,_loadVehicles:x}}function X({vehicles:t,lines:c}){const[M,s]=r.useState(new Map),[g,e]=r.useState(null),d=r.useRef(new Map),x=r.useCallback(()=>d.current,[]),y=r.useCallback(b=>{d.current=b,s(b),e(null)},[]),D=r.useCallback((b,P)=>{if(!t.some(m=>m.id===b)){const m=`Vehicle '${b}' not found`;return e(m),{success:!1,error:m}}const i=c.find(m=>m.id===P.targetLineId);if(!i){const m=`Line '${P.targetLineId}' not found`;return e(m),{success:!1,error:m}}const n=P.isPercentage!==!1,p=R.distance(i.start,i.end);if(!n&&P.targetPosition===void 0){const m="targetPosition is required when isPercentage is false";return e(m),{success:!1,error:m}}const u=P.targetPosition??1;if(n){if(u<0||u>1){const m=`Invalid targetPosition: ${u} (must be 0-1 for percentage)`;return e(m),{success:!1,error:m}}}else{if(u<0){const m=`Invalid targetPosition: ${u} (must be >= 0 for absolute distance)`;return e(m),{success:!1,error:m}}if(u>p){const m=`Position ${u} exceeds line length ${p}`;return e(m),{success:!1,error:m}}}const v=J({vehicleId:b,...P}),V=new Map(d.current),Q=V.get(b)||[];return V.set(b,[...Q,v]),d.current=V,s(V),e(null),{success:!0}},[t,c]),k=r.useCallback(b=>{if(b!==void 0){if(!t.some(i=>i.id===b)){const i=`Vehicle '${b}' not found`;return e(i),{success:!1,error:i}}const C=new Map(d.current);C.delete(b),d.current=C,s(C)}else d.current=new Map,s(new Map);return e(null),{success:!0}},[t]);return{vehicleQueues:M,getVehicleQueues:x,queueMovement:D,clearQueue:k,error:g,_loadQueues:y}}function ee({vehicles:t,lines:c,vehicleQueues:M,getVehicleQueues:s,wheelbase:g,tangentMode:e,curves:d,eventEmitter:x}){const[y,D]=r.useState([]),k=r.useRef([]),b=r.useCallback(f=>{typeof f=="function"?D(o=>{const a=f(o);return k.current=a,a}):(k.current=f,D(f))},[]),P=r.useCallback(()=>k.current,[]),C=r.useMemo(()=>({wheelbase:g,tangentMode:e}),[g,e]),i=r.useMemo(()=>new Map(c.map(f=>[f.id,f])),[c]),n=r.useRef(new Map);r.useEffect(()=>{const{movingVehicles:f,stateMap:o}=R.initializeAllVehicles(t,i);n.current=o;const a=setTimeout(()=>{b(f)},0);return()=>clearTimeout(a)},[t,i]);const p=r.useRef(null);r.useEffect(()=>{c.length>0&&(p.current=R.buildGraph(c,d,C))},[c,d,C]);const u=r.useRef(0),v=r.useRef(!1),V=r.useCallback(f=>{if(!v.current)return!1;let o=!1;for(const[,l]of n.current)if(l.vehicle.state==="moving"){o=!0;break}if(!o)return!1;const a=[];for(const[l,h]of n.current){if(h.vehicle.state!=="moving"||!h.execution)continue;const I=h.execution;let S;if(I.front.currentSegmentIndex<I.path.segments.length){const T=I.path.segments[I.front.currentSegmentIndex];if(T.type==="line"){const E=i.get(T.lineId);E&&(S=Math.sqrt(Math.pow(E.end.x-E.start.x,2)+Math.pow(E.end.y-E.start.y,2)))}}const O=R.updateAxlePosition(h.vehicle.rear,I.rear,I.path,f,i,I.curveDataMap),q=R.updateAxlePosition(h.vehicle.front,I.front,I.path,f,i,I.curveDataMap,S);if(h.vehicle={...h.vehicle,rear:O.axleState,front:q.axleState},h.execution.rear=O.execution,h.execution.front=q.execution,O.completed){const T={linesMap:i,config:C,vehicleQueues:M,curves:d,graphRef:p,prepareCommandPath:R.prepareCommandPath,onCommandComplete:F=>a.push({type:"commandComplete",data:F}),onCommandStart:F=>a.push({type:"commandStart",data:F})},E=R.handleArrival(h,T);h.vehicle=E.vehicle,E.newExecution!==void 0&&(h.execution=E.newExecution),E.vehicle.state!=="moving"&&a.push({type:"stateChange",data:{vehicleId:l,from:"moving",to:E.vehicle.state}});const w=E.vehicle.rear.position,_=E.vehicle.front.position;a.push({type:"positionUpdate",data:{vehicleId:l,rear:w,front:_,center:{x:(w.x+_.x)/2,y:(w.y+_.y)/2},angle:Math.atan2(_.y-w.y,_.x-w.x)}})}}if(b(l=>l.map(h=>{const I=n.current.get(h.id);return I?I.vehicle:h})),x&&a.length>0){const l=u.current;setTimeout(()=>{u.current===l&&a.forEach(({type:h,data:I})=>{x.emit(h,I)})},0)}for(const[,l]of n.current)if(l.vehicle.state==="moving")return!0;return v.current=!1,!1},[i,d,C,M,x]),Q=r.useCallback(()=>{const f=p.current;if(!f)return!1;const o=s?s():M,a=[];let l=!1;for(const[h,I]of n.current){const S=I.vehicle;if(S.state==="moving")continue;const O=o.get(h);if(!O||O.length===0)continue;const q=O[0],T={graph:f,linesMap:i,curves:d,config:C},E=R.prepareCommandPath(S,q,T);if(!E){console.warn(`No path found for vehicle ${h}`);continue}const w=R.calculateFrontAxlePosition(E.path,0,0,g);n.current.set(h,{...I,execution:{path:E.path,curveDataMap:E.curveDataMap,currentCommandIndex:0,rear:{currentSegmentIndex:0,segmentDistance:0},front:w?{currentSegmentIndex:w.segmentIndex,segmentDistance:w.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},vehicle:{...S,state:"moving"}}),l=!0,a.push({id:h,fromState:S.state,command:q,startPosition:{lineId:S.rear.lineId,absoluteOffset:S.rear.absoluteOffset,position:S.rear.position}})}if(!l)return!1;if(v.current=!0,b(h=>h.map(I=>{const S=n.current.get(I.id);return S?S.vehicle:I})),x&&a.length>0){const h=u.current;setTimeout(()=>{u.current===h&&a.forEach(({id:I,fromState:S,command:O,startPosition:q})=>{x.emit("commandStart",{vehicleId:I,command:O,commandIndex:0,startPosition:q}),x.emit("stateChange",{vehicleId:I,from:S,to:"moving"})})},0)}return!0},[i,d,M,s,C,g,x]),m=r.useCallback(()=>{u.current++,v.current=!1;const{movingVehicles:f,stateMap:o}=R.initializeAllVehicles(t,i);n.current=o,b(f)},[t,i]),$=r.useCallback(f=>{const o=t.find(I=>I.id===f);if(!o||!i.get(o.lineId))return;const l=R.initializeMovingVehicle(o),h=R.createInitialMovementState(l);n.current.set(f,h),b(I=>I.map(S=>S.id===f?l:S))},[t,i]),L=r.useCallback(f=>{const o=n.current.get(f);if(!o||o.vehicle.state!=="waiting")return!1;const a=M.get(f),l=o.execution;if(!l)return!1;const h=l.currentCommandIndex+1;if(a&&h<a.length){const I=p.current;if(I){const S=a[h],O={graph:I,linesMap:i,curves:d,config:C},q=R.prepareCommandPath(o.vehicle,S,O);if(q){const T=R.calculateFrontAxlePosition(q.path,0,0,g);if(o.execution={path:q.path,curveDataMap:q.curveDataMap,currentCommandIndex:h,rear:{currentSegmentIndex:0,segmentDistance:0},front:T?{currentSegmentIndex:T.segmentIndex,segmentDistance:T.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},o.vehicle={...o.vehicle,state:"moving"},b(E=>E.map(w=>w.id===f?o.vehicle:w)),x){const E=u.current;setTimeout(()=>{u.current===E&&x.emit("stateChange",{vehicleId:f,from:"waiting",to:"moving"})},0)}return!0}}}if(o.vehicle={...o.vehicle,state:"idle"},o.execution=null,b(I=>I.map(S=>S.id===f?o.vehicle:S)),x){const I=u.current;setTimeout(()=>{u.current===I&&x.emit("stateChange",{vehicleId:f,from:"waiting",to:"idle"})},0)}return!0},[M,i,d,C,g,x]),j=r.useCallback(()=>{for(const[,f]of n.current)if(f.vehicle.state==="moving")return!0;return!1},[]);return{movingVehicles:y,getMovingVehicles:P,prepare:Q,tick:V,reset:m,resetVehicle:$,continueVehicle:L,isMoving:j,isPrepared:v.current}}function ne({wheelbase:t,tangentMode:c="proportional-40",eventEmitter:M}){const s=B(),g=W({lines:s.lines,wheelbase:t}),e=X({vehicles:g.vehicles,lines:s.lines,curves:s.curves}),d=ee({vehicles:g.vehicles,lines:s.lines,vehicleQueues:e.vehicleQueues,getVehicleQueues:e.getVehicleQueues,wheelbase:t,tangentMode:c,curves:s.curves,eventEmitter:M}),x=r.useCallback(o=>g.vehicles.filter(a=>a.lineId===o||a.rear.lineId===o),[g.vehicles]),y=r.useCallback(o=>x(o).length>0,[x]),D=r.useCallback(o=>{const a=s.addLine(o);return a.success?{success:!0}:{success:!1,error:a.error}},[s]),k=r.useCallback((o,a)=>{const l=s.updateLine(o,a);return l.success?{success:!0}:{success:!1,error:l.error}},[s]),b=r.useCallback(o=>{const a=[],l=x(o);l.length>0&&(a.push({type:"vehicle_on_removed_line",message:`${l.length} vehicle(s) are on line '${o}'`,details:{lineId:o,vehicleIds:l.map(S=>S.id)}}),l.forEach(S=>{g.removeVehicle(S.id),e.clearQueue(S.id)}));const h=s.curves.filter(S=>S.fromLineId===o||S.toLineId===o);h.length>0&&a.push({type:"orphaned_connection",message:`${h.length} connection(s) will be removed`,details:{lineId:o,connectionCount:h.length}});const I=s.removeLine(o);return I.success?{success:!0,warnings:a.length>0?a:void 0}:{success:!1,error:I.error}},[s,x,g,e]),P=r.useCallback(()=>{s.clear(),g.clear(),e.clearQueue()},[s,g,e]),C=r.useCallback((o,a,l)=>{const h=s.addConnection({from:o,to:a,fromPosition:l?.fromOffset,fromIsPercentage:l?.fromIsPercentage,toPosition:l?.toOffset,toIsPercentage:l?.toIsPercentage});return h.success?{success:!0}:{success:!1,error:h.error}},[s]),i=r.useCallback((o,a,l)=>{const h=s.updateConnection(o,a,l);return h.success?{success:!0}:{success:!1,error:h.error}},[s]),n=r.useCallback((o,a)=>{const l=s.removeConnection(o,a);return l.success?{success:!0}:{success:!1,error:l.error}},[s]),p=r.useCallback(o=>{const a=g.addVehicles(o);return a.success?{success:!0}:{success:!1,error:a.errors?.join("; ")}},[g]),u=r.useCallback((o,a)=>{const l=g.updateVehicle(o,a);return l.success?{success:!0}:{success:!1,error:l.error}},[g]),v=r.useCallback(o=>{const a=[],l=e.vehicleQueues.get(o);l&&l.length>0&&(a.push({type:"movement_queue_cleared",message:`${l.length} queued movement(s) will be cleared for vehicle '${o}'`,details:{vehicleId:o}}),e.clearQueue(o));const h=g.removeVehicle(o);return h.success?{success:!0,warnings:a.length>0?a:void 0}:{success:!1,error:h.error}},[g,e]),V=r.useCallback(()=>{g.clear(),e.clearQueue()},[g,e]),Q=r.useCallback(o=>{const a={targetLineId:o.lineId,targetPosition:o.position??1,isPercentage:o.isPercentage,wait:o.wait,payload:o.payload},l=e.queueMovement(o.id,a);return l.success?{success:!0}:{success:!1,error:l.error}},[e]),m=r.useCallback(o=>{const a=e.clearQueue(o);return a.success?{success:!0}:{success:!1,error:a.error}},[e]),$=r.useCallback(o=>{e.clearQueue(o),d.resetVehicle(o)},[e,d]),L=r.useCallback(o=>{const a=[],l=[],{scene:h,vehicles:I,movements:S}=A.parseAllDSL(o);h.errors.length>0&&l.push(...h.errors),I.errors.length>0&&l.push(...I.errors),S.errors.length>0&&l.push(...S.errors);const O=h.data.lines.map(K),q=(h.data.connections||[]).map(U),T=I.data.map(H),{vehicles:E,errors:w}=A.validateAndCreateVehicles(T,O,t);w.length>0&&l.push(...w);const _=new Map;for(const F of S.data){const Z=_.get(F.vehicleId)||[];Z.push(J(F)),_.set(F.vehicleId,Z)}return s._loadScene(O,q),g._loadVehicles(E),e._loadQueues(_),l.length>0&&a.push({type:"dsl_parse_error",message:`DSL loading had ${l.length} error(s)`,details:{errors:l}}),{success:!0,warnings:a.length>0?a:void 0}},[s,g,e,t]),j=r.useCallback(o=>{const a=[],l=[],h=o.lines.map(K),I=(o.connections||[]).map(U),S=(o.vehicles||[]).map(H),{vehicles:O,errors:q}=A.validateAndCreateVehicles(S,h,t);q.length>0&&l.push(...q);const T=new Map;for(const E of o.movements||[]){const w=T.get(E.vehicleId)||[];w.push(J({vehicleId:E.vehicleId,targetLineId:E.targetLineId,targetPosition:E.targetPosition,isPercentage:E.isPercentage,wait:E.wait,payload:E.payload})),T.set(E.vehicleId,w)}return s._loadScene(h,I),g._loadVehicles(O),e._loadQueues(T),l.length>0&&a.push({type:"dsl_parse_error",message:`JSON loading had ${l.length} error(s)`,details:{errors:l}}),{success:!0,warnings:a.length>0?a:void 0}},[s,g,e,t]),f=r.useMemo(()=>s.error||g.error||e.error,[s.error,g.error,e.error]);return{lines:s.lines,curves:s.curves,vehicles:g.vehicles,movingVehicles:d.movingVehicles,getMovingVehicles:d.getMovingVehicles,vehicleQueues:e.vehicleQueues,error:f,addLine:D,updateLine:k,removeLine:b,clearScene:P,connect:C,updateConnection:i,disconnect:n,addVehicles:p,updateVehicle:u,removeVehicle:v,clearVehicles:V,goto:Q,clearQueue:m,prepare:d.prepare,tick:d.tick,reset:d.reset,resetVehicle:$,continueVehicle:d.continueVehicle,isMoving:d.isMoving,loadFromDSL:L,loadFromJSON:j,getVehiclesOnLine:x,hasVehiclesOnLine:y}}function z(t){return t.map(c=>({id:c.id,start:c.start,end:c.end}))}function N(t){return t.map(c=>({from:c.fromLineId,to:c.toLineId,fromPosition:c.fromOffset,fromIsPercentage:c.fromIsPercentage,toPosition:c.toOffset,toIsPercentage:c.toIsPercentage}))}function oe(){const[t,c]=r.useState(""),[M,s]=r.useState(null),{lines:g,curves:e,setScene:d}=B(),x=r.useRef(!1),y=r.useRef("");r.useEffect(()=>{y.current=t},[t]),r.useEffect(()=>{if(x.current)return;const P={lines:z(g),connections:e.length>0?N(e):void 0},C=A.generateSceneDSL(P);C!==y.current&&(x.current=!0,c(C),setTimeout(()=>{x.current=!1},50))},[g,e]);const D=r.useCallback(P=>{x.current=!0,c(P);try{const{data:C,errors:i}=A.parseSceneDSL(P);i.length>0&&s(i.join("; "));const n=d(C);!n.success&&n.errors?s(p=>p?`${p}; ${n.errors.join("; ")}`:n.errors.join("; ")):i.length===0&&s(null)}catch(C){s(C instanceof Error?C.message:"Invalid scene definition")}setTimeout(()=>{x.current=!1},50)},[d]),k=r.useCallback(P=>{const C=typeof P=="function"?P(g):P,i=N(e);d({lines:z(C),connections:i.length>0?i:void 0});const n={lines:z(C),connections:i.length>0?i:void 0},p=A.generateSceneDSL(n);x.current=!0,c(p),setTimeout(()=>{x.current=!1},50)},[g,e,d]),b=r.useCallback(P=>{const C=typeof P=="function"?P(e):P,i=N(C);d({lines:z(g),connections:i.length>0?i:void 0});const n={lines:z(g),connections:i.length>0?i:void 0},p=A.generateSceneDSL(n);x.current=!0,c(p),setTimeout(()=>{x.current=!1},50)},[g,e,d]);return{lines:g,curves:e,sceneDefinitionText:t,sceneError:M,isDebouncing:!1,debounceKey:0,setLines:k,setCurves:b,setSceneDefinitionText:D}}function ce({lines:t,wheelbase:c}){const[M,s]=r.useState(""),[g,e]=r.useState(null),{vehicles:d,addVehicles:x,clear:y,error:D}=W({lines:t,wheelbase:c}),k=r.useRef(!1),b=r.useCallback(P=>{k.current=!0,s(P);try{const{data:C,errors:i}=A.parseVehiclesDSL(P),n=[...i];y();for(const p of C){const u=x(p);!u.success&&u.errors&&n.push(...u.errors)}n.length>0?e(n.join(`
|
|
1
|
+
"use strict";const r=require("react"),R=require("./core.cjs"),A=require("./vehicle-helpers-bgHGBdo9.cjs"),se=require("react/jsx-runtime");function G(t){return Array.isArray(t)?{x:t[0],y:t[1]}:t}function K(t){return{id:t.id,start:G(t.start),end:G(t.end)}}function U(t){const c=t.fromIsPercentage!==!1,M=t.toIsPercentage!==!1;return{fromLineId:t.from,toLineId:t.to,fromOffset:t.fromPosition,fromIsPercentage:t.fromPosition!==void 0?c:void 0,toOffset:t.toPosition,toIsPercentage:t.toPosition!==void 0?M:void 0}}function H(t){const c=t.position??0,M=t.isPercentage!==!1;return{vehicleId:t.id,lineId:t.lineId,offset:c,isPercentage:M}}function J(t){const c=t.isPercentage!==!1,M=t.targetPosition??1;return{vehicleId:t.vehicleId,targetLineId:t.targetLineId,targetOffset:M,isPercentage:c,awaitConfirmation:t.wait,payload:t.payload}}function re(t){const c=[],M=new Set;for(const s of t.lines)M.has(s.id)&&c.push(`Duplicate line ID: ${s.id}`),M.add(s.id);if(t.connections)for(const s of t.connections){M.has(s.from)||c.push(`Connection references non-existent line: ${s.from}`),M.has(s.to)||c.push(`Connection references non-existent line: ${s.to}`);const g=s.fromIsPercentage!==!1,e=s.toIsPercentage!==!1;!g&&s.fromPosition===void 0&&c.push("fromPosition is required when fromIsPercentage is false"),!e&&s.toPosition===void 0&&c.push("toPosition is required when toIsPercentage is false"),s.fromPosition!==void 0&&(g&&(s.fromPosition<0||s.fromPosition>1)?c.push(`Invalid fromPosition: ${s.fromPosition} (must be 0-1 for percentage)`):!g&&s.fromPosition<0&&c.push(`Invalid fromPosition: ${s.fromPosition} (must be >= 0 for absolute distance)`)),s.toPosition!==void 0&&(e&&(s.toPosition<0||s.toPosition>1)?c.push(`Invalid toPosition: ${s.toPosition} (must be 0-1 for percentage)`):!e&&s.toPosition<0&&c.push(`Invalid toPosition: ${s.toPosition} (must be >= 0 for absolute distance)`))}return{valid:c.length===0,errors:c}}function B(){const[t,c]=r.useState([]),[M,s]=r.useState([]),[g,e]=r.useState(null),d=r.useCallback((n,p)=>{c(n),s(p),e(null)},[]),x=r.useCallback(n=>{const p=re(n);if(!p.valid)return e(p.errors.join("; ")),{success:!1,errors:p.errors};const u=n.lines.map(K),v=n.connections?.map(U)||[];return d(u,v),{success:!0}},[d]),y=r.useCallback(n=>{if(t.some(u=>u.id===n.id)){const u=`Line with ID '${n.id}' already exists`;return e(u),{success:!1,error:u}}return c(u=>[...u,K(n)]),e(null),{success:!0}},[t]),D=r.useCallback((n,p)=>{if(t.findIndex(v=>v.id===n)===-1){const v=`Line with ID '${n}' not found`;return e(v),{success:!1,error:v}}return c(v=>v.map(V=>V.id!==n?V:{...V,start:p.start?G(p.start):V.start,end:p.end?G(p.end):V.end})),e(null),{success:!0}},[t]),k=r.useCallback(n=>{if(!t.some(u=>u.id===n)){const u=`Line with ID '${n}' not found`;return e(u),{success:!1,error:u}}return c(u=>u.filter(v=>v.id!==n)),s(u=>u.filter(v=>v.fromLineId!==n&&v.toLineId!==n)),e(null),{success:!0}},[t]),b=r.useCallback(n=>{const p=t.some(m=>m.id===n.from),u=t.some(m=>m.id===n.to);if(!p){const m=`Line '${n.from}' not found`;return e(m),{success:!1,error:m}}if(!u){const m=`Line '${n.to}' not found`;return e(m),{success:!1,error:m}}const v=n.fromIsPercentage!==!1,V=n.toIsPercentage!==!1;if(!v&&n.fromPosition===void 0){const m="fromPosition is required when fromIsPercentage is false";return e(m),{success:!1,error:m}}if(!V&&n.toPosition===void 0){const m="toPosition is required when toIsPercentage is false";return e(m),{success:!1,error:m}}if(M.some(m=>m.fromLineId===n.from&&m.toLineId===n.to)){const m=`Connection from '${n.from}' to '${n.to}' already exists`;return e(m),{success:!1,error:m}}return s(m=>[...m,U(n)]),e(null),{success:!0}},[t,M]),P=r.useCallback((n,p,u)=>{const v=M.findIndex(f=>f.fromLineId===n&&f.toLineId===p);if(v===-1){const f=`Connection from '${n}' to '${p}' not found`;return e(f),{success:!1,error:f}}const V=M[v],Q=u.fromIsPercentage??V.fromIsPercentage,m=u.toIsPercentage??V.toIsPercentage;let $;u.fromOffset!==void 0?$=u.fromOffset:V.fromOffset!==void 0&&($=V.fromOffset);let L;if(u.toOffset!==void 0?L=u.toOffset:V.toOffset!==void 0&&(L=V.toOffset),$!==void 0){if(Q!==!1&&($<0||$>1)){const f=`Invalid fromOffset: ${$} (must be 0-1 for percentage)`;return e(f),{success:!1,error:f}}if(Q===!1&&$<0){const f=`Invalid fromOffset: ${$} (must be >= 0 for absolute distance)`;return e(f),{success:!1,error:f}}}if(L!==void 0){if(m!==!1&&(L<0||L>1)){const f=`Invalid toOffset: ${L} (must be 0-1 for percentage)`;return e(f),{success:!1,error:f}}if(m===!1&&L<0){const f=`Invalid toOffset: ${L} (must be >= 0 for absolute distance)`;return e(f),{success:!1,error:f}}}if(Q===!1&&$===void 0){const f="fromOffset is required when fromIsPercentage is false";return e(f),{success:!1,error:f}}if(m===!1&&L===void 0){const f="toOffset is required when toIsPercentage is false";return e(f),{success:!1,error:f}}const j={from:n,to:p,fromPosition:$,fromIsPercentage:Q,toPosition:L,toIsPercentage:m};return s(f=>f.map((o,a)=>a===v?U(j):o)),e(null),{success:!0}},[M]),C=r.useCallback((n,p)=>{if(!M.some(v=>v.fromLineId===n&&v.toLineId===p)){const v=`Connection from '${n}' to '${p}' not found`;return e(v),{success:!1,error:v}}return s(v=>v.filter(V=>!(V.fromLineId===n&&V.toLineId===p))),e(null),{success:!0}},[M]),i=r.useCallback(()=>{c([]),s([]),e(null)},[]);return{lines:t,curves:M,setScene:x,addLine:y,updateLine:D,removeLine:k,addConnection:b,updateConnection:P,removeConnection:C,clear:i,error:g,_loadScene:d}}function W({lines:t,wheelbase:c}){const[M,s]=r.useState([]),[g,e]=r.useState(null),d=r.useRef([]),x=r.useCallback(P=>{d.current=P,s(P),e(null)},[]),y=r.useCallback(P=>{const C=Array.isArray(P)?P:[P],i=[];for(const v of C)d.current.some(Q=>Q.id===v.id)&&i.push(`Vehicle with ID '${v.id}' already exists`);if(i.length>0)return e(i.join("; ")),{success:!1,errors:i};const n=C.map(H),{vehicles:p,errors:u}=A.validateAndCreateVehicles(n,t,c);return u.length>0?(e(u.join("; ")),{success:!1,errors:u}):(d.current=[...d.current,...p],s(d.current),e(null),{success:!0})},[t,c]),D=r.useCallback((P,C)=>{const i=d.current.findIndex(L=>L.id===P);if(i===-1){const L=`Vehicle with ID '${P}' not found`;return e(L),{success:!1,error:L}}const n=d.current[i];if(n.state!=="idle"){const L=`Cannot update vehicle '${P}' while it is ${n.state}. Vehicle must be idle.`;return e(L),{success:!1,error:L}}const p=C.lineId??n.lineId;if(!t.find(L=>L.id===p)){const L=`Line '${p}' not found`;return e(L),{success:!1,error:L}}let v,V;C.lineId!==void 0&&C.position===void 0?(v=0,V=!0):C.position!==void 0?(v=C.position,V=C.isPercentage??!0):(v=n.offset,V=n.isPercentage);const Q={vehicleId:P,lineId:p,offset:v,isPercentage:V},{vehicles:m,errors:$}=A.validateAndCreateVehicles([Q],t,c);return $.length>0?(e($.join("; ")),{success:!1,error:$.join("; ")}):(d.current=d.current.map((L,j)=>j===i?m[0]:L),s(d.current),e(null),{success:!0})},[t,c]),k=r.useCallback(P=>{if(!d.current.some(i=>i.id===P)){const i=`Vehicle with ID '${P}' not found`;return e(i),{success:!1,error:i}}return d.current=d.current.filter(i=>i.id!==P),s(d.current),e(null),{success:!0}},[]),b=r.useCallback(()=>{d.current=[],s([]),e(null)},[]);return{vehicles:M,addVehicles:y,updateVehicle:D,removeVehicle:k,clear:b,error:g,_loadVehicles:x}}function X({vehicles:t,lines:c}){const[M,s]=r.useState(new Map),[g,e]=r.useState(null),d=r.useRef(new Map),x=r.useCallback(()=>d.current,[]),y=r.useCallback(b=>{d.current=b,s(b),e(null)},[]),D=r.useCallback((b,P)=>{if(!t.some(m=>m.id===b)){const m=`Vehicle '${b}' not found`;return e(m),{success:!1,error:m}}const i=c.find(m=>m.id===P.targetLineId);if(!i){const m=`Line '${P.targetLineId}' not found`;return e(m),{success:!1,error:m}}const n=P.isPercentage!==!1,p=R.distance(i.start,i.end);if(!n&&P.targetPosition===void 0){const m="targetPosition is required when isPercentage is false";return e(m),{success:!1,error:m}}const u=P.targetPosition??1;if(n){if(u<0||u>1){const m=`Invalid targetPosition: ${u} (must be 0-1 for percentage)`;return e(m),{success:!1,error:m}}}else{if(u<0){const m=`Invalid targetPosition: ${u} (must be >= 0 for absolute distance)`;return e(m),{success:!1,error:m}}if(u>p){const m=`Position ${u} exceeds line length ${p}`;return e(m),{success:!1,error:m}}}const v=J({vehicleId:b,...P}),V=new Map(d.current),Q=V.get(b)||[];return V.set(b,[...Q,v]),d.current=V,s(V),e(null),{success:!0}},[t,c]),k=r.useCallback(b=>{if(b!==void 0){if(!t.some(i=>i.id===b)){const i=`Vehicle '${b}' not found`;return e(i),{success:!1,error:i}}const C=new Map(d.current);C.delete(b),d.current=C,s(C)}else d.current=new Map,s(new Map);return e(null),{success:!0}},[t]);return{vehicleQueues:M,getVehicleQueues:x,queueMovement:D,clearQueue:k,error:g,_loadQueues:y}}function ee({vehicles:t,lines:c,vehicleQueues:M,getVehicleQueues:s,wheelbase:g,tangentMode:e,curves:d,eventEmitter:x}){const[y,D]=r.useState([]),k=r.useRef([]),b=r.useCallback(f=>{typeof f=="function"?D(o=>{const a=f(o);return k.current=a,a}):(k.current=f,D(f))},[]),P=r.useCallback(()=>k.current,[]),C=r.useMemo(()=>({wheelbase:g,tangentMode:e}),[g,e]),i=r.useMemo(()=>new Map(c.map(f=>[f.id,f])),[c]),n=r.useRef(new Map);r.useEffect(()=>{const{movingVehicles:f,stateMap:o}=R.initializeAllVehicles(t,i);n.current=o;const a=setTimeout(()=>{b(f)},0);return()=>clearTimeout(a)},[t,i]);const p=r.useRef(null);r.useEffect(()=>{c.length>0&&(p.current=R.buildGraph(c,d,C))},[c,d,C]);const u=r.useRef(0),v=r.useRef(!1),V=r.useCallback(f=>{if(!v.current)return!1;let o=!1;for(const[,l]of n.current)if(l.vehicle.state==="moving"){o=!0;break}if(!o)return!1;const a=[];for(const[l,h]of n.current){if(h.vehicle.state!=="moving"||!h.execution)continue;const I=h.execution;let S;if(I.front.currentSegmentIndex<I.path.segments.length){const T=I.path.segments[I.front.currentSegmentIndex];if(T.type==="line"){const E=i.get(T.lineId);E&&(S=Math.sqrt(Math.pow(E.end.x-E.start.x,2)+Math.pow(E.end.y-E.start.y,2)))}}const O=R.updateAxlePosition(h.vehicle.rear,I.rear,I.path,f,i,I.curveDataMap),q=R.updateAxlePosition(h.vehicle.front,I.front,I.path,f,i,I.curveDataMap,S);if(h.vehicle={...h.vehicle,rear:O.axleState,front:q.axleState},h.execution.rear=O.execution,h.execution.front=q.execution,O.completed){const T={linesMap:i,config:C,vehicleQueues:M,curves:d,graphRef:p,prepareCommandPath:R.prepareCommandPath,onCommandComplete:F=>a.push({type:"commandComplete",data:F}),onCommandStart:F=>a.push({type:"commandStart",data:F})},E=R.handleArrival(h,T);h.vehicle=E.vehicle,E.newExecution!==void 0&&(h.execution=E.newExecution),E.vehicle.state!=="moving"&&a.push({type:"stateChange",data:{vehicleId:l,from:"moving",to:E.vehicle.state}});const w=E.vehicle.rear.position,_=E.vehicle.front.position;a.push({type:"positionUpdate",data:{vehicleId:l,rear:w,front:_,center:{x:(w.x+_.x)/2,y:(w.y+_.y)/2},angle:Math.atan2(_.y-w.y,_.x-w.x)}})}}if(b(l=>l.map(h=>{const I=n.current.get(h.id);return I?I.vehicle:h})),x&&a.length>0){const l=u.current;setTimeout(()=>{u.current===l&&a.forEach(({type:h,data:I})=>{x.emit(h,I)})},0)}for(const[,l]of n.current)if(l.vehicle.state==="moving")return!0;return v.current=!1,!1},[i,d,C,M,x]),Q=r.useCallback(()=>{const f=p.current;if(!f)return!1;const o=s?s():M,a=[];let l=!1;for(const[h,I]of n.current){const S=I.vehicle;if(S.state==="moving")continue;const O=o.get(h);if(!O||O.length===0)continue;const q=O[0],T={graph:f,linesMap:i,curves:d,config:C},E=R.prepareCommandPath(S,q,T);if(!E){console.warn(`No path found for vehicle ${h}`);continue}const w=R.calculateFrontAxlePosition(E.path,0,0,g);n.current.set(h,{...I,execution:{path:E.path,curveDataMap:E.curveDataMap,currentCommandIndex:0,rear:{currentSegmentIndex:0,segmentDistance:0},front:w?{currentSegmentIndex:w.segmentIndex,segmentDistance:w.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},vehicle:{...S,state:"moving"}}),l=!0,a.push({id:h,fromState:S.state,command:q,startPosition:{lineId:S.rear.lineId,absoluteOffset:S.rear.absoluteOffset,position:S.rear.position}})}if(!l)return!1;if(v.current=!0,b(h=>h.map(I=>{const S=n.current.get(I.id);return S?S.vehicle:I})),x&&a.length>0){const h=u.current;setTimeout(()=>{u.current===h&&a.forEach(({id:I,fromState:S,command:O,startPosition:q})=>{x.emit("commandStart",{vehicleId:I,command:O,commandIndex:0,startPosition:q}),x.emit("stateChange",{vehicleId:I,from:S,to:"moving"})})},0)}return!0},[i,d,M,s,C,g,x]),m=r.useCallback(()=>{u.current++,v.current=!1;const{movingVehicles:f,stateMap:o}=R.initializeAllVehicles(t,i);n.current=o,b(f)},[t,i]),$=r.useCallback(f=>{const o=t.find(I=>I.id===f);if(!o||!i.get(o.lineId))return;const l=R.initializeMovingVehicle(o),h=R.createInitialMovementState(l);n.current.set(f,h),b(I=>I.map(S=>S.id===f?l:S))},[t,i]),L=r.useCallback(f=>{const o=n.current.get(f);if(!o||o.vehicle.state!=="waiting")return!1;const a=M.get(f),l=o.execution;if(!l)return!1;const h=l.currentCommandIndex+1;if(a&&h<a.length){const I=p.current;if(I){const S=a[h],O={graph:I,linesMap:i,curves:d,config:C},q=R.prepareCommandPath(o.vehicle,S,O);if(q){const T=R.calculateFrontAxlePosition(q.path,0,0,g);if(o.execution={path:q.path,curveDataMap:q.curveDataMap,currentCommandIndex:h,rear:{currentSegmentIndex:0,segmentDistance:0},front:T?{currentSegmentIndex:T.segmentIndex,segmentDistance:T.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},o.vehicle={...o.vehicle,state:"moving"},b(E=>E.map(w=>w.id===f?o.vehicle:w)),x){const E=u.current;setTimeout(()=>{u.current===E&&x.emit("stateChange",{vehicleId:f,from:"waiting",to:"moving"})},0)}return!0}}}if(o.vehicle={...o.vehicle,state:"idle"},o.execution=null,b(I=>I.map(S=>S.id===f?o.vehicle:S)),x){const I=u.current;setTimeout(()=>{u.current===I&&x.emit("stateChange",{vehicleId:f,from:"waiting",to:"idle"})},0)}return!0},[M,i,d,C,g,x]),j=r.useCallback(()=>{for(const[,f]of n.current)if(f.vehicle.state==="moving")return!0;return!1},[]);return{movingVehicles:y,getMovingVehicles:P,prepare:Q,tick:V,reset:m,resetVehicle:$,continueVehicle:L,isMoving:j,isPrepared:v.current}}function ne({wheelbase:t,tangentMode:c="proportional-40",eventEmitter:M}){const s=B(),g=W({lines:s.lines,wheelbase:t}),e=X({vehicles:g.vehicles,lines:s.lines,curves:s.curves}),d=ee({vehicles:g.vehicles,lines:s.lines,vehicleQueues:e.vehicleQueues,getVehicleQueues:e.getVehicleQueues,wheelbase:t,tangentMode:c,curves:s.curves,eventEmitter:M}),x=r.useCallback(o=>g.vehicles.filter(a=>a.lineId===o||a.rear.lineId===o),[g.vehicles]),y=r.useCallback(o=>x(o).length>0,[x]),D=r.useCallback(o=>{const a=s.addLine(o);return a.success?{success:!0}:{success:!1,error:a.error}},[s]),k=r.useCallback((o,a)=>{const l=s.updateLine(o,a);return l.success?{success:!0}:{success:!1,error:l.error}},[s]),b=r.useCallback(o=>{const a=[],l=x(o);l.length>0&&(a.push({type:"vehicle_on_removed_line",message:`${l.length} vehicle(s) are on line '${o}'`,details:{lineId:o,vehicleIds:l.map(S=>S.id)}}),l.forEach(S=>{g.removeVehicle(S.id),e.clearQueue(S.id)}));const h=s.curves.filter(S=>S.fromLineId===o||S.toLineId===o);h.length>0&&a.push({type:"orphaned_connection",message:`${h.length} connection(s) will be removed`,details:{lineId:o,connectionCount:h.length}});const I=s.removeLine(o);return I.success?{success:!0,warnings:a.length>0?a:void 0}:{success:!1,error:I.error}},[s,x,g,e]),P=r.useCallback(()=>{s.clear(),g.clear(),e.clearQueue()},[s,g,e]),C=r.useCallback((o,a,l)=>{const h=s.addConnection({from:o,to:a,fromPosition:l?.fromOffset,fromIsPercentage:l?.fromIsPercentage,toPosition:l?.toOffset,toIsPercentage:l?.toIsPercentage});return h.success?{success:!0}:{success:!1,error:h.error}},[s]),i=r.useCallback((o,a,l)=>{const h=s.updateConnection(o,a,l);return h.success?{success:!0}:{success:!1,error:h.error}},[s]),n=r.useCallback((o,a)=>{const l=s.removeConnection(o,a);return l.success?{success:!0}:{success:!1,error:l.error}},[s]),p=r.useCallback(o=>{const a=g.addVehicles(o);return a.success?{success:!0}:{success:!1,error:a.errors?.join("; ")}},[g]),u=r.useCallback((o,a)=>{const l=g.updateVehicle(o,a);return l.success?{success:!0}:{success:!1,error:l.error}},[g]),v=r.useCallback(o=>{const a=[],l=e.vehicleQueues.get(o);l&&l.length>0&&(a.push({type:"movement_queue_cleared",message:`${l.length} queued movement(s) will be cleared for vehicle '${o}'`,details:{vehicleId:o}}),e.clearQueue(o));const h=g.removeVehicle(o);return h.success?{success:!0,warnings:a.length>0?a:void 0}:{success:!1,error:h.error}},[g,e]),V=r.useCallback(()=>{g.clear(),e.clearQueue()},[g,e]),Q=r.useCallback(o=>{const a={targetLineId:o.lineId,targetPosition:o.position??1,isPercentage:o.isPercentage,wait:o.wait,payload:o.payload},l=e.queueMovement(o.id,a);return l.success?{success:!0}:{success:!1,error:l.error}},[e]),m=r.useCallback(o=>{const a=e.clearQueue(o);return a.success?{success:!0}:{success:!1,error:a.error}},[e]),$=r.useCallback(o=>{e.clearQueue(o),d.resetVehicle(o)},[e,d]),L=r.useCallback(o=>{const a=[],l=[],{scene:h,vehicles:I,movements:S}=A.parseAllDSL(o);h.errors.length>0&&l.push(...h.errors),I.errors.length>0&&l.push(...I.errors),S.errors.length>0&&l.push(...S.errors);const O=h.data.lines.map(K),q=(h.data.connections||[]).map(U),T=I.data.map(H),{vehicles:E,errors:w}=A.validateAndCreateVehicles(T,O,t);w.length>0&&l.push(...w);const _=new Map;for(const F of S.data){const Z=_.get(F.vehicleId)||[];Z.push(J(F)),_.set(F.vehicleId,Z)}return s._loadScene(O,q),g._loadVehicles(E),e._loadQueues(_),l.length>0&&a.push({type:"dsl_parse_error",message:`DSL loading had ${l.length} error(s)`,details:{errors:l}}),{success:!0,warnings:a.length>0?a:void 0}},[s,g,e,t]),j=r.useCallback(o=>{const a=[],l=[],h=o.lines.map(K),I=(o.connections||[]).map(U),S=(o.vehicles||[]).map(H),{vehicles:O,errors:q}=A.validateAndCreateVehicles(S,h,t);q.length>0&&l.push(...q);const T=new Map;for(const E of o.movements||[]){const w=T.get(E.vehicleId)||[];w.push(J({vehicleId:E.vehicleId,targetLineId:E.targetLineId,targetPosition:E.targetPosition,isPercentage:E.isPercentage,wait:E.wait,payload:E.payload})),T.set(E.vehicleId,w)}return s._loadScene(h,I),g._loadVehicles(O),e._loadQueues(T),l.length>0&&a.push({type:"dsl_parse_error",message:`JSON loading had ${l.length} error(s)`,details:{errors:l}}),{success:!0,warnings:a.length>0?a:void 0}},[s,g,e,t]),f=r.useMemo(()=>s.error||g.error||e.error,[s.error,g.error,e.error]);return{lines:s.lines,curves:s.curves,vehicles:g.vehicles,movingVehicles:d.movingVehicles,getMovingVehicles:d.getMovingVehicles,vehicleQueues:e.vehicleQueues,error:f,addLine:D,updateLine:k,removeLine:b,clearScene:P,connect:C,updateConnection:i,disconnect:n,addVehicles:p,updateVehicle:u,removeVehicle:v,clearVehicles:V,goto:Q,clearQueue:m,prepare:d.prepare,tick:d.tick,reset:d.reset,resetVehicle:$,continueVehicle:d.continueVehicle,isMoving:d.isMoving,loadFromDSL:L,loadFromJSON:j,getVehiclesOnLine:x,hasVehiclesOnLine:y}}function z(t){return t.map(c=>({id:c.id,start:c.start,end:c.end}))}function N(t){return t.map(c=>({from:c.fromLineId,to:c.toLineId,fromPosition:c.fromOffset,fromIsPercentage:c.fromIsPercentage,toPosition:c.toOffset,toIsPercentage:c.toIsPercentage}))}function oe(){const[t,c]=r.useState(""),[M,s]=r.useState(null),{lines:g,curves:e,setScene:d}=B(),x=r.useRef(!1),y=r.useRef("");r.useEffect(()=>{y.current=t},[t]),r.useEffect(()=>{if(x.current)return;const P={lines:z(g),connections:e.length>0?N(e):void 0},C=A.generateSceneDSL(P);C!==y.current&&(x.current=!0,c(C),setTimeout(()=>{x.current=!1},50))},[g,e]);const D=r.useCallback(P=>{x.current=!0,c(P);try{const{data:C,errors:i}=A.parseSceneDSL(P);i.length>0&&s(i.join("; "));const n=d(C);!n.success&&n.errors?s(p=>p?`${p}; ${n.errors.join("; ")}`:n.errors.join("; ")):i.length===0&&s(null)}catch(C){s(C instanceof Error?C.message:"Invalid scene definition")}setTimeout(()=>{x.current=!1},50)},[d]),k=r.useCallback(P=>{const C=typeof P=="function"?P(g):P,i=N(e);d({lines:z(C),connections:i.length>0?i:void 0});const n={lines:z(C),connections:i.length>0?i:void 0},p=A.generateSceneDSL(n);x.current=!0,c(p),setTimeout(()=>{x.current=!1},50)},[g,e,d]),b=r.useCallback(P=>{const C=typeof P=="function"?P(e):P,i=N(C);d({lines:z(g),connections:i.length>0?i:void 0});const n={lines:z(g),connections:i.length>0?i:void 0},p=A.generateSceneDSL(n);x.current=!0,c(p),setTimeout(()=>{x.current=!1},50)},[g,e,d]);return{lines:g,curves:e,sceneDefinitionText:t,sceneError:M,isDebouncing:!1,debounceKey:0,setLines:k,setCurves:b,setSceneDefinitionText:D}}function ce({lines:t,wheelbase:c}){const[M,s]=r.useState(""),[g,e]=r.useState(null),{vehicles:d,addVehicles:x,clear:y,error:D}=W({lines:t,wheelbase:c}),k=r.useRef(!1),b=r.useCallback(P=>{k.current=!0,s(P);try{const{data:C,errors:i}=A.parseVehiclesDSL(P),n=[...i];y();for(const p of C){const u=x(p);!u.success&&u.errors&&n.push(...u.errors)}n.length>0?e(n.join(`
|
|
2
2
|
`)):e(null)}catch(C){e(C instanceof Error?C.message:"Invalid initial movement")}setTimeout(()=>{k.current=!1},50)},[x,y]);return{vehicles:d,initialMovementText:M,movementError:g||D,isDebouncing:!1,debounceKey:0,setInitialMovementText:b}}function ie({lines:t,vehicles:c}){const[M,s]=r.useState(""),[g,e]=r.useState([]),[d,x]=r.useState(null),{vehicleQueues:y,queueMovement:D,clearQueue:k,error:b}=X({vehicles:c,lines:t}),P=r.useRef(!1),C=r.useCallback(i=>{P.current=!0,s(i);try{const{data:n,errors:p}=A.parseMovementDSL(i),u=[...p];k();for(const v of n){const V=D(v.vehicleId,{targetLineId:v.targetLineId,targetPosition:v.targetPosition,isPercentage:v.isPercentage,wait:v.wait,payload:v.payload});!V.success&&V.error&&u.push(V.error)}e(n),u.length>0?x(u.join(`
|
|
3
3
|
`)):x(null)}catch(n){x(n instanceof Error?n.message:"Invalid movement sequence"),e([])}setTimeout(()=>{P.current=!1},50)},[D,k]);return{movementSequenceText:M,gotoCommands:g,vehicleQueues:y,sequenceError:d||b,isDebouncing:!1,debounceKey:0,setMovementSequenceText:C}}const Y=r.createContext(null);function te(){const t=r.useContext(Y);if(!t)throw new Error("useVehicleEventEmitter must be used within a VehicleEventProvider");return t}function ae(){return r.useMemo(()=>new A.VehicleEventEmitter,[])}function ue(t,c,M=[]){const s=te();r.useEffect(()=>s.on(t,c),[s,t,...M])}function le({children:t}){const c=r.useMemo(()=>new A.VehicleEventEmitter,[]);return se.jsx(Y.Provider,{value:c,children:t})}exports.VehicleEventContext=Y;exports.VehicleEventProvider=le;exports.useAnimation=ee;exports.useCreateVehicleEventEmitter=ae;exports.useInitialMovement=ce;exports.useMovementQueue=X;exports.useMovementSequence=ie;exports.useScene=B;exports.useSceneDefinition=oe;exports.useVehicleEvent=ue;exports.useVehicleEventEmitter=te;exports.useVehicleSimulation=ne;exports.useVehicles=W;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState as _, useCallback as p, useRef as A, useMemo as G, useEffect as K, createContext as ue, useContext as le } from "react";
|
|
2
2
|
import { distance as fe, initializeAllVehicles as te, buildGraph as de, updateAxlePosition as re, handleArrival as me, prepareCommandPath as B, calculateFrontAxlePosition as se, initializeMovingVehicle as ge, createInitialMovementState as he } from "./core.js";
|
|
3
|
-
import { v as N, p as ve, a as W, f as pe, h as Pe, e as Ie, V as ne } from "./vehicle-helpers-
|
|
3
|
+
import { v as N, p as ve, a as W, f as pe, h as Pe, e as Ie, V as ne } from "./vehicle-helpers-BYb2Ibex.js";
|
|
4
4
|
import { jsx as xe } from "react/jsx-runtime";
|
|
5
5
|
function J(t) {
|
|
6
6
|
return Array.isArray(t) ? { x: t[0], y: t[1] } : t;
|
package/dist/utils.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./vehicle-helpers-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./vehicle-helpers-bgHGBdo9.cjs"),t=require("./animation-loop-fC2LjxCd.cjs");exports.VehicleEventEmitter=e.VehicleEventEmitter;exports.generateMovementDSL=e.generateMovementDSL;exports.generateSceneDSL=e.generateSceneDSL;exports.generateVehiclesDSL=e.generateVehiclesDSL;exports.getNextGotoVehicleId=e.getNextGotoVehicleId;exports.getNextStartVehicleId=e.getNextStartVehicleId;exports.parseAllDSL=e.parseAllDSL;exports.parseMovementDSL=e.parseMovementDSL;exports.parseSceneDSL=e.parseSceneDSL;exports.parseVehiclesDSL=e.parseVehiclesDSL;exports.validateAndCreateVehicles=e.validateAndCreateVehicles;exports.createAnimationLoop=t.createAnimationLoop;exports.useAnimationLoop=t.useAnimationLoop;
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { V as t, g as s, a as r, b as o, c as n, d as i, p as c, e as S, f as l, h as p, v as L } from "./vehicle-helpers-
|
|
1
|
+
import { V as t, g as s, a as r, b as o, c as n, d as i, p as c, e as S, f as l, h as p, v as L } from "./vehicle-helpers-BYb2Ibex.js";
|
|
2
2
|
import { c as m, u as D } from "./animation-loop-bZEm2pMN.js";
|
|
3
3
|
export {
|
|
4
4
|
t as VehicleEventEmitter,
|
|
@@ -7,9 +7,9 @@ class S {
|
|
|
7
7
|
* @param callback - Function to call when event is emitted
|
|
8
8
|
* @returns Unsubscribe function
|
|
9
9
|
*/
|
|
10
|
-
on(
|
|
11
|
-
return this.listeners.has(
|
|
12
|
-
this.listeners.get(
|
|
10
|
+
on(e, t) {
|
|
11
|
+
return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(t), () => {
|
|
12
|
+
this.listeners.get(e)?.delete(t);
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -17,12 +17,12 @@ class S {
|
|
|
17
17
|
* @param event - The event type to emit
|
|
18
18
|
* @param data - The event data
|
|
19
19
|
*/
|
|
20
|
-
emit(
|
|
21
|
-
this.listeners.get(
|
|
20
|
+
emit(e, t) {
|
|
21
|
+
this.listeners.get(e)?.forEach((s) => {
|
|
22
22
|
try {
|
|
23
|
-
s(
|
|
23
|
+
s(t);
|
|
24
24
|
} catch (o) {
|
|
25
|
-
console.error(`Error in event listener for "${
|
|
25
|
+
console.error(`Error in event listener for "${e}":`, o);
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
}
|
|
@@ -30,29 +30,29 @@ class S {
|
|
|
30
30
|
* Remove all listeners for a specific event, or all events if no event specified
|
|
31
31
|
* @param event - Optional event type to clear listeners for
|
|
32
32
|
*/
|
|
33
|
-
off(
|
|
34
|
-
|
|
33
|
+
off(e) {
|
|
34
|
+
e ? this.listeners.delete(e) : this.listeners.clear();
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Get the number of listeners for a specific event
|
|
38
38
|
* @param event - The event type
|
|
39
39
|
* @returns Number of listeners
|
|
40
40
|
*/
|
|
41
|
-
listenerCount(
|
|
42
|
-
return this.listeners.get(
|
|
41
|
+
listenerCount(e) {
|
|
42
|
+
return this.listeners.get(e)?.size ?? 0;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
function P(i) {
|
|
46
|
-
const
|
|
46
|
+
const e = [], t = [], s = [], o = i.trim().split(`
|
|
47
47
|
`);
|
|
48
|
-
let
|
|
48
|
+
let d = 0;
|
|
49
49
|
for (const n of o) {
|
|
50
|
-
|
|
50
|
+
d++;
|
|
51
51
|
const r = n.trim();
|
|
52
52
|
if (!r || r.startsWith("#")) continue;
|
|
53
53
|
const a = r.match(/^(\w+)\s*:\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)\s*->\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)/);
|
|
54
54
|
if (a) {
|
|
55
|
-
|
|
55
|
+
e.push({
|
|
56
56
|
id: a[1],
|
|
57
57
|
start: [parseFloat(a[2]), parseFloat(a[3])],
|
|
58
58
|
end: [parseFloat(a[4]), parseFloat(a[5])]
|
|
@@ -66,38 +66,38 @@ function P(i) {
|
|
|
66
66
|
to: c[4]
|
|
67
67
|
};
|
|
68
68
|
if (c[2]) {
|
|
69
|
-
const f = parseFloat(c[2]);
|
|
70
|
-
l.fromPosition =
|
|
69
|
+
const f = parseFloat(c[2]), h = c[3] === "%";
|
|
70
|
+
l.fromPosition = h ? f / 100 : f, l.fromIsPercentage = h;
|
|
71
71
|
}
|
|
72
72
|
if (c[5]) {
|
|
73
|
-
const f = parseFloat(c[5]);
|
|
74
|
-
l.toPosition =
|
|
73
|
+
const f = parseFloat(c[5]), h = c[6] === "%";
|
|
74
|
+
l.toPosition = h ? f / 100 : f, l.toIsPercentage = h;
|
|
75
75
|
}
|
|
76
|
-
|
|
76
|
+
t.push(l);
|
|
77
77
|
continue;
|
|
78
78
|
}
|
|
79
|
-
r.match(/^\w+\s+start\s+/) || r.match(/^\w+\s+goto\s+/) || s.push(`Line ${
|
|
79
|
+
r.match(/^\w+\s+start\s+/) || r.match(/^\w+\s+goto\s+/) || s.push(`Line ${d}: Unable to parse "${r}"`);
|
|
80
80
|
}
|
|
81
81
|
return {
|
|
82
82
|
data: {
|
|
83
|
-
lines:
|
|
84
|
-
connections:
|
|
83
|
+
lines: e,
|
|
84
|
+
connections: t.length > 0 ? t : void 0
|
|
85
85
|
},
|
|
86
86
|
errors: s
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
function v(i) {
|
|
90
|
-
const
|
|
90
|
+
const e = [], t = [], s = i.trim().split(`
|
|
91
91
|
`);
|
|
92
92
|
let o = 0;
|
|
93
|
-
for (const
|
|
93
|
+
for (const d of s) {
|
|
94
94
|
o++;
|
|
95
|
-
const n =
|
|
95
|
+
const n = d.trim();
|
|
96
96
|
if (!n || n.startsWith("#")) continue;
|
|
97
97
|
const r = n.match(/^(\w+)\s+start\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);
|
|
98
98
|
if (r) {
|
|
99
99
|
const a = parseFloat(r[3]), c = r[4] === "%";
|
|
100
|
-
|
|
100
|
+
e.push({
|
|
101
101
|
id: r[1],
|
|
102
102
|
lineId: r[2],
|
|
103
103
|
// API uses 0-1 for percentage, DSL uses 0-100
|
|
@@ -106,20 +106,20 @@ function v(i) {
|
|
|
106
106
|
});
|
|
107
107
|
continue;
|
|
108
108
|
}
|
|
109
|
-
n.match(/^\w+\s*:\s*\(/) || n.match(/^\w+.*->\s*\w+/) || n.match(/^\w+\s+goto\s+/) || n.match(/^\w+\s+start/) &&
|
|
109
|
+
n.match(/^\w+\s*:\s*\(/) || n.match(/^\w+.*->\s*\w+/) || n.match(/^\w+\s+goto\s+/) || n.match(/^\w+\s+start/) && t.push(`Line ${o}: Invalid vehicle start format "${n}"`);
|
|
110
110
|
}
|
|
111
111
|
return {
|
|
112
|
-
data:
|
|
113
|
-
errors:
|
|
112
|
+
data: e,
|
|
113
|
+
errors: t
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
function w(i) {
|
|
117
|
-
const
|
|
117
|
+
const e = [], t = [], s = i.trim().split(`
|
|
118
118
|
`);
|
|
119
119
|
let o = 0;
|
|
120
|
-
for (const
|
|
120
|
+
for (const d of s) {
|
|
121
121
|
o++;
|
|
122
|
-
const n =
|
|
122
|
+
const n = d.trim();
|
|
123
123
|
if (!n || n.startsWith("#")) continue;
|
|
124
124
|
const r = n.match(/^(\w+)\s+goto\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);
|
|
125
125
|
if (r) {
|
|
@@ -130,26 +130,26 @@ function w(i) {
|
|
|
130
130
|
try {
|
|
131
131
|
l = JSON.parse(f[1]);
|
|
132
132
|
} catch {
|
|
133
|
-
|
|
133
|
+
t.push(`Line ${o}: Invalid JSON payload "${f[1]}"`);
|
|
134
134
|
}
|
|
135
|
-
const
|
|
136
|
-
|
|
135
|
+
const h = parseFloat(r[3]), u = r[4] === "%";
|
|
136
|
+
e.push({
|
|
137
137
|
vehicleId: r[1],
|
|
138
138
|
targetLineId: r[2],
|
|
139
139
|
// API uses 0-1 for percentage, DSL uses 0-100
|
|
140
140
|
// For absolute offsets, keep the raw value
|
|
141
|
-
targetPosition: u ?
|
|
141
|
+
targetPosition: u ? h / 100 : h,
|
|
142
142
|
isPercentage: u,
|
|
143
143
|
wait: c || void 0,
|
|
144
144
|
payload: l
|
|
145
145
|
});
|
|
146
146
|
continue;
|
|
147
147
|
}
|
|
148
|
-
n.match(/^\w+\s*:\s*\(/) || n.match(/^\w+.*->\s*\w+/) || n.match(/^\w+\s+start\s+/) || n.match(/^\w+\s+goto/) &&
|
|
148
|
+
n.match(/^\w+\s*:\s*\(/) || n.match(/^\w+.*->\s*\w+/) || n.match(/^\w+\s+start\s+/) || n.match(/^\w+\s+goto/) && t.push(`Line ${o}: Invalid goto command format "${n}"`);
|
|
149
149
|
}
|
|
150
150
|
return {
|
|
151
|
-
data:
|
|
152
|
-
errors:
|
|
151
|
+
data: e,
|
|
152
|
+
errors: t
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
function y(i) {
|
|
@@ -163,48 +163,48 @@ function m(i) {
|
|
|
163
163
|
return Array.isArray(i) ? { x: i[0], y: i[1] } : i;
|
|
164
164
|
}
|
|
165
165
|
function M(i) {
|
|
166
|
-
const
|
|
167
|
-
for (const
|
|
168
|
-
const s = m(
|
|
169
|
-
|
|
166
|
+
const e = [];
|
|
167
|
+
for (const t of i.lines) {
|
|
168
|
+
const s = m(t.start), o = m(t.end);
|
|
169
|
+
e.push(`${t.id} : (${Math.round(s.x)}, ${Math.round(s.y)}) -> (${Math.round(o.x)}, ${Math.round(o.y)})`);
|
|
170
170
|
}
|
|
171
|
-
if (i.lines.length > 0 && i.connections && i.connections.length > 0 &&
|
|
172
|
-
for (const
|
|
173
|
-
let s =
|
|
174
|
-
|
|
171
|
+
if (i.lines.length > 0 && i.connections && i.connections.length > 0 && e.push(""), i.connections)
|
|
172
|
+
for (const t of i.connections) {
|
|
173
|
+
let s = t.from;
|
|
174
|
+
t.fromPosition !== void 0 && (t.fromIsPercentage !== !1 ? s += ` ${t.fromPosition * 100}%` : s += ` ${t.fromPosition}`), s += " -> ", s += t.to, t.toPosition !== void 0 && (t.toIsPercentage !== !1 ? s += ` ${t.toPosition * 100}%` : s += ` ${t.toPosition}`), e.push(s);
|
|
175
175
|
}
|
|
176
|
-
return
|
|
176
|
+
return e.join(`
|
|
177
177
|
`);
|
|
178
178
|
}
|
|
179
179
|
function x(i) {
|
|
180
|
-
return i.map((
|
|
181
|
-
const
|
|
182
|
-
return
|
|
180
|
+
return i.map((e) => {
|
|
181
|
+
const t = e.position ?? 0;
|
|
182
|
+
return e.isPercentage !== !1 ? `${e.id} start ${e.lineId} ${t * 100}%` : `${e.id} start ${e.lineId} ${t}`;
|
|
183
183
|
}).join(`
|
|
184
184
|
`);
|
|
185
185
|
}
|
|
186
186
|
function V(i) {
|
|
187
|
-
return i.map((
|
|
188
|
-
const
|
|
189
|
-
let o =
|
|
190
|
-
return o += ` goto ${
|
|
187
|
+
return i.map((e) => {
|
|
188
|
+
const t = e.targetPosition ?? 1, s = e.isPercentage !== !1;
|
|
189
|
+
let o = e.vehicleId;
|
|
190
|
+
return o += ` goto ${e.targetLineId}`, s ? o += ` ${t * 100}%` : o += ` ${t}`, e.wait && (o += " --wait"), e.payload !== void 0 && (o += ` --payload ${JSON.stringify(e.payload)}`), o;
|
|
191
191
|
}).join(`
|
|
192
192
|
`);
|
|
193
193
|
}
|
|
194
|
-
function N(i,
|
|
195
|
-
const s = [], o = [],
|
|
194
|
+
function N(i, e, t = 0) {
|
|
195
|
+
const s = [], o = [], d = /* @__PURE__ */ new Set();
|
|
196
196
|
for (const n of i) {
|
|
197
|
-
if (
|
|
197
|
+
if (d.has(n.vehicleId)) {
|
|
198
198
|
o.push(`Duplicate vehicle ID: ${n.vehicleId}`);
|
|
199
199
|
continue;
|
|
200
200
|
}
|
|
201
|
-
|
|
202
|
-
const r =
|
|
201
|
+
d.add(n.vehicleId);
|
|
202
|
+
const r = e.find((p) => p.id === n.lineId);
|
|
203
203
|
if (!r) {
|
|
204
204
|
o.push(`Vehicle ${n.vehicleId}: Line "${n.lineId}" not found`);
|
|
205
205
|
continue;
|
|
206
206
|
}
|
|
207
|
-
const a = g(r.start, r.end), c = Math.max(0, a -
|
|
207
|
+
const a = g(r.start, r.end), c = Math.max(0, a - t);
|
|
208
208
|
let l;
|
|
209
209
|
if (n.isPercentage) {
|
|
210
210
|
if (n.offset < 0 || n.offset > 1) {
|
|
@@ -219,14 +219,14 @@ function N(i, t, e = 0) {
|
|
|
219
219
|
}
|
|
220
220
|
l = Math.min(n.offset, c);
|
|
221
221
|
}
|
|
222
|
-
const f = $(r, l, !1),
|
|
222
|
+
const f = $(r, l, !1), h = {
|
|
223
223
|
lineId: n.lineId,
|
|
224
224
|
position: f,
|
|
225
225
|
absoluteOffset: l
|
|
226
226
|
}, u = I(
|
|
227
227
|
n.lineId,
|
|
228
228
|
l,
|
|
229
|
-
|
|
229
|
+
t,
|
|
230
230
|
r
|
|
231
231
|
);
|
|
232
232
|
s.push({
|
|
@@ -235,31 +235,31 @@ function N(i, t, e = 0) {
|
|
|
235
235
|
offset: n.offset,
|
|
236
236
|
isPercentage: n.isPercentage,
|
|
237
237
|
state: "idle",
|
|
238
|
-
rear:
|
|
238
|
+
rear: h,
|
|
239
239
|
front: u
|
|
240
240
|
});
|
|
241
241
|
}
|
|
242
242
|
return { vehicles: s, errors: o };
|
|
243
243
|
}
|
|
244
244
|
function b(i) {
|
|
245
|
-
const
|
|
245
|
+
const e = i.map((s) => {
|
|
246
246
|
const o = s.vehicleId.match(/^v(\d+)$/);
|
|
247
247
|
return o ? parseInt(o[1]) : 0;
|
|
248
248
|
}).filter((s) => s > 0);
|
|
249
|
-
return `v${(
|
|
249
|
+
return `v${(e.length > 0 ? Math.max(...e) : 0) + 1}`;
|
|
250
250
|
}
|
|
251
|
-
function F(i,
|
|
252
|
-
if (
|
|
251
|
+
function F(i, e) {
|
|
252
|
+
if (e.length === 0) return null;
|
|
253
253
|
if (i.length === 0)
|
|
254
|
-
return
|
|
255
|
-
const
|
|
256
|
-
for (const s of
|
|
257
|
-
|
|
254
|
+
return e[0].id;
|
|
255
|
+
const t = /* @__PURE__ */ new Map();
|
|
256
|
+
for (const s of e)
|
|
257
|
+
t.set(s.id, 0);
|
|
258
258
|
for (const s of i) {
|
|
259
|
-
const o =
|
|
260
|
-
|
|
259
|
+
const o = t.get(s.vehicleId) || 0;
|
|
260
|
+
t.set(s.vehicleId, o + 1);
|
|
261
261
|
}
|
|
262
|
-
return
|
|
262
|
+
return e[0].id;
|
|
263
263
|
}
|
|
264
264
|
export {
|
|
265
265
|
S as V,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"use strict";const m=require("./core.cjs");class
|
|
2
|
-
`);let
|
|
3
|
-
`);let o=0;for(const
|
|
4
|
-
`);let o=0;for(const
|
|
1
|
+
"use strict";const m=require("./core.cjs");class v{listeners=new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.listeners.get(e)?.delete(t)}}emit(e,t){this.listeners.get(e)?.forEach(s=>{try{s(t)}catch(o){console.error(`Error in event listener for "${e}":`,o)}})}off(e){e?this.listeners.delete(e):this.listeners.clear()}listenerCount(e){return this.listeners.get(e)?.size??0}}function g(i){const e=[],t=[],s=[],o=i.trim().split(`
|
|
2
|
+
`);let d=0;for(const n of o){d++;const r=n.trim();if(!r||r.startsWith("#"))continue;const a=r.match(/^(\w+)\s*:\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)\s*->\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)/);if(a){e.push({id:a[1],start:[parseFloat(a[2]),parseFloat(a[3])],end:[parseFloat(a[4]),parseFloat(a[5])]});continue}const c=r.match(/^(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))??\s*->\s*(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))?/);if(c){const l={from:c[1],to:c[4]};if(c[2]){const f=parseFloat(c[2]),h=c[3]==="%";l.fromPosition=h?f/100:f,l.fromIsPercentage=h}if(c[5]){const f=parseFloat(c[5]),h=c[6]==="%";l.toPosition=h?f/100:f,l.toIsPercentage=h}t.push(l);continue}r.match(/^\w+\s+start\s+/)||r.match(/^\w+\s+goto\s+/)||s.push(`Line ${d}: Unable to parse "${r}"`)}return{data:{lines:e,connections:t.length>0?t:void 0},errors:s}}function I(i){const e=[],t=[],s=i.trim().split(`
|
|
3
|
+
`);let o=0;for(const d of s){o++;const n=d.trim();if(!n||n.startsWith("#"))continue;const r=n.match(/^(\w+)\s+start\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);if(r){const a=parseFloat(r[3]),c=r[4]==="%";e.push({id:r[1],lineId:r[2],position:c?a/100:a,isPercentage:c});continue}n.match(/^\w+\s*:\s*\(/)||n.match(/^\w+.*->\s*\w+/)||n.match(/^\w+\s+goto\s+/)||n.match(/^\w+\s+start/)&&t.push(`Line ${o}: Invalid vehicle start format "${n}"`)}return{data:e,errors:t}}function $(i){const e=[],t=[],s=i.trim().split(`
|
|
4
|
+
`);let o=0;for(const d of s){o++;const n=d.trim();if(!n||n.startsWith("#"))continue;const r=n.match(/^(\w+)\s+goto\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);if(r){const a=n.slice(r[0].length),c=a.includes("--wait");let l;const f=a.match(/--payload\s+(\{.*\})/);if(f)try{l=JSON.parse(f[1])}catch{t.push(`Line ${o}: Invalid JSON payload "${f[1]}"`)}const h=parseFloat(r[3]),u=r[4]==="%";e.push({vehicleId:r[1],targetLineId:r[2],targetPosition:u?h/100:h,isPercentage:u,wait:c||void 0,payload:l});continue}n.match(/^\w+\s*:\s*\(/)||n.match(/^\w+.*->\s*\w+/)||n.match(/^\w+\s+start\s+/)||n.match(/^\w+\s+goto/)&&t.push(`Line ${o}: Invalid goto command format "${n}"`)}return{data:e,errors:t}}function L(i){return{scene:g(i),vehicles:I(i),movements:$(i)}}function p(i){return Array.isArray(i)?{x:i[0],y:i[1]}:i}function w(i){const e=[];for(const t of i.lines){const s=p(t.start),o=p(t.end);e.push(`${t.id} : (${Math.round(s.x)}, ${Math.round(s.y)}) -> (${Math.round(o.x)}, ${Math.round(o.y)})`)}if(i.lines.length>0&&i.connections&&i.connections.length>0&&e.push(""),i.connections)for(const t of i.connections){let s=t.from;t.fromPosition!==void 0&&(t.fromIsPercentage!==!1?s+=` ${t.fromPosition*100}%`:s+=` ${t.fromPosition}`),s+=" -> ",s+=t.to,t.toPosition!==void 0&&(t.toIsPercentage!==!1?s+=` ${t.toPosition*100}%`:s+=` ${t.toPosition}`),e.push(s)}return e.join(`
|
|
5
5
|
`)}function S(i){return i.map(e=>{const t=e.position??0;return e.isPercentage!==!1?`${e.id} start ${e.lineId} ${t*100}%`:`${e.id} start ${e.lineId} ${t}`}).join(`
|
|
6
6
|
`)}function M(i){return i.map(e=>{const t=e.targetPosition??1,s=e.isPercentage!==!1;let o=e.vehicleId;return o+=` goto ${e.targetLineId}`,s?o+=` ${t*100}%`:o+=` ${t}`,e.wait&&(o+=" --wait"),e.payload!==void 0&&(o+=` --payload ${JSON.stringify(e.payload)}`),o}).join(`
|
|
7
|
-
`)}function V(i,e,t=0){const s=[],o=[],
|
|
7
|
+
`)}function V(i,e,t=0){const s=[],o=[],d=new Set;for(const n of i){if(d.has(n.vehicleId)){o.push(`Duplicate vehicle ID: ${n.vehicleId}`);continue}d.add(n.vehicleId);const r=e.find(P=>P.id===n.lineId);if(!r){o.push(`Vehicle ${n.vehicleId}: Line "${n.lineId}" not found`);continue}const a=m.distance(r.start,r.end),c=Math.max(0,a-t);let l;if(n.isPercentage){if(n.offset<0||n.offset>1){o.push(`Vehicle ${n.vehicleId}: Offset ${n.offset} must be between 0 and 1 for percentage`);continue}l=n.offset*c}else{if(n.offset<0||n.offset>a){o.push(`Vehicle ${n.vehicleId}: Offset ${n.offset} exceeds line length ${a.toFixed(2)}`);continue}l=Math.min(n.offset,c)}const f=m.getPointOnLineByOffset(r,l,!1),h={lineId:n.lineId,position:f,absoluteOffset:l},u=m.calculateInitialFrontPosition(n.lineId,l,t,r);s.push({id:n.vehicleId,lineId:n.lineId,offset:n.offset,isPercentage:n.isPercentage,state:"idle",rear:h,front:u})}return{vehicles:s,errors:o}}function y(i){const e=i.map(s=>{const o=s.vehicleId.match(/^v(\d+)$/);return o?parseInt(o[1]):0}).filter(s=>s>0);return`v${(e.length>0?Math.max(...e):0)+1}`}function D(i,e){if(e.length===0)return null;if(i.length===0)return e[0].id;const t=new Map;for(const s of e)t.set(s.id,0);for(const s of i){const o=t.get(s.vehicleId)||0;t.set(s.vehicleId,o+1)}return e[0].id}exports.VehicleEventEmitter=v;exports.generateMovementDSL=M;exports.generateSceneDSL=w;exports.generateVehiclesDSL=S;exports.getNextGotoVehicleId=D;exports.getNextStartVehicleId=y;exports.parseAllDSL=L;exports.parseMovementDSL=$;exports.parseSceneDSL=g;exports.parseVehiclesDSL=I;exports.validateAndCreateVehicles=V;
|
package/dist/vehicle-path.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),i=require("./vehicle-helpers-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),i=require("./vehicle-helpers-bgHGBdo9.cjs"),n=require("./animation-loop-fC2LjxCd.cjs"),t=require("./useVehicleEvents-B7Z-9Hn2.cjs");exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialFrontPosition=e.calculateInitialFrontPosition;exports.calculatePositionOnCurve=e.calculatePositionOnCurve;exports.calculatePositionOnLine=e.calculatePositionOnLine;exports.createBezierCurve=e.createBezierCurve;exports.createInitialMovementState=e.createInitialMovementState;exports.distance=e.distance;exports.distanceToT=e.distanceToT;exports.findPath=e.findPath;exports.getArcLength=e.getArcLength;exports.getCumulativeArcLength=e.getCumulativeArcLength;exports.getLineLength=e.getLineLength;exports.getPointOnBezier=e.getPointOnBezier;exports.getPointOnLine=e.getPointOnLine;exports.getPointOnLineByOffset=e.getPointOnLineByOffset;exports.getPositionFromOffset=e.getPositionFromOffset;exports.handleArrival=e.handleArrival;exports.initializeAllVehicles=e.initializeAllVehicles;exports.initializeMovingVehicle=e.initializeMovingVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;exports.VehicleEventEmitter=i.VehicleEventEmitter;exports.generateMovementDSL=i.generateMovementDSL;exports.generateSceneDSL=i.generateSceneDSL;exports.generateVehiclesDSL=i.generateVehiclesDSL;exports.getNextGotoVehicleId=i.getNextGotoVehicleId;exports.getNextStartVehicleId=i.getNextStartVehicleId;exports.parseAllDSL=i.parseAllDSL;exports.parseMovementDSL=i.parseMovementDSL;exports.parseSceneDSL=i.parseSceneDSL;exports.parseVehiclesDSL=i.parseVehiclesDSL;exports.validateAndCreateVehicles=i.validateAndCreateVehicles;exports.createAnimationLoop=n.createAnimationLoop;exports.useAnimationLoop=n.useAnimationLoop;exports.VehicleEventContext=t.VehicleEventContext;exports.VehicleEventProvider=t.VehicleEventProvider;exports.useAnimation=t.useAnimation;exports.useCreateVehicleEventEmitter=t.useCreateVehicleEventEmitter;exports.useInitialMovement=t.useInitialMovement;exports.useMovement=t.useMovementQueue;exports.useMovementQueue=t.useMovementQueue;exports.useMovementSequence=t.useMovementSequence;exports.useScene=t.useScene;exports.useSceneDefinition=t.useSceneDefinition;exports.useVehicleEvent=t.useVehicleEvent;exports.useVehicleEventEmitter=t.useVehicleEventEmitter;exports.useVehicleMovement=t.useAnimation;exports.useVehicleSimulation=t.useVehicleSimulation;exports.useVehicles=t.useVehicles;
|
package/dist/vehicle-path.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { arcLengthToSegmentPosition as i, buildArcLengthTable as a, buildGraph as n, calculateBezierArcLength as s, calculateFrontAxlePosition as o, calculateInitialFrontPosition as l, calculatePositionOnCurve as r, calculatePositionOnLine as c, createBezierCurve as u, createInitialMovementState as h, distance as m, distanceToT as v, findPath as g, getArcLength as L, getCumulativeArcLength as V, getLineLength as d, getPointOnBezier as f, getPointOnLine as S, getPointOnLineByOffset as p, getPositionFromOffset as A, handleArrival as P, initializeAllVehicles as x, initializeMovingVehicle as E, normalize as M, prepareCommandPath as O, resolveFromLineOffset as D, resolveToLineOffset as C, updateAxlePosition as z } from "./core.js";
|
|
2
|
-
import { V as I, g as T, a as B, b as F, c as G, d as N, p as j, e as k, f as q, h as y, v as Q } from "./vehicle-helpers-
|
|
2
|
+
import { V as I, g as T, a as B, b as F, c as G, d as N, p as j, e as k, f as q, h as y, v as Q } from "./vehicle-helpers-BYb2Ibex.js";
|
|
3
3
|
import { c as H, u as J } from "./animation-loop-bZEm2pMN.js";
|
|
4
|
-
import { V as R, a as U, u as W, b as X, c as Y, d as Z, d as _, e as $, f as ee, g as te, h as ie, i as ae, u as ne, j as se, k as oe } from "./useVehicleEvents-
|
|
4
|
+
import { V as R, a as U, u as W, b as X, c as Y, d as Z, d as _, e as $, f as ee, g as te, h as ie, i as ae, u as ne, j as se, k as oe } from "./useVehicleEvents-t_p-Bwhj.js";
|
|
5
5
|
export {
|
|
6
6
|
R as VehicleEventContext,
|
|
7
7
|
I as VehicleEventEmitter,
|
package/package.json
CHANGED