@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
|
@@ -1,40 +1,83 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { queryTrackSegmentIdsAlongRay } from '../../simulation/track/trackQueryIndex.js';
|
|
2
2
|
import { metersToSimUnits } from '../../simulation/units.js';
|
|
3
3
|
|
|
4
4
|
const RAY_BOUND_QUERY_MARGIN_METERS = 18;
|
|
5
5
|
|
|
6
|
-
export function findIndexedRayBoundaryHit(track, origin, vector, lengthMeters, offsets) {
|
|
7
|
-
const boundaries = findIndexedRayBoundaryDistances(track, origin, vector, lengthMeters, offsets);
|
|
6
|
+
export function findIndexedRayBoundaryHit(track, origin, vector, lengthMeters, offsets, target = null) {
|
|
7
|
+
const boundaries = findIndexedRayBoundaryDistances(track, origin, vector, lengthMeters, offsets, target);
|
|
8
8
|
if (!boundaries.available) return { available: false, distance: null };
|
|
9
9
|
return {
|
|
10
10
|
available: true,
|
|
11
|
-
distance:
|
|
11
|
+
distance: minFiniteArray(boundaries.distances),
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function findIndexedRayBoundaryDistances(track, origin, vector, lengthMeters, offsets) {
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
export function findIndexedRayBoundaryDistances(track, origin, vector, lengthMeters, offsets, target = null) {
|
|
16
|
+
const result = target ?? {};
|
|
17
|
+
const finiteOffsets = target?.finiteOffsets ?? [];
|
|
18
|
+
const distances = target?.distances ?? [];
|
|
19
|
+
const segmentIds = target?.segmentIds ?? [];
|
|
20
|
+
if (target) {
|
|
21
|
+
target.finiteOffsets = finiteOffsets;
|
|
22
|
+
target.distances = distances;
|
|
23
|
+
target.segmentIds = segmentIds;
|
|
24
|
+
}
|
|
25
|
+
finiteOffsets.length = 0;
|
|
26
|
+
distances.length = 0;
|
|
27
|
+
segmentIds.length = 0;
|
|
28
|
+
for (let index = 0; index < offsets.length; index += 1) {
|
|
29
|
+
const offset = offsets[index];
|
|
30
|
+
if (Number.isFinite(offset)) finiteOffsets.push(offset);
|
|
31
|
+
}
|
|
32
|
+
if (finiteOffsets.length === 0) {
|
|
33
|
+
result.available = true;
|
|
34
|
+
result.distances = distances;
|
|
35
|
+
result.segmentIds = segmentIds;
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
18
38
|
const maxDistance = metersToSimUnits(lengthMeters);
|
|
19
|
-
|
|
39
|
+
let maxOffset = 0;
|
|
40
|
+
for (let index = 0; index < finiteOffsets.length; index += 1) {
|
|
41
|
+
maxOffset = Math.max(maxOffset, Math.abs(finiteOffsets[index]));
|
|
42
|
+
}
|
|
20
43
|
const margin = maxOffset + metersToSimUnits(RAY_BOUND_QUERY_MARGIN_METERS);
|
|
21
|
-
const
|
|
22
|
-
if (!
|
|
23
|
-
|
|
44
|
+
const segmentIdsAlongRay = queryTrackSegmentIdsAlongRay(track, origin, vector, maxDistance, margin);
|
|
45
|
+
if (!segmentIdsAlongRay) {
|
|
46
|
+
result.available = false;
|
|
47
|
+
result.distances = distances;
|
|
48
|
+
result.segmentIds = segmentIds;
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
const centerline = track.queryIndex.centerline;
|
|
52
|
+
distances.length = finiteOffsets.length;
|
|
53
|
+
segmentIds.length = finiteOffsets.length;
|
|
54
|
+
for (let index = 0; index < finiteOffsets.length; index += 1) {
|
|
55
|
+
distances[index] = Infinity;
|
|
56
|
+
segmentIds[index] = null;
|
|
57
|
+
}
|
|
24
58
|
|
|
25
|
-
for (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
const distance =
|
|
30
|
-
if (distance != null && distance < distances[offsetIndex])
|
|
31
|
-
|
|
59
|
+
for (let segmentIndex = 0; segmentIndex < segmentIdsAlongRay.length; segmentIndex += 1) {
|
|
60
|
+
const segmentId = segmentIdsAlongRay[segmentIndex];
|
|
61
|
+
for (let offsetIndex = 0; offsetIndex < finiteOffsets.length; offsetIndex += 1) {
|
|
62
|
+
const offset = finiteOffsets[offsetIndex];
|
|
63
|
+
const distance = rayOffsetSegmentIntersectionDistance(origin, vector, centerline, segmentId, offset, maxDistance);
|
|
64
|
+
if (distance != null && distance < distances[offsetIndex]) {
|
|
65
|
+
distances[offsetIndex] = distance;
|
|
66
|
+
segmentIds[offsetIndex] = segmentId;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
32
69
|
}
|
|
33
70
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
71
|
+
for (let index = 0; index < distances.length; index += 1) {
|
|
72
|
+
if (!Number.isFinite(distances[index])) {
|
|
73
|
+
distances[index] = null;
|
|
74
|
+
segmentIds[index] = null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
result.available = true;
|
|
78
|
+
result.distances = distances;
|
|
79
|
+
result.segmentIds = segmentIds;
|
|
80
|
+
return result;
|
|
38
81
|
}
|
|
39
82
|
|
|
40
83
|
export function findIndexedTrackBandBoundaries(
|
|
@@ -47,44 +90,71 @@ export function findIndexedTrackBandBoundaries(
|
|
|
47
90
|
cache = null,
|
|
48
91
|
) {
|
|
49
92
|
if (cache?.trackBandBoundaries) return cache.trackBandBoundaries;
|
|
93
|
+
const scratch = prepareTrackBandBoundaryScratch(cache);
|
|
94
|
+
const offsets = scratch?.offsets ?? [
|
|
95
|
+
trackHalfWidth,
|
|
96
|
+
-trackHalfWidth,
|
|
97
|
+
kerbOuterWidth,
|
|
98
|
+
-kerbOuterWidth,
|
|
99
|
+
];
|
|
100
|
+
if (scratch) {
|
|
101
|
+
offsets[0] = trackHalfWidth;
|
|
102
|
+
offsets[1] = -trackHalfWidth;
|
|
103
|
+
offsets[2] = kerbOuterWidth;
|
|
104
|
+
offsets[3] = -kerbOuterWidth;
|
|
105
|
+
offsets.length = 4;
|
|
106
|
+
}
|
|
50
107
|
const boundaries = findIndexedRayBoundaryDistances(
|
|
51
108
|
track,
|
|
52
109
|
origin,
|
|
53
110
|
vector,
|
|
54
111
|
lengthMeters,
|
|
55
|
-
|
|
112
|
+
offsets,
|
|
113
|
+
scratch?.boundaryDistances,
|
|
114
|
+
);
|
|
115
|
+
const result = scratch?.result ?? {};
|
|
116
|
+
result.available = boundaries.available;
|
|
117
|
+
result.trackEdgeDistance = minFinite(boundaries.distances[0], boundaries.distances[1]);
|
|
118
|
+
result.trackEdgeSegmentId = nearestSegmentId(
|
|
119
|
+
boundaries.distances[0],
|
|
120
|
+
boundaries.segmentIds[0],
|
|
121
|
+
boundaries.distances[1],
|
|
122
|
+
boundaries.segmentIds[1],
|
|
123
|
+
);
|
|
124
|
+
result.kerbOuterDistance = minFinite(boundaries.distances[2], boundaries.distances[3]);
|
|
125
|
+
result.kerbOuterSegmentId = nearestSegmentId(
|
|
126
|
+
boundaries.distances[2],
|
|
127
|
+
boundaries.segmentIds[2],
|
|
128
|
+
boundaries.distances[3],
|
|
129
|
+
boundaries.segmentIds[3],
|
|
56
130
|
);
|
|
57
|
-
const result = {
|
|
58
|
-
available: boundaries.available,
|
|
59
|
-
trackEdgeDistance: minFinite(boundaries.distances[0], boundaries.distances[1]),
|
|
60
|
-
kerbOuterDistance: minFinite(boundaries.distances[2], boundaries.distances[3]),
|
|
61
|
-
};
|
|
62
131
|
if (cache) cache.trackBandBoundaries = result;
|
|
63
132
|
return result;
|
|
64
133
|
}
|
|
65
134
|
|
|
66
|
-
function
|
|
67
|
-
return
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function offsetSegmentEnd(segment, offset) {
|
|
74
|
-
return {
|
|
75
|
-
x: segment.endX + segment.endNormalX * offset,
|
|
76
|
-
y: segment.endY + segment.endNormalY * offset,
|
|
135
|
+
function prepareTrackBandBoundaryScratch(cache) {
|
|
136
|
+
if (!cache) return null;
|
|
137
|
+
const scratch = cache.trackBandBoundaryScratch ?? {
|
|
138
|
+
offsets: [],
|
|
139
|
+
boundaryDistances: {},
|
|
140
|
+
result: {},
|
|
77
141
|
};
|
|
142
|
+
cache.trackBandBoundaryScratch = scratch;
|
|
143
|
+
return scratch;
|
|
78
144
|
}
|
|
79
145
|
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
const
|
|
146
|
+
function rayOffsetSegmentIntersectionDistance(origin, ray, centerline, segmentId, offset, maxDistance) {
|
|
147
|
+
const startX = centerline.startX[segmentId] + centerline.normalX[segmentId] * offset;
|
|
148
|
+
const startY = centerline.startY[segmentId] + centerline.normalY[segmentId] * offset;
|
|
149
|
+
const endX = centerline.endX[segmentId] + centerline.endNormalX[segmentId] * offset;
|
|
150
|
+
const endY = centerline.endY[segmentId] + centerline.endNormalY[segmentId] * offset;
|
|
151
|
+
const sx = endX - startX;
|
|
152
|
+
const sy = endY - startY;
|
|
83
153
|
const denominator = cross(ray.x, ray.y, sx, sy);
|
|
84
154
|
if (Math.abs(denominator) < 1e-9) return null;
|
|
85
155
|
|
|
86
|
-
const ox =
|
|
87
|
-
const oy =
|
|
156
|
+
const ox = startX - origin.x;
|
|
157
|
+
const oy = startY - origin.y;
|
|
88
158
|
const rayDistance = cross(ox, oy, sx, sy) / denominator;
|
|
89
159
|
const segmentAmount = cross(ox, oy, ray.x, ray.y) / denominator;
|
|
90
160
|
|
|
@@ -97,7 +167,25 @@ function cross(ax, ay, bx, by) {
|
|
|
97
167
|
return ax * by - ay * bx;
|
|
98
168
|
}
|
|
99
169
|
|
|
100
|
-
function minFinite(
|
|
101
|
-
|
|
170
|
+
function minFinite(first, second) {
|
|
171
|
+
if (!Number.isFinite(first)) return Number.isFinite(second) ? second : null;
|
|
172
|
+
if (!Number.isFinite(second)) return first;
|
|
173
|
+
return first <= second ? first : second;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function minFiniteArray(values) {
|
|
177
|
+
let minimum = Infinity;
|
|
178
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
179
|
+
const value = values[index];
|
|
180
|
+
if (Number.isFinite(value) && value < minimum) minimum = value;
|
|
181
|
+
}
|
|
102
182
|
return Number.isFinite(minimum) ? minimum : null;
|
|
103
183
|
}
|
|
184
|
+
|
|
185
|
+
function nearestSegmentId(firstDistance, firstSegmentId, secondDistance, secondSegmentId) {
|
|
186
|
+
if (!Number.isFinite(firstDistance)) return Number.isInteger(secondSegmentId) ? secondSegmentId : null;
|
|
187
|
+
if (!Number.isFinite(secondDistance)) return Number.isInteger(firstSegmentId) ? firstSegmentId : null;
|
|
188
|
+
return firstDistance <= secondDistance
|
|
189
|
+
? (Number.isInteger(firstSegmentId) ? firstSegmentId : null)
|
|
190
|
+
: (Number.isInteger(secondSegmentId) ? secondSegmentId : null);
|
|
191
|
+
}
|