vehicle-path 1.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/README.md +293 -0
- package/dist/hooks/useCanvasInteraction.d.ts +31 -0
- package/dist/hooks/useInitialMovement.d.ts +16 -0
- package/dist/hooks/useMovementSequence.d.ts +17 -0
- package/dist/hooks/useSceneDefinition.d.ts +12 -0
- package/dist/hooks/useVehicleEvents.d.ts +31 -0
- package/dist/hooks/useVehicleMovement.d.ts +24 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/types/core.d.ts +26 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/movement.d.ts +64 -0
- package/dist/types/ui.d.ts +13 -0
- package/dist/types/vehicle.d.ts +65 -0
- package/dist/utils/VehicleEventEmitter.d.ts +79 -0
- package/dist/utils/canvasHelpers.d.ts +9 -0
- package/dist/utils/canvasRenderer.d.ts +13 -0
- package/dist/utils/math.d.ts +35 -0
- package/dist/utils/pathFinding.d.ts +75 -0
- package/dist/utils/textParser.d.ts +22 -0
- package/dist/utils/vehicleHelpers.d.ts +14 -0
- package/dist/utils/vehicleMovement/arcLengthTracking.d.ts +40 -0
- package/dist/utils/vehicleMovement/index.d.ts +8 -0
- package/dist/utils/vehicleMovement/initialize.d.ts +37 -0
- package/dist/utils/vehicleMovement/pathPreparation.d.ts +18 -0
- package/dist/utils/vehicleMovement/positionUpdate.d.ts +44 -0
- package/dist/utils/vehicleMovement/segmentTransition.d.ts +39 -0
- package/dist/utils/vehicleMovement/shared.d.ts +10 -0
- package/dist/vehicle-path.cjs +14 -0
- package/dist/vehicle-path.js +1346 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# VehiclePath
|
|
2
|
+
|
|
3
|
+
An interactive web-based vehicle motion simulator that visualizes dual-axle vehicle movement along complex paths composed of lines and Bezier curves. The system accurately tracks both rear and front axles with proper wheelbase constraints.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Interactive Canvas Drawing** - Create lines and Bezier curves with mouse controls
|
|
8
|
+
- **Dual-Axle Vehicle Tracking** - Track both front (F) and rear (R) axles with configurable wheelbase
|
|
9
|
+
- **Text-based Scene Definition** - Define scenes using intuitive DSL syntax
|
|
10
|
+
- **Command-based Movement** - Queue goto commands with `--wait` and `--payload` options
|
|
11
|
+
- **Arc-Length Parameterization** - Accurate curve traversal with constant speed
|
|
12
|
+
- **Event System** - Observer pattern for vehicle events (commandComplete, positionUpdate, stateChange)
|
|
13
|
+
- **Playback Controls** - Run, pause, and reset animations
|
|
14
|
+
- **Real-time Visualization** - Canvas rendering with endpoints, curves, and moving vehicles
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install dependencies
|
|
20
|
+
npm install
|
|
21
|
+
|
|
22
|
+
# Start development server
|
|
23
|
+
npm run dev
|
|
24
|
+
|
|
25
|
+
# Run tests
|
|
26
|
+
npm test
|
|
27
|
+
|
|
28
|
+
# Build for production
|
|
29
|
+
npm run build
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Scene Definition DSL
|
|
33
|
+
|
|
34
|
+
### Lines
|
|
35
|
+
```
|
|
36
|
+
line001 : (100, 100) -> (500, 100)
|
|
37
|
+
line002 : (500, 100) -> (500, 400)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Curves (connect lines)
|
|
41
|
+
```
|
|
42
|
+
line001 -> line002
|
|
43
|
+
line001 80% -> line002 30%
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Vehicle Start Positions
|
|
47
|
+
```
|
|
48
|
+
v1 start line001 0%
|
|
49
|
+
v2 start line002 50
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Movement Commands
|
|
53
|
+
```
|
|
54
|
+
v1 goto line002 100%
|
|
55
|
+
v1 goto line001 50% --wait
|
|
56
|
+
v1 goto line002 0% --payload {"orderId":"123"}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Architecture
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
src/
|
|
63
|
+
├── components/
|
|
64
|
+
│ ├── Canvas.tsx # Interactive canvas for drawing
|
|
65
|
+
│ └── Controls.tsx # Control panel with parameters
|
|
66
|
+
├── hooks/
|
|
67
|
+
│ ├── useCanvasInteraction.ts # Mouse/drag handling
|
|
68
|
+
│ ├── useSceneDefinition.ts # Lines/curves state
|
|
69
|
+
│ ├── useInitialMovement.ts # Vehicle start positions
|
|
70
|
+
│ ├── useMovementSequence.ts # Goto command queuing
|
|
71
|
+
│ ├── useVehicleMovement.ts # Animation loop
|
|
72
|
+
│ └── useVehicleEvents.ts # Event subscription
|
|
73
|
+
├── types/
|
|
74
|
+
│ ├── core.ts # Point, Line, Curve
|
|
75
|
+
│ ├── vehicle.ts # Vehicle, AxleState, GotoCommand
|
|
76
|
+
│ ├── movement.ts # MovementConfig, PathExecutionState
|
|
77
|
+
│ └── ui.ts # DrawMode, TangentMode
|
|
78
|
+
└── utils/
|
|
79
|
+
├── pathFinding.ts # Graph-based path finding
|
|
80
|
+
├── textParser.ts # DSL parsing
|
|
81
|
+
├── VehicleEventEmitter.ts # Event system
|
|
82
|
+
└── vehicleMovement/ # Core movement algorithms
|
|
83
|
+
├── initialize.ts
|
|
84
|
+
├── positionUpdate.ts
|
|
85
|
+
├── arcLengthTracking.ts
|
|
86
|
+
├── pathPreparation.ts
|
|
87
|
+
└── segmentTransition.ts
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Core Concepts
|
|
91
|
+
|
|
92
|
+
### Dual-Axle Tracking
|
|
93
|
+
|
|
94
|
+
The system tracks two axle positions:
|
|
95
|
+
- **Rear Axle (R)** - The reference point that follows the path exactly
|
|
96
|
+
- **Front Axle (F)** - Maintains constant wheelbase distance from R
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
R ----[wheelbase]---- F
|
|
100
|
+
(30-60 pixels)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Arc-Length Parameterization
|
|
104
|
+
|
|
105
|
+
Bezier curves are pre-computed with arc-length lookup tables for:
|
|
106
|
+
- Constant speed movement along curves
|
|
107
|
+
- Accurate position calculation at any distance
|
|
108
|
+
- Smooth transitions between segments
|
|
109
|
+
|
|
110
|
+
### Event System
|
|
111
|
+
|
|
112
|
+
Subscribe to vehicle events using the observer pattern:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Using React hook
|
|
116
|
+
useVehicleEvent('positionUpdate', (data) => {
|
|
117
|
+
console.log(`Center: (${data.center.x}, ${data.center.y})`)
|
|
118
|
+
console.log(`Angle: ${data.angle} radians`)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// Manual subscription
|
|
122
|
+
const unsubscribe = emitter.on('commandComplete', (info) => {
|
|
123
|
+
console.log(`Vehicle ${info.vehicleId} arrived`)
|
|
124
|
+
console.log(`Payload:`, info.payload)
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Available Events:**
|
|
129
|
+
| Event | Data | Description |
|
|
130
|
+
|-------|------|-------------|
|
|
131
|
+
| `commandComplete` | `GotoCompletionInfo` | Fired when vehicle reaches destination |
|
|
132
|
+
| `positionUpdate` | `VehiclePositionUpdate` | Fired each frame with position/angle |
|
|
133
|
+
| `stateChange` | `{vehicleId, from, to}` | Fired when vehicle state changes |
|
|
134
|
+
|
|
135
|
+
### Manual Control with `--wait`
|
|
136
|
+
|
|
137
|
+
Pause vehicle after command completion:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
v1 goto station-A 100% --wait
|
|
141
|
+
v1 goto station-B 0%
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Then resume programmatically:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const { continueVehicle } = useVehicleMovement({...})
|
|
148
|
+
|
|
149
|
+
// After processing...
|
|
150
|
+
continueVehicle('v1')
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Payload System
|
|
154
|
+
|
|
155
|
+
Attach custom data to commands:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
v1 goto pickup 100% --wait --payload {"orderId":"order-123","priority":1}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Access in callback:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
emitter.on('commandComplete', (info) => {
|
|
165
|
+
if (info.payload) {
|
|
166
|
+
const { orderId, priority } = info.payload as OrderPayload
|
|
167
|
+
// Process order...
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## API Reference
|
|
173
|
+
|
|
174
|
+
### useVehicleMovement
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const {
|
|
178
|
+
movingVehicles, // Current vehicle states
|
|
179
|
+
playbackState, // 'stopped' | 'running' | 'paused'
|
|
180
|
+
handleRun, // Start animation
|
|
181
|
+
handlePause, // Pause animation
|
|
182
|
+
handleReset, // Reset to initial positions
|
|
183
|
+
continueVehicle // Resume waiting vehicle
|
|
184
|
+
} = useVehicleMovement({
|
|
185
|
+
vehicles, // Initial vehicle configs
|
|
186
|
+
lines, // Line definitions
|
|
187
|
+
vehicleQueues, // Map<vehicleId, GotoCommand[]>
|
|
188
|
+
velocity, // Pixels per frame
|
|
189
|
+
wheelbase, // Distance R to F
|
|
190
|
+
tangentMode, // 'smooth' | 'linear'
|
|
191
|
+
curves, // Curve definitions
|
|
192
|
+
eventEmitter // Optional VehicleEventEmitter
|
|
193
|
+
})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### VehicleEventEmitter
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const emitter = new VehicleEventEmitter()
|
|
200
|
+
|
|
201
|
+
// Subscribe
|
|
202
|
+
const unsubscribe = emitter.on('positionUpdate', callback)
|
|
203
|
+
|
|
204
|
+
// Emit
|
|
205
|
+
emitter.emit('positionUpdate', data)
|
|
206
|
+
|
|
207
|
+
// Unsubscribe all
|
|
208
|
+
emitter.off('positionUpdate') // Specific event
|
|
209
|
+
emitter.off() // All events
|
|
210
|
+
|
|
211
|
+
// Check listeners
|
|
212
|
+
emitter.listenerCount('positionUpdate')
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### GotoCommand
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
interface GotoCommand {
|
|
219
|
+
vehicleId: string
|
|
220
|
+
targetLineId: string
|
|
221
|
+
targetOffset: number
|
|
222
|
+
isPercentage: boolean
|
|
223
|
+
awaitConfirmation?: boolean // --wait flag
|
|
224
|
+
payload?: unknown // --payload JSON
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### VehiclePositionUpdate
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
interface VehiclePositionUpdate {
|
|
232
|
+
vehicleId: string
|
|
233
|
+
rear: Point // Rear axle position
|
|
234
|
+
front: Point // Front axle position
|
|
235
|
+
center: Point // Midpoint between axles
|
|
236
|
+
angle: number // Heading in radians
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Testing
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Run all tests
|
|
244
|
+
npm test
|
|
245
|
+
|
|
246
|
+
# Run with UI
|
|
247
|
+
npm run test:ui
|
|
248
|
+
|
|
249
|
+
# Generate coverage report
|
|
250
|
+
npm run test:coverage
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Test files are located in `src/utils/vehicleMovement/__tests__/`:
|
|
254
|
+
- `arcLengthTracking.test.ts` - Arc-length calculations
|
|
255
|
+
- `dualAxleMovement.test.ts` - Dual-axle scenarios
|
|
256
|
+
- `initialize.test.ts` - Initialization logic
|
|
257
|
+
- `pathPreparation.test.ts` - Path preparation
|
|
258
|
+
- `positionUpdate.test.ts` - Position updates
|
|
259
|
+
- `userScenario.test.ts` - End-to-end scenarios
|
|
260
|
+
|
|
261
|
+
## Configuration
|
|
262
|
+
|
|
263
|
+
### Tangent Modes
|
|
264
|
+
|
|
265
|
+
Control curve smoothness:
|
|
266
|
+
- **smooth** - Bezier curves with smooth tangents
|
|
267
|
+
- **linear** - Sharp corners at connection points
|
|
268
|
+
|
|
269
|
+
### Parameters
|
|
270
|
+
|
|
271
|
+
| Parameter | Default | Description |
|
|
272
|
+
|-----------|---------|-------------|
|
|
273
|
+
| `wheelbase` | 30-60 | Distance between R and F axles |
|
|
274
|
+
| `velocity` | 1-5 | Movement speed (pixels/frame) |
|
|
275
|
+
|
|
276
|
+
## Tech Stack
|
|
277
|
+
|
|
278
|
+
- **React 19** - UI framework
|
|
279
|
+
- **TypeScript 5.9** - Type safety
|
|
280
|
+
- **Vite 7** - Build tool
|
|
281
|
+
- **Vitest** - Testing framework
|
|
282
|
+
- **Canvas API** - Rendering
|
|
283
|
+
|
|
284
|
+
## Documentation
|
|
285
|
+
|
|
286
|
+
Additional documentation in `/docs`:
|
|
287
|
+
- `DEBUG_GUIDE.md` - Debugging vehicle movement
|
|
288
|
+
- `HOOKS.md` - Custom hooks reference
|
|
289
|
+
- `UI.md` - UI architecture
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Point, Line, Curve } from '../types/core';
|
|
2
|
+
import type { DrawMode } from '../types/ui';
|
|
3
|
+
interface UseCanvasInteractionProps {
|
|
4
|
+
canvasRef: React.RefObject<HTMLCanvasElement | null>;
|
|
5
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
6
|
+
drawMode: DrawMode;
|
|
7
|
+
lines: Line[];
|
|
8
|
+
curves: Curve[];
|
|
9
|
+
setLines: (lines: Line[]) => void;
|
|
10
|
+
setCurves: (curves: Curve[]) => void;
|
|
11
|
+
lineCounterRef: React.MutableRefObject<number>;
|
|
12
|
+
}
|
|
13
|
+
export declare function useCanvasInteraction({ canvasRef, containerRef, drawMode, lines, curves, setLines, setCurves, lineCounterRef }: UseCanvasInteractionProps): {
|
|
14
|
+
handleMouseDown: (e: React.MouseEvent<HTMLCanvasElement>) => void;
|
|
15
|
+
handleMouseMove: (e: React.MouseEvent<HTMLCanvasElement>) => void;
|
|
16
|
+
handleMouseUp: () => void;
|
|
17
|
+
tempLine: {
|
|
18
|
+
start: Point;
|
|
19
|
+
current: Point;
|
|
20
|
+
} | null;
|
|
21
|
+
hoveredEndpoint: {
|
|
22
|
+
lineId: string;
|
|
23
|
+
endpoint: "start" | "end";
|
|
24
|
+
} | null;
|
|
25
|
+
curveStart: {
|
|
26
|
+
lineId: string;
|
|
27
|
+
endpoint: "start" | "end";
|
|
28
|
+
} | null;
|
|
29
|
+
mousePos: Point;
|
|
30
|
+
};
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Line } from '../types/core';
|
|
2
|
+
import type { Vehicle } from '../types/vehicle';
|
|
3
|
+
interface UseInitialMovementProps {
|
|
4
|
+
lines: Line[];
|
|
5
|
+
wheelbase: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function useInitialMovement({ lines, wheelbase }: UseInitialMovementProps): {
|
|
8
|
+
vehicles: Vehicle[];
|
|
9
|
+
initialMovementText: string;
|
|
10
|
+
movementError: string | null;
|
|
11
|
+
isDebouncing: boolean;
|
|
12
|
+
debounceKey: number;
|
|
13
|
+
setInitialMovementText: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
14
|
+
handleAddStartCommand: () => void;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Line } from '../types/core';
|
|
2
|
+
import type { Vehicle, GotoCommand } from '../types/vehicle';
|
|
3
|
+
interface UseMovementSequenceProps {
|
|
4
|
+
lines: Line[];
|
|
5
|
+
vehicles: Vehicle[];
|
|
6
|
+
}
|
|
7
|
+
export declare function useMovementSequence({ lines, vehicles }: UseMovementSequenceProps): {
|
|
8
|
+
movementSequenceText: string;
|
|
9
|
+
gotoCommands: GotoCommand[];
|
|
10
|
+
vehicleQueues: Map<string, GotoCommand[]>;
|
|
11
|
+
sequenceError: string | null;
|
|
12
|
+
isDebouncing: boolean;
|
|
13
|
+
debounceKey: number;
|
|
14
|
+
setMovementSequenceText: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
15
|
+
handleAddGotoCommand: () => void;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Line, Curve } from '../types/core';
|
|
2
|
+
export declare function useSceneDefinition(): {
|
|
3
|
+
lines: Line[];
|
|
4
|
+
curves: Curve[];
|
|
5
|
+
sceneDefinitionText: string;
|
|
6
|
+
sceneError: string | null;
|
|
7
|
+
isDebouncing: boolean;
|
|
8
|
+
debounceKey: number;
|
|
9
|
+
setLines: import("react").Dispatch<import("react").SetStateAction<Line[]>>;
|
|
10
|
+
setCurves: import("react").Dispatch<import("react").SetStateAction<Curve[]>>;
|
|
11
|
+
setSceneDefinitionText: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { VehicleEventEmitter, type VehicleEventType, type VehicleEventCallback, type VehicleEventMap, type VehiclePositionUpdate } from '../utils/VehicleEventEmitter';
|
|
2
|
+
/**
|
|
3
|
+
* React context for VehicleEventEmitter
|
|
4
|
+
*/
|
|
5
|
+
export declare const VehicleEventContext: import("react").Context<VehicleEventEmitter | null>;
|
|
6
|
+
/**
|
|
7
|
+
* Hook to access the VehicleEventEmitter instance from context
|
|
8
|
+
* @returns VehicleEventEmitter instance
|
|
9
|
+
* @throws Error if used outside of VehicleEventProvider
|
|
10
|
+
*/
|
|
11
|
+
export declare function useVehicleEventEmitter(): VehicleEventEmitter;
|
|
12
|
+
/**
|
|
13
|
+
* Hook to create a new VehicleEventEmitter instance (for provider)
|
|
14
|
+
* @returns VehicleEventEmitter instance (stable reference)
|
|
15
|
+
*/
|
|
16
|
+
export declare function useCreateVehicleEventEmitter(): VehicleEventEmitter;
|
|
17
|
+
/**
|
|
18
|
+
* Hook to subscribe to a vehicle event with automatic cleanup
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* useVehicleEvent('commandComplete', (info) => {
|
|
23
|
+
* console.log(`Vehicle ${info.vehicleId} arrived!`)
|
|
24
|
+
* if (info.payload) {
|
|
25
|
+
* // Handle payload
|
|
26
|
+
* }
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function useVehicleEvent<K extends VehicleEventType>(event: K, callback: VehicleEventCallback<K>, deps?: React.DependencyList): void;
|
|
31
|
+
export type { VehicleEventEmitter, VehicleEventType, VehicleEventCallback, VehicleEventMap, VehiclePositionUpdate };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Line } from '../types/core';
|
|
2
|
+
import type { Vehicle, GotoCommand } from '../types/vehicle';
|
|
3
|
+
import type { TangentMode } from '../types/ui';
|
|
4
|
+
import type { VehicleEventEmitter } from '../utils/VehicleEventEmitter';
|
|
5
|
+
interface UseVehicleMovementProps {
|
|
6
|
+
vehicles: Vehicle[];
|
|
7
|
+
lines: Line[];
|
|
8
|
+
vehicleQueues: Map<string, GotoCommand[]>;
|
|
9
|
+
velocity: number;
|
|
10
|
+
wheelbase: number;
|
|
11
|
+
tangentMode: TangentMode;
|
|
12
|
+
curves: import('../types/core').Curve[];
|
|
13
|
+
eventEmitter?: VehicleEventEmitter;
|
|
14
|
+
}
|
|
15
|
+
type PlaybackState = 'stopped' | 'running' | 'paused';
|
|
16
|
+
export declare function useVehicleMovement({ vehicles, lines, vehicleQueues, velocity, wheelbase, tangentMode, curves, eventEmitter }: UseVehicleMovementProps): {
|
|
17
|
+
movingVehicles: Vehicle[];
|
|
18
|
+
playbackState: PlaybackState;
|
|
19
|
+
handleRun: () => void;
|
|
20
|
+
handlePause: () => void;
|
|
21
|
+
handleReset: () => void;
|
|
22
|
+
continueVehicle: (vehicleId: string) => boolean;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VehiclePath - Vehicle motion simulator library
|
|
3
|
+
*
|
|
4
|
+
* A library for simulating dual-axle vehicle movement along paths
|
|
5
|
+
* composed of lines and Bezier curves.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import {
|
|
10
|
+
* useVehicleMovement,
|
|
11
|
+
* VehicleEventEmitter,
|
|
12
|
+
* parseSceneDefinition
|
|
13
|
+
* } from 'vehicle-path'
|
|
14
|
+
* import type { Point, Line, Vehicle } from 'vehicle-path'
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export type { Point, Line, BezierCurve, Curve, VehicleState, VehicleStart, Vehicle, AxleState, GotoCommand, GotoCompletionInfo, GotoCompletionCallback, CurveData, PathExecutionState, VehicleMovementState, MovementConfig, SceneDefinition, SceneContext, DrawMode, TangentMode } from './types';
|
|
18
|
+
export { useVehicleMovement } from './hooks/useVehicleMovement';
|
|
19
|
+
export { useVehicleEventEmitter, useCreateVehicleEventEmitter, useVehicleEvent, VehicleEventContext } from './hooks/useVehicleEvents';
|
|
20
|
+
export { useSceneDefinition } from './hooks/useSceneDefinition';
|
|
21
|
+
export { useInitialMovement } from './hooks/useInitialMovement';
|
|
22
|
+
export { useMovementSequence } from './hooks/useMovementSequence';
|
|
23
|
+
export { useCanvasInteraction } from './hooks/useCanvasInteraction';
|
|
24
|
+
export { VehicleEventEmitter, type VehicleEventMap, type VehicleEventType, type VehicleEventCallback, type VehiclePositionUpdate, type Unsubscribe } from './utils/VehicleEventEmitter';
|
|
25
|
+
export { parseSceneDefinition, generateSceneDefinition, parseVehicleStarts, generateVehicleStarts, parseGotoCommands, generateGotoCommands } from './utils/textParser';
|
|
26
|
+
export { buildGraph, findPath, canReachTarget, getReachableCurves, calculateBezierArcLength, resolveOffset, resolveFromLineOffset, resolveToLineOffset, type Graph, type GraphEdge, type PathSegment, type PathResult, type VehiclePosition } from './utils/pathFinding';
|
|
27
|
+
export { initializeMovingVehicle, createInitialMovementState, initializeAllVehicles, calculateInitialFrontPosition, type InitializationResult, updateAxlePosition, calculatePositionOnLine, calculatePositionOnCurve, calculateFrontAxlePosition, getCumulativeArcLength, arcLengthToSegmentPosition, prepareCommandPath, type PreparedPath, checkRearCompletion, handleArrival, type SegmentCompletionContext, type SegmentCompletionResult, type SegmentVehicleState, getPositionFromOffset, getLineLength } from './utils/vehicleMovement';
|
|
28
|
+
export { distance, normalize, getPointOnLine, getPointOnLineByOffset, getPointOnBezier, createBezierCurve, buildArcLengthTable, distanceToT, getArcLength, type ArcLengthEntry, type CurveOffsetOptions } from './utils/math';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VehiclePath - Vehicle motion simulator library
|
|
3
|
+
*
|
|
4
|
+
* A library for simulating dual-axle vehicle movement along paths
|
|
5
|
+
* composed of lines and Bezier curves.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import {
|
|
10
|
+
* useVehicleMovement,
|
|
11
|
+
* VehicleEventEmitter,
|
|
12
|
+
* parseSceneDefinition
|
|
13
|
+
* } from 'vehicle-path'
|
|
14
|
+
* import type { Point, Line, Vehicle } from 'vehicle-path'
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export type { Point, Line, BezierCurve, Curve, VehicleState, VehicleStart, Vehicle, AxleState, GotoCommand, GotoCompletionInfo, GotoCompletionCallback, CurveData, PathExecutionState, VehicleMovementState, MovementConfig, SceneDefinition, SceneContext, DrawMode, TangentMode } from './types';
|
|
18
|
+
export { useVehicleMovement } from './hooks/useVehicleMovement';
|
|
19
|
+
export { useVehicleEventEmitter, useCreateVehicleEventEmitter, useVehicleEvent, VehicleEventContext } from './hooks/useVehicleEvents';
|
|
20
|
+
export { useSceneDefinition } from './hooks/useSceneDefinition';
|
|
21
|
+
export { useInitialMovement } from './hooks/useInitialMovement';
|
|
22
|
+
export { useMovementSequence } from './hooks/useMovementSequence';
|
|
23
|
+
export { useCanvasInteraction } from './hooks/useCanvasInteraction';
|
|
24
|
+
export { VehicleEventEmitter, type VehicleEventMap, type VehicleEventType, type VehicleEventCallback, type VehiclePositionUpdate, type Unsubscribe } from './utils/VehicleEventEmitter';
|
|
25
|
+
export { parseSceneDefinition, generateSceneDefinition, parseVehicleStarts, generateVehicleStarts, parseGotoCommands, generateGotoCommands } from './utils/textParser';
|
|
26
|
+
export { buildGraph, findPath, canReachTarget, getReachableCurves, calculateBezierArcLength, resolveOffset, resolveFromLineOffset, resolveToLineOffset, type Graph, type GraphEdge, type PathSegment, type PathResult, type VehiclePosition } from './utils/pathFinding';
|
|
27
|
+
export { initializeMovingVehicle, createInitialMovementState, initializeAllVehicles, calculateInitialFrontPosition, type InitializationResult, updateAxlePosition, calculatePositionOnLine, calculatePositionOnCurve, calculateFrontAxlePosition, getCumulativeArcLength, arcLengthToSegmentPosition, prepareCommandPath, type PreparedPath, checkRearCompletion, handleArrival, type SegmentCompletionContext, type SegmentCompletionResult, type SegmentVehicleState, getPositionFromOffset, getLineLength } from './utils/vehicleMovement';
|
|
28
|
+
export { distance, normalize, getPointOnLine, getPointOnLineByOffset, getPointOnBezier, createBezierCurve, buildArcLengthTable, distanceToT, getArcLength, type ArcLengthEntry, type CurveOffsetOptions } from './utils/math';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core geometry types for the bezier-path system
|
|
3
|
+
*/
|
|
4
|
+
export interface Point {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
export interface Line {
|
|
9
|
+
id: string;
|
|
10
|
+
start: Point;
|
|
11
|
+
end: Point;
|
|
12
|
+
}
|
|
13
|
+
export interface BezierCurve {
|
|
14
|
+
p0: Point;
|
|
15
|
+
p1: Point;
|
|
16
|
+
p2: Point;
|
|
17
|
+
p3: Point;
|
|
18
|
+
}
|
|
19
|
+
export interface Curve {
|
|
20
|
+
fromLineId: string;
|
|
21
|
+
toLineId: string;
|
|
22
|
+
fromOffset?: number;
|
|
23
|
+
fromIsPercentage?: boolean;
|
|
24
|
+
toOffset?: number;
|
|
25
|
+
toIsPercentage?: boolean;
|
|
26
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export all types from a single entry point
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import type { Point, Line, Vehicle } from '../types'
|
|
6
|
+
* // or
|
|
7
|
+
* import type { Point } from '../types/core'
|
|
8
|
+
*/
|
|
9
|
+
export type { Point, Line, BezierCurve, Curve } from './core';
|
|
10
|
+
export type { VehicleState, VehicleStart, Vehicle, AxleState, GotoCommand, GotoCompletionInfo, GotoCompletionCallback } from './vehicle';
|
|
11
|
+
export type { CurveData, PathExecutionState, VehicleMovementState, MovementConfig, SceneDefinition, SceneContext } from './movement';
|
|
12
|
+
export type { DrawMode, TangentMode } from './ui';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Movement and animation state types
|
|
3
|
+
*/
|
|
4
|
+
import type { Line, Curve, BezierCurve } from './core';
|
|
5
|
+
import type { Vehicle, VehicleStart } from './vehicle';
|
|
6
|
+
import type { TangentMode } from './ui';
|
|
7
|
+
export type { PathResult } from '../utils/pathFinding';
|
|
8
|
+
export type { ArcLengthEntry } from '../utils/math';
|
|
9
|
+
/**
|
|
10
|
+
* Bezier curve data with arc-length lookup table for animation
|
|
11
|
+
*/
|
|
12
|
+
export interface CurveData {
|
|
13
|
+
bezier: BezierCurve;
|
|
14
|
+
arcLengthTable: import('../utils/math').ArcLengthEntry[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Execution state for a single axle (Front or Rear)
|
|
18
|
+
*/
|
|
19
|
+
export interface AxleExecutionState {
|
|
20
|
+
currentSegmentIndex: number;
|
|
21
|
+
segmentDistance: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* State for path execution during animation
|
|
25
|
+
*/
|
|
26
|
+
export interface PathExecutionState {
|
|
27
|
+
path: import('../utils/pathFinding').PathResult;
|
|
28
|
+
curveDataMap: Map<number, CurveData>;
|
|
29
|
+
currentCommandIndex: number;
|
|
30
|
+
rear: AxleExecutionState;
|
|
31
|
+
front: AxleExecutionState;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Movement state container for a vehicle
|
|
35
|
+
*/
|
|
36
|
+
export interface VehicleMovementState {
|
|
37
|
+
vehicle: Vehicle;
|
|
38
|
+
execution: PathExecutionState | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Configuration for vehicle movement
|
|
42
|
+
*/
|
|
43
|
+
export interface MovementConfig {
|
|
44
|
+
wheelbase: number;
|
|
45
|
+
tangentMode: TangentMode;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Scene definition (parsed from text input)
|
|
49
|
+
*/
|
|
50
|
+
export interface SceneDefinition {
|
|
51
|
+
lines: Line[];
|
|
52
|
+
curves: Curve[];
|
|
53
|
+
vehicles: VehicleStart[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Scene context for path preparation and movement calculations
|
|
57
|
+
* Bundles commonly-passed together dependencies
|
|
58
|
+
*/
|
|
59
|
+
export interface SceneContext {
|
|
60
|
+
config: MovementConfig;
|
|
61
|
+
graph: import('../utils/pathFinding').Graph;
|
|
62
|
+
linesMap: Map<string, Line>;
|
|
63
|
+
curves: Curve[];
|
|
64
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI-related types for canvas and controls
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Drawing mode for canvas interaction
|
|
6
|
+
*/
|
|
7
|
+
export type DrawMode = 'line' | 'curve' | 'drag';
|
|
8
|
+
/**
|
|
9
|
+
* Tangent calculation mode for bezier curves
|
|
10
|
+
* - proportional-40: 40% of distance for tangent length
|
|
11
|
+
* - magic-55: 55.22% of distance (approximates circular arc)
|
|
12
|
+
*/
|
|
13
|
+
export type TangentMode = 'proportional-40' | 'magic-55';
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vehicle-related types
|
|
3
|
+
*/
|
|
4
|
+
import type { Point } from './core';
|
|
5
|
+
/**
|
|
6
|
+
* Animation state for a vehicle
|
|
7
|
+
*/
|
|
8
|
+
export type VehicleState = 'idle' | 'moving' | 'waiting';
|
|
9
|
+
/**
|
|
10
|
+
* Vehicle start position (input from text parsing)
|
|
11
|
+
*/
|
|
12
|
+
export interface VehicleStart {
|
|
13
|
+
vehicleId: string;
|
|
14
|
+
lineId: string;
|
|
15
|
+
offset: number;
|
|
16
|
+
isPercentage: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* State for a single axle (Front or Rear)
|
|
20
|
+
*/
|
|
21
|
+
export interface AxleState {
|
|
22
|
+
lineId: string;
|
|
23
|
+
position: Point;
|
|
24
|
+
absoluteOffset: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Vehicle with runtime state (used during animation)
|
|
28
|
+
*/
|
|
29
|
+
export interface Vehicle {
|
|
30
|
+
id: string;
|
|
31
|
+
lineId: string;
|
|
32
|
+
offset: number;
|
|
33
|
+
isPercentage: boolean;
|
|
34
|
+
state: VehicleState;
|
|
35
|
+
rear: AxleState;
|
|
36
|
+
front: AxleState;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Command to move a vehicle to a target position
|
|
40
|
+
*/
|
|
41
|
+
export interface GotoCommand {
|
|
42
|
+
vehicleId: string;
|
|
43
|
+
targetLineId: string;
|
|
44
|
+
targetOffset: number;
|
|
45
|
+
isPercentage: boolean;
|
|
46
|
+
awaitConfirmation?: boolean;
|
|
47
|
+
payload?: unknown;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Information provided when a goto command completes
|
|
51
|
+
*/
|
|
52
|
+
export interface GotoCompletionInfo {
|
|
53
|
+
vehicleId: string;
|
|
54
|
+
command: GotoCommand;
|
|
55
|
+
finalPosition: {
|
|
56
|
+
lineId: string;
|
|
57
|
+
absoluteOffset: number;
|
|
58
|
+
position: Point;
|
|
59
|
+
};
|
|
60
|
+
payload?: unknown;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Callback type for goto command completion
|
|
64
|
+
*/
|
|
65
|
+
export type GotoCompletionCallback = (info: GotoCompletionInfo) => void;
|