Browse Source

feat: Add vehicle dimensions visualization and enhance track risk coloring

Vehicle Dimensions:
- Added "Show Dimensions" toggle to the display settings.
- Implemented `drawObjectDimensions` in `drawUtils.js` to render object extents as oriented rectangles based on `objectExtentRadii` and `objectExtentAngle`.
- Updated `radarSketch.js` to draw dimensions when enabled.
- Ensured dimensions and covariance ellipses are drawn at the `correctedPosition` for accurate alignment with track markers.

Track Visualization:
- Updated `drawTrajectories` to prioritize the `risk` property on track logs for coloring (0=Low/Blue, 1=Medium/Orange, 2=High/Red).
- Added fallback to `ttcCategoryTimeline` for backward compatibility.
- Fixed off-by-one error in trajectory history filtering to prevent drawing future points.

Frame Synchronization & UI:
- Refactored frame number display logic across Overlays, Data Explorer, and Timeline.
- UI now displays the actual `frameIdx` from the data source instead of the internal array index, resolving discrepancies between the Data Explorer and the main view.
refactor/sync-centralize
RUSHIL AMBARISH KADU 4 months ago
parent
commit
e13a734ab9
  1. 2
      steps/index.html
  2. 1
      steps/src/dom.js
  3. 123
      steps/src/drawUtils.js
  4. 34
      steps/src/p5/radarSketch.js
  5. 4
      steps/src/ui.js

2
steps/index.html

@ -318,6 +318,8 @@
(P)</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-covariance"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" /> Show Covariance</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox" id="toggle-vehicle-dimensions"
class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500" checked /> Show Dimensions</label>
<label class="flex items-center gap-2 text-sm cursor-pointer"><input type="checkbox"
id="toggle-confirmed-only" class="form-checkbox h-4 w-4 text-blue-600 rounded focus:ring-blue-500"
checked />

1
steps/src/dom.js

@ -71,6 +71,7 @@ export const modalCancelBtn = document.getElementById("modal-cancel-btn");
export const toggleCloseUp = document.getElementById("toggle-close-up");
export const togglePredictedPos = document.getElementById("toggle-predicted-pos");
export const toggleCovariance = document.getElementById("toggle-covariance");
export const toggleVehicleDimensions = document.getElementById("toggle-vehicle-dimensions");
export const modalProgressContainer = document.getElementById("modal-progress-container");
export const modalProgressBar = document.getElementById("modal-progress-bar");
export const modalProgressText = document.getElementById("modal-progress-text");

123
steps/src/drawUtils.js

@ -332,12 +332,12 @@ export function drawTrajectories(p, plotScales) {
}
const logs = track.historyLog.filter(
(log) => log.frameIdx <= appState.currentFrame + 1
(log) => log.frameIdx <= appState.currentFrame
);
if (logs.length < 2) continue;
const lastLog = logs[logs.length - 1];
if (appState.currentFrame + 1 - lastLog.frameIdx > MAX_TRAJECTORY_LENGTH)
if (appState.currentFrame - lastLog.frameIdx > MAX_TRAJECTORY_LENGTH)
continue;
const isCurrentlyStationary = lastLog.isStationary;
@ -388,34 +388,52 @@ export function drawTrajectories(p, plotScales) {
} else {
// MODE 2: DEFAULT TTC SCHEME (Use pre-calculated category from JSON)
// FIND the TTC category from the new timeline
let ttcCategory = null;
if (track.ttcCategoryTimeline) {
const ttcEntry = track.ttcCategoryTimeline.find(
(entry) => entry.frameIdx === lastLog.frameIdx
);
ttcCategory = ttcEntry ? ttcEntry.ttcCategory : null; // Get the category if found
}
// 1. Check for 'risk' property (New Logic)
if (lastLog.risk !== undefined && lastLog.risk !== null) {
switch (lastLog.risk) {
case 2: // High Risk
trajectoryColor = p.color(localTtcColors.critical); // Red
break;
case 1: // Medium Risk
trajectoryColor = p.color(localTtcColors.high); // Orange
break;
case 0: // Low Risk
trajectoryColor = p.color(localTtcColors.away); // Blue
break;
default:
trajectoryColor = p.color(localTtcColors.default); // Gray
break;
}
} else {
// 2. Fallback to 'ttcCategoryTimeline' (Old Logic)
let ttcCategory = null;
if (track.ttcCategoryTimeline) {
const ttcEntry = track.ttcCategoryTimeline.find(
(entry) => entry.frameIdx === lastLog.frameIdx
);
ttcCategory = ttcEntry ? ttcEntry.ttcCategory : null; // Get the category if found
}
switch (ttcCategory) {
case 3:
trajectoryColor = p.color(localTtcColors.critical);
break;
case 2:
trajectoryColor = p.color(localTtcColors.high);
break;
case 1:
trajectoryColor = p.color(localTtcColors.medium);
break;
case 0:
trajectoryColor = p.color(localTtcColors.low);
break;
case -1:
trajectoryColor = p.color(localTtcColors.away);
break;
default:
trajectoryColor = p.color(localTtcColors.default);
break;
switch (ttcCategory) {
case 3:
trajectoryColor = p.color(localTtcColors.critical);
break;
case 2:
trajectoryColor = p.color(localTtcColors.high);
break;
case 1:
trajectoryColor = p.color(localTtcColors.medium);
break;
case 0:
trajectoryColor = p.color(localTtcColors.low);
break;
case -1:
trajectoryColor = p.color(localTtcColors.away);
break;
default:
trajectoryColor = p.color(localTtcColors.default);
break;
}
}
}
@ -522,10 +540,15 @@ export function drawTrackMarkers(p, plotScales) {
// Defer Text Drawing
const speed = (Math.sqrt(vx * vx + vy * vy) * 3.6).toFixed(1);
let ttcText =
log.ttc !== null && isFinite(log.ttc) && log.ttc < 100
? `TTC: ${log.ttc.toFixed(1)}s`
: "";
let ttcText = "";
if ("tti" in log) {
const tti = log.tti;
if (typeof tti === "number" && isFinite(tti)) {
ttcText = `TTI: ${tti.toFixed(1)}s`;
}
} else if (log.ttc !== null && isFinite(log.ttc) && log.ttc < 100) {
ttcText = `TTC: ${log.ttc.toFixed(1)}s`;
}
if (log.state !== undefined && log.state !== null) {
ttcText += ttcText ? ` | st: ${log.state}` : `st: ${log.state}`;
}
@ -886,6 +909,40 @@ export function drawCovarianceEllipse(
}
}
export function drawObjectDimensions(
p,
position,
dims,
angle,
plotScales,
isStationary
) {
try {
if (isStationary) return;
const [dimA, dimB] = dims;
const angledegrees = 90 + angle;
p.push();
p.noFill();
p.stroke(128, 0, 128, 150); // Purple
p.strokeWeight(1);
p.translate(
position[0] * plotScales.plotScaleX,
position[1] * plotScales.plotScaleY
);
p.rotate(p.radians(angledegrees));
p.rectMode(p.CENTER);
p.rect(
0,
0,
dimA * 2 * plotScales.plotScaleX,
dimB * 2 * plotScales.plotScaleY
);
p.pop();
} catch (error) {
console.error("Error in drawObjectDimensions:", error);
}
}
export function drawEgoVehicle(p, plotScales) {
try {

34
steps/src/p5/radarSketch.js

@ -14,6 +14,7 @@ import {
togglePredictedPos,
toggleCovariance,
toggleVelocity,
toggleVehicleDimensions,
toggleClusterColor,
} from "../dom.js";
import {
@ -26,6 +27,7 @@ import {
snrColors,
handleCloseUpDisplay,
drawCovarianceEllipse,
drawObjectDimensions,
ttcColors,
drawRegionsOfInterest,
drawClusterCentroids,
@ -203,15 +205,13 @@ export const radarSketch = function (p) {
// }
if (togglePredictedPos.checked) {
for (const track of appState.vizData.tracks) {
const log = track.historyLog.find(
(log) => log.frameIdx === appState.currentFrame
);
const log = track.historyLog.find((log) => log.frameIdx === appState.currentFrame);
if (
log &&
log.predictedPosition &&
log.predictedPosition[0] !== null
) {
const pos = log.predictedPosition;
const pos = log.predictedPosition; //using predicted position from data
const x = pos[0] * plotScales.plotScaleX;
const y = pos[1] * plotScales.plotScaleY;
@ -230,8 +230,7 @@ export const radarSketch = function (p) {
if (toggleCovariance.checked) {
for (const track of appState.vizData.tracks) {
const log = track.historyLog.find(
(log) => log.frameIdx === appState.currentFrame + 1
);
(log) => log.frameIdx === appState.currentFrame);
if (
log &&
log.ellipseRadii &&
@ -251,6 +250,29 @@ export const radarSketch = function (p) {
}
}
}
if (toggleVehicleDimensions.checked) {
for (const track of appState.vizData.tracks) {
const log = track.historyLog.find(
(log) => log.frameIdx === appState.currentFrame);
if (
log &&
log.objectExtentRadii &&
typeof log.objectExtentAngle !== "undefined"
) {
const pos = log.correctedPosition;
if (pos && pos[0] !== null) {
drawObjectDimensions(
p,
pos,
log.objectExtentRadii,
log.objectExtentAngle,
plotScales,
log.isStationary
);
}
}
}
}
}
// Draw cluster centroids if enabled

4
steps/src/ui.js

@ -18,6 +18,8 @@ import {
toggleDebugOverlay,
toggleDebug2Overlay,
toggleCloseUp,
toggleCovariance,
toggleVehicleDimensions,
snrMinInput,
snrMaxInput,
applySnrBtn,
@ -185,7 +187,7 @@ export function initUIEventListeners() {
t.addEventListener("change", handleColorToggles);
});
[toggleVelocity, toggleEgoSpeed, toggleFrameNorm, toggleTracks, toggleDebugOverlay, toggleDebug2Overlay].forEach((t) => {
[toggleVelocity, toggleEgoSpeed, toggleFrameNorm, toggleTracks, toggleDebugOverlay, toggleDebug2Overlay, toggleCovariance, toggleVehicleDimensions].forEach((t) => {
t.addEventListener("change", () => {
if (appState.p5_instance) appState.p5_instance.redraw();
if (t === toggleDebugOverlay || t === toggleDebug2Overlay) {

Loading…
Cancel
Save