feat(lab): add bounded local SLAM surface

This commit is contained in:
DCCONSTRUCTIONS
2026-08-06 09:41:25 +03:00
parent b8fb4ebcba
commit b7a51e26e6
10 changed files with 369 additions and 8 deletions
@@ -13,6 +13,7 @@ let selectM4ThreatTimelineFrame;
let selectM4ThreatTimelineSequence;
let advanceRecordedEvidencePlayback;
let m4ThreatChunkWindowStarts;
let buildM4LocalSurface;
const resultId = `m4-threat-replay-${"a".repeat(64)}`;
@@ -36,6 +37,9 @@ before(async () => {
({ m4ThreatChunkWindowStarts } = await server.ssrLoadModule(
"/src/workspaces/laboratory/useM4ThreatTimeline.ts",
));
({ buildM4LocalSurface } = await server.ssrLoadModule(
"/src/core/laboratory/m4LocalSurface.ts",
));
});
after(async () => {
@@ -65,6 +69,10 @@ function timelineFrame(sequence, sessionSeconds, overrides = {}) {
session_seconds: sessionSeconds,
source_available: true,
spatial_available: true,
body_frame: {
origin_map_xyz_m: [sequence, 0, 0],
basis_map_from_body: [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
},
point_cloud_body_xyz_m: [[1, 0, 0.1]],
point_cloud_source_count: 1,
point_cloud_sample_count: 1,
@@ -262,6 +270,14 @@ test("M4.6 timeline keeps only a compact index and decodes bounded spatial chunk
point_sample_limit: 4096,
maximum_source_points_per_frame: 3092,
point_delivery: "exact-current-increment",
local_surface_visualization: {
derivation: "bounded-registered-increment-accumulation",
window_seconds: 2,
voxel_size_m: 0.1,
radius_m: 12,
point_limit: 20000,
authority: "visual-derived",
},
rig: { length_m: 1, width_m: 0.6, nominal_sensor_height_m: 1.25 },
corridor: {
forward_length_m: 8,
@@ -277,6 +293,8 @@ test("M4.6 timeline keeps only a compact index and decodes bounded spatial chunk
assert.equal(timeline.pointDelivery, "exact-current-increment");
assert.equal(timeline.maximumSourcePointsPerFrame, 3092);
assert.equal(timeline.occupiedVoxelSizeM, 0.45);
assert.equal(timeline.localSurfaceVisualization.windowSeconds, 2);
assert.equal(timeline.localSurfaceVisualization.authority, "visual-derived");
assert.equal(selectM4ThreatTimelineSequence(timeline.frameTimesNs, 35.50), 1);
const chunk = await fetchM4ThreatTimelineChunk(resultId, 0, 2, {
@@ -300,6 +318,54 @@ test("M4.6 timeline keeps only a compact index and decodes bounded spatial chunk
assert.equal(selectM4ThreatTimelineFrame(chunk.frames, 35.50).sequence, 1);
});
test("M4.6 local SLAM surface reprojects registered increments into the active body frame", () => {
const frames = [
timelineFrame(0, 10, {
body_frame: {
origin_map_xyz_m: [0, 0, 0],
basis_map_from_body: [[0, -1, 0], [1, 0, 0], [0, 0, 1]],
},
point_cloud_body_xyz_m: [[1, 0, 0]],
}),
timelineFrame(1, 10.1, {
body_frame: {
origin_map_xyz_m: [0, 0, 0],
basis_map_from_body: [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
},
point_cloud_body_xyz_m: [[1, 0, 0]],
}),
].map((raw, index) => ({
sequence: raw.sequence,
frameId: raw.frame_id,
sourceTimeNs: raw.source_time_ns,
sessionSeconds: raw.session_seconds,
sourceAvailable: true,
spatialAvailable: true,
bodyFrame: {
originMapXyzM: raw.body_frame.origin_map_xyz_m,
basisMapFromBody: raw.body_frame.basis_map_from_body,
},
pointCloudBodyXyzM: raw.point_cloud_body_xyz_m,
pointCloudSourceCount: 1,
pointCloudSampleCount: 1,
pointCloudLayer: "current-increment",
rollingMapComponentCount: 0,
metricObstacles: [],
cameraProposals: [],
decisionCounts: { threat: 0, "not-threat": 0, unknown: 0 },
cameraUrl: raw.camera_url,
}));
const surface = buildM4LocalSurface(frames, frames[1], {
windowSeconds: 2,
voxelSizeM: 0.1,
radiusM: 12,
pointLimit: 20_000,
});
assert.equal(surface.sourceFrameCount, 2);
assert.equal(surface.sourcePointCount, 2);
assert.deepEqual(surface.pointsBodyXyzM, [[0, 1, 0], [1, 0, 0]]);
});
test("M4.6 spatial buffering keeps previous, active and two future chunks", () => {
assert.deepEqual(m4ThreatChunkWindowStarts(48, 24, 4489), [24, 48, 72, 96]);
assert.deepEqual(m4ThreatChunkWindowStarts(0, 24, 4489), [0, 24, 48]);
@@ -345,8 +411,9 @@ test("M4.6 viewer reuses shared camera, video and metric evidence renderers", as
assert.match(videoScene, /<RecordedFmp4Player/);
assert.match(imageScene, /<RecordedEvidenceBoxOverlay/);
assert.match(metricScene, /OrbitControls/);
assert.match(visual, /CURRENT INCREMENT/);
assert.match(visual, /ROLLING MAP/);
assert.match(visual, /LOCAL SLAM/);
assert.match(visual, /showLocalSurface/);
assert.match(metricScene, /Local SLAM surface/);
assert.match(visual, /showJumpToEnd=\{false\}/);
assert.doesNotMatch(metricScene, /ЛКМ · вращение/);
});