@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.
Files changed (97) hide show
  1. package/CHANGELOG.md +152 -1
  2. package/INSTALL_AND_UPDATE.md +21 -4
  3. package/README.md +103 -551
  4. package/docs/architecture.md +28 -18
  5. package/docs/component_inventory.md +5 -4
  6. package/docs/composable-layouts.md +79 -0
  7. package/docs/custom_model_controller.md +4 -4
  8. package/docs/data-helpers.md +50 -0
  9. package/docs/data_contract.md +13 -7
  10. package/docs/getting-started.md +105 -0
  11. package/docs/headless-environment.md +68 -0
  12. package/docs/index.md +17 -4
  13. package/docs/rules.md +6 -2
  14. package/docs/system_specs.md +60 -7
  15. package/docs/theming.md +64 -0
  16. package/docs/training.md +20 -14
  17. package/docs/troubleshooting.md +76 -0
  18. package/docs/upgrading-hosts-to-3.md +42 -0
  19. package/examples/python/README.md +6 -0
  20. package/examples/python/base_policy_server.py +19 -0
  21. package/package.json +21 -5
  22. package/src/api/PaddockSimulatorController.js +78 -22
  23. package/src/api/runtimeTheme.js +59 -0
  24. package/src/app/F1SimulatorApp.js +24 -3
  25. package/src/app/readouts/timingTowerRenderer.js +203 -42
  26. package/src/app/runtime/frameLoop.js +5 -1
  27. package/src/config/defaultOptions.js +8 -1
  28. package/src/config/themeOptions.js +5 -0
  29. package/src/data/index.d.ts +212 -0
  30. package/src/data/index.js +14 -0
  31. package/src/environment/episode.js +11 -1
  32. package/src/environment/metrics.js +59 -16
  33. package/src/environment/observationVector.js +50 -33
  34. package/src/environment/observations.js +89 -20
  35. package/src/environment/runtime.js +41 -0
  36. package/src/environment/sensors/carRays.js +48 -37
  37. package/src/environment/sensors/index.js +501 -97
  38. package/src/environment/sensors/indexedRayBands.js +134 -46
  39. package/src/environment/sensors/rayBandTrace.js +1171 -0
  40. package/src/environment/sensors/rayChannels.js +108 -0
  41. package/src/environment/sensors/rayConfig.js +71 -25
  42. package/src/environment/sensors/rayGeometry.js +23 -17
  43. package/src/environment/sensors/sensorTargets.js +67 -1
  44. package/src/environment/sensors/surfaceRays.js +130 -89
  45. package/src/environment/sensors/trackRays.js +115 -1
  46. package/src/index.d.ts +43 -0
  47. package/src/index.js +27 -2
  48. package/src/placeholder/index.d.ts +11 -0
  49. package/src/placeholder/index.js +61 -0
  50. package/src/placeholder.css +72 -0
  51. package/src/simulation/collisionGeometry.js +260 -96
  52. package/src/simulation/pit/pitFlow.js +21 -9
  53. package/src/simulation/pit/pitQueue.js +5 -3
  54. package/src/simulation/pit/pitRouteMovement.js +9 -4
  55. package/src/simulation/pit/pitRouting.js +77 -42
  56. package/src/simulation/pit/pitState.js +1 -0
  57. package/src/simulation/pit/pitTireService.js +7 -3
  58. package/src/simulation/race/raceFinish.js +25 -8
  59. package/src/simulation/race/raceOrder.js +189 -32
  60. package/src/simulation/race/raceProgress.js +129 -37
  61. package/src/simulation/race/raceSetup.js +2 -0
  62. package/src/simulation/race/raceStep.js +25 -13
  63. package/src/simulation/raceSimulation.js +20 -17
  64. package/src/simulation/rules/collisionSteward.js +40 -23
  65. package/src/simulation/rules/rulesReview.js +77 -56
  66. package/src/simulation/snapshots/raceSnapshots.js +37 -0
  67. package/src/simulation/timing/drsTiming.js +143 -30
  68. package/src/simulation/timing/gapEstimation.js +25 -3
  69. package/src/simulation/timing/lapTelemetry.js +115 -36
  70. package/src/simulation/timing/raceTiming.js +5 -1
  71. package/src/simulation/timing/sectorPerformance.js +104 -26
  72. package/src/simulation/timing/timingHistory.js +229 -14
  73. package/src/simulation/timing/timingLines.js +65 -7
  74. package/src/simulation/track/pitLaneLayout.js +23 -0
  75. package/src/simulation/track/pitLaneState.js +218 -19
  76. package/src/simulation/track/spatialQueries.js +67 -11
  77. package/src/simulation/track/trackMath.js +91 -24
  78. package/src/simulation/track/trackModel.js +2 -0
  79. package/src/simulation/track/trackQueryIndex.js +1334 -100
  80. package/src/simulation/track/trackQueryPitIndex.js +138 -14
  81. package/src/simulation/track/trackQueryScratch.js +7 -0
  82. package/src/simulation/track/trackQueryStats.js +25 -0
  83. package/src/simulation/track/trackSnapshotJson.js +139 -0
  84. package/src/simulation/track/trackStatePolicy.js +249 -1
  85. package/src/simulation/vehicle/contactResolution.js +96 -59
  86. package/src/simulation/vehicle/mainTrackWheelSurface.js +73 -34
  87. package/src/simulation/vehicle/pitWheelSurface.js +81 -28
  88. package/src/simulation/vehicle/runoffResponse.js +54 -29
  89. package/src/simulation/vehicle/vehicleGeometry.js +245 -51
  90. package/src/simulation/vehicle/vehiclePhysics.js +42 -27
  91. package/src/simulation/vehicle/vehicleSnapshots.js +23 -0
  92. package/src/simulation/vehicle/vehicleState.js +6 -0
  93. package/src/simulation/vehicle/wheelSurface.js +807 -92
  94. package/src/styles.css +497 -497
  95. package/src/ui/raceControlsTemplate.js +1 -0
  96. package/src/ui/telemetryDrawerTemplate.js +1 -0
  97. package/src/ui/telemetryTemplates.js +1 -0
@@ -1,40 +1,83 @@
1
- import { queryTrackSegmentsAlongRay } from '../../simulation/track/trackQueryIndex.js';
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: minFinite(...boundaries.distances),
11
+ distance: minFiniteArray(boundaries.distances),
12
12
  };
13
13
  }
14
14
 
15
- export function findIndexedRayBoundaryDistances(track, origin, vector, lengthMeters, offsets) {
16
- const finiteOffsets = offsets.filter(Number.isFinite);
17
- if (finiteOffsets.length === 0) return { available: true, distances: [] };
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
- const maxOffset = Math.max(0, ...finiteOffsets.map((offset) => Math.abs(offset)));
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 segments = queryTrackSegmentsAlongRay(track, origin, vector, maxDistance, margin);
22
- if (!segments) return { available: false, distances: [] };
23
- const distances = finiteOffsets.map(() => Infinity);
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 (const segment of segments) {
26
- finiteOffsets.forEach((offset, offsetIndex) => {
27
- const start = offsetSegmentStart(segment, offset);
28
- const finish = offsetSegmentEnd(segment, offset);
29
- const distance = raySegmentIntersectionDistance(origin, vector, start, finish, maxDistance);
30
- if (distance != null && distance < distances[offsetIndex]) distances[offsetIndex] = distance;
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
- return {
35
- available: true,
36
- distances: distances.map((distance) => (Number.isFinite(distance) ? distance : null)),
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
- [trackHalfWidth, -trackHalfWidth, kerbOuterWidth, -kerbOuterWidth],
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 offsetSegmentStart(segment, offset) {
67
- return {
68
- x: segment.startX + segment.normalX * offset,
69
- y: segment.startY + segment.normalY * offset,
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 raySegmentIntersectionDistance(origin, ray, start, end, maxDistance) {
81
- const sx = end.x - start.x;
82
- const sy = end.y - start.y;
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 = start.x - origin.x;
87
- const oy = start.y - origin.y;
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(...values) {
101
- const minimum = Math.min(...values.filter((value) => Number.isFinite(value)));
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
+ }