feat: 添加导入场景文件支持,优化坐标转换逻辑以处理反向坐标转换

This commit is contained in:
xudan 2025-08-04 14:57:12 +08:00
parent 72f0415f27
commit 0728911ef7
3 changed files with 93 additions and 13 deletions

View File

@ -63,7 +63,7 @@ const importScene = async () => {
const file = await selectFile('.scene');
if (!file?.size) return;
const json = await decodeTextFile(file);
editor.value?.load(json, editable.value, detail.value ?? {});
editor.value?.load(json, editable.value, detail.value ?? {}, true); // isImport=true
};
const exportScene = () => {
const json = editor.value?.save();

View File

@ -100,7 +100,7 @@ const importScene = async () => {
const file = await selectFile('.scene');
if (!file?.size) return;
const json = await decodeTextFile(file);
editor.value?.load(json, editable.value);
editor.value?.load(json, editable.value, undefined, true); // isImport=true
};
const exportScene = () => {
const json = editor.value?.save();

View File

@ -45,8 +45,14 @@ export class EditorService extends Meta2d {
* @param map JSON字符串
* @param editable
* @param detail
* @param isImport true时进行反向坐标转换
*/
public async load(map?: string, editable = false, detail?: Partial<GroupSceneDetail>): Promise<void> {
public async load(
map?: string,
editable = false,
detail?: Partial<GroupSceneDetail>,
isImport = false,
): Promise<void> {
const scene: StandardScene = map ? JSON.parse(map) : {};
if (!isEmpty(detail?.group)) {
scene.robotGroups = [detail.group];
@ -59,9 +65,9 @@ export class EditorService extends Meta2d {
this.open();
this.setState(editable);
this.#loadRobots(robotGroups, robots);
await this.#loadScenePoints(points);
this.#loadSceneRoutes(routes);
await this.#loadSceneAreas(areas);
await this.#loadScenePoints(points, isImport);
this.#loadSceneRoutes(routes, isImport);
await this.#loadSceneAreas(areas, isImport);
this.store.historyIndex = undefined;
this.store.histories = [];
// this.scale(scale);与xd 自定义缩放冲突,暂时去掉
@ -105,13 +111,22 @@ export class EditorService extends Meta2d {
/**
*
* @param points
* @param isImport true时进行反向坐标转换
*/
async #loadScenePoints(points?: StandardScenePoint[]): Promise<void> {
async #loadScenePoints(points?: StandardScenePoint[], isImport = false): Promise<void> {
if (!points?.length) return;
await Promise.all(
points.map(async (v) => {
const { id, name, desc, x, y, type, extensionType, robots, actions, properties, deviceId, enabled } = v;
await this.addPoint({ x, y }, type, id);
// 只有在导入场景文件时才进行反向坐标转换
let finalX = x;
let finalY = y;
if (isImport) {
const transformedCoords = this.#reverseTransformCoordinate(x, y);
finalX = transformedCoords.x;
finalY = transformedCoords.y;
}
await this.addPoint({ x: finalX, y: finalY }, type, id);
this.setValue(
{ id, label: name, desc, properties, point: { type, extensionType, robots, actions, deviceId, enabled } },
{ render: false, history: false, doEvent: false },
@ -122,8 +137,9 @@ export class EditorService extends Meta2d {
/**
* 线
* @param routes 线
* @param isImport true时进行反向坐标转换
*/
#loadSceneRoutes(routes?: StandardSceneRoute[]): void {
#loadSceneRoutes(routes?: StandardSceneRoute[], isImport = false): void {
if (!routes?.length) return;
routes.map((v) => {
const { id, desc, from, to, type, pass, c1, c2, properties } = v;
@ -133,6 +149,23 @@ export class EditorService extends Meta2d {
this.addRoute([p1, p2], <MapRouteType>type, id);
const { x: x1, y: y1 } = this.getPointRect(p1)!;
const { x: x2, y: y2 } = this.getPointRect(p2)!;
// 只有在导入场景文件时才对控制点坐标进行反向转换
let transformedC1 = { x: (c1?.x ?? 0) - x1, y: (c1?.y ?? 0) - y1 };
let transformedC2 = { x: (c2?.x ?? 0) - x2, y: (c2?.y ?? 0) - y2 };
if (isImport) {
if (c1 && c1.x !== undefined && c1.y !== undefined) {
const reversedC1 = this.#reverseTransformCoordinate(c1.x, c1.y);
transformedC1 = { x: reversedC1.x - x1, y: reversedC1.y - y1 };
}
if (c2 && c2.x !== undefined && c2.y !== undefined) {
const reversedC2 = this.#reverseTransformCoordinate(c2.x, c2.y);
transformedC2 = { x: reversedC2.x - x2, y: reversedC2.y - y2 };
}
}
this.setValue(
{
id,
@ -141,20 +174,39 @@ export class EditorService extends Meta2d {
route: {
type,
pass,
c1: { x: (c1?.x ?? 0) - x1, y: (c1?.y ?? 0) - y1 },
c2: { x: (c2?.x ?? 0) - x2, y: (c2?.y ?? 0) - y2 },
c1: transformedC1,
c2: transformedC2,
},
},
{ render: false, history: false, doEvent: false },
);
});
}
async #loadSceneAreas(areas?: StandardSceneArea[]): Promise<void> {
/**
*
* @param areas
* @param isImport true时进行反向坐标转换
*/
async #loadSceneAreas(areas?: StandardSceneArea[], isImport = false): Promise<void> {
if (!areas?.length) return;
await Promise.all(
areas.map(async (v) => {
const { id, name, desc, x, y, w, h, type, points, routes, maxAmr, inoutflag, storageLocations, properties } = v;
await this.addArea({ x, y }, { x: x + w, y: y + h }, type, id);
// 只有在导入场景文件时才进行反向坐标转换
let finalX = x;
let finalY = y;
let finalW = w;
let finalH = h;
if (isImport) {
const transformedCoords = this.#reverseTransformCoordinate(x, y);
finalX = transformedCoords.x;
finalY = transformedCoords.y;
finalW = this.#reverseTransformSize(w);
finalH = this.#reverseTransformSize(h);
}
await this.addArea({ x: finalX, y: finalY }, { x: finalX + finalW, y: finalY + finalH }, type, id);
// 对于库区类型需要将点位名称数组转换为点位ID数组并更新动作点的库位信息
let processedPoints = points;
@ -503,6 +555,34 @@ export class EditorService extends Meta2d {
return this.#fixPrecision(scaledSize);
}
/** 反向坐标转换方法 - 将中心点原点的坐标转换为左上角原点的坐标 */
#reverseTransformCoordinate(x: number, y: number): { x: number; y: number } {
const { ratio = 1, width = 0, height = 0 } = this.#originalSceneData ?? {};
// 先进行坐标系转换:中心点原点 -> 左上角原点
const topLeftX = x + width / 2;
const topLeftY = height / 2 - y;
// 再根据ratio进行缩放
const scaledX = topLeftX * ratio;
const scaledY = topLeftY * ratio;
// 应用精度控制保留3位小数之后直接舍去
return {
x: this.#fixPrecision(scaledX),
y: this.#fixPrecision(scaledY),
};
}
/** 反向尺寸转换方法 - 根据ratio还原尺寸 */
#reverseTransformSize(size: number): number {
const { ratio = 1 } = this.#originalSceneData ?? {};
const scaledSize = size * ratio;
// 应用精度控制保留3位小数之后直接舍去
return this.#fixPrecision(scaledSize);
}
/** 精度控制方法 - 固定3位小数3位之后直接舍去不四舍五入不足3位则补齐 */
#fixPrecision(value: number): number {
// 先截断到3位小数不四舍五入