Share the K1 live scene template and preserve idle media channels
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import {SceneDisplayControls} from "../../../packages/spatial-ui/src/SceneDisplayControls";
|
||||
import {SceneLayerControls} from "../../../packages/spatial-ui/src/SceneLayerControls";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
AdminNavigationPanel,
|
||||
@@ -5,15 +7,11 @@ import {
|
||||
ApplicationPanel,
|
||||
ApplicationShell,
|
||||
Button,
|
||||
Checker,
|
||||
ColorField,
|
||||
ControlRow,
|
||||
HeaderNavigation,
|
||||
HeaderProfile,
|
||||
Icon,
|
||||
Inspector,
|
||||
RangeControl,
|
||||
Select,
|
||||
StatusBadge,
|
||||
TextField,
|
||||
UserProfileMenu,
|
||||
@@ -66,8 +64,6 @@ import {
|
||||
import { backendLabel, localConnectionPhaseLabel, phaseTone } from "./presentation";
|
||||
import {
|
||||
defaultSceneSettings,
|
||||
type PointColorMode,
|
||||
type PointPalette,
|
||||
type SceneSettings,
|
||||
} from "./sceneSettings";
|
||||
import { DeviceWorkspace } from "./workspaces/DeviceWorkspace";
|
||||
@@ -77,22 +73,6 @@ import "./styles/scene-windows.css";
|
||||
type SceneToolWindowId = "sources" | "display" | "layers";
|
||||
const viewerSettingsQuietPeriodMs = 750;
|
||||
|
||||
const colorModeOptions: Array<{ value: PointColorMode; label: string; description: string }> = [
|
||||
{ value: "intensity", label: "Интенсивность", description: "Значение отражённого сигнала" },
|
||||
{ value: "height", label: "Высота Z", description: "Градиент по вертикальной координате" },
|
||||
{ value: "distance", label: "Расстояние", description: "Дальность точки от сенсора" },
|
||||
{ value: "rgb", label: "RGB", description: "Цвет, если он присутствует в данных" },
|
||||
{ value: "class", label: "Класс", description: "Категория внешнего модуля восприятия" },
|
||||
];
|
||||
|
||||
const paletteOptions: Array<{ value: PointPalette; label: string; description: string }> = [
|
||||
{ value: "turbo", label: "Turbo", description: "Контрастный спектральный градиент" },
|
||||
{ value: "viridis", label: "Viridis", description: "Равномерный перцептивный градиент" },
|
||||
{ value: "plasma", label: "Plasma", description: "Тёплый контрастный градиент" },
|
||||
{ value: "grayscale", label: "Серый", description: "Монохромное отображение" },
|
||||
{ value: "custom", label: "Свой цвет", description: "Один назначенный цвет" },
|
||||
];
|
||||
|
||||
interface LivePerceptionLayers {
|
||||
detections2d: boolean;
|
||||
segmentation: boolean;
|
||||
@@ -1029,132 +1009,8 @@ export default function App() {
|
||||
onPointerDown={() => activateSceneWindow("display")}
|
||||
onClose={() => closeSceneWindow("display")}
|
||||
>
|
||||
<Inspector
|
||||
defaultOpen={["points"]}
|
||||
singleOpen
|
||||
sections={[
|
||||
{
|
||||
id: "points",
|
||||
label: "Облако точек",
|
||||
description: "Размер и способ окрашивания",
|
||||
content: (
|
||||
<div className="inspector-control-stack">
|
||||
<div
|
||||
className="scene-settings-commit-field"
|
||||
onPointerUp={flushDisplaySettings}
|
||||
onKeyUp={flushDisplaySettings}
|
||||
onBlur={flushDisplaySettings}
|
||||
>
|
||||
<RangeControl
|
||||
label="Размер точки"
|
||||
value={displayDraft.pointSize}
|
||||
min={0.5}
|
||||
max={12}
|
||||
step={0.5}
|
||||
formatValue={(value) => `${value.toFixed(1)} пкс`}
|
||||
onChange={(pointSize) => stageDisplayPatch({ pointSize })}
|
||||
/>
|
||||
</div>
|
||||
<div className="scene-settings-commit-field" onBlur={flushDisplaySettings}>
|
||||
<ControlRow label="Атрибут цвета">
|
||||
<Select
|
||||
variant="split"
|
||||
label="Атрибут цвета"
|
||||
value={displayDraft.colorMode}
|
||||
options={colorModeOptions}
|
||||
onChange={(colorMode) => stageDisplayPatch({ colorMode })}
|
||||
/>
|
||||
</ControlRow>
|
||||
</div>
|
||||
<div className="scene-settings-commit-field" onBlur={flushDisplaySettings}>
|
||||
<ControlRow label="Палитра">
|
||||
<Select
|
||||
variant="split"
|
||||
label="Палитра"
|
||||
value={displayDraft.palette}
|
||||
options={paletteOptions}
|
||||
onChange={(palette) => stageDisplayPatch({ palette })}
|
||||
/>
|
||||
</ControlRow>
|
||||
</div>
|
||||
{displayDraft.palette === "custom" || displayDraft.colorMode === "class" ? (
|
||||
<div
|
||||
className="scene-settings-commit-field"
|
||||
onPointerUp={flushDisplaySettings}
|
||||
onKeyUp={flushDisplaySettings}
|
||||
onBlur={flushDisplaySettings}
|
||||
>
|
||||
<ControlRow label="Цвет точек">
|
||||
<ColorField
|
||||
label="Цвет точек"
|
||||
value={displayDraft.customColor}
|
||||
onChange={(customColor) => stageDisplayPatch({ customColor })}
|
||||
/>
|
||||
</ControlRow>
|
||||
</div>
|
||||
) : null}
|
||||
{replayPresented ? (
|
||||
<p className="scene-window-note">
|
||||
Первый новый режим читает индекс архивных точек. Следующие палитры
|
||||
переключаются из подготовленного цветового кэша без переэкспорта геометрии.
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "history",
|
||||
label: "Накопление и время",
|
||||
description: "История облака и траектория",
|
||||
content: (
|
||||
<div className="inspector-control-stack">
|
||||
<div
|
||||
className="scene-settings-commit-field"
|
||||
onPointerUp={flushDisplaySettings}
|
||||
onKeyUp={flushDisplaySettings}
|
||||
onBlur={flushDisplaySettings}
|
||||
>
|
||||
<RangeControl
|
||||
label="Окно накопления"
|
||||
value={displayDraft.accumulationSeconds}
|
||||
min={0}
|
||||
max={120}
|
||||
step={1}
|
||||
formatValue={(value) => (value === 0 ? "Только кадр" : `${value} с`)}
|
||||
onChange={(accumulationSeconds) => stageDisplayPatch({ accumulationSeconds })}
|
||||
/>
|
||||
</div>
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Линия пути устройства в координатах сцены</span>
|
||||
<Checker
|
||||
checked={displayDraft.showTrajectory}
|
||||
label="Показывать траекторию"
|
||||
onChange={(showTrajectory) => commitDisplayPatch({ showTrajectory })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "scene",
|
||||
label: "Окружение сцены",
|
||||
description: "Сетка, подписи и камеры",
|
||||
content: (
|
||||
<div className="inspector-control-stack">
|
||||
<Checker checked={displayDraft.showGrid} label="Сетка и оси" onChange={(showGrid) => commitDisplayPatch({ showGrid })} />
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Появятся после подключения семантических сущностей</span>
|
||||
<Checker checked={false} disabled label="Подписи сущностей" onChange={() => undefined} />
|
||||
</div>
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Камерный канал пока не подключён</span>
|
||||
<Checker checked={false} disabled label="Области обзора камер" onChange={() => undefined} />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<SceneDisplayControls displayDraft={displayDraft} stageDisplayPatch={stageDisplayPatch}
|
||||
commitDisplayPatch={commitDisplayPatch} flushDisplaySettings={flushDisplaySettings} replayPresented={replayPresented}/>
|
||||
</Window>
|
||||
|
||||
<Window
|
||||
@@ -1180,64 +1036,7 @@ export default function App() {
|
||||
</span>
|
||||
<p>Структура повторяет продуктовые сущности, а не внутренние панели визуального движка.</p>
|
||||
</div>
|
||||
<Inspector
|
||||
defaultOpen={["geometry"]}
|
||||
singleOpen
|
||||
sections={[
|
||||
{
|
||||
id: "geometry",
|
||||
label: "Геометрия",
|
||||
description: "Облако точек и путь",
|
||||
content: (
|
||||
<div className="inspector-control-stack">
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Основной поток геометрии лидара</span>
|
||||
<Checker disabled={runtime.pendingAction === "viewer"} checked={sceneSettings.showPoints} label="Облако точек" onChange={(showPoints) => void applyScenePatch({ showPoints })} />
|
||||
</div>
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Положение и ориентация устройства во времени</span>
|
||||
<Checker disabled={runtime.pendingAction === "viewer"} checked={sceneSettings.showTrajectory} label="Траектория" onChange={(showTrajectory) => void applyScenePatch({ showTrajectory })} />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "frames",
|
||||
label: "Координаты и камеры",
|
||||
description: "Преобразования и области обзора",
|
||||
content: (
|
||||
<div className="inspector-control-stack">
|
||||
<Checker disabled={runtime.pendingAction === "viewer"} checked={sceneSettings.showGrid} label="Сетка и оси" onChange={(showGrid) => void applyScenePatch({ showGrid })} />
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Камерный канал пока не подключён</span>
|
||||
<Checker checked={false} disabled label="Области обзора камер" onChange={() => undefined} />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "perception",
|
||||
label: "Объекты и маски",
|
||||
description: "Ожидают внешние обработчики",
|
||||
content: (
|
||||
<div className="inspector-control-stack">
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Внешний обработчик не подключён</span>
|
||||
<Checker checked={false} disabled label="Рамки 2D и 3D" onChange={() => undefined} />
|
||||
</div>
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Внешний обработчик не подключён</span>
|
||||
<Checker checked={false} disabled label="Маски сегментации" onChange={() => undefined} />
|
||||
</div>
|
||||
<div className="nodedc-field">
|
||||
<span className="nodedc-field__description">Внешний обработчик не подключён</span>
|
||||
<Checker checked={false} disabled label="Ключевые точки и треки" onChange={() => undefined} />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<SceneLayerControls sceneSettings={sceneSettings} pending={runtime.pendingAction === "viewer"} applyScenePatch={applyScenePatch}/>
|
||||
</Window>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user