feat(simulation): optimize and persist collision viewing
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
export type SimulationSceneType = "interior" | "outdoor" | "object";
|
||||
export type SimulationTransformAxis = "x" | "y" | "z";
|
||||
export type SimulationViewerQuality = "low" | "medium" | "high" | "ultra" | "maximum";
|
||||
export type SimulationProjectStatus =
|
||||
| "uploading"
|
||||
| "queued"
|
||||
@@ -32,6 +34,14 @@ export interface SimulationWorldManifest {
|
||||
};
|
||||
}
|
||||
|
||||
export interface SimulationViewerSettings {
|
||||
schemaVersion: "missioncore.simulation-viewer-settings/v1";
|
||||
quality: SimulationViewerQuality;
|
||||
visual: { inverted: boolean; axis: SimulationTransformAxis };
|
||||
collision: { inverted: boolean; axis: SimulationTransformAxis };
|
||||
camera: { invertHorizontal: boolean; invertVertical: boolean };
|
||||
}
|
||||
|
||||
export interface SimulationProject {
|
||||
schemaVersion: "missioncore.simulation-project/v1";
|
||||
projectId: string;
|
||||
@@ -60,6 +70,7 @@ export interface SimulationProject {
|
||||
byteLength: number;
|
||||
}>;
|
||||
worldManifest: SimulationWorldManifest | null;
|
||||
viewerSettings: SimulationViewerSettings;
|
||||
error: string | null;
|
||||
createdAtUtc: string;
|
||||
updatedAtUtc: string;
|
||||
@@ -223,6 +234,30 @@ export async function updateSimulationProject(
|
||||
return parseProject(await jsonResponse(response));
|
||||
}
|
||||
|
||||
export async function saveSimulationViewerSettings(
|
||||
projectId: string,
|
||||
settings: SimulationViewerSettings,
|
||||
): Promise<SimulationProject> {
|
||||
const response = await fetch(
|
||||
`${API_ROOT}/${encodeURIComponent(projectId)}/viewer-settings`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
schema_version: settings.schemaVersion,
|
||||
quality: settings.quality,
|
||||
visual: settings.visual,
|
||||
collision: settings.collision,
|
||||
camera: {
|
||||
invert_horizontal: settings.camera.invertHorizontal,
|
||||
invert_vertical: settings.camera.invertVertical,
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
return parseProject(await jsonResponse(response));
|
||||
}
|
||||
|
||||
export async function retrySimulationProject(projectId: string): Promise<SimulationProject> {
|
||||
const response = await fetch(`${API_ROOT}/${encodeURIComponent(projectId)}/build`, {
|
||||
method: "POST",
|
||||
@@ -251,7 +286,7 @@ function parseProject(value: unknown): SimulationProject {
|
||||
const record = objectValue(value, "simulation project");
|
||||
exactKeys(record, [
|
||||
"schema_version", "project_id", "name", "scene_type", "status", "source", "provider",
|
||||
"artifacts", "world_manifest", "error", "created_at_utc", "updated_at_utc",
|
||||
"artifacts", "world_manifest", "viewer_settings", "error", "created_at_utc", "updated_at_utc",
|
||||
], "simulation project");
|
||||
if (record.schema_version !== "missioncore.simulation-project/v1") {
|
||||
throw new Error("Проект симуляции вернул неподдерживаемую версию.");
|
||||
@@ -301,12 +336,47 @@ function parseProject(value: unknown): SimulationProject {
|
||||
};
|
||||
}),
|
||||
worldManifest: record.world_manifest === null ? null : parseWorldManifest(record.world_manifest),
|
||||
viewerSettings: parseViewerSettings(record.viewer_settings),
|
||||
error: nullableString(record.error, "project error"),
|
||||
createdAtUtc: stringValue(record.created_at_utc, "created at"),
|
||||
updatedAtUtc: stringValue(record.updated_at_utc, "updated at"),
|
||||
};
|
||||
}
|
||||
|
||||
function parseViewerSettings(value: unknown): SimulationViewerSettings {
|
||||
const record = objectValue(value, "viewer settings");
|
||||
exactKeys(record, ["schema_version", "quality", "visual", "collision", "camera"], "viewer settings");
|
||||
if (record.schema_version !== "missioncore.simulation-viewer-settings/v1") {
|
||||
throw new Error("Настройки сцены вернули неподдерживаемую версию.");
|
||||
}
|
||||
const visual = parseLayerViewerSettings(record.visual, "visual settings");
|
||||
const collision = parseLayerViewerSettings(record.collision, "collision settings");
|
||||
const camera = objectValue(record.camera, "camera settings");
|
||||
exactKeys(camera, ["invert_horizontal", "invert_vertical"], "camera settings");
|
||||
return {
|
||||
schemaVersion: "missioncore.simulation-viewer-settings/v1",
|
||||
quality: qualityValue(record.quality),
|
||||
visual,
|
||||
collision,
|
||||
camera: {
|
||||
invertHorizontal: booleanValue(camera.invert_horizontal, "horizontal camera inversion"),
|
||||
invertVertical: booleanValue(camera.invert_vertical, "vertical camera inversion"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function parseLayerViewerSettings(
|
||||
value: unknown,
|
||||
label: string,
|
||||
): { inverted: boolean; axis: SimulationTransformAxis } {
|
||||
const record = objectValue(value, label);
|
||||
exactKeys(record, ["inverted", "axis"], label);
|
||||
return {
|
||||
inverted: booleanValue(record.inverted, `${label} inversion`),
|
||||
axis: axisValue(record.axis),
|
||||
};
|
||||
}
|
||||
|
||||
function parseWorldManifest(value: unknown): SimulationWorldManifest {
|
||||
const record = objectValue(value, "world manifest");
|
||||
const visual = objectValue(record.visual, "visual manifest");
|
||||
@@ -396,6 +466,18 @@ function sceneTypeValue(value: unknown): SimulationSceneType {
|
||||
return invalid("scene type");
|
||||
}
|
||||
|
||||
function axisValue(value: unknown): SimulationTransformAxis {
|
||||
if (value === "x" || value === "y" || value === "z") return value;
|
||||
return invalid("transform axis");
|
||||
}
|
||||
|
||||
function qualityValue(value: unknown): SimulationViewerQuality {
|
||||
if (["low", "medium", "high", "ultra", "maximum"].includes(String(value))) {
|
||||
return value as SimulationViewerQuality;
|
||||
}
|
||||
return invalid("viewer quality");
|
||||
}
|
||||
|
||||
function statusValue(value: unknown): SimulationProjectStatus {
|
||||
if (["uploading", "queued", "processing", "importing", "ready", "failed"].includes(String(value))) {
|
||||
return value as SimulationProjectStatus;
|
||||
|
||||
Reference in New Issue
Block a user