feat(lab): project system obstacles into fisheye
This commit is contained in:
@@ -17,6 +17,7 @@ let synchronizeRecordedEvidencePlayback;
|
||||
let m4ThreatChunkWindowStarts;
|
||||
let cancelM4ThreatChunkRequestsOutsideWindow;
|
||||
let buildM4LocalSurface;
|
||||
let buildM4StaticObstacleBoxes;
|
||||
|
||||
const resultId = `m4-threat-replay-${"a".repeat(64)}`;
|
||||
|
||||
@@ -50,6 +51,9 @@ before(async () => {
|
||||
({ buildM4LocalSurface } = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/m4LocalSurface.ts",
|
||||
));
|
||||
({ buildM4StaticObstacleBoxes } = await server.ssrLoadModule(
|
||||
"/src/workspaces/laboratory/m4StaticObstacleBoxes.ts",
|
||||
));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
@@ -365,6 +369,8 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
camera_point_window_seconds: 2,
|
||||
camera_point_sample_limit: 20000,
|
||||
world_state_delivery: "source-paced-latest-wins",
|
||||
occupancy_provenance_delivery: "baseline-versus-additive-component-diff",
|
||||
camera_obstacle_projection_delivery: "factory-kb4-occupied-voxel-bounds",
|
||||
world_state_frame_count: 4481,
|
||||
superseded_frame_count: 8,
|
||||
local_surface_visualization: {
|
||||
@@ -392,9 +398,14 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
assert.equal(timeline.cameraPointWindowSeconds, 2);
|
||||
assert.equal(timeline.worldStateFrameCount, 4481);
|
||||
assert.equal(timeline.supersededFrameCount, 8);
|
||||
assert.equal(
|
||||
timeline.cameraObstacleProjectionDelivery,
|
||||
"factory-kb4-occupied-voxel-bounds",
|
||||
);
|
||||
|
||||
const chunk = await fetchM4ThreatTimelineChunk(replayResultId, 1, 1, {
|
||||
endpointRoot,
|
||||
cameraObstacleProjectionDelivery: timeline.cameraObstacleProjectionDelivery,
|
||||
fetcher: async (input) => {
|
||||
requested = String(input);
|
||||
return new Response(JSON.stringify({
|
||||
@@ -411,6 +422,30 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
camera_projected_point_count: 1,
|
||||
camera_projected_sample_count: 1,
|
||||
camera_projection: "factory-kb4-exact",
|
||||
metric_obstacles: [{
|
||||
component_id: "temporal-1855-7",
|
||||
state: "current",
|
||||
motion: "stationary",
|
||||
centroid_body_xyz_m: [2.4, 0.1, 0.3],
|
||||
cell_centers_body_xyz_m: [[2.4, 0.1, 0.3]],
|
||||
occupancy_source: "additive-low-step",
|
||||
camera_projection: {
|
||||
bbox_xyxy: [390.5, 280.25, 408.75, 318.5],
|
||||
nearest_depth_m: 2.3,
|
||||
projected_cell_count: 1,
|
||||
projection: "factory-kb4-occupied-voxel-bounds",
|
||||
authority: "visual-derived",
|
||||
},
|
||||
assessment: {
|
||||
component_id: "temporal-1855-7",
|
||||
decision: "threat",
|
||||
corridor_intersection: "intersects",
|
||||
relative_speed_mps: null,
|
||||
closest_approach_m: 0.2,
|
||||
ttc_seconds: null,
|
||||
reason_codes: ["current-corridor-intersection"],
|
||||
},
|
||||
}],
|
||||
camera_url: `${endpointRoot}/${replayResultId}/timeline/frames/1/camera`,
|
||||
})],
|
||||
authority: "replay-simulated",
|
||||
@@ -418,10 +453,18 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
},
|
||||
});
|
||||
assert.match(requested, new RegExp(`^${endpointRoot}/${replayResultId}/timeline/chunk`));
|
||||
assert.match(
|
||||
requested,
|
||||
/obstacle_projection=factory-kb4-occupied-voxel-bounds/,
|
||||
);
|
||||
assert.equal(chunk.frames[0].worldStateAvailable, false);
|
||||
assert.equal(chunk.frames[0].terminalOutcome, "superseded");
|
||||
assert.deepEqual(chunk.frames[0].cameraProjectedPointsXyd[0], [100.5, 200.25, 3.75]);
|
||||
assert.equal(chunk.frames[0].cameraProjection, "factory-kb4-exact");
|
||||
assert.deepEqual(
|
||||
chunk.frames[0].metricObstacles[0].cameraProjection.bboxXyxy,
|
||||
[390.5, 280.25, 408.75, 318.5],
|
||||
);
|
||||
|
||||
const overlay = await fetchM4ThreatCameraPointOverlay(replayResultId, 1, {
|
||||
endpointRoot,
|
||||
@@ -453,6 +496,43 @@ test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint"
|
||||
assert.equal(overlay.projection, "factory-kb4-causal-registered-accumulation");
|
||||
});
|
||||
|
||||
test("M4.8R3 turns active low-step components into native fisheye obstacle boxes", () => {
|
||||
const obstacle = {
|
||||
componentId: "temporal-1855-7",
|
||||
state: "current",
|
||||
motion: "stationary",
|
||||
centroidBodyXyzM: [2.4, 0.1, 0.3],
|
||||
cellCentersBodyXyzM: [[2.4, 0.1, 0.3]],
|
||||
occupancySource: "additive-low-step",
|
||||
cameraProjection: {
|
||||
bboxXyxy: [398, 298, 402, 302],
|
||||
nearestDepthM: 2.3,
|
||||
projectedCellCount: 1,
|
||||
projection: "factory-kb4-occupied-voxel-bounds",
|
||||
authority: "visual-derived",
|
||||
},
|
||||
assessment: {
|
||||
componentId: "temporal-1855-7",
|
||||
decision: "threat",
|
||||
corridorIntersection: "intersects",
|
||||
relativeSpeedMps: null,
|
||||
closestApproachM: 0.2,
|
||||
ttcSeconds: null,
|
||||
reasonCodes: ["current-corridor-intersection"],
|
||||
},
|
||||
};
|
||||
const boxes = buildM4StaticObstacleBoxes([
|
||||
obstacle,
|
||||
{ ...obstacle, componentId: "baseline", occupancySource: "baseline" },
|
||||
{ ...obstacle, componentId: "held", state: "held" },
|
||||
], 800, 600);
|
||||
assert.equal(boxes.length, 1);
|
||||
assert.deepEqual(boxes[0].boxXyxy, [394, 294, 406, 306]);
|
||||
assert.equal(boxes[0].label, "OBS #7 · 2,3 м");
|
||||
assert.equal(boxes[0].tone, "danger");
|
||||
assert.equal(boxes[0].dashed, false);
|
||||
});
|
||||
|
||||
test("M4.6 local SLAM surface reprojects registered increments into the active body frame", () => {
|
||||
const frames = [
|
||||
timelineFrame(0, 10, {
|
||||
@@ -603,6 +683,9 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(visual, /label: "3D"/);
|
||||
assert.match(visual, /label: "PLAN"/);
|
||||
assert.match(visual, />\s*POINTS\s*</);
|
||||
assert.match(visual, />\s*OBSTACLES\s*</);
|
||||
assert.match(visual, /useState\(true\);[\s\S]*setShowStaticObstacles/);
|
||||
assert.match(visual, /buildM4StaticObstacleBoxes/);
|
||||
assert.match(visual, /pointCloudOverlay=/);
|
||||
assert.match(visual, /mediaMode/);
|
||||
assert.match(visual, /spatialMode/);
|
||||
|
||||
Reference in New Issue
Block a user