@inventure71/paddockjs 3.0.0 → 4.1.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/CHANGELOG.md +152 -1
- package/INSTALL_AND_UPDATE.md +21 -4
- package/README.md +103 -551
- package/docs/architecture.md +28 -18
- package/docs/component_inventory.md +5 -4
- package/docs/composable-layouts.md +79 -0
- package/docs/custom_model_controller.md +4 -4
- package/docs/data-helpers.md +50 -0
- package/docs/data_contract.md +13 -7
- package/docs/getting-started.md +105 -0
- package/docs/headless-environment.md +68 -0
- package/docs/index.md +17 -4
- package/docs/rules.md +6 -2
- package/docs/system_specs.md +60 -7
- package/docs/theming.md +64 -0
- package/docs/training.md +20 -14
- package/docs/troubleshooting.md +76 -0
- package/docs/upgrading-hosts-to-3.md +42 -0
- package/examples/python/README.md +6 -0
- package/examples/python/base_policy_server.py +19 -0
- package/package.json +21 -5
- package/src/api/PaddockSimulatorController.js +78 -22
- package/src/api/runtimeTheme.js +59 -0
- package/src/app/F1SimulatorApp.js +24 -3
- package/src/app/readouts/timingTowerRenderer.js +203 -42
- package/src/app/runtime/frameLoop.js +5 -1
- package/src/config/defaultOptions.js +8 -1
- package/src/config/themeOptions.js +5 -0
- package/src/data/index.d.ts +212 -0
- package/src/data/index.js +14 -0
- package/src/environment/episode.js +11 -1
- package/src/environment/metrics.js +59 -16
- package/src/environment/observationVector.js +50 -33
- package/src/environment/observations.js +89 -20
- package/src/environment/runtime.js +41 -0
- package/src/environment/sensors/carRays.js +48 -37
- package/src/environment/sensors/index.js +501 -97
- package/src/environment/sensors/indexedRayBands.js +134 -46
- package/src/environment/sensors/rayBandTrace.js +1171 -0
- package/src/environment/sensors/rayChannels.js +108 -0
- package/src/environment/sensors/rayConfig.js +71 -25
- package/src/environment/sensors/rayGeometry.js +23 -17
- package/src/environment/sensors/sensorTargets.js +67 -1
- package/src/environment/sensors/surfaceRays.js +130 -89
- package/src/environment/sensors/trackRays.js +115 -1
- package/src/index.d.ts +43 -0
- package/src/index.js +27 -2
- package/src/placeholder/index.d.ts +11 -0
- package/src/placeholder/index.js +61 -0
- package/src/placeholder.css +72 -0
- package/src/simulation/collisionGeometry.js +260 -96
- package/src/simulation/pit/pitFlow.js +21 -9
- package/src/simulation/pit/pitQueue.js +5 -3
- package/src/simulation/pit/pitRouteMovement.js +9 -4
- package/src/simulation/pit/pitRouting.js +77 -42
- package/src/simulation/pit/pitState.js +1 -0
- package/src/simulation/pit/pitTireService.js +7 -3
- package/src/simulation/race/raceFinish.js +25 -8
- package/src/simulation/race/raceOrder.js +189 -32
- package/src/simulation/race/raceProgress.js +129 -37
- package/src/simulation/race/raceSetup.js +2 -0
- package/src/simulation/race/raceStep.js +25 -13
- package/src/simulation/raceSimulation.js +20 -17
- package/src/simulation/rules/collisionSteward.js +40 -23
- package/src/simulation/rules/rulesReview.js +77 -56
- package/src/simulation/snapshots/raceSnapshots.js +37 -0
- package/src/simulation/timing/drsTiming.js +143 -30
- package/src/simulation/timing/gapEstimation.js +25 -3
- package/src/simulation/timing/lapTelemetry.js +115 -36
- package/src/simulation/timing/raceTiming.js +5 -1
- package/src/simulation/timing/sectorPerformance.js +104 -26
- package/src/simulation/timing/timingHistory.js +229 -14
- package/src/simulation/timing/timingLines.js +65 -7
- package/src/simulation/track/pitLaneLayout.js +23 -0
- package/src/simulation/track/pitLaneState.js +218 -19
- package/src/simulation/track/spatialQueries.js +67 -11
- package/src/simulation/track/trackMath.js +91 -24
- package/src/simulation/track/trackModel.js +2 -0
- package/src/simulation/track/trackQueryIndex.js +1334 -100
- package/src/simulation/track/trackQueryPitIndex.js +138 -14
- package/src/simulation/track/trackQueryScratch.js +7 -0
- package/src/simulation/track/trackQueryStats.js +25 -0
- package/src/simulation/track/trackSnapshotJson.js +139 -0
- package/src/simulation/track/trackStatePolicy.js +249 -1
- package/src/simulation/vehicle/contactResolution.js +96 -59
- package/src/simulation/vehicle/mainTrackWheelSurface.js +73 -34
- package/src/simulation/vehicle/pitWheelSurface.js +81 -28
- package/src/simulation/vehicle/runoffResponse.js +54 -29
- package/src/simulation/vehicle/vehicleGeometry.js +245 -51
- package/src/simulation/vehicle/vehiclePhysics.js +42 -27
- package/src/simulation/vehicle/vehicleSnapshots.js +23 -0
- package/src/simulation/vehicle/vehicleState.js +6 -0
- package/src/simulation/vehicle/wheelSurface.js +807 -92
- package/src/styles.css +497 -497
- package/src/ui/raceControlsTemplate.js +1 -0
- package/src/ui/telemetryDrawerTemplate.js +1 -0
- package/src/ui/telemetryTemplates.js +1 -0
|
@@ -127,6 +127,16 @@ export function expandBounds(bounds, point) {
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
export function expandBoundsByPadding(bounds, padding = 0) {
|
|
131
|
+
const resolvedPadding = Number.isFinite(padding) ? Math.max(0, padding) : 0;
|
|
132
|
+
return {
|
|
133
|
+
minX: bounds.minX - resolvedPadding,
|
|
134
|
+
maxX: bounds.maxX + resolvedPadding,
|
|
135
|
+
minY: bounds.minY - resolvedPadding,
|
|
136
|
+
maxY: bounds.maxY + resolvedPadding,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
130
140
|
export function createPointBounds(points, padding = 0) {
|
|
131
141
|
const bounds = points.filter(Boolean).reduce(
|
|
132
142
|
(current, point) => expandBounds(current, point),
|
|
@@ -181,43 +191,100 @@ export function projectPointToSegment(position, start, end) {
|
|
|
181
191
|
}
|
|
182
192
|
|
|
183
193
|
export function nearestPointOnPolyline(points, position, segmentIndices = null) {
|
|
194
|
+
return nearestPointOnPolylineInto({}, points, position, { segmentIndices });
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function nearestPointOnPolylineInto(target, points, position, {
|
|
198
|
+
segmentIndices = null,
|
|
199
|
+
scratch = null,
|
|
200
|
+
cumulativeDistances: precomputedCumulativeDistances = null,
|
|
201
|
+
} = {}) {
|
|
184
202
|
if (!Array.isArray(points) || points.length < 2) return null;
|
|
185
|
-
const
|
|
186
|
-
|
|
203
|
+
const output = target ?? {};
|
|
204
|
+
const outputPoint = output.point ?? {};
|
|
205
|
+
output.point = outputPoint;
|
|
206
|
+
const restrictedSegments = Array.isArray(segmentIndices) && segmentIndices.length > 0;
|
|
207
|
+
const cumulativeDistances = restrictedSegments
|
|
208
|
+
? (Array.isArray(precomputedCumulativeDistances) && precomputedCumulativeDistances.length >= points.length
|
|
209
|
+
? precomputedCumulativeDistances
|
|
210
|
+
: writePolylineCumulativeDistances(scratch?.cumulativeDistances ?? new Array(points.length), points))
|
|
187
211
|
: null;
|
|
188
|
-
|
|
189
|
-
|
|
212
|
+
if (scratch && restrictedSegments && cumulativeDistances !== precomputedCumulativeDistances) {
|
|
213
|
+
scratch.cumulativeDistances = cumulativeDistances;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let bestSegmentIndex = -1;
|
|
217
|
+
let bestAmount = 0;
|
|
218
|
+
let bestLength = 0;
|
|
219
|
+
let bestHeading = 0;
|
|
220
|
+
let bestNormalX = 0;
|
|
221
|
+
let bestNormalY = 1;
|
|
222
|
+
let bestSignedOffset = 0;
|
|
223
|
+
let bestCrossTrackError = Infinity;
|
|
224
|
+
let bestDistanceAlong = 0;
|
|
225
|
+
let bestX = 0;
|
|
226
|
+
let bestY = 0;
|
|
190
227
|
let distanceBefore = 0;
|
|
191
228
|
let totalLength = 0;
|
|
192
229
|
|
|
193
|
-
const segmentCount = restrictedSegments
|
|
230
|
+
const segmentCount = restrictedSegments ? segmentIndices.length : (points.length - 1);
|
|
194
231
|
for (let segmentOffset = 0; segmentOffset < segmentCount; segmentOffset += 1) {
|
|
195
|
-
const index = restrictedSegments ?
|
|
232
|
+
const index = restrictedSegments ? segmentIndices[segmentOffset] : segmentOffset;
|
|
233
|
+
if (!Number.isInteger(index) || index < 0 || index >= points.length - 1) continue;
|
|
196
234
|
const current = points[index];
|
|
197
235
|
const next = points[index + 1];
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
236
|
+
const dx = next.x - current.x;
|
|
237
|
+
const dy = next.y - current.y;
|
|
238
|
+
const lengthSquared = dx * dx + dy * dy;
|
|
239
|
+
const amount = lengthSquared > 0
|
|
240
|
+
? clamp(((position.x - current.x) * dx + (position.y - current.y) * dy) / lengthSquared, 0, 1)
|
|
241
|
+
: 0;
|
|
242
|
+
const projectedX = current.x + dx * amount;
|
|
243
|
+
const projectedY = current.y + dy * amount;
|
|
244
|
+
const length = Math.sqrt(lengthSquared);
|
|
245
|
+
const heading = Math.atan2(dy, dx);
|
|
246
|
+
const normalX = length > 0 ? -dy / length : 0;
|
|
247
|
+
const normalY = length > 0 ? dx / length : 1;
|
|
248
|
+
const signedOffset = (position.x - projectedX) * normalX + (position.y - projectedY) * normalY;
|
|
249
|
+
const crossTrackError = Math.abs(signedOffset);
|
|
250
|
+
if (crossTrackError < bestCrossTrackError) {
|
|
251
|
+
bestSegmentIndex = index;
|
|
252
|
+
bestAmount = amount;
|
|
253
|
+
bestLength = length;
|
|
254
|
+
bestHeading = heading;
|
|
255
|
+
bestNormalX = normalX;
|
|
256
|
+
bestNormalY = normalY;
|
|
257
|
+
bestSignedOffset = signedOffset;
|
|
258
|
+
bestCrossTrackError = crossTrackError;
|
|
259
|
+
bestDistanceAlong = (restrictedSegments ? cumulativeDistances[index] : distanceBefore) + length * amount;
|
|
260
|
+
bestX = projectedX;
|
|
261
|
+
bestY = projectedY;
|
|
205
262
|
}
|
|
206
|
-
if (!restrictedSegments) distanceBefore +=
|
|
207
|
-
totalLength +=
|
|
263
|
+
if (!restrictedSegments) distanceBefore += length;
|
|
264
|
+
totalLength += length;
|
|
208
265
|
}
|
|
209
266
|
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
267
|
+
if (bestSegmentIndex < 0) return null;
|
|
268
|
+
outputPoint.x = bestX;
|
|
269
|
+
outputPoint.y = bestY;
|
|
270
|
+
output.amount = bestAmount;
|
|
271
|
+
output.length = bestLength;
|
|
272
|
+
output.heading = bestHeading;
|
|
273
|
+
output.normalX = bestNormalX;
|
|
274
|
+
output.normalY = bestNormalY;
|
|
275
|
+
output.signedOffset = bestSignedOffset;
|
|
276
|
+
output.crossTrackError = bestCrossTrackError;
|
|
277
|
+
output.segmentIndex = bestSegmentIndex;
|
|
278
|
+
output.distanceAlong = bestDistanceAlong;
|
|
279
|
+
output.totalLength = restrictedSegments
|
|
280
|
+
? cumulativeDistances[cumulativeDistances.length - 1]
|
|
281
|
+
: totalLength;
|
|
282
|
+
return output;
|
|
217
283
|
}
|
|
218
284
|
|
|
219
|
-
function
|
|
220
|
-
|
|
285
|
+
function writePolylineCumulativeDistances(distances, points) {
|
|
286
|
+
distances.length = points.length;
|
|
287
|
+
distances[0] = 0;
|
|
221
288
|
for (let index = 1; index < points.length; index += 1) {
|
|
222
289
|
distances[index] = distances[index - 1] + distance(points[index - 1], points[index]);
|
|
223
290
|
}
|
|
@@ -11,6 +11,7 @@ import { deriveDrsZones, normalizeDrsZone } from './drsZones.js';
|
|
|
11
11
|
import { createPitLaneModel } from './pitLaneLayout.js';
|
|
12
12
|
import { attachTrackQueryIndex, createTrackQueryIndex } from './trackQueryIndex.js';
|
|
13
13
|
import { resolveProceduralTrackOptions } from './trackGenerationOptions.js';
|
|
14
|
+
import { attachTrackSnapshotJsonSerializer } from './trackSnapshotJson.js';
|
|
14
15
|
|
|
15
16
|
export { WORLD, TRACK } from './trackConstants.js';
|
|
16
17
|
export { isInDrsZone } from './drsZones.js';
|
|
@@ -56,6 +57,7 @@ export function buildTrackModel(track = TRACK) {
|
|
|
56
57
|
? null
|
|
57
58
|
: createPitLaneModel(model);
|
|
58
59
|
attachTrackQueryIndex(model, createTrackQueryIndex(model));
|
|
60
|
+
attachTrackSnapshotJsonSerializer(model);
|
|
59
61
|
if (canReuseCachedModel) {
|
|
60
62
|
TRACK_MODEL_CACHE.set(track, freezeTrackModel(model));
|
|
61
63
|
}
|