Files
zhengte.babylonjs-sdk/docs/placement-area-migration.md
2026-05-13 11:28:49 +08:00

9.1 KiB
Raw Blame History

放置区域 API 迁移指南

概述

新的放置区域系统使用参数化墙面定义替代了旧的包围盒自动生成方案,提供更灵活、更精确的控制。


主要变化

旧方案的问题

  • 依赖模型包围盒自动计算
  • 只能生成固定的矩形四周
  • 无法适应不规则形状
  • 所有墙面必须使用相同的分割数

新方案的优势

  • 直接定义每个墙面的起始和结束坐标
  • 每个墙面可以有独立的分割数
  • 支持任意数量的墙面1个、4个、N个
  • 可以创建不规则形状L形、U形等
  • 不依赖模型,坐标完全可控

API 对比

旧 API已废弃

import { AppDropZone } from './AppDropZone';

const appDropZone = new AppDropZone(scene);

// 旧的配置方式
const zones = appDropZone.generateDropZones({
  modelName: 'myModel',    // 依赖模型名称
  divisions: 5,            // 所有边使用相同分割数
  color: '#21c7ff',
  alpha: 0.3,
  thickness: 2,
  offset: 5,               // 距离模型的偏移
  scale: 1.0               // 缩放比例
});

// 返回 Mesh[]

新 API推荐

import { AppDropZone } from './AppDropZone';

const appDropZone = new AppDropZone(scene);

// 新的配置方式
const zones = appDropZone.generateDropZones({
  walls: [                 // 墙面数组
    {
      name: 'front',       // 墙面名称
      startPoint: new Vector3(-50, 0, -50),  // 起始点
      endPoint: new Vector3(50, 0, -50),     // 结束点
      height: 30,          // 高度
      divisions: 5         // 这个墙面的分割数
    },
    {
      name: 'back',
      startPoint: new Vector3(50, 0, 50),
      endPoint: new Vector3(-50, 0, 50),
      height: 30,
      divisions: 5
    },
    // ... 更多墙面
  ],
  color: '#21c7ff',
  alpha: 0.3,
  thickness: 2,
  showBorder: true,        // 是否显示边框
  borderColor: '#ffffff'   // 边框颜色
});

// 返回 PlacementZoneInfo[]

迁移步骤

步骤 1确定墙面坐标

如果你之前使用模型包围盒,需要先获取模型的边界坐标:

// 获取模型的包围盒坐标
function getModelBounds(scene: Scene, modelName: string) {
  const mesh = scene.getMeshByName(modelName);
  if (!mesh) return null;

  mesh.computeWorldMatrix(true);
  const boundingInfo = mesh.getBoundingInfo();
  const min = boundingInfo.boundingBox.minimumWorld;
  const max = boundingInfo.boundingBox.maximumWorld;

  return {
    minX: min.x,
    maxX: max.x,
    minY: min.y,
    maxY: max.y,
    minZ: min.z,
    maxZ: max.z
  };
}

步骤 2转换为墙面配置

const bounds = getModelBounds(scene, 'myModel');
if (!bounds) return;

const { minX, maxX, minY, maxY, minZ, maxZ } = bounds;
const height = maxY - minY;

// 转换为新的墙面配置
const walls = [
  {
    name: 'front',
    startPoint: new Vector3(minX, minY, minZ),
    endPoint: new Vector3(maxX, minY, minZ),
    height: height,
    divisions: 5
  },
  {
    name: 'back',
    startPoint: new Vector3(maxX, minY, maxZ),
    endPoint: new Vector3(minX, minY, maxZ),
    height: height,
    divisions: 5
  },
  {
    name: 'left',
    startPoint: new Vector3(minX, minY, maxZ),
    endPoint: new Vector3(minX, minY, minZ),
    height: height,
    divisions: 5
  },
  {
    name: 'right',
    startPoint: new Vector3(maxX, minY, minZ),
    endPoint: new Vector3(maxX, minY, maxZ),
    height: height,
    divisions: 5
  }
];

步骤 3应用偏移如果需要

如果旧代码中使用了 offset 参数,需要手动调整坐标:

const offset = 5;

// 前墙向外偏移
walls[0].startPoint.z -= offset;
walls[0].endPoint.z -= offset;

// 后墙向外偏移
walls[1].startPoint.z += offset;
walls[1].endPoint.z += offset;

// 左墙向外偏移
walls[2].startPoint.x -= offset;
walls[2].endPoint.x -= offset;

// 右墙向外偏移
walls[3].startPoint.x += offset;
walls[3].endPoint.x += offset;

步骤 4应用缩放如果需要

如果旧代码中使用了 scale 参数,需要调整坐标:

const scale = 0.8;  // 缩放到80%

const centerX = (minX + maxX) / 2;
const centerZ = (minZ + maxZ) / 2;

const scaledWidth = (maxX - minX) * scale;
const scaledDepth = (maxZ - minZ) * scale;

const scaledMinX = centerX - scaledWidth / 2;
const scaledMaxX = centerX + scaledWidth / 2;
const scaledMinZ = centerZ - scaledDepth / 2;
const scaledMaxZ = centerZ + scaledDepth / 2;

// 使用缩放后的坐标
walls[0].startPoint = new Vector3(scaledMinX, minY, scaledMinZ);
walls[0].endPoint = new Vector3(scaledMaxX, minY, scaledMinZ);
// ... 其他墙面类似

完整迁移示例

旧代码

const appDropZone = new AppDropZone(scene);

const zones = appDropZone.generateDropZones({
  modelName: 'warehouse',
  divisions: 10,
  color: '#21c7ff',
  alpha: 0.3,
  thickness: 2,
  offset: 5,
  scale: 0.9
});

新代码

const appDropZone = new AppDropZone(scene);

// 1. 获取模型边界
const bounds = getModelBounds(scene, 'warehouse');
if (!bounds) return;

const { minX, maxX, minY, maxY, minZ, maxZ } = bounds;

// 2. 应用缩放
const scale = 0.9;
const centerX = (minX + maxX) / 2;
const centerZ = (minZ + maxZ) / 2;
const width = (maxX - minX) * scale;
const depth = (maxZ - minZ) * scale;
const height = maxY - minY;

const scaledMinX = centerX - width / 2;
const scaledMaxX = centerX + width / 2;
const scaledMinZ = centerZ - depth / 2;
const scaledMaxZ = centerZ + depth / 2;

// 3. 应用偏移
const offset = 5;

// 4. 生成放置区域
const zones = appDropZone.generateDropZones({
  walls: [
    {
      name: 'front',
      startPoint: new Vector3(scaledMinX, minY, scaledMinZ - offset),
      endPoint: new Vector3(scaledMaxX, minY, scaledMinZ - offset),
      height: height,
      divisions: 10
    },
    {
      name: 'back',
      startPoint: new Vector3(scaledMaxX, minY, scaledMaxZ + offset),
      endPoint: new Vector3(scaledMinX, minY, scaledMaxZ + offset),
      height: height,
      divisions: 10
    },
    {
      name: 'left',
      startPoint: new Vector3(scaledMinX - offset, minY, scaledMaxZ),
      endPoint: new Vector3(scaledMinX - offset, minY, scaledMinZ),
      height: height,
      divisions: 10
    },
    {
      name: 'right',
      startPoint: new Vector3(scaledMaxX + offset, minY, scaledMinZ),
      endPoint: new Vector3(scaledMaxX + offset, minY, scaledMaxZ),
      height: height,
      divisions: 10
    }
  ],
  color: '#21c7ff',
  alpha: 0.3,
  thickness: 2,
  showBorder: true
});

新功能示例

1. 不同墙面使用不同分割数

const zones = appDropZone.generateDropZones({
  walls: [
    { name: 'front', ..., divisions: 10 },  // 前墙10块
    { name: 'back', ..., divisions: 10 },   // 后墙10块
    { name: 'left', ..., divisions: 5 },    // 左墙5块
    { name: 'right', ..., divisions: 5 }    // 右墙5块
  ],
  // ...
});

2. 创建L形区域

const zones = appDropZone.generateDropZones({
  walls: [
    {
      name: 'wall1',
      startPoint: new Vector3(0, 0, 0),
      endPoint: new Vector3(100, 0, 0),
      height: 25,
      divisions: 10
    },
    {
      name: 'wall2',
      startPoint: new Vector3(100, 0, 0),
      endPoint: new Vector3(100, 0, 60),
      height: 25,
      divisions: 6
    }
  ],
  color: '#ff6b6b',
  alpha: 0.4
});

3. 只创建单个墙面

const zones = appDropZone.generateDropZones({
  walls: [
    {
      name: 'display',
      startPoint: new Vector3(-30, 0, 0),
      endPoint: new Vector3(30, 0, 0),
      height: 20,
      divisions: 6
    }
  ],
  color: '#4ecdc4',
  alpha: 0.35
});

获取放置区域信息

新API返回更详细的区域信息

const zones = appDropZone.generateDropZones(config);

// 每个zone包含
zones.forEach(zone => {
  console.log({
    mesh: zone.mesh,           // Babylon.js Mesh对象
    wallName: zone.wallName,   // 所属墙面名称
    index: zone.index,         // 在该墙面上的索引
    center: zone.center,       // 中心点坐标
    width: zone.width,         // 宽度
    height: zone.height,       // 高度
    normal: zone.normal        // 法线方向
  });
});

// 获取特定墙面的所有区域
const frontZones = appDropZone.getZonesByWall('front');

// 获取特定的某一块
const zone = appDropZone.getZone('front', 2);

常见问题

Q: 我必须迁移吗?

A: 旧的API已经被完全移除必须迁移到新API。

Q: 如何快速迁移?

A: 使用上面的 getModelBounds 函数获取模型边界,然后转换为墙面配置。

Q: 新API性能如何

A: 新API性能更好因为不需要计算包围盒直接使用预定义的坐标。

Q: 可以动态调整墙面吗?

A: 可以,调用 clearAll() 清除旧的,然后用新坐标重新生成。


总结

新的放置区域系统提供了:

  • 更精确的控制
  • 更灵活的配置
  • 更好的性能
  • 更清晰的API

虽然迁移需要一些工作,但新系统的灵活性和可控性值得这个投入!