vehicle-path2 1.0.7 → 1.0.9

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/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-CCCiLoAw.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-DcNmJGRn.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.7",
3
+ "version": "1.0.9",
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",
@@ -1,3 +0,0 @@
1
- "use strict";const o=require("react"),R=require("./core.cjs"),A=require("./vehicle-helpers-82D2V4MI.cjs"),te=require("react/jsx-runtime");function G(s){return Array.isArray(s)?{x:s[0],y:s[1]}:s}function K(s){return{id:s.id,start:G(s.start),end:G(s.end)}}function U(s){const i=s.fromIsPercentage!==!1,x=s.toIsPercentage!==!1;return{fromLineId:s.from,toLineId:s.to,fromOffset:s.fromPosition,fromIsPercentage:s.fromPosition!==void 0?i:void 0,toOffset:s.toPosition,toIsPercentage:s.toPosition!==void 0?x:void 0}}function H(s){const i=s.position??0,x=s.isPercentage!==!1;return{vehicleId:s.id,lineId:s.lineId,offset:i,isPercentage:x}}function J(s){const i=s.isPercentage!==!1,x=s.targetPosition??1;return{vehicleId:s.vehicleId,targetLineId:s.targetLineId,targetOffset:x,isPercentage:i,awaitConfirmation:s.wait,payload:s.payload}}function se(s){const i=[],x=new Set;for(const r of s.lines)x.has(r.id)&&i.push(`Duplicate line ID: ${r.id}`),x.add(r.id);if(s.connections)for(const r of s.connections){x.has(r.from)||i.push(`Connection references non-existent line: ${r.from}`),x.has(r.to)||i.push(`Connection references non-existent line: ${r.to}`);const m=r.fromIsPercentage!==!1,t=r.toIsPercentage!==!1;!m&&r.fromPosition===void 0&&i.push("fromPosition is required when fromIsPercentage is false"),!t&&r.toPosition===void 0&&i.push("toPosition is required when toIsPercentage is false"),r.fromPosition!==void 0&&(m&&(r.fromPosition<0||r.fromPosition>1)?i.push(`Invalid fromPosition: ${r.fromPosition} (must be 0-1 for percentage)`):!m&&r.fromPosition<0&&i.push(`Invalid fromPosition: ${r.fromPosition} (must be >= 0 for absolute distance)`)),r.toPosition!==void 0&&(t&&(r.toPosition<0||r.toPosition>1)?i.push(`Invalid toPosition: ${r.toPosition} (must be 0-1 for percentage)`):!t&&r.toPosition<0&&i.push(`Invalid toPosition: ${r.toPosition} (must be >= 0 for absolute distance)`))}return{valid:i.length===0,errors:i}}function B(){const[s,i]=o.useState([]),[x,r]=o.useState([]),[m,t]=o.useState(null),f=o.useCallback((n,h)=>{i(n),r(h),t(null)},[]),C=o.useCallback(n=>{const h=se(n);if(!h.valid)return t(h.errors.join("; ")),{success:!1,errors:h.errors};const l=n.lines.map(K),g=n.connections?.map(U)||[];return f(l,g),{success:!0}},[f]),D=o.useCallback(n=>{if(s.some(l=>l.id===n.id)){const l=`Line with ID '${n.id}' already exists`;return t(l),{success:!1,error:l}}return i(l=>[...l,K(n)]),t(null),{success:!0}},[s]),q=o.useCallback((n,h)=>{if(s.findIndex(g=>g.id===n)===-1){const g=`Line with ID '${n}' not found`;return t(g),{success:!1,error:g}}return i(g=>g.map(S=>S.id!==n?S:{...S,start:h.start?G(h.start):S.start,end:h.end?G(h.end):S.end})),t(null),{success:!0}},[s]),w=o.useCallback(n=>{if(!s.some(l=>l.id===n)){const l=`Line with ID '${n}' not found`;return t(l),{success:!1,error:l}}return i(l=>l.filter(g=>g.id!==n)),r(l=>l.filter(g=>g.fromLineId!==n&&g.toLineId!==n)),t(null),{success:!0}},[s]),V=o.useCallback(n=>{const h=s.some(d=>d.id===n.from),l=s.some(d=>d.id===n.to);if(!h){const d=`Line '${n.from}' not found`;return t(d),{success:!1,error:d}}if(!l){const d=`Line '${n.to}' not found`;return t(d),{success:!1,error:d}}const g=n.fromIsPercentage!==!1,S=n.toIsPercentage!==!1;if(!g&&n.fromPosition===void 0){const d="fromPosition is required when fromIsPercentage is false";return t(d),{success:!1,error:d}}if(!S&&n.toPosition===void 0){const d="toPosition is required when toIsPercentage is false";return t(d),{success:!1,error:d}}if(x.some(d=>d.fromLineId===n.from&&d.toLineId===n.to)){const d=`Connection from '${n.from}' to '${n.to}' already exists`;return t(d),{success:!1,error:d}}return r(d=>[...d,U(n)]),t(null),{success:!0}},[s,x]),p=o.useCallback((n,h,l)=>{const g=x.findIndex(e=>e.fromLineId===n&&e.toLineId===h);if(g===-1){const e=`Connection from '${n}' to '${h}' not found`;return t(e),{success:!1,error:e}}const S=x[g],Q=l.fromIsPercentage??S.fromIsPercentage,d=l.toIsPercentage??S.toIsPercentage;let $;l.fromOffset!==void 0?$=l.fromOffset:S.fromOffset!==void 0&&($=S.fromOffset);let b;if(l.toOffset!==void 0?b=l.toOffset:S.toOffset!==void 0&&(b=S.toOffset),$!==void 0){if(Q!==!1&&($<0||$>1)){const e=`Invalid fromOffset: ${$} (must be 0-1 for percentage)`;return t(e),{success:!1,error:e}}if(Q===!1&&$<0){const e=`Invalid fromOffset: ${$} (must be >= 0 for absolute distance)`;return t(e),{success:!1,error:e}}}if(b!==void 0){if(d!==!1&&(b<0||b>1)){const e=`Invalid toOffset: ${b} (must be 0-1 for percentage)`;return t(e),{success:!1,error:e}}if(d===!1&&b<0){const e=`Invalid toOffset: ${b} (must be >= 0 for absolute distance)`;return t(e),{success:!1,error:e}}}if(Q===!1&&$===void 0){const e="fromOffset is required when fromIsPercentage is false";return t(e),{success:!1,error:e}}if(d===!1&&b===void 0){const e="toOffset is required when toIsPercentage is false";return t(e),{success:!1,error:e}}const j={from:n,to:h,fromPosition:$,fromIsPercentage:Q,toPosition:b,toIsPercentage:d};return r(e=>e.map((c,u)=>u===g?U(j):c)),t(null),{success:!0}},[x]),P=o.useCallback((n,h)=>{if(!x.some(g=>g.fromLineId===n&&g.toLineId===h)){const g=`Connection from '${n}' to '${h}' not found`;return t(g),{success:!1,error:g}}return r(g=>g.filter(S=>!(S.fromLineId===n&&S.toLineId===h))),t(null),{success:!0}},[x]),a=o.useCallback(()=>{i([]),r([]),t(null)},[]);return{lines:s,curves:x,setScene:C,addLine:D,updateLine:q,removeLine:w,addConnection:V,updateConnection:p,removeConnection:P,clear:a,error:m,_loadScene:f}}function W({lines:s,wheelbase:i}){const[x,r]=o.useState([]),[m,t]=o.useState(null),f=o.useRef([]),C=o.useCallback(p=>{f.current=p,r(p),t(null)},[]),D=o.useCallback(p=>{const P=Array.isArray(p)?p:[p],a=[];for(const g of P)f.current.some(Q=>Q.id===g.id)&&a.push(`Vehicle with ID '${g.id}' already exists`);if(a.length>0)return t(a.join("; ")),{success:!1,errors:a};const n=P.map(H),{vehicles:h,errors:l}=A.validateAndCreateVehicles(n,s,i);return l.length>0?(t(l.join("; ")),{success:!1,errors:l}):(f.current=[...f.current,...h],r(f.current),t(null),{success:!0})},[s,i]),q=o.useCallback((p,P)=>{const a=f.current.findIndex(b=>b.id===p);if(a===-1){const b=`Vehicle with ID '${p}' not found`;return t(b),{success:!1,error:b}}const n=f.current[a];if(n.state!=="idle"){const b=`Cannot update vehicle '${p}' while it is ${n.state}. Vehicle must be idle.`;return t(b),{success:!1,error:b}}const h=P.lineId??n.lineId;if(!s.find(b=>b.id===h)){const b=`Line '${h}' not found`;return t(b),{success:!1,error:b}}let g,S;P.lineId!==void 0&&P.position===void 0?(g=0,S=!0):P.position!==void 0?(g=P.position,S=P.isPercentage??!0):(g=n.offset,S=n.isPercentage);const Q={vehicleId:p,lineId:h,offset:g,isPercentage:S},{vehicles:d,errors:$}=A.validateAndCreateVehicles([Q],s,i);return $.length>0?(t($.join("; ")),{success:!1,error:$.join("; ")}):(f.current=f.current.map((b,j)=>j===a?d[0]:b),r(f.current),t(null),{success:!0})},[s,i]),w=o.useCallback(p=>{if(!f.current.some(a=>a.id===p)){const a=`Vehicle with ID '${p}' not found`;return t(a),{success:!1,error:a}}return f.current=f.current.filter(a=>a.id!==p),r(f.current),t(null),{success:!0}},[]),V=o.useCallback(()=>{f.current=[],r([]),t(null)},[]);return{vehicles:x,addVehicles:D,updateVehicle:q,removeVehicle:w,clear:V,error:m,_loadVehicles:C}}function X({vehicles:s,lines:i}){const[x,r]=o.useState(new Map),[m,t]=o.useState(null),f=o.useRef(new Map),C=o.useCallback(()=>f.current,[]),D=o.useCallback(V=>{f.current=V,r(V),t(null)},[]),q=o.useCallback((V,p)=>{if(!s.some(d=>d.id===V)){const d=`Vehicle '${V}' not found`;return t(d),{success:!1,error:d}}const a=i.find(d=>d.id===p.targetLineId);if(!a){const d=`Line '${p.targetLineId}' not found`;return t(d),{success:!1,error:d}}const n=p.isPercentage!==!1,h=R.distance(a.start,a.end);if(!n&&p.targetPosition===void 0){const d="targetPosition is required when isPercentage is false";return t(d),{success:!1,error:d}}const l=p.targetPosition??1;if(n){if(l<0||l>1){const d=`Invalid targetPosition: ${l} (must be 0-1 for percentage)`;return t(d),{success:!1,error:d}}}else{if(l<0){const d=`Invalid targetPosition: ${l} (must be >= 0 for absolute distance)`;return t(d),{success:!1,error:d}}if(l>h){const d=`Position ${l} exceeds line length ${h}`;return t(d),{success:!1,error:d}}}const g=J({vehicleId:V,...p}),S=new Map(f.current),Q=S.get(V)||[];return S.set(V,[...Q,g]),f.current=S,r(S),t(null),{success:!0}},[s,i]),w=o.useCallback(V=>{if(V!==void 0){if(!s.some(a=>a.id===V)){const a=`Vehicle '${V}' not found`;return t(a),{success:!1,error:a}}const P=new Map(f.current);P.delete(V),f.current=P,r(P)}else f.current=new Map,r(new Map);return t(null),{success:!0}},[s]);return{vehicleQueues:x,getVehicleQueues:C,queueMovement:q,clearQueue:w,error:m,_loadQueues:D}}function Z({vehicles:s,lines:i,vehicleQueues:x,getVehicleQueues:r,wheelbase:m,tangentMode:t,curves:f,eventEmitter:C}){const[D,q]=o.useState([]),w=o.useRef([]),V=o.useCallback(e=>{typeof e=="function"?q(c=>{const u=e(c);return w.current=u,u}):(w.current=e,q(e))},[]),p=o.useCallback(()=>w.current,[]),P=o.useMemo(()=>({wheelbase:m,tangentMode:t}),[m,t]),a=o.useMemo(()=>new Map(i.map(e=>[e.id,e])),[i]),n=o.useRef(new Map);o.useEffect(()=>{const{movingVehicles:e,stateMap:c}=R.initializeAllVehicles(s,a);n.current=c;const u=setTimeout(()=>{V(e)},0);return()=>clearTimeout(u)},[s,a]);const h=o.useRef(null);o.useEffect(()=>{i.length>0&&(h.current=R.buildGraph(i,f,P))},[i,f,P]);const l=o.useRef(0),g=o.useRef(!1),S=o.useCallback(e=>{if(!g.current)return!1;let c=!1;for(const[,M]of n.current)if(M.vehicle.state==="moving"){c=!0;break}if(!c)return!1;const u=[];for(const[M,I]of n.current){if(I.vehicle.state!=="moving"||!I.execution)continue;const v=I.execution;let E;if(v.front.currentSegmentIndex<v.path.segments.length){const k=v.path.segments[v.front.currentSegmentIndex];if(k.type==="line"){const L=a.get(k.lineId);L&&(E=Math.sqrt(Math.pow(L.end.x-L.start.x,2)+Math.pow(L.end.y-L.start.y,2)))}}const T=R.updateAxlePosition(I.vehicle.rear,v.rear,v.path,e,a,v.curveDataMap),y=R.updateAxlePosition(I.vehicle.front,v.front,v.path,e,a,v.curveDataMap,E);if(I.vehicle={...I.vehicle,rear:T.axleState,front:y.axleState},I.execution.rear=T.execution,I.execution.front=y.execution,T.completed){const k={linesMap:a,config:P,vehicleQueues:x,curves:f,graphRef:h,prepareCommandPath:R.prepareCommandPath,onCommandComplete:F=>u.push({type:"commandComplete",data:F}),onCommandStart:F=>u.push({type:"commandStart",data:F})},L=R.handleArrival(I,k);I.vehicle=L.vehicle,L.newExecution!==void 0&&(I.execution=L.newExecution),L.vehicle.state!=="moving"&&u.push({type:"stateChange",data:{vehicleId:M,from:"moving",to:L.vehicle.state}});const O=L.vehicle.rear.position,_=L.vehicle.front.position;u.push({type:"positionUpdate",data:{vehicleId:M,rear:O,front:_,center:{x:(O.x+_.x)/2,y:(O.y+_.y)/2},angle:Math.atan2(_.y-O.y,_.x-O.x)}})}}if(V(M=>M.map(I=>{const v=n.current.get(I.id);return v?v.vehicle:I})),C&&u.length>0){const M=l.current;setTimeout(()=>{l.current===M&&u.forEach(({type:I,data:v})=>{C.emit(I,v)})},0)}for(const[,M]of n.current)if(M.vehicle.state==="moving")return!0;return g.current=!1,!1},[a,f,P,x,C]),Q=o.useCallback(()=>{const e=h.current;if(!e)return!1;const c=r?r():x,u=[];let M=!1;for(const[I,v]of n.current){const E=v.vehicle;if(E.state==="moving")continue;const T=c.get(I);if(!T||T.length===0)continue;const y=T[0],k={graph:e,linesMap:a,curves:f,config:P},L=R.prepareCommandPath(E,y,k);if(!L){console.warn(`No path found for vehicle ${I}`);continue}const O=R.calculateFrontAxlePosition(L.path,0,0,m);n.current.set(I,{...v,execution:{path:L.path,curveDataMap:L.curveDataMap,currentCommandIndex:0,rear:{currentSegmentIndex:0,segmentDistance:0},front:O?{currentSegmentIndex:O.segmentIndex,segmentDistance:O.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},vehicle:{...E,state:"moving"}}),M=!0,u.push({id:I,fromState:E.state,command:y,startPosition:{lineId:E.rear.lineId,absoluteOffset:E.rear.absoluteOffset,position:E.rear.position}})}if(!M)return!1;if(g.current=!0,V(I=>I.map(v=>{const E=n.current.get(v.id);return E?E.vehicle:v})),C&&u.length>0){const I=l.current;setTimeout(()=>{l.current===I&&u.forEach(({id:v,fromState:E,command:T,startPosition:y})=>{C.emit("commandStart",{vehicleId:v,command:T,commandIndex:0,startPosition:y}),C.emit("stateChange",{vehicleId:v,from:E,to:"moving"})})},0)}return!0},[a,f,x,r,P,m,C]),d=o.useCallback(()=>{l.current++,g.current=!1;const{movingVehicles:e,stateMap:c}=R.initializeAllVehicles(s,a);n.current=c,V(e)},[s,a]),$=o.useCallback(e=>{const c=s.find(v=>v.id===e);if(!c||!a.get(c.lineId))return;const M=R.initializeMovingVehicle(c),I=R.createInitialMovementState(M);n.current.set(e,I),V(v=>v.map(E=>E.id===e?M:E))},[s,a]),b=o.useCallback(e=>{const c=n.current.get(e);if(!c||c.vehicle.state!=="waiting")return!1;const u=x.get(e),M=c.execution;if(!M)return!1;const I=M.currentCommandIndex+1;if(u&&I<u.length){const v=h.current;if(v){const E=u[I],T={graph:v,linesMap:a,curves:f,config:P},y=R.prepareCommandPath(c.vehicle,E,T);if(y){const k=R.calculateFrontAxlePosition(y.path,0,0,m);if(c.execution={path:y.path,curveDataMap:y.curveDataMap,currentCommandIndex:I,rear:{currentSegmentIndex:0,segmentDistance:0},front:k?{currentSegmentIndex:k.segmentIndex,segmentDistance:k.segmentDistance}:{currentSegmentIndex:0,segmentDistance:0}},c.vehicle={...c.vehicle,state:"moving"},V(L=>L.map(O=>O.id===e?c.vehicle:O)),C){const L=l.current;setTimeout(()=>{l.current===L&&C.emit("stateChange",{vehicleId:e,from:"waiting",to:"moving"})},0)}return!0}}}if(c.vehicle={...c.vehicle,state:"idle"},c.execution=null,V(v=>v.map(E=>E.id===e?c.vehicle:E)),C){const v=l.current;setTimeout(()=>{l.current===v&&C.emit("stateChange",{vehicleId:e,from:"waiting",to:"idle"})},0)}return!0},[x,a,f,P,m,C]),j=o.useCallback(()=>{for(const[,e]of n.current)if(e.vehicle.state==="moving")return!0;return!1},[]);return{movingVehicles:D,getMovingVehicles:p,prepare:Q,tick:S,reset:d,resetVehicle:$,continueVehicle:b,isMoving:j,isPrepared:g.current}}function re({wheelbase:s,tangentMode:i="proportional-40",eventEmitter:x}){const r=B(),m=W({lines:r.lines,wheelbase:s}),t=X({vehicles:m.vehicles,lines:r.lines,curves:r.curves}),f=Z({vehicles:m.vehicles,lines:r.lines,vehicleQueues:t.vehicleQueues,getVehicleQueues:t.getVehicleQueues,wheelbase:s,tangentMode:i,curves:r.curves,eventEmitter:x}),C=o.useCallback(e=>m.vehicles.filter(c=>c.lineId===e||c.rear.lineId===e),[m.vehicles]),D=o.useCallback(e=>C(e).length>0,[C]),q=o.useCallback(e=>{const c=r.addLine(e);return c.success?{success:!0}:{success:!1,error:c.error}},[r]),w=o.useCallback((e,c)=>{const u=r.updateLine(e,c);return u.success?{success:!0}:{success:!1,error:u.error}},[r]),V=o.useCallback(e=>{const c=[],u=C(e);u.length>0&&(c.push({type:"vehicle_on_removed_line",message:`${u.length} vehicle(s) are on line '${e}'`,details:{lineId:e,vehicleIds:u.map(v=>v.id)}}),u.forEach(v=>{m.removeVehicle(v.id),t.clearQueue(v.id)}));const M=r.curves.filter(v=>v.fromLineId===e||v.toLineId===e);M.length>0&&c.push({type:"orphaned_connection",message:`${M.length} connection(s) will be removed`,details:{lineId:e,connectionCount:M.length}});const I=r.removeLine(e);return I.success?{success:!0,warnings:c.length>0?c:void 0}:{success:!1,error:I.error}},[r,C,m,t]),p=o.useCallback(()=>{r.clear(),m.clear(),t.clearQueue()},[r,m,t]),P=o.useCallback((e,c,u)=>{const M=r.addConnection({from:e,to:c,fromPosition:u?.fromOffset,fromIsPercentage:u?.fromIsPercentage,toPosition:u?.toOffset,toIsPercentage:u?.toIsPercentage});return M.success?{success:!0}:{success:!1,error:M.error}},[r]),a=o.useCallback((e,c,u)=>{const M=r.updateConnection(e,c,u);return M.success?{success:!0}:{success:!1,error:M.error}},[r]),n=o.useCallback((e,c)=>{const u=r.removeConnection(e,c);return u.success?{success:!0}:{success:!1,error:u.error}},[r]),h=o.useCallback(e=>{const c=m.addVehicles(e);return c.success?{success:!0}:{success:!1,error:c.errors?.join("; ")}},[m]),l=o.useCallback((e,c)=>{const u=m.updateVehicle(e,c);return u.success?{success:!0}:{success:!1,error:u.error}},[m]),g=o.useCallback(e=>{const c=[],u=t.vehicleQueues.get(e);u&&u.length>0&&(c.push({type:"movement_queue_cleared",message:`${u.length} queued movement(s) will be cleared for vehicle '${e}'`,details:{vehicleId:e}}),t.clearQueue(e));const M=m.removeVehicle(e);return M.success?{success:!0,warnings:c.length>0?c:void 0}:{success:!1,error:M.error}},[m,t]),S=o.useCallback(()=>{m.clear(),t.clearQueue()},[m,t]),Q=o.useCallback(e=>{const c={targetLineId:e.lineId,targetPosition:e.position??1,isPercentage:e.isPercentage,wait:e.wait,payload:e.payload},u=t.queueMovement(e.id,c);return u.success?{success:!0}:{success:!1,error:u.error}},[t]),d=o.useCallback(e=>{const c=t.clearQueue(e);return c.success?{success:!0}:{success:!1,error:c.error}},[t]),$=o.useCallback(e=>{const c=[],u=[],{scene:M,vehicles:I,movements:v}=A.parseAllDSL(e);M.errors.length>0&&u.push(...M.errors),I.errors.length>0&&u.push(...I.errors),v.errors.length>0&&u.push(...v.errors);const E=M.data.lines.map(K),T=(M.data.connections||[]).map(U),y=I.data.map(H),{vehicles:k,errors:L}=A.validateAndCreateVehicles(y,E,s);L.length>0&&u.push(...L);const O=new Map;for(const _ of v.data){const F=O.get(_.vehicleId)||[];F.push(J(_)),O.set(_.vehicleId,F)}return r._loadScene(E,T),m._loadVehicles(k),t._loadQueues(O),u.length>0&&c.push({type:"dsl_parse_error",message:`DSL loading had ${u.length} error(s)`,details:{errors:u}}),{success:!0,warnings:c.length>0?c:void 0}},[r,m,t,s]),b=o.useCallback(e=>{const c=[],u=[],M=e.lines.map(K),I=(e.connections||[]).map(U),v=(e.vehicles||[]).map(H),{vehicles:E,errors:T}=A.validateAndCreateVehicles(v,M,s);T.length>0&&u.push(...T);const y=new Map;for(const k of e.movements||[]){const L=y.get(k.vehicleId)||[];L.push(J({vehicleId:k.vehicleId,targetLineId:k.targetLineId,targetPosition:k.targetPosition,isPercentage:k.isPercentage,wait:k.wait,payload:k.payload})),y.set(k.vehicleId,L)}return r._loadScene(M,I),m._loadVehicles(E),t._loadQueues(y),u.length>0&&c.push({type:"dsl_parse_error",message:`JSON loading had ${u.length} error(s)`,details:{errors:u}}),{success:!0,warnings:c.length>0?c:void 0}},[r,m,t,s]),j=o.useMemo(()=>r.error||m.error||t.error,[r.error,m.error,t.error]);return{lines:r.lines,curves:r.curves,vehicles:m.vehicles,movingVehicles:f.movingVehicles,getMovingVehicles:f.getMovingVehicles,vehicleQueues:t.vehicleQueues,error:j,addLine:q,updateLine:w,removeLine:V,clearScene:p,connect:P,updateConnection:a,disconnect:n,addVehicles:h,updateVehicle:l,removeVehicle:g,clearVehicles:S,goto:Q,clearQueue:d,prepare:f.prepare,tick:f.tick,reset:f.reset,resetVehicle:f.resetVehicle,continueVehicle:f.continueVehicle,isMoving:f.isMoving,loadFromDSL:$,loadFromJSON:b,getVehiclesOnLine:C,hasVehiclesOnLine:D}}function z(s){return s.map(i=>({id:i.id,start:i.start,end:i.end}))}function N(s){return s.map(i=>({from:i.fromLineId,to:i.toLineId,fromPosition:i.fromOffset,fromIsPercentage:i.fromIsPercentage,toPosition:i.toOffset,toIsPercentage:i.toIsPercentage}))}function ne(){const[s,i]=o.useState(""),[x,r]=o.useState(null),{lines:m,curves:t,setScene:f}=B(),C=o.useRef(!1),D=o.useRef("");o.useEffect(()=>{D.current=s},[s]),o.useEffect(()=>{if(C.current)return;const p={lines:z(m),connections:t.length>0?N(t):void 0},P=A.generateSceneDSL(p);P!==D.current&&(C.current=!0,i(P),setTimeout(()=>{C.current=!1},50))},[m,t]);const q=o.useCallback(p=>{C.current=!0,i(p);try{const{data:P,errors:a}=A.parseSceneDSL(p);a.length>0&&r(a.join("; "));const n=f(P);!n.success&&n.errors?r(h=>h?`${h}; ${n.errors.join("; ")}`:n.errors.join("; ")):a.length===0&&r(null)}catch(P){r(P instanceof Error?P.message:"Invalid scene definition")}setTimeout(()=>{C.current=!1},50)},[f]),w=o.useCallback(p=>{const P=typeof p=="function"?p(m):p,a=N(t);f({lines:z(P),connections:a.length>0?a:void 0});const n={lines:z(P),connections:a.length>0?a:void 0},h=A.generateSceneDSL(n);C.current=!0,i(h),setTimeout(()=>{C.current=!1},50)},[m,t,f]),V=o.useCallback(p=>{const P=typeof p=="function"?p(t):p,a=N(P);f({lines:z(m),connections:a.length>0?a:void 0});const n={lines:z(m),connections:a.length>0?a:void 0},h=A.generateSceneDSL(n);C.current=!0,i(h),setTimeout(()=>{C.current=!1},50)},[m,t,f]);return{lines:m,curves:t,sceneDefinitionText:s,sceneError:x,isDebouncing:!1,debounceKey:0,setLines:w,setCurves:V,setSceneDefinitionText:q}}function oe({lines:s,wheelbase:i}){const[x,r]=o.useState(""),[m,t]=o.useState(null),{vehicles:f,addVehicles:C,clear:D,error:q}=W({lines:s,wheelbase:i}),w=o.useRef(!1),V=o.useCallback(p=>{w.current=!0,r(p);try{const{data:P,errors:a}=A.parseVehiclesDSL(p),n=[...a];D();for(const h of P){const l=C(h);!l.success&&l.errors&&n.push(...l.errors)}n.length>0?t(n.join(`
2
- `)):t(null)}catch(P){t(P instanceof Error?P.message:"Invalid initial movement")}setTimeout(()=>{w.current=!1},50)},[C,D]);return{vehicles:f,initialMovementText:x,movementError:m||q,isDebouncing:!1,debounceKey:0,setInitialMovementText:V}}function ce({lines:s,vehicles:i}){const[x,r]=o.useState(""),[m,t]=o.useState([]),[f,C]=o.useState(null),{vehicleQueues:D,queueMovement:q,clearQueue:w,error:V}=X({vehicles:i,lines:s}),p=o.useRef(!1),P=o.useCallback(a=>{p.current=!0,r(a);try{const{data:n,errors:h}=A.parseMovementDSL(a),l=[...h];w();for(const g of n){const S=q(g.vehicleId,{targetLineId:g.targetLineId,targetPosition:g.targetPosition,isPercentage:g.isPercentage,wait:g.wait,payload:g.payload});!S.success&&S.error&&l.push(S.error)}t(n),l.length>0?C(l.join(`
3
- `)):C(null)}catch(n){C(n instanceof Error?n.message:"Invalid movement sequence"),t([])}setTimeout(()=>{p.current=!1},50)},[q,w]);return{movementSequenceText:x,gotoCommands:m,vehicleQueues:D,sequenceError:f||V,isDebouncing:!1,debounceKey:0,setMovementSequenceText:P}}const Y=o.createContext(null);function ee(){const s=o.useContext(Y);if(!s)throw new Error("useVehicleEventEmitter must be used within a VehicleEventProvider");return s}function ie(){return o.useMemo(()=>new A.VehicleEventEmitter,[])}function ae(s,i,x=[]){const r=ee();o.useEffect(()=>r.on(s,i),[r,s,...x])}function ue({children:s}){const i=o.useMemo(()=>new A.VehicleEventEmitter,[]);return te.jsx(Y.Provider,{value:i,children:s})}exports.VehicleEventContext=Y;exports.VehicleEventProvider=ue;exports.useAnimation=Z;exports.useCreateVehicleEventEmitter=ie;exports.useInitialMovement=oe;exports.useMovementQueue=X;exports.useMovementSequence=ce;exports.useScene=B;exports.useSceneDefinition=ne;exports.useVehicleEvent=ae;exports.useVehicleEventEmitter=ee;exports.useVehicleSimulation=re;exports.useVehicles=W;