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 CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function p(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),I=p(f,l),v=V(r,I),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=p(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 p(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+=p(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+=p(n,r),n=r}return s}function S(e,t,s,n,o){const c=p(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 return Math.max(o,Math.min(t,c));return o+i*r}function T(e,t,s,n,o){const r=p(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,p(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}),I=j(g),v={curveIndex:r,fromLineId:i.fromLineId,toLineId:i.toLineId,fromOffset:f,toOffset:u,curveLength:I};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,I=(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=I(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=I(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],I=g.type==="line"?O(o.get(g.lineId),g.startOffset+f):M(c.get(g.curveIndex),f);return{axleState:{...e,...I},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=p;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;
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 d = M(e.start, e.end), a = n ? {
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 - d.x * c,
21
- y: r.y - d.y * c
22
- } : r, u = M(e.start, e.end), g = M(t.start, t.end), p = v(a, l), I = F(i, p), f = n ? { x: a.x - u.x * I, y: a.y - u.y * I } : { x: a.x + u.x * I, y: a.y + u.y * I }, m = {
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, d = t * t, a = d * t;
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 * d * s.x + a * c.x,
43
- y: l * o.y + 3 * r * t * n.y + 3 * i * d * s.y + a * c.y
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 d = (t - c) / (i - c);
70
- return r + d * (l - 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
- return Math.max(s, Math.min(t, c));
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), d = s.get(r.toLineId);
115
- if (!l || !d) continue;
116
- const a = b(l, r.fromOffset, r.fromIsPercentage, 1, o.wheelbase), u = A(d, r.toOffset, r.toIsPercentage, 0, o.wheelbase), g = T(
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
- d,
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: u,
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: u,
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 d = r.get(o), a = s ? n / 100 * d : n, u = [], g = /* @__PURE__ */ new Map(), p = (f, m) => `${f}:${Math.round(m)}`;
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
- u.push({
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 (u.sort((f, m) => f.totalDistance - m.totalDistance); u.length > 0; ) {
183
- const f = u.shift(), m = p(f.lineId, f.entryOffset), y = g.get(m);
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
- u.push({
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
- u.sort((h, x) => h.totalDistance - x.totalDistance);
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, u = t.currentSegmentIndex + 1;
328
- if (u >= o.segments.length) {
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[u], p = g.type === "line" ? O(
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: u,
371
+ currentSegmentIndex: d,
370
372
  segmentDistance: a
371
373
  },
372
374
  completed: !1
373
375
  };
374
376
  }
375
- const d = r.type === "line" ? O(
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, ...d },
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 d = b(
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
- ), u = T(
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: d,
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(u);
424
- s.set(c.curveIndex, { bezier: u, arcLengthTable: g });
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 d = N(r) - i.wheelbase;
434
- if (d <= 0) return null;
435
- const a = t.isPercentage ? t.targetOffset * d : Math.min(t.targetOffset, d), u = G(
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 (!u) return null;
443
- const g = H(u, c, s, i);
444
- return { path: u, curveDataMap: g };
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 d = {
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
- d
479
+ u
478
480
  );
479
481
  if (a) {
480
- const u = W(
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: u ? {
505
- currentSegmentIndex: u.segmentIndex,
506
- segmentDistance: u.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-D69WkcSs.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;
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-BOJPYrlM.js";
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-BXX3GPzk.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-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-82D2V4MI.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;
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-BXX3GPzk.js";
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(t, e) {
11
- return this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(e), () => {
12
- this.listeners.get(t)?.delete(e);
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(t, e) {
21
- this.listeners.get(t)?.forEach((s) => {
20
+ emit(e, t) {
21
+ this.listeners.get(e)?.forEach((s) => {
22
22
  try {
23
- s(e);
23
+ s(t);
24
24
  } catch (o) {
25
- console.error(`Error in event listener for "${t}":`, o);
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(t) {
34
- t ? this.listeners.delete(t) : this.listeners.clear();
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(t) {
42
- return this.listeners.get(t)?.size ?? 0;
41
+ listenerCount(e) {
42
+ return this.listeners.get(e)?.size ?? 0;
43
43
  }
44
44
  }
45
45
  function P(i) {
46
- const t = [], e = [], s = [], o = i.trim().split(`
46
+ const e = [], t = [], s = [], o = i.trim().split(`
47
47
  `);
48
- let h = 0;
48
+ let d = 0;
49
49
  for (const n of o) {
50
- h++;
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
- t.push({
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 = (c[3] === "%", f / 100);
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 = (c[6] === "%", f / 100);
73
+ const f = parseFloat(c[5]), h = c[6] === "%";
74
+ l.toPosition = h ? f / 100 : f, l.toIsPercentage = h;
75
75
  }
76
- e.push(l);
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 ${h}: Unable to parse "${r}"`);
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: t,
84
- connections: e.length > 0 ? e : void 0
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 t = [], e = [], s = i.trim().split(`
90
+ const e = [], t = [], s = i.trim().split(`
91
91
  `);
92
92
  let o = 0;
93
- for (const h of s) {
93
+ for (const d of s) {
94
94
  o++;
95
- const n = h.trim();
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
- t.push({
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/) && e.push(`Line ${o}: Invalid vehicle start format "${n}"`);
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: t,
113
- errors: e
112
+ data: e,
113
+ errors: t
114
114
  };
115
115
  }
116
116
  function w(i) {
117
- const t = [], e = [], s = i.trim().split(`
117
+ const e = [], t = [], s = i.trim().split(`
118
118
  `);
119
119
  let o = 0;
120
- for (const h of s) {
120
+ for (const d of s) {
121
121
  o++;
122
- const n = h.trim();
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
- e.push(`Line ${o}: Invalid JSON payload "${f[1]}"`);
133
+ t.push(`Line ${o}: Invalid JSON payload "${f[1]}"`);
134
134
  }
135
- const d = parseFloat(r[3]), u = r[4] === "%";
136
- t.push({
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 ? d / 100 : d,
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/) && e.push(`Line ${o}: Invalid goto command format "${n}"`);
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: t,
152
- errors: e
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 t = [];
167
- for (const e of i.lines) {
168
- const s = m(e.start), o = m(e.end);
169
- t.push(`${e.id} : (${Math.round(s.x)}, ${Math.round(s.y)}) -> (${Math.round(o.x)}, ${Math.round(o.y)})`);
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 && t.push(""), i.connections)
172
- for (const e of i.connections) {
173
- let s = e.from;
174
- e.fromPosition !== void 0 && (e.fromIsPercentage !== !1 ? s += ` ${e.fromPosition * 100}%` : s += ` ${e.fromPosition}`), s += " -> ", s += e.to, e.toPosition !== void 0 && (e.toIsPercentage !== !1 ? s += ` ${e.toPosition * 100}%` : s += ` ${e.toPosition}`), t.push(s);
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 t.join(`
176
+ return e.join(`
177
177
  `);
178
178
  }
179
179
  function x(i) {
180
- return i.map((t) => {
181
- const e = t.position ?? 0;
182
- return t.isPercentage !== !1 ? `${t.id} start ${t.lineId} ${e * 100}%` : `${t.id} start ${t.lineId} ${e}`;
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((t) => {
188
- const e = t.targetPosition ?? 1, s = t.isPercentage !== !1;
189
- let o = t.vehicleId;
190
- return o += ` goto ${t.targetLineId}`, s ? o += ` ${e * 100}%` : o += ` ${e}`, t.wait && (o += " --wait"), t.payload !== void 0 && (o += ` --payload ${JSON.stringify(t.payload)}`), o;
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, t, e = 0) {
195
- const s = [], o = [], h = /* @__PURE__ */ new Set();
194
+ function N(i, e, t = 0) {
195
+ const s = [], o = [], d = /* @__PURE__ */ new Set();
196
196
  for (const n of i) {
197
- if (h.has(n.vehicleId)) {
197
+ if (d.has(n.vehicleId)) {
198
198
  o.push(`Duplicate vehicle ID: ${n.vehicleId}`);
199
199
  continue;
200
200
  }
201
- h.add(n.vehicleId);
202
- const r = t.find((p) => p.id === n.lineId);
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 - e);
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), d = {
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
- e,
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: d,
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 t = i.map((s) => {
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${(t.length > 0 ? Math.max(...t) : 0) + 1}`;
249
+ return `v${(e.length > 0 ? Math.max(...e) : 0) + 1}`;
250
250
  }
251
- function F(i, t) {
252
- if (t.length === 0) return null;
251
+ function F(i, e) {
252
+ if (e.length === 0) return null;
253
253
  if (i.length === 0)
254
- return t[0].id;
255
- const e = /* @__PURE__ */ new Map();
256
- for (const s of t)
257
- e.set(s.id, 0);
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 = e.get(s.vehicleId) || 0;
260
- e.set(s.vehicleId, o + 1);
259
+ const o = t.get(s.vehicleId) || 0;
260
+ t.set(s.vehicleId, o + 1);
261
261
  }
262
- return t[0].id;
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 P{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 h=0;for(const n of o){h++;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]);l.fromPosition=(c[3]==="%",f/100)}if(c[5]){const f=parseFloat(c[5]);l.toPosition=(c[6]==="%",f/100)}t.push(l);continue}r.match(/^\w+\s+start\s+/)||r.match(/^\w+\s+goto\s+/)||s.push(`Line ${h}: Unable to parse "${r}"`)}return{data:{lines:e,connections:t.length>0?t:void 0},errors:s}}function $(i){const e=[],t=[],s=i.trim().split(`
3
- `);let o=0;for(const h of s){o++;const n=h.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(i){const e=[],t=[],s=i.trim().split(`
4
- `);let o=0;for(const h of s){o++;const n=h.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 d=parseFloat(r[3]),u=r[4]==="%";e.push({vehicleId:r[1],targetLineId:r[2],targetPosition:u?d/100:d,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),movements:I(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(`
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=[],h=new Set;for(const n of i){if(h.has(n.vehicleId)){o.push(`Duplicate vehicle ID: ${n.vehicleId}`);continue}h.add(n.vehicleId);const r=e.find(v=>v.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),d={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:d,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=P;exports.generateMovementDSL=M;exports.generateSceneDSL=w;exports.generateVehiclesDSL=S;exports.getNextGotoVehicleId=D;exports.getNextStartVehicleId=y;exports.parseAllDSL=L;exports.parseMovementDSL=I;exports.parseSceneDSL=g;exports.parseVehiclesDSL=$;exports.validateAndCreateVehicles=V;
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;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),i=require("./vehicle-helpers-82D2V4MI.cjs"),n=require("./animation-loop-fC2LjxCd.cjs"),t=require("./useVehicleEvents-D69WkcSs.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;
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;
@@ -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-BXX3GPzk.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-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-BOJPYrlM.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-t_p-Bwhj.js";
5
5
  export {
6
6
  R as VehicleEventContext,
7
7
  I as VehicleEventEmitter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vehicle-path2",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Vehicle motion simulator library for dual-axle vehicle movement along paths composed of lines and Bezier curves",
5
5
  "type": "module",
6
6
  "main": "./dist/vehicle-path.cjs",