vehicle-path2 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,21 +35,21 @@ export interface VehiclePosition {
35
35
  */
36
36
  export declare function calculateBezierArcLength(bezier: BezierCurve, segments?: number): number;
37
37
  /**
38
- * Resolve offset untuk FROM line (garis asal kurva)
39
- * - 0% wheelbase (bukan 0, untuk memberi ruang vehicle)
40
- * - 100% → lineLength (ujung garis)
38
+ * Resolve offset untuk FROM line (garis asal kurva).
39
+ * Kurva bisa ditempatkan di mana saja pada line: range [0, lineLength].
41
40
  *
42
- * Effective range: [wheelbase, lineLength]
41
+ * Untuk absolute offset: clamp ke [0, lineLength].
42
+ * Untuk percentage (0-1): map ke [0, lineLength].
43
43
  */
44
- export declare function resolveFromLineOffset(line: Line, offset: number | undefined, isPercentage: boolean | undefined, defaultPercentage: number, maxWheelbase: number): number;
44
+ export declare function resolveFromLineOffset(line: Line, offset: number | undefined, isPercentage: boolean | undefined, defaultPercentage: number, _maxWheelbase: number): number;
45
45
  /**
46
- * Resolve offset untuk TO line (garis tujuan kurva)
47
- * - 0% 0 (awal garis)
48
- * - 100% → lineLength - wheelbase (untuk memberi ruang vehicle)
46
+ * Resolve offset untuk TO line (garis tujuan kurva).
47
+ * Kurva bisa ditempatkan di mana saja pada line: range [0, lineLength].
49
48
  *
50
- * Effective range: [0, lineLength - wheelbase]
49
+ * Untuk absolute offset: clamp ke [0, lineLength].
50
+ * Untuk percentage (0-1): map ke [0, lineLength].
51
51
  */
52
- export declare function resolveToLineOffset(line: Line, offset: number | undefined, isPercentage: boolean | undefined, defaultPercentage: number, maxWheelbase: number): number;
52
+ export declare function resolveToLineOffset(line: Line, offset: number | undefined, isPercentage: boolean | undefined, defaultPercentage: number, _maxWheelbase: number): number;
53
53
  /**
54
54
  * Membangun graph dari lines dan curves
55
55
  */
@@ -186,7 +186,12 @@ export type { VehicleMovementState as SegmentVehicleState };
186
186
  * Advance semua axle vehicle oleh `distance` sepanjang path.
187
187
  *
188
188
  * Ini adalah low-level tick primitive. Update semua axle menggunakan
189
- * arc-length parameterization. Arrival = axles[0] (terdepan) mencapai ujung path.
189
+ * arc-length parameterization. Arrival = axles[N-1] (rearmost) mencapai ujung path.
190
+ *
191
+ * Semantik: path dibuat dari posisi rear axle ke targetOffset. Sehingga
192
+ * `arrived=true` berarti rear axle telah mencapai targetOffset — bukan
193
+ * front axle mencapai ujung segmennya. Front axle tetap bisa "hang over"
194
+ * di luar batas path (di ujung line) via maxOffset.
190
195
  *
191
196
  * @param axleStates - Array AxleState saat ini, axles[0] = terdepan
192
197
  * @param axleExecutions - Array AxleExecutionState sesuai urutan axleStates
@@ -19,4 +19,4 @@ export { buildGraph, findPath, calculateBezierArcLength, resolveFromLineOffset,
19
19
  export { initializeMovingVehicle, createInitialMovementState, initializeAllVehicles, calculateInitialAxlePositions, type InitializationResult, updateAxlePosition, calculatePositionOnLine, calculatePositionOnCurve, calculateFrontAxlePosition, getCumulativeArcLength, arcLengthToSegmentPosition, prepareCommandPath, type PreparedPath, handleArrival, type SegmentCompletionContext, type SegmentCompletionResult, type SegmentVehicleState, moveVehicle, getPositionFromOffset, getLineLength } from './algorithms/vehicleMovement';
20
20
  export { PathEngine, type PathEngineConfig, type VehiclePathState, type PathExecution } from './engine';
21
21
  export { distance, normalize, getPointOnLine, getPointOnLineByOffset, getPointOnBezier, createBezierCurve, buildArcLengthTable, distanceToT, getArcLength, calculateTangentLength, isPointNearPoint, type ArcLengthEntry, type CurveOffsetOptions } from './algorithms/math';
22
- export { serializeScene, type SceneSnapshot } from './snapshot';
22
+ export { serializeScene, deserializeScene, type SceneSnapshot } from './snapshot';
@@ -6,28 +6,37 @@ export interface SceneSnapshot {
6
6
  fromLineId: string;
7
7
  toLineId: string;
8
8
  fromOffset: number;
9
+ fromIsPercentage: boolean;
9
10
  toOffset: number;
11
+ toIsPercentage: boolean;
10
12
  }>;
11
13
  vehicles: Array<{
12
14
  id: string;
15
+ lineId: string;
13
16
  axles: Array<{
14
- lineId: string;
15
17
  offset: number;
16
18
  }>;
17
19
  axleSpacings: number[];
20
+ isPercentage: boolean;
18
21
  }>;
19
22
  }
20
23
  /**
21
24
  * Serialize scene state to a JSON string suitable for clipboard or storage.
22
25
  * Strips derived fields (bezier curves, axle positions) — only source-of-truth
23
26
  * data is included.
27
+ *
28
+ * Note: lineId is per-vehicle (not per-axle) because this snapshot captures
29
+ * static placement where all axles share the same line. For mid-movement state,
30
+ * use AxleState directly.
24
31
  */
25
32
  export declare function serializeScene(lines: Line[], curves: Array<{
26
33
  id: string;
27
34
  fromLineId: string;
28
35
  toLineId: string;
29
36
  fromOffset: number;
37
+ fromIsPercentage?: boolean;
30
38
  toOffset: number;
39
+ toIsPercentage?: boolean;
31
40
  }>, vehicles: Array<{
32
41
  id: string;
33
42
  axles: Array<{
@@ -36,4 +45,10 @@ export declare function serializeScene(lines: Line[], curves: Array<{
36
45
  [key: string]: unknown;
37
46
  }>;
38
47
  axleSpacings: number[];
48
+ isPercentage?: boolean;
39
49
  }>): string;
50
+ /**
51
+ * Deserialize a JSON string back into a SceneSnapshot.
52
+ * Throws if the string is not valid JSON or missing required fields.
53
+ */
54
+ export declare function deserializeScene(json: string): SceneSnapshot;
package/dist/core.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DfPg-M5u.cjs");function r(n,a,o){const l={lines:n,curves:a.map(i=>({id:i.id,fromLineId:i.fromLineId,toLineId:i.toLineId,fromOffset:i.fromOffset,toOffset:i.toOffset})),vehicles:o.map(i=>({id:i.id,axles:i.axles.map(t=>({lineId:t.lineId,offset:t.offset})),axleSpacings:i.axleSpacings}))};return JSON.stringify(l,null,2)}exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;exports.calculatePositionOnCurve=e.calculatePositionOnCurve;exports.calculatePositionOnLine=e.calculatePositionOnLine;exports.calculateTangentLength=e.calculateTangentLength;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.isPointNearPoint=e.isPointNearPoint;exports.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;exports.serializeScene=r;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-BUYdltrL.cjs");function o(r,n,t){const a={lines:r,curves:n.map(i=>({id:i.id,fromLineId:i.fromLineId,toLineId:i.toLineId,fromOffset:i.fromOffset,fromIsPercentage:i.fromIsPercentage??!1,toOffset:i.toOffset,toIsPercentage:i.toIsPercentage??!1})),vehicles:t.map(i=>({id:i.id,lineId:i.axles[0].lineId,axles:i.axles.map(l=>({offset:l.offset})),axleSpacings:i.axleSpacings,isPercentage:i.isPercentage??!1}))};return JSON.stringify(a,null,2)}function s(r){let n;try{n=JSON.parse(r)}catch{throw new Error("deserializeScene: invalid JSON")}if(!n||typeof n!="object"||Array.isArray(n))throw new Error("deserializeScene: expected a JSON object");const t=n;if(!Array.isArray(t.lines))throw new Error('deserializeScene: missing "lines"');if(!Array.isArray(t.curves))throw new Error('deserializeScene: missing "curves"');if(!Array.isArray(t.vehicles))throw new Error('deserializeScene: missing "vehicles"');return{lines:t.lines,curves:t.curves,vehicles:t.vehicles}}exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;exports.calculatePositionOnCurve=e.calculatePositionOnCurve;exports.calculatePositionOnLine=e.calculatePositionOnLine;exports.calculateTangentLength=e.calculateTangentLength;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.isPointNearPoint=e.isPointNearPoint;exports.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;exports.deserializeScene=s;exports.serializeScene=o;
package/dist/core.js CHANGED
@@ -1,54 +1,78 @@
1
- import { P as f, a as c, b as g, c as d, d as h, e as m, f as u, g as L, h as P, i as O, j as p, k as v, l as x, m as A, n as z, o as I, p as S, q as T, r as B, s as C, t as b, u as y, v as F, w as V, x as E, y as M, z as N, A as j, B as k, C as q, D as w, E as D } from "./index-D8o0W80x.js";
2
- function o(i, t, s) {
3
- const n = {
4
- lines: i,
5
- curves: t.map((e) => ({
1
+ import { P as f, a as g, b as h, c as d, d as u, e as m, f as P, g as A, h as v, i as L, j as O, k as p, l as S, m as z, n as y, o as w, p as x, q as I, r as b, s as E, t as T, u as B, v as C, w as N, x as j, y as J, z as F, A as V, B as M, C as k, D as q, E as D } from "./index-D-HctiIv.js";
2
+ function n(s, a, i) {
3
+ const r = {
4
+ lines: s,
5
+ curves: a.map((e) => ({
6
6
  id: e.id,
7
7
  fromLineId: e.fromLineId,
8
8
  toLineId: e.toLineId,
9
9
  fromOffset: e.fromOffset,
10
- toOffset: e.toOffset
10
+ fromIsPercentage: e.fromIsPercentage ?? !1,
11
+ toOffset: e.toOffset,
12
+ toIsPercentage: e.toIsPercentage ?? !1
11
13
  })),
12
- vehicles: s.map((e) => ({
14
+ vehicles: i.map((e) => ({
13
15
  id: e.id,
14
- axles: e.axles.map((a) => ({ lineId: a.lineId, offset: a.offset })),
15
- axleSpacings: e.axleSpacings
16
+ lineId: e.axles[0].lineId,
17
+ axles: e.axles.map((t) => ({ offset: t.offset })),
18
+ axleSpacings: e.axleSpacings,
19
+ isPercentage: e.isPercentage ?? !1
16
20
  }))
17
21
  };
18
- return JSON.stringify(n, null, 2);
22
+ return JSON.stringify(r, null, 2);
23
+ }
24
+ function o(s) {
25
+ let a;
26
+ try {
27
+ a = JSON.parse(s);
28
+ } catch {
29
+ throw new Error("deserializeScene: invalid JSON");
30
+ }
31
+ if (!a || typeof a != "object" || Array.isArray(a))
32
+ throw new Error("deserializeScene: expected a JSON object");
33
+ const i = a;
34
+ if (!Array.isArray(i.lines)) throw new Error('deserializeScene: missing "lines"');
35
+ if (!Array.isArray(i.curves)) throw new Error('deserializeScene: missing "curves"');
36
+ if (!Array.isArray(i.vehicles)) throw new Error('deserializeScene: missing "vehicles"');
37
+ return {
38
+ lines: i.lines,
39
+ curves: i.curves,
40
+ vehicles: i.vehicles
41
+ };
19
42
  }
20
43
  export {
21
44
  f as PathEngine,
22
- c as arcLengthToSegmentPosition,
23
- g as buildArcLengthTable,
45
+ g as arcLengthToSegmentPosition,
46
+ h as buildArcLengthTable,
24
47
  d as buildGraph,
25
- h as calculateBezierArcLength,
48
+ u as calculateBezierArcLength,
26
49
  m as calculateFrontAxlePosition,
27
- u as calculateInitialAxlePositions,
28
- L as calculatePositionOnCurve,
29
- P as calculatePositionOnLine,
30
- O as calculateTangentLength,
31
- p as createBezierCurve,
32
- v as createInitialMovementState,
33
- x as distance,
34
- A as distanceToT,
35
- z as findPath,
36
- I as getArcLength,
37
- S as getCumulativeArcLength,
38
- T as getLineLength,
39
- B as getPointOnBezier,
40
- C as getPointOnLine,
41
- b as getPointOnLineByOffset,
42
- y as getPositionFromOffset,
43
- F as handleArrival,
44
- V as initializeAllVehicles,
45
- E as initializeMovingVehicle,
46
- M as isPointNearPoint,
47
- N as moveVehicle,
48
- j as normalize,
49
- k as prepareCommandPath,
50
- q as resolveFromLineOffset,
51
- w as resolveToLineOffset,
52
- o as serializeScene,
50
+ P as calculateInitialAxlePositions,
51
+ A as calculatePositionOnCurve,
52
+ v as calculatePositionOnLine,
53
+ L as calculateTangentLength,
54
+ O as createBezierCurve,
55
+ p as createInitialMovementState,
56
+ o as deserializeScene,
57
+ S as distance,
58
+ z as distanceToT,
59
+ y as findPath,
60
+ w as getArcLength,
61
+ x as getCumulativeArcLength,
62
+ I as getLineLength,
63
+ b as getPointOnBezier,
64
+ E as getPointOnLine,
65
+ T as getPointOnLineByOffset,
66
+ B as getPositionFromOffset,
67
+ C as handleArrival,
68
+ N as initializeAllVehicles,
69
+ j as initializeMovingVehicle,
70
+ J as isPointNearPoint,
71
+ F as moveVehicle,
72
+ V as normalize,
73
+ M as prepareCommandPath,
74
+ k as resolveFromLineOffset,
75
+ q as resolveToLineOffset,
76
+ n as serializeScene,
53
77
  D as updateAxlePosition
54
78
  };
@@ -0,0 +1 @@
1
+ "use strict";function L(t,e){const s=e.x-t.x,n=e.y-t.y;return Math.sqrt(s*s+n*n)}function D(t,e){const s=e.x-t.x,n=e.y-t.y,i=Math.sqrt(s*s+n*n);return i===0?{x:0,y:0}:{x:s/i,y:n/i}}function E(t,e){return e*(t==="proportional-40"?.4:.5522)}function V(t,e,s,n=!1,i){const{maxWheelbase:o,tangentMode:c}=s;let r;i?.fromOffset!==void 0?r=b(t,i.fromOffset,i.fromIsPercentage??!1):r=t.end;let a;i?.toOffset!==void 0?a=b(e,i.toOffset,i.toIsPercentage??!1):a=e.start;const l=D(t.start,t.end),u=n?{x:r.x-l.x*o,y:r.y-l.y*o}:r,g=D(t.start,t.end),d=D(e.start,e.end),h=L(u,a),p=E(c,h),f=n?{x:u.x-g.x*p,y:u.y-g.y*p}:{x:u.x+g.x*p,y:u.y+g.y*p},v={x:a.x-d.x*p,y:a.y-d.y*p};return{p0:u,p1:f,p2:v,p3:a}}function F(t,e){return{x:t.start.x+(t.end.x-t.start.x)*e,y:t.start.y+(t.end.y-t.start.y)*e}}function b(t,e,s){const n=L(t.start,t.end);let i;return s?i=e:i=n>0?e/n:0,i=Math.max(0,Math.min(1,i)),F(t,i)}function T(t,e){const{p0:s,p1:n,p2:i,p3:o}=t,c=1-e,r=c*c,a=r*c,l=e*e,u=l*e;return{x:a*s.x+3*r*e*n.x+3*c*l*i.x+u*o.x,y:a*s.y+3*r*e*n.y+3*c*l*i.y+u*o.y}}function ee(t,e,s=10){return L(t,e)<=s}function N(t,e=100){const s=[{t:0,distance:0}];let n=t.p0,i=0;for(let o=1;o<=e;o++){const c=o/e,r=T(t,c);i+=L(n,r),s.push({t:c,distance:i}),n=r}return s}function $(t,e){if(e<=0)return 0;const s=t[t.length-1].distance;if(e>=s)return 1;let n=0,i=t.length-1;for(;n<i-1;){const u=Math.floor((n+i)/2);t[u].distance<e?n=u:i=u}const o=t[n].distance,c=t[i].distance,r=t[n].t,a=t[i].t;if(c===o)return r;const l=(e-o)/(c-o);return r+l*(a-r)}function te(t){return t[t.length-1].distance}function j(t,e=100){let s=0,n=t.p0;for(let i=1;i<=e;i++){const o=i/e,c=T(t,o);s+=L(n,c),n=c}return s}function z(t,e,s,n,i){const o=L(t.start,t.end);return e===void 0?n*o:s?Math.max(0,Math.min(e,1))*o:Math.max(0,Math.min(e,o))}function W(t,e,s,n,i){const o=L(t.start,t.end);return e===void 0?n*o:s?Math.max(0,Math.min(e,1))*o:Math.max(0,Math.min(e,o))}function x(t,e,s){const n=new Map,i=new Map,o=new Map;for(const c of t)i.set(c.id,c),o.set(c.id,L(c.start,c.end)),n.set(c.id,[]);for(let c=0;c<e.length;c++){const r=e[c],a=i.get(r.fromLineId),l=i.get(r.toLineId);if(!a||!l)continue;const u=z(a,r.fromOffset,r.fromIsPercentage,1,s.maxWheelbase),g=W(l,r.toOffset,r.toIsPercentage,0,s.maxWheelbase),d=V(a,l,s,!1,{fromOffset:u,fromIsPercentage:!1,toOffset:g,toIsPercentage:!1}),h=j(d),p={curveIndex:c,fromLineId:r.fromLineId,toLineId:r.toLineId,fromOffset:u,toOffset:g,curveLength:h};n.get(r.fromLineId).push(p)}return{adjacency:n,lines:i,lineLengths:o}}function q(t,e){return t.curveCount!==e.curveCount?t.curveCount-e.curveCount:t.totalDistance-e.totalDistance}function K(t,e,s,n,i=!1){const{adjacency:o,lines:c,lineLengths:r}=t;if(!c.get(s))return null;const l=r.get(s),u=i?n/100*l:n,g=[],d=new Map,h=(f,v)=>`${f}:${Math.round(v)}`;if(e.lineId===s&&u>=e.offset){const f=u-e.offset;return{segments:[{type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:u,length:f}],totalDistance:f,curveCount:0}}const p=o.get(e.lineId)||[];for(const f of p){if(f.fromOffset<e.offset)continue;const v=f.fromOffset-e.offset,I=v+f.curveLength,O={type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:f.fromOffset,length:v},m={type:"curve",curveIndex:f.curveIndex,startOffset:0,endOffset:f.curveLength,length:f.curveLength};g.push({lineId:f.toLineId,entryOffset:f.toOffset,totalDistance:I,curveCount:1,path:[O,m]})}for(g.sort(q);g.length>0;){const f=g.shift(),v=h(f.lineId,f.entryOffset),I=d.get(v);if(I!==void 0&&(I.curveCount<f.curveCount||I.curveCount===f.curveCount&&I.distance<=f.totalDistance))continue;if(d.set(v,{curveCount:f.curveCount,distance:f.totalDistance}),f.lineId===s){const m=Math.abs(u-f.entryOffset);if(u>=f.entryOffset){const P={type:"line",lineId:s,startOffset:f.entryOffset,endOffset:u,length:m};return{segments:[...f.path,P],totalDistance:f.totalDistance+m,curveCount:f.curveCount}}}const O=o.get(f.lineId)||[];for(const m of O){if(m.fromOffset<f.entryOffset)continue;const P=m.fromOffset-f.entryOffset,B=f.totalDistance+P+m.curveLength,w=f.curveCount+1,X=h(m.toLineId,m.toOffset),C=d.get(X);if(C!==void 0&&(C.curveCount<w||C.curveCount===w&&C.distance<=B))continue;const Y={type:"line",lineId:f.lineId,startOffset:f.entryOffset,endOffset:m.fromOffset,length:P},Z={type:"curve",curveIndex:m.curveIndex,startOffset:0,endOffset:m.curveLength,length:m.curveLength};g.push({lineId:m.toLineId,entryOffset:m.toOffset,totalDistance:B,curveCount:w,path:[...f.path,Y,Z]})}g.sort(q)}return null}function S(t,e){const s=Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2)),n=s>0?e/s:0;return{x:t.start.x+(t.end.x-t.start.x)*Math.min(1,Math.max(0,n)),y:t.start.y+(t.end.y-t.start.y)*Math.min(1,Math.max(0,n))}}function M(t){return Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2))}function _(t,e,s){let n=0;for(let i=0;i<e;i++)n+=t.segments[i].length;return n+=s,n}function k(t,e){let s=0;for(let n=0;n<t.segments.length;n++){const i=t.segments[n],o=s+i.length;if(e<o)return{segmentIndex:n,segmentDistance:e-s};if(e===o)return n+1<t.segments.length?{segmentIndex:n+1,segmentDistance:0}:{segmentIndex:n,segmentDistance:i.length};s+=i.length}return null}function ne(t,e,s,n){const o=_(t,e,s)+n;return k(t,o)}function G(t,e,s,n){const i=M(n),o=s.length+1,c=new Array(o);c[o-1]={lineId:t,absoluteOffset:e,position:S(n,e)};let r=e;for(let a=o-2;a>=0;a--)r=Math.min(r+s[a],i),c[a]={lineId:t,absoluteOffset:r,position:S(n,r)};return c}function Q(t,e){return{...t,state:"idle"}}function R(t){return{vehicle:t,execution:null}}function se(t,e){const s=[],n=new Map;for(const i of t){if(!e.get(i.lineId))continue;const c=Q(i);s.push(c);const r=R(c);n.set(i.id,r)}return{movingVehicles:s,stateMap:n}}function y(t,e){return{position:S(t,e),lineId:t.id,absoluteOffset:e}}function A(t,e){const s=$(t.arcLengthTable,e);return{position:T(t.bezier,s)}}function H(t,e,s,n,i,o,c){const r=s.segments[e.currentSegmentIndex],a=e.segmentDistance+n;if(a>=r.length){const u=a-r.length,g=e.currentSegmentIndex+1;if(g>=s.segments.length){if(c!==void 0&&r.type==="line"){const f=i.get(r.lineId),v=r.startOffset+a;if(v<=c){const O=y(f,v);return{axleState:{...t,...O},execution:{...e,segmentDistance:a},completed:!1}}const I=y(f,c);return{axleState:{...t,...I},execution:{...e,segmentDistance:c-r.startOffset},completed:!0}}const p=r.type==="line"?y(i.get(r.lineId),r.endOffset):A(o.get(r.curveIndex),r.length);return{axleState:{...t,...p},execution:{...e,segmentDistance:r.length},completed:!0}}const d=s.segments[g],h=d.type==="line"?y(i.get(d.lineId),d.startOffset+u):A(o.get(d.curveIndex),u);return{axleState:{...t,...h},execution:{currentSegmentIndex:g,segmentDistance:u},completed:!1}}const l=r.type==="line"?y(i.get(r.lineId),r.startOffset+a):A(o.get(r.curveIndex),a);return{axleState:{...t,...l},execution:{...e,segmentDistance:a},completed:!1}}function ie(t,e,s,n){const i=new Map;for(const o of t.segments)if(o.type==="curve"&&o.curveIndex!==void 0){const c=e[o.curveIndex];if(c){const r=s.get(c.fromLineId),a=s.get(c.toLineId);if(r&&a){const l=z(r,c.fromOffset,c.fromIsPercentage,1,n.maxWheelbase),u=W(a,c.toOffset,c.toIsPercentage,0,n.maxWheelbase),g=V(r,a,n,!1,{fromOffset:l,fromIsPercentage:!1,toOffset:u,toIsPercentage:!1}),d=N(g);i.set(o.curveIndex,{bezier:g,arcLengthTable:d})}}}return i}function J(t,e,s){const{graph:n,linesMap:i,curves:o,config:c}=s,r=i.get(e.targetLineId);if(!r)return null;const a=t.axleSpacings.reduce((f,v)=>f+v,0),u=M(r)-a;if(u<=0)return null;const g=e.isPercentage?e.targetOffset*u:Math.min(e.targetOffset,u),d=t.axles[t.axles.length-1],h=K(n,{lineId:d.lineId,offset:d.absoluteOffset},e.targetLineId,g,!1);if(!h)return null;const p=ie(h,o,i,c);return{path:h,curveDataMap:p}}function re(t,e){const s=t.execution,i=e.vehicleQueues.get(t.vehicle.id)?.[s.currentCommandIndex];return i&&e.onCommandComplete&&e.onCommandComplete({vehicleId:t.vehicle.id,command:i,finalPosition:{lineId:t.vehicle.axles[t.vehicle.axles.length-1].lineId,absoluteOffset:t.vehicle.axles[t.vehicle.axles.length-1].absoluteOffset,position:t.vehicle.axles[t.vehicle.axles.length-1].position},payload:i.payload}),{handled:!0,vehicle:{...t.vehicle,state:"waiting"},newExecution:s,isWaiting:!0}}function U(t,e,s,n,i,o){let c;const r=e[0];if(r.currentSegmentIndex<s.segments.length){const l=s.segments[r.currentSegmentIndex];if(l.type==="line"){const u=i.get(l.lineId);u&&(c=M(u))}}const a=t.map((l,u)=>{const g=u===0?c:void 0;return H(l,e[u],s,n,i,o,g)});return{axles:a.map(l=>l.axleState),axleExecutions:a.map(l=>l.execution),arrived:a[a.length-1].completed}}class oe{graph=null;linesMap=new Map;curves=[];config;constructor(e){this.config={maxWheelbase:e.maxWheelbase,tangentMode:e.tangentMode}}get movementConfig(){return this.config}get lines(){return Array.from(this.linesMap.values())}getCurves(){return this.curves}setScene(e,s){this.linesMap.clear();for(const n of e)this.linesMap.set(n.id,n);this.curves=s,this.graph=x(e,s,this.config)}addLine(e){return this.linesMap.has(e.id)?!1:(this.linesMap.set(e.id,e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}updateLine(e,s){const n=this.linesMap.get(e);return n?(s.start&&(n.start=s.start),s.end&&(n.end=s.end),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}updateLineEndpoint(e,s,n){return this.updateLine(e,{[s]:n})}renameLine(e,s){const n=s.trim();if(!n)return{success:!1,error:"Name cannot be empty"};if(n===e)return{success:!0};if(this.linesMap.has(n))return{success:!1,error:`"${n}" already exists`};const i=this.linesMap.get(e);if(!i)return{success:!1,error:`Line "${e}" not found`};i.id=n,this.linesMap.delete(e),this.linesMap.set(n,i);for(const o of this.curves)o.fromLineId===e&&(o.fromLineId=n),o.toLineId===e&&(o.toLineId=n);return this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),{success:!0}}removeLine(e){return this.linesMap.has(e)?(this.linesMap.delete(e),this.curves=this.curves.filter(s=>s.fromLineId!==e&&s.toLineId!==e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}addCurve(e){this.curves.push(e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config)}updateCurve(e,s){return e<0||e>=this.curves.length?!1:(this.curves[e]={...this.curves[e],...s},this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}removeCurve(e){return e<0||e>=this.curves.length?!1:(this.curves.splice(e,1),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}initializeVehicle(e,s,n){const i=this.linesMap.get(e);if(!i)return null;const o=n.reduce((l,u)=>l+u,0),c=M(i),r=Math.min(s,c-o);return{axles:G(e,r,n,i).map(l=>({lineId:l.lineId,offset:l.absoluteOffset,position:l.position})),axleSpacings:n}}preparePath(e,s,n,i=!1){if(!this.graph)return null;const o=e.axleSpacings.reduce((h,p)=>h+p,0),c=e.axles[e.axles.length-1],r={lineId:c.lineId,offset:c.offset,axles:e.axles.map(h=>({lineId:h.lineId,position:h.position,absoluteOffset:h.offset})),axleSpacings:e.axleSpacings},a=J(r,{targetLineId:s,targetOffset:n,isPercentage:i},{graph:this.graph,linesMap:this.linesMap,curves:this.curves,config:this.config});if(!a)return null;let l=n;const u=this.linesMap.get(s);if(u){const h=Math.max(0,M(u)-o);l=i?n*h:Math.min(n,h)}let g=0;const d=[{segmentIndex:0,segmentDistance:o}];for(let h=0;h<e.axleSpacings.length;h++)g+=e.axleSpacings[h],d.push({segmentIndex:0,segmentDistance:o-g});return{path:a.path,curveDataMap:a.curveDataMap,axleExecutions:d,targetLineId:s,targetOffset:l}}moveVehicle(e,s,n){const i=e.axles.map(r=>({lineId:r.lineId,position:r.position,absoluteOffset:r.offset})),o=s.axleExecutions.map(r=>({currentSegmentIndex:r.segmentIndex,segmentDistance:r.segmentDistance})),c=U(i,o,s.path,n,this.linesMap,s.curveDataMap);return{state:{axles:c.axles.map(r=>({lineId:r.lineId,offset:r.absoluteOffset,position:r.position})),axleSpacings:e.axleSpacings},execution:{...s,axleExecutions:c.axleExecutions.map(r=>({segmentIndex:r.currentSegmentIndex,segmentDistance:r.segmentDistance}))},arrived:c.arrived}}}exports.PathEngine=oe;exports.arcLengthToSegmentPosition=k;exports.buildArcLengthTable=N;exports.buildGraph=x;exports.calculateBezierArcLength=j;exports.calculateFrontAxlePosition=ne;exports.calculateInitialAxlePositions=G;exports.calculatePositionOnCurve=A;exports.calculatePositionOnLine=y;exports.calculateTangentLength=E;exports.createBezierCurve=V;exports.createInitialMovementState=R;exports.distance=L;exports.distanceToT=$;exports.findPath=K;exports.getArcLength=te;exports.getCumulativeArcLength=_;exports.getLineLength=M;exports.getPointOnBezier=T;exports.getPointOnLine=F;exports.getPointOnLineByOffset=b;exports.getPositionFromOffset=S;exports.handleArrival=re;exports.initializeAllVehicles=se;exports.initializeMovingVehicle=Q;exports.isPointNearPoint=ee;exports.moveVehicle=U;exports.normalize=D;exports.prepareCommandPath=J;exports.resolveFromLineOffset=z;exports.resolveToLineOffset=W;exports.updateAxlePosition=H;
@@ -3,27 +3,27 @@ function y(t, e) {
3
3
  return Math.sqrt(s * s + n * n);
4
4
  }
5
5
  function w(t, e) {
6
- const s = e.x - t.x, n = e.y - t.y, i = Math.sqrt(s * s + n * n);
7
- return i === 0 ? { x: 0, y: 0 } : { x: s / i, y: n / i };
6
+ const s = e.x - t.x, n = e.y - t.y, r = Math.sqrt(s * s + n * n);
7
+ return r === 0 ? { x: 0, y: 0 } : { x: s / r, y: n / r };
8
8
  }
9
9
  function k(t, e) {
10
10
  return e * (t === "proportional-40" ? 0.4 : 0.5522);
11
11
  }
12
- function q(t, e, s, n = !1, i) {
13
- const { maxWheelbase: c, tangentMode: o } = s;
14
- let r;
15
- i?.fromOffset !== void 0 ? r = V(t, i.fromOffset, i.fromIsPercentage ?? !1) : r = t.end;
16
- let a;
17
- i?.toOffset !== void 0 ? a = V(e, i.toOffset, i.toIsPercentage ?? !1) : a = e.start;
12
+ function z(t, e, s, n = !1, r) {
13
+ const { maxWheelbase: o, tangentMode: a } = s;
14
+ let i;
15
+ r?.fromOffset !== void 0 ? i = V(t, r.fromOffset, r.fromIsPercentage ?? !1) : i = t.end;
16
+ let c;
17
+ r?.toOffset !== void 0 ? c = V(e, r.toOffset, r.toIsPercentage ?? !1) : c = e.start;
18
18
  const l = w(t.start, t.end), f = n ? {
19
19
  // Transition with flip: kurva dimulai dari P (baseP0 - wheelbase in line direction)
20
- x: r.x - l.x * c,
21
- y: r.y - l.y * c
22
- } : r, g = w(t.start, t.end), d = w(e.start, e.end), h = y(f, a), p = k(o, h), u = n ? { x: f.x - g.x * p, y: f.y - g.y * p } : { x: f.x + g.x * p, y: f.y + g.y * p }, v = {
23
- x: a.x - d.x * p,
24
- y: a.y - d.y * p
20
+ x: i.x - l.x * o,
21
+ y: i.y - l.y * o
22
+ } : i, g = w(t.start, t.end), d = w(e.start, e.end), h = y(f, c), p = k(a, h), u = n ? { x: f.x - g.x * p, y: f.y - g.y * p } : { x: f.x + g.x * p, y: f.y + g.y * p }, v = {
23
+ x: c.x - d.x * p,
24
+ y: c.y - d.y * p
25
25
  };
26
- return { p0: f, p1: u, p2: v, p3: a };
26
+ return { p0: f, p1: u, p2: v, p3: c };
27
27
  }
28
28
  function K(t, e) {
29
29
  return {
@@ -33,14 +33,14 @@ function K(t, e) {
33
33
  }
34
34
  function V(t, e, s) {
35
35
  const n = y(t.start, t.end);
36
- let i;
37
- return s ? i = e : i = n > 0 ? e / n : 0, i = Math.max(0, Math.min(1, i)), K(t, i);
36
+ let r;
37
+ return s ? r = e : r = n > 0 ? e / n : 0, r = Math.max(0, Math.min(1, r)), K(t, r);
38
38
  }
39
- function T(t, e) {
40
- const { p0: s, p1: n, p2: i, p3: c } = t, o = 1 - e, r = o * o, a = r * o, l = e * e, f = l * e;
39
+ function b(t, e) {
40
+ const { p0: s, p1: n, p2: r, p3: o } = t, a = 1 - e, i = a * a, c = i * a, l = e * e, f = l * e;
41
41
  return {
42
- x: a * s.x + 3 * r * e * n.x + 3 * o * l * i.x + f * c.x,
43
- y: a * s.y + 3 * r * e * n.y + 3 * o * l * i.y + f * c.y
42
+ x: c * s.x + 3 * i * e * n.x + 3 * a * l * r.x + f * o.x,
43
+ y: c * s.y + 3 * i * e * n.y + 3 * a * l * r.y + f * o.y
44
44
  };
45
45
  }
46
46
  function ne(t, e, s = 10) {
@@ -48,75 +48,55 @@ function ne(t, e, s = 10) {
48
48
  }
49
49
  function N(t, e = 100) {
50
50
  const s = [{ t: 0, distance: 0 }];
51
- let n = t.p0, i = 0;
52
- for (let c = 1; c <= e; c++) {
53
- const o = c / e, r = T(t, o);
54
- i += y(n, r), s.push({ t: o, distance: i }), n = r;
51
+ let n = t.p0, r = 0;
52
+ for (let o = 1; o <= e; o++) {
53
+ const a = o / e, i = b(t, a);
54
+ r += y(n, i), s.push({ t: a, distance: r }), n = i;
55
55
  }
56
56
  return s;
57
57
  }
58
- function F(t, e) {
58
+ function _(t, e) {
59
59
  if (e <= 0) return 0;
60
60
  const s = t[t.length - 1].distance;
61
61
  if (e >= s) return 1;
62
- let n = 0, i = t.length - 1;
63
- for (; n < i - 1; ) {
64
- const f = Math.floor((n + i) / 2);
65
- t[f].distance < e ? n = f : i = f;
62
+ let n = 0, r = t.length - 1;
63
+ for (; n < r - 1; ) {
64
+ const f = Math.floor((n + r) / 2);
65
+ t[f].distance < e ? n = f : r = f;
66
66
  }
67
- const c = t[n].distance, o = t[i].distance, r = t[n].t, a = t[i].t;
68
- if (o === c) return r;
69
- const l = (e - c) / (o - c);
70
- return r + l * (a - r);
67
+ const o = t[n].distance, a = t[r].distance, i = t[n].t, c = t[r].t;
68
+ if (a === o) return i;
69
+ const l = (e - o) / (a - o);
70
+ return i + l * (c - i);
71
71
  }
72
72
  function se(t) {
73
73
  return t[t.length - 1].distance;
74
74
  }
75
- function G(t, e = 100) {
75
+ function F(t, e = 100) {
76
76
  let s = 0, n = t.p0;
77
- for (let i = 1; i <= e; i++) {
78
- const c = i / e, o = T(t, c);
79
- s += y(n, o), n = o;
77
+ for (let r = 1; r <= e; r++) {
78
+ const o = r / e, a = b(t, o);
79
+ s += y(n, a), n = a;
80
80
  }
81
81
  return s;
82
82
  }
83
- function E(t, e, s, n, i) {
84
- const c = y(t.start, t.end), o = c - i;
85
- if (o <= 0)
86
- return c;
87
- let r;
88
- if (e === void 0)
89
- r = n;
90
- else if (s)
91
- r = e;
92
- else {
93
- const a = Math.max(0, Math.min(e, o));
94
- return i + a;
95
- }
96
- return i + r * o;
83
+ function q(t, e, s, n, r) {
84
+ const o = y(t.start, t.end);
85
+ return e === void 0 ? n * o : s ? Math.max(0, Math.min(e, 1)) * o : Math.max(0, Math.min(e, o));
97
86
  }
98
- function W(t, e, s, n, i) {
99
- const o = y(t.start, t.end) - i;
100
- if (o <= 0)
101
- return 0;
102
- let r;
103
- if (e === void 0)
104
- r = n;
105
- else if (s)
106
- r = e;
107
- else
108
- return Math.max(0, Math.min(e, o));
109
- return r * o;
87
+ function E(t, e, s, n, r) {
88
+ const o = y(t.start, t.end);
89
+ return e === void 0 ? n * o : s ? Math.max(0, Math.min(e, 1)) * o : Math.max(0, Math.min(e, o));
110
90
  }
111
91
  function I(t, e, s) {
112
- const n = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map();
113
- for (const o of t)
114
- i.set(o.id, o), c.set(o.id, y(o.start, o.end)), n.set(o.id, []);
115
- for (let o = 0; o < e.length; o++) {
116
- const r = e[o], a = i.get(r.fromLineId), l = i.get(r.toLineId);
117
- if (!a || !l) continue;
118
- const f = E(a, r.fromOffset, r.fromIsPercentage, 1, s.maxWheelbase), g = W(l, r.toOffset, r.toIsPercentage, 0, s.maxWheelbase), d = q(
119
- a,
92
+ const n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
93
+ for (const a of t)
94
+ r.set(a.id, a), o.set(a.id, y(a.start, a.end)), n.set(a.id, []);
95
+ for (let a = 0; a < e.length; a++) {
96
+ const i = e[a], c = r.get(i.fromLineId), l = r.get(i.toLineId);
97
+ if (!c || !l) continue;
98
+ const f = q(c, i.fromOffset, i.fromIsPercentage, 1, s.maxWheelbase), g = E(l, i.toOffset, i.toIsPercentage, 0, s.maxWheelbase), d = z(
99
+ c,
120
100
  l,
121
101
  s,
122
102
  !1,
@@ -129,25 +109,25 @@ function I(t, e, s) {
129
109
  toIsPercentage: !1
130
110
  // Already resolved to absolute
131
111
  }
132
- ), h = G(d), p = {
133
- curveIndex: o,
134
- fromLineId: r.fromLineId,
135
- toLineId: r.toLineId,
112
+ ), h = F(d), p = {
113
+ curveIndex: a,
114
+ fromLineId: i.fromLineId,
115
+ toLineId: i.toLineId,
136
116
  fromOffset: f,
137
117
  toOffset: g,
138
118
  curveLength: h
139
119
  };
140
- n.get(r.fromLineId).push(p);
120
+ n.get(i.fromLineId).push(p);
141
121
  }
142
- return { adjacency: n, lines: i, lineLengths: c };
122
+ return { adjacency: n, lines: r, lineLengths: o };
143
123
  }
144
- function z(t, e) {
124
+ function W(t, e) {
145
125
  return t.curveCount !== e.curveCount ? t.curveCount - e.curveCount : t.totalDistance - e.totalDistance;
146
126
  }
147
- function Q(t, e, s, n, i = !1) {
148
- const { adjacency: c, lines: o, lineLengths: r } = t;
149
- if (!o.get(s)) return null;
150
- const l = r.get(s), f = i ? n / 100 * l : n, g = [], d = /* @__PURE__ */ new Map(), h = (u, v) => `${u}:${Math.round(v)}`;
127
+ function G(t, e, s, n, r = !1) {
128
+ const { adjacency: o, lines: a, lineLengths: i } = t;
129
+ if (!a.get(s)) return null;
130
+ const l = i.get(s), f = r ? n / 100 * l : n, g = [], d = /* @__PURE__ */ new Map(), h = (u, v) => `${u}:${Math.round(v)}`;
151
131
  if (e.lineId === s && f >= e.offset) {
152
132
  const u = f - e.offset;
153
133
  return {
@@ -162,7 +142,7 @@ function Q(t, e, s, n, i = !1) {
162
142
  curveCount: 0
163
143
  };
164
144
  }
165
- const p = c.get(e.lineId) || [];
145
+ const p = o.get(e.lineId) || [];
166
146
  for (const u of p) {
167
147
  if (u.fromOffset < e.offset) continue;
168
148
  const v = u.fromOffset - e.offset, x = v + u.curveLength, L = {
@@ -186,7 +166,7 @@ function Q(t, e, s, n, i = !1) {
186
166
  path: [L, m]
187
167
  });
188
168
  }
189
- for (g.sort(z); g.length > 0; ) {
169
+ for (g.sort(W); g.length > 0; ) {
190
170
  const u = g.shift(), v = h(u.lineId, u.entryOffset), x = d.get(v);
191
171
  if (x !== void 0 && (x.curveCount < u.curveCount || x.curveCount === u.curveCount && x.distance <= u.totalDistance))
192
172
  continue;
@@ -207,11 +187,11 @@ function Q(t, e, s, n, i = !1) {
207
187
  };
208
188
  }
209
189
  }
210
- const L = c.get(u.lineId) || [];
190
+ const L = o.get(u.lineId) || [];
211
191
  for (const m of L) {
212
192
  if (m.fromOffset < u.entryOffset) continue;
213
- const C = m.fromOffset - u.entryOffset, b = u.totalDistance + C + m.curveLength, P = u.curveCount + 1, B = h(m.toLineId, m.toOffset), D = d.get(B);
214
- if (D !== void 0 && (D.curveCount < P || D.curveCount === P && D.distance <= b))
193
+ const C = m.fromOffset - u.entryOffset, T = u.totalDistance + C + m.curveLength, P = u.curveCount + 1, B = h(m.toLineId, m.toOffset), D = d.get(B);
194
+ if (D !== void 0 && (D.curveCount < P || D.curveCount === P && D.distance <= T))
215
195
  continue;
216
196
  const j = {
217
197
  type: "line",
@@ -229,12 +209,12 @@ function Q(t, e, s, n, i = !1) {
229
209
  g.push({
230
210
  lineId: m.toLineId,
231
211
  entryOffset: m.toOffset,
232
- totalDistance: b,
212
+ totalDistance: T,
233
213
  curveCount: P,
234
214
  path: [...u.path, j, $]
235
215
  });
236
216
  }
237
- g.sort(z);
217
+ g.sort(W);
238
218
  }
239
219
  return null;
240
220
  }
@@ -252,56 +232,56 @@ function O(t) {
252
232
  Math.pow(t.end.x - t.start.x, 2) + Math.pow(t.end.y - t.start.y, 2)
253
233
  );
254
234
  }
255
- function R(t, e, s) {
235
+ function Q(t, e, s) {
256
236
  let n = 0;
257
- for (let i = 0; i < e; i++)
258
- n += t.segments[i].length;
237
+ for (let r = 0; r < e; r++)
238
+ n += t.segments[r].length;
259
239
  return n += s, n;
260
240
  }
261
- function _(t, e) {
241
+ function R(t, e) {
262
242
  let s = 0;
263
243
  for (let n = 0; n < t.segments.length; n++) {
264
- const i = t.segments[n], c = s + i.length;
265
- if (e < c)
244
+ const r = t.segments[n], o = s + r.length;
245
+ if (e < o)
266
246
  return {
267
247
  segmentIndex: n,
268
248
  segmentDistance: e - s
269
249
  };
270
- if (e === c)
250
+ if (e === o)
271
251
  return n + 1 < t.segments.length ? {
272
252
  segmentIndex: n + 1,
273
253
  segmentDistance: 0
274
254
  } : {
275
255
  segmentIndex: n,
276
- segmentDistance: i.length
256
+ segmentDistance: r.length
277
257
  };
278
- s += i.length;
258
+ s += r.length;
279
259
  }
280
260
  return null;
281
261
  }
282
- function ie(t, e, s, n) {
283
- const c = R(
262
+ function re(t, e, s, n) {
263
+ const o = Q(
284
264
  t,
285
265
  e,
286
266
  s
287
267
  ) + n;
288
- return _(t, c);
268
+ return R(t, o);
289
269
  }
290
270
  function H(t, e, s, n) {
291
- const i = O(n), c = s.length + 1, o = new Array(c);
292
- o[c - 1] = {
271
+ const r = O(n), o = s.length + 1, a = new Array(o);
272
+ a[o - 1] = {
293
273
  lineId: t,
294
274
  absoluteOffset: e,
295
275
  position: A(n, e)
296
276
  };
297
- let r = e;
298
- for (let a = c - 2; a >= 0; a--)
299
- r = Math.min(r + s[a], i), o[a] = {
277
+ let i = e;
278
+ for (let c = o - 2; c >= 0; c--)
279
+ i = Math.min(i + s[c], r), a[c] = {
300
280
  lineId: t,
301
- absoluteOffset: r,
302
- position: A(n, r)
281
+ absoluteOffset: i,
282
+ position: A(n, i)
303
283
  };
304
- return o;
284
+ return a;
305
285
  }
306
286
  function J(t, e) {
307
287
  return {
@@ -315,14 +295,14 @@ function U(t) {
315
295
  execution: null
316
296
  };
317
297
  }
318
- function re(t, e) {
298
+ function ie(t, e) {
319
299
  const s = [], n = /* @__PURE__ */ new Map();
320
- for (const i of t) {
321
- if (!e.get(i.lineId)) continue;
322
- const o = J(i);
323
- s.push(o);
324
- const r = U(o);
325
- n.set(i.id, r);
300
+ for (const r of t) {
301
+ if (!e.get(r.lineId)) continue;
302
+ const a = J(r);
303
+ s.push(a);
304
+ const i = U(a);
305
+ n.set(r.id, i);
326
306
  }
327
307
  return { movingVehicles: s, stateMap: n };
328
308
  }
@@ -330,49 +310,49 @@ function M(t, e) {
330
310
  return { position: A(t, e), lineId: t.id, absoluteOffset: e };
331
311
  }
332
312
  function S(t, e) {
333
- const s = F(t.arcLengthTable, e);
334
- return { position: T(t.bezier, s) };
313
+ const s = _(t.arcLengthTable, e);
314
+ return { position: b(t.bezier, s) };
335
315
  }
336
- function X(t, e, s, n, i, c, o) {
337
- const r = s.segments[e.currentSegmentIndex], a = e.segmentDistance + n;
338
- if (a >= r.length) {
339
- const f = a - r.length, g = e.currentSegmentIndex + 1;
316
+ function X(t, e, s, n, r, o, a) {
317
+ const i = s.segments[e.currentSegmentIndex], c = e.segmentDistance + n;
318
+ if (c >= i.length) {
319
+ const f = c - i.length, g = e.currentSegmentIndex + 1;
340
320
  if (g >= s.segments.length) {
341
- if (o !== void 0 && r.type === "line") {
342
- const u = i.get(r.lineId), v = r.startOffset + a;
343
- if (v <= o) {
321
+ if (a !== void 0 && i.type === "line") {
322
+ const u = r.get(i.lineId), v = i.startOffset + c;
323
+ if (v <= a) {
344
324
  const L = M(u, v);
345
325
  return {
346
326
  axleState: { ...t, ...L },
347
- execution: { ...e, segmentDistance: a },
327
+ execution: { ...e, segmentDistance: c },
348
328
  completed: !1
349
329
  };
350
330
  }
351
- const x = M(u, o);
331
+ const x = M(u, a);
352
332
  return {
353
333
  axleState: { ...t, ...x },
354
- execution: { ...e, segmentDistance: o - r.startOffset },
334
+ execution: { ...e, segmentDistance: a - i.startOffset },
355
335
  completed: !0
356
336
  };
357
337
  }
358
- const p = r.type === "line" ? M(
359
- i.get(r.lineId),
360
- r.endOffset
338
+ const p = i.type === "line" ? M(
339
+ r.get(i.lineId),
340
+ i.endOffset
361
341
  ) : S(
362
- c.get(r.curveIndex),
363
- r.length
342
+ o.get(i.curveIndex),
343
+ i.length
364
344
  );
365
345
  return {
366
346
  axleState: { ...t, ...p },
367
- execution: { ...e, segmentDistance: r.length },
347
+ execution: { ...e, segmentDistance: i.length },
368
348
  completed: !0
369
349
  };
370
350
  }
371
351
  const d = s.segments[g], h = d.type === "line" ? M(
372
- i.get(d.lineId),
352
+ r.get(d.lineId),
373
353
  d.startOffset + f
374
354
  ) : S(
375
- c.get(d.curveIndex),
355
+ o.get(d.curveIndex),
376
356
  f
377
357
  );
378
358
  return {
@@ -384,43 +364,43 @@ function X(t, e, s, n, i, c, o) {
384
364
  completed: !1
385
365
  };
386
366
  }
387
- const l = r.type === "line" ? M(
388
- i.get(r.lineId),
389
- r.startOffset + a
367
+ const l = i.type === "line" ? M(
368
+ r.get(i.lineId),
369
+ i.startOffset + c
390
370
  ) : S(
391
- c.get(r.curveIndex),
392
- a
371
+ o.get(i.curveIndex),
372
+ c
393
373
  );
394
374
  return {
395
375
  axleState: { ...t, ...l },
396
- execution: { ...e, segmentDistance: a },
376
+ execution: { ...e, segmentDistance: c },
397
377
  completed: !1
398
378
  };
399
379
  }
400
380
  function Y(t, e, s, n) {
401
- const i = /* @__PURE__ */ new Map();
402
- for (const c of t.segments)
403
- if (c.type === "curve" && c.curveIndex !== void 0) {
404
- const o = e[c.curveIndex];
405
- if (o) {
406
- const r = s.get(o.fromLineId), a = s.get(o.toLineId);
407
- if (r && a) {
408
- const l = E(
409
- r,
410
- o.fromOffset,
411
- o.fromIsPercentage,
381
+ const r = /* @__PURE__ */ new Map();
382
+ for (const o of t.segments)
383
+ if (o.type === "curve" && o.curveIndex !== void 0) {
384
+ const a = e[o.curveIndex];
385
+ if (a) {
386
+ const i = s.get(a.fromLineId), c = s.get(a.toLineId);
387
+ if (i && c) {
388
+ const l = q(
389
+ i,
390
+ a.fromOffset,
391
+ a.fromIsPercentage,
412
392
  1,
413
393
  // Default: 100% = 1.0
414
394
  n.maxWheelbase
415
- ), f = W(
416
- a,
417
- o.toOffset,
418
- o.toIsPercentage,
395
+ ), f = E(
396
+ c,
397
+ a.toOffset,
398
+ a.toIsPercentage,
419
399
  0,
420
400
  n.maxWheelbase
421
- ), g = q(
422
- r,
423
- a,
401
+ ), g = z(
402
+ i,
403
+ c,
424
404
  n,
425
405
  !1,
426
406
  // willFlip is always false now
@@ -433,18 +413,18 @@ function Y(t, e, s, n) {
433
413
  // Already resolved to absolute
434
414
  }
435
415
  ), d = N(g);
436
- i.set(c.curveIndex, { bezier: g, arcLengthTable: d });
416
+ r.set(o.curveIndex, { bezier: g, arcLengthTable: d });
437
417
  }
438
418
  }
439
419
  }
440
- return i;
420
+ return r;
441
421
  }
442
422
  function Z(t, e, s) {
443
- const { graph: n, linesMap: i, curves: c, config: o } = s, r = i.get(e.targetLineId);
444
- if (!r) return null;
445
- const a = t.axleSpacings.reduce((u, v) => u + v, 0), f = O(r) - a;
423
+ const { graph: n, linesMap: r, curves: o, config: a } = s, i = r.get(e.targetLineId);
424
+ if (!i) return null;
425
+ const c = t.axleSpacings.reduce((u, v) => u + v, 0), f = O(i) - c;
446
426
  if (f <= 0) return null;
447
- const g = e.isPercentage ? e.targetOffset * f : Math.min(e.targetOffset, f), d = t.axles[t.axles.length - 1], h = Q(
427
+ const g = e.isPercentage ? e.targetOffset * f : Math.min(e.targetOffset, f), d = t.axles[t.axles.length - 1], h = G(
448
428
  n,
449
429
  { lineId: d.lineId, offset: d.absoluteOffset },
450
430
  e.targetLineId,
@@ -452,20 +432,20 @@ function Z(t, e, s) {
452
432
  !1
453
433
  );
454
434
  if (!h) return null;
455
- const p = Y(h, c, i, o);
435
+ const p = Y(h, o, r, a);
456
436
  return { path: h, curveDataMap: p };
457
437
  }
458
438
  function oe(t, e) {
459
- const s = t.execution, i = e.vehicleQueues.get(t.vehicle.id)?.[s.currentCommandIndex];
460
- return i && e.onCommandComplete && e.onCommandComplete({
439
+ const s = t.execution, r = e.vehicleQueues.get(t.vehicle.id)?.[s.currentCommandIndex];
440
+ return r && e.onCommandComplete && e.onCommandComplete({
461
441
  vehicleId: t.vehicle.id,
462
- command: i,
442
+ command: r,
463
443
  finalPosition: {
464
444
  lineId: t.vehicle.axles[t.vehicle.axles.length - 1].lineId,
465
445
  absoluteOffset: t.vehicle.axles[t.vehicle.axles.length - 1].absoluteOffset,
466
446
  position: t.vehicle.axles[t.vehicle.axles.length - 1].position
467
447
  },
468
- payload: i.payload
448
+ payload: r.payload
469
449
  }), {
470
450
  handled: !0,
471
451
  vehicle: { ...t.vehicle, state: "waiting" },
@@ -474,28 +454,28 @@ function oe(t, e) {
474
454
  isWaiting: !0
475
455
  };
476
456
  }
477
- function ee(t, e, s, n, i, c) {
478
- let o;
479
- const r = e[0];
480
- if (r.currentSegmentIndex < s.segments.length) {
481
- const l = s.segments[r.currentSegmentIndex];
457
+ function ee(t, e, s, n, r, o) {
458
+ let a;
459
+ const i = e[0];
460
+ if (i.currentSegmentIndex < s.segments.length) {
461
+ const l = s.segments[i.currentSegmentIndex];
482
462
  if (l.type === "line") {
483
- const f = i.get(l.lineId);
484
- f && (o = O(f));
463
+ const f = r.get(l.lineId);
464
+ f && (a = O(f));
485
465
  }
486
466
  }
487
- const a = t.map((l, f) => {
488
- const g = f === 0 ? o : void 0;
489
- return X(l, e[f], s, n, i, c, g);
467
+ const c = t.map((l, f) => {
468
+ const g = f === 0 ? a : void 0;
469
+ return X(l, e[f], s, n, r, o, g);
490
470
  });
491
471
  return {
492
- axles: a.map((l) => l.axleState),
493
- axleExecutions: a.map((l) => l.execution),
494
- arrived: a[0].completed
495
- // axles[0] = terdepan menentukan arrived
472
+ axles: c.map((l) => l.axleState),
473
+ axleExecutions: c.map((l) => l.execution),
474
+ arrived: c[c.length - 1].completed
475
+ // axles[N-1] = rearmost menentukan arrived
496
476
  };
497
477
  }
498
- class ce {
478
+ class ae {
499
479
  graph = null;
500
480
  linesMap = /* @__PURE__ */ new Map();
501
481
  curves = [];
@@ -557,11 +537,11 @@ class ce {
557
537
  if (!n) return { success: !1, error: "Name cannot be empty" };
558
538
  if (n === e) return { success: !0 };
559
539
  if (this.linesMap.has(n)) return { success: !1, error: `"${n}" already exists` };
560
- const i = this.linesMap.get(e);
561
- if (!i) return { success: !1, error: `Line "${e}" not found` };
562
- i.id = n, this.linesMap.delete(e), this.linesMap.set(n, i);
563
- for (const c of this.curves)
564
- c.fromLineId === e && (c.fromLineId = n), c.toLineId === e && (c.toLineId = n);
540
+ const r = this.linesMap.get(e);
541
+ if (!r) return { success: !1, error: `Line "${e}" not found` };
542
+ r.id = n, this.linesMap.delete(e), this.linesMap.set(n, r);
543
+ for (const o of this.curves)
544
+ o.fromLineId === e && (o.fromLineId = n), o.toLineId === e && (o.toLineId = n);
565
545
  return this.graph = I(Array.from(this.linesMap.values()), this.curves, this.config), { success: !0 };
566
546
  }
567
547
  /**
@@ -600,11 +580,11 @@ class ce {
600
580
  * @returns Initial VehiclePathState, or null if lineId does not exist
601
581
  */
602
582
  initializeVehicle(e, s, n) {
603
- const i = this.linesMap.get(e);
604
- if (!i) return null;
605
- const c = n.reduce((l, f) => l + f, 0), o = O(i), r = Math.min(s, o - c);
583
+ const r = this.linesMap.get(e);
584
+ if (!r) return null;
585
+ const o = n.reduce((l, f) => l + f, 0), a = O(r), i = Math.min(s, a - o);
606
586
  return {
607
- axles: H(e, r, n, i).map((l) => ({ lineId: l.lineId, offset: l.absoluteOffset, position: l.position })),
587
+ axles: H(e, i, n, r).map((l) => ({ lineId: l.lineId, offset: l.absoluteOffset, position: l.position })),
608
588
  axleSpacings: n
609
589
  };
610
590
  }
@@ -618,44 +598,44 @@ class ce {
618
598
  * @param targetOffset - Position on the target line
619
599
  * @param isPercentage - If true, targetOffset is 0-1 fraction; if false, absolute distance
620
600
  */
621
- preparePath(e, s, n, i = !1) {
601
+ preparePath(e, s, n, r = !1) {
622
602
  if (!this.graph) return null;
623
- const c = e.axleSpacings.reduce((h, p) => h + p, 0), o = e.axles[e.axles.length - 1], r = {
624
- lineId: o.lineId,
625
- offset: o.offset,
603
+ const o = e.axleSpacings.reduce((h, p) => h + p, 0), a = e.axles[e.axles.length - 1], i = {
604
+ lineId: a.lineId,
605
+ offset: a.offset,
626
606
  axles: e.axles.map((h) => ({
627
607
  lineId: h.lineId,
628
608
  position: h.position,
629
609
  absoluteOffset: h.offset
630
610
  })),
631
611
  axleSpacings: e.axleSpacings
632
- }, a = Z(r, {
612
+ }, c = Z(i, {
633
613
  targetLineId: s,
634
614
  targetOffset: n,
635
- isPercentage: i
615
+ isPercentage: r
636
616
  }, {
637
617
  graph: this.graph,
638
618
  linesMap: this.linesMap,
639
619
  curves: this.curves,
640
620
  config: this.config
641
621
  });
642
- if (!a) return null;
622
+ if (!c) return null;
643
623
  let l = n;
644
624
  const f = this.linesMap.get(s);
645
625
  if (f) {
646
- const h = Math.max(0, O(f) - c);
647
- l = i ? n * h : Math.min(n, h);
626
+ const h = Math.max(0, O(f) - o);
627
+ l = r ? n * h : Math.min(n, h);
648
628
  }
649
629
  let g = 0;
650
630
  const d = [
651
- { segmentIndex: 0, segmentDistance: c }
631
+ { segmentIndex: 0, segmentDistance: o }
652
632
  // axles[0] = front
653
633
  ];
654
634
  for (let h = 0; h < e.axleSpacings.length; h++)
655
- g += e.axleSpacings[h], d.push({ segmentIndex: 0, segmentDistance: c - g });
635
+ g += e.axleSpacings[h], d.push({ segmentIndex: 0, segmentDistance: o - g });
656
636
  return {
657
- path: a.path,
658
- curveDataMap: a.curveDataMap,
637
+ path: c.path,
638
+ curveDataMap: c.curveDataMap,
659
639
  axleExecutions: d,
660
640
  targetLineId: s,
661
641
  targetOffset: l
@@ -672,60 +652,60 @@ class ce {
672
652
  * @param distance - Distance to advance this tick (speed × deltaTime)
673
653
  */
674
654
  moveVehicle(e, s, n) {
675
- const i = e.axles.map((r) => ({
676
- lineId: r.lineId,
677
- position: r.position,
678
- absoluteOffset: r.offset
679
- })), c = s.axleExecutions.map((r) => ({
680
- currentSegmentIndex: r.segmentIndex,
681
- segmentDistance: r.segmentDistance
682
- })), o = ee(i, c, s.path, n, this.linesMap, s.curveDataMap);
655
+ const r = e.axles.map((i) => ({
656
+ lineId: i.lineId,
657
+ position: i.position,
658
+ absoluteOffset: i.offset
659
+ })), o = s.axleExecutions.map((i) => ({
660
+ currentSegmentIndex: i.segmentIndex,
661
+ segmentDistance: i.segmentDistance
662
+ })), a = ee(r, o, s.path, n, this.linesMap, s.curveDataMap);
683
663
  return {
684
664
  state: {
685
- axles: o.axles.map((r) => ({ lineId: r.lineId, offset: r.absoluteOffset, position: r.position })),
665
+ axles: a.axles.map((i) => ({ lineId: i.lineId, offset: i.absoluteOffset, position: i.position })),
686
666
  axleSpacings: e.axleSpacings
687
667
  },
688
668
  execution: {
689
669
  ...s,
690
- axleExecutions: o.axleExecutions.map((r) => ({
691
- segmentIndex: r.currentSegmentIndex,
692
- segmentDistance: r.segmentDistance
670
+ axleExecutions: a.axleExecutions.map((i) => ({
671
+ segmentIndex: i.currentSegmentIndex,
672
+ segmentDistance: i.segmentDistance
693
673
  }))
694
674
  },
695
- arrived: o.arrived
675
+ arrived: a.arrived
696
676
  };
697
677
  }
698
678
  }
699
679
  export {
700
680
  w as A,
701
681
  Z as B,
702
- E as C,
703
- W as D,
682
+ q as C,
683
+ E as D,
704
684
  X as E,
705
- ce as P,
706
- _ as a,
685
+ ae as P,
686
+ R as a,
707
687
  N as b,
708
688
  I as c,
709
- G as d,
710
- ie as e,
689
+ F as d,
690
+ re as e,
711
691
  H as f,
712
692
  S as g,
713
693
  M as h,
714
694
  k as i,
715
- q as j,
695
+ z as j,
716
696
  U as k,
717
697
  y as l,
718
- F as m,
719
- Q as n,
698
+ _ as m,
699
+ G as n,
720
700
  se as o,
721
- R as p,
701
+ Q as p,
722
702
  O as q,
723
- T as r,
703
+ b as r,
724
704
  K as s,
725
705
  V as t,
726
706
  A as u,
727
707
  oe as v,
728
- re as w,
708
+ ie as w,
729
709
  J as x,
730
710
  ne as y,
731
711
  ee as z
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DfPg-M5u.cjs");exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;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.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-BUYdltrL.cjs");exports.PathEngine=e.PathEngine;exports.arcLengthToSegmentPosition=e.arcLengthToSegmentPosition;exports.buildArcLengthTable=e.buildArcLengthTable;exports.buildGraph=e.buildGraph;exports.calculateBezierArcLength=e.calculateBezierArcLength;exports.calculateFrontAxlePosition=e.calculateFrontAxlePosition;exports.calculateInitialAxlePositions=e.calculateInitialAxlePositions;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.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;
@@ -1,4 +1,4 @@
1
- import { P as t, a as i, b as s, c as n, d as o, e as l, f as r, g as c, h as g, j as h, k as P, l as u, m as L, n as f, o as m, p as v, q as A, r as d, s as O, t as z, u as p, v as x, w as B, x as C, z as T, A as b, B as F, C as V, D as E, E as I } from "./index-D8o0W80x.js";
1
+ import { P as t, a as i, b as s, c as n, d as o, e as l, f as r, g as c, h as g, j as h, k as P, l as u, m as L, n as f, o as m, p as v, q as A, r as d, s as O, t as z, u as p, v as x, w as B, x as C, z as T, A as b, B as F, C as V, D as E, E as I } from "./index-D-HctiIv.js";
2
2
  export {
3
3
  t as PathEngine,
4
4
  i as arcLengthToSegmentPosition,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vehicle-path2",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
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 +0,0 @@
1
- "use strict";function L(t,e){const s=e.x-t.x,n=e.y-t.y;return Math.sqrt(s*s+n*n)}function D(t,e){const s=e.x-t.x,n=e.y-t.y,i=Math.sqrt(s*s+n*n);return i===0?{x:0,y:0}:{x:s/i,y:n/i}}function W(t,e){return e*(t==="proportional-40"?.4:.5522)}function V(t,e,s,n=!1,i){const{maxWheelbase:c,tangentMode:o}=s;let r;i?.fromOffset!==void 0?r=b(t,i.fromOffset,i.fromIsPercentage??!1):r=t.end;let a;i?.toOffset!==void 0?a=b(e,i.toOffset,i.toIsPercentage??!1):a=e.start;const l=D(t.start,t.end),f=n?{x:r.x-l.x*c,y:r.y-l.y*c}:r,g=D(t.start,t.end),d=D(e.start,e.end),h=L(f,a),p=W(o,h),u=n?{x:f.x-g.x*p,y:f.y-g.y*p}:{x:f.x+g.x*p,y:f.y+g.y*p},v={x:a.x-d.x*p,y:a.y-d.y*p};return{p0:f,p1:u,p2:v,p3:a}}function F(t,e){return{x:t.start.x+(t.end.x-t.start.x)*e,y:t.start.y+(t.end.y-t.start.y)*e}}function b(t,e,s){const n=L(t.start,t.end);let i;return s?i=e:i=n>0?e/n:0,i=Math.max(0,Math.min(1,i)),F(t,i)}function T(t,e){const{p0:s,p1:n,p2:i,p3:c}=t,o=1-e,r=o*o,a=r*o,l=e*e,f=l*e;return{x:a*s.x+3*r*e*n.x+3*o*l*i.x+f*c.x,y:a*s.y+3*r*e*n.y+3*o*l*i.y+f*c.y}}function ee(t,e,s=10){return L(t,e)<=s}function N(t,e=100){const s=[{t:0,distance:0}];let n=t.p0,i=0;for(let c=1;c<=e;c++){const o=c/e,r=T(t,o);i+=L(n,r),s.push({t:o,distance:i}),n=r}return s}function $(t,e){if(e<=0)return 0;const s=t[t.length-1].distance;if(e>=s)return 1;let n=0,i=t.length-1;for(;n<i-1;){const f=Math.floor((n+i)/2);t[f].distance<e?n=f:i=f}const c=t[n].distance,o=t[i].distance,r=t[n].t,a=t[i].t;if(o===c)return r;const l=(e-c)/(o-c);return r+l*(a-r)}function te(t){return t[t.length-1].distance}function j(t,e=100){let s=0,n=t.p0;for(let i=1;i<=e;i++){const c=i/e,o=T(t,c);s+=L(n,o),n=o}return s}function z(t,e,s,n,i){const c=L(t.start,t.end),o=c-i;if(o<=0)return c;let r;if(e===void 0)r=n;else if(s)r=e;else{const a=Math.max(0,Math.min(e,o));return i+a}return i+r*o}function B(t,e,s,n,i){const o=L(t.start,t.end)-i;if(o<=0)return 0;let r;if(e===void 0)r=n;else if(s)r=e;else return Math.max(0,Math.min(e,o));return r*o}function x(t,e,s){const n=new Map,i=new Map,c=new Map;for(const o of t)i.set(o.id,o),c.set(o.id,L(o.start,o.end)),n.set(o.id,[]);for(let o=0;o<e.length;o++){const r=e[o],a=i.get(r.fromLineId),l=i.get(r.toLineId);if(!a||!l)continue;const f=z(a,r.fromOffset,r.fromIsPercentage,1,s.maxWheelbase),g=B(l,r.toOffset,r.toIsPercentage,0,s.maxWheelbase),d=V(a,l,s,!1,{fromOffset:f,fromIsPercentage:!1,toOffset:g,toIsPercentage:!1}),h=j(d),p={curveIndex:o,fromLineId:r.fromLineId,toLineId:r.toLineId,fromOffset:f,toOffset:g,curveLength:h};n.get(r.fromLineId).push(p)}return{adjacency:n,lines:i,lineLengths:c}}function E(t,e){return t.curveCount!==e.curveCount?t.curveCount-e.curveCount:t.totalDistance-e.totalDistance}function K(t,e,s,n,i=!1){const{adjacency:c,lines:o,lineLengths:r}=t;if(!o.get(s))return null;const l=r.get(s),f=i?n/100*l:n,g=[],d=new Map,h=(u,v)=>`${u}:${Math.round(v)}`;if(e.lineId===s&&f>=e.offset){const u=f-e.offset;return{segments:[{type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:f,length:u}],totalDistance:u,curveCount:0}}const p=c.get(e.lineId)||[];for(const u of p){if(u.fromOffset<e.offset)continue;const v=u.fromOffset-e.offset,I=v+u.curveLength,M={type:"line",lineId:e.lineId,startOffset:e.offset,endOffset:u.fromOffset,length:v},m={type:"curve",curveIndex:u.curveIndex,startOffset:0,endOffset:u.curveLength,length:u.curveLength};g.push({lineId:u.toLineId,entryOffset:u.toOffset,totalDistance:I,curveCount:1,path:[M,m]})}for(g.sort(E);g.length>0;){const u=g.shift(),v=h(u.lineId,u.entryOffset),I=d.get(v);if(I!==void 0&&(I.curveCount<u.curveCount||I.curveCount===u.curveCount&&I.distance<=u.totalDistance))continue;if(d.set(v,{curveCount:u.curveCount,distance:u.totalDistance}),u.lineId===s){const m=Math.abs(f-u.entryOffset);if(f>=u.entryOffset){const P={type:"line",lineId:s,startOffset:u.entryOffset,endOffset:f,length:m};return{segments:[...u.path,P],totalDistance:u.totalDistance+m,curveCount:u.curveCount}}}const M=c.get(u.lineId)||[];for(const m of M){if(m.fromOffset<u.entryOffset)continue;const P=m.fromOffset-u.entryOffset,q=u.totalDistance+P+m.curveLength,w=u.curveCount+1,X=h(m.toLineId,m.toOffset),C=d.get(X);if(C!==void 0&&(C.curveCount<w||C.curveCount===w&&C.distance<=q))continue;const Y={type:"line",lineId:u.lineId,startOffset:u.entryOffset,endOffset:m.fromOffset,length:P},Z={type:"curve",curveIndex:m.curveIndex,startOffset:0,endOffset:m.curveLength,length:m.curveLength};g.push({lineId:m.toLineId,entryOffset:m.toOffset,totalDistance:q,curveCount:w,path:[...u.path,Y,Z]})}g.sort(E)}return null}function S(t,e){const s=Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2)),n=s>0?e/s:0;return{x:t.start.x+(t.end.x-t.start.x)*Math.min(1,Math.max(0,n)),y:t.start.y+(t.end.y-t.start.y)*Math.min(1,Math.max(0,n))}}function O(t){return Math.sqrt(Math.pow(t.end.x-t.start.x,2)+Math.pow(t.end.y-t.start.y,2))}function k(t,e,s){let n=0;for(let i=0;i<e;i++)n+=t.segments[i].length;return n+=s,n}function G(t,e){let s=0;for(let n=0;n<t.segments.length;n++){const i=t.segments[n],c=s+i.length;if(e<c)return{segmentIndex:n,segmentDistance:e-s};if(e===c)return n+1<t.segments.length?{segmentIndex:n+1,segmentDistance:0}:{segmentIndex:n,segmentDistance:i.length};s+=i.length}return null}function ne(t,e,s,n){const c=k(t,e,s)+n;return G(t,c)}function Q(t,e,s,n){const i=O(n),c=s.length+1,o=new Array(c);o[c-1]={lineId:t,absoluteOffset:e,position:S(n,e)};let r=e;for(let a=c-2;a>=0;a--)r=Math.min(r+s[a],i),o[a]={lineId:t,absoluteOffset:r,position:S(n,r)};return o}function R(t,e){return{...t,state:"idle"}}function _(t){return{vehicle:t,execution:null}}function se(t,e){const s=[],n=new Map;for(const i of t){if(!e.get(i.lineId))continue;const o=R(i);s.push(o);const r=_(o);n.set(i.id,r)}return{movingVehicles:s,stateMap:n}}function y(t,e){return{position:S(t,e),lineId:t.id,absoluteOffset:e}}function A(t,e){const s=$(t.arcLengthTable,e);return{position:T(t.bezier,s)}}function H(t,e,s,n,i,c,o){const r=s.segments[e.currentSegmentIndex],a=e.segmentDistance+n;if(a>=r.length){const f=a-r.length,g=e.currentSegmentIndex+1;if(g>=s.segments.length){if(o!==void 0&&r.type==="line"){const u=i.get(r.lineId),v=r.startOffset+a;if(v<=o){const M=y(u,v);return{axleState:{...t,...M},execution:{...e,segmentDistance:a},completed:!1}}const I=y(u,o);return{axleState:{...t,...I},execution:{...e,segmentDistance:o-r.startOffset},completed:!0}}const p=r.type==="line"?y(i.get(r.lineId),r.endOffset):A(c.get(r.curveIndex),r.length);return{axleState:{...t,...p},execution:{...e,segmentDistance:r.length},completed:!0}}const d=s.segments[g],h=d.type==="line"?y(i.get(d.lineId),d.startOffset+f):A(c.get(d.curveIndex),f);return{axleState:{...t,...h},execution:{currentSegmentIndex:g,segmentDistance:f},completed:!1}}const l=r.type==="line"?y(i.get(r.lineId),r.startOffset+a):A(c.get(r.curveIndex),a);return{axleState:{...t,...l},execution:{...e,segmentDistance:a},completed:!1}}function ie(t,e,s,n){const i=new Map;for(const c of t.segments)if(c.type==="curve"&&c.curveIndex!==void 0){const o=e[c.curveIndex];if(o){const r=s.get(o.fromLineId),a=s.get(o.toLineId);if(r&&a){const l=z(r,o.fromOffset,o.fromIsPercentage,1,n.maxWheelbase),f=B(a,o.toOffset,o.toIsPercentage,0,n.maxWheelbase),g=V(r,a,n,!1,{fromOffset:l,fromIsPercentage:!1,toOffset:f,toIsPercentage:!1}),d=N(g);i.set(c.curveIndex,{bezier:g,arcLengthTable:d})}}}return i}function J(t,e,s){const{graph:n,linesMap:i,curves:c,config:o}=s,r=i.get(e.targetLineId);if(!r)return null;const a=t.axleSpacings.reduce((u,v)=>u+v,0),f=O(r)-a;if(f<=0)return null;const g=e.isPercentage?e.targetOffset*f:Math.min(e.targetOffset,f),d=t.axles[t.axles.length-1],h=K(n,{lineId:d.lineId,offset:d.absoluteOffset},e.targetLineId,g,!1);if(!h)return null;const p=ie(h,c,i,o);return{path:h,curveDataMap:p}}function re(t,e){const s=t.execution,i=e.vehicleQueues.get(t.vehicle.id)?.[s.currentCommandIndex];return i&&e.onCommandComplete&&e.onCommandComplete({vehicleId:t.vehicle.id,command:i,finalPosition:{lineId:t.vehicle.axles[t.vehicle.axles.length-1].lineId,absoluteOffset:t.vehicle.axles[t.vehicle.axles.length-1].absoluteOffset,position:t.vehicle.axles[t.vehicle.axles.length-1].position},payload:i.payload}),{handled:!0,vehicle:{...t.vehicle,state:"waiting"},newExecution:s,isWaiting:!0}}function U(t,e,s,n,i,c){let o;const r=e[0];if(r.currentSegmentIndex<s.segments.length){const l=s.segments[r.currentSegmentIndex];if(l.type==="line"){const f=i.get(l.lineId);f&&(o=O(f))}}const a=t.map((l,f)=>{const g=f===0?o:void 0;return H(l,e[f],s,n,i,c,g)});return{axles:a.map(l=>l.axleState),axleExecutions:a.map(l=>l.execution),arrived:a[0].completed}}class oe{graph=null;linesMap=new Map;curves=[];config;constructor(e){this.config={maxWheelbase:e.maxWheelbase,tangentMode:e.tangentMode}}get movementConfig(){return this.config}get lines(){return Array.from(this.linesMap.values())}getCurves(){return this.curves}setScene(e,s){this.linesMap.clear();for(const n of e)this.linesMap.set(n.id,n);this.curves=s,this.graph=x(e,s,this.config)}addLine(e){return this.linesMap.has(e.id)?!1:(this.linesMap.set(e.id,e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}updateLine(e,s){const n=this.linesMap.get(e);return n?(s.start&&(n.start=s.start),s.end&&(n.end=s.end),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}updateLineEndpoint(e,s,n){return this.updateLine(e,{[s]:n})}renameLine(e,s){const n=s.trim();if(!n)return{success:!1,error:"Name cannot be empty"};if(n===e)return{success:!0};if(this.linesMap.has(n))return{success:!1,error:`"${n}" already exists`};const i=this.linesMap.get(e);if(!i)return{success:!1,error:`Line "${e}" not found`};i.id=n,this.linesMap.delete(e),this.linesMap.set(n,i);for(const c of this.curves)c.fromLineId===e&&(c.fromLineId=n),c.toLineId===e&&(c.toLineId=n);return this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),{success:!0}}removeLine(e){return this.linesMap.has(e)?(this.linesMap.delete(e),this.curves=this.curves.filter(s=>s.fromLineId!==e&&s.toLineId!==e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0):!1}addCurve(e){this.curves.push(e),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config)}updateCurve(e,s){return e<0||e>=this.curves.length?!1:(this.curves[e]={...this.curves[e],...s},this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}removeCurve(e){return e<0||e>=this.curves.length?!1:(this.curves.splice(e,1),this.graph=x(Array.from(this.linesMap.values()),this.curves,this.config),!0)}initializeVehicle(e,s,n){const i=this.linesMap.get(e);if(!i)return null;const c=n.reduce((l,f)=>l+f,0),o=O(i),r=Math.min(s,o-c);return{axles:Q(e,r,n,i).map(l=>({lineId:l.lineId,offset:l.absoluteOffset,position:l.position})),axleSpacings:n}}preparePath(e,s,n,i=!1){if(!this.graph)return null;const c=e.axleSpacings.reduce((h,p)=>h+p,0),o=e.axles[e.axles.length-1],r={lineId:o.lineId,offset:o.offset,axles:e.axles.map(h=>({lineId:h.lineId,position:h.position,absoluteOffset:h.offset})),axleSpacings:e.axleSpacings},a=J(r,{targetLineId:s,targetOffset:n,isPercentage:i},{graph:this.graph,linesMap:this.linesMap,curves:this.curves,config:this.config});if(!a)return null;let l=n;const f=this.linesMap.get(s);if(f){const h=Math.max(0,O(f)-c);l=i?n*h:Math.min(n,h)}let g=0;const d=[{segmentIndex:0,segmentDistance:c}];for(let h=0;h<e.axleSpacings.length;h++)g+=e.axleSpacings[h],d.push({segmentIndex:0,segmentDistance:c-g});return{path:a.path,curveDataMap:a.curveDataMap,axleExecutions:d,targetLineId:s,targetOffset:l}}moveVehicle(e,s,n){const i=e.axles.map(r=>({lineId:r.lineId,position:r.position,absoluteOffset:r.offset})),c=s.axleExecutions.map(r=>({currentSegmentIndex:r.segmentIndex,segmentDistance:r.segmentDistance})),o=U(i,c,s.path,n,this.linesMap,s.curveDataMap);return{state:{axles:o.axles.map(r=>({lineId:r.lineId,offset:r.absoluteOffset,position:r.position})),axleSpacings:e.axleSpacings},execution:{...s,axleExecutions:o.axleExecutions.map(r=>({segmentIndex:r.currentSegmentIndex,segmentDistance:r.segmentDistance}))},arrived:o.arrived}}}exports.PathEngine=oe;exports.arcLengthToSegmentPosition=G;exports.buildArcLengthTable=N;exports.buildGraph=x;exports.calculateBezierArcLength=j;exports.calculateFrontAxlePosition=ne;exports.calculateInitialAxlePositions=Q;exports.calculatePositionOnCurve=A;exports.calculatePositionOnLine=y;exports.calculateTangentLength=W;exports.createBezierCurve=V;exports.createInitialMovementState=_;exports.distance=L;exports.distanceToT=$;exports.findPath=K;exports.getArcLength=te;exports.getCumulativeArcLength=k;exports.getLineLength=O;exports.getPointOnBezier=T;exports.getPointOnLine=F;exports.getPointOnLineByOffset=b;exports.getPositionFromOffset=S;exports.handleArrival=re;exports.initializeAllVehicles=se;exports.initializeMovingVehicle=R;exports.isPointNearPoint=ee;exports.moveVehicle=U;exports.normalize=D;exports.prepareCommandPath=J;exports.resolveFromLineOffset=z;exports.resolveToLineOffset=B;exports.updateAxlePosition=H;