187 lines
5.6 KiB
TypeScript
187 lines
5.6 KiB
TypeScript
import type { MapAreaInfo, MapPen } from '@api/map';
|
|
import { MapAreaType, MapPointType } from '@api/map';
|
|
|
|
/**
|
|
* 区域操作服务类
|
|
* 负责处理区域大小变化时的点位绑定检查和管理
|
|
*/
|
|
export class AreaOperationService {
|
|
/**
|
|
* 处理区域大小变化事件
|
|
* 当互斥区或非互斥区的大小发生变化时,自动检查并绑定新包含的点位
|
|
* @param pen 发生变化的图形对象
|
|
* @param findPoints 查找点位的函数
|
|
* @param updateArea 更新区域的函数
|
|
*/
|
|
public handleAreaSizeChange(
|
|
pen: MapPen,
|
|
findPoints: (type: string) => MapPen[],
|
|
updateArea: (id: string, info: Partial<MapAreaInfo>) => void,
|
|
): void {
|
|
// 检查是否为区域类型
|
|
if (!pen.area?.type || !['area'].includes(pen.tags?.[0] || '')) {
|
|
return;
|
|
}
|
|
|
|
const areaType = pen.area.type;
|
|
|
|
// 只处理互斥区和非互斥区
|
|
if (![MapAreaType.互斥区, MapAreaType.非互斥区].includes(areaType)) {
|
|
return;
|
|
}
|
|
|
|
// 获取区域边界
|
|
const areaRect = this.getPenRect(pen);
|
|
if (!areaRect) {
|
|
return;
|
|
}
|
|
|
|
// 查找所有点位
|
|
const allPoints = findPoints('point') as MapPen[];
|
|
|
|
// 根据区域类型过滤点位,借鉴 addArea 的逻辑
|
|
const containedPoints: string[] = [];
|
|
const currentBoundPoints = pen.area.points || [];
|
|
|
|
allPoints.forEach((point) => {
|
|
if (!point.point?.type) return;
|
|
|
|
// 根据区域类型过滤点位类型
|
|
let shouldInclude = false;
|
|
switch (areaType) {
|
|
case MapAreaType.互斥区:
|
|
case MapAreaType.非互斥区:
|
|
// 互斥区和非互斥区绑定所有类型的点位
|
|
shouldInclude = true;
|
|
break;
|
|
case MapAreaType.库区:
|
|
// 库区只绑定动作点
|
|
shouldInclude = point.point.type === MapPointType.动作点;
|
|
break;
|
|
case MapAreaType.约束区:
|
|
// 约束区绑定所有类型的点位
|
|
shouldInclude = true;
|
|
break;
|
|
default:
|
|
shouldInclude = false;
|
|
break;
|
|
}
|
|
|
|
if (!shouldInclude) return;
|
|
|
|
// 检查点位是否在区域内(使用点位中心坐标)
|
|
const pointCenter = this.getPointRect(point);
|
|
if (!pointCenter) return;
|
|
|
|
const isContained = this.isPointInArea(pointCenter, areaRect);
|
|
|
|
if (isContained) {
|
|
containedPoints.push(point.id!);
|
|
}
|
|
});
|
|
|
|
// 找出新包含的点位(之前未绑定的)
|
|
const newPoints = containedPoints.filter((id) => !currentBoundPoints.includes(id));
|
|
|
|
// 找出需要解绑的点位(之前绑定但现在不在区域内的)
|
|
const removedPoints = currentBoundPoints.filter((id) => !containedPoints.includes(id));
|
|
|
|
if (newPoints.length > 0 || removedPoints.length > 0) {
|
|
// 更新区域绑定的点位:保留仍在区域内的点位,添加新包含的点位
|
|
const updatedPoints = containedPoints;
|
|
|
|
updateArea(pen.id!, { points: updatedPoints });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查点位是否在指定区域内
|
|
* @param point 点位坐标
|
|
* @param area 区域边界
|
|
* @returns 是否在区域内
|
|
*/
|
|
private isPointInArea(
|
|
point: { x: number; y: number },
|
|
area: { x: number; y: number; width: number; height: number },
|
|
): boolean {
|
|
return point.x >= area.x && point.x <= area.x + area.width && point.y >= area.y && point.y <= area.y + area.height;
|
|
}
|
|
|
|
/**
|
|
* 获取区域边界矩形
|
|
* @param pen 区域图形对象
|
|
* @returns 区域边界矩形
|
|
*/
|
|
private getPenRect(pen: MapPen): { x: number; y: number; width: number; height: number } | null {
|
|
if (!pen.x || !pen.y || !pen.width || !pen.height) {
|
|
return null;
|
|
}
|
|
return {
|
|
x: pen.x,
|
|
y: pen.y,
|
|
width: pen.width,
|
|
height: pen.height,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 获取点位中心坐标矩形
|
|
* @param pen 点位图形对象
|
|
* @returns 点位中心坐标矩形
|
|
*/
|
|
private getPointRect(pen: MapPen): { x: number; y: number; width: number; height: number } | null {
|
|
if (!pen.x || !pen.y || !pen.width || !pen.height) {
|
|
return null;
|
|
}
|
|
return {
|
|
x: pen.x + pen.width / 2,
|
|
y: pen.y + pen.height / 2,
|
|
width: pen.width,
|
|
height: pen.height,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 手动检查并更新指定区域的点位绑定
|
|
* 当用户调整区域大小后,可以调用此方法手动触发检查
|
|
* @param areaId 区域ID
|
|
* @param getPenById 根据ID获取图形对象的函数
|
|
* @param findPoints 查找点位的函数
|
|
* @param updateArea 更新区域的函数
|
|
*/
|
|
public checkAndUpdateAreaPoints(
|
|
areaId: string,
|
|
getPenById: (id: string) => MapPen | undefined,
|
|
findPoints: (type: string) => MapPen[],
|
|
updateArea: (id: string, info: Partial<MapAreaInfo>) => void,
|
|
): void {
|
|
const pen = getPenById(areaId);
|
|
if (!pen) {
|
|
return;
|
|
}
|
|
|
|
this.handleAreaSizeChange(pen, findPoints, updateArea);
|
|
}
|
|
|
|
/**
|
|
* 检查并更新所有互斥区和非互斥区的点位绑定
|
|
* 用于批量检查和更新
|
|
* @param findAreas 查找区域的函数
|
|
* @param findPoints 查找点位的函数
|
|
* @param updateArea 更新区域的函数
|
|
*/
|
|
public checkAndUpdateAllAreas(
|
|
findAreas: (type: string) => MapPen[],
|
|
findPoints: (type: string) => MapPen[],
|
|
updateArea: (id: string, info: Partial<MapAreaInfo>) => void,
|
|
): void {
|
|
const allAreas = findAreas('area') as MapPen[];
|
|
|
|
allAreas.forEach((area) => {
|
|
if (area.area?.type && [MapAreaType.互斥区, MapAreaType.非互斥区].includes(area.area.type)) {
|
|
this.handleAreaSizeChange(area, findPoints, updateArea);
|
|
}
|
|
});
|
|
}
|
|
}
|