vehicle-path2 1.0.15 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/algorithms/pathFinding.d.ts +2 -2
- package/dist/core/algorithms/vehicleMovement.d.ts +24 -19
- package/dist/core/engine.d.ts +16 -18
- package/dist/core/index.d.ts +1 -1
- package/dist/core/types/api.d.ts +9 -0
- package/dist/core/types/movement.d.ts +2 -3
- package/dist/core/types/vehicle.d.ts +4 -2
- package/dist/core.cjs +1 -1
- package/dist/core.js +32 -240
- package/dist/index.d.ts +2 -33
- package/dist/utils/event-emitter.d.ts +4 -6
- package/dist/vehicle-path.cjs +1 -1
- package/dist/vehicle-path.js +729 -62
- package/package.json +1 -21
- package/dist/animation-loop-bZEm2pMN.js +0 -37
- package/dist/animation-loop-fC2LjxCd.cjs +0 -1
- package/dist/react/dsl-hooks/useInitialMovement.d.ts +0 -24
- package/dist/react/dsl-hooks/useMovementSequence.d.ts +0 -27
- package/dist/react/dsl-hooks/useSceneDefinition.d.ts +0 -22
- package/dist/react/hooks/useAnimation.d.ts +0 -47
- package/dist/react/hooks/useMovementQueue.d.ts +0 -53
- package/dist/react/hooks/useScene.d.ts +0 -78
- package/dist/react/hooks/useVehicleSimulation.d.ts +0 -128
- package/dist/react/hooks/useVehicles.d.ts +0 -55
- package/dist/react/index.d.ts +0 -48
- package/dist/react/providers/useVehicleEvents.d.ts +0 -78
- package/dist/react.cjs +0 -1
- package/dist/react.js +0 -18
- package/dist/useVehicleEvents-Bp4v5sln.cjs +0 -3
- package/dist/useVehicleEvents-C0uaNzNP.js +0 -940
- package/dist/utils/animation-loop.d.ts +0 -105
- package/dist/utils/dsl-parser.d.ts +0 -151
- package/dist/utils/index.d.ts +0 -15
- package/dist/utils/type-converters.d.ts +0 -40
- package/dist/utils/vehicle-helpers.d.ts +0 -8
- package/dist/utils.cjs +0 -1
- package/dist/utils.js +0 -17
- package/dist/vehicle-helpers-DQ-OThWd.js +0 -275
- package/dist/vehicle-helpers-DrCYMVs4.cjs +0 -7
- package/dist/vehicleMovement-BiYBE_2a.cjs +0 -1
- package/dist/vehicleMovement-TkCt4q_a.js +0 -524
|
@@ -41,7 +41,7 @@ export declare function calculateBezierArcLength(bezier: BezierCurve, segments?:
|
|
|
41
41
|
*
|
|
42
42
|
* Effective range: [wheelbase, lineLength]
|
|
43
43
|
*/
|
|
44
|
-
export declare function resolveFromLineOffset(line: Line, offset: number | undefined, isPercentage: boolean | undefined, defaultPercentage: number,
|
|
44
|
+
export declare function resolveFromLineOffset(line: Line, offset: number | undefined, isPercentage: boolean | undefined, defaultPercentage: number, maxWheelbase: number): number;
|
|
45
45
|
/**
|
|
46
46
|
* Resolve offset untuk TO line (garis tujuan kurva)
|
|
47
47
|
* - 0% → 0 (awal garis)
|
|
@@ -49,7 +49,7 @@ export declare function resolveFromLineOffset(line: Line, offset: number | undef
|
|
|
49
49
|
*
|
|
50
50
|
* Effective range: [0, lineLength - wheelbase]
|
|
51
51
|
*/
|
|
52
|
-
export declare function resolveToLineOffset(line: Line, offset: number | undefined, isPercentage: boolean | undefined, defaultPercentage: 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
|
*/
|
|
@@ -55,6 +55,16 @@ export declare function calculateFrontAxlePosition(path: PathResult, rearSegment
|
|
|
55
55
|
segmentIndex: number;
|
|
56
56
|
segmentDistance: number;
|
|
57
57
|
} | null;
|
|
58
|
+
/**
|
|
59
|
+
* Hitung posisi awal semua axle dari posisi rearmost axle.
|
|
60
|
+
*
|
|
61
|
+
* @param lineId - Line ID tempat vehicle diinisialisasi
|
|
62
|
+
* @param rearOffset - Absolute offset axle paling belakang (axles[N-1])
|
|
63
|
+
* @param axleSpacings - Jarak antar axle berurutan (N-1 nilai untuk N axle)
|
|
64
|
+
* @param line - Line object untuk kalkulasi posisi
|
|
65
|
+
* @returns Array AxleState, axles[0] = terdepan, axles[N-1] = paling belakang
|
|
66
|
+
*/
|
|
67
|
+
export declare function calculateInitialAxlePositions(lineId: string, rearOffset: number, axleSpacings: number[], line: Line): AxleState[];
|
|
58
68
|
/**
|
|
59
69
|
* Calculate initial front axle position from rear position
|
|
60
70
|
*
|
|
@@ -173,26 +183,21 @@ export interface SegmentCompletionResult {
|
|
|
173
183
|
export declare function handleArrival(state: VehicleMovementState, ctx: SegmentCompletionContext): SegmentCompletionResult;
|
|
174
184
|
export type { VehicleMovementState as SegmentVehicleState };
|
|
175
185
|
/**
|
|
176
|
-
* Advance
|
|
186
|
+
* Advance semua axle vehicle oleh `distance` sepanjang path.
|
|
177
187
|
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* reached the end of the path (arrived).
|
|
188
|
+
* Ini adalah low-level tick primitive. Update semua axle menggunakan
|
|
189
|
+
* arc-length parameterization. Arrival = axles[0] (terdepan) mencapai ujung path.
|
|
181
190
|
*
|
|
182
|
-
* @param
|
|
183
|
-
* @param
|
|
184
|
-
* @param
|
|
185
|
-
* @param
|
|
186
|
-
* @param
|
|
187
|
-
* @param
|
|
188
|
-
* @
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
rear: AxleState;
|
|
194
|
-
front: AxleState;
|
|
195
|
-
rearExecution: AxleExecutionState;
|
|
196
|
-
frontExecution: AxleExecutionState;
|
|
191
|
+
* @param axleStates - Array AxleState saat ini, axles[0] = terdepan
|
|
192
|
+
* @param axleExecutions - Array AxleExecutionState sesuai urutan axleStates
|
|
193
|
+
* @param path - Path yang diikuti
|
|
194
|
+
* @param distance - Jarak yang dimaju per tick
|
|
195
|
+
* @param linesMap - Map line ID ke Line object
|
|
196
|
+
* @param curveDataMap - Pre-built bezier curve data
|
|
197
|
+
* @returns Updated axles, axleExecutions, dan arrival flag
|
|
198
|
+
*/
|
|
199
|
+
export declare function moveVehicle(axleStates: AxleState[], axleExecutions: AxleExecutionState[], path: PathResult, distance: number, linesMap: Map<string, Line>, curveDataMap: Map<number, CurveData>): {
|
|
200
|
+
axles: AxleState[];
|
|
201
|
+
axleExecutions: AxleExecutionState[];
|
|
197
202
|
arrived: boolean;
|
|
198
203
|
};
|
package/dist/core/engine.d.ts
CHANGED
|
@@ -30,24 +30,21 @@ import type { MovementConfig, CurveData } from './types/movement';
|
|
|
30
30
|
import type { PathResult } from './algorithms/pathFinding';
|
|
31
31
|
import type { TangentMode } from './types/config';
|
|
32
32
|
export interface PathEngineConfig {
|
|
33
|
-
|
|
33
|
+
maxWheelbase: number;
|
|
34
34
|
tangentMode: TangentMode;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
37
|
+
* Multi-axle position state for use with PathEngine.
|
|
38
|
+
* axles[0] = terdepan, axles[N-1] = paling belakang.
|
|
39
39
|
*/
|
|
40
40
|
export interface VehiclePathState {
|
|
41
|
-
|
|
41
|
+
axles: Array<{
|
|
42
42
|
lineId: string;
|
|
43
43
|
offset: number;
|
|
44
44
|
position: Point;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
offset: number;
|
|
49
|
-
position: Point;
|
|
50
|
-
};
|
|
45
|
+
}>;
|
|
46
|
+
/** N-1 jarak arc-length antar axle berurutan */
|
|
47
|
+
axleSpacings: number[];
|
|
51
48
|
}
|
|
52
49
|
/**
|
|
53
50
|
* Active path execution state for a vehicle in motion.
|
|
@@ -56,11 +53,11 @@ export interface VehiclePathState {
|
|
|
56
53
|
export interface PathExecution {
|
|
57
54
|
path: PathResult;
|
|
58
55
|
curveDataMap: Map<number, CurveData>;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
/** Execution state per axle, sesuai urutan VehiclePathState.axles */
|
|
57
|
+
axleExecutions: Array<{
|
|
58
|
+
segmentIndex: number;
|
|
59
|
+
segmentDistance: number;
|
|
60
|
+
}>;
|
|
64
61
|
targetLineId: string;
|
|
65
62
|
targetOffset: number;
|
|
66
63
|
}
|
|
@@ -126,13 +123,14 @@ export declare class PathEngine {
|
|
|
126
123
|
*/
|
|
127
124
|
removeCurve(index: number): boolean;
|
|
128
125
|
/**
|
|
129
|
-
* Initialize a vehicle's
|
|
126
|
+
* Initialize a vehicle's N-axle position on a line.
|
|
130
127
|
*
|
|
131
128
|
* @param lineId - The line to place the vehicle on
|
|
132
|
-
* @param
|
|
129
|
+
* @param rearOffset - Absolute distance offset untuk axle paling belakang
|
|
130
|
+
* @param axleSpacings - Jarak antar axle berurutan (N-1 nilai untuk N axle)
|
|
133
131
|
* @returns Initial VehiclePathState, or null if lineId does not exist
|
|
134
132
|
*/
|
|
135
|
-
initializeVehicle(lineId: string,
|
|
133
|
+
initializeVehicle(lineId: string, rearOffset: number, axleSpacings: number[]): VehiclePathState | null;
|
|
136
134
|
/**
|
|
137
135
|
* Prepare a path from the vehicle's current position to a target.
|
|
138
136
|
*
|
package/dist/core/index.d.ts
CHANGED
|
@@ -16,6 +16,6 @@ export type { CurveData, AxleExecutionState, PathExecutionState, VehicleMovement
|
|
|
16
16
|
export type { TangentMode } from './types/config';
|
|
17
17
|
export type { CoordinateInput, SceneLineInput, SceneConnectionInput, SceneConfig, VehicleInput, VehicleUpdateInput, ConnectionUpdateInput, GotoCommandInput } from './types/api';
|
|
18
18
|
export { buildGraph, findPath, calculateBezierArcLength, resolveFromLineOffset, resolveToLineOffset, type Graph, type GraphEdge, type PathSegment, type PathResult, type VehiclePosition } from './algorithms/pathFinding';
|
|
19
|
-
export { initializeMovingVehicle, createInitialMovementState, initializeAllVehicles,
|
|
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';
|
package/dist/core/types/api.d.ts
CHANGED
|
@@ -70,6 +70,15 @@ export interface VehicleInput {
|
|
|
70
70
|
lineId: string;
|
|
71
71
|
position?: number;
|
|
72
72
|
isPercentage?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Jarak arc-length antar axle berurutan.
|
|
75
|
+
* axleSpacings[i] = jarak antara axles[i] dan axles[i+1].
|
|
76
|
+
* axles[0] = terdepan, axles[N-1] = paling belakang.
|
|
77
|
+
* Contoh truk biasa: [30] → 2 axle, jarak 30px
|
|
78
|
+
* Contoh truck+trailer: [20, 45] → 3 axle
|
|
79
|
+
* Total panjang vehicle = sum(axleSpacings) harus ≤ maxWheelbase
|
|
80
|
+
*/
|
|
81
|
+
axleSpacings: number[];
|
|
73
82
|
}
|
|
74
83
|
/**
|
|
75
84
|
* Vehicle update input for updateVehicle()
|
|
@@ -27,8 +27,7 @@ export interface PathExecutionState {
|
|
|
27
27
|
path: import('../algorithms/pathFinding').PathResult;
|
|
28
28
|
curveDataMap: Map<number, CurveData>;
|
|
29
29
|
currentCommandIndex: number;
|
|
30
|
-
|
|
31
|
-
front: AxleExecutionState;
|
|
30
|
+
axles: AxleExecutionState[];
|
|
32
31
|
}
|
|
33
32
|
/**
|
|
34
33
|
* Movement state container for a vehicle
|
|
@@ -41,7 +40,7 @@ export interface VehicleMovementState {
|
|
|
41
40
|
* Configuration for vehicle movement
|
|
42
41
|
*/
|
|
43
42
|
export interface MovementConfig {
|
|
44
|
-
|
|
43
|
+
maxWheelbase: number;
|
|
45
44
|
tangentMode: TangentMode;
|
|
46
45
|
}
|
|
47
46
|
/**
|
|
@@ -14,6 +14,8 @@ export interface VehicleStart {
|
|
|
14
14
|
lineId: string;
|
|
15
15
|
offset: number;
|
|
16
16
|
isPercentage: boolean;
|
|
17
|
+
/** Optional: defaults to [maxWheelbase] jika tidak disediakan */
|
|
18
|
+
axleSpacings?: number[];
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* State for a single axle (Front or Rear)
|
|
@@ -32,8 +34,8 @@ export interface Vehicle {
|
|
|
32
34
|
offset: number;
|
|
33
35
|
isPercentage: boolean;
|
|
34
36
|
state: VehicleState;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
axles: AxleState[];
|
|
38
|
+
axleSpacings: number[];
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
39
41
|
* Command to move a vehicle to a target position
|
package/dist/core.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./vehicle-path.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.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;
|
package/dist/core.js
CHANGED
|
@@ -1,243 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as O, b as P, d as x, e as D, g as y, h as S, D as C, i as E, j as w, k as z, l as T, m as B, n as V, o as F, q as N, r as $, s as j, u as k, v as q, w as G, E as H, y as J, A as K, B as Q, C as R } from "./vehicleMovement-TkCt4q_a.js";
|
|
3
|
-
class I {
|
|
4
|
-
graph = null;
|
|
5
|
-
linesMap = /* @__PURE__ */ new Map();
|
|
6
|
-
curves = [];
|
|
7
|
-
config;
|
|
8
|
-
constructor(e) {
|
|
9
|
-
this.config = {
|
|
10
|
-
wheelbase: e.wheelbase,
|
|
11
|
-
tangentMode: e.tangentMode
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Accessors
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
get movementConfig() {
|
|
18
|
-
return this.config;
|
|
19
|
-
}
|
|
20
|
-
get lines() {
|
|
21
|
-
return Array.from(this.linesMap.values());
|
|
22
|
-
}
|
|
23
|
-
getCurves() {
|
|
24
|
-
return this.curves;
|
|
25
|
-
}
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
// Scene management
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
/**
|
|
30
|
-
* Replace the entire scene and rebuild the graph.
|
|
31
|
-
*/
|
|
32
|
-
setScene(e, t) {
|
|
33
|
-
this.linesMap.clear();
|
|
34
|
-
for (const s of e)
|
|
35
|
-
this.linesMap.set(s.id, s);
|
|
36
|
-
this.curves = t, this.graph = a(e, t, this.config);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Add a single line. Returns false if a line with the same ID already exists.
|
|
40
|
-
*/
|
|
41
|
-
addLine(e) {
|
|
42
|
-
return this.linesMap.has(e.id) ? !1 : (this.linesMap.set(e.id, e), this.graph = a(Array.from(this.linesMap.values()), this.curves, this.config), !0);
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Update start and/or end coordinates of an existing line.
|
|
46
|
-
*/
|
|
47
|
-
updateLine(e, t) {
|
|
48
|
-
const s = this.linesMap.get(e);
|
|
49
|
-
return s ? (t.start && (s.start = t.start), t.end && (s.end = t.end), this.graph = a(Array.from(this.linesMap.values()), this.curves, this.config), !0) : !1;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Update a single endpoint ('start' or 'end') of a line.
|
|
53
|
-
*/
|
|
54
|
-
updateLineEndpoint(e, t, s) {
|
|
55
|
-
return this.updateLine(e, { [t]: s });
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Rename a line ID and cascade the change to all connected curves.
|
|
59
|
-
*/
|
|
60
|
-
renameLine(e, t) {
|
|
61
|
-
const s = t.trim();
|
|
62
|
-
if (!s) return { success: !1, error: "Name cannot be empty" };
|
|
63
|
-
if (s === e) return { success: !0 };
|
|
64
|
-
if (this.linesMap.has(s)) return { success: !1, error: `"${s}" already exists` };
|
|
65
|
-
const i = this.linesMap.get(e);
|
|
66
|
-
if (!i) return { success: !1, error: `Line "${e}" not found` };
|
|
67
|
-
i.id = s, this.linesMap.delete(e), this.linesMap.set(s, i);
|
|
68
|
-
for (const r of this.curves)
|
|
69
|
-
r.fromLineId === e && (r.fromLineId = s), r.toLineId === e && (r.toLineId = s);
|
|
70
|
-
return this.graph = a(Array.from(this.linesMap.values()), this.curves, this.config), { success: !0 };
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Remove a line and all curves connected to it.
|
|
74
|
-
*/
|
|
75
|
-
removeLine(e) {
|
|
76
|
-
return this.linesMap.has(e) ? (this.linesMap.delete(e), this.curves = this.curves.filter((t) => t.fromLineId !== e && t.toLineId !== e), this.graph = a(Array.from(this.linesMap.values()), this.curves, this.config), !0) : !1;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Add a directional curve (connection) from one line to another.
|
|
80
|
-
*/
|
|
81
|
-
addCurve(e) {
|
|
82
|
-
this.curves.push(e), this.graph = a(Array.from(this.linesMap.values()), this.curves, this.config);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Update a curve by index. Returns false if index is out of bounds.
|
|
86
|
-
*/
|
|
87
|
-
updateCurve(e, t) {
|
|
88
|
-
return e < 0 || e >= this.curves.length ? !1 : (this.curves[e] = { ...this.curves[e], ...t }, this.graph = a(Array.from(this.linesMap.values()), this.curves, this.config), !0);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Remove a curve by index. Returns false if index is out of bounds.
|
|
92
|
-
*/
|
|
93
|
-
removeCurve(e) {
|
|
94
|
-
return e < 0 || e >= this.curves.length ? !1 : (this.curves.splice(e, 1), this.graph = a(Array.from(this.linesMap.values()), this.curves, this.config), !0);
|
|
95
|
-
}
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
// Vehicle operations
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
/**
|
|
100
|
-
* Initialize a vehicle's dual-axle position on a line.
|
|
101
|
-
*
|
|
102
|
-
* @param lineId - The line to place the vehicle on
|
|
103
|
-
* @param offset - Absolute distance offset along the line
|
|
104
|
-
* @returns Initial VehiclePathState, or null if lineId does not exist
|
|
105
|
-
*/
|
|
106
|
-
initializeVehicle(e, t) {
|
|
107
|
-
const s = this.linesMap.get(e);
|
|
108
|
-
if (!s) return null;
|
|
109
|
-
const i = u(s), r = Math.min(t, i - this.config.wheelbase), f = p(s, r), o = m(e, r, this.config.wheelbase, s);
|
|
110
|
-
return {
|
|
111
|
-
rear: { lineId: e, offset: r, position: f },
|
|
112
|
-
front: { lineId: o.lineId, offset: o.absoluteOffset, position: o.position }
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Prepare a path from the vehicle's current position to a target.
|
|
117
|
-
*
|
|
118
|
-
* Must be called before moveVehicle(). Returns null if no path exists.
|
|
119
|
-
*
|
|
120
|
-
* @param vehicleState - Current vehicle state (from initializeVehicle or previous tick)
|
|
121
|
-
* @param targetLineId - ID of the target line
|
|
122
|
-
* @param targetOffset - Position on the target line
|
|
123
|
-
* @param isPercentage - If true, targetOffset is 0-1 fraction; if false, absolute distance
|
|
124
|
-
*/
|
|
125
|
-
preparePath(e, t, s, i = !1) {
|
|
126
|
-
if (!this.graph) return null;
|
|
127
|
-
const r = {
|
|
128
|
-
lineId: e.rear.lineId,
|
|
129
|
-
offset: e.rear.offset,
|
|
130
|
-
rear: {
|
|
131
|
-
lineId: e.rear.lineId,
|
|
132
|
-
position: e.rear.position,
|
|
133
|
-
absoluteOffset: e.rear.offset
|
|
134
|
-
},
|
|
135
|
-
front: {
|
|
136
|
-
lineId: e.front.lineId,
|
|
137
|
-
position: e.front.position,
|
|
138
|
-
absoluteOffset: e.front.offset
|
|
139
|
-
}
|
|
140
|
-
}, f = {
|
|
141
|
-
targetLineId: t,
|
|
142
|
-
targetOffset: s,
|
|
143
|
-
isPercentage: i
|
|
144
|
-
}, o = {
|
|
145
|
-
graph: this.graph,
|
|
146
|
-
linesMap: this.linesMap,
|
|
147
|
-
curves: this.curves,
|
|
148
|
-
config: this.config
|
|
149
|
-
}, n = v(r, f, o);
|
|
150
|
-
if (!n) return null;
|
|
151
|
-
let c = s;
|
|
152
|
-
const l = this.linesMap.get(t);
|
|
153
|
-
if (l) {
|
|
154
|
-
const g = u(l), h = Math.max(0, g - this.config.wheelbase);
|
|
155
|
-
c = i ? s * h : Math.min(s, h);
|
|
156
|
-
}
|
|
157
|
-
return {
|
|
158
|
-
path: n.path,
|
|
159
|
-
curveDataMap: n.curveDataMap,
|
|
160
|
-
rearSegmentIndex: 0,
|
|
161
|
-
rearSegmentDistance: 0,
|
|
162
|
-
frontSegmentIndex: 0,
|
|
163
|
-
frontSegmentDistance: this.config.wheelbase,
|
|
164
|
-
targetLineId: t,
|
|
165
|
-
targetOffset: c
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Advance a vehicle by `distance` along its prepared path.
|
|
170
|
-
*
|
|
171
|
-
* Call this every tick. The returned `state` and `execution` replace the
|
|
172
|
-
* previous values. When `arrived` is true, the vehicle has reached the target.
|
|
173
|
-
*
|
|
174
|
-
* @param state - Current vehicle state
|
|
175
|
-
* @param execution - Current path execution (from preparePath or previous tick)
|
|
176
|
-
* @param distance - Distance to advance this tick (speed × deltaTime)
|
|
177
|
-
*/
|
|
178
|
-
moveVehicle(e, t, s) {
|
|
179
|
-
const i = {
|
|
180
|
-
lineId: e.rear.lineId,
|
|
181
|
-
position: e.rear.position,
|
|
182
|
-
absoluteOffset: e.rear.offset
|
|
183
|
-
}, r = {
|
|
184
|
-
lineId: e.front.lineId,
|
|
185
|
-
position: e.front.position,
|
|
186
|
-
absoluteOffset: e.front.offset
|
|
187
|
-
}, f = {
|
|
188
|
-
currentSegmentIndex: t.rearSegmentIndex,
|
|
189
|
-
segmentDistance: t.rearSegmentDistance
|
|
190
|
-
}, o = {
|
|
191
|
-
currentSegmentIndex: t.frontSegmentIndex,
|
|
192
|
-
segmentDistance: t.frontSegmentDistance
|
|
193
|
-
}, n = d(i, r, f, o, t.path, s, this.linesMap, t.curveDataMap);
|
|
194
|
-
return {
|
|
195
|
-
state: {
|
|
196
|
-
rear: { lineId: n.rear.lineId, offset: n.rear.absoluteOffset, position: n.rear.position },
|
|
197
|
-
front: { lineId: n.front.lineId, offset: n.front.absoluteOffset, position: n.front.position }
|
|
198
|
-
},
|
|
199
|
-
execution: {
|
|
200
|
-
...t,
|
|
201
|
-
rearSegmentIndex: n.rearExecution.currentSegmentIndex,
|
|
202
|
-
rearSegmentDistance: n.rearExecution.segmentDistance,
|
|
203
|
-
frontSegmentIndex: n.frontExecution.currentSegmentIndex,
|
|
204
|
-
frontSegmentDistance: n.frontExecution.segmentDistance
|
|
205
|
-
},
|
|
206
|
-
arrived: n.arrived
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
}
|
|
1
|
+
import { PathEngine as i, arcLengthToSegmentPosition as n, buildArcLengthTable as a, buildGraph as o, calculateBezierArcLength as l, calculateFrontAxlePosition as r, calculateInitialAxlePositions as c, calculatePositionOnCurve as s, calculatePositionOnLine as g, c as h, createBezierCurve as P, createInitialMovementState as u, distance as L, distanceToT as f, findPath as m, getArcLength as v, getCumulativeArcLength as A, getLineLength as O, getPointOnBezier as d, getPointOnLine as z, getPointOnLineByOffset as T, getPositionFromOffset as p, handleArrival as x, initializeAllVehicles as B, initializeMovingVehicle as C, i as b, moveVehicle as F, normalize as V, prepareCommandPath as I, resolveFromLineOffset as M, resolveToLineOffset as S, updateAxlePosition as y } from "./vehicle-path.js";
|
|
210
2
|
export {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
3
|
+
i as PathEngine,
|
|
4
|
+
n as arcLengthToSegmentPosition,
|
|
5
|
+
a as buildArcLengthTable,
|
|
6
|
+
o as buildGraph,
|
|
7
|
+
l as calculateBezierArcLength,
|
|
8
|
+
r as calculateFrontAxlePosition,
|
|
9
|
+
c as calculateInitialAxlePositions,
|
|
10
|
+
s as calculatePositionOnCurve,
|
|
11
|
+
g as calculatePositionOnLine,
|
|
12
|
+
h as calculateTangentLength,
|
|
13
|
+
P as createBezierCurve,
|
|
14
|
+
u as createInitialMovementState,
|
|
15
|
+
L as distance,
|
|
16
|
+
f as distanceToT,
|
|
17
|
+
m as findPath,
|
|
18
|
+
v as getArcLength,
|
|
19
|
+
A as getCumulativeArcLength,
|
|
20
|
+
O as getLineLength,
|
|
21
|
+
d as getPointOnBezier,
|
|
22
|
+
z as getPointOnLine,
|
|
23
|
+
T as getPointOnLineByOffset,
|
|
232
24
|
p as getPositionFromOffset,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
25
|
+
x as handleArrival,
|
|
26
|
+
B as initializeAllVehicles,
|
|
27
|
+
C as initializeMovingVehicle,
|
|
28
|
+
b as isPointNearPoint,
|
|
29
|
+
F as moveVehicle,
|
|
30
|
+
V as normalize,
|
|
31
|
+
I as prepareCommandPath,
|
|
32
|
+
M as resolveFromLineOffset,
|
|
33
|
+
S as resolveToLineOffset,
|
|
34
|
+
y as updateAxlePosition
|
|
243
35
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* VehiclePath - Vehicle motion simulator library
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Core library for simulating multi-axle vehicle movement along paths
|
|
5
5
|
* composed of lines and Bezier curves.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { useVehicleSimulation } from 'vehicle-path'
|
|
10
|
-
*
|
|
11
|
-
* const sim = useVehicleSimulation({ wheelbase: 30 })
|
|
12
|
-
* sim.addLine({ id: 'line1', start: [0, 0], end: [400, 0] })
|
|
13
|
-
* sim.addVehicles({ id: 'v1', lineId: 'line1', position: 0 })
|
|
14
|
-
* sim.goto('v1', 'line1', 1.0)
|
|
15
|
-
* sim.prepare()
|
|
16
|
-
* sim.tick(5)
|
|
17
|
-
* ```
|
|
18
6
|
*/
|
|
19
7
|
export type { Point, Line, BezierCurve, Curve } from './core/types/geometry';
|
|
20
8
|
export type { VehicleState, VehicleStart, Vehicle, AxleState, GotoCommand, GotoCompletionInfo, GotoCompletionCallback } from './core/types/vehicle';
|
|
@@ -22,25 +10,6 @@ export type { CurveData, AxleExecutionState, PathExecutionState, VehicleMovement
|
|
|
22
10
|
export type { TangentMode } from './core/types/config';
|
|
23
11
|
export type { CoordinateInput, SceneLineInput, SceneConnectionInput, SceneConfig, VehicleInput, VehicleUpdateInput, ConnectionUpdateInput, GotoInput, GotoCommandInput, MovementCommandInput, SimulationConfig } from './core/types/api';
|
|
24
12
|
export { buildGraph, findPath, calculateBezierArcLength, resolveFromLineOffset, resolveToLineOffset, type Graph, type GraphEdge, type PathSegment, type PathResult, type VehiclePosition } from './core/algorithms/pathFinding';
|
|
25
|
-
export { initializeMovingVehicle, createInitialMovementState, initializeAllVehicles,
|
|
13
|
+
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 './core/algorithms/vehicleMovement';
|
|
26
14
|
export { PathEngine, type PathEngineConfig, type VehiclePathState, type PathExecution } from './core/engine';
|
|
27
15
|
export { distance, normalize, getPointOnLine, getPointOnLineByOffset, getPointOnBezier, createBezierCurve, buildArcLengthTable, distanceToT, getArcLength, type ArcLengthEntry, type CurveOffsetOptions } from './core/algorithms/math';
|
|
28
|
-
export { VehicleEventEmitter, type VehicleEventMap, type VehicleEventType, type VehicleEventCallback, type VehiclePositionUpdate, type Unsubscribe, type CommandStartInfo } from './utils/event-emitter';
|
|
29
|
-
export { parseSceneDSL, parseVehiclesDSL, parseMovementDSL, parseAllDSL, generateSceneDSL, generateVehiclesDSL, generateMovementDSL, type ParseResult, type MovementCommand } from './utils/dsl-parser';
|
|
30
|
-
export { createAnimationLoop, useAnimationLoop, type AnimationLoopOptions, type AnimationLoopControls } from './utils/animation-loop';
|
|
31
|
-
export { validateAndCreateVehicles, getNextStartVehicleId, getNextGotoVehicleId } from './utils/vehicle-helpers';
|
|
32
|
-
export { useVehicleSimulation, type UseVehicleSimulationProps, type UseVehicleSimulationResult, type SimulationWarning, type SimulationResult } from './react/hooks/useVehicleSimulation';
|
|
33
|
-
export { useScene, type UseSceneResult } from './react/hooks/useScene';
|
|
34
|
-
export { useVehicles, type UseVehiclesResult, type UseVehiclesProps } from './react/hooks/useVehicles';
|
|
35
|
-
export { useMovementQueue, type UseMovementQueueResult, type UseMovementQueueProps } from './react/hooks/useMovementQueue';
|
|
36
|
-
export { useAnimation, type UseAnimationProps } from './react/hooks/useAnimation';
|
|
37
|
-
/** @deprecated Use useMovementQueue instead */
|
|
38
|
-
export { useMovementQueue as useMovement } from './react/hooks/useMovementQueue';
|
|
39
|
-
export type { UseMovementQueueResult as UseMovementResult } from './react/hooks/useMovementQueue';
|
|
40
|
-
export type { UseMovementQueueProps as UseMovementProps } from './react/hooks/useMovementQueue';
|
|
41
|
-
/** @deprecated Use useAnimation instead */
|
|
42
|
-
export { useAnimation as useVehicleMovement } from './react/hooks/useAnimation';
|
|
43
|
-
export { useSceneDefinition } from './react/dsl-hooks/useSceneDefinition';
|
|
44
|
-
export { useInitialMovement } from './react/dsl-hooks/useInitialMovement';
|
|
45
|
-
export { useMovementSequence } from './react/dsl-hooks/useMovementSequence';
|
|
46
|
-
export { useVehicleEventEmitter, useCreateVehicleEventEmitter, useVehicleEvent, VehicleEventContext, VehicleEventProvider, type VehicleEventProviderProps } from './react/providers/useVehicleEvents';
|
|
@@ -18,13 +18,11 @@ export interface CommandStartInfo {
|
|
|
18
18
|
*/
|
|
19
19
|
export interface VehiclePositionUpdate {
|
|
20
20
|
vehicleId: string;
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
front: Point;
|
|
25
|
-
/** Center point between rear and front axles */
|
|
21
|
+
/** Posisi semua axle, axles[0] = terdepan */
|
|
22
|
+
axles: Point[];
|
|
23
|
+
/** Center vehicle (rata-rata semua axle) */
|
|
26
24
|
center: Point;
|
|
27
|
-
/** Angle
|
|
25
|
+
/** Angle dari axle paling belakang ke terdepan */
|
|
28
26
|
angle: number;
|
|
29
27
|
}
|
|
30
28
|
/**
|
package/dist/vehicle-path.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./vehicleMovement-BiYBE_2a.cjs"),o=require("./core.cjs"),i=require("./vehicle-helpers-DrCYMVs4.cjs"),n=require("./animation-loop-fC2LjxCd.cjs"),t=require("./useVehicleEvents-Bp4v5sln.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.moveVehicle=e.moveVehicle;exports.normalize=e.normalize;exports.prepareCommandPath=e.prepareCommandPath;exports.resolveFromLineOffset=e.resolveFromLineOffset;exports.resolveToLineOffset=e.resolveToLineOffset;exports.updateAxlePosition=e.updateAxlePosition;exports.PathEngine=o.PathEngine;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"});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 j(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 N(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 $(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=$(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=N(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=j(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=j;exports.buildGraph=x;exports.calculateBezierArcLength=$;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=N;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;
|