This commit is contained in:
2026-05-25 10:43:25 +08:00
parent 84c8752e0b
commit 44925388af
5 changed files with 320 additions and 15 deletions

View File

@ -21,6 +21,7 @@ export class AppDropZone {
private scene: Scene;
private placementWall: AppPlacementWall;
private appModel: AppModel | null = null;
private mainApp: any = null;
// 内部映射:放置区域 -> 模型ID
private zoneModelMap: Map<string, string> = new Map();
@ -46,6 +47,13 @@ export class AppDropZone {
this.appModel = appModel;
}
/**
* 设置 MainApp 引用(内部使用)
*/
setMainApp(mainApp: any): void {
this.mainApp = mainApp;
}
/**
* 设置放置区域数据
* @param config 配置参数
@ -236,6 +244,235 @@ export class AppDropZone {
// 记录新模型
this.zoneModelMap.set(zoneKey, modelId);
console.log(`已记录模型 ${modelId} 到区域 ${zoneKey}`);
// 检查该墙面是否已满,如果满了则自动排列
this.checkAndAutoArrange(wallName);
}
/**
* 通知模型被删除(外部调用,用于更新映射和重新启用拖拽)
* @param modelId 被删除的模型ID
*/
notifyModelRemoved(modelId: string): void {
console.log(`[模型删除通知] 模型 ${modelId} 被删除`);
// 找到该模型所在的墙面和索引
let removedWallName: string | null = null;
let removedZoneKey: string | null = null;
this.zoneModelMap.forEach((id, zoneKey) => {
if (id === modelId) {
removedZoneKey = zoneKey;
// 从 zoneKey 中提取墙面名称,格式为 "wallName[index]"
const match = zoneKey.match(/^(.+)\[(\d+)\]$/);
if (match) {
removedWallName = match[1];
}
}
});
if (removedZoneKey) {
// 从映射中删除
this.zoneModelMap.delete(removedZoneKey);
console.log(`[模型删除通知] 已从映射中删除: ${removedZoneKey}`);
}
if (removedWallName) {
// 检查该墙面是否不满了,如果不满则重新启用拖拽
this.checkAndReenableDrag(removedWallName);
}
}
/**
* 检查墙面是否不满,如果不满则重新启用该墙面所有模型的拖拽
* @param wallName 墙面名称
*/
private checkAndReenableDrag(wallName: string): void {
const currentDivisions = this.wallDivisionsMap.get(wallName);
if (!currentDivisions) return;
// 统计该墙面已放置的模型数量
let placedCount = 0;
const placedModelIds: string[] = [];
this.zoneModelMap.forEach((modelId, zoneKey) => {
if (zoneKey.startsWith(`${wallName}[`)) {
placedCount++;
placedModelIds.push(modelId);
}
});
console.log(`[拖拽检查] 墙面 ${wallName} 当前模型数: ${placedCount}/${currentDivisions}`);
// 如果墙面不满,重新启用所有模型的拖拽
if (placedCount < currentDivisions) {
console.log(`[拖拽检查] 墙面 ${wallName} 未满,重新启用拖拽`);
placedModelIds.forEach(modelId => {
if (this.mainApp && this.mainApp.appModelDrag && typeof this.mainApp.appModelDrag.setDragEnabled === 'function') {
this.mainApp.appModelDrag.setDragEnabled(modelId, true);
console.log(`[拖拽检查] ✓ 已启用模型 ${modelId} 的拖拽功能`);
}
});
}
}
/**
* 检查墙面是否已满
* @param wallName 墙面名称
* @returns 是否已满
*/
isWallFull(wallName: string): boolean {
const currentDivisions = this.wallDivisionsMap.get(wallName);
if (!currentDivisions) return false;
// 统计该墙面已放置的模型数量
let placedCount = 0;
this.zoneModelMap.forEach((modelId, zoneKey) => {
if (zoneKey.startsWith(`${wallName}[`)) {
placedCount++;
}
});
return placedCount >= currentDivisions;
}
/**
* 检查墙面是否已满,如果满了则自动排列模型
* @param wallName 墙面名称
*/
private checkAndAutoArrange(wallName: string): void {
const currentDivisions = this.wallDivisionsMap.get(wallName);
console.log(`[自动排列检查] 墙面: ${wallName}, 分割数: ${currentDivisions}`);
if (!currentDivisions) {
console.log(`[自动排列检查] 墙面 ${wallName} 没有分割数配置,跳过`);
return;
}
// 统计该墙面已放置的模型数量
let placedCount = 0;
const placedModels: string[] = [];
this.zoneModelMap.forEach((modelId, zoneKey) => {
if (zoneKey.startsWith(`${wallName}[`)) {
placedCount++;
placedModels.push(`${zoneKey} -> ${modelId}`);
}
});
console.log(`[自动排列检查] 墙面 ${wallName} 已放置模型数: ${placedCount}/${currentDivisions}`);
console.log(`[自动排列检查] 已放置的模型:`, placedModels);
// 如果该墙面已满(放置数量等于分割数),执行自动排列
if (placedCount === currentDivisions) {
console.log(`[自动排列] 墙面 ${wallName} 已满(${placedCount}/${currentDivisions}),开始执行自动排列`);
this.autoArrangeWall(wallName);
} else {
console.log(`[自动排列检查] 墙面 ${wallName} 未满,不执行自动排列`);
}
}
/**
* 自动排列墙面上的所有模型
* @param wallName 墙面名称
*/
private autoArrangeWall(wallName: string): void {
console.log(`[自动排列] 开始排列墙面: ${wallName}`);
// 获取该墙面的所有放置区域
const wallZones = this.getZonesByWall(wallName);
console.log(`[自动排列] 墙面 ${wallName} 的放置区域数量: ${wallZones.length}`);
if (!wallZones.length) {
console.log(`[自动排列] 墙面 ${wallName} 没有放置区域,退出`);
return;
}
// 收集该墙面已放置的模型信息
const placedModels: Array<{ modelId: string; currentIndex: number }> = [];
this.zoneModelMap.forEach((modelId, zoneKey) => {
const match = zoneKey.match(new RegExp(`^${wallName}\\[(\\d+)\\]$`));
if (match) {
const currentIndex = parseInt(match[1]);
placedModels.push({
modelId: modelId,
currentIndex: currentIndex
});
console.log(`[自动排列] 找到模型: ${modelId}, 当前索引: ${currentIndex}`);
}
});
console.log(`[自动排列] 收集到 ${placedModels.length} 个模型`);
// 按当前索引排序
placedModels.sort((a, b) => a.currentIndex - b.currentIndex);
console.log(`[自动排列] 排序后的模型顺序:`, placedModels.map(m => `${m.modelId}(索引${m.currentIndex})`));
// 重新排列:将模型按顺序放置到 0, 1, 2... 的位置
placedModels.forEach((model, newIndex) => {
console.log(`[自动排列] 处理模型 ${model.modelId}: 当前索引=${model.currentIndex}, 目标索引=${newIndex}`);
// 获取目标放置区域
const targetZone = wallZones[newIndex];
if (!targetZone) {
console.warn(`[自动排列] ✗ 找不到索引 ${newIndex} 的放置区域`);
return;
}
if (this.appModel) {
// 计算新位置(从放置区域的中心点加上法线偏移)
const offsetDistance = 0.05;
const targetPosition = targetZone.center.add(targetZone.normal.scale(offsetDistance));
// 计算旋转角度(根据法线方向)
const targetDirection = targetZone.normal.scale(-1);
const angle = Math.atan2(targetDirection.x, targetDirection.z);
console.log(`[自动排列] 目标区域 ${newIndex} 的位置:`, {
center: targetZone.center,
normal: targetZone.normal,
targetPosition: targetPosition,
rotation: angle * 180 / Math.PI
});
// 移动模型到新位置
const meshes = this.appModel.getCachedMeshes(model.modelId);
if (meshes && meshes.length > 0) {
const rootMesh = meshes[0];
// 更新位置
rootMesh.position.copyFrom(targetPosition);
// 更新旋转
rootMesh.rotation.y = angle;
console.log(`[自动排列] ✓ 模型 ${model.modelId} 已移动到索引 ${newIndex} 的位置`);
} else {
console.warn(`[自动排列] ✗ 找不到模型 ${model.modelId} 的网格`);
}
// 更新映射(无论是否移动,都要确保映射正确)
if (model.currentIndex !== newIndex) {
const oldKey = `${wallName}[${model.currentIndex}]`;
const newKey = `${wallName}[${newIndex}]`;
this.zoneModelMap.delete(oldKey);
this.zoneModelMap.set(newKey, model.modelId);
console.log(`[自动排列] 更新映射: ${oldKey} -> ${newKey}`);
}
}
});
// 禁用该墙面所有模型的拖拽功能
console.log(`[自动排列] 开始禁用拖拽功能`);
placedModels.forEach(model => {
// 安全检查:确保 mainApp 和 appModelDrag 都存在
if (this.mainApp && this.mainApp.appModelDrag && typeof this.mainApp.appModelDrag.setDragEnabled === 'function') {
this.mainApp.appModelDrag.setDragEnabled(model.modelId, false);
console.log(`[自动排列] ✓ 已禁用模型 ${model.modelId} 的拖拽功能`);
} else {
console.warn(`[自动排列] ✗ 无法禁用模型 ${model.modelId} 的拖拽功能appModelDrag 未初始化`);
}
});
console.log(`[自动排列] 墙面 ${wallName} 自动排列完成`);
}
/**