家具布局系统 - 三种模式对比流程文档
整体架构
┌───────────────────────────────────────────────────────────────────── ┐
│ AI 对话阶段(共用) │
│ Round 1: 选择 SolverType → Round 2: 生成 L2 List + Relationships │
└─────────────────────────────────────────────────────────────────────┘
↓
┌────────────────────┬────────────────────┐
↓ ↓ ↓
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ 模式 1 │ │ 模式 2 │ │ 模式 3 │
│ 用户SolverType │ │ LLM SolverType │ │ LLM SolverType │
│ + 模板Relations │ │ + 模板Relations │ │ + LLM Relations│
└────────────────┘ └────────────────┘ └────────────────┘
↓ ↓ ↓
└────────────────────┴────────────────────┘
↓
Constraint Solver(共用)
↓
Canvas 渲染展示
第一部分:AI 对话阶段(三种模式共用)
1.1 Round 1:选择布局拓扑类型(SolverType)
输入
| 字段 | 说明 | 示例 |
|---|---|---|
| L1 区域类型 | L1Type | sofa_group |
| L1 边界尺寸 | 宽 L × 深 D (mm) | 4000 × 3000 |
| 朝向 facingDir | 面向方向向量 | [0, 0, -1] |
| 靠墙 wallAttach | 靠墙方向 | back / left / right / 无 |
| 风格 style | 设计风格 | 意式极简 |
| 关键词 keywords | 用户描述关键词 | ["贵妃榻", "简约"] |
| mustHave | 必须包含的家具 | ["COFFEE_TABLE"] |
| mustNotHave | 排除的家具 | ["FLOOR_LAMP"] |
6 种拓扑类型
| SolverType | 适用场景 | 关联风格 | |
|---|---|---|---|
Linear_I_Shape | 窄长空间、紧凑布局 | 现代简约、北欧 | |
Corner_L_Shape | L型沙发/贵妃榻组合 | 意式极简、现代轻奢 | |
Parallel_Facing | 对称正式、社交会客 | 中式、法式、新古典、美式 | |
U_Shape_Enclosed | 围合会客、多座位 | 中式、新中式、美式、欧式 | |
Organic_Curved | 异形/弧线造型 | 侘寂、日式极简、有机现代 | |
Omni_Modular_Island | 四面不靠墙、中央布局 | 后现代、开放式 |
选择规则(按优先级从高到低)
-
用户明确指定拓扑 → 直接使用
- "U型"/"围合" →
U_Shape_Enclosed - "L型"/"贵妃榻"/"转角" →
Corner_L_Shape - "一字"/"直排" →
Linear_I_Shape - "对坐"/"面对面" →
Parallel_Facing - "弧形"/"曲线" →
Organic_Curved - "岛式"/"中央" →
Omni_Modular_Island
- "U型"/"围合" →
-
风格匹配 → 按"关联风格"列选择最匹配的拓扑
-
空间特征辅助判断(不覆盖规则 1、2)
- 无靠墙 → 倾向
Omni_Modular_Island - 窄长空间 → 倾向
Linear_I_Shape
- 无靠墙 → 倾向
输出
{
"solverType": "Corner_L_Shape",
"reasoning": "用户提及贵妃榻,匹配L型转角布局"
}
1.2 Round 2:生成 L2 家具列表 + Relationships
输入
- Round 1 确定的
solverType - L1 尺寸、用户意图
- 可用家具目录(从
L1_TYPE_CONFIGS动态生成) - 家具尺寸参考表(从黄金样本统计,按 solverType 分类)
关系类型定义
| type | 含义 | 参数 |
|---|---|---|
FRONT_OF | A 在 B 正前方(-y方向) | distance |
BESIDE | A 在 B 旁边(横向) | side (left/right), distance |
PERPENDICULAR_ATTACH | A 垂直接合 B 端部(旋转90°) | attachSide, gap |
UNDER | z轴层叠,俯视图中心对齐 | 无 |
FACING | A 面对 B(旋转180°) | distance |
CORNER | A 在角落位置 | distance |
CENTER_OF | A 居中于 B | 无 |
间距参考
| 关系类型 | 建议间距 |
|---|---|
FRONT_OF | 350-600mm |
BESIDE | 0-150mm |
FACING | ≥1200mm |
空间约束规则
- 横向(X轴):同一 BESIDE 链上所有家具的 L + 间距之和 ≤ L1.L
- 纵向(Y轴):同一 FRONT_OF 链上所有家具的 D + 间距之和 ≤ L1.D
- 防重叠:禁止多个 BESIDE 关系 指向同一目标的同一 side,必须用链式关系(A→B→C)代替并排指向(A→B, C→B 同侧)
- 空间不足时:缩小家具尺寸或减少数量
Tool 调用流程(check_space)
1. LLM 草拟 l2List + relationships
2. 调用 check_space 校验
3. 有 conflicts → 按 suggestions 调整 → 重新调用
4. 无 conflicts → 输出最终结果
check_space Tool 详情
输入
{
l1BoundingBox: { L: number, D: number },
l2List: Array<{
role: string,
typeTag: string,
boxSize: { L: number, D: number }
}>,
relationships?: Array<{
from: string,
to: string,
type: string,
distance?: number,
side?: string
}>
}
校验内容
| 校验项 | 约束类型 | 阈值/条件 |
|---|---|---|
| 单件尺寸超出 L1 | 硬约束 | 任一维度超出即报错 |
| 单件面积占比 | 软约束 | > 40% 警告 |
| 总利用率 | 混合 | 50-60% 警告, >60% 硬约束 |
| BESIDE 横向链总宽 | 硬约束 | > L1.L 报错 |
| FRONT_OF 纵向链总深 | 硬约束 | > L1.D 报错 |
输出
{
l1Area: number, // L1 总面积 mm²
totalL2Area: number, // L2 总面积(排除 FABRIC)
utilization: "45%", // 利用率
conflicts: string[], // 硬约束冲突(必须修)
warnings: string[], // 软约束警告(建议修)
suggestions: string[] // 具体调整建议
}
Round 2 输出
{
"reasoning": "布局思路说明,含尺寸验证",
"layoutRules": {
"symmetry": false,
"densitySpacing": 1.0,
"lDirection": "right"
},
"l2List": [
{
"role": "PRIMARY_SOFA",
"typeTag": "SOFA",
"zoneTag": "CORE",
"priority": "P0",
"boxSize": { "L": 2800, "D": 1000 }
},
{
"role": "COFFEE_TABLE",
"typeTag": "TABLE",
"zoneTag": "CORE",
"priority": "P0",
"boxSize": { "L": 1200, "D": 600 }
}
],
"relationships": [
{
"from": "COFFEE_TABLE",
"to": "PRIMARY_SOFA",
"type": "FRONT_OF",
"distance": 450
}
]
}
第二部分:三种模式分流
AI 对话完成后,同一份 LLM 返回结果按 3 种方式处理:
2.1 模式 1:用户 SolverType + 模板 Relationships
输入组装
{
solverType: userSolverType, // 用户在 DebugPanel 选择的
l2List: decision.l2List, // LLM 返回的家具列表
relationships: generateRelationshipsFromTemplate(
userSolverType, // 用户选的类型
decision.l2List.map(i => i.role),
l1Input.boundingBox // 用于比例缩放
)
}
特点
- SolverType 固定(用户选择)
- Relationships 从
SOLVER_TEMPLATES模板生成 - 模板使用比例参数(如
distanceRatioD: 0.064= 6.4% of L1.D),自动适配不同尺寸 L1
2.2 模式 2:LLM SolverType + 模板 Relationships
输入组装
{
solverType: decision.solverType, // LLM 返回的
l2List: decision.l2List, // LLM 返回的
relationships: generateRelationshipsFromTemplate(
decision.solverType, // LLM 选的类型
decision.l2List.map(i => i.role),
l1Input.boundingBox
)
}
特点
- SolverType 由 LLM 决定
- Relationships 仍用模板(稳定性高)
2.3 模式 3:LLM SolverType + LLM Relationships
输入组装
{
solverType: decision.solverType, // LLM 返回的
l2List: decision.l2List, // LLM 返回的
relationships: decision.relationships // LLM 返回的(完全自由)
}
特点
- 完全由 LLM 决定
- 灵活性最高,但稳定性取决于 LLM 输出质量
第三部分:Constraint Solver 求解流程
三种模式最终都调用同一个 solveByConstraints 函数。
3.1 Step 1:锚点定位
// 从 L1 类型配置获取锚点角色(通常是 PRIMARY_SOFA)
const anchorRole = L1_TYPE_CONFIGS[l1.l1Type].anchorRole || 'PRIMARY_SOFA';
// 初始位置:x 居中, y 贴后墙(如果 wallAttach === 'back')
position = {
x: 0,
y: D / 2 - anchorBox.D / 2 // 贴后墙
}
3.2 Step 2:BFS 关系图扩散
1. 构建邻接表:from → [{to, relationship}]
2. 多轮迭代(最多 20 轮):
- 遍历所有 relationships
- 如果 to 已解算且 from 未解算 → 解算 from
3. 根据关系类型计算 position 和 rotation