Visualizer work
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

139 lines
4.5 KiB

export function parseJsonWithOboe(fileURL, onComplete, onError, onProgress) {
const vizData = {
radarFrames: [],
tracks: [],
};
oboe(fileURL)
.node("radarFrames[*]", (frame) => {
vizData.radarFrames.push(frame);
return oboe.drop;
})
.node("tracks[*]", (track) => {
vizData.tracks.push(track);
return oboe.drop;
})
// Add the progress listener
.on("progress", (progress) => {
// Oboe.js provides a progress object with a 'percent' property
if (onProgress) {
onProgress(progress.percent);
}
})
.done(() => {
console.log("Oboe.js parsing complete.");
onComplete(vizData);
})
.fail((err) => {
console.error("Oboe.js parsing failed:", err);
onError(
"Error parsing JSON stream. Please check file format and console."
);
});
}
//--------------------JSON POST-PROCESSOR (ASYNCHRONOUS & SAFE)------------------------//
// Helper function to process large arrays in chunks without blocking
async function processArrayInChunks(array, chunkSize, processingFn) {
for (let i = 0; i < array.length; i += chunkSize) {
const chunk = array.slice(i, i + chunkSize);
processingFn(chunk);
await new Promise((resolve) => setTimeout(resolve, 0));
}
}
export async function parseVisualizationJson(
vizData,
radarStartTimeMs,
videoStartDate
) {
try {
if (!vizData.radarFrames || vizData.radarFrames.length === 0) {
return {
error: "Error: The JSON file does not contain any radar frames.",
};
}
// Calculate offset: (Radar Start - Video Start). Defaults to 0 if Video Start is unknown.
let offset = 0;
if (videoStartDate && radarStartTimeMs) {
offset = radarStartTimeMs - videoStartDate.getTime();
}
// Always populate timestampMs (Time relative to video start, in ms)
await processArrayInChunks(vizData.radarFrames, 5000, (chunk) => {
chunk.forEach((frame) => {
// frame.timestamp is assumed to be ms from the radar log start.
// We add the offset to align it with the video timeline.
frame.timestampMs = frame.timestamp + offset;
});
});
// Calculate interFrameTime for each frame
const radarFrames = vizData.radarFrames;
for (let i = 0; i < radarFrames.length; i++) {
if (i < radarFrames.length - 1) {
radarFrames[i].interFrameTime = radarFrames[i + 1].timestampMs - radarFrames[i].timestampMs;
} else {
// Last frame edge case: set its interFrameTime equal to the previous frame's interFrameTime
if (radarFrames.length > 1) {
radarFrames[i].interFrameTime = radarFrames[i - 1].interFrameTime;
} else {
radarFrames[i].interFrameTime = 0; // Only one frame, so interFrameTime is 0
}
}
}
// --- Pre-calculate Max Window IFT for Smart Zoom (Sliding Window) ---
// This eliminates the need for real-time lookahead scanning in the render loop.
const lookahead = 80;
for (let i = 0; i < radarFrames.length; i++) {
let localMax = 0;
const start = Math.max(0, i - lookahead);
const end = Math.min(radarFrames.length - 1, i + lookahead);
for (let j = start; j <= end; j++) {
const val = radarFrames[j].interFrameTime || 0;
if (val > localMax) localMax = val;
}
radarFrames[i].maxWindowIFT = localMax;
}
let snrValues = [];
let totalPoints = 0;
await processArrayInChunks(vizData.radarFrames, 5000, (chunk) => {
chunk.forEach((frame) => {
if (frame.pointCloud && frame.pointCloud.length > 0) {
totalPoints += frame.pointCloud.length;
frame.pointCloud.forEach((p) => {
if (p.snr !== null) snrValues.push(p.snr);
});
}
});
});
if (totalPoints === 0) {
console.warn("Warning: Loaded frames contain no point cloud data.");
}
// --- FINAL FIX IS HERE ---
// Manually calculate min and max to avoid stack overflow
let minSnr = 0;
let maxSnr = 1;
if (snrValues.length > 0) {
minSnr = snrValues[0];
maxSnr = snrValues[0];
for (let i = 1; i < snrValues.length; i++) {
if (snrValues[i] < minSnr) minSnr = snrValues[i];
if (snrValues[i] > maxSnr) maxSnr = snrValues[i];
}
}
// --- END OF FIX ---
return { data: vizData, minSnr: minSnr, maxSnr: maxSnr };
} catch (error) {
console.error("JSON Processing Error:", error);
return { error: "Error processing the JSON data. Error: " + error.message };
}
}