rm-wall-snap-3d
v1.4.8
Published
3D物体墙体吸附与位置修正引擎 - 支持家具、电源等自动适配墙体
Downloads
3,660
Maintainers
Readme
rm-wall-snap-3d
3D物体墙体吸附与位置修正引擎 - 支持家具、电源等自动适配墙体
📦 正式版本 1.4.5
更新日期: 2026-06-03 主要变更:
- 移除 THREE.js 依赖,包体积减少 30%
- 移除 1cm 吸附偏移量,物体直接贴墙
- 新增
hotelJson完整模式:直接传入酒店 JSON,自动提取墙体 + 旋转 + 格式转换- 重要变更:
contour现在返回原始数据,quadContour返回吸附后的新轮廓walls与hotelJson字段自动兼容positionArr必须传入,用作墙体方向判断依据,现在也会原样返回- 重要:
contour字段现在是必填项- 前端无需筛选墙体数据,npm 包内部自动处理
- 纯 JS 输出,无 TypeScript 类型导出
- 所有 import 都带
.js后缀
环境要求
- Node.js: >= 16.0.0
- 模块系统: ESM (import/export)
安装
npm install rm-wall-snap-3d导出版本
import { VERSION } from 'rm-wall-snap-3d';
console.log(VERSION); // 例如: "1.4.3"使用
推荐用法(hotelJson 模式)
import { snapToWalls } from 'rm-wall-snap-3d';
// 直接传入完整的酒店 JSON 数据
const response = snapToWalls({
items: [
{
obj_id: 'socket_001',
category: 'socket',
box: {
isBox3: true,
min: { x: 1.0, y: 2.0, z: 1.4 },
max: { x: 1.085, y: 2.085, z: 1.485 }
},
position: { x: 1.0425, y: 2.0425, z: 1.4425 },
size: { x: 0.085, y: 0.085, z: 0.085 },
contour: [{ x, y, z }, ...], // 轮廓点(优先使用)
direction: { x: 0, y: 1, z: 0 },
positionArr: [{ x, y, z }] // 【必填】物体在墙内侧的位置点
}
],
// 直接传 hotelJson(含 walls、center、angle)
hotelJson: {
center: { x: 0, y: 0 },
angle: 0.5,
walls: [
{ start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, thickness: 0.12, height: 2.8 }
]
}
});
if (response.success) {
console.log(response.message);
response.data.results.forEach(result => {
if (result.snapped) {
console.log(`✅ ${result.obj_id} 吸附成功`);
console.log('新位置:', result.position);
console.log('匹配墙体:', result.quadContour);
}
});
}直接传 walls 模式
const response = snapToWalls({
items: [...],
walls: [
// 格式1:内部格式(center/normal)
{ center: { x, y, z }, normal: { x, y, z } },
// 格式2:前端格式(start/end)
{ start: { x, y }, end: { x, y }, thickness: 0.12, height: 2.8 }
]
});两种模式均无需传入 THREE.js 实例。
数据格式
Item(物品)
{
obj_id: string; // 唯一标识
category: string; // 类型:socket, switch, cabinet, air conditioner 等
box: {
isBox3: boolean;
min: { x, y, z }; // 包围盒最小点
max: { x, y, z }; // 包围盒最大点
};
position: { x, y, z }; // 中心位置
size: { x, y, z }; // 尺寸
contour?: { x, y, z }[]; // 轮廓点数组(优先使用)
vertices?: number[]; // 顶点数组(flattened,无 contour 时自动转换)
direction: { x, y, z }; // 朝向
/** 【必填】物体在墙内侧的位置点 */
positionArr: { x, y, z }[];
}⚠️
positionArr必须传入:引擎通过该点判断物体在墙体内侧还是外侧,从而决定吸附方向。缺少该字段会导致吸附失败(返回null)。
Wall(墙体)
本包自动支持两种墙体数据格式:
格式 1:前端格式(start/end) — 推荐
{
start: { x: number, y: number, z?: number }; // 起始点
end: { x: number, y: number, z?: number }; // 结束点
thickness?: number; // 墙体厚度(默认 0.12)
height?: number; // 墙体高度(默认 3.0)
}格式 2:内部格式(center/normal)
{
center: { x, y, z }; // 墙面中心点
normal: { x, y, z }; // 墙面法向量
innerSurface?: { x, y, z }; // 内表面(可选,自动计算)
outerSurface?: { x, y, z }; // 外表面(可选,自动计算)
}hotelJson 格式
{
center: { x: number, y: number }; // 户型中心点(用于旋转校正)
angle: number; // 旋转角度(弧度,用于旋转校正)
height: number; // 墙体高度
walls: Array; // 墙体数组(start/end 格式)
rooms?: any[]; // 房间信息
// ... 其他字段
}传入 hotelJson 后,npm 包会自动执行:提取墙体 → 旋转校正 → 格式转换。
Result(结果)
{
obj_id: string; // 物体唯一标识(不变)
category: string; // 物体类型(不变)
snapped: boolean; // 是否成功吸附
distance: number; // 与墙面的距离
// 不变字段
box: { isBox3: boolean; min: Object; max: Object };
size: Object;
// 吸附后更新
position: Object; // 吸附后的新位置
direction: Object; // 墙面内侧方向
contour?: Array; // 【不变】原始轮廓点(前端传入的值)
positionArr?: Array; // 【不变】物体在墙内侧的位置点数组(前端传入的值)
vertices?: Array; // 【不变】原始顶点数组(前端传入的值)
rotationAngle?: number; // 旋转角度(弧度)
backFaceCenter?: Object; // 物体背面中心点
rawContour?: Array; // 原始轮廓(旋转位移前)
/** 【重要】吸附后的新轮廓点(旋转+位移后) */
quadContour?: Array;
}吸附逻辑
整体流程:墙体提取 → 格式转换 → 找到最近墙 → 旋转 → 位移
- 墙体数据准备:自动从
walls或hotelJson.walls提取墙体,支持自动旋转校正 - 找到最近的墙面:计算物体中心到各墙面的最短距离
- 旋转物体:让物体长边与墙面方向完全平行
- 计算背面中心点:从轮廓中心出发,沿墙面外侧移动物体深度的一半
- 位移:让背面中心点贴到墙体内表面(无额外偏移)
- 保持原始高度:Z 轴坐标保持不变
墙面内外侧判断
使用 positionArr(物体在墙内侧的位置点)来判断该物体应吸附到墙的哪一侧:
- 计算位置点到墙面的投影方向
- 投影为正 → 使用墙面法线方向
- 投影为负 → 使用法线反方向
positionArr是方向判断的关键字段,必须正确传入。
支持的物品类型
| 类型 | 行为 | |------|------| | socket(电源) | 贴墙 | | switch(开关) | 贴墙 | | air conditioner(空调) | 贴墙 | | cabinet(柜子) | 贴墙 | | table / chair / sofa / bed | 保持原位(不吸附) |
输入字段说明
| 字段 | 是否必填 | 说明 |
|------|---------|------|
| obj_id | ✅ | 物体的唯一标识符 |
| category | ✅ | 物体类型 |
| box | ✅ | 包围盒,用于碰撞检测 |
| position | ✅ | 物体中心点坐标 |
| size | ✅ | 物体的长宽高 |
| contour | ✅ | 必填 轮廓点数组(优先使用) |
| vertices | ❌ | 顶点数组(无 contour 时自动转换) |
| direction | ✅ | 物体的朝向向量 |
| positionArr | ✅ | 物体在墙内侧的位置点(方向判断关键) |
输出字段说明
| 字段 | 变化 | 说明 |
|------|------|------|
| obj_id | ❌ 不变 | 物体的唯一标识符 |
| category | ❌ 不变 | 物体类型 |
| box | ❌ 不变 | 原始包围盒 |
| size | ❌ 不变 | 原始尺寸 |
| position | ✅ 更新 | 吸附后的新位置 |
| contour | ❌ 不变 | 【原始】前端传入的轮廓点 |
| positionArr | ❌ 不变 | 【原始】物体在墙内侧的位置点数组(前端传入的值) |
| vertices | ❌ 不变 | 【原始】前端传入的顶点数组 |
| direction | ✅ 更新 | 墙面内侧方向 |
| snapped | ✅ 新增 | 是否成功吸附 |
| distance | ✅ 新增 | 与墙面的距离 |
| backFaceCenter | ✅ 新增 | 物体背面中心点 |
| quadContour | ✅ 更新 | 【重要】吸附后的新轮廓点(旋转+位移后) |
| rawContour | ✅ 新增 | 原始轮廓数据(旋转位移前) |
| rotationAngle | ✅ 新增 | 旋转角度(弧度) |
完整导出示例
// 所有可用的导出
import {
snapToWalls, // 主要的吸附方法
WallSnapEngine, // 类形式的引擎(高级用法)
VERSION, // 版本号
convertHotelJson // 酒店 JSON 数据转换工具
} from 'rm-wall-snap-3d';
console.log('版本号:', VERSION);
// 使用 convertHotelJson
const hotelData = {
walls: [...],
center: { x: 0, y: 0 },
angle: 0
};
const converted = convertHotelJson(hotelData);
console.log('转换后的数据:', converted);注意事项
positionArr必须传入:缺少该字段会导致吸附失败contour优先于vertices:引擎优先使用contour,没有则从vertices自动转换- 无需 THREE.js:引擎使用纯数学计算,不依赖 Three.js
- box 和 size 保持不变:用于碰撞检测和显示尺寸
- 坐标系:右手坐标系,Z 轴向上
- THREE.js 相关代码已全部移除,包体积更小,无需外部注入
- 重要变更:
contour现在返回原始数据,quadContour返回吸附后的新轮廓
License
MIT
