feat(lab): separate current increment from rolling map

This commit is contained in:
DCCONSTRUCTIONS
2026-08-05 21:12:54 +03:00
parent 7aa3ce55c0
commit 31313c3c96
7 changed files with 165 additions and 37 deletions
@@ -10,7 +10,7 @@ export type LaboratoryMetricSceneMode = "3d" | "plan";
export interface LaboratoryMetricObstacleVisual {
id: string;
decision: LaboratoryMetricDecision;
state: "current" | "held" | "expired";
state: "current" | "retained" | "held" | "expired";
centroidBodyXyzM: LaboratoryMetricPoint3;
cellCentersBodyXyzM: readonly LaboratoryMetricPoint3[];
}
@@ -103,6 +103,8 @@ export function LaboratoryMetricEvidenceScene({
const controlsRef = useRef<OrbitControls | null>(null);
const contentRef = useRef<THREE.Group | null>(null);
const [renderError, setRenderError] = useState<string | null>(null);
const [showCurrentIncrement, setShowCurrentIncrement] = useState(true);
const [showRollingMap, setShowRollingMap] = useState(true);
useEffect(() => {
const host = hostRef.current;
@@ -185,24 +187,34 @@ export function LaboratoryMetricEvidenceScene({
child.traverse(disposeRenderable);
}
const contextGeometry = new THREE.BufferGeometry();
contextGeometry.setAttribute(
"position",
new THREE.BufferAttribute(positions(pointCloudBodyXyzM), 3),
);
content.add(new THREE.Points(
contextGeometry,
new THREE.PointsMaterial({
color: tokenColor(host, "--nodedc-text-muted", [147, 151, 159]),
size: 1.7,
sizeAttenuation: false,
transparent: true,
opacity: 0.34,
depthWrite: false,
}),
));
if (showCurrentIncrement) {
const contextGeometry = new THREE.BufferGeometry();
contextGeometry.setAttribute(
"position",
new THREE.BufferAttribute(positions(pointCloudBodyXyzM), 3),
);
content.add(new THREE.Points(
contextGeometry,
new THREE.PointsMaterial({
color: tokenColor(host, "--nodedc-text-muted", [147, 151, 159]),
size: 1.7,
sizeAttenuation: false,
transparent: true,
opacity: 0.34,
depthWrite: false,
}),
));
}
for (const obstacle of obstacles) {
if (
(obstacle.state === "current" && !showCurrentIncrement)
|| (obstacle.state === "retained" && !showRollingMap)
|| obstacle.state === "held"
|| obstacle.state === "expired"
) {
continue;
}
const color = decisionColor(host, obstacle.decision);
const cellsGeometry = new THREE.BufferGeometry();
cellsGeometry.setAttribute(
@@ -213,16 +225,19 @@ export function LaboratoryMetricEvidenceScene({
cellsGeometry,
new THREE.PointsMaterial({
color,
size: obstacle.state === "current" ? 4.8 : 3.8,
size: obstacle.state === "current" ? 4.8 : 5.2,
sizeAttenuation: false,
transparent: true,
opacity: obstacle.state === "current" ? 0.94 : 0.45,
opacity: obstacle.state === "current" ? 0.94 : 0.78,
depthWrite: false,
}),
));
const centroid = new THREE.Mesh(
new THREE.SphereGeometry(0.1, 16, 12),
new THREE.MeshBasicMaterial({ color, wireframe: obstacle.state !== "current" }),
new THREE.MeshBasicMaterial({
color,
wireframe: obstacle.state === "retained",
}),
);
centroid.position.fromArray(scenePoint(obstacle.centroidBodyXyzM));
centroid.userData.evidenceId = obstacle.id;
@@ -287,7 +302,14 @@ export function LaboratoryMetricEvidenceScene({
material.depthWrite = false;
});
content.add(grid);
}, [corridor, obstacles, pointCloudBodyXyzM, rig]);
}, [
corridor,
obstacles,
pointCloudBodyXyzM,
rig,
showCurrentIncrement,
showRollingMap,
]);
const resetView = () => {
const camera = cameraRef.current;
@@ -321,13 +343,30 @@ export function LaboratoryMetricEvidenceScene({
>
Сбросить ракурс
</Button>
<Button
variant={showCurrentIncrement ? "primary" : "secondary"}
size="compact"
aria-pressed={showCurrentIncrement}
onClick={() => setShowCurrentIncrement((visible) => !visible)}
>
CURRENT INCREMENT
</Button>
<Button
variant={showRollingMap ? "primary" : "secondary"}
size="compact"
aria-pressed={showRollingMap}
onClick={() => setShowRollingMap((visible) => !visible)}
>
ROLLING MAP
</Button>
<span>ЛКМ · вращение · колесо · масштаб · ПКМ · панорама</span>
</div>
<div className="laboratory-metric-evidence-scene__legend">
<span data-decision="threat">Угроза</span>
<span data-decision="not-threat">Вне коридора</span>
<span data-decision="unknown">Неизвестно</span>
<span data-decision="context">LiDAR context</span>
<span data-decision="context">Current increment</span>
<span data-decision="rolling">Rolling-map occupied</span>
</div>
</div>
);